├── .github └── workflows │ ├── cmake.yml │ └── stale-issues.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── CMakeLists.txt ├── LICENSE ├── README.md ├── include └── limonp │ ├── ArgvContext.hpp │ ├── Closure.hpp │ ├── Colors.hpp │ ├── Condition.hpp │ ├── Config.hpp │ ├── ForcePublic.hpp │ ├── LocalVector.hpp │ ├── Logging.hpp │ ├── NonCopyable.hpp │ ├── StdExtension.hpp │ └── StringUtil.hpp └── test ├── CMakeLists.txt ├── demo.cpp ├── testdata ├── 1.conf ├── StdExtension.data ├── dict.gbk ├── dict.utf8 ├── io_testfile ├── jieba.dict.0.1.utf8 ├── jieba.dict.0.utf8 ├── jieba.dict.1.utf8 └── jieba.dict.2.utf8 └── unittest ├── CMakeLists.txt ├── TArgvContext.cpp ├── TCastFloat.cpp ├── TClosure.cpp ├── TColorPrint.cpp ├── TConfig.cpp ├── TLocalVector.cpp ├── TLogging.cpp ├── TStdExtension.cpp ├── TStringUtil.cpp └── gtest_main.cpp /.github/workflows/cmake.yml: -------------------------------------------------------------------------------- 1 | name: CMake 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | #env: 8 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 9 | # BUILD_TYPE: Debug 10 | 11 | jobs: 12 | build: 13 | # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. 14 | # You can convert this to a matrix build if you need cross-platform coverage. 15 | # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 16 | runs-on: ${{ matrix.os }} 17 | strategy: 18 | matrix: 19 | os: [ 20 | ubuntu-20.04, 21 | ubuntu-22.04, 22 | macos-13, 23 | macos-14, 24 | macos-15, 25 | windows-2019, 26 | windows-2022, 27 | ] 28 | cpp_version: [11, 14, 17, 20] 29 | build_type: [Release, Debug] 30 | 31 | steps: 32 | - uses: actions/checkout@v4 33 | 34 | - name: Configure CMake 35 | run: cmake -B ${{github.workspace}}/build -DBUILD_TESTING=ON -DCMAKE_CXX_STANDARD=${{matrix.cpp_version}} -DCMAKE_BUILD_TYPE=${{matrix.build_type}} 36 | 37 | - name: Build 38 | run: cmake --build ${{github.workspace}}/build --config ${{matrix.build_type}} 39 | 40 | - name: Test 41 | working-directory: ${{github.workspace}}/build 42 | run: ctest -C ${{matrix.build_type}} --output-on-failure --verbose 43 | 44 | -------------------------------------------------------------------------------- /.github/workflows/stale-issues.yml: -------------------------------------------------------------------------------- 1 | name: Close Stale Issues 2 | 3 | on: 4 | schedule: 5 | - cron: '0 10 1 1 *' # Run yearly on January 1st at 10:00 UTC 6 | 7 | jobs: 8 | stale: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | issues: write 12 | pull-requests: write 13 | 14 | steps: 15 | - uses: actions/stale@v5 16 | with: 17 | repo-token: ${{ secrets.GITHUB_TOKEN }} 18 | stale-issue-message: 'This issue has not been updated for over a year and will be marked as stale. If the issue still exists, please comment or update the issue, otherwise it will be closed after 7 days.' 19 | close-issue-message: 'This issue has been automatically closed due to inactivity. If the issue still exists, please reopen it.' 20 | days-before-issue-stale: 365 21 | days-before-issue-close: 7 22 | stale-issue-label: 'Stale' 23 | exempt-issue-labels: 'pinned,security' 24 | operations-per-run: 100 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.ut 3 | libcm.a 4 | tags 5 | *.d 6 | build 7 | t.cpp 8 | a.out 9 | *.swp 10 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanyiwu/limonp/5c82a3f17e4e0adc6a5decfe245054b0ed533d1a/.gitmodules -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## v1.0.1 4 | 5 | + [CI] Update GitHub Actions configurations 6 | - Add stale issues workflow 7 | - Update checkout action from v2 to v4 8 | - Update macOS test environments (remove macOS-12, add macOS-15) 9 | + [dep] Update googletest to release-1.12.1 10 | + [doc] Add build instructions to README.md 11 | 12 | ## v1.0.0 13 | 14 | + rm thread pool demo 15 | + deleted: include/limonp/BlockingQueue.hpp 16 | + deleted: include/limonp/BoundedBlockingQueue.hpp 17 | + deleted: include/limonp/BoundedQueue.hpp 18 | + deleted: include/limonp/MutexLock.hpp 19 | + deleted: include/limonp/Thread.hpp 20 | + deleted: include/limonp/ThreadPool.hpp 21 | + deleted: test/unittest/TBlockingQueue.cpp 22 | + deleted: test/unittest/TBoundedQueue.cpp 23 | + deleted: test/unittest/TMutexLock.cpp 24 | + deleted: test/unittest/TThread.cpp 25 | + deleted: test/unittest/TThreadPool.cpp 26 | + rm FileLock 27 | + rm Md5.hpp 28 | 29 | ## v0.9.0 30 | 31 | + [c++20] compatibility 32 | + [c++17] compatibility 33 | 34 | ## v0.8.1 35 | 36 | + [CI] fix windows gtest thread link error 37 | + [submodule] rm test/googletest 38 | + [CMake] FetchContent googletest 39 | + [CMake] required 3.5 -> 3.14 40 | 41 | ## v0.8.0 42 | 43 | + [StringUtil] Fix windows assert typo 44 | + [CMake] find_package(Threads REQUIRED); target_link_libraries(... Threads::Threads) 45 | + [CMAKE][CI] windows: 2019,2022 46 | + [CMAKE][CI] matrix.build_type[Release, Debug] 47 | + [unittest] disable #TMd5.cpp 48 | + [unittest] disable #TFileLock.cpp 49 | + [unittest] disable #TBoundedQueue.cpp 50 | + [unittest] disable #TMutexLock.cpp 51 | + [unittest] disable #TBlockingQueue.cpp 52 | + [unittest] disable #TThread.cpp 53 | + [unittest] disable #TThreadPool.cpp 54 | 55 | ## v0.7.2 56 | 57 | + [CI] ubuntu version from 20 to 22, macos version from 12 to 14 58 | + [test/unittes] uint->size_t 59 | + [googletest] v1.6.0->v1.10.0 60 | + [CMake] version required 3.0 -> 3.5 61 | 62 | ## v0.7.1 63 | 64 | + [CMake] fix CMAKE_CXX_STANDARD passed from github/actions and [c++11, c++14] only 65 | 66 | ## v0.7.0 67 | 68 | + [CI] Added os.macos and cpp_version=[c++98, c++03, c++11, c++14, c++17, c++20] 69 | + [git submodule] Added googletest-release-v1.6.0 70 | 71 | ## v0.6.7 72 | 73 | + Merged [pr35](https://github.com/yanyiwu/limonp/pull/35) 74 | + Merged [pr33](https://github.com/yanyiwu/limonp/pull/33) 75 | + Merged [pr32](https://github.com/yanyiwu/limonp/pull/32) 76 | 77 | ## v0.6.6 78 | 79 | + Merged [pr-31 To be compatible with cpp17 and later, use lambda instead of std::not1 & std::bind2nd #31](https://github.com/yanyiwu/limonp/pull/31) 80 | 81 | ## v0.6.5 82 | 83 | + Merged [pr-25 Update cmake.yml](https://github.com/yanyiwu/limonp/pull/25) 84 | + Merged [pr-26 fix license for end of line sequence and remove useless signature](https://github.com/yanyiwu/limonp/pull/26) 85 | + Merged [pr-27 Update cmake.yml](https://github.com/yanyiwu/limonp/pull/27) 86 | + Merged [pr-28 add a target to be ready to support installation](https://github.com/yanyiwu/limonp/pull/28) 87 | + Merged [pr-29 Installable by cmake](https://github.com/yanyiwu/limonp/pull/29) 88 | + Merged [pr-30 Replace localtime with localtime_s on Windows and localtime_r on Linux](https://github.com/yanyiwu/limonp/pull/30) 89 | 90 | ## v0.6.4 91 | 92 | + merge [fixup gcc8 warnings](https://github.com/yanyiwu/gojieba/pull/70) 93 | 94 | ## v0.6.3 95 | 96 | + remove compiler conplained macro 97 | 98 | ## v0.6.2 99 | 100 | + merge [pr-18](https://github.com/yanyiwu/limonp/pull/18/files) 101 | 102 | ## v0.6.1 103 | 104 | add Specialized template for vector 105 | 106 | when it is `vector`, print like this: ["hello", "world"]; (special case) 107 | when it is `vector`, print like this: [1, 10, 1000]; (common cases) 108 | 109 | ## v0.6.0 110 | 111 | + remove Trim out of Split. 112 | 113 | ## v0.5.6 114 | 115 | + fix hidden trouble. 116 | 117 | ## v0.5.5 118 | 119 | + macro name LOG and CHECK in Logging.hpp is so easy to confict with other lib, so I have to rename them to XLOG and XCHECK for avoiding those macro name conflicts. 120 | 121 | ## v0.5.4 122 | 123 | + add ForcePublic.hpp 124 | + Add Utf8ToUnicode32 and Unicode32ToUtf8 in StringUtil.hpp 125 | 126 | ## v0.5.3 127 | 128 | + Fix incompatibility problem about 'time.h' in Windows. 129 | 130 | ## v0.5.2 131 | 132 | + Fix incompatibility problem about `enum {INFO ...}` name conflicts in Windows . 133 | + So from this version begin: the compile flags: `-DLOGGING_LEVEL=WARNING` must be changed to `-DLOGGING_LEVEL=LL_WARNING` 134 | 135 | ## v0.5.1 136 | 137 | + add `ThreadPool::Stop()` to wait util all the threads finished. 138 | If Stop() has not been called, it will be called when the ThreadPool destructing. 139 | 140 | ## v0.5.0 141 | 142 | + Reorganized directories: include/ -> include/limonp/ ... and so on. 143 | + Add `NewClosure` in Closure.hpp, 0~3 arguments have been supported. 144 | + Update ThreadPool, use `NewClosure` instead of `CreateTask` 145 | 146 | ## v0.4.1 147 | 148 | + `CHECK(exp) << "log message"` supported; 149 | 150 | ## v0.4.0 151 | 152 | + add test/demo.cc as example. 153 | + move `print` macro to StdExtension.hpp 154 | + BigChange: rewrite `log` module, use `LOG(INFO) << "xxx" ` instead `LogInfo` . 155 | + remove HandyMacro.hpp, add CHECK in Logging.hpp instead. 156 | 157 | ## v0.3.0 158 | 159 | + remove 'MysqlClient.hpp', 'InitOnOff.hpp', 'CastFloat.hpp' 160 | + add 'Closure.hpp' 161 | + uniform code style 162 | 163 | ## v0.2.0 164 | 165 | + `namespace limonp`, not `Limonp` . 166 | 167 | ## v0.1.0 168 | 169 | + Basic functions 170 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | 3 | PROJECT(limonp 4 | LANGUAGES CXX) 5 | 6 | ################ 7 | # cmake config # 8 | ################ 9 | 10 | if(NOT DEFINED CMAKE_CXX_STANDARD) 11 | set(CMAKE_CXX_STANDARD 11) 12 | endif() 13 | message(STATUS "CMAKE_CXX_STANDARD is ${CMAKE_CXX_STANDARD}") 14 | 15 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 16 | set(CMAKE_CXX_EXTENSIONS OFF) 17 | 18 | 19 | ############## 20 | # dependency # 21 | ############## 22 | include(GNUInstallDirs) 23 | 24 | ########## 25 | # target # 26 | ########## 27 | 28 | add_library(${PROJECT_NAME} INTERFACE) 29 | add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) 30 | 31 | target_include_directories(${PROJECT_NAME} 32 | INTERFACE 33 | $ 34 | $) 35 | 36 | ######## 37 | # test # 38 | ######## 39 | 40 | ENABLE_TESTING() 41 | 42 | ADD_SUBDIRECTORY(test) 43 | ADD_TEST(NAME ./test/demo COMMAND ./test/demo) 44 | ADD_TEST(NAME ./test/test.run COMMAND ./test/test.run) 45 | 46 | ########### 47 | # install # 48 | ########### 49 | 50 | include(GNUInstallDirs) 51 | 52 | install(TARGETS ${PROJECT_NAME} 53 | EXPORT ${PROJECT_NAME}) 54 | 55 | install(EXPORT ${PROJECT_NAME} 56 | DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/cmake/ 57 | NAMESPACE ${PROJECT_NAME}:: 58 | FILE ${PROJECT_NAME}-config.cmake) 59 | 60 | install(DIRECTORY include/ 61 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # limonp 2 | 3 | [![CMake](https://github.com/yanyiwu/limonp/actions/workflows/cmake.yml/badge.svg)](https://github.com/yanyiwu/limonp/actions/workflows/cmake.yml) 4 | [![Author](https://img.shields.io/badge/author-@yanyiwu-blue.svg?style=flat)](http://yanyiwu.com/) 5 | [![Platform](https://img.shields.io/badge/platform-Linux,macOS,Windows-green.svg?style=flat)](https://github.com/yanyiwu/limonp) 6 | [![Tag](https://img.shields.io/github/v/tag/yanyiwu/limonp.svg)](https://github.com/yanyiwu/limonp/releases) 7 | [![License](https://img.shields.io/badge/license-MIT-yellow.svg?style=flat)](http://yanyiwu.mit-license.org) 8 | 9 | ## Introduction 10 | 11 | `C++` headers(hpp) with Python style. 12 | 13 | ## Feature 14 | 15 | + linking is a annoying thing, so I write these source code in headers file(`*.hpp`), you can use them only with `#include "xx.hpp"`, without linking *.a or *.so . 16 | 17 | **`no linking , no hurts`** 18 | 19 | ## Build 20 | 21 | ``` 22 | mkdir build 23 | cmake .. 24 | make 25 | 26 | make test 27 | ``` 28 | 29 | ## Example 30 | 31 | See Details in `test/demo.cpp` 32 | 33 | ## Cases 34 | 35 | 1. [CppJieba] 36 | 37 | ## Contact 38 | 39 | + i@yanyiwu.com 40 | 41 | [CppJieba]:https://github.com/yanyiwu/cppjieba.git 42 | [muduo]:https://github.com/chenshuo/muduo.git 43 | 44 | -------------------------------------------------------------------------------- /include/limonp/ArgvContext.hpp: -------------------------------------------------------------------------------- 1 | /************************************ 2 | * file enc : ascii 3 | * author : wuyanyi09@gmail.com 4 | ************************************/ 5 | 6 | #ifndef LIMONP_ARGV_FUNCTS_H 7 | #define LIMONP_ARGV_FUNCTS_H 8 | 9 | #include 10 | #include 11 | #include "StringUtil.hpp" 12 | 13 | namespace limonp { 14 | 15 | using namespace std; 16 | 17 | class ArgvContext { 18 | public : 19 | ArgvContext(int argc, const char* const * argv) { 20 | for(int i = 0; i < argc; i++) { 21 | if(StartsWith(argv[i], "-")) { 22 | if(i + 1 < argc && !StartsWith(argv[i + 1], "-")) { 23 | mpss_[argv[i]] = argv[i+1]; 24 | i++; 25 | } else { 26 | sset_.insert(argv[i]); 27 | } 28 | } else { 29 | args_.push_back(argv[i]); 30 | } 31 | } 32 | } 33 | ~ArgvContext() { 34 | } 35 | 36 | friend ostream& operator << (ostream& os, const ArgvContext& args); 37 | string operator [](size_t i) const { 38 | if(i < args_.size()) { 39 | return args_[i]; 40 | } 41 | return ""; 42 | } 43 | string operator [](const string& key) const { 44 | map::const_iterator it = mpss_.find(key); 45 | if(it != mpss_.end()) { 46 | return it->second; 47 | } 48 | return ""; 49 | } 50 | 51 | bool HasKey(const string& key) const { 52 | if(mpss_.find(key) != mpss_.end() || sset_.find(key) != sset_.end()) { 53 | return true; 54 | } 55 | return false; 56 | } 57 | 58 | private: 59 | vector args_; 60 | map mpss_; 61 | set sset_; 62 | }; // class ArgvContext 63 | 64 | inline ostream& operator << (ostream& os, const ArgvContext& args) { 65 | return os< 14 | class Closure0: public ClosureInterface { 15 | public: 16 | Closure0(Funct fun) { 17 | fun_ = fun; 18 | } 19 | virtual ~Closure0() { 20 | } 21 | virtual void Run() { 22 | (*fun_)(); 23 | } 24 | private: 25 | Funct fun_; 26 | }; 27 | 28 | template 29 | class Closure1: public ClosureInterface { 30 | public: 31 | Closure1(Funct fun, Arg1 arg1) { 32 | fun_ = fun; 33 | arg1_ = arg1; 34 | } 35 | virtual ~Closure1() { 36 | } 37 | virtual void Run() { 38 | (*fun_)(arg1_); 39 | } 40 | private: 41 | Funct fun_; 42 | Arg1 arg1_; 43 | }; 44 | 45 | template 46 | class Closure2: public ClosureInterface { 47 | public: 48 | Closure2(Funct fun, Arg1 arg1, Arg2 arg2) { 49 | fun_ = fun; 50 | arg1_ = arg1; 51 | arg2_ = arg2; 52 | } 53 | virtual ~Closure2() { 54 | } 55 | virtual void Run() { 56 | (*fun_)(arg1_, arg2_); 57 | } 58 | private: 59 | Funct fun_; 60 | Arg1 arg1_; 61 | Arg2 arg2_; 62 | }; 63 | 64 | template 65 | class Closure3: public ClosureInterface { 66 | public: 67 | Closure3(Funct fun, Arg1 arg1, Arg2 arg2, Arg3 arg3) { 68 | fun_ = fun; 69 | arg1_ = arg1; 70 | arg2_ = arg2; 71 | arg3_ = arg3; 72 | } 73 | virtual ~Closure3() { 74 | } 75 | virtual void Run() { 76 | (*fun_)(arg1_, arg2_, arg3_); 77 | } 78 | private: 79 | Funct fun_; 80 | Arg1 arg1_; 81 | Arg2 arg2_; 82 | Arg3 arg3_; 83 | }; 84 | 85 | template 86 | class ObjClosure0: public ClosureInterface { 87 | public: 88 | ObjClosure0(Obj* p, Funct fun) { 89 | p_ = p; 90 | fun_ = fun; 91 | } 92 | virtual ~ObjClosure0() { 93 | } 94 | virtual void Run() { 95 | (p_->*fun_)(); 96 | } 97 | private: 98 | Obj* p_; 99 | Funct fun_; 100 | }; 101 | 102 | template 103 | class ObjClosure1: public ClosureInterface { 104 | public: 105 | ObjClosure1(Obj* p, Funct fun, Arg1 arg1) { 106 | p_ = p; 107 | fun_ = fun; 108 | arg1_ = arg1; 109 | } 110 | virtual ~ObjClosure1() { 111 | } 112 | virtual void Run() { 113 | (p_->*fun_)(arg1_); 114 | } 115 | private: 116 | Obj* p_; 117 | Funct fun_; 118 | Arg1 arg1_; 119 | }; 120 | 121 | template 122 | class ObjClosure2: public ClosureInterface { 123 | public: 124 | ObjClosure2(Obj* p, Funct fun, Arg1 arg1, Arg2 arg2) { 125 | p_ = p; 126 | fun_ = fun; 127 | arg1_ = arg1; 128 | arg2_ = arg2; 129 | } 130 | virtual ~ObjClosure2() { 131 | } 132 | virtual void Run() { 133 | (p_->*fun_)(arg1_, arg2_); 134 | } 135 | private: 136 | Obj* p_; 137 | Funct fun_; 138 | Arg1 arg1_; 139 | Arg2 arg2_; 140 | }; 141 | template 142 | class ObjClosure3: public ClosureInterface { 143 | public: 144 | ObjClosure3(Obj* p, Funct fun, Arg1 arg1, Arg2 arg2, Arg3 arg3) { 145 | p_ = p; 146 | fun_ = fun; 147 | arg1_ = arg1; 148 | arg2_ = arg2; 149 | arg3_ = arg3; 150 | } 151 | virtual ~ObjClosure3() { 152 | } 153 | virtual void Run() { 154 | (p_->*fun_)(arg1_, arg2_, arg3_); 155 | } 156 | private: 157 | Obj* p_; 158 | Funct fun_; 159 | Arg1 arg1_; 160 | Arg2 arg2_; 161 | Arg3 arg3_; 162 | }; 163 | 164 | template 165 | ClosureInterface* NewClosure(R (*fun)()) { 166 | return new Closure0(fun); 167 | } 168 | 169 | template 170 | ClosureInterface* NewClosure(R (*fun)(Arg1), Arg1 arg1) { 171 | return new Closure1(fun, arg1); 172 | } 173 | 174 | template 175 | ClosureInterface* NewClosure(R (*fun)(Arg1, Arg2), Arg1 arg1, Arg2 arg2) { 176 | return new Closure2(fun, arg1, arg2); 177 | } 178 | 179 | template 180 | ClosureInterface* NewClosure(R (*fun)(Arg1, Arg2, Arg3), Arg1 arg1, Arg2 arg2, Arg3 arg3) { 181 | return new Closure3(fun, arg1, arg2, arg3); 182 | } 183 | 184 | template 185 | ClosureInterface* NewClosure(Obj* obj, R (Obj::* fun)()) { 186 | return new ObjClosure0(obj, fun); 187 | } 188 | 189 | template 190 | ClosureInterface* NewClosure(Obj* obj, R (Obj::* fun)(Arg1), Arg1 arg1) { 191 | return new ObjClosure1(obj, fun, arg1); 192 | } 193 | 194 | template 195 | ClosureInterface* NewClosure(Obj* obj, R (Obj::* fun)(Arg1, Arg2), Arg1 arg1, Arg2 arg2) { 196 | return new ObjClosure2(obj, fun, arg1, arg2); 197 | } 198 | 199 | template 200 | ClosureInterface* NewClosure(Obj* obj, R (Obj::* fun)(Arg1, Arg2, Arg3), Arg1 arg1, Arg2 arg2, Arg3 arg3) { 201 | return new ObjClosure3(obj, fun, arg1, arg2, arg3); 202 | } 203 | 204 | } // namespace limonp 205 | 206 | #endif // LIMONP_CLOSURE_HPP 207 | -------------------------------------------------------------------------------- /include/limonp/Colors.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LIMONP_COLOR_PRINT_HPP 2 | #define LIMONP_COLOR_PRINT_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace limonp { 8 | 9 | using std::string; 10 | 11 | enum Color { 12 | BLACK = 30, 13 | RED, 14 | GREEN, 15 | YELLOW, 16 | BLUE, 17 | PURPLE 18 | }; // enum Color 19 | 20 | static void ColorPrintln(enum Color color, const char * fmt, ...) { 21 | va_list ap; 22 | printf("\033[0;%dm", color); 23 | va_start(ap, fmt); 24 | vprintf(fmt, ap); 25 | va_end(ap); 26 | printf("\033[0m\n"); // if not \n , in some situation , the next lines will be set the same color unexpectedly 27 | } 28 | 29 | } // namespace limonp 30 | 31 | #endif // LIMONP_COLOR_PRINT_HPP 32 | -------------------------------------------------------------------------------- /include/limonp/Condition.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LIMONP_CONDITION_HPP 2 | #define LIMONP_CONDITION_HPP 3 | 4 | #include "MutexLock.hpp" 5 | 6 | namespace limonp { 7 | 8 | class Condition : NonCopyable { 9 | public: 10 | explicit Condition(MutexLock& mutex) 11 | : mutex_(mutex) { 12 | XCHECK(!pthread_cond_init(&pcond_, NULL)); 13 | } 14 | 15 | ~Condition() { 16 | XCHECK(!pthread_cond_destroy(&pcond_)); 17 | } 18 | 19 | void Wait() { 20 | XCHECK(!pthread_cond_wait(&pcond_, mutex_.GetPthreadMutex())); 21 | } 22 | 23 | void Notify() { 24 | XCHECK(!pthread_cond_signal(&pcond_)); 25 | } 26 | 27 | void NotifyAll() { 28 | XCHECK(!pthread_cond_broadcast(&pcond_)); 29 | } 30 | 31 | private: 32 | MutexLock& mutex_; 33 | pthread_cond_t pcond_; 34 | }; // class Condition 35 | 36 | } // namespace limonp 37 | 38 | #endif // LIMONP_CONDITION_HPP 39 | -------------------------------------------------------------------------------- /include/limonp/Config.hpp: -------------------------------------------------------------------------------- 1 | /************************************ 2 | * file enc : utf8 3 | * author : wuyanyi09@gmail.com 4 | ************************************/ 5 | #ifndef LIMONP_CONFIG_H 6 | #define LIMONP_CONFIG_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "StringUtil.hpp" 13 | 14 | namespace limonp { 15 | 16 | using namespace std; 17 | 18 | class Config { 19 | public: 20 | explicit Config(const string& filePath) { 21 | LoadFile(filePath); 22 | } 23 | 24 | operator bool () { 25 | return !map_.empty(); 26 | } 27 | 28 | string Get(const string& key, const string& defaultvalue) const { 29 | map::const_iterator it = map_.find(key); 30 | if(map_.end() != it) { 31 | return it->second; 32 | } 33 | return defaultvalue; 34 | } 35 | int Get(const string& key, int defaultvalue) const { 36 | string str = Get(key, ""); 37 | if("" == str) { 38 | return defaultvalue; 39 | } 40 | return atoi(str.c_str()); 41 | } 42 | const char* operator [] (const char* key) const { 43 | if(NULL == key) { 44 | return NULL; 45 | } 46 | map::const_iterator it = map_.find(key); 47 | if(map_.end() != it) { 48 | return it->second.c_str(); 49 | } 50 | return NULL; 51 | } 52 | 53 | string GetConfigInfo() const { 54 | string res; 55 | res << *this; 56 | return res; 57 | } 58 | 59 | private: 60 | void LoadFile(const string& filePath) { 61 | ifstream ifs(filePath.c_str()); 62 | assert(ifs); 63 | string line; 64 | vector vecBuf; 65 | size_t lineno = 0; 66 | while(getline(ifs, line)) { 67 | lineno ++; 68 | Trim(line); 69 | if(line.empty() || StartsWith(line, "#")) { 70 | continue; 71 | } 72 | vecBuf.clear(); 73 | Split(line, vecBuf, "="); 74 | if(2 != vecBuf.size()) { 75 | fprintf(stderr, "line[%s] illegal.\n", line.c_str()); 76 | assert(false); 77 | continue; 78 | } 79 | string& key = vecBuf[0]; 80 | string& value = vecBuf[1]; 81 | Trim(key); 82 | Trim(value); 83 | if(!map_.insert(make_pair(key, value)).second) { 84 | fprintf(stderr, "key[%s] already exits.\n", key.c_str()); 85 | assert(false); 86 | continue; 87 | } 88 | } 89 | ifs.close(); 90 | } 91 | 92 | friend ostream& operator << (ostream& os, const Config& config); 93 | 94 | map map_; 95 | }; // class Config 96 | 97 | inline ostream& operator << (ostream& os, const Config& config) { 98 | return os << config.map_; 99 | } 100 | 101 | } // namespace limonp 102 | 103 | #endif // LIMONP_CONFIG_H 104 | -------------------------------------------------------------------------------- /include/limonp/ForcePublic.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LIMONP_FORCE_PUBLIC_H 2 | #define LIMONP_FORCE_PUBLIC_H 3 | 4 | #define private public 5 | #define protected public 6 | 7 | #endif // LIMONP_FORCE_PUBLIC_H 8 | -------------------------------------------------------------------------------- /include/limonp/LocalVector.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LIMONP_LOCAL_VECTOR_HPP 2 | #define LIMONP_LOCAL_VECTOR_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace limonp { 10 | using namespace std; 11 | /* 12 | * LocalVector : T must be primitive type (char , int, size_t), if T is struct or class, LocalVector may be dangerous.. 13 | * LocalVector is simple and not well-tested. 14 | */ 15 | const size_t LOCAL_VECTOR_BUFFER_SIZE = 16; 16 | template 17 | class LocalVector { 18 | public: 19 | typedef const T* const_iterator ; 20 | typedef T value_type; 21 | typedef size_t size_type; 22 | private: 23 | T buffer_[LOCAL_VECTOR_BUFFER_SIZE]; 24 | T * ptr_; 25 | size_t size_; 26 | size_t capacity_; 27 | public: 28 | LocalVector() { 29 | init_(); 30 | }; 31 | LocalVector(const LocalVector& vec) { 32 | init_(); 33 | *this = vec; 34 | } 35 | LocalVector(const_iterator begin, const_iterator end) { // TODO: make it faster 36 | init_(); 37 | while(begin != end) { 38 | push_back(*begin++); 39 | } 40 | } 41 | LocalVector(size_t size, const T& t) { // TODO: make it faster 42 | init_(); 43 | while(size--) { 44 | push_back(t); 45 | } 46 | } 47 | ~LocalVector() { 48 | if(ptr_ != buffer_) { 49 | free(ptr_); 50 | } 51 | }; 52 | public: 53 | LocalVector& operator = (const LocalVector& vec) { 54 | clear(); 55 | size_ = vec.size(); 56 | capacity_ = vec.capacity(); 57 | if(vec.buffer_ == vec.ptr_) { 58 | memcpy(static_cast(buffer_), vec.buffer_, sizeof(T) * size_); 59 | ptr_ = buffer_; 60 | } else { 61 | ptr_ = (T*) malloc(vec.capacity() * sizeof(T)); 62 | assert(ptr_); 63 | memcpy(static_cast(ptr_), vec.ptr_, vec.size() * sizeof(T)); 64 | } 65 | return *this; 66 | } 67 | private: 68 | void init_() { 69 | ptr_ = buffer_; 70 | size_ = 0; 71 | capacity_ = LOCAL_VECTOR_BUFFER_SIZE; 72 | } 73 | public: 74 | T& operator [] (size_t i) { 75 | return ptr_[i]; 76 | } 77 | const T& operator [] (size_t i) const { 78 | return ptr_[i]; 79 | } 80 | void push_back(const T& t) { 81 | if(size_ == capacity_) { 82 | assert(capacity_); 83 | reserve(capacity_ * 2); 84 | } 85 | ptr_[size_ ++ ] = t; 86 | } 87 | void reserve(size_t size) { 88 | if(size <= capacity_) { 89 | return; 90 | } 91 | T * next = (T*)malloc(sizeof(T) * size); 92 | assert(next); 93 | T * old = ptr_; 94 | ptr_ = next; 95 | memcpy(static_cast(ptr_), old, sizeof(T) * capacity_); 96 | capacity_ = size; 97 | if(old != buffer_) { 98 | free(old); 99 | } 100 | } 101 | bool empty() const { 102 | return 0 == size(); 103 | } 104 | size_t size() const { 105 | return size_; 106 | } 107 | size_t capacity() const { 108 | return capacity_; 109 | } 110 | const_iterator begin() const { 111 | return ptr_; 112 | } 113 | const_iterator end() const { 114 | return ptr_ + size_; 115 | } 116 | void clear() { 117 | if(ptr_ != buffer_) { 118 | free(ptr_); 119 | } 120 | init_(); 121 | } 122 | }; 123 | 124 | template 125 | ostream & operator << (ostream& os, const LocalVector& vec) { 126 | if(vec.empty()) { 127 | return os << "[]"; 128 | } 129 | os<<"[\""< 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #ifdef XLOG 11 | #error "XLOG has been defined already" 12 | #endif // XLOG 13 | #ifdef XCHECK 14 | #error "XCHECK has been defined already" 15 | #endif // XCHECK 16 | 17 | #define XLOG(level) limonp::Logger(limonp::LL_##level, __FILE__, __LINE__).Stream() 18 | #define XCHECK(exp) if(!(exp)) XLOG(FATAL) << "exp: ["#exp << "] false. " 19 | 20 | namespace limonp { 21 | 22 | enum { 23 | LL_DEBUG = 0, 24 | LL_INFO = 1, 25 | LL_WARNING = 2, 26 | LL_ERROR = 3, 27 | LL_FATAL = 4, 28 | }; // enum 29 | 30 | static const char * LOG_LEVEL_ARRAY[] = {"DEBUG","INFO","WARN","ERROR","FATAL"}; 31 | static const char * LOG_TIME_FORMAT = "%Y-%m-%d %H:%M:%S"; 32 | 33 | class Logger { 34 | public: 35 | Logger(size_t level, const char* filename, int lineno) 36 | : level_(level) { 37 | #ifdef LOGGING_LEVEL 38 | if (level_ < LOGGING_LEVEL) { 39 | return; 40 | } 41 | #endif 42 | assert(level_ <= sizeof(LOG_LEVEL_ARRAY)/sizeof(*LOG_LEVEL_ARRAY)); 43 | 44 | char buf[32]; 45 | 46 | time_t timeNow; 47 | time(&timeNow); 48 | 49 | struct tm tmNow; 50 | 51 | #if defined(_WIN32) || defined(_WIN64) 52 | errno_t e = localtime_s(&tmNow, &timeNow); 53 | assert(e == 0); 54 | #else 55 | struct tm * tm_tmp = localtime_r(&timeNow, &tmNow); 56 | assert(tm_tmp != nullptr); 57 | #endif 58 | 59 | strftime(buf, sizeof(buf), LOG_TIME_FORMAT, &tmNow); 60 | 61 | stream_ << buf 62 | << " " << filename 63 | << ":" << lineno 64 | << " " << LOG_LEVEL_ARRAY[level_] 65 | << " "; 66 | } 67 | ~Logger() { 68 | #ifdef LOGGING_LEVEL 69 | if (level_ < LOGGING_LEVEL) { 70 | return; 71 | } 72 | #endif 73 | std::cerr << stream_.str() << std::endl; 74 | if (level_ == LL_FATAL) { 75 | abort(); 76 | } 77 | } 78 | 79 | std::ostream& Stream() { 80 | return stream_; 81 | } 82 | 83 | private: 84 | std::ostringstream stream_; 85 | size_t level_; 86 | }; // class Logger 87 | 88 | } // namespace limonp 89 | 90 | #endif // LIMONP_LOGGING_HPP 91 | -------------------------------------------------------------------------------- /include/limonp/NonCopyable.hpp: -------------------------------------------------------------------------------- 1 | /************************************ 2 | ************************************/ 3 | #ifndef LIMONP_NONCOPYABLE_H 4 | #define LIMONP_NONCOPYABLE_H 5 | 6 | namespace limonp { 7 | 8 | class NonCopyable { 9 | protected: 10 | NonCopyable() { 11 | } 12 | ~NonCopyable() { 13 | } 14 | private: 15 | NonCopyable(const NonCopyable& ); 16 | const NonCopyable& operator=(const NonCopyable& ); 17 | }; // class NonCopyable 18 | 19 | } // namespace limonp 20 | 21 | #endif // LIMONP_NONCOPYABLE_H 22 | -------------------------------------------------------------------------------- /include/limonp/StdExtension.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LIMONP_STD_EXTEMSION_HPP 2 | #define LIMONP_STD_EXTEMSION_HPP 3 | 4 | #include 5 | 6 | #ifdef __APPLE__ 7 | #include 8 | #include 9 | #elif(__cplusplus >= 201103L) 10 | #include 11 | #include 12 | #elif defined _MSC_VER 13 | #include 14 | #include 15 | #else 16 | #include 17 | #include 18 | namespace std { 19 | using std::tr1::unordered_map; 20 | using std::tr1::unordered_set; 21 | } 22 | 23 | #endif 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | namespace std { 33 | 34 | template 35 | ostream& operator << (ostream& os, const vector& v) { 36 | if(v.empty()) { 37 | return os << "[]"; 38 | } 39 | os<<"["< 48 | inline ostream& operator << (ostream& os, const vector& v) { 49 | if(v.empty()) { 50 | return os << "[]"; 51 | } 52 | os<<"[\""< 61 | ostream& operator << (ostream& os, const deque& dq) { 62 | if(dq.empty()) { 63 | return os << "[]"; 64 | } 65 | os<<"[\""< 75 | ostream& operator << (ostream& os, const pair& pr) { 76 | os << pr.first << ":" << pr.second ; 77 | return os; 78 | } 79 | 80 | 81 | template 82 | string& operator << (string& str, const T& obj) { 83 | stringstream ss; 84 | ss << obj; // call ostream& operator << (ostream& os, 85 | return str = ss.str(); 86 | } 87 | 88 | template 89 | ostream& operator << (ostream& os, const map& mp) { 90 | if(mp.empty()) { 91 | os<<"{}"; 92 | return os; 93 | } 94 | os<<'{'; 95 | typename map::const_iterator it = mp.begin(); 96 | os<<*it; 97 | it++; 98 | while(it != mp.end()) { 99 | os<<", "<<*it; 100 | it++; 101 | } 102 | os<<'}'; 103 | return os; 104 | } 105 | template 106 | ostream& operator << (ostream& os, const std::unordered_map& mp) { 107 | if(mp.empty()) { 108 | return os << "{}"; 109 | } 110 | os<<'{'; 111 | typename std::unordered_map::const_iterator it = mp.begin(); 112 | os<<*it; 113 | it++; 114 | while(it != mp.end()) { 115 | os<<", "<<*it++; 116 | } 117 | return os<<'}'; 118 | } 119 | 120 | template 121 | ostream& operator << (ostream& os, const set& st) { 122 | if(st.empty()) { 123 | os << "{}"; 124 | return os; 125 | } 126 | os<<'{'; 127 | typename set::const_iterator it = st.begin(); 128 | os<<*it; 129 | it++; 130 | while(it != st.end()) { 131 | os<<", "<<*it; 132 | it++; 133 | } 134 | os<<'}'; 135 | return os; 136 | } 137 | 138 | template 139 | bool IsIn(const ContainType& contain, const KeyType& key) { 140 | return contain.end() != contain.find(key); 141 | } 142 | 143 | template 144 | basic_string & operator << (basic_string & s, ifstream & ifs) { 145 | return s.assign((istreambuf_iterator(ifs)), istreambuf_iterator()); 146 | } 147 | 148 | template 149 | ofstream & operator << (ofstream & ofs, const basic_string& s) { 150 | ostreambuf_iterator itr (ofs); 151 | copy(s.begin(), s.end(), itr); 152 | return ofs; 153 | } 154 | 155 | } // namespace std 156 | 157 | #endif 158 | -------------------------------------------------------------------------------- /include/limonp/StringUtil.hpp: -------------------------------------------------------------------------------- 1 | /************************************ 2 | * file enc : ascii 3 | * author : wuyanyi09@gmail.com 4 | ************************************/ 5 | #ifndef LIMONP_STR_FUNCTS_H 6 | #define LIMONP_STR_FUNCTS_H 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "StdExtension.hpp" 27 | 28 | namespace limonp { 29 | using namespace std; 30 | inline string StringFormat(const char* fmt, ...) { 31 | int size = 256; 32 | std::string str; 33 | va_list ap; 34 | while (1) { 35 | str.resize(size); 36 | va_start(ap, fmt); 37 | int n = vsnprintf((char *)str.c_str(), size, fmt, ap); 38 | va_end(ap); 39 | if (n > -1 && n < size) { 40 | str.resize(n); 41 | return str; 42 | } 43 | if (n > -1) 44 | size = n + 1; 45 | else 46 | size *= 2; 47 | } 48 | return str; 49 | } 50 | 51 | template 52 | void Join(T begin, T end, string& res, const string& connector) { 53 | if(begin == end) { 54 | return; 55 | } 56 | stringstream ss; 57 | ss<<*begin; 58 | begin++; 59 | while(begin != end) { 60 | ss << connector << *begin; 61 | begin ++; 62 | } 63 | res = ss.str(); 64 | } 65 | 66 | template 67 | string Join(T begin, T end, const string& connector) { 68 | string res; 69 | Join(begin ,end, res, connector); 70 | return res; 71 | } 72 | 73 | inline string& Upper(string& str) { 74 | transform(str.begin(), str.end(), str.begin(), (int (*)(int))toupper); 75 | return str; 76 | } 77 | 78 | inline string& Lower(string& str) { 79 | transform(str.begin(), str.end(), str.begin(), (int (*)(int))tolower); 80 | return str; 81 | } 82 | 83 | inline bool IsSpace(unsigned c) { 84 | // when passing large int as the argument of isspace, it core dump, so here need a type cast. 85 | return c > 0xff ? false : std::isspace(c & 0xff) != 0; 86 | } 87 | 88 | inline std::string& LTrim(std::string &s) { 89 | s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { 90 | return !std::isspace(ch); 91 | })); 92 | return s; 93 | } 94 | 95 | inline std::string& RTrim(std::string &s) { 96 | s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { 97 | return !std::isspace(ch); 98 | }).base(), s.end()); 99 | return s; 100 | } 101 | 102 | inline std::string& Trim(std::string &s) { 103 | return LTrim(RTrim(s)); 104 | } 105 | 106 | inline std::string& LTrim(std::string& s, char x) { 107 | s.erase(s.begin(), std::find_if(s.begin(), s.end(), 108 | [x](unsigned char c) { return !std::isspace(c) && c != x; })); 109 | return s; 110 | } 111 | 112 | inline std::string& RTrim(std::string& s, char x) { 113 | s.erase(std::find_if(s.rbegin(), s.rend(), 114 | [x](unsigned char c) { return !std::isspace(c) && c != x; }).base(), s.end()); 115 | return s; 116 | } 117 | 118 | inline std::string& Trim(std::string &s, char x) { 119 | return LTrim(RTrim(s, x), x); 120 | } 121 | 122 | inline void Split(const string& src, vector& res, const string& pattern, size_t maxsplit = string::npos) { 123 | res.clear(); 124 | size_t Start = 0; 125 | size_t end = 0; 126 | string sub; 127 | while(Start < src.size()) { 128 | end = src.find_first_of(pattern, Start); 129 | if(string::npos == end || res.size() >= maxsplit) { 130 | sub = src.substr(Start); 131 | res.push_back(sub); 132 | return; 133 | } 134 | sub = src.substr(Start, end - Start); 135 | res.push_back(sub); 136 | Start = end + 1; 137 | } 138 | return; 139 | } 140 | 141 | inline vector Split(const string& src, const string& pattern, size_t maxsplit = string::npos) { 142 | vector res; 143 | Split(src, res, pattern, maxsplit); 144 | return res; 145 | } 146 | 147 | inline bool StartsWith(const string& str, const string& prefix) { 148 | if(prefix.length() > str.length()) { 149 | return false; 150 | } 151 | return 0 == str.compare(0, prefix.length(), prefix); 152 | } 153 | 154 | inline bool EndsWith(const string& str, const string& suffix) { 155 | if(suffix.length() > str.length()) { 156 | return false; 157 | } 158 | return 0 == str.compare(str.length() - suffix.length(), suffix.length(), suffix); 159 | } 160 | 161 | inline bool IsInStr(const string& str, char ch) { 162 | return str.find(ch) != string::npos; 163 | } 164 | 165 | inline uint16_t TwocharToUint16(char high, char low) { 166 | return (((uint16_t(high) & 0x00ff ) << 8) | (uint16_t(low) & 0x00ff)); 167 | } 168 | 169 | template 170 | bool Utf8ToUnicode(const char * const str, size_t len, Uint16Container& vec) { 171 | if(!str) { 172 | return false; 173 | } 174 | char ch1, ch2; 175 | uint16_t tmp; 176 | vec.clear(); 177 | for(size_t i = 0; i < len;) { 178 | if(!(str[i] & 0x80)) { // 0xxxxxxx 179 | vec.push_back(str[i]); 180 | i++; 181 | } else if ((uint8_t)str[i] <= 0xdf && i + 1 < len) { // 110xxxxxx 182 | ch1 = (str[i] >> 2) & 0x07; 183 | ch2 = (str[i+1] & 0x3f) | ((str[i] & 0x03) << 6 ); 184 | tmp = (((uint16_t(ch1) & 0x00ff ) << 8) | (uint16_t(ch2) & 0x00ff)); 185 | vec.push_back(tmp); 186 | i += 2; 187 | } else if((uint8_t)str[i] <= 0xef && i + 2 < len) { 188 | ch1 = ((uint8_t)str[i] << 4) | ((str[i+1] >> 2) & 0x0f ); 189 | ch2 = (((uint8_t)str[i+1]<<6) & 0xc0) | (str[i+2] & 0x3f); 190 | tmp = (((uint16_t(ch1) & 0x00ff ) << 8) | (uint16_t(ch2) & 0x00ff)); 191 | vec.push_back(tmp); 192 | i += 3; 193 | } else { 194 | return false; 195 | } 196 | } 197 | return true; 198 | } 199 | 200 | template 201 | bool Utf8ToUnicode(const string& str, Uint16Container& vec) { 202 | return Utf8ToUnicode(str.c_str(), str.size(), vec); 203 | } 204 | 205 | template 206 | bool Utf8ToUnicode32(const string& str, Uint32Container& vec) { 207 | uint32_t tmp; 208 | vec.clear(); 209 | for(size_t i = 0; i < str.size();) { 210 | if(!(str[i] & 0x80)) { // 0xxxxxxx 211 | // 7bit, total 7bit 212 | tmp = (uint8_t)(str[i]) & 0x7f; 213 | i++; 214 | } else if ((uint8_t)str[i] <= 0xdf && i + 1 < str.size()) { // 110xxxxxx 215 | // 5bit, total 5bit 216 | tmp = (uint8_t)(str[i]) & 0x1f; 217 | 218 | // 6bit, total 11bit 219 | tmp <<= 6; 220 | tmp |= (uint8_t)(str[i+1]) & 0x3f; 221 | i += 2; 222 | } else if((uint8_t)str[i] <= 0xef && i + 2 < str.size()) { // 1110xxxxxx 223 | // 4bit, total 4bit 224 | tmp = (uint8_t)(str[i]) & 0x0f; 225 | 226 | // 6bit, total 10bit 227 | tmp <<= 6; 228 | tmp |= (uint8_t)(str[i+1]) & 0x3f; 229 | 230 | // 6bit, total 16bit 231 | tmp <<= 6; 232 | tmp |= (uint8_t)(str[i+2]) & 0x3f; 233 | 234 | i += 3; 235 | } else if((uint8_t)str[i] <= 0xf7 && i + 3 < str.size()) { // 11110xxxx 236 | // 3bit, total 3bit 237 | tmp = (uint8_t)(str[i]) & 0x07; 238 | 239 | // 6bit, total 9bit 240 | tmp <<= 6; 241 | tmp |= (uint8_t)(str[i+1]) & 0x3f; 242 | 243 | // 6bit, total 15bit 244 | tmp <<= 6; 245 | tmp |= (uint8_t)(str[i+2]) & 0x3f; 246 | 247 | // 6bit, total 21bit 248 | tmp <<= 6; 249 | tmp |= (uint8_t)(str[i+3]) & 0x3f; 250 | 251 | i += 4; 252 | } else { 253 | return false; 254 | } 255 | vec.push_back(tmp); 256 | } 257 | return true; 258 | } 259 | 260 | template 261 | void Unicode32ToUtf8(Uint32ContainerConIter begin, Uint32ContainerConIter end, string& res) { 262 | res.clear(); 263 | uint32_t ui; 264 | while(begin != end) { 265 | ui = *begin; 266 | if(ui <= 0x7f) { 267 | res += char(ui); 268 | } else if(ui <= 0x7ff) { 269 | res += char(((ui >> 6) & 0x1f) | 0xc0); 270 | res += char((ui & 0x3f) | 0x80); 271 | } else if(ui <= 0xffff) { 272 | res += char(((ui >> 12) & 0x0f) | 0xe0); 273 | res += char(((ui >> 6) & 0x3f) | 0x80); 274 | res += char((ui & 0x3f) | 0x80); 275 | } else { 276 | res += char(((ui >> 18) & 0x03) | 0xf0); 277 | res += char(((ui >> 12) & 0x3f) | 0x80); 278 | res += char(((ui >> 6) & 0x3f) | 0x80); 279 | res += char((ui & 0x3f) | 0x80); 280 | } 281 | begin ++; 282 | } 283 | } 284 | 285 | template 286 | void UnicodeToUtf8(Uint16ContainerConIter begin, Uint16ContainerConIter end, string& res) { 287 | res.clear(); 288 | uint16_t ui; 289 | while(begin != end) { 290 | ui = *begin; 291 | if(ui <= 0x7f) { 292 | res += char(ui); 293 | } else if(ui <= 0x7ff) { 294 | res += char(((ui>>6) & 0x1f) | 0xc0); 295 | res += char((ui & 0x3f) | 0x80); 296 | } else { 297 | res += char(((ui >> 12) & 0x0f )| 0xe0); 298 | res += char(((ui>>6) & 0x3f )| 0x80 ); 299 | res += char((ui & 0x3f) | 0x80); 300 | } 301 | begin ++; 302 | } 303 | } 304 | 305 | 306 | template 307 | bool GBKTrans(const char* const str, size_t len, Uint16Container& vec) { 308 | vec.clear(); 309 | if(!str) { 310 | return true; 311 | } 312 | size_t i = 0; 313 | while(i < len) { 314 | if(0 == (str[i] & 0x80)) { 315 | vec.push_back(uint16_t(str[i])); 316 | i++; 317 | } else { 318 | if(i + 1 < len) { //&& (str[i+1] & 0x80)) 319 | uint16_t tmp = (((uint16_t(str[i]) & 0x00ff ) << 8) | (uint16_t(str[i+1]) & 0x00ff)); 320 | vec.push_back(tmp); 321 | i += 2; 322 | } else { 323 | return false; 324 | } 325 | } 326 | } 327 | return true; 328 | } 329 | 330 | template 331 | bool GBKTrans(const string& str, Uint16Container& vec) { 332 | return GBKTrans(str.c_str(), str.size(), vec); 333 | } 334 | 335 | template 336 | void GBKTrans(Uint16ContainerConIter begin, Uint16ContainerConIter end, string& res) { 337 | res.clear(); 338 | //pair pa; 339 | char first, second; 340 | while(begin != end) { 341 | //pa = uint16ToChar2(*begin); 342 | first = ((*begin)>>8) & 0x00ff; 343 | second = (*begin) & 0x00ff; 344 | if(first & 0x80) { 345 | res += first; 346 | res += second; 347 | } else { 348 | res += second; 349 | } 350 | begin++; 351 | } 352 | } 353 | 354 | /* 355 | * format example: "%Y-%m-%d %H:%M:%S" 356 | */ 357 | inline void GetTime(const string& format, string& timeStr) { 358 | time_t timeNow; 359 | time(&timeNow); 360 | 361 | struct tm tmNow; 362 | 363 | #if defined(_WIN32) || defined(_WIN64) 364 | errno_t e = localtime_s(&tmNow, &timeNow); 365 | assert(e == 0); 366 | #else 367 | struct tm * tm_tmp = localtime_r(&timeNow, &tmNow); 368 | assert(tm_tmp != nullptr); 369 | #endif 370 | 371 | timeStr.resize(64); 372 | 373 | size_t len = strftime((char*)timeStr.c_str(), timeStr.size(), format.c_str(), &tmNow); 374 | 375 | timeStr.resize(len); 376 | } 377 | 378 | inline string PathJoin(const string& path1, const string& path2) { 379 | if(EndsWith(path1, "/")) { 380 | return path1 + path2; 381 | } 382 | return path1 + "/" + path2; 383 | } 384 | 385 | } 386 | #endif 387 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/test) 2 | SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/test/lib) 3 | 4 | INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include) 5 | 6 | ADD_EXECUTABLE(demo demo.cpp) 7 | 8 | ADD_SUBDIRECTORY(unittest) 9 | -------------------------------------------------------------------------------- /test/demo.cpp: -------------------------------------------------------------------------------- 1 | #include "limonp/StringUtil.hpp" 2 | #include "limonp/Logging.hpp" 3 | 4 | using namespace std; 5 | 6 | #define print(x) std::cout << x << std::endl 7 | 8 | int main(int argc, char** argv) { 9 | string strname = "hello, world"; 10 | print(strname); //hello, world 11 | map mp; 12 | mp["hello"] = 1; 13 | mp["world"] = 2; 14 | print(mp); // {"hello":1, "world":2} 15 | 16 | string res; 17 | res << mp; 18 | print(res); // {"hello":1, "world":2} 19 | 20 | string str; 21 | str = limonp::StringFormat("%s, %s", "hello", "world"); 22 | print(str); //hello, world 23 | 24 | const char * a[] = {"hello", "world"}; 25 | str = limonp::Join(a, a + sizeof(a)/sizeof(*a), ","); 26 | print(str); //hello,world 27 | 28 | str = "hello, world"; 29 | vector buf; 30 | limonp::Split(str, buf, ","); 31 | print(buf); //["hello", " world"] 32 | 33 | int arr[] = {1,10,100,1000}; 34 | vector vec_i(arr, arr + sizeof(arr)/sizeof(arr[0])); 35 | print(vec_i); //[1, 10, 100, 1000] 36 | 37 | XLOG(INFO) << "hello, world"; //2014-04-05 20:52:37 demo.cpp:35 INFO hello, world 38 | //In the same way, `LOG(DEBUG),LOG(WARNING),LOG(ERROR),LOG(FATAL)`. 39 | return EXIT_SUCCESS; 40 | } 41 | -------------------------------------------------------------------------------- /test/testdata/1.conf: -------------------------------------------------------------------------------- 1 | 2 | key1 = val1 3 | ##this is comment 4 | 5 | key2=val2 6 | -------------------------------------------------------------------------------- /test/testdata/StdExtension.data: -------------------------------------------------------------------------------- 1 | key1 = val1 2 | ##this is comment 3 | key2=val2 4 | -------------------------------------------------------------------------------- /test/testdata/dict.gbk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanyiwu/limonp/5c82a3f17e4e0adc6a5decfe245054b0ed533d1a/test/testdata/dict.gbk -------------------------------------------------------------------------------- /test/testdata/dict.utf8: -------------------------------------------------------------------------------- 1 | AT&T 3 nz 2 | B超 3 n 3 | c# 3 nz 4 | C# 3 nz 5 | c++ 3 nz 6 | C++ 3 nz 7 | T恤 4 n 8 | 一 217830 m 9 | 一一 1670 m 10 | 一一二 11 m 11 | 一一例 3 m 12 | 一一分 8 m 13 | 一一列举 34 i 14 | 一一对 9 m 15 | 一一对应 43 l 16 | 一一记 2 m 17 | 一一道来 4 l 18 | 一丁 18 d 19 | 一丁不识 3 i 20 | 一丁点 3 m 21 | 一丁点儿 24 m 22 | 一七 22 m 23 | 一七八不 3 l 24 | 一万 442 m 25 | 一万一千 4 m 26 | 一万一千五百二十颗 2 m 27 | 一万一千八百八十斤 2 m 28 | 一万一千多间 2 m 29 | 一万一千零九十五册 4 m 30 | 一万七千 5 m 31 | 一万七千余 2 m 32 | 一万七千多 2 m 33 | 一万七千多户 2 m 34 | 一万万 4 m 35 | 一万万两 4 m 36 | 一万三千 8 m 37 | 一万三千五百一十七 2 m 38 | 一万三千五百斤 4 m 39 | 一万三千余种 2 m 40 | 一万三千块 2 m 41 | 一万两 124 m 42 | 一万两万 4 m 43 | 一万两千 3 m 44 | 一万个 62 m 45 | 一万九千 2 m 46 | 一万九千余 2 m 47 | 一万二 10 m 48 | 一万二千 7 m 49 | 一万二千两 2 m 50 | 一万二千五百 4 m 51 | -------------------------------------------------------------------------------- /test/testdata/io_testfile: -------------------------------------------------------------------------------- 1 | line1 2 | line2 3 | -------------------------------------------------------------------------------- /test/testdata/jieba.dict.0.1.utf8: -------------------------------------------------------------------------------- 1 | 龙鸣狮吼 3 nr 2 | 龙齐诺 2 nr 3 | 龙齿 3 n 4 | 龚 176 nr 5 | 龚世萍 2 nr 6 | 龚书铎 2 nr 7 | 龚二人 2 nr 8 | 龚云甫 3 nr 9 | 龚伟强 5 nr 10 | 龚先生 4 nr 11 | 龚光杰 44 nr 12 | 龚古尔 24 nr 13 | 龚子敬 2 nr 14 | 龚孝升 12 nr 15 | 龚学平 2 nr 16 | 龚完敬 5 nr 17 | 龚定庵 3 nr 18 | 龚定敬 2 nr 19 | 龚宝铨 5 nr 20 | 龚家村 3 nr 21 | 龚建国 29 nr 22 | 龚德俊 6 nr 23 | 龚心瀚 3 nr 24 | 龚志国 2 nr 25 | 龚意田 3 nr 26 | 龚慈恩 3 nr 27 | 龚施茜 3 nr 28 | 龚晓犁 2 nr 29 | 龚普洛 3 nr 30 | 龚智超 7 nr 31 | 龚松林 10 nr 32 | 龚永明 3 nr 33 | 龚永泉 5 nr 34 | 龚泽艺 256 nr 35 | 龚睿 8 nrfg 36 | 龚祖同 2 nr 37 | 龚秋婷 3 nr 38 | 龚老爷 2 nr 39 | 龚育之 19 nr 40 | 龚自珍 28 nr 41 | 龚蓓苾 3 nr 42 | 龚虹嘉 3 nr 43 | 龚诗嘉 3 nr 44 | 龛 223 ng 45 | 龜 2 zg 46 | 龟 903 ns 47 | 龟儿子 123 n 48 | 龟兆 3 nz 49 | 龟兹 215 ns 50 | 龟兹王 3 nrt 51 | 龟冷搘床 3 v 52 | 龟冷支床 3 n 53 | 龟卜 3 n 54 | 龟厌不告 3 l 55 | 龟壳 33 n 56 | 龟壳花 3 n 57 | 龟头 34 n 58 | 龟头炎 3 n 59 | 龟山 23 ns 60 | 龟山乡 3 ns 61 | 龟山岛 3 ns 62 | 龟年鹤寿 3 ns 63 | 龟年鹤算 3 l 64 | 龟文 3 nz 65 | 龟文写迹 3 n 66 | 龟文鸟迹 3 n 67 | 龟板 10 n 68 | 龟毛免角 3 n 69 | 龟毛兔角 3 n 70 | 龟溪 3 ns 71 | 龟玉 3 nz 72 | 龟王 3 nz 73 | 龟甲 92 ns 74 | 龟甲胶 3 nz 75 | 龟筮 3 n 76 | 龟纹 3 n 77 | 龟缩 29 v 78 | 龟肉 3 n 79 | 龟背 21 n 80 | 龟背竹 3 n 81 | 龟苓膏 3 n 82 | 龟苗 3 n 83 | 龟裂 34 v 84 | 龟足 5 v 85 | 龟鉴 2 n 86 | 龟镜 3 nz 87 | 龟鳖 3 n 88 | 龟鹤遐寿 3 l 89 | 龟龄鹤算 3 n 90 | 龟龙片甲 3 nz 91 | 龟龙麟凤 3 ns 92 | 龠 5 g 93 | 龢 732 zg 94 | -------------------------------------------------------------------------------- /test/testdata/jieba.dict.0.utf8: -------------------------------------------------------------------------------- 1 | 龙鸣狮吼 3 nr 2 | 龙齐诺 2 nr 3 | 龙齿 3 n 4 | 龚 176 nr 5 | 龚世萍 2 nr 6 | 龚书铎 2 nr 7 | 龚二人 2 nr 8 | 龚云甫 3 nr 9 | 龚伟强 5 nr 10 | 龚先生 4 nr 11 | 龚光杰 44 nr 12 | 龚古尔 24 nr 13 | 龚子敬 2 nr 14 | 龚孝升 12 nr 15 | 龚学平 2 nr 16 | 龚完敬 5 nr 17 | 龚定庵 3 nr 18 | 龚定敬 2 nr 19 | 龚宝铨 5 nr 20 | 龚家村 3 nr 21 | 龚建国 29 nr 22 | 龚德俊 6 nr 23 | 龚心瀚 3 nr 24 | 龚志国 2 nr 25 | 龚意田 3 nr 26 | 龚慈恩 3 nr 27 | 龚施茜 3 nr 28 | 龚晓犁 2 nr 29 | 龚普洛 3 nr 30 | 龚智超 7 nr 31 | 龚松林 10 nr 32 | 龚永明 3 nr 33 | 龚永泉 5 nr 34 | 龚泽艺 256 nr 35 | 龚睿 8 nrfg 36 | 龚祖同 2 nr 37 | 龚秋婷 3 nr 38 | 龚老爷 2 nr 39 | 龚育之 19 nr 40 | 龚自珍 28 nr 41 | 龚蓓苾 3 nr 42 | 龚虹嘉 3 nr 43 | 龚诗嘉 3 nr 44 | 龛 223 ng 45 | 龜 2 zg 46 | 龟 903 ns 47 | 龟儿子 123 n 48 | 龟兆 3 nz 49 | 龟兹 215 ns 50 | 龟兹王 3 nrt 51 | 龟冷搘床 3 v 52 | 龟冷支床 3 n 53 | 龟卜 3 n 54 | 龟厌不告 3 l 55 | 龟壳 33 n 56 | 龟壳花 3 n 57 | 龟头 34 n 58 | 龟头炎 3 n 59 | 龟山 23 ns 60 | 龟山乡 3 ns 61 | 龟山岛 3 ns 62 | 龟年鹤寿 3 ns 63 | 龟年鹤算 3 l 64 | 龟文 3 nz 65 | 龟文写迹 3 n 66 | 龟文鸟迹 3 n 67 | 龟板 10 n 68 | 龟毛免角 3 n 69 | 龟毛兔角 3 n 70 | 龟溪 3 ns 71 | 龟玉 3 nz 72 | 龟王 3 nz 73 | 龟甲 92 ns 74 | 龟甲胶 3 nz 75 | 龟筮 3 n 76 | 龟纹 3 n 77 | 龟缩 29 v 78 | 龟肉 3 n 79 | 龟背 21 n 80 | 龟背竹 3 n 81 | 龟苓膏 3 n 82 | 龟苗 3 n 83 | 龟裂 34 v 84 | 龟足 5 v 85 | 龟鉴 2 n 86 | 龟镜 3 nz 87 | 龟鳖 3 n 88 | 龟鹤遐寿 3 l 89 | 龟龄鹤算 3 n 90 | 龟龙片甲 3 nz 91 | 龟龙麟凤 3 ns 92 | 龠 5 g 93 | 龢 732 zg 94 | -------------------------------------------------------------------------------- /test/testdata/jieba.dict.1.utf8: -------------------------------------------------------------------------------- 1 | AT&T 3 nz 2 | B超 3 n 3 | c# 3 nz 4 | C# 3 nz 5 | c++ 3 nz 6 | C++ 3 nz 7 | T恤 4 n 8 | 一 217830 m 9 | 一一 1670 m 10 | 一一二 11 m 11 | 一一例 3 m 12 | 一一分 8 m 13 | 一一列举 34 i 14 | 一一对 9 m 15 | 一一对应 43 l 16 | 一一记 2 m 17 | 一一道来 4 l 18 | 一丁 18 d 19 | 一丁不识 3 i 20 | 一丁点 3 m 21 | 一丁点儿 24 m 22 | 一七 22 m 23 | 一七八不 3 l 24 | 一万 442 m 25 | 一万一千 4 m 26 | 一万一千五百二十颗 2 m 27 | 一万一千八百八十斤 2 m 28 | 一万一千多间 2 m 29 | 一万一千零九十五册 4 m 30 | 一万七千 5 m 31 | 一万七千余 2 m 32 | 一万七千多 2 m 33 | 一万七千多户 2 m 34 | 一万万 4 m 35 | 一万万两 4 m 36 | 一万三千 8 m 37 | 一万三千五百一十七 2 m 38 | 一万三千五百斤 4 m 39 | 一万三千余种 2 m 40 | 一万三千块 2 m 41 | 一万两 124 m 42 | 一万两万 4 m 43 | 一万两千 3 m 44 | 一万个 62 m 45 | 一万九千 2 m 46 | 一万九千余 2 m 47 | 一万二 10 m 48 | 一万二千 7 m 49 | 一万二千两 2 m 50 | 一万二千五百 4 m 51 | 一万二千五百一十二 2 m 52 | 一万二千五百余 2 m 53 | 一万二千五百余吨 2 m 54 | 一万二千亩 2 m 55 | 一万二千余 2 m 56 | 一万二千六百八十二箱 2 m 57 | 一万二千名 3 m 58 | 一万二千里 3 m 59 | 一万五 6 m 60 | 一万五千 45 m 61 | 一万五千一百四十四卷 2 m 62 | 一万五千两 4 m 63 | 一万五千个 2 m 64 | 一万五千二百余 2 m 65 | 一万五千余 9 m 66 | 一万五千元 3 m 67 | 一万五千名 4 m 68 | -------------------------------------------------------------------------------- /test/testdata/jieba.dict.2.utf8: -------------------------------------------------------------------------------- 1 | 一万七千 5 m 2 | 一万七千余 2 m 3 | 一万七千多 2 m 4 | 一万七千多户 2 m 5 | 一万万 4 m 6 | 一万万两 4 m 7 | 一万三千 8 m 8 | 一万三千五百一十七 2 m 9 | 一万三千五百斤 4 m 10 | 一万三千余种 2 m 11 | 一万三千块 2 m 12 | 一万两 124 m 13 | 一万两万 4 m 14 | 一万两千 3 m 15 | 一万个 62 m 16 | 一万九千 2 m 17 | 一万九千余 2 m 18 | 一万二 10 m 19 | 一万二千 7 m 20 | 一万二千两 2 m 21 | 一万二千五百 4 m 22 | 一万二千五百一十二 2 m 23 | 一万二千五百余 2 m 24 | 一万二千五百余吨 2 m 25 | 一万二千亩 2 m 26 | 一万二千余 2 m 27 | 一万二千六百八十二箱 2 m 28 | 一万二千名 3 m 29 | 一万二千里 3 m 30 | 一万五 6 m 31 | 一万五千 45 m 32 | 一万五千一百四十四卷 2 m 33 | 一万五千两 4 m 34 | 一万五千个 2 m 35 | 一万五千二百余 2 m 36 | 一万五千余 9 m 37 | 一万五千元 3 m 38 | 一万五千名 4 m 39 | 一万五千多 2 m 40 | 一万五千家 2 m 41 | 一万亿 3 m 42 | 一万亿美元 5 m 43 | 一万余 41 m 44 | 一万余吨 2 m 45 | 一万余顷 2 m 46 | 一万倍 14 m 47 | 一万元 61 m 48 | 一万八 5 m 49 | 一万八千 7 m 50 | 一万八千余 8 m 51 | 一万八千多元 2 m 52 | 一万公里 2 m 53 | 一万六千 5 m 54 | 一万六千三百户 2 m 55 | 一万六千余户 2 m 56 | 一万六千多 3 m 57 | 一万册 2 m 58 | 一万刀 7 m 59 | 一万匹 4 m 60 | 一万卷 2 m 61 | 一万双 6 m 62 | 一万发 2 m 63 | 一万句 11 m 64 | 一万只 9 m 65 | -------------------------------------------------------------------------------- /test/unittest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | if (MSVC) 3 | set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDebugDLL") 4 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 5 | endif() 6 | 7 | include(FetchContent) 8 | 9 | FetchContent_Declare( 10 | googletest 11 | GIT_REPOSITORY https://github.com/google/googletest.git 12 | GIT_TAG release-1.12.1 13 | ) 14 | FetchContent_MakeAvailable(googletest) 15 | 16 | ADD_EXECUTABLE(test.run 17 | gtest_main.cpp 18 | TLogging.cpp 19 | TArgvContext.cpp 20 | TConfig.cpp 21 | TStringUtil.cpp 22 | TStdExtension.cpp 23 | TLocalVector.cpp 24 | TClosure.cpp 25 | TColorPrint.cpp 26 | ) 27 | TARGET_LINK_LIBRARIES(test.run gtest) 28 | 29 | #include(GoogleTest) 30 | #gtest_discover_tests(test.run) 31 | -------------------------------------------------------------------------------- /test/unittest/TArgvContext.cpp: -------------------------------------------------------------------------------- 1 | #include "limonp/ArgvContext.hpp" 2 | #include "gtest/gtest.h" 3 | 4 | using namespace limonp; 5 | 6 | TEST(ArgvContextTest, Test1) { 7 | const char * argv[] = {"./exe1", "--hehe", "11", "key2", "-k", "val"}; 8 | string s; 9 | ArgvContext arg(sizeof(argv)/sizeof(argv[0]), argv); 10 | s< 4 | 5 | using namespace std; 6 | using namespace limonp; 7 | using namespace CastFloat; 8 | 9 | TEST(CastFunctTest, Test1) { 10 | ASSERT_LT(abs(shortBitsToFloat(127) - 3.43025e-05), 0.0001); 11 | ASSERT_LT(abs(-122880 - shortBitsToFloat(-128)), 0.0001); 12 | ASSERT_EQ(shortBitsToFloat(0), 0); 13 | //for(short i = -128 ; i <= 127; i++) 14 | //{ 15 | // float f = shortBitsToFloat(i); 16 | // cout<Run(); 36 | delete c; 37 | c = NULL; 38 | 39 | c = NewClosure(&Foo1, 1); 40 | ASSERT_TRUE(c != NULL); 41 | c->Run(); 42 | delete c; 43 | c = NULL; 44 | 45 | c = NewClosure(&Foo2, 1, float(2)); 46 | ASSERT_TRUE(c != NULL); 47 | c->Run(); 48 | delete c; 49 | c = NULL; 50 | 51 | c = NewClosure(&Foo3, 1, float(2), double(3)); 52 | ASSERT_TRUE(c != NULL); 53 | c->Run(); 54 | delete c; 55 | c = NULL; 56 | } 57 | 58 | TEST(Closure, Test1) { 59 | ClosureInterface* c; 60 | 61 | Obj obj; 62 | c = NewClosure(&obj, &Obj::Foo0); 63 | ASSERT_TRUE(c != NULL); 64 | c->Run(); 65 | delete c; 66 | c = NULL; 67 | 68 | c = NewClosure(&obj, &Obj::Foo1, 1); 69 | ASSERT_TRUE(c != NULL); 70 | c->Run(); 71 | delete c; 72 | c = NULL; 73 | 74 | c = NewClosure(&obj, &Obj::Foo2, 1, float(2)); 75 | ASSERT_TRUE(c != NULL); 76 | c->Run(); 77 | delete c; 78 | c = NULL; 79 | 80 | c = NewClosure(&obj, &Obj::Foo3, 1, float(2), double(3)); 81 | ASSERT_TRUE(c != NULL); 82 | c->Run(); 83 | delete c; 84 | c = NULL; 85 | } 86 | -------------------------------------------------------------------------------- /test/unittest/TColorPrint.cpp: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | #include "limonp/Colors.hpp" 3 | #include "limonp/Logging.hpp" 4 | 5 | using namespace limonp; 6 | 7 | TEST(ColorPrint, Test1) { 8 | ColorPrintln(RED, "hello %s", "world"); 9 | ColorPrintln(RED, "hello %s", "world"); 10 | XLOG(INFO) << "hello world"; 11 | ColorPrintln(RED, "hello %s", "world"); 12 | ColorPrintln(GREEN, "hello %s", "world"); 13 | XLOG(INFO) << "hello world"; 14 | ColorPrintln(BLACK, "hello %s", "world"); 15 | ColorPrintln(YELLOW, "hello %s", "world"); 16 | ColorPrintln(BLUE, "hello %s", "world"); 17 | ColorPrintln(PURPLE, "hello %s", "world"); 18 | ColorPrintln(PURPLE, "hello %s", "world", " and colors"); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /test/unittest/TConfig.cpp: -------------------------------------------------------------------------------- 1 | #include "limonp/Config.hpp" 2 | #include "gtest/gtest.h" 3 | 4 | using namespace limonp; 5 | TEST(COnfigTest, Test1) { 6 | Config conf("../test/testdata/1.conf"); 7 | string res; 8 | ASSERT_EQ("{key1:val1, key2:val2}", res << conf); 9 | res = conf.Get("key1", ""); 10 | ASSERT_EQ("val1", res); 11 | res = conf.Get("key2", ""); 12 | ASSERT_EQ("val2", res); 13 | const char * str = conf["key3"]; 14 | ASSERT_FALSE(str); 15 | ASSERT_TRUE(0 == strcmp(conf["key2"], "val2")); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /test/unittest/TLocalVector.cpp: -------------------------------------------------------------------------------- 1 | #include "limonp/LocalVector.hpp" 2 | #include "limonp/StdExtension.hpp" 3 | #include 4 | #include "gtest/gtest.h" 5 | 6 | using namespace limonp; 7 | 8 | TEST(LocalVector, test1) { 9 | LocalVector vec; 10 | ASSERT_EQ(vec.size(), 0u); 11 | ASSERT_EQ(vec.capacity(), LOCAL_VECTOR_BUFFER_SIZE); 12 | ASSERT_TRUE(vec.empty()); 13 | size_t size = 129; 14 | for(size_t i = 0; i < size; i++) { 15 | vec.push_back(i); 16 | } 17 | ASSERT_EQ(vec.size(), size); 18 | ASSERT_EQ(vec.capacity(), 256u); 19 | ASSERT_FALSE(vec.empty()); 20 | LocalVector vec2(vec); 21 | ASSERT_EQ(vec2.capacity(), vec.capacity()); 22 | ASSERT_EQ(vec2.size(), vec.size()); 23 | } 24 | 25 | TEST(LocalVector, test2) { 26 | LocalVector vec; 27 | ASSERT_EQ(vec.size(), 0u); 28 | ASSERT_EQ(vec.capacity(), LOCAL_VECTOR_BUFFER_SIZE); 29 | ASSERT_TRUE(vec.empty()); 30 | size_t size = 1; 31 | for(size_t i = 0; i < size; i++) { 32 | vec.push_back(i); 33 | } 34 | ASSERT_EQ(vec.size(), size); 35 | ASSERT_EQ(vec.capacity(), LOCAL_VECTOR_BUFFER_SIZE); 36 | ASSERT_FALSE(vec.empty()); 37 | LocalVector vec2; 38 | vec2 = vec; 39 | ASSERT_EQ(vec2.capacity(), vec.capacity()); 40 | ASSERT_EQ(vec2.size(), vec.size()); 41 | } 42 | -------------------------------------------------------------------------------- /test/unittest/TLogging.cpp: -------------------------------------------------------------------------------- 1 | #define LOGGING_LEVEL LL_WARNING 2 | #include "limonp/Logging.hpp" 3 | #include "gtest/gtest.h" 4 | 5 | TEST(Logging, Test1) { 6 | XLOG(DEBUG) << "xxx" << " yyy"; 7 | XLOG(INFO) << "hello"; 8 | XLOG(WARNING) << "hello"; 9 | XLOG(ERROR) << "hello"; 10 | //XCHECK(false) << "hello, " << "world"; 11 | //XLOG(FATAL) << "hello"; 12 | } 13 | -------------------------------------------------------------------------------- /test/unittest/TStdExtension.cpp: -------------------------------------------------------------------------------- 1 | #include "limonp/StdExtension.hpp" 2 | #include "limonp/StringUtil.hpp" 3 | #include "gtest/gtest.h" 4 | #include 5 | #include 6 | 7 | using namespace limonp; 8 | TEST(StdOutbound, Test1) { 9 | ifstream ifs("../test/testdata/StdExtension.data"); 10 | string s; 11 | s << ifs; 12 | ASSERT_EQ("key1 = val1\n##this is comment\nkey2=val2\n", s); 13 | 14 | const char * outFileName = "stdoutbuond.test.tmp"; 15 | ofstream ofs(outFileName); 16 | s = outFileName; 17 | ofs << s; 18 | ASSERT_TRUE(!!ofs); 19 | ofs.close(); 20 | 21 | ifstream ifs2(outFileName); 22 | s << ifs2; 23 | ASSERT_EQ(outFileName, s); 24 | } 25 | 26 | TEST(StdOutbound, Funct_IsIn) { 27 | map mp; 28 | for(size_t i = 1; i < 5; i ++) { 29 | mp[i] = i+1; 30 | } 31 | 32 | ASSERT_TRUE(IsIn(mp, 1)); 33 | ASSERT_FALSE(IsIn(mp, 0)); 34 | } 35 | 36 | TEST(StdOutbound, Test2) { 37 | map mp1; 38 | mp1[1] = 2; 39 | mp1[2] = 3; 40 | string s; 41 | ASSERT_EQ(s << mp1, "{1:2, 2:3}"); 42 | unordered_map mp2; 43 | mp2[1] = 2; 44 | mp2[2] = 3; 45 | s << mp2; 46 | ASSERT_TRUE( s == "{1:2, 2:3}" || s == "{2:3, 1:2}"); 47 | } 48 | 49 | TEST(StdOutbound, Test3) { 50 | { 51 | vector v; 52 | v.push_back("1"); 53 | v.push_back("2"); 54 | string s; 55 | ASSERT_EQ(s << v, "[\"1\", \"2\"]"); 56 | } 57 | { 58 | deque v; 59 | v.push_back("1"); 60 | v.push_back("2"); 61 | string s; 62 | ASSERT_EQ(s << v, "[\"1\", \"2\"]"); 63 | } 64 | } 65 | 66 | struct TestWord { 67 | string word; 68 | size_t offset; 69 | }; // struct TestWord 70 | 71 | ostream& operator << (ostream& os, const TestWord& w) { 72 | return os << "{\"word\": \"" << w.word << "\", \"offset\": " << w.offset << "}"; 73 | } 74 | 75 | TEST(StdOutbound, TestWord) { 76 | { 77 | vector v; 78 | v.push_back("1"); 79 | v.push_back("2"); 80 | string s; 81 | ASSERT_EQ(s << v, "[\"1\", \"2\"]"); 82 | } 83 | { 84 | vector v; 85 | TestWord w; 86 | w.word = "hello"; 87 | w.offset = 0; 88 | v.push_back(w); 89 | w.word = "world"; 90 | w.offset = 5; 91 | v.push_back(w); 92 | string s; 93 | ASSERT_EQ(s << v, "[{\"word\": \"hello\", \"offset\": 0}, {\"word\": \"world\", \"offset\": 5}]"); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /test/unittest/TStringUtil.cpp: -------------------------------------------------------------------------------- 1 | #include "limonp/StringUtil.hpp" 2 | #include "gtest/gtest.h" 3 | using namespace limonp; 4 | 5 | TEST(StringUtilTest, Test1) { 6 | vector vec; 7 | string s; 8 | Split("\t1\t3\t4\t", vec, "\t"); 9 | ASSERT_EQ(s << vec, "[\"\", \"1\", \"3\", \"4\"]"); 10 | s = " \t\n ni hao ad \r\n"; 11 | ASSERT_EQ("ni hao ad", Trim(s)); 12 | ASSERT_EQ("select * from table1 limit 1;" ,StringFormat("select %s from %s %s;", "*","table1","limit 1")); 13 | s = StringFormat("select %s from %s %s;", "*","table1","limit 1"); 14 | ASSERT_EQ("select * from table1 limit 1;" ,s); 15 | vec.clear(); 16 | vec.push_back("1"); 17 | vec.push_back("2"); 18 | vec.push_back("3"); 19 | s.clear(); 20 | Join(vec.begin(), vec.end(), s,","); 21 | ASSERT_EQ("1,2,3",s); 22 | s = Join(vec.begin(), vec.end(), ".."); 23 | ASSERT_EQ("1..2..3", s); 24 | const char* arr[] = {"2","3","5"}; 25 | ASSERT_EQ("2,3,5", Join(arr, arr + sizeof(arr)/sizeof(arr[0]), ",")); 26 | map mp; 27 | mp["key1"] =2; 28 | ASSERT_EQ("{key1:2}", s << mp); 29 | std::unordered_map hmp; 30 | hmp[1]=2; 31 | ASSERT_EQ("{1:2}", s << hmp); 32 | } 33 | 34 | TEST(StringUtilTest, Test2) { 35 | string s, gbks; 36 | ifstream ifs("../test/testdata/dict.gbk"); 37 | ASSERT_TRUE(!!ifs); 38 | 39 | vector uni; 40 | while(getline(ifs, s)) { 41 | GBKTrans(s, uni); 42 | GBKTrans(uni.begin(), uni.end(), gbks); 43 | ASSERT_EQ(s, gbks); 44 | } 45 | } 46 | 47 | TEST(StringUtilTest, Test3) { 48 | string s, utf8; 49 | ifstream ifs("../test/testdata/dict.utf8"); 50 | ASSERT_TRUE(!!ifs); 51 | 52 | vector uni; 53 | while(getline(ifs, s)) { 54 | ASSERT_TRUE(Utf8ToUnicode(s, uni)); 55 | UnicodeToUtf8(uni.begin(), uni.end(), utf8); 56 | ASSERT_EQ(s, utf8); 57 | } 58 | } 59 | 60 | TEST(StringUtilTest, Test4) { 61 | //ASSERT_TRUE(StartsWith("--help",NULL)); 62 | ASSERT_TRUE(StartsWith("--help","--")); 63 | ASSERT_TRUE(StartsWith("--help","-")); 64 | ASSERT_FALSE(StartsWith("--help","he")); 65 | ASSERT_TRUE(StartsWith("help","help")); 66 | ASSERT_FALSE(StartsWith("","help")); 67 | ASSERT_TRUE(StartsWith("hel","")); 68 | ASSERT_TRUE(EndsWith("hel","")); 69 | ASSERT_TRUE(EndsWith("hel","el")); 70 | } 71 | 72 | TEST(StringUtilTest, Test5) { 73 | const char* str = "1,2,3,4"; 74 | vector vec; 75 | string res; 76 | Split(str, vec, ","); 77 | ASSERT_EQ("[\"1\", \"2\", \"3\", \"4\"]", res << vec); 78 | Split("1,2,3,4,", vec, ","); 79 | ASSERT_EQ("[\"1\", \"2\", \"3\", \"4\"]", res << vec); 80 | Split(str, vec, ",", 3); 81 | ASSERT_EQ("[\"1\", \"2\", \"3\", \"4\"]", res << vec); 82 | 83 | Split("1", vec, ","); 84 | ASSERT_EQ("[\"1\"]", res << vec); 85 | 86 | Split(str, vec, ",", 1); 87 | ASSERT_EQ("[\"1\", \"2,3,4\"]", res << vec); 88 | 89 | Split("", vec, ","); 90 | ASSERT_EQ("[]", res << vec); 91 | 92 | Split("1, 2", vec, ","); 93 | ASSERT_EQ("[\"1\", \" 2\"]", res << vec); 94 | 95 | Split("1==2", vec, "=="); 96 | ASSERT_EQ("[\"1\", \"\", \"2\"]", res << vec); 97 | 98 | Split("1,", vec, ","); 99 | ASSERT_EQ("[\"1\"]", res << vec); 100 | 101 | Split(",1,", vec, ","); 102 | ASSERT_EQ("[\"\", \"1\"]", res << vec); 103 | 104 | Split("1, ", vec, ","); 105 | ASSERT_EQ("[\"1\", \" \"]", res << vec); 106 | 107 | res << Split("1|2,3", "|,"); 108 | ASSERT_EQ("[\"1\", \"2\", \"3\"]", res); 109 | } 110 | 111 | TEST(StringUtilTest, Trim) { 112 | string s; 113 | s = "xxxyyyxx"; 114 | ASSERT_EQ(RTrim(s, 'x'), "xxxyyy"); 115 | ASSERT_EQ(LTrim(s, 'x'), "yyy"); 116 | s = "xxxyyyxx"; 117 | ASSERT_EQ(Trim(s, 'x'), "yyy"); 118 | 119 | s = " x y "; 120 | ASSERT_EQ(Trim(s), "x y"); 121 | 122 | // check if it core dump when using isalpha 123 | wchar_t w = 1000024; 124 | ASSERT_FALSE(IsSpace(w)); 125 | w = 0x20; 126 | ASSERT_TRUE(IsSpace(w)); 127 | } 128 | 129 | TEST(StringUtilTest, GetTime) { 130 | string s; 131 | GetTime("%Y-%m-%d %H:%M:%S", s); 132 | //print(s); 133 | } 134 | 135 | TEST(StringUtilTest, PathJoin) { 136 | const char * path1 = "/home/foo/dir"; 137 | const char * path2 = "file"; 138 | const char * path3 = "/home/foo/dir/"; 139 | const char * path4 = "file"; 140 | const char * answer = "/home/foo/dir/file"; 141 | 142 | ASSERT_EQ(answer, PathJoin(path1, path2)); 143 | ASSERT_EQ(answer, PathJoin(path3, path4)); 144 | } 145 | 146 | TEST(StringUtilTest, JapaneseUnicode) { 147 | // Japanese 148 | const char* s = "がんば"; 149 | vector unicode; 150 | ASSERT_TRUE(Utf8ToUnicode(s, unicode)); 151 | ASSERT_EQ(3u, unicode.size()); 152 | } 153 | 154 | TEST(StringUtilTest, RareChinese) { 155 | //U+10000 – U+10FFFF 156 | const char* s = "𪚥"; 157 | vector unicode; 158 | ASSERT_FALSE(Utf8ToUnicode(s, unicode)); 159 | ASSERT_EQ(0u, unicode.size()); 160 | } 161 | 162 | TEST(StringUtilTest, RareChineseUnicode32) { 163 | //U+10000 – U+10FFFF 164 | const char* s = "𪚥"; 165 | vector unicode; 166 | ASSERT_TRUE(Utf8ToUnicode32(s, unicode)); 167 | ASSERT_EQ(1u, unicode.size()); 168 | 169 | string s2; 170 | Unicode32ToUtf8(unicode.begin(), unicode.end(), s2); 171 | ASSERT_EQ(s2, s); 172 | } 173 | 174 | TEST(StringUtilTest, Unicode32) { 175 | const char* s = "1+1=2你好世界,。"; 176 | vector unicode; 177 | ASSERT_TRUE(Utf8ToUnicode32(s, unicode)); 178 | ASSERT_EQ(unicode.size(), 11u); 179 | 180 | string s2; 181 | Unicode32ToUtf8(unicode.begin(), unicode.end(), s2); 182 | ASSERT_EQ(s2, s); 183 | } 184 | -------------------------------------------------------------------------------- /test/unittest/gtest_main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2006, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | #include 31 | 32 | #include "gtest/gtest.h" 33 | 34 | GTEST_API_ int main(int argc, char **argv) { 35 | std::cout << "Running main() from gtest_main.cc\n"; 36 | 37 | testing::InitGoogleTest(&argc, argv); 38 | return RUN_ALL_TESTS(); 39 | } 40 | --------------------------------------------------------------------------------