Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unsigned variants #122

Merged
merged 3 commits into from
Mar 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,14 @@ script:
- python --version
- |
if [[ "$WITH_COVERAGE" == "1" ]]; then
coverage run -m zope.testrunner --test-path=. --auto-color --auto-progress --verbose
python -m coverage run -m zope.testrunner --test-path=. --auto-color --auto-progress --verbose
else
zope-testrunner --test-path=. --auto-color --auto-progress --verbose
python -m zope.testrunner --test-path=. --auto-color --auto-progress --verbose
fi
- python setup.py -q bdist_wheel

after_success:
- if [[ "$WITH_COVERAGE" == "1" ]]; then coveralls; fi
- if [[ "$WITH_COVERAGE" == "1" ]]; then python -m coveralls; fi
- |
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
# macpython 3.5 doesn't support recent TLS protocols which causes twine
Expand Down
139 changes: 112 additions & 27 deletions BTrees/BTreeModuleTemplate.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,28 +77,117 @@ static void PyVar_Assign(PyObject **v, PyObject *e) { Py_XDECREF(*v); *v=e;}
#error "PY_LONG_LONG required but not defined"
#endif

static int
longlong_handle_overflow(PY_LONG_LONG result, int overflow)
{
if (overflow)
{
/* Python 3 tends to have an exception already set, Python 2 not so much */
if (!PyErr_Occurred())
PyErr_SetString(PyExc_OverflowError, "couldn't convert integer to C long long");
return 0;
}
else if (result == -1 && PyErr_Occurred())
/* An exception has already been raised. */
return 0;
return 1;
}


#ifdef NEED_LONG_LONG_KEYS

#if defined(ZODB_UNSIGNED_VALUE_INTS) || defined(ZODB_UNSIGNED_KEY_INTS)
static int
ulonglong_check(PyObject *ob)
{
#ifndef PY3K
if (PyInt_Check(ob))
{
long tmp;
tmp = PyInt_AS_LONG(ob);
if (tmp < 0) {
PyErr_SetString(PyExc_OverflowError, "unsigned value less than 0");
return 0;
}
return 1;
}
#endif

if (!PyLong_Check(ob))
{
return 0;
}

if (PyLong_AsUnsignedLongLong(ob) == (unsigned long long)-1 && PyErr_Occurred())
{
return 0;
}
return 1;
}
#endif /* defined(ZODB_UNSIGNED_VALUE_INTS) || defined(ZODB_UNSIGNED_KEY_INTS) */

static int
longlong_check(PyObject *ob)
{
if (INT_CHECK(ob))
#ifndef PY3K
/* Python's small integers can always fit into a long long. */
if (PyInt_Check(ob))
return 1;
#endif

if (PyLong_Check(ob)) {
int overflow;
(void)PyLong_AsLongLongAndOverflow(ob, &overflow);
if (overflow)
goto overflow;
return 1;
PY_LONG_LONG result;
result = PyLong_AsLongLongAndOverflow(ob, &overflow);
return longlong_handle_overflow(result, overflow);
}
return 0;
overflow:
PyErr_SetString(PyExc_ValueError,
"longlong_check: long integer out of range");
return 0;
}

#endif

#if defined(ZODB_UNSIGNED_VALUE_INTS) || defined(ZODB_UNSIGNED_KEY_INTS)
static PyObject *
ulonglong_as_object(unsigned PY_LONG_LONG val)
{
if ((val > LONG_MAX))
return PyLong_FromUnsignedLongLong(val);
return UINT_FROM_LONG((unsigned long)val);
}

static int
ulonglong_convert(PyObject *ob, unsigned PY_LONG_LONG *value)
{
unsigned PY_LONG_LONG val;

#ifndef PY3K
if (PyInt_Check(ob))
{
long tmp;
tmp = PyInt_AS_LONG(ob);
if (tmp < 0) {
PyErr_SetString(PyExc_OverflowError, "unsigned value less than 0");
return 0;
}
(*value) = (unsigned PY_LONG_LONG)tmp;
return 1;
}
#endif

if (!PyLong_Check(ob))
{
PyErr_SetString(PyExc_TypeError, "expected integer key");
return 0;
}

val = PyLong_AsUnsignedLongLong(ob);
if (val == (unsigned long long)-1 && PyErr_Occurred())
return 0;
(*value) = val;
return 1;
}
#endif /* defined(ZODB_UNSIGNED_VALUE_INTS) || defined(ZODB_UNSIGNED_KEY_INTS) */

static PyObject *
longlong_as_object(PY_LONG_LONG val)
{
Expand All @@ -107,10 +196,11 @@ longlong_as_object(PY_LONG_LONG val)
return INT_FROM_LONG((long)val);
}


static int
longlong_convert(PyObject *ob, PY_LONG_LONG *value)
{
PY_LONG_LONG val;
int overflow;
#ifndef PY3K
if (PyInt_Check(ob))
{
Expand All @@ -124,20 +214,15 @@ longlong_convert(PyObject *ob, PY_LONG_LONG *value)
PyErr_SetString(PyExc_TypeError, "expected integer key");
return 0;
}
else
val = PyLong_AsLongLongAndOverflow(ob, &overflow);
if (!longlong_handle_overflow(val, overflow))
{
PY_LONG_LONG val;
int overflow;
val = PyLong_AsLongLongAndOverflow(ob, &overflow);
if (overflow)
goto overflow;
(*value) = val;
return 1;
return 0;
}
overflow:
PyErr_SetString(PyExc_ValueError, "long integer out of range");
return 0;
(*value) = val;
return 1;
}

