Merge branch 'master' of github.com:Araq/Nimrod

This commit is contained in:
Araq
2013-10-31 22:34:15 +01:00
25 changed files with 3237 additions and 2222 deletions

View File

@@ -621,7 +621,7 @@ type
proc initSameTypeClosure: TSameTypeClosure =
# we do the initialization lazily for performance (avoids memory allocations)
nil
proc containsOrIncl(c: var TSameTypeClosure, a, b: PType): bool =
result = not IsNil(c.s) and c.s.contains((a.id, b.id))
if not result:
@@ -750,9 +750,9 @@ template IfFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} =
proc sameObjectTypes*(a, b: PType): bool =
# specialized for efficiency (sigmatch uses it)
IfFastObjectTypeCheckFailed(a, b):
IfFastObjectTypeCheckFailed(a, b):
var c = initSameTypeClosure()
result = sameTypeAux(a, b, c)
result = sameTypeAux(a, b, c)
proc sameDistinctTypes*(a, b: PType): bool {.inline.} =
result = sameObjectTypes(a, b)
@@ -808,11 +808,11 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
if containsOrIncl(c, a, b): return true
proc sameFlags(a, b: PType): bool {.inline.} =
result = eqTypeFlags*a.flags == eqTypeFlags*b.flags
result = eqTypeFlags*a.flags == eqTypeFlags*b.flags
if x == y: return true
var a = skipTypes(x, {tyGenericInst})
var b = skipTypes(y, {tyGenericInst})
var b = skipTypes(y, {tyGenericInst})
assert(a != nil)
assert(b != nil)
if a.kind != b.kind:
@@ -824,7 +824,7 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
if a.kind != b.kind: return false
of dcEqOrDistinctOf:
while a.kind == tyDistinct: a = a.sons[0]
if a.kind != b.kind: return false
if a.kind != b.kind: return false
case a.Kind
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
tyInt..tyBigNum, tyStmt:
@@ -837,15 +837,19 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
result = sameObjectStructures(a, b, c) and sameFlags(a, b)
of tyDistinct:
CycleCheck()
if c.cmp == dcEq: result = sameDistinctTypes(a, b) and sameFlags(a, b)
else: result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b)
if c.cmp == dcEq:
if sameFlags(a, b):
IfFastObjectTypeCheckFailed(a, b):
result = sameTypeAux(a.sons[0], b.sons[0], c)
else:
result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b)
of tyEnum, tyForward, tyProxy:
# XXX generic enums do not make much sense, but require structural checking
result = a.id == b.id and sameFlags(a, b)
of tyTuple:
CycleCheck()
result = sameTuple(a, b, c) and sameFlags(a, b)
of tyGenericInst:
of tyGenericInst:
result = sameTypeAux(lastSon(a), lastSon(b), c)
of tyTypeDesc:
if c.cmp == dcEqIgnoreDistinct: result = false
@@ -858,7 +862,7 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
tyOrdinal, tyTypeClass:
CycleCheck()
CycleCheck()
result = sameChildrenAux(a, b, c) and sameFlags(a, b)
if result and (a.kind == tyProc):
result = a.callConv == b.callConv
@@ -867,7 +871,7 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
result = SameTypeOrNilAux(a.sons[0], b.sons[0], c) and
SameValue(a.n.sons[0], b.n.sons[0]) and
SameValue(a.n.sons[1], b.n.sons[1])
of tyNone: result = false
of tyNone: result = false
proc sameType*(x, y: PType): bool =
var c = initSameTypeClosure()

View File

@@ -52,6 +52,11 @@ For a release version use::
nimrod c koch.nim
./koch boot -d:release
And for a debug version compatible with GDB::
nimrod c koch.nim
./koch boot --debuginfo --linedir:on
The ``koch`` program is Nimrod's maintenance script. It is a replacement for
make and shell scripting with the advantage that it is much more portable.
@@ -64,7 +69,7 @@ Coding Guidelines
* Max line length is 80 characters.
* Provide spaces around binary operators if that enhances readability.
* Use a space after a colon, but not before it.
* Start types with a capital ``T``, unless they are pointers which start
* Start types with a capital ``T``, unless they are pointers/references which start
with ``P``.

View File

@@ -893,11 +893,12 @@ integers from 0 to ``len(A)-1``. An array expression may be constructed by the
array constructor ``[]``.
`Sequences`:idx: are similar to arrays but of dynamic length which may change
during runtime (like strings). A sequence ``S`` is always indexed by integers
from 0 to ``len(S)-1`` and its bounds are checked. Sequences can be
constructed by the array constructor ``[]`` in conjunction with the array to
sequence operator ``@``. Another way to allocate space for a sequence is to
call the built-in ``newSeq`` procedure.
during runtime (like strings). Sequences are implemented as growable arrays,
allocating pieces of memory as items are added. A sequence ``S`` is always
indexed by integers from 0 to ``len(S)-1`` and its bounds are checked.
Sequences can be constructed by the array constructor ``[]`` in conjunction
with the array to sequence operator ``@``. Another way to allocate space for a
sequence is to call the built-in ``newSeq`` procedure.
A sequence may be passed to a parameter that is of type *open array*.
@@ -4673,9 +4674,10 @@ A proc can be marked with the `noStackFrame`:idx: pragma to tell the compiler
it should not generate a stack frame for the proc. There are also no exit
statements like ``return result;`` generated and the generated C function is
declared as ``__declspec(naked)`` or ``__attribute__((naked))`` (depending on
the used C compiler). This is useful for procs that only consist of an
assembler statement.
the used C compiler).
**Note**: This pragma should only be used by procs which consist solely of assembler
statements.
error pragma
------------

View File

