text: #ifndef OKRUZ_BSPLINE_SUPPORT_GRID_H
  #define OKRUZ_BSPLINE_SUPPORT_GRID_H
  #include <okruz/bspline/exceptions/BSplineException.h>
  #include <okruz/bspline/internal/misc.h>
  
  #include <algorithm>
  #include <memory>
  #include <vector>
  
  /*
   * ########################################################################
   * The contents of this file is free and unencumbered software released into the
   * public domain. For more information, please refer to <http://unlicense.org/>
   * ########################################################################
   */
  
  namespace okruz::bspline::support {
  using namespace okruz::bspline::exceptions;
  
  /*!
   * Represents a global grid.
   *
   * @tparam T The datatype of the grid elements.
   */
  template <typename T>
  class Grid {
   private:
    /*! The gridpoints. */
    std::shared_ptr<const std::vector<T>> _data;
  
    bool isSteadilyIncreasing() const {
      for (size_t i = 1; i < _data->size(); i++) {
        if ((*_data)[i - 1] >= (*_data)[i]) {
          return false;
        }
      }
      return true;
    }
  
   public:
    /*!
     * Iterator type.
     */
    using const_iterator = typename std::vector<T>::const_iterator;
  
    Grid() = delete;
  
    /*!
     * Constructs a grid from two iterators. The first element of the grid will be
     * the element referenced by begin. The last element of the grid will be the
     * one before the element pointed to by end;
     *
     * @param begin The iterator referencing the first element to be copied into
     * the grid.
     * @param end The iterator referencing the element behind the last element to
     * be copied into the grid.
     * @tparam Iter The type of the two iterators.
     */
    template <typename Iter>
    Grid(Iter begin, Iter end)
        : _data(std::make_shared<const std::vector<T>>(begin, end)) {
      if (!_data || !isSteadilyIncreasing()) {
        throw BSplineException(ErrorCode::INCONSISTENT_DATA,
                               "The grid points are not steadily increasing.");
      }
    }
  
    /*!
     * Constructs a grid from a std::vector. The elements of the vector are
     * copied, not moved.
     *
     * @param v The input vector.
     */
    Grid(const std::vector<T> &v) : Grid(v.begin(), v.end()){};
  
    /*!
     * Constructs a grid from a std::initializer_list. The elements of the vector
     * are copied, not moved.
     *
     * @param v The input initializer_list.
     */
    Grid(const std::initializer_list<T> &v) : Grid(std::vector<T>(v)){};
  
    /*!
     * Constructs a grid by setting its members.
     *
     * @param data A shared pointer to the grid elements.
     */
    Grid(std::shared_ptr<const std::vector<T>> data) : _data(std::move(data)) {
      if (!_data || !isSteadilyIncreasing()) {
        throw BSplineException(ErrorCode::INCONSISTENT_DATA,
                               "The grid points are not steadily increasing.");
      }
    };
  
    // Default constructors and operators generated by the compiler.
    Grid(const Grid &g) = default;
    Grid(Grid &&g) = default;
    virtual ~Grid() = default;
    Grid &operator=(const Grid &g) = default;
    Grid &operator=(Grid &&g) = default;
  
    /*!
     * Comparison operator.
     *
     * @param g The grid to compare this grid with.
     * @returns Returns true if the grids represent the same logical grid.
     */
    bool operator==(const Grid &g) const {
      if (_data == g._data)
        return true;
      else if (_data->size() != g._data->size())
        return false;
      for (size_t i = 0; i < _data->size(); i++)
        if ((*_data)[i] != (*g._data)[i]) return false;
      return true;
    }
  
    /*!
     * Returns the number of elements of the grid.
     */
    size_t size() const { return _data->size(); };
  
    /*!
     * Returns a shared pointer to the elements of this grid.
     */
    std::shared_ptr<const std::vector<T>> getData() const { return _data; };
  
    /*!
     * Checks whether this spline holds no elements.
     *
     * @returns Returns true if this grid holds no element.
     */
    bool empty() const { return _data->empty(); };
  
    /*!
     * Returns a reference to the ith element of the grid. Performs no bounds
     * checks.
     *
     * @param i The index of the element to be returned.
     * @returns A reference to the ith element.
     */
    const T &operator[](size_t i) const { return (*_data)[i]; };
  
    /*!
     * Returns a reference to the ith element of the grid. Checks the bounds.
     *
     * @param i The index of the element to be returned.
     * @returns A reference to the ith element.
     */
    const T &at(size_t i) const {
      if (i > size()) {
        throw BSplineException(ErrorCode::INVALID_ACCESS);
      }
      return (*_data)[i];
    };
  
    /*!
     * Returns a reference to the first element of the grid.
     *
     * @returns A reference to the first element.
     */
    const T &front() const {
      if (empty()) {
        throw BSplineException(ErrorCode::INVALID_ACCESS);
      }
      return _data->front();
    };
  
    /*!
     * Returns a reference to the last element of the grid.
     *
     * @returns A reference to the last element.
     */
    const T &back() const {
      if (empty()) {
        throw BSplineException(ErrorCode::INVALID_ACCESS);
      }
      return _data->back();
    };
  
    /*!
     * Returns the begin iterator of the grid.
     *
     * @returns An iterator to the first element.
     */
    const_iterator begin() const { return _data->begin(); };
  
    /*!
     * Returns the end iterator of the grid..
     *
     * @returns An iterator pointing behind the last element.
     */
    const_iterator end() const { return _data->end(); };
  
    /*!
     * Returns the index corresponding to the element x.
     *
     * @param x The element to be searched for.
     */
    size_t findElement(const T &x) const {
      auto it = std::lower_bound(begin(), end(), x);
  
      if (it == end() || *it != x) {
        // Element was not found
        throw BSplineException(ErrorCode::INCONSISTENT_DATA);
      } else {
        return std::distance(_data->begin(), it);
      }
    };
  };
  }  // namespace okruz::bspline::support
  #endif  // OKRUZ_BSPLINE_SUPPORT_GRID_H
  