static gpointer file_builder_allocate (FileBuilder *fb, guint alignment, gsize size, struct gvdb_pointer *pointer) { FileChunk *chunk; if (size == 0) return NULL; fb->offset += (-fb->offset) & (alignment - 1); chunk = g_slice_new (FileChunk); chunk->offset = fb->offset; chunk->size = size; chunk->data = g_malloc (size); pointer->start = guint32_to_le (fb->offset); fb->offset += size; pointer->end = guint32_to_le (fb->offset); g_queue_push_tail (fb->chunks, chunk); return chunk->data; }
static void file_builder_allocate_for_hash (FileBuilder *fb, gsize n_buckets, gsize n_items, guint bloom_shift, gsize n_bloom_words, guint32_le **bloom_filter, guint32_le **hash_buckets, struct gvdb_hash_item **hash_items, struct gvdb_pointer *pointer) { guint32_le bloom_hdr, table_hdr; guchar *data; gsize size; g_assert (n_bloom_words < (1u << 27)); bloom_hdr = guint32_to_le (bloom_shift << 27 | n_bloom_words); table_hdr = guint32_to_le (n_buckets); size = sizeof bloom_hdr + sizeof table_hdr + n_bloom_words * sizeof (guint32_le) + n_buckets * sizeof (guint32_le) + n_items * sizeof (struct gvdb_hash_item); data = file_builder_allocate (fb, 4, size, pointer); #define chunk(s) (size -= (s), data += (s), data - (s)) memcpy (chunk (sizeof bloom_hdr), &bloom_hdr, sizeof bloom_hdr); memcpy (chunk (sizeof table_hdr), &table_hdr, sizeof table_hdr); *bloom_filter = (guint32_le *) chunk (n_bloom_words * sizeof (guint32_le)); *hash_buckets = (guint32_le *) chunk (n_buckets * sizeof (guint32_le)); *hash_items = (struct gvdb_hash_item *) chunk (n_items * sizeof (struct gvdb_hash_item)); g_assert (size == 0); #undef chunk memset (*bloom_filter, 0, n_bloom_words * sizeof (guint32_le)); /* NOTE - the code to actually fill in the bloom filter here is missing. * Patches welcome! * * http://en.wikipedia.org/wiki/Bloom_filter * http://0pointer.de/blog/projects/bloom.html */ }
static guint32_le item_to_index (GvdbItem *item) { if (item != NULL) return item->assigned_index; return guint32_to_le (-1u); }
static void file_builder_allocate_for_hash (FileBuilder *fb, gsize n_buckets, gsize n_items, guint bloom_shift, gsize n_bloom_words, guint32_le **bloom_filter, guint32_le **hash_buckets, struct gvdb_hash_item **hash_items, struct gvdb_pointer *pointer) { guint32_le bloom_hdr, table_hdr; guchar *data; gsize size; g_assert (n_bloom_words < (1u << 27)); bloom_hdr = guint32_to_le (bloom_shift << 27 | n_bloom_words); table_hdr = guint32_to_le (n_buckets); size = sizeof bloom_hdr + sizeof table_hdr + n_bloom_words * sizeof (guint32_le) + n_buckets * sizeof (guint32_le) + n_items * sizeof (struct gvdb_hash_item); data = file_builder_allocate (fb, 4, size, pointer); #define chunk(s) (size -= (s), data += (s), data - (s)) memcpy (chunk (sizeof bloom_hdr), &bloom_hdr, sizeof bloom_hdr); memcpy (chunk (sizeof table_hdr), &table_hdr, sizeof table_hdr); *bloom_filter = (guint32_le *) chunk (n_bloom_words * sizeof (guint32_le)); *hash_buckets = (guint32_le *) chunk (n_buckets * sizeof (guint32_le)); *hash_items = (struct gvdb_hash_item *) chunk (n_items * sizeof (struct gvdb_hash_item)); g_assert (size == 0); #undef chunk memset (*bloom_filter, 0, n_bloom_words * sizeof (guint32_le)); }
static void file_builder_add_string (FileBuilder *fb, const gchar *string, guint32_le *start, guint16_le *size) { FileChunk *chunk; gsize length; length = strlen (string); chunk = g_slice_new (FileChunk); chunk->offset = fb->offset; chunk->size = length; chunk->data = g_malloc (length); memcpy (chunk->data, string, length); *start = guint32_to_le (fb->offset); *size = guint16_to_le (length); fb->offset += length; g_queue_push_tail (fb->chunks, chunk); }
static void file_builder_add_hash (FileBuilder *fb, GHashTable *table, struct gvdb_pointer *pointer) { guint32_le *buckets, *bloom_filter; struct gvdb_hash_item *items; HashTable *mytable; GvdbItem *item; guint32 index; gint bucket; mytable = hash_table_new (g_hash_table_size (table)); g_hash_table_foreach (table, hash_table_insert, mytable); index = 0; for (bucket = 0; bucket < mytable->n_buckets; bucket++) for (item = mytable->buckets[bucket]; item; item = item->next) item->assigned_index = guint32_to_le (index++); file_builder_allocate_for_hash (fb, mytable->n_buckets, index, 5, 0, &bloom_filter, &buckets, &items, pointer); index = 0; for (bucket = 0; bucket < mytable->n_buckets; bucket++) { buckets[bucket] = guint32_to_le (index); for (item = mytable->buckets[bucket]; item; item = item->next) { struct gvdb_hash_item *entry = items++; const gchar *basename; g_assert (index == guint32_from_le (item->assigned_index)); entry->hash_value = guint32_to_le (item->hash_value); entry->parent = item_to_index (item->parent); entry->unused = 0; if (item->parent != NULL) basename = item->key + strlen (item->parent->key); else basename = item->key; file_builder_add_string (fb, basename, &entry->key_start, &entry->key_size); if (item->value != NULL) { g_assert (item->child == NULL && item->table == NULL); file_builder_add_value (fb, item->value, &entry->value.pointer); entry->type = 'v'; } if (item->child != NULL) { guint32 children = 0, i = 0; guint32_le *offsets; GvdbItem *child; g_assert (item->table == NULL); for (child = item->child; child; child = child->sibling) children++; offsets = file_builder_allocate (fb, 4, 4 * children, &entry->value.pointer); entry->type = 'L'; for (child = item->child; child; child = child->sibling) offsets[i++] = child->assigned_index; g_assert (children == i); } if (item->table != NULL) { entry->type = 'H'; file_builder_add_hash (fb, item->table, &entry->value.pointer); } index++; } } hash_table_free (mytable); }