Merge remote-tracking branch 'upstream/devel' into devel

This commit is contained in:
PhilipWitte 2015-02-15 17:27:53 -08:00
commit 0e5f6cc3b0
39 changed files with 260 additions and 259 deletions

View file

@ -48,7 +48,7 @@ proc genVarTuple(p: BProc, n: PNode) =
return return
genLineDir(p, n) genLineDir(p, n)
initLocExpr(p, n.sons[L-1], tup) initLocExpr(p, n.sons[L-1], tup)
var t = tup.t var t = tup.t.getUniqueType
for i in countup(0, L-3): for i in countup(0, L-3):
var v = n.sons[i].sym var v = n.sons[i].sym
if sfCompileTime in v.flags: continue if sfCompileTime in v.flags: continue

View file

@ -51,10 +51,10 @@ Files: "configure;makefile"
Files: "*.ini" Files: "*.ini"
Files: "koch.nim" Files: "koch.nim"
Files: "icons/nimrod.ico" Files: "icons/nim.ico"
Files: "icons/nimrod.rc" Files: "icons/nim.rc"
Files: "icons/nimrod.res" Files: "icons/nim.res"
Files: "icons/nimrod_icon.o" Files: "icons/nim_icon.o"
Files: "icons/koch.ico" Files: "icons/koch.ico"
Files: "icons/koch.rc" Files: "icons/koch.rc"
Files: "icons/koch.res" Files: "icons/koch.res"

View file

@ -9,9 +9,9 @@
when defined(gcc) and defined(windows): when defined(gcc) and defined(windows):
when defined(x86): when defined(x86):
{.link: "icons/nimrod.res".} {.link: "icons/nim.res".}
else: else:
{.link: "icons/nimrod_icon.o".} {.link: "icons/nim_icon.o".}
import import
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes, commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,

View file

@ -1597,6 +1597,7 @@ proc parseEnum(p: var TParser): PNode =
optInd(p, result) optInd(p, result)
while true: while true:
var a = parseSymbol(p) var a = parseSymbol(p)
if a.kind == nkEmpty: return
if p.tok.indent >= 0 and p.tok.indent <= p.currInd: if p.tok.indent >= 0 and p.tok.indent <= p.currInd:
add(result, a) add(result, a)
break break

View file

@ -1016,9 +1016,17 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if result != isNone: put(c.bindings, f, aOrig) if result != isNone: put(c.bindings, f, aOrig)
else: else:
result = isNone result = isNone
elif prev.kind == tyStatic:
if aOrig.kind == tyStatic:
result = typeRel(c, prev.lastSon, a)
if result != isNone and prev.n != nil:
if not exprStructuralEquivalent(prev.n, aOrig.n):
result = isNone
else: result = isNone
else: else:
result = typeRel(c, prev, aOrig) # XXX endless recursion?
#result = typeRel(c, prev, aOrig)
result = isNone
of tyTypeDesc: of tyTypeDesc:
var prev = PType(idTableGet(c.bindings, f)) var prev = PType(idTableGet(c.bindings, f))
if prev == nil: if prev == nil:

View file

@ -1,136 +0,0 @@
# Configuration file for the Nim Compiler.
# (c) 2015 Andreas Rumpf
# Feel free to edit the default values as you need.
# You may set environment variables with
# @putenv "key" "val"
# Environment variables cannot be used in the options, however!
cc = gcc
# example of how to setup a cross-compiler:
arm.linux.gcc.exe = "arm-linux-gcc"
arm.linux.gcc.linkerexe = "arm-linux-gcc"
cs:partial
path="$lib/core"
path="$lib/pure"
path="$lib/pure/collections"
path="$lib/pure/concurrency"
path="$lib/impure"
path="$lib/wrappers"
# path="$lib/wrappers/cairo"
# path="$lib/wrappers/gtk"
# path="$lib/wrappers/lua"
# path="$lib/wrappers/opengl"
path="$lib/wrappers/pcre"
path="$lib/wrappers/readline"
path="$lib/wrappers/sdl"
# path="$lib/wrappers/x11"
path="$lib/wrappers/zip"
path="$lib/wrappers/libffi"
path="$lib/windows"
path="$lib/posix"
path="$lib/js"
path="$lib/pure/unidecode"
@if nimbabel:
babelpath="$home/.babel/pkgs/"
@end
@if release or quick:
obj_checks:off
field_checks:off
range_checks:off
bound_checks:off
overflow_checks:off
assertions:off
stacktrace:off
linetrace:off
debugger:off
line_dir:off
dead_code_elim:on
@end
@if release:
opt:speed
@end
# additional options always passed to the compiler:
--parallel_build: "0" # 0 to auto-detect number of processors
hint[LineTooLong]=off
#hint[XDeclaredButNotUsed]=off
@if unix:
@if not bsd:
# -fopenmp
gcc.options.linker = "-ldl"
gpp.options.linker = "-ldl"
clang.options.linker = "-ldl"
tcc.options.linker = "-ldl"
@end
@if bsd or haiku:
# BSD got posix_spawn only recently, so we deactivate it for osproc:
define:useFork
# at least NetBSD has problems with thread local storage:
tlsEmulation:on
@end
@end
# Configuration for the Intel C/C++ compiler:
@if windows:
icl.options.speed = "/Ox /arch:SSE2"
icl.options.always = "/nologo"
@end
# Configuration for the GNU C/C++ compiler:
@if windows:
#gcc.path = r"$nimrod\dist\mingw\bin"
@if gcc:
tlsEmulation:on
@end
@end
@if macosx:
cc = clang
tlsEmulation:on
gcc.options.always = "-w -fasm-blocks"
gpp.options.always = "-w -fasm-blocks -fpermissive"
@else:
gcc.options.always = "-w"
gpp.options.always = "-w -fpermissive"
@end
gcc.options.speed = "-O3 -fno-strict-aliasing"
gcc.options.size = "-Os"
gcc.options.debug = "-g3 -O0"
gpp.options.speed = "-O3 -fno-strict-aliasing"
gpp.options.size = "-Os"
gpp.options.debug = "-g3 -O0"
#passl = "-pg"
# Configuration for the LLVM GCC compiler:
llvm_gcc.options.debug = "-g"
llvm_gcc.options.always = "-w"
llvm_gcc.options.speed = "-O2"
llvm_gcc.options.size = "-Os"
# Configuration for the LLVM CLang compiler:
clang.options.debug = "-g"
clang.options.always = "-w"
clang.options.speed = "-O3"
clang.options.size = "-Os"
# Configuration for the Visual C/C++ compiler:
vcc.options.linker = "/DEBUG /Zi /Fd\"$projectName.pdb\" /F33554432" # set the stack size to 8 MB
vcc.options.debug = "/Zi /Fd\"$projectName.pdb\""
vcc.options.always = "/nologo"
vcc.options.speed = "/Ox /arch:SSE2"
vcc.options.size = "/O1"
# Configuration for the Tiny C Compiler:
tcc.options.always = "-w"

