Merge branch 'devel' of https://github.com/Araq/Nim into add-nre

* 'devel' of https://github.com/Araq/Nim:
  Fix #964, fix #1384
  Don't inspect typedescs
This commit is contained in:
Flaviu Tamas 2015-05-26 19:32:50 -04:00
commit 90ed34db72
168 changed files with 6305 additions and 6961 deletions

View file

@ -1,7 +1,7 @@
#
#
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
# (c) Copyright 2015 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@ -12,56 +12,46 @@
include "system/syslocks"
type
TLock* = TSysLock ## Nim lock; whether this is re-entrant
Lock* = SysLock ## Nim lock; whether this is re-entrant
## or not is unspecified!
TCond* = TSysCond ## Nim condition variable
LockEffect* {.deprecated.} = object of RootEffect ## \
## effect that denotes that some lock operation
## is performed. Deprecated, do not use anymore!
AquireEffect* {.deprecated.} = object of LockEffect ## \
## effect that denotes that some lock is
## acquired. Deprecated, do not use anymore!
ReleaseEffect* {.deprecated.} = object of LockEffect ## \
## effect that denotes that some lock is
## released. Deprecated, do not use anymore!
{.deprecated: [FLock: LockEffect, FAquireLock: AquireEffect,
FReleaseLock: ReleaseEffect].}
proc initLock*(lock: var TLock) {.inline.} =
Cond* = SysCond ## Nim condition variable
{.deprecated: [TLock: Lock, TCond: Cond].}
proc initLock*(lock: var Lock) {.inline.} =
## Initializes the given lock.
initSysLock(lock)
proc deinitLock*(lock: var TLock) {.inline.} =
proc deinitLock*(lock: var Lock) {.inline.} =
## Frees the resources associated with the lock.
deinitSys(lock)
proc tryAcquire*(lock: var TLock): bool =
proc tryAcquire*(lock: var Lock): bool =
## Tries to acquire the given lock. Returns `true` on success.
result = tryAcquireSys(lock)
proc acquire*(lock: var TLock) =
proc acquire*(lock: var Lock) =
## Acquires the given lock.
acquireSys(lock)
proc release*(lock: var TLock) =
proc release*(lock: var Lock) =
## Releases the given lock.
releaseSys(lock)
proc initCond*(cond: var TCond) {.inline.} =
proc initCond*(cond: var Cond) {.inline.} =
## Initializes the given condition variable.
initSysCond(cond)
proc deinitCond*(cond: var TCond) {.inline.} =
proc deinitCond*(cond: var Cond) {.inline.} =
## Frees the resources associated with the lock.
deinitSysCond(cond)
proc wait*(cond: var TCond, lock: var TLock) {.inline.} =
## waits on the condition variable `cond`.
proc wait*(cond: var Cond, lock: var Lock) {.inline.} =
## waits on the condition variable `cond`.
waitSysCond(cond, lock)
proc signal*(cond: var TCond) {.inline.} =
## sends a signal to the condition variable `cond`.
signalSysCond(cond)
proc signal*(cond: var Cond) {.inline.} =
## sends a signal to the condition variable `cond`.
signalSysCond(cond)

View file

@ -9,7 +9,7 @@
## This module implements an interface to Nim's `runtime type information`:idx:
## (`RTTI`:idx:).
## Note that even though ``TAny`` and its operations hide the nasty low level
## Note that even though ``Any`` and its operations hide the nasty low level
## details from its clients, it remains inherently unsafe!
##
## See the `marshal <marshal.html>`_ module for what this module allows you
@ -23,7 +23,7 @@ include "system/hti.nim"
{.pop.}
type
TAnyKind* = enum ## what kind of ``any`` it is
AnyKind* = enum ## what kind of ``any`` it is
akNone = 0, ## invalid any
akBool = 1, ## any represents a ``bool``
akChar = 2, ## any represents a ``char``
@ -55,9 +55,9 @@ type
akUInt32 = 43, ## any represents an unsigned int32
akUInt64 = 44, ## any represents an unsigned int64
TAny* = object ## can represent any nim value; NOTE: the wrapped
Any* = object ## can represent any nim value; NOTE: the wrapped
## value can be modified with its wrapper! This means
## that ``TAny`` keeps a non-traced pointer to its
## that ``Any`` keeps a non-traced pointer to its
## wrapped value and **must not** live longer than
## its wrapped value.
value: pointer
@ -69,6 +69,7 @@ type
TGenericSeq {.importc.} = object
len, space: int
PGenSeq = ptr TGenericSeq
{.deprecated: [TAny: Any, TAnyKind: AnyKind].}
const
GenericSeqSize = (2 * sizeof(int))
@ -103,58 +104,58 @@ proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode =
else:
result = n.sons[n.len]
proc newAny(value: pointer, rawType: PNimType): TAny =
proc newAny(value: pointer, rawType: PNimType): Any =
result.value = value
result.rawType = rawType
when declared(system.TVarSlot):
proc toAny*(x: TVarSlot): TAny {.inline.} =
## constructs a ``TAny`` object from a variable slot ``x``.
when declared(system.VarSlot):
proc toAny*(x: VarSlot): Any {.inline.} =
## constructs a ``Any`` object from a variable slot ``x``.
## This captures `x`'s address, so `x` can be modified with its
## ``TAny`` wrapper! The client needs to ensure that the wrapper
## ``Any`` wrapper! The client needs to ensure that the wrapper
## **does not** live longer than `x`!
## This is provided for easier reflection capabilities of a debugger.
result.value = x.address
result.rawType = x.typ
proc toAny*[T](x: var T): TAny {.inline.} =
## constructs a ``TAny`` object from `x`. This captures `x`'s address, so
## `x` can be modified with its ``TAny`` wrapper! The client needs to ensure
proc toAny*[T](x: var T): Any {.inline.} =
## constructs a ``Any`` object from `x`. This captures `x`'s address, so
## `x` can be modified with its ``Any`` wrapper! The client needs to ensure
## that the wrapper **does not** live longer than `x`!
result.value = addr(x)
result.rawType = cast[PNimType](getTypeInfo(x))
proc kind*(x: TAny): TAnyKind {.inline.} =
proc kind*(x: Any): AnyKind {.inline.} =
## get the type kind
result = TAnyKind(ord(x.rawType.kind))
result = AnyKind(ord(x.rawType.kind))
proc size*(x: TAny): int {.inline.} =
proc size*(x: Any): int {.inline.} =
## returns the size of `x`'s type.
result = x.rawType.size
proc baseTypeKind*(x: TAny): TAnyKind {.inline.} =
proc baseTypeKind*(x: Any): AnyKind {.inline.} =
## get the base type's kind; ``akNone`` is returned if `x` has no base type.
if x.rawType.base != nil:
result = TAnyKind(ord(x.rawType.base.kind))
result = AnyKind(ord(x.rawType.base.kind))
proc baseTypeSize*(x: TAny): int {.inline.} =
proc baseTypeSize*(x: Any): int {.inline.} =
## returns the size of `x`'s basetype.
if x.rawType.base != nil:
result = x.rawType.base.size
proc invokeNew*(x: TAny) =
proc invokeNew*(x: Any) =
## performs ``new(x)``. `x` needs to represent a ``ref``.
assert x.rawType.kind == tyRef
var z = newObj(x.rawType, x.rawType.base.size)
genericAssign(x.value, addr(z), x.rawType)
proc invokeNewSeq*(x: TAny, len: int) =
proc invokeNewSeq*(x: Any, len: int) =
## performs ``newSeq(x, len)``. `x` needs to represent a ``seq``.
assert x.rawType.kind == tySequence
var z = newSeq(x.rawType, len)
genericShallowAssign(x.value, addr(z), x.rawType)
proc extendSeq*(x: TAny) =
proc extendSeq*(x: Any) =
## performs ``setLen(x, x.len+1)``. `x` needs to represent a ``seq``.
assert x.rawType.kind == tySequence
var y = cast[ptr PGenSeq](x.value)[]
@ -164,7 +165,7 @@ proc extendSeq*(x: TAny) =
cast[ppointer](x.value)[] = z
#genericShallowAssign(x.value, addr(z), x.rawType)
proc setObjectRuntimeType*(x: TAny) =
proc setObjectRuntimeType*(x: Any) =
## this needs to be called to set `x`'s runtime object type field.
assert x.rawType.kind == tyObject
objectInit(x.value, x.rawType)
@ -173,7 +174,7 @@ proc skipRange(x: PNimType): PNimType {.inline.} =
result = x
if result.kind == tyRange: result = result.base
proc `[]`*(x: TAny, i: int): TAny =
proc `[]`*(x: Any, i: int): Any =
## accessor for an any `x` that represents an array or a sequence.
case x.rawType.kind
of tyArray:
@ -190,7 +191,7 @@ proc `[]`*(x: TAny, i: int): TAny =
return newAny(s +!! (GenericSeqSize+i*bs), x.rawType.base)
else: assert false
proc `[]=`*(x: TAny, i: int, y: TAny) =
proc `[]=`*(x: Any, i: int, y: Any) =
## accessor for an any `x` that represents an array or a sequence.
case x.rawType.kind
of tyArray:
@ -209,7 +210,7 @@ proc `[]=`*(x: TAny, i: int, y: TAny) =
genericAssign(s +!! (GenericSeqSize+i*bs), y.value, y.rawType)
else: assert false
proc len*(x: TAny): int =
proc len*(x: Any): int =
## len for an any `x` that represents an array or a sequence.
case x.rawType.kind
of tyArray: result = x.rawType.size div x.rawType.base.size
@ -217,20 +218,20 @@ proc len*(x: TAny): int =
else: assert false
proc base*(x: TAny): TAny =
## returns base TAny (useful for inherited object types).
proc base*(x: Any): Any =
## returns base Any (useful for inherited object types).
result.rawType = x.rawType.base
result.value = x.value
proc isNil*(x: TAny): bool =
proc isNil*(x: Any): bool =
## `isNil` for an any `x` that represents a sequence, string, cstring,
## proc or some pointer type.
assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer,
tySequence, tyProc}
result = isNil(cast[ppointer](x.value)[])
proc getPointer*(x: TAny): pointer =
proc getPointer*(x: Any): pointer =
## retrieve the pointer value out of `x`. ``x`` needs to be of kind
## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``,
## ``akPointer``, ``akSequence``.
@ -238,7 +239,7 @@ proc getPointer*(x: TAny): pointer =
tySequence, tyProc}
result = cast[ppointer](x.value)[]
proc setPointer*(x: TAny, y: pointer) =
proc setPointer*(x: Any, y: pointer) =
## sets the pointer value of `x`. ``x`` needs to be of kind
## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``,
## ``akPointer``, ``akSequence``.
@ -247,7 +248,7 @@ proc setPointer*(x: TAny, y: pointer) =
cast[ppointer](x.value)[] = y
proc fieldsAux(p: pointer, n: ptr TNimNode,
ret: var seq[tuple[name: cstring, any: TAny]]) =
ret: var seq[tuple[name: cstring, any: Any]]) =
case n.kind
of nkNone: assert(false)
of nkSlot:
@ -260,7 +261,7 @@ proc fieldsAux(p: pointer, n: ptr TNimNode,
ret.add((n.name, newAny(p +!! n.offset, n.typ)))
if m != nil: fieldsAux(p, m, ret)
iterator fields*(x: TAny): tuple[name: string, any: TAny] =
iterator fields*(x: Any): tuple[name: string, any: Any] =
## iterates over every active field of the any `x` that represents an object
## or a tuple.
assert x.rawType.kind in {tyTuple, tyObject}
@ -269,7 +270,7 @@ iterator fields*(x: TAny): tuple[name: string, any: TAny] =
# XXX BUG: does not work yet, however is questionable anyway
when false:
if x.rawType.kind == tyObject: t = cast[ptr PNimType](x.value)[]
var ret: seq[tuple[name: cstring, any: TAny]] = @[]
var ret: seq[tuple[name: cstring, any: Any]] = @[]
if t.kind == tyObject:
while true:
fieldsAux(p, t.node, ret)
@ -314,7 +315,7 @@ proc getFieldNode(p: pointer, n: ptr TNimNode,
var m = selectBranch(p, n)
if m != nil: result = getFieldNode(p, m, name)
proc `[]=`*(x: TAny, fieldName: string, value: TAny) =
proc `[]=`*(x: Any, fieldName: string, value: Any) =
## sets a field of `x`; `x` represents an object or a tuple.
var t = x.rawType
# XXX BUG: does not work yet, however is questionable anyway
@ -328,7 +329,7 @@ proc `[]=`*(x: TAny, fieldName: string, value: TAny) =
else:
raise newException(ValueError, "invalid field name: " & fieldName)
proc `[]`*(x: TAny, fieldName: string): TAny =
proc `[]`*(x: Any, fieldName: string): Any =
## gets a field of `x`; `x` represents an object or a tuple.
var t = x.rawType
# XXX BUG: does not work yet, however is questionable anyway
@ -339,47 +340,49 @@ proc `[]`*(x: TAny, fieldName: string): TAny =
if n != nil:
result.value = x.value +!! n.offset
result.rawType = n.typ
elif x.rawType.kind == tyObject and x.rawType.base != nil:
return `[]`(TAny(value: x.value, rawType: x.rawType.base), fieldName)
else:
raise newException(ValueError, "invalid field name: " & fieldName)
proc `[]`*(x: TAny): TAny =
proc `[]`*(x: Any): Any =
## dereference operation for the any `x` that represents a ptr or a ref.
assert x.rawType.kind in {tyRef, tyPtr}
result.value = cast[ppointer](x.value)[]
result.rawType = x.rawType.base
proc `[]=`*(x, y: TAny) =
proc `[]=`*(x, y: Any) =
## dereference operation for the any `x` that represents a ptr or a ref.
assert x.rawType.kind in {tyRef, tyPtr}
assert y.rawType == x.rawType.base
genericAssign(cast[ppointer](x.value)[], y.value, y.rawType)
proc getInt*(x: TAny): int =
proc getInt*(x: Any): int =
## retrieve the int value out of `x`. `x` needs to represent an int.
assert skipRange(x.rawType).kind == tyInt
result = cast[ptr int](x.value)[]
proc getInt8*(x: TAny): int8 =
proc getInt8*(x: Any): int8 =
## retrieve the int8 value out of `x`. `x` needs to represent an int8.
assert skipRange(x.rawType).kind == tyInt8
result = cast[ptr int8](x.value)[]
proc getInt16*(x: TAny): int16 =
proc getInt16*(x: Any): int16 =
## retrieve the int16 value out of `x`. `x` needs to represent an int16.
assert skipRange(x.rawType).kind == tyInt16
result = cast[ptr int16](x.value)[]
proc getInt32*(x: TAny): int32 =
proc getInt32*(x: Any): int32 =
## retrieve the int32 value out of `x`. `x` needs to represent an int32.
assert skipRange(x.rawType).kind == tyInt32
result = cast[ptr int32](x.value)[]
proc getInt64*(x: TAny): int64 =
proc getInt64*(x: Any): int64 =
## retrieve the int64 value out of `x`. `x` needs to represent an int64.
assert skipRange(x.rawType).kind == tyInt64
result = cast[ptr int64](x.value)[]
proc getBiggestInt*(x: TAny): BiggestInt =
proc getBiggestInt*(x: Any): BiggestInt =
## retrieve the integer value out of `x`. `x` needs to represent
## some integer, a bool, a char, an enum or a small enough bit set.
## The value might be sign-extended to ``BiggestInt``.
@ -405,7 +408,7 @@ proc getBiggestInt*(x: TAny): BiggestInt =
of tyUInt32: result = BiggestInt(cast[ptr uint32](x.value)[])
else: assert false
proc setBiggestInt*(x: TAny, y: BiggestInt) =
proc setBiggestInt*(x: Any, y: BiggestInt) =
## sets the integer value of `x`. `x` needs to represent
## some integer, a bool, a char, an enum or a small enough bit set.
var t = skipRange(x.rawType)
@ -430,36 +433,36 @@ proc setBiggestInt*(x: TAny, y: BiggestInt) =
of tyUInt32: cast[ptr uint32](x.value)[] = uint32(y)
else: assert false
proc getUInt*(x: TAny): uint =
proc getUInt*(x: Any): uint =
## retrieve the uint value out of `x`, `x` needs to represent an uint.
assert skipRange(x.rawType).kind == tyUInt
result = cast[ptr uint](x.value)[]
proc getUInt8*(x: TAny): uint8 =
proc getUInt8*(x: Any): uint8 =
## retrieve the uint8 value out of `x`, `x` needs to represent an
## uint8.
assert skipRange(x.rawType).kind == tyUInt8
result = cast[ptr uint8](x.value)[]
proc getUInt16*(x: TAny): uint16 =
proc getUInt16*(x: Any): uint16 =
## retrieve the uint16 value out of `x`, `x` needs to represent an
## uint16.
assert skipRange(x.rawType).kind == tyUInt16
result = cast[ptr uint16](x.value)[]
proc getUInt32*(x: TAny): uint32 =
proc getUInt32*(x: Any): uint32 =
## retrieve the uint32 value out of `x`, `x` needs to represent an
## uint32.
assert skipRange(x.rawType).kind == tyUInt32
result = cast[ptr uint32](x.value)[]
proc getUInt64*(x: TAny): uint64 =
proc getUInt64*(x: Any): uint64 =
## retrieve the uint64 value out of `x`, `x` needs to represent an
## uint64.
assert skipRange(x.rawType).kind == tyUInt64
result = cast[ptr uint64](x.value)[]
proc getBiggestUint*(x: TAny): uint64 =
proc getBiggestUint*(x: Any): uint64 =
## retrieve the unsigned integer value out of `x`. `x` needs to
## represent an unsigned integer.
var t = skipRange(x.rawType)
@ -471,7 +474,7 @@ proc getBiggestUint*(x: TAny): uint64 =
of tyUInt64: result = uint64(cast[ptr uint64](x.value)[])
else: assert false
proc setBiggestUint*(x: TAny; y: uint64) =
proc setBiggestUint*(x: Any; y: uint64) =
## sets the unsigned integer value of `c`. `c` needs to represent an
## unsigned integer.
var t = skipRange(x.rawType)
@ -483,25 +486,25 @@ proc setBiggestUint*(x: TAny; y: uint64) =
of tyUInt64: cast[ptr uint64](x.value)[] = uint64(y)
else: assert false
proc getChar*(x: TAny): char =
proc getChar*(x: Any): char =
## retrieve the char value out of `x`. `x` needs to represent a char.
var t = skipRange(x.rawType)
assert t.kind == tyChar
result = cast[ptr char](x.value)[]
proc getBool*(x: TAny): bool =
proc getBool*(x: Any): bool =
## retrieve the bool value out of `x`. `x` needs to represent a bool.
var t = skipRange(x.rawType)
assert t.kind == tyBool
result = cast[ptr bool](x.value)[]
proc skipRange*(x: TAny): TAny =
proc skipRange*(x: Any): Any =
## skips the range information of `x`.
assert x.rawType.kind == tyRange
result.rawType = x.rawType.base
result.value = x.value
proc getEnumOrdinal*(x: TAny, name: string): int =
proc getEnumOrdinal*(x: Any, name: string): int =
## gets the enum field ordinal from `name`. `x` needs to represent an enum
## but is only used to access the type information. In case of an error
## ``low(int)`` is returned.
@ -517,7 +520,7 @@ proc getEnumOrdinal*(x: TAny, name: string): int =
return s[i].offset
result = low(int)
proc getEnumField*(x: TAny, ordinalValue: int): string =
proc getEnumField*(x: Any, ordinalValue: int): string =
## gets the enum field name as a string. `x` needs to represent an enum
## but is only used to access the type information. The field name of
## `ordinalValue` is returned.
@ -535,26 +538,26 @@ proc getEnumField*(x: TAny, ordinalValue: int): string =
if s[i].offset == e: return $s[i].name
result = $e
proc getEnumField*(x: TAny): string =
proc getEnumField*(x: Any): string =
## gets the enum field name as a string. `x` needs to represent an enum.
result = getEnumField(x, getBiggestInt(x).int)
proc getFloat*(x: TAny): float =
proc getFloat*(x: Any): float =
## retrieve the float value out of `x`. `x` needs to represent an float.
assert skipRange(x.rawType).kind == tyFloat
result = cast[ptr float](x.value)[]
proc getFloat32*(x: TAny): float32 =
proc getFloat32*(x: Any): float32 =
## retrieve the float32 value out of `x`. `x` needs to represent an float32.
assert skipRange(x.rawType).kind == tyFloat32
result = cast[ptr float32](x.value)[]
proc getFloat64*(x: TAny): float64 =
proc getFloat64*(x: Any): float64 =
## retrieve the float64 value out of `x`. `x` needs to represent an float64.
assert skipRange(x.rawType).kind == tyFloat64
result = cast[ptr float64](x.value)[]
proc getBiggestFloat*(x: TAny): BiggestFloat =
proc getBiggestFloat*(x: Any): BiggestFloat =
## retrieve the float value out of `x`. `x` needs to represent
## some float. The value is extended to ``BiggestFloat``.
case skipRange(x.rawType).kind
@ -563,7 +566,7 @@ proc getBiggestFloat*(x: TAny): BiggestFloat =
of tyFloat64: result = BiggestFloat(cast[ptr float64](x.value)[])
else: assert false
proc setBiggestFloat*(x: TAny, y: BiggestFloat) =
proc setBiggestFloat*(x: Any, y: BiggestFloat) =
## sets the float value of `x`. `x` needs to represent
## some float.
case skipRange(x.rawType).kind
@ -572,29 +575,29 @@ proc setBiggestFloat*(x: TAny, y: BiggestFloat) =
of tyFloat64: cast[ptr float64](x.value)[] = y
else: assert false
proc getString*(x: TAny): string =
proc getString*(x: Any): string =
## retrieve the string value out of `x`. `x` needs to represent a string.
assert x.rawType.kind == tyString
if not isNil(cast[ptr pointer](x.value)[]):
result = cast[ptr string](x.value)[]
proc setString*(x: TAny, y: string) =
proc setString*(x: Any, y: string) =
## sets the string value of `x`. `x` needs to represent a string.
assert x.rawType.kind == tyString
cast[ptr string](x.value)[] = y
proc getCString*(x: TAny): cstring =
proc getCString*(x: Any): cstring =
## retrieve the cstring value out of `x`. `x` needs to represent a cstring.
assert x.rawType.kind == tyCString
result = cast[ptr cstring](x.value)[]
proc assign*(x, y: TAny) =
## copies the value of `y` to `x`. The assignment operator for ``TAny``
proc assign*(x, y: Any) =
## copies the value of `y` to `x`. The assignment operator for ``Any``
## does NOT do this; it performs a shallow copy instead!
assert y.rawType == x.rawType
genericAssign(x.value, y.value, y.rawType)
iterator elements*(x: TAny): int =
iterator elements*(x: Any): int =
## iterates over every element of `x` that represents a Nim bitset.
assert x.rawType.kind == tySet
var typ = x.rawType
@ -616,7 +619,7 @@ iterator elements*(x: TAny): int =
if (u and (1'i64 shl int64(i))) != 0'i64:
yield i+typ.node.len
proc inclSetElement*(x: TAny, elem: int) =
proc inclSetElement*(x: Any, elem: int) =
## includes an element `elem` in `x`. `x` needs to represent a Nim bitset.
assert x.rawType.kind == tySet
var typ = x.rawType

View file

@ -13,27 +13,28 @@
import strutils, mysql
type
TDbConn* = PMySQL ## encapsulates a database connection
TRow* = seq[string] ## a row of a dataset. NULL database values will be
DbConn* = PMySQL ## encapsulates a database connection
Row* = seq[string] ## a row of a dataset. NULL database values will be
## transformed always to the empty string.
EDb* = object of IOError ## exception that is raised if a database error occurs
TSqlQuery* = distinct string ## an SQL query string
SqlQuery* = distinct string ## an SQL query string
FDb* = object of IOEffect ## effect that denotes a database operation
FReadDb* = object of FDb ## effect that denotes a read operation
FWriteDb* = object of FDb ## effect that denotes a write operation
{.deprecated: [TRow: Row, TSqlQuery: SqlQuery, TDbConn: DbConn].}
proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =
## constructs a TSqlQuery from the string `query`. This is supposed to be
proc sql*(query: string): SqlQuery {.noSideEffect, inline.} =
## constructs a SqlQuery from the string `query`. This is supposed to be
## used as a raw-string-literal modifier:
## ``sql"update user set counter = counter + 1"``
##
## If assertions are turned off, it does nothing. If assertions are turned
## on, later versions will check the string for valid syntax.
result = TSqlQuery(query)
result = SqlQuery(query)
proc dbError(db: TDbConn) {.noreturn.} =
proc dbError(db: DbConn) {.noreturn.} =
## raises an EDb exception.
var e: ref EDb
new(e)
@ -48,7 +49,7 @@ proc dbError*(msg: string) {.noreturn.} =
raise e
when false:
proc dbQueryOpt*(db: TDbConn, query: string, args: varargs[string, `$`]) =
proc dbQueryOpt*(db: DbConn, query: string, args: varargs[string, `$`]) =
var stmt = mysql_stmt_init(db)
if stmt == nil: dbError(db)
if mysql_stmt_prepare(stmt, query, len(query)) != 0:
@ -65,7 +66,7 @@ proc dbQuote*(s: string): string =
else: add(result, c)
add(result, '\'')
proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string =
result = ""
var a = 0
for c in items(string(formatstr)):
@ -78,23 +79,23 @@ proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
else:
add(result, c)
proc tryExec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]): bool {.
proc tryExec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): bool {.
tags: [FReadDB, FWriteDb].} =
## tries to execute the query and returns true if successful, false otherwise.
var q = dbFormat(query, args)
return mysql.realQuery(db, q, q.len) == 0'i32
proc rawExec(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) =
proc rawExec(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) =
var q = dbFormat(query, args)
if mysql.realQuery(db, q, q.len) != 0'i32: dbError(db)
proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
proc exec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) {.
tags: [FReadDB, FWriteDb].} =
## executes the query and raises EDB if not successful.
var q = dbFormat(query, args)
if mysql.realQuery(db, q, q.len) != 0'i32: dbError(db)
proc newRow(L: int): TRow =
proc newRow(L: int): Row =
newSeq(result, L)
for i in 0..L-1: result[i] = ""
@ -103,8 +104,8 @@ proc properFreeResult(sqlres: mysql.PRES, row: cstringArray) =
while mysql.fetchRow(sqlres) != nil: discard
mysql.freeResult(sqlres)
iterator fastRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
iterator fastRows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [FReadDB].} =
## executes the query and iterates over the result dataset. This is very
## fast, but potenially dangerous: If the for-loop-body executes another
## query, the results can be undefined. For MySQL this is the case!.
@ -126,10 +127,10 @@ iterator fastRows*(db: TDbConn, query: TSqlQuery,
yield result
properFreeResult(sqlres, row)
proc getRow*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
proc getRow*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [FReadDB].} =
## retrieves a single row. If the query doesn't return any rows, this proc
## will return a TRow with empty strings for each column.
## will return a Row with empty strings for each column.
rawExec(db, query, args)
var sqlres = mysql.useResult(db)
if sqlres != nil:
@ -145,8 +146,8 @@ proc getRow*(db: TDbConn, query: TSqlQuery,
add(result[i], row[i])
properFreeResult(sqlres, row)
proc getAllRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
proc getAllRows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): seq[Row] {.tags: [FReadDB].} =
## executes the query and returns the whole result dataset.
result = @[]
rawExec(db, query, args)
@ -168,12 +169,12 @@ proc getAllRows*(db: TDbConn, query: TSqlQuery,
inc(j)
mysql.freeResult(sqlres)
iterator rows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
iterator rows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [FReadDB].} =
## same as `fastRows`, but slower and safe.
for r in items(getAllRows(db, query, args)): yield r
proc getValue*(db: TDbConn, query: TSqlQuery,
proc getValue*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): string {.tags: [FReadDB].} =
## executes the query and returns the first column of the first row of the
## result dataset. Returns "" if the dataset contains no rows or the database
@ -183,7 +184,7 @@ proc getValue*(db: TDbConn, query: TSqlQuery,
result = row[0]
break
proc tryInsertId*(db: TDbConn, query: TSqlQuery,
proc tryInsertId*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
## executes the query (typically "INSERT") and returns the
## generated ID for the row or -1 in case of an error.
@ -193,14 +194,14 @@ proc tryInsertId*(db: TDbConn, query: TSqlQuery,
else:
result = mysql.insertId(db)
proc insertId*(db: TDbConn, query: TSqlQuery,
proc insertId*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
## executes the query (typically "INSERT") and returns the
## generated ID for the row.
result = tryInsertID(db, query, args)
if result < 0: dbError(db)
proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
proc execAffectedRows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64 {.
tags: [FReadDB, FWriteDb].} =
## runs the query (typically "UPDATE") and returns the
@ -208,11 +209,11 @@ proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
rawExec(db, query, args)
result = mysql.affectedRows(db)
proc close*(db: TDbConn) {.tags: [FDb].} =
proc close*(db: DbConn) {.tags: [FDb].} =
## closes the database connection.
if db != nil: mysql.close(db)
proc open*(connection, user, password, database: string): TDbConn {.
proc open*(connection, user, password, database: string): DbConn {.
tags: [FDb].} =
## opens a database connection. Raises `EDb` if the connection could not
## be established.
@ -230,8 +231,8 @@ proc open*(connection, user, password, database: string): TDbConn {.
db_mysql.close(result)
dbError(errmsg)
proc setEncoding*(connection: TDbConn, encoding: string): bool {.
proc setEncoding*(connection: DbConn, encoding: string): bool {.
tags: [FDb].} =
## sets the encoding of a database connection, returns true for
## success, false for failure.
result = mysql.set_character_set(connection, encoding) == 0
result = mysql.set_character_set(connection, encoding) == 0

View file

@ -13,28 +13,30 @@
import strutils, postgres
type
TDbConn* = PPGconn ## encapsulates a database connection
TRow* = seq[string] ## a row of a dataset. NULL database values will be
DbConn* = PPGconn ## encapsulates a database connection
Row* = seq[string] ## a row of a dataset. NULL database values will be
## transformed always to the empty string.
EDb* = object of IOError ## exception that is raised if a database error occurs
TSqlQuery* = distinct string ## an SQL query string
TSqlPrepared* = distinct string ## a identifier for the prepared queries
SqlQuery* = distinct string ## an SQL query string
SqlPrepared* = distinct string ## a identifier for the prepared queries
FDb* = object of IOEffect ## effect that denotes a database operation
FReadDb* = object of FDb ## effect that denotes a read operation
FWriteDb* = object of FDb ## effect that denotes a write operation
{.deprecated: [TRow: Row, TSqlQuery: SqlQuery, TDbConn: DbConn,
TSqlPrepared: SqlPrepared].}
proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =
## constructs a TSqlQuery from the string `query`. This is supposed to be
proc sql*(query: string): SqlQuery {.noSideEffect, inline.} =
## constructs a SqlQuery from the string `query`. This is supposed to be
## used as a raw-string-literal modifier:
## ``sql"update user set counter = counter + 1"``
##
## If assertions are turned off, it does nothing. If assertions are turned
## on, later versions will check the string for valid syntax.
result = TSqlQuery(query)
result = SqlQuery(query)
proc dbError*(db: TDbConn) {.noreturn.} =
proc dbError*(db: DbConn) {.noreturn.} =
## raises an EDb exception.
var e: ref EDb
new(e)
@ -56,7 +58,7 @@ proc dbQuote*(s: string): string =
else: add(result, c)
add(result, '\'')
proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string =
result = ""
var a = 0
for c in items(string(formatstr)):
@ -69,7 +71,7 @@ proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
else:
add(result, c)
proc tryExec*(db: TDbConn, query: TSqlQuery,
proc tryExec*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): bool {.tags: [FReadDB, FWriteDb].} =
## tries to execute the query and returns true if successful, false otherwise.
var arr = allocCStringArray(args)
@ -79,7 +81,7 @@ proc tryExec*(db: TDbConn, query: TSqlQuery,
result = pqresultStatus(res) == PGRES_COMMAND_OK
pqclear(res)
proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
proc exec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) {.
tags: [FReadDB, FWriteDb].} =
## executes the query and raises EDB if not successful.
var arr = allocCStringArray(args)
@ -89,7 +91,7 @@ proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
if pqresultStatus(res) != PGRES_COMMAND_OK: dbError(db)
pqclear(res)
proc exec*(db: TDbConn, stmtName: TSqlPrepared,
proc exec*(db: DbConn, stmtName: SqlPrepared,
args: varargs[string]) {.tags: [FReadDB, FWriteDb].} =
var arr = allocCStringArray(args)
var res = pqexecPrepared(db, stmtName.string, int32(args.len), arr,
@ -98,11 +100,11 @@ proc exec*(db: TDbConn, stmtName: TSqlPrepared,
if pqResultStatus(res) != PGRES_COMMAND_OK: dbError(db)
pqclear(res)
proc newRow(L: int): TRow =
proc newRow(L: int): Row =
newSeq(result, L)
for i in 0..L-1: result[i] = ""
proc setupQuery(db: TDbConn, query: TSqlQuery,
proc setupQuery(db: DbConn, query: SqlQuery,
args: varargs[string]): PPGresult =
var arr = allocCStringArray(args)
result = pqexecParams(db, query.string, int32(args.len), nil, arr,
@ -110,7 +112,7 @@ proc setupQuery(db: TDbConn, query: TSqlQuery,
deallocCStringArray(arr)
if pqResultStatus(result) != PGRES_TUPLES_OK: dbError(db)
proc setupQuery(db: TDbConn, stmtName: TSqlPrepared,
proc setupQuery(db: DbConn, stmtName: SqlPrepared,
args: varargs[string]): PPGresult =
var arr = allocCStringArray(args)
result = pqexecPrepared(db, stmtName.string, int32(args.len), arr,
@ -118,13 +120,13 @@ proc setupQuery(db: TDbConn, stmtName: TSqlPrepared,
deallocCStringArray(arr)
if pqResultStatus(result) != PGRES_TUPLES_OK: dbError(db)
proc prepare*(db: TDbConn; stmtName: string, query: TSqlQuery;
nParams: int): TSqlPrepared =
proc prepare*(db: DbConn; stmtName: string, query: SqlQuery;
nParams: int): SqlPrepared =
var res = pqprepare(db, stmtName, query.string, int32(nParams), nil)
if pqResultStatus(res) != PGRES_COMMAND_OK: dbError(db)
return TSqlPrepared(stmtName)
return SqlPrepared(stmtName)
proc setRow(res: PPGresult, r: var TRow, line, cols: int32) =
proc setRow(res: PPGresult, r: var Row, line, cols: int32) =
for col in 0..cols-1:
setLen(r[col], 0)
let x = pqgetvalue(res, line, col)
@ -133,8 +135,8 @@ proc setRow(res: PPGresult, r: var TRow, line, cols: int32) =
else:
add(r[col], x)
iterator fastRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
iterator fastRows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [FReadDB].} =
## executes the query and iterates over the result dataset. This is very
## fast, but potenially dangerous: If the for-loop-body executes another
## query, the results can be undefined. For Postgres it is safe though.
@ -146,8 +148,8 @@ iterator fastRows*(db: TDbConn, query: TSqlQuery,
yield result
pqclear(res)
iterator fastRows*(db: TDbConn, stmtName: TSqlPrepared,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
iterator fastRows*(db: DbConn, stmtName: SqlPrepared,
args: varargs[string, `$`]): Row {.tags: [FReadDB].} =
## executes the prepared query and iterates over the result dataset.
var res = setupQuery(db, stmtName, args)
var L = pqNfields(res)
@ -157,44 +159,44 @@ iterator fastRows*(db: TDbConn, stmtName: TSqlPrepared,
yield result
pqClear(res)
proc getRow*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
proc getRow*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [FReadDB].} =
## retrieves a single row. If the query doesn't return any rows, this proc
## will return a TRow with empty strings for each column.
## will return a Row with empty strings for each column.
var res = setupQuery(db, query, args)
var L = pqnfields(res)
result = newRow(L)
setRow(res, result, 0, L)
pqclear(res)
proc getRow*(db: TDbConn, stmtName: TSqlPrepared,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
proc getRow*(db: DbConn, stmtName: SqlPrepared,
args: varargs[string, `$`]): Row {.tags: [FReadDB].} =
var res = setupQuery(db, stmtName, args)
var L = pqNfields(res)
result = newRow(L)
setRow(res, result, 0, L)
pqClear(res)
proc getAllRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
proc getAllRows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): seq[Row] {.tags: [FReadDB].} =
## executes the query and returns the whole result dataset.
result = @[]
for r in fastRows(db, query, args):
result.add(r)
proc getAllRows*(db: TDbConn, stmtName: TSqlPrepared,
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
proc getAllRows*(db: DbConn, stmtName: SqlPrepared,
args: varargs[string, `$`]): seq[Row] {.tags: [FReadDB].} =
## executes the prepared query and returns the whole result dataset.
result = @[]
for r in fastRows(db, stmtName, args):
result.add(r)
iterator rows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
iterator rows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [FReadDB].} =
## same as `fastRows`, but slower and safe.
for r in items(getAllRows(db, query, args)): yield r
proc getValue*(db: TDbConn, query: TSqlQuery,
proc getValue*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): string {.tags: [FReadDB].} =
## executes the query and returns the first column of the first row of the
## result dataset. Returns "" if the dataset contains no rows or the database
@ -202,20 +204,20 @@ proc getValue*(db: TDbConn, query: TSqlQuery,
var x = pqgetvalue(setupQuery(db, query, args), 0, 0)
result = if isNil(x): "" else: $x
proc tryInsertID*(db: TDbConn, query: TSqlQuery,
proc tryInsertID*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].}=
## executes the query (typically "INSERT") and returns the
## generated ID for the row or -1 in case of an error. For Postgre this adds
## ``RETURNING id`` to the query, so it only works if your primary key is
## named ``id``.
var x = pqgetvalue(setupQuery(db, TSqlQuery(string(query) & " RETURNING id"),
var x = pqgetvalue(setupQuery(db, SqlQuery(string(query) & " RETURNING id"),
args), 0, 0)
if not isNil(x):
result = parseBiggestInt($x)
else:
result = -1
proc insertID*(db: TDbConn, query: TSqlQuery,
proc insertID*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
## executes the query (typically "INSERT") and returns the
## generated ID for the row. For Postgre this adds
@ -224,7 +226,7 @@ proc insertID*(db: TDbConn, query: TSqlQuery,
result = tryInsertID(db, query, args)
if result < 0: dbError(db)
proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
proc execAffectedRows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64 {.tags: [
FReadDB, FWriteDb].} =
## executes the query (typically "UPDATE") and returns the
@ -235,11 +237,11 @@ proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
result = parseBiggestInt($pqcmdTuples(res))
pqclear(res)
proc close*(db: TDbConn) {.tags: [FDb].} =
proc close*(db: DbConn) {.tags: [FDb].} =
## closes the database connection.
if db != nil: pqfinish(db)
proc open*(connection, user, password, database: string): TDbConn {.
proc open*(connection, user, password, database: string): DbConn {.
tags: [FDb].} =
## opens a database connection. Raises `EDb` if the connection could not
## be established.
@ -261,8 +263,8 @@ proc open*(connection, user, password, database: string): TDbConn {.
result = pqsetdbLogin(nil, nil, nil, nil, database, user, password)
if pqStatus(result) != CONNECTION_OK: dbError(result) # result = nil
proc setEncoding*(connection: TDbConn, encoding: string): bool {.
proc setEncoding*(connection: DbConn, encoding: string): bool {.
tags: [FDb].} =
## sets the encoding of a database connection, returns true for
## success, false for failure.
return pqsetClientEncoding(connection, encoding) == 0
return pqsetClientEncoding(connection, encoding) == 0

View file

@ -13,27 +13,28 @@
import strutils, sqlite3
type
TDbConn* = PSqlite3 ## encapsulates a database connection
TRow* = seq[string] ## a row of a dataset. NULL database values will be
DbConn* = PSqlite3 ## encapsulates a database connection
Row* = seq[string] ## a row of a dataset. NULL database values will be
## transformed always to the empty string.
EDb* = object of IOError ## exception that is raised if a database error occurs
TSqlQuery* = distinct string ## an SQL query string
SqlQuery* = distinct string ## an SQL query string
FDb* = object of IOEffect ## effect that denotes a database operation
FReadDb* = object of FDb ## effect that denotes a read operation
FWriteDb* = object of FDb ## effect that denotes a write operation
{.deprecated: [TRow: Row, TSqlQuery: SqlQuery, TDbConn: DbConn].}
proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =
## constructs a TSqlQuery from the string `query`. This is supposed to be
proc sql*(query: string): SqlQuery {.noSideEffect, inline.} =
## constructs a SqlQuery from the string `query`. This is supposed to be
## used as a raw-string-literal modifier:
## ``sql"update user set counter = counter + 1"``
##
## If assertions are turned off, it does nothing. If assertions are turned
## on, later versions will check the string for valid syntax.
result = TSqlQuery(query)
result = SqlQuery(query)
proc dbError(db: TDbConn) {.noreturn.} =
proc dbError(db: DbConn) {.noreturn.} =
## raises an EDb exception.
var e: ref EDb
new(e)
@ -55,7 +56,7 @@ proc dbQuote(s: string): string =
else: add(result, c)
add(result, '\'')
proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string =
result = ""
var a = 0
for c in items(string(formatstr)):
@ -65,7 +66,7 @@ proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
else:
add(result, c)
proc tryExec*(db: TDbConn, query: TSqlQuery,
proc tryExec*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): bool {.tags: [FReadDb, FWriteDb].} =
## tries to execute the query and returns true if successful, false otherwise.
var q = dbFormat(query, args)
@ -74,29 +75,29 @@ proc tryExec*(db: TDbConn, query: TSqlQuery,
if step(stmt) == SQLITE_DONE:
result = finalize(stmt) == SQLITE_OK
proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
proc exec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) {.
tags: [FReadDb, FWriteDb].} =
## executes the query and raises EDB if not successful.
if not tryExec(db, query, args): dbError(db)
proc newRow(L: int): TRow =
proc newRow(L: int): Row =
newSeq(result, L)
for i in 0..L-1: result[i] = ""
proc setupQuery(db: TDbConn, query: TSqlQuery,
proc setupQuery(db: DbConn, query: SqlQuery,
args: varargs[string]): Pstmt =
var q = dbFormat(query, args)
if prepare_v2(db, q, q.len.cint, result, nil) != SQLITE_OK: dbError(db)
proc setRow(stmt: Pstmt, r: var TRow, cols: cint) =
proc setRow(stmt: Pstmt, r: var Row, cols: cint) =
for col in 0..cols-1:
setLen(r[col], column_bytes(stmt, col)) # set capacity
setLen(r[col], 0)
let x = column_text(stmt, col)
if not isNil(x): add(r[col], x)
iterator fastRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDb].} =
iterator fastRows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [FReadDb].} =
## executes the query and iterates over the result dataset. This is very
## fast, but potenially dangerous: If the for-loop-body executes another
## query, the results can be undefined. For Sqlite it is safe though.
@ -108,10 +109,10 @@ iterator fastRows*(db: TDbConn, query: TSqlQuery,
yield result
if finalize(stmt) != SQLITE_OK: dbError(db)
proc getRow*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDb].} =
proc getRow*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [FReadDb].} =
## retrieves a single row. If the query doesn't return any rows, this proc
## will return a TRow with empty strings for each column.
## will return a Row with empty strings for each column.
var stmt = setupQuery(db, query, args)
var L = (column_count(stmt))
result = newRow(L)
@ -119,19 +120,19 @@ proc getRow*(db: TDbConn, query: TSqlQuery,
setRow(stmt, result, L)
if finalize(stmt) != SQLITE_OK: dbError(db)
proc getAllRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDb].} =
proc getAllRows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): seq[Row] {.tags: [FReadDb].} =
## executes the query and returns the whole result dataset.
result = @[]
for r in fastRows(db, query, args):
result.add(r)
iterator rows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDb].} =
iterator rows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [FReadDb].} =
## same as `FastRows`, but slower and safe.
for r in fastRows(db, query, args): yield r
proc getValue*(db: TDbConn, query: TSqlQuery,
proc getValue*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): string {.tags: [FReadDb].} =
## executes the query and returns the first column of the first row of the
## result dataset. Returns "" if the dataset contains no rows or the database
@ -148,7 +149,7 @@ proc getValue*(db: TDbConn, query: TSqlQuery,
result = ""
if finalize(stmt) != SQLITE_OK: dbError(db)
proc tryInsertID*(db: TDbConn, query: TSqlQuery,
proc tryInsertID*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64
{.tags: [FWriteDb], raises: [].} =
## executes the query (typically "INSERT") and returns the
@ -162,7 +163,7 @@ proc tryInsertID*(db: TDbConn, query: TSqlQuery,
if finalize(stmt) != SQLITE_OK:
result = -1
proc insertID*(db: TDbConn, query: TSqlQuery,
proc insertID*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
## executes the query (typically "INSERT") and returns the
## generated ID for the row. For Postgre this adds
@ -171,7 +172,7 @@ proc insertID*(db: TDbConn, query: TSqlQuery,
result = tryInsertID(db, query, args)
if result < 0: dbError(db)
proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
proc execAffectedRows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64 {.
tags: [FReadDb, FWriteDb].} =
## executes the query (typically "UPDATE") and returns the
@ -179,21 +180,21 @@ proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
exec(db, query, args)
result = changes(db)
proc close*(db: TDbConn) {.tags: [FDb].} =
proc close*(db: DbConn) {.tags: [FDb].} =
## closes the database connection.
if sqlite3.close(db) != SQLITE_OK: dbError(db)
proc open*(connection, user, password, database: string): TDbConn {.
proc open*(connection, user, password, database: string): DbConn {.
tags: [FDb].} =
## opens a database connection. Raises `EDb` if the connection could not
## be established. Only the ``connection`` parameter is used for ``sqlite``.
var db: TDbConn
var db: DbConn
if sqlite3.open(connection, db) == SQLITE_OK:
result = db
else:
dbError(db)
proc setEncoding*(connection: TDbConn, encoding: string): bool {.
proc setEncoding*(connection: DbConn, encoding: string): bool {.
tags: [FDb].} =
## sets the encoding of a database connection, returns true for
## success, false for failure.

View file

@ -17,23 +17,24 @@ from sdl import PSurface # Bug
from sdl_ttf import openFont, closeFont
type
TRect* = tuple[x, y, width, height: int]
TPoint* = tuple[x, y: int]
Rect* = tuple[x, y, width, height: int]
Point* = tuple[x, y: int]
PSurface* = ref TSurface ## a surface to draw onto
TSurface* {.pure, final.} = object
PSurface* = ref Surface ## a surface to draw onto
Surface* {.pure, final.} = object
w*, h*: Natural
s*: sdl.PSurface
EGraphics* = object of IOError
TFont {.pure, final.} = object
Font {.pure, final.} = object
f: sdl_ttf.PFont
color: sdl.TColor
PFont* = ref TFont ## represents a font
color: sdl.Color
PFont* = ref Font ## represents a font
{.deprecated: [TSurface: Surface, TFont: Font, TRect: Rect, TPoint: Point].}
proc toSdlColor*(c: Color): sdl.TColor =
## Convert colors.TColor to sdl.TColor
proc toSdlColor*(c: Color): sdl.Color =
## Convert colors.Color to sdl.Color
var x = c.extractRGB
result.r = x.r and 0xff
result.g = x.g and 0xff
@ -45,8 +46,8 @@ proc createSdlColor*(sur: PSurface, c: Color, alpha: int = 0): int32 =
return sdl.mapRGBA(sur.s.format, x.r and 0xff, x.g and 0xff,
x.b and 0xff, alpha and 0xff)
proc toSdlRect*(r: TRect): sdl.TRect =
## Convert ``graphics.TRect`` to ``sdl.TRect``.
proc toSdlRect*(r: Rect): sdl.Rect =
## Convert ``graphics.Rect`` to ``sdl.Rect``.
result.x = int16(r.x)
result.y = int16(r.y)
result.w = uint16(r.width)
@ -103,8 +104,9 @@ proc writeToBMP*(sur: PSurface, filename: string) =
raise newException(IOError, "cannot write: " & filename)
type
TPixels = array[0..1000_000-1, int32]
PPixels = ptr TPixels
Pixels = array[0..1000_000-1, int32]
PPixels = ptr Pixels
{.deprecated: [TPixels: Pixels].}
template setPix(video, pitch, x, y, col: expr): stmt =
video[y * pitch + x] = int32(col)
@ -128,7 +130,7 @@ proc setPixel(sur: PSurface, x, y: Natural, col: colors.Color) {.inline.} =
#pixs[y * (sur.s.pitch div colSize) + x] = int(col)
setPix(pixs, sur.s.pitch.int div ColSize, x, y, col)
proc `[]`*(sur: PSurface, p: TPoint): Color =
proc `[]`*(sur: PSurface, p: Point): Color =
## get pixel at position `p`. No range checking is done!
result = getPixel(sur, p.x, p.y)
@ -136,7 +138,7 @@ proc `[]`*(sur: PSurface, x, y: int): Color =
## get pixel at position ``(x, y)``. No range checking is done!
result = getPixel(sur, x, y)
proc `[]=`*(sur: PSurface, p: TPoint, col: Color) =
proc `[]=`*(sur: PSurface, p: Point, col: Color) =
## set the pixel at position `p`. No range checking is done!
setPixel(sur, p.x, p.y, col)
@ -144,10 +146,10 @@ proc `[]=`*(sur: PSurface, x, y: int, col: Color) =
## set the pixel at position ``(x, y)``. No range checking is done!
setPixel(sur, x, y, col)
proc blit*(destSurf: PSurface, destRect: TRect, srcSurf: PSurface,
srcRect: TRect) =
proc blit*(destSurf: PSurface, destRect: Rect, srcSurf: PSurface,
srcRect: Rect) =
## Copies ``srcSurf`` into ``destSurf``
var destTRect, srcTRect: sdl.TRect
var destTRect, srcTRect: sdl.Rect
destTRect.x = int16(destRect.x)
destTRect.y = int16(destRect.y)
@ -168,7 +170,7 @@ proc textBounds*(text: string, font = defaultFont): tuple[width, height: int] =
result.width = int(w)
result.height = int(h)
proc drawText*(sur: PSurface, p: TPoint, text: string, font = defaultFont) =
proc drawText*(sur: PSurface, p: Point, text: string, font = defaultFont) =
## Draws text with a transparent background, at location ``p`` with the given
## font.
var textSur: PSurface # This surface will have the text drawn on it
@ -179,7 +181,7 @@ proc drawText*(sur: PSurface, p: TPoint, text: string, font = defaultFont) =
# Merge the text surface with sur
sur.blit((p.x, p.y, sur.w, sur.h), textSur, (0, 0, sur.w, sur.h))
proc drawText*(sur: PSurface, p: TPoint, text: string,
proc drawText*(sur: PSurface, p: Point, text: string,
bg: Color, font = defaultFont) =
## Draws text, at location ``p`` with font ``font``. ``bg``
## is the background color.
@ -189,7 +191,7 @@ proc drawText*(sur: PSurface, p: TPoint, text: string,
# Merge the text surface with sur
sur.blit((p.x, p.y, sur.w, sur.h), textSur, (0, 0, sur.w, sur.h))
proc drawCircle*(sur: PSurface, p: TPoint, r: Natural, color: Color) =
proc drawCircle*(sur: PSurface, p: Point, r: Natural, color: Color) =
## draws a circle with center `p` and radius `r` with the given color
## onto the surface `sur`.
var video = cast[PPixels](sur.s.pixels)
@ -229,7 +231,7 @@ proc `>-<`(val: int, s: PSurface): int {.inline.} =
proc `>|<`(val: int, s: PSurface): int {.inline.} =
return if val < 0: 0 elif val >= s.h: s.h-1 else: val
proc drawLine*(sur: PSurface, p1, p2: TPoint, color: Color) =
proc drawLine*(sur: PSurface, p1, p2: Point, color: Color) =
## draws a line between the two points `p1` and `p2` with the given color
## onto the surface `sur`.
var stepx, stepy: int = 0
@ -291,7 +293,7 @@ proc drawVerLine*(sur: PSurface, x, y, h: Natural, color: Color) =
for i in 0 .. min(sur.s.h-y, h)-1:
setPix(video, pitch, x, y + i, color)
proc fillCircle*(s: PSurface, p: TPoint, r: Natural, color: Color) =
proc fillCircle*(s: PSurface, p: Point, r: Natural, color: Color) =
## draws a circle with center `p` and radius `r` with the given color
## onto the surface `sur` and fills it.
var a = 1 - r
@ -319,7 +321,7 @@ proc fillCircle*(s: PSurface, p: TPoint, r: Natural, color: Color) =
drawVerLine(s, x - py - 1, y - px, px, color)
px = px + 1
proc drawRect*(sur: PSurface, r: TRect, color: Color) =
proc drawRect*(sur: PSurface, r: Rect, color: Color) =
## draws a rectangle.
var video = cast[PPixels](sur.s.pixels)
var pitch = sur.s.pitch.int div ColSize
@ -337,7 +339,7 @@ proc drawRect*(sur: PSurface, r: TRect, color: Color) =
setPix(video, pitch, r.x, r.y + i, color)
setPix(video, pitch, r.x + minW - 1, r.y + i, color) # Draw right side
proc fillRect*(sur: PSurface, r: TRect, col: Color) =
proc fillRect*(sur: PSurface, r: Rect, col: Color) =
## Fills a rectangle using sdl's ``FillRect`` function.
var rect = toSdlRect(r)
if sdl.fillRect(sur.s, addr(rect), sur.createSdlColor(col)) == -1:
@ -424,7 +426,7 @@ template cround(x: expr): expr = ipart(x + 0.5)
template fpart(x: expr): expr = x - ipart(x)
template rfpart(x: expr): expr = 1.0 - fpart(x)
proc drawLineAA*(sur: PSurface, p1, p2: TPoint, color: Color) =
proc drawLineAA*(sur: PSurface, p1, p2: Point, color: Color) =
## Draws a anti-aliased line from ``p1`` to ``p2``, using Xiaolin Wu's
## line algorithm
var (x1, x2, y1, y2) = (p1.x.toFloat(), p2.x.toFloat(),
@ -490,9 +492,9 @@ proc fillSurface*(sur: PSurface, color: Color) =
template withEvents*(surf: PSurface, event: expr, actions: stmt): stmt {.
immediate.} =
## Simple template which creates an event loop. ``Event`` is the name of the
## variable containing the TEvent object.
## variable containing the Event object.
while true:
var event: sdl.TEvent
var event: sdl.Event
if sdl.waitEvent(addr(event)) == 1:
actions

View file

@ -135,7 +135,7 @@ else:
var cur, old: Termios
discard fd.tcgetattr(cur.addr)
old = cur
cur.c_lflag = cur.c_lflag and not Tcflag(ECHO)
cur.c_lflag = cur.c_lflag and not Cflag(ECHO)
discard fd.tcsetattr(TCSADRAIN, cur.addr)
stdout.write prompt
result = stdin.readLine(password)

View file

@ -15,11 +15,12 @@
import openssl, strutils, os
type
TSecureSocket* = object
SecureSocket* = object
ssl: SslPtr
bio: BIO
{.deprecated: [TSecureSocket: SecureSocket].}
proc connect*(sock: var TSecureSocket, address: string,
proc connect*(sock: var SecureSocket, address: string,
port: int): int =
## Connects to the specified `address` on the specified `port`.
## Returns the result of the certificate validation.
@ -52,7 +53,7 @@ proc connect*(sock: var TSecureSocket, address: string,
result = SSL_get_verify_result(sock.ssl)
proc recvLine*(sock: TSecureSocket, line: var TaintedString): bool =
proc recvLine*(sock: SecureSocket, line: var TaintedString): bool =
## Acts in a similar fashion to the `recvLine` in the sockets module.
## Returns false when no data is available to be read.
## `Line` must be initialized and not nil!
@ -71,19 +72,19 @@ proc recvLine*(sock: TSecureSocket, line: var TaintedString): bool =
add(line.string, c)
proc send*(sock: TSecureSocket, data: string) =
proc send*(sock: SecureSocket, data: string) =
## Writes `data` to the socket.
if BIO_write(sock.bio, data, data.len.cint) <= 0:
raiseOSError(osLastError())
proc close*(sock: TSecureSocket) =
proc close*(sock: SecureSocket) =
## Closes the socket
if BIO_free(sock.bio) <= 0:
ERR_print_errors_fp(stderr)
raiseOSError(osLastError())
when not defined(testing) and isMainModule:
var s: TSecureSocket
var s: SecureSocket
echo connect(s, "smtp.gmail.com", 465)
#var buffer: array[0..255, char]

View file

@ -13,18 +13,18 @@ import
streams, libzip, times, os, strutils
type
TZipArchive* = object of RootObj ## represents a zip archive
ZipArchive* = object of RootObj ## represents a zip archive
mode: FileMode
w: PZip
{.deprecated: [TZipArchive: ZipArchive].}
proc zipError(z: var TZipArchive) =
proc zipError(z: var ZipArchive) =
var e: ref IOError
new(e)
e.msg = $zip_strerror(z.w)
raise e
proc open*(z: var TZipArchive, filename: string, mode: FileMode = fmRead): bool =
proc open*(z: var ZipArchive, filename: string, mode: FileMode = fmRead): bool =
## Opens a zip file for reading, writing or appending. All file modes are
## supported. Returns true iff successful, false otherwise.
var err, flags: int32
@ -38,11 +38,11 @@ proc open*(z: var TZipArchive, filename: string, mode: FileMode = fmRead): bool
z.mode = mode
result = z.w != nil
proc close*(z: var TZipArchive) =
proc close*(z: var ZipArchive) =
## Closes a zip file.
zip_close(z.w)
proc createDir*(z: var TZipArchive, dir: string) =
proc createDir*(z: var ZipArchive, dir: string) =
## Creates a directory within the `z` archive. This does not fail if the
## directory already exists. Note that for adding a file like
## ``"path1/path2/filename"`` it is not necessary
@ -52,7 +52,7 @@ proc createDir*(z: var TZipArchive, dir: string) =
discard zip_add_dir(z.w, dir)
zip_error_clear(z.w)
proc addFile*(z: var TZipArchive, dest, src: string) =
proc addFile*(z: var ZipArchive, dest, src: string) =
## Adds the file `src` to the archive `z` with the name `dest`. `dest`
## may contain a path that will be created.
assert(z.mode != fmRead)
@ -67,13 +67,13 @@ proc addFile*(z: var TZipArchive, dest, src: string) =
zip_source_free(zipsrc)
zipError(z)
proc addFile*(z: var TZipArchive, file: string) =
proc addFile*(z: var ZipArchive, file: string) =
## A shortcut for ``addFile(z, file, file)``, i.e. the name of the source is
## the name of the destination.
addFile(z, file, file)
proc mySourceCallback(state, data: pointer, len: int,
cmd: TZipSourceCmd): int {.cdecl.} =
cmd: ZipSourceCmd): int {.cdecl.} =
var src = cast[Stream](state)
case cmd
of ZIP_SOURCE_OPEN:
@ -86,7 +86,7 @@ proc mySourceCallback(state, data: pointer, len: int,
zip_stat_init(stat)
stat.size = high(int32)-1 # we don't know the size
stat.mtime = getTime()
result = sizeof(TZipStat)
result = sizeof(ZipStat)
of ZIP_SOURCE_ERROR:
var err = cast[ptr array[0..1, cint]](data)
err[0] = ZIP_ER_INTERNAL
@ -95,7 +95,7 @@ proc mySourceCallback(state, data: pointer, len: int,
of constZIP_SOURCE_FREE: GC_unref(src)
else: assert(false)
proc addFile*(z: var TZipArchive, dest: string, src: Stream) =
proc addFile*(z: var ZipArchive, dest: string, src: Stream) =
## Adds a file named with `dest` to the archive `z`. `dest`
## may contain a path. The file's content is read from the `src` stream.
assert(z.mode != fmRead)
@ -134,7 +134,7 @@ proc newZipFileStream(f: PZipFile): PZipFileStream =
# ----------------------------------------------------------------------------
proc getStream*(z: var TZipArchive, filename: string): PZipFileStream =
proc getStream*(z: var ZipArchive, filename: string): PZipFileStream =
## returns a stream that can be used to read the file named `filename`
## from the archive `z`. Returns nil in case of an error.
## The returned stream does not support the `setPosition`, `getPosition`,
@ -142,7 +142,7 @@ proc getStream*(z: var TZipArchive, filename: string): PZipFileStream =
var x = zip_fopen(z.w, filename, 0'i32)
if x != nil: result = newZipFileStream(x)
iterator walkFiles*(z: var TZipArchive): string =
iterator walkFiles*(z: var ZipArchive): string =
## walks over all files in the archive `z` and returns the filename
## (including the path).
var i = 0'i32
@ -152,7 +152,7 @@ iterator walkFiles*(z: var TZipArchive): string =
inc(i)
proc extractFile*(z: var TZipArchive, srcFile: string, dest: Stream) =
proc extractFile*(z: var ZipArchive, srcFile: string, dest: Stream) =
## extracts a file from the zip archive `z` to the destination stream.
var strm = getStream(z, srcFile)
while true:
@ -162,13 +162,13 @@ proc extractFile*(z: var TZipArchive, srcFile: string, dest: Stream) =
dest.flush()
strm.close()
proc extractFile*(z: var TZipArchive, srcFile: string, dest: string) =
proc extractFile*(z: var ZipArchive, srcFile: string, dest: string) =
## extracts a file from the zip archive `z` to the destination filename.
var file = newFileStream(dest, fmWrite)
extractFile(z, srcFile, file)
file.close()
proc extractAll*(z: var TZipArchive, dest: string) =
proc extractAll*(z: var ZipArchive, dest: string) =
## extracts all files from archive `z` to the destination directory.
for file in walkFiles(z):
if file.endsWith("/"):
@ -177,7 +177,7 @@ proc extractAll*(z: var TZipArchive, dest: string) =
extractFile(z, file, dest / file)
when not defined(testing) and isMainModule:
var zip: TZipArchive
var zip: ZipArchive
if not zip.open("nim-0.11.0.zip"):
raise newException(IOError, "opening zip failed")
zip.extractAll("test")

View file

@ -15,7 +15,7 @@ import
strutils
type
TTokenClass* = enum
TokenClass* = enum
gtEof, gtNone, gtWhitespace, gtDecNumber, gtBinNumber, gtHexNumber,
gtOctNumber, gtFloatNumber, gtIdentifier, gtKeyword, gtStringLit,
gtLongStringLit, gtCharLit, gtEscapeSequence, # escape sequence like \xff
@ -23,20 +23,22 @@ type
gtTagStart, gtTagEnd, gtKey, gtValue, gtRawData, gtAssembler,
gtPreprocessor, gtDirective, gtCommand, gtRule, gtHyperlink, gtLabel,
gtReference, gtOther
TGeneralTokenizer* = object of RootObj
kind*: TTokenClass
GeneralTokenizer* = object of RootObj
kind*: TokenClass
start*, length*: int
buf: cstring
pos: int
state: TTokenClass
state: TokenClass
TSourceLanguage* = enum
SourceLanguage* = enum
langNone, langNim, langNimrod, langCpp, langCsharp, langC, langJava
{.deprecated: [TSourceLanguage: SourceLanguage, TTokenClass: TokenClass,
TGeneralTokenizer: GeneralTokenizer].}
const
sourceLanguageToStr*: array[TSourceLanguage, string] = ["none",
sourceLanguageToStr*: array[SourceLanguage, string] = ["none",
"Nim", "Nimrod", "C++", "C#", "C", "Java"]
tokenClassToStr*: array[TTokenClass, string] = ["Eof", "None", "Whitespace",
tokenClassToStr*: array[TokenClass, string] = ["Eof", "None", "Whitespace",
"DecNumber", "BinNumber", "HexNumber", "OctNumber", "FloatNumber",
"Identifier", "Keyword", "StringLit", "LongStringLit", "CharLit",
"EscapeSequence", "Operator", "Punctuation", "Comment", "LongComment",
@ -58,29 +60,29 @@ const
"template", "try", "tuple", "type", "using", "var", "when", "while", "with",
"without", "xor", "yield"]
proc getSourceLanguage*(name: string): TSourceLanguage =
for i in countup(succ(low(TSourceLanguage)), high(TSourceLanguage)):
proc getSourceLanguage*(name: string): SourceLanguage =
for i in countup(succ(low(SourceLanguage)), high(SourceLanguage)):
if cmpIgnoreStyle(name, sourceLanguageToStr[i]) == 0:
return i
result = langNone
proc initGeneralTokenizer*(g: var TGeneralTokenizer, buf: cstring) =
proc initGeneralTokenizer*(g: var GeneralTokenizer, buf: cstring) =
g.buf = buf
g.kind = low(TTokenClass)
g.kind = low(TokenClass)
g.start = 0
g.length = 0
g.state = low(TTokenClass)
g.state = low(TokenClass)
var pos = 0 # skip initial whitespace:
while g.buf[pos] in {' ', '\x09'..'\x0D'}: inc(pos)
g.pos = pos
proc initGeneralTokenizer*(g: var TGeneralTokenizer, buf: string) =
proc initGeneralTokenizer*(g: var GeneralTokenizer, buf: string) =
initGeneralTokenizer(g, cstring(buf))
proc deinitGeneralTokenizer*(g: var TGeneralTokenizer) =
proc deinitGeneralTokenizer*(g: var GeneralTokenizer) =
discard
proc nimGetKeyword(id: string): TTokenClass =
proc nimGetKeyword(id: string): TokenClass =
for k in nimKeywords:
if cmpIgnoreStyle(id, k) == 0: return gtKeyword
result = gtIdentifier
@ -92,7 +94,7 @@ proc nimGetKeyword(id: string): TTokenClass =
else:
result = gtIdentifier
proc nimNumberPostfix(g: var TGeneralTokenizer, position: int): int =
proc nimNumberPostfix(g: var GeneralTokenizer, position: int): int =
var pos = position
if g.buf[pos] == '\'':
inc(pos)
@ -110,7 +112,7 @@ proc nimNumberPostfix(g: var TGeneralTokenizer, position: int): int =
discard
result = pos
proc nimNumber(g: var TGeneralTokenizer, position: int): int =
proc nimNumber(g: var GeneralTokenizer, position: int): int =
const decChars = {'0'..'9', '_'}
var pos = position
g.kind = gtDecNumber
@ -130,7 +132,7 @@ const
OpChars = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
'|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'}
proc nimNextToken(g: var TGeneralTokenizer) =
proc nimNextToken(g: var GeneralTokenizer) =
const
hexChars = {'0'..'9', 'A'..'F', 'a'..'f', '_'}
octChars = {'0'..'7', '_'}
@ -278,7 +280,7 @@ proc nimNextToken(g: var TGeneralTokenizer) =
assert false, "nimNextToken: produced an empty token"
g.pos = pos
proc generalNumber(g: var TGeneralTokenizer, position: int): int =
proc generalNumber(g: var GeneralTokenizer, position: int): int =
const decChars = {'0'..'9'}
var pos = position
g.kind = gtDecNumber
@ -294,7 +296,7 @@ proc generalNumber(g: var TGeneralTokenizer, position: int): int =
while g.buf[pos] in decChars: inc(pos)
result = pos
proc generalStrLit(g: var TGeneralTokenizer, position: int): int =
proc generalStrLit(g: var GeneralTokenizer, position: int): int =
const
decChars = {'0'..'9'}
hexChars = {'0'..'9', 'A'..'F', 'a'..'f'}
@ -355,12 +357,13 @@ proc isKeywordIgnoreCase(x: openArray[string], y: string): int =
result = - 1
type
TTokenizerFlag = enum
TokenizerFlag = enum
hasPreprocessor, hasNestedComments
TTokenizerFlags = set[TTokenizerFlag]
TokenizerFlags = set[TokenizerFlag]
{.deprecated: [TTokenizerFlag: TokenizerFlag, TTokenizerFlags: TokenizerFlags].}
proc clikeNextToken(g: var TGeneralTokenizer, keywords: openArray[string],
flags: TTokenizerFlags) =
proc clikeNextToken(g: var GeneralTokenizer, keywords: openArray[string],
flags: TokenizerFlags) =
const
hexChars = {'0'..'9', 'A'..'F', 'a'..'f'}
octChars = {'0'..'7'}
@ -493,7 +496,7 @@ proc clikeNextToken(g: var TGeneralTokenizer, keywords: openArray[string],
assert false, "clikeNextToken: produced an empty token"
g.pos = pos
proc cNextToken(g: var TGeneralTokenizer) =
proc cNextToken(g: var GeneralTokenizer) =
const
keywords: array[0..36, string] = ["_Bool", "_Complex", "_Imaginary", "auto",
"break", "case", "char", "const", "continue", "default", "do", "double",
@ -503,7 +506,7 @@ proc cNextToken(g: var TGeneralTokenizer) =
"volatile", "while"]
clikeNextToken(g, keywords, {hasPreprocessor})
proc cppNextToken(g: var TGeneralTokenizer) =
proc cppNextToken(g: var GeneralTokenizer) =
const
keywords: array[0..47, string] = ["asm", "auto", "break", "case", "catch",
"char", "class", "const", "continue", "default", "delete", "do", "double",
@ -514,7 +517,7 @@ proc cppNextToken(g: var TGeneralTokenizer) =
"union", "unsigned", "virtual", "void", "volatile", "while"]
clikeNextToken(g, keywords, {hasPreprocessor})
proc csharpNextToken(g: var TGeneralTokenizer) =
proc csharpNextToken(g: var GeneralTokenizer) =
const
keywords: array[0..76, string] = ["abstract", "as", "base", "bool", "break",
"byte", "case", "catch", "char", "checked", "class", "const", "continue",
@ -529,7 +532,7 @@ proc csharpNextToken(g: var TGeneralTokenizer) =
"virtual", "void", "volatile", "while"]
clikeNextToken(g, keywords, {hasPreprocessor})
proc javaNextToken(g: var TGeneralTokenizer) =
proc javaNextToken(g: var GeneralTokenizer) =
const
keywords: array[0..52, string] = ["abstract", "assert", "boolean", "break",
"byte", "case", "catch", "char", "class", "const", "continue", "default",
@ -541,7 +544,7 @@ proc javaNextToken(g: var TGeneralTokenizer) =
"try", "void", "volatile", "while"]
clikeNextToken(g, keywords, {})
proc getNextToken*(g: var TGeneralTokenizer, lang: TSourceLanguage) =
proc getNextToken*(g: var GeneralTokenizer, lang: SourceLanguage) =
case lang
of langNone: assert false
of langNim, langNimrod: nimNextToken(g)

View file

@ -15,7 +15,7 @@ import
os, strutils, rstast
type
TRstParseOption* = enum ## options for the RST parser
RstParseOption* = enum ## options for the RST parser
roSkipPounds, ## skip ``#`` at line beginning (documentation
## embedded in Nim comments)
roSupportSmilies, ## make the RST parser support smilies like ``:)``
@ -23,14 +23,14 @@ type
## it for sandboxing)
roSupportMarkdown ## support additional features of markdown
TRstParseOptions* = set[TRstParseOption]
RstParseOptions* = set[RstParseOption]
TMsgClass* = enum
MsgClass* = enum
mcHint = "Hint",
mcWarning = "Warning",
mcError = "Error"
TMsgKind* = enum ## the possible messages
MsgKind* = enum ## the possible messages
meCannotOpenFile,
meExpected,
meGridTableNotImplemented,
@ -42,12 +42,14 @@ type
mwUnsupportedLanguage,
mwUnsupportedField
TMsgHandler* = proc (filename: string, line, col: int, msgKind: TMsgKind,
MsgHandler* = proc (filename: string, line, col: int, msgKind: MsgKind,
arg: string) {.nimcall.} ## what to do in case of an error
TFindFileHandler* = proc (filename: string): string {.nimcall.}
FindFileHandler* = proc (filename: string): string {.nimcall.}
{.deprecated: [TRstParseOptions: RstParseOptions, TRstParseOption: RstParseOption,
TMsgKind: MsgKind].}
const
messages: array [TMsgKind, string] = [
messages: array [MsgKind, string] = [
meCannotOpenFile: "cannot open '$1'",
meExpected: "'$1' expected",
meGridTableNotImplemented: "grid table is not implemented",
@ -111,23 +113,24 @@ const
}
type
TTokType = enum
TokType = enum
tkEof, tkIndent, tkWhite, tkWord, tkAdornment, tkPunct, tkOther
TToken = object # a RST token
kind*: TTokType # the type of the token
Token = object # a RST token
kind*: TokType # the type of the token
ival*: int # the indentation or parsed integer value
symbol*: string # the parsed symbol as string
line*, col*: int # line and column of the token
TTokenSeq = seq[TToken]
TLexer = object of RootObj
TokenSeq = seq[Token]
Lexer = object of RootObj
buf*: cstring
bufpos*: int
line*, col*, baseIndent*: int
skipPounds*: bool
{.deprecated: [TTokType: TokType, TToken: Token, TTokenSeq: TokenSeq,
TLexer: Lexer].}
proc getThing(L: var TLexer, tok: var TToken, s: set[char]) =
proc getThing(L: var Lexer, tok: var Token, s: set[char]) =
tok.kind = tkWord
tok.line = L.line
tok.col = L.col
@ -139,7 +142,7 @@ proc getThing(L: var TLexer, tok: var TToken, s: set[char]) =
inc(L.col, pos - L.bufpos)
L.bufpos = pos
proc getAdornment(L: var TLexer, tok: var TToken) =
proc getAdornment(L: var Lexer, tok: var Token) =
tok.kind = tkAdornment
tok.line = L.line
tok.col = L.col
@ -152,7 +155,7 @@ proc getAdornment(L: var TLexer, tok: var TToken) =
inc(L.col, pos - L.bufpos)
L.bufpos = pos
proc getIndentAux(L: var TLexer, start: int): int =
proc getIndentAux(L: var Lexer, start: int): int =
var pos = start
var buf = L.buf
# skip the newline (but include it in the token!)
@ -181,7 +184,7 @@ proc getIndentAux(L: var TLexer, start: int): int =
result = getIndentAux(L, pos)
L.bufpos = pos # no need to set back buf
proc getIndent(L: var TLexer, tok: var TToken) =
proc getIndent(L: var Lexer, tok: var Token) =
tok.col = 0
tok.kind = tkIndent # skip the newline (but include it in the token!)
tok.ival = getIndentAux(L, L.bufpos)
@ -191,7 +194,7 @@ proc getIndent(L: var TLexer, tok: var TToken) =
tok.ival = max(tok.ival - L.baseIndent, 0)
tok.symbol = "\n" & spaces(tok.ival)
proc rawGetTok(L: var TLexer, tok: var TToken) =
proc rawGetTok(L: var Lexer, tok: var Token) =
tok.symbol = ""
tok.ival = 0
var c = L.buf[L.bufpos]
@ -222,8 +225,8 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
inc(L.col)
tok.col = max(tok.col - L.baseIndent, 0)
proc getTokens(buffer: string, skipPounds: bool, tokens: var TTokenSeq): int =
var L: TLexer
proc getTokens(buffer: string, skipPounds: bool, tokens: var TokenSeq): int =
var L: Lexer
var length = len(tokens)
L.buf = cstring(buffer)
L.line = 0 # skip UTF-8 BOM
@ -253,31 +256,31 @@ proc getTokens(buffer: string, skipPounds: bool, tokens: var TTokenSeq): int =
tokens[0].kind = tkIndent
type
TLevelMap = array[char, int]
TSubstitution = object
LevelMap = array[char, int]
Substitution = object
key*: string
value*: PRstNode
TSharedState = object
options: TRstParseOptions # parsing options
SharedState = object
options: RstParseOptions # parsing options
uLevel, oLevel: int # counters for the section levels
subs: seq[TSubstitution] # substitutions
refs: seq[TSubstitution] # references
underlineToLevel: TLevelMap # Saves for each possible title adornment
subs: seq[Substitution] # substitutions
refs: seq[Substitution] # references
underlineToLevel: LevelMap # Saves for each possible title adornment
# character its level in the
# current document.
# This is for single underline adornments.
overlineToLevel: TLevelMap # Saves for each possible title adornment
overlineToLevel: LevelMap # Saves for each possible title adornment
# character its level in the current
# document.
# This is for over-underline adornments.
msgHandler: TMsgHandler # How to handle errors.
findFile: TFindFileHandler # How to find files.
msgHandler: MsgHandler # How to handle errors.
findFile: FindFileHandler # How to find files.
PSharedState = ref TSharedState
TRstParser = object of RootObj
PSharedState = ref SharedState
RstParser = object of RootObj
idx*: int
tok*: TTokenSeq
tok*: TokenSeq
s*: PSharedState
indentStack*: seq[int]
filename*: string
@ -285,8 +288,12 @@ type
hasToc*: bool
EParseError* = object of ValueError
{.deprecated: [TLevelMap: LevelMap, TSubstitution: Substitution,
TSharedState: SharedState, TRstParser: RstParser,
TMsgHandler: MsgHandler, TFindFileHandler: FindFileHandler,
TMsgClass: MsgClass].}
proc whichMsgClass*(k: TMsgKind): TMsgClass =
proc whichMsgClass*(k: MsgKind): MsgClass =
## returns which message class `k` belongs to.
case ($k)[1]
of 'e', 'E': result = mcError
@ -294,7 +301,7 @@ proc whichMsgClass*(k: TMsgKind): TMsgClass =
of 'h', 'H': result = mcHint
else: assert false, "msgkind does not fit naming scheme"
proc defaultMsgHandler*(filename: string, line, col: int, msgkind: TMsgKind,
proc defaultMsgHandler*(filename: string, line, col: int, msgkind: MsgKind,
arg: string) {.procvar.} =
let mc = msgkind.whichMsgClass
let a = messages[msgkind] % arg
@ -306,9 +313,9 @@ proc defaultFindFile*(filename: string): string {.procvar.} =
if existsFile(filename): result = filename
else: result = ""
proc newSharedState(options: TRstParseOptions,
findFile: TFindFileHandler,
msgHandler: TMsgHandler): PSharedState =
proc newSharedState(options: RstParseOptions,
findFile: FindFileHandler,
msgHandler: MsgHandler): PSharedState =
new(result)
result.subs = @[]
result.refs = @[]
@ -316,34 +323,34 @@ proc newSharedState(options: TRstParseOptions,
result.msgHandler = if not isNil(msgHandler): msgHandler else: defaultMsgHandler
result.findFile = if not isNil(findFile): findFile else: defaultFindFile
proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string) =
proc rstMessage(p: RstParser, msgKind: MsgKind, arg: string) =
p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line,
p.col + p.tok[p.idx].col, msgKind, arg)
proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string, line, col: int) =
proc rstMessage(p: RstParser, msgKind: MsgKind, arg: string, line, col: int) =
p.s.msgHandler(p.filename, p.line + line,
p.col + col, msgKind, arg)
proc rstMessage(p: TRstParser, msgKind: TMsgKind) =
proc rstMessage(p: RstParser, msgKind: MsgKind) =
p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line,
p.col + p.tok[p.idx].col, msgKind,
p.tok[p.idx].symbol)
when false:
proc corrupt(p: TRstParser) =
proc corrupt(p: RstParser) =
assert p.indentStack[0] == 0
for i in 1 .. high(p.indentStack): assert p.indentStack[i] < 1_000
proc currInd(p: TRstParser): int =
proc currInd(p: RstParser): int =
result = p.indentStack[high(p.indentStack)]
proc pushInd(p: var TRstParser, ind: int) =
proc pushInd(p: var RstParser, ind: int) =
add(p.indentStack, ind)
proc popInd(p: var TRstParser) =
proc popInd(p: var RstParser) =
if len(p.indentStack) > 1: setLen(p.indentStack, len(p.indentStack) - 1)
proc initParser(p: var TRstParser, sharedState: PSharedState) =
proc initParser(p: var RstParser, sharedState: PSharedState) =
p.indentStack = @[0]
p.tok = @[]
p.idx = 0
@ -393,7 +400,7 @@ proc rstnodeToRefname(n: PRstNode): string =
var b = false
rstnodeToRefnameAux(n, result, b)
proc findSub(p: var TRstParser, n: PRstNode): int =
proc findSub(p: var RstParser, n: PRstNode): int =
var key = addNodes(n)
# the spec says: if no exact match, try one without case distinction:
for i in countup(0, high(p.s.subs)):
@ -404,7 +411,7 @@ proc findSub(p: var TRstParser, n: PRstNode): int =
return i
result = -1
proc setSub(p: var TRstParser, key: string, value: PRstNode) =
proc setSub(p: var RstParser, key: string, value: PRstNode) =
var length = len(p.s.subs)
for i in countup(0, length - 1):
if key == p.s.subs[i].key:
@ -414,7 +421,7 @@ proc setSub(p: var TRstParser, key: string, value: PRstNode) =
p.s.subs[length].key = key
p.s.subs[length].value = value
proc setRef(p: var TRstParser, key: string, value: PRstNode) =
proc setRef(p: var RstParser, key: string, value: PRstNode) =
var length = len(p.s.refs)
for i in countup(0, length - 1):
if key == p.s.refs[i].key:
@ -427,15 +434,15 @@ proc setRef(p: var TRstParser, key: string, value: PRstNode) =
p.s.refs[length].key = key
p.s.refs[length].value = value
proc findRef(p: var TRstParser, key: string): PRstNode =
proc findRef(p: var RstParser, key: string): PRstNode =
for i in countup(0, high(p.s.refs)):
if key == p.s.refs[i].key:
return p.s.refs[i].value
proc newLeaf(p: var TRstParser): PRstNode =
proc newLeaf(p: var RstParser): PRstNode =
result = newRstNode(rnLeaf, p.tok[p.idx].symbol)
proc getReferenceName(p: var TRstParser, endStr: string): PRstNode =
proc getReferenceName(p: var RstParser, endStr: string): PRstNode =
var res = newRstNode(rnInner)
while true:
case p.tok[p.idx].kind
@ -453,17 +460,17 @@ proc getReferenceName(p: var TRstParser, endStr: string): PRstNode =
inc(p.idx)
result = res
proc untilEol(p: var TRstParser): PRstNode =
proc untilEol(p: var RstParser): PRstNode =
result = newRstNode(rnInner)
while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
add(result, newLeaf(p))
inc(p.idx)
proc expect(p: var TRstParser, tok: string) =
proc expect(p: var RstParser, tok: string) =
if p.tok[p.idx].symbol == tok: inc(p.idx)
else: rstMessage(p, meExpected, tok)
proc isInlineMarkupEnd(p: TRstParser, markup: string): bool =
proc isInlineMarkupEnd(p: RstParser, markup: string): bool =
result = p.tok[p.idx].symbol == markup
if not result:
return # Rule 3:
@ -480,7 +487,7 @@ proc isInlineMarkupEnd(p: TRstParser, markup: string): bool =
if (markup != "``") and (p.tok[p.idx - 1].symbol == "\\"):
result = false
proc isInlineMarkupStart(p: TRstParser, markup: string): bool =
proc isInlineMarkupStart(p: RstParser, markup: string): bool =
var d: char
result = p.tok[p.idx].symbol == markup
if not result:
@ -507,7 +514,7 @@ proc isInlineMarkupStart(p: TRstParser, markup: string): bool =
else: d = '\0'
if d != '\0': result = p.tok[p.idx + 1].symbol[0] != d
proc match(p: TRstParser, start: int, expr: string): bool =
proc match(p: RstParser, start: int, expr: string): bool =
# regular expressions are:
# special char exact match
# 'w' tkWord
@ -562,7 +569,7 @@ proc fixupEmbeddedRef(n, a, b: PRstNode) =
for i in countup(0, sep - incr): add(a, n.sons[i])
for i in countup(sep + 1, len(n) - 2): add(b, n.sons[i])
proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode =
proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode =
result = n
if isInlineMarkupEnd(p, "_") or isInlineMarkupEnd(p, "__"):
inc(p.idx)
@ -606,7 +613,7 @@ proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode =
add(result, newRstNode(rnLeaf, p.tok[p.idx + 1].symbol))
inc(p.idx, 3)
proc matchVerbatim(p: TRstParser, start: int, expr: string): int =
proc matchVerbatim(p: RstParser, start: int, expr: string): int =
result = start
var j = 0
while j < expr.len and result < p.tok.len and
@ -615,7 +622,7 @@ proc matchVerbatim(p: TRstParser, start: int, expr: string): int =
inc result
if j < expr.len: result = 0
proc parseSmiley(p: var TRstParser): PRstNode =
proc parseSmiley(p: var RstParser): PRstNode =
if p.tok[p.idx].symbol[0] notin SmileyStartChars: return
for key, val in items(Smilies):
let m = matchVerbatim(p, p.idx, key)
@ -631,12 +638,12 @@ when false:
'$', '(', ')', '~', '_', '?', '+', '-', '=', '\\', '.', '&',
'\128'..'\255'}
proc isUrl(p: TRstParser, i: int): bool =
proc isUrl(p: RstParser, i: int): bool =
result = (p.tok[i+1].symbol == ":") and (p.tok[i+2].symbol == "//") and
(p.tok[i+3].kind == tkWord) and
(p.tok[i].symbol in ["http", "https", "ftp", "telnet", "file"])
proc parseUrl(p: var TRstParser, father: PRstNode) =
proc parseUrl(p: var RstParser, father: PRstNode) =
#if p.tok[p.idx].symbol[strStart] == '<':
if isUrl(p, p.idx):
var n = newRstNode(rnStandaloneHyperlink)
@ -656,7 +663,7 @@ proc parseUrl(p: var TRstParser, father: PRstNode) =
if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n)
add(father, n)
proc parseBackslash(p: var TRstParser, father: PRstNode) =
proc parseBackslash(p: var RstParser, father: PRstNode) =
assert(p.tok[p.idx].kind == tkPunct)
if p.tok[p.idx].symbol == "\\\\":
add(father, newRstNode(rnLeaf, "\\"))
@ -671,7 +678,7 @@ proc parseBackslash(p: var TRstParser, father: PRstNode) =
inc(p.idx)
when false:
proc parseAdhoc(p: var TRstParser, father: PRstNode, verbatim: bool) =
proc parseAdhoc(p: var RstParser, father: PRstNode, verbatim: bool) =
if not verbatim and isURL(p, p.idx):
var n = newRstNode(rnStandaloneHyperlink)
while true:
@ -694,7 +701,7 @@ when false:
if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n)
add(father, n)
proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string,
proc parseUntil(p: var RstParser, father: PRstNode, postfix: string,
interpretBackslash: bool) =
let
line = p.tok[p.idx].line
@ -725,7 +732,7 @@ proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string,
inc(p.idx)
else: rstMessage(p, meExpected, postfix, line, col)
proc parseMarkdownCodeblock(p: var TRstParser): PRstNode =
proc parseMarkdownCodeblock(p: var RstParser): PRstNode =
var args = newRstNode(rnDirArg)
if p.tok[p.idx].kind == tkWord:
add(args, newLeaf(p))
@ -755,7 +762,7 @@ proc parseMarkdownCodeblock(p: var TRstParser): PRstNode =
add(result, nil)
add(result, lb)
proc parseInline(p: var TRstParser, father: PRstNode) =
proc parseInline(p: var RstParser, father: PRstNode) =
case p.tok[p.idx].kind
of tkPunct:
if isInlineMarkupStart(p, "***"):
@ -810,7 +817,7 @@ proc parseInline(p: var TRstParser, father: PRstNode) =
inc(p.idx)
else: discard
proc getDirective(p: var TRstParser): string =
proc getDirective(p: var RstParser): string =
if p.tok[p.idx].kind == tkWhite and p.tok[p.idx+1].kind == tkWord:
var j = p.idx
inc(p.idx)
@ -830,7 +837,7 @@ proc getDirective(p: var TRstParser): string =
else:
result = ""
proc parseComment(p: var TRstParser): PRstNode =
proc parseComment(p: var RstParser): PRstNode =
case p.tok[p.idx].kind
of tkIndent, tkEof:
if p.tok[p.idx].kind != tkEof and p.tok[p.idx + 1].kind == tkIndent:
@ -851,34 +858,35 @@ proc parseComment(p: var TRstParser): PRstNode =
result = nil
type
TDirKind = enum # must be ordered alphabetically!
DirKind = enum # must be ordered alphabetically!
dkNone, dkAuthor, dkAuthors, dkCode, dkCodeBlock, dkContainer, dkContents,
dkFigure, dkImage, dkInclude, dkIndex, dkRaw, dkTitle
{.deprecated: [TDirKind: DirKind].}
const
DirIds: array[0..12, string] = ["", "author", "authors", "code",
"code-block", "container", "contents", "figure", "image", "include",
"index", "raw", "title"]
proc getDirKind(s: string): TDirKind =
proc getDirKind(s: string): DirKind =
let i = find(DirIds, s)
if i >= 0: result = TDirKind(i)
if i >= 0: result = DirKind(i)
else: result = dkNone
proc parseLine(p: var TRstParser, father: PRstNode) =
proc parseLine(p: var RstParser, father: PRstNode) =
while true:
case p.tok[p.idx].kind
of tkWhite, tkWord, tkOther, tkPunct: parseInline(p, father)
else: break
proc parseUntilNewline(p: var TRstParser, father: PRstNode) =
proc parseUntilNewline(p: var RstParser, father: PRstNode) =
while true:
case p.tok[p.idx].kind
of tkWhite, tkWord, tkAdornment, tkOther, tkPunct: parseInline(p, father)
of tkEof, tkIndent: break
proc parseSection(p: var TRstParser, result: PRstNode) {.gcsafe.}
proc parseField(p: var TRstParser): PRstNode =
proc parseSection(p: var RstParser, result: PRstNode) {.gcsafe.}
proc parseField(p: var RstParser): PRstNode =
## Returns a parsed rnField node.
##
## rnField nodes have two children nodes, a rnFieldName and a rnFieldBody.
@ -897,7 +905,7 @@ proc parseField(p: var TRstParser): PRstNode =
add(result, fieldname)
add(result, fieldbody)
proc parseFields(p: var TRstParser): PRstNode =
proc parseFields(p: var RstParser): PRstNode =
## Parses fields for a section or directive block.
##
## This proc may return nil if the parsing doesn't find anything of value,
@ -947,8 +955,8 @@ proc getArgument(n: PRstNode): string =
if n.sons[0] == nil: result = ""
else: result = addNodes(n.sons[0])
proc parseDotDot(p: var TRstParser): PRstNode {.gcsafe.}
proc parseLiteralBlock(p: var TRstParser): PRstNode =
proc parseDotDot(p: var RstParser): PRstNode {.gcsafe.}
proc parseLiteralBlock(p: var RstParser): PRstNode =
result = newRstNode(rnLiteralBlock)
var n = newRstNode(rnLeaf, "")
if p.tok[p.idx].kind == tkIndent:
@ -974,13 +982,13 @@ proc parseLiteralBlock(p: var TRstParser): PRstNode =
inc(p.idx)
add(result, n)
proc getLevel(map: var TLevelMap, lvl: var int, c: char): int =
proc getLevel(map: var LevelMap, lvl: var int, c: char): int =
if map[c] == 0:
inc(lvl)
map[c] = lvl
result = map[c]
proc tokenAfterNewline(p: TRstParser): int =
proc tokenAfterNewline(p: RstParser): int =
result = p.idx
while true:
case p.tok[result].kind
@ -991,28 +999,28 @@ proc tokenAfterNewline(p: TRstParser): int =
break
else: inc(result)
proc isLineBlock(p: TRstParser): bool =
proc isLineBlock(p: RstParser): bool =
var j = tokenAfterNewline(p)
result = (p.tok[p.idx].col == p.tok[j].col) and (p.tok[j].symbol == "|") or
(p.tok[j].col > p.tok[p.idx].col)
proc predNL(p: TRstParser): bool =
proc predNL(p: RstParser): bool =
result = true
if p.idx > 0:
result = p.tok[p.idx-1].kind == tkIndent and
p.tok[p.idx-1].ival == currInd(p)
proc isDefList(p: TRstParser): bool =
proc isDefList(p: RstParser): bool =
var j = tokenAfterNewline(p)
result = (p.tok[p.idx].col < p.tok[j].col) and
(p.tok[j].kind in {tkWord, tkOther, tkPunct}) and
(p.tok[j - 2].symbol != "::")
proc isOptionList(p: TRstParser): bool =
proc isOptionList(p: RstParser): bool =
result = match(p, p.idx, "-w") or match(p, p.idx, "--w") or
match(p, p.idx, "/w") or match(p, p.idx, "//w")
proc whichSection(p: TRstParser): TRstNodeKind =
proc whichSection(p: RstParser): RstNodeKind =
case p.tok[p.idx].kind
of tkAdornment:
if match(p, p.idx + 1, "ii"): result = rnTransition
@ -1053,7 +1061,7 @@ proc whichSection(p: TRstParser): TRstNodeKind =
else: result = rnParagraph
else: result = rnLeaf
proc parseLineBlock(p: var TRstParser): PRstNode =
proc parseLineBlock(p: var RstParser): PRstNode =
result = nil
if p.tok[p.idx + 1].kind == tkWhite:
var col = p.tok[p.idx].col
@ -1072,7 +1080,7 @@ proc parseLineBlock(p: var TRstParser): PRstNode =
break
popInd(p)
proc parseParagraph(p: var TRstParser, result: PRstNode) =
proc parseParagraph(p: var RstParser, result: PRstNode) =
while true:
case p.tok[p.idx].kind
of tkIndent:
@ -1103,7 +1111,7 @@ proc parseParagraph(p: var TRstParser, result: PRstNode) =
parseInline(p, result)
else: break
proc parseHeadline(p: var TRstParser): PRstNode =
proc parseHeadline(p: var RstParser): PRstNode =
result = newRstNode(rnHeadline)
parseUntilNewline(p, result)
assert(p.tok[p.idx].kind == tkIndent)
@ -1113,12 +1121,13 @@ proc parseHeadline(p: var TRstParser): PRstNode =
result.level = getLevel(p.s.underlineToLevel, p.s.uLevel, c)
type
TIntSeq = seq[int]
IntSeq = seq[int]
{.deprecated: [TIntSeq: IntSeq].}
proc tokEnd(p: TRstParser): int =
proc tokEnd(p: RstParser): int =
result = p.tok[p.idx].col + len(p.tok[p.idx].symbol) - 1
proc getColumns(p: var TRstParser, cols: var TIntSeq) =
proc getColumns(p: var RstParser, cols: var IntSeq) =
var L = 0
while true:
inc(L)
@ -1133,15 +1142,15 @@ proc getColumns(p: var TRstParser, cols: var TIntSeq) =
# last column has no limit:
cols[L - 1] = 32000
proc parseDoc(p: var TRstParser): PRstNode {.gcsafe.}
proc parseDoc(p: var RstParser): PRstNode {.gcsafe.}
proc parseSimpleTable(p: var TRstParser): PRstNode =
proc parseSimpleTable(p: var RstParser): PRstNode =
var
cols: TIntSeq
cols: IntSeq
row: seq[string]
i, last, line: int
c: char
q: TRstParser
q: RstParser
a, b: PRstNode
result = newRstNode(rnTable)
cols = @[]
@ -1188,13 +1197,13 @@ proc parseSimpleTable(p: var TRstParser): PRstNode =
add(a, b)
add(result, a)
proc parseTransition(p: var TRstParser): PRstNode =
proc parseTransition(p: var RstParser): PRstNode =
result = newRstNode(rnTransition)
inc(p.idx)
if p.tok[p.idx].kind == tkIndent: inc(p.idx)
if p.tok[p.idx].kind == tkIndent: inc(p.idx)
proc parseOverline(p: var TRstParser): PRstNode =
proc parseOverline(p: var RstParser): PRstNode =
var c = p.tok[p.idx].symbol[0]
inc(p.idx, 2)
result = newRstNode(rnOverline)
@ -1213,7 +1222,7 @@ proc parseOverline(p: var TRstParser): PRstNode =
inc(p.idx) # XXX: check?
if p.tok[p.idx].kind == tkIndent: inc(p.idx)
proc parseBulletList(p: var TRstParser): PRstNode =
proc parseBulletList(p: var RstParser): PRstNode =
result = nil
if p.tok[p.idx + 1].kind == tkWhite:
var bullet = p.tok[p.idx].symbol
@ -1233,7 +1242,7 @@ proc parseBulletList(p: var TRstParser): PRstNode =
break
popInd(p)
proc parseOptionList(p: var TRstParser): PRstNode =
proc parseOptionList(p: var RstParser): PRstNode =
result = newRstNode(rnOptionList)
while true:
if isOptionList(p):
@ -1262,7 +1271,7 @@ proc parseOptionList(p: var TRstParser): PRstNode =
else:
break
proc parseDefinitionList(p: var TRstParser): PRstNode =
proc parseDefinitionList(p: var RstParser): PRstNode =
result = nil
var j = tokenAfterNewline(p) - 1
if (j >= 1) and (p.tok[j].kind == tkIndent) and
@ -1298,7 +1307,7 @@ proc parseDefinitionList(p: var TRstParser): PRstNode =
break
if len(result) == 0: result = nil
proc parseEnumList(p: var TRstParser): PRstNode =
proc parseEnumList(p: var RstParser): PRstNode =
const
wildcards: array[0..2, string] = ["(e) ", "e) ", "e. "]
wildpos: array[0..2, int] = [1, 0, 0]
@ -1328,11 +1337,11 @@ proc parseEnumList(p: var TRstParser): PRstNode =
dec(p.idx, wildpos[w] + 3)
result = nil
proc sonKind(father: PRstNode, i: int): TRstNodeKind =
proc sonKind(father: PRstNode, i: int): RstNodeKind =
result = rnLeaf
if i < len(father): result = father.sons[i].kind
proc parseSection(p: var TRstParser, result: PRstNode) =
proc parseSection(p: var RstParser, result: PRstNode) =
while true:
var leave = false
assert(p.idx >= 0)
@ -1380,16 +1389,16 @@ proc parseSection(p: var TRstParser, result: PRstNode) =
if sonKind(result, 0) == rnParagraph and sonKind(result, 1) != rnParagraph:
result.sons[0].kind = rnInner
proc parseSectionWrapper(p: var TRstParser): PRstNode =
proc parseSectionWrapper(p: var RstParser): PRstNode =
result = newRstNode(rnInner)
parseSection(p, result)
while (result.kind == rnInner) and (len(result) == 1):
result = result.sons[0]
proc `$`(t: TToken): string =
proc `$`(t: Token): string =
result = $t.kind & ' ' & (if isNil(t.symbol): "NIL" else: t.symbol)
proc parseDoc(p: var TRstParser): PRstNode =
proc parseDoc(p: var RstParser): PRstNode =
result = parseSectionWrapper(p)
if p.tok[p.idx].kind != tkEof:
when false:
@ -1403,12 +1412,14 @@ proc parseDoc(p: var TRstParser): PRstNode =
rstMessage(p, meGeneralParseError)
type
TDirFlag = enum
DirFlag = enum
hasArg, hasOptions, argIsFile, argIsWord
TDirFlags = set[TDirFlag]
TSectionParser = proc (p: var TRstParser): PRstNode {.nimcall.}
DirFlags = set[DirFlag]
SectionParser = proc (p: var RstParser): PRstNode {.nimcall.}
{.deprecated: [TDirFlag: DirFlag, TDirFlags: DirFlags,
TSectionParser: SectionParser].}
proc parseDirective(p: var TRstParser, flags: TDirFlags): PRstNode =
proc parseDirective(p: var RstParser, flags: DirFlags): PRstNode =
## Parses arguments and options for a directive block.
##
## A directive block will always have three sons: the arguments for the
@ -1446,11 +1457,11 @@ proc parseDirective(p: var TRstParser, flags: TDirFlags): PRstNode =
options = parseFields(p)
add(result, options)
proc indFollows(p: TRstParser): bool =
proc indFollows(p: RstParser): bool =
result = p.tok[p.idx].kind == tkIndent and p.tok[p.idx].ival > currInd(p)
proc parseDirective(p: var TRstParser, flags: TDirFlags,
contentParser: TSectionParser): PRstNode =
proc parseDirective(p: var RstParser, flags: DirFlags,
contentParser: SectionParser): PRstNode =
## Returns a generic rnDirective tree.
##
## The children are rnDirArg, rnFieldList and rnLineBlock. Any might be nil.
@ -1463,13 +1474,13 @@ proc parseDirective(p: var TRstParser, flags: TDirFlags,
else:
add(result, nil)
proc parseDirBody(p: var TRstParser, contentParser: TSectionParser): PRstNode =
proc parseDirBody(p: var RstParser, contentParser: SectionParser): PRstNode =
if indFollows(p):
pushInd(p, p.tok[p.idx].ival)
result = contentParser(p)
popInd(p)
proc dirInclude(p: var TRstParser): PRstNode =
proc dirInclude(p: var RstParser): PRstNode =
#
#The following options are recognized:
#
@ -1498,7 +1509,7 @@ proc dirInclude(p: var TRstParser): PRstNode =
result = newRstNode(rnLiteralBlock)
add(result, newRstNode(rnLeaf, readFile(path)))
else:
var q: TRstParser
var q: RstParser
initParser(q, p.s)
q.filename = filename
q.col += getTokens(readFile(path), false, q.tok)
@ -1507,7 +1518,7 @@ proc dirInclude(p: var TRstParser): PRstNode =
# InternalError("Too many binary zeros in include file")
result = parseDoc(q)
proc dirCodeBlock(p: var TRstParser, nimrodExtension = false): PRstNode =
proc dirCodeBlock(p: var RstParser, nimrodExtension = false): PRstNode =
## Parses a code block.
##
## Code blocks are rnDirective trees with a `kind` of rnCodeBlock. See the
@ -1548,35 +1559,35 @@ proc dirCodeBlock(p: var TRstParser, nimrodExtension = false): PRstNode =
result.kind = rnCodeBlock
proc dirContainer(p: var TRstParser): PRstNode =
proc dirContainer(p: var RstParser): PRstNode =
result = parseDirective(p, {hasArg}, parseSectionWrapper)
assert(result.kind == rnDirective)
assert(len(result) == 3)
result.kind = rnContainer
proc dirImage(p: var TRstParser): PRstNode =
proc dirImage(p: var RstParser): PRstNode =
result = parseDirective(p, {hasOptions, hasArg, argIsFile}, nil)
result.kind = rnImage
proc dirFigure(p: var TRstParser): PRstNode =
proc dirFigure(p: var RstParser): PRstNode =
result = parseDirective(p, {hasOptions, hasArg, argIsFile},
parseSectionWrapper)
result.kind = rnFigure
proc dirTitle(p: var TRstParser): PRstNode =
proc dirTitle(p: var RstParser): PRstNode =
result = parseDirective(p, {hasArg}, nil)
result.kind = rnTitle
proc dirContents(p: var TRstParser): PRstNode =
proc dirContents(p: var RstParser): PRstNode =
result = parseDirective(p, {hasArg}, nil)
result.kind = rnContents
proc dirIndex(p: var TRstParser): PRstNode =
proc dirIndex(p: var RstParser): PRstNode =
result = parseDirective(p, {}, parseSectionWrapper)
result.kind = rnIndex
proc dirRawAux(p: var TRstParser, result: var PRstNode, kind: TRstNodeKind,
contentParser: TSectionParser) =
proc dirRawAux(p: var RstParser, result: var PRstNode, kind: RstNodeKind,
contentParser: SectionParser) =
var filename = getFieldValue(result, "file")
if filename.len > 0:
var path = p.s.findFile(filename)
@ -1590,7 +1601,7 @@ proc dirRawAux(p: var TRstParser, result: var PRstNode, kind: TRstNodeKind,
result.kind = kind
add(result, parseDirBody(p, contentParser))
proc dirRaw(p: var TRstParser): PRstNode =
proc dirRaw(p: var RstParser): PRstNode =
#
#The following options are recognized:
#
@ -1610,7 +1621,7 @@ proc dirRaw(p: var TRstParser): PRstNode =
else:
dirRawAux(p, result, rnRaw, parseSectionWrapper)
proc parseDotDot(p: var TRstParser): PRstNode =
proc parseDotDot(p: var RstParser): PRstNode =
result = nil
var col = p.tok[p.idx].col
inc(p.idx)
@ -1667,7 +1678,7 @@ proc parseDotDot(p: var TRstParser): PRstNode =
else:
result = parseComment(p)
proc resolveSubs(p: var TRstParser, n: PRstNode): PRstNode =
proc resolveSubs(p: var RstParser, n: PRstNode): PRstNode =
result = n
if n == nil: return
case n.kind
@ -1696,10 +1707,10 @@ proc resolveSubs(p: var TRstParser, n: PRstNode): PRstNode =
proc rstParse*(text, filename: string,
line, column: int, hasToc: var bool,
options: TRstParseOptions,
findFile: TFindFileHandler = nil,
msgHandler: TMsgHandler = nil): PRstNode =
var p: TRstParser
options: RstParseOptions,
findFile: FindFileHandler = nil,
msgHandler: MsgHandler = nil): PRstNode =
var p: RstParser
initParser(p, newSharedState(options, findFile, msgHandler))
p.filename = filename
p.line = line

View file

@ -12,7 +12,7 @@
import strutils, json
type
TRstNodeKind* = enum ## the possible node kinds of an PRstNode
RstNodeKind* = enum ## the possible node kinds of an PRstNode
rnInner, # an inner node or a root
rnHeadline, # a headline
rnOverline, # an over- and underlined headline
@ -62,24 +62,26 @@ type
# leaf val
PRstNode* = ref TRstNode ## an RST node
TRstNodeSeq* = seq[PRstNode]
TRstNode* {.acyclic, final.} = object ## an RST node's description
kind*: TRstNodeKind ## the node's kind
PRstNode* = ref RstNode ## an RST node
RstNodeSeq* = seq[PRstNode]
RstNode* {.acyclic, final.} = object ## an RST node's description
kind*: RstNodeKind ## the node's kind
text*: string ## valid for leafs in the AST; and the title of
## the document or the section
level*: int ## valid for some node kinds
sons*: TRstNodeSeq ## the node's sons
sons*: RstNodeSeq ## the node's sons
{.deprecated: [TRstNodeKind: RstNodeKind, TRstNodeSeq: RstNodeSeq,
TRstNode: RstNode].}
proc len*(n: PRstNode): int =
result = len(n.sons)
proc newRstNode*(kind: TRstNodeKind): PRstNode =
proc newRstNode*(kind: RstNodeKind): PRstNode =
new(result)
result.sons = @[]
result.kind = kind
proc newRstNode*(kind: TRstNodeKind, s: string): PRstNode =
proc newRstNode*(kind: RstNodeKind, s: string): PRstNode =
result = newRstNode(kind)
result.text = s
@ -94,18 +96,19 @@ proc addIfNotNil*(father, son: PRstNode) =
type
TRenderContext {.pure.} = object
RenderContext {.pure.} = object
indent: int
verbatim: int
{.deprecated: [TRenderContext: RenderContext].}
proc renderRstToRst(d: var TRenderContext, n: PRstNode,
proc renderRstToRst(d: var RenderContext, n: PRstNode,
result: var string) {.gcsafe.}
proc renderRstSons(d: var TRenderContext, n: PRstNode, result: var string) =
proc renderRstSons(d: var RenderContext, n: PRstNode, result: var string) =
for i in countup(0, len(n) - 1):
renderRstToRst(d, n.sons[i], result)
proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
proc renderRstToRst(d: var RenderContext, n: PRstNode, result: var string) =
# this is needed for the index generation; it may also be useful for
# debugging, but most code is already debugged...
const
@ -284,7 +287,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
proc renderRstToRst*(n: PRstNode, result: var string) =
## renders `n` into its string representation and appends to `result`.
var d: TRenderContext
var d: RenderContext
renderRstToRst(d, n, result)
proc renderRstToJsonNode(node: PRstNode): JsonNode =

View file

@ -18,7 +18,7 @@
## document you provide yourself, so it won't contain the usual ``<header>`` or
## ``<body>`` parts.
##
## You can also create a ``TRstGenerator`` structure and populate it with the
## You can also create a ``RstGenerator`` structure and populate it with the
## other lower level methods to finally build complete documents. This requires
## many options and tweaking, but you are not limited to snippets and can
## generate `LaTeX documents <https://en.wikipedia.org/wiki/LaTeX>`_ too.
@ -31,29 +31,29 @@ const
IndexExt* = ".idx"
type
TOutputTarget* = enum ## which document type to generate
OutputTarget* = enum ## which document type to generate
outHtml, # output is HTML
outLatex # output is Latex
TTocEntry = object
TocEntry = object
n*: PRstNode
refname*, header*: string
TMetaEnum* = enum
MetaEnum* = enum
metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion
TRstGenerator* = object of RootObj
target*: TOutputTarget
RstGenerator* = object of RootObj
target*: OutputTarget
config*: StringTableRef
splitAfter*: int # split too long entries in the TOC
tocPart*: seq[TTocEntry]
tocPart*: seq[TocEntry]
hasToc*: bool
theIndex: string # Contents of the index file to be dumped at the end.
options*: TRstParseOptions
findFile*: TFindFileHandler
msgHandler*: TMsgHandler
options*: RstParseOptions
findFile*: FindFileHandler
msgHandler*: MsgHandler
filename*: string
meta*: array[TMetaEnum, string]
meta*: array[MetaEnum, string]
currentSection: string ## \
## Stores the empty string or the last headline/overline found in the rst
## document, so it can be used as a prettier name for term index generation.
@ -61,14 +61,15 @@ type
## Keeps count of same text index terms to generate different identifiers
## for hyperlinks. See renderIndexTerm proc for details.
PDoc = var TRstGenerator ## Alias to type less.
PDoc = var RstGenerator ## Alias to type less.
CodeBlockParams = object ## Stores code block params.
numberLines: bool ## True if the renderer has to show line numbers.
startLine: int ## The starting line of the code block, by default 1.
langStr: string ## Input string used to specify the language.
lang: TSourceLanguage ## Type of highlighting, by default none.
lang: SourceLanguage ## Type of highlighting, by default none.
{.deprecated: [TRstGenerator: RstGenerator, TTocEntry: TocEntry,
TOutputTarget: OutputTarget, TMetaEnum: MetaEnum].}
proc init(p: var CodeBlockParams) =
## Default initialisation of CodeBlockParams to sane values.
@ -76,14 +77,14 @@ proc init(p: var CodeBlockParams) =
p.lang = langNone
p.langStr = ""
proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget,
proc initRstGenerator*(g: var RstGenerator, target: OutputTarget,
config: StringTableRef, filename: string,
options: TRstParseOptions,
findFile: TFindFileHandler=nil,
msgHandler: TMsgHandler=nil) =
## Initializes a ``TRstGenerator``.
options: RstParseOptions,
findFile: FindFileHandler=nil,
msgHandler: MsgHandler=nil) =
## Initializes a ``RstGenerator``.
##
## You need to call this before using a ``TRstGenerator`` with any other
## You need to call this before using a ``RstGenerator`` with any other
## procs in this module. Pass a non ``nil`` ``StringTableRef`` value as
## `config` with parameters used by the HTML output generator. If you don't
## know what to use, pass the results of the `defaultConfig()
@ -96,7 +97,7 @@ proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget,
## filename``. This default title can be overriden by the embedded rst, but
## it helps to prettify the generated index if no title is found.
##
## The ``TRstParseOptions``, ``TFindFileHandler`` and ``TMsgHandler`` types
## The ``RstParseOptions``, ``FindFileHandler`` and ``MsgHandler`` types
## are defined in the the `packages/docutils/rst module <rst.html>`_.
## ``options`` selects the behaviour of the rst parser.
##
@ -120,7 +121,7 @@ proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget,
##
## import packages/docutils/rstgen
##
## var gen: TRstGenerator
## var gen: RstGenerator
## gen.initRstGenerator(outHtml, defaultConfig(), "filename", {})
g.config = config
g.target = target
@ -141,7 +142,7 @@ proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget,
if s != "": g.splitAfter = parseInt(s)
for i in low(g.meta)..high(g.meta): g.meta[i] = ""
proc writeIndexFile*(g: var TRstGenerator, outfile: string) =
proc writeIndexFile*(g: var RstGenerator, outfile: string) =
## Writes the current index buffer to the specified output file.
##
## You previously need to add entries to the index with the `setIndexTerm()
@ -183,7 +184,7 @@ proc addTexChar(dest: var string, c: char) =
var splitter*: string = "<wbr />"
proc escChar*(target: TOutputTarget, dest: var string, c: char) {.inline.} =
proc escChar*(target: OutputTarget, dest: var string, c: char) {.inline.} =
case target
of outHtml: addXmlChar(dest, c)
of outLatex: addTexChar(dest, c)
@ -200,7 +201,7 @@ proc nextSplitPoint*(s: string, start: int): int =
inc(result)
dec(result) # last valid index
proc esc*(target: TOutputTarget, s: string, splitAfter = -1): string =
proc esc*(target: OutputTarget, s: string, splitAfter = -1): string =
result = ""
if splitAfter >= 0:
var partLen = 0
@ -217,16 +218,16 @@ proc esc*(target: TOutputTarget, s: string, splitAfter = -1): string =
for i in countup(0, len(s) - 1): escChar(target, result, s[i])
proc disp(target: TOutputTarget, xml, tex: string): string =
proc disp(target: OutputTarget, xml, tex: string): string =
if target != outLatex: result = xml
else: result = tex
proc dispF(target: TOutputTarget, xml, tex: string,
proc dispF(target: OutputTarget, xml, tex: string,
args: varargs[string]): string =
if target != outLatex: result = xml % args
else: result = tex % args
proc dispA(target: TOutputTarget, dest: var string,
proc dispA(target: OutputTarget, dest: var string,
xml, tex: string, args: varargs[string]) =
if target != outLatex: addf(dest, xml, args)
else: addf(dest, tex, args)
@ -234,10 +235,10 @@ proc dispA(target: TOutputTarget, dest: var string,
proc `or`(x, y: string): string {.inline.} =
result = if x.isNil: y else: x
proc renderRstToOut*(d: var TRstGenerator, n: PRstNode, result: var string)
proc renderRstToOut*(d: var RstGenerator, n: PRstNode, result: var string)
## Writes into ``result`` the rst ast ``n`` using the ``d`` configuration.
##
## Before using this proc you need to initialise a ``TRstGenerator`` with
## Before using this proc you need to initialise a ``RstGenerator`` with
## ``initRstGenerator`` and parse a rst file with ``rstParse`` from the
## `packages/docutils/rst module <rst.html>`_. Example:
##
@ -277,7 +278,7 @@ proc unquoteIndexColumn(text: string): string =
## Returns the unquoted version generated by ``quoteIndexColumn``.
result = text.replace("\\t", "\t").replace("\\n", "\n").replace("\\\\", "\\")
proc setIndexTerm*(d: var TRstGenerator, id, term: string,
proc setIndexTerm*(d: var RstGenerator, id, term: string,
linkTitle, linkDesc = "") =
## Adds a `term` to the index using the specified hyperlink identifier.
##
@ -351,30 +352,30 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) =
[id, term])
type
TIndexEntry = object
IndexEntry = object
keyword: string
link: string
linkTitle: string ## If not nil, contains a prettier text for the href
linkDesc: string ## If not nil, the title attribute of the final href
TIndexedDocs = Table[TIndexEntry, seq[TIndexEntry]] ## \
IndexedDocs = Table[IndexEntry, seq[IndexEntry]] ## \
## Contains the index sequences for doc types.
##
## The key is a *fake* TIndexEntry which will contain the title of the
## The key is a *fake* IndexEntry which will contain the title of the
## document in the `keyword` field and `link` will contain the html
## filename for the document. `linkTitle` and `linkDesc` will be nil.
##
## The value indexed by this TIndexEntry is a sequence with the real index
## The value indexed by this IndexEntry is a sequence with the real index
## entries found in the ``.idx`` file.
{.deprecated: [TIndexEntry: IndexEntry, TIndexedDocs: IndexedDocs].}
proc cmp(a, b: TIndexEntry): int =
## Sorts two ``TIndexEntry`` first by `keyword` field, then by `link`.
proc cmp(a, b: IndexEntry): int =
## Sorts two ``IndexEntry`` first by `keyword` field, then by `link`.
result = cmpIgnoreStyle(a.keyword, b.keyword)
if result == 0:
result = cmpIgnoreStyle(a.link, b.link)
proc hash(x: TIndexEntry): THash =
proc hash(x: IndexEntry): Hash =
## Returns the hash for the combined fields of the type.
##
## The hash is computed as the chained hash of the individual string hashes.
@ -385,7 +386,7 @@ proc hash(x: TIndexEntry): THash =
result = result !& (x.linkDesc or "").hash
result = !$result
proc `<-`(a: var TIndexEntry, b: TIndexEntry) =
proc `<-`(a: var IndexEntry, b: IndexEntry) =
shallowCopy a.keyword, b.keyword
shallowCopy a.link, b.link
if b.linkTitle.isNil: a.linkTitle = nil
@ -393,7 +394,7 @@ proc `<-`(a: var TIndexEntry, b: TIndexEntry) =
if b.linkDesc.isNil: a.linkDesc = nil
else: shallowCopy a.linkDesc, b.linkDesc
proc sortIndex(a: var openArray[TIndexEntry]) =
proc sortIndex(a: var openArray[IndexEntry]) =
# we use shellsort here; fast and simple
let n = len(a)
var h = 1
@ -403,7 +404,7 @@ proc sortIndex(a: var openArray[TIndexEntry]) =
while true:
h = h div 3
for i in countup(h, n - 1):
var v: TIndexEntry
var v: IndexEntry
v <- a[i]
var j = i
while cmp(a[j-h], v) >= 0:
@ -413,7 +414,7 @@ proc sortIndex(a: var openArray[TIndexEntry]) =
a[j] <- v
if h == 1: break
proc generateSymbolIndex(symbols: seq[TIndexEntry]): string =
proc generateSymbolIndex(symbols: seq[IndexEntry]): string =
result = ""
var i = 0
while i < symbols.len:
@ -466,7 +467,7 @@ proc indentToLevel(level: var int, newLevel: int): string =
result = repeat("</ul>", level - newLevel)
level = newLevel
proc generateDocumentationTOC(entries: seq[TIndexEntry]): string =
proc generateDocumentationTOC(entries: seq[IndexEntry]): string =
## Returns the sequence of index entries in an HTML hierarchical list.
result = ""
# Build a list of levels and extracted titles to make processing easier.
@ -507,12 +508,12 @@ proc generateDocumentationTOC(entries: seq[TIndexEntry]): string =
assert(not titleRef.isNil,
"Can't use this proc on an API index, docs always have a title entry")
proc generateDocumentationIndex(docs: TIndexedDocs): string =
proc generateDocumentationIndex(docs: IndexedDocs): string =
## Returns all the documentation TOCs in an HTML hierarchical list.
result = ""
# Sort the titles to generate their toc in alphabetical order.
var titles = toSeq(keys[TIndexEntry, seq[TIndexEntry]](docs))
var titles = toSeq(keys[IndexEntry, seq[IndexEntry]](docs))
sort(titles, cmp)
for title in titles:
@ -520,12 +521,12 @@ proc generateDocumentationIndex(docs: TIndexedDocs): string =
result.add("<ul><li><a href=\"" &
title.link & "\">" & title.keyword & "</a>\n" & tocList & "</ul>\n")
proc generateDocumentationJumps(docs: TIndexedDocs): string =
proc generateDocumentationJumps(docs: IndexedDocs): string =
## Returns a plain list of hyperlinks to documentation TOCs in HTML.
result = "Documents: "
# Sort the titles to generate their toc in alphabetical order.
var titles = toSeq(keys[TIndexEntry, seq[TIndexEntry]](docs))
var titles = toSeq(keys[IndexEntry, seq[IndexEntry]](docs))
sort(titles, cmp)
var chunks: seq[string] = @[]
@ -545,14 +546,14 @@ proc generateModuleJumps(modules: seq[string]): string =
result.add(chunks.join(", ") & ".<br>")
proc readIndexDir(dir: string):
tuple[modules: seq[string], symbols: seq[TIndexEntry], docs: TIndexedDocs] =
## Walks `dir` reading ``.idx`` files converting them in TIndexEntry items.
tuple[modules: seq[string], symbols: seq[IndexEntry], docs: IndexedDocs] =
## Walks `dir` reading ``.idx`` files converting them in IndexEntry items.
##
## Returns the list of found module names, the list of free symbol entries
## and the different documentation indexes. The list of modules is sorted.
## See the documentation of ``mergeIndexes`` for details.
result.modules = @[]
result.docs = initTable[TIndexEntry, seq[TIndexEntry]](32)
result.docs = initTable[IndexEntry, seq[IndexEntry]](32)
newSeq(result.symbols, 15_000)
setLen(result.symbols, 0)
var L = 0
@ -560,8 +561,8 @@ proc readIndexDir(dir: string):
for kind, path in walkDir(dir):
if kind == pcFile and path.endsWith(IndexExt):
var
fileEntries: seq[TIndexEntry]
title: TIndexEntry
fileEntries: seq[IndexEntry]
title: IndexEntry
F = 0
newSeq(fileEntries, 500)
setLen(fileEntries, 0)
@ -662,7 +663,7 @@ proc mergeIndexes*(dir: string): string =
proc stripTOCHTML(s: string): string =
## Ugly quick hack to remove HTML tags from TOC titles.
##
## A TTocEntry.header field already contains rendered HTML tags. Instead of
## A TocEntry.header field already contains rendered HTML tags. Instead of
## implementing a proper version of renderRstToOut() which recursively
## renders an rst tree to plain text, we simply remove text found between
## angled brackets. Given the limited possibilities of rst inside TOC titles
@ -728,12 +729,12 @@ proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
rstnodeToRefname(n), tmp, $chr(n.level - 1 + ord('A'))])
proc renderTocEntry(d: PDoc, e: TTocEntry, result: var string) =
proc renderTocEntry(d: PDoc, e: TocEntry, result: var string) =
dispA(d.target, result,
"<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>\n",
"\\item\\label{$1_toc} $2\\ref{$1}\n", [e.refname, e.header])
proc renderTocEntries*(d: var TRstGenerator, j: var int, lvl: int,
proc renderTocEntries*(d: var RstGenerator, j: var int, lvl: int,
result: var string) =
var tmp = ""
while j <= high(d.tocPart):
@ -878,7 +879,7 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
d.msgHandler(d.filename, 1, 0, mwUnsupportedLanguage, params.langStr)
for letter in m.text: escChar(d.target, result, letter)
else:
var g: TGeneralTokenizer
var g: GeneralTokenizer
initGeneralTokenizer(g, m.text)
while true:
getNextToken(g, params.lang)
@ -1214,7 +1215,7 @@ $content
# ---------- forum ---------------------------------------------------------
proc rstToHtml*(s: string, options: TRstParseOptions,
proc rstToHtml*(s: string, options: RstParseOptions,
config: StringTableRef): string =
## Converts an input rst string into embeddable HTML.
##
@ -1233,7 +1234,7 @@ proc rstToHtml*(s: string, options: TRstParseOptions,
## # --> <em>Hello</em> <strong>world</strong>!
##
## If you need to allow the rst ``include`` directive or tweak the generated
## output you have to create your own ``TRstGenerator`` with
## output you have to create your own ``RstGenerator`` with
## ``initRstGenerator`` and related procs.
proc myFindFile(filename: string): string =
@ -1241,7 +1242,7 @@ proc rstToHtml*(s: string, options: TRstParseOptions,
result = ""
const filen = "input"
var d: TRstGenerator
var d: RstGenerator
initRstGenerator(d, outHtml, config, filen, options, myFindFile,
rst.defaultMsgHandler)
var dummyHasToc = false

View file

@ -12,14 +12,15 @@
# Get the platform-dependent flags.
# Structure describing an inotify event.
type
Tinotify_event*{.pure, final, importc: "struct inotify_event",
InotifyEvent*{.pure, final, importc: "struct inotify_event",
header: "<sys/inotify.h>".} = object
wd*{.importc: "wd".}: cint # Watch descriptor.
mask*{.importc: "mask".}: uint32 # Watch mask.
cookie*{.importc: "cookie".}: uint32 # Cookie to synchronize two events.
len*{.importc: "len".}: uint32 # Length (including NULs) of name.
name*{.importc: "name".}: char # Name.
{.deprecated: [Tinotify_event: InotifyEvent].}
# Supported events suitable for MASK parameter of INOTIFY_ADD_WATCH.
const
IN_ACCESS* = 0x00000001 # File was accessed.
@ -69,4 +70,4 @@ proc inotify_add_watch*(fd: cint; name: cstring; mask: uint32): cint{.
cdecl, importc: "inotify_add_watch", header: "<sys/inotify.h>".}
# Remove the watch specified by WD from the inotify instance FD.
proc inotify_rm_watch*(fd: cint; wd: cint): cint{.cdecl,
importc: "inotify_rm_watch", header: "<sys/inotify.h>".}
importc: "inotify_rm_watch", header: "<sys/inotify.h>".}

View file

@ -24,5 +24,5 @@ const
# fn should be of type proc (a2: pointer): void {.cdecl.}
proc clone*(fn: pointer; child_stack: pointer; flags: cint;
arg: pointer; ptid: ptr TPid; tls: pointer;
ctid: ptr TPid): cint {.importc, header: "<sched.h>".}
arg: pointer; ptid: ptr Pid; tls: pointer;
ctid: ptr Pid): cint {.importc, header: "<sched.h>".}

File diff suppressed because it is too large Load diff

View file

@ -12,17 +12,18 @@ import posix
type
Speed* = cuint
Tcflag* = cuint
Cflag* = cuint
{.deprecated: [Tcflag: Cflag].}
const
NCCS* = 32
type
Termios* {.importc: "struct termios", header: "<termios.h>".} = object
c_iflag*: Tcflag # input mode flags
c_oflag*: Tcflag # output mode flags
c_cflag*: Tcflag # control mode flags
c_lflag*: Tcflag # local mode flags
c_iflag*: Cflag # input mode flags
c_oflag*: Cflag # output mode flags
c_cflag*: Cflag # control mode flags
c_lflag*: Cflag # local mode flags
c_line*: cuchar # line discipline
c_cc*: array[NCCS, cuchar] # control characters
@ -258,4 +259,4 @@ proc tcFlow*(fd: cint; action: cint): cint {.importc: "tcflow",
header: "<termios.h>".}
# Get process group ID for session leader for controlling terminal FD.
proc tcGetSid*(fd: cint): TPid {.importc: "tcgetsid", header: "<termios.h>".}
proc tcGetSid*(fd: cint): Pid {.importc: "tcgetsid", header: "<termios.h>".}

View file

@ -16,7 +16,7 @@
## .. code-block:: nim
##
## var
## a: TActorPool[int, void]
## a: ActorPool[int, void]
## createActorPool(a)
## for i in 0 .. < 300:
## a.spawn(i, proc (x: int) {.thread.} = echo x)
@ -30,75 +30,76 @@
from os import sleep
type
TTask*[TIn, TOut] = object{.pure, final.} ## a task
when TOut isnot void:
receiver*: ptr TChannel[TOut] ## the receiver channel of the response
action*: proc (x: TIn): TOut {.thread.} ## action to execute;
Task*[In, Out] = object{.pure, final.} ## a task
when Out isnot void:
receiver*: ptr Channel[Out] ## the receiver channel of the response
action*: proc (x: In): Out {.thread.} ## action to execute;
## sometimes useful
shutDown*: bool ## set to tell an actor to shut-down
data*: TIn ## the data to process
data*: In ## the data to process
TActor[TIn, TOut] = object{.pure, final.}
i: TChannel[TTask[TIn, TOut]]
t: TThread[ptr TActor[TIn, TOut]]
Actor[In, Out] = object{.pure, final.}
i: Channel[Task[In, Out]]
t: TThread[ptr Actor[In, Out]]
PActor*[TIn, TOut] = ptr TActor[TIn, TOut] ## an actor
proc spawn*[TIn, TOut](action: proc(
self: PActor[TIn, TOut]){.thread.}): PActor[TIn, TOut] =
PActor*[In, Out] = ptr Actor[In, Out] ## an actor
{.deprecated: [TTask: Task, TActor: Actor].}
proc spawn*[In, Out](action: proc(
self: PActor[In, Out]){.thread.}): PActor[In, Out] =
## creates an actor; that is a thread with an inbox. The caller MUST call
## ``join`` because that also frees the actor's associated resources.
result = cast[PActor[TIn, TOut]](allocShared0(sizeof(result[])))
result = cast[PActor[In, Out]](allocShared0(sizeof(result[])))
open(result.i)
createThread(result.t, action, result)
proc inbox*[TIn, TOut](self: PActor[TIn, TOut]): ptr TChannel[TIn] =
proc inbox*[In, Out](self: PActor[In, Out]): ptr Channel[In] =
## gets a pointer to the associated inbox of the actor `self`.
result = addr(self.i)
proc running*[TIn, TOut](a: PActor[TIn, TOut]): bool =
proc running*[In, Out](a: PActor[In, Out]): bool =
## returns true if the actor `a` is running.
result = running(a.t)
proc ready*[TIn, TOut](a: PActor[TIn, TOut]): bool =
proc ready*[In, Out](a: PActor[In, Out]): bool =
## returns true if the actor `a` is ready to process new messages.
result = ready(a.i)
proc join*[TIn, TOut](a: PActor[TIn, TOut]) =
proc join*[In, Out](a: PActor[In, Out]) =
## joins an actor.
joinThread(a.t)
close(a.i)
deallocShared(a)
proc recv*[TIn, TOut](a: PActor[TIn, TOut]): TTask[TIn, TOut] =
proc recv*[In, Out](a: PActor[In, Out]): Task[In, Out] =
## receives a task from `a`'s inbox.
result = recv(a.i)
proc send*[TIn, TOut, X, Y](receiver: PActor[TIn, TOut], msg: TIn,
proc send*[In, Out, X, Y](receiver: PActor[In, Out], msg: In,
sender: PActor[X, Y]) =
## sends a message to `a`'s inbox.
var t: TTask[TIn, TOut]
var t: Task[In, Out]
t.receiver = addr(sender.i)
shallowCopy(t.data, msg)
send(receiver.i, t)
proc send*[TIn, TOut](receiver: PActor[TIn, TOut], msg: TIn,
sender: ptr TChannel[TOut] = nil) =
proc send*[In, Out](receiver: PActor[In, Out], msg: In,
sender: ptr Channel[Out] = nil) =
## sends a message to `receiver`'s inbox.
var t: TTask[TIn, TOut]
var t: Task[In, Out]
t.receiver = sender
shallowCopy(t.data, msg)
send(receiver.i, t)
proc sendShutdown*[TIn, TOut](receiver: PActor[TIn, TOut]) =
proc sendShutdown*[In, Out](receiver: PActor[In, Out]) =
## send a shutdown message to `receiver`.
var t: TTask[TIn, TOut]
var t: Task[In, Out]
t.shutdown = true
send(receiver.i, t)
proc reply*[TIn, TOut](t: TTask[TIn, TOut], m: TOut) =
proc reply*[In, Out](t: Task[In, Out], m: Out) =
## sends a message to io's output message box.
when TOut is void:
when Out is void:
{.error: "you cannot reply to a void outbox".}
assert t.receiver != nil
send(t.receiver[], m)
@ -107,34 +108,35 @@ proc reply*[TIn, TOut](t: TTask[TIn, TOut], m: TOut) =
# ----------------- actor pools ----------------------------------------------
type
TActorPool*[TIn, TOut] = object{.pure, final.} ## an actor pool
actors: seq[PActor[TIn, TOut]]
when TOut isnot void:
outputs: TChannel[TOut]
ActorPool*[In, Out] = object{.pure, final.} ## an actor pool
actors: seq[PActor[In, Out]]
when Out isnot void:
outputs: Channel[Out]
{.deprecated: [TActorPool: ActorPool].}
proc `^`*[T](f: ptr TChannel[T]): T =
proc `^`*[T](f: ptr Channel[T]): T =
## alias for 'recv'.
result = recv(f[])
proc poolWorker[TIn, TOut](self: PActor[TIn, TOut]) {.thread.} =
proc poolWorker[In, Out](self: PActor[In, Out]) {.thread.} =
while true:
var m = self.recv
if m.shutDown: break
when TOut is void:
when Out is void:
m.action(m.data)
else:
send(m.receiver[], m.action(m.data))
#self.reply()
proc createActorPool*[TIn, TOut](a: var TActorPool[TIn, TOut], poolSize = 4) =
proc createActorPool*[In, Out](a: var ActorPool[In, Out], poolSize = 4) =
## creates an actor pool.
newSeq(a.actors, poolSize)
when TOut isnot void:
when Out isnot void:
open(a.outputs)
for i in 0 .. < a.actors.len:
a.actors[i] = spawn(poolWorker[TIn, TOut])
a.actors[i] = spawn(poolWorker[In, Out])
proc sync*[TIn, TOut](a: var TActorPool[TIn, TOut], polling=50) =
proc sync*[In, Out](a: var ActorPool[In, Out], polling=50) =
## waits for every actor of `a` to finish with its work. Currently this is
## implemented as polling every `polling` ms and has a slight chance
## of failing since we check for every actor to be in `ready` state and not
@ -157,18 +159,18 @@ proc sync*[TIn, TOut](a: var TActorPool[TIn, TOut], polling=50) =
if allReadyCount > 1: break
sleep(polling)
proc terminate*[TIn, TOut](a: var TActorPool[TIn, TOut]) =
proc terminate*[In, Out](a: var ActorPool[In, Out]) =
## terminates each actor in the actor pool `a` and frees the
## resources attached to `a`.
var t: TTask[TIn, TOut]
var t: Task[In, Out]
t.shutdown = true
for i in 0.. <a.actors.len: send(a.actors[i].i, t)
for i in 0.. <a.actors.len: join(a.actors[i])
when TOut isnot void:
when Out isnot void:
close(a.outputs)
a.actors = nil
proc join*[TIn, TOut](a: var TActorPool[TIn, TOut]) =
proc join*[In, Out](a: var ActorPool[In, Out]) =
## short-cut for `sync` and then `terminate`.
sync(a)
terminate(a)
@ -202,28 +204,28 @@ template schedule =
else:
raise newException(DeadThreadError, "cannot send message; thread died")
proc spawn*[TIn, TOut](p: var TActorPool[TIn, TOut], input: TIn,
action: proc (input: TIn): TOut {.thread.}
): ptr TChannel[TOut] =
proc spawn*[In, Out](p: var ActorPool[In, Out], input: In,
action: proc (input: In): Out {.thread.}
): ptr Channel[Out] =
## uses the actor pool to run ``action(input)`` concurrently.
## `spawn` is guaranteed to not block.
var t: TTask[TIn, TOut]
var t: Task[In, Out]
setupTask()
result = addr(p.outputs)
t.receiver = result
schedule()
proc spawn*[TIn](p: var TActorPool[TIn, void], input: TIn,
action: proc (input: TIn) {.thread.}) =
proc spawn*[In](p: var ActorPool[In, void], input: In,
action: proc (input: In) {.thread.}) =
## uses the actor pool to run ``action(input)`` concurrently.
## `spawn` is guaranteed to not block.
var t: TTask[TIn, void]
var t: Task[In, void]
setupTask()
schedule()
when not defined(testing) and isMainModule:
var
a: TActorPool[int, void]
a: ActorPool[int, void]
createActorPool(a)
for i in 0 .. < 300:
a.spawn(i, proc (x: int) {.thread.} = echo x)

View file

@ -99,16 +99,13 @@ proc lowerBound*[T](a: openArray[T], key: T, cmp: proc(x,y: T): int {.closure.})
## arr.insert(4, arr.lowerBound(4))
## `after running the above arr is `[1,2,3,4,5,6,7,8,9]`
result = a.low
var pos = result
var count, step: int
count = a.high - a.low + 1
var count = a.high - a.low + 1
var step, pos: int
while count != 0:
pos = result
step = count div 2
pos += step
pos = result + step
if cmp(a[pos], key) < 0:
pos.inc
result = pos
result = pos + 1
count -= step + 1
else:
count = step
@ -331,3 +328,16 @@ proc prevPermutation*[T](x: var openarray[T]): bool {.discardable.} =
swap x[i-1], x[j]
result = true
when isMainModule:
# Tests for lowerBound
var arr = @[1,2,3,5,6,7,8,9]
assert arr.lowerBound(0) == 0
assert arr.lowerBound(4) == 3
assert arr.lowerBound(5) == 3
assert arr.lowerBound(10) == 8
arr = @[1,5,10]
assert arr.lowerBound(4) == 1
assert arr.lowerBound(5) == 1
assert arr.lowerBound(6) == 2

View file

@ -323,32 +323,34 @@ proc processTimers(p: PDispatcherBase) =
when defined(windows) or defined(nimdoc):
import winlean, sets, hashes
type
TCompletionKey = Dword
CompletionKey = Dword
TCompletionData* = object
fd*: TAsyncFD # TODO: Rename this.
cb*: proc (fd: TAsyncFD, bytesTransferred: Dword,
CompletionData* = object
fd*: AsyncFD # TODO: Rename this.
cb*: proc (fd: AsyncFD, bytesTransferred: Dword,
errcode: OSErrorCode) {.closure,gcsafe.}
PDispatcher* = ref object of PDispatcherBase
ioPort: THandle
handles: HashSet[TAsyncFD]
ioPort: Handle
handles: HashSet[AsyncFD]
TCustomOverlapped = object of TOVERLAPPED
data*: TCompletionData
CustomOverlapped = object of TOVERLAPPED
data*: CompletionData
PCustomOverlapped* = ref TCustomOverlapped
PCustomOverlapped* = ref CustomOverlapped
TAsyncFD* = distinct int
AsyncFD* = distinct int
{.deprecated: [TCompletionKey: CompletionKey, TAsyncFD: AsyncFD,
TCustomOverlapped: CustomOverlapped, TCompletionData: CompletionData].}
proc hash(x: TAsyncFD): THash {.borrow.}
proc `==`*(x: TAsyncFD, y: TAsyncFD): bool {.borrow.}
proc hash(x: AsyncFD): Hash {.borrow.}
proc `==`*(x: AsyncFD, y: AsyncFD): bool {.borrow.}
proc newDispatcher*(): PDispatcher =
## Creates a new Dispatcher instance.
new result
result.ioPort = createIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1)
result.handles = initSet[TAsyncFD]()
result.handles = initSet[AsyncFD]()
result.timers = @[]
var gDisp{.threadvar.}: PDispatcher ## Global dispatcher
@ -357,15 +359,15 @@ when defined(windows) or defined(nimdoc):
if gDisp.isNil: gDisp = newDispatcher()
result = gDisp
proc register*(fd: TAsyncFD) =
proc register*(fd: AsyncFD) =
## Registers ``fd`` with the dispatcher.
let p = getGlobalDispatcher()
if createIoCompletionPort(fd.THandle, p.ioPort,
cast[TCompletionKey](fd), 1) == 0:
if createIoCompletionPort(fd.Handle, p.ioPort,
cast[CompletionKey](fd), 1) == 0:
raiseOSError(osLastError())
p.handles.incl(fd)
proc verifyPresence(fd: TAsyncFD) =
proc verifyPresence(fd: AsyncFD) =
## Ensures that file descriptor has been registered with the dispatcher.
let p = getGlobalDispatcher()
if fd notin p.handles:
@ -394,7 +396,7 @@ when defined(windows) or defined(nimdoc):
# TODO: http://www.serverframework.com/handling-multiple-pending-socket-read-and-write-operations.html
if res:
# This is useful for ensuring the reliability of the overlapped struct.
assert customOverlapped.data.fd == lpCompletionKey.TAsyncFD
assert customOverlapped.data.fd == lpCompletionKey.AsyncFD
customOverlapped.data.cb(customOverlapped.data.fd,
lpNumberOfBytesTransferred, OSErrorCode(-1))
@ -402,7 +404,7 @@ when defined(windows) or defined(nimdoc):
else:
let errCode = osLastError()
if customOverlapped != nil:
assert customOverlapped.data.fd == lpCompletionKey.TAsyncFD
assert customOverlapped.data.fd == lpCompletionKey.AsyncFD
customOverlapped.data.cb(customOverlapped.data.fd,
lpNumberOfBytesTransferred, errCode)
GC_unref(customOverlapped)
@ -480,7 +482,7 @@ when defined(windows) or defined(nimdoc):
dwRemoteAddressLength, LocalSockaddr, LocalSockaddrLength,
RemoteSockaddr, RemoteSockaddrLength)
proc connect*(socket: TAsyncFD, address: string, port: Port,
proc connect*(socket: AsyncFD, address: string, port: Port,
af = AF_INET): Future[void] =
## Connects ``socket`` to server at ``address:port``.
##
@ -506,8 +508,8 @@ when defined(windows) or defined(nimdoc):
# http://blogs.msdn.com/b/oldnewthing/archive/2011/02/02/10123392.aspx
var ol = PCustomOverlapped()
GC_ref(ol)
ol.data = TCompletionData(fd: socket, cb:
proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
ol.data = CompletionData(fd: socket, cb:
proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
if not retFuture.finished:
if errcode == OSErrorCode(-1):
retFuture.complete()
@ -542,7 +544,7 @@ when defined(windows) or defined(nimdoc):
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
return retFuture
proc recv*(socket: TAsyncFD, size: int,
proc recv*(socket: AsyncFD, size: int,
flags = {SocketFlag.SafeDisconn}): Future[string] =
## Reads **up to** ``size`` bytes from ``socket``. Returned future will
## complete once all the data requested is read, a part of the data has been
@ -570,8 +572,8 @@ when defined(windows) or defined(nimdoc):
var flagsio = flags.toOSFlags().Dword
var ol = PCustomOverlapped()
GC_ref(ol)
ol.data = TCompletionData(fd: socket, cb:
proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
ol.data = CompletionData(fd: socket, cb:
proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
if not retFuture.finished:
if errcode == OSErrorCode(-1):
if bytesCount == 0 and dataBuf.buf[0] == '\0':
@ -634,7 +636,7 @@ when defined(windows) or defined(nimdoc):
# free ``ol``.
return retFuture
proc recvInto*(socket: TAsyncFD, buf: cstring, size: int,
proc recvInto*(socket: AsyncFD, buf: cstring, size: int,
flags = {SocketFlag.SafeDisconn}): Future[int] =
## Reads **up to** ``size`` bytes from ``socket`` into ``buf``, which must
## at least be of that size. Returned future will complete once all the
@ -665,8 +667,8 @@ when defined(windows) or defined(nimdoc):
var flagsio = flags.toOSFlags().Dword
var ol = PCustomOverlapped()
GC_ref(ol)
ol.data = TCompletionData(fd: socket, cb:
proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
ol.data = CompletionData(fd: socket, cb:
proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
if not retFuture.finished:
if errcode == OSErrorCode(-1):
if bytesCount == 0 and dataBuf.buf[0] == '\0':
@ -721,7 +723,7 @@ when defined(windows) or defined(nimdoc):
# free ``ol``.
return retFuture
proc send*(socket: TAsyncFD, data: string,
proc send*(socket: AsyncFD, data: string,
flags = {SocketFlag.SafeDisconn}): Future[void] =
## Sends ``data`` to ``socket``. The returned future will complete once all
## data has been sent.
@ -735,8 +737,8 @@ when defined(windows) or defined(nimdoc):
var bytesReceived, lowFlags: Dword
var ol = PCustomOverlapped()
GC_ref(ol)
ol.data = TCompletionData(fd: socket, cb:
proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
ol.data = CompletionData(fd: socket, cb:
proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
if not retFuture.finished:
if errcode == OSErrorCode(-1):
retFuture.complete()
@ -764,8 +766,8 @@ when defined(windows) or defined(nimdoc):
# free ``ol``.
return retFuture
proc acceptAddr*(socket: TAsyncFD, flags = {SocketFlag.SafeDisconn}):
Future[tuple[address: string, client: TAsyncFD]] =
proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn}):
Future[tuple[address: string, client: AsyncFD]] =
## Accepts a new connection. Returns a future containing the client socket
## corresponding to that connection and the remote address of the client.
## The future will complete when the connection is successfully accepted.
@ -778,7 +780,7 @@ when defined(windows) or defined(nimdoc):
## flag is specified then this error will not be raised and instead
## accept will be called again.
verifyPresence(socket)
var retFuture = newFuture[tuple[address: string, client: TAsyncFD]]("acceptAddr")
var retFuture = newFuture[tuple[address: string, client: AsyncFD]]("acceptAddr")
var clientSock = newRawSocket()
if clientSock == osInvalidSocket: raiseOSError(osLastError())
@ -803,11 +805,11 @@ when defined(windows) or defined(nimdoc):
dwLocalAddressLength, dwRemoteAddressLength,
addr localSockaddr, addr localLen,
addr remoteSockaddr, addr remoteLen)
register(clientSock.TAsyncFD)
register(clientSock.AsyncFD)
# TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186
retFuture.complete(
(address: $inet_ntoa(cast[ptr Sockaddr_in](remoteSockAddr).sin_addr),
client: clientSock.TAsyncFD)
client: clientSock.AsyncFD)
)
template failAccept(errcode): stmt =
@ -824,8 +826,8 @@ when defined(windows) or defined(nimdoc):
var ol = PCustomOverlapped()
GC_ref(ol)
ol.data = TCompletionData(fd: socket, cb:
proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
ol.data = CompletionData(fd: socket, cb:
proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
if not retFuture.finished:
if errcode == OSErrorCode(-1):
completeAccept()
@ -853,26 +855,26 @@ when defined(windows) or defined(nimdoc):
return retFuture
proc newAsyncRawSocket*(domain, typ, protocol: cint): TAsyncFD =
proc newAsyncRawSocket*(domain, typ, protocol: cint): AsyncFD =
## Creates a new socket and registers it with the dispatcher implicitly.
result = newRawSocket(domain, typ, protocol).TAsyncFD
result = newRawSocket(domain, typ, protocol).AsyncFD
result.SocketHandle.setBlocking(false)
register(result)
proc newAsyncRawSocket*(domain: Domain = AF_INET,
typ: SockType = SOCK_STREAM,
protocol: Protocol = IPPROTO_TCP): TAsyncFD =
protocol: Protocol = IPPROTO_TCP): AsyncFD =
## Creates a new socket and registers it with the dispatcher implicitly.
result = newRawSocket(domain, typ, protocol).TAsyncFD
result = newRawSocket(domain, typ, protocol).AsyncFD
result.SocketHandle.setBlocking(false)
register(result)
proc closeSocket*(socket: TAsyncFD) =
proc closeSocket*(socket: AsyncFD) =
## Closes a socket and ensures that it is unregistered.
socket.SocketHandle.close()
getGlobalDispatcher().handles.excl(socket)
proc unregister*(fd: TAsyncFD) =
proc unregister*(fd: AsyncFD) =
## Unregisters ``fd``.
getGlobalDispatcher().handles.excl(fd)
@ -892,18 +894,19 @@ else:
MSG_NOSIGNAL
type
TAsyncFD* = distinct cint
TCallback = proc (fd: TAsyncFD): bool {.closure,gcsafe.}
AsyncFD* = distinct cint
Callback = proc (fd: AsyncFD): bool {.closure,gcsafe.}
PData* = ref object of RootRef
fd: TAsyncFD
readCBs: seq[TCallback]
writeCBs: seq[TCallback]
fd: AsyncFD
readCBs: seq[Callback]
writeCBs: seq[Callback]
PDispatcher* = ref object of PDispatcherBase
selector: Selector
{.deprecated: [TAsyncFD: AsyncFD, TCallback: Callback].}
proc `==`*(x, y: TAsyncFD): bool {.borrow.}
proc `==`*(x, y: AsyncFD): bool {.borrow.}
proc newDispatcher*(): PDispatcher =
new result
@ -915,18 +918,18 @@ else:
if gDisp.isNil: gDisp = newDispatcher()
result = gDisp
proc update(fd: TAsyncFD, events: set[Event]) =
proc update(fd: AsyncFD, events: set[Event]) =
let p = getGlobalDispatcher()
assert fd.SocketHandle in p.selector
discard p.selector.update(fd.SocketHandle, events)
proc register*(fd: TAsyncFD) =
proc register*(fd: AsyncFD) =
let p = getGlobalDispatcher()
var data = PData(fd: fd, readCBs: @[], writeCBs: @[])
p.selector.register(fd.SocketHandle, {}, data.RootRef)
proc newAsyncRawSocket*(domain: cint, typ: cint, protocol: cint): TAsyncFD =
result = newRawSocket(domain, typ, protocol).TAsyncFD
proc newAsyncRawSocket*(domain: cint, typ: cint, protocol: cint): AsyncFD =
result = newRawSocket(domain, typ, protocol).AsyncFD
result.SocketHandle.setBlocking(false)
when defined(macosx):
result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
@ -934,29 +937,29 @@ else:
proc newAsyncRawSocket*(domain: Domain = AF_INET,
typ: SockType = SOCK_STREAM,
protocol: Protocol = IPPROTO_TCP): TAsyncFD =
result = newRawSocket(domain, typ, protocol).TAsyncFD
protocol: Protocol = IPPROTO_TCP): AsyncFD =
result = newRawSocket(domain, typ, protocol).AsyncFD
result.SocketHandle.setBlocking(false)
when defined(macosx):
result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
register(result)
proc closeSocket*(sock: TAsyncFD) =
proc closeSocket*(sock: AsyncFD) =
let disp = getGlobalDispatcher()
sock.SocketHandle.close()
disp.selector.unregister(sock.SocketHandle)
proc unregister*(fd: TAsyncFD) =
proc unregister*(fd: AsyncFD) =
getGlobalDispatcher().selector.unregister(fd.SocketHandle)
proc addRead*(fd: TAsyncFD, cb: TCallback) =
proc addRead*(fd: AsyncFD, cb: Callback) =
let p = getGlobalDispatcher()
if fd.SocketHandle notin p.selector:
raise newException(ValueError, "File descriptor not registered.")
p.selector[fd.SocketHandle].data.PData.readCBs.add(cb)
update(fd, p.selector[fd.SocketHandle].events + {EvRead})
proc addWrite*(fd: TAsyncFD, cb: TCallback) =
proc addWrite*(fd: AsyncFD, cb: Callback) =
let p = getGlobalDispatcher()
if fd.SocketHandle notin p.selector:
raise newException(ValueError, "File descriptor not registered.")
@ -967,7 +970,7 @@ else:
let p = getGlobalDispatcher()
for info in p.selector.select(timeout):
let data = PData(info.key.data)
assert data.fd == info.key.fd.TAsyncFD
assert data.fd == info.key.fd.AsyncFD
#echo("In poll ", data.fd.cint)
if EvError in info.events:
closeSocket(data.fd)
@ -1005,11 +1008,11 @@ else:
processTimers(p)
proc connect*(socket: TAsyncFD, address: string, port: Port,
proc connect*(socket: AsyncFD, address: string, port: Port,
af = AF_INET): Future[void] =
var retFuture = newFuture[void]("connect")
proc cb(fd: TAsyncFD): bool =
proc cb(fd: AsyncFD): bool =
# We have connected.
retFuture.complete()
return true
@ -1040,13 +1043,13 @@ else:
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
return retFuture
proc recv*(socket: TAsyncFD, size: int,
proc recv*(socket: AsyncFD, size: int,
flags = {SocketFlag.SafeDisconn}): Future[string] =
var retFuture = newFuture[string]("recv")
var readBuffer = newString(size)
proc cb(sock: TAsyncFD): bool =
proc cb(sock: AsyncFD): bool =
result = true
let res = recv(sock.SocketHandle, addr readBuffer[0], size.cint,
flags.toOSFlags())
@ -1070,11 +1073,11 @@ else:
addRead(socket, cb)
return retFuture
proc recvInto*(socket: TAsyncFD, buf: cstring, size: int,
proc recvInto*(socket: AsyncFD, buf: cstring, size: int,
flags = {SocketFlag.SafeDisconn}): Future[int] =
var retFuture = newFuture[int]("recvInto")
proc cb(sock: TAsyncFD): bool =
proc cb(sock: AsyncFD): bool =
result = true
let res = recv(sock.SocketHandle, buf, size.cint,
flags.toOSFlags())
@ -1094,13 +1097,13 @@ else:
addRead(socket, cb)
return retFuture
proc send*(socket: TAsyncFD, data: string,
proc send*(socket: AsyncFD, data: string,
flags = {SocketFlag.SafeDisconn}): Future[void] =
var retFuture = newFuture[void]("send")
var written = 0
proc cb(sock: TAsyncFD): bool =
proc cb(sock: AsyncFD): bool =
result = true
let netSize = data.len-written
var d = data.cstring
@ -1126,11 +1129,11 @@ else:
addWrite(socket, cb)
return retFuture
proc acceptAddr*(socket: TAsyncFD, flags = {SocketFlag.SafeDisconn}):
Future[tuple[address: string, client: TAsyncFD]] =
proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn}):
Future[tuple[address: string, client: AsyncFD]] =
var retFuture = newFuture[tuple[address: string,
client: TAsyncFD]]("acceptAddr")
proc cb(sock: TAsyncFD): bool =
client: AsyncFD]]("acceptAddr")
proc cb(sock: AsyncFD): bool =
result = true
var sockAddress: SockAddr_in
var addrLen = sizeof(sockAddress).Socklen
@ -1147,8 +1150,8 @@ else:
else:
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
else:
register(client.TAsyncFD)
retFuture.complete(($inet_ntoa(sockAddress.sin_addr), client.TAsyncFD))
register(client.AsyncFD)
retFuture.complete(($inet_ntoa(sockAddress.sin_addr), client.AsyncFD))
addRead(socket, cb)
return retFuture
@ -1160,15 +1163,15 @@ proc sleepAsync*(ms: int): Future[void] =
p.timers.add((epochTime() + (ms / 1000), retFuture))
return retFuture
proc accept*(socket: TAsyncFD,
flags = {SocketFlag.SafeDisconn}): Future[TAsyncFD] =
proc accept*(socket: AsyncFD,
flags = {SocketFlag.SafeDisconn}): Future[AsyncFD] =
## Accepts a new connection. Returns a future containing the client socket
## corresponding to that connection.
## The future will complete when the connection is successfully accepted.
var retFut = newFuture[TAsyncFD]("accept")
var retFut = newFuture[AsyncFD]("accept")
var fut = acceptAddr(socket, flags)
fut.callback =
proc (future: Future[tuple[address: string, client: TAsyncFD]]) =
proc (future: Future[tuple[address: string, client: AsyncFD]]) =
assert future.finished
if future.failed:
retFut.fail(future.error)
@ -1495,7 +1498,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
#if prc[0].getName == "test":
# echo(toStrLit(result))
proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
proc recvLine*(socket: AsyncFD): Future[string] {.async.} =
## Reads a line of data from ``socket``. Returned future will complete once
## a full line is read or an error occurs.
##

View file

@ -31,7 +31,7 @@ else:
type
AsyncFile* = ref object
fd: TAsyncFd
fd: AsyncFd
offset: int64
when defined(windows) or defined(nimdoc):
@ -72,7 +72,7 @@ proc getFileSize(f: AsyncFile): int64 =
## Retrieves the specified file's size.
when defined(windows) or defined(nimdoc):
var high: DWord
let low = getFileSize(f.fd.THandle, addr high)
let low = getFileSize(f.fd.Handle, addr high)
if low == INVALID_FILE_SIZE:
raiseOSError(osLastError())
return (high shl 32) or low
@ -88,13 +88,13 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile =
when useWinUnicode:
result.fd = createFileW(newWideCString(filename), desiredAccess,
FILE_SHARE_READ,
nil, creationDisposition, flags, 0).TAsyncFd
nil, creationDisposition, flags, 0).AsyncFd
else:
result.fd = createFileA(filename, desiredAccess,
FILE_SHARE_READ,
nil, creationDisposition, flags, 0).TAsyncFd
nil, creationDisposition, flags, 0).AsyncFd
if result.fd.THandle == INVALID_HANDLE_VALUE:
if result.fd.Handle == INVALID_HANDLE_VALUE:
raiseOSError(osLastError())
register(result.fd)
@ -106,7 +106,7 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile =
let flags = getPosixFlags(mode)
# RW (Owner), RW (Group), R (Other)
let perm = S_IRUSR or S_IWUSR or S_IRGRP or S_IWGRP or S_IROTH
result.fd = open(filename, flags, perm).TAsyncFD
result.fd = open(filename, flags, perm).AsyncFD
if result.fd.cint == -1:
raiseOSError(osLastError())
@ -125,8 +125,8 @@ proc read*(f: AsyncFile, size: int): Future[string] =
var ol = PCustomOverlapped()
GC_ref(ol)
ol.data = TCompletionData(fd: f.fd, cb:
proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
ol.data = CompletionData(fd: f.fd, cb:
proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
if not retFuture.finished:
if errcode == OSErrorCode(-1):
assert bytesCount > 0
@ -148,7 +148,7 @@ proc read*(f: AsyncFile, size: int): Future[string] =
ol.offsetHigh = DWord(f.offset shr 32)
# According to MSDN we're supposed to pass nil to lpNumberOfBytesRead.
let ret = readFile(f.fd.THandle, buffer, size.int32, nil,
let ret = readFile(f.fd.Handle, buffer, size.int32, nil,
cast[POVERLAPPED](ol))
if not ret.bool:
let err = osLastError()
@ -161,7 +161,7 @@ proc read*(f: AsyncFile, size: int): Future[string] =
else:
# Request completed immediately.
var bytesRead: DWord
let overlappedRes = getOverlappedResult(f.fd.THandle,
let overlappedRes = getOverlappedResult(f.fd.Handle,
cast[POverlapped](ol)[], bytesRead, false.WinBool)
if not overlappedRes.bool:
let err = osLastError()
@ -179,7 +179,7 @@ proc read*(f: AsyncFile, size: int): Future[string] =
else:
var readBuffer = newString(size)
proc cb(fd: TAsyncFD): bool =
proc cb(fd: AsyncFD): bool =
result = true
let res = read(fd.cint, addr readBuffer[0], size.cint)
if res < 0:
@ -251,8 +251,8 @@ proc write*(f: AsyncFile, data: string): Future[void] =
var ol = PCustomOverlapped()
GC_ref(ol)
ol.data = TCompletionData(fd: f.fd, cb:
proc (fd: TAsyncFD, bytesCount: DWord, errcode: OSErrorCode) =
ol.data = CompletionData(fd: f.fd, cb:
proc (fd: AsyncFD, bytesCount: DWord, errcode: OSErrorCode) =
if not retFuture.finished:
if errcode == OSErrorCode(-1):
assert bytesCount == data.len.int32
@ -268,7 +268,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
ol.offsetHigh = DWord(f.offset shr 32)
# According to MSDN we're supposed to pass nil to lpNumberOfBytesWritten.
let ret = writeFile(f.fd.THandle, buffer, data.len.int32, nil,
let ret = writeFile(f.fd.Handle, buffer, data.len.int32, nil,
cast[POVERLAPPED](ol))
if not ret.bool:
let err = osLastError()
@ -281,7 +281,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
else:
# Request completed immediately.
var bytesWritten: DWord
let overlappedRes = getOverlappedResult(f.fd.THandle,
let overlappedRes = getOverlappedResult(f.fd.Handle,
cast[POverlapped](ol)[], bytesWritten, false.WinBool)
if not overlappedRes.bool:
retFuture.fail(newException(OSError, osErrorMsg(osLastError())))
@ -292,7 +292,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
else:
var written = 0
proc cb(fd: TAsyncFD): bool =
proc cb(fd: AsyncFD): bool =
result = true
let remainderSize = data.len-written
let res = write(fd.cint, addr copy[written], remainderSize.cint)
@ -317,7 +317,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
proc close*(f: AsyncFile) =
## Closes the file specified.
when defined(windows) or defined(nimdoc):
if not closeHandle(f.fd.THandle).bool:
if not closeHandle(f.fd.Handle).bool:
raiseOSError(osLastError())
else:
if close(f.fd.cint) == -1:

View file

@ -210,6 +210,7 @@ proc processClient(client: AsyncSocket, address: string,
var contentLength = 0
if parseInt(request.headers["Content-Length"], contentLength) == 0:
await request.respond(Http400, "Bad Request. Invalid Content-Length.")
continue
else:
request.body = await client.recv(contentLength)
assert request.body.len == contentLength

View file

@ -188,8 +188,8 @@ proc asyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
result.socket.setBlocking(false)
proc toAsyncSocket*(sock: Socket, state: SocketStatus = SockConnected): AsyncSocket =
## Wraps an already initialized ``TSocket`` into a AsyncSocket.
## This is useful if you want to use an already connected TSocket as an
## Wraps an already initialized ``Socket`` into a AsyncSocket.
## This is useful if you want to use an already connected Socket as an
## asynchronous AsyncSocket in asyncio's event loop.
##
## ``state`` may be overriden, i.e. if ``sock`` is not connected it should be

View file

@ -91,13 +91,13 @@ type
# TODO: Save AF, domain etc info and reuse it in procs which need it like connect.
proc newAsyncSocket*(fd: TAsyncFD, isBuff: bool): AsyncSocket =
proc newAsyncSocket*(fd: AsyncFD, buffered = true): AsyncSocket =
## Creates a new ``AsyncSocket`` based on the supplied params.
assert fd != osInvalidSocket.TAsyncFD
assert fd != osInvalidSocket.AsyncFD
new(result)
result.fd = fd.SocketHandle
result.isBuffered = isBuff
if isBuff:
result.isBuffered = buffered
if buffered:
result.currPos = 0
proc newAsyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
@ -142,7 +142,7 @@ when defined(ssl):
if read < 0:
raiseSslError()
data.setLen(read)
await socket.fd.TAsyncFd.send(data, flags)
await socket.fd.AsyncFd.send(data, flags)
proc appeaseSsl(socket: AsyncSocket, flags: set[SocketFlag],
sslError: cint) {.async.} =
@ -150,7 +150,7 @@ when defined(ssl):
of SSL_ERROR_WANT_WRITE:
await sendPendingSslData(socket, flags)
of SSL_ERROR_WANT_READ:
var data = await recv(socket.fd.TAsyncFD, BufferSize, flags)
var data = await recv(socket.fd.AsyncFD, BufferSize, flags)
let ret = bioWrite(socket.bioIn, addr data[0], data.len.cint)
if ret < 0:
raiseSSLError()
@ -175,7 +175,7 @@ proc connect*(socket: AsyncSocket, address: string, port: Port,
##
## Returns a ``Future`` which will complete when the connection succeeds
## or an error occurs.
await connect(socket.fd.TAsyncFD, address, port, af)
await connect(socket.fd.AsyncFD, address, port, af)
if socket.isSsl:
when defined(ssl):
let flags = {SocketFlag.SafeDisconn}
@ -194,7 +194,7 @@ template readInto(buf: cstring, size: int, socket: AsyncSocket,
sslRead(socket.sslHandle, buf, size.cint))
res = opResult
else:
var recvIntoFut = recvInto(socket.fd.TAsyncFD, buf, size, flags)
var recvIntoFut = recvInto(socket.fd.AsyncFD, buf, size, flags)
yield recvIntoFut
# Not in SSL mode.
res = recvIntoFut.read()
@ -271,7 +271,7 @@ proc send*(socket: AsyncSocket, data: string,
sslWrite(socket.sslHandle, addr copy[0], copy.len.cint))
await sendPendingSslData(socket, flags)
else:
await send(socket.fd.TAsyncFD, data, flags)
await send(socket.fd.AsyncFD, data, flags)
proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}):
Future[tuple[address: string, client: AsyncSocket]] =
@ -279,9 +279,9 @@ proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}):
## corresponding to that connection and the remote address of the client.
## The future will complete when the connection is successfully accepted.
var retFuture = newFuture[tuple[address: string, client: AsyncSocket]]("asyncnet.acceptAddr")
var fut = acceptAddr(socket.fd.TAsyncFD, flags)
var fut = acceptAddr(socket.fd.AsyncFD, flags)
fut.callback =
proc (future: Future[tuple[address: string, client: TAsyncFD]]) =
proc (future: Future[tuple[address: string, client: AsyncFD]]) =
assert future.finished
if future.failed:
retFuture.fail(future.readError)
@ -445,7 +445,7 @@ proc bindAddr*(socket: AsyncSocket, port = Port(0), address = "") {.
proc close*(socket: AsyncSocket) =
## Closes the socket.
defer:
socket.fd.TAsyncFD.closeSocket()
socket.fd.AsyncFD.closeSocket()
when defined(ssl):
if socket.isSSL:
let res = SslShutdown(socket.sslHandle)

View file

@ -20,20 +20,20 @@ import strutils
##
## # Create a matrix which first rotates, then scales and at last translates
##
## var m:TMatrix2d=rotate(DEG90) & scale(2.0) & move(100.0,200.0)
## var m:Matrix2d=rotate(DEG90) & scale(2.0) & move(100.0,200.0)
##
## # Create a 2d point at (100,0) and a vector (5,2)
##
## var pt:TPoint2d=point2d(100.0,0.0)
## var pt:Point2d=point2d(100.0,0.0)
##
## var vec:TVector2d=vector2d(5.0,2.0)
## var vec:Vector2d=vector2d(5.0,2.0)
##
##
## pt &= m # transforms pt in place
##
## var pt2:TPoint2d=pt & m #concatenates pt with m and returns a new point
## var pt2:Point2d=pt & m #concatenates pt with m and returns a new point
##
## var vec2:TVector2d=vec & m #concatenates vec with m and returns a new vector
## var vec2:Vector2d=vec & m #concatenates vec with m and returns a new vector
const
@ -57,46 +57,46 @@ const
## used internally by DegToRad and RadToDeg
type
TMatrix2d* = object
Matrix2d* = object
## Implements a row major 2d matrix, which means
## transformations are applied the order they are concatenated.
## The rightmost column of the 3x3 matrix is left out since normally
## not used for geometric transformations in 2d.
ax*,ay*,bx*,by*,tx*,ty*:float
TPoint2d* = object
Point2d* = object
## Implements a non-homegeneous 2d point stored as
## an `x` coordinate and an `y` coordinate.
x*,y*:float
TVector2d* = object
Vector2d* = object
## Implements a 2d **direction vector** stored as
## an `x` coordinate and an `y` coordinate. Direction vector means,
## that when transforming a vector with a matrix, the translational
## part of the matrix is ignored.
x*,y*:float
{.deprecated: [TMatrix2d: Matrix2d, TPoint2d: Point2d, TVector2d: Vector2d].}
# Some forward declarations...
proc matrix2d*(ax,ay,bx,by,tx,ty:float):TMatrix2d {.noInit.}
proc matrix2d*(ax,ay,bx,by,tx,ty:float):Matrix2d {.noInit.}
## Creates a new matrix.
## `ax`,`ay` is the local x axis
## `bx`,`by` is the local y axis
## `tx`,`ty` is the translation
proc vector2d*(x,y:float):TVector2d {.noInit,inline.}
proc vector2d*(x,y:float):Vector2d {.noInit,inline.}
## Returns a new vector (`x`,`y`)
proc point2d*(x,y:float):TPoint2d {.noInit,inline.}
proc point2d*(x,y:float):Point2d {.noInit,inline.}
## Returns a new point (`x`,`y`)
let
IDMATRIX*:TMatrix2d=matrix2d(1.0,0.0,0.0,1.0,0.0,0.0)
IDMATRIX*:Matrix2d=matrix2d(1.0,0.0,0.0,1.0,0.0,0.0)
## Quick access to an identity matrix
ORIGO*:TPoint2d=point2d(0.0,0.0)
ORIGO*:Point2d=point2d(0.0,0.0)
## Quick acces to point (0,0)
XAXIS*:TVector2d=vector2d(1.0,0.0)
XAXIS*:Vector2d=vector2d(1.0,0.0)
## Quick acces to an 2d x-axis unit vector
YAXIS*:TVector2d=vector2d(0.0,1.0)
YAXIS*:Vector2d=vector2d(0.0,1.0)
## Quick acces to an 2d y-axis unit vector
@ -116,21 +116,21 @@ proc safeArccos(v:float):float=
template makeBinOpVector(s:expr)=
## implements binary operators + , - , * and / for vectors
proc s*(a,b:TVector2d):TVector2d {.inline,noInit.} = vector2d(s(a.x,b.x),s(a.y,b.y))
proc s*(a:TVector2d,b:float):TVector2d {.inline,noInit.} = vector2d(s(a.x,b),s(a.y,b))
proc s*(a:float,b:TVector2d):TVector2d {.inline,noInit.} = vector2d(s(a,b.x),s(a,b.y))
proc s*(a,b:Vector2d):Vector2d {.inline,noInit.} = vector2d(s(a.x,b.x),s(a.y,b.y))
proc s*(a:Vector2d,b:float):Vector2d {.inline,noInit.} = vector2d(s(a.x,b),s(a.y,b))
proc s*(a:float,b:Vector2d):Vector2d {.inline,noInit.} = vector2d(s(a,b.x),s(a,b.y))
template makeBinOpAssignVector(s:expr)=
## implements inplace binary operators += , -= , /= and *= for vectors
proc s*(a:var TVector2d,b:TVector2d) {.inline.} = s(a.x,b.x) ; s(a.y,b.y)
proc s*(a:var TVector2d,b:float) {.inline.} = s(a.x,b) ; s(a.y,b)
proc s*(a:var Vector2d,b:Vector2d) {.inline.} = s(a.x,b.x) ; s(a.y,b.y)
proc s*(a:var Vector2d,b:float) {.inline.} = s(a.x,b) ; s(a.y,b)
# ***************************************
# TMatrix2d implementation
# Matrix2d implementation
# ***************************************
proc setElements*(t:var TMatrix2d,ax,ay,bx,by,tx,ty:float) {.inline.}=
proc setElements*(t:var Matrix2d,ax,ay,bx,by,tx,ty:float) {.inline.}=
## Sets arbitrary elements in an existing matrix.
t.ax=ax
t.ay=ay
@ -139,10 +139,10 @@ proc setElements*(t:var TMatrix2d,ax,ay,bx,by,tx,ty:float) {.inline.}=
t.tx=tx
t.ty=ty
proc matrix2d*(ax,ay,bx,by,tx,ty:float):TMatrix2d =
proc matrix2d*(ax,ay,bx,by,tx,ty:float):Matrix2d =
result.setElements(ax,ay,bx,by,tx,ty)
proc `&`*(a,b:TMatrix2d):TMatrix2d {.noInit.} = #concatenate matrices
proc `&`*(a,b:Matrix2d):Matrix2d {.noInit.} = #concatenate matrices
## Concatenates matrices returning a new matrix.
# | a.AX a.AY 0 | | b.AX b.AY 0 |
@ -157,34 +157,34 @@ proc `&`*(a,b:TMatrix2d):TMatrix2d {.noInit.} = #concatenate matrices
a.tx * b.ay + a.ty * b.by + b.ty)
proc scale*(s:float):TMatrix2d {.noInit.} =
proc scale*(s:float):Matrix2d {.noInit.} =
## Returns a new scale matrix.
result.setElements(s,0,0,s,0,0)
proc scale*(s:float,org:TPoint2d):TMatrix2d {.noInit.} =
proc scale*(s:float,org:Point2d):Matrix2d {.noInit.} =
## Returns a new scale matrix using, `org` as scale origin.
result.setElements(s,0,0,s,org.x-s*org.x,org.y-s*org.y)
proc stretch*(sx,sy:float):TMatrix2d {.noInit.} =
proc stretch*(sx,sy:float):Matrix2d {.noInit.} =
## Returns new a stretch matrix, which is a
## scale matrix with non uniform scale in x and y.
result.setElements(sx,0,0,sy,0,0)
proc stretch*(sx,sy:float,org:TPoint2d):TMatrix2d {.noInit.} =
proc stretch*(sx,sy:float,org:Point2d):Matrix2d {.noInit.} =
## Returns a new stretch matrix, which is a
## scale matrix with non uniform scale in x and y.
## `org` is used as stretch origin.
result.setElements(sx,0,0,sy,org.x-sx*org.x,org.y-sy*org.y)
proc move*(dx,dy:float):TMatrix2d {.noInit.} =
proc move*(dx,dy:float):Matrix2d {.noInit.} =
## Returns a new translation matrix.
result.setElements(1,0,0,1,dx,dy)
proc move*(v:TVector2d):TMatrix2d {.noInit.} =
proc move*(v:Vector2d):Matrix2d {.noInit.} =
## Returns a new translation matrix from a vector.
result.setElements(1,0,0,1,v.x,v.y)
proc rotate*(rad:float):TMatrix2d {.noInit.} =
proc rotate*(rad:float):Matrix2d {.noInit.} =
## Returns a new rotation matrix, which
## represents a rotation by `rad` radians
let
@ -192,7 +192,7 @@ proc rotate*(rad:float):TMatrix2d {.noInit.} =
c=cos(rad)
result.setElements(c,s,-s,c,0,0)
proc rotate*(rad:float,org:TPoint2d):TMatrix2d {.noInit.} =
proc rotate*(rad:float,org:Point2d):Matrix2d {.noInit.} =
## Returns a new rotation matrix, which
## represents a rotation by `rad` radians around
## the origin `org`
@ -201,7 +201,7 @@ proc rotate*(rad:float,org:TPoint2d):TMatrix2d {.noInit.} =
c=cos(rad)
result.setElements(c,s,-s,c,org.x+s*org.y-c*org.x,org.y-c*org.y-s*org.x)
proc mirror*(v:TVector2d):TMatrix2d {.noInit.} =
proc mirror*(v:Vector2d):Matrix2d {.noInit.} =
## Returns a new mirror matrix, mirroring
## around the line that passes through origo and
## has the direction of `v`
@ -220,7 +220,7 @@ proc mirror*(v:TVector2d):TMatrix2d {.noInit.} =
xy2,-sqd,
0.0,0.0)
proc mirror*(org:TPoint2d,v:TVector2d):TMatrix2d {.noInit.} =
proc mirror*(org:Point2d,v:Vector2d):Matrix2d {.noInit.} =
## Returns a new mirror matrix, mirroring
## around the line that passes through `org` and
## has the direction of `v`
@ -241,20 +241,20 @@ proc mirror*(org:TPoint2d,v:TVector2d):TMatrix2d {.noInit.} =
proc skew*(xskew,yskew:float):TMatrix2d {.noInit.} =
proc skew*(xskew,yskew:float):Matrix2d {.noInit.} =
## Returns a new skew matrix, which has its
## x axis rotated `xskew` radians from the local x axis, and
## y axis rotated `yskew` radians from the local y axis
result.setElements(cos(yskew),sin(yskew),-sin(xskew),cos(xskew),0,0)
proc `$`* (t:TMatrix2d):string {.noInit.} =
proc `$`* (t:Matrix2d):string {.noInit.} =
## Returns a string representation of the matrix
return rtos(t.ax) & "," & rtos(t.ay) &
"," & rtos(t.bx) & "," & rtos(t.by) &
"," & rtos(t.tx) & "," & rtos(t.ty)
proc isUniform*(t:TMatrix2d,tol=1.0e-6):bool=
proc isUniform*(t:Matrix2d,tol=1.0e-6):bool=
## Checks if the transform is uniform, that is
## perpendicular axes of equal length, which means (for example)
## it cannot transform a circle into an ellipse.
@ -268,18 +268,18 @@ proc isUniform*(t:TMatrix2d,tol=1.0e-6):bool=
return true
return false
proc determinant*(t:TMatrix2d):float=
proc determinant*(t:Matrix2d):float=
## Computes the determinant of the matrix.
#NOTE: equivalent with perp.dot product for two 2d vectors
return t.ax*t.by-t.bx*t.ay
proc isMirroring* (m:TMatrix2d):bool=
proc isMirroring* (m:Matrix2d):bool=
## Checks if the `m` is a mirroring matrix,
## which means it will reverse direction of a curve transformed with it
return m.determinant<0.0
proc inverse*(m:TMatrix2d):TMatrix2d {.noInit.} =
proc inverse*(m:Matrix2d):Matrix2d {.noInit.} =
## Returns a new matrix, which is the inverse of the matrix
## If the matrix is not invertible (determinant=0), an EDivByZero
## will be raised.
@ -293,7 +293,7 @@ proc inverse*(m:TMatrix2d):TMatrix2d {.noInit.} =
(m.bx*m.ty-m.by*m.tx)/d,
(m.ay*m.tx-m.ax*m.ty)/d)
proc equals*(m1:TMatrix2d,m2:TMatrix2d,tol=1.0e-6):bool=
proc equals*(m1:Matrix2d,m2:Matrix2d,tol=1.0e-6):bool=
## Checks if all elements of `m1`and `m2` is equal within
## a given tolerance `tol`.
return
@ -304,17 +304,17 @@ proc equals*(m1:TMatrix2d,m2:TMatrix2d,tol=1.0e-6):bool=
abs(m1.tx-m2.tx)<=tol and
abs(m1.ty-m2.ty)<=tol
proc `=~`*(m1,m2:TMatrix2d):bool=
proc `=~`*(m1,m2:Matrix2d):bool=
## Checks if `m1`and `m2` is approximately equal, using a
## tolerance of 1e-6.
equals(m1,m2)
proc isIdentity*(m:TMatrix2d,tol=1.0e-6):bool=
proc isIdentity*(m:Matrix2d,tol=1.0e-6):bool=
## Checks is a matrix is approximately an identity matrix,
## using `tol` as tolerance for each element.
return equals(m,IDMATRIX,tol)
proc apply*(m:TMatrix2d,x,y:var float,translate=false)=
proc apply*(m:Matrix2d,x,y:var float,translate=false)=
## Applies transformation `m` onto `x`,`y`, optionally
## using the translation part of the matrix.
if translate: # positional style transform
@ -329,29 +329,29 @@ proc apply*(m:TMatrix2d,x,y:var float,translate=false)=
# ***************************************
# TVector2d implementation
# Vector2d implementation
# ***************************************
proc vector2d*(x,y:float):TVector2d = #forward decl.
proc vector2d*(x,y:float):Vector2d = #forward decl.
result.x=x
result.y=y
proc polarVector2d*(ang:float,len:float):TVector2d {.noInit.} =
proc polarVector2d*(ang:float,len:float):Vector2d {.noInit.} =
## Returns a new vector with angle `ang` and magnitude `len`
result.x=cos(ang)*len
result.y=sin(ang)*len
proc slopeVector2d*(slope:float,len:float):TVector2d {.noInit.} =
proc slopeVector2d*(slope:float,len:float):Vector2d {.noInit.} =
## Returns a new vector having slope (dy/dx) given by
## `slope`, and a magnitude of `len`
let ang=arctan(slope)
result.x=cos(ang)*len
result.y=sin(ang)*len
proc len*(v:TVector2d):float {.inline.}=
proc len*(v:Vector2d):float {.inline.}=
## Returns the length of the vector.
sqrt(v.x*v.x+v.y*v.y)
proc `len=`*(v:var TVector2d,newlen:float) {.noInit.} =
proc `len=`*(v:var Vector2d,newlen:float) {.noInit.} =
## Sets the length of the vector, keeping its angle.
let fac=newlen/v.len
@ -369,25 +369,25 @@ proc `len=`*(v:var TVector2d,newlen:float) {.noInit.} =
v.x*=fac
v.y*=fac
proc sqrLen*(v:TVector2d):float {.inline.}=
proc sqrLen*(v:Vector2d):float {.inline.}=
## Computes the squared length of the vector, which is
## faster than computing the absolute length.
v.x*v.x+v.y*v.y
proc angle*(v:TVector2d):float=
proc angle*(v:Vector2d):float=
## Returns the angle of the vector.
## (The counter clockwise plane angle between posetive x axis and `v`)
result=arctan2(v.y,v.x)
if result<0.0: result+=DEG360
proc `$` *(v:TVector2d):string=
proc `$` *(v:Vector2d):string=
## String representation of `v`
result=rtos(v.x)
result.add(",")
result.add(rtos(v.y))
proc `&` *(v:TVector2d,m:TMatrix2d):TVector2d {.noInit.} =
proc `&` *(v:Vector2d,m:Matrix2d):Vector2d {.noInit.} =
## Concatenate vector `v` with a transformation matrix.
## Transforming a vector ignores the translational part
## of the matrix.
@ -399,7 +399,7 @@ proc `&` *(v:TVector2d,m:TMatrix2d):TVector2d {.noInit.} =
result.y=v.x*m.ay+v.y*m.by
proc `&=`*(v:var TVector2d,m:TMatrix2d) {.inline.}=
proc `&=`*(v:var Vector2d,m:Matrix2d) {.inline.}=
## Applies transformation `m` onto `v` in place.
## Transforming a vector ignores the translational part
## of the matrix.
@ -412,7 +412,7 @@ proc `&=`*(v:var TVector2d,m:TMatrix2d) {.inline.}=
v.x=newx
proc tryNormalize*(v:var TVector2d):bool=
proc tryNormalize*(v:var Vector2d):bool=
## Modifies `v` to have a length of 1.0, keeping its angle.
## If `v` has zero length (and thus no angle), it is left unmodified and
## false is returned, otherwise true is returned.
@ -427,13 +427,13 @@ proc tryNormalize*(v:var TVector2d):bool=
return true
proc normalize*(v:var TVector2d) {.inline.}=
proc normalize*(v:var Vector2d) {.inline.}=
## Modifies `v` to have a length of 1.0, keeping its angle.
## If `v` has zero length, an EDivByZero will be raised.
if not tryNormalize(v):
raise newException(DivByZeroError,"Cannot normalize zero length vector")
proc transformNorm*(v:var TVector2d,t:TMatrix2d)=
proc transformNorm*(v:var Vector2d,t:Matrix2d)=
## Applies a normal direction transformation `t` onto `v` in place.
## The resulting vector is *not* normalized. Transforming a vector ignores the
## translational part of the matrix. If the matrix is not invertible
@ -452,7 +452,7 @@ proc transformNorm*(v:var TVector2d,t:TMatrix2d)=
v.y = (t.ax*v.y-t.bx*v.x)/d
v.x = newx
proc transformInv*(v:var TVector2d,t:TMatrix2d)=
proc transformInv*(v:var Vector2d,t:Matrix2d)=
## Applies inverse of a transformation `t` to `v` in place.
## This is faster than creating an inverse matrix and apply() it.
## Transforming a vector ignores the translational part
@ -467,7 +467,7 @@ proc transformInv*(v:var TVector2d,t:TMatrix2d)=
v.y = (t.ax*v.y-t.ay*v.x)/d
v.x = newx
proc transformNormInv*(v:var TVector2d,t:TMatrix2d)=
proc transformNormInv*(v:var Vector2d,t:Matrix2d)=
## Applies an inverse normal direction transformation `t` onto `v` in place.
## This is faster than creating an inverse
## matrix and transformNorm(...) it. Transforming a vector ignores the
@ -484,25 +484,25 @@ proc transformNormInv*(v:var TVector2d,t:TMatrix2d)=
v.y=t.by*v.y+t.bx*v.x
v.x=newx
proc rotate90*(v:var TVector2d) {.inline.}=
proc rotate90*(v:var Vector2d) {.inline.}=
## Quickly rotates vector `v` 90 degrees counter clockwise,
## without using any trigonometrics.
swap(v.x,v.y)
v.x= -v.x
proc rotate180*(v:var TVector2d){.inline.}=
proc rotate180*(v:var Vector2d){.inline.}=
## Quickly rotates vector `v` 180 degrees counter clockwise,
## without using any trigonometrics.
v.x= -v.x
v.y= -v.y
proc rotate270*(v:var TVector2d) {.inline.}=
proc rotate270*(v:var Vector2d) {.inline.}=
## Quickly rotates vector `v` 270 degrees counter clockwise,
## without using any trigonometrics.
swap(v.x,v.y)
v.y= -v.y
proc rotate*(v:var TVector2d,rad:float) =
proc rotate*(v:var Vector2d,rad:float) =
## Rotates vector `v` `rad` radians in place.
let
s=sin(rad)
@ -511,18 +511,18 @@ proc rotate*(v:var TVector2d,rad:float) =
v.y=c*v.y+s*v.x
v.x=newx
proc scale*(v:var TVector2d,fac:float){.inline.}=
proc scale*(v:var Vector2d,fac:float){.inline.}=
## Scales vector `v` `rad` radians in place.
v.x*=fac
v.y*=fac
proc stretch*(v:var TVector2d,facx,facy:float){.inline.}=
proc stretch*(v:var Vector2d,facx,facy:float){.inline.}=
## Stretches vector `v` `facx` times horizontally,
## and `facy` times vertically.
v.x*=facx
v.y*=facy
proc mirror*(v:var TVector2d,mirrvec:TVector2d)=
proc mirror*(v:var Vector2d,mirrvec:Vector2d)=
## Mirrors vector `v` using `mirrvec` as mirror direction.
let
sqx=mirrvec.x*mirrvec.x
@ -539,7 +539,7 @@ proc mirror*(v:var TVector2d,mirrvec:TVector2d)=
v.x=newx
proc `-` *(v:TVector2d):TVector2d=
proc `-` *(v:Vector2d):Vector2d=
## Negates a vector
result.x= -v.x
result.y= -v.y
@ -555,27 +555,27 @@ makeBinOpAssignVector(`*=`)
makeBinOpAssignVector(`/=`)
proc dot*(v1,v2:TVector2d):float=
proc dot*(v1,v2:Vector2d):float=
## Computes the dot product of two vectors.
## Returns 0.0 if the vectors are perpendicular.
return v1.x*v2.x+v1.y*v2.y
proc cross*(v1,v2:TVector2d):float=
proc cross*(v1,v2:Vector2d):float=
## Computes the cross product of two vectors, also called
## the 'perpendicular dot product' in 2d. Returns 0.0 if the vectors
## are parallel.
return v1.x*v2.y-v1.y*v2.x
proc equals*(v1,v2:TVector2d,tol=1.0e-6):bool=
proc equals*(v1,v2:Vector2d,tol=1.0e-6):bool=
## Checks if two vectors approximately equals with a tolerance.
return abs(v2.x-v1.x)<=tol and abs(v2.y-v1.y)<=tol
proc `=~` *(v1,v2:TVector2d):bool=
proc `=~` *(v1,v2:Vector2d):bool=
## Checks if two vectors approximately equals with a
## hardcoded tolerance 1e-6
equals(v1,v2)
proc angleTo*(v1,v2:TVector2d):float=
proc angleTo*(v1,v2:Vector2d):float=
## Returns the smallest of the two possible angles
## between `v1` and `v2` in radians.
var
@ -585,7 +585,7 @@ proc angleTo*(v1,v2:TVector2d):float=
return 0.0 # zero length vector has zero angle to any other vector
return safeArccos(dot(nv1,nv2))
proc angleCCW*(v1,v2:TVector2d):float=
proc angleCCW*(v1,v2:Vector2d):float=
## Returns the counter clockwise plane angle from `v1` to `v2`,
## in range 0 - 2*PI
let a=v1.angleTo(v2)
@ -593,7 +593,7 @@ proc angleCCW*(v1,v2:TVector2d):float=
return a
return DEG360-a
proc angleCW*(v1,v2:TVector2d):float=
proc angleCW*(v1,v2:Vector2d):float=
## Returns the clockwise plane angle from `v1` to `v2`,
## in range 0 - 2*PI
let a=v1.angleTo(v2)
@ -601,7 +601,7 @@ proc angleCW*(v1,v2:TVector2d):float=
return a
return DEG360-a
proc turnAngle*(v1,v2:TVector2d):float=
proc turnAngle*(v1,v2:Vector2d):float=
## Returns the amount v1 should be rotated (in radians) to equal v2,
## in range -PI to PI
let a=v1.angleTo(v2)
@ -609,7 +609,7 @@ proc turnAngle*(v1,v2:TVector2d):float=
return -a
return a
proc bisect*(v1,v2:TVector2d):TVector2d {.noInit.}=
proc bisect*(v1,v2:Vector2d):Vector2d {.noInit.}=
## Computes the bisector between v1 and v2 as a normalized vector.
## If one of the input vectors has zero length, a normalized version
## of the other is returned. If both input vectors has zero length,
@ -645,24 +645,24 @@ proc bisect*(v1,v2:TVector2d):TVector2d {.noInit.}=
# ***************************************
# TPoint2d implementation
# Point2d implementation
# ***************************************
proc point2d*(x,y:float):TPoint2d =
proc point2d*(x,y:float):Point2d =
result.x=x
result.y=y
proc sqrDist*(a,b:TPoint2d):float=
proc sqrDist*(a,b:Point2d):float=
## Computes the squared distance between `a` and `b`
let dx=b.x-a.x
let dy=b.y-a.y
result=dx*dx+dy*dy
proc dist*(a,b:TPoint2d):float {.inline.}=
proc dist*(a,b:Point2d):float {.inline.}=
## Computes the absolute distance between `a` and `b`
result=sqrt(sqrDist(a,b))
proc angle*(a,b:TPoint2d):float=
proc angle*(a,b:Point2d):float=
## Computes the angle of the vector `b`-`a`
let dx=b.x-a.x
let dy=b.y-a.y
@ -670,13 +670,13 @@ proc angle*(a,b:TPoint2d):float=
if result<0:
result += DEG360
proc `$` *(p:TPoint2d):string=
proc `$` *(p:Point2d):string=
## String representation of `p`
result=rtos(p.x)
result.add(",")
result.add(rtos(p.y))
proc `&`*(p:TPoint2d,t:TMatrix2d):TPoint2d {.noInit,inline.} =
proc `&`*(p:Point2d,t:Matrix2d):Point2d {.noInit,inline.} =
## Concatenates a point `p` with a transform `t`,
## resulting in a new, transformed point.
@ -686,14 +686,14 @@ proc `&`*(p:TPoint2d,t:TMatrix2d):TPoint2d {.noInit,inline.} =
result.x=p.x*t.ax+p.y*t.bx+t.tx
result.y=p.x*t.ay+p.y*t.by+t.ty
proc `&=` *(p:var TPoint2d,t:TMatrix2d) {.inline.}=
proc `&=` *(p:var Point2d,t:Matrix2d) {.inline.}=
## Applies transformation `t` onto `p` in place.
let newx=p.x*t.ax+p.y*t.bx+t.tx
p.y=p.x*t.ay+p.y*t.by+t.ty
p.x=newx
proc transformInv*(p:var TPoint2d,t:TMatrix2d){.inline.}=
proc transformInv*(p:var Point2d,t:Matrix2d){.inline.}=
## Applies the inverse of transformation `t` onto `p` in place.
## If the matrix is not invertable (determinant=0) , EDivByZero will
## be raised.
@ -710,48 +710,48 @@ proc transformInv*(p:var TPoint2d,t:TMatrix2d){.inline.}=
p.x=newx
proc `+`*(p:TPoint2d,v:TVector2d):TPoint2d {.noInit,inline.} =
proc `+`*(p:Point2d,v:Vector2d):Point2d {.noInit,inline.} =
## Adds a vector `v` to a point `p`, resulting
## in a new point.
result.x=p.x+v.x
result.y=p.y+v.y
proc `+=`*(p:var TPoint2d,v:TVector2d) {.noInit,inline.} =
proc `+=`*(p:var Point2d,v:Vector2d) {.noInit,inline.} =
## Adds a vector `v` to a point `p` in place.
p.x+=v.x
p.y+=v.y
proc `-`*(p:TPoint2d,v:TVector2d):TPoint2d {.noInit,inline.} =
proc `-`*(p:Point2d,v:Vector2d):Point2d {.noInit,inline.} =
## Subtracts a vector `v` from a point `p`, resulting
## in a new point.
result.x=p.x-v.x
result.y=p.y-v.y
proc `-`*(p1,p2:TPoint2d):TVector2d {.noInit,inline.} =
proc `-`*(p1,p2:Point2d):Vector2d {.noInit,inline.} =
## Subtracts `p2`from `p1` resulting in a difference vector.
result.x=p1.x-p2.x
result.y=p1.y-p2.y
proc `-=`*(p:var TPoint2d,v:TVector2d) {.noInit,inline.} =
proc `-=`*(p:var Point2d,v:Vector2d) {.noInit,inline.} =
## Subtracts a vector `v` from a point `p` in place.
p.x-=v.x
p.y-=v.y
proc equals(p1,p2:TPoint2d,tol=1.0e-6):bool {.inline.}=
proc equals(p1,p2:Point2d,tol=1.0e-6):bool {.inline.}=
## Checks if two points approximately equals with a tolerance.
return abs(p2.x-p1.x)<=tol and abs(p2.y-p1.y)<=tol
proc `=~`*(p1,p2:TPoint2d):bool {.inline.}=
proc `=~`*(p1,p2:Point2d):bool {.inline.}=
## Checks if two vectors approximately equals with a
## hardcoded tolerance 1e-6
equals(p1,p2)
proc polar*(p:TPoint2d,ang,dist:float):TPoint2d {.noInit.} =
proc polar*(p:Point2d,ang,dist:float):Point2d {.noInit.} =
## Returns a point with a given angle and distance away from `p`
result.x=p.x+cos(ang)*dist
result.y=p.y+sin(ang)*dist
proc rotate*(p:var TPoint2d,rad:float)=
proc rotate*(p:var Point2d,rad:float)=
## Rotates a point in place `rad` radians around origo.
let
c=cos(rad)
@ -760,7 +760,7 @@ proc rotate*(p:var TPoint2d,rad:float)=
p.y=p.y*c+p.x*s
p.x=newx
proc rotate*(p:var TPoint2d,rad:float,org:TPoint2d)=
proc rotate*(p:var Point2d,rad:float,org:Point2d)=
## Rotates a point in place `rad` radians using `org` as
## center of rotation.
let
@ -770,50 +770,50 @@ proc rotate*(p:var TPoint2d,rad:float,org:TPoint2d)=
p.y=(p.y - org.y) * c + (p.x - org.x) * s + org.y
p.x=newx
proc scale*(p:var TPoint2d,fac:float) {.inline.}=
proc scale*(p:var Point2d,fac:float) {.inline.}=
## Scales a point in place `fac` times with world origo as origin.
p.x*=fac
p.y*=fac
proc scale*(p:var TPoint2d,fac:float,org:TPoint2d){.inline.}=
proc scale*(p:var Point2d,fac:float,org:Point2d){.inline.}=
## Scales the point in place `fac` times with `org` as origin.
p.x=(p.x - org.x) * fac + org.x
p.y=(p.y - org.y) * fac + org.y
proc stretch*(p:var TPoint2d,facx,facy:float){.inline.}=
proc stretch*(p:var Point2d,facx,facy:float){.inline.}=
## Scales a point in place non uniformly `facx` and `facy` times with
## world origo as origin.
p.x*=facx
p.y*=facy
proc stretch*(p:var TPoint2d,facx,facy:float,org:TPoint2d){.inline.}=
proc stretch*(p:var Point2d,facx,facy:float,org:Point2d){.inline.}=
## Scales the point in place non uniformly `facx` and `facy` times with
## `org` as origin.
p.x=(p.x - org.x) * facx + org.x
p.y=(p.y - org.y) * facy + org.y
proc move*(p:var TPoint2d,dx,dy:float){.inline.}=
proc move*(p:var Point2d,dx,dy:float){.inline.}=
## Translates a point `dx`, `dy` in place.
p.x+=dx
p.y+=dy
proc move*(p:var TPoint2d,v:TVector2d){.inline.}=
proc move*(p:var Point2d,v:Vector2d){.inline.}=
## Translates a point with vector `v` in place.
p.x+=v.x
p.y+=v.y
proc sgnArea*(a,b,c:TPoint2d):float=
proc sgnArea*(a,b,c:Point2d):float=
## Computes the signed area of the triangle thru points `a`,`b` and `c`
## result>0.0 for counter clockwise triangle
## result<0.0 for clockwise triangle
## This is commonly used to determinate side of a point with respect to a line.
return ((b.x - c.x) * (b.y - a.y)-(b.y - c.y) * (b.x - a.x))*0.5
proc area*(a,b,c:TPoint2d):float=
proc area*(a,b,c:Point2d):float=
## Computes the area of the triangle thru points `a`,`b` and `c`
return abs(sgnArea(a,b,c))
proc closestPoint*(p:TPoint2d,pts:varargs[TPoint2d]):TPoint2d=
proc closestPoint*(p:Point2d,pts:varargs[Point2d]):Point2d=
## Returns a point selected from `pts`, that has the closest
## euclidean distance to `p`
assert(pts.len>0) # must have at least one point

View file

@ -25,25 +25,25 @@ import times
##
## # Create a matrix which first rotates, then scales and at last translates
##
## var m:TMatrix3d=rotate(PI,vector3d(1,1,2.5)) & scale(2.0) & move(100.0,200.0,300.0)
## var m:Matrix3d=rotate(PI,vector3d(1,1,2.5)) & scale(2.0) & move(100.0,200.0,300.0)
##
## # Create a 3d point at (100,150,200) and a vector (5,2,3)
##
## var pt:TPoint3d=point3d(100.0,150.0,200.0)
## var pt:Point3d=point3d(100.0,150.0,200.0)
##
## var vec:TVector3d=vector3d(5.0,2.0,3.0)
## var vec:Vector3d=vector3d(5.0,2.0,3.0)
##
##
## pt &= m # transforms pt in place
##
## var pt2:TPoint3d=pt & m #concatenates pt with m and returns a new point
## var pt2:Point3d=pt & m #concatenates pt with m and returns a new point
##
## var vec2:TVector3d=vec & m #concatenates vec with m and returns a new vector
## var vec2:Vector3d=vec & m #concatenates vec with m and returns a new vector
type
TMatrix3d* =object
Matrix3d* =object
## Implements a row major 3d matrix, which means
## transformations are applied the order they are concatenated.
## This matrix is stored as an 4x4 matrix:
@ -52,31 +52,31 @@ type
## [ cx cy cz cw ]
## [ tx ty tz tw ]
ax*,ay*,az*,aw*, bx*,by*,bz*,bw*, cx*,cy*,cz*,cw*, tx*,ty*,tz*,tw*:float
TPoint3d* = object
Point3d* = object
## Implements a non-homegeneous 2d point stored as
## an `x` , `y` and `z` coordinate.
x*,y*,z*:float
TVector3d* = object
Vector3d* = object
## Implements a 3d **direction vector** stored as
## an `x` , `y` and `z` coordinate. Direction vector means,
## that when transforming a vector with a matrix, the translational
## part of the matrix is ignored.
x*,y*,z*:float
{.deprecated: [TMatrix3d: Matrix3d, TPoint3d: Point3d, TVector3d: Vector3d].}
# Some forward declarations
proc matrix3d*(ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw:float):TMatrix3d {.noInit.}
proc matrix3d*(ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw:float):Matrix3d {.noInit.}
## Creates a new 4x4 3d transformation matrix.
## `ax` , `ay` , `az` is the local x axis.
## `bx` , `by` , `bz` is the local y axis.
## `cx` , `cy` , `cz` is the local z axis.
## `tx` , `ty` , `tz` is the translation.
proc vector3d*(x,y,z:float):TVector3d {.noInit,inline.}
proc vector3d*(x,y,z:float):Vector3d {.noInit,inline.}
## Returns a new 3d vector (`x`,`y`,`z`)
proc point3d*(x,y,z:float):TPoint3d {.noInit,inline.}
proc point3d*(x,y,z:float):Point3d {.noInit,inline.}
## Returns a new 4d point (`x`,`y`,`z`)
proc tryNormalize*(v:var TVector3d):bool
proc tryNormalize*(v:var Vector3d):bool
## Modifies `v` to have a length of 1.0, keeping its angle.
## If `v` has zero length (and thus no angle), it is left unmodified and false is
## returned, otherwise true is returned.
@ -84,19 +84,19 @@ proc tryNormalize*(v:var TVector3d):bool
let
IDMATRIX*:TMatrix3d=matrix3d(
IDMATRIX*:Matrix3d=matrix3d(
1.0,0.0,0.0,0.0,
0.0,1.0,0.0,0.0,
0.0,0.0,1.0,0.0,
0.0,0.0,0.0,1.0)
## Quick access to a 3d identity matrix
ORIGO*:TPoint3d=point3d(0.0,0.0,0.0)
ORIGO*:Point3d=point3d(0.0,0.0,0.0)
## Quick access to point (0,0)
XAXIS*:TVector3d=vector3d(1.0,0.0,0.0)
XAXIS*:Vector3d=vector3d(1.0,0.0,0.0)
## Quick access to an 3d x-axis unit vector
YAXIS*:TVector3d=vector3d(0.0,1.0,0.0)
YAXIS*:Vector3d=vector3d(0.0,1.0,0.0)
## Quick access to an 3d y-axis unit vector
ZAXIS*:TVector3d=vector3d(0.0,0.0,1.0)
ZAXIS*:Vector3d=vector3d(0.0,0.0,1.0)
## Quick access to an 3d z-axis unit vector
@ -116,27 +116,27 @@ proc safeArccos(v:float):float=
template makeBinOpVector(s:expr)=
## implements binary operators + , - , * and / for vectors
proc s*(a,b:TVector3d):TVector3d {.inline,noInit.} =
proc s*(a,b:Vector3d):Vector3d {.inline,noInit.} =
vector3d(s(a.x,b.x),s(a.y,b.y),s(a.z,b.z))
proc s*(a:TVector3d,b:float):TVector3d {.inline,noInit.} =
proc s*(a:Vector3d,b:float):Vector3d {.inline,noInit.} =
vector3d(s(a.x,b),s(a.y,b),s(a.z,b))
proc s*(a:float,b:TVector3d):TVector3d {.inline,noInit.} =
proc s*(a:float,b:Vector3d):Vector3d {.inline,noInit.} =
vector3d(s(a,b.x),s(a,b.y),s(a,b.z))
template makeBinOpAssignVector(s:expr)=
## implements inplace binary operators += , -= , /= and *= for vectors
proc s*(a:var TVector3d,b:TVector3d) {.inline.} =
proc s*(a:var Vector3d,b:Vector3d) {.inline.} =
s(a.x,b.x) ; s(a.y,b.y) ; s(a.z,b.z)
proc s*(a:var TVector3d,b:float) {.inline.} =
proc s*(a:var Vector3d,b:float) {.inline.} =
s(a.x,b) ; s(a.y,b) ; s(a.z,b)
# ***************************************
# TMatrix3d implementation
# Matrix3d implementation
# ***************************************
proc setElements*(t:var TMatrix3d,ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw:float) {.inline.}=
proc setElements*(t:var Matrix3d,ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw:float) {.inline.}=
## Sets arbitrary elements in an exisitng matrix.
t.ax=ax
t.ay=ay
@ -155,10 +155,10 @@ proc setElements*(t:var TMatrix3d,ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,t
t.tz=tz
t.tw=tw
proc matrix3d*(ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw:float):TMatrix3d =
proc matrix3d*(ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw:float):Matrix3d =
result.setElements(ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw)
proc `&`*(a,b:TMatrix3d):TMatrix3d {.noinit.} =
proc `&`*(a,b:Matrix3d):Matrix3d {.noinit.} =
## Concatenates matrices returning a new matrix.
result.setElements(
a.aw*b.tx+a.az*b.cx+a.ay*b.bx+a.ax*b.ax,
@ -182,36 +182,36 @@ proc `&`*(a,b:TMatrix3d):TMatrix3d {.noinit.} =
a.tw*b.tw+a.tz*b.cw+a.ty*b.bw+a.tx*b.aw)
proc scale*(s:float):TMatrix3d {.noInit.} =
proc scale*(s:float):Matrix3d {.noInit.} =
## Returns a new scaling matrix.
result.setElements(s,0,0,0, 0,s,0,0, 0,0,s,0, 0,0,0,1)
proc scale*(s:float,org:TPoint3d):TMatrix3d {.noInit.} =
proc scale*(s:float,org:Point3d):Matrix3d {.noInit.} =
## Returns a new scaling matrix using, `org` as scale origin.
result.setElements(s,0,0,0, 0,s,0,0, 0,0,s,0,
org.x-s*org.x,org.y-s*org.y,org.z-s*org.z,1.0)
proc stretch*(sx,sy,sz:float):TMatrix3d {.noInit.} =
proc stretch*(sx,sy,sz:float):Matrix3d {.noInit.} =
## Returns new a stretch matrix, which is a
## scale matrix with non uniform scale in x,y and z.
result.setElements(sx,0,0,0, 0,sy,0,0, 0,0,sz,0, 0,0,0,1)
proc stretch*(sx,sy,sz:float,org:TPoint3d):TMatrix3d {.noInit.} =
proc stretch*(sx,sy,sz:float,org:Point3d):Matrix3d {.noInit.} =
## Returns a new stretch matrix, which is a
## scale matrix with non uniform scale in x,y and z.
## `org` is used as stretch origin.
result.setElements(sx,0,0,0, 0,sy,0,0, 0,0,sz,0, org.x-sx*org.x,org.y-sy*org.y,org.z-sz*org.z,1)
proc move*(dx,dy,dz:float):TMatrix3d {.noInit.} =
proc move*(dx,dy,dz:float):Matrix3d {.noInit.} =
## Returns a new translation matrix.
result.setElements(1,0,0,0, 0,1,0,0, 0,0,1,0, dx,dy,dz,1)
proc move*(v:TVector3d):TMatrix3d {.noInit.} =
proc move*(v:Vector3d):Matrix3d {.noInit.} =
## Returns a new translation matrix from a vector.
result.setElements(1,0,0,0, 0,1,0,0, 0,0,1,0, v.x,v.y,v.z,1)
proc rotate*(angle:float,axis:TVector3d):TMatrix3d {.noInit.}=
proc rotate*(angle:float,axis:Vector3d):Matrix3d {.noInit.}=
## Creates a rotation matrix that rotates `angle` radians over
## `axis`, which passes through origo.
@ -242,7 +242,7 @@ proc rotate*(angle:float,axis:TVector3d):TMatrix3d {.noInit.}=
uwomc+vsi, vwomc-usi, w2+(1.0-w2)*cs, 0.0,
0.0,0.0,0.0,1.0)
proc rotate*(angle:float,org:TPoint3d,axis:TVector3d):TMatrix3d {.noInit.}=
proc rotate*(angle:float,org:Point3d,axis:Vector3d):Matrix3d {.noInit.}=
## Creates a rotation matrix that rotates `angle` radians over
## `axis`, which passes through `org`.
@ -282,7 +282,7 @@ proc rotate*(angle:float,org:TPoint3d,axis:TVector3d):TMatrix3d {.noInit.}=
(c*(u2+v2)-w*(a*u+b*v))*omc+(a*v-b*u)*si,1.0)
proc rotateX*(angle:float):TMatrix3d {.noInit.}=
proc rotateX*(angle:float):Matrix3d {.noInit.}=
## Creates a matrix that rotates around the x-axis with `angle` radians,
## which is also called a 'roll' matrix.
let
@ -294,7 +294,7 @@ proc rotateX*(angle:float):TMatrix3d {.noInit.}=
0,-s,c,0,
0,0,0,1)
proc rotateY*(angle:float):TMatrix3d {.noInit.}=
proc rotateY*(angle:float):Matrix3d {.noInit.}=
## Creates a matrix that rotates around the y-axis with `angle` radians,
## which is also called a 'pitch' matrix.
let
@ -306,7 +306,7 @@ proc rotateY*(angle:float):TMatrix3d {.noInit.}=
s,0,c,0,
0,0,0,1)
proc rotateZ*(angle:float):TMatrix3d {.noInit.}=
proc rotateZ*(angle:float):Matrix3d {.noInit.}=
## Creates a matrix that rotates around the z-axis with `angle` radians,
## which is also called a 'yaw' matrix.
let
@ -318,7 +318,7 @@ proc rotateZ*(angle:float):TMatrix3d {.noInit.}=
0,0,1,0,
0,0,0,1)
proc isUniform*(m:TMatrix3d,tol=1.0e-6):bool=
proc isUniform*(m:Matrix3d,tol=1.0e-6):bool=
## Checks if the transform is uniform, that is
## perpendicular axes of equal length, which means (for example)
## it cannot transform a sphere into an ellipsoid.
@ -341,7 +341,7 @@ proc isUniform*(m:TMatrix3d,tol=1.0e-6):bool=
proc mirror*(planeperp:TVector3d):TMatrix3d {.noInit.}=
proc mirror*(planeperp:Vector3d):Matrix3d {.noInit.}=
## Creates a matrix that mirrors over the plane that has `planeperp` as normal,
## and passes through origo. `planeperp` does not need to be normalized.
@ -365,7 +365,7 @@ proc mirror*(planeperp:TVector3d):TMatrix3d {.noInit.}=
0,0,0,1)
proc mirror*(org:TPoint3d,planeperp:TVector3d):TMatrix3d {.noInit.}=
proc mirror*(org:Point3d,planeperp:Vector3d):Matrix3d {.noInit.}=
## Creates a matrix that mirrors over the plane that has `planeperp` as normal,
## and passes through `org`. `planeperp` does not need to be normalized.
@ -400,7 +400,7 @@ proc mirror*(org:TPoint3d,planeperp:TVector3d):TMatrix3d {.noInit.}=
2*(cc*tz+bc*ty+ac*tx) ,1)
proc determinant*(m:TMatrix3d):float=
proc determinant*(m:Matrix3d):float=
## Computes the determinant of matrix `m`.
# This computation is gotten from ratsimp(optimize(determinant(m)))
@ -419,7 +419,7 @@ proc determinant*(m:TMatrix3d):float=
(O3*m.az-O5*m.ay+O6*m.ax)*m.bw
proc inverse*(m:TMatrix3d):TMatrix3d {.noInit.}=
proc inverse*(m:Matrix3d):Matrix3d {.noInit.}=
## Computes the inverse of matrix `m`. If the matrix
## determinant is zero, thus not invertible, a EDivByZero
## will be raised.
@ -461,7 +461,7 @@ proc inverse*(m:TMatrix3d):TMatrix3d {.noInit.}=
(-m.ax*O7+m.ay*O14-m.az*O18)/det , (m.ax*O10-m.ay*O16+m.az*O19)/det)
proc equals*(m1:TMatrix3d,m2:TMatrix3d,tol=1.0e-6):bool=
proc equals*(m1:Matrix3d,m2:Matrix3d,tol=1.0e-6):bool=
## Checks if all elements of `m1`and `m2` is equal within
## a given tolerance `tol`.
return
@ -482,42 +482,42 @@ proc equals*(m1:TMatrix3d,m2:TMatrix3d,tol=1.0e-6):bool=
abs(m1.tz-m2.tz)<=tol and
abs(m1.tw-m2.tw)<=tol
proc `=~`*(m1,m2:TMatrix3d):bool=
proc `=~`*(m1,m2:Matrix3d):bool=
## Checks if `m1` and `m2` is approximately equal, using a
## tolerance of 1e-6.
equals(m1,m2)
proc transpose*(m:TMatrix3d):TMatrix3d {.noInit.}=
proc transpose*(m:Matrix3d):Matrix3d {.noInit.}=
## Returns the transpose of `m`
result.setElements(m.ax,m.bx,m.cx,m.tx,m.ay,m.by,m.cy,m.ty,m.az,m.bz,m.cz,m.tz,m.aw,m.bw,m.cw,m.tw)
proc getXAxis*(m:TMatrix3d):TVector3d {.noInit.}=
proc getXAxis*(m:Matrix3d):Vector3d {.noInit.}=
## Gets the local x axis of `m`
result.x=m.ax
result.y=m.ay
result.z=m.az
proc getYAxis*(m:TMatrix3d):TVector3d {.noInit.}=
proc getYAxis*(m:Matrix3d):Vector3d {.noInit.}=
## Gets the local y axis of `m`
result.x=m.bx
result.y=m.by
result.z=m.bz
proc getZAxis*(m:TMatrix3d):TVector3d {.noInit.}=
proc getZAxis*(m:Matrix3d):Vector3d {.noInit.}=
## Gets the local y axis of `m`
result.x=m.cx
result.y=m.cy
result.z=m.cz
proc `$`*(m:TMatrix3d):string=
proc `$`*(m:Matrix3d):string=
## String representation of `m`
return rtos(m.ax) & "," & rtos(m.ay) & "," & rtos(m.az) & "," & rtos(m.aw) &
"\n" & rtos(m.bx) & "," & rtos(m.by) & "," & rtos(m.bz) & "," & rtos(m.bw) &
"\n" & rtos(m.cx) & "," & rtos(m.cy) & "," & rtos(m.cz) & "," & rtos(m.cw) &
"\n" & rtos(m.tx) & "," & rtos(m.ty) & "," & rtos(m.tz) & "," & rtos(m.tw)
proc apply*(m:TMatrix3d, x,y,z:var float, translate=false)=
proc apply*(m:Matrix3d, x,y,z:var float, translate=false)=
## Applies transformation `m` onto `x` , `y` , `z` , optionally
## using the translation part of the matrix.
let
@ -535,18 +535,18 @@ proc apply*(m:TMatrix3d, x,y,z:var float, translate=false)=
z+=m.tz
# ***************************************
# TVector3d implementation
# Vector3d implementation
# ***************************************
proc vector3d*(x,y,z:float):TVector3d=
proc vector3d*(x,y,z:float):Vector3d=
result.x=x
result.y=y
result.z=z
proc len*(v:TVector3d):float=
proc len*(v:Vector3d):float=
## Returns the length of the vector `v`.
sqrt(v.x*v.x+v.y*v.y+v.z*v.z)
proc `len=`*(v:var TVector3d,newlen:float) {.noInit.} =
proc `len=`*(v:var Vector3d,newlen:float) {.noInit.} =
## Sets the length of the vector, keeping its direction.
## If the vector has zero length before changing it's length,
## an arbitrary vector of the requested length is returned.
@ -571,12 +571,12 @@ proc `len=`*(v:var TVector3d,newlen:float) {.noInit.} =
v.z*=fac
proc sqrLen*(v:TVector3d):float {.inline.}=
proc sqrLen*(v:Vector3d):float {.inline.}=
## Computes the squared length of the vector, which is
## faster than computing the absolute length.
return v.x*v.x+v.y*v.y+v.z*v.z
proc `$` *(v:TVector3d):string=
proc `$` *(v:Vector3d):string=
## String representation of `v`
result=rtos(v.x)
result.add(",")
@ -584,7 +584,7 @@ proc `$` *(v:TVector3d):string=
result.add(",")
result.add(rtos(v.z))
proc `&` *(v:TVector3d,m:TMatrix3d):TVector3d {.noInit.} =
proc `&` *(v:Vector3d,m:Matrix3d):Vector3d {.noInit.} =
## Concatenate vector `v` with a transformation matrix.
## Transforming a vector ignores the translational part
## of the matrix.
@ -601,7 +601,7 @@ proc `&` *(v:TVector3d,m:TMatrix3d):TVector3d {.noInit.} =
result.x=newx
proc `&=` *(v:var TVector3d,m:TMatrix3d) {.noInit.} =
proc `&=` *(v:var Vector3d,m:Matrix3d) {.noInit.} =
## Applies transformation `m` onto `v` in place.
## Transforming a vector ignores the translational part
## of the matrix.
@ -618,7 +618,7 @@ proc `&=` *(v:var TVector3d,m:TMatrix3d) {.noInit.} =
v.y=newy
v.x=newx
proc transformNorm*(v:var TVector3d,m:TMatrix3d)=
proc transformNorm*(v:var Vector3d,m:Matrix3d)=
## Applies a normal direction transformation `m` onto `v` in place.
## The resulting vector is *not* normalized. Transforming a vector ignores the
## translational part of the matrix. If the matrix is not invertible
@ -631,7 +631,7 @@ proc transformNorm*(v:var TVector3d,m:TMatrix3d)=
# (possibly by hardware) as well as having a consistent API with the 2d version.
v&=transpose(inverse(m))
proc transformInv*(v:var TVector3d,m:TMatrix3d)=
proc transformInv*(v:var Vector3d,m:Matrix3d)=
## Applies the inverse of `m` on vector `v`. Transforming a vector ignores
## the translational part of the matrix. Transforming a vector ignores the
## translational part of the matrix.
@ -642,7 +642,7 @@ proc transformInv*(v:var TVector3d,m:TMatrix3d)=
# (possibly by hardware) as well as having a consistent API with the 2d version.
v&=m.inverse
proc transformNormInv*(vec:var TVector3d,m:TMatrix3d)=
proc transformNormInv*(vec:var Vector3d,m:Matrix3d)=
## Applies an inverse normal direction transformation `m` onto `v` in place.
## This is faster than creating an inverse
## matrix and transformNorm(...) it. Transforming a vector ignores the
@ -651,7 +651,7 @@ proc transformNormInv*(vec:var TVector3d,m:TMatrix3d)=
# see vector2d:s equivalent for a deeper look how/why this works
vec&=m.transpose
proc tryNormalize*(v:var TVector3d):bool=
proc tryNormalize*(v:var Vector3d):bool=
## Modifies `v` to have a length of 1.0, keeping its angle.
## If `v` has zero length (and thus no angle), it is left unmodified and false is
## returned, otherwise true is returned.
@ -666,13 +666,13 @@ proc tryNormalize*(v:var TVector3d):bool=
return true
proc normalize*(v:var TVector3d) {.inline.}=
proc normalize*(v:var Vector3d) {.inline.}=
## Modifies `v` to have a length of 1.0, keeping its angle.
## If `v` has zero length, an EDivByZero will be raised.
if not tryNormalize(v):
raise newException(DivByZeroError,"Cannot normalize zero length vector")
proc rotate*(vec:var TVector3d,angle:float,axis:TVector3d)=
proc rotate*(vec:var Vector3d,angle:float,axis:Vector3d)=
## Rotates `vec` in place, with `angle` radians over `axis`, which passes
## through origo.
@ -699,19 +699,19 @@ proc rotate*(vec:var TVector3d,angle:float,axis:TVector3d)=
vec.y=v*uxyzomc+y*cs+(w*x-u*z)*si
vec.z=w*uxyzomc+z*cs+(u*y-v*x)*si
proc scale*(v:var TVector3d,s:float)=
proc scale*(v:var Vector3d,s:float)=
## Scales the vector in place with factor `s`
v.x*=s
v.y*=s
v.z*=s
proc stretch*(v:var TVector3d,sx,sy,sz:float)=
proc stretch*(v:var Vector3d,sx,sy,sz:float)=
## Scales the vector non uniformly with factors `sx` , `sy` , `sz`
v.x*=sx
v.y*=sy
v.z*=sz
proc mirror*(v:var TVector3d,planeperp:TVector3d)=
proc mirror*(v:var Vector3d,planeperp:Vector3d)=
## Computes the mirrored vector of `v` over the plane
## that has `planeperp` as normal direction.
## `planeperp` does not need to be normalized.
@ -735,7 +735,7 @@ proc mirror*(v:var TVector3d,planeperp:TVector3d)=
v.z= -2*(c*c*z+bc*y+ac*x)+z
proc `-` *(v:TVector3d):TVector3d=
proc `-` *(v:Vector3d):Vector3d=
## Negates a vector
result.x= -v.x
result.y= -v.y
@ -751,12 +751,12 @@ makeBinOpAssignVector(`-=`)
makeBinOpAssignVector(`*=`)
makeBinOpAssignVector(`/=`)
proc dot*(v1,v2:TVector3d):float {.inline.}=
proc dot*(v1,v2:Vector3d):float {.inline.}=
## Computes the dot product of two vectors.
## Returns 0.0 if the vectors are perpendicular.
return v1.x*v2.x+v1.y*v2.y+v1.z*v2.z
proc cross*(v1,v2:TVector3d):TVector3d {.inline.}=
proc cross*(v1,v2:Vector3d):Vector3d {.inline.}=
## Computes the cross product of two vectors.
## The result is a vector which is perpendicular
## to the plane of `v1` and `v2`, which means
@ -766,16 +766,16 @@ proc cross*(v1,v2:TVector3d):TVector3d {.inline.}=
result.y = (v1.z * v2.x) - (v2.z * v1.x)
result.z = (v1.x * v2.y) - (v2.x * v1.y)
proc equals*(v1,v2:TVector3d,tol=1.0e-6):bool=
proc equals*(v1,v2:Vector3d,tol=1.0e-6):bool=
## Checks if two vectors approximately equals with a tolerance.
return abs(v2.x-v1.x)<=tol and abs(v2.y-v1.y)<=tol and abs(v2.z-v1.z)<=tol
proc `=~` *(v1,v2:TVector3d):bool=
proc `=~` *(v1,v2:Vector3d):bool=
## Checks if two vectors approximately equals with a
## hardcoded tolerance 1e-6
equals(v1,v2)
proc angleTo*(v1,v2:TVector3d):float=
proc angleTo*(v1,v2:Vector3d):float=
## Returns the smallest angle between v1 and v2,
## which is in range 0-PI
var
@ -785,13 +785,13 @@ proc angleTo*(v1,v2:TVector3d):float=
return 0.0 # zero length vector has zero angle to any other vector
return safeArccos(dot(nv1,nv2))
proc arbitraryAxis*(norm:TVector3d):TMatrix3d {.noInit.}=
proc arbitraryAxis*(norm:Vector3d):Matrix3d {.noInit.}=
## Computes the rotation matrix that would transform
## world z vector into `norm`. The inverse of this matrix
## is useful to transform a planar 3d object to 2d space.
## This is the same algorithm used to interpret DXF and DWG files.
const lim=1.0/64.0
var ax,ay,az:TVector3d
var ax,ay,az:Vector3d
if abs(norm.x)<lim and abs(norm.y)<lim:
ax=cross(YAXIS,norm)
else:
@ -808,7 +808,7 @@ proc arbitraryAxis*(norm:TVector3d):TMatrix3d {.noInit.}=
az.x,az.y,az.z,0.0,
0.0,0.0,0.0,1.0)
proc bisect*(v1,v2:TVector3d):TVector3d {.noInit.}=
proc bisect*(v1,v2:Vector3d):Vector3d {.noInit.}=
## Computes the bisector between v1 and v2 as a normalized vector.
## If one of the input vectors has zero length, a normalized version
## of the other is returned. If both input vectors has zero length,
@ -851,25 +851,25 @@ proc bisect*(v1,v2:TVector3d):TVector3d {.noInit.}=
# ***************************************
# TPoint3d implementation
# Point3d implementation
# ***************************************
proc point3d*(x,y,z:float):TPoint3d=
proc point3d*(x,y,z:float):Point3d=
result.x=x
result.y=y
result.z=z
proc sqrDist*(a,b:TPoint3d):float=
proc sqrDist*(a,b:Point3d):float=
## Computes the squared distance between `a`and `b`
let dx=b.x-a.x
let dy=b.y-a.y
let dz=b.z-a.z
result=dx*dx+dy*dy+dz*dz
proc dist*(a,b:TPoint3d):float {.inline.}=
proc dist*(a,b:Point3d):float {.inline.}=
## Computes the absolute distance between `a`and `b`
result=sqrt(sqrDist(a,b))
proc `$` *(p:TPoint3d):string=
proc `$` *(p:Point3d):string=
## String representation of `p`
result=rtos(p.x)
result.add(",")
@ -877,14 +877,14 @@ proc `$` *(p:TPoint3d):string=
result.add(",")
result.add(rtos(p.z))
proc `&`*(p:TPoint3d,m:TMatrix3d):TPoint3d=
proc `&`*(p:Point3d,m:Matrix3d):Point3d=
## Concatenates a point `p` with a transform `m`,
## resulting in a new, transformed point.
result.z=m.cz*p.z+m.bz*p.y+m.az*p.x+m.tz
result.y=m.cy*p.z+m.by*p.y+m.ay*p.x+m.ty
result.x=m.cx*p.z+m.bx*p.y+m.ax*p.x+m.tx
proc `&=` *(p:var TPoint3d,m:TMatrix3d)=
proc `&=` *(p:var Point3d,m:Matrix3d)=
## Applies transformation `m` onto `p` in place.
let
x=p.x
@ -894,7 +894,7 @@ proc `&=` *(p:var TPoint3d,m:TMatrix3d)=
p.y=m.cy*z+m.by*y+m.ay*x+m.ty
p.z=m.cz*z+m.bz*y+m.az*x+m.tz
proc transformInv*(p:var TPoint3d,m:TMatrix3d)=
proc transformInv*(p:var Point3d,m:Matrix3d)=
## Applies the inverse of transformation `m` onto `p` in place.
## If the matrix is not invertable (determinant=0) , EDivByZero will
## be raised.
@ -903,48 +903,48 @@ proc transformInv*(p:var TPoint3d,m:TMatrix3d)=
p&=inverse(m)
proc `+`*(p:TPoint3d,v:TVector3d):TPoint3d {.noInit,inline.} =
proc `+`*(p:Point3d,v:Vector3d):Point3d {.noInit,inline.} =
## Adds a vector `v` to a point `p`, resulting
## in a new point.
result.x=p.x+v.x
result.y=p.y+v.y
result.z=p.z+v.z
proc `+=`*(p:var TPoint3d,v:TVector3d) {.noInit,inline.} =
proc `+=`*(p:var Point3d,v:Vector3d) {.noInit,inline.} =
## Adds a vector `v` to a point `p` in place.
p.x+=v.x
p.y+=v.y
p.z+=v.z
proc `-`*(p:TPoint3d,v:TVector3d):TPoint3d {.noInit,inline.} =
proc `-`*(p:Point3d,v:Vector3d):Point3d {.noInit,inline.} =
## Subtracts a vector `v` from a point `p`, resulting
## in a new point.
result.x=p.x-v.x
result.y=p.y-v.y
result.z=p.z-v.z
proc `-`*(p1,p2:TPoint3d):TVector3d {.noInit,inline.} =
proc `-`*(p1,p2:Point3d):Vector3d {.noInit,inline.} =
## Subtracts `p2`from `p1` resulting in a difference vector.
result.x=p1.x-p2.x
result.y=p1.y-p2.y
result.z=p1.z-p2.z
proc `-=`*(p:var TPoint3d,v:TVector3d) {.noInit,inline.} =
proc `-=`*(p:var Point3d,v:Vector3d) {.noInit,inline.} =
## Subtracts a vector `v` from a point `p` in place.
p.x-=v.x
p.y-=v.y
p.z-=v.z
proc equals(p1,p2:TPoint3d,tol=1.0e-6):bool {.inline.}=
proc equals(p1,p2:Point3d,tol=1.0e-6):bool {.inline.}=
## Checks if two points approximately equals with a tolerance.
return abs(p2.x-p1.x)<=tol and abs(p2.y-p1.y)<=tol and abs(p2.z-p1.z)<=tol
proc `=~`*(p1,p2:TPoint3d):bool {.inline.}=
proc `=~`*(p1,p2:Point3d):bool {.inline.}=
## Checks if two vectors approximately equals with a
## hardcoded tolerance 1e-6
equals(p1,p2)
proc rotate*(p:var TPoint3d,rad:float,axis:TVector3d)=
proc rotate*(p:var Point3d,rad:float,axis:Vector3d)=
## Rotates point `p` in place `rad` radians about an axis
## passing through origo.
@ -954,7 +954,7 @@ proc rotate*(p:var TPoint3d,rad:float,axis:TVector3d)=
p.y=v.y
p.z=v.z
proc rotate*(p:var TPoint3d,angle:float,org:TPoint3d,axis:TVector3d)=
proc rotate*(p:var Point3d,angle:float,org:Point3d,axis:Vector3d)=
## Rotates point `p` in place `rad` radians about an axis
## passing through `org`
@ -992,26 +992,26 @@ proc rotate*(p:var TPoint3d,angle:float,org:TPoint3d,axis:TVector3d)=
p.y=(b*(uu+ww)-v*(au+cw-uxmvymwz))*omc + y*cs + (c*u-a*w+w*x-u*z)*si
p.z=(c*(uu+vv)-w*(au+bv-uxmvymwz))*omc + z*cs + (a*v+u*y-b*u-v*x)*si
proc scale*(p:var TPoint3d,fac:float) {.inline.}=
proc scale*(p:var Point3d,fac:float) {.inline.}=
## Scales a point in place `fac` times with world origo as origin.
p.x*=fac
p.y*=fac
p.z*=fac
proc scale*(p:var TPoint3d,fac:float,org:TPoint3d){.inline.}=
proc scale*(p:var Point3d,fac:float,org:Point3d){.inline.}=
## Scales the point in place `fac` times with `org` as origin.
p.x=(p.x - org.x) * fac + org.x
p.y=(p.y - org.y) * fac + org.y
p.z=(p.z - org.z) * fac + org.z
proc stretch*(p:var TPoint3d,facx,facy,facz:float){.inline.}=
proc stretch*(p:var Point3d,facx,facy,facz:float){.inline.}=
## Scales a point in place non uniformly `facx` , `facy` , `facz` times
## with world origo as origin.
p.x*=facx
p.y*=facy
p.z*=facz
proc stretch*(p:var TPoint3d,facx,facy,facz:float,org:TPoint3d){.inline.}=
proc stretch*(p:var Point3d,facx,facy,facz:float,org:Point3d){.inline.}=
## Scales the point in place non uniformly `facx` , `facy` , `facz` times
## with `org` as origin.
p.x=(p.x - org.x) * facx + org.x
@ -1019,19 +1019,19 @@ proc stretch*(p:var TPoint3d,facx,facy,facz:float,org:TPoint3d){.inline.}=
p.z=(p.z - org.z) * facz + org.z
proc move*(p:var TPoint3d,dx,dy,dz:float){.inline.}=
proc move*(p:var Point3d,dx,dy,dz:float){.inline.}=
## Translates a point `dx` , `dy` , `dz` in place.
p.x+=dx
p.y+=dy
p.z+=dz
proc move*(p:var TPoint3d,v:TVector3d){.inline.}=
proc move*(p:var Point3d,v:Vector3d){.inline.}=
## Translates a point with vector `v` in place.
p.x+=v.x
p.y+=v.y
p.z+=v.z
proc area*(a,b,c:TPoint3d):float {.inline.}=
proc area*(a,b,c:Point3d):float {.inline.}=
## Computes the area of the triangle thru points `a` , `b` and `c`
# The area of a planar 3d quadliteral is the magnitude of the cross

View file

@ -46,24 +46,25 @@ const
when sizeof(int) == 4: # 32bit
type
TRaw = range[0..1073741823]
Raw = range[0..1073741823]
## The range of uint values that can be stored directly in a value slot
## when on a 32 bit platform
{.deprecated: [TRaw: Raw].}
elif sizeof(int) == 8: # 64bit
type
TRaw = range[0..4611686018427387903]
Raw = range[0..4611686018427387903]
## The range of uint values that can be stored directly in a value slot
## when on a 64 bit platform
{.deprecated: [TRaw: Raw].}
else:
{.error: "unsupported platform".}
type
TEntry = tuple
Entry = tuple
key: int
value: int
TEntryArr = ptr array[0..10_000_000, TEntry]
EntryArr = ptr array[0..10_000_000, Entry]
PConcTable[K,V] = ptr object {.pure.}
len: int
@ -72,8 +73,8 @@ type
copyIdx: int
copyDone: int
next: PConcTable[K,V]
data: TEntryArr
data: EntryArr
{.deprecated: [TEntry: Entry, TEntryArr: EntryArr.}
proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
expVal: int, match: bool): int
@ -84,7 +85,7 @@ proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
proc newLFTable*[K,V](size: int = minTableSize): PConcTable[K,V] =
let
dataLen = max(nextPowerOfTwo(size), minTableSize)
dataSize = dataLen*sizeof(TEntry)
dataSize = dataLen*sizeof(Entry)
dataMem = allocShared0(dataSize)
tableSize = 7 * intSize
tableMem = allocShared0(tableSize)
@ -95,7 +96,7 @@ proc newLFTable*[K,V](size: int = minTableSize): PConcTable[K,V] =
table.copyIdx = 0
table.copyDone = 0
table.next = nil
table.data = cast[TEntryArr](dataMem)
table.data = cast[EntryArr](dataMem)
result = table
#------------------------------------------------------------------------------
@ -107,7 +108,7 @@ proc deleteConcTable[K,V](tbl: PConcTable[K,V]) =
#------------------------------------------------------------------------------
proc `[]`[K,V](table: var PConcTable[K,V], i: int): var TEntry {.inline.} =
proc `[]`[K,V](table: var PConcTable[K,V], i: int): var Entry {.inline.} =
table.data[i]
#------------------------------------------------------------------------------
@ -191,7 +192,7 @@ proc resize[K,V](self: PConcTable[K,V]): PConcTable[K,V] =
#proc keyEQ[K](key1: ptr K, key2: ptr K): bool {.inline.} =
proc keyEQ[K](key1: int, key2: int): bool {.inline.} =
result = false
when K is TRaw:
when K is Raw:
if key1 == key2:
result = true
else:
@ -236,7 +237,7 @@ proc copySlot[K,V](idx: int, oldTbl: var PConcTable[K,V], newTbl: var PConcTable
break
#echo("oldVal was = ", oldVal, " set it to prime ", box)
if isPrime(oldVal) and isTomb(oldVal):
#when not (K is TRaw):
#when not (K is Raw):
# deallocShared(popPtr[K](oldKey))
return false
if isTomb(oldVal):
@ -343,7 +344,7 @@ proc helpCopy[K,V](table: var PConcTable[K,V]): PConcTable[K,V] =
proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
expVal: int, match: bool): int =
#echo("-try set- in table ", " key = ", (popPtr[K](key)[]), " val = ", val)
when K is TRaw:
when K is Raw:
var idx = hashInt(key)
else:
var idx = popPtr[K](key)[].hash
@ -428,7 +429,7 @@ proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
proc getVal[K,V](table: var PConcTable[K,V], key: int): int =
#echo("-try get- key = " & $key)
when K is TRaw:
when K is Raw:
var idx = hashInt(key)
else:
var idx = popPtr[K](key)[].hash
@ -468,37 +469,37 @@ proc getVal[K,V](table: var PConcTable[K,V], key: int): int =
#------------------------------------------------------------------------------
#proc set*(table: var PConcTable[TRaw,TRaw], key: TRaw, val: TRaw) =
#proc set*(table: var PConcTable[Raw,Raw], key: Raw, val: Raw) =
# discard setVal(table, pack(key), pack(key), 0, false)
#proc set*[V](table: var PConcTable[TRaw,V], key: TRaw, val: ptr V) =
#proc set*[V](table: var PConcTable[Raw,V], key: Raw, val: ptr V) =
# discard setVal(table, pack(key), cast[int](val), 0, false)
proc set*[K,V](table: var PConcTable[K,V], key: var K, val: var V) =
when not (K is TRaw):
when not (K is Raw):
var newKey = cast[int](copyShared(key))
else:
var newKey = pack(key)
when not (V is TRaw):
when not (V is Raw):
var newVal = cast[int](copyShared(val))
else:
var newVal = pack(val)
var oldPtr = pop(setVal(table, newKey, newVal, 0, false))
#echo("oldPtr = ", cast[int](oldPtr), " newPtr = ", cast[int](newPtr))
when not (V is TRaw):
when not (V is Raw):
if newVal != oldPtr and oldPtr != 0:
deallocShared(cast[ptr V](oldPtr))
proc get*[K,V](table: var PConcTable[K,V], key: var K): V =
when not (V is TRaw):
when not (K is TRaw):
when not (V is Raw):
when not (K is Raw):
return popPtr[V](getVal(table, cast[int](key.addr)))[]
else:
return popPtr[V](getVal(table, pack(key)))[]
else:
when not (K is TRaw):
when not (K is Raw):
return popRaw(getVal(table, cast[int](key.addr)))
else:
return popRaw(getVal(table, pack(key)))
@ -535,23 +536,24 @@ when not defined(testing) and isMainModule:
type
TTestObj = tuple
TestObj = tuple
thr: int
f0: int
f1: int
TData = tuple[k: string,v: TTestObj]
PDataArr = array[0..numTests-1, TData]
Dict = PConcTable[string,TTestObj]
Data = tuple[k: string,v: TestObj]
PDataArr = array[0..numTests-1, Data]
Dict = PConcTable[string,TestObj]
{.deprecated: [TTestObj: TestObj, TData: Data].}
var
thr: array[0..numThreads-1, TThread[Dict]]
thr: array[0..numThreads-1, Thread[Dict]]
table = newLFTable[string,TTestObj](8)
table = newLFTable[string,TestObj](8)
rand = newMersenneTwister(2525)
proc createSampleData(len: int): PDataArr =
#result = cast[PDataArr](allocShared0(sizeof(TData)*numTests))
#result = cast[PDataArr](allocShared0(sizeof(Data)*numTests))
for i in 0..len-1:
result[i].k = "mark" & $(i+1)
#echo("mark" & $(i+1), " ", hash("mark" & $(i+1)))

View file

@ -30,25 +30,25 @@ const
IntMask = 1 shl IntShift - 1
type
PTrunk = ref TTrunk
TTrunk {.final.} = object
PTrunk = ref Trunk
Trunk {.final.} = object
next: PTrunk # all nodes are connected with this pointer
key: int # start address at bit 0
bits: array[0..IntsPerTrunk - 1, BitScalar] # a bit vector
TTrunkSeq = seq[PTrunk]
TrunkSeq = seq[PTrunk]
IntSet* = object ## an efficient set of 'int' implemented as a sparse bit set
counter, max: int
head: PTrunk
data: TTrunkSeq
data: TrunkSeq
{.deprecated: [TIntSet: IntSet].}
{.deprecated: [TIntSet: IntSet, TTrunk: Trunk, TTrunkSeq: TrunkSeq].}
proc mustRehash(length, counter: int): bool {.inline.} =
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)
proc nextTry(h, maxHash: THash): THash {.inline.} =
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
result = ((5 * h) + 1) and maxHash
proc intSetGet(t: IntSet, key: int): PTrunk =
@ -59,7 +59,7 @@ proc intSetGet(t: IntSet, key: int): PTrunk =
h = nextTry(h, t.max)
result = nil
proc intSetRawInsert(t: IntSet, data: var TTrunkSeq, desc: PTrunk) =
proc intSetRawInsert(t: IntSet, data: var TrunkSeq, desc: PTrunk) =
var h = desc.key and t.max
while data[h] != nil:
assert(data[h] != desc)
@ -68,7 +68,7 @@ proc intSetRawInsert(t: IntSet, data: var TTrunkSeq, desc: PTrunk) =
data[h] = desc
proc intSetEnlarge(t: var IntSet) =
var n: TTrunkSeq
var n: TrunkSeq
var oldMax = t.max
t.max = ((t.max + 1) * 2) - 1
newSeq(n, t.max + 1)

View file

@ -29,7 +29,7 @@ when not defined(nimhygiene):
# codes should never be needed, and this can pack more entries per cache-line.
# Losing hcode entirely is also possible - if some element value is forbidden.
type
KeyValuePair[A] = tuple[hcode: THash, key: A]
KeyValuePair[A] = tuple[hcode: Hash, key: A]
KeyValuePairSeq[A] = seq[KeyValuePair[A]]
HashSet* {.myShallow.}[A] = object ## \
## A generic hash set.
@ -43,10 +43,10 @@ type
# 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.} =
proc isEmpty(hcode: Hash): bool {.inline.} =
result = hcode == 0
proc isFilled(hcode: THash): bool {.inline.} =
proc isFilled(hcode: Hash): bool {.inline.} =
result = hcode != 0
proc isValid*[A](s: HashSet[A]): bool =
@ -58,7 +58,7 @@ proc isValid*[A](s: HashSet[A]): bool =
## initialized. Example:
##
## .. code-block ::
## proc savePreferences(options: TSet[string]) =
## proc savePreferences(options: Set[string]) =
## assert options.isValid, "Pass an initialized set!"
## # Do stuff here, may crash in release builds!
result = not s.data.isNil
@ -72,7 +72,7 @@ proc len*[A](s: HashSet[A]): int =
##
## .. code-block::
##
## var values: TSet[int]
## var values: Set[int]
## assert(not values.isValid)
## assert values.len == 0
result = s.counter
@ -123,15 +123,15 @@ proc rightSize*(count: Natural): int {.inline.} =
## Internally, we want mustRehash(rightSize(x), x) == false.
result = nextPowerOfTwo(count * 3 div 2 + 4)
proc nextTry(h, maxHash: THash): THash {.inline.} =
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
result = (h + 1) and maxHash
template rawGetKnownHCImpl() {.dirty.} =
var h: THash = hc and high(s.data) # start with real hash value
var h: Hash = hc and high(s.data) # start with real hash value
while isFilled(s.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
# It does slow down succeeding lookups by one extra Hash cmp&and..usually
# just a few clock cycles, generally worth it for any non-integer-like A.
if s.data[h].hcode == hc and s.data[h].key == key: # compare hc THEN key
return h
@ -148,10 +148,10 @@ template rawInsertImpl() {.dirty.} =
data[h].key = key
data[h].hcode = hc
proc rawGetKnownHC[A](s: HashSet[A], key: A, hc: THash): int {.inline.} =
proc rawGetKnownHC[A](s: HashSet[A], key: A, hc: Hash): int {.inline.} =
rawGetKnownHCImpl()
proc rawGet[A](s: HashSet[A], key: A, hc: var THash): int {.inline.} =
proc rawGet[A](s: HashSet[A], key: A, hc: var Hash): int {.inline.} =
rawGetImpl()
proc mget*[A](s: var HashSet[A], key: A): var A =
@ -160,7 +160,7 @@ proc mget*[A](s: var HashSet[A], key: A): var A =
## when one overloaded 'hash' and '==' but still needs reference semantics
## for sharing.
assert s.isValid, "The set needs to be initialized."
var hc: THash
var hc: Hash
var index = rawGet(s, key, hc)
if index >= 0: result = s.data[index].key
else: raise newException(KeyError, "key not found: " & $key)
@ -178,12 +178,12 @@ proc contains*[A](s: HashSet[A], key: A): bool =
## values.excl(2)
## assert(not values.contains(2))
assert s.isValid, "The set needs to be initialized."
var hc: THash
var hc: Hash
var index = rawGet(s, key, hc)
result = index >= 0
proc rawInsert[A](s: var HashSet[A], data: var KeyValuePairSeq[A], key: A,
hc: THash, h: THash) =
hc: Hash, h: Hash) =
rawInsertImpl()
proc enlarge[A](s: var HashSet[A]) =
@ -196,7 +196,7 @@ proc enlarge[A](s: var HashSet[A]) =
rawInsert(s, s.data, n[i].key, n[i].hcode, j)
template inclImpl() {.dirty.} =
var hc: THash
var hc: Hash
var index = rawGet(s, key, hc)
if index < 0:
if mustRehash(len(s.data), s.counter):
@ -206,7 +206,7 @@ template inclImpl() {.dirty.} =
inc(s.counter)
template containsOrInclImpl() {.dirty.} =
var hc: THash
var hc: Hash
var index = rawGet(s, key, hc)
if index >= 0:
result = true
@ -261,7 +261,7 @@ proc excl*[A](s: var HashSet[A], key: A) =
## s.excl(2)
## assert s.len == 3
assert s.isValid, "The set needs to be initialized."
var hc: THash
var hc: Hash
var i = rawGet(s, key, hc)
var msk = high(s.data)
if i >= 0:
@ -323,7 +323,7 @@ proc init*[A](s: var HashSet[A], initialSize=64) =
## existing values and calling `excl() <#excl,TSet[A],A>`_ on them. Example:
##
## .. code-block ::
## var a: TSet[int]
## var a: Set[int]
## a.init(4)
## a.incl(2)
## a.init
@ -552,7 +552,7 @@ proc map*[A, B](data: HashSet[A], op: proc (x: A): B {.closure.}): HashSet[B] =
type
OrderedKeyValuePair[A] = tuple[
hcode: THash, next: int, key: A]
hcode: Hash, next: int, key: A]
OrderedKeyValuePairSeq[A] = seq[OrderedKeyValuePair[A]]
OrderedSet* {.myShallow.}[A] = object ## \
## A generic hash set that remembers insertion order.
@ -574,7 +574,7 @@ proc isValid*[A](s: OrderedSet[A]): bool =
## correctly initialized. Example:
##
## .. code-block::
## proc saveTarotCards(cards: TOrderedSet[int]) =
## proc saveTarotCards(cards: OrderedSet[int]) =
## assert cards.isValid, "Pass an initialized set!"
## # Do stuff here, may crash in release builds!
result = not s.data.isNil
@ -588,7 +588,7 @@ proc len*[A](s: OrderedSet[A]): int {.inline.} =
##
## .. code-block::
##
## var values: TOrderedSet[int]
## var values: OrderedSet[int]
## assert(not values.isValid)
## assert values.len == 0
result = s.counter
@ -629,10 +629,10 @@ iterator items*[A](s: OrderedSet[A]): A =
forAllOrderedPairs:
yield s.data[h].key
proc rawGetKnownHC[A](s: OrderedSet[A], key: A, hc: THash): int {.inline.} =
proc rawGetKnownHC[A](s: OrderedSet[A], key: A, hc: Hash): int {.inline.} =
rawGetKnownHCImpl()
proc rawGet[A](s: OrderedSet[A], key: A, hc: var THash): int {.inline.} =
proc rawGet[A](s: OrderedSet[A], key: A, hc: var Hash): int {.inline.} =
rawGetImpl()
proc contains*[A](s: OrderedSet[A], key: A): bool =
@ -646,12 +646,12 @@ proc contains*[A](s: OrderedSet[A], key: A): bool =
## values.incl(2)
## assert values.contains(2)
assert s.isValid, "The set needs to be initialized."
var hc: THash
var hc: Hash
var index = rawGet(s, key, hc)
result = index >= 0
proc rawInsert[A](s: var OrderedSet[A], data: var OrderedKeyValuePairSeq[A],
key: A, hc: THash, h: THash) =
key: A, hc: Hash, h: Hash) =
rawInsertImpl()
data[h].next = -1
if s.first < 0: s.first = h
@ -729,7 +729,7 @@ proc init*[A](s: var OrderedSet[A], initialSize=64) =
## from an ordered hash set. Example:
##
## .. code-block ::
## var a: TOrderedSet[int]
## var a: OrderedSet[int]
## a.init(4)
## a.incl(2)
## a.init

View file

@ -24,13 +24,13 @@
##
## Error: type mismatch: got (Person)
## but expected one of:
## hashes.hash(x: openarray[A]): THash
## hashes.hash(x: int): THash
## hashes.hash(x: float): THash
## hashes.hash(x: openarray[A]): Hash
## hashes.hash(x: int): Hash
## hashes.hash(x: float): Hash
## …
##
## What is happening here is that the types used for table keys require to have
## a ``hash()`` proc which will convert them to a `THash <hashes.html#THash>`_
## a ``hash()`` proc which will convert them to a `Hash <hashes.html#Hash>`_
## value, and the compiler is listing all the hash functions it knows.
## Additionally there has to be a ``==`` operator that provides the same
## semantics as its corresponding ``hash`` proc.
@ -46,7 +46,7 @@
## Person = object
## firstName, lastName: string
##
## proc hash(x: Person): THash =
## proc hash(x: Person): Hash =
## ## Piggyback on the already available string hash proc.
## ##
## ## Without this proc nothing works!
@ -71,7 +71,7 @@ import
{.pragma: myShallow.}
type
KeyValuePair[A, B] = tuple[hcode: THash, key: A, val: B]
KeyValuePair[A, B] = tuple[hcode: Hash, key: A, val: B]
KeyValuePairSeq[A, B] = seq[KeyValuePair[A, B]]
Table* {.myShallow.}[A, B] = object ## generic hash table
data: KeyValuePairSeq[A, B]
@ -85,10 +85,10 @@ when not defined(nimhygiene):
# 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.} =
proc isEmpty(hcode: Hash): bool {.inline.} =
result = hcode == 0
proc isFilled(hcode: THash): bool {.inline.} =
proc isFilled(hcode: Hash): bool {.inline.} =
result = hcode != 0
proc len*[A, B](t: Table[A, B]): int =
@ -137,15 +137,15 @@ proc rightSize*(count: Natural): int {.inline.} =
## Internally, we want mustRehash(rightSize(x), x) == false.
result = nextPowerOfTwo(count * 3 div 2 + 4)
proc nextTry(h, maxHash: THash): THash {.inline.} =
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
result = (h + 1) and maxHash
template rawGetKnownHCImpl() {.dirty.} =
var h: THash = hc and high(t.data) # start with real hash value
var h: Hash = 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
# It does slow down succeeding lookups by one extra Hash 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
@ -162,7 +162,7 @@ template rawGetDeepImpl() {.dirty.} = # Search algo for unconditional add
hc = hash(key)
if hc == 0:
hc = 314159265
var h: THash = hc and high(t.data)
var h: Hash = hc and high(t.data)
while isFilled(t.data[h].hcode):
h = nextTry(h, high(t.data))
result = h
@ -172,13 +172,13 @@ template rawInsertImpl() {.dirty.} =
data[h].val = val
data[h].hcode = hc
proc rawGetKnownHC[A, B](t: Table[A, B], key: A, hc: THash): int {.inline.} =
proc rawGetKnownHC[A, B](t: Table[A, B], key: A, hc: Hash): int {.inline.} =
rawGetKnownHCImpl()
proc rawGetDeep[A, B](t: Table[A, B], key: A, hc: var THash): int {.inline.} =
proc rawGetDeep[A, B](t: Table[A, B], key: A, hc: var Hash): int {.inline.} =
rawGetDeepImpl()
proc rawGet[A, B](t: Table[A, B], key: A, hc: var THash): int {.inline.} =
proc rawGet[A, B](t: Table[A, B], key: A, hc: var Hash): int {.inline.} =
rawGetImpl()
proc `[]`*[A, B](t: Table[A, B], key: A): B =
@ -186,14 +186,14 @@ proc `[]`*[A, B](t: Table[A, B], key: A): B =
## default empty value for the type `B` is returned
## and no exception is raised. One can check with ``hasKey`` whether the key
## exists.
var hc: THash
var hc: Hash
var index = rawGet(t, key, hc)
if index >= 0: result = t.data[index].val
proc mget*[A, B](t: var Table[A, B], key: A): var B =
## retrieves the value at ``t[key]``. The value can be modified.
## If `key` is not in `t`, the ``KeyError`` exception is raised.
var hc: THash
var hc: Hash
var index = rawGet(t, key, hc)
if index >= 0: result = t.data[index].val
else:
@ -204,7 +204,7 @@ proc mget*[A, B](t: var Table[A, B], key: A): var 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`.
var h: THash = hash(key) and high(t.data)
var h: Hash = hash(key) and high(t.data)
while isFilled(t.data[h].hcode):
if t.data[h].key == key:
yield t.data[h].val
@ -212,7 +212,7 @@ iterator allValues*[A, B](t: Table[A, B]; key: A): B =
proc hasKey*[A, B](t: Table[A, B], key: A): bool =
## returns true iff `key` is in the table `t`.
var hc: THash
var hc: Hash
result = rawGet(t, key, hc) >= 0
proc contains*[A, B](t: Table[A, B], key: A): bool =
@ -220,7 +220,7 @@ proc contains*[A, B](t: Table[A, B], key: A): bool =
return hasKey[A, B](t, key)
proc rawInsert[A, B](t: var Table[A, B], data: var KeyValuePairSeq[A, B],
key: A, val: B, hc: THash, h: THash) =
key: A, val: B, hc: Hash, h: Hash) =
rawInsertImpl()
proc enlarge[A, B](t: var Table[A, B]) =
@ -234,7 +234,7 @@ proc enlarge[A, B](t: var Table[A, B]) =
template addImpl() {.dirty.} =
if mustRehash(len(t.data), t.counter): enlarge(t)
var hc: THash
var hc: Hash
var j = rawGetDeep(t, key, hc)
rawInsert(t, t.data, key, val, hc, j)
inc(t.counter)
@ -248,19 +248,19 @@ template maybeRehashPutImpl() {.dirty.} =
inc(t.counter)
template putImpl() {.dirty.} =
var hc: THash
var hc: Hash
var index = rawGet(t, key, hc)
if index >= 0: t.data[index].val = val
else: maybeRehashPutImpl()
template mgetOrPutImpl() {.dirty.} =
var hc: THash
var hc: Hash
var index = rawGet(t, key, hc)
if index < 0: maybeRehashPutImpl() # not present: insert (flipping index)
result = t.data[index].val # either way return modifiable val
template hasKeyOrPutImpl() {.dirty.} =
var hc: THash
var hc: Hash
var index = rawGet(t, key, hc)
if index < 0:
result = false
@ -291,7 +291,7 @@ template doWhile(a: expr, b: stmt): stmt =
proc del*[A, B](t: var Table[A, B], key: A) =
## deletes `key` from hash table `t`.
var hc: THash
var hc: Hash
var i = rawGet(t, key, hc)
let msk = high(t.data)
if i >= 0:
@ -460,7 +460,7 @@ proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B]
type
OrderedKeyValuePair[A, B] = tuple[
hcode: THash, next: int, key: A, val: B]
hcode: Hash, next: int, key: A, val: B]
OrderedKeyValuePairSeq[A, B] = seq[OrderedKeyValuePair[A, B]]
OrderedTable* {.
myShallow.}[A, B] = object ## table that remembers insertion order
@ -509,13 +509,13 @@ iterator mvalues*[A, B](t: var OrderedTable[A, B]): var B =
forAllOrderedPairs:
yield t.data[h].val
proc rawGetKnownHC[A, B](t: OrderedTable[A, B], key: A, hc: THash): int =
proc rawGetKnownHC[A, B](t: OrderedTable[A, B], key: A, hc: Hash): int =
rawGetKnownHCImpl()
proc rawGetDeep[A, B](t: OrderedTable[A, B], key: A, hc: var THash): int {.inline.} =
proc rawGetDeep[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int {.inline.} =
rawGetDeepImpl()
proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var THash): int =
proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int =
rawGetImpl()
proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B =
@ -523,21 +523,21 @@ proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B =
## default empty value for the type `B` is returned
## and no exception is raised. One can check with ``hasKey`` whether the key
## exists.
var hc: THash
var hc: Hash
var index = rawGet(t, key, hc)
if index >= 0: result = t.data[index].val
proc mget*[A, B](t: var OrderedTable[A, B], key: A): var B =
## retrieves the value at ``t[key]``. The value can be modified.
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
var hc: THash
var hc: Hash
var index = rawGet(t, key, hc)
if index >= 0: result = t.data[index].val
else: raise newException(KeyError, "key not found: " & $key)
proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool =
## returns true iff `key` is in the table `t`.
var hc: THash
var hc: Hash
result = rawGet(t, key, hc) >= 0
proc contains*[A, B](t: OrderedTable[A, B], key: A): bool =
@ -546,7 +546,7 @@ proc contains*[A, B](t: OrderedTable[A, B], key: A): bool =
proc rawInsert[A, B](t: var OrderedTable[A, B],
data: var OrderedKeyValuePairSeq[A, B],
key: A, val: B, hc: THash, h: THash) =
key: A, val: B, hc: Hash, h: Hash) =
rawInsertImpl()
data[h].next = -1
if t.first < 0: t.first = h
@ -796,7 +796,7 @@ iterator mvalues*[A](t: CountTable[A]): var int =
if t.data[h].val != 0: yield t.data[h].val
proc rawGet[A](t: CountTable[A], key: A): int =
var h: THash = hash(key) and high(t.data) # start with real hash value
var h: Hash = hash(key) and high(t.data) # start with real hash value
while t.data[h].val != 0:
if t.data[h].key == key: return h
h = nextTry(h, high(t.data))
@ -826,7 +826,7 @@ proc contains*[A](t: CountTable[A], key: A): bool =
proc rawInsert[A](t: CountTable[A], data: var seq[tuple[key: A, val: int]],
key: A, val: int) =
var h: THash = hash(key) and high(data)
var h: Hash = hash(key) and high(data)
while data[h].val != 0: h = nextTry(h, high(data))
data[h].key = key
data[h].val = val
@ -1032,7 +1032,7 @@ when isMainModule:
Person = object
firstName, lastName: string
proc hash(x: Person): THash =
proc hash(x: Person): Hash =
## Piggyback on the already available string hash proc.
##
## Without this proc nothing works!

View file

@ -13,7 +13,7 @@
when defined(windows):
import winlean, os, strutils, math
proc `-`(a, b: TFILETIME): int64 = a.rdFileTime - b.rdFileTime
proc `-`(a, b: FILETIME): int64 = a.rdFileTime - b.rdFileTime
elif defined(linux):
from cpuinfo import countProcessors
@ -25,16 +25,16 @@ type
ThreadPoolState* = object
when defined(windows):
prevSysKernel, prevSysUser, prevProcKernel, prevProcUser: TFILETIME
prevSysKernel, prevSysUser, prevProcKernel, prevProcUser: FILETIME
calls*: int
proc advice*(s: var ThreadPoolState): ThreadPoolAdvice =
when defined(windows):
var
sysIdle, sysKernel, sysUser,
procCreation, procExit, procKernel, procUser: TFILETIME
procCreation, procExit, procKernel, procUser: FILETIME
if getSystemTimes(sysIdle, sysKernel, sysUser) == 0 or
getProcessTimes(THandle(-1), procCreation, procExit,
getProcessTimes(Handle(-1), procCreation, procExit,
procKernel, procUser) == 0:
return doNothing
if s.calls > 0:
@ -57,7 +57,7 @@ proc advice*(s: var ThreadPoolState): ThreadPoolAdvice =
s.prevProcKernel = procKernel
s.prevProcUser = procUser
elif defined(linux):
proc fscanf(c: File, frmt: cstring) {.varargs, importc,
proc fscanf(c: File, frmt: cstring) {.varargs, importc,
header: "<stdio.h>".}
var f = open("/proc/loadavg")

View file

@ -18,8 +18,8 @@ import cpuinfo, cpuload, locks
type
Semaphore = object
c: TCond
L: TLock
c: Cond
L: Lock
counter: int
proc createSemaphore(): Semaphore =
@ -113,7 +113,7 @@ type
ToFreeQueue = object
len: int
lock: TLock
lock: Lock
empty: Semaphore
data: array[128, pointer]
@ -221,11 +221,17 @@ proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) =
action(fv.blob)
finished(fv)
proc `^`*[T](fv: FlowVar[ref T]): foreign ptr T =
proc unsafeRead*[T](fv: FlowVar[ref T]): foreign ptr T =
## blocks until the value is available and then returns this value.
await(fv)
result = cast[foreign ptr T](fv.data)
proc `^`*[T](fv: FlowVar[ref T]): ref T =
## blocks until the value is available and then returns this value.
await(fv)
let src = cast[ref T](fv.data)
deepCopy result, src
proc `^`*[T](fv: FlowVar[T]): T =
## blocks until the value is available and then returns this value.
await(fv)
@ -349,7 +355,7 @@ proc parallel*(body: stmt) {.magic: "Parallel".}
var
state: ThreadPoolState
stateLock: TLock
stateLock: Lock
initLock stateLock

View file

@ -211,12 +211,13 @@ when defined(windows):
when false:
# not needed yet:
type
TCpInfo = object
CpInfo = object
maxCharSize: int32
defaultChar: array[0..1, char]
leadByte: array[0..12-1, char]
{.deprecated: [TCpInfo: CpInfo].}
proc getCPInfo(codePage: CodePage, lpCPInfo: var TCpInfo): int32 {.
proc getCPInfo(codePage: CodePage, lpCPInfo: var CpInfo): int32 {.
stdcall, importc: "GetCPInfo", dynlib: "kernel32".}
proc nameToCodePage(name: string): CodePage =
@ -262,7 +263,7 @@ else:
else:
const iconvDll = "(libc.so.6|libiconv.so)"
when defined(macosx) and defined(powerpc):
when defined(macosx):
const prefix = "lib"
else:
const prefix = ""

23
lib/pure/etcpriv.nim Normal file
View file

@ -0,0 +1,23 @@
#
#
# Nim's Runtime Library
# (c) Copyright 2015 Nim Authors
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module contains utils that are less then easy to categorize and
## don't really warrant a specific module. They are private to compiler
## and stdlib usage, and should not be used outside of that - they may
## change or disappear at any time.
# Used by pure/hashes.nim, and the compiler parsing
const magicIdentSeparatorRuneByteWidth* = 3
# Used by pure/hashes.nim, and the compiler parsing
proc isMagicIdentSeparatorRune*(cs: cstring, i: int): bool {. inline } =
result = cs[i] == '\226' and
cs[i + 1] == '\128' and
cs[i + 2] == '\147' # en-dash # 145 = nb-hyphen

View file

@ -108,7 +108,7 @@ proc del*(monitor: FSMonitor, wd: cint) =
proc getEvent(m: FSMonitor, fd: cint): seq[MonitorEvent] =
result = @[]
let size = (sizeof(TINotifyEvent)+2000)*MaxEvents
let size = (sizeof(INotifyEvent)+2000)*MaxEvents
var buffer = newString(size)
let le = read(fd, addr(buffer[0]), size)
@ -117,7 +117,7 @@ proc getEvent(m: FSMonitor, fd: cint): seq[MonitorEvent] =
var i = 0
while i < le:
var event = cast[ptr TINotifyEvent](addr(buffer[i]))
var event = cast[ptr INotifyEvent](addr(buffer[i]))
var mev: MonitorEvent
mev.wd = event.wd
if event.len.int != 0:
@ -129,7 +129,7 @@ proc getEvent(m: FSMonitor, fd: cint): seq[MonitorEvent] =
if (event.mask.int and IN_MOVED_FROM) != 0:
# Moved from event, add to m's collection
movedFrom.add(event.cookie.cint, (mev.wd, mev.name))
inc(i, sizeof(TINotifyEvent) + event.len.int)
inc(i, sizeof(INotifyEvent) + event.len.int)
continue
elif (event.mask.int and IN_MOVED_TO) != 0:
mev.kind = MonitorMoved
@ -159,7 +159,7 @@ proc getEvent(m: FSMonitor, fd: cint): seq[MonitorEvent] =
mev.fullname = ""
result.add(mev)
inc(i, sizeof(TINotifyEvent) + event.len.int)
inc(i, sizeof(INotifyEvent) + event.len.int)
# If movedFrom events have not been matched with a moveTo. File has
# been moved to an unwatched location, emit a MonitorDelete.

View file

@ -18,20 +18,22 @@ import
os, hashes, strutils
type
TGenTableMode* = enum ## describes the table's key matching mode
GenTableMode* = enum ## describes the table's key matching mode
modeCaseSensitive, ## case sensitive matching of keys
modeCaseInsensitive, ## case insensitive matching of keys
modeStyleInsensitive ## style sensitive matching of keys
TGenKeyValuePair[T] = tuple[key: string, val: T]
TGenKeyValuePairSeq[T] = seq[TGenKeyValuePair[T]]
TGenTable*[T] = object of RootObj
GenKeyValuePair[T] = tuple[key: string, val: T]
GenKeyValuePairSeq[T] = seq[GenKeyValuePair[T]]
GenTable*[T] = object of RootObj
counter: int
data: TGenKeyValuePairSeq[T]
mode: TGenTableMode
data: GenKeyValuePairSeq[T]
mode: GenTableMode
PGenTable*[T] = ref TGenTable[T] ## use this type to declare hash tables
PGenTable*[T] = ref GenTable[T] ## use this type to declare hash tables
{.deprecated: [TGenTableMode: GenTableMode, TGenKeyValuePair: GenKeyValuePair,
TGenKeyValuePairSeq: GenKeyValuePairSeq, TGenTable: GenTable].}
const
growthFactor = 2
@ -48,7 +50,7 @@ iterator pairs*[T](tbl: PGenTable[T]): tuple[key: string, value: T] =
if not isNil(tbl.data[h].key):
yield (tbl.data[h].key, tbl.data[h].val)
proc myhash[T](tbl: PGenTable[T], key: string): THash =
proc myhash[T](tbl: PGenTable[T], key: string): Hash =
case tbl.mode
of modeCaseSensitive: result = hashes.hash(key)
of modeCaseInsensitive: result = hashes.hashIgnoreCase(key)
@ -64,18 +66,18 @@ proc mustRehash(length, counter: int): bool =
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)
proc newGenTable*[T](mode: TGenTableMode): PGenTable[T] =
proc newGenTable*[T](mode: GenTableMode): PGenTable[T] =
## creates a new generic hash table that is empty.
new(result)
result.mode = mode
result.counter = 0
newSeq(result.data, startSize)
proc nextTry(h, maxHash: THash): THash {.inline.} =
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
result = ((5 * h) + 1) and maxHash
proc rawGet[T](tbl: PGenTable[T], key: string): int =
var h: THash
var h: Hash
h = myhash(tbl, key) and high(tbl.data) # start with real hash value
while not isNil(tbl.data[h].key):
if myCmp(tbl, tbl.data[h].key, key):
@ -83,9 +85,9 @@ proc rawGet[T](tbl: PGenTable[T], key: string): int =
h = nextTry(h, high(tbl.data))
result = - 1
proc rawInsert[T](tbl: PGenTable[T], data: var TGenKeyValuePairSeq[T],
proc rawInsert[T](tbl: PGenTable[T], data: var GenKeyValuePairSeq[T],
key: string, val: T) =
var h: THash
var h: Hash
h = myhash(tbl, key) and high(data)
while not isNil(data[h].key):
h = nextTry(h, high(data))
@ -93,7 +95,7 @@ proc rawInsert[T](tbl: PGenTable[T], data: var TGenKeyValuePairSeq[T],
data[h].val = val
proc enlarge[T](tbl: PGenTable[T]) =
var n: TGenKeyValuePairSeq[T]
var n: GenKeyValuePairSeq[T]
newSeq(n, len(tbl.data) * growthFactor)
for i in countup(0, high(tbl.data)):
if not isNil(tbl.data[i].key):
@ -146,19 +148,20 @@ when isMainModule:
# Verify a table of user-defined types
#
type
TMyType = tuple[first, second: string] # a pair of strings
MyType = tuple[first, second: string] # a pair of strings
{.deprecated: [TMyType: MyType].}
var y = newGenTable[TMyType](modeCaseInsensitive) # hash table where each
# value is TMyType tuple
var y = newGenTable[MyType](modeCaseInsensitive) # hash table where each
# value is MyType tuple
#var junk: TMyType = ("OK", "Here")
#var junk: MyType = ("OK", "Here")
#echo junk.first, " ", junk.second
y["Hello"] = ("Hello", "World")
y["Goodbye"] = ("Goodbye", "Everyone")
#y["Hello"] = TMyType( ("Hello", "World") )
#y["Goodbye"] = TMyType( ("Goodbye", "Everyone") )
#y["Hello"] = MyType( ("Hello", "World") )
#y["Goodbye"] = MyType( ("Goodbye", "Everyone") )
assert( not isNil(y["Hello"].first) )
assert( y["Hello"].first == "Hello" )

View file

@ -15,9 +15,9 @@
## code:
##
## .. code-block:: Nim
## proc hash(x: Something): THash =
## ## Computes a THash from `x`.
## var h: THash = 0
## proc hash(x: Something): Hash =
## ## Computes a Hash from `x`.
## var h: Hash = 0
## # Iterate over parts of `x`.
## for xAtom in x:
## # Mix the atom with the partial hash.
@ -30,38 +30,39 @@
## together the hash value of the individual fields:
##
## .. code-block:: Nim
## proc hash(x: Something): THash =
## ## Computes a THash from `x`.
## var h: THash = 0
## proc hash(x: Something): Hash =
## ## Computes a Hash from `x`.
## var h: Hash = 0
## h = h !& hash(x.foo)
## h = h !& hash(x.bar)
## result = !$h
import
strutils
strutils, etcpriv
type
THash* = int ## a hash value; hash tables using these values should
Hash* = int ## a hash value; hash tables using these values should
## always have a size of a power of two and can use the ``and``
## operator instead of ``mod`` for truncation of the hash value.
{.deprecated: [THash: Hash].}
proc `!&`*(h: THash, val: int): THash {.inline.} =
proc `!&`*(h: Hash, val: int): Hash {.inline.} =
## mixes a hash value `h` with `val` to produce a new hash value. This is
## only needed if you need to implement a hash proc for a new datatype.
result = h +% val
result = result +% result shl 10
result = result xor (result shr 6)
proc `!$`*(h: THash): THash {.inline.} =
proc `!$`*(h: Hash): Hash {.inline.} =
## finishes the computation of the hash value. This is
## only needed if you need to implement a hash proc for a new datatype.
result = h +% h shl 3
result = result xor (result shr 11)
result = result +% result shl 15
proc hashData*(data: pointer, size: int): THash =
proc hashData*(data: pointer, size: int): Hash =
## hashes an array of bytes of size `size`
var h: THash = 0
var h: Hash = 0
when defined(js):
var p: cstring
asm """`p` = `Data`;"""
@ -78,7 +79,7 @@ proc hashData*(data: pointer, size: int): THash =
when defined(js):
var objectID = 0
proc hash*(x: pointer): THash {.inline.} =
proc hash*(x: pointer): Hash {.inline.} =
## efficient hashing of pointers
when defined(js):
asm """
@ -92,50 +93,57 @@ proc hash*(x: pointer): THash {.inline.} =
}
"""
else:
result = (cast[THash](x)) shr 3 # skip the alignment
result = (cast[Hash](x)) shr 3 # skip the alignment
when not defined(booting):
proc hash*[T: proc](x: T): THash {.inline.} =
proc hash*[T: proc](x: T): Hash {.inline.} =
## efficient hashing of proc vars; closures are supported too.
when T is "closure":
result = hash(rawProc(x)) !& hash(rawEnv(x))
else:
result = hash(pointer(x))
proc hash*(x: int): THash {.inline.} =
proc hash*(x: int): Hash {.inline.} =
## efficient hashing of integers
result = x
proc hash*(x: int64): THash {.inline.} =
proc hash*(x: int64): Hash {.inline.} =
## efficient hashing of integers
result = toU32(x)
proc hash*(x: char): THash {.inline.} =
proc hash*(x: char): Hash {.inline.} =
## efficient hashing of characters
result = ord(x)
proc hash*(x: string): THash =
proc hash*(x: string): Hash =
## efficient hashing of strings
var h: THash = 0
var h: Hash = 0
for i in 0..x.len-1:
h = h !& ord(x[i])
result = !$h
proc hashIgnoreStyle*(x: string): THash =
proc hashIgnoreStyle*(x: string): Hash =
## efficient hashing of strings; style is ignored
var h: THash = 0
for i in 0..x.len-1:
var h: Hash = 0
var i = 0
let xLen = x.len
while i < xLen:
var c = x[i]
if c == '_':
continue # skip _
if c in {'A'..'Z'}:
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
h = h !& ord(c)
inc(i)
elif isMagicIdentSeparatorRune(cstring(x), i):
inc(i, magicIdentSeparatorRuneByteWidth)
else:
if c in {'A'..'Z'}:
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
h = h !& ord(c)
inc(i)
result = !$h
proc hashIgnoreCase*(x: string): THash =
proc hashIgnoreCase*(x: string): Hash =
## efficient hashing of strings; case is ignored
var h: THash = 0
var h: Hash = 0
for i in 0..x.len-1:
var c = x[i]
if c in {'A'..'Z'}:
@ -143,28 +151,28 @@ proc hashIgnoreCase*(x: string): THash =
h = h !& ord(c)
result = !$h
proc hash*(x: float): THash {.inline.} =
proc hash*(x: float): Hash {.inline.} =
var y = x + 1.0
result = cast[ptr THash](addr(y))[]
result = cast[ptr Hash](addr(y))[]
# Forward declarations before methods that hash containers. This allows
# containers to contain other containers
proc hash*[A](x: openArray[A]): THash
proc hash*[A](x: set[A]): THash
proc hash*[A](x: openArray[A]): Hash
proc hash*[A](x: set[A]): Hash
proc hash*[T: tuple](x: T): THash =
proc hash*[T: tuple](x: T): Hash =
## efficient hashing of tuples.
for f in fields(x):
result = result !& hash(f)
result = !$result
proc hash*[A](x: openArray[A]): THash =
proc hash*[A](x: openArray[A]): Hash =
for it in items(x): result = result !& hash(it)
result = !$result
proc hash*[A](x: set[A]): THash =
proc hash*[A](x: set[A]): Hash =
for it in items(x): result = result !& hash(it)
result = !$result

View file

@ -52,7 +52,7 @@
import strutils, streams, parsexml, xmltree, unicode, strtabs
type
THtmlTag* = enum ## list of all supported HTML tags; order will always be
HtmlTag* = enum ## list of all supported HTML tags; order will always be
## alphabetically
tagUnknown, ## unknown HTML element
tagA, ## the HTML ``a`` element
@ -178,6 +178,7 @@ type
tagVar, ## the HTML ``var`` element
tagVideo, ## the HTML ``video`` element
tagWbr ## the HTML ``wbr`` element
{.deprecated: [THtmlTag: HtmlTag].}
const
tagToStr* = [
@ -295,7 +296,7 @@ proc allLower(s: string): bool =
if c < 'a' or c > 'z': return false
return true
proc toHtmlTag(s: string): THtmlTag =
proc toHtmlTag(s: string): HtmlTag =
case s
of "a": tagA
of "abbr": tagAbbr
@ -422,14 +423,14 @@ proc toHtmlTag(s: string): THtmlTag =
of "wbr": tagWbr
else: tagUnknown
proc htmlTag*(n: XmlNode): THtmlTag =
## gets `n`'s tag as a ``THtmlTag``.
proc htmlTag*(n: XmlNode): HtmlTag =
## gets `n`'s tag as a ``HtmlTag``.
if n.clientData == 0:
n.clientData = toHtmlTag(n.tag).ord
result = THtmlTag(n.clientData)
result = HtmlTag(n.clientData)
proc htmlTag*(s: string): THtmlTag =
## converts `s` to a ``THtmlTag``. If `s` is no HTML tag, ``tagUnknown`` is
proc htmlTag*(s: string): HtmlTag =
## converts `s` to a ``HtmlTag``. If `s` is no HTML tag, ``tagUnknown`` is
## returned.
let s = if allLower(s): s else: s.toLower
result = toHtmlTag(s)

View file

@ -106,9 +106,10 @@ proc serveFile*(client: Socket, filename: string) =
when false:
# TODO: Fix this, or get rid of it.
type
TRequestMethod = enum reqGet, reqPost
RequestMethod = enum reqGet, reqPost
{.deprecated: [TRequestMethod: RequestMethod].}
proc executeCgi(client: Socket, path, query: string, meth: TRequestMethod) =
proc executeCgi(client: Socket, path, query: string, meth: RequestMethod) =
var env = newStringTable(modeCaseInsensitive)
var contentLength = -1
case meth
@ -208,7 +209,7 @@ when false:
executeCgi(client, path, query, meth)
type
TServer* = object of RootObj ## contains the current server state
Server* = object of RootObj ## contains the current server state
socket: Socket
port: Port
client*: Socket ## the socket to write the file data to
@ -218,11 +219,12 @@ type
body*: string ## only set with POST requests
ip*: string ## ip address of the requesting client
PAsyncHTTPServer* = ref TAsyncHTTPServer
TAsyncHTTPServer = object of TServer
PAsyncHTTPServer* = ref AsyncHTTPServer
AsyncHTTPServer = object of Server
asyncSocket: AsyncSocket
{.deprecated: [TAsyncHTTPServer: AsyncHTTPServer, TServer: Server].}
proc open*(s: var TServer, port = Port(80), reuseAddr = false) =
proc open*(s: var Server, port = Port(80), reuseAddr = false) =
## creates a new server at port `port`. If ``port == 0`` a free port is
## acquired that can be accessed later by the ``port`` proc.
s.socket = socket(AF_INET)
@ -243,11 +245,11 @@ proc open*(s: var TServer, port = Port(80), reuseAddr = false) =
s.query = ""
s.headers = {:}.newStringTable()
proc port*(s: var TServer): Port =
proc port*(s: var Server): Port =
## get the port number the server has acquired.
result = s.port
proc next*(s: var TServer) =
proc next*(s: var Server) =
## proceed to the first/next request.
var client: Socket
new(client)
@ -354,7 +356,7 @@ proc next*(s: var TServer) =
s.query = ""
s.path = data.substr(i, last-1)
proc close*(s: TServer) =
proc close*(s: Server) =
## closes the server (and the socket the server uses).
close(s.socket)
@ -362,7 +364,7 @@ proc run*(handleRequest: proc (client: Socket,
path, query: string): bool {.closure.},
port = Port(80)) =
## encapsulates the server object and main loop
var s: TServer
var s: Server
open(s, port, reuseAddr = true)
#echo("httpserver running on port ", s.port)
while true:
@ -517,7 +519,7 @@ proc close*(h: PAsyncHTTPServer) =
when not defined(testing) and isMainModule:
var counter = 0
var s: TServer
var s: Server
open(s, Port(0))
echo("httpserver running on port ", s.port)
while true:

View file

@ -68,7 +68,7 @@ type
jsonArrayStart, ## start of an array: the ``[`` token
jsonArrayEnd ## start of an array: the ``]`` token
TTokKind = enum # must be synchronized with TJsonEventKind!
TokKind = enum # must be synchronized with TJsonEventKind!
tkError,
tkEof,
tkString,
@ -103,14 +103,14 @@ type
JsonParser* = object of BaseLexer ## the parser object.
a: string
tok: TTokKind
tok: TokKind
kind: JsonEventKind
err: JsonError
state: seq[ParserState]
filename: string
{.deprecated: [TJsonEventKind: JsonEventKind, TJsonError: JsonError,
TJsonParser: JsonParser].}
TJsonParser: JsonParser, TTokKind: TokKind].}
const
errorMessages: array [JsonError, string] = [
@ -126,7 +126,7 @@ const
"EOF expected",
"expression expected"
]
tokToStr: array [TTokKind, string] = [
tokToStr: array [TokKind, string] = [
"invalid token",
"EOF",
"string literal",
@ -203,7 +203,7 @@ proc handleHexChar(c: char, x: var int): bool =
of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10)
else: result = false # error
proc parseString(my: var JsonParser): TTokKind =
proc parseString(my: var JsonParser): TokKind =
result = tkString
var pos = my.bufpos + 1
var buf = my.buf
@ -359,7 +359,7 @@ proc parseName(my: var JsonParser) =
inc(pos)
my.bufpos = pos
proc getTok(my: var JsonParser): TTokKind =
proc getTok(my: var JsonParser): TokKind =
setLen(my.a, 0)
skip(my) # skip whitespace, comments
case my.buf[my.bufpos]
@ -734,7 +734,7 @@ proc `==`* (a,b: JsonNode): bool =
of JObject:
a.fields == b.fields
proc hash* (n:JsonNode): THash =
proc hash* (n:JsonNode): Hash =
## Compute the hash for a JSON node
case n.kind
of JArray:
@ -1016,7 +1016,7 @@ iterator mpairs*(node: var JsonNode): var tuple[key: string, val: JsonNode] =
for keyVal in mitems(node.fields):
yield keyVal
proc eat(p: var JsonParser, tok: TTokKind) =
proc eat(p: var JsonParser, tok: TokKind) =
if p.tok == tok: discard getTok(p)
else: raiseParseErr(p, tokToStr[tok])
@ -1091,8 +1091,10 @@ when not defined(js):
else:
from math import `mod`
type
TJSObject = object
proc parseNativeJson(x: cstring): TJSObject {.importc: "JSON.parse".}
JSObject = object
{.deprecated: [TJSObject: JSObject].}
proc parseNativeJson(x: cstring): JSObject {.importc: "JSON.parse".}
proc getVarType(x): JsonNodeKind =
result = JNull
@ -1111,25 +1113,25 @@ else:
of "[object String]": return JString
else: assert false
proc len(x: TJSObject): int =
proc len(x: JSObject): int =
assert x.getVarType == JArray
asm """
return `x`.length;
"""
proc `[]`(x: TJSObject, y: string): TJSObject =
proc `[]`(x: JSObject, y: string): JSObject =
assert x.getVarType == JObject
asm """
return `x`[`y`];
"""
proc `[]`(x: TJSObject, y: int): TJSObject =
proc `[]`(x: JSObject, y: int): JSObject =
assert x.getVarType == JArray
asm """
return `x`[`y`];
"""
proc convertObject(x: TJSObject): JsonNode =
proc convertObject(x: JSObject): JsonNode =
case getVarType(x)
of JArray:
result = newJArray()
@ -1141,7 +1143,7 @@ else:
if (`x`.hasOwnProperty(property)) {
"""
var nimProperty: cstring
var nimValue: TJSObject
var nimValue: JSObject
asm "`nimProperty` = property; `nimValue` = `x`[property];"
result[$nimProperty] = nimValue.convertObject()
asm "}}"

View file

@ -39,7 +39,7 @@ type
{.deprecated: [TBaseLexer: BaseLexer].}
proc open*(L: var BaseLexer, input: Stream, bufLen: int = 8192)
## inits the TBaseLexer with a stream to read from
## inits the BaseLexer with a stream to read from
proc close*(L: var BaseLexer)
## closes the base lexer. This closes `L`'s associated stream too.

View file

@ -82,6 +82,7 @@ type
baseName: string # initial filename
baseMode: FileMode # initial file mode
logFiles: int # how many log files already created, e.g. basename.1, basename.2...
bufSize: int # size of output buffer (-1: use system defaults, 0: unbuffered, >0: fixed buffer size)
{.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger,
PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].}
@ -112,27 +113,22 @@ proc substituteLog(frmt: string): string =
of "appname": result.add(app.splitFile.name)
else: discard
method log*(logger: Logger, level: Level,
frmt: string, args: varargs[string, `$`]) {.
method log*(logger: Logger, level: Level, args: varargs[string, `$`]) {.
raises: [Exception],
tags: [TimeEffect, WriteIOEffect, ReadIOEffect].} =
## Override this method in custom loggers. Default implementation does
## nothing.
discard
method log*(logger: ConsoleLogger, level: Level,
frmt: string, args: varargs[string, `$`]) =
method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) =
## Logs to the console using ``logger`` only.
if level >= logger.levelThreshold:
writeln(stdout, LevelNames[level], " ", substituteLog(logger.fmtStr),
frmt % args)
writeln(stdout, LevelNames[level], " ", substituteLog(logger.fmtStr), args)
method log*(logger: FileLogger, level: Level,
frmt: string, args: varargs[string, `$`]) =
method log*(logger: FileLogger, level: Level, args: varargs[string, `$`]) =
## Logs to a file using ``logger`` only.
if level >= logger.levelThreshold:
writeln(logger.f, LevelNames[level], " ",
substituteLog(logger.fmtStr), frmt % args)
writeln(logger.f, LevelNames[level], " ", substituteLog(logger.fmtStr), args)
proc defaultFilename*(): string =
## Returns the default filename for a logger.
@ -148,11 +144,14 @@ proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): Console
proc newFileLogger*(filename = defaultFilename(),
mode: FileMode = fmAppend,
levelThreshold = lvlAll,
fmtStr = defaultFmtStr): FileLogger =
fmtStr = defaultFmtStr,
bufSize: int = -1): FileLogger =
## Creates a new file logger. This logger logs to a file.
## Use ``bufSize`` as size of the output buffer when writing the file
## (-1: use system defaults, 0: unbuffered, >0: fixed buffer size).
new(result)
result.levelThreshold = levelThreshold
result.f = open(filename, mode)
result.f = open(filename, mode, bufSize = bufSize)
result.fmtStr = fmtStr
# ------
@ -181,14 +180,18 @@ proc newRollingFileLogger*(filename = defaultFilename(),
mode: FileMode = fmReadWrite,
levelThreshold = lvlAll,
fmtStr = defaultFmtStr,
maxLines = 1000): RollingFileLogger =
maxLines = 1000,
bufSize: int = -1): RollingFileLogger =
## Creates a new rolling file logger. Once a file reaches ``maxLines`` lines
## a new log file will be started and the old will be renamed.
## Use ``bufSize`` as size of the output buffer when writing the file
## (-1: use system defaults, 0: unbuffered, >0: fixed buffer size).
new(result)
result.levelThreshold = levelThreshold
result.fmtStr = fmtStr
result.maxLines = maxLines
result.f = open(filename, mode)
result.bufSize = bufSize
result.f = open(filename, mode, bufSize=result.bufSize)
result.curLine = 0
result.baseName = filename
result.baseMode = mode
@ -206,8 +209,7 @@ proc rotate(logger: RollingFileLogger) =
moveFile(dir / (name & ext & srcSuff),
dir / (name & ext & ExtSep & $(i+1)))
method log*(logger: RollingFileLogger, level: Level,
frmt: string, args: varargs[string, `$`]) =
method log*(logger: RollingFileLogger, level: Level, args: varargs[string, `$`]) =
## Logs to a file using rolling ``logger`` only.
if level >= logger.levelThreshold:
if logger.curLine >= logger.maxLines:
@ -215,9 +217,9 @@ method log*(logger: RollingFileLogger, level: Level,
rotate(logger)
logger.logFiles.inc
logger.curLine = 0
logger.f = open(logger.baseName, logger.baseMode)
logger.f = open(logger.baseName, logger.baseMode, bufSize = logger.bufSize)
writeln(logger.f, LevelNames[level], " ",substituteLog(logger.fmtStr), frmt % args)
writeln(logger.f, LevelNames[level], " ", substituteLog(logger.fmtStr), args)
logger.curLine.inc
# --------
@ -225,39 +227,39 @@ method log*(logger: RollingFileLogger, level: Level,
var level {.threadvar.}: Level ## global log filter
var handlers {.threadvar.}: seq[Logger] ## handlers with their own log levels
proc logLoop(level: Level, frmt: string, args: varargs[string, `$`]) =
proc logLoop(level: Level, args: varargs[string, `$`]) =
for logger in items(handlers):
if level >= logger.levelThreshold:
log(logger, level, frmt, args)
log(logger, level, args)
template log*(level: Level, frmt: string, args: varargs[string, `$`]) =
template log*(level: Level, args: varargs[string, `$`]) =
## Logs a message to all registered handlers at the given level.
bind logLoop
bind `%`
bind logging.level
if level >= logging.level:
logLoop(level, frmt, args)
logLoop(level, args)
template debug*(frmt: string, args: varargs[string, `$`]) =
template debug*(args: varargs[string, `$`]) =
## Logs a debug message to all registered handlers.
log(lvlDebug, frmt, args)
log(lvlDebug, args)
template info*(frmt: string, args: varargs[string, `$`]) =
template info*(args: varargs[string, `$`]) =
## Logs an info message to all registered handlers.
log(lvlInfo, frmt, args)
log(lvlInfo, args)
template warn*(frmt: string, args: varargs[string, `$`]) =
template warn*(args: varargs[string, `$`]) =
## Logs a warning message to all registered handlers.
log(lvlWarn, frmt, args)
log(lvlWarn, args)
template error*(frmt: string, args: varargs[string, `$`]) =
template error*(args: varargs[string, `$`]) =
## Logs an error message to all registered handlers.
log(lvlError, frmt, args)
log(lvlError, args)
template fatal*(frmt: string, args: varargs[string, `$`]) =
template fatal*(args: varargs[string, `$`]) =
## Logs a fatal error message to all registered handlers.
log(lvlFatal, frmt, args)
log(lvlFatal, args)
proc addHandler*(handler: Logger) =
## Adds ``handler`` to the list of handlers.
@ -286,6 +288,4 @@ when not defined(testing) and isMainModule:
addHandler(fL)
addHandler(rL)
for i in 0 .. 25:
info("hello" & $i, [])
info("hello", i)

View file

@ -17,13 +17,13 @@
## .. code-block:: nim
##
## type
## TA = object
## TB = object of TA
## A = object
## B = object of A
## f: int
##
## var
## a: ref TA
## b: ref TB
## a: ref A
## b: ref B
##
## new(b)
## a = b
@ -36,7 +36,7 @@ import streams, typeinfo, json, intsets, tables
proc ptrToInt(x: pointer): int {.inline.} =
result = cast[int](x) # don't skip alignment
proc storeAny(s: Stream, a: TAny, stored: var IntSet) =
proc storeAny(s: Stream, a: Any, stored: var IntSet) =
case a.kind
of akNone: assert false
of akBool: s.write($getBool(a))
@ -96,7 +96,7 @@ proc storeAny(s: Stream, a: TAny, stored: var IntSet) =
of akInt..akInt64, akUInt..akUInt64: s.write($getBiggestInt(a))
of akFloat..akFloat128: s.write($getBiggestFloat(a))
proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
proc loadAny(p: var JsonParser, a: Any, t: var Table[BiggestInt, pointer]) =
case a.kind
of akNone: assert false
of akBool:
@ -222,7 +222,7 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
raiseParseErr(p, "float expected")
of akRange: loadAny(p, a.skipRange, t)
proc loadAny(s: Stream, a: TAny, t: var Table[BiggestInt, pointer]) =
proc loadAny(s: Stream, a: Any, t: var Table[BiggestInt, pointer]) =
var p: JsonParser
open(p, s, "unknown file")
next(p)
@ -278,10 +278,11 @@ when not defined(testing) and isMainModule:
else:
nil
PNode = ref TNode
TNode = object
PNode = ref Node
Node = object
next, prev: PNode
data: string
{.deprecated: [TNode: Node].}
proc buildList(): PNode =
new(result)
@ -317,14 +318,15 @@ when not defined(testing) and isMainModule:
testit(test7)
type
TA {.inheritable.} = object
TB = object of TA
A {.inheritable.} = object
B = object of A
f: int
var
a: ref TA
b: ref TB
a: ref A
b: ref B
new(b)
a = b
echo($$a[]) # produces "{}", not "{f: 0}"

View file

@ -196,7 +196,7 @@ proc open*(filename: string, mode: FileMode = fmRead,
if mappedSize != -1:
result.size = mappedSize
else:
var stat: TStat
var stat: Stat
if fstat(result.handle, stat) != -1:
# XXX: Hmm, this could be unsafe
# Why is mmap taking int anyway?

View file

@ -86,7 +86,7 @@ type
IPv6, ## IPv6 address
IPv4 ## IPv4 address
TIpAddress* = object ## stores an arbitrary IP address
IpAddress* = object ## stores an arbitrary IP address
case family*: IpAddressFamily ## the type of the IP address (IPv4 or IPv6)
of IpAddressFamily.IPv6:
address_v6*: array[0..15, uint8] ## Contains the IP address in bytes in
@ -94,9 +94,10 @@ type
of IpAddressFamily.IPv4:
address_v4*: array[0..3, uint8] ## Contains the IP address in bytes in
## case of IPv4
{.deprecated: [TIpAddress: IpAddress].}
proc isIpAddress*(address_str: string): bool {.tags: [].}
proc parseIpAddress*(address_str: string): TIpAddress
proc parseIpAddress*(address_str: string): IpAddress
proc isDisconnectionError*(flags: set[SocketFlag],
lastError: OSErrorCode): bool =
@ -118,13 +119,13 @@ proc toOSFlags*(socketFlags: set[SocketFlag]): cint =
result = result or MSG_PEEK
of SocketFlag.SafeDisconn: continue
proc newSocket(fd: SocketHandle, isBuff: bool): Socket =
proc newSocket*(fd: SocketHandle, buffered = true): Socket =
## Creates a new socket as specified by the params.
assert fd != osInvalidSocket
new(result)
result.fd = fd
result.isBuffered = isBuff
if isBuff:
result.isBuffered = buffered
if buffered:
result.currPos = 0
proc newSocket*(domain, typ, protocol: cint, buffered = true): Socket =
@ -395,7 +396,7 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string,
when false: #defined(ssl):
proc acceptAddrSSL*(server: Socket, client: var Socket,
address: var string): TSSLAcceptResult {.
address: var string): SSLAcceptResult {.
tags: [ReadIOEffect].} =
## This procedure should only be used for non-blocking **SSL** sockets.
## It will immediately return with one of the following values:
@ -992,39 +993,39 @@ proc isSsl*(socket: Socket): bool =
proc getFd*(socket: Socket): SocketHandle = return socket.fd
## Returns the socket's file descriptor
proc IPv4_any*(): TIpAddress =
proc IPv4_any*(): IpAddress =
## Returns the IPv4 any address, which can be used to listen on all available
## network adapters
result = TIpAddress(
result = IpAddress(
family: IpAddressFamily.IPv4,
address_v4: [0'u8, 0, 0, 0])
proc IPv4_loopback*(): TIpAddress =
proc IPv4_loopback*(): IpAddress =
## Returns the IPv4 loopback address (127.0.0.1)
result = TIpAddress(
result = IpAddress(
family: IpAddressFamily.IPv4,
address_v4: [127'u8, 0, 0, 1])
proc IPv4_broadcast*(): TIpAddress =
proc IPv4_broadcast*(): IpAddress =
## Returns the IPv4 broadcast address (255.255.255.255)
result = TIpAddress(
result = IpAddress(
family: IpAddressFamily.IPv4,
address_v4: [255'u8, 255, 255, 255])
proc IPv6_any*(): TIpAddress =
proc IPv6_any*(): IpAddress =
## Returns the IPv6 any address (::0), which can be used
## to listen on all available network adapters
result = TIpAddress(
result = IpAddress(
family: IpAddressFamily.IPv6,
address_v6: [0'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
proc IPv6_loopback*(): TIpAddress =
proc IPv6_loopback*(): IpAddress =
## Returns the IPv6 loopback address (::1)
result = TIpAddress(
result = IpAddress(
family: IpAddressFamily.IPv6,
address_v6: [0'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
proc `==`*(lhs, rhs: TIpAddress): bool =
proc `==`*(lhs, rhs: IpAddress): bool =
## Compares two IpAddresses for Equality. Returns two if the addresses are equal
if lhs.family != rhs.family: return false
if lhs.family == IpAddressFamily.IPv4:
@ -1035,8 +1036,8 @@ proc `==`*(lhs, rhs: TIpAddress): bool =
if lhs.address_v6[i] != rhs.address_v6[i]: return false
return true
proc `$`*(address: TIpAddress): string =
## Converts an TIpAddress into the textual representation
proc `$`*(address: IpAddress): string =
## Converts an IpAddress into the textual representation
result = ""
case address.family
of IpAddressFamily.IPv4:
@ -1095,7 +1096,7 @@ proc `$`*(address: TIpAddress): string =
mask = mask shr 4
printedLastGroup = true
proc parseIPv4Address(address_str: string): TIpAddress =
proc parseIPv4Address(address_str: string): IpAddress =
## Parses IPv4 adresses
## Raises EInvalidValue on errors
var
@ -1129,7 +1130,7 @@ proc parseIPv4Address(address_str: string): TIpAddress =
raise newException(ValueError, "Invalid IP Address")
result.address_v4[byteCount] = cast[uint8](currentByte)
proc parseIPv6Address(address_str: string): TIpAddress =
proc parseIPv6Address(address_str: string): IpAddress =
## Parses IPv6 adresses
## Raises EInvalidValue on errors
result.family = IpAddressFamily.IPv6
@ -1250,7 +1251,7 @@ proc parseIPv6Address(address_str: string): TIpAddress =
raise newException(ValueError,
"Invalid IP Address. The address consists of too many groups")
proc parseIpAddress(address_str: string): TIpAddress =
proc parseIpAddress(address_str: string): IpAddress =
## Parses an IP address
## Raises EInvalidValue on error
if address_str == nil:

View file

@ -26,17 +26,19 @@ const
withThreads = compileOption("threads")
tickCountCorrection = 50_000
when not declared(system.TStackTrace):
type TStackTrace = array [0..20, cstring]
when not declared(system.StackTrace):
type StackTrace = array [0..20, cstring]
{.deprecated: [TStackTrace: StackTrace].}
# We use a simple hash table of bounded size to keep track of the stack traces:
type
TProfileEntry = object
ProfileEntry = object
total: int
st: TStackTrace
TProfileData = array [0..64*1024-1, ptr TProfileEntry]
st: StackTrace
ProfileData = array [0..64*1024-1, ptr ProfileEntry]
{.deprecated: [TProfileEntry: ProfileEntry, TProfileData: ProfileData].}
proc `==`(a, b: TStackTrace): bool =
proc `==`(a, b: StackTrace): bool =
for i in 0 .. high(a):
if a[i] != b[i]: return false
result = true
@ -44,13 +46,13 @@ proc `==`(a, b: TStackTrace): bool =
# XXX extract this data structure; it is generally useful ;-)
# However a chain length of over 3000 is suspicious...
var
profileData: TProfileData
profileData: ProfileData
emptySlots = profileData.len * 3 div 2
maxChainLen = 0
totalCalls = 0
when not defined(memProfiler):
var interval: TNanos = 5_000_000 - tickCountCorrection # 5ms
var interval: Nanos = 5_000_000 - tickCountCorrection # 5ms
proc setSamplingFrequency*(intervalInUs: int) =
## set this to change the sampling frequency. Default value is 5ms.
@ -62,11 +64,11 @@ when not defined(memProfiler):
when withThreads:
import locks
var
profilingLock: TLock
profilingLock: Lock
initLock profilingLock
proc hookAux(st: TStackTrace, costs: int) =
proc hookAux(st: StackTrace, costs: int) =
# this is quite performance sensitive!
when withThreads: acquire profilingLock
inc totalCalls
@ -94,8 +96,8 @@ proc hookAux(st: TStackTrace, costs: int) =
var chain = 0
while true:
if profileData[h] == nil:
profileData[h] = cast[ptr TProfileEntry](
allocShared0(sizeof(TProfileEntry)))
profileData[h] = cast[ptr ProfileEntry](
allocShared0(sizeof(ProfileEntry)))
profileData[h].total = costs
profileData[h].st = st
dec emptySlots
@ -115,7 +117,7 @@ when defined(memProfiler):
var
gTicker {.threadvar.}: int
proc hook(st: TStackTrace, size: int) {.nimcall.} =
proc hook(st: StackTrace, size: int) {.nimcall.} =
if gTicker == 0:
gTicker = -1
when defined(ignoreAllocationSize):
@ -127,26 +129,26 @@ when defined(memProfiler):
else:
var
t0 {.threadvar.}: TTicks
t0 {.threadvar.}: Ticks
proc hook(st: TStackTrace) {.nimcall.} =
proc hook(st: StackTrace) {.nimcall.} =
if interval == 0:
hookAux(st, 1)
elif int64(t0) == 0 or getTicks() - t0 > interval:
hookAux(st, 1)
t0 = getTicks()
proc getTotal(x: ptr TProfileEntry): int =
proc getTotal(x: ptr ProfileEntry): int =
result = if isNil(x): 0 else: x.total
proc cmpEntries(a, b: ptr TProfileEntry): int =
proc cmpEntries(a, b: ptr ProfileEntry): int =
result = b.getTotal - a.getTotal
proc `//`(a, b: int): string =
result = format("$1/$2 = $3%", a, b, formatFloat(a / b * 100.0, ffDefault, 2))
proc writeProfile() {.noconv.} =
when declared(system.TStackTrace):
when declared(system.StackTrace):
system.profilerHook = nil
const filename = "profile_results.txt"
echo "writing " & filename & "..."
@ -161,7 +163,7 @@ proc writeProfile() {.noconv.} =
var perProc = initCountTable[string]()
for i in 0..entries-1:
var dups = initSet[string]()
for ii in 0..high(TStackTrace):
for ii in 0..high(StackTrace):
let procname = profileData[i].st[ii]
if isNil(procname): break
let p = $procname
@ -176,7 +178,7 @@ proc writeProfile() {.noconv.} =
writeln(f, "Entry: ", i+1, "/", entries, " Calls: ",
profileData[i].total // totalCalls, " [sum: ", sum, "; ",
sum // totalCalls, "]")
for ii in 0..high(TStackTrace):
for ii in 0..high(StackTrace):
let procname = profileData[i].st[ii]
if isNil(procname): break
writeln(f, " ", procname, " ", perProc[$procname] // totalCalls)
@ -189,16 +191,16 @@ var
disabled: int
proc disableProfiling*() =
when declared(system.TStackTrace):
when declared(system.StackTrace):
atomicDec disabled
system.profilerHook = nil
proc enableProfiling*() =
when declared(system.TStackTrace):
when declared(system.StackTrace):
if atomicInc(disabled) >= 0:
system.profilerHook = hook
when declared(system.TStackTrace):
when declared(system.StackTrace):
system.profilerHook = hook
addQuitProc(writeProfile)

View file

@ -41,7 +41,7 @@ type
OSErrorCode* = distinct int32 ## Specifies an OS Error Code.
{.deprecated: [FReadEnv: ReadEnvEffect, FWriteEnv: WriteEnvEffect,
{.deprecated: [FReadEnv: ReadEnvEffect, FWriteEnv: WriteEnvEffect,
FReadDir: ReadDirEffect,
FWriteDir: WriteDirEffect,
TOSErrorCode: OSErrorCode
@ -359,7 +359,7 @@ when defined(windows):
template wrapBinary(varname, winApiProc, arg, arg2: expr) {.immediate.} =
var varname = winApiProc(newWideCString(arg), arg2)
proc findFirstFile(a: string, b: var TWIN32_FIND_DATA): THandle =
proc findFirstFile(a: string, b: var WIN32_FIND_DATA): Handle =
result = findFirstFileW(newWideCString(a), b)
template findNextFile(a, b: expr): expr = findNextFileW(a, b)
template getCommandLine(): expr = getCommandLineW()
@ -373,7 +373,7 @@ when defined(windows):
template getFilename(f: expr): expr = $f.cFilename
proc skipFindData(f: TWIN32_FIND_DATA): bool {.inline.} =
proc skipFindData(f: WIN32_FIND_DATA): bool {.inline.} =
# Note - takes advantage of null delimiter in the cstring
const dot = ord('.')
result = f.cFileName[0].int == dot and (f.cFileName[1].int == 0 or
@ -390,7 +390,7 @@ proc existsFile*(filename: string): bool {.rtl, extern: "nos$1",
if a != -1'i32:
result = (a and FILE_ATTRIBUTE_DIRECTORY) == 0'i32
else:
var res: TStat
var res: Stat
return stat(filename, res) >= 0'i32 and S_ISREG(res.st_mode)
proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect].} =
@ -404,7 +404,7 @@ proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect]
if a != -1'i32:
result = (a and FILE_ATTRIBUTE_DIRECTORY) != 0'i32
else:
var res: TStat
var res: Stat
return stat(dir, res) >= 0'i32 and S_ISDIR(res.st_mode)
proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1",
@ -419,7 +419,7 @@ proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1",
if a != -1'i32:
result = (a and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32
else:
var res: TStat
var res: Stat
return lstat(link, res) >= 0'i32 and S_ISLNK(res.st_mode)
proc fileExists*(filename: string): bool {.inline.} =
@ -433,11 +433,11 @@ proc dirExists*(dir: string): bool {.inline.} =
proc getLastModificationTime*(file: string): Time {.rtl, extern: "nos$1".} =
## Returns the `file`'s last modification time.
when defined(posix):
var res: TStat
var res: Stat
if stat(file, res) < 0'i32: raiseOSError(osLastError())
return res.st_mtime
else:
var f: TWIN32_FIND_DATA
var f: WIN32_FIND_DATA
var h = findFirstFile(file, f)
if h == -1'i32: raiseOSError(osLastError())
result = winTimeToUnixTime(rdFileTime(f.ftLastWriteTime))
@ -446,11 +446,11 @@ proc getLastModificationTime*(file: string): Time {.rtl, extern: "nos$1".} =
proc getLastAccessTime*(file: string): Time {.rtl, extern: "nos$1".} =
## Returns the `file`'s last read or write access time.
when defined(posix):
var res: TStat
var res: Stat
if stat(file, res) < 0'i32: raiseOSError(osLastError())
return res.st_atime
else:
var f: TWIN32_FIND_DATA
var f: WIN32_FIND_DATA
var h = findFirstFile(file, f)
if h == -1'i32: raiseOSError(osLastError())
result = winTimeToUnixTime(rdFileTime(f.ftLastAccessTime))
@ -461,11 +461,11 @@ proc getCreationTime*(file: string): Time {.rtl, extern: "nos$1".} =
## Note that under posix OS's, the returned time may actually be the time at
## which the file's attribute's were last modified.
when defined(posix):
var res: TStat
var res: Stat
if stat(file, res) < 0'i32: raiseOSError(osLastError())
return res.st_ctime
else:
var f: TWIN32_FIND_DATA
var f: WIN32_FIND_DATA
var h = findFirstFile(file, f)
if h == -1'i32: raiseOSError(osLastError())
result = winTimeToUnixTime(rdFileTime(f.ftCreationTime))
@ -794,20 +794,20 @@ proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1".} =
result = path[0] == '/'
when defined(Windows):
proc openHandle(path: string, followSymlink=true): THandle =
proc openHandle(path: string, followSymlink=true): Handle =
var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL
if not followSymlink:
flags = flags or FILE_FLAG_OPEN_REPARSE_POINT
when useWinUnicode:
result = createFileW(
newWideCString(path), 0'i32,
newWideCString(path), 0'i32,
FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, flags, 0
)
else:
result = createFileA(
path, 0'i32,
path, 0'i32,
FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, flags, 0
)
@ -827,7 +827,7 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
var lastErr: OSErrorCode
if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE:
var fi1, fi2: TBY_HANDLE_FILE_INFORMATION
var fi1, fi2: BY_HANDLE_FILE_INFORMATION
if getFileInformationByHandle(f1, addr(fi1)) != 0 and
getFileInformationByHandle(f2, addr(fi2)) != 0:
@ -846,7 +846,7 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
if not success: raiseOSError(lastErr)
else:
var a, b: TStat
var a, b: Stat
if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32:
raiseOSError(osLastError())
else:
@ -903,7 +903,7 @@ proc getFilePermissions*(filename: string): set[FilePermission] {.
## an error. On Windows, only the ``readonly`` flag is checked, every other
## permission is available in any case.
when defined(posix):
var a: TStat
var a: Stat
if stat(filename, a) < 0'i32: raiseOSError(osLastError())
result = {}
if (a.st_mode and S_IRUSR) != 0'i32: result.incl(fpUserRead)
@ -924,11 +924,11 @@ proc getFilePermissions*(filename: string): set[FilePermission] {.
var res = getFileAttributesA(filename)
if res == -1'i32: raiseOSError(osLastError())
if (res and FILE_ATTRIBUTE_READONLY) != 0'i32:
result = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead,
result = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead,
fpOthersExec, fpOthersRead}
else:
result = {fpUserExec..fpOthersRead}
proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {.
rtl, extern: "nos$1", tags: [WriteDirEffect].} =
## sets the file permissions for `filename`. `OSError` is raised in case of
@ -939,15 +939,15 @@ proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {.
if fpUserRead in permissions: p = p or S_IRUSR
if fpUserWrite in permissions: p = p or S_IWUSR
if fpUserExec in permissions: p = p or S_IXUSR
if fpGroupRead in permissions: p = p or S_IRGRP
if fpGroupWrite in permissions: p = p or S_IWGRP
if fpGroupExec in permissions: p = p or S_IXGRP
if fpOthersRead in permissions: p = p or S_IROTH
if fpOthersWrite in permissions: p = p or S_IWOTH
if fpOthersExec in permissions: p = p or S_IXOTH
if chmod(filename, p) != 0: raiseOSError(osLastError())
else:
when useWinUnicode:
@ -955,7 +955,7 @@ proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {.
else:
var res = getFileAttributesA(filename)
if res == -1'i32: raiseOSError(osLastError())
if fpUserWrite in permissions:
if fpUserWrite in permissions:
res = res and not FILE_ATTRIBUTE_READONLY
else:
res = res or FILE_ATTRIBUTE_READONLY
@ -1030,11 +1030,11 @@ when not declared(ENOENT) and not defined(Windows):
when defined(Windows):
when useWinUnicode:
template deleteFile(file: expr): expr {.immediate.} = deleteFileW(file)
template setFileAttributes(file, attrs: expr): expr {.immediate.} =
template setFileAttributes(file, attrs: expr): expr {.immediate.} =
setFileAttributesW(file, attrs)
else:
template deleteFile(file: expr): expr {.immediate.} = deleteFileA(file)
template setFileAttributes(file, attrs: expr): expr {.immediate.} =
template setFileAttributes(file, attrs: expr): expr {.immediate.} =
setFileAttributesA(file, attrs)
proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
@ -1047,7 +1047,7 @@ proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].}
else:
let f = file
if deleteFile(f) == 0:
if getLastError() == ERROR_ACCESS_DENIED:
if getLastError() == ERROR_ACCESS_DENIED:
if setFileAttributes(f, FILE_ATTRIBUTE_NORMAL) == 0:
raiseOSError(osLastError())
if deleteFile(f) == 0:
@ -1220,7 +1220,7 @@ iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect].} =
## notation is supported.
when defined(windows):
var
f: TWIN32_FIND_DATA
f: WIN32_FIND_DATA
res: int
res = findFirstFile(pattern, f)
if res != -1:
@ -1232,7 +1232,7 @@ iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect].} =
findClose(res)
else: # here we use glob
var
f: TGlob
f: Glob
res: int
f.gl_offs = 0
f.gl_pathc = 0
@ -1276,7 +1276,7 @@ iterator walkDir*(dir: string): tuple[kind: PathComponent, path: string] {.
## dirA/fileA1.txt
## dirA/fileA2.txt
when defined(windows):
var f: TWIN32_FIND_DATA
var f: WIN32_FIND_DATA
var h = findFirstFile(dir / "*", f)
if h != -1:
while true:
@ -1297,7 +1297,7 @@ iterator walkDir*(dir: string): tuple[kind: PathComponent, path: string] {.
if x == nil: break
var y = $x.d_name
if y != "." and y != "..":
var s: TStat
var s: Stat
y = dir / y
var k = pcFile
@ -1319,9 +1319,9 @@ iterator walkDirRec*(dir: string, filter={pcFile, pcDir}): string {.
## walks over the directory `dir` and yields for each file in `dir`. The
## full path for each file is returned.
## **Warning**:
## Modifying the directory structure while the iterator
## is traversing may result in undefined behavior!
##
## Modifying the directory structure while the iterator
## is traversing may result in undefined behavior!
##
## Walking is recursive. `filter` controls the behaviour of the iterator:
##
## --------------------- ---------------------------------------------
@ -1424,7 +1424,7 @@ proc createSymlink*(src, dest: string) =
## by `src`. On most operating systems, will fail if a lonk
##
## **Warning**:
## Some OS's (such as Microsoft Windows) restrict the creation
## Some OS's (such as Microsoft Windows) restrict the creation
## of symlinks to root users (administrators).
when defined(Windows):
let flag = dirExists(src).int32
@ -1444,7 +1444,7 @@ proc createHardlink*(src, dest: string) =
## Create a hard link at `dest` which points to the item specified
## by `src`.
##
## **Warning**: Most OS's restrict the creation of hard links to
## **Warning**: Most OS's restrict the creation of hard links to
## root users (administrators) .
when defined(Windows):
when useWinUnicode:
@ -1548,7 +1548,7 @@ proc parseCmdLine*(c: string): seq[string] {.
add(a, c[i])
inc(i)
add(result, a)
proc copyFileWithPermissions*(source, dest: string,
ignorePermissionErrors = true) =
## Copies a file from `source` to `dest` preserving file permissions.
@ -1842,7 +1842,7 @@ proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect].} =
when defined(windows):
winlean.sleep(int32(milsecs))
else:
var a, b: Ttimespec
var a, b: Timespec
a.tv_sec = Time(milsecs div 1000)
a.tv_nsec = (milsecs mod 1000) * 1000 * 1000
discard posix.nanosleep(a, b)
@ -1851,7 +1851,7 @@ proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1",
tags: [ReadIOEffect].} =
## returns the file size of `file`. Can raise ``OSError``.
when defined(windows):
var a: TWIN32_FIND_DATA
var a: WIN32_FIND_DATA
var resA = findFirstFile(file, a)
if resA == -1: raiseOSError(osLastError())
result = rdFileSize(a)
@ -1907,8 +1907,8 @@ when defined(Windows):
FileId* = int64
else:
type
DeviceId* = TDev
FileId* = Tino
DeviceId* = Dev
FileId* = Ino
type
FileInfo* = object
@ -1925,7 +1925,7 @@ type
template rawToFormalFileInfo(rawInfo, formalInfo): expr =
## Transforms the native file info structure into the one nim uses.
## 'rawInfo' is either a 'TBY_HANDLE_FILE_INFORMATION' structure on Windows,
## or a 'TStat' structure on posix
## or a 'Stat' structure on posix
when defined(Windows):
template toTime(e): expr = winTimeToUnixTime(rdFileTime(e))
template merge(a, b): expr = a or (b shl 32)
@ -1936,10 +1936,10 @@ template rawToFormalFileInfo(rawInfo, formalInfo): expr =
formalInfo.lastAccessTime = toTime(rawInfo.ftLastAccessTime)
formalInfo.lastWriteTime = toTime(rawInfo.ftLastWriteTime)
formalInfo.creationTime = toTime(rawInfo.ftCreationTime)
# Retrieve basic permissions
if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_READONLY) != 0'i32:
formalInfo.permissions = {fpUserExec, fpUserRead, fpGroupExec,
formalInfo.permissions = {fpUserExec, fpUserRead, fpGroupExec,
fpGroupRead, fpOthersExec, fpOthersRead}
else:
result.permissions = {fpUserExec..fpOthersRead}
@ -1953,7 +1953,7 @@ template rawToFormalFileInfo(rawInfo, formalInfo): expr =
else:
template checkAndIncludeMode(rawMode, formalMode: expr) =
template checkAndIncludeMode(rawMode, formalMode: expr) =
if (rawInfo.st_mode and rawMode) != 0'i32:
formalInfo.permissions.incl(formalMode)
formalInfo.id = (rawInfo.st_dev, rawInfo.st_ino)
@ -1988,7 +1988,7 @@ proc getFileInfo*(handle: FileHandle): FileInfo =
## is invalid, an error will be thrown.
# Done: ID, Kind, Size, Permissions, Link Count
when defined(Windows):
var rawInfo: TBY_HANDLE_FILE_INFORMATION
var rawInfo: BY_HANDLE_FILE_INFORMATION
# We have to use the super special '_get_osfhandle' call (wrapped above)
# To transform the C file descripter to a native file handle.
var realHandle = get_osfhandle(handle)
@ -1996,7 +1996,7 @@ proc getFileInfo*(handle: FileHandle): FileInfo =
raiseOSError(osLastError())
rawToFormalFileInfo(rawInfo, result)
else:
var rawInfo: TStat
var rawInfo: Stat
if fstat(handle, rawInfo) < 0'i32:
raiseOSError(osLastError())
rawToFormalFileInfo(rawInfo, result)
@ -2008,22 +2008,22 @@ proc getFileInfo*(file: File): FileInfo =
proc getFileInfo*(path: string, followSymlink = true): FileInfo =
## Retrieves file information for the file object pointed to by `path`.
##
##
## Due to intrinsic differences between operating systems, the information
## contained by the returned `FileInfo` structure will be slightly different
## across platforms, and in some cases, incomplete or inaccurate.
##
##
## When `followSymlink` is true, symlinks are followed and the information
## retrieved is information related to the symlink's target. Otherwise,
## information on the symlink itself is retrieved.
##
##
## If the information cannot be retrieved, such as when the path doesn't
## exist, or when permission restrictions prevent the program from retrieving
## file information, an error will be thrown.
when defined(Windows):
var
var
handle = openHandle(path, followSymlink)
rawInfo: TBY_HANDLE_FILE_INFORMATION
rawInfo: BY_HANDLE_FILE_INFORMATION
if handle == INVALID_HANDLE_VALUE:
raiseOSError(osLastError())
if getFileInformationByHandle(handle, addr rawInfo) == 0:
@ -2031,7 +2031,7 @@ proc getFileInfo*(path: string, followSymlink = true): FileInfo =
rawToFormalFileInfo(rawInfo, result)
discard closeHandle(handle)
else:
var rawInfo: TStat
var rawInfo: Stat
if followSymlink:
if stat(path, rawInfo) < 0'i32:
raiseOSError(osLastError())
@ -2044,7 +2044,7 @@ proc isHidden*(path: string): bool =
## Determines whether a given path is hidden or not. Returns false if the
## file doesn't exist. The given path must be accessible from the current
## working directory of the program.
##
##
## On Windows, a file is hidden if the file's 'hidden' attribute is set.
## On Unix-like systems, a file is hidden if it starts with a '.' (period)
## and is not *just* '.' or '..' ' ."

View file

@ -26,13 +26,13 @@ when defined(linux):
type
ProcessObj = object of RootObj
when defined(windows):
fProcessHandle: THandle
fProcessHandle: Handle
inHandle, outHandle, errHandle: FileHandle
id: THandle
id: Handle
else:
inHandle, outHandle, errHandle: FileHandle
inStream, outStream, errStream: Stream
id: TPid
id: Pid
exitCode: cint
Process* = ref ProcessObj ## represents an operating system process
@ -334,10 +334,11 @@ when not defined(useNimRtl):
when defined(Windows) and not defined(useNimRtl):
# We need to implement a handle stream for Windows:
type
PFileHandleStream = ref TFileHandleStream
TFileHandleStream = object of StreamObj
handle: THandle
PFileHandleStream = ref FileHandleStream
FileHandleStream = object of StreamObj
handle: Handle
atTheEnd: bool
{.deprecated: [TFileHandleStream: FileHandleStream].}
proc hsClose(s: Stream) = discard # nothing to do here
proc hsAtEnd(s: Stream): bool = return PFileHandleStream(s).atTheEnd
@ -361,7 +362,7 @@ when defined(Windows) and not defined(useNimRtl):
addr bytesWritten, nil)
if a == 0: raiseOSError(osLastError())
proc newFileHandleStream(handle: THandle): PFileHandleStream =
proc newFileHandleStream(handle: Handle): PFileHandleStream =
new(result)
result.handle = handle
result.closeImpl = hsClose
@ -387,22 +388,22 @@ when defined(Windows) and not defined(useNimRtl):
copyMem(addr(result[L]), cstring(x), x.len+1) # copy \0
inc(L, x.len+1)
#proc open_osfhandle(osh: THandle, mode: int): int {.
#proc open_osfhandle(osh: Handle, mode: int): int {.
# importc: "_open_osfhandle", header: "<fcntl.h>".}
#var
# O_WRONLY {.importc: "_O_WRONLY", header: "<fcntl.h>".}: int
# O_RDONLY {.importc: "_O_RDONLY", header: "<fcntl.h>".}: int
proc createPipeHandles(rdHandle, wrHandle: var THandle) =
var piInheritablePipe: TSECURITY_ATTRIBUTES
piInheritablePipe.nLength = sizeof(TSECURITY_ATTRIBUTES).cint
proc createPipeHandles(rdHandle, wrHandle: var Handle) =
var piInheritablePipe: SECURITY_ATTRIBUTES
piInheritablePipe.nLength = sizeof(SECURITY_ATTRIBUTES).cint
piInheritablePipe.lpSecurityDescriptor = nil
piInheritablePipe.bInheritHandle = 1
if createPipe(rdHandle, wrHandle, piInheritablePipe, 1024) == 0'i32:
raiseOSError(osLastError())
proc fileClose(h: THandle) {.inline.} =
proc fileClose(h: Handle) {.inline.} =
if h > 4: discard closeHandle(h)
proc startProcess(command: string,
@ -411,10 +412,10 @@ when defined(Windows) and not defined(useNimRtl):
env: StringTableRef = nil,
options: set[ProcessOption] = {poStdErrToStdOut}): Process =
var
si: TSTARTUPINFO
procInfo: TPROCESS_INFORMATION
si: STARTUPINFO
procInfo: PROCESS_INFORMATION
success: int
hi, ho, he: THandle
hi, ho, he: Handle
new(result)
si.cb = sizeof(si).cint
if poParentStreams notin options:
@ -525,9 +526,9 @@ when defined(Windows) and not defined(useNimRtl):
proc execCmd(command: string): int =
var
si: TSTARTUPINFO
procInfo: TPROCESS_INFORMATION
process: THandle
si: STARTUPINFO
procInfo: PROCESS_INFORMATION
process: Handle
L: int32
si.cb = sizeof(si).cint
si.hStdError = getStdHandle(STD_ERROR_HANDLE)
@ -554,7 +555,7 @@ when defined(Windows) and not defined(useNimRtl):
proc select(readfds: var seq[Process], timeout = 500): int =
assert readfds.len <= MAXIMUM_WAIT_OBJECTS
var rfds: TWOHandleArray
var rfds: WOHandleArray
for i in 0..readfds.len()-1:
rfds[i] = readfds[i].fProcessHandle
@ -595,7 +596,7 @@ elif not defined(useNimRtl):
copyMem(result[i], addr(x[0]), x.len+1)
inc(i)
type TStartProcessData = object
type StartProcessData = object
sysCommand: cstring
sysArgs: cstringArray
sysEnv: cstringArray
@ -604,14 +605,15 @@ elif not defined(useNimRtl):
optionPoUsePath: bool
optionPoParentStreams: bool
optionPoStdErrToStdOut: bool
{.deprecated: [TStartProcessData: StartProcessData].}
when not defined(useFork):
proc startProcessAuxSpawn(data: TStartProcessData): TPid {.
proc startProcessAuxSpawn(data: StartProcessData): Pid {.
tags: [ExecIOEffect, ReadEnvEffect], gcsafe.}
proc startProcessAuxFork(data: TStartProcessData): TPid {.
proc startProcessAuxFork(data: StartProcessData): Pid {.
tags: [ExecIOEffect, ReadEnvEffect], gcsafe.}
{.push stacktrace: off, profiler: off.}
proc startProcessAfterFork(data: ptr TStartProcessData) {.
proc startProcessAfterFork(data: ptr StartProcessData) {.
tags: [ExecIOEffect, ReadEnvEffect], cdecl, gcsafe.}
{.pop.}
@ -641,7 +643,7 @@ elif not defined(useNimRtl):
for arg in args.items:
sysArgsRaw.add arg
var pid: TPid
var pid: Pid
var sysArgs = allocCStringArray(sysArgsRaw)
defer: deallocCStringArray(sysArgs)
@ -653,7 +655,7 @@ elif not defined(useNimRtl):
defer: deallocCStringArray(sysEnv)
var data: TStartProcessData
var data: StartProcessData
data.sysCommand = sysCommand
data.sysArgs = sysArgs
data.sysEnv = sysEnv
@ -698,7 +700,7 @@ elif not defined(useNimRtl):
discard close(pStdout[writeIdx])
when not defined(useFork):
proc startProcessAuxSpawn(data: TStartProcessData): TPid =
proc startProcessAuxSpawn(data: StartProcessData): Pid =
var attr: Tposix_spawnattr
var fops: Tposix_spawn_file_actions
@ -708,7 +710,7 @@ elif not defined(useNimRtl):
chck posix_spawn_file_actions_init(fops)
chck posix_spawnattr_init(attr)
var mask: Tsigset
var mask: Sigset
chck sigemptyset(mask)
chck posix_spawnattr_setsigmask(attr, mask)
chck posix_spawnattr_setpgroup(attr, 0'i32)
@ -732,7 +734,7 @@ elif not defined(useNimRtl):
# FIXME: chdir is global to process
if data.workingDir.len > 0:
setCurrentDir($data.workingDir)
var pid: TPid
var pid: Pid
if data.optionPoUsePath:
res = posix_spawnp(pid, data.sysCommand, fops, attr, data.sysArgs, data.sysEnv)
@ -744,14 +746,14 @@ elif not defined(useNimRtl):
chck res
return pid
proc startProcessAuxFork(data: TStartProcessData): TPid =
proc startProcessAuxFork(data: StartProcessData): Pid =
if pipe(data.pErrorPipe) != 0:
raiseOSError(osLastError())
defer:
discard close(data.pErrorPipe[readIdx])
var pid: TPid
var pid: Pid
var dataCopy = data
when defined(useClone):
@ -781,7 +783,7 @@ elif not defined(useNimRtl):
return pid
{.push stacktrace: off, profiler: off.}
proc startProcessFail(data: ptr TStartProcessData) =
proc startProcessFail(data: ptr StartProcessData) =
var error: cint = errno
discard write(data.pErrorPipe[writeIdx], addr error, sizeof(error))
exitnow(1)
@ -789,7 +791,7 @@ elif not defined(useNimRtl):
when defined(macosx) or defined(freebsd):
var environ {.importc.}: cstringArray
proc startProcessAfterFork(data: ptr TStartProcessData) =
proc startProcessAfterFork(data: ptr StartProcessData) =
# Warning: no GC here!
# Or anything that touches global structures - all called nim procs
# must be marked with stackTrace:off. Inspect C code after making changes.

View file

@ -133,7 +133,7 @@ proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} =
when declared(initOptParser):
iterator getopt*(): tuple[kind: CmdLineKind, key, val: TaintedString] =
## This is an convenience iterator for iterating over the command line.
## This uses the TOptParser object. Example:
## This uses the OptParser object. Example:
##
## .. code-block:: nim
## var

View file

@ -74,8 +74,8 @@ type
line: int ## line the symbol has been declared/used in
col: int ## column the symbol has been declared/used in
flags: set[NonTerminalFlag] ## the nonterminal's flags
rule: TNode ## the rule that the symbol refers to
TNode {.shallow.} = object
rule: Node ## the rule that the symbol refers to
Node {.shallow.} = object
case kind: PegKind
of pkEmpty..pkWhitespace: nil
of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle: term: string
@ -83,12 +83,12 @@ type
of pkCharChoice, pkGreedyRepSet: charChoice: ref set[char]
of pkNonTerminal: nt: NonTerminal
of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns]
else: sons: seq[TNode]
else: sons: seq[Node]
NonTerminal* = ref NonTerminalObj
Peg* = TNode ## type that represents a PEG
Peg* = Node ## type that represents a PEG
{.deprecated: [TPeg: Peg].}
{.deprecated: [TPeg: Peg, TNode: Node].}
proc term*(t: string): Peg {.nosideEffect, rtl, extern: "npegs$1Str".} =
## constructs a PEG from a terminal string
@ -1014,12 +1014,12 @@ proc split*(s: string, sep: Peg): seq[string] {.
# ------------------- scanner -------------------------------------------------
type
TModifier = enum
Modifier = enum
modNone,
modVerbatim,
modIgnoreCase,
modIgnoreStyle
TTokKind = enum ## enumeration of all tokens
TokKind = enum ## enumeration of all tokens
tkInvalid, ## invalid token
tkEof, ## end of file reached
tkAny, ## .
@ -1046,9 +1046,9 @@ type
tkDollar, ## '$'
tkHat ## '^'
TToken {.final.} = object ## a token
kind: TTokKind ## the type of the token
modifier: TModifier
Token {.final.} = object ## a token
kind: TokKind ## the type of the token
modifier: Modifier
literal: string ## the parsed (string) literal
charset: set[char] ## if kind == tkCharSet
index: int ## if kind == tkBackref
@ -1060,9 +1060,10 @@ type
lineStart: int ## index of last line start in buffer
colOffset: int ## column to add
filename: string
{.deprecated: [TTokKind: TokKind, TToken: Token, TModifier: Modifier].}
const
tokKindToStr: array[TTokKind, string] = [
tokKindToStr: array[TokKind, string] = [
"invalid", "[EOF]", ".", "_", "identifier", "string literal",
"character set", "(", ")", "{", "}", "{@}",
"<-", "/", "*", "+", "&", "!", "?",
@ -1114,7 +1115,7 @@ proc handleHexChar(c: var PegLexer, xi: var int) =
inc(c.bufpos)
else: discard
proc getEscapedChar(c: var PegLexer, tok: var TToken) =
proc getEscapedChar(c: var PegLexer, tok: var Token) =
inc(c.bufpos)
case c.buf[c.bufpos]
of 'r', 'R', 'c', 'C':
@ -1185,7 +1186,7 @@ proc skip(c: var PegLexer) =
break # EndOfFile also leaves the loop
c.bufpos = pos
proc getString(c: var PegLexer, tok: var TToken) =
proc getString(c: var PegLexer, tok: var Token) =
tok.kind = tkStringLit
var pos = c.bufpos + 1
var buf = c.buf
@ -1207,7 +1208,7 @@ proc getString(c: var PegLexer, tok: var TToken) =
inc(pos)
c.bufpos = pos
proc getDollar(c: var PegLexer, tok: var TToken) =
proc getDollar(c: var PegLexer, tok: var Token) =
var pos = c.bufpos + 1
var buf = c.buf
if buf[pos] in {'0'..'9'}:
@ -1220,7 +1221,7 @@ proc getDollar(c: var PegLexer, tok: var TToken) =
tok.kind = tkDollar
c.bufpos = pos
proc getCharSet(c: var PegLexer, tok: var TToken) =
proc getCharSet(c: var PegLexer, tok: var Token) =
tok.kind = tkCharSet
tok.charset = {}
var pos = c.bufpos + 1
@ -1271,7 +1272,7 @@ proc getCharSet(c: var PegLexer, tok: var TToken) =
c.bufpos = pos
if caret: tok.charset = {'\1'..'\xFF'} - tok.charset
proc getSymbol(c: var PegLexer, tok: var TToken) =
proc getSymbol(c: var PegLexer, tok: var Token) =
var pos = c.bufpos
var buf = c.buf
while true:
@ -1281,7 +1282,7 @@ proc getSymbol(c: var PegLexer, tok: var TToken) =
c.bufpos = pos
tok.kind = tkIdentifier
proc getBuiltin(c: var PegLexer, tok: var TToken) =
proc getBuiltin(c: var PegLexer, tok: var Token) =
if c.buf[c.bufpos+1] in strutils.Letters:
inc(c.bufpos)
getSymbol(c, tok)
@ -1290,7 +1291,7 @@ proc getBuiltin(c: var PegLexer, tok: var TToken) =
tok.kind = tkEscaped
getEscapedChar(c, tok) # may set tok.kind to tkInvalid
proc getTok(c: var PegLexer, tok: var TToken) =
proc getTok(c: var PegLexer, tok: var Token) =
tok.kind = tkInvalid
tok.modifier = modNone
setLen(tok.literal, 0)
@ -1408,9 +1409,9 @@ type
EInvalidPeg* = object of ValueError ## raised if an invalid
## PEG has been detected
PegParser = object of PegLexer ## the PEG parser object
tok: TToken
tok: Token
nonterms: seq[NonTerminal]
modifier: TModifier
modifier: Modifier
captures: int
identIsVerbatim: bool
skip: Peg
@ -1425,7 +1426,7 @@ proc getTok(p: var PegParser) =
getTok(p, p.tok)
if p.tok.kind == tkInvalid: pegError(p, "invalid token")
proc eat(p: var PegParser, kind: TTokKind) =
proc eat(p: var PegParser, kind: TokKind) =
if p.tok.kind == kind: getTok(p)
else: pegError(p, tokKindToStr[kind] & " expected")
@ -1439,13 +1440,13 @@ proc getNonTerminal(p: var PegParser, name: string): NonTerminal =
result = newNonTerminal(name, getLine(p), getColumn(p))
add(p.nonterms, result)
proc modifiedTerm(s: string, m: TModifier): Peg =
proc modifiedTerm(s: string, m: Modifier): Peg =
case m
of modNone, modVerbatim: result = term(s)
of modIgnoreCase: result = termIgnoreCase(s)
of modIgnoreStyle: result = termIgnoreStyle(s)
proc modifiedBackref(s: int, m: TModifier): Peg =
proc modifiedBackref(s: int, m: Modifier): Peg =
case m
of modNone, modVerbatim: result = backref(s)
of modIgnoreCase: result = backrefIgnoreCase(s)

View file

@ -206,13 +206,13 @@ proc abs*[T](x: Rational[T]): Rational[T] =
result.num = abs x.num
result.den = abs x.den
proc hash*[T](x: Rational[T]): THash =
proc hash*[T](x: Rational[T]): Hash =
## Computes hash for rational `x`
# reduce first so that hash(x) == hash(y) for x == y
var copy = x
reduce(copy)
var h: THash = 0
var h: Hash = 0
h = h !& hash(copy.num)
h = h !& hash(copy.den)
result = !$h

View file

@ -106,13 +106,13 @@ proc `$`*(p: Port): string {.borrow.}
## returns the port number as a string
proc toInt*(domain: Domain): cint
## Converts the TDomain enum to a platform-dependent ``cint``.
## Converts the Domain enum to a platform-dependent ``cint``.
proc toInt*(typ: SockType): cint
## Converts the TType enum to a platform-dependent ``cint``.
## Converts the SockType enum to a platform-dependent ``cint``.
proc toInt*(p: Protocol): cint
## Converts the TProtocol enum to a platform-dependent ``cint``.
## Converts the Protocol enum to a platform-dependent ``cint``.
when not useWinVersion:
proc toInt(domain: Domain): cint =

View file

@ -10,8 +10,8 @@
## This module implements a redis client. It allows you to connect to a
## redis-server instance, send commands and receive replies.
##
## **Beware**: Most (if not all) functions that return a ``TRedisString`` may
## return ``redisNil``, and functions which return a ``TRedisList``
## **Beware**: Most (if not all) functions that return a ``RedisString`` may
## return ``redisNil``, and functions which return a ``RedisList``
## may return ``nil``.
import sockets, os, strutils, parseutils
@ -843,27 +843,27 @@ proc pfmerge*(r: Redis, destination: string, sources: varargs[string]) =
# TODO: pub/sub -- I don't think this will work synchronously.
discard """
proc psubscribe*(r: TRedis, pattern: openarray[string]): ???? =
proc psubscribe*(r: Redis, pattern: openarray[string]): ???? =
## Listen for messages published to channels matching the given patterns
r.socket.send("PSUBSCRIBE $#\c\L" % pattern)
return ???
proc publish*(r: TRedis, channel: string, message: string): TRedisInteger =
proc publish*(r: Redis, channel: string, message: string): RedisInteger =
## Post a message to a channel
r.socket.send("PUBLISH $# $#\c\L" % [channel, message])
return r.readInteger()
proc punsubscribe*(r: TRedis, [pattern: openarray[string], : string): ???? =
proc punsubscribe*(r: Redis, [pattern: openarray[string], : string): ???? =
## Stop listening for messages posted to channels matching the given patterns
r.socket.send("PUNSUBSCRIBE $# $#\c\L" % [[pattern.join(), ])
return ???
proc subscribe*(r: TRedis, channel: openarray[string]): ???? =
proc subscribe*(r: Redis, channel: openarray[string]): ???? =
## Listen for messages published to the given channels
r.socket.send("SUBSCRIBE $#\c\L" % channel.join)
return ???
proc unsubscribe*(r: TRedis, [channel: openarray[string], : string): ???? =
proc unsubscribe*(r: Redis, [channel: openarray[string], : string): ???? =
## Stop listening for messages posted to the given channels
r.socket.send("UNSUBSCRIBE $# $#\c\L" % [[channel.join(), ])
return ???
@ -991,7 +991,7 @@ proc lastsave*(r: Redis): RedisInteger =
return r.readInteger()
discard """
proc monitor*(r: TRedis) =
proc monitor*(r: Redis) =
## Listen for all requests received by the server in real time
r.socket.send("MONITOR\c\L")
raiseNoOK(r.readStatus(), r.pipeline.enabled)

View file

@ -18,7 +18,7 @@ elif defined(windows):
else:
import posix
proc hash*(x: SocketHandle): THash {.borrow.}
proc hash*(x: SocketHandle): Hash {.borrow.}
proc `$`*(x: SocketHandle): string {.borrow.}
type
@ -41,7 +41,7 @@ when defined(nimdoc):
proc register*(s: Selector, fd: SocketHandle, events: set[Event],
data: RootRef): SelectorKey {.discardable.} =
## Registers file descriptor ``fd`` to selector ``s`` with a set of TEvent
## Registers file descriptor ``fd`` to selector ``s`` with a set of Event
## ``events``.
proc update*(s: Selector, fd: SocketHandle,

View file

@ -1,697 +0,0 @@
#
#
# Nim's Runtime Library
# (c) Copyright 2015 Andreas Rumpf, Dominik Picheta
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
import
hashes, strutils, lexbase, streams, unicode, macros
type
SexpEventKind* = enum ## enumeration of all events that may occur when parsing
sexpError, ## an error occurred during parsing
sexpEof, ## end of file reached
sexpString, ## a string literal
sexpSymbol, ## a symbol
sexpInt, ## an integer literal
sexpFloat, ## a float literal
sexpNil, ## the value ``nil``
sexpDot, ## the dot to separate car/cdr
sexpListStart, ## start of a list: the ``(`` token
sexpListEnd, ## end of a list: the ``)`` token
TTokKind = enum # must be synchronized with SexpEventKind!
tkError,
tkEof,
tkString,
tkSymbol,
tkInt,
tkFloat,
tkNil,
tkDot,
tkParensLe,
tkParensRi
tkSpace
SexpError* = enum ## enumeration that lists all errors that can occur
errNone, ## no error
errInvalidToken, ## invalid token
errParensRiExpected, ## ``)`` expected
errQuoteExpected, ## ``"`` expected
errEofExpected, ## EOF expected
SexpParser* = object of BaseLexer ## the parser object.
a: string
tok: TTokKind
kind: SexpEventKind
err: SexpError
const
errorMessages: array [SexpError, string] = [
"no error",
"invalid token",
"')' expected",
"'\"' or \"'\" expected",
"EOF expected",
]
tokToStr: array [TTokKind, string] = [
"invalid token",
"EOF",
"string literal",
"symbol",
"int literal",
"float literal",
"nil",
".",
"(", ")", "space"
]
proc close*(my: var SexpParser) {.inline.} =
## closes the parser `my` and its associated input stream.
lexbase.close(my)
proc str*(my: SexpParser): string {.inline.} =
## returns the character data for the events: ``sexpInt``, ``sexpFloat``,
## ``sexpString``
assert(my.kind in {sexpInt, sexpFloat, sexpString})
result = my.a
proc getInt*(my: SexpParser): BiggestInt {.inline.} =
## returns the number for the event: ``sexpInt``
assert(my.kind == sexpInt)
result = parseBiggestInt(my.a)
proc getFloat*(my: SexpParser): float {.inline.} =
## returns the number for the event: ``sexpFloat``
assert(my.kind == sexpFloat)
result = parseFloat(my.a)
proc kind*(my: SexpParser): SexpEventKind {.inline.} =
## returns the current event type for the SEXP parser
result = my.kind
proc getColumn*(my: SexpParser): int {.inline.} =
## get the current column the parser has arrived at.
result = getColNumber(my, my.bufpos)
proc getLine*(my: SexpParser): int {.inline.} =
## get the current line the parser has arrived at.
result = my.lineNumber
proc errorMsg*(my: SexpParser): string =
## returns a helpful error message for the event ``sexpError``
assert(my.kind == sexpError)
result = "($1, $2) Error: $3" % [$getLine(my), $getColumn(my), errorMessages[my.err]]
proc errorMsgExpected*(my: SexpParser, e: string): string =
## returns an error message "`e` expected" in the same format as the
## other error messages
result = "($1, $2) Error: $3" % [$getLine(my), $getColumn(my), e & " expected"]
proc handleHexChar(c: char, x: var int): bool =
result = true # Success
case c
of '0'..'9': x = (x shl 4) or (ord(c) - ord('0'))
of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10)
of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10)
else: result = false # error
proc parseString(my: var SexpParser): TTokKind =
result = tkString
var pos = my.bufpos + 1
var buf = my.buf
while true:
case buf[pos]
of '\0':
my.err = errQuoteExpected
result = tkError
break
of '"':
inc(pos)
break
of '\\':
case buf[pos+1]
of '\\', '"', '\'', '/':
add(my.a, buf[pos+1])
inc(pos, 2)
of 'b':
add(my.a, '\b')
inc(pos, 2)
of 'f':
add(my.a, '\f')
inc(pos, 2)
of 'n':
add(my.a, '\L')
inc(pos, 2)
of 'r':
add(my.a, '\C')
inc(pos, 2)
of 't':
add(my.a, '\t')
inc(pos, 2)
of 'u':
inc(pos, 2)
var r: int
if handleHexChar(buf[pos], r): inc(pos)
if handleHexChar(buf[pos], r): inc(pos)
if handleHexChar(buf[pos], r): inc(pos)
if handleHexChar(buf[pos], r): inc(pos)
add(my.a, toUTF8(Rune(r)))
else:
# don't bother with the error
add(my.a, buf[pos])
inc(pos)
of '\c':
pos = lexbase.handleCR(my, pos)
buf = my.buf
add(my.a, '\c')
of '\L':
pos = lexbase.handleLF(my, pos)
buf = my.buf
add(my.a, '\L')
else:
add(my.a, buf[pos])
inc(pos)
my.bufpos = pos # store back
proc parseNumber(my: var SexpParser) =
var pos = my.bufpos
var buf = my.buf
if buf[pos] == '-':
add(my.a, '-')
inc(pos)
if buf[pos] == '.':
add(my.a, "0.")
inc(pos)
else:
while buf[pos] in Digits:
add(my.a, buf[pos])
inc(pos)
if buf[pos] == '.':
add(my.a, '.')
inc(pos)
# digits after the dot:
while buf[pos] in Digits:
add(my.a, buf[pos])
inc(pos)
if buf[pos] in {'E', 'e'}:
add(my.a, buf[pos])
inc(pos)
if buf[pos] in {'+', '-'}:
add(my.a, buf[pos])
inc(pos)
while buf[pos] in Digits:
add(my.a, buf[pos])
inc(pos)
my.bufpos = pos
proc parseSymbol(my: var SexpParser) =
var pos = my.bufpos
var buf = my.buf
if buf[pos] in IdentStartChars:
while buf[pos] in IdentChars:
add(my.a, buf[pos])
inc(pos)
my.bufpos = pos
proc getTok(my: var SexpParser): TTokKind =
setLen(my.a, 0)
case my.buf[my.bufpos]
of '-', '0'..'9': # numbers that start with a . are not parsed
# correctly.
parseNumber(my)
if {'.', 'e', 'E'} in my.a:
result = tkFloat
else:
result = tkInt
of '"': #" # gotta fix nim-mode
result = parseString(my)
of '(':
inc(my.bufpos)
result = tkParensLe
of ')':
inc(my.bufpos)
result = tkParensRi
of '\0':
result = tkEof
of 'a'..'z', 'A'..'Z', '_':
parseSymbol(my)
if my.a == "nil":
result = tkNil
else:
result = tkSymbol
of ' ':
result = tkSpace
inc(my.bufpos)
of '.':
result = tkDot
inc(my.bufpos)
else:
inc(my.bufpos)
result = tkError
my.tok = result
# ------------- higher level interface ---------------------------------------
type
SexpNodeKind* = enum ## possible SEXP node types
SNil,
SInt,
SFloat,
SString,
SSymbol,
SList,
SCons
SexpNode* = ref SexpNodeObj ## SEXP node
SexpNodeObj* {.acyclic.} = object
case kind*: SexpNodeKind
of SString:
str*: string
of SSymbol:
symbol*: string
of SInt:
num*: BiggestInt
of SFloat:
fnum*: float
of SList:
elems*: seq[SexpNode]
of SCons:
car: SexpNode
cdr: SexpNode
of SNil:
discard
Cons = tuple[car: SexpNode, cdr: SexpNode]
SexpParsingError* = object of ValueError ## is raised for a SEXP error
proc raiseParseErr*(p: SexpParser, msg: string) {.noinline, noreturn.} =
## raises an `ESexpParsingError` exception.
raise newException(SexpParsingError, errorMsgExpected(p, msg))
proc newSString*(s: string): SexpNode {.procvar.}=
## Creates a new `SString SexpNode`.
new(result)
result.kind = SString
result.str = s
proc newSStringMove(s: string): SexpNode =
new(result)
result.kind = SString
shallowCopy(result.str, s)
proc newSInt*(n: BiggestInt): SexpNode {.procvar.} =
## Creates a new `SInt SexpNode`.
new(result)
result.kind = SInt
result.num = n
proc newSFloat*(n: float): SexpNode {.procvar.} =
## Creates a new `SFloat SexpNode`.
new(result)
result.kind = SFloat
result.fnum = n
proc newSNil*(): SexpNode {.procvar.} =
## Creates a new `SNil SexpNode`.
new(result)
proc newSCons*(car, cdr: SexpNode): SexpNode {.procvar.} =
## Creates a new `SCons SexpNode`
new(result)
result.kind = SCons
result.car = car
result.cdr = cdr
proc newSList*(): SexpNode {.procvar.} =
## Creates a new `SList SexpNode`
new(result)
result.kind = SList
result.elems = @[]
proc newSSymbol*(s: string): SexpNode {.procvar.} =
new(result)
result.kind = SSymbol
result.symbol = s
proc newSSymbolMove(s: string): SexpNode =
new(result)
result.kind = SSymbol
shallowCopy(result.symbol, s)
proc getStr*(n: SexpNode, default: string = ""): string =
## Retrieves the string value of a `SString SexpNode`.
##
## Returns ``default`` if ``n`` is not a ``SString``.
if n.kind != SString: return default
else: return n.str
proc getNum*(n: SexpNode, default: BiggestInt = 0): BiggestInt =
## Retrieves the int value of a `SInt SexpNode`.
##
## Returns ``default`` if ``n`` is not a ``SInt``.
if n.kind != SInt: return default
else: return n.num
proc getFNum*(n: SexpNode, default: float = 0.0): float =
## Retrieves the float value of a `SFloat SexpNode`.
##
## Returns ``default`` if ``n`` is not a ``SFloat``.
if n.kind != SFloat: return default
else: return n.fnum
proc getSymbol*(n: SexpNode, default: string = ""): string =
## Retrieves the int value of a `SList SexpNode`.
##
## Returns ``default`` if ``n`` is not a ``SList``.
if n.kind != SSymbol: return default
else: return n.symbol
proc getElems*(n: SexpNode, default: seq[SexpNode] = @[]): seq[SexpNode] =
## Retrieves the int value of a `SList SexpNode`.
##
## Returns ``default`` if ``n`` is not a ``SList``.
if n.kind == SNil: return @[]
elif n.kind != SList: return default
else: return n.elems
proc getCons*(n: SexpNode, defaults: Cons = (newSNil(), newSNil())): Cons =
## Retrieves the cons value of a `SList SexpNode`.
##
## Returns ``default`` if ``n`` is not a ``SList``.
if n.kind == SCons: return (n.car, n.cdr)
elif n.kind == SList: return (n.elems[0], n.elems[1])
else: return defaults
proc sexp*(s: string): SexpNode =
## Generic constructor for SEXP data. Creates a new `SString SexpNode`.
new(result)
result.kind = SString
result.str = s
proc sexp*(n: BiggestInt): SexpNode =
## Generic constructor for SEXP data. Creates a new `SInt SexpNode`.
new(result)
result.kind = SInt
result.num = n
proc sexp*(n: float): SexpNode =
## Generic constructor for SEXP data. Creates a new `SFloat SexpNode`.
new(result)
result.kind = SFloat
result.fnum = n
proc sexp*(b: bool): SexpNode =
## Generic constructor for SEXP data. Creates a new `SSymbol
## SexpNode` with value t or `SNil SexpNode`.
new(result)
if b:
result.kind = SSymbol
result.symbol = "t"
else:
result.kind = SNil
proc sexp*(elements: openArray[SexpNode]): SexpNode =
## Generic constructor for SEXP data. Creates a new `SList SexpNode`
new(result)
result.kind = SList
newSeq(result.elems, elements.len)
for i, p in pairs(elements): result.elems[i] = p
proc sexp*(s: SexpNode): SexpNode =
result = s
proc toSexp(x: NimNode): NimNode {.compiletime.} =
case x.kind
of nnkBracket:
result = newNimNode(nnkBracket)
for i in 0 .. <x.len:
result.add(toSexp(x[i]))
else:
result = x
result = prefix(result, "sexp")
macro convertSexp*(x: expr): expr =
## Convert an expression to a SexpNode directly, without having to specify
## `%` for every element.
result = toSexp(x)
proc `==`* (a,b: SexpNode): bool =
## Check two nodes for equality
if a.isNil:
if b.isNil: return true
return false
elif b.isNil or a.kind != b.kind:
return false
else:
return case a.kind
of SString:
a.str == b.str
of SInt:
a.num == b.num
of SFloat:
a.fnum == b.fnum
of SNil:
true
of SList:
a.elems == b.elems
of SSymbol:
a.symbol == b.symbol
of SCons:
a.car == b.car and a.cdr == b.cdr
proc hash* (n:SexpNode): THash =
## Compute the hash for a SEXP node
case n.kind
of SList:
result = hash(n.elems)
of SInt:
result = hash(n.num)
of SFloat:
result = hash(n.fnum)
of SString:
result = hash(n.str)
of SNil:
result = hash(0)
of SSymbol:
result = hash(n.symbol)
of SCons:
result = hash(n.car) !& hash(n.cdr)
proc len*(n: SexpNode): int =
## If `n` is a `SList`, it returns the number of elements.
## If `n` is a `JObject`, it returns the number of pairs.
## Else it returns 0.
case n.kind
of SList: result = n.elems.len
else: discard
proc `[]`*(node: SexpNode, index: int): SexpNode =
## Gets the node at `index` in a List. Result is undefined if `index`
## is out of bounds
assert(not isNil(node))
assert(node.kind == SList)
return node.elems[index]
proc add*(father, child: SexpNode) =
## Adds `child` to a SList node `father`.
assert father.kind == SList
father.elems.add(child)
# ------------- pretty printing ----------------------------------------------
proc indent(s: var string, i: int) =
s.add(spaces(i))
proc newIndent(curr, indent: int, ml: bool): int =
if ml: return curr + indent
else: return indent
proc nl(s: var string, ml: bool) =
if ml: s.add("\n")
proc escapeJson*(s: string): string =
## Converts a string `s` to its JSON representation.
result = newStringOfCap(s.len + s.len shr 3)
result.add("\"")
for x in runes(s):
var r = int(x)
if r >= 32 and r <= 127:
var c = chr(r)
case c
of '"': result.add("\\\"") #" # gotta fix nim-mode
of '\\': result.add("\\\\")
else: result.add(c)
else:
result.add("\\u")
result.add(toHex(r, 4))
result.add("\"")
proc copy*(p: SexpNode): SexpNode =
## Performs a deep copy of `a`.
case p.kind
of SString:
result = newSString(p.str)
of SInt:
result = newSInt(p.num)
of SFloat:
result = newSFloat(p.fnum)
of SNil:
result = newSNil()
of SSymbol:
result = newSSymbol(p.symbol)
of SList:
result = newSList()
for i in items(p.elems):
result.elems.add(copy(i))
of SCons:
result = newSCons(copy(p.car), copy(p.cdr))
proc toPretty(result: var string, node: SexpNode, indent = 2, ml = true,
lstArr = false, currIndent = 0) =
case node.kind
of SString:
if lstArr: result.indent(currIndent)
result.add(escapeJson(node.str))
of SInt:
if lstArr: result.indent(currIndent)
result.add($node.num)
of SFloat:
if lstArr: result.indent(currIndent)
result.add($node.fnum)
of SNil:
if lstArr: result.indent(currIndent)
result.add("nil")
of SSymbol:
if lstArr: result.indent(currIndent)
result.add($node.symbol)
of SList:
if lstArr: result.indent(currIndent)
if len(node.elems) != 0:
result.add("(")
result.nl(ml)
for i in 0..len(node.elems)-1:
if i > 0:
result.add(" ")
result.nl(ml) # New Line
toPretty(result, node.elems[i], indent, ml,
true, newIndent(currIndent, indent, ml))
result.nl(ml)
result.indent(currIndent)
result.add(")")
else: result.add("nil")
of SCons:
if lstArr: result.indent(currIndent)
result.add("(")
toPretty(result, node.car, indent, ml,
true, newIndent(currIndent, indent, ml))
result.add(" . ")
toPretty(result, node.cdr, indent, ml,
true, newIndent(currIndent, indent, ml))
result.add(")")
proc pretty*(node: SexpNode, indent = 2): string =
## Converts `node` to its Sexp Representation, with indentation and
## on multiple lines.
result = ""
toPretty(result, node, indent)
proc `$`*(node: SexpNode): string =
## Converts `node` to its SEXP Representation on one line.
result = ""
toPretty(result, node, 0, false)
iterator items*(node: SexpNode): SexpNode =
## Iterator for the items of `node`. `node` has to be a SList.
assert node.kind == SList
for i in items(node.elems):
yield i
iterator mitems*(node: var SexpNode): var SexpNode =
## Iterator for the items of `node`. `node` has to be a SList. Items can be
## modified.
assert node.kind == SList
for i in mitems(node.elems):
yield i
proc eat(p: var SexpParser, tok: TTokKind) =
if p.tok == tok: discard getTok(p)
else: raiseParseErr(p, tokToStr[tok])
proc parseSexp(p: var SexpParser): SexpNode =
## Parses SEXP from a SEXP Parser `p`.
case p.tok
of tkString:
# we capture 'p.a' here, so we need to give it a fresh buffer afterwards:
result = newSStringMove(p.a)
p.a = ""
discard getTok(p)
of tkInt:
result = newSInt(parseBiggestInt(p.a))
discard getTok(p)
of tkFloat:
result = newSFloat(parseFloat(p.a))
discard getTok(p)
of tkNil:
result = newSNil()
discard getTok(p)
of tkSymbol:
result = newSSymbolMove(p.a)
p.a = ""
discard getTok(p)
of tkParensLe:
result = newSList()
discard getTok(p)
while p.tok notin {tkParensRi, tkDot}:
result.add(parseSexp(p))
if p.tok != tkSpace: break
discard getTok(p)
if p.tok == tkDot:
eat(p, tkDot)
eat(p, tkSpace)
result.add(parseSexp(p))
result = newSCons(result[0], result[1])
eat(p, tkParensRi)
of tkSpace, tkDot, tkError, tkParensRi, tkEof:
raiseParseErr(p, "(")
proc open*(my: var SexpParser, input: Stream) =
## initializes the parser with an input stream.
lexbase.open(my, input)
my.kind = sexpError
my.a = ""
proc parseSexp*(s: Stream): SexpNode =
## Parses from a buffer `s` into a `SexpNode`.
var p: SexpParser
p.open(s)
discard getTok(p) # read first token
result = p.parseSexp()
p.close()
proc parseSexp*(buffer: string): SexpNode =
## Parses Sexp from `buffer`.
result = parseSexp(newStringStream(buffer))
when isMainModule:
let testSexp = parseSexp("""(1 (98 2) nil (2) foobar "foo" 9.234)""")
assert(testSexp[0].getNum == 1)
assert(testSexp[1][0].getNum == 98)
assert(testSexp[2].getElems == @[])
assert(testSexp[4].getSymbol == "foobar")
assert(testSexp[5].getStr == "foo")
let alist = parseSexp("""((1 . 2) (2 . "foo"))""")
assert(alist[0].getCons.car.getNum == 1)
assert(alist[0].getCons.cdr.getNum == 2)
assert(alist[1].getCons.cdr.getStr == "foo")
# Generator:
var j = convertSexp([true, false, "foobar", [1, 2, "baz"]])
assert($j == """(t nil "foobar" (1 2 "baz"))""")

View file

@ -75,7 +75,7 @@ const
BufferSize*: int = 4000 ## size of a buffered socket's buffer
type
TSocketImpl = object ## socket type
SocketImpl = object ## socket type
fd: SocketHandle
case isBuffered: bool # determines whether this socket is buffered.
of true:
@ -94,7 +94,7 @@ type
of false: nil
nonblocking: bool
Socket* = ref TSocketImpl
Socket* = ref SocketImpl
Port* = distinct uint16 ## port type
@ -146,8 +146,9 @@ type
{.deprecated: [TSocket: Socket, TType: SockType, TPort: Port, TDomain: Domain,
TProtocol: Protocol, TServent: Servent, THostent: Hostent,
TSOBool: SOBool, TRecvLineResult: RecvLineResult,
TReadLineResult: ReadLineResult, ETimeout: TimeoutError].}
TSOBool: SOBool, TRecvLineResult: RecvLineResult,
TReadLineResult: ReadLineResult, ETimeout: TimeoutError,
TSocketImpl: SocketImpl].}
when defined(booting):
let invalidSocket*: Socket = nil ## invalid socket

View file

@ -327,7 +327,7 @@ proc newStringStream*(s: string = ""): StringStream =
when not defined(js):
type
FileStream* = ref FileStreamObj ## a stream that encapsulates a `TFile`
FileStream* = ref FileStreamObj ## a stream that encapsulates a `File`
FileStreamObj* = object of Stream
f: File
{.deprecated: [PFileStream: FileStream, TFileStream: FileStreamObj].}

View file

@ -74,7 +74,7 @@ const
growthFactor = 2
startSize = 64
proc myhash(t: StringTableRef, key: string): THash =
proc myhash(t: StringTableRef, key: string): Hash =
case t.mode
of modeCaseSensitive: result = hashes.hash(key)
of modeCaseInsensitive: result = hashes.hashIgnoreCase(key)
@ -90,11 +90,11 @@ proc mustRehash(length, counter: int): bool =
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)
proc nextTry(h, maxHash: THash): THash {.inline.} =
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
result = ((5 * h) + 1) and maxHash
proc rawGet(t: StringTableRef, key: string): int =
var h: THash = myhash(t, key) and high(t.data) # start with real hash value
var h: Hash = myhash(t, key) and high(t.data) # start with real hash value
while not isNil(t.data[h].key):
if myCmp(t, t.data[h].key, key):
return h
@ -122,7 +122,7 @@ proc hasKey*(t: StringTableRef, key: string): bool {.rtl, extern: "nst$1".} =
result = rawGet(t, key) >= 0
proc rawInsert(t: StringTableRef, data: var KeyValuePairSeq, key, val: string) =
var h: THash = myhash(t, key) and high(data)
var h: Hash = myhash(t, key) and high(data)
while not isNil(data[h].key):
h = nextTry(h, high(data))
data[h].key = key

View file

@ -23,7 +23,8 @@ import parseutils
include "system/inclrtl"
type
TCharSet* {.deprecated.} = set[char] # for compatibility with Nim
CharSet* {.deprecated.} = set[char] # for compatibility with Nim
{.deprecated: [TCharSet: CharSet].}
const
Whitespace* = {' ', '\t', '\v', '\r', '\l', '\f'}

View file

@ -37,13 +37,14 @@ proc raiseInvalidFormat(msg: string) {.noinline.} =
raise newException(SubexError, "invalid format string: " & msg)
type
TFormatParser = object {.pure, final.}
FormatParser = object {.pure, final.}
when defined(js):
f: string # we rely on the '\0' terminator
# which JS's native string doesn't have
else:
f: cstring
num, i, lineLen: int
{.deprecated: [TFormatParser: FormatParser].}
template call(x: stmt) {.immediate.} =
p.i = i
@ -57,7 +58,7 @@ template callNoLineLenTracking(x: stmt) {.immediate.} =
i = p.i
p.lineLen = oldLineLen
proc getFormatArg(p: var TFormatParser, a: openArray[string]): int =
proc getFormatArg(p: var FormatParser, a: openArray[string]): int =
const PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\128'..'\255', '_'}
var i = p.i
var f = p.f
@ -90,22 +91,22 @@ proc getFormatArg(p: var TFormatParser, a: openArray[string]): int =
if result >=% a.len: raiseInvalidFormat("index out of bounds: " & $result)
p.i = i
proc scanDollar(p: var TFormatParser, a: openarray[string], s: var string) {.
proc scanDollar(p: var FormatParser, a: openarray[string], s: var string) {.
noSideEffect.}
proc emitChar(p: var TFormatParser, x: var string, ch: char) {.inline.} =
proc emitChar(p: var FormatParser, x: var string, ch: char) {.inline.} =
x.add(ch)
if ch == '\L': p.lineLen = 0
else: inc p.lineLen
proc emitStrLinear(p: var TFormatParser, x: var string, y: string) {.inline.} =
proc emitStrLinear(p: var FormatParser, x: var string, y: string) {.inline.} =
for ch in items(y): emitChar(p, x, ch)
proc emitStr(p: var TFormatParser, x: var string, y: string) {.inline.} =
proc emitStr(p: var FormatParser, x: var string, y: string) {.inline.} =
x.add(y)
inc p.lineLen, y.len
proc scanQuote(p: var TFormatParser, x: var string, toAdd: bool) =
proc scanQuote(p: var FormatParser, x: var string, toAdd: bool) =
var i = p.i+1
var f = p.f
while true:
@ -120,7 +121,7 @@ proc scanQuote(p: var TFormatParser, x: var string, toAdd: bool) =
inc i
p.i = i
proc scanBranch(p: var TFormatParser, a: openArray[string],
proc scanBranch(p: var FormatParser, a: openArray[string],
x: var string, choice: int) =
var i = p.i
var f = p.f
@ -167,7 +168,7 @@ proc scanBranch(p: var TFormatParser, a: openArray[string],
i = last
p.i = i+1
proc scanSlice(p: var TFormatParser, a: openarray[string]): tuple[x, y: int] =
proc scanSlice(p: var FormatParser, a: openarray[string]): tuple[x, y: int] =
var slice = false
var i = p.i
var f = p.f
@ -193,7 +194,7 @@ proc scanSlice(p: var TFormatParser, a: openarray[string]): tuple[x, y: int] =
inc i
p.i = i
proc scanDollar(p: var TFormatParser, a: openarray[string], s: var string) =
proc scanDollar(p: var FormatParser, a: openarray[string], s: var string) =
var i = p.i
var f = p.f
case f[i]
@ -312,7 +313,7 @@ proc subex*(s: string): Subex =
proc addf*(s: var string, formatstr: Subex, a: varargs[string, `$`]) {.
noSideEffect, rtl, extern: "nfrmtAddf".} =
## The same as ``add(s, formatstr % a)``, but more efficient.
var p: TFormatParser
var p: FormatParser
p.f = formatstr.string
var i = 0
while i < len(formatstr.string):
@ -386,10 +387,10 @@ when isMainModule:
longishA,
longish)"""
assert "type TMyEnum* = enum\n $', '2i'\n '{..}" % ["fieldA",
assert "type MyEnum* = enum\n $', '2i'\n '{..}" % ["fieldA",
"fieldB", "FiledClkad", "fieldD", "fieldE", "longishFieldName"] ==
strutils.unindent """
type TMyEnum* = enum
type MyEnum* = enum
fieldA, fieldB,
FiledClkad, fieldD,
fieldE, longishFieldName"""
@ -400,11 +401,11 @@ when isMainModule:
doAssert subex"$['''|'|''''|']']#" % "0" == "'|"
assert subex("type\n TEnum = enum\n $', '40c'\n '{..}") % [
assert subex("type\n Enum = enum\n $', '40c'\n '{..}") % [
"fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"] ==
strutils.unindent """
type
TEnum = enum
Enum = enum
fieldNameA, fieldNameB, fieldNameC,
fieldNameD"""

View file

@ -20,7 +20,7 @@ when defined(windows):
import windows, os
var
conHandle: THandle
conHandle: Handle
# = createFile("CONOUT$", GENERIC_WRITE, 0, nil, OPEN_ALWAYS, 0, 0)
block:
@ -30,13 +30,13 @@ when defined(windows):
raiseOSError(osLastError())
proc getCursorPos(): tuple [x,y: int] =
var c: TCONSOLESCREENBUFFERINFO
var c: CONSOLESCREENBUFFERINFO
if GetConsoleScreenBufferInfo(conHandle, addr(c)) == 0:
raiseOSError(osLastError())
return (int(c.dwCursorPosition.X), int(c.dwCursorPosition.Y))
proc getAttributes(): int16 =
var c: TCONSOLESCREENBUFFERINFO
var c: CONSOLESCREENBUFFERINFO
# workaround Windows bugs: try several times
if GetConsoleScreenBufferInfo(conHandle, addr(c)) != 0:
return c.wAttributes
@ -51,11 +51,11 @@ else:
proc setRaw(fd: FileHandle, time: cint = TCSAFLUSH) =
var mode: Termios
discard fd.tcgetattr(addr mode)
mode.c_iflag = mode.c_iflag and not Tcflag(BRKINT or ICRNL or INPCK or
mode.c_iflag = mode.c_iflag and not Cflag(BRKINT or ICRNL or INPCK or
ISTRIP or IXON)
mode.c_oflag = mode.c_oflag and not Tcflag(OPOST)
mode.c_cflag = (mode.c_cflag and not Tcflag(CSIZE or PARENB)) or CS8
mode.c_lflag = mode.c_lflag and not Tcflag(ECHO or ICANON or IEXTEN or ISIG)
mode.c_oflag = mode.c_oflag and not Cflag(OPOST)
mode.c_cflag = (mode.c_cflag and not Cflag(CSIZE or PARENB)) or CS8
mode.c_lflag = mode.c_lflag and not Cflag(ECHO or ICANON or IEXTEN or ISIG)
mode.c_cc[VMIN] = 1.cuchar
mode.c_cc[VTIME] = 0.cuchar
discard fd.tcsetattr(time, addr mode)
@ -64,7 +64,7 @@ proc setCursorPos*(x, y: int) =
## sets the terminal's cursor to the (x,y) position. (0,0) is the
## upper left of the screen.
when defined(windows):
var c: TCOORD
var c: COORD
c.X = int16(x)
c.Y = int16(y)
if SetConsoleCursorPosition(conHandle, c) == 0: raiseOSError(osLastError())
@ -75,7 +75,7 @@ proc setCursorXPos*(x: int) =
## sets the terminal's cursor to the x position. The y position is
## not changed.
when defined(windows):
var scrbuf: TCONSOLESCREENBUFFERINFO
var scrbuf: CONSOLESCREENBUFFERINFO
var hStdout = conHandle
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0:
raiseOSError(osLastError())
@ -91,7 +91,7 @@ when defined(windows):
## sets the terminal's cursor to the y position. The x position is
## not changed. **Warning**: This is not supported on UNIX!
when defined(windows):
var scrbuf: TCONSOLESCREENBUFFERINFO
var scrbuf: CONSOLESCREENBUFFERINFO
var hStdout = conHandle
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0:
raiseOSError(osLastError())
@ -172,7 +172,7 @@ else:
proc eraseLine* =
## Erases the entire current line.
when defined(windows):
var scrbuf: TCONSOLESCREENBUFFERINFO
var scrbuf: CONSOLESCREENBUFFERINFO
var numwrote: DWORD
var hStdout = conHandle
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0:
@ -196,9 +196,9 @@ proc eraseLine* =
proc eraseScreen* =
## Erases the screen with the background colour and moves the cursor to home.
when defined(windows):
var scrbuf: TCONSOLESCREENBUFFERINFO
var scrbuf: CONSOLESCREENBUFFERINFO
var numwrote: DWORD
var origin: TCOORD # is inititalized to 0, 0
var origin: COORD # is inititalized to 0, 0
var hStdout = conHandle
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0:
@ -364,7 +364,13 @@ macro styledEcho*(m: varargs[expr]): stmt =
result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n")))
result.add(newCall(bindSym"resetAttributes"))
when not defined(windows):
when defined(nimdoc):
proc getch*(): char =
## Read a single character from the terminal, blocking until it is entered.
## The character is not printed to the terminal. This is not available for
## Windows.
discard
elif not defined(windows):
proc getch*(): char =
## Read a single character from the terminal, blocking until it is entered.
## The character is not printed to the terminal. This is not available for

View file

@ -470,7 +470,7 @@ when not defined(JS):
posix_gettimeofday(a)
result = toFloat(a.tv_sec) + toFloat(a.tv_usec)*0.00_0001
elif defined(windows):
var f: winlean.TFILETIME
var f: winlean.FILETIME
getSystemTimeAsFileTime(f)
var i64 = rdFileTime(f) - epochDiff
var secs = i64 div rateDiff

View file

@ -99,8 +99,9 @@ template test*(name: expr, body: stmt): stmt {.immediate, dirty.} =
body
except:
checkpoint("Unhandled exception: " & getCurrentExceptionMsg())
echo getCurrentException().getStackTrace()
when not defined(js):
checkpoint("Unhandled exception: " & getCurrentExceptionMsg())
echo getCurrentException().getStackTrace()
fail()
finally:
@ -114,9 +115,7 @@ proc checkpoint*(msg: string) =
template fail* =
bind checkpoints
for msg in items(checkpoints):
# this used to be 'echo' which now breaks due to a bug. XXX will revisit
# this issue later.
stdout.writeln msg
echo msg
when not defined(ECMAScript):
if abortOnError: quit(1)
@ -157,12 +156,13 @@ macro check*(conditions: stmt): stmt {.immediate.} =
# Ident !"v"
# IntLit 2
paramAst = exp[i][1]
argsAsgns.add getAst(asgn(arg, paramAst))
argsPrintOuts.add getAst(print(argStr, arg))
if exp[i].kind != nnkExprEqExpr:
exp[i] = arg
else:
exp[i][1] = arg
if exp[i].typekind notin {ntyTypeDesc}:
argsAsgns.add getAst(asgn(arg, paramAst))
argsPrintOuts.add getAst(print(argStr, arg))
if exp[i].kind != nnkExprEqExpr:
exp[i] = arg
else:
exp[i][1] = arg
case checked.kind
of nnkCallKinds:

View file

@ -249,7 +249,7 @@ when defined(nimNewShared):
guarded* {.magic: "Guarded".}
# comparison operators:
proc `==` *[TEnum: enum](x, y: TEnum): bool {.magic: "EqEnum", noSideEffect.}
proc `==` *[Enum: enum](x, y: Enum): bool {.magic: "EqEnum", noSideEffect.}
proc `==` *(x, y: pointer): bool {.magic: "EqRef", noSideEffect.}
proc `==` *(x, y: string): bool {.magic: "EqStr", noSideEffect.}
proc `==` *(x, y: cstring): bool {.magic: "EqCString", noSideEffect.}
@ -260,7 +260,7 @@ proc `==` *[T](x, y: ref T): bool {.magic: "EqRef", noSideEffect.}
proc `==` *[T](x, y: ptr T): bool {.magic: "EqRef", noSideEffect.}
proc `==` *[T: proc](x, y: T): bool {.magic: "EqProc", noSideEffect.}
proc `<=` *[TEnum: enum](x, y: TEnum): bool {.magic: "LeEnum", noSideEffect.}
proc `<=` *[Enum: enum](x, y: Enum): bool {.magic: "LeEnum", noSideEffect.}
proc `<=` *(x, y: string): bool {.magic: "LeStr", noSideEffect.}
proc `<=` *(x, y: char): bool {.magic: "LeCh", noSideEffect.}
proc `<=` *[T](x, y: set[T]): bool {.magic: "LeSet", noSideEffect.}
@ -268,7 +268,7 @@ proc `<=` *(x, y: bool): bool {.magic: "LeB", noSideEffect.}
proc `<=` *[T](x, y: ref T): bool {.magic: "LePtr", noSideEffect.}
proc `<=` *(x, y: pointer): bool {.magic: "LePtr", noSideEffect.}
proc `<` *[TEnum: enum](x, y: TEnum): bool {.magic: "LtEnum", noSideEffect.}
proc `<` *[Enum: enum](x, y: Enum): bool {.magic: "LtEnum", noSideEffect.}
proc `<` *(x, y: string): bool {.magic: "LtStr", noSideEffect.}
proc `<` *(x, y: char): bool {.magic: "LtCh", noSideEffect.}
proc `<` *[T](x, y: set[T]): bool {.magic: "LtSet", noSideEffect.}
@ -332,7 +332,7 @@ type
RootObj* {.exportc: "TNimObject", inheritable.} =
object ## the root of Nim's object hierarchy. Objects should
## inherit from TObject or one of its descendants. However,
## inherit from RootObj or one of its descendants. However,
## objects that have no ancestor are allowed.
RootRef* = ref RootObj ## reference to RootObj
@ -1505,7 +1505,7 @@ proc `$` *(x: string): string {.magic: "StrToStr", noSideEffect.}
## as it is. This operator is useful for generic code, so
## that ``$expr`` also works if ``expr`` is already a string.
proc `$` *[TEnum: enum](x: TEnum): string {.magic: "EnumToStr", noSideEffect.}
proc `$` *[Enum: enum](x: Enum): string {.magic: "EnumToStr", noSideEffect.}
## The stringify operator for an enumeration argument. This works for
## any enumeration type thanks to compiler magic. If
## a ``$`` operator for a concrete enumeration is provided, this is
@ -1535,7 +1535,7 @@ const
NimMinor*: int = 11
## is the minor number of Nim's version.
NimPatch*: int = 2
NimPatch*: int = 3
## is the patch number of Nim's version.
NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
@ -1578,7 +1578,7 @@ else:
type IntLikeForCount = int|int8|int16|int32|char|bool|uint8|uint16|enum
iterator countdown*[T](a, b: T, step = 1): T {.inline.} =
## Counts from ordinal value `a` down to `b` with the given
## Counts from ordinal value `a` down to `b` (inclusive) with the given
## step count. `T` may be any ordinal type, `step` may only
## be positive. **Note**: This fails to count to ``low(int)`` if T = int for
## efficiency reasons.
@ -1606,7 +1606,7 @@ template countupImpl(incr: stmt) {.immediate, dirty.} =
incr
iterator countup*[S, T](a: S, b: T, step = 1): T {.inline.} =
## Counts from ordinal value `a` up to `b` with the given
## Counts from ordinal value `a` up to `b` (inclusive) with the given
## step count. `S`, `T` may be any ordinal type, `step` may only
## be positive. **Note**: This fails to count to ``high(int)`` if T = int for
## efficiency reasons.
@ -2213,6 +2213,7 @@ type
filename*: cstring ## filename of the proc that is currently executing
len*: int16 ## length of the inspectable slots
calldepth*: int16 ## used for max call depth checking
#{.deprecated: [TFrame: Frame].}
when defined(JS):
proc add*(x: var string, y: cstring) {.asmNoStackFrame.} =
@ -2414,7 +2415,7 @@ when not defined(JS): #and not defined(NimrodVM):
proc open*(f: var File, filehandle: FileHandle,
mode: FileMode = fmRead): bool {.tags: [], benign.}
## Creates a ``TFile`` from a `filehandle` with given `mode`.
## Creates a ``File`` from a `filehandle` with given `mode`.
##
## Default mode is readonly. Returns true iff the file could be opened.
@ -2604,6 +2605,8 @@ when not defined(JS): #and not defined(NimrodVM):
context: C_JmpBuf
hasRaiseAction: bool
raiseAction: proc (e: ref Exception): bool {.closure.}
SafePoint = TSafePoint
# {.deprecated: [TSafePoint: SafePoint].}
when declared(initAllocator):
initAllocator()
@ -3054,9 +3057,10 @@ proc raiseAssert*(msg: string) {.noinline.} =
proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
# trick the compiler to not list ``AssertionError`` when called
# by ``assert``.
type THide = proc (msg: string) {.noinline, raises: [], noSideEffect,
type Hide = proc (msg: string) {.noinline, raises: [], noSideEffect,
tags: [].}
THide(raiseAssert)(msg)
{.deprecated: [THide: Hide].}
Hide(raiseAssert)(msg)
template assert*(cond: bool, msg = "") =
## Raises ``AssertionError`` with `msg` if `cond` is false. Note

View file

@ -98,46 +98,49 @@ const
SmallChunkSize = PageSize
type
PTrunk = ptr TTrunk
TTrunk {.final.} = object
PTrunk = ptr Trunk
Trunk {.final.} = object
next: PTrunk # all nodes are connected with this pointer
key: int # start address at bit 0
bits: array[0..IntsPerTrunk-1, int] # a bit vector
TTrunkBuckets = array[0..255, PTrunk]
TIntSet {.final.} = object
data: TTrunkBuckets
TrunkBuckets = array[0..255, PTrunk]
IntSet {.final.} = object
data: TrunkBuckets
{.deprecated: [TIntSet: IntSet, TTrunk: Trunk, TTrunkBuckets: TrunkBuckets].}
type
TAlignType = BiggestFloat
TFreeCell {.final, pure.} = object
next: ptr TFreeCell # next free cell in chunk (overlaid with refcount)
AlignType = BiggestFloat
FreeCell {.final, pure.} = object
next: ptr FreeCell # next free cell in chunk (overlaid with refcount)
zeroField: int # 0 means cell is not used (overlaid with typ field)
# 1 means cell is manually managed pointer
# otherwise a PNimType is stored in there
PChunk = ptr TBaseChunk
PBigChunk = ptr TBigChunk
PSmallChunk = ptr TSmallChunk
TBaseChunk {.pure, inheritable.} = object
PChunk = ptr BaseChunk
PBigChunk = ptr BigChunk
PSmallChunk = ptr SmallChunk
BaseChunk {.pure, inheritable.} = object
prevSize: int # size of previous chunk; for coalescing
size: int # if < PageSize it is a small chunk
used: bool # later will be optimized into prevSize...
TSmallChunk = object of TBaseChunk
SmallChunk = object of BaseChunk
next, prev: PSmallChunk # chunks of the same size
freeList: ptr TFreeCell
freeList: ptr FreeCell
free: int # how many bytes remain
acc: int # accumulator for small object allocation
data: TAlignType # start of usable memory
data: AlignType # start of usable memory
TBigChunk = object of TBaseChunk # not necessarily > PageSize!
BigChunk = object of BaseChunk # not necessarily > PageSize!
next, prev: PBigChunk # chunks of the same (or bigger) size
align: int
data: TAlignType # start of usable memory
data: AlignType # start of usable memory
{.deprecated: [TAlignType: AlignType, TFreeCell: FreeCell, TBaseChunk: BaseChunk,
TBigChunk: BigChunk, TSmallChunk: SmallChunk].}
template smallChunkOverhead(): expr = sizeof(TSmallChunk)-sizeof(TAlignType)
template bigChunkOverhead(): expr = sizeof(TBigChunk)-sizeof(TAlignType)
template smallChunkOverhead(): expr = sizeof(SmallChunk)-sizeof(AlignType)
template bigChunkOverhead(): expr = sizeof(BigChunk)-sizeof(AlignType)
proc roundup(x, v: int): int {.inline.} =
result = (x + (v-1)) and not (v-1)
@ -156,31 +159,32 @@ sysAssert(roundup(65, 8) == 72, "roundup broken 2")
# to the OS), a fixed size array can be used.
type
PLLChunk = ptr TLLChunk
TLLChunk {.pure.} = object ## *low-level* chunk
PLLChunk = ptr LLChunk
LLChunk {.pure.} = object ## *low-level* chunk
size: int # remaining size
acc: int # accumulator
next: PLLChunk # next low-level chunk; only needed for dealloc
PAvlNode = ptr TAvlNode
TAvlNode {.pure, final.} = object
PAvlNode = ptr AvlNode
AvlNode {.pure, final.} = object
link: array[0..1, PAvlNode] # Left (0) and right (1) links
key, upperBound: int
level: int
TMemRegion {.final, pure.} = object
MemRegion {.final, pure.} = object
minLargeObj, maxLargeObj: int
freeSmallChunks: array[0..SmallChunkSize div MemAlign-1, PSmallChunk]
llmem: PLLChunk
currMem, maxMem, freeMem: int # memory sizes (allocated from OS)
lastSize: int # needed for the case that OS gives us pages linearly
freeChunksList: PBigChunk # XXX make this a datastructure with O(1) access
chunkStarts: TIntSet
chunkStarts: IntSet
root, deleted, last, freeAvlNodes: PAvlNode
{.deprecated: [TLLChunk: LLChunk, TAvlNode: AvlNode, TMemRegion: MemRegion].}
# shared:
var
bottomData: TAvlNode
bottomData: AvlNode
bottom: PAvlNode
{.push stack_trace: off.}
@ -191,44 +195,44 @@ proc initAllocator() =
bottom.link[1] = bottom
{.pop.}
proc incCurrMem(a: var TMemRegion, bytes: int) {.inline.} =
proc incCurrMem(a: var MemRegion, bytes: int) {.inline.} =
inc(a.currMem, bytes)
proc decCurrMem(a: var TMemRegion, bytes: int) {.inline.} =
proc decCurrMem(a: var MemRegion, bytes: int) {.inline.} =
a.maxMem = max(a.maxMem, a.currMem)
dec(a.currMem, bytes)
proc getMaxMem(a: var TMemRegion): int =
proc getMaxMem(a: var MemRegion): int =
# Since we update maxPagesCount only when freeing pages,
# maxPagesCount may not be up to date. Thus we use the
# maximum of these both values here:
result = max(a.currMem, a.maxMem)
proc llAlloc(a: var TMemRegion, size: int): pointer =
proc llAlloc(a: var MemRegion, size: int): pointer =
# *low-level* alloc for the memory managers data structures. Deallocation
# is done at he end of the allocator's life time.
if a.llmem == nil or size > a.llmem.size:
# the requested size is ``roundup(size+sizeof(TLLChunk), PageSize)``, but
# the requested size is ``roundup(size+sizeof(LLChunk), PageSize)``, but
# since we know ``size`` is a (small) constant, we know the requested size
# is one page:
sysAssert roundup(size+sizeof(TLLChunk), PageSize) == PageSize, "roundup 6"
sysAssert roundup(size+sizeof(LLChunk), PageSize) == PageSize, "roundup 6"
var old = a.llmem # can be nil and is correct with nil
a.llmem = cast[PLLChunk](osAllocPages(PageSize))
incCurrMem(a, PageSize)
a.llmem.size = PageSize - sizeof(TLLChunk)
a.llmem.acc = sizeof(TLLChunk)
a.llmem.size = PageSize - sizeof(LLChunk)
a.llmem.acc = sizeof(LLChunk)
a.llmem.next = old
result = cast[pointer](cast[ByteAddress](a.llmem) + a.llmem.acc)
dec(a.llmem.size, size)
inc(a.llmem.acc, size)
zeroMem(result, size)
proc allocAvlNode(a: var TMemRegion, key, upperBound: int): PAvlNode =
proc allocAvlNode(a: var MemRegion, key, upperBound: int): PAvlNode =
if a.freeAvlNodes != nil:
result = a.freeAvlNodes
a.freeAvlNodes = a.freeAvlNodes.link[0]
else:
result = cast[PAvlNode](llAlloc(a, sizeof(TAvlNode)))
result = cast[PAvlNode](llAlloc(a, sizeof(AvlNode)))
result.key = key
result.upperBound = upperBound
result.link[0] = bottom
@ -238,13 +242,13 @@ proc allocAvlNode(a: var TMemRegion, key, upperBound: int): PAvlNode =
sysAssert(bottom.link[0] == bottom, "bottom link[0]")
sysAssert(bottom.link[1] == bottom, "bottom link[1]")
proc deallocAvlNode(a: var TMemRegion, n: PAvlNode) {.inline.} =
proc deallocAvlNode(a: var MemRegion, n: PAvlNode) {.inline.} =
n.link[0] = a.freeAvlNodes
a.freeAvlNodes = n
include "system/avltree"
proc llDeallocAll(a: var TMemRegion) =
proc llDeallocAll(a: var MemRegion) =
var it = a.llmem
while it != nil:
# we know each block in the list has the size of 1 page:
@ -252,14 +256,14 @@ proc llDeallocAll(a: var TMemRegion) =
osDeallocPages(it, PageSize)
it = next
proc intSetGet(t: TIntSet, key: int): PTrunk =
proc intSetGet(t: IntSet, key: int): PTrunk =
var it = t.data[key and high(t.data)]
while it != nil:
if it.key == key: return it
it = it.next
result = nil
proc intSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk =
proc intSetPut(a: var MemRegion, t: var IntSet, key: int): PTrunk =
result = intSetGet(t, key)
if result == nil:
result = cast[PTrunk](llAlloc(a, sizeof(result[])))
@ -267,7 +271,7 @@ proc intSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk =
t.data[key and high(t.data)] = result
result.key = key
proc contains(s: TIntSet, key: int): bool =
proc contains(s: IntSet, key: int): bool =
var t = intSetGet(s, key shr TrunkShift)
if t != nil:
var u = key and TrunkMask
@ -275,19 +279,19 @@ proc contains(s: TIntSet, key: int): bool =
else:
result = false
proc incl(a: var TMemRegion, s: var TIntSet, key: int) =
proc incl(a: var MemRegion, s: var IntSet, key: int) =
var t = intSetPut(a, s, key shr TrunkShift)
var u = key and TrunkMask
t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask))
proc excl(s: var TIntSet, key: int) =
proc excl(s: var IntSet, key: int) =
var t = intSetGet(s, key shr TrunkShift)
if t != nil:
var u = key and TrunkMask
t.bits[u shr IntShift] = t.bits[u shr IntShift] and not
(1 shl (u and IntMask))
iterator elements(t: TIntSet): int {.inline.} =
iterator elements(t: IntSet): int {.inline.} =
# while traversing it is forbidden to change the set!
for h in 0..high(t.data):
var r = t.data[h]
@ -311,7 +315,7 @@ proc isSmallChunk(c: PChunk): bool {.inline.} =
proc chunkUnused(c: PChunk): bool {.inline.} =
result = not c.used
iterator allObjects(m: TMemRegion): pointer {.inline.} =
iterator allObjects(m: MemRegion): pointer {.inline.} =
for s in elements(m.chunkStarts):
# we need to check here again as it could have been modified:
if s in m.chunkStarts:
@ -331,7 +335,7 @@ iterator allObjects(m: TMemRegion): pointer {.inline.} =
yield addr(c.data)
proc isCell(p: pointer): bool {.inline.} =
result = cast[ptr TFreeCell](p).zeroField >% 1
result = cast[ptr FreeCell](p).zeroField >% 1
# ------------- chunk management ----------------------------------------------
proc pageIndex(c: PChunk): int {.inline.} =
@ -344,7 +348,7 @@ proc pageAddr(p: pointer): PChunk {.inline.} =
result = cast[PChunk](cast[ByteAddress](p) and not PageMask)
#sysAssert(Contains(allocator.chunkStarts, pageIndex(result)))
proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk =
proc requestOsChunks(a: var MemRegion, size: int): PBigChunk =
incCurrMem(a, size)
inc(a.freeMem, size)
result = cast[PBigChunk](osAllocPages(size))
@ -373,7 +377,7 @@ proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk =
result.prevSize = 0 # unknown
a.lastSize = size # for next request
proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) =
proc freeOsChunks(a: var MemRegion, p: pointer, size: int) =
# update next.prevSize:
var c = cast[PChunk](p)
var nxt = cast[ByteAddress](p) +% c.size
@ -387,7 +391,7 @@ proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) =
dec(a.freeMem, size)
#c_fprintf(c_stdout, "[Alloc] back to OS: %ld\n", size)
proc isAccessible(a: TMemRegion, p: pointer): bool {.inline.} =
proc isAccessible(a: MemRegion, p: pointer): bool {.inline.} =
result = contains(a.chunkStarts, pageIndex(p))
proc contains[T](list, x: T): bool =
@ -396,7 +400,7 @@ proc contains[T](list, x: T): bool =
if it == x: return true
it = it.next
proc writeFreeList(a: TMemRegion) =
proc writeFreeList(a: MemRegion) =
var it = a.freeChunksList
c_fprintf(c_stdout, "freeChunksList: %p\n", it)
while it != nil:
@ -427,14 +431,14 @@ proc listRemove[T](head: var T, c: T) {.inline.} =
c.next = nil
c.prev = nil
proc updatePrevSize(a: var TMemRegion, c: PBigChunk,
proc updatePrevSize(a: var MemRegion, c: PBigChunk,
prevSize: int) {.inline.} =
var ri = cast[PChunk](cast[ByteAddress](c) +% c.size)
sysAssert((cast[ByteAddress](ri) and PageMask) == 0, "updatePrevSize")
if isAccessible(a, ri):
ri.prevSize = prevSize
proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
proc freeBigChunk(a: var MemRegion, c: PBigChunk) =
var c = c
sysAssert(c.size >= PageSize, "freeBigChunk")
inc(a.freeMem, c.size)
@ -467,7 +471,7 @@ proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
else:
freeOsChunks(a, c, c.size)
proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) =
proc splitChunk(a: var MemRegion, c: PBigChunk, size: int) =
var rest = cast[PBigChunk](cast[ByteAddress](c) +% size)
sysAssert(rest notin a.freeChunksList, "splitChunk")
rest.size = c.size - size
@ -480,7 +484,7 @@ proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) =
incl(a, a.chunkStarts, pageIndex(rest))
listAdd(a.freeChunksList, rest)
proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
proc getBigChunk(a: var MemRegion, size: int): PBigChunk =
# use first fit for now:
sysAssert((size and PageMask) == 0, "getBigChunk 1")
sysAssert(size > 0, "getBigChunk 2")
@ -507,16 +511,16 @@ proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
incl(a, a.chunkStarts, pageIndex(result))
dec(a.freeMem, size)
proc getSmallChunk(a: var TMemRegion): PSmallChunk =
proc getSmallChunk(a: var MemRegion): PSmallChunk =
var res = getBigChunk(a, PageSize)
sysAssert res.prev == nil, "getSmallChunk 1"
sysAssert res.next == nil, "getSmallChunk 2"
result = cast[PSmallChunk](res)
# -----------------------------------------------------------------------------
proc isAllocatedPtr(a: TMemRegion, p: pointer): bool {.benign.}
proc isAllocatedPtr(a: MemRegion, p: pointer): bool {.benign.}
proc allocInv(a: TMemRegion): bool =
proc allocInv(a: MemRegion): bool =
## checks some (not all yet) invariants of the allocator's data structures.
for s in low(a.freeSmallChunks)..high(a.freeSmallChunks):
var c = a.freeSmallChunks[s]
@ -537,10 +541,10 @@ proc allocInv(a: TMemRegion): bool =
c = c.next
result = true
proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
proc rawAlloc(a: var MemRegion, requestedSize: int): pointer =
sysAssert(allocInv(a), "rawAlloc: begin")
sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken")
sysAssert(requestedSize >= sizeof(TFreeCell), "rawAlloc: requested size too small")
sysAssert(requestedSize >= sizeof(FreeCell), "rawAlloc: requested size too small")
var size = roundup(requestedSize, MemAlign)
sysAssert(size >= requestedSize, "insufficient allocated size!")
#c_fprintf(c_stdout, "alloc; size: %ld; %ld\n", requestedSize, size)
@ -601,11 +605,11 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
sysAssert(allocInv(a), "rawAlloc: end")
when logAlloc: cprintf("rawAlloc: %ld %p\n", requestedSize, result)
proc rawAlloc0(a: var TMemRegion, requestedSize: int): pointer =
proc rawAlloc0(a: var MemRegion, requestedSize: int): pointer =
result = rawAlloc(a, requestedSize)
zeroMem(result, requestedSize)
proc rawDealloc(a: var TMemRegion, p: pointer) =
proc rawDealloc(a: var MemRegion, p: pointer) =
#sysAssert(isAllocatedPtr(a, p), "rawDealloc: no allocated pointer")
sysAssert(allocInv(a), "rawDealloc: begin")
var c = pageAddr(p)
@ -615,7 +619,7 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
var s = c.size
sysAssert(((cast[ByteAddress](p) and PageMask) - smallChunkOverhead()) %%
s == 0, "rawDealloc 3")
var f = cast[ptr TFreeCell](p)
var f = cast[ptr FreeCell](p)
#echo("setting to nil: ", $cast[TAddress](addr(f.zeroField)))
sysAssert(f.zeroField != 0, "rawDealloc 1")
f.zeroField = 0
@ -623,8 +627,8 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
c.freeList = f
when overwriteFree:
# set to 0xff to check for usage after free bugs:
c_memset(cast[pointer](cast[int](p) +% sizeof(TFreeCell)), -1'i32,
s -% sizeof(TFreeCell))
c_memset(cast[pointer](cast[int](p) +% sizeof(FreeCell)), -1'i32,
s -% sizeof(FreeCell))
# check if it is not in the freeSmallChunks[s] list:
if c.free < s:
# add it to the freeSmallChunks[s] array:
@ -649,7 +653,7 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
sysAssert(allocInv(a), "rawDealloc: end")
when logAlloc: cprintf("rawDealloc: %p\n", p)
proc isAllocatedPtr(a: TMemRegion, p: pointer): bool =
proc isAllocatedPtr(a: MemRegion, p: pointer): bool =
if isAccessible(a, p):
var c = pageAddr(p)
if not chunkUnused(c):
@ -658,16 +662,16 @@ proc isAllocatedPtr(a: TMemRegion, p: pointer): bool =
var offset = (cast[ByteAddress](p) and (PageSize-1)) -%
smallChunkOverhead()
result = (c.acc >% offset) and (offset %% c.size == 0) and
(cast[ptr TFreeCell](p).zeroField >% 1)
(cast[ptr FreeCell](p).zeroField >% 1)
else:
var c = cast[PBigChunk](c)
result = p == addr(c.data) and cast[ptr TFreeCell](p).zeroField >% 1
result = p == addr(c.data) and cast[ptr FreeCell](p).zeroField >% 1
proc prepareForInteriorPointerChecking(a: var TMemRegion) {.inline.} =
proc prepareForInteriorPointerChecking(a: var MemRegion) {.inline.} =
a.minLargeObj = lowGauge(a.root)
a.maxLargeObj = highGauge(a.root)
proc interiorAllocatedPtr(a: TMemRegion, p: pointer): pointer =
proc interiorAllocatedPtr(a: MemRegion, p: pointer): pointer =
if isAccessible(a, p):
var c = pageAddr(p)
if not chunkUnused(c):
@ -678,7 +682,7 @@ proc interiorAllocatedPtr(a: TMemRegion, p: pointer): pointer =
if c.acc >% offset:
sysAssert(cast[ByteAddress](addr(c.data)) +% offset ==
cast[ByteAddress](p), "offset is not what you think it is")
var d = cast[ptr TFreeCell](cast[ByteAddress](addr(c.data)) +%
var d = cast[ptr FreeCell](cast[ByteAddress](addr(c.data)) +%
offset -% (offset %% c.size))
if d.zeroField >% 1:
result = d
@ -686,7 +690,7 @@ proc interiorAllocatedPtr(a: TMemRegion, p: pointer): pointer =
else:
var c = cast[PBigChunk](c)
var d = addr(c.data)
if p >= d and cast[ptr TFreeCell](d).zeroField >% 1:
if p >= d and cast[ptr FreeCell](d).zeroField >% 1:
result = d
sysAssert isAllocatedPtr(a, result), " result wrong pointer!"
else:
@ -699,38 +703,38 @@ proc interiorAllocatedPtr(a: TMemRegion, p: pointer): pointer =
var k = cast[pointer](avlNode.key)
var c = cast[PBigChunk](pageAddr(k))
sysAssert(addr(c.data) == k, " k is not the same as addr(c.data)!")
if cast[ptr TFreeCell](k).zeroField >% 1:
if cast[ptr FreeCell](k).zeroField >% 1:
result = k
sysAssert isAllocatedPtr(a, result), " result wrong pointer!"
proc ptrSize(p: pointer): int =
var x = cast[pointer](cast[ByteAddress](p) -% sizeof(TFreeCell))
var x = cast[pointer](cast[ByteAddress](p) -% sizeof(FreeCell))
var c = pageAddr(p)
sysAssert(not chunkUnused(c), "ptrSize")
result = c.size -% sizeof(TFreeCell)
result = c.size -% sizeof(FreeCell)
if not isSmallChunk(c):
dec result, bigChunkOverhead()
proc alloc(allocator: var TMemRegion, size: Natural): pointer =
result = rawAlloc(allocator, size+sizeof(TFreeCell))
cast[ptr TFreeCell](result).zeroField = 1 # mark it as used
proc alloc(allocator: var MemRegion, size: Natural): pointer =
result = rawAlloc(allocator, size+sizeof(FreeCell))
cast[ptr FreeCell](result).zeroField = 1 # mark it as used
sysAssert(not isAllocatedPtr(allocator, result), "alloc")
result = cast[pointer](cast[ByteAddress](result) +% sizeof(TFreeCell))
result = cast[pointer](cast[ByteAddress](result) +% sizeof(FreeCell))
proc alloc0(allocator: var TMemRegion, size: Natural): pointer =
proc alloc0(allocator: var MemRegion, size: Natural): pointer =
result = alloc(allocator, size)
zeroMem(result, size)
proc dealloc(allocator: var TMemRegion, p: pointer) =
proc dealloc(allocator: var MemRegion, p: pointer) =
sysAssert(p != nil, "dealloc 0")
var x = cast[pointer](cast[ByteAddress](p) -% sizeof(TFreeCell))
var x = cast[pointer](cast[ByteAddress](p) -% sizeof(FreeCell))
sysAssert(x != nil, "dealloc 1")
sysAssert(isAccessible(allocator, x), "is not accessible")
sysAssert(cast[ptr TFreeCell](x).zeroField == 1, "dealloc 2")
sysAssert(cast[ptr FreeCell](x).zeroField == 1, "dealloc 2")
rawDealloc(allocator, x)
sysAssert(not isAllocatedPtr(allocator, x), "dealloc 3")
proc realloc(allocator: var TMemRegion, p: pointer, newsize: Natural): pointer =
proc realloc(allocator: var MemRegion, p: pointer, newsize: Natural): pointer =
if newsize > 0:
result = alloc0(allocator, newsize)
if p != nil:
@ -739,7 +743,7 @@ proc realloc(allocator: var TMemRegion, p: pointer, newsize: Natural): pointer =
elif p != nil:
dealloc(allocator, p)
proc deallocOsPages(a: var TMemRegion) =
proc deallocOsPages(a: var MemRegion) =
# we free every 'ordinarily' allocated page by iterating over the page bits:
for p in elements(a.chunkStarts):
var page = cast[PChunk](p shl PageShift)
@ -756,9 +760,9 @@ proc deallocOsPages(a: var TMemRegion) =
# And then we free the pages that are in use for the page bits:
llDeallocAll(a)
proc getFreeMem(a: TMemRegion): int {.inline.} = result = a.freeMem
proc getTotalMem(a: TMemRegion): int {.inline.} = result = a.currMem
proc getOccupiedMem(a: TMemRegion): int {.inline.} =
proc getFreeMem(a: MemRegion): int {.inline.} = result = a.freeMem
proc getTotalMem(a: MemRegion): int {.inline.} = result = a.currMem
proc getOccupiedMem(a: MemRegion): int {.inline.} =
result = a.currMem - a.freeMem
# ---------------------- thread memory region -------------------------------
@ -769,7 +773,7 @@ template instantiateForRegion(allocator: expr) =
result = interiorAllocatedPtr(allocator, p)
proc isAllocatedPtr*(p: pointer): bool =
let p = cast[pointer](cast[ByteAddress](p)-%ByteAddress(sizeof(TCell)))
let p = cast[pointer](cast[ByteAddress](p)-%ByteAddress(sizeof(Cell)))
result = isAllocatedPtr(allocator, p)
proc deallocOsPages = deallocOsPages(allocator)
@ -803,8 +807,8 @@ template instantiateForRegion(allocator: expr) =
# -------------------- shared heap region ----------------------------------
when hasThreadSupport:
var sharedHeap: TMemRegion
var heapLock: TSysLock
var sharedHeap: MemRegion
var heapLock: SysLock
initSysLock(heapLock)
proc allocShared(size: Natural): pointer =

View file

@ -17,17 +17,114 @@ proc raiseOverflow {.compilerproc, noinline.} =
proc raiseDivByZero {.compilerproc, noinline.} =
sysFatal(DivByZeroError, "division by zero")
proc addInt64(a, b: int64): int64 {.compilerProc, inline.} =
result = a +% b
if (result xor a) >= int64(0) or (result xor b) >= int64(0):
return result
raiseOverflow()
when defined(builtinOverflow):
# Builtin compiler functions for improved performance
when sizeof(clong) == 8:
proc addInt64Overflow[T: int64|int](a, b: T, c: var T): bool {.
importc: "__builtin_saddl_overflow", nodecl, nosideeffect.}
proc subInt64(a, b: int64): int64 {.compilerProc, inline.} =
result = a -% b
if (result xor a) >= int64(0) or (result xor not b) >= int64(0):
return result
raiseOverflow()
proc subInt64Overflow[T: int64|int](a, b: T, c: var T): bool {.
importc: "__builtin_ssubl_overflow", nodecl, nosideeffect.}
proc mulInt64Overflow[T: int64|int](a, b: T, c: var T): bool {.
importc: "__builtin_smull_overflow", nodecl, nosideeffect.}
elif sizeof(clonglong) == 8:
proc addInt64Overflow[T: int64|int](a, b: T, c: var T): bool {.
importc: "__builtin_saddll_overflow", nodecl, nosideeffect.}
proc subInt64Overflow[T: int64|int](a, b: T, c: var T): bool {.
importc: "__builtin_ssubll_overflow", nodecl, nosideeffect.}
proc mulInt64Overflow[T: int64|int](a, b: T, c: var T): bool {.
importc: "__builtin_smulll_overflow", nodecl, nosideeffect.}
when sizeof(int) == 8:
proc addIntOverflow(a, b: int, c: var int): bool {.inline.} =
addInt64Overflow(a, b, c)
proc subIntOverflow(a, b: int, c: var int): bool {.inline.} =
subInt64Overflow(a, b, c)
proc mulIntOverflow(a, b: int, c: var int): bool {.inline.} =
mulInt64Overflow(a, b, c)
elif sizeof(int) == 4 and sizeof(cint) == 4:
proc addIntOverflow(a, b: int, c: var int): bool {.
importc: "__builtin_sadd_overflow", nodecl, nosideeffect.}
proc subIntOverflow(a, b: int, c: var int): bool {.
importc: "__builtin_ssub_overflow", nodecl, nosideeffect.}
proc mulIntOverflow(a, b: int, c: var int): bool {.
importc: "__builtin_smul_overflow", nodecl, nosideeffect.}
proc addInt64(a, b: int64): int64 {.compilerProc, inline.} =
if addInt64Overflow(a, b, result):
raiseOverflow()
proc subInt64(a, b: int64): int64 {.compilerProc, inline.} =
if subInt64Overflow(a, b, result):
raiseOverflow()
proc mulInt64(a, b: int64): int64 {.compilerproc, inline.} =
if mulInt64Overflow(a, b, result):
raiseOverflow()
else:
proc addInt64(a, b: int64): int64 {.compilerProc, inline.} =
result = a +% b
if (result xor a) >= int64(0) or (result xor b) >= int64(0):
return result
raiseOverflow()
proc subInt64(a, b: int64): int64 {.compilerProc, inline.} =
result = a -% b
if (result xor a) >= int64(0) or (result xor not b) >= int64(0):
return result
raiseOverflow()
#
# This code has been inspired by Python's source code.
# The native int product x*y is either exactly right or *way* off, being
# just the last n bits of the true product, where n is the number of bits
# in an int (the delivered product is the true product plus i*2**n for
# some integer i).
#
# The native float64 product x*y is subject to three
# rounding errors: on a sizeof(int)==8 box, each cast to double can lose
# info, and even on a sizeof(int)==4 box, the multiplication can lose info.
# But, unlike the native int product, it's not in *range* trouble: even
# if sizeof(int)==32 (256-bit ints), the product easily fits in the
# dynamic range of a float64. So the leading 50 (or so) bits of the float64
# product are correct.
#
# We check these two ways against each other, and declare victory if they're
# approximately the same. Else, because the native int product is the only
# one that can lose catastrophic amounts of information, it's the native int
# product that must have overflowed.
#
proc mulInt64(a, b: int64): int64 {.compilerproc.} =
var
resAsFloat, floatProd: float64
result = a *% b
floatProd = toBiggestFloat(a) # conversion
floatProd = floatProd * toBiggestFloat(b)
resAsFloat = toBiggestFloat(result)
# Fast path for normal case: small multiplicands, and no info
# is lost in either method.
if resAsFloat == floatProd: return result
# Somebody somewhere lost info. Close enough, or way off? Note
# that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
# The difference either is or isn't significant compared to the
# true value (of which floatProd is a good approximation).
# abs(diff)/abs(prod) <= 1/32 iff
# 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd):
return result
raiseOverflow()
proc negInt64(a: int64): int64 {.compilerProc, inline.} =
if a != low(int64): return -a
@ -51,50 +148,6 @@ proc modInt64(a, b: int64): int64 {.compilerProc, inline.} =
raiseDivByZero()
return a mod b
#
# This code has been inspired by Python's source code.
# The native int product x*y is either exactly right or *way* off, being
# just the last n bits of the true product, where n is the number of bits
# in an int (the delivered product is the true product plus i*2**n for
# some integer i).
#
# The native float64 product x*y is subject to three
# rounding errors: on a sizeof(int)==8 box, each cast to double can lose
# info, and even on a sizeof(int)==4 box, the multiplication can lose info.
# But, unlike the native int product, it's not in *range* trouble: even
# if sizeof(int)==32 (256-bit ints), the product easily fits in the
# dynamic range of a float64. So the leading 50 (or so) bits of the float64
# product are correct.
#
# We check these two ways against each other, and declare victory if they're
# approximately the same. Else, because the native int product is the only
# one that can lose catastrophic amounts of information, it's the native int
# product that must have overflowed.
#
proc mulInt64(a, b: int64): int64 {.compilerproc.} =
var
resAsFloat, floatProd: float64
result = a *% b
floatProd = toBiggestFloat(a) # conversion
floatProd = floatProd * toBiggestFloat(b)
resAsFloat = toBiggestFloat(result)
# Fast path for normal case: small multiplicands, and no info
# is lost in either method.
if resAsFloat == floatProd: return result
# Somebody somewhere lost info. Close enough, or way off? Note
# that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
# The difference either is or isn't significant compared to the
# true value (of which floatProd is a good approximation).
# abs(diff)/abs(prod) <= 1/32 iff
# 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd):
return result
raiseOverflow()
proc absInt(a: int): int {.compilerProc, inline.} =
if a != low(int):
if a >= 0: return a
@ -246,6 +299,21 @@ elif false: # asmVersion and (defined(gcc) or defined(llvm_gcc)):
:"%edx"
"""
when not declared(addInt) and defined(builtinOverflow):
proc addInt(a, b: int): int {.compilerProc, inline.} =
if addIntOverflow(a, b, result):
raiseOverflow()
when not declared(subInt) and defined(builtinOverflow):
proc subInt(a, b: int): int {.compilerProc, inline.} =
if subIntOverflow(a, b, result):
raiseOverflow()
when not declared(mulInt) and defined(builtinOverflow):
proc mulInt(a, b: int): int {.compilerProc, inline.} =
if mulIntOverflow(a, b, result):
raiseOverflow()
# Platform independent versions of the above (slower!)
when not declared(addInt):
proc addInt(a, b: int): int {.compilerProc, inline.} =

View file

@ -37,39 +37,40 @@ when someGcc and hasThreadSupport:
## and release stores in all threads.
type
TAtomType* = SomeNumber|pointer|ptr|char|bool
AtomType* = SomeNumber|pointer|ptr|char|bool
## Type Class representing valid types for use with atomic procs
{.deprecated: [TAtomType: AtomType].}
proc atomicLoadN*[T: TAtomType](p: ptr T, mem: AtomMemModel): T {.
proc atomicLoadN*[T: AtomType](p: ptr T, mem: AtomMemModel): T {.
importc: "__atomic_load_n", nodecl.}
## This proc implements an atomic load operation. It returns the contents at p.
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_ACQUIRE, ATOMIC_CONSUME.
proc atomicLoad*[T: TAtomType](p, ret: ptr T, mem: AtomMemModel) {.
proc atomicLoad*[T: AtomType](p, ret: ptr T, mem: AtomMemModel) {.
importc: "__atomic_load", nodecl.}
## This is the generic version of an atomic load. It returns the contents at p in ret.
proc atomicStoreN*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel) {.
proc atomicStoreN*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel) {.
importc: "__atomic_store_n", nodecl.}
## This proc implements an atomic store operation. It writes val at p.
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, and ATOMIC_RELEASE.
proc atomicStore*[T: TAtomType](p, val: ptr T, mem: AtomMemModel) {.
proc atomicStore*[T: AtomType](p, val: ptr T, mem: AtomMemModel) {.
importc: "__atomic_store", nodecl.}
## This is the generic version of an atomic store. It stores the value of val at p
proc atomicExchangeN*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicExchangeN*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_exchange_n", nodecl.}
## This proc implements an atomic exchange operation. It writes val at p,
## and returns the previous contents at p.
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_ACQUIRE, ATOMIC_RELEASE, ATOMIC_ACQ_REL
proc atomicExchange*[T: TAtomType](p, val, ret: ptr T, mem: AtomMemModel) {.
proc atomicExchange*[T: AtomType](p, val, ret: ptr T, mem: AtomMemModel) {.
importc: "__atomic_exchange", nodecl.}
## This is the generic version of an atomic exchange. It stores the contents at val at p.
## The original value at p is copied into ret.
proc atomicCompareExchangeN*[T: TAtomType](p, expected: ptr T, desired: T,
proc atomicCompareExchangeN*[T: AtomType](p, expected: ptr T, desired: T,
weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
importc: "__atomic_compare_exchange_n ", nodecl.}
## This proc implements an atomic compare and exchange operation. This compares the
@ -85,7 +86,7 @@ when someGcc and hasThreadSupport:
## cannot be __ATOMIC_RELEASE nor __ATOMIC_ACQ_REL. It also cannot be a stronger model
## than that specified by success_memmodel.
proc atomicCompareExchange*[T: TAtomType](p, expected, desired: ptr T,
proc atomicCompareExchange*[T: AtomType](p, expected, desired: ptr T,
weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
importc: "__atomic_compare_exchange", nodecl.}
## This proc implements the generic version of atomic_compare_exchange.
@ -93,31 +94,31 @@ when someGcc and hasThreadSupport:
## value is also a pointer.
## Perform the operation return the new value, all memory models are valid
proc atomicAddFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicAddFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_add_fetch", nodecl.}
proc atomicSubFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicSubFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_sub_fetch", nodecl.}
proc atomicOrFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicOrFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_or_fetch ", nodecl.}
proc atomicAndFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicAndFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_and_fetch", nodecl.}
proc atomicXorFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicXorFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_xor_fetch", nodecl.}
proc atomicNandFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicNandFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_nand_fetch ", nodecl.}
## Perform the operation return the old value, all memory models are valid
proc atomicFetchAdd*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicFetchAdd*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_add", nodecl.}
proc atomicFetchSub*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicFetchSub*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_sub", nodecl.}
proc atomicFetchOr*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicFetchOr*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_or", nodecl.}
proc atomicFetchAnd*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicFetchAnd*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_and", nodecl.}
proc atomicFetchXor*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicFetchXor*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_xor", nodecl.}
proc atomicFetchNand*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicFetchNand*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_nand", nodecl.}
proc atomicTestAndSet*(p: pointer, mem: AtomMemModel): bool {.

View file

@ -51,7 +51,7 @@ proc split(t: var PAvlNode) =
t.link[0] = temp
inc t.level
proc add(a: var TMemRegion, t: var PAvlNode, key, upperBound: int) {.benign.} =
proc add(a: var MemRegion, t: var PAvlNode, key, upperBound: int) {.benign.} =
if t == bottom:
t = allocAvlNode(a, key, upperBound)
else:
@ -64,7 +64,7 @@ proc add(a: var TMemRegion, t: var PAvlNode, key, upperBound: int) {.benign.} =
skew(t)
split(t)
proc del(a: var TMemRegion, t: var PAvlNode, x: int) {.benign.} =
proc del(a: var MemRegion, t: var PAvlNode, x: int) {.benign.} =
if t == bottom: return
a.last = t
if x <% t.key:

View file

@ -10,10 +10,10 @@
# Efficient set of pointers for the GC (and repr)
type
TRefCount = int
RefCount = int
TCell {.pure.} = object
refcount: TRefCount # the refcount and some flags
Cell {.pure.} = object
refcount: RefCount # the refcount and some flags
typ: PNimType
when trackAllocationSource:
filename: cstring
@ -21,34 +21,35 @@ type
when useCellIds:
id: int
PCell = ptr TCell
PCell = ptr Cell
PPageDesc = ptr TPageDesc
TBitIndex = range[0..UnitsPerPage-1]
TPageDesc {.final, pure.} = object
PPageDesc = ptr PageDesc
BitIndex = range[0..UnitsPerPage-1]
PageDesc {.final, pure.} = object
next: PPageDesc # all nodes are connected with this pointer
key: ByteAddress # start address at bit 0
bits: array[TBitIndex, int] # a bit vector
bits: array[BitIndex, int] # a bit vector
PPageDescArray = ptr array[0..1000_000, PPageDesc]
TCellSet {.final, pure.} = object
CellSet {.final, pure.} = object
counter, max: int
head: PPageDesc
data: PPageDescArray
PCellArray = ptr array[0..100_000_000, PCell]
TCellSeq {.final, pure.} = object
CellSeq {.final, pure.} = object
len, cap: int
d: PCellArray
{.deprecated: [TCell: Cell, TBitIndex: BitIndex, TPageDesc: PageDesc,
TRefCount: RefCount, TCellSet: CellSet, TCellSeq: CellSeq].}
# ------------------- cell seq handling ---------------------------------------
proc contains(s: TCellSeq, c: PCell): bool {.inline.} =
proc contains(s: CellSeq, c: PCell): bool {.inline.} =
for i in 0 .. s.len-1:
if s.d[i] == c: return true
return false
proc add(s: var TCellSeq, c: PCell) {.inline.} =
proc add(s: var CellSeq, c: PCell) {.inline.} =
if s.len >= s.cap:
s.cap = s.cap * 3 div 2
var d = cast[PCellArray](alloc(s.cap * sizeof(PCell)))
@ -59,12 +60,12 @@ proc add(s: var TCellSeq, c: PCell) {.inline.} =
s.d[s.len] = c
inc(s.len)
proc init(s: var TCellSeq, cap: int = 1024) =
proc init(s: var CellSeq, cap: int = 1024) =
s.len = 0
s.cap = cap
s.d = cast[PCellArray](alloc0(cap * sizeof(PCell)))
proc deinit(s: var TCellSeq) =
proc deinit(s: var CellSeq) =
dealloc(s.d)
s.d = nil
s.len = 0
@ -75,13 +76,13 @@ proc deinit(s: var TCellSeq) =
const
InitCellSetSize = 1024 # must be a power of two!
proc init(s: var TCellSet) =
proc init(s: var CellSet) =
s.data = cast[PPageDescArray](alloc0(InitCellSetSize * sizeof(PPageDesc)))
s.max = InitCellSetSize-1
s.counter = 0
s.head = nil
proc deinit(s: var TCellSet) =
proc deinit(s: var CellSet) =
var it = s.head
while it != nil:
var n = it.next
@ -98,14 +99,14 @@ proc nextTry(h, maxHash: int): int {.inline.} =
# generates each int in range(maxHash) exactly once (see any text on
# random-number generation for proof).
proc cellSetGet(t: TCellSet, key: ByteAddress): PPageDesc =
proc cellSetGet(t: CellSet, key: ByteAddress): PPageDesc =
var h = cast[int](key) and t.max
while t.data[h] != nil:
if t.data[h].key == key: return t.data[h]
h = nextTry(h, t.max)
return nil
proc cellSetRawInsert(t: TCellSet, data: PPageDescArray, desc: PPageDesc) =
proc cellSetRawInsert(t: CellSet, data: PPageDescArray, desc: PPageDesc) =
var h = cast[int](desc.key) and t.max
while data[h] != nil:
sysAssert(data[h] != desc, "CellSetRawInsert 1")
@ -113,7 +114,7 @@ proc cellSetRawInsert(t: TCellSet, data: PPageDescArray, desc: PPageDesc) =
sysAssert(data[h] == nil, "CellSetRawInsert 2")
data[h] = desc
proc cellSetEnlarge(t: var TCellSet) =
proc cellSetEnlarge(t: var CellSet) =
var oldMax = t.max
t.max = ((t.max+1)*2)-1
var n = cast[PPageDescArray](alloc0((t.max + 1) * sizeof(PPageDesc)))
@ -123,7 +124,7 @@ proc cellSetEnlarge(t: var TCellSet) =
dealloc(t.data)
t.data = n
proc cellSetPut(t: var TCellSet, key: ByteAddress): PPageDesc =
proc cellSetPut(t: var CellSet, key: ByteAddress): PPageDesc =
var h = cast[int](key) and t.max
while true:
var x = t.data[h]
@ -138,7 +139,7 @@ proc cellSetPut(t: var TCellSet, key: ByteAddress): PPageDesc =
while t.data[h] != nil: h = nextTry(h, t.max)
sysAssert(t.data[h] == nil, "CellSetPut")
# the new page descriptor goes into result
result = cast[PPageDesc](alloc0(sizeof(TPageDesc)))
result = cast[PPageDesc](alloc0(sizeof(PageDesc)))
result.next = t.head
result.key = key
t.head = result
@ -146,7 +147,7 @@ proc cellSetPut(t: var TCellSet, key: ByteAddress): PPageDesc =
# ---------- slightly higher level procs --------------------------------------
proc contains(s: TCellSet, cell: PCell): bool =
proc contains(s: CellSet, cell: PCell): bool =
var u = cast[ByteAddress](cell)
var t = cellSetGet(s, u shr PageShift)
if t != nil:
@ -155,13 +156,13 @@ proc contains(s: TCellSet, cell: PCell): bool =
else:
result = false
proc incl(s: var TCellSet, cell: PCell) {.noinline.} =
proc incl(s: var CellSet, cell: PCell) {.noinline.} =
var u = cast[ByteAddress](cell)
var t = cellSetPut(s, u shr PageShift)
u = (u %% PageSize) /% MemAlign
t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask))
proc excl(s: var TCellSet, cell: PCell) =
proc excl(s: var CellSet, cell: PCell) =
var u = cast[ByteAddress](cell)
var t = cellSetGet(s, u shr PageShift)
if t != nil:
@ -169,7 +170,7 @@ proc excl(s: var TCellSet, cell: PCell) =
t.bits[u shr IntShift] = (t.bits[u shr IntShift] and
not (1 shl (u and IntMask)))
proc containsOrIncl(s: var TCellSet, cell: PCell): bool =
proc containsOrIncl(s: var CellSet, cell: PCell): bool =
var u = cast[ByteAddress](cell)
var t = cellSetGet(s, u shr PageShift)
if t != nil:
@ -182,7 +183,7 @@ proc containsOrIncl(s: var TCellSet, cell: PCell): bool =
incl(s, cell)
result = false
iterator elements(t: TCellSet): PCell {.inline.} =
iterator elements(t: CellSet): PCell {.inline.} =
# while traversing it is forbidden to add pointers to the tree!
var r = t.head
while r != nil:
@ -200,7 +201,7 @@ iterator elements(t: TCellSet): PCell {.inline.} =
inc(i)
r = r.next
iterator elementsExcept(t, s: TCellSet): PCell {.inline.} =
iterator elementsExcept(t, s: CellSet): PCell {.inline.} =
var r = t.head
while r != nil:
let ss = cellSetGet(s, r.key)

View file

@ -12,12 +12,13 @@
proc addChar(s: NimString, c: char): NimString {.compilerProc, benign.}
type
TLibHandle = pointer # private type
TProcAddr = pointer # library loading and loading of procs:
LibHandle = pointer # private type
ProcAddr = pointer # library loading and loading of procs:
{.deprecated: [TLibHandle: LibHandle, TProcAddr: ProcAddr].}
proc nimLoadLibrary(path: string): TLibHandle {.compilerproc.}
proc nimUnloadLibrary(lib: TLibHandle) {.compilerproc.}
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr {.compilerproc.}
proc nimLoadLibrary(path: string): LibHandle {.compilerproc.}
proc nimUnloadLibrary(lib: LibHandle) {.compilerproc.}
proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr {.compilerproc.}
proc nimLoadLibraryError(path: string) {.compilerproc, noinline.}

View file

@ -19,18 +19,20 @@ when not declared(NimString):
type
pbytes = ptr array[0.. 0xffff, byte]
TRawChannel {.pure, final.} = object ## msg queue for a thread
RawChannel {.pure, final.} = object ## msg queue for a thread
rd, wr, count, mask: int
data: pbytes
lock: TSysLock
cond: TSysCond
lock: SysLock
cond: SysCond
elemType: PNimType
ready: bool
region: TMemRegion
PRawChannel = ptr TRawChannel
TLoadStoreMode = enum mStore, mLoad
TChannel* {.gcsafe.}[TMsg] = TRawChannel ## a channel for thread communication
region: MemRegion
PRawChannel = ptr RawChannel
LoadStoreMode = enum mStore, mLoad
Channel* {.gcsafe.}[TMsg] = RawChannel ## a channel for thread communication
{.deprecated: [TRawChannel: RawChannel, TLoadStoreMode: LoadStoreMode,
TChannel: Channel].}
const ChannelDeadMask = -2
proc initRawChannel(p: pointer) =
@ -49,9 +51,9 @@ proc deinitRawChannel(p: pointer) =
deinitSysCond(c.cond)
proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
mode: TLoadStoreMode) {.benign.}
mode: LoadStoreMode) {.benign.}
proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel,
mode: TLoadStoreMode) {.benign.} =
mode: LoadStoreMode) {.benign.} =
var
d = cast[ByteAddress](dest)
s = cast[ByteAddress](src)
@ -68,7 +70,7 @@ proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel,
of nkNone: sysAssert(false, "storeAux")
proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
mode: TLoadStoreMode) =
mode: LoadStoreMode) =
var
d = cast[ByteAddress](dest)
s = cast[ByteAddress](src)
@ -202,7 +204,7 @@ template sendImpl(q: expr) {.immediate.} =
releaseSys(q.lock)
signalSysCond(q.cond)
proc send*[TMsg](c: var TChannel[TMsg], msg: TMsg) =
proc send*[TMsg](c: var Channel[TMsg], msg: TMsg) =
## sends a message to a thread. `msg` is deeply copied.
var q = cast[PRawChannel](addr(c))
sendImpl(q)
@ -218,7 +220,7 @@ proc llRecv(q: PRawChannel, res: pointer, typ: PNimType) =
sysFatal(ValueError, "cannot receive message of wrong type")
rawRecv(q, res, typ)
proc recv*[TMsg](c: var TChannel[TMsg]): TMsg =
proc recv*[TMsg](c: var Channel[TMsg]): TMsg =
## receives a message from the channel `c`. This blocks until
## a message has arrived! You may use ``peek`` to avoid the blocking.
var q = cast[PRawChannel](addr(c))
@ -226,7 +228,7 @@ proc recv*[TMsg](c: var TChannel[TMsg]): TMsg =
llRecv(q, addr(result), cast[PNimType](getTypeInfo(result)))
releaseSys(q.lock)
proc tryRecv*[TMsg](c: var TChannel[TMsg]): tuple[dataAvailable: bool,
proc tryRecv*[TMsg](c: var Channel[TMsg]): tuple[dataAvailable: bool,
msg: TMsg] =
## try to receives a message from the channel `c` if available. Otherwise
## it returns ``(false, default(msg))``.
@ -238,7 +240,7 @@ proc tryRecv*[TMsg](c: var TChannel[TMsg]): tuple[dataAvailable: bool,
result.dataAvailable = true
releaseSys(q.lock)
proc peek*[TMsg](c: var TChannel[TMsg]): int =
proc peek*[TMsg](c: var Channel[TMsg]): int =
## returns the current number of messages in the channel `c`. Returns -1
## if the channel has been closed. **Note**: This is dangerous to use
## as it encourages races. It's much better to use ``tryRecv`` instead.
@ -249,15 +251,15 @@ proc peek*[TMsg](c: var TChannel[TMsg]): int =
else:
result = -1
proc open*[TMsg](c: var TChannel[TMsg]) =
proc open*[TMsg](c: var Channel[TMsg]) =
## opens a channel `c` for inter thread communication.
initRawChannel(addr(c))
proc close*[TMsg](c: var TChannel[TMsg]) =
proc close*[TMsg](c: var Channel[TMsg]) =
## closes a channel `c` and frees its associated resources.
deinitRawChannel(addr(c))
proc ready*[TMsg](c: var TChannel[TMsg]): bool =
proc ready*[TMsg](c: var Channel[TMsg]): bool =
## returns true iff some thread is waiting on the channel `c` for
## new messages.
var q = cast[PRawChannel](addr(c))

View file

@ -10,22 +10,23 @@
## This file implements basic features for any debugger.
type
TVarSlot* {.compilerproc, final.} = object ## a slot in a frame
VarSlot* {.compilerproc, final.} = object ## a slot in a frame
address*: pointer ## the variable's address
typ*: PNimType ## the variable's type
name*: cstring ## the variable's name; for globals this is "module.name"
PExtendedFrame = ptr TExtendedFrame
TExtendedFrame = object # If the debugger is enabled the compiler
PExtendedFrame = ptr ExtendedFrame
ExtendedFrame = object # If the debugger is enabled the compiler
# provides an extended frame. Of course
# only slots that are
# needed are allocated and not 10_000,
# except for the global data description.
f: TFrame
slots: array[0..10_000, TVarSlot]
f: Frame
slots: array[0..10_000, VarSlot]
{.deprecated: [TVarSlot: VarSlot, TExtendedFrame: ExtendedFrame].}
var
dbgGlobalData: TExtendedFrame # this reserves much space, but
dbgGlobalData: ExtendedFrame # this reserves much space, but
# for now it is the most practical way
proc dbgRegisterGlobal(name: cstring, address: pointer,
@ -39,7 +40,7 @@ proc dbgRegisterGlobal(name: cstring, address: pointer,
dbgGlobalData.slots[i].address = address
inc(dbgGlobalData.f.len)
proc getLocal*(frame: PFrame; slot: int): TVarSlot {.inline.} =
proc getLocal*(frame: PFrame; slot: int): VarSlot {.inline.} =
## retrieves the meta data for the local variable at `slot`. CAUTION: An
## invalid `slot` value causes a corruption!
result = cast[PExtendedFrame](frame).slots[slot]
@ -48,7 +49,7 @@ proc getGlobalLen*(): int {.inline.} =
## gets the number of registered globals.
result = dbgGlobalData.f.len
proc getGlobal*(slot: int): TVarSlot {.inline.} =
proc getGlobal*(slot: int): VarSlot {.inline.} =
## retrieves the meta data for the global variable at `slot`. CAUTION: An
## invalid `slot` value causes a corruption!
result = dbgGlobalData.slots[slot]
@ -56,13 +57,13 @@ proc getGlobal*(slot: int): TVarSlot {.inline.} =
# ------------------- breakpoint support ------------------------------------
type
TBreakpoint* = object ## represents a break point
Breakpoint* = object ## represents a break point
low*, high*: int ## range from low to high; if disabled
## both low and high are set to their negative values
filename*: cstring ## the filename of the breakpoint
var
dbgBP: array[0..127, TBreakpoint] # breakpoints
dbgBP: array[0..127, Breakpoint] # breakpoints
dbgBPlen: int
dbgBPbloom: int64 # we use a bloom filter to speed up breakpoint checking
@ -131,16 +132,16 @@ proc canonFilename*(filename: cstring): cstring =
if fileMatches(result, filename): return result
result = nil
iterator listBreakpoints*(): ptr TBreakpoint =
iterator listBreakpoints*(): ptr Breakpoint =
## lists all breakpoints.
for i in 0..dbgBPlen-1: yield addr(dbgBP[i])
proc isActive*(b: ptr TBreakpoint): bool = b.low > 0
proc flip*(b: ptr TBreakpoint) =
proc isActive*(b: ptr Breakpoint): bool = b.low > 0
proc flip*(b: ptr Breakpoint) =
## enables or disables 'b' depending on its current state.
b.low = -b.low; b.high = -b.high
proc checkBreakpoints*(filename: cstring, line: int): ptr TBreakpoint =
proc checkBreakpoints*(filename: cstring, line: int): ptr Breakpoint =
## in which breakpoint (if any) we are.
if (dbgBPbloom and line) != line: return nil
for b in listBreakpoints():
@ -149,29 +150,30 @@ proc checkBreakpoints*(filename: cstring, line: int): ptr TBreakpoint =
# ------------------- watchpoint support ------------------------------------
type
THash = int
TWatchpoint {.pure, final.} = object
Hash = int
Watchpoint {.pure, final.} = object
name: cstring
address: pointer
typ: PNimType
oldValue: THash
oldValue: Hash
{.deprecated: [THash: Hash, TWatchpoint: Watchpoint].}
var
watchpoints: array [0..99, TWatchpoint]
watchpoints: array [0..99, Watchpoint]
watchpointsLen: int
proc `!&`(h: THash, val: int): THash {.inline.} =
proc `!&`(h: Hash, val: int): Hash {.inline.} =
result = h +% val
result = result +% result shl 10
result = result xor (result shr 6)
proc `!$`(h: THash): THash {.inline.} =
proc `!$`(h: Hash): Hash {.inline.} =
result = h +% h shl 3
result = result xor (result shr 11)
result = result +% result shl 15
proc hash(data: pointer, size: int): THash =
var h: THash = 0
proc hash(data: pointer, size: int): Hash =
var h: Hash = 0
var p = cast[cstring](data)
var i = 0
var s = size
@ -181,14 +183,14 @@ proc hash(data: pointer, size: int): THash =
dec(s)
result = !$h
proc hashGcHeader(data: pointer): THash =
proc hashGcHeader(data: pointer): Hash =
const headerSize = sizeof(int)*2
result = hash(cast[pointer](cast[int](data) -% headerSize), headerSize)
proc genericHashAux(dest: pointer, mt: PNimType, shallow: bool,
h: THash): THash
h: Hash): Hash
proc genericHashAux(dest: pointer, n: ptr TNimNode, shallow: bool,
h: THash): THash =
h: Hash): Hash =
var d = cast[ByteAddress](dest)
case n.kind
of nkSlot:
@ -204,7 +206,7 @@ proc genericHashAux(dest: pointer, n: ptr TNimNode, shallow: bool,
of nkNone: sysAssert(false, "genericHashAux")
proc genericHashAux(dest: pointer, mt: PNimType, shallow: bool,
h: THash): THash =
h: Hash): Hash =
sysAssert(mt != nil, "genericHashAux 2")
case mt.kind
of tyString:

View file

@ -15,7 +15,7 @@
{.push stack_trace: off.}
const
NilLibHandle: TLibHandle = nil
NilLibHandle: LibHandle = nil
proc rawWrite(f: File, s: string) =
# we cannot throw an exception here!
@ -55,22 +55,22 @@ when defined(posix):
var
RTLD_NOW {.importc: "RTLD_NOW", header: "<dlfcn.h>".}: int
proc dlclose(lib: TLibHandle) {.importc, header: "<dlfcn.h>".}
proc dlopen(path: cstring, mode: int): TLibHandle {.
proc dlclose(lib: LibHandle) {.importc, header: "<dlfcn.h>".}
proc dlopen(path: cstring, mode: int): LibHandle {.
importc, header: "<dlfcn.h>".}
proc dlsym(lib: TLibHandle, name: cstring): TProcAddr {.
proc dlsym(lib: LibHandle, name: cstring): ProcAddr {.
importc, header: "<dlfcn.h>".}
proc dlerror(): cstring {.importc, header: "<dlfcn.h>".}
proc nimUnloadLibrary(lib: TLibHandle) =
proc nimUnloadLibrary(lib: LibHandle) =
dlclose(lib)
proc nimLoadLibrary(path: string): TLibHandle =
proc nimLoadLibrary(path: string): LibHandle =
result = dlopen(path, RTLD_NOW)
#c_fprintf(c_stdout, "%s\n", dlerror())
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
result = dlsym(lib, name)
if result == nil: procAddrError(name)
@ -84,12 +84,12 @@ elif defined(windows) or defined(dos):
type
THINSTANCE {.importc: "HINSTANCE".} = object
x: pointer
proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {.
proc getProcAddress(lib: THINSTANCE, name: cstring): ProcAddr {.
importcpp: "(void*)GetProcAddress(@)", header: "<windows.h>", stdcall.}
else:
type
THINSTANCE {.importc: "HINSTANCE".} = pointer
proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {.
proc getProcAddress(lib: THINSTANCE, name: cstring): ProcAddr {.
importc: "GetProcAddress", header: "<windows.h>", stdcall.}
proc freeLibrary(lib: THINSTANCE) {.
@ -97,13 +97,13 @@ elif defined(windows) or defined(dos):
proc winLoadLibrary(path: cstring): THINSTANCE {.
importc: "LoadLibraryA", header: "<windows.h>", stdcall.}
proc nimUnloadLibrary(lib: TLibHandle) =
proc nimUnloadLibrary(lib: LibHandle) =
freeLibrary(cast[THINSTANCE](lib))
proc nimLoadLibrary(path: string): TLibHandle =
result = cast[TLibHandle](winLoadLibrary(path))
proc nimLoadLibrary(path: string): LibHandle =
result = cast[LibHandle](winLoadLibrary(path))
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
result = getProcAddress(cast[THINSTANCE](lib), name)
if result == nil: procAddrError(name)
@ -115,13 +115,13 @@ elif defined(mac):
#
{.error: "no implementation for dyncalls yet".}
proc nimUnloadLibrary(lib: TLibHandle) =
proc nimUnloadLibrary(lib: LibHandle) =
NSUnLinkModule(NSModule(lib), NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES)
var
dyld_present {.importc: "_dyld_present", header: "<dyld.h>".}: int
proc nimLoadLibrary(path: string): TLibHandle =
proc nimLoadLibrary(path: string): LibHandle =
var
img: NSObjectFileImage
ret: NSObjectFileImageReturnCode
@ -134,13 +134,13 @@ elif defined(mac):
modul = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE or
NSLINKMODULE_OPTION_RETURN_ON_ERROR)
NSDestroyObjectFileImage(img)
result = TLibHandle(modul)
result = LibHandle(modul)
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
var
nss: NSSymbol
nss = NSLookupSymbolInModule(NSModule(lib), name)
result = TProcAddr(NSAddressOfSymbol(nss))
result = ProcAddr(NSAddressOfSymbol(nss))
if result == nil: ProcAddrError(name)
else:

View file

@ -20,63 +20,65 @@ const
EndbEnd = "***\n"
type
TStaticStr = object
StaticStr = object
len: int
data: array[0..100, char]
TBreakpointFilename = object
b: ptr TBreakpoint
filename: TStaticStr
BreakpointFilename = object
b: ptr Breakpoint
filename: StaticStr
TDbgState = enum
DbgState = enum
dbOff, # debugger is turned off
dbStepInto, # debugger is in tracing mode
dbStepOver,
dbSkipCurrent,
dbQuiting, # debugger wants to quit
dbBreakpoints # debugger is only interested in breakpoints
{.deprecated: [TStaticStr: StaticStr, TBreakpointFilename: BreakpointFilename,
TDbgState: DbgState].}
var
dbgUser: TStaticStr # buffer for user input; first command is ``step_into``
dbgUser: StaticStr # buffer for user input; first command is ``step_into``
# needs to be global cause we store the last command
# in it
dbgState: TDbgState # state of debugger
dbgState: DbgState # state of debugger
dbgSkipToFrame: PFrame # frame to be skipped to
maxDisplayRecDepth: int = 5 # do not display too much data!
brkPoints: array[0..127, TBreakpointFilename]
brkPoints: array[0..127, BreakpointFilename]
proc setLen(s: var TStaticStr, newLen=0) =
proc setLen(s: var StaticStr, newLen=0) =
s.len = newLen
s.data[newLen] = '\0'
proc add(s: var TStaticStr, c: char) =
proc add(s: var StaticStr, c: char) =
if s.len < high(s.data)-1:
s.data[s.len] = c
s.data[s.len+1] = '\0'
inc s.len
proc add(s: var TStaticStr, c: cstring) =
proc add(s: var StaticStr, c: cstring) =
var i = 0
while c[i] != '\0':
add s, c[i]
inc i
proc assign(s: var TStaticStr, c: cstring) =
proc assign(s: var StaticStr, c: cstring) =
setLen(s)
add s, c
proc `==`(a, b: TStaticStr): bool =
proc `==`(a, b: StaticStr): bool =
if a.len == b.len:
for i in 0 .. a.len-1:
if a.data[i] != b.data[i]: return false
return true
proc `==`(a: TStaticStr, b: cstring): bool =
proc `==`(a: StaticStr, b: cstring): bool =
result = c_strcmp(a.data, b) == 0
proc write(f: TFile, s: TStaticStr) =
proc write(f: File, s: StaticStr) =
write(f, cstring(s.data))
proc listBreakPoints() =
@ -95,14 +97,14 @@ proc listBreakPoints() =
write(stdout, "\n")
write(stdout, EndbEnd)
proc openAppend(filename: cstring): TFile =
proc openAppend(filename: cstring): File =
var p: pointer = fopen(filename, "ab")
if p != nil:
result = cast[TFile](p)
result = cast[File](p)
write(result, "----------------------------------------\n")
proc dbgRepr(p: pointer, typ: PNimType): string =
var cl: TReprClosure
var cl: ReprClosure
initReprClosure(cl)
cl.recDepth = maxDisplayRecDepth
# locks for the GC turned out to be a bad idea...
@ -112,12 +114,12 @@ proc dbgRepr(p: pointer, typ: PNimType): string =
# dec(recGcLock)
deinitReprClosure(cl)
proc writeVariable(stream: TFile, slot: TVarSlot) =
proc writeVariable(stream: File, slot: VarSlot) =
write(stream, slot.name)
write(stream, " = ")
writeln(stream, dbgRepr(slot.address, slot.typ))
proc listFrame(stream: TFile, f: PFrame) =
proc listFrame(stream: File, f: PFrame) =
write(stream, EndbBeg)
write(stream, "| Frame (")
write(stream, f.len)
@ -126,7 +128,7 @@ proc listFrame(stream: TFile, f: PFrame) =
writeln(stream, getLocal(f, i).name)
write(stream, EndbEnd)
proc listLocals(stream: TFile, f: PFrame) =
proc listLocals(stream: File, f: PFrame) =
write(stream, EndbBeg)
write(stream, "| Frame (")
write(stream, f.len)
@ -135,7 +137,7 @@ proc listLocals(stream: TFile, f: PFrame) =
writeVariable(stream, getLocal(f, i))
write(stream, EndbEnd)
proc listGlobals(stream: TFile) =
proc listGlobals(stream: File) =
write(stream, EndbBeg)
write(stream, "| Globals:\n")
for i in 0 .. getGlobalLen()-1:
@ -172,7 +174,7 @@ proc dbgShowExecutionPoint() =
write(stdout, framePtr.procname)
write(stdout, " ***\n")
proc scanAndAppendWord(src: cstring, a: var TStaticStr, start: int): int =
proc scanAndAppendWord(src: cstring, a: var StaticStr, start: int): int =
result = start
# skip whitespace:
while src[result] in {'\t', ' '}: inc(result)
@ -184,11 +186,11 @@ proc scanAndAppendWord(src: cstring, a: var TStaticStr, start: int): int =
else: break
inc(result)
proc scanWord(src: cstring, a: var TStaticStr, start: int): int =
proc scanWord(src: cstring, a: var StaticStr, start: int): int =
setlen(a)
result = scanAndAppendWord(src, a, start)
proc scanFilename(src: cstring, a: var TStaticStr, start: int): int =
proc scanFilename(src: cstring, a: var StaticStr, start: int): int =
result = start
setLen a
while src[result] in {'\t', ' '}: inc(result)
@ -250,8 +252,8 @@ proc hasExt(s: cstring): bool =
if s[i] == '.': return true
inc i
proc parseBreakpoint(s: cstring, start: int): TBreakpoint =
var dbgTemp: TStaticStr
proc parseBreakpoint(s: cstring, start: int): Breakpoint =
var dbgTemp: StaticStr
var i = scanNumber(s, result.low, start)
if result.low == 0: result.low = framePtr.line
i = scanNumber(s, result.high, i)
@ -279,11 +281,11 @@ proc breakpointToggle(s: cstring, start: int) =
if not b.isNil: b.flip
else: debugOut("[Warning] unknown breakpoint ")
proc dbgEvaluate(stream: TFile, s: cstring, start: int, f: PFrame) =
var dbgTemp: TStaticStr
proc dbgEvaluate(stream: File, s: cstring, start: int, f: PFrame) =
var dbgTemp: StaticStr
var i = scanWord(s, dbgTemp, start)
while s[i] in {' ', '\t'}: inc(i)
var v: TVarSlot
var v: VarSlot
if s[i] == '.':
inc(i)
add(dbgTemp, '.')
@ -299,7 +301,7 @@ proc dbgEvaluate(stream: TFile, s: cstring, start: int, f: PFrame) =
writeVariable(stream, v)
proc dbgOut(s: cstring, start: int, currFrame: PFrame) =
var dbgTemp: TStaticStr
var dbgTemp: StaticStr
var i = scanFilename(s, dbgTemp, start)
if dbgTemp.len == 0:
invalidCommand()
@ -312,7 +314,7 @@ proc dbgOut(s: cstring, start: int, currFrame: PFrame) =
close(stream)
proc dbgStackFrame(s: cstring, start: int, currFrame: PFrame) =
var dbgTemp: TStaticStr
var dbgTemp: StaticStr
var i = scanFilename(s, dbgTemp, start)
if dbgTemp.len == 0:
# just write it to stdout:
@ -325,7 +327,7 @@ proc dbgStackFrame(s: cstring, start: int, currFrame: PFrame) =
listFrame(stream, currFrame)
close(stream)
proc readLine(f: TFile, line: var TStaticStr): bool =
proc readLine(f: File, line: var StaticStr): bool =
while true:
var c = fgetc(f)
if c < 0'i32:
@ -358,7 +360,7 @@ proc commandPrompt() =
again = true
dbgFramePtr = framePtr # for going down and up the stack
dbgDown = 0 # how often we did go down
dbgTemp: TStaticStr
dbgTemp: StaticStr
while again:
write(stdout, "*** endb| >>")

View file

@ -365,5 +365,6 @@ when not defined(noSignalHandler):
proc setControlCHook(hook: proc () {.noconv.} not nil) =
# ugly cast, but should work on all architectures:
type TSignalHandler = proc (sig: cint) {.noconv, benign.}
c_signal(SIGINT, cast[TSignalHandler](hook))
type SignalHandler = proc (sig: cint) {.noconv, benign.}
{.deprecated: [TSignalHandler: SignalHandler].}
c_signal(SIGINT, cast[SignalHandler](hook))

View file

@ -45,17 +45,17 @@ const
rcShift = 3 # shift by rcShift to get the reference counter
colorMask = 0b011
type
TWalkOp = enum
WalkOp = enum
waMarkGlobal, # part of the backup/debug mark&sweep
waMarkPrecise, # part of the backup/debug mark&sweep
waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack,
waCollectWhite #, waDebug
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
# A ref type can have a finalizer that is called before the object's
# storage is freed.
TGcStat {.final, pure.} = object
GcStat {.final, pure.} = object
stackScans: int # number of performed stack scans (for statistics)
cycleCollections: int # number of performed full collections
maxThreshold: int # max threshold that has been set
@ -64,35 +64,36 @@ type
cycleTableSize: int # max entries in cycle table
maxPause: int64 # max measured GC pause in nanoseconds
TGcHeap {.final, pure.} = object # this contains the zero count and
GcHeap {.final, pure.} = object # this contains the zero count and
# non-zero count table
stackBottom: pointer
cycleThreshold: int
when useCellIds:
idGenerator: int
zct: TCellSeq # the zero count table
decStack: TCellSeq # cells in the stack that are to decref again
cycleRoots: TCellSet
tempStack: TCellSeq # temporary stack for recursion elimination
zct: CellSeq # the zero count table
decStack: CellSeq # cells in the stack that are to decref again
cycleRoots: CellSet
tempStack: CellSeq # temporary stack for recursion elimination
recGcLock: int # prevent recursion via finalizers; no thread lock
when withRealTime:
maxPause: TNanos # max allowed pause in nanoseconds; active if > 0
region: TMemRegion # garbage collected region
stat: TGcStat
maxPause: Nanos # max allowed pause in nanoseconds; active if > 0
region: MemRegion # garbage collected region
stat: GcStat
when useMarkForDebug or useBackupGc:
marked: TCellSet
marked: CellSet
{.deprecated: [TWalkOp: WalkOp, TFinalizer: Finalizer, TGcHeap: GcHeap,
TGcStat: GcStat].}
var
gch {.rtlThreadVar.}: TGcHeap
gch {.rtlThreadVar.}: GcHeap
when not defined(useNimRtl):
instantiateForRegion(gch.region)
template acquire(gch: TGcHeap) =
template acquire(gch: GcHeap) =
when hasThreadSupport and hasSharedHeap:
acquireSys(HeapLock)
template release(gch: TGcHeap) =
template release(gch: GcHeap) =
when hasThreadSupport and hasSharedHeap:
releaseSys(HeapLock)
@ -104,18 +105,18 @@ template gcAssert(cond: bool, msg: string) =
writeStackTrace()
quit 1
proc addZCT(s: var TCellSeq, c: PCell) {.noinline.} =
proc addZCT(s: var CellSeq, c: PCell) {.noinline.} =
if (c.refcount and ZctFlag) == 0:
c.refcount = c.refcount or ZctFlag
add(s, c)
proc cellToUsr(cell: PCell): pointer {.inline.} =
# convert object (=pointer to refcount) to pointer to userdata
result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(TCell)))
result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(Cell)))
proc usrToCell(usr: pointer): PCell {.inline.} =
# convert pointer to userdata to object (=pointer to refcount)
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(Cell)))
proc canBeCycleRoot(c: PCell): bool {.inline.} =
result = ntfAcyclic notin c.typ.flags
@ -152,11 +153,11 @@ template gcTrace(cell, state: expr): stmt {.immediate.} =
when traceGC: traceCell(cell, state)
# forward declarations:
proc collectCT(gch: var TGcHeap) {.benign.}
proc collectCT(gch: var GcHeap) {.benign.}
proc isOnStack*(p: pointer): bool {.noinline, benign.}
proc forAllChildren(cell: PCell, op: TWalkOp) {.benign.}
proc doOperation(p: pointer, op: TWalkOp) {.benign.}
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) {.benign.}
proc forAllChildren(cell: PCell, op: WalkOp) {.benign.}
proc doOperation(p: pointer, op: WalkOp) {.benign.}
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.}
# we need the prototype here for debugging purposes
when hasThreadSupport and hasSharedHeap:
@ -178,7 +179,7 @@ proc prepareDealloc(cell: PCell) =
# prevend recursive entering here by a lock.
# XXX: we should set the cell's children to nil!
inc(gch.recGcLock)
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
(cast[Finalizer](cell.typ.finalizer))(cellToUsr(cell))
dec(gch.recGcLock)
proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
@ -276,7 +277,7 @@ proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerProc.} =
proc initGC() =
when not defined(useNimRtl):
when traceGC:
for i in low(TCellState)..high(TCellState): init(states[i])
for i in low(CellState)..high(CellState): init(states[i])
gch.cycleThreshold = InitialCycleThreshold
gch.stat.stackScans = 0
gch.stat.cycleCollections = 0
@ -308,12 +309,13 @@ proc setupForeignThreadGc*() =
when useMarkForDebug or useBackupGc:
type
TGlobalMarkerProc = proc () {.nimcall, benign.}
GlobalMarkerProc = proc () {.nimcall, benign.}
{.deprecated: [TGlobalMarkerProc: GlobalMarkerProc].}
var
globalMarkersLen: int
globalMarkers: array[0.. 7_000, TGlobalMarkerProc]
globalMarkers: array[0.. 7_000, GlobalMarkerProc]
proc nimRegisterGlobalMarker(markerProc: TGlobalMarkerProc) {.compilerProc.} =
proc nimRegisterGlobalMarker(markerProc: GlobalMarkerProc) {.compilerProc.} =
if globalMarkersLen <= high(globalMarkers):
globalMarkers[globalMarkersLen] = markerProc
inc globalMarkersLen
@ -321,11 +323,11 @@ when useMarkForDebug or useBackupGc:
echo "[GC] cannot register global variable; too many global variables"
quit 1
proc cellsetReset(s: var TCellSet) =
proc cellsetReset(s: var CellSet) =
deinit(s)
init(s)
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} =
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} =
var d = cast[ByteAddress](dest)
case n.kind
of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
@ -345,7 +347,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} =
if m != nil: forAllSlotsAux(dest, m, op)
of nkNone: sysAssert(false, "forAllSlotsAux")
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) =
var d = cast[ByteAddress](dest)
if dest == nil: return # nothing to do
if ntfNoRefs notin mt.flags:
@ -359,7 +361,7 @@ proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
else: discard
proc forAllChildren(cell: PCell, op: TWalkOp) =
proc forAllChildren(cell: PCell, op: WalkOp) =
gcAssert(cell != nil, "forAllChildren: 1")
gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: 2")
gcAssert(cell.typ != nil, "forAllChildren: 3")
@ -380,7 +382,7 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
GenericSeqSize), cell.typ.base, op)
else: discard
proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
proc addNewObjToZCT(res: PCell, gch: var GcHeap) {.inline.} =
# we check the last 8 entries (cache line) for a slot that could be reused.
# In 63% of all cases we succeed here! But we have to optimize the heck
# out of this small linear search so that ``newObj`` is not slowed down.
@ -431,13 +433,13 @@ proc gcInvariant*() =
markForDebug(gch)
{.pop.}
proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
# generates a new object and sets its reference counter to 0
sysAssert(allocInv(gch.region), "rawNewObj begin")
acquire(gch)
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
collectCT(gch)
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
# now it is buffered in the ZCT
res.typ = typ
@ -486,7 +488,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
collectCT(gch)
sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc")
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
# now it is buffered in the ZCT
@ -515,7 +517,7 @@ proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
cast[PGenericSeq](result).reserved = len
when defined(memProfiler): nimProfile(size)
proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
acquire(gch)
collectCT(gch)
var ol = usrToCell(old)
@ -523,13 +525,13 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
sysAssert(allocInv(gch.region), "growObj begin")
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
var elemSize = 1
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
copyMem(res, ol, oldsize + sizeof(TCell))
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
copyMem(res, ol, oldsize + sizeof(Cell))
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)),
newsize-oldsize)
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
# This can be wrong for intermediate temps that are nevertheless on the
@ -564,7 +566,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
decRef(ol)
else:
sysAssert(ol.typ != nil, "growObj: 5")
zeroMem(ol, sizeof(TCell))
zeroMem(ol, sizeof(Cell))
release(gch)
when useCellIds:
inc gch.idGenerator
@ -580,7 +582,7 @@ proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
# ---------------- cycle collector -------------------------------------------
proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
proc freeCyclicCell(gch: var GcHeap, c: PCell) =
prepareDealloc(c)
gcTrace(c, csCycFreed)
when logGC: writeCell("cycle collector dealloc cell", c)
@ -589,7 +591,7 @@ proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
rawDealloc(gch.region, c)
else:
gcAssert(c.typ != nil, "freeCyclicCell")
zeroMem(c, sizeof(TCell))
zeroMem(c, sizeof(Cell))
proc markGray(s: PCell) =
if s.color != rcGray:
@ -620,7 +622,7 @@ proc collectWhite(s: PCell) =
forAllChildren(s, waCollectWhite)
freeCyclicCell(gch, s)
proc markRoots(gch: var TGcHeap) =
proc markRoots(gch: var GcHeap) =
var tabSize = 0
for s in elements(gch.cycleRoots):
#writeCell("markRoot", s)
@ -635,7 +637,7 @@ proc markRoots(gch: var TGcHeap) =
gch.stat.cycleTableSize = max(gch.stat.cycleTableSize, tabSize)
when useBackupGc:
proc sweep(gch: var TGcHeap) =
proc sweep(gch: var GcHeap) =
for x in allObjects(gch.region):
if isCell(x):
# cast to PCell is correct here:
@ -643,7 +645,7 @@ when useBackupGc:
if c notin gch.marked: freeCyclicCell(gch, c)
when useMarkForDebug or useBackupGc:
proc markS(gch: var TGcHeap, c: PCell) =
proc markS(gch: var GcHeap, c: PCell) =
incl(gch.marked, c)
gcAssert gch.tempStack.len == 0, "stack not empty!"
forAllChildren(c, waMarkPrecise)
@ -653,10 +655,10 @@ when useMarkForDebug or useBackupGc:
if not containsOrIncl(gch.marked, d):
forAllChildren(d, waMarkPrecise)
proc markGlobals(gch: var TGcHeap) =
proc markGlobals(gch: var GcHeap) =
for i in 0 .. < globalMarkersLen: globalMarkers[i]()
proc stackMarkS(gch: var TGcHeap, p: pointer) {.inline.} =
proc stackMarkS(gch: var GcHeap, p: pointer) {.inline.} =
# the addresses are not as cells on the stack, so turn them to cells:
var cell = usrToCell(p)
var c = cast[TAddress](cell)
@ -688,7 +690,7 @@ when logGC:
forAllChildren(s, waDebug)
c_fprintf(c_stdout, "}\n")
proc doOperation(p: pointer, op: TWalkOp) =
proc doOperation(p: pointer, op: WalkOp) =
if p == nil: return
var c: PCell = usrToCell(p)
gcAssert(c != nil, "doOperation: 1")
@ -733,19 +735,19 @@ proc doOperation(p: pointer, op: TWalkOp) =
#of waDebug: debugGraph(c)
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
doOperation(d, TWalkOp(op))
doOperation(d, WalkOp(op))
proc collectZCT(gch: var TGcHeap): bool {.benign.}
proc collectZCT(gch: var GcHeap): bool {.benign.}
when useMarkForDebug or useBackupGc:
proc markStackAndRegistersForSweep(gch: var TGcHeap) {.noinline, cdecl,
proc markStackAndRegistersForSweep(gch: var GcHeap) {.noinline, cdecl,
benign.}
proc collectRoots(gch: var TGcHeap) =
proc collectRoots(gch: var GcHeap) =
for s in elements(gch.cycleRoots):
collectWhite(s)
proc collectCycles(gch: var TGcHeap) =
proc collectCycles(gch: var GcHeap) =
# ensure the ZCT 'color' is not used:
while gch.zct.len > 0: discard collectZCT(gch)
when useBackupGc:
@ -778,7 +780,7 @@ proc collectCycles(gch: var TGcHeap) =
if cycleRootsLen != 0:
cfprintf(cstdout, "cycle roots: %ld\n", cycleRootsLen)
proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
# the addresses are not as cells on the stack, so turn them to cells:
sysAssert(allocInv(gch.region), "gcMark begin")
var cell = usrToCell(p)
@ -798,7 +800,7 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
add(gch.decStack, cell)
sysAssert(allocInv(gch.region), "gcMark end")
proc markThreadStacks(gch: var TGcHeap) =
proc markThreadStacks(gch: var GcHeap) =
when hasThreadSupport and hasSharedHeap:
{.error: "not fully implemented".}
var it = threadList
@ -887,7 +889,7 @@ elif stackIncreases:
var
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
# a little hack to get the size of a TJmpBuf in the generated C code
# a little hack to get the size of a JmpBuf in the generated C code
# in a platform independent way
template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} =
@ -947,18 +949,18 @@ else:
gcMark(gch, cast[PPointer](sp)[])
sp = sp +% sizeof(pointer)
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
forEachStackSlot(gch, gcMark)
when useMarkForDebug or useBackupGc:
proc markStackAndRegistersForSweep(gch: var TGcHeap) =
proc markStackAndRegistersForSweep(gch: var GcHeap) =
forEachStackSlot(gch, stackMarkS)
# ----------------------------------------------------------------------------
# end of non-portable code
# ----------------------------------------------------------------------------
proc collectZCT(gch: var TGcHeap): bool =
proc collectZCT(gch: var GcHeap): bool =
# Note: Freeing may add child objects to the ZCT! So essentially we do
# deep freeing, which is bad for incremental operation. In order to
# avoid a deep stack, we move objects to keep the ZCT small.
@ -968,7 +970,7 @@ proc collectZCT(gch: var TGcHeap): bool =
when withRealTime:
var steps = workPackage
var t0: TTicks
var t0: Ticks
if gch.maxPause > 0: t0 = getticks()
while L[] > 0:
var c = gch.zct.d[0]
@ -1001,7 +1003,7 @@ proc collectZCT(gch: var TGcHeap): bool =
rawDealloc(gch.region, c)
else:
sysAssert(c.typ != nil, "collectZCT 2")
zeroMem(c, sizeof(TCell))
zeroMem(c, sizeof(Cell))
when withRealTime:
if steps == 0:
steps = workPackage
@ -1014,7 +1016,7 @@ proc collectZCT(gch: var TGcHeap): bool =
return false
result = true
proc unmarkStackAndRegisters(gch: var TGcHeap) =
proc unmarkStackAndRegisters(gch: var GcHeap) =
var d = gch.decStack.d
for i in 0..gch.decStack.len-1:
sysAssert isAllocatedPtr(gch.region, d[i]), "unmarkStackAndRegisters"
@ -1026,7 +1028,7 @@ proc unmarkStackAndRegisters(gch: var TGcHeap) =
#sysAssert c.typ != nil, "unmarkStackAndRegisters 2"
gch.decStack.len = 0
proc collectCTBody(gch: var TGcHeap) =
proc collectCTBody(gch: var GcHeap) =
when withRealTime:
let t0 = getticks()
sysAssert(allocInv(gch.region), "collectCT: begin")
@ -1058,11 +1060,11 @@ proc collectCTBody(gch: var TGcHeap) =
c_fprintf(c_stdout, "[GC] missed deadline: %ld\n", duration)
when useMarkForDebug or useBackupGc:
proc markForDebug(gch: var TGcHeap) =
proc markForDebug(gch: var GcHeap) =
markStackAndRegistersForSweep(gch)
markGlobals(gch)
proc collectCT(gch: var TGcHeap) =
proc collectCT(gch: var GcHeap) =
# stackMarkCosts prevents some pathological behaviour: Stack marking
# becomes more expensive with large stacks and large stacks mean that
# cells with RC=0 are more likely to be kept alive by the stack.
@ -1077,13 +1079,13 @@ proc collectCT(gch: var TGcHeap) =
collectCTBody(gch)
when withRealTime:
proc toNano(x: int): TNanos {.inline.} =
proc toNano(x: int): Nanos {.inline.} =
result = x * 1000
proc GC_setMaxPause*(MaxPauseInUs: int) =
gch.maxPause = MaxPauseInUs.toNano
proc GC_step(gch: var TGcHeap, us: int, strongAdvice: bool) =
proc GC_step(gch: var GcHeap, us: int, strongAdvice: bool) =
acquire(gch)
gch.maxPause = us.toNano
if (gch.zct.len >= ZctThreshold or (cycleGC and

View file

@ -54,7 +54,7 @@ const
# was replaced by a resize operation.
# see growObj for details
rcColorMask = TRefCount(0b00111)
rcColorMask = RefCount(0b00111)
rcZct = 0b01000 # already added to ZCT
rcInCycleRoots = 0b10000 # already buffered as cycle candidate
@ -97,14 +97,14 @@ const
CollectCyclesStats = false
type
TWalkOp = enum
WalkOp = enum
waPush
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall.}
Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall.}
# A ref type can have a finalizer that is called before the object's
# storage is freed.
TGcStat {.final, pure.} = object
GcStat {.final, pure.} = object
stackScans: int # number of performed stack scans (for statistics)
cycleCollections: int # number of performed full collections
maxThreshold: int # max threshold that has been set
@ -113,16 +113,16 @@ type
cycleTableSize: int # max entries in cycle table
maxPause: int64 # max measured GC pause in nanoseconds
TGcHeap {.final, pure.} = object # this contains the zero count and
GcHeap {.final, pure.} = object # this contains the zero count and
# non-zero count table
stackBottom: pointer
stackTop: pointer
cycleThreshold: int
zct: TCellSeq # the zero count table
decStack: TCellSeq # cells in the stack that are to decref again
cycleRoots: TCellSeq
tempStack: TCellSeq # temporary stack for recursion elimination
freeStack: TCellSeq # objects ready to be freed
zct: CellSeq # the zero count table
decStack: CellSeq # cells in the stack that are to decref again
cycleRoots: CellSeq
tempStack: CellSeq # temporary stack for recursion elimination
freeStack: CellSeq # objects ready to be freed
recGcLock: int # prevent recursion via finalizers; no thread lock
cycleRootsTrimIdx: int # Trimming is a light-weight collection of the
# cycle roots table that uses a cheap linear scan
@ -132,21 +132,22 @@ type
# This index indicates the start of the range of
# such new objects within the table.
when withRealTime:
maxPause: TNanos # max allowed pause in nanoseconds; active if > 0
region: TMemRegion # garbage collected region
stat: TGcStat
maxPause: Nanos # max allowed pause in nanoseconds; active if > 0
region: MemRegion # garbage collected region
stat: GcStat
{.deprecated: [TWalkOp: WalkOp, TFinalizer: Finalizer, TGcStat: GcStat,
TGcHeap: GcHeap].}
var
gch* {.rtlThreadVar.}: TGcHeap
gch* {.rtlThreadVar.}: GcHeap
when not defined(useNimRtl):
instantiateForRegion(gch.region)
template acquire(gch: TGcHeap) =
template acquire(gch: GcHeap) =
when hasThreadSupport and hasSharedHeap:
AcquireSys(HeapLock)
template release(gch: TGcHeap) =
template release(gch: GcHeap) =
when hasThreadSupport and hasSharedHeap:
releaseSys(HeapLock)
@ -169,7 +170,7 @@ template isDead(c: Pcell): expr =
c.isBitUp(rcReallyDead) # also covers rcRetiredBuffer
template clearBit(c: PCell, bit): expr =
c.refcount = c.refcount and (not TRefCount(bit))
c.refcount = c.refcount and (not RefCount(bit))
when debugGC:
var gcCollectionIdx = 0
@ -206,7 +207,7 @@ when debugGC:
c_fprintf(c_stdout, "[GC] %s: %p %d rc=%ld\n",
msg, c, kind, c.refcount shr rcShift)
proc addZCT(zct: var TCellSeq, c: PCell) {.noinline.} =
proc addZCT(zct: var CellSeq, c: PCell) {.noinline.} =
if c.isBitDown(rcZct):
c.setBit rcZct
zct.add c
@ -221,7 +222,7 @@ template setStackTop(gch) =
var stackTop {.volatile.}: pointer
gch.stackTop = addr(stackTop)
template addCycleRoot(cycleRoots: var TCellSeq, c: PCell) =
template addCycleRoot(cycleRoots: var CellSeq, c: PCell) =
if c.color != rcCycleCandidate:
c.setColor rcCycleCandidate
@ -233,11 +234,11 @@ template addCycleRoot(cycleRoots: var TCellSeq, c: PCell) =
proc cellToUsr(cell: PCell): pointer {.inline.} =
# convert object (=pointer to refcount) to pointer to userdata
result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(TCell)))
result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(Cell)))
proc usrToCell*(usr: pointer): PCell {.inline.} =
# convert pointer to userdata to object (=pointer to refcount)
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(Cell)))
proc canbeCycleRoot(c: PCell): bool {.inline.} =
result = ntfAcyclic notin c.typ.flags
@ -254,11 +255,11 @@ when BitsPerPage mod (sizeof(int)*8) != 0:
{.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
# forward declarations:
proc collectCT(gch: var TGcHeap)
proc collectCT(gch: var GcHeap)
proc isOnStack*(p: pointer): bool {.noinline.}
proc forAllChildren(cell: PCell, op: TWalkOp)
proc doOperation(p: pointer, op: TWalkOp)
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp)
proc forAllChildren(cell: PCell, op: WalkOp)
proc doOperation(p: pointer, op: WalkOp)
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp)
# we need the prototype here for debugging purposes
proc prepareDealloc(cell: PCell) =
@ -269,18 +270,19 @@ proc prepareDealloc(cell: PCell) =
# prevend recursive entering here by a lock.
# XXX: we should set the cell's children to nil!
inc(gch.recGcLock)
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
(cast[Finalizer](cell.typ.finalizer))(cellToUsr(cell))
dec(gch.recGcLock)
when traceGC:
# traceGC is a special switch to enable extensive debugging
type
TCellState = enum
CellState = enum
csAllocated, csFreed
{.deprecated: [TCellState: CellState].}
var
states: array[TCellState, TCellSet]
states: array[CellState, CellSet]
proc traceCell(c: PCell, state: TCellState) =
proc traceCell(c: PCell, state: CellState) =
case state
of csAllocated:
if c in states[csAllocated]:
@ -300,7 +302,7 @@ when traceGC:
incl(states[state], c)
proc computeCellWeight(c: PCell): int =
var x: TCellSet
var x: CellSet
x.init
let startLen = gch.tempStack.len
@ -363,30 +365,32 @@ proc rtlAddZCT(c: PCell) {.rtl, inl.} =
WithHeapLock: addZCT(gch.zct, c)
type
TCyclicMode = enum
CyclicMode = enum
Cyclic,
Acyclic,
MaybeCyclic
TReleaseType = enum
ReleaseType = enum
AddToZTC
FreeImmediately
THeapType = enum
HeapType = enum
LocalHeap
SharedHeap
{.deprecated: [TCyclicMode: CyclicMode, TReleaseType: ReleaseType,
THeapType: HeapType].}
template `++` (rc: TRefCount, heapType: THeapType): stmt =
template `++` (rc: RefCount, heapType: HeapType): stmt =
when heapType == SharedHeap:
discard atomicInc(rc, rcIncrement)
else:
inc rc, rcIncrement
template `--`(rc: TRefCount): expr =
template `--`(rc: RefCount): expr =
dec rc, rcIncrement
rc <% rcIncrement
template `--` (rc: TRefCount, heapType: THeapType): expr =
template `--` (rc: RefCount, heapType: HeapType): expr =
(when heapType == SharedHeap: atomicDec(rc, rcIncrement) <% rcIncrement else: --rc)
template doDecRef(cc: PCell,
@ -479,7 +483,7 @@ when hasThreadSupport and hasSharedHeap:
proc initGC() =
when not defined(useNimRtl):
when traceGC:
for i in low(TCellState)..high(TCellState): init(states[i])
for i in low(CellState)..high(CellState): init(states[i])
gch.cycleThreshold = InitialCycleThreshold
gch.stat.stackScans = 0
gch.stat.cycleCollections = 0
@ -494,7 +498,7 @@ proc initGC() =
init(gch.cycleRoots)
init(gch.decStack)
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) =
var d = cast[ByteAddress](dest)
case n.kind
of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
@ -514,7 +518,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
if m != nil: forAllSlotsAux(dest, m, op)
of nkNone: sysAssert(false, "forAllSlotsAux")
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) =
var d = cast[ByteAddress](dest)
if dest == nil: return # nothing to do
if ntfNoRefs notin mt.flags:
@ -528,7 +532,7 @@ proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
else: discard
proc forAllChildren(cell: PCell, op: TWalkOp) =
proc forAllChildren(cell: PCell, op: WalkOp) =
sysAssert(cell != nil, "forAllChildren: 1")
sysAssert(cell.typ != nil, "forAllChildren: 2")
sysAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 3"
@ -549,7 +553,7 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
cell.typ.base, op)
else: discard
proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
proc addNewObjToZCT(res: PCell, gch: var GcHeap) {.inline.} =
# we check the last 8 entries (cache line) for a slot that could be reused.
# In 63% of all cases we succeed here! But we have to optimize the heck
# out of this small linear search so that ``newObj`` is not slowed down.
@ -593,7 +597,7 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
return
add(gch.zct, res)
proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1 = false): pointer =
proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap, rc1 = false): pointer =
# generates a new object and sets its reference counter to 0
acquire(gch)
sysAssert(allocInv(gch.region), "rawNewObj begin")
@ -602,7 +606,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1 = false): pointer
collectCT(gch)
sysAssert(allocInv(gch.region), "rawNewObj after collect")
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
sysAssert(allocInv(gch.region), "rawNewObj after rawAlloc")
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
@ -638,20 +642,20 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1 = false): pointer
{.pop.}
proc freeCell(gch: var TGcHeap, c: PCell) =
proc freeCell(gch: var GcHeap, c: PCell) =
# prepareDealloc(c)
gcTrace(c, csFreed)
when reallyDealloc: rawDealloc(gch.region, c)
else:
sysAssert(c.typ != nil, "collectCycles")
zeroMem(c, sizeof(TCell))
zeroMem(c, sizeof(Cell))
template eraseAt(cells: var TCellSeq, at: int): stmt =
template eraseAt(cells: var CellSeq, at: int): stmt =
cells.d[at] = cells.d[cells.len - 1]
dec cells.len
template trimAt(roots: var TCellSeq, at: int): stmt =
template trimAt(roots: var CellSeq, at: int): stmt =
# This will remove a cycle root candidate during trimming.
# a candidate is removed either because it received a refup and
# it's no longer a candidate or because it received further refdowns
@ -696,7 +700,7 @@ proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
cast[PGenericSeq](result).len = len
cast[PGenericSeq](result).reserved = len
proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
acquire(gch)
collectCT(gch)
var ol = usrToCell(old)
@ -704,7 +708,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
sysAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
sysAssert(allocInv(gch.region), "growObj begin")
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
var elemSize = if ol.typ.kind != tyString: ol.typ.base.size
else: 1
@ -713,8 +717,8 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
# XXX: This should happen outside
# call user-defined move code
# call user-defined default constructor
copyMem(res, ol, oldsize + sizeof(TCell))
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
copyMem(res, ol, oldsize + sizeof(Cell))
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)),
newsize-oldsize)
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
@ -778,26 +782,27 @@ proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
# ---------------- cycle collector -------------------------------------------
proc doOperation(p: pointer, op: TWalkOp) =
proc doOperation(p: pointer, op: WalkOp) =
if p == nil: return
var c: PCell = usrToCell(p)
sysAssert(c != nil, "doOperation: 1")
gch.tempStack.add c
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
doOperation(d, TWalkOp(op))
doOperation(d, WalkOp(op))
type
TRecursionType = enum
RecursionType = enum
FromChildren,
FromRoot
{.deprecated: [TRecursionType: RecursionType].}
proc collectZCT(gch: var TGcHeap): bool
proc collectZCT(gch: var GcHeap): bool
template pseudoRecursion(typ: TRecursionType, body: stmt): stmt =
template pseudoRecursion(typ: RecursionType, body: stmt): stmt =
discard
proc trimCycleRoots(gch: var TGcHeap, startIdx = gch.cycleRootsTrimIdx) =
proc trimCycleRoots(gch: var GcHeap, startIdx = gch.cycleRootsTrimIdx) =
var i = startIdx
while i < gch.cycleRoots.len:
if gch.cycleRoots.d[i].color != rcCycleCandidate:
@ -808,7 +813,7 @@ proc trimCycleRoots(gch: var TGcHeap, startIdx = gch.cycleRootsTrimIdx) =
gch.cycleRootsTrimIdx = gch.cycleRoots.len
# we now use a much simpler and non-recursive algorithm for cycle removal
proc collectCycles(gch: var TGcHeap) =
proc collectCycles(gch: var GcHeap) =
if gch.cycleRoots.len == 0: return
gch.stat.cycleTableSize = max(gch.stat.cycleTableSize, gch.cycleRoots.len)
@ -990,7 +995,7 @@ var gcDebugging* = false
var seqdbg* : proc (s: PGenericSeq) {.cdecl.}
proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
# the addresses are not as cells on the stack, so turn them to cells:
sysAssert(allocInv(gch.region), "gcMark begin")
var cell = usrToCell(p)
@ -1025,7 +1030,7 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
add(gch.decStack, cell)
sysAssert(allocInv(gch.region), "gcMark end")
proc markThreadStacks(gch: var TGcHeap) =
proc markThreadStacks(gch: var GcHeap) =
when hasThreadSupport and hasSharedHeap:
{.error: "not fully implemented".}
var it = threadList
@ -1074,7 +1079,7 @@ proc stackSize(): int {.noinline.} =
var
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
# a little hack to get the size of a TJmpBuf in the generated C code
# a little hack to get the size of a JmpBuf in the generated C code
# in a platform independent way
when defined(sparc): # For SPARC architecture.
@ -1086,7 +1091,7 @@ when defined(sparc): # For SPARC architecture.
var x = cast[ByteAddress](p)
result = a <=% x and x <=% b
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
when defined(sparcv9):
asm """"flushw \n" """
else:
@ -1117,7 +1122,7 @@ elif stackIncreases:
var x = cast[ByteAddress](p)
result = a <=% x and x <=% b
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
var registers: C_JmpBuf
if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
var max = cast[ByteAddress](gch.stackBottom)
@ -1140,7 +1145,7 @@ else:
var x = cast[ByteAddress](p)
result = a <=% x and x <=% b
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
# We use a jmp_buf buffer that is in the C stack.
# Used to traverse the stack and registers assuming
# that 'setjmp' will save registers in the C stack.
@ -1181,7 +1186,7 @@ else:
# end of non-portable code
# ----------------------------------------------------------------------------
proc releaseCell(gch: var TGcHeap, cell: PCell) =
proc releaseCell(gch: var GcHeap, cell: PCell) =
if cell.color != rcReallyDead:
prepareDealloc(cell)
cell.setColor rcReallyDead
@ -1210,13 +1215,13 @@ proc releaseCell(gch: var TGcHeap, cell: PCell) =
# recursion).
# We can ignore it now as the ZCT cleaner will reach it soon.
proc collectZCT(gch: var TGcHeap): bool =
proc collectZCT(gch: var GcHeap): bool =
const workPackage = 100
var L = addr(gch.zct.len)
when withRealtime:
var steps = workPackage
var t0: TTicks
var t0: Ticks
if gch.maxPause > 0: t0 = getticks()
while L[] > 0:
@ -1257,7 +1262,7 @@ proc collectZCT(gch: var TGcHeap): bool =
#deInit(gch.zct)
#init(gch.zct)
proc unmarkStackAndRegisters(gch: var TGcHeap) =
proc unmarkStackAndRegisters(gch: var GcHeap) =
var d = gch.decStack.d
for i in 0 .. <gch.decStack.len:
sysAssert isAllocatedPtr(gch.region, d[i]), "unmarkStackAndRegisters"
@ -1283,7 +1288,7 @@ proc unmarkStackAndRegisters(gch: var TGcHeap) =
gch.decStack.len = 0
proc collectCTBody(gch: var TGcHeap) =
proc collectCTBody(gch: var GcHeap) =
when withRealtime:
let t0 = getticks()
when debugGC: inc gcCollectionIdx
@ -1315,20 +1320,20 @@ proc collectCTBody(gch: var TGcHeap) =
if gch.maxPause > 0 and duration > gch.maxPause:
c_fprintf(c_stdout, "[GC] missed deadline: %ld\n", duration)
proc collectCT(gch: var TGcHeap) =
proc collectCT(gch: var GcHeap) =
if (gch.zct.len >= ZctThreshold or (cycleGC and
getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and
gch.recGcLock == 0:
collectCTBody(gch)
when withRealtime:
proc toNano(x: int): TNanos {.inline.} =
proc toNano(x: int): Nanos {.inline.} =
result = x * 1000
proc GC_setMaxPause*(MaxPauseInUs: int) =
gch.maxPause = MaxPauseInUs.toNano
proc GC_step(gch: var TGcHeap, us: int, strongAdvice: bool) =
proc GC_step(gch: var GcHeap, us: int, strongAdvice: bool) =
acquire(gch)
gch.maxPause = us.toNano
if (gch.zct.len >= ZctThreshold or (cycleGC and

View file

@ -26,49 +26,50 @@ when defined(memProfiler):
proc nimProfile(requestedSize: int)
type
TWalkOp = enum
WalkOp = enum
waMarkGlobal, # we need to mark conservatively for global marker procs
# as these may refer to a global var and not to a thread
# local
waMarkPrecise # fast precise marking
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
# A ref type can have a finalizer that is called before the object's
# storage is freed.
TGlobalMarkerProc = proc () {.nimcall, benign.}
GlobalMarkerProc = proc () {.nimcall, benign.}
TGcStat = object
GcStat = object
collections: int # number of performed full collections
maxThreshold: int # max threshold that has been set
maxStackSize: int # max stack size
freedObjects: int # max entries in cycle table
TGcHeap = object # this contains the zero count and
GcHeap = object # this contains the zero count and
# non-zero count table
stackBottom: pointer
cycleThreshold: int
when useCellIds:
idGenerator: int
when withBitvectors:
allocated, marked: TCellSet
tempStack: TCellSeq # temporary stack for recursion elimination
allocated, marked: CellSet
tempStack: CellSeq # temporary stack for recursion elimination
recGcLock: int # prevent recursion via finalizers; no thread lock
region: TMemRegion # garbage collected region
stat: TGcStat
additionalRoots: TCellSeq # dummy roots for GC_ref/unref
region: MemRegion # garbage collected region
stat: GcStat
additionalRoots: CellSeq # dummy roots for GC_ref/unref
{.deprecated: [TWalkOp: WalkOp, TFinalizer: Finalizer, TGcStat: GcStat,
TGlobalMarkerProc: GlobalMarkerProc, TGcHeap: GcHeap].}
var
gch {.rtlThreadVar.}: TGcHeap
gch {.rtlThreadVar.}: GcHeap
when not defined(useNimRtl):
instantiateForRegion(gch.region)
template acquire(gch: TGcHeap) =
template acquire(gch: GcHeap) =
when hasThreadSupport and hasSharedHeap:
acquireSys(HeapLock)
template release(gch: TGcHeap) =
template release(gch: GcHeap) =
when hasThreadSupport and hasSharedHeap:
releaseSys(HeapLock)
@ -80,11 +81,11 @@ template gcAssert(cond: bool, msg: string) =
proc cellToUsr(cell: PCell): pointer {.inline.} =
# convert object (=pointer to refcount) to pointer to userdata
result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(TCell)))
result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(Cell)))
proc usrToCell(usr: pointer): PCell {.inline.} =
# convert pointer to userdata to object (=pointer to refcount)
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(Cell)))
proc canbeCycleRoot(c: PCell): bool {.inline.} =
result = ntfAcyclic notin c.typ.flags
@ -101,9 +102,9 @@ proc internRefcount(p: pointer): int {.exportc: "getRefcount".} =
var
globalMarkersLen: int
globalMarkers: array[0.. 7_000, TGlobalMarkerProc]
globalMarkers: array[0.. 7_000, GlobalMarkerProc]
proc nimRegisterGlobalMarker(markerProc: TGlobalMarkerProc) {.compilerProc.} =
proc nimRegisterGlobalMarker(markerProc: GlobalMarkerProc) {.compilerProc.} =
if globalMarkersLen <= high(globalMarkers):
globalMarkers[globalMarkersLen] = markerProc
inc globalMarkersLen
@ -116,11 +117,11 @@ when BitsPerPage mod (sizeof(int)*8) != 0:
{.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
# forward declarations:
proc collectCT(gch: var TGcHeap) {.benign.}
proc collectCT(gch: var GcHeap) {.benign.}
proc isOnStack*(p: pointer): bool {.noinline, benign.}
proc forAllChildren(cell: PCell, op: TWalkOp) {.benign.}
proc doOperation(p: pointer, op: TWalkOp) {.benign.}
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) {.benign.}
proc forAllChildren(cell: PCell, op: WalkOp) {.benign.}
proc doOperation(p: pointer, op: WalkOp) {.benign.}
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.}
# we need the prototype here for debugging purposes
proc prepareDealloc(cell: PCell) =
@ -131,7 +132,7 @@ proc prepareDealloc(cell: PCell) =
# prevend recursive entering here by a lock.
# XXX: we should set the cell's children to nil!
inc(gch.recGcLock)
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
(cast[Finalizer](cell.typ.finalizer))(cellToUsr(cell))
dec(gch.recGcLock)
proc nimGCref(p: pointer) {.compilerProc.} =
@ -182,7 +183,7 @@ proc setupForeignThreadGc*() =
setStackBottom(addr(stackTop))
initGC()
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} =
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} =
var d = cast[ByteAddress](dest)
case n.kind
of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
@ -194,7 +195,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} =
if m != nil: forAllSlotsAux(dest, m, op)
of nkNone: sysAssert(false, "forAllSlotsAux")
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) =
var d = cast[ByteAddress](dest)
if dest == nil: return # nothing to do
if ntfNoRefs notin mt.flags:
@ -208,7 +209,7 @@ proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
else: discard
proc forAllChildren(cell: PCell, op: TWalkOp) =
proc forAllChildren(cell: PCell, op: WalkOp) =
gcAssert(cell != nil, "forAllChildren: 1")
gcAssert(cell.typ != nil, "forAllChildren: 2")
gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 3"
@ -228,12 +229,12 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
GenericSeqSize), cell.typ.base, op)
else: discard
proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
# generates a new object and sets its reference counter to 0
acquire(gch)
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
collectCT(gch)
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
# now it is buffered in the ZCT
res.typ = typ
@ -285,20 +286,20 @@ proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
cast[PGenericSeq](result).reserved = len
when defined(memProfiler): nimProfile(size)
proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
acquire(gch)
collectCT(gch)
var ol = usrToCell(old)
sysAssert(ol.typ != nil, "growObj: 1")
gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
var elemSize = 1
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
copyMem(res, ol, oldsize + sizeof(TCell))
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
copyMem(res, ol, oldsize + sizeof(Cell))
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)),
newsize-oldsize)
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
when false:
@ -306,7 +307,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
when withBitvectors: excl(gch.allocated, ol)
when reallyDealloc: rawDealloc(gch.region, ol)
else:
zeroMem(ol, sizeof(TCell))
zeroMem(ol, sizeof(Cell))
when withBitvectors: incl(gch.allocated, res)
when useCellIds:
inc gch.idGenerator
@ -322,7 +323,7 @@ proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
# ----------------- collector -----------------------------------------------
proc mark(gch: var TGcHeap, c: PCell) =
proc mark(gch: var GcHeap, c: PCell) =
when withBitvectors:
incl(gch.marked, c)
gcAssert gch.tempStack.len == 0, "stack not empty!"
@ -344,7 +345,7 @@ proc mark(gch: var TGcHeap, c: PCell) =
d.refCount = rcBlack
forAllChildren(d, waMarkPrecise)
proc doOperation(p: pointer, op: TWalkOp) =
proc doOperation(p: pointer, op: WalkOp) =
if p == nil: return
var c: PCell = usrToCell(p)
gcAssert(c != nil, "doOperation: 1")
@ -359,17 +360,17 @@ proc doOperation(p: pointer, op: TWalkOp) =
of waMarkPrecise: add(gch.tempStack, c)
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
doOperation(d, TWalkOp(op))
doOperation(d, WalkOp(op))
proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
proc freeCyclicCell(gch: var GcHeap, c: PCell) =
inc gch.stat.freedObjects
prepareDealloc(c)
when reallyDealloc: rawDealloc(gch.region, c)
else:
gcAssert(c.typ != nil, "freeCyclicCell")
zeroMem(c, sizeof(TCell))
zeroMem(c, sizeof(Cell))
proc sweep(gch: var TGcHeap) =
proc sweep(gch: var GcHeap) =
when withBitvectors:
for c in gch.allocated.elementsExcept(gch.marked):
gch.allocated.excl(c)
@ -391,12 +392,12 @@ when false:
writeStackTrace()
quit 1
proc markGlobals(gch: var TGcHeap) =
proc markGlobals(gch: var GcHeap) =
for i in 0 .. < globalMarkersLen: globalMarkers[i]()
let d = gch.additionalRoots.d
for i in 0 .. < gch.additionalRoots.len: mark(gch, d[i])
proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
# the addresses are not as cells on the stack, so turn them to cells:
var cell = usrToCell(p)
var c = cast[ByteAddress](cell)
@ -446,7 +447,7 @@ when defined(sparc): # For SPARC architecture.
var x = cast[ByteAddress](p)
result = a <=% x and x <=% b
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
when defined(sparcv9):
asm """"flushw \n" """
else:
@ -479,10 +480,10 @@ elif stackIncreases:
var
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
# a little hack to get the size of a TJmpBuf in the generated C code
# a little hack to get the size of a JmpBuf in the generated C code
# in a platform independent way
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
var registers: C_JmpBuf
if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
var max = cast[ByteAddress](gch.stackBottom)
@ -505,7 +506,7 @@ else:
var x = cast[ByteAddress](p)
result = a <=% x and x <=% b
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
# We use a jmp_buf buffer that is in the C stack.
# Used to traverse the stack and registers assuming
# that 'setjmp' will save registers in the C stack.
@ -543,7 +544,7 @@ else:
# end of non-portable code
# ----------------------------------------------------------------------------
proc collectCTBody(gch: var TGcHeap) =
proc collectCTBody(gch: var GcHeap) =
gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
prepareForInteriorPointerChecking(gch.region)
markStackAndRegisters(gch)
@ -558,7 +559,7 @@ proc collectCTBody(gch: var TGcHeap) =
gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
sysAssert(allocInv(gch.region), "collectCT: end")
proc collectCT(gch: var TGcHeap) =
proc collectCT(gch: var GcHeap) =
if getOccupiedMem(gch.region) >= gch.cycleThreshold and gch.recGcLock == 0:
collectCTBody(gch)

View file

@ -15,13 +15,13 @@ else:
proc log*(s: cstring) {.importc: "console.log", varargs, nodecl.}
type
PSafePoint = ptr TSafePoint
TSafePoint {.compilerproc, final.} = object
PSafePoint = ptr SafePoint
SafePoint {.compilerproc, final.} = object
prev: PSafePoint # points to next safe point
exc: ref Exception
PCallFrame = ptr TCallFrame
TCallFrame {.importc, nodecl, final.} = object
PCallFrame = ptr CallFrame
CallFrame {.importc, nodecl, final.} = object
prev: PCallFrame
procname: cstring
line: int # current line number
@ -33,6 +33,7 @@ type
lineNumber {.importc.}: int
message {.importc.}: cstring
stack {.importc.}: cstring
{.deprecated: [TSafePoint: SafePoint, TCallFrame: CallFrame].}
var
framePtr {.importc, nodecl, volatile.}: PCallFrame
@ -60,12 +61,13 @@ proc getCurrentExceptionMsg*(): string =
proc auxWriteStackTrace(f: PCallFrame): string =
type
TTempFrame = tuple[procname: cstring, line: int]
TempFrame = tuple[procname: cstring, line: int]
{.deprecated: [TTempFrame: TempFrame].}
var
it = f
i = 0
total = 0
tempFrames: array [0..63, TTempFrame]
tempFrames: array [0..63, TempFrame]
while it != nil and i <= high(tempFrames):
tempFrames[i].procname = it.procname
tempFrames[i].line = it.line
@ -260,17 +262,17 @@ proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerProc.} =
"""
type
TDocument {.importc.} = object of RootObj
Document {.importc.} = object of RootObj
write: proc (text: cstring) {.nimcall.}
writeln: proc (text: cstring) {.nimcall.}
createAttribute: proc (identifier: cstring): ref TNode {.nimcall.}
createElement: proc (identifier: cstring): ref TNode {.nimcall.}
createTextNode: proc (identifier: cstring): ref TNode {.nimcall.}
getElementById: proc (id: cstring): ref TNode {.nimcall.}
getElementsByName: proc (name: cstring): seq[ref TNode] {.nimcall.}
getElementsByTagName: proc (name: cstring): seq[ref TNode] {.nimcall.}
createAttribute: proc (identifier: cstring): ref Node {.nimcall.}
createElement: proc (identifier: cstring): ref Node {.nimcall.}
createTextNode: proc (identifier: cstring): ref Node {.nimcall.}
getElementById: proc (id: cstring): ref Node {.nimcall.}
getElementsByName: proc (name: cstring): seq[ref Node] {.nimcall.}
getElementsByTagName: proc (name: cstring): seq[ref Node] {.nimcall.}
TNodeType* = enum
NodeType* = enum
ElementNode = 1,
AttributeNode,
TextNode,
@ -283,35 +285,36 @@ type
DocumentTypeNode,
DocumentFragmentNode,
NotationNode
TNode* {.importc.} = object of RootObj
attributes*: seq[ref TNode]
childNodes*: seq[ref TNode]
Node* {.importc.} = object of RootObj
attributes*: seq[ref Node]
childNodes*: seq[ref Node]
data*: cstring
firstChild*: ref TNode
lastChild*: ref TNode
nextSibling*: ref TNode
firstChild*: ref Node
lastChild*: ref Node
nextSibling*: ref Node
nodeName*: cstring
nodeType*: TNodeType
nodeType*: NodeType
nodeValue*: cstring
parentNode*: ref TNode
previousSibling*: ref TNode
appendChild*: proc (child: ref TNode) {.nimcall.}
parentNode*: ref Node
previousSibling*: ref Node
appendChild*: proc (child: ref Node) {.nimcall.}
appendData*: proc (data: cstring) {.nimcall.}
cloneNode*: proc (copyContent: bool) {.nimcall.}
deleteData*: proc (start, len: int) {.nimcall.}
getAttribute*: proc (attr: cstring): cstring {.nimcall.}
getAttributeNode*: proc (attr: cstring): ref TNode {.nimcall.}
getElementsByTagName*: proc (): seq[ref TNode] {.nimcall.}
getAttributeNode*: proc (attr: cstring): ref Node {.nimcall.}
getElementsByTagName*: proc (): seq[ref Node] {.nimcall.}
hasChildNodes*: proc (): bool {.nimcall.}
insertBefore*: proc (newNode, before: ref TNode) {.nimcall.}
insertBefore*: proc (newNode, before: ref Node) {.nimcall.}
insertData*: proc (position: int, data: cstring) {.nimcall.}
removeAttribute*: proc (attr: cstring) {.nimcall.}
removeAttributeNode*: proc (attr: ref TNode) {.nimcall.}
removeChild*: proc (child: ref TNode) {.nimcall.}
replaceChild*: proc (newNode, oldNode: ref TNode) {.nimcall.}
removeAttributeNode*: proc (attr: ref Node) {.nimcall.}
removeChild*: proc (child: ref Node) {.nimcall.}
replaceChild*: proc (newNode, oldNode: ref Node) {.nimcall.}
replaceData*: proc (start, len: int, text: cstring) {.nimcall.}
setAttribute*: proc (name, value: cstring) {.nimcall.}
setAttributeNode*: proc (attr: ref TNode) {.nimcall.}
setAttributeNode*: proc (attr: ref Node) {.nimcall.}
{.deprecated: [TNode: Node, TNodeType: NodeType, TDocument: Document].}
when defined(kwin):
proc rawEcho {.compilerproc, asmNoStackFrame.} =
@ -337,7 +340,7 @@ elif defined(nodejs):
else:
var
document {.importc, nodecl.}: ref TDocument
document {.importc, nodecl.}: ref Document
proc ewriteln(x: cstring) =
var node = document.getElementsByTagName("body")[0]

View file

@ -34,9 +34,10 @@ const
type
PPointer = ptr pointer
TByteArray = array[0..1000_0000, byte]
PByte = ptr TByteArray
ByteArray = array[0..1000_0000, byte]
PByte = ptr ByteArray
PString = ptr string
{.deprecated: [TByteArray: ByteArray].}
# Page size of the system; in most cases 4096 bytes. For exotic OS or
# CPU this needs to be changed:
@ -180,16 +181,17 @@ when defined(boehmgc):
dest[] = src
type
TMemRegion = object {.final, pure.}
MemRegion = object {.final, pure.}
{.deprecated: [TMemRegion: MemRegion].}
proc alloc(r: var TMemRegion, size: int): pointer =
proc alloc(r: var MemRegion, size: int): pointer =
result = boehmAlloc(size)
if result == nil: raiseOutOfMem()
proc alloc0(r: var TMemRegion, size: int): pointer =
proc alloc0(r: var MemRegion, size: int): pointer =
result = alloc(size)
zeroMem(result, size)
proc dealloc(r: var TMemRegion, p: pointer) = boehmDealloc(p)
proc deallocOsPages(r: var TMemRegion) {.inline.} = discard
proc dealloc(r: var MemRegion, p: pointer) = boehmDealloc(p)
proc deallocOsPages(r: var MemRegion) {.inline.} = discard
proc deallocOsPages() {.inline.} = discard
include "system/cellsets"
@ -257,14 +259,15 @@ elif defined(nogc) and defined(useMalloc):
dest[] = src
type
TMemRegion = object {.final, pure.}
MemRegion = object {.final, pure.}
{.deprecated: [TMemRegion: MemRegion].}
proc alloc(r: var TMemRegion, size: int): pointer =
proc alloc(r: var MemRegion, size: int): pointer =
result = alloc(size)
proc alloc0(r: var TMemRegion, size: int): pointer =
proc alloc0(r: var MemRegion, size: int): pointer =
result = alloc0(size)
proc dealloc(r: var TMemRegion, p: pointer) = dealloc(p)
proc deallocOsPages(r: var TMemRegion) {.inline.} = discard
proc dealloc(r: var MemRegion, p: pointer) = dealloc(p)
proc deallocOsPages(r: var MemRegion) {.inline.} = discard
proc deallocOsPages() {.inline.} = discard
elif defined(nogc):
@ -313,7 +316,7 @@ elif defined(nogc):
proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline.} =
dest[] = src
var allocator {.rtlThreadVar.}: TMemRegion
var allocator {.rtlThreadVar.}: MemRegion
instantiateForRegion(allocator)
include "system/cellsets"
@ -323,7 +326,7 @@ else:
include "system/cellsets"
when not leakDetector:
sysAssert(sizeof(TCell) == sizeof(TFreeCell), "sizeof TFreeCell")
sysAssert(sizeof(Cell) == sizeof(FreeCell), "sizeof FreeCell")
when compileOption("gc", "v2"):
include "system/gc2"
elif defined(gcMarkAndSweep):

View file

@ -19,10 +19,11 @@ const
MaxTraceLen = 20 # tracking the last 20 calls is enough
type
TStackTrace* = array [0..MaxTraceLen-1, cstring]
TProfilerHook* = proc (st: TStackTrace) {.nimcall.}
StackTrace* = array [0..MaxTraceLen-1, cstring]
ProfilerHook* = proc (st: StackTrace) {.nimcall.}
{.deprecated: [TStackTrace: StackTrace, TProfilerHook: ProfilerHook].}
proc captureStackTrace(f: PFrame, st: var TStackTrace) =
proc captureStackTrace(f: PFrame, st: var StackTrace) =
const
firstCalls = 5
var
@ -51,14 +52,15 @@ proc captureStackTrace(f: PFrame, st: var TStackTrace) =
when defined(memProfiler):
type
TMemProfilerHook* = proc (st: TStackTrace, requestedSize: int) {.nimcall, benign.}
MemProfilerHook* = proc (st: StackTrace, requestedSize: int) {.nimcall, benign.}
{.deprecated: [TMemProfilerHook: MemProfilerHook].}
var
profilerHook*: TMemProfilerHook
profilerHook*: MemProfilerHook
## set this variable to provide a procedure that implements a profiler in
## user space. See the `nimprof` module for a reference implementation.
proc callProfilerHook(hook: TMemProfilerHook, requestedSize: int) =
var st: TStackTrace
proc callProfilerHook(hook: MemProfilerHook, requestedSize: int) =
var st: StackTrace
captureStackTrace(framePtr, st)
hook(st, requestedSize)
@ -70,15 +72,15 @@ else:
SamplingInterval = 50_000
# set this to change the default sampling interval
var
profilerHook*: TProfilerHook
profilerHook*: ProfilerHook
## set this variable to provide a procedure that implements a profiler in
## user space. See the `nimprof` module for a reference implementation.
gTicker {.threadvar.}: int
proc callProfilerHook(hook: TProfilerHook) {.noinline.} =
proc callProfilerHook(hook: ProfilerHook) {.noinline.} =
# 'noinline' so that 'nimProfile' does not perform the stack allocation
# in the common case.
var st: TStackTrace
var st: StackTrace
captureStackTrace(framePtr, st)
hook(st)

View file

@ -121,38 +121,39 @@ proc reprSet(p: pointer, typ: PNimType): string {.compilerRtl.} =
reprSetAux(result, p, typ)
type
TReprClosure {.final.} = object # we cannot use a global variable here
ReprClosure {.final.} = object # we cannot use a global variable here
# as this wouldn't be thread-safe
when declared(TCellSet):
marked: TCellSet
when declared(CellSet):
marked: CellSet
recdepth: int # do not recurse endlessly
indent: int # indentation
{.deprecated: [TReprClosure: ReprClosure].}
when not defined(useNimRtl):
proc initReprClosure(cl: var TReprClosure) =
proc initReprClosure(cl: var ReprClosure) =
# Important: cellsets does not lock the heap when doing allocations! We
# have to do it here ...
when hasThreadSupport and hasSharedHeap and declared(heapLock):
AcquireSys(HeapLock)
when declared(TCellSet):
when declared(CellSet):
init(cl.marked)
cl.recdepth = -1 # default is to display everything!
cl.indent = 0
proc deinitReprClosure(cl: var TReprClosure) =
when declared(TCellSet): deinit(cl.marked)
proc deinitReprClosure(cl: var ReprClosure) =
when declared(CellSet): deinit(cl.marked)
when hasThreadSupport and hasSharedHeap and declared(heapLock):
ReleaseSys(HeapLock)
proc reprBreak(result: var string, cl: TReprClosure) =
proc reprBreak(result: var string, cl: ReprClosure) =
add result, "\n"
for i in 0..cl.indent-1: add result, ' '
proc reprAux(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) {.benign.}
cl: var ReprClosure) {.benign.}
proc reprArray(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
cl: var ReprClosure) =
add result, "["
var bs = typ.base.size
for i in 0..typ.size div bs - 1:
@ -161,7 +162,7 @@ when not defined(useNimRtl):
add result, "]"
proc reprSequence(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
cl: var ReprClosure) =
if p == nil:
add result, "nil"
return
@ -174,7 +175,7 @@ when not defined(useNimRtl):
add result, "]"
proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
cl: var TReprClosure) {.benign.} =
cl: var ReprClosure) {.benign.} =
case n.kind
of nkNone: sysAssert(false, "reprRecordAux")
of nkSlot:
@ -191,7 +192,7 @@ when not defined(useNimRtl):
if m != nil: reprRecordAux(result, p, m, cl)
proc reprRecord(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
cl: var ReprClosure) =
add result, "["
let oldLen = result.len
reprRecordAux(result, p, typ.node, cl)
@ -201,9 +202,9 @@ when not defined(useNimRtl):
add result, "]"
proc reprRef(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
cl: var ReprClosure) =
# we know that p is not nil here:
when declared(TCellSet):
when declared(CellSet):
when defined(boehmGC) or defined(nogc):
var cell = cast[PCell](p)
else:
@ -216,7 +217,7 @@ when not defined(useNimRtl):
reprAux(result, p, typ.base, cl)
proc reprAux(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
cl: var ReprClosure) =
if cl.recdepth == 0:
add result, "..."
return
@ -261,7 +262,7 @@ when not defined(useNimRtl):
proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {.
compilerRtl.} =
var
cl: TReprClosure
cl: ReprClosure
initReprClosure(cl)
result = "["
var bs = elemtyp.size
@ -274,7 +275,7 @@ proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {.
when not defined(useNimRtl):
proc reprAny(p: pointer, typ: PNimType): string =
var
cl: TReprClosure
cl: ReprClosure
initReprClosure(cl)
result = ""
if typ.kind in {tyObject, tyTuple, tyArray, tyArrayConstr, tySet}:

View file

@ -10,7 +10,8 @@
# set handling
type
TNimSet = array [0..4*2048-1, uint8]
NimSet = array [0..4*2048-1, uint8]
{.deprecated: [TNimSet: NimSet].}
proc countBits32(n: int32): int {.compilerproc.} =
var v = n
@ -22,7 +23,7 @@ proc countBits64(n: int64): int {.compilerproc.} =
result = countBits32(toU32(n and 0xffff'i64)) +
countBits32(toU32(n shr 16'i64))
proc cardSet(s: TNimSet, len: int): int {.compilerproc.} =
proc cardSet(s: NimSet, len: int): int {.compilerproc.} =
result = 0
for i in countup(0, len-1):
inc(result, countBits32(int32(s[i])))

View file

@ -11,8 +11,8 @@
when defined(Windows):
type
THandle = int
TSysLock {.final, pure.} = object # CRITICAL_SECTION in WinApi
Handle = int
SysLock {.final, pure.} = object # CRITICAL_SECTION in WinApi
DebugInfo: pointer
LockCount: int32
RecursionCount: int32
@ -20,85 +20,87 @@ when defined(Windows):
LockSemaphore: int
Reserved: int32
TSysCond = THandle
SysCond = Handle
{.deprecated: [THandle: Handle, TSysLock: SysLock, TSysCond: SysCond].}
proc initSysLock(L: var TSysLock) {.stdcall, noSideEffect,
proc initSysLock(L: var SysLock) {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "InitializeCriticalSection".}
## Initializes the lock `L`.
proc tryAcquireSysAux(L: var TSysLock): int32 {.stdcall, noSideEffect,
proc tryAcquireSysAux(L: var SysLock): int32 {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "TryEnterCriticalSection".}
## Tries to acquire the lock `L`.
proc tryAcquireSys(L: var TSysLock): bool {.inline.} =
proc tryAcquireSys(L: var SysLock): bool {.inline.} =
result = tryAcquireSysAux(L) != 0'i32
proc acquireSys(L: var TSysLock) {.stdcall, noSideEffect,
proc acquireSys(L: var SysLock) {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "EnterCriticalSection".}
## Acquires the lock `L`.
proc releaseSys(L: var TSysLock) {.stdcall, noSideEffect,
proc releaseSys(L: var SysLock) {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "LeaveCriticalSection".}
## Releases the lock `L`.
proc deinitSys(L: var TSysLock) {.stdcall, noSideEffect,
proc deinitSys(L: var SysLock) {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "DeleteCriticalSection".}
proc createEvent(lpEventAttributes: pointer,
bManualReset, bInitialState: int32,
lpName: cstring): TSysCond {.stdcall, noSideEffect,
lpName: cstring): SysCond {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "CreateEventA".}
proc closeHandle(hObject: THandle) {.stdcall, noSideEffect,
proc closeHandle(hObject: Handle) {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "CloseHandle".}
proc waitForSingleObject(hHandle: THandle, dwMilliseconds: int32): int32 {.
proc waitForSingleObject(hHandle: Handle, dwMilliseconds: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "WaitForSingleObject", noSideEffect.}
proc signalSysCond(hEvent: TSysCond) {.stdcall, noSideEffect,
proc signalSysCond(hEvent: SysCond) {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "SetEvent".}
proc initSysCond(cond: var TSysCond) {.inline.} =
proc initSysCond(cond: var SysCond) {.inline.} =
cond = createEvent(nil, 0'i32, 0'i32, nil)
proc deinitSysCond(cond: var TSysCond) {.inline.} =
proc deinitSysCond(cond: var SysCond) {.inline.} =
closeHandle(cond)
proc waitSysCond(cond: var TSysCond, lock: var TSysLock) =
proc waitSysCond(cond: var SysCond, lock: var SysLock) =
releaseSys(lock)
discard waitForSingleObject(cond, -1'i32)
acquireSys(lock)
proc waitSysCondWindows(cond: var TSysCond) =
proc waitSysCondWindows(cond: var SysCond) =
discard waitForSingleObject(cond, -1'i32)
else:
type
TSysLock {.importc: "pthread_mutex_t", pure, final,
SysLock {.importc: "pthread_mutex_t", pure, final,
header: "<sys/types.h>".} = object
TSysCond {.importc: "pthread_cond_t", pure, final,
SysCond {.importc: "pthread_cond_t", pure, final,
header: "<sys/types.h>".} = object
proc initSysLock(L: var TSysLock, attr: pointer = nil) {.
proc initSysLock(L: var SysLock, attr: pointer = nil) {.
importc: "pthread_mutex_init", header: "<pthread.h>", noSideEffect.}
proc acquireSys(L: var TSysLock) {.noSideEffect,
proc acquireSys(L: var SysLock) {.noSideEffect,
importc: "pthread_mutex_lock", header: "<pthread.h>".}
proc tryAcquireSysAux(L: var TSysLock): cint {.noSideEffect,
proc tryAcquireSysAux(L: var SysLock): cint {.noSideEffect,
importc: "pthread_mutex_trylock", header: "<pthread.h>".}
proc tryAcquireSys(L: var TSysLock): bool {.inline.} =
proc tryAcquireSys(L: var SysLock): bool {.inline.} =
result = tryAcquireSysAux(L) == 0'i32
proc releaseSys(L: var TSysLock) {.noSideEffect,
proc releaseSys(L: var SysLock) {.noSideEffect,
importc: "pthread_mutex_unlock", header: "<pthread.h>".}
proc deinitSys(L: var TSysLock) {.noSideEffect,
proc deinitSys(L: var SysLock) {.noSideEffect,
importc: "pthread_mutex_destroy", header: "<pthread.h>".}
proc initSysCond(cond: var TSysCond, cond_attr: pointer = nil) {.
proc initSysCond(cond: var SysCond, cond_attr: pointer = nil) {.
importc: "pthread_cond_init", header: "<pthread.h>", noSideEffect.}
proc waitSysCond(cond: var TSysCond, lock: var TSysLock) {.
proc waitSysCond(cond: var SysCond, lock: var SysLock) {.
importc: "pthread_cond_wait", header: "<pthread.h>", noSideEffect.}
proc signalSysCond(cond: var TSysCond) {.
proc signalSysCond(cond: var SysCond) {.
importc: "pthread_cond_signal", header: "<pthread.h>", noSideEffect.}
proc deinitSysCond(cond: var TSysCond) {.noSideEffect,
proc deinitSysCond(cond: var SysCond) {.noSideEffect,
importc: "pthread_cond_destroy", header: "<pthread.h>".}

View file

@ -19,9 +19,9 @@ when not declared(NimString):
type
CondVar = object
c: TSysCond
c: SysCond
when defined(posix):
stupidLock: TSysLock
stupidLock: SysLock
counter: int
proc createCondVar(): CondVar =

View file

@ -24,8 +24,8 @@
## import locks
##
## var
## thr: array [0..4, TThread[tuple[a,b: int]]]
## L: TLock
## thr: array [0..4, Thread[tuple[a,b: int]]]
## L: Lock
##
## proc threadFunc(interval: tuple[a,b: int]) {.thread.} =
## for i in interval.a..interval.b:
@ -51,40 +51,41 @@ const
when defined(windows):
type
TSysThread = THandle
TWinThreadProc = proc (x: pointer): int32 {.stdcall.}
SysThread = Handle
WinThreadProc = proc (x: pointer): int32 {.stdcall.}
{.deprecated: [TSysThread: SysThread, TWinThreadProc: WinThreadProc].}
proc createThread(lpThreadAttributes: pointer, dwStackSize: int32,
lpStartAddress: TWinThreadProc,
lpStartAddress: WinThreadProc,
lpParameter: pointer,
dwCreationFlags: int32,
lpThreadId: var int32): TSysThread {.
lpThreadId: var int32): SysThread {.
stdcall, dynlib: "kernel32", importc: "CreateThread".}
proc winSuspendThread(hThread: TSysThread): int32 {.
proc winSuspendThread(hThread: SysThread): int32 {.
stdcall, dynlib: "kernel32", importc: "SuspendThread".}
proc winResumeThread(hThread: TSysThread): int32 {.
proc winResumeThread(hThread: SysThread): int32 {.
stdcall, dynlib: "kernel32", importc: "ResumeThread".}
proc waitForMultipleObjects(nCount: int32,
lpHandles: ptr TSysThread,
lpHandles: ptr SysThread,
bWaitAll: int32,
dwMilliseconds: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}
proc terminateThread(hThread: TSysThread, dwExitCode: int32): int32 {.
proc terminateThread(hThread: SysThread, dwExitCode: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "TerminateThread".}
type
TThreadVarSlot = distinct int32
ThreadVarSlot = distinct int32
when true:
proc threadVarAlloc(): TThreadVarSlot {.
proc threadVarAlloc(): ThreadVarSlot {.
importc: "TlsAlloc", stdcall, header: "<windows.h>".}
proc threadVarSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
proc threadVarSetValue(dwTlsIndex: ThreadVarSlot, lpTlsValue: pointer) {.
importc: "TlsSetValue", stdcall, header: "<windows.h>".}
proc tlsGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
proc tlsGetValue(dwTlsIndex: ThreadVarSlot): pointer {.
importc: "TlsGetValue", stdcall, header: "<windows.h>".}
proc getLastError(): uint32 {.
@ -92,16 +93,16 @@ when defined(windows):
proc setLastError(x: uint32) {.
importc: "SetLastError", stdcall, header: "<windows.h>".}
proc threadVarGetValue(dwTlsIndex: TThreadVarSlot): pointer =
proc threadVarGetValue(dwTlsIndex: ThreadVarSlot): pointer =
let realLastError = getLastError()
result = tlsGetValue(dwTlsIndex)
setLastError(realLastError)
else:
proc threadVarAlloc(): TThreadVarSlot {.
proc threadVarAlloc(): ThreadVarSlot {.
importc: "TlsAlloc", stdcall, dynlib: "kernel32".}
proc threadVarSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
proc threadVarSetValue(dwTlsIndex: ThreadVarSlot, lpTlsValue: pointer) {.
importc: "TlsSetValue", stdcall, dynlib: "kernel32".}
proc threadVarGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
proc threadVarGetValue(dwTlsIndex: ThreadVarSlot): pointer {.
importc: "TlsGetValue", stdcall, dynlib: "kernel32".}
else:
@ -111,55 +112,58 @@ else:
{.passC: "-pthread".}
type
TSysThread {.importc: "pthread_t", header: "<sys/types.h>",
SysThread {.importc: "pthread_t", header: "<sys/types.h>",
final, pure.} = object
Tpthread_attr {.importc: "pthread_attr_t",
Pthread_attr {.importc: "pthread_attr_t",
header: "<sys/types.h>", final, pure.} = object
Ttimespec {.importc: "struct timespec",
Timespec {.importc: "struct timespec",
header: "<time.h>", final, pure.} = object
tv_sec: int
tv_nsec: int
{.deprecated: [TSysThread: SysThread, Tpthread_attr: PThreadAttr,
Ttimespec: Timespec].}
proc pthread_attr_init(a1: var TPthread_attr) {.
proc pthread_attr_init(a1: var PthreadAttr) {.
importc, header: "<pthread.h>".}
proc pthread_attr_setstacksize(a1: var TPthread_attr, a2: int) {.
proc pthread_attr_setstacksize(a1: var PthreadAttr, a2: int) {.
importc, header: "<pthread.h>".}
proc pthread_create(a1: var TSysThread, a2: var TPthread_attr,
proc pthread_create(a1: var SysThread, a2: var PthreadAttr,
a3: proc (x: pointer): pointer {.noconv.},
a4: pointer): cint {.importc: "pthread_create",
header: "<pthread.h>".}
proc pthread_join(a1: TSysThread, a2: ptr pointer): cint {.
proc pthread_join(a1: SysThread, a2: ptr pointer): cint {.
importc, header: "<pthread.h>".}
proc pthread_cancel(a1: TSysThread): cint {.
proc pthread_cancel(a1: SysThread): cint {.
importc: "pthread_cancel", header: "<pthread.h>".}
type
TThreadVarSlot {.importc: "pthread_key_t", pure, final,
ThreadVarSlot {.importc: "pthread_key_t", pure, final,
header: "<sys/types.h>".} = object
{.deprecated: [TThreadVarSlot: ThreadVarSlot].}
proc pthread_getspecific(a1: TThreadVarSlot): pointer {.
proc pthread_getspecific(a1: ThreadVarSlot): pointer {.
importc: "pthread_getspecific", header: "<pthread.h>".}
proc pthread_key_create(a1: ptr TThreadVarSlot,
proc pthread_key_create(a1: ptr ThreadVarSlot,
destruct: proc (x: pointer) {.noconv.}): int32 {.
importc: "pthread_key_create", header: "<pthread.h>".}
proc pthread_key_delete(a1: TThreadVarSlot): int32 {.
proc pthread_key_delete(a1: ThreadVarSlot): int32 {.
importc: "pthread_key_delete", header: "<pthread.h>".}
proc pthread_setspecific(a1: TThreadVarSlot, a2: pointer): int32 {.
proc pthread_setspecific(a1: ThreadVarSlot, a2: pointer): int32 {.
importc: "pthread_setspecific", header: "<pthread.h>".}
proc threadVarAlloc(): TThreadVarSlot {.inline.} =
proc threadVarAlloc(): ThreadVarSlot {.inline.} =
discard pthread_key_create(addr(result), nil)
proc threadVarSetValue(s: TThreadVarSlot, value: pointer) {.inline.} =
proc threadVarSetValue(s: ThreadVarSlot, value: pointer) {.inline.} =
discard pthread_setspecific(s, value)
proc threadVarGetValue(s: TThreadVarSlot): pointer {.inline.} =
proc threadVarGetValue(s: ThreadVarSlot): pointer {.inline.} =
result = pthread_getspecific(s)
when useStackMaskHack:
proc pthread_attr_setstack(attr: var TPthread_attr, stackaddr: pointer,
proc pthread_attr_setstack(attr: var PthreadAttr, stackaddr: pointer,
size: int): cint {.
importc: "pthread_attr_setstack", header: "<pthread.h>".}
@ -175,13 +179,13 @@ when emulatedThreadVars:
# allocations are needed. Currently less than 7K are used on a 64bit machine.
# We use ``float`` for proper alignment:
type
TThreadLocalStorage = array [0..1_000, float]
ThreadLocalStorage = array [0..1_000, float]
PGcThread = ptr TGcThread
TGcThread {.pure, inheritable.} = object
sys: TSysThread
PGcThread = ptr GcThread
GcThread {.pure, inheritable.} = object
sys: SysThread
when emulatedThreadVars and not useStackMaskHack:
tls: TThreadLocalStorage
tls: ThreadLocalStorage
else:
nil
when hasSharedHeap:
@ -190,15 +194,16 @@ type
stackSize: int
else:
nil
{.deprecated: [TThreadLocalStorage: ThreadLocalStorage, TGcThread: GcThread].}
# XXX it'd be more efficient to not use a global variable for the
# thread storage slot, but to rely on the implementation to assign slot X
# for us... ;-)
var globalsSlot: TThreadVarSlot
var globalsSlot: ThreadVarSlot
when not defined(useNimRtl):
when not useStackMaskHack:
var mainThread: TGcThread
var mainThread: GcThread
proc initThreadVarsEmulation() {.compilerProc, inline.} =
when not defined(useNimRtl):
@ -206,7 +211,7 @@ proc initThreadVarsEmulation() {.compilerProc, inline.} =
when declared(mainThread):
threadVarSetValue(globalsSlot, addr(mainThread))
#const globalsSlot = TThreadVarSlot(0)
#const globalsSlot = ThreadVarSlot(0)
#sysAssert checkSlot.int == globalsSlot.int
when emulatedThreadVars:
@ -228,7 +233,7 @@ when not defined(useNimRtl):
initGC()
when emulatedThreadVars:
if nimThreadVarsSize() > sizeof(TThreadLocalStorage):
if nimThreadVarsSize() > sizeof(ThreadLocalStorage):
echo "too large thread local storage size requested"
quit 1
@ -269,26 +274,27 @@ when not defined(useNimRtl):
# use ``stdcall`` since it is mapped to ``noconv`` on UNIX anyway.
type
TThread* {.pure, final.}[TArg] =
object of TGcThread ## Nim thread. A thread is a heavy object (~14K)
Thread* {.pure, final.}[TArg] =
object of GcThread ## Nim thread. A thread is a heavy object (~14K)
## that **must not** be part of a message! Use
## a ``TThreadId`` for that.
## a ``ThreadId`` for that.
when TArg is void:
dataFn: proc () {.nimcall, gcsafe.}
else:
dataFn: proc (m: TArg) {.nimcall, gcsafe.}
data: TArg
TThreadId*[TArg] = ptr TThread[TArg] ## the current implementation uses
ThreadId*[TArg] = ptr Thread[TArg] ## the current implementation uses
## a pointer as a thread ID.
{.deprecated: [TThread: Thread, TThreadId: ThreadId].}
when not defined(boehmgc) and not hasSharedHeap:
proc deallocOsPages()
template threadProcWrapperBody(closure: expr) {.immediate.} =
when declared(globalsSlot): threadVarSetValue(globalsSlot, closure)
var t = cast[ptr TThread[TArg]](closure)
var t = cast[ptr Thread[TArg]](closure)
when useStackMaskHack:
var tls: TThreadLocalStorage
var tls: ThreadLocalStorage
when not defined(boehmgc) and not defined(nogc) and not hasSharedHeap:
# init the GC for this thread:
setStackBottom(addr(t))
@ -319,35 +325,35 @@ else:
threadProcWrapperBody(closure)
{.pop.}
proc running*[TArg](t: TThread[TArg]): bool {.inline.} =
proc running*[TArg](t: Thread[TArg]): bool {.inline.} =
## returns true if `t` is running.
result = t.dataFn != nil
when hostOS == "windows":
proc joinThread*[TArg](t: TThread[TArg]) {.inline.} =
proc joinThread*[TArg](t: Thread[TArg]) {.inline.} =
## waits for the thread `t` to finish.
discard waitForSingleObject(t.sys, -1'i32)
proc joinThreads*[TArg](t: varargs[TThread[TArg]]) =
proc joinThreads*[TArg](t: varargs[Thread[TArg]]) =
## waits for every thread in `t` to finish.
var a: array[0..255, TSysThread]
var a: array[0..255, SysThread]
sysAssert a.len >= t.len, "a.len >= t.len"
for i in 0..t.high: a[i] = t[i].sys
discard waitForMultipleObjects(t.len.int32,
cast[ptr TSysThread](addr(a)), 1, -1)
cast[ptr SysThread](addr(a)), 1, -1)
else:
proc joinThread*[TArg](t: TThread[TArg]) {.inline.} =
proc joinThread*[TArg](t: Thread[TArg]) {.inline.} =
## waits for the thread `t` to finish.
discard pthread_join(t.sys, nil)
proc joinThreads*[TArg](t: varargs[TThread[TArg]]) =
proc joinThreads*[TArg](t: varargs[Thread[TArg]]) =
## waits for every thread in `t` to finish.
for i in 0..t.high: joinThread(t[i])
when false:
# XXX a thread should really release its heap here somehow:
proc destroyThread*[TArg](t: var TThread[TArg]) =
proc destroyThread*[TArg](t: var Thread[TArg]) =
## forces the thread `t` to terminate. This is potentially dangerous if
## you don't have full control over `t` and its acquired resources.
when hostOS == "windows":
@ -358,7 +364,7 @@ when false:
t.dataFn = nil
when hostOS == "windows":
proc createThread*[TArg](t: var TThread[TArg],
proc createThread*[TArg](t: var Thread[TArg],
tp: proc (arg: TArg) {.thread.},
param: TArg) =
## creates a new thread `t` and starts its execution. Entry point is the
@ -373,7 +379,7 @@ when hostOS == "windows":
if t.sys <= 0:
raise newException(ResourceExhaustedError, "cannot create thread")
else:
proc createThread*[TArg](t: var TThread[TArg],
proc createThread*[TArg](t: var Thread[TArg],
tp: proc (arg: TArg) {.thread.},
param: TArg) =
## creates a new thread `t` and starts its execution. Entry point is the
@ -382,29 +388,29 @@ else:
when TArg isnot void: t.data = param
t.dataFn = tp
when hasSharedHeap: t.stackSize = ThreadStackSize
var a {.noinit.}: Tpthread_attr
var a {.noinit.}: PthreadAttr
pthread_attr_init(a)
pthread_attr_setstacksize(a, ThreadStackSize)
if pthread_create(t.sys, a, threadProcWrapper[TArg], addr(t)) != 0:
raise newException(ResourceExhaustedError, "cannot create thread")
proc threadId*[TArg](t: var TThread[TArg]): TThreadId[TArg] {.inline.} =
proc threadId*[TArg](t: var Thread[TArg]): ThreadId[TArg] {.inline.} =
## returns the thread ID of `t`.
result = addr(t)
proc myThreadId*[TArg](): TThreadId[TArg] =
proc myThreadId*[TArg](): ThreadId[TArg] =
## returns the thread ID of the thread that calls this proc. This is unsafe
## because the type ``TArg`` is not checked for consistency!
result = cast[TThreadId[TArg]](threadVarGetValue(globalsSlot))
result = cast[ThreadId[TArg]](threadVarGetValue(globalsSlot))
when false:
proc mainThreadId*[TArg](): TThreadId[TArg] =
proc mainThreadId*[TArg](): ThreadId[TArg] =
## returns the thread ID of the main thread.
result = cast[TThreadId[TArg]](addr(mainThread))
result = cast[ThreadId[TArg]](addr(mainThread))
when useStackMaskHack:
proc runMain(tp: proc () {.thread.}) {.compilerproc.} =
var mainThread: TThread[pointer]
var mainThread: Thread[pointer]
createThread(mainThread, tp)
joinThread(mainThread)

View file

@ -11,83 +11,86 @@
## `<https://github.com/jckarter/clay/blob/master/compiler/src/hirestimer.cpp>`_
type
TTicks = distinct int64
TNanos = int64
Ticks = distinct int64
Nanos = int64
{.deprecated: [TTicks: Ticks, TNanos: Nanos].}
when defined(windows):
proc QueryPerformanceCounter(res: var TTicks) {.
proc QueryPerformanceCounter(res: var Ticks) {.
importc: "QueryPerformanceCounter", stdcall, dynlib: "kernel32".}
proc QueryPerformanceFrequency(res: var int64) {.
importc: "QueryPerformanceFrequency", stdcall, dynlib: "kernel32".}
proc getTicks(): TTicks {.inline.} =
proc getTicks(): Ticks {.inline.} =
QueryPerformanceCounter(result)
proc `-`(a, b: TTicks): TNanos =
proc `-`(a, b: Ticks): Nanos =
var frequency: int64
QueryPerformanceFrequency(frequency)
var performanceCounterRate = 1e+9'f64 / float64(frequency)
result = TNanos(float64(a.int64 - b.int64) * performanceCounterRate)
result = Nanos(float64(a.int64 - b.int64) * performanceCounterRate)
elif defined(macosx):
type
TMachTimebaseInfoData {.pure, final,
MachTimebaseInfoData {.pure, final,
importc: "mach_timebase_info_data_t",
header: "<mach/mach_time.h>".} = object
numer, denom: int32
{.deprecated: [TMachTimebaseInfoData: MachTimebaseInfoData].}
proc mach_absolute_time(): int64 {.importc, header: "<mach/mach.h>".}
proc mach_timebase_info(info: var TMachTimebaseInfoData) {.importc,
proc mach_timebase_info(info: var MachTimebaseInfoData) {.importc,
header: "<mach/mach_time.h>".}
proc getTicks(): TTicks {.inline.} =
result = TTicks(mach_absolute_time())
proc getTicks(): Ticks {.inline.} =
result = Ticks(mach_absolute_time())
var timeBaseInfo: TMachTimebaseInfoData
var timeBaseInfo: MachTimebaseInfoData
mach_timebase_info(timeBaseInfo)
proc `-`(a, b: TTicks): TNanos =
proc `-`(a, b: Ticks): Nanos =
result = (a.int64 - b.int64) * timeBaseInfo.numer div timeBaseInfo.denom
elif defined(posixRealtime):
type
TClockid {.importc: "clockid_t", header: "<time.h>", final.} = object
Clockid {.importc: "clockid_t", header: "<time.h>", final.} = object
TTimeSpec {.importc: "struct timespec", header: "<time.h>",
TimeSpec {.importc: "struct timespec", header: "<time.h>",
final, pure.} = object ## struct timespec
tv_sec: int ## Seconds.
tv_nsec: int ## Nanoseconds.
{.deprecated: [TClockid: Clickid, TTimeSpec: TimeSpec].}
var
CLOCK_REALTIME {.importc: "CLOCK_REALTIME", header: "<time.h>".}: TClockid
CLOCK_REALTIME {.importc: "CLOCK_REALTIME", header: "<time.h>".}: Clockid
proc clock_gettime(clkId: TClockid, tp: var TTimespec) {.
proc clock_gettime(clkId: Clockid, tp: var Timespec) {.
importc: "clock_gettime", header: "<time.h>".}
proc getTicks(): TTicks =
var t: TTimespec
proc getTicks(): Ticks =
var t: Timespec
clock_gettime(CLOCK_REALTIME, t)
result = TTicks(int64(t.tv_sec) * 1000000000'i64 + int64(t.tv_nsec))
result = Ticks(int64(t.tv_sec) * 1000000000'i64 + int64(t.tv_nsec))
proc `-`(a, b: TTicks): TNanos {.borrow.}
proc `-`(a, b: Ticks): Nanos {.borrow.}
else:
# fallback Posix implementation:
type
Ttimeval {.importc: "struct timeval", header: "<sys/select.h>",
Timeval {.importc: "struct timeval", header: "<sys/select.h>",
final, pure.} = object ## struct timeval
tv_sec: int ## Seconds.
tv_usec: int ## Microseconds.
proc posix_gettimeofday(tp: var Ttimeval, unused: pointer = nil) {.
{.deprecated: [Ttimeval: Timeval].}
proc posix_gettimeofday(tp: var Timeval, unused: pointer = nil) {.
importc: "gettimeofday", header: "<sys/time.h>".}
proc getTicks(): TTicks =
var t: Ttimeval
proc getTicks(): Ticks =
var t: Timeval
posix_gettimeofday(t)
result = TTicks(int64(t.tv_sec) * 1000_000_000'i64 +
result = Ticks(int64(t.tv_sec) * 1000_000_000'i64 +
int64(t.tv_usec) * 1000'i64)
proc `-`(a, b: TTicks): TNanos {.borrow.}
proc `-`(a, b: Ticks): Nanos {.borrow.}

View file

@ -14,8 +14,9 @@ when not declared(NimString):
{.error: "You must not import this module explicitly".}
type
TUtf16Char* = distinct int16
WideCString* = ref array[0.. 1_000_000, TUtf16Char]
Utf16Char* = distinct int16
WideCString* = ref array[0.. 1_000_000, Utf16Char]
{.deprecated: [TUtf16Char: Utf16Char].}
proc len*(w: WideCString): int =
## returns the length of a widestring. This traverses the whole string to
@ -23,7 +24,7 @@ proc len*(w: WideCString): int =
while int16(w[result]) != 0'i16: inc result
const
UNI_REPLACEMENT_CHAR = TUtf16Char(0xFFFD'i16)
UNI_REPLACEMENT_CHAR = Utf16Char(0xFFFD'i16)
UNI_MAX_BMP = 0x0000FFFF
UNI_MAX_UTF16 = 0x0010FFFF
UNI_MAX_UTF32 = 0x7FFFFFFF
@ -89,16 +90,16 @@ proc newWideCString*(source: cstring, L: int): WideCString =
if ch >=% UNI_SUR_HIGH_START and ch <=% UNI_SUR_LOW_END:
result[d] = UNI_REPLACEMENT_CHAR
else:
result[d] = TUtf16Char(toU16(ch))
result[d] = Utf16Char(toU16(ch))
elif ch >% UNI_MAX_UTF16:
result[d] = UNI_REPLACEMENT_CHAR
else:
let ch = ch -% halfBase
result[d] = TUtf16Char(toU16((ch shr halfShift) +% UNI_SUR_HIGH_START))
result[d] = Utf16Char(toU16((ch shr halfShift) +% UNI_SUR_HIGH_START))
inc d
result[d] = TUtf16Char(toU16((ch and halfMask) +% UNI_SUR_LOW_START))
result[d] = Utf16Char(toU16((ch and halfMask) +% UNI_SUR_LOW_START))
inc d
result[d] = TUtf16Char(0'i16)
result[d] = Utf16Char(0'i16)
proc newWideCString*(s: cstring): WideCString =
if s.isNil: return nil

View file

@ -29,12 +29,12 @@ import
type
MMRESULT* = uint32
MMVERSION* = uint32
HWAVEOUT* = THandle
HWAVEOUT* = Handle
LPHWAVEOUT* = ptr HWAVEOUT
HWAVEIN* = THandle
HWAVEIN* = Handle
LPHWAVEIN* = ptr HWAVEOUT
HWAVE* = THandle
LPHWAVE* = ptr THandle
HWAVE* = Handle
LPHWAVE* = ptr Handle
LPUINT* = ptr uint32
const
@ -151,7 +151,7 @@ const
CALLBACK_FUNCTION* = 0x00030000
type
HDRVR* = THandle
HDRVR* = Handle
const
DRV_LOAD* = 1
@ -178,7 +178,7 @@ const
DRV_MCI_LAST* = (DRV_RESERVED + 0x00000FFF)
type
PDRVCALLBACK* = proc (hdrvr: THandle, uMsg: uint32, dwUser, dw1, dw2: DWORD){.
PDRVCALLBACK* = proc (hdrvr: Handle, uMsg: uint32, dwUser, dw1, dw2: DWORD){.
stdcall.}
proc sndPlaySoundA*(Name: LPCSTR, flags: uint32): bool{.stdcall,
@ -991,7 +991,6 @@ type
NPMMTIME* = ptr MMTIME
LPMMTIME* = ptr MMTIME
PWAVEHDR* = ptr WAVEHDR
TMMTime* = MMTIME
WAVEHDR* {.final.} = object
lpData*: cstring
dwBufferLength*: DWORD
@ -1002,7 +1001,6 @@ type
lpNext*: PWAVEHDR
reserved*: DWORD
TWAVEHDR* = WAVEHDR
NPWAVEHDR* = ptr WAVEHDR
LPWAVEHDR* = ptr WAVEHDR
WAVEOUTCAPSA* {.final.} = object
@ -1015,7 +1013,6 @@ type
wReserved1*: int16
dwSupport*: DWORD
TWAVEOUTCAPSA* = WAVEOUTCAPSA
PWAVEOUTCAPSA* = ptr WAVEOUTCAPSA
NPWAVEOUTCAPSA* = ptr WAVEOUTCAPSA
LPWAVEOUTCAPSA* = ptr WAVEOUTCAPSA
@ -1032,7 +1029,8 @@ type
PWAVEOUTCAPSW* = ptr WAVEOUTCAPSW
NPWAVEOUTCAPSW* = ptr WAVEOUTCAPSW
LPWAVEOUTCAPSW* = ptr WAVEOUTCAPSW
TWAVEOUTCAPSW* = WAVEOUTCAPSW
{.deprecated: [Twavehdr: Wavehdr, Tmmtime: Mmtime, Twaveoutcapsa: Waveoutcapsa,
Twaveoutcapsw: Waveoutcapsw].}
when defined(UNICODE):
type
@ -1127,10 +1125,10 @@ type
LPWAVEFORMATEX* = ptr WAVEFORMATEX
LPCWAVEFORMATEX* = ptr WAVEFORMATEX
TWAVEFORMATEX* = WAVEFORMATEX
HMIDI* = THandle
HMIDIIN* = THandle
HMIDIOUT* = THandle
HMIDISTRM* = THandle
HMIDI* = Handle
HMIDIIN* = Handle
HMIDIOUT* = Handle
HMIDISTRM* = Handle
LPHMIDI* = ptr HMIDI
LPHMIDIIN* = ptr HMIDIIN
LPHMIDIOUT* = ptr HMIDIOUT
@ -1299,9 +1297,9 @@ else:
LPAUXCAPS* = LPAUXCAPSA
type
TAUXCAPS* = AUXCAPS
HMIXEROBJ* = THandle
HMIXEROBJ* = Handle
LPHMIXEROBJ* = ptr HMIXEROBJ
HMIXER* = THandle
HMIXER* = Handle
LPHMIXER* = ptr HMIXER
proc mixerGetNumDevs*(): uint32{.stdcall, dynlib: "winmm.dll",
@ -1647,7 +1645,7 @@ type
TJOYINFOEX* = JOYINFOEX
FOURCC* = DWORD
HPSTR* = cstring
HMMIO* = THandle
HMMIO* = Handle
LPMMIOPROC* = proc (x1: LPSTR, x2: uint32, x3, x4: LPARAM): LRESULT{.stdcall.}
TMMIOPROC* = LPMMIOPROC
MMIOINFO* {.final.} = object
@ -2096,14 +2094,14 @@ else:
type
MCI_ANIM_RECT_PARMS* {.final.} = object
dwCallback*: DWORD
rc*: TRECT
rc*: RECT
PMCI_ANIM_RECT_PARMS* = ptr MCI_ANIM_RECT_PARMS
LPMCI_ANIM_RECT_PARMS* = ptr MCI_ANIM_RECT_PARMS
TMCI_ANIM_RECT_PARMS* = MCI_ANIM_RECT_PARMS
MCI_ANIM_UPDATE_PARMS* {.final.} = object
dwCallback*: DWORD
rc*: TRECT
rc*: RECT
hDC*: HDC
PMCI_ANIM_UPDATE_PARMS* = ptr MCI_ANIM_UPDATE_PARMS
@ -2179,7 +2177,7 @@ type
TMCI_OVLY_WINDOW_PARMS* = MCI_OVLY_WINDOW_PARMSW
MCI_OVLY_RECT_PARMS* {.final.} = object
dwCallback*: DWORD
rc*: TRECT
rc*: RECT
PMCI_OVLY_RECT_PARMS* = ptr MCI_OVLY_RECT_PARMS
LPMCI_OVLY_RECT_PARMS* = ptr MCI_OVLY_RECT_PARMS
@ -2187,7 +2185,7 @@ type
MCI_OVLY_SAVE_PARMSA* {.final.} = object
dwCallback*: DWORD
lpfilename*: LPCSTR
rc*: TRECT
rc*: RECT
PMCI_OVLY_SAVE_PARMSA* = ptr MCI_OVLY_SAVE_PARMSA
LPMCI_OVLY_SAVE_PARMSA* = ptr MCI_OVLY_SAVE_PARMSA
@ -2195,7 +2193,7 @@ type
MCI_OVLY_SAVE_PARMSW* {.final.} = object
dwCallback*: DWORD
lpfilename*: LPCWSTR
rc*: TRECT
rc*: RECT
PMCI_OVLY_SAVE_PARMSW* = ptr MCI_OVLY_SAVE_PARMSW
LPMCI_OVLY_SAVE_PARMSW* = ptr MCI_OVLY_SAVE_PARMSW
@ -2216,7 +2214,7 @@ type
MCI_OVLY_LOAD_PARMSA* {.final.} = object
dwCallback*: DWORD
lpfilename*: LPCSTR
rc*: TRECT
rc*: RECT
PMCI_OVLY_LOAD_PARMSA* = ptr MCI_OVLY_LOAD_PARMSA
LPMCI_OVLY_LOAD_PARMSA* = ptr MCI_OVLY_LOAD_PARMSA
@ -2224,7 +2222,7 @@ type
MCI_OVLY_LOAD_PARMSW* {.final.} = object
dwCallback*: DWORD
lpfilename*: LPCWSTR
rc*: TRECT
rc*: RECT
PMCI_OVLY_LOAD_PARMSW* = ptr MCI_OVLY_LOAD_PARMSW
LPMCI_OVLY_LOAD_PARMSW* = ptr MCI_OVLY_LOAD_PARMSW

View file

@ -20,9 +20,9 @@ const
MAX_LANA* = 254 # lana's in range 0 to MAX_LANA inclusive
type # Network Control Block
PNCB* = ptr TNCB
TNCBPostProc* = proc (P: PNCB) {.stdcall.}
TNCB* {.final.} = object # Structure returned to the NCB command NCBASTAT is ADAPTER_STATUS followed
PNCB* = ptr NCB
NCBPostProc* = proc (P: PNCB) {.stdcall.}
NCB* {.final.} = object # Structure returned to the NCB command NCBASTAT is ADAPTER_STATUS followed
# by an array of NAME_BUFFER structures.
ncb_command*: char # command code
ncb_retcode*: char # return code
@ -34,17 +34,17 @@ type # Network Control Block
ncb_name*: array[0..NCBNAMSZ - 1, char] # our blank-padded netname
ncb_rto*: char # rcv timeout/retry count
ncb_sto*: char # send timeout/sys timeout
ncb_post*: TNCBPostProc # POST routine address
ncb_post*: NCBPostProc # POST routine address
ncb_lana_num*: char # lana (adapter) number
ncb_cmd_cplt*: char # 0xff => commmand pending
ncb_reserve*: array[0..9, char] # reserved, used by BIOS
ncb_event*: THandle # HANDLE to Win32 event which
ncb_event*: Handle # HANDLE to Win32 event which
# will be set to the signalled
# state when an ASYNCH command
# completes
PAdapterStatus* = ptr TAdapterStatus
TAdapterStatus* {.final.} = object
PAdapterStatus* = ptr AdapterStatus
AdapterStatus* {.final.} = object
adapter_address*: array[0..5, char]
rev_major*: char
reserved0*: char
@ -73,11 +73,13 @@ type # Network Control Block
max_sess_pkt_size*: int16
name_count*: int16
PNameBuffer* = ptr TNameBuffer
TNameBuffer* {.final.} = object
PNameBuffer* = ptr NameBuffer
NameBuffer* {.final.} = object
name*: array[0..NCBNAMSZ - 1, char]
name_num*: char
name_flags*: char
{.deprecated: [TNCB: NCB, TNCBPostProc: NCBPostProc,
TAdapterStatus: AdapterStatus, TNameBuffer: NameBuffer].}
const # values for name_flags bits.
@ -94,21 +96,22 @@ type # Structure returned to the NCB command NCBSSTAT is SESSION_HEADER followed
# by an array of SESSION_BUFFER structures. If the NCB_NAME starts with an
# asterisk then an array of these structures is returned containing the
# status for all names.
PSessionHeader* = ptr TSessionHeader
TSessionHeader* {.final.} = object
PSessionHeader* = ptr SessionHeader
SessionHeader* {.final.} = object
sess_name*: char
num_sess*: char
rcv_dg_outstanding*: char
rcv_any_outstanding*: char
PSessionBuffer* = ptr TSessionBuffer
TSessionBuffer* {.final.} = object
PSessionBuffer* = ptr SessionBuffer
SessionBuffer* {.final.} = object
lsn*: char
state*: char
local_name*: array[0..NCBNAMSZ - 1, char]
remote_name*: array[0..NCBNAMSZ - 1, char]
rcvs_outstanding*: char
sends_outstanding*: char
{.deprecated: [TSessionHeader: SessionHeader, TSessionBuffer: SessionBuffer].}
const # Values for state
@ -128,14 +131,14 @@ type # Structure returned to the NCB command NCBENUM.
len*: char # Number of valid entries in lana[]
lana*: array[0..MAX_LANA, char]
PFindNameHeader* = ptr TFindNameHeader
TFindNameHeader* {.final.} = object
PFindNameHeader* = ptr FindNameHeader
FindNameHeader* {.final.} = object
node_count*: int16
reserved*: char
unique_group*: char
PFindNameBuffer* = ptr TFindNameBuffer
TFindNameBuffer* {.final.} = object # Structure provided with NCBACTION. The purpose of NCBACTION is to provide
PFindNameBuffer* = ptr FindNameBuffer
FindNameBuffer* {.final.} = object # Structure provided with NCBACTION. The purpose of NCBACTION is to provide
# transport specific extensions to netbios.
len*: char
access_control*: char
@ -144,12 +147,13 @@ type # Structure returned to the NCB command NCBENUM.
source_addr*: array[0..5, char]
routing_info*: array[0..17, char]
PActionHeader* = ptr TActionHeader
TActionHeader* {.final.} = object
PActionHeader* = ptr ActionHeader
ActionHeader* {.final.} = object
transport_id*: int32
action_code*: int16
reserved*: int16
{.deprecated: [TFindNameHeader: FindNameHeader, TFindNameBuffer: FindNameBuffer,
TActionHeader: ActionHeader].}
const # Values for transport_id
ALL_TRANSPORTS* = "M\0\0\0"

View file

@ -31,7 +31,7 @@ import
windows
type
HDROP* = THandle
HDROP* = Handle
UINT_PTR* = ptr uint32
DWORD_PTR* = ptr DWORD
PHICON* = ptr HICON
@ -57,8 +57,8 @@ type
hStdError*: HANDLE
LPSTARTUPINFOW* = ptr STARTUPINFOW
TSTARTUPINFOW* = STARTUPINFOW
PSTARTUPINFOW* = ptr STARTUPINFOW #unicode
{.deprecated: [TSTARTUPINFOW: STARTUPINFOW].}
proc DragQueryFileA*(arg1: HDROP, arg2: uint32, arg3: LPSTR, arg4: uint32): uint32{.
stdcall, dynlib: "shell32.dll", importc: "DragQueryFileA".}
@ -132,7 +132,6 @@ type # init with sizeof(DRAGINFO)
lpFileList*: LPSTR
grfKeyState*: DWORD
TDRAGINFOA* = DRAGINFOA
LPDRAGINFOA* = ptr DRAGINFOA # init with sizeof(DRAGINFO)
DRAGINFOW* {.final.} = object
uSize*: uint32
@ -141,19 +140,19 @@ type # init with sizeof(DRAGINFO)
lpFileList*: LPWSTR
grfKeyState*: DWORD
TDRAGINFOW* = DRAGINFOW
LPDRAGINFOW* = ptr DRAGINFOW
{.deprecated: [TDRAGINFOA: DRAGINFOA, TDRAGINFOW: DRAGINFOW].}
when defined(UNICODE):
type
DRAGINFO* = DRAGINFOW
TDRAGINFO* = DRAGINFOW
LPDRAGINFO* = LPDRAGINFOW
{.deprecated: [TDRAGINFO: DRAGINFOW].}
else:
type
DRAGINFO* = DRAGINFOA
TDRAGINFO* = DRAGINFOW
LPDRAGINFO* = LPDRAGINFOA
{.deprecated: [TDRAGINFO: DRAGINFOW].}
const
ABM_NEW* = 0x00000000
ABM_REMOVE* = 0x00000001
@ -189,8 +188,8 @@ type
rc*: RECT
lParam*: LPARAM # message specific
TAPPBARDATA* = AppBarData
PAPPBARDATA* = ptr AppBarData
{.deprecated: [TAPPBARDATA: AppBarData].}
proc SHAppBarMessage*(dwMessage: DWORD, pData: APPBARDATA): UINT_PTR{.stdcall,
dynlib: "shell32.dll", importc: "SHAppBarMessage".}
@ -299,7 +298,6 @@ type
hNameMappings*: LPVOID
lpszProgressTitle*: LPCSTR # only used if FOF_SIMPLEPROGRESS
TSHFILEOPSTRUCTA* = SHFILEOPSTRUCTA
LPSHFILEOPSTRUCTA* = ptr SHFILEOPSTRUCTA
SHFILEOPSTRUCTW* {.final.} = object
hwnd*: HWND
@ -311,19 +309,21 @@ type
hNameMappings*: LPVOID
lpszProgressTitle*: LPCWSTR
TSHFILEOPSTRUCTW* = SHFILEOPSTRUCTW
LPSHFILEOPSTRUCTW* = ptr SHFILEOPSTRUCTW
{.deprecated: [TSHFILEOPSTRUCTA: SHFILEOPSTRUCTA,
TSHFILEOPSTRUCTW: SHFILEOPSTRUCTW].}
when defined(UNICODE):
type
SHFILEOPSTRUCT* = SHFILEOPSTRUCTW
TSHFILEOPSTRUCT* = SHFILEOPSTRUCTW
LPSHFILEOPSTRUCT* = LPSHFILEOPSTRUCTW
{.deprecated: [TSHFILEOPSTRUCT: SHFILEOPSTRUCTW].}
else:
type
SHFILEOPSTRUCT* = SHFILEOPSTRUCTA
TSHFILEOPSTRUCT* = SHFILEOPSTRUCTA
LPSHFILEOPSTRUCT* = LPSHFILEOPSTRUCTA
{.deprecated: [TSHFILEOPSTRUCT: SHFILEOPSTRUCTA].}
proc SHFileOperationA*(lpFileOp: LPSHFILEOPSTRUCTA): int32{.stdcall,
dynlib: "shell32.dll", importc: "SHFileOperationA".}
proc SHFileOperationW*(lpFileOp: LPSHFILEOPSTRUCTW): int32{.stdcall,
@ -332,7 +332,7 @@ proc SHFileOperation*(lpFileOp: LPSHFILEOPSTRUCTA): int32{.stdcall,
dynlib: "shell32.dll", importc: "SHFileOperationA".}
proc SHFileOperation*(lpFileOp: LPSHFILEOPSTRUCTW): int32{.stdcall,
dynlib: "shell32.dll", importc: "SHFileOperationW".}
proc SHFreeNameMappings*(hNameMappings: THandle){.stdcall,
proc SHFreeNameMappings*(hNameMappings: Handle){.stdcall,
dynlib: "shell32.dll", importc: "SHFreeNameMappings".}
type
SHNAMEMAPPINGA* {.final.} = object
@ -341,7 +341,6 @@ type
cchOldPath*: int32
cchNewPath*: int32
TSHNAMEMAPPINGA* = SHNAMEMAPPINGA
LPSHNAMEMAPPINGA* = ptr SHNAMEMAPPINGA
SHNAMEMAPPINGW* {.final.} = object
pszOldPath*: LPWSTR
@ -349,19 +348,20 @@ type
cchOldPath*: int32
cchNewPath*: int32
TSHNAMEMAPPINGW* = SHNAMEMAPPINGW
LPSHNAMEMAPPINGW* = ptr SHNAMEMAPPINGW
{.deprecated: [TSHNAMEMAPPINGA: SHNAMEMAPPINGA,
TSHNAMEMAPPINGW: SHNAMEMAPPINGW].}
when not(defined(UNICODE)):
type
SHNAMEMAPPING* = SHNAMEMAPPINGW
TSHNAMEMAPPING* = SHNAMEMAPPINGW
LPSHNAMEMAPPING* = LPSHNAMEMAPPINGW
{.deprecated: [TSHNAMEMAPPING: SHNAMEMAPPINGW].}
else:
type
SHNAMEMAPPING* = SHNAMEMAPPINGA
TSHNAMEMAPPING* = SHNAMEMAPPINGA
LPSHNAMEMAPPING* = LPSHNAMEMAPPINGA
{.deprecated: [TSHNAMEMAPPING: SHNAMEMAPPINGA].}
#
# End Shell File Operations
#
@ -424,7 +424,6 @@ type
hMonitor*: HANDLE # also: hIcon
hProcess*: HANDLE
TSHELLEXECUTEINFOA* = SHELLEXECUTEINFOA
LPSHELLEXECUTEINFOA* = ptr SHELLEXECUTEINFOA
SHELLEXECUTEINFOW* {.final.} = object
cbSize*: DWORD
@ -443,19 +442,21 @@ type
hMonitor*: HANDLE # also: hIcon
hProcess*: HANDLE
TSHELLEXECUTEINFOW* = SHELLEXECUTEINFOW
LPSHELLEXECUTEINFOW* = ptr SHELLEXECUTEINFOW
{.deprecated: [TSHELLEXECUTEINFOA: SHELLEXECUTEINFOA,
TSHELLEXECUTEINFOW: SHELLEXECUTEINFOW].}
when defined(UNICODE):
type
SHELLEXECUTEINFO* = SHELLEXECUTEINFOW
TSHELLEXECUTEINFO* = SHELLEXECUTEINFOW
LPSHELLEXECUTEINFO* = LPSHELLEXECUTEINFOW
{.deprecated: [TSHELLEXECUTEINFO: SHELLEXECUTEINFOW].}
else:
type
SHELLEXECUTEINFO* = SHELLEXECUTEINFOA
TSHELLEXECUTEINFO* = SHELLEXECUTEINFOA
LPSHELLEXECUTEINFO* = LPSHELLEXECUTEINFOA
{.deprecated: [TSHELLEXECUTEINFO: SHELLEXECUTEINFOA].}
proc ShellExecuteExA*(lpExecInfo: LPSHELLEXECUTEINFOA): bool{.stdcall,
dynlib: "shell32.dll", importc: "ShellExecuteExA".}
proc ShellExecuteExW*(lpExecInfo: LPSHELLEXECUTEINFOW): bool{.stdcall,
@ -492,8 +493,8 @@ type
lpStartupInfo*: LPSTARTUPINFOW
lpProcessInformation*: LPPROCESS_INFORMATION
TSHCREATEPROCESSINFOW* = SHCREATEPROCESSINFOW
PSHCREATEPROCESSINFOW* = ptr SHCREATEPROCESSINFOW
{.deprecated: [TSHCREATEPROCESSINFOW: SHCREATEPROCESSINFOW].}
proc SHCreateProcessAsUserW*(pscpi: PSHCREATEPROCESSINFOW): bool{.stdcall,
dynlib: "shell32.dll", importc: "SHCreateProcessAsUserW".}
@ -510,8 +511,8 @@ type
i64Size*: int64
i64NumItems*: int64
TSHQUERYRBINFO* = SHQUERYRBINFO
LPSHQUERYRBINFO* = ptr SHQUERYRBINFO # flags for SHEmptyRecycleBin
{.deprecated: [TSHQUERYRBINFO: SHQUERYRBINFO].}
const
SHERB_NOCONFIRMATION* = 0x00000001
@ -555,9 +556,8 @@ type
uTimeout*: uint32 # also: uVersion
szInfoTitle*: array[0..63, char]
dwInfoFlags*: DWORD
guidItem*: TGUID
guidItem*: GUID
TNOTIFYICONDATAA* = NOTIFYICONDATAA
PNOTIFYICONDATAA* = ptr NOTIFYICONDATAA
NOTIFYICONDATAW* {.final.} = object
cbSize*: DWORD
@ -573,21 +573,22 @@ type
uTimeout*: uint32 # also uVersion : UINT
szInfoTitle*: array[0..63, char]
dwInfoFlags*: DWORD
guidItem*: TGUID
guidItem*: GUID
TNOTIFYICONDATAW* = NOTIFYICONDATAW
PNOTIFYICONDATAW* = ptr NOTIFYICONDATAW
{.deprecated: [TNOTIFYICONDATAA: NOTIFYICONDATAA,
TNOTIFYICONDATAW: NOTIFYICONDATAW].}
when defined(UNICODE):
type
NOTIFYICONDATA* = NOTIFYICONDATAW
TNOTIFYICONDATA* = NOTIFYICONDATAW
PNOTIFYICONDATA* = PNOTIFYICONDATAW
{.deprecated: [TNOTIFYICONDATA: NOTIFYICONDATAW].}
else:
type
NOTIFYICONDATA* = NOTIFYICONDATAA
TNOTIFYICONDATA* = NOTIFYICONDATAA
PNOTIFYICONDATA* = PNOTIFYICONDATAA
{.deprecated: [TNOTIFYICONDATA: NOTIFYICONDATAA].}
const
NIN_SELECT* = WM_USER + 0
NINF_KEY* = 0x00000001
@ -655,7 +656,6 @@ type
szDisplayName*: array[0..(MAX_PATH) - 1, char] # out: display name (or path)
szTypeName*: array[0..79, char] # out: type name
TSHFILEINFOA* = SHFILEINFOA
PSHFILEINFOA* = ptr SHFILEINFOA
SHFILEINFOW* {.final.} = object
hIcon*: HICON # out: icon
@ -664,19 +664,19 @@ type
szDisplayName*: array[0..(MAX_PATH) - 1, Wchar] # out: display name (or path)
szTypeName*: array[0..79, Wchar] # out: type name
TSHFILEINFOW* = SHFILEINFOW
PSHFILEINFOW* = ptr SHFILEINFOW
{.deprecated: [TSHFILEINFOA: SHFILEINFOA, TSHFILEINFOW: SHFILEINFOW].}
when defined(UNICODE):
type
SHFILEINFO* = SHFILEINFOW
TSHFILEINFO* = SHFILEINFOW
pFILEINFO* = SHFILEINFOW
{.deprecated: [TSHFILEINFO: SHFILEINFOW].}
else:
type
SHFILEINFO* = SHFILEINFOA
TSHFILEINFO* = SHFILEINFOA
pFILEINFO* = SHFILEINFOA
{.deprecated: [TSHFILEINFO: SHFILEINFOA].}
# NOTE: This is also in shlwapi.h. Please keep in synch.
const
@ -710,16 +710,16 @@ proc SHGetFileInfo*(pszPath: LPCSTR, dwFileAttributes: DWORD,
psfi: PSHFILEINFOA, cbFileInfo, UFlags: uint32): DWORD{.
stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoA".}
proc SHGetFileInfoA*(pszPath: LPCSTR, dwFileAttributes: DWORD,
psfi: var TSHFILEINFOA, cbFileInfo, UFlags: uint32): DWORD{.
psfi: var SHFILEINFOA, cbFileInfo, UFlags: uint32): DWORD{.
stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoA".}
proc SHGetFileInfoW*(pszPath: LPCWSTR, dwFileAttributes: DWORD,
psfi: var TSHFILEINFOW, cbFileInfo, UFlags: uint32): DWORD{.
psfi: var SHFILEINFOW, cbFileInfo, UFlags: uint32): DWORD{.
stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoW".}
proc SHGetFileInfo*(pszPath: LPCSTR, dwFileAttributes: DWORD,
psfi: var TSHFILEINFOA, cbFileInfo, UFlags: uint32): DWORD{.
psfi: var SHFILEINFOA, cbFileInfo, UFlags: uint32): DWORD{.
stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoA".}
proc SHGetFileInfo*(pszPath: LPCWSTR, dwFileAttributes: DWORD,
psfi: var TSHFILEINFOW, cbFileInfo, UFlags: uint32): DWORD{.
psfi: var SHFILEINFOW, cbFileInfo, UFlags: uint32): DWORD{.
stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoW".}
proc SHGetDiskFreeSpaceExA*(pszDirectoryName: LPCSTR,
pulFreeBytesAvailableToCaller: PULARGE_INTEGER,

View file

@ -72,22 +72,22 @@ const
CSIDL_FLAG_CREATE* = 0x00008000 # (force creation of requested folder if it doesn't exist yet)
# Original entry points
proc SHGetFolderPathA*(Ahwnd: HWND, Csidl: int, Token: THandle, Flags: DWord,
proc SHGetFolderPathA*(Ahwnd: HWND, Csidl: int, Token: Handle, Flags: DWord,
Path: cstring): HRESULT{.stdcall, dynlib: LibName,
importc: "SHGetFolderPathA".}
proc SHGetFolderPathW*(Ahwnd: HWND, Csidl: int, Token: THandle, Flags: DWord,
proc SHGetFolderPathW*(Ahwnd: HWND, Csidl: int, Token: Handle, Flags: DWord,
Path: cstring): HRESULT{.stdcall, dynlib: LibName,
importc: "SHGetFolderPathW".}
proc SHGetFolderPath*(Ahwnd: HWND, Csidl: int, Token: THandle, Flags: DWord,
proc SHGetFolderPath*(Ahwnd: HWND, Csidl: int, Token: Handle, Flags: DWord,
Path: cstring): HRESULT{.stdcall, dynlib: LibName,
importc: "SHGetFolderPathA".}
type
PFNSHGetFolderPathA* = proc (Ahwnd: HWND, Csidl: int, Token: THandle,
PFNSHGetFolderPathA* = proc (Ahwnd: HWND, Csidl: int, Token: Handle,
Flags: DWord, Path: cstring): HRESULT{.stdcall.}
PFNSHGetFolderPathW* = proc (Ahwnd: HWND, Csidl: int, Token: THandle,
PFNSHGetFolderPathW* = proc (Ahwnd: HWND, Csidl: int, Token: Handle,
Flags: DWord, Path: cstring): HRESULT{.stdcall.}
PFNSHGetFolderPath* = PFNSHGetFolderPathA
TSHGetFolderPathA* = PFNSHGetFolderPathA
TSHGetFolderPathW* = PFNSHGetFolderPathW
TSHGetFolderPath* = TSHGetFolderPathA
{.deprecated: [TSHGetFolderPathA: PFNSHGetFolderPathA,
TSHGetFolderPathW: PFNSHGetFolderPathW,
TSHGetFolderPath: SHGetFolderPathA].}

File diff suppressed because it is too large Load diff

View file

@ -16,7 +16,7 @@ const
useWinUnicode* = not defined(useWinAnsi)
type
THandle* = int
Handle* = int
LONG* = int32
ULONG* = int
PULONG* = ptr int
@ -24,15 +24,15 @@ type
DWORD* = int32
PDWORD* = ptr DWORD
LPINT* = ptr int32
HDC* = THandle
HGLRC* = THandle
HDC* = Handle
HGLRC* = Handle
TSECURITY_ATTRIBUTES* {.final, pure.} = object
SECURITY_ATTRIBUTES* {.final, pure.} = object
nLength*: int32
lpSecurityDescriptor*: pointer
bInheritHandle*: WINBOOL
TSTARTUPINFO* {.final, pure.} = object
STARTUPINFO* {.final, pure.} = object
cb*: int32
lpReserved*: cstring
lpDesktop*: cstring
@ -48,25 +48,25 @@ type
wShowWindow*: int16
cbReserved2*: int16
lpReserved2*: pointer
hStdInput*: THandle
hStdOutput*: THandle
hStdError*: THandle
hStdInput*: Handle
hStdOutput*: Handle
hStdError*: Handle
TPROCESS_INFORMATION* {.final, pure.} = object
hProcess*: THandle
hThread*: THandle
PROCESS_INFORMATION* {.final, pure.} = object
hProcess*: Handle
hThread*: Handle
dwProcessId*: int32
dwThreadId*: int32
TFILETIME* {.final, pure.} = object ## CANNOT BE int64 BECAUSE OF ALIGNMENT
FILETIME* {.final, pure.} = object ## CANNOT BE int64 BECAUSE OF ALIGNMENT
dwLowDateTime*: DWORD
dwHighDateTime*: DWORD
TBY_HANDLE_FILE_INFORMATION* {.final, pure.} = object
BY_HANDLE_FILE_INFORMATION* {.final, pure.} = object
dwFileAttributes*: DWORD
ftCreationTime*: TFILETIME
ftLastAccessTime*: TFILETIME
ftLastWriteTime*: TFILETIME
ftCreationTime*: FILETIME
ftLastAccessTime*: FILETIME
ftLastWriteTime*: FILETIME
dwVolumeSerialNumber*: DWORD
nFileSizeHigh*: DWORD
nFileSizeLow*: DWORD
@ -74,10 +74,16 @@ type
nFileIndexHigh*: DWORD
nFileIndexLow*: DWORD
{.deprecated: [THandle: Handle, TSECURITY_ATTRIBUTES: SECURITY_ATTRIBUTES,
TSTARTUPINFO: STARTUPINFO, TPROCESS_INFORMATION: PROCESS_INFORMATION,
TFILETIME: FILETIME, TBY_HANDLE_FILE_INFORMATION: BY_HANDLE_FILE_INFORMATION].}
when useWinUnicode:
type TWinChar* = TUtf16Char
type WinChar* = Utf16Char
{.deprecated: [TWinChar: WinChar].}
else:
type TWinChar* = char
type WinChar* = char
{.deprecated: [TWinChar: WinChar].}
const
STARTF_USESHOWWINDOW* = 1'i32
@ -98,67 +104,67 @@ const
DETACHED_PROCESS* = 8'i32
SW_SHOWNORMAL* = 1'i32
INVALID_HANDLE_VALUE* = THandle(-1)
INVALID_HANDLE_VALUE* = Handle(-1)
CREATE_UNICODE_ENVIRONMENT* = 1024'i32
proc closeHandle*(hObject: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
proc closeHandle*(hObject: Handle): WINBOOL {.stdcall, dynlib: "kernel32",
importc: "CloseHandle".}
proc readFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToRead: int32,
proc readFile*(hFile: Handle, Buffer: pointer, nNumberOfBytesToRead: int32,
lpNumberOfBytesRead: ptr int32, lpOverlapped: pointer): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "ReadFile".}
proc writeFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToWrite: int32,
proc writeFile*(hFile: Handle, Buffer: pointer, nNumberOfBytesToWrite: int32,
lpNumberOfBytesWritten: ptr int32,
lpOverlapped: pointer): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "WriteFile".}
proc createPipe*(hReadPipe, hWritePipe: var THandle,
lpPipeAttributes: var TSECURITY_ATTRIBUTES,
proc createPipe*(hReadPipe, hWritePipe: var Handle,
lpPipeAttributes: var SECURITY_ATTRIBUTES,
nSize: int32): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "CreatePipe".}
when useWinUnicode:
proc createProcessW*(lpApplicationName, lpCommandLine: WideCString,
lpProcessAttributes: ptr TSECURITY_ATTRIBUTES,
lpThreadAttributes: ptr TSECURITY_ATTRIBUTES,
lpProcessAttributes: ptr SECURITY_ATTRIBUTES,
lpThreadAttributes: ptr SECURITY_ATTRIBUTES,
bInheritHandles: WINBOOL, dwCreationFlags: int32,
lpEnvironment, lpCurrentDirectory: WideCString,
lpStartupInfo: var TSTARTUPINFO,
lpProcessInformation: var TPROCESS_INFORMATION): WINBOOL{.
lpStartupInfo: var STARTUPINFO,
lpProcessInformation: var PROCESS_INFORMATION): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "CreateProcessW".}
else:
proc createProcessA*(lpApplicationName, lpCommandLine: cstring,
lpProcessAttributes: ptr TSECURITY_ATTRIBUTES,
lpThreadAttributes: ptr TSECURITY_ATTRIBUTES,
lpProcessAttributes: ptr SECURITY_ATTRIBUTES,
lpThreadAttributes: ptr SECURITY_ATTRIBUTES,
bInheritHandles: WINBOOL, dwCreationFlags: int32,
lpEnvironment: pointer, lpCurrentDirectory: cstring,
lpStartupInfo: var TSTARTUPINFO,
lpProcessInformation: var TPROCESS_INFORMATION): WINBOOL{.
lpStartupInfo: var STARTUPINFO,
lpProcessInformation: var PROCESS_INFORMATION): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "CreateProcessA".}
proc suspendThread*(hThread: THandle): int32 {.stdcall, dynlib: "kernel32",
proc suspendThread*(hThread: Handle): int32 {.stdcall, dynlib: "kernel32",
importc: "SuspendThread".}
proc resumeThread*(hThread: THandle): int32 {.stdcall, dynlib: "kernel32",
proc resumeThread*(hThread: Handle): int32 {.stdcall, dynlib: "kernel32",
importc: "ResumeThread".}
proc waitForSingleObject*(hHandle: THandle, dwMilliseconds: int32): int32 {.
proc waitForSingleObject*(hHandle: Handle, dwMilliseconds: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".}
proc terminateProcess*(hProcess: THandle, uExitCode: int): WINBOOL {.stdcall,
proc terminateProcess*(hProcess: Handle, uExitCode: int): WINBOOL {.stdcall,
dynlib: "kernel32", importc: "TerminateProcess".}
proc getExitCodeProcess*(hProcess: THandle, lpExitCode: var int32): WINBOOL {.
proc getExitCodeProcess*(hProcess: Handle, lpExitCode: var int32): WINBOOL {.
stdcall, dynlib: "kernel32", importc: "GetExitCodeProcess".}
proc getStdHandle*(nStdHandle: int32): THandle {.stdcall, dynlib: "kernel32",
proc getStdHandle*(nStdHandle: int32): Handle {.stdcall, dynlib: "kernel32",
importc: "GetStdHandle".}
proc setStdHandle*(nStdHandle: int32, hHandle: THandle): WINBOOL {.stdcall,
proc setStdHandle*(nStdHandle: int32, hHandle: Handle): WINBOOL {.stdcall,
dynlib: "kernel32", importc: "SetStdHandle".}
proc flushFileBuffers*(hFile: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
proc flushFileBuffers*(hFile: Handle): WINBOOL {.stdcall, dynlib: "kernel32",
importc: "FlushFileBuffers".}
proc getLastError*(): int32 {.importc: "GetLastError",
@ -193,7 +199,7 @@ when useWinUnicode:
proc setEnvironmentVariableW*(lpName, lpValue: WideCString): int32 {.
stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableW".}
proc getModuleFileNameW*(handle: THandle, buf: WideCString,
proc getModuleFileNameW*(handle: Handle, buf: WideCString,
size: int32): int32 {.importc: "GetModuleFileNameW",
dynlib: "kernel32", stdcall.}
else:
@ -208,7 +214,7 @@ else:
proc setEnvironmentVariableA*(lpName, lpValue: cstring): int32 {.
stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableA".}
proc getModuleFileNameA*(handle: THandle, buf: cstring, size: int32): int32 {.
proc getModuleFileNameA*(handle: Handle, buf: cstring, size: int32): int32 {.
importc: "GetModuleFileNameA", dynlib: "kernel32", stdcall.}
when useWinUnicode:
@ -239,34 +245,35 @@ const
MAX_PATH* = 260
type
TWIN32_FIND_DATA* {.pure.} = object
WIN32_FIND_DATA* {.pure.} = object
dwFileAttributes*: int32
ftCreationTime*: TFILETIME
ftLastAccessTime*: TFILETIME
ftLastWriteTime*: TFILETIME
ftCreationTime*: FILETIME
ftLastAccessTime*: FILETIME
ftLastWriteTime*: FILETIME
nFileSizeHigh*: int32
nFileSizeLow*: int32
dwReserved0: int32
dwReserved1: int32
cFileName*: array[0..(MAX_PATH) - 1, TWinChar]
cAlternateFileName*: array[0..13, TWinChar]
cFileName*: array[0..(MAX_PATH) - 1, WinChar]
cAlternateFileName*: array[0..13, WinChar]
{.deprecated: [TWIN32_FIND_DATA: WIN32_FIND_DATA].}
when useWinUnicode:
proc findFirstFileW*(lpFileName: WideCString,
lpFindFileData: var TWIN32_FIND_DATA): THandle {.
lpFindFileData: var WIN32_FIND_DATA): Handle {.
stdcall, dynlib: "kernel32", importc: "FindFirstFileW".}
proc findNextFileW*(hFindFile: THandle,
lpFindFileData: var TWIN32_FIND_DATA): int32 {.
proc findNextFileW*(hFindFile: Handle,
lpFindFileData: var WIN32_FIND_DATA): int32 {.
stdcall, dynlib: "kernel32", importc: "FindNextFileW".}
else:
proc findFirstFileA*(lpFileName: cstring,
lpFindFileData: var TWIN32_FIND_DATA): THANDLE {.
lpFindFileData: var WIN32_FIND_DATA): THANDLE {.
stdcall, dynlib: "kernel32", importc: "FindFirstFileA".}
proc findNextFileA*(hFindFile: THANDLE,
lpFindFileData: var TWIN32_FIND_DATA): int32 {.
lpFindFileData: var WIN32_FIND_DATA): int32 {.
stdcall, dynlib: "kernel32", importc: "FindNextFileA".}
proc findClose*(hFindFile: THandle) {.stdcall, dynlib: "kernel32",
proc findClose*(hFindFile: Handle) {.stdcall, dynlib: "kernel32",
importc: "FindClose".}
when useWinUnicode:
@ -326,32 +333,32 @@ else:
proc getCommandLineA*(): cstring {.
importc: "GetCommandLineA", stdcall, dynlib: "kernel32".}
proc rdFileTime*(f: TFILETIME): int64 =
proc rdFileTime*(f: FILETIME): int64 =
result = ze64(f.dwLowDateTime) or (ze64(f.dwHighDateTime) shl 32)
proc rdFileSize*(f: TWIN32_FIND_DATA): int64 =
proc rdFileSize*(f: WIN32_FIND_DATA): int64 =
result = ze64(f.nFileSizeLow) or (ze64(f.nFileSizeHigh) shl 32)
proc getSystemTimeAsFileTime*(lpSystemTimeAsFileTime: var TFILETIME) {.
proc getSystemTimeAsFileTime*(lpSystemTimeAsFileTime: var FILETIME) {.
importc: "GetSystemTimeAsFileTime", dynlib: "kernel32", stdcall.}
proc sleep*(dwMilliseconds: int32){.stdcall, dynlib: "kernel32",
importc: "Sleep".}
when useWinUnicode:
proc shellExecuteW*(HWND: THandle, lpOperation, lpFile,
proc shellExecuteW*(HWND: Handle, lpOperation, lpFile,
lpParameters, lpDirectory: WideCString,
nShowCmd: int32): THandle{.
nShowCmd: int32): Handle{.
stdcall, dynlib: "shell32.dll", importc: "ShellExecuteW".}
else:
proc shellExecuteA*(HWND: THandle, lpOperation, lpFile,
proc shellExecuteA*(HWND: Handle, lpOperation, lpFile,
lpParameters, lpDirectory: cstring,
nShowCmd: int32): THandle{.
nShowCmd: int32): Handle{.
stdcall, dynlib: "shell32.dll", importc: "ShellExecuteA".}
proc getFileInformationByHandle*(hFile: THandle,
lpFileInformation: ptr TBY_HANDLE_FILE_INFORMATION): WINBOOL{.
proc getFileInformationByHandle*(hFile: Handle,
lpFileInformation: ptr BY_HANDLE_FILE_INFORMATION): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "GetFileInformationByHandle".}
const
@ -374,7 +381,6 @@ proc wsaGetLastError*(): cint {.importc: "WSAGetLastError", dynlib: ws2dll.}
type
SocketHandle* = distinct int
{.deprecated: [TSocketHandle: SocketHandle].}
type
@ -451,7 +457,6 @@ type
ai_next*: ptr AddrInfo ## Pointer to next in list.
SockLen* = cuint
{.deprecated: [TSockaddr_in: Sockaddr_in, TAddrinfo: AddrInfo,
TSockAddr: SockAddr, TSockLen: SockLen, TTimeval: Timeval,
TWSADATA: WSADATA, Thostent: Hostent, TServent: Servent,
@ -571,8 +576,9 @@ const
MAXIMUM_WAIT_OBJECTS* = 0x00000040
type
TWOHandleArray* = array[0..MAXIMUM_WAIT_OBJECTS - 1, THandle]
PWOHandleArray* = ptr TWOHandleArray
WOHandleArray* = array[0..MAXIMUM_WAIT_OBJECTS - 1, Handle]
PWOHandleArray* = ptr WOHandleArray
{.deprecated: [TWOHandleArray: WOHandleArray].}
proc waitForMultipleObjects*(nCount: DWORD, lpHandles: PWOHandleArray,
bWaitAll: WINBOOL, dwMilliseconds: DWORD): DWORD{.
@ -613,7 +619,7 @@ when useWinUnicode:
proc createFileW*(lpFileName: WideCString, dwDesiredAccess, dwShareMode: DWORD,
lpSecurityAttributes: pointer,
dwCreationDisposition, dwFlagsAndAttributes: DWORD,
hTemplateFile: THandle): THandle {.
hTemplateFile: Handle): Handle {.
stdcall, dynlib: "kernel32", importc: "CreateFileW".}
proc deleteFileW*(pathName: WideCString): int32 {.
importc: "DeleteFileW", dynlib: "kernel32", stdcall.}
@ -626,28 +632,28 @@ else:
proc deleteFileA*(pathName: cstring): int32 {.
importc: "DeleteFileA", dynlib: "kernel32", stdcall.}
proc setEndOfFile*(hFile: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
proc setEndOfFile*(hFile: Handle): WINBOOL {.stdcall, dynlib: "kernel32",
importc: "SetEndOfFile".}
proc setFilePointer*(hFile: THandle, lDistanceToMove: LONG,
proc setFilePointer*(hFile: Handle, lDistanceToMove: LONG,
lpDistanceToMoveHigh: ptr LONG,
dwMoveMethod: DWORD): DWORD {.
stdcall, dynlib: "kernel32", importc: "SetFilePointer".}
proc getFileSize*(hFile: THandle, lpFileSizeHigh: ptr DWORD): DWORD{.stdcall,
proc getFileSize*(hFile: Handle, lpFileSizeHigh: ptr DWORD): DWORD{.stdcall,
dynlib: "kernel32", importc: "GetFileSize".}
proc mapViewOfFileEx*(hFileMappingObject: THandle, dwDesiredAccess: DWORD,
proc mapViewOfFileEx*(hFileMappingObject: Handle, dwDesiredAccess: DWORD,
dwFileOffsetHigh, dwFileOffsetLow: DWORD,
dwNumberOfBytesToMap: DWORD,
lpBaseAddress: pointer): pointer{.
stdcall, dynlib: "kernel32", importc: "MapViewOfFileEx".}
proc createFileMappingW*(hFile: THandle,
proc createFileMappingW*(hFile: Handle,
lpFileMappingAttributes: pointer,
flProtect, dwMaximumSizeHigh: DWORD,
dwMaximumSizeLow: DWORD,
lpName: pointer): THandle {.
lpName: pointer): Handle {.
stdcall, dynlib: "kernel32", importc: "CreateFileMappingW".}
when not useWinUnicode:
@ -661,46 +667,48 @@ proc unmapViewOfFile*(lpBaseAddress: pointer): WINBOOL {.stdcall,
dynlib: "kernel32", importc: "UnmapViewOfFile".}
type
TOVERLAPPED* {.pure, inheritable.} = object
OVERLAPPED* {.pure, inheritable.} = object
internal*: PULONG
internalHigh*: PULONG
offset*: DWORD
offsetHigh*: DWORD
hEvent*: THandle
hEvent*: Handle
POVERLAPPED* = ptr TOVERLAPPED
POVERLAPPED* = ptr OVERLAPPED
POVERLAPPED_COMPLETION_ROUTINE* = proc (para1: DWORD, para2: DWORD,
para3: POVERLAPPED){.stdcall.}
TGUID* {.final, pure.} = object
GUID* {.final, pure.} = object
D1*: int32
D2*: int16
D3*: int16
D4*: array [0..7, int8]
{.deprecated: [TOVERLAPPED: OVERLAPPED, TGUID: GUID].}
const
ERROR_IO_PENDING* = 997 # a.k.a WSA_IO_PENDING
FILE_FLAG_OVERLAPPED* = 1073741824
WSAECONNABORTED* = 10053
WSAEADDRINUSE* = 10048
WSAECONNRESET* = 10054
WSAEDISCON* = 10101
WSAENETRESET* = 10052
WSAETIMEDOUT* = 10060
ERROR_NETNAME_DELETED* = 64
proc createIoCompletionPort*(FileHandle: THandle, ExistingCompletionPort: THandle,
proc createIoCompletionPort*(FileHandle: Handle, ExistingCompletionPort: Handle,
CompletionKey: DWORD,
NumberOfConcurrentThreads: DWORD): THandle{.stdcall,
NumberOfConcurrentThreads: DWORD): Handle{.stdcall,
dynlib: "kernel32", importc: "CreateIoCompletionPort".}
proc getQueuedCompletionStatus*(CompletionPort: THandle,
proc getQueuedCompletionStatus*(CompletionPort: Handle,
lpNumberOfBytesTransferred: PDWORD, lpCompletionKey: PULONG,
lpOverlapped: ptr POVERLAPPED,
dwMilliseconds: DWORD): WINBOOL{.stdcall,
dynlib: "kernel32", importc: "GetQueuedCompletionStatus".}
proc getOverlappedResult*(hFile: THandle, lpOverlapped: TOVERLAPPED,
proc getOverlappedResult*(hFile: Handle, lpOverlapped: OVERLAPPED,
lpNumberOfBytesTransferred: var DWORD, bWait: WINBOOL): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "GetOverlappedResult".}
@ -717,11 +725,11 @@ const
SO_UPDATE_ACCEPT_CONTEXT* = 0x700B
var
WSAID_CONNECTEX*: TGUID = TGUID(D1: 0x25a207b9, D2: 0xddf3'i16, D3: 0x4660, D4: [
WSAID_CONNECTEX*: GUID = GUID(D1: 0x25a207b9, D2: 0xddf3'i16, D3: 0x4660, D4: [
0x8e'i8, 0xe9'i8, 0x76'i8, 0xe5'i8, 0x8c'i8, 0x74'i8, 0x06'i8, 0x3e'i8])
WSAID_ACCEPTEX*: TGUID = TGUID(D1: 0xb5367df1'i32, D2: 0xcbac'i16, D3: 0x11cf, D4: [
WSAID_ACCEPTEX*: GUID = GUID(D1: 0xb5367df1'i32, D2: 0xcbac'i16, D3: 0x11cf, D4: [
0x95'i8, 0xca'i8, 0x00'i8, 0x80'i8, 0x5f'i8, 0x48'i8, 0xa1'i8, 0x92'i8])
WSAID_GETACCEPTEXSOCKADDRS*: TGUID = TGUID(D1: 0xb5367df2'i32, D2: 0xcbac'i16, D3: 0x11cf, D4: [
WSAID_GETACCEPTEXSOCKADDRS*: GUID = GUID(D1: 0xb5367df2'i32, D2: 0xcbac'i16, D3: 0x11cf, D4: [
0x95'i8, 0xca'i8, 0x00'i8, 0x80'i8, 0x5f'i8, 0x48'i8, 0xa1'i8, 0x92'i8])
proc WSAIoctl*(s: SocketHandle, dwIoControlCode: DWORD, lpvInBuffer: pointer,
@ -745,13 +753,13 @@ proc WSASend*(s: SocketHandle, buf: ptr TWSABuf, bufCount: DWORD,
completionProc: POVERLAPPED_COMPLETION_ROUTINE): cint {.
stdcall, importc: "WSASend", dynlib: "Ws2_32.dll".}
proc get_osfhandle*(fd:FileHandle): THandle {.
proc get_osfhandle*(fd:FileHandle): Handle {.
importc: "_get_osfhandle", header:"<io.h>".}
proc getSystemTimes*(lpIdleTime, lpKernelTime,
lpUserTime: var TFILETIME): WINBOOL {.stdcall,
lpUserTime: var FILETIME): WINBOOL {.stdcall,
dynlib: "kernel32", importc: "GetSystemTimes".}
proc getProcessTimes*(hProcess: THandle; lpCreationTime, lpExitTime,
lpKernelTime, lpUserTime: var TFILETIME): WINBOOL {.stdcall,
proc getProcessTimes*(hProcess: Handle; lpCreationTime, lpExitTime,
lpKernelTime, lpUserTime: var FILETIME): WINBOOL {.stdcall,
dynlib: "kernel32", importc: "GetProcessTimes".}

File diff suppressed because it is too large Load diff

View file

@ -13,9 +13,9 @@ when not defined(expatDll):
const
expatDll = "libexpat.so(.1|)"
type
TParserStruct{.pure, final.} = object
ParserStruct{.pure, final.} = object
PParser* = ptr TParserStruct
PParser* = ptr ParserStruct
# The XML_Status enum gives the possible return values for several
# API functions. The preprocessor #defines are included so this
@ -30,11 +30,12 @@ type
# Otherwise, the #define hackery is quite ugly and would have been
# dropped.
#
{.deprecated: [TParserStruct: ParserStruct].}
type
TStatus*{.size: sizeof(cint).} = enum
Status*{.size: sizeof(cint).} = enum
STATUS_ERROR = 0, STATUS_OK = 1, STATUS_SUSPENDED = 2
TError*{.size: sizeof(cint).} = enum
Error*{.size: sizeof(cint).} = enum
ERROR_NONE, ERROR_NO_MEMORY, ERROR_SYNTAX, ERROR_NO_ELEMENTS,
ERROR_INVALID_TOKEN, ERROR_UNCLOSED_TOKEN, ERROR_PARTIAL_CHAR,
ERROR_TAG_MISMATCH, ERROR_DUPLICATE_ATTRIBUTE,
@ -52,10 +53,12 @@ type
ERROR_ABORTED, ERROR_FINISHED, ERROR_SUSPEND_PE,
ERROR_RESERVED_PREFIX_XML, ERROR_RESERVED_PREFIX_XMLNS,
ERROR_RESERVED_NAMESPACE_URI
TContent_Type*{.size: sizeof(cint).} = enum
ContentType*{.size: sizeof(cint).} = enum
CTYPE_EMPTY = 1, CTYPE_ANY, CTYPE_MIXED, CTYPE_NAME, CTYPE_CHOICE, CTYPE_SEQ
TContent_Quant*{.size: sizeof(cint).} = enum
ContentQuant*{.size: sizeof(cint).} = enum
CQUANT_NONE, CQUANT_OPT, CQUANT_REP, CQUANT_PLUS
{.deprecated: [TStatus: Status, TError: Error, TContent_Type: ContentType,
TContent_Quant: ContentQuant].}
# If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be
# XML_CQUANT_NONE, and the other fields will be zero or NULL.
@ -76,13 +79,13 @@ type
#
type
TContent*{.pure, final.} = object
typ*: TContentType
quant*: TContentQuant
Content*{.pure, final.} = object
typ*: ContentType
quant*: ContentQuant
name*: cstring
numchildren*: cint
children*: ptr TContent
children*: ptr Content
{.deprecated: [TContent: Content].}
# This is called for an element declaration. See above for
# description of the model argument. It's the caller's responsibility
@ -90,10 +93,11 @@ type
#
type
TElementDeclHandler* = proc (userData: pointer, name: cstring,
model: ptr TContent){.cdecl.}
ElementDeclHandler* = proc (userData: pointer, name: cstring,
model: ptr Content){.cdecl.}
{.deprecated: [TElementDeclHandler: ElementDeclHandler].}
proc setElementDeclHandler*(parser: PParser, eldecl: TElementDeclHandler){.
proc setElementDeclHandler*(parser: PParser, eldecl: ElementDeclHandler){.
cdecl, importc: "XML_SetElementDeclHandler", dynlib: expatDll.}
# The Attlist declaration handler is called for *each* attribute. So
# a single Attlist declaration with multiple attributes declared will
@ -105,11 +109,12 @@ proc setElementDeclHandler*(parser: PParser, eldecl: TElementDeclHandler){.
#
type
TAttlistDeclHandler* = proc (userData: pointer, elname: cstring,
AttlistDeclHandler* = proc (userData: pointer, elname: cstring,
attname: cstring, attType: cstring,
dflt: cstring, isrequired: cint){.cdecl.}
{.deprecated: [TAttlistDeclHandler: AttlistDeclHandler].}
proc setAttlistDeclHandler*(parser: PParser, attdecl: TAttlistDeclHandler){.
proc setAttlistDeclHandler*(parser: PParser, attdecl: AttlistDeclHandler){.
cdecl, importc: "XML_SetAttlistDeclHandler", dynlib: expatDll.}
# The XML declaration handler is called for *both* XML declarations
# and text declarations. The way to distinguish is that the version
@ -121,17 +126,18 @@ proc setAttlistDeclHandler*(parser: PParser, attdecl: TAttlistDeclHandler){.
#
type
TXmlDeclHandler* = proc (userData: pointer, version: cstring,
XmlDeclHandler* = proc (userData: pointer, version: cstring,
encoding: cstring, standalone: cint){.cdecl.}
{.deprecated: [TXmlDeclHandler: XmlDeclHandler].}
proc setXmlDeclHandler*(parser: PParser, xmldecl: TXmlDeclHandler){.cdecl,
proc setXmlDeclHandler*(parser: PParser, xmldecl: XmlDeclHandler){.cdecl,
importc: "XML_SetXmlDeclHandler", dynlib: expatDll.}
type
TMemory_Handling_Suite*{.pure, final.} = object
Memory_Handling_Suite*{.pure, final.} = object
mallocFcn*: proc (size: int): pointer{.cdecl.}
reallocFcn*: proc (p: pointer, size: int): pointer{.cdecl.}
freeFcn*: proc (p: pointer){.cdecl.}
{.deprecated: [TMemory_Handling_Suite: MemoryHandlingSuite].}
# Constructs a new parser; encoding is the encoding specified by the
# external protocol or NULL if there is none specified.
@ -183,29 +189,33 @@ proc parserReset*(parser: PParser, encoding: cstring): bool{.cdecl,
#
type
TStartElementHandler* = proc (userData: pointer, name: cstring,
StartElementHandler* = proc (userData: pointer, name: cstring,
atts: cstringArray){.cdecl.}
TEndElementHandler* = proc (userData: pointer, name: cstring){.cdecl.}
EndElementHandler* = proc (userData: pointer, name: cstring){.cdecl.}
{.deprecated: [TStartElementHandler: StartElementHandler,
TEndElementHandler: EndElementHandler].}
# s is not 0 terminated.
type
TCharacterDataHandler* = proc (userData: pointer, s: cstring, len: cint){.
CharacterDataHandler* = proc (userData: pointer, s: cstring, len: cint){.
cdecl.}
{.deprecated: [TCharacterDataHandler: CharacterDataHandler].}
# target and data are 0 terminated
type
TProcessingInstructionHandler* = proc (userData: pointer, target: cstring,
ProcessingInstructionHandler* = proc (userData: pointer, target: cstring,
data: cstring){.cdecl.}
{.deprecated: [TProcessingInstructionHandler: ProcessingInstructionHandler].}
# data is 0 terminated
type
TCommentHandler* = proc (userData: pointer, data: cstring){.cdecl.}
TStartCdataSectionHandler* = proc (userData: pointer){.cdecl.}
TEndCdataSectionHandler* = proc (userData: pointer){.cdecl.}
CommentHandler* = proc (userData: pointer, data: cstring){.cdecl.}
StartCdataSectionHandler* = proc (userData: pointer){.cdecl.}
EndCdataSectionHandler* = proc (userData: pointer){.cdecl.}
{.deprecated: [TCommentHandler: CommentHandler,
TStartCdataSectionHandler: StartCdataSectionHandler,
TEndCdataSectionHandler: EndCdataSectionHandler].}
# This is called for any characters in the XML document for which
# there is no applicable handler. This includes both characters that
# are part of markup which is of a kind that is not reported
@ -221,16 +231,17 @@ type
#
type
TDefaultHandler* = proc (userData: pointer, s: cstring, len: cint){.cdecl.}
DefaultHandler* = proc (userData: pointer, s: cstring, len: cint){.cdecl.}
{.deprecated: [TDefaultHandler: DefaultHandler].}
# This is called for the start of the DOCTYPE declaration, before
# any DTD or internal subset is parsed.
#
type
TStartDoctypeDeclHandler* = proc (userData: pointer, doctypeName: cstring,
StartDoctypeDeclHandler* = proc (userData: pointer, doctypeName: cstring,
sysid: cstring, pubid: cstring,
hasInternalSubset: cint){.cdecl.}
{.deprecated: [TStartDoctypeDeclHandler: StartDoctypeDeclHandler].}
# This is called for the start of the DOCTYPE declaration when the
# closing > is encountered, but after processing any external
@ -238,7 +249,8 @@ type
#
type
TEndDoctypeDeclHandler* = proc (userData: pointer){.cdecl.}
EndDoctypeDeclHandler* = proc (userData: pointer){.cdecl.}
{.deprecated: [TEndDoctypeDeclHandler: EndDoctypeDeclHandler].}
# This is called for entity declarations. The is_parameter_entity
# argument will be non-zero if the entity is a parameter entity, zero
@ -260,13 +272,14 @@ type
#
type
TEntityDeclHandler* = proc (userData: pointer, entityName: cstring,
EntityDeclHandler* = proc (userData: pointer, entityName: cstring,
isParameterEntity: cint, value: cstring,
valueLength: cint, base: cstring,
systemId: cstring, publicId: cstring,
notationName: cstring){.cdecl.}
{.deprecated: [TEntityDeclHandler: EntityDeclHandler].}
proc setEntityDeclHandler*(parser: PParser, handler: TEntityDeclHandler){.cdecl,
proc setEntityDeclHandler*(parser: PParser, handler: EntityDeclHandler){.cdecl,
importc: "XML_SetEntityDeclHandler", dynlib: expatDll.}
# OBSOLETE -- OBSOLETE -- OBSOLETE
# This handler has been superceded by the EntityDeclHandler above.
@ -279,10 +292,11 @@ proc setEntityDeclHandler*(parser: PParser, handler: TEntityDeclHandler){.cdecl,
#
type
TUnparsedEntityDeclHandler* = proc (userData: pointer, entityName: cstring,
UnparsedEntityDeclHandler* = proc (userData: pointer, entityName: cstring,
base: cstring, systemId: cstring,
publicId, notationName: cstring){.
cdecl.}
{.deprecated: [TUnparsedEntityDeclHandler: UnparsedEntityDeclHandler].}
# This is called for a declaration of notation. The base argument is
# whatever was set by XML_SetBase. The notationName will never be
@ -290,9 +304,10 @@ type
#
type
TNotationDeclHandler* = proc (userData: pointer, notationName: cstring,
NotationDeclHandler* = proc (userData: pointer, notationName: cstring,
base: cstring, systemId: cstring,
publicId: cstring){.cdecl.}
{.deprecated: [TNotationDeclHandler: NotationDeclHandler].}
# When namespace processing is enabled, these are called once for
# each namespace declaration. The call to the start and end element
@ -302,10 +317,11 @@ type
#
type
TStartNamespaceDeclHandler* = proc (userData: pointer, prefix: cstring,
StartNamespaceDeclHandler* = proc (userData: pointer, prefix: cstring,
uri: cstring){.cdecl.}
TEndNamespaceDeclHandler* = proc (userData: pointer, prefix: cstring){.cdecl.}
EndNamespaceDeclHandler* = proc (userData: pointer, prefix: cstring){.cdecl.}
{.deprecated: [TStartNamespaceDeclHandler: StartNamespaceDeclHandler,
TEndNamespaceDeclHandler: EndNamespaceDeclHandler].}
# This is called if the document is not standalone, that is, it has an
# external subset or a reference to a parameter entity, but does not
# have standalone="yes". If this handler returns XML_STATUS_ERROR,
@ -317,7 +333,8 @@ type
#
type
TNotStandaloneHandler* = proc (userData: pointer): cint{.cdecl.}
NotStandaloneHandler* = proc (userData: pointer): cint{.cdecl.}
{.deprecated: [TNotStandaloneHandler: NotStandaloneHandler].}
# This is called for a reference to an external parsed general
# entity. The referenced entity is not automatically parsed. The
@ -355,10 +372,10 @@ type
#
type
TExternalEntityRefHandler* = proc (parser: PParser, context: cstring,
ExternalEntityRefHandler* = proc (parser: PParser, context: cstring,
base: cstring, systemId: cstring,
publicId: cstring): cint{.cdecl.}
{.deprecated: [TExternalEntityRefHandler: ExternalEntityRefHandler].}
# This is called in two situations:
# 1) An entity reference is encountered for which no declaration
# has been read *and* this is not an error.
@ -371,8 +388,9 @@ type
#
type
TSkippedEntityHandler* = proc (userData: pointer, entityName: cstring,
SkippedEntityHandler* = proc (userData: pointer, entityName: cstring,
isParameterEntity: cint){.cdecl.}
{.deprecated: [TSkippedEntityHandler: SkippedEntityHandler].}
# This structure is filled in by the XML_UnknownEncodingHandler to
# provide information to the parser about encodings that are unknown
@ -428,11 +446,12 @@ type
#
type
TEncoding*{.pure, final.} = object
Encoding*{.pure, final.} = object
map*: array[0..256 - 1, cint]
data*: pointer
convert*: proc (data: pointer, s: cstring): cint{.cdecl.}
release*: proc (data: pointer){.cdecl.}
{.deprecated: [TEncoding: Encoding].}
# This is called for an encoding that is unknown to the parser.
@ -452,74 +471,75 @@ type
#
type
TUnknownEncodingHandler* = proc (encodingHandlerData: pointer, name: cstring,
info: ptr TEncoding): cint{.cdecl.}
UnknownEncodingHandler* = proc (encodingHandlerData: pointer, name: cstring,
info: ptr Encoding): cint{.cdecl.}
{.deprecated: [TUnknownEncodingHandler: UnknownEncodingHandler].}
proc setElementHandler*(parser: PParser, start: TStartElementHandler,
endHandler: TEndElementHandler){.cdecl,
proc setElementHandler*(parser: PParser, start: StartElementHandler,
endHandler: EndElementHandler){.cdecl,
importc: "XML_SetElementHandler", dynlib: expatDll.}
proc setStartElementHandler*(parser: PParser, handler: TStartElementHandler){.
proc setStartElementHandler*(parser: PParser, handler: StartElementHandler){.
cdecl, importc: "XML_SetStartElementHandler", dynlib: expatDll.}
proc setEndElementHandler*(parser: PParser, handler: TEndElementHandler){.cdecl,
proc setEndElementHandler*(parser: PParser, handler: EndElementHandler){.cdecl,
importc: "XML_SetEndElementHandler", dynlib: expatDll.}
proc setCharacterDataHandler*(parser: PParser, handler: TCharacterDataHandler){.
proc setCharacterDataHandler*(parser: PParser, handler: CharacterDataHandler){.
cdecl, importc: "XML_SetCharacterDataHandler", dynlib: expatDll.}
proc setProcessingInstructionHandler*(parser: PParser,
handler: TProcessingInstructionHandler){.
handler: ProcessingInstructionHandler){.
cdecl, importc: "XML_SetProcessingInstructionHandler", dynlib: expatDll.}
proc setCommentHandler*(parser: PParser, handler: TCommentHandler){.cdecl,
proc setCommentHandler*(parser: PParser, handler: CommentHandler){.cdecl,
importc: "XML_SetCommentHandler", dynlib: expatDll.}
proc setCdataSectionHandler*(parser: PParser, start: TStartCdataSectionHandler,
endHandler: TEndCdataSectionHandler){.cdecl,
proc setCdataSectionHandler*(parser: PParser, start: StartCdataSectionHandler,
endHandler: EndCdataSectionHandler){.cdecl,
importc: "XML_SetCdataSectionHandler", dynlib: expatDll.}
proc setStartCdataSectionHandler*(parser: PParser,
start: TStartCdataSectionHandler){.cdecl,
start: StartCdataSectionHandler){.cdecl,
importc: "XML_SetStartCdataSectionHandler", dynlib: expatDll.}
proc setEndCdataSectionHandler*(parser: PParser,
endHandler: TEndCdataSectionHandler){.cdecl,
endHandler: EndCdataSectionHandler){.cdecl,
importc: "XML_SetEndCdataSectionHandler", dynlib: expatDll.}
# This sets the default handler and also inhibits expansion of
# internal entities. These entity references will be passed to the
# default handler, or to the skipped entity handler, if one is set.
#
proc setDefaultHandler*(parser: PParser, handler: TDefaultHandler){.cdecl,
proc setDefaultHandler*(parser: PParser, handler: DefaultHandler){.cdecl,
importc: "XML_SetDefaultHandler", dynlib: expatDll.}
# This sets the default handler but does not inhibit expansion of
# internal entities. The entity reference will not be passed to the
# default handler.
#
proc setDefaultHandlerExpand*(parser: PParser, handler: TDefaultHandler){.cdecl,
proc setDefaultHandlerExpand*(parser: PParser, handler: DefaultHandler){.cdecl,
importc: "XML_SetDefaultHandlerExpand", dynlib: expatDll.}
proc setDoctypeDeclHandler*(parser: PParser, start: TStartDoctypeDeclHandler,
endHandler: TEndDoctypeDeclHandler){.cdecl,
proc setDoctypeDeclHandler*(parser: PParser, start: StartDoctypeDeclHandler,
endHandler: EndDoctypeDeclHandler){.cdecl,
importc: "XML_SetDoctypeDeclHandler", dynlib: expatDll.}
proc setStartDoctypeDeclHandler*(parser: PParser,
start: TStartDoctypeDeclHandler){.cdecl,
start: StartDoctypeDeclHandler){.cdecl,
importc: "XML_SetStartDoctypeDeclHandler", dynlib: expatDll.}
proc setEndDoctypeDeclHandler*(parser: PParser,
endHandler: TEndDoctypeDeclHandler){.cdecl,
endHandler: EndDoctypeDeclHandler){.cdecl,
importc: "XML_SetEndDoctypeDeclHandler", dynlib: expatDll.}
proc setUnparsedEntityDeclHandler*(parser: PParser,
handler: TUnparsedEntityDeclHandler){.cdecl,
handler: UnparsedEntityDeclHandler){.cdecl,
importc: "XML_SetUnparsedEntityDeclHandler", dynlib: expatDll.}
proc setNotationDeclHandler*(parser: PParser, handler: TNotationDeclHandler){.
proc setNotationDeclHandler*(parser: PParser, handler: NotationDeclHandler){.
cdecl, importc: "XML_SetNotationDeclHandler", dynlib: expatDll.}
proc setNamespaceDeclHandler*(parser: PParser,
start: TStartNamespaceDeclHandler,
endHandler: TEndNamespaceDeclHandler){.cdecl,
start: StartNamespaceDeclHandler,
endHandler: EndNamespaceDeclHandler){.cdecl,
importc: "XML_SetNamespaceDeclHandler", dynlib: expatDll.}
proc setStartNamespaceDeclHandler*(parser: PParser,
start: TStartNamespaceDeclHandler){.cdecl,
start: StartNamespaceDeclHandler){.cdecl,
importc: "XML_SetStartNamespaceDeclHandler", dynlib: expatDll.}
proc setEndNamespaceDeclHandler*(parser: PParser,
endHandler: TEndNamespaceDeclHandler){.cdecl,
endHandler: EndNamespaceDeclHandler){.cdecl,
importc: "XML_SetEndNamespaceDeclHandler", dynlib: expatDll.}
proc setNotStandaloneHandler*(parser: PParser, handler: TNotStandaloneHandler){.
proc setNotStandaloneHandler*(parser: PParser, handler: NotStandaloneHandler){.
cdecl, importc: "XML_SetNotStandaloneHandler", dynlib: expatDll.}
proc setExternalEntityRefHandler*(parser: PParser,
handler: TExternalEntityRefHandler){.cdecl,
handler: ExternalEntityRefHandler){.cdecl,
importc: "XML_SetExternalEntityRefHandler", dynlib: expatDll.}
# If a non-NULL value for arg is specified here, then it will be
# passed as the first argument to the external entity ref handler
@ -528,10 +548,10 @@ proc setExternalEntityRefHandler*(parser: PParser,
proc setExternalEntityRefHandlerArg*(parser: PParser, arg: pointer){.cdecl,
importc: "XML_SetExternalEntityRefHandlerArg", dynlib: expatDll.}
proc setSkippedEntityHandler*(parser: PParser, handler: TSkippedEntityHandler){.
proc setSkippedEntityHandler*(parser: PParser, handler: SkippedEntityHandler){.
cdecl, importc: "XML_SetSkippedEntityHandler", dynlib: expatDll.}
proc setUnknownEncodingHandler*(parser: PParser,
handler: TUnknownEncodingHandler,
handler: UnknownEncodingHandler,
encodingHandlerData: pointer){.cdecl,
importc: "XML_SetUnknownEncodingHandler", dynlib: expatDll.}
# This can be called within a handler for a start element, end
@ -573,7 +593,7 @@ template getUserData*(parser: expr): expr =
# has no effect and returns XML_STATUS_ERROR.
#
proc setEncoding*(parser: PParser, encoding: cstring): TStatus{.cdecl,
proc setEncoding*(parser: PParser, encoding: cstring): Status{.cdecl,
importc: "XML_SetEncoding", dynlib: expatDll.}
# If this function is called, then the parser will be passed as the
# first argument to callbacks instead of userData. The userData will
@ -601,7 +621,7 @@ proc useParserAsHandlerArg*(parser: PParser){.cdecl,
# XML_ERROR_FEATURE_REQUIRES_XML_DTD.
#
proc useForeignDTD*(parser: PParser, useDTD: bool): TError{.cdecl,
proc useForeignDTD*(parser: PParser, useDTD: bool): Error{.cdecl,
importc: "XML_UseForeignDTD", dynlib: expatDll.}
# Sets the base to be used for resolving relative URIs in system
# identifiers in declarations. Resolving relative identifiers is
@ -612,7 +632,7 @@ proc useForeignDTD*(parser: PParser, useDTD: bool): TError{.cdecl,
# XML_STATUS_OK otherwise.
#
proc setBase*(parser: PParser, base: cstring): TStatus{.cdecl,
proc setBase*(parser: PParser, base: cstring): Status{.cdecl,
importc: "XML_SetBase", dynlib: expatDll.}
proc getBase*(parser: PParser): cstring{.cdecl, importc: "XML_GetBase",
dynlib: expatDll.}
@ -643,11 +663,11 @@ proc getIdAttributeIndex*(parser: PParser): cint{.cdecl,
# values.
#
proc parse*(parser: PParser, s: cstring, len: cint, isFinal: cint): TStatus{.
proc parse*(parser: PParser, s: cstring, len: cint, isFinal: cint): Status{.
cdecl, importc: "XML_Parse", dynlib: expatDll.}
proc getBuffer*(parser: PParser, len: cint): pointer{.cdecl,
importc: "XML_GetBuffer", dynlib: expatDll.}
proc parseBuffer*(parser: PParser, len: cint, isFinal: cint): TStatus{.cdecl,
proc parseBuffer*(parser: PParser, len: cint, isFinal: cint): Status{.cdecl,
importc: "XML_ParseBuffer", dynlib: expatDll.}
# Stops parsing, causing XML_Parse() or XML_ParseBuffer() to return.
# Must be called from within a call-back handler, except when aborting
@ -681,7 +701,7 @@ proc parseBuffer*(parser: PParser, len: cint, isFinal: cint): TStatus{.cdecl,
# When suspended, parsing can be resumed by calling XML_ResumeParser().
#
proc stopParser*(parser: PParser, resumable: bool): TStatus{.cdecl,
proc stopParser*(parser: PParser, resumable: bool): Status{.cdecl,
importc: "XML_StopParser", dynlib: expatDll.}
# Resumes parsing after it has been suspended with XML_StopParser().
# Must not be called from within a handler call-back. Returns same
@ -696,15 +716,16 @@ proc stopParser*(parser: PParser, resumable: bool): TStatus{.cdecl,
# application to call XML_ResumeParser() on it at the appropriate moment.
#
proc resumeParser*(parser: PParser): TStatus{.cdecl,
proc resumeParser*(parser: PParser): Status{.cdecl,
importc: "XML_ResumeParser", dynlib: expatDll.}
type
TParsing* = enum
INITIALIZED, PARSING, FINISHED, SUSPENDED
TParsingStatus*{.pure, final.} = object
ParsingStatus*{.pure, final.} = object
parsing*: TParsing
finalBuffer*: bool
{.deprecated: [#TParsing: Parsing, # Naming conflict if we drop the `T`
TParsingStatus: ParsingStatus].}
# Returns status of parser with respect to being initialized, parsing,
# finished, or suspended and processing the final buffer.
@ -712,7 +733,7 @@ type
# XXX with XML_FINISHED_OK or XML_FINISHED_ERROR replacing XML_FINISHED
#
proc getParsingStatus*(parser: PParser, status: ptr TParsingStatus){.cdecl,
proc getParsingStatus*(parser: PParser, status: ptr ParsingStatus){.cdecl,
importc: "XML_GetParsingStatus", dynlib: expatDll.}
# Creates an XML_Parser object that can parse an external general
# entity; context is a '\0'-terminated string specifying the parse
@ -735,9 +756,10 @@ proc externalEntityParserCreate*(parser: PParser, context: cstring,
encoding: cstring): PParser{.cdecl,
importc: "XML_ExternalEntityParserCreate", dynlib: expatDll.}
type
TParamEntityParsing* = enum
ParamEntityParsing* = enum
PARAM_ENTITY_PARSING_NEVER, PARAM_ENTITY_PARSING_UNLESS_STANDALONE,
PARAM_ENTITY_PARSING_ALWAYS
{.deprecated: [TParamEntityParsing: ParamEntityParsing].}
# Controls parsing of parameter entities (including the external DTD
# subset). If parsing of parameter entities is enabled, then
@ -763,13 +785,13 @@ type
# XML_ParseBuffer, then it has no effect and will always return 0.
#
proc setParamEntityParsing*(parser: PParser, parsing: TParamEntityParsing): cint{.
proc setParamEntityParsing*(parser: PParser, parsing: ParamEntityParsing): cint{.
cdecl, importc: "XML_SetParamEntityParsing", dynlib: expatDll.}
# If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then
# XML_GetErrorCode returns information about the error.
#
proc getErrorCode*(parser: PParser): TError{.cdecl, importc: "XML_GetErrorCode",
proc getErrorCode*(parser: PParser): Error{.cdecl, importc: "XML_GetErrorCode",
dynlib: expatDll.}
# These functions return information about the current parse
# location. They may be called from any callback called to report
@ -815,7 +837,7 @@ proc getInputContext*(parser: PParser, offset: ptr cint, size: ptr cint): cstrin
cdecl, importc: "XML_GetInputContext", dynlib: expatDll.}
# Frees the content model passed to the element declaration handler
proc freeContentModel*(parser: PParser, model: ptr TContent){.cdecl,
proc freeContentModel*(parser: PParser, model: ptr Content){.cdecl,
importc: "XML_FreeContentModel", dynlib: expatDll.}
# Exposing the memory handling functions used in Expat
@ -831,39 +853,39 @@ proc parserFree*(parser: PParser){.cdecl, importc: "XML_ParserFree",
dynlib: expatDll.}
# Returns a string describing the error.
proc errorString*(code: TError): cstring{.cdecl, importc: "XML_ErrorString",
proc errorString*(code: Error): cstring{.cdecl, importc: "XML_ErrorString",
dynlib: expatDll.}
# Return a string containing the version number of this expat
proc expatVersion*(): cstring{.cdecl, importc: "XML_ExpatVersion",
dynlib: expatDll.}
type
TExpat_Version*{.pure, final.} = object
Expat_Version*{.pure, final.} = object
major*: cint
minor*: cint
micro*: cint
{.deprecated: [TExpat_Version: ExpatVersion].}
# Return an XML_Expat_Version structure containing numeric version
# number information for this version of expat.
#
proc expatVersionInfo*(): TExpatVersion{.cdecl,
proc expatVersionInfo*(): ExpatVersion{.cdecl,
importc: "XML_ExpatVersionInfo", dynlib: expatDll.}
# Added in Expat 1.95.5.
type
TFeatureEnum* = enum
FeatureEnum* = enum
FEATURE_END = 0, FEATURE_UNICODE, FEATURE_UNICODE_WCHAR_T, FEATURE_DTD,
FEATURE_CONTEXT_BYTES, FEATURE_MIN_SIZE, FEATURE_SIZEOF_XML_CHAR,
FEATURE_SIZEOF_XML_LCHAR, FEATURE_NS, FEATURE_LARGE_SIZE # Additional features must be added to the end of this enum.
TFeature*{.pure, final.} = object
feature*: TFeatureEnum
Feature*{.pure, final.} = object
feature*: FeatureEnum
name*: cstring
value*: int
{.deprecated: [TFeatureEnum: FeatureEnum, TFeature: Feature].}
proc getFeatureList*(): ptr TFeature{.cdecl, importc: "XML_GetFeatureList",
proc getFeatureList*(): ptr Feature{.cdecl, importc: "XML_GetFeatureList",
dynlib: expatDll.}
# Expat follows the GNU/Linux convention of odd number minor version for
# beta/development releases and even number minor version for stable

View file

@ -1,20 +1,20 @@
type
csize = int
HttpDataProc* = proc (a2: ptr THttpParser, at: cstring, length: csize): cint {.cdecl.}
HttpProc* = proc (a2: ptr THttpParser): cint {.cdecl.}
HttpDataProc* = proc (a2: ptr HttpParser, at: cstring, length: csize): cint {.cdecl.}
HttpProc* = proc (a2: ptr HttpParser): cint {.cdecl.}
THttpMethod* = enum
HttpMethod* = enum
HTTP_DELETE = 0, HTTP_GET, HTTP_HEAD, HTTP_POST, HTTP_PUT, HTTP_CONNECT,
HTTP_OPTIONS, HTTP_TRACE, HTTP_COPY, HTTP_LOCK, HTTP_MKCOL, HTTP_MOVE,
HTTP_PROPFIND, HTTP_PROPPATCH, HTTP_UNLOCK, HTTP_REPORT, HTTP_MKACTIVITY,
HTTP_CHECKOUT, HTTP_MERGE, HTTP_MSEARCH, HTTP_NOTIFY, HTTP_SUBSCRIBE,
HTTP_UNSUBSCRIBE, HTTP_PATCH
THttpParserType* = enum
HttpParserType* = enum
HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH
TParserFlag* = enum
ParserFlag* = enum
F_CHUNKED = 1 shl 0,
F_CONNECTION_KEEP_ALIVE = 1 shl 1,
F_CONNECTION_CLOSE = 1 shl 2,
@ -22,7 +22,7 @@ type
F_UPGRADE = 1 shl 4,
F_SKIPBODY = 1 shl 5
THttpErrNo* = enum
HttpErrNo* = enum
HPE_OK, HPE_CB_message_begin, HPE_CB_path, HPE_CB_query_string, HPE_CB_url,
HPE_CB_fragment, HPE_CB_header_field, HPE_CB_header_value,
HPE_CB_headers_complete, HPE_CB_body, HPE_CB_message_complete,
@ -34,7 +34,7 @@ type
HPE_INVALID_CHUNK_SIZE, HPE_INVALID_CONSTANT, HPE_INVALID_INTERNAL_STATE,
HPE_STRICT, HPE_UNKNOWN
THttpParser*{.pure, final, importc: "http_parser", header: "http_parser.h".} = object
HttpParser*{.pure, final, importc: "http_parser", header: "http_parser.h".} = object
typ {.importc: "type".}: char
flags {.importc: "flags".}: char
state*{.importc: "state".}: char
@ -50,7 +50,7 @@ type
upgrade {.importc: "upgrade".}: bool
data*{.importc: "data".}: pointer
THttpParserSettings*{.pure, final, importc: "http_parser_settings", header: "http_parser.h".} = object
HttpParserSettings*{.pure, final, importc: "http_parser_settings", header: "http_parser.h".} = object
on_message_begin*{.importc: "on_message_begin".}: HttpProc
on_url*{.importc: "on_url".}: HttpDataProc
on_header_field*{.importc: "on_header_field".}: HttpDataProc
@ -58,24 +58,27 @@ type
on_headers_complete*{.importc: "on_headers_complete".}: HttpProc
on_body*{.importc: "on_body".}: HttpDataProc
on_message_complete*{.importc: "on_message_complete".}: HttpProc
{.deprecated: [THttpMethod: HttpMethod, THttpParserType: HttpParserType,
TParserFlag: ParserFlag, THttpErrNo: HttpErrNo,
THttpParser: HttpParser, THttpParserSettings: HttpParserSettings].}
proc http_parser_init*(parser: var THttpParser, typ: THttpParserType){.
proc http_parser_init*(parser: var HttpParser, typ: HttpParserType){.
importc: "http_parser_init", header: "http_parser.h".}
proc http_parser_execute*(parser: var THttpParser,
settings: var THttpParserSettings, data: cstring,
proc http_parser_execute*(parser: var HttpParser,
settings: var HttpParserSettings, data: cstring,
len: csize): csize {.
importc: "http_parser_execute", header: "http_parser.h".}
proc http_should_keep_alive*(parser: var THttpParser): cint{.
proc http_should_keep_alive*(parser: var HttpParser): cint{.
importc: "http_should_keep_alive", header: "http_parser.h".}
proc http_method_str*(m: THttpMethod): cstring{.
proc http_method_str*(m: HttpMethod): cstring{.
importc: "http_method_str", header: "http_parser.h".}
proc http_errno_name*(err: THttpErrNo): cstring{.
proc http_errno_name*(err: HttpErrNo): cstring{.
importc: "http_errno_name", header: "http_parser.h".}
proc http_errno_description*(err: THttpErrNo): cstring{.
proc http_errno_description*(err: HttpErrNo): cstring{.
importc: "http_errno_description", header: "http_parser.h".}

View file

@ -31,47 +31,47 @@ elif defined(unix):
const
libname = "libcurl.so.4"
type
Pcalloc_callback* = ptr Tcalloc_callback
Pclosepolicy* = ptr Tclosepolicy
Pforms* = ptr Tforms
Pftpauth* = ptr Tftpauth
Pftpmethod* = ptr Tftpmethod
Pftpssl* = ptr Tftpssl
PHTTP_VERSION* = ptr THTTP_VERSION
Phttppost* = ptr Thttppost
Pcalloc_callback* = ptr Calloc_callback
Pclosepolicy* = ptr Closepolicy
Pforms* = ptr Forms
Pftpauth* = ptr Ftpauth
Pftpmethod* = ptr Ftpmethod
Pftpssl* = ptr Ftpssl
PHTTP_VERSION* = ptr HTTP_VERSION
Phttppost* = ptr Httppost
PPcurl_httppost* = ptr Phttppost
Pinfotype* = ptr Tinfotype
Plock_access* = ptr Tlock_access
Plock_data* = ptr Tlock_data
Pmalloc_callback* = ptr Tmalloc_callback
PNETRC_OPTION* = ptr TNETRC_OPTION
Pproxytype* = ptr Tproxytype
Prealloc_callback* = ptr Trealloc_callback
Pslist* = ptr Tslist
Psocket* = ptr Tsocket
PSSL_VERSION* = ptr TSSL_VERSION
Pstrdup_callback* = ptr Tstrdup_callback
PTIMECOND* = ptr TTIMECOND
Pversion_info_data* = ptr Tversion_info_data
Pcode* = ptr Tcode
PFORMcode* = ptr TFORMcode
Pformoption* = ptr Tformoption
PINFO* = ptr TINFO
Piocmd* = ptr Tiocmd
Pioerr* = ptr Tioerr
PM* = ptr TM
PMcode* = ptr TMcode
PMoption* = ptr TMoption
PMSG* = ptr TMSG
Poption* = ptr Toption
PSH* = ptr TSH
PSHcode* = ptr TSHcode
PSHoption* = ptr TSHoption
Pversion* = ptr Tversion
Pinfotype* = ptr Infotype
Plock_access* = ptr Lock_access
Plock_data* = ptr Lock_data
Pmalloc_callback* = ptr Malloc_callback
PNETRC_OPTION* = ptr NETRC_OPTION
Pproxytype* = ptr Proxytype
Prealloc_callback* = ptr Realloc_callback
Pslist* = ptr Slist
Psocket* = ptr Socket
PSSL_VERSION* = ptr SSL_VERSION
Pstrdup_callback* = ptr Strdup_callback
PTIMECOND* = ptr TIMECOND
Pversion_info_data* = ptr Version_info_data
Pcode* = ptr Code
PFORMcode* = ptr FORMcode
Pformoption* = ptr Formoption
PINFO* = ptr INFO
Piocmd* = ptr Iocmd
Pioerr* = ptr Ioerr
PM* = ptr M
PMcode* = ptr Mcode
PMoption* = ptr Moption
PMSG* = ptr MSG
Poption* = ptr Option
PSH* = ptr SH
PSHcode* = ptr SHcode
PSHoption* = ptr SHoption
Pversion* = ptr Version
Pfd_set* = pointer
PCurl* = ptr TCurl
TCurl* = pointer
Thttppost*{.final, pure.} = object
PCurl* = ptr Curl
Curl* = pointer
Httppost*{.final, pure.} = object
next*: Phttppost
name*: cstring
namelength*: int32
@ -85,32 +85,32 @@ type
flags*: int32
showfilename*: cstring
Tprogress_callback* = proc (clientp: pointer, dltotal: float64,
Progress_callback* = proc (clientp: pointer, dltotal: float64,
dlnow: float64, ultotal: float64,
ulnow: float64): int32 {.cdecl.}
Twrite_callback* = proc (buffer: cstring, size: int, nitems: int,
Write_callback* = proc (buffer: cstring, size: int, nitems: int,
outstream: pointer): int{.cdecl.}
Tread_callback* = proc (buffer: cstring, size: int, nitems: int,
Read_callback* = proc (buffer: cstring, size: int, nitems: int,
instream: pointer): int{.cdecl.}
Tpasswd_callback* = proc (clientp: pointer, prompt: cstring, buffer: cstring,
Passwd_callback* = proc (clientp: pointer, prompt: cstring, buffer: cstring,
buflen: int32): int32{.cdecl.}
Tioerr* = enum
Ioerr* = enum
IOE_OK, IOE_UNKNOWNCMD, IOE_FAILRESTART, IOE_LAST
Tiocmd* = enum
Iocmd* = enum
IOCMD_NOP, IOCMD_RESTARTREAD, IOCMD_LAST
Tioctl_callback* = proc (handle: PCurl, cmd: int32, clientp: pointer): Tioerr{.
Ioctl_callback* = proc (handle: PCurl, cmd: int32, clientp: pointer): Ioerr{.
cdecl.}
Tmalloc_callback* = proc (size: int): pointer{.cdecl.}
Tfree_callback* = proc (p: pointer){.cdecl.}
Trealloc_callback* = proc (p: pointer, size: int): pointer{.cdecl.}
Tstrdup_callback* = proc (str: cstring): cstring{.cdecl.}
Tcalloc_callback* = proc (nmemb: int, size: int): pointer{.noconv.}
Tinfotype* = enum
Malloc_callback* = proc (size: int): pointer{.cdecl.}
Free_callback* = proc (p: pointer){.cdecl.}
Realloc_callback* = proc (p: pointer, size: int): pointer{.cdecl.}
Strdup_callback* = proc (str: cstring): cstring{.cdecl.}
Calloc_callback* = proc (nmemb: int, size: int): pointer{.noconv.}
Infotype* = enum
INFO_TEXT = 0, INFO_HEADER_IN, INFO_HEADER_OUT, INFO_DATA_IN, INFO_DATA_OUT,
INFO_SSL_DATA_IN, INFO_SSL_DATA_OUT, INFO_END
Tdebug_callback* = proc (handle: PCurl, theType: Tinfotype, data: cstring,
Debug_callback* = proc (handle: PCurl, theType: Infotype, data: cstring,
size: int, userptr: pointer): int32{.cdecl.}
Tcode* = enum
Code* = enum
E_OK = 0, E_UNSUPPORTED_PROTOCOL, E_FAILED_INIT, E_URL_MALFORMAT,
E_URL_MALFORMAT_USER, E_COULDNT_RESOLVE_PROXY, E_COULDNT_RESOLVE_HOST,
E_COULDNT_CONNECT, E_FTP_WEIRD_SERVER_REPLY, E_FTP_ACCESS_DENIED,
@ -135,18 +135,18 @@ type
E_LOGIN_DENIED, E_TFTP_NOTFOUND, E_TFTP_PERM, E_TFTP_DISKFULL,
E_TFTP_ILLEGAL, E_TFTP_UNKNOWNID, E_TFTP_EXISTS, E_TFTP_NOSUCHUSER,
E_CONV_FAILED, E_CONV_REQD, LAST
Tconv_callback* = proc (buffer: cstring, len: int): Tcode{.cdecl.}
Tssl_ctx_callback* = proc (curl: PCurl, ssl_ctx, userptr: pointer): Tcode{.cdecl.}
Tproxytype* = enum
Conv_callback* = proc (buffer: cstring, len: int): Code{.cdecl.}
Ssl_ctx_callback* = proc (curl: PCurl, ssl_ctx, userptr: pointer): Code{.cdecl.}
Proxytype* = enum
PROXY_HTTP = 0, PROXY_SOCKS4 = 4, PROXY_SOCKS5 = 5
Tftpssl* = enum
Ftpssl* = enum
FTPSSL_NONE, FTPSSL_TRY, FTPSSL_CONTROL, FTPSSL_ALL, FTPSSL_LAST
Tftpauth* = enum
Ftpauth* = enum
FTPAUTH_DEFAULT, FTPAUTH_SSL, FTPAUTH_TLS, FTPAUTH_LAST
Tftpmethod* = enum
Ftpmethod* = enum
FTPMETHOD_DEFAULT, FTPMETHOD_MULTICWD, FTPMETHOD_NOCWD, FTPMETHOD_SINGLECWD,
FTPMETHOD_LAST
Toption* = enum
Option* = enum
OPT_PORT = 0 + 3, OPT_TIMEOUT = 0 + 13, OPT_INFILESIZE = 0 + 14,
OPT_LOW_SPEED_LIMIT = 0 + 19, OPT_LOW_SPEED_TIME = 0 + 20,
OPT_RESUME_FROM = 0 + 21, OPT_CRLF = 0 + 27, OPT_SSLVERSION = 0 + 32,
@ -211,37 +211,37 @@ type
OPT_MAXFILESIZE_LARGE = 30000 + 117, OPT_POSTFIELDSIZE_LARGE = 30000 + 120,
OPT_MAX_SEND_SPEED_LARGE = 30000 + 145,
OPT_MAX_RECV_SPEED_LARGE = 30000 + 146
THTTP_VERSION* = enum
HTTP_VERSION* = enum
HTTP_VERSION_NONE, HTTP_VERSION_1_0, HTTP_VERSION_1_1, HTTP_VERSION_LAST
TNETRC_OPTION* = enum
NETRC_OPTION* = enum
NETRC_IGNORED, NETRC_OPTIONAL, NETRC_REQUIRED, NETRC_LAST
TSSL_VERSION* = enum
SSL_VERSION* = enum
SSLVERSION_DEFAULT, SSLVERSION_TLSv1, SSLVERSION_SSLv2, SSLVERSION_SSLv3,
SSLVERSION_LAST
TTIMECOND* = enum
TIMECOND* = enum
TIMECOND_NONE, TIMECOND_IFMODSINCE, TIMECOND_IFUNMODSINCE, TIMECOND_LASTMOD,
TIMECOND_LAST
Tformoption* = enum
Formoption* = enum
FORM_NOTHING, FORM_COPYNAME, FORM_PTRNAME, FORM_NAMELENGTH,
FORM_COPYCONTENTS, FORM_PTRCONTENTS, FORM_CONTENTSLENGTH, FORM_FILECONTENT,
FORM_ARRAY, FORM_OBSOLETE, FORM_FILE, FORM_BUFFER, FORM_BUFFERPTR,
FORM_BUFFERLENGTH, FORM_CONTENTTYPE, FORM_CONTENTHEADER, FORM_FILENAME,
FORM_END, FORM_OBSOLETE2, FORM_LASTENTRY
Tforms*{.pure, final.} = object
option*: Tformoption
Forms*{.pure, final.} = object
option*: Formoption
value*: cstring
TFORMcode* = enum
FORMcode* = enum
FORMADD_OK, FORMADD_MEMORY, FORMADD_OPTION_TWICE, FORMADD_NULL,
FORMADD_UNKNOWN_OPTION, FORMADD_INCOMPLETE, FORMADD_ILLEGAL_ARRAY,
FORMADD_DISABLED, FORMADD_LAST
Tformget_callback* = proc (arg: pointer, buf: cstring, length: int): int{.
Formget_callback* = proc (arg: pointer, buf: cstring, length: int): int{.
cdecl.}
Tslist*{.pure, final.} = object
Slist*{.pure, final.} = object
data*: cstring
next*: Pslist
TINFO* = enum
INFO* = enum
INFO_NONE = 0, INFO_LASTONE = 30, INFO_EFFECTIVE_URL = 0x00100000 + 1,
INFO_CONTENT_TYPE = 0x00100000 + 18, INFO_PRIVATE = 0x00100000 + 21,
INFO_FTP_ENTRY_PATH = 0x00100000 + 30, INFO_RESPONSE_CODE = 0x00200000 + 2,
@ -261,31 +261,31 @@ type
INFO_STARTTRANSFER_TIME = 0x00300000 + 17,
INFO_REDIRECT_TIME = 0x00300000 + 19, INFO_SSL_ENGINES = 0x00400000 + 27,
INFO_COOKIELIST = 0x00400000 + 28
Tclosepolicy* = enum
Closepolicy* = enum
CLOSEPOLICY_NONE, CLOSEPOLICY_OLDEST, CLOSEPOLICY_LEAST_RECENTLY_USED,
CLOSEPOLICY_LEAST_TRAFFIC, CLOSEPOLICY_SLOWEST, CLOSEPOLICY_CALLBACK,
CLOSEPOLICY_LAST
Tlock_data* = enum
Lock_data* = enum
LOCK_DATA_NONE = 0, LOCK_DATA_SHARE, LOCK_DATA_COOKIE, LOCK_DATA_DNS,
LOCK_DATA_SSL_SESSION, LOCK_DATA_CONNECT, LOCK_DATA_LAST
Tlock_access* = enum
Lock_access* = enum
LOCK_ACCESS_NONE = 0, LOCK_ACCESS_SHARED = 1, LOCK_ACCESS_SINGLE = 2,
LOCK_ACCESS_LAST
Tlock_function* = proc (handle: PCurl, data: Tlock_data,
locktype: Tlock_access,
Lock_function* = proc (handle: PCurl, data: Lock_data,
locktype: Lock_access,
userptr: pointer){.cdecl.}
Tunlock_function* = proc (handle: PCurl, data: Tlock_data, userptr: pointer){.
Unlock_function* = proc (handle: PCurl, data: Lock_data, userptr: pointer){.
cdecl.}
TSH* = pointer
TSHcode* = enum
SH* = pointer
SHcode* = enum
SHE_OK, SHE_BAD_OPTION, SHE_IN_USE, SHE_INVALID, SHE_NOMEM, SHE_LAST
TSHoption* = enum
SHoption* = enum
SHOPT_NONE, SHOPT_SHARE, SHOPT_UNSHARE, SHOPT_LOCKFUNC, SHOPT_UNLOCKFUNC,
SHOPT_USERDATA, SHOPT_LAST
Tversion* = enum
Version* = enum
VERSION_FIRST, VERSION_SECOND, VERSION_THIRD, VERSION_LAST
Tversion_info_data*{.pure, final.} = object
age*: Tversion
Version_info_data*{.pure, final.} = object
age*: Version
version*: cstring
version_num*: int32
host*: cstring
@ -299,15 +299,15 @@ type
libidn*: cstring
iconv_ver_num*: int32
TM* = pointer
Tsocket* = int32
TMcode* = enum
M* = pointer
Socket* = int32
Mcode* = enum
M_CALL_MULTI_PERFORM = - 1, M_OK = 0, M_BAD_HANDLE, M_BAD_EASY_HANDLE,
M_OUT_OF_MEMORY, M_INTERNAL_ERROR, M_BAD_SOCKET, M_UNKNOWN_OPTION, M_LAST
TMSGEnum* = enum
MSGEnum* = enum
MSG_NONE, MSG_DONE, MSG_LAST
TMsg*{.pure, final.} = object
msg*: TMSGEnum
Msg*{.pure, final.} = object
msg*: MSGEnum
easy_handle*: PCurl
whatever*: pointer #data : record
# case longint of
@ -315,11 +315,29 @@ type
# 1 : ( result : CURLcode );
# end;
Tsocket_callback* = proc (easy: PCurl, s: Tsocket, what: int32,
Socket_callback* = proc (easy: PCurl, s: Socket, what: int32,
userp, socketp: pointer): int32{.cdecl.}
TMoption* = enum
Moption* = enum
MOPT_SOCKETDATA = 10000 + 2, MOPT_LASTENTRY = 10000 + 3,
MOPT_SOCKETFUNCTION = 20000 + 1
{.deprecated: [TMsg: Msg, TCurl: Curl, Thttppost: Httppost,
Tprogress_callback: Progress_callback, Twrite_callback: Write_callback,
Tread_callback: Read_callback, Tpasswd_callback: Passwd_callback, Tioerr: Ioerr,
Tiocmd: Iocmd, Tioctl_callback: Ioctl_callback, Tmalloc_callback: Malloc_callback,
Tfree_callback: Free_callback, Trealloc_callback: Realloc_callback,
Tstrdup_callback: Strdup_callback, Tcalloc_callback: Calloc_callback,
Tinfotype: Infotype, Tdebug_callback: Debug_callback, Tcode: Code,
Tconv_callback: Conv_callback, Tssl_ctx_callback: Ssl_ctx_callback,
Tproxytype: Proxytype, Tftpssl: Ftpssl, Tftpauth: Ftpauth, Tftpmethod: Ftpmethod,
Toption: Option, THTTP_VERSION: HTTP_VERSION, TNETRC_OPTION: NETRC_OPTION,
TSSL_VERSION: SSL_VERSION, TTIMECOND: TIMECOND, Tformoption: Formoption,
Tforms: Forms, TFORMcode: FORMcode, Tformget_callback: Formget_callback,
Tslist: Slist, TINFO: INFO, Tclosepolicy: Closepolicy, Tlock_data: Lock_data,
Tlock_access: Lock_access, Tlock_function: Lock_function,
Tunlock_function: Unlock_function, TSH: Sh, TSHcode: SHcode, TSHoption: SHoption,
Tversion: Version, Tversion_info_data: Version_info_data, TM: M, Tsocket: Socket,
TMcode: Mcode, TMSGEnum: MsGEnum, Tsocket_callback: Socket_callback,
TMoption: Moption].}
const
OPT_SSLKEYPASSWD* = OPT_SSLCERTPASSWD
@ -413,9 +431,9 @@ proc strequal*(s1, s2: cstring): int32{.cdecl, dynlib: libname,
importc: "curl_strequal".}
proc strnequal*(s1, s2: cstring, n: int): int32{.cdecl, dynlib: libname,
importc: "curl_strnequal".}
proc formadd*(httppost, last_post: PPcurl_httppost): TFORMcode{.cdecl, varargs,
proc formadd*(httppost, last_post: PPcurl_httppost): FORMcode{.cdecl, varargs,
dynlib: libname, importc: "curl_formadd".}
proc formget*(form: Phttppost, arg: pointer, append: Tformget_callback): int32{.
proc formget*(form: Phttppost, arg: pointer, append: Formget_callback): int32{.
cdecl, dynlib: libname, importc: "curl_formget".}
proc formfree*(form: Phttppost){.cdecl, dynlib: libname,
importc: "curl_formfree".}
@ -431,11 +449,11 @@ proc easy_unescape*(handle: PCurl, str: cstring, len: int32, outlength: var int3
proc unescape*(str: cstring, len: int32): cstring{.cdecl, dynlib: libname,
importc: "curl_unescape".}
proc free*(p: pointer){.cdecl, dynlib: libname, importc: "curl_free".}
proc global_init*(flags: int32): Tcode{.cdecl, dynlib: libname,
proc global_init*(flags: int32): Code{.cdecl, dynlib: libname,
importc: "curl_global_init".}
proc global_init_mem*(flags: int32, m: Tmalloc_callback, f: Tfree_callback,
r: Trealloc_callback, s: Tstrdup_callback,
c: Tcalloc_callback): Tcode{.cdecl, dynlib: libname,
proc global_init_mem*(flags: int32, m: Malloc_callback, f: Free_callback,
r: Realloc_callback, s: Strdup_callback,
c: Calloc_callback): Code{.cdecl, dynlib: libname,
importc: "curl_global_init_mem".}
proc global_cleanup*(){.cdecl, dynlib: libname, importc: "curl_global_cleanup".}
proc slist_append*(slist: Pslist, p: cstring): Pslist{.cdecl, dynlib: libname,
@ -445,50 +463,50 @@ proc slist_free_all*(para1: Pslist){.cdecl, dynlib: libname,
proc getdate*(p: cstring, unused: ptr Time): Time{.cdecl, dynlib: libname,
importc: "curl_getdate".}
proc share_init*(): PSH{.cdecl, dynlib: libname, importc: "curl_share_init".}
proc share_setopt*(para1: PSH, option: TSHoption): TSHcode{.cdecl, varargs,
proc share_setopt*(para1: PSH, option: SHoption): SHcode{.cdecl, varargs,
dynlib: libname, importc: "curl_share_setopt".}
proc share_cleanup*(para1: PSH): TSHcode{.cdecl, dynlib: libname,
proc share_cleanup*(para1: PSH): SHcode{.cdecl, dynlib: libname,
importc: "curl_share_cleanup".}
proc version_info*(para1: Tversion): Pversion_info_data{.cdecl, dynlib: libname,
proc version_info*(para1: Version): Pversion_info_data{.cdecl, dynlib: libname,
importc: "curl_version_info".}
proc easy_strerror*(para1: Tcode): cstring{.cdecl, dynlib: libname,
proc easy_strerror*(para1: Code): cstring{.cdecl, dynlib: libname,
importc: "curl_easy_strerror".}
proc share_strerror*(para1: TSHcode): cstring{.cdecl, dynlib: libname,
proc share_strerror*(para1: SHcode): cstring{.cdecl, dynlib: libname,
importc: "curl_share_strerror".}
proc easy_init*(): PCurl{.cdecl, dynlib: libname, importc: "curl_easy_init".}
proc easy_setopt*(curl: PCurl, option: Toption): Tcode{.cdecl, varargs, dynlib: libname,
proc easy_setopt*(curl: PCurl, option: Option): Code{.cdecl, varargs, dynlib: libname,
importc: "curl_easy_setopt".}
proc easy_perform*(curl: PCurl): Tcode{.cdecl, dynlib: libname,
proc easy_perform*(curl: PCurl): Code{.cdecl, dynlib: libname,
importc: "curl_easy_perform".}
proc easy_cleanup*(curl: PCurl){.cdecl, dynlib: libname, importc: "curl_easy_cleanup".}
proc easy_getinfo*(curl: PCurl, info: TINFO): Tcode{.cdecl, varargs, dynlib: libname,
proc easy_getinfo*(curl: PCurl, info: INFO): Code{.cdecl, varargs, dynlib: libname,
importc: "curl_easy_getinfo".}
proc easy_duphandle*(curl: PCurl): PCurl{.cdecl, dynlib: libname,
importc: "curl_easy_duphandle".}
proc easy_reset*(curl: PCurl){.cdecl, dynlib: libname, importc: "curl_easy_reset".}
proc multi_init*(): PM{.cdecl, dynlib: libname, importc: "curl_multi_init".}
proc multi_add_handle*(multi_handle: PM, handle: PCurl): TMcode{.cdecl,
proc multi_add_handle*(multi_handle: PM, handle: PCurl): Mcode{.cdecl,
dynlib: libname, importc: "curl_multi_add_handle".}
proc multi_remove_handle*(multi_handle: PM, handle: PCurl): TMcode{.cdecl,
proc multi_remove_handle*(multi_handle: PM, handle: PCurl): Mcode{.cdecl,
dynlib: libname, importc: "curl_multi_remove_handle".}
proc multi_fdset*(multi_handle: PM, read_fd_set: Pfd_set, write_fd_set: Pfd_set,
exc_fd_set: Pfd_set, max_fd: var int32): TMcode{.cdecl,
exc_fd_set: Pfd_set, max_fd: var int32): Mcode{.cdecl,
dynlib: libname, importc: "curl_multi_fdset".}
proc multi_perform*(multi_handle: PM, running_handles: var int32): TMcode{.
proc multi_perform*(multi_handle: PM, running_handles: var int32): Mcode{.
cdecl, dynlib: libname, importc: "curl_multi_perform".}
proc multi_cleanup*(multi_handle: PM): TMcode{.cdecl, dynlib: libname,
proc multi_cleanup*(multi_handle: PM): Mcode{.cdecl, dynlib: libname,
importc: "curl_multi_cleanup".}
proc multi_info_read*(multi_handle: PM, msgs_in_queue: var int32): PMsg{.cdecl,
dynlib: libname, importc: "curl_multi_info_read".}
proc multi_strerror*(para1: TMcode): cstring{.cdecl, dynlib: libname,
proc multi_strerror*(para1: Mcode): cstring{.cdecl, dynlib: libname,
importc: "curl_multi_strerror".}
proc multi_socket*(multi_handle: PM, s: Tsocket, running_handles: var int32): TMcode{.
proc multi_socket*(multi_handle: PM, s: Socket, running_handles: var int32): Mcode{.
cdecl, dynlib: libname, importc: "curl_multi_socket".}
proc multi_socket_all*(multi_handle: PM, running_handles: var int32): TMcode{.
proc multi_socket_all*(multi_handle: PM, running_handles: var int32): Mcode{.
cdecl, dynlib: libname, importc: "curl_multi_socket_all".}
proc multi_timeout*(multi_handle: PM, milliseconds: var int32): TMcode{.cdecl,
proc multi_timeout*(multi_handle: PM, milliseconds: var int32): Mcode{.cdecl,
dynlib: libname, importc: "curl_multi_timeout".}
proc multi_setopt*(multi_handle: PM, option: TMoption): TMcode{.cdecl, varargs,
proc multi_setopt*(multi_handle: PM, option: Moption): Mcode{.cdecl, varargs,
dynlib: libname, importc: "curl_multi_setopt".}
proc multi_assign*(multi_handle: PM, sockfd: Tsocket, sockp: pointer): TMcode{.
proc multi_assign*(multi_handle: PM, sockfd: Socket, sockp: pointer): Mcode{.
cdecl, dynlib: libname, importc: "curl_multi_assign".}

View file

@ -58,8 +58,9 @@ else:
{.pragma: mylib, dynlib: "libffi.so".}
type
TArg* = int
TSArg* = int
Arg* = int
SArg* = int
{.deprecated: [TArg: Arg, TSArg: SArg].}
when defined(windows) and defined(x86):
type
@ -105,67 +106,71 @@ const
tkSMALL_STRUCT_4B* = (tkLAST + 3)
type
TType* = object
Type* = object
size*: int
alignment*: uint16
typ*: uint16
elements*: ptr ptr TType
elements*: ptr ptr Type
{.deprecated: [TType: Type].}
var
type_void* {.importc: "ffi_type_void", mylib.}: TType
type_uint8* {.importc: "ffi_type_uint8", mylib.}: TType
type_sint8* {.importc: "ffi_type_sint8", mylib.}: TType
type_uint16* {.importc: "ffi_type_uint16", mylib.}: TType
type_sint16* {.importc: "ffi_type_sint16", mylib.}: TType
type_uint32* {.importc: "ffi_type_uint32", mylib.}: TType
type_sint32* {.importc: "ffi_type_sint32", mylib.}: TType
type_uint64* {.importc: "ffi_type_uint64", mylib.}: TType
type_sint64* {.importc: "ffi_type_sint64", mylib.}: TType
type_float* {.importc: "ffi_type_float", mylib.}: TType
type_double* {.importc: "ffi_type_double", mylib.}: TType
type_pointer* {.importc: "ffi_type_pointer", mylib.}: TType
type_longdouble* {.importc: "ffi_type_longdouble", mylib.}: TType
type_void* {.importc: "ffi_type_void", mylib.}: Type
type_uint8* {.importc: "ffi_type_uint8", mylib.}: Type
type_sint8* {.importc: "ffi_type_sint8", mylib.}: Type
type_uint16* {.importc: "ffi_type_uint16", mylib.}: Type
type_sint16* {.importc: "ffi_type_sint16", mylib.}: Type
type_uint32* {.importc: "ffi_type_uint32", mylib.}: Type
type_sint32* {.importc: "ffi_type_sint32", mylib.}: Type
type_uint64* {.importc: "ffi_type_uint64", mylib.}: Type
type_sint64* {.importc: "ffi_type_sint64", mylib.}: Type
type_float* {.importc: "ffi_type_float", mylib.}: Type
type_double* {.importc: "ffi_type_double", mylib.}: Type
type_pointer* {.importc: "ffi_type_pointer", mylib.}: Type
type_longdouble* {.importc: "ffi_type_longdouble", mylib.}: Type
type
Tstatus* {.size: sizeof(cint).} = enum
Status* {.size: sizeof(cint).} = enum
OK, BAD_TYPEDEF, BAD_ABI
TTypeKind* = cuint
TypeKind* = cuint
TCif* {.pure, final.} = object
abi*: TABI
nargs*: cuint
arg_types*: ptr ptr TType
rtype*: ptr TType
arg_types*: ptr ptr Type
rtype*: ptr Type
bytes*: cuint
flags*: cuint
{.deprecated: [Tstatus: Status].}
type
TRaw* = object
sint*: TSArg
Raw* = object
sint*: SArg
{.deprecated: [TRaw: Raw].}
proc raw_call*(cif: var Tcif; fn: proc () {.cdecl.}; rvalue: pointer;
avalue: ptr TRaw) {.cdecl, importc: "ffi_raw_call", mylib.}
proc ptrarray_to_raw*(cif: var Tcif; args: ptr pointer; raw: ptr TRaw) {.cdecl,
avalue: ptr Raw) {.cdecl, importc: "ffi_raw_call", mylib.}
proc ptrarray_to_raw*(cif: var Tcif; args: ptr pointer; raw: ptr Raw) {.cdecl,
importc: "ffi_ptrarray_to_raw", mylib.}
proc raw_to_ptrarray*(cif: var Tcif; raw: ptr TRaw; args: ptr pointer) {.cdecl,
proc raw_to_ptrarray*(cif: var Tcif; raw: ptr Raw; args: ptr pointer) {.cdecl,
importc: "ffi_raw_to_ptrarray", mylib.}
proc raw_size*(cif: var Tcif): int {.cdecl, importc: "ffi_raw_size", mylib.}
proc prep_cif*(cif: var Tcif; abi: TABI; nargs: cuint; rtype: ptr TType;
atypes: ptr ptr TType): TStatus {.cdecl, importc: "ffi_prep_cif",
proc prep_cif*(cif: var Tcif; abi: TABI; nargs: cuint; rtype: ptr Type;
atypes: ptr ptr Type): Status {.cdecl, importc: "ffi_prep_cif",
mylib.}
proc call*(cif: var Tcif; fn: proc () {.cdecl.}; rvalue: pointer;
avalue: ptr pointer) {.cdecl, importc: "ffi_call", mylib.}
# the same with an easier interface:
type
TParamList* = array[0..100, ptr TType]
TArgList* = array[0..100, pointer]
ParamList* = array[0..100, ptr Type]
ArgList* = array[0..100, pointer]
{.deprecated: [TParamList: ParamList, TArgList: ArgList].}
proc prep_cif*(cif: var Tcif; abi: TABI; nargs: cuint; rtype: ptr TType;
atypes: TParamList): TStatus {.cdecl, importc: "ffi_prep_cif",
proc prep_cif*(cif: var Tcif; abi: TABI; nargs: cuint; rtype: ptr Type;
atypes: ParamList): Status {.cdecl, importc: "ffi_prep_cif",
mylib.}
proc call*(cif: var Tcif; fn, rvalue: pointer;
avalue: TArgList) {.cdecl, importc: "ffi_call", mylib.}
avalue: ArgList) {.cdecl, importc: "ffi_call", mylib.}
# Useful for eliminating compiler warnings
##define FFI_FN(f) ((void (*)(void))f)

View file

@ -21,24 +21,24 @@ else:
const svmdll* = "libsvm.so"
type
Tnode*{.pure, final.} = object
Node*{.pure, final.} = object
index*: cint
value*: cdouble
Tproblem*{.pure, final.} = object
Problem*{.pure, final.} = object
L*: cint
y*: ptr cdouble
x*: ptr ptr Tnode
x*: ptr ptr Node
Ttype*{.size: sizeof(cint).} = enum
Type*{.size: sizeof(cint).} = enum
C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR
TKernelType*{.size: sizeof(cint).} = enum
KernelType*{.size: sizeof(cint).} = enum
LINEAR, POLY, RBF, SIGMOID, PRECOMPUTED
Tparameter*{.pure, final.} = object
typ*: TType
kernelType*: TKernelType
Parameter*{.pure, final.} = object
typ*: Type
kernelType*: KernelType
degree*: cint # for poly
gamma*: cdouble # for poly/rbf/sigmoid
coef0*: cdouble # for poly/sigmoid
@ -53,18 +53,19 @@ type
p*: cdouble # for EPSILON_SVR
shrinking*: cint # use the shrinking heuristics
probability*: cint # do probability estimates
{.deprecated: [Tnode: Node, Tproblem: Problem, Ttype: Type,
TKernelType: KernelType, Tparameter: Parameter].}
#
# svm_model
#
type
TModel*{.pure, final.} = object
param*: Tparameter # parameter
Model*{.pure, final.} = object
param*: Parameter # parameter
nr_class*: cint # number of classes, = 2 in regression/one class svm
L*: cint # total #SV
SV*: ptr ptr Tnode # SVs (SV[l])
SV*: ptr ptr Node # SVs (SV[l])
sv_coef*: ptr ptr cdouble # coefficients for SVs in decision functions (sv_coef[k-1][l])
rho*: ptr cdouble # constants in decision functions (rho[k*(k-1)/2])
probA*: ptr cdouble # pariwise probability information
@ -74,42 +75,42 @@ type
# nSV[0] + nSV[1] + ... + nSV[k-1] = l
# XXX
free_sv*: cint # 1 if svm_model is created by svm_load_model
# 0 if svm_model is created by svm_train
# 0 if svm_model is created by svm_train
{.deprecated: [TModel: Model].}
proc train*(prob: ptr Tproblem, param: ptr Tparameter): ptr Tmodel{.cdecl,
proc train*(prob: ptr Problem, param: ptr Parameter): ptr Model{.cdecl,
importc: "svm_train", dynlib: svmdll.}
proc cross_validation*(prob: ptr Tproblem, param: ptr Tparameter, nr_fold: cint,
proc cross_validation*(prob: ptr Problem, param: ptr Parameter, nr_fold: cint,
target: ptr cdouble){.cdecl,
importc: "svm_cross_validation", dynlib: svmdll.}
proc save_model*(model_file_name: cstring, model: ptr Tmodel): cint{.cdecl,
proc save_model*(model_file_name: cstring, model: ptr Model): cint{.cdecl,
importc: "svm_save_model", dynlib: svmdll.}
proc load_model*(model_file_name: cstring): ptr Tmodel{.cdecl,
proc load_model*(model_file_name: cstring): ptr Model{.cdecl,
importc: "svm_load_model", dynlib: svmdll.}
proc get_svm_type*(model: ptr Tmodel): cint{.cdecl, importc: "svm_get_svm_type",
proc get_svm_type*(model: ptr Model): cint{.cdecl, importc: "svm_get_svm_type",
dynlib: svmdll.}
proc get_nr_class*(model: ptr Tmodel): cint{.cdecl, importc: "svm_get_nr_class",
proc get_nr_class*(model: ptr Model): cint{.cdecl, importc: "svm_get_nr_class",
dynlib: svmdll.}
proc get_labels*(model: ptr Tmodel, label: ptr cint){.cdecl,
proc get_labels*(model: ptr Model, label: ptr cint){.cdecl,
importc: "svm_get_labels", dynlib: svmdll.}
proc get_svr_probability*(model: ptr Tmodel): cdouble{.cdecl,
proc get_svr_probability*(model: ptr Model): cdouble{.cdecl,
importc: "svm_get_svr_probability", dynlib: svmdll.}
proc predict_values*(model: ptr Tmodel, x: ptr Tnode, dec_values: ptr cdouble): cdouble{.
proc predict_values*(model: ptr Model, x: ptr Node, dec_values: ptr cdouble): cdouble{.
cdecl, importc: "svm_predict_values", dynlib: svmdll.}
proc predict*(model: ptr Tmodel, x: ptr Tnode): cdouble{.cdecl,
proc predict*(model: ptr Model, x: ptr Node): cdouble{.cdecl,
importc: "svm_predict", dynlib: svmdll.}
proc predict_probability*(model: ptr Tmodel, x: ptr Tnode,
proc predict_probability*(model: ptr Model, x: ptr Node,
prob_estimates: ptr cdouble): cdouble{.cdecl,
importc: "svm_predict_probability", dynlib: svmdll.}
proc free_model_content*(model_ptr: ptr Tmodel){.cdecl,
proc free_model_content*(model_ptr: ptr Model){.cdecl,
importc: "svm_free_model_content", dynlib: svmdll.}
proc free_and_destroy_model*(model_ptr_ptr: ptr ptr Tmodel){.cdecl,
proc free_and_destroy_model*(model_ptr_ptr: ptr ptr Model){.cdecl,
importc: "svm_free_and_destroy_model", dynlib: svmdll.}
proc destroy_param*(param: ptr Tparameter){.cdecl, importc: "svm_destroy_param",
proc destroy_param*(param: ptr Parameter){.cdecl, importc: "svm_destroy_param",
dynlib: svmdll.}
proc check_parameter*(prob: ptr Tproblem, param: ptr Tparameter): cstring{.
proc check_parameter*(prob: ptr Problem, param: ptr Parameter): cstring{.
cdecl, importc: "svm_check_parameter", dynlib: svmdll.}
proc check_probability_model*(model: ptr Tmodel): cint{.cdecl,
proc check_probability_model*(model: ptr Model): cint{.cdecl,
importc: "svm_check_probability_model", dynlib: svmdll.}
proc set_print_string_function*(print_func: proc (arg: cstring) {.cdecl.}){.

Some files were not shown because too many files have changed in this diff Show more