├── .clang-format ├── .clang-tidy ├── .gitignore ├── CMakeLists.txt ├── README.md ├── callback_function ├── callback_bind_class_member_function.cpp └── callback_function_example.cpp ├── chrono_timer ├── CMakeLists.txt ├── chromo_example.cpp ├── clock.hpp ├── compare_clock.cpp └── timer.hpp ├── diy ├── binheap.hpp ├── diy.md ├── dsa │ ├── disjoint_set.hpp │ ├── merge_sort.hpp │ ├── segment_tree.hpp │ └── segment_tree_2.hpp └── unique_ptr.hpp ├── lambda └── lambda_example.cpp ├── pimpl ├── CMakeLists.txt ├── pimpl_main.cpp ├── x.cpp └── x.h ├── singleton ├── CMakeLists.txt ├── basic_singleton_example.cpp ├── basic_singleton_example_v2.cpp ├── inherit_singleton_example.cpp ├── inherit_singleton_example_v2.cpp ├── magic_static_singleton_example.cpp ├── ref_ret_function_template_ex.cpp └── ref_ret_singleton_example.cpp └── test ├── CMakeLists.txt ├── test_binheap.cpp ├── test_disjoint_set.cpp ├── test_segment_tree.cpp ├── test_sort.cpp └── test_unique_ptr.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | Language: Cpp 3 | AlwaysBreakAfterReturnType: None 4 | Standard: Auto 5 | ColumnLimit: 140 -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | --- 2 | Checks: '*, -bugprone-exception-escape, -cert-env33-c, -cert-err34-c, -clang-diagnostic-unknown-warning-option, -cppcoreguidelines-avoid-magic-numbers, -cppcoreguidelines-narrowing-conversions, -cppcoreguidelines-owning-memory, -cppcoreguidelines-pro-bounds-array-to-pointer-decay, -fuchsia-default-arguments, -fuchsia-overloaded-operator, -hicpp-no-array-decay, -hicpp-signed-bitwise, -llvm-header-guard, -misc-non-private-member-variables-in-classes, -modernize-pass-by-value, -readability-magic-numbers' 3 | WarningsAsErrors: '' 4 | HeaderFilterRegex: '' 5 | AnalyzeTemporaryDtors: false 6 | FormatStyle: none 7 | User: sasq 8 | CheckOptions: 9 | - key: bugprone-argument-comment.StrictMode 10 | value: '0' 11 | - key: bugprone-assert-side-effect.AssertMacros 12 | value: assert 13 | - key: bugprone-assert-side-effect.CheckFunctionCalls 14 | value: '0' 15 | - key: bugprone-dangling-handle.HandleClasses 16 | value: 'std::basic_string_view;std::experimental::basic_string_view' 17 | - key: bugprone-string-constructor.LargeLengthThreshold 18 | value: '8388608' 19 | - key: bugprone-string-constructor.WarnOnLargeLength 20 | value: '1' 21 | - key: cert-dcl59-cpp.HeaderFileExtensions 22 | value: ',h,hh,hpp,hxx' 23 | - key: cert-err09-cpp.CheckThrowTemporaries 24 | value: '1' 25 | - key: cert-err61-cpp.CheckThrowTemporaries 26 | value: '1' 27 | - key: cert-oop11-cpp.IncludeStyle 28 | value: llvm 29 | - key: cppcoreguidelines-no-malloc.Allocations 30 | value: '::malloc;::calloc' 31 | - key: cppcoreguidelines-no-malloc.Deallocations 32 | value: '::free' 33 | - key: cppcoreguidelines-no-malloc.Reallocations 34 | value: '::realloc' 35 | - key: cppcoreguidelines-pro-bounds-constant-array-index.GslHeader 36 | value: '' 37 | - key: cppcoreguidelines-pro-bounds-constant-array-index.IncludeStyle 38 | value: '0' 39 | - key: cppcoreguidelines-pro-type-member-init.IgnoreArrays 40 | value: '0' 41 | - key: google-build-namespaces.HeaderFileExtensions 42 | value: ',h,hh,hpp,hxx' 43 | - key: google-global-names-in-headers.HeaderFileExtensions 44 | value: ',h,hh,hpp,hxx' 45 | - key: google-readability-braces-around-statements.ShortStatementLines 46 | value: '1' 47 | - key: google-readability-function-size.BranchThreshold 48 | value: '4294967295' 49 | - key: google-readability-function-size.LineThreshold 50 | value: '4294967295' 51 | - key: google-readability-function-size.NestingThreshold 52 | value: '4294967295' 53 | - key: google-readability-function-size.ParameterThreshold 54 | value: '4294967295' 55 | - key: google-readability-function-size.StatementThreshold 56 | value: '800' 57 | - key: google-readability-namespace-comments.ShortNamespaceLines 58 | value: '10' 59 | - key: google-readability-namespace-comments.SpacesBeforeComments 60 | value: '2' 61 | - key: google-runtime-int.SignedTypePrefix 62 | value: int 63 | - key: google-runtime-int.TypeSuffix 64 | value: '' 65 | - key: google-runtime-int.UnsignedTypePrefix 66 | value: uint 67 | - key: google-runtime-references.WhiteListTypes 68 | value: '' 69 | - key: hicpp-braces-around-statements.ShortStatementLines 70 | value: '0' 71 | - key: hicpp-function-size.BranchThreshold 72 | value: '4294967295' 73 | - key: hicpp-function-size.LineThreshold 74 | value: '4294967295' 75 | - key: hicpp-function-size.NestingThreshold 76 | value: '4294967295' 77 | - key: hicpp-function-size.ParameterThreshold 78 | value: '4294967295' 79 | - key: hicpp-function-size.StatementThreshold 80 | value: '800' 81 | - key: hicpp-member-init.IgnoreArrays 82 | value: '0' 83 | - key: hicpp-move-const-arg.CheckTriviallyCopyableMove 84 | value: '1' 85 | - key: hicpp-named-parameter.IgnoreFailedSplit 86 | value: '0' 87 | - key: hicpp-no-malloc.Allocations 88 | value: '::malloc;::calloc' 89 | - key: hicpp-no-malloc.Deallocations 90 | value: '::free' 91 | - key: hicpp-no-malloc.Reallocations 92 | value: '::realloc' 93 | - key: hicpp-use-auto.RemoveStars 94 | value: '0' 95 | - key: hicpp-use-emplace.ContainersWithPushBack 96 | value: '::std::vector;::std::list;::std::deque' 97 | - key: hicpp-use-emplace.SmartPointers 98 | value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr' 99 | - key: hicpp-use-emplace.TupleMakeFunctions 100 | value: '::std::make_pair;::std::make_tuple' 101 | - key: hicpp-use-emplace.TupleTypes 102 | value: '::std::pair;::std::tuple' 103 | - key: hicpp-use-equals-default.IgnoreMacros 104 | value: '1' 105 | - key: hicpp-use-noexcept.ReplacementString 106 | value: '' 107 | - key: hicpp-use-noexcept.UseNoexceptFalse 108 | value: '1' 109 | - key: hicpp-use-nullptr.NullMacros 110 | value: '' 111 | - key: llvm-namespace-comment.ShortNamespaceLines 112 | value: '1' 113 | - key: llvm-namespace-comment.SpacesBeforeComments 114 | value: '1' 115 | - key: misc-definitions-in-headers.HeaderFileExtensions 116 | value: ',h,hh,hpp,hxx' 117 | - key: misc-definitions-in-headers.UseHeaderFileExtension 118 | value: '1' 119 | - key: misc-misplaced-widening-cast.CheckImplicitCasts 120 | value: '0' 121 | - key: misc-sizeof-expression.WarnOnSizeOfCompareToConstant 122 | value: '1' 123 | - key: misc-sizeof-expression.WarnOnSizeOfConstant 124 | value: '1' 125 | - key: misc-sizeof-expression.WarnOnSizeOfThis 126 | value: '1' 127 | - key: misc-suspicious-enum-usage.StrictMode 128 | value: '0' 129 | - key: misc-suspicious-missing-comma.MaxConcatenatedTokens 130 | value: '5' 131 | - key: misc-suspicious-missing-comma.RatioThreshold 132 | value: '0.200000' 133 | - key: misc-suspicious-missing-comma.SizeThreshold 134 | value: '5' 135 | - key: misc-suspicious-string-compare.StringCompareLikeFunctions 136 | value: '' 137 | - key: misc-suspicious-string-compare.WarnOnImplicitComparison 138 | value: '1' 139 | - key: misc-suspicious-string-compare.WarnOnLogicalNotComparison 140 | value: '0' 141 | - key: misc-throw-by-value-catch-by-reference.CheckThrowTemporaries 142 | value: '1' 143 | - key: modernize-loop-convert.MaxCopySize 144 | value: '16' 145 | - key: modernize-loop-convert.MinConfidence 146 | value: reasonable 147 | - key: modernize-loop-convert.NamingStyle 148 | value: CamelCase 149 | - key: modernize-make-shared.IgnoreMacros 150 | value: '1' 151 | - key: modernize-make-shared.IncludeStyle 152 | value: '0' 153 | - key: modernize-make-shared.MakeSmartPtrFunction 154 | value: 'std::make_shared' 155 | - key: modernize-make-shared.MakeSmartPtrFunctionHeader 156 | value: memory 157 | - key: modernize-make-unique.IgnoreMacros 158 | value: '1' 159 | - key: modernize-make-unique.IncludeStyle 160 | value: '0' 161 | - key: modernize-make-unique.MakeSmartPtrFunction 162 | value: 'std::make_unique' 163 | - key: modernize-make-unique.MakeSmartPtrFunctionHeader 164 | value: memory 165 | - key: modernize-pass-by-value.IncludeStyle 166 | value: llvm 167 | - key: modernize-raw-string-literal.ReplaceShorterLiterals 168 | value: '0' 169 | - key: modernize-replace-auto-ptr.IncludeStyle 170 | value: llvm 171 | - key: modernize-replace-random-shuffle.IncludeStyle 172 | value: llvm 173 | - key: modernize-use-auto.RemoveStars 174 | value: '0' 175 | - key: modernize-use-default-member-init.IgnoreMacros 176 | value: '1' 177 | - key: modernize-use-default-member-init.UseAssignment 178 | value: '0' 179 | - key: modernize-use-emplace.ContainersWithPushBack 180 | value: '::std::vector;::std::list;::std::deque' 181 | - key: modernize-use-emplace.SmartPointers 182 | value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr' 183 | - key: modernize-use-emplace.TupleMakeFunctions 184 | value: '::std::make_pair;::std::make_tuple' 185 | - key: modernize-use-emplace.TupleTypes 186 | value: '::std::pair;::std::tuple' 187 | - key: modernize-use-equals-default.IgnoreMacros 188 | value: '1' 189 | - key: modernize-use-noexcept.ReplacementString 190 | value: '' 191 | - key: modernize-use-noexcept.UseNoexceptFalse 192 | value: '1' 193 | - key: modernize-use-nullptr.NullMacros 194 | value: 'NULL' 195 | - key: modernize-use-transparent-functors.SafeMode 196 | value: '0' 197 | - key: modernize-use-using.IgnoreMacros 198 | value: '1' 199 | - key: objc-forbidden-subclassing.ForbiddenSuperClassNames 200 | value: 'ABNewPersonViewController;ABPeoplePickerNavigationController;ABPersonViewController;ABUnknownPersonViewController;NSHashTable;NSMapTable;NSPointerArray;NSPointerFunctions;NSTimer;UIActionSheet;UIAlertView;UIImagePickerController;UITextInputMode;UIWebView' 201 | - key: objc-property-declaration.Acronyms 202 | value: 'ASCII;PDF;XML;HTML;URL;RTF;HTTP;TIFF;JPG;PNG;GIF;LZW;ROM;RGB;CMYK;MIDI;FTP' 203 | - key: performance-faster-string-find.StringLikeClasses 204 | value: 'std::basic_string' 205 | - key: performance-for-range-copy.WarnOnAllAutoCopies 206 | value: '0' 207 | - key: performance-inefficient-string-concatenation.StrictMode 208 | value: '0' 209 | - key: performance-inefficient-vector-operation.VectorLikeClasses 210 | value: '::std::vector' 211 | - key: performance-move-const-arg.CheckTriviallyCopyableMove 212 | value: '1' 213 | - key: performance-move-constructor-init.IncludeStyle 214 | value: llvm 215 | - key: performance-type-promotion-in-math-fn.IncludeStyle 216 | value: llvm 217 | - key: performance-unnecessary-value-param.IncludeStyle 218 | value: llvm 219 | - key: readability-function-size.BranchThreshold 220 | value: '4294967295' 221 | - key: readability-function-size.LineThreshold 222 | value: '4294967295' 223 | - key: readability-function-size.NestingThreshold 224 | value: '4294967295' 225 | - key: readability-function-size.ParameterThreshold 226 | value: '4294967295' 227 | - key: readability-function-size.StatementThreshold 228 | value: '800' 229 | - key: readability-identifier-naming.IgnoreFailedSplit 230 | value: '0' 231 | - key: readability-implicit-bool-conversion.AllowIntegerConditions 232 | value: '0' 233 | - key: readability-implicit-bool-conversion.AllowPointerConditions 234 | value: '0' 235 | - key: readability-simplify-boolean-expr.ChainedConditionalAssignment 236 | value: '0' 237 | - key: readability-simplify-boolean-expr.ChainedConditionalReturn 238 | value: '0' 239 | - key: readability-static-accessed-through-instance.NameSpecifierNestingThreshold 240 | value: '3' -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | .clangd 35 | 36 | build 37 | compile_commands.json -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | cmake_policy(SET CMP0048 NEW) 3 | cmake_policy(SET CMP0076 NEW) 4 | project(PracticeCpp VERSION 0.0.1) 5 | 6 | set(CMAKE_CXX_FLAGS "-std=c++17") 7 | 8 | Include(FetchContent) 9 | # Catch2 Unitestt Framework 10 | FetchContent_Declare( 11 | Catch2 12 | GIT_REPOSITORY https://github.com/catchorg/Catch2.git 13 | GIT_TAG v3.0.1 # or a later release 14 | ) 15 | FetchContent_MakeAvailable(Catch2) 16 | list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras) 17 | 18 | enable_testing() 19 | include(CTest) 20 | include(Catch) 21 | 22 | add_subdirectory(singleton) 23 | add_subdirectory(chrono_timer) 24 | add_subdirectory(pimpl) 25 | add_subdirectory(test) 26 | add_executable(callback_ex callback_function/callback_function_example.cpp) 27 | add_executable(callback_bind_class_func_ex callback_function/callback_bind_class_member_function.cpp) 28 | add_executable(lambda_ex lambda/lambda_example.cpp) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PracticeCpp 2 | 3 | Practicing some modern or advanced features and skills with some portable code snippets. Also collecting some best or good practices of cpp project. 4 | 5 | # ## Content 6 | 7 | - [X] singleton 8 | - [X] lambda function 9 | - [X] callback 10 | - [X] chrono timer: use \ to implement a timer to compute the time of a program cost. 11 | - [ ] diy: implement some toys of for study purpose 12 | 13 | - [ ] implementing smart ptr 14 | - [X] unique_ptr 15 | - [ ] dsa: data structure and implementation 16 | - [X] segment tree 17 | 18 | ## Build 19 | 20 | ### 3rd-party libraries 21 | 22 | This project uses [catchorg/Catch2](https://github.com/catchorg/Catch2) as unittest framework, which is as a git submodule. 23 | 24 | ``` 25 | git clone --recurse-submodules https://github.com/charles-sun0v0/PracticeCpp 26 | ``` 27 | 28 | Alternatively, the user could `git clone` this then `cd 3rdparty` and run `git submodule init && git submodule update` to fetch dependencies. 29 | 30 | ### build with CMake 31 | 32 | This project uses modern CMake concepts which is target-based. 33 | 34 | ```bash 35 | cd 36 | cmake -S . -B build 37 | ``` 38 | 39 | ## Warning 40 | 41 | The code is written for demonize or studying purpose without adequate tests. Therefore, it should not be applied to production directly. 42 | -------------------------------------------------------------------------------- /callback_function/callback_bind_class_member_function.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | class BeCalled{ 4 | public: 5 | int handle(int x,int y){ 6 | std::cout< func_; 15 | public: 16 | void register_callback(std::function handle){ 17 | func_=handle; 18 | } 19 | void call(int x){ 20 | if(func_ == nullptr) 21 | std::cout<<" nullptr"< 2 | 3 | ///*** Step1:C-style function pointer ***/ 4 | //typedef int (*FP)(int a, int b); 5 | 6 | 7 | // or like below 8 | using FP = int(*)(int a,int b); 9 | 10 | int add(int a, int b){ 11 | return a+b; 12 | } 13 | 14 | int minus(int a,int b){ 15 | return a-b; 16 | } 17 | 18 | 19 | int main(int argc, char** argv){ 20 | 21 | 22 | /* test1: C-style function pointer */ 23 | int (*func_ptr)(int,int); 24 | func_ptr =add; 25 | FP func_ptr2=add; 26 | std::cout<<"Test1..."<// std::function 35 | 36 | //void func(void) 37 | //{ 38 | // std::cout << __FUNCTION__ << std::endl; 39 | //} 40 | 41 | //class Foo 42 | //{ 43 | //public: 44 | // static int foo_func(int a) 45 | // { 46 | // std::cout << __FUNCTION__ << "(" << a << ") ->: "; 47 | // return a; 48 | // } 49 | //}; 50 | 51 | //class Bar 52 | //{ 53 | //public: 54 | // int operator() (int a) 55 | // { 56 | // std::cout << __FUNCTION__ << "(" << a << ") ->: "; 57 | // return a; 58 | // } 59 | //}; 60 | 61 | //int main() 62 | //{ 63 | 64 | // std::cout << __FUNCTION__ << std::endl; 65 | // // 绑定普通函数 66 | // std::function fr1 = func; 67 | // fr1(); 68 | 69 | // // 绑定类的静态成员函数,需要加上类作用域符号 70 | // std::function fr2 = Foo::foo_func; 71 | // std::cout << fr2(100) << std::endl; 72 | 73 | // // 绑定仿函数 74 | // Bar bar; 75 | // fr2 = bar; 76 | // std::cout << fr2(200) << std::endl; 77 | 78 | // return 0; 79 | //} 80 | -------------------------------------------------------------------------------- /chrono_timer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(chrono_example chromo_example.cpp) 2 | add_executable(compare_clock compare_clock.cpp) -------------------------------------------------------------------------------- /chrono_timer/chromo_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | template 7 | ostream& operator << (ostream& s, const chrono::duration& d) 8 | { 9 | s << "[" << d.count() << " of " << R::num << "/" 10 | << R::den << "]"; 11 | return s; 12 | } 13 | 14 | int main(int argc, char** argv) { 15 | chrono::seconds twentySeconds(20); 16 | chrono::hours aDay(24); 17 | chrono::milliseconds oneMillisecond(1); 18 | chrono::duration> d1(1); // 1 tick of 1/3 second 19 | chrono::duration> d2(1); // 1 tick of 1/5 second 20 | 21 | std::cout << twentySeconds << aDay << oneMillisecond << std::endl; 22 | 23 | #ifdef _WIN32 24 | system("pause"); 25 | #endif // _WIN32 26 | 27 | return 0; 28 | } -------------------------------------------------------------------------------- /chrono_timer/clock.hpp: -------------------------------------------------------------------------------- 1 | // copied from http://www.informit.com/articles/article.aspx?p=1881386&seqNum=2; 2 | // Author: Nicolai M. Josuttis 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | template 9 | void printClockData () 10 | { 11 | using namespace std; 12 | 13 | cout << "- precision: "; 14 | // if time unit is less or equal one millisecond 15 | typedef typename C::period P;// type of time unit 16 | if (ratio_less_equal::value) { 17 | // convert to and print as milliseconds 18 | typedef typename ratio_multiply::type TT; 19 | cout << fixed << double(TT::num)/TT::den 20 | << " milliseconds" << endl; 21 | } 22 | else { 23 | // print as seconds 24 | cout << fixed << double(P::num)/P::den << " seconds" << endl; 25 | } 26 | cout << "- is_steady: " << boolalpha << C::is_steady << endl; 27 | } -------------------------------------------------------------------------------- /chrono_timer/compare_clock.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chao-sun01io/PracticeCpp/ec87449e581f6d74b75dc8fc8348550101b4e38c/chrono_timer/compare_clock.cpp -------------------------------------------------------------------------------- /chrono_timer/timer.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define TIMERSTART(tag) auto tag##_start = std::chrono::steady_clock::now(),tag##_end = tag##_start 4 | #define TIMEREND(tag) tag##_end = std::chrono::steady_clock::now() 5 | #define DURATION_s(tag) printf("%s costs %d s\n",#tag,std::chrono::duration_cast(tag##_end - tag##_start).count()) 6 | #define DURATION_ms(tag) printf("%s costs %d ms\n",#tag,std::chrono::duration_cast(tag##_end - tag##_start).count()); 7 | #define DURATION_us(tag) printf("%s costs %d us\n",#tag,std::chrono::duration_cast(tag##_end - tag##_start).count()); 8 | #define DURATION_ns(tag) printf("%s costs %d ns\n",#tag,std::chrono::duration_cast(tag##_end - tag##_start).count()); 9 | 10 | 11 | // usage: 12 | // TIMERSTART(for_loop); 13 | // for (int i = 0; i < 100000; i++) 14 | // { 15 | // i*i; 16 | // } 17 | // TIMEREND(for_loop); 18 | // DURATION_ms(for_loop); -------------------------------------------------------------------------------- /diy/binheap.hpp: -------------------------------------------------------------------------------- 1 | // Binary heap implemention 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | // take min heap for example. 9 | template class BinaryHeap { 10 | public: 11 | explicit BinaryHeap(int capacity = 100) { 12 | cur_size_ = 0; 13 | data_.resize(capacity); 14 | } 15 | // explicit BinaryHeap(const std::vector &items); 16 | 17 | // insertion 18 | void push(Comparable v) { 19 | // data_[0] is not used 20 | if (cur_size_ == data_.size() - 1) { 21 | data_.resize(2 * cur_size_ + 1); 22 | } 23 | 24 | // percolate up 25 | int hole = ++cur_size_; 26 | auto copy = v; 27 | 28 | data_[0] = std::move(v); 29 | for (; copy < parent(hole); hole /= 2) { 30 | data_[hole] = std::move(data_[parent(hole)]); 31 | } 32 | data_[hole] = std::move(data_[0]); 33 | } 34 | 35 | void pop() { 36 | // pick the lastelement ,then percolate down 37 | data_[1] = data_[--cur_size_]; 38 | 39 | Comparable tmp = std::move(data_[1]); 40 | int hole = 1; 41 | for (int child; lchild(hole) <= cur_size_; hole = child) { 42 | child = lchild(hole); 43 | if (rchild(hole) <= cur_size_ && 44 | data_[rchild(hole)] < data_[lchild(hole)]) 45 | child = rchild(hole); 46 | if (data_[child] < tmp) { 47 | data_[hole] = std::move(data_[child]); 48 | } else 49 | break; 50 | } 51 | data_[hole] = std::move(tmp); 52 | } 53 | 54 | Comparable top() { 55 | // if(empty()) 56 | // throw xxxx; 57 | 58 | return data_[1]; 59 | } 60 | 61 | bool empty() { return cur_size_ == 0; } 62 | 63 | private: 64 | std::size_t cur_size_; 65 | std::vector data_; 66 | size_t lchild(size_t i) { return 2 * i; } 67 | size_t rchild(size_t i) { return 2 * i + 1; } 68 | size_t parent(size_t i) { return i / 2; } 69 | }; 70 | -------------------------------------------------------------------------------- /diy/diy.md: -------------------------------------------------------------------------------- 1 | # DIY 2 | 3 | - [ ] diy::unique_ptr -------------------------------------------------------------------------------- /diy/dsa/disjoint_set.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | namespace diy { 6 | class DisjointSet { 7 | public: 8 | DisjointSet(int n_elements); 9 | 10 | int find(int i); 11 | void union_set(int root1, int root2); 12 | 13 | private: 14 | std::vector s; 15 | }; 16 | 17 | inline DisjointSet::DisjointSet(int n_elements) : s(n_elements) { 18 | for (int i = 0; i < s.size(); ++i) { 19 | s[i] = i; 20 | } 21 | } 22 | auto DisjointSet::find(int i) -> int { 23 | if (i >= s.size()) throw std::out_of_range("index of out range"); 24 | if (s[i] != i) s[i] = find(s[i]); 25 | return s[i]; 26 | } 27 | 28 | // Note: there is more effient way to implement disjoint set : union by size 29 | void DisjointSet::union_set(int x, int y) { s[find(x)] = find(s[y]); } 30 | } // namespace diy -------------------------------------------------------------------------------- /diy/dsa/merge_sort.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | // merge sort elements between [left, right) 5 | 6 | // Note: This isn't an efficient way because create log(N) vector at the same time 7 | // Prefer the implementation bellow. 8 | // template 9 | // std::vector mergeSort(std::vector &arr, int left, int right) { 10 | // if (left == right - 1) return {arr[left]}; 11 | // int center = left + (right - left) / 2; 12 | // auto left_sorted = mergeSort(arr, left, center); 13 | // auto right_sorted = mergeSort(arr, center, right); 14 | // std::vector res(left_sorted.size() + right_sorted.size()); 15 | // std::merge(left_sorted.begin(), left_sorted.end(), right_sorted.begin(), right_sorted.end(), res.begin()); 16 | // return res; 17 | // } 18 | 19 | // merge elements of arr in [left,right) and [right,end) into [left,end) of buf 20 | template 21 | void merge(std::vector &arr, std::vector &buf, int left, int right, int rightend) { 22 | int left_end = right; 23 | int i = left; 24 | int j = right; 25 | int pos = left; 26 | 27 | for (; i < right && j < rightend;) { 28 | if (arr[i] <= arr[j]) { 29 | buf[pos++] = std::move(arr[i++]); 30 | } else { 31 | buf[pos++] = std::move(arr[j++]); 32 | } 33 | } 34 | 35 | if (i != right) { 36 | std::copy(arr.begin() + i, arr.begin() + right, buf.begin() + pos); 37 | } 38 | 39 | if (j != rightend) { 40 | std::copy(arr.begin() + j, arr.begin() + rightend, buf.begin() + pos); 41 | } 42 | 43 | std::copy(buf.begin() + left, buf.begin() + rightend, arr.begin() + left); 44 | } 45 | 46 | // mergeSoft subroution in [left,right] 47 | template 48 | void mergeSort(std::vector &arr, std::vector &buf, int left, int right) { 49 | // if (left == right - 1) return; 50 | if (left < right) { 51 | int center = left + (right - left) / 2; 52 | mergeSort(arr, buf, left, center); 53 | mergeSort(arr, buf, center + 1, right); 54 | // std::merge(arr.begin() + left, arr.begin() + center + 1, arr.begin() + center + 1, arr.begin() + right + 1, buf.begin() + left); 55 | // std::copy(buf.begin() + left, buf.begin() + right + 1, arr.begin() + left); 56 | merge(arr, buf, left, center + 1, right + 1); 57 | } 58 | } 59 | 60 | template 61 | void mergeSort(std::vector &arr) { 62 | std::vector buf(arr.size()); 63 | mergeSort(arr, buf, 0, arr.size() - 1); 64 | } 65 | -------------------------------------------------------------------------------- /diy/dsa/segment_tree.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | namespace diy { 8 | 9 | /** 10 | * @brief Demostrate SegmentTree by compute the range sum in interval [L,R) 11 | * Implemented by Binary Heap which is more efficient 12 | */ 13 | template 14 | class SegmentTree { 15 | public: 16 | explicit SegmentTree(const std::vector &arr) { build(arr); } 17 | void build(const std::vector &arr) { 18 | n_ = arr.size(); 19 | tree_ = std::vector(2 * n_, 0); 20 | std::copy(arr.begin(), arr.end(), tree_.begin() + n_); 21 | for (int i = n_ - 1; i > 0; --i) { 22 | tree_[i] = tree_[i << 1] + tree_[i << 1 | 1]; 23 | } 24 | } 25 | 26 | void update(int idx, T val) { 27 | if (idx < 0 || idx >= n_) throw std::out_of_range("idx of range"); 28 | tree_[idx + n_] = val; 29 | // move upward and update parents 30 | for (int i = idx + n_; i > 0; i >>= 1) { 31 | tree_[i >> 1] = tree_[i] + tree_[i ^ 1]; // if m = 2*i,then m^1 = 2*i+1 and vice versa 32 | } 33 | } 34 | 35 | // return the range_sum value of [l,r); 36 | auto query(int l, int r) -> T { 37 | if (l < 0 || r > n_) throw std::out_of_range("idx of range"); 38 | 39 | T res = 0; 40 | // loop to find the sum in the range [L,R) 41 | // if(l is odd) then its parent is not included in the result( L is the right child of its parent) 42 | // if(r is odd) then (R-1)'s parent is not included in the result (R-1 is even,so it's the left child of it's parent) 43 | for (l = l + n_, r = r + n_; l > 0 && l < r; l >>= 1, r >>= 1) { 44 | if (l & 1) { 45 | res += tree_[l++]; 46 | } 47 | if (r & 1) { 48 | res += tree_[--r]; 49 | } 50 | } 51 | 52 | return res; 53 | } 54 | 55 | private: 56 | std::vector tree_; 57 | int n_{}; 58 | }; 59 | 60 | } // namespace diy -------------------------------------------------------------------------------- /diy/dsa/segment_tree_2.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | namespace diy { 8 | /** 9 | * @brief Demostrate SegmentTree by compute the range sum in interval [L,R). Implemented by recursion 10 | * 11 | */ 12 | template 13 | class SegmentTree2 { 14 | public: 15 | explicit SegmentTree2(const std::vector &arr) { build(arr); } 16 | void build(const std::vector &arr) { 17 | n_ = arr.size(); 18 | tree_ = std::vector(n_ * 4); 19 | build(arr, 0, 0, n_ - 1); 20 | } 21 | 22 | void update(int idx, T val) { 23 | if (idx < 0 || idx >= n_) throw std::out_of_range("idx of range"); 24 | update(0, 0, n_ - 1, idx, val); 25 | } 26 | 27 | // return the range_sum value of [l,r); 28 | auto query(int l, int r) -> T { return query(0, 0, n_ - 1, l, r - 1); } 29 | 30 | private: 31 | // tree_[idx] stores the sum of arr[l : r] 32 | void build(const std::vector &arr, int node, int l, int r) { 33 | if (l == r) { 34 | tree_[node] = arr[l]; 35 | return; 36 | } 37 | // mid = (l + r) / 2 38 | int mid = l + (r - l) / 2; 39 | build(arr, lchild(node), l, mid); 40 | build(arr, rchild(node), mid + 1, r); 41 | tree_[node] = tree_[lchild(node)] + tree_[rchild(node)]; 42 | } 43 | 44 | void update(int node, int start, int end, int idx, int val) { 45 | if (start == end) { 46 | tree_[node] = val; 47 | } else { 48 | int mid = start + (end - start) / 2; 49 | if (start <= idx && idx <= mid) { 50 | update(lchild(node), start, mid, idx, val); 51 | } else { 52 | update(rchild(node), mid + 1, end, idx, val); 53 | } 54 | tree_[node] = tree_[lchild(node)] + tree_[rchild(node)]; 55 | } 56 | } 57 | 58 | /** 59 | * @brief Get range sum of [L,R] 60 | * 61 | * @param node the node of segment tree 62 | * @param start start point of range represented by node 63 | * @param end end of range represented by node 64 | * @param l l - end of interval 65 | * @param r r - endo of interval 66 | * @return T 67 | */ 68 | auto query(int node, int start, int end, int l, int r) -> T { 69 | if (r < start || l > end) { 70 | return 0; 71 | } 72 | 73 | if (l <= start && r >= end) { // all represented by node is included in [l,r] 74 | return tree_[node]; 75 | } 76 | 77 | // range repsented by a node is partially included in thve given range 78 | int mid = start + (end - start) / 2; 79 | int v1 = query(lchild(node), start, mid, l, r); 80 | int v2 = query(rchild(node), mid + 1, end, l, r); 81 | return v1 + v2; 82 | } 83 | 84 | int lchild(int i) { return 2 * i + 1; } 85 | int rchild(int i) { return 2 * i + 2; } 86 | std::vector tree_; 87 | int n_{}; 88 | }; 89 | 90 | } // namespace diy -------------------------------------------------------------------------------- /diy/unique_ptr.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | namespace diy { 5 | template 6 | class unique_ptr { 7 | private: 8 | T *ptr_; 9 | 10 | public: 11 | explicit unique_ptr(T *ptr) : ptr_(ptr) {} 12 | unique_ptr(unique_ptr &&other) noexcept : ptr_(nullptr) { this->swap(other); }; 13 | unique_ptr &operator=(unique_ptr &&other) noexcept { 14 | this->swap(other); 15 | return *this; 16 | } 17 | 18 | // TODO: Constructor/Assignment that allows move semantics 19 | // template 20 | // unique_ptr(unique_ptr&& moving); 21 | 22 | // move and swap idiom 23 | // unique_ptr &operator=(unique_ptr rhs) noexcept // will call move constructor 24 | // { 25 | // // std::swap(ptr_, rhs.ptr_);// is also ok 26 | // this->swap(rhs); 27 | // return *this; 28 | // } 29 | unique_ptr(const unique_ptr &) = delete; 30 | unique_ptr &operator=(const unique_ptr &) = 31 | delete; // note: shouldn't be reserved when use move-swap 32 | 33 | ~unique_ptr() { 34 | delete ptr_; 35 | ptr_ = nullptr; 36 | } 37 | 38 | void swap(unique_ptr &other) noexcept { 39 | using std::swap; 40 | swap(ptr_, other.ptr_); 41 | } 42 | 43 | T *get() const { return ptr_; } 44 | 45 | T &operator*() const { return *ptr_; } 46 | 47 | T *operator->() const { return ptr_; } 48 | 49 | // So it can be used in conditional expression 50 | explicit operator bool() { return ptr_; } 51 | }; 52 | } // namespace diy -------------------------------------------------------------------------------- /lambda/lambda_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include // for_each 5 | int external = 1; 6 | void func(int param){ 7 | static int sum = 0; 8 | int internal_local = 1; 9 | // lambda: [capture list](parameter list)->return type{function body} 10 | // [...] capture list: non-static local variable! 11 | auto add = [internal_local,param](int a,int b){ 12 | return sum + internal_local+param+external+a+b; 13 | 14 | }; 15 | std::cout< str_vec(&str[0],&str[4]); // output: I love (without C++) 23 | // std::vector str_vec(&str[0],&str[5]); // It outputs "I love C++",but str[5] the index is overflow! 24 | std::vector str_vec(str,str+5); // good! 25 | std::for_each(str_vec.begin(),str_vec.end(), 26 | [](const std::string& s){ std::cout << s;}); // empty capture list; 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /pimpl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(pimpl_main pimpl_main.cpp x.h x.cpp) 2 | -------------------------------------------------------------------------------- /pimpl/pimpl_main.cpp: -------------------------------------------------------------------------------- 1 | #include "x.h" 2 | #include 3 | #include 4 | #include 5 | int main(int argc, char *argv[]) 6 | { 7 | X x; 8 | x.push_element("I"); 9 | x.push_element("love"); 10 | x.push_element("coding"); 11 | x.print(); 12 | 13 | X x2 = x; // copy ctor 14 | x2.push_element(",too"); 15 | x2.print(); 16 | 17 | x = x2; // copy assignment op 18 | x.print(); 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /pimpl/x.cpp: -------------------------------------------------------------------------------- 1 | #include "x.h" 2 | #include 3 | #include 4 | #include 5 | class X::XImpl{ 6 | public: 7 | XImpl() = default; 8 | std::vector array_; 9 | }; 10 | 11 | X::X() 12 | :pimpl_{new XImpl} 13 | { 14 | 15 | } 16 | 17 | // or =default; This is neccessary,because 18 | // unique_ptr’s destructor requires a complete type in order to invoke delete; 19 | // here force it to be defined in a place where impl is already defined 20 | // see: https://herbsutter.com/gotw/_100/ 21 | X::~X(){} 22 | 23 | X::X(const X &x) 24 | { 25 | pimpl_ = std::make_unique(); 26 | *pimpl_ = *x.pimpl_; 27 | } 28 | 29 | X &X::operator=(const X &other) 30 | { 31 | if(&other == this){ 32 | return *this; 33 | } 34 | *pimpl_ = *other.pimpl_; 35 | return *this; 36 | } 37 | 38 | void X::push_element(const std::string &str) 39 | { 40 | pimpl_->array_.push_back(str); 41 | } 42 | 43 | void X::print() 44 | { 45 | for(const auto & i :pimpl_->array_){ 46 | std::cout<< i <<" "; 47 | } 48 | std::cout< // std::unique_ptr 5 | #include 6 | class X 7 | { 8 | public: 9 | X(); 10 | ~X(); 11 | X(const X& x); 12 | X& operator=(const X& x); 13 | void push_element(const std::string& str); 14 | void print(); 15 | private: 16 | class XImpl; 17 | std::unique_ptr pimpl_; 18 | }; 19 | 20 | #endif // X_H 21 | -------------------------------------------------------------------------------- /singleton/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(inherit_singleton_ex inherit_singleton_example.cpp) 2 | 3 | add_executable(inherit_singleton_ex_v2 inherit_singleton_example_v2.cpp) 4 | 5 | add_executable(basic_singleton_ex basic_singleton_example.cpp) 6 | 7 | add_executable(basic_singleton_ex_v2 basic_singleton_example_v2.cpp) 8 | 9 | add_executable(magic_static_singleton_ex magic_static_singleton_example.cpp) 10 | 11 | add_executable(ref_ret_function_ex ref_ret_singleton_example.cpp) 12 | 13 | add_executable(ref_ret_function_template_ex ref_ret_function_template_ex.cpp) 14 | -------------------------------------------------------------------------------- /singleton/basic_singleton_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | // version1: 3 | // with problems below: 4 | // 1. thread is not safe 5 | // 2. memory leak 6 | 7 | class Singleton{ 8 | private: 9 | Singleton(){ 10 | std::cout<<"constructor called!"< 2 | #include // shared_ptr 3 | #include // mutex 4 | 5 | // version 2: 6 | // with problems below fixed: 7 | // 1. thread is safe now 8 | // 2. memory doesn't leak 9 | 10 | class Singleton{ 11 | public: 12 | typedef std::shared_ptr Ptr; 13 | ~Singleton(){ 14 | std::cout<<"destructor called!"< lk(m_mutex); 23 | if(m_instance_ptr == nullptr){ 24 | m_instance_ptr = std::shared_ptr(new Singleton); 25 | } 26 | return m_instance_ptr; 27 | } 28 | } 29 | 30 | 31 | private: 32 | Singleton(){ 33 | std::cout<<"constructor called!"< 4 | 5 | template 6 | class Singleton{ 7 | public: 8 | static T& get_instance() noexcept(std::is_nothrow_constructible::value){ 9 | static T instance; 10 | return instance; 11 | } 12 | virtual ~Singleton() noexcept{ 13 | std::cout<<"destructor called!"<{ 30 | // !!!! attention!!! 31 | // needs to be friend in order to 32 | // access the private constructor/destructor 33 | friend class Singleton; 34 | public: 35 | DerivedSingle(const DerivedSingle&)=delete; 36 | DerivedSingle& operator =(const DerivedSingle&)= delete; 37 | private: 38 | DerivedSingle()=default; 39 | }; 40 | 41 | int main(int argc, char* argv[]){ 42 | DerivedSingle& instance1 = DerivedSingle::get_instance(); 43 | DerivedSingle& instance2 = DerivedSingle::get_instance(); 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /singleton/inherit_singleton_example_v2.cpp: -------------------------------------------------------------------------------- 1 | // author: sunchaothu 2 | // brief: a singleton base class offering an easy way to create singleton 3 | #include 4 | 5 | template 6 | class Singleton{ 7 | public: 8 | static T& get_instance() noexcept(std::is_nothrow_constructible::value){ 9 | static T instance{token()}; 10 | return instance; 11 | } 12 | virtual ~Singleton() =default; 13 | Singleton(const Singleton&)=delete; 14 | Singleton& operator =(const Singleton&)=delete; 15 | protected: 16 | struct token{}; // helper class 17 | Singleton() noexcept=default; 18 | }; 19 | 20 | 21 | /********************************************/ 22 | // Example: 23 | // constructor should be public because protected `token` control the access 24 | 25 | 26 | class DerivedSingle:public Singleton{ 27 | public: 28 | DerivedSingle(token){ 29 | std::cout<<"constructor called!"< 2 | 3 | class Singleton 4 | { 5 | public: 6 | ~Singleton(){ 7 | std::cout<<"destructor called!"< 2 | 3 | class A 4 | { 5 | public: 6 | A() { 7 | std::cout<<"constructor" < 15 | T& get_global(){ 16 | static T instance; 17 | return instance; 18 | } 19 | 20 | int main(int argc, char *argv[]) 21 | { 22 | A& instance_1 = get_global(); 23 | A& instance_2 = get_global(); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /singleton/ref_ret_singleton_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class A 4 | { 5 | public: 6 | A() { 7 | std::cout<<"constructor" < 2 | #include 3 | #include 4 | TEST_CASE("test_disjoint_set", "[disjoint_set]") { 5 | diy::DisjointSet set(10); 6 | set.union_set(1, 3); 7 | REQUIRE(set.find(1) == set.find(3)); 8 | REQUIRE(set.find(1) != set.find(5)); 9 | set.union_set(1, 5); 10 | set.union_set(5, 9); 11 | REQUIRE(set.find(1) == set.find(9)); 12 | REQUIRE(set.find(3) == set.find(9)); 13 | } -------------------------------------------------------------------------------- /test/test_segment_tree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "diy/dsa/segment_tree.hpp" 5 | #include "diy/dsa/segment_tree_2.hpp" 6 | TEST_CASE("test_segment_tree") { 7 | using namespace diy; 8 | std::vector inputs{1, 3, 5, 7, 9}; 9 | 10 | diy::SegmentTree tree(inputs); 11 | 12 | SECTION("test range sum of [L,R)") { 13 | REQUIRE(tree.query(0, 1) == 1); 14 | REQUIRE(tree.query(1, 3) == 8); 15 | REQUIRE(tree.query(3, 5) == 16); 16 | REQUIRE(tree.query(1, 5) == 24); 17 | } 18 | SECTION("update some value") { 19 | tree.update(2, 4); 20 | tree.update(4, 6); 21 | //{1,3,4,7,6} 22 | REQUIRE(tree.query(0, 1) == 1); 23 | REQUIRE(tree.query(1, 3) == 7); 24 | REQUIRE(tree.query(3, 5) == 13); 25 | REQUIRE(tree.query(1, 5) == 20); 26 | } 27 | } 28 | 29 | TEST_CASE("test segment tree v2") { 30 | using namespace diy; 31 | std::vector inputs{1, 3, 5, 7, 9}; 32 | 33 | diy::SegmentTree2 tree(inputs); 34 | 35 | SECTION("test range sum of [L,R)") { 36 | REQUIRE(tree.query(0, 1) == 1); 37 | REQUIRE(tree.query(1, 3) == 8); 38 | REQUIRE(tree.query(3, 5) == 16); 39 | REQUIRE(tree.query(1, 5) == 24); 40 | } 41 | SECTION("update some value") { 42 | tree.update(2, 4); 43 | // tree.update(4, 6); 44 | //{1,3,4,7,6} 45 | // REQUIRE(tree.query(0, 1) == 1); 46 | // REQUIRE(tree.query(1, 3) == 7); 47 | // REQUIRE(tree.query(3, 5) == 13); 48 | // REQUIRE(tree.query(1, 5) == 20); 49 | } 50 | } -------------------------------------------------------------------------------- /test/test_sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "catch2/catch_test_macros.hpp" 8 | #include "catch2/matchers/catch_matchers.hpp" 9 | #include "catch2/matchers/catch_matchers_vector.hpp" 10 | #include "diy/dsa/merge_sort.hpp" 11 | 12 | class SortFixture { 13 | public: 14 | SortFixture() : data(150) { 15 | // fill the vectors with random numbers 16 | std::random_device rd; 17 | std::mt19937 mt(rd()); 18 | std::uniform_int_distribution<> dis(-100000, 100000); 19 | 20 | std::generate(data.begin(), data.end(), std::bind(dis, std::ref(mt))); 21 | sorted_data = data; 22 | std::sort(sorted_data.begin(), sorted_data.end()); 23 | } 24 | 25 | protected: 26 | std::vector data; 27 | std::vector sorted_data; 28 | }; 29 | 30 | TEST_CASE_METHOD(SortFixture, "[sort][mergeSort]") { 31 | mergeSort(data); 32 | REQUIRE_THAT(data, Catch::Matchers::Equals(sorted_data)); 33 | } -------------------------------------------------------------------------------- /test/test_unique_ptr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "diy/unique_ptr.hpp" 4 | using namespace std; 5 | 6 | class TestClass { 7 | public: 8 | TestClass() { std::cout << "constructor!" << std::endl; }; 9 | ~TestClass() { std::cout << "destructor!" << std::endl; } 10 | void print() { std::cout << "my address: " << this << std::endl; } 11 | }; 12 | 13 | int main(int argc, const char **argv) { 14 | auto raw_ptr = new TestClass; 15 | std::cout << "raw ptr point to: " << raw_ptr << std::endl; 16 | 17 | diy::unique_ptr ptr(raw_ptr); 18 | std::cout << "smart ptr point to: " << ptr.get() << std::endl; 19 | ptr->print(); 20 | 21 | // auto ptr1 = ptr; // compile error as expected because copy-constructor is 22 | // deleted 23 | auto ptr2 = std::move(ptr); 24 | ptr2->print(); 25 | 26 | // move assignment 27 | ptr = std::move(ptr2); 28 | ptr->print(); 29 | return 0; 30 | } --------------------------------------------------------------------------------