diff --git a/wave_containers/include/wave/containers/impl/landmark_measurement_container.hpp b/wave_containers/include/wave/containers/impl/landmark_measurement_container.hpp index 7b4f8341..0ad4b7f3 100644 --- a/wave_containers/include/wave/containers/impl/landmark_measurement_container.hpp +++ b/wave_containers/include/wave/containers/impl/landmark_measurement_container.hpp @@ -19,7 +19,11 @@ using boost::multi_index::tag; * holding measurements of type T. See `wave::internal::measurement_container`. */ template -struct landmark_container { +struct container_traits<::wave::LandmarkMeasurementContainer> { + // Define to give MeasurementContainerBase access to its derived type + using MeasurementType = T; + + // Then, set up boost::multi_index_container // First, define which members of the Measurement object are used as keys struct time_key : member {}; struct sensor_key : member {}; @@ -38,18 +42,15 @@ struct landmark_container { // multi_index_container is generated struct time_index {}; struct sensor_index {}; - struct sensor_composite_index {}; struct landmark_index {}; struct composite_index {}; // Define an index for each key. Each index will be accessible via its tag struct indices - : indexed_by< - ordered_non_unique, time_key>, - ordered_non_unique, sensor_key>, - ordered_non_unique, landmark_key>, - ordered_unique, combined_key>, - ordered_unique, sensor_composite_key>> {}; + : indexed_by, time_key>, + ordered_non_unique, landmark_key>, + ordered_unique, combined_key>, + ordered_unique, sensor_composite_key>> {}; // Finally, define the multi_index_container type. // This is the container type which can actually be used to make objects @@ -58,8 +59,7 @@ struct landmark_container { // For convenience, get the type of the indices, using their tags using composite_type = typename type::template index::type; using time_type = typename type::template index::type; - using sensor_composite_type = - typename type::template index::type; + using sensor_type = typename type::template index::type; using landmark_type = typename type::template index::type; // Define a view indexed by time, for complex searches @@ -73,65 +73,6 @@ struct landmark_container { template LandmarkMeasurementContainer::LandmarkMeasurementContainer() {} - -template -template -LandmarkMeasurementContainer::LandmarkMeasurementContainer(InputIt first, - InputIt last) { - this->composite().insert(first, last); -}; - -template -std::pair::iterator, bool> -LandmarkMeasurementContainer::insert(const MeasurementType &m) { - return this->composite().insert(m); -} - -template -template -void LandmarkMeasurementContainer::insert(InputIt first, InputIt last) { - return this->composite().insert(first, last); -} - -template -template -std::pair::iterator, bool> -LandmarkMeasurementContainer::emplace(Args &&... args) { -// Support Boost.MultiIndex <= 1.54, which does not have emplace() -#if BOOST_VERSION < 105500 - return this->composite().insert( - MeasurementType{std::forward(args)...}); -#else - return this->composite().emplace(std::forward(args)...); -#endif -} - -template -typename LandmarkMeasurementContainer::size_type -LandmarkMeasurementContainer::erase(const TimeType &t, - SensorIdType s, - LandmarkIdType id) { - auto &composite = this->composite(); - auto it = composite.find(boost::make_tuple(t, s, id)); - if (it == composite.end()) { - return 0; - } - composite.erase(it); - return 1; -} - -template -typename LandmarkMeasurementContainer::iterator -LandmarkMeasurementContainer::erase(iterator position) noexcept { - return this->composite().erase(position); -} - -template -typename LandmarkMeasurementContainer::iterator -LandmarkMeasurementContainer::erase(iterator first, iterator last) noexcept { - return this->composite().erase(first, last); -} - template typename LandmarkMeasurementContainer::ValueType LandmarkMeasurementContainer::get(const TimeType &t, @@ -147,38 +88,6 @@ LandmarkMeasurementContainer::get(const TimeType &t, return iter->value; } -template -std::pair::sensor_iterator, - typename LandmarkMeasurementContainer::sensor_iterator> -LandmarkMeasurementContainer::getAllFromSensor(const SensorIdType &s) const - noexcept { - // Get the measurements sorted by sensor_id - const auto &sensor_composite_index = this->storage.template get< - typename internal::landmark_container::sensor_composite_index>(); - - return sensor_composite_index.equal_range(s); -}; - -template -std::pair::iterator, - typename LandmarkMeasurementContainer::iterator> -LandmarkMeasurementContainer::getTimeWindow(const TimeType &start, - const TimeType &end) const - noexcept { - // Consider a "backward" window empty - if (start > end) { - return {this->end(), this->end()}; - } - - // The composite index is already sorted by time first, thus it's enough to - // do a partial search. Find the start and end of the range. - const auto &composite = this->composite(); - auto iter_begin = composite.lower_bound(boost::make_tuple(start)); - auto iter_end = composite.upper_bound(boost::make_tuple(end)); - - return {iter_begin, iter_end}; -} - template std::vector::LandmarkIdType> LandmarkMeasurementContainer::getLandmarkIDs() const { @@ -190,8 +99,8 @@ std::vector::LandmarkIdType> LandmarkMeasurementContainer::getLandmarkIDsInWindow( const TimeType &start, const TimeType &end) const { // Use the index sorted by landmark id - const auto &landmark_index = this->storage.template get< - typename internal::landmark_container::landmark_index>(); + const auto &landmark_index = + this->storage.template get(); auto unique_ids = std::vector{}; // Iterate over all measurements sorted by time, first then landmark_id. @@ -232,8 +141,8 @@ LandmarkMeasurementContainer::getTrackInWindow(const SensorIdType &s, return Track{}; } - const auto &landmark_index = this->storage.template get< - typename internal::landmark_container::landmark_index>(); + const auto &landmark_index = + this->storage.template get(); // Get all measurements with desired landmark id const auto res = landmark_index.equal_range(id); @@ -245,7 +154,7 @@ LandmarkMeasurementContainer::getTrackInWindow(const SensorIdType &s, // http://www.boost.org/doc/libs/1_63_0/libs/multi_index/doc/examples.html#example6 // // While iterating, pick the measurements with desired sensor_id - auto time_view = typename internal::landmark_container::time_view{}; + auto time_view = typename traits::time_view{}; for (auto it = res.first; it != res.second; ++it) { if (it->sensor_id == s) { // insert a pointer to the measurement @@ -266,70 +175,4 @@ LandmarkMeasurementContainer::getTrackInWindow(const SensorIdType &s, return track; }; -template -bool LandmarkMeasurementContainer::empty() const noexcept { - return this->composite().empty(); -} - -template -typename LandmarkMeasurementContainer::size_type -LandmarkMeasurementContainer::size() const noexcept { - return this->composite().size(); -} - -template -void LandmarkMeasurementContainer::clear() noexcept { - return this->composite().clear(); -} - -template -typename LandmarkMeasurementContainer::iterator -LandmarkMeasurementContainer::begin() noexcept { - return this->composite().begin(); -} - -template -typename LandmarkMeasurementContainer::iterator -LandmarkMeasurementContainer::end() noexcept { - return this->composite().end(); -} - -template -typename LandmarkMeasurementContainer::const_iterator -LandmarkMeasurementContainer::begin() const noexcept { - return this->composite().begin(); -} - -template -typename LandmarkMeasurementContainer::const_iterator -LandmarkMeasurementContainer::end() const noexcept { - return this->composite().end(); -} - -template -typename LandmarkMeasurementContainer::const_iterator -LandmarkMeasurementContainer::cbegin() const noexcept { - return this->composite().cbegin(); -} - -template -typename LandmarkMeasurementContainer::const_iterator -LandmarkMeasurementContainer::cend() const noexcept { - return this->composite().cend(); -} - -template -typename LandmarkMeasurementContainer::composite_type & -LandmarkMeasurementContainer::composite() noexcept { - return this->storage.template get< - typename internal::landmark_container::composite_index>(); -} - -template -const typename LandmarkMeasurementContainer::composite_type & -LandmarkMeasurementContainer::composite() const noexcept { - return this->storage.template get< - typename internal::landmark_container::composite_index>(); -} - } // namespace wave diff --git a/wave_containers/include/wave/containers/impl/measurement_container.hpp b/wave_containers/include/wave/containers/impl/measurement_container.hpp index 4c9496af..feff0868 100644 --- a/wave_containers/include/wave/containers/impl/measurement_container.hpp +++ b/wave_containers/include/wave/containers/impl/measurement_container.hpp @@ -31,8 +31,13 @@ using boost::multi_index::tag; * * Note this template is for convenience only, no objects are constructed. */ + template -struct measurement_container { +struct container_traits<::wave::MeasurementContainer> { + // Define to give MeasurementContainerBase access to its derived type + using MeasurementType = T; + + // Then, set up boost::multi_index_container // First, define which members of the Measurement object are used as keys // Specify that the time key corresponds to the time_point member struct time_key : member {}; @@ -55,10 +60,6 @@ struct measurement_container { ordered_non_unique, sensor_key>, ordered_unique, sensor_and_time_key>> { }; - - // Note we use separate struct definitions above, instead of typedefs, to - // reduce the length of the name printed by the compiler. - // Finally, define the multi_index_container type. // This is the container type which can actually be used to make objects using type = boost::multi_index_container>; @@ -79,62 +80,6 @@ struct measurement_container { template MeasurementContainer::MeasurementContainer() {} -/** Construct the container with the contents of a range */ -template -template -MeasurementContainer::MeasurementContainer(InputIt first, InputIt last) { - this->composite().insert(first, last); -}; - -template -std::pair::iterator, bool> -MeasurementContainer::insert(const MeasurementType &m) { - return this->composite().insert(m); -} - -template -template -void MeasurementContainer::insert(InputIt first, InputIt last) { - return this->composite().insert(first, last); -} - -template -template -std::pair::iterator, bool> -MeasurementContainer::emplace(Args &&... args) { -// Support Boost.MultiIndex <= 1.54, which does not have emplace() -#if BOOST_VERSION < 105500 - return this->composite().insert( - MeasurementType{std::forward(args)...}); -#else - return this->composite().emplace(std::forward(args)...); -#endif -} - -template -typename MeasurementContainer::size_type MeasurementContainer::erase( - const TimeType &t, const SensorIdType &s) { - auto &composite = this->composite(); - auto it = composite.find(boost::make_tuple(t, s)); - if (it == composite.end()) { - return 0; - } - composite.erase(it); - return 1; -} - -template -typename MeasurementContainer::iterator MeasurementContainer::erase( - iterator position) noexcept { - return this->composite().erase(position); -} - -template -typename MeasurementContainer::iterator MeasurementContainer::erase( - iterator first, iterator last) noexcept { - return this->composite().erase(first, last); -} - template typename MeasurementContainer::ValueType MeasurementContainer::get( const TimeType &t, const SensorIdType &s) const { @@ -144,12 +89,12 @@ typename MeasurementContainer::ValueType MeasurementContainer::get( // http://www.boost.org/doc/libs/1_63_0/libs/multi_index/doc/examples.html#example6 // Find all measurements from this sensor - const auto &sensor_index = this->storage.template get< - typename internal::measurement_container::sensor_index>(); + const auto &sensor_index = + this->storage.template get(); const auto sensor_it = sensor_index.equal_range(s); // Construct a view, indexed by time, with only those measurements - auto time_view = typename internal::measurement_container::time_view{}; + auto time_view = typename traits::time_view{}; for (auto it = sensor_it.first; it != sensor_it.second; ++it) { time_view.insert(&*it); // the view holds pointers to the measurements } @@ -182,102 +127,4 @@ typename MeasurementContainer::ValueType MeasurementContainer::get( return interpolate(*p_prev, *p_next, t); } -template -std::pair::sensor_iterator, - typename MeasurementContainer::sensor_iterator> -MeasurementContainer::getAllFromSensor(const SensorIdType &s) const - noexcept { - // Get the measurements sorted by sensor_id - const auto &sensor_index = this->storage.template get< - typename internal::measurement_container::sensor_index>(); - - return sensor_index.equal_range(s); -}; - -template -std::pair::iterator, - typename MeasurementContainer::iterator> -MeasurementContainer::getTimeWindow(const TimeType &start, - const TimeType &end) const noexcept { - // Consider a "backward" window empty - if (start > end) { - return {this->end(), this->end()}; - } - - // The composite index is already sorted by time first, thus it's enough to - // do a partial search. Find the start and end of the range. - const auto &composite = this->composite(); - auto iter_begin = composite.lower_bound(boost::make_tuple(start)); - auto iter_end = composite.upper_bound(boost::make_tuple(end)); - - return {iter_begin, iter_end}; -} - -template -bool MeasurementContainer::empty() const noexcept { - return this->composite().empty(); -} - -template -typename MeasurementContainer::size_type MeasurementContainer::size() - const noexcept { - return this->composite().size(); -} - -template -void MeasurementContainer::clear() noexcept { - return this->composite().clear(); -} - -template -typename MeasurementContainer::iterator -MeasurementContainer::begin() noexcept { - return this->composite().begin(); -} - -template -typename MeasurementContainer::iterator -MeasurementContainer::end() noexcept { - return this->composite().end(); -} - -template -typename MeasurementContainer::const_iterator -MeasurementContainer::begin() const noexcept { - return this->composite().begin(); -} - -template -typename MeasurementContainer::const_iterator MeasurementContainer::end() - const noexcept { - return this->composite().end(); -} - -template -typename MeasurementContainer::const_iterator -MeasurementContainer::cbegin() const noexcept { - return this->composite().cbegin(); -} - -template -typename MeasurementContainer::const_iterator MeasurementContainer::cend() - const noexcept { - return this->composite().cend(); -} - -template -typename MeasurementContainer::composite_type & -MeasurementContainer::composite() noexcept { - return this->storage.template get< - typename internal::measurement_container::composite_index>(); -} - -template -const typename MeasurementContainer::composite_type & -MeasurementContainer::composite() const noexcept { - return this->storage.template get< - typename internal::measurement_container::composite_index>(); -} - - } // namespace wave diff --git a/wave_containers/include/wave/containers/impl/measurement_container_base.hpp b/wave_containers/include/wave/containers/impl/measurement_container_base.hpp new file mode 100644 index 00000000..7dc69c36 --- /dev/null +++ b/wave_containers/include/wave/containers/impl/measurement_container_base.hpp @@ -0,0 +1,161 @@ +#include + +namespace wave { + +/** Construct the container with the contents of a range */ +template +template +MeasurementContainerBase::MeasurementContainerBase(InputIt first, + InputIt last) { + this->composite().insert(first, last); +}; + +template +bool MeasurementContainerBase::empty() const noexcept { + return this->composite().empty(); +} + +template +typename MeasurementContainerBase::size_type +MeasurementContainerBase::size() const noexcept { + return this->composite().size(); +} + +template +std::pair::iterator, bool> +MeasurementContainerBase::insert(const MeasurementType &m) { + return this->composite().insert(m); +} + +template +template +void MeasurementContainerBase::insert(InputIt first, InputIt last) { + return this->composite().insert(first, last); +} + +template +template +std::pair::iterator, bool> +MeasurementContainerBase::emplace(Args &&... args) { +// Support Boost.MultiIndex <= 1.54, which does not have emplace() +#if BOOST_VERSION < 105500 + return this->composite().insert( + MeasurementType{std::forward(args)...}); +#else + return this->composite().emplace(std::forward(args)...); +#endif +} + +template +template +typename MeasurementContainerBase::size_type +MeasurementContainerBase::erase(Args &&... args) { + auto &composite = this->composite(); + auto it = composite.find(boost::make_tuple(std::forward(args)...)); + if (it == composite.end()) { + return 0; + } + composite.erase(it); + return 1; +} + +template +typename MeasurementContainerBase::iterator +MeasurementContainerBase::erase(iterator position) noexcept { + return this->composite().erase(position); +} + +template +typename MeasurementContainerBase::iterator +MeasurementContainerBase::erase(iterator first, + iterator last) noexcept { + return this->composite().erase(first, last); +} + +template +void MeasurementContainerBase::clear() noexcept { + return this->composite().clear(); +} + +template +std::pair::sensor_iterator, + typename MeasurementContainerBase::sensor_iterator> +MeasurementContainerBase::getAllFromSensor(const SensorIdType &s) const + noexcept { + // Get the measurements sorted by sensor_id + const auto &sensor_index = + this->storage.template get(); + + return sensor_index.equal_range(s); +}; + +template +std::pair::iterator, + typename MeasurementContainerBase::iterator> +MeasurementContainerBase::getTimeWindow(const TimeType &start, + const TimeType &end) const + noexcept { + // Consider a "backward" window empty + if (start > end) { + return {this->end(), this->end()}; + } + + // The composite index is already sorted by time first, thus it's enough to + // do a partial search. Find the start and end of the range. + const auto &composite = this->composite(); + auto iter_begin = composite.lower_bound(boost::make_tuple(start)); + auto iter_end = composite.upper_bound(boost::make_tuple(end)); + + return {iter_begin, iter_end}; +} + +template +typename MeasurementContainerBase::iterator +MeasurementContainerBase::begin() noexcept { + return this->composite().begin(); +} + +template +typename MeasurementContainerBase::iterator +MeasurementContainerBase::end() noexcept { + return this->composite().end(); +} + +template +typename MeasurementContainerBase::const_iterator +MeasurementContainerBase::begin() const noexcept { + return this->composite().begin(); +} + +template +typename MeasurementContainerBase::const_iterator +MeasurementContainerBase::end() const noexcept { + return this->composite().end(); +} + +template +typename MeasurementContainerBase::const_iterator +MeasurementContainerBase::cbegin() const noexcept { + return this->composite().cbegin(); +} + +template +typename MeasurementContainerBase::const_iterator +MeasurementContainerBase::cend() const noexcept { + return this->composite().cend(); +} + +template +typename MeasurementContainerBase::traits::composite_type & +MeasurementContainerBase::composite() noexcept { + return this->storage.template get(); +} + +template +const typename MeasurementContainerBase::traits::composite_type & +MeasurementContainerBase::composite() const noexcept { + return this->storage.template get(); +} + + +} // namespace wave diff --git a/wave_containers/include/wave/containers/landmark_measurement_container.hpp b/wave_containers/include/wave/containers/landmark_measurement_container.hpp index efbbb740..ba4d3835 100644 --- a/wave_containers/include/wave/containers/landmark_measurement_container.hpp +++ b/wave_containers/include/wave/containers/landmark_measurement_container.hpp @@ -5,22 +5,12 @@ #ifndef WAVE_CONTAINERS_LANDMARK_MEASUREMENT_CONTAINER_HPP #define WAVE_CONTAINERS_LANDMARK_MEASUREMENT_CONTAINER_HPP -#include +#include "wave/containers/measurement_container_base.hpp" namespace wave { /** @addtogroup containers * @{ */ -using TimeType = std::chrono::steady_clock::time_point; - -/** Internal implementation details - for developers only */ -namespace internal { - -template -struct landmark_container; - -} // namespace internal - /** Container which stores landmark measurements. * * @tparam T is the stored measurement type. The `LandmarkMeasurement` class @@ -31,104 +21,44 @@ struct landmark_container; * - `sensor_id` (any type sortable by \c std::less) * - `landmark_id` (any type sortable by \c std::less) * - `value` (any type) + * + * The unique key for this container is the tuple (time_point, sensor_id, + * landmark_id). That is, an insertion will have an effect only if there is not + * already an element in the container with that key. When iterating over the + * container, elements are sorted lexicographically: first by time, then by + * sensor_id, then by landmark_id. */ template -class LandmarkMeasurementContainer { +class LandmarkMeasurementContainer + : public MeasurementContainerBase> { + using traits = internal::container_traits>; + public: + using Base = MeasurementContainerBase>; + // Types - /** Alias for the template parameter, giving the type of measurement stored + /** Alias for the template parameter, giving the type of Measurement stored * in this container */ - using MeasurementType = T; + using typename Base::MeasurementType; /** Alias for the measurement's value. * Note this does *not* correspond to a typical container's value_type. */ - using ValueType = decltype(MeasurementType::value); - /** Alias for the type of the sensor id */ - using SensorIdType = decltype(MeasurementType::sensor_id); + using typename Base::ValueType; + /** Alias for template parameter giving the type of the sensor id */ + using typename Base::SensorIdType; /** Alias for the type of the landmark id */ using LandmarkIdType = decltype(MeasurementType::landmark_id); /** A vector representing landmark / feature measurements across images */ using Track = std::vector; - - using iterator = - typename internal::landmark_container::composite_type::iterator; - using const_iterator = - typename internal::landmark_container::composite_type::const_iterator; - using sensor_iterator = - typename internal::landmark_container::sensor_composite_type::iterator; - using size_type = std::size_t; - // Constructors /** Default construct an empty container */ LandmarkMeasurementContainer(); - /** Construct the container with the contents of the range [first, last) */ - template - LandmarkMeasurementContainer(InputIt first, InputIt last); - - // Capacity - - /** Return true if the container has no elements. */ - bool empty() const noexcept; - - /** Return the number of elements in the container. */ - size_type size() const noexcept; - - // Modifiers - - /** Insert a Measurement if a measurement for the same time and sensor does - * not already exist. - * - * @return a pair p. If and only if insertion occurred, p.second is true and - * p.first points to the element inserted. - */ - std::pair insert(const MeasurementType &m); - - /** For each element of the range [first, last), inserts a Measurement if a - * measurement for the same time and sensor does not already exist. - * - * @param first, last iterators representing a valid range of Measurements, - * but not iterators into this container - */ - template - void insert(InputIt first, InputIt last); - - /** Insert a Measurement constructed from the arguments if a measurement for - * the same time and sensor does not already exist. - * - * @return a pair p. If and only if insertion occurred, p.second is true and - * p.first points to the element inserted. - */ - template - std::pair emplace(Args &&... args); - - /** Delete the element with the matching time, sensor, and landmark id if - * one exists. - * - * @return the number of elements deleted. - */ - size_type erase(const TimeType &t, SensorIdType s, LandmarkIdType id); - - /** Delete the element at `position` - * - * @param position a valid dereferenceable iterator of this container - * @return An iterator pointing to the element following the deleted one, or - * `end()` if it was the last. - */ - iterator erase(iterator position) noexcept; - - - /** Delete the elements in the range [first, last) - * - * @param first, last a valid range of this container - * @return `last` - */ - iterator erase(iterator first, iterator last) noexcept; - - /** Delete all elements */ - void clear() noexcept; + /** Inherit all non-default constuctors from base */ + using MeasurementContainerBase< + LandmarkMeasurementContainer>::MeasurementContainerBase; // Retrieval @@ -141,29 +71,6 @@ class LandmarkMeasurementContainer { */ ValueType get(const TimeType &t, SensorIdType s, LandmarkIdType id) const; - /** Get all measurements from the given sensor - * - * @return a pair of iterators representing the start and end of the range. - * If the range is empty, both iterators will be equal. - * - * @note because these iterators use the underlying ordered index of - * sensor_ids, they are not the same type as those from `begin()`, - * `getTimeWindow()`, etc. - */ - std::pair getAllFromSensor( - const SensorIdType &s) const noexcept; - - /** Get all measurements between the given times. - * - * @param start, end an inclusive range of times, with start <= end - * - * @return a pair of iterators representing the start and end of the range. - * If the range is empty, both iterators will be equal. - */ - std::pair getTimeWindow(const TimeType &start, - const TimeType &end) const - noexcept; - /** Get a list of all unique landmark IDs in the container */ std::vector getLandmarkIDs() const; @@ -188,26 +95,6 @@ class LandmarkMeasurementContainer { const LandmarkIdType &id, const TimeType &start, const TimeType &end) const noexcept; - - // Iterators - - iterator begin() noexcept; - iterator end() noexcept; - const_iterator begin() const noexcept; - const_iterator end() const noexcept; - const_iterator cbegin() const noexcept; - const_iterator cend() const noexcept; - - protected: - using composite_type = - typename internal::landmark_container::composite_type; - - // Helper to get the composite index - composite_type &composite() noexcept; - const composite_type &composite() const noexcept; - - // Internal multi_index_container - typename internal::landmark_container::type storage; }; /** @} group containers */ diff --git a/wave_containers/include/wave/containers/measurement_container.hpp b/wave_containers/include/wave/containers/measurement_container.hpp index be6334aa..dba47dd2 100644 --- a/wave_containers/include/wave/containers/measurement_container.hpp +++ b/wave_containers/include/wave/containers/measurement_container.hpp @@ -12,23 +12,12 @@ #ifndef WAVE_CONTAINERS_MEASUREMENT_CONTAINER_HPP #define WAVE_CONTAINERS_MEASUREMENT_CONTAINER_HPP -#include +#include "wave/containers/measurement_container_base.hpp" namespace wave { - /** @addtogroup containers * @{ */ -using TimeType = std::chrono::steady_clock::time_point; - -/** Internal implementation details - for developers only */ -namespace internal { - -template -struct measurement_container; - -} // namespace internal - /** Container which stores and transparently interpolates measurements. * * @tparam T is the stored measurement type. The Measurement class template @@ -44,147 +33,44 @@ struct measurement_container; * interpolate(const T&, const T&, const TimeType&) * ``` * must be defined for type `T`. + * + * The unique key for this container is the tuple (time_point, sensor_id). That + * is, an insertion will have an effect only if there is not already an element + * in the container with that key. When iterating over the container, elements + * are sorted lexicographically: first by time, then by sensor_id. */ template -class MeasurementContainer { +class MeasurementContainer + : public MeasurementContainerBase> { + using traits = internal::container_traits>; + public: + using Base = MeasurementContainerBase>; + // Types /** Alias for the template parameter, giving the type of Measurement stored * in this container */ - using MeasurementType = T; + using typename Base::MeasurementType; /** Alias for the measurement's value. * Note this does *not* correspond to a typical container's value_type. */ - using ValueType = decltype(MeasurementType::value); + using typename Base::ValueType; /** Alias for template parameter giving the type of the sensor id */ - using SensorIdType = decltype(MeasurementType::sensor_id); - - using iterator = - typename internal::measurement_container::composite_type::iterator; - using const_iterator = typename internal::measurement_container< - T>::composite_type::const_iterator; - using sensor_iterator = - typename internal::measurement_container::sensor_type::iterator; - using size_type = std::size_t; + using typename Base::SensorIdType; // Constructors /** Default construct an empty container */ MeasurementContainer(); - /** Construct the container with the contents of the range [first, last) */ - template - MeasurementContainer(InputIt first, InputIt last); - - // Capacity - - /** Return true if the container has no elements. */ - bool empty() const noexcept; - - /** Return the number of elements in the container. */ - size_type size() const noexcept; - - // Modifiers - - /** Insert a Measurement if a measurement for the same time and sensor does - * not already exist. - * - * @return a pair p. If and only if insertion occurred, p.second is true and - * p.first points to the element inserted. - */ - std::pair insert(const MeasurementType &); - - /** For each element of the range [first, last), inserts a Measurement if a - * measurement for the same time and sensor does not already exist. - * - * @param first, last iterators representing a valid range of Measurements, - * but not iterators into this container - */ - template - void insert(InputIt first, InputIt last); - - /** Insert a Measurement constructed from the arguments if a measurement for - * the same time and sensor does not already exist. - * - * @return a pair p. If and only if insertion occurred, p.second is true and - * p.first points to the element inserted. - */ - template - std::pair emplace(Args &&... args); - - /** Delete the element with the matching time and sensor id, if one exists. - * - * @return the number of elements deleted. - */ - size_type erase(const TimeType &t, const SensorIdType &s); - - /** Delete the element at `position` - * - * @param position a valid dereferenceable iterator of this container - * @return An iterator pointing to the element following the deleted one, or - * `end()` if it was the last. - */ - iterator erase(iterator position) noexcept; - - - /** Delete the elements in the range [first, last) - * - * @param first, last a valid range of this container - * @return `last` - */ - iterator erase(iterator first, iterator last) noexcept; - - - /** Delete all elements */ - void clear() noexcept; + /** Inherit all non-default constuctors from base */ + using MeasurementContainerBase< + MeasurementContainer>::MeasurementContainerBase; // Retrieval /** Get the value of a measurement with corresponding time and sensor id */ ValueType get(const TimeType &t, const SensorIdType &s) const; - - /** Get all measurements from the given sensor - * - * @return a pair of iterators representing the start and end of the range. - * If the range is empty, both iterators will be equal. - * - * @note because these iterators use the underlying ordered index of - * sensor_ids, they are not the same type as those from `begin()`, - * `getTimeWindow()`, etc. - */ - std::pair getAllFromSensor( - const SensorIdType &s) const noexcept; - - /** Get all measurements between the given times. - * - * @param start, end an inclusive range of times, with start <= end - * - * @return a pair of iterators representing the start and end of the range. - * If the range is empty, both iterators will be equal. - */ - std::pair getTimeWindow(const TimeType &start, - const TimeType &end) const - noexcept; - - // Iterators - - iterator begin() noexcept; - iterator end() noexcept; - const_iterator begin() const noexcept; - const_iterator end() const noexcept; - const_iterator cbegin() const noexcept; - const_iterator cend() const noexcept; - - private: - using composite_type = - typename internal::measurement_container::composite_type; - - // Helper to get the composite index - composite_type &composite() noexcept; - const composite_type &composite() const noexcept; - - // Internal multi_index_container - typename internal::measurement_container::type storage; }; /** @} group containers */ diff --git a/wave_containers/include/wave/containers/measurement_container_base.hpp b/wave_containers/include/wave/containers/measurement_container_base.hpp new file mode 100644 index 00000000..78329382 --- /dev/null +++ b/wave_containers/include/wave/containers/measurement_container_base.hpp @@ -0,0 +1,203 @@ +/** + * @file + * @ingroup containers + */ + +#ifndef WAVE_CONTAINERS_MEASUREMENT_CONTAINER_BASE_HPP +#define WAVE_CONTAINERS_MEASUREMENT_CONTAINER_BASE_HPP + +#include + +namespace wave { +/** @addtogroup containers + * @{ */ + +using TimeType = std::chrono::steady_clock::time_point; + +/** Internal implementation details - for developers only */ +namespace internal { + +/** Internal traits class template. Must be specialized for each derived type + * of MeasurementContainerBase. */ +template +struct container_traits; + +} // namespace internal + +/** Base class for containers which store measurements. + * + * It implements constructors, interators, counting, insertion, and some + * retrieval methods; derived classes should implement their own specialized + * retrieval methods. + * + * A traits class template, `internal::container_traits`, must be specialized + * for each derived class. It defines the types of keys and indices used for the + * underlying multi_index_container. + * + * The base methods are shared with derived classes through static polymorphism, + * using the curiously recurring template pattern (CRTP) - a common pattern used + * extensively by Eigen, for example. For more about CRTP see: + * + * - Eli Bendersky, [The Curiously Recurring Template Pattern in C++] + * (http://eli.thegreenplace.net/2011/05/17/the-curiously-recurring-template-pattern-in-c) + * - [What is the curiously recurring template pattern (CRTP)?] + * (https://stackoverflow.com/questions/4173254) + * - [C++ static polymorphism (CRTP) and using typedefs from derived classes] + * (https://stackoverflow.com/questions/6006614) + * + * @tparam Derived is the derived type, e.g. LandmarkMeasurementContainer + */ +template +class MeasurementContainerBase { + using traits = internal::container_traits; + + public: + // Types + + /** Alias for the template parameter, giving the type of Measurement stored + * in this container */ + using MeasurementType = typename traits::MeasurementType; + /** Alias for the measurement's value. + * Note this does *not* correspond to a typical container's value_type. */ + using ValueType = decltype(MeasurementType::value); + /** Alias for template parameter giving the type of the sensor id */ + using SensorIdType = decltype(MeasurementType::sensor_id); + + using iterator = typename traits::composite_type::iterator; + using const_iterator = typename traits::composite_type::const_iterator; + using sensor_iterator = typename traits::sensor_type::iterator; + using size_type = std::size_t; + + // Constructors + + MeasurementContainerBase() = default; + + /** Construct the container with the contents of the range [first, last) */ + template + MeasurementContainerBase(InputIt first, InputIt last); + + // Capacity + + /** Return true if the container has no elements. */ + bool empty() const noexcept; + + /** Return the number of elements in the container. */ + size_type size() const noexcept; + + // Modifiers + + /** Insert a Measurement if a measurement for the same time and sensor does + * not already exist. + * + * @return a pair p. If and only if insertion occurred, p.second is true and + * p.first points to the element inserted. + */ + std::pair insert(const MeasurementType &); + + /** For each element of the range [first, last), inserts a Measurement if a + * measurement for the same time and sensor does not already exist. + * + * @param first, last iterators representing a valid range of Measurements, + * but not iterators into this container + */ + template + void insert(InputIt first, InputIt last); + + /** Insert a Measurement constructed from the arguments if a measurement for + * the same time and sensor does not already exist. + * + * @return a pair p. If and only if insertion occurred, p.second is true and + * p.first points to the element inserted. + */ + template + std::pair emplace(Args &&... args); + + /** Delete the element with the matching key, if one exists. + * + * @param args + * @parblock + * arguments forming a unique key for the container. + * + * See the documentation for the derived container class for a definition of + * the unique key. + * + * For example, for MeasurementContainer, the key consists of time and + * sensor_id. For LandmarkMeasurementContainer, the key consists of time, + * sensor_id, and landmark_id. + * @endparblock + * + * @return the number of elements deleted (0 or 1). + */ + template + size_type erase(Args &&... args); + + /** Delete the element at `position` + * + * @param position a valid dereferenceable iterator of this container + * @return An iterator pointing to the element following the deleted one, or + * `end()` if it was the last. + */ + iterator erase(iterator position) noexcept; + + + /** Delete the elements in the range [first, last) + * + * @param first, last a valid range of this container + * @return `last` + */ + iterator erase(iterator first, iterator last) noexcept; + + + /** Delete all elements */ + void clear() noexcept; + + // Retrieval + + /** Get all measurements from the given sensor + * + * @return a pair of iterators representing the start and end of the range. + * If the range is empty, both iterators will be equal. + * + * @note because these iterators use the underlying ordered index of + * sensor_ids, they are not the same type as those from `begin()`, + * `getTimeWindow()`, etc. + */ + std::pair getAllFromSensor( + const SensorIdType &s) const noexcept; + + /** Get all measurements between the given times. + * + * @param start, end an inclusive range of times, with start <= end + * + * @return a pair of iterators representing the start and end of the range. + * If the range is empty, both iterators will be equal. + */ + std::pair getTimeWindow(const TimeType &start, + const TimeType &end) const + noexcept; + + + // Iterators + + iterator begin() noexcept; + iterator end() noexcept; + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + + protected: + // Helper to get the composite index + typename traits::composite_type &composite() noexcept; + const typename traits::composite_type &composite() const noexcept; + + // Internal multi_index_container + typename traits::type storage; +}; + +/** @} group containers */ +} // namespace wave + +#include "impl/measurement_container_base.hpp" + +#endif // WAVE_CONTAINERS_MEASUREMENT_CONTAINER_BASE_HPP