/* * Copyright 2011-present Facebook, Inc. * * 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 namespace folly { namespace detail { struct DynamicHasher { using is_transparent = void; size_t operator()(dynamic const& d) const { return d.hash(); } template std::enable_if_t::value, size_t> operator()(T const& val) const { // keep consistent with dynamic::hash() for strings return Hash()(static_cast(val)); } }; struct DynamicKeyEqual { using is_transparent = void; bool operator()(const dynamic& lhs, const dynamic& rhs) const { return std::equal_to()(lhs, rhs); } // Dynamic objects contains a map. At least one of the // operands should be a dynamic. Hence, an operator() where both operands are // convertible to StringPiece is unnecessary. template std::enable_if_t< std::is_convertible::value && std::is_convertible::value, bool> operator()(A const& lhs, B const& rhs) const = delete; template std::enable_if_t::value, bool> operator()( A const& lhs, dynamic const& rhs) const { return FOLLY_LIKELY(rhs.type() == dynamic::Type::STRING) && std::equal_to()(lhs, rhs.stringPiece()); } template std::enable_if_t::value, bool> operator()( dynamic const& lhs, B const& rhs) const { return FOLLY_LIKELY(lhs.type() == dynamic::Type::STRING) && std::equal_to()(lhs.stringPiece(), rhs); } }; } // namespace detail } // namespace folly ////////////////////////////////////////////////////////////////////// namespace std { template <> struct hash<::folly::dynamic> { size_t operator()(::folly::dynamic const& d) const { return d.hash(); } }; } // namespace std ////////////////////////////////////////////////////////////////////// // This is a higher-order preprocessor macro to aid going from runtime // types to the compile time type system. #define FB_DYNAMIC_APPLY(type, apply) \ do { \ switch ((type)) { \ case NULLT: \ apply(std::nullptr_t); \ break; \ case ARRAY: \ apply(Array); \ break; \ case BOOL: \ apply(bool); \ break; \ case DOUBLE: \ apply(double); \ break; \ case INT64: \ apply(int64_t); \ break; \ case OBJECT: \ apply(ObjectImpl); \ break; \ case STRING: \ apply(std::string); \ break; \ default: \ CHECK(0); \ abort(); \ } \ } while (0) ////////////////////////////////////////////////////////////////////// namespace folly { struct FOLLY_EXPORT TypeError : std::runtime_error { explicit TypeError(const std::string& expected, dynamic::Type actual); explicit TypeError( const std::string& expected, dynamic::Type actual1, dynamic::Type actual2); // TODO: noexcept calculation required through gcc-v4.9; remove once upgrading // to gcc-v5. TypeError(const TypeError&) noexcept( std::is_nothrow_copy_constructible::value); TypeError& operator=(const TypeError&) noexcept( std::is_nothrow_copy_assignable::value); TypeError(TypeError&&) noexcept( std::is_nothrow_move_constructible::value); TypeError& operator=(TypeError&&) noexcept( std::is_nothrow_move_assignable::value); ~TypeError() override; }; ////////////////////////////////////////////////////////////////////// namespace detail { // This helper is used in destroy() to be able to run destructors on // types like "int64_t" without a compiler error. struct Destroy { template static void destroy(T* t) { t->~T(); } }; /* * Helper for implementing numeric conversions in operators on * numbers. Just promotes to double when one of the arguments is * double, or throws if either is not a numeric type. */ template