small-cache 0.0.1__tar.gz → 0.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,9 +14,9 @@ jobs:
14
14
  python-version: ["3.11", "3.12"]
15
15
 
16
16
  steps:
17
- - uses: actions/checkout@v4
17
+ - uses: actions/checkout@v6
18
18
 
19
- - uses: actions/setup-python@v5
19
+ - uses: actions/setup-python@v6
20
20
  with:
21
21
  python-version: ${{ matrix.python-version }}
22
22
 
@@ -11,7 +11,7 @@ jobs:
11
11
  name: Build SDist
12
12
  runs-on: ubuntu-latest
13
13
  steps:
14
- - uses: actions/checkout@v4
14
+ - uses: actions/checkout@v6
15
15
  with:
16
16
  submodules: true
17
17
 
@@ -21,7 +21,7 @@ jobs:
21
21
  - name: Check metadata
22
22
  run: pipx run twine check dist/*
23
23
 
24
- - uses: actions/upload-artifact@v4
24
+ - uses: actions/upload-artifact@v5
25
25
  with:
26
26
  name: dist-sdist
27
27
  path: dist/*.tar.gz
@@ -36,18 +36,18 @@ jobs:
36
36
  os: [ubuntu-latest, macos-latest, windows-latest]
37
37
 
38
38
  steps:
39
- - uses: actions/checkout@v4
39
+ - uses: actions/checkout@v6
40
40
  with:
41
41
  submodules: true
42
42
 
43
- - uses: pypa/cibuildwheel@v3.0
43
+ - uses: pypa/cibuildwheel@v3.3
44
44
 
45
45
  - name: Verify clean directory
46
46
  run: git diff --exit-code
47
47
  shell: bash
48
48
 
49
49
  - name: Upload wheels
50
- uses: actions/upload-artifact@v4
50
+ uses: actions/upload-artifact@v5
51
51
  with:
52
52
  path: wheelhouse/*.whl
53
53
  name: dist-${{ matrix.os }}
@@ -59,8 +59,8 @@ jobs:
59
59
  if: github.event_name == 'release' && github.event.action == 'published'
60
60
 
61
61
  steps:
62
- - uses: actions/setup-python@v5
63
- - uses: actions/download-artifact@v4
62
+ - uses: actions/setup-python@v6
63
+ - uses: actions/download-artifact@v6
64
64
  with:
65
65
  path: dist
66
66
  pattern: dist-*
@@ -66,7 +66,7 @@ include(FetchContent)
66
66
  FetchContent_Declare(
67
67
  glaze
68
68
  GIT_REPOSITORY https://github.com/stephenberry/glaze.git
69
- GIT_TAG main
69
+ GIT_TAG v6.1.0
70
70
  GIT_SHALLOW TRUE
71
71
  )
72
72
 
@@ -75,7 +75,7 @@ FetchContent_MakeAvailable(glaze)
75
75
  FetchContent_Declare(
76
76
  tsl_sparse_map
77
77
  GIT_REPOSITORY https://github.com/Tessil/sparse-map
78
- GIT_TAG master
78
+ GIT_TAG v0.7.0
79
79
  GIT_SHALLOW TRUE
80
80
  )
81
81
  FetchContent_MakeAvailable(tsl_sparse_map)
@@ -83,7 +83,7 @@ FetchContent_MakeAvailable(tsl_sparse_map)
83
83
  FetchContent_Declare(
84
84
  absl
85
85
  GIT_REPOSITORY https://github.com/abseil/abseil-cpp.git
86
- GIT_TAG master
86
+ GIT_TAG 20250814.1
87
87
  GIT_SHALLOW TRUE
88
88
  OVERRIDE_FIND_PACKAGE TRUE
89
89
  EXCLUDE_FROM_ALL
@@ -92,14 +92,14 @@ FetchContent_Declare(
92
92
  find_package(
93
93
  absl
94
94
  REQUIRED
95
- COMPONENTS flat_hash_map hash
95
+ COMPONENTS flat_hash_map flat_hash_set hash
96
96
  )
97
97
 
98
98
  Set(FETCHCONTENT_QUIET FALSE)
99
99
  FetchContent_Declare(
100
100
  Boost
101
101
  URL https://github.com/boostorg/boost/releases/download/boost-1.88.0/boost-1.88.0-cmake.7z
102
- GIT_TAG "boost-1.88.0"
102
+ GIT_TAG "boost-1.89.0"
103
103
  USES_TERMINAL_DOWNLOAD TRUE
104
104
  GIT_PROGRESS TRUE
105
105
  DOWNLOAD_NO_EXTRACT FALSE
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: small-cache
3
- Version: 0.0.1
3
+ Version: 0.0.3
4
4
  Summary: Small cache
5
5
  Author: kam1k4dze
6
6
  Classifier: License :: OSI Approved :: BSD License
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "small-cache"
7
- version = "0.0.1"
7
+ version = "0.0.3"
8
8
  description = "Small cache"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -8,6 +8,7 @@
8
8
  #include <tsl/sparse_map.h>
9
9
  #include <absl/hash/hash.h>
10
10
  #include <absl/container/flat_hash_map.h>
11
+ #include <absl/container/flat_hash_set.h>
11
12
  #include <boost/flyweight.hpp>
12
13
  #include <optional>
13
14
  #include <algorithm>
@@ -55,7 +56,7 @@ class SmallCache {
55
56
  using str = std::string;
56
57
  using strVec = std::vector<str>;
57
58
  using fwStr = boost::flyweight<str>;
58
- using strVecUPtr = std::unique_ptr<std::vector<fwStr> >;
59
+ using strVecUPtr = std::unique_ptr<std::vector<fwStr>>;
59
60
 
60
61
  using AttributeValue = std::variant<std::monostate, double, bool, fwStr, strVecUPtr>;
61
62
  using pyAttrValue = std::variant<std::monostate, bool, double, str, strVec>;
@@ -109,7 +110,7 @@ public:
109
110
  return (attrs_flags[w] >> b) & 1u;
110
111
  }
111
112
 
112
- [[nodiscard]] std::optional<std::reference_wrapper<AttributeValue> > getValue(size_t idx) noexcept {
113
+ [[nodiscard]] std::optional<std::reference_wrapper<AttributeValue>> getValue(size_t idx) noexcept {
113
114
  if (!hasIdx(idx))
114
115
  return std::nullopt;
115
116
 
@@ -130,7 +131,7 @@ public:
130
131
  return value.size() > pos ? std::optional{std::ref(value[pos])} : std::nullopt; // just-in-case
131
132
  }
132
133
 
133
- [[nodiscard]] std::optional<std::reference_wrapper<const AttributeValue> > getValue(size_t idx) const noexcept {
134
+ [[nodiscard]] std::optional<std::reference_wrapper<const AttributeValue>> getValue(size_t idx) const noexcept {
134
135
  if (auto ref = const_cast<MarkedItem *>(this)->getValue(idx))
135
136
  return std::cref(ref->get());
136
137
  return std::nullopt;
@@ -142,7 +143,7 @@ public:
142
143
  item.attrs_flags.fill(0);
143
144
 
144
145
  // build a slot for each possible attr index
145
- std::vector<std::optional<AttributeValue> > slots(attrMap.size());
146
+ std::vector<std::optional<AttributeValue>> slots(attrMap.size());
146
147
 
147
148
  // 1) collect into slots[] by index
148
149
  for (auto &[name, pyVal]: attrs) {
@@ -185,29 +186,29 @@ public:
185
186
 
186
187
  static AttributeValue convert_value(const json::AttributeValue &src) {
187
188
  return std::visit(overloaded{
188
- [](bool b) -> AttributeValue { return b; },
189
- [](double d) -> AttributeValue { return d; },
190
- [](const str &s) -> AttributeValue {
191
- // if (s.empty()) return std::monostate{};
192
- return fwStr{s};
193
- },
194
-
195
- [](const std::vector<glz::raw_json> &json_vec) -> AttributeValue {
196
- auto out = std::make_unique<std::vector<fwStr> >();
197
- out->reserve(json_vec.size());
198
- for (auto &r: json_vec)
199
- if (!r.str.empty())
200
- out->emplace_back(r.str);
201
- // if (out->empty()) {
202
- // return std::monostate{};
203
- // }
204
- out->shrink_to_fit();
205
- return out;
206
- },
207
- [](const std::optional<glz::raw_json> &o) -> AttributeValue {
208
- // if (!o.has_value() || o->str.empty()) return std::monostate{};
209
- return fwStr{o->str};
210
- },
189
+ [](bool b) -> AttributeValue { return b; },
190
+ [](double d) -> AttributeValue { return d; },
191
+ [](const str &s) -> AttributeValue {
192
+ // if (s.empty()) return std::monostate{};
193
+ return fwStr{s};
194
+ },
195
+
196
+ [](const std::vector<glz::raw_json> &json_vec) -> AttributeValue {
197
+ auto out = std::make_unique<std::vector<fwStr>>();
198
+ out->reserve(json_vec.size());
199
+ for (auto &r: json_vec)
200
+ if (!r.str.empty())
201
+ out->emplace_back(r.str);
202
+ // if (out->empty()) {
203
+ // return std::monostate{};
204
+ // }
205
+ out->shrink_to_fit();
206
+ return out;
207
+ },
208
+ [](const std::optional<glz::raw_json> &o) -> AttributeValue {
209
+ // if (!o.has_value() || o->str.empty()) return std::monostate{};
210
+ return fwStr{o->str};
211
+ },
211
212
 
212
213
  },
213
214
  src);
@@ -216,17 +217,17 @@ public:
216
217
 
217
218
  static pyAttrValue convert_valueJ(const json::AttributeValue &src) {
218
219
  return std::visit(overloaded{
219
- [](std::monostate b) -> pyAttrValue { return b; },
220
- [](bool b) -> pyAttrValue { return b; },
221
- [](double d) -> pyAttrValue { return d; },
222
- [](const str &s) -> pyAttrValue { return s; },
223
- [](const std::vector<glz::raw_json> &json_vec) -> pyAttrValue {
224
- return json_vec | std::views::transform([](const glz::raw_json &j) -> str {
225
- return j.str;
226
- }) |
227
- std::ranges::to<strVec>();
228
- },
229
- [](const std::optional<glz::raw_json> &o) -> pyAttrValue { return o ? o->str : ""; },
220
+ [](std::monostate b) -> pyAttrValue { return b; },
221
+ [](bool b) -> pyAttrValue { return b; },
222
+ [](double d) -> pyAttrValue { return d; },
223
+ [](const str &s) -> pyAttrValue { return s; },
224
+ [](const std::vector<glz::raw_json> &json_vec) -> pyAttrValue {
225
+ return json_vec | std::views::transform([](const glz::raw_json &j) -> str {
226
+ return j.str;
227
+ }) |
228
+ std::ranges::to<strVec>();
229
+ },
230
+ [](const std::optional<glz::raw_json> &o) -> pyAttrValue { return o ? o->str : ""; },
230
231
 
231
232
  },
232
233
  src);
@@ -234,54 +235,54 @@ public:
234
235
 
235
236
  static pyAttrValue convert_value(const AttributeValue &src) {
236
237
  return std::visit(overloaded{
237
- [](std::monostate b) -> pyAttrValue { return b; },
238
- [](bool b) -> pyAttrValue { return b; },
239
- [](double d) -> pyAttrValue { return d; },
240
- [](const fwStr &s) -> pyAttrValue { return s; },
241
- [](const strVecUPtr &fw_vec) -> pyAttrValue {
242
- return *fw_vec | std::views::transform([](const fwStr &s) -> str { return s; }) |
243
- std::ranges::to<strVec>();
244
- },
238
+ [](std::monostate b) -> pyAttrValue { return b; },
239
+ [](bool b) -> pyAttrValue { return b; },
240
+ [](double d) -> pyAttrValue { return d; },
241
+ [](const fwStr &s) -> pyAttrValue { return s; },
242
+ [](const strVecUPtr &fw_vec) -> pyAttrValue {
243
+ return *fw_vec | std::views::transform([](const fwStr &s) -> str { return s; }) |
244
+ std::ranges::to<strVec>();
245
+ },
245
246
  },
246
247
  src);
247
248
  }
248
249
 
249
250
  static AttributeValue convert_value(const pyAttrValue &src) {
250
251
  return std::visit(overloaded{
251
- [](std::monostate b) -> AttributeValue { return b; },
252
- [](bool b) -> AttributeValue { return b; },
253
- [](double d) -> AttributeValue { return d; },
254
- [](const str &s) -> AttributeValue { return fwStr{s}; },
255
- [](const strVec &vec) -> AttributeValue {
256
- auto out = std::make_unique<std::vector<fwStr> >();
257
- out->reserve(vec.size());
258
- for (auto &r: vec) {
259
- out->emplace_back(r);
260
- }
261
- out->shrink_to_fit();
262
- return out;
263
- },
252
+ [](std::monostate b) -> AttributeValue { return b; },
253
+ [](bool b) -> AttributeValue { return b; },
254
+ [](double d) -> AttributeValue { return d; },
255
+ [](const str &s) -> AttributeValue { return fwStr{s}; },
256
+ [](const strVec &vec) -> AttributeValue {
257
+ auto out = std::make_unique<std::vector<fwStr>>();
258
+ out->reserve(vec.size());
259
+ for (auto &r: vec) {
260
+ out->emplace_back(r);
261
+ }
262
+ out->shrink_to_fit();
263
+ return out;
264
+ },
264
265
  },
265
266
  src);
266
267
  }
267
268
 
268
269
  static str to_string(const pyAttrValue &src) {
269
270
  return std::visit(overloaded{
270
- [](std::monostate) -> str { return "null"; },
271
- [](bool b) -> str { return b ? "true" : "false"; },
272
- [](double d) -> str { return std::to_string(d); },
273
- [](const str &s) -> str { return s; },
274
-
275
- [](const strVec &vecptr) -> str {
276
- str out = "[";
277
-
278
- for (auto &r: vecptr) {
279
- out.append(r);
280
- out.append(",");
281
- }
282
- out.append("]");
283
- return out;
284
- },
271
+ [](std::monostate) -> str { return "null"; },
272
+ [](bool b) -> str { return b ? "true" : "false"; },
273
+ [](double d) -> str { return std::to_string(d); },
274
+ [](const str &s) -> str { return s; },
275
+
276
+ [](const strVec &vecptr) -> str {
277
+ str out = "[";
278
+
279
+ for (auto &r: vecptr) {
280
+ out.append(r);
281
+ out.append(",");
282
+ }
283
+ out.append("]");
284
+ return out;
285
+ },
285
286
  },
286
287
  src);
287
288
  }
@@ -295,7 +296,7 @@ public:
295
296
  increaseIteratorVersion();
296
297
  }
297
298
 
298
- std::vector<pyAttrValue> get(const str &id, const strVec &attributes) {
299
+ std::vector<pyAttrValue> get_one(const str &id, const strVec &attributes) {
299
300
  if (attributes.empty()) {
300
301
  return {};
301
302
  }
@@ -311,41 +312,49 @@ public:
311
312
  return {};
312
313
  return convert_value(*attr_value);
313
314
  }) |
314
- std::ranges::to<std::vector<pyAttrValue> >();
315
+ std::ranges::to<std::vector<pyAttrValue>>();
315
316
  }
316
317
  return {};
317
318
  }
318
319
 
319
-
320
- struct getAllResponse {
320
+ struct getManyResponse {
321
321
  uint64_t iterator_version{};
322
322
  uint64_t iterator{};
323
- std::vector<std::pair<str, std::vector<pyAttrValue> > > result{};
323
+ std::vector<std::pair<str, std::vector<pyAttrValue>>> result{};
324
324
  };
325
325
 
326
- str get_all(const strVec &attributes, uint64_t per_iteration = 10000, uint64_t iterator_version = 0,
327
- uint64_t iterator = 0) {
326
+ str get_many(const strVec &ids, const strVec &attributes, uint64_t per_iteration = 10000,
327
+ uint64_t iterator_version = 0, uint64_t iterator = 0) {
328
328
  if (transactionOpened)
329
- throw std::runtime_error("Can't get all when transaction is opened");
329
+ throw std::runtime_error("Can't get many when transaction is opened");
330
330
  if (iterator && iterator_version == 0) {
331
331
  throw std::runtime_error("Invalid iterator version");
332
332
  }
333
333
  if (iterator && iterator_version != this->iterator_version)
334
334
  throw std::runtime_error("Iterator already invalidated");
335
- getAllResponse resp{};
336
- std::vector<str> keys = cache | std::views::keys | std::ranges::to<std::vector>();
335
+ getManyResponse resp{};
336
+ std::vector<str> keys;
337
+ if (ids.empty()) {
338
+ keys = cache | std::views::keys | std::ranges::to<std::vector>();
339
+ std::ranges::sort(keys);
340
+ } else {
341
+ absl::flat_hash_set<str> set_of_ids(ids.begin(), ids.end());
342
+ keys = cache | std::views::keys |
343
+ std::views::filter([&](const auto &key) { return set_of_ids.contains(key); }) |
344
+ std::ranges::to<std::vector>();
345
+ }
337
346
  std::ranges::sort(keys);
338
347
 
339
- uint64_t start = iterator;
340
- uint64_t available = keys.size() > start ? keys.size() - start : 0;
341
- uint64_t to_take = std::min<uint64_t>(available, per_iteration);
348
+ const uint64_t start = iterator;
349
+ const uint64_t available = keys.size() > start ? keys.size() - start : 0;
350
+ const uint64_t to_take = std::min<uint64_t>(available, per_iteration);
342
351
 
343
352
  resp.result.reserve(to_take);
344
353
 
345
354
  auto i = iterator;
346
355
  while (i < iterator + per_iteration && i < keys.size()) {
347
356
  const auto &key = keys[i];
348
- resp.result.emplace_back(key, get(key, attributes));
357
+ resp.result.emplace_back(key, get_one(key, attributes));
349
358
  i++;
350
359
  }
351
360
  resp.iterator_version = this->iterator_version;
@@ -354,7 +363,7 @@ public:
354
363
  }
355
364
 
356
365
 
357
- void begin_transaction(uint64_t estimated_number_of_items = 0) {
366
+ void begin_transaction(uint64_t estimated_number_of_items = 0, bool remove_old_items = true) {
358
367
  if (transactionOpened) {
359
368
  throw std::runtime_error("Transaction already open");
360
369
  }
@@ -364,6 +373,7 @@ public:
364
373
  }
365
374
  oldCacheSize = cache.size();
366
375
  transactionOpened = true;
376
+ transactionShouldRemoveOldItems = remove_old_items;
367
377
  }
368
378
 
369
379
  void end_transaction() {
@@ -375,11 +385,16 @@ public:
375
385
  it.value().isNew = false;
376
386
  ++it;
377
387
  } else {
378
- it = cache.erase(it);
388
+ if (transactionShouldRemoveOldItems) {
389
+ it = cache.erase(it);
390
+ } else {
391
+ ++it;
392
+ }
379
393
  }
380
394
  }
381
395
  increaseIteratorVersion();
382
396
  transactionOpened = false;
397
+ transactionShouldRemoveOldItems = true;
383
398
  }
384
399
 
385
400
  size_t load_page(const str &json_text) {
@@ -408,11 +423,12 @@ public:
408
423
  }
409
424
 
410
425
  tsl::sparse_map<str, MarkedItem> cache;
411
- absl::flat_hash_map<str, uint8_t, absl::Hash<str> > attrMap;
426
+ absl::flat_hash_map<str, uint8_t, absl::Hash<str>> attrMap;
412
427
  strVec attrIdx;
413
428
  const uint8_t numberOfAttributes;
414
429
  size_t oldCacheSize = 0;
415
430
  bool transactionOpened = false;
431
+ bool transactionShouldRemoveOldItems = true;
416
432
  uint64_t iterator_version = 1; // for get_all()
417
433
  };
418
434
 
@@ -421,11 +437,13 @@ NB_MODULE(_small_cache_impl, m) {
421
437
  nb::class_<SmallCache> cache(m, "SmallCache");
422
438
  cache
423
439
  .def(nb::init<std::vector<std::string> >(), nb::arg("attribute_names"))
424
- .def("begin_transaction", &SmallCache::begin_transaction, nb::arg("estimated_number_of_items") = 0)
440
+ .def("begin_transaction", &SmallCache::begin_transaction,
441
+ nb::arg("estimated_number_of_items") = 0,
442
+ nb::arg("remove_old_items") = true)
425
443
  .def("end_transaction", &SmallCache::end_transaction)
426
444
  .def("add", &SmallCache::add_item, nb::arg("item_id"), nb::arg("attributes"))
427
- .def("get", &SmallCache::get, nb::arg("id"), nb::arg("attributes"))
428
- .def("get_all", &SmallCache::get_all, nb::arg("attributes"), nb::arg("per_iteration") = 10000,
445
+ .def("get_one", &SmallCache::get_one, nb::arg("id"), nb::arg("attributes"))
446
+ .def("get_many", &SmallCache::get_many, nb::arg("ids"), nb::arg("attributes"), nb::arg("per_iteration") = 10000,
429
447
  nb::arg("iterator_version") = 0,
430
448
  nb::arg("iterator") = 0)
431
449
  .def("load_page", &SmallCache::load_page, nb::arg("json_text"));
File without changes
File without changes