Program Listing for File utils.h

Return to documentation for file (src/sparsebase/utils/utils.h)

/*******************************************************
 * Copyright (c) 2022 SparCity, Amro Alabsi Aljundi, Taha Atahan Akyildiz, Arda
 *Sener All rights reserved.
 *
 * This file is distributed under MIT license.
 * The complete license agreement can be obtained at:
 * https://sparcityeu.github.io/sparsebase/pages/license.html
 ********************************************************/
#ifndef SPARSEBASE_SPARSEBASE_UTILS_H_
#define SPARSEBASE_SPARSEBASE_UTILS_H_

#include <any>
#include <cstdint>
#include <fstream>
#include <limits>
#include <string>
#include <typeindex>
#include <typeinfo>

#include "exception.h"

namespace sparsebase::utils {

typedef float CostType;
// Thanks to artificial mind blog:
// https://artificial-mind.net/blog/2020/10/03/always-false
template <typename... T>
constexpr bool always_false = false;

struct TypeIndexVectorHash {
  std::size_t operator()(const std::vector<std::type_index> &vf) const;
};

using std::numeric_limits;

// Cross float-integral type conversion is not currently available
template <typename T, typename U>
bool CanTypeFitValue(const U value) {
  bool decision;
  if constexpr (std::is_integral_v<T> != std::is_integral_v<U>)
    decision = false;
  if constexpr (std::is_integral_v<T> && std::is_integral_v<U>) {
    const intmax_t botT = []() {
      intmax_t ret;
      if constexpr (std::is_floating_point_v<T>)
        ret = intmax_t(-(numeric_limits<T>::max()));
      else
        ret = intmax_t(numeric_limits<T>::min());
      return ret;
    }();
    const intmax_t botU = []() {
      intmax_t ret;
      if constexpr (std::is_floating_point_v<U>)
        ret = intmax_t(-(numeric_limits<U>::max()));
      else
        ret = intmax_t(numeric_limits<U>::min());
      return ret;
    }();
    const uintmax_t topT = uintmax_t(numeric_limits<T>::max());
    const uintmax_t topU = uintmax_t(numeric_limits<U>::max());
    decision = !((botT > botU && value < (U)(botT)) ||
                 (topT < topU && value > (U)(topT)));
  } else if constexpr (!std::is_integral_v<T> && !std::is_integral_v<U>) {
    const double botT = []() {
      T ret;
      if constexpr (std::is_floating_point_v<T>)
        ret = T(-(numeric_limits<T>::max()));
      else
        ret = T(numeric_limits<T>::min());
      return ret;
    }();
    const double botU = []() {
      U ret;
      if constexpr (std::is_floating_point_v<U>)
        ret = U(-(numeric_limits<U>::max()));
      else
        ret = U(numeric_limits<U>::min());
      return ret;
    }();
    const double topT = numeric_limits<T>::max();
    const double topU = numeric_limits<U>::max();
    decision = !((botT > botU && value < (U)(botT)) ||
                 (topT < topU && value > (U)(topT)));
  }
  return decision;
  //} else if constexpr (std::is_integral_v<T> && !std::is_integral_v<U> ){
  //  const double topT = double(numeric_limits<T>::max());
  //  const uintmax_t topU = uintmax_t(numeric_limits<U>::max());
  //  const double botT = []() {
  //    if constexpr (std::is_floating_point_v<T>)
  //      return double(-(numeric_limits<T>::max()));
  //    else
  //      return double(numeric_limits<T>::min());
  //  }();
  //  const intmax_t botU = []() {
  //    if constexpr (std::is_floating_point_v<U>)
  //      return intmax_t(-(numeric_limits<U>::max()));
  //    else
  //      return intmax_t(numeric_limits<U>::min());
  //  }();
  //  return !(double(topU) > topT && double(value) > topT) || !(double(botU) <
  //  botT && double(value) > topT);
  //} else {
  //  const uintmax_t topT = uintmax_t(numeric_limits<T>::max());
  //  const double topU = double(numeric_limits<U>::max());
  //  const intmax_t botT = []() {
  //    if constexpr (std::is_floating_point_v<T>)
  //      return intmax_t(-(numeric_limits<T>::max()));
  //    else
  //      return intmax_t(numeric_limits<T>::min());
  //  }();
  //  const double botU = []() {
  //    if constexpr (std::is_floating_point_v<U>)
  //      return double(-(numeric_limits<U>::max()));
  //    else
  //      return double(numeric_limits<U>::min());
  //  }();
  //  return !(topU > double(topT) && value > double(topT)) || !(botU <
  //  double(botT) && value > double(topT));
  //}
}

template <typename FromType, typename ToType>
inline bool isTypeConversionSafe(FromType from_val, ToType to_val) {
  return from_val == to_val && CanTypeFitValue<ToType>(from_val);
}

template <typename ToType, typename FromType, typename SizeType>
ToType *ConvertArrayType(FromType *from_ptr, SizeType size) {
  if constexpr (!(std::is_same_v<ToType, void> &&
                  std::is_same_v<FromType, void>)) {
    if (from_ptr == nullptr) return nullptr;
    auto to_ptr = new ToType[size];
    for (SizeType i = 0; i < size; i++) {
      to_ptr[i] = from_ptr[i];
      if (!isTypeConversionSafe(from_ptr[i], to_ptr[i])) {
        throw utils::TypeException(
            "Could not convert array from type " +
            std::string(std::type_index(typeid(FromType)).name()) +
            " to type " + std::string(std::type_index(typeid(ToType)).name()) +
            ". Overflow detected");
      }
    }
    return to_ptr;
  }
  return nullptr;
}

template <typename T>
class OnceSettable {
 public:
  OnceSettable() : is_set_(false) {}
  operator T() const { return data_; }
  OnceSettable(const OnceSettable &) = delete;
  OnceSettable(OnceSettable &&) = delete;
  OnceSettable &operator=(T &&data) {
    if (!is_set_) {
      data_ = std::move(data);
      is_set_ = true;
      return *this;
    }
    throw utils::AttemptToReset<T>();
  }
  const T &get() const { return data_; }

