~ehmry/nim-tkrzw

aa2f1b21653d463ddda256980c9ed37970e83cdf — Emery Hemingway 3 years ago e8a54d0
C++ constructor chaos
3 files changed, 72 insertions(+), 46 deletions(-)

M src/tkrzw.nim
M tests/config.nims
M tests/test_tkrzw.nim
M src/tkrzw.nim => src/tkrzw.nim +58 -34
@@ 16,34 16,40 @@ type
    ooNoWait = 1 shl 2,
    ooNoLock = 1 shl 3

  HashDBM* {.
  HashDBMObj* {.
    header: "tkrzw_dbm_hash.h",
    importcpp: "tkrzw::HashDBM", byref.} = object
  HashDBM* = ref HashDBMObj
    ## File database manager implementation based on hash table.

  TreeDBM* {.
  TreeDBMObj {.
    header: "tkrzw_dbm_tree.h",
    importcpp: "tkrzw::TreeDBM", byref.} = object
  TreeDBM* = ref TreeDBMObj
    ## File database manager implementation based on B+ tree.

  SkipDBM* {.
  SkipDBMObj {.
    header: "tkrzw_dbm_skip.h",
    importcpp: "tkrzw::SkipDBM", byref.} = object
  SkipDBM* = ref SkipDBMObj
    ## File database manager implementation based on skip list.

  TinyDBM* {.
  TinyDBMObj {.
    header: "tkrzw_dbm_tiny.h",
    importcpp: "tkrzw::TinyDBM", byref.} = object
  TinyDBM* = ref TinyDBMObj
    ## TinyDBM : On-memory database manager implementation based on hash table.

  BabyDBM* {.
  BabyDBMObj {.
    header: "tkrzw_dbm_baby.h",
    importcpp: "tkrzw::BabyDBM", byref.} = object
  BabyDBM* = ref BabyDBMObj
    ## On-memory database manager implementation based on B+ tree.

  CacheDBM* {.
  CacheDBMObj {.
    header: "tkrzw_dbm_cache.h",
    importcpp: "tkrzw::CacheDBM", byref.} = object
  CacheDBM* = ref CacheDBMObj
    ## On-memory database manager implementation with LRU deletion.

  FileDBM = HashDBM | TreeDBM | SkipDBM


@@ 66,36 72,52 @@ proc GetKey(iter: Iterator): cstring {.importcpp: "#->GetKey().c_str()".}
proc GetValue(iter: Iterator): cstring {.importcpp: "#->GetValue().c_str()".}

template importDBM(T: untyped): untyped =
  proc Close(dbm: T) {.importcpp: "#.Close()".}
  proc GetSimple(dbm: T; key, default: cstring): cstring {.
      importcpp: "#.GetSimple(@).c_str()".}
  proc Set(dbm: T; key, value: cstring; overwrite: bool) {.importcpp: "#.Set(@)".}
  proc MakeIterator(dbm: T): Iterator {.importcpp: "#.MakeIterator()".}
  proc Synchronize(dbm: T; hard: bool): Status {.importcpp: "#.Synchronize(@)".}
  proc Rebuild(dbm: T): Status {.importcpp: "#.Rebuild()".}
  proc ShouldBeRebuilt(dbm: T; toBe: ptr bool): Status {.importcpp: "#.ShouldBeRebuilt()".}
  proc IsOpen(dbm: T): bool {.importcpp: "#.IsOpen()".}
  proc IsWritable(dbm: T): bool {.importcpp: "#.IsWritable()".}
  proc IsHealthy(dbm: T): bool {.importcpp: "#.IsHealthy()".}
  proc IsOrdered(dbm: T): bool {.importcpp: "#.IsOrdered()".}

template importFileDBM(T: untyped): untyped =
  proc `=destroy`(obj: var `T Obj`) {.importcpp: "#.~" & $T & "()".}
  proc Open(dbm: T; path: cstring; writeable: bool; options: int32) {.
      importcpp: "#.Open(@)".}
  importDBM(T)

importFileDBM(HashDBM)
importFileDBM(TreeDBM)
importFileDBM(SkipDBM)
      importcpp: "#->Open(@)".}
  proc Close(dbm: T) {.importcpp: "#->Close()".}
  proc GetSimple(dbm: T; key, default: cstring): cstring {.
      importcpp: "#->GetSimple(@).c_str()".}
  proc Set(dbm: T; key, value: cstring; overwrite: bool) {.
      importcpp: "#->Set(@)".}
  proc MakeIterator(dbm: T): Iterator {.importcpp: "#->MakeIterator()".}
  proc Synchronize(dbm: T; hard: bool): Status {.
      importcpp: "#->Synchronize(@)".}
  proc Rebuild(dbm: T): Status {.importcpp: "#->Rebuild()".}
  proc ShouldBeRebuilt(dbm: T; toBe: ptr bool): Status {.
      importcpp: "#->ShouldBeRebuilt()".}
  proc IsOpen(dbm: T): bool {.importcpp: "#->IsOpen()".}
  proc IsWritable(dbm: T): bool {.importcpp: "#->IsWritable()".}
  proc IsHealthy(dbm: T): bool {.importcpp: "#->IsHealthy()".}
  proc IsOrdered(dbm: T): bool {.importcpp: "#->IsOrdered()".}

importDBM(HashDBM)
importDBM(TreeDBM)
importDBM(SkipDBM)
importDBM(TinyDBM)
importDBM(BabyDBM)
importDBM(CacheDBM)

proc open*(dbm: FileDBM; path: string; rw: RW; options: set[OpenOption] = {}) =
  ## Opens a database file.
  var opt: int32
  for o in options.items: opt.inc o.int32
  dbm.Open(path, rw == writeable, opt)
proc construct[T](): T =
  new(result)
  {.emit: "new ((void*)result) tkrzw::" & $T & "();".}

template declareNewFile(T: untyped): untyped =
  proc `new T`*(path: string; rw: RW; options: set[OpenOption] = {}): T =
    var opts: int32
    for o in options.items: opts.inc o.int32
    result = construct[T]()
    result.Open(path, rw == writeable, opts)

template declareNewMem(T: untyped): untyped =
  proc `new T`*(): T = construct[T]()

declareNewFile(HashDBM)
declareNewFile(TreeDBM)
declareNewFile(SkipDBM)
declareNewMem(TinyDBM)
declareNewMem(BabyDBM)
declareNewMem(CacheDBM)

proc close*(dbm: DBM) =
  ## Closes the database file.


@@ 146,7 168,8 @@ proc rebuild*(dbm) =
proc rebuild*(dbm: TinyDBM; numBuckets = -1) =
  ## Rebuilds the entire database.
  ## When `numBuckets` is calculated implicitly when -1.
  proc RebuildAdvanced(dbm: TinyDBM; nb: int64): Status {.importcpp: "#.RebuildAdvanced(@)".}
  proc RebuildAdvanced(dbm: TinyDBM; nb: int64): Status {.
      importcpp: "#->RebuildAdvanced(@)".}
  check dbm.RebuildAdvanced(numBuckets)

proc rebuild*(dbm: CacheDBM; capRecNum = -1; capMemSize = -1) =


@@ 154,13 177,14 @@ proc rebuild*(dbm: CacheDBM; capRecNum = -1; capMemSize = -1) =
  ## * `capRecNum` is the maximum number of records.
  ## * `capMemSize` is the total memory size to use
  ## When `numBuckets` is calculated implicitly when -1.
  proc RebuildAdvanced(dbm: CacheDBM; crn, cms: int64): Status {.importcpp: "#.RebuildAdvanced(@)".}
  proc RebuildAdvanced(dbm: CacheDBM; crn, cms: int64): Status {.
      importcpp: "#->RebuildAdvanced(@)".}
  check dbm.RebuildAdvanced(capRecNum, capMemSize)

proc isOpen*(dbm): bool = dbm.IsOpen()
  ## Checks whether the database is open.

proc isWritable*(dbm): bool = dbm .IsWritable()
proc isWritable*(dbm): bool = dbm.IsWritable()
  ## Checks whether the database is writable.

proc isHealthy*(dbm): bool = dbm.IsHealthy()

M tests/config.nims => tests/config.nims +1 -1
@@ 1,1 1,1 @@
switch("path", "$projectDir/../src")
\ No newline at end of file
switch("path", "$projectDir/../src")

M tests/test_tkrzw.nim => tests/test_tkrzw.nim +13 -11
@@ 2,18 2,20 @@ import std/[os, unittest]

import tkrzw

template testEx1(T: untyped; isFile: static[bool]): untyped =
template testEx1(newProc: untyped; isFile: static[bool]): untyped =
  test "ex1":
    const path = "casket.test"
    var dbm: T
    when isFIle:
      dbm.open(path, writeable, {ooTruncate})
    when isFile:
      var dbm = newProc(path, writeable, {ooTruncate})
        # newHashDBM(…), etc
    else:
      var dbm = newProc()

    dbm["foo"] = "hop"
    dbm["bar"] = "step"
    dbm["baz"] = "jump"

    dbm.synchronize(hard=false)
    dbm.synchronize(hard = false)

    check dbm["foo"] == "hop"
    check dbm["bar"] == "step"


@@ 32,19 34,19 @@ template testEx1(T: untyped; isFile: static[bool]): untyped =
    removeFile(path)

suite "HashDBM":
  testEx1(HashDBM, true)
  testEx1(newHashDBM, true)

suite "TreeDBM":
  testEx1(TreeDBM, true)
  testEx1(newTreeDBM, true)

suite "SkipDBM":
  testEx1(SkipDBM, true)
  testEx1(newSkipDBM, true)

suite "TinyDBM":
  testEx1(TinyDBM, false)
  testEx1(newTinyDBM, false)

suite "BabyDBM":
  testEx1(BabyDBM, false)
  testEx1(newBabyDBM, false)

suite "CacheDBM":
  testEx1(CacheDBM, false)
  testEx1(newCacheDBM, false)