diff --git a/Control/CxxUtils/CMakeLists.txt b/Control/CxxUtils/CMakeLists.txt index fc349195ee855bd675a9651eda9d29efb1e3ba86..bb622480c55757e654f12cd08fae937ba9bb51f8 100644 --- a/Control/CxxUtils/CMakeLists.txt +++ b/Control/CxxUtils/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +# Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration # Declare the package name: atlas_subdir( CxxUtils ) @@ -132,7 +132,8 @@ foreach( test sincos_test ArrayScanner_test Arrayrep_test restrict_test vectorize_test get_unaligned_test aligned_vector_test vec_int_test vec_float_test vec_fb_int_test vec_fb_float_test ConcurrentHashmapImpl_test SimpleUpdater_test hexdump_test - FPControl_test LockedPointer_test nodiscard_test) + FPControl_test LockedPointer_test nodiscard_test span_test + reverse_wrapper_test ) atlas_add_test( ${test} SOURCES test/${test}.cxx LOG_IGNORE_PATTERN "no version information available" diff --git a/Control/CxxUtils/CxxUtils/reverse_wrapper.h b/Control/CxxUtils/CxxUtils/reverse_wrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..8b8d5a505555b60dcb5ad821d881dfb20b8afefc --- /dev/null +++ b/Control/CxxUtils/CxxUtils/reverse_wrapper.h @@ -0,0 +1,52 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. +/* + * Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration. + */ +/** + * @file CxxUtils/reverse_wrapper.h + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2022 + * @brief Helper for iterating over a container in reverse order. + * + * Given a container @c c, this code will iterate over the container + * in reverse order: + * + *@code + * for (... elt : CxxUtils::make_reverse_wrapper (c)) { + @endcode + */ + + +#ifndef CXXUTILS_REVERSE_WRAPPER_H +#define CXXUTILS_REVERSE_WRAPPER_H + + +namespace CxxUtils { + + +/** + * @brief Adapter for a container-like class to be used in a range-for + * so as to iterate in the reverse direction. + */ +template <class C> +class reverse_wrapper +{ +public: + reverse_wrapper (C& r) : m_r (r) {} + auto begin() { return m_r.rbegin(); } + auto end() { return m_r.rend(); } + C& m_r; +}; + + +/** + * @brief Make a @c reverse_wrapper for a given container-like object. + */ +template <class T> +auto make_reverse_wrapper (T& r) { return reverse_wrapper(r); } + + +} // namespace CxxUtils + + +#endif // not CXXUTILS_REVERSE_WRAPPER_H diff --git a/Control/CxxUtils/CxxUtils/span.h b/Control/CxxUtils/CxxUtils/span.h new file mode 100644 index 0000000000000000000000000000000000000000..24a3d40e332d8b08d3092f92a37d0acfd1ab87de --- /dev/null +++ b/Control/CxxUtils/CxxUtils/span.h @@ -0,0 +1,276 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. +/* + * Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration. + */ +/** + * @file CxxUtils/span.h + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2022 + * @brief Simplified version of the C++20 std::span. + */ + + +#ifndef CXXUTILS_SPAN_H +#define CXXUTILS_SPAN_H + + +#include <cstdlib> +#include <type_traits> +#include <iterator> +#include <cassert> + + +namespace CxxUtils { + + +/// Used to specify a subrange of indefinite size in subspan(). +inline constexpr size_t dynamic_extent = static_cast<size_t>(-1); + + +/** + * @brief Simplified version of the C++20 std::span. + * + * This class is meant to be very similar to the C++20 std::span class. + * There are however a few differences. + * - The option for a fixed-length span is not implemented; hence, there + * is no second template argument. + * - Constructors from arrays / std::array are not implemented. + * - The external member functions as_bytes / as_writable_bytes and + * deduction guides are not implemented. + * + * Contact the core sw group if any of these are a problem. + * + * In addition: + * - The concept requirements on the constructors are not checked. + * - Accessor methods are split into const / non-const versions. + * This is required to avoid warnings from the thread-safety checker, + * but be careful of potential incompatibilies with std::span. + * Again, contact the core sw group if this is an issue. + */ +template <class T> +class span +{ +public: + /// Required typedefs. + using element_type = T; + using value_type = std::remove_cv_t<T>; + using size_type = size_t; + using difference_type = ptrdiff_t; + using pointer = T*; + using const_pointer = const T*; + using reference = element_type&; + using const_reference = const element_type&; + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator<iterator>; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + + + /* + * @brief Default constructor. + * Makes an empty span. + */ + span(); + + + /** + * @brief Constructor from start and length. + * @param ptr Start of the span. + * @param sz Length of the span. + */ + span (T* ptr, size_type sz); + + + /** + * @brief Constructor from start and end. + * @param beg Start of the span. + * @param end One past the end of the span. + */ + span (T* beg, T* end); + + + // Default copy / assignment. + span (const span&) = default; + span& operator= (const span&) = default; + + + /** + * @brief Return the size of the span. + */ + constexpr size_type size() const noexcept; + + + /** + * @brief Return the size of contents of the span, in bytes. + */ + constexpr size_type size_bytes() const noexcept; + + + /** + * @brief Test if the span is empty. + */ + [[nodiscard]] constexpr bool empty() const noexcept; + + + /** + * @brief Return a reference to the first element in the span. + */ + constexpr reference front() noexcept; + + + /** + * @brief Return a reference to the first element in the span. + */ + constexpr const_reference front() const noexcept; + + + /** + * @brief Return a reference to the last element in the span. + */ + constexpr reference back() noexcept; + + + /** + * @brief Return a reference to the last element in the span. + */ + constexpr const_reference back() const noexcept; + + + /** + * @brief Return a reference to the i-th element in the span. + * @param i Index of the element to return. + */ + constexpr reference operator[] (size_type i) noexcept; + + + /** + * @brief Return a reference to the i-th element in the span. + * @param i Index of the element to return. + */ + constexpr const_reference operator[] (size_type i) const noexcept; + + + /** + * @brief Return a pointer to the start of the span. + */ + constexpr pointer data() noexcept; + + + /** + * @brief Return a pointer to the start of the span. + */ + constexpr const_pointer data() const noexcept; + + + /** + * @brief Return a begin iterator. + */ + constexpr iterator begin() noexcept; + + + /** + * @brief Return a begin iterator. + */ + constexpr const_iterator begin() const noexcept; + + + /** + * @brief Return an end iterator. + */ + constexpr iterator end() noexcept; + + + /** + * @brief Return an end iterator. + */ + constexpr const_iterator end() const noexcept; + + + /** + * @brief Return a begin reverse iterator. + */ + constexpr reverse_iterator rbegin() noexcept; + + + /** + * @brief Return a begin reverse iterator. + */ + constexpr const_reverse_iterator rbegin() const noexcept; + + + /** + * @brief Return an end reverse iterator. + */ + constexpr reverse_iterator rend() noexcept; + + + /** + * @brief Return an end reverse iterator. + */ + constexpr const_reverse_iterator rend() const noexcept; + + + /** + * @brief Return a subspan from the start. + * @param n Number of elements in the subspan. + */ + constexpr span first (size_type n) noexcept; + + + /** + * @brief Return a subspan from the start. + * @param n Number of elements in the subspan. + */ + constexpr span<const T> first (size_type n) const noexcept; + + + /** + * @brief Return a subspan from the end. + * @param n Number of elements in the subspan. + */ + constexpr span last (size_type n) noexcept; + + + /** + * @brief Return a subspan from the end. + * @param n Number of elements in the subspan. + */ + constexpr span<const T> last (size_type n) const noexcept; + + + /** + * @brief Return a subspan. + * @param offs Starting element of the subspan. + * @param n Number of elements in the subspan. + * If defaulted, take all remaining elements. + */ + constexpr span + subspan (size_type offs, size_type n = dynamic_extent) noexcept; + + + /** + * @brief Return a subspan. + * @param offs Starting element of the subspan. + * @param n Number of elements in the subspan. + * If defaulted, take all remaining elements. + */ + constexpr span<const T> + subspan (size_type offs, size_type n = dynamic_extent) const noexcept; + + +private: + /// Pointer to the start of the span. + T* m_ptr; + + /// Number of elements in the span. + size_t m_size; +}; + + +} // namespace CxxUtils + + +#include "CxxUtils/span.icc" + + +#endif // not CXXUTILS_SPAN_H diff --git a/Control/CxxUtils/CxxUtils/span.icc b/Control/CxxUtils/CxxUtils/span.icc new file mode 100644 index 0000000000000000000000000000000000000000..dc412903d9f12c4bd04eb56f2ae44d18510057c6 --- /dev/null +++ b/Control/CxxUtils/CxxUtils/span.icc @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration. + */ +/** + * @file CxxUtils/span.icc + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2022 + * @brief Simplified version of the C++20 std::span. + */ + + +namespace CxxUtils { + + +/* + * @brief Default constructor. + * Makes an empty span. + */ +template <class T> +inline +span<T>::span() + : m_ptr(nullptr), + m_size(0) +{ +} + + +/** + * @brief Constructor from start and length. + * @param ptr Start of the span. + * @param sz Length of the span. + */ +template <class T> +inline +span<T>::span (T* ptr, size_type sz) + : m_ptr(ptr), + m_size(sz) +{ +} + + +/** + * @brief Constructor from start and end. + * @param beg Start of the span. + * @param end One past the end of the span. + */ +template <class T> +inline +span<T>::span (T* beg, T* end) + : m_ptr(beg), + m_size (end-beg) +{ +} + + +/** + * @brief Return the size of the span. + */ +template <class T> +inline +constexpr typename span<T>::size_type +span<T>::size() const noexcept +{ + return m_size; +} + + +/** + * @brief Return the size of contents of the span, in bytes. + */ +template <class T> +inline +constexpr typename span<T>::size_type +span<T>::size_bytes() const noexcept +{ + return m_size * sizeof(element_type); +} + + +/** + * @brief Test if the span is empty. + */ +template <class T> +inline +constexpr bool +span<T>::empty() const noexcept +{ + return m_size == 0; +} + + +/** + * @brief Return a reference to the first element in the span. + */ +template <class T> +inline +constexpr typename span<T>::reference +span<T>::front() noexcept +{ + assert (m_ptr != nullptr); + return *m_ptr; +} + + +/** + * @brief Return a reference to the first element in the span. + */ +template <class T> +inline +constexpr typename span<T>::const_reference +span<T>::front() const noexcept +{ + assert (m_ptr != nullptr); + return *m_ptr; +} + + +/** + * @brief Return a reference to the last element in the span. + */ +template <class T> +inline +constexpr typename span<T>::reference +span<T>::back() noexcept +{ + assert (m_ptr != nullptr); + return *(m_ptr + m_size-1); +} + + +/** + * @brief Return a reference to the last element in the span. + */ +template <class T> +inline +constexpr typename span<T>::const_reference +span<T>::back() const noexcept +{ + assert (m_ptr != nullptr); + return *(m_ptr + m_size-1); +} + + +/** + * @brief Return a reference to the i-th element in the span. + * @param i Index of the element to return. + */ +template <class T> +inline +constexpr typename span<T>::reference +span<T>::operator[] (size_type i) noexcept +{ + assert (i < m_size); + return m_ptr[i]; +} + + +/** + * @brief Return a reference to the i-th element in the span. + * @param i Index of the element to return. + */ +template <class T> +inline +constexpr typename span<T>::const_reference +span<T>::operator[] (size_type i) const noexcept +{ + assert (i < m_size); + return m_ptr[i]; +} + + +/** + * @brief Return a pointer to the start of the span. + */ +template <class T> +inline +constexpr typename span<T>::pointer +span<T>::data() noexcept +{ + return m_ptr; +} + + +/** + * @brief Return a pointer to the start of the span. + */ +template <class T> +inline +constexpr typename span<T>::const_pointer +span<T>::data() const noexcept +{ + return m_ptr; +} + + +/** + * @brief Return a begin iterator. + */ +template <class T> +inline +constexpr typename span<T>::iterator +span<T>::begin() noexcept +{ + return m_ptr; +} + + +/** + * @brief Return a begin iterator. + */ +template <class T> +inline +constexpr typename span<T>::const_iterator +span<T>::begin() const noexcept +{ + return m_ptr; +} + + +/** + * @brief Return an end iterator. + */ +template <class T> +inline +constexpr typename span<T>::iterator +span<T>::end() noexcept +{ + return m_ptr + m_size; +} + + +/** + * @brief Return an end iterator. + */ +template <class T> +inline +constexpr typename span<T>::const_iterator +span<T>::end() const noexcept +{ + return m_ptr + m_size; +} + + +/** + * @brief Return a begin reverse iterator. + */ +template <class T> +inline +constexpr typename span<T>::reverse_iterator +span<T>::rbegin() noexcept +{ + return reverse_iterator (end()); +} + + +/** + * @brief Return a begin reverse iterator. + */ +template <class T> +inline +constexpr typename span<T>::const_reverse_iterator +span<T>::rbegin() const noexcept +{ + return const_reverse_iterator (end()); +} + + +/** + * @brief Return an end reverse iterator. + */ +template <class T> +inline +constexpr typename span<T>::reverse_iterator +span<T>::rend() noexcept +{ + return reverse_iterator (begin()); +} + + +/** + * @brief Return an end reverse iterator. + */ +template <class T> +inline +constexpr typename span<T>::const_reverse_iterator +span<T>::rend() const noexcept +{ + return const_reverse_iterator (begin()); +} + + +/** + * @brief Return a subspan from the start. + * @param n Number of elements in the subspan. + */ +template <class T> +inline +constexpr span<T> +span<T>::first (size_type n) noexcept +{ + assert (n <= size()); + return span (m_ptr, n); +} + + +/** + * @brief Return a subspan from the start. + * @param n Number of elements in the subspan. + */ +template <class T> +inline +constexpr span<const T> +span<T>::first (size_type n) const noexcept +{ + assert (n <= size()); + return span<const T> (m_ptr, n); +} + + +/** + * @brief Return a subspan from the end. + * @param n Number of elements in the subspan. + */ +template <class T> +inline +constexpr span<T> +span<T>::last (size_type n) noexcept +{ + assert (n <= size()); + return span (m_ptr + (size() - n), n); +} + + +/** + * @brief Return a subspan from the end. + * @param n Number of elements in the subspan. + */ +template <class T> +inline +constexpr span<const T> +span<T>::last (size_type n) const noexcept +{ + assert (n <= size()); + return span<const T> (m_ptr + (size() - n), n); +} + + +/** + * @brief Return a subspan. + * @param offs Starting element of the subspan. + * @param n Number of elements in the subspan. + * If defaulted, take all remaining elements. + */ +template <class T> +inline +constexpr span<T> +span<T>::subspan (size_type offs, size_type n /*= dynamic_extent*/) noexcept +{ + assert (offs <= size()); + if (n == dynamic_extent) + n = size() - offs; + else { + assert (n <= size()); + assert (offs + n <= size()); + } + return span (m_ptr + offs, n); +} + + +/** + * @brief Return a subspan. + * @param offs Starting element of the subspan. + * @param n Number of elements in the subspan. + * If defaulted, take all remaining elements. + */ +template <class T> +inline +constexpr span<const T> +span<T>::subspan (size_type offs, size_type n /*= dynamic_extent*/) const noexcept +{ + assert (offs <= size()); + if (n == dynamic_extent) + n = size() - offs; + else { + assert (n <= size()); + assert (offs + n <= size()); + } + return span<const T> (m_ptr + offs, n); +} + + +} // namespace CxxUtils diff --git a/Control/CxxUtils/share/reverse_wrapper_test.ref b/Control/CxxUtils/share/reverse_wrapper_test.ref new file mode 100644 index 0000000000000000000000000000000000000000..7e6cc08a9b6f55041b8cffb3686c8f7ef32f283a --- /dev/null +++ b/Control/CxxUtils/share/reverse_wrapper_test.ref @@ -0,0 +1,2 @@ +CxxUtils/reverse_wrapper_test.cxx +test1 diff --git a/Control/CxxUtils/share/span_test.ref b/Control/CxxUtils/share/span_test.ref new file mode 100644 index 0000000000000000000000000000000000000000..b171da04655e0d2999dd2394c9190f86ad492016 --- /dev/null +++ b/Control/CxxUtils/share/span_test.ref @@ -0,0 +1,2 @@ +CxxUtils/span_test.cxx +test1 diff --git a/Control/CxxUtils/test/reverse_wrapper_test.cxx b/Control/CxxUtils/test/reverse_wrapper_test.cxx new file mode 100644 index 0000000000000000000000000000000000000000..cefb2300f5d138eb36058b8ad082a4e445e8e50b --- /dev/null +++ b/Control/CxxUtils/test/reverse_wrapper_test.cxx @@ -0,0 +1,36 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +*/ +/** + * @file CxxUtils/tests/reverse_wrapper_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2022 + * @brief Unit tests for reverse_wrapper. + */ + + +#undef NDEBUG +#include "CxxUtils/reverse_wrapper.h" +#include <cassert> +#include <iostream> +#include <vector> + + +void test1() +{ + std::cout << "test1\n"; + std::vector<int> v { 1, 2, 3 }; + int acc = 0; + for (int i : CxxUtils::make_reverse_wrapper (v)) { + acc = acc*2 + i; + } + assert (acc == 17); +} + + +int main() +{ + std::cout << "CxxUtils/reverse_wrapper_test.cxx\n"; + test1(); + return 0; +} diff --git a/Control/CxxUtils/test/span_test.cxx b/Control/CxxUtils/test/span_test.cxx new file mode 100644 index 0000000000000000000000000000000000000000..dbdad647331e1b45881fd6d919a9442d9d6cb7ea --- /dev/null +++ b/Control/CxxUtils/test/span_test.cxx @@ -0,0 +1,95 @@ +/* + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +*/ +/** + * @file CxxUtils/tests/span_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jan, 2022 + * @brief Unit tests for span. + */ + + +#undef NDEBUG +#include "CxxUtils/span.h" +#include "CxxUtils/reverse_wrapper.h" +#include <cassert> +#include <iostream> + + +template <class ELT, class T> +void test1a(T& s2) +{ + assert (s2.size() == 8); + assert (s2.size_bytes() == 8*sizeof(float)); + assert (!s2.empty()); + assert (s2.front() == 0); + assert (s2.back() == 7); + assert (s2[3] == 3); + assert (s2.data()[4] == 4); + assert (*s2.begin() == 0); + assert (s2.end() - s2.begin() == 8); + assert (s2.begin() != s2.end()); + assert (s2.begin()+8 == s2.end()); + assert (*s2.rbegin() == 7); + assert (s2.rend() - s2.rbegin() == 8); + assert (s2.rbegin() != s2.rend()); + assert (s2.rbegin()+8 == s2.rend()); + float acc = 0; + for (float f : s2) { + acc = 2*acc + f; + } + assert (acc == 247); + acc = 0; + for (float f : CxxUtils::make_reverse_wrapper (s2)) { + acc = 2*acc + f; + } + assert (acc == 1538); + + CxxUtils::span<ELT> s3 = s2.first (3); + assert (s3.size() == 3); + assert (s3[1] == 1); + + CxxUtils::span<ELT> s4 = s2.last (3); + assert (s4.size() == 3); + assert (s4[1] == 6); + + CxxUtils::span<ELT> s5 = s2.subspan (4); + assert (s5.size() == 4); + assert (s5[1] == 5); + + CxxUtils::span<ELT> s6 = s2.subspan (2, 3); + assert (s6.size() == 3); + assert (s6[1] == 3); +} + + +void test1() +{ + std::cout << "test1\n"; + CxxUtils::span<float> s1; + assert (s1.size() == 0); + assert (s1.size_bytes() == 0); + assert (s1.empty()); + + float ff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + CxxUtils::span<float> s2 (ff, 8); + test1a<float> (s2); + const CxxUtils::span<float>& cs2 = s2; + test1a<const float> (cs2); + + CxxUtils::span<float> s3 = s2; + test1a<float> (s3); + s1 = s2; + test1a<float> (s1); + + CxxUtils::span<float> s4 (ff, ff+8); + test1a<float> (s4); +} + + +int main() +{ + std::cout << "CxxUtils/span_test.cxx\n"; + test1(); + return 0; +}