Merge branch 'devel' into araq
This commit is contained in:
commit
1eaeccc15d
616 changed files with 73547 additions and 36764 deletions
|
|
@ -129,13 +129,6 @@ const
|
|||
nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
|
||||
nnkCallStrLit}
|
||||
|
||||
proc `[]`*(n: NimNode, i: int): NimNode {.magic: "NChild", noSideEffect.}
|
||||
## get `n`'s `i`'th child.
|
||||
|
||||
proc `[]=`*(n: NimNode, i: int, child: NimNode) {.magic: "NSetChild",
|
||||
noSideEffect.}
|
||||
## set `n`'s `i`'th child to `child`.
|
||||
|
||||
proc `!`*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect.}
|
||||
## constructs an identifier from the string `s`
|
||||
|
||||
|
|
@ -162,6 +155,20 @@ proc sameType*(a, b: NimNode): bool {.magic: "SameNodeType", noSideEffect.} =
|
|||
proc len*(n: NimNode): int {.magic: "NLen", noSideEffect.}
|
||||
## returns the number of children of `n`.
|
||||
|
||||
proc `[]`*(n: NimNode, i: int): NimNode {.magic: "NChild", noSideEffect.}
|
||||
## get `n`'s `i`'th child.
|
||||
|
||||
proc `[]`*(n: NimNode, i: BackwardsIndex): NimNode = n[n.len - i.int]
|
||||
## get `n`'s `i`'th child.
|
||||
|
||||
proc `[]=`*(n: NimNode, i: int, child: NimNode) {.magic: "NSetChild",
|
||||
noSideEffect.}
|
||||
## set `n`'s `i`'th child to `child`.
|
||||
|
||||
proc `[]=`*(n: NimNode, i: BackwardsIndex, child: NimNode) =
|
||||
## set `n`'s `i`'th child to `child`.
|
||||
n[n.len - i.int] = child
|
||||
|
||||
proc add*(father, child: NimNode): NimNode {.magic: "NAdd", discardable,
|
||||
noSideEffect, locks: 0.}
|
||||
## Adds the `child` to the `father` node. Returns the
|
||||
|
|
@ -839,7 +846,7 @@ proc newNilLit*(): NimNode {.compileTime.} =
|
|||
## New nil literal shortcut
|
||||
result = newNimNode(nnkNilLit)
|
||||
|
||||
proc last*(node: NimNode): NimNode {.compileTime.} = node[<node.len]
|
||||
proc last*(node: NimNode): NimNode {.compileTime.} = node[node.len-1]
|
||||
## Return the last item in nodes children. Same as `node[^1]`
|
||||
|
||||
|
||||
|
|
@ -887,7 +894,7 @@ proc newIfStmt*(branches: varargs[tuple[cond, body: NimNode]]):
|
|||
|
||||
proc copyChildrenTo*(src, dest: NimNode) {.compileTime.}=
|
||||
## Copy all children from `src` to `dest`
|
||||
for i in 0 .. < src.len:
|
||||
for i in 0 ..< src.len:
|
||||
dest.add src[i].copyNimTree
|
||||
|
||||
template expectRoutine(node: NimNode) =
|
||||
|
|
@ -986,6 +993,11 @@ iterator items*(n: NimNode): NimNode {.inline.} =
|
|||
for i in 0 ..< n.len:
|
||||
yield n[i]
|
||||
|
||||
iterator pairs*(n: NimNode): (int, NimNode) {.inline.} =
|
||||
## Iterates over the children of the NimNode ``n`` and its indices.
|
||||
for i in 0 ..< n.len:
|
||||
yield (i, n[i])
|
||||
|
||||
iterator children*(n: NimNode): NimNode {.inline.} =
|
||||
## Iterates over the children of the NimNode ``n``.
|
||||
for i in 0 ..< n.len:
|
||||
|
|
@ -1099,10 +1111,10 @@ proc eqIdent*(node: NimNode; s: string): bool {.compileTime.} =
|
|||
else:
|
||||
result = false
|
||||
|
||||
proc hasArgOfName* (params: NimNode; name: string): bool {.compiletime.}=
|
||||
proc hasArgOfName*(params: NimNode; name: string): bool {.compiletime.}=
|
||||
## Search nnkFormalParams for an argument.
|
||||
assert params.kind == nnkFormalParams
|
||||
for i in 1 .. <params.len:
|
||||
for i in 1 ..< params.len:
|
||||
template node: untyped = params[i]
|
||||
if name.eqIdent( $ node[0]):
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
## var
|
||||
## a: ActorPool[int, void]
|
||||
## createActorPool(a)
|
||||
## for i in 0 .. < 300:
|
||||
## for i in 0 ..< 300:
|
||||
## a.spawn(i, proc (x: int) {.thread.} = echo x)
|
||||
## a.join()
|
||||
##
|
||||
|
|
@ -133,7 +133,7 @@ proc createActorPool*[In, Out](a: var ActorPool[In, Out], poolSize = 4) =
|
|||
newSeq(a.actors, poolSize)
|
||||
when Out isnot void:
|
||||
open(a.outputs)
|
||||
for i in 0 .. < a.actors.len:
|
||||
for i in 0 ..< a.actors.len:
|
||||
a.actors[i] = spawn(poolWorker[In, Out])
|
||||
|
||||
proc sync*[In, Out](a: var ActorPool[In, Out], polling=50) =
|
||||
|
|
@ -164,8 +164,8 @@ proc terminate*[In, Out](a: var ActorPool[In, Out]) =
|
|||
## resources attached to `a`.
|
||||
var t: Task[In, Out]
|
||||
t.shutdown = true
|
||||
for i in 0.. <a.actors.len: send(a.actors[i].i, t)
|
||||
for i in 0.. <a.actors.len: join(a.actors[i])
|
||||
for i in 0..<a.actors.len: send(a.actors[i].i, t)
|
||||
for i in 0..<a.actors.len: join(a.actors[i])
|
||||
when Out isnot void:
|
||||
close(a.outputs)
|
||||
a.actors = nil
|
||||
|
|
@ -227,7 +227,7 @@ when not defined(testing) and isMainModule:
|
|||
var
|
||||
a: ActorPool[int, void]
|
||||
createActorPool(a)
|
||||
for i in 0 .. < 300:
|
||||
for i in 0 ..< 300:
|
||||
a.spawn(i, proc (x: int) {.thread.} = echo x)
|
||||
|
||||
when false:
|
||||
|
|
|
|||
|
|
@ -98,15 +98,18 @@ proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string =
|
|||
var a = 0
|
||||
if args.len > 0 and not string(formatstr).contains("?"):
|
||||
dbError("""parameter substitution expects "?" """)
|
||||
for c in items(string(formatstr)):
|
||||
if c == '?':
|
||||
if args[a] == nil:
|
||||
add(result, "NULL")
|
||||
if args.len == 0:
|
||||
return string(formatstr)
|
||||
else:
|
||||
for c in items(string(formatstr)):
|
||||
if c == '?':
|
||||
if args[a] == nil:
|
||||
add(result, "NULL")
|
||||
else:
|
||||
add(result, dbQuote(args[a]))
|
||||
inc(a)
|
||||
else:
|
||||
add(result, dbQuote(args[a]))
|
||||
inc(a)
|
||||
else:
|
||||
add(result, c)
|
||||
add(result, c)
|
||||
|
||||
proc tryExec*(db: DbConn, query: SqlQuery,
|
||||
args: varargs[string, `$`]): bool {.tags: [ReadDbEffect, WriteDbEffect].} =
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ type
|
|||
## - ``"abc".match(re"(?<letter>\w)").captures["letter"] == "a"``
|
||||
## - ``"abc".match(re"(\w)\w").captures[-1] == "ab"``
|
||||
##
|
||||
## ``captureBounds[]: Option[Slice[int]]``
|
||||
## ``captureBounds[]: Option[HSlice[int, int]]``
|
||||
## gets the bounds of the given capture according to the same rules as
|
||||
## the above. If the capture is not filled, then ``None`` is returned.
|
||||
## The bounds are both inclusive.
|
||||
|
|
@ -167,7 +167,7 @@ type
|
|||
## ``match: string``
|
||||
## the full text of the match.
|
||||
##
|
||||
## ``matchBounds: Slice[int]``
|
||||
## ``matchBounds: HSlice[int, int]``
|
||||
## the bounds of the match, as in ``captureBounds[]``
|
||||
##
|
||||
## ``(captureBounds|captures).toTable``
|
||||
|
|
@ -182,9 +182,9 @@ type
|
|||
## Not nil.
|
||||
str*: string ## The string that was matched against.
|
||||
## Not nil.
|
||||
pcreMatchBounds: seq[Slice[cint]] ## First item is the bounds of the match
|
||||
## Other items are the captures
|
||||
## `a` is inclusive start, `b` is exclusive end
|
||||
pcreMatchBounds: seq[HSlice[cint, cint]] ## First item is the bounds of the match
|
||||
## Other items are the captures
|
||||
## `a` is inclusive start, `b` is exclusive end
|
||||
|
||||
Captures* = distinct RegexMatch
|
||||
CaptureBounds* = distinct RegexMatch
|
||||
|
|
@ -251,13 +251,13 @@ proc captureBounds*(pattern: RegexMatch): CaptureBounds = return CaptureBounds(p
|
|||
|
||||
proc captures*(pattern: RegexMatch): Captures = return Captures(pattern)
|
||||
|
||||
proc `[]`*(pattern: CaptureBounds, i: int): Option[Slice[int]] =
|
||||
proc `[]`*(pattern: CaptureBounds, i: int): Option[HSlice[int, int]] =
|
||||
let pattern = RegexMatch(pattern)
|
||||
if pattern.pcreMatchBounds[i + 1].a != -1:
|
||||
let bounds = pattern.pcreMatchBounds[i + 1]
|
||||
return some(int(bounds.a) .. int(bounds.b-1))
|
||||
else:
|
||||
return none(Slice[int])
|
||||
return none(HSlice[int, int])
|
||||
|
||||
proc `[]`*(pattern: Captures, i: int): string =
|
||||
let pattern = RegexMatch(pattern)
|
||||
|
|
@ -272,10 +272,10 @@ proc `[]`*(pattern: Captures, i: int): string =
|
|||
proc match*(pattern: RegexMatch): string =
|
||||
return pattern.captures[-1]
|
||||
|
||||
proc matchBounds*(pattern: RegexMatch): Slice[int] =
|
||||
proc matchBounds*(pattern: RegexMatch): HSlice[int, int] =
|
||||
return pattern.captureBounds[-1].get
|
||||
|
||||
proc `[]`*(pattern: CaptureBounds, name: string): Option[Slice[int]] =
|
||||
proc `[]`*(pattern: CaptureBounds, name: string): Option[HSlice[int, int]] =
|
||||
let pattern = RegexMatch(pattern)
|
||||
return pattern.captureBounds[pattern.pattern.captureNameToId.fget(name)]
|
||||
|
||||
|
|
@ -295,13 +295,13 @@ proc toTable*(pattern: Captures, default: string = nil): Table[string, string] =
|
|||
result = initTable[string, string]()
|
||||
toTableImpl(nextVal == nil)
|
||||
|
||||
proc toTable*(pattern: CaptureBounds, default = none(Slice[int])):
|
||||
Table[string, Option[Slice[int]]] =
|
||||
result = initTable[string, Option[Slice[int]]]()
|
||||
proc toTable*(pattern: CaptureBounds, default = none(HSlice[int, int])):
|
||||
Table[string, Option[HSlice[int, int]]] =
|
||||
result = initTable[string, Option[HSlice[int, int]]]()
|
||||
toTableImpl(nextVal.isNone)
|
||||
|
||||
template itemsImpl(cond: untyped) {.dirty.} =
|
||||
for i in 0 .. <RegexMatch(pattern).pattern.captureCount:
|
||||
for i in 0 ..< RegexMatch(pattern).pattern.captureCount:
|
||||
let nextVal = pattern[i]
|
||||
# done in this roundabout way to avoid multiple yields (potential code
|
||||
# bloat)
|
||||
|
|
@ -309,13 +309,13 @@ template itemsImpl(cond: untyped) {.dirty.} =
|
|||
yield nextYieldVal
|
||||
|
||||
|
||||
iterator items*(pattern: CaptureBounds, default = none(Slice[int])): Option[Slice[int]] =
|
||||
iterator items*(pattern: CaptureBounds, default = none(HSlice[int, int])): Option[HSlice[int, int]] =
|
||||
itemsImpl(nextVal.isNone)
|
||||
|
||||
iterator items*(pattern: Captures, default: string = nil): string =
|
||||
itemsImpl(nextVal == nil)
|
||||
|
||||
proc toSeq*(pattern: CaptureBounds, default = none(Slice[int])): seq[Option[Slice[int]]] =
|
||||
proc toSeq*(pattern: CaptureBounds, default = none(HSlice[int, int])): seq[Option[HSlice[int, int]]] =
|
||||
accumulateResult(pattern.items(default))
|
||||
|
||||
proc toSeq*(pattern: Captures, default: string = nil): seq[string] =
|
||||
|
|
@ -396,8 +396,6 @@ proc extractOptions(pattern: string): tuple[pattern: string, flags: int, study:
|
|||
|
||||
# }}}
|
||||
|
||||
type UncheckedArray {.unchecked.}[T] = array[0 .. 0, T]
|
||||
|
||||
proc destroyRegex(pattern: Regex) =
|
||||
pcre.free_substring(cast[cstring](pattern.pcreObj))
|
||||
pattern.pcreObj = nil
|
||||
|
|
@ -412,7 +410,7 @@ proc getNameToNumberTable(pattern: Regex): Table[string, int] =
|
|||
|
||||
result = initTable[string, int]()
|
||||
|
||||
for i in 0 .. <entryCount:
|
||||
for i in 0 ..< entryCount:
|
||||
let pos = i * entrySize
|
||||
let num = (int(table[pos]) shl 8) or int(table[pos + 1]) - 1
|
||||
var name = ""
|
||||
|
|
@ -464,7 +462,7 @@ proc matchImpl(str: string, pattern: Regex, start, endpos: int, flags: int): Opt
|
|||
# 1x capture count as slack space for PCRE
|
||||
let vecsize = (pattern.captureCount() + 1) * 3
|
||||
# div 2 because each element is 2 cints long
|
||||
myResult.pcreMatchBounds = newSeq[Slice[cint]](ceil(vecsize / 2).int)
|
||||
myResult.pcreMatchBounds = newSeq[HSlice[cint, cint]](ceil(vecsize / 2).int)
|
||||
myResult.pcreMatchBounds.setLen(vecsize div 3)
|
||||
|
||||
let strlen = if endpos == int.high: str.len else: endpos+1
|
||||
|
|
|
|||
|
|
@ -13,10 +13,6 @@
|
|||
## We had to de-deprecate this module since too much code relies on it
|
||||
## and many people prefer its API over ``nre``'s.
|
||||
##
|
||||
## **Note:** The 're' proc defaults to the **extended regular expression
|
||||
## syntax** which lets you use whitespace freely to make your regexes readable.
|
||||
## However, this means matching whitespace requires ``\s`` or something similar.
|
||||
##
|
||||
## This module is implemented by providing a wrapper around the
|
||||
## `PRCE (Perl-Compatible Regular Expressions) <http://www.pcre.org>`_
|
||||
## C library. This means that your application will depend on the PRCE
|
||||
|
|
@ -78,7 +74,7 @@ proc finalizeRegEx(x: Regex) =
|
|||
if not isNil(x.e):
|
||||
pcre.free_substring(cast[cstring](x.e))
|
||||
|
||||
proc re*(s: string, flags = {reExtended, reStudy}): Regex =
|
||||
proc re*(s: string, flags = {reStudy}): Regex =
|
||||
## Constructor of regular expressions.
|
||||
##
|
||||
## Note that Nim's
|
||||
|
|
@ -96,6 +92,13 @@ proc re*(s: string, flags = {reExtended, reStudy}): Regex =
|
|||
result.e = pcre.study(result.h, options, addr msg)
|
||||
if not isNil(msg): raiseInvalidRegex($msg)
|
||||
|
||||
proc rex*(s: string, flags = {reStudy, reExtended}): Regex =
|
||||
## Constructor for extended regular expressions.
|
||||
##
|
||||
## The extended means that comments starting with `#` and
|
||||
## whitespace are ignored.
|
||||
result = re(s, flags)
|
||||
|
||||
proc bufSubstr(b: cstring, sPos, ePos: int): string {.inline.} =
|
||||
## Return a Nim string built from a slice of a cstring buffer.
|
||||
## Don't assume cstring is '\0' terminated
|
||||
|
|
|
|||
|
|
@ -63,16 +63,16 @@ proc recvLine*(sock: SecureSocket, line: var TaintedString): bool =
|
|||
setLen(line.string, 0)
|
||||
while true:
|
||||
var c: array[0..0, char]
|
||||
var n = BIO_read(sock.bio, c, c.len.cint)
|
||||
var n = BIO_read(sock.bio, addr c, c.len.cint)
|
||||
if n <= 0: return false
|
||||
if c[0] == '\r':
|
||||
n = BIO_read(sock.bio, c, c.len.cint)
|
||||
n = BIO_read(sock.bio, addr c, c.len.cint)
|
||||
if n > 0 and c[0] == '\L':
|
||||
return true
|
||||
elif n <= 0:
|
||||
return false
|
||||
elif c[0] == '\L': return true
|
||||
add(line.string, c)
|
||||
add(line.string, c[0])
|
||||
|
||||
|
||||
proc send*(sock: SecureSocket, data: string) =
|
||||
|
|
|
|||
|
|
@ -396,15 +396,13 @@ typedef struct TStringDesc* string;
|
|||
#define GenericSeqSize sizeof(TGenericSeq)
|
||||
#define paramCount() cmdCount
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__i386__)
|
||||
# ifndef NAN
|
||||
static unsigned long nimNaN[2]={0xffffffff, 0x7fffffff};
|
||||
# define NAN (*(double*) nimNaN)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// NAN definition copied from math.h included in the Windows SDK version 10.0.14393.0
|
||||
#ifndef NAN
|
||||
# define NAN (0.0 / 0.0)
|
||||
#ifndef _HUGE_ENUF
|
||||
#define _HUGE_ENUF 1e+300 // _HUGE_ENUF*_HUGE_ENUF must overflow
|
||||
#endif
|
||||
#define NAN_INFINITY ((float)(_HUGE_ENUF * _HUGE_ENUF))
|
||||
#define NAN ((float)(NAN_INFINITY * 0.0F))
|
||||
#endif
|
||||
|
||||
#ifndef INF
|
||||
|
|
|
|||
|
|
@ -26,3 +26,5 @@ const
|
|||
proc clone*(fn: pointer; child_stack: pointer; flags: cint;
|
||||
arg: pointer; ptid: ptr Pid; tls: pointer;
|
||||
ctid: ptr Pid): cint {.importc, header: "<sched.h>".}
|
||||
|
||||
proc pipe2*(a: array[0..1, cint], flags: cint): cint {.importc, header: "<unistd.h>".}
|
||||
|
|
@ -146,7 +146,7 @@ type
|
|||
Mode* {.importc: "mode_t", header: "<sys/types.h>".} = cint
|
||||
Nlink* {.importc: "nlink_t", header: "<sys/types.h>".} = int
|
||||
Off* {.importc: "off_t", header: "<sys/types.h>".} = int64
|
||||
Pid* {.importc: "pid_t", header: "<sys/types.h>".} = int
|
||||
Pid* {.importc: "pid_t", header: "<sys/types.h>".} = int32
|
||||
Pthread_attr* {.importc: "pthread_attr_t", header: "<sys/types.h>".} = int
|
||||
Pthread_barrier* {.importc: "pthread_barrier_t",
|
||||
header: "<sys/types.h>".} = int
|
||||
|
|
|
|||
|
|
@ -371,3 +371,126 @@ when isMainModule:
|
|||
for i in 0 .. high(arr1):
|
||||
assert arr1.reversed(0, i) == arr1.reversed()[high(arr1) - i .. high(arr1)]
|
||||
assert arr1.reversed(i, high(arr1)) == arr1.reversed()[0 .. high(arr1) - i]
|
||||
|
||||
|
||||
proc rotateInternal[T](arg: var openarray[T]; first, middle, last: int): int =
|
||||
## A port of std::rotate from c++. Ported from `this reference <http://www.cplusplus.com/reference/algorithm/rotate/>`_.
|
||||
result = first + last - middle
|
||||
|
||||
if first == middle or middle == last:
|
||||
return
|
||||
|
||||
assert first < middle
|
||||
assert middle < last
|
||||
|
||||
# m prefix for mutable
|
||||
var
|
||||
mFirst = first
|
||||
mMiddle = middle
|
||||
next = middle
|
||||
|
||||
swap(arg[mFirst], arg[next])
|
||||
mFirst += 1
|
||||
next += 1
|
||||
if mFirst == mMiddle:
|
||||
mMiddle = next
|
||||
|
||||
while next != last:
|
||||
swap(arg[mFirst], arg[next])
|
||||
mFirst += 1
|
||||
next += 1
|
||||
if mFirst == mMiddle:
|
||||
mMiddle = next
|
||||
|
||||
next = mMiddle
|
||||
while next != last:
|
||||
swap(arg[mFirst], arg[next])
|
||||
mFirst += 1
|
||||
next += 1
|
||||
if mFirst == mMiddle:
|
||||
mMiddle = next
|
||||
elif next == last:
|
||||
next = mMiddle
|
||||
|
||||
proc rotatedInternal[T](arg: openarray[T]; first, middle, last: int): seq[T] =
|
||||
result = newSeq[T](arg.len)
|
||||
for i in 0 ..< first:
|
||||
result[i] = arg[i]
|
||||
let N = last - middle
|
||||
let M = middle - first
|
||||
for i in 0 ..< N:
|
||||
result[first+i] = arg[middle+i]
|
||||
for i in 0 ..< M:
|
||||
result[first+N+i] = arg[first+i]
|
||||
for i in last ..< arg.len:
|
||||
result[i] = arg[i]
|
||||
|
||||
proc rotateLeft*[T](arg: var openarray[T]; slice: HSlice[int, int]; dist: int): int =
|
||||
## Performs a left rotation on a range of elements. If you want to rotate right, use a negative ``dist``.
|
||||
## Specifically, ``rotateLeft`` rotates the elements at ``slice`` by ``dist`` positions.
|
||||
## The element at index ``slice.a + dist`` will be at index ``slice.a``.
|
||||
## The element at index ``slice.b`` will be at ``slice.a + dist -1``.
|
||||
## The element at index ``slice.a`` will be at ``slice.b + 1 - dist``.
|
||||
## The element at index ``slice.a + dist - 1`` will be at ``slice.b``.
|
||||
#
|
||||
## Elements outsize of ``slice`` will be left unchanged.
|
||||
## The time complexity is linear to ``slice.b - slice.a + 1``.
|
||||
##
|
||||
## ``slice``
|
||||
## the indices of the element range that should be rotated.
|
||||
##
|
||||
## ``dist``
|
||||
## the distance in amount of elements that the data should be rotated. Can be negative, can be any number.
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## var list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
## list.rotateLeft(1 .. 8, 3)
|
||||
## doAssert list == [0, 4, 5, 6, 7, 8, 1, 2, 3, 9, 10]
|
||||
let sliceLen = slice.b + 1 - slice.a
|
||||
let distLeft = ((dist mod sliceLen) + sliceLen) mod sliceLen
|
||||
arg.rotateInternal(slice.a, slice.a+distLeft, slice.b + 1)
|
||||
|
||||
proc rotateLeft*[T](arg: var openarray[T]; dist: int): int =
|
||||
## default arguments for slice, so that this procedure operates on the entire
|
||||
## ``arg``, and not just on a part of it.
|
||||
let arglen = arg.len
|
||||
let distLeft = ((dist mod arglen) + arglen) mod arglen
|
||||
arg.rotateInternal(0, distLeft, arglen)
|
||||
|
||||
proc rotatedLeft*[T](arg: openarray[T]; slice: HSlice[int, int], dist: int): seq[T] =
|
||||
## same as ``rotateLeft``, just with the difference that it does
|
||||
## not modify the argument. It creates a new ``seq`` instead
|
||||
let sliceLen = slice.b + 1 - slice.a
|
||||
let distLeft = ((dist mod sliceLen) + sliceLen) mod sliceLen
|
||||
arg.rotatedInternal(slice.a, slice.a+distLeft, slice.b+1)
|
||||
|
||||
proc rotatedLeft*[T](arg: openarray[T]; dist: int): seq[T] =
|
||||
## same as ``rotateLeft``, just with the difference that it does
|
||||
## not modify the argument. It creates a new ``seq`` instead
|
||||
let arglen = arg.len
|
||||
let distLeft = ((dist mod arglen) + arglen) mod arglen
|
||||
arg.rotatedInternal(0, distLeft, arg.len)
|
||||
|
||||
when isMainModule:
|
||||
var list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
let list2 = list.rotatedLeft(1 ..< 9, 3)
|
||||
let expected = [0, 4, 5, 6, 7, 8, 1, 2, 3, 9, 10]
|
||||
|
||||
doAssert list.rotateLeft(1 ..< 9, 3) == 6
|
||||
doAssert list == expected
|
||||
doAssert list2 == @expected
|
||||
|
||||
var s0,s1,s2,s3,s4,s5 = "xxxabcdefgxxx"
|
||||
|
||||
doAssert s0.rotateLeft(3 ..< 10, 3) == 7
|
||||
doAssert s0 == "xxxdefgabcxxx"
|
||||
doAssert s1.rotateLeft(3 ..< 10, 2) == 8
|
||||
doAssert s1 == "xxxcdefgabxxx"
|
||||
doAssert s2.rotateLeft(3 ..< 10, 4) == 6
|
||||
doAssert s2 == "xxxefgabcdxxx"
|
||||
doAssert s3.rotateLeft(3 ..< 10, -3) == 6
|
||||
doAssert s3 == "xxxefgabcdxxx"
|
||||
doAssert s4.rotateLeft(3 ..< 10, -10) == 6
|
||||
doAssert s4 == "xxxefgabcdxxx"
|
||||
doAssert s5.rotateLeft(3 ..< 10, 11) == 6
|
||||
doAssert s5 == "xxxefgabcdxxx"
|
||||
|
|
|
|||
|
|
@ -61,14 +61,14 @@ proc generateExceptionCheck(futSym,
|
|||
else:
|
||||
var exceptionChecks: seq[tuple[cond, body: NimNode]] = @[]
|
||||
let errorNode = newDotExpr(futSym, newIdentNode("error"))
|
||||
for i in 1 .. <tryStmt.len:
|
||||
for i in 1 ..< tryStmt.len:
|
||||
let exceptBranch = tryStmt[i]
|
||||
if exceptBranch[0].kind == nnkStmtList:
|
||||
exceptionChecks.add((newIdentNode("true"), exceptBranch[0]))
|
||||
else:
|
||||
var exceptIdentCount = 0
|
||||
var ifCond: NimNode
|
||||
for i in 0 .. <exceptBranch.len:
|
||||
for i in 0 ..< exceptBranch.len:
|
||||
let child = exceptBranch[i]
|
||||
if child.kind == nnkIdent:
|
||||
let cond = infix(errorNode, "of", child)
|
||||
|
|
@ -270,7 +270,7 @@ proc processBody(node, retFutureSym: NimNode,
|
|||
return
|
||||
else: discard
|
||||
|
||||
for i in 0 .. <result.len:
|
||||
for i in 0 ..< result.len:
|
||||
result[i] = processBody(result[i], retFutureSym, subTypeIsVoid,
|
||||
futureVarIdents, nil)
|
||||
|
||||
|
|
@ -287,7 +287,7 @@ proc getName(node: NimNode): string {.compileTime.} =
|
|||
|
||||
proc getFutureVarIdents(params: NimNode): seq[NimNode] {.compileTime.} =
|
||||
result = @[]
|
||||
for i in 1 .. <len(params):
|
||||
for i in 1 ..< len(params):
|
||||
expectKind(params[i], nnkIdentDefs)
|
||||
if params[i][1].kind == nnkBracketExpr and
|
||||
($params[i][1][0].ident).normalize == "futurevar":
|
||||
|
|
@ -466,7 +466,7 @@ proc stripAwait(node: NimNode): NimNode =
|
|||
node[0][0] = emptyNoopSym
|
||||
else: discard
|
||||
|
||||
for i in 0 .. <result.len:
|
||||
for i in 0 ..< result.len:
|
||||
result[i] = stripAwait(result[i])
|
||||
|
||||
proc splitParamType(paramType: NimNode, async: bool): NimNode =
|
||||
|
|
@ -512,7 +512,7 @@ proc splitProc(prc: NimNode): (NimNode, NimNode) =
|
|||
# Retrieve the `T` inside `Future[T]`.
|
||||
let returnType = stripReturnType(result[0][3][0])
|
||||
result[0][3][0] = splitParamType(returnType, async=false)
|
||||
for i in 1 .. <result[0][3].len:
|
||||
for i in 1 ..< result[0][3].len:
|
||||
# Sync proc (0) -> FormalParams (3) -> IdentDefs, the parameter (i) ->
|
||||
# parameter type (1).
|
||||
result[0][3][i][1] = splitParamType(result[0][3][i][1], async=false)
|
||||
|
|
@ -521,7 +521,7 @@ proc splitProc(prc: NimNode): (NimNode, NimNode) =
|
|||
result[1] = prc.copyNimTree()
|
||||
if result[1][3][0].kind == nnkBracketExpr:
|
||||
result[1][3][0][1] = splitParamType(result[1][3][0][1], async=true)
|
||||
for i in 1 .. <result[1][3].len:
|
||||
for i in 1 ..< result[1][3].len:
|
||||
# Async proc (1) -> FormalParams (3) -> IdentDefs, the parameter (i) ->
|
||||
# parameter type (1).
|
||||
result[1][3][i][1] = splitParamType(result[1][3][i][1], async=true)
|
||||
|
|
|
|||
|
|
@ -257,7 +257,7 @@ proc allprefixedAux[T](c: CritBitTree[T], key: string; longestMatch: bool): Node
|
|||
p = p.child[dir]
|
||||
if q.byte < key.len: top = p
|
||||
if not longestMatch:
|
||||
for i in 0 .. <key.len:
|
||||
for i in 0 ..< key.len:
|
||||
if p.key[i] != key[i]: return
|
||||
result = top
|
||||
|
||||
|
|
|
|||
|
|
@ -207,9 +207,9 @@ when isMainModule:
|
|||
assert($deq == "[4, 56, 6, 789]")
|
||||
|
||||
assert deq[0] == deq.peekFirst and deq.peekFirst == 4
|
||||
assert deq[^1] == deq.peekLast and deq.peekLast == 789
|
||||
#assert deq[^1] == deq.peekLast and deq.peekLast == 789
|
||||
deq[0] = 42
|
||||
deq[^1] = 7
|
||||
deq[deq.len - 1] = 7
|
||||
|
||||
assert 6 in deq and 789 notin deq
|
||||
assert deq.find(6) >= 0
|
||||
|
|
|
|||
|
|
@ -37,6 +37,14 @@ type
|
|||
DoublyLinkedRing*[T] = object ## a doubly linked ring
|
||||
head*: DoublyLinkedNode[T]
|
||||
|
||||
SomeLinkedList*[T] = SinglyLinkedList[T] | DoublyLinkedList[T]
|
||||
|
||||
SomeLinkedRing*[T] = SinglyLinkedRing[T] | DoublyLinkedRing[T]
|
||||
|
||||
SomeLinkedCollection*[T] = SomeLinkedList[T] | SomeLinkedRing[T]
|
||||
|
||||
SomeLinkedNode*[T] = SinglyLinkedNode[T] | DoublyLinkedNode[T]
|
||||
|
||||
{.deprecated: [TDoublyLinkedNode: DoublyLinkedNodeObj,
|
||||
PDoublyLinkedNode: DoublyLinkedNode,
|
||||
TSinglyLinkedNode: SinglyLinkedNodeObj,
|
||||
|
|
@ -86,14 +94,34 @@ template itemsRingImpl() {.dirty.} =
|
|||
it = it.next
|
||||
if it == L.head: break
|
||||
|
||||
template nodesListImpl() {.dirty.} =
|
||||
iterator items*[T](L: SomeLinkedList[T]): T =
|
||||
## yields every value of `L`.
|
||||
itemsListImpl()
|
||||
|
||||
iterator items*[T](L: SomeLinkedRing[T]): T =
|
||||
## yields every value of `L`.
|
||||
itemsRingImpl()
|
||||
|
||||
iterator mitems*[T](L: var SomeLinkedList[T]): var T =
|
||||
## yields every value of `L` so that you can modify it.
|
||||
itemsListImpl()
|
||||
|
||||
iterator mitems*[T](L: var SomeLinkedRing[T]): var T =
|
||||
## yields every value of `L` so that you can modify it.
|
||||
itemsRingImpl()
|
||||
|
||||
iterator nodes*[T](L: SomeLinkedList[T]): SomeLinkedNode[T] =
|
||||
## iterates over every node of `x`. Removing the current node from the
|
||||
## list during traversal is supported.
|
||||
var it = L.head
|
||||
while it != nil:
|
||||
var nxt = it.next
|
||||
yield it
|
||||
it = nxt
|
||||
|
||||
template nodesRingImpl() {.dirty.} =
|
||||
iterator nodes*[T](L: SomeLinkedRing[T]): SomeLinkedNode[T] =
|
||||
## iterates over every node of `x`. Removing the current node from the
|
||||
## list during traversal is supported.
|
||||
var it = L.head
|
||||
if it != nil:
|
||||
while true:
|
||||
|
|
@ -102,121 +130,21 @@ template nodesRingImpl() {.dirty.} =
|
|||
it = nxt
|
||||
if it == L.head: break
|
||||
|
||||
template findImpl() {.dirty.} =
|
||||
for x in nodes(L):
|
||||
if x.value == value: return x
|
||||
|
||||
iterator items*[T](L: DoublyLinkedList[T]): T =
|
||||
## yields every value of `L`.
|
||||
itemsListImpl()
|
||||
|
||||
iterator items*[T](L: SinglyLinkedList[T]): T =
|
||||
## yields every value of `L`.
|
||||
itemsListImpl()
|
||||
|
||||
iterator items*[T](L: SinglyLinkedRing[T]): T =
|
||||
## yields every value of `L`.
|
||||
itemsRingImpl()
|
||||
|
||||
iterator items*[T](L: DoublyLinkedRing[T]): T =
|
||||
## yields every value of `L`.
|
||||
itemsRingImpl()
|
||||
|
||||
iterator mitems*[T](L: var DoublyLinkedList[T]): var T =
|
||||
## yields every value of `L` so that you can modify it.
|
||||
itemsListImpl()
|
||||
|
||||
iterator mitems*[T](L: var SinglyLinkedList[T]): var T =
|
||||
## yields every value of `L` so that you can modify it.
|
||||
itemsListImpl()
|
||||
|
||||
iterator mitems*[T](L: var SinglyLinkedRing[T]): var T =
|
||||
## yields every value of `L` so that you can modify it.
|
||||
itemsRingImpl()
|
||||
|
||||
iterator mitems*[T](L: var DoublyLinkedRing[T]): var T =
|
||||
## yields every value of `L` so that you can modify it.
|
||||
itemsRingImpl()
|
||||
|
||||
iterator nodes*[T](L: SinglyLinkedList[T]): SinglyLinkedNode[T] =
|
||||
## iterates over every node of `x`. Removing the current node from the
|
||||
## list during traversal is supported.
|
||||
nodesListImpl()
|
||||
|
||||
iterator nodes*[T](L: DoublyLinkedList[T]): DoublyLinkedNode[T] =
|
||||
## iterates over every node of `x`. Removing the current node from the
|
||||
## list during traversal is supported.
|
||||
nodesListImpl()
|
||||
|
||||
iterator nodes*[T](L: SinglyLinkedRing[T]): SinglyLinkedNode[T] =
|
||||
## iterates over every node of `x`. Removing the current node from the
|
||||
## list during traversal is supported.
|
||||
nodesRingImpl()
|
||||
|
||||
iterator nodes*[T](L: DoublyLinkedRing[T]): DoublyLinkedNode[T] =
|
||||
## iterates over every node of `x`. Removing the current node from the
|
||||
## list during traversal is supported.
|
||||
nodesRingImpl()
|
||||
|
||||
template dollarImpl() {.dirty.} =
|
||||
proc `$`*[T](L: SomeLinkedCollection[T]): string =
|
||||
## turns a list into its string representation.
|
||||
result = "["
|
||||
for x in nodes(L):
|
||||
if result.len > 1: result.add(", ")
|
||||
result.add($x.value)
|
||||
result.add("]")
|
||||
|
||||
proc `$`*[T](L: SinglyLinkedList[T]): string =
|
||||
## turns a list into its string representation.
|
||||
dollarImpl()
|
||||
|
||||
proc `$`*[T](L: DoublyLinkedList[T]): string =
|
||||
## turns a list into its string representation.
|
||||
dollarImpl()
|
||||
|
||||
proc `$`*[T](L: SinglyLinkedRing[T]): string =
|
||||
## turns a list into its string representation.
|
||||
dollarImpl()
|
||||
|
||||
proc `$`*[T](L: DoublyLinkedRing[T]): string =
|
||||
## turns a list into its string representation.
|
||||
dollarImpl()
|
||||
|
||||
proc find*[T](L: SinglyLinkedList[T], value: T): SinglyLinkedNode[T] =
|
||||
proc find*[T](L: SomeLinkedCollection[T], value: T): SomeLinkedNode[T] =
|
||||
## searches in the list for a value. Returns nil if the value does not
|
||||
## exist.
|
||||
findImpl()
|
||||
for x in nodes(L):
|
||||
if x.value == value: return x
|
||||
|
||||
proc find*[T](L: DoublyLinkedList[T], value: T): DoublyLinkedNode[T] =
|
||||
## searches in the list for a value. Returns nil if the value does not
|
||||
## exist.
|
||||
findImpl()
|
||||
|
||||
proc find*[T](L: SinglyLinkedRing[T], value: T): SinglyLinkedNode[T] =
|
||||
## searches in the list for a value. Returns nil if the value does not
|
||||
## exist.
|
||||
findImpl()
|
||||
|
||||
proc find*[T](L: DoublyLinkedRing[T], value: T): DoublyLinkedNode[T] =
|
||||
## searches in the list for a value. Returns nil if the value does not
|
||||
## exist.
|
||||
findImpl()
|
||||
|
||||
proc contains*[T](L: SinglyLinkedList[T], value: T): bool {.inline.} =
|
||||
## searches in the list for a value. Returns false if the value does not
|
||||
## exist, true otherwise.
|
||||
result = find(L, value) != nil
|
||||
|
||||
proc contains*[T](L: DoublyLinkedList[T], value: T): bool {.inline.} =
|
||||
## searches in the list for a value. Returns false if the value does not
|
||||
## exist, true otherwise.
|
||||
result = find(L, value) != nil
|
||||
|
||||
proc contains*[T](L: SinglyLinkedRing[T], value: T): bool {.inline.} =
|
||||
## searches in the list for a value. Returns false if the value does not
|
||||
## exist, true otherwise.
|
||||
result = find(L, value) != nil
|
||||
|
||||
proc contains*[T](L: DoublyLinkedRing[T], value: T): bool {.inline.} =
|
||||
proc contains*[T](L: SomeLinkedCollection[T], value: T): bool {.inline.} =
|
||||
## searches in the list for a value. Returns false if the value does not
|
||||
## exist, true otherwise.
|
||||
result = find(L, value) != nil
|
||||
|
|
@ -266,7 +194,6 @@ proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
|
|||
if n.next != nil: n.next.prev = n.prev
|
||||
if n.prev != nil: n.prev.next = n.next
|
||||
|
||||
|
||||
proc append*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) =
|
||||
## appends a node `n` to `L`. Efficiency: O(1).
|
||||
if L.head != nil:
|
||||
|
|
|
|||
|
|
@ -198,9 +198,8 @@ when isMainModule:
|
|||
assert($q == "[4, 56, 6, 789]")
|
||||
|
||||
assert q[0] == q.front and q.front == 4
|
||||
assert q[^1] == q.back and q.back == 789
|
||||
q[0] = 42
|
||||
q[^1] = 7
|
||||
q[q.len - 1] = 7
|
||||
|
||||
assert 6 in q and 789 notin q
|
||||
assert q.find(6) >= 0
|
||||
|
|
|
|||
|
|
@ -13,8 +13,9 @@
|
|||
## were inspired by functional programming languages.
|
||||
##
|
||||
## For functional style programming you may want to pass `anonymous procs
|
||||
## <manual.html#anonymous-procs>`_ to procs like ``filter`` to reduce typing.
|
||||
## Anonymous procs can use `the special do notation <manual.html#do-notation>`_
|
||||
## <manual.html#procedures-anonymous-procs>`_ to procs like ``filter`` to
|
||||
## reduce typing. Anonymous procs can use `the special do notation
|
||||
## <manual.html#procedures-do-notation>`_
|
||||
## which is more convenient in certain situations.
|
||||
|
||||
include "system/inclrtl"
|
||||
|
|
@ -43,8 +44,23 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
|
|||
result[i] = itm
|
||||
inc(i)
|
||||
|
||||
proc cycle*[T](s: seq[T], n: Natural): seq[T] =
|
||||
## Returns a new sequence with the items of `s` repeated `n` times.
|
||||
proc count*[T](s: openArray[T], x: T): int =
|
||||
## Returns the number of occurrences of the item `x` in the container `s`.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block::
|
||||
## let
|
||||
## s = @[1, 2, 2, 3, 2, 4, 2]
|
||||
## c = count(s, 2)
|
||||
## assert c == 4
|
||||
for itm in items(s):
|
||||
if itm == x:
|
||||
inc result
|
||||
|
||||
proc cycle*[T](s: openArray[T], n: Natural): seq[T] =
|
||||
## Returns a new sequence with the items of the container `s` repeated
|
||||
## `n` times.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
|
|
@ -56,7 +72,7 @@ proc cycle*[T](s: seq[T], n: Natural): seq[T] =
|
|||
## assert total == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
|
||||
result = newSeq[T](n * s.len)
|
||||
var o = 0
|
||||
for x in 0..<n:
|
||||
for x in 0 ..< n:
|
||||
for e in s:
|
||||
result[o] = e
|
||||
inc o
|
||||
|
|
@ -72,12 +88,14 @@ proc repeat*[T](x: T, n: Natural): seq[T] =
|
|||
## total = repeat(5, 3)
|
||||
## assert total == @[5, 5, 5]
|
||||
result = newSeq[T](n)
|
||||
for i in 0..<n:
|
||||
for i in 0 ..< n:
|
||||
result[i] = x
|
||||
|
||||
proc deduplicate*[T](seq1: seq[T]): seq[T] =
|
||||
proc deduplicate*[T](s: openArray[T]): seq[T] =
|
||||
## Returns a new sequence without duplicates.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block::
|
||||
## let
|
||||
## dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
|
||||
|
|
@ -87,17 +105,19 @@ proc deduplicate*[T](seq1: seq[T]): seq[T] =
|
|||
## assert unique1 == @[1, 3, 4, 2, 8]
|
||||
## assert unique2 == @["a", "c", "d"]
|
||||
result = @[]
|
||||
for itm in items(seq1):
|
||||
for itm in items(s):
|
||||
if not result.contains(itm): result.add(itm)
|
||||
|
||||
{.deprecated: [distnct: deduplicate].}
|
||||
|
||||
proc zip*[S, T](seq1: seq[S], seq2: seq[T]): seq[tuple[a: S, b: T]] =
|
||||
## Returns a new sequence with a combination of the two input sequences.
|
||||
proc zip*[S, T](s1: openArray[S], s2: openArray[T]): seq[tuple[a: S, b: T]] =
|
||||
## Returns a new sequence with a combination of the two input containers.
|
||||
##
|
||||
## For convenience you can access the returned tuples through the named
|
||||
## fields `a` and `b`. If one sequence is shorter, the remaining items in the
|
||||
## longer sequence are discarded. Example:
|
||||
## fields `a` and `b`. If one container is shorter, the remaining items in
|
||||
## the longer container are discarded.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block::
|
||||
## let
|
||||
|
|
@ -110,15 +130,16 @@ proc zip*[S, T](seq1: seq[S], seq2: seq[T]): seq[tuple[a: S, b: T]] =
|
|||
## assert zip2 == @[(1, "one"), (2, "two"), (3, "three")]
|
||||
## assert zip1[2].b == 4
|
||||
## assert zip2[2].b == "three"
|
||||
var m = min(seq1.len, seq2.len)
|
||||
var m = min(s1.len, s2.len)
|
||||
newSeq(result, m)
|
||||
for i in 0 .. m-1: result[i] = (seq1[i], seq2[i])
|
||||
for i in 0 ..< m:
|
||||
result[i] = (s1[i], s2[i])
|
||||
|
||||
proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
|
||||
## Splits and distributes a sequence `s` into `num` sub sequences.
|
||||
##
|
||||
## Returns a sequence of `num` sequences. For some input values this is the
|
||||
## inverse of the `concat <#concat>`_ proc. The proc will assert in debug
|
||||
## inverse of the `concat <#concat>`_ proc. The proc will assert in debug
|
||||
## builds if `s` is nil or `num` is less than one, and will likely crash on
|
||||
## release builds. The input sequence `s` can be empty, which will produce
|
||||
## `num` empty sequences.
|
||||
|
|
@ -159,48 +180,52 @@ proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
|
|||
# Use an algorithm which overcounts the stride and minimizes reading limits.
|
||||
if extra > 0: inc(stride)
|
||||
|
||||
for i in 0 .. <num:
|
||||
for i in 0 ..< num:
|
||||
result[i] = newSeq[T]()
|
||||
for g in first .. <min(s.len, first + stride):
|
||||
for g in first ..< min(s.len, first + stride):
|
||||
result[i].add(s[g])
|
||||
first += stride
|
||||
|
||||
else:
|
||||
# Use an undercounting algorithm which *adds* the remainder each iteration.
|
||||
for i in 0 .. <num:
|
||||
for i in 0 ..< num:
|
||||
last = first + stride
|
||||
if extra > 0:
|
||||
extra -= 1
|
||||
inc(last)
|
||||
|
||||
result[i] = newSeq[T]()
|
||||
for g in first .. <last:
|
||||
for g in first ..< last:
|
||||
result[i].add(s[g])
|
||||
first = last
|
||||
|
||||
|
||||
proc map*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}):
|
||||
proc map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}):
|
||||
seq[S]{.inline.} =
|
||||
## Returns a new sequence with the results of `op` applied to every item in
|
||||
## `data`.
|
||||
## the container `s`.
|
||||
##
|
||||
## Since the input is not modified you can use this version of ``map`` to
|
||||
## transform the type of the elements in the input sequence. Example:
|
||||
## transform the type of the elements in the input container.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## let
|
||||
## a = @[1, 2, 3, 4]
|
||||
## b = map(a, proc(x: int): string = $x)
|
||||
## assert b == @["1", "2", "3", "4"]
|
||||
newSeq(result, data.len)
|
||||
for i in 0..data.len-1: result[i] = op(data[i])
|
||||
newSeq(result, s.len)
|
||||
for i in 0 ..< s.len:
|
||||
result[i] = op(s[i])
|
||||
|
||||
proc map*[T](data: var openArray[T], op: proc (x: var T) {.closure.})
|
||||
proc map*[T](s: var openArray[T], op: proc (x: var T) {.closure.})
|
||||
{.deprecated.} =
|
||||
## Applies `op` to every item in `data` modifying it directly.
|
||||
## Applies `op` to every item in `s` modifying it directly.
|
||||
##
|
||||
## Note that this version of ``map`` requires your input and output types to
|
||||
## be the same, since they are modified in-place. Example:
|
||||
## be the same, since they are modified in-place.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## var a = @["1", "2", "3", "4"]
|
||||
|
|
@ -210,15 +235,16 @@ proc map*[T](data: var openArray[T], op: proc (x: var T) {.closure.})
|
|||
## echo repr(a)
|
||||
## # --> ["142", "242", "342", "442"]
|
||||
## **Deprecated since version 0.12.0:** Use the ``apply`` proc instead.
|
||||
for i in 0..data.len-1: op(data[i])
|
||||
for i in 0 ..< s.len: op(s[i])
|
||||
|
||||
proc apply*[T](data: var seq[T], op: proc (x: var T) {.closure.})
|
||||
proc apply*[T](s: var openArray[T], op: proc (x: var T) {.closure.})
|
||||
{.inline.} =
|
||||
## Applies `op` to every item in `data` modifying it directly.
|
||||
## Applies `op` to every item in `s` modifying it directly.
|
||||
##
|
||||
## Note that this requires your input and output types to
|
||||
## be the same, since they are modified in-place.
|
||||
## The parameter function takes a ``var T`` type parameter.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
|
|
@ -229,15 +255,16 @@ proc apply*[T](data: var seq[T], op: proc (x: var T) {.closure.})
|
|||
## echo repr(a)
|
||||
## # --> ["142", "242", "342", "442"]
|
||||
##
|
||||
for i in 0..data.len-1: op(data[i])
|
||||
for i in 0 ..< s.len: op(s[i])
|
||||
|
||||
proc apply*[T](data: var seq[T], op: proc (x: T): T {.closure.})
|
||||
proc apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.})
|
||||
{.inline.} =
|
||||
## Applies `op` to every item in `data` modifying it directly.
|
||||
## Applies `op` to every item in `s` modifying it directly.
|
||||
##
|
||||
## Note that this requires your input and output types to
|
||||
## be the same, since they are modified in-place.
|
||||
## The parameter function takes and returns a ``T`` type variable.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
|
|
@ -248,11 +275,10 @@ proc apply*[T](data: var seq[T], op: proc (x: T): T {.closure.})
|
|||
## echo repr(a)
|
||||
## # --> ["142", "242", "342", "442"]
|
||||
##
|
||||
for i in 0..data.len-1: data[i] = op(data[i])
|
||||
for i in 0 ..< s.len: s[i] = op(s[i])
|
||||
|
||||
|
||||
iterator filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): T =
|
||||
## Iterates through a sequence and yields every item that fulfills the
|
||||
iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T =
|
||||
## Iterates through a container and yields every item that fulfills the
|
||||
## predicate.
|
||||
##
|
||||
## Example:
|
||||
|
|
@ -262,11 +288,11 @@ iterator filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): T =
|
|||
## for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
|
||||
## echo($n)
|
||||
## # echoes 4, 8, 4 in separate lines
|
||||
for i in 0..<seq1.len:
|
||||
if pred(seq1[i]):
|
||||
yield seq1[i]
|
||||
for i in 0 ..< s.len:
|
||||
if pred(s[i]):
|
||||
yield s[i]
|
||||
|
||||
proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T]
|
||||
proc filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T]
|
||||
{.inline.} =
|
||||
## Returns a new sequence with all the items that fulfilled the predicate.
|
||||
##
|
||||
|
|
@ -280,11 +306,11 @@ proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T]
|
|||
## assert f1 == @["red", "black"]
|
||||
## assert f2 == @["yellow"]
|
||||
result = newSeq[T]()
|
||||
for i in 0..<seq1.len:
|
||||
if pred(seq1[i]):
|
||||
result.add(seq1[i])
|
||||
for i in 0 ..< s.len:
|
||||
if pred(s[i]):
|
||||
result.add(s[i])
|
||||
|
||||
proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.})
|
||||
proc keepIf*[T](s: var seq[T], pred: proc(x: T): bool {.closure.})
|
||||
{.inline.} =
|
||||
## Keeps the items in the passed sequence if they fulfilled the predicate.
|
||||
## Same as the ``filter`` proc, but modifies the sequence directly.
|
||||
|
|
@ -296,12 +322,12 @@ proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.})
|
|||
## keepIf(floats, proc(x: float): bool = x > 10)
|
||||
## assert floats == @[13.0, 12.5, 10.1]
|
||||
var pos = 0
|
||||
for i in 0 .. <len(seq1):
|
||||
if pred(seq1[i]):
|
||||
for i in 0 ..< len(s):
|
||||
if pred(s[i]):
|
||||
if pos != i:
|
||||
shallowCopy(seq1[pos], seq1[i])
|
||||
shallowCopy(s[pos], s[i])
|
||||
inc(pos)
|
||||
setLen(seq1, pos)
|
||||
setLen(s, pos)
|
||||
|
||||
proc delete*[T](s: var seq[T]; first, last: Natural) =
|
||||
## Deletes in `s` the items at position `first` .. `last`. This modifies
|
||||
|
|
@ -354,11 +380,12 @@ proc insert*[T](dest: var seq[T], src: openArray[T], pos=0) =
|
|||
inc(j)
|
||||
|
||||
|
||||
template filterIt*(seq1, pred: untyped): untyped =
|
||||
template filterIt*(s, pred: untyped): untyped =
|
||||
## Returns a new sequence with all the items that fulfilled the predicate.
|
||||
##
|
||||
## Unlike the `proc` version, the predicate needs to be an expression using
|
||||
## the ``it`` variable for testing, like: ``filterIt("abcxyz", it == 'x')``.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block::
|
||||
|
|
@ -368,8 +395,8 @@ template filterIt*(seq1, pred: untyped): untyped =
|
|||
## notAcceptable = filterIt(temperatures, it > 50 or it < -10)
|
||||
## assert acceptable == @[-2.0, 24.5, 44.31]
|
||||
## assert notAcceptable == @[-272.15, 99.9, -113.44]
|
||||
var result = newSeq[type(seq1[0])]()
|
||||
for it {.inject.} in items(seq1):
|
||||
var result = newSeq[type(s[0])]()
|
||||
for it {.inject.} in items(s):
|
||||
if pred: result.add(it)
|
||||
result
|
||||
|
||||
|
|
@ -378,6 +405,7 @@ template keepItIf*(varSeq: seq, pred: untyped) =
|
|||
##
|
||||
## Unlike the `proc` version, the predicate needs to be an expression using
|
||||
## the ``it`` variable for testing, like: ``keepItIf("abcxyz", it == 'x')``.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block::
|
||||
|
|
@ -385,7 +413,7 @@ template keepItIf*(varSeq: seq, pred: untyped) =
|
|||
## keepItIf(candidates, it.len == 3 and it[0] == 'b')
|
||||
## assert candidates == @["bar", "baz"]
|
||||
var pos = 0
|
||||
for i in 0 .. <len(varSeq):
|
||||
for i in 0 ..< len(varSeq):
|
||||
let it {.inject.} = varSeq[i]
|
||||
if pred:
|
||||
if pos != i:
|
||||
|
|
@ -393,8 +421,8 @@ template keepItIf*(varSeq: seq, pred: untyped) =
|
|||
inc(pos)
|
||||
setLen(varSeq, pos)
|
||||
|
||||
proc all*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): bool =
|
||||
## Iterates through a sequence and checks if every item fulfills the
|
||||
proc all*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool =
|
||||
## Iterates through a container and checks if every item fulfills the
|
||||
## predicate.
|
||||
##
|
||||
## Example:
|
||||
|
|
@ -403,12 +431,12 @@ proc all*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): bool =
|
|||
## let numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||
## assert all(numbers, proc (x: int): bool = return x < 10) == true
|
||||
## assert all(numbers, proc (x: int): bool = return x < 9) == false
|
||||
for i in seq1:
|
||||
for i in s:
|
||||
if not pred(i):
|
||||
return false
|
||||
return true
|
||||
|
||||
template allIt*(seq1, pred: untyped): bool =
|
||||
template allIt*(s, pred: untyped): bool =
|
||||
## Checks if every item fulfills the predicate.
|
||||
##
|
||||
## Example:
|
||||
|
|
@ -418,14 +446,14 @@ template allIt*(seq1, pred: untyped): bool =
|
|||
## assert allIt(numbers, it < 10) == true
|
||||
## assert allIt(numbers, it < 9) == false
|
||||
var result = true
|
||||
for it {.inject.} in items(seq1):
|
||||
for it {.inject.} in items(s):
|
||||
if not pred:
|
||||
result = false
|
||||
break
|
||||
result
|
||||
|
||||
proc any*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): bool =
|
||||
## Iterates through a sequence and checks if some item fulfills the
|
||||
proc any*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool =
|
||||
## Iterates through a container and checks if some item fulfills the
|
||||
## predicate.
|
||||
##
|
||||
## Example:
|
||||
|
|
@ -434,12 +462,12 @@ proc any*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): bool =
|
|||
## let numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||
## assert any(numbers, proc (x: int): bool = return x > 8) == true
|
||||
## assert any(numbers, proc (x: int): bool = return x > 9) == false
|
||||
for i in seq1:
|
||||
for i in s:
|
||||
if pred(i):
|
||||
return true
|
||||
return false
|
||||
|
||||
template anyIt*(seq1, pred: untyped): bool =
|
||||
template anyIt*(s, pred: untyped): bool =
|
||||
## Checks if some item fulfills the predicate.
|
||||
##
|
||||
## Example:
|
||||
|
|
@ -449,7 +477,7 @@ template anyIt*(seq1, pred: untyped): bool =
|
|||
## assert anyIt(numbers, it > 8) == true
|
||||
## assert anyIt(numbers, it > 9) == false
|
||||
var result = false
|
||||
for it {.inject.} in items(seq1):
|
||||
for it {.inject.} in items(s):
|
||||
if pred:
|
||||
result = true
|
||||
break
|
||||
|
|
@ -493,7 +521,9 @@ template foldl*(sequence, operation: untyped): untyped =
|
|||
## variables ``a`` and ``b`` for each step of the fold. Since this is a left
|
||||
## fold, for non associative binary operations like subtraction think that
|
||||
## the sequence of numbers 1, 2 and 3 will be parenthesized as (((1) - 2) -
|
||||
## 3). Example:
|
||||
## 3).
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block::
|
||||
## let
|
||||
|
|
@ -527,6 +557,7 @@ template foldl*(sequence, operation, first): untyped =
|
|||
## The ``operation`` parameter should be an expression which uses the variables
|
||||
## ``a`` and ``b`` for each step of the fold. The ``first`` parameter is the
|
||||
## start value (the first ``a``) and therefor defines the type of the result.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block::
|
||||
|
|
@ -555,7 +586,9 @@ template foldr*(sequence, operation: untyped): untyped =
|
|||
## variables ``a`` and ``b`` for each step of the fold. Since this is a right
|
||||
## fold, for non associative binary operations like subtraction think that
|
||||
## the sequence of numbers 1, 2 and 3 will be parenthesized as (1 - (2 -
|
||||
## (3))). Example:
|
||||
## (3))).
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block::
|
||||
## let
|
||||
|
|
@ -580,13 +613,15 @@ template foldr*(sequence, operation: untyped): untyped =
|
|||
result = operation
|
||||
result
|
||||
|
||||
template mapIt*(seq1, typ, op: untyped): untyped =
|
||||
template mapIt*(s, typ, op: untyped): untyped =
|
||||
## Convenience template around the ``map`` proc to reduce typing.
|
||||
##
|
||||
## The template injects the ``it`` variable which you can use directly in an
|
||||
## expression. You also need to pass as `typ` the type of the expression,
|
||||
## since the new returned sequence can have a different type than the
|
||||
## original. Example:
|
||||
## original.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block::
|
||||
## let
|
||||
|
|
@ -596,16 +631,18 @@ template mapIt*(seq1, typ, op: untyped): untyped =
|
|||
## **Deprecated since version 0.12.0:** Use the ``mapIt(seq1, op)``
|
||||
## template instead.
|
||||
var result: seq[typ] = @[]
|
||||
for it {.inject.} in items(seq1):
|
||||
for it {.inject.} in items(s):
|
||||
result.add(op)
|
||||
result
|
||||
|
||||
|
||||
template mapIt*(seq1, op: untyped): untyped =
|
||||
template mapIt*(s, op: untyped): untyped =
|
||||
## Convenience template around the ``map`` proc to reduce typing.
|
||||
##
|
||||
## The template injects the ``it`` variable which you can use directly in an
|
||||
## expression. Example:
|
||||
## expression.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block::
|
||||
## let
|
||||
|
|
@ -614,19 +651,19 @@ template mapIt*(seq1, op: untyped): untyped =
|
|||
## assert strings == @["4", "8", "12", "16"]
|
||||
type outType = type((
|
||||
block:
|
||||
var it{.inject.}: type(items(seq1));
|
||||
var it{.inject.}: type(items(s));
|
||||
op))
|
||||
var result: seq[outType]
|
||||
when compiles(seq1.len):
|
||||
let s = seq1
|
||||
when compiles(s.len):
|
||||
let t = s
|
||||
var i = 0
|
||||
result = newSeq[outType](s.len)
|
||||
for it {.inject.} in s:
|
||||
for it {.inject.} in t:
|
||||
result[i] = op
|
||||
i += 1
|
||||
else:
|
||||
result = @[]
|
||||
for it {.inject.} in seq1:
|
||||
for it {.inject.} in s:
|
||||
result.add(op)
|
||||
result
|
||||
|
||||
|
|
@ -635,20 +672,23 @@ template applyIt*(varSeq, op: untyped) =
|
|||
##
|
||||
## The template injects the ``it`` variable which you can use directly in an
|
||||
## expression. The expression has to return the same type as the sequence you
|
||||
## are mutating. Example:
|
||||
## are mutating.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block::
|
||||
## var nums = @[1, 2, 3, 4]
|
||||
## nums.applyIt(it * 3)
|
||||
## assert nums[0] + nums[3] == 15
|
||||
for i in 0 .. <varSeq.len:
|
||||
for i in 0 ..< varSeq.len:
|
||||
let it {.inject.} = varSeq[i]
|
||||
varSeq[i] = op
|
||||
|
||||
|
||||
|
||||
template newSeqWith*(len: int, init: untyped): untyped =
|
||||
## creates a new sequence, calling `init` to initialize each value. Example:
|
||||
## creates a new sequence, calling `init` to initialize each value.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block::
|
||||
## var seq2D = newSeqWith(20, newSeq[bool](10))
|
||||
|
|
@ -660,7 +700,7 @@ template newSeqWith*(len: int, init: untyped): untyped =
|
|||
## var seqRand = newSeqWith(20, random(10))
|
||||
## echo seqRand
|
||||
var result = newSeq[type(init)](len)
|
||||
for i in 0 .. <len:
|
||||
for i in 0 ..< len:
|
||||
result[i] = init
|
||||
result
|
||||
|
||||
|
|
@ -674,45 +714,178 @@ when isMainModule:
|
|||
total = concat(s1, s2, s3)
|
||||
assert total == @[1, 2, 3, 4, 5, 6, 7]
|
||||
|
||||
block: # duplicates test
|
||||
block: # count test
|
||||
let
|
||||
s1 = @[1, 2, 3, 2]
|
||||
s2 = @['a', 'b', 'x', 'a']
|
||||
a1 = [1, 2, 3, 2]
|
||||
a2 = ['a', 'b', 'x', 'a']
|
||||
r0 = count(s1, 0)
|
||||
r1 = count(s1, 1)
|
||||
r2 = count(s1, 2)
|
||||
r3 = count(s2, 'y')
|
||||
r4 = count(s2, 'x')
|
||||
r5 = count(s2, 'a')
|
||||
ar0 = count(a1, 0)
|
||||
ar1 = count(a1, 1)
|
||||
ar2 = count(a1, 2)
|
||||
ar3 = count(a2, 'y')
|
||||
ar4 = count(a2, 'x')
|
||||
ar5 = count(a2, 'a')
|
||||
assert r0 == 0
|
||||
assert r1 == 1
|
||||
assert r2 == 2
|
||||
assert r3 == 0
|
||||
assert r4 == 1
|
||||
assert r5 == 2
|
||||
assert ar0 == 0
|
||||
assert ar1 == 1
|
||||
assert ar2 == 2
|
||||
assert ar3 == 0
|
||||
assert ar4 == 1
|
||||
assert ar5 == 2
|
||||
|
||||
block: # cycle tests
|
||||
let
|
||||
a = @[1, 2, 3]
|
||||
b: seq[int] = @[]
|
||||
c = [1, 2, 3]
|
||||
|
||||
doAssert a.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
|
||||
doAssert a.cycle(0) == @[]
|
||||
#doAssert a.cycle(-1) == @[] # will not compile!
|
||||
doAssert b.cycle(3) == @[]
|
||||
doAssert c.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
|
||||
doAssert c.cycle(0) == @[]
|
||||
|
||||
block: # repeat tests
|
||||
assert repeat(10, 5) == @[10, 10, 10, 10, 10]
|
||||
assert repeat(@[1,2,3], 2) == @[@[1,2,3], @[1,2,3]]
|
||||
assert repeat([1,2,3], 2) == @[[1,2,3], [1,2,3]]
|
||||
|
||||
block: # deduplicates test
|
||||
let
|
||||
dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
|
||||
dup2 = @["a", "a", "c", "d", "d"]
|
||||
dup3 = [1, 1, 3, 4, 2, 2, 8, 1, 4]
|
||||
dup4 = ["a", "a", "c", "d", "d"]
|
||||
unique1 = deduplicate(dup1)
|
||||
unique2 = deduplicate(dup2)
|
||||
unique3 = deduplicate(dup3)
|
||||
unique4 = deduplicate(dup4)
|
||||
assert unique1 == @[1, 3, 4, 2, 8]
|
||||
assert unique2 == @["a", "c", "d"]
|
||||
assert unique3 == @[1, 3, 4, 2, 8]
|
||||
assert unique4 == @["a", "c", "d"]
|
||||
|
||||
block: # zip test
|
||||
let
|
||||
short = @[1, 2, 3]
|
||||
long = @[6, 5, 4, 3, 2, 1]
|
||||
words = @["one", "two", "three"]
|
||||
ashort = [1, 2, 3]
|
||||
along = [6, 5, 4, 3, 2, 1]
|
||||
awords = ["one", "two", "three"]
|
||||
zip1 = zip(short, long)
|
||||
zip2 = zip(short, words)
|
||||
zip3 = zip(ashort, along)
|
||||
zip4 = zip(ashort, awords)
|
||||
zip5 = zip(ashort, words)
|
||||
assert zip1 == @[(1, 6), (2, 5), (3, 4)]
|
||||
assert zip2 == @[(1, "one"), (2, "two"), (3, "three")]
|
||||
assert zip3 == @[(1, 6), (2, 5), (3, 4)]
|
||||
assert zip4 == @[(1, "one"), (2, "two"), (3, "three")]
|
||||
assert zip5 == @[(1, "one"), (2, "two"), (3, "three")]
|
||||
assert zip1[2].b == 4
|
||||
assert zip2[2].b == "three"
|
||||
assert zip3[2].b == 4
|
||||
assert zip4[2].b == "three"
|
||||
assert zip5[2].b == "three"
|
||||
|
||||
block: # distribute tests
|
||||
let numbers = @[1, 2, 3, 4, 5, 6, 7]
|
||||
doAssert numbers.distribute(3) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
|
||||
doAssert numbers.distribute(6)[0] == @[1, 2]
|
||||
doAssert numbers.distribute(6)[5] == @[7]
|
||||
let a = @[1, 2, 3, 4, 5, 6, 7]
|
||||
doAssert a.distribute(1, true) == @[@[1, 2, 3, 4, 5, 6, 7]]
|
||||
doAssert a.distribute(1, false) == @[@[1, 2, 3, 4, 5, 6, 7]]
|
||||
doAssert a.distribute(2, true) == @[@[1, 2, 3, 4], @[5, 6, 7]]
|
||||
doAssert a.distribute(2, false) == @[@[1, 2, 3, 4], @[5, 6, 7]]
|
||||
doAssert a.distribute(3, true) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
|
||||
doAssert a.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]]
|
||||
doAssert a.distribute(4, true) == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
|
||||
doAssert a.distribute(4, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
|
||||
doAssert a.distribute(5, true) == @[@[1, 2], @[3, 4], @[5], @[6], @[7]]
|
||||
doAssert a.distribute(5, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7], @[]]
|
||||
doAssert a.distribute(6, true) == @[@[1, 2], @[3], @[4], @[5], @[6], @[7]]
|
||||
doAssert a.distribute(6, false) == @[
|
||||
@[1, 2], @[3, 4], @[5, 6], @[7], @[], @[]]
|
||||
doAssert a.distribute(8, false) == a.distribute(8, true)
|
||||
doAssert a.distribute(90, false) == a.distribute(90, true)
|
||||
var b = @[0]
|
||||
for f in 1 .. 25: b.add(f)
|
||||
doAssert b.distribute(5, true)[4].len == 5
|
||||
doAssert b.distribute(5, false)[4].len == 2
|
||||
|
||||
block: # map test
|
||||
let
|
||||
numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||
anumbers = [1, 4, 5, 8, 9, 7, 4]
|
||||
m1 = map(numbers, proc(x: int): int = 2*x)
|
||||
m2 = map(anumbers, proc(x: int): int = 2*x)
|
||||
assert m1 == @[2, 8, 10, 16, 18, 14, 8]
|
||||
assert m2 == @[2, 8, 10, 16, 18, 14, 8]
|
||||
|
||||
block: # apply test
|
||||
var a = @["1", "2", "3", "4"]
|
||||
apply(a, proc(x: var string) = x &= "42")
|
||||
assert a == @["142", "242", "342", "442"]
|
||||
|
||||
block: # filter proc test
|
||||
let
|
||||
colors = @["red", "yellow", "black"]
|
||||
acolors = ["red", "yellow", "black"]
|
||||
f1 = filter(colors, proc(x: string): bool = x.len < 6)
|
||||
f2 = filter(colors) do (x: string) -> bool : x.len > 5
|
||||
f3 = filter(acolors, proc(x: string): bool = x.len < 6)
|
||||
f4 = filter(acolors) do (x: string) -> bool : x.len > 5
|
||||
assert f1 == @["red", "black"]
|
||||
assert f2 == @["yellow"]
|
||||
assert f3 == @["red", "black"]
|
||||
assert f4 == @["yellow"]
|
||||
|
||||
block: # filter iterator test
|
||||
let numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||
let anumbers = [1, 4, 5, 8, 9, 7, 4]
|
||||
assert toSeq(filter(numbers, proc (x: int): bool = x mod 2 == 0)) ==
|
||||
@[4, 8, 4]
|
||||
assert toSeq(filter(anumbers, proc (x: int): bool = x mod 2 == 0)) ==
|
||||
@[4, 8, 4]
|
||||
|
||||
block: # keepIf test
|
||||
var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
|
||||
keepIf(floats, proc(x: float): bool = x > 10)
|
||||
assert floats == @[13.0, 12.5, 10.1]
|
||||
|
||||
block: # delete tests
|
||||
let outcome = @[1,1,1,1,1,1,1,1]
|
||||
var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
|
||||
dest.delete(3, 8)
|
||||
assert outcome == dest, """\
|
||||
Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1]
|
||||
is [1,1,1,1,1,1,1,1]"""
|
||||
|
||||
block: # insert tests
|
||||
var dest = @[1,1,1,1,1,1,1,1]
|
||||
let
|
||||
src = @[2,2,2,2,2,2]
|
||||
outcome = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
|
||||
dest.insert(src, 3)
|
||||
assert dest == outcome, """\
|
||||
Inserting [2,2,2,2,2,2] into [1,1,1,1,1,1,1,1]
|
||||
at 3 is [1,1,1,2,2,2,2,2,2,1,1,1,1,1]"""
|
||||
|
||||
block: # filterIt test
|
||||
let
|
||||
temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44]
|
||||
|
|
@ -726,37 +899,49 @@ when isMainModule:
|
|||
keepItIf(candidates, it.len == 3 and it[0] == 'b')
|
||||
assert candidates == @["bar", "baz"]
|
||||
|
||||
block: # any
|
||||
let
|
||||
numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||
len0seq : seq[int] = @[]
|
||||
assert any(numbers, proc (x: int): bool = return x > 8) == true
|
||||
assert any(numbers, proc (x: int): bool = return x > 9) == false
|
||||
assert any(len0seq, proc (x: int): bool = return true) == false
|
||||
|
||||
block: # anyIt
|
||||
let
|
||||
numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||
len0seq : seq[int] = @[]
|
||||
assert anyIt(numbers, it > 8) == true
|
||||
assert anyIt(numbers, it > 9) == false
|
||||
assert anyIt(len0seq, true) == false
|
||||
|
||||
block: # all
|
||||
let
|
||||
numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||
anumbers = [1, 4, 5, 8, 9, 7, 4]
|
||||
len0seq : seq[int] = @[]
|
||||
assert all(numbers, proc (x: int): bool = return x < 10) == true
|
||||
assert all(numbers, proc (x: int): bool = return x < 9) == false
|
||||
assert all(len0seq, proc (x: int): bool = return false) == true
|
||||
assert all(anumbers, proc (x: int): bool = return x < 10) == true
|
||||
assert all(anumbers, proc (x: int): bool = return x < 9) == false
|
||||
|
||||
block: # allIt
|
||||
let
|
||||
numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||
anumbers = [1, 4, 5, 8, 9, 7, 4]
|
||||
len0seq : seq[int] = @[]
|
||||
assert allIt(numbers, it < 10) == true
|
||||
assert allIt(numbers, it < 9) == false
|
||||
assert allIt(len0seq, false) == true
|
||||
assert allIt(anumbers, it < 10) == true
|
||||
assert allIt(anumbers, it < 9) == false
|
||||
|
||||
block: # any
|
||||
let
|
||||
numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||
anumbers = [1, 4, 5, 8, 9, 7, 4]
|
||||
len0seq : seq[int] = @[]
|
||||
assert any(numbers, proc (x: int): bool = return x > 8) == true
|
||||
assert any(numbers, proc (x: int): bool = return x > 9) == false
|
||||
assert any(len0seq, proc (x: int): bool = return true) == false
|
||||
assert any(anumbers, proc (x: int): bool = return x > 8) == true
|
||||
assert any(anumbers, proc (x: int): bool = return x > 9) == false
|
||||
|
||||
block: # anyIt
|
||||
let
|
||||
numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||
anumbers = [1, 4, 5, 8, 9, 7, 4]
|
||||
len0seq : seq[int] = @[]
|
||||
assert anyIt(numbers, it > 8) == true
|
||||
assert anyIt(numbers, it > 9) == false
|
||||
assert anyIt(len0seq, true) == false
|
||||
assert anyIt(anumbers, it > 8) == true
|
||||
assert anyIt(anumbers, it > 9) == false
|
||||
|
||||
block: # toSeq test
|
||||
let
|
||||
|
|
@ -792,56 +977,13 @@ when isMainModule:
|
|||
assert multiplication == 495, "Multiplication is (5*(9*(11)))"
|
||||
assert concatenation == "nimiscool"
|
||||
|
||||
block: # delete tests
|
||||
let outcome = @[1,1,1,1,1,1,1,1]
|
||||
var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
|
||||
dest.delete(3, 8)
|
||||
assert outcome == dest, """\
|
||||
Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1]
|
||||
is [1,1,1,1,1,1,1,1]"""
|
||||
|
||||
block: # insert tests
|
||||
var dest = @[1,1,1,1,1,1,1,1]
|
||||
let
|
||||
src = @[2,2,2,2,2,2]
|
||||
outcome = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
|
||||
dest.insert(src, 3)
|
||||
assert dest == outcome, """\
|
||||
Inserting [2,2,2,2,2,2] into [1,1,1,1,1,1,1,1]
|
||||
at 3 is [1,1,1,2,2,2,2,2,2,1,1,1,1,1]"""
|
||||
|
||||
block: # mapIt tests
|
||||
var
|
||||
nums = @[1, 2, 3, 4]
|
||||
strings = nums.mapIt($(4 * it))
|
||||
nums.applyIt(it * 3)
|
||||
assert nums[0] + nums[3] == 15
|
||||
|
||||
block: # distribute tests
|
||||
let numbers = @[1, 2, 3, 4, 5, 6, 7]
|
||||
doAssert numbers.distribute(3) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
|
||||
doAssert numbers.distribute(6)[0] == @[1, 2]
|
||||
doAssert numbers.distribute(6)[5] == @[7]
|
||||
let a = @[1, 2, 3, 4, 5, 6, 7]
|
||||
doAssert a.distribute(1, true) == @[@[1, 2, 3, 4, 5, 6, 7]]
|
||||
doAssert a.distribute(1, false) == @[@[1, 2, 3, 4, 5, 6, 7]]
|
||||
doAssert a.distribute(2, true) == @[@[1, 2, 3, 4], @[5, 6, 7]]
|
||||
doAssert a.distribute(2, false) == @[@[1, 2, 3, 4], @[5, 6, 7]]
|
||||
doAssert a.distribute(3, true) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
|
||||
doAssert a.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]]
|
||||
doAssert a.distribute(4, true) == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
|
||||
doAssert a.distribute(4, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
|
||||
doAssert a.distribute(5, true) == @[@[1, 2], @[3, 4], @[5], @[6], @[7]]
|
||||
doAssert a.distribute(5, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7], @[]]
|
||||
doAssert a.distribute(6, true) == @[@[1, 2], @[3], @[4], @[5], @[6], @[7]]
|
||||
doAssert a.distribute(6, false) == @[
|
||||
@[1, 2], @[3, 4], @[5, 6], @[7], @[], @[]]
|
||||
doAssert a.distribute(8, false) == a.distribute(8, true)
|
||||
doAssert a.distribute(90, false) == a.distribute(90, true)
|
||||
var b = @[0]
|
||||
for f in 1 .. 25: b.add(f)
|
||||
doAssert b.distribute(5, true)[4].len == 5
|
||||
doAssert b.distribute(5, false)[4].len == 2
|
||||
assert strings[2] == "12"
|
||||
|
||||
block: # newSeqWith tests
|
||||
var seq2D = newSeqWith(4, newSeq[bool](2))
|
||||
|
|
@ -850,19 +992,5 @@ when isMainModule:
|
|||
seq2D[0][1] = true
|
||||
doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
|
||||
|
||||
block: # cycle tests
|
||||
let
|
||||
a = @[1, 2, 3]
|
||||
b: seq[int] = @[]
|
||||
|
||||
doAssert a.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
|
||||
doAssert a.cycle(0) == @[]
|
||||
#doAssert a.cycle(-1) == @[] # will not compile!
|
||||
doAssert b.cycle(3) == @[]
|
||||
|
||||
block: # repeat tests
|
||||
assert repeat(10, 5) == @[10, 10, 10, 10, 10]
|
||||
assert repeat(@[1,2,3], 2) == @[@[1,2,3], @[1,2,3]]
|
||||
|
||||
when not defined(testing):
|
||||
echo "Finished doc tests"
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ proc `[]=`*(s: var SharedString; i: Natural; value: char) =
|
|||
if i < s.len: s.buffer.data[i+s.first] = value
|
||||
else: raise newException(IndexError, "index out of bounds")
|
||||
|
||||
proc `[]`*(s: SharedString; ab: Slice[int]): SharedString =
|
||||
proc `[]`*(s: SharedString; ab: HSlice[int, int]): SharedString =
|
||||
#incRef(src.buffer)
|
||||
if ab.a < s.len:
|
||||
result.buffer = s.buffer
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ template delImpl() {.dirty.} =
|
|||
delImplIdx(t, i)
|
||||
|
||||
template clearImpl() {.dirty.} =
|
||||
for i in 0 .. <t.data.len:
|
||||
for i in 0 ..< t.data.len:
|
||||
when compiles(t.data[i].hcode): # CountTable records don't contain a hcode
|
||||
t.data[i].hcode = 0
|
||||
t.data[i].key = default(type(t.data[i].key))
|
||||
|
|
|
|||
|
|
@ -45,8 +45,25 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
|
|||
## returns the numer of the processors/cores the machine has.
|
||||
## Returns 0 if it cannot be detected.
|
||||
when defined(windows):
|
||||
var x = getEnv("NUMBER_OF_PROCESSORS")
|
||||
if x.len > 0: result = parseInt(x.string)
|
||||
type
|
||||
SYSTEM_INFO {.final, pure.} = object
|
||||
u1: int32
|
||||
dwPageSize: int32
|
||||
lpMinimumApplicationAddress: pointer
|
||||
lpMaximumApplicationAddress: pointer
|
||||
dwActiveProcessorMask: ptr int32
|
||||
dwNumberOfProcessors: int32
|
||||
dwProcessorType: int32
|
||||
dwAllocationGranularity: int32
|
||||
wProcessorLevel: int16
|
||||
wProcessorRevision: int16
|
||||
|
||||
proc GetSystemInfo(lpSystemInfo: var SYSTEM_INFO) {.stdcall, dynlib: "kernel32", importc: "GetSystemInfo".}
|
||||
|
||||
var
|
||||
si: SYSTEM_INFO
|
||||
GetSystemInfo(si)
|
||||
result = si.dwNumberOfProcessors
|
||||
elif defined(macosx) or defined(bsd):
|
||||
var
|
||||
mib: array[0..3, cint]
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ proc selectWorker(w: ptr Worker; fn: WorkerProc; data: pointer): bool =
|
|||
proc cleanFlowVars(w: ptr Worker) =
|
||||
let q = addr(w.q)
|
||||
acquire(q.lock)
|
||||
for i in 0 .. <q.len:
|
||||
for i in 0 ..< q.len:
|
||||
GC_unref(cast[RootRef](q.data[i]))
|
||||
#echo "GC_unref"
|
||||
q.len = 0
|
||||
|
|
@ -401,7 +401,7 @@ proc setup() =
|
|||
gCpus = p
|
||||
currentPoolSize = min(p, MaxThreadPoolSize)
|
||||
readyWorker = addr(workersData[0])
|
||||
for i in 0.. <currentPoolSize: activateWorkerThread(i)
|
||||
for i in 0..<currentPoolSize: activateWorkerThread(i)
|
||||
|
||||
proc preferSpawn*(): bool =
|
||||
## Use this proc to determine quickly if a 'spawn' or a direct call is
|
||||
|
|
@ -446,14 +446,24 @@ proc nimSpawn3(fn: WorkerProc; data: pointer) {.compilerProc.} =
|
|||
# implementation of 'spawn' that is used by the code generator.
|
||||
while true:
|
||||
if selectWorker(readyWorker, fn, data): return
|
||||
for i in 0.. <currentPoolSize:
|
||||
for i in 0..<currentPoolSize:
|
||||
if selectWorker(addr(workersData[i]), fn, data): return
|
||||
|
||||
# determine what to do, but keep in mind this is expensive too:
|
||||
# state.calls < maxPoolSize: warmup phase
|
||||
# (state.calls and 127) == 0: periodic check
|
||||
if state.calls < maxPoolSize or (state.calls and 127) == 0:
|
||||
# ensure the call to 'advice' is atomic:
|
||||
if tryAcquire(stateLock):
|
||||
if currentPoolSize < minPoolSize:
|
||||
if not workersData[currentPoolSize].initialized:
|
||||
activateWorkerThread(currentPoolSize)
|
||||
let w = addr(workersData[currentPoolSize])
|
||||
atomicInc currentPoolSize
|
||||
if selectWorker(w, fn, data):
|
||||
release(stateLock)
|
||||
return
|
||||
|
||||
case advice(state)
|
||||
of doNothing: discard
|
||||
of doCreateThread:
|
||||
|
|
@ -533,7 +543,7 @@ proc sync*() =
|
|||
var toRelease = 0
|
||||
while true:
|
||||
var allReady = true
|
||||
for i in 0 .. <currentPoolSize:
|
||||
for i in 0 ..< currentPoolSize:
|
||||
if not allReady: break
|
||||
allReady = allReady and workersData[i].ready
|
||||
if allReady: break
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ proc createProcType(p, b: NimNode): NimNode {.compileTime.} =
|
|||
|
||||
case p.kind
|
||||
of nnkPar:
|
||||
for i in 0 .. <p.len:
|
||||
for i in 0 ..< p.len:
|
||||
let ident = p[i]
|
||||
var identDefs = newNimNode(nnkIdentDefs)
|
||||
case ident.kind
|
||||
|
|
@ -77,7 +77,7 @@ macro `=>`*(p, b: untyped): untyped =
|
|||
if c[0].kind == nnkIdent and c[0].ident == !"->":
|
||||
var procTy = createProcType(c[1], c[2])
|
||||
params[0] = procTy[0][0]
|
||||
for i in 1 .. <procTy[0].len:
|
||||
for i in 1 ..< procTy[0].len:
|
||||
params.add(procTy[0][i])
|
||||
else:
|
||||
error("Expected proc type (->) got (" & $c[0].ident & ").")
|
||||
|
|
@ -96,7 +96,7 @@ macro `=>`*(p, b: untyped): untyped =
|
|||
if p[0].kind == nnkIdent and p[0].ident == !"->":
|
||||
var procTy = createProcType(p[1], p[2])
|
||||
params[0] = procTy[0][0]
|
||||
for i in 1 .. <procTy[0].len:
|
||||
for i in 1 ..< procTy[0].len:
|
||||
params.add(procTy[0][i])
|
||||
else:
|
||||
error("Expected proc type (->) got (" & $p[0].ident & ").")
|
||||
|
|
|
|||
|
|
@ -883,7 +883,9 @@ proc recvFull(client: HttpClient | AsyncHttpClient, size: int, timeout: int,
|
|||
let data = client.socket.recv(sizeToRecv, timeout)
|
||||
else:
|
||||
let data = await client.socket.recv(sizeToRecv)
|
||||
if data == "": break # We've been disconnected.
|
||||
if data == "":
|
||||
client.close()
|
||||
break # We've been disconnected.
|
||||
|
||||
readLen.inc(data.len)
|
||||
if keep:
|
||||
|
|
@ -950,6 +952,7 @@ proc parseBody(client: HttpClient | AsyncHttpClient,
|
|||
if length > 0:
|
||||
let recvLen = await client.recvFull(length, client.timeout, true)
|
||||
if recvLen == 0:
|
||||
client.close()
|
||||
httpError("Got disconnected while trying to read body.")
|
||||
if recvLen != length:
|
||||
httpError("Received length doesn't match expected length. Wanted " &
|
||||
|
|
@ -962,13 +965,20 @@ proc parseBody(client: HttpClient | AsyncHttpClient,
|
|||
if headers.getOrDefault"Connection" == "close" or httpVersion == "1.0":
|
||||
while true:
|
||||
let recvLen = await client.recvFull(4000, client.timeout, true)
|
||||
if recvLen == 0: break
|
||||
if recvLen == 0:
|
||||
client.close()
|
||||
break
|
||||
|
||||
when client is AsyncHttpClient:
|
||||
client.bodyStream.complete()
|
||||
else:
|
||||
client.bodyStream.setPosition(0)
|
||||
|
||||
# If the server will close our connection, then no matter the method of
|
||||
# reading the body, we need to close our socket.
|
||||
if headers.getOrDefault"Connection" == "close":
|
||||
client.close()
|
||||
|
||||
proc parseResponse(client: HttpClient | AsyncHttpClient,
|
||||
getBody: bool): Future[Response | AsyncResponse]
|
||||
{.multisync.} =
|
||||
|
|
@ -984,7 +994,10 @@ proc parseResponse(client: HttpClient | AsyncHttpClient,
|
|||
line = await client.socket.recvLine(client.timeout)
|
||||
else:
|
||||
line = await client.socket.recvLine()
|
||||
if line == "": break # We've been disconnected.
|
||||
if line == "":
|
||||
# We've been disconnected.
|
||||
client.close()
|
||||
break
|
||||
if line == "\c\L":
|
||||
fullyRead = true
|
||||
break
|
||||
|
|
@ -1033,7 +1046,8 @@ proc newConnection(client: HttpClient | AsyncHttpClient,
|
|||
url: Uri) {.multisync.} =
|
||||
if client.currentURL.hostname != url.hostname or
|
||||
client.currentURL.scheme != url.scheme or
|
||||
client.currentURL.port != url.port:
|
||||
client.currentURL.port != url.port or
|
||||
(not client.connected):
|
||||
let isSsl = url.scheme.toLowerAscii() == "https"
|
||||
|
||||
if isSsl and not defined(ssl):
|
||||
|
|
|
|||
|
|
@ -113,6 +113,9 @@ proc newHttpHeaders*(keyValuePairs:
|
|||
new result
|
||||
result.table = newTable[string, seq[string]](pairs)
|
||||
|
||||
proc `$`*(headers: HttpHeaders): string =
|
||||
return $headers.table
|
||||
|
||||
proc clear*(headers: HttpHeaders) =
|
||||
headers.table.clear()
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ proc findEnvVar(key: string): int =
|
|||
if startsWith(environment[i], temp): return i
|
||||
return -1
|
||||
|
||||
proc getEnv*(key: string): TaintedString {.tags: [ReadEnvEffect].} =
|
||||
proc getEnv*(key: string, default = ""): TaintedString {.tags: [ReadEnvEffect].} =
|
||||
## Returns the value of the `environment variable`:idx: named `key`.
|
||||
##
|
||||
## If the variable does not exist, "" is returned. To distinguish
|
||||
|
|
@ -108,7 +108,7 @@ proc getEnv*(key: string): TaintedString {.tags: [ReadEnvEffect].} =
|
|||
return TaintedString(substr(environment[i], find(environment[i], '=')+1))
|
||||
else:
|
||||
var env = c_getenv(key)
|
||||
if env == nil: return TaintedString("")
|
||||
if env == nil: return TaintedString(default)
|
||||
result = TaintedString($env)
|
||||
|
||||
proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} =
|
||||
|
|
|
|||
|
|
@ -37,15 +37,15 @@
|
|||
## Retrieving the value of a JSON node can then be achieved using one of the
|
||||
## helper procedures, which include:
|
||||
##
|
||||
## * ``getNum``
|
||||
## * ``getFNum``
|
||||
## * ``getInt``
|
||||
## * ``getFloat``
|
||||
## * ``getStr``
|
||||
## * ``getBVal``
|
||||
## * ``getBool``
|
||||
##
|
||||
## To retrieve the value of ``"key"`` you can do the following:
|
||||
##
|
||||
## .. code-block:: Nim
|
||||
## doAssert jsonNode["key"].getFNum() == 3.14
|
||||
## doAssert jsonNode["key"].getFloat() == 3.14
|
||||
##
|
||||
## The ``[]`` operator will raise an exception when the specified field does
|
||||
## not exist. If you wish to avoid this behaviour you can use the ``{}``
|
||||
|
|
@ -681,14 +681,25 @@ proc getStr*(n: JsonNode, default: string = ""): string =
|
|||
if n.isNil or n.kind != JString: return default
|
||||
else: return n.str
|
||||
|
||||
proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
|
||||
proc getInt*(n: JsonNode, default: int = 0): int =
|
||||
## Retrieves the int value of a `JInt JsonNode`.
|
||||
##
|
||||
## Returns ``default`` if ``n`` is not a ``JInt``, or if ``n`` is nil.
|
||||
if n.isNil or n.kind != JInt: return default
|
||||
else: return int(n.num)
|
||||
|
||||
proc getBiggestInt*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
|
||||
## Retrieves the BiggestInt value of a `JInt JsonNode`.
|
||||
##
|
||||
## Returns ``default`` if ``n`` is not a ``JInt``, or if ``n`` is nil.
|
||||
if n.isNil or n.kind != JInt: return default
|
||||
else: return n.num
|
||||
|
||||
proc getFNum*(n: JsonNode, default: float = 0.0): float =
|
||||
proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt {.deprecated.} =
|
||||
## Deprecated - use getInt or getBiggestInt instead
|
||||
getBiggestInt(n, default)
|
||||
|
||||
proc getFloat*(n: JsonNode, default: float = 0.0): float =
|
||||
## Retrieves the float value of a `JFloat JsonNode`.
|
||||
##
|
||||
## Returns ``default`` if ``n`` is not a ``JFloat`` or ``JInt``, or if ``n`` is nil.
|
||||
|
|
@ -698,13 +709,21 @@ proc getFNum*(n: JsonNode, default: float = 0.0): float =
|
|||
of JInt: return float(n.num)
|
||||
else: return default
|
||||
|
||||
proc getBVal*(n: JsonNode, default: bool = false): bool =
|
||||
proc getFNum*(n: JsonNode, default: float = 0.0): float {.deprecated.} =
|
||||
## Deprecated - use getFloat instead
|
||||
getFloat(n, default)
|
||||
|
||||
proc getBool*(n: JsonNode, default: bool = false): bool =
|
||||
## Retrieves the bool value of a `JBool JsonNode`.
|
||||
##
|
||||
## Returns ``default`` if ``n`` is not a ``JBool``, or if ``n`` is nil.
|
||||
if n.isNil or n.kind != JBool: return default
|
||||
else: return n.bval
|
||||
|
||||
proc getBVal*(n: JsonNode, default: bool = false): bool {.deprecated.} =
|
||||
## Deprecated - use getBVal instead
|
||||
getBool(n, default)
|
||||
|
||||
proc getFields*(n: JsonNode,
|
||||
default = initOrderedTable[string, JsonNode](4)):
|
||||
OrderedTable[string, JsonNode] =
|
||||
|
|
@ -804,13 +823,13 @@ proc toJson(x: NimNode): NimNode {.compiletime.} =
|
|||
of nnkBracket: # array
|
||||
if x.len == 0: return newCall(bindSym"newJArray")
|
||||
result = newNimNode(nnkBracket)
|
||||
for i in 0 .. <x.len:
|
||||
for i in 0 ..< x.len:
|
||||
result.add(toJson(x[i]))
|
||||
result = newCall(bindSym"%", result)
|
||||
of nnkTableConstr: # object
|
||||
if x.len == 0: return newCall(bindSym"newJObject")
|
||||
result = newNimNode(nnkTableConstr)
|
||||
for i in 0 .. <x.len:
|
||||
for i in 0 ..< x.len:
|
||||
x[i].expectKind nnkExprColonExpr
|
||||
result.add newTree(nnkExprColonExpr, x[i][0], toJson(x[i][1]))
|
||||
result = newCall(bindSym"%", result)
|
||||
|
|
@ -1284,7 +1303,7 @@ else:
|
|||
case getVarType(x)
|
||||
of JArray:
|
||||
result = newJArray()
|
||||
for i in 0 .. <x.len:
|
||||
for i in 0 ..< x.len:
|
||||
result.add(x[i].convertObject())
|
||||
of JObject:
|
||||
result = newJObject()
|
||||
|
|
@ -1342,7 +1361,7 @@ proc getEnum(node: JsonNode, ast: string, T: typedesc): T =
|
|||
# TODO: I shouldn't need this proc.
|
||||
proc convert[T](x: BiggestInt): T = T(x)
|
||||
verifyJsonKind(node, {JInt}, ast)
|
||||
return convert[T](node.getNum())
|
||||
return convert[T](node.getBiggestInt())
|
||||
else:
|
||||
verifyJsonKind(node, {JString}, ast)
|
||||
return parseEnum[T](node.getStr())
|
||||
|
|
@ -1430,7 +1449,7 @@ proc processElseBranch(recCaseNode, elseBranch, jsonNode, kindType,
|
|||
# We need to build up a list of conditions from each ``of`` branch so that
|
||||
# we can then negate it to get ``else``.
|
||||
var cond = newIdentNode("false")
|
||||
for i in 1 .. <len(recCaseNode):
|
||||
for i in 1 ..< len(recCaseNode):
|
||||
if recCaseNode[i].kind == nnkElse:
|
||||
break
|
||||
|
||||
|
|
@ -1492,7 +1511,7 @@ proc processObjField(field, jsonNode: NimNode): seq[NimNode] =
|
|||
exprColonExpr.add(getEnumCall)
|
||||
|
||||
# Iterate through each `of` branch.
|
||||
for i in 1 .. <field.len:
|
||||
for i in 1 ..< field.len:
|
||||
case field[i].kind
|
||||
of nnkOfBranch:
|
||||
result.add processOfBranch(field[i], jsonNode, kindType, kindJsonNode)
|
||||
|
|
@ -1621,7 +1640,7 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
|
|||
(
|
||||
var list: `typeSym` = @[];
|
||||
verifyJsonKind(`jsonNode`, {JArray}, astToStr(`jsonNode`));
|
||||
for `forLoopI` in 0 .. <`jsonNode`.len: list.add(`constructorNode`);
|
||||
for `forLoopI` in 0 ..< `jsonNode`.len: list.add(`constructorNode`);
|
||||
list
|
||||
)
|
||||
of "array":
|
||||
|
|
@ -1635,7 +1654,7 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
|
|||
(
|
||||
var list: `typeSym`;
|
||||
verifyJsonKind(`jsonNode`, {JArray}, astToStr(`jsonNode`));
|
||||
for `forLoopI` in 0 .. <`jsonNode`.len: list[`forLoopI`] =`constructorNode`;
|
||||
for `forLoopI` in 0 ..< `jsonNode`.len: list[`forLoopI`] =`constructorNode`;
|
||||
list
|
||||
)
|
||||
|
||||
|
|
@ -1664,7 +1683,7 @@ proc postProcessValue(value: NimNode): NimNode =
|
|||
result = postProcess(value)
|
||||
else:
|
||||
result = value
|
||||
for i in 0 .. <len(result):
|
||||
for i in 0 ..< len(result):
|
||||
result[i] = postProcessValue(result[i])
|
||||
|
||||
proc postProcessExprColonExpr(exprColonExpr, resIdent: NimNode): NimNode =
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ type
|
|||
lineNumber*: int ## the current line number
|
||||
sentinel: int
|
||||
lineStart: int # index of last line start in buffer
|
||||
offsetBase*: int # use ``offsetBase + bufpos`` to get the offset
|
||||
refillChars: set[char]
|
||||
|
||||
{.deprecated: [TBaseLexer: BaseLexer].}
|
||||
|
|
@ -107,7 +108,8 @@ proc fillBaseLexer(L: var BaseLexer, pos: int): int =
|
|||
result = pos + 1 # nothing to do
|
||||
else:
|
||||
fillBuffer(L)
|
||||
L.bufpos = 0 # XXX: is this really correct?
|
||||
L.offsetBase += pos
|
||||
L.bufpos = 0
|
||||
result = 0
|
||||
|
||||
proc handleCR*(L: var BaseLexer, pos: int): int =
|
||||
|
|
@ -147,6 +149,7 @@ proc open*(L: var BaseLexer, input: Stream, bufLen: int = 8192;
|
|||
assert(input != nil)
|
||||
L.input = input
|
||||
L.bufpos = 0
|
||||
L.offsetBase = 0
|
||||
L.bufLen = bufLen
|
||||
L.refillChars = refillChars
|
||||
when defined(js):
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ proc to*[T](data: string): T =
|
|||
loadAny(newStringStream(data), toAny(result), tab)
|
||||
|
||||
when not defined(testing) and isMainModule:
|
||||
template testit(x: expr) = echo($$to[type(x)]($$x))
|
||||
template testit(x: untyped) = echo($$to[type(x)]($$x))
|
||||
|
||||
var x: array[0..4, array[0..4, string]] = [
|
||||
["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ proc validEmailAddress*(s: string): bool {.noSideEffect,
|
|||
"aero", "jobs", "museum": return true
|
||||
else: return false
|
||||
|
||||
proc parseInt*(s: string, value: var int, validRange: Slice[int]) {.
|
||||
proc parseInt*(s: string, value: var int, validRange: HSlice[int, int]) {.
|
||||
noSideEffect, rtl, extern: "nmatchParseInt".} =
|
||||
## parses `s` into an integer in the range `validRange`. If successful,
|
||||
## `value` is modified to contain the result. Otherwise no exception is
|
||||
|
|
|
|||
|
|
@ -184,6 +184,8 @@ when not defined(JS):
|
|||
proc pow*(x, y: float32): float32 {.importc: "powf", header: "<math.h>".}
|
||||
proc pow*(x, y: float64): float64 {.importc: "pow", header: "<math.h>".}
|
||||
## computes x to power raised of y.
|
||||
##
|
||||
## To compute power between integers, use `^` e.g. 2 ^ 6
|
||||
|
||||
proc erf*(x: float32): float32 {.importc: "erff", header: "<math.h>".}
|
||||
proc erf*(x: float64): float64 {.importc: "erf", header: "<math.h>".}
|
||||
|
|
|
|||
|
|
@ -496,11 +496,12 @@ proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
|
|||
addr(namelen)) == -1'i32:
|
||||
raiseOSError(osLastError())
|
||||
# Cannot use INET6_ADDRSTRLEN here, because it's a C define.
|
||||
var buf: array[64, char]
|
||||
result[0] = newString(64)
|
||||
if inet_ntop(name.sin6_family.cint,
|
||||
addr name.sin6_addr, buf.cstring, sizeof(buf).int32).isNil:
|
||||
addr name.sin6_addr, addr result[0][0], (result[0].len+1).int32).isNil:
|
||||
raiseOSError(osLastError())
|
||||
result = ($buf, Port(nativesockets.ntohs(name.sin6_port)))
|
||||
setLen(result[0], result[0].cstring.len)
|
||||
result[1] = Port(nativesockets.ntohs(name.sin6_port))
|
||||
else:
|
||||
raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr")
|
||||
|
||||
|
|
@ -532,11 +533,12 @@ proc getPeerAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
|
|||
addr(namelen)) == -1'i32:
|
||||
raiseOSError(osLastError())
|
||||
# Cannot use INET6_ADDRSTRLEN here, because it's a C define.
|
||||
var buf: array[64, char]
|
||||
result[0] = newString(64)
|
||||
if inet_ntop(name.sin6_family.cint,
|
||||
addr name.sin6_addr, buf.cstring, sizeof(buf).int32).isNil:
|
||||
addr name.sin6_addr, addr result[0][0], (result[0].len+1).int32).isNil:
|
||||
raiseOSError(osLastError())
|
||||
result = ($buf, Port(nativesockets.ntohs(name.sin6_port)))
|
||||
setLen(result[0], result[0].cstring.len)
|
||||
result[1] = Port(nativesockets.ntohs(name.sin6_port))
|
||||
else:
|
||||
raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr")
|
||||
|
||||
|
|
|
|||
|
|
@ -857,13 +857,16 @@ proc close*(socket: Socket) =
|
|||
# shutdown i.e not wait for the peers "close notify" alert with a second
|
||||
# call to SSLShutdown
|
||||
let res = SSLShutdown(socket.sslHandle)
|
||||
SSLFree(socket.sslHandle)
|
||||
socket.sslHandle = nil
|
||||
if res == 0:
|
||||
discard
|
||||
elif res != 1:
|
||||
socketError(socket, res)
|
||||
finally:
|
||||
when defineSsl:
|
||||
if socket.isSSL and socket.sslHandle != nil:
|
||||
SSLFree(socket.sslHandle)
|
||||
socket.sslHandle = nil
|
||||
|
||||
socket.fd.close()
|
||||
|
||||
proc toCInt*(opt: SOBool): cint =
|
||||
|
|
|
|||
|
|
@ -153,7 +153,10 @@ proc `==`*(a, b: Option): bool =
|
|||
(a.has and b.has and a.val == b.val) or (not a.has and not b.has)
|
||||
|
||||
proc `$`*[T](self: Option[T]): string =
|
||||
## Returns the contents of this option or `otherwise` if the option is none.
|
||||
## Get the string representation of this option. If the option has a value,
|
||||
## the result will be `Some(x)` where `x` is the string representation of the contained value.
|
||||
## If the option does not have a value, the result will be `None[T]` where `T` is the name of
|
||||
## the type contained in the option.
|
||||
if self.has:
|
||||
"Some(" & $self.val & ")"
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -790,7 +790,10 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path:
|
|||
while true:
|
||||
var x = readdir(d)
|
||||
if x == nil: break
|
||||
var y = $x.d_name
|
||||
when defined(nimNoArrayToCstringConversion):
|
||||
var y = $cstring(addr x.d_name)
|
||||
else:
|
||||
var y = $x.d_name.cstring
|
||||
if y != "." and y != "..":
|
||||
var s: Stat
|
||||
if not relative:
|
||||
|
|
|
|||
|
|
@ -280,7 +280,7 @@ proc execProcesses*(cmds: openArray[string],
|
|||
## executes the commands `cmds` in parallel. Creates `n` processes
|
||||
## that execute in parallel. The highest return value of all processes
|
||||
## is returned. Runs `beforeRunEvent` before running each command.
|
||||
when defined(posix):
|
||||
when false:
|
||||
# poParentStreams causes problems on Posix, so we simply disable it:
|
||||
var options = options - {poParentStreams}
|
||||
|
||||
|
|
@ -617,6 +617,7 @@ when defined(Windows) and not defined(useNimRtl):
|
|||
var res: int32
|
||||
discard getExitCodeProcess(p.fProcessHandle, res)
|
||||
result = res
|
||||
p.exitStatus = res
|
||||
discard closeHandle(p.fProcessHandle)
|
||||
|
||||
proc peekExitCode(p: Process): int =
|
||||
|
|
@ -625,6 +626,7 @@ when defined(Windows) and not defined(useNimRtl):
|
|||
else:
|
||||
var res: int32
|
||||
discard getExitCodeProcess(p.fProcessHandle, res)
|
||||
if res == 0: return p.exitStatus
|
||||
return res
|
||||
|
||||
proc inputStream(p: Process): Stream =
|
||||
|
|
|
|||
|
|
@ -72,7 +72,10 @@ proc raiseEInvalidCsv(filename: string, line, col: int,
|
|||
msg: string) {.noreturn.} =
|
||||
var e: ref CsvError
|
||||
new(e)
|
||||
e.msg = filename & "(" & $line & ", " & $col & ") Error: " & msg
|
||||
if filename.len == 0:
|
||||
e.msg = "Error: " & msg
|
||||
else:
|
||||
e.msg = filename & "(" & $line & ", " & $col & ") Error: " & msg
|
||||
raise e
|
||||
|
||||
proc error(my: CsvParser, pos: int, msg: string) =
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ type
|
|||
cmd: seq[string]
|
||||
pos: int
|
||||
remainingShortOptions: string
|
||||
kind*: CmdLineKind ## the dected command line token
|
||||
kind*: CmdLineKind ## the detected command line token
|
||||
key*, val*: TaintedString ## key and value pair; ``key`` is the option
|
||||
## or the argument, ``value`` is not "" if
|
||||
## the option was given a value
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
#
|
||||
|
||||
## This module contains helpers for parsing tokens, numbers, identifiers, etc.
|
||||
##
|
||||
## To unpack raw bytes look at the `streams <streams.html>`_ module.
|
||||
|
||||
{.deadCodeElim: on.}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ proc random*(max: float): float {.benign.} =
|
|||
let u = (0x3FFu64 shl 52u64) or (x shr 12u64)
|
||||
result = (cast[float](u) - 1.0) * max
|
||||
|
||||
proc random*[T](x: Slice[T]): T =
|
||||
proc random*[T](x: HSlice[T, T]): T =
|
||||
## For a slice `a .. b` returns a value in the range `a .. b-1`.
|
||||
result = T(random(x.b - x.a)) + x.a
|
||||
|
||||
|
|
|
|||
|
|
@ -39,47 +39,13 @@ proc toRational*[T:SomeInteger](x: T): Rational[T] =
|
|||
result.num = x
|
||||
result.den = 1
|
||||
|
||||
proc toRationalSub(x: float, n: int): Rational[int] =
|
||||
var
|
||||
a = 0'i64
|
||||
b, c, d = 1'i64
|
||||
result = 0 // 1 # rational 0
|
||||
while b <= n and d <= n:
|
||||
let ac = (a+c)
|
||||
let bd = (b+d)
|
||||
# scale by 1000 so not overflow for high precision
|
||||
let mediant = (ac.float/1000) / (bd.float/1000)
|
||||
if x == mediant:
|
||||
if bd <= n:
|
||||
result.num = ac.int
|
||||
result.den = bd.int
|
||||
return result
|
||||
elif d > b:
|
||||
result.num = c.int
|
||||
result.den = d.int
|
||||
return result
|
||||
else:
|
||||
result.num = a.int
|
||||
result.den = b.int
|
||||
return result
|
||||
elif x > mediant:
|
||||
a = ac
|
||||
b = bd
|
||||
else:
|
||||
c = ac
|
||||
d = bd
|
||||
if (b > n):
|
||||
return initRational(c.int, d.int)
|
||||
return initRational(a.int, b.int)
|
||||
|
||||
proc toRational*(x: float, n: int = high(int)): Rational[int] =
|
||||
## Calculate the best rational numerator and denominator
|
||||
proc toRational*(x: float, n: int = high(int32)): Rational[int] =
|
||||
## Calculates the best rational numerator and denominator
|
||||
## that approximates to `x`, where the denominator is
|
||||
## smaller than `n` (default is the largest possible
|
||||
## int to give maximum resolution)
|
||||
## int to give maximum resolution).
|
||||
##
|
||||
## The algorithm is based on the Farey sequence named
|
||||
## after John Farey
|
||||
## The algorithm is based on the theory of continued fractions.
|
||||
##
|
||||
## .. code-block:: Nim
|
||||
## import math, rationals
|
||||
|
|
@ -88,13 +54,24 @@ proc toRational*(x: float, n: int = high(int)): Rational[int] =
|
|||
## let x = toRational(PI, t)
|
||||
## let newPI = x.num / x.den
|
||||
## echo x, " ", newPI, " error: ", PI - newPI, " ", t
|
||||
if x > 1:
|
||||
result = toRationalSub(1.0/x, n)
|
||||
swap(result.num, result.den)
|
||||
elif x == 1.0:
|
||||
result = 1 // 1
|
||||
else:
|
||||
result = toRationalSub(x, n)
|
||||
|
||||
# David Eppstein / UC Irvine / 8 Aug 1993
|
||||
# With corrections from Arno Formella, May 2008
|
||||
var
|
||||
m11, m22 = 1
|
||||
m12, m21 = 0
|
||||
ai = int(x)
|
||||
x = x
|
||||
while m21 * ai + m22 <= n:
|
||||
swap m12, m11
|
||||
swap m22, m21
|
||||
m11 = m12 * ai + m11
|
||||
m21 = m22 * ai + m21
|
||||
if x == float(ai): break # division by zero
|
||||
x = 1/(x - float(ai))
|
||||
if x > float(high(int32)): break # representation failure
|
||||
ai = int(x)
|
||||
result = m11 // m21
|
||||
|
||||
proc toFloat*[T](x: Rational[T]): float =
|
||||
## Convert a rational number `x` to a float.
|
||||
|
|
@ -346,7 +323,14 @@ when isMainModule:
|
|||
assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7
|
||||
assert toInt(z) == 0
|
||||
|
||||
assert toRational(0.98765432) == 12345679 // 12500000
|
||||
assert toRational(0.1, 1000000) == 1 // 10
|
||||
assert toRational(0.9, 1000000) == 9 // 10
|
||||
#assert toRational(PI) == 80143857 // 25510582
|
||||
assert toRational(0.98765432) == 2111111029 // 2137499919
|
||||
assert toRational(PI) == 817696623 // 260280919
|
||||
assert toRational(0.1) == 1 // 10
|
||||
assert toRational(0.9) == 9 // 10
|
||||
|
||||
assert toRational(0.0) == 0 // 1
|
||||
assert toRational(-0.25) == 1 // -4
|
||||
assert toRational(3.2) == 16 // 5
|
||||
assert toRational(0.33) == 33 // 100
|
||||
assert toRational(0.22) == 11 // 50
|
||||
assert toRational(10.0) == 10 // 1
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ proc `$`*(self: SecureHash): string =
|
|||
result.add(toHex(int(v), 2))
|
||||
|
||||
proc parseSecureHash*(hash: string): SecureHash =
|
||||
for i in 0.. <Sha1DigestSize:
|
||||
for i in 0 ..< Sha1DigestSize:
|
||||
Sha1Digest(result)[i] = uint8(parseHexInt(hash[i*2] & hash[i*2 + 1]))
|
||||
|
||||
proc `==`*(a, b: SecureHash): bool =
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ elif defined(linux):
|
|||
return @[]
|
||||
raiseOSError(err)
|
||||
if evNum == 0: return @[]
|
||||
for i in 0 .. <evNum:
|
||||
for i in 0 ..< evNum:
|
||||
let fd = s.events[i].data.fd.SocketHandle
|
||||
|
||||
var evSet: set[Event] = {}
|
||||
|
|
@ -253,7 +253,7 @@ elif defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd):
|
|||
return @[]
|
||||
raiseOSError(err)
|
||||
if evNum == 0: return @[]
|
||||
for i in 0 .. <evNum:
|
||||
for i in 0 ..< evNum:
|
||||
let fd = s.events[i].ident.SocketHandle
|
||||
|
||||
var evSet: set[Event] = {}
|
||||
|
|
|
|||
|
|
@ -224,6 +224,38 @@ proc peekInt64*(s: Stream): int64 =
|
|||
## peeks an int64 from the stream `s`. Raises `EIO` if an error occurred.
|
||||
peek(s, result)
|
||||
|
||||
proc readUint8*(s: Stream): uint8 =
|
||||
## reads an uint8 from the stream `s`. Raises `EIO` if an error occurred.
|
||||
read(s, result)
|
||||
|
||||
proc peekUint8*(s: Stream): uint8 =
|
||||
## peeks an uint8 from the stream `s`. Raises `EIO` if an error occurred.
|
||||
peek(s, result)
|
||||
|
||||
proc readUint16*(s: Stream): uint16 =
|
||||
## reads an uint16 from the stream `s`. Raises `EIO` if an error occurred.
|
||||
read(s, result)
|
||||
|
||||
proc peekUint16*(s: Stream): uint16 =
|
||||
## peeks an uint16 from the stream `s`. Raises `EIO` if an error occurred.
|
||||
peek(s, result)
|
||||
|
||||
proc readUint32*(s: Stream): uint32 =
|
||||
## reads an uint32 from the stream `s`. Raises `EIO` if an error occurred.
|
||||
read(s, result)
|
||||
|
||||
proc peekUint32*(s: Stream): uint32 =
|
||||
## peeks an uint32 from the stream `s`. Raises `EIO` if an error occurred.
|
||||
peek(s, result)
|
||||
|
||||
proc readUint64*(s: Stream): uint64 =
|
||||
## reads an uint64 from the stream `s`. Raises `EIO` if an error occurred.
|
||||
read(s, result)
|
||||
|
||||
proc peekUint64*(s: Stream): uint64 =
|
||||
## peeks an uint64 from the stream `s`. Raises `EIO` if an error occurred.
|
||||
peek(s, result)
|
||||
|
||||
proc readFloat32*(s: Stream): float32 =
|
||||
## reads a float32 from the stream `s`. Raises `EIO` if an error occurred.
|
||||
read(s, result)
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ is performed.
|
|||
for r in collectLinks(body):
|
||||
echo r
|
||||
|
||||
In this example both macros are combined seamlessly in order to maximise
|
||||
In this example both macros are combined seamlessly in order to maximise
|
||||
efficiency and perform different checks.
|
||||
|
||||
.. code-block:: nim
|
||||
|
|
@ -308,7 +308,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
|||
## See top level documentation of his module of how ``scanf`` works.
|
||||
template matchBind(parser) {.dirty.} =
|
||||
var resLen = genSym(nskLet, "resLen")
|
||||
conds.add newLetStmt(resLen, newCall(bindSym(parser), input, results[i], idx))
|
||||
conds.add newLetStmt(resLen, newCall(bindSym(parser), inp, results[i], idx))
|
||||
conds.add resLen.notZero
|
||||
conds.add resLen
|
||||
|
||||
|
|
@ -316,7 +316,8 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
|||
var p = 0
|
||||
var idx = genSym(nskVar, "idx")
|
||||
var res = genSym(nskVar, "res")
|
||||
result = newTree(nnkStmtListExpr, newVarStmt(idx, newLit 0), newVarStmt(res, newLit false))
|
||||
let inp = genSym(nskLet, "inp")
|
||||
result = newTree(nnkStmtListExpr, newLetStmt(inp, input), newVarStmt(idx, newLit 0), newVarStmt(res, newLit false))
|
||||
var conds = newTree(nnkStmtList)
|
||||
var fullMatch = false
|
||||
while p < pattern.len:
|
||||
|
|
@ -325,7 +326,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
|||
case pattern[p]
|
||||
of '$':
|
||||
var resLen = genSym(nskLet, "resLen")
|
||||
conds.add newLetStmt(resLen, newCall(bindSym"skip", input, newLit($pattern[p]), idx))
|
||||
conds.add newLetStmt(resLen, newCall(bindSym"skip", inp, newLit($pattern[p]), idx))
|
||||
conds.add resLen.notZero
|
||||
conds.add resLen
|
||||
of 'w':
|
||||
|
|
@ -347,7 +348,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
|||
error("no float var given for $f")
|
||||
inc i
|
||||
of 's':
|
||||
conds.add newCall(bindSym"inc", idx, newCall(bindSym"skipWhitespace", input, idx))
|
||||
conds.add newCall(bindSym"inc", idx, newCall(bindSym"skipWhitespace", inp, idx))
|
||||
conds.add newEmptyNode()
|
||||
conds.add newEmptyNode()
|
||||
of '.':
|
||||
|
|
@ -364,7 +365,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
|||
token.add pattern[q]
|
||||
inc q
|
||||
var resLen = genSym(nskLet, "resLen")
|
||||
conds.add newLetStmt(resLen, newCall(bindSym"parseUntil", input, results[i], newLit(token), idx))
|
||||
conds.add newLetStmt(resLen, newCall(bindSym"parseUntil", inp, results[i], newLit(token), idx))
|
||||
conds.add newCall(bindSym"!=", resLen, newLit min)
|
||||
conds.add resLen
|
||||
else:
|
||||
|
|
@ -386,7 +387,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
|||
let expr = pattern.substr(start, p-1)
|
||||
if i < results.len:
|
||||
var resLen = genSym(nskLet, "resLen")
|
||||
conds.add newLetStmt(resLen, buildUserCall(expr, input, results[i], idx))
|
||||
conds.add newLetStmt(resLen, buildUserCall(expr, inp, results[i], idx))
|
||||
conds.add newCall(bindSym"!=", resLen, newLit 0)
|
||||
conds.add resLen
|
||||
else:
|
||||
|
|
@ -406,7 +407,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
|||
else: discard
|
||||
inc p
|
||||
let expr = pattern.substr(start, p-1)
|
||||
conds.add newCall(bindSym"inc", idx, buildUserCall(expr, input, idx))
|
||||
conds.add newCall(bindSym"inc", idx, buildUserCall(expr, inp, idx))
|
||||
conds.add newEmptyNode()
|
||||
conds.add newEmptyNode()
|
||||
else: error("invalid format string")
|
||||
|
|
@ -417,13 +418,13 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
|||
token.add pattern[p]
|
||||
inc p
|
||||
var resLen = genSym(nskLet, "resLen")
|
||||
conds.add newLetStmt(resLen, newCall(bindSym"skip", input, newLit(token), idx))
|
||||
conds.add newLetStmt(resLen, newCall(bindSym"skip", inp, newLit(token), idx))
|
||||
conds.add resLen.notZero
|
||||
conds.add resLen
|
||||
result.add conditionsToIfChain(conds, idx, res, 0)
|
||||
if fullMatch:
|
||||
result.add newCall(bindSym"and", res,
|
||||
newCall(bindSym">=", idx, newCall(bindSym"len", input)))
|
||||
newCall(bindSym">=", idx, newCall(bindSym"len", inp)))
|
||||
else:
|
||||
result.add res
|
||||
|
||||
|
|
@ -684,3 +685,14 @@ when isMainModule:
|
|||
"NimMain c:/users/anwender/projects/nim/lib/system.nim:2613",
|
||||
"main c:/users/anwender/projects/nim/lib/system.nim:2620"]
|
||||
doAssert parseGDB(gdbOut) == result
|
||||
|
||||
# bug #6487
|
||||
var count = 0
|
||||
|
||||
proc test(): string =
|
||||
inc count
|
||||
result = ",123123"
|
||||
|
||||
var a: int
|
||||
discard scanf(test(), ",$i", a)
|
||||
doAssert count == 1
|
||||
|
|
|
|||
|
|
@ -138,7 +138,8 @@ proc isAlphaNumeric*(s: string): bool {.noSideEffect, procvar,
|
|||
|
||||
result = true
|
||||
for c in s:
|
||||
result = c.isAlphaNumeric() and result
|
||||
if not c.isAlphaNumeric():
|
||||
return false
|
||||
|
||||
proc isDigit*(s: string): bool {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuIsDigitStr".}=
|
||||
|
|
@ -153,7 +154,8 @@ proc isDigit*(s: string): bool {.noSideEffect, procvar,
|
|||
|
||||
result = true
|
||||
for c in s:
|
||||
result = c.isDigit() and result
|
||||
if not c.isDigit():
|
||||
return false
|
||||
|
||||
proc isSpaceAscii*(s: string): bool {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuIsSpaceAsciiStr".}=
|
||||
|
|
@ -1062,8 +1064,8 @@ proc align*(s: string, count: Natural, padding = ' '): string {.
|
|||
##
|
||||
## `padding` characters (by default spaces) are added before `s` resulting in
|
||||
## right alignment. If ``s.len >= count``, no spaces are added and `s` is
|
||||
## returned unchanged. If you need to left align a string use the `repeatChar
|
||||
## proc <#repeatChar>`_. Example:
|
||||
## returned unchanged. If you need to left align a string use the `alignLeft
|
||||
## proc <#alignLeft>`_. Example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## assert align("abc", 4) == " abc"
|
||||
|
|
@ -1078,6 +1080,28 @@ proc align*(s: string, count: Natural, padding = ' '): string {.
|
|||
else:
|
||||
result = s
|
||||
|
||||
proc alignLeft*(s: string, count: Natural, padding = ' '): string {.noSideEffect.} =
|
||||
## Left-Aligns a string `s` with `padding`, so that it is of length `count`.
|
||||
##
|
||||
## `padding` characters (by default spaces) are added after `s` resulting in
|
||||
## left alignment. If ``s.len >= count``, no spaces are added and `s` is
|
||||
## returned unchanged. If you need to right align a string use the `align
|
||||
## proc <#align>`_. Example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## assert alignLeft("abc", 4) == "abc "
|
||||
## assert alignLeft("a", 0) == "a"
|
||||
## assert alignLeft("1232", 6) == "1232 "
|
||||
## assert alignLeft("1232", 6, '#') == "1232##"
|
||||
if s.len < count:
|
||||
result = newString(count)
|
||||
if s.len > 0:
|
||||
result[0 .. (s.len - 1)] = s
|
||||
for i in s.len ..< count:
|
||||
result[i] = padding
|
||||
else:
|
||||
result = s
|
||||
|
||||
iterator tokenize*(s: string, seps: set[char] = Whitespace): tuple[
|
||||
token: string, isSep: bool] =
|
||||
## Tokenizes the string `s` into substrings.
|
||||
|
|
@ -1175,7 +1199,7 @@ proc unindent*(s: string, count: Natural, padding: string = " "): string
|
|||
var indentCount = 0
|
||||
for j in 0..<count.int:
|
||||
indentCount.inc
|
||||
if line[j .. j + <padding.len] != padding:
|
||||
if line[j .. j + padding.len-1] != padding:
|
||||
indentCount = j
|
||||
break
|
||||
result.add(line[indentCount*padding.len .. ^1])
|
||||
|
|
@ -1306,18 +1330,36 @@ proc join*[T: not string](a: openArray[T], sep: string = ""): string {.
|
|||
add(result, $x)
|
||||
|
||||
type
|
||||
SkipTable = array[char, int]
|
||||
SkipTable* = array[char, int]
|
||||
|
||||
{.push profiler: off.}
|
||||
proc preprocessSub(sub: string, a: var SkipTable) =
|
||||
var m = len(sub)
|
||||
for i in 0..0xff: a[chr(i)] = m+1
|
||||
for i in 0..m-1: a[sub[i]] = m-i
|
||||
{.pop.}
|
||||
proc initSkipTable*(a: var SkipTable, sub: string)
|
||||
{.noSideEffect, rtl, extern: "nsuInitSkipTable".} =
|
||||
## Preprocess table `a` for `sub`.
|
||||
let m = len(sub)
|
||||
let m1 = m + 1
|
||||
var i = 0
|
||||
while i <= 0xff-7:
|
||||
a[chr(i + 0)] = m1
|
||||
a[chr(i + 1)] = m1
|
||||
a[chr(i + 2)] = m1
|
||||
a[chr(i + 3)] = m1
|
||||
a[chr(i + 4)] = m1
|
||||
a[chr(i + 5)] = m1
|
||||
a[chr(i + 6)] = m1
|
||||
a[chr(i + 7)] = m1
|
||||
i += 8
|
||||
|
||||
proc findAux(s, sub: string, start, last: int, a: SkipTable): int =
|
||||
# Fast "quick search" algorithm:
|
||||
var
|
||||
for i in 0..m-1:
|
||||
a[sub[i]] = m-i
|
||||
|
||||
proc find*(a: SkipTable, s, sub: string, start: Natural = 0, last: Natural = 0): int
|
||||
{.noSideEffect, rtl, extern: "nsuFindStrA".} =
|
||||
## Searches for `sub` in `s` inside range `start`..`last` using preprocessed table `a`.
|
||||
## If `last` is unspecified, it defaults to `s.high`.
|
||||
##
|
||||
## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
|
||||
let
|
||||
last = if last==0: s.high else: last
|
||||
m = len(sub)
|
||||
n = last + 1
|
||||
# search:
|
||||
|
|
@ -1337,17 +1379,6 @@ when not (defined(js) or defined(nimdoc) or defined(nimscript)):
|
|||
else:
|
||||
const hasCStringBuiltin = false
|
||||
|
||||
proc find*(s, sub: string, start: Natural = 0, last: Natural = 0): int {.noSideEffect,
|
||||
rtl, extern: "nsuFindStr".} =
|
||||
## Searches for `sub` in `s` inside range `start`..`last`.
|
||||
## If `last` is unspecified, it defaults to `s.high`.
|
||||
##
|
||||
## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
|
||||
var a {.noinit.}: SkipTable
|
||||
let last = if last==0: s.high else: last
|
||||
preprocessSub(sub, a)
|
||||
result = findAux(s, sub, start, last, a)
|
||||
|
||||
proc find*(s: string, sub: char, start: Natural = 0, last: Natural = 0): int {.noSideEffect,
|
||||
rtl, extern: "nsuFindChar".} =
|
||||
## Searches for `sub` in `s` inside range `start`..`last`.
|
||||
|
|
@ -1366,9 +1397,24 @@ proc find*(s: string, sub: char, start: Natural = 0, last: Natural = 0): int {.n
|
|||
else:
|
||||
for i in start..last:
|
||||
if sub == s[i]: return i
|
||||
|
||||
return -1
|
||||
|
||||
proc find*(s, sub: string, start: Natural = 0, last: Natural = 0): int {.noSideEffect,
|
||||
rtl, extern: "nsuFindStr".} =
|
||||
## Searches for `sub` in `s` inside range `start`..`last`.
|
||||
## If `last` is unspecified, it defaults to `s.high`.
|
||||
##
|
||||
## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
|
||||
if sub.len > s.len:
|
||||
return -1
|
||||
|
||||
if sub.len == 1:
|
||||
return find(s, sub[0], start, last)
|
||||
|
||||
var a {.noinit.}: SkipTable
|
||||
initSkipTable(a, sub)
|
||||
result = find(a, s, sub, start, last)
|
||||
|
||||
proc find*(s: string, chars: set[char], start: Natural = 0, last: Natural = 0): int {.noSideEffect,
|
||||
rtl, extern: "nsuFindCharSet".} =
|
||||
## Searches for `chars` in `s` inside range `start`..`last`.
|
||||
|
|
@ -1500,11 +1546,11 @@ proc replace*(s, sub: string, by = ""): string {.noSideEffect,
|
|||
## Replaces `sub` in `s` by the string `by`.
|
||||
var a {.noinit.}: SkipTable
|
||||
result = ""
|
||||
preprocessSub(sub, a)
|
||||
initSkipTable(a, sub)
|
||||
let last = s.high
|
||||
var i = 0
|
||||
while true:
|
||||
var j = findAux(s, sub, i, last, a)
|
||||
var j = find(a, s, sub, i, last)
|
||||
if j < 0: break
|
||||
add result, substr(s, i, j - 1)
|
||||
add result, by
|
||||
|
|
@ -1534,11 +1580,11 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
|
|||
const wordChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'}
|
||||
var a {.noinit.}: SkipTable
|
||||
result = ""
|
||||
preprocessSub(sub, a)
|
||||
initSkipTable(a, sub)
|
||||
var i = 0
|
||||
let last = s.high
|
||||
while true:
|
||||
var j = findAux(s, sub, i, last, a)
|
||||
var j = find(a, s, sub, i, last)
|
||||
if j < 0: break
|
||||
# word boundary?
|
||||
if (j == 0 or s[j-1] notin wordChars) and
|
||||
|
|
@ -1890,17 +1936,32 @@ proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault,
|
|||
frmtstr[3] = '*'
|
||||
frmtstr[4] = floatFormatToChar[format]
|
||||
frmtstr[5] = '\0'
|
||||
L = c_sprintf(buf, frmtstr, precision, f)
|
||||
when defined(nimNoArrayToCstringConversion):
|
||||
L = c_sprintf(addr buf, addr frmtstr, precision, f)
|
||||
else:
|
||||
L = c_sprintf(buf, frmtstr, precision, f)
|
||||
else:
|
||||
frmtstr[1] = floatFormatToChar[format]
|
||||
frmtstr[2] = '\0'
|
||||
L = c_sprintf(buf, frmtstr, f)
|
||||
when defined(nimNoArrayToCstringConversion):
|
||||
L = c_sprintf(addr buf, addr frmtstr, f)
|
||||
else:
|
||||
L = c_sprintf(buf, frmtstr, f)
|
||||
result = newString(L)
|
||||
for i in 0 ..< L:
|
||||
# Depending on the locale either dot or comma is produced,
|
||||
# but nothing else is possible:
|
||||
if buf[i] in {'.', ','}: result[i] = decimalsep
|
||||
else: result[i] = buf[i]
|
||||
when defined(vcc):
|
||||
# VS pre 2015 violates the C standard: "The exponent always contains at
|
||||
# least two digits, and only as many more digits as necessary to
|
||||
# represent the exponent." [C11 §7.21.6.1]
|
||||
# The following post-processing fixes this behavior.
|
||||
if result.len > 4 and result[^4] == '+' and result[^3] == '0':
|
||||
result[^3] = result[^2]
|
||||
result[^2] = result[^1]
|
||||
result.setLen(result.len - 1)
|
||||
|
||||
proc formatFloat*(f: float, format: FloatFormatMode = ffDefault,
|
||||
precision: range[0..32] = 16; decimalSep = '.'): string {.
|
||||
|
|
@ -2169,11 +2230,26 @@ proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.
|
|||
if idx >% a.high: invalidFormatString()
|
||||
add s, a[idx]
|
||||
of '{':
|
||||
var j = i+1
|
||||
while formatstr[j] notin {'\0', '}'}: inc(j)
|
||||
var x = findNormalized(substr(formatstr, i+2, j-1), a)
|
||||
if x >= 0 and x < high(a): add s, a[x+1]
|
||||
else: invalidFormatString()
|
||||
var j = i+2
|
||||
var k = 0
|
||||
var negative = formatstr[j] == '-'
|
||||
if negative: inc j
|
||||
var isNumber = 0
|
||||
while formatstr[j] notin {'\0', '}'}:
|
||||
if formatstr[j] in Digits:
|
||||
k = k * 10 + ord(formatstr[j]) - ord('0')
|
||||
if isNumber == 0: isNumber = 1
|
||||
else:
|
||||
isNumber = -1
|
||||
inc(j)
|
||||
if isNumber == 1:
|
||||
let idx = if not negative: k-1 else: a.len-k
|
||||
if idx >% a.high: invalidFormatString()
|
||||
add s, a[idx]
|
||||
else:
|
||||
var x = findNormalized(substr(formatstr, i+2, j-1), a)
|
||||
if x >= 0 and x < high(a): add s, a[x+1]
|
||||
else: invalidFormatString()
|
||||
i = j+1
|
||||
of 'a'..'z', 'A'..'Z', '\128'..'\255', '_':
|
||||
var j = i+1
|
||||
|
|
@ -2250,60 +2326,104 @@ proc format*(formatstr: string, a: varargs[string, `$`]): string {.noSideEffect,
|
|||
|
||||
proc removeSuffix*(s: var string, chars: set[char] = Newlines) {.
|
||||
rtl, extern: "nsuRemoveSuffixCharSet".} =
|
||||
## Removes the first matching character from the string (in-place) given a
|
||||
## set of characters. If the set of characters is only equal to `Newlines`
|
||||
## then it will remove both the newline and return feed.
|
||||
## Removes all characters from `chars` from the end of the string `s`
|
||||
## (in-place).
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## var
|
||||
## userInput = "Hello World!\r\n"
|
||||
## otherInput = "Hello!?!"
|
||||
## var userInput = "Hello World!*~\r\n"
|
||||
## userInput.removeSuffix
|
||||
## userInput == "Hello World!"
|
||||
## userInput.removeSuffix({'!', '?'})
|
||||
## userInput == "Hello World"
|
||||
## doAssert userInput == "Hello World!*~"
|
||||
## userInput.removeSuffix({'~', '*'})
|
||||
## doAssert userInput == "Hello World!"
|
||||
##
|
||||
## var otherInput = "Hello!?!"
|
||||
## otherInput.removeSuffix({'!', '?'})
|
||||
## otherInput == "Hello!?"
|
||||
## doAssert otherInput == "Hello"
|
||||
if s.len == 0: return
|
||||
var last = len(s) - 1
|
||||
if chars == Newlines:
|
||||
if s[last] == '\10':
|
||||
last -= 1
|
||||
if s[last] == '\13':
|
||||
last -= 1
|
||||
else:
|
||||
if s[last] in chars:
|
||||
last -= 1
|
||||
var last = s.high
|
||||
while last > -1 and s[last] in chars: last -= 1
|
||||
s.setLen(last + 1)
|
||||
|
||||
proc removeSuffix*(s: var string, c: char) {.
|
||||
rtl, extern: "nsuRemoveSuffixChar".} =
|
||||
## Removes a single character (in-place) from a string.
|
||||
## Removes all occurrences of a single character (in-place) from the end
|
||||
## of a string.
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## var
|
||||
## table = "users"
|
||||
## var table = "users"
|
||||
## table.removeSuffix('s')
|
||||
## table == "user"
|
||||
## doAssert table == "user"
|
||||
##
|
||||
## var dots = "Trailing dots......."
|
||||
## dots.removeSuffix('.')
|
||||
## doAssert dots == "Trailing dots"
|
||||
removeSuffix(s, chars = {c})
|
||||
|
||||
proc removeSuffix*(s: var string, suffix: string) {.
|
||||
rtl, extern: "nsuRemoveSuffixString".} =
|
||||
## Remove the first matching suffix (in-place) from a string.
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## var
|
||||
## answers = "yeses"
|
||||
## var answers = "yeses"
|
||||
## answers.removeSuffix("es")
|
||||
## answers == "yes"
|
||||
## doAssert answers == "yes"
|
||||
var newLen = s.len
|
||||
if s.endsWith(suffix):
|
||||
newLen -= len(suffix)
|
||||
s.setLen(newLen)
|
||||
|
||||
proc removePrefix*(s: var string, chars: set[char] = Newlines) {.
|
||||
rtl, extern: "nsuRemovePrefixCharSet".} =
|
||||
## Removes all characters from `chars` from the start of the string `s`
|
||||
## (in-place).
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## var userInput = "\r\n*~Hello World!"
|
||||
## userInput.removePrefix
|
||||
## doAssert userInput == "*~Hello World!"
|
||||
## userInput.removePrefix({'~', '*'})
|
||||
## doAssert userInput == "Hello World!"
|
||||
##
|
||||
## var otherInput = "?!?Hello!?!"
|
||||
## otherInput.removePrefix({'!', '?'})
|
||||
## doAssert otherInput == "Hello!?!"
|
||||
var start = 0
|
||||
while start < s.len and s[start] in chars: start += 1
|
||||
if start > 0: s.delete(0, start - 1)
|
||||
|
||||
proc removePrefix*(s: var string, c: char) {.
|
||||
rtl, extern: "nsuRemovePrefixChar".} =
|
||||
## Removes all occurrences of a single character (in-place) from the start
|
||||
## of a string.
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## var ident = "pControl"
|
||||
## ident.removePrefix('p')
|
||||
## doAssert ident == "Control"
|
||||
removePrefix(s, chars = {c})
|
||||
|
||||
proc removePrefix*(s: var string, prefix: string) {.
|
||||
rtl, extern: "nsuRemovePrefixString".} =
|
||||
## Remove the first matching prefix (in-place) from a string.
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## var answers = "yesyes"
|
||||
## answers.removePrefix("yes")
|
||||
## doAssert answers == "yes"
|
||||
if s.startsWith(prefix):
|
||||
s.delete(0, prefix.len - 1)
|
||||
|
||||
when isMainModule:
|
||||
doAssert align("abc", 4) == " abc"
|
||||
doAssert align("a", 0) == "a"
|
||||
doAssert align("1232", 6) == " 1232"
|
||||
doAssert align("1232", 6, '#') == "##1232"
|
||||
|
||||
doAssert alignLeft("abc", 4) == "abc "
|
||||
doAssert alignLeft("a", 0) == "a"
|
||||
doAssert alignLeft("1232", 6) == "1232 "
|
||||
doAssert alignLeft("1232", 6, '#') == "1232##"
|
||||
|
||||
let
|
||||
inp = """ this is a long text -- muchlongerthan10chars and here
|
||||
it goes"""
|
||||
|
|
@ -2313,8 +2433,12 @@ when isMainModule:
|
|||
doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001"
|
||||
doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in
|
||||
["1,0e-11", "1,0e-011"]
|
||||
# bug #6589
|
||||
doAssert formatFloat(123.456, ffScientific, precision=0) in
|
||||
["1.234560e+02", "1.234560e+002"]
|
||||
|
||||
doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
|
||||
doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb"
|
||||
|
||||
block: # formatSize tests
|
||||
doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB"
|
||||
|
|
|
|||
|
|
@ -77,20 +77,17 @@ when defined(posix) and not defined(JS):
|
|||
|
||||
when not defined(freebsd) and not defined(netbsd) and not defined(openbsd):
|
||||
var timezone {.importc, header: "<time.h>".}: int
|
||||
proc tzset(): void {.importc, header: "<time.h>".}
|
||||
tzset()
|
||||
|
||||
elif defined(windows):
|
||||
import winlean
|
||||
|
||||
when defined(vcc) or defined(bcc) or defined(icl):
|
||||
# newest version of Visual C++ defines time_t to be of 64 bits
|
||||
type TimeImpl {.importc: "time_t", header: "<time.h>".} = int64
|
||||
# visual c's c runtime exposes these under a different name
|
||||
var
|
||||
timezone {.importc: "_timezone", header: "<time.h>".}: int
|
||||
else:
|
||||
type TimeImpl {.importc: "time_t", header: "<time.h>".} = int
|
||||
var
|
||||
timezone {.importc, header: "<time.h>".}: int
|
||||
# newest version of Visual C++ defines time_t to be of 64 bits
|
||||
type TimeImpl {.importc: "time_t", header: "<time.h>".} = int64
|
||||
# visual c's c runtime exposes these under a different name
|
||||
var
|
||||
timezone {.importc: "_timezone", header: "<time.h>".}: int
|
||||
|
||||
type
|
||||
Time* = distinct TimeImpl
|
||||
|
|
@ -1028,7 +1025,7 @@ proc countLeapYears*(yearSpan: int): int =
|
|||
## counts the number of leap years up to January 1st of a given year.
|
||||
## Keep in mind that if specified year is a leap year, the leap day
|
||||
## has not happened before January 1st of that year.
|
||||
(((yearSpan - 1) / 4) - ((yearSpan - 1) / 100) + ((yearSpan - 1) / 400)).int
|
||||
(yearSpan - 1) div 4 - (yearSpan - 1) div 100 + (yearSpan - 1) div 400
|
||||
|
||||
proc countDays*(yearSpan: int): int =
|
||||
## Returns the number of days spanned by a given number of years.
|
||||
|
|
|
|||
|
|
@ -31,6 +31,10 @@ proc name*(t: typedesc): string {.magic: "TypeTrait".}
|
|||
## test(@['A','B'])
|
||||
## # --> type: seq[char], value: @[A, B]
|
||||
|
||||
proc `$`*(t: typedesc): string =
|
||||
## An alias for `name`.
|
||||
name(t)
|
||||
|
||||
proc arity*(t: typedesc): int {.magic: "TypeTrait".}
|
||||
## Returns the arity of the given type
|
||||
|
||||
|
|
@ -49,3 +53,15 @@ proc stripGenericParams*(t: typedesc): typedesc {.magic: "TypeTrait".}
|
|||
## This trait is similar to `genericHead`, but instead of producing
|
||||
## error for non-generic types, it will just return them unmodified
|
||||
|
||||
proc supportsCopyMem*(t: typedesc): bool {.magic: "TypeTrait".}
|
||||
## This trait returns true iff the type ``t`` is safe to use for
|
||||
## `copyMem`:idx:. Other languages name a type like these `blob`:idx:.
|
||||
|
||||
|
||||
when isMainModule:
|
||||
# echo type(42)
|
||||
import streams
|
||||
var ss = newStringStream()
|
||||
ss.write($type(42)) # needs `$`
|
||||
ss.setPosition(0)
|
||||
doAssert ss.readAll() == "int"
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ proc runeReverseOffset*(s: string, rev:Positive): (int, int) =
|
|||
|
||||
proc runeSubStr*(s: string, pos:int, len:int = int.high): string =
|
||||
## Returns the UTF-8 substring starting at codepoint pos
|
||||
## with len codepoints. If pos or len is negativ they count from
|
||||
## with len codepoints. If pos or len is negative they count from
|
||||
## the end of the string. If len is not given it means the longest
|
||||
## possible string.
|
||||
##
|
||||
|
|
|
|||
|
|
@ -312,7 +312,7 @@ proc ensureInitialized() =
|
|||
|
||||
if not testsToRun.isValid:
|
||||
testsToRun.init()
|
||||
when declared(os):
|
||||
when declared(paramCount):
|
||||
# Read tests to run from the command line.
|
||||
for i in 1 .. paramCount():
|
||||
testsToRun.incl(paramStr(i))
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ proc combine*(base: Uri, reference: Uri): Uri =
|
|||
proc combine*(uris: varargs[Uri]): Uri =
|
||||
## Combines multiple URIs together.
|
||||
result = uris[0]
|
||||
for i in 1 .. <uris.len:
|
||||
for i in 1 ..< uris.len:
|
||||
result = combine(result, uris[i])
|
||||
|
||||
proc isAbsolute*(uri: Uri): bool =
|
||||
|
|
@ -278,7 +278,9 @@ proc `/`*(x: Uri, path: string): Uri =
|
|||
result = x
|
||||
|
||||
if result.path.len == 0:
|
||||
result.path = path
|
||||
if path[0] != '/':
|
||||
result.path = "/"
|
||||
result.path.add(path)
|
||||
return
|
||||
|
||||
if result.path[result.path.len-1] == '/':
|
||||
|
|
@ -476,6 +478,11 @@ when isMainModule:
|
|||
let foo = parseUri("http://example.com") / "/baz"
|
||||
doAssert foo.path == "/baz"
|
||||
|
||||
# bug found on stream 13/10/17
|
||||
block:
|
||||
let foo = parseUri("http://localhost:9515") / "status"
|
||||
doAssert $foo == "http://localhost:9515/status"
|
||||
|
||||
# isAbsolute tests
|
||||
block:
|
||||
doAssert "www.google.com".parseUri().isAbsolute() == false
|
||||
|
|
@ -515,4 +522,6 @@ when isMainModule:
|
|||
doAssert "https://example.com/about".parseUri().isAbsolute == true
|
||||
doAssert "https://example.com/about/staff.html".parseUri().isAbsolute == true
|
||||
doAssert "https://example.com/about/staff.html?".parseUri().isAbsolute == true
|
||||
doAssert "https://example.com/about/staff.html?parameters".parseUri().isAbsolute == true
|
||||
doAssert "https://example.com/about/staff.html?parameters".parseUri().isAbsolute == true
|
||||
|
||||
echo("All good!")
|
||||
237
lib/system.nim
237
lib/system.nim
|
|
@ -275,7 +275,7 @@ proc low*[T](x: T): T {.magic: "Low", noSideEffect.}
|
|||
proc low*[I, T](x: typeDesc[array[I, T]]): I {.magic: "Low", noSideEffect.}
|
||||
proc low*(x: cstring): int {.magic: "Low", noSideEffect.}
|
||||
proc low*(x: string): int {.magic: "Low", noSideEffect.}
|
||||
## returns the lowest possible index of an array, a sequence, a string or
|
||||
## returns the lowest possible index of an array, a sequence, a string or
|
||||
## the lowest possible value of an ordinal value `x`. As a special
|
||||
## semantic rule, `x` may also be a type identifier.
|
||||
##
|
||||
|
|
@ -285,6 +285,13 @@ proc low*(x: string): int {.magic: "Low", noSideEffect.}
|
|||
## low(2) #=> -9223372036854775808
|
||||
## low(int) #=> -9223372036854775808
|
||||
|
||||
proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".}
|
||||
## use this instead of `=` for a `shallow copy`:idx:. The shallow copy
|
||||
## only changes the semantics for sequences and strings (and types which
|
||||
## contain those). Be careful with the changed semantics though! There
|
||||
## is a reason why the default assignment does a deep copy of sequences
|
||||
## and strings.
|
||||
|
||||
when defined(nimArrIdx):
|
||||
# :array|openarray|string|seq|cstring|tuple
|
||||
proc `[]`*[I: Ordinal;T](a: T; i: I): T {.
|
||||
|
|
@ -292,15 +299,21 @@ when defined(nimArrIdx):
|
|||
proc `[]=`*[I: Ordinal;T,S](a: T; i: I;
|
||||
x: S) {.noSideEffect, magic: "ArrPut".}
|
||||
proc `=`*[T](dest: var T; src: T) {.noSideEffect, magic: "Asgn".}
|
||||
when defined(nimNewRuntime):
|
||||
proc `=destroy`*[T](x: var T) {.inline, magic: "Asgn".} =
|
||||
## generic `destructor`:idx: implementation that can be overriden.
|
||||
discard
|
||||
proc `=sink`*[T](x: var T; y: T) {.inline, magic: "Asgn".} =
|
||||
## generic `sink`:idx: implementation that can be overriden.
|
||||
shallowCopy(x, y)
|
||||
|
||||
type
|
||||
Slice*[T] = object ## builtin slice type
|
||||
a*, b*: T ## the bounds
|
||||
HSlice*[T, U] = object ## "heterogenous" slice type
|
||||
a*: T ## the lower bound (inclusive)
|
||||
b*: U ## the upper bound (inclusive)
|
||||
Slice*[T] = HSlice[T, T] ## an alias for ``HSlice[T, T]``
|
||||
|
||||
when defined(nimalias):
|
||||
{.deprecated: [TSlice: Slice].}
|
||||
|
||||
proc `..`*[T](a, b: T): Slice[T] {.noSideEffect, inline, magic: "DotDot".} =
|
||||
proc `..`*[T, U](a: T, b: U): HSlice[T, U] {.noSideEffect, inline, magic: "DotDot".} =
|
||||
## `slice`:idx: operator that constructs an interval ``[a, b]``, both `a`
|
||||
## and `b` are inclusive. Slices can also be used in the set constructor
|
||||
## and in ordinal case statements, but then they are special-cased by the
|
||||
|
|
@ -308,7 +321,7 @@ proc `..`*[T](a, b: T): Slice[T] {.noSideEffect, inline, magic: "DotDot".} =
|
|||
result.a = a
|
||||
result.b = b
|
||||
|
||||
proc `..`*[T](b: T): Slice[T] {.noSideEffect, inline, magic: "DotDot".} =
|
||||
proc `..`*[T](b: T): HSlice[int, T] {.noSideEffect, inline, magic: "DotDot".} =
|
||||
## `slice`:idx: operator that constructs an interval ``[default(T), b]``
|
||||
result.b = b
|
||||
|
||||
|
|
@ -638,13 +651,17 @@ proc sizeof*[T](x: T): int {.magic: "SizeOf", noSideEffect.}
|
|||
when defined(nimtypedescfixed):
|
||||
proc sizeof*(x: typedesc): int {.magic: "SizeOf", noSideEffect.}
|
||||
|
||||
proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect.}
|
||||
proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect, deprecated.}
|
||||
## unary ``<`` that can be used for nice looking excluding ranges:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## for i in 0 .. <10: echo i #=> 0 1 2 3 4 5 6 7 8 9
|
||||
##
|
||||
## Semantically this is the same as ``pred``.
|
||||
##
|
||||
## **Deprecated since version 0.18.0**. For the common excluding range
|
||||
## write ``0 ..< 10`` instead of ``0 .. < 10`` (look at the spacing).
|
||||
## For ``<x`` write ``pred(x)``.
|
||||
|
||||
proc succ*[T](x: Ordinal[T], y = 1): T {.magic: "Succ", noSideEffect.}
|
||||
## returns the ``y``-th successor of the value ``x``. ``T`` has to be
|
||||
|
|
@ -1150,7 +1167,7 @@ proc contains*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.}
|
|||
## is achieved by reversing the parameters for ``contains``; ``in`` then
|
||||
## passes its arguments in reverse order.
|
||||
|
||||
proc contains*[T](s: Slice[T], value: T): bool {.noSideEffect, inline.} =
|
||||
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 iff
|
||||
## `value >= s.a and value <= s.b`
|
||||
##
|
||||
|
|
@ -1429,7 +1446,8 @@ when defined(nimdoc):
|
|||
## <#GC_fullCollect>`_.
|
||||
##
|
||||
## The proc ``quit(QuitSuccess)`` is called implicitly when your nim
|
||||
## program finishes without incident. A raised unhandled exception is
|
||||
## program finishes without incident for platforms where this is the
|
||||
## expected behavior. A raised unhandled exception is
|
||||
## equivalent to calling ``quit(QuitFailure)``.
|
||||
##
|
||||
## Note that this is a *runtime* call and using ``quit`` inside a macro won't
|
||||
|
|
@ -1444,7 +1462,7 @@ elif defined(genode):
|
|||
header: "<base/sleep.h>".}
|
||||
|
||||
elif defined(nodejs):
|
||||
proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit",
|
||||
proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit",
|
||||
importc: "process.exit", noreturn.}
|
||||
|
||||
else:
|
||||
|
|
@ -1480,13 +1498,6 @@ proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} =
|
|||
setLen(x, xl + y.len)
|
||||
for i in 0..high(y): x[xl+i] = y[i]
|
||||
|
||||
proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".}
|
||||
## use this instead of `=` for a `shallow copy`:idx:. The shallow copy
|
||||
## only changes the semantics for sequences and strings (and types which
|
||||
## contain those). Be careful with the changed semantics though! There
|
||||
## is a reason why the default assignment does a deep copy of sequences
|
||||
## and strings.
|
||||
|
||||
proc del*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
|
||||
## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
|
||||
## This is an O(1) operation.
|
||||
|
|
@ -1875,7 +1886,7 @@ proc `$` *(x: float): string {.magic: "FloatToStr", noSideEffect.}
|
|||
proc `$` *(x: bool): string {.magic: "BoolToStr", noSideEffect.}
|
||||
## The stringify operator for a boolean argument. Returns `x`
|
||||
## converted to the string "false" or "true".
|
||||
|
||||
#
|
||||
proc `$` *(x: char): string {.magic: "CharToStr", noSideEffect.}
|
||||
## The stringify operator for a character argument. Returns `x`
|
||||
## converted to a string.
|
||||
|
|
@ -2065,6 +2076,9 @@ proc max*[T](x, y: T): T =
|
|||
if y <= x: x else: y
|
||||
{.pop.}
|
||||
|
||||
proc high*(T: typedesc[SomeReal]): T = Inf
|
||||
proc low*(T: typedesc[SomeReal]): T = NegInf
|
||||
|
||||
proc clamp*[T](x, a, b: T): T =
|
||||
## limits the value ``x`` within the interval [a, b]
|
||||
##
|
||||
|
|
@ -2075,7 +2089,7 @@ proc clamp*[T](x, a, b: T): T =
|
|||
if x > b: return b
|
||||
return x
|
||||
|
||||
proc len*[T: Ordinal](x: Slice[T]): int {.noSideEffect, inline.} =
|
||||
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
|
||||
##
|
||||
## .. code-block:: Nim
|
||||
|
|
@ -2143,7 +2157,7 @@ iterator items*(E: typedesc[enum]): E =
|
|||
for v in low(E)..high(E):
|
||||
yield v
|
||||
|
||||
iterator items*[T](s: Slice[T]): T =
|
||||
iterator items*[T](s: HSlice[T, T]): T =
|
||||
## iterates over the slice `s`, yielding each value between `s.a` and `s.b`
|
||||
## (inclusively).
|
||||
for x in s.a..s.b:
|
||||
|
|
@ -2437,20 +2451,28 @@ proc `$`*[T: tuple|object](x: T): string =
|
|||
result.add("...")
|
||||
result.add(")")
|
||||
|
||||
proc collectionToString[T: set | seq](x: T, b, e: string): string =
|
||||
when x is seq:
|
||||
if x.isNil: return "nil"
|
||||
result = b
|
||||
proc collectionToString[T](x: T, prefix, separator, suffix: string): string =
|
||||
result = prefix
|
||||
var firstElement = true
|
||||
for value in items(x):
|
||||
if not firstElement: result.add(", ")
|
||||
if firstElement:
|
||||
firstElement = false
|
||||
else:
|
||||
result.add(separator)
|
||||
|
||||
when compiles(value.isNil):
|
||||
if value.isNil: result.add "nil"
|
||||
else: result.add($value)
|
||||
# this branch should not be necessary
|
||||
if value.isNil:
|
||||
result.add "nil"
|
||||
else:
|
||||
result.add($value)
|
||||
# prevent temporary string allocation
|
||||
elif compiles(result.add(value)):
|
||||
result.add(value)
|
||||
else:
|
||||
result.add($value)
|
||||
firstElement = false
|
||||
result.add(e)
|
||||
|
||||
result.add(suffix)
|
||||
|
||||
proc `$`*[T](x: set[T]): string =
|
||||
## generic ``$`` operator for sets that is lifted from the components
|
||||
|
|
@ -2458,7 +2480,7 @@ proc `$`*[T](x: set[T]): string =
|
|||
##
|
||||
## .. code-block:: nim
|
||||
## ${23, 45} == "{23, 45}"
|
||||
collectionToString(x, "{", "}")
|
||||
collectionToString(x, "{", ", ", "}")
|
||||
|
||||
proc `$`*[T](x: seq[T]): string =
|
||||
## generic ``$`` operator for seqs that is lifted from the components
|
||||
|
|
@ -2466,13 +2488,10 @@ proc `$`*[T](x: seq[T]): string =
|
|||
##
|
||||
## .. code-block:: nim
|
||||
## $(@[23, 45]) == "@[23, 45]"
|
||||
collectionToString(x, "@[", "]")
|
||||
|
||||
when false:
|
||||
# causes bootstrapping to fail as we use array of chars and cstring should
|
||||
# match better ...
|
||||
proc `$`*[T, IDX](x: array[IDX, T]): string =
|
||||
collectionToString(x, "[", "]")
|
||||
if x.isNil:
|
||||
"nil"
|
||||
else:
|
||||
collectionToString(x, "@[", ", ", "]")
|
||||
|
||||
# ----------------- GC interface ---------------------------------------------
|
||||
|
||||
|
|
@ -2816,7 +2835,7 @@ when not defined(JS): #and not defined(nimscript):
|
|||
fmRead, ## Open the file for read access only.
|
||||
fmWrite, ## Open the file for write access only.
|
||||
## If the file does not exist, it will be
|
||||
## created.
|
||||
## created. Existing files will be cleared!
|
||||
fmReadWrite, ## Open the file for read and write access.
|
||||
## If the file does not exist, it will be
|
||||
## created. Existing files will be cleared!
|
||||
|
|
@ -2872,7 +2891,7 @@ when not defined(JS): #and not defined(nimscript):
|
|||
importc: when defined(bcc): "setmode" else: "_setmode",
|
||||
header: "<io.h>".}
|
||||
var
|
||||
O_BINARY {.importc: "O_BINARY", nodecl.}: cint
|
||||
O_BINARY {.importc: "_O_BINARY", header:"<fcntl.h>".}: cint
|
||||
|
||||
# we use binary mode on Windows:
|
||||
c_setmode(c_fileno(stdin), O_BINARY)
|
||||
|
|
@ -3329,6 +3348,10 @@ elif defined(JS):
|
|||
include "system/sysio"
|
||||
|
||||
|
||||
proc `$`*[T, IDX](x: array[IDX, T]): string =
|
||||
## generic ``$`` operator for arrays that is lifted from the components
|
||||
collectionToString(x, "[", ", ", "]")
|
||||
|
||||
proc quit*(errormsg: string, errorcode = QuitFailure) {.noReturn.} =
|
||||
## a shorthand for ``echo(errormsg); quit(errorcode)``.
|
||||
echo(errormsg)
|
||||
|
|
@ -3393,6 +3416,29 @@ proc `/`*(x, y: int): float {.inline, noSideEffect.} =
|
|||
## integer division that results in a float.
|
||||
result = toFloat(x) / toFloat(y)
|
||||
|
||||
type
|
||||
BackwardsIndex* = distinct int ## type that is constructed by ``^`` for
|
||||
## reversed array accesses.
|
||||
|
||||
template `^`*(x: int): BackwardsIndex = BackwardsIndex(x)
|
||||
## builtin `roof`:idx: operator that can be used for convenient array access.
|
||||
## ``a[^x]`` is a shortcut for ``a[a.len-x]``.
|
||||
|
||||
template `..^`*(a, b: untyped): untyped =
|
||||
## a shortcut for '.. ^' to avoid the common gotcha that a space between
|
||||
## '..' and '^' is required.
|
||||
a .. ^b
|
||||
|
||||
template `..<`*(a, b: untyped): untyped =
|
||||
## a shortcut for 'a..pred(b)'.
|
||||
a .. pred(b)
|
||||
|
||||
iterator `..<`*[S,T](a: S, b: T): T =
|
||||
var i = T(a)
|
||||
while i < b:
|
||||
yield i
|
||||
inc i
|
||||
|
||||
template spliceImpl(s, a, L, b: untyped): untyped =
|
||||
# make room for additional elements or cut:
|
||||
var shift = b.len - max(0,L) # ignore negative slice size
|
||||
|
|
@ -3406,19 +3452,22 @@ template spliceImpl(s, a, L, b: untyped): untyped =
|
|||
# cut down:
|
||||
setLen(s, newLen)
|
||||
# fill the hole:
|
||||
for i in 0 .. <b.len: s[a+i] = b[i]
|
||||
for i in 0 ..< b.len: s[a+i] = b[i]
|
||||
|
||||
template `^^`(s, i: untyped): untyped =
|
||||
(when i is BackwardsIndex: s.len - int(i) else: int(i))
|
||||
|
||||
when hasAlloc or defined(nimscript):
|
||||
proc `[]`*(s: string, x: Slice[int]): string {.inline.} =
|
||||
proc `[]`*[T, U](s: string, x: HSlice[T, U]): string {.inline.} =
|
||||
## slice operation for strings.
|
||||
## returns the inclusive range [s[x.a], s[x.b]]:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## var s = "abcdef"
|
||||
## assert s[1..3] == "bcd"
|
||||
result = s.substr(x.a, x.b)
|
||||
result = s.substr(s ^^ x.a, s ^^ x.b)
|
||||
|
||||
proc `[]=`*(s: var string, x: Slice[int], b: string) =
|
||||
proc `[]=`*[T, U](s: var string, x: HSlice[T, U], b: string) =
|
||||
## slice assignment for strings. If
|
||||
## ``b.len`` is not exactly the number of elements that are referred to
|
||||
## by `x`, a `splice`:idx: is performed:
|
||||
|
|
@ -3427,75 +3476,74 @@ when hasAlloc or defined(nimscript):
|
|||
## var s = "abcdef"
|
||||
## s[1 .. ^2] = "xyz"
|
||||
## assert s == "axyzf"
|
||||
var a = x.a
|
||||
var L = x.b - a + 1
|
||||
var a = s ^^ x.a
|
||||
var L = (s ^^ x.b) - a + 1
|
||||
if L == b.len:
|
||||
for i in 0 .. <L: s[i+a] = b[i]
|
||||
for i in 0..<L: s[i+a] = b[i]
|
||||
else:
|
||||
spliceImpl(s, a, L, b)
|
||||
|
||||
proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[int]): seq[T] =
|
||||
proc `[]`*[Idx, T, U, V](a: array[Idx, T], x: HSlice[U, V]): seq[T] =
|
||||
## slice operation for arrays.
|
||||
## returns the inclusive range [a[x.a], a[x.b]]:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## var a = [1,2,3,4]
|
||||
## assert a[0..2] == @[1,2,3]
|
||||
when low(a) < 0:
|
||||
{.error: "Slicing for arrays with negative indices is unsupported.".}
|
||||
var L = x.b - x.a + 1
|
||||
let xa = a ^^ x.a
|
||||
let L = (a ^^ x.b) - xa + 1
|
||||
result = newSeq[T](L)
|
||||
for i in 0.. <L: result[i] = a[i + x.a]
|
||||
for i in 0..<L: result[i] = a[Idx(i + xa + int low(a))]
|
||||
|
||||
proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[int], b: openArray[T]) =
|
||||
proc `[]=`*[Idx, T, U, V](a: var array[Idx, T], x: HSlice[U, V], b: openArray[T]) =
|
||||
## slice assignment for arrays.
|
||||
when low(a) < 0:
|
||||
{.error: "Slicing for arrays with negative indices is unsupported.".}
|
||||
var L = x.b - x.a + 1
|
||||
let xa = a ^^ x.a
|
||||
let L = (a ^^ x.b) - xa + 1
|
||||
if L == b.len:
|
||||
for i in 0 .. <L: a[i+x.a] = b[i]
|
||||
for i in 0..<L: a[Idx(i + xa + int low(a))] = b[i]
|
||||
else:
|
||||
sysFatal(RangeError, "different lengths for slice assignment")
|
||||
|
||||
proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[Idx]): seq[T] =
|
||||
## slice operation for arrays.
|
||||
var L = ord(x.b) - ord(x.a) + 1
|
||||
newSeq(result, L)
|
||||
for i in 0.. <L:
|
||||
result[i] = a[Idx(ord(x.a) + i)]
|
||||
|
||||
proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[Idx], b: openArray[T]) =
|
||||
## slice assignment for arrays.
|
||||
var L = ord(x.b) - ord(x.a) + 1
|
||||
if L == b.len:
|
||||
for i in 0 .. <L:
|
||||
a[Idx(ord(x.a) + i)] = b[i]
|
||||
else:
|
||||
sysFatal(RangeError, "different lengths for slice assignment")
|
||||
|
||||
proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] =
|
||||
proc `[]`*[T, U, V](s: openArray[T], x: HSlice[U, V]): seq[T] =
|
||||
## slice operation for sequences.
|
||||
## returns the inclusive range [s[x.a], s[x.b]]:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## var s = @[1,2,3,4]
|
||||
## assert s[0..2] == @[1,2,3]
|
||||
var a = x.a
|
||||
var L = x.b - a + 1
|
||||
let a = s ^^ x.a
|
||||
let L = (s ^^ x.b) - a + 1
|
||||
newSeq(result, L)
|
||||
for i in 0.. <L: result[i] = s[i + a]
|
||||
for i in 0 ..< L: result[i] = s[i + a]
|
||||
|
||||
proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) =
|
||||
proc `[]=`*[T, U, V](s: var seq[T], x: HSlice[U, V], b: openArray[T]) =
|
||||
## slice assignment for sequences. If
|
||||
## ``b.len`` is not exactly the number of elements that are referred to
|
||||
## by `x`, a `splice`:idx: is performed.
|
||||
var a = x.a
|
||||
var L = x.b - a + 1
|
||||
let a = s ^^ x.a
|
||||
let L = (s ^^ x.b) - a + 1
|
||||
if L == b.len:
|
||||
for i in 0 .. <L: s[i+a] = b[i]
|
||||
for i in 0 ..< L: s[i+a] = b[i]
|
||||
else:
|
||||
spliceImpl(s, a, L, b)
|
||||
|
||||
proc `[]`*[T](s: openArray[T]; i: BackwardsIndex): T {.inline.} = s[s.len - int(i)]
|
||||
proc `[]`*[Idx, T](a: array[Idx, T]; i: BackwardsIndex): T {.inline.} =
|
||||
a[Idx(a.len - int(i) + int low(a))]
|
||||
proc `[]`*(s: string; i: BackwardsIndex): char {.inline.} = s[s.len - int(i)]
|
||||
|
||||
proc `[]`*[T](s: var openArray[T]; i: BackwardsIndex): var T {.inline.} =
|
||||
s[s.len - int(i)]
|
||||
proc `[]`*[Idx, T](a: var array[Idx, T]; i: BackwardsIndex): var T {.inline.} =
|
||||
a[Idx(a.len - int(i) + int low(a))]
|
||||
|
||||
proc `[]=`*[T](s: var openArray[T]; i: BackwardsIndex; x: T) {.inline.} =
|
||||
s[s.len - int(i)] = x
|
||||
proc `[]=`*[Idx, T](a: var array[Idx, T]; i: BackwardsIndex; x: T) {.inline.} =
|
||||
a[Idx(a.len - int(i) + int low(a))] = x
|
||||
proc `[]=`*(s: var string; i: BackwardsIndex; x: char) {.inline.} =
|
||||
s[s.len - int(i)] = x
|
||||
|
||||
proc slurp*(filename: string): string {.magic: "Slurp".}
|
||||
## This is an alias for `staticRead <#staticRead>`_.
|
||||
|
||||
|
|
@ -3836,31 +3884,6 @@ proc procCall*(x: untyped) {.magic: "ProcCall", compileTime.} =
|
|||
## procCall someMethod(a, b)
|
||||
discard
|
||||
|
||||
proc `^`*[T](x: int; y: openArray[T]): int {.noSideEffect, magic: "Roof".}
|
||||
proc `^`*(x: int): int {.noSideEffect, magic: "Roof".} =
|
||||
## builtin `roof`:idx: operator that can be used for convenient array access.
|
||||
## ``a[^x]`` is rewritten to ``a[a.len-x]``. However currently the ``a``
|
||||
## expression must not have side effects for this to compile. Note that since
|
||||
## this is a builtin, it automatically works for all kinds of
|
||||
## overloaded ``[]`` or ``[]=`` accessors.
|
||||
discard
|
||||
|
||||
template `..^`*(a, b: untyped): untyped =
|
||||
## a shortcut for '.. ^' to avoid the common gotcha that a space between
|
||||
## '..' and '^' is required.
|
||||
a .. ^b
|
||||
|
||||
template `..<`*(a, b: untyped): untyped {.dirty.} =
|
||||
## a shortcut for '.. <' to avoid the common gotcha that a space between
|
||||
## '..' and '<' is required.
|
||||
a .. <b
|
||||
|
||||
iterator `..<`*[S,T](a: S, b: T): T =
|
||||
var i = T(a)
|
||||
while i < b:
|
||||
yield i
|
||||
inc i
|
||||
|
||||
proc xlen*(x: string): int {.magic: "XLenStr", noSideEffect.} = discard
|
||||
proc xlen*[T](x: seq[T]): int {.magic: "XLenSeq", noSideEffect.} =
|
||||
## returns the length of a sequence or a string without testing for 'nil'.
|
||||
|
|
|
|||
|
|
@ -301,13 +301,14 @@ proc pageAddr(p: pointer): PChunk {.inline.} =
|
|||
result = cast[PChunk](cast[ByteAddress](p) and not PageMask)
|
||||
#sysAssert(Contains(allocator.chunkStarts, pageIndex(result)))
|
||||
|
||||
proc writeFreeList(a: MemRegion) =
|
||||
var it = a.freeChunksList
|
||||
c_fprintf(stdout, "freeChunksList: %p\n", it)
|
||||
while it != nil:
|
||||
c_fprintf(stdout, "it: %p, next: %p, prev: %p, size: %ld\n",
|
||||
it, it.next, it.prev, it.size)
|
||||
it = it.next
|
||||
when false:
|
||||
proc writeFreeList(a: MemRegion) =
|
||||
var it = a.freeChunksList
|
||||
c_fprintf(stdout, "freeChunksList: %p\n", it)
|
||||
while it != nil:
|
||||
c_fprintf(stdout, "it: %p, next: %p, prev: %p, size: %ld\n",
|
||||
it, it.next, it.prev, it.size)
|
||||
it = it.next
|
||||
|
||||
const nimMaxHeap {.intdefine.} = 0
|
||||
|
||||
|
|
|
|||
|
|
@ -103,8 +103,12 @@ proc c_sprintf(buf, frmt: cstring): cint {.
|
|||
importc: "sprintf", header: "<stdio.h>", varargs, noSideEffect.}
|
||||
# we use it only in a way that cannot lead to security issues
|
||||
|
||||
proc c_fileno(f: File): cint {.
|
||||
importc: "fileno", header: "<fcntl.h>".}
|
||||
when defined(windows):
|
||||
proc c_fileno(f: File): cint {.
|
||||
importc: "_fileno", header: "<stdio.h>".}
|
||||
else:
|
||||
proc c_fileno(f: File): cint {.
|
||||
importc: "fileno", header: "<fcntl.h>".}
|
||||
|
||||
proc c_malloc(size: csize): pointer {.
|
||||
importc: "malloc", header: "<stdlib.h>".}
|
||||
|
|
|
|||
|
|
@ -61,13 +61,17 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
|
|||
unsureAsgnRef(x, s2)
|
||||
return
|
||||
sysAssert(dest != nil, "genericAssignAux 3")
|
||||
unsureAsgnRef(x, newSeq(mt, seq.len))
|
||||
var dst = cast[ByteAddress](cast[PPointer](dest)[])
|
||||
if ntfNoRefs in mt.base.flags:
|
||||
var ss = nimNewSeqOfCap(mt, seq.len)
|
||||
cast[PGenericSeq](ss).len = seq.len
|
||||
unsureAsgnRef(x, ss)
|
||||
var dst = cast[ByteAddress](cast[PPointer](dest)[])
|
||||
copyMem(cast[pointer](dst +% GenericSeqSize),
|
||||
cast[pointer](cast[ByteAddress](s2) +% GenericSeqSize),
|
||||
seq.len * mt.base.size)
|
||||
else:
|
||||
unsureAsgnRef(x, newSeq(mt, seq.len))
|
||||
var dst = cast[ByteAddress](cast[PPointer](dest)[])
|
||||
for i in 0..seq.len-1:
|
||||
genericAssignAux(
|
||||
cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ proc fileMatches(c, bp: cstring): bool =
|
|||
|
||||
proc canonFilename*(filename: cstring): cstring =
|
||||
## returns 'nil' if the filename cannot be found.
|
||||
for i in 0 .. <dbgFilenameLen:
|
||||
for i in 0 .. dbgFilenameLen-1:
|
||||
result = dbgFilenames[i]
|
||||
if fileMatches(result, filename): return result
|
||||
result = nil
|
||||
|
|
@ -261,7 +261,7 @@ proc genericHash(dest: pointer, mt: PNimType): int =
|
|||
proc dbgRegisterWatchpoint(address: pointer, name: cstring,
|
||||
typ: PNimType) {.compilerproc.} =
|
||||
let L = watchPointsLen
|
||||
for i in 0.. <L:
|
||||
for i in 0 .. pred(L):
|
||||
if watchPoints[i].name == name:
|
||||
# address may have changed:
|
||||
watchPoints[i].address = address
|
||||
|
|
@ -288,7 +288,7 @@ var
|
|||
|
||||
proc checkWatchpoints =
|
||||
let L = watchPointsLen
|
||||
for i in 0.. <L:
|
||||
for i in 0 .. pred(L):
|
||||
let newHash = genericHash(watchPoints[i].address, watchPoints[i].typ)
|
||||
if newHash != watchPoints[i].oldValue:
|
||||
dbgWatchpointHook(watchPoints[i].name)
|
||||
|
|
|
|||
|
|
@ -142,7 +142,10 @@ elif defined(windows) or defined(dos):
|
|||
dec(m)
|
||||
k = k div 10
|
||||
if k == 0: break
|
||||
result = getProcAddress(cast[THINSTANCE](lib), decorated)
|
||||
when defined(nimNoArrayToCstringConversion):
|
||||
result = getProcAddress(cast[THINSTANCE](lib), addr decorated)
|
||||
else:
|
||||
result = getProcAddress(cast[THINSTANCE](lib), decorated)
|
||||
if result != nil: return
|
||||
procAddrError(name)
|
||||
|
||||
|
|
|
|||
|
|
@ -76,10 +76,10 @@ proc `==`(a, b: StaticStr): bool =
|
|||
return true
|
||||
|
||||
proc `==`(a: StaticStr, b: cstring): bool =
|
||||
result = c_strcmp(a.data, b) == 0
|
||||
result = c_strcmp(unsafeAddr a.data, b) == 0
|
||||
|
||||
proc write(f: File, s: StaticStr) =
|
||||
write(f, cstring(s.data))
|
||||
write(f, cstring(unsafeAddr s.data))
|
||||
|
||||
proc listBreakPoints() =
|
||||
write(stdout, EndbBeg)
|
||||
|
|
@ -260,8 +260,8 @@ proc parseBreakpoint(s: cstring, start: int): Breakpoint =
|
|||
if result.high == 0: result.high = result.low
|
||||
i = scanFilename(s, dbgTemp, i)
|
||||
if dbgTemp.len != 0:
|
||||
if not hasExt(dbgTemp.data): add(dbgTemp, ".nim")
|
||||
result.filename = canonFilename(dbgTemp.data.cstring)
|
||||
if not hasExt(addr dbgTemp.data): add(dbgTemp, ".nim")
|
||||
result.filename = canonFilename(addr dbgTemp.data)
|
||||
if result.filename.isNil:
|
||||
debugOut("[Warning] no breakpoint could be set; unknown filename ")
|
||||
return
|
||||
|
|
@ -292,12 +292,12 @@ proc dbgEvaluate(stream: File, s: cstring, start: int, f: PFrame) =
|
|||
i = scanAndAppendWord(s, dbgTemp, i)
|
||||
for i in 0 .. getGlobalLen()-1:
|
||||
let v = getGlobal(i)
|
||||
if c_strcmp(v.name, dbgTemp.data) == 0:
|
||||
if c_strcmp(v.name, addr dbgTemp.data) == 0:
|
||||
writeVariable(stream, v)
|
||||
else:
|
||||
for i in 0 .. f.len-1:
|
||||
let v = getLocal(f, i)
|
||||
if c_strcmp(v.name, dbgTemp.data) == 0:
|
||||
if c_strcmp(v.name, addr dbgTemp.data) == 0:
|
||||
writeVariable(stream, v)
|
||||
|
||||
proc dbgOut(s: cstring, start: int, currFrame: PFrame) =
|
||||
|
|
@ -306,7 +306,7 @@ proc dbgOut(s: cstring, start: int, currFrame: PFrame) =
|
|||
if dbgTemp.len == 0:
|
||||
invalidCommand()
|
||||
return
|
||||
var stream = openAppend(dbgTemp.data)
|
||||
var stream = openAppend(addr dbgTemp.data)
|
||||
if stream == nil:
|
||||
debugOut("[Warning] could not open or create file ")
|
||||
return
|
||||
|
|
@ -320,7 +320,7 @@ proc dbgStackFrame(s: cstring, start: int, currFrame: PFrame) =
|
|||
# just write it to stdout:
|
||||
listFrame(stdout, currFrame)
|
||||
else:
|
||||
var stream = openAppend(dbgTemp.data)
|
||||
var stream = openAppend(addr dbgTemp.data)
|
||||
if stream == nil:
|
||||
debugOut("[Warning] could not open or create file ")
|
||||
return
|
||||
|
|
@ -369,7 +369,7 @@ proc commandPrompt() =
|
|||
if not readLine(stdin, dbgUser): break
|
||||
if dbgUser.len == 0: dbgUser.len = oldLen
|
||||
# now look what we have to do:
|
||||
var i = scanWord(dbgUser.data, dbgTemp, 0)
|
||||
var i = scanWord(addr dbgUser.data, dbgTemp, 0)
|
||||
template `?`(x: expr): expr = dbgTemp == cstring(x)
|
||||
if ?"s" or ?"step":
|
||||
dbgState = dbStepInto
|
||||
|
|
@ -400,13 +400,13 @@ proc commandPrompt() =
|
|||
prevState = dbgState
|
||||
prevSkipFrame = dbgSkipToFrame
|
||||
dbgState = dbSkipCurrent
|
||||
dbgEvaluate(stdout, dbgUser.data, i, dbgFramePtr)
|
||||
dbgEvaluate(stdout, addr dbgUser.data, i, dbgFramePtr)
|
||||
dbgState = prevState
|
||||
dbgSkipToFrame = prevSkipFrame
|
||||
elif ?"o" or ?"out":
|
||||
dbgOut(dbgUser.data, i, dbgFramePtr)
|
||||
dbgOut(addr dbgUser.data, i, dbgFramePtr)
|
||||
elif ?"stackframe":
|
||||
dbgStackFrame(dbgUser.data, i, dbgFramePtr)
|
||||
dbgStackFrame(addr dbgUser.data, i, dbgFramePtr)
|
||||
elif ?"w" or ?"where":
|
||||
dbgShowExecutionPoint()
|
||||
elif ?"l" or ?"locals":
|
||||
|
|
@ -444,16 +444,16 @@ proc commandPrompt() =
|
|||
elif ?"bt" or ?"backtrace":
|
||||
dbgWriteStackTrace(framePtr)
|
||||
elif ?"b" or ?"break":
|
||||
createBreakPoint(dbgUser.data, i)
|
||||
createBreakPoint(addr dbgUser.data, i)
|
||||
elif ?"breakpoints":
|
||||
listBreakPoints()
|
||||
elif ?"toggle":
|
||||
breakpointToggle(dbgUser.data, i)
|
||||
breakpointToggle(addr dbgUser.data, i)
|
||||
elif ?"filenames":
|
||||
listFilenames()
|
||||
elif ?"maxdisplay":
|
||||
var parsed: int
|
||||
i = scanNumber(dbgUser.data, parsed, i)
|
||||
i = scanNumber(addr dbgUser.data, parsed, i)
|
||||
if dbgUser.data[i-1] in {'0'..'9'}:
|
||||
if parsed == 0: maxDisplayRecDepth = -1
|
||||
else: maxDisplayRecDepth = parsed
|
||||
|
|
|
|||
|
|
@ -306,8 +306,12 @@ proc raiseExceptionAux(e: ref Exception) =
|
|||
add(buf, " [")
|
||||
xadd(buf, e.name, e.name.len)
|
||||
add(buf, "]\n")
|
||||
unhandled(buf):
|
||||
showErrorMessage(buf)
|
||||
when defined(nimNoArrayToCstringConversion):
|
||||
template tbuf(): untyped = addr buf
|
||||
else:
|
||||
template tbuf(): untyped = buf
|
||||
unhandled(tbuf()):
|
||||
showErrorMessage(tbuf())
|
||||
quitOrDebug()
|
||||
|
||||
proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} =
|
||||
|
|
|
|||
|
|
@ -155,14 +155,15 @@ template setColor(c, col) =
|
|||
else:
|
||||
c.refcount = c.refcount and not colorMask or col
|
||||
|
||||
proc writeCell(msg: cstring, c: PCell) =
|
||||
var kind = -1
|
||||
var typName: cstring = "nil"
|
||||
if c.typ != nil:
|
||||
kind = ord(c.typ.kind)
|
||||
when defined(nimTypeNames):
|
||||
if not c.typ.name.isNil:
|
||||
typName = c.typ.name
|
||||
when defined(logGC):
|
||||
proc writeCell(msg: cstring, c: PCell) =
|
||||
var kind = -1
|
||||
var typName: cstring = "nil"
|
||||
if c.typ != nil:
|
||||
kind = ord(c.typ.kind)
|
||||
when defined(nimTypeNames):
|
||||
if not c.typ.name.isNil:
|
||||
typName = c.typ.name
|
||||
|
||||
when leakDetector:
|
||||
c_fprintf(stdout, "[GC] %s: %p %d %s rc=%ld from %s(%ld)\n",
|
||||
|
|
@ -642,9 +643,9 @@ when useMarkForDebug or useBackupGc:
|
|||
forAllChildren(d, waMarkPrecise)
|
||||
|
||||
proc markGlobals(gch: var GcHeap) =
|
||||
for i in 0 .. < globalMarkersLen: globalMarkers[i]()
|
||||
for i in 0 .. globalMarkersLen-1: globalMarkers[i]()
|
||||
let d = gch.additionalRoots.d
|
||||
for i in 0 .. < gch.additionalRoots.len: markS(gch, d[i])
|
||||
for i in 0 .. gch.additionalRoots.len-1: markS(gch, d[i])
|
||||
|
||||
when logGC:
|
||||
var
|
||||
|
|
@ -652,7 +653,7 @@ when logGC:
|
|||
cycleCheckALen = 0
|
||||
|
||||
proc alreadySeen(c: PCell): bool =
|
||||
for i in 0 .. <cycleCheckALen:
|
||||
for i in 0 .. cycleCheckALen-1:
|
||||
if cycleCheckA[i] == c: return true
|
||||
if cycleCheckALen == len(cycleCheckA):
|
||||
gcAssert(false, "cycle detection overflow")
|
||||
|
|
|
|||
|
|
@ -487,12 +487,12 @@ proc GC_dumpHeap*(file: File) =
|
|||
var spaceIter: ObjectSpaceIter
|
||||
when false:
|
||||
var d = gch.decStack.d
|
||||
for i in 0 .. < gch.decStack.len:
|
||||
for i in 0 .. gch.decStack.len-1:
|
||||
if isAllocatedPtr(gch.region, d[i]):
|
||||
c_fprintf(file, "onstack %p\n", d[i])
|
||||
else:
|
||||
c_fprintf(file, "onstack_invalid %p\n", d[i])
|
||||
for i in 0 .. < globalMarkersLen: globalMarkers[i]()
|
||||
for i in 0 .. globalMarkersLen-1: globalMarkers[i]()
|
||||
while true:
|
||||
let x = allObjectsAsProc(gch.region, addr spaceIter)
|
||||
if spaceIter.state < 0: break
|
||||
|
|
@ -579,7 +579,7 @@ proc markIncremental(gch: var GcHeap): bool =
|
|||
result = true
|
||||
|
||||
proc markGlobals(gch: var GcHeap) =
|
||||
for i in 0 .. < globalMarkersLen: globalMarkers[i]()
|
||||
for i in 0 .. globalMarkersLen-1: globalMarkers[i]()
|
||||
|
||||
proc doOperation(p: pointer, op: WalkOp) =
|
||||
if p == nil: return
|
||||
|
|
|
|||
|
|
@ -450,9 +450,9 @@ when false:
|
|||
quit 1
|
||||
|
||||
proc markGlobals(gch: var GcHeap) =
|
||||
for i in 0 .. < globalMarkersLen: globalMarkers[i]()
|
||||
for i in 0 .. globalMarkersLen-1: globalMarkers[i]()
|
||||
let d = gch.additionalRoots.d
|
||||
for i in 0 .. < gch.additionalRoots.len: mark(gch, d[i])
|
||||
for i in 0 .. gch.additionalRoots.len-1: mark(gch, d[i])
|
||||
|
||||
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
|
||||
# the addresses are not as cells on the stack, so turn them to cells:
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ proc cmpic*(a, b: string): int =
|
|||
## Compares `a` and `b` ignoring case.
|
||||
cmpIgnoreCase(a, b)
|
||||
|
||||
proc getEnv*(key: string): string {.tags: [ReadIOEffect].} =
|
||||
proc getEnv*(key: string; default = ""): string {.tags: [ReadIOEffect].} =
|
||||
## Retrieves the environment variable of name `key`.
|
||||
builtin
|
||||
|
||||
|
|
|
|||
|
|
@ -16,34 +16,39 @@ proc reprInt(x: int64): string {.compilerproc.} = return $x
|
|||
proc reprFloat(x: float): string {.compilerproc.} = return $x
|
||||
|
||||
proc reprPointer(x: pointer): string {.compilerproc.} =
|
||||
var buf: array[0..59, char]
|
||||
discard c_sprintf(buf, "%p", x)
|
||||
return $buf
|
||||
when defined(nimNoArrayToCstringConversion):
|
||||
result = newString(60)
|
||||
let n = c_sprintf(addr result[0], "%p", x)
|
||||
setLen(result, n)
|
||||
else:
|
||||
var buf: array[0..59, char]
|
||||
discard c_sprintf(buf, "%p", x)
|
||||
return $buf
|
||||
|
||||
proc `$`(x: uint64): string =
|
||||
if x == 0:
|
||||
result = "0"
|
||||
else:
|
||||
var buf: array[60, char]
|
||||
result = newString(60)
|
||||
var i = 0
|
||||
var n = x
|
||||
while n != 0:
|
||||
let nn = n div 10'u64
|
||||
buf[i] = char(n - 10'u64 * nn + ord('0'))
|
||||
result[i] = char(n - 10'u64 * nn + ord('0'))
|
||||
inc i
|
||||
n = nn
|
||||
result.setLen i
|
||||
|
||||
let half = i div 2
|
||||
# Reverse
|
||||
for t in 0 .. < half: swap(buf[t], buf[i-t-1])
|
||||
result = $buf
|
||||
for t in 0 .. half-1: swap(result[t], result[i-t-1])
|
||||
|
||||
proc reprStrAux(result: var string, s: cstring; len: int) =
|
||||
if cast[pointer](s) == nil:
|
||||
add result, "nil"
|
||||
return
|
||||
add result, reprPointer(cast[pointer](s)) & "\""
|
||||
for i in 0.. <len:
|
||||
for i in 0 .. pred(len):
|
||||
let c = s[i]
|
||||
case c
|
||||
of '"': add result, "\\\""
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@
|
|||
# The generic ``repr`` procedure for the javascript backend.
|
||||
|
||||
proc reprInt(x: int64): string {.compilerproc.} = return $x
|
||||
proc reprFloat(x: float): string {.compilerproc.} =
|
||||
proc reprFloat(x: float): string {.compilerproc.} =
|
||||
# Js toString doesn't differentiate between 1.0 and 1,
|
||||
# but we do.
|
||||
if $x == $(x.int): $x & ".0"
|
||||
else: $x
|
||||
|
||||
proc reprPointer(p: pointer): string {.compilerproc.} =
|
||||
proc reprPointer(p: pointer): string {.compilerproc.} =
|
||||
# Do we need to generate the full 8bytes ? In js a pointer is an int anyway
|
||||
var tmp: int
|
||||
{. emit: """
|
||||
|
|
@ -38,7 +38,7 @@ proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
|
|||
result = $typ.node.sons[e].name
|
||||
else:
|
||||
result = $e & " (invalid data!)"
|
||||
|
||||
|
||||
proc reprChar(x: char): string {.compilerRtl.} =
|
||||
result = "\'"
|
||||
case x
|
||||
|
|
@ -50,7 +50,7 @@ proc reprChar(x: char): string {.compilerRtl.} =
|
|||
|
||||
proc reprStrAux(result: var string, s: cstring, len: int) =
|
||||
add(result, "\"")
|
||||
for i in 0 .. <len:
|
||||
for i in 0 .. len-1:
|
||||
let c = s[i]
|
||||
case c
|
||||
of '"': add(result, "\\\"")
|
||||
|
|
@ -67,7 +67,7 @@ proc reprStr(s: string): string {.compilerRtl.} =
|
|||
if cast[pointer](s).isNil:
|
||||
# Handle nil strings here because they don't have a length field in js
|
||||
# TODO: check for null/undefined before generating call to length in js?
|
||||
# Also: c backend repr of a nil string is <pointer>"", but repr of an
|
||||
# Also: c backend repr of a nil string is <pointer>"", but repr of an
|
||||
# array of string that is not initialized is [nil, nil, ...] ??
|
||||
add(result, "nil")
|
||||
else:
|
||||
|
|
@ -86,7 +86,7 @@ proc addSetElem(result: var string, elem: int, typ: PNimType) =
|
|||
|
||||
iterator setKeys(s: int): int {.inline.} =
|
||||
# The type of s is a lie, but it's expected to be a set.
|
||||
# Iterate over the JS object representing a set
|
||||
# Iterate over the JS object representing a set
|
||||
# and returns the keys as int.
|
||||
var len: int
|
||||
var yieldRes: int
|
||||
|
|
@ -124,16 +124,16 @@ proc initReprClosure(cl: var ReprClosure) =
|
|||
cl.recDepth = -1 # default is to display everything!
|
||||
cl.indent = 0
|
||||
|
||||
proc reprAux(result: var string, p: pointer, typ: PNimType, cl: var ReprClosure)
|
||||
proc reprAux(result: var string, p: pointer, typ: PNimType, cl: var ReprClosure)
|
||||
|
||||
proc reprArray(a: pointer, typ: PNimType,
|
||||
proc reprArray(a: pointer, typ: PNimType,
|
||||
cl: var ReprClosure): string {.compilerRtl.} =
|
||||
var isNilArrayOrSeq: bool
|
||||
# isnil is not enough here as it would try to deref `a` without knowing what's inside
|
||||
{. emit: """
|
||||
if (`a` == null) {
|
||||
if (`a` == null) {
|
||||
`isNilArrayOrSeq` = true;
|
||||
} else if (`a`[0] == null) {
|
||||
} else if (`a`[0] == null) {
|
||||
`isNilArrayOrSeq` = true;
|
||||
} else {
|
||||
`isNilArrayOrSeq` = false;
|
||||
|
|
@ -146,19 +146,19 @@ proc reprArray(a: pointer, typ: PNimType,
|
|||
result = if typ.kind == tySequence: "@[" else: "["
|
||||
var len: int = 0
|
||||
var i: int = 0
|
||||
|
||||
|
||||
{. emit: "`len` = `a`.length;\n" .}
|
||||
var dereffed: pointer = a
|
||||
for i in 0 .. < len:
|
||||
for i in 0 .. len-1:
|
||||
if i > 0 :
|
||||
add(result, ", ")
|
||||
# advance pointer and point to element at index
|
||||
{. emit: """
|
||||
`dereffed`_Idx = `i`;
|
||||
`dereffed`_Idx = `i`;
|
||||
`dereffed` = `a`[`dereffed`_Idx];
|
||||
""" .}
|
||||
reprAux(result, dereffed, typ.base, cl)
|
||||
|
||||
|
||||
add(result, "]")
|
||||
|
||||
proc isPointedToNil(p: pointer): bool {.inline.}=
|
||||
|
|
@ -181,7 +181,7 @@ proc reprRef(result: var string, p: pointer, typ: PNimType,
|
|||
|
||||
proc reprRecordAux(result: var string, o: pointer, typ: PNimType, cl: var ReprClosure) =
|
||||
add(result, "[")
|
||||
|
||||
|
||||
var first: bool = true
|
||||
var val: pointer = o
|
||||
if typ.node.len == 0:
|
||||
|
|
@ -192,7 +192,7 @@ proc reprRecordAux(result: var string, o: pointer, typ: PNimType, cl: var ReprCl
|
|||
reprAux(result, val, typ.node.typ, cl)
|
||||
else:
|
||||
# if the object has more than one field, sons is not nil and contains the fields.
|
||||
for i in 0 .. <typ.node.len:
|
||||
for i in 0 .. typ.node.len-1:
|
||||
if first: first = false
|
||||
else: add(result, ",\n")
|
||||
|
||||
|
|
@ -214,11 +214,11 @@ proc reprJSONStringify(p: int): string {.compilerRtl.} =
|
|||
{. emit: "`tmp` = JSON.stringify(`p`);\n" .}
|
||||
result = $tmp
|
||||
|
||||
proc reprAux(result: var string, p: pointer, typ: PNimType,
|
||||
proc reprAux(result: var string, p: pointer, typ: PNimType,
|
||||
cl: var ReprClosure) =
|
||||
if cl.recDepth == 0:
|
||||
add(result, "...")
|
||||
return
|
||||
return
|
||||
dec(cl.recDepth)
|
||||
case typ.kind
|
||||
of tyInt..tyInt64, tyUInt..tyUInt64:
|
||||
|
|
|
|||
|
|
@ -15,9 +15,12 @@
|
|||
{.push debugger:off .} # the user does not want to trace a part
|
||||
# of the standard library!
|
||||
|
||||
|
||||
proc c_fdopen(filehandle: cint, mode: cstring): File {.
|
||||
importc: "fdopen", header: "<stdio.h>".}
|
||||
when defined(windows):
|
||||
proc c_fdopen(filehandle: cint, mode: cstring): File {.
|
||||
importc: "_fdopen", header: "<stdio.h>".}
|
||||
else:
|
||||
proc c_fdopen(filehandle: cint, mode: cstring): File {.
|
||||
importc: "fdopen", header: "<stdio.h>".}
|
||||
proc c_fputs(c: cstring, f: File): cint {.
|
||||
importc: "fputs", header: "<stdio.h>", tags: [WriteIOEffect].}
|
||||
proc c_fgets(c: cstring, n: cint, f: File): cstring {.
|
||||
|
|
@ -401,4 +404,18 @@ proc setStdIoUnbuffered() =
|
|||
when declared(stdin):
|
||||
discard c_setvbuf(stdin, nil, IONBF, 0)
|
||||
|
||||
when declared(stdout):
|
||||
proc echoBinSafe(args: openArray[string]) {.compilerProc.} =
|
||||
when not defined(windows):
|
||||
proc flockfile(f: File) {.importc, noDecl.}
|
||||
proc funlockfile(f: File) {.importc, noDecl.}
|
||||
flockfile(stdout)
|
||||
for s in args:
|
||||
discard c_fwrite(s.cstring, s.len, 1, stdout)
|
||||
const linefeed = "\n" # can be 1 or more chars
|
||||
discard c_fwrite(linefeed.cstring, linefeed.len, 1, stdout)
|
||||
discard c_fflush(stdout)
|
||||
when not defined(windows):
|
||||
funlockfile(stdout)
|
||||
|
||||
{.pop.}
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ var
|
|||
workersData: array[NumThreads, Worker]
|
||||
|
||||
proc setup() =
|
||||
for i in 0.. <NumThreads:
|
||||
for i in 0 ..< NumThreads:
|
||||
workersData[i].taskArrived = createCondVar()
|
||||
workersData[i].taskStarted = createFastCondVar()
|
||||
createThread(workers[i], slave, addr(workersData[i]))
|
||||
|
|
|
|||
|
|
@ -24,7 +24,10 @@ proc cmpStrings(a, b: NimString): int {.inline, compilerProc.} =
|
|||
if a == b: return 0
|
||||
if a == nil: return -1
|
||||
if b == nil: return 1
|
||||
return c_strcmp(a.data, b.data)
|
||||
when defined(nimNoArrayToCstringConversion):
|
||||
return c_strcmp(addr a.data, addr b.data)
|
||||
else:
|
||||
return c_strcmp(a.data, b.data)
|
||||
|
||||
proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
|
||||
if a == b: return true
|
||||
|
|
@ -275,7 +278,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
|
|||
GenericSeqSize +% (i*%elemSize)),
|
||||
extGetCellType(result).base, waPush)
|
||||
let len1 = gch.tempStack.len
|
||||
for i in len0 .. <len1:
|
||||
for i in len0 ..< len1:
|
||||
doDecRef(gch.tempStack.d[i], LocalHeap, MaybeCyclic)
|
||||
gch.tempStack.len = len0
|
||||
else:
|
||||
|
|
@ -320,7 +323,10 @@ proc nimIntToStr(x: int): string {.compilerRtl.} =
|
|||
|
||||
proc add*(result: var string; x: float) =
|
||||
var buf: array[0..64, char]
|
||||
var n: int = c_sprintf(buf, "%.16g", x)
|
||||
when defined(nimNoArrayToCstringConversion):
|
||||
var n: int = c_sprintf(addr buf, "%.16g", x)
|
||||
else:
|
||||
var n: int = c_sprintf(buf, "%.16g", x)
|
||||
var hasDot = false
|
||||
for i in 0..n-1:
|
||||
if buf[i] == ',':
|
||||
|
|
@ -332,9 +338,10 @@ proc add*(result: var string; x: float) =
|
|||
buf[n] = '.'
|
||||
buf[n+1] = '0'
|
||||
buf[n+2] = '\0'
|
||||
# On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' are produced.
|
||||
# On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN'
|
||||
# of '-1.#IND' are produced.
|
||||
# We want to get rid of these here:
|
||||
if buf[n-1] in {'n', 'N'}:
|
||||
if buf[n-1] in {'n', 'N', 'D', 'd'}:
|
||||
result.add "nan"
|
||||
elif buf[n-1] == 'F':
|
||||
if buf[0] == '-':
|
||||
|
|
@ -342,7 +349,10 @@ proc add*(result: var string; x: float) =
|
|||
else:
|
||||
result.add "inf"
|
||||
else:
|
||||
result.add buf
|
||||
var i = 0
|
||||
while buf[i] != '\0':
|
||||
result.add buf[i]
|
||||
inc i
|
||||
|
||||
proc nimFloatToStr(f: float): string {.compilerproc.} =
|
||||
result = newStringOfCap(8)
|
||||
|
|
@ -353,9 +363,9 @@ proc c_strtod(buf: cstring, endptr: ptr cstring): float64 {.
|
|||
|
||||
const
|
||||
IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
|
||||
powtens = [ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
|
||||
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
|
||||
1e20, 1e21, 1e22]
|
||||
powtens = [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
|
||||
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
|
||||
1e20, 1e21, 1e22]
|
||||
|
||||
proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
||||
start = 0): int {.compilerProc.} =
|
||||
|
|
@ -507,7 +517,10 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
|||
t[ti-2] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10
|
||||
t[ti-3] = ('0'.ord + abs_exponent mod 10).char
|
||||
|
||||
number = c_strtod(t, nil)
|
||||
when defined(nimNoArrayToCstringConversion):
|
||||
number = c_strtod(addr t, nil)
|
||||
else:
|
||||
number = c_strtod(t, nil)
|
||||
|
||||
proc nimInt64ToStr(x: int64): string {.compilerRtl.} =
|
||||
result = newStringOfCap(sizeof(x)*4)
|
||||
|
|
|
|||
|
|
@ -398,7 +398,7 @@ template afterThreadRuns() =
|
|||
threadDestructionHandlers[i]()
|
||||
|
||||
when not defined(boehmgc) and not hasSharedHeap and not defined(gogc) and not defined(gcRegions):
|
||||
proc deallocOsPages()
|
||||
proc deallocOsPages() {.rtl.}
|
||||
|
||||
when defined(boehmgc):
|
||||
type GCStackBaseProc = proc(sb: pointer, t: pointer) {.noconv.}
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
import dynlib
|
||||
|
||||
when defined(vcc):
|
||||
{.passC: "-DWIN32_LEAN_AND_MEAN".}
|
||||
|
||||
{.passC: "-DWIN32_LEAN_AND_MEAN".}
|
||||
|
||||
const
|
||||
useWinUnicode* = not defined(useWinAnsi)
|
||||
|
|
|
|||
|
|
@ -590,13 +590,13 @@ proc md5_Transform*(c: var MD5_CTX; b: ptr cuchar){.importc: "MD5_Transform".}
|
|||
|
||||
from strutils import toHex, toLowerAscii
|
||||
|
||||
proc hexStr (buf:cstring): string =
|
||||
proc hexStr(buf: cstring): string =
|
||||
# turn md5s output into a nice hex str
|
||||
result = newStringOfCap(32)
|
||||
for i in 0 .. <16:
|
||||
for i in 0 ..< 16:
|
||||
result.add toHex(buf[i].ord, 2).toLowerAscii
|
||||
|
||||
proc md5_File* (file: string): string {.raises: [IOError,Exception].} =
|
||||
proc md5_File*(file: string): string {.raises: [IOError,Exception].} =
|
||||
## Generate MD5 hash for a file. Result is a 32 character
|
||||
# hex string with lowercase characters (like the output
|
||||
# of `md5sum`
|
||||
|
|
@ -611,14 +611,14 @@ proc md5_File* (file: string): string {.raises: [IOError,Exception].} =
|
|||
while(let bytes = f.readChars(buf, 0, sz); bytes > 0):
|
||||
discard md5_update(ctx, buf[0].addr, bytes)
|
||||
|
||||
discard md5_final( buf[0].addr, ctx )
|
||||
discard md5_final(buf[0].addr, ctx)
|
||||
f.close
|
||||
|
||||
result = hexStr(buf)
|
||||
result = hexStr(addr buf)
|
||||
|
||||
proc md5_Str*(str:string): string =
|
||||
##Generate MD5 hash for a string. Result is a 32 character
|
||||
#hex string with lowercase characters
|
||||
proc md5_Str*(str: string): string =
|
||||
## Generate MD5 hash for a string. Result is a 32 character
|
||||
## hex string with lowercase characters
|
||||
var
|
||||
ctx: MD5_CTX
|
||||
res: array[MD5_DIGEST_LENGTH,char]
|
||||
|
|
@ -631,5 +631,5 @@ proc md5_Str*(str:string): string =
|
|||
discard md5_update(ctx, input[i].addr, L)
|
||||
i += L
|
||||
|
||||
discard md5_final(res,ctx)
|
||||
result = hexStr(res)
|
||||
discard md5_final(addr res, ctx)
|
||||
result = hexStr(addr res)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -20,16 +20,12 @@ proc openCCState*(): PccState {.importc: "tcc_new", cdecl.}
|
|||
proc closeCCState*(s: PccState) {.importc: "tcc_delete", cdecl.}
|
||||
## free a TCC compilation context
|
||||
|
||||
proc enableDebug*(s: PccState) {.importc: "tcc_enable_debug", cdecl.}
|
||||
## add debug information in the generated code
|
||||
|
||||
proc setErrorFunc*(s: PccState, errorOpaque: pointer, errorFun: ErrorFunc) {.
|
||||
cdecl, importc: "tcc_set_error_func".}
|
||||
## set error/warning display callback
|
||||
|
||||
proc setWarning*(s: PccState, warningName: cstring, value: int) {.cdecl,
|
||||
importc: "tcc_set_warning".}
|
||||
## set/reset a warning
|
||||
proc setOptions*(s: PccState, options: cstring) {.cdecl, importc: "tcc_set_options".}
|
||||
## set a options
|
||||
|
||||
# preprocessor
|
||||
|
||||
|
|
@ -41,7 +37,6 @@ proc addSysincludePath*(s: PccState, pathname: cstring) {.cdecl,
|
|||
importc: "tcc_add_sysinclude_path".}
|
||||
## add in system include path
|
||||
|
||||
|
||||
proc defineSymbol*(s: PccState, sym, value: cstring) {.cdecl,
|
||||
importc: "tcc_define_symbol".}
|
||||
## define preprocessor symbol 'sym'. Can put optional value
|
||||
|
|
@ -65,16 +60,12 @@ proc compileString*(s: PccState, buf: cstring): cint {.cdecl,
|
|||
|
||||
|
||||
const
|
||||
OutputMemory*: cint = 0 ## output will be ran in memory (no
|
||||
OutputMemory*: cint = 1 ## output will be ran in memory (no
|
||||
## output file) (default)
|
||||
OutputExe*: cint = 1 ## executable file
|
||||
OutputDll*: cint = 2 ## dynamic library
|
||||
OutputObj*: cint = 3 ## object file
|
||||
OutputPreprocess*: cint = 4 ## preprocessed file (used internally)
|
||||
|
||||
OutputFormatElf*: cint = 0 ## default output format: ELF
|
||||
OutputFormatBinary*: cint = 1 ## binary image output
|
||||
OutputFormatCoff*: cint = 2 ## COFF
|
||||
OutputExe*: cint = 2 ## executable file
|
||||
OutputDll*: cint = 3 ## dynamic library
|
||||
OutputObj*: cint = 4 ## object file
|
||||
OutputPreprocess*: cint = 5 ## preprocessed file (used internally)
|
||||
|
||||
proc setOutputType*(s: PCCState, outputType: cint): cint {.cdecl,
|
||||
importc: "tcc_set_output_type".}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue