/usr/local/lib64/python3.6/site-packages/pyarrow/include/arrow/util
Edit: /usr/local/lib64/python3.6/site-packages/pyarrow/include/arrow/util/variant.h (13728B)
// 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.
#pragma once
#include
#include
#include
#include
#include "arrow/util/macros.h"
#include "arrow/util/type_traits.h"
namespace arrow {
namespace util {
/// \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;
Variant& operator=(Variant&& other) noexcept {
this->destroy();
other.move_to(this);
return *this;
}
using Impl::Impl;
using Impl::operator=;
Variant(Variant&& other) noexcept { other.move_to(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();
}
/// \brief Get a const pointer to the value held by the variant
///
/// If the type given as template argument doesn't match, a nullptr is returned.
template
const U* get_if(const Variant* v) {
return v->template get();
}
/// \brief Get a pointer to the value held by the variant
///
/// If the type given as template argument doesn't match, a nullptr is returned.
template
U* get_if(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