34#include <unordered_map>
36#include <pdi/array_datatype.h>
37#include <pdi/pdi_fwd.h>
38#include <pdi/datatype.h>
40#include <pdi/record_datatype.h>
41#include <pdi/scalar_datatype.h>
50template<
bool R,
bool W>
59struct Ref_access<R, true> {
67struct Ref_access<true, false> {
69 typedef const void* type;
117 m_read_locks{readable ? 0 : 1},
118 m_write_locks{writable ? 0 : 1}
132 assert(m_read_locks == 0 || m_read_locks == 1);
133 assert(m_write_locks == 0 || m_write_locks == 1);
134 assert(m_notifications.empty());
166 m_type{
std::move(type)},
190 type->destroy_data(data);
192 }, readable, writable};
221 if ( !other.m_content )
return NULL;
222 if ( !other.m_content->m_data )
return NULL;
223 return other.m_content;
249 size_t hash() const noexcept
251 return std::hash<Referenced_data*>()(get_content(*
this));
270template<
bool R,
bool W>
275 template<
bool OR,
bool OW>
291 link(get_content(other));
300 template<
bool OR,
bool OW>
304 link(get_content(other));
313 if (!other.m_content)
return;
317 m_content = other.m_content;
318 other.m_content =
nullptr;
332 if (type->datasize() && !data && (readable||writable)) {
333 throw Type_error{
"Referencing null data with non-null size"};
336 link(
new Referenced_data(data, freefunc, std::move(type), readable, writable));
350 if (&other ==
this)
return *
this;
354 if (other.is_null())
return *
this;
356 other.m_content->m_buffer->m_notifications.erase(&other);
358 m_content = other.m_content;
359 other.m_content =
nullptr;
366 if (&other ==
this)
return *
this;
370 link(get_content(other));
377 return m_content == get_content(o);
383 return m_content != get_content(o);
389 return m_content < get_content(o);
395 return m_content > get_content(o);
401 return m_content <= get_content(o);
407 return m_content >= get_content(o);
415 Ref operator[] (
const std::string& member_name)
const
417 return this->operator[](member_name.c_str());
425 Ref operator[] (
const char* member_name)
const
428 throw Type_error{
"Cannot access member from empty Ref: `{}'", member_name};
430 std::pair<void*, Datatype_sptr> subref_info = type()->member(member_name, m_content->m_data);
435 std::move(subref_info.second)));
445 std::enable_if_t<std::is_integral<T>::value,
Ref> operator[] (T index)
const
448 throw Type_error{
"Cannot access array index from empty Ref: `{}'", index};
450 std::pair<void*, Datatype_sptr> subref_info = type()->index(index, m_content->m_data);
455 std::move(subref_info.second)));
464 Ref operator[] (std::pair<std::size_t, std::size_t> slice)
const
467 throw Type_error(
"Cannot access array slice from empty Ref: `{}:{}'", slice.first, slice.second);
469 std::pair<void*, Datatype_sptr> subref_info = type()->slice(slice.first, slice.second, m_content->m_data);
474 std::move(subref_info.second)));
482 operator typename Ref_access<R, W>::type()
const
491 typename Ref_access<R, W>::type
get()
const
493 if (is_null())
throw Right_error{
"Trying to dereference a null reference"};
494 return m_content->m_data;
501 typename Ref_access<R, W>::type
get(std::nothrow_t)
const noexcept
503 if (is_null())
return nullptr;
504 return m_content->m_data;
513 static_assert(R,
"Cannot get scalar_value from Ref without read access");
514 if (
auto&& scalar_type = std::dynamic_pointer_cast<const Scalar_datatype>(type())) {
516 switch (scalar_type->buffersize()) {
518 return *
static_cast<const uint8_t*
>(m_content->m_data);
520 return *
static_cast<const uint16_t*
>(m_content->m_data);
522 return *
static_cast<const uint32_t*
>(m_content->m_data);
524 return *
static_cast<const uint64_t*
>(m_content->m_data);
526 throw Type_error{
"Unknown size of unsigned integer datatype"};
529 switch (scalar_type->buffersize()) {
531 return *
static_cast<const int8_t*
>(m_content->m_data);
533 return *
static_cast<const int16_t*
>(m_content->m_data);
535 return *
static_cast<const int32_t*
>(m_content->m_data);
537 return *
static_cast<const int64_t*
>(m_content->m_data);
539 throw Type_error{
"Unknown size of integer datatype"};
542 switch (type()->buffersize()) {
544 return *
static_cast<const float*
>(m_content->m_data);
547 return *
static_cast<const double*
>(m_content->m_data);
550 throw Type_error{
"Unknown size of float datatype"};
553 throw Type_error{
"Unknown datatype to get value"};
556 throw Type_error{
"Expected scalar, found invalid type instead: {}", type()->debug_string()};
563 operator bool () const noexcept
572 if (m_content) unlink();
582 return do_copy(*
this);
593 if (is_null())
return nullptr;
596 while (!m_content->m_buffer->m_notifications.empty()) {
598 const Reference_base* key = m_content->m_buffer->m_notifications.begin()->first;
600 m_content->m_buffer->m_notifications.begin()->second(*
this);
602 m_content->m_buffer->m_notifications.erase(key);
605 void* result = m_content->m_data;
606 m_content->m_data =
nullptr;
607 m_content->m_buffer->m_delete = []() {};
620 if (!is_null()) m_content->m_buffer->m_notifications[
this] = notifier;
631 bool PDI_NO_EXPORT is_null() const noexcept
633 if (!m_content)
return true;
634 if (!m_content->m_data) {
645 void PDI_NO_EXPORT unlink() const noexcept
648 m_content->m_buffer->m_notifications.erase(
this);
649 if (R || W) --m_content->m_buffer->m_write_locks;
650 if (W) --m_content->m_buffer->m_read_locks;
651 --m_content->m_owners;
652 if (!m_content->m_owners)
delete m_content;
664 void PDI_NO_EXPORT link(Referenced_data* content)
noexcept
667 if (!content || !content->m_data)
return;
668 if (R && content->m_buffer->m_read_locks || W && content->m_buffer->m_write_locks) {
669 if (content->m_owners == 0)
delete content;
673 ++m_content->m_owners;
674 if (R || W) ++m_content->m_buffer->m_write_locks;
675 if (W) ++m_content->m_buffer->m_read_locks;
684template<
bool R,
bool W>
685struct 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:273
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:329
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:301
Ref_access< R, W >::type get(std::nothrow_t) const noexcept
Offers access to the referenced raw data, returns null for null references.
Definition: ref_any.h:501
Ref_any(Ref_any &&other) noexcept
Moves an existing reference.
Definition: ref_any.h:310
~Ref_any()
Destructor.
Definition: ref_any.h:342
Ref_access< R, W >::type get() const
Offers access to the referenced raw data, throws on null references.
Definition: ref_any.h:491
void * release() noexcept
Releases ownership of the referenced raw data by nullifying all existing references.
Definition: ref_any.h:591
Ref copy() const
Makes a copy of the raw content behind this reference and returns a new reference.
Definition: ref_any.h:580
Ref_any(const Ref_any &other) noexcept
Copies an existing reference.
Definition: ref_any.h:288
T scalar_value() const
Returns a scalar value of type T taken from the data buffer.
Definition: ref_any.h:511
void on_nullify(std::function< void(Ref)> notifier) const noexcept
Registers a nullification callback.
Definition: ref_any.h:618
void reset() noexcept
Nullify the reference.
Definition: ref_any.h:570
A common base for all references, whatever their access privileges.
Definition: ref_any.h:81
Reference_base(Reference_base &&)=delete
static 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:219
Reference_base() noexcept
Constructs a null reference.
Definition: ref_any.h:232
Reference_base(const Reference_base &)=delete
Referenced_data * m_content
Pointer on the data content, can be null if the ref is null.
Definition: ref_any.h:214
static Ref do_copy(Ref_r ref)
Datatype_sptr type() const noexcept
accesses the type of the referenced raw data
Definition: array_datatype.h:38
std::shared_ptr< const Datatype > Datatype_sptr
Definition: pdi_fwd.h:78
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:106
Referenced_buffer(const Referenced_buffer &)=delete
Referenced_buffer()=delete
int m_write_locks
Number of locks preventing write access.
Definition: ref_any.h:103
Referenced_buffer(Referenced_buffer &&)=delete
int m_read_locks
Number of locks preventing read access.
Definition: ref_any.h:97
std::function< void()> m_delete
The function to call to deallocate the buffer memory.
Definition: ref_any.h:91
int m_owners
Number of references to this buffer.
Definition: ref_any.h:94
Referenced_buffer(std::function< void()> deleter, bool readable, bool writable) noexcept
Constructs a new buffer descriptor.
Definition: ref_any.h:114
~Referenced_buffer()
Definition: ref_any.h:128
A descriptor for data on which references can point.
Definition: ref_any.h:143
Referenced_data(Referenced_buffer *buffer, void *data, Datatype_sptr type)
Constructs a new data descriptor from an already referenced buffer.
Definition: ref_any.h:163
Referenced_buffer * m_buffer
The buffer in which the data lives.
Definition: ref_any.h:146
Datatype_sptr m_type
Type of the data.
Definition: ref_any.h:152
~Referenced_data()
Definition: ref_any.h:202
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:182
Referenced_data(const Referenced_data &)=delete
void * m_data
In-memory location of the data.
Definition: ref_any.h:149
int m_owners
Number of references to this data.
Definition: ref_any.h:155
Referenced_data(Referenced_data &&)=delete