Skip to content

Commit

Permalink
Merge branch 'main' of github.com:getml/reflect-cpp
Browse files Browse the repository at this point in the history
  • Loading branch information
liuzicheng1987 committed Apr 16, 2024
2 parents 62619d4 + fbeca9b commit bcf3483
Show file tree
Hide file tree
Showing 13 changed files with 273 additions and 10 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,7 @@
*.yaml

!vcpkg.json

# clangd
compile_flags.txt
compile_commands.json
50 changes: 47 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.15)

option(REFLECTCPP_BUILD_SHARED "Build shared library" OFF)
option(REFLECTCPP_BUILD_SHARED "Build shared library" ${BUILD_SHARED_LIBS})
option(REFLECTCPP_BSON "Enable BSON support" OFF)
option(REFLECTCPP_CBOR "Enable CBOR support" OFF)
option(REFLECTCPP_FLEXBUFFERS "Enable flexbuffers support" OFF)
Expand All @@ -10,8 +10,15 @@ option(REFLECTCPP_YAML "Enable YAML support" OFF)

option(REFLECTCPP_BUILD_TESTS "Build tests" OFF)

# enable vcpkg if require features other than JSON
set(REFLECTCPP_USE_VCPKG_DEFAULT OFF)
if (REFLECTCPP_BSON OR REFLECTCPP_CBOR OR REFLECTCPP_FLEXBUFFERS OR REFLECTCPP_XML OR REFLECTCPP_TOML OR REFLECTCPP_YAML)
# enable vcpkg per default if require features other than JSON
set(REFLECTCPP_USE_VCPKG_DEFAULT ON)
endif()

option(REFLECTCPP_USE_VCPKG "Use VCPKG to download and build dependencies" ${REFLECTCPP_USE_VCPKG_DEFAULT})

if (REFLECTCPP_USE_VCPKG)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake CACHE STRING "Vcpkg toolchain file")
endif ()

Expand All @@ -25,7 +32,9 @@ else ()
add_library(reflectcpp STATIC src/yyjson.c)
endif ()

target_include_directories(reflectcpp PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_compile_features(reflectcpp PUBLIC cxx_std_20)

target_include_directories(reflectcpp PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include> )

if (REFLECTCPP_BSON)
find_package(bson-1.0 CONFIG REQUIRED)
Expand Down Expand Up @@ -66,3 +75,38 @@ target_compile_options(reflectcpp PRIVATE -Wall)
if (REFLECTCPP_BUILD_TESTS)
add_subdirectory(tests)
endif ()


include(GNUInstallDirs)
include(CMakePackageConfigHelpers)

configure_package_config_file(reflectcpp-config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/reflectcpp-config.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/reflectcpp
)

install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/reflectcpp-config.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/reflectcpp"
)

file(GLOB_RECURSE RFL_HEADERS RELATIVE ${CMAKE_CURRENT_LIST_DIR} "${CMAKE_CURRENT_LIST_DIR}/include/*" )

target_sources(reflectcpp
PUBLIC
FILE_SET reflectcpp_headers
TYPE HEADERS
BASE_DIRS $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
FILES ${RFL_HEADERS})

install(
TARGETS reflectcpp
EXPORT reflectcpp-exports
FILE_SET reflectcpp_headers DESTINATION ${INCLUDE_INSTALL_DIR}
)

install(
EXPORT reflectcpp-exports
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/reflectcpp
NAMESPACE reflectcpp::
)
1 change: 1 addition & 0 deletions include/rfl/internal/bind_to_tuple.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "../always_false.hpp"
#include "is_named_tuple.hpp"
#include "num_fields.hpp"