View file

@ -189,6 +189,12 @@ Math libraries
Floating-point environment. Handling of floating-point rounding and Floating-point environment. Handling of floating-point rounding and
exceptions (overflow, zero-devide, etc.). exceptions (overflow, zero-devide, etc.).
* `basic2d <basic2d.html>`_
Basic 2d support with vectors, points, matrices and some basic utilities.
* `basic3d <basic3d.html>`_
Basic 3d support with vectors, points, matrices and some basic utilities.
Internet Protocols and Support Internet Protocols and Support
------------------------------ ------------------------------
@ -218,9 +224,6 @@ Internet Protocols and Support
* `smtp <smtp.html>`_ * `smtp <smtp.html>`_
This module implement a simple SMTP client. This module implement a simple SMTP client.
* `irc <irc.html>`_
This module implements an asynchronous IRC client.
* `ftpclient <ftpclient.html>`_ * `ftpclient <ftpclient.html>`_
This module implements an FTP client. This module implements an FTP client.

View file

@ -1,4 +1,4 @@
# Nimrod configuration file. # Nimrod configuration file.
# The file is used only to add the path of the backend to the compiler options. # The file is used only to add the path of the backend to the compiler options.
path="../nimrod_backend" path="../nim_backend"

View file

@ -21,7 +21,7 @@ type
cmdParams, # Two valid parameters were provided cmdParams, # Two valid parameters were provided
cmdInteractive # No parameters were provided, run interactive mode cmdInteractive # No parameters were provided, run interactive mode
TParamConfig = object of TObject TParamConfig = object of RootObj
action: TCommand # store the type of operation action: TCommand # store the type of operation
paramA, paramB: int # possibly store the valid parameters paramA, paramB: int # possibly store the valid parameters
@ -63,7 +63,7 @@ proc parseCmdLine(): TParamConfig =
stdout.write USAGE stdout.write USAGE
quit "Unexpected option: " & key, 2 quit "Unexpected option: " & key, 2
of cmdEnd: break of cmdEnd: break
except EInvalidValue: except ValueError:
stdout.write USAGE stdout.write USAGE
quit "Invalid value " & val & " for parameter " & key, 3 quit "Invalid value " & val & " for parameter " & key, 3
@ -85,7 +85,7 @@ proc parseUserInput(question: string): int =
try: try:
result = input.parseInt result = input.parseInt
break break
except EInvalidValue: except ValueError:
if input.len < 1: quit "Blank line detected, quitting.", 0 if input.len < 1: quit "Blank line detected, quitting.", 0
echo "Sorry, `$1' doesn't seem to be a valid integer" % input echo "Sorry, `$1' doesn't seem to be a valid integer" % input

View file

@ -1,10 +1,10 @@
In this directory you will find the nimrod commandline version of the In this directory you will find the nim commandline version of the
cross-calculator sample. cross-calculator sample.
The commandline interface can be used non interactively through switches, or The commandline interface can be used non interactively through switches, or
interactively when running the command without parameters. interactively when running the command without parameters.
Compilation is fairly easy despite having the source split in different Compilation is fairly easy despite having the source split in different
directories. Thanks to the nimrod.cfg file, which adds the ../nimrod_backend directories. Thanks to the nim.cfg file, which adds the ../nim_backend
directory as a search path, you can compile and run the example just fine from directory as a search path, you can compile and run the example just fine from
the command line with 'nimrod c -r nimcalculator.nim'. the command line with 'nim c -r nimcalculator.nim'.

View file

