uproot-custom 2.0.0.dev0__tar.gz → 2.1.0__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.
Files changed (82) hide show
  1. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/.github/workflows/build-wheels.yml +1 -1
  2. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/.github/workflows/deploy-docs.yml +3 -1
  3. uproot_custom-2.1.0/.github/workflows/semantic-pr-titles.yml +19 -0
  4. uproot_custom-2.0.0.dev0/.github/workflows/run-pytest.yml → uproot_custom-2.1.0/.github/workflows/test-package.yml +23 -2
  5. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/PKG-INFO +27 -3
  6. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/README.md +23 -0
  7. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/cpp/include/uproot-custom/uproot-custom.hh +220 -13
  8. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/cpp/src/uproot-custom.cc +495 -62
  9. uproot_custom-2.1.0/docs/Doxyfile +2618 -0
  10. uproot_custom-2.1.0/docs/conf.py +151 -0
  11. {uproot_custom-2.0.0.dev0/docs/examples → uproot_custom-2.1.0/docs/example}/override-streamer.md +2 -2
  12. {uproot_custom-2.0.0.dev0/docs/examples → uproot_custom-2.1.0/docs/example}/read-tobjarray.md +3 -3
  13. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/docs/index.md +32 -18
  14. uproot_custom-2.1.0/docs/reference/api/cpp-api.md +8 -0
  15. uproot_custom-2.1.0/docs/reference/api/cpp-module.md +6 -0
  16. uproot_custom-2.1.0/docs/reference/api/uproot-custom-ref.md +12 -0
  17. uproot_custom-2.1.0/docs/reference/api/uproot_custom.rst +37 -0
  18. uproot_custom-2.1.0/docs/reference/api.md +10 -0
  19. uproot_custom-2.1.0/docs/reference/version-requirements.md +23 -0
  20. {uproot_custom-2.0.0.dev0/docs/architecture → uproot_custom-2.1.0/docs/tutorial/customize-factory-reader}/binary-data.md +7 -6
  21. {uproot_custom-2.0.0.dev0/docs/architecture → uproot_custom-2.1.0/docs/tutorial/customize-factory-reader}/bootstrap.md +7 -7
  22. {uproot_custom-2.0.0.dev0/docs/architecture → uproot_custom-2.1.0/docs/tutorial/customize-factory-reader}/reader-and-factory.md +10 -10
  23. uproot_custom-2.1.0/docs/tutorial/customize-factory-reader/template-python-project.md +51 -0
  24. uproot_custom-2.1.0/docs/tutorial/customize-factory-reader.md +26 -0
  25. uproot_custom-2.0.0.dev0/docs/get-started.md → uproot_custom-2.1.0/docs/tutorial/use-built-in.md +4 -12
  26. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/cpp/CMakeLists.txt +1 -1
  27. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/cpp/my_reader.cc +4 -4
  28. uproot_custom-2.1.0/example/my_reader/my_reader_cpp.pyi +11 -0
  29. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/pyproject.toml +4 -3
  30. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/tests/test_AsCustom.py +29 -13
  31. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/tests/test_downstream_build_pyproject.toml +5 -1
  32. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/uproot_custom/AsCustom.py +26 -2
  33. uproot_custom-2.1.0/uproot_custom/__init__.py +27 -0
  34. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/uproot_custom/_version.py +3 -3
  35. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/uproot_custom/cpp.pyi +38 -36
  36. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/uproot_custom/factories.py +2 -2
  37. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/uproot_custom/utils.py +1 -1
  38. uproot_custom-2.0.0.dev0/docs/conf.py +0 -65
  39. uproot_custom-2.0.0.dev0/example/my_reader/my_reader_cpp.pyi +0 -11
  40. uproot_custom-2.0.0.dev0/tests/test_AsGroupedMap.py +0 -35
  41. uproot_custom-2.0.0.dev0/uproot_custom/AsBinary.py +0 -94
  42. uproot_custom-2.0.0.dev0/uproot_custom/AsGroupedMap.py +0 -44
  43. uproot_custom-2.0.0.dev0/uproot_custom/__init__.py +0 -58
  44. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/.clang-format +0 -0
  45. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/.github/workflows/python-publish.yml +0 -0
  46. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/.gitignore +0 -0
  47. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/CHANGELOG.md +0 -0
  48. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/LICENSE +0 -0
  49. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/cpp/CMakeLists.txt +0 -0
  50. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/cpp/share/cmake/uproot-customConfig.cmake +0 -0
  51. {uproot_custom-2.0.0.dev0/docs → uproot_custom-2.1.0/docs/reference}/binary-format.md +0 -0
  52. {uproot_custom-2.0.0.dev0/docs/architecture → uproot_custom-2.1.0/docs/tutorial/customize-factory-reader}/streamer-info.md +0 -0
  53. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/README.md +0 -0
  54. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/gen-demo-data/CMakeLists.txt +0 -0
  55. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/gen-demo-data/include/LinkDef.h +0 -0
  56. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/gen-demo-data/include/TBasicTypes.hh +0 -0
  57. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/gen-demo-data/include/TCStyleArray.hh +0 -0
  58. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/gen-demo-data/include/TComplicatedSTL.hh +0 -0
  59. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/gen-demo-data/include/TNestedSTL.hh +0 -0
  60. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/gen-demo-data/include/TObjInObjArray.hh +0 -0
  61. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/gen-demo-data/include/TOverrideStreamer.hh +0 -0
  62. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/gen-demo-data/include/TRootObjects.hh +0 -0
  63. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/gen-demo-data/include/TSTLArray.hh +0 -0
  64. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/gen-demo-data/include/TSTLMap.hh +0 -0
  65. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/gen-demo-data/include/TSTLMapWithObj.hh +0 -0
  66. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/gen-demo-data/include/TSTLSeqWithObj.hh +0 -0
  67. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/gen-demo-data/include/TSTLSequence.hh +0 -0
  68. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/gen-demo-data/include/TSTLString.hh +0 -0
  69. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/gen-demo-data/include/TSimpleObject.hh +0 -0
  70. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/gen-demo-data/src/TOverrideStreamer.cc +0 -0
  71. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/gen-demo-data/src/main.cc +0 -0
  72. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/my_reader/OverrideStreamerFactory.py +0 -0
  73. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/my_reader/TObjArrayFactory.py +0 -0
  74. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/my_reader/__init__.py +0 -0
  75. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/pyproject.toml +0 -0
  76. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/read-dask.py +0 -0
  77. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/example/read-data.py +0 -0
  78. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/tests/conftest.py +0 -0
  79. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/tests/test-data.root +0 -0
  80. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/tests/test_docs.py +0 -0
  81. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/tests/test_downstream_build.py +0 -0
  82. {uproot_custom-2.0.0.dev0 → uproot_custom-2.1.0}/uproot_custom/share/cmake/__init__.py +0 -0
