various bugfixes for generics; added generic sort proc

This commit is contained in:
Araq
2011-03-03 02:01:22 +01:00
parent f93ca8e42a
commit e424e13bd9
18 changed files with 392 additions and 113 deletions

View File

@@ -62,7 +62,7 @@ proc finalizeRegEx(x: TRegEx) =
proc re*(s: string, flags = {reExtended}): TRegEx =
## Constructor of regular expressions. Note that Nimrod's
## extended raw string literals supports this syntax ``re"[abc]"`` as
## extended raw string literals support this syntax ``re"[abc]"`` as
## a short form for ``re(r"[abc]")``.
new(result, finalizeRegEx)
result.h = rawCompile(s, cast[cint](flags))
@@ -152,8 +152,12 @@ proc find*(s: string, pattern: TRegEx, matches: var openarray[string],
proc find*(s: string, pattern: TRegEx, start = 0): int =
## returns the starting position of ``pattern`` in ``s``. If it does not
## match, -1 is returned.
var matches: array[0..maxSubpatterns-1, string]
result = find(s, pattern, matches, start)
var
rawMatches: array[0..3 - 1, cint]
res = pcre.Exec(pattern.h, nil, s, len(s), start, 0'i32,
cast[ptr cint](addr(rawMatches)), 3)
if res < 0'i32: return res
return rawMatches[0]
iterator findAll*(s: string, pattern: TRegEx, start = 0): string =
## yields all matching captures of pattern in `s`.

101
lib/pure/algorithm.nim Normal file
View File

@@ -0,0 +1,101 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements some common generic algorithms.
type
TSortOrder* = enum ## sort order
Descending, Ascending
proc `*`*(x: int, order: TSortOrder): int {.inline.} =
## flips `x` if ``order == Descending``;
## if ``order == Ascending`` then `x` is returned.
## `x` is supposed to be the result of a comparator.
var y = order.ord - 1
result = (x xor y) - y
proc reverse*[T](a: var openArray[T], first, last: int) =
## reverses the array ``a[first..last]``.
var x = first
var y = last
while x < y:
swap(a[x], a[y])
dec(y)
inc(x)
proc reverse*[T](a: var openArray[T]) =
## reverses the array `a`.
reverse(a, 0, a.high)
const
onlySafeCode = false
proc merge[T](a, b: var openArray[T], lo, m, hi: int,
cmp: proc (x, y: T): int, order: TSortOrder) =
template `<-` (a, b: expr) =
when onlySafeCode:
a = b
else:
copyMem(addr(a), addr(b), sizeof(T))
# optimization: If max(left) <= min(right) there is nothing to do!
# 1 2 3 4 ## 5 6 7 8
# -> O(n) for sorted arrays.
# On random data this safes up to 40% of merge calls
if cmp(a[m], a[m+1]) * order <= 0: return
var j = lo
# copy a[j..m] into b:
assert j <= m
when onlySafeCode:
var bb = 0
while j <= m:
b[bb] = a[j]
inc(bb)
inc(j)
else:
CopyMem(addr(b[0]), addr(a[j]), sizeof(T)*(m-j+1))
j = m+1
var i = 0
var k = lo
# copy proper element back:
while k < j and j <= hi:
if cmp(b[i], a[j]) * order <= 0:
a[k] <- b[i]
inc(i)
else:
a[k] <- a[j]
inc(j)
inc(k)
# copy rest of b:
when onlySafeCode:
while k < j:
a[k] = b[i]
inc(k)
inc(i)
else:
if k < j: copyMem(addr(a[k]), addr(b[i]), sizeof(T)*(j-k))
proc sort*[T](a: var openArray[T],
cmp: proc (x, y: T): int = cmp,
order = TSortOrder.Ascending) =
## Default Nimrod sort. The sorting is guaranteed to be stable and
## the worst case is guaranteed to be O(n log n).
## The current implementation uses an iterative
## mergesort to achieve this. It uses a temporary sequence of
## length ``a.len div 2``.
var n = a.len
var b: seq[T]
newSeq(b, n div 2)
var s = 1
while s < n:
var m = n-1-s
while m >= 0:
merge(a, b, max(m-s+1, 0), m, m+s, cmp, order)
dec(m, s*2)
s = s*2

View File

@@ -97,14 +97,15 @@ proc normalize*(s: string): string {.noSideEffect, procvar,
add result, s[i]
proc cmpIgnoreCase*(a, b: string): int {.noSideEffect,
rtl, extern: "nsuCmpIgnoreCase".} =
rtl, extern: "nsuCmpIgnoreCase", procvar.} =
## Compares two strings in a case insensitive manner. Returns:
##
## | 0 iff a == b
## | < 0 iff a < b
## | > 0 iff a > b
var i = 0
while i < a.len and i < b.len:
var i = 0
var m = min(a.len, b.len)
while i < m:
result = ord(toLower(a[i])) - ord(toLower(b[i]))
if result != 0: return
inc(i)
@@ -114,7 +115,7 @@ proc cmpIgnoreCase*(a, b: string): int {.noSideEffect,
# thus we compile without checks here
proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
rtl, extern: "nsuCmpIgnoreStyle".} =
rtl, extern: "nsuCmpIgnoreStyle", procvar.} =
## Compares two strings normalized (i.e. case and
## underscores do not matter). Returns:
##

