//********************************************************
// The following code example is taken from the book
//  C++23 - The Complete Guide
//  by Nicolai M. Josuttis (www.josuttis.com)
//  https://www.cppstd23.com
//
// The code is licensed under a
//  Creative Commons Attribution 4.0 International License
//  https://creativecommons.org/licenses/by/4.0/
//********************************************************


#include <mdspan>
#include <type_traits>

template<typename ElemT>
requires (!std::is_array_v<ElemT> && !std::is_abstract_v<ElemT>)
struct DefAccessor
{
  // required accessor types:
  using element_type = ElemT;               // type of an elements
  using reference = element_type&;          // reference to an elements
  using data_handle_type = element_type*;   // handle to the data/elements
  using offset_policy = DefAccessor;        // type to deal with offsets

  constexpr DefAccessor() noexcept = default;

  template<typename OtherElemT>
  requires std::is_convertible_v<OtherElemT(*)[], element_type(*)[]>
  constexpr DefAccessor(DefAccessor<OtherElemT>) noexcept { 
  }

  // element access:
  constexpr reference access(data_handle_type p, std::size_t n) const noexcept {
    return p[n];   // yield a reference to the n-th element starting with p 
  }

  // define the effect offsets:
  constexpr data_handle_type offset(data_handle_type p,
                                    std::size_t n) const noexcept {
    return p + i;  // move the iterator forward by n elements
  }
};

