diff options
author | Miran <narimiran@disroot.org> | 2020-01-15 14:42:49 +0100 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2020-01-15 14:42:49 +0100 |
commit | e708d5de75c0cccba666f19390ee1ac8e3df8a7a (patch) | |
tree | f9e78b7e4f9f3f8b7429ca64f37e632992bbeaa6 | |
parent | 79a326759a5fb49bed60163e48e8e17f3c1ee3a3 (diff) | |
download | Nim-e708d5de75c0cccba666f19390ee1ac8e3df8a7a.tar.gz |
System cleanup, part 2 (#13155)
* create basic_types, arithmetics, exceptions, comparisons * create setops.nim * create memalloc.nim * create gc_interface.nim * create iterators_1.nim
-rw-r--r-- | lib/system.nim | 1678 | ||||
-rw-r--r-- | lib/system/arithmetics.nim | 486 | ||||
-rw-r--r-- | lib/system/basic_types.nim | 67 | ||||
-rw-r--r-- | lib/system/comparisons.nim | 311 | ||||
-rw-r--r-- | lib/system/exceptions.nim | 137 | ||||
-rw-r--r-- | lib/system/gc_interface.nim | 100 | ||||
-rw-r--r-- | lib/system/iterators_1.nim | 214 | ||||
-rw-r--r-- | lib/system/memalloc.nim | 262 | ||||
-rw-r--r-- | lib/system/setops.nim | 94 |
9 files changed, 1700 insertions, 1649 deletions
diff --git a/lib/system.nim b/lib/system.nim index 1fd7a81a3..5722edbe4 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -23,27 +23,12 @@ type - int* {.magic: Int.} ## Default integer type; bitwidth depends on - ## architecture, but is always the same as a pointer. - int8* {.magic: Int8.} ## Signed 8 bit integer type. - int16* {.magic: Int16.} ## Signed 16 bit integer type. - int32* {.magic: Int32.} ## Signed 32 bit integer type. - int64* {.magic: Int64.} ## Signed 64 bit integer type. - uint* {.magic: UInt.} ## Unsigned default integer type. - uint8* {.magic: UInt8.} ## Unsigned 8 bit integer type. - uint16* {.magic: UInt16.} ## Unsigned 16 bit integer type. - uint32* {.magic: UInt32.} ## Unsigned 32 bit integer type. - uint64* {.magic: UInt64.} ## Unsigned 64 bit integer type. float* {.magic: Float.} ## Default floating point type. float32* {.magic: Float32.} ## 32 bit floating point type. float64* {.magic: Float.} ## 64 bit floating point type. # 'float64' is now an alias to 'float'; this solves many problems -type # we need to start a new type section here, so that ``0`` can have a type - bool* {.magic: Bool.} = enum ## Built-in boolean type. - false = 0, true = 1 - type char* {.magic: Char.} ## Built-in 8 bit character type (unsigned). string* {.magic: String.} ## Built-in string type. @@ -53,28 +38,7 @@ type typedesc* {.magic: TypeDesc.} ## Meta type to denote a type description. -const - on* = true ## Alias for ``true``. - off* = false ## Alias for ``false``. - -{.push warning[GcMem]: off, warning[Uninit]: off.} -{.push hints: off.} - -proc `or`*(a, b: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.} - ## Constructs an `or` meta class. - -proc `and`*(a, b: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.} - ## Constructs an `and` meta class. - -proc `not`*(a: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.} - ## Constructs an `not` meta class. - type - Ordinal*[T] {.magic: Ordinal.} ## Generic ordinal type. Includes integer, - ## bool, character, and enumeration types - ## as well as their subtypes. Note `uint` - ## and `uint64` are not ordinal types for - ## implementation reasons. `ptr`*[T] {.magic: Pointer.} ## Built-in generic untraced pointer type. `ref`*[T] {.magic: Pointer.} ## Built-in generic traced pointer type. @@ -88,19 +52,22 @@ type typed* {.magic: Stmt.} ## Meta type to denote an expression that ## is resolved (for templates). - SomeSignedInt* = int|int8|int16|int32|int64 - ## Type class matching all signed integer types. +include "system/basic_types" - SomeUnsignedInt* = uint|uint8|uint16|uint32|uint64 - ## Type class matching all unsigned integer types. +{.push warning[GcMem]: off, warning[Uninit]: off.} +{.push hints: off.} - SomeInteger* = SomeSignedInt|SomeUnsignedInt - ## Type class matching all integer types. +proc `or`*(a, b: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.} + ## Constructs an `or` meta class. + +proc `and`*(a, b: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.} + ## Constructs an `and` meta class. + +proc `not`*(a: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.} + ## Constructs an `not` meta class. - SomeOrdinal* = int|int8|int16|int32|int64|bool|enum|uint|uint8|uint16|uint32|uint64 - ## Type class matching all ordinal types; however this includes enums with - ## holes. +type SomeFloat* = float|float32|float64 ## Type class matching all floating point number types. @@ -228,22 +195,6 @@ when defined(nimHasTypeof): ## Since version 0.20.0. discard -proc `not`*(x: bool): bool {.magic: "Not", noSideEffect.} - ## Boolean not; returns true if ``x == false``. - -proc `and`*(x, y: bool): bool {.magic: "And", noSideEffect.} - ## Boolean ``and``; returns true if ``x == y == true`` (if both arguments - ## are true). - ## - ## Evaluation is lazy: if ``x`` is false, ``y`` will not even be evaluated. -proc `or`*(x, y: bool): bool {.magic: "Or", noSideEffect.} - ## Boolean ``or``; returns true if ``not (not x and not y)`` (if any of - ## the arguments is true). - ## - ## Evaluation is lazy: if ``x`` is true, ``y`` will not even be evaluated. -proc `xor`*(x, y: bool): bool {.magic: "Xor", noSideEffect.} - ## Boolean `exclusive or`; returns true if ``x != y`` (if either argument - ## is true while the other is false). const ThisIsSystem = true @@ -507,146 +458,14 @@ when defined(hotCodeReloading): else: {.pragma: hcrInline.} -# comparison operators: -proc `==`*[Enum: enum](x, y: Enum): bool {.magic: "EqEnum", noSideEffect.} - ## Checks whether values within the *same enum* have the same underlying value. - ## - ## .. code-block:: Nim - ## type - ## Enum1 = enum - ## Field1 = 3, Field2 - ## Enum2 = enum - ## Place1, Place2 = 3 - ## var - ## e1 = Field1 - ## e2 = Enum1(Place2) - ## echo (e1 == e2) # true - ## echo (e1 == Place2) # raises error -proc `==`*(x, y: pointer): bool {.magic: "EqRef", noSideEffect.} - ## .. code-block:: Nim - ## var # this is a wildly dangerous example - ## a = cast[pointer](0) - ## b = cast[pointer](nil) - ## echo (a == b) # true due to the special meaning of `nil`/0 as a pointer -proc `==`*(x, y: string): bool {.magic: "EqStr", noSideEffect.} - ## Checks for equality between two `string` variables. - -proc `==`*(x, y: char): bool {.magic: "EqCh", noSideEffect.} - ## Checks for equality between two `char` variables. -proc `==`*(x, y: bool): bool {.magic: "EqB", noSideEffect.} - ## Checks for equality between two `bool` variables. -proc `==`*[T](x, y: set[T]): bool {.magic: "EqSet", noSideEffect.} - ## Checks for equality between two variables of type `set`. - ## - ## .. code-block:: Nim - ## var a = {1, 2, 2, 3} # duplication in sets is ignored - ## var b = {1, 2, 3} - ## echo (a == b) # true -proc `==`*[T](x, y: ref T): bool {.magic: "EqRef", noSideEffect.} - ## Checks that two `ref` variables refer to the same item. -proc `==`*[T](x, y: ptr T): bool {.magic: "EqRef", noSideEffect.} - ## Checks that two `ptr` variables refer to the same item. -proc `==`*[T: proc](x, y: T): bool {.magic: "EqProc", noSideEffect.} - ## Checks that two `proc` variables refer to the same procedure. - -proc `<=`*[Enum: enum](x, y: Enum): bool {.magic: "LeEnum", noSideEffect.} -proc `<=`*(x, y: string): bool {.magic: "LeStr", noSideEffect.} - ## Compares two strings and returns true if `x` is lexicographically - ## before `y` (uppercase letters come before lowercase letters). - ## - ## .. code-block:: Nim - ## let - ## a = "abc" - ## b = "abd" - ## c = "ZZZ" - ## assert a <= b - ## assert a <= a - ## assert (a <= c) == false -proc `<=`*(x, y: char): bool {.magic: "LeCh", noSideEffect.} - ## Compares two chars and returns true if `x` is lexicographically - ## before `y` (uppercase letters come before lowercase letters). - ## - ## .. code-block:: Nim - ## let - ## a = 'a' - ## b = 'b' - ## c = 'Z' - ## assert a <= b - ## assert a <= a - ## assert (a <= c) == false -proc `<=`*[T](x, y: set[T]): bool {.magic: "LeSet", noSideEffect.} - ## Returns true if `x` is a subset of `y`. - ## - ## A subset `x` has all of its members in `y` and `y` doesn't necessarily - ## have more members than `x`. That is, `x` can be equal to `y`. - ## - ## .. code-block:: Nim - ## let - ## a = {3, 5} - ## b = {1, 3, 5, 7} - ## c = {2} - ## assert a <= b - ## assert a <= a - ## assert (a <= c) == false -proc `<=`*(x, y: bool): bool {.magic: "LeB", noSideEffect.} -proc `<=`*[T](x, y: ref T): bool {.magic: "LePtr", noSideEffect.} -proc `<=`*(x, y: pointer): bool {.magic: "LePtr", noSideEffect.} - -proc `<`*[Enum: enum](x, y: Enum): bool {.magic: "LtEnum", noSideEffect.} -proc `<`*(x, y: string): bool {.magic: "LtStr", noSideEffect.} - ## Compares two strings and returns true if `x` is lexicographically - ## before `y` (uppercase letters come before lowercase letters). - ## - ## .. code-block:: Nim - ## let - ## a = "abc" - ## b = "abd" - ## c = "ZZZ" - ## assert a < b - ## assert (a < a) == false - ## assert (a < c) == false -proc `<`*(x, y: char): bool {.magic: "LtCh", noSideEffect.} - ## Compares two chars and returns true if `x` is lexicographically - ## before `y` (uppercase letters come before lowercase letters). - ## - ## .. code-block:: Nim - ## let - ## a = 'a' - ## b = 'b' - ## c = 'Z' - ## assert a < b - ## assert (a < a) == false - ## assert (a < c) == false -proc `<`*[T](x, y: set[T]): bool {.magic: "LtSet", noSideEffect.} - ## Returns true if `x` is a strict or proper subset of `y`. - ## - ## A strict or proper subset `x` has all of its members in `y` but `y` has - ## more elements than `y`. - ## - ## .. code-block:: Nim - ## let - ## a = {3, 5} - ## b = {1, 3, 5, 7} - ## c = {2} - ## assert a < b - ## assert (a < a) == false - ## assert (a < c) == false -proc `<`*(x, y: bool): bool {.magic: "LtB", noSideEffect.} -proc `<`*[T](x, y: ref T): bool {.magic: "LtPtr", noSideEffect.} -proc `<`*[T](x, y: ptr T): bool {.magic: "LtPtr", noSideEffect.} -proc `<`*(x, y: pointer): bool {.magic: "LtPtr", noSideEffect.} - -template `!=`*(x, y: untyped): untyped = - ## Unequals operator. This is a shorthand for ``not (x == y)``. - not (x == y) - -template `>=`*(x, y: untyped): untyped = - ## "is greater or equals" operator. This is the same as ``y <= x``. - y <= x - -template `>`*(x, y: untyped): untyped = - ## "is greater" operator. This is the same as ``y < x``. - y < x +{.push profiler: off.} +let nimvm* {.magic: "Nimvm", compileTime.}: bool = false + ## May be used only in `when` expression. + ## It is true in Nim VM context and false otherwise. +{.pop.} + +include "system/arithmetics" +include "system/comparisons" const appType* {.magic: "AppType"}: string = "" @@ -698,142 +517,8 @@ type ## However, objects that have no ancestor are also allowed. RootRef* = ref RootObj ## Reference to `RootObj`. - RootEffect* {.compilerproc.} = object of RootObj ## \ - ## Base effect class. - ## - ## Each effect should inherit from `RootEffect` unless you know what - ## you're doing. - TimeEffect* = object of RootEffect ## Time effect. - IOEffect* = object of RootEffect ## IO effect. - ReadIOEffect* = object of IOEffect ## Effect describing a read IO operation. - WriteIOEffect* = object of IOEffect ## Effect describing a write IO operation. - ExecIOEffect* = object of IOEffect ## Effect describing an executing IO operation. - - StackTraceEntry* = object ## In debug mode exceptions store the stack trace that led - ## to them. A `StackTraceEntry` is a single entry of the - ## stack trace. - procname*: cstring ## Name of the proc that is currently executing. - line*: int ## Line number of the proc that is currently executing. - filename*: cstring ## Filename of the proc that is currently executing. - - Exception* {.compilerproc, magic: "Exception".} = object of RootObj ## \ - ## Base exception class. - ## - ## Each exception has to inherit from `Exception`. See the full `exception - ## hierarchy <manual.html#exception-handling-exception-hierarchy>`_. - parent*: ref Exception ## Parent exception (can be used as a stack). - name*: cstring ## The exception's name is its Nim identifier. - ## This field is filled automatically in the - ## ``raise`` statement. - msg* {.exportc: "message".}: string ## The exception's message. Not - ## providing an exception message - ## is bad style. - when defined(js): - trace: string - else: - trace: seq[StackTraceEntry] - when defined(nimBoostrapCsources0_19_0): - # see #10315, bootstrap with `nim cpp` from csources gave error: - # error: no member named 'raise_id' in 'Exception' - raise_id: uint # set when exception is raised - else: - raiseId: uint # set when exception is raised - up: ref Exception # used for stacking exceptions. Not exported! - - Defect* = object of Exception ## \ - ## Abstract base class for all exceptions that Nim's runtime raises - ## but that are strictly uncatchable as they can also be mapped to - ## a ``quit`` / ``trap`` / ``exit`` operation. - - CatchableError* = object of Exception ## \ - ## Abstract class for all exceptions that are catchable. - IOError* = object of CatchableError ## \ - ## Raised if an IO error occurred. - EOFError* = object of IOError ## \ - ## Raised if an IO "end of file" error occurred. - OSError* = object of CatchableError ## \ - ## Raised if an operating system service failed. - errorCode*: int32 ## OS-defined error code describing this error. - LibraryError* = object of OSError ## \ - ## Raised if a dynamic library could not be loaded. - ResourceExhaustedError* = object of CatchableError ## \ - ## Raised if a resource request could not be fulfilled. - ArithmeticError* = object of Defect ## \ - ## Raised if any kind of arithmetic error occurred. - DivByZeroError* = object of ArithmeticError ## \ - ## Raised for runtime integer divide-by-zero errors. - - OverflowError* = object of ArithmeticError ## \ - ## Raised for runtime integer overflows. - ## - ## This happens for calculations whose results are too large to fit in the - ## provided bits. - AccessViolationError* = object of Defect ## \ - ## Raised for invalid memory access errors - AssertionError* = object of Defect ## \ - ## Raised when assertion is proved wrong. - ## - ## Usually the result of using the `assert() template - ## <assertions.html#assert.t,untyped,string>`_. - ValueError* = object of CatchableError ## \ - ## Raised for string and object conversion errors. - KeyError* = object of ValueError ## \ - ## Raised if a key cannot be found in a table. - ## - ## Mostly used by the `tables <tables.html>`_ module, it can also be raised - ## by other collection modules like `sets <sets.html>`_ or `strtabs - ## <strtabs.html>`_. - OutOfMemError* = object of Defect ## \ - ## Raised for unsuccessful attempts to allocate memory. - IndexError* = object of Defect ## \ - ## Raised if an array index is out of bounds. - - FieldError* = object of Defect ## \ - ## Raised if a record field is not accessible because its discriminant's - ## value does not fit. - RangeError* = object of Defect ## \ - ## Raised if a range check error occurred. - StackOverflowError* = object of Defect ## \ - ## Raised if the hardware stack used for subroutine calls overflowed. - ReraiseError* = object of Defect ## \ - ## Raised if there is no exception to reraise. - ObjectAssignmentError* = object of Defect ## \ - ## Raised if an object gets assigned to its parent's object. - ObjectConversionError* = object of Defect ## \ - ## Raised if an object is converted to an incompatible object type. - ## You can use ``of`` operator to check if conversion will succeed. - FloatingPointError* = object of Defect ## \ - ## Base class for floating point exceptions. - FloatInvalidOpError* = object of FloatingPointError ## \ - ## Raised by invalid operations according to IEEE. - ## - ## Raised by ``0.0/0.0``, for example. - FloatDivByZeroError* = object of FloatingPointError ## \ - ## Raised by division by zero. - ## - ## Divisor is zero and dividend is a finite nonzero number. - FloatOverflowError* = object of FloatingPointError ## \ - ## Raised for overflows. - ## - ## The operation produced a result that exceeds the range of the exponent. - FloatUnderflowError* = object of FloatingPointError ## \ - ## Raised for underflows. - ## - ## The operation produced a result that is too small to be represented as a - ## normal number. - FloatInexactError* = object of FloatingPointError ## \ - ## Raised for inexact results. - ## - ## The operation produced a result that cannot be represented with infinite - ## precision -- for example: ``2.0 / 3.0, log(1.1)`` - ## - ## **Note**: Nim currently does not detect these! - DeadThreadError* = object of Defect ## \ - ## Raised if it is attempted to send a message to a dead thread. - NilAccessError* = object of Defect ## \ - ## Raised on dereferences of ``nil`` pointers. - ## - ## This is only raised if the `segfaults module <segfaults.html>`_ was imported! + +include "system/exceptions" when defined(JS) or defined(nimdoc): type @@ -889,52 +574,6 @@ when defined(nimtypedescfixed): proc sizeof*(x: typedesc): int {.magic: "SizeOf", noSideEffect.} -proc succ*[T: Ordinal](x: T, y = 1): T {.magic: "Succ", noSideEffect.} - ## Returns the ``y``-th successor (default: 1) of the value ``x``. - ## ``T`` has to be an `ordinal type <#Ordinal>`_. - ## - ## If such a value does not exist, ``OverflowError`` is raised - ## or a compile time error occurs. - ## - ## .. code-block:: Nim - ## let x = 5 - ## echo succ(5) # => 6 - ## echo succ(5, 3) # => 8 - -proc pred*[T: Ordinal](x: T, y = 1): T {.magic: "Pred", noSideEffect.} - ## Returns the ``y``-th predecessor (default: 1) of the value ``x``. - ## ``T`` has to be an `ordinal type <#Ordinal>`_. - ## - ## If such a value does not exist, ``OverflowError`` is raised - ## or a compile time error occurs. - ## - ## .. code-block:: Nim - ## let x = 5 - ## echo pred(5) # => 4 - ## echo pred(5, 3) # => 2 - -proc inc*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Inc", noSideEffect.} - ## Increments the ordinal ``x`` by ``y``. - ## - ## If such a value does not exist, ``OverflowError`` is raised or a compile - ## time error occurs. This is a short notation for: ``x = succ(x, y)``. - ## - ## .. code-block:: Nim - ## var i = 2 - ## inc(i) # i <- 3 - ## inc(i, 3) # i <- 6 - -proc dec*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Dec", noSideEffect.} - ## Decrements the ordinal ``x`` by ``y``. - ## - ## If such a value does not exist, ``OverflowError`` is raised or a compile - ## time error occurs. This is a short notation for: ``x = pred(x, y)``. - ## - ## .. code-block:: Nim - ## var i = 2 - ## dec(i) # i <- 1 - ## dec(i, 3) # i <- -2 - proc newSeq*[T](s: var seq[T], len: Natural) {.magic: "NewSeq", noSideEffect.} ## Creates a new sequence of type ``seq[T]`` with length ``len``. ## @@ -1044,54 +683,6 @@ proc len*[T](x: seq[T]): int {.magic: "LengthSeq", noSideEffect.} ## var s = @[1, 1, 1, 1, 1] ## echo len(s) # => 5 -# set routines: -proc incl*[T](x: var set[T], y: T) {.magic: "Incl", noSideEffect.} - ## Includes element ``y`` in the set ``x``. - ## - ## This is the same as ``x = x + {y}``, but it might be more efficient. - ## - ## .. code-block:: Nim - ## var a = {1, 3, 5} - ## a.incl(2) # a <- {1, 2, 3, 5} - ## a.incl(4) # a <- {1, 2, 3, 4, 5} - -template incl*[T](x: var set[T], y: set[T]) = - ## Includes the set ``y`` in the set ``x``. - ## - ## .. code-block:: Nim - ## var a = {1, 3, 5, 7} - ## var b = {4, 5, 6} - ## a.incl(b) # a <- {1, 3, 4, 5, 6, 7} - x = x + y - -proc excl*[T](x: var set[T], y: T) {.magic: "Excl", noSideEffect.} - ## Excludes element ``y`` from the set ``x``. - ## - ## This is the same as ``x = x - {y}``, but it might be more efficient. - ## - ## .. code-block:: Nim - ## var b = {2, 3, 5, 6, 12, 545} - ## b.excl(5) # b <- {2, 3, 6, 12, 545} - -template excl*[T](x: var set[T], y: set[T]) = - ## Excludes the set ``y`` from the set ``x``. - ## - ## .. code-block:: Nim - ## var a = {1, 3, 5, 7} - ## var b = {3, 4, 5} - ## a.excl(b) # a <- {1, 7} - x = x - y - -proc card*[T](x: set[T]): int {.magic: "Card", noSideEffect.} - ## Returns the cardinality of the set ``x``, i.e. the number of elements - ## in the set. - ## - ## .. code-block:: Nim - ## var a = {1, 3, 5, 7} - ## echo card(a) # => 4 - -proc len*[T](x: set[T]): int {.magic: "Card", noSideEffect.} - ## An alias for `card(x)`. proc ord*[T: Ordinal|enum](x: T): int {.magic: "Ord", noSideEffect.} ## Returns the internal `int` value of an ordinal value ``x``. @@ -1107,480 +698,6 @@ proc chr*(u: range[0..255]): char {.magic: "Chr", noSideEffect.} ## echo chr(65) # => A ## echo chr(97) # => a -# -------------------------------------------------------------------------- -# built-in operators - -when defined(nimNoZeroExtendMagic): - proc ze*(x: int8): int {.deprecated.} = - ## zero extends a smaller integer type to ``int``. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int](uint(cast[uint8](x))) - - proc ze*(x: int16): int {.deprecated.} = - ## zero extends a smaller integer type to ``int``. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int](uint(cast[uint16](x))) - - proc ze64*(x: int8): int64 {.deprecated.} = - ## zero extends a smaller integer type to ``int64``. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int64](uint64(cast[uint8](x))) - - proc ze64*(x: int16): int64 {.deprecated.} = - ## zero extends a smaller integer type to ``int64``. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int64](uint64(cast[uint16](x))) - - proc ze64*(x: int32): int64 {.deprecated.} = - ## zero extends a smaller integer type to ``int64``. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int64](uint64(cast[uint32](x))) - - proc ze64*(x: int): int64 {.deprecated.} = - ## zero extends a smaller integer type to ``int64``. This treats `x` as - ## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``. - ## (This is the case on 64 bit processors.) - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int64](uint64(cast[uint](x))) - - proc toU8*(x: int): int8 {.deprecated.} = - ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits - ## from `x`. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int8](x) - - proc toU16*(x: int): int16 {.deprecated.} = - ## treats `x` as unsigned and converts it to an ``int16`` by taking the last - ## 16 bits from `x`. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int16](x) - - proc toU32*(x: int64): int32 {.deprecated.} = - ## treats `x` as unsigned and converts it to an ``int32`` by taking the - ## last 32 bits from `x`. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - cast[int32](x) - -elif not defined(JS): - proc ze*(x: int8): int {.magic: "Ze8ToI", noSideEffect, deprecated.} - ## zero extends a smaller integer type to ``int``. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - - proc ze*(x: int16): int {.magic: "Ze16ToI", noSideEffect, deprecated.} - ## zero extends a smaller integer type to ``int``. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - - proc ze64*(x: int8): int64 {.magic: "Ze8ToI64", noSideEffect, deprecated.} - ## zero extends a smaller integer type to ``int64``. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - - proc ze64*(x: int16): int64 {.magic: "Ze16ToI64", noSideEffect, deprecated.} - ## zero extends a smaller integer type to ``int64``. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - - proc ze64*(x: int32): int64 {.magic: "Ze32ToI64", noSideEffect, deprecated.} - ## zero extends a smaller integer type to ``int64``. This treats `x` as - ## unsigned. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - - proc ze64*(x: int): int64 {.magic: "ZeIToI64", noSideEffect, deprecated.} - ## zero extends a smaller integer type to ``int64``. This treats `x` as - ## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``. - ## (This is the case on 64 bit processors.) - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - - proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect, deprecated.} - ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits - ## from `x`. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - - proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect, deprecated.} - ## treats `x` as unsigned and converts it to an ``int16`` by taking the last - ## 16 bits from `x`. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - - proc toU32*(x: int64): int32 {.magic: "ToU32", noSideEffect, deprecated.} - ## treats `x` as unsigned and converts it to an ``int32`` by taking the - ## last 32 bits from `x`. - ## **Deprecated since version 0.19.9**: Use unsigned integers instead. - -# integer calculations: -proc `+`*(x: int): int {.magic: "UnaryPlusI", noSideEffect.} - ## Unary `+` operator for an integer. Has no effect. -proc `+`*(x: int8): int8 {.magic: "UnaryPlusI", noSideEffect.} -proc `+`*(x: int16): int16 {.magic: "UnaryPlusI", noSideEffect.} -proc `+`*(x: int32): int32 {.magic: "UnaryPlusI", noSideEffect.} -proc `+`*(x: int64): int64 {.magic: "UnaryPlusI", noSideEffect.} - -proc `-`*(x: int): int {.magic: "UnaryMinusI", noSideEffect.} - ## Unary `-` operator for an integer. Negates `x`. -proc `-`*(x: int8): int8 {.magic: "UnaryMinusI", noSideEffect.} -proc `-`*(x: int16): int16 {.magic: "UnaryMinusI", noSideEffect.} -proc `-`*(x: int32): int32 {.magic: "UnaryMinusI", noSideEffect.} -proc `-`*(x: int64): int64 {.magic: "UnaryMinusI64", noSideEffect.} - -proc `not`*(x: int): int {.magic: "BitnotI", noSideEffect.} - ## Computes the `bitwise complement` of the integer `x`. - ## - ## .. code-block:: Nim - ## var - ## a = 0'u8 - ## b = 0'i8 - ## c = 1000'u16 - ## d = 1000'i16 - ## - ## echo not a # => 255 - ## echo not b # => -1 - ## echo not c # => 64535 - ## echo not d # => -1001 -proc `not`*(x: int8): int8 {.magic: "BitnotI", noSideEffect.} -proc `not`*(x: int16): int16 {.magic: "BitnotI", noSideEffect.} -proc `not`*(x: int32): int32 {.magic: "BitnotI", noSideEffect.} -proc `not`*(x: int64): int64 {.magic: "BitnotI", noSideEffect.} - -proc `+`*(x, y: int): int {.magic: "AddI", noSideEffect.} - ## Binary `+` operator for an integer. -proc `+`*(x, y: int8): int8 {.magic: "AddI", noSideEffect.} -proc `+`*(x, y: int16): int16 {.magic: "AddI", noSideEffect.} -proc `+`*(x, y: int32): int32 {.magic: "AddI", noSideEffect.} -proc `+`*(x, y: int64): int64 {.magic: "AddI", noSideEffect.} - -proc `-`*(x, y: int): int {.magic: "SubI", noSideEffect.} - ## Binary `-` operator for an integer. -proc `-`*(x, y: int8): int8 {.magic: "SubI", noSideEffect.} -proc `-`*(x, y: int16): int16 {.magic: "SubI", noSideEffect.} -proc `-`*(x, y: int32): int32 {.magic: "SubI", noSideEffect.} -proc `-`*(x, y: int64): int64 {.magic: "SubI", noSideEffect.} - -proc `*`*(x, y: int): int {.magic: "MulI", noSideEffect.} - ## Binary `*` operator for an integer. -proc `*`*(x, y: int8): int8 {.magic: "MulI", noSideEffect.} -proc `*`*(x, y: int16): int16 {.magic: "MulI", noSideEffect.} -proc `*`*(x, y: int32): int32 {.magic: "MulI", noSideEffect.} -proc `*`*(x, y: int64): int64 {.magic: "MulI", noSideEffect.} - -proc `div`*(x, y: int): int {.magic: "DivI", noSideEffect.} - ## Computes the integer division. - ## - ## This is roughly the same as ``trunc(x/y)``. - ## - ## .. code-block:: Nim - ## ( 1 div 2) == 0 - ## ( 2 div 2) == 1 - ## ( 3 div 2) == 1 - ## ( 7 div 3) == 2 - ## (-7 div 3) == -2 - ## ( 7 div -3) == -2 - ## (-7 div -3) == 2 -proc `div`*(x, y: int8): int8 {.magic: "DivI", noSideEffect.} -proc `div`*(x, y: int16): int16 {.magic: "DivI", noSideEffect.} -proc `div`*(x, y: int32): int32 {.magic: "DivI", noSideEffect.} -proc `div`*(x, y: int64): int64 {.magic: "DivI", noSideEffect.} - -proc `mod`*(x, y: int): int {.magic: "ModI", noSideEffect.} - ## Computes the integer modulo operation (remainder). - ## - ## This is the same as ``x - (x div y) * y``. - ## - ## .. code-block:: Nim - ## ( 7 mod 5) == 2 - ## (-7 mod 5) == -2 - ## ( 7 mod -5) == 2 - ## (-7 mod -5) == -2 -proc `mod`*(x, y: int8): int8 {.magic: "ModI", noSideEffect.} -proc `mod`*(x, y: int16): int16 {.magic: "ModI", noSideEffect.} -proc `mod`*(x, y: int32): int32 {.magic: "ModI", noSideEffect.} -proc `mod`*(x, y: int64): int64 {.magic: "ModI", noSideEffect.} - -when defined(nimOldShiftRight) or not defined(nimAshr): - const shrDepMessage = "`shr` will become sign preserving." - proc `shr`*(x: int, y: SomeInteger): int {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} - proc `shr`*(x: int8, y: SomeInteger): int8 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} - proc `shr`*(x: int16, y: SomeInteger): int16 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} - proc `shr`*(x: int32, y: SomeInteger): int32 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} - proc `shr`*(x: int64, y: SomeInteger): int64 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} -else: - proc `shr`*(x: int, y: SomeInteger): int {.magic: "AshrI", noSideEffect.} - ## Computes the `shift right` operation of `x` and `y`, filling - ## vacant bit positions with the sign bit. - ## - ## **Note**: `Operator precedence <manual.html#syntax-precedence>`_ - ## is different than in *C*. - ## - ## See also: - ## * `ashr proc <#ashr,int,SomeInteger>`_ for arithmetic shift right - ## - ## .. code-block:: Nim - ## 0b0001_0000'i8 shr 2 == 0b0000_0100'i8 - ## 0b0000_0001'i8 shr 1 == 0b0000_0000'i8 - ## 0b1000_0000'i8 shr 4 == 0b1111_1000'i8 - ## -1 shr 5 == -1 - ## 1 shr 5 == 0 - ## 16 shr 2 == 4 - ## -16 shr 2 == -4 - proc `shr`*(x: int8, y: SomeInteger): int8 {.magic: "AshrI", noSideEffect.} - proc `shr`*(x: int16, y: SomeInteger): int16 {.magic: "AshrI", noSideEffect.} - proc `shr`*(x: int32, y: SomeInteger): int32 {.magic: "AshrI", noSideEffect.} - proc `shr`*(x: int64, y: SomeInteger): int64 {.magic: "AshrI", noSideEffect.} - - -proc `shl`*(x: int, y: SomeInteger): int {.magic: "ShlI", noSideEffect.} - ## Computes the `shift left` operation of `x` and `y`. - ## - ## **Note**: `Operator precedence <manual.html#syntax-precedence>`_ - ## is different than in *C*. - ## - ## .. code-block:: Nim - ## 1'i32 shl 4 == 0x0000_0010 - ## 1'i64 shl 4 == 0x0000_0000_0000_0010 -proc `shl`*(x: int8, y: SomeInteger): int8 {.magic: "ShlI", noSideEffect.} -proc `shl`*(x: int16, y: SomeInteger): int16 {.magic: "ShlI", noSideEffect.} -proc `shl`*(x: int32, y: SomeInteger): int32 {.magic: "ShlI", noSideEffect.} -proc `shl`*(x: int64, y: SomeInteger): int64 {.magic: "ShlI", noSideEffect.} - -when defined(nimAshr): - proc ashr*(x: int, y: SomeInteger): int {.magic: "AshrI", noSideEffect.} - ## Shifts right by pushing copies of the leftmost bit in from the left, - ## and let the rightmost bits fall off. - ## - ## Note that `ashr` is not an operator so use the normal function - ## call syntax for it. - ## - ## See also: - ## * `shr proc <#shr,int,SomeInteger>`_ - ## - ## .. code-block:: Nim - ## ashr(0b0001_0000'i8, 2) == 0b0000_0100'i8 - ## ashr(0b1000_0000'i8, 8) == 0b1111_1111'i8 - ## ashr(0b1000_0000'i8, 1) == 0b1100_0000'i8 - proc ashr*(x: int8, y: SomeInteger): int8 {.magic: "AshrI", noSideEffect.} - proc ashr*(x: int16, y: SomeInteger): int16 {.magic: "AshrI", noSideEffect.} - proc ashr*(x: int32, y: SomeInteger): int32 {.magic: "AshrI", noSideEffect.} - proc ashr*(x: int64, y: SomeInteger): int64 {.magic: "AshrI", noSideEffect.} -else: - # used for bootstrapping the compiler - proc ashr*[T](x: T, y: SomeInteger): T = discard - -proc `and`*(x, y: int): int {.magic: "BitandI", noSideEffect.} - ## Computes the `bitwise and` of numbers `x` and `y`. - ## - ## .. code-block:: Nim - ## (0b0011 and 0b0101) == 0b0001 - ## (0b0111 and 0b1100) == 0b0100 -proc `and`*(x, y: int8): int8 {.magic: "BitandI", noSideEffect.} -proc `and`*(x, y: int16): int16 {.magic: "BitandI", noSideEffect.} -proc `and`*(x, y: int32): int32 {.magic: "BitandI", noSideEffect.} -proc `and`*(x, y: int64): int64 {.magic: "BitandI", noSideEffect.} - -proc `or`*(x, y: int): int {.magic: "BitorI", noSideEffect.} - ## Computes the `bitwise or` of numbers `x` and `y`. - ## - ## .. code-block:: Nim - ## (0b0011 or 0b0101) == 0b0111 - ## (0b0111 or 0b1100) == 0b1111 -proc `or`*(x, y: int8): int8 {.magic: "BitorI", noSideEffect.} -proc `or`*(x, y: int16): int16 {.magic: "BitorI", noSideEffect.} -proc `or`*(x, y: int32): int32 {.magic: "BitorI", noSideEffect.} -proc `or`*(x, y: int64): int64 {.magic: "BitorI", noSideEffect.} - -proc `xor`*(x, y: int): int {.magic: "BitxorI", noSideEffect.} - ## Computes the `bitwise xor` of numbers `x` and `y`. - ## - ## .. code-block:: Nim - ## (0b0011 xor 0b0101) == 0b0110 - ## (0b0111 xor 0b1100) == 0b1011 -proc `xor`*(x, y: int8): int8 {.magic: "BitxorI", noSideEffect.} -proc `xor`*(x, y: int16): int16 {.magic: "BitxorI", noSideEffect.} -proc `xor`*(x, y: int32): int32 {.magic: "BitxorI", noSideEffect.} -proc `xor`*(x, y: int64): int64 {.magic: "BitxorI", noSideEffect.} - -proc `==`*(x, y: int): bool {.magic: "EqI", noSideEffect.} - ## Compares two integers for equality. -proc `==`*(x, y: int8): bool {.magic: "EqI", noSideEffect.} -proc `==`*(x, y: int16): bool {.magic: "EqI", noSideEffect.} -proc `==`*(x, y: int32): bool {.magic: "EqI", noSideEffect.} -proc `==`*(x, y: int64): bool {.magic: "EqI", noSideEffect.} - -proc `<=`*(x, y: int): bool {.magic: "LeI", noSideEffect.} - ## Returns true if `x` is less than or equal to `y`. -proc `<=`*(x, y: int8): bool {.magic: "LeI", noSideEffect.} -proc `<=`*(x, y: int16): bool {.magic: "LeI", noSideEffect.} -proc `<=`*(x, y: int32): bool {.magic: "LeI", noSideEffect.} -proc `<=`*(x, y: int64): bool {.magic: "LeI", noSideEffect.} - -proc `<`*(x, y: int): bool {.magic: "LtI", noSideEffect.} - ## Returns true if `x` is less than `y`. -proc `<`*(x, y: int8): bool {.magic: "LtI", noSideEffect.} -proc `<`*(x, y: int16): bool {.magic: "LtI", noSideEffect.} -proc `<`*(x, y: int32): bool {.magic: "LtI", noSideEffect.} -proc `<`*(x, y: int64): bool {.magic: "LtI", noSideEffect.} - -type - IntMax32 = int|int8|int16|int32 - -proc `+%`*(x, y: IntMax32): IntMax32 {.magic: "AddU", noSideEffect.} -proc `+%`*(x, y: int64): int64 {.magic: "AddU", noSideEffect.} - ## Treats `x` and `y` as unsigned and adds them. - ## - ## The result is truncated to fit into the result. - ## This implements modulo arithmetic. No overflow errors are possible. - -proc `-%`*(x, y: IntMax32): IntMax32 {.magic: "SubU", noSideEffect.} -proc `-%`*(x, y: int64): int64 {.magic: "SubU", noSideEffect.} - ## Treats `x` and `y` as unsigned and subtracts them. - ## - ## The result is truncated to fit into the result. - ## This implements modulo arithmetic. No overflow errors are possible. - -proc `*%`*(x, y: IntMax32): IntMax32 {.magic: "MulU", noSideEffect.} -proc `*%`*(x, y: int64): int64 {.magic: "MulU", noSideEffect.} - ## Treats `x` and `y` as unsigned and multiplies them. - ## - ## The result is truncated to fit into the result. - ## This implements modulo arithmetic. No overflow errors are possible. - -proc `/%`*(x, y: IntMax32): IntMax32 {.magic: "DivU", noSideEffect.} -proc `/%`*(x, y: int64): int64 {.magic: "DivU", noSideEffect.} - ## Treats `x` and `y` as unsigned and divides them. - ## - ## The result is truncated to fit into the result. - ## This implements modulo arithmetic. No overflow errors are possible. - -proc `%%`*(x, y: IntMax32): IntMax32 {.magic: "ModU", noSideEffect.} -proc `%%`*(x, y: int64): int64 {.magic: "ModU", noSideEffect.} - ## Treats `x` and `y` as unsigned and compute the modulo of `x` and `y`. - ## - ## The result is truncated to fit into the result. - ## This implements modulo arithmetic. No overflow errors are possible. - -proc `<=%`*(x, y: IntMax32): bool {.magic: "LeU", noSideEffect.} -proc `<=%`*(x, y: int64): bool {.magic: "LeU64", noSideEffect.} - ## Treats `x` and `y` as unsigned and compares them. - ## Returns true if ``unsigned(x) <= unsigned(y)``. - -proc `<%`*(x, y: IntMax32): bool {.magic: "LtU", noSideEffect.} -proc `<%`*(x, y: int64): bool {.magic: "LtU64", noSideEffect.} - ## Treats `x` and `y` as unsigned and compares them. - ## Returns true if ``unsigned(x) < unsigned(y)``. - -template `>=%`*(x, y: untyped): untyped = y <=% x - ## Treats `x` and `y` as unsigned and compares them. - ## Returns true if ``unsigned(x) >= unsigned(y)``. - -template `>%`*(x, y: untyped): untyped = y <% x - ## Treats `x` and `y` as unsigned and compares them. - ## Returns true if ``unsigned(x) > unsigned(y)``. - - -# unsigned integer operations: -proc `not`*(x: uint): uint {.magic: "BitnotI", noSideEffect.} - ## Computes the `bitwise complement` of the integer `x`. -proc `not`*(x: uint8): uint8 {.magic: "BitnotI", noSideEffect.} -proc `not`*(x: uint16): uint16 {.magic: "BitnotI", noSideEffect.} -proc `not`*(x: uint32): uint32 {.magic: "BitnotI", noSideEffect.} -proc `not`*(x: uint64): uint64 {.magic: "BitnotI", noSideEffect.} - -proc `shr`*(x: uint, y: SomeInteger): uint {.magic: "ShrI", noSideEffect.} - ## Computes the `shift right` operation of `x` and `y`. -proc `shr`*(x: uint8, y: SomeInteger): uint8 {.magic: "ShrI", noSideEffect.} -proc `shr`*(x: uint16, y: SomeInteger): uint16 {.magic: "ShrI", noSideEffect.} -proc `shr`*(x: uint32, y: SomeInteger): uint32 {.magic: "ShrI", noSideEffect.} -proc `shr`*(x: uint64, y: SomeInteger): uint64 {.magic: "ShrI", noSideEffect.} - -proc `shl`*(x: uint, y: SomeInteger): uint {.magic: "ShlI", noSideEffect.} - ## Computes the `shift left` operation of `x` and `y`. -proc `shl`*(x: uint8, y: SomeInteger): uint8 {.magic: "ShlI", noSideEffect.} -proc `shl`*(x: uint16, y: SomeInteger): uint16 {.magic: "ShlI", noSideEffect.} -proc `shl`*(x: uint32, y: SomeInteger): uint32 {.magic: "ShlI", noSideEffect.} -proc `shl`*(x: uint64, y: SomeInteger): uint64 {.magic: "ShlI", noSideEffect.} - -proc `and`*(x, y: uint): uint {.magic: "BitandI", noSideEffect.} - ## Computes the `bitwise and` of numbers `x` and `y`. -proc `and`*(x, y: uint8): uint8 {.magic: "BitandI", noSideEffect.} -proc `and`*(x, y: uint16): uint16 {.magic: "BitandI", noSideEffect.} -proc `and`*(x, y: uint32): uint32 {.magic: "BitandI", noSideEffect.} -proc `and`*(x, y: uint64): uint64 {.magic: "BitandI", noSideEffect.} - -proc `or`*(x, y: uint): uint {.magic: "BitorI", noSideEffect.} - ## Computes the `bitwise or` of numbers `x` and `y`. -proc `or`*(x, y: uint8): uint8 {.magic: "BitorI", noSideEffect.} -proc `or`*(x, y: uint16): uint16 {.magic: "BitorI", noSideEffect.} -proc `or`*(x, y: uint32): uint32 {.magic: "BitorI", noSideEffect.} -proc `or`*(x, y: uint64): uint64 {.magic: "BitorI", noSideEffect.} - -proc `xor`*(x, y: uint): uint {.magic: "BitxorI", noSideEffect.} - ## Computes the `bitwise xor` of numbers `x` and `y`. -proc `xor`*(x, y: uint8): uint8 {.magic: "BitxorI", noSideEffect.} -proc `xor`*(x, y: uint16): uint16 {.magic: "BitxorI", noSideEffect.} -proc `xor`*(x, y: uint32): uint32 {.magic: "BitxorI", noSideEffect.} -proc `xor`*(x, y: uint64): uint64 {.magic: "BitxorI", noSideEffect.} - -proc `==`*(x, y: uint): bool {.magic: "EqI", noSideEffect.} - ## Compares two unsigned integers for equality. -proc `==`*(x, y: uint8): bool {.magic: "EqI", noSideEffect.} -proc `==`*(x, y: uint16): bool {.magic: "EqI", noSideEffect.} -proc `==`*(x, y: uint32): bool {.magic: "EqI", noSideEffect.} -proc `==`*(x, y: uint64): bool {.magic: "EqI", noSideEffect.} - -proc `+`*(x, y: uint): uint {.magic: "AddU", noSideEffect.} - ## Binary `+` operator for unsigned integers. -proc `+`*(x, y: uint8): uint8 {.magic: "AddU", noSideEffect.} -proc `+`*(x, y: uint16): uint16 {.magic: "AddU", noSideEffect.} -proc `+`*(x, y: uint32): uint32 {.magic: "AddU", noSideEffect.} -proc `+`*(x, y: uint64): uint64 {.magic: "AddU", noSideEffect.} - -proc `-`*(x, y: uint): uint {.magic: "SubU", noSideEffect.} - ## Binary `-` operator for unsigned integers. -proc `-`*(x, y: uint8): uint8 {.magic: "SubU", noSideEffect.} -proc `-`*(x, y: uint16): uint16 {.magic: "SubU", noSideEffect.} -proc `-`*(x, y: uint32): uint32 {.magic: "SubU", noSideEffect.} -proc `-`*(x, y: uint64): uint64 {.magic: "SubU", noSideEffect.} - -proc `*`*(x, y: uint): uint {.magic: "MulU", noSideEffect.} - ## Binary `*` operator for unsigned integers. -proc `*`*(x, y: uint8): uint8 {.magic: "MulU", noSideEffect.} -proc `*`*(x, y: uint16): uint16 {.magic: "MulU", noSideEffect.} -proc `*`*(x, y: uint32): uint32 {.magic: "MulU", noSideEffect.} -proc `*`*(x, y: uint64): uint64 {.magic: "MulU", noSideEffect.} - -proc `div`*(x, y: uint): uint {.magic: "DivU", noSideEffect.} - ## Computes the integer division for unsigned integers. - ## This is roughly the same as ``trunc(x/y)``. -proc `div`*(x, y: uint8): uint8 {.magic: "DivU", noSideEffect.} -proc `div`*(x, y: uint16): uint16 {.magic: "DivU", noSideEffect.} -proc `div`*(x, y: uint32): uint32 {.magic: "DivU", noSideEffect.} -proc `div`*(x, y: uint64): uint64 {.magic: "DivU", noSideEffect.} - -proc `mod`*(x, y: uint): uint {.magic: "ModU", noSideEffect.} - ## Computes the integer modulo operation (remainder) for unsigned integers. - ## This is the same as ``x - (x div y) * y``. -proc `mod`*(x, y: uint8): uint8 {.magic: "ModU", noSideEffect.} -proc `mod`*(x, y: uint16): uint16 {.magic: "ModU", noSideEffect.} -proc `mod`*(x, y: uint32): uint32 {.magic: "ModU", noSideEffect.} -proc `mod`*(x, y: uint64): uint64 {.magic: "ModU", noSideEffect.} - -proc `<=`*(x, y: uint): bool {.magic: "LeU", noSideEffect.} - ## Returns true if ``x <= y``. -proc `<=`*(x, y: uint8): bool {.magic: "LeU", noSideEffect.} -proc `<=`*(x, y: uint16): bool {.magic: "LeU", noSideEffect.} -proc `<=`*(x, y: uint32): bool {.magic: "LeU", noSideEffect.} -proc `<=`*(x, y: uint64): bool {.magic: "LeU", noSideEffect.} - -proc `<`*(x, y: uint): bool {.magic: "LtU", noSideEffect.} - ## Returns true if ``unsigned(x) < unsigned(y)``. -proc `<`*(x, y: uint8): bool {.magic: "LtU", noSideEffect.} -proc `<`*(x, y: uint16): bool {.magic: "LtU", noSideEffect.} -proc `<`*(x, y: uint32): bool {.magic: "LtU", noSideEffect.} -proc `<`*(x, y: uint64): bool {.magic: "LtU", noSideEffect.} # floating point operations: proc `+`*(x: float32): float32 {.magic: "UnaryPlusF64", noSideEffect.} @@ -1605,52 +722,9 @@ proc `==`*(x, y: float): bool {.magic: "EqF64", noSideEffect.} proc `<=`*(x, y: float): bool {.magic: "LeF64", noSideEffect.} proc `<`*(x, y: float): bool {.magic: "LtF64", noSideEffect.} -# set operators -proc `*`*[T](x, y: set[T]): set[T] {.magic: "MulSet", noSideEffect.} - ## This operator computes the intersection of two sets. - ## - ## .. code-block:: Nim - ## let - ## a = {1, 2, 3} - ## b = {2, 3, 4} - ## echo a * b # => {2, 3} -proc `+`*[T](x, y: set[T]): set[T] {.magic: "PlusSet", noSideEffect.} - ## This operator computes the union of two sets. - ## - ## .. code-block:: Nim - ## let - ## a = {1, 2, 3} - ## b = {2, 3, 4} - ## echo a + b # => {1, 2, 3, 4} -proc `-`*[T](x, y: set[T]): set[T] {.magic: "MinusSet", noSideEffect.} - ## This operator computes the difference of two sets. - ## - ## .. code-block:: Nim - ## let - ## a = {1, 2, 3} - ## b = {2, 3, 4} - ## echo a - b # => {1} -proc contains*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.} - ## One should overload this proc if one wants to overload the ``in`` operator. - ## - ## The parameters are in reverse order! ``a in b`` is a template for - ## ``contains(b, a)``. - ## This is because the unification algorithm that Nim uses for overload - ## resolution works from left to right. - ## But for the ``in`` operator that would be the wrong direction for this - ## piece of code: - ## - ## .. code-block:: Nim - ## var s: set[range['a'..'z']] = {'a'..'c'} - ## assert s.contains('c') - ## assert 'b' in s - ## - ## If ``in`` had been declared as ``[T](elem: T, s: set[T])`` then ``T`` would - ## have been bound to ``char``. But ``s`` is not compatible to type - ## ``set[char]``! The solution is to bind ``T`` to ``range['a'..'z']``. This - ## is achieved by reversing the parameters for ``contains``; ``in`` then - ## passes its arguments in reverse order. +include "system/setops" + proc contains*[U, V, W](s: HSlice[U, V], value: W): bool {.noSideEffect, inline.} = ## Checks if `value` is within the range of `s`; returns true if @@ -1954,12 +1028,6 @@ const # emit this flag # for string literals, it allows for some optimizations. -{.push profiler: off.} -let nimvm* {.magic: "Nimvm", compileTime.}: bool = false - ## May be used only in `when` expression. - ## It is true in Nim VM context and false otherwise. -{.pop.} - proc compileOption*(option: string): bool {. magic: "CompileOption", noSideEffect.} ## Can be used to determine an `on|off` compile-time option. Example: @@ -2215,11 +1283,6 @@ type ## is the signed integer type that should be used for converting ## pointers to integer addresses for readability. - BiggestInt* = int64 - ## is an alias for the biggest signed integer type the Nim compiler - ## supports. Currently this is ``int64``, but it is platform-dependent - ## in general. - BiggestFloat* = float64 ## is an alias for the biggest floating point type the Nim ## compiler supports. Currently this is ``float64``, but it is @@ -2344,221 +1407,6 @@ proc addQuitProc*(quitProc: proc() {.noconv.}) {. # In case of an unhandled exception the exit handlers should # not be called explicitly! The user may decide to do this manually though. -when notJSnotNims: - proc zeroMem*(p: pointer, size: Natural) {.inline, noSideEffect, - tags: [], locks: 0, raises: [].} - ## Overwrites the contents of the memory at ``p`` with the value 0. - ## - ## Exactly ``size`` bytes will be overwritten. Like any procedure - ## dealing with raw memory this is **unsafe**. - - proc copyMem*(dest, source: pointer, size: Natural) {.inline, benign, - tags: [], locks: 0, raises: [].} - ## Copies the contents from the memory at ``source`` to the memory - ## at ``dest``. - ## Exactly ``size`` bytes will be copied. The memory - ## regions may not overlap. Like any procedure dealing with raw - ## memory this is **unsafe**. - - proc moveMem*(dest, source: pointer, size: Natural) {.inline, benign, - tags: [], locks: 0, raises: [].} - ## Copies the contents from the memory at ``source`` to the memory - ## at ``dest``. - ## - ## Exactly ``size`` bytes will be copied. The memory - ## regions may overlap, ``moveMem`` handles this case appropriately - ## and is thus somewhat more safe than ``copyMem``. Like any procedure - ## dealing with raw memory this is still **unsafe**, though. - - proc equalMem*(a, b: pointer, size: Natural): bool {.inline, noSideEffect, - tags: [], locks: 0, raises: [].} - ## Compares the memory blocks ``a`` and ``b``. ``size`` bytes will - ## be compared. - ## - ## If the blocks are equal, `true` is returned, `false` - ## otherwise. Like any procedure dealing with raw memory this is - ## **unsafe**. - -when hasAlloc: - proc alloc*(size: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].} - ## Allocates a new memory block with at least ``size`` bytes. - ## - ## The block has to be freed with `realloc(block, 0) <#realloc,pointer,Natural>`_ - ## or `dealloc(block) <#dealloc,pointer>`_. - ## The block is not initialized, so reading - ## from it before writing to it is undefined behaviour! - ## - ## The allocated memory belongs to its allocating thread! - ## Use `allocShared <#allocShared,Natural>`_ to allocate from a shared heap. - ## - ## See also: - ## * `alloc0 <#alloc0,Natural>`_ - proc createU*(T: typedesc, size = 1.Positive): ptr T {.inline, benign, raises: [].} = - ## 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>`_ - ## or `dealloc(block) <#dealloc,pointer>`_. - ## The block is not initialized, so reading - ## from it before writing to it is undefined behaviour! - ## - ## The allocated memory belongs to its allocating thread! - ## Use `createSharedU <#createSharedU,typedesc>`_ to allocate from a shared heap. - ## - ## See also: - ## * `create <#create,typedesc>`_ - cast[ptr T](alloc(T.sizeof * size)) - - proc alloc0*(size: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].} - ## Allocates a new memory block with at least ``size`` bytes. - ## - ## The block has to be freed with `realloc(block, 0) <#realloc,pointer,Natural>`_ - ## or `dealloc(block) <#dealloc,pointer>`_. - ## The block is initialized with all bytes containing zero, so it is - ## somewhat safer than `alloc <#alloc,Natural>`_. - ## - ## The allocated memory belongs to its allocating thread! - ## Use `allocShared0 <#allocShared0,Natural>`_ to allocate from a shared heap. - proc create*(T: typedesc, size = 1.Positive): ptr T {.inline, benign, raises: [].} = - ## 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>`_ - ## or `dealloc(block) <#dealloc,pointer>`_. - ## The block is initialized with all bytes containing zero, so it is - ## somewhat safer than `createU <#createU,typedesc>`_. - ## - ## The allocated memory belongs to its allocating thread! - ## Use `createShared <#createShared,typedesc>`_ to allocate from a shared heap. - cast[ptr T](alloc0(sizeof(T) * size)) - - proc realloc*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [], - benign, raises: [].} - ## Grows or shrinks a given memory block. - ## - ## If `p` is **nil** then a new memory block is returned. - ## In either way the block has at least ``newSize`` bytes. - ## If ``newSize == 0`` and `p` is not **nil** ``realloc`` calls ``dealloc(p)``. - ## In other cases the block has to be freed with - ## `dealloc(block) <#dealloc,pointer>`_. - ## - ## The allocated memory belongs to its allocating thread! - ## Use `reallocShared <#reallocShared,pointer,Natural>`_ to reallocate - ## from a shared heap. - proc resize*[T](p: ptr T, newSize: Natural): ptr T {.inline, benign, raises: [].} = - ## Grows or shrinks a given memory block. - ## - ## If `p` is **nil** then a new memory block is returned. - ## In either way the block has at least ``T.sizeof * newSize`` bytes. - ## If ``newSize == 0`` and `p` is not **nil** ``resize`` calls ``dealloc(p)``. - ## In other cases the block has to be freed with ``free``. - ## - ## The allocated memory belongs to its allocating thread! - ## Use `resizeShared <#resizeShared,ptr.T,Natural>`_ to reallocate - ## from a shared heap. - cast[ptr T](realloc(p, T.sizeof * newSize)) - - proc dealloc*(p: pointer) {.noconv, rtl, tags: [], benign, raises: [].} - ## Frees the memory allocated with ``alloc``, ``alloc0`` or - ## ``realloc``. - ## - ## **This procedure is dangerous!** - ## If one forgets to free the memory a leak occurs; if one tries to - ## access freed memory (or just freeing it twice!) a core dump may happen - ## or other memory may be corrupted. - ## - ## The freed memory must belong to its allocating thread! - ## Use `deallocShared <#deallocShared,pointer>`_ to deallocate from a shared heap. - - proc allocShared*(size: Natural): pointer {.noconv, rtl, benign, raises: [], tags: [].} - ## Allocates a new memory block on the shared heap with at - ## least ``size`` bytes. - ## - ## The block has to be freed with - ## `reallocShared(block, 0) <#reallocShared,pointer,Natural>`_ - ## or `deallocShared(block) <#deallocShared,pointer>`_. - ## - ## The block is not initialized, so reading from it before writing - ## to it is undefined behaviour! - ## - ## See also: - ## `allocShared0 <#allocShared0,Natural>`_. - proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline, tags: [], - benign, raises: [].} = - ## Allocates a new memory block on the shared heap with at - ## least ``T.sizeof * size`` bytes. - ## - ## The block has to be freed with - ## `resizeShared(block, 0) <#resizeShared,ptr.T,Natural>`_ or - ## `freeShared(block) <#freeShared,ptr.T>`_. - ## - ## The block is not initialized, so reading from it before writing - ## to it is undefined behaviour! - ## - ## See also: - ## * `createShared <#createShared,typedesc>`_ - cast[ptr T](allocShared(T.sizeof * size)) - - proc allocShared0*(size: Natural): pointer {.noconv, rtl, benign, raises: [], tags: [].} - ## Allocates a new memory block on the shared heap with at - ## least ``size`` bytes. - ## - ## The block has to be freed with - ## `reallocShared(block, 0) <#reallocShared,pointer,Natural>`_ - ## or `deallocShared(block) <#deallocShared,pointer>`_. - ## - ## The block is initialized with all bytes - ## containing zero, so it is somewhat safer than - ## `allocShared <#allocShared,Natural>`_. - proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} = - ## Allocates a new memory block on the shared heap with at - ## least ``T.sizeof * size`` bytes. - ## - ## The block has to be freed with - ## `resizeShared(block, 0) <#resizeShared,ptr.T,Natural>`_ or - ## `freeShared(block) <#freeShared,ptr.T>`_. - ## - ## The block is initialized with all bytes - ## containing zero, so it is somewhat safer than - ## `createSharedU <#createSharedU,typedesc>`_. - cast[ptr T](allocShared0(T.sizeof * size)) - - proc reallocShared*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [], - benign, raises: [].} - ## Grows or shrinks a given memory block on the heap. - ## - ## If `p` is **nil** then a new memory block is returned. - ## In either way the block has at least ``newSize`` bytes. - ## If ``newSize == 0`` and `p` is not **nil** ``reallocShared`` calls - ## ``deallocShared(p)``. - ## In other cases the block has to be freed with - ## `deallocShared <#deallocShared,pointer>`_. - proc resizeShared*[T](p: ptr T, newSize: Natural): ptr T {.inline, raises: [].} = - ## Grows or shrinks a given memory block on the heap. - ## - ## If `p` is **nil** then a new memory block is returned. - ## In either way the block has at least ``T.sizeof * newSize`` bytes. - ## If ``newSize == 0`` and `p` is not **nil** ``resizeShared`` calls - ## ``freeShared(p)``. - ## In other cases the block has to be freed with - ## `freeShared <#freeShared,ptr.T>`_. - cast[ptr T](reallocShared(p, T.sizeof * newSize)) - - proc deallocShared*(p: pointer) {.noconv, rtl, benign, raises: [], tags: [].} - ## Frees the memory allocated with ``allocShared``, ``allocShared0`` or - ## ``reallocShared``. - ## - ## **This procedure is dangerous!** - ## If one forgets to free the memory a leak occurs; if one tries to - ## access freed memory (or just freeing it twice!) a core dump may happen - ## or other memory may be corrupted. - proc freeShared*[T](p: ptr T) {.inline, benign, raises: [].} = - ## Frees the memory allocated with ``createShared``, ``createSharedU`` or - ## ``resizeShared``. - ## - ## **This procedure is dangerous!** - ## If one forgets to free the memory a leak occurs; if one tries to - ## access freed memory (or just freeing it twice!) a core dump may happen - ## or other memory may be corrupted. - deallocShared(p) proc swap*[T](a, b: var T) {.magic: "Swap", noSideEffect.} ## Swaps the values `a` and `b`. @@ -2595,289 +1443,16 @@ const ## and expect a reasonable result - use the `classify` procedure ## in the `math module <math.html>`_ for checking for NaN. -# GC interface: -when hasAlloc: - proc getOccupiedMem*(): int {.rtl.} - ## Returns the number of bytes that are owned by the process and hold data. - - proc getFreeMem*(): int {.rtl.} - ## Returns the number of bytes that are owned by the process, but do not - ## hold any meaningful data. - - proc getTotalMem*(): int {.rtl.} - ## Returns the number of bytes that are owned by the process. - - -when hasAlloc and hasThreadSupport: - proc getOccupiedSharedMem*(): int {.rtl.} - ## Returns the number of bytes that are owned by the process - ## on the shared heap and hold data. This is only available when - ## threads are enabled. - - proc getFreeSharedMem*(): int {.rtl.} - ## Returns the number of bytes that are owned by the - ## process on the shared heap, but do not hold any meaningful data. - ## This is only available when threads are enabled. - - proc getTotalSharedMem*(): int {.rtl.} - ## Returns the number of bytes on the shared heap that are owned by the - ## process. This is only available when threads are enabled. +include "system/memalloc" proc `|`*(a, b: typedesc): typedesc = discard -when sizeof(int) <= 2: - type IntLikeForCount = int|int8|int16|char|bool|uint8|enum -else: - type IntLikeForCount = int|int8|int16|int32|char|bool|uint8|uint16|enum +include "system/iterators_1" -iterator countdown*[T](a, b: T, step: Positive = 1): T {.inline.} = - ## Counts from ordinal value `a` down to `b` (inclusive) with the given - ## step count. - ## - ## `T` may be any ordinal type, `step` may only be positive. - ## - ## **Note**: This fails to count to ``low(int)`` if T = int for - ## efficiency reasons. - ## - ## .. code-block:: Nim - ## for i in countdown(7, 3): - ## echo i # => 7; 6; 5; 4; 3 - ## - ## for i in countdown(9, 2, 3): - ## echo i # => 9; 6; 3 - when T is (uint|uint64): - var res = a - while res >= b: - yield res - if res == b: break - dec(res, step) - elif T is IntLikeForCount: - var res = int(a) - while res >= int(b): - yield T(res) - dec(res, step) - else: - var res = a - while res >= b: - yield res - dec(res, step) - -when defined(nimNewRoof): - iterator countup*[T](a, b: T, step: Positive = 1): T {.inline.} = - ## Counts from ordinal value `a` to `b` (inclusive) with the given - ## step count. - ## - ## `T` may be any ordinal type, `step` may only be positive. - ## - ## **Note**: This fails to count to ``high(int)`` if T = int for - ## efficiency reasons. - ## - ## .. code-block:: Nim - ## for i in countup(3, 7): - ## echo i # => 3; 4; 5; 6; 7 - ## - ## for i in countup(2, 9, 3): - ## echo i # => 2; 5; 8 - mixin inc - when T is IntLikeForCount: - var res = int(a) - while res <= int(b): - yield T(res) - inc(res, step) - else: - var res = a - while res <= b: - yield res - inc(res, step) - - iterator `..`*[T](a, b: T): T {.inline.} = - ## An alias for `countup(a, b, 1)`. - ## - ## See also: - ## * [..<](#..<.i,T,T) - ## - ## .. code-block:: Nim - ## for i in 3 .. 7: - ## echo i # => 3; 4; 5; 6; 7 - mixin inc - when T is IntLikeForCount: - var res = int(a) - while res <= int(b): - yield T(res) - inc(res) - else: - var res = a - while res <= b: - yield res - inc(res) - - template dotdotImpl(t) {.dirty.} = - iterator `..`*(a, b: t): t {.inline.} = - ## A type specialized version of ``..`` for convenience so that - ## mixing integer types works better. - ## - ## See also: - ## * [..<](#..<.i,T,T) - var res = a - while res <= b: - yield res - inc(res) - - dotdotImpl(int64) - dotdotImpl(int32) - dotdotImpl(uint64) - dotdotImpl(uint32) - - iterator `..<`*[T](a, b: T): T {.inline.} = - mixin inc - var i = a - while i < b: - yield i - inc i - - template dotdotLessImpl(t) {.dirty.} = - iterator `..<`*(a, b: t): t {.inline.} = - ## A type specialized version of ``..<`` for convenience so that - ## mixing integer types works better. - var res = a - while res < b: - yield res - inc(res) - - dotdotLessImpl(int64) - dotdotLessImpl(int32) - dotdotLessImpl(uint64) - dotdotLessImpl(uint32) - -else: # not defined(nimNewRoof) - iterator countup*[S, T](a: S, b: T, step = 1): T {.inline.} = - ## Counts from ordinal value `a` up to `b` (inclusive) with the given - ## step count. - ## - ## `S`, `T` may be any ordinal type, `step` may only be positive. - ## - ## **Note**: This fails to count to ``high(int)`` if T = int for - ## efficiency reasons. - ## - ## .. code-block:: Nim - ## for i in countup(3, 7): - ## echo i # => 3; 4; 5; 6; 7 - ## - ## for i in countup(2, 9, 3): - ## echo i # => 2; 5; 8 - when T is IntLikeForCount: - var res = int(a) - while res <= int(b): - yield T(res) - inc(res, step) - else: - var res = T(a) - while res <= b: - yield res - inc(res, step) - - iterator `..`*[S, T](a: S, b: T): T {.inline.} = - ## An alias for `countup(a, b, 1)`. - ## - ## See also: - ## * [..<](#..<.i,T,T) - ## - ## .. code-block:: Nim - ## for i in 3 .. 7: - ## echo i # => 3; 4; 5; 6; 7 - mixin inc - when T is IntLikeForCount: - var res = int(a) - while res <= int(b): - yield T(res) - inc(res) - else: - var res = T(a) - while res <= b: - yield res - inc(res) - - iterator `..<`*[S, T](a: S, b: T): T {.inline.} = - mixin inc - var i = T(a) - while i < b: - yield i - inc i - - -iterator `||`*[S, T](a: S, b: T, annotation: static string = "parallel for"): T {. - inline, magic: "OmpParFor", sideEffect.} = - ## OpenMP parallel loop iterator. Same as `..` but the loop may run in parallel. - ## - ## `annotation` is an additional annotation for the code generator to use. - ## The default annotation is `parallel for`. - ## Please refer to the `OpenMP Syntax Reference - ## <https://www.openmp.org/wp-content/uploads/OpenMP-4.5-1115-CPP-web.pdf>`_ - ## for further information. - ## - ## Note that the compiler maps that to - ## the ``#pragma omp parallel for`` construct of `OpenMP`:idx: and as - ## such isn't aware of the parallelism in your code! Be careful! Later - ## versions of ``||`` will get proper support by Nim's code generator - ## and GC. - discard - -iterator `||`*[S, T](a: S, b: T, step: Positive, annotation: static string = "parallel for"): T {. - inline, magic: "OmpParFor", sideEffect.} = - ## OpenMP parallel loop iterator with stepping. - ## Same as `countup` but the loop may run in parallel. - ## - ## `annotation` is an additional annotation for the code generator to use. - ## The default annotation is `parallel for`. - ## Please refer to the `OpenMP Syntax Reference - ## <https://www.openmp.org/wp-content/uploads/OpenMP-4.5-1115-CPP-web.pdf>`_ - ## for further information. - ## - ## Note that the compiler maps that to - ## the ``#pragma omp parallel for`` construct of `OpenMP`:idx: and as - ## such isn't aware of the parallelism in your code! Be careful! Later - ## versions of ``||`` will get proper support by Nim's code generator - ## and GC. - discard {.push stackTrace: off.} -proc min*(x, y: int): int {.magic: "MinI", noSideEffect.} = - if x <= y: x else: y -proc min*(x, y: int8): int8 {.magic: "MinI", noSideEffect.} = - if x <= y: x else: y -proc min*(x, y: int16): int16 {.magic: "MinI", noSideEffect.} = - if x <= y: x else: y -proc min*(x, y: int32): int32 {.magic: "MinI", noSideEffect.} = - if x <= y: x else: y -proc min*(x, y: int64): int64 {.magic: "MinI", noSideEffect.} = - ## The minimum value of two integers. - if x <= y: x else: y - -proc min*[T](x: openArray[T]): T = - ## The minimum value of `x`. ``T`` needs to have a ``<`` operator. - result = x[0] - for i in 1..high(x): - if x[i] < result: result = x[i] - -proc max*(x, y: int): int {.magic: "MaxI", noSideEffect.} = - if y <= x: x else: y -proc max*(x, y: int8): int8 {.magic: "MaxI", noSideEffect.} = - if y <= x: x else: y -proc max*(x, y: int16): int16 {.magic: "MaxI", noSideEffect.} = - if y <= x: x else: y -proc max*(x, y: int32): int32 {.magic: "MaxI", noSideEffect.} = - if y <= x: x else: y -proc max*(x, y: int64): int64 {.magic: "MaxI", noSideEffect.} = - ## The maximum value of two integers. - if y <= x: x else: y - -proc max*[T](x: openArray[T]): T = - ## The maximum value of `x`. ``T`` needs to have a ``<`` operator. - result = x[0] - for i in 1..high(x): - if result < x[i]: result = x[i] proc abs*(x: float64): float64 {.noSideEffect, inline.} = if x < 0.0: -x else: x @@ -2895,21 +1470,13 @@ proc min*[T: not SomeFloat](x, y: T): T {.inline.} = if x <= y: x else: y proc max*[T: not SomeFloat](x, y: T): T {.inline.} = if y <= x: x else: y + {.pop.} # stackTrace: off + proc high*(T: typedesc[SomeFloat]): T = Inf proc low*(T: typedesc[SomeFloat]): T = NegInf -proc clamp*[T](x, a, b: T): T = - ## Limits the value ``x`` within the interval [a, b]. - ## - ## .. code-block:: Nim - ## assert((1.4).clamp(0.0, 1.0) == 1.0) - ## assert((0.5).clamp(0.0, 1.0) == 0.5) - if x < a: return a - if x > b: return b - return x - proc len*[U: Ordinal; V: Ordinal](x: HSlice[U, V]): int {.noSideEffect, inline.} = ## Length of ordinal slice. When x.b < x.a returns zero length. ## @@ -2937,21 +1504,6 @@ proc isNil*[T: proc](x: T): bool {.noSideEffect, magic: "IsNil".} ## Fast check whether `x` is nil. This is sometimes more efficient than ## ``== nil``. -proc `==`*[I, T](x, y: array[I, T]): bool = - for f in low(x)..high(x): - if x[f] != y[f]: - return - result = true - -proc `==`*[T](x, y: openArray[T]): bool = - if x.len != y.len: - return false - - for f in low(x)..high(x): - if x[f] != y[f]: - return false - - result = true proc `@`*[T](a: openArray[T]): seq[T] = ## Turns an *openArray* into a sequence. @@ -3004,43 +1556,6 @@ proc `&`*[T](x: T, y: seq[T]): seq[T] {.noSideEffect.} = for i in 0..y.len-1: result[i+1] = y[i] -proc `==`*[T](x, y: seq[T]): bool {.noSideEffect.} = - ## Generic equals operator for sequences: relies on a equals operator for - ## the element type `T`. - when nimvm: - when not defined(nimNoNil): - if x.isNil and y.isNil: - return true - else: - if x.len == 0 and y.len == 0: - return true - else: - when not defined(JS): - proc seqToPtr[T](x: seq[T]): pointer {.inline, noSideEffect.} = - when defined(nimSeqsV2): - result = cast[NimSeqV2[T]](x).p - else: - result = cast[pointer](x) - - if seqToPtr(x) == seqToPtr(y): - return true - else: - var sameObject = false - asm """`sameObject` = `x` === `y`""" - if sameObject: return true - - when not defined(nimNoNil): - if x.isNil or y.isNil: - return false - - if x.len != y.len: - return false - - for i in 0..x.len-1: - if x[i] != y[i]: - return false - - return true proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.} ## Converts the AST of `x` into a string representation. This is very useful @@ -3222,107 +1737,7 @@ proc `<`*[T: tuple](x, y: T): bool = return false - -# ----------------- GC interface --------------------------------------------- -const - usesDestructors = defined(gcDestructors) or defined(gcHooks) - -when not usesDestructors: - {.pragma: nodestroy.} - -when hasAlloc: - type - GC_Strategy* = enum ## The strategy the GC should use for the application. - gcThroughput, ## optimize for throughput - gcResponsiveness, ## optimize for responsiveness (default) - gcOptimizeTime, ## optimize for speed - gcOptimizeSpace ## optimize for memory footprint - -when hasAlloc and not defined(JS) and not usesDestructors: - proc GC_disable*() {.rtl, inl, benign.} - ## Disables the GC. If called `n` times, `n` calls to `GC_enable` - ## are needed to reactivate the GC. - ## - ## Note that in most circumstances one should only disable - ## the mark and sweep phase with - ## `GC_disableMarkAndSweep <#GC_disableMarkAndSweep>`_. - - proc GC_enable*() {.rtl, inl, benign.} - ## Enables the GC again. - - proc GC_fullCollect*() {.rtl, benign.} - ## Forces a full garbage collection pass. - ## Ordinary code does not need to call this (and should not). - - proc GC_enableMarkAndSweep*() {.rtl, benign.} - proc GC_disableMarkAndSweep*() {.rtl, benign.} - ## The current implementation uses a reference counting garbage collector - ## with a seldomly run mark and sweep phase to free cycles. The mark and - ## sweep phase may take a long time and is not needed if the application - ## does not create cycles. Thus the mark and sweep phase can be deactivated - ## and activated separately from the rest of the GC. - - proc GC_getStatistics*(): string {.rtl, benign.} - ## Returns an informative string about the GC's activity. This may be useful - ## for tweaking. - - proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.} - proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.} - proc GC_ref*(x: string) {.magic: "GCref", benign.} - ## Marks the object `x` as referenced, so that it will not be freed until - ## it is unmarked via `GC_unref`. - ## If called n-times for the same object `x`, - ## n calls to `GC_unref` are needed to unmark `x`. - - proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.} - proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.} - proc GC_unref*(x: string) {.magic: "GCunref", benign.} - ## See the documentation of `GC_ref <#GC_ref,string>`_. - - proc nimGC_setStackBottom*(theStackBottom: pointer) {.compilerRtl, noinline, benign.} - ## Expands operating GC stack range to `theStackBottom`. Does nothing - ## if current stack bottom is already lower than `theStackBottom`. - -when hasAlloc and defined(JS): - template GC_disable* = - {.warning: "GC_disable is a no-op in JavaScript".} - - template GC_enable* = - {.warning: "GC_enable is a no-op in JavaScript".} - - template GC_fullCollect* = - {.warning: "GC_fullCollect is a no-op in JavaScript".} - - template GC_setStrategy* = - {.warning: "GC_setStrategy is a no-op in JavaScript".} - - template GC_enableMarkAndSweep* = - {.warning: "GC_enableMarkAndSweep is a no-op in JavaScript".} - - template GC_disableMarkAndSweep* = - {.warning: "GC_disableMarkAndSweep is a no-op in JavaScript".} - - template GC_ref*[T](x: ref T) = - {.warning: "GC_ref is a no-op in JavaScript".} - - template GC_ref*[T](x: seq[T]) = - {.warning: "GC_ref is a no-op in JavaScript".} - - template GC_ref*(x: string) = - {.warning: "GC_ref is a no-op in JavaScript".} - - template GC_unref*[T](x: ref T) = - {.warning: "GC_unref is a no-op in JavaScript".} - - template GC_unref*[T](x: seq[T]) = - {.warning: "GC_unref is a no-op in JavaScript".} - - template GC_unref*(x: string) = - {.warning: "GC_unref is a no-op in JavaScript".} - - template GC_getStatistics*(): string = - {.warning: "GC_getStatistics is a no-op in JavaScript".} - "" +include "system/gc_interface" # we have to compute this here before turning it off in except.nim anyway ... const NimStackTrace = compileOption("stacktrace") @@ -3850,21 +2265,6 @@ when notJSnotNims: """.} when defined(JS): - # Stubs: - proc getOccupiedMem(): int = return -1 - proc getFreeMem(): int = return -1 - proc getTotalMem(): int = return -1 - - proc dealloc(p: pointer) = discard - proc alloc(size: Natural): pointer = discard - proc alloc0(size: Natural): pointer = discard - proc realloc(p: pointer, newsize: Natural): pointer = discard - - proc allocShared(size: Natural): pointer = discard - proc allocShared0(size: Natural): pointer = discard - proc deallocShared(p: pointer) = discard - proc reallocShared(p: pointer, newsize: Natural): pointer = discard - when not defined(nimscript): include "system/jssys" include "system/reprjs" @@ -4111,26 +2511,6 @@ proc gorgeEx*(command: string, input = "", cache = ""): tuple[output: string, ## precious exit code. discard -proc `+=`*[T: SomeInteger](x: var T, y: T) {. - magic: "Inc", noSideEffect.} - ## Increments an integer. - -proc `+=`*[T: enum|bool](x: var T, y: T) {. - magic: "Inc", noSideEffect, deprecated: "use `inc` instead".} - ## **Deprecated since v0.20**: use `inc` instead. - -proc `-=`*[T: SomeInteger](x: var T, y: T) {. - magic: "Dec", noSideEffect.} - ## Decrements an integer. - -proc `-=`*[T: enum|bool](x: var T, y: T) {. - magic: "Dec", noSideEffect, deprecated: "0.20.0, use `dec` instead".} - ## **Deprecated since v0.20**: use `dec` instead. - -proc `*=`*[T: SomeInteger](x: var T, y: T) {. - inline, noSideEffect.} = - ## Binary `*=` operator for integers. - x = x * y proc `+=`*[T: float|float32|float64] (x: var T, y: T) {. inline, noSideEffect.} = diff --git a/lib/system/arithmetics.nim b/lib/system/arithmetics.nim new file mode 100644 index 000000000..f9f9b35d4 --- /dev/null +++ b/lib/system/arithmetics.nim @@ -0,0 +1,486 @@ +proc succ*[T: Ordinal](x: T, y = 1): T {.magic: "Succ", noSideEffect.} + ## Returns the ``y``-th successor (default: 1) of the value ``x``. + ## ``T`` has to be an `ordinal type <#Ordinal>`_. + ## + ## If such a value does not exist, ``OverflowError`` is raised + ## or a compile time error occurs. + ## + ## .. code-block:: Nim + ## let x = 5 + ## echo succ(5) # => 6 + ## echo succ(5, 3) # => 8 + +proc pred*[T: Ordinal](x: T, y = 1): T {.magic: "Pred", noSideEffect.} + ## Returns the ``y``-th predecessor (default: 1) of the value ``x``. + ## ``T`` has to be an `ordinal type <#Ordinal>`_. + ## + ## If such a value does not exist, ``OverflowError`` is raised + ## or a compile time error occurs. + ## + ## .. code-block:: Nim + ## let x = 5 + ## echo pred(5) # => 4 + ## echo pred(5, 3) # => 2 + +proc inc*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Inc", noSideEffect.} + ## Increments the ordinal ``x`` by ``y``. + ## + ## If such a value does not exist, ``OverflowError`` is raised or a compile + ## time error occurs. This is a short notation for: ``x = succ(x, y)``. + ## + ## .. code-block:: Nim + ## var i = 2 + ## inc(i) # i <- 3 + ## inc(i, 3) # i <- 6 + +proc dec*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Dec", noSideEffect.} + ## Decrements the ordinal ``x`` by ``y``. + ## + ## If such a value does not exist, ``OverflowError`` is raised or a compile + ## time error occurs. This is a short notation for: ``x = pred(x, y)``. + ## + ## .. code-block:: Nim + ## var i = 2 + ## dec(i) # i <- 1 + ## dec(i, 3) # i <- -2 + + + +# -------------------------------------------------------------------------- +# built-in operators + +when defined(nimNoZeroExtendMagic): + proc ze*(x: int8): int {.deprecated.} = + ## zero extends a smaller integer type to ``int``. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int](uint(cast[uint8](x))) + + proc ze*(x: int16): int {.deprecated.} = + ## zero extends a smaller integer type to ``int``. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int](uint(cast[uint16](x))) + + proc ze64*(x: int8): int64 {.deprecated.} = + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int64](uint64(cast[uint8](x))) + + proc ze64*(x: int16): int64 {.deprecated.} = + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int64](uint64(cast[uint16](x))) + + proc ze64*(x: int32): int64 {.deprecated.} = + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int64](uint64(cast[uint32](x))) + + proc ze64*(x: int): int64 {.deprecated.} = + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``. + ## (This is the case on 64 bit processors.) + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int64](uint64(cast[uint](x))) + + proc toU8*(x: int): int8 {.deprecated.} = + ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits + ## from `x`. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int8](x) + + proc toU16*(x: int): int16 {.deprecated.} = + ## treats `x` as unsigned and converts it to an ``int16`` by taking the last + ## 16 bits from `x`. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int16](x) + + proc toU32*(x: int64): int32 {.deprecated.} = + ## treats `x` as unsigned and converts it to an ``int32`` by taking the + ## last 32 bits from `x`. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + cast[int32](x) + +elif not defined(JS): + proc ze*(x: int8): int {.magic: "Ze8ToI", noSideEffect, deprecated.} + ## zero extends a smaller integer type to ``int``. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + + proc ze*(x: int16): int {.magic: "Ze16ToI", noSideEffect, deprecated.} + ## zero extends a smaller integer type to ``int``. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + + proc ze64*(x: int8): int64 {.magic: "Ze8ToI64", noSideEffect, deprecated.} + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + + proc ze64*(x: int16): int64 {.magic: "Ze16ToI64", noSideEffect, deprecated.} + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + + proc ze64*(x: int32): int64 {.magic: "Ze32ToI64", noSideEffect, deprecated.} + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + + proc ze64*(x: int): int64 {.magic: "ZeIToI64", noSideEffect, deprecated.} + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``. + ## (This is the case on 64 bit processors.) + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + + proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect, deprecated.} + ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits + ## from `x`. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + + proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect, deprecated.} + ## treats `x` as unsigned and converts it to an ``int16`` by taking the last + ## 16 bits from `x`. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + + proc toU32*(x: int64): int32 {.magic: "ToU32", noSideEffect, deprecated.} + ## treats `x` as unsigned and converts it to an ``int32`` by taking the + ## last 32 bits from `x`. + ## **Deprecated since version 0.19.9**: Use unsigned integers instead. + +# integer calculations: +proc `+`*(x: int): int {.magic: "UnaryPlusI", noSideEffect.} + ## Unary `+` operator for an integer. Has no effect. +proc `+`*(x: int8): int8 {.magic: "UnaryPlusI", noSideEffect.} +proc `+`*(x: int16): int16 {.magic: "UnaryPlusI", noSideEffect.} +proc `+`*(x: int32): int32 {.magic: "UnaryPlusI", noSideEffect.} +proc `+`*(x: int64): int64 {.magic: "UnaryPlusI", noSideEffect.} + +proc `-`*(x: int): int {.magic: "UnaryMinusI", noSideEffect.} + ## Unary `-` operator for an integer. Negates `x`. +proc `-`*(x: int8): int8 {.magic: "UnaryMinusI", noSideEffect.} +proc `-`*(x: int16): int16 {.magic: "UnaryMinusI", noSideEffect.} +proc `-`*(x: int32): int32 {.magic: "UnaryMinusI", noSideEffect.} +proc `-`*(x: int64): int64 {.magic: "UnaryMinusI64", noSideEffect.} + +proc `not`*(x: int): int {.magic: "BitnotI", noSideEffect.} + ## Computes the `bitwise complement` of the integer `x`. + ## + ## .. code-block:: Nim + ## var + ## a = 0'u8 + ## b = 0'i8 + ## c = 1000'u16 + ## d = 1000'i16 + ## + ## echo not a # => 255 + ## echo not b # => -1 + ## echo not c # => 64535 + ## echo not d # => -1001 +proc `not`*(x: int8): int8 {.magic: "BitnotI", noSideEffect.} +proc `not`*(x: int16): int16 {.magic: "BitnotI", noSideEffect.} +proc `not`*(x: int32): int32 {.magic: "BitnotI", noSideEffect.} +proc `not`*(x: int64): int64 {.magic: "BitnotI", noSideEffect.} + +proc `+`*(x, y: int): int {.magic: "AddI", noSideEffect.} + ## Binary `+` operator for an integer. +proc `+`*(x, y: int8): int8 {.magic: "AddI", noSideEffect.} +proc `+`*(x, y: int16): int16 {.magic: "AddI", noSideEffect.} +proc `+`*(x, y: int32): int32 {.magic: "AddI", noSideEffect.} +proc `+`*(x, y: int64): int64 {.magic: "AddI", noSideEffect.} + +proc `-`*(x, y: int): int {.magic: "SubI", noSideEffect.} + ## Binary `-` operator for an integer. +proc `-`*(x, y: int8): int8 {.magic: "SubI", noSideEffect.} +proc `-`*(x, y: int16): int16 {.magic: "SubI", noSideEffect.} +proc `-`*(x, y: int32): int32 {.magic: "SubI", noSideEffect.} +proc `-`*(x, y: int64): int64 {.magic: "SubI", noSideEffect.} + +proc `*`*(x, y: int): int {.magic: "MulI", noSideEffect.} + ## Binary `*` operator for an integer. +proc `*`*(x, y: int8): int8 {.magic: "MulI", noSideEffect.} +proc `*`*(x, y: int16): int16 {.magic: "MulI", noSideEffect.} +proc `*`*(x, y: int32): int32 {.magic: "MulI", noSideEffect.} +proc `*`*(x, y: int64): int64 {.magic: "MulI", noSideEffect.} + +proc `div`*(x, y: int): int {.magic: "DivI", noSideEffect.} + ## Computes the integer division. + ## + ## This is roughly the same as ``trunc(x/y)``. + ## + ## .. code-block:: Nim + ## ( 1 div 2) == 0 + ## ( 2 div 2) == 1 + ## ( 3 div 2) == 1 + ## ( 7 div 3) == 2 + ## (-7 div 3) == -2 + ## ( 7 div -3) == -2 + ## (-7 div -3) == 2 +proc `div`*(x, y: int8): int8 {.magic: "DivI", noSideEffect.} +proc `div`*(x, y: int16): int16 {.magic: "DivI", noSideEffect.} +proc `div`*(x, y: int32): int32 {.magic: "DivI", noSideEffect.} +proc `div`*(x, y: int64): int64 {.magic: "DivI", noSideEffect.} + +proc `mod`*(x, y: int): int {.magic: "ModI", noSideEffect.} + ## Computes the integer modulo operation (remainder). + ## + ## This is the same as ``x - (x div y) * y``. + ## + ## .. code-block:: Nim + ## ( 7 mod 5) == 2 + ## (-7 mod 5) == -2 + ## ( 7 mod -5) == 2 + ## (-7 mod -5) == -2 +proc `mod`*(x, y: int8): int8 {.magic: "ModI", noSideEffect.} +proc `mod`*(x, y: int16): int16 {.magic: "ModI", noSideEffect.} +proc `mod`*(x, y: int32): int32 {.magic: "ModI", noSideEffect.} +proc `mod`*(x, y: int64): int64 {.magic: "ModI", noSideEffect.} + +when defined(nimOldShiftRight) or not defined(nimAshr): + const shrDepMessage = "`shr` will become sign preserving." + proc `shr`*(x: int, y: SomeInteger): int {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} + proc `shr`*(x: int8, y: SomeInteger): int8 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} + proc `shr`*(x: int16, y: SomeInteger): int16 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} + proc `shr`*(x: int32, y: SomeInteger): int32 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} + proc `shr`*(x: int64, y: SomeInteger): int64 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} +else: + proc `shr`*(x: int, y: SomeInteger): int {.magic: "AshrI", noSideEffect.} + ## Computes the `shift right` operation of `x` and `y`, filling + ## vacant bit positions with the sign bit. + ## + ## **Note**: `Operator precedence <manual.html#syntax-precedence>`_ + ## is different than in *C*. + ## + ## See also: + ## * `ashr proc <#ashr,int,SomeInteger>`_ for arithmetic shift right + ## + ## .. code-block:: Nim + ## 0b0001_0000'i8 shr 2 == 0b0000_0100'i8 + ## 0b0000_0001'i8 shr 1 == 0b0000_0000'i8 + ## 0b1000_0000'i8 shr 4 == 0b1111_1000'i8 + ## -1 shr 5 == -1 + ## 1 shr 5 == 0 + ## 16 shr 2 == 4 + ## -16 shr 2 == -4 + proc `shr`*(x: int8, y: SomeInteger): int8 {.magic: "AshrI", noSideEffect.} + proc `shr`*(x: int16, y: SomeInteger): int16 {.magic: "AshrI", noSideEffect.} + proc `shr`*(x: int32, y: SomeInteger): int32 {.magic: "AshrI", noSideEffect.} + proc `shr`*(x: int64, y: SomeInteger): int64 {.magic: "AshrI", noSideEffect.} + + +proc `shl`*(x: int, y: SomeInteger): int {.magic: "ShlI", noSideEffect.} + ## Computes the `shift left` operation of `x` and `y`. + ## + ## **Note**: `Operator precedence <manual.html#syntax-precedence>`_ + ## is different than in *C*. + ## + ## .. code-block:: Nim + ## 1'i32 shl 4 == 0x0000_0010 + ## 1'i64 shl 4 == 0x0000_0000_0000_0010 +proc `shl`*(x: int8, y: SomeInteger): int8 {.magic: "ShlI", noSideEffect.} +proc `shl`*(x: int16, y: SomeInteger): int16 {.magic: "ShlI", noSideEffect.} +proc `shl`*(x: int32, y: SomeInteger): int32 {.magic: "ShlI", noSideEffect.} +proc `shl`*(x: int64, y: SomeInteger): int64 {.magic: "ShlI", noSideEffect.} + +when defined(nimAshr): + proc ashr*(x: int, y: SomeInteger): int {.magic: "AshrI", noSideEffect.} + ## Shifts right by pushing copies of the leftmost bit in from the left, + ## and let the rightmost bits fall off. + ## + ## Note that `ashr` is not an operator so use the normal function + ## call syntax for it. + ## + ## See also: + ## * `shr proc <#shr,int,SomeInteger>`_ + ## + ## .. code-block:: Nim + ## ashr(0b0001_0000'i8, 2) == 0b0000_0100'i8 + ## ashr(0b1000_0000'i8, 8) == 0b1111_1111'i8 + ## ashr(0b1000_0000'i8, 1) == 0b1100_0000'i8 + proc ashr*(x: int8, y: SomeInteger): int8 {.magic: "AshrI", noSideEffect.} + proc ashr*(x: int16, y: SomeInteger): int16 {.magic: "AshrI", noSideEffect.} + proc ashr*(x: int32, y: SomeInteger): int32 {.magic: "AshrI", noSideEffect.} + proc ashr*(x: int64, y: SomeInteger): int64 {.magic: "AshrI", noSideEffect.} +else: + # used for bootstrapping the compiler + proc ashr*[T](x: T, y: SomeInteger): T = discard + +proc `and`*(x, y: int): int {.magic: "BitandI", noSideEffect.} + ## Computes the `bitwise and` of numbers `x` and `y`. + ## + ## .. code-block:: Nim + ## (0b0011 and 0b0101) == 0b0001 + ## (0b0111 and 0b1100) == 0b0100 +proc `and`*(x, y: int8): int8 {.magic: "BitandI", noSideEffect.} +proc `and`*(x, y: int16): int16 {.magic: "BitandI", noSideEffect.} +proc `and`*(x, y: int32): int32 {.magic: "BitandI", noSideEffect.} +proc `and`*(x, y: int64): int64 {.magic: "BitandI", noSideEffect.} + +proc `or`*(x, y: int): int {.magic: "BitorI", noSideEffect.} + ## Computes the `bitwise or` of numbers `x` and `y`. + ## + ## .. code-block:: Nim + ## (0b0011 or 0b0101) == 0b0111 + ## (0b0111 or 0b1100) == 0b1111 +proc `or`*(x, y: int8): int8 {.magic: "BitorI", noSideEffect.} +proc `or`*(x, y: int16): int16 {.magic: "BitorI", noSideEffect.} +proc `or`*(x, y: int32): int32 {.magic: "BitorI", noSideEffect.} +proc `or`*(x, y: int64): int64 {.magic: "BitorI", noSideEffect.} + +proc `xor`*(x, y: int): int {.magic: "BitxorI", noSideEffect.} + ## Computes the `bitwise xor` of numbers `x` and `y`. + ## + ## .. code-block:: Nim + ## (0b0011 xor 0b0101) == 0b0110 + ## (0b0111 xor 0b1100) == 0b1011 +proc `xor`*(x, y: int8): int8 {.magic: "BitxorI", noSideEffect.} +proc `xor`*(x, y: int16): int16 {.magic: "BitxorI", noSideEffect.} +proc `xor`*(x, y: int32): int32 {.magic: "BitxorI", noSideEffect.} +proc `xor`*(x, y: int64): int64 {.magic: "BitxorI", noSideEffect.} + +type + IntMax32 = int|int8|int16|int32 + +proc `+%`*(x, y: IntMax32): IntMax32 {.magic: "AddU", noSideEffect.} +proc `+%`*(x, y: int64): int64 {.magic: "AddU", noSideEffect.} + ## Treats `x` and `y` as unsigned and adds them. + ## + ## The result is truncated to fit into the result. + ## This implements modulo arithmetic. No overflow errors are possible. + +proc `-%`*(x, y: IntMax32): IntMax32 {.magic: "SubU", noSideEffect.} +proc `-%`*(x, y: int64): int64 {.magic: "SubU", noSideEffect.} + ## Treats `x` and `y` as unsigned and subtracts them. + ## + ## The result is truncated to fit into the result. + ## This implements modulo arithmetic. No overflow errors are possible. + +proc `*%`*(x, y: IntMax32): IntMax32 {.magic: "MulU", noSideEffect.} +proc `*%`*(x, y: int64): int64 {.magic: "MulU", noSideEffect.} + ## Treats `x` and `y` as unsigned and multiplies them. + ## + ## The result is truncated to fit into the result. + ## This implements modulo arithmetic. No overflow errors are possible. + +proc `/%`*(x, y: IntMax32): IntMax32 {.magic: "DivU", noSideEffect.} +proc `/%`*(x, y: int64): int64 {.magic: "DivU", noSideEffect.} + ## Treats `x` and `y` as unsigned and divides them. + ## + ## The result is truncated to fit into the result. + ## This implements modulo arithmetic. No overflow errors are possible. + +proc `%%`*(x, y: IntMax32): IntMax32 {.magic: "ModU", noSideEffect.} +proc `%%`*(x, y: int64): int64 {.magic: "ModU", noSideEffect.} + ## Treats `x` and `y` as unsigned and compute the modulo of `x` and `y`. + ## + ## The result is truncated to fit into the result. + ## This implements modulo arithmetic. No overflow errors are possible. + + +# unsigned integer operations: +proc `not`*(x: uint): uint {.magic: "BitnotI", noSideEffect.} + ## Computes the `bitwise complement` of the integer `x`. +proc `not`*(x: uint8): uint8 {.magic: "BitnotI", noSideEffect.} +proc `not`*(x: uint16): uint16 {.magic: "BitnotI", noSideEffect.} +proc `not`*(x: uint32): uint32 {.magic: "BitnotI", noSideEffect.} +proc `not`*(x: uint64): uint64 {.magic: "BitnotI", noSideEffect.} + +proc `shr`*(x: uint, y: SomeInteger): uint {.magic: "ShrI", noSideEffect.} + ## Computes the `shift right` operation of `x` and `y`. +proc `shr`*(x: uint8, y: SomeInteger): uint8 {.magic: "ShrI", noSideEffect.} +proc `shr`*(x: uint16, y: SomeInteger): uint16 {.magic: "ShrI", noSideEffect.} +proc `shr`*(x: uint32, y: SomeInteger): uint32 {.magic: "ShrI", noSideEffect.} +proc `shr`*(x: uint64, y: SomeInteger): uint64 {.magic: "ShrI", noSideEffect.} + +proc `shl`*(x: uint, y: SomeInteger): uint {.magic: "ShlI", noSideEffect.} + ## Computes the `shift left` operation of `x` and `y`. +proc `shl`*(x: uint8, y: SomeInteger): uint8 {.magic: "ShlI", noSideEffect.} +proc `shl`*(x: uint16, y: SomeInteger): uint16 {.magic: "ShlI", noSideEffect.} +proc `shl`*(x: uint32, y: SomeInteger): uint32 {.magic: "ShlI", noSideEffect.} +proc `shl`*(x: uint64, y: SomeInteger): uint64 {.magic: "ShlI", noSideEffect.} + +proc `and`*(x, y: uint): uint {.magic: "BitandI", noSideEffect.} + ## Computes the `bitwise and` of numbers `x` and `y`. +proc `and`*(x, y: uint8): uint8 {.magic: "BitandI", noSideEffect.} +proc `and`*(x, y: uint16): uint16 {.magic: "BitandI", noSideEffect.} +proc `and`*(x, y: uint32): uint32 {.magic: "BitandI", noSideEffect.} +proc `and`*(x, y: uint64): uint64 {.magic: "BitandI", noSideEffect.} + +proc `or`*(x, y: uint): uint {.magic: "BitorI", noSideEffect.} + ## Computes the `bitwise or` of numbers `x` and `y`. +proc `or`*(x, y: uint8): uint8 {.magic: "BitorI", noSideEffect.} +proc `or`*(x, y: uint16): uint16 {.magic: "BitorI", noSideEffect.} +proc `or`*(x, y: uint32): uint32 {.magic: "BitorI", noSideEffect.} +proc `or`*(x, y: uint64): uint64 {.magic: "BitorI", noSideEffect.} + +proc `xor`*(x, y: uint): uint {.magic: "BitxorI", noSideEffect.} + ## Computes the `bitwise xor` of numbers `x` and `y`. +proc `xor`*(x, y: uint8): uint8 {.magic: "BitxorI", noSideEffect.} +proc `xor`*(x, y: uint16): uint16 {.magic: "BitxorI", noSideEffect.} +proc `xor`*(x, y: uint32): uint32 {.magic: "BitxorI", noSideEffect.} +proc `xor`*(x, y: uint64): uint64 {.magic: "BitxorI", noSideEffect.} + +proc `+`*(x, y: uint): uint {.magic: "AddU", noSideEffect.} + ## Binary `+` operator for unsigned integers. +proc `+`*(x, y: uint8): uint8 {.magic: "AddU", noSideEffect.} +proc `+`*(x, y: uint16): uint16 {.magic: "AddU", noSideEffect.} +proc `+`*(x, y: uint32): uint32 {.magic: "AddU", noSideEffect.} +proc `+`*(x, y: uint64): uint64 {.magic: "AddU", noSideEffect.} + +proc `-`*(x, y: uint): uint {.magic: "SubU", noSideEffect.} + ## Binary `-` operator for unsigned integers. +proc `-`*(x, y: uint8): uint8 {.magic: "SubU", noSideEffect.} +proc `-`*(x, y: uint16): uint16 {.magic: "SubU", noSideEffect.} +proc `-`*(x, y: uint32): uint32 {.magic: "SubU", noSideEffect.} +proc `-`*(x, y: uint64): uint64 {.magic: "SubU", noSideEffect.} + +proc `*`*(x, y: uint): uint {.magic: "MulU", noSideEffect.} + ## Binary `*` operator for unsigned integers. +proc `*`*(x, y: uint8): uint8 {.magic: "MulU", noSideEffect.} +proc `*`*(x, y: uint16): uint16 {.magic: "MulU", noSideEffect.} +proc `*`*(x, y: uint32): uint32 {.magic: "MulU", noSideEffect.} +proc `*`*(x, y: uint64): uint64 {.magic: "MulU", noSideEffect.} + +proc `div`*(x, y: uint): uint {.magic: "DivU", noSideEffect.} + ## Computes the integer division for unsigned integers. + ## This is roughly the same as ``trunc(x/y)``. +proc `div`*(x, y: uint8): uint8 {.magic: "DivU", noSideEffect.} +proc `div`*(x, y: uint16): uint16 {.magic: "DivU", noSideEffect.} +proc `div`*(x, y: uint32): uint32 {.magic: "DivU", noSideEffect.} +proc `div`*(x, y: uint64): uint64 {.magic: "DivU", noSideEffect.} + +proc `mod`*(x, y: uint): uint {.magic: "ModU", noSideEffect.} + ## Computes the integer modulo operation (remainder) for unsigned integers. + ## This is the same as ``x - (x div y) * y``. +proc `mod`*(x, y: uint8): uint8 {.magic: "ModU", noSideEffect.} +proc `mod`*(x, y: uint16): uint16 {.magic: "ModU", noSideEffect.} +proc `mod`*(x, y: uint32): uint32 {.magic: "ModU", noSideEffect.} +proc `mod`*(x, y: uint64): uint64 {.magic: "ModU", noSideEffect.} + + + + +proc `+=`*[T: SomeInteger](x: var T, y: T) {. + magic: "Inc", noSideEffect.} + ## Increments an integer. + +proc `+=`*[T: enum|bool](x: var T, y: T) {. + magic: "Inc", noSideEffect, deprecated: "use `inc` instead".} + ## **Deprecated since v0.20**: use `inc` instead. + +proc `-=`*[T: SomeInteger](x: var T, y: T) {. + magic: "Dec", noSideEffect.} + ## Decrements an integer. + +proc `-=`*[T: enum|bool](x: var T, y: T) {. + magic: "Dec", noSideEffect, deprecated: "0.20.0, use `dec` instead".} + ## **Deprecated since v0.20**: use `dec` instead. + +proc `*=`*[T: SomeInteger](x: var T, y: T) {. + inline, noSideEffect.} = + ## Binary `*=` operator for integers. + x = x * y diff --git a/lib/system/basic_types.nim b/lib/system/basic_types.nim new file mode 100644 index 000000000..39ad0a76c --- /dev/null +++ b/lib/system/basic_types.nim @@ -0,0 +1,67 @@ +type + int* {.magic: Int.} ## Default integer type; bitwidth depends on + ## architecture, but is always the same as a pointer. + int8* {.magic: Int8.} ## Signed 8 bit integer type. + int16* {.magic: Int16.} ## Signed 16 bit integer type. + int32* {.magic: Int32.} ## Signed 32 bit integer type. + int64* {.magic: Int64.} ## Signed 64 bit integer type. + uint* {.magic: UInt.} ## Unsigned default integer type. + uint8* {.magic: UInt8.} ## Unsigned 8 bit integer type. + uint16* {.magic: UInt16.} ## Unsigned 16 bit integer type. + uint32* {.magic: UInt32.} ## Unsigned 32 bit integer type. + uint64* {.magic: UInt64.} ## Unsigned 64 bit integer type. + +type # we need to start a new type section here, so that ``0`` can have a type + bool* {.magic: Bool.} = enum ## Built-in boolean type. + false = 0, true = 1 + +const + on* = true ## Alias for ``true``. + off* = false ## Alias for ``false``. + +type + Ordinal*[T] {.magic: Ordinal.} ## Generic ordinal type. Includes integer, + ## bool, character, and enumeration types + ## as well as their subtypes. + + SomeSignedInt* = int|int8|int16|int32|int64 + ## Type class matching all signed integer types. + + SomeUnsignedInt* = uint|uint8|uint16|uint32|uint64 + ## Type class matching all unsigned integer types. + + SomeInteger* = SomeSignedInt|SomeUnsignedInt + ## Type class matching all integer types. + + SomeOrdinal* = int|int8|int16|int32|int64|bool|enum|uint|uint8|uint16|uint32|uint64 + ## Type class matching all ordinal types; however this includes enums with + ## holes. + + BiggestInt* = int64 + ## is an alias for the biggest signed integer type the Nim compiler + ## supports. Currently this is ``int64``, but it is platform-dependent + ## in general. + + +{.push warning[GcMem]: off, warning[Uninit]: off.} +{.push hints: off.} + +proc `not`*(x: bool): bool {.magic: "Not", noSideEffect.} + ## Boolean not; returns true if ``x == false``. + +proc `and`*(x, y: bool): bool {.magic: "And", noSideEffect.} + ## Boolean ``and``; returns true if ``x == y == true`` (if both arguments + ## are true). + ## + ## Evaluation is lazy: if ``x`` is false, ``y`` will not even be evaluated. +proc `or`*(x, y: bool): bool {.magic: "Or", noSideEffect.} + ## Boolean ``or``; returns true if ``not (not x and not y)`` (if any of + ## the arguments is true). + ## + ## Evaluation is lazy: if ``x`` is true, ``y`` will not even be evaluated. +proc `xor`*(x, y: bool): bool {.magic: "Xor", noSideEffect.} + ## Boolean `exclusive or`; returns true if ``x != y`` (if either argument + ## is true while the other is false). + +{.pop.} +{.pop.} diff --git a/lib/system/comparisons.nim b/lib/system/comparisons.nim new file mode 100644 index 000000000..ab140c938 --- /dev/null +++ b/lib/system/comparisons.nim @@ -0,0 +1,311 @@ +# comparison operators: +proc `==`*[Enum: enum](x, y: Enum): bool {.magic: "EqEnum", noSideEffect.} + ## Checks whether values within the *same enum* have the same underlying value. + ## + ## .. code-block:: Nim + ## type + ## Enum1 = enum + ## Field1 = 3, Field2 + ## Enum2 = enum + ## Place1, Place2 = 3 + ## var + ## e1 = Field1 + ## e2 = Enum1(Place2) + ## echo (e1 == e2) # true + ## echo (e1 == Place2) # raises error +proc `==`*(x, y: pointer): bool {.magic: "EqRef", noSideEffect.} + ## .. code-block:: Nim + ## var # this is a wildly dangerous example + ## a = cast[pointer](0) + ## b = cast[pointer](nil) + ## echo (a == b) # true due to the special meaning of `nil`/0 as a pointer +proc `==`*(x, y: string): bool {.magic: "EqStr", noSideEffect.} + ## Checks for equality between two `string` variables. + +proc `==`*(x, y: char): bool {.magic: "EqCh", noSideEffect.} + ## Checks for equality between two `char` variables. +proc `==`*(x, y: bool): bool {.magic: "EqB", noSideEffect.} + ## Checks for equality between two `bool` variables. +proc `==`*[T](x, y: set[T]): bool {.magic: "EqSet", noSideEffect.} + ## Checks for equality between two variables of type `set`. + ## + ## .. code-block:: Nim + ## var a = {1, 2, 2, 3} # duplication in sets is ignored + ## var b = {1, 2, 3} + ## echo (a == b) # true +proc `==`*[T](x, y: ref T): bool {.magic: "EqRef", noSideEffect.} + ## Checks that two `ref` variables refer to the same item. +proc `==`*[T](x, y: ptr T): bool {.magic: "EqRef", noSideEffect.} + ## Checks that two `ptr` variables refer to the same item. +proc `==`*[T: proc](x, y: T): bool {.magic: "EqProc", noSideEffect.} + ## Checks that two `proc` variables refer to the same procedure. + +proc `<=`*[Enum: enum](x, y: Enum): bool {.magic: "LeEnum", noSideEffect.} +proc `<=`*(x, y: string): bool {.magic: "LeStr", noSideEffect.} + ## Compares two strings and returns true if `x` is lexicographically + ## before `y` (uppercase letters come before lowercase letters). + ## + ## .. code-block:: Nim + ## let + ## a = "abc" + ## b = "abd" + ## c = "ZZZ" + ## assert a <= b + ## assert a <= a + ## assert (a <= c) == false +proc `<=`*(x, y: char): bool {.magic: "LeCh", noSideEffect.} + ## Compares two chars and returns true if `x` is lexicographically + ## before `y` (uppercase letters come before lowercase letters). + ## + ## .. code-block:: Nim + ## let + ## a = 'a' + ## b = 'b' + ## c = 'Z' + ## assert a <= b + ## assert a <= a + ## assert (a <= c) == false +proc `<=`*[T](x, y: set[T]): bool {.magic: "LeSet", noSideEffect.} + ## Returns true if `x` is a subset of `y`. + ## + ## A subset `x` has all of its members in `y` and `y` doesn't necessarily + ## have more members than `x`. That is, `x` can be equal to `y`. + ## + ## .. code-block:: Nim + ## let + ## a = {3, 5} + ## b = {1, 3, 5, 7} + ## c = {2} + ## assert a <= b + ## assert a <= a + ## assert (a <= c) == false +proc `<=`*(x, y: bool): bool {.magic: "LeB", noSideEffect.} +proc `<=`*[T](x, y: ref T): bool {.magic: "LePtr", noSideEffect.} +proc `<=`*(x, y: pointer): bool {.magic: "LePtr", noSideEffect.} + +proc `<`*[Enum: enum](x, y: Enum): bool {.magic: "LtEnum", noSideEffect.} +proc `<`*(x, y: string): bool {.magic: "LtStr", noSideEffect.} + ## Compares two strings and returns true if `x` is lexicographically + ## before `y` (uppercase letters come before lowercase letters). + ## + ## .. code-block:: Nim + ## let + ## a = "abc" + ## b = "abd" + ## c = "ZZZ" + ## assert a < b + ## assert (a < a) == false + ## assert (a < c) == false +proc `<`*(x, y: char): bool {.magic: "LtCh", noSideEffect.} + ## Compares two chars and returns true if `x` is lexicographically + ## before `y` (uppercase letters come before lowercase letters). + ## + ## .. code-block:: Nim + ## let + ## a = 'a' + ## b = 'b' + ## c = 'Z' + ## assert a < b + ## assert (a < a) == false + ## assert (a < c) == false +proc `<`*[T](x, y: set[T]): bool {.magic: "LtSet", noSideEffect.} + ## Returns true if `x` is a strict or proper subset of `y`. + ## + ## A strict or proper subset `x` has all of its members in `y` but `y` has + ## more elements than `y`. + ## + ## .. code-block:: Nim + ## let + ## a = {3, 5} + ## b = {1, 3, 5, 7} + ## c = {2} + ## assert a < b + ## assert (a < a) == false + ## assert (a < c) == false +proc `<`*(x, y: bool): bool {.magic: "LtB", noSideEffect.} +proc `<`*[T](x, y: ref T): bool {.magic: "LtPtr", noSideEffect.} +proc `<`*[T](x, y: ptr T): bool {.magic: "LtPtr", noSideEffect.} +proc `<`*(x, y: pointer): bool {.magic: "LtPtr", noSideEffect.} + +template `!=`*(x, y: untyped): untyped = + ## Unequals operator. This is a shorthand for ``not (x == y)``. + not (x == y) + +template `>=`*(x, y: untyped): untyped = + ## "is greater or equals" operator. This is the same as ``y <= x``. + y <= x + +template `>`*(x, y: untyped): untyped = + ## "is greater" operator. This is the same as ``y < x``. + y < x + + +proc `==`*(x, y: int): bool {.magic: "EqI", noSideEffect.} + ## Compares two integers for equality. +proc `==`*(x, y: int8): bool {.magic: "EqI", noSideEffect.} +proc `==`*(x, y: int16): bool {.magic: "EqI", noSideEffect.} +proc `==`*(x, y: int32): bool {.magic: "EqI", noSideEffect.} +proc `==`*(x, y: int64): bool {.magic: "EqI", noSideEffect.} + +proc `<=`*(x, y: int): bool {.magic: "LeI", noSideEffect.} + ## Returns true if `x` is less than or equal to `y`. +proc `<=`*(x, y: int8): bool {.magic: "LeI", noSideEffect.} +proc `<=`*(x, y: int16): bool {.magic: "LeI", noSideEffect.} +proc `<=`*(x, y: int32): bool {.magic: "LeI", noSideEffect.} +proc `<=`*(x, y: int64): bool {.magic: "LeI", noSideEffect.} + +proc `<`*(x, y: int): bool {.magic: "LtI", noSideEffect.} + ## Returns true if `x` is less than `y`. +proc `<`*(x, y: int8): bool {.magic: "LtI", noSideEffect.} +proc `<`*(x, y: int16): bool {.magic: "LtI", noSideEffect.} +proc `<`*(x, y: int32): bool {.magic: "LtI", noSideEffect.} +proc `<`*(x, y: int64): bool {.magic: "LtI", noSideEffect.} + + +proc `<=%`*(x, y: IntMax32): bool {.magic: "LeU", noSideEffect.} +proc `<=%`*(x, y: int64): bool {.magic: "LeU64", noSideEffect.} + ## Treats `x` and `y` as unsigned and compares them. + ## Returns true if ``unsigned(x) <= unsigned(y)``. + +proc `<%`*(x, y: IntMax32): bool {.magic: "LtU", noSideEffect.} +proc `<%`*(x, y: int64): bool {.magic: "LtU64", noSideEffect.} + ## Treats `x` and `y` as unsigned and compares them. + ## Returns true if ``unsigned(x) < unsigned(y)``. + +template `>=%`*(x, y: untyped): untyped = y <=% x + ## Treats `x` and `y` as unsigned and compares them. + ## Returns true if ``unsigned(x) >= unsigned(y)``. + +template `>%`*(x, y: untyped): untyped = y <% x + ## Treats `x` and `y` as unsigned and compares them. + ## Returns true if ``unsigned(x) > unsigned(y)``. + + +proc `==`*(x, y: uint): bool {.magic: "EqI", noSideEffect.} + ## Compares two unsigned integers for equality. +proc `==`*(x, y: uint8): bool {.magic: "EqI", noSideEffect.} +proc `==`*(x, y: uint16): bool {.magic: "EqI", noSideEffect.} +proc `==`*(x, y: uint32): bool {.magic: "EqI", noSideEffect.} +proc `==`*(x, y: uint64): bool {.magic: "EqI", noSideEffect.} + + +proc `<=`*(x, y: uint): bool {.magic: "LeU", noSideEffect.} + ## Returns true if ``x <= y``. +proc `<=`*(x, y: uint8): bool {.magic: "LeU", noSideEffect.} +proc `<=`*(x, y: uint16): bool {.magic: "LeU", noSideEffect.} +proc `<=`*(x, y: uint32): bool {.magic: "LeU", noSideEffect.} +proc `<=`*(x, y: uint64): bool {.magic: "LeU", noSideEffect.} + +proc `<`*(x, y: uint): bool {.magic: "LtU", noSideEffect.} + ## Returns true if ``unsigned(x) < unsigned(y)``. +proc `<`*(x, y: uint8): bool {.magic: "LtU", noSideEffect.} +proc `<`*(x, y: uint16): bool {.magic: "LtU", noSideEffect.} +proc `<`*(x, y: uint32): bool {.magic: "LtU", noSideEffect.} +proc `<`*(x, y: uint64): bool {.magic: "LtU", noSideEffect.} + + +{.push stackTrace: off.} + +proc min*(x, y: int): int {.magic: "MinI", noSideEffect.} = + if x <= y: x else: y +proc min*(x, y: int8): int8 {.magic: "MinI", noSideEffect.} = + if x <= y: x else: y +proc min*(x, y: int16): int16 {.magic: "MinI", noSideEffect.} = + if x <= y: x else: y +proc min*(x, y: int32): int32 {.magic: "MinI", noSideEffect.} = + if x <= y: x else: y +proc min*(x, y: int64): int64 {.magic: "MinI", noSideEffect.} = + ## The minimum value of two integers. + if x <= y: x else: y + +proc max*(x, y: int): int {.magic: "MaxI", noSideEffect.} = + if y <= x: x else: y +proc max*(x, y: int8): int8 {.magic: "MaxI", noSideEffect.} = + if y <= x: x else: y +proc max*(x, y: int16): int16 {.magic: "MaxI", noSideEffect.} = + if y <= x: x else: y +proc max*(x, y: int32): int32 {.magic: "MaxI", noSideEffect.} = + if y <= x: x else: y +proc max*(x, y: int64): int64 {.magic: "MaxI", noSideEffect.} = + ## The maximum value of two integers. + if y <= x: x else: y + + +proc min*[T](x: openArray[T]): T = + ## The minimum value of `x`. ``T`` needs to have a ``<`` operator. + result = x[0] + for i in 1..high(x): + if x[i] < result: result = x[i] + +proc max*[T](x: openArray[T]): T = + ## The maximum value of `x`. ``T`` needs to have a ``<`` operator. + result = x[0] + for i in 1..high(x): + if result < x[i]: result = x[i] + +{.pop.} # stackTrace: off + + +proc clamp*[T](x, a, b: T): T = + ## Limits the value ``x`` within the interval [a, b]. + ## + ## .. code-block:: Nim + ## assert((1.4).clamp(0.0, 1.0) == 1.0) + ## assert((0.5).clamp(0.0, 1.0) == 0.5) + if x < a: return a + if x > b: return b + return x + + +proc `==`*[I, T](x, y: array[I, T]): bool = + for f in low(x)..high(x): + if x[f] != y[f]: + return + result = true + +proc `==`*[T](x, y: openArray[T]): bool = + if x.len != y.len: + return false + for f in low(x)..high(x): + if x[f] != y[f]: + return false + result = true + + +proc `==`*[T](x, y: seq[T]): bool {.noSideEffect.} = + ## Generic equals operator for sequences: relies on a equals operator for + ## the element type `T`. + when nimvm: + when not defined(nimNoNil): + if x.isNil and y.isNil: + return true + else: + if x.len == 0 and y.len == 0: + return true + else: + when not defined(JS): + proc seqToPtr[T](x: seq[T]): pointer {.inline, noSideEffect.} = + when defined(nimSeqsV2): + result = cast[NimSeqV2[T]](x).p + else: + result = cast[pointer](x) + + if seqToPtr(x) == seqToPtr(y): + return true + else: + var sameObject = false + asm """`sameObject` = `x` === `y`""" + if sameObject: return true + + when not defined(nimNoNil): + if x.isNil or y.isNil: + return false + + if x.len != y.len: + return false + + for i in 0..x.len-1: + if x[i] != y[i]: + return false + + return true diff --git a/lib/system/exceptions.nim b/lib/system/exceptions.nim new file mode 100644 index 000000000..f575f9b9f --- /dev/null +++ b/lib/system/exceptions.nim @@ -0,0 +1,137 @@ +type + RootEffect* {.compilerproc.} = object of RootObj ## \ + ## Base effect class. + ## + ## Each effect should inherit from `RootEffect` unless you know what + ## you're doing. + TimeEffect* = object of RootEffect ## Time effect. + IOEffect* = object of RootEffect ## IO effect. + ReadIOEffect* = object of IOEffect ## Effect describing a read IO operation. + WriteIOEffect* = object of IOEffect ## Effect describing a write IO operation. + ExecIOEffect* = object of IOEffect ## Effect describing an executing IO operation. + + StackTraceEntry* = object ## In debug mode exceptions store the stack trace that led + ## to them. A `StackTraceEntry` is a single entry of the + ## stack trace. + procname*: cstring ## Name of the proc that is currently executing. + line*: int ## Line number of the proc that is currently executing. + filename*: cstring ## Filename of the proc that is currently executing. + + Exception* {.compilerproc, magic: "Exception".} = object of RootObj ## \ + ## Base exception class. + ## + ## Each exception has to inherit from `Exception`. See the full `exception + ## hierarchy <manual.html#exception-handling-exception-hierarchy>`_. + parent*: ref Exception ## Parent exception (can be used as a stack). + name*: cstring ## The exception's name is its Nim identifier. + ## This field is filled automatically in the + ## ``raise`` statement. + msg* {.exportc: "message".}: string ## The exception's message. Not + ## providing an exception message + ## is bad style. + when defined(js): + trace: string + else: + trace: seq[StackTraceEntry] + when defined(nimBoostrapCsources0_19_0): + # see #10315, bootstrap with `nim cpp` from csources gave error: + # error: no member named 'raise_id' in 'Exception' + raise_id: uint # set when exception is raised + else: + raiseId: uint # set when exception is raised + up: ref Exception # used for stacking exceptions. Not exported! + + Defect* = object of Exception ## \ + ## Abstract base class for all exceptions that Nim's runtime raises + ## but that are strictly uncatchable as they can also be mapped to + ## a ``quit`` / ``trap`` / ``exit`` operation. + + CatchableError* = object of Exception ## \ + ## Abstract class for all exceptions that are catchable. + IOError* = object of CatchableError ## \ + ## Raised if an IO error occurred. + EOFError* = object of IOError ## \ + ## Raised if an IO "end of file" error occurred. + OSError* = object of CatchableError ## \ + ## Raised if an operating system service failed. + errorCode*: int32 ## OS-defined error code describing this error. + LibraryError* = object of OSError ## \ + ## Raised if a dynamic library could not be loaded. + ResourceExhaustedError* = object of CatchableError ## \ + ## Raised if a resource request could not be fulfilled. + ArithmeticError* = object of Defect ## \ + ## Raised if any kind of arithmetic error occurred. + DivByZeroError* = object of ArithmeticError ## \ + ## Raised for runtime integer divide-by-zero errors. + + OverflowError* = object of ArithmeticError ## \ + ## Raised for runtime integer overflows. + ## + ## This happens for calculations whose results are too large to fit in the + ## provided bits. + AccessViolationError* = object of Defect ## \ + ## Raised for invalid memory access errors + AssertionError* = object of Defect ## \ + ## Raised when assertion is proved wrong. + ## + ## Usually the result of using the `assert() template + ## <assertions.html#assert.t,untyped,string>`_. + ValueError* = object of CatchableError ## \ + ## Raised for string and object conversion errors. + KeyError* = object of ValueError ## \ + ## Raised if a key cannot be found in a table. + ## + ## Mostly used by the `tables <tables.html>`_ module, it can also be raised + ## by other collection modules like `sets <sets.html>`_ or `strtabs + ## <strtabs.html>`_. + OutOfMemError* = object of Defect ## \ + ## Raised for unsuccessful attempts to allocate memory. + IndexError* = object of Defect ## \ + ## Raised if an array index is out of bounds. + + FieldError* = object of Defect ## \ + ## Raised if a record field is not accessible because its discriminant's + ## value does not fit. + RangeError* = object of Defect ## \ + ## Raised if a range check error occurred. + StackOverflowError* = object of Defect ## \ + ## Raised if the hardware stack used for subroutine calls overflowed. + ReraiseError* = object of Defect ## \ + ## Raised if there is no exception to reraise. + ObjectAssignmentError* = object of Defect ## \ + ## Raised if an object gets assigned to its parent's object. + ObjectConversionError* = object of Defect ## \ + ## Raised if an object is converted to an incompatible object type. + ## You can use ``of`` operator to check if conversion will succeed. + FloatingPointError* = object of Defect ## \ + ## Base class for floating point exceptions. + FloatInvalidOpError* = object of FloatingPointError ## \ + ## Raised by invalid operations according to IEEE. + ## + ## Raised by ``0.0/0.0``, for example. + FloatDivByZeroError* = object of FloatingPointError ## \ + ## Raised by division by zero. + ## + ## Divisor is zero and dividend is a finite nonzero number. + FloatOverflowError* = object of FloatingPointError ## \ + ## Raised for overflows. + ## + ## The operation produced a result that exceeds the range of the exponent. + FloatUnderflowError* = object of FloatingPointError ## \ + ## Raised for underflows. + ## + ## The operation produced a result that is too small to be represented as a + ## normal number. + FloatInexactError* = object of FloatingPointError ## \ + ## Raised for inexact results. + ## + ## The operation produced a result that cannot be represented with infinite + ## precision -- for example: ``2.0 / 3.0, log(1.1)`` + ## + ## **Note**: Nim currently does not detect these! + DeadThreadError* = object of Defect ## \ + ## Raised if it is attempted to send a message to a dead thread. + NilAccessError* = object of Defect ## \ + ## Raised on dereferences of ``nil`` pointers. + ## + ## This is only raised if the `segfaults module <segfaults.html>`_ was imported! diff --git a/lib/system/gc_interface.nim b/lib/system/gc_interface.nim new file mode 100644 index 000000000..5f27b432d --- /dev/null +++ b/lib/system/gc_interface.nim @@ -0,0 +1,100 @@ +# ----------------- GC interface --------------------------------------------- +const + usesDestructors = defined(gcDestructors) or defined(gcHooks) + +when not usesDestructors: + {.pragma: nodestroy.} + +when hasAlloc: + type + GC_Strategy* = enum ## The strategy the GC should use for the application. + gcThroughput, ## optimize for throughput + gcResponsiveness, ## optimize for responsiveness (default) + gcOptimizeTime, ## optimize for speed + gcOptimizeSpace ## optimize for memory footprint + +when hasAlloc and not defined(JS) and not usesDestructors: + proc GC_disable*() {.rtl, inl, benign.} + ## Disables the GC. If called `n` times, `n` calls to `GC_enable` + ## are needed to reactivate the GC. + ## + ## Note that in most circumstances one should only disable + ## the mark and sweep phase with + ## `GC_disableMarkAndSweep <#GC_disableMarkAndSweep>`_. + + proc GC_enable*() {.rtl, inl, benign.} + ## Enables the GC again. + + proc GC_fullCollect*() {.rtl, benign.} + ## Forces a full garbage collection pass. + ## Ordinary code does not need to call this (and should not). + + proc GC_enableMarkAndSweep*() {.rtl, benign.} + proc GC_disableMarkAndSweep*() {.rtl, benign.} + ## The current implementation uses a reference counting garbage collector + ## with a seldomly run mark and sweep phase to free cycles. The mark and + ## sweep phase may take a long time and is not needed if the application + ## does not create cycles. Thus the mark and sweep phase can be deactivated + ## and activated separately from the rest of the GC. + + proc GC_getStatistics*(): string {.rtl, benign.} + ## Returns an informative string about the GC's activity. This may be useful + ## for tweaking. + + proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.} + proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.} + proc GC_ref*(x: string) {.magic: "GCref", benign.} + ## Marks the object `x` as referenced, so that it will not be freed until + ## it is unmarked via `GC_unref`. + ## If called n-times for the same object `x`, + ## n calls to `GC_unref` are needed to unmark `x`. + + proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.} + proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.} + proc GC_unref*(x: string) {.magic: "GCunref", benign.} + ## See the documentation of `GC_ref <#GC_ref,string>`_. + + proc nimGC_setStackBottom*(theStackBottom: pointer) {.compilerRtl, noinline, benign.} + ## Expands operating GC stack range to `theStackBottom`. Does nothing + ## if current stack bottom is already lower than `theStackBottom`. + +when hasAlloc and defined(JS): + template GC_disable* = + {.warning: "GC_disable is a no-op in JavaScript".} + + template GC_enable* = + {.warning: "GC_enable is a no-op in JavaScript".} + + template GC_fullCollect* = + {.warning: "GC_fullCollect is a no-op in JavaScript".} + + template GC_setStrategy* = + {.warning: "GC_setStrategy is a no-op in JavaScript".} + + template GC_enableMarkAndSweep* = + {.warning: "GC_enableMarkAndSweep is a no-op in JavaScript".} + + template GC_disableMarkAndSweep* = + {.warning: "GC_disableMarkAndSweep is a no-op in JavaScript".} + + template GC_ref*[T](x: ref T) = + {.warning: "GC_ref is a no-op in JavaScript".} + + template GC_ref*[T](x: seq[T]) = + {.warning: "GC_ref is a no-op in JavaScript".} + + template GC_ref*(x: string) = + {.warning: "GC_ref is a no-op in JavaScript".} + + template GC_unref*[T](x: ref T) = + {.warning: "GC_unref is a no-op in JavaScript".} + + template GC_unref*[T](x: seq[T]) = + {.warning: "GC_unref is a no-op in JavaScript".} + + template GC_unref*(x: string) = + {.warning: "GC_unref is a no-op in JavaScript".} + + template GC_getStatistics*(): string = + {.warning: "GC_getStatistics is a no-op in JavaScript".} + "" diff --git a/lib/system/iterators_1.nim b/lib/system/iterators_1.nim new file mode 100644 index 000000000..07c731c3b --- /dev/null +++ b/lib/system/iterators_1.nim @@ -0,0 +1,214 @@ +when sizeof(int) <= 2: + type IntLikeForCount = int|int8|int16|char|bool|uint8|enum +else: + type IntLikeForCount = int|int8|int16|int32|char|bool|uint8|uint16|enum + +iterator countdown*[T](a, b: T, step: Positive = 1): T {.inline.} = + ## Counts from ordinal value `a` down to `b` (inclusive) with the given + ## step count. + ## + ## `T` may be any ordinal type, `step` may only be positive. + ## + ## **Note**: This fails to count to ``low(int)`` if T = int for + ## efficiency reasons. + ## + ## .. code-block:: Nim + ## for i in countdown(7, 3): + ## echo i # => 7; 6; 5; 4; 3 + ## + ## for i in countdown(9, 2, 3): + ## echo i # => 9; 6; 3 + when T is (uint|uint64): + var res = a + while res >= b: + yield res + if res == b: break + dec(res, step) + elif T is IntLikeForCount: + var res = int(a) + while res >= int(b): + yield T(res) + dec(res, step) + else: + var res = a + while res >= b: + yield res + dec(res, step) + +when defined(nimNewRoof): + iterator countup*[T](a, b: T, step: Positive = 1): T {.inline.} = + ## Counts from ordinal value `a` to `b` (inclusive) with the given + ## step count. + ## + ## `T` may be any ordinal type, `step` may only be positive. + ## + ## **Note**: This fails to count to ``high(int)`` if T = int for + ## efficiency reasons. + ## + ## .. code-block:: Nim + ## for i in countup(3, 7): + ## echo i # => 3; 4; 5; 6; 7 + ## + ## for i in countup(2, 9, 3): + ## echo i # => 2; 5; 8 + mixin inc + when T is IntLikeForCount: + var res = int(a) + while res <= int(b): + yield T(res) + inc(res, step) + else: + var res = a + while res <= b: + yield res + inc(res, step) + + iterator `..`*[T](a, b: T): T {.inline.} = + ## An alias for `countup(a, b, 1)`. + ## + ## See also: + ## * [..<](#..<.i,T,T) + ## + ## .. code-block:: Nim + ## for i in 3 .. 7: + ## echo i # => 3; 4; 5; 6; 7 + mixin inc + when T is IntLikeForCount: + var res = int(a) + while res <= int(b): + yield T(res) + inc(res) + else: + var res = a + while res <= b: + yield res + inc(res) + + template dotdotImpl(t) {.dirty.} = + iterator `..`*(a, b: t): t {.inline.} = + ## A type specialized version of ``..`` for convenience so that + ## mixing integer types works better. + ## + ## See also: + ## * [..<](#..<.i,T,T) + var res = a + while res <= b: + yield res + inc(res) + + dotdotImpl(int64) + dotdotImpl(int32) + dotdotImpl(uint64) + dotdotImpl(uint32) + + iterator `..<`*[T](a, b: T): T {.inline.} = + mixin inc + var i = a + while i < b: + yield i + inc i + + template dotdotLessImpl(t) {.dirty.} = + iterator `..<`*(a, b: t): t {.inline.} = + ## A type specialized version of ``..<`` for convenience so that + ## mixing integer types works better. + var res = a + while res < b: + yield res + inc(res) + + dotdotLessImpl(int64) + dotdotLessImpl(int32) + dotdotLessImpl(uint64) + dotdotLessImpl(uint32) + +else: # not defined(nimNewRoof) + iterator countup*[S, T](a: S, b: T, step = 1): T {.inline.} = + ## Counts from ordinal value `a` up to `b` (inclusive) with the given + ## step count. + ## + ## `S`, `T` may be any ordinal type, `step` may only be positive. + ## + ## **Note**: This fails to count to ``high(int)`` if T = int for + ## efficiency reasons. + ## + ## .. code-block:: Nim + ## for i in countup(3, 7): + ## echo i # => 3; 4; 5; 6; 7 + ## + ## for i in countup(2, 9, 3): + ## echo i # => 2; 5; 8 + when T is IntLikeForCount: + var res = int(a) + while res <= int(b): + yield T(res) + inc(res, step) + else: + var res = T(a) + while res <= b: + yield res + inc(res, step) + + iterator `..`*[S, T](a: S, b: T): T {.inline.} = + ## An alias for `countup(a, b, 1)`. + ## + ## See also: + ## * [..<](#..<.i,T,T) + ## + ## .. code-block:: Nim + ## for i in 3 .. 7: + ## echo i # => 3; 4; 5; 6; 7 + mixin inc + when T is IntLikeForCount: + var res = int(a) + while res <= int(b): + yield T(res) + inc(res) + else: + var res = T(a) + while res <= b: + yield res + inc(res) + + iterator `..<`*[S, T](a: S, b: T): T {.inline.} = + mixin inc + var i = T(a) + while i < b: + yield i + inc i + + +iterator `||`*[S, T](a: S, b: T, annotation: static string = "parallel for"): T {. + inline, magic: "OmpParFor", sideEffect.} = + ## OpenMP parallel loop iterator. Same as `..` but the loop may run in parallel. + ## + ## `annotation` is an additional annotation for the code generator to use. + ## The default annotation is `parallel for`. + ## Please refer to the `OpenMP Syntax Reference + ## <https://www.openmp.org/wp-content/uploads/OpenMP-4.5-1115-CPP-web.pdf>`_ + ## for further information. + ## + ## Note that the compiler maps that to + ## the ``#pragma omp parallel for`` construct of `OpenMP`:idx: and as + ## such isn't aware of the parallelism in your code! Be careful! Later + ## versions of ``||`` will get proper support by Nim's code generator + ## and GC. + discard + +iterator `||`*[S, T](a: S, b: T, step: Positive, annotation: static string = "parallel for"): T {. + inline, magic: "OmpParFor", sideEffect.} = + ## OpenMP parallel loop iterator with stepping. + ## Same as `countup` but the loop may run in parallel. + ## + ## `annotation` is an additional annotation for the code generator to use. + ## The default annotation is `parallel for`. + ## Please refer to the `OpenMP Syntax Reference + ## <https://www.openmp.org/wp-content/uploads/OpenMP-4.5-1115-CPP-web.pdf>`_ + ## for further information. + ## + ## Note that the compiler maps that to + ## the ``#pragma omp parallel for`` construct of `OpenMP`:idx: and as + ## such isn't aware of the parallelism in your code! Be careful! Later + ## versions of ``||`` will get proper support by Nim's code generator + ## and GC. + discard diff --git a/lib/system/memalloc.nim b/lib/system/memalloc.nim new file mode 100644 index 000000000..1e41123f0 --- /dev/null +++ b/lib/system/memalloc.nim @@ -0,0 +1,262 @@ +when notJSnotNims: + proc zeroMem*(p: pointer, size: Natural) {.inline, noSideEffect, + tags: [], locks: 0, raises: [].} + ## Overwrites the contents of the memory at ``p`` with the value 0. + ## + ## Exactly ``size`` bytes will be overwritten. Like any procedure + ## dealing with raw memory this is **unsafe**. + + proc copyMem*(dest, source: pointer, size: Natural) {.inline, benign, + tags: [], locks: 0, raises: [].} + ## Copies the contents from the memory at ``source`` to the memory + ## at ``dest``. + ## Exactly ``size`` bytes will be copied. The memory + ## regions may not overlap. Like any procedure dealing with raw + ## memory this is **unsafe**. + + proc moveMem*(dest, source: pointer, size: Natural) {.inline, benign, + tags: [], locks: 0, raises: [].} + ## Copies the contents from the memory at ``source`` to the memory + ## at ``dest``. + ## + ## Exactly ``size`` bytes will be copied. The memory + ## regions may overlap, ``moveMem`` handles this case appropriately + ## and is thus somewhat more safe than ``copyMem``. Like any procedure + ## dealing with raw memory this is still **unsafe**, though. + + proc equalMem*(a, b: pointer, size: Natural): bool {.inline, noSideEffect, + tags: [], locks: 0, raises: [].} + ## Compares the memory blocks ``a`` and ``b``. ``size`` bytes will + ## be compared. + ## + ## If the blocks are equal, `true` is returned, `false` + ## otherwise. Like any procedure dealing with raw memory this is + ## **unsafe**. + +when hasAlloc: + proc alloc*(size: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].} + ## Allocates a new memory block with at least ``size`` bytes. + ## + ## The block has to be freed with `realloc(block, 0) <#realloc,pointer,Natural>`_ + ## or `dealloc(block) <#dealloc,pointer>`_. + ## The block is not initialized, so reading + ## from it before writing to it is undefined behaviour! + ## + ## The allocated memory belongs to its allocating thread! + ## Use `allocShared <#allocShared,Natural>`_ to allocate from a shared heap. + ## + ## See also: + ## * `alloc0 <#alloc0,Natural>`_ + proc createU*(T: typedesc, size = 1.Positive): ptr T {.inline, benign, raises: [].} = + ## 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>`_ + ## or `dealloc(block) <#dealloc,pointer>`_. + ## The block is not initialized, so reading + ## from it before writing to it is undefined behaviour! + ## + ## The allocated memory belongs to its allocating thread! + ## Use `createSharedU <#createSharedU,typedesc>`_ to allocate from a shared heap. + ## + ## See also: + ## * `create <#create,typedesc>`_ + cast[ptr T](alloc(T.sizeof * size)) + + proc alloc0*(size: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].} + ## Allocates a new memory block with at least ``size`` bytes. + ## + ## The block has to be freed with `realloc(block, 0) <#realloc,pointer,Natural>`_ + ## or `dealloc(block) <#dealloc,pointer>`_. + ## The block is initialized with all bytes containing zero, so it is + ## somewhat safer than `alloc <#alloc,Natural>`_. + ## + ## The allocated memory belongs to its allocating thread! + ## Use `allocShared0 <#allocShared0,Natural>`_ to allocate from a shared heap. + proc create*(T: typedesc, size = 1.Positive): ptr T {.inline, benign, raises: [].} = + ## 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>`_ + ## or `dealloc(block) <#dealloc,pointer>`_. + ## The block is initialized with all bytes containing zero, so it is + ## somewhat safer than `createU <#createU,typedesc>`_. + ## + ## The allocated memory belongs to its allocating thread! + ## Use `createShared <#createShared,typedesc>`_ to allocate from a shared heap. + cast[ptr T](alloc0(sizeof(T) * size)) + + proc realloc*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [], + benign, raises: [].} + ## Grows or shrinks a given memory block. + ## + ## If `p` is **nil** then a new memory block is returned. + ## In either way the block has at least ``newSize`` bytes. + ## If ``newSize == 0`` and `p` is not **nil** ``realloc`` calls ``dealloc(p)``. + ## In other cases the block has to be freed with + ## `dealloc(block) <#dealloc,pointer>`_. + ## + ## The allocated memory belongs to its allocating thread! + ## Use `reallocShared <#reallocShared,pointer,Natural>`_ to reallocate + ## from a shared heap. + proc resize*[T](p: ptr T, newSize: Natural): ptr T {.inline, benign, raises: [].} = + ## Grows or shrinks a given memory block. + ## + ## If `p` is **nil** then a new memory block is returned. + ## In either way the block has at least ``T.sizeof * newSize`` bytes. + ## If ``newSize == 0`` and `p` is not **nil** ``resize`` calls ``dealloc(p)``. + ## In other cases the block has to be freed with ``free``. + ## + ## The allocated memory belongs to its allocating thread! + ## Use `resizeShared <#resizeShared,ptr.T,Natural>`_ to reallocate + ## from a shared heap. + cast[ptr T](realloc(p, T.sizeof * newSize)) + + proc dealloc*(p: pointer) {.noconv, rtl, tags: [], benign, raises: [].} + ## Frees the memory allocated with ``alloc``, ``alloc0`` or + ## ``realloc``. + ## + ## **This procedure is dangerous!** + ## If one forgets to free the memory a leak occurs; if one tries to + ## access freed memory (or just freeing it twice!) a core dump may happen + ## or other memory may be corrupted. + ## + ## The freed memory must belong to its allocating thread! + ## Use `deallocShared <#deallocShared,pointer>`_ to deallocate from a shared heap. + + proc allocShared*(size: Natural): pointer {.noconv, rtl, benign, raises: [], tags: [].} + ## Allocates a new memory block on the shared heap with at + ## least ``size`` bytes. + ## + ## The block has to be freed with + ## `reallocShared(block, 0) <#reallocShared,pointer,Natural>`_ + ## or `deallocShared(block) <#deallocShared,pointer>`_. + ## + ## The block is not initialized, so reading from it before writing + ## to it is undefined behaviour! + ## + ## See also: + ## `allocShared0 <#allocShared0,Natural>`_. + proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline, tags: [], + benign, raises: [].} = + ## Allocates a new memory block on the shared heap with at + ## least ``T.sizeof * size`` bytes. + ## + ## The block has to be freed with + ## `resizeShared(block, 0) <#resizeShared,ptr.T,Natural>`_ or + ## `freeShared(block) <#freeShared,ptr.T>`_. + ## + ## The block is not initialized, so reading from it before writing + ## to it is undefined behaviour! + ## + ## See also: + ## * `createShared <#createShared,typedesc>`_ + cast[ptr T](allocShared(T.sizeof * size)) + + proc allocShared0*(size: Natural): pointer {.noconv, rtl, benign, raises: [], tags: [].} + ## Allocates a new memory block on the shared heap with at + ## least ``size`` bytes. + ## + ## The block has to be freed with + ## `reallocShared(block, 0) <#reallocShared,pointer,Natural>`_ + ## or `deallocShared(block) <#deallocShared,pointer>`_. + ## + ## The block is initialized with all bytes + ## containing zero, so it is somewhat safer than + ## `allocShared <#allocShared,Natural>`_. + proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} = + ## Allocates a new memory block on the shared heap with at + ## least ``T.sizeof * size`` bytes. + ## + ## The block has to be freed with + ## `resizeShared(block, 0) <#resizeShared,ptr.T,Natural>`_ or + ## `freeShared(block) <#freeShared,ptr.T>`_. + ## + ## The block is initialized with all bytes + ## containing zero, so it is somewhat safer than + ## `createSharedU <#createSharedU,typedesc>`_. + cast[ptr T](allocShared0(T.sizeof * size)) + + proc reallocShared*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [], + benign, raises: [].} + ## Grows or shrinks a given memory block on the heap. + ## + ## If `p` is **nil** then a new memory block is returned. + ## In either way the block has at least ``newSize`` bytes. + ## If ``newSize == 0`` and `p` is not **nil** ``reallocShared`` calls + ## ``deallocShared(p)``. + ## In other cases the block has to be freed with + ## `deallocShared <#deallocShared,pointer>`_. + proc resizeShared*[T](p: ptr T, newSize: Natural): ptr T {.inline, raises: [].} = + ## Grows or shrinks a given memory block on the heap. + ## + ## If `p` is **nil** then a new memory block is returned. + ## In either way the block has at least ``T.sizeof * newSize`` bytes. + ## If ``newSize == 0`` and `p` is not **nil** ``resizeShared`` calls + ## ``freeShared(p)``. + ## In other cases the block has to be freed with + ## `freeShared <#freeShared,ptr.T>`_. + cast[ptr T](reallocShared(p, T.sizeof * newSize)) + + proc deallocShared*(p: pointer) {.noconv, rtl, benign, raises: [], tags: [].} + ## Frees the memory allocated with ``allocShared``, ``allocShared0`` or + ## ``reallocShared``. + ## + ## **This procedure is dangerous!** + ## If one forgets to free the memory a leak occurs; if one tries to + ## access freed memory (or just freeing it twice!) a core dump may happen + ## or other memory may be corrupted. + proc freeShared*[T](p: ptr T) {.inline, benign, raises: [].} = + ## Frees the memory allocated with ``createShared``, ``createSharedU`` or + ## ``resizeShared``. + ## + ## **This procedure is dangerous!** + ## If one forgets to free the memory a leak occurs; if one tries to + ## access freed memory (or just freeing it twice!) a core dump may happen + ## or other memory may be corrupted. + deallocShared(p) + + +# GC interface: + +when hasAlloc: + proc getOccupiedMem*(): int {.rtl.} + ## Returns the number of bytes that are owned by the process and hold data. + + proc getFreeMem*(): int {.rtl.} + ## Returns the number of bytes that are owned by the process, but do not + ## hold any meaningful data. + + proc getTotalMem*(): int {.rtl.} + ## Returns the number of bytes that are owned by the process. + + +when defined(JS): + # Stubs: + proc getOccupiedMem(): int = return -1 + proc getFreeMem(): int = return -1 + proc getTotalMem(): int = return -1 + + proc dealloc(p: pointer) = discard + proc alloc(size: Natural): pointer = discard + proc alloc0(size: Natural): pointer = discard + proc realloc(p: pointer, newsize: Natural): pointer = discard + + proc allocShared(size: Natural): pointer = discard + proc allocShared0(size: Natural): pointer = discard + proc deallocShared(p: pointer) = discard + proc reallocShared(p: pointer, newsize: Natural): pointer = discard + + +when hasAlloc and hasThreadSupport: + proc getOccupiedSharedMem*(): int {.rtl.} + ## Returns the number of bytes that are owned by the process + ## on the shared heap and hold data. This is only available when + ## threads are enabled. + + proc getFreeSharedMem*(): int {.rtl.} + ## Returns the number of bytes that are owned by the + ## process on the shared heap, but do not hold any meaningful data. + ## This is only available when threads are enabled. + + proc getTotalSharedMem*(): int {.rtl.} + ## Returns the number of bytes on the shared heap that are owned by the + ## process. This is only available when threads are enabled. diff --git a/lib/system/setops.nim b/lib/system/setops.nim new file mode 100644 index 000000000..97f042d93 --- /dev/null +++ b/lib/system/setops.nim @@ -0,0 +1,94 @@ +proc incl*[T](x: var set[T], y: T) {.magic: "Incl", noSideEffect.} + ## Includes element ``y`` in the set ``x``. + ## + ## This is the same as ``x = x + {y}``, but it might be more efficient. + ## + ## .. code-block:: Nim + ## var a = {1, 3, 5} + ## a.incl(2) # a <- {1, 2, 3, 5} + ## a.incl(4) # a <- {1, 2, 3, 4, 5} + +template incl*[T](x: var set[T], y: set[T]) = + ## Includes the set ``y`` in the set ``x``. + ## + ## .. code-block:: Nim + ## var a = {1, 3, 5, 7} + ## var b = {4, 5, 6} + ## a.incl(b) # a <- {1, 3, 4, 5, 6, 7} + x = x + y + +proc excl*[T](x: var set[T], y: T) {.magic: "Excl", noSideEffect.} + ## Excludes element ``y`` from the set ``x``. + ## + ## This is the same as ``x = x - {y}``, but it might be more efficient. + ## + ## .. code-block:: Nim + ## var b = {2, 3, 5, 6, 12, 545} + ## b.excl(5) # b <- {2, 3, 6, 12, 545} + +template excl*[T](x: var set[T], y: set[T]) = + ## Excludes the set ``y`` from the set ``x``. + ## + ## .. code-block:: Nim + ## var a = {1, 3, 5, 7} + ## var b = {3, 4, 5} + ## a.excl(b) # a <- {1, 7} + x = x - y + +proc card*[T](x: set[T]): int {.magic: "Card", noSideEffect.} + ## Returns the cardinality of the set ``x``, i.e. the number of elements + ## in the set. + ## + ## .. code-block:: Nim + ## var a = {1, 3, 5, 7} + ## echo card(a) # => 4 + +proc len*[T](x: set[T]): int {.magic: "Card", noSideEffect.} + ## An alias for `card(x)`. + + +proc `*`*[T](x, y: set[T]): set[T] {.magic: "MulSet", noSideEffect.} + ## This operator computes the intersection of two sets. + ## + ## .. code-block:: Nim + ## let + ## a = {1, 2, 3} + ## b = {2, 3, 4} + ## echo a * b # => {2, 3} +proc `+`*[T](x, y: set[T]): set[T] {.magic: "PlusSet", noSideEffect.} + ## This operator computes the union of two sets. + ## + ## .. code-block:: Nim + ## let + ## a = {1, 2, 3} + ## b = {2, 3, 4} + ## echo a + b # => {1, 2, 3, 4} +proc `-`*[T](x, y: set[T]): set[T] {.magic: "MinusSet", noSideEffect.} + ## This operator computes the difference of two sets. + ## + ## .. code-block:: Nim + ## let + ## a = {1, 2, 3} + ## b = {2, 3, 4} + ## echo a - b # => {1} + +proc contains*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.} + ## One should overload this proc if one wants to overload the ``in`` operator. + ## + ## The parameters are in reverse order! ``a in b`` is a template for + ## ``contains(b, a)``. + ## This is because the unification algorithm that Nim uses for overload + ## resolution works from left to right. + ## But for the ``in`` operator that would be the wrong direction for this + ## piece of code: + ## + ## .. code-block:: Nim + ## var s: set[range['a'..'z']] = {'a'..'c'} + ## assert s.contains('c') + ## assert 'b' in s + ## + ## If ``in`` had been declared as ``[T](elem: T, s: set[T])`` then ``T`` would + ## have been bound to ``char``. But ``s`` is not compatible to type + ## ``set[char]``! The solution is to bind ``T`` to ``range['a'..'z']``. This + ## is achieved by reversing the parameters for ``contains``; ``in`` then + ## passes its arguments in reverse order. |