yalantinglibs/include/ylt/struct_pack/trivial_view.hpp

106 lines
2.9 KiB
C++

/*
* Copyright (c) 2023, Alibaba Group Holding Limited;
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <cassert>
#include "reflection.hpp"
/*!
* \ingroup struct_pack
* \struct trivial_view
* \brief
* trivial_view<T> is a view for trivial struct. It's equals T in type system.
* It can decrease memory copy in proto initialization/deserialization
*
* For example:
*
* ```cpp
* struct Data {
* int x[10000],y[10000],z[10000];
* };
*
* struct Proto {
* std::string name;
* Data data;
* };
* void serialzie(std::string_view name, Data& data) {
* Proto proto={.name = name, .data = data};
* // heavy cost in initialization.
* auto buffer = struct_pack::serialize(proto);
* auto result = struct_pack::deserialize<Proto>(data);
* // memory copy in deserialization.
* assert(result->name == name && result->data == data);
* }
* ```
*
* The solution: use view type:
* ```cpp
* struct ProtoView {
* std::string_view name;
* struct_pack::trivial_view<Data> data;
* };
* void serialzie(std::string_view name, Data& data) {
* ProtoView proto={.name = name, .data = data};
* // zero-copy initialization.
* auto buffer = struct_pack::serialize(proto);
* auto result = struct_pack::deserialize<ProtoView>(data);
* // zero-copy deserialization.
* assert(result->name == name && result->data.get() == data);
* }
* ```
* trivial_view<T> has same memory as T. So it's legal to serialize T then
* deserialize to trivial_view<T>
* ```cpp
* void serialzie(Proto& proto) {
* auto buffer = struct_pack::serialize(proto);
* auto result = struct_pack::deserialize<ProtoView>(data);
* // zero-copy deserialization.
* assert(result->name == name && result->data.get() == data);
* }
* ```
*
*/
namespace struct_pack {
template <detail::trivial_serializable T>
struct trivial_view {
private:
const T* ref;
public:
trivial_view(const T* t) : ref(t){};
trivial_view(const T& t) : ref(&t){};
trivial_view(const trivial_view&) = default;
trivial_view(trivial_view&&) = default;
trivial_view() : ref(nullptr){};
trivial_view& operator=(const trivial_view&) = default;
trivial_view& operator=(trivial_view&&) = default;
using value_type = T;
const T& get() const {
assert(ref != nullptr);
return *ref;
}
const T* operator->() const {
assert(ref != nullptr);
return ref;
}
};
} // namespace struct_pack