summary refs log tree commit diff stats
path: root/compiler/nstrtabs.nim
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2011-04-12 01:13:42 +0200
committerAraq <rumpf_a@web.de>2011-04-12 01:13:42 +0200
commitcd292568d775d55d9abb51e962882ecda12c03a9 (patch)
tree85451f0e1f17dc0463350915f12bdd0a82a73455 /compiler/nstrtabs.nim
parent46c41e43690cba9bc1caff6a994bb6915df8a1b7 (diff)
downloadNim-cd292568d775d55d9abb51e962882ecda12c03a9.tar.gz
big repo cleanup
Diffstat (limited to 'compiler/nstrtabs.nim')
-rwxr-xr-xcompiler/nstrtabs.nim171
1 files changed, 171 insertions, 0 deletions
diff --git a/compiler/nstrtabs.nim b/compiler/nstrtabs.nim
new file mode 100755
index 000000000..811e461cc
--- /dev/null
+++ b/compiler/nstrtabs.nim
@@ -0,0 +1,171 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# String tables.
+
+import 
+  os, nhashes, strutils
+
+type 
+  TStringTableMode* = enum 
+    modeCaseSensitive,        # the table is case sensitive
+    modeCaseInsensitive,      # the table is case insensitive
+    modeStyleInsensitive      # the table is style insensitive
+  TKeyValuePair* = tuple[key, val: string]
+  TKeyValuePairSeq* = seq[TKeyValuePair]
+  TStringTable* = object of TObject
+    counter*: int
+    data*: TKeyValuePairSeq
+    mode*: TStringTableMode
+
+  PStringTable* = ref TStringTable
+
+proc newStringTable*(keyValuePairs: openarray[string], 
+                     mode: TStringTableMode = modeCaseSensitive): PStringTable
+proc put*(t: PStringTable, key, val: string)
+proc get*(t: PStringTable, key: string): string
+proc hasKey*(t: PStringTable, key: string): bool
+proc length*(t: PStringTable): int
+type 
+  TFormatFlag* = enum 
+    useEnvironment,           # use environment variable if the ``$key``
+                              # is not found in the table
+    useEmpty,                 # use the empty string as a default, thus it
+                              # won't throw an exception if ``$key`` is not
+                              # in the table
+    useKey                    # do not replace ``$key`` if it is not found
+                              # in the table (or in the environment)
+  TFormatFlags* = set[TFormatFlag]
+
+proc `%`*(f: string, t: PStringTable, flags: TFormatFlags = {}): string
+# implementation
+
+const 
+  growthFactor = 2
+  startSize = 64
+
+proc newStringTable(keyValuePairs: openarray[string], 
+                    mode: TStringTableMode = modeCaseSensitive): PStringTable = 
+  new(result)
+  result.mode = mode
+  result.counter = 0
+  newSeq(result.data, startSize)
+  var i = 0
+  while i < high(keyValuePairs): 
+    put(result, keyValuePairs[i], keyValuePairs[i + 1])
+    inc(i, 2)
+
+proc myhash(t: PStringTable, key: string): THash = 
+  case t.mode
+  of modeCaseSensitive: result = nhashes.GetHashStr(key)
+  of modeCaseInsensitive: result = nhashes.GetHashStrCI(key)
+  of modeStyleInsensitive: result = nhashes.getNormalizedHash(key)
+  
+proc myCmp(t: PStringTable, a, b: string): bool = 
+  case t.mode
+  of modeCaseSensitive: result = cmp(a, b) == 0
+  of modeCaseInsensitive: result = cmpIgnoreCase(a, b) == 0
+  of modeStyleInsensitive: result = cmpIgnoreStyle(a, b) == 0
+  
+proc mustRehash(length, counter: int): bool = 
+  assert(length > counter)
+  result = (length * 2 < counter * 3) or (length - counter < 4)
+
+proc length(t: PStringTable): int = 
+  result = t.counter
+
+proc nextTry(h, maxHash: THash): THash = 
+  result = ((5 * h) + 1) and maxHash
+  # For any initial h in range(maxHash), repeating that maxHash times
+  # generates each int in range(maxHash) exactly once (see any text on
+  # random-number generation for proof).
+  
+proc RawGet(t: PStringTable, key: string): int = 
+  var h = myhash(t, key) and high(t.data) # start with real hash value
+  while not isNil(t.data[h].key): 
+    if mycmp(t, t.data[h].key, key): 
+      return h
+    h = nextTry(h, high(t.data))
+  result = - 1
+
+proc get(t: PStringTable, key: string): string = 
+  var index = RawGet(t, key)
+  if index >= 0: result = t.data[index].val
+  else: result = ""
+  
+proc hasKey(t: PStringTable, key: string): bool = 
+  result = rawGet(t, key) >= 0
+
+proc RawInsert(t: PStringTable, data: var TKeyValuePairSeq, key, val: string) = 
+  var h = myhash(t, key) and high(data)
+  while not isNil(data[h].key): 
+    h = nextTry(h, high(data))
+  data[h].key = key
+  data[h].val = val
+
+proc Enlarge(t: PStringTable) = 
+  var n: TKeyValuePairSeq
+  newSeq(n, len(t.data) * growthFactor)
+  for i in countup(0, high(t.data)): 
+    if not isNil(t.data[i].key): RawInsert(t, n, t.data[i].key, t.data[i].val)
+  swap(t.data, n)
+
+proc Put(t: PStringTable, key, val: string) = 
+  var index = RawGet(t, key)
+  if index >= 0: 
+    t.data[index].val = val
+  else: 
+    if mustRehash(len(t.data), t.counter): Enlarge(t)
+    RawInsert(t, t.data, key, val)
+    inc(t.counter)
+
+proc RaiseFormatException(s: string) = 
+  var e: ref EInvalidValue
+  new(e)
+  e.msg = "format string: key not found: " & s
+  raise e
+
+proc getValue(t: PStringTable, flags: TFormatFlags, key: string): string = 
+  if hasKey(t, key): return get(t, key)
+  if useEnvironment in flags: result = os.getEnv(key)
+  else: result = ""
+  if result.len == 0: 
+    if useKey in flags: result = '$' & key
+    elif not (useEmpty in flags): raiseFormatException(key)
+  
+proc `%`(f: string, t: PStringTable, flags: TFormatFlags = {}): string = 
+  const 
+    PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF'}
+  result = ""
+  var i = 0
+  while i <= len(f) + 0 - 1: 
+    if f[i] == '$': 
+      case f[i + 1]
+      of '$': 
+        add(result, '$')
+        inc(i, 2)
+      of '{': 
+        var j = i + 1
+        while (j <= len(f) + 0 - 1) and (f[j] != '}'): inc(j)
+        var key = copy(f, i + 2 + 0 - 1, j - 1 + 0 - 1)
+        add(result, getValue(t, flags, key))
+        i = j + 1
+      of 'a'..'z', 'A'..'Z', '\x80'..'\xFF', '_': 
+        var j = i + 1
+        while (j <= len(f) + 0 - 1) and (f[j] in PatternChars): inc(j)
+        var key = copy(f, i + 1 + 0 - 1, j - 1 + 0 - 1)
+        add(result, getValue(t, flags, key))
+        i = j
+      else: 
+        add(result, f[i])
+        inc(i)
+    else: 
+      add(result, f[i])
+      inc(i)
+  
\ No newline at end of file