// SPDX-FileCopyrightText: 2021-2024 The Ikarus Developers mueller@ibb.uni-stuttgart.de
// SPDX-License-Identifier: LGPL-3.0-or-later

/**
 * \file math.hh
 * \brief Implementation of math related algorithms
 */

#pragma once
#include <concepts>

namespace Ikarus {
namespace Impl {
  /**
   * @brief Helper function for compile-time square root calculation.
   *
   * @tparam T The type for which square root is calculated.
   * @param x The value for which square root is calculated.
   * @param lo Lower bound for the search interval.
   * @param hi Upper bound for the search interval.
   * @return constexpr T The calculated square root.
   */
  template <typename T>
  constexpr T sqrt_helper(T x, T lo, T hi) {
    if (lo == hi)
      return lo;

    const T mid = (lo + hi + 1) / 2;

    if (x / mid < mid)
      return sqrt_helper<T>(x, lo, mid - 1);
    else
      return sqrt_helper(x, mid, hi);
  }

} // namespace Impl

/**
 * @brief Compile-time square root for integer types.
 *
 * @tparam T The integral type for which square root is calculated.
 * @param x The value for which square root is calculated.
 * @return constexpr T The calculated square root.
 */
template <typename T>
requires std::integral<T>
constexpr T ct_sqrt(T x) {
  return Impl::sqrt_helper<T>(x, 0, x / 2 + 1);
}
} // namespace Ikarus
