26 #ifndef PDI_REF_ANY_H_ 27 #define PDI_REF_ANY_H_ 34 #include <unordered_map> 36 #include <pdi/array_datatype.h> 37 #include <pdi/pdi_fwd.h> 38 #include <pdi/datatype.h> 39 #include <pdi/error.h> 40 #include <pdi/record_datatype.h> 41 #include <pdi/scalar_datatype.h> 50 template<
bool R,
bool W>
59 struct Ref_access<R, true> {
67 struct 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)},
184 m_type{std::move(type)},
191 delete (cloned_type);
193 }, readable, writable};
222 if ( !other.m_content )
return NULL;
223 if ( !other.m_content->m_data )
return NULL;
224 return other.m_content;
248 const Datatype& type()
const noexcept;
252 return std::hash<Referenced_data*>()(get_content(*
this));
271 template<
bool R,
bool W>
272 class PDI_EXPORT Ref_any:
289 link(get_content(other));
298 template<
bool OR,
bool OW>
302 link(get_content(other));
311 if (!other.m_content)
return;
315 m_content = other.m_content;
316 other.m_content =
nullptr;
330 if (type->datasize() && !data && (readable||writable)) {
331 throw Type_error{
"Referencing null data with non-null size"};
334 link(
new Referenced_data(data, freefunc, std::move(type), readable, writable));
347 std::pair<void*, Datatype_uptr> subref_info = other.
type().
subaccess(get_content(other)->m_data, accessor);
349 get_content(other)->m_buffer,
351 std::move(subref_info.second)));
360 Ref_any(
Ref other,
const std::vector<std::unique_ptr<Datatype::Accessor_base>>& accessors):
364 std::pair<void*, Datatype_uptr> subref_info = other.
type().
subaccess(get_content(other)->m_data, accessors);
366 get_content(other)->m_buffer,
368 std::move(subref_info.second)));
379 Ref_any& operator= (Ref_any&& other) noexcept
382 if (&other ==
this)
return *
this;
386 if (other.is_null())
return *
this;
388 other.m_content->m_buffer->m_notifications.erase(&other);
390 m_content = other.m_content;
391 other.m_content =
nullptr;
395 Ref_any& operator= (
const Ref_any& other)
const noexcept
398 if (&other ==
this)
return *
this;
402 link(get_content(other));
409 return m_content == get_content(o);
415 return m_content != get_content(o);
421 return m_content < get_content(o);
427 return m_content > get_content(o);
433 return m_content <= get_content(o);
439 return m_content >= get_content(o);
447 Ref operator[] (
const std::string& member_name)
const 450 throw Type_error{
"Cannot access member from empty Ref: `{}'", member_name};
460 Ref operator[] (
const char* member_name)
const 462 return this->operator[](std::string(member_name));
470 Ref operator[] (std::size_t index)
const 473 throw Type_error{
"Cannot access array index from empty Ref: `{}'", index};
483 Ref operator[] (std::pair<std::size_t, std::size_t> slice)
const 486 throw Type_error{
"Cannot access array slice from empty Ref: `{}'", index};
495 operator typename Ref_access<R, W>::type()
const 504 typename Ref_access<R, W>::type
get()
const 506 if (is_null())
throw Right_error{
"Trying to dereference a null reference"};
507 return m_content->m_data;
514 typename Ref_access<R, W>::type
get(std::nothrow_t)
const noexcept
516 if (is_null())
return nullptr;
517 return m_content->m_data;
526 static_assert(R,
"Cannot get scalar_value from Ref without read access");
527 if (
const Scalar_datatype* scalar_type = dynamic_cast<const Scalar_datatype*>(&type())) {
529 switch (scalar_type->buffersize()) {
531 return *
static_cast<const uint8_t*
>(m_content->m_data);
533 return *
static_cast<const uint16_t*
>(m_content->m_data);
535 return *
static_cast<const uint32_t*
>(m_content->m_data);
537 return *
static_cast<const uint64_t*
>(m_content->m_data);
539 throw Type_error{
"Unknown size of unsigned integer datatype"};
542 switch (scalar_type->buffersize()) {
544 return *
static_cast<const int8_t*
>(m_content->m_data);
546 return *
static_cast<const int16_t*
>(m_content->m_data);
548 return *
static_cast<const int32_t*
>(m_content->m_data);
550 return *
static_cast<const int64_t*
>(m_content->m_data);
552 throw Type_error{
"Unknown size of integer datatype"};
555 switch (type().buffersize()) {
557 return *
static_cast<const float*
>(m_content->m_data);
560 return *
static_cast<const double*
>(m_content->m_data);
563 throw Type_error{
"Unknown size of float datatype"};
566 throw Type_error{
"Unknown datatype to get value"};
569 throw Type_error{
"Expected scalar, found invalid type instead: {}", type().debug_string()};
576 operator bool () const noexcept
585 if (m_content) unlink();
595 return do_copy(*
this);
606 if (is_null())
return nullptr;
609 while (!m_content->m_buffer->m_notifications.empty()) {
611 const Reference_base* key = m_content->m_buffer->m_notifications.begin()->first;
613 m_content->m_buffer->m_notifications.begin()->second(*
this);
615 m_content->m_buffer->m_notifications.erase(key);
618 void* result = m_content->m_data;
619 m_content->m_data =
nullptr;
620 m_content->m_buffer->m_delete = []() {};
633 if (!is_null()) m_content->m_buffer->m_notifications[
this] = notifier;
644 bool PDI_NO_EXPORT is_null()
const noexcept
646 if (!m_content)
return true;
647 if (!m_content->m_data) {
658 void PDI_NO_EXPORT unlink()
const noexcept
661 m_content->m_buffer->m_notifications.erase(
this);
662 if (R || W) --m_content->m_buffer->m_write_locks;
663 if (W) --m_content->m_buffer->m_read_locks;
664 --m_content->m_owners;
665 if (!m_content->m_owners)
delete m_content;
679 if (!content || !content->
m_data)
return;
684 if (R || W) ++m_content->m_buffer->m_write_locks;
685 if (W) ++m_content->m_buffer->m_read_locks;
694 template<
bool R,
bool W>
695 struct hash<
PDI::Ref_any<R,W>> {
704 #endif // PDI_REF_ANY_H_ virtual Datatype_uptr clone_type() const =0
Creates a new datatype as an exact copy of this one.
A descriptor for data on which references can point.
Definition: ref_any.h:143
Accessor to get single element from array.
Definition: array_datatype.h:61
T scalar_value()
Returns a scalar value of type T taken from the data buffer.
Definition: ref_any.h:524
Definition: scalar_datatype.h:38
std::unordered_map< const Reference_base *, std::function< void(Ref)> > m_notifications
Nullification notifications registered on this instance.
Definition: ref_any.h:106
A Datatype is a Datatype_template that accepts no argument.
Definition: datatype.h:46
virtual void destroy_data(void *ptr) const =0
Function used to delete the data behind the datatype.
Base class for datatype accesssors, that allow to get pointer to subtype.
Definition: datatype.h:52
Ref_any(const Ref_any &other) noexcept
Copies an existing reference.
Definition: ref_any.h:286
void * m_data
In-memory location of the data.
Definition: ref_any.h:149
A dynamically typed reference to data with automatic memory management and read/write locking semanti...
Definition: pdi_fwd.h:93
~Referenced_buffer()
Definition: ref_any.h:128
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:220
Ref_any(Ref other, const Datatype::Accessor_base &accessor)
Creates a subreference from reference.
Definition: ref_any.h:343
Accessor to get a slice of an array, returns array of the same subtype.
Definition: array_datatype.h:84
size_t hash() const noexcept
Definition: ref_any.h:250
int m_owners
Number of references to this buffer.
Definition: ref_any.h:94
std::unique_ptr< Datatype > Datatype_uptr
Definition: pdi_fwd.h:78
Datatype_uptr m_type
Type of the data.
Definition: ref_any.h:152
Referenced_data(Referenced_buffer *buffer, void *data, Datatype_uptr type)
Constructs a new data descriptor from an already referenced buffer.
Definition: ref_any.h:163
Reference_base() noexcept
Constructs a null reference.
Definition: ref_any.h:233
std::function< void()> m_delete
The function to call to deallocate the buffer memory.
Definition: ref_any.h:91
int m_read_locks
Number of locks preventing read access.
Definition: ref_any.h:97
int m_owners
Number of references to this data.
Definition: ref_any.h:155
void * release() noexcept
Releases ownership of the referenced raw data by nullifying all existing references.
Definition: ref_any.h:604
A descriptor for a buffer in which references can point.
Definition: ref_any.h:88
~Ref_any()
Destructor.
Definition: ref_any.h:374
Referenced_data(void *data, std::function< void(void *)> freefunc, Datatype_uptr type, bool readable, bool writable)
Constructs a new data descriptor.
Definition: ref_any.h:182
Referenced_buffer * m_buffer
The buffer in which the data lives.
Definition: ref_any.h:146
void reset() noexcept
Nullify the reference.
Definition: ref_any.h:583
Ref_any(void *data, std::function< void(void *)> freefunc, Datatype_uptr type, bool readable, bool writable)
Creates a reference to currently unreferenced data.
Definition: ref_any.h:327
int m_write_locks
Number of locks preventing write access.
Definition: ref_any.h:103
Definition: array_datatype.h:37
void on_nullify(std::function< void(Ref)> notifier) const noexcept
Registers a nullification callback.
Definition: ref_any.h:631
Ref_any(const Ref_any< OR, OW > &other) noexcept
Copies an existing reference with different privileges.
Definition: ref_any.h:299
Ref_any(Ref other, const std::vector< std::unique_ptr< Datatype::Accessor_base >> &accessors)
Creates a subreference from reference.
Definition: ref_any.h:360
Ref_any(Ref_any &&other) noexcept
Moves an existing reference.
Definition: ref_any.h:308
Referenced_data * m_content
Pointer on the data content, can be null if the ref is null.
Definition: ref_any.h:215
std::pair< void *, Datatype_uptr > subaccess(void *from, const Accessor_base &accessor) const
Creates datatype of subtype and returns it with a moved pointer.
Member accessor for record datatype.
Definition: record_datatype.h:48
A common base for all references, whatever their access privileges.
Definition: ref_any.h:80
const Datatype & type() const noexcept
accesses the type of the referenced raw data
Ref copy() const
Makes a copy of the raw content behind this reference and returns a new reference.
Definition: ref_any.h:593
Referenced_buffer(std::function< void()> deleter, bool readable, bool writable) noexcept
Constructs a new buffer descriptor.
Definition: ref_any.h:114
~Referenced_data()
Definition: ref_any.h:203