@@ -6,7 +6,7 @@ on:
6
6
 
7
7
  jobs:
8
8
  run-pytest:
9
- uses: ./.github/workflows/run-pytest.yml
9
+ uses: ./.github/workflows/test-package.yml
10
10
 
11
11
  build-wheels:
12
12
  needs: run-pytest
@@ -16,12 +16,14 @@ jobs:
16
16
  - name: Set up Python
17
17
  uses: actions/setup-python@v4
18
18
  with:
19
- python-version: '3.13'
19
+ python-version: "3.13"
20
20
 
21
21
  - name: Install dependencies
22
22
  run: |
23
23
  python -m pip install --upgrade pip
24
24
  pip install .[docs]
25
+ sudo apt-get update
26
+ sudo apt-get install -y doxygen
25
27
 
26
28
  - name: Build docs
27
29
  run: |
@@ -0,0 +1,19 @@
1
+ name: 'Lint PR'
2
+
3
+ on:
4
+ pull_request_target:
5
+ types:
6
+ - opened
7
+ - edited
8
+ - reopened
9
+
10
+ jobs:
11
+ main:
12
+ name: Validate PR title
13
+ runs-on: ubuntu-latest
14
+ permissions:
15
+ pull-requests: read
16
+ steps:
17
+ - uses: amannn/action-semantic-pull-request@v6
18
+ env:
19
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -12,7 +12,7 @@ permissions:
12
12
  contents: read
13
13
 
14
14
  jobs:
15
- test:
15
+ test-package:
16
16
  runs-on: ${{ matrix.os }}
17
17
  strategy:
18
18
  matrix:
@@ -34,4 +34,25 @@ jobs:
34
34
  - name: Run pytest
