Commits

Anonymous committed 2ef8fcf

initial revision pulled out from bitbucket.org/ww/hashtable

Comments (0)

Files changed (4)

+include $(GOROOT)/src/Make.inc
+
+TARG=bitbucket.org/ww/cabinet
+CGOFILES=cabinet.go		
+
+include $(GOROOT)/src/Make.pkg
+
+format:
+	for x in *.go; do gofmt $${x} > $${x}.fmt && mv $${x}.fmt $${x}; done
+
+docs:
+	godoc -v=true ${TARG} > README.txt
+
+Kyoto Cabinet bindings for Go.
+
+Written by William Waites in 2011
+
+This is public domain software, do with what you like, no warranties, etc.
+
+Normal usage will be along the lines of,
+
+    kc := cabinet.New()
+    err = kc.Open("some_db.kch")
+    kc.Set("hello", "world")
+    world, err = kc.Get("hello"
+    err = kc.Close()
+    kc.Del()
+
+Obviously checking the relevant errors...
+
+package cabinet
+import "bitbucket.org/ww/hashtable/kyoto/cabinet"
+
+TYPES
+
+type KCDB struct {
+    // contains unexported fields
+}
+
+func New() *KCDB
+
+func (kc *KCDB) Close() (err os.Error)
+
+func (kc *KCDB) Del()
+
+func (kc *KCDB) Get(key string) (value string, err os.Error)
+
+func (kc *KCDB) Open(filename string) (err os.Error)
+
+func (kc *KCDB) Set(key, value string) (err os.Error)
+
+/*
+ Kyoto Cabinet bindings for Go.
+
+ Written by William Waites in 2011
+
+ This is public domain software, do with what you like, no warranties, etc.
+
+ Normal usage will be along the lines of,
+
+     kc := cabinet.New()
+     err = kc.Open("some_db.kch")
+     kc.Set("hello", "world")
+     world, err = kc.Get("hello"
+     err = kc.Close()
+     kc.Del()
+
+ Obviously checking the relevant errors...
+
+*/
+
+package cabinet
+
+// #cgo CFLAGS: -I/usr/local/include
+// #cgo LDFLAGS: -L/usr/local/lib -lkyotocabinet
+// #include <kclangc.h>
+import "C"
+
+import (
+	"os"
+	"unsafe"
+)
+
+type KCDB struct {
+	db *C.KCDB
+}
+
+func New() *KCDB {
+	db := C.kcdbnew()
+	return &KCDB{db}
+}
+
+func (kc *KCDB) error() os.Error {
+	err := C.kcecodename(C.kcdbecode(kc.db))
+	return os.NewError(C.GoString(err))
+}
+
+func (kc *KCDB) Open(filename string) (err os.Error) {
+	name := C.CString(filename)
+	defer C.free(unsafe.Pointer(name))
+	if C.kcdbopen(kc.db, name, C.KCOWRITER|C.KCOCREATE) == 0 {
+		err = kc.error()
+	}
+	return
+}
+
+func (kc *KCDB) Close() (err os.Error) {
+	if C.kcdbclose(kc.db) == 0 {
+		err = kc.error()
+	}
+	return
+}
+
+func (kc *KCDB) Free() {
+	C.kcdbdel(kc.db)
+}
+
+func (kc *KCDB) Set(key, value string) (err os.Error) {
+	if C.kcdbset(kc.db,
+		C.CString(key), C.size_t(len(key)),
+		C.CString(value), C.size_t(len(value))) == 0 {
+		err = kc.error()
+	}
+	return
+}
+
+func (kc *KCDB) Add(key, value string) (err os.Error) {
+	if C.kcdbadd(kc.db,
+		C.CString(key), C.size_t(len(key)),
+		C.CString(value), C.size_t(len(value))) == 0 {
+		err = kc.error()
+	}
+	return
+}
+
+func (kc *KCDB) Replace(key, value string) (err os.Error) {
+	if C.kcdbreplace(kc.db,
+		C.CString(key), C.size_t(len(key)),
+		C.CString(value), C.size_t(len(value))) == 0 {
+		err = kc.error()
+	}
+	return
+}
+
+func (kc *KCDB) Append(key, value string) (err os.Error) {
+	if C.kcdbappend(kc.db,
+		C.CString(key), C.size_t(len(key)),
+		C.CString(value), C.size_t(len(value))) == 0 {
+		err = kc.error()
+	}
+	return
+}
+
+func (kc *KCDB) Remove(key string) (err os.Error) {
+	if C.kcdbremove(kc.db, C.CString(key), C.size_t(len(key))) == 0 {
+		err = kc.error()
+	}
+	return
+}
+
+func (kc *KCDB) Get(key string) (value string, err os.Error) {
+	var vlen C.size_t
+	cval := C.kcdbget(kc.db, C.CString(key), C.size_t(len(key)), &vlen)
+	if cval == nil {
+		err = kc.error()
+	} else {
+		value = C.GoString(cval)
+		C.kcfree(unsafe.Pointer(cval))
+	}
+	return
+}
+
+type KCCUR struct {
+	cur *C.KCCUR
+}
+
+func (kc *KCDB) Cursor() (kcc *KCCUR) {
+	cur := C.kcdbcursor(kc.db)
+	if cur == nil {
+		return nil
+	}
+	kcc = &KCCUR{cur}
+	kcc.Jump()
+	return
+}
+
+func (kcc *KCCUR) Jump() {
+	C.kccurjump(kcc.cur)
+}
+
+func (kcc *KCCUR) Free() {
+	C.kccurdel(kcc.cur)
+}
+
+func (kcc *KCCUR) GetKey(advance int) (k string, ok bool) {
+	var ksiz C.size_t
+	kp := C.kccurgetkey(kcc.cur, &ksiz, C.int32_t(advance))
+	if kp != nil {
+		k = C.GoString(kp)
+		C.kcfree(unsafe.Pointer(kp))
+		ok = true
+	}
+	return
+}
+
+func (kcc *KCCUR) GetValue(advance int) (v string, ok bool) {
+	var vsiz C.size_t
+	vp := C.kccurgetvalue(kcc.cur, &vsiz, C.int32_t(advance))
+	if vp != nil {
+		v = C.GoString(vp)
+		C.kcfree(unsafe.Pointer(vp))
+		ok = true
+	}
+	return
+}
+
+func (kcc *KCCUR) Get(advance int) (k, v string, ok bool) {
+	var ksiz, vsiz C.size_t
+	var vp *C.char
+	kp := C.kccurget(kcc.cur, &ksiz, &vp, &vsiz, C.int32_t(advance))
+	if kp != nil {
+		k = C.GoString(kp)
+		v = C.GoString(vp)
+		C.kcfree(unsafe.Pointer(kp))
+		ok = true
+	}
+	return
+}
+
+func (kc *KCDB) Keys() (out chan string) {
+	out = make(chan string)
+	go func() {
+		cur := kc.Cursor()
+		defer func() {
+			cur.Free()
+			close(out)
+		}()
+		for {
+			k, ok := cur.GetKey(1)
+			if !ok {
+				break
+			}
+			out <- k
+		}
+	}()
+	return
+}
+
+func (kc *KCDB) Values() (out chan string) {
+	out = make(chan string)
+	go func() {
+		cur := kc.Cursor()
+		defer func() {
+			cur.Free()
+			close(out)
+		}()
+		for {
+			v, ok := cur.GetValue(1)
+			if !ok {
+				break
+			}
+			out <- v
+		}
+	}()
+	return
+}
+
+type Item struct {
+	Key   string
+	Value string
+}
+
+func (kc *KCDB) Items() (out chan *Item) {
+	out = make(chan *Item)
+	go func() {
+		cur := kc.Cursor()
+		defer func() {
+			cur.Free()
+			close(out)
+		}()
+		for {
+			k, v, ok := cur.Get(1)
+			if !ok {
+				break
+			}
+			out <- &Item{k, v}
+		}
+	}()
+	return
+}
+package cabinet
+
+import (
+	"testing"
+	"os"
+)
+
+var test_db string = "casket.kch"
+
+func TestCabinet(t *testing.T) {
+	kc := New()
+	err := kc.Open(test_db)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer func() {
+		err = kc.Close()
+		if err != nil {
+			t.Fatal(err)
+		}
+		kc.Free()
+		os.Remove(test_db)
+	}()
+	err = kc.Set("hello", "world")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	world, err := kc.Get("hello")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if world != "world" {
+		t.Errorf("Get(hello) expected world, got %s", world)
+	}
+
+	keys := kc.Keys()
+	for {
+		k := <-keys
+		if closed(keys) {
+			break
+		}
+		if k != "hello" {
+			t.Errorf("key: %s", k)
+		}
+	}
+
+	values := kc.Values()
+	for {
+		v := <-values
+		if closed(values) {
+			break
+		}
+		if v != "world" {
+			t.Errorf("value: %s", v)
+		}
+	}
+
+	items := kc.Items()
+	for {
+		kvp := <-items
+		if closed(items) {
+			break
+		}
+		if kvp.Key != "hello" || kvp.Value != "world" {
+			t.Errorf("(%s, %s)", kvp.Key, kvp.Value)
+		}
+	}
+}