@@ -81,6 +81,8 @@ else:
## A type representing a directory stream.
type
TSocketHandle* = distinct cint # The type used to represent socket descriptors
Tdirent* {.importc: "struct dirent",
header: "<dirent.h>", final, pure.} = object ## dirent_t struct
d_ino*: TIno ## File serial number.
@@ -1791,7 +1793,7 @@ proc dlopen*(a1: cstring, a2: cint): pointer {.importc, header: "<dlfcn.h>".}
proc dlsym*(a1: pointer, a2: cstring): pointer {.importc, header: "<dlfcn.h>".}
proc creat*(a1: cstring, a2: Tmode): cint {.importc, header: "<fcntl.h>".}
proc fcntl*(a1: cint, a2: cint): cint {.varargs, importc, header: "<fcntl.h>".}
proc fcntl*(a1: cint | TSocketHandle, a2: cint): cint {.varargs, importc, header: "<fcntl.h>".}
proc open*(a1: cstring, a2: cint): cint {.varargs, importc, header: "<fcntl.h>".}
proc posix_fadvise*(a1: cint, a2, a3: Toff, a4: cint): cint {.
importc, header: "<fcntl.h>".}
@@ -2068,7 +2070,7 @@ proc access*(a1: cstring, a2: cint): cint {.importc, header: "<unistd.h>".}
proc alarm*(a1: cint): cint {.importc, header: "<unistd.h>".}
proc chdir*(a1: cstring): cint {.importc, header: "<unistd.h>".}
proc chown*(a1: cstring, a2: Tuid, a3: Tgid): cint {.importc, header: "<unistd.h>".}
proc close*(a1: cint): cint {.importc, header: "<unistd.h>".}
proc close*(a1: cint | TSocketHandle): cint {.importc, header: "<unistd.h>".}
proc confstr*(a1: cint, a2: cstring, a3: int): int {.importc, header: "<unistd.h>".}
proc crypt*(a1, a2: cstring): cstring {.importc, header: "<unistd.h>".}
proc ctermid*(a1: cstring): cstring {.importc, header: "<unistd.h>".}
@@ -2346,9 +2348,9 @@ proc strerror*(errnum: cint): cstring {.importc, header: "<string.h>".}
proc hstrerror*(herrnum: cint): cstring {.importc, header: "<netdb.h>".}
proc FD_CLR*(a1: cint, a2: var Tfd_set) {.importc, header: "<sys/select.h>".}
proc FD_ISSET*(a1: cint, a2: var Tfd_set): cint {.
proc FD_ISSET*(a1: cint | TSocketHandle, a2: var Tfd_set): cint {.
importc, header: "<sys/select.h>".}
proc FD_SET*(a1: cint, a2: var Tfd_set) {.importc, header: "<sys/select.h>".}
proc FD_SET*(a1: cint | TSocketHandle, a2: var Tfd_set) {.importc, header: "<sys/select.h>".}
proc FD_ZERO*(a1: var Tfd_set) {.importc, header: "<sys/select.h>".}
proc pselect*(a1: cint, a2, a3, a4: ptr Tfd_set, a5: ptr ttimespec,
@@ -2428,44 +2430,49 @@ proc CMSG_NXTHDR*(mhdr: ptr TMsgHdr, cmsg: ptr TCMsgHdr): ptr TCmsgHdr {.
proc CMSG_FIRSTHDR*(mhdr: ptr TMsgHdr): ptr TCMsgHdr {.
importc, header: "<sys/socket.h>".}
proc accept*(a1: cint, a2: ptr Tsockaddr, a3: ptr Tsocklen): cint {.
const
INVALID_SOCKET* = TSocketHandle(-1)
proc `==`*(x, y: TSocketHandle): bool {.borrow.}
proc accept*(a1: TSocketHandle, a2: ptr Tsockaddr, a3: ptr Tsocklen): TSocketHandle {.
importc, header: "<sys/socket.h>".}
proc bindSocket*(a1: cint, a2: ptr Tsockaddr, a3: Tsocklen): cint {.
proc bindSocket*(a1: TSocketHandle, a2: ptr Tsockaddr, a3: Tsocklen): cint {.
importc: "bind", header: "<sys/socket.h>".}
## is Posix's ``bind``, because ``bind`` is a reserved word
proc connect*(a1: cint, a2: ptr Tsockaddr, a3: Tsocklen): cint {.
proc connect*(a1: TSocketHandle, a2: ptr Tsockaddr, a3: Tsocklen): cint {.
importc, header: "<sys/socket.h>".}
proc getpeername*(a1: cint, a2: ptr Tsockaddr, a3: ptr Tsocklen): cint {.
proc getpeername*(a1: TSocketHandle, a2: ptr Tsockaddr, a3: ptr Tsocklen): cint {.
importc, header: "<sys/socket.h>".}
proc getsockname*(a1: cint, a2: ptr Tsockaddr, a3: ptr Tsocklen): cint {.
proc getsockname*(a1: TSocketHandle, a2: ptr Tsockaddr, a3: ptr Tsocklen): cint {.
importc, header: "<sys/socket.h>".}
proc getsockopt*(a1, a2, a3: cint, a4: pointer, a5: ptr Tsocklen): cint {.
proc getsockopt*(a1: TSocketHandle, a2, a3: cint, a4: pointer, a5: ptr Tsocklen): cint {.
importc, header: "<sys/socket.h>".}
proc listen*(a1, a2: cint): cint {.
proc listen*(a1: TSocketHandle, a2: cint): cint {.
importc, header: "<sys/socket.h>".}
proc recv*(a1: cint, a2: pointer, a3: int, a4: cint): int {.
proc recv*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint): int {.
importc, header: "<sys/socket.h>".}
proc recvfrom*(a1: cint, a2: pointer, a3: int, a4: cint,
proc recvfrom*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint,
a5: ptr Tsockaddr, a6: ptr Tsocklen): int {.
importc, header: "<sys/socket.h>".}
proc recvmsg*(a1: cint, a2: ptr Tmsghdr, a3: cint): int {.
proc recvmsg*(a1: TSocketHandle, a2: ptr Tmsghdr, a3: cint): int {.
importc, header: "<sys/socket.h>".}
proc send*(a1: cint, a2: pointer, a3: int, a4: cint): int {.
proc send*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint): int {.
importc, header: "<sys/socket.h>".}
proc sendmsg*(a1: cint, a2: ptr Tmsghdr, a3: cint): int {.
proc sendmsg*(a1: TSocketHandle, a2: ptr Tmsghdr, a3: cint): int {.
importc, header: "<sys/socket.h>".}
proc sendto*(a1: cint, a2: pointer, a3: int, a4: cint, a5: ptr Tsockaddr,
proc sendto*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint, a5: ptr Tsockaddr,
a6: Tsocklen): int {.
importc, header: "<sys/socket.h>".}
proc setsockopt*(a1, a2, a3: cint, a4: pointer, a5: Tsocklen): cint {.
proc setsockopt*(a1: TSocketHandle, a2, a3: cint, a4: pointer, a5: Tsocklen): cint {.
importc, header: "<sys/socket.h>".}
proc shutdown*(a1, a2: cint): cint {.
proc shutdown*(a1: TSocketHandle, a2: cint): cint {.
importc, header: "<sys/socket.h>".}
proc socket*(a1, a2, a3: cint): cint {.
proc socket*(a1, a2, a3: cint): TSocketHandle {.
importc, header: "<sys/socket.h>".}
proc sockatmark*(a1: cint): cint {.
importc, header: "<sys/socket.h>".}

View File

@@ -89,13 +89,13 @@ import sockets, os
## getSocket(s).accept(client)
when defined(windows):
from winlean import TTimeVal, TFdSet, FD_ZERO, FD_SET, FD_ISSET, select
from winlean import TTimeVal, TSocketHandle, TFdSet, FD_ZERO, FD_SET, FD_ISSET, select
else:
from posix import TTimeVal, TFdSet, FD_ZERO, FD_SET, FD_ISSET, select
from posix import TTimeVal, TSocketHandle, TFdSet, FD_ZERO, FD_SET, FD_ISSET, select
type
TDelegate* = object
fd*: cint
fd*: TSocketHandle
deleVal*: PObject
handleRead*: proc (h: PObject) {.nimcall.}
@@ -213,6 +213,7 @@ proc asyncSockHandleRead(h: PObject) =
else:
PAsyncSocket(h).handleAccept(PAsyncSocket(h))
proc close*(sock: PAsyncSocket)
proc asyncSockHandleWrite(h: PObject) =
when defined(ssl):
if PAsyncSocket(h).socket.isSSL and not
@@ -230,15 +231,19 @@ proc asyncSockHandleWrite(h: PObject) =
else:
if PAsyncSocket(h).sendBuffer != "":
let sock = PAsyncSocket(h)
let bytesSent = sock.socket.sendAsync(sock.sendBuffer)
assert bytesSent > 0
if bytesSent != sock.sendBuffer.len:
sock.sendBuffer = sock.sendBuffer[bytesSent .. -1]
elif bytesSent == sock.sendBuffer.len:
sock.sendBuffer = ""
if PAsyncSocket(h).handleWrite != nil:
PAsyncSocket(h).handleWrite(PAsyncSocket(h))
try:
let bytesSent = sock.socket.sendAsync(sock.sendBuffer)
assert bytesSent > 0
if bytesSent != sock.sendBuffer.len:
sock.sendBuffer = sock.sendBuffer[bytesSent .. -1]
elif bytesSent == sock.sendBuffer.len:
sock.sendBuffer = ""
if PAsyncSocket(h).handleWrite != nil:
PAsyncSocket(h).handleWrite(PAsyncSocket(h))
except EOS:
# Most likely the socket closed before the full buffer could be sent to it.
sock.close() # TODO: Provide a handleError for users?
else:
if PAsyncSocket(h).handleWrite != nil:
PAsyncSocket(h).handleWrite(PAsyncSocket(h))

View File

@@ -1,117 +1,127 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements a base64 encoder and decoder.
const
cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
proc encode*(s: string, lineLen = 75, newLine="\13\10"): string =
## encodes `s` into base64 representation. After `lineLen` characters, a
## `newline` is added.
var total = ((len(s) + 2) div 3) * 4
var numLines = (total + lineLen - 1) div lineLen
#
#
# Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements a base64 encoder and decoder.
const
cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
template encodeInternal(s: expr, lineLen: int, newLine: string): stmt {.immediate.} =
## encodes `s` into base64 representation. After `lineLen` characters, a
## `newline` is added.
var total = ((len(s) + 2) div 3) * 4
var numLines = (total + lineLen - 1) div lineLen
if numLines > 0: inc(total, (numLines-1) * newLine.len)
result = newString(total)
var i = 0
var r = 0
var currLine = 0
while i < s.len - 2:
var a = ord(s[i])
var b = ord(s[i+1])
var c = ord(s[i+2])
result[r] = cb64[a shr 2]
result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
result[r+2] = cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)]
result[r+3] = cb64[c and 0x3F]
inc(r, 4)
inc(i, 3)
inc(currLine, 4)
if currLine >= lineLen and i != s.len-2:
for x in items(newLine):
result[r] = x
inc(r)
currLine = 0
if i < s.len-1:
var a = ord(s[i])
var b = ord(s[i+1])
result[r] = cb64[a shr 2]
result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
result[r+2] = cb64[((b and 0x0F) shl 2)]
result[r+3] = '='
if r+4 != result.len:
setLen(result, r+4)
elif i < s.len:
var a = ord(s[i])
result[r] = cb64[a shr 2]
result[r+1] = cb64[(a and 3) shl 4]
result[r+2] = '='
result[r+3] = '='
if r+4 != result.len:
setLen(result, r+4)
else:
assert(r == result.len)
proc decodeByte(b: char): int {.inline.} =
case b
of '+': result = ord('>')
of '0'..'9': result = ord(b) + 4
of 'A'..'Z': result = ord(b) - ord('A')
of 'a'..'z': result = ord(b) - 71
else: result = 63
proc decode*(s: string): string =
## decodes a string in base64 representation back into its original form.
## Whitespace is skipped.
const Whitespace = {' ', '\t', '\v', '\r', '\l', '\f'}
var total = ((len(s) + 3) div 4) * 3
# total is an upper bound, as we will skip arbitrary whitespace:
result = newString(total)
var i = 0
var r = 0
while true:
while s[i] in Whitespace: inc(i)
if i < s.len-3:
var a = s[i].decodeByte
var b = s[i+1].decodeByte
var c = s[i+2].decodeByte
var d = s[i+3].decodeByte
result[r] = chr((a shl 2) and 0xff or ((b shr 4) and 0x03))
result[r+1] = chr((b shl 4) and 0xff or ((c shr 2) and 0x0F))
result[r+2] = chr((c shl 6) and 0xff or (d and 0x3F))
inc(r, 3)
inc(i, 4)
else: break
assert i == s.len
# adjust the length:
if i > 0 and s[i-1] == '=':
dec(r)
if i > 1 and s[i-2] == '=': dec(r)
setLen(result, r)
when isMainModule:
assert encode("leasure.") == "bGVhc3VyZS4="
assert encode("easure.") == "ZWFzdXJlLg=="
assert encode("asure.") == "YXN1cmUu"
assert encode("sure.") == "c3VyZS4="
const longText = """Man is distinguished, not only by his reason, but by this
singular passion from other animals, which is a lust of the mind,
that by a perseverance of delight in the continued and indefatigable
generation of knowledge, exceeds the short vehemence of any carnal
pleasure."""
const tests = ["", "abc", "xyz", "man", "leasure.", "sure.", "easure.",
"asure.", longText]
for t in items(tests):
assert decode(encode(t)) == t
result = newString(total)
var i = 0
var r = 0
var currLine = 0
while i < s.len - 2:
var a = ord(s[i])
var b = ord(s[i+1])
var c = ord(s[i+2])
result[r] = cb64[a shr 2]
result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
result[r+2] = cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)]
result[r+3] = cb64[c and 0x3F]
inc(r, 4)
inc(i, 3)
inc(currLine, 4)
if currLine >= lineLen and i != s.len-2:
for x in items(newLine):
result[r] = x
inc(r)
currLine = 0
if i < s.len-1:
var a = ord(s[i])
var b = ord(s[i+1])
result[r] = cb64[a shr 2]
result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
result[r+2] = cb64[((b and 0x0F) shl 2)]
result[r+3] = '='
if r+4 != result.len:
setLen(result, r+4)
elif i < s.len:
var a = ord(s[i])
result[r] = cb64[a shr 2]
result[r+1] = cb64[(a and 3) shl 4]
result[r+2] = '='
result[r+3] = '='
if r+4 != result.len:
setLen(result, r+4)
else:
assert(r == result.len)
proc encode*[T:TInteger|char](s: openarray[T], lineLen = 75, newLine="\13\10"): string =
## encodes `s` into base64 representation. After `lineLen` characters, a
## `newline` is added.
encodeInternal(s, lineLen, newLine)
proc encode*(s: string, lineLen = 75, newLine="\13\10"): string =
## encodes `s` into base64 representation. After `lineLen` characters, a
## `newline` is added.
encodeInternal(s, lineLen, newLine)
proc decodeByte(b: char): int {.inline.} =
case b
of '+': result = ord('>')
of '0'..'9': result = ord(b) + 4
of 'A'..'Z': result = ord(b) - ord('A')
of 'a'..'z': result = ord(b) - 71
else: result = 63
proc decode*(s: string): string =
## decodes a string in base64 representation back into its original form.
## Whitespace is skipped.
const Whitespace = {' ', '\t', '\v', '\r', '\l', '\f'}
var total = ((len(s) + 3) div 4) * 3
# total is an upper bound, as we will skip arbitrary whitespace:
result = newString(total)
var i = 0
var r = 0
while true:
while s[i] in Whitespace: inc(i)
if i < s.len-3:
var a = s[i].decodeByte
var b = s[i+1].decodeByte
var c = s[i+2].decodeByte
var d = s[i+3].decodeByte
result[r] = chr((a shl 2) and 0xff or ((b shr 4) and 0x03))
result[r+1] = chr((b shl 4) and 0xff or ((c shr 2) and 0x0F))
result[r+2] = chr((c shl 6) and 0xff or (d and 0x3F))
inc(r, 3)
inc(i, 4)
else: break
assert i == s.len
# adjust the length:
if i > 0 and s[i-1] == '=':
dec(r)
if i > 1 and s[i-2] == '=': dec(r)
setLen(result, r)
when isMainModule:
assert encode("leasure.") == "bGVhc3VyZS4="
assert encode("easure.") == "ZWFzdXJlLg=="
assert encode("asure.") == "YXN1cmUu"
assert encode("sure.") == "c3VyZS4="
const longText = """Man is distinguished, not only by his reason, but by this
singular passion from other animals, which is a lust of the mind,
that by a perseverance of delight in the continued and indefatigable
generation of knowledge, exceeds the short vehemence of any carnal
pleasure."""
const tests = ["", "abc", "xyz", "man", "leasure.", "sure.", "easure.",
"asure.", longText]
for t in items(tests):
assert decode(encode(t)) == t

View File

@@ -0,0 +1,581 @@
#nimrod c -t:-march=i686 --cpu:amd64 --threads:on -d:release lockfreehash.nim
import baseutils, unsigned, math, hashes
const
minTableSize = 8
reProbeLimit = 12
minCopyWork = 4096
intSize = sizeof(int)
when sizeof(int) == 4: # 32bit
type
TRaw = range[0..1073741823]
## The range of uint values that can be stored directly in a value slot
## when on a 32 bit platform
elif sizeof(int) == 8: # 64bit
type
TRaw = range[0..4611686018427387903]
## The range of uint values that can be stored directly in a value slot
## when on a 64 bit platform
else: echo("unsupported platform")
type
TEntry = tuple
key: int
value: int
TEntryArr = ptr array[0..10_000_000, TEntry]
PConcTable[K,V] = ptr object {.pure.}
len: int
used: int
active: int
copyIdx: int
copyDone: int
next: PConcTable[K,V]
data: TEntryArr
proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
expVal: int, match: bool): int
#------------------------------------------------------------------------------
# Create a new table
proc newLFTable*[K,V](size: int = minTableSize): PConcTable[K,V] =
let
dataLen = max(nextPowerOfTwo(size), minTableSize)
dataSize = dataLen*sizeof(TEntry)
dataMem = allocShared0(dataSize)
tableSize = 7 * intSize
tableMem = allocShared0(tableSize)
table = cast[PConcTable[K,V]](tableMem)
table.len = dataLen
table.used = 0
table.active = 0
table.copyIdx = 0
table.copyDone = 0
table.next = nil
table.data = cast[TEntryArr](dataMem)
result = table
#------------------------------------------------------------------------------
# Delete a table
proc deleteConcTable[K,V](tbl: PConcTable[K,V]) =
deallocShared(tbl.data)
deallocShared(tbl)
#------------------------------------------------------------------------------
proc `[]`[K,V](table: var PConcTable[K,V], i: int): var TEntry {.inline.} =
table.data[i]
#------------------------------------------------------------------------------
# State flags stored in ptr
proc pack[T](x: T): int {.inline.} =
result = (cast[int](x) shl 2)
#echo("packKey ",cast[int](x) , " -> ", result)
# Pop the flags off returning a 4 byte aligned ptr to our Key or Val
proc pop(x: int): int {.inline.} =
result = x and 0xFFFFFFFC'i32
# Pop the raw value off of our Key or Val
proc popRaw(x: int): int {.inline.} =
result = x shr 2
# Pop the flags off returning a 4 byte aligned ptr to our Key or Val
proc popPtr[V](x: int): ptr V {.inline.} =
result = cast[ptr V](pop(x))
#echo("popPtr " & $x & " -> " & $cast[int](result))
# Ghost (sentinel)
# K or V is no longer valid use new table
const Ghost = 0xFFFFFFFC
proc isGhost(x: int): bool {.inline.} =
result = x == 0xFFFFFFFC
# Tombstone
# applied to V = K is dead
proc isTomb(x: int): bool {.inline.} =
result = (x and 0x00000002) != 0
proc setTomb(x: int): int {.inline.} =
result = x or 0x00000002
# Prime
# K or V is in new table copied from old
proc isPrime(x: int): bool {.inline.} =
result = (x and 0x00000001) != 0
proc setPrime(x: int): int {.inline.} =
result = x or 0x00000001
#------------------------------------------------------------------------------
##This is for i32 only need to override for i64
proc hashInt(x: int):int {.inline.} =
var h = uint32(x) #shr 2'u32
h = h xor (h shr 16'u32)
h *= 0x85ebca6b'u32
h = h xor (h shr 13'u32)
h *= 0xc2b2ae35'u32
h = h xor (h shr 16'u32)
result = int(h)
#------------------------------------------------------------------------------
proc resize[K,V](self: PConcTable[K,V]): PConcTable[K,V] =
var next = atomic_load_n(self.next.addr, ATOMIC_RELAXED)
#echo("next = " & $cast[int](next))
if next != nil:
#echo("A new table already exists, copy in progress")
return next
var
oldLen = atomic_load_n(self.len.addr, ATOMIC_RELAXED)
newTable = newLFTable[K,V](oldLen*2)
success = atomic_compare_exchange_n(self.next.addr, next.addr, newTable,
false, ATOMIC_RELAXED, ATOMIC_RELAXED)
if not success:
echo("someone beat us to it! delete table we just created and return his " & $cast[int](next))
deleteConcTable(newTable)
return next
else:
echo("Created New Table! " & $cast[int](newTable) & " Size = " & $newTable.len)
return newTable
#------------------------------------------------------------------------------
#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:
if key1 == key2:
result = true
else:
var
p1 = popPtr[K](key1)
p2 = popPtr[K](key2)
if p1 != nil and p2 != nil:
if cast[int](p1) == cast[int](p2):
return true
if p1[] == p2[]:
return true
#------------------------------------------------------------------------------
#proc tableFull(self: var PConcTable[K,V]) : bool {.inline.} =
#------------------------------------------------------------------------------
proc copySlot[K,V](idx: int, oldTbl: var PConcTable[K,V], newTbl: var PConcTable[K,V]): bool =
#echo("Copy idx " & $idx)
var
oldVal = 0
oldkey = 0
ok = false
result = false
#Block the key so no other threads waste time here
while not ok:
ok = atomic_compare_exchange_n(oldTbl[idx].key.addr, oldKey.addr,
setTomb(oldKey), false, ATOMIC_RELAXED, ATOMIC_RELAXED)
#echo("oldKey was = " & $oldKey & " set it to tomb " & $setTomb(oldKey))
#Prevent new values from appearing in the old table by priming
oldVal = atomic_load_n(oldTbl[idx].value.addr, ATOMIC_RELAXED)
while not isPrime(oldVal):
var box = if oldVal == NULL or isTomb(oldVal) : oldVal.setTomb.setPrime
else: oldVal.setPrime
if atomic_compare_exchange_n(oldTbl[idx].value.addr, oldVal.addr,
box, false, ATOMIC_RELAXED, ATOMIC_RELAXED):
if isPrime(box) and isTomb(box):
return true
oldVal = box
break
#echo("oldVal was = ", oldVal, " set it to prime ", box)
if isPrime(oldVal) and isTomb(oldVal):
#when not (K is TRaw):
# deallocShared(popPtr[K](oldKey))
return false
if isTomb(oldVal):
echo("oldVal is Tomb!!!, should not happen")
if pop(oldVal) != NULL:
result = setVal(newTbl, pop(oldKey), pop(oldVal), NULL, true) == NULL
if result:
#echo("Copied a Slot! idx= " & $idx & " key= " & $oldKey & " val= " & $oldVal)
else:
#echo("copy slot failed")
# Our copy is done so we disable the old slot
while not ok:
ok = atomic_compare_exchange_n(oldTbl[idx].value.addr, oldVal.addr,
oldVal.setTomb.setPrime , false, ATOMIC_RELAXED, ATOMIC_RELAXED)
#echo("disabled old slot")
#echo"---------------------"
#------------------------------------------------------------------------------
proc promote[K,V](table: var PConcTable[K,V]) =
var
newData = atomic_load_n(table.next.data.addr, ATOMIC_RELAXED)
newLen = atomic_load_n(table.next.len.addr, ATOMIC_RELAXED)
newUsed = atomic_load_n(table.next.used.addr, ATOMIC_RELAXED)
deallocShared(table.data)
atomic_store_n(table.data.addr, newData, ATOMIC_RELAXED)
atomic_store_n(table.len.addr, newLen, ATOMIC_RELAXED)
atomic_store_n(table.used.addr, newUsed, ATOMIC_RELAXED)
atomic_store_n(table.copyIdx.addr, 0, ATOMIC_RELAXED)
atomic_store_n(table.copyDone.addr, 0, ATOMIC_RELAXED)
deallocShared(table.next)
atomic_store_n(table.next.addr, nil, ATOMIC_RELAXED)
echo("new table swapped!")
#------------------------------------------------------------------------------
proc checkAndPromote[K,V](table: var PConcTable[K,V], workDone: int): bool =
var
oldLen = atomic_load_n(table.len.addr, ATOMIC_RELAXED)
copyDone = atomic_load_n(table.copyDone.addr, ATOMIC_RELAXED)
ok: bool
result = false
if workDone > 0:
#echo("len to copy =" & $oldLen)
#echo("copyDone + workDone = " & $copyDone & " + " & $workDone)
while not ok:
ok = atomic_compare_exchange_n(table.copyDone.addr, copyDone.addr,
copyDone + workDone, false, ATOMIC_RELAXED, ATOMIC_RELAXED)
#if ok: echo("set copyDone")
# If the copy is done we can promote this table
if copyDone + workDone >= oldLen:
# Swap new data
#echo("work is done!")
table.promote
result = true
#------------------------------------------------------------------------------
proc copySlotAndCheck[K,V](table: var PConcTable[K,V], idx: int):
PConcTable[K,V] =
var
newTable = cast[PConcTable[K,V]](atomic_load_n(table.next.addr, ATOMIC_RELAXED))
result = newTable
if newTable != nil and copySlot(idx, table, newTable):
#echo("copied a single slot, idx = " & $idx)
if checkAndPromote(table, 1): return table
#------------------------------------------------------------------------------
proc helpCopy[K,V](table: var PConcTable[K,V]): PConcTable[K,V] =
var
newTable = cast[PConcTable[K,V]](atomic_load_n(table.next.addr, ATOMIC_RELAXED))
result = newTable
if newTable != nil:
var
oldLen = atomic_load_n(table.len.addr, ATOMIC_RELAXED)
copyDone = atomic_load_n(table.copyDone.addr, ATOMIC_RELAXED)
copyIdx = 0
work = min(oldLen, minCopyWork)
#panicStart = -1
workDone = 0
if copyDone < oldLen:
var ok: bool
while not ok:
ok = atomic_compare_exchange_n(table.copyIdx.addr, copyIdx.addr,
copyIdx + work, false, ATOMIC_RELAXED, ATOMIC_RELAXED)
#echo("copy idx = ", copyIdx)
for i in 0..work-1:
var idx = (copyIdx + i) and (oldLen - 1)
if copySlot(idx, table, newTable):
workDone += 1
if workDone > 0:
#echo("did work ", workDone, " on thread ", cast[int](myThreadID[pointer]()))
if checkAndPromote(table, workDone): return table
# In case a thread finished all the work then got stalled before promotion
if checkAndPromote(table, 0): return table
#------------------------------------------------------------------------------
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:
var idx = hashInt(key)
else:
var idx = popPtr[K](key)[].hash
var
nextTable: PConcTable[K,V]
probes = 1
# spin until we find a key slot or build and jump to next table
while true:
idx = idx and (table.len - 1)
#echo("try set idx = " & $idx & "for" & $key)
var
probedKey = NULL
openKey = atomic_compare_exchange_n(table[idx].key.addr, probedKey.addr,
key, false, ATOMIC_RELAXED, ATOMIC_RELAXED)
if openKey:
if val.isTomb:
#echo("val was tomb, bail, no reason to set an open slot to tomb")
return val
#increment used slots
#echo("found an open slot, total used = " &
#$atomic_add_fetch(table.used.addr, 1, ATOMIC_RELAXED))
discard atomic_add_fetch(table.used.addr, 1, ATOMIC_RELAXED)
break # We found an open slot
#echo("set idx ", idx, " key = ", key, " probed = ", probedKey)
if keyEQ[K](probedKey, key):
#echo("we found the matching slot")
break # We found a matching slot
if (not(expVal != NULL and match)) and (probes >= reProbeLimit or key.isTomb):
if key.isTomb: echo("Key is Tombstone")
#if probes >= reProbeLimit: echo("Too much probing " & $probes)
#echo("try to resize")
#create next bigger table
nextTable = resize(table)
#help do some copying
#echo("help copy old table to new")
nextTable = helpCopy(table)
#now setVal in the new table instead
#echo("jumping to next table to set val")
return setVal(nextTable, key, val, expVal, match)
else:
idx += 1
probes += 1
# Done spinning for a new slot
var oldVal = atomic_load_n(table[idx].value.addr, ATOMIC_RELAXED)
if val == oldVal:
#echo("this val is alredy in the slot")
return oldVal
nextTable = atomic_load_n(table.next.addr, ATOMIC_SEQ_CST)
if nextTable == nil and
((oldVal == NULL and
(probes >= reProbeLimit or table.used / table.len > 0.8)) or
(isPrime(oldVal))):
if table.used / table.len > 0.8: echo("resize because usage ratio = " &
$(table.used / table.len))
if isPrime(oldVal): echo("old val isPrime, should be a rare mem ordering event")
nextTable = resize(table)
if nextTable != nil:
#echo("tomb old slot then set in new table")
nextTable = copySlotAndCheck(table,idx)
return setVal(nextTable, key, val, expVal, match)
# Finaly ready to add new val to table
while true:
if match and oldVal != expVal:
#echo("set failed, no match oldVal= " & $oldVal & " expVal= " & $expVal)
return oldVal
if atomic_compare_exchange_n(table[idx].value.addr, oldVal.addr,
val, false, ATOMIC_RELEASE, ATOMIC_RELAXED):
#echo("val set at table " & $cast[int](table))
if expVal != NULL:
if (oldVal == NULL or isTomb(oldVal)) and not isTomb(val):
discard atomic_add_fetch(table.active.addr, 1, ATOMIC_RELAXED)
elif not (oldVal == NULL or isTomb(oldVal)) and isTomb(val):
discard atomic_add_fetch(table.active.addr, -1, ATOMIC_RELAXED)
if oldVal == NULL and expVal != NULL:
return setTomb(oldVal)
else: return oldVal
if isPrime(oldVal):
nextTable = copySlotAndCheck(table, idx)
return setVal(nextTable, key, val, expVal, match)
#------------------------------------------------------------------------------
proc getVal[K,V](table: var PConcTable[K,V], key: int): int =
#echo("-try get- key = " & $key)
when K is TRaw:
var idx = hashInt(key)
else:
var idx = popPtr[K](key)[].hash
#echo("get idx ", idx)
var
probes = 0
val: int
while true:
idx = idx and (table.len - 1)
var
newTable: PConcTable[K,V] # = atomic_load_n(table.next.addr, ATOMIC_ACQUIRE)
probedKey = atomic_load_n(table[idx].key.addr, ATOMIC_SEQ_CST)
if keyEQ[K](probedKey, key):
#echo("found key after ", probes+1)
val = atomic_load_n(table[idx].value.addr, ATOMIC_ACQUIRE)
if not isPrime(val):
if isTomb(val):
#echo("val was tomb but not prime")
return NULL
else:
#echo("-GotIt- idx = ", idx, " key = ", key, " val ", val )
return val
else:
newTable = copySlotAndCheck(table, idx)
return getVal(newTable, key)
else:
#echo("probe ", probes, " idx = ", idx, " key = ", key, " found ", probedKey )
if probes >= reProbeLimit*4 or key.isTomb:
if newTable == nil:
#echo("too many probes and no new table ", key, " ", idx )
return NULL
else:
newTable = helpCopy(table)
return getVal(newTable, key)
idx += 1
probes += 1
#------------------------------------------------------------------------------
#proc set*(table: var PConcTable[TRaw,TRaw], key: TRaw, val: TRaw) =
# discard setVal(table, pack(key), pack(key), NULL, false)
#proc set*[V](table: var PConcTable[TRaw,V], key: TRaw, val: ptr V) =
# discard setVal(table, pack(key), cast[int](val), NULL, false)
proc set*[K,V](table: var PConcTable[K,V], key: var K, val: var V) =
when not (K is TRaw):
var newKey = cast[int](copyShared(key))
else:
var newKey = pack(key)
when not (V is TRaw):
var newVal = cast[int](copyShared(val))
else:
var newVal = pack(val)
var oldPtr = pop(setVal(table, newKey, newVal, NULL, false))
#echo("oldPtr = ", cast[int](oldPtr), " newPtr = ", cast[int](newPtr))
when not (V is TRaw):
if newVal != oldPtr and oldPtr != NULL:
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):
return popPtr[V](getVal(table, cast[int](key.addr)))[]
else:
return popPtr[V](getVal(table, pack(key)))[]
else:
when not (K is TRaw):
return popRaw(getVal(table, cast[int](key.addr)))
else:
return popRaw(getVal(table, pack(key)))
#proc `[]`[K,V](table: var PConcTable[K,V], key: K): PEntry[K,V] {.inline.} =
# getVal(table, key)
#proc `[]=`[K,V](table: var PConcTable[K,V], key: K, val: V): PEntry[K,V] {.inline.} =
# setVal(table, key, val)
#Tests ----------------------------
when isMainModule:
import locks, times, mersenne
const
numTests = 100000
numThreads = 10
type
TTestObj = tuple
thr: int
f0: int
f1: int
TData = tuple[k: string,v: TTestObj]
PDataArr = array[0..numTests-1, TData]
Dict = PConcTable[string,TTestObj]
var
thr: array[0..numThreads-1, TThread[Dict]]
table = newLFTable[string,TTestObj](8)
rand = newMersenneTwister(2525)
proc createSampleData(len: int): PDataArr =
#result = cast[PDataArr](allocShared0(sizeof(TData)*numTests))
for i in 0..len-1:
result[i].k = "mark" & $(i+1)
#echo("mark" & $(i+1), " ", hash("mark" & $(i+1)))
result[i].v.thr = 0
result[i].v.f0 = i+1
result[i].v.f1 = 0
#echo("key = " & $(i+1) & " Val ptr = " & $cast[int](result[i].v.addr))
proc threadProc(tp: Dict) {.thread.} =
var t = cpuTime();
for i in 1..numTests:
var key = "mark" & $(i)
var got = table.get(key)
got.thr = cast[int](myThreadID[pointer]())
got.f1 = got.f1 + 1
table.set(key, got)
t = cpuTime() - t
echo t
var testData = createSampleData(numTests)
for i in 0..numTests-1:
table.set(testData[i].k, testData[i].v)
var i = 0
while i < numThreads:
createThread(thr[i], threadProc, table)
i += 1
joinThreads(thr)
var fails = 0
for i in 0..numTests-1:
var got = table.get(testData[i].k)
if got.f0 != i+1 or got.f1 != numThreads:
fails += 1
echo(got)
echo("Failed read or write = ", fails)
#for i in 1..numTests:
# echo(i, " = ", hashInt(i) and 8191)
deleteConcTable(table)

View File

@@ -0,0 +1,41 @@
#------------------------------------------------------------------------------
## Useful Constants
const NULL* = 0
#------------------------------------------------------------------------------
## Memory Utility Functions
proc newHeap*[T](): ptr T =
result = cast[ptr T](alloc0(sizeof(T)))
proc copyNew*[T](x: var T): ptr T =
var
size = sizeof(T)
mem = alloc(size)
copyMem(mem, x.addr, size)
return cast[ptr T](mem)
proc copyTo*[T](val: var T, dest: int) =
copyMem(pointer(dest), val.addr, sizeof(T))
proc allocType*[T](): pointer = alloc(sizeof(T))
proc newShared*[T](): ptr T =
result = cast[ptr T](allocShared0(sizeof(T)))
proc copyShared*[T](x: var T): ptr T =
var
size = sizeof(T)
mem = allocShared(size)
copyMem(mem, x.addr, size)
return cast[ptr T](mem)
#------------------------------------------------------------------------------
## Pointer arithmetic
proc `+`*(p: pointer, i: int): pointer {.inline.} =
cast[pointer](cast[int](p) + i)

View File

@@ -117,6 +117,57 @@ proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T] =
## assert f2 == @["yellow"]
accumulateResult(filter(seq1, pred))
proc delete*[T](s: var seq[T], first=0, last=0) =
## Deletes in `s` the items at position `first` .. `last`. This modifies
## `s` itself, it does not return a copy.
##
## Example:
##
##.. code-block:: nimrod
## let outcome = @[1,1,1,1,1,1,1,1]
## var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
## dest.delete(3, 8)
## assert outcome == dest
var i = first
var j = last+1
var newLen = len(s)-j+i
while i < newLen:
s[i].shallowCopy(s[j])
inc(i)
inc(j)
setlen(s, newLen)
proc insert*[T](dest: var seq[T], src: openArray[T], pos=0) =
## Inserts items from `src` into `dest` at position `pos`. This modifies
## `dest` itself, it does not return a copy.
##
## Example:
##
##.. code-block:: nimrod
## var dest = @[1,1,1,1,1,1,1,1]
## let
## src = @[2,2,2,2,2,2]
## outcome = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
## dest.insert(src, 3)
## assert dest == outcome
var j = len(dest) - 1
var i = len(dest) + len(src) - 1
dest.setLen(i + 1)
# Move items after `pos` to the end of the sequence.
while j >= pos:
dest[i].shallowCopy(dest[j])
dec(i)
dec(j)
# Insert items from `dest` into `dest` at `pos`
inc(j)
for item in src:
dest[j] = item
inc(j)
template filterIt*(seq1, pred: expr): expr {.immediate.} =
## Returns a new sequence with all the items that fulfilled the predicate.
##
@@ -312,4 +363,22 @@ when isMainModule:
assert multiplication == 495, "Multiplication is (5*(9*(11)))"
assert concatenation == "nimrodiscool"
block: # delete tests
let outcome = @[1,1,1,1,1,1,1,1]
var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
dest.delete(3, 8)
assert outcome == dest, """\
Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1]
is [1,1,1,1,1,1,1,1]"""
block: # insert tests
var dest = @[1,1,1,1,1,1,1,1]
let
src = @[2,2,2,2,2,2]
outcome = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
dest.insert(src, 3)
assert dest == outcome, """\
Inserting [2,2,2,2,2,2] into [1,1,1,1,1,1,1,1]
at 3 is [1,1,1,2,2,2,2,2,2,1,1,1,1,1]"""
echo "Finished doc tests"

View File

@@ -224,11 +224,13 @@ type
TAsyncHTTPServer = object of TServer
asyncSocket: PAsyncSocket
proc open*(s: var TServer, port = TPort(80)) =
proc open*(s: var TServer, port = TPort(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)
if s.socket == InvalidSocket: OSError(OSLastError())
if reuseAddr:
s.socket.setSockOpt(OptReuseAddr, True)
bindAddr(s.socket, port)
listen(s.socket)
@@ -475,7 +477,8 @@ proc nextAsync(s: PAsyncHTTPServer) =
proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSocket,
path, query: string): bool {.closure.},
port = TPort(80), address = ""): PAsyncHTTPServer =
port = TPort(80), address = "",
reuseAddr = false): PAsyncHTTPServer =
## Creates an Asynchronous HTTP server at ``port``.
var capturedRet: PAsyncHTTPServer
new(capturedRet)
@@ -486,6 +489,8 @@ proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSo
let quit = handleRequest(capturedRet, capturedRet.client, capturedRet.path,
capturedRet.query)
if quit: capturedRet.asyncSocket.close()
if reuseAddr:
capturedRet.asyncSocket.setSockOpt(OptReuseAddr, True)
capturedRet.asyncSocket.bindAddr(port, address)
capturedRet.asyncSocket.listen()

39
lib/pure/mersenne.nim Normal file
View File

@@ -0,0 +1,39 @@
import unsigned
type
TMersenneTwister* = object
mt: array[0..623, uint32]
index: int
proc newMersenneTwister*(seed: int): TMersenneTwister =
result.index = 0
result.mt[0]= uint32(seed)
for i in 1..623'u32:
result.mt[i]= (0x6c078965'u32 * (result.mt[i-1] xor (result.mt[i-1] shr 30'u32)) + i)
proc generateNumbers(m: var TMersenneTwister) =
for i in 0..623:
var y = (m.mt[i] and 0x80000000'u32) + (m.mt[(i+1) mod 624] and 0x7fffffff'u32)
m.mt[i] = m.mt[(i+397) mod 624] xor uint32(y shr 1'u32)
if (y mod 2'u32) != 0:
m.mt[i] = m.mt[i] xor 0x9908b0df'u32
proc getNum*(m: var TMersenneTwister): int =
if m.index == 0:
generateNumbers(m)
var y = m.mt[m.index]
y = y xor (y shr 11'u32)
y = y xor ((7'u32 shl y) and 0x9d2c5680'u32)
y = y xor ((15'u32 shl y) and 0xefc60000'u32)
y = y xor (y shr 18'u32)
m.index = (m.index+1) mod 624
return int(y)
# Test
when isMainModule:
var mt = newMersenneTwister(2525)
for i in 0..99:
echo mt.getNum

View File

@@ -24,10 +24,10 @@ type
TProcess = object of TObject
when defined(windows):
FProcessHandle: Thandle
inputHandle, outputHandle, errorHandle: TFileHandle
inHandle, outHandle, errHandle: TFileHandle
id: THandle
else:
inputHandle, outputHandle, errorHandle: TFileHandle
inHandle, outHandle, errHandle: TFileHandle
inStream, outStream, errStream: PStream
id: TPid
exitCode: cint
@@ -113,23 +113,47 @@ proc peekExitCode*(p: PProcess): int {.tags: [].}
## return -1 if the process is still running. Otherwise the process' exit code
proc inputStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].}
## returns ``p``'s input stream for writing to
## returns ``p``'s input stream for writing to.
##
## **Warning**: The returned `PStream` should not be closed manually as it
## is closed when closing the PProcess ``p``.
proc outputStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].}
## returns ``p``'s output stream for reading from
## returns ``p``'s output stream for reading from.
##
## **Warning**: The returned `PStream` should not be closed manually as it
## is closed when closing the PProcess ``p``.
proc errorStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].}
## returns ``p``'s output stream for reading from
## returns ``p``'s error stream for reading from.
##
## **Warning**: The returned `PStream` should not be closed manually as it
## is closed when closing the PProcess ``p``.
proc inputHandle*(p: PProcess): TFileHandle {.rtl, extern: "nosp$1",
tags: [].} =
## returns ``p``'s input file handle for writing to.
##
## **Warning**: The returned `TFileHandle` should not be closed manually as
## it is closed when closing the PProcess ``p``.
result = p.inHandle
proc outputHandle*(p: PProcess): TFileHandle {.rtl, extern: "nosp$1",
tags: [].} =
## returns ``p``'s output file handle for reading from.
##
## **Warning**: The returned `TFileHandle` should not be closed manually as
## it is closed when closing the PProcess ``p``.
result = p.outHandle
proc errorHandle*(p: PProcess): TFileHandle {.rtl, extern: "nosp$1",
tags: [].} =
## returns ``p``'s error file handle for reading from.
##
## **Warning**: The returned `TFileHandle` should not be closed manually as
## it is closed when closing the PProcess ``p``.
result = p.errHandle
when defined(macosx) or defined(bsd):
const
CTL_HW = 6
@@ -212,8 +236,8 @@ proc execProcesses*(cmds: openArray[string],
inc(i)
if i > high(cmds): break
for j in 0..m-1:
if q[j] != nil: close(q[j])
result = max(waitForExit(q[j]), result)
if q[j] != nil: close(q[j])
else:
for i in 0..high(cmds):
var p = startCmd(cmds[i], options=options)
@@ -339,16 +363,16 @@ when defined(Windows) and not defined(useNimRtl):
HE = HO
else:
CreatePipeHandles(HE, Si.hStdError)
result.inputHandle = TFileHandle(hi)
result.outputHandle = TFileHandle(ho)
result.errorHandle = TFileHandle(he)
result.inHandle = TFileHandle(hi)
result.outHandle = TFileHandle(ho)
result.errHandle = TFileHandle(he)
else:
SI.hStdError = GetStdHandle(STD_ERROR_HANDLE)
SI.hStdInput = GetStdHandle(STD_INPUT_HANDLE)
SI.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE)
result.inputHandle = TFileHandle(si.hStdInput)
result.outputHandle = TFileHandle(si.hStdOutput)
result.errorHandle = TFileHandle(si.hStdError)
result.inHandle = TFileHandle(si.hStdInput)
result.outHandle = TFileHandle(si.hStdOutput)
result.errHandle = TFileHandle(si.hStdError)
var cmdl: cstring
when false: # poUseShell in options:
@@ -389,9 +413,9 @@ when defined(Windows) and not defined(useNimRtl):
proc close(p: PProcess) =
when false:
# somehow this does not work on Windows:
discard CloseHandle(p.inputHandle)
discard CloseHandle(p.outputHandle)
discard CloseHandle(p.errorHandle)
discard CloseHandle(p.inHandle)
discard CloseHandle(p.outHandle)
discard CloseHandle(p.errHandle)
discard CloseHandle(p.FProcessHandle)
proc suspend(p: PProcess) =
@@ -425,13 +449,13 @@ when defined(Windows) and not defined(useNimRtl):
return res
proc inputStream(p: PProcess): PStream =
result = newFileHandleStream(p.inputHandle)
result = newFileHandleStream(p.inHandle)
proc outputStream(p: PProcess): PStream =
result = newFileHandleStream(p.outputHandle)
result = newFileHandleStream(p.outHandle)
proc errorStream(p: PProcess): PStream =
result = newFileHandleStream(p.errorHandle)
result = newFileHandleStream(p.errHandle)
proc execCmd(command: string): int =
var
@@ -626,20 +650,20 @@ elif not defined(useNimRtl):
if poParentStreams in options:
# does not make much sense, but better than nothing:
result.inputHandle = 0
result.outputHandle = 1
result.inHandle = 0
result.outHandle = 1
if poStdErrToStdOut in options:
result.errorHandle = result.outputHandle
result.errHandle = result.outHandle
else:
result.errorHandle = 2
result.errHandle = 2
else:
result.inputHandle = p_stdin[writeIdx]
result.outputHandle = p_stdout[readIdx]
result.inHandle = p_stdin[writeIdx]
result.outHandle = p_stdout[readIdx]
if poStdErrToStdOut in options:
result.errorHandle = result.outputHandle
result.errHandle = result.outHandle
discard close(p_stderr[readIdx])
else:
result.errorHandle = p_stderr[readIdx]
result.errHandle = p_stderr[readIdx]
discard close(p_stderr[writeIdx])
discard close(p_stdin[readIdx])
discard close(p_stdout[writeIdx])
@@ -648,9 +672,9 @@ elif not defined(useNimRtl):
if p.inStream != nil: close(p.inStream)
if p.outStream != nil: close(p.outStream)
if p.errStream != nil: close(p.errStream)
discard close(p.inputHandle)
discard close(p.outputHandle)
discard close(p.errorHandle)
discard close(p.inHandle)
discard close(p.outHandle)
discard close(p.errHandle)
proc suspend(p: PProcess) =
if kill(-p.id, SIGSTOP) != 0'i32: OSError(OSLastError())
@@ -696,17 +720,17 @@ elif not defined(useNimRtl):
proc inputStream(p: PProcess): PStream =
if p.inStream == nil:
createStream(p.inStream, p.inputHandle, fmWrite)
createStream(p.inStream, p.inHandle, fmWrite)
return p.inStream
proc outputStream(p: PProcess): PStream =
if p.outStream == nil:
createStream(p.outStream, p.outputHandle, fmRead)
createStream(p.outStream, p.outHandle, fmRead)
return p.outStream
proc errorStream(p: PProcess): PStream =
if p.errStream == nil:
createStream(p.errStream, p.errorHandle, fmRead)
createStream(p.errStream, p.errHandle, fmRead)
return p.errStream
proc csystem(cmd: cstring): cint {.nodecl, importc: "system".}
@@ -717,14 +741,14 @@ elif not defined(useNimRtl):
proc createFdSet(fd: var TFdSet, s: seq[PProcess], m: var int) =
FD_ZERO(fd)
for i in items(s):
m = max(m, int(i.outputHandle))
FD_SET(cint(i.outputHandle), fd)
m = max(m, int(i.outHandle))
FD_SET(cint(i.outHandle), fd)
proc pruneProcessSet(s: var seq[PProcess], fd: var TFdSet) =
var i = 0
var L = s.len
while i < L:
if FD_ISSET(cint(s[i].outputHandle), fd) != 0'i32:
if FD_ISSET(cint(s[i].outHandle), fd) != 0'i32:
s[i] = s[L-1]
dec(L)
else:

View File

@@ -95,7 +95,8 @@ proc recvBuffer(s: var TScgiState, L: int) =
scgiError("could not read all data")
setLen(s.input, L)
proc open*(s: var TScgiState, port = TPort(4000), address = "127.0.0.1") =
proc open*(s: var TScgiState, port = TPort(4000), address = "127.0.0.1",
reuseAddr = False) =
## opens a connection.
s.bufLen = 4000
s.input = newString(s.buflen) # will be reused
@@ -104,6 +105,8 @@ proc open*(s: var TScgiState, port = TPort(4000), address = "127.0.0.1") =
new(s.client) # Initialise s.client for `next`
if s.server == InvalidSocket: scgiError("could not open socket")
#s.server.connect(connectionName, port)
if reuseAddr:
s.server.setSockOpt(OptReuseAddr, True)
bindAddr(s.server, port, address)
listen(s.server)
@@ -243,7 +246,8 @@ proc handleAccept(sock: PAsyncSocket, s: PAsyncScgiState) =
proc open*(handleRequest: proc (client: PAsyncSocket,
input: string, headers: PStringTable) {.closure.},
port = TPort(4000), address = "127.0.0.1"): PAsyncScgiState =
port = TPort(4000), address = "127.0.0.1",
reuseAddr = false): PAsyncScgiState =
## Creates an ``PAsyncScgiState`` object which serves as a SCGI server.
##
## After the execution of ``handleRequest`` the client socket will be closed
@@ -252,6 +256,8 @@ proc open*(handleRequest: proc (client: PAsyncSocket,
new(cres)
cres.asyncServer = AsyncSocket()
cres.asyncServer.handleAccept = proc (s: PAsyncSocket) = handleAccept(s, cres)
if reuseAddr:
cres.asyncServer.setSockOpt(OptReuseAddr, True)
bindAddr(cres.asyncServer, port, address)
listen(cres.asyncServer)
cres.handleRequest = handleRequest

View File

@@ -31,6 +31,7 @@ when hostos == "solaris":
import os, parseutils
from times import epochTime
import unsigned
when defined(ssl):
import openssl
@@ -62,7 +63,7 @@ const
type
TSocketImpl = object ## socket type
fd: cint
fd: TSocketHandle
case isBuffered: bool # determines whether this socket is buffered.
of true:
buffer: array[0..BufferSize, char]
@@ -82,7 +83,7 @@ type
TSocket* = ref TSocketImpl
TPort* = distinct int16 ## port type
TPort* = distinct uint16 ## port type
TDomain* = enum ## domain, which specifies the protocol family of the
## created socket. Other domains than those that are listed
@@ -118,6 +119,10 @@ type
length*: int
addrList*: seq[string]
TSOBool* = enum ## Boolean socket options.
OptAcceptConn, OptBroadcast, OptDebug, OptDontRoute, OptKeepAlive,
OptOOBInline, OptReuseAddr
TRecvLineResult* = enum ## result for recvLineAsync
RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail
@@ -126,7 +131,19 @@ type
ETimeout* = object of ESynch
proc newTSocket(fd: int32, isBuff: bool): TSocket =
let
InvalidSocket*: TSocket = nil ## invalid socket
when defined(windows):
let
OSInvalidSocket = winlean.INVALID_SOCKET
else:
let
OSInvalidSocket = posix.INVALID_SOCKET
proc newTSocket(fd: TSocketHandle, isBuff: bool): TSocket =
if fd == OSInvalidSocket:
return nil
new(result)
result.fd = fd
result.isBuffered = isBuff
@@ -134,9 +151,6 @@ proc newTSocket(fd: int32, isBuff: bool): TSocket =
result.currPos = 0
result.nonblocking = false
let
InvalidSocket*: TSocket = nil ## invalid socket
proc `==`*(a, b: TPort): bool {.borrow.}
## ``==`` for ports.
@@ -211,7 +225,9 @@ else:
proc socket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
protocol: TProtocol = IPPROTO_TCP, buffered = true): TSocket =
## Creates a new socket; returns `InvalidSocket` if an error occurs.
## Creates a new socket; returns `InvalidSocket` if an error occurs.
# TODO: Perhaps this should just raise EOS when an error occurs.
when defined(Windows):
result = newTSocket(winlean.socket(ord(domain), ord(typ), ord(protocol)), buffered)
else:
@@ -456,7 +472,7 @@ template acceptAddrPlain(noClientRet, successRet: expr,
var sock = accept(server.fd, cast[ptr TSockAddr](addr(sockAddress)),
addr(addrLen))
if sock < 0:
if sock == OSInvalidSocket:
let err = OSLastError()
when defined(windows):
if err.int32 == WSAEINPROGRESS:
@@ -529,7 +545,7 @@ proc acceptAddr*(server: TSocket, client: var TSocket, address: var string) {.
SSLError("Unknown error")
proc setBlocking*(s: TSocket, blocking: bool) {.tags: [].}
## sets blocking mode on socket
## Sets blocking mode on socket
when defined(ssl):
proc acceptAddrSSL*(server: TSocket, client: var TSocket,
@@ -623,24 +639,32 @@ proc close*(socket: TSocket) =
discard SSLShutdown(socket.sslHandle)
proc getServByName*(name, proto: string): TServent {.tags: [FReadIO].} =
## well-known getservbyname proc.
## Searches the database from the beginning and finds the first entry for
## which the service name specified by ``name`` matches the s_name member
## and the protocol name specified by ``proto`` matches the s_proto member.
##
## On posix this will search through the ``/etc/services`` file.
when defined(Windows):
var s = winlean.getservbyname(name, proto)
else:
var s = posix.getservbyname(name, proto)
if s == nil: OSError(OSLastError())
if s == nil: raise newException(EOS, "Service not found.")
result.name = $s.s_name
result.aliases = cstringArrayToSeq(s.s_aliases)
result.port = TPort(s.s_port)
result.proto = $s.s_proto
proc getServByPort*(port: TPort, proto: string): TServent {.tags: [FReadIO].} =
## well-known getservbyport proc.
## Searches the database from the beginning and finds the first entry for
## which the port specified by ``port`` matches the s_port member and the
## protocol name specified by ``proto`` matches the s_proto member.
##
## On posix this will search through the ``/etc/services`` file.
when defined(Windows):
var s = winlean.getservbyport(ze(int16(port)).cint, proto)
else:
var s = posix.getservbyport(ze(int16(port)).cint, proto)
if s == nil: OSError(OSLastError())
if s == nil: raise newException(EOS, "Service not found.")
result.name = $s.s_name
result.aliases = cstringArrayToSeq(s.s_aliases)
result.port = TPort(s.s_port)
@@ -676,7 +700,7 @@ proc getHostByAddr*(ip: string): THostEnt {.tags: [FReadIO].} =
result.length = int(s.h_length)
proc getHostByName*(name: string): THostEnt {.tags: [FReadIO].} =
## well-known gethostbyname proc.
## This function will lookup the IP address of a hostname.
when defined(Windows):
var s = winlean.gethostbyname(name)
else:
@@ -714,6 +738,34 @@ proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
sizeof(value).TSockLen) < 0'i32:
OSError(OSLastError())
proc toCInt(opt: TSOBool): cint =
case opt
of OptAcceptConn: SO_ACCEPTCONN
of OptBroadcast: SO_BROADCAST
of OptDebug: SO_DEBUG
of OptDontRoute: SO_DONTROUTE
of OptKeepAlive: SO_KEEPALIVE
of OptOOBInline: SO_OOBINLINE
of OptReuseAddr: SO_REUSEADDR
proc getSockOpt*(socket: TSocket, opt: TSOBool, level = SOL_SOCKET): bool {.
tags: [FReadIO].} =
## Retrieves option ``opt`` as a boolean value.
var res: cint
var size = sizeof(res).TSockLen
if getsockopt(socket.fd, cint(level), toCInt(opt),
addr(res), addr(size)) < 0'i32:
OSError(OSLastError())
result = res != 0
proc setSockOpt*(socket: TSocket, opt: TSOBool, value: bool, level = SOL_SOCKET) {.
tags: [FWriteIO].} =
## Sets option ``opt`` to a boolean value specified by ``value``.
var valuei = cint(if value: 1 else: 0)
if setsockopt(socket.fd, cint(level), toCInt(opt), addr(valuei),
sizeof(valuei).TSockLen) < 0'i32:
OSError(OSLastError())
proc connect*(socket: TSocket, address: string, port = TPort(0),
af: TDomain = AF_INET) {.tags: [FReadIO].} =
## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a
@@ -866,11 +918,6 @@ proc timeValFromMilliseconds(timeout = 500): TTimeVal =
var seconds = timeout div 1000
result.tv_sec = seconds.int32
result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
#proc recvfrom*(s: TWinSocket, buf: cstring, len, flags: cint,
# fromm: ptr TSockAddr, fromlen: ptr cint): cint
#proc sendto*(s: TWinSocket, buf: cstring, len, flags: cint,
# to: ptr TSockAddr, tolen: cint): cint
proc createFdSet(fd: var TFdSet, s: seq[TSocket], m: var int) =
FD_ZERO(fd)
@@ -1608,14 +1655,14 @@ when defined(Windows):
FIONBIO = IOC_IN.int32 or ((sizeof(int32) and IOCPARM_MASK) shl 16) or
(102 shl 8) or 126
proc ioctlsocket(s: TWinSocket, cmd: clong,
proc ioctlsocket(s: TSocketHandle, cmd: clong,
argptr: ptr clong): cint {.
stdcall, importc:"ioctlsocket", dynlib: "ws2_32.dll".}
proc setBlocking(s: TSocket, blocking: bool) =
when defined(Windows):
var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
if ioctlsocket(TWinSocket(s.fd), FIONBIO, addr(mode)) == -1:
if ioctlsocket(TSocketHandle(s.fd), FIONBIO, addr(mode)) == -1:
OSError(OSLastError())
else: # BSD sockets
var x: int = fcntl(s.fd, F_GETFL, 0)
@@ -1656,9 +1703,12 @@ proc connect*(socket: TSocket, address: string, port = TPort(0), timeout: int,
proc isSSL*(socket: TSocket): bool = return socket.isSSL
## Determines whether ``socket`` is a SSL socket.
proc getFD*(socket: TSocket): cint = return socket.fd
proc getFD*(socket: TSocket): TSocketHandle = return socket.fd
## Returns the socket's file descriptor
proc isBlocking*(socket: TSocket): bool = not socket.nonblocking
## Determines whether ``socket`` is blocking.
when defined(Windows):
var wsa: TWSADATA
if WSAStartup(0x0101'i16, addr wsa) != 0: OSError(OSLastError())

View File

@@ -849,7 +849,7 @@ const
## a string that describes the application type. Possible values:
## "console", "gui", "lib".
seqShallowFlag = 1 shl (sizeof(int)*8-1)
seqShallowFlag = low(int)
proc compileOption*(option: string): bool {.
magic: "CompileOption", noSideEffect.}
@@ -1791,7 +1791,7 @@ when defined(JS):
elif hostOS != "standalone":
{.push stack_trace:off, profiler:off.}
proc add*(x: var string, y: cstring) {.noStackFrame.} =
proc add*(x: var string, y: cstring) =
var i = 0
while y[i] != '\0':
add(x, y[i])

View File

@@ -9,68 +9,207 @@
# Atomic operations for Nimrod.
when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport and
not defined(windows):
proc sync_add_and_fetch(p: var int, val: int): int {.
importc: "__sync_add_and_fetch", nodecl.}
proc sync_sub_and_fetch(p: var int, val: int): int {.
importc: "__sync_sub_and_fetch", nodecl.}
when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
type
AtomMemModel* = enum
ATOMIC_RELAXED,
## No barriers or synchronization.
ATOMIC_CONSUME,
## Data dependency only for both barrier and synchronization with another thread.
ATOMIC_ACQUIRE,
## Barrier to hoisting of code and synchronizes with release (or stronger)
## semantic stores from another thread.
ATOMIC_RELEASE,
## Barrier to sinking of code and synchronizes with acquire (or stronger)
## semantic loads from another thread.
ATOMIC_ACQ_REL,
## Full barrier in both directions and synchronizes with acquire loads
## and release stores in another thread.
ATOMIC_SEQ_CST
## Full barrier in both directions and synchronizes with acquire loads
## and release stores in all threads.
TAtomType* = TNumber|pointer|ptr|char
## Type Class representing valid types for use with atomic procs
proc atomic_load_n*[T: TAtomType](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 atomic_load*[T: TAtomType](p: ptr T, 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 atomic_store_n*[T: TAtomType](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 atomic_store*[T: TAtomType](p: ptr T, 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 atomic_exchange_n*[T: TAtomType](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 atomic_exchange*[T: TAtomType](p: ptr T, val: ptr T, 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 atomic_compare_exchange_n*[T: TAtomType](p: ptr T, 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
## contents at p with the contents at expected and if equal, writes desired at p.
## If they are not equal, the current contents at p is written into expected.
## Weak is true for weak compare_exchange, and false for the strong variation.
## Many targets only offer the strong variation and ignore the parameter.
## When in doubt, use the strong variation.
## True is returned if desired is written at p and the execution is considered
## to conform to the memory model specified by success_memmodel. There are no
## restrictions on what memory model can be used here. False is returned otherwise,
## and the execution is considered to conform to failure_memmodel. This memory model
## cannot be __ATOMIC_RELEASE nor __ATOMIC_ACQ_REL. It also cannot be a stronger model
## than that specified by success_memmodel.
proc atomic_compare_exchange*[T: TAtomType](p: ptr T, expected: ptr T, desired: ptr T,
weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
importc: "__atomic_compare_exchange_n ", nodecl.}
## This proc implements the generic version of atomic_compare_exchange.
## The proc is virtually identical to atomic_compare_exchange_n, except the desired
## value is also a pointer.
## Perform the operation return the new value, all memory models are valid
proc atomic_add_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_add_fetch", nodecl.}
proc atomic_sub_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_sub_fetch", nodecl.}
proc atomic_or_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_or_fetch ", nodecl.}
proc atomic_and_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_and_fetch", nodecl.}
proc atomic_xor_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_xor_fetch", nodecl.}
proc atomic_nand_fetch*[T: TAtomType](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 atomic_fetch_add*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_add ", nodecl.}
proc atomic_fetch_sub*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_sub ", nodecl.}
proc atomic_fetch_or*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_or ", nodecl.}
proc atomic_fetch_and*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_and ", nodecl.}
proc atomic_fetch_xor*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_xor ", nodecl.}
proc atomic_fetch_nand*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_nand", nodecl.}
proc atomic_test_and_set*(p: pointer, mem: AtomMemModel): bool {.
importc: "__atomic_test_and_set ", nodecl.}
## This built-in function performs an atomic test-and-set operation on the byte at p.
## The byte is set to some implementation defined nonzero “set” value and the return
## value is true if and only if the previous contents were “set”.
## All memory models are valid.
proc atomic_clear*(p: pointer, mem: AtomMemModel) {.
importc: "__atomic_clear", nodecl.}
## This built-in function performs an atomic clear operation at p.
## After the operation, at p contains 0.
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_RELEASE
proc atomic_thread_fence*(mem: AtomMemModel) {.
importc: "__atomic_thread_fence ", nodecl.}
## This built-in function acts as a synchronization fence between threads based
## on the specified memory model. All memory orders are valid.
proc atomic_signal_fence*(mem: AtomMemModel) {.
importc: "__atomic_signal_fence ", nodecl.}
## This built-in function acts as a synchronization fence between a thread and
## signal handlers based in the same thread. All memory orders are valid.
proc atomic_always_lock_free*(size: int, p: pointer): bool {.
importc: "__atomic_always_lock_free ", nodecl.}
## This built-in function returns true if objects of size bytes always generate
## lock free atomic instructions for the target architecture. size must resolve
## to a compile-time constant and the result also resolves to a compile-time constant.
## ptr is an optional pointer to the object that may be used to determine alignment.
## A value of 0 indicates typical alignment should be used. The compiler may also
## ignore this parameter.
proc atomic_is_lock_free*(size: int, p: pointer): bool {.
importc: "__atomic_is_lock_free ", nodecl.}
## This built-in function returns true if objects of size bytes always generate
## lock free atomic instructions for the target architecture. If it is not known
## to be lock free a call is made to a runtime routine named __atomic_is_lock_free.
## ptr is an optional pointer to the object that may be used to determine alignment.
## A value of 0 indicates typical alignment should be used. The compiler may also
## ignore this parameter.
elif defined(vcc) and hasThreadSupport:
proc sync_add_and_fetch(p: var int, val: int): int {.
proc add_and_fetch*(p: ptr int, val: int): int {.
importc: "NimXadd", nodecl.}
else:
proc sync_add_and_fetch(p: var int, val: int): int {.inline.} =
inc(p, val)
result = p
proc add_and_fetch*(p: ptr int, val: int): int {.inline.} =
inc(p[], val)
result = p[]
proc atomicInc(memLoc: var int, x: int = 1): int =
when hasThreadSupport:
result = sync_add_and_fetch(memLoc, x)
# atomic compare and swap (CAS) funcitons to implement lock-free algorithms
#if defined(windows) and not defined(gcc) and hasThreadSupport:
# proc InterlockedCompareExchangePointer(mem: ptr pointer,
# newValue: pointer, comparand: pointer) : pointer {.nodecl,
# importc: "InterlockedCompareExchangePointer", header:"windows.h".}
# proc compareAndSwap*[T](mem: ptr T,
# expected: T, newValue: T): bool {.inline.}=
# ## Returns true if successfully set value at mem to newValue when value
# ## at mem == expected
# return InterlockedCompareExchangePointer(addr(mem),
# addr(newValue), addr(expected))[] == expected
#elif not hasThreadSupport:
# proc compareAndSwap*[T](mem: ptr T,
# expected: T, newValue: T): bool {.inline.} =
# ## Returns true if successfully set value at mem to newValue when value
# ## at mem == expected
# var oldval = mem[]
# if oldval == expected:
# mem[] = newValue
# return true
# return false
# Some convenient functions
proc atomicInc*(memLoc: var int, x: int = 1): int =
when defined(gcc) and hasThreadSupport:
result = atomic_add_fetch(memLoc.addr, x, ATOMIC_RELAXED)
else:
inc(memLoc, x)
result = memLoc
proc atomicDec(memLoc: var int, x: int = 1): int =
when hasThreadSupport:
when defined(sync_sub_and_fetch):
result = sync_sub_and_fetch(memLoc, x)
proc atomicDec*(memLoc: var int, x: int = 1): int =
when defined(gcc) and hasThreadSupport:
when defined(atomic_sub_fetch):
result = atomic_sub_fetch(memLoc.addr, x, ATOMIC_RELAXED)
else:
result = sync_add_and_fetch(memLoc, -x)
result = atomic_add_fetch(memLoc.addr, -x, ATOMIC_RELAXED)
else:
dec(memLoc, x)
result = memLoc
# atomic compare and swap (CAS) funcitons to implement lock-free algorithms
when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
proc compareAndSwap*[T: ptr|ref|pointer](mem: var T, expected: T, newValue: T): bool {.nodecl,
importc: " __sync_bool_compare_and_swap".}
## Returns true if successfully set value at mem to newValue when value
## at mem == expected
elif defined(windows) and hasThreadSupport:
proc InterlockedCompareExchangePointer(mem: ptr pointer,
newValue: pointer, comparand: pointer) : pointer {.nodecl,
importc: "InterlockedCompareExchangePointer", header:"windows.h".}
proc compareAndSwap*[T: ptr|ref|pointer](mem: var T,
expected: T, newValue: T): bool {.inline.}=
## Returns true if successfully set value at mem to newValue when value
## at mem == expected
return InterlockedCompareExchangePointer(addr(mem),
newValue, expected) == expected
elif not hasThreadSupport:
proc compareAndSwap*[T: ptr|ref|pointer](mem: var T,
expected: T, newValue: T): bool {.inline.} =
## Returns true if successfully set value at mem to newValue when value
## at mem == expected
var oldval = mem
if oldval == expected:
mem = newValue
return true
return false

View File

@@ -334,6 +334,9 @@ const
proc WSAGetLastError*(): cint {.importc: "WSAGetLastError", dynlib: ws2dll.}
type
TSocketHandle* = distinct int
type
TWSAData* {.pure, final, importc: "WSADATA", header: "Winsock2.h".} = object
wVersion, wHighVersion: int16
@@ -389,12 +392,10 @@ type
h_addrtype*: int16
h_length*: int16
h_addr_list*: cstringArray
TWinSocket* = cint
TFdSet* {.pure, final.} = object
fd_count*: cint # unsigned
fd_array*: array[0..FD_SETSIZE-1, TWinSocket]
fd_array*: array[0..FD_SETSIZE-1, TSocketHandle]
TTimeval* {.pure, final.} = object
tv_sec*, tv_usec*: int32
@@ -413,6 +414,22 @@ type
var
SOMAXCONN* {.importc, header: "Winsock2.h".}: cint
INVALID_SOCKET* {.importc, header: "Winsock2.h".}: TSocketHandle
SOL_SOCKET* {.importc, header: "Winsock2.h".}: cint
SO_DEBUG* {.importc, header: "Winsock2.h".}: cint ## turn on debugging info recording
SO_ACCEPTCONN* {.importc, header: "Winsock2.h".}: cint # socket has had listen()
SO_REUSEADDR* {.importc, header: "Winsock2.h".}: cint # allow local address reuse
SO_KEEPALIVE* {.importc, header: "Winsock2.h".}: cint # keep connections alive
SO_DONTROUTE* {.importc, header: "Winsock2.h".}: cint # just use interface addresses
SO_BROADCAST* {.importc, header: "Winsock2.h".}: cint # permit sending of broadcast msgs
SO_USELOOPBACK* {.importc, header: "Winsock2.h".}: cint # bypass hardware when possible
SO_LINGER* {.importc, header: "Winsock2.h".}: cint # linger on close if data present
SO_OOBINLINE* {.importc, header: "Winsock2.h".}: cint # leave received OOB data in line
SO_DONTLINGER* {.importc, header: "Winsock2.h".}: cint
SO_EXCLUSIVEADDRUSE* {.importc, header: "Winsock2.h".}: cint # disallow local address reuse
proc `==`*(x, y: TSocketHandle): bool {.borrow.}
proc getservbyname*(name, proto: cstring): ptr TServent {.
stdcall, importc: "getservbyname", dynlib: ws2dll.}
@@ -426,45 +443,45 @@ proc gethostbyaddr*(ip: ptr TInAddr, len: cuint, theType: cint): ptr THostEnt {.
proc gethostbyname*(name: cstring): ptr THostEnt {.
stdcall, importc: "gethostbyname", dynlib: ws2dll.}
proc socket*(af, typ, protocol: cint): TWinSocket {.
proc socket*(af, typ, protocol: cint): TSocketHandle {.
stdcall, importc: "socket", dynlib: ws2dll.}
proc closesocket*(s: TWinSocket): cint {.
proc closesocket*(s: TSocketHandle): cint {.
stdcall, importc: "closesocket", dynlib: ws2dll.}
proc accept*(s: TWinSocket, a: ptr TSockAddr, addrlen: ptr TSockLen): TWinSocket {.
proc accept*(s: TSocketHandle, a: ptr TSockAddr, addrlen: ptr TSockLen): TSocketHandle {.
stdcall, importc: "accept", dynlib: ws2dll.}
proc bindSocket*(s: TWinSocket, name: ptr TSockAddr, namelen: TSockLen): cint {.
proc bindSocket*(s: TSocketHandle, name: ptr TSockAddr, namelen: TSockLen): cint {.
stdcall, importc: "bind", dynlib: ws2dll.}
proc connect*(s: TWinSocket, name: ptr TSockAddr, namelen: TSockLen): cint {.
proc connect*(s: TSocketHandle, name: ptr TSockAddr, namelen: TSockLen): cint {.
stdcall, importc: "connect", dynlib: ws2dll.}
proc getsockname*(s: TWinSocket, name: ptr TSockAddr,
proc getsockname*(s: TSocketHandle, name: ptr TSockAddr,
namelen: ptr TSockLen): cint {.
stdcall, importc: "getsockname", dynlib: ws2dll.}
proc getsockopt*(s: TWinSocket, level, optname: cint, optval: pointer,
proc getsockopt*(s: TSocketHandle, level, optname: cint, optval: pointer,
optlen: ptr TSockLen): cint {.
stdcall, importc: "getsockopt", dynlib: ws2dll.}
proc setsockopt*(s: TWinSocket, level, optname: cint, optval: pointer,
proc setsockopt*(s: TSocketHandle, level, optname: cint, optval: pointer,
optlen: TSockLen): cint {.
stdcall, importc: "setsockopt", dynlib: ws2dll.}
proc listen*(s: TWinSocket, backlog: cint): cint {.
proc listen*(s: TSocketHandle, backlog: cint): cint {.
stdcall, importc: "listen", dynlib: ws2dll.}
proc recv*(s: TWinSocket, buf: pointer, len, flags: cint): cint {.
proc recv*(s: TSocketHandle, buf: pointer, len, flags: cint): cint {.
stdcall, importc: "recv", dynlib: ws2dll.}
proc recvfrom*(s: TWinSocket, buf: cstring, len, flags: cint,
proc recvfrom*(s: TSocketHandle, buf: cstring, len, flags: cint,
fromm: ptr TSockAddr, fromlen: ptr Tsocklen): cint {.
stdcall, importc: "recvfrom", dynlib: ws2dll.}
proc select*(nfds: cint, readfds, writefds, exceptfds: ptr TFdSet,
timeout: ptr TTimeval): cint {.
stdcall, importc: "select", dynlib: ws2dll.}
proc send*(s: TWinSocket, buf: pointer, len, flags: cint): cint {.
proc send*(s: TSocketHandle, buf: pointer, len, flags: cint): cint {.
stdcall, importc: "send", dynlib: ws2dll.}
proc sendto*(s: TWinSocket, buf: pointer, len, flags: cint,
proc sendto*(s: TSocketHandle, buf: pointer, len, flags: cint,
to: ptr TSockAddr, tolen: Tsocklen): cint {.
stdcall, importc: "sendto", dynlib: ws2dll.}
proc shutdown*(s: TWinSocket, how: cint): cint {.
proc shutdown*(s: TSocketHandle, how: cint): cint {.
stdcall, importc: "shutdown", dynlib: ws2dll.}
proc getnameinfo*(a1: ptr Tsockaddr, a2: Tsocklen,
@@ -475,13 +492,13 @@ proc getnameinfo*(a1: ptr Tsockaddr, a2: Tsocklen,
proc inet_addr*(cp: cstring): int32 {.
stdcall, importc: "inet_addr", dynlib: ws2dll.}
proc WSAFDIsSet(s: TWinSocket, FDSet: var TFDSet): bool {.
proc WSAFDIsSet(s: TSocketHandle, FDSet: var TFDSet): bool {.
stdcall, importc: "__WSAFDIsSet", dynlib: ws2dll.}
proc FD_ISSET*(Socket: TWinSocket, FDSet: var TFDSet): cint =
proc FD_ISSET*(Socket: TSocketHandle, FDSet: var TFDSet): cint =
result = if WSAFDIsSet(Socket, FDSet): 1'i32 else: 0'i32
proc FD_SET*(Socket: TWinSocket, FDSet: var TFDSet) =
proc FD_SET*(Socket: TSocketHandle, FDSet: var TFDSet) =
if FDSet.fd_count < FD_SETSIZE:
FDSet.fd_array[int(FDSet.fd_count)] = Socket
inc(FDSet.fd_count)

View File

@@ -36,23 +36,23 @@ else:
const
dllname = "libGL.so"
const
GLX_USE_GL* = 1
GLX_BUFFER_SIZE* = 2
GLX_LEVEL* = 3
GLX_RGBA* = 4
GLX_DOUBLEBUFFER* = 5
GLX_STEREO* = 6
GLX_AUX_BUFFERS* = 7
GLX_RED_SIZE* = 8
GLX_GREEN_SIZE* = 9
GLX_BLUE_SIZE* = 10
GLX_ALPHA_SIZE* = 11
GLX_DEPTH_SIZE* = 12
GLX_STENCIL_SIZE* = 13
GLX_ACCUM_RED_SIZE* = 14
GLX_ACCUM_GREEN_SIZE* = 15
GLX_ACCUM_BLUE_SIZE* = 16
GLX_ACCUM_ALPHA_SIZE* = 17 # GLX_EXT_visual_info extension
GLX_USE_GL* = 1'i32
GLX_BUFFER_SIZE* = 2'i32
GLX_LEVEL* = 3'i32
GLX_RGBA* = 4'i32
GLX_DOUBLEBUFFER* = 5'i32
GLX_STEREO* = 6'i32
GLX_AUX_BUFFERS* = 7'i32
GLX_RED_SIZE* = 8'i32
GLX_GREEN_SIZE* = 9'i32
GLX_BLUE_SIZE* = 10'i32
GLX_ALPHA_SIZE* = 11'i32
GLX_DEPTH_SIZE* = 12'i32
GLX_STENCIL_SIZE* = 13'i32
GLX_ACCUM_RED_SIZE* = 14'i32
GLX_ACCUM_GREEN_SIZE* = 15'i32
GLX_ACCUM_BLUE_SIZE* = 16'i32
GLX_ACCUM_ALPHA_SIZE* = 17'i32 # GLX_EXT_visual_info extension
GLX_X_VISUAL_TYPE_EXT* = 0x00000022
GLX_TRANSPARENT_TYPE_EXT* = 0x00000023
GLX_TRANSPARENT_INDEX_VALUE_EXT* = 0x00000024

View File

@@ -45,6 +45,7 @@ when defined(WINDOWS):
const
DLLSSLName = "(ssleay32|libssl32).dll"
DLLUtilName = "libeay32.dll"
from winlean import TSocketHandle
else:
const
versions = "(|.1.0.0|.0.9.9|.0.9.8|.0.9.7|.0.9.6|.0.9.5|.0.9.4)"
@@ -56,6 +57,7 @@ else:
const
DLLSSLName = "libssl.so" & versions
DLLUtilName = "libcrypto.so" & versions
from posix import TSocketHandle
type
SslStruct {.final, pure.} = object
@@ -225,7 +227,7 @@ proc SSL_CTX_use_PrivateKey_file*(ctx: PSSL_CTX,
proc SSL_CTX_check_private_key*(ctx: PSSL_CTX): cInt{.cdecl, dynlib: DLLSSLName,
importc.}
proc SSL_set_fd*(ssl: PSSL, fd: cint): cint{.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_set_fd*(ssl: PSSL, fd: TSocketHandle): cint{.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_shutdown*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_connect*(ssl: PSSL): cint{.cdecl, dynlib: DLLSSLName, importc.}

File diff suppressed because it is too large Load Diff

View File

@@ -1811,210 +1811,217 @@ proc XSetAuthorization*(para1: cstring, para2: cint, para3: cstring, para4: cint
# _Xmbtowc?
# _Xwctomb?
#
when defined(MACROS):
proc ConnectionNumber*(dpy: PDisplay): cint
proc RootWindow*(dpy: PDisplay, scr: cint): TWindow
proc DefaultScreen*(dpy: PDisplay): cint
proc DefaultRootWindow*(dpy: PDisplay): TWindow
proc DefaultVisual*(dpy: PDisplay, scr: cint): PVisual
proc DefaultGC*(dpy: PDisplay, scr: cint): TGC
proc BlackPixel*(dpy: PDisplay, scr: cint): culong
proc WhitePixel*(dpy: PDisplay, scr: cint): culong
proc QLength*(dpy: PDisplay): cint
proc DisplayWidth*(dpy: PDisplay, scr: cint): cint
proc DisplayHeight*(dpy: PDisplay, scr: cint): cint
proc DisplayWidthMM*(dpy: PDisplay, scr: cint): cint
proc DisplayHeightMM*(dpy: PDisplay, scr: cint): cint
proc DisplayPlanes*(dpy: PDisplay, scr: cint): cint
proc DisplayCells*(dpy: PDisplay, scr: cint): cint
proc ScreenCount*(dpy: PDisplay): cint
proc ServerVendor*(dpy: PDisplay): cstring
proc ProtocolVersion*(dpy: PDisplay): cint
proc ProtocolRevision*(dpy: PDisplay): cint
proc VendorRelease*(dpy: PDisplay): cint
proc DisplayString*(dpy: PDisplay): cstring
proc DefaultDepth*(dpy: PDisplay, scr: cint): cint
proc DefaultColormap*(dpy: PDisplay, scr: cint): TColormap
proc BitmapUnit*(dpy: PDisplay): cint
proc BitmapBitOrder*(dpy: PDisplay): cint
proc BitmapPad*(dpy: PDisplay): cint
proc ImageByteOrder*(dpy: PDisplay): cint
proc NextRequest*(dpy: PDisplay): culong
proc LastKnownRequestProcessed*(dpy: PDisplay): culong
proc ScreenOfDisplay*(dpy: PDisplay, scr: cint): PScreen
proc DefaultScreenOfDisplay*(dpy: PDisplay): PScreen
proc DisplayOfScreen*(s: PScreen): PDisplay
proc RootWindowOfScreen*(s: PScreen): TWindow
proc BlackPixelOfScreen*(s: PScreen): culong
proc WhitePixelOfScreen*(s: PScreen): culong
proc DefaultColormapOfScreen*(s: PScreen): TColormap
proc DefaultDepthOfScreen*(s: PScreen): cint
proc DefaultGCOfScreen*(s: PScreen): TGC
proc DefaultVisualOfScreen*(s: PScreen): PVisual
proc WidthOfScreen*(s: PScreen): cint
proc HeightOfScreen*(s: PScreen): cint
proc WidthMMOfScreen*(s: PScreen): cint
proc HeightMMOfScreen*(s: PScreen): cint
proc PlanesOfScreen*(s: PScreen): cint
proc CellsOfScreen*(s: PScreen): cint
proc MinCmapsOfScreen*(s: PScreen): cint
proc MaxCmapsOfScreen*(s: PScreen): cint
proc DoesSaveUnders*(s: PScreen): TBool
proc DoesBackingStore*(s: PScreen): cint
proc EventMaskOfScreen*(s: PScreen): clong
proc XAllocID*(dpy: PDisplay): TXID
#when defined(MACROS):
proc ConnectionNumber*(dpy: PDisplay): cint
proc RootWindow*(dpy: PDisplay, scr: cint): TWindow
proc DefaultScreen*(dpy: PDisplay): cint
proc DefaultRootWindow*(dpy: PDisplay): TWindow
proc DefaultVisual*(dpy: PDisplay, scr: cint): PVisual
proc DefaultGC*(dpy: PDisplay, scr: cint): TGC
proc BlackPixel*(dpy: PDisplay, scr: cint): culong
proc WhitePixel*(dpy: PDisplay, scr: cint): culong
proc QLength*(dpy: PDisplay): cint
proc DisplayWidth*(dpy: PDisplay, scr: cint): cint
proc DisplayHeight*(dpy: PDisplay, scr: cint): cint
proc DisplayWidthMM*(dpy: PDisplay, scr: cint): cint
proc DisplayHeightMM*(dpy: PDisplay, scr: cint): cint
proc DisplayPlanes*(dpy: PDisplay, scr: cint): cint
proc DisplayCells*(dpy: PDisplay, scr: cint): cint
proc ScreenCount*(dpy: PDisplay): cint
proc ServerVendor*(dpy: PDisplay): cstring
proc ProtocolVersion*(dpy: PDisplay): cint
proc ProtocolRevision*(dpy: PDisplay): cint
proc VendorRelease*(dpy: PDisplay): cint
proc DisplayString*(dpy: PDisplay): cstring
proc DefaultDepth*(dpy: PDisplay, scr: cint): cint
proc DefaultColormap*(dpy: PDisplay, scr: cint): TColormap
proc BitmapUnit*(dpy: PDisplay): cint
proc BitmapBitOrder*(dpy: PDisplay): cint
proc BitmapPad*(dpy: PDisplay): cint
proc ImageByteOrder*(dpy: PDisplay): cint
proc NextRequest*(dpy: PDisplay): culong
proc LastKnownRequestProcessed*(dpy: PDisplay): culong
proc ScreenOfDisplay*(dpy: PDisplay, scr: cint): PScreen
proc DefaultScreenOfDisplay*(dpy: PDisplay): PScreen
proc DisplayOfScreen*(s: PScreen): PDisplay
proc RootWindowOfScreen*(s: PScreen): TWindow
proc BlackPixelOfScreen*(s: PScreen): culong
proc WhitePixelOfScreen*(s: PScreen): culong
proc DefaultColormapOfScreen*(s: PScreen): TColormap
proc DefaultDepthOfScreen*(s: PScreen): cint
proc DefaultGCOfScreen*(s: PScreen): TGC
proc DefaultVisualOfScreen*(s: PScreen): PVisual
proc WidthOfScreen*(s: PScreen): cint
proc HeightOfScreen*(s: PScreen): cint
proc WidthMMOfScreen*(s: PScreen): cint
proc HeightMMOfScreen*(s: PScreen): cint
proc PlanesOfScreen*(s: PScreen): cint
proc CellsOfScreen*(s: PScreen): cint
proc MinCmapsOfScreen*(s: PScreen): cint
proc MaxCmapsOfScreen*(s: PScreen): cint
proc DoesSaveUnders*(s: PScreen): TBool
proc DoesBackingStore*(s: PScreen): cint
proc EventMaskOfScreen*(s: PScreen): clong
proc XAllocID*(dpy: PDisplay): TXID
# implementation
when defined(MACROS):
proc ConnectionNumber(dpy: PDisplay): cint =
ConnectionNumber = (PXPrivDisplay(dpy))[] .fd
#when defined(MACROS):
template privDisp : expr = cast[PXPrivDisplay](dpy)
proc ConnectionNumber(dpy: PDisplay): cint =
privDisp.fd
proc RootWindow(dpy: PDisplay, scr: cint): TWindow =
RootWindow = (ScreenOfDisplay(dpy, scr))[] .root
proc RootWindow(dpy: PDisplay, scr: cint): TWindow =
ScreenOfDisplay(dpy, scr).root
proc DefaultScreen(dpy: PDisplay): cint =
DefaultScreen = (PXPrivDisplay(dpy))[] .default_screen
proc DefaultScreen(dpy: PDisplay): cint =
privDisp.default_screen
proc DefaultRootWindow(dpy: PDisplay): TWindow =
DefaultRootWindow = (ScreenOfDisplay(dpy, DefaultScreen(dpy)))[] .root
proc DefaultRootWindow(dpy: PDisplay): TWindow =
ScreenOfDisplay(dpy, DefaultScreen(dpy)).root
proc DefaultVisual(dpy: PDisplay, scr: cint): PVisual =
DefaultVisual = (ScreenOfDisplay(dpy, scr))[] .root_visual
proc DefaultVisual(dpy: PDisplay, scr: cint): PVisual =
ScreenOfDisplay(dpy, scr).root_visual
proc DefaultGC(dpy: PDisplay, scr: cint): TGC =
DefaultGC = (ScreenOfDisplay(dpy, scr))[] .default_gc
proc DefaultGC(dpy: PDisplay, scr: cint): TGC =
ScreenOfDisplay(dpy, scr).default_gc
proc BlackPixel(dpy: PDisplay, scr: cint): culong =
BlackPixel = (ScreenOfDisplay(dpy, scr))[] .black_pixel
proc BlackPixel(dpy: PDisplay, scr: cint): culong =
ScreenOfDisplay(dpy, scr).black_pixel
proc WhitePixel(dpy: PDisplay, scr: cint): culong =
WhitePixel = (ScreenOfDisplay(dpy, scr))[] .white_pixel
proc WhitePixel(dpy: PDisplay, scr: cint): culong =
ScreenOfDisplay(dpy, scr).white_pixel
proc QLength(dpy: PDisplay): cint =
QLength = (PXPrivDisplay(dpy))[] .qlen
proc QLength(dpy: PDisplay): cint =
privDisp.qlen
proc DisplayWidth(dpy: PDisplay, scr: cint): cint =
DisplayWidth = (ScreenOfDisplay(dpy, scr))[] .width
proc DisplayWidth(dpy: PDisplay, scr: cint): cint =
ScreenOfDisplay(dpy, scr).width
proc DisplayHeight(dpy: PDisplay, scr: cint): cint =
DisplayHeight = (ScreenOfDisplay(dpy, scr))[] .height
proc DisplayHeight(dpy: PDisplay, scr: cint): cint =
ScreenOfDisplay(dpy, scr).height
proc DisplayWidthMM(dpy: PDisplay, scr: cint): cint =
DisplayWidthMM = (ScreenOfDisplay(dpy, scr))[] .mwidth
proc DisplayWidthMM(dpy: PDisplay, scr: cint): cint =
ScreenOfDisplay(dpy, scr).mwidth
proc DisplayHeightMM(dpy: PDisplay, scr: cint): cint =
DisplayHeightMM = (ScreenOfDisplay(dpy, scr))[] .mheight
proc DisplayHeightMM(dpy: PDisplay, scr: cint): cint =
ScreenOfDisplay(dpy, scr).mheight
proc DisplayPlanes(dpy: PDisplay, scr: cint): cint =
DisplayPlanes = (ScreenOfDisplay(dpy, scr))[] .root_depth
proc DisplayPlanes(dpy: PDisplay, scr: cint): cint =
ScreenOfDisplay(dpy, scr).root_depth
proc DisplayCells(dpy: PDisplay, scr: cint): cint =
DisplayCells = (DefaultVisual(dpy, scr))[] .map_entries
proc DisplayCells(dpy: PDisplay, scr: cint): cint =
DefaultVisual(dpy, scr).map_entries
proc ScreenCount(dpy: PDisplay): cint =
ScreenCount = (PXPrivDisplay(dpy))[] .nscreens
proc ScreenCount(dpy: PDisplay): cint =
privDisp.nscreens
proc ServerVendor(dpy: PDisplay): cstring =
ServerVendor = (PXPrivDisplay(dpy))[] .vendor
proc ServerVendor(dpy: PDisplay): cstring =
privDisp.vendor
proc ProtocolVersion(dpy: PDisplay): cint =
ProtocolVersion = (PXPrivDisplay(dpy))[] .proto_major_version
proc ProtocolVersion(dpy: PDisplay): cint =
privDisp.proto_major_version
proc ProtocolRevision(dpy: PDisplay): cint =
ProtocolRevision = (PXPrivDisplay(dpy))[] .proto_minor_version
proc ProtocolRevision(dpy: PDisplay): cint =
privDisp.proto_minor_version
proc VendorRelease(dpy: PDisplay): cint =
VendorRelease = (PXPrivDisplay(dpy))[] .release
proc VendorRelease(dpy: PDisplay): cint =
privDisp.release
proc DisplayString(dpy: PDisplay): cstring =
DisplayString = (PXPrivDisplay(dpy))[] .display_name
proc DisplayString(dpy: PDisplay): cstring =
privDisp.display_name
proc DefaultDepth(dpy: PDisplay, scr: cint): cint =
DefaultDepth = (ScreenOfDisplay(dpy, scr))[] .root_depth
proc DefaultDepth(dpy: PDisplay, scr: cint): cint =
ScreenOfDisplay(dpy, scr).root_depth
proc DefaultColormap(dpy: PDisplay, scr: cint): TColormap =
DefaultColormap = (ScreenOfDisplay(dpy, scr))[] .cmap
proc DefaultColormap(dpy: PDisplay, scr: cint): TColormap =
ScreenOfDisplay(dpy, scr).cmap
proc BitmapUnit(dpy: PDisplay): cint =
BitmapUnit = (PXPrivDisplay(dpy))[] .bitmap_unit
proc BitmapUnit(dpy: PDisplay): cint =
privDisp.bitmap_unit
proc BitmapBitOrder(dpy: PDisplay): cint =
BitmapBitOrder = (PXPrivDisplay(dpy))[] .bitmap_bit_order
proc BitmapBitOrder(dpy: PDisplay): cint =
privDisp.bitmap_bit_order
proc BitmapPad(dpy: PDisplay): cint =
BitmapPad = (PXPrivDisplay(dpy))[] .bitmap_pad
proc BitmapPad(dpy: PDisplay): cint =
privDisp.bitmap_pad
proc ImageByteOrder(dpy: PDisplay): cint =
ImageByteOrder = (PXPrivDisplay(dpy))[] .byte_order
proc ImageByteOrder(dpy: PDisplay): cint =
privDisp.byte_order
proc NextRequest(dpy: PDisplay): culong =
NextRequest = ((PXPrivDisplay(dpy))[] .request) + 1
import unsigned
proc NextRequest(dpy: PDisplay): culong =
privDisp.request + 1.culong
proc LastKnownRequestProcessed(dpy: PDisplay): culong =
LastKnownRequestProcessed = (PXPrivDisplay(dpy))[] .last_request_read
proc LastKnownRequestProcessed(dpy: PDisplay): culong =
privDisp.last_request_read
proc ScreenOfDisplay(dpy: PDisplay, scr: cint): PScreen =
ScreenOfDisplay = addr((((PXPrivDisplay(dpy))[] .screens)[scr]))
# from fowltek/pointer_arithm, required for ScreenOfDisplay()
proc offset[A] (some: ptr A; b: int): ptr A =
cast[ptr A](cast[int](some) + (b * sizeof(A)))
proc ScreenOfDisplay(dpy: PDisplay, scr: cint): PScreen =
#addr(((privDisp.screens)[scr]))
privDisp.screens.offset(scr.int)
proc DefaultScreenOfDisplay(dpy: PDisplay): PScreen =
DefaultScreenOfDisplay = ScreenOfDisplay(dpy, DefaultScreen(dpy))
proc DefaultScreenOfDisplay(dpy: PDisplay): PScreen =
ScreenOfDisplay(dpy, DefaultScreen(dpy))
proc DisplayOfScreen(s: PScreen): PDisplay =
DisplayOfScreen = s[] .display
proc DisplayOfScreen(s: PScreen): PDisplay =
s.display
proc RootWindowOfScreen(s: PScreen): TWindow =
RootWindowOfScreen = s[] .root
proc RootWindowOfScreen(s: PScreen): TWindow =
s.root
proc BlackPixelOfScreen(s: PScreen): culong =
BlackPixelOfScreen = s[] .black_pixel
proc BlackPixelOfScreen(s: PScreen): culong =
s.black_pixel
proc WhitePixelOfScreen(s: PScreen): culong =
WhitePixelOfScreen = s[] .white_pixel
proc WhitePixelOfScreen(s: PScreen): culong =
s.white_pixel
proc DefaultColormapOfScreen(s: PScreen): TColormap =
DefaultColormapOfScreen = s[] .cmap
proc DefaultColormapOfScreen(s: PScreen): TColormap =
s.cmap
proc DefaultDepthOfScreen(s: PScreen): cint =
DefaultDepthOfScreen = s[] .root_depth
proc DefaultDepthOfScreen(s: PScreen): cint =
s.root_depth
proc DefaultGCOfScreen(s: PScreen): TGC =
DefaultGCOfScreen = s[] .default_gc
proc DefaultGCOfScreen(s: PScreen): TGC =
s.default_gc
proc DefaultVisualOfScreen(s: PScreen): PVisual =
DefaultVisualOfScreen = s[] .root_visual
proc DefaultVisualOfScreen(s: PScreen): PVisual =
s.root_visual
proc WidthOfScreen(s: PScreen): cint =
WidthOfScreen = s[] .width
proc WidthOfScreen(s: PScreen): cint =
s.width
proc HeightOfScreen(s: PScreen): cint =
HeightOfScreen = s[] .height
proc HeightOfScreen(s: PScreen): cint =
s.height
proc WidthMMOfScreen(s: PScreen): cint =
WidthMMOfScreen = s[] .mwidth
proc WidthMMOfScreen(s: PScreen): cint =
s.mwidth
proc HeightMMOfScreen(s: PScreen): cint =
HeightMMOfScreen = s[] .mheight
proc HeightMMOfScreen(s: PScreen): cint =
s.mheight
proc PlanesOfScreen(s: PScreen): cint =
PlanesOfScreen = s[] .root_depth
proc PlanesOfScreen(s: PScreen): cint =
s.root_depth
proc CellsOfScreen(s: PScreen): cint =
CellsOfScreen = (DefaultVisualOfScreen(s))[] .map_entries
proc CellsOfScreen(s: PScreen): cint =
DefaultVisualOfScreen(s).map_entries
proc MinCmapsOfScreen(s: PScreen): cint =
MinCmapsOfScreen = s[] .min_maps
proc MinCmapsOfScreen(s: PScreen): cint =
s.min_maps
proc MaxCmapsOfScreen(s: PScreen): cint =
MaxCmapsOfScreen = s[] .max_maps
proc MaxCmapsOfScreen(s: PScreen): cint =
s.max_maps
proc DoesSaveUnders(s: PScreen): TBool =
DoesSaveUnders = s[] .save_unders
proc DoesSaveUnders(s: PScreen): TBool =
s.save_unders
proc DoesBackingStore(s: PScreen): cint =
DoesBackingStore = s[] .backing_store
proc DoesBackingStore(s: PScreen): cint =
s.backing_store
proc EventMaskOfScreen(s: PScreen): clong =
EventMaskOfScreen = s[] .root_input_mask
proc EventMaskOfScreen(s: PScreen): clong =
s.root_input_mask
proc XAllocID(dpy: PDisplay): TXID =
XAllocID = (PXPrivDisplay(dpy))[] .resource_alloc(dpy)
proc XAllocID(dpy: PDisplay): TXID =
privDisp.resource_alloc(dpy)

View File

@@ -1,6 +1,6 @@
import
x, xlib, keysym
x, xlib, keysym, unsigned
#const
# libX11* = "libX11.so"
@@ -356,57 +356,57 @@ proc XWMGeometry*(para1: PDisplay, para2: cint, para3: cstring, para4: cstring,
dynlib: libX11, importc.}
proc XXorRegion*(para1: TRegion, para2: TRegion, para3: TRegion): cint{.cdecl,
dynlib: libX11, importc.}
when defined(MACROS):
proc XDestroyImage*(ximage: PXImage): cint
proc XGetPixel*(ximage: PXImage, x, y: cint): culong
proc XPutPixel*(ximage: PXImage, x, y: cint, pixel: culong): cint
proc XSubImage*(ximage: PXImage, x, y: cint, width, height: cuint): PXImage
proc XAddPixel*(ximage: PXImage, value: clong): cint
proc IsKeypadKey*(keysym: TKeySym): bool
proc IsPrivateKeypadKey*(keysym: TKeySym): bool
proc IsCursorKey*(keysym: TKeySym): bool
proc IsPFKey*(keysym: TKeySym): bool
proc IsFunctionKey*(keysym: TKeySym): bool
proc IsMiscFunctionKey*(keysym: TKeySym): bool
proc IsModifierKey*(keysym: TKeySym): bool
#function XUniqueContext : TXContext;
#function XStringToContext(_string : Pchar) : TXContext;
#when defined(MACROS):
proc XDestroyImage*(ximage: PXImage): cint
proc XGetPixel*(ximage: PXImage, x, y: cint): culong
proc XPutPixel*(ximage: PXImage, x, y: cint, pixel: culong): cint
proc XSubImage*(ximage: PXImage, x, y: cint, width, height: cuint): PXImage
proc XAddPixel*(ximage: PXImage, value: clong): cint
proc IsKeypadKey*(keysym: TKeySym): bool
proc IsPrivateKeypadKey*(keysym: TKeySym): bool
proc IsCursorKey*(keysym: TKeySym): bool
proc IsPFKey*(keysym: TKeySym): bool
proc IsFunctionKey*(keysym: TKeySym): bool
proc IsMiscFunctionKey*(keysym: TKeySym): bool
proc IsModifierKey*(keysym: TKeySym): bool
#function XUniqueContext : TXContext;
#function XStringToContext(_string : Pchar) : TXContext;
# implementation
when defined(MACROS):
proc XDestroyImage(ximage: PXImage): cint =
XDestroyImage = ximage[] .f.destroy_image(ximage)
#when defined(MACROS):
proc XDestroyImage(ximage: PXImage): cint =
ximage.f.destroy_image(ximage)
proc XGetPixel(ximage: PXImage, x, y: cint): culong =
XGetPixel = ximage[] .f.get_pixel(ximage, x, y)
proc XGetPixel(ximage: PXImage, x, y: cint): culong =
ximage.f.get_pixel(ximage, x, y)
proc XPutPixel(ximage: PXImage, x, y: cint, pixel: culong): cint =
XPutPixel = ximage[] .f.put_pixel(ximage, x, y, pixel)
proc XPutPixel(ximage: PXImage, x, y: cint, pixel: culong): cint =
ximage.f.put_pixel(ximage, x, y, pixel)
proc XSubImage(ximage: PXImage, x, y: cint, width, height: cuint): PXImage =
XSubImage = ximage[] .f.sub_image(ximage, x, y, width, height)
proc XSubImage(ximage: PXImage, x, y: cint, width, height: cuint): PXImage =
ximage.f.sub_image(ximage, x, y, width, height)
proc XAddPixel(ximage: PXImage, value: clong): cint =
XAddPixel = ximage[] .f.add_pixel(ximage, value)
proc XAddPixel(ximage: PXImage, value: clong): cint =
ximage.f.add_pixel(ximage, value)
proc IsKeypadKey(keysym: TKeySym): bool =
IsKeypadKey = (keysym >= XK_KP_Space) and (keysym <= XK_KP_Equal)
proc IsKeypadKey(keysym: TKeySym): bool =
(keysym >= XK_KP_Space) and (keysym <= XK_KP_Equal)
proc IsPrivateKeypadKey(keysym: TKeySym): bool =
IsPrivateKeypadKey = (keysym >= 0x11000000) and (keysym <= 0x1100FFFF)
proc IsPrivateKeypadKey(keysym: TKeySym): bool =
(keysym >= 0x11000000.TKeySym) and (keysym <= 0x1100FFFF.TKeySym)
proc IsCursorKey(keysym: TKeySym): bool =
IsCursorKey = (keysym >= XK_Home) and (keysym < XK_Select)
proc IsCursorKey(keysym: TKeySym): bool =
(keysym >= XK_Home) and (keysym < XK_Select)
proc IsPFKey(keysym: TKeySym): bool =
IsPFKey = (keysym >= XK_KP_F1) and (keysym <= XK_KP_F4)
proc IsPFKey(keysym: TKeySym): bool =
(keysym >= XK_KP_F1) and (keysym <= XK_KP_F4)
proc IsFunctionKey(keysym: TKeySym): bool =
IsFunctionKey = (keysym >= XK_F1) and (keysym <= XK_F35)
proc IsFunctionKey(keysym: TKeySym): bool =
(keysym >= XK_F1) and (keysym <= XK_F35)
proc IsMiscFunctionKey(keysym: TKeySym): bool =
IsMiscFunctionKey = (keysym >= XK_Select) and (keysym <= XK_Break)
proc IsMiscFunctionKey(keysym: TKeySym): bool =
(keysym >= XK_Select) and (keysym <= XK_Break)
proc IsModifierKey(keysym: TKeySym): bool =
IsModifierKey = ((keysym >= XK_Shift_L) And (keysym <= XK_Hyper_R)) Or
(keysym == XK_Mode_switch) Or (keysym == XK_Num_Lock)
proc IsModifierKey(keysym: TKeySym): bool =
((keysym >= XK_Shift_L) And (keysym <= XK_Hyper_R)) Or
(keysym == XK_Mode_switch) Or (keysym == XK_Num_Lock)

View File

@@ -102,6 +102,7 @@ proc compress2*(dest: pbytef, destLen: puLongf, source: pbytef,
proc uncompress*(dest: pbytef, destLen: puLongf, source: pbytef,
sourceLen: uLong): cint{.cdecl, dynlib: libz,
importc: "uncompress".}
proc compressBound*(sourceLen: uLong): uLong {.cdecl, dynlib: libz, importc.}
proc gzopen*(path: cstring, mode: cstring): gzFile{.cdecl, dynlib: libz,
importc: "gzopen".}
proc gzdopen*(fd: int32, mode: cstring): gzFile{.cdecl, dynlib: libz,

View File

@@ -9,9 +9,9 @@ static int cvariable = 420;
""".}
proc embedsC() {.noStackFrame.} =
proc embedsC() =
var nimrodVar = 89
{.emit: """fprintf(stdout, "%d\n", cvariable + (int)`nimrodVar`);""".}
{.emit: """printf("%d\n", cvariable + (int)`nimrodVar`);""".}
embedsC()

View File

@@ -54,7 +54,7 @@ case $uos in
myos="linux"
LINK_FLAGS="$LINK_FLAGS -ldl -lm"
;;
*freebsd* )
*freebsd* | *dragonfly* )
myos="freebsd"
LINK_FLAGS="$LINK_FLAGS -lm"
;;