/* * 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 #include #include #include #include #include #include namespace apache { namespace thrift { namespace op { namespace detail { template > struct StructuredOp : BaseOp { using NameList = std::array>; using size_type = typename NameList::size_type; using Base = BaseOp; using Base::check_found; using Base::ref; using Base::ret; using Base::unimplemented; template using FTag = op::get_field_tag; template static bool putIf(bool cond, T& self, const Dyn& val) { if (cond) { if (!val.has_value()) { op::clear_field>(op::get(self), self); } else { op::get(self) = val.as>(); } } return cond; } static bool put(void* s, FieldId fid, size_t, const Dyn& n, const Dyn& val) { // TODO(afuller): Use a hash map lookups for these. if (n != nullptr) { const auto& name = n.as(); check_found(find_by_field_id([&](auto id) { using Id = decltype(id); return putIf(op::get_name_v == name, ref(s), val); })); } else { check_found(find_by_field_id([&](auto id) { return putIf(id() == fid, ref(s), val); })); } return true; } template static bool getIf(bool cond, T& self, Ptr& result) { auto&& field = op::get(self); if (cond && !isAbsent(field)) { result = ret(op::get_type_tag{}, *field); } return cond; } static Ptr get(void* s, FieldId fid, size_t, const Dyn& n) { Ptr result; // TODO(afuller): Use a hash map for these lookups. if (n != nullptr) { // Get by name. const auto& name = n.as(); check_found(find_by_field_id([&](auto id) { using Id = decltype(id); return getIf(op::get_name_v == name, ref(s), result); })); } else { // Get by field id. check_found(find_by_field_id([&](auto id) { return getIf(id() == fid, ref(s), result); })); } return result; } static Ptr getByName(void* s, const std::string& name) { return get(s, FieldId{0}, 0, ret(type::string_t{}, name)); } static size_type& pos(std::any& i) { if (!i.has_value()) { i = size_type{}; } return std::any_cast(i); } static Ptr next(T& self, IterType type, size_type& itr) { if (itr == op::size_v) { return {}; } static const NameList& kNames = *([]() { auto result = std::make_unique(); op::for_each_ordinal([&](auto ord) { (*result)[type::toPosition(ord)] = op::get_name_v; }); return result.release(); })(); const std::string& name = kNames[itr++]; switch (type) { case IterType::Key: return ret(type::string_t{}, name); case IterType::Value: return getByName(&self, name); case IterType::Default: unimplemented(); } } static Ptr next(void* s, IterType type, std::any& i) { if (type == IterType::Default) { unimplemented(); // TODO(afuller): Key-value pair? } return next(ref(s), type, pos(i)); } template static bool ensureIf(bool cond, T& self, const Dyn& val, Ptr& result) { if (cond) { auto&& field = op::get(self); if (isAbsent(field)) { if (val != nullptr) { *field = val.as>(); } else { ensureValue(field); } } result = ret(get_type_tag{}, *field); } return cond; } static Ptr ensure(void* s, FieldId fid, const Dyn& n, const Dyn& val) { // TODO(afuller): Use a hash map for these lookups. Ptr result; if (n != nullptr) { // Ensure by name. const auto& name = n.as(); check_found(find_by_field_id([&](auto id) { using Id = decltype(id); return ensureIf(op::get_name_v == name, ref(s), val, result); })); } else { // Ensure by field id. check_found(find_by_field_id([&](auto id) { return ensureIf(id() == fid, ref(s), val, result); })); } return result; } static size_t size(const void*) { return op::size_v; } }; template struct AnyOp> : StructuredOp {}; } // namespace detail } // namespace op } // namespace thrift } // namespace apache