Added cmpMem export (#16484)

* added cmpMem export

* updates

* fix test

* Tiny changelog change

* Add a dot.

Co-authored-by: Clyybber <darkmine956@gmail.com>
This commit is contained in:
Antonis Geralis 2020-12-29 14:27:08 +02:00 • committed by GitHub
commit d5a3c2c2da
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 81 additions and 49 deletions

View file

@ -36,6 +36,8 @@
- `nodejs` backend now supports osenv: `getEnv`, `putEnv`, `envPairs`, `delEnv`, `existsEnv`. - `nodejs` backend now supports osenv: `getEnv`, `putEnv`, `envPairs`, `delEnv`, `existsEnv`.
- Added `cmpMem` to `system`.
- `doAssertRaises` now correctly handles foreign exceptions. - `doAssertRaises` now correctly handles foreign exceptions.
- Added `asyncdispatch.activeDescriptors` that returns the number of currently - Added `asyncdispatch.activeDescriptors` that returns the number of currently
@ -57,7 +59,7 @@
- Added `decodeQuery` to `std/uri`. - Added `decodeQuery` to `std/uri`.
- `strscans.scanf` now supports parsing single characters. - `strscans.scanf` now supports parsing single characters.
- `strscans.scanTuple` added which uses `strscans.scanf` internally, returning a tuple which can be unpacked for easier usage of `scanf`. - `strscans.scanTuple` added which uses `strscans.scanf` internally, returning a tuple which can be unpacked for easier usage of `scanf`.
- Added `setutils.toSet` that can take any iterable and convert it to a built-in set, - Added `setutils.toSet` that can take any iterable and convert it to a built-in set,
if the iterable yields a built-in settable type. if the iterable yields a built-in settable type.
@ -71,7 +73,7 @@
and `lists.toDoublyLinkedList` convert from `openArray`s; `lists.copy` implements and `lists.toDoublyLinkedList` convert from `openArray`s; `lists.copy` implements
shallow copying; `lists.add` concatenates two lists - an O(1) variation that consumes shallow copying; `lists.add` concatenates two lists - an O(1) variation that consumes
its argument, `addMoved`, is also supplied. its argument, `addMoved`, is also supplied.
- Added `sequtils` import to `prelude`. - Added `sequtils` import to `prelude`.
- Added `euclDiv` and `euclMod` to `math`. - Added `euclDiv` and `euclMod` to `math`.

View file

@ -2182,6 +2182,8 @@ when notJSnotNims:
memTrackerOp("moveMem", dest, size) memTrackerOp("moveMem", dest, size)
proc equalMem(a, b: pointer, size: Natural): bool = proc equalMem(a, b: pointer, size: Natural): bool =
nimCmpMem(a, b, size) == 0 nimCmpMem(a, b, size) == 0
proc cmpMem(a, b: pointer, size: Natural): int =
nimCmpMem(a, b, size)
when not defined(js): when not defined(js):
proc cmp(x, y: string): int = proc cmp(x, y: string): int =

View file

@ -1,38 +1,51 @@
when notJSnotNims: when notJSnotNims:
proc zeroMem*(p: pointer, size: Natural) {.inline, noSideEffect, proc zeroMem*(p: pointer, size: Natural) {.inline, noSideEffect,
tags: [], locks: 0, raises: [].} tags: [], locks: 0, raises: [].}
## Overwrites the contents of the memory at ``p`` with the value 0. ## Overwrites the contents of the memory at `p` with the value 0.
## ##
## Exactly ``size`` bytes will be overwritten. Like any procedure ## Exactly `size` bytes will be overwritten. Like any procedure
## dealing with raw memory this is **unsafe**. ## dealing with raw memory this is **unsafe**.
proc copyMem*(dest, source: pointer, size: Natural) {.inline, benign, proc copyMem*(dest, source: pointer, size: Natural) {.inline, benign,
tags: [], locks: 0, raises: [].} tags: [], locks: 0, raises: [].}
## Copies the contents from the memory at ``source`` to the memory ## Copies the contents from the memory at `source` to the memory
## at ``dest``. ## at `dest`.
## Exactly ``size`` bytes will be copied. The memory ## Exactly `size` bytes will be copied. The memory
## regions may not overlap. Like any procedure dealing with raw ## regions may not overlap. Like any procedure dealing with raw
## memory this is **unsafe**. ## memory this is **unsafe**.
proc moveMem*(dest, source: pointer, size: Natural) {.inline, benign, proc moveMem*(dest, source: pointer, size: Natural) {.inline, benign,
tags: [], locks: 0, raises: [].} tags: [], locks: 0, raises: [].}
## Copies the contents from the memory at ``source`` to the memory ## Copies the contents from the memory at `source` to the memory
## at ``dest``. ## at `dest`.
## ##
## Exactly ``size`` bytes will be copied. The memory ## Exactly `size` bytes will be copied. The memory
## regions may overlap, ``moveMem`` handles this case appropriately ## regions may overlap, `moveMem` handles this case appropriately
## and is thus somewhat more safe than ``copyMem``. Like any procedure ## and is thus somewhat more safe than `copyMem`. Like any procedure
## dealing with raw memory this is still **unsafe**, though. ## dealing with raw memory this is still **unsafe**, though.
proc equalMem*(a, b: pointer, size: Natural): bool {.inline, noSideEffect, proc equalMem*(a, b: pointer, size: Natural): bool {.inline, noSideEffect,
tags: [], locks: 0, raises: [].} tags: [], locks: 0, raises: [].}
## Compares the memory blocks ``a`` and ``b``. ``size`` bytes will ## Compares the memory blocks `a` and `b`. `size` bytes will
## be compared. ## be compared.
## ##
## If the blocks are equal, `true` is returned, `false` ## If the blocks are equal, `true` is returned, `false`
## otherwise. Like any procedure dealing with raw memory this is ## otherwise. Like any procedure dealing with raw memory this is
## **unsafe**. ## **unsafe**.
proc cmpMem*(a, b: pointer, size: Natural): int {.inline, noSideEffect,
tags: [], locks: 0, raises: [].}
## Compares the memory blocks `a` and `b`. `size` bytes will
## be compared.
##
## Returns:
## * a value less than zero, if `a < b`
## * a value greater than zero, if `a > b`
## * zero, if `a == b`
##
## Like any procedure dealing with raw memory this is
## **unsafe**.
when hasAlloc and not defined(js): when hasAlloc and not defined(js):
proc allocImpl*(size: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].} proc allocImpl*(size: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].}
@ -75,7 +88,7 @@ when hasAlloc and not defined(js):
proc getAllocStats*(): AllocStats = discard proc getAllocStats*(): AllocStats = discard
template alloc*(size: Natural): pointer = template alloc*(size: Natural): pointer =
## Allocates a new memory block with at least ``size`` bytes. ## Allocates a new memory block with at least `size` bytes.
## ##
## The block has to be freed with `realloc(block, 0) <#realloc.t,pointer,Natural>`_ ## The block has to be freed with `realloc(block, 0) <#realloc.t,pointer,Natural>`_
## or `dealloc(block) <#dealloc,pointer>`_. ## or `dealloc(block) <#dealloc,pointer>`_.
@ -91,7 +104,7 @@ when hasAlloc and not defined(js):
allocImpl(size) allocImpl(size)
proc createU*(T: typedesc, size = 1.Positive): ptr T {.inline, benign, raises: [].} = proc createU*(T: typedesc, size = 1.Positive): ptr T {.inline, benign, raises: [].} =
## Allocates a new memory block with at least ``T.sizeof * size`` bytes. ## Allocates a new memory block with at least `T.sizeof * size` bytes.
## ##
## The block has to be freed with `resize(block, 0) <#resize,ptr.T,Natural>`_ ## The block has to be freed with `resize(block, 0) <#resize,ptr.T,Natural>`_
## or `dealloc(block) <#dealloc,pointer>`_. ## or `dealloc(block) <#dealloc,pointer>`_.
@ -106,7 +119,7 @@ when hasAlloc and not defined(js):
cast[ptr T](alloc(T.sizeof * size)) cast[ptr T](alloc(T.sizeof * size))
template alloc0*(size: Natural): pointer = template alloc0*(size: Natural): pointer =
## Allocates a new memory block with at least ``size`` bytes. ## Allocates a new memory block with at least `size` bytes.
## ##
## The block has to be freed with `realloc(block, 0) <#realloc.t,pointer,Natural>`_ ## The block has to be freed with `realloc(block, 0) <#realloc.t,pointer,Natural>`_
## or `dealloc(block) <#dealloc,pointer>`_. ## or `dealloc(block) <#dealloc,pointer>`_.
@ -119,7 +132,7 @@ when hasAlloc and not defined(js):
alloc0Impl(size) alloc0Impl(size)
proc create*(T: typedesc, size = 1.Positive): ptr T {.inline, benign, raises: [].} = proc create*(T: typedesc, size = 1.Positive): ptr T {.inline, benign, raises: [].} =
## Allocates a new memory block with at least ``T.sizeof * size`` bytes. ## Allocates a new memory block with at least `T.sizeof * size` bytes.
## ##
## The block has to be freed with `resize(block, 0) <#resize,ptr.T,Natural>`_ ## The block has to be freed with `resize(block, 0) <#resize,ptr.T,Natural>`_
## or `dealloc(block) <#dealloc,pointer>`_. ## or `dealloc(block) <#dealloc,pointer>`_.
@ -134,8 +147,8 @@ when hasAlloc and not defined(js):
## Grows or shrinks a given memory block. ## Grows or shrinks a given memory block.
## ##
## If `p` is **nil** then a new memory block is returned. ## If `p` is **nil** then a new memory block is returned.
## In either way the block has at least ``newSize`` bytes. ## In either way the block has at least `newSize` bytes.
## If ``newSize == 0`` and `p` is not **nil** ``realloc`` calls ``dealloc(p)``. ## If `newSize == 0` and `p` is not **nil** `realloc` calls `dealloc(p)`.
## In other cases the block has to be freed with ## In other cases the block has to be freed with
## `dealloc(block) <#dealloc,pointer>`_. ## `dealloc(block) <#dealloc,pointer>`_.
## ##
@ -148,8 +161,8 @@ when hasAlloc and not defined(js):
## Grows or shrinks a given memory block. ## Grows or shrinks a given memory block.
## ##
## If `p` is **nil** then a new memory block is returned. ## If `p` is **nil** then a new memory block is returned.
## In either way the block has at least ``newSize`` bytes. ## In either way the block has at least `newSize` bytes.
## If ``newSize == 0`` and `p` is not **nil** ``realloc`` calls ``dealloc(p)``. ## If `newSize == 0` and `p` is not **nil** `realloc` calls `dealloc(p)`.
## In other cases the block has to be freed with ## In other cases the block has to be freed with
## `dealloc(block) <#dealloc,pointer>`_. ## `dealloc(block) <#dealloc,pointer>`_.
## ##
@ -165,9 +178,9 @@ when hasAlloc and not defined(js):
## Grows or shrinks a given memory block. ## Grows or shrinks a given memory block.
## ##
## If `p` is **nil** then a new memory block is returned. ## If `p` is **nil** then a new memory block is returned.
## In either way the block has at least ``T.sizeof * newSize`` bytes. ## In either way the block has at least `T.sizeof * newSize` bytes.
## If ``newSize == 0`` and `p` is not **nil** ``resize`` calls ``dealloc(p)``. ## If `newSize == 0` and `p` is not **nil** `resize` calls `dealloc(p)`.
## In other cases the block has to be freed with ``free``. ## In other cases the block has to be freed with `free`.
## ##
## The allocated memory belongs to its allocating thread! ## The allocated memory belongs to its allocating thread!
## Use `resizeShared <#resizeShared,ptr.T,Natural>`_ to reallocate ## Use `resizeShared <#resizeShared,ptr.T,Natural>`_ to reallocate
@ -175,8 +188,8 @@ when hasAlloc and not defined(js):
cast[ptr T](realloc(p, T.sizeof * newSize)) cast[ptr T](realloc(p, T.sizeof * newSize))
proc dealloc*(p: pointer) {.noconv, compilerproc, rtl, benign, raises: [], tags: [].} = proc dealloc*(p: pointer) {.noconv, compilerproc, rtl, benign, raises: [], tags: [].} =
## Frees the memory allocated with ``alloc``, ``alloc0`` or ## Frees the memory allocated with `alloc`, `alloc0` or
## ``realloc``. ## `realloc`.
## ##
## **This procedure is dangerous!** ## **This procedure is dangerous!**
## If one forgets to free the memory a leak occurs; if one tries to ## If one forgets to free the memory a leak occurs; if one tries to
@ -190,7 +203,7 @@ when hasAlloc and not defined(js):
template allocShared*(size: Natural): pointer = template allocShared*(size: Natural): pointer =
## Allocates a new memory block on the shared heap with at ## Allocates a new memory block on the shared heap with at
## least ``size`` bytes. ## least `size` bytes.
## ##
## The block has to be freed with ## The block has to be freed with
## `reallocShared(block, 0) <#reallocShared.t,pointer,Natural>`_ ## `reallocShared(block, 0) <#reallocShared.t,pointer,Natural>`_
@ -207,7 +220,7 @@ when hasAlloc and not defined(js):
proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline, tags: [], proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline, tags: [],
benign, raises: [].} = benign, raises: [].} =
## Allocates a new memory block on the shared heap with at ## Allocates a new memory block on the shared heap with at
## least ``T.sizeof * size`` bytes. ## least `T.sizeof * size` bytes.
## ##
## The block has to be freed with ## The block has to be freed with
## `resizeShared(block, 0) <#resizeShared,ptr.T,Natural>`_ or ## `resizeShared(block, 0) <#resizeShared,ptr.T,Natural>`_ or
@ -222,7 +235,7 @@ when hasAlloc and not defined(js):
template allocShared0*(size: Natural): pointer = template allocShared0*(size: Natural): pointer =
## Allocates a new memory block on the shared heap with at ## Allocates a new memory block on the shared heap with at
## least ``size`` bytes. ## least `size` bytes.
## ##
## The block has to be freed with ## The block has to be freed with
## `reallocShared(block, 0) <#reallocShared.t,pointer,Natural>`_ ## `reallocShared(block, 0) <#reallocShared.t,pointer,Natural>`_
@ -236,7 +249,7 @@ when hasAlloc and not defined(js):
proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} = proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
## Allocates a new memory block on the shared heap with at ## Allocates a new memory block on the shared heap with at
## least ``T.sizeof * size`` bytes. ## least `T.sizeof * size` bytes.
## ##
## The block has to be freed with ## The block has to be freed with
## `resizeShared(block, 0) <#resizeShared,ptr.T,Natural>`_ or ## `resizeShared(block, 0) <#resizeShared,ptr.T,Natural>`_ or
@ -251,9 +264,9 @@ when hasAlloc and not defined(js):
## Grows or shrinks a given memory block on the heap. ## Grows or shrinks a given memory block on the heap.
## ##
## If `p` is **nil** then a new memory block is returned. ## If `p` is **nil** then a new memory block is returned.
## In either way the block has at least ``newSize`` bytes. ## In either way the block has at least `newSize` bytes.
## If ``newSize == 0`` and `p` is not **nil** ``reallocShared`` calls ## If `newSize == 0` and `p` is not **nil** `reallocShared` calls
## ``deallocShared(p)``. ## `deallocShared(p)`.
## In other cases the block has to be freed with ## In other cases the block has to be freed with
## `deallocShared <#deallocShared,pointer>`_. ## `deallocShared <#deallocShared,pointer>`_.
reallocSharedImpl(p, newSize) reallocSharedImpl(p, newSize)
@ -265,9 +278,9 @@ when hasAlloc and not defined(js):
## containing zero, so it is somewhat safer then reallocShared ## containing zero, so it is somewhat safer then reallocShared
## ##
## If `p` is **nil** then a new memory block is returned. ## If `p` is **nil** then a new memory block is returned.
## In either way the block has at least ``newSize`` bytes. ## In either way the block has at least `newSize` bytes.
## If ``newSize == 0`` and `p` is not **nil** ``reallocShared`` calls ## If `newSize == 0` and `p` is not **nil** `reallocShared` calls
## ``deallocShared(p)``. ## `deallocShared(p)`.
## In other cases the block has to be freed with ## In other cases the block has to be freed with
## `deallocShared <#deallocShared,pointer>`_. ## `deallocShared <#deallocShared,pointer>`_.
reallocShared0Impl(p, oldSize, newSize) reallocShared0Impl(p, oldSize, newSize)
@ -276,16 +289,16 @@ when hasAlloc and not defined(js):
## Grows or shrinks a given memory block on the heap. ## Grows or shrinks a given memory block on the heap.
## ##
## If `p` is **nil** then a new memory block is returned. ## If `p` is **nil** then a new memory block is returned.
## In either way the block has at least ``T.sizeof * newSize`` bytes. ## In either way the block has at least `T.sizeof * newSize` bytes.
## If ``newSize == 0`` and `p` is not **nil** ``resizeShared`` calls ## If `newSize == 0` and `p` is not **nil** `resizeShared` calls
## ``freeShared(p)``. ## `freeShared(p)`.
## In other cases the block has to be freed with ## In other cases the block has to be freed with
## `freeShared <#freeShared,ptr.T>`_. ## `freeShared <#freeShared,ptr.T>`_.
cast[ptr T](reallocShared(p, T.sizeof * newSize)) cast[ptr T](reallocShared(p, T.sizeof * newSize))
proc deallocShared*(p: pointer) {.noconv, compilerproc, rtl, benign, raises: [], tags: [].} = proc deallocShared*(p: pointer) {.noconv, compilerproc, rtl, benign, raises: [], tags: [].} =
## Frees the memory allocated with ``allocShared``, ``allocShared0`` or ## Frees the memory allocated with `allocShared`, `allocShared0` or
## ``reallocShared``. ## `reallocShared`.
## ##
## **This procedure is dangerous!** ## **This procedure is dangerous!**
## If one forgets to free the memory a leak occurs; if one tries to ## If one forgets to free the memory a leak occurs; if one tries to
@ -295,8 +308,8 @@ when hasAlloc and not defined(js):
deallocSharedImpl(p) deallocSharedImpl(p)
proc freeShared*[T](p: ptr T) {.inline, benign, raises: [].} = proc freeShared*[T](p: ptr T) {.inline, benign, raises: [].} =
## Frees the memory allocated with ``createShared``, ``createSharedU`` or ## Frees the memory allocated with `createShared`, `createSharedU` or
## ``resizeShared``. ## `resizeShared`.
## ##
## **This procedure is dangerous!** ## **This procedure is dangerous!**
## If one forgets to free the memory a leak occurs; if one tries to ## If one forgets to free the memory a leak occurs; if one tries to
@ -304,7 +317,7 @@ when hasAlloc and not defined(js):
## or other memory may be corrupted. ## or other memory may be corrupted.
deallocShared(p) deallocShared(p)
include bitmasks include bitmasks
template `+!`(p: pointer, s: SomeInteger): pointer = template `+!`(p: pointer, s: SomeInteger): pointer =
cast[pointer](cast[int](p) +% int(s)) cast[pointer](cast[int](p) +% int(s))
@ -318,7 +331,7 @@ when hasAlloc and not defined(js):
result = allocShared(size) result = allocShared(size)
else: else:
result = alloc(size) result = alloc(size)
else: else:
# allocate (size + align - 1) necessary for alignment, # allocate (size + align - 1) necessary for alignment,
# plus 2 bytes to store offset # plus 2 bytes to store offset
when compileOption("threads"): when compileOption("threads"):
@ -326,7 +339,7 @@ when hasAlloc and not defined(js):
else: else:
let base = alloc(size + align - 1 + sizeof(uint16)) let base = alloc(size + align - 1 + sizeof(uint16))
# memory layout: padding + offset (2 bytes) + user_data # memory layout: padding + offset (2 bytes) + user_data
# in order to deallocate: read offset at user_data - 2 bytes, # in order to deallocate: read offset at user_data - 2 bytes,
# then deallocate user_data - offset # then deallocate user_data - offset
let offset = align - (cast[int](base) and (align - 1)) let offset = align - (cast[int](base) and (align - 1))
cast[ptr uint16](base +! (offset - sizeof(uint16)))[] = uint16(offset) cast[ptr uint16](base +! (offset - sizeof(uint16)))[] = uint16(offset)
@ -338,7 +351,7 @@ when hasAlloc and not defined(js):
result = allocShared0(size) result = allocShared0(size)
else: else:
result = alloc0(size) result = alloc0(size)
else: else:
# see comments for alignedAlloc # see comments for alignedAlloc
when compileOption("threads"): when compileOption("threads"):
let base = allocShared0(size + align - 1 + sizeof(uint16)) let base = allocShared0(size + align - 1 + sizeof(uint16))
@ -348,13 +361,13 @@ when hasAlloc and not defined(js):
cast[ptr uint16](base +! (offset - sizeof(uint16)))[] = uint16(offset) cast[ptr uint16](base +! (offset - sizeof(uint16)))[] = uint16(offset)
result = base +! offset result = base +! offset
proc alignedDealloc(p: pointer, align: int) {.compilerproc.} = proc alignedDealloc(p: pointer, align: int) {.compilerproc.} =
if align <= MemAlign: if align <= MemAlign:
when compileOption("threads"): when compileOption("threads"):
deallocShared(p) deallocShared(p)
else: else:
dealloc(p) dealloc(p)
else: else:
# read offset at p - 2 bytes, then deallocate (p - offset) pointer # read offset at p - 2 bytes, then deallocate (p - offset) pointer
let offset = cast[ptr uint16](p -! sizeof(uint16))[] let offset = cast[ptr uint16](p -! sizeof(uint16))[]
when compileOption("threads"): when compileOption("threads"):

15
tests/stdlib/tmemory.nim Normal file
View file

@ -0,0 +1,15 @@
block: # cmpMem
type
SomeHash = array[15, byte]
var
a: SomeHash
b: SomeHash
a[^1] = byte(1)
let c = a
doAssert cmpMem(a.addr, b.addr, sizeof(SomeHash)) > 0
doAssert cmpMem(b.addr, a.addr, sizeof(SomeHash)) < 0
doAssert cmpMem(a.addr, c.unsafeAddr, sizeof(SomeHash)) == 0