Skip to content

Commit 8fa2d46

Browse files
authored
Define a search helper to reduce code duplication (#284)
* There should be no meaningful performance degradation * If there is any impact at all, it will be positive (still not meaningful, though) * Calling `lower_bound` and then checking for equality preserves the search result. * Calling `find` requires a comparison with the end pointer, which `find` already did internally after calling `lower_bound`.
1 parent 1e1f689 commit 8fa2d46

3 files changed

Lines changed: 31 additions & 13 deletions

File tree

src/pysorteddict/sorted_dict_type.cc

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,23 @@ bool SortedDictType::is_nargs_good(char const* caller, Py_ssize_t nargs, int at_
214214
return true;
215215
}
216216

217+
/**
218+
* Find the lower bound of the given good key and report whether it was found.
219+
* (To determine whether a good key is present, check the second element of the
220+
* result; there is no meaningful performance impact of doing this instead of
221+
* calling `find` directly because it internally does the same thing done
222+
* here.)
223+
*
224+
* @param key Good key.
225+
*
226+
* @return The lower bound of the given key and whether it was found.
227+
*/
228+
std::pair<FwdIterType, bool> SortedDictType::lower_bound_and_found(PyObject* key)
229+
{
230+
auto it = this->map->lower_bound(key);
231+
return { it, it != this->map->end() && !this->map->key_comp()(key, it->first) };
232+
}
233+
217234
/**
218235
* Update the sorted dictionary with the keys and values from the given
219236
* mapping.
@@ -398,8 +415,8 @@ int SortedDictType::contains(PyObject* key, PyObject* value)
398415
{
399416
return -1;
400417
}
401-
auto it = this->map->find(key);
402-
if (it == this->map->end())
418+
auto [it, found] = this->lower_bound_and_found(key);
419+
if (!found)
403420
{
404421
return 0;
405422
}
@@ -433,8 +450,8 @@ PyObject* SortedDictType::getitem(PyObject* key)
433450
{
434451
return nullptr;
435452
}
436-
auto it = this->map->find(key);
437-
if (it == this->map->end())
453+
auto [it, found] = this->lower_bound_and_found(key);
454+
if (!found)
438455
{
439456
PyErr_SetObject(PyExc_KeyError, key);
440457
return nullptr;
@@ -460,8 +477,7 @@ int SortedDictType::setitem(PyObject* key, PyObject* value)
460477

461478
// Insertion will be faster if the approximate location is known. Hence,
462479
// look for the nearest match.
463-
auto it = this->map->lower_bound(key);
464-
bool found = it != this->map->end() && !this->map->key_comp()(key, it->first);
480+
auto [it, found] = this->lower_bound_and_found(key);
465481

466482
if (value == nullptr)
467483
{
@@ -558,8 +574,8 @@ PyObject* SortedDictType::get(PyObject* const* args, Py_ssize_t nargs)
558574
{
559575
return nullptr;
560576
}
561-
auto it = this->map->find(key);
562-
if (it != this->map->end())
577+
auto [it, found] = this->lower_bound_and_found(key);
578+
if (found)
563579
{
564580
return Py_NewRef(it->second.value); // 🆕
565581
}
@@ -588,8 +604,7 @@ PyObject* SortedDictType::setdefault(PyObject* const* args, Py_ssize_t nargs)
588604
{
589605
return nullptr;
590606
}
591-
auto it = this->map->lower_bound(key);
592-
bool found = it != this->map->end() && !this->map->key_comp()(key, it->first);
607+
auto [it, found] = this->lower_bound_and_found(key);
593608
if (found)
594609
{
595610
return Py_NewRef(it->second.value); // 🆕

src/pysorteddict/sorted_dict_type.hh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33

44
#define PY_SSIZE_T_CLEAN
55
#include <Python.h>
6+
#include <iterator>
67
#include <map>
8+
#include <utility>
79

810
/**
911
* C++-style comparison implementation for Python objects.
@@ -39,6 +41,9 @@ public:
3941
}
4042
};
4143

44+
using FwdIterType = std::map<PyObject*, SortedDictValue, SortedDictKeyCompare>::iterator;
45+
using RevIterType = std::reverse_iterator<FwdIterType>;
46+
4247
struct SortedDictType
4348
{
4449
public:
@@ -63,6 +68,7 @@ private:
6368
bool is_deletion_allowed(void);
6469
static bool is_deletion_allowed(Py_ssize_t);
6570
static bool is_nargs_good(char const*, Py_ssize_t, int, int);
71+
std::pair<FwdIterType, bool> lower_bound_and_found(PyObject*);
6672
bool update_from_mapping(PyObject*);
6773
bool update_from_sequence(PyObject*);
6874
bool update_from_object(PyObject*);

src/pysorteddict/sorted_dict_view_type.hh

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,10 @@
33

44
#define PY_SSIZE_T_CLEAN
55
#include <Python.h>
6-
#include <iterator>
76
#include <map>
87

98
#include "sorted_dict_type.hh"
109

11-
using FwdIterType = std::map<PyObject*, SortedDictValue, SortedDictKeyCompare>::iterator;
12-
using RevIterType = std::reverse_iterator<FwdIterType>;
1310
template<typename T>
1411
using IteratorToObject = PyObject* (*)(T);
1512

0 commit comments

Comments
 (0)