#endif /* NEED_LONG_LONG_SUPPORT */


Expand Down Expand Up @@ -424,30 +509,30 @@ static char *search_keywords[] = {"min", "max",

static struct PyMethodDef module_methods[] = {
{"difference", (PyCFunction) difference_m, METH_VARARGS,
"difference(o1, o2) -- "
"difference(o1, o2)\n"
"compute the difference between o1 and o2"
},
{"union", (PyCFunction) union_m, METH_VARARGS,
"union(o1, o2) -- compute the union of o1 and o2\n"
"union(o1, o2)\ncompute the union of o1 and o2\n"
},
{"intersection", (PyCFunction) intersection_m, METH_VARARGS,
"intersection(o1, o2) -- "
"intersection(o1, o2)\n"
"compute the intersection of o1 and o2"
},
#ifdef MERGE
{"weightedUnion", (PyCFunction) wunion_m, METH_VARARGS,
"weightedUnion(o1, o2 [, w1, w2]) -- compute the union of o1 and o2\n"
"weightedUnion(o1, o2 [, w1, w2])\ncompute the union of o1 and o2\n"
"\nw1 and w2 are weights."
},
{"weightedIntersection", (PyCFunction) wintersection_m, METH_VARARGS,
"weightedIntersection(o1, o2 [, w1, w2]) -- "
"weightedIntersection(o1, o2 [, w1, w2])\n"
"compute the intersection of o1 and o2\n"
"\nw1 and w2 are weights."
},
#endif
#ifdef MULTI_INT_UNION
{"multiunion", (PyCFunction) multiunion_m, METH_VARARGS,
"multiunion(seq) -- compute union of a sequence of integer sets.\n"
"multiunion(seq)\ncompute union of a sequence of integer sets.\n"
"\n"
"Each element of seq must be an integer set, or convertible to one\n"
"via the set iteration protocol. The union returned is an IISet."
Expand Down
113 changes: 113 additions & 0 deletions BTrees/IUBTree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
##############################################################################
#
# Copyright (c) 2001-2012 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################

__all__ = ('Bucket', 'Set', 'BTree', 'TreeSet',
'IUBucket', 'IUSet', 'IUBTree', 'IUTreeSet',
'union', 'intersection', 'difference',
'weightedUnion', 'weightedIntersection', 'multiunion',
)

from zope.interface import moduleProvides

from .Interfaces import IIntegerUnsignedBTreeModule
from ._base import Bucket
from ._base import MERGE
from ._base import MERGE_WEIGHT_numeric
from ._base import MERGE_DEFAULT_int
from ._base import Set
from ._base import Tree as BTree
from ._base import TreeSet
from ._base import _TreeIterator
from ._base import difference as _difference
from ._base import intersection as _intersection
from ._base import multiunion as _multiunion
from ._base import set_operation as _set_operation
from ._base import to_int as _to_key
from ._base import to_uint as _to_value
from ._base import union as _union
from ._base import weightedIntersection as _weightedIntersection
from ._base import weightedUnion as _weightedUnion
from ._base import _fix_pickle
from ._compat import import_c_extension

_BUCKET_SIZE = 120
_TREE_SIZE = 500
using64bits = False


class IUBucketPy(Bucket):
_to_key = _to_key
_to_value = _to_value
MERGE = MERGE
MERGE_WEIGHT = MERGE_WEIGHT_numeric
MERGE_DEFAULT = MERGE_DEFAULT_int


class IUSetPy(Set):
_to_key = _to_key
MERGE = MERGE
MERGE_WEIGHT = MERGE_WEIGHT_numeric
MERGE_DEFAULT = MERGE_DEFAULT_int


class IUBTreePy(BTree):
max_leaf_size = _BUCKET_SIZE
max_internal_size = _TREE_SIZE
_to_key = _to_key
_to_value = _to_value
MERGE = MERGE
MERGE_WEIGHT = MERGE_WEIGHT_numeric
MERGE_DEFAULT = MERGE_DEFAULT_int


class IUTreeSetPy(TreeSet):
max_leaf_size = _BUCKET_SIZE
max_internal_size = _TREE_SIZE
_to_key = _to_key
MERGE = MERGE
MERGE_WEIGHT = MERGE_WEIGHT_numeric
MERGE_DEFAULT = MERGE_DEFAULT_int


class IUTreeIteratorPy(_TreeIterator):
pass


# Can't declare forward refs, so fix up afterwards:

IUBucketPy._mapping_type = IUBucketPy._bucket_type = IUBucketPy
IUBucketPy._set_type = IUSetPy

IUSetPy._mapping_type = IUBucketPy
IUSetPy._set_type = IUSetPy._bucket_type = IUSetPy

IUBTreePy._mapping_type = IUBTreePy._bucket_type = IUBucketPy
IUBTreePy._set_type = IUSetPy

IUTreeSetPy._mapping_type = IUBucketPy
IUTreeSetPy._set_type = IUTreeSetPy._bucket_type = IUSetPy


differencePy = _set_operation(_difference, IUSetPy)
unionPy = _set_operation(_union, IUSetPy)
intersectionPy = _set_operation(_intersection, IUSetPy)
multiunionPy = _set_operation(_multiunion, IUSetPy)
weightedUnionPy = _set_operation(_weightedUnion, IUSetPy)
weightedIntersectionPy = _set_operation(_weightedIntersection, IUSetPy)

import_c_extension(globals())

_fix_pickle(globals(), __name__)

moduleProvides(IIntegerUnsignedBTreeModule)