diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..c099d3eb3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +# cache +*.~ +*.bk +*.org +*.old + +# output +*.o +bin + +# IDE +.vs +.vscode + +# test +test \ No newline at end of file diff --git a/base64.cpp b/base64.cpp new file mode 100644 index 000000000..dcb6e87b6 --- /dev/null +++ b/base64.cpp @@ -0,0 +1,135 @@ +/* This is a public domain base64 implementation written by WEI Zhicheng. */ + +#include + +#include "base64.h" + +/* BASE 64 encode table */ +static const char base64en[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/', +}; + +#define BASE64_PAD '=' + + +#define BASE64DE_FIRST '+' +#define BASE64DE_LAST 'z' +/* ASCII order for BASE 64 decode, -1 in unused character */ +static const signed char base64de[] = { + /* '+', ',', '-', '.', '/', '0', '1', '2', */ + 62, -1, -1, -1, 63, 52, 53, 54, + + /* '3', '4', '5', '6', '7', '8', '9', ':', */ + 55, 56, 57, 58, 59, 60, 61, -1, + + /* ';', '<', '=', '>', '?', '@', 'A', 'B', */ + -1, -1, -1, -1, -1, -1, 0, 1, + + /* 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', */ + 2, 3, 4, 5, 6, 7, 8, 9, + + /* 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', */ + 10, 11, 12, 13, 14, 15, 16, 17, + + /* 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', */ + 18, 19, 20, 21, 22, 23, 24, 25, + + /* '[', '\', ']', '^', '_', '`', 'a', 'b', */ + -1, -1, -1, -1, -1, -1, 26, 27, + + /* 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', */ + 28, 29, 30, 31, 32, 33, 34, 35, + + /* 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', */ + 36, 37, 38, 39, 40, 41, 42, 43, + + /* 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', */ + 44, 45, 46, 47, 48, 49, 50, 51, +}; + +int +base64_encode(const unsigned char *in, unsigned int inlen, char *out) +{ + unsigned int i, j; + + for (i = j = 0; i < inlen; i++) { + int s = i % 3; /* from 6/gcd(6, 8) */ + + switch (s) { + case 0: + out[j++] = base64en[(in[i] >> 2) & 0x3F]; + continue; + case 1: + out[j++] = base64en[((in[i-1] & 0x3) << 4) + ((in[i] >> 4) & 0xF)]; + continue; + case 2: + out[j++] = base64en[((in[i-1] & 0xF) << 2) + ((in[i] >> 6) & 0x3)]; + out[j++] = base64en[in[i] & 0x3F]; + } + } + + /* move back */ + i -= 1; + + /* check the last and add padding */ + if ((i % 3) == 0) { + out[j++] = base64en[(in[i] & 0x3) << 4]; + out[j++] = BASE64_PAD; + out[j++] = BASE64_PAD; + } else if ((i % 3) == 1) { + out[j++] = base64en[(in[i] & 0xF) << 2]; + out[j++] = BASE64_PAD; + } + + return BASE64_OK; +} + +int +base64_decode(const char *in, unsigned int inlen, unsigned char *out) +{ + unsigned int i, j; + + for (i = j = 0; i < inlen; i++) { + int c; + int s = i % 4; /* from 8/gcd(6, 8) */ + + if (in[i] == '=') + return BASE64_OK; + + if (in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST || + (c = base64de[in[i] - BASE64DE_FIRST]) == -1) + return BASE64_INVALID; + + switch (s) { + case 0: + out[j] = ((unsigned int)c << 2) & 0xFF; + continue; + case 1: + out[j++] += ((unsigned int)c >> 4) & 0x3; + + /* if not last char with padding */ + if (i < (inlen - 3) || in[inlen - 2] != '=') + out[j] = ((unsigned int)c & 0xF) << 4; + continue; + case 2: + out[j++] += ((unsigned int)c >> 2) & 0xF; + + /* if not last char with padding */ + if (i < (inlen - 2) || in[inlen - 1] != '=') + out[j] = ((unsigned int)c & 0x3) << 6; + continue; + case 3: + out[j++] += (unsigned char)c; + } + } + + return BASE64_OK; +} + diff --git a/base64.h b/base64.h new file mode 100644 index 000000000..53f87451b --- /dev/null +++ b/base64.h @@ -0,0 +1,14 @@ +#ifndef __BASE64_H__ +#define __BASE64_H__ + +enum {BASE64_OK = 0, BASE64_INVALID}; + +#define BASE64_ENCODE_OUT_SIZE(s) (((s) + 2) / 3 * 4) +#define BASE64_DECODE_OUT_SIZE(s) (((s)) / 4 * 3) + +int base64_encode(const unsigned char *in, unsigned int inlen, char *out); +int base64_decode(const char *in, unsigned int inlen, unsigned char *out); + + +#endif /* __BASE64_H__ */ + diff --git a/h.h b/h.h new file mode 100644 index 000000000..c815979d9 --- /dev/null +++ b/h.h @@ -0,0 +1,36 @@ +#ifndef H_H +#define H_H + +// platform +#include "hplatform.h" +#ifdef __unix__ +#include "hunix.h" +#endif + +// c +#include "hversion.h" +#include "hdef.h" +#include "htime.h" +#include "hlog.h" +#include "herr.h" + +// cpp +#ifdef __cplusplus +#include "hstring.h" +#include "hthread.h" +#include "hmutex.h" +#include "hscope.h" +#include "singleton.h" + +#include "hvar.h" +#include "hobj.h" + +#include "hbuf.h" +#include "hbytearray.h" +#include "hgui.h" + +#include "hframe.h" +#include "htable.h" +#endif + +#endif // H_H \ No newline at end of file diff --git a/hbuf.h b/hbuf.h new file mode 100644 index 000000000..6ecb4f06d --- /dev/null +++ b/hbuf.h @@ -0,0 +1,194 @@ +#ifndef H_BUF_H +#define H_BUF_H + +#include "hdef.h" +#include +#include +#include + +typedef struct hbuf_s{ + uint8* base; + size_t len; + + hbuf_s(){ + base = NULL; + len = 0; + } + + hbuf_s(uint8* base, size_t len){ + this->base = base; + this->len = len; + } + + void init(size_t cap){ + if (cap == len) return; + + if (!base){ + base = (uint8*)malloc(cap); + memset(base, 0, cap); + }else{ + base = (uint8*)realloc(base, cap); + } + len = cap; + } + + void resize(size_t cap){ + init(cap); + } + + void cleanup(){ + SAFE_FREE(base); + len = 0; + } + + bool isNull(){ + return base == NULL || len == 0; + } +}hbuf_t; + +class HBuf : public hbuf_t{ +public: + HBuf() : hbuf_t(){} + HBuf(size_t cap) {init(cap);} + HBuf(void* data, size_t len){ + init(len); + memcpy(base, data, len); + } + virtual ~HBuf() {cleanup();} + + std::mutex mutex; // used in multi-thread +}; + +// VL: Variable-Length +class HVLBuf : public HBuf{ +public: + HVLBuf() : HBuf() {_offset = _size = 0;} + HVLBuf(size_t cap) : HBuf(cap) {_offset = _size = 0;} + HVLBuf(void* data, size_t len) : HBuf(data, len) {_offset = 0; _size = len;} + virtual ~HVLBuf() {} + + uint8* data() {return base+_offset;} + size_t size() {return _size;} + + void push_front(void* ptr, size_t len){ + if (len > this->len - _size){ + this->len = MAX(this->len, len)*2; + base = (uint8*)realloc(base, this->len); + } + + if (_offset < len){ + // move => end + memmove(base+this->len-_size, data(), _size); + _offset = this->len-_size; + } + + memcpy(data()-len, ptr, len); + _offset -= len; + _size += len; + } + + void push_back(void* ptr, size_t len){ + if (len > this->len - _size){ + this->len = MAX(this->len, len)*2; + base = (uint8*)realloc(base, this->len); + }else if (len > this->len - _offset - _size){ + // move => start + memmove(base, data(), _size); + _offset = 0; + } + memcpy(data()+_size, ptr, len); + _size += len; + } + + void pop_front(void* ptr, size_t len){ + if (len <= _size){ + if (ptr){ + memcpy(ptr, data(), len); + } + _offset += len; + if (_offset >= len) _offset = 0; + _size -= len; + } + } + + void pop_back(void* ptr, size_t len){ + if (len <= _size){ + if (ptr){ + memcpy(ptr, data()+_size-len, len); + } + _size -= len; + } + } + + void clear(){ + _offset = _size = 0; + } + + void prepend(void* ptr, size_t len){ + push_front(ptr, len); + } + + void append(void* ptr, size_t len){ + push_back(ptr, len); + } + + void insert(void* ptr, size_t len){ + push_back(ptr, len); + } + + void remove(size_t len){ + pop_front(NULL, len); + } + +private: + size_t _offset; + size_t _size; +}; + +class HRingBuf : public HBuf{ +public: + HRingBuf() : HBuf() {_head = _tail = _size = 0;} + HRingBuf(size_t cap) : HBuf(cap) {_head = _tail = _size = 0;} + + uint8* alloc(size_t len){ + uint8* ret = NULL; + if (_head < _tail || _size == 0){ + // [_tail, this->len) && [0, _head) + if (this->len - _tail >= len){ + ret = base + _tail; + _tail += len; + if (_tail == this->len) _tail = 0; + }else if(_head >= len){ + ret = base; + _tail = len; + } + }else{ + // [_tail, _head) + if (_head - _tail >= len){ + ret = base + _tail; + _tail += len; + } + } + _size += ret ? len : 0; + return ret; + } + + void free(size_t len){ + _size -= len; + if (len <= this->len - _head){ + _head += len; + if (_head == this->len) _head = 0; + }else{ + _head = len; + } + } + + size_t size() {return _size;} + +private: + size_t _head; + size_t _tail; + size_t _size; +}; + +#endif // H_BUF_H diff --git a/hbytearray.h b/hbytearray.h new file mode 100644 index 000000000..fe1812a68 --- /dev/null +++ b/hbytearray.h @@ -0,0 +1,26 @@ +#ifndef H_BYTE_ARRAY_H +#define H_BYTE_ARRAY_H + +#include "hbuf.h" +#include "base64.h" + +class HByteArray : public HVLBuf{ +public: + HByteArray() : HVLBuf() {} + HByteArray(int cap) : HVLBuf(cap) {} + HByteArray(void* data, int len) : HVLBuf(data, len) {} + + bool encodeBase64(void* ptr, int len){ + int base64_len = BASE64_ENCODE_OUT_SIZE(len) + 1; // +1 for '\0' + init(base64_len); + return base64_encode((unsigned char*)ptr, len, (char*)data()) == BASE64_OK; + } + + bool decodeBase64(const char* base64){ + int out_len = BASE64_DECODE_OUT_SIZE(strlen(base64)); + init(out_len); + return base64_decode(base64, strlen(base64), data()) == BASE64_OK; + } +}; + +#endif // H_BYTE_ARRAY \ No newline at end of file diff --git a/hdef.h b/hdef.h new file mode 100644 index 000000000..be06f953e --- /dev/null +++ b/hdef.h @@ -0,0 +1,66 @@ +#ifndef H_DEF_H +#define H_DEF_H + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; +typedef unsigned long long uint64; + +typedef char int8; +typedef short int16; +typedef int int32; +typedef long long int64; + +typedef float float32; +typedef double float64; + +typedef int BOOL; + +typedef int (*method_t)(void* userdata); +typedef void (*procedure_t)(void* userdata); + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef TRUE +#define TRUE 1L +#endif + +#ifndef FALSE +#define FALSE 0L +#endif + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) + +#define SAFE_FREE(p) do{if (p) {free(p); (p) = NULL;}}while(0) +#define SAFE_DELETE(p) do{if (p) {delete (p); (p) = NULL;}}while(0) +#define SAFE_DELETE_ARRAY(p) do{if (p) {delete[] (p); (p) = NULL;}}while(0) +#define SAFE_RELEASE(p) do{if (p) {(p)->release(); (p) = NULL;}}while(0) + +#ifndef MAKE_FOURCC +#define MAKE_FOURCC(a,b,c,d) \ +( ((uint32)d) | ( ((uint32)c) << 8 ) | ( ((uint32)b) << 16 ) | ( ((uint32)a) << 24 ) ) +#endif + +#define FLOAT_PRECISION 1e-6 +#define FLOAT_EQUAL_ZERO(f) (-FLOAT_PRECISION < (f) && (f) < FLOAT_PRECISION) + +#define STRINGIFY(x) STRINGIFY_HELPER(x) +#define STRINGIFY_HELPER(x) #x + +#define STRINGCAT(x,y) STRINGCAT_HELPER(x,y) +#define STRINGCAT_HELPER(x,y) x##y + +#define container_of(ptr, type, member) \ + ((type *) ((char *) (ptr) - offsetof(type, member))) + +#endif // H_DEF_H \ No newline at end of file diff --git a/herr.cpp b/herr.cpp new file mode 100644 index 000000000..df1a375ab --- /dev/null +++ b/herr.cpp @@ -0,0 +1,41 @@ +#include "herr.h" +#include "hthread.h" // for gettid + +#include + +// id => errcode +static std::map s_mapErr; + +void set_id_errcode(int id, int errcode){ + s_mapErr[id] = errcode; +} + +int get_id_errcode(int id){ + auto iter = s_mapErr.find(id); + if (iter != s_mapErr.end()) { + // note: erase after get + s_mapErr.erase(iter); + return iter->second; + } + return ERR_OK; +} + +void set_last_errcode(int errcode){ + set_id_errcode(gettid(), errcode); +} + +int get_last_errcode(){ + return get_id_errcode(gettid()); +} + +const char* get_errmsg(int err){ + switch(err){ +#define CASE_ERR(macro, errcode, errmsg) \ + case errcode: \ + return errmsg; + FOREACH_ERR(CASE_ERR) +#undef CASE_ERR + default: + return "undefined errcode"; + } +} diff --git a/herr.h b/herr.h new file mode 100644 index 000000000..a898af53a --- /dev/null +++ b/herr.h @@ -0,0 +1,68 @@ +#ifndef H_ERR_H +#define H_ERR_H + +// F(macro, errcode, errmsg) +#define FOREACH_ERR_COMMON(F) \ + F(ERR_OK, 0, "ok") \ + F(ERR_UNKNOWN, 1000, "unknown error") \ + F(ERR_NULL_PARAM, 1001, "null param") \ + F(ERR_NULL_POINTER, 1002, "null pointer") \ + F(ERR_NULL_DATA, 1003, "null data") \ + \ + F(ERR_INVALID_PARAM, 1010, "invalid param") \ + F(ERR_INVALID_HANDLE, 1011, "invalid handle") \ + F(ERR_INVALID_JSON, 1012, "invalid json") \ + F(ERR_INVALID_XML, 1013, "invalid xml") \ + F(ERR_INVALID_FMT, 1014, "invalid format") \ + \ + F(ERR_MISMATCH, 1020, "mismatch") \ + F(ERR_REQUEST, 1021, "error request") \ + F(ERR_RESPONSE, 1022, "error response") \ + \ + F(ERR_MALLOC, 1030, "malloc failed") \ + F(ERR_FREE, 1031, "free failed") \ + \ + F(ERR_TASK_TIMEOUT, 1100, "task timeout") \ + F(ERR_TASK_DEQUE_FULL, 1101, "task deque full") \ + F(ERR_TASK_NOT_CREATE, 1102, "task not create") \ + \ + F(ERR_OPEN_FILE, 1200, "open file failed") \ + F(ERR_SAVE_FILE, 1201, "save file failed") + +#define FOREACH_ERR_NETWORK(F) \ + F(ERR_ADAPTER_NOT_FOUND, 2001, "adapter not found") \ + F(ERR_SERVER_NOT_FOUND, 2002, "server not found") \ + F(ERR_SERVER_UNREACHEABLE, 2003, "server unreacheable") \ + F(ERR_SERVER_DISCONNECT, 2004, "server disconnect") \ + F(ERR_CONNECT_TIMEOUT, 2005, "connect timeout") \ + F(ERR_INVALID_PACKAGE, 2006, "invalid package") \ + F(ERR_SERVER_NOT_STARTUP, 2007, "server not startup") \ + F(ERR_CLIENT_DISCONNECT, 2008, "client disconnect") + +#define FOREACH_ERR_SERVICE(F) \ + F(ERR_GROUP_NOT_FOUND, 3000, "group not found") + +#define FOREACH_ERR(F) \ + FOREACH_ERR_COMMON(F) \ + FOREACH_ERR_NETWORK(F) \ + FOREACH_ERR_SERVICE(F) + +#define ENUM_ERR(macro, errcode, _) macro = errcode, +enum E_ERR{ + FOREACH_ERR(ENUM_ERR) + ERR_LAST +}; +#undef ENUM_ERR + +// id => errcode +void set_id_errcode(int id, int errcode); +int get_id_errcode(int id); + +// id = gettid() +void set_last_errcode(int errcode); +int get_last_errcode(); + +// errcode => errmsg +const char* get_errmsg(int errcode); + +#endif // H_ERR_H diff --git a/hframe.cpp b/hframe.cpp new file mode 100644 index 000000000..448c81c7e --- /dev/null +++ b/hframe.cpp @@ -0,0 +1,65 @@ +#include "hframe.h" + +int HFrameBuf::push(HFrame* pFrame){ + if (pFrame->isNull()) + return -10; + + frame_stats.push_cnt++; + + std::lock_guard locker(mutex); + + if (frames.size() >= cache_num){ + if (policy == HFrameBuf::DISCARD){ + return -20; // note: cache full, discard frame + } + + // note: cache full, remove front, push newer frame + HFrame& frame = frames.front(); + frames.pop_front(); + free(frame.buf.len); + } + + int ret = 0; + if (isNull()){ + init(pFrame->buf.len * cache_num); + ret = 1; // note: first push + + frame_info.w = pFrame->w; + frame_info.h = pFrame->h; + frame_info.type = pFrame->type; + frame_info.bpp = pFrame->bpp; + } + + HFrame frame; + frame.buf.base = alloc(pFrame->buf.len); + frame.buf.len = pFrame->buf.len; + frame.copy(*pFrame); + frames.push_back(frame); + frame_stats.push_ok_cnt++; + + return ret; +} + +int HFrameBuf::pop(HFrame* pFrame){ + frame_stats.pop_cnt++; + + std::lock_guard locker(mutex); + + if (isNull()) + return -10; + + if (frames.size() == 0) + return -20; + + HFrame& frame = frames.front(); + frames.pop_front(); + free(frame.buf.len); + + if (frame.isNull()) + return -30; + + pFrame->copy(frame); + frame_stats.pop_ok_cnt++; + + return 0; +} \ No newline at end of file diff --git a/hframe.h b/hframe.h new file mode 100644 index 000000000..2764b7d4a --- /dev/null +++ b/hframe.h @@ -0,0 +1,84 @@ +#ifndef H_FRAME_H +#define H_FRAME_H + +#include "hbuf.h" +#include + +typedef struct hframe_s{ + hbuf_t buf; + int w; + int h; + int type; + int bpp; + uint64 ts; + void* userdata; + hframe_s(){ + w = h = type = bpp = ts = 0; + userdata = NULL; + } + + bool isNull(){ + return w == 0 || h == 0 || buf.isNull(); + } + + // deep copy + void copy(const hframe_s& rhs){ + this->w = rhs.w; + this->h = rhs.h; + this->type = rhs.type; + this->bpp = rhs.bpp; + this->ts = rhs.ts; + this->userdata = rhs.userdata; + if (this->buf.isNull() || this->buf.len != rhs.buf.len){ + this->buf.init(rhs.buf.len); + } + memcpy(this->buf.base, rhs.buf.base, rhs.buf.len); + } +}HFrame; + +typedef struct frame_info_s{ + int w; + int h; + int type; + int bpp; +}FrameInfo; + +typedef struct frame_stats_s{ + int push_cnt; + int pop_cnt; + + int push_ok_cnt; + int pop_ok_cnt; + + frame_stats_s(){ + push_cnt = pop_cnt = push_ok_cnt = pop_ok_cnt = 0; + } +}FrameStats; + +#define DEFAULT_FRAME_CACHENUM 10 + +class HFrameBuf : public HRingBuf{ +public: + enum CacheFullPolicy{ + SQUEEZE, + DISCARD, + }policy; + + HFrameBuf() : HRingBuf() { + cache_num = DEFAULT_FRAME_CACHENUM; + policy = SQUEEZE; + } + + void setCache(int num) {cache_num = num;} + void setPolicy(CacheFullPolicy policy) {this->policy = policy;} + + int push(HFrame* pFrame); + int pop(HFrame* pFrame); + + int cache_num; + FrameStats frame_stats; + FrameInfo frame_info; + std::deque frames; +}; + +#endif // H_FRAME_H diff --git a/hgl.h b/hgl.h new file mode 100644 index 000000000..59a917282 --- /dev/null +++ b/hgl.h @@ -0,0 +1,15 @@ +#ifndef HGL_H +#define HGL_H + +#include +#include "hframe.h" + +// GL PixelFormat extend +#define GL_I420 0x1910 + +typedef struct GLTexture_s{ + GLuint id; // glGenTextures分配的ID + HFrame frame; +}GLTexture; + +#endif // HGL_H diff --git a/hgui.h b/hgui.h new file mode 100644 index 000000000..120cd5df0 --- /dev/null +++ b/hgui.h @@ -0,0 +1,71 @@ +#ifndef HGUI_H +#define HGUI_H + +#include "hdef.h" + +typedef uint32 HColor; // 0xAARRGGBB + +#define CLR_B(c) ( c & 0xff) +#define CLR_G(c) ((c >> 8) & 0xff) +#define CLR_R(c) ((c >> 16) & 0xff) +#define CLR_A(c) ((c >> 24) & 0xff) +#define ARGB(a, r, g, b) MAKE_FOURCC(a,r,g,b) + +typedef struct hpoint_s{ + int x; + int y; + +#ifdef __cplusplus + hpoint_s(){ + x = y = 0; + } + + hpoint_s(int x, int y){ + this->x = x; + this->y = y; + } +#endif +}HPoint; + +typedef struct hsize_s{ + int w; + int h; + +#ifdef __cplusplus + hsize_s(){ + w = h = 0; + } + + hsize_s(int w, int h){ + this->w = w; + this->h = h; + } +#endif +}HSize; + +typedef struct hrect_s{ + int x; + int y; + int w; + int h; + +#ifdef __cplusplus + hrect_s(){ + x = y = w = h = 0; + } + + hrect_s(int x, int y, int w, int h){ + this->x = x; + this->y = y; + this->w = w; + this->h = h; + } + + int left() {return x;} + int right() {return x+w;} + int top() {return y;} + int bottom() {return y+h;} +#endif +}HRect; + +#endif // HGUI_H diff --git a/hlog.cpp b/hlog.cpp new file mode 100644 index 000000000..b89fa029c --- /dev/null +++ b/hlog.cpp @@ -0,0 +1,85 @@ +#include "hlog.h" +#include +#include +#include +#include +#include "htime.h" // for get_datetime + +#define LOGBUF_SIZE (1<<13) // 8k +#define LOGFILE_MAXSIZE (1<<23) // 8M + +static FILE* s_logfp = NULL; +static char s_logfile[256] = DEFAULT_LOG_FILE; +static int s_loglevel = DEFAULT_LOG_LEVEL; +static char s_logbuf[LOGBUF_SIZE]; +static std::mutex s_mutex; + +int hlog_set_file(const char* logfile) { + if (logfile && strlen(logfile) > 0) { + strncpy(s_logfile, logfile, 256); + } + + if (s_logfp) { + fclose(s_logfp); + s_logfp = NULL; + } + + s_logfp = fopen(s_logfile, "a"); + + return s_logfp ? 0 : -1; +} + +void hlog_set_level(int level){ + s_loglevel = level; +} + +int hlog_printf(int level, const char* fmt, ...) { + if (level < s_loglevel) + return -10; + + const char* pcolor = ""; + const char* plevel = ""; +#define CASE_LOG(id, str, clr) \ + case id: plevel = str; pcolor = clr; break; + + switch (level) { + FOREACH_LOG(CASE_LOG) + } +#undef CASE_LOG + +#ifdef _WIN32 + pcolor = ""; +#endif + + std::lock_guard locker(s_mutex); + + if (!s_logfp){ + if (hlog_set_file(s_logfile) != 0) + return -20; + } + + if (ftell(s_logfp) > LOGFILE_MAXSIZE){ + fclose(s_logfp); + s_logfp = fopen(s_logfile, "w"); + if (!s_logfp) + return -30; + } + + datetime_t now = get_datetime(); + + int len = snprintf(s_logbuf, LOGBUF_SIZE, "%s[%04d:%02d:%02d %02d-%02d-%02d.%03d][%s]: ", + pcolor, now.year, now.month, now.day, now.hour, now.min, now.sec, now.ms, plevel); + va_list ap; + va_start(ap, fmt); + len += vsnprintf(s_logbuf + len, LOGBUF_SIZE-len, fmt, ap); + va_end(ap); + + fprintf(s_logfp, "%s\n", s_logbuf); +#ifndef _WIN32 + fprintf(s_logfp, CL_CLR); +#endif + + fflush(NULL); + + return len; +} diff --git a/hlog.h b/hlog.h new file mode 100644 index 000000000..c60b78a93 --- /dev/null +++ b/hlog.h @@ -0,0 +1,51 @@ +#ifndef H_LOG_H +#define H_LOG_H + +#define CL_CLR "\033[0m" /* 恢复颜色 */ +#define CL_BLACK "\033[30m" /* 黑色字 */ +#define CL_RED "\e[1;31m" /* 红色字 */ +#define CL_GREEN "\e[1;32m" /* 绿色字 */ +#define CL_YELLOW "\e[1;33m" /* 黄色字 */ +#define CL_BLUE "\033[34m" /* 蓝色字 */ +#define CL_PURPLE "\e[1;35m" /* 紫色字 */ +#define CL_SKYBLUE "\e[1;36m" /* 天蓝字 */ +#define CL_WHITE "\033[37m" /* 白色字 */ + +#define CL_BLK_WHT "\033[40;37m" /* 黑底白字 */ +#define CL_RED_WHT "\033[41;37m" /* 红底白字 */ +#define CL_GRE_WHT "\033[42;37m" /* 绿底白字 */ +#define CL_YEW_WHT "\033[43;37m" /* 黄底白字 */ +#define CL_BLUE_WHT "\033[44;37m" /* 蓝底白字 */ +#define CL_PPL_WHT "\033[45;37m" /* 紫底白字 */ +#define CL_SKYB_WHT "\033[46;37m" /* 天蓝底白字 */ +#define CL_WHT_BLK "\033[47;30m" /* 白底黑字 */ + +// F(id, str, clr) +#define FOREACH_LOG(F) \ + F(LOG_LEVEL_DEBUG, "DEBUG", CL_WHITE) \ + F(LOG_LEVEL_INFO, "INFO ", CL_GREEN) \ + F(LOG_LEVEL_WARN, "WARN ", CL_YELLOW) \ + F(LOG_LEVEL_ERROR, "ERROR", CL_RED) \ + F(LOG_LEVEL_FATAL, "FATAL", CL_RED_WHT) + +enum LOG_LEVEL{ + LOG_LEVEL_NONE = 0, +#define ENUM_LOG(id, str, clr) id, + FOREACH_LOG(ENUM_LOG) +#undef ENUM_LOG +}; + +#define DEFAULT_LOG_FILE "./default.log" +#define DEFAULT_LOG_LEVEL LOG_LEVEL_NONE + +int hlog_set_file(const char* file); +void hlog_set_level(int level); +int hlog_printf(int level, const char* fmt, ...); + +#define hlogd(fmt, ...) hlog_printf(LOG_LEVEL_DEBUG, fmt " [%s:%d:%s]", ## __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__) +#define hlogi(fmt, ...) hlog_printf(LOG_LEVEL_INFO, fmt " [%s:%d:%s]", ## __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__) +#define hlogw(fmt, ...) hlog_printf(LOG_LEVEL_WARN, fmt " [%s:%d:%s]", ## __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__) +#define hloge(fmt, ...) hlog_printf(LOG_LEVEL_ERROR, fmt " [%s:%d:%s]", ## __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__) +#define hlogf(fmt, ...) hlog_printf(LOG_LEVEL_FATAL, fmt " [%s:%d:%s]", ## __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__) + +#endif // H_LOG_H diff --git a/hmutex.h b/hmutex.h new file mode 100644 index 000000000..f7f99b004 --- /dev/null +++ b/hmutex.h @@ -0,0 +1,36 @@ +#ifndef H_MUTEX_H +#define H_MUTEX_H + +#include "hplatform.h" + +#ifdef _MSC_VER +class RWLock{ +public: + RWLock() { InitializeSRWLock(&_rwlock); } + ~RWLock() { } + + void rdlock() { AcquireSRWLockShared(&_rwlock); } + void rdunlock() { ReleaseSRWLockShared(&_rwlock); } + + void wrlock() { AcquireSRWLockExclusive(&_rwlock); } + void wrunlock() { ReleaseSRWLockExclusive(&_rwlock); } +private: + SRWLOCK _rwlock; +}; +#else +class RWLock{ +public: + RWLock() { pthread_rwlock_init(&_rwlock, NULL); } + ~RWLock() { pthread_rwlock_destroy(&_rwlock); } + + void rdlock() { pthread_rwlock_rdlock(&_rwlock); } + void rdunlock() { pthread_rwlock_unlock(&_rwlock); } + + void wrlock() { pthread_rwlock_wrlock(&_rwlock); } + void wrunlock() { pthread_rwlock_unlock(&_rwlock); } +private: + pthread_rwlock_t _rwlock; +}; +#endif + +#endif // H_MUTEX_H diff --git a/hobj.h b/hobj.h new file mode 100644 index 000000000..ff4fe014f --- /dev/null +++ b/hobj.h @@ -0,0 +1,84 @@ +#ifndef H_OBJ_H +#define H_OBJ_H + +#include "hdef.h" +#include "hvar.h" +#include +#include +#include + +class HObj{ +public: + HObj(HObj* parent = NULL) { + _parent = parent; + } + + virtual ~HObj() { + auto iter = children.begin(); + while (iter != children.end()) { + SAFE_DELETE(*iter); + iter++; + } + } + + std::string name() { + return _objName; + } + + void setName(char* name) { + _objName = name; + } + + HObj* parent() { + return _parent; + } + + void setParent(HObj* ptr) { + _parent = ptr; + } + + void setChild(HObj* ptr) { + children.push_back(ptr); + } + + HObj* findChild(std::string objName) { + auto iter = children.begin(); + while (iter != children.end()) { + if ((*iter)->name() == objName) + return *iter; + iter++; + } + } + + HVar property(std::string key) { + auto iter = properties.find(key); + if (iter != properties.end()) + return iter->second; + return HVar(); + } + + void setProperty(std::string key, HVar value) { + properties[key] = value; + } + + method_t method(std::string key) { + auto iter = methods.find(key); + if (iter != methods.end()) + return iter->second; + return NULL; + } + + void setMethod(std::string key, method_t method) { + methods[key] = method; + } + +public: + std::string _objName; + std::map properties; + std::map methods; + + HObj* _parent; + std::list children; +}; + +#endif \ No newline at end of file diff --git a/hplatform.h b/hplatform.h new file mode 100644 index 000000000..ae170394b --- /dev/null +++ b/hplatform.h @@ -0,0 +1,27 @@ +#ifndef H_PLATFORM_H +#define H_PLATFORM_H + +#ifdef _MSC_VER + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + #include + #include + #undef WIN32_LEAN_AND_MEAN +#else + #include + #include + #include + + #include + #define stricmp strcasecmp + #define strnicmp strncasecmp +#endif + +#ifdef __GNUC__ + #define GNUC_ALIGN(n) __attribute__((aligned(n))) +#else + #define GNUC_ALIGN(n) +#endif + +#endif // H_PLATFORM_H \ No newline at end of file diff --git a/hscope.h b/hscope.h new file mode 100644 index 000000000..6b77a1d40 --- /dev/null +++ b/hscope.h @@ -0,0 +1,51 @@ +#ifndef H_SCOPE_H +#define H_SCOPE_H + +#include "hdef.h" + +template +class ScopeFree{ +public: + ScopeFree(T* p) : _p(p) {} + ~ScopeFree() {SAFE_FREE(_p);} +private: + T* _p; +}; + +template +class ScopeDelete{ +public: + ScopeDelete(T* p) : _p(p) {} + ~ScopeDelete() {SAFE_DELETE(_p);} +private: + T* _p; +}; + +template +class ScopeDeleteArray{ +public: + ScopeDeleteArray(T* p) : _p(p) {} + ~ScopeDeleteArray() {SAFE_DELETE_ARRAY(_p);} +private: + T* _p; +}; + +template +class ScopeRelease{ +public: + ScopeRelease(T* p) : _p(p) {} + ~ScopeRelease() {SAFE_RELEASE(_p);} +private: + T* _p; +}; + +template +class ScopeLock{ +public: + ScopeLock(T& mutex) : _mutex(mutex) {_mutex.lock();} + ~ScopeLock() {_mutex.unlock();} +private: + T& _mutex; +}; + +#endif // H_SCOPE_H \ No newline at end of file diff --git a/hstring.cpp b/hstring.cpp new file mode 100644 index 000000000..b43bae890 --- /dev/null +++ b/hstring.cpp @@ -0,0 +1,118 @@ +#include "hstring.h" +#include +#include +#include +#include +#include + +int vscprintf(const char* fmt, va_list ap) { + return vsnprintf(NULL, 0, fmt, ap); +} + +std::string asprintf(const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + int len = vscprintf(fmt, ap) + 1; + va_end(ap); + // must recall va_start in linux + va_start(ap, fmt); + char* buf = (char*)malloc(len); + vsnprintf(buf, len, fmt, ap); + va_end(ap); + buf[len-1] = '\0'; + std::string res(buf); + free(buf); + return res; +} + +StringList split(std::string& str, char delim){ + std::stringstream ss; + ss << str; + std::string item; + StringList res; + while (std::getline(ss, item, delim)){ + res.push_back(item); + } + return res; +} + +std::string trim(std::string& str){ + std::string::size_type pos1 = str.find_first_not_of(" \t\r\n"); + if (pos1 == std::string::npos) return ""; + + std::string::size_type pos2 = str.find_last_not_of(" \t\r\n"); + return str.substr(pos1, pos2-pos1+1); +} + +std::string replace(std::string& str, std::string& find, std::string& rep){ + std::string::size_type pos = 0; + std::string::size_type a = find.size(); + std::string::size_type b = rep.size(); + while ((pos = str.find(find,pos)) != std::string::npos){ + str.replace(pos, a, rep); + pos += b; + } + return str; +} + +string basename(string& str){ + string::size_type pos1 = str.find_last_not_of("/\\"); + if (pos1 == string::npos){ + return "/"; + } + string::size_type pos2 = str.find_last_of("/\\", pos1); + if (pos2 == string::npos){ + pos2 = 0; + }else{ + pos2++; + } + + return str.substr(pos2, pos1-pos2+1); +} + +string dirname(string& str){ + string::size_type pos1 = str.find_last_not_of("/\\"); + if (pos1 == string::npos){ + return "/"; + } + string::size_type pos2 = str.find_last_of("/\\", pos1); + if (pos2 == string::npos){ + return "."; + }else if (pos2 == 0){ + pos2 = 1; + } + + return str.substr(0, pos2); +} + +string filename(string& str){ + string::size_type pos1 = str.find_last_of("/\\"); + if (pos1 == string::npos){ + pos1 = 0; + }else{ + pos1++; + } + string file = str.substr(pos1, -1); + + string::size_type pos2 = file.find_last_of("."); + if (pos2 == string::npos){ + return file; + } + return file.substr(0, pos2); +} + +string suffixname(string& str){ + string::size_type pos1 = str.find_last_of("/\\"); + if (pos1 == string::npos){ + pos1 = 0; + }else{ + pos1++; + } + string file = str.substr(pos1, -1); + + string::size_type pos2 = file.find_last_of("."); + if (pos2 == string::npos){ + return ""; + } + return file.substr(pos2+1, -1); +} diff --git a/hstring.h b/hstring.h new file mode 100644 index 000000000..7c9811e62 --- /dev/null +++ b/hstring.h @@ -0,0 +1,19 @@ +#ifndef H_STRING_H +#define H_STRING_H + +#include +#include +using std::string; + +typedef std::vector StringList; + +string asprintf(const char* fmt, ...); +StringList split(string& str, char delim); +string trim(string& str); + +string basename(string& str); +string dirname(string& str); +string filename(string& str); +string suffixname(string& str); + +#endif // H_STRING_H diff --git a/htable.cpp b/htable.cpp new file mode 100644 index 000000000..a25424440 --- /dev/null +++ b/htable.cpp @@ -0,0 +1,50 @@ +#include "htable.h" +#include "hdef.h" + +HTable::HTable(){ + row = col = 0; +} + +void HTable::init(int row, int col){ + this->row = row; + this->col = col; + m_mapCells.clear(); + for (int r = 1; r <= row; ++r){ + for (int c = 1; c <= col; ++c){ + int id = (r-1) * col + c; + m_mapCells[id] = HTableCell(r,r,c,c); + } + } +} + +bool HTable::getTableCell(int id, HTableCell& rst){ + if (m_mapCells.find(id) != m_mapCells.end()){ + rst = m_mapCells[id]; + return true; + } + return false; +} + +HTableCell HTable::merge(int lt, int rb){ + HTableCell cell_lt,cell_rb; + if (getTableCell(lt, cell_lt) && getTableCell(rb, cell_rb)){ + int r1 = MIN(cell_lt.r1, cell_rb.r1); + int r2 = MAX(cell_lt.r2, cell_rb.r2); + int c1 = MIN(cell_lt.c1, cell_rb.c1); + int c2 = MAX(cell_lt.c2, cell_rb.c2); + + HTableCell cell(r1, r2, c1, c2); + std::map::iterator iter = m_mapCells.begin(); + while (iter != m_mapCells.end()){ + if (cell.contain(iter->second)){ + iter = m_mapCells.erase(iter); + }else + ++iter; + } + m_mapCells[lt] = cell; + + return cell; + } + + return HTableCell(0,0,0,0); +} diff --git a/htable.h b/htable.h new file mode 100644 index 000000000..acee10a2e --- /dev/null +++ b/htable.h @@ -0,0 +1,45 @@ +#ifndef H_TABLE_H +#define H_TABLE_H + +#include + +class HTableCell{ +public: + HTableCell(){r1=r2=c1=c2=0;} + HTableCell(int r1, int r2, int c1, int c2){ + this->r1 = r1; + this->r2 = r2; + this->c1 = c1; + this->c2 = c2; + } + + int rowspan() {return r2 - r1 + 1;} + int colspan() {return c2 - c1 + 1;} + int span() {return rowspan() * colspan();} + + bool contain(HTableCell cell){ + if (cell.r1 >= r1 && cell.r2 <= r2 && + cell.c1 >= c1 && cell.c2 <= c2) + return true; + return false; + } + + int r1,r2,c1,c2; +}; + +class HTable +{ +public: + HTable(); + + void init(int row, int col); + bool getTableCell(int id, HTableCell& rst); + HTableCell merge(int lt, int rb); + +public: + int row; + int col; + std::map m_mapCells; // id => HTabelCell +}; + +#endif // H_TABLE_H diff --git a/hthread.h b/hthread.h new file mode 100644 index 000000000..78766b43c --- /dev/null +++ b/hthread.h @@ -0,0 +1,103 @@ +#ifndef H_THREAD_H +#define H_THREAD_H + +#include "hdef.h" +#include "hplatform.h" +#include "htime.h" // for msleep +#include +#include + +#ifdef _MSC_VER +inline uint32 getpid(){ + return GetCurrentProcessId(); +} +#endif + +inline uint32 gettid(){ +#ifdef _MSC_VER + return GetCurrentThreadId(); +#else + return pthread_self(); +#endif +} + +/************************************************ + * HThread + * Status: STOP,RUNNING,PAUSE + * Control: start,stop,pause,resume + * first-level virtual: doTask + * second-level virtual: run +************************************************/ +class HThread{ +public: + HThread() { + status = STOP; + } + + virtual ~HThread() { + + } + + virtual int start() { + if (status == STOP) { + status = RUNNING; + thread = std::thread(&HThread::thread_proc, this); + } + return 0; + } + + virtual int stop() { + if (status != STOP) { + status = STOP; + thread.join(); // wait thread exit + } + return 0; + } + + virtual int pause() { + if (status == RUNNING) { + status = PAUSE; + } + return 0; + } + + virtual int resume() { + if (status == PAUSE) { + status = RUNNING; + } + return 0; + } + + void thread_proc() { + doPrepare(); + run(); + doFinish(); + } + + virtual void run() { + while (status != STOP) { + if (status == PAUSE) { + msleep(1); + continue; + } + + doTask(); + + msleep(1); + } + } + + virtual void doPrepare() {} + virtual void doTask() {} + virtual void doFinish() {} + + std::thread thread; + enum Status { + STOP, + RUNNING, + PAUSE, + }; + std::atomic status; +}; + +#endif // H_THREAD_H diff --git a/htime.cpp b/htime.cpp new file mode 100644 index 000000000..069bab3da --- /dev/null +++ b/htime.cpp @@ -0,0 +1,78 @@ +#include "htime.h" +#include +#include + +void msleep(unsigned long ms){ +#ifdef _MSC_VER + Sleep(ms); +#else + usleep(ms*1000); +#endif +} + +uint64 gettick(){ +#ifdef _MSC_VER + return GetTickCount(); +#else + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec + tv.tv_usec/1000; +#endif +} + +datetime_t get_datetime(){ + datetime_t dt; +#ifdef _MSC_VER + SYSTEMTIME tm; + GetLocalTime(&tm); + dt.year = tm.wYear; + dt.month = tm.wMonth; + dt.day = tm.wDay; + dt.hour = tm.wHour; + dt.min = tm.wMinute; + dt.sec = tm.wSecond; + dt.ms = tm.wMilliseconds; +#else + struct timeval tv; + struct tm* tm = NULL; + gettimeofday(&tv, NULL); + time_t tt = tv.tv_sec; + tm = localtime(&tt); + + dt.year = tm->tm_year + 1900; + dt.month = tm->tm_mon + 1; + dt.day = tm->tm_mday; + dt.hour = tm->tm_hour; + dt.min = tm->tm_min; + dt.sec = tm->tm_sec; + dt.ms = tv.tv_usec/1000; +#endif + return dt; +} + +static const char* s_month[] = {"January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December"}; + +int month_atoi(const char* month){ + for (int i = 0; i < ARRAY_SIZE(s_month); ++i){ + if (strnicmp(month, s_month[i], strlen(month)) == 0) + return i+1; + } + return 0; +} + +const char* month_itoa(int month){ + if (month < 1 || month > 12){ + return NULL; + } + return s_month[month-1]; +} + +datetime_t get_compile_datetime(){ + static datetime_t dt; + char month[32]; + sscanf(__DATE__, "%s %d %d", month, &dt.day, &dt.year); + sscanf(__TIME__, "%d %d %d", &dt.hour, &dt.min, &dt.sec); + dt.month = month_atoi(month); + return dt; +} diff --git a/htime.h b/htime.h new file mode 100644 index 000000000..e86a417f4 --- /dev/null +++ b/htime.h @@ -0,0 +1,34 @@ +#ifndef H_TIME_H +#define H_TIME_H + +#include "hdef.h" +#include "hplatform.h" +#include + +typedef struct datetime_s{ + int year; + int month; + int day; + int hour; + int min; + int sec; + int ms; +}datetime_t; + +void msleep(unsigned long ms); + +#ifdef _MSC_VER +inline void sleep(unsigned int s){ + Sleep(s*1000); +} +#endif + +uint64 gettick(); + +int month_atoi(const char* month); +const char* month_itoa(int month); + +datetime_t get_datetime(); +datetime_t get_compile_datetime(); + +#endif // H_TIME_H diff --git a/hunix.cpp b/hunix.cpp new file mode 100644 index 000000000..25c851303 --- /dev/null +++ b/hunix.cpp @@ -0,0 +1,39 @@ +#ifdef __unix__ + +#include "hunix.h" + +#include +#include +#include +#include +#include +#include +#include + +void daemonize(){ + pid_t pid = fork(); + if (pid < 0){ + printf("fork error: %d", errno); + return; + } + + if (pid > 0){ + // exit parent process + exit(0); + } + + // child process become process leader + setsid(); + + // set fd + int fd; + if ((fd = open("/dev/null", O_RDWR, 0)) != -1){ + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + if (fd > STDERR_FILENO) + close(fd); + } +} + +#endif // __unix__ \ No newline at end of file diff --git a/hunix.h b/hunix.h new file mode 100644 index 000000000..2cf3c45ed --- /dev/null +++ b/hunix.h @@ -0,0 +1,6 @@ +#ifndef H_UNIX_H +#define H_UNIX_H + +void daemonize(); + +#endif // H_UNIX_H \ No newline at end of file diff --git a/hvar.h b/hvar.h new file mode 100644 index 000000000..87b51d2ad --- /dev/null +++ b/hvar.h @@ -0,0 +1,54 @@ +#ifndef H_VAR_H +#define H_VAR_H + +#include "hdef.h" +#include +#include + +class HVar{ +public: + enum TYPE{ + UNKNOWN, + BOOLEAN, + INTEGER, + FLOAT, + STRING, + POINTER + } type; + + union DATA{ + bool b; + int64 i; + float64 f; + char* str; + void* ptr; + } data; + + HVar() {memset(&data, 0, sizeof(data)); type = UNKNOWN;} + HVar(bool b) {data.b = b; type = BOOLEAN;} + HVar(int64 i) {data.i = i; type = INTEGER;} + HVar(float64 f) {data.f = f; type = FLOAT;} + HVar(char* str) { + data.str = (char*)malloc(strlen(str)+1); + strcpy(data.str, str); + type = STRING; + } + HVar(void* ptr) {data.ptr = ptr; type = POINTER;} + + ~HVar() { + if (type == STRING) { + SAFE_FREE(data.str); + } + } + + bool isNull() {return type == UNKNOWN;} + bool isValid() {return type != UNKNOWN;} + + bool toBool() {return data.b;} + int64 toInt() {return data.i;} + float64 toFloat() {return data.f;} + char* toString() {return data.str;} + void* toPointer() {return data.ptr;} +}; + +#endif // H_VAR_H \ No newline at end of file diff --git a/hversion.h b/hversion.h new file mode 100644 index 000000000..72e70f3b3 --- /dev/null +++ b/hversion.h @@ -0,0 +1,31 @@ +#ifndef H_VERSION_H +#define H_VERSION_H + +#include "hdef.h" +#include "htime.h" +#include + +#define VERSION_MAJOR 1 +#define VERSION_MINOR 18 +#define VERSION_MICRO 5 +#define VERSION_PATCH 1 + +#define VERSION_STRING STRINGIFY(VERSION_MAJOR) "." \ + STRINGIFY(VERSION_MINOR) "." \ + STRINGIFY(VERSION_MICRO) "." \ + STRINGIFY(VERSION_PATCH) + +#define VERSION_HEX (VERSION_MAJOR << 24) | (VERSION_MINOR << 16) | (VERSION_MICRO << 8) | VERSION_PATCH + +inline const char* get_static_version(){ + return VERSION_STRING; +} + +inline const char* get_compile_version(){ + static char version[16]; + static datetime_t dt = get_compile_datetime(); + sprintf(version, "%d.%d.%d.%d", VERSION_MAJOR, dt.year%100, dt.month, dt.day); + return version; +} + +#endif // H_VERSION_H \ No newline at end of file diff --git a/singleton.h b/singleton.h new file mode 100644 index 000000000..4c33fda9f --- /dev/null +++ b/singleton.h @@ -0,0 +1,31 @@ +#ifndef SINGLETON_H +#define SINGLETON_H + +#define DISABLE_COPY(Class) \ + Class(const Class &) = delete; \ + Class &operator=(const Class &) = delete; + +#define DCLR_SINGLETON(Class) \ + public: \ + static Class* instance(); \ + static void exitInstance(); \ + private: \ + DISABLE_COPY(Class) \ + static Class* s_pInstance; + +#define IMPL_SINGLETON(Class) \ + Class* Class::s_pInstance = NULL; \ + Class* Class::instance(){ \ + if (s_pInstance == NULL){ \ + s_pInstance = new Class; \ + } \ + return s_pInstance; \ + } \ + void Class::exitInstance(){ \ + if (s_pInstance){ \ + delete s_pInstance; \ + s_pInstance = NULL; \ + } \ + } + +#endif // SINGLETON_H