Skip to content

Instantly share code, notes, and snippets.

@amitsingh19975
Last active October 6, 2020 19:54
Show Gist options
  • Save amitsingh19975/65c0c7e4ec334d2a24a0942ff9bdfa4d to your computer and use it in GitHub Desktop.
Save amitsingh19975/65c0c7e4ec334d2a24a0942ff9bdfa4d to your computer and use it in GitHub Desktop.
Span implementation
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;
}
// 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