#pragma once #include "enumDetails.h" #include #include #include #include #include #include #include template concept stringlike = requires(const S & s) { s.substr(0); }; template concept NonStringIterableCollection = std::is_same_v().begin()), decltype(std::declval().end())> && !stringlike; namespace std { std::ostream & operator<<(std::ostream & s, const NonStringIterableCollection auto & collection) { s << '('; for (size_t nth {}; const auto & element : collection) { if (nth++) { s << ", "; } s << element; } return s << ')'; } template std::ostream & operator<<(std::ostream & s, const glm::mat & m) { return (s << std::span {&m[0], L}); } template std::ostream & operator<<(std::ostream & s, const glm::vec & v) { return (s << std::span {&v[0], L}); } template std::ostream & operator<<(std::ostream & s, const std::pair & v) { return (s << '(' << v.first << ", " << v.second << ')'); } namespace { template std::ostream & printTuple(std::ostream & s, const std::tuple & v, std::integer_sequence) { return ((s << (Idx ? ", " : "") << std::get(v)), ...); } } template std::ostream & operator<<(std::ostream & s, const std::tuple & v) { return printTuple(s << '{', v, std::make_index_sequence()) << '}'; } inline std::ostream & operator<<(std::ostream & s, const Arc & arc) { return s << arc.first << " ↺ " << arc.second; } template concept IsEnum = std::is_enum_v; template inline std::ostream & operator<<(std::ostream & s, const E & e) { return s << EnumTypeDetails::typeName << "::" << EnumDetails::to_string(e).value(); } } template std::string streamed_string(const T & v) { std::stringstream ss; ss << v; return std::move(ss).str(); } #define CLOG(x) std::cerr << __LINE__ << " : " #x " : " << x << "\n";