35
35
  run: |
36
36
  pytest --version
37
- pytest -n auto tests/
37
+ pytest -v tests/
38
+
39
+ test-build-docs:
40
+ runs-on: ubuntu-latest
41
+ steps:
42
+ - uses: actions/checkout@v4
43
+
44
+ - name: Set up Python
45
+ uses: actions/setup-python@v4
46
+ with:
47
+ python-version: "3.13"
48
+
49
+ - name: Install dependencies
50
+ run: |
51
+ python -m pip install --upgrade pip
52
+ pip install .[docs]
53
+ sudo apt-get update
54
+ sudo apt-get install -y doxygen
55
+
56
+ - name: Build docs
57
+ run: |
58
+ sphinx-build -b html docs/ build/html
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: uproot-custom
3
- Version: 2.0.0.dev0
3
+ Version: 2.1.0
4
4
  Summary: uproot extension for reading custom classes
5
5
  Author-Email: Mingrun Li <mrli@ihep.ac.cn>
6
6
  Classifier: Development Status :: 3 - Alpha
@@ -27,9 +27,9 @@ Classifier: Topic :: Software Development
27
27
  Classifier: Topic :: Utilities
28
28
  Project-URL: Homepage, https://github.com/mrzimu/uproot-custom
29
29
  Requires-Python: <3.14,>=3.9
30
- Requires-Dist: uproot>=5.0
30
+ Requires-Dist: uproot>=5.6.7
31
31
  Requires-Dist: numpy
32
- Requires-Dist: awkward
32
+ Requires-Dist: awkward>=2.8.0
33
33
  Provides-Extra: dev
34
34
  Requires-Dist: pytest; extra == "dev"
35
35
  Requires-Dist: pytest-xdist; extra == "dev"
@@ -49,6 +49,7 @@ Requires-Dist: sphinx-togglebutton; extra == "docs"
49
49
  Requires-Dist: sphinxcontrib-mermaid; extra == "docs"
50
50
  Requires-Dist: sphinx-autobuild; extra == "docs"
51
51
  Requires-Dist: sphinx-intl; extra == "docs"
52
+ Requires-Dist: breathe; extra == "docs"
52
53
  Description-Content-Type: text/markdown
53
54
 
54
55
  # Introduction
@@ -63,6 +64,29 @@ Description-Content-Type: text/markdown
63
64
 
64
65
  `uproot-custom` uses a `reader`/`factory` mechanism to read classes:
65
66
 
67
+ ```mermaid
68
+ flowchart TD
69
+ subgraph py["Python field"]
70
+ direction TB
71
+ AsCustom --> fac["Factory (Primitive, STLVector, TString, ...)"]
72
+ fac["Factory (Primitive, STLVector, TString, ...)"] -- Optional --> form(["construct awkward forms"])
73
+ fac --> build_reader(["build corresponding C++ reader"])
74
+ fac --> build_ak(["construct awkward arrays"])
75
+ end
76
+
77
+ user_fac["User's Factory"] -. Register .-> fac
78
+
79
+ subgraph cpp["C++ field"]
80
+ direction TB
81
+ build_reader --> reader["C++ Reader"]
82
+ reader --> read_bin(["read binary data"])
83
+ read_bin --> ret_data(["return data"])
84
+ end
85
+
86
+ ret_data --> raw_data[("tuple, list, numpy arrays, ...")]
87
+ raw_data --> build_ak
88
+ ```
89
+
66
90
  - `reader` is a C++ class that implements the logic to read data from binary buffers.
67
91
  - `factory` is a Python class that creates, combines `reader`s, and post-processes the data read by `reader`s.
68
92
 
@@ -10,6 +10,29 @@
10
10
 
11
11
  `uproot-custom` uses a `reader`/`factory` mechanism to read classes:
12
12
 
