Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add data read #85

Draft
wants to merge 163 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
163 commits
Select commit Hold shift + click to select a range
1e1f041
Define base classes for reading
oruebel Aug 31, 2024
e58f50f
First draft of reading datasets and attributes
oruebel Aug 31, 2024
250a66b
Split reading of attribute and dataset to separate functions
oruebel Aug 31, 2024
e1bfa2e
Remove debug print
oruebel Aug 31, 2024
4aedefd
Add functions to construct ReadDatasetWrapper and ReadAttributeWrappe…
oruebel Aug 31, 2024
4dae171
Fix formatting
oruebel Aug 31, 2024
140809e
Add test for using the ReadDatasetWrapper
oruebel Aug 31, 2024
4d7b1ea
Start refactor containers for read
oruebel Aug 31, 2024
2db4bfe
Fix format
oruebel Aug 31, 2024
b2959d2
Read ElectricalSeries.data example working
oruebel Sep 1, 2024
37d30d3
Revert change to tests used for debugging
oruebel Sep 1, 2024
6cfe416
Fix codespell issue
oruebel Sep 1, 2024
3d86aff
Move read example to an example file
oruebel Sep 1, 2024
3fc1d7a
Fix bug in Container::create
oruebel Sep 1, 2024
b09a4fa
Add example for data read
oruebel Sep 1, 2024
970f4c8
Fix spelling error
oruebel Sep 1, 2024
26fbae9
Add user docs for data read
oruebel Sep 1, 2024
4299f99
Update read user docs
oruebel Sep 1, 2024
9c9301c
Add toc
oruebel Sep 2, 2024
447337a
Add read software design figure and more details on the design
oruebel Sep 2, 2024
e3d4330
Some adjustment to the edges in the fig
oruebel Sep 2, 2024
77f0861
Some adjustment to the edges in the fig
oruebel Sep 2, 2024
5190731
Add intro for data read page
oruebel Sep 2, 2024
f08e42f
Make Container::create inline
oruebel Sep 3, 2024
1a754b9
Make DataBlock::fromGeneric inline
oruebel Sep 3, 2024
ebfbdf1
Implement function to allow us to get the storage object type for a g…
oruebel Sep 3, 2024
3022861
Rename getObjectType to getStroageObjectType
oruebel Sep 3, 2024
6ba32a5
Fix reading of attributes and add TimeSeries.resolution read
oruebel Sep 3, 2024
1fb5d95
Add example for reading an attribute
oruebel Sep 3, 2024
676b978
Add ReadDataWrapperBase as common base class for ReadDatasetWrapper a…
oruebel Sep 3, 2024
14c8362
Fix docstring
oruebel Sep 3, 2024
d2b1c23
Minor fixed to docs
oruebel Sep 3, 2024
78825f2
Mention ReadDataWrapperBase in the read dox page
oruebel Sep 3, 2024
85db320
Merge branch 'main' into add_read
oruebel Sep 3, 2024
5c2faae
Fix unit tests after merge
oruebel Sep 3, 2024
c481260
Remove NWBFile.identifierText property
oruebel Sep 3, 2024
b418149
Allow setting of value type template parameter for ReadDataWrapperBas…
oruebel Sep 4, 2024
1f3ad24
Save the std::type_index as part of the DataBlock to support runtime …
oruebel Sep 4, 2024
99b5d4e
Fix #88 move io classes to their own module
oruebel Sep 5, 2024
04117e9
Refactor to add IO namespace to match folder structure
oruebel Sep 5, 2024
82a4c08
Move HDF5RecordingData to its own hpp/cpp files
oruebel Sep 5, 2024
6554e29
Moved read I/O classes to new ReadIO.hpp
oruebel Sep 5, 2024
bff7121
Refactor the read data wrappers to use a single ReadDataWrapper class…
oruebel Sep 5, 2024
53365ff
Replace redundant ReadObjectType with StorageObjectType
oruebel Sep 6, 2024
c66b3bc
Add traits for ReadObjectWrapper to prevent instantiation for Group a…
oruebel Sep 6, 2024
0da4800
Fix formatting
oruebel Sep 6, 2024
d161c47
Fix spelling error
oruebel Sep 6, 2024
58e5afb
Inline functions in ReadIO.hpp
oruebel Sep 6, 2024
b7cc149
Some minor fixes
oruebel Sep 6, 2024
b9c6c9b
Merge branch 'main' into add_read
oruebel Sep 7, 2024
0e8ef12
First draft of Container registry
oruebel Sep 8, 2024
69c3c4e
Update ElectrodGroup to provide standard Container constructor and mo…
oruebel Sep 8, 2024
e75c7ad
Fix formatting
oruebel Sep 8, 2024
eeaceae
Merge branch 'add_read' into add_container_read
oruebel Sep 8, 2024
e62164b
Register subtypes
oruebel Sep 8, 2024
e99feee
Move the registry to a new RegisteredType class to also cover non-Gro…
oruebel Sep 8, 2024
3683921
Fix formatting
oruebel Sep 8, 2024
20050c7
Ensure all neurodata_types are registered correctly
oruebel Sep 8, 2024
cf9c017
Add unittest for RegisteredTrype
oruebel Sep 8, 2024
be29fb6
Add developer docs for RegisteredTypes
oruebel Sep 8, 2024
779c2af
Fix name of the unit test file for RegisteredType
oruebel Sep 8, 2024
3179c4b
Add example code for RegisteredType
oruebel Sep 8, 2024
dbdd945
Use both namespace and type name to register and access subtypes
oruebel Sep 8, 2024
4a7197f
Update documentation to clarify the use of namespace::classname to ma…
oruebel Sep 8, 2024
d11870b
Update read test to use the registry to construct the class
oruebel Sep 8, 2024
7a64982
Minor dox fixes
oruebel Sep 8, 2024
b42065b
Fix getTypeName and getNamespace and use them instead of hard-coded v…
oruebel Sep 9, 2024
501bc32
Update docs for getTypeName add getNamespace
oruebel Sep 9, 2024
5ab8464
Merge branch 'main' into add_read
oruebel Sep 9, 2024
803dfcf
Fix ElectricalSeries
oruebel Sep 9, 2024
5d959bd
Merge branch 'add_read' into add_container_read
oruebel Sep 9, 2024
a1dc63d
Attempt to fix reading of string attribute
oruebel Sep 9, 2024
bba4a79
Fix read neurodata_type attribute read test
oruebel Sep 9, 2024
a58a44a
Add test for reading a TimeSeries Container back
oruebel Sep 9, 2024
3ac8ca4
Add RegisteredType::create method to read a type from file
oruebel Sep 9, 2024
5f0bdd6
Fix path ecephys read test
oruebel Sep 9, 2024
edc45cf
Change RegisteredType::create to return shared pointer to support cas…
oruebel Sep 9, 2024
7184f96
Update ecephys read example
oruebel Sep 9, 2024
bda279d
Updated read tutorial and example
oruebel Sep 9, 2024
db8c652
Add missing comment
oruebel Sep 9, 2024
cf06a19
Clarify read docs and rename workflow docs
oruebel Sep 9, 2024
cdffc74
Run test workflows on all PRs
oruebel Sep 19, 2024
b0a28f9
Merge branch 'add_read' into add_container_read
oruebel Sep 19, 2024
89f6d29
Fix static assert for ReadDataWrapper
oruebel Sep 19, 2024
5608c5a
Sync add_read with main branch (#101)
oruebel Sep 19, 2024
8bbecb8
Merge branch 'add_read' into add_container_read
oruebel Sep 19, 2024
c7ced4e
Merge branch 'main' into add_read
oruebel Sep 19, 2024
dd01ad3
Merge branch 'main' into add_read
oruebel Sep 20, 2024
968fcf0
Fix formatting and docs error after merge with main
oruebel Sep 20, 2024
b424eaf
Merge branch 'add_read' into add_container_read
oruebel Sep 20, 2024
8aa5680
Fix formatting after merge
oruebel Sep 20, 2024
5798145
Remove SpikeEventSeries.neurodata_type
oruebel Sep 20, 2024
8832b04
Register SpikeEventSeries as a type
oruebel Sep 20, 2024
f244d8c
Updated RegisterTypes to allow overwrite of the typename to use and o…
oruebel Sep 21, 2024
c78e7cb
Fix code formatting
oruebel Sep 21, 2024
9d7f408
Add missing description for DynamicTableRegion
oruebel Sep 21, 2024
435866c
Fix #109 Add missing axis attribute for channel_conversion and remove…
oruebel Sep 21, 2024
ce3227c
Remove undefined functions from Device
oruebel Sep 21, 2024
cc0cd84
Rename member variable in ElectricalSeries
oruebel Sep 21, 2024
f99ed91
Rename member variable in SpikeEventSeries
oruebel Sep 21, 2024
6a4876f
Added mergePaths functions and made functions in Utils.hpp static inline
oruebel Sep 21, 2024
af28b29
Updated ElectrodeTable to use mergePaths method
oruebel Sep 21, 2024
c222955
Updated DynamicTable to use mergePaths method
oruebel Sep 21, 2024
0d402f3
Update ElectrodeGroup to use mergePaths
oruebel Sep 21, 2024
156910c
Updated ElectricalSeries to use mergePaths
oruebel Sep 21, 2024
962faaa
Updated TimerSeries to use mergePaths function
oruebel Sep 21, 2024
8f13baf
Updated NWBFile to use the mergePaths function
oruebel Sep 21, 2024
bf92ce2
Updated ElectrodeTable static paths to not used trailing / for consis…
oruebel Sep 22, 2024
c2251a8
Fix Doxygen error by extracting also static members in the docs
oruebel Sep 22, 2024
f3e30cd
Fix section level in install.dox
oruebel Sep 22, 2024
cea343b
Update ReadDataWrapper to use m_ member naming convention
oruebel Sep 22, 2024
7c884d4
Updated DataBlock / DataBlockGeneric to avoid shadowing of constructo…
oruebel Sep 22, 2024
8145382
Fix reference error in read.dox
oruebel Sep 22, 2024
078c4f9
Add ReadDataWrapper isType, getPath, getIO methods and update docstrings
oruebel Sep 22, 2024
98377cb
Create macro DEFINE_FIELD to simplify creating access methods for fie…
oruebel Sep 22, 2024
281375c
Replace previous field access methods in TimeSeries with DEFINE_FIELD…
oruebel Sep 22, 2024
9eb00cf
Replace TimeSeries.dataLazy and resolutionLazy with DEFINE_FIELD defi…
oruebel Sep 22, 2024
90803a8
Update the Doxygen built to expand the DEFINE_FIELD macro to document…
oruebel Sep 22, 2024
4dfb541
Fix spellcheck
oruebel Sep 22, 2024
9b9c8c3
Fix section levels in read.dox
oruebel Sep 22, 2024
3c4b2d7
Add docs for using the DEFINE_FIELD macro
oruebel Sep 22, 2024
aad6928
Added attributeExists method on IO and ReadDataWrapper::exists method…
oruebel Sep 22, 2024
5a411c4
Add TimeSeries.descriptionLazy field to test that reading string attr…
oruebel Sep 22, 2024
daca8f2
Added function getGroupObjects to the I/O to allow gettings all objec…
oruebel Sep 22, 2024
1f81e6d
Add BaseIO::findTypes method to search for neurodata_types in a file
oruebel Sep 22, 2024
3affcca
Add example for searching for typed objects
oruebel Sep 23, 2024
30e1226
Update ElectrodeTable to use m_ member names
oruebel Sep 23, 2024
fa6a981
Added field definitions for TimeSeries
oruebel Sep 23, 2024
a0e02b2
Add some design docs about reading registered types
oruebel Sep 24, 2024
fbed92c
Update read types design figure
oruebel Sep 24, 2024
d4c2e64
Minor update to docs of RegisteredType
oruebel Sep 24, 2024
bfaabb8
Update docs/pages/userdocs/read.dox
oruebel Sep 24, 2024
a439212
Update src/io/ReadIO.hpp
oruebel Sep 24, 2024
5f28fb0
Update src/io/ReadIO.hpp
oruebel Sep 24, 2024
a9725b2
Rename ReadDataWrapper.is_dataset
oruebel Sep 24, 2024
e70949c
Update src/io/hdf5/HDF5IO.hpp
oruebel Sep 24, 2024
d1da5d1
Remove duplicate code in NWBFile
oruebel Sep 24, 2024
12a86a5
Remove outdated ToDo item
oruebel Sep 24, 2024
423f3d7
Apply suggestions on docs from code review
oruebel Oct 2, 2024
ae66f33
Merge branch 'main' into add_read
oruebel Oct 22, 2024
69df3e0
Fix build error after merge
oruebel Oct 22, 2024
415926c
Merge branch 'add_read' into add_container_read
oruebel Oct 22, 2024
a93cadd
Fix build error due to error during merge with base branch
oruebel Oct 22, 2024
2554667
Apply suggestions from code review
oruebel Oct 22, 2024
6c57527
Fix read.dox figure based on suggestion
oruebel Oct 23, 2024
a7cf936
Fix docs based on code review
oruebel Oct 23, 2024
3d89d78
update getAttribute method to detect object type
stephprince Dec 12, 2024
c22d658
update read example
stephprince Dec 12, 2024
a91cc91
add file mode options and readonly mode to io
stephprince Dec 12, 2024
b20388c
update example to use readonly
stephprince Dec 12, 2024
20afbae
add getter functions to Container classes with attributes
stephprince Dec 18, 2024
20813c2
fix formatting
stephprince Dec 18, 2024
f211978
update lint workflow
stephprince Dec 18, 2024
0b7d181
add NWBFile fields
stephprince Dec 19, 2024
a5cda51
update filenames
stephprince Dec 19, 2024
6a7bb45
remove duplicate file mode checks
stephprince Dec 19, 2024
bfa740a
Merge pull request #91 from NeurodataWithoutBorders/add_container_read
stephprince Dec 19, 2024
ddb8f50
Merge branch 'main' into add_read
oruebel Dec 22, 2024
54d55da
Fix spelling and complete merge
oruebel Dec 22, 2024
8492bf7
Fix missing merge in file
oruebel Dec 22, 2024
9ed9bd3
Install Boost multi-array in windows action
oruebel Dec 22, 2024
f6b306b
Use std::vector instead of variable-length arrays to avoid Windows bu…
oruebel Dec 22, 2024
7b88122
Add note to docs to clarify non-virtual DEFINE_FIELD
oruebel Dec 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/codespell.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ on:
- main

pull_request:
branches:
- main
#branches:
oruebel marked this conversation as resolved.
Show resolved Hide resolved
#- main
workflow_dispatch:

jobs:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/doxygen-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ name: Doxygen build test

on:
pull_request:
branches:
- main
#branches:
#- main

jobs:
test:
Expand All @@ -17,7 +17,7 @@ jobs:
uses: actions/checkout@v4
with:
submodules: "true"

- name: Install dependencies - macos
run: brew install hdf5 boost catch2 doxygen graphviz

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ on:
- main

pull_request:
branches:
- main
#branches:
#- main
workflow_dispatch:

jobs:
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ on:
- main

pull_request:
branches:
- main
#branches:
#- main
workflow_dispatch:

jobs:
Expand Down Expand Up @@ -39,7 +39,7 @@ jobs:
git checkout "v3.5.3"
cmake -Bbuild -H. -DBUILD_TESTING=OFF
sudo cmake --build build/ --target install

- name: Install dependencies - macos
if: matrix.os == 'macos-latest'
run: brew install hdf5 boost catch2
Expand All @@ -48,7 +48,7 @@ jobs:
if: matrix.os == 'windows-latest'
run: |
cd "${VCPKG_INSTALLATION_ROOT}"
vcpkg install hdf5[cpp]:x64-windows boost-date-time:x64-windows boost-endian:x64-windows boost-uuid:x64-windows catch2:x64-windows
vcpkg install hdf5[cpp]:x64-windows boost-date-time:x64-windows boost-endian:x64-windows boost-uuid:x64-windows boost-multi-array:x64-windows catch2:x64-windows
vcpkg integrate install

- name: Configure
Expand All @@ -74,7 +74,7 @@ jobs:

sanitize:
needs: test

runs-on: ubuntu-latest

steps:
Expand Down
9 changes: 7 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,24 @@ include(cmake/variables.cmake)

add_library(
aqnwb_aqnwb
src/BaseIO.cpp
src/io/BaseIO.cpp
src/Channel.cpp
src/hdf5/HDF5IO.cpp
src/io/hdf5/HDF5IO.cpp
src/io/hdf5/HDF5RecordingData.cpp
src/nwb/NWBFile.cpp
src/nwb/RecordingContainers.cpp
src/nwb/RegisteredType.cpp
src/nwb/base/TimeSeries.cpp
src/nwb/device/Device.cpp
src/nwb/ecephys/ElectricalSeries.cpp
src/nwb/ecephys/SpikeEventSeries.cpp
src/nwb/file/ElectrodeGroup.cpp
src/nwb/file/ElectrodeTable.cpp
src/nwb/hdmf/base/Container.cpp
src/nwb/hdmf/base/Data.cpp
src/nwb/hdmf/table/DynamicTable.cpp
src/nwb/hdmf/table/VectorData.cpp
src/nwb/hdmf/table/ElementIdentifiers.cpp
)

add_library(aqnwb::aqnwb ALIAS aqnwb_aqnwb)
Expand Down
20 changes: 20 additions & 0 deletions docs/Doxyfile.in
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,34 @@
PROJECT_NAME = "@PROJECT_NAME@"
PROJECT_NUMBER = "@PROJECT_VERSION@"


# Expand the DEFINE_FIELD macro to create documentation also for functions created by
# this macro as part of the RegisterType.hpp logic, which simplifies the creation
# of functions for lazy read access. Unfortunately, expanding the macro directly
# from the source code directly for some reason did not work with Doxygen and
# using "EXPAND_AS_DEFINED = DEFINE_FIELD" also failed. As a workaround we here define
# a simplified version of the macro as part of the PREDEFINED key to create a
# simplified expansion of the macro for documentation purposes
MACRO_EXPANSION = YES
PREDEFINED += "DEFINE_FIELD(name, storageObjectType, default_type, fieldPath, description)=/** description */ template<typename VTYPE = default_type> inline std::unique_ptr<IO::ReadDataWrapper<storageObjectType, VTYPE>> name() const;"
EXPAND_ONLY_PREDEF = YES


# Add sources
INPUT = "@PROJECT_SOURCE_DIR@/src" "@PROJECT_SOURCE_DIR@/docs/pages"
RECURSIVE = YES
EXAMPLE_PATH = "@PROJECT_SOURCE_DIR@/tests" "@PROJECT_SOURCE_DIR@/.github/CODE_OF_CONDUCT.md" "@PROJECT_SOURCE_DIR@/Legal.txt" "@PROJECT_SOURCE_DIR@/LICENSE"
IMAGE_PATH = "@PROJECT_SOURCE_DIR@/resources/images"
EXTRACT_ALL = YES
RECURSIVE = YES
OUTPUT_DIRECTORY = "@DOXYGEN_OUTPUT_DIRECTORY@"

# Also show private members in the docs,
EXTRACT_PRIVATE = YES
# Also show static members in the docs
EXTRACT_STATIC = YES
# HIDE_UNDOC_MEMBERS = YES

# Enable Markdown support
MARKDOWN_SUPPORT = YES

Expand Down
1 change: 1 addition & 0 deletions docs/pages/1_userdocs.dox
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
*
* - \subpage user_install_page
* - \subpage workflow
* - \subpage read_page
* - \subpage hdf5io
*/
1 change: 1 addition & 0 deletions docs/pages/2_devdocs.dox
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* - \subpage testing
* - \subpage dev_docs_page
* - \subpage nwb_schema_page
* - \subpage registered_type_page
* - \subpage code_of_conduct_page
* - \subpage license_page
* - \subpage copyright_page
Expand Down
2 changes: 1 addition & 1 deletion docs/pages/devdocs/documentation.dox
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
*
* To display a code snippet from our example in the documentation we can use the
* ``\snippet <file> <label>`` Doxygen command in our ``*.dox`` documentation file.
* For example to just show the line where we create the \ref AQNWB::HDF5::HDF5IO "HDF5IO
* For example to just show the line where we create the \ref AQNWB::IO::HDF5::HDF5IO "HDF5IO"
* object we use:
*
* \code{.sh}
Expand Down
215 changes: 215 additions & 0 deletions docs/pages/devdocs/registered_types.dox
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
/**
*
* \page registered_type_page Implementing a new Neurodata Type
*
* \tableofcontents
*
*
*
* New neurodata_types typically inherit from at least either \ref AQNWB::NWB::Container "Container"
* or \ref AQNWB::NWB::Data "Data", or a more specialized type of the two. In any case,
* all classes that represent a ``neurodata_type`` defined in the schema should be implemented
* as a subtype of \ref AQNWB::NWB::RegisteredType "RegisteredType".
*
* @section implement_registered_type How to Implement a RegisteredType
*
* To implement a subclass of \ref AQNWB::NWB::RegisteredType "RegisteredType", follow these steps:
*
* 1. Include the `RegisteredType.hpp` header file in your subclass header file.
* @code
* #include "nwb/RegisteredType.hpp"
* @endcode
*
* 2. Define your subclass by inheriting from \ref AQNWB::NWB::RegisteredType "RegisteredType".
* Ensure that your subclass implements a constructor with the arguments
* `(const std::string& path, std::shared_ptr<IO::BaseIO> io)`,
* as the "create" method expects this constructor signature.
* @code
* class MySubClass : public AQNWB::NWB::RegisteredType {
* public:
* MySubClass(const std::string& path, std::shared_ptr<IO::BaseIO> io)
* : RegisteredType(path, io) {}
*
* // Implement any additional methods or overrides here
* };
* @endcode
*
* 3. Use the \ref REGISTER_SUBCLASS macro to register your subclass. This should usually appear in
* the header (`hpp`) file as part of the class definition:
* @code
* REGISTER_SUBCLASS(MySubClass, "my-namespace")
* @endcode
*
* 4. In the corresponding source (`cpp`) file, initialize the static member to trigger the registration
* using the \ref REGISTER_SUBCLASS_IMPL macro:
* @code
* #include "MySubClass.h"
*
* // Initialize the static member to trigger registration
* REGISTER_SUBCLASS_IMPL(MySubClass)
* @endcode
*
* 5. To define getter methods for lazy read access to datasets and attributes that belong to our type,
* we can use the \ref DEFINE_FIELD macro. This macro creates a standard method for retrieving a
* \ref AQNWB::IO::ReadDataWrapper "ReadDataWrapper" for lazy reading for the field:
* @code
* DEFINE_FIELD(getData, DatasetField, float, "data", The main data)
* @endcode
*
* \warning
* To ensure proper function on read, the name of the class should match the name of the
* ``neurodata_type`` as defined in the schema. Similarly, "my-namespace" should match
* the name of the namespace in the schema (e.g., "core", "hdmf-common"). In this way
* we can look up the corresponding class for an object in a file based on the
* ``neurodata_type`` and ``namespace`` attributes stored in the file.
*
* \note
* A special version of the ``REGISTER_SUBCLASS`` macro, called ``REGISTER_SUBCLASS_WITH_TYPENAME``,
* allows setting the typename explicitly as a third argument. This is for the **special case**
* where we want to implement a class for a modified type that does not have its
* own `neurodata_type` in the NWB schema. An example is `ElectrodesTable` in NWB <v2.7, which
* did not have an assigned `neurodata_type`, but was implemented as a regular
* `DynamicTable`. To allow us to define a class `ElectrodeTable` to help with writing the table
* we can then use ``REGISTER_SUBCLASS_WITH_TYPENAME(ElectrodeTable, "core", "DynamicTable")``
* in the `ElectrodesTable` class. This ensures that the `neurodata_type` attribute is set
* correctly to `DynamicTable` on write instead of `ElectrodesTable`. However, on read this
* will by default not use the `ElectrodesTable` class but the regular `DynamicTable` class
* since that is what the schema is indicating to use. In the registry, the class will still
* be registered under the ``core::ElectrodesTable`` key, but with "DynamicTable" as the
* typename value and the `ElectrodesTable.getTypeName` automatic override returning
* the indicated typename instead of the classname.
*
* \note
* ``DEFINE_FIELD`` creates templated, non-virtual read functions. This means if we
* want to "redefine" a field in a child class by calling ``DEFINE_FIELD`` again, then
* the function will be "hidden" instead of "override". This is important to remember
* when casting a pointer to a base type, as in this case the implementation from the
* base type will be used since the function created by ``DEFINE_FIELD`` is not virtual.
*
*
* @subsection implement_registered_type_example Example: Implementing a new type
*
* *MySubClass.hpp*
* @code
* #pragma once
* #include "RegisteredType.hpp"
*
* class MySubClass : public AQNWB::NWB::RegisteredType
* {
* public:
* MySubClass(const std::string& path, std::shared_ptr<IO::BaseIO> io)
* : RegisteredType(path, io) {}
*
* DEFINE_FIELD(getData, DatasetField, float, "data", The main data)
*
* REGISTER_SUBCLASS(MySubClass, "my-namespace")
* };
* @endcode
*
* *MySubClass.cpp*
* @code
* #include "MySubClass.h"
*
* // Initialize the static member to trigger registration
* REGISTER_SUBCLASS_IMPL(MySubClass)
* @endcode
*
* @section type_registry How the Type Registry in RegisteredType Works
*
* The type registry in \ref AQNWB::NWB::RegisteredType "RegisteredType" allows for dynamic creation of registered subclasses by name. Here is how it works:
*
* 1. **Registry Storage**:
* - The registry is implemented using 1) an `std::unordered_set` to store subclass names (which can be
* accessed via \ref AQNWB::NWB::RegisteredType::getRegistry "getRegistry()") and
* 2) an `std::unordered_map` to store factory functions for creating instances of the subclasses
* (which can be accessed via \ref AQNWB::NWB::RegisteredType::getFactoryMap() "getFactoryMap()").
* The factory methods are the required constructor that uses the io and path as input.
* - These are defined as static members within the \ref AQNWB::NWB::RegisteredType "RegisteredType" class.
*
* 2. **Registration**:
* - The \ref AQNWB::NWB::RegisteredType::registerSubclass "registerSubclass" method is used to add a
* subclass name and its corresponding factory function to the registry.
* - This method is called via the `REGISTER_SUBCLASS` macro, which defines a static method (`registerSubclass()`)
* and static member (`registered_`) to trigger the registration when the subclass is loaded.
*
* 3. **Dynamic Creation**:
* - The \ref AQNWB::NWB::RegisteredType::create "create" method is used to create an instance of a registered subclass by name.
* - This method looks up the subclass name in the registry and calls the corresponding factory function to create an instance.
*
* 4. **Automatic Registration**:
* - The `REGISTER_SUBCLASS_IMPL` macro initializes the static member (`registered_`), which triggers the
* \ref AQNWB::NWB::RegisteredType::registerSubclass "registerSubclass" method
* and ensures that the subclass is registered when the program starts.
*
* 5. **Class Name and Namespace Retrieval**:
* - The \ref AQNWB::NWB::RegisteredType::getTypeName "getTypeName" and
* \ref AQNWB::NWB::RegisteredType::getNamespace "getNamespace" return the string name of the
* class and namespace, respectively. The `REGISTER_SUBCLASS` macro implements an automatic
* override of the methods to ensure the appropriate type and namespace string are returned.
* These methods should, hence, not be manually overridden by subclasses, to ensure consistency
* in type identification.
*
*
* @section use_registered_type_registry How to Use the RegisteredType Registry
*
* The \ref AQNWB::NWB::RegisteredType "RegisteredType" registry allows for dynamic creation and management of registered subclasses. Here is how you can use it:
*
* 1. **Creating Instances Dynamically**:
* - Use the \ref AQNWB::NWB::RegisteredType::create "create" method to create an instance of a registered subclass by name.
* - This method takes the subclass name, path, and a shared pointer to the IO object as arguments. This
* illustrates how we can read a specific typed object in an NWB file.
* \snippet tests/examples/test_RegisteredType_example.cpp example_RegisterType_get_type_instance
*
* 2. **Retrieving Registered Subclass Names**:
* - Use the \ref AQNWB::NWB::RegisteredType::getRegistry "getRegistry" method to retrieve the
* set of registered subclass names.
* \snippet tests/examples/test_RegisteredType_example.cpp example_RegisterType_get_registered_names
*
* 3. **Retrieving the Factory Map**:
* - Use the \ref AQNWB::NWB::RegisteredType::getFactoryMap "getFactoryMap" method to retrieve
* the map of factory functions for creating instances of registered subclasses.
* \snippet tests/examples/test_RegisteredType_example.cpp example_RegisterType_get_registered_factories
*
* @subsection use_registered_type_registry_example Example: Using the type registry
*
* \snippet tests/examples/test_RegisteredType_example.cpp example_RegisterType_full
*
* @section use_the_define_field_macro How to Use the DEFINE_FIELD macro
*
* The \ref DEFINE_FIELD macro takes the following main inputs:
*
* * ``name``: The name of the function to generate.
* * ``storageObjectType`` : One of either \ref AQNWB::NWB::DatasetField "DatasetField" or
* \ref AQNWB::NWB::AttributeField "AttributeField" to define the type of storage object used
* to store the field.
* * ``default_type`` : The default data type to use. If not known, we can use ``std::any``.
* * ``fieldPath`` : Literal string with the relative path to the field within the schema of the
* respective neurodata_type. This is automatically being expanded at runtime to the full path.
* * ``description`` : Description of the field to include in the docstring for the docs
*
* All of these inputs are required. A typical example will look as follows:
*
* @code
* DEFINE_FIELD(getData, DatasetField, float, "data", The main data)
* @endcode
*
* The compiler will then expand this definition to create a new method
* called ``getData`` that will return a \ref AQNWB::IO::ReadDataWrapper "ReadDataWrapper"
* for lazy reading for the field. The corresponding expanded function will look something like:
*
* @code
* template<typename VTYPE = float>
* inline std::unique_ptr<IO::ReadDataWrapper<DatasetField, VTYPE>> getData() const
* {
* return std::make_unique<IO::ReadDataWrapper<DatasetField, VTYPE>>(
* m_io,
* AQNWB::mergePaths(m_path, fieldPath));
* }
* @endcode
*
* See \ref read_page for an example of how to use such methods (e.g.,
* \ref AQNWB::NWB::TimeSeries::readData "TimeSeries::readData" )
* for reading data fields from a file.
*
*
*/
Loading
Loading