|
|
|
|
@ -22,6 +22,16 @@
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_GC
|
|
|
|
|
# include <gc/gc.h>
|
|
|
|
|
# define CALLOC(x,y) GC_MALLOC(x*y)
|
|
|
|
|
# define IF_NO_GC(x)
|
|
|
|
|
#else
|
|
|
|
|
# define CALLOC(x,y) calloc(x,y)
|
|
|
|
|
# define IF_NO_GC(x) x
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef MAP_TABLE_NAME
|
|
|
|
|
# error You must define MAP_TABLE_NAME.
|
|
|
|
|
#endif
|
|
|
|
|
@ -77,7 +87,7 @@ typedef struct
|
|
|
|
|
{
|
|
|
|
|
mutex_t lock;
|
|
|
|
|
unsigned int table_used;
|
|
|
|
|
unsigned int enumerator_count;
|
|
|
|
|
IF_NO_GC(unsigned int enumerator_count;)
|
|
|
|
|
struct PREFIX(_table_cell_struct) table[MAP_TABLE_STATIC_SIZE];
|
|
|
|
|
} PREFIX(_table);
|
|
|
|
|
static PREFIX(_table) MAP_TABLE_STATIC_NAME;
|
|
|
|
|
@ -94,14 +104,14 @@ typedef struct PREFIX(_table_struct)
|
|
|
|
|
mutex_t lock;
|
|
|
|
|
unsigned int table_size;
|
|
|
|
|
unsigned int table_used;
|
|
|
|
|
unsigned int enumerator_count;
|
|
|
|
|
IF_NO_GC(unsigned int enumerator_count;)
|
|
|
|
|
struct PREFIX(_table_struct) *old;
|
|
|
|
|
struct PREFIX(_table_cell_struct) *table;
|
|
|
|
|
} PREFIX(_table);
|
|
|
|
|
|
|
|
|
|
PREFIX(_table) *PREFIX(_create)(uint32_t capacity)
|
|
|
|
|
{
|
|
|
|
|
PREFIX(_table) *table = calloc(1, sizeof(PREFIX(_table)));
|
|
|
|
|
PREFIX(_table) *table = CALLOC(1, sizeof(PREFIX(_table)));
|
|
|
|
|
# ifndef MAP_TABLE_NO_LOCK
|
|
|
|
|
INIT_LOCK(table->lock);
|
|
|
|
|
# endif
|
|
|
|
|
@ -112,8 +122,6 @@ PREFIX(_table) *PREFIX(_create)(uint32_t capacity)
|
|
|
|
|
# define TABLE_SIZE(x) (x->table_size)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Collects garbage in the background
|
|
|
|
|
void objc_collect_garbage_data(void(*)(void*), void*);
|
|
|
|
|
|
|
|
|
|
#ifdef MAP_TABLE_STATIC_SIZE
|
|
|
|
|
static int PREFIX(_table_resize)(PREFIX(_table) *table)
|
|
|
|
|
@ -122,7 +130,10 @@ static int PREFIX(_table_resize)(PREFIX(_table) *table)
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
# ifndef MAP_TABLE_SINGLE_THREAD
|
|
|
|
|
# if !(defined(MAP_TABLE_SINGLE_THREAD) || defined(ENABLE_GC))
|
|
|
|
|
// Collects garbage in the background
|
|
|
|
|
void objc_collect_garbage_data(void(*)(void*), void*);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Free the memory from an old table. By the time that this is reached, there
|
|
|
|
|
* are no heap pointers pointing to this table. There may be iterators, in
|
|
|
|
|
@ -162,13 +173,13 @@ static int PREFIX(_table_resize)(PREFIX(_table) *table)
|
|
|
|
|
// Note: We multiply the table size, rather than the count, by two so that
|
|
|
|
|
// we get overflow checking in calloc. Two times the size of a cell will
|
|
|
|
|
// never overflow, but two times the table size might.
|
|
|
|
|
struct PREFIX(_table_cell_struct) *newArray = calloc(table->table_size, 2 *
|
|
|
|
|
struct PREFIX(_table_cell_struct) *newArray = CALLOC(table->table_size, 2 *
|
|
|
|
|
sizeof(struct PREFIX(_table_cell_struct)));
|
|
|
|
|
if (NULL == newArray) { return 0; }
|
|
|
|
|
|
|
|
|
|
// Allocate a new table structure and move the array into that. Now
|
|
|
|
|
// lookups will try using that one, if possible.
|
|
|
|
|
PREFIX(_table) *copy = calloc(1, sizeof(PREFIX(_table)));
|
|
|
|
|
PREFIX(_table) *copy = CALLOC(1, sizeof(PREFIX(_table)));
|
|
|
|
|
memcpy(copy, table, sizeof(PREFIX(_table)));
|
|
|
|
|
table->old = copy;
|
|
|
|
|
|
|
|
|
|
@ -192,10 +203,12 @@ static int PREFIX(_table_resize)(PREFIX(_table) *table)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
table->old = NULL;
|
|
|
|
|
# ifdef MAP_TABLE_SINGLE_THREAD
|
|
|
|
|
# ifndef ENABLE_GC
|
|
|
|
|
# ifdef MAP_TABLE_SINGLE_THREAD
|
|
|
|
|
free(copy);
|
|
|
|
|
# else
|
|
|
|
|
# else
|
|
|
|
|
objc_collect_garbage_data(PREFIX(_table_collect_garbage), copy);
|
|
|
|
|
# endif
|
|
|
|
|
# endif
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
@ -448,21 +461,23 @@ PREFIX(_next)(PREFIX(_table) *table,
|
|
|
|
|
{
|
|
|
|
|
if (NULL == *state)
|
|
|
|
|
{
|
|
|
|
|
*state = calloc(1, sizeof(struct PREFIX(_table_enumerator)));
|
|
|
|
|
*state = CALLOC(1, sizeof(struct PREFIX(_table_enumerator)));
|
|
|
|
|
// Make sure that we are not reallocating the table when we start
|
|
|
|
|
// enumerating
|
|
|
|
|
MAP_LOCK();
|
|
|
|
|
(*state)->table = table;
|
|
|
|
|
(*state)->index = -1;
|
|
|
|
|
__sync_fetch_and_add(&table->enumerator_count, 1);
|
|
|
|
|
IF_NO_GC(__sync_fetch_and_add(&table->enumerator_count, 1);)
|
|
|
|
|
MAP_UNLOCK();
|
|
|
|
|
}
|
|
|
|
|
if ((*state)->seen >= (*state)->table->table_used)
|
|
|
|
|
{
|
|
|
|
|
#ifndef ENABLE_GC
|
|
|
|
|
MAP_LOCK();
|
|
|
|
|
__sync_fetch_and_sub(&table->enumerator_count, 1);
|
|
|
|
|
MAP_UNLOCK();
|
|
|
|
|
free(*state);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef MAP_TABLE_ACCESS_BY_REFERENCE
|
|
|
|
|
return NULL;
|
|
|
|
|
#else
|
|
|
|
|
@ -481,11 +496,13 @@ PREFIX(_next)(PREFIX(_table) *table,
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#ifndef ENABLE_GC
|
|
|
|
|
// Should not be reached, but may be if the table is unsafely modified.
|
|
|
|
|
MAP_LOCK();
|
|
|
|
|
table->enumerator_count--;
|
|
|
|
|
MAP_UNLOCK();
|
|
|
|
|
free(*state);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef MAP_TABLE_ACCESS_BY_REFERENCE
|
|
|
|
|
return NULL;
|
|
|
|
|
#else
|
|
|
|
|
@ -545,3 +562,6 @@ PREFIX(_current)(PREFIX(_table) *table,
|
|
|
|
|
#ifdef MAP_TABLE_ACCESS_BY_REFERENCE
|
|
|
|
|
# undef MAP_TABLE_ACCESS_BY_REFERENCE
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#undef CALLOC
|
|
|
|
|
#undef IF_NO_GC
|
|
|
|
|
|