big rename
This commit is contained in:
parent
df172806ea
commit
27869b6c7b
7 changed files with 380 additions and 380 deletions
|
|
@ -16,7 +16,7 @@ type
|
||||||
{.deprecated: [TSortOrder: SortOrder].}
|
{.deprecated: [TSortOrder: SortOrder].}
|
||||||
|
|
||||||
|
|
||||||
proc `*`*(x: int, order: TSortOrder): int {.inline.} =
|
proc `*`*(x: int, order: SortOrder): int {.inline.} =
|
||||||
## flips `x` if ``order == Descending``;
|
## flips `x` if ``order == Descending``;
|
||||||
## if ``order == Ascending`` then `x` is returned.
|
## if ``order == Ascending`` then `x` is returned.
|
||||||
## `x` is supposed to be the result of a comparator, ie ``< 0`` for
|
## `x` is supposed to be the result of a comparator, ie ``< 0`` for
|
||||||
|
|
@ -103,7 +103,7 @@ proc lowerBound*[T](a: openArray[T], key: T, cmp: proc(x,y: T): int {.closure.})
|
||||||
|
|
||||||
proc lowerBound*[T](a: openArray[T], key: T): int = lowerBound(a, key, cmp[T])
|
proc lowerBound*[T](a: openArray[T], key: T): int = lowerBound(a, key, cmp[T])
|
||||||
proc merge[T](a, b: var openArray[T], lo, m, hi: int,
|
proc merge[T](a, b: var openArray[T], lo, m, hi: int,
|
||||||
cmp: proc (x, y: T): int {.closure.}, order: TSortOrder) =
|
cmp: proc (x, y: T): int {.closure.}, order: SortOrder) =
|
||||||
template `<-` (a, b: expr) =
|
template `<-` (a, b: expr) =
|
||||||
when false:
|
when false:
|
||||||
a = b
|
a = b
|
||||||
|
|
@ -150,7 +150,7 @@ proc merge[T](a, b: var openArray[T], lo, m, hi: int,
|
||||||
|
|
||||||
proc sort*[T](a: var openArray[T],
|
proc sort*[T](a: var openArray[T],
|
||||||
cmp: proc (x, y: T): int {.closure.},
|
cmp: proc (x, y: T): int {.closure.},
|
||||||
order = TSortOrder.Ascending) =
|
order = SortOrder.Ascending) =
|
||||||
## Default Nimrod sort. The sorting is guaranteed to be stable and
|
## Default Nimrod sort. The sorting is guaranteed to be stable and
|
||||||
## the worst case is guaranteed to be O(n log n).
|
## the worst case is guaranteed to be O(n log n).
|
||||||
## The current implementation uses an iterative
|
## The current implementation uses an iterative
|
||||||
|
|
|
||||||
|
|
@ -156,12 +156,12 @@ proc read*[T](future: Future[T]): T =
|
||||||
return future.value
|
return future.value
|
||||||
else:
|
else:
|
||||||
# TODO: Make a custom exception type for this?
|
# TODO: Make a custom exception type for this?
|
||||||
raise newException(EInvalidValue, "Future still in progress.")
|
raise newException(ValueError, "Future still in progress.")
|
||||||
|
|
||||||
proc readError*[T](future: Future[T]): ref EBase =
|
proc readError*[T](future: Future[T]): ref Exception =
|
||||||
if future.error != nil: return future.error
|
if future.error != nil: return future.error
|
||||||
else:
|
else:
|
||||||
raise newException(EInvalidValue, "No error in future.")
|
raise newException(ValueError, "No error in future.")
|
||||||
|
|
||||||
proc finished*[T](future: Future[T]): bool =
|
proc finished*[T](future: Future[T]): bool =
|
||||||
## Determines whether ``future`` has completed.
|
## Determines whether ``future`` has completed.
|
||||||
|
|
@ -206,7 +206,7 @@ proc `or`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] =
|
||||||
fut2.callback = cb
|
fut2.callback = cb
|
||||||
|
|
||||||
type
|
type
|
||||||
PDispatcherBase = ref object of PObject
|
PDispatcherBase = ref object of RootRef
|
||||||
timers: seq[tuple[finishAt: float, fut: Future[void]]]
|
timers: seq[tuple[finishAt: float, fut: Future[void]]]
|
||||||
|
|
||||||
proc processTimers(p: PDispatcherBase) =
|
proc processTimers(p: PDispatcherBase) =
|
||||||
|
|
@ -226,11 +226,11 @@ when defined(windows) or defined(nimdoc):
|
||||||
TCompletionData* = object
|
TCompletionData* = object
|
||||||
sock: TAsyncFD
|
sock: TAsyncFD
|
||||||
cb: proc (sock: TAsyncFD, bytesTransferred: DWORD,
|
cb: proc (sock: TAsyncFD, bytesTransferred: DWORD,
|
||||||
errcode: TOSErrorCode) {.closure,gcsafe.}
|
errcode: OSErrorCode) {.closure,gcsafe.}
|
||||||
|
|
||||||
PDispatcher* = ref object of PDispatcherBase
|
PDispatcher* = ref object of PDispatcherBase
|
||||||
ioPort: THandle
|
ioPort: THandle
|
||||||
handles: TSet[TAsyncFD]
|
handles: HashSet[TAsyncFD]
|
||||||
|
|
||||||
TCustomOverlapped = object of TOVERLAPPED
|
TCustomOverlapped = object of TOVERLAPPED
|
||||||
data*: TCompletionData
|
data*: TCompletionData
|
||||||
|
|
@ -245,7 +245,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
proc newDispatcher*(): PDispatcher =
|
proc newDispatcher*(): PDispatcher =
|
||||||
## Creates a new Dispatcher instance.
|
## Creates a new Dispatcher instance.
|
||||||
new result
|
new result
|
||||||
result.ioPort = CreateIOCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1)
|
result.ioPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1)
|
||||||
result.handles = initSet[TAsyncFD]()
|
result.handles = initSet[TAsyncFD]()
|
||||||
result.timers = @[]
|
result.timers = @[]
|
||||||
|
|
||||||
|
|
@ -258,16 +258,16 @@ when defined(windows) or defined(nimdoc):
|
||||||
proc register*(sock: TAsyncFD) =
|
proc register*(sock: TAsyncFD) =
|
||||||
## Registers ``sock`` with the dispatcher.
|
## Registers ``sock`` with the dispatcher.
|
||||||
let p = getGlobalDispatcher()
|
let p = getGlobalDispatcher()
|
||||||
if CreateIOCompletionPort(sock.THandle, p.ioPort,
|
if CreateIoCompletionPort(sock.THandle, p.ioPort,
|
||||||
cast[TCompletionKey](sock), 1) == 0:
|
cast[TCompletionKey](sock), 1) == 0:
|
||||||
osError(osLastError())
|
raiseOSError(osLastError())
|
||||||
p.handles.incl(sock)
|
p.handles.incl(sock)
|
||||||
|
|
||||||
proc verifyPresence(sock: TAsyncFD) =
|
proc verifyPresence(sock: TAsyncFD) =
|
||||||
## Ensures that socket has been registered with the dispatcher.
|
## Ensures that socket has been registered with the dispatcher.
|
||||||
let p = getGlobalDispatcher()
|
let p = getGlobalDispatcher()
|
||||||
if sock notin p.handles:
|
if sock notin p.handles:
|
||||||
raise newException(EInvalidValue,
|
raise newException(ValueError,
|
||||||
"Operation performed on a socket which has not been registered with" &
|
"Operation performed on a socket which has not been registered with" &
|
||||||
" the dispatcher yet.")
|
" the dispatcher yet.")
|
||||||
|
|
||||||
|
|
@ -275,7 +275,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
## Waits for completion events and processes them.
|
## Waits for completion events and processes them.
|
||||||
let p = getGlobalDispatcher()
|
let p = getGlobalDispatcher()
|
||||||
if p.handles.len == 0 and p.timers.len == 0:
|
if p.handles.len == 0 and p.timers.len == 0:
|
||||||
raise newException(EInvalidValue,
|
raise newException(ValueError,
|
||||||
"No handles or timers registered in dispatcher.")
|
"No handles or timers registered in dispatcher.")
|
||||||
|
|
||||||
let llTimeout =
|
let llTimeout =
|
||||||
|
|
@ -286,7 +286,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
var customOverlapped: PCustomOverlapped
|
var customOverlapped: PCustomOverlapped
|
||||||
let res = GetQueuedCompletionStatus(p.ioPort,
|
let res = GetQueuedCompletionStatus(p.ioPort,
|
||||||
addr lpNumberOfBytesTransferred, addr lpCompletionKey,
|
addr lpNumberOfBytesTransferred, addr lpCompletionKey,
|
||||||
cast[ptr POverlapped](addr customOverlapped), llTimeout).bool
|
cast[ptr POVERLAPPED](addr customOverlapped), llTimeout).bool
|
||||||
|
|
||||||
# http://stackoverflow.com/a/12277264/492186
|
# http://stackoverflow.com/a/12277264/492186
|
||||||
# TODO: http://www.serverframework.com/handling-multiple-pending-socket-read-and-write-operations.html
|
# TODO: http://www.serverframework.com/handling-multiple-pending-socket-read-and-write-operations.html
|
||||||
|
|
@ -295,7 +295,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
assert customOverlapped.data.sock == lpCompletionKey.TAsyncFD
|
assert customOverlapped.data.sock == lpCompletionKey.TAsyncFD
|
||||||
|
|
||||||
customOverlapped.data.cb(customOverlapped.data.sock,
|
customOverlapped.data.cb(customOverlapped.data.sock,
|
||||||
lpNumberOfBytesTransferred, TOSErrorCode(-1))
|
lpNumberOfBytesTransferred, OSErrorCode(-1))
|
||||||
GC_unref(customOverlapped)
|
GC_unref(customOverlapped)
|
||||||
else:
|
else:
|
||||||
let errCode = osLastError()
|
let errCode = osLastError()
|
||||||
|
|
@ -308,7 +308,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
if errCode.int32 == WAIT_TIMEOUT:
|
if errCode.int32 == WAIT_TIMEOUT:
|
||||||
# Timed out
|
# Timed out
|
||||||
discard
|
discard
|
||||||
else: osError(errCode)
|
else: raiseOSError(errCode)
|
||||||
|
|
||||||
# Timer processing.
|
# Timer processing.
|
||||||
processTimers(p)
|
processTimers(p)
|
||||||
|
|
@ -317,9 +317,9 @@ when defined(windows) or defined(nimdoc):
|
||||||
var acceptExPtr: pointer = nil
|
var acceptExPtr: pointer = nil
|
||||||
var getAcceptExSockAddrsPtr: pointer = nil
|
var getAcceptExSockAddrsPtr: pointer = nil
|
||||||
|
|
||||||
proc initPointer(s: TSocketHandle, func: var pointer, guid: var TGUID): bool =
|
proc initPointer(s: SocketHandle, func: var pointer, guid: var TGUID): bool =
|
||||||
# Ref: https://github.com/powdahound/twisted/blob/master/twisted/internet/iocpreactor/iocpsupport/winsock_pointers.c
|
# Ref: https://github.com/powdahound/twisted/blob/master/twisted/internet/iocpreactor/iocpsupport/winsock_pointers.c
|
||||||
var bytesRet: DWord
|
var bytesRet: DWORD
|
||||||
func = nil
|
func = nil
|
||||||
result = WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, addr guid,
|
result = WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, addr guid,
|
||||||
sizeof(TGUID).dword, addr func, sizeof(pointer).DWORD,
|
sizeof(TGUID).dword, addr func, sizeof(pointer).DWORD,
|
||||||
|
|
@ -328,34 +328,34 @@ when defined(windows) or defined(nimdoc):
|
||||||
proc initAll() =
|
proc initAll() =
|
||||||
let dummySock = newRawSocket()
|
let dummySock = newRawSocket()
|
||||||
if not initPointer(dummySock, connectExPtr, WSAID_CONNECTEX):
|
if not initPointer(dummySock, connectExPtr, WSAID_CONNECTEX):
|
||||||
osError(osLastError())
|
raiseOSError(osLastError())
|
||||||
if not initPointer(dummySock, acceptExPtr, WSAID_ACCEPTEX):
|
if not initPointer(dummySock, acceptExPtr, WSAID_ACCEPTEX):
|
||||||
osError(osLastError())
|
raiseOSError(osLastError())
|
||||||
if not initPointer(dummySock, getAcceptExSockAddrsPtr, WSAID_GETACCEPTEXSOCKADDRS):
|
if not initPointer(dummySock, getAcceptExSockAddrsPtr, WSAID_GETACCEPTEXSOCKADDRS):
|
||||||
osError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
|
||||||
proc connectEx(s: TSocketHandle, name: ptr TSockAddr, namelen: cint,
|
proc connectEx(s: SocketHandle, name: ptr TSockAddr, namelen: cint,
|
||||||
lpSendBuffer: pointer, dwSendDataLength: dword,
|
lpSendBuffer: pointer, dwSendDataLength: dword,
|
||||||
lpdwBytesSent: PDWORD, lpOverlapped: POverlapped): bool =
|
lpdwBytesSent: PDWORD, lpOverlapped: POVERLAPPED): bool =
|
||||||
if connectExPtr.isNil: raise newException(EInvalidValue, "Need to initialise ConnectEx().")
|
if connectExPtr.isNil: raise newException(ValueError, "Need to initialise ConnectEx().")
|
||||||
let func =
|
let func =
|
||||||
cast[proc (s: TSocketHandle, name: ptr TSockAddr, namelen: cint,
|
cast[proc (s: SocketHandle, name: ptr TSockAddr, namelen: cint,
|
||||||
lpSendBuffer: pointer, dwSendDataLength: dword,
|
lpSendBuffer: pointer, dwSendDataLength: dword,
|
||||||
lpdwBytesSent: PDWORD, lpOverlapped: POverlapped): bool {.stdcall,gcsafe.}](connectExPtr)
|
lpdwBytesSent: PDWORD, lpOverlapped: POVERLAPPED): bool {.stdcall,gcsafe.}](connectExPtr)
|
||||||
|
|
||||||
result = func(s, name, namelen, lpSendBuffer, dwSendDataLength, lpdwBytesSent,
|
result = func(s, name, namelen, lpSendBuffer, dwSendDataLength, lpdwBytesSent,
|
||||||
lpOverlapped)
|
lpOverlapped)
|
||||||
|
|
||||||
proc acceptEx(listenSock, acceptSock: TSocketHandle, lpOutputBuffer: pointer,
|
proc acceptEx(listenSock, acceptSock: SocketHandle, lpOutputBuffer: pointer,
|
||||||
dwReceiveDataLength, dwLocalAddressLength,
|
dwReceiveDataLength, dwLocalAddressLength,
|
||||||
dwRemoteAddressLength: DWORD, lpdwBytesReceived: PDWORD,
|
dwRemoteAddressLength: DWORD, lpdwBytesReceived: PDWORD,
|
||||||
lpOverlapped: POverlapped): bool =
|
lpOverlapped: POVERLAPPED): bool =
|
||||||
if acceptExPtr.isNil: raise newException(EInvalidValue, "Need to initialise AcceptEx().")
|
if acceptExPtr.isNil: raise newException(ValueError, "Need to initialise AcceptEx().")
|
||||||
let func =
|
let func =
|
||||||
cast[proc (listenSock, acceptSock: TSocketHandle, lpOutputBuffer: pointer,
|
cast[proc (listenSock, acceptSock: SocketHandle, lpOutputBuffer: pointer,
|
||||||
dwReceiveDataLength, dwLocalAddressLength,
|
dwReceiveDataLength, dwLocalAddressLength,
|
||||||
dwRemoteAddressLength: DWORD, lpdwBytesReceived: PDWORD,
|
dwRemoteAddressLength: DWORD, lpdwBytesReceived: PDWORD,
|
||||||
lpOverlapped: POverlapped): bool {.stdcall,gcsafe.}](acceptExPtr)
|
lpOverlapped: POVERLAPPED): bool {.stdcall,gcsafe.}](acceptExPtr)
|
||||||
result = func(listenSock, acceptSock, lpOutputBuffer, dwReceiveDataLength,
|
result = func(listenSock, acceptSock, lpOutputBuffer, dwReceiveDataLength,
|
||||||
dwLocalAddressLength, dwRemoteAddressLength, lpdwBytesReceived,
|
dwLocalAddressLength, dwRemoteAddressLength, lpdwBytesReceived,
|
||||||
lpOverlapped)
|
lpOverlapped)
|
||||||
|
|
@ -365,7 +365,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
LocalSockaddr: ptr ptr TSockAddr, LocalSockaddrLength: lpint,
|
LocalSockaddr: ptr ptr TSockAddr, LocalSockaddrLength: lpint,
|
||||||
RemoteSockaddr: ptr ptr TSockAddr, RemoteSockaddrLength: lpint) =
|
RemoteSockaddr: ptr ptr TSockAddr, RemoteSockaddrLength: lpint) =
|
||||||
if getAcceptExSockAddrsPtr.isNil:
|
if getAcceptExSockAddrsPtr.isNil:
|
||||||
raise newException(EInvalidValue, "Need to initialise getAcceptExSockAddrs().")
|
raise newException(ValueError, "Need to initialise getAcceptExSockAddrs().")
|
||||||
|
|
||||||
let func =
|
let func =
|
||||||
cast[proc (lpOutputBuffer: pointer,
|
cast[proc (lpOutputBuffer: pointer,
|
||||||
|
|
@ -378,7 +378,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
dwRemoteAddressLength, LocalSockaddr, LocalSockaddrLength,
|
dwRemoteAddressLength, LocalSockaddr, LocalSockaddrLength,
|
||||||
RemoteSockaddr, RemoteSockaddrLength)
|
RemoteSockaddr, RemoteSockaddrLength)
|
||||||
|
|
||||||
proc connect*(socket: TAsyncFD, address: string, port: TPort,
|
proc connect*(socket: TAsyncFD, address: string, port: Port,
|
||||||
af = AF_INET): Future[void] =
|
af = AF_INET): Future[void] =
|
||||||
## Connects ``socket`` to server at ``address:port``.
|
## Connects ``socket`` to server at ``address:port``.
|
||||||
##
|
##
|
||||||
|
|
@ -391,13 +391,13 @@ when defined(windows) or defined(nimdoc):
|
||||||
saddr.sin_family = int16(toInt(af))
|
saddr.sin_family = int16(toInt(af))
|
||||||
saddr.sin_port = 0
|
saddr.sin_port = 0
|
||||||
saddr.sin_addr.s_addr = INADDR_ANY
|
saddr.sin_addr.s_addr = INADDR_ANY
|
||||||
if bindAddr(socket.TSocketHandle, cast[ptr TSockAddr](addr(saddr)),
|
if bindAddr(socket.SocketHandle, cast[ptr TSockAddr](addr(saddr)),
|
||||||
sizeof(saddr).TSockLen) < 0'i32:
|
sizeof(saddr).TSockLen) < 0'i32:
|
||||||
osError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
|
||||||
var aiList = getAddrInfo(address, port, af)
|
var aiList = getAddrInfo(address, port, af)
|
||||||
var success = false
|
var success = false
|
||||||
var lastError: TOSErrorCode
|
var lastError: OSErrorCode
|
||||||
var it = aiList
|
var it = aiList
|
||||||
while it != nil:
|
while it != nil:
|
||||||
# "the OVERLAPPED structure must remain valid until the I/O completes"
|
# "the OVERLAPPED structure must remain valid until the I/O completes"
|
||||||
|
|
@ -405,17 +405,17 @@ when defined(windows) or defined(nimdoc):
|
||||||
var ol = PCustomOverlapped()
|
var ol = PCustomOverlapped()
|
||||||
GC_ref(ol)
|
GC_ref(ol)
|
||||||
ol.data = TCompletionData(sock: socket, cb:
|
ol.data = TCompletionData(sock: socket, cb:
|
||||||
proc (sock: TAsyncFD, bytesCount: DWord, errcode: TOSErrorCode) =
|
proc (sock: TAsyncFD, bytesCount: DWORD, errcode: OSErrorCode) =
|
||||||
if not retFuture.finished:
|
if not retFuture.finished:
|
||||||
if errcode == TOSErrorCode(-1):
|
if errcode == OSErrorCode(-1):
|
||||||
retFuture.complete()
|
retFuture.complete()
|
||||||
else:
|
else:
|
||||||
retFuture.fail(newException(EOS, osErrorMsg(errcode)))
|
retFuture.fail(newException(OSError, osErrorMsg(errcode)))
|
||||||
)
|
)
|
||||||
|
|
||||||
var ret = connectEx(socket.TSocketHandle, it.ai_addr,
|
var ret = connectEx(socket.SocketHandle, it.ai_addr,
|
||||||
sizeof(TSockAddrIn).cint, nil, 0, nil,
|
sizeof(Tsockaddr_in).cint, nil, 0, nil,
|
||||||
cast[POverlapped](ol))
|
cast[POVERLAPPED](ol))
|
||||||
if ret:
|
if ret:
|
||||||
# Request to connect completed immediately.
|
# Request to connect completed immediately.
|
||||||
success = true
|
success = true
|
||||||
|
|
@ -437,11 +437,11 @@ when defined(windows) or defined(nimdoc):
|
||||||
|
|
||||||
dealloc(aiList)
|
dealloc(aiList)
|
||||||
if not success:
|
if not success:
|
||||||
retFuture.fail(newException(EOS, osErrorMsg(lastError)))
|
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
|
||||||
return retFuture
|
return retFuture
|
||||||
|
|
||||||
proc recv*(socket: TAsyncFD, size: int,
|
proc recv*(socket: TAsyncFD, size: int,
|
||||||
flags = {TSocketFlags.SafeDisconn}): Future[string] =
|
flags = {SocketFlag.SafeDisconn}): Future[string] =
|
||||||
## Reads **up to** ``size`` bytes from ``socket``. Returned future will
|
## Reads **up to** ``size`` bytes from ``socket``. Returned future will
|
||||||
## complete once all the data requested is read, a part of the data has been
|
## complete once all the data requested is read, a part of the data has been
|
||||||
## read, or the socket has disconnected in which case the future will
|
## read, or the socket has disconnected in which case the future will
|
||||||
|
|
@ -460,14 +460,14 @@ when defined(windows) or defined(nimdoc):
|
||||||
dataBuf.buf = cast[cstring](alloc0(size))
|
dataBuf.buf = cast[cstring](alloc0(size))
|
||||||
dataBuf.len = size
|
dataBuf.len = size
|
||||||
|
|
||||||
var bytesReceived: DWord
|
var bytesReceived: DWORD
|
||||||
var flagsio = flags.toOSFlags().DWord
|
var flagsio = flags.toOSFlags().DWORD
|
||||||
var ol = PCustomOverlapped()
|
var ol = PCustomOverlapped()
|
||||||
GC_ref(ol)
|
GC_ref(ol)
|
||||||
ol.data = TCompletionData(sock: socket, cb:
|
ol.data = TCompletionData(sock: socket, cb:
|
||||||
proc (sock: TAsyncFD, bytesCount: DWord, errcode: TOSErrorCode) =
|
proc (sock: TAsyncFD, bytesCount: DWORD, errcode: OSErrorCode) =
|
||||||
if not retFuture.finished:
|
if not retFuture.finished:
|
||||||
if errcode == TOSErrorCode(-1):
|
if errcode == OSErrorCode(-1):
|
||||||
if bytesCount == 0 and dataBuf.buf[0] == '\0':
|
if bytesCount == 0 and dataBuf.buf[0] == '\0':
|
||||||
retFuture.complete("")
|
retFuture.complete("")
|
||||||
else:
|
else:
|
||||||
|
|
@ -479,14 +479,14 @@ when defined(windows) or defined(nimdoc):
|
||||||
if flags.isDisconnectionError(errcode):
|
if flags.isDisconnectionError(errcode):
|
||||||
retFuture.complete("")
|
retFuture.complete("")
|
||||||
else:
|
else:
|
||||||
retFuture.fail(newException(EOS, osErrorMsg(errcode)))
|
retFuture.fail(newException(OSError, osErrorMsg(errcode)))
|
||||||
if dataBuf.buf != nil:
|
if dataBuf.buf != nil:
|
||||||
dealloc dataBuf.buf
|
dealloc dataBuf.buf
|
||||||
dataBuf.buf = nil
|
dataBuf.buf = nil
|
||||||
)
|
)
|
||||||
|
|
||||||
let ret = WSARecv(socket.TSocketHandle, addr dataBuf, 1, addr bytesReceived,
|
let ret = WSARecv(socket.SocketHandle, addr dataBuf, 1, addr bytesReceived,
|
||||||
addr flagsio, cast[POverlapped](ol), nil)
|
addr flagsio, cast[POVERLAPPED](ol), nil)
|
||||||
if ret == -1:
|
if ret == -1:
|
||||||
let err = osLastError()
|
let err = osLastError()
|
||||||
if err.int32 != ERROR_IO_PENDING:
|
if err.int32 != ERROR_IO_PENDING:
|
||||||
|
|
@ -497,7 +497,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
if flags.isDisconnectionError(err):
|
if flags.isDisconnectionError(err):
|
||||||
retFuture.complete("")
|
retFuture.complete("")
|
||||||
else:
|
else:
|
||||||
retFuture.fail(newException(EOS, osErrorMsg(err)))
|
retFuture.fail(newException(OSError, osErrorMsg(err)))
|
||||||
elif ret == 0 and bytesReceived == 0 and dataBuf.buf[0] == '\0':
|
elif ret == 0 and bytesReceived == 0 and dataBuf.buf[0] == '\0':
|
||||||
# We have to ensure that the buffer is empty because WSARecv will tell
|
# We have to ensure that the buffer is empty because WSARecv will tell
|
||||||
# us immediatelly when it was disconnected, even when there is still
|
# us immediatelly when it was disconnected, even when there is still
|
||||||
|
|
@ -529,7 +529,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
return retFuture
|
return retFuture
|
||||||
|
|
||||||
proc send*(socket: TAsyncFD, data: string,
|
proc send*(socket: TAsyncFD, data: string,
|
||||||
flags = {TSocketFlags.SafeDisconn}): Future[void] =
|
flags = {SocketFlag.SafeDisconn}): Future[void] =
|
||||||
## Sends ``data`` to ``socket``. The returned future will complete once all
|
## Sends ``data`` to ``socket``. The returned future will complete once all
|
||||||
## data has been sent.
|
## data has been sent.
|
||||||
verifyPresence(socket)
|
verifyPresence(socket)
|
||||||
|
|
@ -539,23 +539,23 @@ when defined(windows) or defined(nimdoc):
|
||||||
dataBuf.buf = data # since this is not used in a callback, this is fine
|
dataBuf.buf = data # since this is not used in a callback, this is fine
|
||||||
dataBuf.len = data.len
|
dataBuf.len = data.len
|
||||||
|
|
||||||
var bytesReceived, lowFlags: DWord
|
var bytesReceived, lowFlags: DWORD
|
||||||
var ol = PCustomOverlapped()
|
var ol = PCustomOverlapped()
|
||||||
GC_ref(ol)
|
GC_ref(ol)
|
||||||
ol.data = TCompletionData(sock: socket, cb:
|
ol.data = TCompletionData(sock: socket, cb:
|
||||||
proc (sock: TAsyncFD, bytesCount: DWord, errcode: TOSErrorCode) =
|
proc (sock: TAsyncFD, bytesCount: DWORD, errcode: OSErrorCode) =
|
||||||
if not retFuture.finished:
|
if not retFuture.finished:
|
||||||
if errcode == TOSErrorCode(-1):
|
if errcode == OSErrorCode(-1):
|
||||||
retFuture.complete()
|
retFuture.complete()
|
||||||
else:
|
else:
|
||||||
if flags.isDisconnectionError(errcode):
|
if flags.isDisconnectionError(errcode):
|
||||||
retFuture.complete()
|
retFuture.complete()
|
||||||
else:
|
else:
|
||||||
retFuture.fail(newException(EOS, osErrorMsg(errcode)))
|
retFuture.fail(newException(OSError, osErrorMsg(errcode)))
|
||||||
)
|
)
|
||||||
|
|
||||||
let ret = WSASend(socket.TSocketHandle, addr dataBuf, 1, addr bytesReceived,
|
let ret = WSASend(socket.SocketHandle, addr dataBuf, 1, addr bytesReceived,
|
||||||
lowFlags, cast[POverlapped](ol), nil)
|
lowFlags, cast[POVERLAPPED](ol), nil)
|
||||||
if ret == -1:
|
if ret == -1:
|
||||||
let err = osLastError()
|
let err = osLastError()
|
||||||
if err.int32 != ERROR_IO_PENDING:
|
if err.int32 != ERROR_IO_PENDING:
|
||||||
|
|
@ -563,7 +563,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
if flags.isDisconnectionError(err):
|
if flags.isDisconnectionError(err):
|
||||||
retFuture.complete()
|
retFuture.complete()
|
||||||
else:
|
else:
|
||||||
retFuture.fail(newException(EOS, osErrorMsg(err)))
|
retFuture.fail(newException(OSError, osErrorMsg(err)))
|
||||||
else:
|
else:
|
||||||
retFuture.complete()
|
retFuture.complete()
|
||||||
# We don't deallocate ``ol`` here because even though this completed
|
# We don't deallocate ``ol`` here because even though this completed
|
||||||
|
|
@ -571,7 +571,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
# free ``ol``.
|
# free ``ol``.
|
||||||
return retFuture
|
return retFuture
|
||||||
|
|
||||||
proc acceptAddr*(socket: TAsyncFD, flags = {TSocketFlags.SafeDisconn}):
|
proc acceptAddr*(socket: TAsyncFD, flags = {SocketFlag.SafeDisconn}):
|
||||||
Future[tuple[address: string, client: TAsyncFD]] =
|
Future[tuple[address: string, client: TAsyncFD]] =
|
||||||
## Accepts a new connection. Returns a future containing the client socket
|
## Accepts a new connection. Returns a future containing the client socket
|
||||||
## corresponding to that connection and the remote address of the client.
|
## corresponding to that connection and the remote address of the client.
|
||||||
|
|
@ -588,21 +588,21 @@ when defined(windows) or defined(nimdoc):
|
||||||
var retFuture = newFuture[tuple[address: string, client: TAsyncFD]]("acceptAddr")
|
var retFuture = newFuture[tuple[address: string, client: TAsyncFD]]("acceptAddr")
|
||||||
|
|
||||||
var clientSock = newRawSocket()
|
var clientSock = newRawSocket()
|
||||||
if clientSock == osInvalidSocket: osError(osLastError())
|
if clientSock == osInvalidSocket: raiseOSError(osLastError())
|
||||||
|
|
||||||
const lpOutputLen = 1024
|
const lpOutputLen = 1024
|
||||||
var lpOutputBuf = newString(lpOutputLen)
|
var lpOutputBuf = newString(lpOutputLen)
|
||||||
var dwBytesReceived: DWORD
|
var dwBytesReceived: DWORD
|
||||||
let dwReceiveDataLength = 0.DWORD # We don't want any data to be read.
|
let dwReceiveDataLength = 0.DWORD # We don't want any data to be read.
|
||||||
let dwLocalAddressLength = DWORD(sizeof (TSockaddr_in) + 16)
|
let dwLocalAddressLength = DWORD(sizeof (Tsockaddr_in) + 16)
|
||||||
let dwRemoteAddressLength = DWORD(sizeof(TSockaddr_in) + 16)
|
let dwRemoteAddressLength = DWORD(sizeof(Tsockaddr_in) + 16)
|
||||||
|
|
||||||
template completeAccept(): stmt {.immediate, dirty.} =
|
template completeAccept(): stmt {.immediate, dirty.} =
|
||||||
var listenSock = socket
|
var listenSock = socket
|
||||||
let setoptRet = setsockopt(clientSock, SOL_SOCKET,
|
let setoptRet = setsockopt(clientSock, SOL_SOCKET,
|
||||||
SO_UPDATE_ACCEPT_CONTEXT, addr listenSock,
|
SO_UPDATE_ACCEPT_CONTEXT, addr listenSock,
|
||||||
sizeof(listenSock).TSockLen)
|
sizeof(listenSock).TSockLen)
|
||||||
if setoptRet != 0: osError(osLastError())
|
if setoptRet != 0: raiseOSError(osLastError())
|
||||||
|
|
||||||
var LocalSockaddr, RemoteSockaddr: ptr TSockAddr
|
var LocalSockaddr, RemoteSockaddr: ptr TSockAddr
|
||||||
var localLen, remoteLen: int32
|
var localLen, remoteLen: int32
|
||||||
|
|
@ -627,25 +627,25 @@ when defined(windows) or defined(nimdoc):
|
||||||
else:
|
else:
|
||||||
retFuture.complete(newAcceptFut.read)
|
retFuture.complete(newAcceptFut.read)
|
||||||
else:
|
else:
|
||||||
retFuture.fail(newException(EOS, osErrorMsg(errcode)))
|
retFuture.fail(newException(OSError, osErrorMsg(errcode)))
|
||||||
|
|
||||||
var ol = PCustomOverlapped()
|
var ol = PCustomOverlapped()
|
||||||
GC_ref(ol)
|
GC_ref(ol)
|
||||||
ol.data = TCompletionData(sock: socket, cb:
|
ol.data = TCompletionData(sock: socket, cb:
|
||||||
proc (sock: TAsyncFD, bytesCount: DWord, errcode: TOSErrorCode) =
|
proc (sock: TAsyncFD, bytesCount: DWORD, errcode: OSErrorCode) =
|
||||||
if not retFuture.finished:
|
if not retFuture.finished:
|
||||||
if errcode == TOSErrorCode(-1):
|
if errcode == OSErrorCode(-1):
|
||||||
completeAccept()
|
completeAccept()
|
||||||
else:
|
else:
|
||||||
failAccept(errcode)
|
failAccept(errcode)
|
||||||
)
|
)
|
||||||
|
|
||||||
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms737524%28v=vs.85%29.aspx
|
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms737524%28v=vs.85%29.aspx
|
||||||
let ret = acceptEx(socket.TSocketHandle, clientSock, addr lpOutputBuf[0],
|
let ret = acceptEx(socket.SocketHandle, clientSock, addr lpOutputBuf[0],
|
||||||
dwReceiveDataLength,
|
dwReceiveDataLength,
|
||||||
dwLocalAddressLength,
|
dwLocalAddressLength,
|
||||||
dwRemoteAddressLength,
|
dwRemoteAddressLength,
|
||||||
addr dwBytesReceived, cast[POverlapped](ol))
|
addr dwBytesReceived, cast[POVERLAPPED](ol))
|
||||||
|
|
||||||
if not ret:
|
if not ret:
|
||||||
let err = osLastError()
|
let err = osLastError()
|
||||||
|
|
@ -660,17 +660,17 @@ when defined(windows) or defined(nimdoc):
|
||||||
|
|
||||||
return retFuture
|
return retFuture
|
||||||
|
|
||||||
proc newAsyncRawSocket*(domain: TDomain = AF_INET,
|
proc newAsyncRawSocket*(domain: Domain = AF_INET,
|
||||||
typ: TType = SOCK_STREAM,
|
typ: SockType = SOCK_STREAM,
|
||||||
protocol: TProtocol = IPPROTO_TCP): TAsyncFD =
|
protocol: Protocol = IPPROTO_TCP): TAsyncFD =
|
||||||
## Creates a new socket and registers it with the dispatcher implicitly.
|
## Creates a new socket and registers it with the dispatcher implicitly.
|
||||||
result = newRawSocket(domain, typ, protocol).TAsyncFD
|
result = newRawSocket(domain, typ, protocol).TAsyncFD
|
||||||
result.TSocketHandle.setBlocking(false)
|
result.SocketHandle.setBlocking(false)
|
||||||
register(result)
|
register(result)
|
||||||
|
|
||||||
proc closeSocket*(socket: TAsyncFD) =
|
proc closeSocket*(socket: TAsyncFD) =
|
||||||
## Closes a socket and ensures that it is unregistered.
|
## Closes a socket and ensures that it is unregistered.
|
||||||
socket.TSocketHandle.close()
|
socket.SocketHandle.close()
|
||||||
getGlobalDispatcher().handles.excl(socket)
|
getGlobalDispatcher().handles.excl(socket)
|
||||||
|
|
||||||
proc unregister*(fd: TAsyncFD) =
|
proc unregister*(fd: TAsyncFD) =
|
||||||
|
|
@ -925,7 +925,7 @@ proc sleepAsync*(ms: int): Future[void] =
|
||||||
return retFuture
|
return retFuture
|
||||||
|
|
||||||
proc accept*(socket: TAsyncFD,
|
proc accept*(socket: TAsyncFD,
|
||||||
flags = {TSocketFlags.SafeDisconn}): Future[TAsyncFD] =
|
flags = {SocketFlag.SafeDisconn}): Future[TAsyncFD] =
|
||||||
## Accepts a new connection. Returns a future containing the client socket
|
## Accepts a new connection. Returns a future containing the client socket
|
||||||
## corresponding to that connection.
|
## corresponding to that connection.
|
||||||
## The future will complete when the connection is successfully accepted.
|
## The future will complete when the connection is successfully accepted.
|
||||||
|
|
@ -1010,14 +1010,14 @@ proc processBody(node, retFutureSym: PNimrodNode,
|
||||||
of nnkReturnStmt:
|
of nnkReturnStmt:
|
||||||
result = newNimNode(nnkStmtList, node)
|
result = newNimNode(nnkStmtList, node)
|
||||||
if node[0].kind == nnkEmpty:
|
if node[0].kind == nnkEmpty:
|
||||||
if not subtypeIsVoid:
|
if not subTypeIsVoid:
|
||||||
result.add newCall(newIdentNode("complete"), retFutureSym,
|
result.add newCall(newIdentNode("complete"), retFutureSym,
|
||||||
newIdentNode("result"))
|
newIdentNode("result"))
|
||||||
else:
|
else:
|
||||||
result.add newCall(newIdentNode("complete"), retFutureSym)
|
result.add newCall(newIdentNode("complete"), retFutureSym)
|
||||||
else:
|
else:
|
||||||
result.add newCall(newIdentNode("complete"), retFutureSym,
|
result.add newCall(newIdentNode("complete"), retFutureSym,
|
||||||
node[0].processBody(retFutureSym, subtypeIsVoid, exceptBranch))
|
node[0].processBody(retFutureSym, subTypeIsVoid, exceptBranch))
|
||||||
|
|
||||||
result.add newNimNode(nnkReturnStmt, node).add(newNilLit())
|
result.add newNimNode(nnkReturnStmt, node).add(newNilLit())
|
||||||
return # Don't process the children of this return stmt
|
return # Don't process the children of this return stmt
|
||||||
|
|
@ -1072,7 +1072,7 @@ proc processBody(node, retFutureSym: PNimrodNode,
|
||||||
res: PNimrodNode): bool {.compileTime.} =
|
res: PNimrodNode): bool {.compileTime.} =
|
||||||
result = false
|
result = false
|
||||||
while i < n[0].len:
|
while i < n[0].len:
|
||||||
var processed = processBody(n[0][i], retFutureSym, subtypeIsVoid, n[1])
|
var processed = processBody(n[0][i], retFutureSym, subTypeIsVoid, n[1])
|
||||||
if processed.kind != n[0][i].kind or processed.len != n[0][i].len:
|
if processed.kind != n[0][i].kind or processed.len != n[0][i].len:
|
||||||
expectKind(processed, nnkStmtList)
|
expectKind(processed, nnkStmtList)
|
||||||
expectKind(processed[2][1], nnkElse)
|
expectKind(processed[2][1], nnkElse)
|
||||||
|
|
@ -1092,7 +1092,7 @@ proc processBody(node, retFutureSym: PNimrodNode,
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
for i in 0 .. <result.len:
|
for i in 0 .. <result.len:
|
||||||
result[i] = processBody(result[i], retFutureSym, subtypeIsVoid, exceptBranch)
|
result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, exceptBranch)
|
||||||
|
|
||||||
proc getName(node: PNimrodNode): string {.compileTime.} =
|
proc getName(node: PNimrodNode): string {.compileTime.} =
|
||||||
case node.kind
|
case node.kind
|
||||||
|
|
@ -1214,7 +1214,7 @@ proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
|
||||||
if c.len == 0:
|
if c.len == 0:
|
||||||
return ""
|
return ""
|
||||||
if c == "\r":
|
if c == "\r":
|
||||||
c = await recv(socket, 1, {TSocketFlags.SafeDisconn, TSocketFlags.Peek})
|
c = await recv(socket, 1, {SocketFlag.SafeDisconn, SocketFlag.Peek})
|
||||||
if c.len > 0 and c == "\L":
|
if c.len > 0 and c == "\L":
|
||||||
discard await recv(socket, 1)
|
discard await recv(socket, 1)
|
||||||
addNLIfEmpty()
|
addNLIfEmpty()
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ type
|
||||||
|
|
||||||
{.deprecated: [TSet: HashSet].}
|
{.deprecated: [TSet: HashSet].}
|
||||||
|
|
||||||
proc isValid*[A](s: TSet[A]): bool =
|
proc isValid*[A](s: HashSet[A]): bool =
|
||||||
## Returns `true` if the set has been initialized with `initSet <#initSet>`_.
|
## Returns `true` if the set has been initialized with `initSet <#initSet>`_.
|
||||||
##
|
##
|
||||||
## Most operations over an uninitialized set will crash at runtime and
|
## Most operations over an uninitialized set will crash at runtime and
|
||||||
|
|
@ -51,7 +51,7 @@ proc isValid*[A](s: TSet[A]): bool =
|
||||||
## # Do stuff here, may crash in release builds!
|
## # Do stuff here, may crash in release builds!
|
||||||
result = not s.data.isNil
|
result = not s.data.isNil
|
||||||
|
|
||||||
proc len*[A](s: TSet[A]): int =
|
proc len*[A](s: HashSet[A]): int =
|
||||||
## Returns the number of keys in `s`.
|
## Returns the number of keys in `s`.
|
||||||
##
|
##
|
||||||
## Due to an implementation detail you can call this proc on variables which
|
## Due to an implementation detail you can call this proc on variables which
|
||||||
|
|
@ -65,14 +65,14 @@ proc len*[A](s: TSet[A]): int =
|
||||||
## assert values.len == 0
|
## assert values.len == 0
|
||||||
result = s.counter
|
result = s.counter
|
||||||
|
|
||||||
proc card*[A](s: TSet[A]): int =
|
proc card*[A](s: HashSet[A]): int =
|
||||||
## Alias for `len() <#len,TSet[A]>`_.
|
## Alias for `len() <#len,TSet[A]>`_.
|
||||||
##
|
##
|
||||||
## Card stands for the `cardinality
|
## Card stands for the `cardinality
|
||||||
## <http://en.wikipedia.org/wiki/Cardinality>`_ of a set.
|
## <http://en.wikipedia.org/wiki/Cardinality>`_ of a set.
|
||||||
result = s.counter
|
result = s.counter
|
||||||
|
|
||||||
iterator items*[A](s: TSet[A]): A =
|
iterator items*[A](s: HashSet[A]): A =
|
||||||
## Iterates over keys in the set `s`.
|
## Iterates over keys in the set `s`.
|
||||||
##
|
##
|
||||||
## If you need a sequence with the keys you can use `sequtils.toSeq()
|
## If you need a sequence with the keys you can use `sequtils.toSeq()
|
||||||
|
|
@ -120,10 +120,10 @@ template rawInsertImpl() {.dirty.} =
|
||||||
data[h].key = key
|
data[h].key = key
|
||||||
data[h].slot = seFilled
|
data[h].slot = seFilled
|
||||||
|
|
||||||
proc rawGet[A](s: TSet[A], key: A): int =
|
proc rawGet[A](s: HashSet[A], key: A): int =
|
||||||
rawGetImpl()
|
rawGetImpl()
|
||||||
|
|
||||||
proc mget*[A](s: var TSet[A], key: A): var A =
|
proc mget*[A](s: var HashSet[A], key: A): var A =
|
||||||
## returns the element that is actually stored in 's' which has the same
|
## returns the element that is actually stored in 's' which has the same
|
||||||
## value as 'key' or raises the ``EInvalidKey`` exception. This is useful
|
## value as 'key' or raises the ``EInvalidKey`` exception. This is useful
|
||||||
## when one overloaded 'hash' and '==' but still needs reference semantics
|
## when one overloaded 'hash' and '==' but still needs reference semantics
|
||||||
|
|
@ -133,7 +133,7 @@ proc mget*[A](s: var TSet[A], key: A): var A =
|
||||||
if index >= 0: result = t.data[index].key
|
if index >= 0: result = t.data[index].key
|
||||||
else: raise newException(KeyError, "key not found: " & $key)
|
else: raise newException(KeyError, "key not found: " & $key)
|
||||||
|
|
||||||
proc contains*[A](s: TSet[A], key: A): bool =
|
proc contains*[A](s: HashSet[A], key: A): bool =
|
||||||
## Returns true iff `key` is in `s`.
|
## Returns true iff `key` is in `s`.
|
||||||
##
|
##
|
||||||
## Example:
|
## Example:
|
||||||
|
|
@ -149,10 +149,10 @@ proc contains*[A](s: TSet[A], key: A): bool =
|
||||||
var index = rawGet(s, key)
|
var index = rawGet(s, key)
|
||||||
result = index >= 0
|
result = index >= 0
|
||||||
|
|
||||||
proc rawInsert[A](s: var TSet[A], data: var KeyValuePairSeq[A], key: A) =
|
proc rawInsert[A](s: var HashSet[A], data: var KeyValuePairSeq[A], key: A) =
|
||||||
rawInsertImpl()
|
rawInsertImpl()
|
||||||
|
|
||||||
proc enlarge[A](s: var TSet[A]) =
|
proc enlarge[A](s: var HashSet[A]) =
|
||||||
var n: KeyValuePairSeq[A]
|
var n: KeyValuePairSeq[A]
|
||||||
newSeq(n, len(s.data) * growthFactor)
|
newSeq(n, len(s.data) * growthFactor)
|
||||||
for i in countup(0, high(s.data)):
|
for i in countup(0, high(s.data)):
|
||||||
|
|
@ -175,7 +175,7 @@ template containsOrInclImpl() {.dirty.} =
|
||||||
rawInsert(s, s.data, key)
|
rawInsert(s, s.data, key)
|
||||||
inc(s.counter)
|
inc(s.counter)
|
||||||
|
|
||||||
proc incl*[A](s: var TSet[A], key: A) =
|
proc incl*[A](s: var HashSet[A], key: A) =
|
||||||
## Includes an element `key` in `s`.
|
## Includes an element `key` in `s`.
|
||||||
##
|
##
|
||||||
## This doesn't do anything if `key` is already in `s`. Example:
|
## This doesn't do anything if `key` is already in `s`. Example:
|
||||||
|
|
@ -188,7 +188,7 @@ proc incl*[A](s: var TSet[A], key: A) =
|
||||||
assert s.isValid, "The set needs to be initialized."
|
assert s.isValid, "The set needs to be initialized."
|
||||||
inclImpl()
|
inclImpl()
|
||||||
|
|
||||||
proc incl*[A](s: var TSet[A], other: TSet[A]) =
|
proc incl*[A](s: var HashSet[A], other: TSet[A]) =
|
||||||
## Includes all elements from `other` into `s`.
|
## Includes all elements from `other` into `s`.
|
||||||
##
|
##
|
||||||
## Example:
|
## Example:
|
||||||
|
|
@ -203,7 +203,7 @@ proc incl*[A](s: var TSet[A], other: TSet[A]) =
|
||||||
assert other.isValid, "The set `other` needs to be initialized."
|
assert other.isValid, "The set `other` needs to be initialized."
|
||||||
for item in other: incl(s, item)
|
for item in other: incl(s, item)
|
||||||
|
|
||||||
proc excl*[A](s: var TSet[A], key: A) =
|
proc excl*[A](s: var HashSet[A], key: A) =
|
||||||
## Excludes `key` from the set `s`.
|
## Excludes `key` from the set `s`.
|
||||||
##
|
##
|
||||||
## This doesn't do anything if `key` is not found in `s`. Example:
|
## This doesn't do anything if `key` is not found in `s`. Example:
|
||||||
|
|
@ -219,7 +219,7 @@ proc excl*[A](s: var TSet[A], key: A) =
|
||||||
s.data[index].slot = seDeleted
|
s.data[index].slot = seDeleted
|
||||||
dec(s.counter)
|
dec(s.counter)
|
||||||
|
|
||||||
proc excl*[A](s: var TSet[A], other: TSet[A]) =
|
proc excl*[A](s: var HashSet[A], other: TSet[A]) =
|
||||||
## Excludes everything in `other` from `s`.
|
## Excludes everything in `other` from `s`.
|
||||||
##
|
##
|
||||||
## Example:
|
## Example:
|
||||||
|
|
@ -235,7 +235,7 @@ proc excl*[A](s: var TSet[A], other: TSet[A]) =
|
||||||
assert other.isValid, "The set `other` needs to be initialized."
|
assert other.isValid, "The set `other` needs to be initialized."
|
||||||
for item in other: excl(s, item)
|
for item in other: excl(s, item)
|
||||||
|
|
||||||
proc containsOrIncl*[A](s: var TSet[A], key: A): bool =
|
proc containsOrIncl*[A](s: var HashSet[A], key: A): bool =
|
||||||
## Includes `key` in the set `s` and tells if `key` was added to `s`.
|
## Includes `key` in the set `s` and tells if `key` was added to `s`.
|
||||||
##
|
##
|
||||||
## The difference with regards to the `incl() <#incl,TSet[A],A>`_ proc is
|
## The difference with regards to the `incl() <#incl,TSet[A],A>`_ proc is
|
||||||
|
|
@ -250,7 +250,7 @@ proc containsOrIncl*[A](s: var TSet[A], key: A): bool =
|
||||||
assert s.isValid, "The set needs to be initialized."
|
assert s.isValid, "The set needs to be initialized."
|
||||||
containsOrInclImpl()
|
containsOrInclImpl()
|
||||||
|
|
||||||
proc init*[A](s: var TSet[A], initialSize=64) =
|
proc init*[A](s: var HashSet[A], initialSize=64) =
|
||||||
## Initializes a hash set.
|
## Initializes a hash set.
|
||||||
##
|
##
|
||||||
## The `initialSize` parameter needs to be a power of too. You can use
|
## The `initialSize` parameter needs to be a power of too. You can use
|
||||||
|
|
@ -273,7 +273,7 @@ proc init*[A](s: var TSet[A], initialSize=64) =
|
||||||
s.counter = 0
|
s.counter = 0
|
||||||
newSeq(s.data, initialSize)
|
newSeq(s.data, initialSize)
|
||||||
|
|
||||||
proc initSet*[A](initialSize=64): TSet[A] =
|
proc initSet*[A](initialSize=64): HashSet[A] =
|
||||||
## Wrapper around `init() <#init,TSet[A],int>`_ for initialization of hash
|
## Wrapper around `init() <#init,TSet[A],int>`_ for initialization of hash
|
||||||
## sets.
|
## sets.
|
||||||
##
|
##
|
||||||
|
|
@ -285,7 +285,7 @@ proc initSet*[A](initialSize=64): TSet[A] =
|
||||||
## a.incl(2)
|
## a.incl(2)
|
||||||
result.init(initialSize)
|
result.init(initialSize)
|
||||||
|
|
||||||
proc toSet*[A](keys: openArray[A]): TSet[A] =
|
proc toSet*[A](keys: openArray[A]): HashSet[A] =
|
||||||
## Creates a new hash set that contains the given `keys`.
|
## Creates a new hash set that contains the given `keys`.
|
||||||
##
|
##
|
||||||
## Example:
|
## Example:
|
||||||
|
|
@ -304,7 +304,7 @@ template dollarImpl(): stmt {.dirty.} =
|
||||||
result.add($key)
|
result.add($key)
|
||||||
result.add("}")
|
result.add("}")
|
||||||
|
|
||||||
proc `$`*[A](s: TSet[A]): string =
|
proc `$`*[A](s: HashSet[A]): string =
|
||||||
## Converts the set `s` to a string, mostly for logging purposes.
|
## Converts the set `s` to a string, mostly for logging purposes.
|
||||||
##
|
##
|
||||||
## Don't use this proc for serialization, the representation may change at
|
## Don't use this proc for serialization, the representation may change at
|
||||||
|
|
@ -320,7 +320,7 @@ proc `$`*[A](s: TSet[A]): string =
|
||||||
assert s.isValid, "The set needs to be initialized."
|
assert s.isValid, "The set needs to be initialized."
|
||||||
dollarImpl()
|
dollarImpl()
|
||||||
|
|
||||||
proc union*[A](s1, s2: TSet[A]): TSet[A] =
|
proc union*[A](s1, s2: HashSet[A]): TSet[A] =
|
||||||
## Returns the union of the sets `s1` and `s2`.
|
## Returns the union of the sets `s1` and `s2`.
|
||||||
##
|
##
|
||||||
## The union of two sets is represented mathematically as *A ∪ B* and is the
|
## The union of two sets is represented mathematically as *A ∪ B* and is the
|
||||||
|
|
@ -337,7 +337,7 @@ proc union*[A](s1, s2: TSet[A]): TSet[A] =
|
||||||
result = s1
|
result = s1
|
||||||
incl(result, s2)
|
incl(result, s2)
|
||||||
|
|
||||||
proc intersection*[A](s1, s2: TSet[A]): TSet[A] =
|
proc intersection*[A](s1, s2: HashSet[A]): TSet[A] =
|
||||||
## Returns the intersection of the sets `s1` and `s2`.
|
## Returns the intersection of the sets `s1` and `s2`.
|
||||||
##
|
##
|
||||||
## The intersection of two sets is represented mathematically as *A ∩ B* and
|
## The intersection of two sets is represented mathematically as *A ∩ B* and
|
||||||
|
|
@ -356,7 +356,7 @@ proc intersection*[A](s1, s2: TSet[A]): TSet[A] =
|
||||||
for item in s1:
|
for item in s1:
|
||||||
if item in s2: incl(result, item)
|
if item in s2: incl(result, item)
|
||||||
|
|
||||||
proc difference*[A](s1, s2: TSet[A]): TSet[A] =
|
proc difference*[A](s1, s2: HashSet[A]): TSet[A] =
|
||||||
## Returns the difference of the sets `s1` and `s2`.
|
## Returns the difference of the sets `s1` and `s2`.
|
||||||
##
|
##
|
||||||
## The difference of two sets is represented mathematically as *A \ B* and is
|
## The difference of two sets is represented mathematically as *A \ B* and is
|
||||||
|
|
@ -376,7 +376,7 @@ proc difference*[A](s1, s2: TSet[A]): TSet[A] =
|
||||||
if not contains(s2, item):
|
if not contains(s2, item):
|
||||||
incl(result, item)
|
incl(result, item)
|
||||||
|
|
||||||
proc symmetricDifference*[A](s1, s2: TSet[A]): TSet[A] =
|
proc symmetricDifference*[A](s1, s2: HashSet[A]): TSet[A] =
|
||||||
## Returns the symmetric difference of the sets `s1` and `s2`.
|
## Returns the symmetric difference of the sets `s1` and `s2`.
|
||||||
##
|
##
|
||||||
## The symmetric difference of two sets is represented mathematically as *A △
|
## The symmetric difference of two sets is represented mathematically as *A △
|
||||||
|
|
@ -395,23 +395,23 @@ proc symmetricDifference*[A](s1, s2: TSet[A]): TSet[A] =
|
||||||
for item in s2:
|
for item in s2:
|
||||||
if containsOrIncl(result, item): excl(result, item)
|
if containsOrIncl(result, item): excl(result, item)
|
||||||
|
|
||||||
proc `+`*[A](s1, s2: TSet[A]): TSet[A] {.inline.} =
|
proc `+`*[A](s1, s2: HashSet[A]): TSet[A] {.inline.} =
|
||||||
## Alias for `union(s1, s2) <#union>`_.
|
## Alias for `union(s1, s2) <#union>`_.
|
||||||
result = union(s1, s2)
|
result = union(s1, s2)
|
||||||
|
|
||||||
proc `*`*[A](s1, s2: TSet[A]): TSet[A] {.inline.} =
|
proc `*`*[A](s1, s2: HashSet[A]): TSet[A] {.inline.} =
|
||||||
## Alias for `intersection(s1, s2) <#intersection>`_.
|
## Alias for `intersection(s1, s2) <#intersection>`_.
|
||||||
result = intersection(s1, s2)
|
result = intersection(s1, s2)
|
||||||
|
|
||||||
proc `-`*[A](s1, s2: TSet[A]): TSet[A] {.inline.} =
|
proc `-`*[A](s1, s2: HashSet[A]): TSet[A] {.inline.} =
|
||||||
## Alias for `difference(s1, s2) <#difference>`_.
|
## Alias for `difference(s1, s2) <#difference>`_.
|
||||||
result = difference(s1, s2)
|
result = difference(s1, s2)
|
||||||
|
|
||||||
proc `-+-`*[A](s1, s2: TSet[A]): TSet[A] {.inline.} =
|
proc `-+-`*[A](s1, s2: HashSet[A]): TSet[A] {.inline.} =
|
||||||
## Alias for `symmetricDifference(s1, s2) <#symmetricDifference>`_.
|
## Alias for `symmetricDifference(s1, s2) <#symmetricDifference>`_.
|
||||||
result = symmetricDifference(s1, s2)
|
result = symmetricDifference(s1, s2)
|
||||||
|
|
||||||
proc disjoint*[A](s1, s2: TSet[A]): bool =
|
proc disjoint*[A](s1, s2: HashSet[A]): bool =
|
||||||
## Returns true iff the sets `s1` and `s2` have no items in common.
|
## Returns true iff the sets `s1` and `s2` have no items in common.
|
||||||
##
|
##
|
||||||
## Example:
|
## Example:
|
||||||
|
|
@ -428,7 +428,7 @@ proc disjoint*[A](s1, s2: TSet[A]): bool =
|
||||||
if item in s2: return false
|
if item in s2: return false
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc `<`*[A](s, t: TSet[A]): bool =
|
proc `<`*[A](s, t: HashSet[A]): bool =
|
||||||
## Returns true if `s` is a strict or proper subset of `t`.
|
## Returns true if `s` is a strict or proper subset of `t`.
|
||||||
##
|
##
|
||||||
## A strict or proper subset `s` has all of its members in `t` but `t` has
|
## A strict or proper subset `s` has all of its members in `t` but `t` has
|
||||||
|
|
@ -443,7 +443,7 @@ proc `<`*[A](s, t: TSet[A]): bool =
|
||||||
## assert((a < a) == false)
|
## assert((a < a) == false)
|
||||||
s.counter != t.counter and s <= t
|
s.counter != t.counter and s <= t
|
||||||
|
|
||||||
proc `<=`*[A](s, t: TSet[A]): bool =
|
proc `<=`*[A](s, t: HashSet[A]): bool =
|
||||||
## Returns true if `s` is subset of `t`.
|
## Returns true if `s` is subset of `t`.
|
||||||
##
|
##
|
||||||
## A subset `s` has all of its members in `t` and `t` doesn't necessarily
|
## A subset `s` has all of its members in `t` and `t` doesn't necessarily
|
||||||
|
|
@ -464,7 +464,7 @@ proc `<=`*[A](s, t: TSet[A]): bool =
|
||||||
result = false
|
result = false
|
||||||
return
|
return
|
||||||
|
|
||||||
proc `==`*[A](s, t: TSet[A]): bool =
|
proc `==`*[A](s, t: HashSet[A]): bool =
|
||||||
## Returns true if both `s` and `t` have the same members and set size.
|
## Returns true if both `s` and `t` have the same members and set size.
|
||||||
##
|
##
|
||||||
## Example:
|
## Example:
|
||||||
|
|
@ -477,7 +477,7 @@ proc `==`*[A](s, t: TSet[A]): bool =
|
||||||
## assert a == b
|
## assert a == b
|
||||||
s.counter == t.counter and s <= t
|
s.counter == t.counter and s <= t
|
||||||
|
|
||||||
proc map*[A, B](data: TSet[A], op: proc (x: A): B {.closure.}): TSet[B] =
|
proc map*[A, B](data: HashSet[A], op: proc (x: A): B {.closure.}): TSet[B] =
|
||||||
## Returns a new set after applying `op` on each of the elements of `data`.
|
## Returns a new set after applying `op` on each of the elements of `data`.
|
||||||
##
|
##
|
||||||
## You can use this proc to transform the elements from a set. Example:
|
## You can use this proc to transform the elements from a set. Example:
|
||||||
|
|
@ -534,7 +534,7 @@ proc len*[A](s: OrderedSet[A]): int {.inline.} =
|
||||||
## assert values.len == 0
|
## assert values.len == 0
|
||||||
result = s.counter
|
result = s.counter
|
||||||
|
|
||||||
proc card*[A](s: TOrderedSet[A]): int {.inline.} =
|
proc card*[A](s: OrderedSet[A]): int {.inline.} =
|
||||||
## Alias for `len() <#len,TOrderedSet[A]>`_.
|
## Alias for `len() <#len,TOrderedSet[A]>`_.
|
||||||
##
|
##
|
||||||
## Card stands for the `cardinality
|
## Card stands for the `cardinality
|
||||||
|
|
@ -548,7 +548,7 @@ template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} =
|
||||||
if s.data[h].slot == seFilled: yieldStmt
|
if s.data[h].slot == seFilled: yieldStmt
|
||||||
h = nxt
|
h = nxt
|
||||||
|
|
||||||
iterator items*[A](s: TOrderedSet[A]): A =
|
iterator items*[A](s: OrderedSet[A]): A =
|
||||||
## Iterates over keys in the ordered set `s` in insertion order.
|
## Iterates over keys in the ordered set `s` in insertion order.
|
||||||
##
|
##
|
||||||
## If you need a sequence with the keys you can use `sequtils.toSeq()
|
## If you need a sequence with the keys you can use `sequtils.toSeq()
|
||||||
|
|
@ -570,10 +570,10 @@ iterator items*[A](s: TOrderedSet[A]): A =
|
||||||
forAllOrderedPairs:
|
forAllOrderedPairs:
|
||||||
yield s.data[h].key
|
yield s.data[h].key
|
||||||
|
|
||||||
proc rawGet[A](s: TOrderedSet[A], key: A): int =
|
proc rawGet[A](s: OrderedSet[A], key: A): int =
|
||||||
rawGetImpl()
|
rawGetImpl()
|
||||||
|
|
||||||
proc contains*[A](s: TOrderedSet[A], key: A): bool =
|
proc contains*[A](s: OrderedSet[A], key: A): bool =
|
||||||
## Returns true iff `key` is in `s`.
|
## Returns true iff `key` is in `s`.
|
||||||
##
|
##
|
||||||
## Example:
|
## Example:
|
||||||
|
|
@ -587,7 +587,7 @@ proc contains*[A](s: TOrderedSet[A], key: A): bool =
|
||||||
var index = rawGet(s, key)
|
var index = rawGet(s, key)
|
||||||
result = index >= 0
|
result = index >= 0
|
||||||
|
|
||||||
proc rawInsert[A](s: var TOrderedSet[A],
|
proc rawInsert[A](s: var OrderedSet[A],
|
||||||
data: var OrderedKeyValuePairSeq[A], key: A) =
|
data: var OrderedKeyValuePairSeq[A], key: A) =
|
||||||
rawInsertImpl()
|
rawInsertImpl()
|
||||||
data[h].next = -1
|
data[h].next = -1
|
||||||
|
|
@ -595,7 +595,7 @@ proc rawInsert[A](s: var TOrderedSet[A],
|
||||||
if s.last >= 0: data[s.last].next = h
|
if s.last >= 0: data[s.last].next = h
|
||||||
s.last = h
|
s.last = h
|
||||||
|
|
||||||
proc enlarge[A](s: var TOrderedSet[A]) =
|
proc enlarge[A](s: var OrderedSet[A]) =
|
||||||
var n: OrderedKeyValuePairSeq[A]
|
var n: OrderedKeyValuePairSeq[A]
|
||||||
newSeq(n, len(s.data) * growthFactor)
|
newSeq(n, len(s.data) * growthFactor)
|
||||||
var h = s.first
|
var h = s.first
|
||||||
|
|
@ -608,7 +608,7 @@ proc enlarge[A](s: var TOrderedSet[A]) =
|
||||||
h = nxt
|
h = nxt
|
||||||
swap(s.data, n)
|
swap(s.data, n)
|
||||||
|
|
||||||
proc incl*[A](s: var TOrderedSet[A], key: A) =
|
proc incl*[A](s: var OrderedSet[A], key: A) =
|
||||||
## Includes an element `key` in `s`.
|
## Includes an element `key` in `s`.
|
||||||
##
|
##
|
||||||
## This doesn't do anything if `key` is already in `s`. Example:
|
## This doesn't do anything if `key` is already in `s`. Example:
|
||||||
|
|
@ -621,7 +621,7 @@ proc incl*[A](s: var TOrderedSet[A], key: A) =
|
||||||
assert s.isValid, "The set needs to be initialized."
|
assert s.isValid, "The set needs to be initialized."
|
||||||
inclImpl()
|
inclImpl()
|
||||||
|
|
||||||
proc incl*[A](s: var TSet[A], other: TOrderedSet[A]) =
|
proc incl*[A](s: var HashSet[A], other: TOrderedSet[A]) =
|
||||||
## Includes all elements from `other` into `s`.
|
## Includes all elements from `other` into `s`.
|
||||||
##
|
##
|
||||||
## Example:
|
## Example:
|
||||||
|
|
@ -636,7 +636,7 @@ proc incl*[A](s: var TSet[A], other: TOrderedSet[A]) =
|
||||||
assert other.isValid, "The set `other` needs to be initialized."
|
assert other.isValid, "The set `other` needs to be initialized."
|
||||||
for item in other: incl(s, item)
|
for item in other: incl(s, item)
|
||||||
|
|
||||||
proc containsOrIncl*[A](s: var TOrderedSet[A], key: A): bool =
|
proc containsOrIncl*[A](s: var OrderedSet[A], key: A): bool =
|
||||||
## Includes `key` in the set `s` and tells if `key` was added to `s`.
|
## Includes `key` in the set `s` and tells if `key` was added to `s`.
|
||||||
##
|
##
|
||||||
## The difference with regards to the `incl() <#incl,TOrderedSet[A],A>`_ proc
|
## The difference with regards to the `incl() <#incl,TOrderedSet[A],A>`_ proc
|
||||||
|
|
@ -651,7 +651,7 @@ proc containsOrIncl*[A](s: var TOrderedSet[A], key: A): bool =
|
||||||
assert s.isValid, "The set needs to be initialized."
|
assert s.isValid, "The set needs to be initialized."
|
||||||
containsOrInclImpl()
|
containsOrInclImpl()
|
||||||
|
|
||||||
proc init*[A](s: var TOrderedSet[A], initialSize=64) =
|
proc init*[A](s: var OrderedSet[A], initialSize=64) =
|
||||||
## Initializes an ordered hash set.
|
## Initializes an ordered hash set.
|
||||||
##
|
##
|
||||||
## The `initialSize` parameter needs to be a power of too. You can use
|
## The `initialSize` parameter needs to be a power of too. You can use
|
||||||
|
|
@ -676,7 +676,7 @@ proc init*[A](s: var TOrderedSet[A], initialSize=64) =
|
||||||
s.last = -1
|
s.last = -1
|
||||||
newSeq(s.data, initialSize)
|
newSeq(s.data, initialSize)
|
||||||
|
|
||||||
proc initOrderedSet*[A](initialSize=64): TOrderedSet[A] =
|
proc initOrderedSet*[A](initialSize=64): OrderedSet[A] =
|
||||||
## Wrapper around `init() <#init,TOrderedSet[A],int>`_ for initialization of
|
## Wrapper around `init() <#init,TOrderedSet[A],int>`_ for initialization of
|
||||||
## ordered hash sets.
|
## ordered hash sets.
|
||||||
##
|
##
|
||||||
|
|
@ -688,7 +688,7 @@ proc initOrderedSet*[A](initialSize=64): TOrderedSet[A] =
|
||||||
## a.incl(2)
|
## a.incl(2)
|
||||||
result.init(initialSize)
|
result.init(initialSize)
|
||||||
|
|
||||||
proc toOrderedSet*[A](keys: openArray[A]): TOrderedSet[A] =
|
proc toOrderedSet*[A](keys: openArray[A]): OrderedSet[A] =
|
||||||
## Creates a new ordered hash set that contains the given `keys`.
|
## Creates a new ordered hash set that contains the given `keys`.
|
||||||
##
|
##
|
||||||
## Example:
|
## Example:
|
||||||
|
|
@ -700,7 +700,7 @@ proc toOrderedSet*[A](keys: openArray[A]): TOrderedSet[A] =
|
||||||
result = initOrderedSet[A](nextPowerOfTwo(keys.len+10))
|
result = initOrderedSet[A](nextPowerOfTwo(keys.len+10))
|
||||||
for key in items(keys): result.incl(key)
|
for key in items(keys): result.incl(key)
|
||||||
|
|
||||||
proc `$`*[A](s: TOrderedSet[A]): string =
|
proc `$`*[A](s: OrderedSet[A]): string =
|
||||||
## Converts the ordered hash set `s` to a string, mostly for logging purposes.
|
## Converts the ordered hash set `s` to a string, mostly for logging purposes.
|
||||||
##
|
##
|
||||||
## Don't use this proc for serialization, the representation may change at
|
## Don't use this proc for serialization, the representation may change at
|
||||||
|
|
@ -716,7 +716,7 @@ proc `$`*[A](s: TOrderedSet[A]): string =
|
||||||
assert s.isValid, "The set needs to be initialized."
|
assert s.isValid, "The set needs to be initialized."
|
||||||
dollarImpl()
|
dollarImpl()
|
||||||
|
|
||||||
proc `==`*[A](s, t: TOrderedSet[A]): bool =
|
proc `==`*[A](s, t: OrderedSet[A]): bool =
|
||||||
## Equality for ordered sets.
|
## Equality for ordered sets.
|
||||||
if s.counter != t.counter: return false
|
if s.counter != t.counter: return false
|
||||||
var h = s.first
|
var h = s.first
|
||||||
|
|
@ -738,7 +738,7 @@ proc testModule() =
|
||||||
## Internal micro test to validate docstrings and such.
|
## Internal micro test to validate docstrings and such.
|
||||||
block isValidTest:
|
block isValidTest:
|
||||||
var options: HashSet[string]
|
var options: HashSet[string]
|
||||||
proc savePreferences(options: TSet[string]) =
|
proc savePreferences(options: HashSet[string]) =
|
||||||
assert options.isValid, "Pass an initialized set!"
|
assert options.isValid, "Pass an initialized set!"
|
||||||
options = initSet[string]()
|
options = initSet[string]()
|
||||||
options.savePreferences
|
options.savePreferences
|
||||||
|
|
@ -839,7 +839,7 @@ proc testModule() =
|
||||||
|
|
||||||
block isValidTest:
|
block isValidTest:
|
||||||
var cards: OrderedSet[string]
|
var cards: OrderedSet[string]
|
||||||
proc saveTarotCards(cards: TOrderedSet[string]) =
|
proc saveTarotCards(cards: OrderedSet[string]) =
|
||||||
assert cards.isValid, "Pass an initialized set!"
|
assert cards.isValid, "Pass an initialized set!"
|
||||||
cards = initOrderedSet[string]()
|
cards = initOrderedSet[string]()
|
||||||
cards.saveTarotCards
|
cards.saveTarotCards
|
||||||
|
|
@ -891,7 +891,7 @@ proc testModule() =
|
||||||
a.incl(2)
|
a.incl(2)
|
||||||
assert a.len == 1
|
assert a.len == 1
|
||||||
|
|
||||||
var b: TSet[int]
|
var b: HashSet[int]
|
||||||
b.init(4)
|
b.init(4)
|
||||||
b.incl(2)
|
b.incl(2)
|
||||||
b.init
|
b.init
|
||||||
|
|
|
||||||
|
|
@ -74,32 +74,32 @@ type
|
||||||
when not defined(nimhygiene):
|
when not defined(nimhygiene):
|
||||||
{.pragma: dirty.}
|
{.pragma: dirty.}
|
||||||
|
|
||||||
proc len*[A, B](t: TTable[A, B]): int =
|
proc len*[A, B](t: Table[A, B]): int =
|
||||||
## returns the number of keys in `t`.
|
## returns the number of keys in `t`.
|
||||||
result = t.counter
|
result = t.counter
|
||||||
|
|
||||||
iterator pairs*[A, B](t: TTable[A, B]): tuple[key: A, val: B] =
|
iterator pairs*[A, B](t: Table[A, B]): tuple[key: A, val: B] =
|
||||||
## iterates over any (key, value) pair in the table `t`.
|
## iterates over any (key, value) pair in the table `t`.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
|
if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
|
||||||
|
|
||||||
iterator mpairs*[A, B](t: var TTable[A, B]): tuple[key: A, val: var B] =
|
iterator mpairs*[A, B](t: var Table[A, B]): tuple[key: A, val: var B] =
|
||||||
## iterates over any (key, value) pair in the table `t`. The values
|
## iterates over any (key, value) pair in the table `t`. The values
|
||||||
## can be modified.
|
## can be modified.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
|
if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
|
||||||
|
|
||||||
iterator keys*[A, B](t: TTable[A, B]): A =
|
iterator keys*[A, B](t: Table[A, B]): A =
|
||||||
## iterates over any key in the table `t`.
|
## iterates over any key in the table `t`.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].slot == seFilled: yield t.data[h].key
|
if t.data[h].slot == seFilled: yield t.data[h].key
|
||||||
|
|
||||||
iterator values*[A, B](t: TTable[A, B]): B =
|
iterator values*[A, B](t: Table[A, B]): B =
|
||||||
## iterates over any value in the table `t`.
|
## iterates over any value in the table `t`.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].slot == seFilled: yield t.data[h].val
|
if t.data[h].slot == seFilled: yield t.data[h].val
|
||||||
|
|
||||||
iterator mvalues*[A, B](t: var TTable[A, B]): var B =
|
iterator mvalues*[A, B](t: var Table[A, B]): var B =
|
||||||
## iterates over any value in the table `t`. The values can be modified.
|
## iterates over any value in the table `t`. The values can be modified.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].slot == seFilled: yield t.data[h].val
|
if t.data[h].slot == seFilled: yield t.data[h].val
|
||||||
|
|
@ -130,10 +130,10 @@ template rawInsertImpl() {.dirty.} =
|
||||||
data[h].val = val
|
data[h].val = val
|
||||||
data[h].slot = seFilled
|
data[h].slot = seFilled
|
||||||
|
|
||||||
proc rawGet[A, B](t: TTable[A, B], key: A): int =
|
proc rawGet[A, B](t: Table[A, B], key: A): int =
|
||||||
rawGetImpl()
|
rawGetImpl()
|
||||||
|
|
||||||
proc `[]`*[A, B](t: TTable[A, B], key: A): B =
|
proc `[]`*[A, B](t: Table[A, B], key: A): B =
|
||||||
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
||||||
## default empty value for the type `B` is returned
|
## default empty value for the type `B` is returned
|
||||||
## and no exception is raised. One can check with ``hasKey`` whether the key
|
## and no exception is raised. One can check with ``hasKey`` whether the key
|
||||||
|
|
@ -141,14 +141,14 @@ proc `[]`*[A, B](t: TTable[A, B], key: A): B =
|
||||||
var index = rawGet(t, key)
|
var index = rawGet(t, key)
|
||||||
if index >= 0: result = t.data[index].val
|
if index >= 0: result = t.data[index].val
|
||||||
|
|
||||||
proc mget*[A, B](t: var TTable[A, B], key: A): var B =
|
proc mget*[A, B](t: var Table[A, B], key: A): var B =
|
||||||
## retrieves the value at ``t[key]``. The value can be modified.
|
## retrieves the value at ``t[key]``. The value can be modified.
|
||||||
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
||||||
var index = rawGet(t, key)
|
var index = rawGet(t, key)
|
||||||
if index >= 0: result = t.data[index].val
|
if index >= 0: result = t.data[index].val
|
||||||
else: raise newException(KeyError, "key not found: " & $key)
|
else: raise newException(KeyError, "key not found: " & $key)
|
||||||
|
|
||||||
iterator allValues*[A, B](t: TTable[A, B]; key: A): B =
|
iterator allValues*[A, B](t: Table[A, B]; key: A): B =
|
||||||
## iterates over any value in the table `t` that belongs to the given `key`.
|
## iterates over any value in the table `t` that belongs to the given `key`.
|
||||||
var h: THash = hash(key) and high(t.data)
|
var h: THash = hash(key) and high(t.data)
|
||||||
while t.data[h].slot != seEmpty:
|
while t.data[h].slot != seEmpty:
|
||||||
|
|
@ -156,15 +156,15 @@ iterator allValues*[A, B](t: TTable[A, B]; key: A): B =
|
||||||
yield t.data[h].val
|
yield t.data[h].val
|
||||||
h = nextTry(h, high(t.data))
|
h = nextTry(h, high(t.data))
|
||||||
|
|
||||||
proc hasKey*[A, B](t: TTable[A, B], key: A): bool =
|
proc hasKey*[A, B](t: Table[A, B], key: A): bool =
|
||||||
## returns true iff `key` is in the table `t`.
|
## returns true iff `key` is in the table `t`.
|
||||||
result = rawGet(t, key) >= 0
|
result = rawGet(t, key) >= 0
|
||||||
|
|
||||||
proc rawInsert[A, B](t: var TTable[A, B], data: var KeyValuePairSeq[A, B],
|
proc rawInsert[A, B](t: var Table[A, B], data: var KeyValuePairSeq[A, B],
|
||||||
key: A, val: B) =
|
key: A, val: B) =
|
||||||
rawInsertImpl()
|
rawInsertImpl()
|
||||||
|
|
||||||
proc enlarge[A, B](t: var TTable[A, B]) =
|
proc enlarge[A, B](t: var Table[A, B]) =
|
||||||
var n: KeyValuePairSeq[A, B]
|
var n: KeyValuePairSeq[A, B]
|
||||||
newSeq(n, len(t.data) * growthFactor)
|
newSeq(n, len(t.data) * growthFactor)
|
||||||
for i in countup(0, high(t.data)):
|
for i in countup(0, high(t.data)):
|
||||||
|
|
@ -196,22 +196,22 @@ when false:
|
||||||
inc(t.counter)
|
inc(t.counter)
|
||||||
result = false
|
result = false
|
||||||
|
|
||||||
proc `[]=`*[A, B](t: var TTable[A, B], key: A, val: B) =
|
proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) =
|
||||||
## puts a (key, value)-pair into `t`.
|
## puts a (key, value)-pair into `t`.
|
||||||
putImpl()
|
putImpl()
|
||||||
|
|
||||||
proc add*[A, B](t: var TTable[A, B], key: A, val: B) =
|
proc add*[A, B](t: var Table[A, B], key: A, val: B) =
|
||||||
## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
|
## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
|
||||||
addImpl()
|
addImpl()
|
||||||
|
|
||||||
proc del*[A, B](t: var TTable[A, B], key: A) =
|
proc del*[A, B](t: var Table[A, B], key: A) =
|
||||||
## deletes `key` from hash table `t`.
|
## deletes `key` from hash table `t`.
|
||||||
let index = rawGet(t, key)
|
let index = rawGet(t, key)
|
||||||
if index >= 0:
|
if index >= 0:
|
||||||
t.data[index].slot = seDeleted
|
t.data[index].slot = seDeleted
|
||||||
dec(t.counter)
|
dec(t.counter)
|
||||||
|
|
||||||
proc initTable*[A, B](initialSize=64): TTable[A, B] =
|
proc initTable*[A, B](initialSize=64): Table[A, B] =
|
||||||
## creates a new hash table that is empty.
|
## creates a new hash table that is empty.
|
||||||
##
|
##
|
||||||
## `initialSize` needs to be a power of two. If you need to accept runtime
|
## `initialSize` needs to be a power of two. If you need to accept runtime
|
||||||
|
|
@ -222,7 +222,7 @@ proc initTable*[A, B](initialSize=64): TTable[A, B] =
|
||||||
newSeq(result.data, initialSize)
|
newSeq(result.data, initialSize)
|
||||||
|
|
||||||
proc toTable*[A, B](pairs: openArray[tuple[key: A,
|
proc toTable*[A, B](pairs: openArray[tuple[key: A,
|
||||||
val: B]]): TTable[A, B] =
|
val: B]]): Table[A, B] =
|
||||||
## creates a new hash table that contains the given `pairs`.
|
## creates a new hash table that contains the given `pairs`.
|
||||||
result = initTable[A, B](nextPowerOfTwo(pairs.len+10))
|
result = initTable[A, B](nextPowerOfTwo(pairs.len+10))
|
||||||
for key, val in items(pairs): result[key] = val
|
for key, val in items(pairs): result[key] = val
|
||||||
|
|
@ -239,7 +239,7 @@ template dollarImpl(): stmt {.dirty.} =
|
||||||
result.add($val)
|
result.add($val)
|
||||||
result.add("}")
|
result.add("}")
|
||||||
|
|
||||||
proc `$`*[A, B](t: TTable[A, B]): string =
|
proc `$`*[A, B](t: Table[A, B]): string =
|
||||||
## The `$` operator for hash tables.
|
## The `$` operator for hash tables.
|
||||||
dollarImpl()
|
dollarImpl()
|
||||||
|
|
||||||
|
|
@ -253,93 +253,93 @@ template equalsImpl() =
|
||||||
if t[key] != val: return false
|
if t[key] != val: return false
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc `==`*[A, B](s, t: TTable[A, B]): bool =
|
proc `==`*[A, B](s, t: Table[A, B]): bool =
|
||||||
equalsImpl()
|
equalsImpl()
|
||||||
|
|
||||||
proc indexBy*[A, B, C](collection: A, index: proc(x: B): C): TTable[C, B] =
|
proc indexBy*[A, B, C](collection: A, index: proc(x: B): C): Table[C, B] =
|
||||||
## Index the collection with the proc provided.
|
## Index the collection with the proc provided.
|
||||||
# TODO: As soon as supported, change collection: A to collection: A[B]
|
# TODO: As soon as supported, change collection: A to collection: A[B]
|
||||||
result = initTable[C, B]()
|
result = initTable[C, B]()
|
||||||
for item in collection:
|
for item in collection:
|
||||||
result[index(item)] = item
|
result[index(item)] = item
|
||||||
|
|
||||||
proc len*[A, B](t: PTable[A, B]): int =
|
proc len*[A, B](t: TableRef[A, B]): int =
|
||||||
## returns the number of keys in `t`.
|
## returns the number of keys in `t`.
|
||||||
result = t.counter
|
result = t.counter
|
||||||
|
|
||||||
iterator pairs*[A, B](t: PTable[A, B]): tuple[key: A, val: B] =
|
iterator pairs*[A, B](t: TableRef[A, B]): tuple[key: A, val: B] =
|
||||||
## iterates over any (key, value) pair in the table `t`.
|
## iterates over any (key, value) pair in the table `t`.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
|
if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
|
||||||
|
|
||||||
iterator mpairs*[A, B](t: PTable[A, B]): tuple[key: A, val: var B] =
|
iterator mpairs*[A, B](t: TableRef[A, B]): tuple[key: A, val: var B] =
|
||||||
## iterates over any (key, value) pair in the table `t`. The values
|
## iterates over any (key, value) pair in the table `t`. The values
|
||||||
## can be modified.
|
## can be modified.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
|
if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
|
||||||
|
|
||||||
iterator keys*[A, B](t: PTable[A, B]): A =
|
iterator keys*[A, B](t: TableRef[A, B]): A =
|
||||||
## iterates over any key in the table `t`.
|
## iterates over any key in the table `t`.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].slot == seFilled: yield t.data[h].key
|
if t.data[h].slot == seFilled: yield t.data[h].key
|
||||||
|
|
||||||
iterator values*[A, B](t: PTable[A, B]): B =
|
iterator values*[A, B](t: TableRef[A, B]): B =
|
||||||
## iterates over any value in the table `t`.
|
## iterates over any value in the table `t`.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].slot == seFilled: yield t.data[h].val
|
if t.data[h].slot == seFilled: yield t.data[h].val
|
||||||
|
|
||||||
iterator mvalues*[A, B](t: PTable[A, B]): var B =
|
iterator mvalues*[A, B](t: TableRef[A, B]): var B =
|
||||||
## iterates over any value in the table `t`. The values can be modified.
|
## iterates over any value in the table `t`. The values can be modified.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].slot == seFilled: yield t.data[h].val
|
if t.data[h].slot == seFilled: yield t.data[h].val
|
||||||
|
|
||||||
proc `[]`*[A, B](t: PTable[A, B], key: A): B =
|
proc `[]`*[A, B](t: TableRef[A, B], key: A): B =
|
||||||
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
||||||
## default empty value for the type `B` is returned
|
## default empty value for the type `B` is returned
|
||||||
## and no exception is raised. One can check with ``hasKey`` whether the key
|
## and no exception is raised. One can check with ``hasKey`` whether the key
|
||||||
## exists.
|
## exists.
|
||||||
result = t[][key]
|
result = t[][key]
|
||||||
|
|
||||||
proc mget*[A, B](t: PTable[A, B], key: A): var B =
|
proc mget*[A, B](t: TableRef[A, B], key: A): var B =
|
||||||
## retrieves the value at ``t[key]``. The value can be modified.
|
## retrieves the value at ``t[key]``. The value can be modified.
|
||||||
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
||||||
t[].mget(key)
|
t[].mget(key)
|
||||||
|
|
||||||
proc hasKey*[A, B](t: PTable[A, B], key: A): bool =
|
proc hasKey*[A, B](t: TableRef[A, B], key: A): bool =
|
||||||
## returns true iff `key` is in the table `t`.
|
## returns true iff `key` is in the table `t`.
|
||||||
result = t[].hasKey(key)
|
result = t[].hasKey(key)
|
||||||
|
|
||||||
proc `[]=`*[A, B](t: PTable[A, B], key: A, val: B) =
|
proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: B) =
|
||||||
## puts a (key, value)-pair into `t`.
|
## puts a (key, value)-pair into `t`.
|
||||||
t[][key] = val
|
t[][key] = val
|
||||||
|
|
||||||
proc add*[A, B](t: PTable[A, B], key: A, val: B) =
|
proc add*[A, B](t: TableRef[A, B], key: A, val: B) =
|
||||||
## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
|
## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
|
||||||
t[].add(key, val)
|
t[].add(key, val)
|
||||||
|
|
||||||
proc del*[A, B](t: PTable[A, B], key: A) =
|
proc del*[A, B](t: TableRef[A, B], key: A) =
|
||||||
## deletes `key` from hash table `t`.
|
## deletes `key` from hash table `t`.
|
||||||
t[].del(key)
|
t[].del(key)
|
||||||
|
|
||||||
proc newTable*[A, B](initialSize=64): PTable[A, B] =
|
proc newTable*[A, B](initialSize=64): TableRef[A, B] =
|
||||||
new(result)
|
new(result)
|
||||||
result[] = initTable[A, B](initialSize)
|
result[] = initTable[A, B](initialSize)
|
||||||
|
|
||||||
proc newTable*[A, B](pairs: openArray[tuple[key: A, val: B]]): PTable[A, B] =
|
proc newTable*[A, B](pairs: openArray[tuple[key: A, val: B]]): TableRef[A, B] =
|
||||||
## creates a new hash table that contains the given `pairs`.
|
## creates a new hash table that contains the given `pairs`.
|
||||||
new(result)
|
new(result)
|
||||||
result[] = toTable[A, B](pairs)
|
result[] = toTable[A, B](pairs)
|
||||||
|
|
||||||
proc `$`*[A, B](t: PTable[A, B]): string =
|
proc `$`*[A, B](t: TableRef[A, B]): string =
|
||||||
## The `$` operator for hash tables.
|
## The `$` operator for hash tables.
|
||||||
dollarImpl()
|
dollarImpl()
|
||||||
|
|
||||||
proc `==`*[A, B](s, t: PTable[A, B]): bool =
|
proc `==`*[A, B](s, t: TableRef[A, B]): bool =
|
||||||
if isNil(s): result = isNil(t)
|
if isNil(s): result = isNil(t)
|
||||||
elif isNil(t): result = false
|
elif isNil(t): result = false
|
||||||
else: result = equalsImpl()
|
else: result = equalsImpl()
|
||||||
|
|
||||||
proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): PTable[C, B] =
|
proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B] =
|
||||||
## Index the collection with the proc provided.
|
## Index the collection with the proc provided.
|
||||||
# TODO: As soon as supported, change collection: A to collection: A[B]
|
# TODO: As soon as supported, change collection: A to collection: A[B]
|
||||||
result = newTable[C, B]()
|
result = newTable[C, B]()
|
||||||
|
|
@ -360,7 +360,7 @@ type
|
||||||
|
|
||||||
{.deprecated: [TOrderedTable: OrderedTable, POrderedTable: OrderedTableRef].}
|
{.deprecated: [TOrderedTable: OrderedTable, POrderedTable: OrderedTableRef].}
|
||||||
|
|
||||||
proc len*[A, B](t: TOrderedTable[A, B]): int {.inline.} =
|
proc len*[A, B](t: OrderedTable[A, B]): int {.inline.} =
|
||||||
## returns the number of keys in `t`.
|
## returns the number of keys in `t`.
|
||||||
result = t.counter
|
result = t.counter
|
||||||
|
|
||||||
|
|
@ -371,38 +371,38 @@ template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} =
|
||||||
if t.data[h].slot == seFilled: yieldStmt
|
if t.data[h].slot == seFilled: yieldStmt
|
||||||
h = nxt
|
h = nxt
|
||||||
|
|
||||||
iterator pairs*[A, B](t: TOrderedTable[A, B]): tuple[key: A, val: B] =
|
iterator pairs*[A, B](t: OrderedTable[A, B]): tuple[key: A, val: B] =
|
||||||
## iterates over any (key, value) pair in the table `t` in insertion
|
## iterates over any (key, value) pair in the table `t` in insertion
|
||||||
## order.
|
## order.
|
||||||
forAllOrderedPairs:
|
forAllOrderedPairs:
|
||||||
yield (t.data[h].key, t.data[h].val)
|
yield (t.data[h].key, t.data[h].val)
|
||||||
|
|
||||||
iterator mpairs*[A, B](t: var TOrderedTable[A, B]): tuple[key: A, val: var B] =
|
iterator mpairs*[A, B](t: var OrderedTable[A, B]): tuple[key: A, val: var B] =
|
||||||
## iterates over any (key, value) pair in the table `t` in insertion
|
## iterates over any (key, value) pair in the table `t` in insertion
|
||||||
## order. The values can be modified.
|
## order. The values can be modified.
|
||||||
forAllOrderedPairs:
|
forAllOrderedPairs:
|
||||||
yield (t.data[h].key, t.data[h].val)
|
yield (t.data[h].key, t.data[h].val)
|
||||||
|
|
||||||
iterator keys*[A, B](t: TOrderedTable[A, B]): A =
|
iterator keys*[A, B](t: OrderedTable[A, B]): A =
|
||||||
## iterates over any key in the table `t` in insertion order.
|
## iterates over any key in the table `t` in insertion order.
|
||||||
forAllOrderedPairs:
|
forAllOrderedPairs:
|
||||||
yield t.data[h].key
|
yield t.data[h].key
|
||||||
|
|
||||||
iterator values*[A, B](t: TOrderedTable[A, B]): B =
|
iterator values*[A, B](t: OrderedTable[A, B]): B =
|
||||||
## iterates over any value in the table `t` in insertion order.
|
## iterates over any value in the table `t` in insertion order.
|
||||||
forAllOrderedPairs:
|
forAllOrderedPairs:
|
||||||
yield t.data[h].val
|
yield t.data[h].val
|
||||||
|
|
||||||
iterator mvalues*[A, B](t: var TOrderedTable[A, B]): var B =
|
iterator mvalues*[A, B](t: var OrderedTable[A, B]): var B =
|
||||||
## iterates over any value in the table `t` in insertion order. The values
|
## iterates over any value in the table `t` in insertion order. The values
|
||||||
## can be modified.
|
## can be modified.
|
||||||
forAllOrderedPairs:
|
forAllOrderedPairs:
|
||||||
yield t.data[h].val
|
yield t.data[h].val
|
||||||
|
|
||||||
proc rawGet[A, B](t: TOrderedTable[A, B], key: A): int =
|
proc rawGet[A, B](t: OrderedTable[A, B], key: A): int =
|
||||||
rawGetImpl()
|
rawGetImpl()
|
||||||
|
|
||||||
proc `[]`*[A, B](t: TOrderedTable[A, B], key: A): B =
|
proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B =
|
||||||
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
||||||
## default empty value for the type `B` is returned
|
## default empty value for the type `B` is returned
|
||||||
## and no exception is raised. One can check with ``hasKey`` whether the key
|
## and no exception is raised. One can check with ``hasKey`` whether the key
|
||||||
|
|
@ -410,18 +410,18 @@ proc `[]`*[A, B](t: TOrderedTable[A, B], key: A): B =
|
||||||
var index = rawGet(t, key)
|
var index = rawGet(t, key)
|
||||||
if index >= 0: result = t.data[index].val
|
if index >= 0: result = t.data[index].val
|
||||||
|
|
||||||
proc mget*[A, B](t: var TOrderedTable[A, B], key: A): var B =
|
proc mget*[A, B](t: var OrderedTable[A, B], key: A): var B =
|
||||||
## retrieves the value at ``t[key]``. The value can be modified.
|
## retrieves the value at ``t[key]``. The value can be modified.
|
||||||
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
||||||
var index = rawGet(t, key)
|
var index = rawGet(t, key)
|
||||||
if index >= 0: result = t.data[index].val
|
if index >= 0: result = t.data[index].val
|
||||||
else: raise newException(KeyError, "key not found: " & $key)
|
else: raise newException(KeyError, "key not found: " & $key)
|
||||||
|
|
||||||
proc hasKey*[A, B](t: TOrderedTable[A, B], key: A): bool =
|
proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool =
|
||||||
## returns true iff `key` is in the table `t`.
|
## returns true iff `key` is in the table `t`.
|
||||||
result = rawGet(t, key) >= 0
|
result = rawGet(t, key) >= 0
|
||||||
|
|
||||||
proc rawInsert[A, B](t: var TOrderedTable[A, B],
|
proc rawInsert[A, B](t: var OrderedTable[A, B],
|
||||||
data: var OrderedKeyValuePairSeq[A, B],
|
data: var OrderedKeyValuePairSeq[A, B],
|
||||||
key: A, val: B) =
|
key: A, val: B) =
|
||||||
rawInsertImpl()
|
rawInsertImpl()
|
||||||
|
|
@ -430,7 +430,7 @@ proc rawInsert[A, B](t: var TOrderedTable[A, B],
|
||||||
if t.last >= 0: data[t.last].next = h
|
if t.last >= 0: data[t.last].next = h
|
||||||
t.last = h
|
t.last = h
|
||||||
|
|
||||||
proc enlarge[A, B](t: var TOrderedTable[A, B]) =
|
proc enlarge[A, B](t: var OrderedTable[A, B]) =
|
||||||
var n: OrderedKeyValuePairSeq[A, B]
|
var n: OrderedKeyValuePairSeq[A, B]
|
||||||
newSeq(n, len(t.data) * growthFactor)
|
newSeq(n, len(t.data) * growthFactor)
|
||||||
var h = t.first
|
var h = t.first
|
||||||
|
|
@ -443,15 +443,15 @@ proc enlarge[A, B](t: var TOrderedTable[A, B]) =
|
||||||
h = nxt
|
h = nxt
|
||||||
swap(t.data, n)
|
swap(t.data, n)
|
||||||
|
|
||||||
proc `[]=`*[A, B](t: var TOrderedTable[A, B], key: A, val: B) =
|
proc `[]=`*[A, B](t: var OrderedTable[A, B], key: A, val: B) =
|
||||||
## puts a (key, value)-pair into `t`.
|
## puts a (key, value)-pair into `t`.
|
||||||
putImpl()
|
putImpl()
|
||||||
|
|
||||||
proc add*[A, B](t: var TOrderedTable[A, B], key: A, val: B) =
|
proc add*[A, B](t: var OrderedTable[A, B], key: A, val: B) =
|
||||||
## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
|
## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
|
||||||
addImpl()
|
addImpl()
|
||||||
|
|
||||||
proc initOrderedTable*[A, B](initialSize=64): TOrderedTable[A, B] =
|
proc initOrderedTable*[A, B](initialSize=64): OrderedTable[A, B] =
|
||||||
## creates a new ordered hash table that is empty.
|
## creates a new ordered hash table that is empty.
|
||||||
##
|
##
|
||||||
## `initialSize` needs to be a power of two. If you need to accept runtime
|
## `initialSize` needs to be a power of two. If you need to accept runtime
|
||||||
|
|
@ -464,16 +464,16 @@ proc initOrderedTable*[A, B](initialSize=64): TOrderedTable[A, B] =
|
||||||
newSeq(result.data, initialSize)
|
newSeq(result.data, initialSize)
|
||||||
|
|
||||||
proc toOrderedTable*[A, B](pairs: openArray[tuple[key: A,
|
proc toOrderedTable*[A, B](pairs: openArray[tuple[key: A,
|
||||||
val: B]]): TOrderedTable[A, B] =
|
val: B]]): OrderedTable[A, B] =
|
||||||
## creates a new ordered hash table that contains the given `pairs`.
|
## creates a new ordered hash table that contains the given `pairs`.
|
||||||
result = initOrderedTable[A, B](nextPowerOfTwo(pairs.len+10))
|
result = initOrderedTable[A, B](nextPowerOfTwo(pairs.len+10))
|
||||||
for key, val in items(pairs): result[key] = val
|
for key, val in items(pairs): result[key] = val
|
||||||
|
|
||||||
proc `$`*[A, B](t: TOrderedTable[A, B]): string =
|
proc `$`*[A, B](t: OrderedTable[A, B]): string =
|
||||||
## The `$` operator for ordered hash tables.
|
## The `$` operator for ordered hash tables.
|
||||||
dollarImpl()
|
dollarImpl()
|
||||||
|
|
||||||
proc sort*[A, B](t: var TOrderedTable[A, B],
|
proc sort*[A, B](t: var OrderedTable[A, B],
|
||||||
cmp: proc (x,y: tuple[key: A, val: B]): int) =
|
cmp: proc (x,y: tuple[key: A, val: B]): int) =
|
||||||
## sorts `t` according to `cmp`. This modifies the internal list
|
## sorts `t` according to `cmp`. This modifies the internal list
|
||||||
## that kept the insertion order, so insertion order is lost after this
|
## that kept the insertion order, so insertion order is lost after this
|
||||||
|
|
@ -519,7 +519,7 @@ proc sort*[A, B](t: var TOrderedTable[A, B],
|
||||||
t.first = list
|
t.first = list
|
||||||
t.last = tail
|
t.last = tail
|
||||||
|
|
||||||
proc len*[A, B](t: POrderedTable[A, B]): int {.inline.} =
|
proc len*[A, B](t: OrderedTableRef[A, B]): int {.inline.} =
|
||||||
## returns the number of keys in `t`.
|
## returns the number of keys in `t`.
|
||||||
result = t.counter
|
result = t.counter
|
||||||
|
|
||||||
|
|
@ -530,59 +530,59 @@ template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} =
|
||||||
if t.data[h].slot == seFilled: yieldStmt
|
if t.data[h].slot == seFilled: yieldStmt
|
||||||
h = nxt
|
h = nxt
|
||||||
|
|
||||||
iterator pairs*[A, B](t: POrderedTable[A, B]): tuple[key: A, val: B] =
|
iterator pairs*[A, B](t: OrderedTableRef[A, B]): tuple[key: A, val: B] =
|
||||||
## iterates over any (key, value) pair in the table `t` in insertion
|
## iterates over any (key, value) pair in the table `t` in insertion
|
||||||
## order.
|
## order.
|
||||||
forAllOrderedPairs:
|
forAllOrderedPairs:
|
||||||
yield (t.data[h].key, t.data[h].val)
|
yield (t.data[h].key, t.data[h].val)
|
||||||
|
|
||||||
iterator mpairs*[A, B](t: POrderedTable[A, B]): tuple[key: A, val: var B] =
|
iterator mpairs*[A, B](t: OrderedTableRef[A, B]): tuple[key: A, val: var B] =
|
||||||
## iterates over any (key, value) pair in the table `t` in insertion
|
## iterates over any (key, value) pair in the table `t` in insertion
|
||||||
## order. The values can be modified.
|
## order. The values can be modified.
|
||||||
forAllOrderedPairs:
|
forAllOrderedPairs:
|
||||||
yield (t.data[h].key, t.data[h].val)
|
yield (t.data[h].key, t.data[h].val)
|
||||||
|
|
||||||
iterator keys*[A, B](t: POrderedTable[A, B]): A =
|
iterator keys*[A, B](t: OrderedTableRef[A, B]): A =
|
||||||
## iterates over any key in the table `t` in insertion order.
|
## iterates over any key in the table `t` in insertion order.
|
||||||
forAllOrderedPairs:
|
forAllOrderedPairs:
|
||||||
yield t.data[h].key
|
yield t.data[h].key
|
||||||
|
|
||||||
iterator values*[A, B](t: POrderedTable[A, B]): B =
|
iterator values*[A, B](t: OrderedTableRef[A, B]): B =
|
||||||
## iterates over any value in the table `t` in insertion order.
|
## iterates over any value in the table `t` in insertion order.
|
||||||
forAllOrderedPairs:
|
forAllOrderedPairs:
|
||||||
yield t.data[h].val
|
yield t.data[h].val
|
||||||
|
|
||||||
iterator mvalues*[A, B](t: POrderedTable[A, B]): var B =
|
iterator mvalues*[A, B](t: OrderedTableRef[A, B]): var B =
|
||||||
## iterates over any value in the table `t` in insertion order. The values
|
## iterates over any value in the table `t` in insertion order. The values
|
||||||
## can be modified.
|
## can be modified.
|
||||||
forAllOrderedPairs:
|
forAllOrderedPairs:
|
||||||
yield t.data[h].val
|
yield t.data[h].val
|
||||||
|
|
||||||
proc `[]`*[A, B](t: POrderedTable[A, B], key: A): B =
|
proc `[]`*[A, B](t: OrderedTableRef[A, B], key: A): B =
|
||||||
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
||||||
## default empty value for the type `B` is returned
|
## default empty value for the type `B` is returned
|
||||||
## and no exception is raised. One can check with ``hasKey`` whether the key
|
## and no exception is raised. One can check with ``hasKey`` whether the key
|
||||||
## exists.
|
## exists.
|
||||||
result = t[][key]
|
result = t[][key]
|
||||||
|
|
||||||
proc mget*[A, B](t: POrderedTable[A, B], key: A): var B =
|
proc mget*[A, B](t: OrderedTableRef[A, B], key: A): var B =
|
||||||
## retrieves the value at ``t[key]``. The value can be modified.
|
## retrieves the value at ``t[key]``. The value can be modified.
|
||||||
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
||||||
result = t[].mget(key)
|
result = t[].mget(key)
|
||||||
|
|
||||||
proc hasKey*[A, B](t: POrderedTable[A, B], key: A): bool =
|
proc hasKey*[A, B](t: OrderedTableRef[A, B], key: A): bool =
|
||||||
## returns true iff `key` is in the table `t`.
|
## returns true iff `key` is in the table `t`.
|
||||||
result = t[].hasKey(key)
|
result = t[].hasKey(key)
|
||||||
|
|
||||||
proc `[]=`*[A, B](t: POrderedTable[A, B], key: A, val: B) =
|
proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: A, val: B) =
|
||||||
## puts a (key, value)-pair into `t`.
|
## puts a (key, value)-pair into `t`.
|
||||||
t[][key] = val
|
t[][key] = val
|
||||||
|
|
||||||
proc add*[A, B](t: POrderedTable[A, B], key: A, val: B) =
|
proc add*[A, B](t: OrderedTableRef[A, B], key: A, val: B) =
|
||||||
## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
|
## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
|
||||||
t[].add(key, val)
|
t[].add(key, val)
|
||||||
|
|
||||||
proc newOrderedTable*[A, B](initialSize=64): POrderedTable[A, B] =
|
proc newOrderedTable*[A, B](initialSize=64): OrderedTableRef[A, B] =
|
||||||
## creates a new ordered hash table that is empty.
|
## creates a new ordered hash table that is empty.
|
||||||
##
|
##
|
||||||
## `initialSize` needs to be a power of two. If you need to accept runtime
|
## `initialSize` needs to be a power of two. If you need to accept runtime
|
||||||
|
|
@ -592,16 +592,16 @@ proc newOrderedTable*[A, B](initialSize=64): POrderedTable[A, B] =
|
||||||
result[] = initOrderedTable[A, B]()
|
result[] = initOrderedTable[A, B]()
|
||||||
|
|
||||||
proc newOrderedTable*[A, B](pairs: openArray[tuple[key: A,
|
proc newOrderedTable*[A, B](pairs: openArray[tuple[key: A,
|
||||||
val: B]]): POrderedTable[A, B] =
|
val: B]]): OrderedTableRef[A, B] =
|
||||||
## creates a new ordered hash table that contains the given `pairs`.
|
## creates a new ordered hash table that contains the given `pairs`.
|
||||||
result = newOrderedTable[A, B](nextPowerOfTwo(pairs.len+10))
|
result = newOrderedTable[A, B](nextPowerOfTwo(pairs.len+10))
|
||||||
for key, val in items(pairs): result[key] = val
|
for key, val in items(pairs): result[key] = val
|
||||||
|
|
||||||
proc `$`*[A, B](t: POrderedTable[A, B]): string =
|
proc `$`*[A, B](t: OrderedTableRef[A, B]): string =
|
||||||
## The `$` operator for ordered hash tables.
|
## The `$` operator for ordered hash tables.
|
||||||
dollarImpl()
|
dollarImpl()
|
||||||
|
|
||||||
proc sort*[A, B](t: POrderedTable[A, B],
|
proc sort*[A, B](t: OrderedTableRef[A, B],
|
||||||
cmp: proc (x,y: tuple[key: A, val: B]): int) =
|
cmp: proc (x,y: tuple[key: A, val: B]): int) =
|
||||||
## sorts `t` according to `cmp`. This modifies the internal list
|
## sorts `t` according to `cmp`. This modifies the internal list
|
||||||
## that kept the insertion order, so insertion order is lost after this
|
## that kept the insertion order, so insertion order is lost after this
|
||||||
|
|
@ -620,81 +620,81 @@ type
|
||||||
|
|
||||||
{.deprecated: [TCountTable: CountTable, PCountTable: CountTableRef].}
|
{.deprecated: [TCountTable: CountTable, PCountTable: CountTableRef].}
|
||||||
|
|
||||||
proc len*[A](t: TCountTable[A]): int =
|
proc len*[A](t: CountTable[A]): int =
|
||||||
## returns the number of keys in `t`.
|
## returns the number of keys in `t`.
|
||||||
result = t.counter
|
result = t.counter
|
||||||
|
|
||||||
iterator pairs*[A](t: TCountTable[A]): tuple[key: A, val: int] =
|
iterator pairs*[A](t: CountTable[A]): tuple[key: A, val: int] =
|
||||||
## iterates over any (key, value) pair in the table `t`.
|
## iterates over any (key, value) pair in the table `t`.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
|
if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
|
||||||
|
|
||||||
iterator mpairs*[A](t: var TCountTable[A]): tuple[key: A, val: var int] =
|
iterator mpairs*[A](t: var CountTable[A]): tuple[key: A, val: var int] =
|
||||||
## iterates over any (key, value) pair in the table `t`. The values can
|
## iterates over any (key, value) pair in the table `t`. The values can
|
||||||
## be modified.
|
## be modified.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
|
if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
|
||||||
|
|
||||||
iterator keys*[A](t: TCountTable[A]): A =
|
iterator keys*[A](t: CountTable[A]): A =
|
||||||
## iterates over any key in the table `t`.
|
## iterates over any key in the table `t`.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].val != 0: yield t.data[h].key
|
if t.data[h].val != 0: yield t.data[h].key
|
||||||
|
|
||||||
iterator values*[A](t: TCountTable[A]): int =
|
iterator values*[A](t: CountTable[A]): int =
|
||||||
## iterates over any value in the table `t`.
|
## iterates over any value in the table `t`.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].val != 0: yield t.data[h].val
|
if t.data[h].val != 0: yield t.data[h].val
|
||||||
|
|
||||||
iterator mvalues*[A](t: TCountTable[A]): var int =
|
iterator mvalues*[A](t: CountTable[A]): var int =
|
||||||
## iterates over any value in the table `t`. The values can be modified.
|
## iterates over any value in the table `t`. The values can be modified.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].val != 0: yield t.data[h].val
|
if t.data[h].val != 0: yield t.data[h].val
|
||||||
|
|
||||||
proc rawGet[A](t: TCountTable[A], key: A): int =
|
proc rawGet[A](t: CountTable[A], key: A): int =
|
||||||
var h: THash = hash(key) and high(t.data) # start with real hash value
|
var h: THash = hash(key) and high(t.data) # start with real hash value
|
||||||
while t.data[h].val != 0:
|
while t.data[h].val != 0:
|
||||||
if t.data[h].key == key: return h
|
if t.data[h].key == key: return h
|
||||||
h = nextTry(h, high(t.data))
|
h = nextTry(h, high(t.data))
|
||||||
result = -1
|
result = -1
|
||||||
|
|
||||||
proc `[]`*[A](t: TCountTable[A], key: A): int =
|
proc `[]`*[A](t: CountTable[A], key: A): int =
|
||||||
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
||||||
## 0 is returned. One can check with ``hasKey`` whether the key
|
## 0 is returned. One can check with ``hasKey`` whether the key
|
||||||
## exists.
|
## exists.
|
||||||
var index = rawGet(t, key)
|
var index = rawGet(t, key)
|
||||||
if index >= 0: result = t.data[index].val
|
if index >= 0: result = t.data[index].val
|
||||||
|
|
||||||
proc mget*[A](t: var TCountTable[A], key: A): var int =
|
proc mget*[A](t: var CountTable[A], key: A): var int =
|
||||||
## retrieves the value at ``t[key]``. The value can be modified.
|
## retrieves the value at ``t[key]``. The value can be modified.
|
||||||
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
||||||
var index = rawGet(t, key)
|
var index = rawGet(t, key)
|
||||||
if index >= 0: result = t.data[index].val
|
if index >= 0: result = t.data[index].val
|
||||||
else: raise newException(KeyError, "key not found: " & $key)
|
else: raise newException(KeyError, "key not found: " & $key)
|
||||||
|
|
||||||
proc hasKey*[A](t: TCountTable[A], key: A): bool =
|
proc hasKey*[A](t: CountTable[A], key: A): bool =
|
||||||
## returns true iff `key` is in the table `t`.
|
## returns true iff `key` is in the table `t`.
|
||||||
result = rawGet(t, key) >= 0
|
result = rawGet(t, key) >= 0
|
||||||
|
|
||||||
proc rawInsert[A](t: TCountTable[A], data: var seq[tuple[key: A, val: int]],
|
proc rawInsert[A](t: CountTable[A], data: var seq[tuple[key: A, val: int]],
|
||||||
key: A, val: int) =
|
key: A, val: int) =
|
||||||
var h: THash = hash(key) and high(data)
|
var h: THash = hash(key) and high(data)
|
||||||
while data[h].val != 0: h = nextTry(h, high(data))
|
while data[h].val != 0: h = nextTry(h, high(data))
|
||||||
data[h].key = key
|
data[h].key = key
|
||||||
data[h].val = val
|
data[h].val = val
|
||||||
|
|
||||||
proc enlarge[A](t: var TCountTable[A]) =
|
proc enlarge[A](t: var CountTable[A]) =
|
||||||
var n: seq[tuple[key: A, val: int]]
|
var n: seq[tuple[key: A, val: int]]
|
||||||
newSeq(n, len(t.data) * growthFactor)
|
newSeq(n, len(t.data) * growthFactor)
|
||||||
for i in countup(0, high(t.data)):
|
for i in countup(0, high(t.data)):
|
||||||
if t.data[i].val != 0: rawInsert(t, n, t.data[i].key, t.data[i].val)
|
if t.data[i].val != 0: rawInsert(t, n, t.data[i].key, t.data[i].val)
|
||||||
swap(t.data, n)
|
swap(t.data, n)
|
||||||
|
|
||||||
proc `[]=`*[A](t: var TCountTable[A], key: A, val: int) =
|
proc `[]=`*[A](t: var CountTable[A], key: A, val: int) =
|
||||||
## puts a (key, value)-pair into `t`. `val` has to be positive.
|
## puts a (key, value)-pair into `t`. `val` has to be positive.
|
||||||
assert val > 0
|
assert val > 0
|
||||||
putImpl()
|
putImpl()
|
||||||
|
|
||||||
proc initCountTable*[A](initialSize=64): TCountTable[A] =
|
proc initCountTable*[A](initialSize=64): CountTable[A] =
|
||||||
## creates a new count table that is empty.
|
## creates a new count table that is empty.
|
||||||
##
|
##
|
||||||
## `initialSize` needs to be a power of two. If you need to accept runtime
|
## `initialSize` needs to be a power of two. If you need to accept runtime
|
||||||
|
|
@ -704,16 +704,16 @@ proc initCountTable*[A](initialSize=64): TCountTable[A] =
|
||||||
result.counter = 0
|
result.counter = 0
|
||||||
newSeq(result.data, initialSize)
|
newSeq(result.data, initialSize)
|
||||||
|
|
||||||
proc toCountTable*[A](keys: openArray[A]): TCountTable[A] =
|
proc toCountTable*[A](keys: openArray[A]): CountTable[A] =
|
||||||
## creates a new count table with every key in `keys` having a count of 1.
|
## creates a new count table with every key in `keys` having a count of 1.
|
||||||
result = initCountTable[A](nextPowerOfTwo(keys.len+10))
|
result = initCountTable[A](nextPowerOfTwo(keys.len+10))
|
||||||
for key in items(keys): result[key] = 1
|
for key in items(keys): result[key] = 1
|
||||||
|
|
||||||
proc `$`*[A](t: TCountTable[A]): string =
|
proc `$`*[A](t: CountTable[A]): string =
|
||||||
## The `$` operator for count tables.
|
## The `$` operator for count tables.
|
||||||
dollarImpl()
|
dollarImpl()
|
||||||
|
|
||||||
proc inc*[A](t: var TCountTable[A], key: A, val = 1) =
|
proc inc*[A](t: var CountTable[A], key: A, val = 1) =
|
||||||
## increments `t[key]` by `val`.
|
## increments `t[key]` by `val`.
|
||||||
var index = rawGet(t, key)
|
var index = rawGet(t, key)
|
||||||
if index >= 0:
|
if index >= 0:
|
||||||
|
|
@ -723,7 +723,7 @@ proc inc*[A](t: var TCountTable[A], key: A, val = 1) =
|
||||||
rawInsert(t, t.data, key, val)
|
rawInsert(t, t.data, key, val)
|
||||||
inc(t.counter)
|
inc(t.counter)
|
||||||
|
|
||||||
proc smallest*[A](t: TCountTable[A]): tuple[key: A, val: int] =
|
proc smallest*[A](t: CountTable[A]): tuple[key: A, val: int] =
|
||||||
## returns the largest (key,val)-pair. Efficiency: O(n)
|
## returns the largest (key,val)-pair. Efficiency: O(n)
|
||||||
assert t.len > 0
|
assert t.len > 0
|
||||||
var minIdx = 0
|
var minIdx = 0
|
||||||
|
|
@ -732,7 +732,7 @@ proc smallest*[A](t: TCountTable[A]): tuple[key: A, val: int] =
|
||||||
result.key = t.data[minIdx].key
|
result.key = t.data[minIdx].key
|
||||||
result.val = t.data[minIdx].val
|
result.val = t.data[minIdx].val
|
||||||
|
|
||||||
proc largest*[A](t: TCountTable[A]): tuple[key: A, val: int] =
|
proc largest*[A](t: CountTable[A]): tuple[key: A, val: int] =
|
||||||
## returns the (key,val)-pair with the largest `val`. Efficiency: O(n)
|
## returns the (key,val)-pair with the largest `val`. Efficiency: O(n)
|
||||||
assert t.len > 0
|
assert t.len > 0
|
||||||
var maxIdx = 0
|
var maxIdx = 0
|
||||||
|
|
@ -741,7 +741,7 @@ proc largest*[A](t: TCountTable[A]): tuple[key: A, val: int] =
|
||||||
result.key = t.data[maxIdx].key
|
result.key = t.data[maxIdx].key
|
||||||
result.val = t.data[maxIdx].val
|
result.val = t.data[maxIdx].val
|
||||||
|
|
||||||
proc sort*[A](t: var TCountTable[A]) =
|
proc sort*[A](t: var CountTable[A]) =
|
||||||
## sorts the count table so that the entry with the highest counter comes
|
## sorts the count table so that the entry with the highest counter comes
|
||||||
## first. This is destructive! You must not modify `t` afterwards!
|
## first. This is destructive! You must not modify `t` afterwards!
|
||||||
## You can use the iterators `pairs`, `keys`, and `values` to iterate over
|
## You can use the iterators `pairs`, `keys`, and `values` to iterate over
|
||||||
|
|
@ -762,57 +762,57 @@ proc sort*[A](t: var TCountTable[A]) =
|
||||||
if j < h: break
|
if j < h: break
|
||||||
if h == 1: break
|
if h == 1: break
|
||||||
|
|
||||||
proc len*[A](t: PCountTable[A]): int =
|
proc len*[A](t: CountTableRef[A]): int =
|
||||||
## returns the number of keys in `t`.
|
## returns the number of keys in `t`.
|
||||||
result = t.counter
|
result = t.counter
|
||||||
|
|
||||||
iterator pairs*[A](t: PCountTable[A]): tuple[key: A, val: int] =
|
iterator pairs*[A](t: CountTableRef[A]): tuple[key: A, val: int] =
|
||||||
## iterates over any (key, value) pair in the table `t`.
|
## iterates over any (key, value) pair in the table `t`.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
|
if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
|
||||||
|
|
||||||
iterator mpairs*[A](t: PCountTable[A]): tuple[key: A, val: var int] =
|
iterator mpairs*[A](t: CountTableRef[A]): tuple[key: A, val: var int] =
|
||||||
## iterates over any (key, value) pair in the table `t`. The values can
|
## iterates over any (key, value) pair in the table `t`. The values can
|
||||||
## be modified.
|
## be modified.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
|
if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
|
||||||
|
|
||||||
iterator keys*[A](t: PCountTable[A]): A =
|
iterator keys*[A](t: CountTableRef[A]): A =
|
||||||
## iterates over any key in the table `t`.
|
## iterates over any key in the table `t`.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].val != 0: yield t.data[h].key
|
if t.data[h].val != 0: yield t.data[h].key
|
||||||
|
|
||||||
iterator values*[A](t: PCountTable[A]): int =
|
iterator values*[A](t: CountTableRef[A]): int =
|
||||||
## iterates over any value in the table `t`.
|
## iterates over any value in the table `t`.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].val != 0: yield t.data[h].val
|
if t.data[h].val != 0: yield t.data[h].val
|
||||||
|
|
||||||
iterator mvalues*[A](t: PCountTable[A]): var int =
|
iterator mvalues*[A](t: CountTableRef[A]): var int =
|
||||||
## iterates over any value in the table `t`. The values can be modified.
|
## iterates over any value in the table `t`. The values can be modified.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].val != 0: yield t.data[h].val
|
if t.data[h].val != 0: yield t.data[h].val
|
||||||
|
|
||||||
proc `[]`*[A](t: PCountTable[A], key: A): int =
|
proc `[]`*[A](t: CountTableRef[A], key: A): int =
|
||||||
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
||||||
## 0 is returned. One can check with ``hasKey`` whether the key
|
## 0 is returned. One can check with ``hasKey`` whether the key
|
||||||
## exists.
|
## exists.
|
||||||
result = t[][key]
|
result = t[][key]
|
||||||
|
|
||||||
proc mget*[A](t: PCountTable[A], key: A): var int =
|
proc mget*[A](t: CountTableRef[A], key: A): var int =
|
||||||
## retrieves the value at ``t[key]``. The value can be modified.
|
## retrieves the value at ``t[key]``. The value can be modified.
|
||||||
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
||||||
result = t[].mget(key)
|
result = t[].mget(key)
|
||||||
|
|
||||||
proc hasKey*[A](t: PCountTable[A], key: A): bool =
|
proc hasKey*[A](t: CountTableRef[A], key: A): bool =
|
||||||
## returns true iff `key` is in the table `t`.
|
## returns true iff `key` is in the table `t`.
|
||||||
result = t[].hasKey(key)
|
result = t[].hasKey(key)
|
||||||
|
|
||||||
proc `[]=`*[A](t: PCountTable[A], key: A, val: int) =
|
proc `[]=`*[A](t: CountTableRef[A], key: A, val: int) =
|
||||||
## puts a (key, value)-pair into `t`. `val` has to be positive.
|
## puts a (key, value)-pair into `t`. `val` has to be positive.
|
||||||
assert val > 0
|
assert val > 0
|
||||||
t[][key] = val
|
t[][key] = val
|
||||||
|
|
||||||
proc newCountTable*[A](initialSize=64): PCountTable[A] =
|
proc newCountTable*[A](initialSize=64): CountTableRef[A] =
|
||||||
## creates a new count table that is empty.
|
## creates a new count table that is empty.
|
||||||
##
|
##
|
||||||
## `initialSize` needs to be a power of two. If you need to accept runtime
|
## `initialSize` needs to be a power of two. If you need to accept runtime
|
||||||
|
|
@ -821,28 +821,28 @@ proc newCountTable*[A](initialSize=64): PCountTable[A] =
|
||||||
new(result)
|
new(result)
|
||||||
result[] = initCountTable[A](initialSize)
|
result[] = initCountTable[A](initialSize)
|
||||||
|
|
||||||
proc newCountTable*[A](keys: openArray[A]): PCountTable[A] =
|
proc newCountTable*[A](keys: openArray[A]): CountTableRef[A] =
|
||||||
## creates a new count table with every key in `keys` having a count of 1.
|
## creates a new count table with every key in `keys` having a count of 1.
|
||||||
result = newCountTable[A](nextPowerOfTwo(keys.len+10))
|
result = newCountTable[A](nextPowerOfTwo(keys.len+10))
|
||||||
for key in items(keys): result[key] = 1
|
for key in items(keys): result[key] = 1
|
||||||
|
|
||||||
proc `$`*[A](t: PCountTable[A]): string =
|
proc `$`*[A](t: CountTableRef[A]): string =
|
||||||
## The `$` operator for count tables.
|
## The `$` operator for count tables.
|
||||||
dollarImpl()
|
dollarImpl()
|
||||||
|
|
||||||
proc inc*[A](t: PCountTable[A], key: A, val = 1) =
|
proc inc*[A](t: CountTableRef[A], key: A, val = 1) =
|
||||||
## increments `t[key]` by `val`.
|
## increments `t[key]` by `val`.
|
||||||
t[].inc(key, val)
|
t[].inc(key, val)
|
||||||
|
|
||||||
proc smallest*[A](t: PCountTable[A]): tuple[key: A, val: int] =
|
proc smallest*[A](t: CountTableRef[A]): tuple[key: A, val: int] =
|
||||||
## returns the largest (key,val)-pair. Efficiency: O(n)
|
## returns the largest (key,val)-pair. Efficiency: O(n)
|
||||||
t[].smallest
|
t[].smallest
|
||||||
|
|
||||||
proc largest*[A](t: PCountTable[A]): tuple[key: A, val: int] =
|
proc largest*[A](t: CountTableRef[A]): tuple[key: A, val: int] =
|
||||||
## returns the (key,val)-pair with the largest `val`. Efficiency: O(n)
|
## returns the (key,val)-pair with the largest `val`. Efficiency: O(n)
|
||||||
t[].largest
|
t[].largest
|
||||||
|
|
||||||
proc sort*[A](t: PCountTable[A]) =
|
proc sort*[A](t: CountTableRef[A]) =
|
||||||
## sorts the count table so that the entry with the highest counter comes
|
## sorts the count table so that the entry with the highest counter comes
|
||||||
## first. This is destructive! You must not modify `t` afterwards!
|
## first. This is destructive! You must not modify `t` afterwards!
|
||||||
## You can use the iterators `pairs`, `keys`, and `values` to iterate over
|
## You can use the iterators `pairs`, `keys`, and `values` to iterate over
|
||||||
|
|
|
||||||
202
lib/pure/net.nim
202
lib/pure/net.nim
|
|
@ -94,11 +94,11 @@ proc toOSFlags*(socketFlags: set[SocketFlag]): cint =
|
||||||
## Converts the flags into the underlying OS representation.
|
## Converts the flags into the underlying OS representation.
|
||||||
for f in socketFlags:
|
for f in socketFlags:
|
||||||
case f
|
case f
|
||||||
of TSocketFlags.Peek:
|
of SocketFlag.Peek:
|
||||||
result = result or MSG_PEEK
|
result = result or MSG_PEEK
|
||||||
of TSocketFlags.SafeDisconn: continue
|
of SocketFlag.SafeDisconn: continue
|
||||||
|
|
||||||
proc createSocket(fd: TSocketHandle, isBuff: bool): PSocket =
|
proc createSocket(fd: TSocketHandle, isBuff: bool): Socket =
|
||||||
assert fd != osInvalidSocket
|
assert fd != osInvalidSocket
|
||||||
new(result)
|
new(result)
|
||||||
result.fd = fd
|
result.fd = fd
|
||||||
|
|
@ -106,14 +106,14 @@ proc createSocket(fd: TSocketHandle, isBuff: bool): PSocket =
|
||||||
if isBuff:
|
if isBuff:
|
||||||
result.currPos = 0
|
result.currPos = 0
|
||||||
|
|
||||||
proc newSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
|
proc newSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
|
||||||
protocol: TProtocol = IPPROTO_TCP, buffered = true): PSocket =
|
protocol: Protocol = IPPROTO_TCP, buffered = true): Socket =
|
||||||
## Creates a new socket.
|
## Creates a new socket.
|
||||||
##
|
##
|
||||||
## If an error occurs EOS will be raised.
|
## If an error occurs EOS will be raised.
|
||||||
let fd = newRawSocket(domain, typ, protocol)
|
let fd = newRawSocket(domain, typ, protocol)
|
||||||
if fd == osInvalidSocket:
|
if fd == osInvalidSocket:
|
||||||
osError(osLastError())
|
raiseOSError(osLastError())
|
||||||
result = createSocket(fd, buffered)
|
result = createSocket(fd, buffered)
|
||||||
|
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
|
|
@ -218,8 +218,8 @@ when defined(ssl):
|
||||||
if SSLSetFd(socket.sslHandle, socket.fd) != 1:
|
if SSLSetFd(socket.sslHandle, socket.fd) != 1:
|
||||||
SSLError()
|
SSLError()
|
||||||
|
|
||||||
proc socketError*(socket: PSocket, err: int = -1, async = false,
|
proc socketError*(socket: Socket, err: int = -1, async = false,
|
||||||
lastError = (-1).TOSErrorCode) =
|
lastError = (-1).OSErrorCode) =
|
||||||
## Raises an EOS error based on the error code returned by ``SSLGetError``
|
## Raises an EOS error based on the error code returned by ``SSLGetError``
|
||||||
## (for SSL sockets) and ``osLastError`` otherwise.
|
## (for SSL sockets) and ``osLastError`` otherwise.
|
||||||
##
|
##
|
||||||
|
|
@ -254,23 +254,23 @@ proc socketError*(socket: PSocket, err: int = -1, async = false,
|
||||||
when useWinVersion:
|
when useWinVersion:
|
||||||
if lastE.int32 == WSAEWOULDBLOCK:
|
if lastE.int32 == WSAEWOULDBLOCK:
|
||||||
return
|
return
|
||||||
else: osError(lastE)
|
else: raiseOSError(lastE)
|
||||||
else:
|
else:
|
||||||
if lastE.int32 == EAGAIN or lastE.int32 == EWOULDBLOCK:
|
if lastE.int32 == EAGAIN or lastE.int32 == EWOULDBLOCK:
|
||||||
return
|
return
|
||||||
else: osError(lastE)
|
else: osError(lastE)
|
||||||
else: osError(lastE)
|
else: raiseOSError(lastE)
|
||||||
|
|
||||||
proc listen*(socket: PSocket, backlog = SOMAXCONN) {.tags: [FReadIO].} =
|
proc listen*(socket: Socket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} =
|
||||||
## Marks ``socket`` as accepting connections.
|
## Marks ``socket`` as accepting connections.
|
||||||
## ``Backlog`` specifies the maximum length of the
|
## ``Backlog`` specifies the maximum length of the
|
||||||
## queue of pending connections.
|
## queue of pending connections.
|
||||||
##
|
##
|
||||||
## Raises an EOS error upon failure.
|
## Raises an EOS error upon failure.
|
||||||
if listen(socket.fd, backlog) < 0'i32: osError(osLastError())
|
if listen(socket.fd, backlog) < 0'i32: raiseOSError(osLastError())
|
||||||
|
|
||||||
proc bindAddr*(socket: PSocket, port = TPort(0), address = "") {.
|
proc bindAddr*(socket: Socket, port = Port(0), address = "") {.
|
||||||
tags: [FReadIO].} =
|
tags: [ReadIOEffect].} =
|
||||||
## Binds ``address``:``port`` to the socket.
|
## Binds ``address``:``port`` to the socket.
|
||||||
##
|
##
|
||||||
## If ``address`` is "" then ADDR_ANY will be bound.
|
## If ``address`` is "" then ADDR_ANY will be bound.
|
||||||
|
|
@ -285,16 +285,16 @@ proc bindAddr*(socket: PSocket, port = TPort(0), address = "") {.
|
||||||
name.sin_addr.s_addr = htonl(INADDR_ANY)
|
name.sin_addr.s_addr = htonl(INADDR_ANY)
|
||||||
if bindAddr(socket.fd, cast[ptr TSockAddr](addr(name)),
|
if bindAddr(socket.fd, cast[ptr TSockAddr](addr(name)),
|
||||||
sizeof(name).TSocklen) < 0'i32:
|
sizeof(name).TSocklen) < 0'i32:
|
||||||
osError(osLastError())
|
raiseOSError(osLastError())
|
||||||
else:
|
else:
|
||||||
var aiList = getAddrInfo(address, port, AF_INET)
|
var aiList = getAddrInfo(address, port, AF_INET)
|
||||||
if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.TSocklen) < 0'i32:
|
if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.TSocklen) < 0'i32:
|
||||||
dealloc(aiList)
|
dealloc(aiList)
|
||||||
osError(osLastError())
|
raiseOSError(osLastError())
|
||||||
dealloc(aiList)
|
dealloc(aiList)
|
||||||
|
|
||||||
proc acceptAddr*(server: PSocket, client: var PSocket, address: var string,
|
proc acceptAddr*(server: Socket, client: var Socket, address: var string,
|
||||||
flags = {TSocketFlags.SafeDisconn}) {.tags: [FReadIO].} =
|
flags = {SocketFlag.SafeDisconn}) {.tags: [ReadIOEffect].} =
|
||||||
## Blocks until a connection is being made from a client. When a connection
|
## Blocks until a connection is being made from a client. When a connection
|
||||||
## is made sets ``client`` to the client socket and ``address`` to the address
|
## is made sets ``client`` to the client socket and ``address`` to the address
|
||||||
## of the connecting client.
|
## of the connecting client.
|
||||||
|
|
@ -311,7 +311,7 @@ proc acceptAddr*(server: PSocket, client: var PSocket, address: var string,
|
||||||
## flag is specified then this error will not be raised and instead
|
## flag is specified then this error will not be raised and instead
|
||||||
## accept will be called again.
|
## accept will be called again.
|
||||||
assert(client != nil)
|
assert(client != nil)
|
||||||
var sockAddress: Tsockaddr_in
|
var sockAddress: TSockaddr_in
|
||||||
var addrLen = sizeof(sockAddress).TSocklen
|
var addrLen = sizeof(sockAddress).TSocklen
|
||||||
var sock = accept(server.fd, cast[ptr TSockAddr](addr(sockAddress)),
|
var sock = accept(server.fd, cast[ptr TSockAddr](addr(sockAddress)),
|
||||||
addr(addrLen))
|
addr(addrLen))
|
||||||
|
|
@ -320,7 +320,7 @@ proc acceptAddr*(server: PSocket, client: var PSocket, address: var string,
|
||||||
let err = osLastError()
|
let err = osLastError()
|
||||||
if flags.isDisconnectionError(err):
|
if flags.isDisconnectionError(err):
|
||||||
acceptAddr(server, client, address, flags)
|
acceptAddr(server, client, address, flags)
|
||||||
osError(err)
|
raiseOSError(err)
|
||||||
else:
|
else:
|
||||||
client.fd = sock
|
client.fd = sock
|
||||||
client.isBuffered = server.isBuffered
|
client.isBuffered = server.isBuffered
|
||||||
|
|
@ -389,8 +389,8 @@ when false: #defined(ssl):
|
||||||
acceptAddrPlain(AcceptNoClient, AcceptSuccess):
|
acceptAddrPlain(AcceptNoClient, AcceptSuccess):
|
||||||
doHandshake()
|
doHandshake()
|
||||||
|
|
||||||
proc accept*(server: PSocket, client: var PSocket,
|
proc accept*(server: Socket, client: var Socket,
|
||||||
flags = {TSocketFlags.SafeDisconn}) {.tags: [FReadIO].} =
|
flags = {SocketFlag.SafeDisconn}) {.tags: [ReadIOEffect].} =
|
||||||
## Equivalent to ``acceptAddr`` but doesn't return the address, only the
|
## Equivalent to ``acceptAddr`` but doesn't return the address, only the
|
||||||
## socket.
|
## socket.
|
||||||
##
|
##
|
||||||
|
|
@ -404,7 +404,7 @@ proc accept*(server: PSocket, client: var PSocket,
|
||||||
var addrDummy = ""
|
var addrDummy = ""
|
||||||
acceptAddr(server, client, addrDummy, flags)
|
acceptAddr(server, client, addrDummy, flags)
|
||||||
|
|
||||||
proc close*(socket: PSocket) =
|
proc close*(socket: Socket) =
|
||||||
## Closes a socket.
|
## Closes a socket.
|
||||||
socket.fd.close()
|
socket.fd.close()
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
|
|
@ -416,7 +416,7 @@ proc close*(socket: PSocket) =
|
||||||
elif res != 1:
|
elif res != 1:
|
||||||
socketError(socket)
|
socketError(socket)
|
||||||
|
|
||||||
proc toCInt(opt: TSOBool): cint =
|
proc toCInt(opt: SOBool): cint =
|
||||||
case opt
|
case opt
|
||||||
of OptAcceptConn: SO_ACCEPTCONN
|
of OptAcceptConn: SO_ACCEPTCONN
|
||||||
of OptBroadcast: SO_BROADCAST
|
of OptBroadcast: SO_BROADCAST
|
||||||
|
|
@ -426,20 +426,20 @@ proc toCInt(opt: TSOBool): cint =
|
||||||
of OptOOBInline: SO_OOBINLINE
|
of OptOOBInline: SO_OOBINLINE
|
||||||
of OptReuseAddr: SO_REUSEADDR
|
of OptReuseAddr: SO_REUSEADDR
|
||||||
|
|
||||||
proc getSockOpt*(socket: PSocket, opt: TSOBool, level = SOL_SOCKET): bool {.
|
proc getSockOpt*(socket: Socket, opt: SOBool, level = SOL_SOCKET): bool {.
|
||||||
tags: [FReadIO].} =
|
tags: [ReadIOEffect].} =
|
||||||
## Retrieves option ``opt`` as a boolean value.
|
## Retrieves option ``opt`` as a boolean value.
|
||||||
var res = getsockoptint(socket.fd, cint(level), toCInt(opt))
|
var res = getSockOptInt(socket.fd, cint(level), toCInt(opt))
|
||||||
result = res != 0
|
result = res != 0
|
||||||
|
|
||||||
proc setSockOpt*(socket: PSocket, opt: TSOBool, value: bool, level = SOL_SOCKET) {.
|
proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) {.
|
||||||
tags: [FWriteIO].} =
|
tags: [WriteIOEffect].} =
|
||||||
## Sets option ``opt`` to a boolean value specified by ``value``.
|
## Sets option ``opt`` to a boolean value specified by ``value``.
|
||||||
var valuei = cint(if value: 1 else: 0)
|
var valuei = cint(if value: 1 else: 0)
|
||||||
setsockoptint(socket.fd, cint(level), toCInt(opt), valuei)
|
setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei)
|
||||||
|
|
||||||
proc connect*(socket: PSocket, address: string, port = TPort(0),
|
proc connect*(socket: Socket, address: string, port = Port(0),
|
||||||
af: TDomain = AF_INET) {.tags: [FReadIO].} =
|
af: Domain = AF_INET) {.tags: [ReadIOEffect].} =
|
||||||
## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a
|
## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a
|
||||||
## host name. If ``address`` is a host name, this function will try each IP
|
## host name. If ``address`` is a host name, this function will try each IP
|
||||||
## of that host name. ``htons`` is already performed on ``port`` so you must
|
## of that host name. ``htons`` is already performed on ``port`` so you must
|
||||||
|
|
@ -449,7 +449,7 @@ proc connect*(socket: PSocket, address: string, port = TPort(0),
|
||||||
var aiList = getAddrInfo(address, port, af)
|
var aiList = getAddrInfo(address, port, af)
|
||||||
# try all possibilities:
|
# try all possibilities:
|
||||||
var success = false
|
var success = false
|
||||||
var lastError: TOSErrorCode
|
var lastError: OSErrorCode
|
||||||
var it = aiList
|
var it = aiList
|
||||||
while it != nil:
|
while it != nil:
|
||||||
if connect(socket.fd, it.ai_addr, it.ai_addrlen.TSocklen) == 0'i32:
|
if connect(socket.fd, it.ai_addr, it.ai_addrlen.TSocklen) == 0'i32:
|
||||||
|
|
@ -459,7 +459,7 @@ proc connect*(socket: PSocket, address: string, port = TPort(0),
|
||||||
it = it.ai_next
|
it = it.ai_next
|
||||||
|
|
||||||
dealloc(aiList)
|
dealloc(aiList)
|
||||||
if not success: osError(lastError)
|
if not success: raiseOSError(lastError)
|
||||||
|
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
|
|
@ -507,7 +507,7 @@ when defined(ssl):
|
||||||
else:
|
else:
|
||||||
SSLError("Socket is not an SSL socket.")
|
SSLError("Socket is not an SSL socket.")
|
||||||
|
|
||||||
proc hasDataBuffered*(s: PSocket): bool =
|
proc hasDataBuffered*(s: Socket): bool =
|
||||||
## Determines whether a socket has data buffered.
|
## Determines whether a socket has data buffered.
|
||||||
result = false
|
result = false
|
||||||
if s.isBuffered:
|
if s.isBuffered:
|
||||||
|
|
@ -517,15 +517,15 @@ proc hasDataBuffered*(s: PSocket): bool =
|
||||||
if s.isSSL and not result:
|
if s.isSSL and not result:
|
||||||
result = s.sslHasPeekChar
|
result = s.sslHasPeekChar
|
||||||
|
|
||||||
proc select(readfd: PSocket, timeout = 500): int =
|
proc select(readfd: Socket, timeout = 500): int =
|
||||||
## Used for socket operation timeouts.
|
## Used for socket operation timeouts.
|
||||||
if readfd.hasDataBuffered:
|
if readfd.hasDataBuffered:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
var fds = @[readFd.fd]
|
var fds = @[readfd.fd]
|
||||||
result = select(fds, timeout)
|
result = select(fds, timeout)
|
||||||
|
|
||||||
proc readIntoBuf(socket: PSocket, flags: int32): int =
|
proc readIntoBuf(socket: Socket, flags: int32): int =
|
||||||
result = 0
|
result = 0
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
|
|
@ -549,7 +549,7 @@ template retRead(flags, readBytes: int) {.dirty.} =
|
||||||
else:
|
else:
|
||||||
return res
|
return res
|
||||||
|
|
||||||
proc recv*(socket: PSocket, data: pointer, size: int): int {.tags: [FReadIO].} =
|
proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ReadIOEffect].} =
|
||||||
## Receives data from a socket.
|
## Receives data from a socket.
|
||||||
##
|
##
|
||||||
## **Note**: This is a low-level function, you may be interested in the higher
|
## **Note**: This is a low-level function, you may be interested in the higher
|
||||||
|
|
@ -590,8 +590,8 @@ proc recv*(socket: PSocket, data: pointer, size: int): int {.tags: [FReadIO].} =
|
||||||
else:
|
else:
|
||||||
result = recv(socket.fd, data, size.cint, 0'i32)
|
result = recv(socket.fd, data, size.cint, 0'i32)
|
||||||
|
|
||||||
proc waitFor(socket: PSocket, waited: var float, timeout, size: int,
|
proc waitFor(socket: Socket, waited: var float, timeout, size: int,
|
||||||
funcName: string): int {.tags: [FTime].} =
|
funcName: string): int {.tags: [TimeEffect].} =
|
||||||
## determines the amount of characters that can be read. Result will never
|
## determines the amount of characters that can be read. Result will never
|
||||||
## be larger than ``size``. For unbuffered sockets this will be ``1``.
|
## be larger than ``size``. For unbuffered sockets this will be ``1``.
|
||||||
## For buffered sockets it can be as big as ``BufferSize``.
|
## For buffered sockets it can be as big as ``BufferSize``.
|
||||||
|
|
@ -606,7 +606,7 @@ proc waitFor(socket: PSocket, waited: var float, timeout, size: int,
|
||||||
result = min(result, size)
|
result = min(result, size)
|
||||||
else:
|
else:
|
||||||
if timeout - int(waited * 1000.0) < 1:
|
if timeout - int(waited * 1000.0) < 1:
|
||||||
raise newException(ETimeout, "Call to '" & funcName & "' timed out.")
|
raise newException(TimeoutError, "Call to '" & funcName & "' timed out.")
|
||||||
|
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
|
|
@ -619,13 +619,13 @@ proc waitFor(socket: PSocket, waited: var float, timeout, size: int,
|
||||||
|
|
||||||
var startTime = epochTime()
|
var startTime = epochTime()
|
||||||
let selRet = select(socket, timeout - int(waited * 1000.0))
|
let selRet = select(socket, timeout - int(waited * 1000.0))
|
||||||
if selRet < 0: osError(osLastError())
|
if selRet < 0: raiseOSError(osLastError())
|
||||||
if selRet != 1:
|
if selRet != 1:
|
||||||
raise newException(ETimeout, "Call to '" & funcName & "' timed out.")
|
raise newException(TimeoutError, "Call to '" & funcName & "' timed out.")
|
||||||
waited += (epochTime() - startTime)
|
waited += (epochTime() - startTime)
|
||||||
|
|
||||||
proc recv*(socket: PSocket, data: pointer, size: int, timeout: int): int {.
|
proc recv*(socket: Socket, data: pointer, size: int, timeout: int): int {.
|
||||||
tags: [FReadIO, FTime].} =
|
tags: [ReadIOEffect, FTime].} =
|
||||||
## overload with a ``timeout`` parameter in miliseconds.
|
## overload with a ``timeout`` parameter in miliseconds.
|
||||||
var waited = 0.0 # number of seconds already waited
|
var waited = 0.0 # number of seconds already waited
|
||||||
|
|
||||||
|
|
@ -642,8 +642,8 @@ proc recv*(socket: PSocket, data: pointer, size: int, timeout: int): int {.
|
||||||
|
|
||||||
result = read
|
result = read
|
||||||
|
|
||||||
proc recv*(socket: PSocket, data: var string, size: int, timeout = -1,
|
proc recv*(socket: Socket, data: var string, size: int, timeout = -1,
|
||||||
flags = {TSocketFlags.SafeDisconn}): int =
|
flags = {SocketFlag.SafeDisconn}): int =
|
||||||
## Higher-level version of ``recv``.
|
## Higher-level version of ``recv``.
|
||||||
##
|
##
|
||||||
## When 0 is returned the socket's connection has been closed.
|
## When 0 is returned the socket's connection has been closed.
|
||||||
|
|
@ -666,7 +666,7 @@ proc recv*(socket: PSocket, data: var string, size: int, timeout = -1,
|
||||||
socket.socketError(result, lastError = lastError)
|
socket.socketError(result, lastError = lastError)
|
||||||
data.setLen(result)
|
data.setLen(result)
|
||||||
|
|
||||||
proc peekChar(socket: PSocket, c: var char): int {.tags: [FReadIO].} =
|
proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} =
|
||||||
if socket.isBuffered:
|
if socket.isBuffered:
|
||||||
result = 1
|
result = 1
|
||||||
if socket.bufLen == 0 or socket.currPos > socket.bufLen-1:
|
if socket.bufLen == 0 or socket.currPos > socket.bufLen-1:
|
||||||
|
|
@ -686,9 +686,9 @@ proc peekChar(socket: PSocket, c: var char): int {.tags: [FReadIO].} =
|
||||||
return
|
return
|
||||||
result = recv(socket.fd, addr(c), 1, MSG_PEEK)
|
result = recv(socket.fd, addr(c), 1, MSG_PEEK)
|
||||||
|
|
||||||
proc readLine*(socket: PSocket, line: var TaintedString, timeout = -1,
|
proc readLine*(socket: Socket, line: var TaintedString, timeout = -1,
|
||||||
flags = {TSocketFlags.SafeDisconn}) {.
|
flags = {SocketFlag.SafeDisconn}) {.
|
||||||
tags: [FReadIO, FTime].} =
|
tags: [ReadIOEffect, FTime].} =
|
||||||
## Reads a line of data from ``socket``.
|
## Reads a line of data from ``socket``.
|
||||||
##
|
##
|
||||||
## If a full line is read ``\r\L`` is not
|
## If a full line is read ``\r\L`` is not
|
||||||
|
|
@ -735,9 +735,9 @@ proc readLine*(socket: PSocket, line: var TaintedString, timeout = -1,
|
||||||
return
|
return
|
||||||
add(line.string, c)
|
add(line.string, c)
|
||||||
|
|
||||||
proc recvFrom*(socket: PSocket, data: var string, length: int,
|
proc recvFrom*(socket: Socket, data: var string, length: int,
|
||||||
address: var string, port: var TPort, flags = 0'i32): int {.
|
address: var string, port: var Port, flags = 0'i32): int {.
|
||||||
tags: [FReadIO].} =
|
tags: [ReadIOEffect].} =
|
||||||
## Receives data from ``socket``. This function should normally be used with
|
## Receives data from ``socket``. This function should normally be used with
|
||||||
## connection-less sockets (UDP sockets).
|
## connection-less sockets (UDP sockets).
|
||||||
##
|
##
|
||||||
|
|
@ -751,7 +751,7 @@ proc recvFrom*(socket: PSocket, data: var string, length: int,
|
||||||
|
|
||||||
# TODO: Buffered sockets
|
# TODO: Buffered sockets
|
||||||
data.setLen(length)
|
data.setLen(length)
|
||||||
var sockAddress: Tsockaddr_in
|
var sockAddress: TSockaddr_in
|
||||||
var addrLen = sizeof(sockAddress).TSocklen
|
var addrLen = sizeof(sockAddress).TSocklen
|
||||||
result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint,
|
result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint,
|
||||||
cast[ptr TSockAddr](addr(sockAddress)), addr(addrLen))
|
cast[ptr TSockAddr](addr(sockAddress)), addr(addrLen))
|
||||||
|
|
@ -759,11 +759,11 @@ proc recvFrom*(socket: PSocket, data: var string, length: int,
|
||||||
if result != -1:
|
if result != -1:
|
||||||
data.setLen(result)
|
data.setLen(result)
|
||||||
address = $inet_ntoa(sockAddress.sin_addr)
|
address = $inet_ntoa(sockAddress.sin_addr)
|
||||||
port = ntohs(sockAddress.sin_port).TPort
|
port = ntohs(sockAddress.sin_port).Port
|
||||||
else:
|
else:
|
||||||
osError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
|
||||||
proc skip*(socket: PSocket, size: int, timeout = -1) =
|
proc skip*(socket: Socket, size: int, timeout = -1) =
|
||||||
## Skips ``size`` amount of bytes.
|
## Skips ``size`` amount of bytes.
|
||||||
##
|
##
|
||||||
## An optional timeout can be specified in miliseconds, if skipping the
|
## An optional timeout can be specified in miliseconds, if skipping the
|
||||||
|
|
@ -778,8 +778,8 @@ proc skip*(socket: PSocket, size: int, timeout = -1) =
|
||||||
bytesSkipped += recv(socket, dummy, avail)
|
bytesSkipped += recv(socket, dummy, avail)
|
||||||
dealloc(dummy)
|
dealloc(dummy)
|
||||||
|
|
||||||
proc send*(socket: PSocket, data: pointer, size: int): int {.
|
proc send*(socket: Socket, data: pointer, size: int): int {.
|
||||||
tags: [FWriteIO].} =
|
tags: [WriteIOEffect].} =
|
||||||
## Sends data to a socket.
|
## Sends data to a socket.
|
||||||
##
|
##
|
||||||
## **Note**: This is a low-level version of ``send``. You likely should use
|
## **Note**: This is a low-level version of ``send``. You likely should use
|
||||||
|
|
@ -795,8 +795,8 @@ proc send*(socket: PSocket, data: pointer, size: int): int {.
|
||||||
const MSG_NOSIGNAL = 0
|
const MSG_NOSIGNAL = 0
|
||||||
result = send(socket.fd, data, size, int32(MSG_NOSIGNAL))
|
result = send(socket.fd, data, size, int32(MSG_NOSIGNAL))
|
||||||
|
|
||||||
proc send*(socket: PSocket, data: string,
|
proc send*(socket: Socket, data: string,
|
||||||
flags = {TSocketFlags.SafeDisconn}) {.tags: [FWriteIO].} =
|
flags = {SocketFlag.SafeDisconn}) {.tags: [WriteIOEffect].} =
|
||||||
## sends data to a socket.
|
## sends data to a socket.
|
||||||
let sent = send(socket, cstring(data), data.len)
|
let sent = send(socket, cstring(data), data.len)
|
||||||
if sent < 0:
|
if sent < 0:
|
||||||
|
|
@ -805,16 +805,16 @@ proc send*(socket: PSocket, data: string,
|
||||||
socketError(socket, lastError = lastError)
|
socketError(socket, lastError = lastError)
|
||||||
|
|
||||||
if sent != data.len:
|
if sent != data.len:
|
||||||
raise newException(EOS, "Could not send all data.")
|
raise newException(OSError, "Could not send all data.")
|
||||||
|
|
||||||
proc trySend*(socket: PSocket, data: string): bool {.tags: [FWriteIO].} =
|
proc trySend*(socket: Socket, data: string): bool {.tags: [WriteIOEffect].} =
|
||||||
## Safe alternative to ``send``. Does not raise an EOS when an error occurs,
|
## Safe alternative to ``send``. Does not raise an EOS when an error occurs,
|
||||||
## and instead returns ``false`` on failure.
|
## and instead returns ``false`` on failure.
|
||||||
result = send(socket, cstring(data), data.len) == data.len
|
result = send(socket, cstring(data), data.len) == data.len
|
||||||
|
|
||||||
proc sendTo*(socket: PSocket, address: string, port: TPort, data: pointer,
|
proc sendTo*(socket: Socket, address: string, port: Port, data: pointer,
|
||||||
size: int, af: TDomain = AF_INET, flags = 0'i32): int {.
|
size: int, af: Domain = AF_INET, flags = 0'i32): int {.
|
||||||
tags: [FWriteIO].} =
|
tags: [WriteIOEffect].} =
|
||||||
## This proc sends ``data`` to the specified ``address``,
|
## This proc sends ``data`` to the specified ``address``,
|
||||||
## which may be an IP address or a hostname, if a hostname is specified
|
## which may be an IP address or a hostname, if a hostname is specified
|
||||||
## this function will try each IP of that hostname.
|
## this function will try each IP of that hostname.
|
||||||
|
|
@ -839,8 +839,8 @@ proc sendTo*(socket: PSocket, address: string, port: TPort, data: pointer,
|
||||||
|
|
||||||
dealloc(aiList)
|
dealloc(aiList)
|
||||||
|
|
||||||
proc sendTo*(socket: PSocket, address: string, port: TPort,
|
proc sendTo*(socket: Socket, address: string, port: Port,
|
||||||
data: string): int {.tags: [FWriteIO].} =
|
data: string): int {.tags: [WriteIOEffect].} =
|
||||||
## This proc sends ``data`` to the specified ``address``,
|
## This proc sends ``data`` to the specified ``address``,
|
||||||
## which may be an IP address or a hostname, if a hostname is specified
|
## which may be an IP address or a hostname, if a hostname is specified
|
||||||
## this function will try each IP of that hostname.
|
## this function will try each IP of that hostname.
|
||||||
|
|
@ -848,8 +848,8 @@ proc sendTo*(socket: PSocket, address: string, port: TPort,
|
||||||
## This is the high-level version of the above ``sendTo`` function.
|
## This is the high-level version of the above ``sendTo`` function.
|
||||||
result = socket.sendTo(address, port, cstring(data), data.len)
|
result = socket.sendTo(address, port, cstring(data), data.len)
|
||||||
|
|
||||||
proc connectAsync(socket: PSocket, name: string, port = TPort(0),
|
proc connectAsync(socket: Socket, name: string, port = Port(0),
|
||||||
af: TDomain = AF_INET) {.tags: [FReadIO].} =
|
af: Domain = AF_INET) {.tags: [ReadIOEffect].} =
|
||||||
## A variant of ``connect`` for non-blocking sockets.
|
## A variant of ``connect`` for non-blocking sockets.
|
||||||
##
|
##
|
||||||
## This procedure will immediatelly return, it will not block until a connection
|
## This procedure will immediatelly return, it will not block until a connection
|
||||||
|
|
@ -861,7 +861,7 @@ proc connectAsync(socket: PSocket, name: string, port = TPort(0),
|
||||||
var aiList = getAddrInfo(name, port, af)
|
var aiList = getAddrInfo(name, port, af)
|
||||||
# try all possibilities:
|
# try all possibilities:
|
||||||
var success = false
|
var success = false
|
||||||
var lastError: TOSErrorCode
|
var lastError: OSErrorCode
|
||||||
var it = aiList
|
var it = aiList
|
||||||
while it != nil:
|
while it != nil:
|
||||||
var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.TSocklen)
|
var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.TSocklen)
|
||||||
|
|
@ -883,10 +883,10 @@ proc connectAsync(socket: PSocket, name: string, port = TPort(0),
|
||||||
it = it.ai_next
|
it = it.ai_next
|
||||||
|
|
||||||
dealloc(aiList)
|
dealloc(aiList)
|
||||||
if not success: osError(lastError)
|
if not success: raiseOSError(lastError)
|
||||||
|
|
||||||
proc connect*(socket: PSocket, address: string, port = TPort(0), timeout: int,
|
proc connect*(socket: Socket, address: string, port = Port(0), timeout: int,
|
||||||
af: TDomain = AF_INET) {.tags: [FReadIO, FWriteIO].} =
|
af: Domain = AF_INET) {.tags: [ReadIOEffect, FWriteIO].} =
|
||||||
## Connects to server as specified by ``address`` on port specified by ``port``.
|
## Connects to server as specified by ``address`` on port specified by ``port``.
|
||||||
##
|
##
|
||||||
## The ``timeout`` paremeter specifies the time in miliseconds to allow for
|
## The ``timeout`` paremeter specifies the time in miliseconds to allow for
|
||||||
|
|
@ -896,7 +896,7 @@ proc connect*(socket: PSocket, address: string, port = TPort(0), timeout: int,
|
||||||
socket.connectAsync(address, port, af)
|
socket.connectAsync(address, port, af)
|
||||||
var s = @[socket.fd]
|
var s = @[socket.fd]
|
||||||
if selectWrite(s, timeout) != 1:
|
if selectWrite(s, timeout) != 1:
|
||||||
raise newException(ETimeout, "Call to 'connect' timed out.")
|
raise newException(TimeoutError, "Call to 'connect' timed out.")
|
||||||
else:
|
else:
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
|
|
@ -904,10 +904,10 @@ proc connect*(socket: PSocket, address: string, port = TPort(0), timeout: int,
|
||||||
doAssert socket.handshake()
|
doAssert socket.handshake()
|
||||||
socket.fd.setBlocking(true)
|
socket.fd.setBlocking(true)
|
||||||
|
|
||||||
proc isSSL*(socket: PSocket): bool = return socket.isSSL
|
proc isSSL*(socket: Socket): bool = return socket.isSSL
|
||||||
## Determines whether ``socket`` is a SSL socket.
|
## Determines whether ``socket`` is a SSL socket.
|
||||||
|
|
||||||
proc getFD*(socket: PSocket): TSocketHandle = return socket.fd
|
proc getFD*(socket: Socket): TSocketHandle = return socket.fd
|
||||||
## Returns the socket's file descriptor
|
## Returns the socket's file descriptor
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -1042,23 +1042,23 @@ proc parseIPv4Address(address_str: string): TIpAddress =
|
||||||
currentByte = currentByte * 10 +
|
currentByte = currentByte * 10 +
|
||||||
cast[uint16](ord(address_str[i]) - ord('0'))
|
cast[uint16](ord(address_str[i]) - ord('0'))
|
||||||
if currentByte > 255'u16:
|
if currentByte > 255'u16:
|
||||||
raise newException(EInvalidValue,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. Value is out of range")
|
"Invalid IP Address. Value is out of range")
|
||||||
seperatorValid = true
|
seperatorValid = true
|
||||||
elif address_str[i] == '.': # IPv4 address separator
|
elif address_str[i] == '.': # IPv4 address separator
|
||||||
if not seperatorValid or byteCount >= 3:
|
if not seperatorValid or byteCount >= 3:
|
||||||
raise newException(EInvalidValue,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. The address consists of too many groups")
|
"Invalid IP Address. The address consists of too many groups")
|
||||||
result.address_v4[byteCount] = cast[uint8](currentByte)
|
result.address_v4[byteCount] = cast[uint8](currentByte)
|
||||||
currentByte = 0
|
currentByte = 0
|
||||||
byteCount.inc
|
byteCount.inc
|
||||||
seperatorValid = false
|
seperatorValid = false
|
||||||
else:
|
else:
|
||||||
raise newException(EInvalidValue,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. Address contains an invalid character")
|
"Invalid IP Address. Address contains an invalid character")
|
||||||
|
|
||||||
if byteCount != 3 or not seperatorValid:
|
if byteCount != 3 or not seperatorValid:
|
||||||
raise newException(EInvalidValue, "Invalid IP Address")
|
raise newException(ValueError, "Invalid IP Address")
|
||||||
result.address_v4[byteCount] = cast[uint8](currentByte)
|
result.address_v4[byteCount] = cast[uint8](currentByte)
|
||||||
|
|
||||||
proc parseIPv6Address(address_str: string): TIpAddress =
|
proc parseIPv6Address(address_str: string): TIpAddress =
|
||||||
|
|
@ -1066,7 +1066,7 @@ proc parseIPv6Address(address_str: string): TIpAddress =
|
||||||
## Raises EInvalidValue on errors
|
## Raises EInvalidValue on errors
|
||||||
result.family = IpAddressFamily.IPv6
|
result.family = IpAddressFamily.IPv6
|
||||||
if address_str.len < 2:
|
if address_str.len < 2:
|
||||||
raise newException(EInvalidValue, "Invalid IP Address")
|
raise newException(ValueError, "Invalid IP Address")
|
||||||
|
|
||||||
var
|
var
|
||||||
groupCount = 0
|
groupCount = 0
|
||||||
|
|
@ -1081,17 +1081,17 @@ proc parseIPv6Address(address_str: string): TIpAddress =
|
||||||
for i,c in address_str:
|
for i,c in address_str:
|
||||||
if c == ':':
|
if c == ':':
|
||||||
if not seperatorValid:
|
if not seperatorValid:
|
||||||
raise newException(EInvalidValue,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. Address contains an invalid seperator")
|
"Invalid IP Address. Address contains an invalid seperator")
|
||||||
if lastWasColon:
|
if lastWasColon:
|
||||||
if dualColonGroup != -1:
|
if dualColonGroup != -1:
|
||||||
raise newException(EInvalidValue,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. Address contains more than one \"::\" seperator")
|
"Invalid IP Address. Address contains more than one \"::\" seperator")
|
||||||
dualColonGroup = groupCount
|
dualColonGroup = groupCount
|
||||||
seperatorValid = false
|
seperatorValid = false
|
||||||
elif i != 0 and i != high(address_str):
|
elif i != 0 and i != high(address_str):
|
||||||
if groupCount >= 8:
|
if groupCount >= 8:
|
||||||
raise newException(EInvalidValue,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. The address consists of too many groups")
|
"Invalid IP Address. The address consists of too many groups")
|
||||||
result.address_v6[groupCount*2] = cast[uint8](currentShort shr 8)
|
result.address_v6[groupCount*2] = cast[uint8](currentShort shr 8)
|
||||||
result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF)
|
result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF)
|
||||||
|
|
@ -1100,17 +1100,17 @@ proc parseIPv6Address(address_str: string): TIpAddress =
|
||||||
if dualColonGroup != -1: seperatorValid = false
|
if dualColonGroup != -1: seperatorValid = false
|
||||||
elif i == 0: # only valid if address starts with ::
|
elif i == 0: # only valid if address starts with ::
|
||||||
if address_str[1] != ':':
|
if address_str[1] != ':':
|
||||||
raise newException(EInvalidValue,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. Address may not start with \":\"")
|
"Invalid IP Address. Address may not start with \":\"")
|
||||||
else: # i == high(address_str) - only valid if address ends with ::
|
else: # i == high(address_str) - only valid if address ends with ::
|
||||||
if address_str[high(address_str)-1] != ':':
|
if address_str[high(address_str)-1] != ':':
|
||||||
raise newException(EInvalidValue,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. Address may not end with \":\"")
|
"Invalid IP Address. Address may not end with \":\"")
|
||||||
lastWasColon = true
|
lastWasColon = true
|
||||||
currentGroupStart = i + 1
|
currentGroupStart = i + 1
|
||||||
elif c == '.': # Switch to parse IPv4 mode
|
elif c == '.': # Switch to parse IPv4 mode
|
||||||
if i < 3 or not seperatorValid or groupCount >= 7:
|
if i < 3 or not seperatorValid or groupCount >= 7:
|
||||||
raise newException(EInvalidValue, "Invalid IP Address")
|
raise newException(ValueError, "Invalid IP Address")
|
||||||
v4StartPos = currentGroupStart
|
v4StartPos = currentGroupStart
|
||||||
currentShort = 0
|
currentShort = 0
|
||||||
seperatorValid = false
|
seperatorValid = false
|
||||||
|
|
@ -1123,19 +1123,19 @@ proc parseIPv6Address(address_str: string): TIpAddress =
|
||||||
else: # Upper case hex
|
else: # Upper case hex
|
||||||
currentShort = (currentShort shl 4) + cast[uint32](ord(c) - ord('A')) + 10
|
currentShort = (currentShort shl 4) + cast[uint32](ord(c) - ord('A')) + 10
|
||||||
if currentShort > 65535'u32:
|
if currentShort > 65535'u32:
|
||||||
raise newException(EInvalidValue,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. Value is out of range")
|
"Invalid IP Address. Value is out of range")
|
||||||
lastWasColon = false
|
lastWasColon = false
|
||||||
seperatorValid = true
|
seperatorValid = true
|
||||||
else:
|
else:
|
||||||
raise newException(EInvalidValue,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. Address contains an invalid character")
|
"Invalid IP Address. Address contains an invalid character")
|
||||||
|
|
||||||
|
|
||||||
if v4StartPos == -1: # Don't parse v4. Copy the remaining v6 stuff
|
if v4StartPos == -1: # Don't parse v4. Copy the remaining v6 stuff
|
||||||
if seperatorValid: # Copy remaining data
|
if seperatorValid: # Copy remaining data
|
||||||
if groupCount >= 8:
|
if groupCount >= 8:
|
||||||
raise newException(EInvalidValue,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. The address consists of too many groups")
|
"Invalid IP Address. The address consists of too many groups")
|
||||||
result.address_v6[groupCount*2] = cast[uint8](currentShort shr 8)
|
result.address_v6[groupCount*2] = cast[uint8](currentShort shr 8)
|
||||||
result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF)
|
result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF)
|
||||||
|
|
@ -1145,32 +1145,32 @@ proc parseIPv6Address(address_str: string): TIpAddress =
|
||||||
if c in strutils.Digits: # Character is a number
|
if c in strutils.Digits: # Character is a number
|
||||||
currentShort = currentShort * 10 + cast[uint32](ord(c) - ord('0'))
|
currentShort = currentShort * 10 + cast[uint32](ord(c) - ord('0'))
|
||||||
if currentShort > 255'u32:
|
if currentShort > 255'u32:
|
||||||
raise newException(EInvalidValue,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. Value is out of range")
|
"Invalid IP Address. Value is out of range")
|
||||||
seperatorValid = true
|
seperatorValid = true
|
||||||
elif c == '.': # IPv4 address separator
|
elif c == '.': # IPv4 address separator
|
||||||
if not seperatorValid or byteCount >= 3:
|
if not seperatorValid or byteCount >= 3:
|
||||||
raise newException(EInvalidValue, "Invalid IP Address")
|
raise newException(ValueError, "Invalid IP Address")
|
||||||
result.address_v6[groupCount*2 + byteCount] = cast[uint8](currentShort)
|
result.address_v6[groupCount*2 + byteCount] = cast[uint8](currentShort)
|
||||||
currentShort = 0
|
currentShort = 0
|
||||||
byteCount.inc()
|
byteCount.inc()
|
||||||
seperatorValid = false
|
seperatorValid = false
|
||||||
else: # Invalid character
|
else: # Invalid character
|
||||||
raise newException(EInvalidValue,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. Address contains an invalid character")
|
"Invalid IP Address. Address contains an invalid character")
|
||||||
|
|
||||||
if byteCount != 3 or not seperatorValid:
|
if byteCount != 3 or not seperatorValid:
|
||||||
raise newException(EInvalidValue, "Invalid IP Address")
|
raise newException(ValueError, "Invalid IP Address")
|
||||||
result.address_v6[groupCount*2 + byteCount] = cast[uint8](currentShort)
|
result.address_v6[groupCount*2 + byteCount] = cast[uint8](currentShort)
|
||||||
groupCount += 2
|
groupCount += 2
|
||||||
|
|
||||||
# Shift and fill zeros in case of ::
|
# Shift and fill zeros in case of ::
|
||||||
if groupCount > 8:
|
if groupCount > 8:
|
||||||
raise newException(EInvalidValue,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. The address consists of too many groups")
|
"Invalid IP Address. The address consists of too many groups")
|
||||||
elif groupCount < 8: # must fill
|
elif groupCount < 8: # must fill
|
||||||
if dualColonGroup == -1:
|
if dualColonGroup == -1:
|
||||||
raise newException(EInvalidValue,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. The address consists of too few groups")
|
"Invalid IP Address. The address consists of too few groups")
|
||||||
var toFill = 8 - groupCount # The number of groups to fill
|
var toFill = 8 - groupCount # The number of groups to fill
|
||||||
var toShift = groupCount - dualColonGroup # Nr of known groups after ::
|
var toShift = groupCount - dualColonGroup # Nr of known groups after ::
|
||||||
|
|
@ -1179,14 +1179,14 @@ proc parseIPv6Address(address_str: string): TIpAddress =
|
||||||
for i in 0..2*toFill-1: # fill with 0s
|
for i in 0..2*toFill-1: # fill with 0s
|
||||||
result.address_v6[dualColonGroup*2+i] = 0
|
result.address_v6[dualColonGroup*2+i] = 0
|
||||||
elif dualColonGroup != -1:
|
elif dualColonGroup != -1:
|
||||||
raise newException(EInvalidValue,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. The address consists of too many groups")
|
"Invalid IP Address. The address consists of too many groups")
|
||||||
|
|
||||||
proc parseIpAddress*(address_str: string): TIpAddress =
|
proc parseIpAddress*(address_str: string): TIpAddress =
|
||||||
## Parses an IP address
|
## Parses an IP address
|
||||||
## Raises EInvalidValue on error
|
## Raises EInvalidValue on error
|
||||||
if address_str == nil:
|
if address_str == nil:
|
||||||
raise newException(EInvalidValue, "IP Address string is nil")
|
raise newException(ValueError, "IP Address string is nil")
|
||||||
if address_str.contains(':'):
|
if address_str.contains(':'):
|
||||||
return parseIPv6Address(address_str)
|
return parseIPv6Address(address_str)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
import unsigned, os
|
import unsigned, os
|
||||||
|
|
||||||
when hostos == "solaris":
|
when hostOS == "solaris":
|
||||||
{.passl: "-lsocket -lnsl".}
|
{.passl: "-lsocket -lnsl".}
|
||||||
|
|
||||||
const useWinVersion = defined(Windows) or defined(nimdoc)
|
const useWinVersion = defined(Windows) or defined(nimdoc)
|
||||||
|
|
@ -156,7 +156,7 @@ proc newRawSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
|
||||||
proc close*(socket: SocketHandle) =
|
proc close*(socket: SocketHandle) =
|
||||||
## closes a socket.
|
## closes a socket.
|
||||||
when useWinVersion:
|
when useWinVersion:
|
||||||
discard winlean.closeSocket(socket)
|
discard winlean.closesocket(socket)
|
||||||
else:
|
else:
|
||||||
discard posix.close(socket)
|
discard posix.close(socket)
|
||||||
# TODO: These values should not be discarded. An EOS should be raised.
|
# TODO: These values should not be discarded. An EOS should be raised.
|
||||||
|
|
@ -165,7 +165,7 @@ proc close*(socket: SocketHandle) =
|
||||||
proc bindAddr*(socket: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint =
|
proc bindAddr*(socket: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint =
|
||||||
result = bindSocket(socket, name, namelen)
|
result = bindSocket(socket, name, namelen)
|
||||||
|
|
||||||
proc listen*(socket: SocketHandle, backlog = SOMAXCONN): cint {.tags: [FReadIO].} =
|
proc listen*(socket: SocketHandle, backlog = SOMAXCONN): cint {.tags: [ReadIOEffect].} =
|
||||||
## Marks ``socket`` as accepting connections.
|
## Marks ``socket`` as accepting connections.
|
||||||
## ``Backlog`` specifies the maximum length of the
|
## ``Backlog`` specifies the maximum length of the
|
||||||
## queue of pending connections.
|
## queue of pending connections.
|
||||||
|
|
@ -223,7 +223,7 @@ proc htons*(x: int16): int16 =
|
||||||
## order, this is a no-op; otherwise, it performs a 2-byte swap operation.
|
## order, this is a no-op; otherwise, it performs a 2-byte swap operation.
|
||||||
result = rawsockets.ntohs(x)
|
result = rawsockets.ntohs(x)
|
||||||
|
|
||||||
proc getServByName*(name, proto: string): Servent {.tags: [FReadIO].} =
|
proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} =
|
||||||
## Searches the database from the beginning and finds the first entry for
|
## Searches the database from the beginning and finds the first entry for
|
||||||
## which the service name specified by ``name`` matches the s_name member
|
## which the service name specified by ``name`` matches the s_name member
|
||||||
## and the protocol name specified by ``proto`` matches the s_proto member.
|
## and the protocol name specified by ``proto`` matches the s_proto member.
|
||||||
|
|
@ -233,13 +233,13 @@ proc getServByName*(name, proto: string): Servent {.tags: [FReadIO].} =
|
||||||
var s = winlean.getservbyname(name, proto)
|
var s = winlean.getservbyname(name, proto)
|
||||||
else:
|
else:
|
||||||
var s = posix.getservbyname(name, proto)
|
var s = posix.getservbyname(name, proto)
|
||||||
if s == nil: raise newException(EOS, "Service not found.")
|
if s == nil: raise newException(OSError, "Service not found.")
|
||||||
result.name = $s.s_name
|
result.name = $s.s_name
|
||||||
result.aliases = cstringArrayToSeq(s.s_aliases)
|
result.aliases = cstringArrayToSeq(s.s_aliases)
|
||||||
result.port = Port(s.s_port)
|
result.port = Port(s.s_port)
|
||||||
result.proto = $s.s_proto
|
result.proto = $s.s_proto
|
||||||
|
|
||||||
proc getServByPort*(port: Port, proto: string): Servent {.tags: [FReadIO].} =
|
proc getServByPort*(port: Port, proto: string): Servent {.tags: [ReadIOEffect].} =
|
||||||
## Searches the database from the beginning and finds the first entry for
|
## 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
|
## which the port specified by ``port`` matches the s_port member and the
|
||||||
## protocol name specified by ``proto`` matches the s_proto member.
|
## protocol name specified by ``proto`` matches the s_proto member.
|
||||||
|
|
@ -249,13 +249,13 @@ proc getServByPort*(port: Port, proto: string): Servent {.tags: [FReadIO].} =
|
||||||
var s = winlean.getservbyport(ze(int16(port)).cint, proto)
|
var s = winlean.getservbyport(ze(int16(port)).cint, proto)
|
||||||
else:
|
else:
|
||||||
var s = posix.getservbyport(ze(int16(port)).cint, proto)
|
var s = posix.getservbyport(ze(int16(port)).cint, proto)
|
||||||
if s == nil: raise newException(EOS, "Service not found.")
|
if s == nil: raise newException(OSError, "Service not found.")
|
||||||
result.name = $s.s_name
|
result.name = $s.s_name
|
||||||
result.aliases = cstringArrayToSeq(s.s_aliases)
|
result.aliases = cstringArrayToSeq(s.s_aliases)
|
||||||
result.port = Port(s.s_port)
|
result.port = Port(s.s_port)
|
||||||
result.proto = $s.s_proto
|
result.proto = $s.s_proto
|
||||||
|
|
||||||
proc getHostByAddr*(ip: string): Hostent {.tags: [FReadIO].} =
|
proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} =
|
||||||
## This function will lookup the hostname of an IP Address.
|
## This function will lookup the hostname of an IP Address.
|
||||||
var myaddr: InAddr
|
var myaddr: InAddr
|
||||||
myaddr.s_addr = inet_addr(ip)
|
myaddr.s_addr = inet_addr(ip)
|
||||||
|
|
@ -284,7 +284,7 @@ proc getHostByAddr*(ip: string): Hostent {.tags: [FReadIO].} =
|
||||||
result.addrList = cstringArrayToSeq(s.h_addr_list)
|
result.addrList = cstringArrayToSeq(s.h_addr_list)
|
||||||
result.length = int(s.h_length)
|
result.length = int(s.h_length)
|
||||||
|
|
||||||
proc getHostByName*(name: string): Hostent {.tags: [FReadIO].} =
|
proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} =
|
||||||
## This function will lookup the IP address of a hostname.
|
## This function will lookup the IP address of a hostname.
|
||||||
when useWinVersion:
|
when useWinVersion:
|
||||||
var s = winlean.gethostbyname(name)
|
var s = winlean.gethostbyname(name)
|
||||||
|
|
@ -314,28 +314,28 @@ proc getSockName*(socket: SocketHandle): Port =
|
||||||
name.sin_family = posix.AF_INET
|
name.sin_family = posix.AF_INET
|
||||||
#name.sin_port = htons(cint16(port))
|
#name.sin_port = htons(cint16(port))
|
||||||
#name.sin_addr.s_addr = htonl(INADDR_ANY)
|
#name.sin_addr.s_addr = htonl(INADDR_ANY)
|
||||||
var namelen = sizeof(name).Socklen
|
var namelen = sizeof(name).SockLen
|
||||||
if getsockname(socket, cast[ptr SockAddr](addr(name)),
|
if getsockname(socket, cast[ptr SockAddr](addr(name)),
|
||||||
addr(namelen)) == -1'i32:
|
addr(namelen)) == -1'i32:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
result = Port(rawsockets.ntohs(name.sin_port))
|
result = Port(rawsockets.ntohs(name.sin_port))
|
||||||
|
|
||||||
proc getSockOptInt*(socket: SocketHandle, level, optname: int): int {.
|
proc getSockOptInt*(socket: SocketHandle, level, optname: int): int {.
|
||||||
tags: [FReadIO].} =
|
tags: [ReadIOEffect].} =
|
||||||
## getsockopt for integer options.
|
## getsockopt for integer options.
|
||||||
var res: cint
|
var res: cint
|
||||||
var size = sizeof(res).Socklen
|
var size = sizeof(res).SockLen
|
||||||
if getsockopt(socket, cint(level), cint(optname),
|
if getsockopt(socket, cint(level), cint(optname),
|
||||||
addr(res), addr(size)) < 0'i32:
|
addr(res), addr(size)) < 0'i32:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
result = int(res)
|
result = int(res)
|
||||||
|
|
||||||
proc setSockOptInt*(socket: SocketHandle, level, optname, optval: int) {.
|
proc setSockOptInt*(socket: SocketHandle, level, optname, optval: int) {.
|
||||||
tags: [FWriteIO].} =
|
tags: [WriteIOEffect].} =
|
||||||
## setsockopt for integer options.
|
## setsockopt for integer options.
|
||||||
var value = cint(optval)
|
var value = cint(optval)
|
||||||
if setsockopt(socket, cint(level), cint(optname), addr(value),
|
if setsockopt(socket, cint(level), cint(optname), addr(value),
|
||||||
sizeof(value).Socklen) < 0'i32:
|
sizeof(value).SockLen) < 0'i32:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
|
||||||
proc setBlocking*(s: SocketHandle, blocking: bool) =
|
proc setBlocking*(s: SocketHandle, blocking: bool) =
|
||||||
|
|
@ -361,13 +361,13 @@ proc timeValFromMilliseconds(timeout = 500): Timeval =
|
||||||
result.tv_sec = seconds.int32
|
result.tv_sec = seconds.int32
|
||||||
result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
|
result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
|
||||||
|
|
||||||
proc createFdSet(fd: var FdSet, s: seq[SocketHandle], m: var int) =
|
proc createFdSet(fd: var FD_SET, s: seq[SocketHandle], m: var int) =
|
||||||
FD_ZERO(fd)
|
FD_ZERO(fd)
|
||||||
for i in items(s):
|
for i in items(s):
|
||||||
m = max(m, int(i))
|
m = max(m, int(i))
|
||||||
FD_SET(i, fd)
|
FD_SET(i, fd)
|
||||||
|
|
||||||
proc pruneSocketSet(s: var seq[SocketHandle], fd: var FdSet) =
|
proc pruneSocketSet(s: var seq[SocketHandle], fd: var FD_SET) =
|
||||||
var i = 0
|
var i = 0
|
||||||
var L = s.len
|
var L = s.len
|
||||||
while i < L:
|
while i < L:
|
||||||
|
|
@ -386,7 +386,7 @@ proc select*(readfds: var seq[SocketHandle], timeout = 500): int =
|
||||||
##
|
##
|
||||||
## A socket is removed from the specific ``seq`` when it has data waiting to
|
## A socket is removed from the specific ``seq`` when it has data waiting to
|
||||||
## be read/written to or has errors (``exceptfds``).
|
## be read/written to or has errors (``exceptfds``).
|
||||||
var tv {.noInit.}: Ttimeval = timeValFromMilliseconds(timeout)
|
var tv {.noInit.}: TTimeval = timeValFromMilliseconds(timeout)
|
||||||
|
|
||||||
var rd: TFdSet
|
var rd: TFdSet
|
||||||
var m = 0
|
var m = 0
|
||||||
|
|
@ -400,7 +400,7 @@ proc select*(readfds: var seq[SocketHandle], timeout = 500): int =
|
||||||
pruneSocketSet(readfds, (rd))
|
pruneSocketSet(readfds, (rd))
|
||||||
|
|
||||||
proc selectWrite*(writefds: var seq[SocketHandle],
|
proc selectWrite*(writefds: var seq[SocketHandle],
|
||||||
timeout = 500): int {.tags: [FReadIO].} =
|
timeout = 500): int {.tags: [ReadIOEffect].} =
|
||||||
## When a socket in ``writefds`` is ready to be written to then a non-zero
|
## When a socket in ``writefds`` is ready to be written to then a non-zero
|
||||||
## value will be returned specifying the count of the sockets which can be
|
## value will be returned specifying the count of the sockets which can be
|
||||||
## written to. The sockets which can be written to will also be removed
|
## written to. The sockets which can be written to will also be removed
|
||||||
|
|
|
||||||
|
|
@ -425,7 +425,7 @@ type
|
||||||
|
|
||||||
TFdSet* {.pure, final.} = object
|
TFdSet* {.pure, final.} = object
|
||||||
fd_count*: cint # unsigned
|
fd_count*: cint # unsigned
|
||||||
fd_array*: array[0..FD_SETSIZE-1, TSocketHandle]
|
fd_array*: array[0..FD_SETSIZE-1, SocketHandle]
|
||||||
|
|
||||||
TTimeval* {.pure, final.} = object
|
TTimeval* {.pure, final.} = object
|
||||||
tv_sec*, tv_usec*: int32
|
tv_sec*, tv_usec*: int32
|
||||||
|
|
@ -444,7 +444,7 @@ type
|
||||||
|
|
||||||
var
|
var
|
||||||
SOMAXCONN* {.importc, header: "Winsock2.h".}: cint
|
SOMAXCONN* {.importc, header: "Winsock2.h".}: cint
|
||||||
INVALID_SOCKET* {.importc, header: "Winsock2.h".}: TSocketHandle
|
INVALID_SOCKET* {.importc, header: "Winsock2.h".}: SocketHandle
|
||||||
SOL_SOCKET* {.importc, header: "Winsock2.h".}: cint
|
SOL_SOCKET* {.importc, header: "Winsock2.h".}: cint
|
||||||
SO_DEBUG* {.importc, header: "Winsock2.h".}: cint ## turn on debugging info recording
|
SO_DEBUG* {.importc, header: "Winsock2.h".}: cint ## turn on debugging info recording
|
||||||
SO_ACCEPTCONN* {.importc, header: "Winsock2.h".}: cint # socket has had listen()
|
SO_ACCEPTCONN* {.importc, header: "Winsock2.h".}: cint # socket has had listen()
|
||||||
|
|
@ -460,7 +460,7 @@ var
|
||||||
SO_EXCLUSIVEADDRUSE* {.importc, header: "Winsock2.h".}: cint # disallow local address reuse
|
SO_EXCLUSIVEADDRUSE* {.importc, header: "Winsock2.h".}: cint # disallow local address reuse
|
||||||
SO_ERROR* {.importc, header: "Winsock2.h".}: cint
|
SO_ERROR* {.importc, header: "Winsock2.h".}: cint
|
||||||
|
|
||||||
proc `==`*(x, y: TSocketHandle): bool {.borrow.}
|
proc `==`*(x, y: SocketHandle): bool {.borrow.}
|
||||||
|
|
||||||
proc getservbyname*(name, proto: cstring): ptr TServent {.
|
proc getservbyname*(name, proto: cstring): ptr TServent {.
|
||||||
stdcall, importc: "getservbyname", dynlib: ws2dll.}
|
stdcall, importc: "getservbyname", dynlib: ws2dll.}
|
||||||
|
|
@ -474,45 +474,45 @@ proc gethostbyaddr*(ip: ptr TInAddr, len: cuint, theType: cint): ptr Thostent {.
|
||||||
proc gethostbyname*(name: cstring): ptr Thostent {.
|
proc gethostbyname*(name: cstring): ptr Thostent {.
|
||||||
stdcall, importc: "gethostbyname", dynlib: ws2dll.}
|
stdcall, importc: "gethostbyname", dynlib: ws2dll.}
|
||||||
|
|
||||||
proc socket*(af, typ, protocol: cint): TSocketHandle {.
|
proc socket*(af, typ, protocol: cint): SocketHandle {.
|
||||||
stdcall, importc: "socket", dynlib: ws2dll.}
|
stdcall, importc: "socket", dynlib: ws2dll.}
|
||||||
|
|
||||||
proc closesocket*(s: TSocketHandle): cint {.
|
proc closesocket*(s: SocketHandle): cint {.
|
||||||
stdcall, importc: "closesocket", dynlib: ws2dll.}
|
stdcall, importc: "closesocket", dynlib: ws2dll.}
|
||||||
|
|
||||||
proc accept*(s: TSocketHandle, a: ptr TSockAddr, addrlen: ptr TSockLen): TSocketHandle {.
|
proc accept*(s: SocketHandle, a: ptr TSockAddr, addrlen: ptr TSockLen): SocketHandle {.
|
||||||
stdcall, importc: "accept", dynlib: ws2dll.}
|
stdcall, importc: "accept", dynlib: ws2dll.}
|
||||||
proc bindSocket*(s: TSocketHandle, name: ptr TSockAddr, namelen: TSockLen): cint {.
|
proc bindSocket*(s: SocketHandle, name: ptr TSockAddr, namelen: TSockLen): cint {.
|
||||||
stdcall, importc: "bind", dynlib: ws2dll.}
|
stdcall, importc: "bind", dynlib: ws2dll.}
|
||||||
proc connect*(s: TSocketHandle, name: ptr TSockAddr, namelen: TSockLen): cint {.
|
proc connect*(s: SocketHandle, name: ptr TSockAddr, namelen: TSockLen): cint {.
|
||||||
stdcall, importc: "connect", dynlib: ws2dll.}
|
stdcall, importc: "connect", dynlib: ws2dll.}
|
||||||
proc getsockname*(s: TSocketHandle, name: ptr TSockAddr,
|
proc getsockname*(s: SocketHandle, name: ptr TSockAddr,
|
||||||
namelen: ptr TSockLen): cint {.
|
namelen: ptr TSockLen): cint {.
|
||||||
stdcall, importc: "getsockname", dynlib: ws2dll.}
|
stdcall, importc: "getsockname", dynlib: ws2dll.}
|
||||||
proc getsockopt*(s: TSocketHandle, level, optname: cint, optval: pointer,
|
proc getsockopt*(s: SocketHandle, level, optname: cint, optval: pointer,
|
||||||
optlen: ptr TSockLen): cint {.
|
optlen: ptr TSockLen): cint {.
|
||||||
stdcall, importc: "getsockopt", dynlib: ws2dll.}
|
stdcall, importc: "getsockopt", dynlib: ws2dll.}
|
||||||
proc setsockopt*(s: TSocketHandle, level, optname: cint, optval: pointer,
|
proc setsockopt*(s: SocketHandle, level, optname: cint, optval: pointer,
|
||||||
optlen: TSockLen): cint {.
|
optlen: TSockLen): cint {.
|
||||||
stdcall, importc: "setsockopt", dynlib: ws2dll.}
|
stdcall, importc: "setsockopt", dynlib: ws2dll.}
|
||||||
|
|
||||||
proc listen*(s: TSocketHandle, backlog: cint): cint {.
|
proc listen*(s: SocketHandle, backlog: cint): cint {.
|
||||||
stdcall, importc: "listen", dynlib: ws2dll.}
|
stdcall, importc: "listen", dynlib: ws2dll.}
|
||||||
proc recv*(s: TSocketHandle, buf: pointer, len, flags: cint): cint {.
|
proc recv*(s: SocketHandle, buf: pointer, len, flags: cint): cint {.
|
||||||
stdcall, importc: "recv", dynlib: ws2dll.}
|
stdcall, importc: "recv", dynlib: ws2dll.}
|
||||||
proc recvfrom*(s: TSocketHandle, buf: cstring, len, flags: cint,
|
proc recvfrom*(s: SocketHandle, buf: cstring, len, flags: cint,
|
||||||
fromm: ptr TSockAddr, fromlen: ptr TSockLen): cint {.
|
fromm: ptr TSockAddr, fromlen: ptr TSockLen): cint {.
|
||||||
stdcall, importc: "recvfrom", dynlib: ws2dll.}
|
stdcall, importc: "recvfrom", dynlib: ws2dll.}
|
||||||
proc select*(nfds: cint, readfds, writefds, exceptfds: ptr TFdSet,
|
proc select*(nfds: cint, readfds, writefds, exceptfds: ptr TFdSet,
|
||||||
timeout: ptr TTimeval): cint {.
|
timeout: ptr TTimeval): cint {.
|
||||||
stdcall, importc: "select", dynlib: ws2dll.}
|
stdcall, importc: "select", dynlib: ws2dll.}
|
||||||
proc send*(s: TSocketHandle, buf: pointer, len, flags: cint): cint {.
|
proc send*(s: SocketHandle, buf: pointer, len, flags: cint): cint {.
|
||||||
stdcall, importc: "send", dynlib: ws2dll.}
|
stdcall, importc: "send", dynlib: ws2dll.}
|
||||||
proc sendto*(s: TSocketHandle, buf: pointer, len, flags: cint,
|
proc sendto*(s: SocketHandle, buf: pointer, len, flags: cint,
|
||||||
to: ptr TSockAddr, tolen: TSockLen): cint {.
|
to: ptr TSockAddr, tolen: TSockLen): cint {.
|
||||||
stdcall, importc: "sendto", dynlib: ws2dll.}
|
stdcall, importc: "sendto", dynlib: ws2dll.}
|
||||||
|
|
||||||
proc shutdown*(s: TSocketHandle, how: cint): cint {.
|
proc shutdown*(s: SocketHandle, how: cint): cint {.
|
||||||
stdcall, importc: "shutdown", dynlib: ws2dll.}
|
stdcall, importc: "shutdown", dynlib: ws2dll.}
|
||||||
|
|
||||||
proc getnameinfo*(a1: ptr TSockAddr, a2: TSockLen,
|
proc getnameinfo*(a1: ptr TSockAddr, a2: TSockLen,
|
||||||
|
|
@ -523,13 +523,13 @@ proc getnameinfo*(a1: ptr TSockAddr, a2: TSockLen,
|
||||||
proc inet_addr*(cp: cstring): int32 {.
|
proc inet_addr*(cp: cstring): int32 {.
|
||||||
stdcall, importc: "inet_addr", dynlib: ws2dll.}
|
stdcall, importc: "inet_addr", dynlib: ws2dll.}
|
||||||
|
|
||||||
proc WSAFDIsSet(s: TSocketHandle, FDSet: var TFdSet): bool {.
|
proc WSAFDIsSet(s: SocketHandle, FDSet: var TFdSet): bool {.
|
||||||
stdcall, importc: "__WSAFDIsSet", dynlib: ws2dll, noSideEffect.}
|
stdcall, importc: "__WSAFDIsSet", dynlib: ws2dll, noSideEffect.}
|
||||||
|
|
||||||
proc FD_ISSET*(Socket: TSocketHandle, FDSet: var TFdSet): cint =
|
proc FD_ISSET*(Socket: SocketHandle, FDSet: var TFdSet): cint =
|
||||||
result = if WSAFDIsSet(Socket, FDSet): 1'i32 else: 0'i32
|
result = if WSAFDIsSet(Socket, FDSet): 1'i32 else: 0'i32
|
||||||
|
|
||||||
proc FD_SET*(Socket: TSocketHandle, FDSet: var TFdSet) =
|
proc FD_SET*(Socket: SocketHandle, FDSet: var TFdSet) =
|
||||||
if FDSet.fd_count < FD_SETSIZE:
|
if FDSet.fd_count < FD_SETSIZE:
|
||||||
FDSet.fd_array[int(FDSet.fd_count)] = Socket
|
FDSet.fd_array[int(FDSet.fd_count)] = Socket
|
||||||
inc(FDSet.fd_count)
|
inc(FDSet.fd_count)
|
||||||
|
|
@ -699,7 +699,7 @@ var
|
||||||
WSAID_GETACCEPTEXSOCKADDRS*: TGUID = TGUID(D1: 0xb5367df2'i32, D2: 0xcbac'i16, D3: 0x11cf, D4: [
|
WSAID_GETACCEPTEXSOCKADDRS*: TGUID = TGUID(D1: 0xb5367df2'i32, D2: 0xcbac'i16, D3: 0x11cf, D4: [
|
||||||
0x95'i8, 0xca'i8, 0x00'i8, 0x80'i8, 0x5f'i8, 0x48'i8, 0xa1'i8, 0x92'i8])
|
0x95'i8, 0xca'i8, 0x00'i8, 0x80'i8, 0x5f'i8, 0x48'i8, 0xa1'i8, 0x92'i8])
|
||||||
|
|
||||||
proc WSAIoctl*(s: TSocketHandle, dwIoControlCode: DWORD, lpvInBuffer: pointer,
|
proc WSAIoctl*(s: SocketHandle, dwIoControlCode: DWORD, lpvInBuffer: pointer,
|
||||||
cbInBuffer: DWORD, lpvOutBuffer: pointer, cbOutBuffer: DWORD,
|
cbInBuffer: DWORD, lpvOutBuffer: pointer, cbOutBuffer: DWORD,
|
||||||
lpcbBytesReturned: PDWORD, lpOverlapped: POVERLAPPED,
|
lpcbBytesReturned: PDWORD, lpOverlapped: POVERLAPPED,
|
||||||
lpCompletionRoutine: POVERLAPPED_COMPLETION_ROUTINE): cint
|
lpCompletionRoutine: POVERLAPPED_COMPLETION_ROUTINE): cint
|
||||||
|
|
@ -710,12 +710,12 @@ type
|
||||||
len*: ULONG
|
len*: ULONG
|
||||||
buf*: cstring
|
buf*: cstring
|
||||||
|
|
||||||
proc WSARecv*(s: TSocketHandle, buf: ptr TWSABuf, bufCount: DWORD,
|
proc WSARecv*(s: SocketHandle, buf: ptr TWSABuf, bufCount: DWORD,
|
||||||
bytesReceived, flags: PDWORD, lpOverlapped: POVERLAPPED,
|
bytesReceived, flags: PDWORD, lpOverlapped: POVERLAPPED,
|
||||||
completionProc: POVERLAPPED_COMPLETION_ROUTINE): cint {.
|
completionProc: POVERLAPPED_COMPLETION_ROUTINE): cint {.
|
||||||
stdcall, importc: "WSARecv", dynlib: "Ws2_32.dll".}
|
stdcall, importc: "WSARecv", dynlib: "Ws2_32.dll".}
|
||||||
|
|
||||||
proc WSASend*(s: TSocketHandle, buf: ptr TWSABuf, bufCount: DWORD,
|
proc WSASend*(s: SocketHandle, buf: ptr TWSABuf, bufCount: DWORD,
|
||||||
bytesSent: PDWORD, flags: DWORD, lpOverlapped: POVERLAPPED,
|
bytesSent: PDWORD, flags: DWORD, lpOverlapped: POVERLAPPED,
|
||||||
completionProc: POVERLAPPED_COMPLETION_ROUTINE): cint {.
|
completionProc: POVERLAPPED_COMPLETION_ROUTINE): cint {.
|
||||||
stdcall, importc: "WSASend", dynlib: "Ws2_32.dll".}
|
stdcall, importc: "WSASend", dynlib: "Ws2_32.dll".}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue