Last active
October 6, 2020 19:54
-
-
Save amitsingh19975/65c0c7e4ec334d2a24a0942ff9bdfa4d to your computer and use it in GitHub Desktop.
Span implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace ub = boost::numeric::ublas; | |
int main(){ | |
using namespace ub::literals; | |
/// dynamic span | |
{ | |
// span[first: 0, last: 600, step: 4] | |
auto s1 = ub::span<>(0,600,4); | |
// span[first: 0, last: 600, step: 4] | |
auto s2 = ub::span<>(4_s, 600_l); // auto s2 = ub::span<>(ub::span_step{4}, ub::span_last{600}); | |
// span[first: 30, last: end, step: 1] | |
auto s3 = ub::span<>(30_f); // auto s3 = ub::span<>(ub::span_first{30}); | |
// span[first: 3, last: end, step: 1] | |
auto s4 = ub::span<>(3); | |
} | |
/// static span | |
{ | |
// span[first: 0, last: 600, step: 4] | |
auto s1 = ub::span<0,600,4>(); | |
// span[first: 0, last: 600, step: 1] | |
auto s2 = ub::span<0,600>(); | |
// span[first: 30, last: end, step: 1] | |
auto s3 = ub::span<30>(); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com | |
// | |
// Distributed under the Boost Software License, Version 1.0. (See | |
// accompanying file LICENSE_1_0.txt or copy at | |
// http://www.boost.org/LICENSE_1_0.txt) | |
// | |
// The authors gratefully acknowledge the support of | |
// Fraunhofer and Google in producing this work | |
// which started as a Google Summer of Code project. | |
// | |
#ifndef _BOOST_UBLAS_TENSOR_SPAN_ | |
#define _BOOST_UBLAS_TENSOR_SPAN_ | |
#include <limits> | |
#include <stdexcept> | |
#include <ostream> | |
#include <boost/numeric/ublas/tensor/interface/meta.hpp> | |
namespace boost::numeric::ublas { | |
/** \class span | |
* \ingroup Core_Module | |
* | |
* \brief Selection operator class to initialize stl::multi_subarray | |
* | |
* This class is used to generate stl::multi_subarray from stl::multi_array and | |
* to work on views. \note zero based indexing is used. | |
* | |
*/ | |
template <class ValueType, ValueType...> class basic_span; | |
struct span_first { | |
using value_type = std::size_t; | |
constexpr span_first() noexcept = default; | |
constexpr span_first(span_first const& other) noexcept = default; | |
constexpr span_first(span_first&& other) noexcept = default; | |
constexpr span_first& operator=(span_first const& other) noexcept = default; | |
constexpr span_first& operator=(span_first&& other) noexcept = default; | |
~span_first() noexcept = default; | |
constexpr span_first(value_type val) noexcept | |
: value(val) | |
{ | |
} | |
constexpr operator std::size_t() noexcept { return value; } | |
value_type value{}; | |
}; | |
struct span_last { | |
using value_type = std::size_t; | |
constexpr span_last() noexcept = default; | |
constexpr span_last(span_last const& other) noexcept = default; | |
constexpr span_last(span_last&& other) noexcept = default; | |
constexpr span_last& operator=(span_last const& other) noexcept = default; | |
constexpr span_last& operator=(span_last&& other) noexcept = default; | |
~span_last() noexcept = default; | |
constexpr span_last(value_type val) noexcept | |
: value(val) | |
{ | |
} | |
constexpr operator std::size_t() noexcept { return value; } | |
value_type value{std::numeric_limits<value_type>::max()}; | |
}; | |
struct span_step { | |
using value_type = std::size_t; | |
constexpr span_step() noexcept = default; | |
constexpr span_step(span_step const& other) noexcept = default; | |
constexpr span_step(span_step&& other) noexcept = default; | |
constexpr span_step& operator=(span_step const& other) noexcept = default; | |
constexpr span_step& operator=(span_step&& other) noexcept = default; | |
~span_step() noexcept = default; | |
constexpr span_step(value_type val) noexcept | |
: value(val) | |
{ | |
} | |
constexpr operator std::size_t() noexcept { return value; } | |
value_type value{1u}; | |
}; | |
namespace literals { | |
constexpr span_first operator""_f(unsigned long long val) noexcept | |
{ | |
return {val}; | |
} | |
constexpr span_last operator""_l(unsigned long long val) noexcept | |
{ | |
return {val}; | |
} | |
constexpr span_step operator""_s(unsigned long long val) noexcept | |
{ | |
return {val}; | |
} | |
}; // namespace literals | |
template <class ValueType> class basic_span<ValueType> { | |
public: | |
using self_type = basic_span<ValueType>; | |
using value_type = ValueType; | |
using size_type = std::size_t; | |
static_assert( | |
!std::numeric_limits<value_type>::is_signed, | |
"boost::numeric::ublas::basic_span : ValueType should be unsigned integer"); | |
static constexpr auto end = std::numeric_limits<value_type>::max(); | |
constexpr basic_span() noexcept = default; | |
constexpr basic_span(basic_span const& other) noexcept = default; | |
constexpr basic_span(basic_span&& other) noexcept = default; | |
constexpr basic_span& operator=(basic_span const& other) noexcept = default; | |
constexpr basic_span& operator=(basic_span&& other) noexcept = default; | |
~basic_span() noexcept = default; | |
template <class T, class... Ts> constexpr basic_span(T&& arg0, Ts&&... args) | |
{ | |
constexpr auto sz = 1ul + sizeof...(Ts); | |
static_assert(sz <= 3, | |
"boost::numeric::ublas::basic_span(T&&,Ts&&...) : " | |
"arity of the constructor should be less than or equal or 3"); | |
auto arguments_as_tuple = std::forward_as_tuple(arg0, args...); | |
meta::for_each<meta::iota_c<sz>>( | |
[targs = std::move(arguments_as_tuple), this](auto idx) { | |
constexpr auto I = std::decay_t<decltype(idx)>::value; | |
auto arg = std::get<I>(targs); | |
using arg_type = std::decay_t<decltype(arg)>; | |
static_assert(std::is_convertible_v<arg_type, value_type>, | |
"boost::numeric::ublas::basic_span(T&&,Ts&&...) : " | |
"argument type should be one of the following " | |
"type: ValueType or convertible to ValueType, " | |
"span_first, span_last, and span_step"); | |
if constexpr (std::is_same_v<arg_type, span_first>) | |
m_first = arg; | |
else if constexpr (std::is_same_v<arg_type, span_last>) | |
m_last = arg; | |
else if constexpr (std::is_same_v<arg_type, span_step>) | |
m_step = arg; | |
else { | |
if constexpr (I == 0u) | |
m_first = arg; | |
else if constexpr (I == 1u) | |
m_last = arg; | |
else | |
m_step = arg; | |
} | |
}); | |
if (m_first != m_last) { | |
if (m_step == 0) { | |
throw std::runtime_error( | |
"boost::numeric::ublas::basic_span(T&&,Ts&&...) : " | |
"cannot have a m_step equal to zero"); | |
} | |
if (m_first > m_last) { | |
throw std::runtime_error( | |
"boost::numeric::ublas::basic_span(T&&,Ts&&...) : " | |
"m_last is smaller than m_first"); | |
} | |
auto n_last = m_last - ((m_last - m_first) % m_step); | |
m_last = (m_last == end ? end : n_last); | |
} | |
} | |
constexpr auto first() const noexcept { return m_first; } | |
constexpr auto last() const noexcept { return m_last; } | |
constexpr auto step() const noexcept { return m_step; } | |
constexpr auto size() const noexcept | |
{ | |
return ((m_last - m_first) / m_step) + value_type{1}; | |
} | |
constexpr value_type operator[](std::size_t idx) const noexcept | |
{ | |
return m_first + idx * m_step; | |
} | |
constexpr basic_span operator()(const basic_span& rhs) const noexcept | |
{ | |
auto const& lhs = *this; | |
return basic_span((rhs.m_first * lhs.m_step) + lhs.m_first, | |
(rhs.m_last * lhs.m_step) + lhs.m_first, | |
(lhs.m_step * rhs.m_step)); | |
} | |
private: | |
value_type m_first{}; | |
value_type m_last{end}; | |
value_type m_step{1}; | |
}; | |
template <class ValueType, ValueType First, ValueType Last, ValueType Step> | |
class basic_span<ValueType, First, Last, Step> { | |
public: | |
using self_type = basic_span<ValueType, First, Last, Step>; | |
using value_type = ValueType; | |
using size_type = std::size_t; | |
template <typename T, T...> friend class basic_span; | |
static_assert( | |
!std::numeric_limits<value_type>::is_signed, | |
"boost::numeric::ublas::basic_span : ValueType should be unsigned integer"); | |
static_assert(Step != 0ul, | |
"boost::numeric::ublas::basic_span : Step cannot be 0"); | |
static_assert(First < Last, | |
"boost::numeric::ublas::basic_span : Last is less than First"); | |
static constexpr auto end = std::numeric_limits<value_type>::max(); | |
constexpr basic_span() noexcept = default; | |
constexpr basic_span(basic_span const& other) noexcept = default; | |
constexpr basic_span(basic_span&& other) noexcept = default; | |
constexpr basic_span& operator=(basic_span const& other) noexcept = default; | |
constexpr basic_span& operator=(basic_span&& other) noexcept = default; | |
~basic_span() noexcept = default; | |
constexpr auto first() const noexcept { return m_first; } | |
constexpr auto last() const noexcept { return m_last; } | |
constexpr auto step() const noexcept { return m_step; } | |
constexpr auto size() const noexcept | |
{ | |
return ((m_last - m_first) / m_step) + value_type{1}; | |
} | |
constexpr value_type operator[](std::size_t idx) const noexcept | |
{ | |
return m_first + idx * m_step; | |
} | |
template <ValueType... Vs> | |
constexpr basic_span operator()( | |
const basic_span<ValueType, Vs...>& rhs) const noexcept | |
{ | |
auto const& lhs = *this; | |
return basic_span((rhs.m_first * lhs.m_step) + lhs.m_first, | |
(rhs.m_last * lhs.m_step) + lhs.m_first, | |
(lhs.m_step * rhs.m_step)); | |
} | |
private: | |
template <ValueType F, ValueType L> | |
struct last_assigner | |
: std::integral_constant<ValueType, L - ((L - F) % Step)> { | |
}; | |
template <ValueType F> | |
struct last_assigner<F, F> : std::integral_constant<ValueType, F> { | |
}; | |
template <ValueType F> | |
struct last_assigner<F, end> : std::integral_constant<ValueType, end> { | |
}; | |
private: | |
static constexpr value_type m_first = First; | |
static constexpr value_type m_last = last_assigner<First, Last>::value; | |
static constexpr value_type m_step = Step; | |
}; | |
template <class ValueType, ValueType First, ValueType Last> | |
class basic_span<ValueType, First, Last> | |
: public basic_span<ValueType, First, Last, 1ul> { | |
}; | |
template <class ValueType, ValueType First> | |
class basic_span<ValueType, First> | |
: public basic_span<ValueType, First, std::numeric_limits<ValueType>::max()> { | |
}; | |
} // namespace boost::numeric::ublas | |
namespace boost::numeric::ublas { | |
template <std::size_t... Vs> using span = basic_span<std::size_t, Vs...>; | |
} // namespace boost::numeric::ublas | |
template <class ValueType, ValueType... Vs> | |
std::ostream& operator<<( | |
std::ostream& out, | |
boost::numeric::ublas::basic_span<ValueType, Vs...> const& s) | |
{ | |
return out << "[ First: " << s.first() << ", Last: " << s.last() | |
<< ", Step: " << s.step() << " ]"; | |
} | |
template <class ValueType, ValueType... Vs1, ValueType... Vs2> | |
constexpr bool operator==( | |
boost::numeric::ublas::basic_span<ValueType, Vs1...> const& lhs, | |
boost::numeric::ublas::basic_span<ValueType, Vs2...> const& rhs) noexcept | |
{ | |
return lhs.first() == rhs.first() && lhs.last() == rhs.last() && | |
lhs.step() == rhs.step(); | |
} | |
template <class ValueType, ValueType... Vs1, ValueType... Vs2> | |
constexpr bool operator!=( | |
boost::numeric::ublas::basic_span<ValueType, Vs1...> const& lhs, | |
boost::numeric::ublas::basic_span<ValueType, Vs2...> const& rhs) noexcept | |
{ | |
return !(lhs == rhs); | |
} | |
#endif // _BOOST_UBLAS_TENSOR_SPAN_ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment