thrift/lib/cpp2/protocol/Cpp2Ops-inl.h (687 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * 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 <thrift/lib/cpp2/protocol/Cpp2Ops.h> #include <type_traits> #include <folly/Traits.h> #include <folly/Utility.h> #include <folly/io/IOBuf.h> namespace apache { namespace thrift { namespace detail { template < typename C, typename T = decltype(std::declval<C&>().push_back( std::declval<typename C::value_type>()))> struct push_back_result { using type = T; }; template < typename C, typename T = decltype(std::declval<C&>().insert( std::declval<typename C::key_type>()))> struct insert_key_result { using type = T; }; template < typename C, typename T = decltype(std::declval<C&>()[std::declval<typename C::key_type>()])> struct subscript_key_result { using type = T; }; template < typename C, typename T = decltype(std::declval<C&>().reserve( std::declval<typename C::size_type>()))> struct reserve_result { using type = T; }; template <typename C, typename = void> struct Reserver { static void reserve(C&, typename C::size_type) {} }; template <typename C> struct Reserver<C, folly::void_t<typename reserve_result<C>::type>> { static void reserve(C& container, typename C::size_type size) { container.reserve(size); } }; } // namespace detail template <> class Cpp2Ops<folly::fbstring> { public: typedef folly::fbstring Type; static constexpr protocol::TType thriftType() { return protocol::T_STRING; } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { return prot->writeString(*value); } template <class Protocol> static void read(Protocol* prot, Type* value) { prot->readString(*value); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeString(*value); } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeString(*value); } }; template <> class Cpp2Ops<std::string> { public: typedef std::string Type; static constexpr protocol::TType thriftType() { return protocol::T_STRING; } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { return prot->writeString(*value); } template <class Protocol> static void read(Protocol* prot, Type* value) { prot->readString(*value); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeString(*value); } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeString(*value); } }; template <> class Cpp2Ops<int8_t> { public: typedef int8_t Type; static constexpr protocol::TType thriftType() { return protocol::T_BYTE; } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { return prot->writeByte(*value); } template <class Protocol> static void read(Protocol* prot, Type* value) { prot->readByte(*value); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeByte(*value); } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeByte(*value); } }; template <> class Cpp2Ops<int16_t> { public: typedef int16_t Type; static constexpr protocol::TType thriftType() { return protocol::T_I16; } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { return prot->writeI16(*value); } template <class Protocol> static void read(Protocol* prot, Type* value) { prot->readI16(*value); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeI16(*value); } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeI16(*value); } }; template <> class Cpp2Ops<int32_t> { public: typedef int32_t Type; static constexpr protocol::TType thriftType() { return protocol::T_I32; } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { return prot->writeI32(*value); } template <class Protocol> static void read(Protocol* prot, Type* value) { prot->readI32(*value); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeI32(*value); } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeI32(*value); } }; template <> class Cpp2Ops<int64_t> { public: typedef int64_t Type; static constexpr protocol::TType thriftType() { return protocol::T_I64; } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { return prot->writeI64(*value); } template <class Protocol> static void read(Protocol* prot, Type* value) { prot->readI64(*value); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeI64(*value); } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeI64(*value); } }; template <> class Cpp2Ops<uint8_t> { public: using Type = uint8_t; using SignedType = std::make_signed_t<Type>; static constexpr protocol::TType thriftType() { return protocol::T_BYTE; } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { return prot->writeByte(folly::to_signed(*value)); } template <class Protocol> static void read(Protocol* prot, Type* value) { SignedType signedValue; prot->readByte(signedValue); *value = folly::to_unsigned(signedValue); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeByte(folly::to_signed(*value)); } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeByte(folly::to_signed(*value)); } }; template <> class Cpp2Ops<uint16_t> { public: using Type = uint16_t; using SignedType = std::make_signed_t<Type>; static constexpr protocol::TType thriftType() { return protocol::T_I16; } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { return prot->writeI16(folly::to_signed(*value)); } template <class Protocol> static void read(Protocol* prot, Type* value) { SignedType signedValue; prot->readI16(signedValue); *value = folly::to_unsigned(signedValue); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeI16(folly::to_signed(*value)); } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeI16(folly::to_signed(*value)); } }; template <> class Cpp2Ops<uint32_t> { public: using Type = uint32_t; using SignedType = std::make_signed_t<Type>; static constexpr protocol::TType thriftType() { return protocol::T_I32; } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { return prot->writeI32(folly::to_signed(*value)); } template <class Protocol> static void read(Protocol* prot, Type* value) { SignedType signedValue; prot->readI32(signedValue); *value = folly::to_unsigned(signedValue); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeI32(folly::to_signed(*value)); } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeI32(folly::to_signed(*value)); } }; template <> class Cpp2Ops<uint64_t> { public: using Type = uint64_t; using SignedType = std::make_signed_t<Type>; static constexpr protocol::TType thriftType() { return protocol::T_I64; } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { return prot->writeI64(folly::to_signed(*value)); } template <class Protocol> static void read(Protocol* prot, Type* value) { SignedType signedValue; prot->readI64(signedValue); *value = folly::to_unsigned(signedValue); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeI64(folly::to_signed(*value)); } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeI64(folly::to_signed(*value)); } }; template <> class Cpp2Ops<bool> { public: typedef bool Type; static constexpr protocol::TType thriftType() { return protocol::T_BOOL; } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { return prot->writeBool(*value); } template <class Protocol> static void read(Protocol* prot, Type* value) { prot->readBool(*value); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeBool(*value); } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeBool(*value); } }; template <> class Cpp2Ops<double> { public: typedef double Type; static constexpr protocol::TType thriftType() { return protocol::T_DOUBLE; } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { return prot->writeDouble(*value); } template <class Protocol> static void read(Protocol* prot, Type* value) { prot->readDouble(*value); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeDouble(*value); } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeDouble(*value); } }; template <class E> class Cpp2Ops<E, typename std::enable_if<std::is_enum<E>::value>::type> { public: typedef E Type; static constexpr protocol::TType thriftType() { return protocol::T_I32; } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { return prot->writeI32(static_cast<int32_t>(*value)); } template <class Protocol> static void read(Protocol* prot, Type* value) { int32_t val; prot->readI32(val); *value = static_cast<Type>(val); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeI32(static_cast<int32_t>(*value)); } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeI32(static_cast<int32_t>(*value)); } }; template <> class Cpp2Ops<float> { public: typedef float Type; static constexpr protocol::TType thriftType() { return protocol::T_FLOAT; } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { return prot->writeFloat(*value); } template <class Protocol> static void read(Protocol* prot, Type* value) { prot->readFloat(*value); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeFloat(*value); } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeFloat(*value); } }; namespace detail { template <class Protocol, class V> void readIntoVector(Protocol* prot, V& vec) { typedef typename V::value_type ElemType; for (auto& e : vec) { Cpp2Ops<ElemType>::read(prot, &e); } } template <class Protocol> void readIntoVector(Protocol* prot, std::vector<bool>& vec) { for (auto e : vec) { // e is a proxy object because the elements don't have distinct addresses // (packed into a bitvector). We actually copy the proxy during iteration // (can't use non-const reference because iteration returns by value, can't // use const reference because we modify it), but it still points to the // actual element. bool b; Cpp2Ops<bool>::read(prot, &b); e = b; } } } // namespace detail template <class L> class Cpp2Ops< L, folly::void_t<typename apache::thrift::detail::push_back_result<L>::type>> { public: typedef L Type; static constexpr protocol::TType thriftType() { return protocol::T_LIST; } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { typedef typename Type::value_type ElemType; uint32_t xfer = 0; xfer += prot->writeListBegin( Cpp2Ops<ElemType>::thriftType(), folly::to_narrow(value->size())); for (const auto& e : *value) { xfer += Cpp2Ops<ElemType>::write(prot, &e); } xfer += prot->writeListEnd(); return xfer; } template <class Protocol> static void read(Protocol* prot, Type* value) { value->clear(); uint32_t size; protocol::TType etype; prot->readListBegin(etype, size); value->resize(size); apache::thrift::detail::readIntoVector(prot, *value); prot->readListEnd(); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { typedef typename Type::value_type ElemType; uint32_t xfer = 0; xfer += prot->serializedSizeListBegin( Cpp2Ops<ElemType>::thriftType(), value->size()); for (const auto& e : *value) { xfer += Cpp2Ops<ElemType>::serializedSize(prot, &e); } xfer += prot->serializedSizeListEnd(); return xfer; } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { typedef typename Type::value_type ElemType; uint32_t xfer = 0; xfer += prot->serializedSizeListBegin( Cpp2Ops<ElemType>::thriftType(), folly::to_narrow(value->size())); for (const auto& e : *value) { xfer += Cpp2Ops<ElemType>::serializedSizeZC(prot, &e); } xfer += prot->serializedSizeListEnd(); return xfer; } }; template <class S> class Cpp2Ops< S, folly::void_t< typename apache::thrift::detail::insert_key_result<S>::type>> { public: typedef S Type; static constexpr protocol::TType thriftType() { return protocol::T_SET; } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { typedef typename Type::key_type ElemType; uint32_t xfer = 0; xfer += prot->writeSetBegin(Cpp2Ops<ElemType>::thriftType(), value->size()); for (const auto& e : *value) { xfer += Cpp2Ops<ElemType>::write(prot, &e); } xfer += prot->writeSetEnd(); return xfer; } template <class Protocol> static void read(Protocol* prot, Type* value) { typedef typename Type::key_type ElemType; value->clear(); uint32_t size; protocol::TType etype; prot->readSetBegin(etype, size); apache::thrift::detail::Reserver<Type>::reserve(*value, size); for (uint32_t i = 0; i < size; i++) { ElemType elem; Cpp2Ops<ElemType>::read(prot, &elem); value->insert(std::move(elem)); } prot->readSetEnd(); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { typedef typename Type::key_type ElemType; uint32_t xfer = 0; xfer += prot->serializedSizeSetBegin( Cpp2Ops<ElemType>::thriftType(), value->size()); for (const auto& e : *value) { xfer += Cpp2Ops<ElemType>::serializedSize(prot, &e); } xfer += prot->serializedSizeSetEnd(); return xfer; } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { typedef typename Type::key_type ElemType; uint32_t xfer = 0; xfer += prot->serializedSizeSetBegin( Cpp2Ops<ElemType>::thriftType(), value->size()); for (const auto& e : *value) { xfer += Cpp2Ops<ElemType>::serializedSizeZC(prot, &e); } xfer += prot->serializedSizeSetEnd(); return xfer; } }; template <class M> class Cpp2Ops< M, folly::void_t< typename apache::thrift::detail::subscript_key_result<M>::type>> { public: typedef M Type; static constexpr protocol::TType thriftType() { return protocol::T_MAP; } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { typedef typename Type::key_type KeyType; typedef typename std::remove_cv< typename std::remove_reference<decltype(*value->begin())>::type>::type PairType; typedef typename PairType::second_type ValueType; uint32_t xfer = 0; xfer += prot->writeMapBegin( Cpp2Ops<KeyType>::thriftType(), Cpp2Ops<ValueType>::thriftType(), value->size()); for (const auto& e : *value) { xfer += Cpp2Ops<KeyType>::write(prot, &e.first); xfer += Cpp2Ops<ValueType>::write(prot, &e.second); } xfer += prot->writeMapEnd(); return xfer; } template <class Protocol> static void read(Protocol* prot, Type* value) { typedef typename Type::key_type KeyType; // We do this dance with decltype rather than just using Type::mapped_type // because different map implementations (such as Google's dense_hash_map) // call it data_type. typedef typename std::remove_cv< typename std::remove_reference<decltype(*value->begin())>::type>::type PairType; typedef typename PairType::second_type ValueType; value->clear(); uint32_t size; protocol::TType keytype, valuetype; prot->readMapBegin(keytype, valuetype, size); apache::thrift::detail::Reserver<Type>::reserve(*value, size); for (uint32_t i = 0; i < size; i++) { KeyType key; Cpp2Ops<KeyType>::read(prot, &key); auto& val = (*value)[std::move(key)]; Cpp2Ops<ValueType>::read(prot, &val); } prot->readMapEnd(); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { typedef typename Type::key_type KeyType; typedef typename std::remove_cv< typename std::remove_reference<decltype(*value->begin())>::type>::type PairType; typedef typename PairType::second_type ValueType; uint32_t xfer = 0; xfer += prot->serializedSizeMapBegin( Cpp2Ops<KeyType>::thriftType(), Cpp2Ops<ValueType>::thriftType(), value->size()); for (const auto& e : *value) { xfer += Cpp2Ops<KeyType>::serializedSize(prot, &e.first); xfer += Cpp2Ops<ValueType>::serializedSize(prot, &e.second); } xfer += prot->serializedSizeMapEnd(); return xfer; } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { typedef typename Type::key_type KeyType; typedef typename std::remove_cv< typename std::remove_reference<decltype(*value->begin())>::type>::type PairType; typedef typename PairType::second_type ValueType; uint32_t xfer = 0; xfer += prot->serializedSizeMapBegin( Cpp2Ops<KeyType>::thriftType(), Cpp2Ops<ValueType>::thriftType(), value->size()); for (const auto& e : *value) { xfer += Cpp2Ops<KeyType>::serializedSizeZC(prot, &e.first); xfer += Cpp2Ops<ValueType>::serializedSizeZC(prot, &e.second); } xfer += prot->serializedSizeMapEnd(); return xfer; } }; template <> class Cpp2Ops<folly::IOBuf> { public: typedef folly::IOBuf Type; static constexpr protocol::TType thriftType() { return protocol::T_STRING; } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { return prot->writeBinary(*value); } template <class Protocol> static void read(Protocol* prot, Type* value) { prot->readBinary(*value); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeBinary(*value); } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeZCBinary(*value); } }; template <> class Cpp2Ops<std::unique_ptr<folly::IOBuf>> { public: typedef std::unique_ptr<folly::IOBuf> Type; static constexpr protocol::TType thriftType() { return protocol::T_STRING; } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { return prot->writeBinary(*value); } template <class Protocol> static void read(Protocol* prot, Type* value) { prot->readBinary(*value); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeBinary(*value); } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeZCBinary(*value); } }; template <class T> class Cpp2Ops< T, std::enable_if_t< is_thrift_class_v<T> && !folly::is_detected_v<detect_indirection_fn_t, T>>> { public: typedef T Type; static constexpr protocol::TType thriftType() { return protocol::T_STRUCT; } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { return value->write(prot); } template <class Protocol> static void read(Protocol* prot, Type* value) { value->readNoXfer(prot); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { return value->serializedSize(prot); } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return value->serializedSizeZC(prot); } }; template <class T> class Cpp2Ops< T, std::enable_if_t<folly::is_detected_v<detect_indirection_fn_t, T>>> { private: using S = folly::remove_cvref_t< folly::invoke_result_t<detail::apply_indirection_fn, T>>; public: using Type = T; static constexpr protocol::TType thriftType() { return Cpp2Ops<S>::thriftType(); } template <class Protocol> static uint32_t write(Protocol* prot, const Type* value) { return Cpp2Ops<S>::write(prot, &apply_indirection(*value)); } template <class Protocol> static void read(Protocol* prot, Type* value) { return Cpp2Ops<S>::read(prot, &apply_indirection(*value)); } template <class Protocol> static uint32_t serializedSize(Protocol* prot, const Type* value) { return Cpp2Ops<S>::serializedSize(prot, &apply_indirection(*value)); } template <class Protocol> static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return Cpp2Ops<S>::serializedSizeZC(prot, &apply_indirection(*value)); } }; } // namespace thrift } // namespace apache