@ -13,7 +13,7 @@ type
text*: string ## Description of the task to do. text*: string ## Description of the task to do.
priority*: int ## The priority can be any user defined integer. priority*: int ## The priority can be any user defined integer.
isDone*: bool ## Done todos are still kept marked. isDone*: bool ## Done todos are still kept marked.
modificationDate: TTime ## The modification time can't be modified from modificationDate: Time ## The modification time can't be modified from
## outside of this module, use the ## outside of this module, use the
## getModificationDate accessor. ## getModificationDate accessor.
@ -64,7 +64,7 @@ proc openDatabase*(path: string): TDbConn =
# - Procs related to TTodo objects # - Procs related to TTodo objects
# #
proc initFromDB(id: int64; text: string; priority: int, isDone: bool; proc initFromDB(id: int64; text: string; priority: int, isDone: bool;
modificationDate: TTime): TTodo = modificationDate: Time): TTodo =
## Returns an initialized TTodo object created from database parameters. ## Returns an initialized TTodo object created from database parameters.
## ##
## The proc assumes all values are right. Note this proc is NOT exported. ## The proc assumes all values are right. Note this proc is NOT exported.
@ -81,7 +81,7 @@ proc getId*(todo: TTodo): int64 =
return todo.id return todo.id
proc getModificationDate*(todo: TTodo): TTime = proc getModificationDate*(todo: TTodo): Time =
## Returns the last modification date of a TTodo entry. ## Returns the last modification date of a TTodo entry.
return todo.modificationDate return todo.modificationDate
@ -99,14 +99,14 @@ proc update*(todo: var TTodo; conn: TDbConn): bool =
FROM Todos WHERE id = ?""" FROM Todos WHERE id = ?"""
try: try:
let rows = conn.GetAllRows(query, $todo.id) let rows = conn.getAllRows(query, $todo.id)
if len(rows) < 1: if len(rows) < 1:
return return
assert(1 == len(rows), "Woah, didn't expect so many rows") assert(1 == len(rows), "Woah, didn't expect so many rows")
todo.text = rows[0][0] todo.text = rows[0][0]
todo.priority = rows[0][1].parseInt todo.priority = rows[0][1].parseInt
todo.isDone = rows[0][2].parseBool todo.isDone = rows[0][2].parseBool
todo.modificationDate = TTime(rows[0][3].parseInt) todo.modificationDate = Time(rows[0][3].parseInt)
result = true result = true
except: except:
echo("Something went wrong selecting for id " & $todo.id) echo("Something went wrong selecting for id " & $todo.id)
@ -202,12 +202,12 @@ proc getPagedTodos*(conn: TDbConn; params: TPagedParams;
#echo("Query " & string(query)) #echo("Query " & string(query))
#echo("args: " & args.join(", ")) #echo("args: " & args.join(", "))
var newId: biggestInt var newId: BiggestInt
for row in conn.fastRows(query, args): for row in conn.fastRows(query, args):
let numChars = row[0].parseBiggestInt(newId) let numChars = row[0].parseBiggestInt(newId)
assert(numChars > 0, "Huh, couldn't parse identifier from database?") assert(numChars > 0, "Huh, couldn't parse identifier from database?")
result.add(initFromDB(int64(newId), row[1], row[2].parseInt, result.add(initFromDB(int64(newId), row[1], row[2].parseInt,
row[3].parseBool, TTime(row[4].parseInt))) row[3].parseBool, Time(row[4].parseInt)))
proc getTodo*(conn: TDbConn; todoId: int64): ref TTodo = proc getTodo*(conn: TDbConn; todoId: int64): ref TTodo =

View file

@ -1,4 +1,4 @@
This directory contains the nimrod backend code for the todo cross platform This directory contains the nim backend code for the todo cross platform
example. example.
Unlike the cross platform calculator example, this backend features more code, Unlike the cross platform calculator example, this backend features more code,
@ -8,7 +8,7 @@ The test is not embedded directly in the backend.nim file to avoid being able
to access internal data types and procs not exported and replicate the to access internal data types and procs not exported and replicate the
environment of client code. environment of client code.
In a bigger project with several people you could run `nimrod doc backend.nim` In a bigger project with several people you could run `nim doc backend.nim`
(or use the doc2 command for a whole project) and provide the generated html (or use the doc2 command for a whole project) and provide the generated html
documentation to another programer for her to implement an interface without documentation to another programer for her to implement an interface without
having to look at the source code. having to look at the source code.

View file

@ -1,4 +1,4 @@
# Nimrod configuration file. # Nimrod configuration file.
# The file is used only to add the path of the backend to the compiler options. # The file is used only to add the path of the backend to the compiler options.
path="../nimrod_backend" path="../nim_backend"

View file

@ -69,11 +69,11 @@ template parseTodoIdAndSetCommand(newCommand: TCommand): stmt =
## Helper to parse a big todo identifier into todoId and set command. ## Helper to parse a big todo identifier into todoId and set command.
try: try:
let numChars = val.parseBiggestInt(newId) let numChars = val.parseBiggestInt(newId)
if numChars < 1: raise newException(EInvalidValue, "Empty string?") if numChars < 1: raise newException(ValueError, "Empty string?")
result.command = newCommand result.command = newCommand
result.todoId = newId result.todoId = newId
except EOverflow: except OverflowError:
raise newException(EInvalidValue, "Value $1 too big" % val) raise newException(ValueError, "Value $1 too big" % val)
template verifySingleCommand(actions: stmt): stmt = template verifySingleCommand(actions: stmt): stmt =
@ -111,7 +111,7 @@ proc parseCmdLine(): TParamConfig =
usesListParams = false usesListParams = false
p = initOptParser() p = initOptParser()
key, val: TaintedString key, val: TaintedString
newId: biggestInt newId: BiggestInt
result.initDefaults result.initDefaults
@ -178,7 +178,7 @@ proc parseCmdLine(): TParamConfig =
abort("Unexpected option '$1'." % [key], 6) abort("Unexpected option '$1'." % [key], 6)
of cmdEnd: of cmdEnd:
break break
except EInvalidValue: except ValueError:
abort("Invalid integer value '$1' for parameter '$2'." % [val, key], 7) abort("Invalid integer value '$1' for parameter '$2'." % [val, key], 7)
if not specifiedCommand: if not specifiedCommand:

View file

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Before After
Before After

3
icons/nim.rc Normal file
View file

@ -0,0 +1,3 @@
nimicon ICON "nim.ico"

View file

@ -1,3 +0,0 @@
nimrodicon ICON "nimrod.ico"

View file

@ -812,7 +812,7 @@ proc bisect*(v1,v2:TVector3d):TVector3d {.noInit.}=
## Computes the bisector between v1 and v2 as a normalized vector. ## Computes the bisector between v1 and v2 as a normalized vector.
## If one of the input vectors has zero length, a normalized version ## If one of the input vectors has zero length, a normalized version
## of the other is returned. If both input vectors has zero length, ## of the other is returned. If both input vectors has zero length,
## an arbitrary normalized vector `v1`is returned. ## an arbitrary normalized vector `v1` is returned.
var var
vmag1=v1.len vmag1=v1.len
vmag2=v2.len vmag2=v2.len

View file

@ -276,7 +276,7 @@ proc excl*[A](s: var HashSet[A], key: A) =
if isEmpty(s.data[i].hcode): # end of collision cluster; So all done if isEmpty(s.data[i].hcode): # end of collision cluster; So all done
return return
r = s.data[i].hcode and msk # "home" location of key@i r = s.data[i].hcode and msk # "home" location of key@i
s.data[j] = s.data[i] # data[j] will be marked EMPTY next loop shallowCopy(s.data[j], s.data[i]) # data[j] will be marked EMPTY next loop
proc excl*[A](s: var HashSet[A], other: HashSet[A]) = proc excl*[A](s: var HashSet[A], other: HashSet[A]) =
## Excludes everything in `other` from `s`. ## Excludes everything in `other` from `s`.
@ -313,9 +313,9 @@ proc init*[A](s: var HashSet[A], initialSize=64) =
## Initializes a hash set. ## Initializes a hash set.
## ##
## The `initialSize` parameter needs to be a power of two. You can use ## The `initialSize` parameter needs to be a power of two. You can use
## `math.nextPowerOfTwo() <math.html#nextPowerOfTwo>`_ to guarantee that at ## `math.nextPowerOfTwo() <math.html#nextPowerOfTwo>`_ or `rightSize` to
## runtime. All set variables have to be initialized before you can use them ## guarantee that at runtime. All set variables must be initialized before
## with other procs from this module with the exception of `isValid() ## use with other procs from this module with the exception of `isValid()
## <#isValid,TSet[A]>`_ and `len() <#len,TSet[A]>`_. ## <#isValid,TSet[A]>`_ and `len() <#len,TSet[A]>`_.
## ##
## You can call this proc on a previously initialized hash set, which will ## You can call this proc on a previously initialized hash set, which will
@ -719,9 +719,9 @@ proc init*[A](s: var OrderedSet[A], initialSize=64) =
## Initializes an ordered hash set. ## Initializes an ordered hash set.
## ##
## The `initialSize` parameter needs to be a power of two. You can use ## The `initialSize` parameter needs to be a power of two. You can use
## `math.nextPowerOfTwo() <math.html#nextPowerOfTwo>`_ to guarantee that at ## `math.nextPowerOfTwo() <math.html#nextPowerOfTwo>`_ or `rightSize` to
## runtime. All set variables have to be initialized before you can use them ## guarantee that at runtime. All set variables must be initialized before
## with other procs from this module with the exception of `isValid() ## use with other procs from this module with the exception of `isValid()
## <#isValid,TOrderedSet[A]>`_ and `len() <#len,TOrderedSet[A]>`_. ## <#isValid,TOrderedSet[A]>`_ and `len() <#len,TOrderedSet[A]>`_.
## ##
## You can call this proc on a previously initialized ordered hash set to ## You can call this proc on a previously initialized ordered hash set to

View file

@ -71,8 +71,7 @@ import
{.pragma: myShallow.} {.pragma: myShallow.}
type type
SlotEnum = enum seEmpty, seFilled, seDeleted KeyValuePair[A, B] = tuple[hcode: THash, key: A, val: B]
KeyValuePair[A, B] = tuple[slot: SlotEnum, key: A, val: B]
KeyValuePairSeq[A, B] = seq[KeyValuePair[A, B]] KeyValuePairSeq[A, B] = seq[KeyValuePair[A, B]]
Table* {.myShallow.}[A, B] = object ## generic hash table Table* {.myShallow.}[A, B] = object ## generic hash table
data: KeyValuePairSeq[A, B] data: KeyValuePairSeq[A, B]
@ -84,6 +83,14 @@ type
when not defined(nimhygiene): when not defined(nimhygiene):
{.pragma: dirty.} {.pragma: dirty.}
# hcode for real keys cannot be zero. hcode==0 signifies an empty slot. These
# two procs retain clarity of that encoding without the space cost of an enum.
proc isEmpty(hcode: THash): bool {.inline.} =
result = hcode == 0
proc isFilled(hcode: THash): bool {.inline.} =
result = hcode != 0
proc len*[A, B](t: Table[A, B]): int = proc len*[A, B](t: Table[A, B]): int =
## returns the number of keys in `t`. ## returns the number of keys in `t`.
result = t.counter result = t.counter
@ -91,28 +98,28 @@ proc len*[A, B](t: Table[A, B]): int =
iterator pairs*[A, B](t: Table[A, B]): tuple[key: A, val: B] = iterator pairs*[A, B](t: Table[A, B]): tuple[key: A, val: B] =
## iterates over any (key, value) pair in the table `t`. ## iterates over any (key, value) pair in the table `t`.
for h in 0..high(t.data): for h in 0..high(t.data):
if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val) if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
iterator mpairs*[A, B](t: var Table[A, B]): tuple[key: A, val: var B] = iterator mpairs*[A, B](t: var Table[A, B]): tuple[key: A, val: var B] =
## iterates over any (key, value) pair in the table `t`. The values ## iterates over any (key, value) pair in the table `t`. The values
## can be modified. ## can be modified.
for h in 0..high(t.data): for h in 0..high(t.data):
if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val) if isFilled(t.data[h].slot): yield (t.data[h].key, t.data[h].val)
iterator keys*[A, B](t: Table[A, B]): A = iterator keys*[A, B](t: Table[A, B]): A =
## iterates over any key in the table `t`. ## iterates over any key in the table `t`.
for h in 0..high(t.data): for h in 0..high(t.data):
if t.data[h].slot == seFilled: yield t.data[h].key if isFilled(t.data[h].hcode): yield t.data[h].key
iterator values*[A, B](t: Table[A, B]): B = iterator values*[A, B](t: Table[A, B]): B =
## iterates over any value in the table `t`. ## iterates over any value in the table `t`.
for h in 0..high(t.data): for h in 0..high(t.data):
if t.data[h].slot == seFilled: yield t.data[h].val if isFilled(t.data[h].hcode): yield t.data[h].val
iterator mvalues*[A, B](t: var Table[A, B]): var B = iterator mvalues*[A, B](t: var Table[A, B]): var B =
## iterates over any value in the table `t`. The values can be modified. ## iterates over any value in the table `t`. The values can be modified.
for h in 0..high(t.data): for h in 0..high(t.data):
if t.data[h].slot == seFilled: yield t.data[h].val if isFilled(t.data[h].hcode): yield t.data[h].val
const const
growthFactor = 2 growthFactor = 2
@ -121,26 +128,57 @@ proc mustRehash(length, counter: int): bool {.inline.} =
assert(length > counter) assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4) result = (length * 2 < counter * 3) or (length - counter < 4)
proc nextTry(h, maxHash: THash): THash {.inline.} = proc rightSize*(count: int): int {.inline.} =
result = ((5 * h) + 1) and maxHash ## Return the value of `initialSize` to support `count` items.
##
## If more items are expected to be added, simply add that
## expected extra amount to the parameter before calling this.
##
## Internally, we want mustRehash(rightSize(x), x) == false.
result = nextPowerOfTwo(count * 3 div 2 + 4)
template rawGetImpl() {.dirty.} = proc nextTry(h, maxHash: THash): THash {.inline.} =
var h: THash = hash(key) and high(t.data) # start with real hash value result = (h + 1) and maxHash
while t.data[h].slot != seEmpty:
if t.data[h].key == key and t.data[h].slot == seFilled: template rawGetKnownHCImpl() {.dirty.} =
var h: THash = hc and high(t.data) # start with real hash value
while isFilled(t.data[h].hcode):
# Compare hc THEN key with boolean short circuit. This makes the common case
# zero ==key's for missing (e.g.inserts) and exactly one ==key for present.
# It does slow down succeeding lookups by one extra THash cmp&and..usually
# just a few clock cycles, generally worth it for any non-integer-like A.
if t.data[h].hcode == hc and t.data[h].key == key:
return h return h
h = nextTry(h, high(t.data)) h = nextTry(h, high(t.data))
result = -1 result = -1 - h # < 0 => MISSING; insert idx = -1 - result
template rawGetImpl() {.dirty.} =
hc = hash(key)
if hc == 0: # This almost never taken branch should be very predictable.
hc = 314159265 # Value doesn't matter; Any non-zero favorite is fine.
rawGetKnownHCImpl()
template rawGetDeepImpl() {.dirty.} = # Search algo for unconditional add
hc = hash(key)
if hc == 0:
hc = 314159265
var h: THash = hc and high(t.data)
while isFilled(t.data[h].hcode):
h = nextTry(h, high(t.data))
result = h
template rawInsertImpl() {.dirty.} = template rawInsertImpl() {.dirty.} =
var h: THash = hash(key) and high(data)
while data[h].slot == seFilled:
h = nextTry(h, high(data))
data[h].key = key data[h].key = key
data[h].val = val data[h].val = val
data[h].slot = seFilled data[h].hcode = hc
proc rawGet[A, B](t: Table[A, B], key: A): int = proc rawGetKnownHC[A, B](t: Table[A, B], key: A, hc: THash): int {.inline.} =
rawGetKnownHCImpl()
proc rawGetDeep[A, B](t: Table[A, B], key: A, hc: var THash): int {.inline.} =
rawGetDeepImpl()
proc rawGet[A, B](t: Table[A, B], key: A, hc: var THash): int {.inline.} =
rawGetImpl() rawGetImpl()
proc `[]`*[A, B](t: Table[A, B], key: A): B = proc `[]`*[A, B](t: Table[A, B], key: A): B =
@ -148,55 +186,68 @@ proc `[]`*[A, B](t: Table[A, B], key: A): B =
## default empty value for the type `B` is returned ## default empty value for the type `B` is returned
## and no exception is raised. One can check with ``hasKey`` whether the key ## and no exception is raised. One can check with ``hasKey`` whether the key
## exists. ## exists.
var index = rawGet(t, key) var hc: THash
var index = rawGet(t, key, hc)
if index >= 0: result = t.data[index].val if index >= 0: result = t.data[index].val
proc mget*[A, B](t: var Table[A, B], key: A): var B = proc mget*[A, B](t: var Table[A, B], key: A): var B =
## retrieves the value at ``t[key]``. The value can be modified. ## retrieves the value at ``t[key]``. The value can be modified.
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised. ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
var index = rawGet(t, key) var hc: THash
var index = rawGet(t, key, hc)
if index >= 0: result = t.data[index].val if index >= 0: result = t.data[index].val
else: raise newException(KeyError, "key not found: " & $key) else: raise newException(KeyError, "key not found: " & $key)
iterator allValues*[A, B](t: Table[A, B]; key: A): B = iterator allValues*[A, B](t: Table[A, B]; key: A): B =
## iterates over any value in the table `t` that belongs to the given `key`. ## iterates over any value in the table `t` that belongs to the given `key`.
var h: THash = hash(key) and high(t.data) var h: THash = hash(key) and high(t.data)
while t.data[h].slot != seEmpty: while isFilled(t.data[h].hcode):
if t.data[h].key == key and t.data[h].slot == seFilled: if t.data[h].key == key:
yield t.data[h].val yield t.data[h].val
h = nextTry(h, high(t.data)) h = nextTry(h, high(t.data))
proc hasKey*[A, B](t: Table[A, B], key: A): bool = proc hasKey*[A, B](t: Table[A, B], key: A): bool =
## returns true iff `key` is in the table `t`. ## returns true iff `key` is in the table `t`.
result = rawGet(t, key) >= 0 var hc: THash
result = rawGet(t, key, hc) >= 0
proc rawInsert[A, B](t: var Table[A, B], data: var KeyValuePairSeq[A, B], proc rawInsert[A, B](t: var Table[A, B], data: var KeyValuePairSeq[A, B],
key: A, val: B) = key: A, val: B, hc: THash, h: THash) =
rawInsertImpl() rawInsertImpl()
proc enlarge[A, B](t: var Table[A, B]) = proc enlarge[A, B](t: var Table[A, B]) =
var n: KeyValuePairSeq[A, B] var n: KeyValuePairSeq[A, B]
newSeq(n, len(t.data) * growthFactor) newSeq(n, len(t.data) * growthFactor)
for i in countup(0, high(t.data)):
if t.data[i].slot == seFilled: rawInsert(t, n, t.data[i].key, t.data[i].val)
swap(t.data, n) swap(t.data, n)
for i in countup(0, high(n)):
if isFilled(n[i].hcode):
var j = -1 - rawGetKnownHC(t, n[i].key, n[i].hcode)
rawInsert(t, t.data, n[i].key, n[i].val, n[i].hcode, j)
template addImpl() {.dirty.} = template addImpl() {.dirty.} =
if mustRehash(len(t.data), t.counter): enlarge(t) if mustRehash(len(t.data), t.counter): enlarge(t)
rawInsert(t, t.data, key, val) var hc: THash
var j = rawGetDeep(t, key, hc)
rawInsert(t, t.data, key, val, hc, j)
inc(t.counter) inc(t.counter)
template putImpl() {.dirty.} = template putImpl() {.dirty.} =
var index = rawGet(t, key) var hc: THash
var index = rawGet(t, key, hc)
if index >= 0: if index >= 0:
t.data[index].val = val t.data[index].val = val
else: else:
addImpl() if mustRehash(len(t.data), t.counter):
enlarge(t)
index = rawGetKnownHC(t, key, hc)
rawInsert(t, t.data, key, val, hc, -1 - index)
inc(t.counter)
when false: when false:
# not yet used: # not yet used:
template hasKeyOrPutImpl() {.dirty.} = template hasKeyOrPutImpl() {.dirty.} =
var index = rawGet(t, key) var hc: THash
var index = rawGet(t, key, hc)
if index >= 0: if index >= 0:
t.data[index].val = val t.data[index].val = val
result = true result = true
@ -214,19 +265,36 @@ proc add*[A, B](t: var Table[A, B], key: A, val: B) =
## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists. ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
addImpl() addImpl()
template doWhile(a: expr, b: stmt): stmt =
while true:
b
if not a: break
proc del*[A, B](t: var Table[A, B], key: A) = proc del*[A, B](t: var Table[A, B], key: A) =
## deletes `key` from hash table `t`. ## deletes `key` from hash table `t`.
let index = rawGet(t, key) var hc: THash
if index >= 0: var i = rawGet(t, key, hc)
t.data[index].slot = seDeleted let msk = high(t.data)
if i >= 0:
t.data[i].hcode = 0
dec(t.counter) dec(t.counter)
while true: # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1
var j = i # The correctness of this depends on (h+1) in nextTry,
var r = j # though may be adaptable to other simple sequences.
t.data[i].hcode = 0 # mark current EMPTY
doWhile ((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)):
i = (i + 1) and msk # increment mod table size
if isEmpty(t.data[i].hcode): # end of collision cluster; So all done
return
r = t.data[i].hcode and msk # "home" location of key@i
shallowCopy(t.data[j], t.data[i]) # data[j] will be marked EMPTY next loop
proc initTable*[A, B](initialSize=64): Table[A, B] = proc initTable*[A, B](initialSize=64): Table[A, B] =
## creates a new hash table that is empty. ## creates a new hash table that is empty.
## ##
## `initialSize` needs to be a power of two. If you need to accept runtime ## `initialSize` needs to be a power of two. If you need to accept runtime
## values for this you could use the ``nextPowerOfTwo`` proc from the ## values for this you could use the ``nextPowerOfTwo`` proc from the
## `math <math.html>`_ module. ## `math <math.html>`_ module or the ``rightSize`` proc from this module.
assert isPowerOfTwo(initialSize) assert isPowerOfTwo(initialSize)
result.counter = 0 result.counter = 0
newSeq(result.data, initialSize) newSeq(result.data, initialSize)
@ -234,7 +302,7 @@ proc initTable*[A, B](initialSize=64): Table[A, B] =
proc toTable*[A, B](pairs: openArray[tuple[key: A, proc toTable*[A, B](pairs: openArray[tuple[key: A,
val: B]]): Table[A, B] = val: B]]): Table[A, B] =
## creates a new hash table that contains the given `pairs`. ## creates a new hash table that contains the given `pairs`.
result = initTable[A, B](nextPowerOfTwo(pairs.len+10)) result = initTable[A, B](rightSize(pairs.len))
for key, val in items(pairs): result[key] = val for key, val in items(pairs): result[key] = val
template dollarImpl(): stmt {.dirty.} = template dollarImpl(): stmt {.dirty.} =
@ -280,28 +348,28 @@ proc len*[A, B](t: TableRef[A, B]): int =
iterator pairs*[A, B](t: TableRef[A, B]): tuple[key: A, val: B] = iterator pairs*[A, B](t: TableRef[A, B]): tuple[key: A, val: B] =
## iterates over any (key, value) pair in the table `t`. ## iterates over any (key, value) pair in the table `t`.
for h in 0..high(t.data): for h in 0..high(t.data):
if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val) if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
iterator mpairs*[A, B](t: TableRef[A, B]): tuple[key: A, val: var B] = iterator mpairs*[A, B](t: TableRef[A, B]): tuple[key: A, val: var B] =
## iterates over any (key, value) pair in the table `t`. The values ## iterates over any (key, value) pair in the table `t`. The values
## can be modified. ## can be modified.
for h in 0..high(t.data): for h in 0..high(t.data):
if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val) if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
iterator keys*[A, B](t: TableRef[A, B]): A = iterator keys*[A, B](t: TableRef[A, B]): A =
## iterates over any key in the table `t`. ## iterates over any key in the table `t`.
for h in 0..high(t.data): for h in 0..high(t.data):
if t.data[h].slot == seFilled: yield t.data[h].key if isFilled(t.data[h].hcode): yield t.data[h].key
iterator values*[A, B](t: TableRef[A, B]): B = iterator values*[A, B](t: TableRef[A, B]): B =
## iterates over any value in the table `t`. ## iterates over any value in the table `t`.
for h in 0..high(t.data): for h in 0..high(t.data):
if t.data[h].slot == seFilled: yield t.data[h].val if isFilled(t.data[h].hcode): yield t.data[h].val
iterator mvalues*[A, B](t: TableRef[A, B]): var B = iterator mvalues*[A, B](t: TableRef[A, B]): var B =
## iterates over any value in the table `t`. The values can be modified. ## iterates over any value in the table `t`. The values can be modified.
for h in 0..high(t.data): for h in 0..high(t.data):
if t.data[h].slot == seFilled: yield t.data[h].val if isFilled(t.data[h].hcode): yield t.data[h].val
proc `[]`*[A, B](t: TableRef[A, B], key: A): B = proc `[]`*[A, B](t: TableRef[A, B], key: A): B =
## retrieves the value at ``t[key]``. If `key` is not in `t`, ## retrieves the value at ``t[key]``. If `key` is not in `t`,
@ -360,7 +428,7 @@ proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B]
type type
OrderedKeyValuePair[A, B] = tuple[ OrderedKeyValuePair[A, B] = tuple[
slot: SlotEnum, next: int, key: A, val: B] hcode: THash, next: int, key: A, val: B]
OrderedKeyValuePairSeq[A, B] = seq[OrderedKeyValuePair[A, B]] OrderedKeyValuePairSeq[A, B] = seq[OrderedKeyValuePair[A, B]]
OrderedTable* {. OrderedTable* {.
myShallow.}[A, B] = object ## table that remembers insertion order myShallow.}[A, B] = object ## table that remembers insertion order
@ -378,7 +446,7 @@ template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} =
var h = t.first var h = t.first
while h >= 0: while h >= 0:
var nxt = t.data[h].next var nxt = t.data[h].next
if t.data[h].slot == seFilled: yieldStmt if isFilled(t.data[h].hcode): yieldStmt
h = nxt h = nxt
iterator pairs*[A, B](t: OrderedTable[A, B]): tuple[key: A, val: B] = iterator pairs*[A, B](t: OrderedTable[A, B]): tuple[key: A, val: B] =
@ -409,7 +477,13 @@ iterator mvalues*[A, B](t: var OrderedTable[A, B]): var B =
forAllOrderedPairs: forAllOrderedPairs:
yield t.data[h].val yield t.data[h].val
proc rawGet[A, B](t: OrderedTable[A, B], key: A): int = proc rawGetKnownHC[A, B](t: OrderedTable[A, B], key: A, hc: THash): int =
rawGetKnownHCImpl()
proc rawGetDeep[A, B](t: OrderedTable[A, B], key: A, hc: var THash): int {.inline.} =
rawGetDeepImpl()
proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var THash): int =
rawGetImpl() rawGetImpl()
proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B = proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B =
@ -417,23 +491,26 @@ proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B =
## default empty value for the type `B` is returned ## default empty value for the type `B` is returned
## and no exception is raised. One can check with ``hasKey`` whether the key ## and no exception is raised. One can check with ``hasKey`` whether the key
## exists. ## exists.
var index = rawGet(t, key) var hc: THash
var index = rawGet(t, key, hc)
if index >= 0: result = t.data[index].val if index >= 0: result = t.data[index].val
proc mget*[A, B](t: var OrderedTable[A, B], key: A): var B = proc mget*[A, B](t: var OrderedTable[A, B], key: A): var B =
## retrieves the value at ``t[key]``. The value can be modified. ## retrieves the value at ``t[key]``. The value can be modified.
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised. ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
var index = rawGet(t, key) var hc: THash
var index = rawGet(t, key, hc)
if index >= 0: result = t.data[index].val if index >= 0: result = t.data[index].val
else: raise newException(KeyError, "key not found: " & $key) else: raise newException(KeyError, "key not found: " & $key)
proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool = proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool =
## returns true iff `key` is in the table `t`. ## returns true iff `key` is in the table `t`.
result = rawGet(t, key) >= 0 var hc: THash
result = rawGet(t, key, hc) >= 0
proc rawInsert[A, B](t: var OrderedTable[A, B], proc rawInsert[A, B](t: var OrderedTable[A, B],
data: var OrderedKeyValuePairSeq[A, B], data: var OrderedKeyValuePairSeq[A, B],
key: A, val: B) = key: A, val: B, hc: THash, h: THash) =
rawInsertImpl() rawInsertImpl()
data[h].next = -1 data[h].next = -1
if t.first < 0: t.first = h if t.first < 0: t.first = h
@ -446,12 +523,13 @@ proc enlarge[A, B](t: var OrderedTable[A, B]) =
var h = t.first var h = t.first
t.first = -1 t.first = -1
t.last = -1 t.last = -1
while h >= 0:
var nxt = t.data[h].next
if t.data[h].slot == seFilled:
rawInsert(t, n, t.data[h].key, t.data[h].val)
h = nxt
swap(t.data, n) swap(t.data, n)
while h >= 0:
var nxt = n[h].next
if isFilled(n[h].hcode):
var j = -1 - rawGetKnownHC(t, n[h].key, n[h].hcode)
rawInsert(t, t.data, n[h].key, n[h].val, n[h].hcode, j)
h = nxt
proc `[]=`*[A, B](t: var OrderedTable[A, B], key: A, val: B) = proc `[]=`*[A, B](t: var OrderedTable[A, B], key: A, val: B) =
## puts a (key, value)-pair into `t`. ## puts a (key, value)-pair into `t`.
@ -466,7 +544,7 @@ proc initOrderedTable*[A, B](initialSize=64): OrderedTable[A, B] =
## ##
## `initialSize` needs to be a power of two. If you need to accept runtime ## `initialSize` needs to be a power of two. If you need to accept runtime
## values for this you could use the ``nextPowerOfTwo`` proc from the ## values for this you could use the ``nextPowerOfTwo`` proc from the
## `math <math.html>`_ module. ## `math <math.html>`_ module or the ``rightSize`` proc from this module.
assert isPowerOfTwo(initialSize) assert isPowerOfTwo(initialSize)
result.counter = 0 result.counter = 0
result.first = -1 result.first = -1
@ -476,7 +554,7 @@ proc initOrderedTable*[A, B](initialSize=64): OrderedTable[A, B] =
proc toOrderedTable*[A, B](pairs: openArray[tuple[key: A, proc toOrderedTable*[A, B](pairs: openArray[tuple[key: A,
val: B]]): OrderedTable[A, B] = val: B]]): OrderedTable[A, B] =
## creates a new ordered hash table that contains the given `pairs`. ## creates a new ordered hash table that contains the given `pairs`.
result = initOrderedTable[A, B](nextPowerOfTwo(pairs.len+10)) result = initOrderedTable[A, B](rightSize(pairs.len))
for key, val in items(pairs): result[key] = val for key, val in items(pairs): result[key] = val
proc `$`*[A, B](t: OrderedTable[A, B]): string = proc `$`*[A, B](t: OrderedTable[A, B]): string =
@ -537,7 +615,7 @@ template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} =
var h = t.first var h = t.first
while h >= 0: while h >= 0:
var nxt = t.data[h].next var nxt = t.data[h].next
if t.data[h].slot == seFilled: yieldStmt if isFilled(t.data[h].hcode): yieldStmt
h = nxt h = nxt
iterator pairs*[A, B](t: OrderedTableRef[A, B]): tuple[key: A, val: B] = iterator pairs*[A, B](t: OrderedTableRef[A, B]): tuple[key: A, val: B] =
@ -597,14 +675,14 @@ proc newOrderedTable*[A, B](initialSize=64): OrderedTableRef[A, B] =
## ##
## `initialSize` needs to be a power of two. If you need to accept runtime ## `initialSize` needs to be a power of two. If you need to accept runtime
## values for this you could use the ``nextPowerOfTwo`` proc from the ## values for this you could use the ``nextPowerOfTwo`` proc from the
## `math <math.html>`_ module. ## `math <math.html>`_ module or the ``rightSize`` proc from this module.
new(result) new(result)
result[] = initOrderedTable[A, B]() result[] = initOrderedTable[A, B]()
proc newOrderedTable*[A, B](pairs: openArray[tuple[key: A, proc newOrderedTable*[A, B](pairs: openArray[tuple[key: A,
val: B]]): OrderedTableRef[A, B] = val: B]]): OrderedTableRef[A, B] =
## creates a new ordered hash table that contains the given `pairs`. ## creates a new ordered hash table that contains the given `pairs`.
result = newOrderedTable[A, B](nextPowerOfTwo(pairs.len+10)) result = newOrderedTable[A, B](rightSize(pairs.len))
for key, val in items(pairs): result[key] = val for key, val in items(pairs): result[key] = val
proc `$`*[A, B](t: OrderedTableRef[A, B]): string = proc `$`*[A, B](t: OrderedTableRef[A, B]): string =
@ -665,7 +743,7 @@ proc rawGet[A](t: CountTable[A], key: A): int =
while t.data[h].val != 0: while t.data[h].val != 0:
if t.data[h].key == key: return h if t.data[h].key == key: return h
h = nextTry(h, high(t.data)) h = nextTry(h, high(t.data))
result = -1 result = -1 - h # < 0 => MISSING; insert idx = -1 - result
proc `[]`*[A](t: CountTable[A], key: A): int = proc `[]`*[A](t: CountTable[A], key: A): int =
## retrieves the value at ``t[key]``. If `key` is not in `t`, ## retrieves the value at ``t[key]``. If `key` is not in `t`,
@ -702,21 +780,27 @@ proc enlarge[A](t: var CountTable[A]) =
proc `[]=`*[A](t: var CountTable[A], key: A, val: int) = proc `[]=`*[A](t: var CountTable[A], key: A, val: int) =
## puts a (key, value)-pair into `t`. `val` has to be positive. ## puts a (key, value)-pair into `t`. `val` has to be positive.
assert val > 0 assert val > 0
putImpl() var h = rawGet(t, key)
if h >= 0:
t.data[h].val = val
else:
h = -1 - h
t.data[h].key = key
t.data[h].val = val
proc initCountTable*[A](initialSize=64): CountTable[A] = proc initCountTable*[A](initialSize=64): CountTable[A] =
## creates a new count table that is empty. ## creates a new count table that is empty.
## ##
## `initialSize` needs to be a power of two. If you need to accept runtime ## `initialSize` needs to be a power of two. If you need to accept runtime
## values for this you could use the ``nextPowerOfTwo`` proc from the ## values for this you could use the ``nextPowerOfTwo`` proc from the
## `math <math.html>`_ module. ## `math <math.html>`_ module or the ``rightSize`` proc in this module.
assert isPowerOfTwo(initialSize) assert isPowerOfTwo(initialSize)
result.counter = 0 result.counter = 0
newSeq(result.data, initialSize) newSeq(result.data, initialSize)
proc toCountTable*[A](keys: openArray[A]): CountTable[A] = proc toCountTable*[A](keys: openArray[A]): CountTable[A] =
## creates a new count table with every key in `keys` having a count of 1. ## creates a new count table with every key in `keys` having a count of 1.
result = initCountTable[A](nextPowerOfTwo(keys.len+10)) result = initCountTable[A](rightSize(keys.len))
for key in items(keys): result[key] = 1 for key in items(keys): result[key] = 1
proc `$`*[A](t: CountTable[A]): string = proc `$`*[A](t: CountTable[A]): string =
@ -827,13 +911,13 @@ proc newCountTable*[A](initialSize=64): CountTableRef[A] =
## ##
## `initialSize` needs to be a power of two. If you need to accept runtime ## `initialSize` needs to be a power of two. If you need to accept runtime
## values for this you could use the ``nextPowerOfTwo`` proc from the ## values for this you could use the ``nextPowerOfTwo`` proc from the
## `math <math.html>`_ module. ## `math <math.html>`_ module or the ``rightSize`` method in this module.
new(result) new(result)
result[] = initCountTable[A](initialSize) result[] = initCountTable[A](initialSize)
proc newCountTable*[A](keys: openArray[A]): CountTableRef[A] = proc newCountTable*[A](keys: openArray[A]): CountTableRef[A] =
## creates a new count table with every key in `keys` having a count of 1. ## creates a new count table with every key in `keys` having a count of 1.
result = newCountTable[A](nextPowerOfTwo(keys.len+10)) result = newCountTable[A](rightSize(keys.len))
for key in items(keys): result[key] = 1 for key in items(keys): result[key] = 1
proc `$`*[A](t: CountTableRef[A]): string = proc `$`*[A](t: CountTableRef[A]): string =

