├── .gitattributes ├── .github └── workflows │ ├── ci.yml │ ├── docdeploy.yml │ └── doctest.yml ├── .gitignore ├── LICENSE.txt ├── README.md ├── config.nims ├── cppstl.nim ├── cppstl.nimble ├── cppstl ├── private │ └── iterators.nim ├── std_basicstring.nim ├── std_complex.nim ├── std_exception.nim ├── std_pair.nim ├── std_smartptrs.nim ├── std_string.nim └── std_vector.nim ├── docs └── index.html └── tests ├── .gitignore ├── config.nims ├── destroy_bug_15.nim ├── tcomplex.nim ├── tdestructor_codegen_bug.nim ├── tpair.nim ├── tsmart_ptrs.nim ├── tstring.nim └── tvector.nim /.gitattributes: -------------------------------------------------------------------------------- 1 | docs/* linguist-vendored 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | branches: 4 | - master 5 | push: 6 | branches: 7 | - devel 8 | - master 9 | 10 | jobs: 11 | build: 12 | runs-on: ${{ matrix.os }} 13 | strategy: 14 | matrix: 15 | nim: 16 | - '2.0.x' 17 | - 'stable' 18 | - devel 19 | os: 20 | - ubuntu-latest 21 | # - windows-latest 22 | - macOS-latest 23 | 24 | name: '${{ matrix.nim }} (${{ matrix.os }})' 25 | steps: 26 | - uses: actions/checkout@v4 27 | - name: Setup nim 28 | uses: jiro4989/setup-nim-action@v2 29 | with: 30 | use-nightlies: true 31 | nim-version: ${{ matrix.nim }} 32 | repo-token: ${{ secrets.GITHUB_TOKEN }} 33 | - run: nimble install -y 34 | - run: testament p "tests/t*.nim" 35 | - run: nimble test 36 | 37 | -------------------------------------------------------------------------------- /.github/workflows/docdeploy.yml: -------------------------------------------------------------------------------- 1 | 2 | on: 3 | push: 4 | branches: 5 | - master 6 | 7 | permissions: 8 | id-token: write 9 | pages: write 10 | 11 | 12 | jobs: 13 | # Build job 14 | build: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | 20 | - name: Setup nim 21 | uses: jiro4989/setup-nim-action@v2 22 | with: 23 | nim-version: stable 24 | repo-token: ${{ secrets.GITHUB_TOKEN }} 25 | 26 | - name: Setup Pages 27 | id: pages 28 | uses: actions/configure-pages@v3 29 | 30 | - name: Build docs 31 | run: nimble gendoc -y 32 | 33 | - name: Upload artifact 34 | uses: actions/upload-pages-artifact@v3 35 | with: 36 | path: 'docs/' 37 | 38 | - name: Deploy to GitHub Pages 39 | id: deployment 40 | uses: actions/deploy-pages@v4 41 | 42 | -------------------------------------------------------------------------------- /.github/workflows/doctest.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | branches: 4 | - master 5 | push: 6 | branches: 7 | - devel 8 | - master 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Setup nim 16 | uses: jiro4989/setup-nim-action@v2 17 | with: 18 | nim-version: stable 19 | repo-token: ${{ secrets.GITHUB_TOKEN }} 20 | 21 | - run: nimble install -y 22 | - run: nimble gendoc 23 | 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | htmldocs 2 | docs/ 3 | !docs/index.html 4 | bin 5 | testresults/ 6 | nimcache/ 7 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2019 Nouredine Hussain 2 | Copyright 2021 Caillaud Regis 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nim bindings for the C++ STL 2 | 3 | ![workflow](https://github.com/Clonkk/nim-cppstl/actions/workflows/ci.yml/badge.svg) 4 | ![workflow](https://github.com/Clonkk/nim-cppstl/actions/workflows/doctest.yml/badge.svg) 5 | 6 | ## Introduction 7 | 8 | This library is a Nim wrapper for C++ Standard Template Library (STL) class. 9 | **This library is obviously only compatible with the C++ backend** 10 | 11 | I recommand using this bindings only in two cases: 12 | * When wrapping a C++ library (But make sure to offer a Nim idomatic API that does not expose the STL to the user if possible). 13 | * In some performance critical code where the cost of converting Nim types to c++ types is problematic (like embeded devices). 14 | 15 | 16 | ## Installation 17 | 18 | ``` 19 | nimble install cppstl 20 | ``` 21 | 22 | Add the following lines to your `.nimble`: 23 | ``` 24 | backend = "cpp" 25 | requires "cppstl" 26 | ``` 27 | 28 | ## Limitations 29 | 30 | #### ``cppstl`` currently wraps : 31 | 32 | * ``std::string`` 33 | * ``std::basic_string`` 34 | * ``std::vector`` 35 | * ``std::complex`` 36 | * ``std::pair`` 37 | 38 | * Smart pointers are partially supported: 39 | * ``std::unique_ptr`` 40 | * ``std::shared_ptr`` 41 | 42 | #### Avoid using wrapped STL objects in top-level Nim scope. 43 | Most of the times it works on Nim 1.x but leads to both compile-time and runtime errors on 2.x. 44 | So instantiate them in subroutines only to ensure portability between 1.x and 2.x. 45 | 46 | I.e this usecase is not recommended: 47 | ``` 48 | when isMainModule: 49 | var vec = initCppVector[int]() 50 | vec.pushBack(20) 51 | ``` 52 | Use this one instead: 53 | ``` 54 | when isMainModule: 55 | proc foo = 56 | var vec = initCppVector[int]() 57 | vec.pushBack(20) 58 | foo() 59 | ``` 60 | 61 | 62 | ## Contributions 63 | 64 | All contributions are welcome! 65 | 66 | If there is a missing function or class, that you need, don't be shy to open an issue or a PR. 67 | 68 | ### Running Tests 69 | 70 | ``` 71 | nimble test 72 | ``` 73 | 74 | or 75 | 76 | ``` 77 | testament p "tests/t*.nim" 78 | ``` 79 | 80 | ## Usage 81 | 82 | The documentation is here : https://clonkk.github.io/nim-cppstl/cppstl.html 83 | 84 | You can find more use-case in the `tests` folder. 85 | 86 | ## License 87 | 88 | This code is licensed under MIT license (see [LICENSE.txt](./LICENSE.txt) for details) 89 | -------------------------------------------------------------------------------- /config.nims: -------------------------------------------------------------------------------- 1 | when not compiles(nimVersion): 2 | const nimVersion = (major: NimMajor, minor: NimMinor, patch: NimPatch) 3 | 4 | switch("backend", "cpp") 5 | 6 | when defined(macosx): 7 | switch("cc", "gcc") 8 | -------------------------------------------------------------------------------- /cppstl.nim: -------------------------------------------------------------------------------- 1 | import cppstl/std_vector 2 | export std_vector 3 | import cppstl/std_basicstring 4 | export std_basicstring 5 | import cppstl/std_string 6 | export std_string 7 | import cppstl/std_smartptrs 8 | export std_smartptrs 9 | import cppstl/std_complex 10 | export std_complex 11 | import cppstl/std_pair 12 | export std_pair 13 | 14 | when not defined(cpp): 15 | {.error: "C++ backend required to use STL wrapper".} 16 | # std=c++11 at least needed 17 | # {.passC: "-std=c++11".} 18 | 19 | ## Nim wrapper for C++ STL : 20 | ## * ``std::vector`` mapped to ``CppVector`` 21 | ## * ``std::basic_string`` mapped to ``CppBasicString`` 22 | ## * ``std::string`` mapped to ``CppString`` (alias for ``CppBasicString[cchar]``) 23 | ## * ``std::complex`` mapped to ``CppComplex`` 24 | ## * ``std::shared_ptr`` mapped to ``CppSharedPtr`` 25 | ## * ``std::unique_ptr`` mapped to ``CppUniquePtr`` 26 | ## * ``std::pair`` mapped to ``CppPair`` 27 | 28 | runnableExamples: 29 | import cppstl 30 | var stdstr = initCppString("AZERTY") 31 | assert stdstr == "AZERTY" 32 | stdstr.append("UIOP") 33 | assert stdstr == "AZERTYUIOP" 34 | let startportion = stdstr.find("AZ") 35 | if startportion != std_npos: 36 | let endportion = startportion + len("AZ") 37 | stdstr.replace(startportion, endportion, "QW") 38 | assert stdstr == "QWERTYUIOP" 39 | 40 | runnableExamples: 41 | import cppstl 42 | import complex 43 | var z = initCppComplex[float32](41.0, 31.0) 44 | var conj_z = z.conj() 45 | assert conj_z.real == z.real 46 | assert conj_z.imag == -z.imag 47 | 48 | 49 | -------------------------------------------------------------------------------- /cppstl.nimble: -------------------------------------------------------------------------------- 1 | # Package 2 | 3 | version = "0.7.0" 4 | author = "Clonkk" 5 | description = "Bindings for the C++ Standard Template Library (STL)" 6 | license = "MIT" 7 | 8 | 9 | # Dependencies 10 | 11 | requires "nim >= 2.0.0" 12 | 13 | backend = "cpp" 14 | 15 | task gendoc, "gen doc": 16 | exec("nimble doc --backend:cpp --project cppstl.nim --out:docs/") 17 | 18 | task test, "Run the tests": 19 | # run the manually to change the compilation flags 20 | exec "nim cpp -r tests/destroy_bug_15.nim" 21 | exec "nim cpp -r --gc:arc tests/destroy_bug_15.nim" 22 | exec "nim cpp -r tests/tvector.nim" 23 | exec "nim cpp -r --gc:arc tests/tvector.nim" 24 | exec "nim cpp -r tests/tstring.nim" 25 | exec "nim cpp -r --gc:arc tests/tstring.nim" 26 | exec "nim cpp -r tests/tcomplex.nim" 27 | exec "nim cpp -r --gc:arc tests/tcomplex.nim" 28 | exec "nim cpp -r tests/tpair.nim" 29 | exec "nim cpp -r --gc:arc tests/tpair.nim" 30 | exec "nim cpp -r tests/tsmart_ptrs.nim" 31 | exec "nim cpp -r --gc:arc tests/tsmart_ptrs.nim" 32 | 33 | # the following should compile and *not* produce a codegen error 34 | exec "nim cpp --gc:arc -r tests/tdestructor_codegen_bug.nim" 35 | exec "nim cpp -r tests/tdestructor_codegen_bug.nim" 36 | -------------------------------------------------------------------------------- /cppstl/private/iterators.nim: -------------------------------------------------------------------------------- 1 | # This code is licensed under MIT license (see LICENSE.txt for details) 2 | 3 | type 4 | CppIterator*[ValueType] {.importc.} = object 5 | CppConstIterator*[ValueType] {.importc.} = object 6 | 7 | type SomeCppIterator = CppIterator or CppConstIterator 8 | 9 | proc `+`*[I: SomeCppIterator](it: I, offset: int): I {.importcpp: "# + #".} 10 | proc `-`*[I: SomeCppIterator](it: I, offset: int): I {.importcpp: "# - #".} 11 | 12 | proc inc*(it: SomeCppIterator) {.importcpp: "(void)(++#)".} 13 | proc inc*(it: SomeCppIterator, offset: int) {.importcpp: "(void)(# += #)".} 14 | 15 | proc `==`*[ValueType](it, otherIt: CppIterator[ValueType]): bool {.importcpp: "# == #".} 16 | proc `==`*[ValueType](it, otherIt: CppConstIterator[ValueType]): bool {.importcpp: "# == #".} 17 | 18 | proc `[]`*[ValueType](it: CppIterator[ValueType]): var ValueType {.importcpp: "*#".} 19 | proc `[]`*[ValueType](it: CppConstIterator[ValueType]): ValueType {.importcpp: "*#".} 20 | -------------------------------------------------------------------------------- /cppstl/std_basicstring.nim: -------------------------------------------------------------------------------- 1 | # This code is licensed under MIT license (see LICENSE.txt for details) 2 | 3 | import strformat 4 | import ./private/iterators 5 | export iterators 6 | import ./std_exception 7 | export std_exception 8 | when not defined(cpp): 9 | {.error: "C++ backend required to use STL wrapper".} 10 | 11 | {.push header: "".} 12 | 13 | type 14 | CppBasicString*[T] {.importcpp: "std::basic_string".} = object 15 | CppBasicStringIterator*[T] {.importcpp: "std::basic_string<'0>::iterator".} = CppIterator[T] 16 | CppBasicStringConstIterator*[T] {.importcpp: "std::basic_string<'0>::const_iterator".} = CppConstIterator[T] 17 | 18 | # npos is declared as the highest possible value of csize_t 19 | # In C++ it is -1 due how overflow works 20 | const stdNpos*: csize_t = high(typedesc[csize_t]) 21 | 22 | # Constructor 23 | proc initCppBasicString*[T](): CppBasicString[T] {.constructor, importcpp: "std::basic_string<'*0>()".} 24 | proc initCppBasicString*[T]( 25 | str: CppBasicString[T] 26 | ): CppBasicString[T] {.constructor, importcpp: "std::basic_string<'*0>(@)".} 27 | 28 | proc initCppBasicString*[T]( 29 | str: CppBasicString[T], pos: csize_t 30 | ): CppBasicString[T] {.constructor, importcpp: "std::basic_string<'*0>(@)".} 31 | 32 | proc initCppBasicString*[T]( 33 | str: CppBasicString[T], pos, len: csize_t 34 | ): CppBasicString[T] {.constructor, importcpp: "std::basic_string<'*0>(@)".} 35 | 36 | proc initCppBasicString*[T]( 37 | s: ptr UncheckedArray[T] 38 | ): CppBasicString[T] {.constructor, importcpp: "std::basic_string<'*0>(@)".} 39 | 40 | proc initCppBasicString*[T]( 41 | s: ptr UncheckedArray[T], n: csize_t 42 | ): CppBasicString[T] {.constructor, importcpp: "std::basic_string<'*0>(@)".} 43 | 44 | proc initCppBasicString*[T]( 45 | first, last: CppBasicStringConstIterator 46 | ): CppBasicString[T] {.constructor, importcpp: "std::basic_string<'*0>(@)".} 47 | 48 | # Iterators 49 | proc begin*[T](x: CppBasicString[T]): CppBasicStringIterator[T] {.importcpp: "begin".} 50 | proc `end`*[T](x: CppBasicString[T]): CppBasicStringIterator[T] {.importcpp: "end".} 51 | 52 | proc rBegin*[T](x: CppBasicString[T]): CppBasicStringIterator[T] {.importcpp: "rbegin".} 53 | proc rEnd*[T](x: CppBasicString[T]): CppBasicStringIterator[T] {.importcpp: "rend".} 54 | 55 | proc cBegin*[T](x: CppBasicString[T]): CppBasicStringConstIterator[T] {.importcpp: "cbegin".} 56 | proc cEnd*[T](x: CppBasicString[T]): CppBasicStringConstIterator[T] {.importcpp: "cend".} 57 | 58 | proc crBegin*[T](x: CppBasicString[T]): CppBasicStringConstIterator[T] {.importcpp: "crbegin".} 59 | proc crEnd*[T](x: CppBasicString[T]): CppBasicStringConstIterator[T] {.importcpp: "crend".} 60 | 61 | # Capacity 62 | proc size*[T](self: CppBasicString[T]): csize_t {.importcpp: "size".} 63 | proc length*[T](s: CppBasicString[T]): csize_t {.importcpp: "length".} 64 | proc maxSize*[T](self: CppBasicString[T]): csize_t {.importcpp: "max_size".} 65 | proc resize*[T](self: CppBasicString[T], n: csize_t) {.importcpp: "resize".} 66 | proc capacity*[T](self: CppBasicString[T]): csize_t {.importcpp: "capacity".} 67 | proc reserve*[T](self: var CppBasicString[T], n: csize_t) {.importcpp: "reserve".} 68 | proc clear*[T](self: var CppBasicString[T]) {.importcpp: "clear".} 69 | proc empty*[T](self: CppBasicString[T]): bool {.importcpp: "empty".} 70 | proc shrinkToFit*[T](self: var CppBasicString[T]) {.importcpp: "shrink_to_fit".} 71 | 72 | # Element access 73 | proc at*[T](self: var CppBasicString[T], n: csize_t): var T {.importcpp: "at".} 74 | proc at*[T](self: CppBasicString[T], n: csize_t): T {.importcpp: "at".} 75 | 76 | proc front*[T](self: CppBasicString[T]): T {.importcpp: "front".} 77 | proc front*[T](self: var CppBasicString[T]): var T {.importcpp: "front".} 78 | 79 | proc back*[T](self: CppBasicString[T]): T {.importcpp: "back".} 80 | proc back*[T](self: var CppBasicString[T]): var T {.importcpp: "back".} 81 | 82 | # Internal utility functions 83 | proc unsafeIndex[T](self: var CppBasicString[T], i: csize_t): var T {.importcpp: "#[#]".} 84 | proc unsafeIndex[T](self: CppBasicString[T], i: csize_t): lent T {.importcpp: "#[#]".} 85 | 86 | # Modifiers 87 | proc `+=`*[T](self: var CppBasicString[T], str: CppBasicString[T]) {.importcpp: "# += #".} 88 | proc `+=`*[T](self: var CppBasicString[T], str: ptr UncheckedArray[T]) {.importcpp: "# += #".} 89 | proc `+=`*[T](self: var CppBasicString[T], str: T) {.importcpp: "# += #".} 90 | 91 | proc append*[T](self: var CppBasicString[T], str: CppBasicString[T]) {.importcpp: "append".} 92 | proc append*[T](self: var CppBasicString[T], str: CppBasicString[T], subpos, sublen: csize_t) {.importcpp: "append".} 93 | proc append*[T](self: var CppBasicString[T], str: ptr UncheckedArray[T]) {.importcpp: "append".} 94 | proc append*[T](self: var CppBasicString[T], str: ptr UncheckedArray[T], n: csize_t) {.importcpp: "append".} 95 | proc append*[T](self: var CppBasicString[T], n: csize_t, str: T) {.importcpp: "append".} 96 | proc append*[T](self: var CppBasicString[T], first, last: CppBasicStringConstIterator[T]) {.importcpp: "append".} 97 | 98 | proc pushBack*[T](self: var CppBasicString[T], x: T) {.importcpp: "push_back".} 99 | 100 | proc assign*[T](self: var CppBasicString[T], str: CppBasicString[T]) {.importcpp: "assign".} 101 | proc assign*[T](self: var CppBasicString[T], str: CppBasicString[T], subpos, sublen: csize_t) {.importcpp: "assign".} 102 | proc assign*[T](self: var CppBasicString[T], str: ptr UncheckedArray[T]) {.importcpp: "assign".} 103 | proc assign*[T](self: var CppBasicString[T], str: ptr UncheckedArray[T], n: csize_t) {.importcpp: "assign".} 104 | proc assign*[T](self: var CppBasicString[T], n: csize_t, c: T) {.importcpp: "assign".} 105 | proc assign*[T](self: var CppBasicString[T], first, last: CppBasicStringConstIterator[T]) {.importcpp: "assign".} 106 | 107 | proc insert*[T](self: var CppBasicString[T], pos: csize_t, str: CppBasicString[T]) {.importcpp: "insert".} 108 | proc insert*[T]( 109 | self: var CppBasicString[T], pos: csize_t, str: CppBasicString[T], subpos, sublen: csize_t 110 | ) {.importcpp: "insert".} 111 | 112 | proc insert*[T](self: var CppBasicString[T], pos: csize_t, s: ptr UncheckedArray[T]) {.importcpp: "insert".} 113 | proc insert*[T](self: var CppBasicString[T], pos: csize_t, s: ptr UncheckedArray[T], n: csize_t) {.importcpp: "insert".} 114 | proc insert*[T](self: var CppBasicString[T], p, n: csize_t, c: T) {.importcpp: "insert".} 115 | proc insert*[T]( 116 | self: var CppBasicString[T], p: CppBasicStringConstIterator[T], n: csize_t, c: T 117 | ) {.importcpp: "insert".} 118 | 119 | proc insert*[T](self: var CppBasicString[T], p: CppBasicStringConstIterator[T], c: T) {.importcpp: "insert".} 120 | proc insert*[T]( 121 | self: var CppBasicString[T], p: CppBasicStringIterator[T], first, last: CppBasicStringConstIterator[T] 122 | ) {.importcpp: "insert".} 123 | 124 | proc erase*[T](self: var CppBasicString[T]) {.importcpp: "erase".} 125 | proc erase*[T](self: var CppBasicString[T], pos: csize_t, l: csize_t = std_npos) {.importcpp: "erase".} 126 | proc erase*[T](self: var CppBasicString[T], pos: CppBasicStringIterator[T]) {.importcpp: "erase".} 127 | proc erase*[T](self: var CppBasicString[T], first, last: CppBasicStringIterator[T]) {.importcpp: "erase".} 128 | 129 | proc replace*[T](self: var CppBasicString[T], pos, l: csize_t, str: CppBasicString[T]) {.importcpp: "replace".} 130 | proc replace*[T]( 131 | self: var CppBasicString[T], i1, i2: CppBasicStringConstIterator[T], str: CppBasicString[T] 132 | ) {.importcpp: "replace".} 133 | 134 | proc replace*[T]( 135 | self: var CppBasicString[T], pos, l: csize_t, str: CppBasicString[T], subpos, subl: csize_t 136 | ) {.importcpp: "replace".} 137 | 138 | proc replace*[T](self: var CppBasicString[T], pos, l: csize_t, s: ptr UncheckedArray[T]) {.importcpp: "replace".} 139 | proc replace*[T]( 140 | self: var CppBasicString[T], i1, i2: CppBasicStringConstIterator[T], s: ptr UncheckedArray[T] 141 | ) {.importcpp: "replace".} 142 | 143 | proc replace*[T]( 144 | self: var CppBasicString[T], pos, l: csize_t, s: ptr UncheckedArray[T], n: csize_t 145 | ) {.importcpp: "replace".} 146 | 147 | proc replace*[T]( 148 | self: var CppBasicString[T], i1, i2: CppBasicStringConstIterator[T], s: ptr UncheckedArray[T], n: csize_t 149 | ) {.importcpp: "replace".} 150 | 151 | proc replace*[T](self: var CppBasicString[T], pos, l: csize_t, n: csize_t, c: T) {.importcpp: "replace".} 152 | proc replace*[T]( 153 | self: var CppBasicString[T], i1, i2: CppBasicStringConstIterator[T], n: csize_t, c: T 154 | ) {.importcpp: "replace".} 155 | 156 | proc replace*[T]( 157 | self: var CppBasicString[T], i1, i2: CppBasicStringConstIterator[T], first, last: CppBasicStringConstIterator[T] 158 | ) {.importcpp: "replace".} 159 | 160 | proc swap*[T](self: var CppBasicString[T], x: var CppBasicString[T]) {.importcpp: "swap".} 161 | 162 | proc popBack*[T](self: var CppBasicString[T]) {.importcpp: "pop_back".} 163 | 164 | # CppBasicString[T] operations 165 | # Avoid const T* vs T* issues 166 | proc cStr*[T](self: CppBasicString[T]): ptr UncheckedArray[T] {.importcpp: "const_cast<'0'*>(#.c_str())".} 167 | func data*[T](self: CppBasicString[T]): ptr T {.importcpp: "const_cast<'0'*>(#.data())".} 168 | 169 | proc copy*[T](self: CppBasicString[T], s: ptr T, l: csize_t, pos: csize_t = 0): csize_t {.importcpp: "copy".} 170 | 171 | proc find*[T](self, str: CppBasicString[T], pos: csize_t = 0): csize_t {.importcpp: "find".} 172 | proc find*[T](self, str: CppBasicString[T], pos, n: csize_t): csize_t {.importcpp: "find".} 173 | proc find*[T](self: CppBasicString[T], s: ptr UncheckedArray[T], pos: csize_t = 0): csize_t {.importcpp: "find".} 174 | proc find*[T](self: CppBasicString[T], s: ptr UncheckedArray[T], pos, n: csize_t): csize_t {.importcpp: "find".} 175 | proc find*[T](self: CppBasicString[T], c: T, pos: csize_t = 0): csize_t {.importcpp: "find".} 176 | 177 | proc rfind*[T](self, str: CppBasicString[T], pos: csize_t = std_npos): csize_t {.importcpp: "rfind".} 178 | proc rfind*[T](self: CppBasicString[T], s: CppBasicString[T], pos, n: csize_t): csize_t {.importcpp: "rfind".} 179 | proc rfind*[T]( 180 | self: CppBasicString[T], s: ptr UncheckedArray[T], pos: csize_t = std_npos 181 | ): csize_t {.importcpp: "rfind".} 182 | 183 | proc rfind*[T](self: CppBasicString[T], s: ptr UncheckedArray[T], pos, n: csize_t): csize_t {.importcpp: "rfind".} 184 | proc rfind*[T](self: CppBasicString[T], c: T, pos: csize_t = std_npos): csize_t {.importcpp: "rfind".} 185 | 186 | proc findFirstOf*[T](self, str: CppBasicString[T], pos: csize_t = 0): csize_t {.importcpp: "find_first_of".} 187 | proc findFirstOf*[T](self, str: CppBasicString[T], pos, n: csize_t): csize_t {.importcpp: "find_first_of".} 188 | proc findFirstOf*[T]( 189 | self: CppBasicString[T], s: ptr UncheckedArray[T], pos: csize_t = 0 190 | ): csize_t {.importcpp: "find_first_of".} 191 | 192 | proc findFirstOf*[T]( 193 | self: CppBasicString[T], s: ptr UncheckedArray[T], pos, n: csize_t 194 | ): csize_t {.importcpp: "find_first_of".} 195 | 196 | proc findFirstOf*[T](self: CppBasicString[T], c: T, pos: csize_t = 0): csize_t {.importcpp: "find_first_of".} 197 | 198 | proc findLastOf*[T](self, str: CppBasicString[T], pos: csize_t = std_npos): csize_t {.importcpp: "find_last_of".} 199 | proc findLastOf*[T]( 200 | self: CppBasicString[T], s: CppBasicString[T], pos, n: csize_t 201 | ): csize_t {.importcpp: "find_last_of".} 202 | 203 | proc findLastOf*[T]( 204 | self: CppBasicString[T], s: ptr UncheckedArray[T], pos: csize_t = std_npos 205 | ): csize_t {.importcpp: "find_last_of".} 206 | 207 | proc findLastOf*[T]( 208 | self: CppBasicString[T], s: ptr UncheckedArray[T], pos, n: csize_t 209 | ): csize_t {.importcpp: "find_last_of".} 210 | 211 | proc findLastOf*[T](self: CppBasicString[T], c: T, pos: csize_t = std_npos): csize_t {.importcpp: "find_last_of".} 212 | 213 | proc findFirstNotOf*[T](self, str: CppBasicString[T], pos: csize_t = 0): csize_t {.importcpp: "find_first_not_of".} 214 | proc findFirstNotOf*[T](self, str: CppBasicString[T], pos, n: csize_t): csize_t {.importcpp: "find_first_not_of".} 215 | proc findFirstNotOf*[T]( 216 | self: CppBasicString[T], s: ptr UncheckedArray[T], pos: csize_t = 0 217 | ): csize_t {.importcpp: "find_first_not_of".} 218 | 219 | proc findFirstNotOf*[T]( 220 | self: CppBasicString[T], s: ptr UncheckedArray[T], pos, n: csize_t 221 | ): csize_t {.importcpp: "find_first_not_of".} 222 | 223 | proc findFirstNotOf*[T](self: CppBasicString[T], c: T, pos: csize_t = 0): csize_t {.importcpp: "find_first_not_of".} 224 | 225 | proc findLastNotOf*[T](self, str: CppBasicString[T], pos: csize_t = std_npos): csize_t {.importcpp: "find_last_not_of".} 226 | proc findLastNotOf*[T](self, str: CppBasicString[T], pos, n: csize_t): csize_t {.importcpp: "find_last_not_of".} 227 | proc findLastNotOf*[T]( 228 | self: CppBasicString[T], s: ptr UncheckedArray[T], pos: csize_t = std_npos 229 | ): csize_t {.importcpp: "find_last_not_of".} 230 | 231 | proc findLastNotOf*[T]( 232 | self: CppBasicString[T], s: ptr UncheckedArray[T], pos, n: csize_t 233 | ): csize_t {.importcpp: "find_last_not_of".} 234 | 235 | proc findLastNotOf*[T]( 236 | self: CppBasicString[T], c: T, pos: csize_t = std_npos 237 | ): csize_t {.importcpp: "find_last_not_of".} 238 | 239 | proc substr*[T]( 240 | self: CppBasicString[T], pos: csize_t = 0, l: csize_t = std_npos 241 | ): CppBasicString[T] {.importcpp: "substr".} 242 | 243 | proc compare*[T](self, str: CppBasicString[T]): cint {.importcpp: "compare".} 244 | proc compare*[T](self: CppBasicString[T], pos, l: csize_t, str: CppBasicString[T]): cint {.importcpp: "compare".} 245 | proc compare*[T]( 246 | self: CppBasicString[T], pos, l: csize_t, str: CppBasicString[T], subpos, subl: csize_t 247 | ): cint {.importcpp: "compare".} 248 | 249 | proc compare*[T](self: CppBasicString[T], s: ptr UncheckedArray[T]): cint {.importcpp: "compare".} 250 | proc compare*[T](self: CppBasicString[T], pos, l: csize_t, str: ptr UncheckedArray[T]): cint {.importcpp: "compare".} 251 | proc compare*[T]( 252 | self: CppBasicString[T], pos, l: csize_t, str: ptr UncheckedArray[T], n: csize_t 253 | ): cint {.importcpp: "compare".} 254 | 255 | proc compare*[T]( 256 | self: CppBasicString[T], pos, l: csize_t, str: ptr UncheckedArray[T], subpos, subl: csize_t 257 | ): cint {.importcpp: "compare".} 258 | 259 | # Non-member function overloads 260 | 261 | proc `+`*[T](a: CppBasicString[T], b: T): CppBasicString[T] {.importcpp: "# + ('2)(#)".} 262 | proc `+`*[T](a: T, b: CppBasicString[T]): CppBasicString[T] {.importcpp: "('1)(#) + #".} 263 | proc `+`*[T](a: CppBasicString[T], b: CppBasicString[T]): CppBasicString[T] {.importcpp: "(# + #)".} 264 | 265 | proc `==`*[T](a: CppBasicString[T], b: CppBasicString[T]): bool {.importcpp: "(# == #)".} 266 | proc `!=`*[T](a: CppBasicString[T], b: CppBasicString[T]): bool {.importcpp: "(# != #)".} 267 | proc `<`*[T](a: CppBasicString[T], b: CppBasicString[T]): bool {.importcpp: "(# < #)".} 268 | proc `<=`*[T](a: CppBasicString[T], b: CppBasicString[T]): bool {.importcpp: "(# <= #)".} 269 | proc `>`*[T](a: CppBasicString[T], b: CppBasicString[T]): bool {.importcpp: "(# > #)".} 270 | proc `>=`*[T](a: CppBasicString[T], b: CppBasicString[T]): bool {.importcpp: "(# >= #)".} 271 | 272 | # Converter: CppBasicStringIterator[T] -> CppBasicStringConstIterator[T] 273 | converter CppBasicStringIteratorToBasicStringConstIterator*[T]( 274 | s: CppBasicStringIterator[T] 275 | ): CppBasicStringConstIterator[T] {.importcpp: "#".} 276 | 277 | {.pop.} 278 | 279 | {.push inline.} 280 | 281 | proc `+`*[T](a: CppBasicString[T], b: ptr UncheckedArray[T]): CppBasicString[T] = 282 | result = (a + initCppBasicString(b)) 283 | 284 | proc `+`*[T](a: ptr UncheckedArray[T], b: CppBasicString[T]): CppBasicString[T] = 285 | let a = initCppBasicString(a) 286 | result = (a + b) 287 | 288 | proc `==`*[T](a: CppBasicString[T], b: ptr UncheckedArray[T]): bool = 289 | let b = initCppBasicString(b) 290 | result = (a == b) 291 | 292 | proc `==`*[T](a: ptr UncheckedArray[T], b: CppBasicString[T]): bool = 293 | let a = initCppBasicString(a) 294 | result = (a == b) 295 | 296 | proc `!=`*[T](a: CppBasicString[T], b: ptr UncheckedArray[T]): bool = 297 | result = (a != initCppBasicString(b)) 298 | 299 | proc `!=`*[T](a: ptr UncheckedArray[T], b: CppBasicString[T]): bool = 300 | result = (initCppBasicString(a) != b) 301 | 302 | proc `<`*[T](a: CppBasicString[T], b: ptr UncheckedArray[T]): bool = 303 | result = (a < initCppBasicString(b)) 304 | 305 | proc `<`*[T](a: ptr UncheckedArray[T], b: CppBasicString[T]): bool = 306 | result = (initCppBasicString(a) < b) 307 | 308 | proc `<=`*[T](a: CppBasicString[T], b: ptr UncheckedArray[T]): bool = 309 | result = (a <= initCppBasicString(b)) 310 | 311 | proc `<=`*[T](a: ptr UncheckedArray[T], b: CppBasicString[T]): bool = 312 | result = (initCppBasicString(a) <= b) 313 | 314 | proc `>`*[T](a: CppBasicString[T], b: ptr UncheckedArray[T]): bool = 315 | result = (a > initCppBasicString(b)) 316 | 317 | proc `>`*[T](a: ptr UncheckedArray[T], b: CppBasicString[T]): bool = 318 | result = (initCppBasicString(a) > b) 319 | 320 | proc `>=`*[T](a: CppBasicString[T], b: ptr UncheckedArray[T]): bool = 321 | result = (a >= initCppBasicString(b)) 322 | 323 | proc `>=`*[T](a: ptr UncheckedArray[T], b: CppBasicString[T]): bool = 324 | result = (initCppBasicString(a) >= b) 325 | 326 | proc checkIndex[T](self: CppBasicString[T], i: csize_t) = 327 | if i > self.size: 328 | raise newException(IndexDefect, &"index out of bounds: (i:{i}) <= (n:{self.size})") 329 | 330 | proc `[]`*[T](self: CppBasicString[T], idx: Natural): T = 331 | let i = csize_t(idx) 332 | # If you add a mechanism exception to operator `[]` it simply becomes at so might as well use at directly 333 | when compileOption("boundChecks"): 334 | self.checkIndex(i) 335 | (unsafeAddr self.unsafeIndex(i))[] 336 | 337 | proc `[]`*[T](self: var CppBasicString[T], idx: Natural): var T = 338 | let i = csize_t(idx) 339 | # If you add a mechanism exception to operator `[]` it simply becomes at so might as well use at directly 340 | when compileOption("boundChecks"): 341 | self.checkIndex(i) 342 | # TODO : find Nim bugs # associated 343 | # This strange syntax is to avoid a bug in the Nim c++ code generator 344 | (unsafeAddr self.unsafeIndex(i))[] 345 | 346 | proc `[]=`*[T](self: var CppBasicString[T], idx: Natural, val: T) = 347 | let i = csize_t(idx) 348 | when compileOption("boundChecks"): 349 | self.checkIndex(i) 350 | self.unsafeIndex(i) = val 351 | 352 | {.pop.} 353 | 354 | # Alias for Nim idiomatic API 355 | 356 | proc len*[T](v: CppBasicString[T]): csize_t {.inline.} = 357 | ## Alias for `size proc <#size%2CCppBasicString[T]>`_. 358 | v.size() 359 | 360 | proc add*[T](v: var CppBasicString[T], elem: T) {.inline.} = 361 | ## Alias for `pushBack proc <#pushBack%2CCppBasicString[T][T]%2CT>`_. 362 | v.pushBack(elem) 363 | 364 | proc first*[T](v: var CppBasicString[T]): var T {.inline.} = 365 | ## Alias for `front proc <#front%2CCppBasicString[T][T]>`_. 366 | v.front() 367 | 368 | proc first*[T](v: CppBasicString[T]): T {.inline.} = 369 | ## Alias for `front proc <#front%2CCppBasicString[T][T]_2>`_. 370 | v.front() 371 | 372 | proc last*[T](v: var CppBasicString[T]): var T {.inline.} = 373 | ## Alias for `back proc <#back%2CCppBasicString[T][T]>`_. 374 | v.back() 375 | 376 | proc last*[T](v: CppBasicString[T]): T {.inline.} = 377 | ## Alias for `back proc <#back%2CCppBasicString[T][T]_2>`_. 378 | v.back() 379 | 380 | # Nim Iterators 381 | iterator items*[T](v: CppBasicString[T]): T = 382 | ## Iterate over all the elements in CppBasicString[T] `v`. 383 | for idx in 0.csize_t ..< v.len(): 384 | yield v[idx] 385 | 386 | iterator pairs*[T](v: CppBasicString[T]): (csize_t, T) = 387 | ## Iterate over `(index, value)` for all the elements in CppBasicString[T] `v`. 388 | for idx in 0.csize_t ..< v.len(): 389 | yield (idx, v[idx]) 390 | 391 | iterator mitems*[T](v: var CppBasicString[T]): var T = 392 | ## Iterate over all the elements in CppBasicString[T] `v`. 393 | for idx in 0.csize_t ..< v.len(): 394 | yield v[idx] 395 | 396 | iterator mpairs*[T](v: var CppBasicString[T]): (csize_t, var T) = 397 | ## Iterate over `(index, value)` for all the elements in CppBasicString[T] `v`. 398 | for idx in 0.csize_t ..< v.len(): 399 | yield (idx, v[idx]) 400 | -------------------------------------------------------------------------------- /cppstl/std_complex.nim: -------------------------------------------------------------------------------- 1 | # std::complex 2 | # ----------------------------------------------------------------------- 3 | {.push header: "".} 4 | type CppComplex*[T: SomeFloat] {.importcpp: "std::complex".} = object 5 | 6 | func initCppComplex*[T: SomeFloat](re, im: T): CppComplex[T] {.constructor, importcpp: "std::complex<'*0>(@)".} 7 | func polar*[T: SomeFloat](r, theta: T): CppComplex[T] {.importcpp: "std::polar<'*0>(@)".} 8 | 9 | func real*[T: SomeFloat](self: CppComplex[T]): T {.importcpp: "#.real()".} 10 | func imag*[T: SomeFloat](self: CppComplex[T]): T {.importcpp: "#.imag()".} 11 | 12 | proc `+=`*[T: SomeFloat](self: var CppComplex[T], arg: CppComplex[T]) {.importcpp: "(# += #)".} 13 | proc `-=`*[T: SomeFloat](self: var CppComplex[T], arg: CppComplex[T]) {.importcpp: "(# -= #)".} 14 | proc `*=`*[T: SomeFloat](self: var CppComplex[T], arg: CppComplex[T]) {.importcpp: "(# *= #)".} 15 | proc `/=`*[T: SomeFloat](self: var CppComplex[T], arg: CppComplex[T]) {.importcpp: "(# /= #)".} 16 | 17 | proc `+`*[T: SomeFloat](a, b: CppComplex[T]): CppComplex[T] {.importcpp: "(# + #)".} 18 | proc `-`*[T: SomeFloat](a, b: CppComplex[T]): CppComplex[T] {.importcpp: "(# - #)".} 19 | proc `*`*[T: SomeFloat](a, b: CppComplex[T]): CppComplex[T] {.importcpp: "(# * #)".} 20 | proc `/`*[T: SomeFloat](a, b: CppComplex[T]): CppComplex[T] {.importcpp: "(# / #)".} 21 | 22 | proc `==`*[T: SomeFloat](a, b: CppComplex[T]): bool {.importcpp: "(# == #)".} 23 | proc `!=`*[T: SomeFloat](a, b: CppComplex[T]): bool {.importcpp: "(# != #)".} 24 | 25 | func abs*[T: SomeFloat](self: CppComplex[T]): T {.importcpp: "std::abs(@)".} 26 | func norm*[T: SomeFloat](self: CppComplex[T]): T {.importcpp: "std::norm(@)".} 27 | func arg*[T: SomeFloat](self: CppComplex[T]): T {.importcpp: "std::arg(@)".} 28 | func conj*[T: SomeFloat](self: CppComplex[T]): CppComplex[T] {.importcpp: "std::conj(@)".} 29 | 30 | {.pop.} 31 | 32 | import complex 33 | proc toComplex*[T](c: CppComplex[T]): Complex[T] = 34 | result.re = c.real() 35 | result.im = c.imag() 36 | 37 | proc toCppComplex*[T](c: Complex[T]): CppComplex[T] = 38 | result = initCppComplex(c.re, c.im) 39 | 40 | proc `$`*[T](c: CppComplex[T]): string = 41 | result.add "(" 42 | result.add $(c.real()) 43 | result.add ", " 44 | result.add $(c.imag()) 45 | result.add ")" 46 | -------------------------------------------------------------------------------- /cppstl/std_exception.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Nouredine Hussain 2 | 3 | # This code is licensed under MIT license (see LICENSE.txt for details) 4 | 5 | when (NimMajor, NimMinor, NimPatch) < (1, 4, 0): 6 | # IndexDefect was introduced in 1.4.0 7 | type IndexDefect* = IndexError 8 | 9 | type OutOfRangeException* {.importcpp: "std::out_of_range", header: "stdexcept".} = object of ValueError 10 | -------------------------------------------------------------------------------- /cppstl/std_pair.nim: -------------------------------------------------------------------------------- 1 | # This code is licensed under MIT license (see LICENSE.txt for details) 2 | import std/strformat 3 | 4 | when not defined(cpp): 5 | {.error: "C++ backend required to use STL wrapper".} 6 | 7 | {.push header: "".} 8 | # https://cplusplus.com/reference/utility/pair/ 9 | 10 | type CppPair*[F, S] {.importcpp: "std::pair <'0,'1>".} = object 11 | 12 | # procs 13 | proc first*[T1, T2](this: CppPair[T1, T2]): T1 {.importcpp: "#.first".} 14 | proc first*[T1, T2](this: var CppPair[T1, T2]): var T1 {.importcpp: "#.first".} 15 | proc `first=`*[T1, T2](this: var CppPair[T1, T2], val: T1) {.importcpp: "#.first = #".} 16 | proc second*[T1, T2](this: CppPair[T1, T2]): T2 {.importcpp: "#.second".} 17 | proc second*[T1, T2](this: var CppPair[T1, T2]): var T2 {.importcpp: "#.second".} 18 | proc `second=`*[T1, T2](this: var CppPair[T1, T2], val: T2) {.importcpp: "#.second = #".} 19 | 20 | # Constructor 21 | proc initCppPair*[T1, T2](): CppPair[T1, T2] {.constructor, importcpp: "'0(@)".} 22 | proc initCppPair*[T1, T2](x: T1, y: T2): CppPair[T1, T2] {.constructor, importcpp: "'0(@)".} 23 | proc initCppPair*[T1, T2](p: CppPair[T1, T2]): CppPair[T1, T2] {.constructor, importcpp: "'0(@)".} 24 | 25 | # Member functions 26 | proc swap*[T1, T2](this, other: var CppPair[T1, T2]) {.importcpp: "#.swap(@)".} 27 | 28 | # Non-member functions 29 | # https://en.cppreference.com/w/cpp/utility/pair/make_pair 30 | proc makePair*[F, S](a: F, b: S): CppPair[F, S] {.importcpp: "std::make_pair(@)".} 31 | 32 | proc getImpl[T1, T2](p: CppPair[T1, T2], T: typedesc[T1 or T2]): T {.importcpp: "std::get<'0>(@)".} 33 | proc getImpl[T1, T2](n: int, p: CppPair[T1, T2], T: typedesc[T1 or T2]): T {.importcpp: "std::get<#>(@)".} 34 | 35 | # proc `==`*[T1, T2](lhs, rhs: CppPair[T1, T2]): bool {.importcpp: "(# == #)".} 36 | # proc `!=`*[T1, T2](lhs, rhs: CppPair[T1, T2]): bool {.importcpp: "(# != #)".} 37 | # proc `<=`*[T1, T2](lhs, rhs: CppPair[T1, T2]): bool {.importcpp: "(# <= #)".} 38 | # proc `>=`*[T1, T2](lhs, rhs: CppPair[T1, T2]): bool {.importcpp: "(# >= #)".} 39 | # proc `<`*[T1, T2](lhs, rhs: CppPair[T1, T2]): bool {.importcpp: "(# < #)".} 40 | # proc `>`*[T1, T2](lhs, rhs: CppPair[T1, T2]): bool {.importcpp: "(# > #)".} 41 | 42 | {.pop.} # header 43 | 44 | # Implement comparaison operator manually because for some reason NimStringV2 does not have operator==() definied in C++ 45 | proc `==`*[T1, T2](lhs, rhs: CppPair[T1, T2]): bool = 46 | if (lhs.first() == rhs.first()) and (lhs.second() == rhs.second()): 47 | result = true 48 | else: 49 | result = false 50 | 51 | proc `!=`*[T1, T2](lhs, rhs: CppPair[T1, T2]): bool = 52 | if lhs == rhs: 53 | result = false 54 | else: 55 | result = true 56 | 57 | proc `<`*[T1, T2](lhs, rhs: CppPair[T1, T2]): bool = 58 | ## If lhs.first`*[T1, T2](lhs, rhs: CppPair[T1, T2]): bool = 83 | ## 5) rhs < lhs 84 | return rhs < lhs 85 | 86 | proc `>=`*[T1, T2](lhs, rhs: CppPair[T1, T2]): bool = 87 | ## 6) !(lhs < rhs) 88 | if lhs < rhs: 89 | result = false 90 | else: 91 | result = true 92 | 93 | #----------- 94 | # Some sugar 95 | #----------- 96 | 97 | proc get*[T1, T2](T: typedesc, p: CppPair[T1, T2]): auto = 98 | when T1 is T2: 99 | {.error: "ambiguous call to `get` with a pair whose two elements are of the same type".} 100 | getImpl(p, T) 101 | 102 | proc get*[T1, T2](n: static int, p: CppPair[T1, T2]): auto = 103 | when n == 0: 104 | type ResultType = T1 105 | elif n == 1: 106 | type ResultType = T2 107 | else: 108 | {.error: "index in pair must be 0 or 1".} 109 | getImpl(n, p, ResultType) 110 | 111 | proc `$`*[F, S](val: CppPair[F, S]): string = 112 | # provides stdout for CppPair 113 | &"CppPair(first: {val.first}, second: {val.second})" 114 | 115 | proc toTuple*[F, S](val: CppPair[F, S]): tuple[first: F, second: S] = 116 | ## converts a CppPair into a Nim's tuple 117 | (val.first, val.second) 118 | 119 | proc makePair*[F, S](t: tuple[first: F, second: S]): CppPair[F, S] = 120 | result = initCppPair[F, S]() 121 | result.first = t.first 122 | result.second = t.second 123 | -------------------------------------------------------------------------------- /cppstl/std_smartptrs.nim: -------------------------------------------------------------------------------- 1 | import std/macros 2 | 3 | when not defined(cpp): 4 | {.error: "C++ backend required to use STL wrapper".} 5 | # std::shared_ptr 6 | # ----------------------------------------------------------------------- 7 | {.push header: "".} 8 | 9 | type CppSharedPtr*[T] {.importcpp: "std::shared_ptr", bycopy.} = object 10 | 11 | proc newCppSharedPtr*[T](p: ptr T): CppSharedPtr[T] {.constructor, importcpp: "std::shared_ptr<'*0>(#)".} 12 | 13 | func makeShared*(T: typedesc): CppSharedPtr[T] {.importcpp: "std::make_shared<'*0>()".} 14 | 15 | func makeShared*[T](p: CppSharedPtr[T]): CppSharedPtr[T] {.importcpp: "std::make_shared<'*0>(#)".} 16 | 17 | proc `=copy`*[T](p: var CppSharedPtr[T], o: CppSharedPtr[T]) {.noInit, importcpp: "# = #".} 18 | proc `=sink`*[T](dst: var CppSharedPtr[T], src: CppSharedPtr[T]) {.importcpp: "# = std::move(#)".} 19 | 20 | # std::unique_ptr 21 | # ----------------------------------------------------------------------- 22 | type CppUniquePtr*[T] {.importcpp: "std::unique_ptr", header: "", bycopy.} = object 23 | 24 | func makeUnique*(T: typedesc): CppUniquePtr[T] {.importcpp: "std::make_unique<'*0>()".} 25 | 26 | proc `=copy`*[T](dst: var CppUniquePtr[T], src: CppUniquePtr[T]) {.error: "A unique ptr cannot be copied".} 27 | proc `=sink`*[T](dst: var CppUniquePtr[T], src: CppUniquePtr[T]) {.importcpp: "# = std::move(#)".} 28 | 29 | {.pop.} 30 | 31 | # Let C++ destructor do their things 32 | proc `=destroy`[T](dst: var CppUniquePtr[T]) = 33 | discard 34 | 35 | proc `=destroy`[T](dst: var CppSharedPtr[T]) = 36 | discard 37 | 38 | # Seamless pointer access 39 | # ----------------------------------------------------------------------- 40 | {.experimental: "dotOperators".} 41 | 42 | # This returns var T but with strictFunc it shouldn't 43 | func deref*[T](p: CppUniquePtr[T] or CppSharedPtr[T]): var T {.noInit, importcpp: "(* #)", header: "".} 44 | 45 | func get*[T](p: CppUniquePtr[T] or CppSharedPtr[T]): ptr T {.noInit, importcpp: "(#.get())", header: "".} 46 | 47 | proc `$`*[T](p: CppUniquePtr[T]): string = 48 | result = "CppUnique " & repr(get(p)) 49 | 50 | func `$`*[T](p: CppSharedPtr[T]): string = 51 | result = "CppShared " & repr(get(p)) 52 | 53 | macro `.()`*[T](p: CppUniquePtr[T] or CppSharedPtr[T], fieldOrFunc: untyped, args: varargs[untyped]): untyped = 54 | result = nnkCall.newTree(nnkDotExpr.newTree(newCall(bindSym"deref", p), fieldOrFunc)) 55 | copyChildrenTo(args, result) 56 | # echo result.repr 57 | 58 | macro `.`*[T](p: CppUniquePtr[T] or CppSharedPtr[T], fieldOrFunc: untyped): untyped = 59 | result = nnkDotExpr.newTree(newCall(bindSym"deref", p), fieldOrFunc) 60 | # echo result.repr 61 | 62 | macro `.=`*[T](p: CppUniquePtr[T] or CppSharedPtr[T], fieldOrFunc: untyped, args: untyped): untyped = 63 | result = newAssignment(nnkDotExpr.newTree(newCall(bindSym"deref", p), fieldOrFunc), args) 64 | # echo result.repr 65 | -------------------------------------------------------------------------------- /cppstl/std_string.nim: -------------------------------------------------------------------------------- 1 | # This code is licensed under MIT license (see LICENSE.txt for details) 2 | 3 | ## This module contains types and procs specific to ``std::string`` (i.e. 4 | ## ``std::basic_string``), including constructors and overloads that 5 | ## take Nim ``string``/``cstring``. 6 | 7 | import ./std_basicstring 8 | export std_basicstring 9 | 10 | type 11 | CppString* = CppBasicString[cchar] 12 | CppStrIterator* = CppBasicStringIterator[cchar] 13 | CppStrConstIterator* = CppBasicStringConstIterator[cchar] 14 | 15 | {.push header: "".} 16 | 17 | #Constructor 18 | proc initCppString*(): CppString {.constructor, importcpp: "std::string()".} 19 | proc initCppString*(str: CppString): CppString {.constructor, importcpp: "std::string(@)".} 20 | proc initCppString*(str: CppString, pos: csize_t): CppString {.constructor, importcpp: "std::string(@)".} 21 | proc initCppString*(str: CppString, pos, len: csize_t): CppString {.constructor, importcpp: "std::string(@)".} 22 | proc initCppString*(s: cstring): CppString {.constructor, importcpp: "std::string(@)".} 23 | proc initCppString*(s: cstring, n: csize_t): CppString {.constructor, importcpp: "std::string(@)".} 24 | proc initCppString*(first, last: CppStrConstIterator): CppString {.constructor, importcpp: "std::string(@)".} 25 | 26 | # Modifiers 27 | proc `+=`*(self: var CppString, str: cstring) {.importcpp: "(# += #)".} 28 | 29 | proc append*(self: var CppString, str: cstring) {.importcpp: "append".} 30 | proc append*(self: var CppString, str: cstring, n: csize_t) {.importcpp: "append".} 31 | 32 | proc assign*(self: var CppString, str: cstring) {.importcpp: "assign".} 33 | proc assign*(self: var CppString, str: cstring, n: csize_t) {.importcpp: "assign".} 34 | 35 | proc insert*(self: var CppString, pos: csize_t, s: cstring) {.importcpp: "insert".} 36 | proc insert*(self: var CppString, pos: csize_t, s: cstring, n: csize_t) {.importcpp: "insert".} 37 | 38 | proc replace*(self: var CppString, pos, l: csize_t, s: cstring) {.importcpp: "replace".} 39 | proc replace*(self: var CppString, i1, i2: CppStrConstIterator, s: cstring) {.importcpp: "replace".} 40 | proc replace*(self: var CppString, pos, l: csize_t, s: cstring, n: csize_t) {.importcpp: "replace".} 41 | proc replace*(self: var CppString, i1, i2: CppStrConstIterator, s: cstring, n: csize_t) {.importcpp: "replace".} 42 | 43 | # CppString operations 44 | # Avoid const char* vs char* issues 45 | proc cStr*(self: CppString): cstring {.importcpp: "const_cast(#.c_str())".} 46 | 47 | proc find*(self: CppString, s: cstring, pos: csize_t = 0): csize_t {.importcpp: "find".} 48 | proc find*(self: CppString, s: cstring, pos, n: csize_t): csize_t {.importcpp: "find".} 49 | 50 | proc rfind*(self: CppString, s: cstring, pos: csize_t = std_npos): csize_t {.importcpp: "rfind".} 51 | proc rfind*(self: CppString, s: cstring, pos, n: csize_t): csize_t {.importcpp: "rfind".} 52 | 53 | proc findFirstOf*(self: CppString, s: cstring, pos: csize_t = 0): csize_t {.importcpp: "find_first_of".} 54 | proc findFirstOf*(self: CppString, s: cstring, pos, n: csize_t): csize_t {.importcpp: "find_first_of".} 55 | 56 | proc findLastOf*(self: CppString, s: cstring, pos: csize_t = std_npos): csize_t {.importcpp: "find_last_of".} 57 | proc findLastOf*(self: CppString, s: cstring, pos, n: csize_t): csize_t {.importcpp: "find_last_of".} 58 | 59 | proc findFirstNotOf*(self: CppString, s: cstring, pos: csize_t = 0): csize_t {.importcpp: "find_first_not_of".} 60 | proc findFirstNotOf*(self: CppString, s: cstring, pos, n: csize_t): csize_t {.importcpp: "find_first_not_of".} 61 | 62 | proc findLastNotOf*(self: CppString, s: cstring, pos: csize_t = std_npos): csize_t {.importcpp: "find_last_not_of".} 63 | proc findLastNotOf*(self: CppString, s: cstring, pos, n: csize_t): csize_t {.importcpp: "find_last_not_of".} 64 | 65 | proc compare*(self: CppString, s: cstring): cint {.importcpp: "compare".} 66 | proc compare*(self: CppString, pos, l: csize_t, str: cstring): cint {.importcpp: "compare".} 67 | proc compare*(self: CppString, pos, l: csize_t, str: cstring, n: csize_t): cint {.importcpp: "compare".} 68 | proc compare*(self: CppString, pos, l: csize_t, str: cstring, subpos, subl: csize_t): cint {.importcpp: "compare".} 69 | 70 | # Converter: CppStrIterator -> StrConstIterator 71 | converter CppStrIteratorToStrConstIterator*(s: CppStrIterator): CppStrConstIterator {.importcpp: "#".} 72 | 73 | # Relational operators 74 | proc `==`*(a: CppString, b: CppString): bool {.importcpp: "(# == #)".} 75 | proc `!=`*(a: CppString, b: CppString): bool {.importcpp: "(# != #)".} 76 | proc `<`*(a: CppString, b: CppString): bool {.importcpp: "(# < #)".} 77 | proc `<=`*(a: CppString, b: CppString): bool {.importcpp: "(# <= #)".} 78 | proc `>`*(a: CppString, b: CppString): bool {.importcpp: "(# > #)".} 79 | proc `>=`*(a: CppString, b: CppString): bool {.importcpp: "(# >= #)".} 80 | 81 | {.pop.} 82 | 83 | {.push inline.} 84 | 85 | proc initCppString*(s: string): CppString = 86 | initCppString(s.cstring) 87 | 88 | proc `+`*(a: CppString, b: string | cstring): CppString = 89 | result = (a + initCppString(b)) 90 | 91 | proc `+`*(a: string | cstring, b: CppString): CppString = 92 | let a = initCppString(a) 93 | result = (a + b) 94 | 95 | proc `==`*(a: CppString, b: string | cstring): bool = 96 | let b = initCppString(b) 97 | result = (a == b) 98 | 99 | proc `==`*(a: string | cstring, b: CppString): bool = 100 | let a = initCppString(a) 101 | result = (a == b) 102 | 103 | proc `!=`*(a: CppString, b: string | cstring): bool = 104 | result = (a != initCppString(b)) 105 | 106 | proc `!=`*(a: string | cstring, b: CppString): bool = 107 | result = (initCppString(a) != b) 108 | 109 | proc `<`*(a: CppString, b: string | cstring): bool = 110 | result = (a < initCppString(b)) 111 | 112 | proc `<`*(a: string | cstring, b: CppString): bool = 113 | result = (initCppString(a) < b) 114 | 115 | proc `<=`*(a: CppString, b: string | cstring): bool = 116 | result = (a <= initCppString(b)) 117 | 118 | proc `<=`*(a: string | cstring, b: CppString): bool = 119 | result = (initCppString(a) <= b) 120 | 121 | proc `>`*(a: CppString, b: string | cstring): bool = 122 | result = (a > initCppString(b)) 123 | 124 | proc `>`*(a: string | cstring, b: CppString): bool = 125 | result = (initCppString(a) > b) 126 | 127 | proc `>=`*(a: CppString, b: string | cstring): bool = 128 | result = (a >= initCppString(b)) 129 | 130 | proc `>=`*(a: string | cstring, b: CppString): bool = 131 | result = (initCppString(a) >= b) 132 | 133 | {.pop.} 134 | 135 | # Alias for Nim idiomatic API 136 | 137 | proc toCppString*(s: string): CppString {.inline.} = 138 | initCppString(cstring(s), len(s).csize_t) 139 | 140 | proc toString*(s: CppString): string = 141 | $(s.cStr()) 142 | 143 | # Display CppString 144 | proc `$`*(s: CppString): string {.noinit.} = 145 | result = $(s.cStr()) 146 | -------------------------------------------------------------------------------- /cppstl/std_vector.nim: -------------------------------------------------------------------------------- 1 | # self code is licensed under MIT license (see LICENSE.txt for details) 2 | 3 | import ./private/iterators 4 | import ./std_exception 5 | export iterators 6 | export std_exception 7 | 8 | when not defined(cpp): 9 | {.error: "C++ backend required to use STL wrapper".} 10 | 11 | {.push header: "".} 12 | 13 | type 14 | CppVector*[T] {.importcpp: "std::vector".} = object 15 | # https://nim-lang.github.io/Nim/manual.html#importcpp-pragma-importcpp-for-objects 16 | CppVectorIterator*[T] {.importcpp: "std::vector<'0>::iterator".} = CppIterator[T] 17 | CppVectorConstIterator*[T] {.importcpp: "std::vector<'0>::const_iterator".} = CppConstIterator[T] 18 | 19 | # Constructors 20 | # https://nim-lang.github.io/Nim/manual.html#importcpp-pragma-importcpp-for-procs 21 | proc initCppVector*[T](): CppVector[T] {.constructor, importcpp: "std::vector<'*0>(@)".} 22 | proc initCppVector*[T](n: csize_t): CppVector[T] {.constructor, importcpp: "std::vector<'*0>(@)".} 23 | proc initCppVector*[T](n: csize_t, val: T): CppVector[T] {.constructor, importcpp: "std::vector<'*0>(@)".} 24 | proc initCppVector*[T]( 25 | first, last: CppVectorConstIterator[T] 26 | ): CppVector[T] {.constructor, importcpp: "std::vector<'*0>(@)".} 27 | 28 | # TODO Fix this one 29 | proc initCppVector*[T](x: CppVector[T]): CppVector[T] {.constructor, importcpp: "std::vector<'*0>(@)".} 30 | 31 | # Iterators 32 | proc begin*[T](v: CppVector[T]): CppVectorIterator[T] {.importcpp: "begin".} = 33 | ## Return a mutable C++ iterator pointing to the beginning position of the CppVector. 34 | ## 35 | ## https://www.cplusplus.com/reference/CppVector/CppVector/begin/ 36 | runnableExamples: 37 | var v = @[1, 2, 3].toCppVector() 38 | discard v.insert(v.begin(), 100) 39 | doAssert v.toSeq() == @[100, 1, 2, 3] 40 | 41 | proc `end`*[T](v: CppVector[T]): CppVectorIterator[T] {.importcpp: "end".} = 42 | ## Return a mutable C++ iterator pointing to *after* the end position of the CppVector. 43 | ## 44 | ## https://www.cplusplus.com/reference/CppVector/CppVector/end/ 45 | runnableExamples: 46 | var v = @[1, 2, 3].toCppVector() 47 | discard v.insert(v.`end`(), 100) 48 | doAssert v.toSeq() == @[1, 2, 3, 100] 49 | 50 | proc cBegin*[T](v: CppVector[T]): CppVectorConstIterator[T] {.importcpp: "cbegin".} = 51 | ## Return an immutable C++ iterator pointing to the beginning position of the CppVector. 52 | ## 53 | ## https://www.cplusplus.com/reference/CppVector/CppVector/begin/ 54 | runnableExamples: 55 | var v = @[1, 2, 3].toCppVector() 56 | discard v.insert(v.cBegin(), 100) 57 | doAssert v.toSeq() == @[100, 1, 2, 3] 58 | 59 | proc cEnd*[T](v: CppVector[T]): CppVectorConstIterator[T] {.importcpp: "cend".} = 60 | ## Return an immutable C++ iterator pointing to *after* the end position of the CppVector. 61 | ## 62 | ## https://www.cplusplus.com/reference/CppVector/CppVector/end/ 63 | runnableExamples: 64 | var v = @[1, 2, 3].toCppVector() 65 | discard v.insert(v.cEnd(), 100) 66 | doAssert v.toSeq() == @[1, 2, 3, 100] 67 | 68 | proc rBegin*[T](x: CppVector[T]): CppVectorIterator[T] {.importcpp: "rbegin".} 69 | proc rEnd*[T](x: CppVector[T]): CppVectorIterator[T] {.importcpp: "rend".} 70 | 71 | proc crBegin*[T](x: CppVector[T]): CppVectorConstIterator[T] {.importcpp: "crbegin".} 72 | proc crEnd*[T](x: CppVector[T]): CppVectorConstIterator[T] {.importcpp: "crend".} 73 | 74 | # Capacity 75 | proc size*(v: CppVector): csize_t {.importcpp: "size".} = 76 | ## Return the number of elements in the CppVector. 77 | ## 78 | ## This has an alias proc `len <#len%2CCppVector>`_. 79 | ## 80 | ## https://en.cppreference.com/w/cpp/container/CppVector/size 81 | runnableExamples: 82 | var v = initCppVector[int]() 83 | doAssert v.size() == 0 84 | 85 | v.add(100) 86 | v.add(200) 87 | doAssert v.len() == 2 88 | doAssert v.size() == 2 89 | 90 | proc maxSize*[T](self: CppVector[T]): csize_t {.importcpp: "max_size".} 91 | proc resize*[T](self: CppVector[T], n: csize_t) {.importcpp: "resize".} 92 | proc capacity*[T](self: CppVector[T]): csize_t {.importcpp: "capacity".} 93 | 94 | proc empty*(v: CppVector): bool {.importcpp: "empty".} = 95 | ## Check if the CppVector is empty i.e. has zero elements. 96 | ## 97 | ## https://en.cppreference.com/w/cpp/container/CppVector/empty 98 | runnableExamples: 99 | var v = initCppVector[int]() 100 | doAssert v.empty() 101 | 102 | v.add(100) 103 | doAssert not v.empty() 104 | 105 | proc reserve*[T](self: var CppVector[T], n: csize_t) {.importcpp: "reserve".} 106 | proc shrinkToFit*[T](self: var CppVector[T]) {.importcpp: "shrink_to_fit".} 107 | 108 | # Internal utility functions 109 | proc unsafeIndex[T](self: var CppVector[T], i: csize_t): var T {.importcpp: "(#[#])".} 110 | proc unsafeIndex[T](self: CppVector[T], i: csize_t): lent T {.importcpp: "(#[#])".} 111 | 112 | proc at*[T](self: var CppVector[T], n: csize_t): var T {.importcpp: "at".} 113 | proc at*[T](self: CppVector[T], n: csize_t): T {.importcpp: "at".} 114 | 115 | proc front*[T](v: var CppVector[T]): var T {.importcpp: "front".} = 116 | ## Return the reference to the first element of the CppVector. 117 | ## 118 | ## This has an alias proc `first <#first%2CCppVector[T]>`_. 119 | ## 120 | ## https://en.cppreference.com/w/cpp/container/CppVector/front 121 | runnableExamples: 122 | var v = initCppVector[int]() 123 | 124 | v.add(100) 125 | v.add(200) 126 | doAssert v.front() == 100 127 | 128 | v.front() = 300 129 | doAssert v.front() == 300 130 | 131 | proc front*[T](v: CppVector[T]): T {.importcpp: "front".} 132 | 133 | proc back*[T](v: var CppVector[T]): var T {.importcpp: "back".} = 134 | ## Return the reference to the last element of the CppVector. 135 | ## 136 | ## This has an alias proc `last <#last%2CCppVector[T]>`_. 137 | ## 138 | ## https://www.cplusplus.com/reference/CppVector/CppVector/back/ 139 | runnableExamples: 140 | var v = initCppVector[int]() 141 | 142 | v.add(100) 143 | v.add(200) 144 | doAssert v.back() == 200 145 | 146 | v.back() = 300 147 | doAssert v.back() == 300 148 | 149 | proc back*[T](v: CppVector[T]): T {.importcpp: "back".} 150 | 151 | proc data*[T](self: CppVector[T]): ptr T {.importcpp: "data".} 152 | 153 | # Modifiers 154 | proc assign*[T](v: var CppVector[T], num: csize_t, val: T) {.importcpp: "assign".} = 155 | ## Return a CppVector with `num` elements assigned to the specified value `val`. 156 | ## 157 | ## https://en.cppreference.com/w/cpp/container/CppVector/assign 158 | runnableExamples: 159 | var v: CppVector[float] 160 | 161 | v.assign(5, 1.0) 162 | doAssert v.toSeq() == @[1.0, 1.0, 1.0, 1.0, 1.0] 163 | 164 | v.assign(2, 2.3) 165 | doAssert v.toSeq() == @[2.3, 2.3] 166 | 167 | proc assign*[T](n: csize_t, val: T) {.importcpp: "assign".} 168 | proc assign*[T](first: CppVectorIterator[T], last: CppVectorIterator[T]) {.importcpp: "assign".} 169 | 170 | proc pushBack*[T](v: var CppVector[T], elem: T) {.importcpp: "push_back".} = 171 | ## Append a new element to the end of the CppVector. 172 | ## 173 | ## This has an alias proc `add <#add%2CCppVector[T]%2CT>`_. 174 | ## 175 | ## https://en.cppreference.com/w/cpp/container/CppVector/push_back 176 | runnableExamples: 177 | var v = initCppVector[int]() 178 | doAssert v.len() == 0 179 | 180 | v.pushBack(100) 181 | v.pushBack(200) 182 | doAssert v.len() == 2 183 | 184 | proc popBack*[T](v: var CppVector[T]) {.importcpp: "pop_back".} = 185 | ## Remove the last element of the CppVector. 186 | ## This proc does not return anything. 187 | ## 188 | ## https://www.cplusplus.com/reference/CppVector/CppVector/pop_back/ 189 | runnableExamples: 190 | var v = initCppVector[int]() 191 | doAssert v.len() == 0 192 | 193 | v.add(100) 194 | doAssert v.len() == 1 195 | 196 | v.popBack() 197 | doAssert v.len() == 0 198 | 199 | proc insert*[T]( 200 | v: var CppVector[T], position: CppVectorConstIterator[T], val: T 201 | ): CppVectorIterator[T] {.importcpp: "insert".} = 202 | ## Insert an element before the specified position. 203 | runnableExamples: 204 | var v = @['a', 'b'].toCppVector() 205 | discard v.insert(v.cBegin(), 'c') 206 | doAssert v.toSeq() == @['c', 'a', 'b'] 207 | 208 | proc insert*[T]( 209 | v: var CppVector[T], position: CppVectorConstIterator[T], count: csize_t, val: T 210 | ): CppVectorIterator[T] {.importcpp: "insert".} = 211 | ## Insert `count` copies of element before the specified position. 212 | runnableExamples: 213 | var v = @['a', 'b'].toCppVector() 214 | discard v.insert(v.cBegin(), 3, 'c') 215 | doAssert v.toSeq() == @['c', 'c', 'c', 'a', 'b'] 216 | 217 | proc insert*[T]( 218 | v: var CppVector[T], position, first, last: CppVectorConstIterator[T] 219 | ): CppVectorIterator[T] {.importcpp: "insert".} = 220 | ## Insert elements from range `first` ..< `last` before the specified position. 221 | runnableExamples: 222 | let v1 = @['a', 'b'].toCppVector() 223 | var v2: CppVector[char] 224 | discard v2.insert(v2.cBegin(), v1.cBegin(), v1.cEnd()) 225 | doAssert v2.toSeq() == @['a', 'b'] 226 | 227 | proc swap*[T](v1, v2: var CppVector[T]) {.importcpp: "swap".} = 228 | ## Swap the contents of vectors `v1` and `v2`. 229 | ## 230 | ## https://en.cppreference.com/w/cpp/container/CppVector/swap 231 | runnableExamples: 232 | var 233 | v1 = @[1, 2, 3].toCppVector() 234 | v2 = @[7, 8, 9].toCppVector() 235 | v1.swap(v2) 236 | doAssert v1.toSeq() == @[7, 8, 9] 237 | doAssert v2.toSeq() == @[1, 2, 3] 238 | 239 | proc erase*[T](self: var CppVector[T], position: CppVectorConstIterator[T]): CppVectorIterator[T] {.importcpp: "erase".} 240 | proc erase*[T]( 241 | self: var CppVector[T], first, last: CppVectorConstIterator[T] 242 | ): CppVectorIterator[T] {.importcpp: "erase".} 243 | 244 | proc clear*[T](self: var CppVector[T]) {.importcpp: "clear".} 245 | 246 | # Relational operators 247 | proc `==`*[T](a: CppVector[T], b: CppVector[T]): bool {.importcpp: "(# == #)".} = 248 | ## Return `true` if the contents of lhs and rhs are equal, that is, 249 | ## they have the same number of elements and each element in lhs compares 250 | ## equal with the element in rhs at the same position. 251 | ## 252 | ## https://en.cppreference.com/w/cpp/container/CppVector/operator_cmp 253 | runnableExamples: 254 | let 255 | v1 = @[1, 2, 3].toCppVector() 256 | v2 = v1 257 | doAssert v1 == v2 258 | 259 | proc `!=`*[T](a: CppVector[T], b: CppVector[T]): bool {.importcpp: "(# != #)".} = 260 | ## Return `true` if the contents of lhs and rhs are not equal, that is, 261 | ## either they do not have the same number of elements, or one of the elements 262 | ## in lhs does not compare equal with the element in rhs at the same position. 263 | ## 264 | ## https://en.cppreference.com/w/cpp/container/CppVector/operator_cmp 265 | runnableExamples: 266 | let v1 = @[1, 2, 3].toCppVector() 267 | var 268 | v2 = v1 269 | v3 = v1 270 | v2.add(4) 271 | doAssert v2 != v1 272 | 273 | v3[0] = 100 274 | doAssert v3 != v1 275 | 276 | proc `<`*[T](a: CppVector[T], b: CppVector[T]): bool {.importcpp: "(# < #)".} = 277 | ## Return `true` if `a` is `lexicographically `_ 278 | ## less than `b`. 279 | ## 280 | ## https://en.cppreference.com/w/cpp/container/CppVector/operator_cmp 281 | runnableExamples: 282 | let v1 = @[1, 2, 3].toCppVector() 283 | var v2 = v1 284 | doAssert not (v1 < v2) 285 | 286 | v2.add(4) 287 | doAssert v1 < v2 288 | 289 | v2[2] = 0 290 | doAssert v2 < v1 291 | 292 | proc `<=`*[T](a: CppVector[T], b: CppVector[T]): bool {.importcpp: "(# <= #)".} = 293 | ## Return `true` if `a` is `lexicographically `_ 294 | ## less than or equal to `b`. 295 | ## 296 | ## https://en.cppreference.com/w/cpp/container/CppVector/operator_cmp 297 | runnableExamples: 298 | let v1 = @[1, 2, 3].toCppVector() 299 | var v2 = v1 300 | doAssert v1 <= v2 301 | 302 | v2.add(4) 303 | doAssert v1 <= v2 304 | 305 | v2[2] = 0 306 | doAssert v2 <= v1 307 | 308 | proc `>`*[T](a: CppVector[T], b: CppVector[T]): bool {.importcpp: "(# > #)".} = 309 | ## Return `true` if `a` is `lexicographically `_ 310 | ## greater than `b`. 311 | ## 312 | ## https://en.cppreference.com/w/cpp/container/CppVector/operator_cmp 313 | runnableExamples: 314 | let v1 = @[1, 2, 3].toCppVector() 315 | var v2 = v1 316 | doAssert not (v2 > v1) 317 | 318 | v2.add(4) 319 | doAssert v2 > v1 320 | 321 | v2[2] = 0 322 | doAssert v1 > v2 323 | 324 | proc `>=`*[T](a: CppVector[T], b: CppVector[T]): bool {.importcpp: "(# >= #)".} = 325 | ## Return `true` if `a` is `lexicographically `_ 326 | ## greater than or equal to `b`. 327 | ## 328 | ## https://en.cppreference.com/w/cpp/container/CppVector/operator_cmp 329 | runnableExamples: 330 | let v1 = @[1, 2, 3].toCppVector() 331 | var v2 = v1 332 | doAssert v2 >= v1 333 | 334 | v2.add(4) 335 | doAssert v2 >= v1 336 | 337 | v2[2] = 0 338 | doAssert v1 >= v2 339 | 340 | {.pop.} # {.push header: "".} 341 | 342 | # Nim specifics 343 | template checkIndex[T](self: CppVector[T], i: csize_t) = 344 | let maxLen = self.size() 345 | if unlikely i >= maxLen: 346 | let msg = "Index out-of-bound: " & $i & " >= " & $maxLen & "." 347 | raise newException(IndexDefect, msg) 348 | 349 | # Element access 350 | proc `[]`*[T](self: CppVector[T], idx: Natural): lent T {.inline.} = 351 | ## Return the reference to `self[idx]`. 352 | let i = csize_t(idx) 353 | when compileOption("boundChecks"): 354 | self.checkIndex(i) 355 | self.unsafeIndex(i) 356 | 357 | proc `[]`*[T](self: var CppVector[T], idx: Natural): var T {.inline.} = 358 | ## Return the reference to `self[idx]`. 359 | runnableExamples: 360 | var v = initCppVector[char]() 361 | v.add('a') 362 | v.add('b') 363 | v.add('c') 364 | 365 | v[1] = 'z' 366 | doAssert v[0] == 'a' 367 | doAssert v[1] == 'z' 368 | doAssert v[2] == 'c' 369 | # 370 | let i = csize_t(idx) 371 | when compileOption("boundChecks"): 372 | self.checkIndex(i) 373 | # this strange syntax is to avoid a bug in the Nim C++ code generator 374 | self.unsafeIndex(i) 375 | 376 | proc `[]=`*[T](self: var CppVector[T], idx: Natural, val: T) {.inline.} = 377 | ## Set the value at `v[idx]` to the specified value `val`. 378 | runnableExamples: 379 | var v = initCppVector[int](2) 380 | doAssert v.toSeq() == @[0, 0] 381 | 382 | v[0] = -1 383 | doAssert v.toSeq() == @[-1, 0] 384 | # 385 | let i = csize_t(idx) 386 | when compileOption("boundChecks"): 387 | self.checkIndex(i) 388 | self.unsafeIndex(i) = val 389 | 390 | template `iterator`*[T](_: typedesc[CppVector[T]]): typedesc[CppVectorIterator[T]] = 391 | CppVectorIterator[T] 392 | 393 | template constIterator*[T](_: typedesc[CppVector[T]]): typedesc[CppVectorConstIterator[T]] = 394 | CppVectorConstIterator[T] 395 | 396 | # Nim Iterators 397 | iterator items*[T](v: CppVector[T]): T = 398 | ## Iterate over all the elements in CppVector `v`. 399 | runnableExamples: 400 | var 401 | v: CppVector[int] 402 | sum: int 403 | 404 | v.assign(3, 5) 405 | 406 | for elem in v: 407 | sum += elem 408 | doAssert sum == 15 409 | # 410 | for idx in 0.csize_t ..< v.len(): 411 | yield v[idx] 412 | 413 | iterator pairs*[T](v: CppVector[T]): (csize_t, T) = 414 | ## Iterate over `(index, value)` for all the elements in CppVector `v`. 415 | runnableExamples: 416 | var 417 | v: CppVector[int] 418 | sum: int 419 | 420 | v.assign(3, 5) 421 | 422 | for idx, elem in v: 423 | sum += idx.int + elem 424 | doAssert sum == 18 425 | # 426 | for idx in 0.csize_t ..< v.len(): 427 | yield (idx, v[idx]) 428 | 429 | # Converter: CppVectorIterator -> CppVectorConstIterator 430 | converter CppVectorIteratorToCppVectorConstIterator*[T]( 431 | x: CppVectorIterator[T] 432 | ): CppVectorConstIterator[T] {.importcpp: "#".} ## Implicitly convert mutable C++ iterator to immutable C++ iterator. 433 | 434 | # Aliases 435 | proc len*(v: CppVector): csize_t {.inline.} = 436 | ## Alias for `size proc <#size%2CCppVector>`_. 437 | v.size() 438 | 439 | proc add*[T](v: var CppVector[T], elem: T) {.inline.} = 440 | ## Alias for `pushBack proc <#pushBack%2CCppVector[T]%2CT>`_. 441 | runnableExamples: 442 | var v = initCppVector[int]() 443 | doAssert v.len() == 0 444 | 445 | v.add(100) 446 | v.add(200) 447 | doAssert v.len() == 2 448 | # 449 | v.pushBack(elem) 450 | 451 | proc first*[T](v: var CppVector[T]): var T {.inline.} = 452 | ## Alias for `front proc <#front%2CCppVector[T]>`_. 453 | runnableExamples: 454 | var v = initCppVector[int]() 455 | 456 | v.add(100) 457 | v.add(200) 458 | doAssert v.first() == 100 459 | 460 | v.first() = 300 461 | doAssert v.first() == 300 462 | # 463 | v.front() 464 | 465 | proc first*[T](v: CppVector[T]): T {.inline.} = 466 | ## Alias for `front proc <#front%2CCppVector[T]_2>`_. 467 | v.front() 468 | 469 | proc last*[T](v: var CppVector[T]): var T {.inline.} = 470 | ## Alias for `back proc <#back%2CCppVector[T]>`_. 471 | runnableExamples: 472 | var v = initCppVector[int]() 473 | 474 | v.add(100) 475 | v.add(200) 476 | doAssert v.last() == 200 477 | 478 | v.last() = 300 479 | doAssert v.last() == 300 480 | # 481 | v.back() 482 | 483 | proc last*[T](v: CppVector[T]): T {.inline.} = 484 | ## Alias for `back proc <#back%2CCppVector[T]_2>`_. 485 | v.back() 486 | 487 | # Display the content of a vector 488 | # Workaround due to generic bug 489 | proc toString[T](v: CppVector[T]): string = 490 | result = "[" 491 | let maxIdx = v.size() - 1 492 | for idx, val in v.pairs(): 493 | result.add($(val)) 494 | if idx < maxIdx: 495 | result.add ", " 496 | 497 | result.add("]") 498 | 499 | proc `$`*[T](v: CppVector[T]): string = 500 | ## The `$` operator for CppVector type variables. 501 | ## This is used internally when calling `echo` on a CppVector type variable. 502 | runnableExamples: 503 | var v = initCppVector[int]() 504 | doAssert $v == "[]" 505 | 506 | v.add(100) 507 | v.add(200) 508 | doAssert $v == "[100, 200]" 509 | 510 | toString(v) 511 | 512 | # To and from seq 513 | proc toSeq*[T](v: CppVector[T]): seq[T] = 514 | ## Convert a CppVector to a sequence. 515 | runnableExamples: 516 | var v: CppVector[char] 517 | v.assign(3, 'k') 518 | 519 | doAssert v.toSeq() == @['k', 'k', 'k'] 520 | # 521 | for elem in v: 522 | result.add(elem) 523 | 524 | proc toCppVector*[T](s: openArray[T]): CppVector[T] = 525 | ## Convert an array/sequence to a CppVector. 526 | runnableExamples: 527 | let 528 | s = @[1, 2, 3] 529 | a = [1, 2, 3] 530 | 531 | doAssert s.toCppVector().toSeq() == s 532 | doAssert a.toCppVector().toSeq() == s 533 | # 534 | for elem in s: 535 | result.add(elem) 536 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | cppstl 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | # Trick to ignore extension-less binary 2 | # * 3 | # !*.* 4 | 5 | bin/ 6 | # List of tests 7 | tstring 8 | tvector 9 | tcomplex 10 | tpair 11 | tsmart_ptrs 12 | tdestructor_codegen_bug 13 | -------------------------------------------------------------------------------- /tests/config.nims: -------------------------------------------------------------------------------- 1 | switch("path", "$projectDir/..") 2 | # switch("cc", "clang") 3 | switch("backend", "cpp") 4 | switch("cc", "gcc") 5 | when not defined(testing): 6 | switch("outdir", "tests/bin") 7 | 8 | -------------------------------------------------------------------------------- /tests/destroy_bug_15.nim: -------------------------------------------------------------------------------- 1 | import cppstl/std_vector 2 | import std/strutils 3 | 4 | type Foo = object 5 | x: int 6 | 7 | # proc `$`*(x: Foo) : string = 8 | # result = "Foo(x: " 9 | # result &= $x 10 | # result &= ")" 11 | 12 | proc `=destroy`*(a: Foo) = 13 | echo ("=destroy", a.x) 14 | 15 | proc main() = 16 | var v = initCppVector[Foo]() 17 | 18 | # Should be empty 19 | echo v 20 | v.add Foo(x: 10) 21 | v.add Foo(x: 11) 22 | 23 | # Should contain 10, 11 24 | echo v 25 | 26 | v.add Foo(x: 12) 27 | v.add Foo(x: 13) 28 | # Should contain 10, 11, 12, 14 29 | echo v 30 | echo "-----------" 31 | # Clear should call object destructor 32 | v.clear() 33 | 34 | when isMainModule: 35 | main() 36 | -------------------------------------------------------------------------------- /tests/tcomplex.nim: -------------------------------------------------------------------------------- 1 | # This code is licensed under MIT license (see LICENSE.txt for details) 2 | import unittest 3 | import complex 4 | import std/math 5 | import cppstl/std_complex 6 | 7 | 8 | proc main() = 9 | suite "CppComplex": 10 | test "constructors": 11 | var a = initCppComplex[float32](41.0, 31.0) 12 | var refa = Complex32(re: 41.0, im: 31.0) 13 | check refa.re == a.real 14 | check refa.im == a.imag 15 | 16 | test "Operators": 17 | block: 18 | var 19 | a = initCppComplex[float64](1.5, 1.0) 20 | b = initCppComplex[float64](1.5, 1.0) 21 | check a == b 22 | 23 | block: 24 | var 25 | a = initCppComplex[float64](141.571, 124.412) 26 | b = initCppComplex[float64](22.17843, 0.523) 27 | refa = toComplex(a) 28 | refb = toComplex(b) 29 | refres = refa + refb 30 | res = a + b 31 | check almostEqual(refres, toComplex(res)) 32 | 33 | block: 34 | var 35 | a = initCppComplex[float64](141.571, 124.412) 36 | b = initCppComplex[float64](22.17843, 0.523) 37 | refa = toComplex(a) 38 | refb = toComplex(b) 39 | refres = refa - refb 40 | res = a - b 41 | check almostEqual(refres, toComplex(res)) 42 | block: 43 | var 44 | a = initCppComplex[float64](141.571, 124.412) 45 | b = initCppComplex[float64](22.17843, 0.523) 46 | refa = toComplex(a) 47 | refb = toComplex(b) 48 | refres = refa * refb 49 | res = a * b 50 | check almostEqual(refres, toComplex(res)) 51 | block: 52 | var 53 | a = initCppComplex[float64](141.571, 124.412) 54 | b = initCppComplex[float64](22.17843, 0.523) 55 | refa = toComplex(a) 56 | refb = toComplex(b) 57 | refres = refa / refb 58 | res = a / b 59 | check almostEqual(refres, toComplex(res)) 60 | 61 | test "abs": 62 | var 63 | a = initCppComplex[float64](141.571, 124.412) 64 | refa = toComplex(a) 65 | 66 | check abs(a) == abs(refa) 67 | 68 | test "norm": 69 | var 70 | a = initCppComplex[float64](141.571, 124.412) 71 | refa = toComplex(a) 72 | 73 | check norm(a) == abs2(refa) 74 | 75 | test "conj": 76 | var 77 | a = initCppComplex[float64](141.571, 124.412) 78 | refa = toComplex(a) 79 | 80 | check conj(a) == conjugate(refa).toCppComplex() 81 | 82 | test "polar": 83 | var 84 | a = initCppComplex[float64](141.571, 124.412) 85 | refa = toComplex(a) 86 | # Use Nim to calculate polar coordinate of refa 87 | polcoord = polar(refa) 88 | b = polar(polcoord.r, polcoord.phi) 89 | 90 | check (a - b).real < 1e-12 91 | check (a - b).imag < 1e-12 92 | 93 | test "display": 94 | var a = initCppComplex[float64](141.571, 124.412) 95 | check `$`(a) == "(141.571, 124.412)" 96 | 97 | when isMainModule: 98 | main() 99 | 100 | -------------------------------------------------------------------------------- /tests/tdestructor_codegen_bug.nim: -------------------------------------------------------------------------------- 1 | # without the definiton of the `=destroy` hook this gives a code gen error 2 | import cppstl/std_smartptrs 3 | 4 | type Obj = object 5 | id: string 6 | isDestroyed: bool 7 | 8 | type 9 | SharedPtrObj = CppSharedPtr[Obj] 10 | UniquePtrObj = CppUniquePtr[Obj] 11 | 12 | proc `=destroy`*(x: var Obj) = 13 | echo "---------------------------" 14 | echo "=destroy : ", x.id 15 | echo "=destroy : ", x.isDestroyed 16 | x.isDestroyed = true 17 | echo "---------------------------" 18 | 19 | proc init*(T: type SharedPtrObj, id: string): SharedPtrObj = 20 | result = make_shared(Obj) 21 | result.id = id 22 | result.isDestroyed = false 23 | 24 | proc init*(T: type UniquePtrObj, id: string): UniquePtrObj = 25 | result = make_unique(Obj) 26 | result.id = id 27 | result.isDestroyed = false 28 | 29 | proc main() = 30 | echo "BEGIN" 31 | var o1 = SharedPtrObj.init("shared_o1") 32 | echo "o1>", o1 33 | 34 | var o2 = o1 35 | o2.id = "shared_o2" 36 | echo "o1>", o1 37 | echo "o2>", o2 38 | echo "----" 39 | 40 | var o = UniquePtrObj.init("unique_o") 41 | # Create a codegen bug 42 | # See https://github.com/nim-lang/Nim/issues/18982 43 | # echo o 44 | echo o.id 45 | 46 | echo "END" 47 | 48 | when isMainModule: 49 | main() 50 | -------------------------------------------------------------------------------- /tests/tpair.nim: -------------------------------------------------------------------------------- 1 | # This code is licensed under MIT license (see LICENSE.txt for details) 2 | import std/unittest 3 | import cppstl/std_string 4 | import cppstl/std_pair 5 | 6 | proc main() = 7 | suite "CppPair": 8 | test "constructors and field access": 9 | block: 10 | var p = initCppPair[CppString, cint]() 11 | check p.first == initCppString() 12 | check p.second == 0.cint 13 | 14 | block: 15 | var p1 = initCppPair(("hello"), 42.cint) 16 | check p1.first == ("hello") 17 | check p1.second == 42.cint 18 | 19 | var p2 = initCppPair(p1) 20 | check p2.first == ("hello") 21 | check p2.second == 42.cint 22 | 23 | test "member functions": 24 | block: 25 | var 26 | p1 = initCppPair("hello", 42.cint) 27 | p2 = initCppPair("world", 100.cint) 28 | 29 | p1.swap(p2) 30 | check p1.first == ("world") 31 | check p1.second == 100.cint 32 | check p2.first == ("hello") 33 | check p2.second == 42.cint 34 | 35 | test "comparison operators": 36 | block: 37 | let 38 | s1 = toCppString("hello") 39 | s2 = toCppString("0hello") 40 | s3 = toCppString("zhello") 41 | 42 | var 43 | p1 = initCppPair(s1, 42.cint) 44 | p2 = initCppPair(toCppString("hello"), 50.cint) 45 | p3 = initCppPair(s2, 50.cint) 46 | p4 = initCppPair(s3, 50.cint) 47 | 48 | check not (p1 == p2) 49 | check not (p2 == p1) 50 | check p1 != p2 51 | check p2 != p1 52 | check p1 < p2 53 | check not (p2 < p1) 54 | check p1 <= p2 55 | check not (p2 <= p1) 56 | check not (p1 > p2) 57 | check p2 > p1 58 | check not (p1 >= p2) 59 | check p2 >= p1 60 | check p3 < p1 61 | check not (p3 >= p1) 62 | check p4 > p1 63 | check not (p4 <= p1) 64 | 65 | block: 66 | var 67 | p1 = initCppPair("hello", 42.cint) 68 | p2 = initCppPair("hello", 50.cint) 69 | p3 = initCppPair("0hello", 50.cint) 70 | p4 = initCppPair("zhello", 50.cint) 71 | 72 | check not (p1 == p2) 73 | check not (p2 == p1) 74 | check p1 != p2 75 | check p2 != p1 76 | check p1 < p2 77 | check not (p2 < p1) 78 | check p1 <= p2 79 | check not (p2 <= p1) 80 | check not (p1 > p2) 81 | check p2 > p1 82 | check not (p1 >= p2) 83 | check p2 >= p1 84 | check p3 < p1 85 | check not (p3 >= p1) 86 | check p4 > p1 87 | check not (p4 <= p1) 88 | 89 | test "other non-member functions": 90 | block: 91 | var p = initCppPair(initCppString("hello"), 42.cint) 92 | check get(CppString, p) == initCppString("hello") 93 | check get(cint, p) == 42.cint 94 | check not compiles(get(cfloat, p)) 95 | 96 | block: 97 | var p = initCppPair(100.cint, 42.cint) 98 | check not compiles(get(cint, p)) 99 | 100 | block: 101 | var p = initCppPair(initCppString("hello"), 42.cint) 102 | check get(0, p) == initCppString("hello") 103 | check get(1, p) == 42.cint 104 | check not compiles(get(2, p)) 105 | 106 | test "$": 107 | var p = initCppPair(initCppString("hello"), 42.cint) 108 | check $p == "CppPair(first: hello, second: 42)" 109 | 110 | test "toTuple and back": 111 | let 112 | f = "Hello world" 113 | s = 144 114 | var pair: CppPair[string, int] = makePair(f, s) 115 | var tup = pair.toTuple() 116 | check tup == (first: f, second: s) 117 | check makePair(tup) == pair 118 | 119 | 120 | when isMainModule: 121 | main() 122 | 123 | -------------------------------------------------------------------------------- /tests/tsmart_ptrs.nim: -------------------------------------------------------------------------------- 1 | import cppstl/std_smartptrs 2 | import std/unittest 3 | import std/strutils 4 | 5 | type Obj = object 6 | id: int 7 | name: string 8 | 9 | var guid = 0 10 | 11 | type 12 | SharedPtrObj = CppSharedPtr[Obj] 13 | UniquePtrObj = CppUniquePtr[Obj] 14 | 15 | proc init*(T: type SharedPtrObj, name: string): SharedPtrObj = 16 | inc(guid) 17 | result = makeShared(Obj) 18 | result.name = name 19 | result.id = guid 20 | 21 | proc init*(T: type UniquePtrObj, name: string): UniquePtrObj = 22 | inc(guid) 23 | result = makeUnique(Obj) 24 | result.name = name 25 | result.id = guid 26 | 27 | proc cppNew[T](x: typedesc[T]): ptr T {.importcpp: "(new '1)", nodecl.} 28 | 29 | proc testShared() = 30 | test "SharedPtr": 31 | var sp1 = SharedPtrObj.init("ptr_1") 32 | 33 | check: 34 | sp1.id == 1 35 | 36 | check: 37 | sp1.name == "ptr_1" 38 | 39 | sp1.name = "ptr_2" 40 | check: 41 | sp1.name == "ptr_2" 42 | 43 | var sp2 = sp1 44 | check: 45 | sp2.id == 1 46 | check: 47 | sp2.name == "ptr_2" 48 | 49 | sp2.name = "ptr_3" 50 | check: 51 | sp1.name == "ptr_3" 52 | check sp1.name.len() == 5 53 | 54 | var sp3 = block: 55 | let p = cppNew(Obj) 56 | p[] = sp1.deref 57 | newCppSharedPtr(p) 58 | check sp3.deref == sp1.deref 59 | 60 | when defined(gcArc) or defined(gcOrc): 61 | check: 62 | $(sp1) == "CppShared ptr Obj(id: 1, name: \"ptr_3\")" 63 | else: 64 | check: 65 | contains($(sp1), """CppShared ptr""") 66 | check: 67 | contains( 68 | $(sp1), 69 | """[id = 1, 70 | name =""", 71 | ) 72 | check: 73 | contains($(sp1), """"ptr_3"]""") 74 | 75 | proc testUnique() = 76 | test "UniquePtr": 77 | var up1 = UniquePtrObj.init("ptr_1") 78 | 79 | check: 80 | up1.id == 2 81 | 82 | check: 83 | up1.name == "ptr_1" 84 | 85 | up1.name = "ptr_2" 86 | check: 87 | up1.name == "ptr_2" 88 | # Create a codegen bug 89 | # See https://github.com/nim-lang/Nim/issues/18982 90 | # check: $(up1) == "CppUnique ptr Obj(id: 2, name: \"ptr_2\")" 91 | 92 | when isMainModule: 93 | testShared() 94 | testUnique() 95 | -------------------------------------------------------------------------------- /tests/tstring.nim: -------------------------------------------------------------------------------- 1 | # This code is licensed under MIT license (see LICENSE.txt for details) 2 | import unittest 3 | import cppstl/std_string 4 | 5 | 6 | proc main() = 7 | suite "CppString": 8 | test "constructors and iterators": 9 | var s = initCppString() 10 | check s.empty 11 | check s.length == 0 12 | check s == "".cstring 13 | 14 | s = initCppString("hello nim") 15 | check s == "hello nim".cstring 16 | check $s == "hello nim".cstring 17 | 18 | s = initCppString("hello nim", 5) 19 | check s == "hello".cstring 20 | 21 | var s1: CppString = initCppString("hello") 22 | check s1 == s 23 | 24 | s1 = initCppString(s) 25 | check s1 == s 26 | 27 | s1 = initCppString(s, 3) 28 | check s1 == "lo".cstring 29 | 30 | s1 = initCppString(s, 0, 4) 31 | check s1 == "hell".cstring 32 | 33 | s1 = initCppString(s.begin, s.`end`) 34 | check s1 == s 35 | 36 | s1 = initCppString(s.begin, s.begin + 4) 37 | check s1 == "hell".cstring 38 | 39 | s1 = initCppString(s.cbegin, s.cbegin + 4) 40 | check s1 == "hell".cstring 41 | 42 | s1 = initCppString(s.rbegin, s.rend) 43 | check s1 == "olleh".cstring 44 | 45 | s1 = initCppString(s.crbegin, s.crend) 46 | check s1 == "olleh".cstring 47 | 48 | test "capacity & size": 49 | var s: CppString = initCppString "Hello Nim!" 50 | 51 | check s.size == s.length 52 | check s.maxSize > s.size 53 | 54 | s.resize 5 55 | 56 | check s == "Hello".cstring 57 | check s.capacity >= s.size 58 | 59 | let oldCap = s.capacity 60 | s.reserve(2 * oldCap) 61 | 62 | #Capacity should be at least the reserved space 63 | check s.capacity >= 2 * oldCap 64 | 65 | s.clear 66 | 67 | check s.empty 68 | check s == "".cstring 69 | 70 | s = initCppString("Hello") 71 | s.reserve(s.capacity * 2) 72 | s.shrinkToFit 73 | 74 | # check s.length == s.capacity # implementation dependent. 75 | # Does not allways hold 76 | 77 | test "accessors": 78 | var s: CppString = initCppString("Hello Nim!") 79 | check s[1] == 'e' 80 | check s.at(1) == 'e' 81 | check s.front == 'H' 82 | check s.back == '!' 83 | 84 | s[1] = 'o' 85 | 86 | check s[1] == 'o' 87 | 88 | s.at(1) = 'e' 89 | s.front() = 'h' 90 | s.back() = '?' 91 | 92 | check s == "hello Nim?".cstring 93 | 94 | when compileOption("boundChecks"): 95 | expect(IndexDefect): 96 | discard s[100] 97 | expect(OutOfRangeException): 98 | discard s.at(100) 99 | 100 | test "test string modifiers": 101 | var s: CppString = toCppString("Hello") 102 | var s2 = toCppString(" Nim!") 103 | s += s2 104 | 105 | check s == "Hello Nim!".cstring 106 | s += " Welcome!".cstring 107 | check s == "Hello Nim! Welcome!".cstring 108 | s += '!' 109 | check s == "Hello Nim! Welcome!!".cstring 110 | 111 | s = initCppString("Hello") 112 | s.append s2 113 | check s == "Hello Nim!".cstring 114 | s.append " Welcome!".cstring 115 | check s == "Hello Nim! Welcome!".cstring 116 | s.append(1, '!') 117 | check s == "Hello Nim! Welcome!!".cstring 118 | s.append(3, '!') 119 | check s == "Hello Nim! Welcome!!!!!".cstring 120 | 121 | s2 = initCppString "!!! :)" 122 | s.append(s2, 3, 3) 123 | check s == "Hello Nim! Welcome!!!!! :)".cstring 124 | s.append(" :)...........".cstring, 4) 125 | check s == "Hello Nim! Welcome!!!!! :) :).".cstring 126 | 127 | s2 = initCppString "I say Bye!" 128 | s.append(s2.cbegin + 5, s2.cend) 129 | check s == "Hello Nim! Welcome!!!!! :) :). Bye!".cstring 130 | s.pushBack '!' 131 | check s == "Hello Nim! Welcome!!!!! :) :). Bye!!".cstring 132 | 133 | s = initCppString "" 134 | s2 = initCppString "Hello" 135 | s.assign(s2) 136 | check s == s2 137 | s.assign(s2, 1, 3) 138 | check s == "ell".cstring 139 | s.assign("hi".cstring) 140 | check s == "hi".cstring 141 | s.assign("hello".cstring, 4) 142 | check s == "hell".cstring 143 | s.assign(3, '6') 144 | check s == "666".cstring 145 | 146 | s = initCppString "H!!!" 147 | s2 = initCppString "ello " 148 | s.insert(1, s2) 149 | check s == "Hello !!!".cstring 150 | 151 | s = initCppString "H!!!" 152 | s2 = initCppString "Hello !!!" 153 | s.insert(1, s2, 1, 5) 154 | check s == "Hello !!!".cstring 155 | 156 | s = initCppString "H!!!" 157 | s.insert(1, "ello ".cstring) 158 | check s == "Hello !!!".cstring 159 | 160 | s = initCppString "H!!!" 161 | s.insert(1, "ello ???".cstring, 5) 162 | check s == "Hello !!!".cstring 163 | 164 | s = initCppString "Heo !!!" 165 | s.insert(2, 2, 'l') 166 | check s == "Hello !!!".cstring 167 | 168 | s = initCppString "Heo !!!" 169 | s.insert(s.begin + 2, 2, 'l') 170 | check s == "Hello !!!".cstring 171 | 172 | s = initCppString "Hllo !!!" 173 | s.insert(s.begin + 1, 'e') 174 | check s == "Hello !!!".cstring 175 | 176 | s = initCppString "H!!!" 177 | s2 = initCppString "Hello !!!" 178 | s.insert(s.begin + 1, s2.cbegin + 1, s2.cend - 3) 179 | check s == "Hello !!!".cstring 180 | 181 | s = initCppString "Hello" 182 | s.erase() 183 | check s.empty 184 | 185 | s = initCppString "Hello" 186 | s.erase(1) 187 | check s == "H".cstring 188 | 189 | s = initCppString "Hello" 190 | s.erase(1, 3) 191 | check s == "Ho".cstring 192 | 193 | s = initCppString "Hello" 194 | s.erase(s.begin + 1) 195 | check s == "Hllo".cstring 196 | 197 | s = initCppString "Hello" 198 | s.erase(s.begin + 1, s.`end`) 199 | check s == "H".cstring 200 | 201 | s = initCppString "HELLO !" 202 | s2 = initCppString "ello" 203 | s.replace(1, 4, s2) 204 | check s == "Hello !".cstring 205 | 206 | s = initCppString "HELLO !" 207 | s2 = initCppString "ello" 208 | s.replace(s.cbegin + 1, s.cend - 2, s2) 209 | check s == "Hello !".cstring 210 | 211 | s = initCppString "HELLO !" 212 | s2 = initCppString "hhhello there" 213 | s.replace(1, 4, s2, 3, 4) 214 | check s == "Hello !".cstring 215 | 216 | s = initCppString "HELLO !" 217 | s.replace(1, 4, "ello".cstring) 218 | check s == "Hello !".cstring 219 | 220 | s = initCppString "HELLO !" 221 | s.replace(s.cbegin + 1, s.cend - 2, "ello".cstring) 222 | check s == "Hello !".cstring 223 | 224 | s = initCppString "HELLO !" 225 | s.replace(1, 4, "ello....".cstring, 4) 226 | check s == "Hello !".cstring 227 | 228 | s = initCppString "HELLO !" 229 | s.replace(s.cbegin + 1, s.cend - 2, "ello....".cstring, 4) 230 | check s == "Hello !".cstring 231 | 232 | s = initCppString "Hejjo !" 233 | s.replace(2, 2, 4, 'l') 234 | check s == "Hellllo !".cstring 235 | 236 | s = initCppString "Hejjo !" 237 | s.replace(s.cbegin + 2, s.cbegin + 4, 4, 'l') 238 | check s == "Hellllo !".cstring 239 | 240 | s = initCppString "HELLO !" 241 | s2 = initCppString "hello" 242 | s.replace(s.cbegin + 1, s.cend - 2, s2.cbegin + 1, s2.cend) 243 | check s == "Hello !".cstring 244 | 245 | s = initCppString "HELLO !" 246 | s2 = initCppString "hello" 247 | s.swap s2 248 | check s == "hello".cstring 249 | s.popBack 250 | check s == "hell".cstring 251 | 252 | test "test string operations": 253 | var s: CppString = initCppString "Hello Nim!" 254 | 255 | check s.cStr == "Hello Nim!".cstring 256 | check s.data[] == 'H' 257 | 258 | var s2: CppString = initCppString "Hello" 259 | var cstr = newSeq[cchar](4) 260 | discard s2.copy(addr cstr[0], 3, 2) 261 | 262 | check cast[cstring](addr cstr[0]) == "llo" 263 | 264 | s = initCppString "hello hello" 265 | s2 = initCppString "ll" 266 | 267 | check s.find(s2) == 2 268 | check s.find(s2, 5) == 8 269 | check s.find("ll".cstring) == 2 270 | check s.find("ll".cstring, 5) == 8 271 | check s.find("ll0".cstring, 5, 3) == std_npos 272 | check s.find("ll0".cstring, 5, 2) == 8 273 | check s.find('e') == 1 274 | check s.find('e', 3) == 7 275 | 276 | check s.rfind(s2) == 8 277 | check s.rfind(s2, 5) == 2 278 | check s.rfind("ll".cstring) == 8 279 | check s.rfind("ll".cstring, 5) == 2 280 | check s.rfind("ll0".cstring, 5, 3) == std_npos 281 | check s.rfind("ll0".cstring, 5, 2) == 2 282 | check s.rfind('e') == 7 283 | check s.rfind('e', 3) == 1 284 | 285 | s = initCppString "Please, replace the vowels in this sentence by asterisks." 286 | s2 = initCppString "aeiou" 287 | var found = s.findFirstOf(s2) 288 | while found != std_npos: 289 | s[found] = '*' 290 | found = s.findFirstOf(s2, found + 1) 291 | 292 | check s == "Pl**s*, r*pl*c* th* v*w*ls *n th*s s*nt*nc* by *st*r*sks.".cstring 293 | 294 | s = initCppString "Please, replace the vowels in this sentence by asterisks." 295 | found = s.findFirstOf("aeiou") 296 | while found != std_npos: 297 | s[found] = '*' 298 | found = s.findFirstOf("aeiou", found + 1) 299 | 300 | check s == "Pl**s*, r*pl*c* th* v*w*ls *n th*s s*nt*nc* by *st*r*sks.".cstring 301 | 302 | s = initCppString "Please, replace the vowels in this sentence by asterisks." 303 | found = s.findFirstOf("aeiou", 0, 3) 304 | while found != std_npos: 305 | s[found] = '*' 306 | found = s.findFirstOf("aeiou", found + 1, 3) 307 | 308 | check s == "Pl**s*, r*pl*c* th* vow*ls *n th*s s*nt*nc* by *st*r*sks.".cstring 309 | check s.findFirstOf('l', 3) == 11 310 | 311 | s = initCppString "/usr/bin/man" 312 | s2 = initCppString "/\\" 313 | 314 | found = s.findLastOf(s2) 315 | check s.substr(found + 1) == "man".cstring 316 | found = s.findLastOf(s2, found - 1) 317 | check s.substr(found + 1) == "bin/man".cstring 318 | found = s.findLastOf("/\\") 319 | check s.substr(found + 1) == "man".cstring 320 | found = s.findLastOf("/\\", found - 1) 321 | check s.substr(found + 1) == "bin/man".cstring 322 | found = s.findLastOf("/\\lll", std_npos, 3) 323 | check s.substr(found + 1) == "man".cstring 324 | found = s.findLastOf("/\\", found - 1, 3) 325 | check s.substr(found + 1) == "bin/man".cstring 326 | found = s.findLastOf('m') 327 | check s.substr(found) == "man".cstring 328 | found = s.findLastOf('b', found - 1) 329 | check s.substr(found) == "bin/man".cstring 330 | 331 | s = initCppString "1293a456b7" 332 | s2 = initCppString "123456789" 333 | 334 | check s.findFirstNotOf(s2) == 4 335 | check s.findFirstNotOf(s2, 5) == 8 336 | check s.findFirstNotOf("123456789".cstring) == 4 337 | check s.findFirstNotOf("123456789".cstring, 5) == 8 338 | check s.findFirstNotOf("123456789".cstring, 0, 3) == 2 339 | check s.findFirstNotOf("123456789".cstring, 4, 3) == 4 340 | check s.findFirstNotOf('1') == 1 341 | check s.findFirstNotOf('1', 1) == 1 342 | 343 | check s.findLastNotOf(s2) == 8 344 | check s.findLastNotOf(s2, 5) == 4 345 | check s.findLastNotOf("123456789".cstring) == 8 346 | check s.findLastNotOf("123456789".cstring, 5) == 4 347 | check s.findLastNotOf("123456789".cstring, std_npos, 3) == 9 348 | check s.findLastNotOf("123456789".cstring, 4, 3) == 4 349 | check s.findLastNotOf('1') == 9 350 | check s.findLastNotOf('1', 1) == 1 351 | 352 | s = initCppString "green apple" 353 | s2 = initCppString "red apple" 354 | 355 | check s.compare(s2) != 0 356 | check s.compare("red apple".cstring) != 0 357 | check s.compare(0, s.length, s2) != 0 358 | check s.compare(0, s.length, "red apple".cstring) != 0 359 | check s.compare(6, 5, "apple".cstring) == 0 360 | check s.compare(6, 5, "red apple".cstring, 4, 5) == 0 361 | check s.compare(6, 5, s2, 4, 5) == 0 362 | 363 | test "test string non-member function overloads": 364 | var s1: CppString = initCppString "Hello " 365 | var s2: CppString = initCppString "Nim" 366 | 367 | check s1 + s2 == "Hello Nim".cstring 368 | check s1 + "Nim".cstring == "Hello Nim".cstring 369 | check "Hello ".cstring() + s2 == "Hello Nim".cstring 370 | check s1 + '!' == "Hello !".cstring 371 | check '!' + s1 + '!' == "!Hello !".cstring 372 | 373 | s1 += s2 374 | 375 | check s1 == "Hello Nim".cstring 376 | 377 | s1 = initCppString "alpha" 378 | s2 = initCppString "beta" 379 | 380 | check s1 != s2 381 | check s1 != "beta".cstring 382 | check "alpha".cstring != s2 383 | check not (s1 == s2) 384 | check not (s1 == "beta".cstring) 385 | check not ("alpha".cstring == s2) 386 | check s1 < s2 387 | check not (s1 > s2) 388 | check s1 > "aaaaaaaaaaaaa".cstring 389 | check s1 <= s2 390 | check not (s1 >= s2) 391 | check s1 >= "aaaaaaaaaaaaa".cstring 392 | 393 | test "Nim iterators": 394 | let s1 = toCppString("123456789") 395 | block: 396 | var i = 0 397 | for c in s1: 398 | inc(i) 399 | check cchar(i.uint8 + uint8('0')) == c 400 | block: 401 | var i = 0 402 | for idx, c in s1.pairs: 403 | check idx == i.csize_t 404 | inc(i) 405 | check cchar(i.uint8 + uint8('0')) == c 406 | 407 | test "mutable Nim iterators": 408 | var s1 = toCppString("123456789") 409 | for c in s1.mitems: 410 | c = 'a' 411 | check s1.toString == "aaaaaaaaa" 412 | 413 | var i = 0 414 | for idx, c in s1.mpairs: 415 | check idx == i.csize_t 416 | inc(i) 417 | c = 'b' 418 | check s1.toString == "bbbbbbbbb" 419 | 420 | 421 | when isMainModule: 422 | main() 423 | 424 | -------------------------------------------------------------------------------- /tests/tvector.nim: -------------------------------------------------------------------------------- 1 | # This code is licensed under MIT license (see LICENSE.txt for details) 2 | import std/[unittest, strformat, sequtils] 3 | import cppstl/std_vector 4 | 5 | 6 | proc main() = 7 | suite "CppVector": 8 | test "constructor, size/len, empty": 9 | var 10 | v1 = initCppVector[int]() 11 | v2 = initCppVector[int](10) 12 | 13 | check v1.size() == 0.csize_t 14 | check v2.len() == 10.csize_t 15 | check v1.empty() == true 16 | check v2.empty() == false 17 | 18 | test "constructors and iterators": 19 | block: 20 | var v = initCppVector[int](3) 21 | check v.size == 3 22 | check v[0] == 0 23 | check v[1] == 0 24 | check v[2] == 0 25 | 26 | block: 27 | var v = initCppVector[int](3, 1) 28 | check v.size() == 3 29 | check v[0] == 1 30 | check v[1] == 1 31 | check v[2] == 1 32 | 33 | var v = initCppVector[int]() 34 | v.pushBack(1) 35 | v.pushBack(2) 36 | v.pushBack(3) 37 | 38 | check v.size() == 3 39 | check v[0] == 1 40 | check v[1] == 2 41 | check v[2] == 3 42 | 43 | block: 44 | var v2 = initCppVector(v) 45 | check v.size() == v2.size() 46 | check v[0] == v2[0] 47 | check v[1] == v2[1] 48 | check v[2] == v2[2] 49 | 50 | block: 51 | var v2 = initCppVector(begin(v), `end`(v)) 52 | 53 | check v.size == v2.size 54 | check v[0] == v2[0] 55 | check v[1] == v2[1] 56 | check v[2] == v2[2] 57 | check v == v2 58 | 59 | block: 60 | var v2 = initCppVector(rBegin(v), rEnd(v)) 61 | 62 | check v.size == v2.size 63 | check v[0] == v2[2] 64 | check v[1] == v2[1] 65 | check v[2] == v2[0] 66 | check v != v2 67 | 68 | block: 69 | var v2 = initCppVector(cBegin(v), cEnd(v)) 70 | 71 | check v.size == v2.size 72 | check v[0] == v2[0] 73 | check v[1] == v2[1] 74 | check v[2] == v2[2] 75 | check v == v2 76 | 77 | block: 78 | var v2 = initCppVector(crBegin(v), crEnd(v)) 79 | 80 | check v.size == v2.size 81 | check v[0] == v2[2] 82 | check v[1] == v2[1] 83 | check v[2] == v2[0] 84 | check v != v2 85 | 86 | test "capacity": 87 | var v = initCppVector[int](3) 88 | 89 | check v.size == 3 90 | check v.capacity >= v.size 91 | check v.maxSize >= v.size 92 | check not v.empty 93 | 94 | let oldCap = v.capacity 95 | let oldSz = v.size 96 | v.reserve(2 * oldCap) 97 | 98 | check oldCap < v.capacity 99 | check oldSz == v.size 100 | 101 | v.resize(oldSz + 1) 102 | 103 | check oldSz + 1 == v.size 104 | 105 | v.shrinkToFit() 106 | 107 | check v.size == v.capacity 108 | 109 | test "element access": 110 | var v = initCppVector[int](3) 111 | 112 | check v[0] == 0 113 | check v.at(0) == 0 114 | 115 | v[0] = 100 116 | 117 | check v[0] == 100 118 | check v.at(0) == 100 119 | 120 | v.at(0) = 1000 121 | 122 | check v[0] == 1000 123 | check v.at(0) == 1000 124 | 125 | when compileOption("boundChecks"): 126 | expect(IndexDefect): 127 | discard v[4] 128 | expect(OutOfRangeException): 129 | discard v.at(4) 130 | 131 | v = initCppVector[int](5) 132 | for i in 0 ..< v.size: 133 | v[i] = i.int 134 | 135 | check v.front == 0 136 | check v.back == 4 137 | 138 | v = initCppVector[int](2) 139 | v.front() = 10 140 | v.back() = 11 141 | 142 | check v[0] == 10 143 | check v[1] == 11 144 | 145 | var pdata = v.data 146 | 147 | check pdata[] == 10 148 | check cast[ptr int](cast[int](pdata) + 1 * sizeof(int))[] == 11 149 | 150 | test "push/add, pop, front/first, back/last": 151 | var 152 | v = initCppVector[int]() 153 | refSeq = @[100, 300, 400, 500] # This test will create the following Vector 154 | 155 | v.pushBack(100) 156 | check v.len() == 1.csize_t 157 | 158 | v.add(200) 159 | check v.len() == 2.csize_t 160 | 161 | v.popBack() 162 | check v.len() == 1.csize_t 163 | 164 | v.add(300) 165 | v.add(400) 166 | v.add(500) 167 | 168 | for idx in 0.csize_t ..< v.len(): 169 | check v[idx] == refSeq[idx] 170 | 171 | check v.len() == 4.csize_t 172 | 173 | check v.first() == 100 174 | v.first() = 1 175 | check v.front() == 1 176 | 177 | check v.last() == 500 178 | v.last() = 5 179 | check v.back() == 5 180 | 181 | test "modifiers": 182 | var v = initCppVector[int]() 183 | for i in 0 ..< 3: 184 | v.pushBack i 185 | 186 | for i in 0 ..< 3: 187 | check v[i] == i 188 | 189 | v.popBack() 190 | 191 | check v.size == 2 192 | for i in 0 ..< v.size: 193 | check v[i] == i.int 194 | 195 | discard v.insert(v.`end`, 2) 196 | 197 | check v.size == 3 198 | for i in 0 ..< 3: 199 | check v[i] == i.int 200 | 201 | v.popBack() 202 | 203 | discard v.insert(v.cEnd, 2) 204 | 205 | check v.size == 3 206 | for i in 0 ..< 3: 207 | check v[i] == i 208 | 209 | discard v.insert(v.begin, 100) 210 | 211 | check v.size == 4 212 | check v[0] == 100 213 | 214 | discard v.insert(v.begin() + 1, 13) 215 | 216 | check v.size == 5 217 | check v[1] == 13 218 | 219 | discard v.insert(v.begin(), 3, 1) 220 | 221 | check v.size == 8 222 | for i in 0 ..< 3: 223 | check v[i] == 1 224 | 225 | discard v.insert(v.`end`(), v.begin(), v.`end`()) 226 | 227 | check v.size == 16 228 | for i in 0 ..< 8: 229 | check v[i] == v[i + 8] 230 | 231 | discard v.erase(v.begin() + 8, v.`end`()) 232 | 233 | check v.size == 8 234 | 235 | discard v.erase(v.begin() + 2, v.`end`()) 236 | 237 | check v.size == 2 238 | 239 | v[0] = 1 240 | v[1] = 2 241 | discard v.erase(v.begin() + 1) 242 | 243 | check v.size == 1 244 | check v[0] == 1 245 | 246 | v.pushBack 2 247 | discard v.erase(v.begin()) 248 | 249 | check v.size == 1 250 | check v[0] == 2 251 | 252 | v = initCppVector[int](3, 1) 253 | var v1 = initCppVector[int](3, 2) 254 | 255 | for i in 0 ..< 3: 256 | check v[i] == 1 257 | check v1[i] == 2 258 | 259 | v.swap v1 260 | 261 | for i in 0 ..< 3: 262 | check v1[i] == 1 263 | check v[i] == 2 264 | 265 | v.clear 266 | 267 | check v.size == 0 268 | check v.empty 269 | 270 | test "relational operators": 271 | let foo = initCppVector[int](3, 100) 272 | let bar = initCppVector[int](2, 200) 273 | 274 | check foo == foo 275 | check foo <= foo 276 | check foo >= foo 277 | check foo != bar 278 | check not (foo > bar) 279 | check foo < bar 280 | check not (foo >= bar) 281 | check foo <= bar 282 | 283 | let v1 = @[1, 2, 3].toCppVector() 284 | 285 | block: # ==, <=, >= 286 | let v2 = v1 287 | check v1 == v2 288 | check v1 <= v2 289 | check v1 >= v2 290 | 291 | block: # >, >= 292 | let v2 = @[1, 2, 4].toCppVector() 293 | check v2 > v1 294 | check v2 >= v1 295 | 296 | block: # >, unequal CppVector lengths 297 | let 298 | v2 = @[1, 2, 4].toCppVector() 299 | v3 = @[1, 2, 3, 0].toCppVector() 300 | check v3 > v1 301 | check v2 > v3 302 | 303 | block: # <, <= 304 | let v2 = @[1, 2, 4].toCppVector() 305 | check v1 < v2 306 | check v1 <= v2 307 | 308 | block: # <, unequal CppVector lengths 309 | let 310 | v2 = @[1, 2, 4].toCppVector() 311 | v3 = @[1, 2, 3, 0].toCppVector() 312 | check v1 < v3 313 | check v3 < v2 314 | 315 | test "display, $": 316 | block: 317 | var v = initCppVector[int]() 318 | check $v == "[]" 319 | v.pushBack(1) 320 | v.pushBack(2) 321 | v.pushBack(3) 322 | check $v == "[1, 2, 3]" 323 | check (v.size() == 3) 324 | 325 | block: 326 | var v = initCppVector[string]() 327 | v.add "hi" 328 | v.add "there" 329 | v.add "bye" 330 | check $v == "[hi, there, bye]" 331 | 332 | block: 333 | var v = initCppVector[float](5, 0.0'f64) 334 | check $v == "[0.0, 0.0, 0.0, 0.0, 0.0]" 335 | check v.size() == 5 336 | 337 | test "iterators": 338 | var 339 | refSeq = @["hi", "there", "bye"] 340 | v = toCppVector(refSeq) 341 | 342 | var i = 0 343 | for elem in v: 344 | check elem == refSeq[i] 345 | inc(i) 346 | 347 | for idx, elem in v: 348 | check elem == refSeq[idx] 349 | 350 | test "converting to/from a CppVector/mutable sequence": 351 | var 352 | s = @[1.1, 2.2, 3.3, 4.4, 5.5] 353 | v: CppVector[float] 354 | 355 | v = s.toCppVector() 356 | check v.toSeq() == s 357 | 358 | test "converting from an immutable sequence": 359 | let s = @[1.1, 2.2, 3.3, 4.4, 5.5] 360 | var v: CppVector[float] 361 | 362 | v = s.toCppVector() 363 | check v.toSeq() == s 364 | 365 | test "converting array -> CppVector -> sequence": 366 | let 367 | a = [1.1, 2.2, 3.3, 4.4, 5.5] 368 | v = a.toCppVector() 369 | s = a.toSeq() 370 | 371 | check v.toSeq() == s 372 | 373 | test "assign": 374 | var v: CppVector[char] 375 | 376 | check v.len() == 0 377 | 378 | v.assign(4, '.') 379 | check v.toSeq() == @['.', '.', '.', '.'] 380 | 381 | v.assign(2, 'a') 382 | check v.toSeq() == @['a', 'a'] 383 | 384 | test "set an element value `[]=`": 385 | var v = initCppVector[int](5) 386 | 387 | v[1] = 100 388 | v[3] = 300 389 | check v.toSeq() == @[0, 100, 0, 300, 0] 390 | 391 | test "(c)begin, (c)end, insert": 392 | var v = @[1, 2, 3].toCppVector() 393 | 394 | # insert elem at the beginning 395 | discard v.insert(v.cBegin(), 9) 396 | check v == @[9, 1, 2, 3].toCppVector() 397 | 398 | # Below, using .begin() instead of .cBegin() also 399 | # works.. because of the CppVectorIteratorToCppVectorConstIterator converter. 400 | discard v.insert(v.begin(), 10) 401 | check v == @[10, 9, 1, 2, 3].toCppVector() 402 | 403 | # insert elem at the end 404 | v = @[1, 2, 3].toCppVector() 405 | discard v.insert(v.cEnd(), 9) 406 | check v == @[1, 2, 3, 9].toCppVector() 407 | 408 | # Below, using .`end`() instead of .cEnd() also 409 | # works.. because of the CppVectorIteratorToCppVectorConstIterator converter. 410 | discard v.insert(v.`end`(), 10) 411 | check v == @[1, 2, 3, 9, 10].toCppVector() 412 | 413 | # insert copies of a val 414 | v = @[1, 2, 3].toCppVector() 415 | discard v.insert(v.cEnd(), 3, 111) 416 | check v == @[1, 2, 3, 111, 111, 111].toCppVector() 417 | 418 | # insert elements from a CppVector range 419 | v = @[1, 2, 3].toCppVector() 420 | # Below copies the whole CppVector and appends to itself at the end. 421 | discard v.insert(v.cEnd(), v.cBegin(), v.cEnd()) 422 | check v == @[1, 2, 3, 1, 2, 3].toCppVector() 423 | 424 | # Below is a long-winded way to copy one CppVector to another. 425 | var v2: CppVector[int] 426 | discard v2.insert(v2.cEnd(), v.cBegin(), v.cEnd()) 427 | check v2 == v 428 | 429 | test "iterator arithmetic": 430 | var v = @[1, 2, 3].toCppVector() 431 | 432 | # Insert elem after the first element. 433 | discard v.insert(v.cBegin() + 1, 9) 434 | check v == @[1, 9, 2, 3].toCppVector() 435 | 436 | # Insert elem before the last element. 437 | discard v.insert(v.cEnd() - 1, 9) 438 | check v == @[1, 9, 2, 9, 3].toCppVector() 439 | 440 | test "swap two vectors": 441 | var 442 | v1 = @['a', 'b', 'c'].toCppVector() 443 | v2 = @['w', 'x', 'y', 'z'].toCppVector() 444 | 445 | v1.swap(v2) 446 | check v1 == @['w', 'x', 'y', 'z'].toCppVector() 447 | check v2 == @['a', 'b', 'c'].toCppVector() 448 | 449 | when isMainModule: 450 | main() 451 | 452 | --------------------------------------------------------------------------------