pyxcp 0.25.4__cp313-cp313-win_amd64.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.
Files changed (157) hide show
  1. pyxcp/__init__.py +20 -0
  2. pyxcp/aml/EtasCANMonitoring.a2l +82 -0
  3. pyxcp/aml/EtasCANMonitoring.aml +67 -0
  4. pyxcp/aml/XCP_Common.aml +408 -0
  5. pyxcp/aml/XCPonCAN.aml +78 -0
  6. pyxcp/aml/XCPonEth.aml +33 -0
  7. pyxcp/aml/XCPonFlx.aml +113 -0
  8. pyxcp/aml/XCPonSxI.aml +66 -0
  9. pyxcp/aml/XCPonUSB.aml +106 -0
  10. pyxcp/aml/ifdata_CAN.a2l +20 -0
  11. pyxcp/aml/ifdata_Eth.a2l +11 -0
  12. pyxcp/aml/ifdata_Flx.a2l +94 -0
  13. pyxcp/aml/ifdata_SxI.a2l +13 -0
  14. pyxcp/aml/ifdata_USB.a2l +81 -0
  15. pyxcp/asam/__init__.py +0 -0
  16. pyxcp/asam/types.py +131 -0
  17. pyxcp/asamkeydll.c +116 -0
  18. pyxcp/asamkeydll.exe +0 -0
  19. pyxcp/asamkeydll.sh +2 -0
  20. pyxcp/checksum.py +732 -0
  21. pyxcp/cmdline.py +71 -0
  22. pyxcp/config/__init__.py +1257 -0
  23. pyxcp/config/legacy.py +120 -0
  24. pyxcp/constants.py +47 -0
  25. pyxcp/cpp_ext/__init__.py +0 -0
  26. pyxcp/cpp_ext/aligned_buffer.hpp +168 -0
  27. pyxcp/cpp_ext/bin.hpp +105 -0
  28. pyxcp/cpp_ext/blockmem.hpp +58 -0
  29. pyxcp/cpp_ext/cpp_ext.cp310-win_amd64.pyd +0 -0
  30. pyxcp/cpp_ext/cpp_ext.cp311-win_amd64.pyd +0 -0
  31. pyxcp/cpp_ext/cpp_ext.cp312-win_amd64.pyd +0 -0
  32. pyxcp/cpp_ext/cpp_ext.cp313-win_amd64.pyd +0 -0
  33. pyxcp/cpp_ext/daqlist.hpp +374 -0
  34. pyxcp/cpp_ext/event.hpp +67 -0
  35. pyxcp/cpp_ext/extension_wrapper.cpp +131 -0
  36. pyxcp/cpp_ext/framing.hpp +360 -0
  37. pyxcp/cpp_ext/helper.hpp +280 -0
  38. pyxcp/cpp_ext/mcobject.hpp +248 -0
  39. pyxcp/cpp_ext/sxi_framing.hpp +332 -0
  40. pyxcp/cpp_ext/tsqueue.hpp +46 -0
  41. pyxcp/daq_stim/__init__.py +291 -0
  42. pyxcp/daq_stim/optimize/__init__.py +67 -0
  43. pyxcp/daq_stim/optimize/binpacking.py +41 -0
  44. pyxcp/daq_stim/scheduler.cpp +62 -0
  45. pyxcp/daq_stim/scheduler.hpp +75 -0
  46. pyxcp/daq_stim/stim.cp310-win_amd64.pyd +0 -0
  47. pyxcp/daq_stim/stim.cp311-win_amd64.pyd +0 -0
  48. pyxcp/daq_stim/stim.cp312-win_amd64.pyd +0 -0
  49. pyxcp/daq_stim/stim.cp313-win_amd64.pyd +0 -0
  50. pyxcp/daq_stim/stim.cpp +13 -0
  51. pyxcp/daq_stim/stim.hpp +604 -0
  52. pyxcp/daq_stim/stim_wrapper.cpp +50 -0
  53. pyxcp/dllif.py +100 -0
  54. pyxcp/errormatrix.py +878 -0
  55. pyxcp/examples/conf_can.toml +19 -0
  56. pyxcp/examples/conf_can_user.toml +16 -0
  57. pyxcp/examples/conf_can_vector.json +11 -0
  58. pyxcp/examples/conf_can_vector.toml +11 -0
  59. pyxcp/examples/conf_eth.toml +9 -0
  60. pyxcp/examples/conf_nixnet.json +20 -0
  61. pyxcp/examples/conf_socket_can.toml +12 -0
  62. pyxcp/examples/run_daq.py +165 -0
  63. pyxcp/examples/xcp_policy.py +60 -0
  64. pyxcp/examples/xcp_read_benchmark.py +38 -0
  65. pyxcp/examples/xcp_skel.py +48 -0
  66. pyxcp/examples/xcp_unlock.py +36 -0
  67. pyxcp/examples/xcp_user_supplied_driver.py +43 -0
  68. pyxcp/examples/xcphello.py +65 -0
  69. pyxcp/examples/xcphello_recorder.py +107 -0
  70. pyxcp/master/__init__.py +10 -0
  71. pyxcp/master/errorhandler.py +677 -0
  72. pyxcp/master/master.py +2641 -0
  73. pyxcp/py.typed +0 -0
  74. pyxcp/recorder/.idea/.gitignore +8 -0
  75. pyxcp/recorder/.idea/misc.xml +4 -0
  76. pyxcp/recorder/.idea/modules.xml +8 -0
  77. pyxcp/recorder/.idea/recorder.iml +6 -0
  78. pyxcp/recorder/.idea/sonarlint/issuestore/3/8/3808afc69ac1edb9d760000a2f137335b1b99728 +7 -0
  79. pyxcp/recorder/.idea/sonarlint/issuestore/9/a/9a2aa4db38d3115ed60da621e012c0efc0172aae +0 -0
  80. pyxcp/recorder/.idea/sonarlint/issuestore/b/4/b49006702b459496a8e8c94ebe60947108361b91 +0 -0
  81. pyxcp/recorder/.idea/sonarlint/issuestore/index.pb +7 -0
  82. pyxcp/recorder/.idea/sonarlint/securityhotspotstore/3/8/3808afc69ac1edb9d760000a2f137335b1b99728 +0 -0
  83. pyxcp/recorder/.idea/sonarlint/securityhotspotstore/9/a/9a2aa4db38d3115ed60da621e012c0efc0172aae +0 -0
  84. pyxcp/recorder/.idea/sonarlint/securityhotspotstore/b/4/b49006702b459496a8e8c94ebe60947108361b91 +0 -0
  85. pyxcp/recorder/.idea/sonarlint/securityhotspotstore/index.pb +7 -0
  86. pyxcp/recorder/.idea/vcs.xml +10 -0
  87. pyxcp/recorder/__init__.py +96 -0
  88. pyxcp/recorder/build_clang.cmd +1 -0
  89. pyxcp/recorder/build_clang.sh +2 -0
  90. pyxcp/recorder/build_gcc.cmd +1 -0
  91. pyxcp/recorder/build_gcc.sh +2 -0
  92. pyxcp/recorder/build_gcc_arm.sh +2 -0
  93. pyxcp/recorder/converter/__init__.py +444 -0
  94. pyxcp/recorder/lz4.c +2829 -0
  95. pyxcp/recorder/lz4.h +879 -0
  96. pyxcp/recorder/lz4hc.c +2041 -0
  97. pyxcp/recorder/lz4hc.h +413 -0
  98. pyxcp/recorder/mio.hpp +1714 -0
  99. pyxcp/recorder/reader.hpp +138 -0
  100. pyxcp/recorder/reco.py +278 -0
  101. pyxcp/recorder/recorder.rst +0 -0
  102. pyxcp/recorder/rekorder.cp310-win_amd64.pyd +0 -0
  103. pyxcp/recorder/rekorder.cp311-win_amd64.pyd +0 -0
  104. pyxcp/recorder/rekorder.cp312-win_amd64.pyd +0 -0
  105. pyxcp/recorder/rekorder.cp313-win_amd64.pyd +0 -0
  106. pyxcp/recorder/rekorder.cpp +59 -0
  107. pyxcp/recorder/rekorder.hpp +274 -0
  108. pyxcp/recorder/setup.py +41 -0
  109. pyxcp/recorder/test_reko.py +34 -0
  110. pyxcp/recorder/unfolder.hpp +1354 -0
  111. pyxcp/recorder/wrap.cpp +184 -0
  112. pyxcp/recorder/writer.hpp +302 -0
  113. pyxcp/scripts/__init__.py +0 -0
  114. pyxcp/scripts/pyxcp_probe_can_drivers.py +20 -0
  115. pyxcp/scripts/xcp_examples.py +64 -0
  116. pyxcp/scripts/xcp_fetch_a2l.py +40 -0
  117. pyxcp/scripts/xcp_id_scanner.py +18 -0
  118. pyxcp/scripts/xcp_info.py +159 -0
  119. pyxcp/scripts/xcp_profile.py +26 -0
  120. pyxcp/scripts/xmraw_converter.py +31 -0
  121. pyxcp/stim/__init__.py +0 -0
  122. pyxcp/tests/test_asam_types.py +24 -0
  123. pyxcp/tests/test_binpacking.py +186 -0
  124. pyxcp/tests/test_can.py +1324 -0
  125. pyxcp/tests/test_checksum.py +95 -0
  126. pyxcp/tests/test_daq.py +193 -0
  127. pyxcp/tests/test_daq_opt.py +426 -0
  128. pyxcp/tests/test_frame_padding.py +156 -0
  129. pyxcp/tests/test_framing.py +262 -0
  130. pyxcp/tests/test_master.py +2116 -0
  131. pyxcp/tests/test_transport.py +177 -0
  132. pyxcp/tests/test_utils.py +30 -0
  133. pyxcp/timing.py +60 -0
  134. pyxcp/transport/__init__.py +13 -0
  135. pyxcp/transport/base.py +484 -0
  136. pyxcp/transport/base_transport.hpp +0 -0
  137. pyxcp/transport/can.py +660 -0
  138. pyxcp/transport/eth.py +254 -0
  139. pyxcp/transport/hdf5_policy.py +129 -0
  140. pyxcp/transport/sxi.py +209 -0
  141. pyxcp/transport/transport_ext.cp310-win_amd64.pyd +0 -0
  142. pyxcp/transport/transport_ext.cp311-win_amd64.pyd +0 -0
  143. pyxcp/transport/transport_ext.cp312-win_amd64.pyd +0 -0
  144. pyxcp/transport/transport_ext.cp313-win_amd64.pyd +0 -0
  145. pyxcp/transport/transport_ext.hpp +214 -0
  146. pyxcp/transport/transport_wrapper.cpp +249 -0
  147. pyxcp/transport/usb_transport.py +229 -0
  148. pyxcp/types.py +987 -0
  149. pyxcp/utils/__init__.py +127 -0
  150. pyxcp/utils/cli.py +78 -0
  151. pyxcp/vector/__init__.py +0 -0
  152. pyxcp/vector/map.py +82 -0
  153. pyxcp-0.25.4.dist-info/METADATA +341 -0
  154. pyxcp-0.25.4.dist-info/RECORD +157 -0
  155. pyxcp-0.25.4.dist-info/WHEEL +4 -0
  156. pyxcp-0.25.4.dist-info/entry_points.txt +9 -0
  157. pyxcp-0.25.4.dist-info/licenses/LICENSE +165 -0
