Sync from fork #2

Open
CommanderRedYT wants to merge 5 commits from CommanderRedYT/main into main
6 changed files with 66 additions and 27 deletions

View File

@ -23,18 +23,12 @@ set(sources
src/strutils.cpp src/strutils.cpp
) )
set(dependencies
fmt
)
idf_component_register( idf_component_register(
INCLUDE_DIRS INCLUDE_DIRS
src src
SRCS SRCS
${headers} ${headers}
${sources} ${sources}
REQUIRES
${dependencies}
) )
target_compile_options(${COMPONENT_TARGET} target_compile_options(${COMPONENT_TARGET}

View File

@ -33,6 +33,11 @@ struct ArrayView
m_begin{begin}, m_end{begin + size} m_begin{begin}, m_end{begin + size}
{} {}
template<std::size_t N>
constexpr explicit ArrayView(value_type (&array)[N]) noexcept :
m_begin{array}, m_end{array + N}
{}
constexpr ArrayView(const ArrayView &other) noexcept : constexpr ArrayView(const ArrayView &other) noexcept :
m_begin{other.m_begin}, m_end{other.m_end} m_begin{other.m_begin}, m_end{other.m_end}
{} {}

View File

@ -2,14 +2,12 @@
// system includes // system includes
#include <cstdio> #include <cstdio>
#include <format>
// 3rdparty lib includes
#include <fmt/core.h>
namespace cpputils { namespace cpputils {
std::string toString(ColorHelper color) std::string toString(ColorHelper color)
{ {
return fmt::format("#{:02X}{:02X}{:02X}", color.r, color.g, color.b); return std::format("#{:02X}{:02X}{:02X}", color.r, color.g, color.b);
} }
std::expected<ColorHelper, std::string> parseColor(std::string_view str) std::expected<ColorHelper, std::string> parseColor(std::string_view str)
@ -21,13 +19,14 @@ std::expected<ColorHelper, std::string> parseColor(std::string_view str)
if (ColorHelper helper; std::sscanf(str.data(), "#%1hhx%1hhx%1hhx", &helper.r, &helper.g, &helper.b) == 3) if (ColorHelper helper; std::sscanf(str.data(), "#%1hhx%1hhx%1hhx", &helper.r, &helper.g, &helper.b) == 3)
{ {
helper.r <<= 4; // #F00 -> #FF0000
helper.g <<= 4; helper.r *= 0x11;
helper.b <<= 4; helper.g *= 0x11;
helper.b *= 0x11;
return helper; return helper;
} }
return std::unexpected(fmt::format("invalid color {}", str)); return std::unexpected(std::format("invalid color {}", str));
} }
} // namespace cpputils } // namespace cpputils

View File

@ -3,9 +3,7 @@
// system includes // system includes
#include <string> #include <string>
#include <expected> #include <expected>
#include <format>
// 3rdparty lib includes
#include <fmt/core.h>
// local includes // local includes
#include "cppmacros.h" #include "cppmacros.h"
@ -13,6 +11,14 @@
// These macros make it possible to define a typesafe enum with parse and // These macros make it possible to define a typesafe enum with parse and
// toString methods // toString methods
namespace typesafeenum {
template<typename T>
struct iterateEnum;
template<typename T>
struct parseEnum;
}
#define DECLARE_TYPESAFE_ENUM_HELPER1(name, ...) name __VA_ARGS__ , #define DECLARE_TYPESAFE_ENUM_HELPER1(name, ...) name __VA_ARGS__ ,
#define DECLARE_TYPESAFE_ENUM_HELPER2(name, ...) case TheEnum::name: return #name; #define DECLARE_TYPESAFE_ENUM_HELPER2(name, ...) case TheEnum::name: return #name;
#define DECLARE_TYPESAFE_ENUM_HELPER3(name, ...) else if (str == CPP_STRINGIFY(name)) return TheEnum::name; #define DECLARE_TYPESAFE_ENUM_HELPER3(name, ...) else if (str == CPP_STRINGIFY(name)) return TheEnum::name;
@ -30,14 +36,14 @@
using TheEnum = Name; \ using TheEnum = Name; \
Values(DECLARE_TYPESAFE_ENUM_HELPER2) \ Values(DECLARE_TYPESAFE_ENUM_HELPER2) \
} \ } \
return fmt::format("Unknown " #Name "({})", int(value)); \ return std::format("Unknown " #Name "({})", int(value)); \
} \ } \
inline std::expected<Name, std::string> parse##Name(std::string_view str) \ inline std::expected<Name, std::string> parse##Name(std::string_view str) \
{ \ { \
using TheEnum = Name; \ using TheEnum = Name; \
if (false) {} \ if (false) {} \
Values(DECLARE_TYPESAFE_ENUM_HELPER3) \ Values(DECLARE_TYPESAFE_ENUM_HELPER3) \
return std::unexpected(fmt::format("invalid " #Name " ({})", str)); \ return std::unexpected(std::format("invalid " #Name " ({})", str)); \
} \ } \
template<typename T> \ template<typename T> \
void iterate##Name(T &&cb) \ void iterate##Name(T &&cb) \
@ -45,3 +51,25 @@
using TheEnum = Name; \ using TheEnum = Name; \
Values(DECLARE_TYPESAFE_ENUM_HELPER4) \ Values(DECLARE_TYPESAFE_ENUM_HELPER4) \
} }
#define DECLARE_GLOBAL_TYPESAFE_ENUM(Name, Derivation, Values) \
DECLARE_TYPESAFE_ENUM(Name, Derivation, Values) \
namespace typesafeenum { \
template<> \
struct iterateEnum<Name> { \
template<typename T> \
static void iterate(T&&cb) \
{ \
return iterate##Name(std::forward<T>(cb)); \
} \
}; \
template<> \
struct parseEnum<Name> { \
static std::expected<Name, std::string> parse(std::string_view str) \
{ \
return parse##Name(str); \
} \
}; \
}
using namespace typesafeenum;

