├── .gitignore ├── .idea └── vcs.xml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── docs ├── tinyorm.mdj └── tinyorm.png ├── example ├── demo_orm.cpp ├── demo_reflection.cpp ├── demo_serialize.cpp ├── demo_serialize_dyn.cpp ├── player.h ├── player.pb.cc ├── player.pb.h ├── player.proto └── tinyobj │ ├── tinyobj.cpp │ ├── tinyobj.h │ ├── tinyplayer.cpp │ ├── tinyplayer.h │ ├── tinyplayer.orm.h │ ├── tinyplayer.pb.cc │ ├── tinyplayer.pb.h │ ├── tinyplayer.proto │ └── tinyplayer.xml ├── include ├── archive.pb.cc ├── archive.pb.h ├── archive.proto ├── hashkit.h ├── pool.h ├── pool_sharding.h ├── sharding.h ├── tinydb.h ├── tinylogger.h ├── tinymysql.h ├── tinyorm.h ├── tinyorm_mysql.h ├── tinyorm_mysql.in.h ├── tinyorm_soci.h ├── tinyorm_soci.in.h ├── tinyreflection.h ├── tinyserializer.h ├── tinyserializer_proto.h ├── tinyserializer_proto_dyn.h ├── tinyserializer_proto_mapping.h ├── tinyworld.h └── url.h ├── src ├── hashkit.cpp ├── tinymysql.cpp ├── tinyorm.cpp └── url.cpp ├── test ├── catch.hpp └── test_serialize.cpp └── tools └── tinyobj.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(tiny-orm) 3 | 4 | # protoc 5 | set(PROTOC protoc) 6 | 7 | # catch.hpp options 8 | add_definitions(-DCATCH_PLATFORM_WINDOWS) 9 | 10 | # CXX_FLAGS 11 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Werror -Wall -g") 12 | 13 | set(SRC_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/include) 14 | set(SRC_EXAMPLE ${CMAKE_CURRENT_SOURCE_DIR}/example) 15 | set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) 16 | 17 | include_directories(include) 18 | include_directories(/usr/local/include) 19 | 20 | link_directories(/usr/local/lib/) 21 | link_directories(/usr/lib/) 22 | 23 | # mysql 24 | set(LIBS_MYSQL mysqlpp mysqlclient z ssl crypto) 25 | 26 | # 27 | # SOCI ? Mysql++ ? 28 | # 29 | set(USE_ORM_SOCI 0) 30 | set(ORM_LIBS "") 31 | if (USE_ORM_SOCI) 32 | include_directories(/usr/local/include/soci 33 | /usr/local/include/soci/mysql 34 | /usr/include/mysq) 35 | link_directories(/usr/local/lib64) 36 | 37 | set(ORM_LIBS soci_core soci_mysql) 38 | else () 39 | add_definitions(-DUSE_ORM_MYSQLPP) 40 | add_definitions(-DMYSQLPP_MYSQL_HEADERS_BURIED) 41 | set(ORM_LIBS mysqlpp) 42 | endif () 43 | 44 | execute_process(COMMAND ${PROTOC} -I=${SRC_INCLUDE} --cpp_out=${SRC_INCLUDE} ${SRC_INCLUDE}/archive.proto) 45 | execute_process(COMMAND ${PROTOC} -I=${SRC_EXAMPLE} --cpp_out=${SRC_EXAMPLE} ${SRC_EXAMPLE}/player.proto) 46 | 47 | add_library(tinyserializer 48 | STATIC 49 | ${SRC_INCLUDE}/archive.pb.h 50 | ${SRC_INCLUDE}/archive.pb.cc) 51 | 52 | add_library(tinyorm 53 | STATIC 54 | ${SRC_DIR}/url.cpp 55 | ${SRC_DIR}/tinymysql.cpp 56 | ${SRC_DIR}/tinyorm.cpp 57 | ${SRC_DIR}/hashkit.cpp) 58 | 59 | add_executable(demo_serialize example/demo_serialize.cpp example/player.pb.cc) 60 | target_link_libraries(demo_serialize tinyserializer protobuf) 61 | 62 | add_executable(demo_serialize_dyn example/demo_serialize_dyn.cpp example/player.pb.cc) 63 | target_link_libraries(demo_serialize_dyn tinyserializer protobuf) 64 | 65 | add_executable(demo_orm example/demo_orm.cpp example/player.pb.cc) 66 | target_link_libraries(demo_orm tinyserializer protobuf tinyorm ${LIBS_MYSQL}) 67 | 68 | add_executable(test_serialize test/test_serialize.cpp example/player.pb.cc) 69 | target_link_libraries(test_serialize tinyserializer protobuf) 70 | 71 | install(TARGETS tinyserializer DESTINATION lib) 72 | install(TARGETS tinyorm DESTINATION lib) 73 | 74 | install(FILES 75 | include/tinyreflection.h 76 | include/tinyserializer.h 77 | include/tinyserializer_proto.h 78 | include/tinyserializer_proto_dyn.h 79 | include/tinyserializer_proto_mapping.h 80 | include/tinyworld.h 81 | include/archive.pb.h 82 | include/archive.pb.cc 83 | include/pool.h 84 | include/pool_sharding.h 85 | include/hashkit.h 86 | include/tinydb.h 87 | include/tinylogger.h 88 | include/tinymysql.h 89 | include/tinyorm.h 90 | include/tinyorm_mysql.h 91 | include/tinyorm_mysql.in.h 92 | include/tinyorm_soci.h 93 | include/tinyorm_soci.in.h 94 | DESTINATION include/tinyworld) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 david++ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | TinyORM 2 | -------------------- 3 | 4 | 对象关系映射(ORM,Object-Relational Mappings),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。说白了,就是将C++对象映射到数据库表的一种技术,目的就是简化对象存档和交换的代码。 5 | 6 | 一般情况下,对象要存储到关系型数据库,需要在代码里面使用SQL语句,若对象较为复杂的话,就需要编写大量代码去支持对象的数据库操作,代码也不怎么美观,扩展性也比较差。ORM则封装这些操作作为对象的成员函数,这样使用时候就会比较方便。(PS. ORM会损失一定的灵活性,偶尔SQL也是必要的) 7 | 8 | 9 | 该项目尝试使用C++写一个简单的ORM,支持: 10 | - 一个C++结构体映射射到一张关系表。 11 | - 映射关系可以手工编写也可以使用工具自动生成。 12 | - 结构体成员变量支持多种类型,简单类型、复合类型、STL容器都有支持。 13 | - 复合成员或STL成员映射为表的二进制字段,此时需进行序列化,当然序列化也可以自动生成。 14 | - 数据库表的自动创建和更新(现阶段只支持数据库添加字段)。 15 | 16 | 不支持复杂的多表操作,数据分表等,用于存档的话完全够用了。 17 | 18 | 依赖: 19 | 20 | - `C++11` 21 | - `protobuf` 22 | - `mysql/mysql++` 或 `soci` 23 | 24 | 框架和简单用法: 25 | 26 | ![TinyORM](./docs/tinyorm.png) 27 | 28 | ## 用法 29 | 30 | 现在要定义一个游戏玩家对象,有名字、ID、年龄,同时可以装备多件武器。 31 | 32 | 第一步:定义支持映射的结构体 33 | 34 | ```c++ 35 | // 武器数据 36 | struct Weapon { 37 | uint32_t type = 0; 38 | std::string name = ""; 39 | 40 | std::string serialize() const { 41 | WeaponProto proto; 42 | proto.set_type(type); 43 | proto.set_name(name); 44 | return proto.SerializeAsString(); 45 | } 46 | 47 | bool deserialize(const std::string &data) { 48 | WeaponProto proto; 49 | if (proto.ParseFromString(data)) { 50 | type = proto.type(); 51 | name = proto.name(); 52 | return true; 53 | } 54 | return false; 55 | } 56 | }; 57 | 58 | // 玩家数据 59 | struct Player { 60 | uint32_t id = 0; 61 | std::string name; 62 | uint8_t age = 0; 63 | std::vector weapons; 64 | } 65 | ``` 66 | 67 | 第二步:定义映射关系 68 | 69 | 把`Player`结构体映射到`PLAYER`表: 70 | 71 | ``` 72 | > DESC PLAYER; 73 | +----------------+----------------------+------+-----+---------+-------+ 74 | | Field | Type | Null | Key | Default | Extra | 75 | +----------------+----------------------+------+-----+---------+-------+ 76 | | ID | int(10) unsigned | NO | PRI | 0 | | 77 | | NAME | text | YES | | NULL | | 78 | | AGE | tinyint(3) | NO | | 30 | | 79 | | WEAPONS | blob | YES | | NULL | | 80 | +----------------+----------------------+------+-----+---------+-------+ 81 | ``` 82 | 83 | ```c++ 84 | TableFactory::instance().table("PLAYER") 85 | .field(&Player::id, "ID", FieldType::UINT32) 86 | .field(&Player::name, "NAME", FieldType::STRING) 87 | .field(&Player::age, "AGE", FieldType::UINT8, "30") 88 | .field(&Player::weapons, "WEAPONS", FieldType::OBJECT) 89 | .key("ID") 90 | .index("NAME"); 91 | 92 | ``` 93 | 94 | 第三步:直接使用 95 | 96 | 假设要把所有`PLAYER`加载到内存: 97 | 98 | ```c++ 99 | TinyORM db; 100 | TinyORM::Records players; 101 | db.loadFromDB(players); 102 | ``` 103 | 104 | 假设要更新`PLAYER`表里面的某条记录: 105 | 106 | ```c++ 107 | Object2DB p; 108 | p.id = 1024; 109 | p.age = 30; 110 | p.name = "David"; 111 | p.weapons.clear(); 112 | p.update(); 113 | ``` 114 | 115 | 例子详细内容,请查看:[demo_orm.cpp](./example/demo_orm.cpp) 116 | 117 | 118 | ## 自动生成ORM映射关系和序列化代码 119 | 120 | 第一步:设计对象并填写用于生成ORM的配置 121 | 122 | ```xml 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | ``` 140 | 141 | 第二步:生成ORM和序列化代码 142 | 143 | ```bash 144 | tools/tinyobj.py -o example/tinyobj/ example/tinyobj/tinyplayer.xml 145 | ``` 146 | 147 | 将会在`example/tinyobj`目录下生成下列文件: 148 | 149 | - 对象定义文件:`tinyplayer.h` `tinyplayer.cpp`。 150 | - 对象序列化相关文件:`tinyplayer.proto` `tinyplayer.pb.h` `tinyplayer.pb.cc`。 151 | - ORM映射:`tinyplayer.orm.h` 152 | 153 | 例子详情,请查看:[tinyplayer.xml](./example/tinyobj/tinyplayer.xml) 154 | 155 | ## 自动生成配置文件说明 156 | 157 | #### 字段类型支持(`type`字段) 158 | 159 | - 基本类型: 160 | 161 | ``` 162 | 脚本类型 : (C++类型、PROTO类型、DB字段类型、默认值) 163 | 164 | # 整数-有符号 165 | "int8" : ("int8_t", "sint32", "INT8", "0"), 166 | "int16": ("int16_t", "sint32", "INT16", "0"), 167 | "int32": ("int32_t", "sint32", "INT32", "0"), 168 | "int64": ("int64_t", "sint64", "INT64", "0"), 169 | 170 | # 整数-无符号 171 | "uint8" : ("uint8_t", "uint32", "UINT8", "0"), 172 | "uint16": ("uint16_t", "uint32", "UINT16", "0"), 173 | "uint32": ("uint32_t", "uint32", "UINT32", "0"), 174 | "uint64": ("uint64_t", "uint64", "UINT64", "0"), 175 | 176 | # 浮点 177 | "float" : ("float", "float", "FLOAT", "0"), 178 | "double": ("double", "double", "DOUBLE", "0"), 179 | 180 | # 布尔 181 | "bool": ("bool", "bool", "BOOL", "0"), 182 | 183 | # 字符串 184 | "string": ("std::string", "bytes", "STRING", ""), 185 | "vchar" : ("std::string", "bytes", "VCHAR", ""), 186 | 187 | # 二进制 188 | "bytes" : ("std::string", "bytes", "BYTES", ""), 189 | "bytes_tiny" : ("std::string", "bytes", "BYTES_TINY", ""), 190 | "bytes_medium" : ("std::string", "bytes", "BYTES_MEDIUM", ""), 191 | "bytes_long" : ("std::string", "bytes", "BYTES_LONG",""), 192 | ``` 193 | 194 | - 自定义类型: 195 | 196 | ``` 197 | Player 198 | Weapon 199 | ``` 200 | 201 | - STL:(由于`<`和`>`两个字符在XML中是特殊字符,脚本中表示STL容器时用`{`和`}`替换即可) 202 | 203 | ``` 204 | // 简单 205 | std::vector{int8} 206 | // 复合类型 207 | std::list 208 | // 任意层次的嵌套 209 | std::map{std::map{std::string, Player}} 210 | ``` 211 | 212 | #### 指定表的键值和索引(现阶段尚未支持索引) 213 | 214 | ``` 215 | 216 | ... 217 | 218 | ``` 219 | 220 | #### 控制不需要生成ORM映射 221 | 222 | `orm="0"` 223 | 224 | ``` 225 | 226 | ... 227 | 228 | ``` 229 | 230 | ## 参考 231 | 232 | - https://en.wikipedia.org/wiki/Object-relational_mapping 233 | - http://www.agiledata.org/essays/mappingObjects.html 234 | - http://www.codesynthesis.com/products/odb/ 235 | 236 | -------------------------------------------------------------------------------- /docs/tinyorm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-pp/tiny-orm/7d852e3a8479e696244aba31487a984b75cc865e/docs/tinyorm.png -------------------------------------------------------------------------------- /example/demo_orm.cpp: -------------------------------------------------------------------------------- 1 | //ODB: C++ Object-Relational Mapping (ORM) 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "tinylogger.h" 10 | 11 | #include "tinyorm.h" 12 | 13 | #ifdef USE_ORM_MYSQLPP 14 | # include "tinyorm_mysql.h" 15 | #else 16 | # include "tinyorm_soci.h" 17 | #endif 18 | 19 | #include "player.h" 20 | 21 | void test_create() { 22 | TinyORM db; 23 | db.createTableByName("PLAYER"); 24 | } 25 | 26 | void test_drop() { 27 | TinyORM db; 28 | db.dropTableByName("PLAYER"); 29 | } 30 | 31 | void test_update() { 32 | TinyORM db; 33 | db.updateTables(); 34 | } 35 | 36 | void test_sql() { 37 | TinyORM db; 38 | 39 | #ifdef USE_ORM_MYSQLPP 40 | { 41 | mysqlpp::Query query(NULL); 42 | db.makeSelectQuery(query, Player()); 43 | LOG_INFO(__FUNCTION__, "%s", query.str().c_str()); 44 | } 45 | 46 | { 47 | mysqlpp::Query query(NULL); 48 | db.makeInsertQuery(query, Player()); 49 | LOG_INFO(__FUNCTION__, "%s", query.str().c_str()); 50 | } 51 | 52 | { 53 | mysqlpp::Query query(NULL); 54 | db.makeReplaceQuery(query, Player()); 55 | LOG_INFO(__FUNCTION__, "%s", query.str().c_str()); 56 | } 57 | 58 | { 59 | mysqlpp::Query query(NULL); 60 | db.makeUpdateQuery(query, Player()); 61 | LOG_INFO(__FUNCTION__, "%s", query.str().c_str()); 62 | } 63 | 64 | { 65 | mysqlpp::Query query(NULL); 66 | db.makeDeleteQuery(query, Player()); 67 | LOG_INFO(__FUNCTION__, "%s", query.str().c_str()); 68 | } 69 | #endif 70 | } 71 | 72 | void test_insertDB() { 73 | 74 | TinyORM db; 75 | for (uint32_t i = 0; i < 10; ++i) { 76 | Player p; 77 | p.init(); 78 | p.id = i; 79 | p.age = 30; 80 | p.name = "david-insert-" + std::to_string(i); 81 | db.insert(p); 82 | } 83 | }; 84 | 85 | void test_replaceDB() { 86 | TinyORM db; 87 | for (uint32_t i = 0; i < 10; ++i) { 88 | Player p; 89 | p.init(); 90 | p.id = i; 91 | p.age = 30; 92 | p.name = "david-replace-" + std::to_string(i); 93 | db.replace(p); 94 | } 95 | } 96 | 97 | void test_updateDB() { 98 | TinyORM db; 99 | for (uint32_t i = 0; i < 10; ++i) { 100 | Player p; 101 | p.init(); 102 | p.id = i; 103 | p.age = 30; 104 | p.name = "david-update-" + std::to_string(i); 105 | db.update(p); 106 | } 107 | } 108 | 109 | void test_deleteDB() { 110 | TinyORM db; 111 | for (uint32_t i = 0; i < 10; ++i) { 112 | Player p; 113 | p.id = i; 114 | db.del(p); 115 | } 116 | } 117 | 118 | void test_selectDB() { 119 | TinyORM db; 120 | for (uint32_t i = 0; i < 10; ++i) { 121 | Player p; 122 | p.id = i; 123 | p.age = 0; 124 | p.name = ""; 125 | if (db.select(p)) 126 | std::cout << p << std::endl; 127 | } 128 | } 129 | 130 | void test_load() { 131 | TinyORM db; 132 | TinyORM::Records players; 133 | db.loadFromDB(players, "WHERE ID %% %d=0 ORDER BY ID DESC", 2); 134 | 135 | for (auto p : players) { 136 | std::cout << *p; 137 | } 138 | } 139 | 140 | void test_load2() { 141 | TinyORM db; 142 | db.loadFromDB([](std::shared_ptr p) { 143 | std::cout << *p; 144 | }, nullptr); 145 | } 146 | 147 | void test_load3() { 148 | TinyORM db; 149 | 150 | struct PlayerCompare { 151 | bool operator()(const std::shared_ptr &lhs, const std::shared_ptr &rhs) const { 152 | return lhs->id > rhs->id; 153 | } 154 | }; 155 | 156 | // using PlayerSet = std::set, PlayerCompare>; 157 | using PlayerSet = std::set>; 158 | 159 | PlayerSet players; 160 | db.loadFromDB(players, nullptr); 161 | 162 | for (auto it = players.begin(); it != players.end(); ++it) { 163 | std::cout << *(*it); 164 | } 165 | } 166 | 167 | 168 | #include 169 | #include 170 | #include 171 | #include 172 | 173 | namespace tiny { 174 | using boost::multi_index_container; 175 | using namespace boost::multi_index; 176 | 177 | struct by_id { 178 | }; 179 | struct by_name { 180 | }; 181 | 182 | using PlayerSet = boost::multi_index_container< 183 | Player, 184 | indexed_by< 185 | // sort by employee::operator< 186 | ordered_unique, member >, 187 | // sort by less on name 188 | ordered_non_unique, member > 189 | > 190 | >; 191 | } 192 | 193 | void test_load4() { 194 | TinyORM db; 195 | 196 | tiny::PlayerSet players; 197 | db.loadFromDB2MultiIndexSet(players, nullptr); 198 | 199 | auto &players_by_id = players.get(); 200 | auto &players_by_name = players.get(); 201 | 202 | auto it = players_by_id.find(5); 203 | if (it != players_by_id.end()) { 204 | std::cout << (*it); 205 | } 206 | 207 | for (auto it = players_by_name.begin(); it != players_by_name.end(); ++it) { 208 | std::cout << (*it); 209 | } 210 | 211 | std::cout << players_by_name.count("david") << std::endl; 212 | } 213 | 214 | 215 | void test_delete() { 216 | TinyORM db; 217 | db.deleteFromDB("WHERE ID %% %d=0", 2); 218 | } 219 | 220 | void test_obj2db() { 221 | Object2DB p2db; 222 | p2db.id = 1024; 223 | p2db.name = "david-p2db"; 224 | 225 | p2db.dropTable(); 226 | p2db.updateTable(); 227 | 228 | p2db.name = "david-insert"; 229 | p2db.insertDB(); 230 | if (p2db.selectDB()) 231 | std::cout << p2db.name << std::endl; 232 | 233 | p2db.name = "david-update"; 234 | p2db.updateDB(); 235 | if (p2db.selectDB()) 236 | std::cout << p2db.name << std::endl; 237 | 238 | p2db.name = "david-replace"; 239 | p2db.replaceDB(); 240 | if (p2db.selectDB()) 241 | std::cout << p2db.name << std::endl; 242 | 243 | p2db.deleteDB(); 244 | if (p2db.selectDB()) 245 | std::cout << p2db.name << std::endl; 246 | 247 | 248 | // p2db.id = 8; 249 | // p2db.selectDB(&MySqlConnectionPool::instance()); 250 | // std::cout << p2db; 251 | // 252 | // ScopedMySqlConnection mysql; 253 | // if (mysql) { 254 | // p2db.id = 7; 255 | // p2db.selectDB(mysql.get()); 256 | // std::cout << p2db; 257 | // } 258 | } 259 | 260 | int main(int argc, const char *argv[]) { 261 | if (argc < 2) { 262 | std::cout << "Usage:" << argv[0] 263 | << " create | drop | update" << std::endl; 264 | return 1; 265 | } 266 | 267 | #ifdef USE_ORM_MYSQLPP 268 | MySqlConnectionPool::instance().connect("mysql://david:123456@127.0.0.1/tinyworld?maxconn=5"); 269 | #else 270 | SOCIPool::instance().connect("mysql://host=127.0.0.1 db=tinyworld user=david password='123456'", 5); 271 | #endif 272 | 273 | std::string op = argv[1]; 274 | if ("sql" == op) 275 | test_sql(); 276 | else if ("create" == op) 277 | test_create(); 278 | else if ("drop" == op) 279 | test_drop(); 280 | else if ("update" == op) 281 | test_update(); 282 | else if ("insertDB" == op) 283 | test_insertDB(); 284 | else if ("replaceDB" == op) 285 | test_replaceDB(); 286 | else if ("updateDB" == op) 287 | test_updateDB(); 288 | else if ("deleteDB" == op) 289 | test_deleteDB(); 290 | else if ("selectDB" == op) 291 | test_selectDB(); 292 | else if ("load" == op) 293 | test_load(); 294 | else if ("load2" == op) 295 | test_load2(); 296 | else if ("load3" == op) 297 | test_load3(); 298 | else if ("load4" == op) 299 | test_load4(); 300 | else if ("delete" == op) 301 | test_delete(); 302 | else if ("obj2db" == op) 303 | test_obj2db(); 304 | 305 | return 0; 306 | } 307 | 308 | -------------------------------------------------------------------------------- /example/demo_reflection.cpp: -------------------------------------------------------------------------------- 1 | #include "tinyreflection.h" 2 | 3 | // User Defined Struct 4 | struct Player { 5 | int id = 0; 6 | std::string name; 7 | int score = 0; 8 | float salary = 20000.25; 9 | std::vector vec = {21, 22 , 23, 24, 25}; 10 | std::vector vec2 = {"david", "LL", "JJ"}; 11 | std::vector > vec3 = { 12 | {"david1", "LL", "JJ"}, 13 | {"david2", "LL", "JJ"}, 14 | {"david3", "LL", "JJ"} 15 | }; 16 | 17 | void dump() { 18 | std::cout << std::dec << id << "," << name << "," << score << "," << salary << std::endl; 19 | 20 | std::cout << "vec = ["; 21 | std::for_each(vec.begin(), vec.end(), [](int v) { 22 | std::cout << v << ","; 23 | }); 24 | std::cout << "]" << std::endl; 25 | 26 | std::cout << "vec2 = ["; 27 | std::for_each(vec2.begin(), vec2.end(), [](std::string& v) { 28 | std::cout << v << ","; 29 | }); 30 | std::cout << "]" << std::endl; 31 | 32 | std::cout << "vec3 = ["; 33 | std::for_each(vec3.begin(), vec3.end(), [](std::vector& v) { 34 | std::cout << "["; 35 | std::for_each(v.begin(), v.end(), [](std::string& v1) { 36 | std::cout << v1 << ","; 37 | }); 38 | std::cout << "]," ; 39 | }); 40 | std::cout << "]" << std::endl; 41 | } 42 | }; 43 | 44 | // Player's Reflection 45 | RUN_ONCE(Player){ 46 | StructFactory::instance().declare("Player").version(2016) 47 | .property("id", &Player::id, 1) 48 | .property("name", &Player::name, 2) 49 | .property("score", &Player::score, 3) 50 | .property("salary", &Player::salary, 4) 51 | .property("vec", &Player::vec, 5) 52 | .property("vec2", &Player::vec2, 6) 53 | .property("vec3", &Player::vec3, 7); 54 | } 55 | 56 | 57 | void demo_1() { 58 | 59 | Player p; 60 | auto reflection = StructFactory::instance().structByType(); 61 | 62 | std::cout << "\n-----------relection:set ------------\n"; 63 | { 64 | reflection->set(p, "id", 100); 65 | reflection->set(p, "name", "david"); 66 | 67 | std::cout << p.id << std::endl; 68 | std::cout << p.name << std::endl; 69 | } 70 | 71 | std::cout << "\n-----------relection:get ------------\n"; 72 | { 73 | std::cout << reflection->get(p, "id") << std::endl; 74 | std::cout << reflection->get(p, "name") << std::endl; 75 | } 76 | 77 | std::cout << "\n-----------relection:iteration ------------\n"; 78 | { 79 | for (auto prop : reflection->propertyIterator()) { 80 | if (prop->type() == typeid(int)) 81 | std::cout << prop->name() << ":" << reflection->get(p, prop->name()) << std::endl; 82 | else if (prop->type() == typeid(std::string)) 83 | std::cout << prop->name() << ":" << reflection->get(p, prop->name()) << std::endl; 84 | } 85 | } 86 | } 87 | 88 | int main() { 89 | demo_1(); 90 | } -------------------------------------------------------------------------------- /example/demo_serialize.cpp: -------------------------------------------------------------------------------- 1 | #include "tinyreflection.h" 2 | #include "tinyserializer.h" 3 | #include "tinyserializer_proto.h" 4 | 5 | #include "player.pb.h" 6 | 7 | // 8 | // Demo for Scalar 9 | // 10 | void demo_basic() { 11 | 12 | std::cout << "\n========" << __PRETTY_FUNCTION__ << std::endl; 13 | 14 | std::cout << "\n------ int ----------\n"; 15 | { 16 | uint32_t v1 = 1024; 17 | std::string data = serialize(v1); 18 | 19 | uint64_t v2 = 0; 20 | deserialize(v2, data); 21 | 22 | std::cout << v2 << std::endl; 23 | } 24 | 25 | std::cout << "\n------ float ----------\n"; 26 | { 27 | double v1 = 3.1415926; 28 | std::string data = serialize(v1); 29 | 30 | float v2 = 0; 31 | deserialize(v2, data); 32 | 33 | std::cout << v2 << std::endl; 34 | } 35 | 36 | std::cout << "\n------ string ----------\n"; 37 | { 38 | std::string v1 = "Hello David++!"; 39 | std::string data = serialize(v1); 40 | 41 | std::string v2; 42 | if (deserialize(v2, data)) 43 | std::cout << v2 << std::endl; 44 | else 45 | std::cout << "error happens !" << std::endl; 46 | } 47 | 48 | std::cout << "\n------ proto ----------\n"; 49 | { 50 | PlayerProto p1; 51 | p1.set_id(1024); 52 | p1.set_name("david"); 53 | p1.add_quests(1); 54 | p1.add_quests(2); 55 | p1.mutable_weapon()->set_type(2); 56 | p1.mutable_weapon()->set_name("Sword"); 57 | 58 | 59 | std::string data = serialize(p1); 60 | 61 | PlayerProto p2; 62 | if (deserialize(p2, data)) 63 | std::cout << p2.ShortDebugString() << std::endl; 64 | else 65 | std::cout << "error happens !" << std::endl; 66 | } 67 | } 68 | 69 | // 70 | // Demo for STL container 71 | // 72 | void demo_stl() { 73 | std::cout << "\n========" << __PRETTY_FUNCTION__ << std::endl; 74 | 75 | PlayerProto p; 76 | p.set_id(1024); 77 | p.set_name("david"); 78 | p.add_quests(1); 79 | p.add_quests(2); 80 | p.mutable_weapon()->set_type(2); 81 | p.mutable_weapon()->set_name("Sword"); 82 | 83 | std::cout << "\n------ vector ----------\n"; 84 | { 85 | std::vector v1 = {1, 2, 3, 4, 5, 6}; 86 | std::string data = serialize(v1); 87 | 88 | std::list v2; 89 | deserialize(v2, data); 90 | 91 | for (auto &v : v2) 92 | std::cout << v << ","; 93 | std::cout << std::endl; 94 | } 95 | 96 | std::cout << "\n------ map ----------\n"; 97 | { 98 | std::map v1 = { 99 | {1024, p}, 100 | {1025, p}, 101 | {1026, p}, 102 | }; 103 | 104 | std::string data = serialize(v1); 105 | 106 | std::map v2; 107 | deserialize(v2, data); 108 | 109 | for (auto &v : v2) 110 | std::cout << v.first << " - " << v.second.ShortDebugString() << std::endl; 111 | } 112 | 113 | std::cout << "\n------ map> ----------\n"; 114 | { 115 | std::map> v1 = { 116 | {1024, {p, p, p}}, 117 | {1025, {p, p}}, 118 | {1026, {p}}, 119 | }; 120 | 121 | std::string data = serialize(v1); 122 | 123 | std::map> v2; 124 | deserialize(v2, data); 125 | 126 | for (auto &v : v2) { 127 | std::cout << v.first << std::endl; 128 | for (auto& player : v.second) 129 | std::cout << "\t - " << player.ShortDebugString() << std::endl; 130 | } 131 | } 132 | } 133 | 134 | // 135 | // Demo for User-Defined 136 | // 137 | 138 | struct Weapon { 139 | uint32_t type = 0; 140 | std::string name = ""; 141 | 142 | // 143 | // intrusive way 144 | // 145 | std::string serialize() const { 146 | WeaponProto proto; 147 | proto.set_type(type); 148 | proto.set_name(name); 149 | return proto.SerializeAsString(); 150 | } 151 | 152 | bool deserialize(const std::string &data) { 153 | WeaponProto proto; 154 | if (proto.ParseFromString(data)) { 155 | type = proto.type(); 156 | name = proto.name(); 157 | return true; 158 | } 159 | return false; 160 | } 161 | }; 162 | 163 | struct Player { 164 | uint32_t id = 0; 165 | std::string name = ""; 166 | std::vector quests; 167 | Weapon weapon; 168 | std::map weapons; 169 | std::map> weapons_map; 170 | 171 | void dump() const { 172 | std::cout << "id = " << id << std::endl; 173 | std::cout << "name = " << name << std::endl; 174 | 175 | std::cout << "quests = ["; 176 | for (auto v : quests) 177 | std::cout << v << ","; 178 | std::cout << "]" << std::endl; 179 | 180 | std::cout << "weapon = {" << weapon.type << "," << weapon.name << "}" << std::endl; 181 | 182 | std::cout << "weapons_map = {" << std::endl; 183 | for (auto &kv : weapons_map) { 184 | std::cout << "\t" << kv.first << ": ["; 185 | for (auto &p : kv.second) { 186 | std::cout << "{" << p.type << "," << p.name << "},"; 187 | } 188 | std::cout << "]" << std::endl; 189 | } 190 | std::cout << "}" << std::endl; 191 | } 192 | 193 | void init() { 194 | id = 1024; 195 | name = "david"; 196 | quests.push_back(1); 197 | quests.push_back(2); 198 | 199 | weapon.type = 0; 200 | weapon.name = "Sword"; 201 | 202 | for (uint32_t i = 0; i < 3; i++) { 203 | weapons[i].type = i; 204 | weapons[i].name = "Shield"; 205 | } 206 | 207 | Weapon w; 208 | w.type = 22; 209 | w.name = "Blade"; 210 | weapons_map = { 211 | {1, {w, w, w}}, 212 | {2, {w, w, w}}, 213 | }; 214 | 215 | } 216 | }; 217 | 218 | // non-intrusive way 219 | template<> 220 | struct ProtoSerializer { 221 | std::string serialize(const Player &p) const { 222 | PlayerProto proto; 223 | proto.set_id(p.id); 224 | proto.set_name(p.name); 225 | // complex object 226 | proto.set_weapons_map(::serialize(p.weapons_map)); 227 | return proto.SerializeAsString(); 228 | } 229 | 230 | bool deserialize(Player &p, const std::string &data) const { 231 | PlayerProto proto; 232 | if (proto.ParseFromString(data)) { 233 | p.id = proto.id(); 234 | p.name = proto.name(); 235 | // complex object 236 | ::deserialize(p.weapons_map, proto.weapons_map()); 237 | return true; 238 | } 239 | return false; 240 | } 241 | }; 242 | 243 | void demo_userdefined() { 244 | std::cout << "\n========" << __PRETTY_FUNCTION__ << std::endl; 245 | 246 | std::cout << "\n------ Weapon ----------\n"; 247 | { 248 | Weapon w; 249 | w.type = 22; 250 | w.name = "Blade"; 251 | 252 | std::string data = serialize(w); 253 | 254 | Weapon w2; 255 | deserialize(w2, data); 256 | std::cout << w2.type << " - " << w2.name << std::endl; 257 | } 258 | 259 | std::cout << "\n------ Player ----------\n"; 260 | { 261 | Player p; 262 | p.init(); 263 | 264 | std::string data = serialize(p); 265 | 266 | Player p2; 267 | deserialize(p2, data); 268 | p2.dump(); 269 | } 270 | } 271 | 272 | // 273 | // Demo for Archiver 274 | // 275 | void demo_archiver() { 276 | std::cout << "\n========" << __PRETTY_FUNCTION__ << std::endl; 277 | 278 | std::string data; 279 | 280 | // serialize 281 | { 282 | PlayerProto p; 283 | p.set_id(1024); 284 | p.set_name("david"); 285 | 286 | std::vector pvec{p, p, p}; 287 | 288 | std::map pmap{ 289 | {1, p}, 290 | {2, p}, 291 | {3, p} 292 | }; 293 | 294 | std::vector > vecmap{pmap, pmap, pmap}; 295 | 296 | ProtoArchiver<> ar; 297 | ar << p << p << p; // support: protobuf generated 298 | ar << pvec; // support: std::vector 299 | ar << pmap; // support: std::map 300 | ar << vecmap; // support: composite of STL container 301 | ar << ar; // support: archiver self ? YES! 302 | 303 | // ar.SerializeToString(&data); 304 | data = serialize(ar); 305 | } 306 | 307 | // deserialize 308 | { 309 | PlayerProto p1, p2, p3; 310 | std::vector pvec; 311 | std::map pmap; 312 | std::vector > vecmap; 313 | 314 | ProtoArchiver<> ar, ar2; 315 | // if (ar.ParseFromString(data)) { 316 | if (::deserialize(ar, data)) { 317 | ar >> p1 >> p2 >> p3; 318 | ar >> pvec; 319 | ar >> pmap; 320 | ar >> vecmap; 321 | ar >> ar2; 322 | } 323 | 324 | std::cout << "\n------ p1 ----------\n"; 325 | { 326 | std::cout << p1.ShortDebugString() << std::endl; 327 | } 328 | std::cout << "\n------ p2 ----------\n"; 329 | { 330 | std::cout << p2.ShortDebugString() << std::endl; 331 | } 332 | std::cout << "\n------ p3 ----------\n"; 333 | { 334 | std::cout << p3.ShortDebugString() << std::endl; 335 | } 336 | 337 | std::cout << "\n------ vector

