• Docs >
  • Program Listing for File array.hpp
Shortcuts

Program Listing for File array.hpp

Return to documentation for file (include/ripple/container/array.hpp)

#ifndef RIPPLE_CONTAINER_ARRAY_HPP
#define RIPPLE_CONTAINER_ARRAY_HPP

#include "array_traits.hpp"
#include <ripple/algorithm/unrolled_for.hpp>

namespace ripple {

template <typename Impl>
struct Array {
  static constexpr size_t elements = array_traits_t<Impl>::size;

 public:
  ripple_all constexpr decltype(auto) operator[](size_t i) noexcept {
    return impl()->operator[](i);
  }

  ripple_all constexpr decltype(auto)
  operator[](size_t i) const noexcept {
    return impl()->operator[](i);
  }

  ripple_all constexpr auto size() const noexcept -> size_t {
    return array_traits_t<Impl>::size;
  }

  /*==--- [comparison operators] -------------------------------------------==*/

  template <typename ImplOther>
  ripple_all constexpr auto
  operator==(const Array<ImplOther>& other) noexcept -> bool {
    assert_size_match<ImplOther>();
    for (size_t i = 0; i < elements; ++i) {
      if (impl()->operator[](i) != other[i]) {
        return false;
      }
    }
    return true;
  }

  template <typename T, array_value_enable_t<T, Impl> = 0>
  ripple_all constexpr auto operator==(T val) const noexcept -> bool {
    for (size_t i = 0; i < elements; ++i) {
      if (impl()->operator[](i) != val) {
        return false;
      }
    }
    return true;
  }

  template <typename ImplOther>
  ripple_all constexpr auto
  operator!=(const Array<ImplOther>& other) noexcept -> bool {
    return !(*this == other);
  }

  template <typename T, array_value_enable_t<T, Impl> = 0>
  ripple_all constexpr auto operator!=(T val) const noexcept -> bool {
    for (size_t i = 0; i < elements; ++i) {
      if (impl()->operator[](i) != val) {
        return true;
      }
    }
    return false;
  }

  template <typename ImplOther>
  ripple_all constexpr auto
  operator<=(const Array<ImplOther>& other) noexcept -> bool {
    for (size_t i = 0; i < elements; ++i) {
      if (impl()->operator[](i) > other[i]) {
        return false;
      }
    }
    return true;
  }

  template <typename T, array_value_enable_t<T, Impl> = 0>
  ripple_all constexpr auto operator<=(T val) const noexcept -> bool {
    for (size_t i = 0; i < elements; ++i) {
      if (impl()->operator[](i) > val) {
        return false;
      }
    }
    return true;
  }

  template <typename ImplOther>
  ripple_all constexpr auto
  operator>=(const Array<ImplOther>& other) noexcept -> bool {
    for (size_t i = 0; i < elements; ++i) {
      if (impl()->operator[](i) < other[i]) {
        return false;
      }
    }
    return true;
  }

  template <typename T, array_value_enable_t<T, Impl> = 0>
  ripple_all constexpr auto operator>=(T val) const noexcept -> bool {
    for (size_t i = 0; i < elements; ++i) {
      if (impl()->operator[](i) < val) {
        return false;
      }
    }
    return true;
  }

  template <typename ImplOther>
  ripple_all constexpr auto
  operator<(const Array<ImplOther>& other) const noexcept -> bool {
    for (size_t i = 0; i < elements; ++i) {
      if (impl()->operator[](i) >= other[i]) {
        return false;
      }
    }
    return true;
  }

  template <typename T, array_value_enable_t<T, Impl> = 0>
  ripple_all constexpr auto operator<(T val) const noexcept -> bool {
    for (size_t i = 0; i < elements; ++i) {
      if (impl()->operator[](i) >= val) {
        return false;
      }
    }
    return true;
  }

  template <typename ImplOther>
  ripple_all constexpr auto
  operator>(const Array<ImplOther>& a) const noexcept -> bool {
    for (size_t i = 0; i < elements; ++i) {
      if (impl()->operator[](i) <= a[i]) {
        return false;
      }
    }
    return true;
  }

  template <typename T, array_value_enable_t<T, Impl> = 0>
  ripple_all constexpr auto operator>(T val) const noexcept -> bool {
    for (size_t i = 0; i < elements; ++i) {
      if (impl()->operator[](i) <= val) {
        return false;
      }
    }
    return true;
  }

  /*==--- [operator {+,+=} overloads] --------------------------------------==*/

  template <typename ImplOther>
  ripple_all constexpr auto
  operator+=(const Array<ImplOther>& other) noexcept -> Impl& {
    assert_size_match<ImplOther>();
    unrolled_for_bounded<elements>(
      [&](auto i) { impl()->operator[](i) += other[i]; });
    return *impl();
  }

