GH-46412: More efficient bool() for ndbm/_gdbmmodule (#96692) · python/cpython@df50938 · GitHub
Skip to content

Commit df50938

Browse files
authored
GH-46412: More efficient bool() for ndbm/_gdbmmodule (#96692)
1 parent 95d6330 commit df50938

5 files changed

Lines changed: 91 additions & 0 deletions

File tree

Lib/test/test_dbm_gnu.py

Lines changed: 14 additions & 0 deletions

Lib/test/test_dbm_ndbm.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,20 @@ def test_open_with_bytes_path(self):
133133
def test_open_with_pathlib_bytes_path(self):
134134
dbm.ndbm.open(os_helper.FakePath(os.fsencode(self.filename)), "c").close()
135135

136+
def test_bool_empty(self):
137+
with dbm.ndbm.open(self.filename, 'c') as db:
138+
self.assertFalse(bool(db))
139+
140+
def test_bool_not_empty(self):
141+
with dbm.ndbm.open(self.filename, 'c') as db:
142+
db['a'] = 'b'
143+
self.assertTrue(bool(db))
144+
145+
def test_bool_on_closed_db_raises(self):
146+
with dbm.ndbm.open(self.filename, 'c') as db:
147+
db['a'] = 'b'
148+
self.assertRaises(dbm.ndbm.error, bool, db)
149+
136150

137151
if __name__ == '__main__':
138152
unittest.main()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve performance of ``bool(db)`` for large ndb/gdb databases. Previously this would call ``len(db)`` which would iterate over all keys -- the answer (empty or not) is known after the first key.

Modules/_dbmmodule.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,37 @@ dbm_length(dbmobject *dp)
130130
return dp->di_size;
131131
}
132132

133+
static int
134+
dbm_bool(dbmobject *dp)
135+
{
136+
_dbm_state *state = PyType_GetModuleState(Py_TYPE(dp));
137+
assert(state != NULL);
138+
139+
if (dp->di_dbm == NULL) {
140+
PyErr_SetString(state->dbm_error, "DBM object has already been closed");
141+
return -1;
142+
}
143+
144+
if (dp->di_size > 0) {
145+
/* Known non-zero size. */
146+
return 1;
147+
}
148+
if (dp->di_size == 0) {
149+
/* Known zero size. */
150+
return 0;
151+
}
152+
153+
/* Unknown size. Ensure DBM object has an entry. */
154+
datum key = dbm_firstkey(dp->di_dbm);
155+
if (key.dptr == NULL) {
156+
/* Empty. Cache this fact. */
157+
dp->di_size = 0;
158+
return 0;
159+
}
160+
/* Non-empty. Don't cache the length since we don't know. */
161+
return 1;
162+
}
163+
133164
static PyObject *
134165
dbm_subscript(dbmobject *dp, PyObject *key)
135166
{
@@ -416,6 +447,7 @@ static PyType_Slot dbmtype_spec_slots[] = {
416447
{Py_mp_length, dbm_length},
417448
{Py_mp_subscript, dbm_subscript},
418449
{Py_mp_ass_subscript, dbm_ass_sub},
450+
{Py_nb_bool, dbm_bool},
419451
{0, 0}
420452
};
421453

Modules/_gdbmmodule.c

Lines changed: 30 additions & 0 deletions

0 commit comments

Comments
 (0)