/* * 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 namespace apache { namespace thrift { namespace op { namespace detail { template struct ContainerOp : BaseOp { using T = type::native_type; using I = typename T::iterator; using Base = BaseOp; using Base::check_found; using Base::ref; using Base::ret; static size_t size(const void* s) { return ref(s).size(); } static auto find(T& self, size_t pos) { check_found(pos < self.size()); auto itr = self.begin(); std::advance(itr, pos); return itr; } // Get or begin iterator. static I& iter(T& self, std::any& i) { if (!i.has_value()) { i = self.begin(); } return std::any_cast(i); } template static Ptr next(ITag tag, T& self, std::any& i) { auto& itr = iter(self, i); if (itr != self.end()) { return ret(tag, *itr++); } return {}; } }; template > struct ListOp : ContainerOp { using T = type::native_type; using Base = ContainerOp; using Base::check_found; using Base::check_op; using Base::find; using Base::next; using Base::ref; using Base::ret; using Base::unimplemented; template > static void prepend(T& self, V&& val) { self.insert(self.begin(), std::forward(val)); } static void prepend(void* s, const Dyn& v) { prepend(ref(s), v.as()); } template > static void append(T& self, V&& val) { self.push_back(std::forward(val)); } static void append(void* s, const Dyn& v) { append(ref(s), v.as()); } template > [[noreturn]] static bool add(T&, V&&) { unimplemented(); // TODO(afuller): Add if not already present. } static bool add(void* s, const Dyn& v) { return add(ref(s), v.as()); } static bool put(void* s, FieldId, size_t pos, const Dyn&, const Dyn& v) { check_op(pos != std::string::npos); if (v == nullptr) { // Remove. ref(s).erase(find(ref(s), pos)); } else { // Insert. check_found(pos <= ref(s).size()); // Allow end(). auto itr = ref(s).begin(); std::advance(itr, pos); ref(s).insert(itr, v.as()); } return true; } template static decltype(auto) get(U&& self, size_t pos) { return folly::forward_like(self.at(pos)); } static Ptr get(void* s, FieldId, size_t pos, const Dyn&) { check_op(pos != std::string::npos); return ret(VTag{}, *find(ref(s), pos)); } static Ptr next(void* s, IterType t, std::any& i) { check_op(t != IterType::Key); return next(VTag{}, ref(s), i); } }; template struct AnyOp> : ListOp {}; template struct AnyOp>> : ListOp>> {}; template > struct SetOp : ContainerOp { using T = type::native_type; using Base = ContainerOp; using Base::check_op; using Base::find; using Base::next; using Base::ref; using Base::ret; using Base::unimplemented; template > static bool add(T& self, K&& key) { return self.insert(std::forward(key)).second; } static bool add(void* s, const Dyn& k) { return add(ref(s), k.as()); } static Ptr get(void* s, FieldId, size_t, const Dyn& k) { check_op(k != nullptr); auto itr = ref(s).find(k.as()); if (itr != ref(s).end()) { return ret(KTag{}, *itr); } return {}; } static bool put(void* s, FieldId, size_t, const Dyn& k, const Dyn& v) { check_op(k != nullptr); check_op(v == nullptr); return ref(s).erase(k.as()); } static Ptr next(void* s, IterType t, std::any& i) { check_op(t != IterType::Value); return next(KTag{}, ref(s), i); } }; template struct AnyOp> : SetOp {}; template > struct MapOp : ContainerOp { using T = type::native_type; using K = type::native_type; using V = type::native_type; using Base = ContainerOp; using Base::bad_op; using Base::check_op; using Base::iter; using Base::ref; using Base::ret; using Base::unimplemented; template static bool put(T& self, J&& key, U&& val) { auto itr = self.find(key); if (itr == self.end()) { self.emplace(std::forward(key), std::forward(val)); return false; // new entry.` } itr->second = std::forward(val); return true; // replacing existing. } template static V& ensure(T& self, J&& key, U&& val) { auto itr = self.find(key); if (itr == self.end()) { itr = self.emplace(std::forward(key), std::forward(val)).first; } return itr->second; } static bool put(void* s, FieldId, size_t, const Dyn& k, const Dyn& v) { check_op(k != nullptr); if (v == nullptr) { // Remove return ref(s).erase(k.as()); } return put(ref(s), k.as(), v.as()); } static Ptr ensure(void* s, FieldId, const Dyn& k, const Dyn& v) { check_op(k != nullptr); if (v == nullptr) { return ret(VTag{}, ensure(ref(s), k.as(), V{})); } else { return ret(VTag{}, ensure(ref(s), k.as(), v.as())); } } static Ptr get(void* s, FieldId, size_t, const Dyn& k) { check_op(k != nullptr); auto itr = ref(s).find(k.as()); if (itr != ref(s).end()) { return ret(VTag{}, itr->second); } return {}; } static Ptr next(T& self, IterType type, typename T::iterator& itr) { if (itr == self.end()) { return {}; } auto& entry = *itr++; switch (type) { case IterType::Key: return ret(KTag{}, entry.first); case IterType::Value: return ret(VTag{}, entry.second); 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, iter(ref(s), i)); } }; template struct AnyOp> : MapOp {}; template struct AnyOp>> : MapOp>> {}; } // namespace detail } // namespace op } // namespace thrift } // namespace apache