View File

@@ -1075,7 +1075,7 @@ proc binarySearch(c: irune, tab: openArray[iRune], len, stride: int): int =
return t
return -1
proc toLower*(c: TRune): TRune {.rtl, extern: "nuc$1".} =
proc toLower*(c: TRune): TRune {.rtl, extern: "nuc$1", procvar.} =
## Converts `c` into lower case. This works for any Unicode character.
## If possible, prefer `toLower` over `toUpper`.
var c = irune(c)
@@ -1087,7 +1087,7 @@ proc toLower*(c: TRune): TRune {.rtl, extern: "nuc$1".} =
return TRune(c + toLowerSinglets[p+1] - 500)
return TRune(c)
proc toUpper*(c: TRune): TRune {.rtl, extern: "nuc$1".} =
proc toUpper*(c: TRune): TRune {.rtl, extern: "nuc$1", procvar.} =
## Converts `c` into upper case. This works for any Unicode character.
## If possible, prefer `toLower` over `toUpper`.
var c = irune(c)
@@ -1099,14 +1099,14 @@ proc toUpper*(c: TRune): TRune {.rtl, extern: "nuc$1".} =
return TRune(c + toUpperSinglets[p+1] - 500)
return TRune(c)
proc toTitle*(c: TRune): TRune {.rtl, extern: "nuc$1".} =
proc toTitle*(c: TRune): TRune {.rtl, extern: "nuc$1", procvar.} =
var c = irune(c)
var p = binarySearch(c, toTitleSinglets, len(toTitleSinglets) div 2, 2)
if p >= 0 and c == toTitleSinglets[p]:
return TRune(c + toTitleSinglets[p+1] - 500)
return TRune(c)
proc isLower*(c: TRune): bool {.rtl, extern: "nuc$1".} =
proc isLower*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
## returns true iff `c` is a lower case Unicode character
## If possible, prefer `isLower` over `isUpper`.
var c = irune(c)
@@ -1118,7 +1118,7 @@ proc isLower*(c: TRune): bool {.rtl, extern: "nuc$1".} =
if p >= 0 and c == toUpperSinglets[p]:
return true
proc isUpper*(c: TRune): bool {.rtl, extern: "nuc$1".} =
proc isUpper*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
## returns true iff `c` is a upper case Unicode character
## If possible, prefer `isLower` over `isUpper`.
var c = irune(c)
@@ -1130,7 +1130,7 @@ proc isUpper*(c: TRune): bool {.rtl, extern: "nuc$1".} =
if p >= 0 and c == toLowerSinglets[p]:
return true
proc isAlpha*(c: TRune): bool {.rtl, extern: "nuc$1".} =
proc isAlpha*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
## returns true iff `c` is an *alpha* Unicode character (i.e. a letter)
if isUpper(c) or isLower(c):
return true
@@ -1142,10 +1142,10 @@ proc isAlpha*(c: TRune): bool {.rtl, extern: "nuc$1".} =
if p >= 0 and c == alphaSinglets[p]:
return true
proc isTitle*(c: TRune): bool {.rtl, extern: "nuc$1".} =
proc isTitle*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
return isUpper(c) and isLower(c)
proc isWhiteSpace*(c: TRune): bool {.rtl, extern: "nuc$1".} =
proc isWhiteSpace*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
## returns true iff `c` is a Unicode whitespace character
var c = irune(c)
var p = binarySearch(c, spaceRanges, len(spaceRanges) div 2, 2)
@@ -1161,7 +1161,7 @@ iterator runes*(s: string): TRune =
fastRuneAt(s, i, result, true)
yield result
proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1".} =
proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} =
## compares two UTF8 strings and ignores the case. Returns:
##
## | 0 iff a == b