View File

@ -3,12 +3,10 @@
// system includes // system includes
#include <cstdint> #include <cstdint>
#include <cstdio> #include <cstdio>
#include <expected>
#include <format>
#include <inttypes.h> #include <inttypes.h>
#include <string> #include <string>
#include <expected>
// 3rdparty lib includes
#include <fmt/format.h>
namespace cpputils { namespace cpputils {
template<typename T> std::expected<T, std::string> fromString(std::string_view str) = delete; template<typename T> std::expected<T, std::string> fromString(std::string_view str) = delete;
@ -94,4 +92,20 @@ template<> inline std::expected<uint64_t, std::string> fromString<uint64_t>(std:
return std::unexpected(fmt::format("invalid uint64_t {}", str)); return std::unexpected(fmt::format("invalid uint64_t {}", str));
return val; return val;
} }
template<> inline std::expected<float, std::string> fromString<float>(std::string_view str)
{
float val;
if (std::sscanf(str.data(), "%f", &val) != 1)
return std::unexpected(fmt::format("invalid float {}", str));
return val;
}
template<> inline std::expected<double, std::string> fromString<double>(std::string_view str)
{
double val;
if (std::sscanf(str.data(), "%lf", &val) != 1)
return std::unexpected(fmt::format("invalid double {}", str));
return val;
}
} // namespace cpputils } // namespace cpputils

View File

@ -2,10 +2,9 @@
// system includes // system includes
#include <cctype> #include <cctype>
#include <format>
#include <assert.h> #include <assert.h>
// 3rdparty lib includes
#include <fmt/core.h>
namespace cpputils { namespace cpputils {
namespace { namespace {
@ -56,7 +55,7 @@ std::expected<std::basic_string<unsigned char>, std::string> fromHexString(std::
case 'A'...'F': nibbles.nibble0 = c - 'A' + 10; break; case 'A'...'F': nibbles.nibble0 = c - 'A' + 10; break;
case 'a'...'f': nibbles.nibble0 = c - 'a' + 10; break; case 'a'...'f': nibbles.nibble0 = c - 'a' + 10; break;
default: default:
return std::unexpected(fmt::format("invalid character {} at pos {}", c, std::distance(std::begin(hex), iter))); return std::unexpected(std::format("invalid character {} at pos {}", c, std::distance(std::begin(hex), iter)));
} }
iter++; iter++;
@ -67,7 +66,7 @@ std::expected<std::basic_string<unsigned char>, std::string> fromHexString(std::
case 'A'...'F': nibbles.nibble1 = c - 'A' + 10; break; case 'A'...'F': nibbles.nibble1 = c - 'A' + 10; break;
case 'a'...'f': nibbles.nibble1 = c - 'a' + 10; break; case 'a'...'f': nibbles.nibble1 = c - 'a' + 10; break;
default: default:
return std::unexpected(fmt::format("invalid character {} at pos {}", c, std::distance(std::begin(hex), iter))); return std::unexpected(std::format("invalid character {} at pos {}", c, std::distance(std::begin(hex), iter)));
} }
iter++; iter++;