13
+ ```mermaid
14
+ flowchart TD
15
+ subgraph py["Python field"]
16
+ direction TB
17
+ AsCustom --> fac["Factory (Primitive, STLVector, TString, ...)"]
18
+ fac["Factory (Primitive, STLVector, TString, ...)"] -- Optional --> form(["construct awkward forms"])
19
+ fac --> build_reader(["build corresponding C++ reader"])
20
+ fac --> build_ak(["construct awkward arrays"])
21
+ end
22
+
23
+ user_fac["User's Factory"] -. Register .-> fac
24
+
25
+ subgraph cpp["C++ field"]
26
+ direction TB
27
+ build_reader --> reader["C++ Reader"]
28
+ reader --> read_bin(["read binary data"])
29
+ read_bin --> ret_data(["return data"])
30
+ end
31
+
32
+ ret_data --> raw_data[("tuple, list, numpy arrays, ...")]
33
+ raw_data --> build_ak
34
+ ```
35
+
13
36
  - `reader` is a C++ class that implements the logic to read data from binary buffers.
14
37
  - `factory` is a Python class that creates, combines `reader`s, and post-processes the data read by `reader`s.
15
38
 
@@ -26,6 +26,10 @@
26
26
  # error "Unsupported compiler!"
27
27
  #endif
28
28
 
29
+ /**
30
+ * @brief Macro to import the uproot_custom.cpp module.
31
+ * @note This macro should be used in the `PYBIND11_MODULE` definition of your module.
32
+ */
29
33
  #define IMPORT_UPROOT_CUSTOM_CPP pybind11::module_::import( "uproot_custom.cpp" );
30
34
 
