diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/core/macros.nim | 2 | ||||
-rw-r--r-- | lib/impure/db_postgres.nim | 182 | ||||
-rw-r--r-- | lib/impure/re.nim | 2 | ||||
-rw-r--r-- | lib/pure/algorithm.nim | 2 | ||||
-rw-r--r-- | lib/pure/asynchttpserver.nim | 4 | ||||
-rw-r--r-- | lib/pure/collections/heapqueue.nim | 41 | ||||
-rw-r--r-- | lib/pure/distros.nim | 2 | ||||
-rw-r--r-- | lib/pure/hashes.nim | 10 | ||||
-rw-r--r-- | lib/pure/httpcore.nim | 6 | ||||
-rw-r--r-- | lib/pure/json.nim | 9 | ||||
-rw-r--r-- | lib/pure/logging.nim | 2 | ||||
-rw-r--r-- | lib/pure/os.nim | 6 | ||||
-rw-r--r-- | lib/pure/parseutils.nim | 24 | ||||
-rw-r--r-- | lib/pure/strutils.nim | 4 | ||||
-rw-r--r-- | lib/pure/unittest.nim | 2 | ||||
-rw-r--r-- | lib/system.nim | 12 | ||||
-rw-r--r-- | lib/system/alloc.nim | 5 | ||||
-rw-r--r-- | lib/system/gc_common.nim | 29 | ||||
-rw-r--r-- | lib/system/sysio.nim | 19 | ||||
-rw-r--r-- | lib/system/threads.nim | 16 |
20 files changed, 308 insertions, 71 deletions
diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 3adf4670d..83776f16b 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -742,6 +742,8 @@ proc `$`*(node: NimNode): string {.compileTime.} = result = $node.symbol of nnkOpenSymChoice, nnkClosedSymChoice: result = $node[0] + of nnkAccQuoted: + result = $node[0] else: badNodeKind node.kind, "$" diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim index 60bd1f081..fc587b5df 100644 --- a/lib/impure/db_postgres.nim +++ b/lib/impure/db_postgres.nim @@ -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 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") + + 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: int32): string {.inline.} = +proc `[]`*(row: InstantRow; col: int): string {.inline.} = ## returns text for given column of the row - $pqgetvalue(row.res, row.line, col) + $pqgetvalue(row.res, int32(row.line), int32(col)) -proc len*(row: InstantRow): int32 {.inline.} = +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].} = diff --git a/lib/impure/re.nim b/lib/impure/re.nim index 9d5d2bdd0..e00f91de1 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -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] diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 739cdc16b..bc39f153b 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -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]`. diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index a558d9d7e..672eb34a0 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -31,7 +31,7 @@ ## ## waitFor server.serve(Port(8080), cb) -import tables, asyncnet, asyncdispatch, parseutils, uri, strutils +import tables, asyncnet, asyncdispatch, parseutils, uri, strutils, nativesockets import httpcore export httpcore except parseHeader @@ -241,7 +241,7 @@ proc serve*(server: AsyncHttpServer, port: Port, ## specified address and port. ## ## When a request is made by a client the specified callback will be called. - server.socket = newAsyncSocket() + server.socket = newAsyncSocket(AF_INET6) if server.reuseAddr: server.socket.setSockOpt(OptReuseAddr, true) if server.reusePort: diff --git a/lib/pure/collections/heapqueue.nim b/lib/pure/collections/heapqueue.nim index abe20e556..f86ba1d3f 100644 --- a/lib/pure/collections/heapqueue.nim +++ b/lib/pure/collections/heapqueue.nim @@ -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)) + doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 5, 6, 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]) - var sort = newSeq[int]() - while heap.len > 0: - sort.add(pop(heap)) - doAssert(sort == @[1, 3, 4, 8, 9]) + heap.del(1) + doAssert(heap.toSortedSeq == @[1]) + + heap.del(0) + doAssert(heap.toSortedSeq == @[]) diff --git a/lib/pure/distros.nim b/lib/pure/distros.nim index ff30f6134..896497630 100644 --- a/lib/pure/distros.nim +++ b/lib/pure/distros.nim @@ -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. diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 11af81149..17d1c6442 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -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'] diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index d7f720f66..aa8f1958d 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -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"] == "" \ No newline at end of file + doAssert test["foobar"] == "" + + doAssert parseHeader("foobar:") == ("foobar", @[""]) \ No newline at end of file diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 5e36a2aa1..c7b581a85 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -952,7 +952,7 @@ proc newIndent(curr, indent: int, ml: bool): int = else: return indent proc nl(s: var string, ml: bool) = - if ml: s.add("\n") + s.add(if ml: "\n" else: " ") proc escapeJson*(s: string; result: var string) = ## Converts a string `s` to its JSON representation. @@ -986,15 +986,14 @@ proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true, lstArr = false, currIndent = 0) = case node.kind of JObject: - if currIndent != 0 and not lstArr: result.nl(ml) - result.indent(currIndent) # Indentation + if lstArr: result.indent(currIndent) # Indentation if node.fields.len > 0: result.add("{") result.nl(ml) # New line var i = 0 for key, val in pairs(node.fields): if i > 0: - result.add(", ") + result.add(",") result.nl(ml) # New Line inc i # Need to indent more than { @@ -1030,7 +1029,7 @@ proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true, result.nl(ml) for i in 0..len(node.elems)-1: if i > 0: - result.add(", ") + result.add(",") result.nl(ml) # New Line toPretty(result, node.elems[i], indent, ml, true, newIndent(currIndent, indent, ml)) diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index 5544a4b3f..65724f75a 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -46,6 +46,8 @@ ## ## **Warning:** The global list of handlers is a thread var, this means that ## the handlers must be re-added in each thread. +## **Warning:** When logging on disk or console, only error and fatal messages +## are flushed out immediately. Use flushFile() where needed. import strutils, times when not defined(js): diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 4cd3870c7..6bf776a44 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -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! @@ -1185,7 +1185,7 @@ proc createHardlink*(src, dest: string) = proc parseCmdLine*(c: string): seq[string] {. noSideEffect, rtl, extern: "nos$1".} = - ## Splits a command line into several components; + ## Splits a `command line`:idx: into several components; ## This proc is only occasionally useful, better use the `parseopt` module. ## ## On Windows, it uses the following parsing rules diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index fb7d72182..8d53a0360 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -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 {. diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 235e66f6a..9c9da92c6 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -898,7 +898,7 @@ proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect, proc toHex*[T](x: T): string = ## Shortcut for ``toHex(x, T.sizeOf * 2)`` - toHex(x, T.sizeOf * 2) + toHex(BiggestInt(x), T.sizeOf * 2) proc intToStr*(x: int, minchars: Positive = 1): string {.noSideEffect, rtl, extern: "nsuIntToStr".} = @@ -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`. ## diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index cdca02ed7..01af0f839 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -24,7 +24,7 @@ ## echo "run before each test" ## ## teardown: -## echo "run after each test": +## echo "run after each test" ## ## test "essential truths": ## # give up and stop if this fails diff --git a/lib/system.nim b/lib/system.nim index 13ca6eaf7..6388e278e 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -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): @@ -2732,6 +2743,7 @@ when not defined(JS): #and not defined(nimscript): # we use binary mode on Windows: c_setmode(c_fileno(stdin), O_BINARY) c_setmode(c_fileno(stdout), O_BINARY) + c_setmode(c_fileno(stderr), O_BINARY) when defined(endb): proc endbStep() diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index a124d7537..f28a124d2 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -292,10 +292,15 @@ proc writeFreeList(a: MemRegion) = it, it.next, it.prev, it.size) it = it.next +const nimMaxHeap {.intdefine.} = 0 + proc requestOsChunks(a: var MemRegion, size: int): PBigChunk = when not defined(emscripten): if not a.blockChunkSizeIncrease: let usedMem = a.currMem # - a.freeMem + when nimMaxHeap != 0: + if usedMem > nimMaxHeap * 1024 * 1024: + raiseOutOfMem() if usedMem < 64 * 1024: a.nextChunkSize = PageSize*4 else: diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index 269514ceb..6ab6bd920 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -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 diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim index 115b67c18..7444661e3 100644 --- a/lib/system/sysio.nim +++ b/lib/system/sysio.nim @@ -171,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, `$`]) = @@ -213,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. diff --git a/lib/system/threads.nim b/lib/system/threads.nim index e8b34bf2e..6e58638e9 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -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) |