timestamp-store 1.0.0__py3-none-any.whl

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.
@@ -0,0 +1,18 @@
1
+ """
2
+ TimestampStore - fast data structure for pairs (id, timestamp)
3
+
4
+ Usage example:
5
+ from timestamp_store import TimestampStore
6
+
7
+ store = TimestampStore()
8
+ store.add(1, 100)
9
+ store.add(2, 50)
10
+
11
+ removed = store.remove_timestamp(80) # [2]
12
+ removed = store.remove_timestamp(120) # [1]
13
+ """
14
+
15
+ from .wrapper import TimestampStore
16
+
17
+ __version__ = "1.0.0"
18
+ __all__ = ["TimestampStore"]
@@ -0,0 +1,203 @@
1
+ #include <map>
2
+ #include <unordered_map>
3
+ #include <unordered_set>
4
+ #include <vector>
5
+ #include <cstdint>
6
+ #include <algorithm>
7
+
8
+ class TimestampStore {
9
+ private:
10
+ std::map<int64_t, std::unordered_set<int64_t>> time_to_ids_;
11
+
12
+ std::unordered_map<int64_t, int64_t> id_to_time_;
13
+
14
+ public:
15
+ TimestampStore() = default;
16
+
17
+ void add(int64_t id, int64_t timestamp) {
18
+ auto it = id_to_time_.find(id);
19
+
20
+ if (it != id_to_time_.end()) {
21
+ int64_t old_time = it->second;
22
+
23
+ if (old_time == timestamp) {
24
+ return;
25
+ }
26
+
27
+ auto old_time_it = time_to_ids_.find(old_time);
28
+ if (old_time_it != time_to_ids_.end()) {
29
+ old_time_it->second.erase(id);
30
+ if (old_time_it->second.empty()) {
31
+ time_to_ids_.erase(old_time_it);
32
+ }
33
+ }
34
+
35
+ it->second = timestamp;
36
+ } else {
37
+ id_to_time_[id] = timestamp;
38
+ }
39
+
40
+ time_to_ids_[timestamp].insert(id);
41
+ }
42
+
43
+ bool remove(int64_t id) {
44
+ auto it = id_to_time_.find(id);
45
+ if (it == id_to_time_.end()) {
46
+ return false;
47
+ }
48
+
49
+ int64_t timestamp = it->second;
50
+ id_to_time_.erase(it);
51
+
52
+ auto time_it = time_to_ids_.find(timestamp);
53
+ if (time_it != time_to_ids_.end()) {
54
+ time_it->second.erase(id);
55
+ if (time_it->second.empty()) {
56
+ time_to_ids_.erase(time_it);
57
+ }
58
+ }
59
+
60
+ return true;
61
+ }
62
+
63
+ std::vector<int64_t> remove_before_timestamp(int64_t timestamp) {
64
+ std::vector<int64_t> removed_ids;
65
+
66
+ while (!time_to_ids_.empty()) {
67
+ auto it = time_to_ids_.begin();
68
+
69
+ if (it->first >= timestamp) {
70
+ break;
71
+ }
72
+
73
+ for (int64_t id : it->second) {
74
+ removed_ids.push_back(id);
75
+ id_to_time_.erase(id);
76
+ }
77
+
78
+ time_to_ids_.erase(it);
79
+ }
80
+
81
+ return removed_ids;
82
+ }
83
+
84
+ size_t size() const {
85
+ return id_to_time_.size();
86
+ }
87
+
88
+ bool empty() const {
89
+ return id_to_time_.empty();
90
+ }
91
+
92
+ int64_t get_min_timestamp() const {
93
+ if (time_to_ids_.empty()) {
94
+ return -1;
95
+ }
96
+ return time_to_ids_.begin()->first;
97
+ }
98
+
99
+ bool contains(int64_t id) const {
100
+ return id_to_time_.count(id) > 0;
101
+ }
102
+
103
+ int64_t get_timestamp(int64_t id) const {
104
+ auto it = id_to_time_.find(id);
105
+ if (it == id_to_time_.end()) {
106
+ return -1;
107
+ }
108
+ return it->second;
109
+ }
110
+ };
111
+
112
+
113
+ // ============================================================================
114
+ // C API ctypes
115
+ // ============================================================================
116
+
117
+ #ifdef _WIN32
118
+ #define EXPORT extern "C" __declspec(dllexport)
119
+ #else
120
+ #define EXPORT extern "C" __attribute__((visibility("default")))
121
+ #endif
122
+
123
+ EXPORT TimestampStore* ts_create() {
124
+ return new TimestampStore();
125
+ }
126
+
127
+ EXPORT TimestampStore* ts_create_from_arrays(
128
+ const int64_t* ids,
129
+ const int64_t* timestamps,
130
+ int64_t count
131
+ ) {
132
+ TimestampStore* store = new TimestampStore();
133
+ for (int64_t i = 0; i < count; ++i) {
134
+ store->add(ids[i], timestamps[i]);
135
+ }
136
+ return store;
137
+ }
138
+
139
+ EXPORT void ts_destroy(TimestampStore* store) {
140
+ delete store;
141
+ }
142
+
143
+ EXPORT void ts_add(TimestampStore* store, int64_t id, int64_t timestamp) {
144
+ if (store) {
145
+ store->add(id, timestamp);
146
+ }
147
+ }
148
+
149
+ EXPORT int32_t ts_remove(TimestampStore* store, int64_t id) {
150
+ if (!store) return 0;
151
+ return store->remove(id) ? 1 : 0;
152
+ }
153
+
154
+ EXPORT int64_t* ts_remove_before_timestamp(
155
+ TimestampStore* store,
156
+ int64_t timestamp,
157
+ int64_t* out_size
158
+ ) {
159
+ if (!store || !out_size) {
160
+ if (out_size) *out_size = 0;
161
+ return nullptr;
162
+ }
163
+
164
+ std::vector<int64_t> result = store->remove_before_timestamp(timestamp);
165
+ *out_size = static_cast<int64_t>(result.size());
166
+
167
+ if (result.empty()) {
168
+ return nullptr;
169
+ }
170
+
171
+ int64_t* arr = new int64_t[result.size()];
172
+ std::copy(result.begin(), result.end(), arr);
173
+ return arr;
174
+ }
175
+
176
+ EXPORT void ts_free_array(int64_t* arr) {
177
+ delete[] arr;
178
+ }
179
+
180
+ EXPORT int64_t ts_size(TimestampStore* store) {
181
+ if (!store) return 0;
182
+ return static_cast<int64_t>(store->size());
183
+ }
184
+
185
+ EXPORT int32_t ts_empty(TimestampStore* store) {
186
+ if (!store) return 1;
187
+ return store->empty() ? 1 : 0;
188
+ }
189
+
190
+ EXPORT int64_t ts_get_min_timestamp(TimestampStore* store) {
191
+ if (!store) return -1;
192
+ return store->get_min_timestamp();
193
+ }
194
+
195
+ EXPORT int32_t ts_contains(TimestampStore* store, int64_t id) {
196
+ if (!store) return 0;
197
+ return store->contains(id) ? 1 : 0;
198
+ }
199
+
200
+ EXPORT int64_t ts_get_timestamp(TimestampStore* store, int64_t id) {
201
+ if (!store) return -1;
202
+ return store->get_timestamp(id);
203
+ }
Binary file
@@ -0,0 +1,175 @@
1
+ import ctypes
2
+ import platform
3
+ from pathlib import Path
4
+ from typing import List, Tuple, Optional, Union, Dict
5
+
6
+ class TimestampStore:
7
+ _lib: ctypes.CDLL = None
8
+ _lib_path: str = None
9
+
10
+ @classmethod
11
+ def _get_lib_name(cls) -> str:
12
+ system = platform.system()
13
+ if system == "Windows":
14
+ return "timestamp_store.dll"
15
+ elif system == "Darwin":
16
+ return "libtimestamp_store.dylib"
17
+ else:
18
+ return "libtimestamp_store.so"
19
+
20
+ @classmethod
21
+ def _find_library(cls) -> str:
22
+ lib_name = cls._get_lib_name()
23
+
24
+ search_paths = [
25
+ Path(__file__).parent / lib_name,
26
+ Path(__file__).parent / "src" / lib_name,
27
+ Path.cwd() / lib_name,
28
+ ]
29
+
30
+ for path in search_paths:
31
+ if path.exists():
32
+ return str(path)
33
+
34
+ raise FileNotFoundError(
35
+ f"Could not find {lib_name}. "
36
+ f"Searched in: {[str(p) for p in search_paths]}. "
37
+ f"Try reinstalling the package: pip install --force-reinstall git+https://github.com/shutkanos/timestamp_store.git"
38
+ )
39
+
40
+ @classmethod
41
+ def _load_library(cls, lib_path: Optional[str] = None) -> ctypes.CDLL:
42
+ if lib_path is None:
43
+ lib_path = cls._find_library()
44
+
45
+ if cls._lib is not None and cls._lib_path == lib_path:
46
+ return cls._lib
47
+
48
+ lib = ctypes.CDLL(lib_path)
49
+
50
+ lib.ts_create.restype = ctypes.c_void_p
51
+ lib.ts_create.argtypes = []
52
+
53
+ lib.ts_create_from_arrays.restype = ctypes.c_void_p
54
+ lib.ts_create_from_arrays.argtypes = [
55
+ ctypes.POINTER(ctypes.c_int64),
56
+ ctypes.POINTER(ctypes.c_int64),
57
+ ctypes.c_int64
58
+ ]
59
+
60
+ lib.ts_destroy.restype = None
61
+ lib.ts_destroy.argtypes = [ctypes.c_void_p]
62
+
63
+ lib.ts_add.restype = None
64
+ lib.ts_add.argtypes = [ctypes.c_void_p, ctypes.c_int64, ctypes.c_int64]
65
+
66
+ lib.ts_remove.restype = ctypes.c_int32
67
+ lib.ts_remove.argtypes = [ctypes.c_void_p, ctypes.c_int64]
68
+
69
+ lib.ts_remove_before_timestamp.restype = ctypes.POINTER(ctypes.c_int64)
70
+ lib.ts_remove_before_timestamp.argtypes = [
71
+ ctypes.c_void_p,
72
+ ctypes.c_int64,
73
+ ctypes.POINTER(ctypes.c_int64)
74
+ ]
75
+
76
+ lib.ts_free_array.restype = None
77
+ lib.ts_free_array.argtypes = [ctypes.POINTER(ctypes.c_int64)]
78
+
79
+ lib.ts_size.restype = ctypes.c_int64
80
+ lib.ts_size.argtypes = [ctypes.c_void_p]
81
+
82
+ lib.ts_empty.restype = ctypes.c_int32
83
+ lib.ts_empty.argtypes = [ctypes.c_void_p]
84
+
85
+ lib.ts_get_min_timestamp.restype = ctypes.c_int64
86
+ lib.ts_get_min_timestamp.argtypes = [ctypes.c_void_p]
87
+
88
+ lib.ts_contains.restype = ctypes.c_int32
89
+ lib.ts_contains.argtypes = [ctypes.c_void_p, ctypes.c_int64]
90
+
91
+ lib.ts_get_timestamp.restype = ctypes.c_int64
92
+ lib.ts_get_timestamp.argtypes = [ctypes.c_void_p, ctypes.c_int64]
93
+
94
+ cls._lib = lib
95
+ cls._lib_path = lib_path
96
+ return lib
97
+
98
+ def __init__(self, data: Optional[Union[List[Tuple[int, int]], Dict[int, int]]] = None, *, lib_path: Optional[str] = None):
99
+ self._lib_instance = self._load_library(lib_path)
100
+
101
+ if data is None:
102
+ self._store = self._lib_instance.ts_create()
103
+ else:
104
+ if isinstance(data, dict):
105
+ pairs = list(data.items())
106
+ else:
107
+ pairs = list(data)
108
+
109
+ if not pairs:
110
+ self._store = self._lib_instance.ts_create()
111
+ else:
112
+ n = len(pairs)
113
+ ids_array = (ctypes.c_int64 * n)()
114
+ timestamps_array = (ctypes.c_int64 * n)()
115
+
116
+ for i, (id_val, ts_val) in enumerate(pairs):
117
+ ids_array[i] = id_val
118
+ timestamps_array[i] = ts_val
119
+
120
+ self._store = self._lib_instance.ts_create_from_arrays(
121
+ ids_array, timestamps_array, n
122
+ )
123
+
124
+ if not self._store:
125
+ raise MemoryError("Failed to create TimestampStore")
126
+
127
+ def __del__(self):
128
+ if hasattr(self, '_store') and self._store and hasattr(self, '_lib_instance'):
129
+ self._lib_instance.ts_destroy(self._store)
130
+ self._store = None
131
+
132
+ def add(self, id: int, timestamp: int) -> None:
133
+ self._lib_instance.ts_add(self._store, id, timestamp)
134
+
135
+ def remove(self, id: int) -> bool:
136
+ return bool(self._lib_instance.ts_remove(self._store, id))
137
+
138
+ def remove_timestamp(self, timestamp: int) -> List[int]:
139
+ """
140
+ Delete all elements with a timestamp value less than the specified argument
141
+ :return: list of deleted IDs.
142
+ """
143
+ size = ctypes.c_int64(0)
144
+ arr_ptr = self._lib_instance.ts_remove_before_timestamp(
145
+ self._store,
146
+ timestamp,
147
+ ctypes.byref(size)
148
+ )
149
+
150
+ if size.value == 0 or not arr_ptr:
151
+ return []
152
+
153
+ try:
154
+ result = [arr_ptr[i] for i in range(size.value)]
155
+ finally:
156
+ self._lib_instance.ts_free_array(arr_ptr)
157
+
158
+ return result
159
+
160
+ def get_timestamp(self, id: int) -> Optional[int]:
161
+ ts = self._lib_instance.ts_get_timestamp(self._store, id)
162
+ return ts if ts >= 0 else None
163
+
164
+ def get_min_timestamp(self) -> Optional[int]:
165
+ ts = self._lib_instance.ts_get_min_timestamp(self._store)
166
+ return ts if ts >= 0 else None
167
+
168
+ def __len__(self) -> int:
169
+ return self._lib_instance.ts_size(self._store)
170
+
171
+ def __bool__(self) -> bool:
172
+ return not self._lib_instance.ts_empty(self._store)
173
+
174
+ def __contains__(self, id: int) -> bool:
175
+ return bool(self._lib_instance.ts_contains(self._store, id))
@@ -0,0 +1,93 @@
1
+ Metadata-Version: 2.4
2
+ Name: timestamp-store
3
+ Version: 1.0.0
4
+ Summary: Fast timestamp-based data structure with O(log N) operations
5
+ Home-page: https://github.com/shutkanos/timestamp_store
6
+ Author: Shutkanos
7
+ Author-email: Shutkanos <Shutkanos836926@mail.ru>
8
+ License: MIT
9
+ Project-URL: Homepage, https://github.com/shutkanos/timestamp_store
10
+ Project-URL: Repository, https://github.com/shutkanos/timestamp_store
11
+ Keywords: timestamp,data-structure,ctypes
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.7
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Programming Language :: C++
25
+ Classifier: Operating System :: OS Independent
26
+ Requires-Python: >=3.7
27
+ Description-Content-Type: text/markdown
28
+ License-File: LICENSE
29
+ Dynamic: author
30
+ Dynamic: home-page
31
+ Dynamic: license-file
32
+ Dynamic: requires-python
33
+
34
+ # TimestampStore
35
+
36
+ Fast data structure for (id, timestamp) pairs with O(log N) operations.
37
+ Warning! Created by claude-opus-4.5 without human intervention.
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pip install git+https://github.com/shutkanos/timestamp_store.git
43
+ ```
44
+
45
+ **Requirements:** C++ compiler (g++, clang++, or MSVC)
46
+
47
+ ### Installing compiler
48
+
49
+ - **Ubuntu/Debian:** `sudo apt install g++`
50
+ - **macOS:** `xcode-select --install`
51
+ - **Windows:** Install [Visual Studio Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) or:
52
+
53
+ PowerShell:
54
+ ```PowerShell
55
+ winget install -e --id MSYS2.MSYS2
56
+ ```
57
+ MSYS2:
58
+ ```
59
+ pacman -S mingw-w64-x86_64-gcc
60
+ ```
61
+
62
+ ## Usage
63
+
64
+ ```python
65
+ from timestamp_store import TimestampStore
66
+
67
+ store = TimestampStore()
68
+
69
+ # Add pairs
70
+ store.add(1, 100)
71
+ store.add(2, 50)
72
+ store.add(3, 150)
73
+
74
+ # Remove all with timestamp < 120
75
+ removed = store.remove_timestamp(120)
76
+ print(removed) # [2, 1]
77
+
78
+ # Remove by id
79
+ store.remove(3)
80
+
81
+ # Create from list
82
+ store = TimestampStore([(1, 100), (2, 200)])
83
+ # Create from dict
84
+ store = TimestampStore({1: 100, 2: 200})
85
+ ```
86
+
87
+ ## Complexity
88
+
89
+ | Operation | Complexity |
90
+ |-----------|------------|
91
+ | `add(id, timestamp)` | O(log N) |
92
+ | `remove(id)` | O(log N) |
93
+ | `remove_timestamp(ts)` | O(K) where K = removed count |
@@ -0,0 +1,9 @@
1
+ timestamp_store/__init__.py,sha256=TGRhO4_Fs0QnCgx6jYLlbIsuv0I7vMjVUqKspdbp32Q,409
2
+ timestamp_store/timestamp_store.dll,sha256=SgRDJZ6UGQmUh2WLtEDriXyDEF3kEmBX1CNNm232SmY,731228
3
+ timestamp_store/wrapper.py,sha256=xuoPlaVgl19DQcJbvmmnoqPRhsBnTaTxrLqgw-hbZsA,5935
4
+ timestamp_store/src/timestamp_store.cpp,sha256=cxu0BDutMk498rR1MGB0KF-d6fP0oWztLTx0M4B-y1s,5038
5
+ timestamp_store-1.0.0.dist-info/licenses/LICENSE,sha256=K7_kNJPZ5f_96bFuI_3LzOuIigXOx8q4pA9Z5sZ18Pc,1086
6
+ timestamp_store-1.0.0.dist-info/METADATA,sha256=IE_k9DKNRoeAM9qLhKdcWsC-zToHHihJ6hLLSgZgwc8,2632
7
+ timestamp_store-1.0.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
8
+ timestamp_store-1.0.0.dist-info/top_level.txt,sha256=SYxzkaPTIfm4d0Zbo6qSNINe6kIhTwc_HxmKHEENTdY,16
9
+ timestamp_store-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shutkanos
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ timestamp_store