diff --git a/.travis.yml b/.travis.yml index 0e575a6..b202748 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,6 +30,6 @@ addons: - "libqt5charts5-dev" script: - - "qmake test/tstcpputils.pro" + - "qmake CLONE_EXPECTED=1 CLONE_FMT=1 test/tstcpputils.pro" - "make -j2" - ./tstcpputils diff --git a/CMakeLists.txt b/CMakeLists.txt index aff08d1..7b3aaa8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,8 @@ set(sources ) set(dependencies + expected + fmt ) idf_component_register( diff --git a/src/cpptypesafeenum.h b/src/cpptypesafeenum.h index 303c193..9d93c01 100644 --- a/src/cpptypesafeenum.h +++ b/src/cpptypesafeenum.h @@ -1,15 +1,16 @@ #pragma once // system includes -#include #include +// 3rdparty lib includes +#include +#include + // local includes #include "cppmacros.h" -#define CPPTYPESAFEENUM_SHOULD_INLINE - -// These two 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 #define DECLARE_TYPESAFE_ENUM_HELPER1(name) name, @@ -17,7 +18,6 @@ #define DECLARE_TYPESAFE_ENUM_HELPER3(name) else if (str == CPP_STRINGIFY(name)) return TheEnum::name; #define DECLARE_TYPESAFE_ENUM_HELPER4(name) cb(TheEnum::name, CPP_STRINGIFY(name)); -#ifdef CPPTYPESAFEENUM_SHOULD_INLINE #define DECLARE_TYPESAFE_ENUM(Name, Derivation, Values) \ enum class Name Derivation \ { \ @@ -30,14 +30,14 @@ using TheEnum = Name; \ Values(DECLARE_TYPESAFE_ENUM_HELPER2) \ } \ - return std::string{"Unknown " #Name "("} + std::to_string(int(value)) + ')'; \ + return fmt::format("Unknown " #Name "({})", int(value)); \ } \ - inline std::optional parse##Name(std::string_view str) \ + inline tl::expected parse##Name(std::string_view str) \ { \ using TheEnum = Name; \ if (false) {} \ Values(DECLARE_TYPESAFE_ENUM_HELPER3) \ - return std::nullopt; \ + return tl::make_unexpected(fmt::format("invalid " #Name " ({})", str)); \ } \ template \ void iterate##Name(T &&cb) \ @@ -47,36 +47,3 @@ } #define IMPLEMENT_TYPESAFE_ENUM(Name, Derivation, Values) -#else -#define DECLARE_TYPESAFE_ENUM(Name, Derivation, Values) \ - enum class Name Derivation \ - { \ - Values(DECLARE_TYPESAFE_ENUM_HELPER1) \ - }; \ - std::string toString(Name value); \ - std::optional parse##Name(std::string_view str); \ - template \ - void iterate##Name(T &&cb) \ - { \ - using TheEnum = Name; \ - Values(DECLARE_TYPESAFE_ENUM_HELPER4) \ - } - -#define IMPLEMENT_TYPESAFE_ENUM(Name, Derivation, Values) \ - ExportPrefix std::string toString(Name value) \ - { \ - switch (value) \ - { \ - using TheEnum = Name; \ - Values(DECLARE_TYPESAFE_ENUM_HELPER2) \ - } \ - return std::string{"Unknown " #Name "("} + std::to_string(int(value)) + ')'; \ - } \ - ExportPrefix std::optional parse##Name(std::string_view str) \ - { \ - using TheEnum = Name; \ - if (false) {} \ - Values(DECLARE_TYPESAFE_ENUM_HELPER3) \ - return std::nullopt; \ - } -#endif diff --git a/src/numberparsing.h b/src/numberparsing.h index 869bfb7..c25f51a 100644 --- a/src/numberparsing.h +++ b/src/numberparsing.h @@ -2,74 +2,78 @@ // system includes #include -#include #include #include +#include + +// 3rdparty lib includes +#include +#include namespace cpputils { -template constexpr std::optional fromString(std::string_view str) = delete; +template constexpr tl::expected fromString(std::string_view str) = delete; -template<> constexpr inline std::optional fromString(std::string_view str) +template<> constexpr inline tl::expected fromString(std::string_view str) { int8_t val{}; - if (std::sscanf(str.data(), "%" SCNi8, &val) == 1) - return val; - return std::nullopt; + if (std::sscanf(str.data(), "%" SCNi8, &val) != 1) + return tl::make_unexpected(fmt::format("invalid int8_t {}", str)); + return val; } -template<> constexpr inline std::optional fromString(std::string_view str) +template<> constexpr inline tl::expected fromString(std::string_view str) { uint8_t val{}; - if (std::sscanf(str.data(), "%" SCNu8, &val) == 1) - return val; - return std::nullopt; + if (std::sscanf(str.data(), "%" SCNu8, &val) != 1) + return tl::make_unexpected(fmt::format("invalid uint8_t {}", str)); + return val; } -template<> constexpr inline std::optional fromString(std::string_view str) +template<> constexpr inline tl::expected fromString(std::string_view str) { int16_t val{}; - if (std::sscanf(str.data(), "%" SCNi16, &val) == 1) - return val; - return std::nullopt; + if (std::sscanf(str.data(), "%" SCNi16, &val) != 1) + return tl::make_unexpected(fmt::format("invalid int16_t {}", str)); + return val; } -template<> constexpr inline std::optional fromString(std::string_view str) +template<> constexpr inline tl::expected fromString(std::string_view str) { uint16_t val{}; - if (std::sscanf(str.data(), "%" SCNu16, &val) == 1) - return val; - return std::nullopt; + if (std::sscanf(str.data(), "%" SCNu16, &val) != 1) + return tl::make_unexpected(fmt::format("invalid uint16_t {}", str)); + return val; } -template<> constexpr inline std::optional fromString(std::string_view str) +template<> constexpr inline tl::expected fromString(std::string_view str) { int32_t val{}; - if (std::sscanf(str.data(), "%" SCNi32, &val) == 1) - return val; - return std::nullopt; + if (std::sscanf(str.data(), "%" SCNi32, &val) != 1) + return tl::make_unexpected(fmt::format("invalid int32_t {}", str)); + return val; } -template<> constexpr inline std::optional fromString(std::string_view str) +template<> constexpr inline tl::expected fromString(std::string_view str) { uint32_t val{}; - if (std::sscanf(str.data(), "%" SCNu32, &val) == 1) - return val; - return std::nullopt; + if (std::sscanf(str.data(), "%" SCNu32, &val) != 1) + return tl::make_unexpected(fmt::format("invalid uint32_t {}", str)); + return val; } -template<> constexpr inline std::optional fromString(std::string_view str) +template<> constexpr inline tl::expected fromString(std::string_view str) { int64_t val{}; - if (std::sscanf(str.data(), "%" SCNi64, &val) == 1) - return val; - return std::nullopt; + if (std::sscanf(str.data(), "%" SCNi64, &val) != 1) + return tl::make_unexpected(fmt::format("invalid int64_t {}", str)); + return val; } -template<> constexpr inline std::optional fromString(std::string_view str) +template<> constexpr inline tl::expected fromString(std::string_view str) { uint64_t val{}; - if (std::sscanf(str.data(), "%" SCNu64, &val) == 1) - return val; - return std::nullopt; + if (std::sscanf(str.data(), "%" SCNu64, &val) != 1) + return tl::make_unexpected(fmt::format("invalid uint64_t {}", str)); + return val; } } // namespace cpputils diff --git a/test/.gitignore b/test/.gitignore index a222802..ef25983 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -1 +1,3 @@ *.user* +expected/ +fmt/ diff --git a/test/tstcpputils.pro b/test/tstcpputils.pro index 6b6ca39..64bd781 100644 --- a/test/tstcpputils.pro +++ b/test/tstcpputils.pro @@ -6,7 +6,8 @@ QT -= gui widgets CONFIG += c++17 qt console warn_on depend_includepath testcase CONFIG -= app_bundle -SOURCES += tst_cppbitmask.cpp +SOURCES += \ + tst_cppbitmask.cpp CPPUTILS_DIR = $$PWD/.. @@ -15,4 +16,39 @@ include($$CPPUTILS_DIR/cpputils_src.pri) include($$CPPUTILS_DIR/test/cpputilstestutils.pri) include($$CPPUTILS_DIR/test/cpputilstestutils_src.pri) +equals(CLONE_EXPECTED, 1) { + EXPECTED_DIR = $$PWD/expected + + message("Checking out expected...") + exists($$EXPECTED_DIR/.git): { + system("git -C $$EXPECTED_DIR pull") + } else { + system("git clone https://github.com/0xFEEDC0DE64/expected.git $$EXPECTED_DIR") + } +} else: exists($$PWD/../../expected/include) { + EXPECTED_DIR = $$PWD/../../expected +} else { + error("expected not found, please run git submodule update --init") +} + +include($$EXPECTED_DIR/expected.pri) + +equals(CLONE_FMT, 1) { + FMT_DIR = $$PWD/fmt + + message("Checking out fmt...") + exists($$FMT_DIR/.git): { + system("git -C $$FMT_DIR pull") + } else { + system("git clone https://github.com/0xFEEDC0DE64/fmt.git $$FMT_DIR") + } +} else: exists($$PWD/../../fmt/include) { + FMT_DIR = $$PWD/../../fmt +} else { + error("fmt not found, please run git submodule update --init") +} + +include($$FMT_DIR/fmt.pri) +include($$FMT_DIR/fmt_src.pri) + QMAKE_CXXFLAGS += -Wno-missing-field-initializers