Program Listing for File conversion.hpp

Return to documentation for file (SeQuant/core/utility/conversion.hpp)

#ifndef SEQUANT_UTILITY_CONVERSION_HPP
#define SEQUANT_UTILITY_CONVERSION_HPP

#include <SeQuant/core/utility/exception.hpp>

#include <charconv>
#include <concepts>
#include <string_view>
#include <system_error>
#include <typeinfo>

namespace sequant {

class ConversionException : public Exception {
 public:
  using Exception::Exception;
};

namespace {
template <typename T, typename Arg>
  requires(std::integral<T> || std::floating_point<T>)
T string_to_impl(std::string_view str, Arg &&arg) {
  T val = 0;

  std::from_chars_result result =
      std::from_chars(str.begin(), str.end(), val, std::forward<Arg>(arg));

  // Note: Beware that typeid(T).name() yields something implementation defined,
  // which may or may not be useful for a human
  if (result.ec != std::errc{}) {
    switch (result.ec) {
      case std::errc::invalid_argument:
        throw ConversionException("'" + std::string(str) +
                                  "' is not a valid '" + typeid(T).name() +
                                  "'");
      case std::errc::result_out_of_range:
        throw ConversionException("'" + std::string(str) +
                                  "' is out of range for type '" +
                                  typeid(T).name() + "'");
      default:
        throw ConversionException("Unexpected conversion error");
    }
  }

  if (result.ptr != str.end()) {
    // Incomplete parse
    throw ConversionException("'" + std::string(str) +
                              "' could not be fully parsed as a '" +
                              typeid(T).name() + "'");
  }

  return val;
}

}  // namespace

template <typename T>
concept string_to_supports =
    requires(const char *c, T &v) { std::from_chars(c, c + 1, v); };

template <std::integral T>
T string_to(std::string_view str, int base = 10) {
  static_assert(string_to_supports<T>,
                "Your C++ standard library is missing a std::from_chars "
                "implementation for this integral type");
  return string_to_impl<T>(str, base);
}

template <std::floating_point T>
T string_to(std::string_view str,
            std::chars_format fmt = std::chars_format::general) {
  static_assert(string_to_supports<T>,
                "Your C++ standard library is missing a std::from_chars "
                "implementation for this floating point type");

  return string_to_impl<T>(str, fmt);
}

}  // namespace sequant

#endif