mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-30 10:31:47 +00:00
Merge branch 'devel' into pr_tables_lent_iter
This commit is contained in:
@@ -470,6 +470,13 @@ typedef char* NCSTRING;
|
||||
|
||||
#define NIM_STRLIT_FLAG ((NU)(1) << ((NIM_INTBITS) - 2)) /* This has to be the same as system.strlitFlag! */
|
||||
|
||||
/* unused in codegen after 2.2 but keep for compatibility: */
|
||||
#define STRING_LITERAL(name, str, length) \
|
||||
static const struct { \
|
||||
TGenericSeq Sup; \
|
||||
NIM_CHAR data[(length) + 1]; \
|
||||
} name = {{length, (NI) ((NU)length | NIM_STRLIT_FLAG)}, str}
|
||||
|
||||
/* declared size of a sequence/variable length array: */
|
||||
#if defined(__cplusplus) && defined(__clang__)
|
||||
# define SEQ_DECL_SIZE 1
|
||||
@@ -485,13 +492,22 @@ typedef char* NCSTRING;
|
||||
|
||||
#define paramCount() cmdCount
|
||||
|
||||
// NAN definition copied from math.h included in the Windows SDK version 10.0.14393.0
|
||||
#ifndef NAN
|
||||
#ifndef NAN /* use __builtin_nanf which is faster, if available */
|
||||
# if defined(__GNUC__)
|
||||
# define NAN (__builtin_nanf(""))
|
||||
# elif defined(__clang__) /* XXX: writing __has_builtin this line cause MSVC complains. */
|
||||
# if __has_builtin (__builtin_nanf)
|
||||
# define NAN (__builtin_nanf(""))
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef NAN /* modified from math.h included in the Windows SDK version 10.0.26100.0 */
|
||||
# ifndef _HUGE_ENUF
|
||||
# define _HUGE_ENUF 1e+300 // _HUGE_ENUF*_HUGE_ENUF must overflow
|
||||
# define _HUGE_ENUF 1e+300 /* _HUGE_ENUF*_HUGE_ENUF must overflow */
|
||||
# endif
|
||||
# define NAN_INFINITY ((float)(_HUGE_ENUF * _HUGE_ENUF))
|
||||
# define NAN ((float)(NAN_INFINITY * 0.0F))
|
||||
# define NAN (-(float)(NAN_INFINITY * 0.0F))
|
||||
#endif
|
||||
|
||||
#ifndef INF
|
||||
|
||||
@@ -215,6 +215,11 @@ when defined(osx): # 2001 POSIX evidently does not concern Apple
|
||||
# present size & has no good reason to call this unless it is growing.
|
||||
if fcntl(a1, F_PREALLOCATE, fst.addr) != cint(-1): ftruncate(a1, a2 + a3)
|
||||
else: cint(-1)
|
||||
elif defined(openbsd):
|
||||
proc posix_fallocate*(a1: cint, a2, a3: Off): cint =
|
||||
# above assumption: "has no good reason to call this unless it is growing."
|
||||
# man ftruncate "it will be extended as if by writing bytes with the value zero."
|
||||
return ftruncate(a1, a2 + a3)
|
||||
else:
|
||||
proc posix_fallocate*(a1: cint, a2, a3: Off): cint {.
|
||||
importc, header: "<fcntl.h>".}
|
||||
@@ -1099,7 +1104,9 @@ when not defined(lwip):
|
||||
# Meanwhile, BSD derivatives had used unsigned int; we will use this
|
||||
# for the else case, because it is more widely cloned than SVR4's
|
||||
# behavior.
|
||||
when defined(linux) or defined(haiku):
|
||||
# Finally, bionic libc (Android) also uses unsigned int, despite being
|
||||
# a Linux.
|
||||
when defined(linux) and not defined(android) or defined(haiku):
|
||||
type
|
||||
Tnfds* {.importc: "nfds_t", header: "<poll.h>".} = culong
|
||||
elif defined(zephyr):
|
||||
|
||||
@@ -46,7 +46,7 @@ template createCb(futTyp, strName, identName, futureVarCompletions: untyped) =
|
||||
{.gcsafe.}:
|
||||
next.addCallback(cast[proc() {.closure, gcsafe.}](proc =
|
||||
identName(fut, it)))
|
||||
except:
|
||||
except Exception:
|
||||
futureVarCompletions
|
||||
if fut.finished:
|
||||
# Take a look at tasyncexceptions for the bug which this fixes.
|
||||
|
||||
@@ -126,8 +126,6 @@ type
|
||||
when defineSsl:
|
||||
sslHandle: SslPtr
|
||||
sslContext: SslContext
|
||||
bioIn: BIO
|
||||
bioOut: BIO
|
||||
sslNoShutdown: bool
|
||||
domain: Domain
|
||||
sockType: SockType
|
||||
@@ -207,7 +205,10 @@ proc newAsyncSocket*(domain, sockType, protocol: cint,
|
||||
Protocol(protocol), buffered, inheritable)
|
||||
|
||||
when defineSsl:
|
||||
proc getSslError(socket: AsyncSocket, err: cint): cint =
|
||||
proc raiseSslHandleError =
|
||||
raiseSSLError("The SSL Handle is closed/unset")
|
||||
|
||||
proc getSslError(socket: AsyncSocket, flags: set[SocketFlag], err: cint): cint =
|
||||
assert socket.isSsl
|
||||
assert err < 0
|
||||
var ret = SSL_get_error(socket.sslHandle, err.cint)
|
||||
@@ -220,65 +221,65 @@ when defineSsl:
|
||||
return ret
|
||||
of SSL_ERROR_WANT_X509_LOOKUP:
|
||||
raiseSSLError("Function for x509 lookup has been called.")
|
||||
of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
|
||||
of SSL_ERROR_SYSCALL:
|
||||
socket.sslNoShutdown = true
|
||||
let osErr = osLastError()
|
||||
if not flags.isDisconnectionError(osErr):
|
||||
var errStr = "IO error has occurred"
|
||||
let sslErr = ERR_peek_last_error()
|
||||
if sslErr == 0 and err == 0:
|
||||
errStr.add ' '
|
||||
errStr.add "because an EOF was observed that violates the protocol"
|
||||
elif sslErr == 0 and err == -1:
|
||||
errStr.add ' '
|
||||
errStr.add "in the BIO layer"
|
||||
else:
|
||||
let errStr = $ERR_error_string(sslErr, nil)
|
||||
raiseSSLError(errStr & ": " & errStr)
|
||||
raiseOSError(osErr, errStr)
|
||||
else:
|
||||
return ret
|
||||
of SSL_ERROR_SSL:
|
||||
socket.sslNoShutdown = true
|
||||
raiseSSLError()
|
||||
else: raiseSSLError("Unknown Error")
|
||||
|
||||
proc sendPendingSslData(socket: AsyncSocket,
|
||||
flags: set[SocketFlag]) {.async.} =
|
||||
let len = bioCtrlPending(socket.bioOut)
|
||||
if len > 0:
|
||||
var data = newString(len)
|
||||
let read = bioRead(socket.bioOut, cast[cstring](addr data[0]), len)
|
||||
assert read != 0
|
||||
if read < 0:
|
||||
raiseSSLError()
|
||||
data.setLen(read)
|
||||
await socket.fd.AsyncFD.send(data, flags)
|
||||
|
||||
proc appeaseSsl(socket: AsyncSocket, flags: set[SocketFlag],
|
||||
sslError: cint): owned(Future[bool]) {.async.} =
|
||||
proc handleSslFailure(socket: AsyncSocket, flags: set[SocketFlag], sslError: cint): Future[bool] =
|
||||
## Returns `true` if `socket` is still connected, otherwise `false`.
|
||||
result = true
|
||||
let retFut = newFuture[bool]("asyncnet.handleSslFailure")
|
||||
case sslError
|
||||
of SSL_ERROR_WANT_WRITE:
|
||||
await sendPendingSslData(socket, flags)
|
||||
of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
|
||||
addWrite(socket.fd.AsyncFD, proc (sock: AsyncFD): bool =
|
||||
retFut.complete(true)
|
||||
return true
|
||||
)
|
||||
of SSL_ERROR_WANT_READ:
|
||||
var data = await recv(socket.fd.AsyncFD, BufferSize, flags)
|
||||
let length = len(data)
|
||||
if length > 0:
|
||||
let ret = bioWrite(socket.bioIn, cast[cstring](addr data[0]), length.cint)
|
||||
if ret < 0:
|
||||
raiseSSLError()
|
||||
elif length == 0:
|
||||
# connection not properly closed by remote side or connection dropped
|
||||
SSL_set_shutdown(socket.sslHandle, SSL_RECEIVED_SHUTDOWN)
|
||||
result = false
|
||||
addRead(socket.fd.AsyncFD, proc (sock: AsyncFD): bool =
|
||||
retFut.complete(true)
|
||||
return true
|
||||
)
|
||||
of SSL_ERROR_SYSCALL:
|
||||
assert flags.isDisconnectionError(osLastError())
|
||||
retFut.complete(false)
|
||||
else:
|
||||
raiseSSLError("Cannot appease SSL.")
|
||||
raiseSSLError("Cannot handle SSL failure.")
|
||||
return retFut
|
||||
|
||||
template sslLoop(socket: AsyncSocket, flags: set[SocketFlag],
|
||||
op: untyped) =
|
||||
var opResult {.inject.} = -1.cint
|
||||
while opResult < 0:
|
||||
if socket.sslHandle == nil:
|
||||
raiseSslHandleError()
|
||||
ErrClearError()
|
||||
# Call the desired operation.
|
||||
opResult = op
|
||||
let err =
|
||||
if opResult < 0:
|
||||
getSslError(socket, opResult.cint)
|
||||
else:
|
||||
SSL_ERROR_NONE
|
||||
# Send any remaining pending SSL data.
|
||||
await sendPendingSslData(socket, flags)
|
||||
|
||||
# If the operation failed, try to see if SSL has some data to read
|
||||
# or write.
|
||||
if opResult < 0:
|
||||
let fut = appeaseSsl(socket, flags, err.cint)
|
||||
yield fut
|
||||
if not fut.read():
|
||||
let err = getSslError(socket, flags, opResult.cint)
|
||||
let connected = await handleSslFailure(socket, flags, err.cint)
|
||||
if not connected:
|
||||
# Socket disconnected.
|
||||
if SocketFlag.SafeDisconn in flags:
|
||||
opResult = 0.cint
|
||||
@@ -306,14 +307,15 @@ proc connect*(socket: AsyncSocket, address: string, port: Port) {.async.} =
|
||||
await connect(socket.fd.AsyncFD, address, port, socket.domain)
|
||||
if socket.isSsl:
|
||||
when defineSsl:
|
||||
if socket.sslHandle == nil:
|
||||
raiseSslHandleError()
|
||||
if not isIpAddress(address):
|
||||
# Set the SNI address for this connection. This call can fail if
|
||||
# we're not using TLSv1+.
|
||||
discard SSL_set_tlsext_host_name(socket.sslHandle, address)
|
||||
|
||||
let flags = {SocketFlag.SafeDisconn}
|
||||
sslSetConnectState(socket.sslHandle)
|
||||
sslLoop(socket, flags, sslDoHandshake(socket.sslHandle))
|
||||
sslLoop(socket, flags, SSL_connect(socket.sslHandle))
|
||||
|
||||
template readInto(buf: pointer, size: int, socket: AsyncSocket,
|
||||
flags: set[SocketFlag]): int =
|
||||
@@ -450,7 +452,6 @@ proc send*(socket: AsyncSocket, buf: pointer, size: int,
|
||||
when defineSsl:
|
||||
sslLoop(socket, flags,
|
||||
sslWrite(socket.sslHandle, cast[cstring](buf), size.cint))
|
||||
await sendPendingSslData(socket, flags)
|
||||
else:
|
||||
await send(socket.fd.AsyncFD, buf, size, flags)
|
||||
|
||||
@@ -464,52 +465,9 @@ proc send*(socket: AsyncSocket, data: string,
|
||||
var copy = data
|
||||
sslLoop(socket, flags,
|
||||
sslWrite(socket.sslHandle, cast[cstring](addr copy[0]), copy.len.cint))
|
||||
await sendPendingSslData(socket, flags)
|
||||
else:
|
||||
await send(socket.fd.AsyncFD, data, flags)
|
||||
|
||||
proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn},
|
||||
inheritable = defined(nimInheritHandles)):
|
||||
owned(Future[tuple[address: string, client: AsyncSocket]]) =
|
||||
## Accepts a new connection. Returns a future containing the client socket
|
||||
## corresponding to that connection and the remote address of the client.
|
||||
##
|
||||
## If `inheritable` is false (the default), the resulting client socket will
|
||||
## not be inheritable by child processes.
|
||||
##
|
||||
## The future will complete when the connection is successfully accepted.
|
||||
var retFuture = newFuture[tuple[address: string, client: AsyncSocket]]("asyncnet.acceptAddr")
|
||||
var fut = acceptAddr(socket.fd.AsyncFD, flags, inheritable)
|
||||
fut.callback =
|
||||
proc (future: Future[tuple[address: string, client: AsyncFD]]) =
|
||||
assert future.finished
|
||||
if future.failed:
|
||||
retFuture.fail(future.readError)
|
||||
else:
|
||||
let resultTup = (future.read.address,
|
||||
newAsyncSocket(future.read.client, socket.domain,
|
||||
socket.sockType, socket.protocol, socket.isBuffered, inheritable))
|
||||
retFuture.complete(resultTup)
|
||||
return retFuture
|
||||
|
||||
proc accept*(socket: AsyncSocket,
|
||||
flags = {SocketFlag.SafeDisconn}): owned(Future[AsyncSocket]) =
|
||||
## Accepts a new connection. Returns a future containing the client socket
|
||||
## corresponding to that connection.
|
||||
## If `inheritable` is false (the default), the resulting client socket will
|
||||
## not be inheritable by child processes.
|
||||
## The future will complete when the connection is successfully accepted.
|
||||
var retFut = newFuture[AsyncSocket]("asyncnet.accept")
|
||||
var fut = acceptAddr(socket, flags)
|
||||
fut.callback =
|
||||
proc (future: Future[tuple[address: string, client: AsyncSocket]]) =
|
||||
assert future.finished
|
||||
if future.failed:
|
||||
retFut.fail(future.readError)
|
||||
else:
|
||||
retFut.complete(future.read.client)
|
||||
return retFut
|
||||
|
||||
proc recvLineInto*(socket: AsyncSocket, resString: FutureVar[string],
|
||||
flags = {SocketFlag.SafeDisconn}, maxLength = MaxLineLength) {.async.} =
|
||||
## Reads a line of data from `socket` into `resString`.
|
||||
@@ -727,6 +685,8 @@ proc close*(socket: AsyncSocket) =
|
||||
defer:
|
||||
socket.fd.AsyncFD.closeSocket()
|
||||
socket.closed = true # TODO: Add extra debugging checks for this.
|
||||
when defineSsl:
|
||||
socket.sslHandle = nil
|
||||
|
||||
when defineSsl:
|
||||
if socket.isSsl:
|
||||
@@ -763,9 +723,8 @@ when defineSsl:
|
||||
if socket.sslHandle == nil:
|
||||
raiseSSLError()
|
||||
|
||||
socket.bioIn = bioNew(bioSMem())
|
||||
socket.bioOut = bioNew(bioSMem())
|
||||
sslSetBio(socket.sslHandle, socket.bioIn, socket.bioOut)
|
||||
if SSL_set_fd(socket.sslHandle, socket.fd) != 1:
|
||||
raiseSSLError()
|
||||
|
||||
socket.sslNoShutdown = true
|
||||
|
||||
@@ -782,6 +741,8 @@ when defineSsl:
|
||||
##
|
||||
## **Disclaimer**: This code is not well tested, may be very unsafe and
|
||||
## prone to security vulnerabilities.
|
||||
if socket.isSsl:
|
||||
return
|
||||
wrapSocket(ctx, socket)
|
||||
|
||||
case handshake
|
||||
@@ -805,6 +766,48 @@ when defineSsl:
|
||||
else:
|
||||
result = getPeerCertificates(socket.sslHandle)
|
||||
|
||||
proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn},
|
||||
inheritable = defined(nimInheritHandles)):
|
||||
owned(Future[tuple[address: string, client: AsyncSocket]]) {.async.} =
|
||||
## Accepts a new connection. Returns a future containing the client socket
|
||||
## corresponding to that connection and the remote address of the client.
|
||||
##
|
||||
## If `inheritable` is false (the default), the resulting client socket will
|
||||
## not be inheritable by child processes.
|
||||
##
|
||||
## The future will complete when the connection is successfully accepted.
|
||||
let (address, fd) = await acceptAddr(socket.fd.AsyncFD, flags, inheritable)
|
||||
let client = newAsyncSocket(fd, socket.domain, socket.sockType,
|
||||
socket.protocol, socket.isBuffered, inheritable)
|
||||
result = (address, client)
|
||||
if socket.isSsl:
|
||||
when defineSsl:
|
||||
if socket.sslContext == nil:
|
||||
raiseSSLError("The SSL Context is closed/unset")
|
||||
wrapSocket(socket.sslContext, result.client)
|
||||
if result.client.sslHandle == nil:
|
||||
raiseSslHandleError()
|
||||
let flags = {SocketFlag.SafeDisconn}
|
||||
sslLoop(result.client, flags, SSL_accept(result.client.sslHandle))
|
||||
|
||||
proc accept*(socket: AsyncSocket,
|
||||
flags = {SocketFlag.SafeDisconn}): owned(Future[AsyncSocket]) =
|
||||
## Accepts a new connection. Returns a future containing the client socket
|
||||
## corresponding to that connection.
|
||||
## If `inheritable` is false (the default), the resulting client socket will
|
||||
## not be inheritable by child processes.
|
||||
## The future will complete when the connection is successfully accepted.
|
||||
var retFut = newFuture[AsyncSocket]("asyncnet.accept")
|
||||
var fut = acceptAddr(socket, flags)
|
||||
fut.callback =
|
||||
proc (future: Future[tuple[address: string, client: AsyncSocket]]) =
|
||||
assert future.finished
|
||||
if future.failed:
|
||||
retFut.fail(future.readError)
|
||||
else:
|
||||
retFut.complete(future.read.client)
|
||||
return retFut
|
||||
|
||||
proc getSockOpt*(socket: AsyncSocket, opt: SOBool, level = SOL_SOCKET): bool {.
|
||||
tags: [ReadIOEffect].} =
|
||||
## Retrieves option `opt` as a boolean value.
|
||||
|
||||
@@ -231,6 +231,18 @@ func deduplicate*[T](s: openArray[T], isSorted: bool = false): seq[T] =
|
||||
for itm in items(s):
|
||||
if not result.contains(itm): result.add(itm)
|
||||
|
||||
proc min*[T](x: openArray[T], cmp: proc(a, b: T): int): T {.effectsOf: cmp.} =
|
||||
## The minimum value of `x`.
|
||||
result = x[0]
|
||||
for i in 1..high(x):
|
||||
if cmp(x[i], result) < 0: result = x[i]
|
||||
|
||||
proc max*[T](x: openArray[T], cmp: proc(a, b: T): int): T {.effectsOf: cmp.} =
|
||||
## The maximum value of `x`.
|
||||
result = x[0]
|
||||
for i in 1..high(x):
|
||||
if cmp(result, x[i]) < 0: result = x[i]
|
||||
|
||||
func minIndex*[T](s: openArray[T]): int {.since: (1, 1).} =
|
||||
## Returns the index of the minimum value of `s`.
|
||||
## `T` needs to have a `<` operator.
|
||||
@@ -248,6 +260,20 @@ func minIndex*[T](s: openArray[T]): int {.since: (1, 1).} =
|
||||
for i in 1..high(s):
|
||||
if s[i] < s[result]: result = i
|
||||
|
||||
func minIndex*[T](s: openArray[T], cmp: proc(a, b: T): int): int {.effectsOf: cmp.} =
|
||||
## Returns the index of the minimum value of `s`.
|
||||
runnableExamples:
|
||||
import std/sugar
|
||||
|
||||
let s1 = @["foo","bar", "hello"]
|
||||
let s2 = @[2..4, 1..3, 6..10]
|
||||
assert minIndex(s1, proc (a, b: string): int = a.len - b.len) == 0
|
||||
assert minIndex(s2, (a, b) => a.a - b.a) == 1
|
||||
|
||||
for i in 1..high(s):
|
||||
if cmp(s[i], s[result]) < 0: result = i
|
||||
|
||||
|
||||
func maxIndex*[T](s: openArray[T]): int {.since: (1, 1).} =
|
||||
## Returns the index of the maximum value of `s`.
|
||||
## `T` needs to have a `<` operator.
|
||||
@@ -265,15 +291,35 @@ func maxIndex*[T](s: openArray[T]): int {.since: (1, 1).} =
|
||||
for i in 1..high(s):
|
||||
if s[i] > s[result]: result = i
|
||||
|
||||
func maxIndex*[T](s: openArray[T], cmp: proc(a, b: T): int): int {.effectsOf: cmp.} =
|
||||
## Returns the index of the maximum value of `s`.
|
||||
runnableExamples:
|
||||
import std/sugar
|
||||
|
||||
let s1 = @["foo","bar", "hello"]
|
||||
let s2 = @[2..4, 1..3, 6..10]
|
||||
assert maxIndex(s1, proc (a, b: string): int = a.len - b.len) == 2
|
||||
assert maxIndex(s2, (a, b) => a.a - b.a) == 2
|
||||
|
||||
for i in 1..high(s):
|
||||
if cmp(s[result], s[i]) < 0: result = i
|
||||
|
||||
func minmax*[T](x: openArray[T]): (T, T) =
|
||||
## The minimum and maximum values of `x`. `T` needs to have a `<` operator.
|
||||
var l = x[0]
|
||||
var h = x[0]
|
||||
for i in 1..high(x):
|
||||
if x[i] < l: l = x[i]
|
||||
if h < x[i]: h = x[i]
|
||||
elif h < x[i]: h = x[i]
|
||||
result = (l, h)
|
||||
|
||||
func minmax*[T](x: openArray[T], cmp: proc(a, b: T): int): (T, T) {.effectsOf: cmp.} =
|
||||
## The minimum and maximum values of `x`.
|
||||
result = (x[0], x[0])
|
||||
for i in 1..high(x):
|
||||
if cmp(x[i], result[0]) < 0: result[0] = x[i]
|
||||
elif cmp(result[1], x[i]) < 0: result[1] = x[i]
|
||||
|
||||
|
||||
template zipImpl(s1, s2, retType: untyped): untyped =
|
||||
proc zip*[S, T](s1: openArray[S], s2: openArray[T]): retType =
|
||||
|
||||
@@ -30,7 +30,7 @@ proc rawGetDeep[X, A](t: X, key: A, hc: var Hash): int {.inline, outParamsAt: [3
|
||||
rawGetDeepImpl()
|
||||
|
||||
proc rawInsert[X, A, B](t: var X, data: var KeyValuePairSeq[A, B],
|
||||
key: A, val: sink B, hc: Hash, h: Hash) =
|
||||
key: sink A, val: sink B, hc: Hash, h: Hash) =
|
||||
rawInsertImpl()
|
||||
|
||||
template checkIfInitialized() =
|
||||
|
||||
@@ -107,7 +107,7 @@ runnableExamples:
|
||||
## container (e.g. string, sequence or array), as it is a mapping where the
|
||||
## items are the keys, and their number of occurrences are the values.
|
||||
## For that purpose `toCountTable proc<#toCountTable,openArray[A]>`_
|
||||
## comes handy:
|
||||
## comes in handy:
|
||||
|
||||
runnableExamples:
|
||||
let myString = "abracadabra"
|
||||
@@ -281,7 +281,7 @@ proc initTable*[A, B](initialSize = defaultInitialSize): Table[A, B] =
|
||||
result = default(Table[A, B])
|
||||
initImpl(result, initialSize)
|
||||
|
||||
proc `[]=`*[A, B](t: var Table[A, B], key: A, val: sink B) =
|
||||
proc `[]=`*[A, B](t: var Table[A, B], key: sink A, val: sink B) =
|
||||
## Inserts a `(key, value)` pair into `t`.
|
||||
##
|
||||
## See also:
|
||||
@@ -494,7 +494,7 @@ proc len*[A, B](t: Table[A, B]): int =
|
||||
|
||||
result = t.counter
|
||||
|
||||
proc add*[A, B](t: var Table[A, B], key: A, val: sink B) {.deprecated:
|
||||
proc add*[A, B](t: var Table[A, B], key: sink A, val: sink B) {.deprecated:
|
||||
"Deprecated since v1.4; it was more confusing than useful, use `[]=`".} =
|
||||
## Puts a new `(key, value)` pair into `t` even if `t[key]` already exists.
|
||||
##
|
||||
@@ -676,6 +676,68 @@ template withValue*[A, B](t: var Table[A, B], key: A,
|
||||
else:
|
||||
body2
|
||||
|
||||
template withValue*[A, B](t: Table[A, B], key: A,
|
||||
value, body1, body2: untyped) =
|
||||
## Retrieves the value at `t[key]` if it exists, assigns
|
||||
## it to the variable `value` and executes `body`
|
||||
runnableExamples:
|
||||
type
|
||||
User = object
|
||||
name: string
|
||||
|
||||
proc `=copy`(dest: var User, source: User) {.error.}
|
||||
|
||||
proc exec(t: Table[int, User]) =
|
||||
t.withValue(1, value):
|
||||
assert value.name == "Hello"
|
||||
do:
|
||||
doAssert false
|
||||
|
||||
var executedElseBranch = false
|
||||
t.withValue(521, value):
|
||||
doAssert false
|
||||
do:
|
||||
executedElseBranch = true
|
||||
assert executedElseBranch
|
||||
|
||||
var t = initTable[int, User]()
|
||||
t[1] = User(name: "Hello")
|
||||
t.exec()
|
||||
|
||||
mixin rawGet
|
||||
var hc: Hash
|
||||
var index = rawGet(t, key, hc)
|
||||
if index > 0:
|
||||
let value {.cursor, inject.} = t.data[index].val
|
||||
body1
|
||||
else:
|
||||
body2
|
||||
|
||||
template withValue*[A, B](t: Table[A, B], key: A,
|
||||
value, body: untyped) =
|
||||
## Retrieves the value at `t[key]` if it exists, assigns
|
||||
## it to the variable `value` and executes `body`
|
||||
runnableExamples:
|
||||
type
|
||||
User = object
|
||||
name: string
|
||||
|
||||
proc `=copy`(dest: var User, source: User) {.error.}
|
||||
|
||||
proc exec(t: Table[int, User]) =
|
||||
t.withValue(1, value):
|
||||
assert value.name == "Hello"
|
||||
|
||||
t.withValue(521, value):
|
||||
doAssert false
|
||||
|
||||
var t = initTable[int, User]()
|
||||
t[1] = User(name: "Hello")
|
||||
t.exec()
|
||||
|
||||
withValue(t, key, value, body):
|
||||
discard
|
||||
|
||||
|
||||
iterator pairs*[A, B](t: Table[A, B]): (lent A, lent B) =
|
||||
## Iterates over any `(key, value)` pair in the table `t`.
|
||||
@@ -888,7 +950,7 @@ proc `[]`*[A, B](t: TableRef[A, B], key: A): var B =
|
||||
|
||||
result = t[][key]
|
||||
|
||||
proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: sink B) =
|
||||
proc `[]=`*[A, B](t: TableRef[A, B], key: sink A, val: sink B) =
|
||||
## Inserts a `(key, value)` pair into `t`.
|
||||
##
|
||||
## See also:
|
||||
@@ -1045,7 +1107,7 @@ proc len*[A, B](t: TableRef[A, B]): int =
|
||||
|
||||
result = t.counter
|
||||
|
||||
proc add*[A, B](t: TableRef[A, B], key: A, val: sink B) {.deprecated:
|
||||
proc add*[A, B](t: TableRef[A, B], key: sink A, val: sink B) {.deprecated:
|
||||
"Deprecated since v1.4; it was more confusing than useful, use `[]=`".} =
|
||||
## Puts a new `(key, value)` pair into `t` even if `t[key]` already exists.
|
||||
##
|
||||
@@ -1297,7 +1359,7 @@ proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int =
|
||||
|
||||
proc rawInsert[A, B](t: var OrderedTable[A, B],
|
||||
data: var OrderedKeyValuePairSeq[A, B],
|
||||
key: A, val: sink B, hc: Hash, h: Hash) =
|
||||
key: sink A, val: sink B, hc: Hash, h: Hash) =
|
||||
rawInsertImpl()
|
||||
data[h].next = -1
|
||||
if t.first < 0: t.first = h
|
||||
@@ -1349,7 +1411,7 @@ proc initOrderedTable*[A, B](initialSize = defaultInitialSize): OrderedTable[A,
|
||||
result = default(OrderedTable[A, B])
|
||||
initImpl(result, initialSize)
|
||||
|
||||
proc `[]=`*[A, B](t: var OrderedTable[A, B], key: A, val: sink B) =
|
||||
proc `[]=`*[A, B](t: var OrderedTable[A, B], key: sink A, val: sink B) =
|
||||
## Inserts a `(key, value)` pair into `t`.
|
||||
##
|
||||
## See also:
|
||||
@@ -1547,7 +1609,7 @@ proc len*[A, B](t: OrderedTable[A, B]): int {.inline.} =
|
||||
|
||||
result = t.counter
|
||||
|
||||
proc add*[A, B](t: var OrderedTable[A, B], key: A, val: sink B) {.deprecated:
|
||||
proc add*[A, B](t: var OrderedTable[A, B], key: sink A, val: sink B) {.deprecated:
|
||||
"Deprecated since v1.4; it was more confusing than useful, use `[]=`".} =
|
||||
## Puts a new `(key, value)` pair into `t` even if `t[key]` already exists.
|
||||
##
|
||||
@@ -1907,7 +1969,7 @@ proc `[]`*[A, B](t: OrderedTableRef[A, B], key: A): var B =
|
||||
echo a['z']
|
||||
result = t[][key]
|
||||
|
||||
proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: A, val: sink B) =
|
||||
proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: sink A, val: sink B) =
|
||||
## Inserts a `(key, value)` pair into `t`.
|
||||
##
|
||||
## See also:
|
||||
@@ -2048,7 +2110,7 @@ proc len*[A, B](t: OrderedTableRef[A, B]): int {.inline.} =
|
||||
|
||||
result = t.counter
|
||||
|
||||
proc add*[A, B](t: OrderedTableRef[A, B], key: A, val: sink B) {.deprecated:
|
||||
proc add*[A, B](t: OrderedTableRef[A, B], key: sink A, val: sink B) {.deprecated:
|
||||
"Deprecated since v1.4; it was more confusing than useful, use `[]=`".} =
|
||||
## Puts a new `(key, value)` pair into `t` even if `t[key]` already exists.
|
||||
##
|
||||
@@ -2267,19 +2329,15 @@ iterator mvalues*[A, B](t: OrderedTableRef[A, B]): var B =
|
||||
yield t.data[h].val
|
||||
assert(len(t) == L, "the length of the table changed while iterating over it")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# ------------------------------ CountTable -------------------------------
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
type
|
||||
CountTable*[A] = object
|
||||
## Hash table that counts the number of each key.
|
||||
## Hash table that counts the number of each key. Unlike `Table<#Table>`_,
|
||||
## this uses a zero count to signal "empty" & so does not cache hash values
|
||||
## for comparison reduction or resize acceleration.
|
||||
##
|
||||
## For creating an empty CountTable, use `initCountTable proc
|
||||
## <#initCountTable>`_.
|
||||
@@ -2674,10 +2732,6 @@ iterator mvalues*[A](t: var CountTable[A]): var int =
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ---------------------------- CountTableRef --------------------------------
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -46,10 +46,10 @@ proc setFileSize(fh: FileHandle, newFileSize = -1, oldSize = -1): OSErrorCode =
|
||||
when defined(windows):
|
||||
var sizeHigh = int32(newFileSize shr 32)
|
||||
let sizeLow = int32(newFileSize and 0xffffffff)
|
||||
let status = setFilePointer(fh, sizeLow, addr(sizeHigh), FILE_BEGIN)
|
||||
let status = setFilePointer(Handle fh, sizeLow, addr(sizeHigh), FILE_BEGIN)
|
||||
let lastErr = osLastError()
|
||||
if (status == INVALID_SET_FILE_POINTER and lastErr.int32 != NO_ERROR) or
|
||||
setEndOfFile(fh) == 0:
|
||||
setEndOfFile(Handle fh) == 0:
|
||||
result = lastErr
|
||||
else:
|
||||
if newFileSize > oldSize: # grow the file
|
||||
|
||||
@@ -285,6 +285,19 @@ proc listen*(socket: SocketHandle, backlog = SOMAXCONN): cint {.tags: [
|
||||
else:
|
||||
result = posix.listen(socket, cint(backlog))
|
||||
|
||||
proc getAddrInfo*(address: string, port: Port, hints: AddrInfo): ptr AddrInfo =
|
||||
##
|
||||
##
|
||||
## .. warning:: The resulting `ptr AddrInfo` must be freed using `freeAddrInfo`!
|
||||
result = nil
|
||||
let socketPort = if hints.ai_socktype == toInt(SOCK_RAW): "" else: $port
|
||||
var gaiResult = getaddrinfo(address, socketPort.cstring, addr(hints), result)
|
||||
if gaiResult != 0'i32:
|
||||
when useWinVersion or defined(freertos) or defined(nuttx):
|
||||
raiseOSError(osLastError())
|
||||
else:
|
||||
raiseOSError(osLastError(), $gai_strerror(gaiResult))
|
||||
|
||||
proc getAddrInfo*(address: string, port: Port, domain: Domain = AF_INET,
|
||||
sockType: SockType = SOCK_STREAM,
|
||||
protocol: Protocol = IPPROTO_TCP): ptr AddrInfo =
|
||||
@@ -296,7 +309,7 @@ proc getAddrInfo*(address: string, port: Port, domain: Domain = AF_INET,
|
||||
ai_socktype: toInt(sockType),
|
||||
ai_protocol: toInt(protocol)
|
||||
)
|
||||
result = nil
|
||||
|
||||
# OpenBSD doesn't support AI_V4MAPPED and doesn't define the macro AI_V4MAPPED.
|
||||
# FreeBSD, Haiku don't support AI_V4MAPPED but defines the macro.
|
||||
# https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=198092
|
||||
@@ -305,13 +318,7 @@ proc getAddrInfo*(address: string, port: Port, domain: Domain = AF_INET,
|
||||
not defined(android) and not defined(haiku):
|
||||
if domain == AF_INET6:
|
||||
hints.ai_flags = AI_V4MAPPED
|
||||
let socketPort = if sockType == SOCK_RAW: "" else: $port
|
||||
var gaiResult = getaddrinfo(address, socketPort.cstring, addr(hints), result)
|
||||
if gaiResult != 0'i32:
|
||||
when useWinVersion or defined(freertos) or defined(nuttx):
|
||||
raiseOSError(osLastError())
|
||||
else:
|
||||
raiseOSError(osLastError(), $gai_strerror(gaiResult))
|
||||
result = getAddrInfo(address, port, hints)
|
||||
|
||||
proc ntohl*(x: uint32): uint32 =
|
||||
## Converts 32-bit unsigned integers from network to host byte order.
|
||||
@@ -723,7 +730,7 @@ when useNimNetLite:
|
||||
##
|
||||
## Similar to POSIX's `getsockname`:idx:.
|
||||
template sockGetNameOrRaiseError(socket: untyped, name: untyped) =
|
||||
var namelen = sizeof(socket).SockLen
|
||||
var namelen = sizeof(name).SockLen
|
||||
if getsockname(socket, cast[ptr SockAddr](addr(name)),
|
||||
addr(namelen)) == -1'i32:
|
||||
raiseOSError(osLastError())
|
||||
|
||||
@@ -845,11 +845,11 @@ when weirdTarget or defined(windows) or defined(posix) or defined(nintendoswitch
|
||||
result = default(FileInfo)
|
||||
when defined(windows):
|
||||
var rawInfo: BY_HANDLE_FILE_INFORMATION
|
||||
# We have to use the super special '_get_osfhandle' call (wrapped above)
|
||||
# We have to use the super special '_get_osfhandle' call (wrapped in winlean)
|
||||
# To transform the C file descriptor to a native file handle.
|
||||
var realHandle = get_osfhandle(handle)
|
||||
var realHandle = get_osfhandle(handle.cint)
|
||||
if getFileInformationByHandle(realHandle, addr rawInfo) == 0:
|
||||
raiseOSError(osLastError(), $handle)
|
||||
raiseOSError(osLastError(), $(int handle))
|
||||
rawToFormalFileInfo(rawInfo, "", result)
|
||||
else:
|
||||
var rawInfo: Stat = default(Stat)
|
||||
|
||||
@@ -546,8 +546,8 @@ when defined(windows) and not defined(useNimRtl):
|
||||
raiseOSError(osLastError())
|
||||
|
||||
proc fileClose[T: Handle | FileHandle](h: var T) {.inline.} =
|
||||
if h > 4:
|
||||
closeHandleCheck(h)
|
||||
if h.int > 4:
|
||||
closeHandleCheck(Handle h)
|
||||
h = INVALID_HANDLE_VALUE.T
|
||||
|
||||
proc hsClose(s: Stream) =
|
||||
@@ -574,8 +574,8 @@ when defined(windows) and not defined(useNimRtl):
|
||||
addr bytesWritten, nil)
|
||||
if a == 0: raiseOSError(osLastError())
|
||||
|
||||
proc newFileHandleStream(handle: Handle): owned FileHandleStream =
|
||||
result = FileHandleStream(handle: handle, closeImpl: hsClose, atEndImpl: hsAtEnd,
|
||||
proc newFileHandleStream(handle: FileHandle): owned FileHandleStream =
|
||||
result = FileHandleStream(handle: Handle handle, closeImpl: hsClose, atEndImpl: hsAtEnd,
|
||||
readDataImpl: hsReadData, writeDataImpl: hsWriteData)
|
||||
|
||||
proc buildCommandLine(a: string, args: openArray[string]): string =
|
||||
@@ -888,7 +888,7 @@ when defined(windows) and not defined(useNimRtl):
|
||||
assert readfds.len <= MAXIMUM_WAIT_OBJECTS
|
||||
var rfds: WOHandleArray
|
||||
for i in 0..readfds.len()-1:
|
||||
rfds[i] = readfds[i].outHandle #fProcessHandle
|
||||
rfds[i] = readfds[i].outHandle.Handle #fProcessHandle
|
||||
|
||||
var ret = waitForMultipleObjects(readfds.len.int32,
|
||||
addr(rfds), 0'i32, timeout.int32)
|
||||
@@ -904,7 +904,7 @@ when defined(windows) and not defined(useNimRtl):
|
||||
|
||||
proc hasData*(p: Process): bool =
|
||||
var x: int32
|
||||
if peekNamedPipe(p.outHandle, lpTotalBytesAvail = addr x):
|
||||
if peekNamedPipe(p.outHandle.Handle, lpTotalBytesAvail = addr x):
|
||||
result = x > 0
|
||||
|
||||
elif not defined(useNimRtl):
|
||||
|
||||
@@ -540,10 +540,17 @@ proc loadConfig*(stream: Stream, filename: string = "[stream]"): Config =
|
||||
|
||||
proc loadConfig*(filename: string): Config =
|
||||
## Loads the specified configuration file into a new Config instance.
|
||||
let file = open(filename, fmRead)
|
||||
let fileStream = newFileStream(file)
|
||||
defer: fileStream.close()
|
||||
result = fileStream.loadConfig(filename)
|
||||
when nimvm:
|
||||
# HACK: As a workaround,
|
||||
# since open() using {.importc.} is not available on NimScript.
|
||||
let stringStream = newStringStream(readFile(filename))
|
||||
defer: stringStream.close()
|
||||
result = stringStream.loadConfig(filename)
|
||||
else:
|
||||
let file = open(filename, fmRead)
|
||||
let fileStream = newFileStream(file)
|
||||
defer: fileStream.close()
|
||||
result = fileStream.loadConfig(filename)
|
||||
|
||||
proc replace(s: string): string =
|
||||
var d = ""
|
||||
|
||||
@@ -105,7 +105,8 @@ proc newPipeOutStream*[T](s: sink (ref T)): owned PipeOutStream[T] =
|
||||
new(result)
|
||||
for dest, src in fields((ref T)(result)[], s[]):
|
||||
dest = src
|
||||
wasMoved(s[])
|
||||
{.cast(raises: []), cast(tags: []).}:
|
||||
wasMoved(s[])
|
||||
if result.readLineImpl != nil:
|
||||
result.baseReadLineImpl = result.readLineImpl
|
||||
result.readLineImpl = posReadLine[T]
|
||||
|
||||
@@ -512,7 +512,7 @@ macro scanTuple*(input: untyped; pattern: static[string]; matcherTypes: varargs[
|
||||
inc userMatches
|
||||
else: discard
|
||||
inc p
|
||||
result.add nnkTupleConstr.newTree(newCall(ident("scanf"), input, newStrLitNode(pattern)))
|
||||
result.add nnkTupleConstr.newTree(newCall(bindSym("scanf"), input, newStrLitNode(pattern)))
|
||||
for arg in arguments:
|
||||
result[^1][0].add arg
|
||||
result[^1].add arg
|
||||
|
||||
@@ -1081,7 +1081,7 @@ func fromBin*[T: SomeInteger](s: string): T =
|
||||
doAssert fromBin[uint8](s) == 153
|
||||
doAssert s.fromBin[:int16] == 0b1110_1110_1001_1001'i16
|
||||
doAssert s.fromBin[:uint64] == 1216933529'u64
|
||||
|
||||
result = T(0)
|
||||
let p = parseutils.parseBin(s, result)
|
||||
if p != s.len or p == 0:
|
||||
raise newException(ValueError, "invalid binary integer: " & s)
|
||||
@@ -1104,7 +1104,7 @@ func fromOct*[T: SomeInteger](s: string): T =
|
||||
doAssert fromOct[uint8](s) == 255'u8
|
||||
doAssert s.fromOct[:int16] == 24063'i16
|
||||
doAssert s.fromOct[:uint64] == 21913087'u64
|
||||
|
||||
result = T(0)
|
||||
let p = parseutils.parseOct(s, result)
|
||||
if p != s.len or p == 0:
|
||||
raise newException(ValueError, "invalid oct integer: " & s)
|
||||
@@ -1127,7 +1127,7 @@ func fromHex*[T: SomeInteger](s: string): T =
|
||||
doAssert fromHex[uint8](s) == 246'u8
|
||||
doAssert s.fromHex[:int16] == -29194'i16
|
||||
doAssert s.fromHex[:uint64] == 305499638'u64
|
||||
|
||||
result = T(0)
|
||||
let p = parseutils.parseHex(s, result)
|
||||
if p != s.len or p == 0:
|
||||
raise newException(ValueError, "invalid hex integer: " & s)
|
||||
@@ -2202,7 +2202,8 @@ func replace*(s, sub: string, by = ""): string {.rtl,
|
||||
## * `replace func<#replace,string,char,char>`_ for replacing
|
||||
## single characters
|
||||
## * `replaceWord func<#replaceWord,string,string,string>`_
|
||||
## * `multiReplace func<#multiReplace,string,varargs[]>`_
|
||||
## * `multiReplace func<#multiReplace,string,varargs[]>`_ for substrings
|
||||
## * `multiReplace func<#multiReplace,openArray[char],varargs[]>`_ for single characters
|
||||
result = ""
|
||||
let subLen = sub.len
|
||||
if subLen == 0:
|
||||
@@ -2245,7 +2246,8 @@ func replace*(s: string, sub, by: char): string {.rtl,
|
||||
## See also:
|
||||
## * `find func<#find,string,char,Natural,int>`_
|
||||
## * `replaceWord func<#replaceWord,string,string,string>`_
|
||||
## * `multiReplace func<#multiReplace,string,varargs[]>`_
|
||||
## * `multiReplace func<#multiReplace,string,varargs[]>`_ for substrings
|
||||
## * `multiReplace func<#multiReplace,openArray[char],varargs[]>`_ for single characters
|
||||
result = newString(s.len)
|
||||
var i = 0
|
||||
while i < s.len:
|
||||
@@ -2330,7 +2332,38 @@ func multiReplace*(s: string, replacements: varargs[(string, string)]): string =
|
||||
add result, s[i]
|
||||
inc(i)
|
||||
|
||||
|
||||
func multiReplace*(s: openArray[char]; replacements: varargs[(set[char], char)]): string {.noinit.} =
|
||||
## Performs multiple character replacements in a single pass through the input.
|
||||
##
|
||||
## `multiReplace` scans the input `s` from left to right and replaces
|
||||
## characters based on character sets, applying the first matching replacement
|
||||
## at each position. Useful for sanitizing or transforming strings with
|
||||
## predefined character mappings.
|
||||
##
|
||||
## The order of the `replacements` matters:
|
||||
## - First matching replacement is applied
|
||||
## - Subsequent replacements are not considered for the same character
|
||||
##
|
||||
## See also:
|
||||
## - `multiReplace(s: string; replacements: varargs[(string, string)]) <#multiReplace,string,varargs[]>`_,
|
||||
runnableExamples:
|
||||
const WinSanitationRules = [
|
||||
({'\0'..'\31'}, ' '),
|
||||
({'"'}, '\''),
|
||||
({'/', '\\', ':', '|'}, '-'),
|
||||
({'*', '?', '<', '>'}, '_'),
|
||||
]
|
||||
# Sanitize a filename with Windows-incompatible characters
|
||||
const file = "a/file:with?invalid*chars.txt"
|
||||
doAssert file.multiReplace(WinSanitationRules) == "a-file-with_invalid_chars.txt"
|
||||
result = newStringUninit(s.len)
|
||||
for i in 0..<s.len:
|
||||
var nextChar = s[i]
|
||||
for subs, by in replacements.items:
|
||||
if nextChar in subs:
|
||||
nextChar = by
|
||||
break
|
||||
result[i] = nextChar
|
||||
|
||||
func insertSep*(s: string, sep = '_', digits = 3): string {.rtl,
|
||||
extern: "nsuInsertSep".} =
|
||||
|
||||
@@ -805,9 +805,13 @@ proc isatty*(f: File): bool =
|
||||
when defined(posix):
|
||||
proc isatty(fildes: FileHandle): cint {.
|
||||
importc: "isatty", header: "<unistd.h>".}
|
||||
else:
|
||||
proc isatty(fildes: FileHandle): cint {.
|
||||
elif defined(windows):
|
||||
proc c_isatty(fildes: cint): cint {.
|
||||
importc: "_isatty", header: "<io.h>".}
|
||||
proc isatty(fildes: FileHandle): cint =
|
||||
c_isatty(cint(fildes))
|
||||
else:
|
||||
{.error: "isatty is not supported on your operating system!".}
|
||||
|
||||
result = isatty(getFileHandle(f)) != 0'i32
|
||||
|
||||
|
||||
@@ -2016,7 +2016,6 @@ proc parsePattern(input: string, pattern: FormatPattern, i: var int,
|
||||
var year = takeInt(2..2)
|
||||
var thisCen = now().year div 100
|
||||
parsed.year = some(thisCen*100 + year)
|
||||
result = year > 0
|
||||
of yyyy:
|
||||
let year =
|
||||
if input[i] in {'+', '-'}:
|
||||
|
||||
@@ -556,15 +556,16 @@ template test*(name, body) {.dirty.} =
|
||||
body
|
||||
{.pop.}
|
||||
|
||||
except:
|
||||
except Exception:
|
||||
let e = getCurrentException()
|
||||
let eTypeDesc = "[" & exceptionTypeName(e) & "]"
|
||||
checkpoint("Unhandled exception: " & getCurrentExceptionMsg() & " " & eTypeDesc)
|
||||
if e == nil: # foreign
|
||||
fail()
|
||||
else:
|
||||
var stackTrace {.inject.} = e.getStackTrace()
|
||||
fail()
|
||||
var stackTrace {.inject.} = e.getStackTrace()
|
||||
fail()
|
||||
|
||||
except:
|
||||
checkpoint("Unhandled exception: " & getCurrentExceptionMsg() & " [<foreign exception>]")
|
||||
fail()
|
||||
|
||||
finally:
|
||||
if testStatusIMPL == TestStatus.FAILED:
|
||||
@@ -760,6 +761,14 @@ macro expect*(exceptions: varargs[typed], body: untyped): untyped =
|
||||
expect IOError, OSError, ValueError, AssertionDefect:
|
||||
defectiveRobot()
|
||||
|
||||
template expectException(errorTypes, lineInfoLit, body): NimNode {.dirty.} =
|
||||
try:
|
||||
body
|
||||
checkpoint(lineInfoLit & ": Expect Failed, no exception was thrown.")
|
||||
fail()
|
||||
except errorTypes:
|
||||
discard
|
||||
|
||||
template expectBody(errorTypes, lineInfoLit, body): NimNode {.dirty.} =
|
||||
{.push warning[BareExcept]:off.}
|
||||
try:
|
||||
@@ -770,17 +779,23 @@ macro expect*(exceptions: varargs[typed], body: untyped): untyped =
|
||||
fail()
|
||||
except errorTypes:
|
||||
discard
|
||||
except:
|
||||
except Exception:
|
||||
let err = getCurrentException()
|
||||
checkpoint(lineInfoLit & ": Expect Failed, " & $err.name & " was thrown.")
|
||||
fail()
|
||||
{.pop.}
|
||||
|
||||
var errorTypes = newNimNode(nnkBracket)
|
||||
var hasException = false
|
||||
for exp in exceptions:
|
||||
if exp.strVal == "Exception":
|
||||
hasException = true
|
||||
errorTypes.add(exp)
|
||||
|
||||
result = getAst(expectBody(errorTypes, errorTypes.lineInfo, body))
|
||||
if hasException:
|
||||
result = getAst(expectException(errorTypes, errorTypes.lineInfo, body))
|
||||
else:
|
||||
result = getAst(expectBody(errorTypes, errorTypes.lineInfo, body))
|
||||
|
||||
proc disableParamFiltering* =
|
||||
## disables filtering tests with the command line params
|
||||
|
||||
@@ -40,9 +40,6 @@ type
|
||||
## at the end. If the file does not exist, it
|
||||
## will be created.
|
||||
|
||||
FileHandle* = cint ## The type that represents an OS file handle; this is
|
||||
## useful for low-level file access.
|
||||
|
||||
FileSeekPos* = enum ## Position relative to which seek should happen.
|
||||
# The values are ordered so that they match with stdio
|
||||
# SEEK_SET, SEEK_CUR and SEEK_END respectively.
|
||||
@@ -50,6 +47,13 @@ type
|
||||
fspCur ## Seek relative to current position
|
||||
fspEnd ## Seek relative to end
|
||||
|
||||
when defined(windows):
|
||||
type FileHandle* = int
|
||||
## Windows `HANDLE` type, convertible to `winlean.Handle`.
|
||||
else:
|
||||
type FileHandle* = cint ## The type that represents an OS file handle; this is
|
||||
## useful for low-level file access.
|
||||
|
||||
# text file handling:
|
||||
when not defined(nimscript) and not defined(js):
|
||||
# duplicated between io and ansi_c
|
||||
@@ -310,12 +314,7 @@ elif defined(windows):
|
||||
proc getOsfhandle(fd: cint): int {.
|
||||
importc: "_get_osfhandle", header: "<io.h>".}
|
||||
|
||||
type
|
||||
IoHandle = distinct pointer
|
||||
## Windows' HANDLE type. Defined as an untyped pointer but is **not**
|
||||
## one. Named like this to avoid collision with other `system` modules.
|
||||
|
||||
proc setHandleInformation(hObject: IoHandle, dwMask, dwFlags: WinDWORD):
|
||||
proc setHandleInformation(hObject: FileHandle, dwMask, dwFlags: WinDWORD):
|
||||
WinBOOL {.stdcall, dynlib: "kernel32",
|
||||
importc: "SetHandleInformation".}
|
||||
|
||||
@@ -361,7 +360,7 @@ proc getFileHandle*(f: File): FileHandle =
|
||||
## Note that on Windows this doesn't return the Windows-specific handle,
|
||||
## but the C library's notion of a handle, whatever that means.
|
||||
## Use `getOsFileHandle` instead.
|
||||
c_fileno(f)
|
||||
FileHandle c_fileno(f)
|
||||
|
||||
proc getOsFileHandle*(f: File): FileHandle =
|
||||
## Returns the OS file handle of the file `f`. This is only useful for
|
||||
@@ -390,7 +389,7 @@ when defined(nimdoc) or (defined(posix) and not defined(nimscript)) or defined(w
|
||||
flags = if inheritable: flags and not FD_CLOEXEC else: flags or FD_CLOEXEC
|
||||
result = c_fcntl(f, F_SETFD, flags) != -1
|
||||
else:
|
||||
result = setHandleInformation(cast[IoHandle](f), HANDLE_FLAG_INHERIT,
|
||||
result = setHandleInformation(f, HANDLE_FLAG_INHERIT,
|
||||
inheritable.WinDWORD) != 0
|
||||
|
||||
proc readLine*(f: File, line: var string): bool {.tags: [ReadIOEffect],
|
||||
@@ -423,12 +422,18 @@ proc readLine*(f: File, line: var string): bool {.tags: [ReadIOEffect],
|
||||
importc: "LocalFree", stdcall, dynlib: "kernel32".}
|
||||
|
||||
proc isatty(f: File): bool =
|
||||
# terminal module also has isatty
|
||||
when defined(posix):
|
||||
proc isatty(fildes: FileHandle): cint {.
|
||||
importc: "isatty", header: "<unistd.h>".}
|
||||
else:
|
||||
proc isatty(fildes: FileHandle): cint {.
|
||||
elif defined(windows):
|
||||
proc c_isatty(fildes: cint): cint {.
|
||||
importc: "_isatty", header: "<io.h>".}
|
||||
proc isatty(fildes: FileHandle): cint =
|
||||
c_isatty(cint(fildes))
|
||||
else:
|
||||
{.error: "isatty is not supported on your operating system!".}
|
||||
|
||||
result = isatty(getFileHandle(f)) != 0'i32
|
||||
|
||||
# this implies the file is open
|
||||
@@ -769,10 +774,10 @@ proc open*(f: var File, filehandle: FileHandle,
|
||||
## The passed file handle will no longer be inheritable.
|
||||
when not defined(nimInheritHandles) and declared(setInheritable):
|
||||
let oshandle = when defined(windows): FileHandle getOsfhandle(
|
||||
filehandle) else: filehandle
|
||||
cint filehandle) else: filehandle
|
||||
if not setInheritable(oshandle, false):
|
||||
return false
|
||||
f = c_fdopen(filehandle, RawFormatOpen[mode])
|
||||
f = c_fdopen(cint filehandle, RawFormatOpen[mode])
|
||||
result = f != nil
|
||||
|
||||
proc open*(filename: string,
|
||||
|
||||
185
lib/system.nim
185
lib/system.nim
@@ -161,12 +161,10 @@ else:
|
||||
proc `=wasMoved`*[T](obj: var T) {.magic: "WasMoved", noSideEffect.} =
|
||||
## Generic `wasMoved`:idx: implementation that can be overridden.
|
||||
|
||||
proc wasMoved*[T](obj: var T) {.inline, noSideEffect.} =
|
||||
proc wasMoved*[T](obj: var T) {.magic: "WasMoved", noSideEffect.}
|
||||
## Resets an object `obj` to its initial (binary zero) value to signify
|
||||
## it was "moved" and to signify its destructor should do nothing and
|
||||
## ideally be optimized away.
|
||||
{.cast(raises: []), cast(tags: []).}:
|
||||
`=wasMoved`(obj)
|
||||
|
||||
proc move*[T](x: var T): T {.magic: "Move", noSideEffect.} =
|
||||
result = x
|
||||
@@ -1618,7 +1616,7 @@ when not defined(js) and defined(nimV2):
|
||||
align: int16
|
||||
depth: int16
|
||||
display: ptr UncheckedArray[uint32] # classToken
|
||||
when defined(nimTypeNames) or defined(nimArcIds):
|
||||
when defined(nimTypeNames) or defined(nimArcIds) or defined(nimOrcLeakDetector):
|
||||
name: cstring
|
||||
traceImpl: pointer
|
||||
typeInfoV1: pointer # for backwards compat, usually nil
|
||||
@@ -1685,7 +1683,7 @@ when not defined(js):
|
||||
else:
|
||||
{.error: "The type T cannot contain managed memory or have destructors".}
|
||||
|
||||
proc newStringUninit*(len: Natural): string =
|
||||
proc newStringUninit*(len: Natural): string {.noSideEffect.} =
|
||||
## Returns a new string of length `len` but with uninitialized
|
||||
## content. One needs to fill the string character after character
|
||||
## with the index operator `s[i]`.
|
||||
@@ -1696,15 +1694,16 @@ when not defined(js):
|
||||
result = newString(len)
|
||||
else:
|
||||
result = newStringOfCap(len)
|
||||
when defined(nimSeqsV2):
|
||||
let s = cast[ptr NimStringV2](addr result)
|
||||
if len > 0:
|
||||
{.cast(noSideEffect).}:
|
||||
when defined(nimSeqsV2):
|
||||
let s = cast[ptr NimStringV2](addr result)
|
||||
if len > 0:
|
||||
s.len = len
|
||||
s.p.data[len] = '\0'
|
||||
else:
|
||||
let s = cast[NimString](result)
|
||||
s.len = len
|
||||
s.p.data[len] = '\0'
|
||||
else:
|
||||
let s = cast[NimString](result)
|
||||
s.len = len
|
||||
s.data[len] = '\0'
|
||||
s.data[len] = '\0'
|
||||
else:
|
||||
proc newStringUninit*(len: Natural): string {.
|
||||
magic: "NewString", importc: "mnewString", noSideEffect.}
|
||||
@@ -2311,8 +2310,16 @@ when notJSnotNims and hostOS != "standalone":
|
||||
##
|
||||
## .. warning:: Only use this if you know what you are doing.
|
||||
currException = exc
|
||||
|
||||
proc raiseDefect() {.compilerRtl.} =
|
||||
let e = getCurrentException()
|
||||
if e of Defect:
|
||||
reportUnhandledError(e)
|
||||
rawQuit(1)
|
||||
|
||||
elif defined(nimscript):
|
||||
proc getCurrentException*(): ref Exception {.compilerRtl.} = discard
|
||||
proc raiseDefect*() {.compilerRtl.} = discard
|
||||
|
||||
when notJSnotNims:
|
||||
{.push stackTrace: off, profiler: off.}
|
||||
@@ -2715,16 +2722,54 @@ proc procCall*(x: untyped) {.magic: "ProcCall", compileTime.} =
|
||||
## ```
|
||||
discard
|
||||
|
||||
proc strcmp(a, b: cstring): cint {.noSideEffect,
|
||||
importc, header: "<string.h>".}
|
||||
|
||||
proc `==`*(x, y: cstring): bool {.magic: "EqCString", noSideEffect,
|
||||
inline.} =
|
||||
## Checks for equality between two `cstring` variables.
|
||||
proc strcmp(a, b: cstring): cint {.noSideEffect,
|
||||
importc, header: "<string.h>".}
|
||||
if pointer(x) == pointer(y): result = true
|
||||
elif pointer(x) == nil or pointer(y) == nil: result = false
|
||||
else: result = strcmp(x, y) == 0
|
||||
|
||||
func ltCStringVm(x, y: cstring): bool {.inline.} =
|
||||
discard "implemented in the vm ops"
|
||||
|
||||
func leCStringVm(x, y: cstring): bool {.inline.} =
|
||||
discard "implemented in the vm ops"
|
||||
|
||||
when defined(nimPreviewCStringComparisons):
|
||||
func `<`*(x, y: cstring): bool {.inline.} =
|
||||
if x == y:
|
||||
result = false
|
||||
elif x == nil:
|
||||
result = true
|
||||
elif y == nil:
|
||||
result = false
|
||||
else:
|
||||
when nimvm:
|
||||
result = ltCStringVm(x, y)
|
||||
else:
|
||||
when defined(js):
|
||||
result = pointer(x) < pointer(y)
|
||||
else:
|
||||
result = strcmp(x, y) < 0
|
||||
|
||||
func `<=`*(x, y: cstring): bool {.inline.} =
|
||||
if x == y: result = true
|
||||
elif x == nil:
|
||||
result = true
|
||||
elif y == nil:
|
||||
result = false
|
||||
else:
|
||||
when nimvm:
|
||||
result = leCStringVm(x, y)
|
||||
else:
|
||||
when defined(js):
|
||||
result = pointer(x) <= pointer(y)
|
||||
else:
|
||||
result = strcmp(x, y) <= 0
|
||||
|
||||
template closureScope*(body: untyped): untyped =
|
||||
## Useful when creating a closure in a loop to capture local loop variables by
|
||||
## their current iteration values.
|
||||
@@ -2769,41 +2814,87 @@ template once*(body: untyped): untyped =
|
||||
|
||||
{.pop.} # warning[GcMem]: off, warning[Uninit]: off
|
||||
|
||||
proc substr*(s: openArray[char]): string =
|
||||
## Copies a slice of `s` into a new string and returns this new
|
||||
## string.
|
||||
runnableExamples:
|
||||
let a = "abcdefgh"
|
||||
assert a.substr(2, 5) == "cdef"
|
||||
assert a.substr(2) == "cdefgh"
|
||||
assert a.substr(5, 99) == "fgh"
|
||||
result = newString(s.len)
|
||||
for i, ch in s:
|
||||
result[i] = ch
|
||||
template NotJSnotVMnotNims(): static bool = # hack, see: #12517 #12518
|
||||
when nimvm:
|
||||
false
|
||||
else:
|
||||
notJSnotNims
|
||||
|
||||
proc substr*(s: string, first, last: int): string = # A bug with `magic: Slice` requires this to exist this way
|
||||
## Copies a slice of `s` into a new string and returns this new
|
||||
## string.
|
||||
proc substr*(a: openArray[char]): string =
|
||||
## Returns a new string, copying contents of `a`.
|
||||
##
|
||||
## The bounds `first` and `last` denote the indices of
|
||||
## the first and last characters that shall be copied. If `last`
|
||||
## is omitted, it is treated as `high(s)`. If `last >= s.len`, `s.len`
|
||||
## is used instead: This means `substr` can also be used to `cut`:idx:
|
||||
## or `limit`:idx: a string's length.
|
||||
## .. warning:: As opposed to other `substr` overloads, no additional input
|
||||
## validation and clamping is performed!
|
||||
##
|
||||
## This proc does not prevent raising an `IndexDefect` when `a` is being
|
||||
## passed using a `toOpenArray` call with out-of-bounds indexes:
|
||||
## * `doAssertRaises(IndexDefect): discard "abc".toOpenArray(-9, 9).substr()`
|
||||
##
|
||||
## If clamping is required, consider using
|
||||
## `substr(s: string; first, last: int) <#substr,string,int,int>`_:
|
||||
## * `doAssert "abc".substr(-9, 9) == "abc"`
|
||||
runnableExamples:
|
||||
let a = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
|
||||
assert a.substr() == "abcdefgh"
|
||||
assert a.toOpenArray(2, 5).substr() == "cdef"
|
||||
assert a.toOpenArray(2, high(a)).substr() == "cdefgh" # From index 2 to `high(a)`
|
||||
doAssertRaises(IndexDefect): discard a.toOpenArray(5, 99).substr()
|
||||
result = newStringUninit(a.len)
|
||||
when NotJSnotVMnotNims:
|
||||
if a.len > 0:
|
||||
copyMem(result[0].addr, a[0].unsafeAddr, a.len)
|
||||
else:
|
||||
for i, ch in a:
|
||||
result[i] = ch
|
||||
|
||||
proc substr*(s: string; first, last: int): string = # A bug with `magic: Slice` requires this to exist this way
|
||||
## Returns a new string containing a substring (slice) of `s`,
|
||||
## copying characters from index `first` to index `last` inclusive.
|
||||
##
|
||||
## Index values are validated and capped:
|
||||
## - Negative `first` is clamped to 0
|
||||
## - If `last >= s.len`, it is clamped to `high(s)`
|
||||
## - If `last < first`, returns an empty string
|
||||
## This means `substr` can also be used to `cut`:idx: or `limit`:idx:
|
||||
## a string's length.
|
||||
##
|
||||
## .. note::
|
||||
## If index values are ensured to be in-bounds, for performance
|
||||
## critical cases consider using a non-clamping overload
|
||||
## `substr(a: openArray[char]) <#substr,openArray[char]>`_
|
||||
runnableExamples:
|
||||
let a = "abcdefgh"
|
||||
assert a.substr(2, 5) == "cdef"
|
||||
assert a.substr(2) == "cdefgh"
|
||||
assert a.substr(5, 99) == "fgh"
|
||||
|
||||
let first = max(first, 0)
|
||||
let L = max(min(last, high(s)) - first + 1, 0)
|
||||
result = newString(L)
|
||||
for i in 0 .. L-1:
|
||||
result[i] = s[i+first]
|
||||
assert a.substr(2, 5) == "cdef" # Normal substring
|
||||
# Invalid indexes
|
||||
assert a.substr(5, 99) == "fgh" # From index 5 to `high(a)`
|
||||
assert a.substr(42, 99) == "" # `first` out of bounds
|
||||
assert a.substr(100, 5) == "" # `first > last`
|
||||
assert a.substr(-1, 2) == "abc" # Negative `first` clamped to 0
|
||||
let
|
||||
first = max(first, 0)
|
||||
last = min(last, high(s))
|
||||
L = max(last - first + 1, 0)
|
||||
result = newStringUninit(L)
|
||||
when NotJSnotVMnotNims:
|
||||
if L > 0:
|
||||
copyMem(result[0].addr, s[first].unsafeAddr, L)
|
||||
else:
|
||||
for i in 0..<L:
|
||||
result[i] = s[i + first]
|
||||
|
||||
proc substr*(s: string, first = 0): string =
|
||||
result = substr(s, first, high(s))
|
||||
## Convenience `substr <#substr,string,int,int>`_ overload that returns
|
||||
## a substring from `first` to the end of the string.
|
||||
##
|
||||
## `first` value is validated and capped:
|
||||
## - `first >= s.len` returns an empty string
|
||||
## - Negative `first` is clamped to 0.
|
||||
runnableExamples:
|
||||
let a = "abcdefgh"
|
||||
assert a.substr(2) == "cdefgh" # From index 2 to string end (`high(a)`)
|
||||
assert a.substr(100) == "" # `first` out of bounds
|
||||
assert a.substr(-1) == "abcdefgh" # Negative `first` clamped to 0
|
||||
substr(s, first, high(s))
|
||||
|
||||
when defined(nimconfig):
|
||||
include "system/nimscript"
|
||||
@@ -2818,8 +2909,10 @@ when not defined(js):
|
||||
|
||||
proc toOpenArray*[T](x: seq[T]; first, last: int): openArray[T] {.
|
||||
magic: "Slice".}
|
||||
## Allows passing the slice of `x` from the element at `first` to the element
|
||||
## at `last` to `openArray[T]` parameters without copying it.
|
||||
## Returns a non-owning slice (a `view`:idx:) of `x` from the element at
|
||||
## index `first` to `last` inclusive. Allows passing slices without copying,
|
||||
## as opposed to using the slice operator
|
||||
## `\`[]\` <#[],openArray[T],HSlice[U: Ordinal,V: Ordinal]>`_.
|
||||
##
|
||||
## Example:
|
||||
## ```nim
|
||||
|
||||
@@ -252,12 +252,12 @@ iterator elementsExcept(t, s: CellSet): PCell {.inline.} =
|
||||
var r = t.head
|
||||
while r != nil:
|
||||
let ss = cellSetGet(s, r.key)
|
||||
var i:uint = 0
|
||||
var i = 0'u
|
||||
while int(i) <= high(r.bits):
|
||||
var w = r.bits[i]
|
||||
if ss != nil:
|
||||
w = w and not ss.bits[i]
|
||||
var j:uint = 0
|
||||
var j = 0'u
|
||||
while w != 0:
|
||||
if (w and 1) != 0:
|
||||
yield cast[PCell]((r.key shl PageShift) or
|
||||
|
||||
@@ -14,20 +14,24 @@ when not defined(nimPreviewSlimSystem):
|
||||
result = ""
|
||||
result.addFloat(x)
|
||||
|
||||
proc `$`*(x: int): string {.raises: [].} =
|
||||
## Outplace version of `addInt`.
|
||||
result = ""
|
||||
result.addInt(x)
|
||||
template addIntAlias(T: typedesc) =
|
||||
proc `$`*(x: T): string {.raises: [].} =
|
||||
## Outplace version of `addInt`.
|
||||
result = ""
|
||||
result.addInt(x)
|
||||
|
||||
proc `$`*(x: int64): string {.raises: [].} =
|
||||
## Outplace version of `addInt`.
|
||||
result = ""
|
||||
result.addInt(x)
|
||||
# need to declare for bit types as well to not clash with converters:
|
||||
addIntAlias int
|
||||
addIntAlias int8
|
||||
addIntAlias int16
|
||||
addIntAlias int32
|
||||
addIntAlias int64
|
||||
|
||||
proc `$`*(x: uint64): string {.raises: [].} =
|
||||
## Outplace version of `addInt`.
|
||||
result = ""
|
||||
addInt(result, x)
|
||||
addIntAlias uint
|
||||
addIntAlias uint8
|
||||
addIntAlias uint16
|
||||
addIntAlias uint32
|
||||
addIntAlias uint64
|
||||
|
||||
# same as old `ctfeWhitelist` behavior, whether or not this is a good idea.
|
||||
template gen(T) =
|
||||
|
||||
@@ -42,6 +42,9 @@ proc raiseExceptionEx(e: sink(ref Exception), ename, procname, filename: cstring
|
||||
proc reraiseException() {.compilerRtl.} =
|
||||
sysFatal(ReraiseDefect, "no exception to reraise")
|
||||
|
||||
proc raiseDefect() {.compilerRtl.} =
|
||||
sysFatal(ReraiseDefect, "exception handling is not available")
|
||||
|
||||
proc writeStackTrace() = discard
|
||||
|
||||
proc unsetControlCHook() = discard
|
||||
|
||||
@@ -597,7 +597,13 @@ proc sweep(gch: var GcHeap) =
|
||||
if isCell(x):
|
||||
# cast to PCell is correct here:
|
||||
var c = cast[PCell](x)
|
||||
if c notin gch.marked: freeCyclicCell(gch, c)
|
||||
if c notin gch.marked:
|
||||
# Don't free objects that have the ZctFlag set (created in finalizers)
|
||||
if (c.refcount and ZctFlag) == 0:
|
||||
freeCyclicCell(gch, c)
|
||||
else:
|
||||
# Clear the ZctFlag for the next collection cycle
|
||||
c.refcount = c.refcount and not ZctFlag
|
||||
|
||||
proc markS(gch: var GcHeap, c: PCell) =
|
||||
gcAssert isAllocatedPtr(gch.region, c), "markS: foreign heap root detected A!"
|
||||
|
||||
@@ -46,5 +46,3 @@ else:
|
||||
{.pragma: compilerRtl, compilerproc.}
|
||||
|
||||
{.pragma: benign, gcsafe.}
|
||||
|
||||
{.push sinkInference: on.}
|
||||
|
||||
@@ -154,6 +154,16 @@ proc raiseException(e: ref Exception, ename: cstring) {.
|
||||
e.trace = rawWriteStackTrace()
|
||||
{.emit: "throw `e`;".}
|
||||
|
||||
proc raiseDefect() {.compilerproc, asmNoStackFrame.} =
|
||||
if isNimException():
|
||||
let e = getCurrentException()
|
||||
if e of Defect:
|
||||
if excHandler == 0:
|
||||
unhandledException(e)
|
||||
when NimStackTrace:
|
||||
e.trace = rawWriteStackTrace()
|
||||
{.emit: "throw `e`;".}
|
||||
|
||||
proc reraiseException() {.compilerproc, asmNoStackFrame.} =
|
||||
if lastJSError == nil:
|
||||
raise newException(ReraiseDefect, "no exception to reraise")
|
||||
|
||||
@@ -55,7 +55,8 @@ elif defined(gogc):
|
||||
include system / mm / go
|
||||
|
||||
elif (defined(nogc) or defined(gcDestructors)) and defined(useMalloc):
|
||||
include system / mm / malloc
|
||||
when not defined(useNimRtl):
|
||||
include system / mm / malloc
|
||||
|
||||
when defined(nogc):
|
||||
proc GC_getStatistics(): string = ""
|
||||
|
||||
@@ -14,21 +14,26 @@ proc rangeBase(T: typedesc): typedesc {.magic: "TypeTrait".}
|
||||
|
||||
proc repr*(x: NimNode): string {.magic: "Repr", noSideEffect.}
|
||||
|
||||
proc repr*(x: int): string =
|
||||
## Same as $x
|
||||
$x
|
||||
template dollarAlias(T: typedesc) =
|
||||
proc repr*(x: T): string {.noSideEffect.} =
|
||||
## Same as $x
|
||||
$x
|
||||
|
||||
proc repr*(x: int64): string =
|
||||
## Same as $x
|
||||
$x
|
||||
# need to declare for bit types as well to not clash with converters:
|
||||
dollarAlias int
|
||||
dollarAlias int8
|
||||
dollarAlias int16
|
||||
dollarAlias int32
|
||||
dollarAlias int64
|
||||
|
||||
proc repr*(x: uint64): string {.noSideEffect.} =
|
||||
## Same as $x
|
||||
$x
|
||||
dollarAlias uint
|
||||
dollarAlias uint8
|
||||
dollarAlias uint16
|
||||
dollarAlias uint32
|
||||
dollarAlias uint64
|
||||
|
||||
proc repr*(x: float): string =
|
||||
## Same as $x
|
||||
$x
|
||||
dollarAlias float
|
||||
dollarAlias float32
|
||||
|
||||
proc repr*(x: bool): string {.magic: "BoolToStr", noSideEffect.}
|
||||
## repr for a boolean argument. Returns `x`
|
||||
|
||||
@@ -300,7 +300,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, elemAlign, newLen: int): PGenericS
|
||||
zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize)
|
||||
result.len = newLen
|
||||
|
||||
proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {.
|
||||
proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int, isTrivial: bool): PGenericSeq {.
|
||||
compilerRtl.} =
|
||||
sysAssert typ.kind == tySequence, "setLengthSeqV2: type is not a seq"
|
||||
if s == nil:
|
||||
@@ -334,7 +334,8 @@ proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {.
|
||||
# presence of user defined destructors, the user will expect the cell to be
|
||||
# "destroyed" thus creating the same problem. We can destroy the cell in the
|
||||
# finalizer of the sequence, but this makes destruction non-deterministic.
|
||||
zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize)
|
||||
if not isTrivial: # optimization for trivial types
|
||||
zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize)
|
||||
else:
|
||||
result = s
|
||||
zeroMem(dataPointer(result, elemAlign, elemSize, result.len), (newLen-%result.len) *% elemSize)
|
||||
|
||||
@@ -437,7 +437,7 @@ type
|
||||
fd_count*: cint # unsigned
|
||||
fd_array*: array[0..FD_SETSIZE-1, SocketHandle]
|
||||
|
||||
AddrInfo* = object
|
||||
AddrInfo* {.importc: "ADDRINFOA", header: "ws2tcpip.h".} = object
|
||||
ai_flags*: cint ## Input flags.
|
||||
ai_family*: cint ## Address family of socket.
|
||||
ai_socktype*: cint ## Socket type.
|
||||
@@ -815,7 +815,7 @@ proc WSASendTo*(s: SocketHandle, buf: ptr TWSABuf, bufCount: DWORD,
|
||||
completionProc: POVERLAPPED_COMPLETION_ROUTINE): cint {.
|
||||
stdcall, importc: "WSASendTo", dynlib: "Ws2_32.dll".}
|
||||
|
||||
proc get_osfhandle*(fd:FileHandle): Handle {.
|
||||
proc get_osfhandle*(fd: cint): Handle {.
|
||||
importc: "_get_osfhandle", header:"<io.h>".}
|
||||
|
||||
proc getSystemTimes*(lpIdleTime, lpKernelTime,
|
||||
|
||||
Reference in New Issue
Block a user