Skip to content
Snippets Groups Projects
Commit 01c0bf6b authored by Adam Edward Barton's avatar Adam Edward Barton
Browse files

Merge branch 'span.CxxUtils-20220126' into 'master'

CxxUtils: Add span and reverse_wrapper.

See merge request atlas/athena!49993
parents 73b14405 7edf25c7
No related branches found
No related tags found
No related merge requests found
# 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: # Declare the package name:
atlas_subdir( CxxUtils ) atlas_subdir( CxxUtils )
...@@ -132,7 +132,8 @@ foreach( test sincos_test ArrayScanner_test Arrayrep_test ...@@ -132,7 +132,8 @@ foreach( test sincos_test ArrayScanner_test Arrayrep_test
restrict_test vectorize_test get_unaligned_test aligned_vector_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 vec_int_test vec_float_test vec_fb_int_test vec_fb_float_test
ConcurrentHashmapImpl_test SimpleUpdater_test hexdump_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} atlas_add_test( ${test}
SOURCES test/${test}.cxx SOURCES test/${test}.cxx
LOG_IGNORE_PATTERN "no version information available" LOG_IGNORE_PATTERN "no version information available"
......
// 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
// 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
/*
* 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
CxxUtils/reverse_wrapper_test.cxx
test1
CxxUtils/span_test.cxx
test1
/*
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;
}
/*
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;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment