Export of internal Abseil changes.

--
fcf9d3facb12451964ad1850073cbfb6f9739379 by CJ Johnson <johnsoncj@google.com>:

Makes it obvious to readers that the comparison operators do not branch more than needed

PiperOrigin-RevId: 240811527

--
680c586f81f805be68e96caffb28d5f46b6a6511 by Jon Cohen <cohenjon@google.com>:

Consistently use "if(" instead of "if (" in CMake files

PiperOrigin-RevId: 240621819

--
c4acc506648622389f33f564fd94f8dda08cb61a by Tom Manshreck <shreck@google.com>:

Internal change

PiperOrigin-RevId: 240619556

--
ddbc1894944aae96767c876a1ae8696ddaba42a2 by Jon Cohen <cohenjon@google.com>:

Remove the warning about install prefixes when we aren't installing abseil

PiperOrigin-RevId: 240614750

--
086c4fad213d99e875038bc8a1c7268e28a7ebf3 by Abseil Team <absl-team@google.com>:

Adjust some tests and test cases which fail on WebAssembly

PiperOrigin-RevId: 240592367

--
46c2c09723a37ef4911ae3c64aab92e3f0fdba79 by Abseil Team <absl-team@google.com>:

CMake install target update
- Add prefix absl_ to each target when install rule are disabled.
- Disable all install commands when absl is used as subdirectory (Fix #287)

PiperOrigin-RevId: 240575083

--
8d88063ed5b16f982a91950693d37ca18fdd46d8 by Jon Cohen <cohenjon@google.com>:

Correctly link to Threads::Threads for a few cmake targets which were missing it.

PiperOrigin-RevId: 240574513
GitOrigin-RevId: fcf9d3facb12451964ad1850073cbfb6f9739379
Change-Id: I031c57de8cd88554348eb8bd1371d01d15ff1fc7
This commit is contained in:
Abseil Team 2019-03-28 11:12:19 -07:00 committed by Gennadiy Civil
parent 5b65c4af51
commit 2c8421e1c6
14 changed files with 235 additions and 149 deletions

View file

@ -59,7 +59,7 @@ set(ABSL_IDE_FOLDER Abseil)
# SRCS # SRCS
# "b.cc" # "b.cc"
# DEPS # DEPS
# absl_internal_awesome # not "awesome"! # absl::awesome # not "awesome" !
# PUBLIC # PUBLIC
# ) # )
# #
@ -68,7 +68,7 @@ set(ABSL_IDE_FOLDER Abseil)
# main_lib # main_lib
# ... # ...
# DEPS # DEPS
# absl::fantastic_lib # since fantastic_lib is public # absl::fantastic_lib
# ) # )
# #
# TODO: Implement "ALWAYSLINK" # TODO: Implement "ALWAYSLINK"
@ -81,7 +81,11 @@ function(absl_cc_library)
) )
if(NOT ABSL_CC_LIB_TESTONLY OR ABSL_RUN_TESTS) if(NOT ABSL_CC_LIB_TESTONLY OR ABSL_RUN_TESTS)
if(ABSL_ENABLE_INSTALL)
set(_NAME "${ABSL_CC_LIB_NAME}") set(_NAME "${ABSL_CC_LIB_NAME}")
else()
set(_NAME "absl_${ABSL_CC_LIB_NAME}")
endif()
# Check if this is a header-only library # Check if this is a header-only library
# Note that as of February 2019, many popular OS's (for example, Ubuntu # Note that as of February 2019, many popular OS's (for example, Ubuntu
@ -155,7 +159,7 @@ function(absl_cc_library)
# TODO currently we don't install googletest alongside abseil sources, so # TODO currently we don't install googletest alongside abseil sources, so
# installed abseil can't be tested. # installed abseil can't be tested.
if (NOT ABSL_CC_LIB_TESTONLY) if(NOT ABSL_CC_LIB_TESTONLY AND ABSL_ENABLE_INSTALL)
install(TARGETS ${_NAME} EXPORT ${PROJECT_NAME}Targets install(TARGETS ${_NAME} EXPORT ${PROJECT_NAME}Targets
RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR} RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR}
LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR} LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR}

View file

@ -1,5 +1,6 @@
## absl CMake configuration file. Note that there is no corresponding # absl CMake configuration file.
# abslConfigVersion.cmake since non-LTS Abseil isn't versioned.
include(FindThreads)
@PACKAGE_INIT@ @PACKAGE_INIT@

View file

@ -86,18 +86,6 @@ if(${ABSL_RUN_TESTS})
enable_testing() enable_testing()
endif() endif()
# absl:lts-remove-begin(system installation is supported for LTS releases)
# We don't support system-wide installation
list(APPEND SYSTEM_INSTALL_DIRS "/usr/local" "/usr" "/opt/" "/opt/local" "c:/Program Files/${PROJECT_NAME}")
if(NOT DEFINED CMAKE_INSTALL_PREFIX OR CMAKE_INSTALL_PREFIX IN_LIST SYSTEM_INSTALL_DIRS)
message(WARNING "\
The default and system-level install directories are unsupported except in LTS \
releases of Abseil. Please set CMAKE_INSTALL_PREFIX to install Abseil in your \
source or build tree directly.\
")
endif()
# absl:lts-remove-end
## check targets ## check targets
if(BUILD_TESTING) if(BUILD_TESTING)
@ -122,6 +110,18 @@ endif()
add_subdirectory(absl) add_subdirectory(absl)
if(ABSL_ENABLE_INSTALL) if(ABSL_ENABLE_INSTALL)
# absl:lts-remove-begin(system installation is supported for LTS releases)
# We don't support system-wide installation
list(APPEND SYSTEM_INSTALL_DIRS "/usr/local" "/usr" "/opt/" "/opt/local" "c:/Program Files/${PROJECT_NAME}")
if(NOT DEFINED CMAKE_INSTALL_PREFIX OR CMAKE_INSTALL_PREFIX IN_LIST SYSTEM_INSTALL_DIRS)
message(WARNING "\
The default and system-level install directories are unsupported except in LTS \
releases of Abseil. Please set CMAKE_INSTALL_PREFIX to install Abseil in your \
source or build tree directly.\
")
endif()
# absl:lts-remove-end
# install as a subdirectory only # install as a subdirectory only
install(EXPORT ${PROJECT_NAME}Targets install(EXPORT ${PROJECT_NAME}Targets
NAMESPACE absl:: NAMESPACE absl::

View file

@ -88,6 +88,7 @@ absl_cc_library(
absl::core_headers absl::core_headers
absl::dynamic_annotations absl::dynamic_annotations
absl::spinlock_wait absl::spinlock_wait
Threads::Threads
) )
absl_cc_library( absl_cc_library(
@ -134,6 +135,7 @@ absl_cc_library(
absl::core_headers absl::core_headers
absl::dynamic_annotations absl::dynamic_annotations
absl::spinlock_wait absl::spinlock_wait
Threads::Threads
PUBLIC PUBLIC
) )
@ -438,3 +440,12 @@ absl_cc_test(
absl::scoped_set_env absl::scoped_set_env
gtest_main gtest_main
) )
absl_cc_test(
NAME
cmake_thread_test
SRCS
"internal/cmake_thread_test.cc"
DEPS
absl::base
)

View file

@ -0,0 +1,22 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://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 <iostream>
#include "absl/base/internal/thread_identity.h"
int main() {
auto* tid = absl::base_internal::CurrentThreadIdentityIfPresent();
// Make sure the above call can't be optimized out
std::cout << (void*)tid << std::endl;
}

View file

@ -847,7 +847,7 @@ class InlinedVector {
private: private:
template <typename H, typename TheT, size_t TheN, typename TheA> template <typename H, typename TheT, size_t TheN, typename TheA>
friend auto AbslHashValue(H h, const InlinedVector<TheT, TheN, TheA>& v) -> H; friend H AbslHashValue(H h, const absl::InlinedVector<TheT, TheN, TheA>& a);
const Tag& tag() const { return storage_.allocator_and_tag_.tag(); } const Tag& tag() const { return storage_.allocator_and_tag_.tag(); }
@ -1231,8 +1231,8 @@ class InlinedVector {
// Swaps the contents of two inlined vectors. This convenience function // Swaps the contents of two inlined vectors. This convenience function
// simply calls `InlinedVector::swap()`. // simply calls `InlinedVector::swap()`.
template <typename T, size_t N, typename A> template <typename T, size_t N, typename A>
auto swap(InlinedVector<T, N, A>& a, void swap(absl::InlinedVector<T, N, A>& a,
InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) -> void { absl::InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) {
a.swap(b); a.swap(b);
} }
@ -1240,17 +1240,21 @@ auto swap(InlinedVector<T, N, A>& a,
// //
// Tests the equivalency of the contents of two inlined vectors. // Tests the equivalency of the contents of two inlined vectors.
template <typename T, size_t N, typename A> template <typename T, size_t N, typename A>
auto operator==(const InlinedVector<T, N, A>& a, bool operator==(const absl::InlinedVector<T, N, A>& a,
const InlinedVector<T, N, A>& b) -> bool { const absl::InlinedVector<T, N, A>& b) {
return absl::equal(a.begin(), a.end(), b.begin(), b.end()); auto a_data = a.data();
auto a_size = a.size();
auto b_data = b.data();
auto b_size = b.size();
return absl::equal(a_data, a_data + a_size, b_data, b_data + b_size);
} }
// `operator!=()` // `operator!=()`
// //
// Tests the inequality of the contents of two inlined vectors. // Tests the inequality of the contents of two inlined vectors.
template <typename T, size_t N, typename A> template <typename T, size_t N, typename A>
auto operator!=(const InlinedVector<T, N, A>& a, bool operator!=(const absl::InlinedVector<T, N, A>& a,
const InlinedVector<T, N, A>& b) -> bool { const absl::InlinedVector<T, N, A>& b) {
return !(a == b); return !(a == b);
} }
@ -1259,9 +1263,14 @@ auto operator!=(const InlinedVector<T, N, A>& a,
// Tests whether the contents of one inlined vector are less than the contents // Tests whether the contents of one inlined vector are less than the contents
// of another through a lexicographical comparison operation. // of another through a lexicographical comparison operation.
template <typename T, size_t N, typename A> template <typename T, size_t N, typename A>
auto operator<(const InlinedVector<T, N, A>& a, const InlinedVector<T, N, A>& b) bool operator<(const absl::InlinedVector<T, N, A>& a,
-> bool { const absl::InlinedVector<T, N, A>& b) {
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); auto a_data = a.data();
auto a_size = a.size();
auto b_data = b.data();
auto b_size = b.size();
return std::lexicographical_compare(a_data, a_data + a_size, b_data,
b_data + b_size);
} }
// `operator>()` // `operator>()`
@ -1269,8 +1278,8 @@ auto operator<(const InlinedVector<T, N, A>& a, const InlinedVector<T, N, A>& b)
// Tests whether the contents of one inlined vector are greater than the // Tests whether the contents of one inlined vector are greater than the
// contents of another through a lexicographical comparison operation. // contents of another through a lexicographical comparison operation.
template <typename T, size_t N, typename A> template <typename T, size_t N, typename A>
auto operator>(const InlinedVector<T, N, A>& a, const InlinedVector<T, N, A>& b) bool operator>(const absl::InlinedVector<T, N, A>& a,
-> bool { const absl::InlinedVector<T, N, A>& b) {
return b < a; return b < a;
} }
@ -1279,8 +1288,8 @@ auto operator>(const InlinedVector<T, N, A>& a, const InlinedVector<T, N, A>& b)
// Tests whether the contents of one inlined vector are less than or equal to // Tests whether the contents of one inlined vector are less than or equal to
// the contents of another through a lexicographical comparison operation. // the contents of another through a lexicographical comparison operation.
template <typename T, size_t N, typename A> template <typename T, size_t N, typename A>
auto operator<=(const InlinedVector<T, N, A>& a, bool operator<=(const absl::InlinedVector<T, N, A>& a,
const InlinedVector<T, N, A>& b) -> bool { const absl::InlinedVector<T, N, A>& b) {
return !(b < a); return !(b < a);
} }
@ -1289,8 +1298,8 @@ auto operator<=(const InlinedVector<T, N, A>& a,
// Tests whether the contents of one inlined vector are greater than or equal to // Tests whether the contents of one inlined vector are greater than or equal to
// the contents of another through a lexicographical comparison operation. // the contents of another through a lexicographical comparison operation.
template <typename T, size_t N, typename A> template <typename T, size_t N, typename A>
auto operator>=(const InlinedVector<T, N, A>& a, bool operator>=(const absl::InlinedVector<T, N, A>& a,
const InlinedVector<T, N, A>& b) -> bool { const absl::InlinedVector<T, N, A>& b) {
return !(a < b); return !(a < b);
} }
@ -1299,11 +1308,13 @@ auto operator>=(const InlinedVector<T, N, A>& a,
// Provides `absl::Hash` support for inlined vectors. You do not normally call // Provides `absl::Hash` support for inlined vectors. You do not normally call
// this function directly. // this function directly.
template <typename H, typename TheT, size_t TheN, typename TheA> template <typename H, typename TheT, size_t TheN, typename TheA>
auto AbslHashValue(H h, const InlinedVector<TheT, TheN, TheA>& v) -> H { H AbslHashValue(H h, const absl::InlinedVector<TheT, TheN, TheA>& a) {
auto p = v.data(); auto a_data = a.data();
auto n = v.size(); auto a_size = a.size();
return H::combine(H::combine_contiguous(std::move(h), p, n), n); return H::combine(H::combine_contiguous(std::move(h), a_data, a_size),
a_size);
} }
} // namespace absl } // namespace absl
#endif // ABSL_CONTAINER_INLINED_VECTOR_H_ #endif // ABSL_CONTAINER_INLINED_VECTOR_H_

View file

@ -414,10 +414,10 @@ TEST(Table, Prefetch) {
t.prefetch(2); t.prefetch(2);
// Do not run in debug mode, when prefetch is not implemented, or when // Do not run in debug mode, when prefetch is not implemented, or when
// sanitizers are enabled. // sanitizers are enabled, or on WebAssembly.
#if defined(NDEBUG) && defined(__GNUC__) && !defined(ADDRESS_SANITIZER) && \ #if defined(NDEBUG) && defined(__GNUC__) && !defined(ADDRESS_SANITIZER) && \
!defined(MEMORY_SANITIZER) && !defined(THREAD_SANITIZER) && \ !defined(MEMORY_SANITIZER) && !defined(THREAD_SANITIZER) && \
!defined(UNDEFINED_BEHAVIOR_SANITIZER) !defined(UNDEFINED_BEHAVIOR_SANITIZER) && !defined(__EMSCRIPTEN__)
const auto now = [] { return absl::base_internal::CycleClock::Now(); }; const auto now = [] { return absl::base_internal::CycleClock::Now(); };
// Make size enough to not fit in L2 cache (16.7 Mb) // Make size enough to not fit in L2 cache (16.7 Mb)

View file

@ -64,6 +64,7 @@ absl_cc_library(
absl::stacktrace absl::stacktrace
absl::symbolize absl::symbolize
absl::time absl::time
Threads::Threads
PUBLIC PUBLIC
) )
@ -191,5 +192,4 @@ absl_cc_test(
absl::synchronization absl::synchronization
absl::base absl::base
absl::core_headers absl::core_headers
Threads::Threads
) )

View file

@ -117,7 +117,12 @@ cc_test(
cc_library( cc_library(
name = "span", name = "span",
hdrs = ["span.h"], srcs = [
"internal/span.h",
],
hdrs = [
"span.h",
],
copts = ABSL_DEFAULT_COPTS, copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [ deps = [

View file

@ -114,6 +114,8 @@ absl_cc_library(
span span
HDRS HDRS
"span.h" "span.h"
SRCS
"internal/span.h"
COPTS COPTS
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
DEPS DEPS

126
absl/types/internal/span.h Normal file
View file

@ -0,0 +1,126 @@
//
// Copyright 2019 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://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.
//
#ifndef ABSL_TYPES_INTERNAL_SPAN_H_
#define ABSL_TYPES_INTERNAL_SPAN_H_
#include <algorithm>
#include <cstddef>
#include <string>
#include <type_traits>
#include "absl/algorithm/algorithm.h"
#include "absl/base/internal/throw_delegate.h"
#include "absl/meta/type_traits.h"
namespace absl {
namespace span_internal {
// A constexpr min function
constexpr size_t Min(size_t a, size_t b) noexcept { return a < b ? a : b; }
// Wrappers for access to container data pointers.
template <typename C>
constexpr auto GetDataImpl(C& c, char) noexcept // NOLINT(runtime/references)
-> decltype(c.data()) {
return c.data();
}
// Before C++17, std::string::data returns a const char* in all cases.
inline char* GetDataImpl(std::string& s, // NOLINT(runtime/references)
int) noexcept {
return &s[0];
}
template <typename C>
constexpr auto GetData(C& c) noexcept // NOLINT(runtime/references)
-> decltype(GetDataImpl(c, 0)) {
return GetDataImpl(c, 0);
}
// Detection idioms for size() and data().
template <typename C>
using HasSize =
std::is_integral<absl::decay_t<decltype(std::declval<C&>().size())>>;
// We want to enable conversion from vector<T*> to Span<const T* const> but
// disable conversion from vector<Derived> to Span<Base>. Here we use
// the fact that U** is convertible to Q* const* if and only if Q is the same
// type or a more cv-qualified version of U. We also decay the result type of
// data() to avoid problems with classes which have a member function data()
// which returns a reference.
template <typename T, typename C>
using HasData =
std::is_convertible<absl::decay_t<decltype(GetData(std::declval<C&>()))>*,
T* const*>;
// Extracts value type from a Container
template <typename C>
struct ElementType {
using type = typename absl::remove_reference_t<C>::value_type;
};
template <typename T, size_t N>
struct ElementType<T (&)[N]> {
using type = T;
};
template <typename C>
using ElementT = typename ElementType<C>::type;
template <typename T>
using EnableIfMutable =
typename std::enable_if<!std::is_const<T>::value, int>::type;
template <template <typename> class SpanT, typename T>
bool EqualImpl(SpanT<T> a, SpanT<T> b) {
static_assert(std::is_const<T>::value, "");
return absl::equal(a.begin(), a.end(), b.begin(), b.end());
}
template <template <typename> class SpanT, typename T>
bool LessThanImpl(SpanT<T> a, SpanT<T> b) {
// We can't use value_type since that is remove_cv_t<T>, so we go the long way
// around.
static_assert(std::is_const<T>::value, "");
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
}
// The `IsConvertible` classes here are needed because of the
// `std::is_convertible` bug in libcxx when compiled with GCC. This build
// configuration is used by Android NDK toolchain. Reference link:
// https://bugs.llvm.org/show_bug.cgi?id=27538.
template <typename From, typename To>
struct IsConvertibleHelper {
private:
static std::true_type testval(To);
static std::false_type testval(...);
public:
using type = decltype(testval(std::declval<From>()));
};
template <typename From, typename To>
struct IsConvertible : IsConvertibleHelper<From, To>::type {};
// TODO(zhangxy): replace `IsConvertible` with `std::is_convertible` once the
// older version of libcxx is not supported.
template <typename From, typename To>
using EnableIfConvertibleTo =
typename std::enable_if<IsConvertible<From, To>::value>::type;
} // namespace span_internal
} // namespace absl
#endif // ABSL_TYPES_INTERNAL_SPAN_H_

View file

@ -60,114 +60,18 @@
#include <cstddef> #include <cstddef>
#include <initializer_list> #include <initializer_list>
#include <iterator> #include <iterator>
#include <string>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include "absl/algorithm/algorithm.h"
#include "absl/base/internal/throw_delegate.h" #include "absl/base/internal/throw_delegate.h"
#include "absl/base/macros.h" #include "absl/base/macros.h"
#include "absl/base/optimization.h" #include "absl/base/optimization.h"
#include "absl/base/port.h" #include "absl/base/port.h" // TODO(strel): remove this include
#include "absl/meta/type_traits.h" #include "absl/meta/type_traits.h"
#include "absl/types/internal/span.h"
namespace absl { namespace absl {
namespace span_internal {
// A constexpr min function
constexpr size_t Min(size_t a, size_t b) noexcept { return a < b ? a : b; }
// Wrappers for access to container data pointers.
template <typename C>
constexpr auto GetDataImpl(C& c, char) noexcept // NOLINT(runtime/references)
-> decltype(c.data()) {
return c.data();
}
// Before C++17, std::string::data returns a const char* in all cases.
inline char* GetDataImpl(std::string& s, // NOLINT(runtime/references)
int) noexcept {
return &s[0];
}
template <typename C>
constexpr auto GetData(C& c) noexcept // NOLINT(runtime/references)
-> decltype(GetDataImpl(c, 0)) {
return GetDataImpl(c, 0);
}
// Detection idioms for size() and data().
template <typename C>
using HasSize =
std::is_integral<absl::decay_t<decltype(std::declval<C&>().size())>>;
// We want to enable conversion from vector<T*> to Span<const T* const> but
// disable conversion from vector<Derived> to Span<Base>. Here we use
// the fact that U** is convertible to Q* const* if and only if Q is the same
// type or a more cv-qualified version of U. We also decay the result type of
// data() to avoid problems with classes which have a member function data()
// which returns a reference.
template <typename T, typename C>
using HasData =
std::is_convertible<absl::decay_t<decltype(GetData(std::declval<C&>()))>*,
T* const*>;
// Extracts value type from a Container
template <typename C>
struct ElementType {
using type = typename absl::remove_reference_t<C>::value_type;
};
template <typename T, size_t N>
struct ElementType<T (&)[N]> {
using type = T;
};
template <typename C>
using ElementT = typename ElementType<C>::type;
template <typename T>
using EnableIfMutable =
typename std::enable_if<!std::is_const<T>::value, int>::type;
template <template <typename> class SpanT, typename T>
bool EqualImpl(SpanT<T> a, SpanT<T> b) {
static_assert(std::is_const<T>::value, "");
return absl::equal(a.begin(), a.end(), b.begin(), b.end());
}
template <template <typename> class SpanT, typename T>
bool LessThanImpl(SpanT<T> a, SpanT<T> b) {
// We can't use value_type since that is remove_cv_t<T>, so we go the long way
// around.
static_assert(std::is_const<T>::value, "");
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
}
// The `IsConvertible` classes here are needed because of the
// `std::is_convertible` bug in libcxx when compiled with GCC. This build
// configuration is used by Android NDK toolchain. Reference link:
// https://bugs.llvm.org/show_bug.cgi?id=27538.
template <typename From, typename To>
struct IsConvertibleHelper {
private:
static std::true_type testval(To);
static std::false_type testval(...);
public:
using type = decltype(testval(std::declval<From>()));
};
template <typename From, typename To>
struct IsConvertible : IsConvertibleHelper<From, To>::type {};
// TODO(zhangxy): replace `IsConvertible` with `std::is_convertible` once the
// older version of libcxx is not supported.
template <typename From, typename To>
using EnableIfConvertibleTo =
typename std::enable_if<IsConvertible<From, To>::value>::type;
} // namespace span_internal
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Span // Span
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------