View File

@@ -623,7 +623,7 @@ template `not_in` * (x, y: expr): expr = not contains(y, x)
proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.}
template `is_not` *(x, y: expr): expr = not (x is y)
proc cmp*[T, S: typeDesc](x: T, y: S): int =
proc cmp*[T, S: typeDesc](x: T, y: S): int {.procvar.} =
## Generic compare proc. Returns a value < 0 iff x < y, a value > 0 iff x > y
## and 0 iff x == y. This is useful for writing generic algorithms without
## performance loss. This generic implementation uses the `==` and `<`
@@ -632,7 +632,7 @@ proc cmp*[T, S: typeDesc](x: T, y: S): int =
if x < y: return -1
return 1
proc cmp*(x, y: string): int {.noSideEffect.}
proc cmp*(x, y: string): int {.noSideEffect, procvar.}
## Compare proc for strings. More efficient than the generic version.
proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {.
@@ -714,7 +714,8 @@ const
cpuEndian* {.magic: "CpuEndian"}: TEndian = littleEndian
## is the endianness of the target CPU. This is a valuable piece of
## information for low-level code only. This works thanks to compiler magic.
## information for low-level code only. This works thanks to compiler
## magic.
hostOS* {.magic: "HostOS"}: string = ""
## a string that describes the host operating system. Possible values:
@@ -1307,7 +1308,7 @@ proc echo*[Ty](x: openarray[Ty]) {.magic: "Echo".}
## available for the ECMAScript target too!
template newException*(exceptn, message: expr): expr =
## creates an exception object of type "exceptn" and sets its ``msg`` field
## creates an exception object of type ``exceptn`` and sets its ``msg`` field
## to `message`. Returns the new exception object.
block: # open a new scope
var
@@ -1365,7 +1366,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
include "system/ansi_c"
proc cmp(x, y: string): int =
return int(c_strcmp(x, y))
result = int(c_strcmp(x, y))
const pccHack = if defined(pcc): "_" else: "" # Hack for PCC
when defined(windows):
@@ -1419,8 +1420,9 @@ when not defined(EcmaScript) and not defined(NimrodVM):
## stream* is a good idea, but since it is named ``stderr`` there are few
## programs out there that distinguish properly between ``stdout`` and
## ``stderr``. So, that's what you get if you don't name your variables
## appropriately. It also annoys people if redirection via ``>output.txt``
## does not work because the program writes to ``stderr``.
## appropriately. It also annoys people if redirection
## via ``>output.txt`` does not work because the program writes
## to ``stderr``.
proc Open*(f: var TFile, filename: string,
mode: TFileMode = fmRead, bufSize: int = -1): Bool

View File

@@ -750,6 +750,12 @@ proc newSymNode(sym: PSym): PNode =
result.typ = sym.typ
result.info = sym.info
proc newSymNode*(sym: PSym, info: TLineInfo): PNode =
result = newNode(nkSym)
result.sym = sym
result.typ = sym.typ
result.info = info
proc newNodeI(kind: TNodeKind, info: TLineInfo): PNode =
result = newNode(kind)
result.info = info
@@ -869,6 +875,11 @@ proc len*(n: PNode): int {.inline.} =
if isNil(n.sons): result = 0
else: result = len(n.sons)
proc safeLen*(n: PNode): int {.inline.} =
## works even for leaves.
if n.kind in {nkNone..nkNilLit} or isNil(n.sons): result = 0
else: result = len(n.sons)
proc add*(father, son: PNode) =
assert son != nil
if isNil(father.sons): father.sons = @[]

View File

@@ -79,20 +79,42 @@ proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode =
initialBinding = nil
result = semDirectCallWithBinding(c, n, f, filter, initialBinding)
proc explictGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
proc explicitGenericInstError(n: PNode): PNode =
LocalError(n.info, errCannotInstantiateX, renderTree(n))
result = n
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
assert n.kind == nkBracketExpr
for i in 1..sonsLen(n)-1:
n.sons[i].typ = semTypeNode(c, n.sons[i], nil)
# we cannot check for the proper number of type parameters because in
# `f[a,b](x, y)` `f` is not resolved yet properly.
# XXX: BUG this should be checked somehow!
assert n.sons[0].kind == nkSym
var s = s
var a = n.sons[0]
if a.kind == nkSym:
# common case; check the only candidate has the right
# number of generic type parameters:
if safeLen(s.ast.sons[genericParamsPos]) != n.len-1:
return explicitGenericInstError(n)
elif a.kind == nkSymChoice:
# choose the generic proc with the proper number of type parameters.
# XXX I think this could be improved by reusing sigmatch.ParamTypesMatch.
# It's good enough for now.
var candidateCount = 0
for i in countup(0, len(a)-1):
var candidate = a.sons[i].sym
if candidate.kind in {skProc, skMethod, skConverter, skIterator}:
# if suffices that the candidate has the proper number of generic
# type parameters:
if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
s = candidate
inc(candidateCount)
if candidateCount != 1: return explicitGenericInstError(n)
else:
assert false
var x: TCandidate
initCandidate(x, s, n)
var newInst = generateInstance(c, s, x.bindings, n.info)
markUsed(n, s)
result = newSymNode(newInst)
result.info = n.info
result = newSymNode(newInst, n.info)

View File

@@ -61,24 +61,22 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
if s.typ.kind in ConstAbstractTypes:
result = copyTree(s.ast)
result.typ = s.typ
result.info = n.info
else:
result = newSymNode(s)
result.info = n.info
result = newSymNode(s, n.info)
of skMacro: result = semMacroExpr(c, n, s)
of skTemplate: result = semTemplateExpr(c, n, s)
of skVar:
markUsed(n, s)
# if a proc accesses a global variable, it is not side effect free:
if sfGlobal in s.flags: incl(c.p.owner.flags, sfSideEffect)
result = newSymNode(s)
result.info = n.info
result = newSymNode(s, n.info)
of skGenericParam:
if s.ast == nil: InternalError(n.info, "no default for")
result = semExpr(c, s.ast)
else:
markUsed(n, s)
result = newSymNode(s)
result.info = n.info
result = newSymNode(s, n.info)
proc checkConversionBetweenObjects(info: TLineInfo, castDest, src: PType) =
var diff = inheritanceDiff(castDest, src)
@@ -645,23 +643,22 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
var ty = n.sons[0].Typ
var f: PSym = nil
result = nil
if ty.kind == tyEnum:
# look up if the identifier belongs to the enum:
while ty != nil:
f = getSymFromList(ty.n, i)
if f != nil: break
ty = ty.sons[0] # enum inheritance
if f != nil:
result = newSymNode(f)
result.info = n.info
result.typ = ty
markUsed(n, f)
else:
GlobalError(n.sons[1].info, errEnumHasNoValueX, i.s)
return
elif not (efAllowType in flags) and isTypeExpr(n.sons[0]):
GlobalError(n.sons[0].info, errATypeHasNoValue)
return
if isTypeExpr(n.sons[0]):
if ty.kind == tyEnum:
# look up if the identifier belongs to the enum:
while ty != nil:
f = getSymFromList(ty.n, i)
if f != nil: break
ty = ty.sons[0] # enum inheritance
if f != nil:
result = newSymNode(f)
result.info = n.info
result.typ = ty
markUsed(n, f)
return
elif efAllowType notin flags:
GlobalError(n.sons[0].info, errATypeHasNoValue)
return
ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef})
var check: PNode = nil
if ty.kind == tyObject:
@@ -1027,7 +1024,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
var s = qualifiedLookup(c, n.sons[0], {checkUndeclared})
if s != nil and s.kind in {skProc, skMethod, skConverter, skIterator}:
# type parameters: partial generic specialization
result = explictGenericInstantiation(c, n, s)
n.sons[0] = semSym(c, n.sons[0], s, flags)
result = explicitGenericInstantiation(c, n, s)
else:
result = semArrayAccess(c, n, flags)
of nkPragmaExpr:

View File

@@ -40,13 +40,15 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
of skMacro:
result = semMacroExpr(c, n, s, false)
of skGenericParam:
result = newSymNode(s)
result = newSymNode(s, n.info)
of skParam:
result = n
of skType:
if (s.typ != nil) and (s.typ.kind != tyGenericParam): result = newSymNode(s)
else: result = n
else: result = newSymNode(s)
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
result = newSymNode(s, n.info)
else:
result = n
else: result = newSymNode(s, n.info)
proc getIdentNode(n: PNode): PNode =
case n.kind
@@ -101,12 +103,12 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
of skProc, skMethod, skIterator, skConverter:
n.sons[0] = symChoice(c, n.sons[0], s)
of skGenericParam:
n.sons[0] = newSymNode(s)
n.sons[0] = newSymNode(s, n.sons[0].info)
of skType:
# bad hack for generics:
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
n.sons[0] = newSymNode(s)
else: n.sons[0] = newSymNode(s)
n.sons[0] = newSymNode(s, n.sons[0].info)
else: n.sons[0] = newSymNode(s, n.sons[0].info)
for i in countup(1, sonsLen(n) - 1):
n.sons[i] = semGenericStmt(c, n.sons[i], flags)
of nkMacroStmt:
@@ -221,9 +223,9 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
if (a.kind != nkIdentDefs): IllFormedAst(a)
checkMinSonsLen(a, 3)
L = sonsLen(a)
a.sons[L - 1] = semGenericStmt(c, a.sons[L - 2], {withinTypeDesc})
a.sons[L - 1] = semGenericStmt(c, a.sons[L - 1])
for j in countup(0, L - 3):
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], {withinTypeDesc})
a.sons[L-1] = semGenericStmt(c, a.sons[L-1])
for j in countup(0, L-3):
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkIteratorDef, nkLambda:

View File

@@ -522,11 +522,15 @@ proc SemTypeSection(c: PContext, n: PNode): PNode =
InternalError(a.info, "semTypeSection: containerID")
s.typ.containerID = getID()
a.sons[1] = semGenericParamList(c, a.sons[1], s.typ)
addSon(s.typ, nil) # to be filled out later
# we fill it out later. For magic generics like 'seq', it won't be filled
# so we use tyEmpty instead of nil to not crash for strange conversions
# like: mydata.seq
addSon(s.typ, newTypeS(tyEmpty, c))
s.ast = a
body = semTypeNode(c, a.sons[2], nil)
if body != nil: body.sym = s
s.typ.sons[sonsLen(s.typ) - 1] = body #debug(s.typ);
s.typ.sons[sonsLen(s.typ) - 1] = body
popOwner()
closeScope(c.tab)
elif a.sons[2].kind != nkEmpty:

View File

@@ -488,7 +488,8 @@ proc paramType(c: PContext, n, genericParams: PNode, cl: var TIntSet): PType =
result = addTypeVarsOfGenericBody(c, result, genericParams, cl)
#if result.kind == tyGenericInvokation: debug(result)
proc semProcTypeNode(c: PContext, n, genericParams: PNode, prev: PType): PType =
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
prev: PType): PType =
var
def, res: PNode
typ: PType
@@ -515,12 +516,12 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, prev: PType): PType =
if a.sons[length - 1].kind != nkEmpty:
def = semExprWithType(c, a.sons[length - 1])
# check type compability between def.typ and typ:
if typ != nil:
if cmpTypes(typ, def.typ) < isConvertible:
typeMismatch(a.sons[length - 1], typ, def.typ)
def = fitNode(c, typ, def)
else:
if typ == nil:
typ = def.typ
elif def != nil and def.typ != nil and def.typ.kind != tyNone:
# example code that triggers it:
# proc sort[T](cmp: proc(a, b: T): int = cmp)
def = fitNode(c, typ, def)
else:
def = ast.emptyNode
for j in countup(0, length - 3):

