diff --git a/LICENSE.txt b/LICENSE.txt index a37ca36c3f0..5c5b9cad878 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -680,34 +680,6 @@ DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- -The file cpp/src/arrow/vendored/variant.hpp has the following license - -Boost Software License - Version 1.0 - August 17th, 2003 - -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - --------------------------------------------------------------------------------- - The files in cpp/src/arrow/vendored/xxhash/ have the following license (BSD 2-Clause License) diff --git a/cpp/src/arrow/compute/function_benchmark.cc b/cpp/src/arrow/compute/function_benchmark.cc index e2214f85174..5dc305bdd89 100644 --- a/cpp/src/arrow/compute/function_benchmark.cc +++ b/cpp/src/arrow/compute/function_benchmark.cc @@ -28,6 +28,7 @@ namespace arrow { using internal::checked_cast; +using internal::checked_pointer_cast; namespace compute { @@ -43,7 +44,7 @@ inline ScalarVector ToScalars(std::shared_ptr arr) { return scalars; } -void BM_CastDispatch(benchmark::State& state) { // NOLINT non-const reference +void BM_CastDispatch(benchmark::State& state) { // Repeatedly invoke a trivial Cast: the main cost should be dispatch random::RandomArrayGenerator rag(kSeed); @@ -61,7 +62,7 @@ void BM_CastDispatch(benchmark::State& state) { // NOLINT non-const reference state.SetItemsProcessed(state.iterations() * kScalarCount); } -void BM_CastDispatchBaseline(benchmark::State& state) { // NOLINT non-const reference +void BM_CastDispatchBaseline(benchmark::State& state) { // Repeatedly invoke a trivial Cast with all dispatch outside the hot loop random::RandomArrayGenerator rag(kSeed); @@ -94,7 +95,7 @@ void BM_CastDispatchBaseline(benchmark::State& state) { // NOLINT non-const ref state.SetItemsProcessed(state.iterations() * kScalarCount); } -void BM_AddDispatch(benchmark::State& state) { // NOLINT non-const reference +void BM_AddDispatch(benchmark::State& state) { ExecContext exec_context; KernelContext kernel_context(&exec_context); @@ -109,9 +110,75 @@ void BM_AddDispatch(benchmark::State& state) { // NOLINT non-const reference state.SetItemsProcessed(state.iterations()); } -BENCHMARK(BM_CastDispatch)->MinTime(1.0); -BENCHMARK(BM_CastDispatchBaseline)->MinTime(1.0); -BENCHMARK(BM_AddDispatch)->MinTime(1.0); +static ScalarVector MakeScalarsForIsValid(int64_t nitems) { + std::vector> scalars; + scalars.reserve(nitems); + for (int64_t i = 0; i < nitems; ++i) { + if (i & 0x10) { + scalars.emplace_back(MakeNullScalar(int64())); + } else { + scalars.emplace_back(*MakeScalar(int64(), i)); + } + } + return scalars; +} + +void BM_ExecuteScalarFunctionOnScalar(benchmark::State& state) { + // Execute a trivial function, with argument dispatch in the hot path + const int64_t N = 10000; + + auto function = checked_pointer_cast( + *GetFunctionRegistry()->GetFunction("is_valid")); + const auto scalars = MakeScalarsForIsValid(N); + + ExecContext exec_context; + KernelContext kernel_context(&exec_context); + + for (auto _ : state) { + int64_t total = 0; + for (const auto& scalar : scalars) { + const Datum result = + *function->Execute({Datum(scalar)}, function->default_options(), &exec_context); + total += result.scalar()->is_valid; + } + benchmark::DoNotOptimize(total); + } + + state.SetItemsProcessed(state.iterations() * N); +} + +void BM_ExecuteScalarKernelOnScalar(benchmark::State& state) { + // Execute a trivial function, with argument dispatch outside the hot path + const int64_t N = 10000; + + auto function = *GetFunctionRegistry()->GetFunction("is_valid"); + auto kernel = *function->DispatchExact({ValueDescr::Scalar(int64())}); + const auto& exec = static_cast(*kernel).exec; + + const auto scalars = MakeScalarsForIsValid(N); + + ExecContext exec_context; + KernelContext kernel_context(&exec_context); + + for (auto _ : state) { + int64_t total = 0; + for (const auto& scalar : scalars) { + Datum result{MakeNullScalar(int64())}; + exec(&kernel_context, ExecBatch{{scalar}, /*length=*/1}, &result); + ABORT_NOT_OK(kernel_context.status()); + total += result.scalar()->is_valid; + } + benchmark::DoNotOptimize(total); + } + + state.SetItemsProcessed(state.iterations() * N); +} + +BENCHMARK(BM_CastDispatch); +BENCHMARK(BM_CastDispatchBaseline); +BENCHMARK(BM_AddDispatch); +BENCHMARK(BM_ExecuteScalarFunctionOnScalar); +BENCHMARK(BM_ExecuteScalarKernelOnScalar); } // namespace compute } // namespace arrow diff --git a/cpp/src/arrow/dataset/filter.h b/cpp/src/arrow/dataset/filter.h index d4cdcd9a033..c6b55b419ff 100644 --- a/cpp/src/arrow/dataset/filter.h +++ b/cpp/src/arrow/dataset/filter.h @@ -414,7 +414,7 @@ class ARROW_DS_EXPORT CastExpression final const std::shared_ptr& like_expr() const; private: - util::variant, std::shared_ptr> to_; + util::Variant, std::shared_ptr> to_; CastOptions options_; }; diff --git a/cpp/src/arrow/datum.h b/cpp/src/arrow/datum.h index 624657940ce..749b0c7907c 100644 --- a/cpp/src/arrow/datum.h +++ b/cpp/src/arrow/datum.h @@ -104,13 +104,13 @@ struct ARROW_EXPORT Datum { // current variant does not have a length. static constexpr int64_t kUnknownLength = -1; - util::variant, std::shared_ptr, + util::Variant, std::shared_ptr, std::shared_ptr, std::shared_ptr, std::shared_ptr, std::vector> value; /// \brief Empty datum, to be populated elsewhere - Datum() : value(NULLPTR) {} + Datum() = default; Datum(std::shared_ptr value) // NOLINT implicit conversion : value(std::move(value)) {} diff --git a/cpp/src/arrow/filesystem/mockfs.cc b/cpp/src/arrow/filesystem/mockfs.cc index 4253b2c168b..7cef8ac2b54 100644 --- a/cpp/src/arrow/filesystem/mockfs.cc +++ b/cpp/src/arrow/filesystem/mockfs.cc @@ -50,7 +50,7 @@ struct File { std::string name; std::string data; - File(TimePoint mtime, const std::string& name) : mtime(mtime), name(name) {} + File(TimePoint mtime, std::string name) : mtime(mtime), name(std::move(name)) {} int64_t size() const { return static_cast(data.length()); } }; @@ -60,8 +60,18 @@ struct Directory { TimePoint mtime; std::map> entries; - Directory(const std::string& name, TimePoint mtime) : name(name), mtime(mtime) {} - Directory(Directory&&) = default; + Directory(std::string name, TimePoint mtime) : name(std::move(name)), mtime(mtime) {} + Directory(Directory&& other) noexcept + : name(std::move(other.name)), + mtime(other.mtime), + entries(std::move(other.entries)) {} + + Directory& operator=(Directory&& other) noexcept { + name = std::move(other.name); + mtime = other.mtime; + entries = std::move(other.entries); + return *this; + } Entry* Find(const std::string& s) { auto it = entries.find(s); @@ -90,11 +100,12 @@ struct Directory { }; // A filesystem entry -using EntryBase = util::variant; +using EntryBase = util::Variant; class Entry : public EntryBase { public: Entry(Entry&&) = default; + Entry& operator=(Entry&&) = default; explicit Entry(Directory&& v) : EntryBase(std::move(v)) {} explicit Entry(File&& v) : EntryBase(std::move(v)) {} @@ -163,7 +174,7 @@ class MockFSOutputStream : public io::OutputStream { public: explicit MockFSOutputStream(File* file) : file_(file), closed_(false) {} - ~MockFSOutputStream() override {} + ~MockFSOutputStream() override = default; // Implement the OutputStream interface Status Close() override { @@ -284,7 +295,7 @@ class MockFileSystem::Impl { } void GatherInfos(const FileSelector& select, const std::string& base_path, - Directory& base_dir, int32_t nesting_depth, + const Directory& base_dir, int32_t nesting_depth, std::vector* infos) { for (const auto& pair : base_dir.entries) { Entry* child = pair.second.get(); @@ -297,7 +308,7 @@ class MockFileSystem::Impl { } } - void DumpDirs(const std::string& prefix, Directory& dir, + void DumpDirs(const std::string& prefix, const Directory& dir, std::vector* out) { std::string path = prefix + dir.name; if (!path.empty()) { @@ -312,7 +323,7 @@ class MockFileSystem::Impl { } } - void DumpFiles(const std::string& prefix, Directory& dir, + void DumpFiles(const std::string& prefix, const Directory& dir, std::vector* out) { std::string path = prefix + dir.name; if (!path.empty()) { @@ -370,7 +381,7 @@ class MockFileSystem::Impl { } }; -MockFileSystem::~MockFileSystem() {} +MockFileSystem::~MockFileSystem() = default; MockFileSystem::MockFileSystem(TimePoint current_time) { impl_ = std::unique_ptr(new Impl(current_time)); diff --git a/cpp/src/arrow/flight/client.h b/cpp/src/arrow/flight/client.h index 441f1146766..9d70067537a 100644 --- a/cpp/src/arrow/flight/client.h +++ b/cpp/src/arrow/flight/client.h @@ -117,7 +117,7 @@ class ARROW_FLIGHT_EXPORT FlightClientOptions { /// \brief Generic connection options, passed to the underlying /// transport; interpretation is implementation-dependent. - std::vector>> generic_options; + std::vector>> generic_options; /// \brief Use TLS without validating the server certificate. Use with caution. bool disable_server_verification; diff --git a/cpp/src/arrow/type.cc b/cpp/src/arrow/type.cc index cbf18a08734..359261ece0f 100644 --- a/cpp/src/arrow/type.cc +++ b/cpp/src/arrow/type.cc @@ -1005,13 +1005,13 @@ FieldRef::FieldRef(FieldPath indices) : impl_(std::move(indices)) { void FieldRef::Flatten(std::vector children) { // flatten children struct Visitor { - void operator()(std::string&& name) { *out++ = FieldRef(std::move(name)); } + void operator()(std::string* name) { *out++ = FieldRef(std::move(*name)); } - void operator()(FieldPath&& indices) { *out++ = FieldRef(std::move(indices)); } + void operator()(FieldPath* indices) { *out++ = FieldRef(std::move(*indices)); } - void operator()(std::vector&& children) { - for (auto& child : children) { - util::visit(*this, std::move(child.impl_)); + void operator()(std::vector* children) { + for (auto& child : *children) { + util::visit(*this, &child.impl_); } } @@ -1020,7 +1020,7 @@ void FieldRef::Flatten(std::vector children) { std::vector out; Visitor visitor{std::back_inserter(out)}; - visitor(std::move(children)); + visitor(&children); DCHECK(!out.empty()); DCHECK(std::none_of(out.begin(), out.end(), diff --git a/cpp/src/arrow/type.h b/cpp/src/arrow/type.h index c45cf857a2a..5347db337eb 100644 --- a/cpp/src/arrow/type.h +++ b/cpp/src/arrow/type.h @@ -1596,7 +1596,7 @@ class ARROW_EXPORT FieldRef { private: void Flatten(std::vector children); - util::variant> impl_; + util::Variant> impl_; ARROW_EXPORT friend void PrintTo(const FieldRef& ref, std::ostream* os); }; diff --git a/cpp/src/arrow/util/CMakeLists.txt b/cpp/src/arrow/util/CMakeLists.txt index c968cdd1a43..d46894d775d 100644 --- a/cpp/src/arrow/util/CMakeLists.txt +++ b/cpp/src/arrow/util/CMakeLists.txt @@ -61,7 +61,8 @@ add_arrow_test(utility-test trie_test.cc uri_test.cc utf8_util_test.cc - value_parsing_test.cc) + value_parsing_test.cc + variant_test.cc) add_arrow_test(threading-utility-test SOURCES @@ -81,3 +82,4 @@ add_arrow_benchmark(thread_pool_benchmark) add_arrow_benchmark(trie_benchmark) add_arrow_benchmark(utf8_util_benchmark) add_arrow_benchmark(value_parsing_benchmark) +add_arrow_benchmark(variant_benchmark) diff --git a/cpp/src/arrow/util/type_traits.h b/cpp/src/arrow/util/type_traits.h index 7f7b1d644e7..80cc6297e39 100644 --- a/cpp/src/arrow/util/type_traits.h +++ b/cpp/src/arrow/util/type_traits.h @@ -17,6 +17,7 @@ #pragma once +#include #include namespace arrow { @@ -41,5 +42,45 @@ template struct is_null_pointer : std::is_same::type> { }; +#ifdef __GLIBCXX__ + +// A aligned_union backport, because old libstdc++ versions don't include it. + +constexpr std::size_t max_size(std::size_t a, std::size_t b) { return (a > b) ? a : b; } + +template +struct max_size_traits; + +template +struct max_size_traits { + static constexpr std::size_t max_sizeof() { + return max_size(sizeof(H), max_size_traits::max_sizeof()); + } + static constexpr std::size_t max_alignof() { + return max_size(alignof(H), max_size_traits::max_alignof()); + } +}; + +template <> +struct max_size_traits<> { + static constexpr std::size_t max_sizeof() { return 0; } + static constexpr std::size_t max_alignof() { return 0; } +}; + +template +struct aligned_union { + static constexpr std::size_t alignment_value = max_size_traits::max_alignof(); + static constexpr std::size_t size_value = + max_size(Len, max_size_traits::max_sizeof()); + using type = typename std::aligned_storage::type; +}; + +#else + +template +using aligned_union = std::aligned_union; + +#endif + } // namespace internal } // namespace arrow diff --git a/cpp/src/arrow/util/variant.h b/cpp/src/arrow/util/variant.h index 335700ba9e6..4713976d485 100644 --- a/cpp/src/arrow/util/variant.h +++ b/cpp/src/arrow/util/variant.h @@ -17,17 +17,408 @@ #pragma once -#include "arrow/vendored/variant.hpp" // IWYU pragma: export +#include +#include +#include +#include + +#include "arrow/util/macros.h" +#include "arrow/util/type_traits.h" namespace arrow { namespace util { -using ::mpark::bad_variant_access; -using ::mpark::get; -using ::mpark::get_if; -using ::mpark::holds_alternative; -using ::mpark::variant; -using ::mpark::visit; +/// \brief a std::variant-like discriminated union +/// +/// Simplifications from std::variant: +/// +/// - Strictly defaultable. The first type of T... should be nothrow default constructible +/// and it will be used for default Variants. +/// +/// - Never valueless_by_exception. std::variant supports a state outside those specified +/// by T... to which it can return in the event that a constructor throws. If a Variant +/// would become valueless_by_exception it will instead return to its default state. +/// +/// - Strictly nothrow move constructible and assignable +/// +/// - Less sophisticated type deduction. std::variant("hello") will +/// intelligently construct std::string while Variant("hello") will +/// construct bool. +/// +/// - Either both copy constructible and assignable or neither (std::variant independently +/// enables copy construction and copy assignment). Variant is copy constructible if +/// each of T... is copy constructible and assignable. +/// +/// - Slimmer interface; several members of std::variant are omitted. +/// +/// - Throws no exceptions; if a bad_variant_access would be thrown Variant will instead +/// segfault (nullptr dereference). +/// +/// - Mutable visit takes a pointer instead of mutable reference or rvalue reference, +/// which is more conformant with our code style. +template +class Variant; + +namespace detail { + +template +struct is_equality_comparable : std::false_type {}; + +template +struct is_equality_comparable< + T, typename std::enable_if() == std::declval()), bool>::value>::type> + : std::true_type {}; + +template +using conditional_t = typename std::conditional::type; + +template +struct type_constant { + using type = T; +}; + +template +struct first; + +template +struct first { + using type = H; +}; + +template +using decay_t = typename std::decay::type; + +template +struct all : std::true_type {}; + +template +struct all : conditional_t, std::false_type> {}; + +struct delete_copy_constructor { + template + struct type { + type() = default; + type(const type& other) = delete; + type& operator=(const type& other) = delete; + }; +}; + +struct explicit_copy_constructor { + template + struct type { + type() = default; + type(const type& other) { static_cast(other).copy_to(this); } + type& operator=(const type& other) { + static_cast(this)->destroy(); + static_cast(other).copy_to(this); + return *this; + } + }; +}; + +template +struct VariantStorage { + VariantStorage() = default; + VariantStorage(const VariantStorage&) {} + VariantStorage& operator=(const VariantStorage&) { return *this; } + VariantStorage(VariantStorage&&) noexcept {} + VariantStorage& operator=(VariantStorage&&) noexcept { return *this; } + ~VariantStorage() { + static_assert(offsetof(VariantStorage, data_) == 0, + "(void*)&VariantStorage::data_ == (void*)this"); + } + + typename arrow::internal::aligned_union<0, T...>::type data_; + uint8_t index_ = 0; +}; + +template +struct VariantImpl; + +template +struct VariantImpl> : VariantStorage { + static void index_of() noexcept {} + void destroy() noexcept {} + void move_to(...) noexcept {} + void copy_to(...) const {} + + template + [[noreturn]] R visit_const(Visitor&& visitor) const { + std::terminate(); + } + template + [[noreturn]] R visit_mutable(Visitor&& visitor) { + std::terminate(); + } +}; + +template +struct VariantImpl, H, T...> : VariantImpl, T...> { + using VariantType = Variant; + using Impl = VariantImpl; + + static constexpr uint8_t kIndex = sizeof...(M) - sizeof...(T) - 1; + + VariantImpl() = default; + + using VariantImpl::VariantImpl; + using Impl::operator=; + using Impl::index_of; + + explicit VariantImpl(H value) { + new (this) H(std::move(value)); + this->index_ = kIndex; + } + + VariantImpl& operator=(H value) { + static_cast(this)->destroy(); + new (this) H(std::move(value)); + this->index_ = kIndex; + return *this; + } + + H& cast_this() { return *reinterpret_cast(this); } + const H& cast_this() const { return *reinterpret_cast(this); } + + void move_to(VariantType* target) noexcept { + if (this->index_ == kIndex) { + new (target) H(std::move(cast_this())); + target->index_ = kIndex; + } else { + Impl::move_to(target); + } + } + + // Templated to avoid instantiation in case H is not copy constructible + template + void copy_to(Void* generic_target) const { + const auto target = static_cast(generic_target); + try { + if (this->index_ == kIndex) { + new (target) H(cast_this()); + target->index_ = kIndex; + } else { + Impl::copy_to(target); + } + } catch (...) { + target->construct_default(); + throw; + } + } + + void destroy() noexcept { + if (this->index_ == kIndex) { + if (!std::is_trivially_destructible::value) { + cast_this().~H(); + } + } else { + Impl::destroy(); + } + } + + static constexpr std::integral_constant index_of( + const type_constant&) { + return {}; + } + + template + R visit_const(Visitor&& visitor) const { + if (this->index_ == kIndex) { + return std::forward(visitor)(cast_this()); + } + return Impl::template visit_const(std::forward(visitor)); + } + + template + R visit_mutable(Visitor&& visitor) { + if (this->index_ == kIndex) { + return std::forward(visitor)(&cast_this()); + } + return Impl::template visit_mutable(std::forward(visitor)); + } +}; + +} // namespace detail + +template +class Variant : detail::VariantImpl, T...>, + detail::conditional_t< + detail::all<(std::is_copy_constructible::value && + std::is_copy_assignable::value)...>::value, + detail::explicit_copy_constructor, + detail::delete_copy_constructor>::template type> { + template + static constexpr uint8_t index_of() { + return Impl::index_of(detail::type_constant{}); + } + + using Impl = detail::VariantImpl, T...>; + + public: + using default_type = typename util::detail::first::type; + + Variant() noexcept { construct_default(); } + + Variant(const Variant& other) = default; + Variant& operator=(const Variant& other) = default; + + using Impl::Impl; + using Impl::operator=; + + Variant(Variant&& other) noexcept { other.move_to(this); } + + Variant& operator=(Variant&& other) noexcept { + this->destroy(); + other.move_to(this); + return *this; + } + + ~Variant() { + static_assert(offsetof(Variant, data_) == 0, "(void*)&Variant::data_ == (void*)this"); + this->destroy(); + } + + /// \brief Return the zero-based type index of the value held by the variant + uint8_t index() const noexcept { return this->index_; } + + /// \brief Get a const pointer to the value held by the variant + /// + /// If the type given as template argument doesn't match, a null pointer is returned. + template ()> + const U* get() const noexcept { + return index() == I ? reinterpret_cast(this) : NULLPTR; + } + + /// \brief Get a pointer to the value held by the variant + /// + /// If the type given as template argument doesn't match, a null pointer is returned. + template ()> + U* get() noexcept { + return index() == I ? reinterpret_cast(this) : NULLPTR; + } + + /// \brief Replace the value held by the variant + /// + /// The intended type must be given as a template argument. + /// The value is constructed in-place using the given function arguments. + template ()> + void emplace(A&&... args) try { + this->destroy(); + new (this) U(std::forward(args)...); + this->index_ = I; + } catch (...) { + construct_default(); + throw; + } + + template ()> + void emplace(std::initializer_list il, A&&... args) try { + this->destroy(); + new (this) U(il, std::forward(args)...); + this->index_ = I; + } catch (...) { + construct_default(); + throw; + } + + /// \brief Swap with another variant's contents + void swap(Variant& other) noexcept { // NOLINT google-runtime-references + Variant tmp = std::move(other); + other = std::move(*this); + *this = std::move(tmp); + } + + using Impl::visit_const; + using Impl::visit_mutable; + + private: + void construct_default() noexcept { + new (this) default_type(); + this->index_ = 0; + } + + template + friend struct detail::explicit_copy_constructor::type; + + template + friend struct detail::VariantImpl; +}; + +/// \brief Call polymorphic visitor on a const variant's value +/// +/// The visitor will receive a const reference to the value held by the variant. +/// It must define overloads for each possible variant type. +/// The overloads should all return the same type (no attempt +/// is made to find a generalized return type). +template ()( + std::declval::default_type&>()))> +R visit(Visitor&& visitor, const util::Variant& v) { + return v.template visit_const(std::forward(visitor)); +} + +/// \brief Call polymorphic visitor on a non-const variant's value +/// +/// The visitor will receive a pointer to the value held by the variant. +/// It must define overloads for each possible variant type. +/// The overloads should all return the same type (no attempt +/// is made to find a generalized return type). +template ()( + std::declval::default_type*>()))> +R visit(Visitor&& visitor, util::Variant* v) { + return v->template visit_mutable(std::forward(visitor)); +} + +/// \brief Get a const reference to the value held by the variant +/// +/// If the type given as template argument doesn't match, behavior is undefined +/// (a null pointer will be dereferenced). +template +const U& get(const Variant& v) { + return *v.template get(); +} + +/// \brief Get a reference to the value held by the variant +/// +/// If the type given as template argument doesn't match, behavior is undefined +/// (a null pointer will be dereferenced). +template +U& get(Variant& v) { + return *v.template get(); +} + +namespace detail { + +template +struct VariantsEqual { + template + bool operator()(const U& r) const { + return get(l_) == r; + } + const Variant& l_; +}; + +} // namespace detail + +template ::value...>::value>> +bool operator==(const Variant& l, const Variant& r) { + if (l.index() != r.index()) return false; + return visit(detail::VariantsEqual{l}, r); +} + +template +auto operator!=(const Variant& l, const Variant& r) -> decltype(l == r) { + return !(l == r); +} + +/// \brief Return whether the variant holds a value of the given type +template +bool holds_alternative(const Variant& v) { + return v.template get(); +} } // namespace util } // namespace arrow diff --git a/cpp/src/arrow/util/variant_benchmark.cc b/cpp/src/arrow/util/variant_benchmark.cc new file mode 100644 index 00000000000..af3fafb8b0e --- /dev/null +++ b/cpp/src/arrow/util/variant_benchmark.cc @@ -0,0 +1,248 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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. + +#include "benchmark/benchmark.h" + +#include +#include +#include +#include +#include + +#include "arrow/array.h" +#include "arrow/chunked_array.h" +#include "arrow/datum.h" +#include "arrow/status.h" +#include "arrow/testing/gtest_util.h" +#include "arrow/testing/random.h" +#include "arrow/type.h" +#include "arrow/util/checked_cast.h" +#include "arrow/util/variant.h" + +namespace arrow { + +using internal::checked_pointer_cast; + +namespace util { + +using TrivialVariant = arrow::util::Variant; + +using NonTrivialVariant = arrow::util::Variant; + +std::vector MakeInts(int64_t nitems) { + auto rng = arrow::random::RandomArrayGenerator(42); + auto array = checked_pointer_cast(rng.Int32(nitems, 0, 1 << 30)); + std::vector items(nitems); + for (int64_t i = 0; i < nitems; ++i) { + items[i] = array->Value(i); + } + return items; +} + +std::vector MakeFloats(int64_t nitems) { + auto rng = arrow::random::RandomArrayGenerator(42); + auto array = checked_pointer_cast(rng.Float32(nitems, 0.0, 1.0)); + std::vector items(nitems); + for (int64_t i = 0; i < nitems; ++i) { + items[i] = array->Value(i); + } + return items; +} + +std::vector MakeStrings(int64_t nitems) { + auto rng = arrow::random::RandomArrayGenerator(42); + // Some std::string's will use short string optimization, but not all... + auto array = checked_pointer_cast(rng.String(nitems, 5, 40)); + std::vector items(nitems); + for (int64_t i = 0; i < nitems; ++i) { + items[i] = array->GetString(i); + } + return items; +} + +static void ConstructTrivialVariant(benchmark::State& state) { + const int64_t N = 10000; + const auto ints = MakeInts(N); + const auto floats = MakeFloats(N); + + for (auto _ : state) { + for (int64_t i = 0; i < N; ++i) { + // About type selection: we ensure 50% of each type, but try to avoid + // branch mispredictions by creating runs of the same type. + if (i & 0x10) { + TrivialVariant v{ints[i]}; + const int32_t* val = &arrow::util::get(v); + benchmark::DoNotOptimize(val); + } else { + TrivialVariant v{floats[i]}; + const float* val = &arrow::util::get(v); + benchmark::DoNotOptimize(val); + } + } + } + + state.SetItemsProcessed(state.iterations() * N); +} + +static void ConstructNonTrivialVariant(benchmark::State& state) { + const int64_t N = 10000; + const auto ints = MakeInts(N); + const auto strings = MakeStrings(N); + + for (auto _ : state) { + for (int64_t i = 0; i < N; ++i) { + if (i & 0x10) { + NonTrivialVariant v{ints[i]}; + const int32_t* val = &arrow::util::get(v); + benchmark::DoNotOptimize(val); + } else { + NonTrivialVariant v{strings[i]}; + const std::string* val = &arrow::util::get(v); + benchmark::DoNotOptimize(val); + } + } + } + + state.SetItemsProcessed(state.iterations() * N); +} + +struct VariantVisitor { + int64_t total = 0; + + void operator()(const int32_t& v) { total += v; } + void operator()(const float& v) { + // Avoid potentially costly float-to-int conversion + int32_t x; + memcpy(&x, &v, 4); + total += x; + } + void operator()(const std::string& v) { total += static_cast(v.length()); } +}; + +template +static void VisitVariant(benchmark::State& state, + const std::vector& variants) { + for (auto _ : state) { + VariantVisitor visitor; + for (const auto& v : variants) { + visit(visitor, v); + } + benchmark::DoNotOptimize(visitor.total); + } + + state.SetItemsProcessed(state.iterations() * variants.size()); +} + +static void VisitTrivialVariant(benchmark::State& state) { + const int64_t N = 10000; + const auto ints = MakeInts(N); + const auto floats = MakeFloats(N); + + std::vector variants; + variants.reserve(N); + for (int64_t i = 0; i < N; ++i) { + if (i & 0x10) { + variants.emplace_back(ints[i]); + } else { + variants.emplace_back(floats[i]); + } + } + + VisitVariant(state, variants); +} + +static void VisitNonTrivialVariant(benchmark::State& state) { + const int64_t N = 10000; + const auto ints = MakeInts(N); + const auto strings = MakeStrings(N); + + std::vector variants; + variants.reserve(N); + for (int64_t i = 0; i < N; ++i) { + if (i & 0x10) { + variants.emplace_back(ints[i]); + } else { + variants.emplace_back(strings[i]); + } + } + + VisitVariant(state, variants); +} + +static void ConstructDatum(benchmark::State& state) { + const int64_t N = 10000; + auto array = *MakeArrayOfNull(int8(), 100); + auto chunked_array = std::make_shared(ArrayVector{array, array}); + + for (auto _ : state) { + for (int64_t i = 0; i < N; ++i) { + if (i & 0x10) { + Datum datum{array}; + const ArrayData* val = datum.array().get(); + benchmark::DoNotOptimize(val); + } else { + Datum datum{chunked_array}; + const ChunkedArray* val = datum.chunked_array().get(); + benchmark::DoNotOptimize(val); + } + } + } + + state.SetItemsProcessed(state.iterations() * N); +} + +static void VisitDatum(benchmark::State& state) { + const int64_t N = 10000; + auto array = *MakeArrayOfNull(int8(), 100); + auto chunked_array = std::make_shared(ArrayVector{array, array}); + + std::vector datums; + datums.reserve(N); + for (int64_t i = 0; i < N; ++i) { + if (i & 0x10) { + datums.emplace_back(array); + } else { + datums.emplace_back(chunked_array); + } + } + + for (auto _ : state) { + int64_t total = 0; + for (const auto& datum : datums) { + // The .is_XXX() methods are the usual idiom when visiting a Datum, + // rather than the visit() function. + if (datum.is_array()) { + total += datum.array()->length; + } else { + total += datum.chunked_array()->length(); + } + } + benchmark::DoNotOptimize(total); + } + + state.SetItemsProcessed(state.iterations() * datums.size()); +} + +BENCHMARK(ConstructTrivialVariant); +BENCHMARK(ConstructNonTrivialVariant); +BENCHMARK(VisitTrivialVariant); +BENCHMARK(VisitNonTrivialVariant); +BENCHMARK(ConstructDatum); +BENCHMARK(VisitDatum); + +} // namespace util +} // namespace arrow diff --git a/cpp/src/arrow/util/variant_test.cc b/cpp/src/arrow/util/variant_test.cc new file mode 100644 index 00000000000..9e36f2eb9cf --- /dev/null +++ b/cpp/src/arrow/util/variant_test.cc @@ -0,0 +1,330 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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. + +#include "arrow/util/variant.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include "arrow/testing/gtest_compat.h" + +namespace arrow { + +namespace util { +namespace { + +using ::testing::Eq; + +template +void AssertDefaultConstruction() { + using variant_type = Variant; + + static_assert(std::is_nothrow_default_constructible::value, ""); + + variant_type v; + EXPECT_EQ(v.index(), 0); + EXPECT_EQ(get(v), H{}); +} + +TEST(Variant, DefaultConstruction) { + AssertDefaultConstruction(); + AssertDefaultConstruction(); + AssertDefaultConstruction(); + AssertDefaultConstruction>(); + AssertDefaultConstruction, int>(); + AssertDefaultConstruction, void*, + std::true_type>(); + AssertDefaultConstruction, void*, bool, + std::string, std::true_type>(); +} + +template +struct AssertCopyConstructionOne { + void operator()(uint8_t index) { + V v{member_}; + EXPECT_EQ(v.index(), index); + EXPECT_EQ(get(v), member_); + + V copy{v}; + EXPECT_EQ(copy.index(), v.index()); + EXPECT_EQ(get(copy), get(v)); + EXPECT_EQ(copy, v); + + V assigned; + assigned = member_; + EXPECT_EQ(assigned.index(), index); + EXPECT_EQ(get(assigned), member_); + + assigned = v; + EXPECT_EQ(assigned.index(), v.index()); + EXPECT_EQ(get(assigned), get(v)); + EXPECT_EQ(assigned, v); + } + + const T& member_; +}; + +template +void AssertCopyConstruction(T... member) { + uint8_t index = 0; + for (auto Assert : {std::function( + AssertCopyConstructionOne, T>{member})...}) { + Assert(index++); + } +} + +template +void AssertCopyConstructionDisabled() { + static_assert(!std::is_copy_constructible>::value, + "copy construction was not disabled"); +} + +TEST(Variant, CopyConstruction) { + // if any member is not copy constructible then Variant is not copy constructible + AssertCopyConstructionDisabled>(); + AssertCopyConstructionDisabled, std::string>(); + AssertCopyConstructionDisabled>(); + + AssertCopyConstruction(32, std::string("hello"), true); + AssertCopyConstruction(std::string("world"), false, 53); + AssertCopyConstruction(nullptr, std::true_type{}, std::string("!")); + AssertCopyConstruction(std::vector{1, 3, 3, 7}, "C string"); + + // copy assignment operator is not used + struct CopyAssignThrows { + CopyAssignThrows() = default; + CopyAssignThrows(const CopyAssignThrows&) = default; + + CopyAssignThrows& operator=(const CopyAssignThrows&) { throw 42; } + + CopyAssignThrows(CopyAssignThrows&&) = default; + CopyAssignThrows& operator=(CopyAssignThrows&&) = default; + + bool operator==(const CopyAssignThrows&) const { return true; } + }; + EXPECT_NO_THROW(AssertCopyConstruction(CopyAssignThrows{})); +} + +TEST(Variant, Emplace) { + using variant_type = Variant, int>; + variant_type v; + + v.emplace(); + EXPECT_EQ(v, variant_type{int{}}); + + v.emplace("hello"); + EXPECT_EQ(v, variant_type{std::string("hello")}); + + v.emplace>({1, 3, 3, 7}); + EXPECT_EQ(v, variant_type{std::vector({1, 3, 3, 7})}); +} + +TEST(Variant, MoveConstruction) { + struct noop_delete { + void operator()(...) const {} + }; + using ptr = std::unique_ptr; + static_assert(!std::is_copy_constructible::value, ""); + + using variant_type = Variant; + + int tag = 42; + auto ExpectIsTag = [&](const variant_type& v) { + EXPECT_EQ(v.index(), 1); + EXPECT_EQ(get(v).get(), &tag); + }; + + ptr p; + + // move construction from member + p.reset(&tag); + variant_type v0{std::move(p)}; + ExpectIsTag(v0); + + // move assignment from member + p.reset(&tag); + v0 = std::move(p); + ExpectIsTag(v0); + + // move construction from other variant + variant_type v1{std::move(v0)}; + ExpectIsTag(v1); + + // move assignment from other variant + p.reset(&tag); + variant_type v2{std::move(p)}; + v1 = std::move(v2); + ExpectIsTag(v1); + + // type changing move assignment from member + variant_type v3; + EXPECT_NE(v3.index(), 1); + p.reset(&tag); + v3 = std::move(p); + ExpectIsTag(v3); + + // type changing move assignment from other variant + variant_type v4; + EXPECT_NE(v4.index(), 1); + v4 = std::move(v3); + ExpectIsTag(v4); +} + +TEST(Variant, ExceptionSafety) { + struct { + } actually_throw; + + struct { + } dont_throw; + + struct ConstructorThrows { + explicit ConstructorThrows(decltype(actually_throw)) { throw 42; } + explicit ConstructorThrows(decltype(dont_throw)) {} + + ConstructorThrows(const ConstructorThrows&) { throw 42; } + + ConstructorThrows& operator=(const ConstructorThrows&) = default; + ConstructorThrows(ConstructorThrows&&) = default; + ConstructorThrows& operator=(ConstructorThrows&&) = default; + }; + + Variant v; + + // constructor throws during emplacement + EXPECT_THROW(v.emplace(actually_throw), int); + // safely returned to the default state + EXPECT_EQ(v.index(), 0); + + // constructor throws during copy assignment from member + EXPECT_THROW( + { + const ConstructorThrows throws(dont_throw); + v = throws; + }, + int); + // safely returned to the default state + EXPECT_EQ(v.index(), 0); +} + +template +struct AssertVisitOne { + void operator()(const T& actual) { EXPECT_EQ(&actual, expected_); } + + void operator()(T* actual) { EXPECT_EQ(actual, expected_); } + + template + void operator()(const U&) { + FAIL() << "the expected type was not visited."; + } + + template + void operator()(U*) { + FAIL() << "the expected type was not visited."; + } + + explicit AssertVisitOne(T member) : member_(std::move(member)) {} + + void operator()() { + V v{member_}; + expected_ = &get(v); + visit(*this, v); + visit(*this, &v); + } + + T member_; + const T* expected_; +}; + +template +void AssertVisit(T... member) { + for (auto Assert : + {std::function(AssertVisitOne, T>{member})...}) { + Assert(); + } +} + +TEST(VariantTest, Visit) { + AssertVisit(32, std::string("hello"), true); + AssertVisit(std::string("world"), false, 53); + AssertVisit(nullptr, std::true_type{}, std::string("!")); + AssertVisit(std::vector{1, 3, 3, 7}, "C string"); + + using int_or_string = Variant; + int_or_string v; + + // value returning visit: + struct { + int_or_string operator()(int i) { return int_or_string{i * 2}; } + int_or_string operator()(const std::string& s) { return int_or_string{s + s}; } + } Double; + + v = 7; + EXPECT_EQ(visit(Double, v), int_or_string{14}); + + v = "lolol"; + EXPECT_EQ(visit(Double, v), int_or_string{"lolollolol"}); + + // mutating visit: + struct { + void operator()(int* i) { *i *= 2; } + void operator()(std::string* s) { *s += *s; } + } DoubleInplace; + + v = 7; + visit(DoubleInplace, &v); + EXPECT_EQ(v, int_or_string{14}); + + v = "lolol"; + visit(DoubleInplace, &v); + EXPECT_EQ(v, int_or_string{"lolollolol"}); +} + +TEST(VariantTest, Equality) { + using int_or_double = Variant; + + auto eq = [](const int_or_double& a, const int_or_double& b) { + EXPECT_TRUE(a == b); + EXPECT_FALSE(a != b); + }; + auto ne = [](const int_or_double& a, const int_or_double& b) { + EXPECT_TRUE(a != b); + EXPECT_FALSE(a == b); + }; + + int_or_double u, v; + u.emplace(1); + v.emplace(1); + eq(u, v); + v.emplace(2); + ne(u, v); + v.emplace(1.0); + ne(u, v); + u.emplace(1.0); + eq(u, v); + u.emplace(2.0); + ne(u, v); +} + +} // namespace +} // namespace util +} // namespace arrow diff --git a/cpp/src/arrow/vendored/variant.hpp b/cpp/src/arrow/vendored/variant.hpp deleted file mode 100644 index d558803b5a6..00000000000 --- a/cpp/src/arrow/vendored/variant.hpp +++ /dev/null @@ -1,2835 +0,0 @@ -// Vendored from v1.4.0, from single-header branch at https://github.com/mpark/variant/commit/d1cdfdd3f2ed80710ba4d671fe6bffaa3e28201a - -// MPark.Variant -// -// Copyright Michael Park, 2015-2017 -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -#ifndef MPARK_VARIANT_HPP -#define MPARK_VARIANT_HPP - -/* - variant synopsis - -namespace std { - - // 20.7.2, class template variant - template - class variant { - public: - - // 20.7.2.1, constructors - constexpr variant() noexcept(see below); - variant(const variant&); - variant(variant&&) noexcept(see below); - - template constexpr variant(T&&) noexcept(see below); - - template - constexpr explicit variant(in_place_type_t, Args&&...); - - template - constexpr explicit variant( - in_place_type_t, initializer_list, Args&&...); - - template - constexpr explicit variant(in_place_index_t, Args&&...); - - template - constexpr explicit variant( - in_place_index_t, initializer_list, Args&&...); - - // 20.7.2.2, destructor - ~variant(); - - // 20.7.2.3, assignment - variant& operator=(const variant&); - variant& operator=(variant&&) noexcept(see below); - - template variant& operator=(T&&) noexcept(see below); - - // 20.7.2.4, modifiers - template - T& emplace(Args&&...); - - template - T& emplace(initializer_list, Args&&...); - - template - variant_alternative& emplace(Args&&...); - - template - variant_alternative& emplace(initializer_list, Args&&...); - - // 20.7.2.5, value status - constexpr bool valueless_by_exception() const noexcept; - constexpr size_t index() const noexcept; - - // 20.7.2.6, swap - void swap(variant&) noexcept(see below); - }; - - // 20.7.3, variant helper classes - template struct variant_size; // undefined - - template - constexpr size_t variant_size_v = variant_size::value; - - template struct variant_size; - template struct variant_size; - template struct variant_size; - - template - struct variant_size>; - - template struct variant_alternative; // undefined - - template - using variant_alternative_t = typename variant_alternative::type; - - template struct variant_alternative; - template struct variant_alternative; - template struct variant_alternative; - - template - struct variant_alternative>; - - constexpr size_t variant_npos = -1; - - // 20.7.4, value access - template - constexpr bool holds_alternative(const variant&) noexcept; - - template - constexpr variant_alternative_t>& - get(variant&); - - template - constexpr variant_alternative_t>&& - get(variant&&); - - template - constexpr variant_alternative_t> const& - get(const variant&); - - template - constexpr variant_alternative_t> const&& - get(const variant&&); - - template - constexpr T& get(variant&); - - template - constexpr T&& get(variant&&); - - template - constexpr const T& get(const variant&); - - template - constexpr const T&& get(const variant&&); - - template - constexpr add_pointer_t>> - get_if(variant*) noexcept; - - template - constexpr add_pointer_t>> - get_if(const variant*) noexcept; - - template - constexpr add_pointer_t - get_if(variant*) noexcept; - - template - constexpr add_pointer_t - get_if(const variant*) noexcept; - - // 20.7.5, relational operators - template - constexpr bool operator==(const variant&, const variant&); - - template - constexpr bool operator!=(const variant&, const variant&); - - template - constexpr bool operator<(const variant&, const variant&); - - template - constexpr bool operator>(const variant&, const variant&); - - template - constexpr bool operator<=(const variant&, const variant&); - - template - constexpr bool operator>=(const variant&, const variant&); - - // 20.7.6, visitation - template - constexpr see below visit(Visitor&&, Variants&&...); - - // 20.7.7, class monostate - struct monostate; - - // 20.7.8, monostate relational operators - constexpr bool operator<(monostate, monostate) noexcept; - constexpr bool operator>(monostate, monostate) noexcept; - constexpr bool operator<=(monostate, monostate) noexcept; - constexpr bool operator>=(monostate, monostate) noexcept; - constexpr bool operator==(monostate, monostate) noexcept; - constexpr bool operator!=(monostate, monostate) noexcept; - - // 20.7.9, specialized algorithms - template - void swap(variant&, variant&) noexcept(see below); - - // 20.7.10, class bad_variant_access - class bad_variant_access; - - // 20.7.11, hash support - template struct hash; - template struct hash>; - template <> struct hash; - -} // namespace std - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -// MPark.Variant -// -// Copyright Michael Park, 2015-2017 -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -#ifndef MPARK_CONFIG_HPP -#define MPARK_CONFIG_HPP - -// MSVC 2015 Update 3. -#if __cplusplus < 201103L && (!defined(_MSC_VER) || _MSC_FULL_VER < 190024210) -#error "MPark.Variant requires C++11 support." -#endif - -#ifndef __has_attribute -#define __has_attribute(x) 0 -#endif - -#ifndef __has_builtin -#define __has_builtin(x) 0 -#endif - -#ifndef __has_include -#define __has_include(x) 0 -#endif - -#ifndef __has_feature -#define __has_feature(x) 0 -#endif - -#if __has_attribute(always_inline) || defined(__GNUC__) -#define MPARK_ALWAYS_INLINE __attribute__((__always_inline__)) inline -#elif defined(_MSC_VER) -#define MPARK_ALWAYS_INLINE __forceinline -#else -#define MPARK_ALWAYS_INLINE inline -#endif - -#if __has_builtin(__builtin_addressof) || \ - (defined(__GNUC__) && __GNUC__ >= 7) || defined(_MSC_VER) -#define MPARK_BUILTIN_ADDRESSOF -#endif - -#if __has_builtin(__builtin_unreachable) || defined(__GNUC__) -#define MPARK_BUILTIN_UNREACHABLE __builtin_unreachable() -#elif defined(_MSC_VER) -#define MPARK_BUILTIN_UNREACHABLE __assume(false) -#else -#define MPARK_BUILTIN_UNREACHABLE -#endif - -#if __has_builtin(__type_pack_element) -#define MPARK_TYPE_PACK_ELEMENT -#endif - -#if defined(__cpp_constexpr) && __cpp_constexpr >= 200704 && \ - !(defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 9) -#define MPARK_CPP11_CONSTEXPR -#endif - -#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304 -#define MPARK_CPP14_CONSTEXPR -#endif - -#if __has_feature(cxx_exceptions) || defined(__cpp_exceptions) || \ - (defined(_MSC_VER) && defined(_CPPUNWIND)) -#define MPARK_EXCEPTIONS -#endif - -#if defined(__cpp_generic_lambdas) || defined(_MSC_VER) -#define MPARK_GENERIC_LAMBDAS -#endif - -#if defined(__cpp_lib_integer_sequence) -#define MPARK_INTEGER_SEQUENCE -#endif - -#if (defined(__cpp_decltype_auto) && defined(__cpp_return_type_deduction)) || defined(_MSC_VER) -#define MPARK_RETURN_TYPE_DEDUCTION -#endif - -#if defined(__cpp_lib_transparent_operators) || defined(_MSC_VER) -#define MPARK_TRANSPARENT_OPERATORS -#endif - -#if defined(__cpp_variable_templates) || defined(_MSC_VER) -#define MPARK_VARIABLE_TEMPLATES -#endif - -#if !defined(__GLIBCXX__) || __has_include() // >= libstdc++-5 -#define MPARK_TRIVIALITY_TYPE_TRAITS -#define MPARK_INCOMPLETE_TYPE_TRAITS -#endif - -#endif // MPARK_CONFIG_HPP - -// MPark.Variant -// -// Copyright Michael Park, 2015-2017 -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -#ifndef MPARK_IN_PLACE_HPP -#define MPARK_IN_PLACE_HPP - -#include - - -namespace mpark { - - struct in_place_t { explicit in_place_t() = default; }; - - template - struct in_place_index_t { explicit in_place_index_t() = default; }; - - template - struct in_place_type_t { explicit in_place_type_t() = default; }; - -#ifdef MPARK_VARIABLE_TEMPLATES - constexpr in_place_t in_place{}; - - template constexpr in_place_index_t in_place_index{}; - - template constexpr in_place_type_t in_place_type{}; -#endif - -} // namespace mpark - -#endif // MPARK_IN_PLACE_HPP - -// MPark.Variant -// -// Copyright Michael Park, 2015-2017 -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -#ifndef MPARK_LIB_HPP -#define MPARK_LIB_HPP - -#include -#include -#include -#include - - -#define MPARK_RETURN(...) \ - noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) { return __VA_ARGS__; } - -namespace mpark { - namespace lib { - template - struct identity { using type = T; }; - - inline namespace cpp14 { - template - struct array { - constexpr const T &operator[](std::size_t index) const { - return data[index]; - } - - T data[N == 0 ? 1 : N]; - }; - - template - using add_pointer_t = typename std::add_pointer::type; - - template - using common_type_t = typename std::common_type::type; - - template - using decay_t = typename std::decay::type; - - template - using enable_if_t = typename std::enable_if::type; - - template - using remove_const_t = typename std::remove_const::type; - - template - using remove_reference_t = typename std::remove_reference::type; - - template - using remove_cvref_t = - typename std::remove_cv>::type; - - template - inline constexpr T &&forward(remove_reference_t &t) noexcept { - return static_cast(t); - } - - template - inline constexpr T &&forward(remove_reference_t &&t) noexcept { - static_assert(!std::is_lvalue_reference::value, - "can not forward an rvalue as an lvalue"); - return static_cast(t); - } - - template - inline constexpr remove_reference_t &&move(T &&t) noexcept { - return static_cast &&>(t); - } - -#ifdef MPARK_INTEGER_SEQUENCE - using std::integer_sequence; - using std::index_sequence; - using std::make_index_sequence; - using std::index_sequence_for; -#else - template - struct integer_sequence { - using value_type = T; - static constexpr std::size_t size() noexcept { return sizeof...(Is); } - }; - - template - using index_sequence = integer_sequence; - - template - struct make_index_sequence_concat; - - template - struct make_index_sequence_concat, - index_sequence> - : identity> {}; - - template - struct make_index_sequence_impl; - - template - using make_index_sequence = typename make_index_sequence_impl::type; - - template - struct make_index_sequence_impl - : make_index_sequence_concat, - make_index_sequence> {}; - - template <> - struct make_index_sequence_impl<0> : identity> {}; - - template <> - struct make_index_sequence_impl<1> : identity> {}; - - template - using index_sequence_for = make_index_sequence; -#endif - - // -#ifdef MPARK_TRANSPARENT_OPERATORS - using equal_to = std::equal_to<>; -#else - struct equal_to { - template - inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const - MPARK_RETURN(lib::forward(lhs) == lib::forward(rhs)) - }; -#endif - -#ifdef MPARK_TRANSPARENT_OPERATORS - using not_equal_to = std::not_equal_to<>; -#else - struct not_equal_to { - template - inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const - MPARK_RETURN(lib::forward(lhs) != lib::forward(rhs)) - }; -#endif - -#ifdef MPARK_TRANSPARENT_OPERATORS - using less = std::less<>; -#else - struct less { - template - inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const - MPARK_RETURN(lib::forward(lhs) < lib::forward(rhs)) - }; -#endif - -#ifdef MPARK_TRANSPARENT_OPERATORS - using greater = std::greater<>; -#else - struct greater { - template - inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const - MPARK_RETURN(lib::forward(lhs) > lib::forward(rhs)) - }; -#endif - -#ifdef MPARK_TRANSPARENT_OPERATORS - using less_equal = std::less_equal<>; -#else - struct less_equal { - template - inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const - MPARK_RETURN(lib::forward(lhs) <= lib::forward(rhs)) - }; -#endif - -#ifdef MPARK_TRANSPARENT_OPERATORS - using greater_equal = std::greater_equal<>; -#else - struct greater_equal { - template - inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const - MPARK_RETURN(lib::forward(lhs) >= lib::forward(rhs)) - }; -#endif - } // namespace cpp14 - - inline namespace cpp17 { - - // - template - using bool_constant = std::integral_constant; - - template - struct voider : identity {}; - - template - using void_t = typename voider::type; - - namespace detail { - namespace swappable { - - using std::swap; - - template - struct is_swappable { - private: - template (), - std::declval()))> - inline static std::true_type test(int); - - template - inline static std::false_type test(...); - - public: - static constexpr bool value = decltype(test(0))::value; - }; - - template - struct is_nothrow_swappable { - static constexpr bool value = - noexcept(swap(std::declval(), std::declval())); - }; - - template - struct is_nothrow_swappable : std::false_type {}; - - } // namespace swappable - } // namespace detail - - using detail::swappable::is_swappable; - - template - using is_nothrow_swappable = - detail::swappable::is_nothrow_swappable::value, T>; - - // - namespace detail { - - template - struct is_reference_wrapper : std::false_type {}; - - template - struct is_reference_wrapper> - : std::true_type {}; - - template - struct Invoke; - - template <> - struct Invoke { - template - inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) - MPARK_RETURN((lib::forward(arg).*pmf)(lib::forward(args)...)) - }; - - template <> - struct Invoke { - template - inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) - MPARK_RETURN((lib::forward(arg).get().*pmf)(lib::forward(args)...)) - }; - - template <> - struct Invoke { - template - inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) - MPARK_RETURN(((*lib::forward(arg)).*pmf)(lib::forward(args)...)) - }; - - template <> - struct Invoke { - template - inline static constexpr auto invoke(R T::*pmo, Arg &&arg) - MPARK_RETURN(lib::forward(arg).*pmo) - }; - - template <> - struct Invoke { - template - inline static constexpr auto invoke(R T::*pmo, Arg &&arg) - MPARK_RETURN(lib::forward(arg).get().*pmo) - }; - - template <> - struct Invoke { - template - inline static constexpr auto invoke(R T::*pmo, Arg &&arg) - MPARK_RETURN((*lib::forward(arg)).*pmo) - }; - - template - inline constexpr auto invoke(R T::*f, Arg &&arg, Args &&... args) - MPARK_RETURN( - Invoke::value, - (std::is_base_of>::value - ? 0 - : is_reference_wrapper>::value - ? 1 - : 2)>::invoke(f, - lib::forward(arg), - lib::forward(args)...)) - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4100) -#endif - template - inline constexpr auto invoke(F &&f, Args &&... args) - MPARK_RETURN(lib::forward(f)(lib::forward(args)...)) -#ifdef _MSC_VER -#pragma warning(pop) -#endif - } // namespace detail - - template - inline constexpr auto invoke(F &&f, Args &&... args) - MPARK_RETURN(detail::invoke(lib::forward(f), - lib::forward(args)...)) - - namespace detail { - - template - struct invoke_result {}; - - template - struct invoke_result(), std::declval()...))>, - F, - Args...> - : identity(), std::declval()...))> {}; - - } // namespace detail - - template - using invoke_result = detail::invoke_result; - - template - using invoke_result_t = typename invoke_result::type; - - namespace detail { - - template - struct is_invocable : std::false_type {}; - - template - struct is_invocable>, F, Args...> - : std::true_type {}; - - template - struct is_invocable_r : std::false_type {}; - - template - struct is_invocable_r>, - R, - F, - Args...> - : std::is_convertible, R> {}; - - } // namespace detail - - template - using is_invocable = detail::is_invocable; - - template - using is_invocable_r = detail::is_invocable_r; - - // -#ifdef MPARK_BUILTIN_ADDRESSOF - template - inline constexpr T *addressof(T &arg) noexcept { - return __builtin_addressof(arg); - } -#else - namespace detail { - - namespace has_addressof_impl { - - struct fail; - - template - inline fail operator&(T &&); - - template - inline static constexpr bool impl() { - return (std::is_class::value || std::is_union::value) && - !std::is_same()), fail>::value; - } - - } // namespace has_addressof_impl - - template - using has_addressof = bool_constant()>; - - template - inline constexpr T *addressof(T &arg, std::true_type) noexcept { - return std::addressof(arg); - } - - template - inline constexpr T *addressof(T &arg, std::false_type) noexcept { - return &arg; - } - - } // namespace detail - - template - inline constexpr T *addressof(T &arg) noexcept { - return detail::addressof(arg, detail::has_addressof{}); - } -#endif - - template - inline constexpr T *addressof(const T &&) = delete; - - } // namespace cpp17 - - template - struct remove_all_extents : identity {}; - - template - struct remove_all_extents> : remove_all_extents {}; - - template - using remove_all_extents_t = typename remove_all_extents::type; - - template - using size_constant = std::integral_constant; - - template - struct indexed_type : size_constant { using type = T; }; - - template - using all = std::is_same, - integer_sequence>; - -#ifdef MPARK_TYPE_PACK_ELEMENT - template - using type_pack_element_t = __type_pack_element; -#else - template - struct type_pack_element_impl { - private: - template - struct set; - - template - struct set> : indexed_type... {}; - - template - inline static std::enable_if impl(indexed_type); - - inline static std::enable_if impl(...); - - public: - using type = decltype(impl(set>{})); - }; - - template - using type_pack_element = typename type_pack_element_impl::type; - - template - using type_pack_element_t = typename type_pack_element::type; -#endif - -#ifdef MPARK_TRIVIALITY_TYPE_TRAITS - using std::is_trivially_copy_constructible; - using std::is_trivially_move_constructible; - using std::is_trivially_copy_assignable; - using std::is_trivially_move_assignable; -#else - template - struct is_trivially_copy_constructible - : bool_constant< - std::is_copy_constructible::value && __has_trivial_copy(T)> {}; - - template - struct is_trivially_move_constructible : bool_constant<__is_trivial(T)> {}; - - template - struct is_trivially_copy_assignable - : bool_constant< - std::is_copy_assignable::value && __has_trivial_assign(T)> {}; - - template - struct is_trivially_move_assignable : bool_constant<__is_trivial(T)> {}; -#endif - - template - struct dependent_type : T {}; - - template - struct push_back; - - template - using push_back_t = typename push_back::type; - - template - struct push_back, J> { - using type = index_sequence; - }; - - } // namespace lib -} // namespace mpark - -#undef MPARK_RETURN - -#endif // MPARK_LIB_HPP - - -namespace mpark { - -#ifdef MPARK_RETURN_TYPE_DEDUCTION - -#define AUTO auto -#define AUTO_RETURN(...) { return __VA_ARGS__; } - -#define AUTO_REFREF auto && -#define AUTO_REFREF_RETURN(...) { return __VA_ARGS__; } - -#define DECLTYPE_AUTO decltype(auto) -#define DECLTYPE_AUTO_RETURN(...) { return __VA_ARGS__; } - -#else - -#define AUTO auto -#define AUTO_RETURN(...) \ - -> lib::decay_t { return __VA_ARGS__; } - -#define AUTO_REFREF auto -#define AUTO_REFREF_RETURN(...) \ - -> decltype((__VA_ARGS__)) { \ - static_assert(std::is_reference::value, ""); \ - return __VA_ARGS__; \ - } - -#define DECLTYPE_AUTO auto -#define DECLTYPE_AUTO_RETURN(...) \ - -> decltype(__VA_ARGS__) { return __VA_ARGS__; } - -#endif - - class bad_variant_access : public std::exception { - public: - virtual const char *what() const noexcept override { return "bad_variant_access"; } - }; - - [[noreturn]] inline void throw_bad_variant_access() { -#ifdef MPARK_EXCEPTIONS - throw bad_variant_access{}; -#else - std::terminate(); - MPARK_BUILTIN_UNREACHABLE; -#endif - } - - template - class variant; - - template - struct variant_size; - -#ifdef MPARK_VARIABLE_TEMPLATES - template - constexpr std::size_t variant_size_v = variant_size::value; -#endif - - template - struct variant_size : variant_size {}; - - template - struct variant_size : variant_size {}; - - template - struct variant_size : variant_size {}; - - template - struct variant_size> : lib::size_constant {}; - - template - struct variant_alternative; - - template - using variant_alternative_t = typename variant_alternative::type; - - template - struct variant_alternative - : std::add_const> {}; - - template - struct variant_alternative - : std::add_volatile> {}; - - template - struct variant_alternative - : std::add_cv> {}; - - template - struct variant_alternative> { - static_assert(I < sizeof...(Ts), - "index out of bounds in `std::variant_alternative<>`"); - using type = lib::type_pack_element_t; - }; - - constexpr std::size_t variant_npos = static_cast(-1); - - namespace detail { - - constexpr std::size_t not_found = static_cast(-1); - constexpr std::size_t ambiguous = static_cast(-2); - -#ifdef MPARK_CPP14_CONSTEXPR - template - inline constexpr std::size_t find_index() { - constexpr lib::array matches = { - {std::is_same::value...} - }; - std::size_t result = not_found; - for (std::size_t i = 0; i < sizeof...(Ts); ++i) { - if (matches[i]) { - if (result != not_found) { - return ambiguous; - } - result = i; - } - } - return result; - } -#else - inline constexpr std::size_t find_index_impl(std::size_t result, - std::size_t) { - return result; - } - - template - inline constexpr std::size_t find_index_impl(std::size_t result, - std::size_t idx, - bool b, - Bs... bs) { - return b ? (result != not_found ? ambiguous - : find_index_impl(idx, idx + 1, bs...)) - : find_index_impl(result, idx + 1, bs...); - } - - template - inline constexpr std::size_t find_index() { - return find_index_impl(not_found, 0, std::is_same::value...); - } -#endif - - template - using find_index_sfinae_impl = - lib::enable_if_t>; - - template - using find_index_sfinae = find_index_sfinae_impl()>; - - template - struct find_index_checked_impl : lib::size_constant { - static_assert(I != not_found, "the specified type is not found."); - static_assert(I != ambiguous, "the specified type is ambiguous."); - }; - - template - using find_index_checked = find_index_checked_impl()>; - - struct valueless_t {}; - - enum class Trait { TriviallyAvailable, Available, Unavailable }; - - template class IsTriviallyAvailable, - template class IsAvailable> - inline constexpr Trait trait() { - return IsTriviallyAvailable::value - ? Trait::TriviallyAvailable - : IsAvailable::value ? Trait::Available - : Trait::Unavailable; - } - -#ifdef MPARK_CPP14_CONSTEXPR - template - inline constexpr Trait common_trait(Traits... traits_) { - Trait result = Trait::TriviallyAvailable; - lib::array traits = {{traits_...}}; - for (std::size_t i = 0; i < sizeof...(Traits); ++i) { - Trait t = traits[i]; - if (static_cast(t) > static_cast(result)) { - result = t; - } - } - return result; - } -#else - inline constexpr Trait common_trait_impl(Trait result) { return result; } - - template - inline constexpr Trait common_trait_impl(Trait result, - Trait t, - Traits... ts) { - return static_cast(t) > static_cast(result) - ? common_trait_impl(t, ts...) - : common_trait_impl(result, ts...); - } - - template - inline constexpr Trait common_trait(Traits... ts) { - return common_trait_impl(Trait::TriviallyAvailable, ts...); - } -#endif - - template - struct traits { - static constexpr Trait copy_constructible_trait = - common_trait(trait()...); - - static constexpr Trait move_constructible_trait = - common_trait(trait()...); - - static constexpr Trait copy_assignable_trait = - common_trait(copy_constructible_trait, - trait()...); - - static constexpr Trait move_assignable_trait = - common_trait(move_constructible_trait, - trait()...); - - static constexpr Trait destructible_trait = - common_trait(trait()...); - }; - - namespace access { - - struct recursive_union { -#ifdef MPARK_RETURN_TYPE_DEDUCTION - template - inline static constexpr auto &&get_alt(V &&v, in_place_index_t<0>) { - return lib::forward(v).head_; - } - - template - inline static constexpr auto &&get_alt(V &&v, in_place_index_t) { - return get_alt(lib::forward(v).tail_, in_place_index_t{}); - } -#else - template - struct get_alt_impl { - template - inline constexpr AUTO_REFREF operator()(V &&v) const - AUTO_REFREF_RETURN(get_alt_impl{}(lib::forward(v).tail_)) - }; - - template - struct get_alt_impl<0, Dummy> { - template - inline constexpr AUTO_REFREF operator()(V &&v) const - AUTO_REFREF_RETURN(lib::forward(v).head_) - }; - - template - inline static constexpr AUTO_REFREF get_alt(V &&v, in_place_index_t) - AUTO_REFREF_RETURN(get_alt_impl{}(lib::forward(v))) -#endif - }; - - struct base { - template - inline static constexpr AUTO_REFREF get_alt(V &&v) -#ifdef _MSC_VER - AUTO_REFREF_RETURN(recursive_union::get_alt( - lib::forward(v).data_, in_place_index_t{})) -#else - AUTO_REFREF_RETURN(recursive_union::get_alt( - data(lib::forward(v)), in_place_index_t{})) -#endif - }; - - struct variant { - template - inline static constexpr AUTO_REFREF get_alt(V &&v) - AUTO_REFREF_RETURN(base::get_alt(lib::forward(v).impl_)) - }; - - } // namespace access - - namespace visitation { - -#if defined(MPARK_CPP14_CONSTEXPR) && !defined(_MSC_VER) -#define MPARK_VARIANT_SWITCH_VISIT -#endif - - struct base { - template - using dispatch_result_t = decltype( - lib::invoke(std::declval(), - access::base::get_alt<0>(std::declval())...)); - - template - struct expected { - template - inline static constexpr bool but_got() { - return std::is_same::value; - } - }; - - template - struct visit_return_type_check { - static_assert( - expected::template but_got(), - "`visit` requires the visitor to have a single return type"); - - template - inline static constexpr DECLTYPE_AUTO invoke(Visitor &&visitor, - Alts &&... alts) - DECLTYPE_AUTO_RETURN(lib::invoke(lib::forward(visitor), - lib::forward(alts)...)) - }; - -#ifdef MPARK_VARIANT_SWITCH_VISIT - template - struct dispatcher; - - template - struct dispatcher { - template - MPARK_ALWAYS_INLINE static constexpr R dispatch( - F &&, typename ITs::type &&..., Vs &&...) { - MPARK_BUILTIN_UNREACHABLE; - } - - template - MPARK_ALWAYS_INLINE static constexpr R dispatch_case(F &&, Vs &&...) { - MPARK_BUILTIN_UNREACHABLE; - } - - template - MPARK_ALWAYS_INLINE static constexpr R dispatch_at(std::size_t, - F &&, - Vs &&...) { - MPARK_BUILTIN_UNREACHABLE; - } - }; - - template - struct dispatcher { - template - MPARK_ALWAYS_INLINE static constexpr R dispatch( - F &&f, typename ITs::type &&... visited_vs) { - using Expected = R; - using Actual = decltype(lib::invoke( - lib::forward(f), - access::base::get_alt( - lib::forward(visited_vs))...)); - return visit_return_type_check::invoke( - lib::forward(f), - access::base::get_alt( - lib::forward(visited_vs))...); - } - - template - MPARK_ALWAYS_INLINE static constexpr R dispatch( - F &&f, typename ITs::type &&... visited_vs, V &&v, Vs &&... vs) { -#define MPARK_DISPATCH(I) \ - dispatcher<(I < lib::decay_t::size()), \ - R, \ - ITs..., \ - lib::indexed_type>:: \ - template dispatch<0>(lib::forward(f), \ - lib::forward(visited_vs)..., \ - lib::forward(v), \ - lib::forward(vs)...) - -#define MPARK_DEFAULT(I) \ - dispatcher<(I < lib::decay_t::size()), R, ITs...>::template dispatch( \ - lib::forward(f), \ - lib::forward(visited_vs)..., \ - lib::forward(v), \ - lib::forward(vs)...) - - switch (v.index()) { - case B + 0: return MPARK_DISPATCH(B + 0); - case B + 1: return MPARK_DISPATCH(B + 1); - case B + 2: return MPARK_DISPATCH(B + 2); - case B + 3: return MPARK_DISPATCH(B + 3); - case B + 4: return MPARK_DISPATCH(B + 4); - case B + 5: return MPARK_DISPATCH(B + 5); - case B + 6: return MPARK_DISPATCH(B + 6); - case B + 7: return MPARK_DISPATCH(B + 7); - case B + 8: return MPARK_DISPATCH(B + 8); - case B + 9: return MPARK_DISPATCH(B + 9); - case B + 10: return MPARK_DISPATCH(B + 10); - case B + 11: return MPARK_DISPATCH(B + 11); - case B + 12: return MPARK_DISPATCH(B + 12); - case B + 13: return MPARK_DISPATCH(B + 13); - case B + 14: return MPARK_DISPATCH(B + 14); - case B + 15: return MPARK_DISPATCH(B + 15); - case B + 16: return MPARK_DISPATCH(B + 16); - case B + 17: return MPARK_DISPATCH(B + 17); - case B + 18: return MPARK_DISPATCH(B + 18); - case B + 19: return MPARK_DISPATCH(B + 19); - case B + 20: return MPARK_DISPATCH(B + 20); - case B + 21: return MPARK_DISPATCH(B + 21); - case B + 22: return MPARK_DISPATCH(B + 22); - case B + 23: return MPARK_DISPATCH(B + 23); - case B + 24: return MPARK_DISPATCH(B + 24); - case B + 25: return MPARK_DISPATCH(B + 25); - case B + 26: return MPARK_DISPATCH(B + 26); - case B + 27: return MPARK_DISPATCH(B + 27); - case B + 28: return MPARK_DISPATCH(B + 28); - case B + 29: return MPARK_DISPATCH(B + 29); - case B + 30: return MPARK_DISPATCH(B + 30); - case B + 31: return MPARK_DISPATCH(B + 31); - default: return MPARK_DEFAULT(B + 32); - } - -#undef MPARK_DEFAULT -#undef MPARK_DISPATCH - } - - template - MPARK_ALWAYS_INLINE static constexpr R dispatch_case(F &&f, - Vs &&... vs) { - using Expected = R; - using Actual = decltype( - lib::invoke(lib::forward(f), - access::base::get_alt(lib::forward(vs))...)); - return visit_return_type_check::invoke( - lib::forward(f), - access::base::get_alt(lib::forward(vs))...); - } - - template - MPARK_ALWAYS_INLINE static constexpr R dispatch_at(std::size_t index, - F &&f, - V &&v, - Vs &&... vs) { - static_assert(lib::all<(lib::decay_t::size() == - lib::decay_t::size())...>::value, - "all of the variants must be the same size."); -#define MPARK_DISPATCH_AT(I) \ - dispatcher<(I < lib::decay_t::size()), R>::template dispatch_case( \ - lib::forward(f), lib::forward(v), lib::forward(vs)...) - -#define MPARK_DEFAULT(I) \ - dispatcher<(I < lib::decay_t::size()), R>::template dispatch_at( \ - index, lib::forward(f), lib::forward(v), lib::forward(vs)...) - - switch (index) { - case B + 0: return MPARK_DISPATCH_AT(B + 0); - case B + 1: return MPARK_DISPATCH_AT(B + 1); - case B + 2: return MPARK_DISPATCH_AT(B + 2); - case B + 3: return MPARK_DISPATCH_AT(B + 3); - case B + 4: return MPARK_DISPATCH_AT(B + 4); - case B + 5: return MPARK_DISPATCH_AT(B + 5); - case B + 6: return MPARK_DISPATCH_AT(B + 6); - case B + 7: return MPARK_DISPATCH_AT(B + 7); - case B + 8: return MPARK_DISPATCH_AT(B + 8); - case B + 9: return MPARK_DISPATCH_AT(B + 9); - case B + 10: return MPARK_DISPATCH_AT(B + 10); - case B + 11: return MPARK_DISPATCH_AT(B + 11); - case B + 12: return MPARK_DISPATCH_AT(B + 12); - case B + 13: return MPARK_DISPATCH_AT(B + 13); - case B + 14: return MPARK_DISPATCH_AT(B + 14); - case B + 15: return MPARK_DISPATCH_AT(B + 15); - case B + 16: return MPARK_DISPATCH_AT(B + 16); - case B + 17: return MPARK_DISPATCH_AT(B + 17); - case B + 18: return MPARK_DISPATCH_AT(B + 18); - case B + 19: return MPARK_DISPATCH_AT(B + 19); - case B + 20: return MPARK_DISPATCH_AT(B + 20); - case B + 21: return MPARK_DISPATCH_AT(B + 21); - case B + 22: return MPARK_DISPATCH_AT(B + 22); - case B + 23: return MPARK_DISPATCH_AT(B + 23); - case B + 24: return MPARK_DISPATCH_AT(B + 24); - case B + 25: return MPARK_DISPATCH_AT(B + 25); - case B + 26: return MPARK_DISPATCH_AT(B + 26); - case B + 27: return MPARK_DISPATCH_AT(B + 27); - case B + 28: return MPARK_DISPATCH_AT(B + 28); - case B + 29: return MPARK_DISPATCH_AT(B + 29); - case B + 30: return MPARK_DISPATCH_AT(B + 30); - case B + 31: return MPARK_DISPATCH_AT(B + 31); - default: return MPARK_DEFAULT(B + 32); - } - -#undef MPARK_DEFAULT -#undef MPARK_DISPATCH_AT - } - }; -#else - template - inline static constexpr const T &at(const T &elem) noexcept { - return elem; - } - - template - inline static constexpr const lib::remove_all_extents_t &at( - const lib::array &elems, std::size_t i, Is... is) noexcept { - return at(elems[i], is...); - } - - template - inline static constexpr lib::array, sizeof...(Fs) + 1> - make_farray(F &&f, Fs &&... fs) { - return {{lib::forward(f), lib::forward(fs)...}}; - } - - template - struct make_fmatrix_impl { - - template - inline static constexpr dispatch_result_t dispatch( - F &&f, Vs &&... vs) { - using Expected = dispatch_result_t; - using Actual = decltype(lib::invoke( - lib::forward(f), - access::base::get_alt(lib::forward(vs))...)); - return visit_return_type_check::invoke( - lib::forward(f), - access::base::get_alt(lib::forward(vs))...); - } - -#ifdef MPARK_RETURN_TYPE_DEDUCTION - template - inline static constexpr auto impl(lib::index_sequence) { - return &dispatch; - } - - template - inline static constexpr auto impl(Is, - lib::index_sequence, - Ls... ls) { - return make_farray(impl(lib::push_back_t{}, ls...)...); - } -#else - template - struct impl; - - template - struct impl> { - inline constexpr AUTO operator()() const - AUTO_RETURN(&dispatch) - }; - - template - struct impl, Ls...> { - inline constexpr AUTO operator()() const - AUTO_RETURN( - make_farray(impl, Ls...>{}()...)) - }; -#endif - }; - -#ifdef MPARK_RETURN_TYPE_DEDUCTION - template - inline static constexpr auto make_fmatrix() { - return make_fmatrix_impl::impl( - lib::index_sequence<>{}, - lib::make_index_sequence::size()>{}...); - } -#else - template - inline static constexpr AUTO make_fmatrix() - AUTO_RETURN( - typename make_fmatrix_impl::template impl< - lib::index_sequence<>, - lib::make_index_sequence::size()>...>{}()) -#endif - - template - struct make_fdiagonal_impl { - template - inline static constexpr dispatch_result_t dispatch( - F &&f, Vs &&... vs) { - using Expected = dispatch_result_t; - using Actual = decltype( - lib::invoke(lib::forward(f), - access::base::get_alt(lib::forward(vs))...)); - return visit_return_type_check::invoke( - lib::forward(f), - access::base::get_alt(lib::forward(vs))...); - } - - template - inline static constexpr AUTO impl(lib::index_sequence) - AUTO_RETURN(make_farray(&dispatch...)) - }; - - template - inline static constexpr auto make_fdiagonal() - -> decltype(make_fdiagonal_impl::impl( - lib::make_index_sequence::size()>{})) { - static_assert(lib::all<(lib::decay_t::size() == - lib::decay_t::size())...>::value, - "all of the variants must be the same size."); - return make_fdiagonal_impl::impl( - lib::make_index_sequence::size()>{}); - } -#endif - }; - -#if !defined(MPARK_VARIANT_SWITCH_VISIT) && \ - (!defined(_MSC_VER) || _MSC_VER >= 1910) - template - using fmatrix_t = decltype(base::make_fmatrix()); - - template - struct fmatrix { - static constexpr fmatrix_t value = - base::make_fmatrix(); - }; - - template - constexpr fmatrix_t fmatrix::value; - - template - using fdiagonal_t = decltype(base::make_fdiagonal()); - - template - struct fdiagonal { - static constexpr fdiagonal_t value = - base::make_fdiagonal(); - }; - - template - constexpr fdiagonal_t fdiagonal::value; -#endif - - struct alt { - template - inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, - Vs &&... vs) -#ifdef MPARK_VARIANT_SWITCH_VISIT - DECLTYPE_AUTO_RETURN( - base::dispatcher< - true, - base::dispatch_result_t(vs)))...>>:: - template dispatch<0>(lib::forward(visitor), - as_base(lib::forward(vs))...)) -#elif !defined(_MSC_VER) || _MSC_VER >= 1910 - DECLTYPE_AUTO_RETURN(base::at( - fmatrix(vs)))...>::value, - vs.index()...)(lib::forward(visitor), - as_base(lib::forward(vs))...)) -#else - DECLTYPE_AUTO_RETURN(base::at( - base::make_fmatrix(vs)))...>(), - vs.index()...)(lib::forward(visitor), - as_base(lib::forward(vs))...)) -#endif - - template - inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, - Visitor &&visitor, - Vs &&... vs) -#ifdef MPARK_VARIANT_SWITCH_VISIT - DECLTYPE_AUTO_RETURN( - base::dispatcher< - true, - base::dispatch_result_t(vs)))...>>:: - template dispatch_at<0>(index, - lib::forward(visitor), - as_base(lib::forward(vs))...)) -#elif !defined(_MSC_VER) || _MSC_VER >= 1910 - DECLTYPE_AUTO_RETURN(base::at( - fdiagonal(vs)))...>::value, - index)(lib::forward(visitor), - as_base(lib::forward(vs))...)) -#else - DECLTYPE_AUTO_RETURN(base::at( - base::make_fdiagonal(vs)))...>(), - index)(lib::forward(visitor), - as_base(lib::forward(vs))...)) -#endif - }; - - struct variant { - private: - template - struct visitor { - template - inline static constexpr bool does_not_handle() { - return lib::is_invocable::value; - } - }; - - template - struct visit_exhaustiveness_check { - static_assert(visitor::template does_not_handle(), - "`visit` requires the visitor to be exhaustive."); - - inline static constexpr DECLTYPE_AUTO invoke(Visitor &&visitor, - Values &&... values) - DECLTYPE_AUTO_RETURN(lib::invoke(lib::forward(visitor), - lib::forward(values)...)) - }; - - template - struct value_visitor { - Visitor &&visitor_; - - template - inline constexpr DECLTYPE_AUTO operator()(Alts &&... alts) const - DECLTYPE_AUTO_RETURN( - visit_exhaustiveness_check< - Visitor, - decltype((lib::forward(alts).value))...>:: - invoke(lib::forward(visitor_), - lib::forward(alts).value...)) - }; - - template - inline static constexpr AUTO make_value_visitor(Visitor &&visitor) - AUTO_RETURN(value_visitor{lib::forward(visitor)}) - - public: - template - inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, - Vs &&... vs) - DECLTYPE_AUTO_RETURN(alt::visit_alt(lib::forward(visitor), - lib::forward(vs).impl_...)) - - template - inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, - Visitor &&visitor, - Vs &&... vs) - DECLTYPE_AUTO_RETURN( - alt::visit_alt_at(index, - lib::forward(visitor), - lib::forward(vs).impl_...)) - - template - inline static constexpr DECLTYPE_AUTO visit_value(Visitor &&visitor, - Vs &&... vs) - DECLTYPE_AUTO_RETURN( - visit_alt(make_value_visitor(lib::forward(visitor)), - lib::forward(vs)...)) - - template - inline static constexpr DECLTYPE_AUTO visit_value_at(std::size_t index, - Visitor &&visitor, - Vs &&... vs) - DECLTYPE_AUTO_RETURN( - visit_alt_at(index, - make_value_visitor(lib::forward(visitor)), - lib::forward(vs)...)) - }; - - } // namespace visitation - - template - struct alt { - using value_type = T; - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4244) -#endif - template - inline explicit constexpr alt(in_place_t, Args &&... args) - : value(lib::forward(args)...) {} -#ifdef _MSC_VER -#pragma warning(pop) -#endif - - T value; - }; - - template - union recursive_union; - - template - union recursive_union {}; - -#define MPARK_VARIANT_RECURSIVE_UNION(destructible_trait, destructor) \ - template \ - union recursive_union { \ - public: \ - inline explicit constexpr recursive_union(valueless_t) noexcept \ - : dummy_{} {} \ - \ - template \ - inline explicit constexpr recursive_union(in_place_index_t<0>, \ - Args &&... args) \ - : head_(in_place_t{}, lib::forward(args)...) {} \ - \ - template \ - inline explicit constexpr recursive_union(in_place_index_t, \ - Args &&... args) \ - : tail_(in_place_index_t{}, lib::forward(args)...) {} \ - \ - recursive_union(const recursive_union &) = default; \ - recursive_union(recursive_union &&) = default; \ - \ - destructor \ - \ - recursive_union &operator=(const recursive_union &) = default; \ - recursive_union &operator=(recursive_union &&) = default; \ - \ - private: \ - char dummy_; \ - alt head_; \ - recursive_union tail_; \ - \ - friend struct access::recursive_union; \ - } - - MPARK_VARIANT_RECURSIVE_UNION(Trait::TriviallyAvailable, - ~recursive_union() = default;); - MPARK_VARIANT_RECURSIVE_UNION(Trait::Available, - ~recursive_union() {}); - MPARK_VARIANT_RECURSIVE_UNION(Trait::Unavailable, - ~recursive_union() = delete;); - -#undef MPARK_VARIANT_RECURSIVE_UNION - - template - using index_t = typename std::conditional< - sizeof...(Ts) < (std::numeric_limits::max)(), - unsigned char, - typename std::conditional< - sizeof...(Ts) < (std::numeric_limits::max)(), - unsigned short, - unsigned int>::type - >::type; - - template - class base { - public: - inline explicit constexpr base(valueless_t tag) noexcept - : data_(tag), index_(static_cast>(-1)) {} - - template - inline explicit constexpr base(in_place_index_t, Args &&... args) - : data_(in_place_index_t{}, lib::forward(args)...), - index_(I) {} - - inline constexpr bool valueless_by_exception() const noexcept { - return index_ == static_cast>(-1); - } - - inline constexpr std::size_t index() const noexcept { - return valueless_by_exception() ? variant_npos : index_; - } - - protected: - using data_t = recursive_union; - - friend inline constexpr base &as_base(base &b) { return b; } - friend inline constexpr const base &as_base(const base &b) { return b; } - friend inline constexpr base &&as_base(base &&b) { return lib::move(b); } - friend inline constexpr const base &&as_base(const base &&b) { return lib::move(b); } - - friend inline constexpr data_t &data(base &b) { return b.data_; } - friend inline constexpr const data_t &data(const base &b) { return b.data_; } - friend inline constexpr data_t &&data(base &&b) { return lib::move(b).data_; } - friend inline constexpr const data_t &&data(const base &&b) { return lib::move(b).data_; } - - inline static constexpr std::size_t size() { return sizeof...(Ts); } - - data_t data_; - index_t index_; - - friend struct access::base; - friend struct visitation::base; - }; - - struct dtor { -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4100) -#endif - template - inline void operator()(Alt &alt) const noexcept { alt.~Alt(); } -#ifdef _MSC_VER -#pragma warning(pop) -#endif - }; - -#if !defined(_MSC_VER) || _MSC_VER >= 1910 -#define MPARK_INHERITING_CTOR(type, base) using base::base; -#else -#define MPARK_INHERITING_CTOR(type, base) \ - template \ - inline explicit constexpr type(Args &&... args) \ - : base(lib::forward(args)...) {} -#endif - - template - class destructor; - -#define MPARK_VARIANT_DESTRUCTOR(destructible_trait, definition, destroy) \ - template \ - class destructor, destructible_trait> \ - : public base { \ - using super = base; \ - \ - public: \ - MPARK_INHERITING_CTOR(destructor, super) \ - using super::operator=; \ - \ - destructor(const destructor &) = default; \ - destructor(destructor &&) = default; \ - definition \ - destructor &operator=(const destructor &) = default; \ - destructor &operator=(destructor &&) = default; \ - \ - protected: \ - destroy \ - } - - MPARK_VARIANT_DESTRUCTOR( - Trait::TriviallyAvailable, - ~destructor() = default;, - inline void destroy() noexcept { - this->index_ = static_cast>(-1); - }); - - MPARK_VARIANT_DESTRUCTOR( - Trait::Available, - ~destructor() { destroy(); }, - inline void destroy() noexcept { - if (!this->valueless_by_exception()) { - visitation::alt::visit_alt(dtor{}, *this); - } - this->index_ = static_cast>(-1); - }); - - MPARK_VARIANT_DESTRUCTOR( - Trait::Unavailable, - ~destructor() = delete;, - inline void destroy() noexcept = delete;); - -#undef MPARK_VARIANT_DESTRUCTOR - - template - class constructor : public destructor { - using super = destructor; - - public: - MPARK_INHERITING_CTOR(constructor, super) - using super::operator=; - - protected: -#ifndef MPARK_GENERIC_LAMBDAS - struct ctor { - template - inline void operator()(LhsAlt &lhs_alt, RhsAlt &&rhs_alt) const { - constructor::construct_alt(lhs_alt, - lib::forward(rhs_alt).value); - } - }; -#endif - - template - inline static T &construct_alt(alt &a, Args &&... args) { - auto *result = ::new (static_cast(lib::addressof(a))) - alt(in_place_t{}, lib::forward(args)...); - return result->value; - } - - template - inline static void generic_construct(constructor &lhs, Rhs &&rhs) { - lhs.destroy(); - if (!rhs.valueless_by_exception()) { - visitation::alt::visit_alt_at( - rhs.index(), -#ifdef MPARK_GENERIC_LAMBDAS - [](auto &lhs_alt, auto &&rhs_alt) { - constructor::construct_alt( - lhs_alt, lib::forward(rhs_alt).value); - } -#else - ctor{} -#endif - , - lhs, - lib::forward(rhs)); - lhs.index_ = rhs.index_; - } - } - }; - - template - class move_constructor; - -#define MPARK_VARIANT_MOVE_CONSTRUCTOR(move_constructible_trait, definition) \ - template \ - class move_constructor, move_constructible_trait> \ - : public constructor> { \ - using super = constructor>; \ - \ - public: \ - MPARK_INHERITING_CTOR(move_constructor, super) \ - using super::operator=; \ - \ - move_constructor(const move_constructor &) = default; \ - definition \ - ~move_constructor() = default; \ - move_constructor &operator=(const move_constructor &) = default; \ - move_constructor &operator=(move_constructor &&) = default; \ - } - - MPARK_VARIANT_MOVE_CONSTRUCTOR( - Trait::TriviallyAvailable, - move_constructor(move_constructor &&that) = default;); - - MPARK_VARIANT_MOVE_CONSTRUCTOR( - Trait::Available, - move_constructor(move_constructor &&that) noexcept( - lib::all::value...>::value) - : move_constructor(valueless_t{}) { - this->generic_construct(*this, lib::move(that)); - }); - - MPARK_VARIANT_MOVE_CONSTRUCTOR( - Trait::Unavailable, - move_constructor(move_constructor &&) = delete;); - -#undef MPARK_VARIANT_MOVE_CONSTRUCTOR - - template - class copy_constructor; - -#define MPARK_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait, definition) \ - template \ - class copy_constructor, copy_constructible_trait> \ - : public move_constructor> { \ - using super = move_constructor>; \ - \ - public: \ - MPARK_INHERITING_CTOR(copy_constructor, super) \ - using super::operator=; \ - \ - definition \ - copy_constructor(copy_constructor &&) = default; \ - ~copy_constructor() = default; \ - copy_constructor &operator=(const copy_constructor &) = default; \ - copy_constructor &operator=(copy_constructor &&) = default; \ - } - - MPARK_VARIANT_COPY_CONSTRUCTOR( - Trait::TriviallyAvailable, - copy_constructor(const copy_constructor &that) = default;); - - MPARK_VARIANT_COPY_CONSTRUCTOR( - Trait::Available, - copy_constructor(const copy_constructor &that) - : copy_constructor(valueless_t{}) { - this->generic_construct(*this, that); - }); - - MPARK_VARIANT_COPY_CONSTRUCTOR( - Trait::Unavailable, - copy_constructor(const copy_constructor &) = delete;); - -#undef MPARK_VARIANT_COPY_CONSTRUCTOR - - template - class assignment : public copy_constructor { - using super = copy_constructor; - - public: - MPARK_INHERITING_CTOR(assignment, super) - using super::operator=; - - template - inline /* auto & */ auto emplace(Args &&... args) - -> decltype(this->construct_alt(access::base::get_alt(*this), - lib::forward(args)...)) { - this->destroy(); - auto &result = this->construct_alt(access::base::get_alt(*this), - lib::forward(args)...); - this->index_ = I; - return result; - } - - protected: -#ifndef MPARK_GENERIC_LAMBDAS - template - struct assigner { - template - inline void operator()(ThisAlt &this_alt, ThatAlt &&that_alt) const { - self->assign_alt(this_alt, lib::forward(that_alt).value); - } - assignment *self; - }; -#endif - - template - inline void assign_alt(alt &a, Arg &&arg) { - if (this->index() == I) { -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4244) -#endif - a.value = lib::forward(arg); -#ifdef _MSC_VER -#pragma warning(pop) -#endif - } else { - struct { - void operator()(std::true_type) const { - this_->emplace(lib::forward(arg_)); - } - void operator()(std::false_type) const { - this_->emplace(T(lib::forward(arg_))); - } - assignment *this_; - Arg &&arg_; - } impl{this, lib::forward(arg)}; - impl(lib::bool_constant< - std::is_nothrow_constructible::value || - !std::is_nothrow_move_constructible::value>{}); - } - } - - template - inline void generic_assign(That &&that) { - if (this->valueless_by_exception() && that.valueless_by_exception()) { - // do nothing. - } else if (that.valueless_by_exception()) { - this->destroy(); - } else { - visitation::alt::visit_alt_at( - that.index(), -#ifdef MPARK_GENERIC_LAMBDAS - [this](auto &this_alt, auto &&that_alt) { - this->assign_alt( - this_alt, lib::forward(that_alt).value); - } -#else - assigner{this} -#endif - , - *this, - lib::forward(that)); - } - } - }; - - template - class move_assignment; - -#define MPARK_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, definition) \ - template \ - class move_assignment, move_assignable_trait> \ - : public assignment> { \ - using super = assignment>; \ - \ - public: \ - MPARK_INHERITING_CTOR(move_assignment, super) \ - using super::operator=; \ - \ - move_assignment(const move_assignment &) = default; \ - move_assignment(move_assignment &&) = default; \ - ~move_assignment() = default; \ - move_assignment &operator=(const move_assignment &) = default; \ - definition \ - } - - MPARK_VARIANT_MOVE_ASSIGNMENT( - Trait::TriviallyAvailable, - move_assignment &operator=(move_assignment &&that) = default;); - - MPARK_VARIANT_MOVE_ASSIGNMENT( - Trait::Available, - move_assignment & - operator=(move_assignment &&that) noexcept( - lib::all<(std::is_nothrow_move_constructible::value && - std::is_nothrow_move_assignable::value)...>::value) { - this->generic_assign(lib::move(that)); - return *this; - }); - - MPARK_VARIANT_MOVE_ASSIGNMENT( - Trait::Unavailable, - move_assignment &operator=(move_assignment &&) = delete;); - -#undef MPARK_VARIANT_MOVE_ASSIGNMENT - - template - class copy_assignment; - -#define MPARK_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, definition) \ - template \ - class copy_assignment, copy_assignable_trait> \ - : public move_assignment> { \ - using super = move_assignment>; \ - \ - public: \ - MPARK_INHERITING_CTOR(copy_assignment, super) \ - using super::operator=; \ - \ - copy_assignment(const copy_assignment &) = default; \ - copy_assignment(copy_assignment &&) = default; \ - ~copy_assignment() = default; \ - definition \ - copy_assignment &operator=(copy_assignment &&) = default; \ - } - - MPARK_VARIANT_COPY_ASSIGNMENT( - Trait::TriviallyAvailable, - copy_assignment &operator=(const copy_assignment &that) = default;); - - MPARK_VARIANT_COPY_ASSIGNMENT( - Trait::Available, - copy_assignment &operator=(const copy_assignment &that) { - this->generic_assign(that); - return *this; - }); - - MPARK_VARIANT_COPY_ASSIGNMENT( - Trait::Unavailable, - copy_assignment &operator=(const copy_assignment &) = delete;); - -#undef MPARK_VARIANT_COPY_ASSIGNMENT - - template - class impl : public copy_assignment> { - using super = copy_assignment>; - - public: - MPARK_INHERITING_CTOR(impl, super) - using super::operator=; - - impl(const impl&) = default; - impl(impl&&) = default; - ~impl() = default; - impl &operator=(const impl &) = default; - impl &operator=(impl &&) = default; - - template - inline void assign(Arg &&arg) { - this->assign_alt(access::base::get_alt(*this), - lib::forward(arg)); - } - - inline void swap(impl &that) { - if (this->valueless_by_exception() && that.valueless_by_exception()) { - // do nothing. - } else if (this->index() == that.index()) { - visitation::alt::visit_alt_at(this->index(), -#ifdef MPARK_GENERIC_LAMBDAS - [](auto &this_alt, auto &that_alt) { - using std::swap; - swap(this_alt.value, - that_alt.value); - } -#else - swapper{} -#endif - , - *this, - that); - } else { - impl *lhs = this; - impl *rhs = lib::addressof(that); - if (lhs->move_nothrow() && !rhs->move_nothrow()) { - std::swap(lhs, rhs); - } - impl tmp(lib::move(*rhs)); -#ifdef MPARK_EXCEPTIONS - // EXTENSION: When the move construction of `lhs` into `rhs` throws - // and `tmp` is nothrow move constructible then we move `tmp` back - // into `rhs` and provide the strong exception safety guarantee. - try { - this->generic_construct(*rhs, lib::move(*lhs)); - } catch (...) { - if (tmp.move_nothrow()) { - this->generic_construct(*rhs, lib::move(tmp)); - } - throw; - } -#else - this->generic_construct(*rhs, lib::move(*lhs)); -#endif - this->generic_construct(*lhs, lib::move(tmp)); - } - } - - private: -#ifndef MPARK_GENERIC_LAMBDAS - struct swapper { - template - inline void operator()(ThisAlt &this_alt, ThatAlt &that_alt) const { - using std::swap; - swap(this_alt.value, that_alt.value); - } - }; -#endif - - inline constexpr bool move_nothrow() const { - return this->valueless_by_exception() || - lib::array{ - {std::is_nothrow_move_constructible::value...} - }[this->index()]; - } - }; - -#undef MPARK_INHERITING_CTOR - - template - struct is_non_narrowing_convertible { - template - static std::true_type test(T(&&)[1]); - - template - static auto impl(int) -> decltype(test({std::declval()})); - - template - static auto impl(...) -> std::false_type; - - static constexpr bool value = decltype(impl(0))::value; - }; - - template ::value, - typename = void> - struct overload_leaf {}; - - template - struct overload_leaf { - using impl = lib::size_constant (*)(T); - operator impl() const { return nullptr; }; - }; - - template - struct overload_leaf< - Arg, - I, - T, - true -#if defined(__clang__) || !defined(__GNUC__) || __GNUC__ >= 5 - , - lib::enable_if_t< - std::is_same, bool>::value - ? std::is_same, bool>::value - : is_non_narrowing_convertible::value> -#endif - > { - using impl = lib::size_constant (*)(T); - operator impl() const { return nullptr; }; - }; - - template - struct overload_impl { - private: - template - struct impl; - - template - struct impl> : overload_leaf... {}; - - public: - using type = impl>; - }; - - template - using overload = typename overload_impl::type; - - template - using best_match = lib::invoke_result_t, Arg>; - - template - struct is_in_place_index : std::false_type {}; - - template - struct is_in_place_index> : std::true_type {}; - - template - struct is_in_place_type : std::false_type {}; - - template - struct is_in_place_type> : std::true_type {}; - - } // detail - - template - class variant { - static_assert(0 < sizeof...(Ts), - "variant must consist of at least one alternative."); - - static_assert(lib::all::value...>::value, - "variant can not have an array type as an alternative."); - - static_assert(lib::all::value...>::value, - "variant can not have a reference type as an alternative."); - - static_assert(lib::all::value...>::value, - "variant can not have a void type as an alternative."); - - public: - template < - typename Front = lib::type_pack_element_t<0, Ts...>, - lib::enable_if_t::value, int> = 0> - inline constexpr variant() noexcept( - std::is_nothrow_default_constructible::value) - : impl_(in_place_index_t<0>{}) {} - - variant(const variant &) = default; - variant(variant &&) = default; - - template < - typename Arg, - typename Decayed = lib::decay_t, - lib::enable_if_t::value, int> = 0, - lib::enable_if_t::value, int> = 0, - lib::enable_if_t::value, int> = 0, - std::size_t I = detail::best_match::value, - typename T = lib::type_pack_element_t, - lib::enable_if_t::value, int> = 0> - inline constexpr variant(Arg &&arg) noexcept( - std::is_nothrow_constructible::value) - : impl_(in_place_index_t{}, lib::forward(arg)) {} - - template < - std::size_t I, - typename... Args, - typename T = lib::type_pack_element_t, - lib::enable_if_t::value, int> = 0> - inline explicit constexpr variant( - in_place_index_t, - Args &&... args) noexcept(std::is_nothrow_constructible::value) - : impl_(in_place_index_t{}, lib::forward(args)...) {} - - template < - std::size_t I, - typename Up, - typename... Args, - typename T = lib::type_pack_element_t, - lib::enable_if_t &, - Args...>::value, - int> = 0> - inline explicit constexpr variant( - in_place_index_t, - std::initializer_list il, - Args &&... args) noexcept(std:: - is_nothrow_constructible< - T, - std::initializer_list &, - Args...>::value) - : impl_(in_place_index_t{}, il, lib::forward(args)...) {} - - template < - typename T, - typename... Args, - std::size_t I = detail::find_index_sfinae::value, - lib::enable_if_t::value, int> = 0> - inline explicit constexpr variant( - in_place_type_t, - Args &&... args) noexcept(std::is_nothrow_constructible::value) - : impl_(in_place_index_t{}, lib::forward(args)...) {} - - template < - typename T, - typename Up, - typename... Args, - std::size_t I = detail::find_index_sfinae::value, - lib::enable_if_t &, - Args...>::value, - int> = 0> - inline explicit constexpr variant( - in_place_type_t, - std::initializer_list il, - Args &&... args) noexcept(std:: - is_nothrow_constructible< - T, - std::initializer_list &, - Args...>::value) - : impl_(in_place_index_t{}, il, lib::forward(args)...) {} - - ~variant() = default; - - variant &operator=(const variant &) = default; - variant &operator=(variant &&) = default; - - template , variant>::value, - int> = 0, - std::size_t I = detail::best_match::value, - typename T = lib::type_pack_element_t, - lib::enable_if_t<(std::is_assignable::value && - std::is_constructible::value), - int> = 0> - inline variant &operator=(Arg &&arg) noexcept( - (std::is_nothrow_assignable::value && - std::is_nothrow_constructible::value)) { - impl_.template assign(lib::forward(arg)); - return *this; - } - - template < - std::size_t I, - typename... Args, - typename T = lib::type_pack_element_t, - lib::enable_if_t::value, int> = 0> - inline T &emplace(Args &&... args) { - return impl_.template emplace(lib::forward(args)...); - } - - template < - std::size_t I, - typename Up, - typename... Args, - typename T = lib::type_pack_element_t, - lib::enable_if_t &, - Args...>::value, - int> = 0> - inline T &emplace(std::initializer_list il, Args &&... args) { - return impl_.template emplace(il, lib::forward(args)...); - } - - template < - typename T, - typename... Args, - std::size_t I = detail::find_index_sfinae::value, - lib::enable_if_t::value, int> = 0> - inline T &emplace(Args &&... args) { - return impl_.template emplace(lib::forward(args)...); - } - - template < - typename T, - typename Up, - typename... Args, - std::size_t I = detail::find_index_sfinae::value, - lib::enable_if_t &, - Args...>::value, - int> = 0> - inline T &emplace(std::initializer_list il, Args &&... args) { - return impl_.template emplace(il, lib::forward(args)...); - } - - inline constexpr bool valueless_by_exception() const noexcept { - return impl_.valueless_by_exception(); - } - - inline constexpr std::size_t index() const noexcept { - return impl_.index(); - } - - template , - Dummy>::value && - lib::dependent_type, - Dummy>::value)...>::value, - int> = 0> - inline void swap(variant &that) noexcept( - lib::all<(std::is_nothrow_move_constructible::value && - lib::is_nothrow_swappable::value)...>::value) { - impl_.swap(that.impl_); - } - - private: - detail::impl impl_; - - friend struct detail::access::variant; - friend struct detail::visitation::variant; - }; - - template - inline constexpr bool holds_alternative(const variant &v) noexcept { - return v.index() == I; - } - - template - inline constexpr bool holds_alternative(const variant &v) noexcept { - return holds_alternative::value>(v); - } - - namespace detail { - template - struct generic_get_impl { - constexpr generic_get_impl(int) noexcept {} - - constexpr AUTO_REFREF operator()(V &&v) const - AUTO_REFREF_RETURN( - access::variant::get_alt(lib::forward(v)).value) - }; - - template - inline constexpr AUTO_REFREF generic_get(V &&v) - AUTO_REFREF_RETURN(generic_get_impl( - holds_alternative(v) ? 0 : (throw_bad_variant_access(), 0))( - lib::forward(v))) - } // namespace detail - - template - inline constexpr variant_alternative_t> &get( - variant &v) { - return detail::generic_get(v); - } - - template - inline constexpr variant_alternative_t> &&get( - variant &&v) { - return detail::generic_get(lib::move(v)); - } - - template - inline constexpr const variant_alternative_t> &get( - const variant &v) { - return detail::generic_get(v); - } - - template - inline constexpr const variant_alternative_t> &&get( - const variant &&v) { - return detail::generic_get(lib::move(v)); - } - - template - inline constexpr T &get(variant &v) { - return get::value>(v); - } - - template - inline constexpr T &&get(variant &&v) { - return get::value>(lib::move(v)); - } - - template - inline constexpr const T &get(const variant &v) { - return get::value>(v); - } - - template - inline constexpr const T &&get(const variant &&v) { - return get::value>(lib::move(v)); - } - - namespace detail { - - template - inline constexpr /* auto * */ AUTO generic_get_if(V *v) noexcept - AUTO_RETURN(v && holds_alternative(*v) - ? lib::addressof(access::variant::get_alt(*v).value) - : nullptr) - - } // namespace detail - - template - inline constexpr lib::add_pointer_t>> - get_if(variant *v) noexcept { - return detail::generic_get_if(v); - } - - template - inline constexpr lib::add_pointer_t< - const variant_alternative_t>> - get_if(const variant *v) noexcept { - return detail::generic_get_if(v); - } - - template - inline constexpr lib::add_pointer_t - get_if(variant *v) noexcept { - return get_if::value>(v); - } - - template - inline constexpr lib::add_pointer_t - get_if(const variant *v) noexcept { - return get_if::value>(v); - } - - namespace detail { - template - struct convert_to_bool { - template - inline constexpr bool operator()(Lhs &&lhs, Rhs &&rhs) const { - static_assert(std::is_convertible, - bool>::value, - "relational operators must return a type" - " implicitly convertible to bool"); - return lib::invoke( - RelOp{}, lib::forward(lhs), lib::forward(rhs)); - } - }; - } // namespace detail - - template - inline constexpr bool operator==(const variant &lhs, - const variant &rhs) { - using detail::visitation::variant; - using equal_to = detail::convert_to_bool; -#ifdef MPARK_CPP14_CONSTEXPR - if (lhs.index() != rhs.index()) return false; - if (lhs.valueless_by_exception()) return true; - return variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs); -#else - return lhs.index() == rhs.index() && - (lhs.valueless_by_exception() || - variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs)); -#endif - } - - template - inline constexpr bool operator!=(const variant &lhs, - const variant &rhs) { - using detail::visitation::variant; - using not_equal_to = detail::convert_to_bool; -#ifdef MPARK_CPP14_CONSTEXPR - if (lhs.index() != rhs.index()) return true; - if (lhs.valueless_by_exception()) return false; - return variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs); -#else - return lhs.index() != rhs.index() || - (!lhs.valueless_by_exception() && - variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs)); -#endif - } - - template - inline constexpr bool operator<(const variant &lhs, - const variant &rhs) { - using detail::visitation::variant; - using less = detail::convert_to_bool; -#ifdef MPARK_CPP14_CONSTEXPR - if (rhs.valueless_by_exception()) return false; - if (lhs.valueless_by_exception()) return true; - if (lhs.index() < rhs.index()) return true; - if (lhs.index() > rhs.index()) return false; - return variant::visit_value_at(lhs.index(), less{}, lhs, rhs); -#else - return !rhs.valueless_by_exception() && - (lhs.valueless_by_exception() || lhs.index() < rhs.index() || - (lhs.index() == rhs.index() && - variant::visit_value_at(lhs.index(), less{}, lhs, rhs))); -#endif - } - - template - inline constexpr bool operator>(const variant &lhs, - const variant &rhs) { - using detail::visitation::variant; - using greater = detail::convert_to_bool; -#ifdef MPARK_CPP14_CONSTEXPR - if (lhs.valueless_by_exception()) return false; - if (rhs.valueless_by_exception()) return true; - if (lhs.index() > rhs.index()) return true; - if (lhs.index() < rhs.index()) return false; - return variant::visit_value_at(lhs.index(), greater{}, lhs, rhs); -#else - return !lhs.valueless_by_exception() && - (rhs.valueless_by_exception() || lhs.index() > rhs.index() || - (lhs.index() == rhs.index() && - variant::visit_value_at(lhs.index(), greater{}, lhs, rhs))); -#endif - } - - template - inline constexpr bool operator<=(const variant &lhs, - const variant &rhs) { - using detail::visitation::variant; - using less_equal = detail::convert_to_bool; -#ifdef MPARK_CPP14_CONSTEXPR - if (lhs.valueless_by_exception()) return true; - if (rhs.valueless_by_exception()) return false; - if (lhs.index() < rhs.index()) return true; - if (lhs.index() > rhs.index()) return false; - return variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs); -#else - return lhs.valueless_by_exception() || - (!rhs.valueless_by_exception() && - (lhs.index() < rhs.index() || - (lhs.index() == rhs.index() && - variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs)))); -#endif - } - - template - inline constexpr bool operator>=(const variant &lhs, - const variant &rhs) { - using detail::visitation::variant; - using greater_equal = detail::convert_to_bool; -#ifdef MPARK_CPP14_CONSTEXPR - if (rhs.valueless_by_exception()) return true; - if (lhs.valueless_by_exception()) return false; - if (lhs.index() > rhs.index()) return true; - if (lhs.index() < rhs.index()) return false; - return variant::visit_value_at(lhs.index(), greater_equal{}, lhs, rhs); -#else - return rhs.valueless_by_exception() || - (!lhs.valueless_by_exception() && - (lhs.index() > rhs.index() || - (lhs.index() == rhs.index() && - variant::visit_value_at( - lhs.index(), greater_equal{}, lhs, rhs)))); -#endif - } - - struct monostate {}; - - inline constexpr bool operator<(monostate, monostate) noexcept { - return false; - } - - inline constexpr bool operator>(monostate, monostate) noexcept { - return false; - } - - inline constexpr bool operator<=(monostate, monostate) noexcept { - return true; - } - - inline constexpr bool operator>=(monostate, monostate) noexcept { - return true; - } - - inline constexpr bool operator==(monostate, monostate) noexcept { - return true; - } - - inline constexpr bool operator!=(monostate, monostate) noexcept { - return false; - } - -#ifdef MPARK_CPP14_CONSTEXPR - namespace detail { - - inline constexpr bool any(std::initializer_list bs) { - for (bool b : bs) { - if (b) { - return true; - } - } - return false; - } - - } // namespace detail - - template - inline constexpr decltype(auto) visit(Visitor &&visitor, Vs &&... vs) { - return (!detail::any({vs.valueless_by_exception()...}) - ? (void)0 - : throw_bad_variant_access()), - detail::visitation::variant::visit_value( - lib::forward(visitor), lib::forward(vs)...); - } -#else - namespace detail { - - template - inline constexpr bool all_impl(const lib::array &bs, - std::size_t idx) { - return idx >= N || (bs[idx] && all_impl(bs, idx + 1)); - } - - template - inline constexpr bool all(const lib::array &bs) { - return all_impl(bs, 0); - } - - } // namespace detail - - template - inline constexpr DECLTYPE_AUTO visit(Visitor &&visitor, Vs &&... vs) - DECLTYPE_AUTO_RETURN( - (detail::all( - lib::array{{!vs.valueless_by_exception()...}}) - ? (void)0 - : throw_bad_variant_access()), - detail::visitation::variant::visit_value(lib::forward(visitor), - lib::forward(vs)...)) -#endif - - template - inline auto swap(variant &lhs, - variant &rhs) noexcept(noexcept(lhs.swap(rhs))) - -> decltype(lhs.swap(rhs)) { - lhs.swap(rhs); - } - - namespace detail { - - template - using enabled_type = T; - - namespace hash { - - template - constexpr bool meets_requirements() noexcept { - return std::is_copy_constructible::value && - std::is_move_constructible::value && - lib::is_invocable_r::value; - } - - template - constexpr bool is_enabled() noexcept { - using H = std::hash; - return meets_requirements() && - std::is_default_constructible::value && - std::is_copy_assignable::value && - std::is_move_assignable::value; - } - - } // namespace hash - - } // namespace detail - -#undef AUTO -#undef AUTO_RETURN - -#undef AUTO_REFREF -#undef AUTO_REFREF_RETURN - -#undef DECLTYPE_AUTO -#undef DECLTYPE_AUTO_RETURN - -} // namespace mpark - -namespace std { - - template - struct hash, - mpark::lib::enable_if_t>()...>::value>>> { - using argument_type = mpark::variant; - using result_type = std::size_t; - - inline result_type operator()(const argument_type &v) const { - using mpark::detail::visitation::variant; - std::size_t result = - v.valueless_by_exception() - ? 299792458 // Random value chosen by the universe upon creation - : variant::visit_alt( -#ifdef MPARK_GENERIC_LAMBDAS - [](const auto &alt) { - using alt_type = mpark::lib::decay_t; - using value_type = mpark::lib::remove_const_t< - typename alt_type::value_type>; - return hash{}(alt.value); - } -#else - hasher{} -#endif - , - v); - return hash_combine(result, hash{}(v.index())); - } - - private: -#ifndef MPARK_GENERIC_LAMBDAS - struct hasher { - template - inline std::size_t operator()(const Alt &alt) const { - using alt_type = mpark::lib::decay_t; - using value_type = - mpark::lib::remove_const_t; - return hash{}(alt.value); - } - }; -#endif - - static std::size_t hash_combine(std::size_t lhs, std::size_t rhs) { - return lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2); - } - }; - - template <> - struct hash { - using argument_type = mpark::monostate; - using result_type = std::size_t; - - inline result_type operator()(const argument_type &) const noexcept { - return 66740831; // return a fundamentally attractive random value. - } - }; - -} // namespace std - -#endif // MPARK_VARIANT_HPP diff --git a/cpp/src/gandiva/literal_holder.h b/cpp/src/gandiva/literal_holder.h index 7f615b27763..c4712aafc4b 100644 --- a/cpp/src/gandiva/literal_holder.h +++ b/cpp/src/gandiva/literal_holder.h @@ -28,7 +28,7 @@ namespace gandiva { using LiteralHolder = - arrow::util::variant; GANDIVA_EXPORT std::string ToString(const LiteralHolder& holder); diff --git a/cpp/src/parquet/arrow/path_internal.cc b/cpp/src/parquet/arrow/path_internal.cc index daa05a81c79..a51773c44d3 100644 --- a/cpp/src/parquet/arrow/path_internal.cc +++ b/cpp/src/parquet/arrow/path_internal.cc @@ -116,7 +116,6 @@ namespace { using ::arrow::Array; using ::arrow::Status; using ::arrow::TypedBufferBuilder; -using ::arrow::util::holds_alternative; constexpr static int16_t kLevelNotSet = -1; @@ -274,7 +273,8 @@ struct AllPresentTerminalNode { /// Node for handling the case when the leaf-array is nullable /// and contains null elements. struct NullableTerminalNode { - NullableTerminalNode(); + NullableTerminalNode() = default; + NullableTerminalNode(const uint8_t* bitmap, int64_t element_offset, int16_t def_level_if_present) : bitmap_(bitmap), @@ -517,9 +517,10 @@ struct PathInfo { // The vectors are expected to the same length info. // Note index order matters here. - using Node = ::arrow::util::variant; + std::vector path; std::shared_ptr primitive_array; int16_t max_def_level = 0; @@ -575,38 +576,32 @@ Status WritePath(ElementRange root_range, PathInfo* path_info, while (stack_position >= stack_base) { PathInfo::Node& node = path_info->path[stack_position - stack_base]; struct { - IterationResult operator()( - NullableNode& node) { // NOLINT google-runtime-references - return node.Run(stack_position, stack_position + 1, context); + IterationResult operator()(NullableNode* node) { + return node->Run(stack_position, stack_position + 1, context); } - IterationResult operator()(ListNode& node) { // NOLINT google-runtime-references - return node.Run(stack_position, stack_position + 1, context); + IterationResult operator()(ListNode* node) { + return node->Run(stack_position, stack_position + 1, context); } - IterationResult operator()( - NullableTerminalNode& node) { // NOLINT google-runtime-references - return node.Run(*stack_position, context); + IterationResult operator()(NullableTerminalNode* node) { + return node->Run(*stack_position, context); } - IterationResult operator()( - FixedSizeListNode& node) { // NOLINT google-runtime-references - return node.Run(stack_position, stack_position + 1, context); + IterationResult operator()(FixedSizeListNode* node) { + return node->Run(stack_position, stack_position + 1, context); } - IterationResult operator()( - AllPresentTerminalNode& node) { // NOLINT google-runtime-references - return node.Run(*stack_position, context); + IterationResult operator()(AllPresentTerminalNode* node) { + return node->Run(*stack_position, context); } - IterationResult operator()( - AllNullsTerminalNode& node) { // NOLINT google-runtime-references - return node.Run(*stack_position, context); + IterationResult operator()(AllNullsTerminalNode* node) { + return node->Run(*stack_position, context); } - IterationResult operator()( - LargeListNode& node) { // NOLINT google-runtime-references - return node.Run(stack_position, stack_position + 1, context); + IterationResult operator()(LargeListNode* node) { + return node->Run(stack_position, stack_position + 1, context); } ElementRange* stack_position; PathWriteContext* context; } visitor = {stack_position, &context}; - IterationResult result = ::arrow::util::visit(visitor, node); + IterationResult result = ::arrow::util::visit(visitor, &node); if (ARROW_PREDICT_FALSE(result == kError)) { DCHECK(!context.last_status.ok()); @@ -653,15 +648,9 @@ struct FixupVisitor { rep_level_if_null = arg->rep_level(); } } - void operator()(ListNode& node) { // NOLINT google-runtime-references - HandleListNode(&node); - } - void operator()(LargeListNode& node) { // NOLINT google-runtime-references - HandleListNode(&node); - } - void operator()(FixedSizeListNode& node) { // NOLINT google-runtime-references - HandleListNode(&node); - } + void operator()(ListNode* node) { HandleListNode(node); } + void operator()(LargeListNode* node) { HandleListNode(node); } + void operator()(FixedSizeListNode* node) { HandleListNode(node); } // For non-list intermediate nodes. template @@ -671,19 +660,17 @@ struct FixupVisitor { } } - void operator()(NullableNode& arg) { // NOLINT google-runtime-references - HandleIntermediateNode(&arg); - } + void operator()(NullableNode* arg) { HandleIntermediateNode(arg); } - void operator()(AllNullsTerminalNode& arg) { // NOLINT google-runtime-references + void operator()(AllNullsTerminalNode* arg) { // Even though no processing happens past this point we // still need to adjust it if a list occurred after an // all null array. - HandleIntermediateNode(&arg); + HandleIntermediateNode(arg); } - void operator()(NullableTerminalNode& arg) {} // NOLINT google-runtime-references - void operator()(AllPresentTerminalNode& arg) {} // NOLINT google-runtime-references + void operator()(NullableTerminalNode*) {} + void operator()(AllPresentTerminalNode*) {} }; PathInfo Fixup(PathInfo info) { @@ -698,7 +685,7 @@ PathInfo Fixup(PathInfo info) { visitor.rep_level_if_null = 0; } for (size_t x = 0; x < info.path.size(); x++) { - ::arrow::util::visit(visitor, info.path[x]); + ::arrow::util::visit(visitor, &info.path[x]); } return info; } @@ -717,12 +704,12 @@ class PathBuilder { // traversing the null bitmap twice (once here and once when calculating // rep/def levels). if (LazyNoNulls(array)) { - info_.path.push_back(AllPresentTerminalNode{info_.max_def_level}); + info_.path.emplace_back(AllPresentTerminalNode{info_.max_def_level}); } else if (LazyNullCount(array) == array.length()) { - info_.path.push_back(AllNullsTerminalNode(info_.max_def_level - 1)); + info_.path.emplace_back(AllNullsTerminalNode(info_.max_def_level - 1)); } else { - info_.path.push_back(NullableTerminalNode(array.null_bitmap_data(), array.offset(), - info_.max_def_level)); + info_.path.emplace_back(NullableTerminalNode(array.null_bitmap_data(), + array.offset(), info_.max_def_level)); } info_.primitive_array = std::make_shared(array.data()); paths_.push_back(Fixup(info_)); @@ -748,7 +735,7 @@ class PathBuilder { ListPathNode> node( VarRangeSelector{array.raw_value_offsets()}, info_.max_rep_level, info_.max_def_level - 1); - info_.path.push_back(node); + info_.path.emplace_back(std::move(node)); nullable_in_parent_ = array.list_type()->value_field()->nullable(); return VisitInline(*array.values()); } @@ -788,11 +775,12 @@ class PathBuilder { return; } if (LazyNullCount(array) == array.length()) { - info_.path.push_back(AllNullsTerminalNode(info_.max_def_level - 1)); + info_.path.emplace_back(AllNullsTerminalNode(info_.max_def_level - 1)); return; } - info_.path.push_back(NullableNode(array.null_bitmap_data(), array.offset(), - /* def_level_if_null = */ info_.max_def_level - 1)); + info_.path.emplace_back( + NullableNode(array.null_bitmap_data(), array.offset(), + /* def_level_if_null = */ info_.max_def_level - 1)); } Status VisitInline(const Array& array); @@ -820,8 +808,8 @@ class PathBuilder { // well. info_.max_def_level++; info_.max_rep_level++; - info_.path.push_back(FixedSizeListNode(FixedSizedRangeSelector{list_size}, - info_.max_rep_level, info_.max_def_level)); + info_.path.emplace_back(FixedSizeListNode(FixedSizedRangeSelector{list_size}, + info_.max_rep_level, info_.max_def_level)); nullable_in_parent_ = array.list_type()->value_field()->nullable(); if (array.offset() > 0) { return VisitInline(*array.values()->Slice(array.value_offset(0))); diff --git a/go/arrow/LICENSE.txt b/go/arrow/LICENSE.txt index 40d9ec7a917..6884e08f455 100644 --- a/go/arrow/LICENSE.txt +++ b/go/arrow/LICENSE.txt @@ -680,34 +680,6 @@ DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- -The file cpp/src/arrow/vendored/variant.hpp has the following license - -Boost Software License - Version 1.0 - August 17th, 2003 - -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - --------------------------------------------------------------------------------- - The files in cpp/src/arrow/vendored/xxhash/ have the following license (BSD 2-Clause License) diff --git a/python/pyarrow/includes/libarrow_flight.pxd b/python/pyarrow/includes/libarrow_flight.pxd index 8d79e21e1ee..2b4283f9760 100644 --- a/python/pyarrow/includes/libarrow_flight.pxd +++ b/python/pyarrow/includes/libarrow_flight.pxd @@ -538,7 +538,7 @@ cdef extern from "arrow/python/flight.h" namespace "arrow::py::flight" nogil: cdef extern from "arrow/util/variant.h" namespace "arrow" nogil: - cdef cppclass CIntStringVariant" arrow::util::variant": + cdef cppclass CIntStringVariant" arrow::util::Variant": CIntStringVariant() CIntStringVariant(int) CIntStringVariant(c_string)