----------\n"; 338 | { 339 | for (auto &p : pvec) { 340 | std::cout << p.ShortDebugString() << std::endl; 341 | } 342 | } 343 | 344 | std::cout << "\n------ map

----------\n"; 345 | { 346 | for (auto &v : pmap) { 347 | std::cout << v.first << " : " << v.second.ShortDebugString() << std::endl; 348 | } 349 | } 350 | 351 | std::cout << "\n------ vector> ----------\n"; 352 | { 353 | for (auto &item : vecmap) { 354 | for (auto &v: item) 355 | std::cout << v.first << " : " << v.second.ShortDebugString() << std::endl; 356 | std::cout << std::endl; 357 | } 358 | } 359 | 360 | std::cout << "\n------ archiver ----------\n"; 361 | { 362 | std::cout << ar2.ShortDebugString() << std::endl; 363 | } 364 | } 365 | } 366 | 367 | int main(int argc, const char* argv[]) { 368 | int count = 1; 369 | if (argc > 1) 370 | count = std::atoi(argv[1]); 371 | 372 | for (int i = 0; i < count; ++i) { 373 | demo_basic(); 374 | demo_stl(); 375 | demo_userdefined(); 376 | demo_archiver(); 377 | } 378 | } -------------------------------------------------------------------------------- /example/demo_serialize_dyn.cpp: -------------------------------------------------------------------------------- 1 | #include "tinyreflection.h" 2 | #include "tinyserializer.h" 3 | #include "tinyserializer_proto.h" 4 | #include "tinyserializer_proto_dyn.h" 5 | 6 | #include "player.pb.h" 7 | 8 | // 9 | // Demo for Scalar 10 | // 11 | void demo_basic() { 12 | 13 | std::cout << "\n========" << __PRETTY_FUNCTION__ << std::endl; 14 | 15 | std::cout << "\n------ int ----------\n"; 16 | { 17 | uint32_t v1 = 1024; 18 | std::string data = serialize(v1); 19 | 20 | uint64_t v2 = 0; 21 | deserialize(v2, data); 22 | 23 | std::cout << v2 << std::endl; 24 | } 25 | 26 | std::cout << "\n------ float ----------\n"; 27 | { 28 | double v1 = 3.1415926; 29 | std::string data = serialize(v1); 30 | 31 | float v2 = 0; 32 | deserialize(v2, data); 33 | 34 | std::cout << v2 << std::endl; 35 | } 36 | 37 | std::cout << "\n------ string ----------\n"; 38 | { 39 | std::string v1 = "Hello David++!"; 40 | std::string data = serialize(v1); 41 | 42 | std::string v2; 43 | if (deserialize(v2, data)) 44 | std::cout << v2 << std::endl; 45 | else 46 | std::cout << "error happens !" << std::endl; 47 | } 48 | 49 | std::cout << "\n------ proto ----------\n"; 50 | { 51 | PlayerProto p1; 52 | p1.set_id(1024); 53 | p1.set_name("david"); 54 | p1.add_quests(1); 55 | p1.add_quests(2); 56 | p1.mutable_weapon()->set_type(2); 57 | p1.mutable_weapon()->set_name("Sword"); 58 | 59 | 60 | std::string data = serialize(p1); 61 | 62 | PlayerProto p2; 63 | if (deserialize(p2, data)) 64 | std::cout << p2.ShortDebugString() << std::endl; 65 | else 66 | std::cout << "error happens !" << std::endl; 67 | } 68 | } 69 | 70 | // 71 | // Demo for STL container 72 | // 73 | void demo_stl() { 74 | std::cout << "\n========" << __PRETTY_FUNCTION__ << std::endl; 75 | 76 | PlayerProto p; 77 | p.set_id(1024); 78 | p.set_name("david"); 79 | p.add_quests(1); 80 | p.add_quests(2); 81 | p.mutable_weapon()->set_type(2); 82 | p.mutable_weapon()->set_name("Sword"); 83 | 84 | std::cout << "\n------ vector ----------\n"; 85 | { 86 | std::vector v1 = {1, 2, 3, 4, 5, 6}; 87 | std::string data = serialize(v1); 88 | 89 | std::vector v2; 90 | deserialize(v2, data); 91 | 92 | for (auto &v : v2) 93 | std::cout << v << ","; 94 | std::cout << std::endl; 95 | } 96 | 97 | std::cout << "\n------ map ----------\n"; 98 | { 99 | std::map v1 = { 100 | {1024, p}, 101 | {1025, p}, 102 | {1026, p}, 103 | }; 104 | 105 | std::string data = serialize(v1); 106 | 107 | std::map v2; 108 | deserialize(v2, data); 109 | 110 | for (auto &v : v2) 111 | std::cout << v.first << " - " << v.second.ShortDebugString() << std::endl; 112 | } 113 | 114 | std::cout << "\n------ map> ----------\n"; 115 | { 116 | std::map> v1 = { 117 | {1024, {p, p, p}}, 118 | {1025, {p, p}}, 119 | {1026, {p}}, 120 | }; 121 | 122 | std::string data = serialize(v1); 123 | 124 | std::map> v2; 125 | deserialize(v2, data); 126 | 127 | for (auto &v : v2) { 128 | std::cout << v.first << std::endl; 129 | for (auto& player : v.second) 130 | std::cout << "\t - " << player.ShortDebugString() << std::endl; 131 | } 132 | } 133 | } 134 | 135 | // 136 | // Demo for User-Defined 137 | // 138 | 139 | struct Weapon { 140 | uint32_t type = 0; 141 | std::string name = ""; 142 | }; 143 | 144 | struct Player { 145 | uint32_t id = 0; 146 | std::string name = ""; 147 | std::vector quests; 148 | Weapon weapon; 149 | std::map weapons; 150 | std::map> weapons_map; 151 | 152 | void dump() const { 153 | std::cout << "id = " << id << std::endl; 154 | std::cout << "name = " << name << std::endl; 155 | 156 | std::cout << "quests = ["; 157 | for (auto v : quests) 158 | std::cout << v << ","; 159 | std::cout << "]" << std::endl; 160 | 161 | std::cout << "weapon = {" << weapon.type << "," << weapon.name << "}" << std::endl; 162 | 163 | std::cout << "weapons_map = {" << std::endl; 164 | for (auto &kv : weapons_map) { 165 | std::cout << "\t" << kv.first << ": ["; 166 | for (auto &p : kv.second) { 167 | std::cout << "{" << p.type << "," << p.name << "},"; 168 | } 169 | std::cout << "]" << std::endl; 170 | } 171 | std::cout << "}" << std::endl; 172 | } 173 | 174 | void init() { 175 | id = 1024; 176 | name = "david"; 177 | quests.push_back(1); 178 | quests.push_back(2); 179 | 180 | weapon.type = 0; 181 | weapon.name = "Sword"; 182 | 183 | for (uint32_t i = 0; i < 3; i++) { 184 | weapons[i].type = i; 185 | weapons[i].name = "Shield"; 186 | } 187 | 188 | Weapon w; 189 | w.type = 22; 190 | w.name = "Blade"; 191 | weapons_map = { 192 | {1, {w, w, w}}, 193 | {2, {w, w, w}}, 194 | }; 195 | 196 | } 197 | }; 198 | 199 | // Struct -> Proto Mapping 200 | RUN_ONCE(Mapping) { 201 | 202 | ProtoMappingFactory::instance().declare("Weapon") 203 | .property("type", &Weapon::type, 1) 204 | .property("name", &Weapon::name, 2); 205 | 206 | ProtoMappingFactory::instance().declare("Player", "PlayerDynProto") 207 | .property("id", &Player::id, 1) 208 | .property("name", &Player::name, 2) 209 | .property("quests", &Player::quests, 3) 210 | .property("weapon", &Player::weapon, 4) 211 | .property("weapon2", &Player::weapons, 5) 212 | .property("weapons_map", &Player::weapons_map, 6); 213 | 214 | // MUST!!! CREATE DESCRIPTORS 215 | ProtoMappingFactory::instance().createAllProtoDescriptor(); 216 | } 217 | 218 | void demo_userdefined() { 219 | std::cout << "\n========" << __PRETTY_FUNCTION__ << std::endl; 220 | 221 | try { 222 | std::cout << "\n------ Proto created ----------\n"; 223 | { 224 | ProtoMappingFactory::instance().createAllProtoDefine(); 225 | } 226 | 227 | std::cout << "\n------ Weapon ----------\n"; 228 | { 229 | Weapon w; 230 | w.type = 22; 231 | w.name = "Blade"; 232 | 233 | std::string data = serialize(w); 234 | 235 | Weapon w2; 236 | deserialize(w2, data); 237 | std::cout << w2.type << " - " << w2.name << std::endl; 238 | } 239 | 240 | std::cout << "\n------ Player ----------\n"; 241 | { 242 | Player p; 243 | p.init(); 244 | 245 | std::string data = serialize(p); 246 | 247 | Player p2; 248 | deserialize(p2, data); 249 | p2.dump(); 250 | } 251 | } catch (const std::exception& e) { 252 | std::cout << "Error Happens: " << e.what() << std::endl; 253 | } 254 | } 255 | 256 | // 257 | // Demo for Archiver 258 | // 259 | void demo_archiver() { 260 | std::cout << "\n========" << __PRETTY_FUNCTION__ << std::endl; 261 | 262 | std::string data; 263 | 264 | // serialize 265 | { 266 | PlayerProto p; 267 | p.set_id(1024); 268 | p.set_name("david"); 269 | 270 | std::vector pvec{p, p, p}; 271 | 272 | std::map pmap{ 273 | {1, p}, 274 | {2, p}, 275 | {3, p} 276 | }; 277 | 278 | std::vector > vecmap{pmap, pmap, pmap}; 279 | 280 | ProtoArchiver ar; 281 | ar << p << p << p; // support: protobuf generated 282 | ar << pvec; // support: std::vector 283 | ar << pmap; // support: std::map 284 | ar << vecmap; // support: composite of STL container 285 | ar << ar; // support: archiver self ? YES! 286 | 287 | // ar.SerializeToString(&data); 288 | data = serialize(ar); 289 | } 290 | 291 | // deserialize 292 | { 293 | PlayerProto p1, p2, p3; 294 | std::vector pvec; 295 | std::map pmap; 296 | std::vector > vecmap; 297 | 298 | ProtoArchiver ar, ar2; 299 | // if (ar.ParseFromString(data)) { 300 | if (::deserialize(ar, data)) { 301 | ar >> p1 >> p2 >> p3; 302 | ar >> pvec; 303 | ar >> pmap; 304 | ar >> vecmap; 305 | ar >> ar2; 306 | } 307 | 308 | std::cout << "\n------ p1 ----------\n"; 309 | { 310 | std::cout << p1.ShortDebugString() << std::endl; 311 | } 312 | std::cout << "\n------ p2 ----------\n"; 313 | { 314 | std::cout << p2.ShortDebugString() << std::endl; 315 | } 316 | std::cout << "\n------ p3 ----------\n"; 317 | { 318 | std::cout << p3.ShortDebugString() << std::endl; 319 | } 320 | 321 | std::cout << "\n------ vector