View File

@@ -130,8 +130,11 @@ proc concreteType(mapping: TIdTable, t: PType): PType =
result = t
while true:
result = PType(idTableGet(mapping, t))
if result == nil: InternalError("lookup failed")
if result.kind != tyGenericParam: break
if result == nil:
break # it's ok, no match
# example code that triggers it:
# proc sort[T](cmp: proc(a, b: T): int = cmp)
if result.kind != tyGenericParam: break
else:
result = t # Note: empty is valid here

View File

@@ -123,7 +123,7 @@ proc suggestFieldAccess(c: PContext, n: PNode) =
else:
# fallback:
suggestEverything(c, n)
elif typ.kind == tyEnum:
elif typ.kind == tyEnum and n.kind == nkSym and n.sym.kind == skType:
# look up if the identifier belongs to the enum:
var t = typ
while t != nil:

View File

@@ -0,0 +1,69 @@
import math, algorithm
proc sorted[T](a: openArray[T], order: TSortOrder): bool =
result = true
for i in 0 .. < a.high:
if cmp(a[i], a[i+1]) * order > 0:
echo "Out of order: ", a[i], " ", a[i+1]
result = false
proc bubbleSort[T](a: var openArray[T],
cmp: proc (x, y: T): int = cmp,
order = TSortOrder.Ascending) =
while true:
var sorted = true
for i in 0 .. a.len-2:
if cmp(a[i], a[i+1]) * order > 0:
swap(a[i], a[i+1])
sorted = false
if sorted: break
when isMainModule:
proc main() =
const order = Ascending
var data: seq[string] = @[]
for i in 0..10_000:
var L = random(59)
setLen(data, L)
for j in 0 .. L-1:
data[j] = $(math.random(90) - 10)
var copy = data
sort(data, cmp, order)
if not sorted(data, order):
#for x in items(data): echo x
break
else:
echo "SUCCESS!"
bubblesort(copy, cmp, order)
if copy.len != data.len:
quit "lengths differ!"
for i in 0 .. copy.high:
if copy[i] != data[i]:
quit "algorithms differ!"
for i in 0..10_000:
var data: seq[int] = @[]
var L = random(59)
setLen(data, L)
for j in 0 .. L-1:
data[j] = (math.random(90) - 10)
var copy = data
sort(data, cmp[int, int], order)
if not sorted(data, order):
#for x in items(data): echo x
break
else:
echo "SUCCESS!"
bubblesort(copy)
if copy.len != data.len:
quit "lengths differ!"
for i in 0 .. copy.high:
if copy[i] != data[i]:
quit "algorithms differ!"
main()
echo "done"

View File

