#pragma once
#include <numeric>
#include <optional>
#include <string>
#include <concepts>
//import std.compat;

namespace Aftr
{
   template< typename T >
   bool isFloatEqual( const T& a, const T& b, const T& epsilon = T(0.00001) )
   {
      //sln todo... https://en.wikipedia.org/wiki/Catastrophic_cancellation
      //of course, this is way more complicated than simply seeing how close two numbers are to each other
      //https://stackoverflow.com/questions/17333/what-is-the-most-effective-way-for-float-and-double-comparison

      if( std::abs( a - b ) <= epsilon )
         return true;
      return false;
   }

   template< typename T >
   bool isFloatZero( const T& a, const T& epsilon = T(0.00001) )
   {
      if( std::abs( a ) <= epsilon )
         return true;
      return false;
   }

   //Given any string, the first occurrance of a floating point number matched by
   //this regular expression will be returned. If no number is found, a nullopt
   //will be returned.
   template< typename T >
   std::optional<T> find_first_float( std::string const& str );

   //Given two unsigned integral types. This function returns the distance from
   //a to b, ignoring any negative value that would result from subtraction.
   //So, for example distance_between( std::uint32_t( 8 ), std::uint32_t( 6 ) ) is two
   //dist_between( 0,0 ) -> 0
   //dist_between( 1,0 ) -> 1
   //dist_between( 0,1 ) -> 1
   //dist_between( 5,7 ) -> 2
   //dist_between( 7,5 ) -> 2
   template< std::unsigned_integral T >
   T distance_between( T a, T b ) noexcept
   {
      return a > b ? a - b : b - a;
   }


} //namespace Aftr