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 {
/// pointers.
struct meta_object {
/// 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.
void (*destroy)(void*) noexcept;
......@@ -59,13 +59,23 @@ CAF_CORE_EXPORT span<const meta_object> global_meta_objects();
/// Returns the global meta object for given type ID.
CAF_CORE_EXPORT meta_object& global_meta_object(uint16_t id);
/// Clears the array for storing global meta objects. Meant for unit testing
/// only!
/// Clears the array for storing global meta objects.
/// @warning intended for unit testing only!
CAF_CORE_EXPORT void clear_global_meta_objects();
/// 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
/// 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);
/// 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
......@@ -25,6 +25,7 @@
#include "caf/detail/make_meta_object.hpp"
#include "caf/detail/meta_object.hpp"
#include "caf/span.hpp"
#include "caf/type_id.hpp"
namespace caf::detail {
......@@ -54,22 +55,26 @@ using make_type_id_sequence =
namespace caf {
/// @warning calling this after constructing any ::actor_system is unsafe and
/// causes undefined behavior.
template <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::make_meta_object<type_by_id_t<Is>>(type_name_by_id_v<Is>)...,
};
auto dst = detail::resize_global_meta_objects(end);
std::copy(src, src + sizeof...(Is), dst.begin() + begin);
detail::set_global_meta_objects(first_id, make_span(src));
}
/// 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>
void init_global_meta_objects() {
static constexpr uint16_t begin = ProjectIds::first;
static constexpr uint16_t end = ProjectIds::last + 1;
init_global_meta_objects_impl(detail::make_type_id_sequence<begin, end>{},
begin, end);
begin);
}
} // namespace caf
This diff is collapsed.
......@@ -27,6 +27,12 @@
namespace caf::detail {
#define fatal(str) \
do { \
fprintf(stderr, "FATAL: " str "\n"); \
abort(); \
} while (false)
namespace {
// Stores global type information.
......@@ -62,11 +68,9 @@ void clear_global_meta_objects() {
}
span<meta_object> resize_global_meta_objects(size_t size) {
if (size <= meta_objects_size) {
fprintf(stderr, "resize_global_meta_objects called with a new size that "
"does not grow the array\n");
abort();
}
if (size <= meta_objects_size)
fatal("resize_global_meta_objects called with a new size that does not "
"grow the array");
auto new_storage = new meta_object[size];
std::copy(meta_objects, meta_objects + meta_objects_size, new_storage);
delete[] meta_objects;
......@@ -75,4 +79,35 @@ span<meta_object> resize_global_meta_objects(size_t 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
......@@ -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(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_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()
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