You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by dc...@apache.org on 2011/09/26 14:36:27 UTC

svn commit: r1175832 [5/5] - in /avro/trunk: ./ lang/c/docs/ lang/c/examples/ lang/c/src/ lang/c/src/avro/ lang/c/tests/

Modified: avro/trunk/lang/c/src/string.c
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/src/string.c?rev=1175832&r1=1175831&r2=1175832&view=diff
==============================================================================
--- avro/trunk/lang/c/src/string.c (original)
+++ avro/trunk/lang/c/src/string.c Mon Sep 26 12:36:26 2011
@@ -24,6 +24,21 @@
 #include "avro/allocation.h"
 #include "avro/errors.h"
 
+#ifndef AVRO_STRING_DEBUG
+#define AVRO_STRING_DEBUG 0
+#endif
+
+#if AVRO_STRING_DEBUG
+#include <stdio.h>
+#define DEBUG(...) \
+	do { \
+		fprintf(stderr, __VA_ARGS__); \
+		fprintf(stderr, "\n"); \
+	} while (0)
+#else
+#define DEBUG(...)  /* don't print messages */
+#endif
+
 
 /*
  * A resizable wrapped buffer implementation.  This implementation makes
@@ -43,6 +58,7 @@ struct avro_wrapped_resizable {
 static void
 avro_wrapped_resizable_free(avro_wrapped_buffer_t *self)
 {
+	DEBUG("--- Freeing resizable <%p:%zu> (%p)", self->buf, self->size, self->user_data);
 	struct avro_wrapped_resizable  *resizable = self->user_data;
 	avro_free(resizable, avro_wrapped_resizable_size(resizable->buf_size));
 }
@@ -52,11 +68,23 @@ avro_wrapped_resizable_resize(avro_wrapp
 {
 	struct avro_wrapped_resizable  *resizable = self->user_data;
 
+	/*
+	 * If we've already allocated enough memory for the desired
+	 * size, there's nothing to do.
+	 */
+
+	if (resizable->buf_size >= desired) {
+		return 0;
+	}
+
 	size_t  new_buf_size = resizable->buf_size * 2;
 	if (desired > new_buf_size) {
 		new_buf_size = desired;
 	}
 
