Commit ba8f0cdb authored by Dominik Charousset's avatar Dominik Charousset

Support incremental build of the meta object table

parent e3e1404c
...@@ -30,7 +30,7 @@ namespace caf::detail { ...@@ -30,7 +30,7 @@ namespace caf::detail {
/// pointers. /// pointers.
struct meta_object { struct meta_object {
/// Stores a human-readable representation of the type's name. /// Stores a human-readable representation of the type's name.
const char* type_name; const char* type_name = nullptr;
/// Calls the destructor for given object. /// Calls the destructor for given object.
void (*destroy)(void*) noexcept; void (*destroy)(void*) noexcept;
...@@ -59,13 +59,23 @@ CAF_CORE_EXPORT span<const meta_object> global_meta_objects(); ...@@ -59,13 +59,23 @@ CAF_CORE_EXPORT span<const meta_object> global_meta_objects();
/// Returns the global meta object for given type ID. /// Returns the global meta object for given type ID.
CAF_CORE_EXPORT meta_object& global_meta_object(uint16_t id); CAF_CORE_EXPORT meta_object& global_meta_object(uint16_t id);
/// Clears the array for storing global meta objects. Meant for unit testing /// Clears the array for storing global meta objects.
/// only! /// @warning intended for unit testing only!
CAF_CORE_EXPORT void clear_global_meta_objects(); CAF_CORE_EXPORT void clear_global_meta_objects();
/// Resizes and returns the global storage for all meta objects. Existing /// Resizes and returns the global storage for all meta objects. Existing
/// entries are copied to the new memory region. The new size *must* grow the /// entries are copied to the new memory region. The new size *must* grow the
/// array. /// array.
/// @warning calling this after constructing any ::actor_system is unsafe and
/// causes undefined behavior.
CAF_CORE_EXPORT span<meta_object> resize_global_meta_objects(size_t size); CAF_CORE_EXPORT span<meta_object> resize_global_meta_objects(size_t size);
/// Sets the meta objects in range `(first_id, first_id + xs.size]` to `xs`.
/// Resizes the global meta object if needed. Aborts the program if the range
/// already contains meta objects.
/// @warning calling this after constructing any ::actor_system is unsafe and
/// causes undefined behavior.
CAF_CORE_EXPORT void set_global_meta_objects(uint16_t first_id,
span<const meta_object> xs);
} // namespace caf::detail } // namespace caf::detail
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "caf/detail/make_meta_object.hpp" #include "caf/detail/make_meta_object.hpp"
#include "caf/detail/meta_object.hpp" #include "caf/detail/meta_object.hpp"
#include "caf/span.hpp"
#include "caf/type_id.hpp" #include "caf/type_id.hpp"
namespace caf::detail { namespace caf::detail {
...@@ -54,22 +55,26 @@ using make_type_id_sequence = ...@@ -54,22 +55,26 @@ using make_type_id_sequence =
namespace caf { namespace caf {
/// @warning calling this after constructing any ::actor_system is unsafe and
/// causes undefined behavior.
template <uint16_t... Is> template <uint16_t... Is>
void init_global_meta_objects_impl(std::integer_sequence<uint16_t, Is...>, void init_global_meta_objects_impl(std::integer_sequence<uint16_t, Is...>,
size_t begin, size_t end) { uint16_t first_id) {
detail::meta_object src[] = { detail::meta_object src[] = {
detail::make_meta_object<type_by_id_t<Is>>(type_name_by_id_v<Is>)..., detail::make_meta_object<type_by_id_t<Is>>(type_name_by_id_v<Is>)...,
}; };
auto dst = detail::resize_global_meta_objects(end); detail::set_global_meta_objects(first_id, make_span(src));
std::copy(src, src + sizeof...(Is), dst.begin() + begin);
} }
/// Initializes the global meta object table with all types in `ProjectIds`.
/// @warning calling this after constructing any ::actor_system is unsafe and
/// causes undefined behavior.
template <class ProjectIds> template <class ProjectIds>
void init_global_meta_objects() { void init_global_meta_objects() {
static constexpr uint16_t begin = ProjectIds::first; static constexpr uint16_t begin = ProjectIds::first;
static constexpr uint16_t end = ProjectIds::last + 1; static constexpr uint16_t end = ProjectIds::last + 1;
init_global_meta_objects_impl(detail::make_type_id_sequence<begin, end>{}, init_global_meta_objects_impl(detail::make_type_id_sequence<begin, end>{},
begin, end); begin);
} }
} // namespace caf } // namespace caf
This diff is collapsed.
...@@ -27,6 +27,12 @@ ...@@ -27,6 +27,12 @@
namespace caf::detail { namespace caf::detail {
#define fatal(str) \
do { \
fprintf(stderr, "FATAL: " str "\n"); \
abort(); \
} while (false)
namespace { namespace {
// Stores global type information. // Stores global type information.
...@@ -62,11 +68,9 @@ void clear_global_meta_objects() { ...@@ -62,11 +68,9 @@ void clear_global_meta_objects() {
} }
span<meta_object> resize_global_meta_objects(size_t size) { span<meta_object> resize_global_meta_objects(size_t size) {
if (size <= meta_objects_size) { if (size <= meta_objects_size)
fprintf(stderr, "resize_global_meta_objects called with a new size that " fatal("resize_global_meta_objects called with a new size that does not "
"does not grow the array\n"); "grow the array");
abort();
}
auto new_storage = new meta_object[size]; auto new_storage = new meta_object[size];
std::copy(meta_objects, meta_objects + meta_objects_size, new_storage); std::copy(meta_objects, meta_objects + meta_objects_size, new_storage);
delete[] meta_objects; delete[] meta_objects;
...@@ -75,4 +79,35 @@ span<meta_object> resize_global_meta_objects(size_t size) { ...@@ -75,4 +79,35 @@ span<meta_object> resize_global_meta_objects(size_t size) {
return {new_storage, size}; return {new_storage, size};
} }
void set_global_meta_objects(uint16_t first_id, span<const meta_object> xs) {
auto new_size = first_id + xs.size();
if (first_id < meta_objects_size) {
if (new_size > meta_objects_size)
fatal("set_global_meta_objects called with "
"'first_id < meta_objects_size' and "
"'new_size > meta_objects_size'");
auto out = meta_objects + first_id;
for (const auto& x : xs) {
if (out->type_name == nullptr) {
// We support calling set_global_meta_objects for building the global
// table chunk-by-chunk.
*out = x;
} else if (strcmp(out->type_name, x.type_name) == 0) {
// nop: set_global_meta_objects implements idempotency.
} else {
fprintf(stderr,
"FATAL: type ID %d already assigned to %s (tried to override "
"with %s)\n",
static_cast<int>(std::distance(meta_objects, out)),
out->type_name, x.type_name);
abort();
}
++out;
}
return;
}
auto dst = resize_global_meta_objects(first_id + xs.size());
std::copy(xs.begin(), xs.end(), dst.begin() + first_id);
}
} // namespace caf::detail } // namespace caf::detail
...@@ -172,6 +172,19 @@ CAF_TEST(init_global_meta_objects takes care of creating a meta object table) { ...@@ -172,6 +172,19 @@ CAF_TEST(init_global_meta_objects takes care of creating a meta object table) {
CAF_CHECK_EQUAL(type_name_by_id_v<type_id_v<i64_wrapper>>, "i64_wrapper"s); CAF_CHECK_EQUAL(type_name_by_id_v<type_id_v<i64_wrapper>>, "i64_wrapper"s);
CAF_CHECK_EQUAL(xs[type_id_v<i32_wrapper>].type_name, "i32_wrapper"s); CAF_CHECK_EQUAL(xs[type_id_v<i32_wrapper>].type_name, "i32_wrapper"s);
CAF_CHECK_EQUAL(xs[type_id_v<i64_wrapper>].type_name, "i64_wrapper"s); CAF_CHECK_EQUAL(xs[type_id_v<i64_wrapper>].type_name, "i64_wrapper"s);
CAF_MESSAGE("calling init_global_meta_objects again is a no-op");
init_global_meta_objects<meta_object_suite_type_ids>();
auto ys = global_meta_objects();
auto same = [](const auto& x, const auto& y) {
return x.type_name == y.type_name;
};
CAF_CHECK(std::equal(xs.begin(), xs.end(), ys.begin(), ys.end(), same));
CAF_MESSAGE("init_global_meta_objects can initialize allocated chunks");
CAF_CHECK_EQUAL(global_meta_object(type_id_v<float>).type_name, nullptr);
init_global_meta_objects<builtin_type_ids>();
CAF_MESSAGE("again, calling init_global_meta_objects again is a no-op");
init_global_meta_objects<builtin_type_ids>();
CAF_CHECK_EQUAL(global_meta_object(type_id_v<float>).type_name, "float"s);
} }
CAF_TEST_FIXTURE_SCOPE_END() CAF_TEST_FIXTURE_SCOPE_END()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment