--- a/mercurial/dirs.c Sat Aug 13 12:18:58 2016 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,315 +0,0 @@
-/*
- dirs.c - dynamic directory diddling for dirstates
-
- Copyright 2013 Facebook
-
- This software may be used and distributed according to the terms of
- the GNU General Public License, incorporated herein by reference.
-*/
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include "util.h"
-
-#ifdef IS_PY3K
-#define PYLONG_VALUE(o) ((PyLongObject *)o)->ob_digit[1]
-#else
-#define PYLONG_VALUE(o) PyInt_AS_LONG(o)
-#endif
-
-/*
- * This is a multiset of directory names, built from the files that
- * appear in a dirstate or manifest.
- *
- * A few implementation notes:
- *
- * We modify Python integers for refcounting, but those integers are
- * never visible to Python code.
- *
- * We mutate strings in-place, but leave them immutable once they can
- * be seen by Python code.
- */
-typedef struct {
- PyObject_HEAD
- PyObject *dict;
-} dirsObject;
-
-static inline Py_ssize_t _finddir(const char *path, Py_ssize_t pos)
-{
- while (pos != -1) {
- if (path[pos] == '/')
- break;
- pos -= 1;
- }
-
- return pos;
-}
-
-static int _addpath(PyObject *dirs, PyObject *path)
-{
- const char *cpath = PyBytes_AS_STRING(path);
- Py_ssize_t pos = PyBytes_GET_SIZE(path);
- PyObject *key = NULL;
- int ret = -1;
-
- /* This loop is super critical for performance. That's why we inline
- * access to Python structs instead of going through a supported API.
- * The implementation, therefore, is heavily dependent on CPython
- * implementation details. We also commit violations of the Python
- * "protocol" such as mutating immutable objects. But since we only
- * mutate objects created in this function or in other well-defined
- * locations, the references are known so these violations should go
- * unnoticed. The code for adjusting the length of a PyBytesObject is
- * essentially a minimal version of _PyBytes_Resize. */
- while ((pos = _finddir(cpath, pos - 1)) != -1) {
- PyObject *val;
-
- /* It's likely that every prefix already has an entry
- in our dict. Try to avoid allocating and
- deallocating a string for each prefix we check. */
- if (key != NULL)
- ((PyBytesObject *)key)->ob_shash = -1;
- else {
- /* Force Python to not reuse a small shared string. */
- key = PyBytes_FromStringAndSize(cpath,
- pos < 2 ? 2 : pos);
- if (key == NULL)
- goto bail;
- }
- /* Py_SIZE(o) refers to the ob_size member of the struct. Yes,
- * assigning to what looks like a function seems wrong. */
- Py_SIZE(key) = pos;
- ((PyBytesObject *)key)->ob_sval[pos] = '\0';
-
- val = PyDict_GetItem(dirs, key);
- if (val != NULL) {
- PYLONG_VALUE(val) += 1;
- break;
- }
-
- /* Force Python to not reuse a small shared int. */
-#ifdef IS_PY3K
- val = PyLong_FromLong(0x1eadbeef);
-#else
- val = PyInt_FromLong(0x1eadbeef);
-#endif
-
- if (val == NULL)
- goto bail;
-
- PYLONG_VALUE(val) = 1;
- ret = PyDict_SetItem(dirs, key, val);
- Py_DECREF(val);
- if (ret == -1)
- goto bail;
- Py_CLEAR(key);
- }
- ret = 0;
-
-bail:
- Py_XDECREF(key);
-
- return ret;
-}
-
-static int _delpath(PyObject *dirs, PyObject *path)
-{
- char *cpath = PyBytes_AS_STRING(path);
- Py_ssize_t pos = PyBytes_GET_SIZE(path);
- PyObject *key = NULL;
- int ret = -1;
-
- while ((pos = _finddir(cpath, pos - 1)) != -1) {
- PyObject *val;
-
- key = PyBytes_FromStringAndSize(cpath, pos);
-
- if (key == NULL)
- goto bail;
-
- val = PyDict_GetItem(dirs, key);
- if (val == NULL) {
- PyErr_SetString(PyExc_ValueError,
- "expected a value, found none");
- goto bail;
- }
-
- if (--PYLONG_VALUE(val) <= 0) {
- if (PyDict_DelItem(dirs, key) == -1)
- goto bail;
- } else
- break;
- Py_CLEAR(key);
- }
- ret = 0;
-
-bail:
- Py_XDECREF(key);
-
- return ret;
-}
-
-static int dirs_fromdict(PyObject *dirs, PyObject *source, char skipchar)
-{
- PyObject *key, *value;
- Py_ssize_t pos = 0;
-
- while (PyDict_Next(source, &pos, &key, &value)) {
- if (!PyBytes_Check(key)) {
- PyErr_SetString(PyExc_TypeError, "expected string key");
- return -1;
- }
- if (skipchar) {
- if (!dirstate_tuple_check(value)) {
- PyErr_SetString(PyExc_TypeError,
- "expected a dirstate tuple");
- return -1;
- }
- if (((dirstateTupleObject *)value)->state == skipchar)
- continue;
- }
-
- if (_addpath(dirs, key) == -1)
- return -1;
- }
-
- return 0;
-}
-
-static int dirs_fromiter(PyObject *dirs, PyObject *source)
-{
- PyObject *iter, *item = NULL;
- int ret;
-
- iter = PyObject_GetIter(source);
- if (iter == NULL)
- return -1;
-
- while ((item = PyIter_Next(iter)) != NULL) {
- if (!PyBytes_Check(item)) {
- PyErr_SetString(PyExc_TypeError, "expected string");
- break;
- }
-
- if (_addpath(dirs, item) == -1)
- break;
- Py_CLEAR(item);
- }
-
- ret = PyErr_Occurred() ? -1 : 0;
- Py_DECREF(iter);
- Py_XDECREF(item);
- return ret;
-}
-
-/*
- * Calculate a refcounted set of directory names for the files in a
- * dirstate.
- */
-static int dirs_init(dirsObject *self, PyObject *args)
-{
- PyObject *dirs = NULL, *source = NULL;
- char skipchar = 0;
- int ret = -1;
-
- self->dict = NULL;
-
- if (!PyArg_ParseTuple(args, "|Oc:__init__", &source, &skipchar))
- return -1;
-
- dirs = PyDict_New();
-
- if (dirs == NULL)
- return -1;
-
- if (source == NULL)
- ret = 0;
- else if (PyDict_Check(source))
- ret = dirs_fromdict(dirs, source, skipchar);
- else if (skipchar)
- PyErr_SetString(PyExc_ValueError,
- "skip character is only supported "
- "with a dict source");
- else
- ret = dirs_fromiter(dirs, source);
-
- if (ret == -1)
- Py_XDECREF(dirs);
- else
- self->dict = dirs;
-
- return ret;
-}
-
-PyObject *dirs_addpath(dirsObject *self, PyObject *args)
-{
- PyObject *path;
-
- if (!PyArg_ParseTuple(args, "O!:addpath", &PyBytes_Type, &path))
- return NULL;
-
- if (_addpath(self->dict, path) == -1)
- return NULL;
-
- Py_RETURN_NONE;
-}
-
-static PyObject *dirs_delpath(dirsObject *self, PyObject *args)
-{
- PyObject *path;
-
- if (!PyArg_ParseTuple(args, "O!:delpath", &PyBytes_Type, &path))
- return NULL;
-
- if (_delpath(self->dict, path) == -1)
- return NULL;
-
- Py_RETURN_NONE;
-}
-
-static int dirs_contains(dirsObject *self, PyObject *value)
-{
- return PyBytes_Check(value) ? PyDict_Contains(self->dict, value) : 0;
-}
-
-static void dirs_dealloc(dirsObject *self)
-{
- Py_XDECREF(self->dict);
- PyObject_Del(self);
-}
-
-static PyObject *dirs_iter(dirsObject *self)
-{
- return PyObject_GetIter(self->dict);
-}
-
-static PySequenceMethods dirs_sequence_methods;
-
-static PyMethodDef dirs_methods[] = {
- {"addpath", (PyCFunction)dirs_addpath, METH_VARARGS, "add a path"},
- {"delpath", (PyCFunction)dirs_delpath, METH_VARARGS, "remove a path"},
- {NULL} /* Sentinel */
-};
-
-static PyTypeObject dirsType = { PyVarObject_HEAD_INIT(NULL, 0) };
-
-void dirs_module_init(PyObject *mod)
-{
- dirs_sequence_methods.sq_contains = (objobjproc)dirs_contains;
- dirsType.tp_name = "parsers.dirs";
- dirsType.tp_new = PyType_GenericNew;
- dirsType.tp_basicsize = sizeof(dirsObject);
- dirsType.tp_dealloc = (destructor)dirs_dealloc;
- dirsType.tp_as_sequence = &dirs_sequence_methods;
- dirsType.tp_flags = Py_TPFLAGS_DEFAULT;
- dirsType.tp_doc = "dirs";
- dirsType.tp_iter = (getiterfunc)dirs_iter;
- dirsType.tp_methods = dirs_methods;
- dirsType.tp_init = (initproc)dirs_init;
-
- if (PyType_Ready(&dirsType) < 0)
- return;
- Py_INCREF(&dirsType);
-
- PyModule_AddObject(mod, "dirs", (PyObject *)&dirsType);
-}