Program Listing for File fastopt.cpp

Return to documentation for file (src/common/fastopt.cpp)

#include "common/fastopt.h"

#include <utility>

namespace marian {

const std::unique_ptr<const FastOpt> FastOpt::uniqueNullPtr{nullptr};

// see fastopt.h for comments
namespace fastopt_helpers {

// helper structs for dynamic type conversion and specializations
// for different conversion scenarios.

// general template, mostly for numerical and logical types
template <typename To, typename From>
struct Convert {
  static inline To apply(const From& from) {
    return (To)from;
  }
};

// specialization for translating from string, @TODO check if this is required at all, mostly for compilation now.
template <typename To>
struct Convert<To, std::string> {
  static inline To apply(const std::string& /* from */) {
    ABORT("Not implemented");
  }
};

// convert anything to string, checked at compile-time
template <typename From>
struct Convert<std::string, From> {
  static inline std::string apply(const From& from) {
    return std::to_string(from);
  }
};

// do nothing conversion for std::string
template <>
struct Convert<std::string, std::string> {
  static inline std::string apply(const std::string& from) {
    return from;
  }
};

// helper class for FastOpt::as<T>() used for specializations
template <typename T>
T As<T>::apply(const FastOpt& node) {
  ABORT_IF(!node.isScalar(), "Node is not a scalar node");

  if(node.isBool())
    return Convert<T, bool>::apply(node.value_.as<bool>());
  else if(node.isInt())
    return Convert<T, int64_t>::apply(node.value_.as<int64_t>());
  else if(node.isFloat())
    return Convert<T, double>::apply(node.value_.as<double>());
  else if(node.isString())
    return Convert<T, std::string>::apply(node.value_.as<std::string>());
  else {
    ABORT("Casting of value failed");
  }
}

// specializations for simple types
template struct As<bool>;
template struct As<int>;
template struct As<unsigned long>;
template struct As<float>;
template struct As<double>;
template struct As<std::string>;

// specialization of above class for std::vector<T>
template <typename T>
std::vector<T> As<std::vector<T>>::apply(const FastOpt& node) {
  ABORT_IF(!node.isSequence(), "Node is not a sequence node");

  std::vector<T> seq;
  for(const auto& elem : node.array_)
    seq.push_back(elem->as<T>());
  return seq;
}

// specializations for simple vector types
template struct As<std::vector<bool>>;
template struct As<std::vector<int>>;
// Windows, Linux based OS and Mac have different type definitions for 'unsigned long'.
// So, we need an explicit definitions for uint64_t, that cover different platforms.
// Otherwise, there's a linking error on windows or Linux or Mac.
// https://software.intel.com/en-us/articles/size-of-long-integer-type-on-different-architecture-and-os/
// https://stackoverflow.com/questions/32021860/c-should-you-size-t-with-a-regular-array
// MacOS: size_t = unsigned long (8 bytes), uint64_t = unsigned long long (8 bytes)
// Linux: size_t = unsigned long (8 bytes), uint64_t = unsigned long (8 bytes)
// Windows: size_t = unsigned long long (8 bytes), uint64_t = unsigned long long (8 bytes)
template struct As<std::vector<unsigned long long>>;
template struct As<std::vector<unsigned long>>;
template struct As<std::vector<float>>;
template struct As<std::vector<double>>;
template struct As<std::vector<std::string>>;

// specialization of above class for std::pair<T>
template <typename T1, typename T2>
std::pair<T1, T2> As<std::pair<T1, T2>>::apply(const FastOpt& node) {
  ABORT_IF(!node.isSequence(), "Node is not a sequence node");
  ABORT_IF(node.size() != 2, "Sequence must contain two elements in order to convert to pair");
  return std::make_pair(node[0].as<T1>(), node[1].as<T2>());
}

template struct As<std::pair<int, int>>;

}
}