/*
  Copyright (C) 2018 David Robillard <d@drobilla.net>
  Copyright (C) 2006-2007 Chris Hamilton <chamilton@cs.dal.ca>

  This program is free software: you can redistribute it and/or modify it under
  the terms of the GNU General Public License as published by the Free Software
  Foundation, either version 2 of the License, or (at your option) any later
  version.

  This program is distributed in the hope that it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
  details.

  You should have received a copy of the GNU General Public License along with
  this program.  If not, see <https://www.gnu.org/licenses/>.
*/

#ifndef CHILBERT_HILBERT_HPP
#define CHILBERT_HILBERT_HPP

#include <cstddef>

namespace chilbert {

/** Map the point `p` to a Hilbert Index.
 *
 * @tparam P Type used to represent a value in a point dimension.
 * @tparam H Hilbert Index.
 *
 * @param p Point with `n` dimensions.
 * @param m Precision of each dimension in bits.
 * @param n Number of dimensions.
 * @param[out] h Hilbert Index.
 */
template <class P, class H>
inline void coords_to_index(const P* const p,
                            const size_t   m,
                            const size_t   n,
                            H&             h);

/** Map the Hilbert Index `p` to a point.
 *
 * @tparam P Type used to represent a value in a point dimension.
 * @tparam H Hilbert Index.
 *
 * @param[out] p Point with `n` dimensions.
 * @param m Precision of each dimension in bits.
 * @param n Number of dimensions.
 * @param h Hilbert Index.
 */
template <class P, class H>
inline void index_to_coords(P* const     p,
                            const size_t m,
                            const size_t n,
                            const H&     h);

/** Map the point `p` to a Compact Hilbert Index.
 *
 * @tparam P Type used to represent a value in a point dimension.
 * @tparam H Compact Hilbert Index.
 *
 * @param p Point with `n` dimensions.
 * @param ms Array of `n` precision values for each dimension in bits.
 * @param n Number of dimensions.
 * @param[out] hc Compact Hilbert Index.
 * @param M Optional net precision (sum of `ms`), the size of `hc` in bits.
 * @param m Optional largest precision in `m`.
 */
template <class P, class H>
inline void coords_to_compact_index(const P* const      p,
                                    const size_t* const ms,
                                    const size_t        n,
                                    H&                  hc,
                                    const size_t        M = 0,
                                    const size_t        m = 0);

/** Map the Compact Hilbert Index `hc` to a point.
 *
 * @tparam P Type used to represent a value in a point dimension.
 * @tparam H Compact Hilbert Index.
 *
 * @param[out] p Point with `n` dimensions.
 * @param ms Array of `n` precision values for each dimension in bits.
 * @param n Number of dimensions.
 * @param hc Compact Hilbert Index.
 * @param M Optional net precision (sum of `ms`), the size of `hc` in bits.
 * @param m Optional largest precision in `m`.
 */
template <class P, class H>
inline void compact_index_to_coords(P* const            p,
                                    const size_t* const ms,
                                    const size_t        n,
                                    const H&            hc,
                                    const size_t        M = 0,
                                    const size_t        m = 0);

} // namespace chilbert

#include "chilbert/Hilbert.ipp"

#endif