void *Trie_get(const Trie* trie, const char *key) { int first, last, mid; if(!key[0]) { return trie->value; } /* The transitions are stored in alphabetical order. Do a binary * search to find the proper one. */ first = 0; last = trie->num_transitions-1; while(first <= last) { Transition* transition; char *suffix; int c; mid = (first+last)/2; transition = &trie->transitions[mid]; suffix = transition->suffix; /* If suffix is a substring of key, then get the value from the next trie. */ c = strncmp(key, suffix, strlen(suffix)); if(c < 0) last = mid-1; else if(c > 0) first = mid+1; else return Trie_get(transition->next, key+strlen(suffix)); } return NULL; }
static void _get_approximate_trie(const Trie* trie, const char *key, const int k, void (*callback)(const char *key, const void *value, const int mismatches, void *data), void *data, const int mismatches, char *current_key, const int max_key ) { int i; /* If there's no more key to match, then I'm done. */ if(!key[0]) { if(trie->value) (*callback)(current_key, trie->value, mismatches, data); } /* If there are no more mismatches allowed, then fall back to the faster Trie_get. */ else if(!k) { void *value = Trie_get(trie, key); if(value) { int l = strlen(current_key); /* Make sure I have enough space for the full key. */ if(l + strlen(key) < max_key) { strcat(current_key, key); (*callback)(current_key, value, mismatches, data); current_key[l] = 0; } /* BUG: Ran out of space for the key. This fails silently, but should signal an error. */ } } /* If there are no more transitions, then all the characters left in the key are mismatches. */ else if(!trie->num_transitions) { if(trie->value && (strlen(key) <= k)) { (*callback)(current_key, trie->value, mismatches+strlen(key), data); } } /* Otherwise, try to match each of the transitions. */ else { for(i=0; i<trie->num_transitions; i++) { Transition* transition = &trie->transitions[i]; const char *suffix = transition->suffix; _get_approximate_transition(key, k, transition, suffix, callback, data, mismatches, current_key, max_key); } } }
static PyObject * trie_get(trieobject *mp, PyObject *args) { const char *key; PyObject *py_value; PyObject *py_failobj = Py_None; if (!PyArg_ParseTuple(args, "s|O:get", &key, &py_failobj)) return NULL; py_value = Trie_get(mp->trie, key); if(!py_value) py_value = py_failobj; Py_INCREF(py_value); return py_value; }
static PyObject * trie_subscript(trieobject *mp, PyObject *py_key) { unsigned char *key; PyObject *py_value; /* Make sure key is a string. */ if(!PyString_Check(py_key)) { PyErr_SetString(PyExc_TypeError, "key must be a string"); return NULL; } key = (unsigned char *)PyString_AS_STRING(py_key); py_value = (PyObject *)Trie_get(mp->trie, key); if(py_value == NULL) PyErr_SetString(PyExc_KeyError, (char *)key); else Py_INCREF(py_value); return py_value; }
static int trie_ass_sub(trieobject *mp, PyObject *py_key, PyObject *py_value) { unsigned char *key; PyObject *py_prev; /* Make sure key is a string. */ if(!PyString_Check(py_key)) { PyErr_SetString(PyExc_TypeError, "key must be a string"); return -1; } key = (unsigned char *)PyString_AS_STRING((char *)py_key); /* Check to see whether something already exists at that key. If there's already an object there, then I will have to remove it. */ py_prev = (PyObject *)Trie_get(mp->trie, key); if(py_prev) { Py_DECREF(py_prev); } /* The client wants to delete a key from a dictionary. The Trie API doesn't support this, so I will just overwrite it with NULL. */ if(!py_value) { /* If the key doesn't exist, raise a KeyError. */ if(!py_prev) { PyErr_SetString(PyExc_KeyError, (char *)key); return -1; } Trie_set(mp->trie, key, NULL); } /* The client wants to set a key in the dictionary. */ else { Py_INCREF(py_value); if(Trie_set(mp->trie, key, py_value)) { PyErr_SetString(PyExc_AssertionError, "error setting trie"); return -1; } } return 0; }
static PyObject * trie_subscript(trieobject *mp, PyObject *py_key) { const char *key; PyObject *py_value; /* Make sure key is a string. */ #ifdef IS_PY3K if(!PyUnicode_Check(py_key)) { #else if(!PyString_Check(py_key)) { #endif PyErr_SetString(PyExc_TypeError, "key must be a string"); return NULL; } #ifdef IS_PY3K /* TODO - Review next line for buffer usage */ key = PyBytes_AS_STRING(PyUnicode_AsASCIIString(py_key)); #else key = PyString_AS_STRING(py_key); #endif py_value = Trie_get(mp->trie, key); if(py_value == NULL) PyErr_SetString(PyExc_KeyError, key); else Py_INCREF(py_value); return py_value; } static int trie_ass_sub(trieobject *mp, PyObject *py_key, PyObject *py_value) { int result = -1; const char *key; PyObject *py_prev; #ifdef IS_PY3K PyObject* bytes; #endif /* Make sure key is a string. */ #ifdef IS_PY3K if(!PyUnicode_Check(py_key)) { #else if(!PyString_Check(py_key)) { #endif PyErr_SetString(PyExc_TypeError, "key must be a string"); return -1; } #ifdef IS_PY3K bytes = PyUnicode_AsASCIIString(py_key); if(!bytes) { PyErr_SetString(PyExc_TypeError, "key must be an ASCII string"); return -1; } key = PyBytes_AsString(bytes); #else key = PyString_AS_STRING(py_key); #endif /* Check to see whether something already exists at that key. If there's already an object there, then I will have to remove it. */ py_prev = Trie_get(mp->trie, key); if(py_prev) { Py_DECREF(py_prev); } /* The client wants to delete a key from a dictionary. The Trie API doesn't support this, so I will just overwrite it with NULL. */ if(!py_value) { /* If the key doesn't exist, raise a KeyError. */ if(!py_prev) PyErr_SetString(PyExc_KeyError, key); else { Trie_set(mp->trie, key, NULL); result = 0; } } /* The client wants to set a key in the dictionary. */ else { Py_INCREF(py_value); if(Trie_set(mp->trie, key, py_value)) PyErr_SetString(PyExc_AssertionError, "error setting trie"); else result = 0; } #ifdef IS_PY3K Py_DECREF(bytes); #endif return result; } static int trie_contains(trieobject *mp, PyObject* py_key) { int result; #ifdef IS_PY3K PyObject* bytes; #endif const char *key; /* Make sure key is a string. */ #ifdef IS_PY3K if(!PyUnicode_Check(py_key)) { #else if(!PyString_Check(py_key)) { #endif PyErr_SetString(PyExc_TypeError, "key must be a string"); return -1; } #ifdef IS_PY3K bytes = PyUnicode_AsASCIIString(py_key); if(!bytes) { PyErr_SetString(PyExc_TypeError, "key must be an ASCII string"); return -1; } key = PyBytes_AsString(bytes); #else key = PyString_AS_STRING(py_key); #endif result = Trie_has_key(mp->trie, key); #ifdef IS_PY3K Py_DECREF(bytes); #endif return result; } static char has_key__doc__[] = "D.has_key(k) -> 1 if D has a key k, else 0"; static PyObject * trie_has_key(trieobject *mp, PyObject *py_key) { int has_key = trie_contains(mp, py_key); if (has_key==-1) return NULL; #ifdef IS_PY3K return PyLong_FromLong((long)has_key); #else return PyInt_FromLong((long)has_key); #endif }
int Trie_has_key(const Trie* trie, const char *key) { return Trie_get(trie, key) != NULL; }