added expected and fmt for cleaner code/interfaces
This commit is contained in:
@ -30,6 +30,6 @@ addons:
|
|||||||
- "libqt5charts5-dev"
|
- "libqt5charts5-dev"
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- "qmake test/tstcpputils.pro"
|
- "qmake CLONE_EXPECTED=1 CLONE_FMT=1 test/tstcpputils.pro"
|
||||||
- "make -j2"
|
- "make -j2"
|
||||||
- ./tstcpputils
|
- ./tstcpputils
|
||||||
|
@ -19,6 +19,8 @@ set(sources
|
|||||||
)
|
)
|
||||||
|
|
||||||
set(dependencies
|
set(dependencies
|
||||||
|
expected
|
||||||
|
fmt
|
||||||
)
|
)
|
||||||
|
|
||||||
idf_component_register(
|
idf_component_register(
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// system includes
|
// system includes
|
||||||
#include <optional>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
// 3rdparty lib includes
|
||||||
|
#include <tl/expected.hpp>
|
||||||
|
#include <fmt/core.h>
|
||||||
|
|
||||||
// local includes
|
// local includes
|
||||||
#include "cppmacros.h"
|
#include "cppmacros.h"
|
||||||
|
|
||||||
#define CPPTYPESAFEENUM_SHOULD_INLINE
|
// These macros make it possible to define a typesafe enum with parse and
|
||||||
|
|
||||||
// These two macros make it possible to define a typesafe enum with parse and
|
|
||||||
// toString methods
|
// toString methods
|
||||||
|
|
||||||
#define DECLARE_TYPESAFE_ENUM_HELPER1(name) name,
|
#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_HELPER3(name) else if (str == CPP_STRINGIFY(name)) return TheEnum::name;
|
||||||
#define DECLARE_TYPESAFE_ENUM_HELPER4(name) cb(TheEnum::name, CPP_STRINGIFY(name));
|
#define DECLARE_TYPESAFE_ENUM_HELPER4(name) cb(TheEnum::name, CPP_STRINGIFY(name));
|
||||||
|
|
||||||
#ifdef CPPTYPESAFEENUM_SHOULD_INLINE
|
|
||||||
#define DECLARE_TYPESAFE_ENUM(Name, Derivation, Values) \
|
#define DECLARE_TYPESAFE_ENUM(Name, Derivation, Values) \
|
||||||
enum class Name Derivation \
|
enum class Name Derivation \
|
||||||
{ \
|
{ \
|
||||||
@ -30,14 +30,14 @@
|
|||||||
using TheEnum = Name; \
|
using TheEnum = Name; \
|
||||||
Values(DECLARE_TYPESAFE_ENUM_HELPER2) \
|
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<Name> parse##Name(std::string_view str) \
|
inline tl::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::nullopt; \
|
return tl::make_unexpected(fmt::format("invalid " #Name " ({})", str)); \
|
||||||
} \
|
} \
|
||||||
template<typename T> \
|
template<typename T> \
|
||||||
void iterate##Name(T &&cb) \
|
void iterate##Name(T &&cb) \
|
||||||
@ -47,36 +47,3 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define IMPLEMENT_TYPESAFE_ENUM(Name, Derivation, Values)
|
#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<Name> parse##Name(std::string_view str); \
|
|
||||||
template<typename T> \
|
|
||||||
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<Name> parse##Name(std::string_view str) \
|
|
||||||
{ \
|
|
||||||
using TheEnum = Name; \
|
|
||||||
if (false) {} \
|
|
||||||
Values(DECLARE_TYPESAFE_ENUM_HELPER3) \
|
|
||||||
return std::nullopt; \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
@ -2,74 +2,78 @@
|
|||||||
|
|
||||||
// system includes
|
// system includes
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <optional>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// 3rdparty lib includes
|
||||||
|
#include <tl/expected.hpp>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
namespace cpputils {
|
namespace cpputils {
|
||||||
template<typename T> constexpr std::optional<T> fromString(std::string_view str) = delete;
|
template<typename T> constexpr tl::expected<T, std::string> fromString(std::string_view str) = delete;
|
||||||
|
|
||||||
template<> constexpr inline std::optional<int8_t> fromString<int8_t>(std::string_view str)
|
template<> constexpr inline tl::expected<int8_t, std::string> fromString<int8_t>(std::string_view str)
|
||||||
{
|
{
|
||||||
int8_t val{};
|
int8_t val{};
|
||||||
if (std::sscanf(str.data(), "%" SCNi8, &val) == 1)
|
if (std::sscanf(str.data(), "%" SCNi8, &val) != 1)
|
||||||
return val;
|
return tl::make_unexpected(fmt::format("invalid int8_t {}", str));
|
||||||
return std::nullopt;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> constexpr inline std::optional<uint8_t> fromString<uint8_t>(std::string_view str)
|
template<> constexpr inline tl::expected<uint8_t, std::string> fromString<uint8_t>(std::string_view str)
|
||||||
{
|
{
|
||||||
uint8_t val{};
|
uint8_t val{};
|
||||||
if (std::sscanf(str.data(), "%" SCNu8, &val) == 1)
|
if (std::sscanf(str.data(), "%" SCNu8, &val) != 1)
|
||||||
return val;
|
return tl::make_unexpected(fmt::format("invalid uint8_t {}", str));
|
||||||
return std::nullopt;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> constexpr inline std::optional<int16_t> fromString<int16_t>(std::string_view str)
|
template<> constexpr inline tl::expected<int16_t, std::string> fromString<int16_t>(std::string_view str)
|
||||||
{
|
{
|
||||||
int16_t val{};
|
int16_t val{};
|
||||||
if (std::sscanf(str.data(), "%" SCNi16, &val) == 1)
|
if (std::sscanf(str.data(), "%" SCNi16, &val) != 1)
|
||||||
return val;
|
return tl::make_unexpected(fmt::format("invalid int16_t {}", str));
|
||||||
return std::nullopt;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> constexpr inline std::optional<uint16_t> fromString<uint16_t>(std::string_view str)
|
template<> constexpr inline tl::expected<uint16_t, std::string> fromString<uint16_t>(std::string_view str)
|
||||||
{
|
{
|
||||||
uint16_t val{};
|
uint16_t val{};
|
||||||
if (std::sscanf(str.data(), "%" SCNu16, &val) == 1)
|
if (std::sscanf(str.data(), "%" SCNu16, &val) != 1)
|
||||||
return val;
|
return tl::make_unexpected(fmt::format("invalid uint16_t {}", str));
|
||||||
return std::nullopt;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> constexpr inline std::optional<int32_t> fromString<int32_t>(std::string_view str)
|
template<> constexpr inline tl::expected<int32_t, std::string> fromString<int32_t>(std::string_view str)
|
||||||
{
|
{
|
||||||
int32_t val{};
|
int32_t val{};
|
||||||
if (std::sscanf(str.data(), "%" SCNi32, &val) == 1)
|
if (std::sscanf(str.data(), "%" SCNi32, &val) != 1)
|
||||||
return val;
|
return tl::make_unexpected(fmt::format("invalid int32_t {}", str));
|
||||||
return std::nullopt;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> constexpr inline std::optional<uint32_t> fromString<uint32_t>(std::string_view str)
|
template<> constexpr inline tl::expected<uint32_t, std::string> fromString<uint32_t>(std::string_view str)
|
||||||
{
|
{
|
||||||
uint32_t val{};
|
uint32_t val{};
|
||||||
if (std::sscanf(str.data(), "%" SCNu32, &val) == 1)
|
if (std::sscanf(str.data(), "%" SCNu32, &val) != 1)
|
||||||
return val;
|
return tl::make_unexpected(fmt::format("invalid uint32_t {}", str));
|
||||||
return std::nullopt;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> constexpr inline std::optional<int64_t> fromString<int64_t>(std::string_view str)
|
template<> constexpr inline tl::expected<int64_t, std::string> fromString<int64_t>(std::string_view str)
|
||||||
{
|
{
|
||||||
int64_t val{};
|
int64_t val{};
|
||||||
if (std::sscanf(str.data(), "%" SCNi64, &val) == 1)
|
if (std::sscanf(str.data(), "%" SCNi64, &val) != 1)
|
||||||
return val;
|
return tl::make_unexpected(fmt::format("invalid int64_t {}", str));
|
||||||
return std::nullopt;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> constexpr inline std::optional<uint64_t> fromString<uint64_t>(std::string_view str)
|
template<> constexpr inline tl::expected<uint64_t, std::string> fromString<uint64_t>(std::string_view str)
|
||||||
{
|
{
|
||||||
uint64_t val{};
|
uint64_t val{};
|
||||||
if (std::sscanf(str.data(), "%" SCNu64, &val) == 1)
|
if (std::sscanf(str.data(), "%" SCNu64, &val) != 1)
|
||||||
return val;
|
return tl::make_unexpected(fmt::format("invalid uint64_t {}", str));
|
||||||
return std::nullopt;
|
return val;
|
||||||
}
|
}
|
||||||
} // namespace cpputils
|
} // namespace cpputils
|
||||||
|
2
test/.gitignore
vendored
2
test/.gitignore
vendored
@ -1 +1,3 @@
|
|||||||
*.user*
|
*.user*
|
||||||
|
expected/
|
||||||
|
fmt/
|
||||||
|
@ -6,7 +6,8 @@ QT -= gui widgets
|
|||||||
CONFIG += c++17 qt console warn_on depend_includepath testcase
|
CONFIG += c++17 qt console warn_on depend_includepath testcase
|
||||||
CONFIG -= app_bundle
|
CONFIG -= app_bundle
|
||||||
|
|
||||||
SOURCES += tst_cppbitmask.cpp
|
SOURCES += \
|
||||||
|
tst_cppbitmask.cpp
|
||||||
|
|
||||||
CPPUTILS_DIR = $$PWD/..
|
CPPUTILS_DIR = $$PWD/..
|
||||||
|
|
||||||
@ -15,4 +16,39 @@ include($$CPPUTILS_DIR/cpputils_src.pri)
|
|||||||
include($$CPPUTILS_DIR/test/cpputilstestutils.pri)
|
include($$CPPUTILS_DIR/test/cpputilstestutils.pri)
|
||||||
include($$CPPUTILS_DIR/test/cpputilstestutils_src.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
|
QMAKE_CXXFLAGS += -Wno-missing-field-initializers
|
||||||
|
Reference in New Issue
Block a user