pyxcp/config/legacy.py ADDED
@@ -0,0 +1,120 @@
1
+ from collections import defaultdict
2
+
3
+ from traitlets.config import LoggingConfigurable
4
+ from traitlets.config.loader import Config
5
+
6
+
7
+ LEGACY_KEYWORDS = {
8
+ # General
9
+ "LOGLEVEL": "General.loglevel",
10
+ "DISABLE_ERROR_HANDLING": "General.disable_error_handling",
11
+ "SEED_N_KEY_DLL": "General.seed_n_key_dll",
12
+ "SEED_N_KEY_DLL_SAME_BIT_WIDTH": "General.seed_n_key_dll_same_bit_width",
13
+ "DISCONNECT_RESPONSE_OPTIONAL": "General.disconnect_response_optional",
14
+ # Transport
15
+ "TRANSPORT": "Transport.layer",
16
+ "CREATE_DAQ_TIMESTAMPS": "Transport.create_daq_timestamps",
17
+ "TIMEOUT": "Transport.timeout",
18
+ "ALIGNMENT": "Transport.alignment",
19
+ # Eth
20
+ "HOST": "Transport.Eth.host",
21
+ "PORT": "Transport.Eth.port",
22
+ "PROTOCOL": "Transport.Eth.protocol",
23
+ "IPV6": "Transport.Eth.ipv6",
24
+ "TCP_NODELAY": "Transport.Eth.tcp_nodelay",
25
+ # Usb
26
+ "SERIAL_NUMBER": "Transport.Usb.serial_number",
27
+ "CONFIGURATION_NUMBER": "Transport.Usb.configuration_number",
28
+ "INTERFACE_NUMBER": "Transport.Usb.interface_number",
29
+ "COMMAND_ENDPOINT_NUMBER": "Transport.Usb.out_ep_number",
30
+ "REPLY_ENDPOINT_NUMBER": "Transport.Usb.in_ep_number",
31
+ "VENDOR_ID": "Transport.Usb.vendor_id",
32
+ "PRODUCT_ID": "Transport.Usb.product_id",
33
+ "LIBRARY": "Transport.Usb.library",
34
+ # Can
35
+ "CAN_DRIVER": "Transport.Can.interface",
36
+ "CHANNEL": "Transport.Can.channel",
37
+ "MAX_DLC_REQUIRED": "Transport.Can.max_dlc_required",
38
+ # "MAX_CAN_FD_DLC": "Transport.Can.max_can_fd_dlc",
39
+ "PADDING_VALUE": "Transport.Can.padding_value",
40
+ "CAN_USE_DEFAULT_LISTENER": "Transport.Can.use_default_listener",
41
+ # Swap master and slave IDs. (s. https://github.com/christoph2/pyxcp/issues/130)
42
+ "CAN_ID_SLAVE": "Transport.Can.can_id_master",
43
+ "CAN_ID_MASTER": "Transport.Can.can_id_slave",
44
+ "CAN_ID_BROADCAST": "Transport.Can.can_id_broadcast",
45
+ "BITRATE": "Transport.Can.bitrate",
46
+ "RECEIVE_OWN_MESSAGES": "Transport.Can.receive_own_messages",
47
+ "POLL_INTERVAL": "Transport.Can.poll_interval",
48
+ "FD": "Transport.Can.fd",
49
+ "DATA_BITRATE": "Transport.Can.data_bitrate",
50
+ "ACCEPT_VIRTUAL": "Transport.Can.Kvaser.accept_virtual",
51
+ "SJW": "Transport.Can.sjw_abr",
52
+ "TSEG1": "Transport.Can.tseg1_abr",
53
+ "TSEG2": "Transport.Can.tseg2_abr",
54
+ "TTY_BAUDRATE": "Transport.Can.SlCan.ttyBaudrate",
55
+ "UNIQUE_HARDWARE_ID": "Transport.Can.Ixxat.unique_hardware_id",
56
+ "RX_FIFO_SIZE": "Transport.Can.Ixxat.rx_fifo_size",
57
+ "TX_FIFO_SIZE": "Transport.Can.Ixxat.tx_fifo_size",
58
+ "DRIVER_MODE": "Transport.Can.Kvaser.driver_mode",
59
+ "NO_SAMP": "Transport.Can.Kvaser.no_samp",
60
+ "SINGLE_HANDLE": "Transport.Can.Kvaser.single_handle",
61
+ "USE_SYSTEM_TIMESTAMP": "Transport.Can.Neovi.use_system_timestamp",
62
+ "OVERRIDE_LIBRARY_NAME": "Transport.Can.Neovi.override_library_name",
63
+ "BAUDRATE": "Transport.Can.Serial.baudrate",
64
+ "SLEEP_AFTER_OPEN": "Transport.Can.SlCan.sleep_after_open",
65
+ "DEVICE_NUMBER": "Transport.Can.Systec.device_number",
66
+ "RX_BUFFER_ENTRIES": "Transport.Can.Systec.rx_buffer_entries",
67
+ "TX_BUFFER_ENTRIES": "Transport.Can.Systec.tx_buffer_entries",
68
+ "FLAGS": "Transport.Can.Usb2Can.flags",
69
+ "APP_NAME": "Transport.Can.Vector.app_name",
70
+ "RX_QUEUE_SIZE": "Transport.Can.Vector.rx_queue_size",
71
+ }
72
+
73
+
74
+ def nested_dict_update(d: dict, key: str, value) -> None:
75
+ root, *path, key = key.split(".")
76
+ sub_dict = d[root]
77
+ for part in path:
78
+ if part not in sub_dict:
79
+ sub_dict[part] = defaultdict(dict)
80
+ sub_dict = sub_dict[part]
81
+ sub_dict[key] = value
82
+
83
+
84
+ def convert_config(legacy_config: dict, logger: LoggingConfigurable) -> Config:
85
+ interface_name = None
86
+ resolv = []
87
+ d = defaultdict(dict)
88
+ for key, value in legacy_config.items():
89
+ key = key.upper()
90
+ item = LEGACY_KEYWORDS.get(key)
91
+ if item is None:
92
+ logger.warning(f"Unknown keyword {key!r} in config file")
93
+ continue
94
+ if key == "CAN_DRIVER":
95
+ value = value.lower()
96
+ interface_name = value
97
+ if key in ("SERIAL", "LOG_ERRORS", "STATE", "RTSCTS"):
98
+ resolv.append((key, value))
99
+ else:
100
+ nested_dict_update(d=d, key=item, value=value)
101
+ for key, value in resolv:
102
+ if key == "SERIAL":
103
+ if interface_name == "neovi":
104
+ d["Transport.Can.Neovi.serial"] = value
105
+ elif interface_name == "vector":
106
+ d["Transport.Can.Vector.serial"] = value
107
+ elif key == "LOG_ERRORS":
108
+ if interface_name == "nican":
109
+ d["Transport.Can.NiCan.log_errors"] = value
110
+ elif key == "STATE":
111
+ if interface_name == "pcan":
112
+ d["Transport.Can.PCan.state"] = value
113
+ elif interface_name == "systec":
114
+ d["Transport.Can.Systec.state"] = value
115
+ elif key == "RTSCTS":
116
+ if interface_name == "serial":
117
+ d["Transport.Can.Serial.rtscts"] = value
118
+ elif interface_name == "slcan":
119
+ d["Transport.Can.SlCan.rtscts"] = value
120
+ return Config(d)
pyxcp/constants.py ADDED
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env python
2
+ import struct
3
+ from typing import Any, Callable
4
+
5
+
6
+ PackerType = Callable[[int], bytes]
7
+ UnpackerType = Callable[[bytes], tuple[Any, ...]]
8
+
9
+
10
+ def makeBytePacker(byteorder: str = "@") -> PackerType:
11
+ """"""
12
+ return struct.Struct(f"{byteorder}B").pack
13
+
14
+
15
+ def makeByteUnpacker(byteorder: str = "@") -> UnpackerType:
16
+ """"""
17
+ return struct.Struct(f"{byteorder}B").unpack
18
+
19
+
20
+ def makeWordPacker(byteorder: str = "@") -> PackerType:
21
+ """"""
22
+ return struct.Struct(f"{byteorder}H").pack
23
+
24
+
25
+ def makeWordUnpacker(byteorder: str = "@") -> UnpackerType:
26
+ """"""
27
+ return struct.Struct(f"{byteorder}H").unpack
28
+
29
+
30
+ def makeDWordPacker(byteorder: str = "@") -> PackerType:
31
+ """"""
32
+ return struct.Struct(f"{byteorder}I").pack
33
+
34
+
35
+ def makeDWordUnpacker(byteorder: str = "@") -> UnpackerType:
36
+ """"""
37
+ return struct.Struct(f"{byteorder}I").unpack
38
+
39
+
40
+ def makeDLongPacker(byteorder: str = "@") -> PackerType:
41
+ """"""
42
+ return struct.Struct(f"{byteorder}Q").pack
43
+
44
+
45
+ def makeDLongUnpacker(byteorder: str = "@") -> UnpackerType:
46
+ """"""
47
+ return struct.Struct(f"{byteorder}Q").unpack
File without changes
@@ -0,0 +1,168 @@
1
+
2
+ #if !defined(__ALIGNED_BUFFER_HPP)
3
+ #define __ALIGNED_BUFFER_HPP
4
+
5
+ #include <variant>
6
+
7
+ #include <cstdint>
8
+ #include <cstdlib>
9
+ #include <vector>
10
+ #include <string_view>
11
+ #include <stdexcept>
12
+ #include <algorithm>
13
+ #include <cstring>
14
+
15
+ #include <pybind11/pybind11.h>
16
+
17
+ #if (defined(_WIN32) || defined(_WIN64)) && defined(_MSC_VER)
18
+ #include <malloc.h>
19
+ #endif
20
+
21
+ namespace py = pybind11;
22
+
23
+ class AlignedBuffer {
24
+
25
+ public:
26
+
27
+ AlignedBuffer(size_t size = 0xffff) : m_size(size), m_current_pos(0) {
28
+ m_buffer = nullptr;
29
+ // Create naturally aligned buffer.
30
+ constexpr std::size_t align = alignof(int);
31
+ // aligned_alloc requires size to be a multiple of alignment.
32
+ const std::size_t aligned_size = ((m_size + align - 1) / align) * align;
33
+ #if (defined(_WIN32) || defined(_WIN64)) && defined(_MSC_VER)
34
+ m_buffer = static_cast<uint8_t*>(::_aligned_malloc(aligned_size, align));
35
+ #else
36
+ m_buffer = static_cast<uint8_t*>(::aligned_alloc(align, aligned_size));
37
+ #endif
38
+ }
39
+
40
+ AlignedBuffer(const AlignedBuffer& other) = delete;
41
+ AlignedBuffer& operator=(const AlignedBuffer& other) = delete;
42
+ AlignedBuffer(AlignedBuffer&& other) = delete;
43
+ AlignedBuffer& operator=(AlignedBuffer&& other) = delete;
44
+
45
+ ~AlignedBuffer() {
46
+ if (m_buffer) {
47
+ #if (defined(_WIN32) || defined(_WIN64)) && defined(_MSC_VER)
48
+ ::_aligned_free(m_buffer);
49
+ #else
50
+ ::free(m_buffer);
51
+ #endif
52
+ m_buffer = nullptr;
53
+ }
54
+ }
55
+
56
+ void reset() noexcept {
57
+ m_current_pos = 0;
58
+ }
59
+
60
+ std::size_t size() const noexcept {
61
+ return m_current_pos;
62
+ }
63
+
64
+ // Get an element by index
65
+ uint8_t get(size_t index) const {
66
+ if (index >= size()) throw std::out_of_range("Index out of range");
67
+ return m_buffer[index];
68
+ }
69
+
70
+ void append(uint8_t value) {
71
+ if ((m_current_pos + 1) > m_size) {
72
+ throw std::overflow_error("Buffer overflow");
73
+ }
74
+ m_buffer[m_current_pos] = value;
75
+ m_current_pos++;
76
+ }
77
+
78
+ // Set an element by index
79
+ void set(size_t index, uint8_t value) {
80
+ if (index >= size()) throw std::out_of_range("Index out of range");
81
+ m_buffer[index] = value;
82
+ }
83
+
84
+ static std::string_view bytes_as_string_view(const py::bytes& data) {
85
+ char* buf = nullptr;
86
+ Py_ssize_t len = 0;
87
+ if (PyBytes_AsStringAndSize(data.ptr(), &buf, &len) != 0 || buf == nullptr || len < 0) {
88
+ return std::string_view{};
89
+ }
90
+ return std::string_view(buf, static_cast<std::size_t>(len));
91
+ }
92
+
93
+
94
+ void extend(const py::bytes& values) {
95
+ auto data_view = bytes_as_string_view(values);
96
+
97
+ if ((data_view.size() + m_current_pos) > m_size) {
98
+ throw std::invalid_argument("Values vector is too large");
99
+ }
100
+ if (!data_view.empty()) {
101
+ std::memcpy(m_buffer + m_current_pos, data_view.data(), data_view.size());
102
+ m_current_pos += data_view.size();
103
+ }
104
+ }
105
+
106
+ void extend(const std::vector<std::uint8_t>& values) {
107
+ if ((values.size() + m_current_pos) > m_size) {
108
+ throw std::invalid_argument("Values vector is too large");
109
+ }
110
+ if (!values.empty()) {
111
+ std::memcpy(m_buffer + m_current_pos, values.data(), values.size());
112
+ m_current_pos += values.size();
113
+ }
114
+ }
115
+
116
+ std::variant<uint8_t, py::bytes> get_item(py::object index) const {
117
+ if (py::isinstance<py::slice>(index)) {
118
+ py::slice slice = index.cast<py::slice>();
119
+ size_t start, stop, step, length;
120
+ if (!slice.compute(size(), &start, &stop, &step, &length)) {
121
+ throw py::error_already_set();
122
+ }
123
+ return slice(start, stop, step);
124
+ } else if (py::isinstance<py::int_>(index)) {
125
+ Py_ssize_t idx = index.cast<Py_ssize_t>();
126
+ if (idx < 0) {
127
+ idx += static_cast<Py_ssize_t>(size());
128
+ }
129
+ if (idx < 0 || static_cast<std::size_t>(idx) >= size()) {
130
+ throw std::out_of_range("Index out of range");
131
+ }
132
+ return get(static_cast<std::size_t>(idx));
133
+ } else {
134
+ throw py::type_error("Invalid index type");
135
+ }
136
+ }
137
+
138
+ py::bytes slice(size_t start, size_t stop, size_t step) const {
139
+ if (step == 0) {
140
+ throw std::invalid_argument("Step cannot be zero");
141
+ }
142
+ // Clamp indices to valid range
143
+ start = std::max(size_t(0), std::min(start, size_t(size())));
144
+ stop = std::max(size_t(0), std::min(stop, size_t(size())));
145
+
146
+ if (start >= stop) {
147
+ return py::bytes("");
148
+ }
149
+ if (step == 1) {
150
+ return py::bytes(reinterpret_cast<const char*>(m_buffer) + start, stop - start);
151
+ }
152
+ // General step handling (build result with stride)
153
+ std::string out;
154
+ out.reserve((stop - start + step - 1) / step);
155
+ for (size_t i = start; i < stop; i += step) {
156
+ out.push_back(static_cast<char>(m_buffer[i]));
157
+ }
158
+ return py::bytes(out);
159
+ }
160
+
161
+ private:
162
+ size_t m_size;
163
+ size_t m_current_pos;
164
+ uint8_t * m_buffer;
165
+ };
166
+
167
+
168
+ #endif // __ALIGNED_BUFFER_HPP
pyxcp/cpp_ext/bin.hpp ADDED
@@ -0,0 +1,105 @@
1
+
2
+ #if !defined(__BIN_HPP)
3
+ #define __BIN_HPP
4
+
5
+ #include <cstdint>
6
+ #include <iostream>
7
+ #include <map>
8
+ #include <optional>
9
+ #include <string>
10
+ #include <vector>
11
+
12
+ #include "mcobject.hpp"
13
+
14
+ class Bin {
15
+ public:
16
+
17
+ Bin(std::uint16_t size) : m_size(size), m_residual_capacity(size) {
18
+ }
19
+
20
+ Bin(std::uint16_t size, uint16_t residual_capacity, const std::vector<McObject>& entries) :
21
+ m_size(size), m_residual_capacity(residual_capacity), m_entries(entries) {
22
+ }
23
+
24
+ void append(const McObject& bin) {
25
+ m_entries.emplace_back(bin);
26
+ }
27
+
28
+ void set_entries(std::vector<McObject>&& entries) {
29
+ m_entries = std::move(entries);
30
+ }
31
+
32
+ std::uint16_t get_size() const {
33
+ return m_size;
34
+ }
35
+
36
+ void set_size(const std::uint16_t size) {
37
+ m_size = size;
38
+ }
39
+
40
+ std::uint16_t get_residual_capacity() const {
41
+ return m_residual_capacity;
42
+ }
43
+
44
+ void set_residual_capacity(const std::uint16_t residual_capacity) {
45
+ m_residual_capacity = residual_capacity;
46
+ }
47
+
48
+ const std::vector<McObject>& get_entries() const {
49
+ return m_entries;
50
+ }
51
+
52
+ bool operator==(const Bin& other) const {
53
+ return (m_size == other.m_size) && (m_residual_capacity == other.m_residual_capacity) && (m_entries == other.m_entries);
54
+ }
55
+
56
+ std::string dumps() const {
57
+ std::stringstream ss;
58
+
59
+ ss << to_binary(m_size);
60
+ ss << to_binary(m_residual_capacity);
61
+
62
+ std::size_t entries_size = m_entries.size();
63
+ ss << to_binary(entries_size);
64
+ for (const auto& entry : m_entries) {
65
+ ss << entry.dumps();
66
+ }
67
+
68
+ return ss.str();
69
+ }
70
+
71
+ private:
72
+
73
+ std::uint16_t m_size;
74
+ std::uint16_t m_residual_capacity;
75
+ std::vector<McObject> m_entries{};
76
+ };
77
+
78
+ std::string bin_entries_to_string(const std::vector<McObject>& entries);
79
+
80
+ std::string to_string(const Bin& obj) {
81
+ std::stringstream ss;
82
+ ss << "Bin(size=" << obj.get_size() << ", residual_capacity=" << obj.get_residual_capacity() << ", entries=["
83
+ << bin_entries_to_string(obj.get_entries()) << "])";
84
+ return ss.str();
85
+ }
86
+
87
+ std::string bin_entries_to_string(const std::vector<McObject>& entries) {
88
+ std::stringstream ss;
89
+ for (std::size_t i = 0; i < entries.size(); ++i) {
90
+ ss << to_string(entries[i]);
91
+ if (i + 1 < entries.size()) {
92
+ ss << ", ";
93
+ }
94
+ }
95
+ return ss.str();
96
+ }
97
+
98
+ #if 0
99
+
100
+ @property
101
+ def __len__(self) -> int:
102
+ return len(self.entries)
103
+ #endif
104
+
105
+ #endif // __BIN_HPP
@@ -0,0 +1,58 @@
1
+
2
+ #ifndef __BLOCKMEM_HPP
3
+ #define __BLOCKMEM_HPP
4
+
5
+ #include <array>
6
+ #include <cstdint>
7
+ #include <mutex>
8
+
9
+ /*
10
+ *
11
+ * Super simplicistic block memory manager.
12
+ *
13
+ */
14
+ template<typename T, int _IS, int _NB>
15
+ class BlockMemory {
16
+ public:
17
+
18
+ using mem_block_t = std::array<T, _IS>;
19
+
20
+ constexpr explicit BlockMemory() noexcept : m_memory{ nullptr }, m_allocation_count{ 0 } {
21
+ m_memory = new T[_IS * _NB];
22
+ }
23
+
24
+ ~BlockMemory() noexcept {
25
+ if (m_memory) {
26
+ delete[] m_memory;
27
+ }
28
+ }
29
+
30
+ BlockMemory(const BlockMemory&) = delete;
31
+
32
+ constexpr T* acquire() noexcept {
33
+ const std::scoped_lock lock(m_mtx);
34
+
35
+ if (m_allocation_count >= _NB) {
36
+ return nullptr;
37
+ }
38
+ T* ptr = reinterpret_cast<T*>(m_memory + (m_allocation_count * _IS));
39
+ m_allocation_count++;
40
+ return ptr;
41
+ }
42
+
43
+ constexpr void release() noexcept {
44
+ const std::scoped_lock lock(m_mtx);
45
+ if (m_allocation_count == 0) {
46
+ return;
47
+ }
48
+ m_allocation_count--;
49
+ }
50
+
51
+ private:
52
+
53
+ T* m_memory;
54
+ std::uint32_t m_allocation_count;
55
+ std::mutex m_mtx;
56
+ };
57
+
58
+ #endif // __BLOCKMEM_HPP