From 7a771b28b948d8056aa7d1f5cfe6063828759352 Mon Sep 17 00:00:00 2001 From: abbycin Date: Sun, 23 Aug 2020 20:21:31 +0800 Subject: [PATCH] merge dev --- .clang-format | 114 ++++ README.md | 4 +- bloom/CMakeLists.txt | 12 + bloom/README.md | 1 + bloom/bloom.h | 100 +++ bloom/main.cpp | 44 ++ bloom/murmur3/CMakeLists.txt | 1 + bloom/murmur3/MurmurHash3.cpp | 415 ++++++++++++ bloom/murmur3/MurmurHash3.h | 37 ++ cfg/hash.h | 362 +++++------ channel/channel.h | 435 ++++++------- channel/test.cpp | 9 +- clp/README.md | 38 -- clp/clp.h | 282 -------- clp/test.cpp | 57 -- coroutine/README.md | 2 +- coroutine/coroutine.h | 268 ++++---- coroutine/main.cpp | 32 +- crypt/crypto.h | 230 ++++--- fake_variant/fake_variant.h | 148 ++--- fake_variant/test.cpp | 14 +- file_sort/bit.cpp | 2 +- file_sort/bs.cpp | 198 +++--- fm/README.md | 10 +- fm/functor_map.h | 233 ++++--- fm/test.cpp | 9 +- form_parser/form_parser.h | 1100 +++++++++++++++----------------- format.sh | 6 + logging/bench.cc | 51 +- logging/logging.h | 1055 ++++++++++++++---------------- logging/test.cpp | 8 +- loop_per_thread/client.cpp | 135 ++-- loop_per_thread/server.cpp | 536 +++++++--------- loop_per_thread/server1.cpp | 257 ++++---- loop_per_thread/server_old.cpp | 374 +++++------ meta/function_traits.h | 39 +- optional/CMakeLists.txt | 0 optional/main.cpp | 0 optional/optional.h | 70 +- rbtree/rb-tree.h | 961 +++++++++++++--------------- rbtree/test.cpp | 12 +- router/main.cpp | 11 +- router/radix.cc | 375 +++++------ signal/signal1.cpp | 19 +- signal/signal1.h | 112 ++-- signal/signal2.cpp | 28 +- signal/signal2.h | 94 ++- signal/signal_call.h | 163 +++-- signal/signal_call_test.cpp | 23 +- string_ext/string_ext.h | 635 +++++++++--------- string_ext/test.cpp | 27 +- string_view.h | 200 +++--- threadpool/test_threadpool.cpp | 12 +- threadpool/threadpool.h | 141 ++-- typelist.cpp | 243 ++++--- variant/test.cpp | 79 ++- variant/variant.h | 770 +++++++++++----------- variant/variantlist.cpp | 155 ++--- 58 files changed, 5319 insertions(+), 5429 deletions(-) create mode 100644 .clang-format create mode 100644 bloom/CMakeLists.txt create mode 100644 bloom/README.md create mode 100644 bloom/bloom.h create mode 100644 bloom/main.cpp create mode 100644 bloom/murmur3/CMakeLists.txt create mode 100644 bloom/murmur3/MurmurHash3.cpp create mode 100644 bloom/murmur3/MurmurHash3.h delete mode 100644 clp/README.md delete mode 100644 clp/clp.h delete mode 100644 clp/test.cpp create mode 100755 format.sh mode change 100755 => 100644 optional/CMakeLists.txt mode change 100755 => 100644 optional/main.cpp mode change 100755 => 100644 optional/optional.h diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..760e1f9 --- /dev/null +++ b/.clang-format @@ -0,0 +1,114 @@ +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: DontAlign +AlignOperands: true +AlignTrailingComments: false +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: true +BreakBeforeBraces: Allman +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + IndentBraces: true + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +BreakBeforeBinaryOperators: None +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ [NOTE|WARNING|TODO|FIXME]:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +FixNamespaceComments: false +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: false +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Left +ReflowComments: true +SortIncludes: false +SortUsingDeclarations: false +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: Never +SpaceBeforeRangeBasedForLoopColon: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 2 +UseTab: Never diff --git a/README.md b/README.md index 160a7d1..77ef33f 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,11 @@ header-only libraries written in modern C++ (11, 14, 17, 2a). -|item| describe | +|item| description | |-|-| +|[bloom](./bloom)| nαïve bloom filter | |[cfg](./cfg)| hash table | |[channel](./channel) | [Rust](https://www.rust-lang.org)-like [channel](https://doc.rust-lang.org/std/sync/mpsc/fn.channel.html) implementation based on lock-free mpsc queue | -|[clp](./clp) | C++17 feature test | |[coroutine](./coroutine) | coroutine impl from scratch, demonstrate how to impl your own coroutine | |[crypt](./crypt) | toy | |[fake_variant](./fake_variant)| tuple-like class based on multi-inherit | diff --git a/bloom/CMakeLists.txt b/bloom/CMakeLists.txt new file mode 100644 index 0000000..5d73bf8 --- /dev/null +++ b/bloom/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.15) +project(bloom) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +include_directories(${PROJECT_SOURCE_DIR}/murmur3) + +add_subdirectory(murmur3) +add_executable(bloom bloom.h main.cpp) +target_link_libraries(bloom murmur3) \ No newline at end of file diff --git a/bloom/README.md b/bloom/README.md new file mode 100644 index 0000000..0485f9f --- /dev/null +++ b/bloom/README.md @@ -0,0 +1 @@ +a naive bloom filter implementation :cherry_blossom::rooster: \ No newline at end of file diff --git a/bloom/bloom.h b/bloom/bloom.h new file mode 100644 index 0000000..e2f1852 --- /dev/null +++ b/bloom/bloom.h @@ -0,0 +1,100 @@ +/********************************************************* + File Name:bloom_filter.h + Author: Abby Cin + Mail: abbytsing@gmail.com + Created Time: Sun 23 Aug 2020 03:51:01 PM CST +**********************************************************/ + +#ifndef BLOOM_FILTER_H +#define BLOOM_FILTER_H + +#include +#include +#include +#include +#include "MurmurHash3.h" +#include + +class BloomFilter +{ +public: + template + static void print(Args&&... args) + { + ((std::cout << args << ' '), ...); + std::cout << '\n'; + } + + // n: collection size + // r: expect false positive ratio + BloomFilter(size_t n, double r) + { + n_ = n; + nb_ = -1 * (n_ * std::log(r)) / std::pow(std::log(2), 2); + k_ = std::ceil(std::log(2) * nb_ / n_); + init(); + print("size:", bits_.size(), nb_); + } + + [[nodiscard]] double estimate() const { return std::pow(1 - std::exp(-((double)n_ * k_ / nb_)), k_); } + + void add(std::string_view x) + { + for(auto& f: hash_) + { + auto h = f(x) % nb_; + size_t span = h / width_; + size_t slot = h % width_; + bits_[span] |= slot; + } + } + + bool test(std::string_view x) + { + for(auto& f: hash_) + { + auto h = f(x) % nb_; + size_t span = h / width_; + size_t slot = h % width_; + if(!(bits_[span] & slot)) + { + return false; + } + } + return true; + } + +private: + using hash_func = std::function; + constexpr static size_t width_ = sizeof(uint64_t) * 8; + size_t n_; + size_t nb_; + size_t k_; + std::vector bits_; + std::vector hash_; + + void init() + { + bits_.resize(nb_ / width_ + 1); // ceil + for(size_t i = 0; i < k_; ++i) + { + hash_.emplace_back([i](std::string_view x) -> uint64_t { + uint32_t h = 0; + uint32_t l = 0; + hash(x, &h, &l); + uint64_t r = h; + r <<= sizeof(uint32_t); + r |= (i + 1) * l; + return r; + }); + } + } + + static void hash(std::string_view x, uint32_t* h, uint32_t* l) + { + MurmurHash3_x86_32(x.data(), x.size(), 7, l); + MurmurHash3_x86_32(x.data(), x.size(), 17, h); + } +}; + +#endif // BLOOM_FILTER_H \ No newline at end of file diff --git a/bloom/main.cpp b/bloom/main.cpp new file mode 100644 index 0000000..84ed762 --- /dev/null +++ b/bloom/main.cpp @@ -0,0 +1,44 @@ +/********************************************************* + File Name:main.cpp + Author: Abby Cin + Mail: abbytsing@gmail.com + Created Time: Sun 23 Aug 2020 03:51:10 PM CST +**********************************************************/ + +#include "bloom.h" + +int main() +{ + using namespace std::string_view_literals; + using namespace std; + BloomFilter bl{100, 0.001}; + cout << bl.estimate() << '\n'; + vector vs; + vs.emplace_back("are"); + vs.emplace_back("are you"); + vs.emplace_back("are you ok"); + vs.emplace_back("are you ok?"); + + vector ha; + ha.emplace_back("are "); + ha.emplace_back("are you "); + ha.emplace_back("are you ok "); + + for(auto x: vs) + { + bl.add(x); + } + + cout << boolalpha; + for(auto x: vs) + { + BloomFilter::print(x, "=>", bl.test(x)); + } + + BloomFilter::print("=========================="); + + for(auto x: ha) + { + BloomFilter::print(x, "=>", bl.test(x)); + } +} \ No newline at end of file diff --git a/bloom/murmur3/CMakeLists.txt b/bloom/murmur3/CMakeLists.txt new file mode 100644 index 0000000..43d2d29 --- /dev/null +++ b/bloom/murmur3/CMakeLists.txt @@ -0,0 +1 @@ +add_library(murmur3 MurmurHash3.h MurmurHash3.cpp) \ No newline at end of file diff --git a/bloom/murmur3/MurmurHash3.cpp b/bloom/murmur3/MurmurHash3.cpp new file mode 100644 index 0000000..4fff583 --- /dev/null +++ b/bloom/murmur3/MurmurHash3.cpp @@ -0,0 +1,415 @@ +//----------------------------------------------------------------------------- +// MurmurHash3 was written by Austin Appleby, and is placed in the public +// domain. The author hereby disclaims copyright to this source code. + +// Note - The x86 and x64 versions do _not_ produce the same results, as the +// algorithms are optimized for their respective platforms. You can still +// compile and run any of them on any platform, but your performance with the +// non-native version will be less than optimal. + +#include "MurmurHash3.h" + +//----------------------------------------------------------------------------- +// Platform-specific functions and macros + +// Microsoft Visual Studio + +#if defined(_MSC_VER) + +#define FORCE_INLINE __forceinline + +#include + +#define ROTL32(x, y) _rotl(x, y) +#define ROTL64(x, y) _rotl64(x, y) + +#define BIG_CONSTANT(x) (x) + +// Other compilers + +#else // defined(_MSC_VER) + +#define FORCE_INLINE inline __attribute__((always_inline)) + +inline uint32_t rotl32(uint32_t x, int8_t r) { return (x << r) | (x >> (32 - r)); } + +inline uint64_t rotl64(uint64_t x, int8_t r) { return (x << r) | (x >> (64 - r)); } + +#define ROTL32(x, y) rotl32(x, y) +#define ROTL64(x, y) rotl64(x, y) + +#define BIG_CONSTANT(x) (x##LLU) + +#endif // !defined(_MSC_VER) + +//----------------------------------------------------------------------------- +// Block read - if your platform needs to do endian-swapping or can only +// handle aligned reads, do the conversion here + +FORCE_INLINE uint32_t getblock32(const uint32_t* p, int i) { return p[i]; } + +FORCE_INLINE uint64_t getblock64(const uint64_t* p, int i) { return p[i]; } + +//----------------------------------------------------------------------------- +// Finalization mix - force all bits of a hash block to avalanche + +FORCE_INLINE uint32_t fmix32(uint32_t h) +{ + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + + return h; +} + +//---------- + +FORCE_INLINE uint64_t fmix64(uint64_t k) +{ + k ^= k >> 33; + k *= BIG_CONSTANT(0xff51afd7ed558ccd); + k ^= k >> 33; + k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53); + k ^= k >> 33; + + return k; +} + +//----------------------------------------------------------------------------- + +void MurmurHash3_x86_32(const void* key, int len, uint32_t seed, void* out) +{ + const uint8_t* data = (const uint8_t*)key; + const int nblocks = len / 4; + + uint32_t h1 = seed; + + const uint32_t c1 = 0xcc9e2d51; + const uint32_t c2 = 0x1b873593; + + //---------- + // body + + const uint32_t* blocks = (const uint32_t*)(data + nblocks * 4); + + for(int i = -nblocks; i; i++) + { + uint32_t k1 = getblock32(blocks, i); + + k1 *= c1; + k1 = ROTL32(k1, 15); + k1 *= c2; + + h1 ^= k1; + h1 = ROTL32(h1, 13); + h1 = h1 * 5 + 0xe6546b64; + } + + //---------- + // tail + + const uint8_t* tail = (const uint8_t*)(data + nblocks * 4); + + uint32_t k1 = 0; + + switch(len & 3) + { + case 3: + k1 ^= tail[2] << 16; + case 2: + k1 ^= tail[1] << 8; + case 1: + k1 ^= tail[0]; + k1 *= c1; + k1 = ROTL32(k1, 15); + k1 *= c2; + h1 ^= k1; + }; + + //---------- + // finalization + + h1 ^= len; + + h1 = fmix32(h1); + + *(uint32_t*)out = h1; +} + +//----------------------------------------------------------------------------- + +void MurmurHash3_x86_128(const void* key, const int len, uint32_t seed, void* out) +{ + const uint8_t* data = (const uint8_t*)key; + const int nblocks = len / 16; + + uint32_t h1 = seed; + uint32_t h2 = seed; + uint32_t h3 = seed; + uint32_t h4 = seed; + + const uint32_t c1 = 0x239b961b; + const uint32_t c2 = 0xab0e9789; + const uint32_t c3 = 0x38b34ae5; + const uint32_t c4 = 0xa1e38b93; + + //---------- + // body + + const uint32_t* blocks = (const uint32_t*)(data + nblocks * 16); + + for(int i = -nblocks; i; i++) + { + uint32_t k1 = getblock32(blocks, i * 4 + 0); + uint32_t k2 = getblock32(blocks, i * 4 + 1); + uint32_t k3 = getblock32(blocks, i * 4 + 2); + uint32_t k4 = getblock32(blocks, i * 4 + 3); + + k1 *= c1; + k1 = ROTL32(k1, 15); + k1 *= c2; + h1 ^= k1; + + h1 = ROTL32(h1, 19); + h1 += h2; + h1 = h1 * 5 + 0x561ccd1b; + + k2 *= c2; + k2 = ROTL32(k2, 16); + k2 *= c3; + h2 ^= k2; + + h2 = ROTL32(h2, 17); + h2 += h3; + h2 = h2 * 5 + 0x0bcaa747; + + k3 *= c3; + k3 = ROTL32(k3, 17); + k3 *= c4; + h3 ^= k3; + + h3 = ROTL32(h3, 15); + h3 += h4; + h3 = h3 * 5 + 0x96cd1c35; + + k4 *= c4; + k4 = ROTL32(k4, 18); + k4 *= c1; + h4 ^= k4; + + h4 = ROTL32(h4, 13); + h4 += h1; + h4 = h4 * 5 + 0x32ac3b17; + } + + //---------- + // tail + + const uint8_t* tail = (const uint8_t*)(data + nblocks * 16); + + uint32_t k1 = 0; + uint32_t k2 = 0; + uint32_t k3 = 0; + uint32_t k4 = 0; + + switch(len & 15) + { + case 15: + k4 ^= tail[14] << 16; + case 14: + k4 ^= tail[13] << 8; + case 13: + k4 ^= tail[12] << 0; + k4 *= c4; + k4 = ROTL32(k4, 18); + k4 *= c1; + h4 ^= k4; + + case 12: + k3 ^= tail[11] << 24; + case 11: + k3 ^= tail[10] << 16; + case 10: + k3 ^= tail[9] << 8; + case 9: + k3 ^= tail[8] << 0; + k3 *= c3; + k3 = ROTL32(k3, 17); + k3 *= c4; + h3 ^= k3; + + case 8: + k2 ^= tail[7] << 24; + case 7: + k2 ^= tail[6] << 16; + case 6: + k2 ^= tail[5] << 8; + case 5: + k2 ^= tail[4] << 0; + k2 *= c2; + k2 = ROTL32(k2, 16); + k2 *= c3; + h2 ^= k2; + + case 4: + k1 ^= tail[3] << 24; + case 3: + k1 ^= tail[2] << 16; + case 2: + k1 ^= tail[1] << 8; + case 1: + k1 ^= tail[0] << 0; + k1 *= c1; + k1 = ROTL32(k1, 15); + k1 *= c2; + h1 ^= k1; + }; + + //---------- + // finalization + + h1 ^= len; + h2 ^= len; + h3 ^= len; + h4 ^= len; + + h1 += h2; + h1 += h3; + h1 += h4; + h2 += h1; + h3 += h1; + h4 += h1; + + h1 = fmix32(h1); + h2 = fmix32(h2); + h3 = fmix32(h3); + h4 = fmix32(h4); + + h1 += h2; + h1 += h3; + h1 += h4; + h2 += h1; + h3 += h1; + h4 += h1; + + ((uint32_t*)out)[0] = h1; + ((uint32_t*)out)[1] = h2; + ((uint32_t*)out)[2] = h3; + ((uint32_t*)out)[3] = h4; +} + +//----------------------------------------------------------------------------- + +void MurmurHash3_x64_128(const void* key, const int len, const uint32_t seed, void* out) +{ + const uint8_t* data = (const uint8_t*)key; + const int nblocks = len / 16; + + uint64_t h1 = seed; + uint64_t h2 = seed; + + const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5); + const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f); + + //---------- + // body + + const uint64_t* blocks = (const uint64_t*)(data); + + for(int i = 0; i < nblocks; i++) + { + uint64_t k1 = getblock64(blocks, i * 2 + 0); + uint64_t k2 = getblock64(blocks, i * 2 + 1); + + k1 *= c1; + k1 = ROTL64(k1, 31); + k1 *= c2; + h1 ^= k1; + + h1 = ROTL64(h1, 27); + h1 += h2; + h1 = h1 * 5 + 0x52dce729; + + k2 *= c2; + k2 = ROTL64(k2, 33); + k2 *= c1; + h2 ^= k2; + + h2 = ROTL64(h2, 31); + h2 += h1; + h2 = h2 * 5 + 0x38495ab5; + } + + //---------- + // tail + + const uint8_t* tail = (const uint8_t*)(data + nblocks * 16); + + uint64_t k1 = 0; + uint64_t k2 = 0; + + switch(len & 15) + { + case 15: + k2 ^= ((uint64_t)tail[14]) << 48; + case 14: + k2 ^= ((uint64_t)tail[13]) << 40; + case 13: + k2 ^= ((uint64_t)tail[12]) << 32; + case 12: + k2 ^= ((uint64_t)tail[11]) << 24; + case 11: + k2 ^= ((uint64_t)tail[10]) << 16; + case 10: + k2 ^= ((uint64_t)tail[9]) << 8; + case 9: + k2 ^= ((uint64_t)tail[8]) << 0; + k2 *= c2; + k2 = ROTL64(k2, 33); + k2 *= c1; + h2 ^= k2; + + case 8: + k1 ^= ((uint64_t)tail[7]) << 56; + case 7: + k1 ^= ((uint64_t)tail[6]) << 48; + case 6: + k1 ^= ((uint64_t)tail[5]) << 40; + case 5: + k1 ^= ((uint64_t)tail[4]) << 32; + case 4: + k1 ^= ((uint64_t)tail[3]) << 24; + case 3: + k1 ^= ((uint64_t)tail[2]) << 16; + case 2: + k1 ^= ((uint64_t)tail[1]) << 8; + case 1: + k1 ^= ((uint64_t)tail[0]) << 0; + k1 *= c1; + k1 = ROTL64(k1, 31); + k1 *= c2; + h1 ^= k1; + }; + + //---------- + // finalization + + h1 ^= len; + h2 ^= len; + + h1 += h2; + h2 += h1; + + h1 = fmix64(h1); + h2 = fmix64(h2); + + h1 += h2; + h2 += h1; + + ((uint64_t*)out)[0] = h1; + ((uint64_t*)out)[1] = h2; +} + +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/bloom/murmur3/MurmurHash3.h b/bloom/murmur3/MurmurHash3.h new file mode 100644 index 0000000..599f218 --- /dev/null +++ b/bloom/murmur3/MurmurHash3.h @@ -0,0 +1,37 @@ +//----------------------------------------------------------------------------- +// MurmurHash3 was written by Austin Appleby, and is placed in the public +// domain. The author hereby disclaims copyright to this source code. + +#ifndef _MURMURHASH3_H_ +#define _MURMURHASH3_H_ + +//----------------------------------------------------------------------------- +// Platform-specific functions and macros + +// Microsoft Visual Studio + +#if defined(_MSC_VER) && (_MSC_VER < 1600) + +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; + +// Other compilers + +#else // defined(_MSC_VER) + +#include + +#endif // !defined(_MSC_VER) + +//----------------------------------------------------------------------------- + +void MurmurHash3_x86_32(const void* key, int len, uint32_t seed, void* out); + +void MurmurHash3_x86_128(const void* key, int len, uint32_t seed, void* out); + +void MurmurHash3_x64_128(const void* key, int len, uint32_t seed, void* out); + +//----------------------------------------------------------------------------- + +#endif // _MURMURHASH3_H_ \ No newline at end of file diff --git a/cfg/hash.h b/cfg/hash.h index 99e0237..a996d7b 100644 --- a/cfg/hash.h +++ b/cfg/hash.h @@ -47,19 +47,19 @@ namespace nm } switch(size) { - case 3: - h ^= static_cast(data[2]) << 16; + case 3: + h ^= static_cast(data[2]) << 16; #if __cplusplus >= 201703 - [[fallthrough]]; + [[fallthrough]]; #endif - case 2: - h ^= static_cast(data[1]) << 8; -#if __cplusplus >=201703 - [[fallthrough]]; + case 2: + h ^= static_cast(data[1]) << 8; +#if __cplusplus >= 201703 + [[fallthrough]]; #endif - case 1: - h ^= static_cast(data[0]); - h *= m; + case 1: + h ^= static_cast(data[0]); + h *= m; } h ^= h >> 13; h *= m; @@ -68,228 +68,208 @@ namespace nm } class HashTable { - private: - struct node + private: + struct node + { + std::string key; + std::string value; + uint32_t hash; + int dup_count; + node* next; + node* sibling; + node() : key(), value(), hash(), dup_count(0), next(nullptr), sibling(nullptr) {} + node(const std::string& k, const std::string& o, uint32_t h) + : key(k), value(o), hash(h), dup_count(0), next(nullptr), sibling(nullptr) { - std::string key; - std::string value; - uint32_t hash; - int dup_count; - node* next; - node* sibling; - node() - :key(), value(), hash(), dup_count(0), - next(nullptr), sibling(nullptr){} - node(const std::string& k, const std::string& o, uint32_t h) - :key(k), value(o), hash(h), dup_count(0), - next(nullptr), sibling(nullptr){} - }; + } + }; + + public: + class iterator + { + private: + node* root; + public: - class iterator + iterator() : root(nullptr) {} + iterator(node* n) : root(n) {} + iterator(const iterator& rhs) { *this = rhs; } + ~iterator() {} + iterator& operator=(const iterator& rhs) { - private: - node* root; - public: - iterator(): root(nullptr){} - iterator(node* n): root(n){} - iterator(const iterator& rhs) - { - *this = rhs; - } - ~iterator(){} - iterator& operator= (const iterator& rhs) - { - root = rhs.root; - return *this; - } - iterator& operator++() - { - root = root->sibling; - return *this; - } - iterator operator++(int) - { - auto tmp = *this; - ++(*this); - return tmp; - } - node& operator* () - { - return *root; - } - node* operator-> () - { - return root; - } - bool is_valid() - { - return root != nullptr; - } - }; - HashTable(): allow_multi_(false), size_(0), limit_(0), list_(nullptr) + root = rhs.root; + return *this; + } + iterator& operator++() { - resize_(); + root = root->sibling; + return *this; } - HashTable(bool allow_multi) - : allow_multi_(allow_multi), size_(0), limit_(0), list_(nullptr) + iterator operator++(int) { - resize_(); + auto tmp = *this; + ++(*this); + return tmp; } - ~HashTable() + node& operator*() { return *root; } + node* operator->() { return root; } + bool is_valid() { return root != nullptr; } + }; + HashTable() : allow_multi_(false), size_(0), limit_(0), list_(nullptr) { resize_(); } + HashTable(bool allow_multi) : allow_multi_(allow_multi), size_(0), limit_(0), list_(nullptr) { resize_(); } + ~HashTable() + { + for(uint32_t i = 0; i < limit_; ++i) { - for(uint32_t i = 0; i < limit_; ++i) + node* ptr = list_[i]; + while(ptr != nullptr) { - node* ptr = list_[i]; - while(ptr != nullptr) + node* tmp = ptr->next; + if(ptr->sibling) { - node* tmp = ptr->next; - if(ptr->sibling) + auto root = ptr->sibling; + while(root != nullptr) { - auto root = ptr->sibling; - while(root != nullptr) - { - auto nxt = root->sibling; - delete root; - root = nxt; - } + auto nxt = root->sibling; + delete root; + root = nxt; } - delete ptr; - ptr = tmp; } + delete ptr; + ptr = tmp; } - delete [] list_; } - uint32_t insert(const std::string& key, const std::string& obj) + delete[] list_; + } + uint32_t insert(const std::string& key, const std::string& obj) + { + bool is_new_entery = true; + uint32_t h = murmurhash2(key.data(), key.size(), 0); + node** ptr = find_(key, h); + node* old = *ptr; + node* item = new node(key, obj, h); + if(old != nullptr) // key already in table, replace with new item { - bool is_new_entery = true; - uint32_t h = murmurhash2(key.data(), key.size(), 0); - node** ptr = find_(key, h); - node* old = *ptr; - node* item = new node(key, obj, h); - if(old != nullptr) // key already in table, replace with new item + if(allow_multi_) { - if(allow_multi_) - { - item->sibling = old->sibling; - old->sibling = item; - old->dup_count += 1; - return h; // insert finished - } - else - { - is_new_entery = false; - node* tmp = old; - old = tmp->next; - delete tmp; - tmp = nullptr; - } + item->sibling = old->sibling; + old->sibling = item; + old->dup_count += 1; + return h; // insert finished } - item->next = (old == nullptr ? nullptr : old->next); - *ptr = item; - if(old == nullptr) + else { - if(is_new_entery) - ++size_; - if(size_ > limit_) - resize_(); + is_new_entery = false; + node* tmp = old; + old = tmp->next; + delete tmp; + tmp = nullptr; } - return h; } - void remove(const std::string& key, uint32_t hash) + item->next = (old == nullptr ? nullptr : old->next); + *ptr = item; + if(old == nullptr) { - node** ptr = find_(key, hash); - node* res = *ptr; - if(res != nullptr) - { - if(res->sibling != nullptr) - { - node* nxt = res->sibling->sibling; - delete res->sibling; - res->sibling = nxt; - res->dup_count -= 1; - } - else - { - *ptr = res->next; - --size_; - delete res; - res = nullptr; - } - } + if(is_new_entery) + ++size_; + if(size_ > limit_) + resize_(); } - void remove_all(const std::string& key, uint32_t hash) + return h; + } + void remove(const std::string& key, uint32_t hash) + { + node** ptr = find_(key, hash); + node* res = *ptr; + if(res != nullptr) { - node** ptr = find_(key, hash); - node* res = *ptr; - if(res != nullptr) + if(res->sibling != nullptr) + { + node* nxt = res->sibling->sibling; + delete res->sibling; + res->sibling = nxt; + res->dup_count -= 1; + } + else { - if(res->sibling != nullptr) - { - node* root = res->sibling; - while(root != nullptr) - { - node* nxt = root->sibling; - delete root; - root = nxt; - res->dup_count -= 1; - } - } *ptr = res->next; --size_; delete res; res = nullptr; } } - iterator search(const std::string& key, uint32_t hash) - { - return iterator(*find_(key, hash)); - } - iterator search(const std::string& key) - { - uint32_t hash = murmurhash2(key.data(), key.size(), 0); - return iterator(this->search(key, hash)); - } - private: - bool allow_multi_; - uint32_t size_; - uint32_t limit_; - node** list_; - void resize_() + } + void remove_all(const std::string& key, uint32_t hash) + { + node** ptr = find_(key, hash); + node* res = *ptr; + if(res != nullptr) { - uint32_t new_len = 4; - while(new_len < size_) - new_len *= 2; - node** new_list = new node*[new_len]; - std::memset(new_list, 0, sizeof(new_list[0]) * new_len); - uint32_t count = 0; - for(uint32_t i = 0; i < limit_; ++i) + if(res->sibling != nullptr) { - node* h = list_[i]; - while(h != nullptr) + node* root = res->sibling; + while(root != nullptr) { - node* next = h->next; - uint32_t hash = h->hash; - node** ptr = &new_list[hash & (new_len - 1)]; - h->next = *ptr; - *ptr = h; - h = next; - count += 1; + node* nxt = root->sibling; + delete root; + root = nxt; + res->dup_count -= 1; } } - assert(size_ == count); - delete [] list_; - list_ = new_list; - limit_ = new_len; + *ptr = res->next; + --size_; + delete res; + res = nullptr; } - node** find_(const std::string& key, uint32_t hash) + } + iterator search(const std::string& key, uint32_t hash) { return iterator(*find_(key, hash)); } + iterator search(const std::string& key) + { + uint32_t hash = murmurhash2(key.data(), key.size(), 0); + return iterator(this->search(key, hash)); + } + + private: + bool allow_multi_; + uint32_t size_; + uint32_t limit_; + node** list_; + void resize_() + { + uint32_t new_len = 4; + while(new_len < size_) + new_len *= 2; + node** new_list = new node*[new_len]; + std::memset(new_list, 0, sizeof(new_list[0]) * new_len); + uint32_t count = 0; + for(uint32_t i = 0; i < limit_; ++i) { - node** ptr = &list_[hash & (limit_ - 1)]; - while(*ptr != nullptr && ((*ptr)->hash != hash || key != (*ptr)->key)) + node* h = list_[i]; + while(h != nullptr) { - ptr = &(*ptr)->next; + node* next = h->next; + uint32_t hash = h->hash; + node** ptr = &new_list[hash & (new_len - 1)]; + h->next = *ptr; + *ptr = h; + h = next; + count += 1; } - return ptr; } + assert(size_ == count); + delete[] list_; + list_ = new_list; + limit_ = new_len; + } + node** find_(const std::string& key, uint32_t hash) + { + node** ptr = &list_[hash & (limit_ - 1)]; + while(*ptr != nullptr && ((*ptr)->hash != hash || key != (*ptr)->key)) + { + ptr = &(*ptr)->next; + } + return ptr; + } }; } } diff --git a/channel/channel.h b/channel/channel.h index 3f4c87d..e10accf 100644 --- a/channel/channel.h +++ b/channel/channel.h @@ -15,11 +15,16 @@ #include class SpinLock; -template class Guard; -template class Queue; -template class Sender; -template class Receiver; -template std::tuple, Receiver> channel(); +template +class Guard; +template +class Queue; +template +class Sender; +template +class Receiver; +template +std::tuple, Receiver> channel(); // -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free #ifdef TBB_ALLOC // -ltbbmalloc @@ -31,10 +36,7 @@ T* alloc() return static_cast(scalable_malloc(sizeof(T))); } -void dealloc(void* x) -{ - scalable_free(x); -} +void dealloc(void* x) { scalable_free(x); } #elif defined(JEMALLOC) // -ljemalloc #include template @@ -43,10 +45,7 @@ T* alloc() return static_cast(malloc(sizeof(T))); } -void dealloc(void *x) -{ - free(x); -} +void dealloc(void* x) { free(x); } #else template T* alloc() @@ -63,151 +62,127 @@ void dealloc(T* x) #ifdef SPIN using Mutex = SpinLock; -template using LockGuard = Guard; +template +using LockGuard = Guard; using CondVar = std::condition_variable_any; #else using Mutex = std::mutex; -template using LockGuard = std::unique_lock; +template +using LockGuard = std::unique_lock; using CondVar = std::condition_variable; #endif #ifdef TBB_QUEUE #include -template using Queue_t = tbb::concurrent_queue; +template +using Queue_t = tbb::concurrent_queue; #else -template using Queue_t = Queue; +template +using Queue_t = Queue; #endif class SpinLock { - public: - SpinLock() - : flag_{ 0 } - {} +public: + SpinLock() : flag_{0} {} - ~SpinLock() - { - flag_.clear(std::memory_order_release); - } + ~SpinLock() { flag_.clear(std::memory_order_release); } - void try_lock() - { - flag_.test_and_set(std::memory_order_acquire); - } + void try_lock() { flag_.test_and_set(std::memory_order_acquire); } - void lock() - { - while(!flag_.test_and_set(std::memory_order_acquire)); - } + void lock() + { + while(!flag_.test_and_set(std::memory_order_acquire)) + ; + } - void unlock() - { - flag_.clear(std::memory_order_release); - } + void unlock() { flag_.clear(std::memory_order_release); } - private: - std::atomic_flag flag_; +private: + std::atomic_flag flag_; }; template class Guard { - public: - Guard(T& lk) - : lk_(lk) - {} +public: + Guard(T& lk) : lk_(lk) {} - ~Guard() - { - lk_.unlock(); - } + ~Guard() { lk_.unlock(); } - void lock() - { - lk_.lock(); - } + void lock() { lk_.lock(); } - void unlock() - { - lk_.unlock(); - } - private: - T& lk_; + void unlock() { lk_.unlock(); } + +private: + T& lk_; }; template class Queue { - private: - struct Node - { - T data; - std::atomic next; - }; - - public: - Queue() - : head_(alloc()), - tail_(head_.load()) - { - auto tmp = head_.load(); - tmp->next.store(nullptr); - } - - ~Queue() - { - this->clear(); - } - - void clear() - { - Node* tmp = nullptr; - while(tail_) - { - tmp = tail_->next.load(); - dealloc(tail_); - tail_ = tmp; - } - tail_ = nullptr; - } - - bool empty() const - { - return tail_->next.load(std::memory_order_acquire) == nullptr; - } - - void push(const T& data) - { - auto tmp = alloc(); - tmp->data = data; - tmp->next.store(nullptr, std::memory_order_relaxed); - auto old_head = head_.exchange(tmp, std::memory_order_acq_rel); - old_head->next.store(tmp, std::memory_order_release); - } - - void push(T&& data) +private: + struct Node + { + T data; + std::atomic next; + }; + +public: + Queue() : head_(alloc()), tail_(head_.load()) + { + auto tmp = head_.load(); + tmp->next.store(nullptr); + } + + ~Queue() { this->clear(); } + + void clear() + { + Node* tmp = nullptr; + while(tail_) { - auto tmp = alloc(); - tmp->data = std::move(data); - tmp->next.store(nullptr, std::memory_order_relaxed); - auto old_head = head_.exchange(tmp, std::memory_order_acq_rel); - old_head->next.store(tmp, std::memory_order_release); - } - - bool try_pop(T& data) - { - auto next = tail_->next.load(std::memory_order_acquire); - if(next == nullptr) - return false; - data = std::move(next->data); + tmp = tail_->next.load(); dealloc(tail_); - tail_ = next; - return true; + tail_ = tmp; } - - private: - std::atomic head_; - Node* tail_; + tail_ = nullptr; + } + + bool empty() const { return tail_->next.load(std::memory_order_acquire) == nullptr; } + + void push(const T& data) + { + auto tmp = alloc(); + tmp->data = data; + tmp->next.store(nullptr, std::memory_order_relaxed); + auto old_head = head_.exchange(tmp, std::memory_order_acq_rel); + old_head->next.store(tmp, std::memory_order_release); + } + + void push(T&& data) + { + auto tmp = alloc(); + tmp->data = std::move(data); + tmp->next.store(nullptr, std::memory_order_relaxed); + auto old_head = head_.exchange(tmp, std::memory_order_acq_rel); + old_head->next.store(tmp, std::memory_order_release); + } + + bool try_pop(T& data) + { + auto next = tail_->next.load(std::memory_order_acquire); + if(next == nullptr) + return false; + data = std::move(next->data); + dealloc(tail_); + tail_ = next; + return true; + } + +private: + std::atomic head_; + Node* tail_; }; // tbbmalloc + spinlock > jemalloc + spinlock > glibc malloc + spinlock @@ -215,175 +190,149 @@ class Queue template class ReceiverImpl { - private: - ReceiverImpl() = default; +private: + ReceiverImpl() = default; - public: - template friend std::tuple, Receiver> channel(); +public: + template + friend std::tuple, Receiver> channel(); - ReceiverImpl(const ReceiverImpl&) = delete; + ReceiverImpl(const ReceiverImpl&) = delete; - ReceiverImpl& operator= (const ReceiverImpl&) = delete; + ReceiverImpl& operator=(const ReceiverImpl&) = delete; - ReceiverImpl(ReceiverImpl&& rhs) = delete; + ReceiverImpl(ReceiverImpl&& rhs) = delete; - ~ReceiverImpl() = default; + ~ReceiverImpl() = default; - void send(const T& data) + void send(const T& data) + { + queue_.push(data); + if(!state_) { - queue_.push(data); - if(!state_) - { - cond_.notify_one(); - } + cond_.notify_one(); } + } - void send(T&& data) + void send(T&& data) + { + queue_.push(std::move(data)); + if(!state_) { - queue_.push(std::move(data)); - if(!state_) - { - cond_.notify_one(); - } + cond_.notify_one(); } + } - bool try_recv(T& data) - { - return queue_.try_pop(data); - } + bool try_recv(T& data) { return queue_.try_pop(data); } - void recv(T& data) + void recv(T& data) + { + for(;;) { - for(;;) + if(!state_) { - if(!state_) - { - LockGuard lk(mtx_); - cond_.wait(lk, [this] { - return !queue_.empty(); - }); - } - if(queue_.try_pop(data)) - { - state_ = true; - break; - } - state_ = false; + LockGuard lk(mtx_); + cond_.wait(lk, [this] { return !queue_.empty(); }); } + if(queue_.try_pop(data)) + { + state_ = true; + break; + } + state_ = false; } - - template - bool recv_timeout(T& data, const std::chrono::duration& timeout) - { - LockGuard lk(mtx_); - cond_.wait_for(lk, timeout, [this] { - return !queue_.empty(); - }); - return queue_.try_pop(data); - } - - private: - Queue_t queue_; - Mutex mtx_; - CondVar cond_; - bool state_{false}; + } + + template + bool recv_timeout(T& data, const std::chrono::duration& timeout) + { + LockGuard lk(mtx_); + cond_.wait_for(lk, timeout, [this] { return !queue_.empty(); }); + return queue_.try_pop(data); + } + +private: + Queue_t queue_; + Mutex mtx_; + CondVar cond_; + bool state_{false}; }; template class Sender { - public: - template friend std::tuple, Receiver> channel(); +public: + template + friend std::tuple, Receiver> channel(); - Sender(Sender&& rhs) - { - sender_ = rhs.sender_; - rhs.sender_.reset(); - } + Sender(Sender&& rhs) + { + sender_ = rhs.sender_; + rhs.sender_.reset(); + } - ~Sender() = default; + ~Sender() = default; - void send(const T& data) - { - sender_->send(data); - } + void send(const T& data) { sender_->send(data); } - void send(T&& data) - { - sender_->send(std::move(data)); - } + void send(T&& data) { sender_->send(std::move(data)); } - Sender clone() - { - return *this; - } + Sender clone() { return *this; } - private: - Sender(std::shared_ptr> recv) - : sender_(recv) - {} +private: + Sender(std::shared_ptr> recv) : sender_(recv) {} - Sender(const Sender& rhs) + Sender(const Sender& rhs) + { + if(this != &rhs) { - if(this != &rhs) - { - sender_ = rhs.sender_; - } + sender_ = rhs.sender_; } + } - Sender& operator= (const Sender&) = delete; + Sender& operator=(const Sender&) = delete; - std::shared_ptr> sender_; + std::shared_ptr> sender_; }; template class Receiver { - public: - template friend std::tuple, Receiver> channel(); +public: + template + friend std::tuple, Receiver> channel(); - Receiver(Receiver&& rhs) + Receiver(Receiver&& rhs) + { + if(this != &rhs) { - if(this != &rhs) - { - recv_ = rhs.recv_; - rhs.recv_.reset(); - } + recv_ = rhs.recv_; + rhs.recv_.reset(); } + } - ~Receiver() = default; + ~Receiver() = default; - void recv(T& data) - { - recv_->recv(data); - } + void recv(T& data) { recv_->recv(data); } - bool try_recv(T& data) - { - return recv_->try_recv(data); - } + bool try_recv(T& data) { return recv_->try_recv(data); } - template - bool recv_timeout(T& data, const std::chrono::duration& timeout) - { - return recv_->recv_timeout(data, timeout); - } + template + bool recv_timeout(T& data, const std::chrono::duration& timeout) + { + return recv_->recv_timeout(data, timeout); + } - private: - Receiver(ReceiverImpl* recv) - : recv_(recv) - {} +private: + Receiver(ReceiverImpl* recv) : recv_(recv) {} - Receiver(const Receiver&) = delete; + Receiver(const Receiver&) = delete; - Receiver& operator= (const Receiver&) = delete; + Receiver& operator=(const Receiver&) = delete; - std::shared_ptr> get() - { - return recv_; - } + std::shared_ptr> get() { return recv_; } - std::shared_ptr> recv_; + std::shared_ptr> recv_; }; template diff --git a/channel/test.cpp b/channel/test.cpp index f3bdf14..e4b1802 100644 --- a/channel/test.cpp +++ b/channel/test.cpp @@ -14,7 +14,7 @@ void sender(Sender tx, size_t data, size_t limit) { - for (; limit > 0;) + for(; limit > 0;) { limit -= 1; tx.send(data); @@ -39,10 +39,7 @@ void receiver(Receiver rx) printf("receiver done.\n"); } -auto now() -{ - return std::chrono::high_resolution_clock::now(); -} +auto now() { return std::chrono::high_resolution_clock::now(); } template // no GNU extension. auto duration(const T& dur) @@ -71,7 +68,7 @@ int main(int argc, char* argv[]) pool.emplace_back(sender, tx.clone(), i, num); } - for(auto& x : pool) + for(auto& x: pool) x.join(); tx.send(309); rcv.join(); diff --git a/clp/README.md b/clp/README.md deleted file mode 100644 index 330668f..0000000 --- a/clp/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# A toy command line parser - -Some C++17's features are list below: - - - std::optional - - if constexpr - - guaranteed copy elision - - if init - - -for `std::optional`, see this example: -```c++ -#include -#include - -using namespace std; - -int bar(int x) -{ - if(x != 0) - return x; - return {}; -} - -optional foo(int x) -{ - return {bar(x)}; -} - -int main() -{ - if(foo(0)) - cout << "oops!\n"; -} -``` -this program will print `oops!`. in this scenario, `std::pair` is a better choice. - -**NOTE:** GCC 7 is required! diff --git a/clp/clp.h b/clp/clp.h deleted file mode 100644 index f7f1c1a..0000000 --- a/clp/clp.h +++ /dev/null @@ -1,282 +0,0 @@ -/********************************************************* - File Name:clp.h - Author: Abby Cin - Mail: abbytsing@gmail.com - Created Time: Wed 29 Mar 2017 07:03:38 PM CST -**********************************************************/ - -#ifndef CLP_H_ -#define CLP_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace nm -{ - class Clp - { - template struct strict_same - { - constexpr static bool value = false; - }; - template struct strict_same - { - constexpr static bool value = true; - }; - - public: - enum Option - { - SHORT = 1, - LONG = 2, - ALL = 3 - }; - - Clp(int argc, char* argv[]) noexcept - : map_{}, cmd_{}, c_{} - { - for(int i = 1; i < argc; ++i) - cmd_.emplace_back(argv[i]); - } - - Clp(const std::string& path) - : map_{}, cmd_{}, none_{}, c_{}, msg_{} - { - errno = 0; - std::ifstream in(path); - if(in.is_open()) - { - string_ext line{}; - while(std::getline(in, line)) - { - if(line.empty()) - continue; - line.lstrip(); - if(!line.empty() && line[0] == '#') - continue; - line.split(cmd_, " "); - } - for(auto& x: cmd_) - { - x.strip(); - } - in.close(); - return; - } - msg_ = path + ' '; - msg_ += strerror(errno); - } - - Clp(const Clp&) = delete; - - Clp(Clp&& rhs) noexcept - : map_{std::move(rhs.map_)}, - cmd_{std::move(rhs.cmd_)}, - none_{std::move(rhs.none_)}, - c_{std::move(rhs.c_)}, - msg_{std::move(rhs.msg_)} - {} - - Clp& operator= (const Clp&) = delete; - - ~Clp() noexcept {} - - Clp& parse(Option op) - { - if(!msg_.empty()) - return *this; - msg_.clear(); - switch(op) - { - case Option::SHORT: - parse("-"); - break; - case Option::LONG: - parse("--"); - break; - case Option::ALL: - parse("-"); - parse("--"); - break; - } - return *this; - } - - bool ok() const noexcept - { - return msg_.empty(); - } - - const std::string& msg() const noexcept - { - return msg_; - } - - // implicitly construct optional. - template - std::optional get(const std::string& key) noexcept - { - static_assert( - strict_same::value || - strict_same::value || - strict_same::value || - strict_same::value || - strict_same::value || - strict_same::value || - strict_same::value || - strict_same::value || - strict_same::value || - strict_same::value || - strict_same::value, - "\ntypename must be:\n" - "boolean type,\n" - "int type (signed or unsigned),\n" - "float type,\n" - "string type,\n" - "WITH NO CV QUALIFIER."); - - msg_.clear(); - auto iter = map_.find(key); - if(iter == map_.end()) - { - msg_ = "no `" + key + "` in argument list"; - return {}; - } - if constexpr(strict_same::value) - { - if(iter->second == "true") - return true; - else if(iter->second == "false") - return false; - else - msg_ = "invalid argument"; - return {}; - } - else if constexpr(strict_same::value) - { - return iter->second; - } - else - { - T res = get_value(iter->second); - if(ok()) - return res; - return {}; - } - } - - const std::set& none() const noexcept - { - return none_; - } - - bool contain(const std::string& key) const noexcept - { - return c_.find(key) != c_.end(); - } - - private: - std::unordered_map map_; - std::list cmd_; - std::set none_; - std::set c_; - std::string msg_; - - void parse(const std::string& delim) - { - std::string tmp{}; - bool has_key{false}; - msg_ = "invalid option"; - for(auto iter = cmd_.begin(); iter != cmd_.end(); ++iter) - { - has_key = false; - if(*iter == "-") - { - return; - } - // get key - if(iter->find(delim) != iter->npos && *iter != "--") - { - tmp = iter->substr(delim.length()); - has_key = true; - ++iter; - } - if(iter == cmd_.end()) - { - c_.emplace(tmp); - break; - } - else if(*iter == "-") - { - return; - } - // get escape - if(*iter == "--") - { - if(!has_key) - { - return; - } - if(++iter != cmd_.end()) - { - map_.insert({tmp, *iter}); - c_.emplace(tmp); - } - else - { - // treat as single option - c_.emplace(tmp); - break; - } - } - // no value - else if(iter->find(delim) < delim.size()) - { - --iter; - c_.emplace(tmp); - } - else if(has_key) - { - map_.insert({tmp, *iter}); - c_.emplace(tmp); - } - else - { - none_.emplace(*iter); - } - } - msg_.clear(); - } - - template - T get_value(const std::string& str) noexcept - { - try - { - if constexpr(std::is_floating_point::value) - return static_cast(std::stold(str)); - else if constexpr(std::is_signed::value) - return static_cast(std::stoll(str)); - else - return static_cast(std::stoull(str)); - } - catch(const std::out_of_range&) - { - msg_ = "error: out of range"; - } - catch(const std::invalid_argument&) - { - msg_ = "error: invalid argument"; - } - return {}; - } - }; -} - -#endif // CLP_H_ diff --git a/clp/test.cpp b/clp/test.cpp deleted file mode 100644 index d56bc24..0000000 --- a/clp/test.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/********************************************************* - File Name:test.cpp - Author: Abby Cin - Mail: abbytsing@gmail.com - Created Time: Wed 29 Mar 2017 08:34:26 PM CST -**********************************************************/ - -#include -#include "clp.h" - -using namespace nm; -using namespace std; - -int main(int argc, char* argv[]) -{ - Clp clpl{argc, argv}; - clpl.parse(Clp::ALL); - auto clp = std::move(clpl); - if(!clp.ok()) - { - cout << clp.msg() << endl; - return 1; - } - if(clp.contain("help") || clp.contain("h")) - { - cout << argv[0] << " -key value ...\n"; - cout << "\t-name name [--name]\n"; - cout << "\t-age age [--age]\n"; - cout << "\t-height height [--height]\n"; - return 1; - } - if(auto n = clp.get("name"); n) - cout << "name: " << n.value() << endl; - else - cout << clp.msg() << endl; - if(auto a = clp.get("age"); a) - cout << "age: " << a.value() << endl; - else - cout << clp.msg() << endl; - if(auto h = clp.get("height"); h) - cout << "height: " << h.value() << endl; - else - cout << clp.msg() << endl; - if(auto es = clp.get("es"); es) - cout << "escape: " << es.value() << endl; - else - cout << clp.msg() << endl; - if(clp.contain("es")) - cout << "found option `es`\n"; - auto none = clp.none(); - if(!none.empty()) - { - cout << "none:\n"; - for(auto&x: clp.none()) - cout << x << endl; - } -} diff --git a/coroutine/README.md b/coroutine/README.md index b2b5fbc..2728dbc 100644 --- a/coroutine/README.md +++ b/coroutine/README.md @@ -28,7 +28,7 @@ cmake --build . ### Doc -Please go to my [blog post](https://note.isliberty.me/2018/06/02/a-coroutine-impl/) +Please go to my [blog post](https://blog.isliberty.me/article/61) ### Bugs diff --git a/coroutine/coroutine.h b/coroutine/coroutine.h index f62aa12..efbc1da 100644 --- a/coroutine/coroutine.h +++ b/coroutine/coroutine.h @@ -15,11 +15,13 @@ namespace nm { - extern "C" { + extern "C" + { void* switch_stack(void* obj, void* context, void* arg); } - template class Coroutine; + template + class Coroutine; template void co_call_member_function(Coroutine* obj, void* ctx); @@ -27,173 +29,149 @@ namespace nm template class Coroutine { - public: - template - friend void co_call_member_function(Coroutine*, void*); + public: + template + friend void co_call_member_function(Coroutine*, void*); - enum { Fixed_Stack_Size = 8 * 1024}; + enum + { + Fixed_Stack_Size = 8 * 1024 + }; - class Iterator - { - template friend class Coroutine; - public: - ~Iterator() {} - - Iterator(const Iterator&) = delete; - Iterator& operator= (const Iterator&) = delete; - - Iterator(Iterator&& rhs) - : co_{rhs.co_} - { - rhs.co_ = nullptr; - } - - Iterator& operator= (Iterator&& rhs) - { - this->co_ = rhs.co_; - rhs.co_ = nullptr; - return *this; - } - - bool operator== (const Iterator& rhs) - { - return this->co_ == rhs.co_; - } - - bool operator!= (const Iterator& rhs) - { - return this->co_ != rhs.co_; - } - - Iterator& operator++ () - { - co_->resume(); - if(co_->done()) - { - co_ = nullptr; - } - return *this; - } - - T& operator* () - { - return co_->data(); - } - - private: - Coroutine* co_; - - Iterator() - : co_{nullptr} - {} - - Iterator(Coroutine* co) - : co_{co} - {} - }; + class Iterator + { + template + friend class Coroutine; - Coroutine() = default; + public: + ~Iterator() {} - ~Coroutine() - { - free(stack_); - stack_ = nullptr; - if(deleter_) - { - deleter_(arg_); - arg_ = nullptr; - } - } + Iterator(const Iterator&) = delete; + Iterator& operator=(const Iterator&) = delete; - Coroutine(const Coroutine&) = delete; - Coroutine(Coroutine&&) = delete; - Coroutine& operator= (const Coroutine&) = delete; - Coroutine& operator= (Coroutine&&) = delete; + Iterator(Iterator&& rhs) : co_{rhs.co_} { rhs.co_ = nullptr; } - template - void start(F&& f, Args&&... args) + Iterator& operator=(Iterator&& rhs) { - this->~Coroutine(); - stack_ = malloc(Fixed_Stack_Size); - memset(stack_, 0, Fixed_Stack_Size); - // call pop in `switch_stack` will grow rsp, here I reserve 4k space for push - // and I don't check alignment, you can adjust by using std::align since C++11 - new_sp_ = (char*)stack_ + 4096; - - this->done_ = false; - using arg_t = typename meta::Inspector::arg_t; - arg_ = new arg_t{std::forward(args)...}; - deleter_ = [](void* data) { delete static_cast(data); }; - fp_ = [f = std::forward(f)](void* arg) { - arg_t* param = static_cast(arg); - std::apply(f, *param); - }; - // skip 6 registers r12~r15 and rbx rbp, assign next instruction to rip - *((void**)((char*)new_sp_ + 6 * 8)) = (void*)co_call_member_function; - new_sp_ = switch_stack(this, new_sp_, arg_); + this->co_ = rhs.co_; + rhs.co_ = nullptr; + return *this; } - void yield(const T& t) - { - data_ = t; - this->yield(); - } + bool operator==(const Iterator& rhs) { return this->co_ == rhs.co_; } - void yield() - { - new_sp_ = switch_stack(nullptr, new_sp_, nullptr); - } + bool operator!=(const Iterator& rhs) { return this->co_ != rhs.co_; } - Iterator begin() + Iterator& operator++() { - if(new_sp_) + co_->resume(); + if(co_->done()) { - this->resume(); - if(this->done()) - { - return {nullptr}; - } + co_ = nullptr; } - return {this}; + return *this; } - Iterator end() - { - return {nullptr}; - } + T& operator*() { return co_->data(); } private: - void* new_sp_{nullptr}; - void* stack_{nullptr}; - bool done_{false}; - std::function fp_; - std::function deleter_; - void* arg_{nullptr}; - std::optional data_{}; - - bool done() - { - return done_; - } + Coroutine* co_; - T& data() - { - return data_.value(); // let it throw - } + Iterator() : co_{nullptr} {} + + Iterator(Coroutine* co) : co_{co} {} + }; - void resume() + Coroutine() = default; + + ~Coroutine() + { + free(stack_); + stack_ = nullptr; + if(deleter_) { - new_sp_ = switch_stack(nullptr, new_sp_, nullptr); + deleter_(arg_); + arg_ = nullptr; } - - void agent(void* ctx) + } + + Coroutine(const Coroutine&) = delete; + Coroutine(Coroutine&&) = delete; + Coroutine& operator=(const Coroutine&) = delete; + Coroutine& operator=(Coroutine&&) = delete; + + template + void start(F&& f, Args&&... args) + { + this->~Coroutine(); + stack_ = malloc(Fixed_Stack_Size); + memset(stack_, 0, Fixed_Stack_Size); + // call pop in `switch_stack` will grow rsp, here I reserve 4k space for push + // and I don't check alignment, you can adjust by using std::align since C++11 + new_sp_ = (char*)stack_ + 4096; + + this->done_ = false; + using arg_t = typename meta::Inspector::arg_t; + arg_ = new arg_t{std::forward(args)...}; + deleter_ = [](void* data) { delete static_cast(data); }; + fp_ = [f = std::forward(f)](void* arg) { + arg_t* param = static_cast(arg); + std::apply(f, *param); + }; + // skip 6 registers r12~r15 and rbx rbp, assign next instruction to rip + *((void**)((char*)new_sp_ + 6 * 8)) = (void*)co_call_member_function; + new_sp_ = switch_stack(this, new_sp_, arg_); + } + + void yield(const T& t) + { + data_ = t; + this->yield(); + } + + void yield() { new_sp_ = switch_stack(nullptr, new_sp_, nullptr); } + + Iterator begin() + { + if(new_sp_) { - new_sp_ = switch_stack(nullptr, ctx, nullptr); - fp_(arg_); - done_ = true; - data_.reset(); - this->yield(); + this->resume(); + if(this->done()) + { + return {nullptr}; + } } + return {this}; + } + + Iterator end() { return {nullptr}; } + + private: + void* new_sp_{nullptr}; + void* stack_{nullptr}; + bool done_{false}; + std::function fp_; + std::function deleter_; + void* arg_{nullptr}; + std::optional data_{}; + + bool done() { return done_; } + + T& data() + { + return data_.value(); // let it throw + } + + void resume() { new_sp_ = switch_stack(nullptr, new_sp_, nullptr); } + + void agent(void* ctx) + { + new_sp_ = switch_stack(nullptr, ctx, nullptr); + fp_(arg_); + done_ = true; + data_.reset(); + this->yield(); + } }; template diff --git a/coroutine/main.cpp b/coroutine/main.cpp index 349ad5b..b3cb1bf 100644 --- a/coroutine/main.cpp +++ b/coroutine/main.cpp @@ -32,21 +32,23 @@ int main() { nm::Coroutine co; - co.start([&co](int x) { - int first = 1; - co.yield(first); - - int second = 1; - co.yield(second); - - for(int i = 0; i < x; ++i) - { - int third = first + second; - first = second; - second = third; - co.yield(third); - } - }, 10); + co.start( + [&co](int x) { + int first = 1; + co.yield(first); + + int second = 1; + co.yield(second); + + for(int i = 0; i < x; ++i) + { + int third = first + second; + first = second; + second = third; + co.yield(third); + } + }, + 10); for(auto& iter: co) { diff --git a/crypt/crypto.h b/crypt/crypto.h index d81de62..4bfd1ae 100644 --- a/crypt/crypto.h +++ b/crypt/crypto.h @@ -13,158 +13,154 @@ #include #include -static const char hex_table[] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' -}; +static const char hex_table[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; -using Callback = void(*)(int, std::string&); +using Callback = void (*)(int, std::string&); class Crypto { - public: - Crypto() = default; - ~Crypto() = default; +public: + Crypto() = default; + ~Crypto() = default; + + std::string encode(const std::string& s, int magic, Callback cb) + { + std::string res = u2h(s); + res = h2b(res); + cb(magic, res); + return res; + } - std::string encode(const std::string& s, int magic, Callback cb) + std::string decode(const std::string& s, int magic, Callback cb) + { + std::string res = s; + cb(magic, res); + res = b2h(res); + res = h2u(res); + return res; + } + +private: + std::string d2h(char n, bool& neg) + { + std::vector v; + int num = n; + neg = false; + if(num < 0) { - std::string res = u2h(s); - res = h2b(res); - cb(magic, res); - return res; + neg = true; + num = 256 + num; } - - std::string decode(const std::string& s, int magic, Callback cb) + while(num > 0) { - std::string res = s; - cb(magic, res); - res = b2h(res); - res = h2u(res); - return res; + v.push_back(hex_table[num % 16]); + num /= 16; } + std::reverse(v.begin(), v.end()); + return std::string(v.begin(), v.end()); + } - private: - - std::string d2h(char n, bool& neg) + std::string h2b(const std::string& hex) + { + std::vector tmp; + int b = 0; + bool high = false; + for(size_t i = 0; i < hex.size(); ++i) { - std::vector v; - int num = n; - neg = false; - if(num < 0) + if(hex[i] >= '0' && hex[i] <= '9') { - neg = true; - num = 256 + num; + b = hex[i] - '0'; } - while(num > 0) + else if(hex[i] >= 'a' && hex[i] <= 'f') { - v.push_back(hex_table[num % 16]); - num /= 16; + b = hex[i] - 'a'; + high = true; } - std::reverse(v.begin(), v.end()); - return std::string(v.begin(), v.end()); - } - - std::string h2b(const std::string& hex) - { - std::vector tmp; - int b = 0; - bool high = false; - for(size_t i = 0; i < hex.size(); ++i) + else + b = hex[i]; + tmp.push_back(b); + if(high) { - if(hex[i] >= '0' && hex[i] <= '9') - { - b = hex[i] - '0'; - } - else if(hex[i] >= 'a' && hex[i] <= 'f') - { - b = hex[i] - 'a'; - high = true; - } - else - b = hex[i]; - tmp.push_back(b); - if(high) - { - high = false; - tmp.push_back('.'); - } + high = false; + tmp.push_back('.'); } - return std::string(tmp.begin(), tmp.end()); } + return std::string(tmp.begin(), tmp.end()); + } - std::string b2h(const std::string& bin) + std::string b2h(const std::string& bin) + { + std::vector tmp; + char hex = 0; + for(size_t i = 0; i < bin.size(); ++i) { - std::vector tmp; - char hex = 0; - for(size_t i = 0; i < bin.size(); ++i) + if(bin[i] != '.') { - if(bin[i] != '.') + if(bin[i + 1] == '.') { - if(bin[i+1] == '.') - { - hex = bin[i] + 'a'; - ++i; - } - else - hex = bin[i] + '0'; + hex = bin[i] + 'a'; + ++i; } - if(bin[i] == '`' || bin[i] == '^') - hex = bin[i]; - tmp.push_back(hex); + else + hex = bin[i] + '0'; } - return std::string(tmp.begin(), tmp.end()); + if(bin[i] == '`' || bin[i] == '^') + hex = bin[i]; + tmp.push_back(hex); } + return std::string(tmp.begin(), tmp.end()); + } - std::string u2h(const std::string& utf) + std::string u2h(const std::string& utf) + { + std::string res; + bool neg = false; + for(auto x: utf) { - std::string res; - bool neg = false; - for(auto x: utf) - { - res.append(d2h(x, neg)); - if(neg) - res.append("`"); - else - res.append("^"); - } - return res; + res.append(d2h(x, neg)); + if(neg) + res.append("`"); + else + res.append("^"); } + return res; + } - std::string h2u(const std::string& hex) + std::string h2u(const std::string& hex) + { + char* tmp = new char[hex.size()]; + memset(tmp, 0, hex.size()); + char* p = nullptr; + int n = 0; + const char* start = hex.data(); + const char* end = start + hex.size(); + for(p = tmp; start <= end; ++p) { - char* tmp = new char[hex.size()]; - memset(tmp, 0, hex.size()); - char* p = nullptr; - int n = 0; - const char* start = hex.data(); - const char* end = start + hex.size(); - for(p = tmp; start <= end; ++p) + if(*(start + 2) == '`') { - if(*(start + 2) == '`') - { - // FIXME: UTF-8 is variable length - if(sscanf(start, "%2x", &n)) - *p = n; - start += 2; - } - else if(*(start + 2) == '^') - { - n = *start++ - '0'; - n <<= 4; - if(*start >= 'a' && *start <= 'f') - n += (*start - 'a') + 10; - else if(*start >= '0' && *start <= '9') - n += (*start - '0'); - ++start; + // FIXME: UTF-8 is variable length + if(sscanf(start, "%2x", &n)) *p = n; - } + start += 2; + } + else if(*(start + 2) == '^') + { + n = *start++ - '0'; + n <<= 4; + if(*start >= 'a' && *start <= 'f') + n += (*start - 'a') + 10; + else if(*start >= '0' && *start <= '9') + n += (*start - '0'); ++start; + *p = n; } - size_t len = p - tmp; - std::string res{tmp, len}; - delete [] tmp; - return res; + ++start; } + size_t len = p - tmp; + std::string res{tmp, len}; + delete[] tmp; + return res; + } }; #endif diff --git a/fake_variant/fake_variant.h b/fake_variant/fake_variant.h index 6e60525..b1e63d9 100644 --- a/fake_variant/fake_variant.h +++ b/fake_variant/fake_variant.h @@ -14,7 +14,9 @@ namespace nm { namespace meta { - struct Nil {}; + struct Nil + { + }; template struct TypeList @@ -23,10 +25,12 @@ namespace nm using Tail = U; }; - template struct GenList; - template<> struct GenList + template + struct GenList; + template<> + struct GenList { - using type = Nil; + using type = Nil; }; template struct GenList @@ -44,7 +48,8 @@ namespace nm using type = TypeList::type>; }; - template struct Remove; + template + struct Remove; template struct Remove { @@ -61,100 +66,99 @@ namespace nm using type = TypeList::type>; }; - template struct Unique; - template<> struct Unique + template + struct Unique; + template<> + struct Unique { using type = Nil; }; template struct Unique> { - private: - using tmp = typename Unique::type; - using tail = typename Remove::type; - public: - using type = TypeList; + private: + using tmp = typename Unique::type; + using tail = typename Remove::type; + + public: + using type = TypeList; }; - template class Class> class GenClasses; + template class Class> + class GenClasses; template class Class> - class GenClasses, Class> : public GenClasses, - public GenClasses - {}; + class GenClasses, Class> : public GenClasses, public GenClasses + { + }; template class Class> class GenClasses : public Class - {}; + { + }; template class Class> class GenClasses - {}; - + { + }; + } template class FakeVariant { + public: + template + bool set(const T& value) + { + return data_.invisible::set(value); + } + template + bool set(Paras&&... paras) + { + return data_.invisible::set(std::forward(paras)...); + } + template + const T& get() const + { + return data_.invisible::get(); + } + template + bool valid() const + { + return data_.invisible::valid(); + } + + private: + template + class invisible + { public: - template bool set(const T& value) - { - return data_.invisible::set(value); - } - template + invisible() : value_{nullptr} {} + ~invisible() { clear(); } + template bool set(Paras&&... paras) { - return data_.invisible::set(std::forward(paras)...); - } - template const T& get() const - { - return data_.invisible::get(); - } - template bool valid() const - { - return data_.invisible::valid(); + bool res = valid(); + clear(); + value_ = new T(std::forward(paras)...); + return !res; } + const T& get() const { return *value_; } + bool valid() const { return value_ != nullptr; } + private: - template - class invisible + T* value_; + void clear() { - public: - invisible() - : value_{nullptr} - {} - ~invisible() - { - clear(); - } - template - bool set(Paras&&... paras) - { - bool res = valid(); - clear(); - value_ = new T(std::forward(paras)...); - return !res; - } - const T& get() const - { - return *value_; - } - bool valid() const - { - return value_ != nullptr; - } - private: - T* value_; - void clear() - { - if(valid()) - { - delete value_; - value_ = nullptr; - } - } - }; - meta::GenClasses - ::type>::type, invisible> data_; + if(valid()) + { + delete value_; + value_ = nullptr; + } + } + }; + meta::GenClasses::type>::type, invisible> data_; }; } diff --git a/fake_variant/test.cpp b/fake_variant/test.cpp index 0cd9260..e9db831 100644 --- a/fake_variant/test.cpp +++ b/fake_variant/test.cpp @@ -16,18 +16,15 @@ int main() { struct NonCopyMoveable { - NonCopyMoveable(int x) - : data_(x) - {} + NonCopyMoveable(int x) : data_(x) {} NonCopyMoveable(const NonCopyMoveable&) = delete; NonCopyMoveable(NonCopyMoveable&&) = delete; - NonCopyMoveable& operator= (const NonCopyMoveable&) = delete; - NonCopyMoveable& operator= (NonCopyMoveable&&) = delete; + NonCopyMoveable& operator=(const NonCopyMoveable&) = delete; + NonCopyMoveable& operator=(NonCopyMoveable&&) = delete; int data_; }; // ignore extra `int` - nm::FakeVariant> va; + nm::FakeVariant> va; va.set(10); va.set(309); va.set("+1s"); @@ -35,8 +32,7 @@ int main() // call `set(const T&)` va.set>({"old", "value"}); // call `set(Para&&...)` - auto res = va.set, std::initializer_list> - ({"this", " is", " a", " test."}); + auto res = va.set, std::initializer_list>({"this", " is", " a", " test."}); if(!res) cout << "override exist value!\n"; cout << va.get() << endl; diff --git a/file_sort/bit.cpp b/file_sort/bit.cpp index c1b9c24..015eda0 100644 --- a/file_sort/bit.cpp +++ b/file_sort/bit.cpp @@ -54,7 +54,7 @@ int main(int argc, char* argv[]) bit_map.reset(); for(i = 0; i < max_scan; ++i) duplicate[i] = 0; - + while(fscanf(fin, "%d\n", &n) != EOF) { if(n >= max_scan && n <= size) diff --git a/file_sort/bs.cpp b/file_sort/bs.cpp index 72ae6c6..27c27f8 100644 --- a/file_sort/bs.cpp +++ b/file_sort/bs.cpp @@ -11,8 +11,8 @@ #include #define failure(func, line) \ - do \ - { \ + do \ + { \ fprintf(stderr, "%s : %d\t", func, line); \ perror(func); \ std::terminate(); \ @@ -20,127 +20,127 @@ class Bigdata { - public: - Bigdata(long limit, const std::string& input, const std::string& output) +public: + Bigdata(long limit, const std::string& input, const std::string& output) : slot_(limit), in_(input), out_(output), count_(0) - { - } + { + } - void sort() - { - split_files(); - merge_files(); - do_clean(); - } + void sort() + { + split_files(); + merge_files(); + do_clean(); + } - private: - const long slot_; - std::string in_, out_; - long count_; +private: + const long slot_; + std::string in_, out_; + long count_; - FILE* get_tmpfd() - { - char name[50]; - sprintf(name, "tmp_%ld", count_++); - FILE* tmpfd = fopen(name, "w"); - if(tmpfd == nullptr) - failure(__func__, __LINE__); - return tmpfd; - } + FILE* get_tmpfd() + { + char name[50]; + sprintf(name, "tmp_%ld", count_++); + FILE* tmpfd = fopen(name, "w"); + if(tmpfd == nullptr) + failure(__func__, __LINE__); + return tmpfd; + } - void split_files() + void split_files() + { + FILE* fd = fopen(in_.c_str(), "r"); + if(fd == nullptr) + failure(__func__, __LINE__); + long n = 0; + FILE* tmpfd = get_tmpfd(); + long local_count = 0; + long* numbers_ = new long[slot_]; + while(fscanf(fd, "%ld\n", &n) != EOF) { - FILE* fd = fopen(in_.c_str(), "r"); - if(fd == nullptr) - failure(__func__, __LINE__); - long n = 0; - FILE* tmpfd = get_tmpfd(); - long local_count = 0; - long* numbers_ = new long[slot_]; - while(fscanf(fd, "%ld\n", &n) != EOF) - { - numbers_[local_count++] = n; - if(local_count == slot_) - { - local_count = 0; - std::sort(numbers_, numbers_ + slot_); - for(long i = 0; i < slot_; ++i) - fprintf(tmpfd, "%ld\n", numbers_[i]); - memset(numbers_, 0, sizeof(long) * slot_); - fclose(tmpfd); - tmpfd = get_tmpfd(); - } - } - if(local_count != 0) + numbers_[local_count++] = n; + if(local_count == slot_) { + local_count = 0; std::sort(numbers_, numbers_ + slot_); for(long i = 0; i < slot_; ++i) fprintf(tmpfd, "%ld\n", numbers_[i]); + memset(numbers_, 0, sizeof(long) * slot_); + fclose(tmpfd); + tmpfd = get_tmpfd(); } - delete [] numbers_; - fclose(tmpfd); - fclose(fd); } + if(local_count != 0) + { + std::sort(numbers_, numbers_ + slot_); + for(long i = 0; i < slot_; ++i) + fprintf(tmpfd, "%ld\n", numbers_[i]); + } + delete[] numbers_; + fclose(tmpfd); + fclose(fd); + } - void merge_files() + void merge_files() + { + FILE* fd = fopen(out_.c_str(), "w"); + if(fd == nullptr) + failure(__func__, __LINE__); + FILE* fds[count_]; + long data[count_]; + bool done[count_]; + char name[50]; + for(long i = 0; i < count_; ++i) { - FILE* fd = fopen(out_.c_str(), "w"); - if(fd == nullptr) - failure(__func__, __LINE__); - FILE* fds[count_]; - long data[count_]; - bool done[count_]; - char name[50]; - for(long i = 0; i < count_; ++i) + done[i] = false; + data[i] = 0; + sprintf(name, "tmp_%ld", i); + fds[i] = fopen(name, "r"); + if(fscanf(fds[i], "%ld\n", &data[i]) == EOF) { - done[i] = false; - data[i] = 0; - sprintf(name, "tmp_%ld", i); - fds[i] = fopen(name, "r"); - if(fscanf(fds[i], "%ld\n", &data[i]) == EOF) - { - fclose(fds[i]); - remove(name); - done[i] = true; - } + fclose(fds[i]); + remove(name); + done[i] = true; } - while(true) + } + while(true) + { + long j = 0; + while(j < count_ && done[j]) + ++j; + if(j >= count_) + break; + long minimum = data[j]; + for(long i = j + 1; i < count_; ++i) { - long j = 0; - while(j < count_ && done[j]) - ++j; - if(j >= count_) - break; - long minimum = data[j]; - for(long i = j + 1; i < count_; ++i) - { - if(!done[i] && minimum > data[i]) - { - minimum = data[i]; - j = i; - } - } - fprintf(fd, "%ld\n", minimum); - if(fscanf(fds[j], "%ld\n", &data[j]) == EOF) + if(!done[i] && minimum > data[i]) { - fclose(fds[j]); - sprintf(name, "tmp_%ld", j); - remove(name); - done[j] = true; + minimum = data[i]; + j = i; } } - fclose(fd); - } - - void do_clean() - { - char name[50]; - for(long i = 0; i < count_; ++i) + fprintf(fd, "%ld\n", minimum); + if(fscanf(fds[j], "%ld\n", &data[j]) == EOF) { - sprintf(name, "tmp_%ld", i); + fclose(fds[j]); + sprintf(name, "tmp_%ld", j); remove(name); + done[j] = true; } } + fclose(fd); + } + + void do_clean() + { + char name[50]; + for(long i = 0; i < count_; ++i) + { + sprintf(name, "tmp_%ld", i); + remove(name); + } + } }; int main(int argc, char* argv[]) diff --git a/fm/README.md b/fm/README.md index 23c4fd6..fe00418 100644 --- a/fm/README.md +++ b/fm/README.md @@ -2,14 +2,6 @@ A container for all callable objects (functor, lamda, free function). - - -## How it works - -the key is erase type inforamtion of callable object and store them in `std::function`. - - - ## Example ```c++ @@ -23,7 +15,7 @@ std::cout << fm.call("bar", 233) << '\n'; // print 233 try { fm.call("bar", "too", "bad"); } catch(const std::runtime_error& e) { - std::cerr << e.what() << '\n'; // print paremter mistach (return type, parameter type and paramter count) + std::cerr << e.what() << '\n'; // print parameter mismatch (return type, parameter type and parameter count) } ``` diff --git a/fm/functor_map.h b/fm/functor_map.h index 1492cc1..bfa1bad 100644 --- a/fm/functor_map.h +++ b/fm/functor_map.h @@ -17,25 +17,32 @@ namespace nm { namespace meta { - template struct test_arg; - template<> struct test_arg<> + template + struct test_arg; + template<> + struct test_arg<> { constexpr static bool value = true; }; - template struct test_arg + template + struct test_arg { - constexpr static bool value = !std::is_reference_v && std::is_copy_assignable_v && std::is_constructible_v; + constexpr static bool value = + !std::is_reference_v && std::is_copy_assignable_v && std::is_constructible_v; }; - template struct test_arg + template + struct test_arg { constexpr static bool value = test_arg::value && test_arg::value; }; - template struct Inspector; + template + struct Inspector; template struct Inspector { - constexpr static bool is_r_valid = std::is_void_v || (std::is_copy_assignable_v && std::is_constructible_v); + constexpr static bool is_r_valid = + std::is_void_v || (std::is_copy_assignable_v && std::is_constructible_v); constexpr static bool is_arg_valid = test_arg::value; static_assert(is_r_valid, "invalid return type, must be `void` or can be copied and constructed"); static_assert(is_arg_valid, "invalid argument type, must be copyable and can't be reference"); @@ -43,27 +50,46 @@ namespace nm using res_t = R; }; template - struct Inspector : Inspector {}; + struct Inspector : Inspector + { + }; template - struct Inspector : Inspector {}; + struct Inspector : Inspector + { + }; template - struct Inspector : Inspector {}; + struct Inspector : Inspector + { + }; template - struct Inspector : Inspector {}; + struct Inspector : Inspector + { + }; template - struct Inspector : Inspector {}; + struct Inspector : Inspector + { + }; template - struct Inspector : Inspector {}; + struct Inspector : Inspector + { + }; // functor like template - struct Inspector : Inspector {}; + struct Inspector : Inspector + { + }; template - struct Inspector : Inspector {}; + struct Inspector : Inspector + { + }; template - struct Inspector : Inspector {}; + struct Inspector : Inspector + { + }; - template struct call_impl + template + struct call_impl { template static R call(F&& f, Arg& args) @@ -76,10 +102,12 @@ namespace nm template static void invoke(R* res, F&& f, TupleType& args, std::index_sequence) { - *res = std::forward(f)(std::forward>>(std::get(args))...); + *res = std::forward(f)( + std::forward>>(std::get(args))...); } }; - template<> struct call_impl + template<> + struct call_impl { template static void call(F&& f, Arg& args) @@ -90,118 +118,111 @@ namespace nm template static void invoke(void*, F&& f, TupleType& args, std::index_sequence) { - std::forward(f)(std::forward>>(std::get(args))...); + std::forward(f)( + std::forward>>(std::get(args))...); } }; } class FunctorMap { - public: - using Fp = std::function; + public: + using Fp = std::function; - FunctorMap() = default; + FunctorMap() = default; - ~FunctorMap() - { - this->clear(); - } + ~FunctorMap() { this->clear(); } - FunctorMap(const FunctorMap&) = delete; - FunctorMap& operator= (const FunctorMap&) = delete; + FunctorMap(const FunctorMap&) = delete; + FunctorMap& operator=(const FunctorMap&) = delete; - FunctorMap(FunctorMap&& rhs) noexcept - : functors_{std::move(rhs.functors_)}, tidy_{std::move(rhs.tidy_)} - {} + FunctorMap(FunctorMap&& rhs) noexcept : functors_{std::move(rhs.functors_)}, tidy_{std::move(rhs.tidy_)} {} - FunctorMap& operator= (FunctorMap&& rhs) noexcept + FunctorMap& operator=(FunctorMap&& rhs) noexcept + { + if(this != &rhs) { - if (this != &rhs) - { - this->~FunctorMap(); - new(this) FunctorMap(std::move(rhs)); - } - return *this; + this->~FunctorMap(); + new(this) FunctorMap(std::move(rhs)); } + return *this; + } - template - bool bind(const std::string& name, F&& f) + template + bool bind(const std::string& name, F&& f) + { + if(functors_.count(name) > 0) { - if(functors_.count(name) > 0) - { - return false; - } - using inspector = meta::Inspector; - using arg_t = typename inspector::arg_t; - using res_t = typename inspector::res_t; - auto fp = [f = std::forward(f)](void* args, void* res) { - using indices = std::make_index_sequence::value>; - arg_t& arg = *static_cast(args); - res_t* tmp = static_cast(res); - meta::call_impl::invoke(tmp, f, arg, indices{}); - }; - functors_[name] = std::move(fp); - std::lock_guard lg{ mtx_ }; - // use res_t* for void type - types_.insert({ name, nullptr }); - tidy_[name] = [name] { - types_.erase(name); - }; - return true; + return false; } - - template - R call(const std::string& name, Args&&... args) + using inspector = meta::Inspector; + using arg_t = typename inspector::arg_t; + using res_t = typename inspector::res_t; + auto fp = [f = std::forward(f)](void* args, void* res) { + using indices = std::make_index_sequence::value>; + arg_t& arg = *static_cast(args); + res_t* tmp = static_cast(res); + meta::call_impl::invoke(tmp, f, arg, indices{}); + }; + functors_[name] = std::move(fp); + std::lock_guard lg{mtx_}; + // use res_t* for void type + types_.insert({name, nullptr}); + tidy_[name] = [name] { types_.erase(name); }; + return true; + } + + template + R call(const std::string& name, Args&&... args) + { + auto params = std::make_tuple(std::forward(args)...); + auto iter = functors_.find(name); + if(iter == functors_.end()) { - auto params = std::make_tuple(std::forward(args)...); - auto iter = functors_.find(name); - if(iter == functors_.end()) - { - return R(); - } - if (types_>.count(name) <= 0) - { - throw std::runtime_error("parameter mismatch"); - } - return meta::call_impl::call(iter->second, params); + return R(); } - - bool contain(const std::string& name) + if(types_>.count(name) <= 0) { - return functors_.count(name) > 0; + throw std::runtime_error("parameter mismatch"); } + return meta::call_impl::call(iter->second, params); + } + + bool contain(const std::string& name) { return functors_.count(name) > 0; } - bool remove(const std::string& name) + bool remove(const std::string& name) + { + if(!this->contain(name)) { - if(!this->contain(name)) - { - return false; - } - functors_.erase(name); - std::lock_guard lg{mtx_}; - auto iter = tidy_.find(name); - iter->second(); - tidy_.erase(iter); - return true; + return false; } - - void clear() + functors_.erase(name); + std::lock_guard lg{mtx_}; + auto iter = tidy_.find(name); + iter->second(); + tidy_.erase(iter); + return true; + } + + void clear() + { + functors_.clear(); + std::lock_guard lg{mtx_}; + for(auto& c: tidy_) { - functors_.clear(); - std::lock_guard lg{mtx_}; - for(auto& c: tidy_) - { - c.second(); - } - tidy_.clear(); + c.second(); } - - private: - std::map functors_; - std::map> tidy_; - static inline std::mutex mtx_; - // vs2017 bug: https://developercommunity.visualstudio.com/content/problem/261624/multiple-initializations-of-inline-static-data-mem.html - template static inline std::map*> types_{}; + tidy_.clear(); + } + + private: + std::map functors_; + std::map> tidy_; + static inline std::mutex mtx_; + // vs2017 bug: + // https://developercommunity.visualstudio.com/content/problem/261624/multiple-initializations-of-inline-static-data-mem.html + template + static inline std::map*> types_{}; }; } diff --git a/fm/test.cpp b/fm/test.cpp index 1cfe0a8..9bce1c9 100644 --- a/fm/test.cpp +++ b/fm/test.cpp @@ -8,15 +8,12 @@ #include "functor_map.h" #include -std::string to_str(int x) -{ - return std::to_string(x); -} +std::string to_str(int x) { return std::to_string(x); } struct Foo { static std::string foo() { return __func__; } - int operator() (int x) { return x * x; } + int operator()(int x) { return x * x; } }; int main() @@ -27,7 +24,7 @@ int main() // bind fm.bind("lambda", [](int lhs, int rhs) { return lhs + rhs; }); - fm.bind("lambda2", [](string lhs, string rhs) { return lhs + rhs; }); + fm.bind("lambda2", [](string lhs, string rhs) { return lhs + rhs; }); fm.bind("void_arg_res", [] { std::cout << "void\n"; }); fm.bind("void_arg", [] { return "666"; }); fm.bind("free_function", to_str); diff --git a/form_parser/form_parser.h b/form_parser/form_parser.h index d12b3b7..1e0b867 100644 --- a/form_parser/form_parser.h +++ b/form_parser/form_parser.h @@ -26,655 +26,613 @@ namespace nm #endif class FormParser { - using CallBack = std::function; - - public: - using map_t = std::map; - - FormParser() + using CallBack = std::function; + + public: + using map_t = std::map; + + FormParser() + { + lookbehind_ = nullptr; + reset_callbacks(); + this->reset(); + } + + ~FormParser() { delete[] lookbehind_; } + + void set_env(const std::string& boundary, const std::string& path) + { + this->reset(); + this->boundary_ = "\r\n--" + boundary; + tmp_path_ = path; + if(tmp_path_[tmp_path_.size() - 1] != '/') { - lookbehind_ = nullptr; - reset_callbacks(); - this->reset(); + tmp_path_.append(1, '/'); } - - ~FormParser() + boundary_data_ = this->boundary_.c_str(); + boundary_size_ = this->boundary_.size(); + this->index_boundary(); + lookbehind_ = new char[boundary_size_ + 8]; + lookbehind_size_ = boundary_size_ + 8; + state_ = START; + error_reason_ = "No error."; + } + + const map_t& file_map() { return files_; } + + const map_t text_map() { return texts_; } + + void consume(const char* buffer, size_t len) + { + if(state_ == PARSE_ERROR || len == 0) { - delete[] lookbehind_; + return; } - void set_env(const std::string& boundary, const std::string& path) - { - this->reset(); - this->boundary_ = "\r\n--" + boundary; - tmp_path_ = path; - if(tmp_path_[tmp_path_.size() - 1] != '/') - { - tmp_path_.append(1, '/'); - } - boundary_data_ = this->boundary_.c_str(); - boundary_size_ = this->boundary_.size(); - this->index_boundary(); - lookbehind_ = new char[boundary_size_ + 8]; - lookbehind_size_ = boundary_size_ + 8; - state_ = START; - error_reason_ = "No error."; - } + State state = this->state_; + int flags = this->flags_; + size_t prev_index = this->index_; + size_t index = this->index_; + size_t boundaryEnd = boundary_size_ - 1; + size_t i; + char c, cl; - const map_t& file_map() + for(i = 0; i < len; i++) { - return files_; - } - - const map_t text_map() - { - return texts_; - } - - void consume(const char* buffer, size_t len) - { - if(state_ == PARSE_ERROR || len == 0) + c = buffer[i]; + switch(state) { + case PARSE_ERROR: return; - } - - State state = this->state_; - int flags = this->flags_; - size_t prev_index = this->index_; - size_t index = this->index_; - size_t boundaryEnd = boundary_size_ - 1; - size_t i; - char c, cl; - - for(i = 0; i < len; i++) - { - c = buffer[i]; - switch(state) + case START: + index = 0; + state = START_BOUNDARY; + FALL_THROUGH + case START_BOUNDARY: + if(index == boundary_size_ - 2) { - case PARSE_ERROR: + if(c != CR) + { + set_error("Malformed. Expected CR after boundary."); return; - case START: - index = 0; - state = START_BOUNDARY; - FALL_THROUGH - case START_BOUNDARY: - if(index == boundary_size_ - 2) - { - if(c != CR) - { - set_error("Malformed. Expected CR after boundary."); - return; - } - index++; - break; - } - else if(index - 1 == boundary_size_ - 2) - { - if(c != LF) - { - set_error("Malformed. Expected LF after boundary CR."); - return; - } - index = 0; - callback(on_part_begin_); - state = HEADER_FIELD_START; - break; - } - if(c != boundary_[index + 2]) - { - set_error( - "Malformed. Found different boundary data than the given one."); - return; - } - index++; - break; - case HEADER_FIELD_START: - state = HEADER_FIELD; - header_field_mark_ = i; - index = 0; - FALL_THROUGH - case HEADER_FIELD: - if(c == CR) - { - header_field_mark_ = UNMARKED; - state = HEADERS_ALMOST_DONE; - break; - } + } + index++; + break; + } + else if(index - 1 == boundary_size_ - 2) + { + if(c != LF) + { + set_error("Malformed. Expected LF after boundary CR."); + return; + } + index = 0; + callback(on_part_begin_); + state = HEADER_FIELD_START; + break; + } + if(c != boundary_[index + 2]) + { + set_error("Malformed. Found different boundary data than the given one."); + return; + } + index++; + break; + case HEADER_FIELD_START: + state = HEADER_FIELD; + header_field_mark_ = i; + index = 0; + FALL_THROUGH + case HEADER_FIELD: + if(c == CR) + { + header_field_mark_ = UNMARKED; + state = HEADERS_ALMOST_DONE; + break; + } - index++; - if(c == DASH) - { - break; - } + index++; + if(c == DASH) + { + break; + } - if(c == COLON) - { - if(index == 1) - { - // empty header field - set_error("Malformed first header name character."); - return; - } - data_callback(on_header_field_, header_field_mark_, buffer, i, - len, true); - state = HEADER_VALUE_START; - break; - } + if(c == COLON) + { + if(index == 1) + { + // empty header field + set_error("Malformed first header name character."); + return; + } + data_callback(on_header_field_, header_field_mark_, buffer, i, len, true); + state = HEADER_VALUE_START; + break; + } - cl = lower(c); - if(cl < 'a' || cl > 'z') - { - set_error("Malformed header name."); - return; - } - break; - case HEADER_VALUE_START: - if(c == SPACE) - { - break; - } + cl = lower(c); + if(cl < 'a' || cl > 'z') + { + set_error("Malformed header name."); + return; + } + break; + case HEADER_VALUE_START: + if(c == SPACE) + { + break; + } - header_value_mark_ = i; - state = HEADER_VALUE; - FALL_THROUGH - case HEADER_VALUE: - if(c == CR) - { - data_callback(on_header_value_, header_value_mark_, buffer, i, - len, true, true); - callback(on_header_end_); - state = HEADER_VALUE_ALMOST_DONE; - } - break; - case HEADER_VALUE_ALMOST_DONE: - if(c != LF) - { - set_error("Malformed header value: LF expected after CR"); - return; - } + header_value_mark_ = i; + state = HEADER_VALUE; + FALL_THROUGH + case HEADER_VALUE: + if(c == CR) + { + data_callback(on_header_value_, header_value_mark_, buffer, i, len, true, true); + callback(on_header_end_); + state = HEADER_VALUE_ALMOST_DONE; + } + break; + case HEADER_VALUE_ALMOST_DONE: + if(c != LF) + { + set_error("Malformed header value: LF expected after CR"); + return; + } - state = HEADER_FIELD_START; - break; - case HEADERS_ALMOST_DONE: - if(c != LF) - { - set_error("Malformed header ending: LF expected after CR"); - return; - } - callback(on_headers_end_); - state = PART_DATA_START; - break; - case PART_DATA_START: - state = PART_DATA; - part_data_mark_ = i; - FALL_THROUGH - case PART_DATA: - prev_index = index; + state = HEADER_FIELD_START; + break; + case HEADERS_ALMOST_DONE: + if(c != LF) + { + set_error("Malformed header ending: LF expected after CR"); + return; + } + callback(on_headers_end_); + state = PART_DATA_START; + break; + case PART_DATA_START: + state = PART_DATA; + part_data_mark_ = i; + FALL_THROUGH + case PART_DATA: + prev_index = index; + + if(index == 0) + { + i += boundaryEnd; + // boyer-moore derived algorithm to safely skip non-boundary data + while(i < len && !is_in_boundary(buffer[i])) + { + i += boundary_size_; + } + i -= boundaryEnd; + c = buffer[i]; + } + if(index < boundary_size_) + { + if(boundary_[index] == c) + { if(index == 0) { - i += boundaryEnd; - // boyer-moore derived algorithm to safely skip non-boundary data - while(i < len && !is_in_boundary(buffer[i])) - { - i += boundary_size_; - } - i -= boundaryEnd; - c = buffer[i]; + data_callback(on_part_data_, part_data_mark_, buffer, i, len, true); } - - if(index < boundary_size_) + index++; + } + else + { + index = 0; + } + } + else if(index == boundary_size_) + { + index++; + if(c == CR) + { + // CR = part boundary + flags |= PART_BOUNDARY; + } + else if(c == DASH) + { + // DASH = end boundary + flags |= LAST_BOUNDARY; + } + else + { + index = 0; + } + } + else if(index - 1 == boundary_size_) + { + if(flags & PART_BOUNDARY) + { + index = 0; + if(c == LF) { - if(boundary_[index] == c) - { - if(index == 0) - { - data_callback(on_part_data_, part_data_mark_, buffer, i, - len, - true); - } - index++; - } - else - { - index = 0; - } + // unset the PART_BOUNDARY flag + flags &= ~PART_BOUNDARY; + callback(on_part_end_); + callback(on_part_begin_); + state = HEADER_FIELD_START; + break; } - else if(index == boundary_size_) + } + else if(flags & LAST_BOUNDARY) + { + if(c == DASH) { - index++; - if(c == CR) - { - // CR = part boundary - flags |= PART_BOUNDARY; - } - else if(c == DASH) - { - // DASH = end boundary - flags |= LAST_BOUNDARY; - } - else - { - index = 0; - } + callback(on_part_end_); + callback(on_end_); + state = END; } - else if(index - 1 == boundary_size_) + else { - if(flags & PART_BOUNDARY) - { - index = 0; - if(c == LF) - { - // unset the PART_BOUNDARY flag - flags &= ~PART_BOUNDARY; - callback(on_part_end_); - callback(on_part_begin_); - state = HEADER_FIELD_START; - break; - } - } - else if(flags & LAST_BOUNDARY) - { - if(c == DASH) - { - callback(on_part_end_); - callback(on_end_); - state = END; - } - else - { - index = 0; - } - } - else - { - index = 0; - } - } - else if (index - 2 == boundary_size_) { - if (c == CR) { - index++; - } else { - index = 0; - } - } else if (index - boundary_size_ == 3) { index = 0; - if (c == LF) { - callback(on_part_end_); - callback(on_end_); - state = END; - break; - } - } - if(index > 0) - { - // when matching a possible boundary, keep a lookbehind reference - // in case it turns out to be a false lead - // since index is unsigned, this can happen either index equal 0 - // or index far more larger than lookbehind_size_ - if(index - 1 >= lookbehind_size_) - { - set_error("Parser bug: index overflows lookbehind buffer. " - "Please send bug report with input file attached."); - return; - } - lookbehind_[index - 1] = c; } - else if(prev_index > 0) - { - // if our boundary turned out to be rubbish, the captured lookbehind - // belongs to partData - callback(on_part_data_, lookbehind_, 0, prev_index); - prev_index = 0; - part_data_mark_ = i; - - // reconsider the current character even so it interrupted the sequence - // it could be the beginning of a new sequence - i--; - } - break; - case END: + } + else + { + index = 0; + } + } + else if(index - 2 == boundary_size_) + { + if(c == CR) + { + index++; + } + else + { + index = 0; + } + } + else if(index - boundary_size_ == 3) + { + index = 0; + if(c == LF) + { + callback(on_part_end_); + callback(on_end_); + state = END; break; - default: + } + } + if(index > 0) + { + // when matching a possible boundary, keep a lookbehind reference + // in case it turns out to be a false lead + // since index is unsigned, this can happen either index equal 0 + // or index far more larger than lookbehind_size_ + if(index - 1 >= lookbehind_size_) + { + set_error("Parser bug: index overflows lookbehind buffer. " + "Please send bug report with input file attached."); return; + } + lookbehind_[index - 1] = c; + } + else if(prev_index > 0) + { + // if our boundary turned out to be rubbish, the captured lookbehind + // belongs to partData + callback(on_part_data_, lookbehind_, 0, prev_index); + prev_index = 0; + part_data_mark_ = i; + + // reconsider the current character even so it interrupted the sequence + // it could be the beginning of a new sequence + i--; } + break; + case END: + break; + default: + return; } - - data_callback(on_header_field_, header_field_mark_, buffer, i, len, false); - data_callback(on_header_value_, header_value_mark_, buffer, i, len, false); - data_callback(on_part_data_, part_data_mark_, buffer, i, len, false); - - this->index_ = index; - this->state_ = state; - this->flags_ = flags; } - bool done() const + data_callback(on_header_field_, header_field_mark_, buffer, i, len, false); + data_callback(on_header_value_, header_value_mark_, buffer, i, len, false); + data_callback(on_part_data_, part_data_mark_, buffer, i, len, false); + + this->index_ = index; + this->state_ = state; + this->flags_ = flags; + } + + bool done() const { return state_ == END; } + + bool is_error() const { return state_ == PARSE_ERROR; } + + const char* err_string() const { return error_reason_; } + + private: + enum State + { + PARSE_ERROR, + START, + START_BOUNDARY, + HEADER_FIELD_START, + HEADER_FIELD, + HEADER_VALUE_START, + HEADER_VALUE, + HEADER_VALUE_ALMOST_DONE, + HEADERS_ALMOST_DONE, + PART_DATA_START, + PART_DATA, + PART_END, + END + }; + + enum Flags + { + PART_BOUNDARY = 1, + LAST_BOUNDARY = 2 + }; + + enum ContentType + { + TEXT = 0, + FILE, + UNKNOWN + }; + + static const char CR = '\r'; + static const char LF = '\n'; + static const char SPACE = ' '; + static const char DASH = '-'; + static const char COLON = ':'; + static const size_t UNMARKED = std::numeric_limits::max(); + std::string boundary_; + std::string tmp_path_; + std::map files_; // filename and tmp file path + std::map texts_; // name and value + ContentType type_; + std::string key_; // either name or filename + std::string value_; // text value of key + std::ofstream of_; // tmp file stream + const char* boundary_data_; + size_t boundary_size_; + bool boundary_index_[256]; + char* lookbehind_; + size_t lookbehind_size_; + State state_; + int flags_; + size_t index_; + size_t header_field_mark_; + size_t header_value_mark_; + size_t part_data_mark_; + const char* error_reason_; + CallBack on_part_begin_; + CallBack on_header_field_; + CallBack on_header_value_; + CallBack on_header_end_; // one header parsed + CallBack on_headers_end_; // all header parsed + CallBack on_part_data_; + CallBack on_part_end_; + CallBack on_end_; + + void reset() + { + delete[] lookbehind_; + state_ = PARSE_ERROR; + type_ = UNKNOWN; + boundary_.clear(); + boundary_data_ = boundary_.c_str(); + boundary_size_ = 0; + lookbehind_ = nullptr; + lookbehind_size_ = 0; + flags_ = 0; + index_ = 0; + header_field_mark_ = UNMARKED; + header_value_mark_ = UNMARKED; + part_data_mark_ = UNMARKED; + error_reason_ = "Parser uninitialized."; + } + + std::string gen_temp_name(const std::string& prefix) + { + std::string res; + res.reserve(prefix.size() + 33); + res.append(prefix); + static const char seed[] = "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + static const int n = sizeof(seed) - 1; + static std::random_device rd; + std::mt19937 rng; + rng.seed(rd()); + std::uniform_int_distribution dist(1, 1000); + for(int i = 0; i < 33; ++i) { - return state_ == END; + res.append(1, seed[dist(rng) % n]); } - - bool is_error() const + return res; + } + + // data call back + void on_header_filed(const char*, size_t, size_t) {} + + // data call back + void on_header_value(const char* buf, size_t beg, size_t end) + { + std::string tmp{buf + beg, end - beg}; + static std::string name = "name=\""; + static std::string filename = "filename=\""; + // only file upload can both appear name and filename + // so, if filename appeared, is must be file upload + size_t index = tmp.find(filename); + if(index != tmp.npos) { - return state_ == PARSE_ERROR; + type_ = FILE; + index += filename.size(); } - - const char* err_string() const + else if((index = tmp.find(name)) != tmp.npos) { - return error_reason_; + type_ = TEXT; + index += name.size(); } - private: - enum State - { - PARSE_ERROR, - START, - START_BOUNDARY, - HEADER_FIELD_START, - HEADER_FIELD, - HEADER_VALUE_START, - HEADER_VALUE, - HEADER_VALUE_ALMOST_DONE, - HEADERS_ALMOST_DONE, - PART_DATA_START, - PART_DATA, - PART_END, - END - }; - - enum Flags - { - PART_BOUNDARY = 1, - LAST_BOUNDARY = 2 - }; - - enum ContentType + if(type_ == UNKNOWN) { - TEXT = 0, - FILE, - UNKNOWN - }; - - static const char CR = '\r'; - static const char LF = '\n'; - static const char SPACE = ' '; - static const char DASH = '-'; - static const char COLON = ':'; - static const size_t UNMARKED = std::numeric_limits::max(); - std::string boundary_; - std::string tmp_path_; - std::map files_; // filename and tmp file path - std::map texts_; // name and value - ContentType type_; - std::string key_; // either name or filename - std::string value_; // text value of key - std::ofstream of_; // tmp file stream - const char* boundary_data_; - size_t boundary_size_; - bool boundary_index_[256]; - char* lookbehind_; - size_t lookbehind_size_; - State state_; - int flags_; - size_t index_; - size_t header_field_mark_; - size_t header_value_mark_; - size_t part_data_mark_; - const char* error_reason_; - CallBack on_part_begin_; - CallBack on_header_field_; - CallBack on_header_value_; - CallBack on_header_end_; // one header parsed - CallBack on_headers_end_; // all header parsed - CallBack on_part_data_; - CallBack on_part_end_; - CallBack on_end_; - - void reset() - { - delete[] lookbehind_; - state_ = PARSE_ERROR; - type_ = UNKNOWN; - boundary_.clear(); - boundary_data_ = boundary_.c_str(); - boundary_size_ = 0; - lookbehind_ = nullptr; - lookbehind_size_ = 0; - flags_ = 0; - index_ = 0; - header_field_mark_ = UNMARKED; - header_value_mark_ = UNMARKED; - part_data_mark_ = UNMARKED; - error_reason_ = "Parser uninitialized."; + // current header don't contain name of filename, maybe + // appear in next header + return; } - - std::string gen_temp_name(const std::string& prefix) + if(key_.empty()) { - std::string res; - res.reserve(prefix.size() + 33); - res.append(prefix); - static const char seed[] = "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - static const int n = sizeof(seed) - 1; - static std::random_device rd; - std::mt19937 rng; - rng.seed(rd()); - std::uniform_int_distribution dist(1, 1000); - for(int i = 0; i < 33; ++i) - { - res.append(1, seed[dist(rng) % n]); - } - return res; + key_ = tmp.substr(index, tmp.size() - index - 1); } + } - // data call back - void on_header_filed(const char*, size_t, size_t) - {} + void on_header_end(const char*, size_t, size_t) {} - // data call back - void on_header_value(const char* buf, size_t beg, size_t end) + void on_headers_end(const char*, size_t, size_t) + { + switch(type_) { - std::string tmp{buf + beg, end - beg}; - static std::string name = "name=\""; - static std::string filename = "filename=\""; - // only file upload can both appear name and filename - // so, if filename appeared, is must be file upload - size_t index = tmp.find(filename); - if(index != tmp.npos) - { - type_ = FILE; - index += filename.size(); - } - else if((index = tmp.find(name)) != tmp.npos) - { - type_ = TEXT; - index += name.size(); - } - - if(type_ == UNKNOWN) - { - // current header don't contain name of filename, maybe - // appear in next header - return; - } - if(key_.empty()) + case UNKNOWN: + this->set_error("no name and filename given in header"); + // invalid header, skip it silently + return; + case TEXT: + value_.clear(); + break; + case FILE: + { + value_ = tmp_path_ + this->gen_temp_name(key_); + of_.open(value_, of_.binary); + if(!of_.is_open()) { - key_ = tmp.substr(index, tmp.size() - index - 1); + this->set_error("can't create temp file"); } + break; } + } + } - void on_header_end(const char*, size_t, size_t) - {} + void on_part_begin(const char*, size_t, size_t) {} - void on_headers_end(const char*, size_t, size_t) + // data call back + void on_part_data(const char* buf, size_t beg, size_t end) + { + if(this->is_error()) { - switch(type_) - { - case UNKNOWN: - this->set_error("no name and filename given in header"); - // invalid header, skip it silently - return; - case TEXT: - value_.clear(); - break; - case FILE: - { - value_ = tmp_path_ + this->gen_temp_name(key_); - of_.open(value_, of_.binary); - if(!of_.is_open()) - { - this->set_error("can't create temp file"); - } - break; - } - } + return; } - - void on_part_begin(const char*, size_t, size_t) - {} - - // data call back - void on_part_data(const char* buf, size_t beg, size_t end) + switch(type_) { - if(this->is_error()) - { - return; - } - switch(type_) - { - case TEXT: - value_.append(buf + beg, end - beg); - break; - case FILE: - of_.write(buf + beg, end - beg); - break; - default: - // impossible - break; - } + case TEXT: + value_.append(buf + beg, end - beg); + break; + case FILE: + of_.write(buf + beg, end - beg); + break; + default: + // impossible + break; } + } - void on_part_end(const char*, size_t, size_t) + void on_part_end(const char*, size_t, size_t) + { + if(this->is_error()) { - if(this->is_error()) - { - return; - } - switch(type_) - { - case TEXT: - texts_.insert({key_, value_}); - texts_.insert({key_, value_}); - break; - case FILE: - files_.insert({key_, value_}); - of_.close(); - break; - default: - break; // impossible - } - key_.clear(); - value_.clear(); - type_ = UNKNOWN; // re-init for next header of part + return; } - - void on_end(const char*, size_t, size_t) - {} - - void reset_callbacks() + switch(type_) { - on_part_begin_ = [this](const char* buf, size_t beg, size_t end) { - this->on_part_begin(buf, beg, end); - }; - on_header_field_ = [this](const char* buf, size_t beg, size_t end) { - this->on_header_filed(buf, beg, end); - }; - on_header_value_ = [this](const char* buf, size_t beg, size_t end) { - this->on_header_value(buf, beg, end); - }; - on_header_end_ = [this](const char* buf, size_t beg, size_t end) { - this->on_header_end(buf, beg, end); - }; - on_headers_end_ = [this](const char* buf, size_t beg, size_t end) { - this->on_headers_end(buf, beg, end); - }; - on_part_data_ = [this](const char* buf, size_t beg, size_t end) { - this->on_part_data(buf, beg, end); - }; - on_part_end_ = [this](const char* buf, size_t beg, size_t end) { - this->on_part_end(buf, beg, end); - }; - on_end_ = [this](const char* buf, size_t beg, size_t end) { - this->on_end(buf, beg, end); - }; + case TEXT: + texts_.insert({key_, value_}); + texts_.insert({key_, value_}); + break; + case FILE: + files_.insert({key_, value_}); + of_.close(); + break; + default: + break; // impossible } - - void index_boundary() + key_.clear(); + value_.clear(); + type_ = UNKNOWN; // re-init for next header of part + } + + void on_end(const char*, size_t, size_t) {} + + void reset_callbacks() + { + on_part_begin_ = [this](const char* buf, size_t beg, size_t end) { this->on_part_begin(buf, beg, end); }; + on_header_field_ = [this](const char* buf, size_t beg, size_t end) { this->on_header_filed(buf, beg, end); }; + on_header_value_ = [this](const char* buf, size_t beg, size_t end) { this->on_header_value(buf, beg, end); }; + on_header_end_ = [this](const char* buf, size_t beg, size_t end) { this->on_header_end(buf, beg, end); }; + on_headers_end_ = [this](const char* buf, size_t beg, size_t end) { this->on_headers_end(buf, beg, end); }; + on_part_data_ = [this](const char* buf, size_t beg, size_t end) { this->on_part_data(buf, beg, end); }; + on_part_end_ = [this](const char* buf, size_t beg, size_t end) { this->on_part_end(buf, beg, end); }; + on_end_ = [this](const char* buf, size_t beg, size_t end) { this->on_end(buf, beg, end); }; + } + + void index_boundary() + { + const char* current; + const char* end = boundary_data_ + boundary_size_; + + memset(boundary_index_, 0, sizeof(boundary_index_)); + + for(current = boundary_data_; current < end; current++) { - const char* current; - const char* end = boundary_data_ + boundary_size_; - - memset(boundary_index_, 0, sizeof(boundary_index_)); - - for(current = boundary_data_; current < end; current++) - { - boundary_index_[(unsigned char) *current] = true; - } + boundary_index_[(unsigned char)*current] = true; } + } - void callback(CallBack& cb, const char* buffer = nullptr, - size_t start = UNMARKED, - size_t end = UNMARKED, bool allow_empty = false) + void callback(CallBack& cb, const char* buffer = nullptr, size_t start = UNMARKED, size_t end = UNMARKED, + bool allow_empty = false) + { + if(start != UNMARKED && start == end && !allow_empty) { - if(start != UNMARKED && start == end && !allow_empty) - { - return; - } - if(cb) - { - cb(buffer, start, end); - } + return; } - - void data_callback(CallBack& cb, size_t& mark, const char* buf, size_t i, - size_t buf_len, - bool clear, bool allow_empty = false) + if(cb) { - if(mark == UNMARKED) - { - return; - } - - if(!clear) - { - callback(cb, buf, mark, buf_len, allow_empty); - mark = 0; - } - else - { - callback(cb, buf, mark, i, allow_empty); - mark = UNMARKED; - } + cb(buffer, start, end); } + } - char lower(char c) const + void data_callback(CallBack& cb, size_t& mark, const char* buf, size_t i, size_t buf_len, bool clear, + bool allow_empty = false) + { + if(mark == UNMARKED) { - return c | 0x20; // 'A' ~ 'Z' => 'a' ~ 'z' + return; } - inline bool is_in_boundary(char c) const + if(!clear) { - return boundary_index_[(unsigned char) c]; + callback(cb, buf, mark, buf_len, allow_empty); + mark = 0; } - - void set_error(const char* message) + else { - state_ = PARSE_ERROR; - error_reason_ = message; + callback(cb, buf, mark, i, allow_empty); + mark = UNMARKED; } + } + + char lower(char c) const + { + return c | 0x20; // 'A' ~ 'Z' => 'a' ~ 'z' + } + + inline bool is_in_boundary(char c) const { return boundary_index_[(unsigned char)c]; } + + void set_error(const char* message) + { + state_ = PARSE_ERROR; + error_reason_ = message; + } }; } #undef FALL_THROUGH -#endif //FORM_DATA_PARSER_ +#endif // FORM_DATA_PARSER_ diff --git a/format.sh b/format.sh new file mode 100755 index 0000000..c95f0bf --- /dev/null +++ b/format.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +find . -iname "*.h" -exec clang-format -style=file -i {} \; +find . -iname "*.cpp" -exec clang-format -style=file -i {} \; +find . -iname "*.cc" -exec clang-format -style=file -i {} \; + diff --git a/logging/bench.cc b/logging/bench.cc index 8a47006..4ec1ecb 100644 --- a/logging/bench.cc +++ b/logging/bench.cc @@ -4,39 +4,35 @@ class ThreadGroup { - public: - ThreadGroup() - : tg_{} - {} +public: + ThreadGroup() : tg_{} {} - ~ThreadGroup() - { - this->join_all(); - } + ~ThreadGroup() { this->join_all(); } - template void spwan(F&& f) - { - tg_.emplace_back(std::forward(f)); - } + template + void spwan(F&& f) + { + tg_.emplace_back(std::forward(f)); + } - void join_all() + void join_all() + { + try { - try + for(auto& t: tg_) { - for(auto& t: tg_) - { - if(t.joinable()) - t.join(); - } - } - catch(...) - { - // swallow + if(t.joinable()) + t.join(); } } + catch(...) + { + // swallow + } + } - private: - std::vector tg_; +private: + std::vector tg_; }; void foo() @@ -51,10 +47,7 @@ void foo() } } -auto now() -{ - return std::chrono::high_resolution_clock::now(); -} +auto now() { return std::chrono::high_resolution_clock::now(); } template auto duration(const T& dur) diff --git a/logging/logging.h b/logging/logging.h index 3acab24..8d84294 100644 --- a/logging/logging.h +++ b/logging/logging.h @@ -54,598 +54,521 @@ namespace nm { class Queue { - private: - struct Node - { - std::string data; - std::atomic next; - }; - - public: - Queue() - : head_(new Node()), - tail_(head_.load()) - { - auto tmp = head_.load(); - tmp->next.store(nullptr); - } - - ~Queue() - { - Node* tmp = nullptr; - while(tail_) - { - tmp = tail_->next.load(); - delete tail_; - tail_ = tmp; - } - tail_ = nullptr; - } + private: + struct Node + { + std::string data; + std::atomic next; + }; - void push(std::string&& data) - { - auto tmp = new Node(); - tmp->data.swap(data); - tmp->next.store(nullptr, std::memory_order_relaxed); - auto old_head = head_.exchange(tmp, std::memory_order_acq_rel); - old_head->next.store(tmp, std::memory_order_release); - } + public: + Queue() : head_(new Node()), tail_(head_.load()) + { + auto tmp = head_.load(); + tmp->next.store(nullptr); + } - bool try_pop(std::string& data) + ~Queue() + { + Node* tmp = nullptr; + while(tail_) { - auto next = tail_->next.load(std::memory_order_acquire); - if(next == nullptr) - return false; - data.swap(next->data); + tmp = tail_->next.load(); delete tail_; - tail_ = next; - return true; + tail_ = tmp; } + tail_ = nullptr; + } + + void push(std::string&& data) + { + auto tmp = new Node(); + tmp->data.swap(data); + tmp->next.store(nullptr, std::memory_order_relaxed); + auto old_head = head_.exchange(tmp, std::memory_order_acq_rel); + old_head->next.store(tmp, std::memory_order_release); + } + + bool try_pop(std::string& data) + { + auto next = tail_->next.load(std::memory_order_acquire); + if(next == nullptr) + return false; + data.swap(next->data); + delete tail_; + tail_ = next; + return true; + } - private: - std::atomic head_; - Node* tail_; + private: + std::atomic head_; + Node* tail_; }; class FileLog { - public: - constexpr static const int COUNT_DOWN{3}; - FileLog(const std::string& path, - const std::string& prefix, long interval) - : path_(path), interval_(interval), count_(now()), - time_cache_(count_), last_roll_(count_), fp_(nullptr) + public: + constexpr static const int COUNT_DOWN{3}; + FileLog(const std::string& path, const std::string& prefix, long interval) + : path_(path), interval_(interval), count_(now()), time_cache_(count_), last_roll_(count_), fp_(nullptr) + { + if(path_.empty()) { - if(path_.empty()) - { - path_ = "./"; - } - else - { - auto pos = path_.find_last_of("/"); - if(pos == path_.npos || pos +1 != path_.size()) - path_ += "/"; - } - current_log_ = path_ + "current.log"; - if(!prefix.empty()) - path_ += prefix + "_"; + path_ = "./"; } + else + { + auto pos = path_.find_last_of("/"); + if(pos == path_.npos || pos + 1 != path_.size()) + path_ += "/"; + } + current_log_ = path_ + "current.log"; + if(!prefix.empty()) + path_ += prefix + "_"; + } - FileLog(FILE* fp) - : path_(), interval_(-1), count_(now()), - time_cache_(count_), last_roll_(count_), fp_(fp) - {} + FileLog(FILE* fp) : path_(), interval_(-1), count_(now()), time_cache_(count_), last_roll_(count_), fp_(fp) {} - ~FileLog() + ~FileLog() + { + if(fp_) { - if(fp_) - { - fflush_unlocked(fp_); - fclose(fp_); - } + fflush_unlocked(fp_); + fclose(fp_); } + } - bool init() + bool init() + { + update_time(); + if(!fp_) { - update_time(); - if(!fp_) + errno = 0; + fp_ = fopen(new_name().c_str(), "a+"); + if(fp_ == nullptr) { - errno = 0; - fp_ = fopen(new_name().c_str(), "a+"); - if(fp_ == nullptr) - { - fprintf(stderr, "open '%s': %s\n", - name_cache_.c_str(), strerror(errno)); - return false; - } - this->link(); - setbuffer(fp_, buffer_, sizeof(buffer_)); + fprintf(stderr, "open '%s': %s\n", name_cache_.c_str(), strerror(errno)); + return false; } - return true; + this->link(); + setbuffer(fp_, buffer_, sizeof(buffer_)); } + return true; + } - void flush() + void flush() { fflush_unlocked(fp_); } + + void write(std::string& buffer) + { + size_t rest = buffer.size(); + if(rest == 0) + return; + size_t write_bytes = 0; + const char* data = buffer.data(); + now(); + if(tv_.tv_sec > time_cache_) + { + time_cache_ = tv_.tv_sec; + update_time(); + } + else + { + update_micro(); + } + fwrite_unlocked(time_buf_, 1, sizeof(time_buf_) - 1, fp_); + while(rest != 0) { + write_bytes = fwrite_unlocked(data, 1, rest, fp_); + data += write_bytes; + rest -= write_bytes; + } + if(time_cache_ - count_ > COUNT_DOWN) + { + count_ = time_cache_; fflush_unlocked(fp_); } - - void write(std::string& buffer) + if(interval_ <= 0) + return; + if(time_cache_ - last_roll_ > interval_) { - size_t rest = buffer.size(); - if(rest == 0) - return; - size_t write_bytes = 0; - const char* data = buffer.data(); - now(); - if(tv_.tv_sec > time_cache_) + last_roll_ = time_cache_; + fflush(fp_); + errno = 0; + update_time(); + this->new_name(); + FILE* tmp = fopen(name_cache_.c_str(), "a+"); + if(!tmp) { - time_cache_ = tv_.tv_sec; - update_time(); + fprintf(stderr, "open '%s': %s\n", name_cache_.c_str(), strerror(errno)); } else { - update_micro(); - } - fwrite_unlocked(time_buf_, 1, sizeof(time_buf_) - 1, fp_); - while(rest != 0) - { - write_bytes = fwrite_unlocked(data, 1, rest, fp_); - data += write_bytes; - rest -= write_bytes; - } - if(time_cache_ - count_ > COUNT_DOWN) - { - count_ = time_cache_; - fflush_unlocked(fp_); - } - if(interval_ <= 0) - return; - if(time_cache_ - last_roll_ > interval_) - { - last_roll_ = time_cache_; - fflush(fp_); - errno = 0; - update_time(); - this->new_name(); - FILE* tmp = fopen(name_cache_.c_str(), "a+"); - if(!tmp) - { - fprintf(stderr, "open '%s': %s\n", - name_cache_.c_str(), strerror(errno)); - } - else - { - fclose(fp_); - this->link(); - fp_ = tmp; - setbuffer(fp_, buffer_, sizeof(buffer_)); - } + fclose(fp_); + this->link(); + fp_ = tmp; + setbuffer(fp_, buffer_, sizeof(buffer_)); } } + } - private: - std::string path_; - const long interval_; - long count_; - long time_cache_; - long last_roll_; - FILE* fp_; - std::string name_cache_; - std::string current_log_; - std::string data_{}; - char buffer_[64 * 1024]; - char time_buf_[25]; - char pid_buf_[10]; - timeval tv_; - tm tm_; - - void link() - { - unlink(current_log_.c_str()); - int res = symlink(new_name().c_str(), current_log_.c_str()); - (void)res; - } - - void update_time() - { - localtime_r(&tv_.tv_sec, &tm_); - snprintf(time_buf_, sizeof(time_buf_), - "%04d%02d%02d %02d:%02d:%02d.%06ld", - tm_.tm_year + 1900, tm_.tm_mon + 1, tm_.tm_mday, - tm_.tm_hour, tm_.tm_min, tm_.tm_sec, tv_.tv_usec); + private: + std::string path_; + const long interval_; + long count_; + long time_cache_; + long last_roll_; + FILE* fp_; + std::string name_cache_; + std::string current_log_; + std::string data_{}; + char buffer_[64 * 1024]; + char time_buf_[25]; + char pid_buf_[10]; + timeval tv_; + tm tm_; + + void link() + { + unlink(current_log_.c_str()); + int res = symlink(new_name().c_str(), current_log_.c_str()); + (void)res; + } - } + void update_time() + { + localtime_r(&tv_.tv_sec, &tm_); + snprintf(time_buf_, sizeof(time_buf_), "%04d%02d%02d %02d:%02d:%02d.%06ld", tm_.tm_year + 1900, tm_.tm_mon + 1, + tm_.tm_mday, tm_.tm_hour, tm_.tm_min, tm_.tm_sec, tv_.tv_usec); + } - void update_micro() - { - snprintf(time_buf_ + 18, 7, "%06ld", tv_.tv_usec); - } + void update_micro() { snprintf(time_buf_ + 18, 7, "%06ld", tv_.tv_usec); } - long now() - { - gettimeofday(&tv_, nullptr); - return tv_.tv_sec; - } + long now() + { + gettimeofday(&tv_, nullptr); + return tv_.tv_sec; + } - std::string& new_name() - { - name_cache_.clear(); - char buf[30] = {0}; - memset(pid_buf_, 0, sizeof(pid_buf_)); - sprintf(pid_buf_, "%d", getpid()); - int res = snprintf(buf, sizeof(buf), - "%04d%02d%02d-%02d%02d%02d.%d.log", - tm_.tm_year + 1900, tm_.tm_mon + 1, - tm_.tm_mday, tm_.tm_hour, tm_.tm_min, - tm_.tm_sec, getpid()); - name_cache_ = path_; - name_cache_.append(buf, res); - return name_cache_; - } + std::string& new_name() + { + name_cache_.clear(); + char buf[30] = {0}; + memset(pid_buf_, 0, sizeof(pid_buf_)); + sprintf(pid_buf_, "%d", getpid()); + int res = snprintf(buf, sizeof(buf), "%04d%02d%02d-%02d%02d%02d.%d.log", tm_.tm_year + 1900, tm_.tm_mon + 1, + tm_.tm_mday, tm_.tm_hour, tm_.tm_min, tm_.tm_sec, getpid()); + name_cache_ = path_; + name_cache_.append(buf, res); + return name_cache_; + } }; template class Stream { - public: - Stream() = default; - ~Stream() = default; - Stream(const Stream&) = delete; - Stream(Stream&&) = delete; - Stream& operator= (const Stream&) = delete; - Stream& operator= (Stream&&) = delete; - - Stream& operator<< (const std::nullptr_t&) - { - return *this; - } + public: + Stream() = default; + ~Stream() = default; + Stream(const Stream&) = delete; + Stream(Stream&&) = delete; + Stream& operator=(const Stream&) = delete; + Stream& operator=(Stream&&) = delete; - Stream& operator<< (const char* s) - { - if(s) - { - append(s, std::char_traits::length(s)); - } - return *this; - } + Stream& operator<<(const std::nullptr_t&) { return *this; } - Stream& operator<< (const unsigned char* s) - { - return this->operator<<(reinterpret_cast(s)); - } - - Stream& operator<< (const std::string& data) + Stream& operator<<(const char* s) + { + if(s) { - append(data.c_str(), data.size()); - return *this; + append(s, std::char_traits::length(s)); } + return *this; + } - Stream& operator<< (const char c) - { - append(&c, 1); - return *this; - } + Stream& operator<<(const unsigned char* s) { return this->operator<<(reinterpret_cast(s)); } - Stream& operator<< (const short data) - { - return this->fmt(data); - } + Stream& operator<<(const std::string& data) + { + append(data.c_str(), data.size()); + return *this; + } - Stream& operator<< (const int data) - { - return this->fmt(data); - } + Stream& operator<<(const char c) + { + append(&c, 1); + return *this; + } - Stream& operator<< (const long data) - { - return this->fmt(data); - } + Stream& operator<<(const short data) { return this->fmt(data); } - Stream& operator<< (const long long data) - { - return this->fmt(data); - } + Stream& operator<<(const int data) { return this->fmt(data); } - Stream& operator<< (const unsigned short data) - { - return this->fmt(data); - } + Stream& operator<<(const long data) { return this->fmt(data); } - Stream& operator<< (const unsigned int data) - { - return this->fmt(data); - } + Stream& operator<<(const long long data) { return this->fmt(data); } - Stream& operator<< (const unsigned long data) - { - return this->fmt(data); - } + Stream& operator<<(const unsigned short data) { return this->fmt(data); } - Stream& operator<< (const unsigned char data) - { - if(data > std::numeric_limits::max()) - return this->operator<<(static_cast(data)); - return this->operator<<(static_cast(data)); - } + Stream& operator<<(const unsigned int data) { return this->fmt(data); } - Stream& operator<< (const unsigned long long data) - { - return this->fmt(data); - } + Stream& operator<<(const unsigned long data) { return this->fmt(data); } - Stream& operator<< (const float data) - { - return this->fmt("%.6g", data); - } + Stream& operator<<(const unsigned char data) + { + if(data > std::numeric_limits::max()) + return this->operator<<(static_cast(data)); + return this->operator<<(static_cast(data)); + } - Stream& operator<< (const double data) - { - return this->fmt("%.10g", data); - } + Stream& operator<<(const unsigned long long data) { return this->fmt(data); } - Stream& operator<< (const void* data) - { - auto p = reinterpret_cast(data); - fmt_buf_[0] = '0'; - fmt_buf_[1] = 'x'; - fmt_len_ = convertHex(fmt_buf_ + 2, p); - append(fmt_buf_, fmt_len_ + 2); - return *this; - } + Stream& operator<<(const float data) { return this->fmt("%.6g", data); } - void append(const char* s, size_t n) - { - if(n + pos_ < SIZE) - { - std::memcpy(buffer_ + pos_, s, n); - pos_ += n; - } - } + Stream& operator<<(const double data) { return this->fmt("%.10g", data); } - // truncate, if message is too long. - std::string str() - { - return {buffer_, pos_}; - } + Stream& operator<<(const void* data) + { + auto p = reinterpret_cast(data); + fmt_buf_[0] = '0'; + fmt_buf_[1] = 'x'; + fmt_len_ = convertHex(fmt_buf_ + 2, p); + append(fmt_buf_, fmt_len_ + 2); + return *this; + } - void clear() + void append(const char* s, size_t n) + { + if(n + pos_ < SIZE) { - pos_ = 0; + std::memcpy(buffer_ + pos_, s, n); + pos_ += n; } + } - private: - char fmt_buf_[32] = {0}; - int fmt_len_{0}; - size_t pos_{0}; - char buffer_[SIZE]; + // truncate, if message is too long. + std::string str() { return {buffer_, pos_}; } - const char* const digits = "9876543210123456789"; - const char* const digitsHex = "0123456789abcdef"; - const char* zero = digits + 9; + void clear() { pos_ = 0; } - template - size_t convert(char buf[], const T value) - { - T i = value; - char* p = buf; + private: + char fmt_buf_[32] = {0}; + int fmt_len_{0}; + size_t pos_{0}; + char buffer_[SIZE]; - do { - int lsd = static_cast(i % 10); - i /= 10; - *p++ = zero[lsd]; // maybe negative index - } while (i != 0); + const char* const digits = "9876543210123456789"; + const char* const digitsHex = "0123456789abcdef"; + const char* zero = digits + 9; - if (value < 0) { - *p++ = '-'; - } - *p = '\0'; - std::reverse(buf, p); - return p - buf; - } + template + size_t convert(char buf[], const T value) + { + T i = value; + char* p = buf; - size_t convertHex(char buf[], uintptr_t value) + do { - uintptr_t i = value; - char* p = buf; - - do - { - int lsd = static_cast(i % 16); - i /= 16; - *p++ = digitsHex[lsd]; - } while (i != 0); - - *p = '\0'; - std::reverse(buf, p); - return p - buf; - } + int lsd = static_cast(i % 10); + i /= 10; + *p++ = zero[lsd]; // maybe negative index + } while(i != 0); - template - Stream& fmt(T data) + if(value < 0) { - size_t res = this->convert(fmt_buf_, data); - append(fmt_buf_, res); - return *this; + *p++ = '-'; } + *p = '\0'; + std::reverse(buf, p); + return p - buf; + } + + size_t convertHex(char buf[], uintptr_t value) + { + uintptr_t i = value; + char* p = buf; - Stream& fmt(const char* format, double data) + do { - fmt_len_ = snprintf(fmt_buf_, sizeof(fmt_buf_), format, data); - append(fmt_buf_, fmt_len_); - return *this; - } + int lsd = static_cast(i % 16); + i /= 16; + *p++ = digitsHex[lsd]; + } while(i != 0); + + *p = '\0'; + std::reverse(buf, p); + return p - buf; + } + + template + Stream& fmt(T data) + { + size_t res = this->convert(fmt_buf_, data); + append(fmt_buf_, res); + return *this; + } + + Stream& fmt(const char* format, double data) + { + fmt_len_ = snprintf(fmt_buf_, sizeof(fmt_buf_), format, data); + append(fmt_buf_, fmt_len_); + return *this; + } }; using StreamBuffer = Stream<4096>; class LoggerBackend { - public: - LoggerBackend() - : queue_(), log_(nullptr), tid_() - {} + public: + LoggerBackend() : queue_(), log_(nullptr), tid_() {} - ~LoggerBackend() - { - this->join(); - } - LoggerBackend(const LoggerBackend&) = delete; - LoggerBackend(LoggerBackend&&) = delete; - LoggerBackend& operator= (const LoggerBackend&) = delete; - LoggerBackend& operator= (LoggerBackend&&) = delete; + ~LoggerBackend() { this->join(); } + LoggerBackend(const LoggerBackend&) = delete; + LoggerBackend(LoggerBackend&&) = delete; + LoggerBackend& operator=(const LoggerBackend&) = delete; + LoggerBackend& operator=(LoggerBackend&&) = delete; - void init(FILE* fp, const char* path, const char* prefix, - long interval, bool is_sync) - { - std::call_once(once_, [&, this] - { - create_logger(fp, path, prefix, interval, is_sync); - if(is_sync) - writer_ = [this](StreamBuffer& ss) { sync_write(ss); }; - else - writer_ = [this](StreamBuffer& ss) { async_write(ss); }; - }); - } + void init(FILE* fp, const char* path, const char* prefix, long interval, bool is_sync) + { + std::call_once(once_, [&, this] { + create_logger(fp, path, prefix, interval, is_sync); + if(is_sync) + writer_ = [this](StreamBuffer& ss) { sync_write(ss); }; + else + writer_ = [this](StreamBuffer& ss) { async_write(ss); }; + }); + } - bool ok() - { - return ok_; - } + bool ok() { return ok_; } - void consume(StreamBuffer& ss) - { - writer_(ss); - } + void consume(StreamBuffer& ss) { writer_(ss); } - void join() + void join() + { + if(tid_.joinable()) { - if(tid_.joinable()) { - { - std::lock_guard lg(mtx_); - running_ = false; - cond_.notify_one(); - } - try { tid_.join(); } catch(const std::system_error&) {} + std::lock_guard lg(mtx_); + running_ = false; + cond_.notify_one(); + } + try + { + tid_.join(); + } + catch(const std::system_error&) + { } } + } - private: - Queue queue_; - std::unique_ptr log_; - std::thread tid_; - bool ok_{true}; - std::mutex mtx_; - std::condition_variable cond_; - std::chrono::seconds timeout_{FileLog::COUNT_DOWN}; - bool running_{true}; - bool need_notify_{false}; - std::function writer_; - std::once_flag once_; - - void sync_write(StreamBuffer& ss) - { - std::lock_guard lg(mtx_); - std::string data{ss.str()}; - log_->write(data); - } + private: + Queue queue_; + std::unique_ptr log_; + std::thread tid_; + bool ok_{true}; + std::mutex mtx_; + std::condition_variable cond_; + std::chrono::seconds timeout_{FileLog::COUNT_DOWN}; + bool running_{true}; + bool need_notify_{false}; + std::function writer_; + std::once_flag once_; + + void sync_write(StreamBuffer& ss) + { + std::lock_guard lg(mtx_); + std::string data{ss.str()}; + log_->write(data); + } - void async_write(StreamBuffer& ss) + void async_write(StreamBuffer& ss) + { + queue_.push(ss.str()); + if(need_notify_) { - queue_.push(ss.str()); - if(need_notify_) - { - cond_.notify_one(); - } + cond_.notify_one(); } + } - void create_logger(FILE* fp, const char* path, const char* prefix, - long interval, bool is_sync) + void create_logger(FILE* fp, const char* path, const char* prefix, long interval, bool is_sync) + { + if(path == nullptr) + path = ""; + if(prefix == nullptr) + prefix = ""; + char* res = getenv("LOG_TYPE"); + std::string env; + if(res != nullptr) + env = res; + bool is_stdout = (env == "custom") && fp != nullptr; + if(is_sync) + log_sync(fp, path, prefix, interval, is_stdout); + else + log_async(fp, path, prefix, interval, is_stdout); + } + + void log_sync(FILE* fp, const char* path, const char* prefix, long interval, bool is_stdout) + { + if(is_stdout) { - if(path == nullptr) - path = ""; - if(prefix == nullptr) - prefix = ""; - char* res = getenv("LOG_TYPE"); - std::string env; - if(res != nullptr) - env = res; - bool is_stdout = (env == "custom") && fp != nullptr; - if(is_sync) - log_sync(fp, path, prefix, interval, is_stdout); - else - log_async(fp, path, prefix, interval, is_stdout); + log_.reset(new FileLog(fp)); + log_->init(); } - - void log_sync(FILE* fp, const char* path, const char* prefix, - long interval, bool is_stdout) + else { - if(is_stdout) - { - log_.reset(new FileLog(fp)); - log_->init(); - } - else + log_.reset(new FileLog(path, prefix, interval)); + if(!log_->init()) { - log_.reset(new FileLog(path, prefix, interval)); - if(!log_->init()) - { - ok_ = false; - return; - } + ok_ = false; + return; } } + } - void thread_func() + void thread_func() + { + std::string data; + while(running_) { - std::string data; - while(running_) - { - while(queue_.try_pop(data)) - { - log_->write(data); - } - data.clear(); - need_notify_ = true; - std::unique_lock lk(mtx_); - cond_.wait_for(lk, timeout_, [this, &data] { - return queue_.try_pop(data) || !running_; - }); - need_notify_ = false; - log_->write(data); - log_->flush(); - } while(queue_.try_pop(data)) { log_->write(data); } + data.clear(); + need_notify_ = true; + std::unique_lock lk(mtx_); + cond_.wait_for(lk, timeout_, [this, &data] { return queue_.try_pop(data) || !running_; }); + need_notify_ = false; + log_->write(data); log_->flush(); } + while(queue_.try_pop(data)) + { + log_->write(data); + } + log_->flush(); + } - void log_async(FILE* fp, const char* path, const char* prefix, - long interval, bool is_stdout) + void log_async(FILE* fp, const char* path, const char* prefix, long interval, bool is_stdout) + { + if(is_stdout) { - if(is_stdout) - { - log_.reset(new FileLog(fp)); - log_->init(); - tid_ = std::thread([this] { - thread_func(); - }); - } - else + log_.reset(new FileLog(fp)); + log_->init(); + tid_ = std::thread([this] { thread_func(); }); + } + else + { + log_.reset(new FileLog(path, prefix, interval)); + if(!log_->init()) { - log_.reset(new FileLog(path, prefix, interval)); - if(!log_->init()) - { - ok_ = false; - return; - } - tid_ = std::thread([this] { - thread_func(); - }); + ok_ = false; + return; } + tid_ = std::thread([this] { thread_func(); }); } + } }; } } @@ -660,108 +583,112 @@ namespace nm #endif class Logger { - public: - struct Dummy - { - template Dummy& operator<< (const T&) { return *this; } - }; - enum Level { INFO = 0, WARNING, DEBUG, ERR, FATAL }; - // default interval is 24hr in seconds, minimum duration is 1s. - static bool create_async(FILE* fp = stderr, const char* path = "", - const char* prefix = "", - long interval = 60 * 60 * 24) - { - if(disable_log_) - return true; - backend_.init(fp, path, prefix, interval, false); - return backend_.ok(); - } - static bool create_sync(FILE* fp = stderr, const char* path = "", - const char* prefix = "", - long interval = 60 * 60 * 24) - { - if(disable_log_) - return true; - backend_.init(fp, path, prefix, interval, true); - return backend_.ok(); - } - - // manually wait async operations complete. - static void join() { backend_.join(); } - - Logger(const char* file, long line, const char* func, Level level) - { - ss_ << ' ' << get_tid() - << MSG[level] << basename(file) << ':' << line << ' '; - if(func) - ss_ << '`' << func << "` "; - } - - // string literal goes here, and string sequence too, - // but string sequence without line terminator(i.e. '\0') - // may cause unexpected result. - template Logger& operator<< (const char (&a)[LEN]) - { - ss_.append(a, LEN - 1); - return *this; - } - - // non string literal and others. - template Logger& operator<< (const T& data) + public: + struct Dummy + { + template + Dummy& operator<<(const T&) { - ss_ << data; return *this; } + }; + enum Level + { + INFO = 0, + WARNING, + DEBUG, + ERR, + FATAL + }; + // default interval is 24hr in seconds, minimum duration is 1s. + static bool create_async(FILE* fp = stderr, const char* path = "", const char* prefix = "", + long interval = 60 * 60 * 24) + { + if(disable_log_) + return true; + backend_.init(fp, path, prefix, interval, false); + return backend_.ok(); + } + static bool create_sync(FILE* fp = stderr, const char* path = "", const char* prefix = "", + long interval = 60 * 60 * 24) + { + if(disable_log_) + return true; + backend_.init(fp, path, prefix, interval, true); + return backend_.ok(); + } - ~Logger() - { - ss_ << '\n'; - backend_.consume(ss_); - ss_.clear(); - } + // manually wait async operations complete. + static void join() { backend_.join(); } - Logger(const Logger&) = delete; - Logger(Logger&&) = delete; - Logger& operator= (const Logger&) = delete; - Logger& operator= (Logger&&) = delete; + Logger(const char* file, long line, const char* func, Level level) + { + ss_ << ' ' << get_tid() << MSG[level] << basename(file) << ':' << line << ' '; + if(func) + ss_ << '`' << func << "` "; + } + + // string literal goes here, and string sequence too, + // but string sequence without line terminator(i.e. '\0') + // may cause unexpected result. + template + Logger& operator<<(const char (&a)[LEN]) + { + ss_.append(a, LEN - 1); + return *this; + } - private: - thread_local inline static meta::StreamBuffer ss_{}; - static inline meta::LoggerBackend backend_{}; - static inline const char* MSG[] = { - " [INFO] ", - " [WARN] ", - " [DEBUG] ", - " [ERROR] ", - " [FATAL] " - }; + // non string literal and others. + template + Logger& operator<<(const T& data) + { + ss_ << data; + return *this; + } - int get_tid() - { + ~Logger() + { + ss_ << '\n'; + backend_.consume(ss_); + ss_.clear(); + } + + Logger(const Logger&) = delete; + Logger(Logger&&) = delete; + Logger& operator=(const Logger&) = delete; + Logger& operator=(Logger&&) = delete; + + private: + thread_local inline static meta::StreamBuffer ss_{}; + static inline meta::LoggerBackend backend_{}; + static inline const char* MSG[] = {" [INFO] ", " [WARN] ", " [DEBUG] ", " [ERROR] ", " [FATAL] "}; + + int get_tid() + { #ifdef __APPLE__ - return static_cast(syscall(SYS_thread_selfid)); + return static_cast(syscall(SYS_thread_selfid)); #elif defined(__FreeBSD__) - long res = 0; - thr_self(&res); - return static_cast(res); + long res = 0; + thr_self(&res); + return static_cast(res); #else - return static_cast(syscall(SYS_gettid)); + return static_cast(syscall(SYS_gettid)); #endif - } + } }; #ifndef NOLOG - #define log_info() nm::Logger(__FILE__, __LINE__, nullptr, nm::Logger::INFO) - #define log_warn() nm::Logger(__FILE__, __LINE__, nullptr, nm::Logger::WARNING) - #define log_debug() nm::Logger(__FILE__, __LINE__, __func__, nm::Logger::DEBUG) - #define log_err() nm::Logger(__FILE__, __LINE__, __func__, nm::Logger::ERR) - #define log_fatal() nm::Logger(__FILE__, __LINE__, __func__, nm::Logger::FATAL) +#define log_info() nm::Logger(__FILE__, __LINE__, nullptr, nm::Logger::INFO) +#define log_warn() nm::Logger(__FILE__, __LINE__, nullptr, nm::Logger::WARNING) +#define log_debug() nm::Logger(__FILE__, __LINE__, __func__, nm::Logger::DEBUG) +#define log_err() nm::Logger(__FILE__, __LINE__, __func__, nm::Logger::ERR) +#define log_fatal() nm::Logger(__FILE__, __LINE__, __func__, nm::Logger::FATAL) #else - #define log_info() nm::Logger::Dummy() - #define log_warn() log_info() - #define log_debug() log_info() - #define log_err() log_info() - #define log_fatal() log_info() +#define log_info() nm::Logger::Dummy() +#define log_warn() log_info() +#define log_debug() log_info() +#define log_err() log_info() +#define log_fatal() log_info() #endif } diff --git a/logging/test.cpp b/logging/test.cpp index bf628e8..2506ac5 100644 --- a/logging/test.cpp +++ b/logging/test.cpp @@ -28,11 +28,11 @@ int main(int argc, char* argv[]) tg.emplace_back([] { for(int j = 0; j < 200; ++j) { - log_info() << "test info " << 233 << " "<< true; + log_info() << "test info " << 233 << " " << true; log_warn() << "test warning " << 233 << " " << false; - log_debug() << "test debug " << -1 << " "<< true; - log_err() << "test error " << &j << " "<< true; - log_fatal() << "test +1s " << 233 << " "<< false; + log_debug() << "test debug " << -1 << " " << true; + log_err() << "test error " << &j << " " << true; + log_fatal() << "test +1s " << 233 << " " << false; } }); } diff --git a/loop_per_thread/client.cpp b/loop_per_thread/client.cpp index 4dc5d00..97282da 100644 --- a/loop_per_thread/client.cpp +++ b/loop_per_thread/client.cpp @@ -18,96 +18,81 @@ using Callback = std::function; class Client : boost::noncopyable { - public: - Client(io_service& io, tcp::endpoint&& ep) - : repeat_(1000), - limit_(1000), - old_limit_(limit_), - ep_(std::move(ep)), - socket_(io, ep_.protocol()), - write_buf_("ping\n", 5), - cb_() - { - socket_.connect(ep_); - } +public: + Client(io_service& io, tcp::endpoint&& ep) + : repeat_(1000), limit_(1000), old_limit_(limit_), ep_(std::move(ep)), socket_(io, ep_.protocol()), + write_buf_("ping\n", 5), cb_() + { + socket_.connect(ep_); + } - ~Client() - { - socket_.shutdown(socket_.shutdown_both); - socket_.close(); - } + ~Client() + { + socket_.shutdown(socket_.shutdown_both); + socket_.close(); + } - void set_callback(Callback&& cb) - { - cb_ = std::move(cb); - } + void set_callback(Callback&& cb) { cb_ = std::move(cb); } + + void run() { handle_write(); } + +private: + int repeat_; + int limit_; + int old_limit_; + tcp::endpoint ep_; + tcp::socket socket_; + boost::asio::streambuf buf_; + boost::asio::const_buffers_1 write_buf_; + Callback cb_; + std::string msg_; - void run() + void reconnect() + { + repeat_ -= 1; + limit_ = old_limit_; + socket_.shutdown(socket_.shutdown_both); + socket_.close(); + socket_.connect(ep_); + if(repeat_ > 0) { handle_write(); } + } - private: - int repeat_; - int limit_; - int old_limit_; - tcp::endpoint ep_; - tcp::socket socket_; - boost::asio::streambuf buf_; - boost::asio::const_buffers_1 write_buf_; - Callback cb_; - std::string msg_; - - void reconnect() - { - repeat_ -= 1; - limit_ = old_limit_; - socket_.shutdown(socket_.shutdown_both); - socket_.close(); - socket_.connect(ep_); - if(repeat_ > 0) + void handle_read() + { + async_read_until(socket_, buf_, '\n', [this](const error_code& ec, size_t) { + if(!ec) { - handle_write(); + if(limit_ == 0 && repeat_ > 0) + { + reconnect(); + } + else + { + if(cb_) + cb_(buf_); + limit_ -= 1; + handle_write(); + } } - } - - void handle_read() - { - async_read_until(socket_, buf_, '\n', - [this](const error_code& ec, size_t) - { - if(!ec) - { - if(limit_ == 0 && repeat_ > 0) - { - reconnect(); - } - else - { - if(cb_) - cb_(buf_); - limit_ -= 1; - handle_write(); - } - } - }); - } + }); + } - void handle_write() - { - socket_.async_write_some(write_buf_, - [this](const error_code& ec, size_t) - { - if(!ec) - handle_read(); - }); - } + void handle_write() + { + socket_.async_write_some(write_buf_, [this](const error_code& ec, size_t) { + if(!ec) + handle_read(); + }); + } }; int main() { std::threadpool pool{std::launch::deferred}; - auto func = []{ + auto func = [] { io_service io; Client cl(io, tcp::endpoint(address::from_string("127.0.0.1"), 8888)); try diff --git a/loop_per_thread/server.cpp b/loop_per_thread/server.cpp index 2fc6fac..504930e 100644 --- a/loop_per_thread/server.cpp +++ b/loop_per_thread/server.cpp @@ -22,100 +22,80 @@ using Callback = std::function; template class Circle { - private: - struct Node - { - T data; - Node* next; - Node() - : data(), next(nullptr) - {} - }; +private: + struct Node + { + T data; + Node* next; + Node() : data(), next(nullptr) {} + }; + +public: + class iterator + { public: - class iterator + iterator(Node* n) : data_(n) {} + + iterator& operator++() { - public: - iterator(Node* n) - : data_(n) - {} - - iterator& operator++ () - { - data_ = data_->next; - return *this; - } - - T* operator-> () - { - return &data_->data; - } - - iterator& operator= (const iterator& rhs) - { - if(this == &rhs) - return *this; - this->data_ = rhs.data_; - return *this; - } - - bool operator== (const iterator& rhs) - { - return data_ == rhs.data_; - } - - bool operator!= (const iterator& rhs) - { - return data_ != rhs.data_; - } - - private: - Node* data_; - }; - Circle(size_t capacity) - : size_(capacity), circle_(nullptr) + data_ = data_->next; + return *this; + } + + T* operator->() { return &data_->data; } + + iterator& operator=(const iterator& rhs) { - for(size_t i = 0; i < size_; ++i) - { - if(circle_ == nullptr) - { - circle_ = new Node; - circle_->next = circle_; - continue; - } - Node* tmp = new Node; - tmp->next = circle_->next; - circle_->next = tmp; - } + if(this == &rhs) + return *this; + this->data_ = rhs.data_; + return *this; } - ~Circle() + bool operator==(const iterator& rhs) { return data_ == rhs.data_; } + + bool operator!=(const iterator& rhs) { return data_ != rhs.data_; } + + private: + Node* data_; + }; + Circle(size_t capacity) : size_(capacity), circle_(nullptr) + { + for(size_t i = 0; i < size_; ++i) { - auto head = circle_->next; - Node* tmp = nullptr; - while(head != circle_) + if(circle_ == nullptr) { - tmp = head; - head = head->next; - delete tmp; + circle_ = new Node; + circle_->next = circle_; + continue; } - delete head; + Node* tmp = new Node; + tmp->next = circle_->next; + circle_->next = tmp; } + } - iterator iter() + ~Circle() + { + auto head = circle_->next; + Node* tmp = nullptr; + while(head != circle_) { - return iterator(circle_); + tmp = head; + head = head->next; + delete tmp; } + delete head; + } - size_t size() const - { - return size_; - } + iterator iter() { return iterator(circle_); } - private: - size_t size_; - Node* circle_; -}; + size_t size() const { return size_; } +private: + size_t size_; + Node* circle_; +}; /// \brief User defined business processing unit /** @@ -126,73 +106,54 @@ class Circle */ class Session : public std::enable_shared_from_this { - public: - static std::shared_ptr make_session(io_service& io) - { - return std::make_shared(io); - } +public: + static std::shared_ptr make_session(io_service& io) { return std::make_shared(io); } - Session(io_service& io) - : socket_(io), cb_() - { - } + Session(io_service& io) : socket_(io), cb_() {} - ~Session() - { - if(socket_.is_open()) - socket_.close(); - } + ~Session() + { + if(socket_.is_open()) + socket_.close(); + } - tcp::socket& socket() - { - return socket_; - } + tcp::socket& socket() { return socket_; } - void set_callback(Callback&& cb) - { - cb_ = std::move(cb); - } + void set_callback(Callback&& cb) { cb_ = std::move(cb); } - void run() - { - do_read(); - } + void run() { do_read(); } - private: - tcp::socket socket_; - Callback cb_; - boost::asio::streambuf buf_; +private: + tcp::socket socket_; + Callback cb_; + boost::asio::streambuf buf_; - void do_read() - { - // NOTE: client may never send a '\n' - async_read_until(socket_, buf_, '\n', - [this, self = shared_from_this()](const error_code& ec, size_t) - { - if(ec) - { - //std::cerr << ec.message() << std::endl; - return; - } - processing(); - }); - } + void do_read() + { + // NOTE: client may never send a '\n' + async_read_until(socket_, buf_, '\n', [this, self = shared_from_this()](const error_code& ec, size_t) { + if(ec) + { + // std::cerr << ec.message() << std::endl; + return; + } + processing(); + }); + } - void processing() - { - async_write(socket_, buf_, - [this, self = shared_from_this()](const error_code& ec, size_t) - { - if(ec) - { - //std::cerr << ec.message() << std::endl; - return; - } - do_read(); - if(cb_) - cb_(); - }); - } + void processing() + { + async_write(socket_, buf_, [this, self = shared_from_this()](const error_code& ec, size_t) { + if(ec) + { + // std::cerr << ec.message() << std::endl; + return; + } + do_read(); + if(cb_) + cb_(); + }); + } }; using SessionPtr = std::shared_ptr; @@ -205,111 +166,91 @@ using SessionPtr = std::shared_ptr; */ class Worker { - public: - Worker() - : circle_(std::thread::hardware_concurrency()), - iter_(circle_.iter()) +public: + Worker() : circle_(std::thread::hardware_concurrency()), iter_(circle_.iter()) + { + for(size_t i = 0; i < circle_.size(); ++i) { - for(size_t i = 0; i < circle_.size(); ++i) - { - workers_.emplace_back([&, idx = i]() mutable { - auto task = circle_.iter(); - while(idx--) - ++task; - task->run(); - }); - } + workers_.emplace_back([&, idx = i]() mutable { + auto task = circle_.iter(); + while(idx--) + ++task; + task->run(); + }); } + } - ~Worker() + ~Worker() + { + for(auto& t: workers_) { - for(auto& t: workers_) + try + { + t.join(); + } + catch(std::system_error&) { - try - { - t.join(); - } - catch(std::system_error&) - { - // swallow exception - } + // swallow exception } } + } + + io_service& get_io_service() { return iter_->get_io_service(); } - io_service& get_io_service() + void enqueue(SessionPtr session) { dispatch(session); } + + void stop() + { + for(size_t i = 0; i < circle_.size(); ++i) { - return iter_->get_io_service(); + iter_->stop(); + ++iter_; } + } + +private: + class Task + { + public: + Task() : strand_(io_), work_(new io_service::work(io_)) {} + + ~Task() {} - void enqueue(SessionPtr session) + io_service& get_io_service() { return io_; } + + // fuck proactor! + void dispatch(SessionPtr session) { - dispatch(session); + strand_.dispatch([session] { session->run(); }); } void stop() { - for(size_t i = 0; i < circle_.size(); ++i) - { - iter_->stop(); - ++iter_; - } + work_.reset(); + io_.stop(); } + void run() { io_.run(); } + private: - class Task - { - public: - Task() - : strand_(io_), - work_(new io_service::work(io_)) - {} - - ~Task() - {} - - io_service& get_io_service() - { - return io_; - } - - // fuck proactor! - void dispatch(SessionPtr session) - { - strand_.dispatch([session] { - session->run(); - }); - } - - void stop() - { - work_.reset(); - io_.stop(); - } - - void run() - { - io_.run(); - } - - private: - io_service io_; + io_service io_; #if BOOST_VERSION >= 106600 - boost::asio::io_service::strand strand_; + boost::asio::io_service::strand strand_; #else - boost::asio::strand strand_; + boost::asio::strand strand_; #endif - std::unique_ptr work_; - }; + std::unique_ptr work_; + }; - Circle circle_; - Circle::iterator iter_; - std::vector workers_; + Circle circle_; + Circle::iterator iter_; + std::vector workers_; - void dispatch(SessionPtr session) - { - iter_->dispatch(session); - ++iter_; - } + void dispatch(SessionPtr session) + { + iter_->dispatch(session); + ++iter_; + } }; using WorkerPtr = std::shared_ptr; @@ -322,59 +263,51 @@ using WorkerPtr = std::shared_ptr; */ class Manager { - public: - Manager(io_service& io, tcp::endpoint&& ep, unsigned long num) - : num_(num), - cur_(0), - acceptor_(io, std::move(ep), true) - { - for(unsigned long i = 0; i < num_; ++i) - workers_.emplace_back(std::make_shared()); +public: + Manager(io_service& io, tcp::endpoint&& ep, unsigned long num) + : num_(num), cur_(0), acceptor_(io, std::move(ep), true) + { + for(unsigned long i = 0; i < num_; ++i) + workers_.emplace_back(std::make_shared()); - acceptor_.listen(); - start_accept(); - } + acceptor_.listen(); + start_accept(); + } - ~Manager() - {} + ~Manager() {} - void stop() - { - acceptor_.cancel(); - for(auto& x: workers_) - x->stop(); - } + void stop() + { + acceptor_.cancel(); + for(auto& x: workers_) + x->stop(); + } - private: - unsigned long num_; - unsigned long cur_; - tcp::acceptor acceptor_; - std::vector workers_; - - void accept_handle(SessionPtr session, - WorkerPtr worker, - const error_code& ec) - { - if(!ec) - { - ++cur_; - worker->enqueue(session); - start_accept(); - } - } +private: + unsigned long num_; + unsigned long cur_; + tcp::acceptor acceptor_; + std::vector workers_; - void start_accept() + void accept_handle(SessionPtr session, WorkerPtr worker, const error_code& ec) + { + if(!ec) { - if(cur_ == num_) - cur_ = 0; - auto worker = workers_.at(cur_); - auto session(Session::make_session(worker->get_io_service())); - acceptor_.async_accept(session->socket(), - [this, session, worker](const error_code& ec) - { - accept_handle(session, worker, ec); - }); + ++cur_; + worker->enqueue(session); + start_accept(); } + } + + void start_accept() + { + if(cur_ == num_) + cur_ = 0; + auto worker = workers_.at(cur_); + auto session(Session::make_session(worker->get_io_service())); + acceptor_.async_accept(session->socket(), + [this, session, worker](const error_code& ec) { accept_handle(session, worker, ec); }); + } }; /// \brief A wrapper class for users @@ -385,37 +318,32 @@ class Manager */ class Server { - public: - Server(tcp::endpoint&& ep, unsigned long num = 1) - : sg_(io_), - manager_(io_, std::move(ep), num) - { - sg_.add(SIGINT); - sg_.add(SIGQUIT); - sg_.add(SIGTERM); - sg_.async_wait([this](const error_code& ec, int sig) { - if(ec) - std::cerr << ec.message() << std::endl; - std::cerr << "Caught signal " << sig << ", exit.\n"; - stop(); - }); - } +public: + Server(tcp::endpoint&& ep, unsigned long num = 1) : sg_(io_), manager_(io_, std::move(ep), num) + { + sg_.add(SIGINT); + sg_.add(SIGQUIT); + sg_.add(SIGTERM); + sg_.async_wait([this](const error_code& ec, int sig) { + if(ec) + std::cerr << ec.message() << std::endl; + std::cerr << "Caught signal " << sig << ", exit.\n"; + stop(); + }); + } - void run() - { - io_.run(); - } + void run() { io_.run(); } - void stop() - { - manager_.stop(); - io_.stop(); - } + void stop() + { + manager_.stop(); + io_.stop(); + } - private: - io_service io_; - boost::asio::signal_set sg_; - Manager manager_; +private: + io_service io_; + boost::asio::signal_set sg_; + Manager manager_; }; void loop(int port, int num) @@ -436,8 +364,10 @@ int main(int argc, char* argv[]) if(argc != 4) { fprintf(stderr, "%s child_num thread_num_per_child start_port\n", argv[0]); - fprintf(stderr, "Example:\n%s 10 2 8888\ncreate 10 child process, 2 thread" - " per child, listen port range from 8888 to (8888 + 10)\n", argv[0]); + fprintf(stderr, + "Example:\n%s 10 2 8888\ncreate 10 child process, 2 thread" + " per child, listen port range from 8888 to (8888 + 10)\n", + argv[0]); return 1; } int child_num = std::stoi(argv[1]); @@ -447,14 +377,14 @@ int main(int argc, char* argv[]) { switch(fork()) { - case -1: - perror("fork"); - return 1; - case 0: - loop(port, thread_num); - return 0; - default: - break; + case -1: + perror("fork"); + return 1; + case 0: + loop(port, thread_num); + return 0; + default: + break; } } while(wait(NULL) != -1) diff --git a/loop_per_thread/server1.cpp b/loop_per_thread/server1.cpp index 4d187cc..8a3abfe 100644 --- a/loop_per_thread/server1.cpp +++ b/loop_per_thread/server1.cpp @@ -9,191 +9,162 @@ #include #include -class Service : boost::noncopyable, - public std::enable_shared_from_this +class Service : boost::noncopyable, public std::enable_shared_from_this { - public: - Service(std::shared_ptr sock) - : socket_(sock), msg_("pong\n") - {} +public: + Service(std::shared_ptr sock) : socket_(sock), msg_("pong\n") {} - static std::shared_ptr - make_service(std::shared_ptr sock) - { - return std::make_shared(sock); - } + static std::shared_ptr make_service(std::shared_ptr sock) + { + return std::make_shared(sock); + } - void run() - { - do_read(); - } + void run() { do_read(); } - private: - std::shared_ptr socket_; - std::string msg_; - boost::asio::streambuf buf_; +private: + std::shared_ptr socket_; + std::string msg_; + boost::asio::streambuf buf_; - void do_read() - { - auto self(shared_from_this()); - boost::asio::async_read_until(*socket_, buf_, '\n', - [this, self](const boost::system::error_code& ec, - size_t bytes) - { - on_read(ec, bytes); - }); - } + void do_read() + { + auto self(shared_from_this()); + boost::asio::async_read_until( + *socket_, buf_, '\n', [this, self](const boost::system::error_code& ec, size_t bytes) { on_read(ec, bytes); }); + } - void on_read(const boost::system::error_code& ec, size_t) + void on_read(const boost::system::error_code& ec, size_t) + { + if(ec) { - if(ec) - { - ;//std::cerr << "--->>> " << __LINE__ << "\t" << ec.message() << std::endl; - } - else - { - do_write(); - } + ; // std::cerr << "--->>> " << __LINE__ << "\t" << ec.message() << std::endl; } - - void do_write() + else { - auto self(shared_from_this()); - boost::asio::async_write(*socket_, - boost::asio::buffer(msg_), - [this, self](const boost::system::error_code& ec, - size_t bytes) - { - on_write(ec, bytes); - }); + do_write(); } + } + + void do_write() + { + auto self(shared_from_this()); + boost::asio::async_write(*socket_, boost::asio::buffer(msg_), + [this, self](const boost::system::error_code& ec, size_t bytes) { on_write(ec, bytes); }); + } - void on_write(const boost::system::error_code& ec, size_t) + void on_write(const boost::system::error_code& ec, size_t) + { + if(ec) { - if(ec) { - //std::cerr << "--->>> " << __LINE__ << "\t" << ec.message() << std::endl; - return; - } - // no more read. - do_read(); + // std::cerr << "--->>> " << __LINE__ << "\t" << ec.message() << std::endl; + return; } + // no more read. + do_read(); + } }; class Acceptor : boost::noncopyable { - public: - Acceptor(boost::asio::io_service* io, boost::asio::ip::tcp::endpoint&& ep) - : io_(io), - acceptor_(*io_, std::move(ep), true), - is_quit_(false) - { - std::atomic_init(&is_quit_, false); - } +public: + Acceptor(boost::asio::io_service* io, boost::asio::ip::tcp::endpoint&& ep) + : io_(io), acceptor_(*io_, std::move(ep), true), is_quit_(false) + { + std::atomic_init(&is_quit_, false); + } - void start() - { - acceptor_.listen(SOMAXCONN); // default SOMAXCONN is 128 - start_accept(); - } + void start() + { + acceptor_.listen(SOMAXCONN); // default SOMAXCONN is 128 + start_accept(); + } - void stop() - { - is_quit_ = true; - } + void stop() { is_quit_ = true; } - private: - boost::asio::io_service* io_; - boost::asio::ip::tcp::acceptor acceptor_; - std::atomic is_quit_; +private: + boost::asio::io_service* io_; + boost::asio::ip::tcp::acceptor acceptor_; + std::atomic is_quit_; - void start_accept() + void start_accept() + { + auto sock(std::make_shared(*io_)); + acceptor_.async_accept(*sock, [this, sock](const boost::system::error_code& ec) { handle_accept(ec, sock); }); + } + + void handle_accept(const boost::system::error_code& ec, std::shared_ptr sock) + { + if(!ec) { - auto sock(std::make_shared(*io_)); - acceptor_.async_accept(*sock,[this, sock] - (const boost::system::error_code& ec) - { - handle_accept(ec, sock); - }); + Service::make_service(sock)->run(); } - - void handle_accept(const boost::system::error_code& ec, - std::shared_ptr sock) + else { - if(!ec) - { - Service::make_service(sock)->run(); - } - else - { - //std::cerr << "--->>> " << __LINE__ << "\t" << ec.message() << std::endl; - } - if(!is_quit_) - start_accept(); - else - acceptor_.close(); + // std::cerr << "--->>> " << __LINE__ << "\t" << ec.message() << std::endl; } + if(!is_quit_) + start_accept(); + else + acceptor_.close(); + } }; class Server { - public: - Server(boost::asio::ip::tcp::endpoint&& ep) - : work_(new boost::asio::io_service::work(io_)), - acceptor_(new Acceptor(&io_, std::move(ep))) - { - } +public: + Server(boost::asio::ip::tcp::endpoint&& ep) + : work_(new boost::asio::io_service::work(io_)), acceptor_(new Acceptor(&io_, std::move(ep))) + { + } - void start(int num_threads) + void start(int num_threads) + { + assert(num_threads > 0); + acceptor_->start(); + + for(int i = 0; i < num_threads; ++i) { - assert(num_threads > 0); - acceptor_->start(); - - for(int i = 0; i < num_threads; ++i) - { - std::unique_ptr th(new std::thread([this]{ - io_.run(); - })); - threads_.push_back(std::move(th)); - } + std::unique_ptr th(new std::thread([this] { io_.run(); })); + threads_.push_back(std::move(th)); } + } - void stop() + void stop() + { + acceptor_->stop(); + io_.stop(); + for(auto& x: threads_) { - acceptor_->stop(); - io_.stop(); - for(auto& x: threads_) - { - if(x->joinable()) - x->join(); - } + if(x->joinable()) + x->join(); } + } - private: - boost::asio::io_service io_; - /** - * @code io_service::run @endcode will return as soon as there is no more - * work to do, so consider an application that have some producer and - * consumer threads, producers occasionally produce works and post them to - * consumer threads with io_service::post, but if all works finished, then - * @code io_service::run @endcode will return and the consumer thread will - * be stopped, so we need an arbitrary work to keep io_service busy, in this - * case we will use @code io_service::work @endcode directly. - * - * BTW, we don't need to destroy @code io_service::work @endcode explicitly - * by @code shared_ptr::reset() @encode, we will use - * @code io_service::stop() @endcode - */ - std::unique_ptr work_; - std::unique_ptr acceptor_; - std::vector> threads_; +private: + boost::asio::io_service io_; + /** + * @code io_service::run @endcode will return as soon as there is no more + * work to do, so consider an application that have some producer and + * consumer threads, producers occasionally produce works and post them to + * consumer threads with io_service::post, but if all works finished, then + * @code io_service::run @endcode will return and the consumer thread will + * be stopped, so we need an arbitrary work to keep io_service busy, in this + * case we will use @code io_service::work @endcode directly. + * + * BTW, we don't need to destroy @code io_service::work @endcode explicitly + * by @code shared_ptr::reset() @encode, we will use + * @code io_service::stop() @endcode + */ + std::unique_ptr work_; + std::unique_ptr acceptor_; + std::vector> threads_; }; int main() { try { - Server se(boost::asio::ip::tcp::endpoint( - boost::asio::ip::address_v4::any(), 8888)); + Server se(boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4::any(), 8888)); se.start(4); std::this_thread::sleep_for(std::chrono::minutes(10)); se.stop(); diff --git a/loop_per_thread/server_old.cpp b/loop_per_thread/server_old.cpp index 57090db..cc16f00 100644 --- a/loop_per_thread/server_old.cpp +++ b/loop_per_thread/server_old.cpp @@ -29,71 +29,54 @@ using Callback = std::function; */ class Session : public std::enable_shared_from_this { - public: - static std::shared_ptr make_session(io_service& io) - { - return std::make_shared(io); - } +public: + static std::shared_ptr make_session(io_service& io) { return std::make_shared(io); } - Session(io_service& io) - : socket_(io), cb_() - {} + Session(io_service& io) : socket_(io), cb_() {} - ~Session() - { - if(socket_.is_open()) - socket_.close(); - } + ~Session() + { + if(socket_.is_open()) + socket_.close(); + } - tcp::socket& socket() - { - return socket_; - } + tcp::socket& socket() { return socket_; } - void set_callback(Callback&& cb) - { - cb_ = std::move(cb); - } + void set_callback(Callback&& cb) { cb_ = std::move(cb); } - void run() - { - do_read(); - } + void run() { do_read(); } - private: - tcp::socket socket_; - Callback cb_; - boost::asio::streambuf buf_; +private: + tcp::socket socket_; + Callback cb_; + boost::asio::streambuf buf_; - void do_read() - { - // NOTE: client may never send a '\n' - async_read_until(socket_, buf_, '\n', - [this, self = shared_from_this()](const error_code& ec, size_t bytes) - { - buf_.consume(bytes); - processing(ec, bytes); - }); - } + void do_read() + { + // NOTE: client may never send a '\n' + async_read_until(socket_, buf_, '\n', [this, self = shared_from_this()](const error_code& ec, size_t bytes) { + buf_.consume(bytes); + processing(ec, bytes); + }); + } - void processing(const error_code& e, size_t) + void processing(const error_code& e, size_t) + { + if(e) { - if(e) - { - std::cerr << e.message() << std::endl; - return; - } - async_write(socket_, boost::asio::buffer("pong\n"), - [this, self = shared_from_this()](const error_code& ec, size_t) - { - if(ec) - std::cerr << ec.message() << std::endl; - else - do_read(); - if(cb_) - cb_(); - }); + std::cerr << e.message() << std::endl; + return; } + async_write(socket_, boost::asio::buffer("pong\n"), + [this, self = shared_from_this()](const error_code& ec, size_t) { + if(ec) + std::cerr << ec.message() << std::endl; + else + do_read(); + if(cb_) + cb_(); + }); + } }; using SessionPtr = std::shared_ptr; @@ -106,86 +89,71 @@ using SessionPtr = std::shared_ptr; */ class Worker { - public: - Worker() - : rbuf_(0), - wbuf_(0), - reader_(io_), - writer_(io_), - read_buf_(&rbuf_, sizeof rbuf_), - write_buf_(&wbuf_, sizeof wbuf_), - thread_([this]{ thread_func(); }) - { - } +public: + Worker() + : rbuf_(0), wbuf_(0), reader_(io_), writer_(io_), read_buf_(&rbuf_, sizeof rbuf_), + write_buf_(&wbuf_, sizeof wbuf_), thread_([this] { thread_func(); }) + { + } - ~Worker() - { - if(thread_.joinable()) - thread_.join(); - } + ~Worker() + { + if(thread_.joinable()) + thread_.join(); + } - io_service& get_io_service() - { - return io_; - } + io_service& get_io_service() { return io_; } - void enqueue(SessionPtr session) - { - enqueue_writer(session); - } + void enqueue(SessionPtr session) { enqueue_writer(session); } - void stop() - { - std::lock_guard lg(mtx_); - io_.stop(); - } + void stop() + { + std::lock_guard lg(mtx_); + io_.stop(); + } - private: - char rbuf_, wbuf_; - io_service io_; - boost::asio::local::stream_protocol::socket reader_, writer_; - boost::asio::mutable_buffers_1 read_buf_; - boost::asio::const_buffers_1 write_buf_; - std::thread thread_; - std::queue tasks_; - std::mutex mtx_; - - void enqueue_reader() - { - reader_.async_read_some(read_buf_, - [this](const error_code& ec, size_t bytes) - { - read_handle(ec, bytes); - }); - } +private: + char rbuf_, wbuf_; + io_service io_; + boost::asio::local::stream_protocol::socket reader_, writer_; + boost::asio::mutable_buffers_1 read_buf_; + boost::asio::const_buffers_1 write_buf_; + std::thread thread_; + std::queue tasks_; + std::mutex mtx_; + + void enqueue_reader() + { + reader_.async_read_some(read_buf_, [this](const error_code& ec, size_t bytes) { read_handle(ec, bytes); }); + } - void enqueue_writer(SessionPtr session) - { - std::lock_guard lg(mtx_); - tasks_.push(session); - writer_.write_some(write_buf_); - } + void enqueue_writer(SessionPtr session) + { + std::lock_guard lg(mtx_); + tasks_.push(session); + writer_.write_some(write_buf_); + } - void read_handle(const error_code& ec, size_t) + void read_handle(const error_code& ec, size_t) + { + if(ec) + return; + std::lock_guard lg(mtx_); + while(!tasks_.empty()) { - if(ec) - return; - std::lock_guard lg(mtx_); - while(!tasks_.empty()) - { - auto session = tasks_.front(); - session->run(); - tasks_.pop(); - } - enqueue_reader(); + auto session = tasks_.front(); + session->run(); + tasks_.pop(); } + enqueue_reader(); + } - void thread_func() - { - boost::asio::local::connect_pair(reader_, writer_); - enqueue_reader(); - io_.run(); - } + void thread_func() + { + boost::asio::local::connect_pair(reader_, writer_); + enqueue_reader(); + io_.run(); + } }; using WorkerPtr = std::shared_ptr; @@ -198,60 +166,51 @@ using WorkerPtr = std::shared_ptr; */ class Manager { - public: - Manager(io_service& io, tcp::endpoint&& ep, unsigned long num) - : num_(num), - cur_(0), - acceptor_(io, std::move(ep), true) - { - for(unsigned long i = 0; i < num_; ++i) - workers_.emplace_back(std::make_shared()); +public: + Manager(io_service& io, tcp::endpoint&& ep, unsigned long num) + : num_(num), cur_(0), acceptor_(io, std::move(ep), true) + { + for(unsigned long i = 0; i < num_; ++i) + workers_.emplace_back(std::make_shared()); - acceptor_.listen(); - start_accept(); - } + acceptor_.listen(); + start_accept(); + } - ~Manager() - { - } + ~Manager() {} - void stop() - { - acceptor_.cancel(); - for(auto& x: workers_) - x->stop(); - } + void stop() + { + acceptor_.cancel(); + for(auto& x: workers_) + x->stop(); + } - private: - unsigned long num_; - unsigned long cur_; - tcp::acceptor acceptor_; - std::vector workers_; +private: + unsigned long num_; + unsigned long cur_; + tcp::acceptor acceptor_; + std::vector workers_; - void accept_handle(SessionPtr session, - WorkerPtr worker, - const error_code& ec) + void accept_handle(SessionPtr session, WorkerPtr worker, const error_code& ec) + { + if(!ec) { - if(!ec) - { - ++cur_; - worker->enqueue(session); - start_accept(); - } + ++cur_; + worker->enqueue(session); + start_accept(); } + } - void start_accept() - { - if(cur_ == num_) - cur_ = 0; - auto worker = workers_.at(cur_); - auto session(Session::make_session(worker->get_io_service())); - acceptor_.async_accept(session->socket(), - [this, session, worker](const error_code& ec) - { - accept_handle(session, worker, ec); - }); - } + void start_accept() + { + if(cur_ == num_) + cur_ = 0; + auto worker = workers_.at(cur_); + auto session(Session::make_session(worker->get_io_service())); + acceptor_.async_accept(session->socket(), + [this, session, worker](const error_code& ec) { accept_handle(session, worker, ec); }); + } }; /// \brief A wrapper class for users @@ -262,37 +221,32 @@ class Manager */ class Server { - public: - Server(tcp::endpoint&& ep, unsigned long num = 1) - : sg_(io_), - manager_(io_, std::move(ep), num) - { - sg_.add(SIGINT); - sg_.add(SIGQUIT); - sg_.add(SIGTERM); - sg_.async_wait([this](const error_code& ec, int sig) { - if(ec) - std::cerr << ec.message() << std::endl; - std::cerr << "Caught signal " << sig << ", exit.\n"; - stop(); - }); - } +public: + Server(tcp::endpoint&& ep, unsigned long num = 1) : sg_(io_), manager_(io_, std::move(ep), num) + { + sg_.add(SIGINT); + sg_.add(SIGQUIT); + sg_.add(SIGTERM); + sg_.async_wait([this](const error_code& ec, int sig) { + if(ec) + std::cerr << ec.message() << std::endl; + std::cerr << "Caught signal " << sig << ", exit.\n"; + stop(); + }); + } - void run() - { - io_.run(); - } + void run() { io_.run(); } - void stop() - { - manager_.stop(); - io_.stop(); - } + void stop() + { + manager_.stop(); + io_.stop(); + } - private: - io_service io_; - boost::asio::signal_set sg_; - Manager manager_; +private: + io_service io_; + boost::asio::signal_set sg_; + Manager manager_; }; void loop(int port, int num) @@ -313,8 +267,10 @@ int main(int argc, char* argv[]) if(argc != 4) { fprintf(stderr, "%s child_num thread_num_per_child start_port\n", argv[0]); - fprintf(stderr, "Example:\n%s 10 2 8888\ncreate 10 child process, 2 thread" - " per child, listen port range from 8888 to (8888 + 10)\n", argv[0]); + fprintf(stderr, + "Example:\n%s 10 2 8888\ncreate 10 child process, 2 thread" + " per child, listen port range from 8888 to (8888 + 10)\n", + argv[0]); return 1; } int child_num = std::stoi(argv[1]); @@ -325,14 +281,14 @@ int main(int argc, char* argv[]) { switch((pid = fork())) { - case -1: - perror("fork"); - return 1; - case 0: - loop(port, thread_num); - return 0; - default: - break; + case -1: + perror("fork"); + return 1; + case 0: + loop(port, thread_num); + return 0; + default: + break; } } while(wait(NULL) != -1) diff --git a/meta/function_traits.h b/meta/function_traits.h index 3c8e7f4..b11f917 100644 --- a/meta/function_traits.h +++ b/meta/function_traits.h @@ -16,7 +16,8 @@ namespace nm { namespace meta { - template struct Inspector; + template + struct Inspector; template struct Inspector { @@ -24,25 +25,43 @@ namespace nm using res_t = R; }; template - struct Inspector : Inspector {}; + struct Inspector : Inspector + { + }; template - struct Inspector : Inspector {}; + struct Inspector : Inspector + { + }; template - struct Inspector : Inspector {}; + struct Inspector : Inspector + { + }; template - struct Inspector : Inspector {}; + struct Inspector : Inspector + { + }; template - struct Inspector : Inspector {}; + struct Inspector : Inspector + { + }; template - struct Inspector : Inspector {}; + struct Inspector : Inspector + { + }; // functor like template - struct Inspector : Inspector {}; + struct Inspector : Inspector + { + }; template - struct Inspector : Inspector {}; + struct Inspector : Inspector + { + }; template - struct Inspector : Inspector {}; + struct Inspector : Inspector + { + }; } } diff --git a/optional/CMakeLists.txt b/optional/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/optional/main.cpp b/optional/main.cpp old mode 100755 new mode 100644 diff --git a/optional/optional.h b/optional/optional.h old mode 100755 new mode 100644 index 92e1b93..190f406 --- a/optional/optional.h +++ b/optional/optional.h @@ -15,26 +15,13 @@ template class Optional { public: - Optional() : data_{}, valid_{false} - { + Optional() : data_{}, valid_{false} {} - } + ~Optional() { this->clear(); } - ~Optional() - { - this->clear(); - } - - explicit Optional(const T& t) : Optional{} - { - this->assign(t); - } + explicit Optional(const T& t) : Optional{} { this->assign(t); } - explicit Optional(T&& t) noexcept : Optional{} - { - - this->move(std::move(t)); - } + explicit Optional(T&& t) noexcept : Optional{} { this->move(std::move(t)); } template explicit Optional(Args&&... args) : Optional{} @@ -42,29 +29,23 @@ class Optional this->emplace(std::forward(args)...); } - Optional(const Optional& rhs) : Optional{} - { - *this = rhs; - } + Optional(const Optional& rhs) : Optional{} { *this = rhs; } - Optional(Optional&& rhs) noexcept : Optional{} - { - *this = std::move(rhs); - } + Optional(Optional&& rhs) noexcept : Optional{} { *this = std::move(rhs); } - Optional& operator= (const T& t) + Optional& operator=(const T& t) { this->assign(t); return *this; } - Optional& operator= (T&& t) + Optional& operator=(T&& t) { this->move(std::move(t)); return *this; } - Optional& operator= (const Optional& rhs) + Optional& operator=(const Optional& rhs) { if(this != &rhs) { @@ -81,7 +62,7 @@ class Optional return *this; } - Optional& operator= (Optional&& rhs) noexcept + Optional& operator=(Optional&& rhs) noexcept { if(this != &rhs) { @@ -99,7 +80,7 @@ class Optional } template::value>::type> - R emplace(Args&& ... args) + R emplace(Args&&... args) { if(!valid_) { @@ -108,24 +89,15 @@ class Optional } } - explicit operator bool() - { - return valid_; - } + explicit operator bool() { return valid_; } operator T() = delete; - T& operator* () - { - return *operator->(); - } + T& operator*() { return *operator->(); } - const T& operator* () const - { - return *operator->(); - } + const T& operator*() const { return *operator->(); } - T* operator-> () + T* operator->() { if(!valid_) { @@ -136,7 +108,7 @@ class Optional const T* operator->() const { - if (!valid_) + if(!valid_) { throw std::logic_error("invalid optional"); } @@ -162,15 +134,9 @@ class Optional new(this->raw()) T{std::move(t)}; } - void* raw() - { - return reinterpret_cast(&data_); - } + void* raw() { return reinterpret_cast(&data_); } - const void* raw() const - { - return reinterpret_cast(&data_); - } + const void* raw() const { return reinterpret_cast(&data_); } void clear() { diff --git a/rbtree/rb-tree.h b/rbtree/rb-tree.h index 9902c91..40cc5ad 100644 --- a/rbtree/rb-tree.h +++ b/rbtree/rb-tree.h @@ -16,647 +16,578 @@ namespace nm template> class RBtree { - private: - enum Color - { - RED, - BLACK - }; - struct node - { - node* parent; - node* lhs; - node* rhs; - Color color; - std::pair data; - node() - : parent(nullptr), lhs(nullptr), - rhs(nullptr), color(RED), data() - {} - node(const Key& k, const Val& v) - : parent(nullptr), lhs(nullptr), - rhs(nullptr), color(RED), data{k, v} - {} - - Key& key() - { - return data.first; - } - std::pair* data_ptr() - { - return &data; - } - - const std::pair* const_data_ptr() const - { - return &data; - } - - std::pair& data_ref() - { - return data; - } + private: + enum Color + { + RED, + BLACK + }; + struct node + { + node* parent; + node* lhs; + node* rhs; + Color color; + std::pair data; + node() : parent(nullptr), lhs(nullptr), rhs(nullptr), color(RED), data() {} + node(const Key& k, const Val& v) : parent(nullptr), lhs(nullptr), rhs(nullptr), color(RED), data{k, v} {} + + Key& key() { return data.first; } + std::pair* data_ptr() { return &data; } + + const std::pair* const_data_ptr() const { return &data; } + + std::pair& data_ref() { return data; } + + const std::pair& const_data_ref() const { return data; } + }; + struct rbnode + { + node* nil; + node* root; + rbnode() : nil(new node), root(nil) { nil->color = BLACK; } + ~rbnode() + { + delete nil; + nil = nullptr; + } + }; - const std::pair& const_data_ref() const - { - return data; - } - }; - struct rbnode - { - node* nil; - node* root; - rbnode() - : nil(new node), root(nil) - { - nil->color = BLACK; - } - ~rbnode() - { - delete nil; - nil = nullptr; - } - }; + rbnode* root_; + size_t size_; + Cmp cmp_; - rbnode* root_; - size_t size_; - Cmp cmp_; + public: + class iterator + { + friend class RBtree; public: - class iterator - { - friend class RBtree; - - public: - std::pair& operator*() - { - return data_->data_ref(); - } + std::pair& operator*() { return data_->data_ref(); } - const std::pair& operator* () const - { - return data_->const_data_ref(); - } + const std::pair& operator*() const { return data_->const_data_ref(); } - std::pair* operator->() - { - return data_->data_ptr(); - } + std::pair* operator->() { return data_->data_ptr(); } - const std::pair* operator->() const - { - return data_->const_data_pr(); - } + const std::pair* operator->() const { return data_->const_data_pr(); } - iterator& operator++() + iterator& operator++() + { + if(data_ == tree_->root_->nil) { - if(data_ == tree_->root_->nil) - { - throw std::runtime_error("iterator is empty"); - } - data_ = tree_->successor(tree_->root_, data_); - return *this; + throw std::runtime_error("iterator is empty"); } + data_ = tree_->successor(tree_->root_, data_); + return *this; + } - friend bool operator== (const iterator& l, const iterator& r) - { - return l.data_ == r.data_; - } + friend bool operator==(const iterator& l, const iterator& r) { return l.data_ == r.data_; } - friend bool operator!= (const iterator l, const iterator& r) - { - return !(l == r); - } + friend bool operator!=(const iterator l, const iterator& r) { return !(l == r); } - private: - RBtree* tree_; - node* data_; + private: + RBtree* tree_; + node* data_; - iterator(RBtree* tree, node* n) - : tree_{tree}, data_{n} - { - } + iterator(RBtree* tree, node* n) : tree_{tree}, data_{n} {} - node* data() const - { - return data_; - } - }; - RBtree() - : root_(new rbnode), size_(0), cmp_() + node* data() const { return data_; } + }; + RBtree() : root_(new rbnode), size_(0), cmp_() {} + RBtree(const std::initializer_list>& rhs) : RBtree() + { + for(const auto& x: rhs) { + insert(x); } - RBtree(const std::initializer_list>& rhs) - : RBtree() - { - for(const auto& x: rhs) - { - insert(x); - } - } - ~RBtree() - { - this->clear(); - delete root_; - root_ = nullptr; - } + } + ~RBtree() + { + this->clear(); + delete root_; + root_ = nullptr; + } - iterator begin() - { - return {this, find_min(root_, root_->root)}; - } + iterator begin() { return {this, find_min(root_, root_->root)}; } + + iterator end() { return {this, root_->nil}; } - iterator end() + bool insert(const std::pair& rhs) + { + if(insert(root_, new node{rhs.first, rhs.second})) { - return {this, root_->nil}; + size_ += 1; + return true; } + return false; + } + + bool insert(const Key& key, const Val& val) { return insert({key, val}); } - bool insert(const std::pair& rhs) + bool remove(const Key& key) + { + auto res = this->find(key); + return this->remove(res); + } + + bool remove(const iterator& iter) + { + if(iter == end()) { - if(insert(root_, new node{rhs.first, rhs.second})) - { - size_ += 1; - return true; - } return false; } + this->remove(root_, iter.data()); + size_ -= 1; + return true; + } - bool insert(const Key& key, const Val& val) - { - return insert({key, val}); - } + iterator find(const Key& key) { return iterator{this, this->find(root_, key)}; } - bool remove(const Key& key) - { - auto res = this->find(key); - return this->remove(res); - } + iterator prev(const Key& key) + { + auto r = find(key); + return prev(r); + } - bool remove(const iterator& iter) + iterator prev(const iterator& iter) + { + if(iter == end()) { - if(iter == end()) - { - return false; - } - this->remove(root_, iter.data()); - size_ -= 1; - return true; + return end(); } + return {predecessor(*iter)}; + } - iterator find(const Key& key) - { - return iterator{this, this->find(root_, key)}; - } + iterator next(const Key& key) + { + auto r = find(key); + return next(r); + } - iterator prev(const Key& key) + iterator next(const iterator& iter) + { + if(iter == end()) { - auto r = find(key); - return prev(r); + return end(); } - - iterator prev(const iterator& iter) - { - if(iter == end()) - { - return end(); - } - return {predecessor(*iter)}; + return {successor(iter.data())}; + } + + size_t size() const { return size_; } + + void clear() + { + this->clear(root_); + size_ = 0; + } + + private: + /* + * x y + * / \ / \ + * a y => x c + * / \ / \ + * b c a b + * + */ + + void left_rotate(rbnode* t, node* x) + { + node* y = x->rhs; + x->rhs = y->lhs; + + if(y->lhs != t->nil) + { + y->lhs->parent = x; } - - iterator next(const Key& key) + y->parent = x->parent; + if(x->parent == t->nil) + t->root = y; + else { - auto r = find(key); - return next(r); + if(x == x->parent->lhs) + x->parent->lhs = y; + else + x->parent->rhs = y; } - - iterator next(const iterator& iter) - { - if(iter == end()) - { - return end(); - } - return {successor(iter.data())}; + y->lhs = x; + x->parent = y; + } + + /* + * + * y x + * / \ / \ + * x c => a y + * / \ / \ + * a b b c + * + */ + + void right_rotate(rbnode* t, node* y) + { + node* x = y->lhs; + y->lhs = x->rhs; + + if(x->rhs != t->nil) + { + x->rhs->parent = y; } - - size_t size() const + x->parent = y->parent; + if(y->parent == t->nil) + t->root = x; + else { - return size_; + if(y == y->parent->rhs) + y->parent->rhs = x; + else + y->parent->lhs = x; } + x->rhs = y; + y->parent = x; + } - void clear() + node* find_min(rbnode* t, node* x) + { + while(x->lhs != t->nil) { - this->clear(root_); - size_ = 0; + x = x->lhs; } + return x; + } - private: - - /* - * x y - * / \ / \ - * a y => x c - * / \ / \ - * b c a b - * - */ - - void left_rotate(rbnode* t, node* x) + node* find_max(rbnode* t, node* x) + { + while(x->rhs != t->nil) { - node* y = x->rhs; - x->rhs = y->lhs; - - if(y->lhs != t->nil) - { - y->lhs->parent = x; - } - y->parent = x->parent; - if(x->parent == t->nil) - t->root = y; - else - { - if(x == x->parent->lhs) - x->parent->lhs = y; - else - x->parent->rhs = y; - } - y->lhs = x; - x->parent = y; + x = x->rhs; } + return x; + } - /* - * - * y x - * / \ / \ - * x c => a y - * / \ / \ - * a b b c - * - */ - - void right_rotate(rbnode* t, node* y) + node* predecessor(rbnode* t, node* x) + { + if(x->lhs != t->nil) { - node* x = y->lhs; - y->lhs = x->rhs; - - if(x->rhs != t->nil) - { - x->rhs->parent = y; - } - x->parent = y->parent; - if(y->parent == t->nil) - t->root = x; - else - { - if(y == y->parent->rhs) - y->parent->rhs = x; - else - y->parent->lhs = x; - } - x->rhs = y; - y->parent = x; + x = find_max(t, x->lhs); } - - node* find_min(rbnode* t, node* x) + else { - while(x->lhs != t->nil) + node* tmp = x->parent; + while(tmp != t->nil && x != tmp->lhs) { - x = x->lhs; + x = tmp; + tmp = x->parent; } - return x; + x = tmp; } + return x; + } - node* find_max(rbnode* t, node* x) + node* successor(rbnode* t, node* x) + { + if(x->rhs != t->nil) { - while(x->rhs != t->nil) - { - x = x->rhs; - } - return x; + x = find_min(t, x->rhs); } - - node* predecessor(rbnode* t, node* x) + else { - if(x->lhs != t->nil) + node* tmp = x->parent; + while(tmp != t->nil && x == tmp->rhs) { - x = find_max(t, x->lhs); - } - else - { - node* tmp = x->parent; - while(tmp != t->nil && x != tmp->lhs) - { - x = tmp; - tmp = x->parent; - } x = tmp; + tmp = x->parent; } - return x; + x = tmp; } + return x; + } - node* successor(rbnode* t, node* x) + void transplant(rbnode* t, node* u, node* v) + { + if(u->parent == t->nil) { - if(x->rhs != t->nil) - { - x = find_min(t, x->rhs); - } - else - { - node* tmp = x->parent; - while(tmp != t->nil && x == tmp->rhs) - { - x = tmp; - tmp = x->parent; - } - x = tmp; - } - return x; + t->root = v; } - - void transplant(rbnode* t, node* u, node* v) + else if(u == u->parent->lhs) { - if(u->parent == t->nil) - { - t->root = v; - } - else if(u == u->parent->lhs) - { - u->parent->lhs = v; - } - else - { - u->parent->rhs = v; - } - v->parent = u->parent; + u->parent->lhs = v; + } + else + { + u->parent->rhs = v; } + v->parent = u->parent; + } - void insert_fixup(rbnode* t, node* x) + void insert_fixup(rbnode* t, node* x) + { + node* y = nullptr; + while(x->parent->color == RED) { - node* y = nullptr; - while(x->parent->color == RED) + if(x->parent == x->parent->parent->lhs) { - if(x->parent == x->parent->parent->lhs) + y = x->parent->parent->rhs; + if(y->color == RED) // a red node can't have red child { - y = x->parent->parent->rhs; - if(y->color == RED) // a red node can't have red child - { - /* - * BEFORE INSERT, THE TREE IS SATISFY RED-BLACK TREE'S PROPERTIES - * THUS, ppa IS BLACK, AND WE DON'T CARE x IS LEFT CHILD OR RIGHT - * CHILD. - * ppa(black) ppa(red) - * / \ / \ - * pa(red) y(red) => pa(black) y(black) - * | | - * x(red) x(red) - * - * - * - * x(ppa: red) black heights of x(ppa) are - * / \ the same(left: 2, right: 2) - * => pa(black) y(black) => - * | - * old x (red) - */ - x->parent->color = BLACK; - y->color = BLACK; - x->parent->parent->color = RED; - x = x->parent->parent; // fix-up till root, go next loop - } - else - { - if(x == x->parent->rhs) - { - x = x->parent; - left_rotate(t, x); - } - x->parent->color = BLACK; - x->parent->parent->color = RED; - right_rotate(t, x->parent->parent); - } + /* + * BEFORE INSERT, THE TREE IS SATISFY RED-BLACK TREE'S PROPERTIES + * THUS, ppa IS BLACK, AND WE DON'T CARE x IS LEFT CHILD OR RIGHT + * CHILD. + * ppa(black) ppa(red) + * / \ / \ + * pa(red) y(red) => pa(black) y(black) + * | | + * x(red) x(red) + * + * + * + * x(ppa: red) black heights of x(ppa) are + * / \ the same(left: 2, right: 2) + * => pa(black) y(black) => + * | + * old x (red) + */ + x->parent->color = BLACK; + y->color = BLACK; + x->parent->parent->color = RED; + x = x->parent->parent; // fix-up till root, go next loop } - else // mirror operation + else { - y = x->parent->parent->lhs; - if(y->color == RED) + if(x == x->parent->rhs) { - x->parent->color = BLACK; - y->color = BLACK; - x->parent->parent->color = RED; - x = x->parent->parent; + x = x->parent; + left_rotate(t, x); } - else + x->parent->color = BLACK; + x->parent->parent->color = RED; + right_rotate(t, x->parent->parent); + } + } + else // mirror operation + { + y = x->parent->parent->lhs; + if(y->color == RED) + { + x->parent->color = BLACK; + y->color = BLACK; + x->parent->parent->color = RED; + x = x->parent->parent; + } + else + { + if(x == x->parent->lhs) { - if(x == x->parent->lhs) - { - x = x->parent; - right_rotate(t, x); - } - x->parent->color = BLACK; - x->parent->parent->color = RED; - left_rotate(t, x->parent->parent); + x = x->parent; + right_rotate(t, x); } + x->parent->color = BLACK; + x->parent->parent->color = RED; + left_rotate(t, x->parent->parent); } } - t->root->color = BLACK; } + t->root->color = BLACK; + } - void delete_fixup(rbnode* t, node* x) + void delete_fixup(rbnode* t, node* x) + { + node* y = nullptr; + while(x != t->root && x->color == BLACK) { - node* y = nullptr; - while(x != t->root && x->color == BLACK) + if(x == x->parent->lhs) { - if(x == x->parent->lhs) + y = x->parent->rhs; + if(y->color == RED) { + y->color = BLACK; + x->parent->color = RED; + left_rotate(t, x->parent); y = x->parent->rhs; - if(y->color == RED) - { - y->color = BLACK; - x->parent->color = RED; - left_rotate(t, x->parent); - y = x->parent->rhs; - } - if(y->lhs->color == BLACK && y->rhs->color == BLACK) + } + if(y->lhs->color == BLACK && y->rhs->color == BLACK) + { + y->color = RED; + x = x->parent; + } + else + { + if(y->rhs->color == BLACK) { + y->lhs->color = BLACK; y->color = RED; - x = x->parent; - } - else - { - if(y->rhs->color == BLACK) - { - y->lhs->color = BLACK; - y->color = RED; - right_rotate(t, y); - y = x->parent->rhs; - } - y->color = x->parent->color; - x->parent->color = BLACK; - y->rhs->color = BLACK; - left_rotate(t, x->parent); - x = t->root; + right_rotate(t, y); + y = x->parent->rhs; } + y->color = x->parent->color; + x->parent->color = BLACK; + y->rhs->color = BLACK; + left_rotate(t, x->parent); + x = t->root; } - else // mirror operation + } + else // mirror operation + { + y = x->parent->lhs; + if(y->color == RED) { + y->color = BLACK; + x->parent->color = RED; + right_rotate(t, x->parent); y = x->parent->lhs; - if(y->color == RED) - { - y->color = BLACK; - x->parent->color = RED; - right_rotate(t, x->parent); - y = x->parent->lhs; - } - if(y->lhs->color == BLACK && y->rhs->color == BLACK) - { - y->color = RED; - x = x->parent; - } - else + } + if(y->lhs->color == BLACK && y->rhs->color == BLACK) + { + y->color = RED; + x = x->parent; + } + else + { + if(y->lhs->color == BLACK) { - if(y->lhs->color == BLACK) - { - y->rhs->color = BLACK; - y->color = RED; - left_rotate(t, y); - y = x->parent->lhs; - } - y->color = x->parent->color; - x->parent->color = BLACK; y->rhs->color = BLACK; - right_rotate(t, x->parent); - x = t->root; + y->color = RED; + left_rotate(t, y); + y = x->parent->lhs; } + y->color = x->parent->color; + x->parent->color = BLACK; + y->rhs->color = BLACK; + right_rotate(t, x->parent); + x = t->root; } } - x->color = BLACK; } + x->color = BLACK; + } - bool insert(rbnode* t, node* z) + bool insert(rbnode* t, node* z) + { + node* x = t->root; + node* y = t->nil; + while(x != t->nil) { - node* x = t->root; - node* y = t->nil; - while(x != t->nil) + y = x; + if(cmp_(z->key(), x->key())) + { + x = x->lhs; + } + else if(cmp_(x->key(), z->key())) + { + x = x->rhs; + } + else { - y = x; - if(cmp_(z->key(), x->key())) - { - x = x->lhs; - } - else if(cmp_(x->key(), z->key())) - { - x = x->rhs; - } - else - { #if 0 x->val = z->val; // replace old value #endif - delete z; - return false; - } - } - z->parent = y; - if(y == t->nil) - { - t->root = z; + delete z; + return false; } - else if(cmp_(z->key(), y->key())) + } + z->parent = y; + if(y == t->nil) + { + t->root = z; + } + else if(cmp_(z->key(), y->key())) + { + y->lhs = z; + } + else + { + y->rhs = z; + } + z->lhs = t->nil; + z->rhs = t->nil; + insert_fixup(t, z); + return true; + } + + void remove(rbnode* t, node* z) + { + node* y = z; + node* x = nullptr; + Color color = y->color; + if(z->lhs == t->nil) + { + x = z->rhs; + transplant(t, z, z->rhs); + } + else if(z->rhs == t->nil) + { + x = z->lhs; + transplant(t, z, z->lhs); + } + else + { + y = successor(t, z); + color = y->color; + x = y->rhs; + if(y->parent == z) { - y->lhs = z; + x->parent = y; } else { - y->rhs = z; + transplant(t, y, y->rhs); + y->rhs = z->rhs; + y->rhs->parent = y; } - z->lhs = t->nil; - z->rhs = t->nil; - insert_fixup(t, z); - return true; + transplant(t, z, y); + y->lhs = z->lhs; + y->lhs->parent = y; + y->color = z->color; } + delete z; + if(color == BLACK) + { + delete_fixup(t, x); + } + } - void remove(rbnode* t, node* z) + node* find(rbnode* t, const Key& key) + { + node* tmp = t->root; + while(tmp != t->nil) { - node* y = z; - node* x = nullptr; - Color color = y->color; - if(z->lhs == t->nil) + if(cmp_(tmp->key(), key)) { - x = z->rhs; - transplant(t, z, z->rhs); + tmp = tmp->rhs; } - else if(z->rhs == t->nil) + else if(cmp_(key, tmp->key())) { - x = z->lhs; - transplant(t, z, z->lhs); + tmp = tmp->lhs; } else { - y = successor(t, z); - color = y->color; - x = y->rhs; - if(y->parent == z) - { - x->parent = y; - } - else - { - transplant(t, y, y->rhs); - y->rhs = z->rhs; - y->rhs->parent = y; - } - transplant(t, z, y); - y->lhs = z->lhs; - y->lhs->parent = y; - y->color = z->color; - } - delete z; - if(color == BLACK) - { - delete_fixup(t, x); + return tmp; } } + return root_->nil; + } - node* find(rbnode* t, const Key& key) + void clear(rbnode* t) + { + std::stack st; + st.push(t->root); + while(!st.empty()) { - node* tmp = t->root; - while(tmp != t->nil) + node* n = st.top(); + st.pop(); + if(n->lhs != t->nil) { - if(cmp_(tmp->key(), key)) - { - tmp = tmp->rhs; - } - else if(cmp_(key, tmp->key())) - { - tmp = tmp->lhs; - } - else - { - return tmp; - } + st.push(n->lhs); } - return root_->nil; - } - - void clear(rbnode* t) - { - std::stack st; - st.push(t->root); - while(!st.empty()) + if(n->rhs != t->nil) { - node* n = st.top(); - st.pop(); - if(n->lhs != t->nil) - { - st.push(n->lhs); - } - if(n->rhs != t->nil) - { - st.push(n->rhs); - } - delete n; + st.push(n->rhs); } + delete n; } + } }; } -#endif //RED_BLACK_TREE_H_ +#endif // RED_BLACK_TREE_H_ diff --git a/rbtree/test.cpp b/rbtree/test.cpp index 35d4ce4..e1756d5 100644 --- a/rbtree/test.cpp +++ b/rbtree/test.cpp @@ -43,17 +43,7 @@ int main() if(iter1 == tree1.end()) std::cout << "-1s\n"; - nm::RBtree lt{ - {1, 0}, - {2, 0}, - {5, 0}, - {7, 0}, - {8, 0}, - {11, 0}, - {14, 0}, - {15, 0}, - {4, 0} - }; + nm::RBtree lt{{1, 0}, {2, 0}, {5, 0}, {7, 0}, {8, 0}, {11, 0}, {14, 0}, {15, 0}, {4, 0}}; for(auto& i: lt) { diff --git a/router/main.cpp b/router/main.cpp index 376b8cd..d75b07f 100644 --- a/router/main.cpp +++ b/router/main.cpp @@ -40,19 +40,10 @@ std::ostream& operator<<(std::ostream& os, const Pairs& m) return os; } -template -struct add_space -{ - add_space(T t) : t_{t} {} - - friend std::ostream& operator<<(std::ostream& os, const add_space& t) { return os << t.t_ << ' '; } - T t_; -}; - template void print(Args&&... args) { - (cout << ... << add_space(args)); + ((cout << args << ' '), ...); cout << '\n'; } diff --git a/router/radix.cc b/router/radix.cc index 1b0c6f0..9b93157 100644 --- a/router/radix.cc +++ b/router/radix.cc @@ -13,225 +13,236 @@ struct Node { - bool word; - std::string path; - std::vector children; - std::vector indices; + bool word; + std::string path; + std::vector children; + std::vector indices; - Node(const std::string_view& s) : word{false}, path{s.data(), s.size()}, children{}, indices{} {} + Node(const std::string_view& s) : word{false}, path{s.data(), s.size()}, children{}, indices{} {} }; class Router { public: - Router(): root_{{}} {} - - ~Router() + Router() : root_{{}} {} + + ~Router() + { + std::cerr << std::boolalpha; + std::cerr << __LINE__ << "-->> " << root_.path << ", " << root_.word << '\n'; + std::list tmp; + for(auto n: root_.children) { - std::cerr << std::boolalpha; - std::cerr << __LINE__ << "-->> " << root_.path << ", " << root_.word << '\n'; - std::list tmp; - for(auto n: root_.children) - { - std::cerr <<__LINE__ << "-->> " << n->path << ", " << n->word << '\n'; - tmp.push_back(n); - } + std::cerr << __LINE__ << "-->> " << n->path << ", " << n->word << '\n'; + tmp.push_back(n); + } - while(!tmp.empty()) - { - Node* n = tmp.front(); - tmp.pop_front(); + while(!tmp.empty()) + { + Node* n = tmp.front(); + tmp.pop_front(); - for(auto c: n->children) - { - std::cerr <<__LINE__ << "-->> " << c->path << ", " << c->word << '\n'; - tmp.push_back(c); - } + for(auto c: n->children) + { + std::cerr << __LINE__ << "-->> " << c->path << ", " << c->word << '\n'; + tmp.push_back(c); + } - delete n; - } + delete n; } + } + + void put(const std::string& s) + { + Node* n = &root_; + auto path = s; + put_impl(n, path); + } + + bool has_word(const std::string& s) + { + bool res = false; + Node* n = &root_; + get_impl(n, s, res, true); + return res; + } + + bool has_prefix(const std::string& s) + { + bool res = false; + Node* n = &root_; + get_impl(n, s, res); + return res; + } - void put(const std::string& s) - { - Node* n = &root_; - auto path = s; - put_impl(n, path); - } +private: + Node root_; - bool has_word(const std::string& s) + void put_impl(Node* n, std::string_view path) + { + if(n->path.empty() && n->indices.empty()) { - bool res = false; - Node* n = &root_; - get_impl(n, s, res, true); - return res; + n->word = true; + n->path = path; + return; } - - bool has_prefix(const std::string& s) + size_t i = common_prefix(n->path, path); + /* + // put dog, doges + [dog] + / + [es] + + // put doll + [do] + / \ + [g] [ll] + / + [es] + */ + if(i < n->path.size()) { - bool res = false; - Node* n = &root_; - get_impl(n, s, res); - return res; + // split edge + Node* c = new Node{n->path.substr(i)}; + c->children = n->children; + c->indices = n->indices; + c->word = true; + + n->children.clear(); + n->children.push_back(c); + n->indices.clear(); + n->indices.push_back(n->path[i]); + n->path = n->path.substr(0, i); + n->word = false; } -private: - Node root_; - - void put_impl(Node* n, std::string_view path) + if(i < path.size()) { - if(n->path.empty() && n->indices.empty()) + path = path.substr(i); + for(size_t idx = 0; idx < n->indices.size(); ++idx) + { + if(n->indices[idx] == path[0]) { - n->word = true; - n->path = path; - return; - } - size_t i = common_prefix(n->path, path); - /* - // put dog, doges - [dog] - / - [es] - - // put doll - [do] - / \ - [g] [ll] - / - [es] - */ - if(i < n->path.size()) - { - // split edge - Node* c = new Node{n->path.substr(i)}; - c->children = n->children; - c->indices = n->indices; - c->word = true; - - n->children.clear(); - n->children.push_back(c); - n->indices.clear(); - n->indices.push_back(n->path[i]); - n->path = n->path.substr(0, i); - n->word = false; - } - - if(i < path.size()) - { - path = path.substr(i); - for(size_t idx = 0; idx < n->indices.size(); ++idx) - { - if(n->indices[idx] == path[0]) - { - n = n->children[idx]; - put_impl(n, path); - return; - } - } - Node* c = new Node{path}; - c->word = true; - n->children.push_back(c); - n->indices.push_back(path[0]); + n = n->children[idx]; + put_impl(n, path); + return; } + } + Node* c = new Node{path}; + c->word = true; + n->children.push_back(c); + n->indices.push_back(path[0]); } + } - void get_impl(Node* n, std::string path, bool& res, bool full = false) + void get_impl(Node* n, std::string path, bool& res, bool full = false) + { + if(path.size() > n->path.size()) { - if(path.size() > n->path.size()) + if(path.substr(0, n->path.size()) == n->path) + { + path = path.substr(n->path.size()); + for(size_t idx = 0; idx < n->indices.size(); ++idx) { - if(path.substr(0, n->path.size()) == n->path) - { - path = path.substr(n->path.size()); - for(size_t idx = 0; idx < n->indices.size(); ++idx) - { - if(n->indices[idx] == path[0]) - { - n = n->children[idx]; - get_impl(n, path, res, full); - } - } - } + if(n->indices[idx] == path[0]) + { + n = n->children[idx]; + get_impl(n, path, res, full); + } } - else if(path.size() < n->path.size()) + } + } + else if(path.size() < n->path.size()) + { + // doge, did + int i = common_prefix(n->path, path); + if(i < path.size()) + { + path = path.substr(i); + for(size_t idx = 0; idx < n->indices.size(); ++idx) { - // doge, did - int i = common_prefix(n->path, path); - if(i < path.size()) - { - path = path.substr(i); - for(size_t idx = 0; idx < n->indices.size(); ++idx) - { - if(n->indices[idx] == path[0]) - { - n = n->children[idx]; - get_impl(n, path, res, full); - } - } - } - else - { - if(!full) - { - res = true; - } - } + if(n->indices[idx] == path[0]) + { + n = n->children[idx]; + get_impl(n, path, res, full); + } } - else if(path == n->path) + } + else + { + if(!full) { - if(full) - { - res = n->word; - } - else - { - res = true; - } + res = true; } - - + } + } + else if(path == n->path) + { + if(full) + { + res = n->word; + } + else + { + res = true; + } } + } - static size_t common_prefix(const std::string_view& l, const std::string_view& r) + static size_t common_prefix(const std::string_view& l, const std::string_view& r) + { + int m = std::min(l.size(), r.size()); + size_t i = 0; + for(; i < m && l[i] == r[i];) { - int m = std::min(l.size(), r.size()); - size_t i = 0; - for(; i < m && l[i] == r[i];) - { - ++i; - } - return i; + ++i; } + return i; + } }; -#define put(x) do { std::cerr << "put: " << x << '\n'; r.put(x); } while(0) -#define has_prefix(x) do { std::cerr << "has_prefix: " << x << "? " << (r.has_prefix(x) ? "true" : "false") << '\n'; } while(0) -#define has_word(x) do { std::cerr << "has_word: " << x << "? " << (r.has_word(x) ? "true" : "false") << '\n'; } while(0) +#define put(x) \ + do \ + { \ + std::cerr << "put: " << x << '\n'; \ + r.put(x); \ + } while(0) +#define has_prefix(x) \ + do \ + { \ + std::cerr << "has_prefix: " << x << "? " << (r.has_prefix(x) ? "true" : "false") << '\n'; \ + } while(0) +#define has_word(x) \ + do \ + { \ + std::cerr << "has_word: " << x << "? " << (r.has_word(x) ? "true" : "false") << '\n'; \ + } while(0) int main() { - Router r{}; - put("dog"); - put("doges"); - put("did"); - put("doll"); - - has_prefix("d"); - has_prefix("do"); - has_prefix("dog"); - has_prefix("doge"); - has_prefix("doges"); - has_prefix("di"); - has_prefix("did"); - has_prefix("dol"); - has_prefix("doll"); - - has_word("d"); - has_word("do"); - has_word("dog"); - has_word("doge"); - has_word("doges"); - has_word("di"); - has_word("did"); - has_word("dol"); - has_word("doll"); + Router r{}; + put("dog"); + put("doges"); + put("did"); + put("doll"); + + has_prefix("d"); + has_prefix("do"); + has_prefix("dog"); + has_prefix("doge"); + has_prefix("doges"); + has_prefix("di"); + has_prefix("did"); + has_prefix("dol"); + has_prefix("doll"); + + has_word("d"); + has_word("do"); + has_word("dog"); + has_word("doge"); + has_word("doges"); + has_word("di"); + has_word("did"); + has_word("dol"); + has_word("doll"); } \ No newline at end of file diff --git a/signal/signal1.cpp b/signal/signal1.cpp index 3851ce8..920e6cd 100644 --- a/signal/signal1.cpp +++ b/signal/signal1.cpp @@ -11,20 +11,11 @@ struct T { - void print(int x) - { - std::cout << "member function: " << x << "\n"; - } - static void show(int x) - { - std::cout << "static member function: " << x << std::endl; - } + void print(int x) { std::cout << "member function: " << x << "\n"; } + static void show(int x) { std::cout << "static member function: " << x << std::endl; } }; -void print(int x) -{ - std::cout << "free function: " << x << "\n"; -} +void print(int x) { std::cout << "free function: " << x << "\n"; } int main() { @@ -32,12 +23,12 @@ int main() T t; Signal sig; auto m = sig.connect(&t); - auto handle = sig.connect([](int x){printf("anonymous function: %d\n", x);}); + auto handle = sig.connect([](int x) { printf("anonymous function: %d\n", x); }); sig.connect(&print); sig.connect(&T::show); sig.emit(40); std::cout << "----------------------\n"; - //sig.disconnect(&t); + // sig.disconnect(&t); sig.disconnect(handle); sig.disconnect(&print); sig.disconnect(&T::show); diff --git a/signal/signal1.h b/signal/signal1.h index b352f49..3811a71 100644 --- a/signal/signal1.h +++ b/signal/signal1.h @@ -15,14 +15,15 @@ namespace nm { namespace { - template struct sig_trait; + template + struct sig_trait; template struct sig_trait { - using mFunc = Res (*)(void*, Args...); - using Func = Res(*)(Args...); - sig_trait(const sig_trait& ) = delete; - sig_trait& operator= (const sig_trait&) = delete; + using mFunc = Res (*)(void*, Args...); + using Func = Res (*)(Args...); + sig_trait(const sig_trait&) = delete; + sig_trait& operator=(const sig_trait&) = delete; sig_trait(sig_trait&& rhs) { obj = rhs.obj; @@ -41,16 +42,10 @@ namespace nm callable = fp; mcallable = nullptr; } - template + template static sig_trait connect(Obj* o) { - return - { - o, [](void* obj, Args... args) - { - return (static_cast(obj)->*mfp)(std::forward(args)...); - } - }; + return {o, [](void* obj, Args... args) { return (static_cast(obj)->*mfp)(std::forward(args)...); }}; } template static sig_trait connect(F&& fp) @@ -75,60 +70,53 @@ namespace nm { using std::list; } - template class Signal; + template + class Signal; template class Signal { - public: - using data_type = Res(Paras...); - using handle_type = typename list>::iterator; - Signal(){} - Signal(const Signal&) = delete; - Signal& operator= (const Signal&) = delete; - ~Signal(){} - template - handle_type& connect(Obj* o) - { //sig_trait::template connect(o); RVO optimization - objs.push_back(sig_trait::template connect(o)); - return --objs.end(); - } - template - handle_type& connect(F&& fp) - { //sig_trait::connect(fp); RVO optimization - objs.push_back(sig_trait::connect(fp)); - return --objs.end(); - } - void disconnect(handle_type& handle) - { - objs.erase(handle); - } - template - void disconnect(F&& fp) - { - for(auto iter = objs.begin(); iter != objs.end();) - { - if(fp == iter->callable) - iter = objs.erase(iter); - else - ++iter; - } - } - template - void emit(Args&&... args) const - { - for(auto& x: objs) - x.call(std::forward(args)...); - } - std::size_t size() const - { - return objs.size(); - } - bool empty() const + public: + using data_type = Res(Paras...); + using handle_type = typename list>::iterator; + Signal() {} + Signal(const Signal&) = delete; + Signal& operator=(const Signal&) = delete; + ~Signal() {} + template + handle_type& connect(Obj* o) + { // sig_trait::template connect(o); RVO optimization + objs.push_back(sig_trait::template connect(o)); + return --objs.end(); + } + template + handle_type& connect(F&& fp) + { // sig_trait::connect(fp); RVO optimization + objs.push_back(sig_trait::connect(fp)); + return --objs.end(); + } + void disconnect(handle_type& handle) { objs.erase(handle); } + template + void disconnect(F&& fp) + { + for(auto iter = objs.begin(); iter != objs.end();) { - return objs.empty(); + if(fp == iter->callable) + iter = objs.erase(iter); + else + ++iter; } - private: - list> objs; + } + template + void emit(Args&&... args) const + { + for(auto& x: objs) + x.call(std::forward(args)...); + } + std::size_t size() const { return objs.size(); } + bool empty() const { return objs.empty(); } + + private: + list> objs; }; } } diff --git a/signal/signal2.cpp b/signal/signal2.cpp index 858e9f4..54b3d3b 100644 --- a/signal/signal2.cpp +++ b/signal/signal2.cpp @@ -10,20 +10,11 @@ struct T { - void print(int x) - { - std::cout << "member function: " << x << "\n"; - } - static void show(int x) - { - std::cout << "static member function: " << x << std::endl; - } + void print(int x) { std::cout << "member function: " << x << "\n"; } + static void show(int x) { std::cout << "static member function: " << x << std::endl; } }; -void print(int x) -{ - std::cout << "free function: " << x << "\n"; -} +void print(int x) { std::cout << "free function: " << x << "\n"; } int main() { @@ -31,17 +22,16 @@ int main() T t; Signal sig; auto m = sig.connect(&t, &T::print); - auto handle = sig.connect([](int x){printf("anonymous function: %d\n", x);}); + auto handle = sig.connect([](int x) { printf("anonymous function: %d\n", x); }); sig.connect(&print); sig.connect(&T::show); - sig.connect([&](int x) - { - t.print(x); - print(x); - }); + sig.connect([&](int x) { + t.print(x); + print(x); + }); sig.emit(40); std::cout << "----------------------\n"; - //sig.disconnect(&t); + // sig.disconnect(&t); sig.disconnect(handle); sig.disconnect(m); sig.emit(30); diff --git a/signal/signal2.h b/signal/signal2.h index a6baee9..de80f7d 100644 --- a/signal/signal2.h +++ b/signal/signal2.h @@ -16,13 +16,14 @@ namespace nm { namespace { - template struct sig_trait; + template + struct sig_trait; template struct sig_trait { - using Func = std::function; - sig_trait(const sig_trait& ) = delete; - sig_trait& operator= (const sig_trait&) = delete; + using Func = std::function; + sig_trait(const sig_trait&) = delete; + sig_trait& operator=(const sig_trait&) = delete; sig_trait(sig_trait&& rhs) { obj = rhs.obj; @@ -58,57 +59,46 @@ namespace nm { using std::list; } - template class Signal; + template + class Signal; template class Signal { - public: - using data_type = Res(Paras...); - using handle_type = typename list>::iterator; - Signal(){} - Signal(const Signal&) = delete; - Signal& operator= (const Signal&) = delete; - ~Signal(){} - template - handle_type& connect(Obj* o, F&& f) - { - auto fp = [f](void* obj, Paras... paras) - { - return (static_cast(obj)->*f)(std::forward(paras)...); - }; - objs.push_back(sig_trait::template connect(o, fp)); - return --objs.end(); - } - template - handle_type& connect(F&& f) - { - auto fp = [f](void*, Paras... paras) - { - return f(std::forward(paras)...); - }; - objs.push_back(sig_trait::connect(fp)); - return --objs.end(); - } - void disconnect(handle_type& handle) - { - objs.erase(handle); - } - template - void emit(Args&&... args) const - { - for(auto& x: objs) - x.call(std::forward(args)...); - } - std::size_t size() const - { - return objs.size(); - } - bool empty() const - { - return objs.empty(); - } - private: - list> objs; + public: + using data_type = Res(Paras...); + using handle_type = typename list>::iterator; + Signal() {} + Signal(const Signal&) = delete; + Signal& operator=(const Signal&) = delete; + ~Signal() {} + template + handle_type& connect(Obj* o, F&& f) + { + auto fp = [f](void* obj, Paras... paras) { + return (static_cast(obj)->*f)(std::forward(paras)...); + }; + objs.push_back(sig_trait::template connect(o, fp)); + return --objs.end(); + } + template + handle_type& connect(F&& f) + { + auto fp = [f](void*, Paras... paras) { return f(std::forward(paras)...); }; + objs.push_back(sig_trait::connect(fp)); + return --objs.end(); + } + void disconnect(handle_type& handle) { objs.erase(handle); } + template + void emit(Args&&... args) const + { + for(auto& x: objs) + x.call(std::forward(args)...); + } + std::size_t size() const { return objs.size(); } + bool empty() const { return objs.empty(); } + + private: + list> objs; }; } } diff --git a/signal/signal_call.h b/signal/signal_call.h index 8534149..6074bf0 100644 --- a/signal/signal_call.h +++ b/signal/signal_call.h @@ -16,10 +16,18 @@ namespace nm { namespace { - struct thread_safe {}; - struct non_thread_safe {}; - struct member_function {}; - struct non_member_function {}; + struct thread_safe + { + }; + struct non_thread_safe + { + }; + struct member_function + { + }; + struct non_member_function + { + }; template struct Trait; @@ -32,10 +40,7 @@ namespace nm typedef member_function func_type; typedef Obj Object; typedef Res (Obj::*Func)(Args...); - static void call(Func f, Obj *o, Args&&... args) - { - (o->*f)(std::forward(args)...); - } + static void call(Func f, Obj* o, Args&&... args) { (o->*f)(std::forward(args)...); } }; // specialization @@ -46,104 +51,96 @@ namespace nm typedef non_member_function func_type; typedef Res (*Func)(Args...); typedef Res Object; - static void call(Func f, Object *, Args&&... args) - { - (*f)(std::forward(args)...); - } + static void call(Func f, Object*, Args&&... args) { (*f)(std::forward(args)...); } }; } - template using SafeTrait = Trait; + template + using SafeTrait = Trait; // template using UnSafeTrait = SomeTrait; template class Default = SafeTrait> class Signal { - public: - using Handle = typename std::list::iterator; - Signal() - { - obj = nullptr; - } + public: + using Handle = typename std::list::iterator; + Signal() { obj = nullptr; } - Signal(const Signal&) = delete; + Signal(const Signal&) = delete; - Signal& operator= (const Signal&) = delete; + Signal& operator=(const Signal&) = delete; - ~Signal() - { - callable.clear(); - obj = nullptr; - } + ~Signal() + { + callable.clear(); + obj = nullptr; + } - template - Handle connect(typename Trait::Object *recv, Func slot) - { - obj = recv; - callable.push_back(slot); - return --callable.end(); - } + template + Handle connect(typename Trait::Object* recv, Func slot) + { + obj = recv; + callable.push_back(slot); + return --callable.end(); + } - template - Handle connect(Func&& f) - { - callable.push_back(f); - return --callable.end(); - } + template + Handle connect(Func&& f) + { + callable.push_back(f); + return --callable.end(); + } - void disconnect(Handle iter) - { - callable.erase(iter); - } + void disconnect(Handle iter) { callable.erase(iter); } - void disconnect(T fp) + void disconnect(T fp) + { + for(auto iter = callable.begin(); iter != callable.end();) { - for(auto iter = callable.begin(); iter != callable.end();) - { - if(*iter == fp) - iter = callable.erase(iter); - else - ++iter; - } + if(*iter == fp) + iter = callable.erase(iter); + else + ++iter; } + } - template - void emit(Args&&... args) - { - this->exec(typename Default::safe_type(), std::forward(args)...); - } + template + void emit(Args&&... args) + { + this->exec(typename Default::safe_type(), std::forward(args)...); + } - private: - typename Default::Object* obj; - std::list callable; - std::mutex l; + private: + typename Default::Object* obj; + std::list callable; + std::mutex l; - template - void do_exec(member_function, Args&&... args) - { - for(auto &x: callable) - Default::call(x, obj, std::forward(args)...); - } + template + void do_exec(member_function, Args&&... args) + { + for(auto& x: callable) + Default::call(x, obj, std::forward(args)...); + } - template - void do_exec(non_member_function, Args&&... args) - { - for(auto &x: callable) - Default::call(x, nullptr, std::forward(args)...); - } + template + void do_exec(non_member_function, Args&&... args) + { + for(auto& x: callable) + Default::call(x, nullptr, std::forward(args)...); + } - template - void exec(thread_safe, Args&&... args) - { - std::lock_guard lock(l); - do_exec(typename Default::func_type(), std::forward(args)...); - } + template + void exec(thread_safe, Args&&... args) + { + std::lock_guard lock(l); + do_exec(typename Default::func_type(), std::forward(args)...); + } - template - void exec(non_thread_safe, Args&&... args) - { - do_exec(typename Default::func_type(), std::forward(args)...); - } + template + void exec(non_thread_safe, Args&&... args) + { + do_exec(typename Default::func_type(), std::forward(args)...); + } }; } diff --git a/signal/signal_call_test.cpp b/signal/signal_call_test.cpp index d064937..d8000df 100644 --- a/signal/signal_call_test.cpp +++ b/signal/signal_call_test.cpp @@ -10,16 +10,10 @@ class Test { - public: - void p(int x) - { - std::cout << x << std::endl; - } +public: + void p(int x) { std::cout << x << std::endl; } - void show(int x) - { - std::cout << "show => " << x << std::endl; - } + void show(int x) { std::cout << "show => " << x << std::endl; } }; int main() @@ -33,12 +27,11 @@ int main() s.disconnect(&Test::show); s.emit(10); - nm::Signal s1; - auto handle = s1.connect([](int x) -> int - { - std::cout << x << std::endl; - return x; - }); + nm::Signal s1; + auto handle = s1.connect([](int x) -> int { + std::cout << x << std::endl; + return x; + }); s1.emit(11); s1.disconnect(handle); s1.emit(12); diff --git a/string_ext/string_ext.h b/string_ext/string_ext.h index 7643a54..105e416 100644 --- a/string_ext/string_ext.h +++ b/string_ext/string_ext.h @@ -18,445 +18,388 @@ namespace nm { class string_ext : public std::string { - using Base = std::string; - using std::string::const_iterator; - //struct null_t {}; - public: - //constexpr static null_t null{}; - string_ext() - : Base() - {} + using Base = std::string; + using std::string::const_iterator; + // struct null_t {}; + public: + // constexpr static null_t null{}; + string_ext() : Base() {} + + string_ext(size_type count, char ch) : Base(count, ch) {} + + string_ext(const string_ext& other, size_type pos) : Base(other, pos) {} + + string_ext(const string_ext& other, size_type pos, size_type count) : Base(other, pos, count) {} + + string_ext(char* s, size_type count) : Base(s, count) {} + + string_ext(const char* s) : Base(s) {} + + template + string_ext(InputIt first, InputIt last) : Base(first, last) + { + } - string_ext(size_type count, char ch) - : Base(count, ch) - {} + string_ext(const string_ext& other) : Base(other) {} - string_ext(const string_ext& other, size_type pos) - : Base(other, pos) - {} + string_ext(string_ext&& other) : Base(std::move(other)) {} - string_ext(const string_ext& other, size_type pos, size_type count) - : Base(other, pos, count) - {} + string_ext(std::initializer_list il) : Base(il) {} - string_ext(char* s, size_type count) - : Base(s, count) - {} + string_ext(const Base& rhs) : Base(rhs) {} - string_ext(const char* s) - : Base(s) - {} + string_ext(Base&& rhs) : Base(std::move(rhs)) {} - template - string_ext(InputIt first, InputIt last) - : Base(first, last) - {} + string_ext& operator=(const string_ext& rhs) + { + if(this != &rhs) + Base::operator=(rhs); + return *this; + } - string_ext(const string_ext& other) - : Base(other) - {} + string_ext& operator=(string_ext&& rhs) + { + if(this != &rhs) + Base::operator=(std::move(rhs)); + return *this; + } - string_ext(string_ext&& other) - : Base(std::move(other)) - {} + string_ext& to_upper() + { + std::transform(begin(), end(), begin(), [](unsigned char x) { return std::toupper(x); }); + return *this; + } - string_ext(std::initializer_list il) - : Base(il) - {} + string_ext& to_lower() + { + std::transform(begin(), end(), begin(), [](unsigned char x) { return std::tolower(x); }); + return *this; + } - string_ext(const Base& rhs) - : Base(rhs) - {} + bool is_upper() const + { + return check([](const_iterator& iter) { return std::isupper(*iter); }); + } - string_ext(Base&& rhs) - : Base(std::move(rhs)) - {} + bool is_lower() const + { + return check([](const_iterator& iter) { return std::islower(*iter); }); + } - string_ext& operator= (const string_ext& rhs) + bool is_alpha() const + { + return check([](const_iterator& iter) { return std::isalpha(*iter); }); + } + + bool is_alnum() const + { + return check([](const_iterator& iter) { return std::isalnum(*iter); }); + } + + bool is_digit() const + { + return check([](const_iterator& iter) { return std::isdigit(*iter); }); + } + + bool is_space() const + { + return check([](const_iterator& iter) { return std::isspace(*iter); }); + } + + bool match(const std::regex& re) { return std::regex_match(*this, re); } + + bool match(const string_ext& pattern) + { + try { - if(this != &rhs) - Base::operator= (rhs); - return *this; + std::regex re{pattern}; + return this->match(re); } - - string_ext& operator= (string_ext&& rhs) + catch(const std::regex_error&) { - if(this != &rhs) - Base::operator= (std::move(rhs)); - return *this; + return false; } + } - string_ext& to_upper() + template + bool extract(const std::regex& re, Args&&... args) + { + std::smatch res; + if(std::regex_match(*this, res, re)) { - std::transform(begin(), end(), begin(), [](unsigned char x) { - return std::toupper(x); - }); - return *this; + return this->apply(res, Parser(std::forward(args))...); } + return false; + } - string_ext& to_lower() + template + bool extract(const string_ext& pattern, Args&&... args) + { + try { - std::transform(begin(), end(), begin(), [](unsigned char x) { - return std::tolower(x); - }); - return *this; + std::regex re{pattern}; + return this->extract(re, std::forward(args)...); } - - bool is_upper() const + catch(const std::regex_error&) { - return check([](const_iterator& iter) { - return std::isupper(*iter); - }); + return false; } - - bool is_lower() const + } + + string_ext join(const std::vector& seq) const + { + std::vector::size_type len = seq.size(), i = 0; + if(len == 0) + return {}; + if(len == 1) + return seq[0]; + string_ext res; + for(i = 1; i < len; ++i) { - return check([](const_iterator& iter) { - return std::islower(*iter); - }); + res += *this + seq[i]; } + return res; + } + + string_ext& lstrip(const string_ext& chars = string_ext()) { return strip_impl(L_STRIP, chars); } - bool is_alpha() const + string_ext& rstrip(const string_ext& chars = string_ext()) { return strip_impl(R_STRIP, chars); } + + string_ext& strip(const string_ext& chars = string_ext()) + { + strip_impl(L_STRIP, chars); + return strip_impl(R_STRIP, chars); + } + + string_ext& replace(const string_ext& oldstr, const string_ext& newstr, long count) + { + auto pos = this->find(oldstr); + if(pos == npos) + return *this; + auto old_len = oldstr.size(); + std::function pred{}; + if(count <= 0) + pred = [&pos, this] { return pos != npos; }; + else + pred = [&count, &pos, this] { return count-- > 0 && pos != npos; }; + + while(pred()) { - return check([](const_iterator& iter) { - return std::isalpha(*iter); - }); + Base::replace(pos, old_len, newstr); + pos = Base::find(oldstr); } - - bool is_alnum() const + return *this; + } + + template + void split(Container& res, const string_ext& sep = string_ext(), long max = -1) const + { + if(max < 0) + max = std::numeric_limits::max(); + + auto sep_len = sep.size(); + auto cur = begin(); + auto iter = cur; + if(sep_len == 0) { - return check([](const_iterator& iter) { - return std::isalnum(*iter); - }); + for(; max > 0 && iter != end(); ++iter) + { + if(std::isspace(*iter)) + { + res.emplace_back(this->substr(cur - begin(), iter - cur)); + cur = iter; + max -= 1; + } + } } - - bool is_digit() const + else { - return check([](const_iterator& iter) { - return std::isdigit(*iter); - }); + while(max > 0 && iter != end()) + { + if(this->substr(iter - begin(), sep_len) == sep) + { + res.emplace_back(this->substr(cur - begin(), iter - cur)); + iter += sep_len; + cur = iter; + max -= 1; + } + else + { + ++iter; + } + } } + res.emplace_back(this->substr(cur - begin())); + } + + private: + enum + { + L_STRIP = 0, + R_STRIP + }; + + class Parser + { + public: + explicit Parser(void*) = delete; + explicit Parser(std::nullptr_t) : arg_(nullptr), parser_([](const string_ext&, void*) {}) {} - bool is_space() const + Parser(int* x) + : arg_(x), parser_([](const string_ext& str, void* res) { *static_cast(res) = std::stoi(str); }) { - return check([](const_iterator& iter) { - return std::isspace(*iter); - }); } - bool match(const std::regex& re) + Parser(long* x) + : arg_(x), parser_([](const string_ext& str, void* res) { *static_cast(res) = std::stol(str); }) { - return std::regex_match(*this, re); } - bool match(const string_ext& pattern) + Parser(long long* x) + : arg_(x), parser_([](const string_ext& str, void* res) { *static_cast(res) = std::stoll(str); }) { - try - { - std::regex re{pattern}; - return this->match(re); - } - catch(const std::regex_error&) - { - return false; - } } - template - bool extract(const std::regex& re, Args&&... args) + Parser(unsigned* x) + : arg_(x), parser_([](const string_ext& str, void* res) { + using std::stoul; + *static_cast(res) = static_cast(stoul(str)); + }) { - std::smatch res; - if(std::regex_match(*this, res, re)) - { - return this->apply(res, Parser(std::forward(args))...); - } - return false; } - template - bool extract(const string_ext& pattern, Args&&... args) + Parser(unsigned long* x) + : arg_(x), + parser_([](const string_ext& str, void* res) { *static_cast(res) = std::stoul(str); }) { - try - { - std::regex re{pattern}; - return this->extract(re, std::forward(args)...); - } - catch(const std::regex_error&) - { - return false; - } } - string_ext join(const std::vector& seq) const + Parser(unsigned long long* x) + : arg_(x), + parser_([](const string_ext& str, void* res) { *static_cast(res) = std::stoull(str); }) { - std::vector::size_type len = seq.size(), i = 0; - if(len == 0) - return {}; - if(len == 1) - return seq[0]; - string_ext res; - for(i = 1; i < len; ++i) - { - res += *this + seq[i]; - } - return res; } - string_ext& lstrip(const string_ext& chars = string_ext()) + Parser(float* x) + : arg_(x), parser_([](const string_ext& str, void* res) { *static_cast(res) = std::stof(str); }) { - return strip_impl(L_STRIP, chars); } - string_ext& rstrip(const string_ext& chars = string_ext()) + Parser(double* x) + : arg_(x), parser_([](const string_ext& str, void* res) { *static_cast(res) = std::stod(str); }) { - return strip_impl(R_STRIP, chars); } - string_ext& strip(const string_ext& chars = string_ext()) + Parser(long double* x) + : arg_(x), + parser_([](const string_ext& str, void* res) { *static_cast(res) = std::stold(str); }) { - strip_impl(L_STRIP, chars); - return strip_impl(R_STRIP, chars); } - string_ext& replace(const string_ext& oldstr, - const string_ext& newstr, - long count) + Parser(bool* x) + : arg_(x), parser_([](const string_ext& str, void* res) { + auto& r = *static_cast(res); + if(str == "true") + r = true; + else if(str == "false") + r = false; + else + throw std::logic_error("invalid argument"); + }) { - auto pos = this->find(oldstr); - if(pos == npos) - return *this; - auto old_len = oldstr.size(); - std::function pred{}; - if(count <= 0) - pred = [&pos, this] { return pos != npos; }; - else - pred = [&count, &pos, this] { return count-- > 0 && pos != npos; }; - - while(pred()) - { - Base::replace(pos, old_len, newstr); - pos = Base::find(oldstr); - } - return *this; } - template - void split(Container& res, const string_ext& sep = string_ext(), - long max = -1) const + Parser(Base* x) : arg_(x), parser_([](const string_ext& str, void* res) { *static_cast(res) = str; }) {} + + Parser(string_ext* x) + : arg_(x), parser_([](const string_ext& str, void* res) { *static_cast(res) = str; }) { - if(max < 0) - max = std::numeric_limits::max(); + } - auto sep_len = sep.size(); - auto cur = begin(); - auto iter = cur; - if(sep_len == 0) + bool parse(const string_ext& s) + { + try { - for(; max > 0 && iter != end(); ++iter) - { - if(std::isspace(*iter)) - { - res.emplace_back(this->substr(cur - begin(), iter - cur)); - cur = iter; - max -= 1; - } - } + parser_(s, arg_); } - else + catch(...) { - while(max > 0 && iter != end()) - { - if(this->substr(iter - begin(), sep_len) == sep) - { - res.emplace_back(this->substr(cur - begin(), iter - cur)); - iter += sep_len; - cur = iter; - max -= 1; - } - else - { - ++iter; - } - } + return false; } - res.emplace_back(this->substr(cur - begin())); + return true; } private: - enum { L_STRIP = 0, R_STRIP }; - - class Parser + void* arg_; + std::function parser_; + }; + + template + bool apply(C& c, Args&&... args) + { + auto argc = sizeof...(args); + Parser* argv[] = {&args...}; + for(size_t i = 1; i < c.size() && i < argc + 1; ++i) { - public: - explicit Parser(void*) = delete; - explicit Parser(std::nullptr_t) - : arg_(nullptr), parser_([](const string_ext&, void*) {}) - {} - - Parser(int* x) - : arg_(x), parser_([](const string_ext& str, void* res) { - *static_cast(res) = std::stoi(str); - }) - {} - - Parser(long* x) - : arg_(x), parser_([](const string_ext& str, void* res) { - *static_cast(res) = std::stol(str); - }) - {} - - Parser(long long* x) - : arg_(x), parser_([](const string_ext& str, void* res) { - *static_cast(res) = std::stoll(str); - }) - {} - - Parser(unsigned* x) - : arg_(x), parser_([](const string_ext& str, void* res) { - using std::stoul; - *static_cast(res) = static_cast(stoul(str)); - }) - {} - - Parser(unsigned long* x) - : arg_(x), parser_([](const string_ext& str, void* res) { - *static_cast(res) = std::stoul(str); - }) - {} - - Parser(unsigned long long* x) - : arg_(x), parser_([](const string_ext& str, void* res) { - *static_cast(res) = std::stoull(str); - }) - {} - - Parser(float* x) - : arg_(x), parser_([](const string_ext& str, void* res) { - *static_cast(res) = std::stof(str); - }) - {} - - Parser(double* x) - : arg_(x), parser_([](const string_ext& str, void* res) { - *static_cast(res) = std::stod(str); - }) - {} - - Parser(long double* x) - : arg_(x), parser_([](const string_ext& str, void* res) { - *static_cast(res) = std::stold(str); - }) - {} - - Parser(bool* x) - : arg_(x), parser_([](const string_ext& str, void* res) { - auto& r = *static_cast(res); - if(str == "true") - r = true; - else if(str == "false") - r = false; - else - throw std::logic_error("invalid argument"); - }) - {} - - Parser(Base* x) - : arg_(x), parser_([](const string_ext& str, void* res) { - *static_cast(res) = str; - }) - {} - - Parser(string_ext* x) - : arg_(x), parser_([](const string_ext& str, void* res) { - *static_cast(res) = str; - }) - {} - - bool parse(const string_ext& s) - { - try - { - parser_(s, arg_); - } - catch(...) - { - return false; - } - return true; - } - - private: - void* arg_; - std::function parser_; - }; - - template - bool apply(C& c, Args&&... args) - { - auto argc = sizeof...(args); - Parser* argv[] = {&args...}; - for(size_t i = 1; i < c.size() && i < argc + 1; ++i) - { - if(!argv[i - 1]->parse(c[i].str())) - return false; - } - return true; + if(!argv[i - 1]->parse(c[i].str())) + return false; } + return true; + } - bool check(std::function pred) const + bool check(std::function pred) const + { + for(auto iter = cbegin(); iter != cend(); ++iter) { - for(auto iter = cbegin(); iter != cend(); ++iter) - { - if(!pred(iter)) - return false; - } - return true; + if(!pred(iter)) + return false; } + return true; + } - string_ext& strip_impl(int type, const string_ext& chars) + string_ext& strip_impl(int type, const string_ext& chars) + { + auto chars_len = chars.length(); + if(chars_len == 0) { - auto chars_len = chars.length(); - if(chars_len == 0) + if(type == L_STRIP) { - if(type == L_STRIP) + auto iter = begin(); + while(iter != end() && std::isspace(*iter)) { - auto iter = begin(); - while(iter != end() && std::isspace(*iter)) - { - ++iter; - } - this->erase(0, iter - begin()); + ++iter; } - else + this->erase(0, iter - begin()); + } + else + { + auto iter = rbegin(); + while(iter != rend() && std::isspace(*iter)) { - auto iter = rbegin(); - while(iter != rend() && std::isspace(*iter)) - { - ++iter; - } - this->erase(rend() - iter); + ++iter; } + this->erase(rend() - iter); } - else + } + else + { + if(type == L_STRIP) { - if(type == L_STRIP) + while(this->substr(0, chars_len) == chars) { - while(this->substr(0, chars_len) == chars) - { - this->erase(0, chars_len); - } + this->erase(0, chars_len); } - else + } + else + { + while(this->size() > chars_len && this->substr(this->size() - chars_len, chars_len) == chars) { - while(this->size() > chars_len && - this->substr(this->size() - chars_len, chars_len) == chars) - { - this->erase(this->size() - chars_len); - } + this->erase(this->size() - chars_len); } } - return *this; } + return *this; + } }; } diff --git a/string_ext/test.cpp b/string_ext/test.cpp index 1082173..c7eb422 100644 --- a/string_ext/test.cpp +++ b/string_ext/test.cpp @@ -35,19 +35,19 @@ bool check(const string_ext& ip) } if(count > 255) return false; - // strict + // strict switch(x.size()) { - case 2: - if(count < 10) - return false; - break; - case 3: - if(count < 100) - return false; - break; - default: - break; + case 2: + if(count < 10) + return false; + break; + case 3: + if(count < 100) + return false; + break; + default: + break; } } return true; @@ -63,7 +63,7 @@ int main(int argc, char* argv[]) ifstream in(argv[1], in.in); if(!in.is_open()) { - cout << "can't open file: " << argv[1] << endl; + cout << "can't open file: " << argv[1] << endl; } string_ext line; vector ips; @@ -78,7 +78,8 @@ int main(int argc, char* argv[]) if(ip.size() != 0) cout << (check(ip) ? "valid ip" : "invalid ip") << "\t" << ip << endl; } - string_ext b{R"del(http://gslb.miaopai.com/stream/aQVm-hdSl~OLe6Lh7Q6C9A__.mp4?yx=&refer=weibo_app&Expires=1490264147&ssig=07XsfjKJkG&KID=unistore,video)del"}; + string_ext b{ + R"del(http://gslb.miaopai.com/stream/aQVm-hdSl~OLe6Lh7Q6C9A__.mp4?yx=&refer=weibo_app&Expires=1490264147&ssig=07XsfjKJkG&KID=unistore,video)del"}; string_ext pattern{R"del(http://(.*\.miaopai.com)/(.*)/([^?]*)(.*))del"}; bool res = b.match(pattern); if(res) diff --git a/string_view.h b/string_view.h index 2dfa395..ed99cf9 100644 --- a/string_view.h +++ b/string_view.h @@ -31,23 +31,22 @@ namespace nm constexpr static size_type npos = size_type(-1); // member functions - constexpr basic_string_view() - : data_{ nullptr }, len_{ 0 } - {} + constexpr basic_string_view() : data_{nullptr}, len_{0} {} - basic_string_view(const value_type* data) - : data_{ data }, len_{ data ? StringType::traits_type::length(data) : 0 } - {} + template + explicit basic_string_view(const T& t) : data_{t.data()}, len_{t.size()} + { + } + + basic_string_view(const std::string& s) : data_{s.data()}, len_{s.size()} {} - constexpr basic_string_view(const value_type* data, size_type len) - : data_{ data }, len_{ len } - {} + basic_string_view(const value_type* data) : data_{data}, len_{data ? StringType::traits_type::length(data) : 0} {} - constexpr basic_string_view(const basic_string_view& rhs) - : data_{ rhs.data_ }, len_{ rhs.len_ } - {} + constexpr basic_string_view(const value_type* data, size_type len) : data_{data}, len_{len} {} - basic_string_view& operator= (basic_string_view&& rhs) noexcept + constexpr basic_string_view(const basic_string_view& rhs) : data_{rhs.data_}, len_{rhs.len_} {} + + basic_string_view& operator=(basic_string_view&& rhs) noexcept { if(this != &rhs) { @@ -58,7 +57,7 @@ namespace nm return *this; } - basic_string_view& operator= (const basic_string_view& rhs) + basic_string_view& operator=(const basic_string_view& rhs) { if(this != &rhs) { @@ -80,8 +79,10 @@ namespace nm len_ = len; } + operator std::string() { return {data_, len_}; } + // element access - value_type at(size_type i) const + value_type& at(size_type i) const { if(i >= len_) { @@ -90,67 +91,33 @@ namespace nm return data_[i]; } - value_type operator[] (size_type i) const - { - return data_[i]; - } + value_type operator[](size_type i) const { return data_[i]; } - const value_type* data() const - { - return data_; - } + void set(size_type i, value_type v) { data_[i] = v; } - const value_type* c_str() const - { - return data_; - } + const value_type* data() const { return data_; } + + const value_type* c_str() const { return data_; } // iterators - const_iterator begin() const - { - return data_; - } + const_iterator begin() const { return data_; } - const_iterator end() const - { - return data_ + len_; - } + const_iterator end() const { return data_ + len_; } - const_reverse_iterator rbegin() const - { - return const_reverse_iterator(data_ + len_); - } + const_reverse_iterator rbegin() const { return const_reverse_iterator(data_ + len_); } - const_reverse_iterator rend() const - { - return const_reverse_iterator(data_); - } + const_reverse_iterator rend() const { return const_reverse_iterator(data_); } // capacity - bool empty() const - { - return len_ == 0; - } + bool empty() const { return len_ == 0; } - size_type size() const - { - return len_; - } + size_type size() const { return len_; } - size_type length() const - { - return len_; - } + size_type length() const { return len_; } - size_type max_size() const - { - return len_; - } + size_type max_size() const { return len_; } - size_type capacity() const - { - return len_; - } + size_type capacity() const { return len_; } // operations void clear() @@ -176,15 +143,44 @@ namespace nm return r; } - void remove_prefix(size_type n) + basic_string_view& remove_prefix(size_type n) { data_ += n; len_ -= n; + return *this; } - void remove_suffix(size_type n) + basic_string_view& remove_suffix(size_type n) { len_ -= n; + return *this; + } + + basic_string_view trim() + { + basic_string_view res = *this; + if(this->empty()) + { + return {}; + } + + while(*res.data() == ' ' || *res.data() == '\r' || *res.data() == '\n' || *res.data() == '\t') + { + res.remove_prefix(1); + } + while(!res.empty()) + { + auto tail = res.end() - 1; + if(*tail == ' ' || *tail == '\r' || *tail == '\n' || *tail == '\t') + { + res.remove_suffix(1); + } + else + { + break; + } + } + return res; } bool starts_with(const basic_string_view& x) const @@ -197,7 +193,7 @@ namespace nm return ((len_ >= x.len_) && (cmp(data_ + (len_ - x.len_), x.data_, x.len_) == 0)); } - basic_string_view substr(size_type pos, size_type size) const + basic_string_view substr(size_type pos, size_type size = npos) const { if(pos > this->size()) { @@ -207,7 +203,7 @@ namespace nm { size = this->size() - pos; } - return { data_ + pos, size }; + return {data_ + pos, size}; } size_type copy(value_type* s, size_type count, size_type pos = 0) const @@ -280,7 +276,7 @@ namespace nm { return this->find(x.data()[0], pos); } - bool lookup[uchar_max + 1] = { false }; + bool lookup[uchar_max + 1] = {false}; build_table(x, lookup); for(size_type i = pos; i < this->size(); ++i) { @@ -306,7 +302,7 @@ namespace nm { return this->find_first_not_of(x.data()[0], pos); } - bool lookup[uchar_max + 1] = { false }; + bool lookup[uchar_max + 1] = {false}; build_table(x, lookup); for(size_type i = pos; i < this->size(); ++i) { @@ -344,7 +340,7 @@ namespace nm { return this->rfind(x.data()[0], pos); } - bool lookup[uchar_max + 1] = { false }; + bool lookup[uchar_max + 1] = {false}; build_table(x, lookup); for(size_type i = std::min(pos, this->size() - 1); i > 0; --i) { @@ -371,7 +367,7 @@ namespace nm { return this->find_last_not_of(x.data()[0], pos); } - bool lookup[uchar_max + 1] = { false }; + bool lookup[uchar_max + 1] = {false}; build_table(x, lookup); for(; i > 0; --i) { @@ -399,17 +395,14 @@ namespace nm return npos; } - std::string to_string() - { - return { data_, len_ }; - } + std::string to_string() const { return {data_, len_}; } static int cmp(const value_type* l, const value_type* r, size_type n) { return StringType::traits_type::compare(l, r, n); } - protected: + private: const value_type* data_; size_type len_; @@ -427,39 +420,27 @@ namespace nm using string_view = basic_string_view; - bool operator== (const string_view& x, const string_view& y) + inline bool operator==(const string_view& x, const string_view& y) { auto r = string_view::cmp(x.data(), y.data(), std::min(x.size(), y.size())); return r == 0 && x.size() == y.size(); } - inline bool operator!= (const string_view& x, const string_view& y) - { - return !(x == y); - } + inline bool operator!=(const string_view& x, const string_view& y) { return !(x == y); } - inline bool operator< (const string_view& x, const string_view& y) + inline bool operator<(const string_view& x, const string_view& y) { auto r = string_view::cmp(x.data(), y.data(), (x.size() < y.size() ? x.size() : y.size())); return ((r < 0) || ((r == 0) && (x.size() < y.size()))); } - inline bool operator> (const string_view& x, const string_view& y) - { - return y < x; - } + inline bool operator>(const string_view& x, const string_view& y) { return y < x; } - inline bool operator<= (const string_view& x, const string_view& y) - { - return !(x > y); - } + inline bool operator<=(const string_view& x, const string_view& y) { return !(x > y); } - inline bool operator>= (const string_view& x, const string_view& y) - { - return !(x < y); - } + inline bool operator>=(const string_view& x, const string_view& y) { return !(x < y); } - inline std::ostream& operator<< (std::ostream& os, const string_view& v) + inline std::ostream& operator<<(std::ostream& os, const string_view& v) { os.write(v.data(), v.size()); return os; @@ -467,7 +448,34 @@ namespace nm constexpr string_view operator""_sv(const string_view::value_type* data, string_view::size_type len) { - return { data, len }; + return {data, len}; + } + + inline int compare_i(const string_view& l, const string_view& r) + { + auto lb = l.begin(); + auto rb = r.begin(); + while(lb != l.end() && rb != r.end()) + { + if(*lb != *rb && std::tolower(*lb) != std::tolower(*rb)) + { + break; + } + ++lb; + ++rb; + } + if(l.size() == r.size()) + { + return 0; + } + else if(l.size() < r.size()) + { + return -1; + } + else + { + return 1; + } } } diff --git a/threadpool/test_threadpool.cpp b/threadpool/test_threadpool.cpp index 20eb189..fb5b06d 100644 --- a/threadpool/test_threadpool.cpp +++ b/threadpool/test_threadpool.cpp @@ -14,11 +14,10 @@ using namespace std; int main() { - auto f = [](int x) - { + auto f = [](int x) { this_thread::sleep_for(chrono::seconds(2)); printf("%d\n", x * x); - return (x*x); + return (x * x); }; nm::threadpool pool; pool.add_task(f, 1); @@ -50,10 +49,7 @@ int main() cout << "get: " << fut.get() << endl; this_thread::sleep_for(chrono::seconds(3)); cout << "--------------------------------------------------------\n"; - auto f2 = [](int x) - { - cout << "tid: " << this_thread::get_id() << "\tdata: " << (x * 2) << endl; - }; + auto f2 = [](int x) { cout << "tid: " << this_thread::get_id() << "\tdata: " << (x * 2) << endl; }; nm::threadpool pool2(std::launch::deferred); pool2.add_task(f2, -1); pool2.add_task(f2, -2); @@ -71,7 +67,7 @@ int main() cout << "Exception: " << e.what() << endl; } nm::threadpool pool3(std::launch::deferred); - pool3.pause(); // set `is_start_` flag in destructor + pool3.pause(); // set `is_start_` flag in destructor pool3.wait(); cout << "done.\n"; } diff --git a/threadpool/threadpool.h b/threadpool/threadpool.h index a65f455..4fa43ed 100644 --- a/threadpool/threadpool.h +++ b/threadpool/threadpool.h @@ -24,88 +24,83 @@ namespace nm { class threadpool final { - public: - threadpool(); - threadpool(std::launch, - std::size_t threads = std::thread::hardware_concurrency()); - threadpool(threadpool&&) = delete; - threadpool(const threadpool&) = delete; - threadpool& operator=(const threadpool&) = delete; - ~threadpool() noexcept; - template - auto add_task(F&&, Args&&...) - -> std::future::type>; - size_t queue_size_limit(); - void set_queue_size_limit(size_t); - void start(); - void wait(); - void pause(); - void stop(); - bool valid() const; - private: - std::launch policy_; - // we don't use `atomic` variable here. - bool is_exit_; - bool is_stop_; - bool is_start_; - size_t task_limit_; - std::vector workers_; - std::queue> tasks_; - mutable std::mutex queue_lock_; - std::condition_variable queue_cond_, wait_cond_; - void check_status_(const std::string& func) - { - if(is_stop_) - throw std::runtime_error(func + " on stopped threadpool."); - } + public: + threadpool(); + threadpool(std::launch, std::size_t threads = std::thread::hardware_concurrency()); + threadpool(threadpool&&) = delete; + threadpool(const threadpool&) = delete; + threadpool& operator=(const threadpool&) = delete; + ~threadpool() noexcept; + template + auto add_task(F&&, Args&&...) -> std::future::type>; + size_t queue_size_limit(); + void set_queue_size_limit(size_t); + void start(); + void wait(); + void pause(); + void stop(); + bool valid() const; + + private: + std::launch policy_; + // we don't use `atomic` variable here. + bool is_exit_; + bool is_stop_; + bool is_start_; + size_t task_limit_; + std::vector workers_; + std::queue> tasks_; + mutable std::mutex queue_lock_; + std::condition_variable queue_cond_, wait_cond_; + void check_status_(const std::string& func) + { + if(is_stop_) + throw std::runtime_error(func + " on stopped threadpool."); + } }; threadpool::threadpool(std::launch p, size_t threads) - : policy_(p), is_exit_(false), is_stop_(false), - is_start_(policy_ == std::launch::async ? true : false), task_limit_(1000) + : policy_(p), is_exit_(false), is_stop_(false), is_start_(policy_ == std::launch::async ? true : false), + task_limit_(1000) { - for(;threads > 0; --threads) + for(; threads > 0; --threads) { - workers_.emplace_back([&] + workers_.emplace_back([&] { + for(;;) { - for(;;) + std::unique_lock l(queue_lock_); + queue_cond_.wait(l, [this] { + if(!is_start_) + return false; + return is_stop_ || is_exit_ || !tasks_.empty(); + }); + // caller request to stop all task. + if(is_stop_) + return; + // normal exit, when pool is going to destroyed. + if(tasks_.empty()) + { + if(is_exit_) + break; + } + else { - std::unique_lock l(queue_lock_); - queue_cond_.wait(l, [this] - { - if(!is_start_) - return false; - return is_stop_ || is_exit_ || !tasks_.empty(); - } - ); - // caller request to stop all task. - if(is_stop_) - return; - // normal exit, when pool is going to destroyed. + auto task(std::move(tasks_.front())); + tasks_.pop(); if(tasks_.empty()) + wait_cond_.notify_one(); + l.unlock(); + try { - if(is_exit_) - break; + task(); } - else + catch(std::exception& e) { - auto task(std::move(tasks_.front())); - tasks_.pop(); - if(tasks_.empty()) - wait_cond_.notify_one(); - l.unlock(); - try - { - task(); - } - catch(std::exception& e) - { - // abort program when encounter an exception. - assert(false); - } + // abort program when encounter an exception. + assert(false); } } } - ); + }); } } threadpool::threadpool() : threadpool(std::launch::async) {} @@ -135,18 +130,16 @@ namespace nm } } template - auto threadpool::add_task(F&& f, Args&&... args) - -> std::future::type> + auto threadpool::add_task(F&& f, Args&&... args) -> std::future::type> { using R = typename std::result_of::type; - auto task = std::make_shared>( - std::bind(std::forward(f), std::forward(args)...)); + auto task = std::make_shared>(std::bind(std::forward(f), std::forward(args)...)); auto res(task->get_future()); std::unique_lock l(queue_lock_); if(tasks_.size() >= task_limit_) throw std::runtime_error("task queue is full."); check_status_(__func__); - tasks_.emplace([task]{ (*task)(); }); + tasks_.emplace([task] { (*task)(); }); if(policy_ == std::launch::async) queue_cond_.notify_one(); return res; // NRVO diff --git a/typelist.cpp b/typelist.cpp index f1e2d67..32b894d 100644 --- a/typelist.cpp +++ b/typelist.cpp @@ -11,170 +11,223 @@ namespace nm { namespace meta { - template struct TypeList {}; - template<> struct TypeList<> {}; + template + struct TypeList + { + }; + template<> + struct TypeList<> + { + }; - template struct Len; - template struct Len> + template + struct Len; + template + struct Len> { constexpr static int value = sizeof...(Args); }; - template struct Append; - template struct Append, TypeList> + template + struct Append; + template + struct Append, TypeList> { using type = TypeList; }; - template struct Append> + template + struct Append> { using type = TypeList; }; - template struct Append, T> + template + struct Append, T> { using type = TypeList; }; - template struct Remove; - template struct Remove> + template + struct Remove; + template + struct Remove> { using type = TypeList<>; }; - template struct Remove> + template + struct Remove> { using type = TypeList; }; - template struct Remove> + template + struct Remove> { using type = typename Append>::type>::type; }; - template struct RemoveAll; - template struct RemoveAll> + template + struct RemoveAll; + template + struct RemoveAll> { using type = TypeList<>; }; - template struct RemoveAll> + template + struct RemoveAll> { using type = typename RemoveAll>::type; }; - template struct RemoveAll> + template + struct RemoveAll> { using type = typename Append>::type>::type; }; - template struct TypeAt; - template struct TypeAt<0, TypeList> + template + struct TypeAt; + template + struct TypeAt<0, TypeList> { using type = T; }; - template struct TypeAt> + template + struct TypeAt> { using type = typename TypeAt>::type; }; - template struct IsContain; - template struct IsContain> + template + struct IsContain; + template + struct IsContain> { constexpr static bool value = false; }; - template struct IsContain> + template + struct IsContain> { constexpr static bool value = true; }; - template struct IsContain> + template + struct IsContain> { constexpr static bool value = IsContain>::value; }; - template struct IndexOf; - template struct IndexOf> + template + struct IndexOf; + template + struct IndexOf> { constexpr static int value = -1; }; - template struct IndexOf> + template + struct IndexOf> { constexpr static int value = 0; }; - template struct IndexOf> + template + struct IndexOf> { - private: - constexpr static bool have_t = IsContain>::value; - public: - constexpr static int value = have_t - ? 1 + IndexOf>::value - : -1; + private: + constexpr static bool have_t = IsContain>::value; + + public: + constexpr static int value = have_t ? 1 + IndexOf>::value : -1; }; - template struct Replace; - template struct Replace> + template + struct Replace; + template + struct Replace> { using type = TypeList<>; }; - template struct Replace> + template + struct Replace> { using type = TypeList; }; - template struct Replace> + template + struct Replace> { using type = typename Append>::type>::type; }; - template struct ReplaceAll; - template struct ReplaceAll> + template + struct ReplaceAll; + template + struct ReplaceAll> { using type = TypeList<>; }; - template struct ReplaceAll> + template + struct ReplaceAll> { using type = typename ReplaceAll>::type; }; - template struct ReplaceAll> + template + struct ReplaceAll> { using type = typename Append>::type>::type; }; - template struct Reverse; - template<> struct Reverse> + template + struct Reverse; + template<> + struct Reverse> { using type = TypeList<>; }; - template struct Reverse> + template + struct Reverse> { using type = typename Append>::type, T>::type; }; - template struct PopFront; - template struct PopFront> + template + struct PopFront; + template + struct PopFront> { using type = TypeList<>; }; - template struct PopFront> + template + struct PopFront> { using type = TypeList; }; - template struct PopBack; - template struct PopBack> + template + struct PopBack; + template + struct PopBack> { using type = TypeList<>; }; - template struct PopBack> + template + struct PopBack> { using type = typename Reverse>::type>::type>::type; }; - template struct Unique; - template<> struct Unique> + template + struct Unique; + template<> + struct Unique> { using type = TypeList<>; }; - template struct Unique> + template + struct Unique> { - using type = typename Append, typename Remove>::type>::type>::type; + using type = + typename Append, typename Remove>::type>::type>::type; }; - template struct for_each_helper; - template struct for_each_helper> + template + struct for_each_helper; + template + struct for_each_helper> { template constexpr static void call(F f) @@ -183,56 +236,78 @@ namespace nm for_each_helper>::call(f); } }; - template<> struct for_each_helper<0, TypeList<>> + template<> + struct for_each_helper<0, TypeList<>> { - template constexpr static void call(F) {} + template + constexpr static void call(F) + { + } }; - template struct for_each_helper<0, TypeList> + template + struct for_each_helper<0, TypeList> { - template constexpr static void call(F) {} + template + constexpr static void call(F) + { + } }; - template struct ForEach1; - template struct ForEach1> - { - private: - constexpr static size_t size = sizeof...(Args); - public: - template - constexpr static void call(F f) - { - for_each_helper>::type>::call(f); - } + template + struct ForEach1; + template + struct ForEach1> + { + private: + constexpr static size_t size = sizeof...(Args); + + public: + template + constexpr static void call(F f) + { + for_each_helper>::type>::call(f); + } }; - template struct ForEach2; - template struct ForEach2> + template + struct ForEach2; + template + struct ForEach2> { - template constexpr static void call(F f) + template + constexpr static void call(F f) { f(T{}); ForEach2>::call(f); } }; - template<> struct ForEach2> + template<> + struct ForEach2> { - template constexpr static void call(F) {} + template + constexpr static void call(F) + { + } }; - template struct overloaded : Args... + template + struct overloaded : Args... { using Args::operator()...; }; - template overloaded(Args...) -> overloaded; + template + overloaded(Args...) -> overloaded; } } -template struct is_same +template +struct is_same { constexpr static bool value = false; }; -template struct is_same +template +struct is_same { constexpr static bool value = true; }; @@ -284,12 +359,8 @@ int main() using l6 = TypeList; using std::cout; - auto vi = overloaded{ - [](int) { cout << "int\n"; }, - [](double) { cout << "double\n"; }, - [](long) { cout << "long\n"; }, - [](auto) { cout << "other\n"; } - }; + auto vi = overloaded{[](int) { cout << "int\n"; }, [](double) { cout << "double\n"; }, [](long) { cout << "long\n"; }, + [](auto) { cout << "other\n"; }}; ForEach1::call(vi); cout << '\n'; ForEach2::call(vi); diff --git a/variant/test.cpp b/variant/test.cpp index 4fb8698..03a551e 100644 --- a/variant/test.cpp +++ b/variant/test.cpp @@ -14,14 +14,9 @@ using namespace nm; struct foo { foo() = default; - foo(int x, int y) - : x_(x), y_(y) {} - ~foo() - { printf("--->>> %s\n", __func__); }; - void show() - { - printf("x: %d\ty: %d\n", x_, y_); - } + foo(int x, int y) : x_(x), y_(y) {} + ~foo() { printf("--->>> %s\n", __func__); }; + void show() { printf("x: %d\ty: %d\n", x_, y_); } int x_; int y_; }; @@ -39,40 +34,65 @@ struct baz : public bar void foo() override { printf("baz\n"); } }; -variant make_variant() -{ - return variant{std::string{"test move"}}; -} +variant make_variant() { return variant{std::string{"test move"}}; } struct Operation { - size_t operator() (size_t x) { cout << "size_t = "; return x; } - size_t operator() (const string& x) { cout << "string.length = "; return x.size(); } - double operator() (double x) { cout << "double = "; return x; } + size_t operator()(size_t x) + { + cout << "size_t = "; + return x; + } + size_t operator()(const string& x) + { + cout << "string.length = "; + return x.size(); + } + double operator()(double x) + { + cout << "double = "; + return x; + } }; struct Operation2 : public variant_visitor { - string operator() (size_t x) { cout << "size_t = "; return to_string(x); } - string operator() (const string& x) { cout << "string = "; return x; } - string operator() (double x) { cout << "double = "; return to_string(x); } + string operator()(size_t x) + { + cout << "size_t = "; + return to_string(x); + } + string operator()(const string& x) + { + cout << "string = "; + return x; + } + string operator()(double x) + { + cout << "double = "; + return to_string(x); + } }; int main() { variant va{bar()}; va.get().foo(); // print 'bar' - va.set(233); cout << va.get() << '\n'; - va.set(std::string("+1s")); cout << va.get() << '\n'; + va.set(233); + cout << va.get() << '\n'; + va.set(std::string("+1s")); + cout << va.get() << '\n'; va.set(foo()); - va.emplace(1, 2); va.get().show(); // test emplace + va.emplace(1, 2); + va.get().show(); // test emplace va.set(2.333); va.set("233333333333333333333333"); variant v(va); // test copy ctor cout << v.get() << '\n'; variant vv(make_variant()); // test move ctor cout << vv.get() << '\n'; - v = std::move(va); cout << v.get() << '\n'; + v = std::move(va); + cout << v.get() << '\n'; variant b{static_cast(new baz{})}; bar* ba = b.get(); ba->bar::foo(); @@ -85,11 +105,11 @@ int main() std::string s("-1s"); vx = 233; vx = s; - cout << s.size() << '\n'; cout << vx.get() << '\n'; + cout << s.size() << '\n'; + cout << vx.get() << '\n'; // test call variant vc = 2.33; - vc.call([](int x) { printf("int = %d\n", x); }, - [](float x) { printf("float = %f\n", x); }, + vc.call([](int x) { printf("int = %d\n", x); }, [](float x) { printf("float = %f\n", x); }, [](std::string x) { printf("string = %s\n", x.c_str()); }, [](const char* x) { printf("const char* = %s\n", x); }); vc = "maybe string"; @@ -116,11 +136,8 @@ int main() app = 2.333; cout << app.apply(Operation2{}) << '\n'; cout << variant{"test operator<<\n"}; - auto v = nm::make_overload( - [](size_t x) { cout << x; }, - [](string& x) { cout << x; }, - [](double x) { cout << x; } - ); - app.apply(v); cout << '\n'; + auto v = nm::make_overload([](size_t x) { cout << x; }, [](string& x) { cout << x; }, [](double x) { cout << x; }); + app.apply(v); + cout << '\n'; } } diff --git a/variant/variant.h b/variant/variant.h index 799b2e7..afe41ab 100644 --- a/variant/variant.h +++ b/variant/variant.h @@ -16,138 +16,155 @@ namespace nm { namespace meta { - template struct max_size_of; - template struct max_size_of<_1> + template + struct max_size_of; + template + struct max_size_of<_1> { constexpr static size_t value = _1; }; template struct max_size_of<_1, _2, Rest...> { - constexpr static size_t value = _1 > _2 ? max_size_of<_1, Rest...>::value - : max_size_of<_2, Rest...>::value; + constexpr static size_t value = _1 > _2 ? max_size_of<_1, Rest...>::value : max_size_of<_2, Rest...>::value; }; - template struct helper_and; - template struct helper_and<_1> + template + struct helper_and; + template + struct helper_and<_1> { constexpr static bool value = _1::value; }; template struct helper_and<_1, _2, R...> { - constexpr static bool value = _1::value ? - helper_and<_2, R...>::value : _1::value; + constexpr static bool value = _1::value ? helper_and<_2, R...>::value : _1::value; }; - template struct helper_or; - template struct helper_or<_1> + template + struct helper_or; + template + struct helper_or<_1> { constexpr static bool value = _1::value; }; template struct helper_or<_1, _2, R...> { - constexpr static bool value = _1::value ? - _1::value : helper_or<_2, R...>::value; + constexpr static bool value = _1::value ? _1::value : helper_or<_2, R...>::value; }; - template struct helper_not + template + struct helper_not { constexpr static bool value = !T::value; }; - template struct is_valid_variant_types; - template<> struct is_valid_variant_types<> + template + struct is_valid_variant_types; + template<> + struct is_valid_variant_types<> { constexpr static bool value = false; }; - template struct is_valid_variant_types + template + struct is_valid_variant_types { - constexpr static bool value = helper_and< - helper_not>, - helper_not>, - helper_not>, - helper_not>>::value; + constexpr static bool value = helper_and>, helper_not>, + helper_not>, helper_not>>::value; }; - template struct is_valid_variant_types + template + struct is_valid_variant_types { - constexpr static bool value = helper_and< - is_valid_variant_types, - is_valid_variant_types>::value; + constexpr static bool value = helper_and, is_valid_variant_types>::value; }; template struct is_valid_variant_types { - constexpr static bool value = helper_and, - is_valid_variant_types>::value; + constexpr static bool value = helper_and, is_valid_variant_types>::value; }; - template struct is_in; - template struct is_in + template + struct is_in; + template + struct is_in { constexpr static bool value = std::is_same::value; }; template struct is_in { - private: - constexpr static bool tmp = is_in::value; - public: - constexpr static bool value = tmp ? tmp : is_in::value; + private: + constexpr static bool tmp = is_in::value; + + public: + constexpr static bool value = tmp ? tmp : is_in::value; }; - template struct cond + template + struct cond { using type = True; }; - template struct cond + template + struct cond { using type = False; }; - template struct is_type_unique; - template struct is_type_unique + template + struct is_type_unique; + template + struct is_type_unique { constexpr static bool value = true; }; - template struct is_type_unique + template + struct is_type_unique { constexpr static bool tmp = !meta::is_in::value; constexpr static bool value = tmp ? is_type_unique::value : tmp; }; - template struct ctor_type_helper; - template struct ctor_type_helper + template + struct ctor_type_helper; + template + struct ctor_type_helper { using type = typename cond::value, U, T>::type; }; - template struct ctor_type_helper + template + struct ctor_type_helper { - using type = typename ctor_type_helper< - typename ctor_type_helper::type, Rest...>::type; + using type = typename ctor_type_helper::type, Rest...>::type; }; - template struct ctor_type + template + struct ctor_type { - private: - using Raw = typename std::remove_cv< - typename std::remove_reference::type>::type; - public: - using type = typename cond::value, Raw, - typename ctor_type_helper::type>::type; + private: + using Raw = typename std::remove_cv::type>::type; + + public: + using type = + typename cond::value, Raw, typename ctor_type_helper::type>::type; }; - template struct is_construct_from + template + struct is_construct_from { - private: - using Type = typename ctor_type::type; - public: - constexpr static bool value = is_in::value; + private: + using Type = typename ctor_type::type; + + public: + constexpr static bool value = is_in::value; }; - template struct not_contain_const; - template struct not_contain_const + template + struct not_contain_const; + template + struct not_contain_const { using Type = typename std::remove_reference::type; constexpr static bool value = helper_not>::value; @@ -159,145 +176,180 @@ namespace nm constexpr static bool value = tmp ? not_contain_const::value : tmp; }; - template struct is_acceptable + template + struct is_acceptable { - private: - using Raw = typename std::remove_reference::type; - static std::false_type test(...); - static std::true_type test(Raw); - public: - constexpr static bool value = helper_and>, - decltype(test(std::forward(std::declval())))>::value; + private: + using Raw = typename std::remove_reference::type; + static std::false_type test(...); + static std::true_type test(Raw); + + public: + constexpr static bool value = + helper_and>, decltype(test(std::forward(std::declval())))>::value; }; - template struct acceptable_type_helper; - template struct acceptable_type_helper + template + struct acceptable_type_helper; + template + struct acceptable_type_helper { using type = typename cond::value, U, T>::type; }; - template struct acceptable_type_helper + template + struct acceptable_type_helper { - using type = typename acceptable_type_helper< - typename acceptable_type_helper::type, Rest...>::type; + using type = typename acceptable_type_helper::type, Rest...>::type; }; - template struct acceptable_type + template + struct acceptable_type { - private: - using Raw = typename std::remove_cv< - typename std::remove_reference::type>::type; - public: - using type = typename cond::value, Raw, - typename acceptable_type_helper::type>::type; + private: + using Raw = typename std::remove_cv::type>::type; + + public: + using type = + typename cond::value, Raw, typename acceptable_type_helper::type>::type; }; - template struct is_acceptable_from; - template struct is_acceptable_from + template + struct is_acceptable_from; + template + struct is_acceptable_from { - constexpr static bool value = std::is_same< - typename acceptable_type::type, U>::value; + constexpr static bool value = std::is_same::type, U>::value; }; - template struct is_acceptable_from + template + struct is_acceptable_from { - private: - using type = typename acceptable_type::type; - public: - constexpr static bool value = helper_and, - not_contain_const>::value; + private: + using type = typename acceptable_type::type; + + public: + constexpr static bool value = helper_and, not_contain_const>::value; }; - template struct index_of_type_helper; - template struct index_of_type_helper + template + struct index_of_type_helper; + template + struct index_of_type_helper { constexpr static int value = 0; }; template struct index_of_type_helper { - private: - constexpr static bool ok = std::is_same::value; - public: - constexpr static int value = ok ? - 0 : - 1 + index_of_type_helper::value; + private: + constexpr static bool ok = std::is_same::value; + + public: + constexpr static int value = ok ? 0 : 1 + index_of_type_helper::value; }; - template struct index_of_type + template + struct index_of_type { - private: - constexpr static int tmp = index_of_type_helper::value; - public: - constexpr static int value = tmp >= sizeof...(Rest) ? -1 : tmp; + private: + constexpr static int tmp = index_of_type_helper::value; + + public: + constexpr static int value = tmp >= sizeof...(Rest) ? -1 : tmp; }; template struct is_type_match { - private: - template struct extract; + private: + template + struct extract; - template - struct extract - { - using ires = R; - using iarg = A; - }; + template + struct extract + { + using ires = R; + using iarg = A; + }; - template - struct extract : extract {}; + template + struct extract : extract + { + }; - template - struct extract> : extract {}; + template + struct extract> : extract + { + }; - template - struct extract : extract {}; + template + struct extract : extract + { + }; + + template + struct extract : extract + { + }; - template - struct extract : extract {}; + template + struct extract : extract + { + }; - template - struct extract : extract {}; + template + struct extract : extract + { + }; - template - struct extract : extract {}; + template + struct extract : extract + { + }; - template - struct extract : extract {}; + template + struct extract : extract + { + }; - template - struct extract : extract {}; + template + struct extract : extract + { + }; - template - struct extract : extract {}; - public: - using arg = typename std::remove_cv< - typename std::remove_reference::type>::type; - using iarg = typename std::remove_cv< - typename std::remove_reference::iarg>::type>::type; - constexpr static bool arg_same = std::is_same::value; + public: + using arg = typename std::remove_cv::type>::type; + using iarg = typename std::remove_cv::iarg>::type>::type; + constexpr static bool arg_same = std::is_same::value; }; template struct variant_call_wrapper { - template static void invoke(Type& arg, F&& f) + template + static void invoke(Type& arg, F&& f) { f(arg); } }; - template<> struct variant_call_wrapper + template<> + struct variant_call_wrapper { - template static void invoke(Type&, F&&) {} + template + static void invoke(Type&, F&&) + { + } }; struct variant_call { - template static void invoke(Type&) {} + template + static void invoke(Type&) + { + } template static void invoke(Type& arg, F&& f) { - variant_call_wrapper::arg_same>::invoke(arg, f); + variant_call_wrapper::arg_same>::invoke(arg, f); } template static void invoke(Type& arg, Fn&& f, Fns&&... fs) @@ -308,19 +360,27 @@ namespace nm }; // return void() in void function: n4659 [expr.type.conv] - template struct variant_helper; - template<> struct variant_helper<> + template + struct variant_helper; + template<> + struct variant_helper<> { static void clear(int, void*) {} static void copy(int, void*, const void*, size_t) {} static void move(int, void*, void*, size_t) {} template - static void call(int, void*, Fn&&...) {} + static void call(int, void*, Fn&&...) + { + } template - static Res apply(int, void*, Obj&) { return Res(); } + static Res apply(int, void*, Obj&) + { + return Res(); + } static void dump(int, const void*, std::ostream&) {} }; - template struct variant_helper + template + struct variant_helper { static void clear(int index, void* data) { @@ -348,8 +408,7 @@ namespace nm } else if(index == 0) { - static_assert(std::is_copy_constructible::value, - "type is not copy constructible"); + static_assert(std::is_copy_constructible::value, "type is not copy constructible"); new(lhs) T(*static_cast(rhs)); } } @@ -363,8 +422,7 @@ namespace nm } else if(index == 0) { - static_assert(std::is_move_constructible::value, - "type is not move constructible"); + static_assert(std::is_move_constructible::value, "type is not move constructible"); new(lhs) T(std::move(*static_cast(rhs))); } } @@ -379,8 +437,7 @@ namespace nm } else if(index == 0) { - variant_call::invoke(*static_cast(data), - std::forward(f)...); + variant_call::invoke(*static_cast(data), std::forward(f)...); } } @@ -418,284 +475,265 @@ namespace nm { using Arg::operator(); using overload_helper::operator(); - overload_helper(Arg arg, Args... args) - : Arg(arg), overload_helper(args...) {} + overload_helper(Arg arg, Args... args) : Arg(arg), overload_helper(args...) {} }; template struct overload_helper : Arg { - overload_helper(Arg arg) : Arg(arg){} + overload_helper(Arg arg) : Arg(arg) {} }; } template constexpr auto make_overload(Args... args) #if __cplusplus < 201402L - -> decltype(meta::overload_helper{args...}) + -> decltype(meta::overload_helper{args...}) #endif { - return meta::overload_helper{ args... }; + return meta::overload_helper{args...}; } } namespace nm { - template struct variant_visitor { using type = T; }; + template + struct variant_visitor + { + using type = T; + }; template class variant { - static_assert(meta::is_valid_variant_types::value, - "invalid variant type(s)"); - static_assert(meta::is_type_unique::value, - "duplicate type is not allowed"); - using helper = meta::variant_helper; - template using and_ = meta::helper_and; - template using or_ = meta::helper_or; - template using not_ = meta::helper_not; - public: - ~variant() - { - clear(); - } + static_assert(meta::is_valid_variant_types::value, "invalid variant type(s)"); + static_assert(meta::is_type_unique::value, "duplicate type is not allowed"); + using helper = meta::variant_helper; + template + using and_ = meta::helper_and; + template + using or_ = meta::helper_or; + template + using not_ = meta::helper_not; - constexpr variant() noexcept : type_index_(-1) {} + public: + ~variant() { clear(); } - template>, - meta::is_construct_from>::value>::type* = nullptr> - variant(const T& rhs) - : variant() - { - assign(rhs); - } + constexpr variant() noexcept : type_index_(-1) {} - template, - not_>, - not_>, - meta::is_construct_from>::value>::type* = nullptr> - variant(T&& rhs) - : variant() - { - using Type = typename meta::ctor_type::type; - data_.template construct(std::forward(rhs)); - update_index(); - } + template>, + meta::is_construct_from>::value>::type* = nullptr> + variant(const T& rhs) : variant() + { + assign(rhs); + } - variant(const variant& rhs) - : variant() - { - copy_construct(rhs); - } + template, not_>, not_>, + meta::is_construct_from>::value>::type* = nullptr> + variant(T&& rhs) : variant() + { + using Type = typename meta::ctor_type::type; + data_.template construct(std::forward(rhs)); + update_index(); + } - variant(variant&& rhs) noexcept - : variant() - { - move_construct(rhs); - } + variant(const variant& rhs) : variant() { copy_construct(rhs); } - template::value - >::type* = nullptr> variant& operator= (const T& rhs) - { - using Type = typename meta::acceptable_type::type; - constexpr int tmp = meta::index_of_type::value; - if(type_index_ != tmp) - { - clear(); - data_.template construct(rhs); - update_index(); - } - else - { - auto& lhs = get(); - lhs = rhs; - } - return *this; - } + variant(variant&& rhs) noexcept : variant() { move_construct(rhs); } - template::value - >::type* = nullptr> variant& operator= (T&& rhs) + template::value>::type* = nullptr> + variant& operator=(const T& rhs) + { + using Type = typename meta::acceptable_type::type; + constexpr int tmp = meta::index_of_type::value; + if(type_index_ != tmp) { - using Real = decltype(rhs); - using Type = typename meta::acceptable_type::type; - constexpr int tmp = meta::index_of_type::value; - if(type_index_ != tmp) - { - clear(); - data_.template construct(std::forward(rhs)); - update_index(); - } - else - { - auto& lhs = get(); - lhs = std::forward(rhs); - } - return *this; + clear(); + data_.template construct(rhs); + update_index(); } - - variant& operator= (const variant& rhs) + else { - if(this != &rhs) - { - copy_construct(rhs); - } - return *this; + auto& lhs = get(); + lhs = rhs; } + return *this; + } - variant& operator= (variant&& rhs) + template::value>::type* = nullptr> + variant& operator=(T&& rhs) + { + using Real = decltype(rhs); + using Type = typename meta::acceptable_type::type; + constexpr int tmp = meta::index_of_type::value; + if(type_index_ != tmp) { - if(this != &rhs) - { - move_construct(rhs); - } - return *this; + clear(); + data_.template construct(std::forward(rhs)); + update_index(); } - - bool operator== (const variant& rhs) + else { - return which() == rhs.which(); + auto& lhs = get(); + lhs = std::forward(rhs); } + return *this; + } - bool operator!= (const variant& rhs) + variant& operator=(const variant& rhs) + { + if(this != &rhs) { - return !(*this == rhs); + copy_construct(rhs); } + return *this; + } - template::value>::type* = nullptr> - void set(const T& rhs) + variant& operator=(variant&& rhs) + { + if(this != &rhs) { - using Type = typename meta::ctor_type::type; - clear(); - data_.template construct(rhs); - update_index(); + move_construct(rhs); } + return *this; + } - template::value>::type* = nullptr> - void set(T&& rhs) - { - using Type = typename meta::ctor_type::type; - clear(); - data_.template construct(std::forward(rhs)); - update_index(); - } + bool operator==(const variant& rhs) { return which() == rhs.which(); } - template - void emplace(Args&&... args) - { - check(); - clear(); - new(data_.raw()) T(std::forward(args)...); - update_index(); - } + bool operator!=(const variant& rhs) { return !(*this == rhs); } - template T& get(typename std::enable_if< - meta::is_in::value>::type* = nullptr) - { - if(type_index_ < 0) - throw std::runtime_error("bad get on an empty variant"); - constexpr int tmp = meta::index_of_type::value; - if(type_index_ != tmp) - throw std::runtime_error("get type mismatch set type"); - return *static_cast(data_.raw()); - } + template::value>::type* = nullptr> + void set(const T& rhs) + { + using Type = typename meta::ctor_type::type; + clear(); + data_.template construct(rhs); + update_index(); + } - template void call(F&& func, Fs&&...funcs) - { - helper::call(type_index_, data_.raw(), - std::forward(func), std::forward(funcs)...); - } + template::value>::type* = nullptr> + void set(T&& rhs) + { + using Type = typename meta::ctor_type::type; + clear(); + data_.template construct(std::forward(rhs)); + update_index(); + } - template typename Obj::type apply(Obj&& obj) - { - return helper::template apply(type_index_, - data_.raw(), obj); - } + template + void emplace(Args&&... args) + { + check(); + clear(); + new(data_.raw()) T(std::forward(args)...); + update_index(); + } - template Res apply(Obj&& obj) - { - return helper::template apply(type_index_, data_.raw(), obj); - } + template + T& get(typename std::enable_if::value>::type* = nullptr) + { + if(type_index_ < 0) + throw std::runtime_error("bad get on an empty variant"); + constexpr int tmp = meta::index_of_type::value; + if(type_index_ != tmp) + throw std::runtime_error("get type mismatch set type"); + return *static_cast(data_.raw()); + } - // if variant is invalid, do nothing. - friend std::ostream& operator<< (std::ostream& os, const variant& rhs) - { - helper::dump(rhs.which(), &rhs.data_.data_, os); - return os; - } + template + void call(F&& func, Fs&&... funcs) + { + helper::call(type_index_, data_.raw(), std::forward(func), std::forward(funcs)...); + } - void clear() - { - helper::clear(type_index_, data_.raw()); - type_index_ = -1; - } + template + typename Obj::type apply(Obj&& obj) + { + return helper::template apply(type_index_, data_.raw(), obj); + } - constexpr int which() const noexcept - { - return type_index_; - } + template + Res apply(Obj&& obj) + { + return helper::template apply(type_index_, data_.raw(), obj); + } - private: - int type_index_; - constexpr static size_t data_size = meta::max_size_of::value; - constexpr static size_t align_size = sizeof(long); - using data_type = typename std::aligned_storage::type; - class Data - { - public: - template void construct(const T& rhs) - { - new(raw()) Type(rhs); - } - template void construct(T&& rhs) - { - new(raw()) Type(std::forward(rhs)); - } - void* raw() { return static_cast(&data_); } - data_type data_; - }; - Data data_; + // if variant is invalid, do nothing. + friend std::ostream& operator<<(std::ostream& os, const variant& rhs) + { + helper::dump(rhs.which(), &rhs.data_.data_, os); + return os; + } - template void check() - { - static_assert(meta::is_in::value, "invalid type"); - } + void clear() + { + helper::clear(type_index_, data_.raw()); + type_index_ = -1; + } - template void update_index() - { - type_index_ = meta::index_of_type::value; - } + constexpr int which() const noexcept { return type_index_; } - template void assign(const T& rhs) + private: + int type_index_; + constexpr static size_t data_size = meta::max_size_of::value; + constexpr static size_t align_size = sizeof(long); + using data_type = typename std::aligned_storage::type; + class Data + { + public: + template + void construct(const T& rhs) { - using Type = typename meta::ctor_type::type; - data_.template construct(rhs); - update_index(); + new(raw()) Type(rhs); } - - void copy_construct(const variant& rhs) + template + void construct(T&& rhs) { - if(rhs.which() < 0) - return; - clear(); - helper::copy(rhs.type_index_, data_.raw(), &rhs.data_.data_, data_size); - type_index_ = rhs.type_index_; + new(raw()) Type(std::forward(rhs)); } + void* raw() { return static_cast(&data_); } + data_type data_; + }; + Data data_; - void move_construct(variant& rhs) - { - if(rhs.which() < 0) - return; - clear(); - helper::move(rhs.type_index_, data_.raw(), &rhs.data_.data_, data_size); - type_index_ = rhs.type_index_; - } + template + void check() + { + static_assert(meta::is_in::value, "invalid type"); + } + + template + void update_index() + { + type_index_ = meta::index_of_type::value; + } + + template + void assign(const T& rhs) + { + using Type = typename meta::ctor_type::type; + data_.template construct(rhs); + update_index(); + } + + void copy_construct(const variant& rhs) + { + if(rhs.which() < 0) + return; + clear(); + helper::copy(rhs.type_index_, data_.raw(), &rhs.data_.data_, data_size); + type_index_ = rhs.type_index_; + } + + void move_construct(variant& rhs) + { + if(rhs.which() < 0) + return; + clear(); + helper::move(rhs.type_index_, data_.raw(), &rhs.data_.data_, data_size); + type_index_ = rhs.type_index_; + } }; } diff --git a/variant/variantlist.cpp b/variant/variantlist.cpp index 3d75b34..0b4d57b 100644 --- a/variant/variantlist.cpp +++ b/variant/variantlist.cpp @@ -13,110 +13,91 @@ namespace nm template class variant_list { - private: - struct Node - { - variant data; - Node* next; - template - Node(U&& u, Node* nxt) - : data(std::forward(u)), next(nxt) - {} - }; - public: - class iterator + private: + struct Node + { + variant data; + Node* next; + template + Node(U&& u, Node* nxt) : data(std::forward(u)), next(nxt) { - public: - iterator(Node* n) - : data_(n) - {} - - iterator(const iterator& rhs) - { - data_ = rhs.data_; - } - - iterator& operator= (const iterator& rhs) - { - if(this != &rhs) - { - data_ = rhs.data_; - } - return *this; - } - - iterator& operator++ () - { - data_ = data_->next; - return *this; - } - - bool operator== (const iterator& rhs) - { - return data_ == rhs.data_; - } - - bool operator!= (const iterator& rhs) - { - return !(*this == rhs); - } - - variant* operator-> () - { - return &data_->data; - } - - variant& operator* () - { - return data_->data; - } - private: - Node* data_; - }; + } + }; + + public: + class iterator + { public: - variant_list() : root_(nullptr) {} - ~variant_list() { this->clear(); } + iterator(Node* n) : data_(n) {} + + iterator(const iterator& rhs) { data_ = rhs.data_; } - template void push(U&& u) + iterator& operator=(const iterator& rhs) { - if(root_ == nullptr) + if(this != &rhs) { - root_ = new Node(std::forward(u), nullptr); - tail_ = root_; - } - else - { - auto tmp = new Node(std::forward(u), nullptr); - tail_->next = tmp; - tail_ = tmp; + data_ = rhs.data_; } + return *this; } - iterator begin() + iterator& operator++() { - return iterator(root_); + data_ = data_->next; + return *this; } - iterator end() + bool operator==(const iterator& rhs) { return data_ == rhs.data_; } + + bool operator!=(const iterator& rhs) { return !(*this == rhs); } + + variant* operator->() { return &data_->data; } + + variant& operator*() { return data_->data; } + + private: + Node* data_; + }; + + public: + variant_list() : root_(nullptr) {} + ~variant_list() { this->clear(); } + + template + void push(U&& u) + { + if(root_ == nullptr) + { + root_ = new Node(std::forward(u), nullptr); + tail_ = root_; + } + else { - return iterator(nullptr); + auto tmp = new Node(std::forward(u), nullptr); + tail_->next = tmp; + tail_ = tmp; } + } - void clear() + iterator begin() { return iterator(root_); } + + iterator end() { return iterator(nullptr); } + + void clear() + { + Node* tmp = nullptr; + while(root_) { - Node* tmp = nullptr; - while(root_) - { - tmp = root_->next; - delete root_; - root_ = tmp; - } - root_ = tail_ = nullptr; + tmp = root_->next; + delete root_; + root_ = tmp; } + root_ = tail_ = nullptr; + } - private: - Node* root_; - Node* tail_; + private: + Node* root_; + Node* tail_; }; }