  template <typename T, array_value_enable_t<T, Impl> = 0>
  ripple_all constexpr auto operator+=(T val) noexcept -> Impl& {
    using Value = typename array_traits_t<Impl>::Value;
    unrolled_for_bounded<elements>(
      [&](auto i) { impl()->operator[](i) += static_cast<Value>(val); });
    return *impl();
  }

  template <typename ImplOther, typename R = array_impl_t<Impl, ImplOther>>
  ripple_all constexpr auto
  operator+(const Array<ImplOther>& other) const noexcept -> R {
    R result;
    unrolled_for_bounded<elements>(
      [&](auto i) { result[i] = impl()->operator[](i) + other[i]; });
    return result;
  }

  template <
    typename T,
    typename R                    = array_impl_t<Impl, Impl>,
    array_value_enable_t<T, Impl> = 0>
  ripple_all constexpr auto operator+(T val) const noexcept -> R {
    R result;
    using Value = typename array_traits_t<Impl>::Value;
    unrolled_for_bounded<elements>([&](auto i) {
      result[i] = impl()->operator[](i) + static_cast<Value>(val);
    });
    return result;
  }

  /*==--- [operator {-,-=} overloads] --------------------------------------==*/

  template <typename ImplOther>
  ripple_all constexpr auto
  operator-=(const Array<ImplOther>& other) noexcept -> Impl& {
    assert_size_match<ImplOther>();
    unrolled_for_bounded<elements>(
      [&](auto i) { impl()->operator[](i) -= other[i]; });
    return *impl();
  }

  template <typename T, array_value_enable_t<T, Impl> = 0>
  ripple_all constexpr auto operator-=(T val) noexcept -> Impl& {
    using Value = typename array_traits_t<Impl>::Value;
    unrolled_for_bounded<elements>(
      [&](auto i) { impl()->operator[](i) -= static_cast<Value>(val); });
    return *impl();
  }

  template <typename ImplOther, typename R = array_impl_t<Impl, ImplOther>>
  ripple_all constexpr auto
  operator-(const Array<ImplOther>& other) const noexcept -> R {
    R result;
    unrolled_for_bounded<elements>(
      [&](auto i) { result[i] = impl()->operator[](i) - other[i]; });
    return result;
  }

  template <
    typename T,
    typename R                    = array_impl_t<Impl, Impl>,
    array_value_enable_t<T, Impl> = 0>
  ripple_all constexpr auto operator-(T val) const noexcept -> R {
    R result;
    using Value = typename array_traits_t<Impl>::Value;
    unrolled_for_bounded<elements>([&](auto i) {
      result[i] = impl()->operator[](i) - static_cast<Value>(val);
    });
    return result;
  }

  /*==--- [operator {*,*=} overloads] --------------------------------------==*/

  template <typename ImplOther>
  ripple_all constexpr auto
  operator*=(const Array<ImplOther>& other) noexcept -> Impl& {
    assert_size_match<ImplOther>();
    unrolled_for_bounded<elements>(
      [&](auto i) { impl()->operator[](i) *= other[i]; });
    return *impl();
  }

  template <typename T, array_value_enable_t<T, Impl> = 0>
  ripple_all constexpr auto operator*=(T val) noexcept -> Impl& {
    using Value = typename array_traits_t<Impl>::Value;
    unrolled_for_bounded<elements>(
      [&](auto i) { impl()->operator[](i) *= static_cast<Value>(val); });
    return *impl();
  }

  template <typename ImplOther, typename R = array_impl_t<Impl, ImplOther>>
  ripple_all constexpr auto
  operator*(const Array<ImplOther>& other) const noexcept -> R {
    R result;
    unrolled_for_bounded<elements>(
      [&](auto i) { result[i] = impl()->operator[](i) * other[i]; });
    return result;
  }

  template <
    typename T,
    typename R                    = array_impl_t<Impl, Impl>,
    array_value_enable_t<T, Impl> = 0>
  ripple_all constexpr auto operator*(T val) const noexcept -> R {
    R result;
    using Value = typename array_traits_t<Impl>::Value;
    unrolled_for_bounded<elements>([&](auto i) {
      result[i] = impl()->operator[](i) * static_cast<Value>(val);
    });
    return result;
  }

  /*==--- [operator {/,/=} overloads] --------------------------------------==*/

  template <typename ImplOther>
  ripple_all constexpr auto
  operator/=(const Array<ImplOther>& other) noexcept -> Impl& {
    assert_size_match<ImplOther>();
    unrolled_for_bounded<elements>(
      [&](auto i) { impl()->operator[](i) /= other[i]; });
    return *impl();
  }

