Merge branch 'master' of github.com:Araq/Nimrod
This commit is contained in:
commit
22c310485a
5 changed files with 257 additions and 6 deletions
|
|
@ -142,6 +142,8 @@ proc parseMessage(msg: string): TIRCEvent =
|
||||||
inc(i) # Skip `:`
|
inc(i) # Skip `:`
|
||||||
var nick = ""
|
var nick = ""
|
||||||
i.inc msg.parseUntil(nick, {'!', ' '}, i)
|
i.inc msg.parseUntil(nick, {'!', ' '}, i)
|
||||||
|
result.nick = ""
|
||||||
|
result.serverName = ""
|
||||||
if msg[i] == '!':
|
if msg[i] == '!':
|
||||||
result.nick = nick
|
result.nick = nick
|
||||||
inc(i) # Skip `!`
|
inc(i) # Skip `!`
|
||||||
|
|
@ -237,7 +239,8 @@ proc processLine(irc: var TIRC, line: string): TIRCEvent =
|
||||||
result = parseMessage(line)
|
result = parseMessage(line)
|
||||||
# Get the origin
|
# Get the origin
|
||||||
result.origin = result.params[0]
|
result.origin = result.params[0]
|
||||||
if result.origin == irc.nick: result.origin = result.nick
|
if result.origin == irc.nick and
|
||||||
|
result.nick != "": result.origin = result.nick
|
||||||
|
|
||||||
if result.cmd == MError:
|
if result.cmd == MError:
|
||||||
irc.close()
|
irc.close()
|
||||||
|
|
@ -386,6 +389,7 @@ proc asyncIRC*(address: string, port: TPort = 6667.TPort,
|
||||||
result.messageBuffer = @[]
|
result.messageBuffer = @[]
|
||||||
result.handleEvent = ircEvent
|
result.handleEvent = ircEvent
|
||||||
result.userArg = userArg
|
result.userArg = userArg
|
||||||
|
result.lineBuffer = ""
|
||||||
|
|
||||||
proc register*(d: PDispatcher, irc: PAsyncIRC) =
|
proc register*(d: PDispatcher, irc: PAsyncIRC) =
|
||||||
## Registers ``irc`` with dispatcher ``d``.
|
## Registers ``irc`` with dispatcher ``d``.
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,12 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
## This module implements a simple portable type-safe sockets layer.
|
## This module implements a simple portable type-safe sockets layer.
|
||||||
|
##
|
||||||
|
## Most procedures raise EOS on error.
|
||||||
|
|
||||||
|
|
||||||
import os, parseutils
|
import os, parseutils
|
||||||
|
from times import epochTime
|
||||||
|
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
import winlean
|
import winlean
|
||||||
|
|
@ -59,6 +63,8 @@ type
|
||||||
TRecvLineResult* = enum ## result for recvLineAsync
|
TRecvLineResult* = enum ## result for recvLineAsync
|
||||||
RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail
|
RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail
|
||||||
|
|
||||||
|
ETimeout* = object of ESynch
|
||||||
|
|
||||||
const
|
const
|
||||||
InvalidSocket* = TSocket(-1'i32) ## invalid socket number
|
InvalidSocket* = TSocket(-1'i32) ## invalid socket number
|
||||||
|
|
||||||
|
|
@ -377,12 +383,14 @@ proc connect*(socket: TSocket, name: string, port = TPort(0),
|
||||||
## host name. If ``name`` is a host name, this function will try each IP
|
## host name. If ``name`` 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
|
||||||
## not do it.
|
## not do it.
|
||||||
|
|
||||||
var hints: TAddrInfo
|
var hints: TAddrInfo
|
||||||
var aiList: ptr TAddrInfo = nil
|
var aiList: ptr TAddrInfo = nil
|
||||||
hints.ai_family = toInt(af)
|
hints.ai_family = toInt(af)
|
||||||
hints.ai_socktype = toInt(SOCK_STREAM)
|
hints.ai_socktype = toInt(SOCK_STREAM)
|
||||||
hints.ai_protocol = toInt(IPPROTO_TCP)
|
hints.ai_protocol = toInt(IPPROTO_TCP)
|
||||||
gaiNim(name, port, hints, aiList)
|
gaiNim(name, port, hints, aiList)
|
||||||
|
|
||||||
# try all possibilities:
|
# try all possibilities:
|
||||||
var success = false
|
var success = false
|
||||||
var it = aiList
|
var it = aiList
|
||||||
|
|
@ -445,7 +453,6 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
|
||||||
freeaddrinfo(aiList)
|
freeaddrinfo(aiList)
|
||||||
if not success: OSError()
|
if not success: OSError()
|
||||||
|
|
||||||
|
|
||||||
proc timeValFromMilliseconds(timeout = 500): TTimeVal =
|
proc timeValFromMilliseconds(timeout = 500): TTimeVal =
|
||||||
if timeout != -1:
|
if timeout != -1:
|
||||||
var seconds = timeout div 1000
|
var seconds = timeout div 1000
|
||||||
|
|
@ -545,7 +552,33 @@ proc select*(readfds: var seq[TSocket], timeout = 500): int =
|
||||||
result = int(select(cint(m+1), addr(rd), nil, nil, nil))
|
result = int(select(cint(m+1), addr(rd), nil, nil, nil))
|
||||||
|
|
||||||
pruneSocketSet(readfds, (rd))
|
pruneSocketSet(readfds, (rd))
|
||||||
|
|
||||||
|
proc recv*(socket: TSocket, data: pointer, size: int): int =
|
||||||
|
## receives data from a socket
|
||||||
|
result = recv(cint(socket), data, size, 0'i32)
|
||||||
|
|
||||||
|
template waitFor(): stmt =
|
||||||
|
if timeout - int(waited * 1000.0) < 1:
|
||||||
|
raise newException(ETimeout, "Call to recv() timed out.")
|
||||||
|
var s = @[socket]
|
||||||
|
var startTime = epochTime()
|
||||||
|
if select(s, timeout - int(waited * 1000.0)) != 1:
|
||||||
|
raise newException(ETimeout, "Call to recv() timed out.")
|
||||||
|
waited += (epochTime() - startTime)
|
||||||
|
|
||||||
|
proc recv*(socket: TSocket, data: var string, size: int, timeout: int): int =
|
||||||
|
## overload with a ``timeout`` parameter in miliseconds.
|
||||||
|
var waited = 0.0 # number of seconds already waited
|
||||||
|
|
||||||
|
var read = 0
|
||||||
|
while read < size:
|
||||||
|
waitFor()
|
||||||
|
result = recv(cint(socket), addr(data[read]), 1, 0'i32)
|
||||||
|
if result < 0:
|
||||||
|
return
|
||||||
|
inc(read)
|
||||||
|
|
||||||
|
result = read
|
||||||
|
|
||||||
proc recvLine*(socket: TSocket, line: var TaintedString): bool =
|
proc recvLine*(socket: TSocket, line: var TaintedString): bool =
|
||||||
## returns false if no further data is available. `Line` must be initialized
|
## returns false if no further data is available. `Line` must be initialized
|
||||||
|
|
@ -567,6 +600,29 @@ proc recvLine*(socket: TSocket, line: var TaintedString): bool =
|
||||||
elif c == '\L': return true
|
elif c == '\L': return true
|
||||||
add(line.string, c)
|
add(line.string, c)
|
||||||
|
|
||||||
|
proc recvLine*(socket: TSocket, line: var TaintedString, timeout: int): bool =
|
||||||
|
## variant with a ``timeout`` parameter, the timeout parameter specifies
|
||||||
|
## how many miliseconds to wait for data.
|
||||||
|
|
||||||
|
var waited = 0.0 # number of seconds already waited
|
||||||
|
|
||||||
|
setLen(line.string, 0)
|
||||||
|
while true:
|
||||||
|
var c: char
|
||||||
|
waitFor()
|
||||||
|
var n = recv(cint(socket), addr(c), 1, 0'i32)
|
||||||
|
if n < 0: return
|
||||||
|
elif n == 0: return true
|
||||||
|
if c == '\r':
|
||||||
|
waitFor()
|
||||||
|
n = recv(cint(socket), addr(c), 1, MSG_PEEK)
|
||||||
|
if n > 0 and c == '\L':
|
||||||
|
discard recv(cint(socket), addr(c), 1, 0'i32)
|
||||||
|
elif n <= 0: return false
|
||||||
|
return true
|
||||||
|
elif c == '\L': return true
|
||||||
|
add(line.string, c)
|
||||||
|
|
||||||
proc recvLineAsync*(socket: TSocket, line: var TaintedString): TRecvLineResult =
|
proc recvLineAsync*(socket: TSocket, line: var TaintedString): TRecvLineResult =
|
||||||
## similar to ``recvLine`` but for non-blocking sockets.
|
## similar to ``recvLine`` but for non-blocking sockets.
|
||||||
## The values of the returned enum should be pretty self explanatory:
|
## The values of the returned enum should be pretty self explanatory:
|
||||||
|
|
@ -592,10 +648,6 @@ proc recvLineAsync*(socket: TSocket, line: var TaintedString): TRecvLineResult =
|
||||||
elif c == '\L': return RecvFullLine
|
elif c == '\L': return RecvFullLine
|
||||||
add(line.string, c)
|
add(line.string, c)
|
||||||
|
|
||||||
proc recv*(socket: TSocket, data: pointer, size: int): int =
|
|
||||||
## receives data from a socket
|
|
||||||
result = recv(cint(socket), data, size, 0'i32)
|
|
||||||
|
|
||||||
proc recv*(socket: TSocket): TaintedString =
|
proc recv*(socket: TSocket): TaintedString =
|
||||||
## receives all the data from the socket.
|
## receives all the data from the socket.
|
||||||
## Socket errors will result in an ``EOS`` error.
|
## Socket errors will result in an ``EOS`` error.
|
||||||
|
|
@ -625,6 +677,16 @@ proc recv*(socket: TSocket): TaintedString =
|
||||||
add(result.string, buf)
|
add(result.string, buf)
|
||||||
if bytesRead != bufSize-1: break
|
if bytesRead != bufSize-1: break
|
||||||
|
|
||||||
|
proc recvTimeout*(socket: TSocket, timeout: int): TaintedString =
|
||||||
|
## overloaded variant to support a ``timeout`` parameter, the ``timeout``
|
||||||
|
## parameter specifies the amount of miliseconds to wait for data on the
|
||||||
|
## socket.
|
||||||
|
var s = @[socket]
|
||||||
|
if s.select(timeout) != 1:
|
||||||
|
raise newException(ETimeout, "Call to recv() timed out.")
|
||||||
|
|
||||||
|
return socket.recv
|
||||||
|
|
||||||
proc recvAsync*(socket: TSocket, s: var TaintedString): bool =
|
proc recvAsync*(socket: TSocket, s: var TaintedString): bool =
|
||||||
## receives all the data from a non-blocking socket. If socket is non-blocking
|
## receives all the data from a non-blocking socket. If socket is non-blocking
|
||||||
## and there are no messages available, `False` will be returned.
|
## and there are no messages available, `False` will be returned.
|
||||||
|
|
@ -723,6 +785,21 @@ proc setBlocking*(s: TSocket, blocking: bool) =
|
||||||
if fcntl(cint(s), F_SETFL, mode) == -1:
|
if fcntl(cint(s), F_SETFL, mode) == -1:
|
||||||
OSError()
|
OSError()
|
||||||
|
|
||||||
|
proc connect*(socket: TSocket, timeout: int, name: string, port = TPort(0),
|
||||||
|
af: TDomain = AF_INET) =
|
||||||
|
## Overload for ``connect`` to support timeouts. The ``timeout`` parameter
|
||||||
|
## specifies the time in miliseconds of how long to wait for a connection
|
||||||
|
## to be made.
|
||||||
|
##
|
||||||
|
## **Warning:** If ``socket`` is non-blocking and timeout is not ``-1`` then
|
||||||
|
## this function may set blocking mode on ``socket`` to true.
|
||||||
|
socket.setBlocking(true)
|
||||||
|
|
||||||
|
socket.connectAsync(name, port, af)
|
||||||
|
var s: seq[TSocket] = @[socket]
|
||||||
|
if selectWrite(s, timeout) != 1:
|
||||||
|
raise newException(ETimeout, "Call to connect() timed out.")
|
||||||
|
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
var wsa: TWSADATA
|
var wsa: TWSADATA
|
||||||
if WSAStartup(0x0101'i16, wsa) != 0: OSError()
|
if WSAStartup(0x0101'i16, wsa) != 0: OSError()
|
||||||
|
|
|
||||||
47
tests/benchmark.nim
Normal file
47
tests/benchmark.nim
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod Benchmark tool
|
||||||
|
# (c) Copyright 2012 Dominik Picheta
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
## This program runs benchmarks
|
||||||
|
import osproc, os, times, json
|
||||||
|
|
||||||
|
type
|
||||||
|
TBenchResult = tuple[file: string, success: bool, time: float]
|
||||||
|
|
||||||
|
proc compileBench(file: string) =
|
||||||
|
## Compiles ``file``.
|
||||||
|
doAssert(execCmdEx("nimrod c -d:release " & file).exitCode == QuitSuccess)
|
||||||
|
|
||||||
|
proc runBench(file: string): TBenchResult =
|
||||||
|
## Runs ``file`` and returns info on how long it took to run.
|
||||||
|
var start = epochTime()
|
||||||
|
if execCmdEx(file.addFileExt(ExeExt)).exitCode == QuitSuccess:
|
||||||
|
var t = epochTime() - start
|
||||||
|
result = (file, true, t)
|
||||||
|
else: result = (file, false, -1.0)
|
||||||
|
|
||||||
|
proc genOutput(benches: seq[TBenchResult]): PJsonNode =
|
||||||
|
result = newJObject()
|
||||||
|
for i in benches:
|
||||||
|
if i.success:
|
||||||
|
result[i.file.extractFilename] = newJFloat(i.time)
|
||||||
|
else:
|
||||||
|
result[i.file.extractFilename] = newJNull()
|
||||||
|
|
||||||
|
proc doBench(): seq[TBenchResult] =
|
||||||
|
result = @[]
|
||||||
|
for i in walkFiles("tests/benchmarks/*.nim"):
|
||||||
|
echo(i.extractFilename)
|
||||||
|
compileBench(i)
|
||||||
|
result.add(runBench(i))
|
||||||
|
|
||||||
|
when isMainModule:
|
||||||
|
var b = doBench()
|
||||||
|
var output = genOutput(b)
|
||||||
|
writeFile("benchmarkResults.json", pretty(output))
|
||||||
|
|
||||||
69
tests/benchmarks/fannkuch.nim
Normal file
69
tests/benchmarks/fannkuch.nim
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
import os
|
||||||
|
import strutils
|
||||||
|
|
||||||
|
proc fannkuch (n: int): int =
|
||||||
|
var
|
||||||
|
count: seq[int]
|
||||||
|
maxFlips = 0
|
||||||
|
m = n-1
|
||||||
|
r = n
|
||||||
|
check = 0
|
||||||
|
perm1: seq[int]
|
||||||
|
perm: seq[int]
|
||||||
|
|
||||||
|
newSeq (count, n+1)
|
||||||
|
newSeq (perm1, n)
|
||||||
|
newSeq (perm, n)
|
||||||
|
for i in 0 .. n-1:
|
||||||
|
count[i] = i+1
|
||||||
|
perm1[i] = i
|
||||||
|
perm[i] = i
|
||||||
|
count[n] = n+1
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if check < 30:
|
||||||
|
for i in items (perm1):
|
||||||
|
write (stdout, $(i+1))
|
||||||
|
echo ("")
|
||||||
|
inc (check)
|
||||||
|
|
||||||
|
while r != 1:
|
||||||
|
count[r-1] = r
|
||||||
|
dec (r)
|
||||||
|
|
||||||
|
if perm1[0] != 0 and perm1[m] != m:
|
||||||
|
# perm = perm1
|
||||||
|
# The above line is between 3 and 4 times slower than the loop below!
|
||||||
|
for i in 0 .. n-1:
|
||||||
|
perm[i] = perm1[i]
|
||||||
|
var flipsCount = 0
|
||||||
|
var k = perm[0]
|
||||||
|
while k != 0:
|
||||||
|
for i in 0 .. (k div 2):
|
||||||
|
swap (perm[i], perm[k-i])
|
||||||
|
inc (flipsCount)
|
||||||
|
k = perm[0]
|
||||||
|
|
||||||
|
if flipsCount > maxFlips:
|
||||||
|
maxFlips = flipsCount
|
||||||
|
|
||||||
|
block makePerm:
|
||||||
|
while r != n:
|
||||||
|
var tmp = perm1[0]
|
||||||
|
# # perm1.delete (0)
|
||||||
|
# # perm1.insert (tmp, r)
|
||||||
|
# # The above is about twice as slow as the following:
|
||||||
|
# moveMem (addr (perm1[0]), addr (perm1[1]), r * sizeof (int))
|
||||||
|
# The call to moveMem is about 50% slower than the loop below!
|
||||||
|
for i in 0 .. r-1:
|
||||||
|
perm1[i] = perm1[i+1]
|
||||||
|
perm1[r] = tmp
|
||||||
|
|
||||||
|
dec (count[r])
|
||||||
|
if count[r] > 0:
|
||||||
|
break makePerm
|
||||||
|
inc (r)
|
||||||
|
return maxFlips
|
||||||
|
|
||||||
|
var n = 10
|
||||||
|
echo ("Pfannkuchen(" & $n & ") = " & $fannkuch (n))
|
||||||
54
tests/benchmarks/quicksort.nim
Normal file
54
tests/benchmarks/quicksort.nim
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
import os
|
||||||
|
import strutils
|
||||||
|
|
||||||
|
# Generate some pseudo-random data
|
||||||
|
var seed: tuple[s1, s2, s3: int32] = (2'i32, 8'i32, 16'i32)
|
||||||
|
|
||||||
|
proc random(): int32 =
|
||||||
|
seed = (((((((seed[0] and 0x0007_FFFF'i32) shl 13'i32) xor seed[0]) shr
|
||||||
|
19'i32) and 0x0000_1FFF'i32) xor
|
||||||
|
((seed[0] and 0x000F_FFFE'i32) shl 12'i32)),
|
||||||
|
|
||||||
|
((((((seed[1] and 0x3FFF_FFFF'i32) shl 2'i32) xor seed[1]) shr
|
||||||
|
25'i32) and 0x0000_007F'i32) xor
|
||||||
|
((seed[1] and 0x0FFF_FFF8'i32) shl 4'i32)),
|
||||||
|
|
||||||
|
((((((seed[2] and 0x1FFF_FFFF'i32) shl 3'i32) xor seed[2]) shr
|
||||||
|
11'i32) and 0x001F_FFFF'i32) xor
|
||||||
|
((seed[2] and 0x0000_7FF0'i32) shl 17'i32)))
|
||||||
|
return seed[0] xor seed[1] xor seed[2]
|
||||||
|
|
||||||
|
var n = 9999999
|
||||||
|
|
||||||
|
var data: seq[int32]
|
||||||
|
newSeq (data, n)
|
||||||
|
for i in 0 .. data.high():
|
||||||
|
data[i] = random()
|
||||||
|
|
||||||
|
|
||||||
|
proc `$` (d: seq[int32]): string =
|
||||||
|
result = "[ "
|
||||||
|
for i in items (d):
|
||||||
|
result.addSep (", ", 2)
|
||||||
|
result.add ($(i and 0xFFFF_FFFF'i64))
|
||||||
|
result.add (" ]")
|
||||||
|
|
||||||
|
# Sort the data
|
||||||
|
proc sort (start, stop: int) =
|
||||||
|
if stop <= start+1:
|
||||||
|
return
|
||||||
|
|
||||||
|
var j = start
|
||||||
|
for i in start..stop-2:
|
||||||
|
if data[i] <% data[stop-1]:
|
||||||
|
swap (data[i], data[j])
|
||||||
|
inc (j)
|
||||||
|
swap (data[j], data[stop-1])
|
||||||
|
|
||||||
|
sort (start, j)
|
||||||
|
sort (j+1, stop)
|
||||||
|
|
||||||
|
sort (0, data.len)
|
||||||
|
echo (data[n div 2 - 1] and 0xFFFF_FFFF'i64, ", ",
|
||||||
|
data[n div 2] and 0xFFFF_FFFF'i64, ", ",
|
||||||
|
data[n div 2 + 1] and 0xFFFF_FFFF'i64)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue