/* * 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 #include #include #include namespace apache { namespace thrift { namespace detail { template < typename C, typename T = decltype(std::declval().push_back( std::declval()))> struct push_back_result { using type = T; }; template < typename C, typename T = decltype(std::declval().insert( std::declval()))> struct insert_key_result { using type = T; }; template < typename C, typename T = decltype(std::declval()[std::declval()])> struct subscript_key_result { using type = T; }; template < typename C, typename T = decltype(std::declval().reserve( std::declval()))> struct reserve_result { using type = T; }; template struct Reserver { static void reserve(C&, typename C::size_type) {} }; template struct Reserver::type>> { static void reserve(C& container, typename C::size_type size) { container.reserve(size); } }; template inline constexpr bool alloc_is_recursive = false; template inline constexpr bool alloc_is_recursive< Cont, Elem, folly:: void_t> = std::uses_allocator::value; template inline constexpr bool alloc_should_propagate = alloc_is_recursive && !std::uses_allocator>::value; template inline constexpr bool alloc_should_propagate_map = alloc_should_propagate || alloc_should_propagate; template std::enable_if_t< alloc_should_propagate, typename C::value_type> default_set_element(C& c) { return typename C::value_type(c.get_allocator()); } template std::enable_if_t< !alloc_should_propagate, typename C::value_type> default_set_element(C&) { return typename C::value_type{}; } template std::enable_if_t< alloc_should_propagate, typename Map::key_type> default_map_key(Map& m) { return typename Map::key_type(m.get_allocator()); } template std::enable_if_t< !alloc_should_propagate, typename Map::key_type> default_map_key(Map&) { return typename Map::key_type{}; } template std::enable_if_t< alloc_should_propagate, typename C::mapped_type> default_map_value(C& map) { return typename C::mapped_type(map.get_allocator()); } template std::enable_if_t< !alloc_should_propagate, typename C::mapped_type> default_map_value(C&) { return typename C::mapped_type{}; } } // namespace detail template <> class Cpp2Ops { public: typedef folly::fbstring Type; static constexpr protocol::TType thriftType() { return protocol::T_STRING; } template static uint32_t write(Protocol* prot, const Type* value) { return prot->writeString(*value); } template static void read(Protocol* prot, Type* value) { prot->readString(*value); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeString(*value); } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeString(*value); } }; template <> class Cpp2Ops { public: typedef std::string Type; static constexpr protocol::TType thriftType() { return protocol::T_STRING; } template static uint32_t write(Protocol* prot, const Type* value) { return prot->writeString(*value); } template static void read(Protocol* prot, Type* value) { prot->readString(*value); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeString(*value); } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeString(*value); } }; template <> class Cpp2Ops { public: typedef int8_t Type; static constexpr protocol::TType thriftType() { return protocol::T_BYTE; } template static uint32_t write(Protocol* prot, const Type* value) { return prot->writeByte(*value); } template static void read(Protocol* prot, Type* value) { prot->readByte(*value); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeByte(*value); } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeByte(*value); } }; template <> class Cpp2Ops { public: typedef int16_t Type; static constexpr protocol::TType thriftType() { return protocol::T_I16; } template static uint32_t write(Protocol* prot, const Type* value) { return prot->writeI16(*value); } template static void read(Protocol* prot, Type* value) { prot->readI16(*value); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeI16(*value); } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeI16(*value); } }; template <> class Cpp2Ops { public: typedef int32_t Type; static constexpr protocol::TType thriftType() { return protocol::T_I32; } template static uint32_t write(Protocol* prot, const Type* value) { return prot->writeI32(*value); } template static void read(Protocol* prot, Type* value) { prot->readI32(*value); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeI32(*value); } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeI32(*value); } }; template <> class Cpp2Ops { public: typedef int64_t Type; static constexpr protocol::TType thriftType() { return protocol::T_I64; } template static uint32_t write(Protocol* prot, const Type* value) { return prot->writeI64(*value); } template static void read(Protocol* prot, Type* value) { prot->readI64(*value); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeI64(*value); } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeI64(*value); } }; template <> class Cpp2Ops { public: using Type = uint8_t; using SignedType = std::make_signed_t; static constexpr protocol::TType thriftType() { return protocol::T_BYTE; } template static uint32_t write(Protocol* prot, const Type* value) { return prot->writeByte(folly::to_signed(*value)); } template static void read(Protocol* prot, Type* value) { SignedType signedValue; prot->readByte(signedValue); *value = folly::to_unsigned(signedValue); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeByte(folly::to_signed(*value)); } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeByte(folly::to_signed(*value)); } }; template <> class Cpp2Ops { public: using Type = uint16_t; using SignedType = std::make_signed_t; static constexpr protocol::TType thriftType() { return protocol::T_I16; } template static uint32_t write(Protocol* prot, const Type* value) { return prot->writeI16(folly::to_signed(*value)); } template static void read(Protocol* prot, Type* value) { SignedType signedValue; prot->readI16(signedValue); *value = folly::to_unsigned(signedValue); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeI16(folly::to_signed(*value)); } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeI16(folly::to_signed(*value)); } }; template <> class Cpp2Ops { public: using Type = uint32_t; using SignedType = std::make_signed_t; static constexpr protocol::TType thriftType() { return protocol::T_I32; } template static uint32_t write(Protocol* prot, const Type* value) { return prot->writeI32(folly::to_signed(*value)); } template static void read(Protocol* prot, Type* value) { SignedType signedValue; prot->readI32(signedValue); *value = folly::to_unsigned(signedValue); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeI32(folly::to_signed(*value)); } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeI32(folly::to_signed(*value)); } }; template <> class Cpp2Ops { public: using Type = uint64_t; using SignedType = std::make_signed_t; static constexpr protocol::TType thriftType() { return protocol::T_I64; } template static uint32_t write(Protocol* prot, const Type* value) { return prot->writeI64(folly::to_signed(*value)); } template static void read(Protocol* prot, Type* value) { SignedType signedValue; prot->readI64(signedValue); *value = folly::to_unsigned(signedValue); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeI64(folly::to_signed(*value)); } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeI64(folly::to_signed(*value)); } }; template <> class Cpp2Ops { public: typedef bool Type; static constexpr protocol::TType thriftType() { return protocol::T_BOOL; } template static uint32_t write(Protocol* prot, const Type* value) { return prot->writeBool(*value); } template static void read(Protocol* prot, Type* value) { prot->readBool(*value); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeBool(*value); } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeBool(*value); } }; template <> class Cpp2Ops { public: typedef double Type; static constexpr protocol::TType thriftType() { return protocol::T_DOUBLE; } template static uint32_t write(Protocol* prot, const Type* value) { return prot->writeDouble(*value); } template static void read(Protocol* prot, Type* value) { prot->readDouble(*value); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeDouble(*value); } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeDouble(*value); } }; template class Cpp2Ops::value>::type> { public: typedef E Type; static constexpr protocol::TType thriftType() { return protocol::T_I32; } template static uint32_t write(Protocol* prot, const Type* value) { return prot->writeI32(static_cast(*value)); } template static void read(Protocol* prot, Type* value) { int32_t val; prot->readI32(val); *value = static_cast(val); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeI32(static_cast(*value)); } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeI32(static_cast(*value)); } }; template <> class Cpp2Ops { public: typedef float Type; static constexpr protocol::TType thriftType() { return protocol::T_FLOAT; } template static uint32_t write(Protocol* prot, const Type* value) { return prot->writeFloat(*value); } template static void read(Protocol* prot, Type* value) { prot->readFloat(*value); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeFloat(*value); } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeFloat(*value); } }; namespace detail { template void readIntoVector(Protocol* prot, V& vec) { typedef typename V::value_type ElemType; for (auto& e : vec) { Cpp2Ops::read(prot, &e); } } template void readIntoVector(Protocol* prot, std::vector& 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::read(prot, &b); e = b; } } } // namespace detail template class Cpp2Ops< L, folly::void_t::type>> { private: // Need a resize func instead of c.resize(size, defaultElement(C)), because // some non-standard vectors do not support resize(size_type, T value = T()). template std::enable_if_t< detail::alloc_should_propagate, void> static resize(C& c, uint32_t size) { c.resize(size, typename C::value_type(c.get_allocator())); } template std::enable_if_t< !detail::alloc_should_propagate, void> static resize(C& c, uint32_t size) { c.resize(size); } public: typedef L Type; static constexpr protocol::TType thriftType() { return protocol::T_LIST; } template static uint32_t write(Protocol* prot, const Type* value) { typedef typename Type::value_type ElemType; uint32_t xfer = 0; xfer += prot->writeListBegin( Cpp2Ops::thriftType(), folly::to_narrow(value->size())); for (const auto& e : *value) { xfer += Cpp2Ops::write(prot, &e); } xfer += prot->writeListEnd(); return xfer; } template static void read(Protocol* prot, Type* value) { value->clear(); uint32_t size; protocol::TType etype; prot->readListBegin(etype, size); resize(*value, size); apache::thrift::detail::readIntoVector(prot, *value); prot->readListEnd(); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { typedef typename Type::value_type ElemType; uint32_t xfer = 0; xfer += prot->serializedSizeListBegin( Cpp2Ops::thriftType(), value->size()); for (const auto& e : *value) { xfer += Cpp2Ops::serializedSize(prot, &e); } xfer += prot->serializedSizeListEnd(); return xfer; } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { typedef typename Type::value_type ElemType; uint32_t xfer = 0; xfer += prot->serializedSizeListBegin( Cpp2Ops::thriftType(), folly::to_narrow(value->size())); for (const auto& e : *value) { xfer += Cpp2Ops::serializedSizeZC(prot, &e); } xfer += prot->serializedSizeListEnd(); return xfer; } }; template class Cpp2Ops< S, folly::void_t< typename apache::thrift::detail::insert_key_result::type>> { private: template std::enable_if_t< detail::alloc_should_propagate, typename C::key_type> static defaultElement(C& c) { return typename C::key_type(c.get_allocator()); } template std::enable_if_t< !detail::alloc_should_propagate, typename C::key_type> static defaultElement(C&) { return typename C::key_type{}; } public: typedef S Type; static constexpr protocol::TType thriftType() { return protocol::T_SET; } template static uint32_t write(Protocol* prot, const Type* value) { typedef typename Type::key_type ElemType; uint32_t xfer = 0; xfer += prot->writeSetBegin(Cpp2Ops::thriftType(), value->size()); for (const auto& e : *value) { xfer += Cpp2Ops::write(prot, &e); } xfer += prot->writeSetEnd(); return xfer; } template 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::reserve(*value, size); for (uint32_t i = 0; i < size; i++) { ElemType elem = defaultElement(*value); Cpp2Ops::read(prot, &elem); value->insert(std::move(elem)); } prot->readSetEnd(); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { typedef typename Type::key_type ElemType; uint32_t xfer = 0; xfer += prot->serializedSizeSetBegin( Cpp2Ops::thriftType(), value->size()); for (const auto& e : *value) { xfer += Cpp2Ops::serializedSize(prot, &e); } xfer += prot->serializedSizeSetEnd(); return xfer; } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { typedef typename Type::key_type ElemType; uint32_t xfer = 0; xfer += prot->serializedSizeSetBegin( Cpp2Ops::thriftType(), value->size()); for (const auto& e : *value) { xfer += Cpp2Ops::serializedSizeZC(prot, &e); } xfer += prot->serializedSizeSetEnd(); return xfer; } }; template class Cpp2Ops< M, folly::void_t< typename apache::thrift::detail::subscript_key_result::type>> { private: template std::enable_if_t< detail::alloc_should_propagate_map, ValueType&> static emplaceKey(Map& m, typename Map::key_type&& key) { return m.emplace(std::move(key), detail::default_map_value(m)) .first->second; } template std::enable_if_t< !detail::alloc_should_propagate_map, ValueType&> static emplaceKey(Map& m, typename Map::key_type&& key) { return m[std::move(key)]; } public: typedef M Type; static constexpr protocol::TType thriftType() { return protocol::T_MAP; } template static uint32_t write(Protocol* prot, const Type* value) { typedef typename Type::key_type KeyType; typedef typename std::remove_cv< typename std::remove_referencebegin())>::type>::type PairType; typedef typename PairType::second_type ValueType; uint32_t xfer = 0; xfer += prot->writeMapBegin( Cpp2Ops::thriftType(), Cpp2Ops::thriftType(), value->size()); for (const auto& e : *value) { xfer += Cpp2Ops::write(prot, &e.first); xfer += Cpp2Ops::write(prot, &e.second); } xfer += prot->writeMapEnd(); return xfer; } template 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_referencebegin())>::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::reserve(*value, size); for (uint32_t i = 0; i < size; i++) { KeyType key = detail::default_map_key(*value); Cpp2Ops::read(prot, &key); ValueType& val = emplaceKey(*value, std::move(key)); Cpp2Ops::read(prot, &val); } prot->readMapEnd(); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { typedef typename Type::key_type KeyType; typedef typename std::remove_cv< typename std::remove_referencebegin())>::type>::type PairType; typedef typename PairType::second_type ValueType; uint32_t xfer = 0; xfer += prot->serializedSizeMapBegin( Cpp2Ops::thriftType(), Cpp2Ops::thriftType(), value->size()); for (const auto& e : *value) { xfer += Cpp2Ops::serializedSize(prot, &e.first); xfer += Cpp2Ops::serializedSize(prot, &e.second); } xfer += prot->serializedSizeMapEnd(); return xfer; } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { typedef typename Type::key_type KeyType; typedef typename std::remove_cv< typename std::remove_referencebegin())>::type>::type PairType; typedef typename PairType::second_type ValueType; uint32_t xfer = 0; xfer += prot->serializedSizeMapBegin( Cpp2Ops::thriftType(), Cpp2Ops::thriftType(), value->size()); for (const auto& e : *value) { xfer += Cpp2Ops::serializedSizeZC(prot, &e.first); xfer += Cpp2Ops::serializedSizeZC(prot, &e.second); } xfer += prot->serializedSizeMapEnd(); return xfer; } }; template <> class Cpp2Ops { public: typedef folly::IOBuf Type; static constexpr protocol::TType thriftType() { return protocol::T_STRING; } template static uint32_t write(Protocol* prot, const Type* value) { return prot->writeBinary(*value); } template static void read(Protocol* prot, Type* value) { prot->readBinary(*value); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeBinary(*value); } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeZCBinary(*value); } }; template <> class Cpp2Ops> { public: typedef std::unique_ptr Type; static constexpr protocol::TType thriftType() { return protocol::T_STRING; } template static uint32_t write(Protocol* prot, const Type* value) { return prot->writeBinary(*value); } template static void read(Protocol* prot, Type* value) { prot->readBinary(*value); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { return prot->serializedSizeBinary(*value); } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return prot->serializedSizeZCBinary(*value); } }; template class Cpp2Ops< T, std::enable_if_t< is_thrift_class_v && !folly::is_detected_v>> { public: typedef T Type; static constexpr protocol::TType thriftType() { return protocol::T_STRUCT; } template static uint32_t write(Protocol* prot, const Type* value) { return value->write(prot); } template static void read(Protocol* prot, Type* value) { value->readNoXfer(prot); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { return value->serializedSize(prot); } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return value->serializedSizeZC(prot); } }; template class Cpp2Ops< T, std::enable_if_t>> { private: using S = folly::remove_cvref_t< folly::invoke_result_t>; public: using Type = T; static constexpr protocol::TType thriftType() { return Cpp2Ops::thriftType(); } template static uint32_t write(Protocol* prot, const Type* value) { return Cpp2Ops::write(prot, &apply_indirection(*value)); } template static void read(Protocol* prot, Type* value) { return Cpp2Ops::read(prot, &apply_indirection(*value)); } template static uint32_t serializedSize(Protocol* prot, const Type* value) { return Cpp2Ops::serializedSize(prot, &apply_indirection(*value)); } template static uint32_t serializedSizeZC(Protocol* prot, const Type* value) { return Cpp2Ops::serializedSizeZC(prot, &apply_indirection(*value)); } }; } // namespace thrift } // namespace apache