git » nmdb » commit 03a87c1

Add D bindings.

author Alberto Bertogli
2007-03-28 01:47:43 UTC
committer Alberto Bertogli
2007-03-28 01:47:43 UTC
parent 8568296068ced9ff713fd60f93be0cffa2f27bf9

Add D bindings.

This adds the initial D bindings. At the moment they only work on amd64 boxes,
but it's quite easy to add support for other architectures.

It needs testing and documentation, this is only the main code.

d/nmdb.d +177 -0
d/nmdb_ll.d +52 -0
d/sizeof.c +17 -0
d/test1c.d +44 -0
d/testt.d +21 -0

diff --git a/d/nmdb.d b/d/nmdb.d
new file mode 100644
index 0000000..f69344f
--- /dev/null
+++ b/d/nmdb.d
@@ -0,0 +1,177 @@
+
+module nmdb;
+
+import nmdb_ll;
+
+
+/* Exception to raise when a key can't be found. It'd be better to use the
+ * same D arrays use (ArrayBoundsException) but it's designed for compiler
+ * use, and the lack of a standard exception hierarchy sucks. */
+class KeyNotFound : Exception {
+	this(char[] s) {
+		super(s);
+	}
+}
+
+
+/* Operation modes */
+enum {
+	MODE_NORMAL = 1,
+	MODE_CACHE = 2,
+	MODE_SYNC = 3,
+}
+
+
+class DB
+{
+	private nmdb_t *db;
+	int mode = MODE_NORMAL;
+
+
+	this(int port = 10)
+	{
+		db = nmdb_init(port);
+	}
+
+	~this()
+	{
+		nmdb_free(db);
+	}
+
+
+	private char[] do_get(char[] key, int mode)
+	{
+		long size;
+		ubyte* k = cast(ubyte *) key.ptr;
+		auto v = new char[256];
+
+		if (mode == MODE_NORMAL || mode == MODE_SYNC) {
+			size = nmdb_get(db, k, key.length,
+					cast(ubyte *) v, v.sizeof);
+		} else if (mode == MODE_CACHE) {
+			size = nmdb_cache_get(db, k, key.length,
+					cast(ubyte *) v, v.sizeof);
+		} else {
+			throw new Exception("Invalid mode");
+		}
+
+		if (size == 0) {
+			throw new KeyNotFound("Key not found: " ~ key);
+		} else if (size < 0) {
+			throw new Exception("Can't get value");
+		}
+
+		return v[0 .. cast(ulong) size];
+	}
+
+	private void do_set(char[] key, char[] val, int mode)
+	{
+		ubyte* k = cast(ubyte *) key.ptr;
+		ubyte* v = cast(ubyte *) val.ptr;
+		int res = 0;
+
+		if (mode == MODE_NORMAL) {
+			res = nmdb_set(db, k, key.length, v, val.length);
+		} else if (mode == MODE_SYNC) {
+			res = nmdb_set_sync(db, k, key.length,
+					v, val.length);
+		} else if (mode == MODE_CACHE) {
+			res = nmdb_cache_set(db, k, key.length,
+					v, val.length);
+		} else {
+			throw new Exception("Invalid mode");
+		}
+
+		if (res != 1) {
+			throw new Exception("Can't set value");
+		}
+	}
+
+	private int do_del(char[] key, int mode)
+	{
+		ubyte* k = cast(ubyte *) key.ptr;
+		int res = 0;
+
+		if (mode == MODE_NORMAL) {
+			res = nmdb_del(db, k, key.length);
+		} else if (mode == MODE_SYNC) {
+			res = nmdb_del_sync(db, k, key.length);
+		} else if (mode == MODE_CACHE) {
+			res = nmdb_cache_del(db, k, key.length);
+		} else {
+			throw new Exception("Invalid mode");
+		}
+		return res;
+	}
+
+
+	char[] get(char[] key)
+	{
+		return do_get(key, mode);
+	}
+
+	char[] get_normal(char[] key)
+	{
+		return do_get(key, MODE_NORMAL);
+	}
+
+	char[] cache_get(char[] key)
+	{
+		return do_get(key, MODE_CACHE);
+	}
+
+
+	void set(char[] key, char[] val)
+	{
+		return do_set(key, val, mode);
+	}
+
+	void set_normal(char[] key, char[] val)
+	{
+		return do_set(key, val, MODE_NORMAL);
+	}
+
+	void set_sync(char[] key, char[] val)
+	{
+		return do_set(key, val, MODE_SYNC);
+	}
+
+	void cache_set(char[] key, char[] val)
+	{
+		return do_set(key, val, MODE_CACHE);
+	}
+
+
+	int remove(char[] key)
+	{
+		return do_del(key, mode);
+	}
+
+	int remove_normal(char[] key)
+	{
+		return do_del(key, MODE_NORMAL);
+	}
+
+	int remove_sync(char[] key)
+	{
+		return do_del(key, MODE_SYNC);
+	}
+
+	int cache_remove(char[] key)
+	{
+		return do_del(key, MODE_CACHE);
+	}
+
+
+	char[] opIndex(char[] key)
+	{
+		return get(key);
+	}
+
+	void opIndexAssign(char[] val, char[] key)
+	{
+		return set(key, val);
+	}
+
+}
+
diff --git a/d/nmdb_ll.d b/d/nmdb_ll.d
new file mode 100644
index 0000000..8750eea
--- /dev/null
+++ b/d/nmdb_ll.d
@@ -0,0 +1,52 @@
+
+module nmdb_ll;
+
+
+/* We need to define the nmdb_t type used by the C API.
+ *
+ * One possiblity is to import the C struct here (alignment and stuff is
+ * supposed to be the same), but since it includes some OS structures like
+ * sockaddr_tipc, it means several lines of code and it's difficult to
+ * maintain. Because to us it's an opaque type, we define it to be an ubyte
+ * array of the same length as C's struct nmdb_t. That way we retain ABI
+ * compatibility but minimize the clutter.
+ *
+ * To port this to another architecture, just compile and run the "sizeof.c"
+ * program. It should output some lines like "sizeof(struct nmdb_t) = 16".
+ * Then use that information to define the aliases for your platform.
+ *
+ * Should nmdb_t change, the numbers must be updated to reflect the new sizes.
+ */
+
+version (X86_64) {
+	/* The following has been generated on a Pentium D running Gentoo in
+	 * 64 bit mode. It should be the same on all Linux amd64 boxes. */
+	alias ubyte[16] nmdb_t;
+	alias ulong size_t;
+	alias long ssize_t;
+}
+
+
+/* nmdb structures and prototypes, these shouldn't need any changes
+ * unless libnmdb/nmdb.h is updated */
+
+extern (C) nmdb_t *nmdb_init(int port);
+extern (C) int nmdb_add_server(nmdb_t *db, int port);
+extern (C) int nmdb_free(nmdb_t *db);
+
+extern (C) ssize_t nmdb_get(nmdb_t *db, ubyte *key, size_t ksize,
+		ubyte *val, size_t vsize);
+extern (C) ssize_t nmdb_cache_get(nmdb_t *db, ubyte *key, size_t ksize,
+		ubyte *val, size_t vsize);
+
+extern (C) int nmdb_set(nmdb_t *db, ubyte *key, size_t ksize,
+		ubyte *val, size_t vsize);
+extern (C) int nmdb_set_sync(nmdb_t *db, ubyte *key, size_t ksize,
+		ubyte *val, size_t vsize);
+extern (C) int nmdb_cache_set(nmdb_t *db, ubyte *key, size_t ksize,
+		ubyte *val, size_t vsize);
+
+extern (C) int nmdb_del(nmdb_t *db, ubyte *key, size_t ksize);
+extern (C) int nmdb_del_sync(nmdb_t *db, ubyte *key, size_t ksize);
+extern (C) int nmdb_cache_del(nmdb_t *db, ubyte *key, size_t ksize);
+
diff --git a/d/sizeof.c b/d/sizeof.c
new file mode 100644
index 0000000..93d053a
--- /dev/null
+++ b/d/sizeof.c
@@ -0,0 +1,17 @@
+
+/* sizeof.c
+ * Used to find out the size of some intresting structures and data types, to
+ * help defining D's bindings.
+ */
+
+#include <stdio.h>
+#include <nmdb.h>
+
+int main()
+{
+	printf("sizeof(struct nmdb_t) = %lu\n", sizeof(struct nmdb_t));
+	printf("sizeof(size_t) = %lu\n", sizeof(size_t));
+	printf("sizeof(ssize_t) = %lu\n", sizeof(ssize_t));
+	return 0;
+}
+
diff --git a/d/test1c.d b/d/test1c.d
new file mode 100644
index 0000000..1bbffc9
--- /dev/null
+++ b/d/test1c.d
@@ -0,0 +1,44 @@
+
+import nmdb;
+import std.stdio;
+import std.stream;
+import std.string;
+import std.perf;
+
+
+int main(char [][] argv)
+{
+	if (argv.length != 2) {
+		writefln("Usage: test1d TIMES");
+		return 1;
+	}
+
+	auto times = atoi(argv[1]);
+	char[] val;
+
+	nmdb.DB db = new nmdb.DB(10);
+	db.mode = nmdb.MODE_CACHE;
+
+	auto counter = new PerformanceCounter;
+
+	counter.start();
+	for (int i = 0; i < times; i++)
+		db["1"] = "D";
+	counter.stop();
+	writefln("d set: ", counter.microseconds());
+
+	counter.start();
+	for (int i = 0; i < times; i++)
+		val = db["1"];
+	counter.stop();
+	writefln("d get: ", counter.microseconds());
+
+	counter.start();
+	for (int i = 0; i < times; i++)
+		db.remove("1");
+	counter.stop();
+	writefln("d del: ", counter.microseconds());
+
+	return 0;
+}
+
diff --git a/d/testt.d b/d/testt.d
new file mode 100644
index 0000000..78e080a
--- /dev/null
+++ b/d/testt.d
@@ -0,0 +1,21 @@
+
+import nmdb;
+import std.stdio;
+import std.stream;
+
+
+int main()
+{
+	char[] val1;
+
+	nmdb.DB db = new nmdb.DB();
+
+	db.mode = MODE_CACHE;
+	db["1"] = "D";
+	val1 = db["1"];
+
+	writefln(val1);
+
+	return 0;
+}
+