summaryrefslogtreecommitdiff
path: root/st.c
diff options
context:
space:
mode:
Diffstat (limited to 'st.c')
-rw-r--r--st.c140
1 files changed, 94 insertions, 46 deletions
diff --git a/st.c b/st.c
index b8ad6ab6c2..4f0259a237 100644
--- a/st.c
+++ b/st.c
@@ -103,11 +103,12 @@
#ifdef NOT_RUBY
#include "regint.h"
#include "st.h"
-#else
+#elif defined RUBY_EXPORT
#include "internal.h"
#include "internal/bits.h"
#include "internal/hash.h"
#include "internal/sanitizers.h"
+#include "internal/st.h"
#endif
#include <stdio.h>
@@ -342,7 +343,7 @@ get_power2(st_index_t size)
unsigned int n = ST_INDEX_BITS - nlz_intptr(size);
if (n <= MAX_POWER2)
return n < MINIMAL_POWER2 ? MINIMAL_POWER2 : n;
-#ifndef NOT_RUBY
+#ifdef RUBY
/* Ran out of the table entries */
rb_raise(rb_eRuntimeError, "st_table too big");
#endif
@@ -657,8 +658,7 @@ st_clear(st_table *tab)
void
st_free_table(st_table *tab)
{
- if (tab->bins != NULL)
- free(tab->bins);
+ free(tab->bins);
free(tab->entries);
free(tab);
}
@@ -718,6 +718,10 @@ count_collision(const struct st_hash_type *type)
#error "REBUILD_THRESHOLD should be >= 2"
#endif
+static void rebuild_table_with(st_table *const new_tab, st_table *const tab);
+static void rebuild_move_table(st_table *const new_tab, st_table *const tab);
+static void rebuild_cleanup(st_table *const tab);
+
/* Rebuild table TAB. Rebuilding removes all deleted bins and entries
and can change size of the table entries and bins arrays.
Rebuilding is implemented by creation of a new table or by
@@ -725,14 +729,6 @@ count_collision(const struct st_hash_type *type)
static void
rebuild_table(st_table *tab)
{
- st_index_t i, ni;
- unsigned int size_ind;
- st_table *new_tab;
- st_table_entry *new_entries;
- st_table_entry *curr_entry_ptr;
- st_index_t *bins;
- st_index_t bin_ind;
-
if ((2 * tab->num_entries <= get_allocated_entries(tab)
&& REBUILD_THRESHOLD * tab->num_entries > get_allocated_entries(tab))
|| tab->num_entries < (1 << MINIMAL_POWER2)) {
@@ -740,17 +736,32 @@ rebuild_table(st_table *tab)
tab->num_entries = 0;
if (tab->bins != NULL)
initialize_bins(tab);
- new_tab = tab;
- new_entries = tab->entries;
+ rebuild_table_with(tab, tab);
}
else {
+ st_table *new_tab;
/* This allocation could trigger GC and compaction. If tab is the
* gen_iv_tbl, then tab could have changed in size due to objects being
* freed and/or moved. Do not store attributes of tab before this line. */
new_tab = st_init_table_with_size(tab->type,
2 * tab->num_entries - 1);
- new_entries = new_tab->entries;
+ rebuild_table_with(new_tab, tab);
+ rebuild_move_table(new_tab, tab);
}
+ rebuild_cleanup(tab);
+}
+
+static void
+rebuild_table_with(st_table *const new_tab, st_table *const tab)
+{
+ st_index_t i, ni;
+ unsigned int size_ind;
+ st_table_entry *new_entries;
+ st_table_entry *curr_entry_ptr;
+ st_index_t *bins;
+ st_index_t bin_ind;
+
+ new_entries = new_tab->entries;
ni = 0;
bins = new_tab->bins;
@@ -773,17 +784,24 @@ rebuild_table(st_table *tab)
new_tab->num_entries++;
ni++;
}
- if (new_tab != tab) {
- tab->entry_power = new_tab->entry_power;
- tab->bin_power = new_tab->bin_power;
- tab->size_ind = new_tab->size_ind;
- if (tab->bins != NULL)
- free(tab->bins);
- tab->bins = new_tab->bins;
- free(tab->entries);
- tab->entries = new_tab->entries;
- free(new_tab);
- }
+}
+
+static void
+rebuild_move_table(st_table *const new_tab, st_table *const tab)
+{
+ tab->entry_power = new_tab->entry_power;
+ tab->bin_power = new_tab->bin_power;
+ tab->size_ind = new_tab->size_ind;
+ free(tab->bins);
+ tab->bins = new_tab->bins;
+ free(tab->entries);
+ tab->entries = new_tab->entries;
+ free(new_tab);
+}
+
+static void
+rebuild_cleanup(st_table *const tab)
+{
tab->entries_start = 0;
tab->entries_bound = tab->num_entries;
tab->rebuilds_num++;
@@ -1168,6 +1186,13 @@ st_add_direct_with_hash(st_table *tab,
}
}
+void
+rb_st_add_direct_with_hash(st_table *tab,
+ st_data_t key, st_data_t value, st_hash_t hash)
+{
+ st_add_direct_with_hash(tab, key, value, hash);
+}
+
/* Insert (KEY, VALUE) into table TAB. The table should not have
entry with KEY before the insertion. */
void
@@ -1228,17 +1253,10 @@ st_insert2(st_table *tab, st_data_t key, st_data_t value,
return 1;
}
-/* Create and return a copy of table OLD_TAB. */
+/* Create a copy of old_tab into new_tab. */
st_table *
-st_copy(st_table *old_tab)
+st_replace(st_table *new_tab, st_table *old_tab)
{
- st_table *new_tab;
-
- new_tab = (st_table *) malloc(sizeof(st_table));
-#ifndef RUBY
- if (new_tab == NULL)
- return NULL;
-#endif
*new_tab = *old_tab;
if (old_tab->bins == NULL)
new_tab->bins = NULL;
@@ -1246,7 +1264,6 @@ st_copy(st_table *old_tab)
new_tab->bins = (st_index_t *) malloc(bins_size(old_tab));
#ifndef RUBY
if (new_tab->bins == NULL) {
- free(new_tab);
return NULL;
}
#endif
@@ -1255,7 +1272,6 @@ st_copy(st_table *old_tab)
* sizeof(st_table_entry));
#ifndef RUBY
if (new_tab->entries == NULL) {
- st_free_table(new_tab);
return NULL;
}
#endif
@@ -1263,6 +1279,27 @@ st_copy(st_table *old_tab)
get_allocated_entries(old_tab));
if (old_tab->bins != NULL)
MEMCPY(new_tab->bins, old_tab->bins, char, bins_size(old_tab));
+
+ return new_tab;
+}
+
+/* Create and return a copy of table OLD_TAB. */
+st_table *
+st_copy(st_table *old_tab)
+{
+ st_table *new_tab;
+
+ new_tab = (st_table *) malloc(sizeof(st_table));
+#ifndef RUBY
+ if (new_tab == NULL)
+ return NULL;
+#endif
+
+ if (st_replace(new_tab, old_tab) == NULL) {
+ st_free_table(new_tab);
+ return NULL;
+ }
+
return new_tab;
}
@@ -2061,6 +2098,7 @@ st_numhash(st_data_t n)
return (st_index_t)((n>>s1|(n<<s2)) ^ (n>>s2));
}
+#ifdef RUBY
/* Expand TAB to be suitable for holding SIZ entries in total.
Pre-existing entries remain not deleted inside of TAB, but its bins
are cleared to expect future reconstruction. See rehash below. */
@@ -2077,10 +2115,8 @@ st_expand_table(st_table *tab, st_index_t siz)
n = get_allocated_entries(tab);
MEMCPY(tmp->entries, tab->entries, st_table_entry, n);
free(tab->entries);
- if (tab->bins != NULL)
- free(tab->bins);
- if (tmp->bins != NULL)
- free(tmp->bins);
+ free(tab->bins);
+ free(tmp->bins);
tab->entry_power = tmp->entry_power;
tab->bin_power = tmp->bin_power;
tab->size_ind = tmp->size_ind;
@@ -2098,10 +2134,10 @@ st_rehash_linear(st_table *tab)
int eq_p, rebuilt_p;
st_index_t i, j;
st_table_entry *p, *q;
- if (tab->bins) {
- free(tab->bins);
- tab->bins = NULL;
- }
+
+ free(tab->bins);
+ tab->bins = NULL;
+
for (i = tab->entries_start; i < tab->entries_bound; i++) {
p = &tab->entries[i];
if (DELETED_ENTRY_P(p))
@@ -2200,7 +2236,6 @@ st_rehash(st_table *tab)
} while (rebuilt_p);
}
-#ifdef RUBY
static st_data_t
st_stringify(VALUE key)
{
@@ -2288,4 +2323,17 @@ rb_st_nth_key(st_table *tab, st_index_t index)
}
}
+void
+rb_st_compact_table(st_table *tab)
+{
+ st_index_t num = tab->num_entries;
+ if (REBUILD_THRESHOLD * num <= get_allocated_entries(tab)) {
+ /* Compaction: */
+ st_table *new_tab = st_init_table_with_size(tab->type, 2 * num);
+ rebuild_table_with(new_tab, tab);
+ rebuild_move_table(new_tab, tab);
+ rebuild_cleanup(tab);
+ }
+}
+
#endif