Atomic variables (std::atomic and std::atomic_flag)¶
reflect-cpp supports serializing and deserializing atomic types. The library treats atomic wrappers as containers around an underlying value and provides helpers to read plain (non-atomic) representations from input and to set atomic fields afterwards.
Supported atomic types¶
std::atomic<T>std::atomic_flag(serialized as a boolean)- Arrays of atomic types (std::array
and C-style arrays) - Aggregate types (structs/NamedTuple) containing atomic fields — each atomic field is handled independently
Example (writing)¶
struct Stats {
std::atomic<std::uint64_t> bytes_downloaded;
std::atomic<bool> finished;
std::atomic_flag atomic_flag;
};
Stats stats{.bytes_downloaded = 123456789, .finished = true, .atomic_flag = ATOMIC_FLAG_INIT};
const auto json_str = rfl::json::write(stats);
// -> {"bytes_downloaded":123456789,"finished":true,"atomic_flag":false}
Note: the exact boolean value for atomic_flag depends on whether it is set or cleared.
Example (reading)¶
Reading atomic variables is not quite trivial, because atomic fields cannot be copied or moved. Consider the following example:
// const auto res = rfl::json::read<Stats>(json_str);
// This will NOT compile because std::atomic<T> is neither copyable nor movable
There are two ways around this problem:
1. Wrap in rfl::Ref, rfl::Box, std::shared_ptr or std::unique_ptr¶
The easiest way to read structs with atomic fields is to wrap them in a pointer-like type such as rfl::Ref, rfl::Box, std::shared_ptr or std::unique_ptr. This works because the pointer-like types themselves are copyable/movable, even if the underlying type is not.
const auto res = rfl::json::read<rfl::Ref<Stats>>(json_str);
2. Read into a non-atomic representation and then set atomic fields¶
The second way is to read into a non-atomic representation of the struct and then set the atomic fields afterwards using rfl::atomic::set_atomic_fields. The non-atomic representation can be obtained using rfl::atomic::remove_atomic_t.
Stats stats;
const rfl::Result<rfl::Nothing> res =
rfl::json::read<rfl::atomic::remove_atomic_t<Stats>>(json_str)
.transform([&](auto&& non_atomic_stats) {
return rfl::atomic::set_atomic_fields(non_atomic_stats, &stats);
});
if (!res) {
// handle error
std::cerr << "Error reading JSON: " << res.error().what() << std::endl;
}
Limitations and notes¶
- Structs containing atomic fields must be default-constructible.
- Atomic types cannot be mixed with
rfl::DefaultValor therfl::DefaultIfMissingprocessor; attempting to do so triggers a static assertion at compile-time (see parser implementations). - The semantics used for setting atomic values use relaxed memory order (
std::memory_order_relaxed). - For complex aggregates,
rfl::atomicwill recurse into nested fields and arrays to set atomic members.