Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Include/dictobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ typedef struct {

/* Number of items in the dictionary */
Py_ssize_t ma_used;
// Number of free entries in front of dk_entries.
Py_ssize_t ma_offset;

/* Dictionary version: globally unique, value change each time
the dictionary is modified */
Expand Down
45 changes: 31 additions & 14 deletions Lib/test/test_ordered_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -520,14 +520,23 @@ def __hash__(self):
od[key] = i

# These should not crash.
with self.assertRaises(KeyError):
# Pure Python implementation raises KeyError, C implementation not.
try:
list(od.values())
with self.assertRaises(KeyError):
except KeyError:
pass
try:
list(od.items())
with self.assertRaises(KeyError):
except KeyError:
pass
try:
repr(od)
with self.assertRaises(KeyError):
except KeyError:
pass
try:
od.copy()
except KeyError:
pass

def test_issue24348(self):
OrderedDict = self.OrderedDict
Expand Down Expand Up @@ -578,8 +587,11 @@ def test_dict_delitem(self):
od['spam'] = 1
od['ham'] = 2
dict.__delitem__(od, 'spam')
with self.assertRaises(KeyError):
# Pure Python implementation raises KeyError, C implementation not.
try:
repr(od)
except KeyError:
pass

def test_dict_clear(self):
OrderedDict = self.OrderedDict
Expand All @@ -595,17 +607,23 @@ def test_dict_pop(self):
od['spam'] = 1
od['ham'] = 2
dict.pop(od, 'spam')
with self.assertRaises(KeyError):
# Pure Python implementation raises KeyError, C implementation not.
try:
repr(od)
except KeyError:
pass

def test_dict_popitem(self):
OrderedDict = self.OrderedDict
od = OrderedDict()
od['spam'] = 1
od['ham'] = 2
dict.popitem(od)
with self.assertRaises(KeyError):
# Pure Python implementation raises KeyError, C implementation not.
try:
repr(od)
except KeyError:
pass

def test_dict_setdefault(self):
OrderedDict = self.OrderedDict
Expand Down Expand Up @@ -676,26 +694,25 @@ def test_sizeof_exact(self):
size = support.calcobjsize
check = self.check_sizeof

basicsize = size('nQ2P' + '3PnPn2P') + calcsize('2nP2n')
basicsize = size('n2Q2P' + '2Pn') + calcsize('2nP2n')

entrysize = calcsize('n2P')
p = calcsize('P')
nodesize = calcsize('Pn2P')

od = OrderedDict()
check(od, basicsize + 8*p + 8 + 5*entrysize) # 8byte indicies + 8*2//3 * entry table
check(od, basicsize + 8 + 5*entrysize) # 8byte indicies + 8*2//3 * entry table
od.x = 1
check(od, basicsize + 8*p + 8 + 5*entrysize)
check(od, basicsize + 8 + 5*entrysize)
od.update([(i, i) for i in range(3)])
check(od, basicsize + 8*p + 8 + 5*entrysize + 3*nodesize)
check(od, basicsize + 8 + 5*entrysize)
od.update([(i, i) for i in range(3, 10)])
check(od, basicsize + 16*p + 16 + 10*entrysize + 10*nodesize)
check(od, basicsize + 16 + 10*entrysize)

check(od.keys(), size('P'))
check(od.items(), size('P'))
check(od.values(), size('P'))

itersize = size('iP2n2P')
itersize = size('i2P3nP')
check(iter(od), itersize)
check(iter(od.keys()), itersize)
check(iter(od.items()), itersize)
Expand Down
6 changes: 3 additions & 3 deletions Lib/test/test_sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -949,9 +949,9 @@ def inner():
# method-wrapper (descriptor object)
check({}.__iter__, size('2P'))
# dict
check({}, size('nQ2P') + calcsize('2nP2n') + 8 + (8*2//3)*calcsize('n2P'))
check({}, size('2nQ2P') + calcsize('2nP2n') + 8 + (8*2//3)*calcsize('n2P'))
longdict = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8}
check(longdict, size('nQ2P') + calcsize('2nP2n') + 16 + (16*2//3)*calcsize('n2P'))
check(longdict, size('2nQ2P') + calcsize('2nP2n') + 16 + (16*2//3)*calcsize('n2P'))
# dictionary-keyview
check({}.keys(), size('P'))
# dictionary-valueview
Expand Down Expand Up @@ -1115,7 +1115,7 @@ def delx(self): del self.__x
class newstyleclass(object): pass
check(newstyleclass, s)
# dict with shared keys
check(newstyleclass().__dict__, size('nQ2P' + '2nP2n'))
check(newstyleclass().__dict__, size('n2Q2P' + '2nP2n'))
# unicode
# each tuple contains a string and its expected character size
# don't put any static strings here, as they may contain
Expand Down
4 changes: 1 addition & 3 deletions Makefile.pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,6 @@ OBJECT_OBJS= \
Objects/listobject.o \
Objects/longobject.o \
Objects/dictobject.o \
Objects/odictobject.o \
Objects/memoryobject.o \
Objects/methodobject.o \
Objects/moduleobject.o \
Expand Down Expand Up @@ -854,8 +853,7 @@ Objects/bytearrayobject.o: $(srcdir)/Objects/bytearrayobject.c $(BYTESTR_DEPS)

Objects/unicodeobject.o: $(srcdir)/Objects/unicodeobject.c $(UNICODE_DEPS)

Objects/odictobject.o: $(srcdir)/Objects/dict-common.h
Objects/dictobject.o: $(srcdir)/Objects/stringlib/eq.h $(srcdir)/Objects/dict-common.h
Objects/dictobject.o: $(srcdir)/Objects/stringlib/eq.h
Objects/setobject.o: $(srcdir)/Objects/stringlib/eq.h

.PHONY: regen-opcode-targets
Expand Down
132 changes: 131 additions & 1 deletion Objects/clinic/dictobject.c.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,134 @@ dict_setdefault(PyDictObject *self, PyObject **args, Py_ssize_t nargs)
exit:
return return_value;
}
/*[clinic end generated code: output=8d09902e60b7ab02 input=a9049054013a1b77]*/

PyDoc_STRVAR(OrderedDict_fromkeys__doc__,
"fromkeys($type, /, iterable, value=None)\n"
"--\n"
"\n"
"Create a new ordered dictionary with keys from iterable and values set to value.");

#define ORDEREDDICT_FROMKEYS_METHODDEF \
{"fromkeys", (PyCFunction)OrderedDict_fromkeys, METH_FASTCALL|METH_KEYWORDS|METH_CLASS, OrderedDict_fromkeys__doc__},

static PyObject *
OrderedDict_fromkeys_impl(PyTypeObject *type, PyObject *seq, PyObject *value);

static PyObject *
OrderedDict_fromkeys(PyTypeObject *type, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
static const char * const _keywords[] = {"iterable", "value", NULL};
static _PyArg_Parser _parser = {"O|O:fromkeys", _keywords, 0};
PyObject *seq;
PyObject *value = Py_None;

if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&seq, &value)) {
goto exit;
}
return_value = OrderedDict_fromkeys_impl(type, seq, value);

exit:
return return_value;
}

PyDoc_STRVAR(OrderedDict_setdefault__doc__,
"setdefault($self, /, key, default=None)\n"
"--\n"
"\n"
"Insert key with a value of default if key is not in the dictionary.\n"
"\n"
"Return the value for key if key is in the dictionary, else default.");

#define ORDEREDDICT_SETDEFAULT_METHODDEF \
{"setdefault", (PyCFunction)OrderedDict_setdefault, METH_FASTCALL|METH_KEYWORDS, OrderedDict_setdefault__doc__},

static PyObject *
OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key,
PyObject *default_value);

static PyObject *
OrderedDict_setdefault(PyODictObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
static const char * const _keywords[] = {"key", "default", NULL};
static _PyArg_Parser _parser = {"O|O:setdefault", _keywords, 0};
PyObject *key;
PyObject *default_value = Py_None;

if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&key, &default_value)) {
goto exit;
}
return_value = OrderedDict_setdefault_impl(self, key, default_value);

exit:
return return_value;
}

PyDoc_STRVAR(OrderedDict_popitem__doc__,
"popitem($self, /, last=True)\n"
"--\n"
"\n"
"Remove and return a (key, value) pair from the dictionary.\n"
"\n"
"Pairs are returned in LIFO order if last is true or FIFO order if false.");

#define ORDEREDDICT_POPITEM_METHODDEF \
{"popitem", (PyCFunction)OrderedDict_popitem, METH_FASTCALL|METH_KEYWORDS, OrderedDict_popitem__doc__},

static PyObject *
OrderedDict_popitem_impl(PyODictObject *self, int last);

static PyObject *
OrderedDict_popitem(PyODictObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
static const char * const _keywords[] = {"last", NULL};
static _PyArg_Parser _parser = {"|p:popitem", _keywords, 0};
int last = 1;

if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&last)) {
goto exit;
}
return_value = OrderedDict_popitem_impl(self, last);

exit:
return return_value;
}

PyDoc_STRVAR(OrderedDict_move_to_end__doc__,
"move_to_end($self, /, key, last=True)\n"
"--\n"
"\n"
"Move an existing element to the end (or beginning if last is false).\n"
"\n"
"Raise KeyError if the element does not exist.");

#define ORDEREDDICT_MOVE_TO_END_METHODDEF \
{"move_to_end", (PyCFunction)OrderedDict_move_to_end, METH_FASTCALL|METH_KEYWORDS, OrderedDict_move_to_end__doc__},

static PyObject *
OrderedDict_move_to_end_impl(PyODictObject *self, PyObject *key, int last);

static PyObject *
OrderedDict_move_to_end(PyODictObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
static const char * const _keywords[] = {"key", "last", NULL};
static _PyArg_Parser _parser = {"O|p:move_to_end", _keywords, 0};
PyObject *key;
int last = 1;

if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&key, &last)) {
goto exit;
}
return_value = OrderedDict_move_to_end_impl(self, key, last);

exit:
return return_value;
}
/*[clinic end generated code: output=c5169c4993a5a8bb input=a9049054013a1b77]*/
Loading