├── tests ├── config.nims ├── traw_pointer.nim ├── tbasic.nim └── titerators.nim ├── ptr_math.nimble ├── config.nims ├── .gitignore ├── .github └── workflows │ ├── README.md │ ├── test.yml │ └── docs.yml ├── LICENSE ├── README.org └── src └── ptr_math.nim /tests/config.nims: -------------------------------------------------------------------------------- 1 | switch("path", "$projectDir/../src") -------------------------------------------------------------------------------- /ptr_math.nimble: -------------------------------------------------------------------------------- 1 | # Package 2 | 3 | version = "0.6.0" 4 | author = "Kaushal Modi" 5 | description = "Pointer arithmetic library" 6 | license = "MIT" 7 | srcDir = "src" 8 | 9 | 10 | # Dependencies 11 | 12 | requires "nim >= 1.4.6" -------------------------------------------------------------------------------- /config.nims: -------------------------------------------------------------------------------- 1 | task pullConfig, "Fetch my global config.nims": 2 | exec("git submodule add -f -b master https://github.com/kaushalmodi/nim_config") 3 | when fileExists("nim_config/config.nims"): 4 | include "nim_config/config.nims" # This gives "nim test" and "nim docs" that's run on Travis 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # https://stackoverflow.com/a/25592735/1219634 2 | 3 | # Ignore all 4 | * 5 | 6 | # Unignore all with extensions 7 | !*.* 8 | 9 | # Unignore all dirs 10 | !*/ 11 | 12 | # Unignore few files 13 | !LICENSE 14 | 15 | #*.*# 16 | *#*.*# 17 | 18 | public/ 19 | *.html 20 | nimdoc.out.css 21 | -------------------------------------------------------------------------------- /.github/workflows/README.md: -------------------------------------------------------------------------------- 1 | # GitHub Actions references 2 | 3 | - https://docs.github.com/en/actions/learn-github-actions/introduction-to-github-actions 4 | - https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#on 5 | - https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobs 6 | - https://github.com/nim-lang/Nim/wiki/BuildServices#github-actions 7 | - https://github.com/marketplace/actions/github-pages-action 8 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: RunTests 2 | 3 | on: 4 | workflow_dispatch: # Manually trigger this workflow 5 | pull_request: 6 | types: 7 | - '*' 8 | push: 9 | schedule: 10 | # Every week: https://crontab.guru/#0_0_*_*_0 11 | - cron: '0 0 * * 0' 12 | 13 | jobs: 14 | run_tests: 15 | # runs-on: ubuntu-latest 16 | runs-on: ${{ matrix.os }} 17 | strategy: 18 | matrix: 19 | os: [ubuntu-latest, windows-latest, macos-latest] 20 | nim: ['devel', 'version-1-6', 'version-1-4'] 21 | steps: 22 | - uses: actions/checkout@v2 23 | - uses: alaviss/setup-nim@0.1.1 24 | with: 25 | path: 'nim' 26 | version: ${{ matrix.nim }} 27 | - name: Pull kaushalmodi's global config.nims 28 | run: nim pullConfig 29 | - name: Run tests 30 | run: nim test 31 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: GenerateDocs 2 | 3 | on: 4 | workflow_dispatch: # Manually trigger this workflow 5 | push: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | gen_docs: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: alaviss/setup-nim@0.1.1 15 | with: 16 | path: 'nim' 17 | version: 'devel' 18 | - name: Pull kaushalmodi's global config.nims 19 | run: nim pullConfig 20 | - name: Generate docs 21 | run: nim docs 22 | - name: Deploy to GitHub Pages 23 | uses: peaceiris/actions-gh-pages@v3.7.3 24 | with: 25 | # Note that the GITHUB_TOKEN is NOT a personal access 26 | # token. A GitHub Actions runner automatically creates a 27 | # GITHUB_TOKEN secret to authenticate in your workflow. 28 | github_token: ${{ secrets.GITHUB_TOKEN }} 29 | publish_dir: ./public 30 | -------------------------------------------------------------------------------- /tests/traw_pointer.nim: -------------------------------------------------------------------------------- 1 | import std/[unittest] 2 | import ptr_math 3 | 4 | suite "raw pointer math": 5 | setup: 6 | type 7 | MyObject = object 8 | i: int 9 | f: float 10 | b: bool 11 | 12 | var 13 | a = [MyObject(i: 100, f: 2.3, b: true), 14 | MyObject(i: 300, f: 4.5, b: false), 15 | MyObject(i: 500, f: 6.7, b: true)] 16 | p = cast[pointer](addr(a[0])) 17 | 18 | test "incr ptr": 19 | p = p + (1*sizeof(MyObject)) 20 | check cast[ptr MyObject](p)[0].i == 300 21 | 22 | test "decr ptr": 23 | p = cast[pointer](addr(a[2])) 24 | p = p - (1*sizeof(MyObject)) 25 | check cast[ptr MyObject](p)[0].f == 4.5 26 | 27 | test "inplace incr ptr": 28 | p += (2*sizeof(MyObject)) 29 | check cast[ptr MyObject](p)[0].i == 500 30 | cast[ptr MyObject](p)[0].f = 7.89 31 | check a[2].f == 7.89 32 | 33 | test "inplace decr ptr": 34 | p = addr(a[2]) 35 | p -= (1*sizeof(MyObject)) 36 | check cast[ptr MyObject](p)[-1].i == 100 37 | cast[ptr MyObject](p)[1].f = 456.789 38 | check a[2] == MyObject(i: 500, f: 456.789, b: true) 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Kaushal Modi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/tbasic.nim: -------------------------------------------------------------------------------- 1 | import std/[unittest] 2 | import ptr_math 3 | 4 | suite "basic": 5 | setup: 6 | type 7 | MyObject = object 8 | i: int 9 | f: float 10 | b: bool 11 | 12 | var 13 | a = [MyObject(i: 100, f: 2.3, b: true), 14 | MyObject(i: 300, f: 4.5, b: false), 15 | MyObject(i: 500, f: 6.7, b: true)] 16 | p = addr(a[0]) 17 | 18 | test "incr ptr": 19 | p = p + 1 20 | check p[0].i == 300 21 | 22 | test "decr ptr": 23 | p = addr(a[2]) 24 | p = p - 1 25 | check p[0].f == 4.5 26 | 27 | test "retrieve value `[]`": 28 | p = addr(a[1]) 29 | check p[0] == a[1] 30 | check p[1] == a[2] 31 | check p[-1] == a[0] 32 | 33 | test "assign value `[]=`": 34 | p[1].f = 123.456 35 | check a[1].f == 123.456 36 | p[2] = MyObject(i: 11, f: 2.2, b: false) 37 | check a[2] == MyObject(i: 11, f: 2.2, b: false) 38 | 39 | test "inplace incr ptr": 40 | p += 2 41 | check p[0].i == 500 42 | p[0].f = 7.89 43 | check a[2].f == 7.89 44 | 45 | test "inplace decr ptr": 46 | p = addr(a[2]) 47 | p -= 1 48 | check p[-1].i == 100 49 | p[1].f = 456.789 50 | check a[2] == MyObject(i: 500, f: 456.789, b: true) 51 | 52 | test "immutable pointer": 53 | let 54 | pImm = addr(a[1]) 55 | check pImm[-1].i == 100 56 | check pImm[0].i == 300 57 | check pImm[1].i == 500 58 | # Below tests that pImm itself isn't getting modified, but in fact 59 | # pImm[0] is auto-dereferencing to a[1], and a is mutable. 60 | pImm[0] = MyObject(i: 1, f: 2.0, b: false) 61 | check a[1] == MyObject(i: 1, f: 2.0, b: false) 62 | 63 | test "unsigned integer offset": 64 | p = addr(a[0]) 65 | p += 1'u 66 | check p[1'u8].i == 500 67 | p[1'u32].i = 10 68 | check a[2].i == 10 -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | #+title: Pointer Arithmetic in Nim 2 | #+author: Kaushal Modi 3 | 4 | [[https://github.com/kaushalmodi/ptr_math/actions/workflows/test.yml][https://github.com/kaushalmodi/ptr_math/actions/workflows/test.yml/badge.svg]] 5 | [[https://github.com/kaushalmodi/ptr_math/actions/workflows/docs.yml][https://github.com/kaushalmodi/ptr_math/actions/workflows/docs.yml/badge.svg]] 6 | 7 | This module implements basic pointer arithmetic functionality. 8 | 9 | * Documentation 10 | [[https://kaushalmodi.github.io/ptr_math/][https://kaushalmodi.github.io/ptr_math/]] 11 | * Installation 12 | #+begin_example 13 | nimble install ptr_math 14 | #+end_example 15 | * Quick Start 16 | #+begin_src nim 17 | import std/[strformat] 18 | import ptr_math 19 | 20 | var 21 | a: array[0 .. 3, int] 22 | p = addr(a[0]) # p is pointing to a[0] 23 | 24 | for i, _ in a: 25 | a[i] += i 26 | echo &"before : a = {a}" 27 | 28 | p += 1 # p is now pointing to a[1] 29 | p[] = 100 # p[] is accessing the contents of a[1] 30 | echo &"after p += 1; p[] = 100 : a = {a}" 31 | 32 | p[0] = 200 # .. so does p[0] 33 | echo &"after p[0] = 200 : a = {a}" 34 | 35 | p[1] -= 2 # p[1] is accessing the contents of a[2] 36 | echo &"after p[1] -= 2 : a = {a}" 37 | 38 | p[2] += 50 # p[2] is accessing the contents of a[3] 39 | echo &"after p[2] += 50 : a = {a}" 40 | 41 | p += 2 # p is now pointing to a[3] 42 | p[-1] += 77 # p[-1] is accessing the contents of a[2] 43 | echo &"after p += 2; p[-1] += 77 : a = {a}" 44 | 45 | echo &"a[0] = p[-3] = {p[-3]}" 46 | echo &"a[1] = p[-2] = {p[-2]}" 47 | echo &"a[2] = p[-1] = {p[-1]}" 48 | echo &"a[3] = p[0] = {p[0]}" 49 | #+end_src 50 | 51 | * Development 52 | ** Requirement 53 | This library is tested using Nim /devel/ version. The version was 54 | 1.5.1 as of writing this on <2021-06-03 Thu>. 55 | ** Prep 56 | Once you clone this repo, cd to the cloned directory and run the below 57 | command *first* (before you execute any of the below "nim" commands): 58 | #+begin_example 59 | nim pullConfig 60 | #+end_example 61 | This will clone my global ~config.nims~ file into a 62 | ~/nim_config/~ directory. That will enable running the ~nim 63 | test~ and ~nim docs~ commands. 64 | ** Testing 65 | #+begin_example 66 | nim test 67 | #+end_example 68 | ** Generate doc 69 | Create the HTML page and associated search index in ~/public/~. 70 | #+begin_example 71 | nim docs 72 | #+end_example 73 | 74 | * Credit 75 | Most of the code in this library is from [[https://forum.nim-lang.org/t/1188#7366][this code snippet]] authored by 76 | Nim Forum user /Jehan/. 77 | -------------------------------------------------------------------------------- /tests/titerators.nim: -------------------------------------------------------------------------------- 1 | import std/[unittest] 2 | import ptr_math 3 | 4 | suite "iterators": 5 | setup: 6 | type 7 | MyObject = object 8 | i: int 9 | f: float 10 | b: bool 11 | 12 | var 13 | a = [MyObject(i: 100, f: 2.3, b: true), 14 | MyObject(i: 300, f: 4.5, b: false), 15 | MyObject(i: 500, f: 6.7, b: true)] 16 | p = addr(a[0]) 17 | 18 | test "items ptr, from start excluding end": 19 | var pend = p + a.len 20 | var i = 0 21 | for it in items(p, pend): 22 | check it.i == a[i].i 23 | inc i 24 | 25 | test "mitems ptr, from start excluding end": 26 | var pend = p + a.len 27 | for it in mitems(p, pend): 28 | inc it.i 29 | check a[2].i == 501 30 | 31 | test "items UncheckedArray[T] | ptr T with length": 32 | var i = 0 33 | for it in items(p, a.len): 34 | check it.i == a[i].i 35 | inc i 36 | 37 | i = 0 38 | for it in items(p, a.len.uint): # test unsigned length 39 | check it.i == a[i].i 40 | inc i 41 | 42 | var u = cast[ptr UncheckedArray[MyObject]](a[0].addr) 43 | i = 0 44 | for it in items(u[], a.len): 45 | check it.i == a[i].i 46 | inc i 47 | 48 | 49 | test "mitems UncheckedArray with length": 50 | var u = cast[ptr UncheckedArray[MyObject]](a[0].addr) 51 | for it in mitems(u[], a.len): 52 | inc it.i 53 | check a[2].i == 501 54 | 55 | for it in mitems(u[], a.len.uint): 56 | inc it.i 57 | check a[2].i == 502 58 | 59 | test "mitems ptr with length": 60 | for it in mitems(p, a.len): 61 | inc it.i 62 | check a[2].i == 501 63 | 64 | for it in mitems(p, a.len.uint): 65 | inc it.i 66 | check a[2].i == 502 67 | 68 | test "pairs UncheckedArray[T] | ptr T with len": 69 | for i, it in pairs(p, a.len): 70 | check it.i == a[i].i 71 | 72 | for i, it in pairs(p, a.len.uint): # test unsigned length 73 | check it.i == a[i].i 74 | 75 | var u = cast[ptr UncheckedArray[MyObject]](a[0].addr) 76 | for i, it in pairs(u[], a.len): 77 | check it.i == a[i].i 78 | 79 | test "mpairs UncheckedArray with length": 80 | var u = cast[ptr UncheckedArray[MyObject]](a[0].addr) 81 | for i, it in mpairs(u[], a.len): 82 | check a[i] == it 83 | 84 | for i, it in mpairs(u[], a.len.uint): 85 | check a[i] == it 86 | 87 | test "mpairs ptr with length": 88 | for i, it in mpairs(p, a.len): 89 | check a[i] == it 90 | 91 | for i, it in mpairs(p, a.len.uint): 92 | check a[i] == it 93 | 94 | test "rows": 95 | var l = 3 96 | var ar = [100, 300, 500] 97 | var b = ['a', 'e', 'i'] 98 | var c = [1.1, 2.2, 3.3] 99 | var pa = ar[0].addr 100 | var pb = b[0].addr 101 | var pc = cast[ptr UncheckedArray[float]](c[0].addr) 102 | 103 | var tuples:seq[(int, int, char, float)] 104 | for i, ta, tb, tc in rows(pa, pb, pc[], l): 105 | tuples.add (i, ta, tb, tc) 106 | 107 | check tuples[^1][0] == l-1 108 | check tuples[^1][3] == 3.3 109 | 110 | test "mrows": 111 | var l = 3 112 | var ar = [100, 300, 500] 113 | var b = ['a', 'e', 'i'] 114 | var c = [1.1, 2.2, 3.3] 115 | var pa = ar[0].addr 116 | var pb = b[0].addr 117 | var pc = cast[ptr UncheckedArray[float]](c[0].addr) 118 | 119 | var tuples:seq[(int, int, char, float)] 120 | for i, ta, tb, tc in mrows(pa, pb, pc[], l): 121 | inc ta 122 | tuples.add (i, ta, tb, tc) 123 | 124 | doAssert(tuples[^1][0] == l-1) 125 | doAssert(tuples[^1][3] == 3.3) 126 | doAssert(tuples[0][1] == 101) -------------------------------------------------------------------------------- /src/ptr_math.nim: -------------------------------------------------------------------------------- 1 | ## :Author: Kaushal Modi 2 | ## :License: MIT 3 | ## 4 | ## Introduction 5 | ## ============ 6 | ## This module implements basic Pointer Arithmetic functions. 7 | ## 8 | ## Source 9 | ## ====== 10 | ## `Repo link `_ 11 | ## 12 | ## The code in this module is mostly from `this code snippet `_ on Nim Forum. 13 | import std / [macros, decls] 14 | export decls 15 | 16 | runnableExamples: 17 | var 18 | a: array[0 .. 3, int] 19 | p = addr(a[0]) # p is pointing to a[0] 20 | 21 | for i, _ in a: 22 | a[i] += i 23 | 24 | p += 1 # p is now pointing to a[1] 25 | p[] = 100 # p[] is accessing the contents of a[1] 26 | doAssert a[1] == 100 27 | 28 | p[0] = 200 # .. so does p[0] 29 | doAssert a[1] == 200 30 | 31 | p[1] -= 2 # p[1] is accessing the contents of a[2] 32 | doAssert a[2] == 0 33 | 34 | p[2] += 50 # p[2] is accessing the contents of a[3] 35 | doAssert a[3] == 53 36 | 37 | p += 2 # p is now pointing to a[3] 38 | p[-1] += 77 # p[-1] is accessing the contents of a[2] 39 | doAssert a[2] == 77 40 | 41 | doAssert a == [0, 200, 77, 53] 42 | ## 43 | 44 | proc `+`*[T; S: SomeInteger](p: ptr T, offset: S): ptr T = 45 | ## Increments pointer `p` by `offset` that jumps memory in increments of 46 | ## the size of `T`. 47 | runnableExamples: 48 | type 49 | MyObject = object 50 | i: int 51 | f: float 52 | b: bool 53 | var 54 | a = [MyObject(i: 100, f: 2.3, b: true), 55 | MyObject(i: 300, f: 4.5, b: false), 56 | MyObject(i: 500, f: 6.7, b: true)] 57 | p = addr(a[0]) 58 | p2 = p + 2 59 | 60 | doAssert p2[0].i == 500 61 | doAssert p2[-1].f == 4.5 62 | ## 63 | return cast[ptr T](cast[ByteAddress](p) +% (int(offset) * sizeof(T))) 64 | # `+%` treats x and y inputs as unsigned 65 | # and adds them: https://nim-lang.github.io/Nim/system.html#%2B%25%2Cint%2Cint 66 | 67 | proc `+`*[S: SomeInteger](p: pointer, offset: S): pointer = 68 | ## Increments pointer `p` by `offset` that jumps memory in increments of 69 | ## single bytes. 70 | runnableExamples: 71 | type 72 | MyObject = object 73 | i: int 74 | f: float 75 | b: bool 76 | var 77 | a = [MyObject(i: 100, f: 2.3, b: true), 78 | MyObject(i: 300, f: 4.5, b: false), 79 | MyObject(i: 500, f: 6.7, b: true)] 80 | p = cast[pointer](addr(a[0])) 81 | p2 = p + (2*sizeof(MyObject)) 82 | 83 | doAssert cast[ptr MyObject](p2)[0].i == 500 84 | doAssert cast[ptr MyObject](p2)[-1].f == 4.5 85 | ## 86 | return cast[pointer](cast[ByteAddress](p) +% int(offset)) 87 | 88 | proc `-`*[T; S: SomeInteger](p: ptr T, offset: S): ptr T = 89 | ## Decrements pointer `p` by `offset` that jumps memory in increments of 90 | ## the size of `T`. 91 | runnableExamples: 92 | type 93 | MyObject = object 94 | i: int 95 | f: float 96 | b: bool 97 | var 98 | a = [MyObject(i: 100, f: 2.3, b: true), 99 | MyObject(i: 300, f: 4.5, b: false), 100 | MyObject(i: 500, f: 6.7, b: true)] 101 | p = addr(a[2]) 102 | p1 = p - 1 103 | doAssert p1[0].i == 300 104 | doAssert p1[-1].b == true 105 | doAssert p1[1].f == 6.7 106 | ## 107 | return cast[ptr T](cast[ByteAddress](p) -% (int(offset) * sizeof(T))) 108 | 109 | proc `-`*[S: SomeInteger](p: pointer, offset: S): pointer = 110 | ## Decrements pointer `p` by `offset` that jumps memory in increments of 111 | ## single bytes. 112 | runnableExamples: 113 | type 114 | MyObject = object 115 | i: int 116 | f: float 117 | b: bool 118 | var 119 | a = [MyObject(i: 100, f: 2.3, b: true), 120 | MyObject(i: 300, f: 4.5, b: false), 121 | MyObject(i: 500, f: 6.7, b: true)] 122 | p = cast[pointer](addr(a[2])) 123 | p1 = p - (1*sizeof(MyObject)) 124 | doAssert cast[ptr MyObject](p1)[0].i == 300 125 | doAssert cast[ptr MyObject](p1)[-1].b == true 126 | doAssert cast[ptr MyObject](p1)[1].f == 6.7 127 | ## 128 | return cast[pointer](cast[ByteAddress](p) -% int(offset)) 129 | 130 | proc `+=`*[T; S: SomeInteger](p: var ptr T, offset: S) = 131 | ## Increments pointer `p` *in place* by `offset` that jumps memory 132 | ## in increments of the size of `T`. 133 | runnableExamples: 134 | type 135 | MyObject = object 136 | i: int 137 | f: float 138 | b: bool 139 | var 140 | a = [MyObject(i: 100, f: 2.3, b: true), 141 | MyObject(i: 300, f: 4.5, b: false), 142 | MyObject(i: 500, f: 6.7, b: true)] 143 | p = addr(a[0]) 144 | 145 | p += 1 146 | doAssert p[].i == 300 147 | ## 148 | p = p + offset 149 | 150 | proc `+=`*[S: SomeInteger](p: var pointer, offset: S) = 151 | ## Increments pointer `p` *in place* by `offset` that jumps memory 152 | ## in increments of single bytes. 153 | runnableExamples: 154 | type 155 | MyObject = object 156 | i: int 157 | f: float 158 | b: bool 159 | var 160 | a = [MyObject(i: 100, f: 2.3, b: true), 161 | MyObject(i: 300, f: 4.5, b: false), 162 | MyObject(i: 500, f: 6.7, b: true)] 163 | p = cast[pointer](addr(a[0])) 164 | 165 | p += (1*sizeof(MyObject)) 166 | doAssert cast[ptr MyObject](p)[].i == 300 167 | ## 168 | p = p + offset 169 | 170 | proc `-=`*[T; S: SomeInteger](p: var ptr T, offset: S) = 171 | ## Decrements pointer `p` *in place* by `offset` that jumps memory 172 | ## in increments of the size of `T`. 173 | runnableExamples: 174 | type 175 | MyObject = object 176 | i: int 177 | f: float 178 | b: bool 179 | var 180 | a = [MyObject(i: 100, f: 2.3, b: true), 181 | MyObject(i: 300, f: 4.5, b: false), 182 | MyObject(i: 500, f: 6.7, b: true)] 183 | p = addr(a[2]) 184 | 185 | p -= 2 186 | doAssert p[].f == 2.3 187 | ## 188 | p = p - offset 189 | 190 | proc `-=`*[S: SomeInteger](p: var pointer, offset: S) = 191 | ## Decrements pointer `p` *in place* by `offset` that jumps memory 192 | ## in increments of single bytes. 193 | runnableExamples: 194 | type 195 | MyObject = object 196 | i: int 197 | f: float 198 | b: bool 199 | var 200 | a = [MyObject(i: 100, f: 2.3, b: true), 201 | MyObject(i: 300, f: 4.5, b: false), 202 | MyObject(i: 500, f: 6.7, b: true)] 203 | p = cast[pointer](addr(a[2])) 204 | 205 | p -= (2*sizeof(MyObject)) 206 | doAssert cast[ptr MyObject](p)[].f == 2.3 207 | ## 208 | p = p - offset 209 | 210 | proc `[]=`*[T; S: SomeInteger](p: ptr T, offset: S, val: T) = 211 | ## Assigns the value at memory location pointed by `p[offset]`. 212 | runnableExamples: 213 | var 214 | a = [1.3, -9.5, 100.0] 215 | p = addr(a[1]) 216 | 217 | p[0] = 123.456 218 | doAssert a[1] == 123.456 219 | ## 220 | (p + offset)[] = val 221 | 222 | proc `[]`*[T; S: SomeInteger](p: ptr T, offset: S): var T = 223 | ## Retrieves the value from `p[offset]`. 224 | runnableExamples: 225 | var 226 | a = [1, 3, 5, 7] 227 | p = addr(a[0]) 228 | 229 | doAssert p[] == a[0] 230 | doAssert p[0] == a[0] 231 | doAssert p[2] == a[2] 232 | ## 233 | return (p + offset)[] 234 | 235 | 236 | iterator items*[T](start: ptr T, stopBefore: ptr T): lent T = 237 | ## Iterates over contiguous `ptr T`s, from `start` excluding `stopBefore`. Yields immutable `T`. 238 | runnableExamples: 239 | var 240 | a = [1, 3, 5, 7] 241 | p = addr(a[0]) 242 | e = p + a.len 243 | sum = 0 244 | for i in items(p, e): 245 | sum += i 246 | doAssert(sum == 16) 247 | ## 248 | var p = start 249 | while p != stopBefore: 250 | yield p[] 251 | p += 1 252 | 253 | iterator mitems*[T](start: ptr T, stopBefore: ptr T): var T = 254 | ## Iterates over contiguous `ptr T`s, from `start` excluding `stopBefore`. Yields mutable `T`. 255 | runnableExamples: 256 | var 257 | a = [1, 3, 5, 7] 258 | p = addr(a[0]) 259 | e = p + a.len 260 | sum = 0 261 | for i in mitems(p, e): 262 | inc i 263 | for i in items(p, e): 264 | sum += i 265 | doAssert(sum == 20) 266 | ## 267 | var p = start 268 | while p != stopBefore: 269 | yield p[] 270 | p += 1 271 | 272 | iterator items*[T](uarray: UncheckedArray[T] | ptr T, len: SomeInteger): lent T = 273 | ## Iterates over `UncheckedArray[T]` or `ptr T` array with length. Yields immutable `T`. 274 | runnableExamples: 275 | let 276 | l = 4 277 | a = cast[ptr UncheckedArray[int]](alloc0(sizeof(int) * l)) 278 | b = [1, 3, 5, 7] 279 | 280 | copyMem(a, b[0].unsafeAddr, sizeof(int) * l) 281 | var i = 0 282 | for val in items(a[], l): 283 | doAssert(val == b[i]) 284 | inc i 285 | 286 | let 287 | p = cast[ptr int](a) 288 | i = 0 289 | for val in items(p, l): 290 | doAssert(val == b[i]) 291 | inc i 292 | dealloc(a) 293 | ## 294 | for i in 0..