View file

@ -42,7 +42,7 @@ proc validEmailAddress*(s: string): bool {.noSideEffect,
case toLower(x) case toLower(x)
of "com", "org", "net", "gov", "mil", "biz", "info", "mobi", "name", of "com", "org", "net", "gov", "mil", "biz", "info", "mobi", "name",
"aero", "jobs", "museum": return true "aero", "jobs", "museum": return true
return false else: return false
proc parseInt*(s: string, value: var int, validRange: Slice[int]) {. proc parseInt*(s: string, value: var int, validRange: Slice[int]) {.
noSideEffect, rtl, extern: "nmatchParseInt".} = noSideEffect, rtl, extern: "nmatchParseInt".} =

View file

@ -1235,11 +1235,12 @@ proc reversed*(s: string): string =
## returns the reverse of `s`, interpreting it as unicode characters. Unicode ## returns the reverse of `s`, interpreting it as unicode characters. Unicode
## combining characters are correctly interpreted as well: ## combining characters are correctly interpreted as well:
## ##
## .. code-block: ## .. code-block:: nim
##
## assert reversed("Reverse this!") == "!siht esreveR" ## assert reversed("Reverse this!") == "!siht esreveR"
## assert reversed("先秦兩漢") == "漢兩秦先" ## assert reversed("先秦兩漢") == "漢兩秦先"
## assert reversed("as⃝df̅") == "f̅ds⃝a" ## assert reversed("as⃝df̅") == "f̅ds⃝a"
## assert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞" ## assert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞"
var var
i = 0 i = 0
lastI = 0 lastI = 0

View file

@ -95,7 +95,9 @@ when defined(windows):
importc: "TlsGetValue", stdcall, dynlib: "kernel32".} importc: "TlsGetValue", stdcall, dynlib: "kernel32".}
else: else:
{.passL: "-pthread".} when not defined(macosx):
{.passL: "-pthread".}
{.passC: "-pthread".} {.passC: "-pthread".}
type type

