564 |
564 |
565 if (self->nt == NULL) |
565 if (self->nt == NULL) |
566 return -2; |
566 return -2; |
567 |
567 |
568 if (hex) |
568 if (hex) |
569 maxlevel = nodelen > 40 ? 40 : nodelen; |
569 maxlevel = nodelen > 40 ? 40 : (int)nodelen; |
570 else |
570 else |
571 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2); |
571 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2); |
572 |
572 |
573 for (level = off = 0; level < maxlevel; level++) { |
573 for (level = off = 0; level < maxlevel; level++) { |
574 int k = getnybble(node, level); |
574 int k = getnybble(node, level); |
793 if (rev == -2) |
793 if (rev == -2) |
794 raise_revlog_error(); |
794 raise_revlog_error(); |
795 return NULL; |
795 return NULL; |
796 } |
796 } |
797 |
797 |
|
798 static int nt_partialmatch(indexObject *self, const char *node, |
|
799 Py_ssize_t nodelen) |
|
800 { |
|
801 int rev; |
|
802 |
|
803 if (nt_init(self) == -1) |
|
804 return -3; |
|
805 |
|
806 if (self->ntrev > 0) { |
|
807 /* ensure that the radix tree is fully populated */ |
|
808 for (rev = self->ntrev - 1; rev >= 0; rev--) { |
|
809 const char *n = index_node(self, rev); |
|
810 if (n == NULL) |
|
811 return -2; |
|
812 if (nt_insert(self, n, rev) == -1) |
|
813 return -3; |
|
814 } |
|
815 self->ntrev = rev; |
|
816 } |
|
817 |
|
818 return nt_find(self, node, nodelen, 1); |
|
819 } |
|
820 |
|
821 static PyObject *index_partialmatch(indexObject *self, PyObject *args) |
|
822 { |
|
823 const char *fullnode; |
|
824 int nodelen; |
|
825 char *node; |
|
826 int rev, i; |
|
827 |
|
828 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen)) |
|
829 return NULL; |
|
830 |
|
831 if (nodelen < 4) { |
|
832 PyErr_SetString(PyExc_ValueError, "key too short"); |
|
833 return NULL; |
|
834 } |
|
835 |
|
836 if (nodelen > 40) |
|
837 nodelen = 40; |
|
838 |
|
839 for (i = 0; i < nodelen; i++) |
|
840 hexdigit(node, i); |
|
841 if (PyErr_Occurred()) { |
|
842 /* input contains non-hex characters */ |
|
843 PyErr_Clear(); |
|
844 Py_RETURN_NONE; |
|
845 } |
|
846 |
|
847 rev = nt_partialmatch(self, node, nodelen); |
|
848 |
|
849 switch (rev) { |
|
850 case -4: |
|
851 raise_revlog_error(); |
|
852 case -3: |
|
853 return NULL; |
|
854 case -2: |
|
855 Py_RETURN_NONE; |
|
856 case -1: |
|
857 return PyString_FromStringAndSize(nullid, 20); |
|
858 } |
|
859 |
|
860 fullnode = index_node(self, rev); |
|
861 if (fullnode == NULL) { |
|
862 PyErr_Format(PyExc_IndexError, |
|
863 "could not access rev %d", rev); |
|
864 return NULL; |
|
865 } |
|
866 return PyString_FromStringAndSize(fullnode, 20); |
|
867 } |
|
868 |
798 static PyObject *index_m_get(indexObject *self, PyObject *args) |
869 static PyObject *index_m_get(indexObject *self, PyObject *args) |
799 { |
870 { |
800 char *node; |
871 char *node; |
801 int nodelen, rev; |
872 int nodelen, rev; |
802 |
873 |
1075 "clear the index caches"}, |
1146 "clear the index caches"}, |
1076 {"get", (PyCFunction)index_m_get, METH_VARARGS, |
1147 {"get", (PyCFunction)index_m_get, METH_VARARGS, |
1077 "get an index entry"}, |
1148 "get an index entry"}, |
1078 {"insert", (PyCFunction)index_insert, METH_VARARGS, |
1149 {"insert", (PyCFunction)index_insert, METH_VARARGS, |
1079 "insert an index entry"}, |
1150 "insert an index entry"}, |
|
1151 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS, |
|
1152 "match a potentially ambiguous node ID"}, |
1080 {"stats", (PyCFunction)index_stats, METH_NOARGS, |
1153 {"stats", (PyCFunction)index_stats, METH_NOARGS, |
1081 "stats for the index"}, |
1154 "stats for the index"}, |
1082 {NULL} /* Sentinel */ |
1155 {NULL} /* Sentinel */ |
1083 }; |
1156 }; |
1084 |
1157 |