----------\n"; 322 | { 323 | for (auto &p : pvec) { 324 | std::cout << p.ShortDebugString() << std::endl; 325 | } 326 | } 327 | 328 | std::cout << "\n------ map

----------\n"; 329 | { 330 | for (auto &v : pmap) { 331 | std::cout << v.first << " : " << v.second.ShortDebugString() << std::endl; 332 | } 333 | } 334 | 335 | std::cout << "\n------ vector> ----------\n"; 336 | { 337 | for (auto &item : vecmap) { 338 | for (auto &v: item) 339 | std::cout << v.first << " : " << v.second.ShortDebugString() << std::endl; 340 | std::cout << std::endl; 341 | } 342 | } 343 | 344 | std::cout << "\n------ archiver ----------\n"; 345 | { 346 | std::cout << ar2.ShortDebugString() << std::endl; 347 | } 348 | } 349 | } 350 | 351 | int main(int argc, const char* argv[]) { 352 | int count = 1; 353 | if (argc > 1) 354 | count = std::atoi(argv[1]); 355 | 356 | for (int i = 0; i < count; ++i) { 357 | demo_basic(); 358 | demo_stl(); 359 | demo_userdefined(); 360 | demo_archiver(); 361 | } 362 | } -------------------------------------------------------------------------------- /example/player.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYWORLD_PLAYER_H 2 | #define TINYWORLD_PLAYER_H 3 | 4 | #include "tinyworld.h" 5 | #include "tinyorm.h" 6 | #include "player.pb.h" 7 | 8 | struct Weapon { 9 | uint32_t type = 0; 10 | std::string name = ""; 11 | 12 | std::string serialize() const { 13 | WeaponProto proto; 14 | proto.set_type(type); 15 | proto.set_name(name); 16 | return proto.SerializeAsString(); 17 | } 18 | 19 | bool deserialize(const std::string &data) { 20 | WeaponProto proto; 21 | if (proto.ParseFromString(data)) { 22 | type = proto.type(); 23 | name = proto.name(); 24 | return true; 25 | } 26 | return false; 27 | } 28 | }; 29 | 30 | // 31 | // Player -> PLAYER 32 | // 33 | struct Player { 34 | // 35 | // Proto序列化约束 36 | // 37 | std::string serialize() const { 38 | PlayerProto4Table proto; 39 | proto.set_id(id); 40 | proto.set_name(name); 41 | proto.set_age(age); 42 | proto.set_weaon(::serialize(weapon)); 43 | proto.set_weapns(::serialize(weapons)); 44 | return proto.SerializeAsString(); 45 | } 46 | 47 | bool deserialize(const std::string &data) { 48 | PlayerProto4Table proto; 49 | if (proto.ParseFromString(data)) { 50 | id = proto.id(); 51 | name = proto.name(); 52 | age = proto.age(); 53 | ::deserialize(weapon, proto.weaon()); 54 | ::deserialize(weapons, proto.weapns()); 55 | 56 | return true; 57 | } 58 | return false; 59 | } 60 | 61 | // ... 62 | uint32_t id = 0; 63 | std::string name; 64 | uint8_t age = 0; 65 | 66 | // 整型 67 | int8_t m_int8 = 0; 68 | uint8_t m_uint8 = 0; 69 | int16_t m_int16 = 0; 70 | uint16_t m_uint16 = 0; 71 | int32_t m_int32 = 0; 72 | uint32_t m_uint32 = 0; 73 | int64_t m_int64 = 0; 74 | uint64_t m_uint64 = 0; 75 | 76 | // 浮点 77 | float m_float = 0.0; 78 | double m_double = 0.0; 79 | 80 | // 布尔 81 | bool m_bool = false; 82 | 83 | // 字符串 84 | std::string m_string; 85 | 86 | // 二进制 87 | std::string m_bytes; 88 | std::string m_bytes_tiny; 89 | std::string m_bytes_medium; 90 | std::string m_bytes_long; 91 | 92 | // 复合对象 93 | Weapon weapon; 94 | std::vector weapons; 95 | 96 | void init() { 97 | id = 1024; 98 | name = "david"; 99 | age = 30; 100 | 101 | // 整型 102 | m_int8 = 1; 103 | m_uint8 = 2; 104 | m_int16 = 3; 105 | m_uint16 = 4; 106 | m_int32 = 5; 107 | m_uint32 = 6; 108 | m_int64 = 7; 109 | m_uint64 = 8; 110 | // 浮点 111 | m_float = 10.11; 112 | m_double = 20.22; 113 | m_bool = true; 114 | 115 | m_string = "string"; 116 | 117 | 118 | m_bytes = "bytes"; 119 | m_bytes_tiny = "tiny...bytes"; 120 | m_bytes_medium = "medium...bytes"; 121 | m_bytes_long = "long...bytes"; 122 | weapon.type = 24; 123 | weapon.name = "sword"; 124 | weapons = {weapon, weapon, weapon}; 125 | } 126 | }; 127 | 128 | // 在cpp中定义一次即可 129 | RUN_ONCE(Player) { 130 | TableFactory::instance().table("PLAYER") 131 | .field(&Player::id, "ID", FieldType::UINT32) 132 | .field(&Player::name, "NAME", FieldType::VCHAR, "david", 32) 133 | .field(&Player::age, "AGE", FieldType::UINT8, "30") 134 | 135 | .field(&Player::m_int8, "M_INT8", FieldType::INT8) 136 | .field(&Player::m_int16, "M_INT16", FieldType::INT16) 137 | .field(&Player::m_int32, "M_INT32", FieldType::INT32) 138 | .field(&Player::m_int64, "M_INT64", FieldType::INT64) 139 | .field(&Player::m_uint8, "M_UINT8", FieldType::UINT8) 140 | .field(&Player::m_uint16, "M_UINT16", FieldType::UINT16) 141 | .field(&Player::m_uint32, "M_UINT32", FieldType::UINT32) 142 | .field(&Player::m_uint64, "M_UINT64", FieldType::UINT64) 143 | 144 | .field(&Player::m_bool, "M_BOOL", FieldType::BOOL) 145 | .field(&Player::m_float, "M_FLOAT", FieldType::FLOAT) 146 | .field(&Player::m_double, "M_DOUBLE", FieldType::DOUBLE) 147 | 148 | .field(&Player::m_string, "M_STRING", FieldType::STRING) 149 | 150 | .field(&Player::m_bytes, "M_BYTES", FieldType::BYTES) 151 | .field(&Player::m_bytes_tiny, "M_BYTES_S", FieldType::BYTES_TINY) 152 | .field(&Player::m_bytes_medium, "M_BYTES_M", FieldType::BYTES_MEDIUM) 153 | .field(&Player::m_bytes_long, "M_BYTES_L", FieldType::BYTES_LONG) 154 | 155 | .field(&Player::weapon, "OBJ1", FieldType::OBJECT) 156 | .field(&Player::weapons, "OBJ2", FieldType::OBJECT) 157 | .key("ID") 158 | .index("NAME"); 159 | } 160 | 161 | std::ostream &operator<<(std::ostream &os, const Player &p) { 162 | os << "-------- Player:(" << p.id << "," << p.name << ")------" << std::endl; 163 | os << "- m_int8 = " << (int) p.m_int8 << std::endl; 164 | os << "- m_int16 = " << p.m_int16 << std::endl; 165 | os << "- m_int32 = " << p.m_int32 << std::endl; 166 | os << "- m_int64 = " << p.m_int64 << std::endl; 167 | os << "- m_uint8 = " << (int) p.m_uint8 << std::endl; 168 | os << "- m_uint16 = " << p.m_uint16 << std::endl; 169 | os << "- m_uint32 = " << p.m_uint32 << std::endl; 170 | os << "- m_uint64 = " << p.m_uint64 << std::endl; 171 | os << "- m_float = " << p.m_float << std::endl; 172 | os << "- m_double = " << p.m_double << std::endl; 173 | os << "- m_bool = " << p.m_bool << std::endl; 174 | os << "- m_string = " << p.m_string << std::endl; 175 | 176 | os << "- m_bytes = " << p.m_bytes.size() << std::endl; 177 | os << "- m_bytes_tiny = " << p.m_bytes_tiny.size() << std::endl; 178 | os << "- m_bytes_medium = " << p.m_bytes_medium.size() << std::endl; 179 | os << "- m_bytes_long = " << p.m_bytes_long.size() << std::endl; 180 | 181 | os << "- weapon = {" << p.weapon.type << "," << p.weapon.name << "}" << std::endl; 182 | os << "- weapons = " << p.weapons.size() << std::endl; 183 | 184 | return os; 185 | } 186 | 187 | #endif //TINYWORLD_PLAYER_H -------------------------------------------------------------------------------- /example/player.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | // 4 | // 定义protobuf消息 5 | // 6 | 7 | message WeaponProto { 8 | optional uint32 type = 1; 9 | optional string name = 2; 10 | } 11 | 12 | message PlayerProto { 13 | // Scalar: 1 vs N 14 | optional uint32 id = 1; 15 | optional string name = 2; 16 | repeated uint32 quests = 3; 17 | 18 | // Nested: 1 vs N 19 | optional WeaponProto weapon = 4; 20 | repeated WeaponProto weapons = 5; 21 | 22 | // STL 23 | optional bytes weapons_map = 6; 24 | } 25 | 26 | message PlayerProto4Table { 27 | optional uint32 id = 1; 28 | optional bytes name = 2; 29 | optional uint32 age = 3; 30 | 31 | optional bytes weaon = 4; 32 | optional bytes weapns = 5; 33 | } -------------------------------------------------------------------------------- /example/tinyobj/tinyobj.cpp: -------------------------------------------------------------------------------- 1 | #include "tinyobj.h" 2 | 3 | void initTinyObjectSystem() 4 | { 5 | } 6 | 7 | #include "tinyplayer.orm.h" 8 | -------------------------------------------------------------------------------- /example/tinyobj/tinyobj.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYWORLD_TINYOBJ_H 2 | #define TINYWORLD_TINYOBJ_H 3 | 4 | #include "tinyworld.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "tinyserializer.h" 15 | #include "tinyserializer_proto.h" 16 | #include "tinyorm.h" 17 | #include "tinyorm_mysql.h" 18 | 19 | extern void initTinyObjectSystem(); 20 | 21 | #endif //TINYWORLD_TINYOBJ_H 22 | -------------------------------------------------------------------------------- /example/tinyobj/tinyplayer.cpp: -------------------------------------------------------------------------------- 1 | #include "tinyplayer.h" 2 | #include "tinyplayer.pb.h" 3 | 4 | namespace tiny { 5 | 6 | std::string Friend::serialize() const { 7 | FriendProto proto; 8 | proto.set_id(id); 9 | proto.set_name(name); 10 | return proto.SerializeAsString(); 11 | } 12 | 13 | 14 | bool Friend::deserialize(const std::string &data) { 15 | FriendProto proto; 16 | if (!proto.ParseFromString(data)) return false; 17 | id = proto.id(); 18 | name = proto.name(); 19 | return true; 20 | } 21 | 22 | 23 | std::string Country::serialize() const { 24 | CountryProto proto; 25 | proto.set_id(id); 26 | proto.set_name(name); 27 | return proto.SerializeAsString(); 28 | } 29 | 30 | 31 | bool Country::deserialize(const std::string &data) { 32 | CountryProto proto; 33 | if (!proto.ParseFromString(data)) return false; 34 | id = proto.id(); 35 | name = proto.name(); 36 | return true; 37 | } 38 | 39 | 40 | std::string Player::serialize() const { 41 | PlayerProto proto; 42 | proto.set_id(id); 43 | proto.set_name(name); 44 | proto.set_country(::serialize(country)); 45 | proto.set_friends(::serialize(friends)); 46 | proto.set_m_int8(m_int8); 47 | proto.set_m_int16(m_int16); 48 | proto.set_m_int32(m_int32); 49 | proto.set_m_int64(m_int64); 50 | proto.set_m_uint8(m_uint8); 51 | proto.set_m_uint16(m_uint16); 52 | proto.set_m_uint32(m_uint32); 53 | proto.set_m_uint64(m_uint64); 54 | proto.set_m_float(m_float); 55 | proto.set_m_double(m_double); 56 | proto.set_m_bool(m_bool); 57 | proto.set_m_string(m_string); 58 | proto.set_m_bytes(m_bytes); 59 | proto.set_m_bytes_tiny(m_bytes_tiny); 60 | proto.set_m_bytes_medium(m_bytes_medium); 61 | proto.set_m_bytes_long(m_bytes_long); 62 | return proto.SerializeAsString(); 63 | } 64 | 65 | 66 | bool Player::deserialize(const std::string &data) { 67 | PlayerProto proto; 68 | if (!proto.ParseFromString(data)) return false; 69 | id = proto.id(); 70 | name = proto.name(); 71 | ::deserialize(country, proto.country()); 72 | ::deserialize(friends, proto.friends()); 73 | m_int8 = proto.m_int8(); 74 | m_int16 = proto.m_int16(); 75 | m_int32 = proto.m_int32(); 76 | m_int64 = proto.m_int64(); 77 | m_uint8 = proto.m_uint8(); 78 | m_uint16 = proto.m_uint16(); 79 | m_uint32 = proto.m_uint32(); 80 | m_uint64 = proto.m_uint64(); 81 | m_float = proto.m_float(); 82 | m_double = proto.m_double(); 83 | m_bool = proto.m_bool(); 84 | m_string = proto.m_string(); 85 | m_bytes = proto.m_bytes(); 86 | m_bytes_tiny = proto.m_bytes_tiny(); 87 | m_bytes_medium = proto.m_bytes_medium(); 88 | m_bytes_long = proto.m_bytes_long(); 89 | return true; 90 | } 91 | 92 | } // namespace tiny 93 | -------------------------------------------------------------------------------- /example/tinyobj/tinyplayer.h: -------------------------------------------------------------------------------- 1 | 2 | // MIT License 3 | // 4 | // Copyright (c) 2017 david++ 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | // 25 | // !!NOTICE: This file is generated by TOOL, DON'T EDIT!. (by david++)") 26 | // 27 | #ifndef __TINYOBJ_TINYPLAYER__ 28 | #define __TINYOBJ_TINYPLAYER__ 29 | 30 | #include "tinyobj.h" 31 | 32 | namespace tiny { 33 | 34 | // 35 | // 好友 36 | // 37 | struct Friend { 38 | // 39 | // Serialization Support 40 | // 41 | std::string serialize() const; 42 | bool deserialize(const std::string &data); 43 | 44 | // 标识符 45 | uint32_t id = 0; 46 | // 名字 47 | std::string name; 48 | }; 49 | 50 | // 51 | // 国家 52 | // 53 | struct Country { 54 | // 55 | // Serialization Support 56 | // 57 | std::string serialize() const; 58 | bool deserialize(const std::string &data); 59 | 60 | // 标识符 61 | uint32_t id = 0; 62 | // 名字 63 | std::string name; 64 | }; 65 | 66 | // 67 | // 角色信息 68 | // 69 | struct Player { 70 | // 71 | // Serialization Support 72 | // 73 | std::string serialize() const; 74 | bool deserialize(const std::string &data); 75 | 76 | // 标识符 77 | uint32_t id = 0; 78 | // 名字 79 | std::string name = "david"; 80 | // 国家信息 81 | Country country; 82 | // 朋友列表 83 | std::vector friends; 84 | int8_t m_int8 = 22; 85 | int16_t m_int16 = 0; 86 | int32_t m_int32 = 0; 87 | int64_t m_int64 = 0; 88 | uint8_t m_uint8 = 0; 89 | uint16_t m_uint16 = 0; 90 | uint32_t m_uint32 = 0; 91 | uint64_t m_uint64 = 0; 92 | float m_float = 0; 93 | double m_double = 0; 94 | bool m_bool = 0; 95 | std::string m_string; 96 | std::string m_bytes; 97 | std::string m_bytes_tiny; 98 | std::string m_bytes_medium; 99 | std::string m_bytes_long; 100 | }; 101 | } // namespace tiny 102 | #endif // __TINYOBJ_TINYPLAYER__ 103 | -------------------------------------------------------------------------------- /example/tinyobj/tinyplayer.orm.h: -------------------------------------------------------------------------------- 1 | #include "tinyplayer.h" 2 | 3 | RUN_ONCE(PlayerORM) { 4 | using namespace tiny; 5 | TableFactory::instance().table("PLAYER") 6 | .field(&Player::id, "ID", FieldType::UINT32, "0") 7 | .field(&Player::name, "NAME", FieldType::STRING, "david") 8 | .field(&Player::country, "COUNTRY", FieldType::OBJECT) 9 | .field(&Player::friends, "FRIENDS", FieldType::OBJECT) 10 | .field(&Player::m_int8, "M_INT8", FieldType::INT8, "22") 11 | .field(&Player::m_int16, "M_INT16", FieldType::INT16, "0") 12 | .field(&Player::m_int32, "M_INT32", FieldType::INT32, "0") 13 | .field(&Player::m_int64, "M_INT64", FieldType::INT64, "0") 14 | .field(&Player::m_uint8, "M_UINT8", FieldType::UINT8, "0") 15 | .field(&Player::m_uint16, "M_UINT16", FieldType::UINT16, "0") 16 | .field(&Player::m_uint32, "M_UINT32", FieldType::UINT32, "0") 17 | .field(&Player::m_uint64, "M_UINT64", FieldType::UINT64, "0") 18 | .field(&Player::m_float, "M_FLOAT", FieldType::FLOAT, "0") 19 | .field(&Player::m_double, "M_DOUBLE", FieldType::DOUBLE, "0") 20 | .field(&Player::m_bool, "M_BOOL", FieldType::BOOL, "0") 21 | .field(&Player::m_string, "M_STRING", FieldType::STRING) 22 | .field(&Player::m_bytes, "M_BYTES", FieldType::BYTES) 23 | .field(&Player::m_bytes_tiny, "M_BYTES_TINY", FieldType::BYTES_TINY) 24 | .field(&Player::m_bytes_medium, "M_BYTES_MEDIUM", FieldType::BYTES_MEDIUM) 25 | .field(&Player::m_bytes_long, "M_BYTES_LONG", FieldType::BYTES_LONG) 26 | .index("NAME") 27 | .key("ID"); 28 | } 29 | -------------------------------------------------------------------------------- /example/tinyobj/tinyplayer.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package tiny; 4 | 5 | 6 | message FriendProto { 7 | optional uint32 id = 1; 8 | optional bytes name = 2; 9 | }; 10 | 11 | 12 | message CountryProto { 13 | optional uint32 id = 1; 14 | optional bytes name = 2; 15 | }; 16 | 17 | 18 | message PlayerProto { 19 | optional uint32 id = 1; 20 | optional bytes name = 2; 21 | optional bytes country = 3; 22 | optional bytes friends = 4; 23 | optional sint32 m_int8 = 10; 24 | optional sint32 m_int16 = 11; 25 | optional sint32 m_int32 = 12; 26 | optional sint64 m_int64 = 13; 27 | optional uint32 m_uint8 = 14; 28 | optional uint32 m_uint16 = 15; 29 | optional uint32 m_uint32 = 16; 30 | optional uint64 m_uint64 = 17; 31 | optional float m_float = 18; 32 | optional double m_double = 19; 33 | optional bool m_bool = 20; 34 | optional bytes m_string = 21; 35 | optional bytes m_bytes = 22; 36 | optional bytes m_bytes_tiny = 23; 37 | optional bytes m_bytes_medium = 24; 38 | optional bytes m_bytes_long = 25; 39 | }; 40 | 41 | -------------------------------------------------------------------------------- /example/tinyobj/tinyplayer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /include/archive.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | // 4 | // 顺序存储数据格式 5 | // 6 | message ArchiveProto { 7 | repeated ArchiveMemberProto members = 1; 8 | } 9 | 10 | message ArchiveMemberProto { 11 | optional bytes data = 1; 12 | } 13 | 14 | 15 | // 16 | // 整数对应的数据格式 17 | // 18 | message IntegerProto { 19 | optional uint64 value = 1; 20 | } 21 | 22 | // 23 | // 浮点数对应的数据格式 24 | // 25 | message FloatProto { 26 | optional double value = 1; 27 | } 28 | 29 | // 30 | // 字符串对应的数据格式 31 | // 32 | message StringProto { 33 | optional bytes value = 1; 34 | } 35 | 36 | 37 | // 38 | // 序列容器对应的数据格式 39 | // 40 | message SequenceProto { 41 | repeated ArchiveMemberProto values = 1; 42 | } 43 | 44 | // 45 | // 关联性容器对应的数据格式 46 | // 47 | message AssociateProto { 48 | message ValueType { 49 | optional ArchiveMemberProto key = 1; 50 | optional ArchiveMemberProto value = 2; 51 | } 52 | 53 | repeated ValueType values = 1; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /include/hashkit.h: -------------------------------------------------------------------------------- 1 | #ifndef __COMMON_HASHKIT_H 2 | #define __COMMON_HASHKIT_H 3 | 4 | #include 5 | #include 6 | 7 | #if 0 8 | void md5_signature(const unsigned char *key, unsigned int length, unsigned char *result); 9 | uint32_t hash_md5(const char *key, size_t key_length); 10 | uint32_t hash_crc16(const char *key, size_t key_length); 11 | uint32_t hash_crc32(const char *key, size_t key_length); 12 | uint32_t hash_crc32a(const char *key, size_t key_length); 13 | uint32_t hash_fnv1_64(const char *key, size_t key_length); 14 | uint32_t hash_fnv1a_64(const char *key, size_t key_length); 15 | uint32_t hash_fnv1_32(const char *key, size_t key_length); 16 | uint32_t hash_fnv1a_32(const char *key, size_t key_length); 17 | uint32_t hash_hsieh(const char *key, size_t key_length); 18 | uint32_t hash_jenkins(const char *key, size_t length); 19 | #endif 20 | 21 | //typedef unsigned int uint32_t; 22 | 23 | uint32_t hash_murmur(const char *key, size_t length); 24 | 25 | inline uint32_t hash_murmur(const std::string& key) 26 | { 27 | return hash_murmur(key.c_str(), key.size()); 28 | } 29 | 30 | #endif // __COMMON_HASHKIT_H 31 | -------------------------------------------------------------------------------- /include/pool.h: -------------------------------------------------------------------------------- 1 | #ifndef __COMMON_POOL_H 2 | #define __COMMON_POOL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | //////////////////////////////////////////////////////////////// 11 | // 12 | // 连接池封装 13 | // 14 | //////////////////////////////////////////////////////////////// 15 | 16 | template 17 | class ConnectionPool { 18 | public: 19 | //// Internal types 20 | struct ConnectionInfo { 21 | Connection *conn; 22 | time_t last_used; 23 | bool in_use; 24 | 25 | ConnectionInfo(Connection *c) : 26 | conn(c), 27 | last_used(time(0)), 28 | in_use(true) { 29 | } 30 | 31 | // Strict weak ordering for ConnectionInfo objects. 32 | // 33 | // This ordering defines all in-use connections to be "less 34 | // than" those not in use. Within each group, connections 35 | // less recently touched are less than those more recent. 36 | bool operator<(const ConnectionInfo &rhs) const { 37 | const ConnectionInfo &lhs = *this; 38 | return lhs.in_use == rhs.in_use ? 39 | lhs.last_used < rhs.last_used : 40 | lhs.in_use; 41 | } 42 | }; 43 | 44 | typedef std::list PoolT; 45 | typedef typename PoolT::iterator PoolIt; 46 | 47 | public: 48 | ConnectionPool() {} 49 | 50 | virtual ~ConnectionPool() {} 51 | 52 | /// Returns true if pool is empty 53 | bool empty() const { return pool_.empty(); } 54 | 55 | 56 | /// Grab a free connection from the pool. 57 | /// 58 | /// This method creates a new connection if an unused one doesn't 59 | /// exist, and destroys any that have remained unused for too long. 60 | /// If there is more than one free connection, we return the most 61 | /// recently used one; this allows older connections to die off over 62 | /// time when the caller's need for connections decreases. 63 | /// 64 | /// Do not delete the returned pointer. This object manages the 65 | /// lifetime of connection objects it creates. 66 | 67 | virtual Connection *grab() { 68 | std::lock_guard guard(mutex_); 69 | if (Connection *mru = find_mru()) { 70 | return mru; 71 | } else { 72 | // No free connections, so create and return a new one. 73 | pool_.push_back(ConnectionInfo(create())); 74 | return pool_.back().conn; 75 | } 76 | } 77 | 78 | 79 | /// Marks the connection as no longer in use. 80 | /// 81 | /// The pool updates the last-used time of a connection only on 82 | /// release, on the assumption that it was used just prior. There's 83 | /// nothing forcing you to do it this way: your code is free to 84 | /// delay releasing idle connections as long as it likes. You 85 | /// want to avoid this because it will make the pool perform poorly; 86 | /// if it doesn't know approximately how long a connection has 87 | /// really been idle, it can't make good judgements about when to 88 | /// remove it from the pool. 89 | 90 | virtual void release(const Connection *pc) { 91 | std::lock_guard guard(mutex_); 92 | for (PoolIt it = pool_.begin(); it != pool_.end(); ++it) { 93 | if (it->conn == pc) { 94 | it->in_use = false; 95 | it->last_used = time(0); 96 | break; 97 | } 98 | } 99 | } 100 | 101 | 102 | /// Removes the given connection from the pool 103 | /// 104 | /// If you mean to simply return a connection to the pool after 105 | /// you're finished using it, call release() instead. This method 106 | /// is primarily for error handling: you somehow have figured out 107 | /// that the connection is defective, so want it destroyed and 108 | /// removed from the pool. If you also want a different connection 109 | /// to retry your operation on, call exchange() instead. 110 | /// 111 | void remove(const Connection *pc) { 112 | std::lock_guard guard(mutex_); 113 | for (PoolIt it = pool_.begin(); it != pool_.end(); ++it) { 114 | if (it->conn == pc) { 115 | remove(it); 116 | return; 117 | } 118 | } 119 | } 120 | 121 | /// Remove all unused connections from the pool 122 | void shrink() { clear(false); } 123 | 124 | void removeAll() { clear(true); } 125 | 126 | protected: 127 | /// Drains the pool, freeing all allocated memory. 128 | /// 129 | /// A derived class must call this in its dtor to avoid leaking all 130 | /// Connection objects still in existence. We can't do it up at 131 | /// this level because this class's dtor can't call our subclass's 132 | /// destroy() method. 133 | /// 134 | /// all if true, remove all connections, even those in use 135 | void clear(bool all = true) { 136 | std::lock_guard guard(mutex_); 137 | 138 | PoolIt it = pool_.begin(); 139 | while (it != pool_.end()) { 140 | if (all || !it->in_use) { 141 | remove(it++); 142 | } else { 143 | ++it; 144 | } 145 | } 146 | } 147 | 148 | /// Create a new connection 149 | /// 150 | /// Subclasses must override this. 151 | /// 152 | /// Essentially, this method lets your code tell ConnectionPool 153 | /// what server to connect to, what login parameters to use, what 154 | /// connection options to enable, etc. ConnectionPool can't know 155 | /// any of this without your help. 156 | /// 157 | /// A connected Connection object 158 | virtual Connection *create() = 0; 159 | 160 | /// Destroy a connection 161 | /// 162 | /// Subclasses must override this. 163 | /// 164 | /// This is for destroying the objects returned by create(). 165 | /// Because we can't know what the derived class did to create the 166 | /// connection we can't reliably know how to destroy it. 167 | virtual void destroy(Connection *) = 0; 168 | 169 | /// Returns the current size of the internal connection pool. 170 | size_t size() const { return pool_.size(); } 171 | 172 | private: 173 | //// Internal support functions 174 | Connection *find_mru() { 175 | PoolIt mru = std::max_element(pool_.begin(), pool_.end()); 176 | if (mru != pool_.end() && !mru->in_use) { 177 | mru->in_use = true; 178 | return mru->conn; 179 | } else { 180 | return 0; 181 | } 182 | } 183 | 184 | void remove(const PoolIt &it) { 185 | // Don't grab the mutex. Only called from other functions that do 186 | // grab it. 187 | destroy(it->conn); 188 | pool_.erase(it); 189 | } 190 | 191 | 192 | //// Internal data 193 | PoolT pool_; 194 | std::mutex mutex_; 195 | }; 196 | 197 | //////////////////////////////////////////////////////////////// 198 | // 199 | // 连接池封装(有上限) 200 | // 201 | //////////////////////////////////////////////////////////////// 202 | template > 203 | class ConnectionPoolWithLimit : public PoolType { 204 | public: 205 | typedef PoolType Base; 206 | 207 | ConnectionPoolWithLimit(const unsigned int maxconn = 1) { 208 | conns_max_ = maxconn; 209 | conns_in_use_ = 0; 210 | grab_waittime_ = -1; 211 | } 212 | 213 | virtual ~ConnectionPoolWithLimit() { 214 | Base::clear(); 215 | } 216 | 217 | // 218 | // aquire the resource 219 | // 220 | Connection *acquire() { 221 | return this->grab(); 222 | } 223 | 224 | // 225 | // release the resource 226 | // 227 | void putback(const Connection *conn) { 228 | if (conn) 229 | this->release(conn); 230 | } 231 | 232 | // 233 | // pool maximum size 234 | // 235 | void setMaxConn(unsigned int maxconn) { 236 | conns_max_ = maxconn; 237 | } 238 | 239 | // 240 | // -1 - waiting for resource forever(your first choice) 241 | // N - waiting for resource with timeout(ms) 242 | // 0 - no waiting 243 | // 244 | void setGrabWaitTime(int ms) { 245 | grab_waittime_ = ms; 246 | } 247 | 248 | // 249 | // create all the resource (using this at starting point) 250 | // once created, will not going to release it, you can aquire it 251 | // 252 | void createAll() { 253 | std::vector conns; 254 | for (unsigned int i = 0; i < conns_max_; i++) 255 | conns.push_back(acquire()); 256 | 257 | for (size_t i = 0; i < conns.size(); i++) 258 | putback(conns[i]); 259 | } 260 | 261 | public: 262 | virtual Connection *grab() { 263 | // no wait 264 | if (grab_waittime_ == 0) { 265 | if (conns_in_use_ >= conns_max_) { 266 | std::cout << "grab failed: not engouh" << std::endl; 267 | return NULL; 268 | } 269 | } 270 | // waiting for release forever 271 | else if (grab_waittime_ < 0) { 272 | while (conns_in_use_ >= conns_max_) { 273 | std::chrono::milliseconds ms(1); 274 | std::this_thread::sleep_for(ms); 275 | } 276 | } 277 | // wating for release during grab_waittime_(ms) 278 | else if (grab_waittime_ > 0) { 279 | int tries = 0; 280 | while (conns_in_use_ >= conns_max_) { 281 | // waiting for release 282 | std::chrono::milliseconds ms(grab_waittime_); 283 | std::this_thread::sleep_for(ms); 284 | 285 | if (++tries > 1000) 286 | return NULL; 287 | } 288 | } 289 | 290 | { 291 | std::lock_guard guard(mutex_); 292 | ++conns_in_use_; 293 | } 294 | 295 | return Base::grab(); 296 | } 297 | 298 | virtual void release(const Connection *pc) { 299 | Base::release(pc); 300 | 301 | { 302 | std::lock_guard guard(mutex_); 303 | --conns_in_use_; 304 | } 305 | } 306 | 307 | virtual Connection *create() = 0; 308 | 309 | virtual void destroy(Connection *cp) { 310 | delete cp; 311 | } 312 | 313 | protected: 314 | // Number of connections currently in use 315 | volatile unsigned int conns_in_use_; 316 | unsigned int conns_max_; 317 | int grab_waittime_; 318 | std::mutex mutex_; 319 | }; 320 | 321 | template 322 | class ScopedConnection { 323 | public: 324 | explicit ScopedConnection(PoolType *pool = &PoolType::instance()) 325 | : pool_(pool), connection_(pool ? (ConnType *) pool->acquire() : NULL) {} 326 | 327 | ~ScopedConnection() { 328 | if (pool_) pool_->putback(connection_); 329 | } 330 | 331 | ConnType *operator->() const { return connection_; } 332 | 333 | ConnType &operator*() const { return *connection_; } 334 | 335 | operator void *() const { return connection_; } 336 | 337 | ConnType *get() { return connection_; } 338 | 339 | private: 340 | PoolType *pool_; 341 | ConnType *connection_; 342 | }; 343 | 344 | 345 | #endif // __COMMON_POOL_H -------------------------------------------------------------------------------- /include/pool_sharding.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYWORLD_POOL_SHARDING_H 2 | #define TINYWORLD_POOL_SHARDING_H 3 | 4 | #include "sharding.h" 5 | 6 | template 7 | class ShardingConnectionPool : public Sharding { 8 | public: 9 | typedef Sharding Base; 10 | 11 | ShardingConnectionPool(int shardnum = 1) 12 | : Base(shardnum) { 13 | } 14 | 15 | virtual ~ShardingConnectionPool() {} 16 | 17 | public: 18 | ConnType *acquireByShard(int shard) { 19 | PoolType *pool = this->getShardByID(shard); 20 | if (pool) { 21 | return (ConnType *) pool->acquire(); 22 | } 23 | 24 | return NULL; 25 | } 26 | 27 | ConnType *acquireByHash(uint32_t hash) { 28 | PoolType *pool = this->getShardByHash(hash); 29 | if (pool) { 30 | return (ConnType *) pool->acquire(); 31 | } 32 | 33 | return NULL; 34 | } 35 | 36 | ConnType *acquireByKey(const std::string &key) { 37 | PoolType *pool = this->getShardByKey(key); 38 | if (pool) { 39 | return (ConnType *) pool->acquire(); 40 | } 41 | 42 | return NULL; 43 | } 44 | 45 | void putback(const ConnType *conn) { 46 | if (!conn) return; 47 | 48 | PoolType *pool = this->getShardByID(conn->shard()); 49 | if (pool) { 50 | return pool->putback(conn); 51 | } 52 | } 53 | }; 54 | 55 | 56 | template 57 | class ScopedConnectionByShard { 58 | public: 59 | explicit ScopedConnectionByShard(int shard, PoolType *pool = PoolType::instance()) 60 | : pool_(pool), connection_(pool->acquireByShard(shard)) {} 61 | 62 | ~ScopedConnectionByShard() { 63 | if (pool_) pool_->putback(connection_); 64 | } 65 | 66 | ConnType *operator->() const { return connection_; } 67 | 68 | ConnType &operator*() const { return *connection_; } 69 | 70 | operator void *() const { return connection_; } 71 | 72 | private: 73 | PoolType *pool_; 74 | ConnType *connection_; 75 | }; 76 | 77 | template 78 | class ScopedConnectionByHash { 79 | public: 80 | explicit ScopedConnectionByHash(uint32_t hash, PoolType *pool = PoolType::instance()) 81 | : pool_(pool), connection_(pool->acquireByHash(hash)) {} 82 | 83 | ~ScopedConnectionByHash() { 84 | if (pool_) pool_->putback(connection_); 85 | } 86 | 87 | ConnType *operator->() const { return connection_; } 88 | 89 | ConnType &operator*() const { return *connection_; } 90 | 91 | operator void *() const { return connection_; } 92 | 93 | private: 94 | PoolType *pool_; 95 | ConnType *connection_; 96 | }; 97 | 98 | 99 | template 100 | class ScopedConnectionByKey { 101 | public: 102 | explicit ScopedConnectionByKey(const std::string &key, PoolType *pool = PoolType::instance()) 103 | : pool_(pool), connection_(pool->acquireByKey(key)) {} 104 | 105 | ~ScopedConnectionByKey() { 106 | if (pool_) pool_->putback(connection_); 107 | } 108 | 109 | ConnType *operator->() const { return connection_; } 110 | 111 | ConnType &operator*() const { return *connection_; } 112 | 113 | operator void *() const { return connection_; } 114 | 115 | private: 116 | PoolType *pool_; 117 | ConnType *connection_; 118 | }; 119 | 120 | 121 | 122 | #endif //TINYWORLD_POOL_SHARDING_H 123 | -------------------------------------------------------------------------------- /include/sharding.h: -------------------------------------------------------------------------------- 1 | #ifndef __COMMON_SHARDING_H 2 | #define __COMMON_SHARDING_H 3 | 4 | #include 5 | #include "hashkit.h" 6 | 7 | struct MurmurHash 8 | { 9 | static uint32_t hash(const std::string& key) 10 | { 11 | return hash_murmur(key.data(), key.size()); 12 | } 13 | }; 14 | 15 | template 16 | class Sharding 17 | { 18 | public: 19 | typedef std::map Shards; 20 | 21 | Sharding(int shardnum = 1) : shardnum_(shardnum) 22 | { 23 | } 24 | 25 | ~Sharding() 26 | { 27 | } 28 | 29 | void setShardNum(int shardnum) 30 | { 31 | shardnum_ = shardnum; 32 | } 33 | 34 | int shardNum() { return shardnum_; } 35 | 36 | bool isReady() 37 | { 38 | for (int i = 0; i < shardnum_; i++) 39 | if (shards_.find(i) == shards_.end()) 40 | return false; 41 | return true; 42 | } 43 | 44 | bool addShard(Shard* shard) 45 | { 46 | if (!shard) return false; 47 | 48 | if (shard->shard() == -1) return false; 49 | 50 | if (shards_.find(shard->shard()) != shards_.end()) 51 | return false; 52 | 53 | shards_[shard->shard()] = shard; 54 | return true; 55 | } 56 | 57 | // 58 | // MAXINT divided by SHARDNUM 59 | // 60 | // N: total sharding number(2^x) 61 | // M: 2^32 62 | // 63 | // shard0 shard1 shard2 shard(N-1) 64 | // |________|________|............| 65 | // 0 M/N 2M/N M 66 | // 67 | Shard* getShardByHash(uint32_t hashcode) 68 | { 69 | return shardnum_ > 0 ? getShardByID(hashcode / (4294967296UL/shardnum_)) : NULL; 70 | } 71 | 72 | Shard* getShardByKey(const std::string& key) 73 | { 74 | return getShardByHash(Hash::hash(key)); 75 | } 76 | 77 | Shard* getShardByID(int shard) 78 | { 79 | typename Shards::iterator it = shards_.find(shard); 80 | if (it != shards_.end()) 81 | return it->second; 82 | return NULL; 83 | } 84 | 85 | protected: 86 | Shards shards_; 87 | 88 | // total shards number(best to be 2^n) 89 | int shardnum_; 90 | }; 91 | 92 | #endif // __COMMON_SHARDING_H -------------------------------------------------------------------------------- /include/tinydb.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYWORLD_TINY_DB_H 2 | #define TINYWORLD_TINY_DB_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "tinylogger.h" 8 | 9 | class SOCIPool { 10 | public: 11 | static SOCIPool& instance() { 12 | static SOCIPool pool_; 13 | return pool_; 14 | } 15 | 16 | bool connect(const std::string& url, size_t poolsize = 1) { 17 | soci::register_factory_mysql(); 18 | 19 | cpool_size_ = poolsize; 20 | cpool_ = std::make_shared(poolsize); 21 | 22 | try { 23 | for (size_t i = 0; i < cpool_size_; ++i) { 24 | soci::session &sql = cpool_->at(i); 25 | sql.open(url); 26 | } 27 | return true; 28 | } 29 | catch (const soci::mysql_soci_error &e) { 30 | LOG_ERROR("SOCI", "Connect Failed, SOCI Error:%s", e.what()); 31 | } 32 | catch (const std::exception &e) { 33 | LOG_ERROR("SOCI", "Connect Failed, Error:%s", e.what()); 34 | } 35 | 36 | return false; 37 | } 38 | 39 | soci::connection_pool* pool() { return cpool_.get(); } 40 | 41 | private: 42 | size_t cpool_size_ = 0; 43 | std::shared_ptr cpool_; 44 | }; 45 | 46 | #endif //TINYWORLD_TINY_DB_H 47 | -------------------------------------------------------------------------------- /include/tinylogger.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYWORLD_TINYLOGGER_H 2 | #define TINYWORLD_TINYLOGGER_H 3 | 4 | #include 5 | #include 6 | 7 | ////////////////////////////////////////////////////////// 8 | // 9 | // Logger Wrapper: 10 | // 11 | // TRACE < DEBUG < INFO < WARN < ERROR << FATAL 12 | // 13 | // - C printf style: 14 | // LOG_TRACE(logger-name, fmt, ...) 15 | // LOG_DEBUG(logger-name, fmt, ...) 16 | // LOG_INFO (logger-name, fmt, ...) 17 | // 18 | // LOG_WARN (logger-name, fmt, ...) 19 | // LOG_ERROR(logger-name, fmt, ...) 20 | // LOG_FATAL(logger-name, fmt, ...) 21 | // 22 | // - C++ stream style: 23 | // LOGGER_TRACE(logger-name, a << b << ...) 24 | // LOGGER_DEBUG(logger-name, a << b << ...) 25 | // LOGGER_INFO (logger-name, a << b << ...) 26 | // 27 | // LOGGER_WARN (logger-name, a << b << ...) 28 | // LOGGER_ERROR(logger-name, a << b << ...) 29 | // LOGGER_FATAL(logger-name, a << b << ...) 30 | // 31 | ///////////////////////////////////////////////////////// 32 | 33 | 34 | #define LOG_LENGTH_MAX 1024 35 | 36 | #ifndef TINYLOGGER_LOG4CXX 37 | #define TINYLOGGER_SIMPLE 38 | #endif 39 | 40 | ////////////////////////////////////////////////////////// 41 | // 42 | // logger using std::cout/std::cerr 43 | // 44 | ///////////////////////////////////////////////////////// 45 | 46 | #ifdef TINYLOGGER_SIMPLE 47 | 48 | #include 49 | #include 50 | #include 51 | #include 52 | 53 | #define SIMPLE_LOGGER_TRACE 1 54 | #define SIMPLE_LOGGER_DEBUG 2 55 | #define SIMPLE_LOGGER_INFO 3 56 | #define SIMPLE_LOGGER_WARN 4 57 | #define SIMPLE_LOGGER_ERROR 5 58 | #define SIMPLE_LOGGER_FATAL 6 59 | 60 | // 61 | // C printf style 62 | // 63 | #define LOG_TRACE(loggername, fmt, ...) \ 64 | SimpleLogger::instance().print_log(SIMPLE_LOGGER_TRACE, loggername, __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, ##__VA_ARGS__) 65 | 66 | #define LOG_DEBUG(loggername, fmt, ...) \ 67 | SimpleLogger::instance().print_log(SIMPLE_LOGGER_DEBUG, loggername, __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, ##__VA_ARGS__) 68 | 69 | #define LOG_INFO(loggername, fmt, ...) \ 70 | SimpleLogger::instance().print_log(SIMPLE_LOGGER_INFO, loggername, __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, ##__VA_ARGS__) 71 | 72 | #define LOG_WARN(loggername, fmt, ...) \ 73 | SimpleLogger::instance().print_log(SIMPLE_LOGGER_WARN, loggername, __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, ##__VA_ARGS__) 74 | 75 | #define LOG_ERROR(loggername, fmt, ...) \ 76 | SimpleLogger::instance().print_log(SIMPLE_LOGGER_ERROR, loggername, __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, ##__VA_ARGS__) 77 | 78 | #define LOG_FATAL(loggername, fmt, ...) \ 79 | SimpleLogger::instance().print_log(SIMPLE_LOGGER_FATAL, loggername, __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, ##__VA_ARGS__) 80 | 81 | // 82 | // C++ streambuf style 83 | // 84 | #define LOGGER_TRACE(loggername, message) { \ 85 | std::ostringstream oss_; \ 86 | oss_ << message; \ 87 | SimpleLogger::instance().print_log(SIMPLE_LOGGER_TRACE, loggername, __FILE__, __LINE__, __PRETTY_FUNCTION__, oss_.str().c_str()); \ 88 | } 89 | 90 | #define LOGGER_DEBUG(loggername, message) { \ 91 | std::ostringstream oss_; \ 92 | oss_ << message; \ 93 | SimpleLogger::instance().print_log(SIMPLE_LOGGER_DEBUG, loggername, __FILE__, __LINE__, __PRETTY_FUNCTION__, oss_.str().c_str()); \ 94 | } 95 | 96 | #define LOGGER_INFO(loggername, message) { \ 97 | std::ostringstream oss_; \ 98 | oss_ << message; \ 99 | SimpleLogger::instance().print_log(SIMPLE_LOGGER_INFO, loggername, __FILE__, __LINE__, __PRETTY_FUNCTION__, oss_.str().c_str()); \ 100 | } 101 | 102 | #define LOGGER_WARN(loggername, message) { \ 103 | std::ostringstream oss_; \ 104 | oss_ << message; \ 105 | SimpleLogger::instance().print_log(SIMPLE_LOGGER_WARN, loggername, __FILE__, __LINE__, __PRETTY_FUNCTION__, oss_.str().c_str()); \ 106 | } 107 | 108 | #define LOGGER_ERROR(loggername, message) { \ 109 | std::ostringstream oss_; \ 110 | oss_ << message; \ 111 | SimpleLogger::instance().print_log(SIMPLE_LOGGER_ERROR, loggername, __FILE__, __LINE__, __PRETTY_FUNCTION__, oss_.str().c_str()); \ 112 | } 113 | 114 | #define LOGGER_FATAL(loggername, message) { \ 115 | std::ostringstream oss_; \ 116 | oss_ << message; \ 117 | SimpleLogger::instance().print_log(SIMPLE_LOGGER_FATAL, loggername, __FILE__, __LINE__, __PRETTY_FUNCTION__, oss_.str().c_str()); \ 118 | } 119 | 120 | 121 | struct SimpleLogger 122 | { 123 | static SimpleLogger& instance() 124 | { 125 | static SimpleLogger logger_instance; 126 | return logger_instance; 127 | } 128 | 129 | const char* level_name(int level) 130 | { 131 | switch (level) 132 | { 133 | case SIMPLE_LOGGER_TRACE : return "TRACE"; 134 | case SIMPLE_LOGGER_DEBUG : return "DEBUG"; 135 | case SIMPLE_LOGGER_INFO : return "INFO"; 136 | case SIMPLE_LOGGER_WARN : return "WARN"; 137 | case SIMPLE_LOGGER_ERROR : return "ERROR"; 138 | case SIMPLE_LOGGER_FATAL : return "FATAL"; 139 | } 140 | return ""; 141 | } 142 | 143 | void print_log(int level, 144 | const char *loggername, 145 | const char *file, 146 | int line, 147 | const char *func, 148 | const char *fmt, ...) 149 | { 150 | char buf[LOG_LENGTH_MAX] = ""; 151 | va_list ap; 152 | va_start(ap, fmt); 153 | vsnprintf(buf, sizeof(buf), fmt, ap); 154 | va_end(ap); 155 | 156 | char nowstr[64] = ""; 157 | std::time_t now = std::time(NULL); 158 | std::strftime(nowstr, sizeof(nowstr), "%Y-%m-%d %H:%M:%S", std::localtime(&now)); 159 | 160 | std::ostream *output = &std::cout; 161 | // if (level >= SIMPLE_LOGGER_WARN) 162 | // output = &std::cerr; 163 | 164 | (*output) << nowstr 165 | << " " << std::setfill(' ') << std::setw(5) << level_name(level) << ": " 166 | << "[" << loggername << "] - " << buf 167 | << std::endl; 168 | output->flush(); 169 | } 170 | }; 171 | 172 | 173 | #endif // TINYLOGGER_SIMPLE 174 | 175 | 176 | ////////////////////////////////////////////////////////// 177 | // 178 | // logger using log4cxx 179 | // 180 | // ./configure --with-charset=utf-8 --with-logchar=utf-8 181 | // 182 | ///////////////////////////////////////////////////////// 183 | 184 | #ifdef TINYLOGGER_LOG4CXX 185 | 186 | #include "log4cxx/logger.h" 187 | #include "log4cxx/basicconfigurator.h" 188 | #include "log4cxx/propertyconfigurator.h" 189 | 190 | using log4cxx::LoggerPtr; 191 | using log4cxx::Logger; 192 | using log4cxx::BasicConfigurator; 193 | using log4cxx::PropertyConfigurator; 194 | 195 | // BasicConfigurator::configure(); 196 | // PropertyConfigurator::configure(filename); 197 | // PropertyConfigurator::configureAndWatch(filename); 198 | 199 | // LOG4CXX_TRACE 200 | // LOG4CXX_DEBUG 201 | // LOG4CXX_INFO 202 | // LOG4CXX_WARN 203 | // LOG4CXX_ERROR 204 | // LOG4CXX_FATAL 205 | // LOG4CXX_ASSERT 206 | 207 | // 208 | // C printf style 209 | // 210 | #define LOG_TRACE(loggername, fmt, ...) { \ 211 | log4cxx::LoggerPtr logger_(log4cxx::Logger::getLogger(loggername)); \ 212 | if (LOG4CXX_UNLIKELY(logger_->isTraceEnabled())) {\ 213 | char buf_[LOG_LENGTH_MAX] = ""; \ 214 | snprintf(buf_, sizeof(buf_), fmt, ##__VA_ARGS__ ); \ 215 | logger_->forcedLog(log4cxx::Level::getTrace(), buf_, LOG4CXX_LOCATION); \ 216 | }} 217 | 218 | #define LOG_DEBUG(loggername, fmt, ...) { \ 219 | log4cxx::LoggerPtr logger_(log4cxx::Logger::getLogger(loggername)); \ 220 | if (LOG4CXX_UNLIKELY(logger_->isDebugEnabled())) {\ 221 | char buf_[LOG_LENGTH_MAX] = ""; \ 222 | snprintf(buf_, sizeof(buf_), fmt, ##__VA_ARGS__ ); \ 223 | logger_->forcedLog(log4cxx::Level::getDebug(), buf_, LOG4CXX_LOCATION); \ 224 | }} 225 | 226 | #define LOG_INFO(loggername, fmt, ...) { \ 227 | log4cxx::LoggerPtr logger_(log4cxx::Logger::getLogger(loggername)); \ 228 | if (LOG4CXX_UNLIKELY(logger_->isInfoEnabled())) {\ 229 | char buf_[LOG_LENGTH_MAX] = ""; \ 230 | snprintf(buf_, sizeof(buf_), fmt, ##__VA_ARGS__ ); \ 231 | logger_->forcedLog(log4cxx::Level::getInfo(), buf_, LOG4CXX_LOCATION); \ 232 | }} 233 | 234 | #define LOG_WARN(loggername, fmt, ...) { \ 235 | log4cxx::LoggerPtr logger_(log4cxx::Logger::getLogger(loggername)); \ 236 | if (LOG4CXX_UNLIKELY(logger_->isWarnEnabled())) {\ 237 | char buf_[LOG_LENGTH_MAX] = ""; \ 238 | snprintf(buf_, sizeof(buf_), fmt, ##__VA_ARGS__ ); \ 239 | logger_->forcedLog(log4cxx::Level::getWarn(), buf_, LOG4CXX_LOCATION); \ 240 | }} 241 | 242 | #define LOG_ERROR(loggername, fmt, ...) { \ 243 | log4cxx::LoggerPtr logger_(log4cxx::Logger::getLogger(loggername)); \ 244 | if (LOG4CXX_UNLIKELY(logger_->isErrorEnabled())) {\ 245 | char buf_[LOG_LENGTH_MAX] = ""; \ 246 | snprintf(buf_, sizeof(buf_), fmt, ##__VA_ARGS__ ); \ 247 | logger_->forcedLog(log4cxx::Level::getError(), buf_, LOG4CXX_LOCATION); \ 248 | }} 249 | 250 | #define LOG_FATAL(loggername, fmt, ...) { \ 251 | log4cxx::LoggerPtr logger_(log4cxx::Logger::getLogger(loggername)); \ 252 | if (LOG4CXX_UNLIKELY(logger_->isFatalEnabled())) {\ 253 | char buf_[LOG_LENGTH_MAX] = ""; \ 254 | snprintf(buf_, sizeof(buf_), fmt, ##__VA_ARGS__ ); \ 255 | logger_->forcedLog(log4cxx::Level::getFatal(), buf_, LOG4CXX_LOCATION); \ 256 | }} 257 | 258 | 259 | // 260 | // C++ streambuf style 261 | // 262 | #define LOGGER_TRACE(loggername, message) { \ 263 | if (LOG4CXX_UNLIKELY(logger->isTraceEnabled())) {\ 264 | log4cxx::helpers::MessageBuffer oss_; \ 265 | log4cxx::LoggerPtr logger_(log4cxx::Logger::getLogger(loggername)); \ 266 | logger_->forcedLog(::log4cxx::Level::getTrace(), oss_.str(oss_ << message), LOG4CXX_LOCATION); \ 267 | }} 268 | 269 | #define LOGGER_DEBUG(loggername, message) { \ 270 | if (LOG4CXX_UNLIKELY(logger->isDebugEnabled())) {\ 271 | log4cxx::helpers::MessageBuffer oss_; \ 272 | log4cxx::LoggerPtr logger_(log4cxx::Logger::getLogger(loggername)); \ 273 | logger_->forcedLog(::log4cxx::Level::getDebug(), oss_.str(oss_ << message), LOG4CXX_LOCATION); \ 274 | }} 275 | 276 | #define LOGGER_INFO(loggername, message) { \ 277 | if (LOG4CXX_UNLIKELY(logger->isInfoEnabled())) {\ 278 | log4cxx::helpers::MessageBuffer oss_; \ 279 | log4cxx::LoggerPtr logger_(log4cxx::Logger::getLogger(loggername)); \ 280 | logger_->forcedLog(::log4cxx::Level::getInfo(), oss_.str(oss_ << message), LOG4CXX_LOCATION); \ 281 | }} 282 | 283 | #define LOGGER_WARN(loggername, message) { \ 284 | if (LOG4CXX_UNLIKELY(logger->isWarnEnabled())) {\ 285 | log4cxx::helpers::MessageBuffer oss_; \ 286 | log4cxx::LoggerPtr logger_(log4cxx::Logger::getLogger(loggername)); \ 287 | logger_->forcedLog(::log4cxx::Level::getWarn(), oss_.str(oss_ << message), LOG4CXX_LOCATION); \ 288 | }} 289 | 290 | #define LOGGER_ERROR(loggername, message) { \ 291 | if (LOG4CXX_UNLIKELY(logger->isErrorEnabled())) {\ 292 | log4cxx::helpers::MessageBuffer oss_; \ 293 | log4cxx::LoggerPtr logger_(log4cxx::Logger::getLogger(loggername)); \ 294 | logger_->forcedLog(::log4cxx::Level::getError(), oss_.str(oss_ << message), LOG4CXX_LOCATION); \ 295 | }} 296 | 297 | #define LOGGER_FATAL(loggername, message) { \ 298 | if (LOG4CXX_UNLIKELY(logger->isFatalEnabled())) {\ 299 | log4cxx::helpers::MessageBuffer oss_; \ 300 | log4cxx::LoggerPtr logger_(log4cxx::Logger::getLogger(loggername)); \ 301 | logger_->forcedLog(::log4cxx::Level::getFatal(), oss_.str(oss_ << message), LOG4CXX_LOCATION); \ 302 | }} 303 | 304 | #endif // TINYLOGGER_LOG4CXX 305 | 306 | #endif //TINYWORLD_TINYLOGGER_H 307 | -------------------------------------------------------------------------------- /include/tinymysql.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYWORLD_TINYMYSQL_H 2 | #define TINYWORLD_TINYMYSQL_H 3 | 4 | #include 5 | #include "pool.h" 6 | #include "pool_sharding.h" 7 | 8 | class MySqlConnection : public mysqlpp::Connection { 9 | public: 10 | MySqlConnection(); 11 | 12 | MySqlConnection(const std::string &url); 13 | 14 | virtual ~MySqlConnection() {} 15 | 16 | // 17 | // TinyURL Format: 18 | // mysql://username:passwd@host:port/db?shard=value... 19 | // 20 | bool connectByURL(const std::string &url); 21 | 22 | int shard() const { return shard_; } 23 | 24 | private: 25 | int shard_; 26 | }; 27 | 28 | class MySqlConnectionPool : public ConnectionPoolWithLimit { 29 | public: 30 | MySqlConnectionPool(); 31 | 32 | virtual ~MySqlConnectionPool() {} 33 | 34 | static MySqlConnectionPool& instance() { 35 | static MySqlConnectionPool mypool; 36 | return mypool; 37 | } 38 | 39 | 40 | // 41 | // TinyURL Format: 42 | // mysql://username:passwd@host:port/db?shard=value&idletime=xx&maxconn=xx... 43 | // shard - shard 44 | // idletime - mysql will close the idle client 45 | // maxconn - pool's biggest connection number 46 | void setServerAddress(const std::string &url); 47 | 48 | void setIdleTime(unsigned int seconds) { 49 | wait_timeout_ = seconds; 50 | } 51 | 52 | int shard() const { return shard_; } 53 | 54 | const std::string &url() const { return url_; } 55 | 56 | void connect(const std::string& url) { 57 | setServerAddress(url); 58 | createAll(); 59 | } 60 | 61 | protected: 62 | virtual mysqlpp::Connection *create(); 63 | 64 | 65 | virtual unsigned int max_idle_time() { 66 | // Set our idle time at an example-friendly 3 seconds. A real 67 | // pool would return some fraction of the server's connection 68 | // idle timeout instead. 69 | // show variables like '%timeout%'; 70 | return wait_timeout_; 71 | } 72 | 73 | private: 74 | // MySQL: show variables like '%timeout%'; 75 | unsigned int wait_timeout_; 76 | 77 | // Our connection parameters 78 | std::string url_; 79 | 80 | int shard_; 81 | }; 82 | 83 | 84 | class MySqlShardingPool : public ShardingConnectionPool { 85 | public: 86 | typedef ShardingConnectionPool Base; 87 | 88 | MySqlShardingPool(int shardnum = 1) { 89 | Base::setShardNum(shardnum); 90 | } 91 | 92 | ~MySqlShardingPool() { 93 | fini(); 94 | } 95 | 96 | static MySqlShardingPool *instance(); 97 | 98 | public: 99 | bool init(); 100 | 101 | void fini(); 102 | 103 | bool addShardings(const std::vector &urls); 104 | 105 | bool addSharding(const std::string &url); 106 | }; 107 | 108 | typedef ScopedConnection ScopedMySqlConnection; 109 | typedef ScopedConnectionByShard MySqlConnectionByShard; 110 | typedef ScopedConnectionByHash MySqlConnectionByHash; 111 | typedef ScopedConnectionByKey MySqlConnectionByKey; 112 | 113 | #endif //TINYWORLD_TINYMYSQL_H 114 | -------------------------------------------------------------------------------- /include/tinyorm.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 david++ 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #ifndef TINYWORLD_TINYORM_H 22 | #define TINYWORLD_TINYORM_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "tinyreflection.h" 30 | #include "tinyserializer.h" 31 | #include "tinyserializer_proto.h" 32 | 33 | enum class FieldType : uint8_t { 34 | INT8, 35 | INT16, 36 | INT32, 37 | INT64, 38 | 39 | UINT8, 40 | UINT16, 41 | UINT32, 42 | UINT64, 43 | 44 | BOOL, 45 | 46 | FLOAT, 47 | DOUBLE, 48 | 49 | STRING, 50 | VCHAR, 51 | 52 | BYTES, 53 | BYTES_TINY, 54 | BYTES_MEDIUM, 55 | BYTES_LONG, 56 | 57 | OBJECT, 58 | }; 59 | 60 | class FieldDescriptor { 61 | public: 62 | using Ptr = std::shared_ptr; 63 | 64 | FieldDescriptor(const std::string &_name, 65 | FieldType _type, 66 | const std::string &_deflt, 67 | size_t _size) 68 | : name(_name), type(_type), deflt(_deflt), size(_size) {} 69 | 70 | std::string sql_ddl(); 71 | 72 | std::string sql_type(); 73 | 74 | std::string sql_default(); 75 | 76 | // Field name 77 | std::string name; 78 | // Field type 79 | FieldType type; 80 | // Default value 81 | std::string deflt; 82 | // Field size (some type is valid) 83 | uint32_t size; 84 | }; 85 | 86 | using FieldDescriptorList = std::vector; 87 | 88 | class TableDescriptorBase { 89 | public: 90 | using Ptr = std::shared_ptr; 91 | 92 | std::string sql_create(); 93 | 94 | std::string sql_drop(); 95 | 96 | std::string sql_addfield(const std::string &field); 97 | 98 | std::string sql_fieldlist(); 99 | 100 | std::string sql_fieldlist2(); 101 | 102 | public: 103 | TableDescriptorBase &field(const std::string &name, 104 | FieldType type, 105 | const std::string &deflt = "", 106 | size_t size = 0); 107 | 108 | TableDescriptorBase &key(const std::string &name); 109 | 110 | TableDescriptorBase &keys(const std::initializer_list &names); 111 | 112 | TableDescriptorBase &index(const std::string &name); 113 | 114 | TableDescriptorBase &indexs(const std::initializer_list &names); 115 | 116 | FieldDescriptor::Ptr getFieldDescriptor(const std::string &name); 117 | 118 | const FieldDescriptorList &fields() { return fields_ordered_; } 119 | 120 | const FieldDescriptorList &keys() { return keys_; } 121 | 122 | public: 123 | TableDescriptorBase(const std::string name) 124 | : table(name) {} 125 | 126 | // Talbe name 127 | std::string table; 128 | // Primary keys 129 | FieldDescriptorList keys_; 130 | // Indexes 131 | FieldDescriptorList indexs_; 132 | // Field Descriptors 133 | FieldDescriptorList fields_ordered_; 134 | // Field Descriptors by name 135 | std::unordered_map fields_; 136 | }; 137 | 138 | 139 | template 140 | class TableDescriptor : public TableDescriptorBase { 141 | public: 142 | TableDescriptor(const std::string &name) 143 | : TableDescriptorBase(name), reflection(name) {} 144 | 145 | template class SerializerT = ProtoSerializer, typename PropType> 146 | TableDescriptor &field(PropType T::* prop, 147 | const std::string &name, 148 | FieldType type, 149 | const std::string &deflt = "", 150 | size_t size = 0) { 151 | reflection.template property(name, prop); 152 | TableDescriptorBase::field(name, type, deflt, size); 153 | return *this; 154 | } 155 | 156 | Struct reflection; 157 | }; 158 | 159 | class TableFactory { 160 | public: 161 | typedef std::unordered_map Tables; 162 | 163 | static TableFactory &instance() { 164 | static TableFactory factory_; 165 | return factory_; 166 | } 167 | 168 | template 169 | TableDescriptor &table(const std::string &name) { 170 | TableDescriptor *td = new TableDescriptor(name); 171 | TableDescriptorBase::Ptr ptr(td); 172 | tables_byname_[name] = ptr; 173 | tables_bytype_[typeid(T).name()] = ptr; 174 | return *td; 175 | } 176 | 177 | TableDescriptorBase::Ptr tableByName(const std::string &name) { 178 | auto it = tables_byname_.find(name); 179 | if (it != tables_byname_.end()) 180 | return it->second; 181 | return nullptr; 182 | } 183 | 184 | template 185 | TableDescriptor *tableByType() { 186 | auto it = tables_bytype_.find(typeid(T).name()); 187 | if (it != tables_bytype_.end()) 188 | return static_cast *>(it->second.get()); 189 | return nullptr; 190 | } 191 | 192 | Tables &tables() { return tables_byname_; } 193 | 194 | private: 195 | Tables tables_byname_; 196 | Tables tables_bytype_; 197 | }; 198 | 199 | 200 | // 201 | // Helper Class: Add datatabase operations to the object. 202 | // eg. 203 | // Object2DB_T object; 204 | // object.selectDB(); 205 | // object.updateDB(); 206 | // 207 | // ORM : 208 | // - TinyMySqlORM 209 | // - TinySociORM 210 | // 211 | template 212 | struct Object2DB_T : public T { 213 | public: 214 | using Records = std::vector>; 215 | using ORMPoolType = typename ORM::PoolType; 216 | using ORMConnectionType = typename ORM::ConnectionType; 217 | 218 | Object2DB_T() {} 219 | 220 | Object2DB_T(const T &object) : T(object) {} 221 | 222 | // 223 | // Create, Drop and Update Table's Structure 224 | // 225 | static bool createTable(ORMPoolType *pool = &ORMPoolType::instance()) { 226 | ORM orm(pool); 227 | return orm.template createTableByType(); 228 | } 229 | 230 | static bool createTable(ORMConnectionType *connect) { 231 | ORM orm(connect); 232 | return orm.template createTableByType(); 233 | } 234 | 235 | static bool dropTable(ORMPoolType *pool = &ORMPoolType::instance()) { 236 | ORM orm(pool); 237 | return orm.template dropTableByType(); 238 | } 239 | 240 | static bool dropTable(ORMConnectionType *connect) { 241 | ORM orm(connect); 242 | return orm.template dropTableByType(); 243 | } 244 | 245 | 246 | static bool updateTable(ORMPoolType *pool = &ORMPoolType::instance()) { 247 | ORM orm(pool); 248 | return orm.template updateTableByType(); 249 | } 250 | 251 | static bool updateTable(ORMConnectionType *connect) { 252 | ORM orm(connect); 253 | return orm.template updateTableByType(); 254 | } 255 | 256 | public: 257 | // 258 | // Database Operations 259 | // 260 | bool selectDB(ORMPoolType *pool = &ORMPoolType::instance()) { 261 | ORM orm(pool); 262 | return orm.template select(*this); 263 | } 264 | 265 | bool selectDB(ORMConnectionType *connect) { 266 | ORM orm(connect); 267 | return orm.template select(*this); 268 | } 269 | 270 | 271 | bool insertDB(ORMPoolType *pool = &ORMPoolType::instance()) { 272 | ORM orm(pool); 273 | return orm.template insert(*this); 274 | } 275 | 276 | bool insertDB(ORMConnectionType *connect) { 277 | ORM orm(connect); 278 | return orm.template insert(*this); 279 | } 280 | 281 | bool replaceDB(ORMPoolType *pool = &ORMPoolType::instance()) { 282 | ORM orm(pool); 283 | return orm.template replace(*this); 284 | } 285 | 286 | bool replaceDB(ORMConnectionType *connect) { 287 | ORM orm(connect); 288 | return orm.template replace(*this); 289 | } 290 | 291 | bool updateDB(ORMPoolType *pool = &ORMPoolType::instance()) { 292 | ORM orm(pool); 293 | return orm.template update(*this); 294 | } 295 | 296 | bool updateDB(ORMConnectionType *connect) { 297 | ORM orm(connect); 298 | return orm.template update(*this); 299 | } 300 | 301 | bool deleteDB(ORMPoolType *pool = &ORMPoolType::instance()) { 302 | ORM orm(pool); 303 | return orm.template del(*this); 304 | } 305 | 306 | bool deleteDB(ORMConnectionType *connect) { 307 | ORM orm(connect); 308 | return orm.template del(*this); 309 | } 310 | }; 311 | 312 | 313 | #endif //TINYWORLD_TINYORM_H 314 | -------------------------------------------------------------------------------- /include/tinyorm_mysql.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 david++ 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #ifndef TINYWORLD_TINYORM_MYSQL_H 22 | #define TINYWORLD_TINYORM_MYSQL_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "tinyorm.h" 29 | #include "tinymysql.h" 30 | #include "tinylogger.h" 31 | 32 | class TinyMySqlORM { 33 | public: 34 | typedef MySqlConnectionPool PoolType; 35 | typedef mysqlpp::Connection ConnectionType; 36 | 37 | // 38 | // 构造: 支持两种方式: 39 | // 1. 连接池 40 | // 2. 指定连接 41 | // 42 | TinyMySqlORM(MySqlConnectionPool *pool = &MySqlConnectionPool::instance()) { 43 | if (pool) { 44 | pool_ = pool; 45 | mysql_ = pool->grab(); 46 | } 47 | } 48 | 49 | TinyMySqlORM(mysqlpp::Connection *connection) { 50 | if (connection) { 51 | mysql_ = connection; 52 | pool_ = nullptr; 53 | } 54 | } 55 | 56 | // 57 | // 析构: 如果是用连接池初始化的则把连接放回 58 | // 59 | ~TinyMySqlORM() { 60 | if (pool_) 61 | pool_->putback(mysql_); 62 | } 63 | 64 | // 65 | // 更新所有表格的结构 66 | // 67 | bool showTables(std::unordered_set &tables); 68 | 69 | bool updateTables(); 70 | 71 | // 72 | // 创建、删除、自动更新表结构 73 | // 74 | template 75 | bool createTableByType(); 76 | 77 | bool createTableByName(const std::string &name); 78 | 79 | template 80 | bool dropTableByType(); 81 | 82 | bool dropTableByName(const std::string &name); 83 | 84 | template 85 | bool updateTableByType(); 86 | 87 | bool updateTableByName(const std::string &name); 88 | 89 | // 90 | // 针对某个对象的数据库操作 91 | // 92 | template 93 | bool select(T &obj); 94 | 95 | template 96 | bool insert(T &obj); 97 | 98 | template 99 | bool replace(T &obj); 100 | 101 | template 102 | bool update(T &obj); 103 | 104 | template 105 | bool del(T &obj); 106 | 107 | // 108 | // 数据库批量加载 109 | // 110 | template 111 | using Records = std::vector>; 112 | 113 | template 114 | bool loadFromDB(Records &records, const char *clause, ...); 115 | 116 | template 117 | bool loadFromDB(TSet &records, const char *clause, ...); 118 | 119 | template 120 | bool loadFromDB2MultiIndexSet(TMultiIndexSet &records, const char *clause, ...); 121 | 122 | template 123 | bool loadFromDB(const std::function)> &callback, const char *clause, ...); 124 | 125 | template 126 | bool vloadFromDB(const std::function)> &callback, const char *clause, va_list ap); 127 | 128 | // 129 | // 数据库批量删除 130 | // 131 | template 132 | bool deleteFromDB(const char *where, ...); 133 | 134 | public: 135 | // 136 | // Generate SQL 137 | // 138 | template 139 | bool makeSelectQuery(mysqlpp::Query &query, const T &obj, TableDescriptor *td = nullptr); 140 | 141 | template 142 | bool makeInsertQuery(mysqlpp::Query &query, const T &obj, TableDescriptor *td = nullptr); 143 | 144 | template 145 | bool makeReplaceQuery(mysqlpp::Query &query, const T &obj, TableDescriptor *td = nullptr); 146 | 147 | template 148 | bool makeUpdateQuery(mysqlpp::Query &query, const T &obj, TableDescriptor *td = nullptr); 149 | 150 | template 151 | bool makeDeleteQuery(mysqlpp::Query &query, const T &obj, TableDescriptor *td = nullptr); 152 | 153 | 154 | protected: 155 | bool updateExistTable(TableDescriptorBase* td); 156 | 157 | bool createTable(TableDescriptorBase* td); 158 | 159 | bool dropTable(TableDescriptorBase* td); 160 | 161 | bool updateTable(TableDescriptorBase* td); 162 | 163 | 164 | // 165 | // value1,value2,...,valueN 166 | // 167 | template 168 | void makeValueList(mysqlpp::Query &query, T &obj, TableDescriptor *td, const FieldDescriptorList &fdlist); 169 | 170 | // 171 | // key1=value1,key2=valule2,...,keyN=valueN 172 | // 173 | template 174 | void makeKeyValueList(mysqlpp::Query &query, T &obj, TableDescriptor *td, const FieldDescriptorList &fdlist, 175 | const std::string &seperator = ","); 176 | 177 | 178 | template 179 | bool fieldToQuery(mysqlpp::Query &query, T &obj, TableDescriptor *td, FieldDescriptor::Ptr fd); 180 | 181 | template 182 | bool recordToObject(mysqlpp::Row &record, T &obj, TableDescriptor *td); 183 | 184 | 185 | private: 186 | mysqlpp::Connection *mysql_ = nullptr; 187 | MySqlConnectionPool *pool_ = nullptr; 188 | }; 189 | 190 | #include "tinyorm_mysql.in.h" 191 | 192 | typedef TinyMySqlORM TinyORM; 193 | 194 | template 195 | using Object2DB = Object2DB_T; 196 | 197 | #endif //TINYWORLD_TINYORM_MYSQL_H 198 | -------------------------------------------------------------------------------- /include/tinyorm_soci.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 david++ 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #ifndef TINYWORLD_TINYORM_SOCI_H 22 | #define TINYWORLD_TINYORM_SOCI_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "tinyorm.h" 29 | #include "tinydb.h" 30 | 31 | class TinySociORM { 32 | public: 33 | typedef SOCIPool PoolType; 34 | typedef soci::session ConnectionType; 35 | 36 | // 37 | // 构造: 支持两种方式: 38 | // 1. 连接池 39 | // 2. 指定连接 40 | // 41 | TinySociORM(SOCIPool *pool = &SOCIPool::instance()) 42 | : pool_(pool) { 43 | if (pool_ && pool_->pool()) { 44 | session_ = new soci::session(*pool->pool()); 45 | } 46 | } 47 | 48 | TinySociORM(soci::session *session) 49 | : session_(session) { 50 | pool_ = nullptr; 51 | } 52 | 53 | // 54 | // 析构: 如果是用连接池初始化的则把连接放回 55 | // 56 | ~TinySociORM() { 57 | if (pool_ && session_) 58 | delete session_; 59 | } 60 | 61 | // 62 | // 更新所有表格的结构 63 | // 64 | bool showTables(std::unordered_set &tables); 65 | 66 | bool updateTables(); 67 | 68 | // 69 | // 创建、删除、自动更新表结构 70 | // 71 | template 72 | bool createTableByType(); 73 | 74 | bool createTableByName(const std::string &name); 75 | 76 | template 77 | bool dropTableByType(); 78 | 79 | bool dropTableByName(const std::string &name); 80 | 81 | template 82 | bool updateTableByType(); 83 | 84 | bool updateTableByName(const std::string &name); 85 | 86 | 87 | // 88 | // 针对某个对象的数据库操作 89 | // 90 | template 91 | bool select(T &obj); 92 | 93 | template 94 | bool insert(T &obj); 95 | 96 | template 97 | bool replace(T &obj); 98 | 99 | template 100 | bool update(T &obj); 101 | 102 | template 103 | bool del(T &obj); 104 | 105 | // 106 | // 数据库批量加载 107 | // 108 | template 109 | using Records = std::vector>; 110 | 111 | template 112 | bool loadFromDB(Records &records, const char *clause, ...); 113 | 114 | template 115 | bool loadFromDB(TSet &records, const char *clause, ...); 116 | 117 | template 118 | bool loadFromDB2MultiIndexSet(TMultiIndexSet &records, const char *clause, ...); 119 | 120 | template 121 | bool loadFromDB(const std::function)> &callback, const char *clause, ...); 122 | 123 | template 124 | bool vloadFromDB(const std::function)> &callback, const char *clause, va_list ap); 125 | 126 | // 127 | // 数据库批量删除 128 | // 129 | template 130 | bool deleteFromDB(const char *where, ...); 131 | 132 | protected: 133 | bool updateExistTable(TableDescriptorBase* td); 134 | 135 | bool createTable(TableDescriptorBase* td); 136 | 137 | bool dropTable(TableDescriptorBase* td); 138 | 139 | bool updateTable(TableDescriptorBase* td); 140 | 141 | struct UseResultBase {}; 142 | 143 | template 144 | struct UseResult : public UseResultBase { 145 | UseResult() {} 146 | UseResult(const UseT& v) : value(v) {} 147 | virtual ~UseResult() {} 148 | UseT value; 149 | }; 150 | 151 | template 152 | UseResultBase* fieldToStatement(soci::statement &st, T &obj, TableDescriptor *td, FieldDescriptor::Ptr fd); 153 | 154 | template 155 | bool recordToObject(soci::row &record, T &obj, TableDescriptor *td); 156 | 157 | private: 158 | soci::session &session() { return *session_; } 159 | 160 | SOCIPool *pool_ = nullptr; 161 | soci::session *session_ = nullptr; 162 | }; 163 | 164 | 165 | #include "tinyorm_soci.in.h" 166 | 167 | using TinyORM = TinySociORM; 168 | 169 | template 170 | using Object2DB = Object2DB_T; 171 | 172 | #endif //TINYWORLD_TINYORM_SOCI_H 173 | -------------------------------------------------------------------------------- /include/tinyreflection.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 david++ 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #ifndef TINYWORLD_TINYREFLECTION_H 22 | #define TINYWORLD_TINYREFLECTION_H 23 | 24 | #include "tinyworld.h" 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | TINY_NAMESPACE_BEGIN 36 | 37 | 38 | // 39 | // Dummy Serializer, Do nothing, satisfy concept : Serializer 40 | // 41 | template 42 | struct DummySerializer { 43 | std::string serialize(const T &object) const { return ""; } 44 | 45 | bool deserialize(T &object, const std::string &bin) const { return false; } 46 | }; 47 | 48 | // 49 | // Base Property Reflection Class 50 | // 51 | template 52 | class Property { 53 | public: 54 | typedef std::shared_ptr Ptr; 55 | 56 | Property(const std::string &name, uint16_t number) 57 | : name_(name), number_(number) {} 58 | 59 | const std::string &name() { return name_; } 60 | 61 | uint16_t number() { return number_; } 62 | 63 | public: 64 | // 65 | // Getter & Setter 66 | // 67 | virtual const std::type_info &type() = 0; 68 | 69 | virtual boost::any get(const T &) = 0; 70 | 71 | virtual void set(T &, boost::any &) = 0; 72 | 73 | // 74 | // Serialization 75 | // 76 | virtual std::string serialize(const T &) = 0; 77 | 78 | virtual bool deserialize(T &object, const std::string &bin) = 0; 79 | 80 | protected: 81 | std::string name_; 82 | uint16_t number_; 83 | }; 84 | 85 | 86 | // 87 | // Concrete Property Reflection 88 | // 89 | template 90 | class Property_T : public Property { 91 | public: 92 | Property_T(const std::string &name, uint16_t id, MemFn fn) 93 | : Property(name, id), fn_(fn) {} 94 | 95 | using PropRefType = typename std::result_of::type; 96 | using PropType = typename std::remove_reference::type; 97 | 98 | virtual const std::type_info &type() final { 99 | return typeid(PropType); 100 | }; 101 | 102 | boost::any get(const T &obj) final { 103 | return fn_(obj); 104 | } 105 | 106 | void set(T &obj, boost::any &v) final { 107 | fn_(obj) = boost::any_cast(v); 108 | } 109 | 110 | std::string serialize(const T &obj) final { 111 | SerializerT serializer; 112 | return serializer.serialize(fn_(obj)); 113 | } 114 | 115 | bool deserialize(T &obj, const std::string &data) final { 116 | // std::cout << __PRETTY_FUNCTION__ << std::endl; 117 | SerializerT serializer; 118 | return serializer.deserialize(fn_(obj), data); 119 | } 120 | 121 | protected: 122 | MemFn fn_; 123 | }; 124 | 125 | template 126 | Property_T *makePropery(const std::string &name, uint16_t id, MemFn fn) { 127 | return new Property_T(name, id, fn); 128 | } 129 | 130 | 131 | // 132 | // Structure Reflection 133 | // 134 | struct StructBase { 135 | }; 136 | 137 | template 138 | struct Struct : public StructBase { 139 | public: 140 | typedef typename Property::Ptr PropertyPtr; 141 | typedef std::vector PropertyContainer; 142 | typedef std::unordered_map PropertyMap; 143 | typedef std::unordered_map PropertyMapByID; 144 | 145 | Struct(const std::string &name, uint16_t version = 0) 146 | : name_(name), version_(version) {} 147 | 148 | virtual ~Struct() {} 149 | 150 | T *clone() { return new T; } 151 | 152 | template class SerializerT = DummySerializer, typename PropType> 153 | Struct &property(const std::string &name, PropType T::* prop, uint16_t id = 0) { 154 | if (!hasPropery(name)) { 155 | typename Property::Ptr ptr(makePropery>(name, id, std::mem_fn(prop))); 156 | properties_[name] = ptr; 157 | properties_ordered_.push_back(ptr); 158 | 159 | if (id) { 160 | properties_byid_[id] = ptr; 161 | } 162 | } 163 | 164 | return *this; 165 | } 166 | 167 | Struct &version(uint16_t ver) { 168 | version_ = ver; 169 | return *this; 170 | } 171 | 172 | bool hasPropery(const std::string &name) { 173 | return properties_.find(name) != properties_.end(); 174 | } 175 | 176 | size_t propertyCount() { return properties_.size(); } 177 | 178 | PropertyContainer propertyIterator() { return properties_ordered_; } 179 | 180 | typename Property::Ptr propertyByName(const std::string &name) { 181 | auto it = properties_.find(name); 182 | if (it != properties_.end()) 183 | return it->second; 184 | return typename Property::Ptr(); 185 | } 186 | 187 | typename Property::Ptr propertyByID(uint16_t id) { 188 | auto it = properties_byid_.find(id); 189 | if (it != properties_byid_.end()) 190 | return it->second; 191 | return typename Property::Ptr(); 192 | } 193 | 194 | template 195 | PropType get(const T &obj, const std::string &propname) { 196 | auto prop = propertyByName(propname); 197 | if (prop) 198 | return boost::any_cast(prop->get(obj)); 199 | return PropType(); 200 | } 201 | 202 | template 203 | void set(T &obj, const std::string &propname, const PropType &value) { 204 | auto prop = propertyByName(propname); 205 | if (prop) { 206 | boost::any v = value; 207 | prop->set(obj, v); 208 | } 209 | } 210 | 211 | const std::string &name() { return name_; } 212 | 213 | uint16_t version() { return version_; } 214 | 215 | protected: 216 | std::string name_; 217 | PropertyContainer properties_ordered_; 218 | PropertyMap properties_; 219 | PropertyMapByID properties_byid_; 220 | 221 | uint16_t version_ = 0; 222 | }; 223 | 224 | 225 | struct StructFactory { 226 | static StructFactory &instance() { 227 | static StructFactory instance_; 228 | return instance_; 229 | } 230 | 231 | template 232 | Struct &declare(const std::string name = "") { 233 | std::string type_name = typeid(T).name(); 234 | std::string struct_name = name; 235 | if (name.empty()) 236 | struct_name = type_name; 237 | 238 | auto desc = std::make_shared>(struct_name); 239 | structs_by_typeid_[type_name] = desc; 240 | structs_by_name_[struct_name] = desc; 241 | return *desc; 242 | } 243 | 244 | template 245 | Struct *structByType() { 246 | std::string type_name = typeid(T).name(); 247 | auto it = structs_by_typeid_.find(type_name); 248 | if (it != structs_by_typeid_.end()) 249 | return static_cast *>(it->second.get()); 250 | return NULL; 251 | } 252 | 253 | template 254 | Struct *structByName(const std::string &name) { 255 | auto it = structs_by_name_.find(name); 256 | if (it != structs_by_name_.end()) 257 | return static_cast *>(it->second.get()); 258 | return NULL; 259 | } 260 | 261 | protected: 262 | typedef std::unordered_map> Structs; 263 | 264 | Structs structs_by_typeid_; 265 | Structs structs_by_name_; 266 | }; 267 | 268 | TINY_NAMESPACE_END 269 | 270 | #endif //TINYWORLD_TINYREFLECTION_H 271 | -------------------------------------------------------------------------------- /include/tinyserializer.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 david++ 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | // Serializer and seriailze/deseriaize declaration 22 | 23 | #ifndef TINYWORLD_TINYSERIALIZER_H 24 | #define TINYWORLD_TINYSERIALIZER_H 25 | 26 | #include "tinyworld.h" 27 | 28 | TINY_NAMESPACE_BEGIN 29 | 30 | // 31 | // Concept : [Serializer] 32 | // 33 | // Constraint: 34 | // template 35 | // struct Serializer { 36 | // std::string serialize(const T &object) const; 37 | // bool deserialize(T &object, const std::string &bin) const; 38 | // }; 39 | // 40 | // Such as: ProtoSerialzer, ProtoDynSerializer 41 | // 42 | // Usage: 43 | // Serializer serializer; 44 | // Player p1; 45 | // std::string data = serializer.serialize(p); 46 | // 47 | // Player p2; 48 | // serializer.deserializer(p2, data); 49 | // 50 | 51 | template 52 | class ProtoSerializer; 53 | 54 | template 55 | class ProtoDynSerializer; 56 | 57 | // 58 | // serialize VS. deserialize functions 59 | // 60 | // eg. 61 | // 62 | // Player p; 63 | // // Serialize and deserialize by default serializer(ProtoSerializer) 64 | // void usage_1() { 65 | // std::string data = serialize(p); 66 | // deserialize(p, data); 67 | // } 68 | // 69 | // // Serialize and deserialize by ProtoSerializer serializer 70 | // void usage_2() { 71 | // std::string data = serialize(p); 72 | // deserialize(p, data); 73 | // } 74 | // 75 | // // Serializer has non-default constructor 76 | // void usage_3() { 77 | // DynProtoSerializer serializer(&GeneratedProtoMappingFactory::intance()); 78 | // std::string data = serialize(p, serializer); 79 | // deserialize(p, serializer); 80 | // } 81 | // 82 | // // Create a new Serializer 83 | // void usage_4() { 84 | // std::string data = serialize(p); 85 | // deserialize(p, data); 86 | // } 87 | // 88 | 89 | template class SerializerT = ProtoSerializer, typename T> 90 | inline std::string serialize(const T &object, const SerializerT &serializer = SerializerT()) { 91 | return serializer.serialize(object); 92 | }; 93 | 94 | template class SerializerT = ProtoSerializer, typename T> 95 | inline bool deserialize(T &object, const std::string &bin, const SerializerT &serializer = SerializerT()) { 96 | return serializer.deserialize(object, bin); 97 | } 98 | 99 | TINY_NAMESPACE_END 100 | 101 | 102 | #endif //TINYWORLD_TINYSERIALIZER_H 103 | -------------------------------------------------------------------------------- /include/tinyserializer_proto.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 david++ 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | // 22 | // Impliment the Serializer Concept by Protobuf 23 | // 24 | 25 | #ifndef TINYWORLD_TINYSERIALIZER_PROTO_H 26 | #define TINYWORLD_TINYSERIALIZER_PROTO_H 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "tinyworld.h" 38 | #include "archive.pb.h" 39 | 40 | // 41 | // T -> int 42 | // 43 | template 44 | struct ProtoCase; 45 | 46 | template 47 | struct ProtoSerializerImpl; 48 | 49 | // 50 | // Proto Serializer 51 | // 52 | template 53 | struct ProtoSerializer : public ProtoSerializerImpl::value> { 54 | }; 55 | 56 | // 57 | // Archiver : serialize and deserialize by the same order 58 | // 59 | template