mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-25 16:53:59 +00:00
Merge branch 'devel' into faster-nimsuggest
This commit is contained in:
@@ -69,16 +69,14 @@ import db_common
|
||||
export db_common
|
||||
|
||||
type
|
||||
DbConn* = PPGconn ## encapsulates a database connection
|
||||
Row* = seq[string] ## a row of a dataset. NULL database values will be
|
||||
## converted to nil.
|
||||
InstantRow* = tuple[res: PPGresult, line: int32] ## a handle that can be
|
||||
## used to get a row's
|
||||
## column text on demand
|
||||
DbConn* = PPGconn ## encapsulates a database connection
|
||||
Row* = seq[string] ## a row of a dataset. NULL database values will be
|
||||
## converted to nil.
|
||||
InstantRow* = object ## a handle that can be
|
||||
res: PPGresult ## used to get a row's
|
||||
line: int ## column text on demand
|
||||
SqlPrepared* = distinct string ## a identifier for the prepared queries
|
||||
|
||||
{.deprecated: [TRow: Row, TDbConn: DbConn,
|
||||
TSqlPrepared: SqlPrepared].}
|
||||
{.deprecated: [TRow: Row, TDbConn: DbConn, TSqlPrepared: SqlPrepared].}
|
||||
|
||||
proc dbError*(db: DbConn) {.noreturn.} =
|
||||
## raises a DbError exception.
|
||||
@@ -213,7 +211,7 @@ iterator instantRows*(db: DbConn, query: SqlQuery,
|
||||
## on demand using []. Returned handle is valid only within iterator body.
|
||||
var res = setupQuery(db, query, args)
|
||||
for i in 0..pqNtuples(res)-1:
|
||||
yield (res: res, line: i)
|
||||
yield InstantRow(res: res, line: i)
|
||||
pqClear(res)
|
||||
|
||||
iterator instantRows*(db: DbConn, stmtName: SqlPrepared,
|
||||
@@ -223,16 +221,170 @@ iterator instantRows*(db: DbConn, stmtName: SqlPrepared,
|
||||
## on demand using []. Returned handle is valid only within iterator body.
|
||||
var res = setupQuery(db, stmtName, args)
|
||||
for i in 0..pqNtuples(res)-1:
|
||||
yield (res: res, line: i)
|
||||
yield InstantRow(res: res, line: i)
|
||||
pqClear(res)
|
||||
|
||||
proc `[]`*(row: InstantRow, col: int32): string {.inline.} =
|
||||
## returns text for given column of the row
|
||||
$pqgetvalue(row.res, row.line, col)
|
||||
proc getColumnType(res: PPGresult, col: int) : DbType =
|
||||
## returns DbType for given column in the row
|
||||
## defined in pg_type.h file in the postgres source code
|
||||
## Wire representation for types: http://www.npgsql.org/dev/types.html
|
||||
var oid = pqftype(res, int32(col))
|
||||
## The integer returned is the internal OID number of the type
|
||||
case oid
|
||||
of 16: return DbType(kind: DbTypeKind.dbBool, name: "bool")
|
||||
of 17: return DbType(kind: DbTypeKind.dbBlob, name: "bytea")
|
||||
|
||||
proc len*(row: InstantRow): int32 {.inline.} =
|
||||
of 21: return DbType(kind: DbTypeKind.dbInt, name: "int2", size: 2)
|
||||
of 23: return DbType(kind: DbTypeKind.dbInt, name: "int4", size: 4)
|
||||
of 20: return DbType(kind: DbTypeKind.dbInt, name: "int8", size: 8)
|
||||
of 1560: return DbType(kind: DbTypeKind.dbBit, name: "bit")
|
||||
of 1562: return DbType(kind: DbTypeKind.dbInt, name: "varbit")
|
||||
|
||||
of 18: return DbType(kind: DbTypeKind.dbFixedChar, name: "char")
|
||||
of 19: return DbType(kind: DbTypeKind.dbFixedChar, name: "name")
|
||||
of 1042: return DbType(kind: DbTypeKind.dbFixedChar, name: "bpchar")
|
||||
|
||||
of 25: return DbType(kind: DbTypeKind.dbVarchar, name: "text")
|
||||
of 1043: return DbType(kind: DbTypeKind.dbVarChar, name: "varchar")
|
||||
of 2275: return DbType(kind: DbTypeKind.dbVarchar, name: "cstring")
|
||||
|
||||
of 700: return DbType(kind: DbTypeKind.dbFloat, name: "float4")
|
||||
of 701: return DbType(kind: DbTypeKind.dbFloat, name: "float8")
|
||||
|
||||
of 790: return DbType(kind: DbTypeKind.dbDecimal, name: "money")
|
||||
of 1700: return DbType(kind: DbTypeKind.dbDecimal, name: "numeric")
|
||||
|
||||
of 704: return DbType(kind: DbTypeKind.dbTimeInterval, name: "tinterval")
|
||||
of 702: return DbType(kind: DbTypeKind.dbTimestamp, name: "abstime")
|
||||
of 703: return DbType(kind: DbTypeKind.dbTimeInterval, name: "reltime")
|
||||
of 1082: return DbType(kind: DbTypeKind.dbDate, name: "date")
|
||||
of 1083: return DbType(kind: DbTypeKind.dbTime, name: "time")
|
||||
of 1114: return DbType(kind: DbTypeKind.dbTimestamp, name: "timestamp")
|
||||
of 1184: return DbType(kind: DbTypeKind.dbTimestamp, name: "timestamptz")
|
||||
of 1186: return DbType(kind: DbTypeKind.dbTimeInterval, name: "interval")
|
||||
of 1266: return DbType(kind: DbTypeKind.dbTime, name: "timetz")
|
||||
|
||||
of 114: return DbType(kind: DbTypeKind.dbJson, name: "json")
|
||||
of 142: return DbType(kind: DbTypeKind.dbXml, name: "xml")
|
||||
of 3802: return DbType(kind: DbTypeKind.dbJson, name: "jsonb")
|
||||
|
||||
of 600: return DbType(kind: DbTypeKind.dbPoint, name: "point")
|
||||
of 601: return DbType(kind: DbTypeKind.dbLseg, name: "lseg")
|
||||
of 602: return DbType(kind: DbTypeKind.dbPath, name: "path")
|
||||
of 603: return DbType(kind: DbTypeKind.dbBox, name: "box")
|
||||
of 604: return DbType(kind: DbTypeKind.dbPolygon, name: "polygon")
|
||||
of 628: return DbType(kind: DbTypeKind.dbLine, name: "line")
|
||||
of 718: return DbType(kind: DbTypeKind.dbCircle, name: "circle")
|
||||
|
||||
of 650: return DbType(kind: DbTypeKind.dbInet, name: "cidr")
|
||||
of 829: return DbType(kind: DbTypeKind.dbMacAddress, name: "macaddr")
|
||||
of 869: return DbType(kind: DbTypeKind.dbInet, name: "inet")
|
||||
|
||||
of 2950: return DbType(kind: DbTypeKind.dbVarchar, name: "uuid")
|
||||
of 3614: return DbType(kind: DbTypeKind.dbVarchar, name: "tsvector")
|
||||
of 3615: return DbType(kind: DbTypeKind.dbVarchar, name: "tsquery")
|
||||
of 2970: return DbType(kind: DbTypeKind.dbVarchar, name: "txid_snapshot")
|
||||
|
||||
of 27: return DbType(kind: DbTypeKind.dbComposite, name: "tid")
|
||||
of 1790: return DbType(kind: DbTypeKind.dbComposite, name: "refcursor")
|
||||
of 2249: return DbType(kind: DbTypeKind.dbComposite, name: "record")
|
||||
of 3904: return DbType(kind: DbTypeKind.dbComposite, name: "int4range")
|
||||
of 3906: return DbType(kind: DbTypeKind.dbComposite, name: "numrange")
|
||||
of 3908: return DbType(kind: DbTypeKind.dbComposite, name: "tsrange")
|
||||
of 3910: return DbType(kind: DbTypeKind.dbComposite, name: "tstzrange")
|
||||
of 3912: return DbType(kind: DbTypeKind.dbComposite, name: "daterange")
|
||||
of 3926: return DbType(kind: DbTypeKind.dbComposite, name: "int8range")
|
||||
|
||||
of 22: return DbType(kind: DbTypeKind.dbArray, name: "int2vector")
|
||||
of 30: return DbType(kind: DbTypeKind.dbArray, name: "oidvector")
|
||||
of 143: return DbType(kind: DbTypeKind.dbArray, name: "xml[]")
|
||||
of 199: return DbType(kind: DbTypeKind.dbArray, name: "json[]")
|
||||
of 629: return DbType(kind: DbTypeKind.dbArray, name: "line[]")
|
||||
of 651: return DbType(kind: DbTypeKind.dbArray, name: "cidr[]")
|
||||
of 719: return DbType(kind: DbTypeKind.dbArray, name: "circle[]")
|
||||
of 791: return DbType(kind: DbTypeKind.dbArray, name: "money[]")
|
||||
of 1000: return DbType(kind: DbTypeKind.dbArray, name: "bool[]")
|
||||
of 1001: return DbType(kind: DbTypeKind.dbArray, name: "bytea[]")
|
||||
of 1002: return DbType(kind: DbTypeKind.dbArray, name: "char[]")
|
||||
of 1003: return DbType(kind: DbTypeKind.dbArray, name: "name[]")
|
||||
of 1005: return DbType(kind: DbTypeKind.dbArray, name: "int2[]")
|
||||
of 1006: return DbType(kind: DbTypeKind.dbArray, name: "int2vector[]")
|
||||
of 1007: return DbType(kind: DbTypeKind.dbArray, name: "int4[]")
|
||||
of 1008: return DbType(kind: DbTypeKind.dbArray, name: "regproc[]")
|
||||
of 1009: return DbType(kind: DbTypeKind.dbArray, name: "text[]")
|
||||
of 1028: return DbType(kind: DbTypeKind.dbArray, name: "oid[]")
|
||||
of 1010: return DbType(kind: DbTypeKind.dbArray, name: "tid[]")
|
||||
of 1011: return DbType(kind: DbTypeKind.dbArray, name: "xid[]")
|
||||
of 1012: return DbType(kind: DbTypeKind.dbArray, name: "cid[]")
|
||||
of 1013: return DbType(kind: DbTypeKind.dbArray, name: "oidvector[]")
|
||||
of 1014: return DbType(kind: DbTypeKind.dbArray, name: "bpchar[]")
|
||||
of 1015: return DbType(kind: DbTypeKind.dbArray, name: "varchar[]")
|
||||
of 1016: return DbType(kind: DbTypeKind.dbArray, name: "int8[]")
|
||||
of 1017: return DbType(kind: DbTypeKind.dbArray, name: "point[]")
|
||||
of 1018: return DbType(kind: DbTypeKind.dbArray, name: "lseg[]")
|
||||
of 1019: return DbType(kind: DbTypeKind.dbArray, name: "path[]")
|
||||
of 1020: return DbType(kind: DbTypeKind.dbArray, name: "box[]")
|
||||
of 1021: return DbType(kind: DbTypeKind.dbArray, name: "float4[]")
|
||||
of 1022: return DbType(kind: DbTypeKind.dbArray, name: "float8[]")
|
||||
of 1023: return DbType(kind: DbTypeKind.dbArray, name: "abstime[]")
|
||||
of 1024: return DbType(kind: DbTypeKind.dbArray, name: "reltime[]")
|
||||
of 1025: return DbType(kind: DbTypeKind.dbArray, name: "tinterval[]")
|
||||
of 1027: return DbType(kind: DbTypeKind.dbArray, name: "polygon[]")
|
||||
of 1040: return DbType(kind: DbTypeKind.dbArray, name: "macaddr[]")
|
||||
of 1041: return DbType(kind: DbTypeKind.dbArray, name: "inet[]")
|
||||
of 1263: return DbType(kind: DbTypeKind.dbArray, name: "cstring[]")
|
||||
of 1115: return DbType(kind: DbTypeKind.dbArray, name: "timestamp[]")
|
||||
of 1182: return DbType(kind: DbTypeKind.dbArray, name: "date[]")
|
||||
of 1183: return DbType(kind: DbTypeKind.dbArray, name: "time[]")
|
||||
of 1185: return DbType(kind: DbTypeKind.dbArray, name: "timestamptz[]")
|
||||
of 1187: return DbType(kind: DbTypeKind.dbArray, name: "interval[]")
|
||||
of 1231: return DbType(kind: DbTypeKind.dbArray, name: "numeric[]")
|
||||
of 1270: return DbType(kind: DbTypeKind.dbArray, name: "timetz[]")
|
||||
of 1561: return DbType(kind: DbTypeKind.dbArray, name: "bit[]")
|
||||
of 1563: return DbType(kind: DbTypeKind.dbArray, name: "varbit[]")
|
||||
of 2201: return DbType(kind: DbTypeKind.dbArray, name: "refcursor[]")
|
||||
of 2951: return DbType(kind: DbTypeKind.dbArray, name: "uuid[]")
|
||||
of 3643: return DbType(kind: DbTypeKind.dbArray, name: "tsvector[]")
|
||||
of 3645: return DbType(kind: DbTypeKind.dbArray, name: "tsquery[]")
|
||||
of 3807: return DbType(kind: DbTypeKind.dbArray, name: "jsonb[]")
|
||||
of 2949: return DbType(kind: DbTypeKind.dbArray, name: "txid_snapshot[]")
|
||||
of 3905: return DbType(kind: DbTypeKind.dbArray, name: "int4range[]")
|
||||
of 3907: return DbType(kind: DbTypeKind.dbArray, name: "numrange[]")
|
||||
of 3909: return DbType(kind: DbTypeKind.dbArray, name: "tsrange[]")
|
||||
of 3911: return DbType(kind: DbTypeKind.dbArray, name: "tstzrange[]")
|
||||
of 3913: return DbType(kind: DbTypeKind.dbArray, name: "daterange[]")
|
||||
of 3927: return DbType(kind: DbTypeKind.dbArray, name: "int8range[]")
|
||||
of 2287: return DbType(kind: DbTypeKind.dbArray, name: "record[]")
|
||||
|
||||
of 705: return DbType(kind: DbTypeKind.dbUnknown, name: "unknown")
|
||||
else: return DbType(kind: DbTypeKind.dbUnknown, name: $oid) ## Query the system table pg_type to determine exactly which type is referenced.
|
||||
|
||||
proc setColumnInfo(columns: var DbColumns; res: PPGresult; L: int32) =
|
||||
setLen(columns, L)
|
||||
for i in 0..<L:
|
||||
columns[i].name = $pqfname(res, i)
|
||||
columns[i].typ = getColumnType(res, i)
|
||||
columns[i].tableName = $(pqftable(res, i)) ## Returns the OID of the table from which the given column was fetched.
|
||||
## Query the system table pg_class to determine exactly which table is referenced.
|
||||
#columns[i].primaryKey = libpq does not have a function for that
|
||||
#columns[i].foreignKey = libpq does not have a function for that
|
||||
|
||||
iterator instantRows*(db: DbConn; columns: var DbColumns; query: SqlQuery;
|
||||
args: varargs[string, `$`]): InstantRow
|
||||
{.tags: [ReadDbEffect].} =
|
||||
var res = setupQuery(db, query, args)
|
||||
setColumnInfo(columns, res, pqnfields(res))
|
||||
for i in 0..<pqntuples(res):
|
||||
yield InstantRow(res: res, line: i)
|
||||
pqClear(res)
|
||||
|
||||
proc `[]`*(row: InstantRow; col: int): string {.inline.} =
|
||||
## returns text for given column of the row
|
||||
$pqgetvalue(row.res, int32(row.line), int32(col))
|
||||
|
||||
proc len*(row: InstantRow): int {.inline.} =
|
||||
## returns number of columns in the row
|
||||
pqNfields(row.res)
|
||||
int(pqNfields(row.res))
|
||||
|
||||
proc getRow*(db: DbConn, query: SqlQuery,
|
||||
args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} =
|
||||
|
||||
@@ -290,7 +290,7 @@ proc find*(buf: cstring, pattern: Regex, matches: var openArray[string],
|
||||
for i in 1..int(res)-1:
|
||||
var a = rawMatches[i * 2]
|
||||
var b = rawMatches[i * 2 + 1]
|
||||
if a >= 0'i32: matches[i-1] = bufSubstr(buf, int(a), int(b)-1)
|
||||
if a >= 0'i32: matches[i-1] = bufSubstr(buf, int(a), int(b))
|
||||
else: matches[i-1] = nil
|
||||
return rawMatches[0]
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ proc reverse*[T](a: var openArray[T], first, last: Natural) =
|
||||
|
||||
proc reverse*[T](a: var openArray[T]) =
|
||||
## reverses the array `a`.
|
||||
reverse(a, 0, a.high)
|
||||
reverse(a, 0, max(0, a.high))
|
||||
|
||||
proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T] =
|
||||
## returns the reverse of the array `a[first..last]`.
|
||||
|
||||
@@ -77,8 +77,10 @@ proc pop*[T](heap: var HeapQueue[T]): T =
|
||||
proc del*[T](heap: var HeapQueue[T], index: int) =
|
||||
## Removes element at `index`, maintaining the heap invariant.
|
||||
swap(seq[T](heap)[^1], seq[T](heap)[index])
|
||||
seq[T](heap).setLen(heap.len - 1)
|
||||
heap.siftup(index)
|
||||
let newLen = heap.len - 1
|
||||
seq[T](heap).setLen(newLen)
|
||||
if index < newLen:
|
||||
heap.siftup(index)
|
||||
|
||||
proc replace*[T](heap: var HeapQueue[T], item: T): T =
|
||||
## Pop and return the current smallest value, and add the new item.
|
||||
@@ -101,16 +103,19 @@ proc pushpop*[T](heap: var HeapQueue[T], item: T): T =
|
||||
return item
|
||||
|
||||
when isMainModule:
|
||||
proc toSortedSeq[T](h: HeapQueue[T]): seq[T] =
|
||||
var tmp = h
|
||||
result = @[]
|
||||
while tmp.len > 0:
|
||||
result.add(pop(tmp))
|
||||
|
||||
block: # Simple sanity test
|
||||
var heap = newHeapQueue[int]()
|
||||
let data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
|
||||
for item in data:
|
||||
push(heap, item)
|
||||
doAssert(heap[0] == 0)
|
||||
var sort = newSeq[int]()
|
||||
while heap.len > 0:
|
||||
sort.add(pop(heap))
|
||||
doAssert(sort == @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
|
||||
doAssert(heap.toSortedSeq == @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
|
||||
|
||||
block: # Test del
|
||||
var heap = newHeapQueue[int]()
|
||||
@@ -121,11 +126,27 @@ when isMainModule:
|
||||
doAssert(heap[0] == 1)
|
||||
|
||||
heap.del(seq[int](heap).find(7))
|
||||
heap.del(seq[int](heap).find(5))
|
||||
heap.del(seq[int](heap).find(6))
|
||||
heap.del(seq[int](heap).find(2))
|
||||
doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 5, 6, 8, 9])
|
||||
|
||||
var sort = newSeq[int]()
|
||||
while heap.len > 0:
|
||||
sort.add(pop(heap))
|
||||
doAssert(sort == @[1, 3, 4, 8, 9])
|
||||
heap.del(seq[int](heap).find(5))
|
||||
doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 6, 8, 9])
|
||||
|
||||
heap.del(seq[int](heap).find(6))
|
||||
doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 8, 9])
|
||||
|
||||
heap.del(seq[int](heap).find(2))
|
||||
doAssert(heap.toSortedSeq == @[1, 3, 4, 8, 9])
|
||||
|
||||
block: # Test del last
|
||||
var heap = newHeapQueue[int]()
|
||||
let data = [1, 2, 3]
|
||||
for item in data: push(heap, item)
|
||||
|
||||
heap.del(2)
|
||||
doAssert(heap.toSortedSeq == @[1, 2])
|
||||
|
||||
heap.del(1)
|
||||
doAssert(heap.toSortedSeq == @[1])
|
||||
|
||||
heap.del(0)
|
||||
doAssert(heap.toSortedSeq == @[])
|
||||
|
||||
@@ -225,7 +225,7 @@ proc foreignDepInstallCmd*(foreignPackageName: string): (string, bool) =
|
||||
else:
|
||||
result = ("<your package manager here> install " & p, true)
|
||||
else:
|
||||
result = ("brew install " & p, true)
|
||||
result = ("brew install " & p, false)
|
||||
|
||||
proc foreignDep*(foreignPackageName: string) =
|
||||
## Registers 'foreignPackageName' to the internal list of foreign deps.
|
||||
|
||||
@@ -127,6 +127,15 @@ proc hash*(x: string): Hash =
|
||||
h = h !& ord(x[i])
|
||||
result = !$h
|
||||
|
||||
proc hash*(x: cstring): Hash =
|
||||
## efficient hashing of null-terminated strings
|
||||
var h: Hash = 0
|
||||
var i = 0
|
||||
while x[i] != 0.char:
|
||||
h = h !& ord(x[i])
|
||||
inc i
|
||||
result = !$h
|
||||
|
||||
proc hash*(sBuf: string, sPos, ePos: int): Hash =
|
||||
## efficient hashing of a string buffer, from starting
|
||||
## position `sPos` to ending position `ePos`
|
||||
@@ -239,6 +248,7 @@ proc hash*[A](x: set[A]): Hash =
|
||||
|
||||
when isMainModule:
|
||||
doAssert( hash("aa bb aaaa1234") == hash("aa bb aaaa1234", 0, 13) )
|
||||
doAssert( hash("aa bb aaaa1234") == hash(cstring("aa bb aaaa1234")) )
|
||||
doAssert( hashIgnoreCase("aa bb aaaa1234") == hash("aa bb aaaa1234") )
|
||||
doAssert( hashIgnoreStyle("aa bb aaaa1234") == hashIgnoreCase("aa bb aaaa1234") )
|
||||
let xx = @['H','e','l','l','o']
|
||||
|
||||
@@ -206,6 +206,8 @@ proc parseHeader*(line: string): tuple[key: string, value: seq[string]] =
|
||||
inc(i) # skip :
|
||||
if i < len(line):
|
||||
i += parseList(line, result.value, i)
|
||||
elif result.key.len > 0:
|
||||
result.value = @[""]
|
||||
else:
|
||||
result.value = @[]
|
||||
|
||||
@@ -318,4 +320,6 @@ when isMainModule:
|
||||
let (key, value) = parseHeader("foobar: ")
|
||||
test = newHttpHeaders()
|
||||
test[key] = value
|
||||
doAssert test["foobar"] == ""
|
||||
doAssert test["foobar"] == ""
|
||||
|
||||
doAssert parseHeader("foobar:") == ("foobar", @[""])
|
||||
@@ -1002,8 +1002,8 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path:
|
||||
|
||||
iterator walkDirRec*(dir: string, filter={pcFile, pcDir}): string {.
|
||||
tags: [ReadDirEffect].} =
|
||||
## walks over the directory `dir` and yields for each file in `dir`. The
|
||||
## full path for each file is returned.
|
||||
## Recursively walks over the directory `dir` and yields for each file in `dir`.
|
||||
## The full path for each file is returned. Directories are not returned.
|
||||
## **Warning**:
|
||||
## Modifying the directory structure while the iterator
|
||||
## is traversing may result in undefined behavior!
|
||||
|
||||
@@ -250,18 +250,18 @@ proc parseInt*(s: string, number: var int, start = 0): int {.
|
||||
elif result != 0:
|
||||
number = int(res)
|
||||
|
||||
# overflowChecks doesn't work with uint64
|
||||
proc rawParseUInt(s: string, b: var uint64, start = 0): int =
|
||||
# overflowChecks doesn't work with BiggestUInt
|
||||
proc rawParseUInt(s: string, b: var BiggestUInt, start = 0): int =
|
||||
var
|
||||
res = 0'u64
|
||||
prev = 0'u64
|
||||
res = 0.BiggestUInt
|
||||
prev = 0.BiggestUInt
|
||||
i = start
|
||||
if s[i] == '+': inc(i) # Allow
|
||||
if s[i] in {'0'..'9'}:
|
||||
b = 0
|
||||
while s[i] in {'0'..'9'}:
|
||||
prev = res
|
||||
res = res * 10 + (ord(s[i]) - ord('0')).uint64
|
||||
res = res * 10 + (ord(s[i]) - ord('0')).BiggestUInt
|
||||
if prev > res:
|
||||
return 0 # overflowChecks emulation
|
||||
inc(i)
|
||||
@@ -269,13 +269,13 @@ proc rawParseUInt(s: string, b: var uint64, start = 0): int =
|
||||
b = res
|
||||
result = i - start
|
||||
|
||||
proc parseBiggestUInt*(s: string, number: var uint64, start = 0): int {.
|
||||
proc parseBiggestUInt*(s: string, number: var BiggestUInt, start = 0): int {.
|
||||
rtl, extern: "npuParseBiggestUInt", noSideEffect.} =
|
||||
## parses an unsigned integer starting at `start` and stores the value
|
||||
## into `number`.
|
||||
## Result is the number of processed chars or 0 if there is no integer
|
||||
## or overflow detected.
|
||||
var res: uint64
|
||||
var res: BiggestUInt
|
||||
# use 'res' for exception safety (don't write to 'number' in case of an
|
||||
# overflow exception):
|
||||
result = rawParseUInt(s, res, start)
|
||||
@@ -287,12 +287,12 @@ proc parseUInt*(s: string, number: var uint, start = 0): int {.
|
||||
## into `number`.
|
||||
## Result is the number of processed chars or 0 if there is no integer or
|
||||
## overflow detected.
|
||||
var res: uint64
|
||||
var res: BiggestUInt
|
||||
result = parseBiggestUInt(s, res, start)
|
||||
if (sizeof(uint) <= 4) and
|
||||
(res > 0xFFFF_FFFF'u64):
|
||||
raise newException(OverflowError, "overflow")
|
||||
elif result != 0:
|
||||
when sizeof(BiggestUInt) > sizeof(uint) and sizeof(uint) <= 4:
|
||||
if res > 0xFFFF_FFFF'u64:
|
||||
raise newException(OverflowError, "overflow")
|
||||
if result != 0:
|
||||
number = uint(res)
|
||||
|
||||
proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {.
|
||||
|
||||
@@ -939,7 +939,7 @@ proc parseUInt*(s: string): uint {.noSideEffect, procvar,
|
||||
if L != s.len or L == 0:
|
||||
raise newException(ValueError, "invalid unsigned integer: " & s)
|
||||
|
||||
proc parseBiggestUInt*(s: string): uint64 {.noSideEffect, procvar,
|
||||
proc parseBiggestUInt*(s: string): BiggestUInt {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuParseBiggestUInt".} =
|
||||
## Parses a decimal unsigned integer value contained in `s`.
|
||||
##
|
||||
|
||||
@@ -1512,6 +1512,17 @@ type
|
||||
## compiler supports. Currently this is ``float64``, but it is
|
||||
## platform-dependant in general.
|
||||
|
||||
when defined(JS):
|
||||
type BiggestUInt* = uint32
|
||||
## is an alias for the biggest unsigned integer type the Nim compiler
|
||||
## supports. Currently this is ``uint32`` for JS and ``uint64`` for other
|
||||
## targets.
|
||||
else:
|
||||
type BiggestUInt* = uint64
|
||||
## is an alias for the biggest unsigned integer type the Nim compiler
|
||||
## supports. Currently this is ``uint32`` for JS and ``uint64`` for other
|
||||
## targets.
|
||||
|
||||
{.deprecated: [TAddress: ByteAddress].}
|
||||
|
||||
when defined(windows):
|
||||
|
||||
@@ -128,13 +128,7 @@ iterator items(stack: ptr GcStack): ptr GcStack =
|
||||
yield s
|
||||
s = s.next
|
||||
|
||||
# There will be problems with GC in foreign threads if `threads` option is off or TLS emulation is enabled
|
||||
const allowForeignThreadGc = compileOption("threads") and not compileOption("tlsEmulation")
|
||||
|
||||
when allowForeignThreadGc:
|
||||
var
|
||||
localGcInitialized {.rtlThreadVar.}: bool
|
||||
|
||||
when declared(threadType):
|
||||
proc setupForeignThreadGc*() {.gcsafe.} =
|
||||
## Call this if you registered a callback that will be run from a thread not
|
||||
## under your control. This has a cheap thread-local guard, so the GC for
|
||||
@@ -143,16 +137,33 @@ when allowForeignThreadGc:
|
||||
##
|
||||
## This function is available only when ``--threads:on`` and ``--tlsEmulation:off``
|
||||
## switches are used
|
||||
if not localGcInitialized:
|
||||
localGcInitialized = true
|
||||
if threadType == ThreadType.None:
|
||||
initAllocator()
|
||||
var stackTop {.volatile.}: pointer
|
||||
setStackBottom(addr(stackTop))
|
||||
initGC()
|
||||
threadType = ThreadType.ForeignThread
|
||||
|
||||
proc tearDownForeignThreadGc*() {.gcsafe.} =
|
||||
## Call this to tear down the GC, previously initialized by ``setupForeignThreadGc``.
|
||||
## If GC has not been previously initialized, or has already been torn down, the
|
||||
## call does nothing.
|
||||
##
|
||||
## This function is available only when ``--threads:on`` and ``--tlsEmulation:off``
|
||||
## switches are used
|
||||
if threadType != ThreadType.ForeignThread:
|
||||
return
|
||||
when declared(deallocOsPages): deallocOsPages()
|
||||
threadType = ThreadType.None
|
||||
when declared(gch): zeroMem(addr gch, sizeof(gch))
|
||||
|
||||
else:
|
||||
template setupForeignThreadGc*() =
|
||||
{.error: "setupForeignThreadGc is available only when ``--threads:on`` and ``--tlsEmulation:off`` are used".}
|
||||
|
||||
template tearDownForeignThreadGc*() =
|
||||
{.error: "tearDownForeignThreadGc is available only when ``--threads:on`` and ``--tlsEmulation:off`` are used".}
|
||||
|
||||
# ----------------- stack management --------------------------------------
|
||||
# inspired from Smart Eiffel
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ proc checkErr(f: File) =
|
||||
{.push stackTrace:off, profiler:off.}
|
||||
proc readBuffer(f: File, buffer: pointer, len: Natural): int =
|
||||
result = c_fread(buffer, 1, len, f)
|
||||
checkErr(f)
|
||||
if result != len: checkErr(f)
|
||||
|
||||
proc readBytes(f: File, a: var openArray[int8|uint8], start, len: Natural): int =
|
||||
result = readBuffer(f, addr(a[start]), len)
|
||||
@@ -118,8 +118,9 @@ const
|
||||
proc close*(f: File) = discard c_fclose(f)
|
||||
proc readChar(f: File): char =
|
||||
let x = c_fgetc(f)
|
||||
if x == -1: raiseEOF()
|
||||
checkErr(f)
|
||||
if x < 0:
|
||||
checkErr(f)
|
||||
raiseEOF()
|
||||
result = char(x)
|
||||
|
||||
proc flushFile*(f: File) = discard c_fflush(f)
|
||||
@@ -140,7 +141,7 @@ proc readLine(f: File, line: var TaintedString): bool =
|
||||
# fgets doesn't append an \L
|
||||
c_memset(addr line.string[pos], '\L'.ord, sp)
|
||||
var fgetsSuccess = c_fgets(addr line.string[pos], sp, f) != nil
|
||||
checkErr(f)
|
||||
if not fgetsSuccess: checkErr(f)
|
||||
let m = c_memchr(addr line.string[pos], '\L'.ord, sp)
|
||||
if m != nil:
|
||||
# \l found: Could be our own or the one by fgets, in any case, we're done
|
||||
@@ -170,21 +171,23 @@ proc readLine(f: File): TaintedString =
|
||||
|
||||
proc write(f: File, i: int) =
|
||||
when sizeof(int) == 8:
|
||||
c_fprintf(f, "%lld", i)
|
||||
if c_fprintf(f, "%lld", i) < 0: checkErr(f)
|
||||
else:
|
||||
c_fprintf(f, "%ld", i)
|
||||
if c_fprintf(f, "%ld", i) < 0: checkErr(f)
|
||||
|
||||
proc write(f: File, i: BiggestInt) =
|
||||
when sizeof(BiggestInt) == 8:
|
||||
c_fprintf(f, "%lld", i)
|
||||
if c_fprintf(f, "%lld", i) < 0: checkErr(f)
|
||||
else:
|
||||
c_fprintf(f, "%ld", i)
|
||||
if c_fprintf(f, "%ld", i) < 0: checkErr(f)
|
||||
|
||||
proc write(f: File, b: bool) =
|
||||
if b: write(f, "true")
|
||||
else: write(f, "false")
|
||||
proc write(f: File, r: float32) = c_fprintf(f, "%g", r)
|
||||
proc write(f: File, r: BiggestFloat) = c_fprintf(f, "%g", r)
|
||||
proc write(f: File, r: float32) =
|
||||
if c_fprintf(f, "%g", r) < 0: checkErr(f)
|
||||
proc write(f: File, r: BiggestFloat) =
|
||||
if c_fprintf(f, "%g", r) < 0: checkErr(f)
|
||||
|
||||
proc write(f: File, c: char) = discard c_putc(ord(c), f)
|
||||
proc write(f: File, a: varargs[string, `$`]) =
|
||||
@@ -212,7 +215,10 @@ proc rawFileSize(file: File): int =
|
||||
discard c_fseek(file, clong(oldPos), 0)
|
||||
|
||||
proc endOfFile(f: File): bool =
|
||||
result = c_feof(f) != 0
|
||||
var c = c_fgetc(f)
|
||||
discard c_ungetc(c, f)
|
||||
return c < 0'i32
|
||||
#result = c_feof(f) != 0
|
||||
|
||||
proc readAllFile(file: File, len: int): string =
|
||||
# We acquire the filesize beforehand and hope it doesn't change.
|
||||
|
||||
@@ -285,7 +285,19 @@ when useStackMaskHack:
|
||||
when not defined(useNimRtl):
|
||||
when not useStackMaskHack:
|
||||
#when not defined(createNimRtl): initStackBottom()
|
||||
when declared(initGC): initGC()
|
||||
when declared(initGC):
|
||||
initGC()
|
||||
when not emulatedThreadVars:
|
||||
type ThreadType {.pure.} = enum
|
||||
None = 0,
|
||||
NimThread = 1,
|
||||
ForeignThread = 2
|
||||
var
|
||||
threadType {.rtlThreadVar.}: ThreadType
|
||||
|
||||
threadType = ThreadType.NimThread
|
||||
|
||||
|
||||
|
||||
when emulatedThreadVars:
|
||||
if nimThreadVarsSize() > sizeof(ThreadLocalStorage):
|
||||
@@ -442,6 +454,8 @@ proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) =
|
||||
# init the GC for refc/markandsweep
|
||||
setStackBottom(addr(p))
|
||||
initGC()
|
||||
when declared(threadType):
|
||||
threadType = ThreadType.NimThread
|
||||
when declared(registerThread):
|
||||
thrd.stackBottom = addr(thrd)
|
||||
registerThread(thrd)
|
||||
|
||||
Reference in New Issue
Block a user