nim-stew/stew/ptrops.nim

55 lines
2.1 KiB
Nim
Raw Normal View History

2019-09-20 14:01:32 +00:00
# stew
# Copyright 2018-2019 Status Research & Development GmbH
# Licensed under either of
#
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
# Pointer operations and helpers - generally, dereferencing pointers that have
# been offset is unsafe and many of the operations herein have undefined
# and platform-specific behavior in corner cases.
2019-09-26 12:26:17 +00:00
# Due to poor codegen and subsequent lack of inlining, these operations
2019-09-20 14:01:32 +00:00
# are templates even where they could be func.
2019-09-26 12:26:17 +00:00
# Note that `ByteAddress` in stdlib is implemented as a signed integer and
# might lead to overflow on arithmetic - avoid
2019-09-20 14:01:32 +00:00
template offset*(p: pointer, bytes: int): pointer =
## Offset a memory address by a number of bytes. Behavior is undefined on
## overflow.
# Actual behavior is wrapping, but this may be revised in the future to enable
# better optimizations
2019-09-26 12:26:17 +00:00
# We assume two's complement wrapping behaviour for `uint`
cast[pointer](cast[uint](p) + cast[uint](bytes))
2019-09-20 14:01:32 +00:00
template offset*[T](p: ptr T, count: int): ptr T =
## Offset a pointer to T by count elements. Behavior is undefined on
## overflow.
2019-09-26 12:26:17 +00:00
2019-09-20 14:01:32 +00:00
# Actual behavior is wrapping, but this may be revised in the future to enable
# better optimizations.
2019-09-26 12:26:17 +00:00
2019-09-20 14:01:32 +00:00
# We turn off checking here - too large counts is UB
{.checks: off.}
2019-09-26 12:26:17 +00:00
mixin offset
2019-09-20 14:01:32 +00:00
let bytes = count * sizeof(T)
2019-09-26 12:26:17 +00:00
cast[ptr T](cast[pointer](p).offset(bytes))
2019-09-20 14:01:32 +00:00
template distance*(a, b: pointer): int =
2019-09-26 12:26:17 +00:00
## Number of bytes between a and b - undefined behavior when difference
## exceeds what can be represented in an int
# We assume two's complement wrapping behaviour for `uint`
cast[int](cast[uint](b) - cast[uint](a))
2019-09-20 14:01:32 +00:00
template distance*[T](a, b: ptr T): int =
# Number of elements between a and b - undefined behavior when difference
# exceeds what can be represented in an int
{.checks: off.}
2019-09-20 20:29:54 +00:00
mixin toMemAddress, distance
2019-09-26 12:26:17 +00:00
cast[pointer](a).distance(cast[pointer](b)) div sizeof(T)