-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
RSDK-6636: Refactored AttributeMap with type-erased ProtoType (#272)
- Loading branch information
Showing
4 changed files
with
880 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,256 @@ | ||
#include <viam/sdk/common/proto_value.hpp> | ||
|
||
#include <google/protobuf/struct.pb.h> | ||
|
||
namespace viam { | ||
namespace sdk { | ||
|
||
using google::protobuf::Struct; | ||
using google::protobuf::Value; | ||
|
||
ProtoValue::ProtoValue() noexcept : ProtoValue(nullptr) {} | ||
|
||
template <typename T> | ||
ProtoValue::ProtoValue(T t) noexcept(std::is_nothrow_move_constructible<T>{}) | ||
: vtable_{model<T>::vtable_}, self_{std::move(t)} {} | ||
|
||
// -- explicit instantiations of by-value constructors -- // | ||
template ProtoValue::ProtoValue(std::nullptr_t) noexcept; | ||
template ProtoValue::ProtoValue(bool) noexcept; | ||
template ProtoValue::ProtoValue(int) noexcept; | ||
template ProtoValue::ProtoValue(double) noexcept; | ||
template ProtoValue::ProtoValue(std::string) noexcept( | ||
std::is_nothrow_move_constructible<std::string>{}); | ||
template ProtoValue::ProtoValue(std::vector<ProtoValue>) noexcept( | ||
std::is_nothrow_move_constructible<std::vector<ProtoValue>>{}); | ||
template ProtoValue::ProtoValue(ProtoStruct m) noexcept( | ||
std::is_nothrow_move_constructible<ProtoStruct>{}); | ||
|
||
ProtoValue::ProtoValue(const char* str) : ProtoValue(std::string(str)) {} | ||
|
||
ProtoValue::ProtoValue(ProtoValue&& other) noexcept(proto_value_details::all_moves_noexcept{}) | ||
: vtable_(std::move(other.vtable_)), self_(std::move(other.self_), vtable_) {} | ||
|
||
ProtoValue::ProtoValue(const ProtoValue& other) | ||
: vtable_(other.vtable_), self_(other.self_, other.vtable_) {} | ||
|
||
ProtoValue::ProtoValue(const Value* value) // NOLINT(misc-no-recursion) | ||
: ProtoValue([](const Value& v) { // NOLINT(misc-no-recursion) | ||
switch (v.kind_case()) { | ||
case Value::KindCase::kBoolValue: { | ||
return ProtoValue(v.bool_value()); | ||
} | ||
case Value::KindCase::kStringValue: { | ||
return ProtoValue(v.string_value()); | ||
} | ||
case Value::KindCase::kNumberValue: { | ||
return ProtoValue(v.number_value()); | ||
} | ||
case Value::KindCase::kListValue: { | ||
std::vector<ProtoValue> vec; | ||
vec.reserve(v.list_value().values_size()); | ||
for (const Value& list_val : v.list_value().values()) { | ||
vec.push_back(ProtoValue::from_proto(list_val)); | ||
} | ||
|
||
return ProtoValue(std::move(vec)); | ||
} | ||
case Value::KindCase::kStructValue: { | ||
return ProtoValue(struct_to_map(v.struct_value())); | ||
} | ||
case Value::KindCase::KIND_NOT_SET: | ||
case Value::KindCase::kNullValue: | ||
default: | ||
return ProtoValue(nullptr); | ||
} | ||
}(*value)) {} | ||
|
||
ProtoValue& ProtoValue::operator=(ProtoValue&& other) noexcept( | ||
proto_value_details::all_moves_noexcept{}) { | ||
ProtoValue(std::move(other)).swap(*this); | ||
return *this; | ||
} | ||
|
||
ProtoValue& ProtoValue::operator=(const ProtoValue& other) { | ||
ProtoValue(other).swap(*this); | ||
return *this; | ||
} | ||
|
||
ProtoValue::~ProtoValue() { | ||
self_.destruct(vtable_); | ||
} | ||
|
||
bool operator==(const ProtoValue& lhs, const ProtoValue& rhs) { | ||
return lhs.vtable_.equal_to(lhs.self_.get(), rhs.self_.get(), rhs.vtable_); | ||
} | ||
|
||
void ProtoValue::swap(ProtoValue& other) noexcept(proto_value_details::all_moves_noexcept{}) { | ||
self_.swap(vtable_, other.self_, other.vtable_); | ||
std::swap(vtable_, other.vtable_); | ||
} | ||
|
||
template <typename Val> | ||
ProtoValue ProtoValue::from_proto(const Val& v) { // NOLINT(misc-no-recursion) | ||
return ProtoValue(&v); | ||
} | ||
|
||
template ProtoValue ProtoValue::from_proto(const Value&); | ||
|
||
int ProtoValue::kind() const { | ||
return vtable_.kind(); | ||
} | ||
|
||
bool ProtoValue::is_null() const { | ||
return kind() == kind_t<std::nullptr_t>{}; | ||
} | ||
|
||
// --- ProtoT::model<T> definitions --- // | ||
template <typename T> | ||
ProtoValue::model<T>::model(T t) noexcept(std::is_nothrow_move_constructible<T>{}) | ||
: data(std::move(t)) {} | ||
|
||
template <typename T> | ||
void ProtoValue::model<T>::dtor(void* self) noexcept { | ||
static_cast<model*>(self)->~model(); | ||
} | ||
|
||
template <typename T> | ||
void ProtoValue::model<T>::copy(void const* self, void* dest) { | ||
new (dest) model(*static_cast<model const*>(self)); | ||
} | ||
|
||
template <typename T> | ||
void ProtoValue::model<T>::move(void* self, void* dest) { | ||
new (dest) model(std::move(*static_cast<model*>(self))); | ||
} | ||
|
||
template <typename T> | ||
void ProtoValue::model<T>::to_proto(void const* self, google::protobuf::Value* v) { | ||
viam::sdk::to_proto(static_cast<model const*>(self)->data, v); | ||
} | ||
|
||
template <typename T> | ||
int ProtoValue::model<T>::kind() noexcept { | ||
return kind_t<T>::value; | ||
} | ||
|
||
template <typename T> | ||
bool ProtoValue::model<T>::equal_to(void const* self, | ||
void const* other, | ||
const ProtoValue::vtable& other_vtable) { | ||
if (model::kind() != other_vtable.kind()) { | ||
return false; | ||
} | ||
|
||
return *static_cast<T const*>(self) == *static_cast<T const*>(other); | ||
} | ||
|
||
// --- ProtoT::storage definitions --- // | ||
template <typename T> | ||
ProtoValue::storage::storage(T t) noexcept(std::is_nothrow_move_constructible<T>{}) { | ||
static_assert(sizeof(T) <= local_storage_size, "Type too large to fit in local storage"); | ||
static_assert(alignof(T) <= local_storage_alignment, | ||
"Type alignment too strict for local storage"); | ||
|
||
static_assert(sizeof(std::vector<void*>) == sizeof(std::vector<ProtoValue>), | ||
"vector<ProtoValue> stand-in size mismatch"); | ||
static_assert(alignof(std::vector<void*>) == alignof(std::vector<ProtoValue>), | ||
"vector<ProtoValue> stand-in alignment mismatch"); | ||
|
||
static_assert(sizeof(std::unordered_map<std::string, void*>) == sizeof(ProtoStruct), | ||
"ProtoStruct stand-in size mismatch"); | ||
static_assert(alignof(std::unordered_map<std::string, void*>) == alignof(ProtoStruct), | ||
"ProtoStruct stand-in alignment mismatch"); | ||
|
||
new (&buf_) model<T>(std::move(t)); | ||
} | ||
|
||
ProtoValue::storage::storage(const ProtoValue::storage& other, const ProtoValue::vtable& vtab) { | ||
vtab.copy(other.get(), this->get()); | ||
} | ||
|
||
ProtoValue::storage::storage(ProtoValue::storage&& other, const ProtoValue::vtable& vtab) noexcept( | ||
proto_value_details::all_moves_noexcept{}) { | ||
vtab.move(other.get(), this->get()); | ||
} | ||
|
||
void ProtoValue::storage::swap( | ||
const ProtoValue::vtable& this_vtable, | ||
ProtoValue::storage& other, | ||
const ProtoValue::vtable& other_vtable) noexcept(proto_value_details::all_moves_noexcept{}) { | ||
if (this == &other) { | ||
return; | ||
} | ||
|
||
BufType tmp; | ||
other_vtable.move(other.get(), &tmp); | ||
other_vtable.dtor(other.get()); | ||
|
||
this_vtable.move(this->get(), other.get()); | ||
this_vtable.dtor(this->get()); | ||
|
||
other_vtable.move(&tmp, this->get()); | ||
other_vtable.dtor(&tmp); | ||
} | ||
|
||
void ProtoValue::storage::destruct(const ProtoValue::vtable& vtab) noexcept { | ||
vtab.dtor(this->get()); | ||
} | ||
|
||
void to_proto(std::nullptr_t, Value* v) { | ||
v->set_null_value(::google::protobuf::NULL_VALUE); | ||
} | ||
|
||
void to_proto(bool b, Value* v) { | ||
v->set_bool_value(b); | ||
} | ||
|
||
void to_proto(int i, Value* v) { | ||
v->set_number_value(i); | ||
} | ||
|
||
void to_proto(double d, Value* v) { | ||
v->set_number_value(d); | ||
} | ||
|
||
void to_proto(std::string s, Value* v) { | ||
v->set_string_value(std::move(s)); | ||
} | ||
|
||
void to_proto(const std::vector<ProtoValue>& vec, Value* v) { | ||
::google::protobuf::ListValue l; | ||
for (const auto& val : vec) { | ||
*l.add_values() = to_proto(val); | ||
} | ||
*(v->mutable_list_value()) = std::move(l); | ||
} | ||
|
||
void to_proto(const ProtoStruct& m, Value* v) { | ||
Struct s; | ||
map_to_struct(m, &s); | ||
|
||
*(v->mutable_struct_value()) = std::move(s); | ||
} | ||
|
||
void to_proto(const ProtoValue& t, Value* v) { | ||
t.vtable_.to_proto(t.self_.get(), v); | ||
} | ||
|
||
ProtoStruct struct_to_map(Struct const* s) { // NOLINT(misc-no-recursion) | ||
ProtoStruct map; | ||
for (const auto& val : s->fields()) { | ||
map.emplace(val.first, ProtoValue::from_proto(val.second)); | ||
} | ||
|
||
return map; | ||
} | ||
|
||
void map_to_struct(const ProtoStruct& m, Struct* s) { | ||
for (const auto& kv : m) { | ||
s->mutable_fields()->insert( | ||
google::protobuf::MapPair<std::string, Value>(kv.first, to_proto(kv.second))); | ||
} | ||
} | ||
|
||
} // namespace sdk | ||
} // namespace viam |
Oops, something went wrong.