Unverified Commit 3d7851f8 authored by Dominik Charousset's avatar Dominik Charousset Committed by GitHub

Merge pull request #1029

Add scaffold for new type_id API
parents 13fc58a2 3640a0d9
......@@ -32,8 +32,8 @@ IndentWidth: 2
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
Language: Cpp
MacroBlockBegin: "^BEGIN_STATE$"
MacroBlockEnd: "^END_STATE$"
MacroBlockBegin: "^BEGIN_STATE$|CAF_BEGIN_TYPE_ID_BLOCK"
MacroBlockEnd: "^END_STATE$|CAF_END_TYPE_ID_BLOCK"
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
PenaltyBreakAssignment: 25
......
......@@ -69,6 +69,7 @@ set(CAF_CORE_SOURCES
src/detail/ini_consumer.cpp
src/detail/invoke_result_visitor.cpp
src/detail/message_data.cpp
src/detail/meta_object.cpp
src/detail/parse.cpp
src/detail/parser/chars.cpp
src/detail/pretty_type_name.cpp
......@@ -154,6 +155,7 @@ set(CAF_CORE_SOURCES
src/tracing_data_factory.cpp
src/type_erased_tuple.cpp
src/type_erased_value.cpp
src/type_id_list.cpp
src/uniform_type_info_map.cpp
src/uri.cpp
src/uri_builder.cpp
......@@ -193,6 +195,7 @@ set(CAF_CORE_TEST_SOURCES
test/detail/bounds_checker.cpp
test/detail/ini_consumer.cpp
test/detail/limited_vector.cpp
test/detail/meta_object.cpp
test/detail/parse.cpp
test/detail/parser/read_bool.cpp
test/detail/parser/read_floating_point.cpp
......@@ -268,6 +271,7 @@ set(CAF_CORE_TEST_SOURCES
test/to_string.cpp
test/tracing_data.cpp
test/type_erased_tuple.cpp
test/type_id_list.cpp
test/typed_response_promise.cpp
test/typed_spawn.cpp
test/unit.cpp
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <algorithm>
#include <cstddef>
#include "caf/binary_deserializer.hpp"
#include "caf/binary_serializer.hpp"
#include "caf/byte.hpp"
#include "caf/deserializer.hpp"
#include "caf/detail/meta_object.hpp"
#include "caf/error.hpp"
#include "caf/serializer.hpp"
namespace caf::detail {
template <class T>
meta_object make_meta_object(const char* type_name) {
return {
type_name,
[](void* ptr) noexcept { reinterpret_cast<T*>(ptr)->~T(); },
[](void* ptr) { new (ptr) T(); },
[](caf::binary_serializer& sink, const void* ptr) {
return sink(*reinterpret_cast<const T*>(ptr));
},
[](caf::binary_deserializer& source, void* ptr) {
return source(*reinterpret_cast<T*>(ptr));
},
[](caf::serializer& sink, const void* ptr) {
return sink(*reinterpret_cast<const T*>(ptr));
},
[](caf::deserializer& source, void* ptr) {
return source(*reinterpret_cast<T*>(ptr));
},
};
}
template <class... Ts>
void register_meta_objects(size_t first_id) {
auto xs = resize_global_meta_objects(first_id + sizeof...(Ts));
meta_object src[] = {make_meta_object<Ts>()...};
std::copy(src, src + sizeof...(Ts), xs.begin() + first_id);
}
} // namespace caf::detail
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cstddef>
#include <cstdint>
#include "caf/detail/core_export.hpp"
#include "caf/fwd.hpp"
namespace caf::detail {
/// Enables destroying, construcing and serializing objects through type-erased
/// pointers.
struct meta_object {
/// Stores a human-readable representation of the type's name.
const char* type_name = nullptr;
/// Calls the destructor for given object.
void (*destroy)(void*) noexcept;
/// Creates a new object at given memory location by calling the default
/// constructor.
void (*default_construct)(void*);
/// Applies an object to a binary serializer.
error_code<sec> (*save_binary)(caf::binary_serializer&, const void*);
/// Applies an object to a binary deserializer.
error_code<sec> (*load_binary)(caf::binary_deserializer&, void*);
/// Applies an object to a generic serializer.
caf::error (*save)(caf::serializer&, const void*);
/// Applies an object to a generic deserializer.
caf::error (*load)(caf::deserializer&, void*);
};
/// Returns the global storage for all meta objects. The ::type_id of an object
/// is the index for accessing the corresonding meta object.
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(type_id_t id);
/// 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(type_id_t first_id,
span<const meta_object> xs);
} // namespace caf::detail
......@@ -40,13 +40,17 @@ template <class> class intrusive_ptr;
template <class> class optional;
template <class> class param;
template <class> class span;
template <class> class stream;
template <class> class stream;;
template <class> class stream_sink;
template <class> class stream_source;
template <class> class trivial_match_case;
template <class> class weak_intrusive_ptr;
template <class> struct timeout_definition;
template <class> struct type_id;
template <uint16_t> struct type_by_id;
template <uint16_t> struct type_name_by_id;
// -- 2 param templates --------------------------------------------------------
......@@ -187,6 +191,7 @@ using ip_endpoint = ipv6_endpoint;
using ip_subnet = ipv6_subnet;
using settings = dictionary<config_value>;
using stream_slot = uint16_t;
using type_id_t = uint16_t;
// -- functions ----------------------------------------------------------------
......@@ -272,6 +277,8 @@ class message_data;
class private_thread;
class uri_impl;
struct meta_object;
// enable intrusive_ptr<uri_impl> with forward declaration only
CAF_CORE_EXPORT void intrusive_ptr_add_ref(const uri_impl*);
CAF_CORE_EXPORT void intrusive_ptr_release(const uri_impl*);
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <utility>
#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 {
template <uint16_t First, uint16_t Second>
struct type_id_pair {};
template <class Range, uint16_t... Is>
struct type_id_sequence_helper;
template <uint16_t End, uint16_t... Is>
struct type_id_sequence_helper<type_id_pair<End, End>, Is...> {
using type = std::integer_sequence<uint16_t, Is...>;
};
template <uint16_t Begin, uint16_t End, uint16_t... Is>
struct type_id_sequence_helper<type_id_pair<Begin, End>, Is...> {
using type = typename type_id_sequence_helper<type_id_pair<Begin + 1, End>,
Is..., Begin>::type;
};
template <uint16_t Begin, uint16_t End>
using make_type_id_sequence =
typename type_id_sequence_helper<type_id_pair<Begin, End>>::type;
} // namespace caf::detail
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...>,
uint16_t first_id) {
detail::meta_object src[] = {
detail::make_meta_object<type_by_id_t<Is>>(type_name_by_id_v<Is>)...,
};
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);
}
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cstdint>
#include <utility>
#include "caf/fwd.hpp"
#include "caf/meta/type_name.hpp"
#include "caf/type_nr.hpp"
namespace caf {
/// Internal representation of a type ID.
using type_id_t = uint16_t;
/// Maps the type `T` to a globally unique ID.
template <class T>
struct type_id;
/// Convenience alias for `type_id<T>::value`.
/// @relates type_id
template <class T>
constexpr type_id_t type_id_v = type_id<T>::value;
/// Maps the globally unique ID `V` to a type (inverse to ::type_id).
/// @relates type_id
template <type_id_t V>
struct type_by_id;
/// Convenience alias for `type_by_id<I>::type`.
/// @relates type_by_id
template <type_id_t I>
using type_by_id_t = typename type_by_id<I>::type;
/// Maps the globally unique ID `V` to a type name.
template <type_id_t V>
struct type_name_by_id;
/// Convenience alias for `type_name_by_id<I>::value`.
/// @relates type_name_by_id
template <type_id_t I>
constexpr const char* type_name_by_id_v = type_name_by_id<I>::value;
/// The first type ID not reserved by CAF and its modules.
constexpr type_id_t first_custom_type_id = 200;
} // namespace caf
/// Starts a code block for registering custom types to CAF. Stores the first ID
/// for the project as `caf::${project_name}_first_type_id`. Usually, users
/// should use `caf::first_custom_type_id` as `first_id`. However, this
/// mechanism also enables modules to append IDs to a block of another module or
/// module. If two modules are developed separately to avoid dependencies, they
/// only need to define sufficiently large offsets to guarantee collision-free
/// IDs (CAF supports gaps in the ID space).
#define CAF_BEGIN_TYPE_ID_BLOCK(project_name, first_id) \
namespace caf { \
constexpr type_id_t project_name##_type_id_counter_init = __COUNTER__; \
constexpr type_id_t project_name##_first_type_id = first_id; \
}
/// Assigns the next free type ID to `fully_qualified_name`.
#define CAF_ADD_TYPE_ID(project_name, fully_qualified_name) \
namespace caf { \
template <> \
struct type_id<fully_qualified_name> { \
static constexpr type_id_t value \
= project_name##_first_type_id \
+ (__COUNTER__ - project_name##_type_id_counter_init - 1); \
}; \
template <> \
struct type_by_id<type_id<fully_qualified_name>::value> { \
using type = fully_qualified_name; \
}; \
template <> \
struct type_name_by_id<type_id<fully_qualified_name>::value> { \
static constexpr const char* value = #fully_qualified_name; \
}; \
}
/// Creates a new tag type (atom) and assigns the next free type ID to it.
#define CAF_ADD_ATOM(project_name, atom_namespace, atom_name) \
namespace atom_namespace { \
struct atom_name {}; \
static constexpr atom_name atom_name##_v = atom_name{}; \
template <class Inspector> \
auto inspect(Inspector& f, atom_name&) { \
return f(caf::meta::type_name(#atom_namespace "::" #atom_name)); \
} \
} \
CAF_ADD_TYPE_ID(project_name, atom_namespace##atom_name)
/// Finalizes a code block for registering custom types to CAF. Stores the last
/// type ID used by the project as `caf::${project_name}_last_type_id`.
#define CAF_END_TYPE_ID_BLOCK(project_name) \
namespace caf { \
constexpr type_id_t project_name##_last_type_id \
= project_name##_first_type_id \
+ (__COUNTER__ - project_name##_type_id_counter_init - 2); \
struct project_name##_type_ids { \
static constexpr type_id_t first = project_name##_first_type_id; \
static constexpr type_id_t last = project_name##_last_type_id; \
}; \
}
CAF_BEGIN_TYPE_ID_BLOCK(builtin, 0)
// -- C types
CAF_ADD_TYPE_ID(builtin, bool)
CAF_ADD_TYPE_ID(builtin, double)
CAF_ADD_TYPE_ID(builtin, float)
CAF_ADD_TYPE_ID(builtin, int16_t)
CAF_ADD_TYPE_ID(builtin, int32_t)
CAF_ADD_TYPE_ID(builtin, int64_t)
CAF_ADD_TYPE_ID(builtin, int8_t)
CAF_ADD_TYPE_ID(builtin, long double)
CAF_ADD_TYPE_ID(builtin, uint16_t)
CAF_ADD_TYPE_ID(builtin, uint32_t)
CAF_ADD_TYPE_ID(builtin, uint64_t)
CAF_ADD_TYPE_ID(builtin, uint8_t)
// -- STL types
CAF_ADD_TYPE_ID(builtin, std::string)
CAF_ADD_TYPE_ID(builtin, std::u16string)
CAF_ADD_TYPE_ID(builtin, std::u32string)
CAF_ADD_TYPE_ID(builtin, std::set<std::string>)
// -- CAF types
CAF_ADD_TYPE_ID(builtin, caf::actor)
CAF_ADD_TYPE_ID(builtin, caf::actor_addr)
CAF_ADD_TYPE_ID(builtin, caf::byte_buffer)
CAF_ADD_TYPE_ID(builtin, caf::config_value)
CAF_ADD_TYPE_ID(builtin, caf::down_msg)
CAF_ADD_TYPE_ID(builtin, caf::downstream_msg)
CAF_ADD_TYPE_ID(builtin, caf::error)
CAF_ADD_TYPE_ID(builtin, caf::exit_msg)
CAF_ADD_TYPE_ID(builtin, caf::group)
CAF_ADD_TYPE_ID(builtin, caf::group_down_msg)
CAF_ADD_TYPE_ID(builtin, caf::message)
CAF_ADD_TYPE_ID(builtin, caf::message_id)
CAF_ADD_TYPE_ID(builtin, caf::node_id)
CAF_ADD_TYPE_ID(builtin, caf::open_stream_msg)
CAF_ADD_TYPE_ID(builtin, caf::strong_actor_ptr)
CAF_ADD_TYPE_ID(builtin, caf::timeout_msg)
CAF_ADD_TYPE_ID(builtin, caf::timespan)
CAF_ADD_TYPE_ID(builtin, caf::timestamp)
CAF_ADD_TYPE_ID(builtin, caf::unit_t)
CAF_ADD_TYPE_ID(builtin, caf::upstream_msg)
CAF_ADD_TYPE_ID(builtin, caf::weak_actor_ptr)
CAF_ADD_TYPE_ID(builtin, std::vector<caf::actor>)
CAF_ADD_TYPE_ID(builtin, std::vector<caf::actor_addr>)
// -- predefined atoms
CAF_ADD_TYPE_ID(builtin, caf::add_atom)
CAF_ADD_TYPE_ID(builtin, caf::close_atom)
CAF_ADD_TYPE_ID(builtin, caf::connect_atom)
CAF_ADD_TYPE_ID(builtin, caf::contact_atom)
CAF_ADD_TYPE_ID(builtin, caf::delete_atom)
CAF_ADD_TYPE_ID(builtin, caf::demonitor_atom)
CAF_ADD_TYPE_ID(builtin, caf::div_atom)
CAF_ADD_TYPE_ID(builtin, caf::flush_atom)
CAF_ADD_TYPE_ID(builtin, caf::forward_atom)
CAF_ADD_TYPE_ID(builtin, caf::get_atom)
CAF_ADD_TYPE_ID(builtin, caf::idle_atom)
CAF_ADD_TYPE_ID(builtin, caf::join_atom)
CAF_ADD_TYPE_ID(builtin, caf::leave_atom)
CAF_ADD_TYPE_ID(builtin, caf::link_atom)
CAF_ADD_TYPE_ID(builtin, caf::migrate_atom)
CAF_ADD_TYPE_ID(builtin, caf::monitor_atom)
CAF_ADD_TYPE_ID(builtin, caf::mul_atom)
CAF_ADD_TYPE_ID(builtin, caf::ok_atom)
CAF_ADD_TYPE_ID(builtin, caf::open_atom)
CAF_ADD_TYPE_ID(builtin, caf::pending_atom)
CAF_ADD_TYPE_ID(builtin, caf::ping_atom)
CAF_ADD_TYPE_ID(builtin, caf::pong_atom)
CAF_ADD_TYPE_ID(builtin, caf::publish_atom)
CAF_ADD_TYPE_ID(builtin, caf::publish_udp_atom)
CAF_ADD_TYPE_ID(builtin, caf::put_atom)
CAF_ADD_TYPE_ID(builtin, caf::receive_atom)
CAF_ADD_TYPE_ID(builtin, caf::redirect_atom)
CAF_ADD_TYPE_ID(builtin, caf::reset_atom)
CAF_ADD_TYPE_ID(builtin, caf::resolve_atom)
CAF_ADD_TYPE_ID(builtin, caf::spawn_atom)
CAF_ADD_TYPE_ID(builtin, caf::stream_atom)
CAF_ADD_TYPE_ID(builtin, caf::sub_atom)
CAF_ADD_TYPE_ID(builtin, caf::subscribe_atom)
CAF_ADD_TYPE_ID(builtin, caf::sys_atom)
CAF_ADD_TYPE_ID(builtin, caf::tick_atom)
CAF_ADD_TYPE_ID(builtin, caf::timeout_atom)
CAF_ADD_TYPE_ID(builtin, caf::unlink_atom)
CAF_ADD_TYPE_ID(builtin, caf::unpublish_atom)
CAF_ADD_TYPE_ID(builtin, caf::unpublish_udp_atom)
CAF_ADD_TYPE_ID(builtin, caf::unsubscribe_atom)
CAF_ADD_TYPE_ID(builtin, caf::update_atom)
CAF_ADD_TYPE_ID(builtin, caf::wait_for_atom)
// TODO: remove atoms from type_nr.hpp and uncomment this block
// CAF_ADD_ATOM(builtin, caf, add_atom)
// CAF_ADD_ATOM(builtin, caf, close_atom)
// CAF_ADD_ATOM(builtin, caf, connect_atom)
// CAF_ADD_ATOM(builtin, caf, contact_atom)
// CAF_ADD_ATOM(builtin, caf, delete_atom)
// CAF_ADD_ATOM(builtin, caf, demonitor_atom)
// CAF_ADD_ATOM(builtin, caf, div_atom)
// CAF_ADD_ATOM(builtin, caf, flush_atom)
// CAF_ADD_ATOM(builtin, caf, forward_atom)
// CAF_ADD_ATOM(builtin, caf, get_atom)
// CAF_ADD_ATOM(builtin, caf, idle_atom)
// CAF_ADD_ATOM(builtin, caf, join_atom)
// CAF_ADD_ATOM(builtin, caf, leave_atom)
// CAF_ADD_ATOM(builtin, caf, link_atom)
// CAF_ADD_ATOM(builtin, caf, migrate_atom)
// CAF_ADD_ATOM(builtin, caf, monitor_atom)
// CAF_ADD_ATOM(builtin, caf, mul_atom)
// CAF_ADD_ATOM(builtin, caf, ok_atom)
// CAF_ADD_ATOM(builtin, caf, open_atom)
// CAF_ADD_ATOM(builtin, caf, pending_atom)
// CAF_ADD_ATOM(builtin, caf, ping_atom)
// CAF_ADD_ATOM(builtin, caf, pong_atom)
// CAF_ADD_ATOM(builtin, caf, publish_atom)
// CAF_ADD_ATOM(builtin, caf, publish_udp_atom)
// CAF_ADD_ATOM(builtin, caf, put_atom)
// CAF_ADD_ATOM(builtin, caf, receive_atom)
// CAF_ADD_ATOM(builtin, caf, redirect_atom)
// CAF_ADD_ATOM(builtin, caf, reset_atom)
// CAF_ADD_ATOM(builtin, caf, resolve_atom)
// CAF_ADD_ATOM(builtin, caf, spawn_atom)
// CAF_ADD_ATOM(builtin, caf, stream_atom)
// CAF_ADD_ATOM(builtin, caf, sub_atom)
// CAF_ADD_ATOM(builtin, caf, subscribe_atom)
// CAF_ADD_ATOM(builtin, caf, sys_atom)
// CAF_ADD_ATOM(builtin, caf, tick_atom)
// CAF_ADD_ATOM(builtin, caf, timeout_atom)
// CAF_ADD_ATOM(builtin, caf, unlink_atom)
// CAF_ADD_ATOM(builtin, caf, unpublish_atom)
// CAF_ADD_ATOM(builtin, caf, unpublish_udp_atom)
// CAF_ADD_ATOM(builtin, caf, unsubscribe_atom)
// CAF_ADD_ATOM(builtin, caf, update_atom)
// CAF_ADD_ATOM(builtin, caf, wait_for_atom)
CAF_END_TYPE_ID_BLOCK(builtin)
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <string>
#include "caf/detail/comparable.hpp"
#include "caf/detail/core_export.hpp"
#include "caf/type_id.hpp"
namespace caf {
/// A list of type IDs, stored in a size-prefix, contiguous memory block.
class type_id_list : detail::comparable<type_id_list> {
public:
using pointer = const type_id_t*;
constexpr explicit type_id_list(pointer data) noexcept : data_(data) {
// nop
}
constexpr type_id_list(const type_id_list&) noexcept = default;
type_id_list& operator=(const type_id_list&) noexcept = default;
/// Queries whether this type list contains data, i.e, `data() != nullptr`.
constexpr operator bool() const noexcept {
return data_ != nullptr;
}
/// Returns the raw pointer to the size-prefixed list.
constexpr pointer data() const noexcept {
return data_;
}
/// Returns the number of elements in the list.
/// @pre `data() != nullptr`
constexpr size_t size() const noexcept {
return data_[0];
}
/// Returns the type ID at `index`.
/// @pre `data() != nullptr`
constexpr type_id_t operator[](size_t index) const noexcept {
return data_[index + 1];
}
/// Compares this list to `other`.
int compare(type_id_list other) const noexcept {
return memcmp(data_, other.data_, size() * sizeof(type_id_t));
}
private:
pointer data_;
};
/// @private
template <class... Ts>
struct make_type_id_list_helper {
static constexpr inline type_id_t data[]
= {static_cast<type_id_t>(sizeof...(Ts)), type_id_v<Ts>...};
};
/// Constructs a ::type_id_list from the template parameter pack `Ts`.
/// @relates type_id_list
template <class... Ts>
constexpr type_id_list make_type_id_list() {
return type_id_list{make_type_id_list_helper<Ts...>::data};
}
/// @relates type_id_list
CAF_CORE_EXPORT std::string to_string(type_id_list xs);
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/detail/meta_object.hpp"
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "caf/config.hpp"
#include "caf/span.hpp"
namespace caf::detail {
#define fatal(str) \
do { \
fprintf(stderr, "FATAL: " str "\n"); \
abort(); \
} while (false)
namespace {
// Stores global type information.
meta_object* meta_objects;
// Stores the size of `meta_objects`.
size_t meta_objects_size;
// Make sure to clean up all meta objects on program exit.
struct meta_objects_cleanup {
~meta_objects_cleanup() {
delete[] meta_objects;
}
} cleanup_helper;
} // namespace
span<const meta_object> global_meta_objects() {
return {meta_objects, meta_objects_size};
}
meta_object& global_meta_object(type_id_t id) {
CAF_ASSERT(id < meta_objects_size);
return meta_objects[id];
}
void clear_global_meta_objects() {
if (meta_objects != nullptr) {
delete[] meta_objects;
meta_objects = nullptr;
meta_objects_size = 0;
}
}
span<meta_object> resize_global_meta_objects(size_t size) {
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;
meta_objects = new_storage;
meta_objects_size = size;
return {new_storage, size};
}
void set_global_meta_objects(type_id_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
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/type_id_list.hpp"
#include "caf/detail/meta_object.hpp"
namespace caf {
std::string to_string(type_id_list xs) {
if (!xs || xs.size() == 0)
return "[]";
std::string result;
result += '[';
result += detail::global_meta_object(xs[0]).type_name;
for (size_t index = 1; index < xs.size(); ++index) {
result += ", ";
result += detail::global_meta_object(xs[index]).type_name;
}
result += ']';
return result;
}
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#define CAF_SUITE detail.meta_object
#include "caf/detail/meta_object.hpp"
#include "caf/test/dsl.hpp"
#include <tuple>
#include <type_traits>
#include "caf/binary_deserializer.hpp"
#include "caf/binary_serializer.hpp"
#include "caf/detail/make_meta_object.hpp"
#include "caf/init_global_meta_objects.hpp"
using namespace std::string_literals;
using namespace caf;
using namespace caf::detail;
namespace {
struct i32_wrapper {
static size_t instances;
int32_t value;
i32_wrapper() : value(0) {
++instances;
}
~i32_wrapper() {
--instances;
}
};
template <class Inspector>
auto inspect(Inspector& f, i32_wrapper& x) {
return f(x.value);
}
size_t i32_wrapper::instances = 0;
struct i64_wrapper {
static size_t instances;
int64_t value;
i64_wrapper() : value(0) {
++instances;
}
~i64_wrapper() {
--instances;
}
};
template <class Inspector>
auto inspect(Inspector& f, i64_wrapper& x) {
return f(x.value);
}
size_t i64_wrapper::instances = 0;
} // namespace
CAF_BEGIN_TYPE_ID_BLOCK(meta_object_suite, caf::first_custom_type_id)
CAF_ADD_TYPE_ID(meta_object_suite, i32_wrapper)
CAF_ADD_TYPE_ID(meta_object_suite, i64_wrapper)
CAF_END_TYPE_ID_BLOCK(meta_object_suite)
namespace caf {
static_assert(meta_object_suite_first_type_id == first_custom_type_id);
static_assert(meta_object_suite_last_type_id == first_custom_type_id + 1);
static_assert(type_id<i32_wrapper>::value == first_custom_type_id);
static_assert(type_id<i64_wrapper>::value == first_custom_type_id + 1);
static_assert(type_id<i32_wrapper>::value == meta_object_suite_first_type_id);
static_assert(type_id<i64_wrapper>::value == meta_object_suite_last_type_id);
} // namespace caf
namespace {
struct fixture {
fixture() {
CAF_ASSERT(i32_wrapper::instances == 0);
clear_global_meta_objects();
}
};
} // namespace
CAF_TEST_FIXTURE_SCOPE(meta_object_suite, fixture)
CAF_TEST(meta objects allow construction and destruction of objects) {
auto meta_i32_wrapper = make_meta_object<i32_wrapper>("i32_wrapper");
std::aligned_storage_t<sizeof(i32_wrapper), alignof(i32_wrapper)> storage;
meta_i32_wrapper.default_construct(&storage);
CAF_CHECK_EQUAL(i32_wrapper::instances, 1u);
meta_i32_wrapper.destroy(&storage);
CAF_CHECK_EQUAL(i32_wrapper::instances, 0u);
}
CAF_TEST(meta objects allow serialization of objects) {
byte_buffer buf;
auto meta_i32_wrapper = make_meta_object<i32_wrapper>("i32_wrapper");
std::aligned_storage_t<sizeof(i32_wrapper), alignof(i32_wrapper)> storage;
binary_serializer sink{nullptr, buf};
meta_i32_wrapper.default_construct(&storage);
CAF_CHECK_EQUAL(i32_wrapper::instances, 1u);
meta_i32_wrapper.save_binary(sink, &storage);
i32_wrapper copy;
CAF_CHECK_EQUAL(i32_wrapper::instances, 2u);
copy.value = 42;
binary_deserializer source{nullptr, buf};
meta_i32_wrapper.load_binary(source, &copy);
CAF_CHECK_EQUAL(copy.value, 0);
meta_i32_wrapper.destroy(&storage);
CAF_CHECK_EQUAL(i32_wrapper::instances, 1u);
}
CAF_TEST(resizing the global meta objects keeps entries) {
auto eq = [](const meta_object& x, const meta_object& y) {
return std::tie(x.destroy, x.default_construct, x.save_binary,
x.load_binary, x.save, x.load)
== std::tie(y.destroy, y.default_construct, y.save_binary,
y.load_binary, y.save, y.load);
};
auto meta_i32 = make_meta_object<int32_t>("int32_t");
auto xs1 = resize_global_meta_objects(1);
CAF_CHECK_EQUAL(xs1.size(), 1u);
xs1[0] = meta_i32;
CAF_CHECK(eq(xs1[0], meta_i32));
auto xs2 = resize_global_meta_objects(2);
CAF_CHECK_EQUAL(xs2.size(), 2u);
CAF_CHECK(eq(xs2[0], meta_i32));
resize_global_meta_objects(3);
CAF_CHECK(eq(global_meta_object(0), meta_i32));
}
CAF_TEST(init_global_meta_objects takes care of creating a meta object table) {
init_global_meta_objects<meta_object_suite_type_ids>();
auto xs = global_meta_objects();
CAF_REQUIRE_EQUAL(xs.size(), meta_object_suite_last_type_id + 1u);
CAF_CHECK_EQUAL(type_name_by_id_v<type_id_v<i32_wrapper>>, "i32_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<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()
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#define CAF_SUITE type_id_list
#include "caf/type_id_list.hpp"
#include "caf/test/dsl.hpp"
#include "caf/init_global_meta_objects.hpp"
using namespace caf;
CAF_TEST(lists store the size at index 0) {
type_id_t data[] = {3, 1, 2, 4};
type_id_list xs{data};
CAF_CHECK_EQUAL(xs.size(), 3u);
CAF_CHECK_EQUAL(xs[0], 1u);
CAF_CHECK_EQUAL(xs[1], 2u);
CAF_CHECK_EQUAL(xs[2], 4u);
}
CAF_TEST(lists are comparable) {
type_id_t data[] = {3, 1, 2, 4};
type_id_list xs{data};
type_id_t data_copy[] = {3, 1, 2, 4};
type_id_list ys{data_copy};
CAF_CHECK_EQUAL(xs, ys);
data_copy[1] = 10;
CAF_CHECK_NOT_EQUAL(xs, ys);
CAF_CHECK_LESS(xs, ys);
}
CAF_TEST(make_type_id_list constructs a list from types) {
auto xs = make_type_id_list<uint8_t, bool, float>();
CAF_CHECK_EQUAL(xs.size(), 3u);
CAF_CHECK_EQUAL(xs[0], type_id_v<uint8_t>);
CAF_CHECK_EQUAL(xs[1], type_id_v<bool>);
CAF_CHECK_EQUAL(xs[2], type_id_v<float>);
}
CAF_TEST(type ID lists are convertible to strings) {
detail::clear_global_meta_objects();
init_global_meta_objects<builtin_type_ids>();
auto xs = make_type_id_list<uint8_t, bool, float>();
CAF_CHECK_EQUAL(to_string(xs), "[uint8_t, bool, float]");
}
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