namespace rfl {
namespace internal {
Expand Down
2 changes: 1 addition & 1 deletion include/rfl/internal/get_field_names.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ consteval auto get_field_name_str_view() {
#endif
#if defined(__clang__)
const auto split = func_name.substr(0, func_name.size() - 2);
return split.substr(split.find_last_of(".") + 1);
return split.substr(split.find_last_of(":.") + 1);
#elif defined(__GNUC__)
const auto split = func_name.substr(0, func_name.size() - 2);
return split.substr(split.find_last_of(":") + 1);
Expand Down
97 changes: 92 additions & 5 deletions include/rfl/internal/num_fields.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ the potential array as we can without missing variables in subsequent fields.
This is the purpose of get_nested_array_size().
*/

#include <algorithm>
#include <cstddef>
#include <type_traits>
#include <utility>
Expand All @@ -48,6 +49,29 @@ This is the purpose of get_nested_array_size().
namespace rfl {
namespace internal {

template <class Derived>
struct any_empty_base {
any_empty_base(std::size_t);
template <class Base>
requires(
std::is_empty_v<std::remove_cvref_t<Base>> &&
std::is_base_of_v<std::remove_cvref_t<Base>,
std::remove_cv_t<Derived>> &&
!std::is_same_v<std::remove_cvref_t<Base>, std::remove_cv_t<Derived>>)
constexpr operator Base&() const noexcept;
};

template <class Derived>
struct any_base {
any_base(std::size_t);
template <class Base>
requires(
std::is_base_of_v<std::remove_cvref_t<Base>,
std::remove_cv_t<Derived>> &&
!std::is_same_v<std::remove_cvref_t<Base>, std::remove_cv_t<Derived>>)
constexpr operator Base&() const noexcept;
};

struct any {
any(std::size_t);
template <typename T>
Expand Down Expand Up @@ -76,12 +100,12 @@ struct CountFieldsHelper {
}

template <std::size_t n = 0>
static consteval std::size_t count_max_fields() {
static consteval std::size_t count_max_args_in_agg_init() {
static_assert(n <= static_cast<std::size_t>(sizeof(T)));
if constexpr (constructible<n>() && !constructible<n + 1>()) {
return n;
} else {
return count_max_fields<n + 1>();
return count_max_args_in_agg_init<n + 1>();
}
}

Expand All @@ -97,20 +121,83 @@ struct CountFieldsHelper {
}
}

template <std::size_t max_args, std::size_t index = 0>
static consteval std::size_t find_the_sole_non_empty_base_index() {
static_assert(index < max_args);
constexpr auto check = []<std::size_t... l, std::size_t... r>(
std::index_sequence<l...>,
std::index_sequence<r...>) {
return requires {
T{any_empty_base<T>(l)..., any_base<T>(0), any_empty_base<T>(r)...};
};
};

if constexpr (check(std::make_index_sequence<index>(),
std::make_index_sequence<max_args - index - 1>())) {
return index;
} else {
return find_the_sole_non_empty_base_index<max_args, index + 1>();
}
}

template <std::size_t arg_index, std::size_t size = 0>
static consteval std::size_t get_nested_base_field_count() {
static_assert(size <= sizeof(T));
if constexpr (constructible_with_nested<arg_index, size, 0>() &&
!constructible_with_nested<arg_index, size + 1, 0>()) {
return size;
} else {
return get_nested_base_field_count<arg_index, size + 1>();
}
}

template <std::size_t n, std::size_t max_arg_num>
static consteval bool has_n_base_param() {
constexpr auto right_len = max_arg_num>=n ? max_arg_num-n : 0;
return []<std::size_t... l, std::size_t... r>(std::index_sequence<l...>,
std::index_sequence<r...>) {
return requires { T{any_base<T>(l)..., any(r)...}; };
}(std::make_index_sequence<n>(), std::make_index_sequence<right_len>());
}

template <std::size_t max_arg_num, std::size_t index = 0>
static consteval std::size_t base_param_num() {
if constexpr (!has_n_base_param<index + 1, max_arg_num>()) {
return index;
} else {
return base_param_num<max_arg_num, index + 1>();
}
}

template <std::size_t index, std::size_t max>
static consteval std::size_t count_fields_impl() {
static consteval std::size_t constructible_no_brace_elision() {
static_assert(index <= max);
if constexpr (index == max) {
return 0;
} else {
return 1 +
count_fields_impl<
constructible_no_brace_elision<
index + get_nested_array_size<index, max - index, 0>(), max>();
}
}

static consteval std::size_t count_fields() {
return count_fields_impl<0, count_max_fields()>();
constexpr std::size_t max_agg_args = count_max_args_in_agg_init();
constexpr std::size_t no_brace_ellison_args =
constructible_no_brace_elision<0, max_agg_args>();
constexpr std::size_t base_args = base_param_num<no_brace_ellison_args>();
if constexpr (no_brace_ellison_args == 0 && base_args == 0) {
// Empty struct
return 0;
} else if constexpr (base_args == no_brace_ellison_args) {
// Special case when the derived class is empty.
// In such cases the filed number is the fields in base class.
// Note that there should be only one base class in this case.
return get_nested_base_field_count<
find_the_sole_non_empty_base_index<max_agg_args>()>();
} else {
return no_brace_ellison_args - base_args;
}
}
};

Expand Down
37 changes: 37 additions & 0 deletions reflectcpp-config.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
@PACKAGE_INIT@

set(REFLECTCPP_BSON @REFLECTCPP_BSON@)
set(REFLECTCPP_FLEXBUFFERS @REFLECTCPP_FLEXBUFFERS@)
set(REFLECTCPP_TOML @REFLECTCPP_TOML@)
set(REFLECTCPP_XML @REFLECTCPP_XML@)
set(REFLECTCPP_YAML @REFLECTCPP_YAML@)

if(REFLECTCPP_BSON OR REFLECTCPP_FLEXBUFFERS OR REFLECTCPP_XML OR REFLECTCPP_YAML)
include(CMakeFindDependencyMacro)
endif()

include(${CMAKE_CURRENT_LIST_DIR}/reflectcpp-exports.cmake)


if (REFLECTCPP_BSON)
find_dependency(bson-1.0)
endif ()

if (REFLECTCPP_FLEXBUFFERS)
find_dependency(flatbuffers)
endif ()

if (REFLECTCPP_TOML)
find_package(PkgConfig REQUIRED)
pkg_check_modules(tomlplusplus REQUIRED IMPORTED_TARGET tomlplusplus)
endif()

if (REFLECTCPP_XML)
find_dependency(pugixml)
endif ()

if (REFLECTCPP_YAML)
find_dependency(yaml-cpp)
endif ()

check_required_components(reflectcpp)
2 changes: 1 addition & 1 deletion tests/json/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
project(reflect-cpp-json-tests)

file(GLOB_RECURSE SOURCES "*.cpp")
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS "*.cpp")

add_executable(reflect-cpp-json-tests ${SOURCES})

Expand Down
26 changes: 26 additions & 0 deletions tests/json/test_inheritance.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include <cassert>
#include <iostream>
#include <rfl.hpp>
#include <source_location>

namespace test_inheritance {

void test() {
std::cout << std::source_location::current().function_name() << std::endl;

struct S {
int x;
};

struct T : S {};

const auto name = get<0>(rfl::fields<T>()).name();
if (name == "x") {
std::cout << "OK" << std::endl;
} else {
std::cout << "FAIL\n"
<< "Expected member name 'x', got '" << name << "'" << std::endl;
}
}

} // namespace test_inheritance
3 changes: 3 additions & 0 deletions tests/json/test_inheritance.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace test_inheritance{
void test();
}
52 changes: 52 additions & 0 deletions tests/json/test_inheritance2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include <cassert>
#include <iostream>
#include <rfl.hpp>

#include "rfl/internal/num_fields.hpp"

namespace test_inheritance2 {

struct EmptyBase1 {};
struct EmptyBase2 {};
struct Derived1 : public EmptyBase1 {
int x;
int y;
};
struct Derived2 : public EmptyBase1, public EmptyBase2 {
int x;
int y;
int z;
};

struct BaseX {
int x;
int y;
};
struct EmptyDerived0 : BaseX, EmptyBase1 {};
struct EmptyDerived1 : EmptyBase1, BaseX {};
struct EmptyDerived2 : EmptyBase1, EmptyBase2, BaseX {};

void test() {
Derived1 derived1;
const auto derived1_view = rfl::to_view(derived1);
static_assert(derived1_view.size() == 2);
Derived2 derived2;
const auto derived2_view = rfl::to_view(derived2);
static_assert(derived2_view.size() == 3);

EmptyDerived1 empty_derived0;
auto empty_derived0_view = rfl::to_view(empty_derived0);
static_assert(empty_derived0_view.size() == 2);

EmptyDerived1 empty_derived1;
auto empty_derived1_view = rfl::to_view(empty_derived1);
static_assert(empty_derived1_view.size() == 2);

EmptyDerived1 empty_derived2;
auto empty_derived2_view = rfl::to_view(empty_derived2);

Check warning on line 46 in tests/json/test_inheritance2.cpp

View workflow job for this annotation

GitHub Actions / linux-clang

unused variable 'empty_derived2_view' [-Wunused-variable]
static_assert(empty_derived0_view.size() == 2);

std::cout << "OK\n";
}

} // namespace test_inheritance
3 changes: 3 additions & 0 deletions tests/json/test_inheritance2.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace test_inheritance2 {
void test();
}
1 change: 1 addition & 0 deletions tests/json/test_view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <type_traits>
#include <vector>

#include "rfl/internal/num_fields.hpp"
#include "test_replace.hpp"
#include "write_and_read.hpp"

Expand Down
Loading

0 comments on commit bcf3483

Please sign in to comment.