+	DEBUG("--- Resizing <%p:%zu> (%p) -> %zu",
+	      self->buf, self->buf_size, self->user_data, new_buf_size);
+
 	struct avro_wrapped_resizable  *new_resizable =
 	    avro_realloc(resizable,
 		         avro_wrapped_resizable_size(resizable->buf_size),
@@ -64,6 +92,7 @@ avro_wrapped_resizable_resize(avro_wrapp
 	if (new_resizable == NULL) {
 		return ENOMEM;
 	}
+	DEBUG("--- New buffer <%p:%zu>", new_buf, new_buf_size);
 
 	new_resizable->buf_size = new_buf_size;
 
@@ -71,8 +100,10 @@ avro_wrapped_resizable_resize(avro_wrapp
 	void  *new_buf = new_resizable;
 
 	ptrdiff_t  offset = self->buf - old_buf;
+	DEBUG("--- Old data pointer is %p", self->buf);
 	self->buf = new_buf + offset;
 	self->user_data = new_resizable;
+	DEBUG("--- New data pointer is %p", self->buf);
 	return 0;
 }
 
@@ -89,6 +120,7 @@ avro_wrapped_resizable_new(avro_wrapped_
 	resizable->buf_size = buf_size;
 
 	dest->buf = ((void *) resizable) + sizeof(struct avro_wrapped_resizable);
+	DEBUG("--- Creating resizable <%p:%zu> (%p)", dest->buf, buf_size, resizable);
 	dest->size = buf_size;
 	dest->user_data = resizable;
 	dest->free = avro_wrapped_resizable_free;
@@ -119,8 +151,10 @@ avro_raw_string_clear(avro_raw_string_t 
 	 */
 
 	if (is_resizable(str->wrapped)) {
+		DEBUG("--- Clearing resizable buffer");
 		str->wrapped.size = 0;
 	} else {
+		DEBUG("--- Freeing wrapped buffer");
 		avro_wrapped_buffer_free(&str->wrapped);
 		avro_raw_string_init(str);
 	}
@@ -146,6 +180,7 @@ avro_raw_string_ensure_buf(avro_raw_stri
 {
 	int  rval;
 
+	DEBUG("--- Ensuring resizable buffer of size %zu", length);
 	if (is_resizable(str->wrapped)) {
 		/*
 		 * If we've already got a resizable buffer, just have it
@@ -191,6 +226,20 @@ avro_raw_string_set_length(avro_raw_stri
 }
 
 
+void avro_raw_string_append_length(avro_raw_string_t *str,
+				   const void *src,
+				   size_t length)
+{
+	if (avro_raw_string_length(str) == 0) {
+		return avro_raw_string_set_length(str, src, length);
+	}
+
+	avro_raw_string_ensure_buf(str, str->wrapped.size + length);
+	memcpy((void *) str->wrapped.buf + str->wrapped.size, src, length);
+	str->wrapped.size += length;
+}
+
+
 void
 avro_raw_string_set(avro_raw_string_t *str, const char *src)
 {
@@ -210,7 +259,7 @@ avro_raw_string_append(avro_raw_string_t
 
 	/* Assume that str->wrapped.size includes a NUL terminator */
 	size_t  length = strlen(src);
-	avro_raw_string_ensure_buf(str, str->wrapped.size+length);
+	avro_raw_string_ensure_buf(str, str->wrapped.size + length);
 	memcpy((void *) str->wrapped.buf + str->wrapped.size - 1, src, length+1);
 	str->wrapped.size += length;
 }
@@ -220,6 +269,8 @@ void
 avro_raw_string_give(avro_raw_string_t *str,
 		     avro_wrapped_buffer_t *src)
 {
+	DEBUG("--- Giving control of <%p:%zu> (%p) to string",
+	      src->buf, src->size, src);
 	avro_wrapped_buffer_free(&str->wrapped);
 	avro_wrapped_buffer_move(&str->wrapped, src);
 }

Added: avro/trunk/lang/c/src/value-hash.c
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/src/value-hash.c?rev=1175832&view=auto
==============================================================================
--- avro/trunk/lang/c/src/value-hash.c (added)
+++ avro/trunk/lang/c/src/value-hash.c Mon Sep 26 12:36:26 2011
@@ -0,0 +1,294 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avro/allocation.h"
+#include "avro/data.h"
+#include "avro/errors.h"
+#include "avro/value.h"
+#include "avro_private.h"
+
+#define check_return(retval, call) \
+	do { \
+		int  rval = call; \
+		if (rval != 0) { return (retval); } \
+	} while (0)
+
+/*
+ * We currently use MurmurHash3 [1], which is public domain, as our hash
+ * implementation.
+ *
+ * [1] http://code.google.com/p/smhasher/
+ */
+
+/* Our seed is the MurmurHash3 of the string "avro.value" */
+#define SEED  0xaf4c78df
+
+#define ROTL32(a,b) (((a) << ((b) & 0x1f)) | ((a) >> (32 - ((b) & 0x1f))))
+
+static inline uint32_t
+fmix(uint32_t h)
+{
+	h ^= h >> 16;
+	h *= 0x85ebca6b;
+	h ^= h >> 13;
+	h *= 0xc2b2ae35;
+	h ^= h >> 16;
+	return h;
+}
+
+static const uint32_t  c1 = 0xcc9e2d51;
+static const uint32_t  c2 = 0x1b873593;
+
+static inline uint32_t
+add_hash(uint32_t start, uint32_t current)
+{
+	current *= c1;
+	current = ROTL32(current, 15);
+	current *= c2;
+
+	start ^= current;
+	start = ROTL32(start, 13);
+	start = start * 5 + 0xe6546b64;
+
+	return start;
+}
+
+static inline uint32_t
+hash_buffer(uint32_t start, const void *src, size_t len)
+{
+	const uint8_t  *data = (const uint8_t *) src;
+	const int  nblocks = len / 4;
+
+	uint32_t  h1 = start;
+
+	//----------
+	// body
+
+	const uint32_t  *blocks = (const uint32_t *) (data + nblocks*4);
+	int  i;
+
+	for (i = -nblocks; i != 0; i++) {
+		uint32_t  k1 = blocks[i];
+
+		k1 *= c1;
+		k1 = ROTL32(k1,15);
+		k1 *= c2;
+
+		h1 ^= k1;
+		h1 = ROTL32(h1,13);
+		h1 = h1*5+0xe6546b64;
+	}
+
+	//----------
+	// tail
+
+	const uint8_t  *tail = (const uint8_t *) (data + nblocks*4);
+
+	uint32_t  k1 = 0;
+
+	switch (len & 3)
+	{
+		case 3: k1 ^= tail[2] << 16;
+		case 2: k1 ^= tail[1] << 8;
+		case 1: k1 ^= tail[0];
+			k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
+	};
+
+	//----------
+	// finalization
+
+	h1 ^= len;
+	return h1;
+}
+
+static uint32_t
+avro_value_hash_fast(avro_value_t *value, uint32_t start)
+{
+	avro_type_t  type = avro_value_get_type(value);
+
+	switch (type) {
+		case AVRO_BOOLEAN:
+		{
+			int  v;
+			check_return(0, avro_value_get_boolean(value, &v));
+			return add_hash(start, v);
+		}
+
+		case AVRO_BYTES:
+		{
+			const void  *buf;
+			size_t  size;
+			check_return(0, avro_value_get_bytes(value, &buf, &size));
+			return hash_buffer(start, buf, size);
+		}
+
+		case AVRO_DOUBLE:
+		{
+			union {
+				double  d;
+				uint32_t  u32[2];
+			} v;
+			check_return(0, avro_value_get_double(value, &v.d));
+			return add_hash(add_hash(start, v.u32[0]), v.u32[1]);
+		}
+
+		case AVRO_FLOAT:
+		{
+			union {
+				float  f;
+				uint32_t  u32;
+			} v;
+			check_return(0, avro_value_get_float(value, &v.f));
+			return add_hash(start, v.u32);
+		}
+
+		case AVRO_INT32:
+		{
+			int32_t  v;
+			check_return(0, avro_value_get_int(value, &v));
+			return add_hash(start, v);
+		}
+
+		case AVRO_INT64:
+		{
+			union {
+				int64_t  u64;
+				uint32_t  u32[2];
+			} v;
+			check_return(0, avro_value_get_long(value, &v.u64));
+			return add_hash(add_hash(start, v.u32[0]), v.u32[1]);
+		}
+
+		case AVRO_NULL:
+		{
+			check_return(0, avro_value_get_null(value));
+			return add_hash(start, 0);
+		}
+
+		case AVRO_STRING:
+		{
+			const char  *buf;
+			size_t  size;
+			check_return(0, avro_value_get_string(value, &buf, &size));
+			return hash_buffer(start, buf, size);
+		}
+
+		case AVRO_ARRAY:
+		{
+			size_t  count;
+			size_t  i;
+			check_return(0, avro_value_get_size(value, &count));
+
+			for (i = 0; i < count; i++) {
+				avro_value_t  child;
+				check_return(0, avro_value_get_by_index
+					     (value, i, &child, NULL));
+				start = avro_value_hash_fast(&child, start);
+			}
+
+			start ^= count;
+			return start;
+		}
+
+		case AVRO_ENUM:
+		{
+			int  v;
+			check_return(0, avro_value_get_enum(value, &v));
+			return add_hash(start, v);
+		}
+
+		case AVRO_FIXED:
+		{
+			const void  *buf;
+			size_t  size;
+			check_return(0, avro_value_get_fixed(value, &buf, &size));
+			return hash_buffer(start, buf, size);
+		}
+
+		case AVRO_MAP:
+		{
+			size_t  count;
+			size_t  i;
+			check_return(0, avro_value_get_size(value, &count));
+
+			/*
+			 * The hash for a map must be built up without
+			 * taking into account the order of the elements
+			 */
+			uint32_t  map_hash = 0;
+			for (i = 0; i < count; i++) {
+				avro_value_t  child;
+				const char  *key;
+				check_return(0, avro_value_get_by_index
+					     (value, i, &child, &key));
+
+				uint32_t  element = SEED;
+				element = hash_buffer(element, key, strlen(key));
+				element = avro_value_hash_fast(&child, element);
+				element = fmix(element);
+
+				map_hash ^= element;
+			}
+			map_hash ^= count;
+
+			return add_hash(start, map_hash);
+		}
+
+		case AVRO_RECORD:
+		{
+			size_t  count;
+			size_t  i;
+			check_return(0, avro_value_get_size(value, &count));
+
+			for (i = 0; i < count; i++) {
+				avro_value_t  child;
+				check_return(0, avro_value_get_by_index
+					     (value, i, &child, NULL));
+				start = avro_value_hash_fast(&child, start);
+			}
+
+			start ^= count;
+			return start;
+		}
+
+		case AVRO_UNION:
+		{
+			int  disc;
+			avro_value_t  branch;
+			check_return(0, avro_value_get_discriminant(value, &disc));
+			check_return(0, avro_value_get_current_branch(value, &branch));
+
+			start = add_hash(start, disc);
+			start = avro_value_hash_fast(&branch, start);
+			return start;
+		}
+
+		default:
+			return 0;
+	}
+}
+
+uint32_t
+avro_value_hash(avro_value_t *value)
+{
+	uint32_t  hash = avro_value_hash_fast(value, SEED);
+	return (hash == 0)? hash: fmix(hash);
+}

Modified: avro/trunk/lang/c/src/value-read.c
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/src/value-read.c?rev=1175832&r1=1175831&r2=1175832&view=diff
==============================================================================
--- avro/trunk/lang/c/src/value-read.c (original)
+++ avro/trunk/lang/c/src/value-read.c Mon Sep 26 12:36:26 2011
@@ -141,8 +141,8 @@ read_record_value(avro_reader_t reader, 
 	for (i = 0; i < field_count; i++) {
 		avro_value_t  field;
 
-		rval = avro_value_get_by_index(dest, i, &field, NULL);
-		if (rval == 0) {
+		check(rval, avro_value_get_by_index(dest, i, &field, NULL));
+		if (field.iface != NULL) {
 			check(rval, read_value(reader, &field));
 		} else {
 			avro_schema_t  field_schema =

Modified: avro/trunk/lang/c/src/value.c
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/src/value.c?rev=1175832&r1=1175831&r2=1175832&view=diff
==============================================================================
--- avro/trunk/lang/c/src/value.c (original)
+++ avro/trunk/lang/c/src/value.c Mon Sep 26 12:36:26 2011
@@ -25,50 +25,47 @@
 #include "avro/value.h"
 #include "avro_private.h"
 
-int
-avro_value_new(const avro_value_iface_t *cls, avro_value_t *val)
-{
-	int  rval;
 
-	val->iface = cls;
+#define check_return(retval, call) \
+	do { \
+		int  rval = call; \
+		if (rval != 0) { return (retval); } \
+	} while (0)
 
-	size_t  instance_size = avro_value_instance_size(cls);
-	if (instance_size == 0) {
-		val->iface = NULL;
-		avro_set_error("Value class doesn't declare instance_size");
-		return EINVAL;
-	}
 
-	val->self = avro_malloc(instance_size);
-	if (val->self == NULL) {
-		avro_set_error(strerror(ENOMEM));
-		return ENOMEM;
-	}
+void
+avro_value_incref(avro_value_t *value)
+{
+	value->iface->incref(value);
+}
 
-	rval = avro_value_init(cls, val->self);
-	if (rval) {
-		avro_free(val->self, instance_size);
-		val->self = NULL;
-		return rval;
-	}
+void
+avro_value_decref(avro_value_t *value)
+{
+	value->iface->decref(value);
+	avro_value_iface_decref(value->iface);
+	value->iface = NULL;
+	value->self = NULL;
+}
 
-	return 0;
+void
+avro_value_copy_ref(avro_value_t *dest, const avro_value_t *src)
+{
+	dest->iface = src->iface;
+	dest->self = src->self;
+	avro_value_iface_incref(dest->iface);
+	dest->iface->incref(dest);
 }
 
 void
-avro_value_free(avro_value_t *val)
+avro_value_move_ref(avro_value_t *dest, avro_value_t *src)
 {
-	if (val->self != NULL) {
-		avro_value_done(val);
-		avro_free(val->self, avro_value_instance_size(val->iface));
-	}
+	dest->iface = src->iface;
+	dest->self = src->self;
+	src->iface = NULL;
+	src->self = NULL;
 }
 
-#define check_return(retval, call) \
-	do { \
-		int  rval = call; \
-		if (rval != 0) { return (retval); } \
-	} while (0)
 
 int
 avro_value_equal_fast(avro_value_t *val1, avro_value_t *val2)

Modified: avro/trunk/lang/c/tests/performance.c
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/tests/performance.c?rev=1175832&r1=1175831&r2=1175832&view=diff
==============================================================================
--- avro/trunk/lang/c/tests/performance.c (original)
+++ avro/trunk/lang/c/tests/performance.c Mon Sep 26 12:36:26 2011
@@ -210,10 +210,10 @@ test_nested_record_value_by_index(unsign
 	avro_value_iface_t  *iface = avro_generic_class_from_schema(schema);
 
 	avro_value_t  val;
-	avro_value_new(iface, &val);
+	avro_generic_value_new(iface, &val);
 
 	avro_value_t  out;
-	avro_value_new(iface, &out);
+	avro_generic_value_new(iface, &out);
 
 	for (i = 0; i < num_tests; i++) {
 		avro_value_t  field;
@@ -249,8 +249,8 @@ test_nested_record_value_by_index(unsign
 		avro_value_equal_fast(&val, &out);
 	}
 
-	avro_value_free(&val);
-	avro_value_free(&out);
+	avro_value_decref(&val);
+	avro_value_decref(&out);
 	avro_value_iface_decref(iface);
 	avro_schema_decref(schema);
 }
@@ -310,10 +310,10 @@ test_nested_record_value_by_name(unsigne
 	avro_value_iface_t  *iface = avro_generic_class_from_schema(schema);
 
 	avro_value_t  val;
-	avro_value_new(iface, &val);
+	avro_generic_value_new(iface, &val);
 
 	avro_value_t  out;
-	avro_value_new(iface, &out);
+	avro_generic_value_new(iface, &out);
 
 	for (i = 0; i < num_tests; i++) {
 		avro_value_t  field;
@@ -349,8 +349,8 @@ test_nested_record_value_by_name(unsigne
 		avro_value_equal_fast(&val, &out);
 	}
 
-	avro_value_free(&val);
-	avro_value_free(&out);
+	avro_value_decref(&val);
+	avro_value_decref(&out);
 	avro_value_iface_decref(iface);
 	avro_schema_decref(schema);
 }

Modified: avro/trunk/lang/c/tests/test_avro_data.c
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/tests/test_avro_data.c?rev=1175832&r1=1175831&r2=1175832&view=diff
==============================================================================
--- avro/trunk/lang/c/tests/test_avro_data.c (original)
+++ avro/trunk/lang/c/tests/test_avro_data.c Mon Sep 26 12:36:26 2011
@@ -49,7 +49,8 @@ test_allocator(void *ud, void *ptr, size
 				"doesn't match size passed to "
 				"avro_malloc (%zu)\n",
 				ptr, osize, *size);
-			exit(EXIT_FAILURE);
+			abort();
+			//exit(EXIT_FAILURE);
 		}
 		free(size);
 		return NULL;

Modified: avro/trunk/lang/c/tests/test_avro_values.c
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/tests/test_avro_values.c?rev=1175832&r1=1175831&r2=1175832&view=diff
==============================================================================
--- avro/trunk/lang/c/tests/test_avro_values.c (original)
+++ avro/trunk/lang/c/tests/test_avro_values.c Mon Sep 26 12:36:26 2011
@@ -316,7 +316,7 @@ _check_write_read(avro_value_t *val)
 	}
 
 	avro_value_t  val_in;
-	if (avro_value_new(val->iface, &val_in)) {
+	if (avro_generic_value_new(val->iface, &val_in)) {
 		fprintf(stderr, "Cannot allocate new value instance:\n  %s\n",
 			avro_strerror());
 		return EXIT_FAILURE;
@@ -333,7 +333,7 @@ _check_write_read(avro_value_t *val)
 		exit(EXIT_FAILURE);
 	}
 
-	avro_value_free(&val_in);
+	avro_value_decref(&val_in);
 	avro_reader_free(reader);
 	avro_writer_free(writer);
 
@@ -344,10 +344,25 @@ _check_write_read(avro_value_t *val)
 	check_(_check_write_read(val))
 
 static int
+_check_hash(avro_value_t *val1, avro_value_t *val2)
+{
+	uint32_t  hash1 = avro_value_hash(val1);
+	uint32_t  hash2 = avro_value_hash(val2);
+	if (hash1 != hash2) {
+		fprintf(stderr, "Copied hashed not equal\n");
+		return EXIT_FAILURE;
+	}
+	return EXIT_SUCCESS;
+}
+
+#define check_hash(val1, val2) \
+	check_(_check_hash(val1, val2))
+
+static int
 _check_copy(avro_value_t *val)
 {
 	avro_value_t  copied_val;
-	if (avro_value_new(val->iface, &copied_val)) {
+	if (avro_generic_value_new(val->iface, &copied_val)) {
 		fprintf(stderr, "Cannot allocate new value instance:\n  %s\n",
 			avro_strerror());
 		return EXIT_FAILURE;
@@ -361,10 +376,12 @@ _check_copy(avro_value_t *val)
 
 	if (!avro_value_equal(val, &copied_val)) {
 		fprintf(stderr, "Copied values not equal\n");
-		exit(EXIT_FAILURE);
+		return EXIT_FAILURE;
 	}
 
-	avro_value_free(&copied_val);
+	check_hash(val, &copied_val);
+
+	avro_value_decref(&copied_val);
 	return EXIT_SUCCESS;
 }
 
@@ -403,7 +420,7 @@ test_boolean(void)
 		check_invalid_methods("boolean", &val);
 		check_write_read(&val);
 		check_copy(&val);
-		avro_value_free(&val);
+		avro_value_decref(&val);
 	}
 	return 0;
 }
@@ -460,7 +477,7 @@ test_bytes(void)
 	check_invalid_methods("bytes", &val);
 	check_write_read(&val);
 	check_copy(&val);
-	avro_value_free(&val);
+	avro_value_decref(&val);
 	return 0;
 }
 
@@ -495,7 +512,7 @@ test_double(void)
 		check_invalid_methods("double", &val);
 		check_write_read(&val);
 		check_copy(&val);
-		avro_value_free(&val);
+		avro_value_decref(&val);
 	}
 	return 0;
 }
@@ -531,7 +548,7 @@ test_float(void)
 		check_invalid_methods("float", &val);
 		check_write_read(&val);
 		check_copy(&val);
-		avro_value_free(&val);
+		avro_value_decref(&val);
 	}
 	return 0;
 }
@@ -567,7 +584,7 @@ test_int(void)
 		check_invalid_methods("int", &val);
 		check_write_read(&val);
 		check_copy(&val);
-		avro_value_free(&val);
+		avro_value_decref(&val);
 	}
 	return 0;
 }
@@ -603,7 +620,7 @@ test_long(void)
 		check_invalid_methods("long", &val);
 		check_write_read(&val);
 		check_copy(&val);
-		avro_value_free(&val);
+		avro_value_decref(&val);
 	}
 	return 0;
 }
@@ -629,7 +646,7 @@ test_null(void)
 	check_invalid_methods("null", &val);
 	check_write_read(&val);
 	check_copy(&val);
-	avro_value_free(&val);
+	avro_value_decref(&val);
 	return 0;
 }
 
@@ -735,7 +752,7 @@ test_string(void)
 		check_invalid_methods("string", &val);
 		check_write_read(&val);
 		check_copy(&val);
-		avro_value_free(&val);
+		avro_value_decref(&val);
 	}
 
 	return 0;
@@ -757,7 +774,7 @@ test_array(void)
 		size_t  count = rand_count();
 
 		avro_value_t  val;
-		try(avro_value_new(array_class, &val),
+		try(avro_generic_value_new(array_class, &val),
 		    "Cannot create array");
 		check(rval, check_type_and_schema
 			    ("array", &val, AVRO_ARRAY,
@@ -813,7 +830,7 @@ test_array(void)
 		}
 
 		check_invalid_methods("array", &val);
-		avro_value_free(&val);
+		avro_value_decref(&val);
 	}
 
 	avro_schema_decref(double_schema);
@@ -842,7 +859,7 @@ test_enum(void)
 	}
 
 	avro_value_iface_t  *enum_class =
-	    avro_generic_enum_class(enum_schema);
+	    avro_generic_class_from_schema(enum_schema);
 
 	int  rval;
 
@@ -850,7 +867,7 @@ test_enum(void)
 	for (i = 0; i < 4; i++) {
 		int  expected = i;
 		avro_value_t  val;
-		try(avro_value_new(enum_class, &val),
+		try(avro_generic_value_new(enum_class, &val),
 		    "Cannot create enum");
 		check(rval, check_type_and_schema
 			    ("enum", &val, AVRO_ENUM,
@@ -872,7 +889,7 @@ test_enum(void)
 		check_invalid_methods("enum", &val);
 		check_write_read(&val);
 		check_copy(&val);
-		avro_value_free(&val);
+		avro_value_decref(&val);
 	}
 
 	avro_schema_decref(enum_schema);
@@ -900,14 +917,14 @@ test_fixed(void)
 	}
 
 	avro_value_iface_t  *fixed_class =
-	    avro_generic_fixed_class(fixed_schema);
+	    avro_generic_class_from_schema(fixed_schema);
 
 	int  rval;
 
 	char fixed[] = { 0xDE, 0xAD, 0xBE, 0xEF };
 
 	avro_value_t  val;
-	try(avro_value_new(fixed_class, &val),
+	try(avro_generic_value_new(fixed_class, &val),
 	    "Cannot create fixed");
 	check(rval, check_type_and_schema
 		    ("fixed", &val, AVRO_FIXED,
@@ -956,7 +973,7 @@ test_fixed(void)
 	check_invalid_methods("fixed", &val);
 	check_write_read(&val);
 	check_copy(&val);
-	avro_value_free(&val);
+	avro_value_decref(&val);
 	avro_schema_decref(fixed_schema);
 	avro_value_iface_decref(fixed_class);
 	return 0;
@@ -978,7 +995,7 @@ test_map(void)
 		size_t  count = rand_count();
 
 		avro_value_t  val;
-		try(avro_value_new(map_class, &val),
+		try(avro_generic_value_new(map_class, &val),
 		    "Cannot create map");
 		check(rval, check_type_and_schema
 			    ("map", &val, AVRO_MAP,
@@ -1048,6 +1065,38 @@ test_map(void)
 			return EXIT_FAILURE;
 		}
 
+		/*
+		 * Create a reversed copy of the map to ensure that the
+		 * element ordering doesn't affect the hash value.
+		 */
+
+		avro_value_t  reversed;
+		try(avro_generic_value_new(map_class, &reversed),
+		    "Cannot create map");
+
+		for (j = count; j-- > 0; ) {
+			avro_value_t  element;
+			const char  *key = NULL;
+			double  element_value = 0.0;
+			try(avro_value_get_by_index(&val, j, &element, &key),
+			    "Cannot get from map");
+			try(avro_value_get_double(&element, &element_value),
+			    "Cannot get double value");
+
+			try(avro_value_add(&reversed, key, &element, NULL, NULL),
+			    "Cannot add to map");
+			try(avro_value_set_double(&element, element_value),
+			    "Cannot set double");
+		}
+
+		check_hash(&val, &reversed);
+		if (!avro_value_equal(&val, &reversed)) {
+			fprintf(stderr, "Reversed values not equal\n");
+			return EXIT_FAILURE;
+		}
+
+		/* Final tests and cleanup */
+
 		check_write_read(&val);
 		check_copy(&val);
 
@@ -1062,7 +1111,8 @@ test_map(void)
 		}
 
 		check_invalid_methods("map", &val);
-		avro_value_free(&val);
+		avro_value_decref(&val);
+		avro_value_decref(&reversed);
 	}
 
 	avro_schema_decref(double_schema);
@@ -1113,7 +1163,7 @@ test_record(void)
 	int  rval;
 
 	avro_value_t  val;
-	try(avro_value_new(record_class, &val),
+	try(avro_generic_value_new(record_class, &val),
 	    "Cannot create record");
 	check(rval, check_type_and_schema
 		    ("record", &val, AVRO_RECORD,
@@ -1214,7 +1264,7 @@ test_record(void)
 	}
 
 	check_invalid_methods("record", &val);
-	avro_value_free(&val);
+	avro_value_decref(&val);
 	avro_value_iface_decref(record_class);
 	avro_schema_decref(record_schema);
 	return EXIT_SUCCESS;
@@ -1246,7 +1296,7 @@ test_union(void)
 	int  rval;
 
 	avro_value_t  val;
-	try(avro_value_new(union_class, &val),
+	try(avro_generic_value_new(union_class, &val),
 	    "Cannot create union");
 	check(rval, check_type_and_schema
 		    ("union", &val, AVRO_UNION,
@@ -1294,7 +1344,7 @@ test_union(void)
 	check_invalid_methods("union", &val);
 	check_write_read(&val);
 	check_copy(&val);
-	avro_value_free(&val);
+	avro_value_decref(&val);
 
 	avro_schema_decref(union_schema);
 	avro_value_iface_decref(union_class);