// vi:set ft=cpp: -*- Mode: C++ -*-
/*
 * (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
 *     economic rights: Technische Universität Dresden (Germany)
 *
 * License: see LICENSE.spdx (in this directory or the directories above)
 */
#pragma once

#include "type_traits"

/**
 * \ingroup cxx_api
 * \brief Various kinds of C++ utilities.
 */
namespace cxx
{
  // trivial, used to terminate the variadic recursion
  template<typename A>
  constexpr A const &
  min(A const &a)
  { return a; }

  /**
   * \ingroup cxx_api
   * Get the minimum of `a1` and `a2` upt to `aN`.
   *
   * \param a1     The first value.
   * \param a2     The second value.
   * \param ...a   Arbitrary number of additional parameters.
   *
   * Matches with automatic argument type deduction.
   */
  template<typename A, typename ...ARGS>
  constexpr A const &
  min(A const &a1, A const &a2, ARGS const &...a)
  {
    return min((a1 <= a2) ? a1 : a2, a...);
  }

  /**
   * \ingroup cxx_api
   * Get the minimum of `a1` and `a2` upt to `aN`.
   *
   * \param a1     The first value.
   * \param a2     The second value.
   * \param ...a   Arbitrary number of additional parameters.
   *
   * Matches with explicit template type A.
   */
  template<typename A, typename ...ARGS>
  constexpr A const &
  min(cxx::identity_t<A> const &a1,
      cxx::identity_t<A> const &a2,
      ARGS const &...a)
  {
    return min<A>((a1 <= a2) ? a1 : a2, a...);
  }

  // trivial, used to terminate the variadic recursion
  template<typename A>
  constexpr A const &
  max(A const &a)
  { return a; }

  /**
   * \ingroup cxx_api
   * Get the maximum of `a1` and `a2` upt to `aN`.
   *
   * \param a1     The first value.
   * \param a2     The second value.
   * \param ...a   Arbitrary number of additional parameters.
   *
   * Matches with automatic argument type deduction.
   */
  template<typename A, typename ...ARGS>
  constexpr A const &
  max(A const &a1, A const &a2, ARGS const &...a)
  { return max((a1 >= a2) ? a1 : a2, a...); }

  /**
   * \ingroup cxx_api
   * Get the maximum of `a1` and `a2` upt to `aN`.
   *
   * \param a1     The first value.
   * \param a2     The second value.
   * \param ...a   Arbitrary number of additional parameters.
   *
   * Matches with explicit template type A.
   */
  template<typename A, typename ...ARGS>
  constexpr A const &
  max(cxx::identity_t<A> const &a1,
      cxx::identity_t<A> const &a2,
      ARGS const &...a)
  {
    return max<A>((a1 >= a2) ? a1 : a2, a...);
  }

  /**
   * \ingroup cxx_api
   * \brief Limit \a v to the range given by \a lo and \a hi.
   * \param v   The value to clamp.
   * \param lo  The lower boundary to clamp \a v to.
   * \param hi  The upper boundary to clamp \a v to.
   */
  template< typename T1 >
  inline
  T1 clamp(T1 v, T1 lo, T1 hi)
  { return min(hi, max(lo, v)); }
};