@@ -4,51 +4,47 @@ discard """
# A min-heap.
type
TNode[T] = tuple[priority: int, data: T]
TNode[T] = tuple[priority: int, data: T]
TBinHeap[T] = object
heap: seq[TNode[T]]
last: int
PBinHeap[T] = ref TBinHeap[T]
TBinHeap[T] = object
heap: seq[TNode[T]]
last: int
PBinHeap[T] = ref TBinHeap[T]
proc newBinHeap*[T](heap: var PBinHeap[T], size: int) =
new(heap)
heap.last = 0
newSeq(heap.seq, size)
new(heap)
heap.last = 0
newSeq(heap.heap, size)
#newSeq(heap.seq, size)
proc parent(elem: int): int {.inline.} =
return (elem-1) div 2
when false:
proc siftUp[T](heap: PBinHeap[T], elem: int) =
var idx = elem
while idx != 0:
var p = parent(idx)
if heap.heap[idx].priority < heap.heap[p].priority:
swap(heap.heap[idx], heap.heap[p])
idx = p
else:
break
proc parent(elem: int): int =
return (elem-1) div 2
proc add*[T](heap: PBinHeap[T], priority: int, data: T) =
var node: TNode[T]
node.priority = priority
node.data = data
heap.heap[heap.last] = node
siftUp(heap, heap.last)
inc(heap.last)
proc siftUp[T](heap: PBinHeap[T], elem: int) =
var idx = elem
while idx != 0:
var p = parent(idx)
if heap.heap[idx] < heap.heap[p]:
var tmp = heap.heap[idx]
heap.heap[idx] = heap.heap[p]
heap.heap[p] = tmp
idx = p
else:
break
proc add*[T](heap: PBinHeap[T], priority: int, data: T) =
var node: TNode
new(node)
node.priority = int
node.data = data
heap.heap[heap.last] = node
siftUp(heap, heap.last)
inc(heap.last)
proc print*[T](heap: PBinHeap[T]) =
for i in countup(0, heap.last):
echo($heap.heap[i])
proc print*[T](heap: PBinHeap[T]) =
for i in countup(0, heap.last):
echo heap.heap[i].data
var
heap: PBinHeap[int]
heap: PBinHeap[int]
newBinHeap(heap, 256)
add(heap, 1, 100)

11
tests/gc/gcleak.nim Normal file
View File

@@ -0,0 +1,11 @@
type
TTestObj = object of TObject
x: string
proc MakeObj(): TTestObj =
result.x = "Hello"
while true:
var obj = MakeObj()

View File

@@ -0,0 +1,55 @@
discard """
file: "tambsym.nim"
line: 36
errormsg: "a type has no value"
"""
# A min-heap.
type
TNode[T] = tuple[priority: int, data: T]
TBinHeap[T] = object
heap: seq[TNode[T]]
last: int
PBinHeap[T] = ref TBinHeap[T]
proc newBinHeap*[T](heap: var PBinHeap[T], size: int) =
new(heap)
heap.last = 0
newSeq(heap.heap, size)
#newSeq(heap.seq, size)
proc parent(elem: int): int {.inline.} =
return (elem-1) div 2
proc siftUp[T](heap: PBinHeap[T], elem: int) =
var idx = elem
while idx != 0:
var p = parent(idx)
if heap.heap[idx] < heap.heap[p]:
swap(heap.heap[idx], heap.heap[p])
idx = p
else:
break
proc add*[T](heap: PBinHeap[T], priority: int, data: T) =
var node: TNode[T]
node.priority = int
node.data = data
heap.heap[heap.last] = node
siftUp(heap, heap.last)
inc(heap.last)
proc print*[T](heap: PBinHeap[T]) =
for i in countup(0, heap.last):
echo($heap.heap[i])
var
heap: PBinHeap[int]
newBinHeap(heap, 256)
add(heap, 1, 100)
print(heap)

View File

@@ -35,7 +35,6 @@ Bugs
To implement
------------
* sort routine
* hash tables and sets
* distinct types for array/seq indexes
* constant sequences