Skip to content

Commit 1bae63c

Browse files
ahilgerfacebook-github-bot
authored andcommitted
consolidate map sort on write code
Summary: Consolidate the `writeMapSorted` for mutable and immutable because they're almost identical, except for call to get items from mutable dict. In the future, if we change immutable data type to dict, then they'll fully converge. Reviewed By: createdbysk Differential Revision: D78528675 fbshipit-source-id: 8641570fbf030ca72fd350cf22b39e4100a3cab1
1 parent 3ca5830 commit 1bae63c

File tree

2 files changed

+64
-54
lines changed

2 files changed

+64
-54
lines changed

thrift/lib/python/types.cpp

Lines changed: 32 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,37 +1021,6 @@ void* setIOBuf(void* objectPtr, const folly::IOBuf& value) {
10211021
return nullptr;
10221022
}
10231023

1024-
// This helper method for `MutableMapTypeInfo::write()` sorts the map keys and
1025-
// writes them to the wire. It is called when the `protocolSortKeys` parameter
1026-
// of `write()` is set to `true`.
1027-
size_t writeMapSorted(
1028-
const void* context,
1029-
const void* object,
1030-
size_t (*writer)(
1031-
const void* context, const void* keyElem, const void* valueElem)) {
1032-
PyObject* dict = const_cast<PyObject*>(toPyObject(object));
1033-
DCHECK(PyDict_Check(dict));
1034-
UniquePyObjectPtr listPtr =
1035-
UniquePyObjectPtr{PySequence_List(PyDict_Items(dict))};
1036-
if (!listPtr) {
1037-
THRIFT_PY3_CHECK_ERROR();
1038-
}
1039-
if (PyList_Sort(listPtr.get()) == -1) {
1040-
THRIFT_PY3_CHECK_ERROR();
1041-
}
1042-
1043-
size_t written = 0;
1044-
const Py_ssize_t size = PyList_Size(listPtr.get());
1045-
for (std::uint32_t i = 0; i < size; ++i) {
1046-
PyObject* pair = PyList_GET_ITEM(listPtr.get(), i);
1047-
PyObject* key = PyTuple_GET_ITEM(pair, 0);
1048-
PyObject* value = PyTuple_GET_ITEM(pair, 1);
1049-
written += writer(context, &key, &value);
1050-
}
1051-
1052-
return written;
1053-
}
1054-
10551024
inline UniquePyObjectPtr primitiveCppToPython(bool value) {
10561025
PyObject* ret = value ? Py_True : Py_False;
10571026
Py_INCREF(ret);
@@ -1647,26 +1616,43 @@ void ImmutableMapHandler::read(
16471616
setPyObject(objectPtr, std::move(map));
16481617
}
16491618

1650-
size_t ImmutableMapHandler::write(
1619+
size_t writeMapSorted(
1620+
const void* context,
1621+
const void* object,
1622+
PyObject* (*toItems)(PyObject* dict_),
1623+
size_t (*writer)(
1624+
const void* context, const void* keyElem, const void* valueElem)) {
1625+
PyObject* dict = const_cast<PyObject*>(toPyObject(object));
1626+
PyObject* keys = toItems(dict);
1627+
UniquePyObjectPtr listPtr = UniquePyObjectPtr{PySequence_List(keys)};
1628+
if (!listPtr) {
1629+
THRIFT_PY3_CHECK_ERROR();
1630+
}
1631+
if (PyList_Sort(listPtr.get()) == -1) {
1632+
THRIFT_PY3_CHECK_ERROR();
1633+
}
1634+
1635+
size_t written = 0;
1636+
const Py_ssize_t size = PyList_Size(listPtr.get());
1637+
for (std::uint32_t i = 0; i < size; ++i) {
1638+
PyObject* pair = PyList_GET_ITEM(listPtr.get(), i);
1639+
PyObject* key = PyTuple_GET_ITEM(pair, 0);
1640+
PyObject* value = PyTuple_GET_ITEM(pair, 1);
1641+
written += writer(context, &key, &value);
1642+
}
1643+
1644+
return written;
1645+
}
1646+
1647+
size_t ImmutableMapHandler::writeUnsorted(
16511648
const void* context,
16521649
const void* object,
1653-
bool protocolSortKeys,
16541650
size_t (*writer)(
16551651
const void* context, const void* keyElem, const void* valueElem)) {
16561652
size_t written = 0;
16571653
PyObject* map = const_cast<PyObject*>(toPyObject(object));
16581654
const Py_ssize_t size = PyTuple_GET_SIZE(map);
16591655
UniquePyObjectPtr seq;
1660-
if (protocolSortKeys) {
1661-
seq = UniquePyObjectPtr{PySequence_List(map)};
1662-
if (!seq) {
1663-
THRIFT_PY3_CHECK_ERROR();
1664-
}
1665-
if (PyList_Sort(seq.get()) == -1) {
1666-
THRIFT_PY3_CHECK_ERROR();
1667-
}
1668-
map = PySequence_Tuple(seq.get());
1669-
}
16701656
for (std::uint32_t i = 0; i < size; ++i) {
16711657
PyObject* pair = PyTuple_GET_ITEM(map, i);
16721658
PyObject* key = PyTuple_GET_ITEM(pair, 0);
@@ -1723,24 +1709,21 @@ void MutableMapHandler::read(
17231709
setPyObject(objectPtr, std::move(dict));
17241710
}
17251711

1726-
size_t MutableMapHandler::write(
1712+
size_t MutableMapHandler::writeUnsorted(
17271713
const void* context,
17281714
const void* object,
1729-
bool protocolSortKeys,
17301715
size_t (*writer)(
17311716
const void* context, const void* keyElem, const void* valueElem)) {
1732-
if (protocolSortKeys) {
1733-
return writeMapSorted(context, object, writer);
1734-
}
1735-
17361717
PyObject* dict = const_cast<PyObject*>(toPyObject(object));
17371718
size_t written = 0;
17381719
PyObject* key = nullptr;
17391720
PyObject* value = nullptr;
17401721
Py_ssize_t pos = 0;
1722+
17411723
while (PyDict_Next(dict, &pos, &key, &value)) {
17421724
written += writer(context, &key, &value);
17431725
}
1726+
17441727
return written;
17451728
}
17461729

thrift/lib/python/types.h

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,17 @@ struct MutableSetHandler {
564564

565565
using MutableSetTypeInfo = SetTypeInfoImpl<MutableSetHandler, false>;
566566

567+
/**
568+
* This helper method sorts map keys and write them to the wire. It may be
569+
* called for both mutable and immutable maps.
570+
*/
571+
size_t writeMapSorted(
572+
const void* context,
573+
const void* object,
574+
PyObject* (*toItems)(PyObject* dict),
575+
size_t (*writer)(
576+
const void* context, const void* keyElem, const void* valueElem));
577+
567578
template <typename Handler>
568579
class MapTypeInfoImpl {
569580
public:
@@ -588,7 +599,10 @@ class MapTypeInfoImpl {
588599
bool protocolSortKeys,
589600
size_t (*writer)(
590601
const void* context, const void* keyElem, const void* valueElem)) {
591-
return Handler::write(context, object, protocolSortKeys, writer);
602+
if (UNLIKELY(protocolSortKeys)) {
603+
return writeMapSorted(context, object, Handler::toItems, writer);
604+
}
605+
return Handler::writeUnsorted(context, object, writer);
592606
}
593607

594608
static void consumeElem(
@@ -632,6 +646,12 @@ class ImmutableMapHandler {
632646
return PyTuple_GET_SIZE(object);
633647
}
634648

649+
// Result is used by writeMapSorted as input to PySequence_list
650+
// Since immutable map representation is tuple, this is a no-op.
651+
// Since maps can't have duplicate keys, the value (second value in tuple)
652+
// will never be used for comparison, only the first value of each.
653+
static PyObject* toItems(PyObject* dictTuple) { return dictTuple; }
654+
635655
static void* clear(void* object) { return setContainer(object); }
636656

637657
static void read(
@@ -641,10 +661,9 @@ class ImmutableMapHandler {
641661
void (*keyReader)(const void* context, void* key),
642662
void (*valueReader)(const void* context, void* val));
643663

644-
static size_t write(
664+
static size_t writeUnsorted(
645665
const void* context,
646666
const void* object,
647-
bool protocolSortKeys,
648667
size_t (*writer)(
649668
const void* context, const void* keyElem, const void* valueElem));
650669

@@ -663,6 +682,15 @@ class MutableMapHandler {
663682
return PyDict_Size(const_cast<PyObject*>(object));
664683
}
665684

685+
// Result is used by writeMapSorted as input to PySequence_List
686+
static PyObject* toItems(PyObject* dict) {
687+
PyObject* keys = PyDict_Items(dict);
688+
if (keys == nullptr) {
689+
THRIFT_PY3_CHECK_ERROR();
690+
}
691+
return keys;
692+
}
693+
666694
static void* clear(void* objectPtr) { return setMutableMap(objectPtr); }
667695

668696
/**
@@ -702,10 +730,9 @@ class MutableMapHandler {
702730
*
703731
* @return Total number of bytes written.
704732
*/
705-
static size_t write(
733+
static size_t writeUnsorted(
706734
const void* context,
707735
const void* object,
708-
bool protocolSortKeys,
709736
size_t (*writer)(
710737
const void* context, const void* keyElem, const void* valueElem));
711738

0 commit comments

Comments
 (0)