Commit ba14ba35 authored by captainwong's avatar captainwong

base

parent 90bfd631
#pragma once
namespace jlib
{
// Taken from google-protobuf stubs/common.h
//
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda) and others
//
// Contains basic types and utilities used by the rest of the library.
//
// Use implicit_cast as a safe version of static_cast or const_cast
// for upcasting in the type hierarchy (i.e. casting a pointer to Foo
// to a pointer to SuperclassOfFoo or casting a pointer to Foo to
// a const pointer to Foo).
// When you use implicit_cast, the compiler checks that the cast is safe.
// Such explicit implicit_casts are necessary in surprisingly many
// situations where C++ demands an exact type match instead of an
// argument type convertable to a target type.
//
// The From type can be inferred, so the preferred syntax for using
// implicit_cast is the same as for static_cast etc.:
//
// implicit_cast<ToType>(expr)
//
// implicit_cast would have been part of the C++ standard library,
// but the proposal was submitted too late. It will probably make
// its way into the language in the future.
template<typename To, typename From>
inline To implicit_cast(From const &f)
{
return f;
}
// When you upcast (that is, cast a pointer from type Foo to type
// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts
// always succeed. When you downcast (that is, cast a pointer from
// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
// how do you know the pointer is really of type SubclassOfFoo? It
// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus,
// when you downcast, you should use this macro. In debug mode, we
// use dynamic_cast<> to double-check the downcast is legal (we die
// if it's not). In normal mode, we do the efficient static_cast<>
// instead. Thus, it's important to test in debug mode to make sure
// the cast is legal!
// This is the only place in the code we should use dynamic_cast<>.
// In particular, you SHOULDN'T be using dynamic_cast<> in order to
// do RTTI (eg code like this:
// if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);
// if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
// You should design the code some other way not to need this.
template<typename To, typename From> // use like this: down_cast<T*>(foo);
inline To down_cast(From* f) // so we only accept pointers
{
// Ensures that To is a sub-type of From *. This test is here only
// for compile-time type checking, and has no overhead in an
// optimized build at run-time, as it will be optimized away
// completely.
if (false) {
implicit_cast<From*, To>(0);
}
#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI)
assert(f == nullptr || dynamic_cast<To>(f) != nullptr); // RTTI: debug mode only!
#endif
return static_cast<To>(f);
}
} // namespace jlib
#pragma once
#ifdef __GNUG__
#define JLIB_LINUX
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32)
#define JLIB_WINDOWS
#else
#error "jlib only support linux and windows"
#endif
#pragma once
#include "config.h"
#include <inttypes.h>
#include <stdio.h>
#ifdef JLIB_LINUX
#include <sys/syscall.h>
#elif defined(JLIB_WINDOWS)
#include <Windows.h>
#endif
namespace jlib
{
namespace CurrentThread
{
namespace detail
{
inline uint64_t gettid() {
#ifdef JLIB_LINUX
return static_cast<uint64_t>(::syscall(SYS_gettid));
#elif defined(JLIB_WINDOWS)
return static_cast<uint64_t>(GetCurrentThreadId());
#endif
}
} // namespace detail
thread_local uint64_t t_cachedTid = 0;
thread_local char t_tidString[32] = {0};
thread_local int t_tidStringLength = 6;
thread_local const char* t_threadName = "unknown";
inline void cacheTid() {
if (t_cachedTid == 0) {
t_cachedTid = detail::gettid();
t_tidStringLength = snprintf(t_tidString, sizeof(t_tidString), "%lld ", t_cachedTid);
}
}
inline uint64_t tid() {
#ifdef JLIB_LINUX
if (__builtin_expect(cachedTid == 0, 0)) {
cachedTid();
}
#else
if (t_cachedTid != 0) {
return t_cachedTid;
} else {
cacheTid();
}
#endif
return t_cachedTid;
}
inline const char* tidString() {
return t_tidString;
}
inline int tidStringLength() {
return t_tidStringLength;
}
inline const char* name() {
return t_threadName;
}
} // namespace CurrentThread
} // namespace jlib
#pragma once
#include "logstream.h"
#include "timestamp.h"
namespace jlib
{
class TimeZone;
class Logger
{
public:
enum class LogLevel {
LOGLEVEL_TRACE,
LOGLEVEL_DEBUG,
LOGLEVEL_INFO,
LOGLEVEL_WARN,
LOGLEVEL_ERROR,
LOGLEVEL_FATAL,
LOGLEVEL_COUNT,
};
// compile time calculation of basename of source file
struct SourceFile
{
template <int N>
SourceFile(const char (&arr)[N]) : data_(arr) , size_(N - 1) {
const char* slash = strrchr(data_, '/');
if (slash) { data_ = slash + 1; }
size_ -= static_cast<int>(data_ - arr);
}
explicit SourceFile(const char* filename) : data_(filename) {
const char* slash = strrchr(filename, '/');
if (slash) { data_ = slash + 1; }
size_ = static_cast<int>(strlen(data_));
}
const char* data_;
int size_;
};
Logger(SourceFile file, int line);
Logger(SourceFile file, int line, LogLevel level);
Logger(SourceFile file, int line, LogLevel level, const char *func);
Logger(SourceFile file, int line, bool toAbort);
~Logger();
LogStream &stream() { return impl_.stream_; }
static LogLevel logLevel();
static void setLogLevel(LogLevel level);
typedef void (*OutputFunc)(const char *msg, int len);
typedef void (*FlushFunc)();
static void setOutput(OutputFunc);
static void setFlush(FlushFunc);
static void setTimeZone(const TimeZone &tz);
private:
class Impl
{
public:
};
}
} // namespace jlib
#pragma once
#include "noncopyable.h"
#include "stringpiece.h"
#include "cast.h"
#include <assert.h>
#include <string.h>
#include <algorithm>
#include <limits>
#include <type_traits>
#include <stdint.h>
#include <stdio.h>
#include <inttypes.h>
namespace jlib
{
namespace detail
{
static constexpr int SMALL_BUFFER = 4096;
static constexpr int LARGE_BUFFER = 4096 * 1000;
template <int SIZE>
class FixedBuffer : noncopyable
{
private:
const char *end() const { return data_ + sizeof data_; }
// Must be outline function for cookies.
static void cookieStart() {}
static void cookieEnd() {}
void (*cookie_)();
char data_[SIZE];
char *cur_;
public:
FixedBuffer()
: cur_(data_)
{
setCookie(cookieStart);
}
~FixedBuffer()
{
setCookie(cookieEnd);
}
void append(const char* buf, size_t len) {
if (implicit_cast<size_t>(avail()) > len) {
memcpy(cur_, buf, len);
cur_ += len;
}
}
const char *data() const { return data_; }
int length() const { return static_cast<int>(cur_ - data_); }
// write to data_ directly
char *current() { return cur_; }
int avail() const { return static_cast<int>(end() - cur_); }
void add(size_t len) { cur_ += len; }
void reset() { cur_ = data_; }
void bzero() { memset(data_, 0, sizeof data_); }
// for used by GDB
const char *debugString() { *cur_ = '\0'; return data_; }
void setCookie(void (*cookie)()) { cookie_ = cookie; }
// for used by unit test
std::string toString() const { return std::string(data_, length()); }
StringPiece toStringPiece() const { return StringPiece(data_, length()); }
}; // class FixedBuffer
template class FixedBuffer<SMALL_BUFFER>;
template class FixedBuffer<LARGE_BUFFER>;
// Efficient Integer to String Conversions, by Matthew Wilson.
template <typename T>
inline size_t convert(char buf[], T value)
{
static const char digits[] = "9876543210123456789";
static const char* zero = digits + 9;
static_assert(sizeof(digits) == 20, "wrong number of digits");
T i = value;
char *p = buf;
do
{
int lsd = static_cast<int>(i % 10);
i /= 10;
*p++ = zero[lsd];
} while (i != 0);
if (value < 0) {
*p++ = '-';
}
*p = '\0';
std::reverse(buf, p);
return p - buf;
}
static size_t convertHex(char buf[], uintptr_t value)
{
static const char digitsHex[] = "0123456789ABCDEF";
static_assert(sizeof(digitsHex) == 17, "wrong number of digitsHex");
uintptr_t i = value;
char *p = buf;
do
{
int lsd = static_cast<int>(i % 16);
i /= 16;
*p++ = digitsHex[lsd];
} while (i != 0);
*p = '\0';
std::reverse(buf, p);
return p - buf;
}
} // namespace detail
class LogStream : noncopyable
{
typedef LogStream self;
public:
typedef detail::FixedBuffer<detail::SMALL_BUFFER> Buffer;
self& operator<<(bool v) {
if (v) { buffer_.append("true", 4); }
else { buffer_.append("false", 5); }
return *this;
}
self& operator<<(short v) { *this << static_cast<int>(v); return *this; }
self& operator<<(unsigned short v) { *this << static_cast<unsigned int>(v); return *this; }
self& operator<<(int v) { formatInteger(v); return *this; };
self& operator<<(unsigned int v) { formatInteger(v); return *this; }
self& operator<<(long v) { formatInteger(v); return *this; };
self& operator<<(unsigned long v) { formatInteger(v); return *this; };
self& operator<<(long long v) { formatInteger(v); return *this; };
self& operator<<(unsigned long long v) { formatInteger(v); return *this; };
self& operator<<(const void * p) {
uintptr_t v = reinterpret_cast<uintptr_t>(p);
if (buffer_.avail() >= MAX_NUMERIC_SIZE) {
char* buf = buffer_.current();
buf[0] = '0';
buf[1] = 'x';
size_t len = detail::convertHex(buf + 2, v);
buffer_.add(len + 2);
}
return *this;
}
self& operator<<(float v) {
*this << static_cast<double>(v);
return *this;
}
self& operator<<(double v) {
if (buffer_.avail() >= MAX_NUMERIC_SIZE) {
int len = snprintf(buffer_.current(), MAX_NUMERIC_SIZE, "%.12g", v);
buffer_.add(len);
}
return *this;
}
// self& operator<<(long double);
self& operator<<(char v) {
buffer_.append(&v, 1);
return *this;
}
// self& operator<<(signed char);
// self& operator<<(unsigned char);
self& operator<<(const char *str) {
if (str) {
buffer_.append(str, strlen(str));
} else {
buffer_.append("(null)", 6);
}
return *this;
}
self& operator<<(const unsigned char *str) {
return operator<<(reinterpret_cast<const char *>(str));
}
self& operator<<(const std::string& v) {
buffer_.append(v.c_str(), v.size());
return *this;
}
self& operator<<(const StringPiece& v) {
buffer_.append(v.data(), v.size());
return *this;
}
self& operator<<(const Buffer& v) {
*this << v.toStringPiece();
return *this;
}
void append(const char *data, int len) { buffer_.append(data, len); }
const Buffer& buffer() const { return buffer_; }
void resetBuffer() { buffer_.reset(); }
private:
void staticCheck() {
static_assert(MAX_NUMERIC_SIZE - 10 > std::numeric_limits<double>::digits10,
"MAX_NUMERIC_SIZE is large enough");
static_assert(MAX_NUMERIC_SIZE - 10 > std::numeric_limits<long double>::digits10,
"MAX_NUMERIC_SIZE is large enough");
static_assert(MAX_NUMERIC_SIZE - 10 > std::numeric_limits<long>::digits10,
"MAX_NUMERIC_SIZE is large enough");
static_assert(MAX_NUMERIC_SIZE - 10 > std::numeric_limits<long long>::digits10,
"MAX_NUMERIC_SIZE is large enough");
}
template <typename T>
void formatInteger(T v) {
if (buffer_.avail() > MAX_NUMERIC_SIZE) {
size_t len = detail::convert(buffer_.current(), v);
buffer_.add(len);
}
}
Buffer buffer_;
static constexpr int MAX_NUMERIC_SIZE = 32;
}; // class LogStream
class Format
{
public:
template <typename T>
Format(const char* fmt, T val) {
static_assert(std::is_arithmetic<T>::value == true, "Must be arithmetic type");
length_ = snprintf(buf_, sizeof(buf_), fmt, val);
assert(static_cast<size_t>(length_) < sizeof(buf_));
}
const char* data() const { return buf_; }
int length() const { return length_; }
private:
char buf_[32];
int length_;
};
// Explicit instantiations
template Format::Format(const char* fmt, char);
template Format::Format(const char* fmt, short);
template Format::Format(const char* fmt, unsigned short);
template Format::Format(const char* fmt, int);
template Format::Format(const char* fmt, unsigned int);
template Format::Format(const char* fmt, long);
template Format::Format(const char* fmt, unsigned long);
template Format::Format(const char* fmt, long long);
template Format::Format(const char* fmt, unsigned long long);
template Format::Format(const char* fmt, float);
template Format::Format(const char* fmt, double);
// Format quantity n in SI units (k, M, G, T, P, E).
// The returned string is atmost 5 characters long.
// Requires n >= 0
/*
Format a number with 5 characters, including SI units.
[0, 999]
[1.00k, 999k]
[1.00M, 999M]
[1.00G, 999G]
[1.00T, 999T]
[1.00P, 999P]
[1.00E, inf)
*/
static std::string formatSI(int64_t s)
{
double n = static_cast<double>(s);
char buf[64];
if (s < 1000)
snprintf(buf, sizeof(buf), "%" PRId64, s);
else if (s < 9995)
snprintf(buf, sizeof(buf), "%.2fk", n / 1e3);
else if (s < 99950)
snprintf(buf, sizeof(buf), "%.1fk", n / 1e3);
else if (s < 999500)
snprintf(buf, sizeof(buf), "%.0fk", n / 1e3);
else if (s < 9995000)
snprintf(buf, sizeof(buf), "%.2fM", n / 1e6);
else if (s < 99950000)
snprintf(buf, sizeof(buf), "%.1fM", n / 1e6);
else if (s < 999500000)
snprintf(buf, sizeof(buf), "%.0fM", n / 1e6);
else if (s < 9995000000)
snprintf(buf, sizeof(buf), "%.2fG", n / 1e9);
else if (s < 99950000000)
snprintf(buf, sizeof(buf), "%.1fG", n / 1e9);
else if (s < 999500000000)
snprintf(buf, sizeof(buf), "%.0fG", n / 1e9);
else if (s < 9995000000000)
snprintf(buf, sizeof(buf), "%.2fT", n / 1e12);
else if (s < 99950000000000)
snprintf(buf, sizeof(buf), "%.1fT", n / 1e12);
else if (s < 999500000000000)
snprintf(buf, sizeof(buf), "%.0fT", n / 1e12);
else if (s < 9995000000000000)
snprintf(buf, sizeof(buf), "%.2fP", n / 1e15);
else if (s < 99950000000000000)
snprintf(buf, sizeof(buf), "%.1fP", n / 1e15);
else if (s < 999500000000000000)
snprintf(buf, sizeof(buf), "%.0fP", n / 1e15);
else
snprintf(buf, sizeof(buf), "%.2fE", n / 1e18);
return buf;
}
// Format quantity n in IEC (binary) units (Ki, Mi, Gi, Ti, Pi, Ei).
// The returned string is atmost 6 characters long.
// Requires n >= 0
/*
[0, 1023]
[1.00Ki, 9.99Ki]
[10.0Ki, 99.9Ki]
[ 100Ki, 1023Ki]
[1.00Mi, 9.99Mi]
*/
static std::string formatIEC(int64_t s)
{
double n = static_cast<double>(s);
char buf[64];
const double Ki = 1024.0;
const double Mi = Ki * 1024.0;
const double Gi = Mi * 1024.0;
const double Ti = Gi * 1024.0;
const double Pi = Ti * 1024.0;
const double Ei = Pi * 1024.0;
if (n < Ki)
snprintf(buf, sizeof buf, "%" PRId64, s);
else if (n < Ki * 9.995)
snprintf(buf, sizeof buf, "%.2fKi", n / Ki);
else if (n < Ki * 99.95)
snprintf(buf, sizeof buf, "%.1fKi", n / Ki);
else if (n < Ki * 1023.5)
snprintf(buf, sizeof buf, "%.0fKi", n / Ki);
else if (n < Mi * 9.995)
snprintf(buf, sizeof buf, "%.2fMi", n / Mi);
else if (n < Mi * 99.95)
snprintf(buf, sizeof buf, "%.1fMi", n / Mi);
else if (n < Mi * 1023.5)
snprintf(buf, sizeof buf, "%.0fMi", n / Mi);
else if (n < Gi * 9.995)
snprintf(buf, sizeof buf, "%.2fGi", n / Gi);
else if (n < Gi * 99.95)
snprintf(buf, sizeof buf, "%.1fGi", n / Gi);
else if (n < Gi * 1023.5)
snprintf(buf, sizeof buf, "%.0fGi", n / Gi);
else if (n < Ti * 9.995)
snprintf(buf, sizeof buf, "%.2fTi", n / Ti);
else if (n < Ti * 99.95)
snprintf(buf, sizeof buf, "%.1fTi", n / Ti);
else if (n < Ti * 1023.5)
snprintf(buf, sizeof buf, "%.0fTi", n / Ti);
else if (n < Pi * 9.995)
snprintf(buf, sizeof buf, "%.2fPi", n / Pi);
else if (n < Pi * 99.95)
snprintf(buf, sizeof buf, "%.1fPi", n / Pi);
else if (n < Pi * 1023.5)
snprintf(buf, sizeof buf, "%.0fPi", n / Pi);
else if (n < Ei * 9.995)
snprintf(buf, sizeof buf, "%.2fEi", n / Ei);
else
snprintf(buf, sizeof buf, "%.1fEi", n / Ei);
return buf;
}
} // namespace jlib
#pragma once
#include "noncopyable.h"
#include <mutex>
#include <stdlib.h>
#include <assert.h>
namespace jlib
{
namespace detail
{
// This doesn't detect inherited member functions!
// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions
template <typename T>
struct has_no_destroy
{
template <typename C> static char test(decltype(&C::no_destroy));
template <typename C> static long test(...);
static const bool value = sizeof(test<T>(nullptr)) == sizeof(char);
};
} // namespace detail
template <typename T>
class singleton : noncopyable
{
public:
singleton() = delete;
~singleton() = delete;
static T& instance() {
std::call_once(once_, &singleton::init);
assert(instance_ != nullptr);
return *instance_;
}
private:
static void init() {
instance_ = new T();
if (!detail::has_no_destroy<T>::value) {
::atexit(destroy);
}
}
static void destroy() {
typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1];
T_must_be_complete_type dummy; (void) dummy;
delete instance_;
instance_ = nullptr;
}
private:
static std::once_flag once_;
static T* instance_;
};
template <typename T>
std::once_flag singleton<T>::once_ = {};
template <typename T>
T* singleton<T>::instance_ = nullptr;
} // namespace jlib
// Taken from PCRE pcre_stringpiece.h
//
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Sanjay Ghemawat
//
// A string like object that points into another piece of memory.
// Useful for providing an interface that allows clients to easily
// pass in either a "const char*" or a "string".
//
// Arghh! I wish C++ literals were automatically of type "string".
#include <string>
#include <string.h>
namespace jlib
{
// For passing C-style string argument to a function.
class StringArg // copyable
{
public:
StringArg(const char *str)
: str_(str)
{}
StringArg(const std::string &str)
: str_(str.c_str())
{}
const char *c_str() const { return str_; }
private:
const char *str_;
};
class StringPiece
{
private:
const char *ptr_;
int length_;
public:
// We provide non-explicit singleton constructors so users can pass
// in a "const char*" or a "string" wherever a "StringPiece" is
// expected.
StringPiece()
: ptr_(nullptr), length_(0)
{}
StringPiece(const char *str)
: ptr_(str), length_(static_cast<int>(strlen(ptr_)))
{}
StringPiece(const unsigned char *str)
: ptr_(reinterpret_cast<const char *>(str)),
length_(static_cast<int>(strlen(ptr_)))
{}
StringPiece(const std::string &str)
: ptr_(str.data()), length_(static_cast<int>(str.size()))
{}
StringPiece(const char *offset, int len)
: ptr_(offset), length_(len)
{}
// data() may return a pointer to a buffer with embedded NULs, and the
// returned buffer may or may not be null terminated. Therefore it is
// typically a mistake to pass data() to a routine that expects a NUL
// terminated string. Use "as_string().c_str()" if you really need to do
// this. Or better yet, change your routine so it does not rely on NUL
// termination.
const char *data() const { return ptr_; }
int size() const { return length_; }
bool empty() const { return length_ == 0; }
const char *begin() const { return ptr_; }
const char *end() const { return ptr_ + length_; }
void clear() {
ptr_ = NULL;
length_ = 0;
}
void set(const char *buffer, int len) {
ptr_ = buffer;
length_ = len;
}
void set(const char *str) {
ptr_ = str;
length_ = static_cast<int>(strlen(str));
}
void set(const void *buffer, int len) {
ptr_ = reinterpret_cast<const char *>(buffer);
length_ = len;
}
char operator[](int i) const { return ptr_[i]; }
void remove_prefix(int n) {
ptr_ += n;
length_ -= n;
}
void remove_suffix(int n) {
length_ -= n;
}
bool operator==(const StringPiece &x) const {
return ((length_ == x.length_) &&
(memcmp(ptr_, x.ptr_, length_) == 0));
}
bool operator!=(const StringPiece &x) const {
return !(*this == x);
}
#define STRINGPIECE_BINARY_PREDICATE(cmp, auxcmp) \
bool operator cmp(const StringPiece &x) const \
{ \
int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); \
return ((r auxcmp 0) || ((r == 0) && (length_ cmp x.length_))); \
}
STRINGPIECE_BINARY_PREDICATE(<, <);
STRINGPIECE_BINARY_PREDICATE(<=, <);
STRINGPIECE_BINARY_PREDICATE(>=, >);
STRINGPIECE_BINARY_PREDICATE(>, >);
#undef STRINGPIECE_BINARY_PREDICATE
int compare(const StringPiece &x) const {
int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_);
if (r == 0) {
if (length_ < x.length_)
r = -1;
else if (length_ > x.length_)
r = +1;
}
return r;
}
std::string as_string() const {
return std::string(data(), size());
}
void CopyToString(std::string *target) const {
target->assign(ptr_, length_);
}
// Does "this" start with "x"
bool starts_with(const StringPiece &x) const {
return ((length_ >= x.length_) && (memcmp(ptr_, x.ptr_, x.length_) == 0));
}
};
} // namespace jlib
#pragma once
#include "config.h"
#include "copyable.h"
#include <boost/operators.hpp>
#include <stdint.h> // int64_t
......@@ -10,20 +11,19 @@
//#define _WIN32_WINNT _WIN32_WINNT_WIN7
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32)
#ifdef JLIB_WINDOWS
# include <windows.h>
static inline struct tm* gmtime_r(const time_t* timep, struct tm* result)
{
gmtime_s(result, timep);
return result;
}
# include <windows.h>
// https://blogs.msdn.microsoft.com/vcblog/2016/03/30/optimizing-the-layout-of-empty-base-classes-in-vs2015-update-2-3/
# define ENABLE_EBO __declspec(empty_bases)
#else
#include <sys/time.h> // gettimeofday
#elif defined(JLIB_LINUX)
# include <sys/time.h> // gettimeofday
# define ENABLE_EBO
#endif
......@@ -84,7 +84,7 @@ public:
static Timestamp now() {
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32)
#ifdef JLIB_WINDOWS
/* FILETIME of Jan 1 1970 00:00:00. */
static constexpr unsigned __int64 EPOCH = 116444736000000000UL;
......@@ -103,7 +103,7 @@ public:
ularge.HighPart = ft.dwHighDateTime;
return Timestamp((ularge.QuadPart - EPOCH) / 10L);
#else
#elif defined(JLIB_LINUX)
struct timeval tv;
gettimeofday(&tv, nullptr);
int64_t seconds = tv.tv_sec;
......
#pragma once
#pragma once
#include <string>
#include <vector>
......@@ -12,90 +12,90 @@ namespace DeviceUniqueIdentifier {
/*
参考1:
《设备唯一标识方法(Unique Identifier):如何在Windows系统上获取设备的唯一标识》
参考1:
《设备唯一标识方法(Unique Identifier):如何在Windows系统上获取设备的唯一标识》
http://www.vonwei.com/post/UniqueDeviceIDforWindows.html
参考2:
《通过WMI获取网卡MAC地址、硬盘序列号、主板序列号、CPU ID、BIOS序列号》
参考2
《通过WMI获取网卡MAC地址、硬盘序列号、主板序列号、CPU ID、BIOS序列号》
https://blog.csdn.net/b_h_l/article/details/7764767
*/
enum QueryType : size_t {
/*
当前网卡MAC
MAC地址可能是最常用的标识方法,但是现在这种方法基本不可靠:
一个电脑可能存在多个网卡,多个MAC地址,
如典型的笔记本可能存在有线、无线、蓝牙等多个MAC地址,
随着不同连接方式的改变,每次MAC地址也会改变。
而且,当安装有虚拟机时,MAC地址会更多。
MAC地址另外一个更加致命的弱点是,MAC地址很容易手动更改。
因此,MAC地址基本不推荐用作设备唯一ID。
当前网卡MAC
MAC地址可能是最常用的标识方法,但是现在这种方法基本不可靠:
一个电脑可能存在多个网卡,多个MAC地址,
如典型的笔记本可能存在有线、无线、蓝牙等多个MAC地址,
随着不同连接方式的改变,每次MAC地址也会改变。
而且,当安装有虚拟机时,MAC地址会更多。
MAC地址另外一个更加致命的弱点是,MAC地址很容易手动更改。
因此,MAC地址基本不推荐用作设备唯一ID。
*/
MAC_ADDR = 1,
/*
当前网卡原生MAC
可以轻易修改网卡MAC,但无法修改原生MAC
当前网卡原生MAC
可以轻易修改网卡MAC,但无法修改原生MAC
*/
MAC_ADDR_REAL = 1 << 1,
/*
硬盘序列号
在Windows系统中通过命令行运行“wmic diskdrive get serialnumber”可以查看。
硬盘序列号作为设备唯一ID存在的问题是,很多机器可能存在多块硬盘,
特别是服务器,而且机器更换硬盘是很可能发生的事情,
更换硬盘后设备ID也必须随之改变, 不然也会影响授权等应用。
因此,很多授权软件没有考虑使用硬盘序列号。
而且,不一定所有的电脑都能获取到硬盘序列号。
硬盘序列号
在Windows系统中通过命令行运行“wmic diskdrive get serialnumber”可以查看。
硬盘序列号作为设备唯一ID存在的问题是,很多机器可能存在多块硬盘,
特别是服务器,而且机器更换硬盘是很可能发生的事情,
更换硬盘后设备ID也必须随之改变, 不然也会影响授权等应用。
因此,很多授权软件没有考虑使用硬盘序列号。
而且,不一定所有的电脑都能获取到硬盘序列号。
*/
HARDDISK_SERIAL = 1 << 2,
//! 主板序列号
//! 主板序列号
/*
在Windows系统中通过命令行运行“wmic csproduct get UUID”可以查看。
主板UUID是很多授权方法和微软官方都比较推崇的方法,
即便重装系统UUID应该也不会变
(笔者没有实测重装,不过在一台机器上安装双系统,获取的主板UUID是一样的,
双系统一个windows一个Linux,Linux下用“dmidecode -s system-uuid”命令可以获取UUID)。
但是这个方法也有缺陷,因为不是所有的厂商都提供一个UUID,
当这种情况发生时,wmic会返回“FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF”,
即一个无效的UUID。
在Windows系统中通过命令行运行“wmic csproduct get UUID”可以查看。
主板UUID是很多授权方法和微软官方都比较推崇的方法,
即便重装系统UUID应该也不会变
(笔者没有实测重装,不过在一台机器上安装双系统,获取的主板UUID是一样的,
双系统一个windows一个Linux,Linux下用“dmidecode -s system-uuid”命令可以获取UUID)。
但是这个方法也有缺陷,因为不是所有的厂商都提供一个UUID,
当这种情况发生时,wmic会返回“FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF”,
即一个无效的UUID。
*/
MOTHERBOARD_UUID = 1 << 3,
//! 主板型号
//! 主板型号
MOTHERBOARD_MODEL = 1 << 4,
/*
CPU ID
在Windows系统中通过命令行运行“wmic cpu get processorid”就可以查看CPU ID。
目前CPU ID也无法唯一标识设备,Intel现在可能同一批次的CPU ID都一样,不再提供唯一的ID。
而且经过实际测试,新购买的同一批次PC的CPU ID很可能一样。
这样作为设备的唯一标识就会存在问题。
在Windows系统中通过命令行运行“wmic cpu get processorid”就可以查看CPU ID。
目前CPU ID也无法唯一标识设备,Intel现在可能同一批次的CPU ID都一样,不再提供唯一的ID。
而且经过实际测试,新购买的同一批次PC的CPU ID很可能一样。
这样作为设备的唯一标识就会存在问题。
*/
CPU_ID = 1 << 5,
//! BIOS序列号
//! BIOS序列号
BIOS_SERIAL = 1 << 6,
/*
Windows 产品ID
在“控制面板\系统和安全\系统”的最下面就可以看到激活的Windows产品ID信息,
另外通过注册表“HKEY_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion”也可以看到看到“ProductId”字段。
不过这个产品ID并不唯一,不同系统或者机器重复的概率也比较大。
虚拟机中克隆的系统,使用同一个镜像安装激活的系统,其产品ID就可能一模一样。
经过实测,笔者在两台Thinkpad笔记本上发现其ProductId完全一样。
Windows 产品ID
在“控制面板\系统和安全\系统”的最下面就可以看到激活的Windows产品ID信息,
另外通过注册表“HKEY_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion”也可以看到看到“ProductId”字段。
不过这个产品ID并不唯一,不同系统或者机器重复的概率也比较大。
虚拟机中克隆的系统,使用同一个镜像安装激活的系统,其产品ID就可能一模一样。
经过实测,笔者在两台Thinkpad笔记本上发现其ProductId完全一样。
*/
WINDOWS_PRODUCT_ID = 1 << 7,
/*
Windows MachineGUID
Windows安装时会唯一生成一个GUID,
可以在注册表“HKEY_MACHINE\SOFTWARE\Microsoft\Cryptography”中查看其“MachineGuid”字段。
这个ID作为Windows系统设备的唯一标识不错,不过值得注意的一点是,与硬件ID不一样,
这个ID在重装Windows系统后应该不一样了。
这样授权软件在重装系统后,可能就需要用户重新购买授权。
Windows安装时会唯一生成一个GUID,
可以在注册表“HKEY_MACHINE\SOFTWARE\Microsoft\Cryptography”中查看其“MachineGuid”字段。
这个ID作为Windows系统设备的唯一标识不错,不过值得注意的一点是,与硬件ID不一样,
这个ID在重装Windows系统后应该不一样了。
这样授权软件在重装系统后,可能就需要用户重新购买授权。
*/
WINDOWS_MACHINE_GUID = 1 << 8,
};
......@@ -117,26 +117,26 @@ enum {
};
/**
* @brief 查询信息
* @param[in] queryTypes QueryType集合
* @param[in,out] results 查询结果集合
* @return 成功或失败
* @brief 查询信息
* @param[in] queryTypes QueryType集合
* @param[in,out] results 查询结果集合
* @return 成功或失败
*/
static bool query(size_t queryTypes, std::unordered_map<QueryType, std::wstring>& results);
/**
* @brief 查询信息
* @param[in] queryTypes QueryType集合
* @param[in,out] results 查询结果集合
* @return 成功或失败
* @brief 查询信息
* @param[in] queryTypes QueryType集合
* @param[in,out] results 查询结果集合
* @return 成功或失败
*/
static bool query(const std::vector<QueryType>& queryTypes, std::unordered_map<QueryType, std::wstring>& results);
/**
* @brief 连接查询结果为一个字符串
* @param[in] results 查询结果集合
* @param[in,out] conjunction 连词
* @return 将结果以连词连接起来组成的字符串
* @brief 连接查询结果为一个字符串
* @param[in] results 查询结果集合
* @param[in,out] conjunction 连词
* @return 将结果以连词连接起来组成的字符串
*/
static std::wstring join_result(const std::vector<std::wstring>& results, const std::wstring& conjunction);
......@@ -164,7 +164,7 @@ namespace DeviceUniqueIdentifier {
namespace detail {
struct DeviceProperty {
enum { PROPERTY_MAX_LEN = 128 }; // 属性字段最大长度
enum { PROPERTY_MAX_LEN = 128 }; // 属性字段最大长度
wchar_t szProperty[PROPERTY_MAX_LEN];
};
......@@ -177,35 +177,35 @@ struct WQL_QUERY
inline WQL_QUERY getWQLQuery(QueryType queryType) {
switch (queryType) {
case DeviceUniqueIdentifier::MAC_ADDR:
return // 网卡当前MAC地址
return // 网卡当前MAC地址
{ L"SELECT * FROM Win32_NetworkAdapter WHERE (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%'))",
L"MACAddress" };
case DeviceUniqueIdentifier::MAC_ADDR_REAL:
return // 网卡原生MAC地址
return // 网卡原生MAC地址
{ L"SELECT * FROM Win32_NetworkAdapter WHERE (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%'))",
L"PNPDeviceID" };
case DeviceUniqueIdentifier::HARDDISK_SERIAL:
return // 硬盘序列号
return // 硬盘序列号
{ L"SELECT * FROM Win32_DiskDrive WHERE (SerialNumber IS NOT NULL) AND (MediaType LIKE 'Fixed hard disk%')",
L"SerialNumber" };
case DeviceUniqueIdentifier::MOTHERBOARD_UUID:
return // 主板序列号
return // 主板序列号
{ L"SELECT * FROM Win32_BaseBoard WHERE (SerialNumber IS NOT NULL)",
L"SerialNumber" };
case DeviceUniqueIdentifier::MOTHERBOARD_MODEL:
return // 主板型号
return // 主板型号
{ L"SELECT * FROM Win32_BaseBoard WHERE (Product IS NOT NULL)",
L"Product" };
case DeviceUniqueIdentifier::CPU_ID:
return // 处理器ID
return // 处理器ID
{ L"SELECT * FROM Win32_Processor WHERE (ProcessorId IS NOT NULL)",
L"ProcessorId" };
case DeviceUniqueIdentifier::BIOS_SERIAL:
return // BIOS序列号
return // BIOS序列号
{ L"SELECT * FROM Win32_BIOS WHERE (SerialNumber IS NOT NULL)",
L"SerialNumber" };
case DeviceUniqueIdentifier::WINDOWS_PRODUCT_ID:
return // Windows 产品ID
return // Windows 产品ID
{ L"SELECT * FROM Win32_OperatingSystem WHERE (SerialNumber IS NOT NULL)",
L"SerialNumber" };
default:
......@@ -221,11 +221,11 @@ static BOOL WMI_DoWithHarddiskSerialNumber(wchar_t *SerialNumber, UINT uSize)
iLen = wcslen(SerialNumber);
if (iLen == 40) // InterfaceType = "IDE"
{ // 需要将16进制编码串转换为字符串
{ // 需要将16进制编码串转换为字符串
wchar_t ch, szBuf[32];
BYTE b;
for (i = 0; i < 20; i++) { // 将16进制字符转换为高4位
for (i = 0; i < 20; i++) { // 将16进制字符转换为高4位
ch = SerialNumber[i * 2];
if ((ch >= '0') && (ch <= '9')) {
b = ch - '0';
......@@ -233,13 +233,13 @@ static BOOL WMI_DoWithHarddiskSerialNumber(wchar_t *SerialNumber, UINT uSize)
b = ch - 'A' + 10;
} else if ((ch >= 'a') && (ch <= 'f')) {
b = ch - 'a' + 10;
} else { // 非法字符
} else { // 非法字符
break;
}
b <<= 4;
// 将16进制字符转换为低4位
// 将16进制字符转换为低4位
ch = SerialNumber[i * 2 + 1];
if ((ch >= '0') && (ch <= '9')) {
b += ch - '0';
......@@ -247,48 +247,48 @@ static BOOL WMI_DoWithHarddiskSerialNumber(wchar_t *SerialNumber, UINT uSize)
b += ch - 'A' + 10;
} else if ((ch >= 'a') && (ch <= 'f')) {
b += ch - 'a' + 10;
} else { // 非法字符
} else { // 非法字符
break;
}
szBuf[i] = b;
}
if (i == 20) { // 转换成功
if (i == 20) { // 转换成功
szBuf[i] = L'\0';
StringCchCopyW(SerialNumber, uSize, szBuf);
iLen = wcslen(SerialNumber);
}
}
// 每2个字符互换位置
// 每2个字符互换位置
for (i = 0; i < iLen; i += 2) {
std::swap(SerialNumber[i], SerialNumber[i + 1]);
}
// 去掉空格
// 去掉空格
std::remove(SerialNumber, SerialNumber + wcslen(SerialNumber) + 1, L' ');
return TRUE;
}
// 通过“PNPDeviceID”获取网卡原生MAC地址
// 通过“PNPDeviceID”获取网卡原生MAC地址
static BOOL WMI_DoWithPNPDeviceID(const wchar_t *PNPDeviceID, wchar_t *MacAddress, UINT uSize)
{
wchar_t DevicePath[MAX_PATH];
HANDLE hDeviceFile;
BOOL isOK = FALSE;
// 生成设备路径名
// 生成设备路径名
StringCchCopyW(DevicePath, MAX_PATH, L"\\\\.\\");
StringCchCatW(DevicePath, MAX_PATH, PNPDeviceID);
// {ad498944-762f-11d0-8dcb-00c04fc3358c} is 'Device Interface Name' for 'Network Card'
StringCchCatW(DevicePath, MAX_PATH, L"#{ad498944-762f-11d0-8dcb-00c04fc3358c}");
// 将“PNPDeviceID”中的“/”替换成“#”,以获得真正的设备路径名
// 将“PNPDeviceID”中的“/”替换成“#”,以获得真正的设备路径名
std::replace(DevicePath + 4, DevicePath + 4 + wcslen(PNPDeviceID), (int)L'\\', (int)L'#');
// 获取设备句柄
// 获取设备句柄
hDeviceFile = CreateFileW(DevicePath,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
......@@ -302,15 +302,15 @@ static BOOL WMI_DoWithPNPDeviceID(const wchar_t *PNPDeviceID, wchar_t *MacAddres
BYTE ucData[8];
DWORD dwByteRet;
// 获取网卡原生MAC地址
// 获取网卡原生MAC地址
dwID = OID_802_3_PERMANENT_ADDRESS;
isOK = DeviceIoControl(hDeviceFile, IOCTL_NDIS_QUERY_GLOBAL_STATS, &dwID, sizeof(dwID), ucData, sizeof(ucData), &dwByteRet, NULL);
if (isOK) { // 将字节数组转换成16进制字符串
if (isOK) { // 将字节数组转换成16进制字符串
for (DWORD i = 0; i < dwByteRet; i++) {
StringCchPrintfW(MacAddress + (i << 1), uSize - (i << 1), L"%02X", ucData[i]);
}
MacAddress[dwByteRet << 1] = L'\0'; // 写入字符串结束标记
MacAddress[dwByteRet << 1] = L'\0'; // 写入字符串结束标记
}
CloseHandle(hDeviceFile);
......@@ -324,18 +324,18 @@ static BOOL WMI_DoWithProperty(QueryType queryType, wchar_t *szProperty, UINT uS
{
BOOL isOK = TRUE;
switch (queryType) {
case MAC_ADDR_REAL: // 网卡原生MAC地址
case MAC_ADDR_REAL: // 网卡原生MAC地址
isOK = WMI_DoWithPNPDeviceID(szProperty, szProperty, uSize);
break;
case HARDDISK_SERIAL: // 硬盘序列号
case HARDDISK_SERIAL: // 硬盘序列号
isOK = WMI_DoWithHarddiskSerialNumber(szProperty, uSize);
break;
case MAC_ADDR: // 网卡当前MAC地址
// 去掉冒号
case MAC_ADDR: // 网卡当前MAC地址
// 去掉冒号
std::remove(szProperty, szProperty + wcslen(szProperty) + 1, L':');
break;
default:
// 去掉空格
// 去掉空格
std::remove(szProperty, szProperty + wcslen(szProperty) + 1, L' ');
}
return isOK;
......@@ -437,12 +437,12 @@ static bool query(size_t queryTypes, std::unordered_map<QueryType, std::wstring>
return ok;
}
// 基于Windows Management Instrumentation(Windows管理规范)
// 基于Windows Management Instrumentation(Windows管理规范)
static bool query(const std::vector<QueryType>& queryTypes, std::unordered_map<QueryType, std::wstring>& results)
{
bool ok = false;
// 初始化COM COINIT_APARTMENTTHREADED
// 初始化COM COINIT_APARTMENTTHREADED
HRESULT hres = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hres)) {
#ifndef __AFXWIN_H__
......@@ -469,7 +469,7 @@ static bool query(const std::vector<QueryType>& queryTypes, std::unordered_map<Q
}
}
// 设置COM的安全认证级别
// 设置COM的安全认证级别
hres = CoInitializeSecurity(
NULL,
-1,
......@@ -501,7 +501,7 @@ static bool query(const std::vector<QueryType>& queryTypes, std::unordered_map<Q
return false;
}
}
// 获得WMI连接COM接口
// 获得WMI连接COM接口
IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(
CLSID_WbemLocator,
......@@ -518,7 +518,7 @@ static bool query(const std::vector<QueryType>& queryTypes, std::unordered_map<Q
return false;
}
// 通过连接接口连接WMI的内核对象名"ROOT//CIMV2"
// 通过连接接口连接WMI的内核对象名"ROOT//CIMV2"
IWbemServices *pSvc = NULL;
hres = pLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"),
......@@ -539,7 +539,7 @@ static bool query(const std::vector<QueryType>& queryTypes, std::unordered_map<Q
return false;
}
// 设置请求代理的安全级别
// 设置请求代理的安全级别
hres = CoSetProxyBlanket(
pSvc,
RPC_C_AUTHN_WINNT,
......@@ -568,7 +568,7 @@ static bool query(const std::vector<QueryType>& queryTypes, std::unordered_map<Q
auto query = detail::getWQLQuery(queryType);
// 通过请求代理来向WMI发送请求
// 通过请求代理来向WMI发送请求
IEnumWbemClassObject *pEnumerator = NULL;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
......@@ -588,7 +588,7 @@ static bool query(const std::vector<QueryType>& queryTypes, std::unordered_map<Q
continue;
}
// 循环枚举所有的结果对象
// 循环枚举所有的结果对象
while (pEnumerator) {
IWbemClassObject *pclsObj = NULL;
ULONG uReturn = 0;
......@@ -604,7 +604,7 @@ static bool query(const std::vector<QueryType>& queryTypes, std::unordered_map<Q
break;
}
// 获取属性值
// 获取属性值
{
VARIANT vtProperty;
VariantInit(&vtProperty);
......@@ -612,7 +612,7 @@ static bool query(const std::vector<QueryType>& queryTypes, std::unordered_map<Q
detail::DeviceProperty deviceProperty{};
StringCchCopyW(deviceProperty.szProperty, detail::DeviceProperty::PROPERTY_MAX_LEN, vtProperty.bstrVal);
VariantClear(&vtProperty);
// 对属性值做进一步的处理
// 对属性值做进一步的处理
if (detail::WMI_DoWithProperty(queryType, deviceProperty.szProperty, detail::DeviceProperty::PROPERTY_MAX_LEN)) {
results[queryType] = (deviceProperty.szProperty);
ok = true;
......@@ -623,7 +623,7 @@ static bool query(const std::vector<QueryType>& queryTypes, std::unordered_map<Q
pclsObj->Release();
} // End While
// 释放资源
// 释放资源
pEnumerator->Release();
}
......
// FileOper.h: interface for the CFileOper class.
// FileOper.h: interface for the CFileOper class.
//
//////////////////////////////////////////////////////////////////////
......@@ -18,10 +18,10 @@ static int CALLBACK BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lParam,LPARAM
{
switch(uMsg)
{
case BFFM_INITIALIZED: //初始化消息
case BFFM_INITIALIZED: //初始化消息
::SendMessage(hwnd,BFFM_SETSELECTION,TRUE,lpData);
break;
case BFFM_SELCHANGED: //选择路径变化,
case BFFM_SELCHANGED: //选择路径变化,
{
TCHAR curr[MAX_PATH];
SHGetPathFromIDList((LPCITEMIDLIST)lParam,curr);
......@@ -37,7 +37,7 @@ static int CALLBACK BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lParam,LPARAM
class CFileOper
{
public:
// 弹出文件夹选择对话框,并返回选定的文件夹路径
// 弹出文件夹选择对话框,并返回选定的文件夹路径
static BOOL BrowseGetPath(CString &path, HWND hWnd){
TCHAR szPath[MAX_PATH] = {0};
BROWSEINFO bi;
......@@ -58,7 +58,7 @@ public:
return TRUE;
}
// 删除该路径下所有文件与文件夹
// 删除该路径下所有文件与文件夹
static BOOL DeleteFolderAndAllSubFolder_Files(LPCTSTR folderPath){
system("echo delete old folder and sub files...\n");
//CString cmd = _T("");
......@@ -77,7 +77,7 @@ public:
return ret;
}
// 获取文件大小
// 获取文件大小
static long GetFileSize(const CString& path){
FILE *p = NULL;
#if defined(_UNICODE) || defined(UNICODE)
......@@ -100,7 +100,7 @@ public:
return len;
}
// 获取路径中最右的文件夹名称,如D:\A\B,返回B
// 获取路径中最右的文件夹名称,如D:\A\B,返回B
static CString GetCurFolderFromFullPath(const CString& strpath)
{
int pos = -1;
......@@ -110,7 +110,7 @@ public:
return _T("");
}
// 获取文件路径中的文件夹路径,如D:/A/B.TXT, 返回D:/A
// 获取文件路径中的文件夹路径,如D:/A/B.TXT, 返回D:/A
static CString GetFolderPathFromFilePath(const CString& strpath)
{
int pos = -1;
......@@ -120,7 +120,7 @@ public:
return _T("");
}
// 复制文件夹到目的,并弹出文件夹复制对话框
// 复制文件夹到目的,并弹出文件夹复制对话框
static BOOL CopyFolder(const CString& dstFolder, const CString& srcFolder, HWND hWnd)
{
TCHAR szDst[MAX_PATH], szSrc[MAX_PATH];
......@@ -143,17 +143,17 @@ public:
return ret == 0 && lpFile.fAnyOperationsAborted == FALSE;
}
// 判断指定路径是否存在(文件夹)
// 判断指定路径是否存在(文件夹)
static BOOL IsFolderExists(LPCTSTR lpszFolderPath){
return FindFirstFileExists(lpszFolderPath, FILE_ATTRIBUTE_DIRECTORY);
}
// 判断指定路径是否存在(文件或文件夹)
// 判断指定路径是否存在(文件或文件夹)
static BOOL PathExists(LPCTSTR lpszPath){
return FindFirstFileExists(lpszPath, FALSE);
}
// 更改文件名后缀名
// 更改文件名后缀名
static CString ChangeFileExt(const CString& srcFilePath, const CString& dstExt){
CString dstFilePath = srcFilePath;
int pos = srcFilePath.ReverseFind(_T('.'));
......@@ -164,7 +164,7 @@ public:
return dstFilePath;
}
// 从文件路径中获取文件标题,如D:\AAA.TXT或者AAA.TXT,返回AAA
// 从文件路径中获取文件标题,如D:\AAA.TXT或者AAA.TXT,返回AAA
static CString GetFileTitle(const CString& fileName){
CString title = _T("");
int pos = -1;
......@@ -178,7 +178,7 @@ public:
return title;
}
// 从文件路径中获取文件后缀名,如D:\AAA.TXT,返回TXT
// 从文件路径中获取文件后缀名,如D:\AAA.TXT,返回TXT
static CString GetFileExt(const CString& filePath){
CString ext = _T("");
int pos = filePath.ReverseFind(_T('.'));
......@@ -189,7 +189,7 @@ public:
return ext;
}
// 从文件路径中获取文件名,如D:\AAA.TXT,返回AAA.TXT
// 从文件路径中获取文件名,如D:\AAA.TXT,返回AAA.TXT
static CString GetFileNameFromPathName(const CString& filePathName){
CString fileName = _T("");
int pos = filePathName.ReverseFind(_T('\\'));
......@@ -199,7 +199,7 @@ public:
return fileName;
}
// 寻找目录(该路径不能以 \ 结尾)下所有指定后缀名(不支持*.*)的文件,并将结果保存在CStringList中,
// 寻找目录(该路径不能以 \ 结尾)下所有指定后缀名(不支持*.*)的文件,并将结果保存在CStringList中,
static int FindFilesInFolder(LPCTSTR lpszFolder, LPCTSTR lpszFilter, CStringList &dstList){
if(lstrlen(lpszFolder) == 0)
return 0;
......@@ -222,7 +222,7 @@ public:
return nNums;
}
// 将目录下符合 *n.* 的文件(n代表数字)重命名为 *00n.*的形式,将n格式化为3位数
// 将目录下符合 *n.* 的文件(n代表数字)重命名为 *00n.*的形式,将n格式化为3位数
static BOOL RenameFile03d(LPCTSTR lpszFilePath){
CString fileName = lpszFilePath;
CString tittle, num, ext, newFileName;
......@@ -263,7 +263,7 @@ public:
return TRUE;
}
// 删除所有该目录路径下指定后缀名的文件
// 删除所有该目录路径下指定后缀名的文件
static DWORD DeleteFilesInFolder(LPCTSTR lpszFolder, LPCTSTR lpszFilter){
DWORD dwDeletedFileNums = 0;
CFileFind find;
......
......@@ -17,6 +17,41 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_json", "test_json\test
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_timestamp", "test_timestamp\test_timestamp.vcxproj", "{372670F2-83A5-4058-B93C-BB0DCC1521ED}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "jlib", "jlib", "{42703978-A988-403D-9723-E35527FA8A07}"
ProjectSection(SolutionItems) = preProject
..\jlib\chrono_wrapper.h = ..\jlib\chrono_wrapper.h
..\jlib\dp.h = ..\jlib\dp.h
..\jlib\log.h = ..\jlib\log.h
..\jlib\log2.h = ..\jlib\log2.h
..\jlib\mem_tool.h = ..\jlib\mem_tool.h
..\jlib\micro_getter_setter.h = ..\jlib\micro_getter_setter.h
..\jlib\net.h = ..\jlib\net.h
..\jlib\space.h = ..\jlib\space.h
..\jlib\std_util.h = ..\jlib\std_util.h
..\jlib\utf8.h = ..\jlib\utf8.h
..\jlib\version_no.h = ..\jlib\version_no.h
..\jlib\vs_ver.h = ..\jlib\vs_ver.h
..\jlib\win32.h = ..\jlib\win32.h
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "thirdparty", "thirdparty", "{5A2CA1BE-5A4B-41B0-B74A-F86AB433F4A5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "base", "base", "{608A105E-40DB-44FD-8FC2-A66AB921688D}"
ProjectSection(SolutionItems) = preProject
..\jlib\base\cast.h = ..\jlib\base\cast.h
..\jlib\base\config.h = ..\jlib\base\config.h
..\jlib\base\copyable.h = ..\jlib\base\copyable.h
..\jlib\base\currentthread.h = ..\jlib\base\currentthread.h
..\jlib\base\logging.h = ..\jlib\base\logging.h
..\jlib\base\logstream.h = ..\jlib\base\logstream.h
..\jlib\base\noncopyable.h = ..\jlib\base\noncopyable.h
..\jlib\base\singleton.h = ..\jlib\base\singleton.h
..\jlib\base\stringpiece.h = ..\jlib\base\stringpiece.h
..\jlib\base\timestamp.h = ..\jlib\base\timestamp.h
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_singleton", "test_singleton\test_singleton.vcxproj", "{B4B8F20B-1B3E-42CD-8B37-A734EF3CA279}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
......@@ -79,10 +114,22 @@ Global
{372670F2-83A5-4058-B93C-BB0DCC1521ED}.Release|x64.Build.0 = Release|x64
{372670F2-83A5-4058-B93C-BB0DCC1521ED}.Release|x86.ActiveCfg = Release|Win32
{372670F2-83A5-4058-B93C-BB0DCC1521ED}.Release|x86.Build.0 = Release|Win32
{B4B8F20B-1B3E-42CD-8B37-A734EF3CA279}.Debug|x64.ActiveCfg = Debug|x64
{B4B8F20B-1B3E-42CD-8B37-A734EF3CA279}.Debug|x64.Build.0 = Debug|x64
{B4B8F20B-1B3E-42CD-8B37-A734EF3CA279}.Debug|x86.ActiveCfg = Debug|Win32
{B4B8F20B-1B3E-42CD-8B37-A734EF3CA279}.Debug|x86.Build.0 = Debug|Win32
{B4B8F20B-1B3E-42CD-8B37-A734EF3CA279}.Release|x64.ActiveCfg = Release|x64
{B4B8F20B-1B3E-42CD-8B37-A734EF3CA279}.Release|x64.Build.0 = Release|x64
{B4B8F20B-1B3E-42CD-8B37-A734EF3CA279}.Release|x86.ActiveCfg = Release|Win32
{B4B8F20B-1B3E-42CD-8B37-A734EF3CA279}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{5A2CA1BE-5A4B-41B0-B74A-F86AB433F4A5} = {42703978-A988-403D-9723-E35527FA8A07}
{608A105E-40DB-44FD-8FC2-A66AB921688D} = {42703978-A988-403D-9723-E35527FA8A07}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A8EBEA58-739C-4DED-99C0-239779F57D5D}
EndGlobalSection
......
......@@ -14,6 +14,7 @@
#include "jlib/vs_ver.h"
#include "jlib/win32.h"
#include <jlib/3rdparty/win32/Registry.hpp>
#include <jlib/win32/mfc/FileOper.h>
int main()
......
......@@ -106,6 +106,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(BOOST);$(DEVLIBS)\jlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
......
......@@ -102,6 +102,7 @@
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(BOOST);$(DEVLIBS)\jlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
......
......@@ -102,6 +102,7 @@
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(BOOST);$(DEVLIBS)\jlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
......
#include "../../jlib/base/singleton.h"
#include "../../jlib/base/currentthread.h"
#include <stdio.h>
#include <thread>
#include <string>
class Test
{
public:
Test() {
printf("tid=%lld, constructing %p\n", jlib::CurrentThread::tid(), this);
}
~Test() {
printf("tid=%lld, destructing %p %s\n", jlib::CurrentThread::tid(), this, name_.c_str());
}
const std::string& name() const { return name_; }
void setName(const std::string& n) { name_ = n; }
private:
std::string name_ = {};
};
class TestNoDestroy
{
public:
void no_destroy();
TestNoDestroy() {
printf("tid=%lld, constructing TestNoDestroy %p\n", jlib::CurrentThread::tid(), this);
}
~TestNoDestroy() {
printf("tid=%lld, destructing TestNoDestroy %p\n", jlib::CurrentThread::tid(), this);
}
};
void func()
{
printf("tid=%lld, %p name=%s\n",
jlib::CurrentThread::tid(),
&jlib::singleton<Test>::instance(),
jlib::singleton<Test>::instance().name().c_str());
jlib::singleton<Test>::instance().setName("only once, changed");
}
int main()
{
printf("pid=%ld\n", GetCurrentProcessId());
printf("tid=%lld\n", jlib::CurrentThread::tid());
jlib::singleton<Test>::instance().setName("only once");
std::thread thread(func);
thread.join();
printf("tid=%lld, %p name=%s\n",
jlib::CurrentThread::tid(),
&jlib::singleton<Test>::instance(),
jlib::singleton<Test>::instance().name().c_str());
jlib::singleton<TestNoDestroy>::instance();
printf("with valgrind, you should see %zd-byte memory leak.\n", sizeof(TestNoDestroy));
//system("pause");
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{B4B8F20B-1B3E-42CD-8B37-A734EF3CA279}</ProjectGuid>
<RootNamespace>testsingleton</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="test_singleton.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="test_singleton.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>
\ No newline at end of file
......@@ -129,6 +129,7 @@
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>$(BOOST);$(DEVLIBS)\jlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment