34#include <unordered_map>
36#include <pdi/pdi_fwd.h>
37#include <pdi/array_datatype.h>
38#include <pdi/datatype.h>
40#include <pdi/record_datatype.h>
41#include <pdi/scalar_datatype.h>
49template <
bool R,
bool W>
58struct Ref_access<R, true> {
66struct Ref_access<true, false> {
68 using type =
void const *;
71template <
bool R,
bool W>
72using ref_access_t =
typename Ref_access<R, W>::type;
111 : m_deallocator{deleter}
112 , m_read_locks{readable ? 0 : 1}
113 , m_write_locks{writable ? 0 : 1}
125 assert(m_read_locks == 0 || m_read_locks == 1);
126 assert(m_write_locks == 0 || m_write_locks == 1);
127 assert(m_notifications.empty());
137 mutable std::shared_ptr<Referenced_buffer>
m_buffer;
152 : m_buffer{
std::move(buffer)}
154 , m_type{
std::move(type)}
170 [data, freefunc, type]() {
171 type->destroy_data(data);
198 if (!other.m_content)
return nullptr;
199 if (!other.m_content->m_data)
return nullptr;
200 return other.m_content;
226 size_t hash() const noexcept {
return std::hash<Referenced_data*>()(get_content(*this).get()); }
240template <
bool R,
bool W>
244 template <
bool OR,
bool OW>
260 link(get_content(other));
269 template <
bool OR,
bool OW>
273 link(get_content(other));
282 if (!other.m_content)
return;
284 other.
m_content->m_buffer->m_notifications.erase(&other);
286 m_content = other.m_content;
287 other.m_content =
nullptr;
301 if (type->datasize() && !data && (readable || writable)) {
302 throw Type_error{
"Referencing null data with non-null size"};
305 link(std::make_shared<Referenced_data>(data, freefunc, std::move(type), readable, writable));
316 if (&other ==
this)
return *
this;
320 if (other.is_null())
return *
this;
322 other.m_content->m_buffer->m_notifications.erase(&other);
324 m_content = other.m_content;
325 other.m_content =
nullptr;
332 if (&other ==
this)
return *
this;
336 link(get_content(other));
343 return m_content == get_content(o);
349 return m_content != get_content(o);
355 return m_content < get_content(o);
361 return m_content > get_content(o);
367 return m_content <= get_content(o);
373 return m_content >= get_content(o);
381 Ref operator[] (
const std::string& member_name)
const {
return this->operator[] (member_name.c_str()); }
388 Ref operator[] (
const char* member_name)
const
391 throw Type_error{
"Cannot access member from empty Ref: `{}'", member_name};
393 std::pair<void*, Datatype_sptr> subref_info = type()->member(member_name, m_content->m_data);
395 result.link(std::make_shared<Referenced_data>(m_content->m_buffer, subref_info.first, std::move(subref_info.second)));
405 std::enable_if_t<std::is_integral<T>::value,
Ref> operator[] (T index)
const
408 throw Type_error{
"Cannot access array index from empty Ref: `{}'", index};
410 std::pair<void*, Datatype_sptr> subref_info = type()->index(index, m_content->m_data);
412 result.link(std::make_shared<Referenced_data>(m_content->m_buffer, subref_info.first, std::move(subref_info.second)));
421 Ref operator[] (std::pair<std::size_t, std::size_t> slice)
const
424 throw Type_error(
"Cannot access array slice from empty Ref: `{}:{}'", slice.first, slice.second);
426 std::pair<void*, Datatype_sptr> subref_info = type()->slice(slice.first, slice.second, m_content->m_data);
428 result.link(std::make_shared<Referenced_data>(m_content->m_buffer, subref_info.first, std::move(subref_info.second)));
439 throw Type_error{
"Cannot dereference an empty Ref"};
442 if (
auto&& pointer_type = std::dynamic_pointer_cast<const PDI::Pointer_datatype>(type())) {
444 std::pair<void*, Datatype_sptr> subref_info = type()->dereference(m_content->m_data);
446 result.link(std::make_shared<Referenced_data>(m_content->m_buffer, subref_info.first, std::move(subref_info.second)));
452 throw Type_error{
"Cannot dereference a non pointer_type"};
460 operator ref_access_t<R, W> ()
const {
return get(); }
466 ref_access_t<R, W>
get()
const
468 if (is_null())
throw Right_error{
"Trying to dereference a null reference"};
469 return m_content->m_data;
476 ref_access_t<R, W>
get(std::nothrow_t)
const noexcept
478 if (is_null())
return nullptr;
479 return m_content->m_data;
488 static_assert(R,
"Cannot get scalar_value from Ref without read access");
489 if (
auto&& scalar_type = std::dynamic_pointer_cast<const Scalar_datatype>(type())) {
491 switch (scalar_type->buffersize()) {
493 return *
static_cast<const uint8_t*
>(m_content->m_data);
495 return *
static_cast<const uint16_t*
>(m_content->m_data);
497 return *
static_cast<const uint32_t*
>(m_content->m_data);
499 return *
static_cast<const uint64_t*
>(m_content->m_data);
501 throw Type_error{
"Unknown size of unsigned integer datatype"};
504 switch (scalar_type->buffersize()) {
506 return *
static_cast<const int8_t*
>(m_content->m_data);
508 return *
static_cast<const int16_t*
>(m_content->m_data);
510 return *
static_cast<const int32_t*
>(m_content->m_data);
512 return *
static_cast<const int64_t*
>(m_content->m_data);
514 throw Type_error{
"Unknown size of integer datatype"};
517 switch (type()->buffersize()) {
519 return *
static_cast<const float*
>(m_content->m_data);
522 return *
static_cast<const double*
>(m_content->m_data);
525 throw Type_error{
"Unknown size of float datatype"};
528 throw Type_error{
"Unknown datatype to get value"};
531 throw Type_error{
"Expected scalar, found invalid type instead: {}", type()->debug_string()};
540 static_assert(std::is_scalar<T>::value,
"T is not a scalar type");
541 static_assert(W,
"Cannot assign a scalar value to Ref without write access");
542 if (
auto&& scalar_type = std::dynamic_pointer_cast<const Scalar_datatype>(type())) {
544 switch (scalar_type->buffersize()) {
546 *
static_cast<uint8_t*
>(this->get()) = value;
549 *
static_cast<uint16_t*
>(this->get()) = value;
552 *
static_cast<uint32_t*
>(this->get()) = value;
555 *
static_cast<uint64_t*
>(this->get()) = value;
558 throw Type_error{
"Unknown size of unsigned integer datatype"};
561 switch (scalar_type->buffersize()) {
563 *
static_cast<int8_t*
>(this->get()) = value;
566 *
static_cast<int16_t*
>(this->get()) = value;
569 *
static_cast<int32_t*
>(this->get()) = value;
572 *
static_cast<int64_t*
>(this->get()) = value;
575 throw Type_error{
"Unknown size of integer datatype"};
578 switch (type()->buffersize()) {
580 *
static_cast<float*
>(this->get()) = value;
584 *
static_cast<double*
>(this->get()) = value;
588 throw Type_error{
"Unknown size of float datatype"};
591 throw Type_error{
"Unknown datatype to get value"};
594 throw Type_error{
"Expected scalar, found invalid type instead: {}", type()->debug_string()};
602 operator bool () const noexcept {
return !is_null(); }
608 if (m_content) unlink();
626 if (is_null())
return nullptr;
629 while (!m_content->m_buffer->m_notifications.empty()) {
631 const Reference_base* key = m_content->m_buffer->m_notifications.begin()->first;
633 m_content->m_buffer->m_notifications.begin()->second(*
this);
635 m_content->m_buffer->m_notifications.erase(key);
638 void* result = m_content->m_data;
639 m_content->m_data =
nullptr;
640 m_content->m_buffer->m_deallocator = []() {
654 if (!is_null()) m_content->m_buffer->m_notifications[
this] = notifier;
665 bool PDI_NO_EXPORT is_null() const noexcept
667 if (!m_content)
return true;
668 if (!m_content->m_data) {
679 void PDI_NO_EXPORT unlink() const noexcept
682 m_content->m_buffer->m_notifications.erase(
this);
683 if (R || W) --m_content->m_buffer->m_write_locks;
684 if (W) --m_content->m_buffer->m_read_locks;
696 void PDI_NO_EXPORT link(std::shared_ptr<Referenced_data> content)
noexcept
699 if (!content || !content->m_data)
return;
700 if ((R && content->m_buffer->m_read_locks) || (W && content->m_buffer->m_write_locks)) {
703 m_content = std::move(content);
704 if (R || W) ++m_content->m_buffer->m_write_locks;
705 if (W) ++m_content->m_buffer->m_read_locks;
713template <
bool R,
bool W>
714struct hash<
PDI::Ref_any<R, W>> {
A dynamically typed reference to data with automatic memory management and read/write locking semanti...
Definition ref_any.h:242
Ref_any(void *data, std::function< void(void *)> freefunc, Datatype_sptr type, bool readable, bool writable)
Creates a reference to currently unreferenced data.
Definition ref_any.h:298
Ref_any()=default
Constructs a null reference.
Ref_any(const Ref_any< OR, OW > &other) noexcept
Copies an existing reference with different privileges.
Definition ref_any.h:270
void scalar_assign(T value)
Assign a scalar value to the data buffer according to its type.
Definition ref_any.h:538
Ref_any(Ref_any &&other) noexcept
Moves an existing reference.
Definition ref_any.h:279
~Ref_any()
Destructor.
Definition ref_any.h:311
void * release() noexcept
Releases ownership of the referenced raw data by nullifying all existing references.
Definition ref_any.h:624
ref_access_t< R, W > get() const
Offers access to the referenced raw data, throws on null references.
Definition ref_any.h:466
Ref copy() const
Makes a copy of the raw content behind this reference and returns a new reference.
Definition ref_any.h:616
Ref_any(const Ref_any &other) noexcept
Copies an existing reference.
Definition ref_any.h:257
ref_access_t< R, W > get(std::nothrow_t) const noexcept
Offers access to the referenced raw data, returns null for null references.
Definition ref_any.h:476
T scalar_value() const
Returns a scalar value of type T taken from the data buffer.
Definition ref_any.h:486
Ref dereference() const
Create a reference to the pointed content in case the ref type is a reference.
Definition ref_any.h:436
void on_nullify(std::function< void(Ref)> notifier) const noexcept
Registers a nullification callback.
Definition ref_any.h:652
void reset() noexcept
Nullify the reference.
Definition ref_any.h:606
A common base for all references, whatever their access privileges.
Definition ref_any.h:82
std::shared_ptr< Referenced_data > m_content
Pointer on the data content, can be null if the ref is null.
Definition ref_any.h:192
Reference_base(Reference_base &&)=delete
Reference_base() noexcept
Constructs a null reference.
Definition ref_any.h:209
Reference_base(const Reference_base &)=delete
static Ref do_copy(Ref_r ref)
Datatype_sptr type() const noexcept
accesses the type of the referenced raw data
static std::shared_ptr< Referenced_data > get_content(const Reference_base &other) noexcept
Function to access the content from a reference with different access right.
Definition ref_any.h:196
Definition array_datatype.h:38
std::shared_ptr< const Datatype > Datatype_sptr
Definition pdi_fwd.h:79
A descriptor for a buffer in which references can point.
Definition ref_any.h:88
std::unordered_map< const Reference_base *, std::function< void(Ref)> > m_notifications
Nullification notifications registered on this instance.
Definition ref_any.h:102
Referenced_buffer(const Referenced_buffer &)=delete
std::function< void()> m_deallocator
The function to call to deallocate the buffer memory.
Definition ref_any.h:90
Referenced_buffer()=delete
int m_write_locks
Number of locks preventing write access.
Definition ref_any.h:99
Referenced_buffer(Referenced_buffer &&)=delete
int m_read_locks
Number of locks preventing read access.
Definition ref_any.h:93
Referenced_buffer(std::function< void()> deleter, bool readable, bool writable) noexcept
Constructs a new buffer descriptor.
Definition ref_any.h:110
~Referenced_buffer()
Definition ref_any.h:122
A descriptor for data on which references can point.
Definition ref_any.h:135
std::shared_ptr< Referenced_buffer > m_buffer
The buffer in which the data lives.
Definition ref_any.h:137
Referenced_data(std::shared_ptr< Referenced_buffer > buffer, void *data, Datatype_sptr type)
Constructs a new data descriptor from an already referenced buffer.
Definition ref_any.h:151
Datatype_sptr m_type
Type of the data.
Definition ref_any.h:143
Referenced_data(void *data, std::function< void(void *)> freefunc, Datatype_sptr type, bool readable, bool writable)
Constructs a new data descriptor.
Definition ref_any.h:168
Referenced_data(const Referenced_data &)=delete
void * m_data
In-memory location of the data.
Definition ref_any.h:140
Referenced_data(Referenced_data &&)=delete