 private:
  T data_;
  bool is_set_;
};
std::string demangle(const std::string &name);

std::string demangle(std::type_index type);

class Identifiable {
 public:
  virtual std::type_index get_id() const = 0;

  virtual std::string get_name() const = 0;
};
template <typename IdentifiableType, typename Base>
class IdentifiableImplementation : public Base {
 public:
  virtual std::type_index get_id() const { return typeid(IdentifiableType); }

  virtual std::string get_name() const { return utils::demangle(get_id()); };

  static std::type_index get_id_static() { return typeid(IdentifiableType); }

  static std::string get_name_static() {
    return utils::demangle(get_id_static());
  };
};

template <typename Interface>
struct Implementation {
 public:
  Implementation() = default;
  template <typename ConcreteType>
  explicit Implementation(ConcreteType &&object)
      : storage{std::forward<ConcreteType>(object)},
        getter{[](std::any &storage) -> Interface & {
          return std::any_cast<ConcreteType &>(storage);
        }} {}
  Implementation(const Implementation &object)
      : storage{object.storage}, getter{object.getter} {}
  Implementation(Implementation &&object) noexcept
      : storage{std::move(object.storage)}, getter{std::move(object.getter)} {}
  Implementation &operator=(Implementation other) {
    storage = other.storage;
    getter = other.getter;
    return *this;
  }

  Interface *operator->() { return &getter(storage); }

 private:
  std::any storage;
  Interface &(*getter)(std::any &);
};

}  // namespace sparsebase::utils

#ifdef _HEADER_ONLY
#include "sparsebase/utils/utils.cc"
#endif

#endif