Skip to content
Snippets Groups Projects

API: Introduce value and datatype structs to Extern C

Merged Florian Spreckelsen requested to merge f-value-data-structs into dev
All threads resolved!
2 files
+ 241
26
Compare changes
  • Side-by-side
  • Inline

Files

+ 239
25
@@ -25,9 +25,10 @@
#include "caosdb/entity/v1alpha1/main.pb.h" // for RepeatedPtrField, Message
#include "caosdb/logging.h"
#include <google/protobuf/util/json_util.h> // for MessageToJson...
#include <memory> // for unique_ptr
#include <string> // for string
#include <vector> // for vector
#include <map>
#include <memory> // for unique_ptr
#include <string> // for string
#include <vector> // for vector
#define LIST_VALUE_CONSTRUCTOR(TYPE, SETTER) \
explicit inline Value(const std::vector<TYPE> &values) : ProtoMessageWrapper<ProtoValue>() { \
@@ -37,7 +38,9 @@
}
namespace caosdb::entity {
using caosdb::utility::get_arena;
using caosdb::utility::ProtoMessageWrapper;
using google::protobuf::Arena;
using ProtoSpecialValue = caosdb::entity::v1alpha1::SpecialValue;
using ProtoValue = caosdb::entity::v1alpha1::Value;
using ProtoScalarValue = caosdb::entity::v1alpha1::ScalarValue;
@@ -46,6 +49,8 @@ using ScalarValueCase = caosdb::entity::v1alpha1::ScalarValue::ScalarValueCase;
class Entity;
class Property;
class ScalarValue;
class Value;
// Represents special values which are otherwise hard to tranfer via protobuf.
enum SpecialValue {
@@ -55,46 +60,225 @@ enum SpecialValue {
EMPTY_STRING = ProtoSpecialValue::SPECIAL_VALUE_EMPTY_STRING,
};
class ScalarValue : public ProtoMessageWrapper<ProtoScalarValue> {
class AbstractValue {
public:
/**
* Virtual destructor.
*/
virtual ~AbstractValue(){};
/**
* Return true iff the value is a NULL value (NULL in the CaosDB sense).
*/
[[nodiscard]] virtual auto IsNull() const noexcept -> bool = 0;
/**
* Return true iff the value is best represented in C++ types as a
* std::string.
*
* If true, clients may call GetAsString to receive a std::string
* representation of the value.
*/
[[nodiscard]] virtual auto IsString() const noexcept -> bool = 0;
/**
* Return true iff the value is best represented in C++ types as a
* bool.
*
* If true, clients may call GetAsBool to receive a bool
* representation of the value.
*/
[[nodiscard]] virtual auto IsBool() const noexcept -> bool = 0;
/**
* Return true iff the value is best represented in C++ types as a
* double.
*
* If true, clients may call GetAsDouble to receive a double
* representation of the value.
*/
[[nodiscard]] virtual auto IsDouble() const noexcept -> bool = 0;
/**
* Return true iff the value is best represented in C++ types as an
* int64_t.
*
* If true, clients may call GetAsInt64 to receive an int64_t
* representation of the value.
*/
[[nodiscard]] virtual auto IsInt64() const noexcept -> bool = 0;
/**
* Return true iff the value is best represented in C++ types as a
* std::vector<ScalarValue>.
*
* If true, clients may call GetAsVector to receive a
* std::vector<ScalarValue> representation of the value.
*/
[[nodiscard]] virtual auto IsVector() const noexcept -> bool = 0;
/**
* Return a std::string representation of this value.
*
* Clients should call IsString before calling this function in order to
* assure that this value is indeed best represented by a std::string.
*
* The return value is undefined if IsString is false.
*/
[[nodiscard]] virtual auto GetAsString() const noexcept -> const std::string & = 0;
/**
* Return a bool representation of this value.
*
* Clients should call IsBool before calling this function in order to
* assure that this value is indeed best represented by a bool.
*
* The return value is undefined if IsBool is false.
*/
[[nodiscard]] virtual auto GetAsBool() const noexcept -> bool = 0;
/**
* Return a double representation of this value.
*
* Clients should call IsDouble before calling this function in order to
* assure that this value is indeed best represented by a double.
*
* The return value is undefined if IsDouble is false.
*/
[[nodiscard]] virtual auto GetAsDouble() const noexcept -> double = 0;
/**
* Return an int64_t representation of this value.
*
* Clients should call IsInt64 before calling this function in order to
* assure that this value is indeed best represented by an int64_t.
*
* The return value is undefined if IsInt64 is false.
*/
[[nodiscard]] virtual auto GetAsInt64() const noexcept -> int64_t = 0;
/**
* Return a std::vector<ScalarValue> representation of this value.
*
* Clients should call IsVector before calling this function in order to
* assure that this value is indeed best represented by a
* std::vector<ScalarValue>.
*
* The return value is undefined if IsVector is false.
*/
[[nodiscard]] virtual auto GetAsVector() const noexcept -> const std::vector<ScalarValue> & = 0;
friend class Value;
protected:
[[nodiscard]] virtual auto GetProtoValue() const noexcept -> const ProtoValue * = 0;
};
class ScalarValue : public AbstractValue, public ProtoMessageWrapper<ProtoScalarValue> {
public:
/**
* Destructor.
*/
inline ~ScalarValue(){};
/**
* Copy constructor.
*/
inline ScalarValue(const ScalarValue &original) : ScalarValue() {
this->wrapped->CopyFrom(*original.wrapped);
}
/**
* Move constructor.
*/
inline ScalarValue(ScalarValue &&other) : ScalarValue(std::move(other.wrapped)){};
/**
* Copy assignment operator.
*/
inline auto operator=(const ScalarValue &original) -> ScalarValue & {
if (&original != this) {
this->wrapped->CopyFrom(*original.wrapped);
}
return *this;
}
/**
* Move assignment operator.
*/
inline auto operator=(ScalarValue &&other) -> ScalarValue & {
if (&other != this) {
this->wrapped = std::move(other.wrapped);
}
return *this;
}
inline ScalarValue(ProtoScalarValue *wrapped) : ProtoMessageWrapper<ProtoScalarValue>(wrapped) {}
[[nodiscard]] inline auto IsNull() const noexcept -> bool {
return (this->wrapped->scalar_value_case() == ScalarValueCase::kSpecialValue &&
this->wrapped->special_value() == ProtoSpecialValue::SPECIAL_VALUE_UNSPECIFIED);
}
[[nodiscard]] inline auto IsString() const noexcept -> bool {
return (this->wrapped->scalar_value_case() == ScalarValueCase::kStringValue) ||
(this->wrapped->scalar_value_case() == ScalarValueCase::kSpecialValue &&
this->wrapped->special_value() == ProtoSpecialValue::SPECIAL_VALUE_EMPTY_STRING);
}
[[nodiscard]] inline auto AsString() const noexcept -> const std::string & {
[[nodiscard]] inline auto GetAsString() const noexcept -> const std::string & {
return this->wrapped->string_value();
}
[[nodiscard]] inline auto IsDouble() const noexcept -> bool {
return (this->wrapped->scalar_value_case() == ScalarValueCase::kDoubleValue);
}
[[nodiscard]] inline auto AsDouble() const noexcept -> double {
[[nodiscard]] inline auto GetAsDouble() const noexcept -> double {
return this->wrapped->double_value();
}
[[nodiscard]] inline auto IsInteger() const noexcept -> bool {
[[nodiscard]] inline auto IsInt64() const noexcept -> bool {
return (this->wrapped->scalar_value_case() == ScalarValueCase::kIntegerValue);
}
[[nodiscard]] inline auto AsInteger() const noexcept -> int64_t {
[[nodiscard]] inline auto GetAsInt64() const noexcept -> int64_t {
return this->wrapped->integer_value();
}
[[nodiscard]] inline auto IsBool() const noexcept -> bool {
return (this->wrapped->scalar_value_case() == ScalarValueCase::kBooleanValue);
}
[[nodiscard]] inline auto AsBool() const noexcept -> bool {
[[nodiscard]] inline auto GetAsBool() const noexcept -> bool {
return this->wrapped->boolean_value();
}
[[nodiscard]] auto IsVector() const noexcept -> bool {
// Always false b/c a scalar value is never a collection.
return false;
}
[[nodiscard]] auto GetAsVector() const noexcept -> const std::vector<ScalarValue> & {
// Always return an empty vector.
static const std::vector<ScalarValue> empty_collection;
return empty_collection;
}
friend class Value;
protected:
[[nodiscard]] auto GetProtoValue() const noexcept -> const ProtoValue * {
if (this->proto_value == nullptr) {
this->proto_value = Arena::CreateMessage<ProtoValue>(get_arena());
this->proto_value->mutable_scalar_value()->CopyFrom(*this->wrapped);
}
return this->proto_value;
};
inline ScalarValue() : ProtoMessageWrapper<ProtoScalarValue>() {}
private:
mutable ProtoValue *proto_value;
};
class Value : public ProtoMessageWrapper<ProtoValue> {
class Value : public AbstractValue, public ProtoMessageWrapper<ProtoValue> {
public:
/**
* Copy constructor.
*/
inline Value(const Value &original) : Value() { this->wrapped->CopyFrom(*original.wrapped); }
/**
* Move constructor.
*/
inline Value(Value &&other) : Value(std::move(other.wrapped)) {}
/**
* Destructor.
*/
inline ~Value() {}
inline Value() : ProtoMessageWrapper<ProtoValue>() {
// has NULL_VALUE now
}
explicit inline Value(const ScalarValue &value) : Value() {
this->wrapped->mutable_scalar_value()->CopyFrom(*value.wrapped);
}
explicit inline Value(const AbstractValue &value) : Value(value.GetProtoValue()) {}
explicit inline Value(ProtoValue *wrapped) : ProtoMessageWrapper<ProtoValue>(wrapped) {}
explicit inline Value(const std::string &value) : ProtoMessageWrapper<ProtoValue>() {
this->wrapped->mutable_scalar_value()->set_string_value(value);
@@ -121,7 +305,10 @@ public:
LIST_VALUE_CONSTRUCTOR(bool, set_boolean_value)
[[nodiscard]] inline auto IsNull() const noexcept -> bool {
return this->wrapped->value_case() == ValueCase::VALUE_NOT_SET;
return this->wrapped->value_case() == ValueCase::VALUE_NOT_SET ||
(this->wrapped->scalar_value().scalar_value_case() == ScalarValueCase::kSpecialValue &&
this->wrapped->scalar_value().special_value() ==
ProtoSpecialValue::SPECIAL_VALUE_UNSPECIFIED);
}
[[nodiscard]] inline auto IsString() const noexcept -> bool {
@@ -134,7 +321,7 @@ public:
}
return false;
}
[[nodiscard]] inline auto AsString() const noexcept -> const std::string & {
[[nodiscard]] inline auto GetAsString() const noexcept -> const std::string & {
return this->wrapped->scalar_value().string_value();
;
}
@@ -146,18 +333,18 @@ public:
}
return false;
}
[[nodiscard]] inline auto AsDouble() const noexcept -> double {
[[nodiscard]] inline auto GetAsDouble() const noexcept -> double {
return this->wrapped->scalar_value().double_value();
}
[[nodiscard]] inline auto IsInteger() const noexcept -> bool {
[[nodiscard]] inline auto IsInt64() const noexcept -> bool {
if (this->wrapped->value_case() == ValueCase::kScalarValue) {
return (this->wrapped->scalar_value().scalar_value_case() == ScalarValueCase::kIntegerValue);
}
return false;
}
[[nodiscard]] inline auto AsInteger() const noexcept -> int64_t {
[[nodiscard]] inline auto GetAsInt64() const noexcept -> int64_t {
return this->wrapped->scalar_value().integer_value();
}
@@ -168,31 +355,55 @@ public:
}
return false;
}
[[nodiscard]] inline auto AsBool() const noexcept -> bool {
[[nodiscard]] inline auto GetAsBool() const noexcept -> bool {
return this->wrapped->scalar_value().boolean_value();
}
[[nodiscard]] inline auto IsList() const noexcept -> bool {
[[nodiscard]] inline auto IsVector() const noexcept -> bool {
return this->wrapped->value_case() == ValueCase::kListValues;
}
[[nodiscard]] inline auto AsList() const noexcept -> const std::vector<ScalarValue> & {
if (!IsList()) {
[[nodiscard]] inline auto GetAsVector() const noexcept -> const std::vector<ScalarValue> & {
if (!IsVector()) {
// create empty list
this->list_values = std::make_unique<std::vector<ScalarValue>>();
this->collection_values = std::make_unique<std::vector<ScalarValue>>();
}
if (this->list_values == nullptr) {
this->list_values = std::make_unique<std::vector<ScalarValue>>();
if (this->collection_values == nullptr) {
this->collection_values = std::make_unique<std::vector<ScalarValue>>();
for (auto &scalar : *(this->wrapped->mutable_list_values()->mutable_values())) {
this->list_values->push_back(ScalarValue(&scalar));
this->collection_values->push_back(ScalarValue(&scalar));
}
}
return *(this->list_values);
return *(this->collection_values);
}
/**
* Return true if the underlying Protobuf messages have the same
* serialization.
*/
inline auto operator==(const Value &other) const noexcept -> bool {
return this->wrapped->SerializeAsString() == other.wrapped->SerializeAsString();
}
/**
* Copy assignment operator.
*/
inline auto operator=(const Value &other) -> Value & {
if (&other != this) {
this->wrapped->CopyFrom(*other.wrapped);
}
return *this;
}
/**
* Move assignment operator.
*/
inline auto operator=(Value &&other) -> Value & {
if (&other != this) {
this->wrapped = std::move(other.wrapped);
}
return *this;
}
inline auto ToString() const noexcept -> const std::string {
CAOSDB_DEBUG_MESSAGE_STRING(*wrapped, out)
return out;
@@ -201,8 +412,11 @@ public:
friend class Entity;
friend class Property;
protected:
[[nodiscard]] auto GetProtoValue() const noexcept -> const ProtoValue * { return this->wrapped; };
private:
mutable std::unique_ptr<std::vector<ScalarValue>> list_values;
mutable std::unique_ptr<std::vector<ScalarValue>> collection_values;
};
} // namespace caosdb::entity
Loading