// Copyright (c) 2016 Graphcore Ltd. All rights reserved.
/** \file VertexTemplates.hpp
 *
 * Generate a string describing a vertex type.
 *
 */

#ifndef poputil_VertexTemplates_hpp
#define poputil_VertexTemplates_hpp
#include <poplar/Type.hpp>
#include <string>

namespace poputil {

inline std::string templateVertexParams(bool first) {
  if (first)
    return "";
  else
    return ">";
}

template <typename... Args>
inline std::string templateVertexParams(bool first, const std::string &val,
                                        Args &&...args);

template <typename... Args>
inline std::string templateVertexParams(bool first, const char *val,
                                        Args &&...args);

template <typename... Args>
inline std::string templateVertexParams(bool first, const poplar::Type &type,
                                        Args &&...args);

template <typename... Args>
inline std::string templateVertexParams(bool first, bool b, Args &&...args);

template <typename T> struct VertexTemplateToString {
  static std::string to_string(const T &x) { return std::to_string(x); }
};

template <> struct VertexTemplateToString<poplar::StringRef> {
  static std::string to_string(const poplar::StringRef &ref) { return ref; }
};

template <typename T, typename... Args>
inline std::string templateVertexParams(bool first, const T &val,
                                        Args &&...args) {
  std::string p = first ? "<" : ",";
  p += VertexTemplateToString<T>::to_string(val) +
       templateVertexParams(false, std::forward<Args>(args)...);
  return p;
}

template <typename... Args>
inline std::string templateVertexParams(bool first, const poplar::Type &type,
                                        Args &&...args) {
  std::string p = first ? "<" : ",";
  p += type.toString() +
       templateVertexParams(false, std::forward<Args>(args)...);
  return p;
}

template <typename... Args>
inline std::string templateVertexParams(bool first, const std::string &val,
                                        Args &&...args) {
  std::string p = first ? "<" : ",";
  p += val + templateVertexParams(false, std::forward<Args>(args)...);
  return p;
}

template <typename... Args>
inline std::string templateVertexParams(bool first, const char *val,
                                        Args &&...args) {
  std::string p = first ? "<" : ",";
  p += val + templateVertexParams(false, std::forward<Args>(args)...);
  return p;
}

template <typename... Args>
inline std::string templateVertexParams(bool first, bool b, Args &&...args) {
  std::string p = first ? "<" : ",";
  auto bstr = (b ? "true" : "false");
  p += bstr + templateVertexParams(false, std::forward<Args>(args)...);
  return p;
}

/**
 * Generate a string representation of a Vertex type for use by
 * poplar::Graph::addVertex().
 *
 * \param name  The name of the vertex.
 * \param args  The types of the arguments to the vertex.
 * \return      A string representation of the vertex type.
 */
template <typename... Args>
inline std::string templateVertex(const std::string &name, Args &&...args) {
  return name + templateVertexParams(true, std::forward<Args>(args)...);
}

} // namespace poputil

#endif // poputil_VertexTemplates_hpp