  template <typename T, array_value_enable_t<T, Impl> = 0>
  ripple_all constexpr auto operator/=(T val) noexcept -> Impl& {
    using Value = typename array_traits_t<Impl>::Value;
    unrolled_for_bounded<elements>(
      [&](auto i) { impl()->operator[](i) /= static_cast<Value>(val); });
    return *impl();
  }

  template <typename ImplOther, typename R = array_impl_t<Impl, ImplOther>>
  ripple_all constexpr auto
  operator/(const Array<ImplOther>& other) const noexcept -> R {
    R result;
    unrolled_for_bounded<elements>(
      [&](auto i) { result[i] = impl()->operator[](i) / other[i]; });
    return result;
  }

  template <
    typename T,
    typename R                    = array_impl_t<Impl, Impl>,
    array_value_enable_t<T, Impl> = 0>
  ripple_all constexpr auto operator/(T val) const noexcept -> R {
    R result;
    using Value = typename array_traits_t<Impl>::Value;
    unrolled_for_bounded<elements>([&](auto i) {
      result[i] = impl()->operator[](i) / static_cast<Value>(val);
    });
    return result;
  }

 private:
  ripple_all constexpr auto impl() noexcept -> Impl* {
    return static_cast<Impl*>(this);
  }

  ripple_all constexpr auto impl() const noexcept -> const Impl* {
    return static_cast<const Impl*>(this);
  }

  template <typename ImplOther>
  ripple_all constexpr auto assert_size_match() const noexcept -> void {
    constexpr size_t size_other = array_traits_t<ImplOther>::size;
    static_assert(
      size_other == elements, "Arrays have different number of elements");
  }
};

/*==--- [operator overloads] -----------------------------------------------==*/

template <
  typename T,
  typename Impl,
  typename R                    = array_impl_t<Impl, Impl>,
  array_value_enable_t<T, Impl> = 0>
ripple_all constexpr auto
operator+(T val, const Array<Impl>& a) noexcept -> R {
  using Value = typename array_traits_t<Impl>::Value;
  using Type  = std::decay_t<T>;

  static_assert(
    std::is_same_v<Type, Value> || std::is_convertible_v<Type, Value>,
    "Cannot perform operations on an array with a type which is not the "
    "value type, or convertible to the value type!");

  R result;
  unrolled_for_bounded<array_traits_t<Impl>::size>(
    [&](auto i) { result[i] = static_cast<Value>(val) + a[i]; });
  return result;
}

template <
  typename T,
  typename Impl,
  typename R                    = array_impl_t<Impl, Impl>,
  array_value_enable_t<T, Impl> = 0>
ripple_all constexpr auto
operator-(T val, const Array<Impl>& a) noexcept -> R {
  using Value = typename array_traits_t<Impl>::Value;
  using Type  = std::decay_t<T>;

  static_assert(
    std::is_same_v<Type, Value> || std::is_convertible_v<Type, Value>,
    "Cannot perform operations on an array with a type which is not the "
    "value type, or convertible to the value type!");

  R result;
  unrolled_for_bounded<array_traits_t<Impl>::size>(
    [&](auto i) { result[i] = static_cast<Value>(val) - a[i]; });
  return result;
}

template <
  typename T,
  typename Impl,
  typename R                    = array_impl_t<Impl, Impl>,
  array_value_enable_t<T, Impl> = 0>
ripple_all constexpr auto
operator*(T val, const Array<Impl>& a) noexcept -> R {
  using Value = typename array_traits_t<Impl>::Value;
  using Type  = std::decay_t<T>;

  static_assert(
    std::is_same_v<Type, Value> || std::is_convertible_v<Type, Value>,
    "Cannot perform operations on an array with a type which is not the "
    "value type, or convertible to the value type!");

  R result;
  unrolled_for_bounded<array_traits_t<Impl>::size>(
    [&](auto i) { result[i] = static_cast<Value>(val) * a[i]; });
  return result;
}

template <
  typename T,
  typename Impl,
  typename R                    = array_impl_t<Impl, Impl>,
  array_value_enable_t<T, Impl> = 0>
ripple_all constexpr auto
operator/(T val, const Array<Impl>& a) noexcept -> R {
  using Value = typename array_traits_t<Impl>::Value;
  using Type  = std::decay_t<T>;

  static_assert(
    std::is_same_v<Type, Value> || std::is_convertible_v<Type, Value>,
    "Cannot perform operations on an array with a type which is not the "
    "value type, or convertible to the value type!");

  R result;
  unrolled_for_bounded<array_traits_t<Impl>::size>(
    [&](auto i) { result[i] = static_cast<Value>(val) / a[i]; });
  return result;
}

} // namespace ripple

#endif // RIPPLE_CONTAINER_ARRAY_HPP

Docs

Access comprehensive developer documentation for Ripple

View Docs

Tutorials

Get tutorials to help with understand all features

View Tutorials

Examples

Find examples to help get started

View Examples