various bugfixes for generics; added generic sort proc
This commit is contained in:
parent
f93ca8e42a
commit
e424e13bd9
18 changed files with 392 additions and 113 deletions
|
|
@ -62,7 +62,7 @@ proc finalizeRegEx(x: TRegEx) =
|
||||||
|
|
||||||
proc re*(s: string, flags = {reExtended}): TRegEx =
|
proc re*(s: string, flags = {reExtended}): TRegEx =
|
||||||
## Constructor of regular expressions. Note that Nimrod's
|
## 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]")``.
|
## a short form for ``re(r"[abc]")``.
|
||||||
new(result, finalizeRegEx)
|
new(result, finalizeRegEx)
|
||||||
result.h = rawCompile(s, cast[cint](flags))
|
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 =
|
proc find*(s: string, pattern: TRegEx, start = 0): int =
|
||||||
## returns the starting position of ``pattern`` in ``s``. If it does not
|
## returns the starting position of ``pattern`` in ``s``. If it does not
|
||||||
## match, -1 is returned.
|
## match, -1 is returned.
|
||||||
var matches: array[0..maxSubpatterns-1, string]
|
var
|
||||||
result = find(s, pattern, matches, start)
|
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 =
|
iterator findAll*(s: string, pattern: TRegEx, start = 0): string =
|
||||||
## yields all matching captures of pattern in `s`.
|
## yields all matching captures of pattern in `s`.
|
||||||
|
|
|
||||||
101
lib/pure/algorithm.nim
Normal file
101
lib/pure/algorithm.nim
Normal 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
|
||||||
|
|
||||||
|
|
@ -97,14 +97,15 @@ proc normalize*(s: string): string {.noSideEffect, procvar,
|
||||||
add result, s[i]
|
add result, s[i]
|
||||||
|
|
||||||
proc cmpIgnoreCase*(a, b: string): int {.noSideEffect,
|
proc cmpIgnoreCase*(a, b: string): int {.noSideEffect,
|
||||||
rtl, extern: "nsuCmpIgnoreCase".} =
|
rtl, extern: "nsuCmpIgnoreCase", procvar.} =
|
||||||
## Compares two strings in a case insensitive manner. Returns:
|
## Compares two strings in a case insensitive manner. Returns:
|
||||||
##
|
##
|
||||||
## | 0 iff a == b
|
## | 0 iff a == b
|
||||||
## | < 0 iff a < b
|
## | < 0 iff a < b
|
||||||
## | > 0 iff a > b
|
## | > 0 iff a > b
|
||||||
var i = 0
|
var i = 0
|
||||||
while i < a.len and i < b.len:
|
var m = min(a.len, b.len)
|
||||||
|
while i < m:
|
||||||
result = ord(toLower(a[i])) - ord(toLower(b[i]))
|
result = ord(toLower(a[i])) - ord(toLower(b[i]))
|
||||||
if result != 0: return
|
if result != 0: return
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
@ -114,7 +115,7 @@ proc cmpIgnoreCase*(a, b: string): int {.noSideEffect,
|
||||||
# thus we compile without checks here
|
# thus we compile without checks here
|
||||||
|
|
||||||
proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
|
proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
|
||||||
rtl, extern: "nsuCmpIgnoreStyle".} =
|
rtl, extern: "nsuCmpIgnoreStyle", procvar.} =
|
||||||
## Compares two strings normalized (i.e. case and
|
## Compares two strings normalized (i.e. case and
|
||||||
## underscores do not matter). Returns:
|
## underscores do not matter). Returns:
|
||||||
##
|
##
|
||||||
|
|
|
||||||
|
|
@ -1075,7 +1075,7 @@ proc binarySearch(c: irune, tab: openArray[iRune], len, stride: int): int =
|
||||||
return t
|
return t
|
||||||
return -1
|
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.
|
## Converts `c` into lower case. This works for any Unicode character.
|
||||||
## If possible, prefer `toLower` over `toUpper`.
|
## If possible, prefer `toLower` over `toUpper`.
|
||||||
var c = irune(c)
|
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 + toLowerSinglets[p+1] - 500)
|
||||||
return TRune(c)
|
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.
|
## Converts `c` into upper case. This works for any Unicode character.
|
||||||
## If possible, prefer `toLower` over `toUpper`.
|
## If possible, prefer `toLower` over `toUpper`.
|
||||||
var c = irune(c)
|
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 + toUpperSinglets[p+1] - 500)
|
||||||
return TRune(c)
|
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 c = irune(c)
|
||||||
var p = binarySearch(c, toTitleSinglets, len(toTitleSinglets) div 2, 2)
|
var p = binarySearch(c, toTitleSinglets, len(toTitleSinglets) div 2, 2)
|
||||||
if p >= 0 and c == toTitleSinglets[p]:
|
if p >= 0 and c == toTitleSinglets[p]:
|
||||||
return TRune(c + toTitleSinglets[p+1] - 500)
|
return TRune(c + toTitleSinglets[p+1] - 500)
|
||||||
return TRune(c)
|
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
|
## returns true iff `c` is a lower case Unicode character
|
||||||
## If possible, prefer `isLower` over `isUpper`.
|
## If possible, prefer `isLower` over `isUpper`.
|
||||||
var c = irune(c)
|
var c = irune(c)
|
||||||
|
|
@ -1118,7 +1118,7 @@ proc isLower*(c: TRune): bool {.rtl, extern: "nuc$1".} =
|
||||||
if p >= 0 and c == toUpperSinglets[p]:
|
if p >= 0 and c == toUpperSinglets[p]:
|
||||||
return true
|
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
|
## returns true iff `c` is a upper case Unicode character
|
||||||
## If possible, prefer `isLower` over `isUpper`.
|
## If possible, prefer `isLower` over `isUpper`.
|
||||||
var c = irune(c)
|
var c = irune(c)
|
||||||
|
|
@ -1130,7 +1130,7 @@ proc isUpper*(c: TRune): bool {.rtl, extern: "nuc$1".} =
|
||||||
if p >= 0 and c == toLowerSinglets[p]:
|
if p >= 0 and c == toLowerSinglets[p]:
|
||||||
return true
|
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)
|
## returns true iff `c` is an *alpha* Unicode character (i.e. a letter)
|
||||||
if isUpper(c) or isLower(c):
|
if isUpper(c) or isLower(c):
|
||||||
return true
|
return true
|
||||||
|
|
@ -1142,10 +1142,10 @@ proc isAlpha*(c: TRune): bool {.rtl, extern: "nuc$1".} =
|
||||||
if p >= 0 and c == alphaSinglets[p]:
|
if p >= 0 and c == alphaSinglets[p]:
|
||||||
return true
|
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)
|
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
|
## returns true iff `c` is a Unicode whitespace character
|
||||||
var c = irune(c)
|
var c = irune(c)
|
||||||
var p = binarySearch(c, spaceRanges, len(spaceRanges) div 2, 2)
|
var p = binarySearch(c, spaceRanges, len(spaceRanges) div 2, 2)
|
||||||
|
|
@ -1161,7 +1161,7 @@ iterator runes*(s: string): TRune =
|
||||||
fastRuneAt(s, i, result, true)
|
fastRuneAt(s, i, result, true)
|
||||||
yield result
|
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:
|
## compares two UTF8 strings and ignores the case. Returns:
|
||||||
##
|
##
|
||||||
## | 0 iff a == b
|
## | 0 iff a == b
|
||||||
|
|
|
||||||
|
|
@ -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.}
|
proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.}
|
||||||
template `is_not` *(x, y: expr): expr = not (x is y)
|
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
|
## 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
|
## and 0 iff x == y. This is useful for writing generic algorithms without
|
||||||
## performance loss. This generic implementation uses the `==` and `<`
|
## 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
|
if x < y: return -1
|
||||||
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.
|
## Compare proc for strings. More efficient than the generic version.
|
||||||
|
|
||||||
proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {.
|
proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {.
|
||||||
|
|
@ -714,7 +714,8 @@ const
|
||||||
|
|
||||||
cpuEndian* {.magic: "CpuEndian"}: TEndian = littleEndian
|
cpuEndian* {.magic: "CpuEndian"}: TEndian = littleEndian
|
||||||
## is the endianness of the target CPU. This is a valuable piece of
|
## 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 = ""
|
hostOS* {.magic: "HostOS"}: string = ""
|
||||||
## a string that describes the host operating system. Possible values:
|
## 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!
|
## available for the ECMAScript target too!
|
||||||
|
|
||||||
template newException*(exceptn, message: expr): expr =
|
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.
|
## to `message`. Returns the new exception object.
|
||||||
block: # open a new scope
|
block: # open a new scope
|
||||||
var
|
var
|
||||||
|
|
@ -1365,7 +1366,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
include "system/ansi_c"
|
include "system/ansi_c"
|
||||||
|
|
||||||
proc cmp(x, y: string): int =
|
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
|
const pccHack = if defined(pcc): "_" else: "" # Hack for PCC
|
||||||
when defined(windows):
|
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
|
## stream* is a good idea, but since it is named ``stderr`` there are few
|
||||||
## programs out there that distinguish properly between ``stdout`` and
|
## programs out there that distinguish properly between ``stdout`` and
|
||||||
## ``stderr``. So, that's what you get if you don't name your variables
|
## ``stderr``. So, that's what you get if you don't name your variables
|
||||||
## appropriately. It also annoys people if redirection via ``>output.txt``
|
## appropriately. It also annoys people if redirection
|
||||||
## does not work because the program writes to ``stderr``.
|
## via ``>output.txt`` does not work because the program writes
|
||||||
|
## to ``stderr``.
|
||||||
|
|
||||||
proc Open*(f: var TFile, filename: string,
|
proc Open*(f: var TFile, filename: string,
|
||||||
mode: TFileMode = fmRead, bufSize: int = -1): Bool
|
mode: TFileMode = fmRead, bufSize: int = -1): Bool
|
||||||
|
|
|
||||||
11
rod/ast.nim
11
rod/ast.nim
|
|
@ -750,6 +750,12 @@ proc newSymNode(sym: PSym): PNode =
|
||||||
result.typ = sym.typ
|
result.typ = sym.typ
|
||||||
result.info = sym.info
|
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 =
|
proc newNodeI(kind: TNodeKind, info: TLineInfo): PNode =
|
||||||
result = newNode(kind)
|
result = newNode(kind)
|
||||||
result.info = info
|
result.info = info
|
||||||
|
|
@ -869,6 +875,11 @@ proc len*(n: PNode): int {.inline.} =
|
||||||
if isNil(n.sons): result = 0
|
if isNil(n.sons): result = 0
|
||||||
else: result = len(n.sons)
|
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) =
|
proc add*(father, son: PNode) =
|
||||||
assert son != nil
|
assert son != nil
|
||||||
if isNil(father.sons): father.sons = @[]
|
if isNil(father.sons): father.sons = @[]
|
||||||
|
|
|
||||||
|
|
@ -79,20 +79,42 @@ proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode =
|
||||||
initialBinding = nil
|
initialBinding = nil
|
||||||
result = semDirectCallWithBinding(c, n, f, filter, initialBinding)
|
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
|
assert n.kind == nkBracketExpr
|
||||||
for i in 1..sonsLen(n)-1:
|
for i in 1..sonsLen(n)-1:
|
||||||
n.sons[i].typ = semTypeNode(c, n.sons[i], nil)
|
n.sons[i].typ = semTypeNode(c, n.sons[i], nil)
|
||||||
# we cannot check for the proper number of type parameters because in
|
var s = s
|
||||||
# `f[a,b](x, y)` `f` is not resolved yet properly.
|
var a = n.sons[0]
|
||||||
# XXX: BUG this should be checked somehow!
|
if a.kind == nkSym:
|
||||||
assert n.sons[0].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
|
var x: TCandidate
|
||||||
initCandidate(x, s, n)
|
initCandidate(x, s, n)
|
||||||
var newInst = generateInstance(c, s, x.bindings, n.info)
|
var newInst = generateInstance(c, s, x.bindings, n.info)
|
||||||
|
|
||||||
markUsed(n, s)
|
markUsed(n, s)
|
||||||
result = newSymNode(newInst)
|
result = newSymNode(newInst, n.info)
|
||||||
result.info = n.info
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,24 +61,22 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
if s.typ.kind in ConstAbstractTypes:
|
if s.typ.kind in ConstAbstractTypes:
|
||||||
result = copyTree(s.ast)
|
result = copyTree(s.ast)
|
||||||
result.typ = s.typ
|
result.typ = s.typ
|
||||||
|
result.info = n.info
|
||||||
else:
|
else:
|
||||||
result = newSymNode(s)
|
result = newSymNode(s, n.info)
|
||||||
result.info = n.info
|
|
||||||
of skMacro: result = semMacroExpr(c, n, s)
|
of skMacro: result = semMacroExpr(c, n, s)
|
||||||
of skTemplate: result = semTemplateExpr(c, n, s)
|
of skTemplate: result = semTemplateExpr(c, n, s)
|
||||||
of skVar:
|
of skVar:
|
||||||
markUsed(n, s)
|
markUsed(n, s)
|
||||||
# if a proc accesses a global variable, it is not side effect free:
|
# if a proc accesses a global variable, it is not side effect free:
|
||||||
if sfGlobal in s.flags: incl(c.p.owner.flags, sfSideEffect)
|
if sfGlobal in s.flags: incl(c.p.owner.flags, sfSideEffect)
|
||||||
result = newSymNode(s)
|
result = newSymNode(s, n.info)
|
||||||
result.info = n.info
|
|
||||||
of skGenericParam:
|
of skGenericParam:
|
||||||
if s.ast == nil: InternalError(n.info, "no default for")
|
if s.ast == nil: InternalError(n.info, "no default for")
|
||||||
result = semExpr(c, s.ast)
|
result = semExpr(c, s.ast)
|
||||||
else:
|
else:
|
||||||
markUsed(n, s)
|
markUsed(n, s)
|
||||||
result = newSymNode(s)
|
result = newSymNode(s, n.info)
|
||||||
result.info = n.info
|
|
||||||
|
|
||||||
proc checkConversionBetweenObjects(info: TLineInfo, castDest, src: PType) =
|
proc checkConversionBetweenObjects(info: TLineInfo, castDest, src: PType) =
|
||||||
var diff = inheritanceDiff(castDest, src)
|
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 ty = n.sons[0].Typ
|
||||||
var f: PSym = nil
|
var f: PSym = nil
|
||||||
result = nil
|
result = nil
|
||||||
if ty.kind == tyEnum:
|
if isTypeExpr(n.sons[0]):
|
||||||
# look up if the identifier belongs to the enum:
|
if ty.kind == tyEnum:
|
||||||
while ty != nil:
|
# look up if the identifier belongs to the enum:
|
||||||
f = getSymFromList(ty.n, i)
|
while ty != nil:
|
||||||
if f != nil: break
|
f = getSymFromList(ty.n, i)
|
||||||
ty = ty.sons[0] # enum inheritance
|
if f != nil: break
|
||||||
if f != nil:
|
ty = ty.sons[0] # enum inheritance
|
||||||
result = newSymNode(f)
|
if f != nil:
|
||||||
result.info = n.info
|
result = newSymNode(f)
|
||||||
result.typ = ty
|
result.info = n.info
|
||||||
markUsed(n, f)
|
result.typ = ty
|
||||||
else:
|
markUsed(n, f)
|
||||||
GlobalError(n.sons[1].info, errEnumHasNoValueX, i.s)
|
return
|
||||||
return
|
elif efAllowType notin flags:
|
||||||
elif not (efAllowType in flags) and isTypeExpr(n.sons[0]):
|
GlobalError(n.sons[0].info, errATypeHasNoValue)
|
||||||
GlobalError(n.sons[0].info, errATypeHasNoValue)
|
return
|
||||||
return
|
|
||||||
ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef})
|
ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef})
|
||||||
var check: PNode = nil
|
var check: PNode = nil
|
||||||
if ty.kind == tyObject:
|
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})
|
var s = qualifiedLookup(c, n.sons[0], {checkUndeclared})
|
||||||
if s != nil and s.kind in {skProc, skMethod, skConverter, skIterator}:
|
if s != nil and s.kind in {skProc, skMethod, skConverter, skIterator}:
|
||||||
# type parameters: partial generic specialization
|
# 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:
|
else:
|
||||||
result = semArrayAccess(c, n, flags)
|
result = semArrayAccess(c, n, flags)
|
||||||
of nkPragmaExpr:
|
of nkPragmaExpr:
|
||||||
|
|
|
||||||
|
|
@ -40,13 +40,15 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
of skMacro:
|
of skMacro:
|
||||||
result = semMacroExpr(c, n, s, false)
|
result = semMacroExpr(c, n, s, false)
|
||||||
of skGenericParam:
|
of skGenericParam:
|
||||||
result = newSymNode(s)
|
result = newSymNode(s, n.info)
|
||||||
of skParam:
|
of skParam:
|
||||||
result = n
|
result = n
|
||||||
of skType:
|
of skType:
|
||||||
if (s.typ != nil) and (s.typ.kind != tyGenericParam): result = newSymNode(s)
|
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
|
||||||
else: result = n
|
result = newSymNode(s, n.info)
|
||||||
else: result = newSymNode(s)
|
else:
|
||||||
|
result = n
|
||||||
|
else: result = newSymNode(s, n.info)
|
||||||
|
|
||||||
proc getIdentNode(n: PNode): PNode =
|
proc getIdentNode(n: PNode): PNode =
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
@ -101,12 +103,12 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
|
||||||
of skProc, skMethod, skIterator, skConverter:
|
of skProc, skMethod, skIterator, skConverter:
|
||||||
n.sons[0] = symChoice(c, n.sons[0], s)
|
n.sons[0] = symChoice(c, n.sons[0], s)
|
||||||
of skGenericParam:
|
of skGenericParam:
|
||||||
n.sons[0] = newSymNode(s)
|
n.sons[0] = newSymNode(s, n.sons[0].info)
|
||||||
of skType:
|
of skType:
|
||||||
# bad hack for generics:
|
# bad hack for generics:
|
||||||
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
|
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
|
||||||
n.sons[0] = newSymNode(s)
|
n.sons[0] = newSymNode(s, n.sons[0].info)
|
||||||
else: n.sons[0] = newSymNode(s)
|
else: n.sons[0] = newSymNode(s, n.sons[0].info)
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
for i in countup(1, sonsLen(n) - 1):
|
||||||
n.sons[i] = semGenericStmt(c, n.sons[i], flags)
|
n.sons[i] = semGenericStmt(c, n.sons[i], flags)
|
||||||
of nkMacroStmt:
|
of nkMacroStmt:
|
||||||
|
|
@ -221,9 +223,9 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
|
||||||
if (a.kind != nkIdentDefs): IllFormedAst(a)
|
if (a.kind != nkIdentDefs): IllFormedAst(a)
|
||||||
checkMinSonsLen(a, 3)
|
checkMinSonsLen(a, 3)
|
||||||
L = sonsLen(a)
|
L = sonsLen(a)
|
||||||
a.sons[L - 1] = semGenericStmt(c, a.sons[L - 2], {withinTypeDesc})
|
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], {withinTypeDesc})
|
||||||
a.sons[L - 1] = semGenericStmt(c, a.sons[L - 1])
|
a.sons[L-1] = semGenericStmt(c, a.sons[L-1])
|
||||||
for j in countup(0, L - 3):
|
for j in countup(0, L-3):
|
||||||
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
|
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
|
||||||
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
||||||
nkIteratorDef, nkLambda:
|
nkIteratorDef, nkLambda:
|
||||||
|
|
|
||||||
|
|
@ -522,11 +522,15 @@ proc SemTypeSection(c: PContext, n: PNode): PNode =
|
||||||
InternalError(a.info, "semTypeSection: containerID")
|
InternalError(a.info, "semTypeSection: containerID")
|
||||||
s.typ.containerID = getID()
|
s.typ.containerID = getID()
|
||||||
a.sons[1] = semGenericParamList(c, a.sons[1], s.typ)
|
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
|
s.ast = a
|
||||||
body = semTypeNode(c, a.sons[2], nil)
|
body = semTypeNode(c, a.sons[2], nil)
|
||||||
if body != nil: body.sym = s
|
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()
|
popOwner()
|
||||||
closeScope(c.tab)
|
closeScope(c.tab)
|
||||||
elif a.sons[2].kind != nkEmpty:
|
elif a.sons[2].kind != nkEmpty:
|
||||||
|
|
|
||||||
|
|
@ -488,7 +488,8 @@ proc paramType(c: PContext, n, genericParams: PNode, cl: var TIntSet): PType =
|
||||||
result = addTypeVarsOfGenericBody(c, result, genericParams, cl)
|
result = addTypeVarsOfGenericBody(c, result, genericParams, cl)
|
||||||
#if result.kind == tyGenericInvokation: debug(result)
|
#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
|
var
|
||||||
def, res: PNode
|
def, res: PNode
|
||||||
typ: PType
|
typ: PType
|
||||||
|
|
@ -515,12 +516,12 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, prev: PType): PType =
|
||||||
if a.sons[length - 1].kind != nkEmpty:
|
if a.sons[length - 1].kind != nkEmpty:
|
||||||
def = semExprWithType(c, a.sons[length - 1])
|
def = semExprWithType(c, a.sons[length - 1])
|
||||||
# check type compability between def.typ and typ:
|
# check type compability between def.typ and typ:
|
||||||
if typ != nil:
|
if typ == nil:
|
||||||
if cmpTypes(typ, def.typ) < isConvertible:
|
|
||||||
typeMismatch(a.sons[length - 1], typ, def.typ)
|
|
||||||
def = fitNode(c, typ, def)
|
|
||||||
else:
|
|
||||||
typ = def.typ
|
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:
|
else:
|
||||||
def = ast.emptyNode
|
def = ast.emptyNode
|
||||||
for j in countup(0, length - 3):
|
for j in countup(0, length - 3):
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,10 @@ proc concreteType(mapping: TIdTable, t: PType): PType =
|
||||||
result = t
|
result = t
|
||||||
while true:
|
while true:
|
||||||
result = PType(idTableGet(mapping, t))
|
result = PType(idTableGet(mapping, t))
|
||||||
if result == nil: InternalError("lookup failed")
|
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
|
if result.kind != tyGenericParam: break
|
||||||
else:
|
else:
|
||||||
result = t # Note: empty is valid here
|
result = t # Note: empty is valid here
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ proc suggestFieldAccess(c: PContext, n: PNode) =
|
||||||
else:
|
else:
|
||||||
# fallback:
|
# fallback:
|
||||||
suggestEverything(c, n)
|
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:
|
# look up if the identifier belongs to the enum:
|
||||||
var t = typ
|
var t = typ
|
||||||
while t != nil:
|
while t != nil:
|
||||||
|
|
|
||||||
69
tests/accept/compile/tsortdev.nim
Normal file
69
tests/accept/compile/tsortdev.nim
Normal 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"
|
||||||
|
|
||||||
|
|
@ -4,51 +4,47 @@ discard """
|
||||||
|
|
||||||
# A min-heap.
|
# A min-heap.
|
||||||
type
|
type
|
||||||
TNode[T] = tuple[priority: int, data: T]
|
TNode[T] = tuple[priority: int, data: T]
|
||||||
|
|
||||||
TBinHeap[T] = object
|
TBinHeap[T] = object
|
||||||
heap: seq[TNode[T]]
|
heap: seq[TNode[T]]
|
||||||
last: int
|
last: int
|
||||||
|
|
||||||
PBinHeap[T] = ref TBinHeap[T]
|
PBinHeap[T] = ref TBinHeap[T]
|
||||||
|
|
||||||
proc newBinHeap*[T](heap: var PBinHeap[T], size: int) =
|
proc newBinHeap*[T](heap: var PBinHeap[T], size: int) =
|
||||||
new(heap)
|
new(heap)
|
||||||
heap.last = 0
|
heap.last = 0
|
||||||
newSeq(heap.seq, size)
|
newSeq(heap.heap, size)
|
||||||
|
#newSeq(heap.seq, size)
|
||||||
|
|
||||||
when false:
|
proc parent(elem: int): int {.inline.} =
|
||||||
|
return (elem-1) div 2
|
||||||
|
|
||||||
proc parent(elem: int): int =
|
proc siftUp[T](heap: PBinHeap[T], elem: int) =
|
||||||
return (elem-1) div 2
|
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 siftUp[T](heap: PBinHeap[T], elem: int) =
|
proc add*[T](heap: PBinHeap[T], priority: int, data: T) =
|
||||||
var idx = elem
|
var node: TNode[T]
|
||||||
while idx != 0:
|
node.priority = priority
|
||||||
var p = parent(idx)
|
node.data = data
|
||||||
if heap.heap[idx] < heap.heap[p]:
|
heap.heap[heap.last] = node
|
||||||
var tmp = heap.heap[idx]
|
siftUp(heap, heap.last)
|
||||||
heap.heap[idx] = heap.heap[p]
|
inc(heap.last)
|
||||||
heap.heap[p] = tmp
|
|
||||||
idx = p
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
proc add*[T](heap: PBinHeap[T], priority: int, data: T) =
|
proc print*[T](heap: PBinHeap[T]) =
|
||||||
var node: TNode
|
for i in countup(0, heap.last):
|
||||||
new(node)
|
echo heap.heap[i].data
|
||||||
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
|
var
|
||||||
heap: PBinHeap[int]
|
heap: PBinHeap[int]
|
||||||
|
|
||||||
newBinHeap(heap, 256)
|
newBinHeap(heap, 256)
|
||||||
add(heap, 1, 100)
|
add(heap, 1, 100)
|
||||||
|
|
|
||||||
11
tests/gc/gcleak.nim
Normal file
11
tests/gc/gcleak.nim
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
type
|
||||||
|
TTestObj = object of TObject
|
||||||
|
x: string
|
||||||
|
|
||||||
|
proc MakeObj(): TTestObj =
|
||||||
|
result.x = "Hello"
|
||||||
|
|
||||||
|
while true:
|
||||||
|
var obj = MakeObj()
|
||||||
|
|
||||||
|
|
||||||
55
tests/reject/ttypenoval.nim
Normal file
55
tests/reject/ttypenoval.nim
Normal 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)
|
||||||
|
|
||||||
|
|
||||||
1
todo.txt
1
todo.txt
|
|
@ -35,7 +35,6 @@ Bugs
|
||||||
To implement
|
To implement
|
||||||
------------
|
------------
|
||||||
|
|
||||||
* sort routine
|
|
||||||
* hash tables and sets
|
* hash tables and sets
|
||||||
* distinct types for array/seq indexes
|
* distinct types for array/seq indexes
|
||||||
* constant sequences
|
* constant sequences
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue