Skip to content

Commit 9a907ab

Browse files
authored
Merge pull request #189 from static-frame/188/x-int-cache
Remove AutoMap integer cache
2 parents 595917d + 385e1dc commit 9a907ab

File tree

2 files changed

+35
-94
lines changed

2 files changed

+35
-94
lines changed

src/auto_map.c

Lines changed: 34 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,15 @@
1010
# define PY_ARRAY_UNIQUE_SYMBOL AK_ARRAY_API
1111
# define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
1212

13-
# include "auto_map.h"
1413
# include "numpy/arrayobject.h"
1514
# include "numpy/arrayscalars.h"
1615
# include "numpy/halffloat.h"
17-
18-
# define DEBUG_MSG_OBJ(msg, obj) \
19-
fprintf(stderr, "--- %s: %i: %s: ", __FILE__, __LINE__, __FUNCTION__); \
20-
fprintf(stderr, #msg " "); \
21-
PyObject_Print(obj, stderr, 0); \
22-
fprintf(stderr, "\n"); \
23-
fflush(stderr); \
16+
# include "auto_map.h"
17+
# include "utilities.h"
2418

2519
//------------------------------------------------------------------------------
2620
// Common
2721

28-
// static PyTypeObject AMType;
29-
// static PyTypeObject FAMIType;
30-
// static PyTypeObject FAMVType;
31-
// static PyTypeObject FAMType;
3222
PyObject *NonUniqueError;
3323

3424
// The main storage "table" is an array of TableElement
@@ -41,7 +31,6 @@ typedef struct TableElement{
4131
# define LOAD 0.9
4232
# define SCAN 16
4333

44-
const static size_t UCS4_SIZE = sizeof(Py_UCS4);
4534

4635
// Partial, two-argument version of PyUnicode_FromKindAndData for consistent templating with bytes version.
4736
static inline PyObject*
@@ -396,52 +385,6 @@ string_to_hash(char *str, Py_ssize_t len) {
396385
return hash;
397386
}
398387

399-
//------------------------------------------------------------------------------
400-
// the global int_cache is shared among all instances
401-
402-
static PyObject *int_cache = NULL;
403-
404-
// NOTE: this used to be a Py_ssize_t, which can be 32 bits on some machines and might easily overflow with a few very large indices. Using an explicit 64-bit int seems safer
405-
static npy_int64 key_count_global = 0;
406-
407-
// Fill the int_cache up to size_needed with PyObject ints; `size` is not the key_count_global.
408-
static int
409-
int_cache_fill(Py_ssize_t size_needed)
410-
{
411-
PyObject *item;
412-
if (!int_cache) {
413-
int_cache = PyList_New(0);
414-
if (!int_cache) {
415-
return -1;
416-
}
417-
}
418-
for (Py_ssize_t i = PyList_GET_SIZE(int_cache); i < size_needed; i++) {
419-
item = PyLong_FromSsize_t(i);
420-
if (!item) {
421-
return -1;
422-
}
423-
if (PyList_Append(int_cache, item)) {
424-
Py_DECREF(item);
425-
return -1;
426-
}
427-
Py_DECREF(item);
428-
}
429-
return 0;
430-
}
431-
432-
// Given the current key_count_global, remove cache elements only if the key_count is less than the the current size of the int_cache.
433-
void
434-
int_cache_remove(Py_ssize_t key_count)
435-
{
436-
if (!key_count) {
437-
Py_CLEAR(int_cache);
438-
}
439-
else if (key_count < PyList_GET_SIZE(int_cache)) {
440-
// del int_cache[key_count:]
441-
PyList_SetSlice(int_cache, key_count, PyList_GET_SIZE(int_cache), NULL);
442-
}
443-
}
444-
445388
//------------------------------------------------------------------------------
446389
// FrozenAutoMapIterator functions
447390

@@ -468,7 +411,7 @@ fami_iter(FAMIObject *self)
468411
return self;
469412
}
470413

471-
// For a FAMI, Return appropriate PyObject for items, keys, and values. When values are needed they are retrieved from the int_cache. For consistency with NumPy array iteration, arrays use PyArray_ToScalar instead of PyArray_GETITEM.
414+
// For a FAMI, Return appropriate PyObject for items, keys, and values. For consistency with NumPy array iteration, arrays use PyArray_ToScalar instead of PyArray_GETITEM.
472415
static PyObject *
473416
fami_iternext(FAMIObject *self)
474417
{
@@ -488,18 +431,20 @@ fami_iternext(FAMIObject *self)
488431
switch (self->kind) {
489432
case ITEMS: {
490433
if (self->fam->keys_array_type) {
491-
return PyTuple_Pack(
492-
2,
434+
return Py_BuildValue(
435+
"NN",
493436
PyArray_ToScalar(PyArray_GETPTR1(self->keys_array, index), self->keys_array),
494-
PyList_GET_ITEM(int_cache, index)
437+
PyLong_FromSsize_t(index)
495438
);
496439
}
497440
else {
498-
return PyTuple_Pack(
499-
2,
500-
PyList_GET_ITEM(self->fam->keys, index),
501-
PyList_GET_ITEM(int_cache, index)
502-
);
441+
PyObject* t = PyTuple_New(2);
442+
if (!t) { return NULL; }
443+
PyObject* k = PyList_GET_ITEM(self->fam->keys, index);
444+
Py_INCREF(k);
445+
PyTuple_SET_ITEM(t, 0, k);
446+
PyTuple_SET_ITEM(t, 1, PyLong_FromSsize_t(index));
447+
return t;
503448
}
504449
}
505450
case KEYS: {
@@ -513,9 +458,7 @@ fami_iternext(FAMIObject *self)
513458
}
514459
}
515460
case VALUES: {
516-
PyObject *yield = PyList_GET_ITEM(int_cache, index);
517-
Py_INCREF(yield);
518-
return yield;
461+
return PyLong_FromSsize_t(index);
519462
}
520463
}
521464
Py_UNREACHABLE();
@@ -1556,10 +1499,6 @@ insert_string(
15561499
static int
15571500
grow_table(FAMObject *self, Py_ssize_t keys_size)
15581501
{
1559-
// NOTE: this is the only place int_cache_fill is called; it is not called with key_count_global, but with the max value needed
1560-
if (int_cache_fill(keys_size)) {
1561-
return -1;
1562-
}
15631502
Py_ssize_t keys_load = keys_size / LOAD;
15641503
Py_ssize_t size_old = self->table_size;
15651504
if (keys_load < size_old) {
@@ -1628,8 +1567,6 @@ copy_to_new(PyTypeObject *cls, FAMObject *self, FAMObject *new)
16281567
return -1;
16291568
}
16301569
}
1631-
key_count_global += self->keys_size;
1632-
16331570
new->table_size = self->table_size;
16341571
new->keys_array_type = self->keys_array_type;
16351572
new->keys_size = self->keys_size;
@@ -1691,7 +1628,6 @@ extend(FAMObject *self, PyObject *keys)
16911628
return -1;
16921629
}
16931630
Py_ssize_t size_extend = PySequence_Fast_GET_SIZE(keys);
1694-
key_count_global += size_extend;
16951631
self->keys_size += size_extend;
16961632

16971633
if (grow_table(self, self->keys_size)) {
@@ -1723,7 +1659,6 @@ append(FAMObject *self, PyObject *key)
17231659
PyErr_SetString(PyExc_NotImplementedError, "Not supported for array keys");
17241660
return -1;
17251661
}
1726-
key_count_global++;
17271662
self->keys_size++;
17281663

17291664
if (grow_table(self, self->keys_size)) {
@@ -1746,7 +1681,7 @@ fam_length(FAMObject *self)
17461681
}
17471682

17481683

1749-
// Given a key for a FAM, return the Python integer (via the int_cache) associated with that key. Utility function used in both fam_subscript() and fam_get()
1684+
// Given a key for a FAM, return the Python integer associated with that key. Utility function used in both fam_subscript() and fam_get()
17501685
static PyObject *
17511686
get(FAMObject *self, PyObject *key, PyObject *missing) {
17521687
Py_ssize_t keys_pos = lookup(self, key);
@@ -1761,10 +1696,7 @@ get(FAMObject *self, PyObject *key, PyObject *missing) {
17611696
PyErr_SetObject(PyExc_KeyError, key);
17621697
return NULL;
17631698
}
1764-
// use a C-integer to fetch the Python integer
1765-
PyObject *index = PyList_GET_ITEM(int_cache, keys_pos);
1766-
Py_INCREF(index);
1767-
return index;
1699+
return PyLong_FromSsize_t(keys_pos);
17681700
}
17691701

17701702

@@ -1981,6 +1913,20 @@ fam_get_all(FAMObject *self, PyObject *key) {
19811913
# undef GET_ALL_FLEXIBLE
19821914

19831915

1916+
static inline int
1917+
append_ssize_t(
1918+
PyObject* list,
1919+
Py_ssize_t value)
1920+
{
1921+
PyObject* v = PyLong_FromSsize_t(value);
1922+
if (v == NULL) {
1923+
return -1;
1924+
}
1925+
int err = PyList_Append(list, v);
1926+
Py_DECREF(v);
1927+
return err;
1928+
}
1929+
19841930
// Give an array of the same kind as KAT, lookup and load any keys_pos. Depends on self, key_size, key_array, table_pos, i, k, values
19851931
# define GET_ANY_SCALARS(npy_type_src, npy_type_dst, kat, lookup_func, hash_func, post_deref) \
19861932
{ \
@@ -1996,7 +1942,7 @@ fam_get_all(FAMObject *self, PyObject *key) {
19961942
continue; \
19971943
} \
19981944
keys_pos = self->table[table_pos].keys_pos; \
1999-
if (PyList_Append(values, PyList_GET_ITEM(int_cache, keys_pos))) { \
1945+
if (append_ssize_t(values, keys_pos)) { \
20001946
Py_DECREF(values); \
20011947
return NULL; \
20021948
} \
@@ -2020,7 +1966,7 @@ fam_get_all(FAMObject *self, PyObject *key) {
20201966
continue; \
20211967
} \
20221968
keys_pos = self->table[table_pos].keys_pos; \
2023-
if (PyList_Append(values, PyList_GET_ITEM(int_cache, keys_pos))) { \
1969+
if (append_ssize_t(values, keys_pos)) { \
20241970
Py_DECREF(values); \
20251971
return NULL; \
20261972
} \
@@ -2066,7 +2012,7 @@ fam_get_any(FAMObject *self, PyObject *key) {
20662012
}
20672013
continue;
20682014
}
2069-
if (PyList_Append(values, PyList_GET_ITEM(int_cache, keys_pos))) {
2015+
if (append_ssize_t(values, keys_pos)) {
20702016
Py_DECREF(values);
20712017
return NULL;
20722018
}
@@ -2145,7 +2091,7 @@ fam_get_any(FAMObject *self, PyObject *key) {
21452091
}
21462092
continue; // do not raise
21472093
}
2148-
if (PyList_Append(values, PyList_GET_ITEM(int_cache, keys_pos))) {
2094+
if (append_ssize_t(values, keys_pos)) {
21492095
Py_DECREF(values);
21502096
return NULL;
21512097
}
@@ -2228,11 +2174,7 @@ fam_dealloc(FAMObject *self)
22282174
if (self->keys) {
22292175
Py_DECREF(self->keys);
22302176
}
2231-
2232-
key_count_global -= self->keys_size;
2233-
22342177
Py_TYPE(self)->tp_free((PyObject *)self);
2235-
int_cache_remove(key_count_global);
22362178
}
22372179

22382180

@@ -2480,7 +2422,6 @@ fam_init(PyObject *self, PyObject *args, PyObject *kwargs)
24802422
fam->keys_array_type = keys_array_type;
24812423
fam->keys_size = keys_size;
24822424
fam->key_buffer = NULL;
2483-
key_count_global += keys_size;
24842425

24852426
// NOTE: on itialization, grow_table() does not use keys
24862427
if (grow_table(fam, keys_size)) {

tasks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def clean(context):
2626
def build(context):
2727
# context.run('pip install -r requirements-test.txt', echo=True, pty=True)
2828
# keep verbose to see warnings
29-
context.run(f'{sys.executable} -m pip --disable-pip-version-check -v install .', echo=True, pty=True)
29+
context.run(f'{sys.executable} -m pip --disable-pip-version-check -v install --no-build-isolation .', echo=True, pty=True)
3030

3131

3232
@invoke.task(build)

0 commit comments

Comments
 (0)