View file

@ -62,7 +62,7 @@ allowing you to create commercial applications.
Read copying.txt for more details. Read copying.txt for more details.
Copyright (c) 2006-2014 Andreas Rumpf. Copyright (c) 2006-2015 Andreas Rumpf.
All rights reserved. All rights reserved.
# Build Status # Build Status

View file

@ -47,7 +47,7 @@ block tableTest1:
for y in 0..1: for y in 0..1:
assert t[(x,y)] == $x & $y assert t[(x,y)] == $x & $y
assert($t == assert($t ==
"{(x: 0, y: 0): 00, (x: 0, y: 1): 01, (x: 1, y: 0): 10, (x: 1, y: 1): 11}") "{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
block tableTest2: block tableTest2:
var t = initTable[string, float]() var t = initTable[string, float]()

View file

@ -302,7 +302,7 @@ template build_specification_lookup():
## Returns the table used to keep pointers to all of the specifications. ## Returns the table used to keep pointers to all of the specifications.
var result {.gensym.}: OrderedTable[string, ptr Tparameter_specification] var result {.gensym.}: OrderedTable[string, ptr Tparameter_specification]
result = initOrderedTable[string, ptr Tparameter_specification]( result = initOrderedTable[string, ptr Tparameter_specification](
nextPowerOfTwo(expected.len)) tables.rightSize(expected.len))
for i in 0..expected.len-1: for i in 0..expected.len-1:
for param_to_detect in expected[i].names: for param_to_detect in expected[i].names:
if result.hasKey(param_to_detect): if result.hasKey(param_to_detect):

View file

@ -0,0 +1,17 @@
type
RectArray*[R, C: static[int], T] = distinct array[R * C, T]
StaticMatrix*[R, C: static[int], T] = object
elements*: RectArray[R, C, T]
StaticVector*[N: static[int], T] = StaticMatrix[N, 1, T]
proc foo*[N, T](a: StaticVector[N, T]): T = 0.T
proc foobar*[N, T](a, b: StaticVector[N, T]): T = 0.T
var a: StaticVector[3, int]
echo foo(a) # OK
echo foobar(a, a) # <--- hangs compiler

View file

@ -0,0 +1,11 @@
discard """
errormsg: "identifier expected, but found 'keyword when'"
"""
# bug #2123
type num = enum
NUM_NONE = 0
NUM_ALL = 1
when defined(macosx): NUM_OSX = 10 # only this differs for real
NUM_XTRA = 20

View file

@ -0,0 +1,9 @@
# bug #2121
type
Item[K,V] = tuple
key: K
value: V
var q = newseq[Item[int,int]](0)
let (x,y) = q[0]

View file

@ -50,8 +50,8 @@
SetCompressor /SOLID /FINAL lzma SetCompressor /SOLID /FINAL lzma
; Installer and Uninstaller Icons ; Installer and Uninstaller Icons
; Icon "nimrod.ico" ; Icon "nim.ico"
; UninstallIcon "nimrod.ico" ; UninstallIcon "nim.ico"
; Set installation details to be shown by default ; Set installation details to be shown by default
ShowInstDetails show ShowInstDetails show

View file

@ -61,6 +61,7 @@ srcdoc2: "pure/rawsockets;pure/asynchttpserver;pure/net;pure/selectors;pure/futu
srcdoc2: "pure/md5" srcdoc2: "pure/md5"
srcdoc2: "posix/posix" srcdoc2: "posix/posix"
srcdoc2: "pure/fenv" srcdoc2: "pure/fenv"
srcdoc2: "pure/basic2d;pure/basic3d"
; Note: everything under 'webdoc' doesn't get listed in the index, so wrappers ; Note: everything under 'webdoc' doesn't get listed in the index, so wrappers
; should live here ; should live here