Skip to content

Commit

Permalink
XXX Recursive table loading doesn't work
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-sparus committed Apr 22, 2024
1 parent 6556690 commit a1d0f9f
Show file tree
Hide file tree
Showing 5 changed files with 271 additions and 26 deletions.
26 changes: 21 additions & 5 deletions immer/extra/archive/champ/champ.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ struct node_traits
class hash_validation_failed_exception : public archive_exception
{
public:
hash_validation_failed_exception()
explicit hash_validation_failed_exception(const std::string& msg)
: archive_exception{"Hash validation failed, likely different hash "
"algos are used for saving and loading"}
"algos are used for saving and loading, " +
msg}
{
}
};
Expand All @@ -59,7 +60,7 @@ class container_loader
{
const value_t* operator()(const value_t& v) const noexcept
{
return &v;
return std::addressof(v);
}
};

Expand Down Expand Up @@ -103,10 +104,25 @@ class container_loader
project_value_ptr,
immer::detail::constantly<const value_t*, nullptr>>(item);
if (!p) {
throw hash_validation_failed_exception{};
if constexpr (std::is_default_constructible_v<
fmt::formatter<
std::decay_t<decltype(item)>>>) {
SPDLOG_INFO(
"items_count = {}, item = {}", items_count, item);
auto c = Container{impl};
for (const auto& x : c) {
SPDLOG_INFO("x = {}, same == {}", x, x == item);
}
}

throw hash_validation_failed_exception{
"Couldn't find an element", item};
}
if (!(*p == item)) {
throw hash_validation_failed_exception{};
throw hash_validation_failed_exception{
"Found element is not equal to the one we were looking "
"for",
item};
}
}
}
Expand Down
11 changes: 7 additions & 4 deletions immer/extra/archive/json/archivable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#include <fmt/format.h>

#include <boost/core/demangle.hpp>

namespace immer::archive {

namespace detail {
Expand Down Expand Up @@ -135,10 +137,11 @@ void load_minimal(
try {
value.container = loader.load(container_id_{id});
} catch (const archive_exception& ex) {
throw ::cereal::Exception{
fmt::format("Failed to load a container ID {} from the archive: {}",
id,
ex.what())};
throw ::cereal::Exception{fmt::format(
"Failed to load a container ID {} from the archive of {}: {}",
id,
boost::core::demangle(typeid(Container).name()),
ex.what())};
}
}

Expand Down
14 changes: 7 additions & 7 deletions test/extra/archive/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ include(CTest)

add_executable(
archive-tests EXCLUDE_FROM_ALL
test_vectors.cpp
test_special_archive.cpp
# test_vectors.cpp
# test_special_archive.cpp
test_special_archive_auto.cpp
test_champ.cpp
test_xxhash.cpp
test_box.cpp
test_conversion.cpp
test_circular_dependency_conversion.cpp
# test_champ.cpp
# test_xxhash.cpp
# test_box.cpp
# test_conversion.cpp
# test_circular_dependency_conversion.cpp
${PROJECT_SOURCE_DIR}/immer/extra/archive/xxhash/xxhash_64.cpp)
add_dependencies(tests archive-tests)
add_test("test/archive-tests" archive-tests)
Expand Down
58 changes: 48 additions & 10 deletions test/extra/archive/test_circular_dependency_conversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,21 @@ struct value_two
int number = {};
vector_one<value_one> ones = {};
key key = {};

friend std::ostream& operator<<(std::ostream& s, const value_two& value)
{
return s << fmt::format("number = {}, ones = {}, key = '{}'",
value.number,
value.ones.size(),
value.key.str);
}
};

std::ostream& operator<<(std::ostream& s, const two_boxed& value)
{
return s << value.two.get();
}

const key& get_table_key(const two_boxed& two) { return two.two.get().key; }

std::size_t xx_hash_value(const two_boxed& value)
Expand All @@ -98,6 +111,14 @@ two_boxed::two_boxed(value_two val)

} // namespace model

template <>
struct fmt::formatter<model::two_boxed> : ostream_formatter
{};

template <>
struct fmt::formatter<model::key> : ostream_formatter
{};

BOOST_HANA_ADAPT_STRUCT(model::value_two, number, ones, key);

namespace model {
Expand Down Expand Up @@ -224,6 +245,14 @@ TEST_CASE("Test exception while circular converting")
immer::archive::to_json_with_auto_archive(value, names);
// REQUIRE(json_str == "");

SECTION("Try to load")
{
const auto loaded =
immer::archive::from_json_with_auto_archive<model::value_one>(
json_str, names);
REQUIRE(loaded == value);
}

/**
* NOTE: There is a circular dependency between archives: to convert
* value_one we need to convert value_two and vice versa.
Expand Down Expand Up @@ -554,16 +583,6 @@ TEST_CASE("Test circular dependency archives", "[conversion]")
REQUIRE(format_twos.impl().root == format_twos_2.impl().root);
}
REQUIRE(test::to_json(value.twos_table) == test::to_json(format_twos));

// SECTION("Compare structure")
// {
// const auto [format_twos_json, ar] =
// immer::archive::to_json_with_auto_archive(format_twos,
// format_names);
// const auto [model_twos_json, ar2] =
// immer::archive::to_json_with_auto_archive(value, names);
// REQUIRE(model_twos_json == format_twos_json);
// }
}

SECTION("map")
Expand Down Expand Up @@ -635,4 +654,23 @@ TEST_CASE("Test circular dependency archives", "[conversion]")
REQUIRE(model_twos_json == format_twos_json);
}
}

SECTION("everything")
{
const auto convert = [&](const auto& value) {
return immer::archive::convert_container(
model_archives, format_load_archives, value);
};
const auto format_value = [&] {
auto result = format::value_one{};
hana::for_each(hana::keys(result), [&](auto key) {
hana::at_key(result, key) = convert(hana::at_key(value, key));
});
return result;
}();
const auto [format_json_str, model_archives] =
immer::archive::to_json_with_auto_archive(format_value,
format_names);
REQUIRE(format_json_str == json_str);
}
}
188 changes: 188 additions & 0 deletions test/extra/archive/test_special_archive_auto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,21 @@

#include <immer/extra/archive/json/json_with_archive_auto.hpp>

#define DEFINE_OPERATIONS(name) \
bool operator==(const name& left, const name& right) \
{ \
return members(left) == members(right); \
} \
template <class Archive> \
void serialize(Archive& ar, name& m) \
{ \
serialize_members(ar, m); \
}

namespace {

namespace hana = boost::hana;
using test::flex_vector_one;
using test::members;
using test::serialize_members;
using test::test_value;
Expand Down Expand Up @@ -357,3 +369,179 @@ TEST_CASE("Test conversion with auto-archive")
REQUIRE(full_load.table == transform_table(value.table));
}
}

namespace champ_test {

struct value_two;

struct two_boxed
{
BOOST_HANA_DEFINE_STRUCT(two_boxed, (immer::box<value_two>, two));

two_boxed() = default;
explicit two_boxed(value_two val);
};

struct key
{
BOOST_HANA_DEFINE_STRUCT(key, (std::string, str));

friend std::size_t xx_hash_value(const key& value)
{
return immer::archive::xx_hash_value_string(value.str);
}
};

const key& get_table_key(const two_boxed& two);

struct table_key_fn
{
const key& operator()(const two_boxed& two) const;

template <typename T, typename K>
auto operator()(T&& x, K&& k) const
{
return set_table_key(std::forward<T>(x), std::forward<K>(k));
}
};

struct value_one
{
BOOST_HANA_DEFINE_STRUCT(
value_one, //
(vector_one<two_boxed>, twos),
(immer::table<two_boxed, table_key_fn, immer::archive::xx_hash<key>>,
twos_table));
};

struct value_two
{
vector_one<value_one> ones = {};
key key = {};

friend std::ostream& operator<<(std::ostream& s, const value_two& value)
{
return s << fmt::format(
"ones = {}, key = '{}'", value.ones.size(), value.key.str);
}
};

const key& table_key_fn::operator()(const two_boxed& two) const
{
return two.two.get().key;
}

} // namespace champ_test

template <>
struct fmt::formatter<champ_test::value_two> : ostream_formatter
{};

namespace champ_test {

std::ostream& operator<<(std::ostream& s, const two_boxed& value)
{
return s << fmt::format("two_boxed[{}]", value.two.get());
}

const key& get_table_key(const two_boxed& two) { return two.two.get().key; }

std::size_t xx_hash_value(const two_boxed& value)
{
return xx_hash_value(value.two.get().key);
}

two_boxed::two_boxed(value_two val)
: two{val}
{
}

} // namespace champ_test

template <>
struct fmt::formatter<champ_test::two_boxed> : ostream_formatter
{};

BOOST_HANA_ADAPT_STRUCT(champ_test::value_two, ones, key);

namespace champ_test {
DEFINE_OPERATIONS(two_boxed);
DEFINE_OPERATIONS(key);
DEFINE_OPERATIONS(value_one);
DEFINE_OPERATIONS(value_two);
} // namespace champ_test

namespace {
struct project_value_ptr
{
template <class T>
const T* operator()(const T& v) const noexcept
{
return std::addressof(v);
}
};
} // namespace

TEST_CASE("Test table with a single funny value")
{
const auto item = champ_test::two_boxed{};
const auto t = immer::table<champ_test::two_boxed,
champ_test::table_key_fn,
immer::archive::xx_hash<champ_test::key>>{item};
SECTION("via table")
{
const auto* p = t.find(champ_test::key{});
REQUIRE(p != nullptr);
REQUIRE(*p == item);
}

SECTION("via impl")
{
const auto& impl = t.impl();
const auto* p = impl.template get<
project_value_ptr,
immer::detail::constantly<const champ_test::two_boxed*, nullptr>>(
item);
REQUIRE(p != nullptr);
REQUIRE(*p == item);
}
}

TEST_CASE("Test table with a funny value")
{
const auto two1 = champ_test::two_boxed{champ_test::value_two{
.key = champ_test::key{"456"},
}};
const auto t1 =
immer::table<champ_test::two_boxed,
champ_test::table_key_fn,
immer::archive::xx_hash<champ_test::key>>{two1};
const auto two2 = champ_test::two_boxed{champ_test::value_two{
.ones =
{
champ_test::value_one{
.twos_table = t1,
},
},
.key = champ_test::key{"123"},
}};

const auto value = champ_test::value_one{
.twos_table = t1.insert(two2),
};

const auto names = immer::archive::get_archives_for_types(
hana::tuple_t<champ_test::value_one,
champ_test::value_two,
champ_test::two_boxed>,
hana::make_map());

const auto [json_str, ar] =
immer::archive::to_json_with_auto_archive(value, names);
// REQUIRE(json_str == "");

const auto loaded =
immer::archive::from_json_with_auto_archive<champ_test::value_one>(
json_str, names);
REQUIRE(loaded == value);
}

0 comments on commit a1d0f9f

Please sign in to comment.