#pragma once #include #include #include #include #include "WallpaperEngine/Logging/CLog.h" #include "WallpaperEngine/Data/Utils/SFINAE.h" namespace WallpaperEngine::Data::Builders { using namespace WallpaperEngine::Data::Utils::SFINAE; class VectorBuilder { /** * Convert template that calls the proper std::strto* function * based on the incoming type * * @tparam type * @param str * @return */ template static type convert (const char* str); public: /** * Takes the string and returns the vector size (2, 3 or 4) * * TODO: THIS SHOULD BE MOVED, RENAMED OR PLACED SOMEWHERE WHERE IT MAKES MORE SENSE * * @param str * @return */ static int preparseSize (const std::string& str) { const char* p = str.c_str (); const char* first = strchr (p, ' '); const char* second = first ? strchr (first + 1, ' ') : nullptr; const char* third = second ? strchr (second + 1, ' ') : nullptr; if (first == nullptr) { sLog.exception ("Invalid vector format: " + str + " (too few values, expected: 2, 3 or 4)"); } if (second == nullptr) { return 2; } if (third == nullptr) { return 3; } return 4; } /** * Takes a string value and parses it into a glm::vec. * This particular parsing uses spaces as separators and basic std::strto* functions * for the actual parsing of the values. * * @tparam length Vector length * @tparam type Vector storage type * @tparam qualifier Precision qualifier * * @param str The string to parse the vector from * * @return */ template [[nodiscard]] static glm::vec parse (const std::string& str) { // ensure a valid type is used, only 1 to 4 vectors are supported static_assert (length >= 1 && length <= 4, "Invalid vector length"); const char* p = str.c_str (); // get up to 4 spaces const char* first = strchr (p, ' '); const char* second = first ? strchr (first + 1, ' ') : nullptr; const char* third = second ? strchr (second + 1, ' ') : nullptr; // validate lengths against what was found in the strings if constexpr (length == 1) { if (first != nullptr) { sLog.exception ("Invalid vector format: " + str + " (too many values, expected: ", length, ")"); } } else if constexpr (length == 2) { if (first == nullptr) { sLog.exception ("Invalid vector format: " + str + " (too few values, expected: ", length, ")"); } if (second != nullptr) { sLog.exception ("Invalid vector format: " + str + " (too many values, expected: ", length, ")"); } } else if constexpr (length == 3) { if (first == nullptr || second == nullptr) { sLog.exception ("Invalid vector format: " + str + " (too few values, expected: ", length, ")"); } if (third != nullptr) { sLog.exception ("Invalid vector format: " + str + " (too many values, expected: ", length, ")"); } } else if constexpr (length == 4) { if (first == nullptr || second == nullptr || third == nullptr) { sLog.exception ("Invalid vector format: " + str + " (too few values, expected: ", length, ")"); } } // lengths validated, values can be used directly without issues if constexpr (length == 1) { return { convert (p) }; } else if constexpr (length == 2) { return { convert (p), convert (first + 1) }; } else if constexpr (length == 3) { return { convert (p), convert (first + 1), convert (second + 1) }; } else if constexpr (length == 4) { return { convert (p), convert (first + 1), convert (second + 1), convert (third + 1) }; } } template ::value, int> = 0> [[nodiscard]] static T parse (const std::string& str) { constexpr int length = GlmVecTraits::length; constexpr glm::qualifier qualifier = GlmVecTraits::qualifier; // call the specialized version of the function return parse::type, qualifier> (str); } }; template <> inline float VectorBuilder::convert (const char* str) { return std::strtof (str, nullptr); } template <> inline int VectorBuilder::convert (const char* str) { return std::stoi (str); } template <> inline unsigned int VectorBuilder::convert (const char* str) { return std::strtoul (str, nullptr, 10); } template <> inline double VectorBuilder::convert (const char* str) { return std::strtod (str, nullptr); } template <> inline uint8_t VectorBuilder::convert (const char* str) { return std::strtoul (str, nullptr, 10); } template <> inline uint16_t VectorBuilder::convert (const char* str) { return std::strtoul (str, nullptr, 10); } template <> inline uint64_t VectorBuilder::convert (const char* str) { return std::strtoull (str, nullptr, 10); } template <> inline int8_t VectorBuilder::convert (const char* str) { return std::strtol (str, nullptr, 10); } template <> inline int16_t VectorBuilder::convert (const char* str) { return std::strtol (str, nullptr, 10); } template <> inline int64_t VectorBuilder::convert (const char* str) { return std::strtoll (str, nullptr, 10); } template <> inline bool VectorBuilder::convert (const char* str) { return std::strtoul (str, nullptr, 10) > 0; } } // namespace WallpaperEngine::Data::Parsers