31
35
  namespace uproot {
@@ -59,12 +63,23 @@ namespace uproot {
59
63
  << 13 ///< if object ctor succeeded but object should not be used
60
64
  };
61
65
 
66
+ /**
67
+ * @brief Construct a BinaryBuffer from numpy arrays.
68
+ * @param data A numpy array of uint8_t containing the raw data.
69
+ * @param offsets A numpy array of uint32_t containing the offsets for each entry.
70
+ */
62
71
  BinaryBuffer( py::array_t<uint8_t> data, py::array_t<uint32_t> offsets )
63
72
  : m_data( static_cast<uint8_t*>( data.request().ptr ) )
64
73
  , m_offsets( static_cast<uint32_t*>( offsets.request().ptr ) )
65
74
  , m_entries( offsets.request().size - 1 )
66
75
  , m_cursor( static_cast<uint8_t*>( data.request().ptr ) ) {}
67
76
 
77
+ /**
78
+ * @brief Read a value of type T from the buffer, handling endianness.
79
+ *
80
+ * @tparam T The type to read.
81
+ * @return The value read from the buffer.
82
+ */
68
83
  template <typename T>
69
84
  const T read() {
70
85
  constexpr auto size = sizeof( T );
@@ -107,8 +122,19 @@ namespace uproot {
107
122
  }
108
123
  }
109
124
 
125
+ /**
126
+ * @brief Read the fVersion field from the buffer
127
+ *
128
+ * @return The fVersion value
129
+ */
110
130
  const int16_t read_fVersion() { return read<int16_t>(); }
111
131
 
132
+ /**
133
+ * @brief Read the fNBytes field from the buffer, checking the byte count mask.
134
+ *
135
+ * @return The fNBytes value without the mask.
136
+ * @exception std::runtime_error if the byte count mask is not set.
137
+ */
112
138
  const uint32_t read_fNBytes() {
113
139
  auto byte_count = read<uint32_t>();
114
140
  if ( !( byte_count & kByteCountMask ) )
@@ -116,6 +142,11 @@ namespace uproot {
116
142
  return byte_count & ~kByteCountMask;
117
143
  }
118
144
 
145
+ /**
146
+ * @brief Read a null-terminated (`\0`) string from the buffer.
147
+ *
148
+ * @return The string read from the buffer.
149
+ */
119
150
  const std::string read_null_terminated_string() {
120
151
  auto start = m_cursor;
121
152
  while ( *m_cursor != 0 ) { m_cursor++; }
@@ -123,6 +154,14 @@ namespace uproot {
123
154
  return std::string( start, m_cursor );
124
155
  }
125
156
 
157
+ /**
158
+ * @brief Read an object header from the buffer. The object header has `fNBytes`,
159
+ * `fVersion`, `fTag`. If `fTag == kNewClassTag`, then a null-terminated class name
160
+ * follows.
161
+ *
162
+ * @return The class name if the object is a new class, empty string
163
+ * otherwise.
164
+ */
126
165
  const std::string read_obj_header() {
127
166
  read_fNBytes();
128
167
  auto fTag = read<uint32_t>();
@@ -130,6 +169,13 @@ namespace uproot {
130
169
  else return std::string();
131
170
  }
132
171
 
172
+ /**
173
+ * @brief Read a TString from the buffer. A TString has `length` (uint8_t). If `length
174
+ * == 255`, then the `length` is a following uint32_t. Then following `length` bytes of
175
+ * string data.
176
+ *
177
+ * @return The TString data read from the buffer, as a std::string.
178
+ */
133
179
  const std::string read_TString() {
134
180
  uint32_t length = read<uint8_t>();
135
181
  if ( length == 255 ) length = read<uint32_t>();
@@ -138,21 +184,48 @@ namespace uproot {
138
184
  return std::string( start, m_cursor );
139
185
  }
140
186
 
187
+ /**
188
+ * @brief Skip `n` bytes in the buffer.
189
+ *
190
+ * @param n Number of bytes to skip.
191
+ */
141
192
  void skip( const size_t n ) { m_cursor += n; }
142
193
 
143
- void skip_fNBytes() { read_fNBytes(); } // need to check the mask
194
+ /**
195
+ * @brief Skip the fNBytes field. Equivalent to read_fNBytes() but does not return the
196
+ * value, since the mask need to be checked.
197
+ */
198
+ void skip_fNBytes() { read_fNBytes(); }
199
+
200
+ /**
201
+ * @brief Skip the fVersion field.
202
+ */
144
203
  void skip_fVersion() { skip( 2 ); }
204
+
205
+ /**
206
+ * @brief Skip a null-terminated (`\0`) string in the buffer.
207
+ */
145
208
  void skip_null_terminated_string() {
146
209
  while ( *m_cursor != 0 ) { m_cursor++; }
147
210
  m_cursor++;
148
211
  }
149
212
 
213
+ /**
214
+ * @brief Skip an object header in the buffer. The object header has `fNBytes`,
215
+ * `fVersion`, `fTag`. If `fTag == kNewClassTag`, then a null-terminated class name
216
+ * follows.
217
+ */
150
218
  void skip_obj_header() {
151
219
  skip_fNBytes();
152
220
  auto fTag = read<uint32_t>();
153
221
  if ( fTag == kNewClassTag ) skip_null_terminated_string();
154
222
  }
155
223
 
224
+ /**
225
+ * @brief Skip a TObject in the buffer. A TObject has `fVersion` (2 bytes), `fUniqueID`
226
+ * (4 bytes), `fBits` (4 bytes). If `fBits & kIsReferenced`, then a `pidf` (2 bytes)
227
+ * follows.
228
+ */
156
229
  void skip_TObject() {
157
230
  // TODO: CanIgnoreTObjectStreamer() ?
158
231
  skip_fVersion();
@@ -161,21 +234,41 @@ namespace uproot {
161
234
  if ( fBits & ( kIsReferenced ) ) skip( 2 ); // pidf
162
235
  }
163
236
 
237
+ /**
238
+ * @brief Get the raw data pointer.
239
+ */
164
240
  const uint8_t* get_data() const { return m_data; }
241
+
242
+ /**
243
+ * @brief Get the current cursor pointer.
244
+ */
165
245
  const uint8_t* get_cursor() const { return m_cursor; }
246
+
247
+ /**
248
+ * @brief Get the entry offsets array pointer.
249
+ */
166
250
  const uint32_t* get_offsets() const { return m_offsets; }
251
+
252
+ /**
253
+ * @brief Get the number of entries.
254
+ */
167
255
  const uint64_t entries() const { return m_entries; }
168
256
 
257
+ /**
258
+ * @brief Debug print the next `n` bytes from the current cursor.
259
+ *
260
+ * @param n Number of bytes to print.
261
+ */
169
262
  void debug_print( const size_t n = 100 ) const {
170
263
  for ( size_t i = 0; i < n; i++ ) { std::cout << (int)*( m_cursor + i ) << " "; }
171
264
  std::cout << std::endl;
172
265
  }
173
266
 
174
267
  private:
175
- uint8_t* m_cursor;
176
- const uint64_t m_entries;
177
- const uint8_t* m_data;
178
- const uint32_t* m_offsets; // by the time, this is not used
268
+ uint8_t* m_cursor; ///< current cursor position
269
+ const uint64_t m_entries; ///< number of entries
270
+ const uint8_t* m_data; ///< raw data pointer
271
+ const uint32_t* m_offsets; ///< entry offsets pointer
179
272
  };
180
273
 
181
274
  /*
@@ -184,24 +277,74 @@ namespace uproot {
184
277
  -----------------------------------------------------------------------------
185
278
  */
186
279
 
187
- class IElementReader {
280
+ /**
281
+ * @brief Interface for element readers. All element readers must inherit from this class.
282
+ */
283
+ class IReader {
188
284
  protected:
189
- const std::string m_name;
285
+ const std::string m_name; ///< name of the reader
190
286
 
191
287
  public:
192
- IElementReader( std::string name ) : m_name( name ) {}
193
- virtual ~IElementReader() = default;
194
-
288
+ /**
289
+ * @brief Construct a new IReader object.
290
+ *
291
+ * @param name Name of the reader.
292
+ */
293
+ IReader( std::string name ) : m_name( name ) {}
294
+
295
+ virtual ~IReader() = default;
296
+
297
+ /**
298
+ * @brief Get the name of the reader.
299
+ *
300
+ * @return Name of the reader.
301
+ */
195
302
  virtual const std::string name() const { return m_name; }
196
303
 
304
+ /**
305
+ * @brief Read an element from the buffer.
306
+ *
307
+ * @param buffer The binary buffer to read from.
308
+ */
197
309
  virtual void read( BinaryBuffer& buffer ) = 0;
198
- virtual py::object data() const = 0;
199
310
 
311
+ /**
312
+ * @brief Get the data read by the reader. This should be called after the whole
313
+ * reading process.
314
+ *
315
+ * @return The data read by the reader.
316
+ */
317
+ virtual py::object data() const = 0;
318
+
319
+ /**
320
+ * @brief Read multiple elements from the buffer in one go. Repeatedly calls @ref
321
+ * read() by default.
322
+ *
323
+ * @note When multiple elements are stored together, some classes may have "one common
324
+ * header + multiple data objects" format. This method can be overridden to handle such
325
+ * cases more efficiently.
326
+ *
327
+ * @param buffer The binary buffer to read from.
328
+ * @param count Number of elements to read.
329
+ * @return Number of elements read.
330
+ */
200
331
  virtual uint32_t read_many( BinaryBuffer& buffer, const int64_t count ) {
201
332
  for ( int32_t i = 0; i < count; i++ ) { read( buffer ); }
202
333
  return count;
203
334
  }
204
335
 
336
+ /**
337
+ * @brief Read elements from the buffer until reaching the end position. Repeatedly
338
+ * calls @ref read() method by default.
339
+ *
340
+ * @note When multiple elements are stored together, some classes may have "one common
341
+ * header + multiple data objects" format. This method can be overridden to handle such
342
+ * cases more efficiently.
343
+ *
344
+ * @param buffer The binary buffer to read from.
345
+ * @param end_pos The end position pointer.
346
+ * @return Number of elements read.
347
+ */
205
348
  virtual uint32_t read_until( BinaryBuffer& buffer, const uint8_t* end_pos ) {
206
349
  uint32_t cur_count = 0;
207
350
  while ( buffer.get_cursor() < end_pos )
@@ -212,6 +355,15 @@ namespace uproot {
212
355
  return cur_count;
213
356
  }
214
357
 
358
+ /**
359
+ * @brief Read multiple elements from the buffer in member-wise fashion. This method
360
+ * checks for negative count and calls @ref read_many() by default. It can be
361
+ * overridden to handle member-wise reading more efficiently.
362
+ *
363
+ * @param buffer The binary buffer to read from.
364
+ * @param count Number of elements to read.
365
+ * @return Number of elements read.
366
+ */
215
367
  virtual uint32_t read_many_memberwise( BinaryBuffer& buffer, const int64_t count ) {
216
368
  if ( count < 0 )
217
369
  {
@@ -223,7 +375,19 @@ namespace uproot {
223
375
  }
224
376
  };
225
377
 
226
- using SharedReader = shared_ptr<IElementReader>;
378
+ /**
379
+ * @brief Deprecated alias for IReader.
380
+ * @deprecated Use IReader instead.
381
+ */
382
+ using IElementReader
383
+ [[deprecated( "IElementReader is deprecated. Use IReader instead." )]] = IReader;
384
+
385
+ /**
386
+ * @brief Shortcut for shared pointer to IReader.
387
+ * @note When a reader requires another reader as a member, it must use
388
+ * `std::shared_ptr<IReader>` to properly handle lifetime management.
389
+ */
390
+ using SharedReader = shared_ptr<IReader>;
227
391
 
228
392
  /*
229
393
  -----------------------------------------------------------------------------
@@ -231,14 +395,33 @@ namespace uproot {
231
395
  -----------------------------------------------------------------------------
232
396
  */
233
397
 
398
+ /**
399
+ * @brief Helper function to create a shared pointer to a reader. Pybind11 requires
400
+ * shared_ptr to handle object lifetime correctly.
401
+ *
402
+ * @tparam ReaderType The type of the reader.
403
+ * @tparam Args The argument types for the reader constructor.
404
+ * @param args The arguments for the reader constructor.
405
+ * @return The shared pointer to the created reader.
406
+ */
234
407
  template <typename ReaderType, typename... Args>
235
408
  shared_ptr<ReaderType> CreateReader( Args... args ) {
236
409
  return std::make_shared<ReaderType>( std::forward<Args>( args )... );
237
410
  }
238
411
 
412
+ /**
413
+ * @brief Helper function to declare a reader class in a pybind11 module. Automatically
414
+ * wraps the class' constructor to return a shared_ptr. User should always use this
415
+ * function to declare reader classes.
416
+ *
417
+ * @tparam ReaderType The type of the reader.
418
+ * @tparam Args The argument types for the reader constructor.
419
+ * @param m The declaring pybind11 module.
420
+ * @param name The name of the reader class in Python.
421
+ */
239
422
  template <typename ReaderType, typename... Args>
240
423
  void declare_reader( py::module& m, const char* name ) {
241
- py::class_<ReaderType, shared_ptr<ReaderType>, IElementReader>( m, name ).def(
424
+ py::class_<ReaderType, shared_ptr<ReaderType>, IReader>( m, name ).def(
242
425
  py::init( &CreateReader<ReaderType, Args...> ) );
243
426
  }
244
427
 
@@ -248,6 +431,14 @@ namespace uproot {
248
431
  -----------------------------------------------------------------------------
249
432
  */
250
433
 
434
+ /**
435
+ * @brief Convert a shared pointer to a std::vector<T> to a numpy array without copying.
436
+ * User can use this function to return numpy arrays from reader's data() method.
437
+ *
438
+ * @tparam T The element type of the vector.
439
+ * @param seq The shared pointer to the std::vector<T>.
440
+ * @return The numpy array wrapping the vector data.
441
+ */
251
442
  template <typename T>
252
443
  inline py::array_t<T> make_array( shared_ptr<std::vector<T>> seq ) {
253
444
  auto size = seq->size();
@@ -266,6 +457,14 @@ namespace uproot {
266
457
  -----------------------------------------------------------------------------
267
458
  */
268
459
 
460
+ /**
461
+ * @brief Debug print function. Prints only when macro or environment varialbe with name
462
+ * `UPROOT_DEBUG` is defined. Use this function like `printf()`.
463
+ *
464
+ * @tparam Args Argument types. No need to specify explicitly.
465
+ * @param msg The format string.
466
+ * @param args Arguments to format.
467
+ */
269
468
  template <typename... Args>
270
469
  inline void debug_printf( const char* msg, Args... args ) {
271
470
  bool do_print = getenv( "UPROOT_DEBUG" );
@@ -276,6 +475,14 @@ namespace uproot {
276
475
  printf( msg, std::forward<Args>( args )... );
277
476
  }
278
477
 
478
+ /**
479
+ * @brief Debug print function for BinaryBuffer. Prints only when macro or environment
480
+ * varialbe with name `UPROOT_DEBUG` is defined. Call @ref BinaryBuffer::debug_print()
481
+ * internally.
482
+ *
483
+ * @param buffer The BinaryBuffer to print.
484
+ * @param n Number of bytes to print.
485
+ */
279
486
  inline void debug_printf( uproot::BinaryBuffer& buffer, const size_t n = 100 ) {
280
487
  bool do_print = getenv( "UPROOT_DEBUG" );
281
488
  #ifdef UPROOT_DEBUG