diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1cb9e79419..538fe07f8f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -163,6 +163,16 @@ jobs: - name: run tests run: ./ci/do_ci.sh bazel.tsan + bazel_osx: + name: Bazel on MacOS + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: 'recursive' + - name: run tests + run: ./ci/do_ci.sh bazel.test + benchmark: name: Benchmark runs-on: ubuntu-latest @@ -195,15 +205,6 @@ jobs: - name: run tests run: ./ci/do_ci.sh format - osx_test: - name: Bazel on MacOS - runs-on: macos-latest - steps: - - uses: actions/checkout@v2 - with: - submodules: 'recursive' - - name: run tests - run: ./ci/do_ci.sh bazel.test windows: name: CMake -> exporter proto diff --git a/CMakeLists.txt b/CMakeLists.txt index c67451ec01..61db8e332b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,48 @@ if(NOT DEFINED CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 11) endif() +option(WITH_STL "Whether to use Standard Library for C++latest features" OFF) + +option(WITH_ABSEIL "Whether to use Abseil for C++latest features" OFF) + +if(WITH_ABSEIL) + add_definitions(-DHAVE_ABSEIL) + find_package(absl CONFIG REQUIRED) + + # Abseil headers-only lib is needed for absl::variant to work vs2015. + # `nostd::mpark::variant` is not compiling in vs2015. + set(CORE_RUNTIME_LIBS absl::any absl::base absl::bits absl::city) + + # target_link_libraries(main PRIVATE absl::any absl::base absl::bits + # absl::city) +endif() + +if(WITH_STL) + # Require at least C++17. C++20 is needed to avoid gsl::span + add_definitions(-DHAVE_CPP_STDLIB -DHAVE_GSL) + + if(CMAKE_MINOR_VERSION VERSION_GREATER "3.18") + # Ask for 20, may get anything below + set(CMAKE_CXX_STANDARD 20) + else() + # Ask for 17, may get anything below + set(CMAKE_CXX_STANDARD 17) + endif() + + # Guidelines Support Library path. Used if we are not on not get C++20. + # + # TODO: respect WITH_ABSEIL as alternate implementation of std::span + set(GSL_DIR third_party/ms-gsl) + include_directories(${GSL_DIR}/include) + + # Optimize for speed to reduce the hops + if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(CMAKE_CXX_FLAGS_SPEED "/O2") + set(CMAKE_CXX_FLAGS + "${CMAKE_CXX_FLAGS} /Zc:__cplusplus ${CMAKE_CXX_FLAGS_SPEED}") + endif() +endif() + option(WITH_OTLP "Whether to include the OpenTelemetry Protocol in the SDK" OFF) option(WITH_PROMETHEUS "Whether to include the Prometheus Client in the SDK" diff --git a/CMakeSettings.json b/CMakeSettings.json index 4b2923f3ca..e5285d3fad 100644 --- a/CMakeSettings.json +++ b/CMakeSettings.json @@ -46,6 +46,63 @@ "type": "BOOL" } ] + }, + { + "name": "stdlib-x64-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "inheritEnvironments": [ "msvc_x64_x64" ], + "buildRoot": "${projectDir}\\out\\vs2019\\${name}", + "installRoot": "${projectDir}\\out\\vs2019\\${name}\\install", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "", + "variables": [ + { + "name": "WITH_STL", + "value": "True", + "type": "BOOL" + }, + { + "name": "WITH_OTLP", + "value": "True", + "type": "BOOL" + }, + { + "name": "WITH_EXAMPLES", + "value": "true", + "type": "BOOL" + } + ] + }, + { + "name": "stdlib-x64-Release", + "generator": "Ninja", + "configurationType": "RelWithDebInfo", + "inheritEnvironments": [ "msvc_x64_x64" ], + "buildRoot": "${projectDir}\\out\\vs2019\\${name}", + "installRoot": "${projectDir}\\out\\vs2019\\${name}\\install", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "", + "cmakeToolchain": "", + "variables": [ + { + "name": "WITH_STL", + "value": "True", + "type": "BOOL" + }, + { + "name": "WITH_OTLP", + "value": "True", + "type": "BOOL" + }, + { + "name": "WITH_EXAMPLES", + "value": "true", + "type": "BOOL" + } + ] } ] } \ No newline at end of file diff --git a/api/CMakeLists.txt b/api/CMakeLists.txt index e446300a03..2f6eed51fb 100644 --- a/api/CMakeLists.txt +++ b/api/CMakeLists.txt @@ -12,3 +12,9 @@ install( if(BUILD_TESTING) add_subdirectory(test) endif() + +if(WITH_STL) + message("Building with standard library types...") +else() + message("Building with nostd types...") +endif() diff --git a/api/include/opentelemetry/common/attribute_value.h b/api/include/opentelemetry/common/attribute_value.h index e68b6d8bb1..6cb399842a 100644 --- a/api/include/opentelemetry/common/attribute_value.h +++ b/api/include/opentelemetry/common/attribute_value.h @@ -10,20 +10,30 @@ OPENTELEMETRY_BEGIN_NAMESPACE namespace common { -using AttributeValue = nostd::variant, - nostd::span, - nostd::span, - nostd::span, - nostd::span, - nostd::span, - nostd::span>; +using AttributeValue = + nostd::variant, +#endif + nostd::span, + nostd::span, + nostd::span, + nostd::span, + nostd::span, + nostd::span, + nostd::span>; enum AttributeType { @@ -34,8 +44,12 @@ enum AttributeType TYPE_UINT64, TYPE_DOUBLE, TYPE_STRING, +#ifdef HAVE_CSTRING_TYPE TYPE_CSTRING, - // TYPE_SPAN_BYTE, // TODO: not part of OT spec yet +#endif +#ifdef HAVE_SPAN_BYTE + TYPE_SPAN_BYTE, +#endif TYPE_SPAN_BOOL, TYPE_SPAN_INT, TYPE_SPAN_INT64, diff --git a/api/include/opentelemetry/common/key_value_iterable.h b/api/include/opentelemetry/common/key_value_iterable.h index f4e4a92bc3..0742082e56 100644 --- a/api/include/opentelemetry/common/key_value_iterable.h +++ b/api/include/opentelemetry/common/key_value_iterable.h @@ -30,5 +30,23 @@ class KeyValueIterable */ virtual size_t size() const noexcept = 0; }; + +// +// NULL object pattern empty iterable. +// +class NullKeyValueIterable : public KeyValueIterable +{ +public: + NullKeyValueIterable(){}; + + virtual bool ForEachKeyValue( + nostd::function_ref) const noexcept + { + return true; + }; + + virtual size_t size() const noexcept { return 0; } +}; + } // namespace common OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/logs/logger.h b/api/include/opentelemetry/logs/logger.h index c7e4896165..53aa6e872d 100644 --- a/api/include/opentelemetry/logs/logger.h +++ b/api/include/opentelemetry/logs/logger.h @@ -28,6 +28,7 @@ #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/nostd/span.h" #include "opentelemetry/nostd/string_view.h" +#include "opentelemetry/nostd/type_traits.h" #include "opentelemetry/trace/span_id.h" #include "opentelemetry/trace/trace_flags.h" #include "opentelemetry/trace/trace_id.h" diff --git a/api/include/opentelemetry/nostd/function_ref.h b/api/include/opentelemetry/nostd/function_ref.h index de61c7040a..508cc53029 100644 --- a/api/include/opentelemetry/nostd/function_ref.h +++ b/api/include/opentelemetry/nostd/function_ref.h @@ -1,3 +1,17 @@ +// Copyright 2020, OpenTelemetry 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 +// +// 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 diff --git a/api/include/opentelemetry/nostd/mpark/variant.h b/api/include/opentelemetry/nostd/mpark/variant.h new file mode 100644 index 0000000000..097bb57355 --- /dev/null +++ b/api/include/opentelemetry/nostd/mpark/variant.h @@ -0,0 +1,1281 @@ +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// Copyright OpenTelemetry Authors, 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file third_party/boost/LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#pragma once + +#include +#include +#include + +#include "opentelemetry/nostd/detail/all.h" +#include "opentelemetry/nostd/detail/dependent_type.h" +#include "opentelemetry/nostd/detail/find_index.h" +#include "opentelemetry/nostd/detail/functional.h" +#include "opentelemetry/nostd/detail/recursive_union.h" +#include "opentelemetry/nostd/detail/trait.h" +#include "opentelemetry/nostd/detail/type_pack_element.h" +#include "opentelemetry/nostd/detail/variant_alternative.h" +#include "opentelemetry/nostd/detail/variant_fwd.h" +#include "opentelemetry/nostd/detail/variant_size.h" +#include "opentelemetry/nostd/type_traits.h" +#include "opentelemetry/nostd/utility.h" +#include "opentelemetry/version.h" + +#define AUTO_RETURN(...) \ + ->decay_t { return __VA_ARGS__; } + +#define AUTO_REFREF_RETURN(...) \ + ->decltype((__VA_ARGS__)) \ + { \ + static_assert(std::is_reference::value, ""); \ + return __VA_ARGS__; \ + } + +#define DECLTYPE_AUTO_RETURN(...) \ + ->decltype(__VA_ARGS__) { return __VA_ARGS__; } + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace nostd +{ +constexpr std::size_t variant_npos = static_cast(-1); + +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() +{ +#if __EXCEPTIONS + throw bad_variant_access{}; +#else + std::terminate(); +#endif +} + +namespace detail +{ +namespace access +{ +struct base +{ + template + inline static constexpr auto get_alt(V &&v) +#ifdef _MSC_VER + AUTO_REFREF_RETURN(recursive_union::get_alt(std::forward(v).data_, in_place_index_t{})) +#else + AUTO_REFREF_RETURN(recursive_union::get_alt(data(std::forward(v)), in_place_index_t{})) +#endif +}; + +struct variant +{ + template + inline static constexpr auto get_alt(V &&v) + AUTO_REFREF_RETURN(base::get_alt(std::forward(v).impl_)) +}; +} // namespace access +} // namespace detail + +namespace detail +{ +namespace visitation +{ + +struct base +{ + template + using dispatch_result_t = decltype( + nostd::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 auto invoke(Visitor &&visitor, Alts &&... alts) + DECLTYPE_AUTO_RETURN(nostd::invoke(std::forward(visitor), + std::forward(alts)...)) + }; + + template + inline static constexpr const T &at(const T &elem) noexcept + { + return elem; + } + + template + inline static constexpr const remove_all_extents_t &at(const std::array &elems, + std::size_t i, + Is... is) noexcept + { + return at(elems[i], is...); + } + + template + inline static constexpr std::array, sizeof...(Fs) + 1> make_farray(F &&f, Fs &&... fs) + { + return {{std::forward(f), std::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( + nostd::invoke(std::forward(f), access::base::get_alt(std::forward(vs))...)); + return visit_return_type_check::invoke( + std::forward(f), access::base::get_alt(std::forward(vs))...); + } + + 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...>{}()...)) + }; + }; + + template + inline static constexpr auto make_fmatrix() AUTO_RETURN( + typename make_fmatrix_impl:: + template impl, make_index_sequence::size()>...>{}()) + + 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( + nostd::invoke(std::forward(f), access::base::get_alt(std::forward(vs))...)); + return visit_return_type_check::invoke( + std::forward(f), access::base::get_alt(std::forward(vs))...); + } + + template + inline static constexpr auto impl(index_sequence) + AUTO_RETURN(make_farray(&dispatch...)) + }; + + template + inline static constexpr auto make_fdiagonal() + -> decltype(make_fdiagonal_impl::impl(make_index_sequence::size()>{})) + { + static_assert(all<(decay_t::size() == decay_t::size())...>::value, + "all of the variants must be the same size."); + return make_fdiagonal_impl::impl(make_index_sequence::size()>{}); + } +}; + +#if !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 auto visit_alt(Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN( + base::at(base::make_fmatrix(vs)))...>(), + vs.index()...)(std::forward(visitor), as_base(std::forward(vs))...)) + + template + inline static constexpr auto visit_alt_at(std::size_t index, Visitor &&visitor, Vs &&... vs) + DECLTYPE_AUTO_RETURN(base::at( + base::make_fdiagonal(vs)))...>(), + index)(std::forward(visitor), as_base(std::forward(vs))...)) +}; + +struct variant +{ +private: + template + struct visitor + { + template + inline static constexpr bool does_not_handle() + { + return nostd::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 auto invoke(Visitor &&visitor, Values &&... values) + DECLTYPE_AUTO_RETURN(nostd::invoke(std::forward(visitor), + std::forward(values)...)) + }; + + template + struct value_visitor + { + Visitor &&visitor_; + + template + inline constexpr auto operator()(Alts &&... alts) const DECLTYPE_AUTO_RETURN( + visit_exhaustiveness_check(alts).value))...>::invoke( + std::forward(visitor_), + std::forward(alts).value...)) + }; + + template + inline static constexpr auto make_value_visitor(Visitor &&visitor) + AUTO_RETURN(value_visitor{std::forward(visitor)}) + + public + : template + inline static constexpr auto visit_alt(Visitor &&visitor, Vs &&... vs) + DECLTYPE_AUTO_RETURN(alt::visit_alt(std::forward(visitor), + std::forward(vs).impl_...)) + + template + inline static constexpr auto visit_alt_at(std::size_t index, + Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN(alt::visit_alt_at(index, + std::forward(visitor), + std::forward(vs).impl_...)) + + template + inline static constexpr auto visit_value(Visitor &&visitor, Vs &&... vs) + DECLTYPE_AUTO_RETURN( + visit_alt(make_value_visitor(std::forward(visitor)), + std::forward(vs)...)) + + template + inline static constexpr auto visit_value_at(std::size_t index, + Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN(visit_alt_at( + index, + make_value_visitor(std::forward(visitor)), + std::forward(vs)...)) +}; +} // namespace visitation + +template +using index_t = typename std::conditional< + sizeof...(Ts) < (std::numeric_limits::max)(), + unsigned char, + typename std::conditional::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{}, std::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 std::move(b); } + friend inline constexpr const base &&as_base(const base &&b) { return std::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 std::move(b).data_; } + friend inline constexpr const data_t &&data(const base &&b) { return std::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 +}; + +template +class destructor; + +#define OPENTELEMETRY_VARIANT_DESTRUCTOR(destructible_trait, definition, destroy) \ + template \ + class destructor, destructible_trait> : public base \ + { \ + using super = base; \ + \ + public: \ + using super::super; \ + using super::operator=; \ + \ + destructor(const destructor &) = default; \ + destructor(destructor &&) = default; \ + definition destructor &operator=(const destructor &) = default; \ + destructor &operator=(destructor &&) = default; \ + \ + protected: \ + destroy \ + } + +OPENTELEMETRY_VARIANT_DESTRUCTOR( + Trait::TriviallyAvailable, ~destructor() = default; + , inline void destroy() noexcept { this->index_ = static_cast>(-1); }); + +OPENTELEMETRY_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); + }); + +OPENTELEMETRY_VARIANT_DESTRUCTOR(Trait::Unavailable, ~destructor() = delete; + , inline void destroy() noexcept = delete;); + +#undef OPENTELEMETRY_VARIANT_DESTRUCTOR + +template +class constructor : public destructor +{ + using super = destructor; + +public: + using super::super; + using super::operator=; + +protected: + struct ctor + { + template + inline void operator()(LhsAlt &lhs_alt, RhsAlt &&rhs_alt) const + { + constructor::construct_alt(lhs_alt, std::forward(rhs_alt).value); + } + }; + + template + inline static T &construct_alt(alt &a, Args &&... args) + { + auto *result = ::new (static_cast(std::addressof(a))) + alt(in_place_t{}, std::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(), ctor{}, lhs, std::forward(rhs)); + lhs.index_ = rhs.index_; + } + } +}; + +template +class move_constructor; + +#define OPENTELEMETRY_VARIANT_MOVE_CONSTRUCTOR(move_constructible_trait, definition) \ + template \ + class move_constructor, move_constructible_trait> \ + : public constructor> \ + { \ + using super = constructor>; \ + \ + public: \ + using super::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; \ + } + +OPENTELEMETRY_VARIANT_MOVE_CONSTRUCTOR(Trait::TriviallyAvailable, + move_constructor(move_constructor &&that) = default;); + +OPENTELEMETRY_VARIANT_MOVE_CONSTRUCTOR( + Trait::Available, + move_constructor(move_constructor &&that) noexcept( + all::value...>::value) + : move_constructor(valueless_t{}) { this->generic_construct(*this, std::move(that)); }); + +OPENTELEMETRY_VARIANT_MOVE_CONSTRUCTOR(Trait::Unavailable, + move_constructor(move_constructor &&) = delete;); + +#undef OPENTELEMETRY_VARIANT_MOVE_CONSTRUCTOR + +template +class copy_constructor; + +#define OPENTELEMETRY_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait, definition) \ + template \ + class copy_constructor, copy_constructible_trait> \ + : public move_constructor> \ + { \ + using super = move_constructor>; \ + \ + public: \ + using super::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; \ + } + +OPENTELEMETRY_VARIANT_COPY_CONSTRUCTOR(Trait::TriviallyAvailable, + copy_constructor(const copy_constructor &that) = default;); + +OPENTELEMETRY_VARIANT_COPY_CONSTRUCTOR( + Trait::Available, copy_constructor(const copy_constructor &that) + : copy_constructor(valueless_t{}) { this->generic_construct(*this, that); }); + +OPENTELEMETRY_VARIANT_COPY_CONSTRUCTOR(Trait::Unavailable, + copy_constructor(const copy_constructor &) = delete;); + +#undef OPENTELEMETRY_VARIANT_COPY_CONSTRUCTOR + +template +class assignment : public copy_constructor +{ + using super = copy_constructor; + +public: + using super::super; + using super::operator=; + + template + inline /* auto & */ auto emplace(Args &&... args) + -> decltype(this->construct_alt(access::base::get_alt(*this), std::forward(args)...)) + { + this->destroy(); + auto &result = + this->construct_alt(access::base::get_alt(*this), std::forward(args)...); + this->index_ = I; + return result; + } + +protected: + template + struct assigner + { + template + inline void operator()(ThisAlt &this_alt, ThatAlt &&that_alt) const + { + self->assign_alt(this_alt, std::forward(that_alt).value); + } + assignment *self; + }; + + 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 = std::forward(arg); +#ifdef _MSC_VER +# pragma warning(pop) +#endif + } + else + { + struct + { + void operator()(std::true_type) const { this_->emplace(std::forward(arg_)); } + void operator()(std::false_type) const { this_->emplace(T(std::forward(arg_))); } + assignment *this_; + Arg &&arg_; + } impl{this, std::forward(arg)}; + impl(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(), assigner{this}, *this, + std::forward(that)); + } + } +}; + +template +class move_assignment; + +#define OPENTELEMETRY_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, definition) \ + template \ + class move_assignment, move_assignable_trait> : public assignment> \ + { \ + using super = assignment>; \ + \ + public: \ + using super::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 \ + } + +OPENTELEMETRY_VARIANT_MOVE_ASSIGNMENT( + Trait::TriviallyAvailable, move_assignment &operator=(move_assignment &&that) = default;); + +OPENTELEMETRY_VARIANT_MOVE_ASSIGNMENT( + Trait::Available, + move_assignment & + operator=(move_assignment &&that) noexcept( + all<(std::is_nothrow_move_constructible::value && + std::is_nothrow_move_assignable::value)...>::value) { + this->generic_assign(std::move(that)); + return *this; + }); + +OPENTELEMETRY_VARIANT_MOVE_ASSIGNMENT(Trait::Unavailable, + move_assignment &operator=(move_assignment &&) = delete;); + +#undef OPENTELEMETRY_VARIANT_MOVE_ASSIGNMENT + +template +class copy_assignment; + +#define OPENTELEMETRY_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, definition) \ + template \ + class copy_assignment, copy_assignable_trait> \ + : public move_assignment> \ + { \ + using super = move_assignment>; \ + \ + public: \ + using super::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; \ + } + +OPENTELEMETRY_VARIANT_COPY_ASSIGNMENT( + Trait::TriviallyAvailable, copy_assignment &operator=(const copy_assignment &that) = default;); + +OPENTELEMETRY_VARIANT_COPY_ASSIGNMENT( + Trait::Available, + copy_assignment & + operator=(const copy_assignment &that) { + this->generic_assign(that); + return *this; + }); + +OPENTELEMETRY_VARIANT_COPY_ASSIGNMENT( + Trait::Unavailable, copy_assignment &operator=(const copy_assignment &) = delete;); + +#undef OPENTELEMETRY_VARIANT_COPY_ASSIGNMENT +template +class impl : public copy_assignment> +{ + using super = copy_assignment>; + +public: + using super::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), std::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(), swapper{}, *this, that); + } + else + { + impl *lhs = this; + impl *rhs = std::addressof(that); + if (lhs->move_nothrow() && !rhs->move_nothrow()) + { + std::swap(lhs, rhs); + } + impl tmp(std::move(*rhs)); +#if __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, std::move(*lhs)); + } + catch (...) + { + if (tmp.move_nothrow()) + { + this->generic_construct(*rhs, std::move(tmp)); + } + throw; + } +#else + this->generic_construct(*rhs, std::move(*lhs)); +#endif + this->generic_construct(*lhs, std::move(tmp)); + } + } + +private: + struct swapper + { + template + inline void operator()(ThisAlt &this_alt, ThatAlt &that_alt) const + { + using std::swap; + swap(this_alt.value, that_alt.value); + } + }; + + inline constexpr bool move_nothrow() const + { + return this->valueless_by_exception() || + std::array{ + {std::is_nothrow_move_constructible::value...}}[this->index()]; + } +}; + +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 = size_constant (*)(T); + operator impl() const { return nullptr; }; +}; + +template +struct overload_leaf, bool>::value + ? std::is_same, bool>::value + : +#if defined(__clang__) || !defined(__GNUC__) || __GNUC__ >= 5 + is_non_narrowing_convertible::value +#else + std::is_convertible::value +#endif + >> +{ + using impl = 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 = 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 +{}; +} // namespace detail + +template +class variant +{ + static_assert(0 < sizeof...(Ts), "variant must consist of at least one alternative."); + + static_assert(detail::all::value...>::value, + "variant can not have an array type as an alternative."); + + static_assert(detail::all::value...>::value, + "variant can not have a reference type as an alternative."); + + static_assert(detail::all::value...>::value, + "variant can not have a void type as an alternative."); + +public: + template , + 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 , + enable_if_t::value, int> = 0, + enable_if_t::value, int> = 0, + enable_if_t::value, int> = 0, + std::size_t I = detail::best_match::value, + typename T = detail::type_pack_element_t, + enable_if_t::value, int> = 0> + inline constexpr variant(Arg &&arg) noexcept(std::is_nothrow_constructible::value) + : impl_(in_place_index_t{}, std::forward(arg)) + {} + + template , + 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{}, std::forward(args)...) + {} + + template < + std::size_t I, + typename Up, + typename... Args, + typename T = detail::type_pack_element_t, + 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 &, + Args...>::value) + : impl_(in_place_index_t{}, il, std::forward(args)...) + {} + + template ::value, + 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{}, std::forward(args)...) + {} + + template < + typename T, + typename Up, + typename... Args, + std::size_t I = detail::find_index_sfinae::value, + 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 &, + Args...>::value) + : impl_(in_place_index_t{}, il, std::forward(args)...) + {} + + ~variant() = default; + + variant &operator=(const variant &) = default; + variant &operator=(variant &&) = default; + + template < + typename Arg, + enable_if_t, variant>::value, int> = 0, + std::size_t I = detail::best_match::value, + typename T = detail::type_pack_element_t, + 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(std::forward(arg)); + return *this; + } + + template , + enable_if_t::value, int> = 0> + inline T &emplace(Args &&... args) + { + return impl_.template emplace(std::forward(args)...); + } + + template < + std::size_t I, + typename Up, + typename... Args, + typename T = detail::type_pack_element_t, + enable_if_t &, Args...>::value, int> = 0> + inline T &emplace(std::initializer_list il, Args &&... args) + { + return impl_.template emplace(il, std::forward(args)...); + } + + template ::value, + enable_if_t::value, int> = 0> + inline T &emplace(Args &&... args) + { + return impl_.template emplace(std::forward(args)...); + } + + template < + typename T, + typename Up, + typename... Args, + std::size_t I = detail::find_index_sfinae::value, + enable_if_t &, Args...>::value, int> = 0> + inline T &emplace(std::initializer_list il, Args &&... args) + { + return impl_.template emplace(il, std::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 && + detail::dependent_type, Dummy>::value)...>::value, + int> = 0> + inline void swap(variant &that) noexcept( + detail::all<(std::is_nothrow_move_constructible::value && + 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 operator()(V &&v) const + AUTO_REFREF_RETURN(access::variant::get_alt(std::forward(v)).value) +}; + +template +inline constexpr auto generic_get(V &&v) AUTO_REFREF_RETURN(generic_get_impl( + holds_alternative(v) ? 0 : (throw_bad_variant_access(), 0))(std::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(std::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(std::move(v)); +} + +template +inline constexpr T &get(variant &v) +{ + return get::value>(v); +} + +template +inline constexpr T &&get(variant &&v) +{ + return get::value>(std::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>(std::move(v)); +} + +namespace detail +{ + +template +inline constexpr /* auto * */ auto generic_get_if(V *v) noexcept AUTO_RETURN( + v &&holds_alternative(*v) ? std::addressof(access::variant::get_alt(*v).value) : nullptr) + +} // namespace detail + +template +inline constexpr add_pointer_t>> get_if( + variant *v) noexcept +{ + return detail::generic_get_if(v); +} + +template +inline constexpr add_pointer_t>> get_if( + const variant *v) noexcept +{ + return detail::generic_get_if(v); +} + +template +inline constexpr add_pointer_t get_if(variant *v) noexcept +{ + return get_if::value>(v); +} + +template +inline constexpr 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 nostd::invoke(RelOp{}, std::forward(lhs), std::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; + return lhs.index() == rhs.index() && (lhs.valueless_by_exception() || + variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs)); +} + +template +inline constexpr bool operator!=(const variant &lhs, const variant &rhs) +{ + using detail::visitation::variant; + using not_equal_to = detail::convert_to_bool; + return lhs.index() != rhs.index() || + (!lhs.valueless_by_exception() && + variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs)); +} + +template +inline constexpr bool operator<(const variant &lhs, const variant &rhs) +{ + using detail::visitation::variant; + using less = detail::convert_to_bool; + 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))); +} + +template +inline constexpr bool operator>(const variant &lhs, const variant &rhs) +{ + using detail::visitation::variant; + using greater = detail::convert_to_bool; + 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))); +} + +template +inline constexpr bool operator<=(const variant &lhs, const variant &rhs) +{ + using detail::visitation::variant; + using less_equal = detail::convert_to_bool; + 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)))); +} + +template +inline constexpr bool operator>=(const variant &lhs, const variant &rhs) +{ + using detail::visitation::variant; + using greater_equal = detail::convert_to_bool; + 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)))); +} + +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; +} + +namespace detail +{ + +template +inline constexpr bool all_of_impl(const std::array &bs, std::size_t idx) +{ + return idx >= N || (bs[idx] && all_of_impl(bs, idx + 1)); +} + +template +inline constexpr bool all_of(const std::array &bs) +{ + return all_of_impl(bs, 0); +} + +} // namespace detail + +template +inline constexpr auto visit(Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN( + (detail::all_of(std::array{{!vs.valueless_by_exception()...}}) + ? (void)0 + : throw_bad_variant_access()), + detail::visitation::variant::visit_value(std::forward(visitor), + std::forward(vs)...)) template +inline auto swap(variant &lhs, variant &rhs) noexcept(noexcept(lhs.swap(rhs))) + -> decltype(lhs.swap(rhs)) +{ + lhs.swap(rhs); +} +} // namespace nostd +OPENTELEMETRY_END_NAMESPACE + +#undef AUTO_RETURN + +#undef AUTO_REFREF_RETURN + +#undef DECLTYPE_AUTO_RETURN diff --git a/api/include/opentelemetry/nostd/shared_ptr.h b/api/include/opentelemetry/nostd/shared_ptr.h index 7d84b6f408..e7c2a464d2 100644 --- a/api/include/opentelemetry/nostd/shared_ptr.h +++ b/api/include/opentelemetry/nostd/shared_ptr.h @@ -1,8 +1,26 @@ -#pragma once +// Copyright 2020, OpenTelemetry 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 +// +// 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 +#pragma once +#ifdef HAVE_CPP_STDLIB +# include "opentelemetry/std/shared_ptr.h" +#else +# include +# include +# include -#include "opentelemetry/version.h" +# include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE namespace nostd @@ -180,3 +198,4 @@ inline bool operator!=(std::nullptr_t, const shared_ptr &rhs) noexcept } } // namespace nostd OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/api/include/opentelemetry/nostd/span.h b/api/include/opentelemetry/nostd/span.h index f28a80cbbf..5b95010edd 100644 --- a/api/include/opentelemetry/nostd/span.h +++ b/api/include/opentelemetry/nostd/span.h @@ -1,14 +1,31 @@ +// Copyright 2020, OpenTelemetry 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #pragma once -#include -#include -#include -#include -#include -#include +#ifdef HAVE_CPP_STDLIB +# include "opentelemetry/std/span.h" +#else +# include +# include +# include +# include +# include +# include -#include "opentelemetry/nostd/utility.h" -#include "opentelemetry/version.h" +# include "opentelemetry/nostd/utility.h" +# include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE namespace nostd @@ -238,3 +255,4 @@ class span }; } // namespace nostd OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/api/include/opentelemetry/nostd/string_view.h b/api/include/opentelemetry/nostd/string_view.h index a5d65d00aa..4a5bdefa81 100644 --- a/api/include/opentelemetry/nostd/string_view.h +++ b/api/include/opentelemetry/nostd/string_view.h @@ -1,13 +1,30 @@ +// Copyright 2020, OpenTelemetry 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #pragma once -#include -#include -#include -#include -#include -#include +#ifdef HAVE_CPP_STDLIB +# include "opentelemetry/std/string_view.h" +#else +# include +# include +# include +# include +# include +# include -#include "opentelemetry/version.h" +# include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE namespace nostd @@ -58,11 +75,11 @@ class string_view { if (pos > length_) { -#if __EXCEPTIONS +# if __EXCEPTIONS throw std::out_of_range{"opentelemetry::nostd::string_view"}; -#else +# else std::terminate(); -#endif +# endif } n = (std::min)(n, length_ - pos); return string_view(data_ + pos, n); @@ -118,12 +135,12 @@ class string_view inline bool operator==(string_view lhs, string_view rhs) noexcept { return lhs.length() == rhs.length() && -#if _MSC_VER == 1900 +# if _MSC_VER == 1900 // Avoid SCL error in Visual Studio 2015 (std::memcmp(lhs.data(), rhs.data(), lhs.length()) == 0); -#else +# else std::equal(lhs.data(), lhs.data() + lhs.length(), rhs.data()); -#endif +# endif } inline bool operator==(string_view lhs, const std::string &rhs) noexcept @@ -192,3 +209,4 @@ struct hash } }; } // namespace std +#endif diff --git a/api/include/opentelemetry/nostd/type_traits.h b/api/include/opentelemetry/nostd/type_traits.h index a42f440df8..c1e4cfdf02 100644 --- a/api/include/opentelemetry/nostd/type_traits.h +++ b/api/include/opentelemetry/nostd/type_traits.h @@ -1,11 +1,28 @@ +// Copyright 2020, OpenTelemetry 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 +// +// 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 +#ifdef HAVE_CPP_STDLIB +# include "opentelemetry/std/type_traits.h" +#else +# include +# include -#include "opentelemetry/config.h" -#include "opentelemetry/nostd/detail/void.h" -#include "opentelemetry/version.h" +# include "opentelemetry/config.h" +# include "opentelemetry/nostd/detail/void.h" +# include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE namespace nostd @@ -116,12 +133,12 @@ using is_nothrow_swappable = detail::swappable::is_nothrow_swappable struct is_trivially_copy_constructible { @@ -145,6 +162,7 @@ struct is_trivially_move_assignable { static constexpr bool value = __is_trivial(T); }; -#endif +# endif } // namespace nostd OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/api/include/opentelemetry/nostd/unique_ptr.h b/api/include/opentelemetry/nostd/unique_ptr.h index fc9a36aa7b..b0418891d0 100644 --- a/api/include/opentelemetry/nostd/unique_ptr.h +++ b/api/include/opentelemetry/nostd/unique_ptr.h @@ -1,11 +1,28 @@ +// Copyright 2020, OpenTelemetry 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 +// +// 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 +#ifdef HAVE_CPP_STDLIB +# include "opentelemetry/std/unique_ptr.h" +#else +# include +# include +# include +# include -#include "opentelemetry/version.h" +# include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE namespace nostd @@ -166,3 +183,4 @@ bool operator!=(std::nullptr_t, const unique_ptr &rhs) noexcept } } // namespace nostd OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/api/include/opentelemetry/nostd/utility.h b/api/include/opentelemetry/nostd/utility.h index d7fa3bfc19..ae9197e714 100644 --- a/api/include/opentelemetry/nostd/utility.h +++ b/api/include/opentelemetry/nostd/utility.h @@ -1,12 +1,30 @@ +// Copyright 2020, OpenTelemetry 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 +// +// 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 +#ifdef HAVE_CPP_STDLIB +# include "opentelemetry/std/utility.h" +#else + +# include +# include +# include -#include "opentelemetry/nostd/detail/decay.h" -#include "opentelemetry/nostd/detail/invoke.h" -#include "opentelemetry/version.h" +# include "opentelemetry/nostd/detail/decay.h" +# include "opentelemetry/nostd/detail/invoke.h" +# include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE namespace nostd @@ -146,3 +164,4 @@ struct in_place_type_t }; } // namespace nostd OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/api/include/opentelemetry/nostd/variant.h b/api/include/opentelemetry/nostd/variant.h index 097bb57355..37281e1db6 100644 --- a/api/include/opentelemetry/nostd/variant.h +++ b/api/include/opentelemetry/nostd/variant.h @@ -1,1281 +1,33 @@ -// MPark.Variant +// Copyright 2020, OpenTelemetry Authors // -// Copyright Michael Park, 2015-2017 -// Copyright OpenTelemetry Authors, 2020 +// 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 // -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file third_party/boost/LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) +// 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 "opentelemetry/nostd/detail/all.h" -#include "opentelemetry/nostd/detail/dependent_type.h" -#include "opentelemetry/nostd/detail/find_index.h" -#include "opentelemetry/nostd/detail/functional.h" -#include "opentelemetry/nostd/detail/recursive_union.h" -#include "opentelemetry/nostd/detail/trait.h" -#include "opentelemetry/nostd/detail/type_pack_element.h" -#include "opentelemetry/nostd/detail/variant_alternative.h" -#include "opentelemetry/nostd/detail/variant_fwd.h" -#include "opentelemetry/nostd/detail/variant_size.h" -#include "opentelemetry/nostd/type_traits.h" -#include "opentelemetry/nostd/utility.h" -#include "opentelemetry/version.h" - -#define AUTO_RETURN(...) \ - ->decay_t { return __VA_ARGS__; } - -#define AUTO_REFREF_RETURN(...) \ - ->decltype((__VA_ARGS__)) \ - { \ - static_assert(std::is_reference::value, ""); \ - return __VA_ARGS__; \ - } - -#define DECLTYPE_AUTO_RETURN(...) \ - ->decltype(__VA_ARGS__) { return __VA_ARGS__; } - +#ifdef HAVE_CPP_STDLIB +# include "opentelemetry/std/variant.h" +#elif defined(HAVE_ABSEIL) +// TODO: prefer `absl::variant` over `nostd::variant` since the latter does not compile with vs2015 +# include "absl/types/variant.h" OPENTELEMETRY_BEGIN_NAMESPACE namespace nostd { -constexpr std::size_t variant_npos = static_cast(-1); - -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() -{ -#if __EXCEPTIONS - throw bad_variant_access{}; -#else - std::terminate(); -#endif -} - -namespace detail -{ -namespace access -{ -struct base -{ - template - inline static constexpr auto get_alt(V &&v) -#ifdef _MSC_VER - AUTO_REFREF_RETURN(recursive_union::get_alt(std::forward(v).data_, in_place_index_t{})) -#else - AUTO_REFREF_RETURN(recursive_union::get_alt(data(std::forward(v)), in_place_index_t{})) -#endif -}; - -struct variant -{ - template - inline static constexpr auto get_alt(V &&v) - AUTO_REFREF_RETURN(base::get_alt(std::forward(v).impl_)) -}; -} // namespace access -} // namespace detail - -namespace detail -{ -namespace visitation -{ - -struct base -{ - template - using dispatch_result_t = decltype( - nostd::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 auto invoke(Visitor &&visitor, Alts &&... alts) - DECLTYPE_AUTO_RETURN(nostd::invoke(std::forward(visitor), - std::forward(alts)...)) - }; - - template - inline static constexpr const T &at(const T &elem) noexcept - { - return elem; - } - - template - inline static constexpr const remove_all_extents_t &at(const std::array &elems, - std::size_t i, - Is... is) noexcept - { - return at(elems[i], is...); - } - - template - inline static constexpr std::array, sizeof...(Fs) + 1> make_farray(F &&f, Fs &&... fs) - { - return {{std::forward(f), std::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( - nostd::invoke(std::forward(f), access::base::get_alt(std::forward(vs))...)); - return visit_return_type_check::invoke( - std::forward(f), access::base::get_alt(std::forward(vs))...); - } - - 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...>{}()...)) - }; - }; - - template - inline static constexpr auto make_fmatrix() AUTO_RETURN( - typename make_fmatrix_impl:: - template impl, make_index_sequence::size()>...>{}()) - - 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( - nostd::invoke(std::forward(f), access::base::get_alt(std::forward(vs))...)); - return visit_return_type_check::invoke( - std::forward(f), access::base::get_alt(std::forward(vs))...); - } - - template - inline static constexpr auto impl(index_sequence) - AUTO_RETURN(make_farray(&dispatch...)) - }; - - template - inline static constexpr auto make_fdiagonal() - -> decltype(make_fdiagonal_impl::impl(make_index_sequence::size()>{})) - { - static_assert(all<(decay_t::size() == decay_t::size())...>::value, - "all of the variants must be the same size."); - return make_fdiagonal_impl::impl(make_index_sequence::size()>{}); - } -}; - -#if !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 auto visit_alt(Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN( - base::at(base::make_fmatrix(vs)))...>(), - vs.index()...)(std::forward(visitor), as_base(std::forward(vs))...)) - - template - inline static constexpr auto visit_alt_at(std::size_t index, Visitor &&visitor, Vs &&... vs) - DECLTYPE_AUTO_RETURN(base::at( - base::make_fdiagonal(vs)))...>(), - index)(std::forward(visitor), as_base(std::forward(vs))...)) -}; - -struct variant -{ -private: - template - struct visitor - { - template - inline static constexpr bool does_not_handle() - { - return nostd::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 auto invoke(Visitor &&visitor, Values &&... values) - DECLTYPE_AUTO_RETURN(nostd::invoke(std::forward(visitor), - std::forward(values)...)) - }; - - template - struct value_visitor - { - Visitor &&visitor_; - - template - inline constexpr auto operator()(Alts &&... alts) const DECLTYPE_AUTO_RETURN( - visit_exhaustiveness_check(alts).value))...>::invoke( - std::forward(visitor_), - std::forward(alts).value...)) - }; - - template - inline static constexpr auto make_value_visitor(Visitor &&visitor) - AUTO_RETURN(value_visitor{std::forward(visitor)}) - - public - : template - inline static constexpr auto visit_alt(Visitor &&visitor, Vs &&... vs) - DECLTYPE_AUTO_RETURN(alt::visit_alt(std::forward(visitor), - std::forward(vs).impl_...)) - - template - inline static constexpr auto visit_alt_at(std::size_t index, - Visitor &&visitor, - Vs &&... vs) - DECLTYPE_AUTO_RETURN(alt::visit_alt_at(index, - std::forward(visitor), - std::forward(vs).impl_...)) - - template - inline static constexpr auto visit_value(Visitor &&visitor, Vs &&... vs) - DECLTYPE_AUTO_RETURN( - visit_alt(make_value_visitor(std::forward(visitor)), - std::forward(vs)...)) - - template - inline static constexpr auto visit_value_at(std::size_t index, - Visitor &&visitor, - Vs &&... vs) - DECLTYPE_AUTO_RETURN(visit_alt_at( - index, - make_value_visitor(std::forward(visitor)), - std::forward(vs)...)) -}; -} // namespace visitation - -template -using index_t = typename std::conditional< - sizeof...(Ts) < (std::numeric_limits::max)(), - unsigned char, - typename std::conditional::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{}, std::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 std::move(b); } - friend inline constexpr const base &&as_base(const base &&b) { return std::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 std::move(b).data_; } - friend inline constexpr const data_t &&data(const base &&b) { return std::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 -}; - -template -class destructor; - -#define OPENTELEMETRY_VARIANT_DESTRUCTOR(destructible_trait, definition, destroy) \ - template \ - class destructor, destructible_trait> : public base \ - { \ - using super = base; \ - \ - public: \ - using super::super; \ - using super::operator=; \ - \ - destructor(const destructor &) = default; \ - destructor(destructor &&) = default; \ - definition destructor &operator=(const destructor &) = default; \ - destructor &operator=(destructor &&) = default; \ - \ - protected: \ - destroy \ - } - -OPENTELEMETRY_VARIANT_DESTRUCTOR( - Trait::TriviallyAvailable, ~destructor() = default; - , inline void destroy() noexcept { this->index_ = static_cast>(-1); }); - -OPENTELEMETRY_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); - }); - -OPENTELEMETRY_VARIANT_DESTRUCTOR(Trait::Unavailable, ~destructor() = delete; - , inline void destroy() noexcept = delete;); - -#undef OPENTELEMETRY_VARIANT_DESTRUCTOR - -template -class constructor : public destructor -{ - using super = destructor; - -public: - using super::super; - using super::operator=; - -protected: - struct ctor - { - template - inline void operator()(LhsAlt &lhs_alt, RhsAlt &&rhs_alt) const - { - constructor::construct_alt(lhs_alt, std::forward(rhs_alt).value); - } - }; - - template - inline static T &construct_alt(alt &a, Args &&... args) - { - auto *result = ::new (static_cast(std::addressof(a))) - alt(in_place_t{}, std::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(), ctor{}, lhs, std::forward(rhs)); - lhs.index_ = rhs.index_; - } - } -}; - -template -class move_constructor; - -#define OPENTELEMETRY_VARIANT_MOVE_CONSTRUCTOR(move_constructible_trait, definition) \ - template \ - class move_constructor, move_constructible_trait> \ - : public constructor> \ - { \ - using super = constructor>; \ - \ - public: \ - using super::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; \ - } - -OPENTELEMETRY_VARIANT_MOVE_CONSTRUCTOR(Trait::TriviallyAvailable, - move_constructor(move_constructor &&that) = default;); - -OPENTELEMETRY_VARIANT_MOVE_CONSTRUCTOR( - Trait::Available, - move_constructor(move_constructor &&that) noexcept( - all::value...>::value) - : move_constructor(valueless_t{}) { this->generic_construct(*this, std::move(that)); }); - -OPENTELEMETRY_VARIANT_MOVE_CONSTRUCTOR(Trait::Unavailable, - move_constructor(move_constructor &&) = delete;); - -#undef OPENTELEMETRY_VARIANT_MOVE_CONSTRUCTOR - -template -class copy_constructor; - -#define OPENTELEMETRY_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait, definition) \ - template \ - class copy_constructor, copy_constructible_trait> \ - : public move_constructor> \ - { \ - using super = move_constructor>; \ - \ - public: \ - using super::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; \ - } - -OPENTELEMETRY_VARIANT_COPY_CONSTRUCTOR(Trait::TriviallyAvailable, - copy_constructor(const copy_constructor &that) = default;); - -OPENTELEMETRY_VARIANT_COPY_CONSTRUCTOR( - Trait::Available, copy_constructor(const copy_constructor &that) - : copy_constructor(valueless_t{}) { this->generic_construct(*this, that); }); - -OPENTELEMETRY_VARIANT_COPY_CONSTRUCTOR(Trait::Unavailable, - copy_constructor(const copy_constructor &) = delete;); - -#undef OPENTELEMETRY_VARIANT_COPY_CONSTRUCTOR - -template -class assignment : public copy_constructor -{ - using super = copy_constructor; - -public: - using super::super; - using super::operator=; - - template - inline /* auto & */ auto emplace(Args &&... args) - -> decltype(this->construct_alt(access::base::get_alt(*this), std::forward(args)...)) - { - this->destroy(); - auto &result = - this->construct_alt(access::base::get_alt(*this), std::forward(args)...); - this->index_ = I; - return result; - } - -protected: - template - struct assigner - { - template - inline void operator()(ThisAlt &this_alt, ThatAlt &&that_alt) const - { - self->assign_alt(this_alt, std::forward(that_alt).value); - } - assignment *self; - }; - - 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 = std::forward(arg); -#ifdef _MSC_VER -# pragma warning(pop) -#endif - } - else - { - struct - { - void operator()(std::true_type) const { this_->emplace(std::forward(arg_)); } - void operator()(std::false_type) const { this_->emplace(T(std::forward(arg_))); } - assignment *this_; - Arg &&arg_; - } impl{this, std::forward(arg)}; - impl(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(), assigner{this}, *this, - std::forward(that)); - } - } -}; - -template -class move_assignment; - -#define OPENTELEMETRY_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, definition) \ - template \ - class move_assignment, move_assignable_trait> : public assignment> \ - { \ - using super = assignment>; \ - \ - public: \ - using super::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 \ - } - -OPENTELEMETRY_VARIANT_MOVE_ASSIGNMENT( - Trait::TriviallyAvailable, move_assignment &operator=(move_assignment &&that) = default;); - -OPENTELEMETRY_VARIANT_MOVE_ASSIGNMENT( - Trait::Available, - move_assignment & - operator=(move_assignment &&that) noexcept( - all<(std::is_nothrow_move_constructible::value && - std::is_nothrow_move_assignable::value)...>::value) { - this->generic_assign(std::move(that)); - return *this; - }); - -OPENTELEMETRY_VARIANT_MOVE_ASSIGNMENT(Trait::Unavailable, - move_assignment &operator=(move_assignment &&) = delete;); - -#undef OPENTELEMETRY_VARIANT_MOVE_ASSIGNMENT - -template -class copy_assignment; - -#define OPENTELEMETRY_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, definition) \ - template \ - class copy_assignment, copy_assignable_trait> \ - : public move_assignment> \ - { \ - using super = move_assignment>; \ - \ - public: \ - using super::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; \ - } - -OPENTELEMETRY_VARIANT_COPY_ASSIGNMENT( - Trait::TriviallyAvailable, copy_assignment &operator=(const copy_assignment &that) = default;); - -OPENTELEMETRY_VARIANT_COPY_ASSIGNMENT( - Trait::Available, - copy_assignment & - operator=(const copy_assignment &that) { - this->generic_assign(that); - return *this; - }); - -OPENTELEMETRY_VARIANT_COPY_ASSIGNMENT( - Trait::Unavailable, copy_assignment &operator=(const copy_assignment &) = delete;); - -#undef OPENTELEMETRY_VARIANT_COPY_ASSIGNMENT -template -class impl : public copy_assignment> -{ - using super = copy_assignment>; - -public: - using super::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), std::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(), swapper{}, *this, that); - } - else - { - impl *lhs = this; - impl *rhs = std::addressof(that); - if (lhs->move_nothrow() && !rhs->move_nothrow()) - { - std::swap(lhs, rhs); - } - impl tmp(std::move(*rhs)); -#if __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, std::move(*lhs)); - } - catch (...) - { - if (tmp.move_nothrow()) - { - this->generic_construct(*rhs, std::move(tmp)); - } - throw; - } -#else - this->generic_construct(*rhs, std::move(*lhs)); -#endif - this->generic_construct(*lhs, std::move(tmp)); - } - } - -private: - struct swapper - { - template - inline void operator()(ThisAlt &this_alt, ThatAlt &that_alt) const - { - using std::swap; - swap(this_alt.value, that_alt.value); - } - }; - - inline constexpr bool move_nothrow() const - { - return this->valueless_by_exception() || - std::array{ - {std::is_nothrow_move_constructible::value...}}[this->index()]; - } -}; - -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 = size_constant (*)(T); - operator impl() const { return nullptr; }; -}; - -template -struct overload_leaf, bool>::value - ? std::is_same, bool>::value - : -#if defined(__clang__) || !defined(__GNUC__) || __GNUC__ >= 5 - is_non_narrowing_convertible::value -#else - std::is_convertible::value -#endif - >> -{ - using impl = 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 = 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 -{}; -} // namespace detail - -template -class variant -{ - static_assert(0 < sizeof...(Ts), "variant must consist of at least one alternative."); - - static_assert(detail::all::value...>::value, - "variant can not have an array type as an alternative."); - - static_assert(detail::all::value...>::value, - "variant can not have a reference type as an alternative."); - - static_assert(detail::all::value...>::value, - "variant can not have a void type as an alternative."); - -public: - template , - 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 , - enable_if_t::value, int> = 0, - enable_if_t::value, int> = 0, - enable_if_t::value, int> = 0, - std::size_t I = detail::best_match::value, - typename T = detail::type_pack_element_t, - enable_if_t::value, int> = 0> - inline constexpr variant(Arg &&arg) noexcept(std::is_nothrow_constructible::value) - : impl_(in_place_index_t{}, std::forward(arg)) - {} - - template , - 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{}, std::forward(args)...) - {} - - template < - std::size_t I, - typename Up, - typename... Args, - typename T = detail::type_pack_element_t, - 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 &, - Args...>::value) - : impl_(in_place_index_t{}, il, std::forward(args)...) - {} - - template ::value, - 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{}, std::forward(args)...) - {} - - template < - typename T, - typename Up, - typename... Args, - std::size_t I = detail::find_index_sfinae::value, - 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 &, - Args...>::value) - : impl_(in_place_index_t{}, il, std::forward(args)...) - {} - - ~variant() = default; - - variant &operator=(const variant &) = default; - variant &operator=(variant &&) = default; - - template < - typename Arg, - enable_if_t, variant>::value, int> = 0, - std::size_t I = detail::best_match::value, - typename T = detail::type_pack_element_t, - 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(std::forward(arg)); - return *this; - } - - template , - enable_if_t::value, int> = 0> - inline T &emplace(Args &&... args) - { - return impl_.template emplace(std::forward(args)...); - } - - template < - std::size_t I, - typename Up, - typename... Args, - typename T = detail::type_pack_element_t, - enable_if_t &, Args...>::value, int> = 0> - inline T &emplace(std::initializer_list il, Args &&... args) - { - return impl_.template emplace(il, std::forward(args)...); - } - - template ::value, - enable_if_t::value, int> = 0> - inline T &emplace(Args &&... args) - { - return impl_.template emplace(std::forward(args)...); - } - - template < - typename T, - typename Up, - typename... Args, - std::size_t I = detail::find_index_sfinae::value, - enable_if_t &, Args...>::value, int> = 0> - inline T &emplace(std::initializer_list il, Args &&... args) - { - return impl_.template emplace(il, std::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 && - detail::dependent_type, Dummy>::value)...>::value, - int> = 0> - inline void swap(variant &that) noexcept( - detail::all<(std::is_nothrow_move_constructible::value && - 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 operator()(V &&v) const - AUTO_REFREF_RETURN(access::variant::get_alt(std::forward(v)).value) -}; - -template -inline constexpr auto generic_get(V &&v) AUTO_REFREF_RETURN(generic_get_impl( - holds_alternative(v) ? 0 : (throw_bad_variant_access(), 0))(std::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(std::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(std::move(v)); -} - -template -inline constexpr T &get(variant &v) -{ - return get::value>(v); -} - -template -inline constexpr T &&get(variant &&v) -{ - return get::value>(std::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>(std::move(v)); -} - -namespace detail -{ - -template -inline constexpr /* auto * */ auto generic_get_if(V *v) noexcept AUTO_RETURN( - v &&holds_alternative(*v) ? std::addressof(access::variant::get_alt(*v).value) : nullptr) - -} // namespace detail - -template -inline constexpr add_pointer_t>> get_if( - variant *v) noexcept -{ - return detail::generic_get_if(v); -} - -template -inline constexpr add_pointer_t>> get_if( - const variant *v) noexcept -{ - return detail::generic_get_if(v); -} - -template -inline constexpr add_pointer_t get_if(variant *v) noexcept -{ - return get_if::value>(v); -} - -template -inline constexpr 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 nostd::invoke(RelOp{}, std::forward(lhs), std::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; - return lhs.index() == rhs.index() && (lhs.valueless_by_exception() || - variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs)); -} - -template -inline constexpr bool operator!=(const variant &lhs, const variant &rhs) -{ - using detail::visitation::variant; - using not_equal_to = detail::convert_to_bool; - return lhs.index() != rhs.index() || - (!lhs.valueless_by_exception() && - variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs)); -} - -template -inline constexpr bool operator<(const variant &lhs, const variant &rhs) -{ - using detail::visitation::variant; - using less = detail::convert_to_bool; - 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))); -} - -template -inline constexpr bool operator>(const variant &lhs, const variant &rhs) -{ - using detail::visitation::variant; - using greater = detail::convert_to_bool; - 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))); -} - -template -inline constexpr bool operator<=(const variant &lhs, const variant &rhs) -{ - using detail::visitation::variant; - using less_equal = detail::convert_to_bool; - 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)))); -} - -template -inline constexpr bool operator>=(const variant &lhs, const variant &rhs) -{ - using detail::visitation::variant; - using greater_equal = detail::convert_to_bool; - 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)))); -} - -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; -} - -namespace detail -{ - -template -inline constexpr bool all_of_impl(const std::array &bs, std::size_t idx) -{ - return idx >= N || (bs[idx] && all_of_impl(bs, idx + 1)); -} - -template -inline constexpr bool all_of(const std::array &bs) -{ - return all_of_impl(bs, 0); -} - -} // namespace detail - -template -inline constexpr auto visit(Visitor &&visitor, Vs &&... vs) DECLTYPE_AUTO_RETURN( - (detail::all_of(std::array{{!vs.valueless_by_exception()...}}) - ? (void)0 - : throw_bad_variant_access()), - detail::visitation::variant::visit_value(std::forward(visitor), - std::forward(vs)...)) template -inline auto swap(variant &lhs, variant &rhs) noexcept(noexcept(lhs.swap(rhs))) - -> decltype(lhs.swap(rhs)) -{ - lhs.swap(rhs); -} +using absl::get; +using absl::holds_alternative; +using absl::variant; +using absl::visit; } // namespace nostd OPENTELEMETRY_END_NAMESPACE - -#undef AUTO_RETURN - -#undef AUTO_REFREF_RETURN - -#undef DECLTYPE_AUTO_RETURN +#else +# include "opentelemetry/nostd/mpark/variant.h" +#endif diff --git a/api/include/opentelemetry/std/shared_ptr.h b/api/include/opentelemetry/std/shared_ptr.h new file mode 100644 index 0000000000..8969f2ced5 --- /dev/null +++ b/api/include/opentelemetry/std/shared_ptr.h @@ -0,0 +1,31 @@ +// Copyright 2020, OpenTelemetry 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 +// +// 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 "opentelemetry/version.h" + +#include + +OPENTELEMETRY_BEGIN_NAMESPACE +// Standard Type aliases in nostd namespace +namespace nostd +{ + +// nostd::shared_ptr +template +using shared_ptr = std::shared_ptr<_Types...>; + +} // namespace nostd +OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/std/span.h b/api/include/opentelemetry/std/span.h new file mode 100644 index 0000000000..da9fcb48a3 --- /dev/null +++ b/api/include/opentelemetry/std/span.h @@ -0,0 +1,76 @@ +// Copyright 2020, OpenTelemetry 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 +// +// 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 "opentelemetry/version.h" + +// Standard library implementation requires at least C++17 compiler. +// Older C++14 compilers may provide support for __has_include as a +// conforming extension. +#if defined __has_include +# if __has_include() // Check for __cpp_{feature} +# include +# if defined(__cpp_lib_span) +# define HAVE_SPAN +# endif +# endif +# if __has_include() && !defined(HAVE_SPAN) // Check for span +# define HAVE_SPAN +# endif +# if !__has_include() // Check for string_view +# error \ + "STL library does not support std::span. Possible solution:" \ + " - #undef HAVE_CPP_STDLIB // to use OpenTelemetry nostd::string_view" +# endif +#endif + +#if !defined(HAVE_SPAN) +# if defined(HAVE_GSL) +# include +// Guidelines Support Library provides an implementation of std::span +# include +OPENTELEMETRY_BEGIN_NAMESPACE +namespace nostd +{ +template +using span = gsl::span; +} +OPENTELEMETRY_END_NAMESPACE +# else +// No span implementation provided. +# error \ + "STL library does not support std::span. Possible solutions:" \ + " - #undef HAVE_CPP_STDLIB // to use OpenTelemetry nostd::span .. or " \ + " - #define HAVE_GSL // to use gsl::span " +# endif + +#else // HAVE_SPAN +// Using std::span (https://wg21.link/P0122R7) from Standard Library available in C++20 : +// - GCC libstdc++ 10+ +// - Clang libc++ 7 +// - MSVC Standard Library 19.26* +// - Apple Clang 10.0.0* +# include +# include +OPENTELEMETRY_BEGIN_NAMESPACE +namespace nostd +{ +constexpr std::size_t dynamic_extent = std::numeric_limits::max(); + +template +using span = std::span; +} // namespace nostd +OPENTELEMETRY_END_NAMESPACE +#endif // of HAVE_SPAN diff --git a/api/include/opentelemetry/std/string_view.h b/api/include/opentelemetry/std/string_view.h new file mode 100644 index 0000000000..755b4387a1 --- /dev/null +++ b/api/include/opentelemetry/std/string_view.h @@ -0,0 +1,36 @@ +// Copyright 2020, OpenTelemetry 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 +// +// 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 "opentelemetry/version.h" + +#include "opentelemetry/std/utility.h" + +#include +#include +#include +#include +#include + +OPENTELEMETRY_BEGIN_NAMESPACE +// Standard Type aliases in nostd namespace +namespace nostd +{ + +// nostd::string_view +using string_view = std::string_view; + +} // namespace nostd +OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/std/type_traits.h b/api/include/opentelemetry/std/type_traits.h new file mode 100644 index 0000000000..1fd6ef7f88 --- /dev/null +++ b/api/include/opentelemetry/std/type_traits.h @@ -0,0 +1,31 @@ +// Copyright 2020, OpenTelemetry 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 +// +// 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 "opentelemetry/version.h" + +#include + +OPENTELEMETRY_BEGIN_NAMESPACE +// Standard Type aliases in nostd namespace +namespace nostd +{ + +// nostd::enable_if_t<...> +template +using enable_if_t = typename std::enable_if::type; + +} // namespace nostd +OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/std/unique_ptr.h b/api/include/opentelemetry/std/unique_ptr.h new file mode 100644 index 0000000000..7877d2d854 --- /dev/null +++ b/api/include/opentelemetry/std/unique_ptr.h @@ -0,0 +1,31 @@ +// Copyright 2020, OpenTelemetry 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 +// +// 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 "opentelemetry/version.h" + +#include + +OPENTELEMETRY_BEGIN_NAMESPACE +// Standard Type aliases in nostd namespace +namespace nostd +{ + +// nostd::unique_ptr +template +using unique_ptr = std::unique_ptr<_Types...>; + +} // namespace nostd +OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/std/utility.h b/api/include/opentelemetry/std/utility.h new file mode 100644 index 0000000000..a0d73c9fe9 --- /dev/null +++ b/api/include/opentelemetry/std/utility.h @@ -0,0 +1,80 @@ +// Copyright 2020, OpenTelemetry 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 +// +// 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 "opentelemetry/version.h" + +#include +#include + +OPENTELEMETRY_BEGIN_NAMESPACE +// Standard Type aliases in nostd namespace +namespace nostd +{ + +// +// Backport of std::data +// +// See https://en.cppreference.com/w/cpp/iterator/data +// +template +auto data(C &c) noexcept(noexcept(c.data())) -> decltype(c.data()) +{ + return c.data(); +} + +template +auto data(const C &c) noexcept(noexcept(c.data())) -> decltype(c.data()) +{ + return c.data(); +} + +template +T *data(T (&array)[N]) noexcept +{ + return array; +} + +template +const E *data(std::initializer_list list) noexcept +{ + return list.begin(); +} + +// +// Backport of std::size +// +// See https://en.cppreference.com/w/cpp/iterator/size +// +template +auto size(const C &c) noexcept(noexcept(c.size())) -> decltype(c.size()) +{ + return c.size(); +} + +template +std::size_t size(T (&array)[N]) noexcept +{ + return N; +} + +template +using make_index_sequence = std::make_index_sequence; + +template +using index_sequence = std::index_sequence; + +} // namespace nostd +OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/std/variant.h b/api/include/opentelemetry/std/variant.h new file mode 100644 index 0000000000..5d19ff325c --- /dev/null +++ b/api/include/opentelemetry/std/variant.h @@ -0,0 +1,235 @@ +// Copyright 2020, OpenTelemetry 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 +// +// 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 "opentelemetry/version.h" + +#include +#include +#include +#include + +OPENTELEMETRY_BEGIN_NAMESPACE +// Standard Type aliases in nostd namespace +namespace nostd +{ + +// nostd::variant<...> +template +using variant = std::variant<_Types...>; + +template +using variant_size = std::variant_size<_Types...>; + +#if defined(__APPLE__) && defined(_LIBCPP_USE_AVAILABILITY_APPLE) +// Apple Platforms provide std::bad_variant_access only in newer versions of OS. +// To keep API compatible with any version of OS - we are providing our own +// implementation of nostd::bad_variant_access exception. +# if __EXCEPTIONS + +// nostd::bad_variant_access +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() +{ + throw bad_variant_access{}; +} +# endif + +# if __EXCEPTIONS +# define THROW_BAD_VARIANT_ACCESS throw_bad_variant_access() +# else +# define THROW_BAD_VARIANT_ACCESS std::terminate() +# endif + +// +// nostd::get<...> for Apple Clang +// +template +constexpr auto get_type = [](auto &&t) constexpr -> decltype(auto) +{ + auto v = t; + auto result = std::get_if(&v); // TODO: optimize with std::forward(t) if t is not rvalue + if (result) + { + return *result; + } + THROW_BAD_VARIANT_ACCESS; + return *result; +}; + +template +constexpr auto get_index = [](auto &&t) constexpr -> decltype(auto) +{ + auto v = t; + auto result = std::get_if(&v); // TODO: optimize with std::forward(t) if t is not rvalue + if (result) + { + return *result; + } + THROW_BAD_VARIANT_ACCESS; + return *result; +}; + +template +constexpr std::variant_alternative_t> &get(std::variant &v) +{ + return get_index(v); +}; + +template +constexpr std::variant_alternative_t> &&get(std::variant &&v) +{ + return get_index(std::forward(v)); +}; + +template +constexpr const std::variant_alternative_t> &get( + const std::variant &v) +{ + return get_index(v); +}; + +template +constexpr const std::variant_alternative_t> &&get( + const std::variant &&v) +{ + return get_index(std::forward(v)); +}; + +template +constexpr T &get(std::variant &v) +{ + return get_type(v); +}; + +template +constexpr T /*&&*/ get(std::variant &&v) +{ + return get_type(v); +}; + +template +constexpr const T &get(const std::variant &v) +{ + return get_type(v); +}; + +template +constexpr const T &&get(const std::variant &&v) +{ + return get_type(std::forward(v)); +}; + +template +constexpr auto visit(_Callable &&_Obj, _Variants &&... _Args) +{ + // Ref: + // https://stackoverflow.com/questions/52310835/xcode-10-call-to-unavailable-function-stdvisit + return std::__variant_detail::__visitation::__variant::__visit_value(_Obj, _Args...); +}; + +#else + +template +constexpr std::variant_alternative_t> &get(std::variant &v) +{ + return std::get(v); +}; + +template +constexpr std::variant_alternative_t> &&get(std::variant &&v) +{ + return std::get(std::forward(v)); +}; + +template +constexpr const std::variant_alternative_t> &get( + const std::variant &v) +{ + return std::get(v); +}; + +template +constexpr const std::variant_alternative_t> &&get( + const std::variant &&v) +{ + return std::get(std::forward(v)); +}; + +template +constexpr T &get(std::variant &v) +{ + return std::get(v); +}; + +template +constexpr T &&get(std::variant &&v) +{ + return std::get(std::forward(v)); +}; + +template +constexpr const T &get(const std::variant &v) +{ + return std::get(v); +}; + +template +constexpr const T &&get(const std::variant &&v) +{ + return std::get(std::forward(v)); +}; + +template +constexpr auto visit(_Callable &&_Obj, _Variants &&... _Args) +{ + return std::visit<_Callable, _Variants...>(static_cast<_Callable &&>(_Obj), + static_cast<_Variants &&>(_Args)...); +}; + +#endif + +/* +# if _HAS_CXX20 +template +constexpr _Ret visit(_Callable &&_Obj, _Variants &&... _Args) +{ + return std::visit<_Ret, _Callable, _Variants...>( + static_cast<_Callable &&>(_Obj), + static_cast<_Variants &&>(_Args)...); +}; +# endif +*/ + +// nostd::holds_alternative +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 std::holds_alternative(v); +} + +} // namespace nostd +OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/trace/span.h b/api/include/opentelemetry/trace/span.h index f324658740..7235e96ae1 100644 --- a/api/include/opentelemetry/trace/span.h +++ b/api/include/opentelemetry/trace/span.h @@ -5,8 +5,10 @@ #include "opentelemetry/common/attribute_value.h" #include "opentelemetry/common/key_value_iterable_view.h" #include "opentelemetry/core/timestamp.h" +#include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/nostd/span.h" #include "opentelemetry/nostd/string_view.h" +#include "opentelemetry/nostd/type_traits.h" #include "opentelemetry/nostd/unique_ptr.h" #include "opentelemetry/trace/canonical_code.h" #include "opentelemetry/trace/span_context.h" @@ -167,5 +169,14 @@ class Span // AddEvent). virtual bool IsRecording() const noexcept = 0; }; + +template +nostd::shared_ptr to_span_ptr(TracerType *objPtr, + nostd::string_view name, + const trace::StartSpanOptions &options) +{ + return nostd::shared_ptr{new (std::nothrow) SpanType{*objPtr, name, options}}; +} + } // namespace trace OPENTELEMETRY_END_NAMESPACE diff --git a/api/test/context/CMakeLists.txt b/api/test/context/CMakeLists.txt index ea5198fd90..2c9da11191 100644 --- a/api/test/context/CMakeLists.txt +++ b/api/test/context/CMakeLists.txt @@ -2,8 +2,9 @@ include(GoogleTest) foreach(testname context_test runtime_context_test) add_executable(${testname} "${testname}.cc") - target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) + target_link_libraries( + ${testname} ${GTEST_BOTH_LIBRARIES} ${CORE_RUNTIME_LIBS} + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) gtest_add_tests( TARGET ${testname} TEST_PREFIX context. diff --git a/api/test/core/CMakeLists.txt b/api/test/core/CMakeLists.txt index 7fead491e5..0d59831bb4 100644 --- a/api/test/core/CMakeLists.txt +++ b/api/test/core/CMakeLists.txt @@ -1,8 +1,9 @@ include(GoogleTest) add_executable(timestamp_test timestamp_test.cc) -target_link_libraries(timestamp_test ${GTEST_BOTH_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) +target_link_libraries( + timestamp_test ${GTEST_BOTH_LIBRARIES} ${CORE_RUNTIME_LIBS} + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) gtest_add_tests( TARGET timestamp_test TEST_PREFIX trace. diff --git a/api/test/metrics/CMakeLists.txt b/api/test/metrics/CMakeLists.txt index 9d70c376ef..f20a46c094 100644 --- a/api/test/metrics/CMakeLists.txt +++ b/api/test/metrics/CMakeLists.txt @@ -1,7 +1,8 @@ foreach(testname noop_instrument_test meter_provider_test noop_metrics_test) add_executable(${testname} "${testname}.cc") - target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) + target_link_libraries( + ${testname} ${GTEST_BOTH_LIBRARIES} ${CORE_RUNTIME_LIBS} + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) gtest_add_tests( TARGET ${testname} TEST_PREFIX metrics. diff --git a/api/test/nostd/CMakeLists.txt b/api/test/nostd/CMakeLists.txt index 1fb120736e..21c2197ced 100644 --- a/api/test/nostd/CMakeLists.txt +++ b/api/test/nostd/CMakeLists.txt @@ -3,8 +3,9 @@ include(GoogleTest) foreach(testname function_ref_test string_view_test unique_ptr_test utility_test span_test shared_ptr_test) add_executable(${testname} "${testname}.cc") - target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) + target_link_libraries( + ${testname} ${GTEST_BOTH_LIBRARIES} ${CORE_RUNTIME_LIBS} + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) gtest_add_tests( TARGET ${testname} TEST_PREFIX nostd. diff --git a/api/test/nostd/shared_ptr_test.cc b/api/test/nostd/shared_ptr_test.cc index f55d47936f..f24b8c6946 100644 --- a/api/test/nostd/shared_ptr_test.cc +++ b/api/test/nostd/shared_ptr_test.cc @@ -159,11 +159,11 @@ TEST(SharedPtrTest, Comparison) EXPECT_EQ(nullptr, ptr3); } -TEST(SharedPtrTest, Sort) +static void SharedPtrTest_Sort(size_t size = 10) { std::vector> nums; - for (int i = 10; i > 0; i--) + for (int i = size; i > 0; i--) { nums.push_back(shared_ptr(new int(i))); } @@ -179,3 +179,8 @@ TEST(SharedPtrTest, Sort) EXPECT_EQ(nums, nums2); } + +TEST(SharedPtrTest, Sort) +{ + SharedPtrTest_Sort(); +} diff --git a/api/test/nostd/span_test.cc b/api/test/nostd/span_test.cc index 44e7d49a15..8bfbf60f29 100644 --- a/api/test/nostd/span_test.cc +++ b/api/test/nostd/span_test.cc @@ -1,5 +1,7 @@ #include "opentelemetry/nostd/span.h" +#include + #include #include #include @@ -56,7 +58,10 @@ TEST(SpanTest, PointerCountConstruction) EXPECT_EQ(s2.data(), array.data()); EXPECT_EQ(s2.size(), array.size()); +#ifndef HAVE_CPP_STDLIB + /* This test is not supposed to fail with STL. Why is this invalid construct? */ EXPECT_DEATH((span{array.data(), array.size()}), ".*"); +#endif } TEST(SpanTest, RangeConstruction) @@ -71,7 +76,10 @@ TEST(SpanTest, RangeConstruction) EXPECT_EQ(s2.data(), array); EXPECT_EQ(s2.size(), 3); +#ifndef HAVE_CPP_STDLIB + /* This test is not supposed to fail with STL. Why is this invalid construct? */ EXPECT_DEATH((span{std::begin(array), std::end(array)}), ".*"); +#endif } TEST(SpanTest, ArrayConstruction) @@ -106,10 +114,15 @@ TEST(SpanTest, ContainerConstruction) EXPECT_EQ(s1.data(), v.data()); EXPECT_EQ(s1.size(), v.size()); - span s2{v}; + span s2{v.data(), 3}; + EXPECT_EQ(s2.data(), v.data()); EXPECT_EQ(s2.size(), v.size()); - EXPECT_DEATH((span{v}), ".*"); + +#ifndef HAVE_CPP_STDLIB + /* This test is not supposed to fail with STL. Why is this invalid construct? */ + EXPECT_DEATH((span{v.data(), 3}), ".*"); +#endif EXPECT_FALSE((std::is_constructible, std::vector>::value)); EXPECT_FALSE((std::is_constructible, std::list>::value)); diff --git a/api/test/nostd/string_view_test.cc b/api/test/nostd/string_view_test.cc index 364410a312..3673082cca 100644 --- a/api/test/nostd/string_view_test.cc +++ b/api/test/nostd/string_view_test.cc @@ -2,7 +2,7 @@ #include -#include "map" +#include using opentelemetry::nostd::string_view; @@ -68,7 +68,7 @@ TEST(StringViewTest, SubstrPortion) TEST(StringViewTest, SubstrOutOfRange) { string_view s = "abc123"; -#if __EXCEPTIONS +#if __EXCEPTIONS || defined(HAVE_STDLIB_CPP) EXPECT_THROW(s.substr(10), std::out_of_range); #else EXPECT_DEATH({ s.substr(10); }, ""); diff --git a/api/test/plugin/CMakeLists.txt b/api/test/plugin/CMakeLists.txt index 6bdcbf9c32..29a75b6b84 100644 --- a/api/test/plugin/CMakeLists.txt +++ b/api/test/plugin/CMakeLists.txt @@ -1,8 +1,9 @@ include(GoogleTest) add_executable(dynamic_load_test dynamic_load_test.cc) -target_link_libraries(dynamic_load_test ${GTEST_BOTH_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) +target_link_libraries( + dynamic_load_test ${GTEST_BOTH_LIBRARIES} ${CORE_RUNTIME_LIBS} + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) target_link_libraries(dynamic_load_test ${CMAKE_DL_LIBS}) gtest_add_tests( TARGET dynamic_load_test diff --git a/api/test/trace/CMakeLists.txt b/api/test/trace/CMakeLists.txt index 0faac5cfb4..6c69883b2c 100644 --- a/api/test/trace/CMakeLists.txt +++ b/api/test/trace/CMakeLists.txt @@ -10,8 +10,9 @@ foreach( noop_test tracer_test) add_executable(api_${testname} "${testname}.cc") - target_link_libraries(api_${testname} ${GTEST_BOTH_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) + target_link_libraries( + api_${testname} ${GTEST_BOTH_LIBRARIES} ${CORE_RUNTIME_LIBS} + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) gtest_add_tests( TARGET api_${testname} TEST_PREFIX trace. diff --git a/api/test/trace/propagation/CMakeLists.txt b/api/test/trace/propagation/CMakeLists.txt index ff707348bd..8f13cd68de 100644 --- a/api/test/trace/propagation/CMakeLists.txt +++ b/api/test/trace/propagation/CMakeLists.txt @@ -1,7 +1,8 @@ foreach(testname http_text_format_test) add_executable(${testname} "${testname}.cc") - target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) + target_link_libraries( + ${testname} ${GTEST_BOTH_LIBRARIES} ${CORE_RUNTIME_LIBS} + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) gtest_add_tests( TARGET ${testname} TEST_PREFIX trace. diff --git a/ci/do_ci.sh b/ci/do_ci.sh index 53fa808027..36708021ec 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -33,6 +33,9 @@ elif [[ "$1" == "cmake.c++20.test" ]]; then elif [[ "$1" == "cmake.legacy.test" ]]; then cd "${BUILD_DIR}" rm -rf * + export BUILD_ROOT="${BUILD_DIR}" + ${SRC_DIR}/tools/build-gtest.sh + ${SRC_DIR}/tools/build-benchmark.sh cmake -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_CXX_FLAGS="-Werror" \ -DCMAKE_CXX_STANDARD=11 \ diff --git a/docker/ubuntu14.04/Dockerfile b/docker/ubuntu14.04/Dockerfile index 9f875f453c..f4e8a04104 100644 --- a/docker/ubuntu14.04/Dockerfile +++ b/docker/ubuntu14.04/Dockerfile @@ -8,7 +8,7 @@ RUN apt-get -y update && apt-get -y upgrade && apt-get -y dist-upgrade RUN apt-get install -qq -y --ignore-missing \ apt-utils \ automake \ - bc \ + bc \ build-essential \ bzip2 \ cmake \ diff --git a/docker/ubuntu16.04/Dockerfile b/docker/ubuntu16.04/Dockerfile index 62f8c64319..328600f1cb 100644 --- a/docker/ubuntu16.04/Dockerfile +++ b/docker/ubuntu16.04/Dockerfile @@ -9,7 +9,7 @@ RUN apt-get install -qq -y --ignore-missing \ apt-utils \ automake \ build-essential \ - bc \ + bc \ bzip2 \ cmake \ curl \ diff --git a/docker/ubuntu18.04/Dockerfile b/docker/ubuntu18.04/Dockerfile index b3f28986cf..9e41506b4f 100644 --- a/docker/ubuntu18.04/Dockerfile +++ b/docker/ubuntu18.04/Dockerfile @@ -8,7 +8,7 @@ RUN apt-get -y update && apt-get -y upgrade && apt-get -y dist-upgrade RUN apt-get install -qq -y --ignore-missing \ apt-utils \ automake \ - bc \ + bc \ build-essential \ bzip2 \ cmake \ diff --git a/docker/ubuntu20.04/Dockerfile b/docker/ubuntu20.04/Dockerfile index 84966fae66..17dba84799 100644 --- a/docker/ubuntu20.04/Dockerfile +++ b/docker/ubuntu20.04/Dockerfile @@ -8,7 +8,7 @@ RUN apt-get -y update && apt-get -y upgrade && apt-get -y dist-upgrade RUN apt-get install -qq -y --ignore-missing \ apt-utils \ automake \ - bc \ + bc \ build-essential \ bzip2 \ cmake \ diff --git a/docs/abi-compatibility.md b/docs/abi-compatibility.md new file mode 100644 index 0000000000..53936de0bd --- /dev/null +++ b/docs/abi-compatibility.md @@ -0,0 +1,35 @@ +# Windows + +## Visual Studio 2015, 2017, 2019 + +The Microsoft C++ (MSVC) compiler toolsets in Visual Studio 2013 and earlier don't guarantee binary compatibility across versions. You can't link object files, static libraries, dynamic libraries, and executables built by different versions. The ABIs, object formats, and runtime libraries are incompatible. + +We've changed this behavior in Visual Studio 2015, 2017, and 2019. The runtime libraries and apps compiled by any of these versions of the compiler are binary-compatible. It's reflected in the C++ toolset major number, which is 14 for all three versions. (The toolset version is v140 for Visual Studio 2015, v141 for 2017, and v142 for 2019). Say you have third-party libraries built by Visual Studio 2015. You can still use them in an application built by Visual Studio 2017 or 2019. There's no need to recompile with a matching toolset. The latest version of the Microsoft Visual C++ Redistributable package (the Redistributable) works for all of them. + +There are three important restrictions on binary compatibility: + +- You can mix binaries built by different versions of the toolset. However, you must use a toolset at least as recent as the most recent binary to link your app. Here's an example: you can link an app compiled using the 2017 toolset to a static library compiled using 2019, if they're linked using the 2019 toolset. + +- The Redistributable your app uses has a similar binary-compatibility restriction. When you mix binaries built by different supported versions of the toolset, the Redistributable version must be at least as new as the latest toolset used by any app component. + +- Static libraries or object files compiled using the /GL (Whole program optimization) compiler switch aren't binary-compatible across versions. All object files and libraries compiled using /GL must use exactly the same toolset for the compile and the final link. + +[Reference](https://docs.microsoft.com/en-us/cpp/porting/binary-compat-2015-2017?view=vs-2019) + +## Breaking Compatibility + +### Exceptions + +- [__CxxFrameHandler4](https://devblogs.microsoft.com/cppblog/making-cpp-exception-handling-smaller-x64/) - static library built with Visual Studio 2019 wont link to executable compiled with Visual Studio 2017 + +### Release vs Debug libraries on Windows + +- [\_SECURE_SCL](https://docs.microsoft.com/en-us/cpp/standard-library/secure-scl?view=vs-2019) - checked iterators (old) + +- [\_ITERATOR_DEBUG_LEVEL](https://docs.microsoft.com/en-us/cpp/standard-library/iterator-debug-level?view=vs-2019) - checked iterators (new) + +### Spectre Mitigation + +- [Runtime Libraries for Spectre Mitigation](https://docs.microsoft.com/en-us/cpp/build/reference/qspectre?view=vs-2019) + +- [New Spectre Mitigations in Visual Studio 2019](https://devblogs.microsoft.com/cppblog/more-spectre-mitigations-in-msvc/) diff --git a/docs/building-with-stdlib.md b/docs/building-with-stdlib.md new file mode 100644 index 0000000000..ed0911aa1a --- /dev/null +++ b/docs/building-with-stdlib.md @@ -0,0 +1,191 @@ +# Building with Standard C++ Library + +Standard Library build flavor works best for statically linking the SDK in a +process (environment where ABI compat is not a requirement), or for +"header-only" implementation of SDK. + +Proposed approach cannot be employed for shared libs in environments where +ABI compatibility is required. OpenTelemetry SDK binary compiled with +`compiler A + STL B` will not be ABI -compatible with the main executable +compiled with `compiler C + STL D`. + +In addition to standard library, similar approach can be reused to implement +the API surface classes with [Abseil classes](https://abseil.io/) instead of +`nostd`, in products that prefer Abseil. + +## Motivation + +`nostd` classes in OpenTelemetry API were introduced for the following reasons: +- ABI stability: scenario where different modules are compiled with different +compiler and incompatible standard library. +- backport of C++17 and above features to C++11 compiler. + +The need for custom `nostd` classes is significantly diminished when the SDK is +compiled with C++17 or above compiler. Only `std::span` needs to be backported. + +Subsequently, there is no need for `nostd` classes in environment with C++20 or +above compiler, where all system modules are compiled with the same / compatible +compiler. And where the same standard library implementation is being used. This +is the case when SDK is compiled into product itself, with no runtime loadable +components. + +Compiling OpenTelemetry SDK from source using standard library classes: +`std::map`, `std::string_view`, `std::span`, `std::variant` +instead of `nostd::` yields better performance and debugability at expense +of potentially losing ABI compatibility. However, the standard library built +for Release is guaranteed to be compatible across Visual Studio 2015, 2017 and +2019 compilers on Windows with vc14x runtime. Thus, ABI stability requirement +introduces an additional unnecessary runtime complexity and overhead. + +While we are committed to support `nostd` classes for those environments where +ABI compatibility is a requirement, we would also like to add flexibility to +build system to optimize the SDK for the case where ABI compatibility is NOT +a requirement. + +Implementation of this feature can be subsequently be used as a foundation for +further work - allow bindings to [Abseil](https://github.com/abseil/abseil-cpp) +"backport" implementation of the standard library. + +Implementation is completely opaque from SDK code / SDK developer perspective: +mapping / aliasing from `nostd::` classes back to their `std::` counterparts +is done in a corresponding `opentelemetry/nostd/*.h` header. Users still use +`nostd` classes, but the most optimal implementation is picked up depending on +whether users require ABI stability or not. + +Example environments that contain the full set of standard classes: +- C++17 or above compiler, with Microsoft GSL backport of `gsl::span` +- C++20 compilers: Visual Studio 2019+, latest LLVM clang, latest gcc + +We continue fully supporting both models (`nostd`, `stdlib`) by running CI for both. + +## Implementation + +Allow to alias from `nostd::` to `std::` classes for C++17 and above. + +Consistent handling of `std::variant` across various OS: + +- backport of a few missing variant features, e.g. `std::get` and `std::visit` + for older version of Mac OS X. Patches that enable proper handling of + `std::visit` and `std::variant` irrespective of OS version to resolve + [this quirk](https://stackoverflow.com/questions/52310835/xcode-10-call-to-unavailable-function-stdvisit). + +- ability to borrow implementation of C++20 `gsl::span` from + [Microsoft Guidelines Support Library](https://github.com/microsoft/GSL). + This is necessary for C++17 and above compiler. + +- ability to use Abseil classes for Visual Studio 2015 :`nostd::variant` does + not compile with Visual Studio 2010. Please refer to [this issue](https://github.com/open-telemetry/opentelemetry-cpp/issues/314) + +## Pros and Cons + +### Using trusted/certified Standard Library + +Using standard library implementation classes in customer code and on API +surface instead of `nostd` classes. Certain environments would prefer to have +**standard** instead of non-standard classes due to security, performance, +stability and debug'ability considerations. For example, Visual Studio IDE +provides 1st class Debug experience for Standard containers, plus additional +runtime-checks for Debug builds that use Standard containers. + +### Minimizing binary size + +No need to marshal types from standard to `nostd`, then back to standard +library across ABI boundary - means less code involved and less memcpy. We use +Standard Library classes used elsewhere in the app. We can optimize the +event passing by avoiding `KeyValueIterable` transform (and, thus, unnecessary memcpy) +when we know that the incoming container type matches that one used by SDK. + +### Avoiding unnecessary extra memcpy (perf improvements) + +No need to transform from 'native' standard library types, e.g. `std::map` via +`KeyValueIterable` means we can bypass that transformation process, if and when +we know that the ABI compatibility is not a requirement in certain environment. +ETA perf improvement is 1.5%-3% better perf since an extra transform, memcpy, +iteration for-each key-value is avoided. Custom OpenTelemetry SDK implementation +may operate on standard container classes rather than doing transform from one +container type to another. + +### ABI stability + +Obviously this approach does not work in Linux environments, where ABI stability +guarantee must be provided, e.g. for dynamically loadable OpenTelemetry SDK +module and plugins for products such as NGINX, Envoy, etc. Example: a product is +compiled with modern gcc compiler. But OpenTelemetry SDK is compiled with an +older runtime library. In this case the SDK must be compiled with `nostd`. + +Note that for most scenarios with modern Windows compilers, STL library is +ABI-safe across Visual Studio 2015, 2017 and 2019 with vc14x runtime. + +Quote from [official documentation](https://docs.microsoft.com/en-us/cpp/porting/binary-compat-2015-2017?view=msvc-160) : + +Visual Studio 2015, 2017, and 2019: the runtime libraries and apps compiled by +any of these versions of the compiler are binary-compatible. It's reflected in +the C++ toolset major number, which is 14 for all three versions. The toolset +version is v140 for Visual Studio 2015, v141 for 2017, and v142 for 2019. +Say you have third-party libraries built by Visual Studio 2015. You can still +use them in an application built by Visual Studio 2017 or 2019. There's no need +to recompile with a matching toolset. The latest version of the Microsoft Visual +C++ Redistributable package (the Redistributable) works for all of them. + +Visual Studio provides 1st class debug experience for the standard library. +## Build and Test considerations + +### Separate flavors of SDK build + +Supported build flavors: + +- `nostd` - OpenTelemetry backport of classes for C++11. Not using standard lib. +- `stdlib` - Standard Library. Full native experience with C++20 compiler. + C++17 works but with additional dependencies, e.g. either MS-GSL or Abseil + for `std::span` implementation (`gsl::span` or `absl::Span`). +- `absl` - TODO: this should allow using Abseil C++ library only (no MS-GSL). + +Currently only `nostd` and `stdlib` configurations are implemented in CMake build. +`absl` is reserved for future use. Build systems other than CMake need to +`#define HAVE_CPP_STDLIB` to enable the Standard Library classes. + +### Build matrix + +List of compilers that support building with standard library classes: + +Compiler | Language standard | Notes +-------------------|-------------------|------------------- +Visual Studio 2015 | C++14 | can only be built with `nostd` flavor +Visual Studio 2017 | C++17 | requires `gsl::span` for `std::span` implementation +Visual Studio 2019 | C++20 | +Xcode 11.x | C++17 | requires `gsl::span` for `std::span` implementation +Xcode 12.x | C++20 | +gcc-7 | C++17 | requires `gsl::span` for `std::span` implementation +gcc-9+ | C++20 | + +C++20 `std::span` -compatible implementation is needed for C++17 compilers. + +Other modern C++ language features used by OpenTelemetry, e.g. `std::string_view` +and `std::variant` are available in C++17 standard library. Minor customization +needed for Apple LLVM clang in `std::variant` exception handling due to the fact +that the variant exception handler presence depends on what OS version developer +is targeting. This exception on Apple systems is implemented inside the OS system +library. This idiosyncrasy is now handled by OpenTelemetry API in opaque manner: +support `nostd::variant` exception handling even on older Mac OS X and iOS by +providing implementation of it in OpenTelemetry SDK: if exceptions are enabled, +then throw `nostd::bad_variant_access` exception old OS where `std::bad_variant_access` +is unavailable. + +#### Note on `gsl::span` vs `absl::Span` + +It is important to note that, while `absl::Span` is similar in design and +purpose to the `std::span` (and existing `gsl::span` reference implementation), +`absl::Span` is not currently guaranteeing to be a drop-in replacement for any +eventual standard. Instead, `absl::Span` aims to have an interface as similar +as possible to `absl::string_view`, without the string-specific functionality. + +Thus, OpenTelemetry built with standard library prefers `gsl::span` as it is +fully compatible with standard `std::span`. It may become possible to use Abseil +classes should we confirm that its behavior is consistent with `nostd::span` +expectations. + +### Test setup + +CI allows to validate that all OpenTelemetry functionality is working the same +identical way irrespective of what C++ runtime / STL library it is compiled +with. diff --git a/examples/batch/CMakeLists.txt b/examples/batch/CMakeLists.txt index d1146d59b3..41654aeb93 100644 --- a/examples/batch/CMakeLists.txt +++ b/examples/batch/CMakeLists.txt @@ -2,5 +2,6 @@ include_directories(${CMAKE_SOURCE_DIR}/exporters/ostream/include) add_executable(batch_span_processor_example main.cc) -target_link_libraries(batch_span_processor_example ${CMAKE_THREAD_LIBS_INIT} - opentelemetry_exporter_ostream_span opentelemetry_trace) +target_link_libraries( + batch_span_processor_example ${CMAKE_THREAD_LIBS_INIT} ${CORE_RUNTIME_LIBS} + opentelemetry_exporter_ostream_span opentelemetry_trace) diff --git a/examples/metrics_simple/CMakeLists.txt b/examples/metrics_simple/CMakeLists.txt index 4269318871..add3a153ce 100644 --- a/examples/metrics_simple/CMakeLists.txt +++ b/examples/metrics_simple/CMakeLists.txt @@ -3,4 +3,4 @@ include_directories(${CMAKE_SOURCE_DIR}/exporters/ostream/include) add_executable(simple_metrics main.cc) target_link_libraries( simple_metrics ${CMAKE_THREAD_LIBS_INIT} opentelemetry_metrics - opentelemetry_exporter_ostream_metrics) + ${CORE_RUNTIME_LIBS} opentelemetry_exporter_ostream_metrics) diff --git a/examples/otlp/CMakeLists.txt b/examples/otlp/CMakeLists.txt index 8c5bf92490..8b77baad38 100644 --- a/examples/otlp/CMakeLists.txt +++ b/examples/otlp/CMakeLists.txt @@ -4,9 +4,14 @@ include_directories(${CMAKE_SOURCE_DIR}/exporters/otlp/include) add_library(otlp_foo_library foo_library/foo_library.cc) target_link_libraries(otlp_foo_library ${CMAKE_THREAD_LIBS_INIT} - opentelemetry_api) + ${CORE_RUNTIME_LIBS} opentelemetry_api) add_executable(example_otlp main.cc) target_link_libraries( - example_otlp ${CMAKE_THREAD_LIBS_INIT} otlp_foo_library opentelemetry_trace - opentelemetry_exporter_otprotocol gRPC::grpc++) + example_otlp + ${CMAKE_THREAD_LIBS_INIT} + otlp_foo_library + opentelemetry_trace + ${CORE_RUNTIME_LIBS} + opentelemetry_exporter_otprotocol + gRPC::grpc++) diff --git a/examples/plugin/plugin/tracer.cc b/examples/plugin/plugin/tracer.cc index cd7d19a1e0..68478c5ce1 100644 --- a/examples/plugin/plugin/tracer.cc +++ b/examples/plugin/plugin/tracer.cc @@ -1,5 +1,4 @@ #include "tracer.h" -#include "opentelemetry/context/runtime_context.h" #include "opentelemetry/nostd/unique_ptr.h" #include diff --git a/exporters/ostream/CMakeLists.txt b/exporters/ostream/CMakeLists.txt index e870bb09cf..909ce7fdbe 100644 --- a/exporters/ostream/CMakeLists.txt +++ b/exporters/ostream/CMakeLists.txt @@ -11,11 +11,11 @@ if(BUILD_TESTING) target_link_libraries( ostream_span_test ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} - opentelemetry_exporter_ostream_span) + ${CORE_RUNTIME_LIBS} opentelemetry_exporter_ostream_span) target_link_libraries( ostream_metrics_test ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} - opentelemetry_exporter_ostream_metrics) + ${CORE_RUNTIME_LIBS} opentelemetry_exporter_ostream_metrics) target_link_libraries( ostream_log_test ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} diff --git a/exporters/otlp/src/recordable.cc b/exporters/otlp/src/recordable.cc index 82afe7b90b..44d04082b4 100644 --- a/exporters/otlp/src/recordable.cc +++ b/exporters/otlp/src/recordable.cc @@ -59,6 +59,12 @@ void PopulateAttribute(opentelemetry::proto::common::v1::KeyValue *attribute, attribute->mutable_value()->set_string_value(nostd::get(value).data(), nostd::get(value).size()); } +#ifdef HAVE_CSTRING_TYPE + else if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_string_value(nostd::get(value)); + } +#endif else if (nostd::holds_alternative>(value)) { for (const auto &val : nostd::get>(value)) diff --git a/ext/include/opentelemetry/ext/http/server/socket_tools.h b/ext/include/opentelemetry/ext/http/server/socket_tools.h index 4e381f3ce1..095a7eeeff 100644 --- a/ext/include/opentelemetry/ext/http/server/socket_tools.h +++ b/ext/include/opentelemetry/ext/http/server/socket_tools.h @@ -96,7 +96,6 @@ struct Thread { std::thread m_thread; - // volatile bool m_terminate{false}; std::atomic m_terminate{false}; /// diff --git a/sdk/include/opentelemetry/sdk/logs/simple_log_processor.h b/sdk/include/opentelemetry/sdk/logs/simple_log_processor.h index 38a4194c16..d387e3c7fc 100644 --- a/sdk/include/opentelemetry/sdk/logs/simple_log_processor.h +++ b/sdk/include/opentelemetry/sdk/logs/simple_log_processor.h @@ -59,7 +59,7 @@ class SimpleLogProcessor : public LogProcessor // The lock used to ensure the exporter is not called concurrently opentelemetry::common::SpinLockMutex lock_; // The atomic boolean flag to ensure the ShutDown() function is only called once - std::atomic_flag shutdown_latch_{ATOMIC_FLAG_INIT}; + std::atomic_flag shutdown_latch_ = ATOMIC_FLAG_INIT; }; } // namespace logs } // namespace sdk diff --git a/sdk/include/opentelemetry/sdk/trace/attribute_utils.h b/sdk/include/opentelemetry/sdk/trace/attribute_utils.h index 2b1c082441..821ad953fa 100644 --- a/sdk/include/opentelemetry/sdk/trace/attribute_utils.h +++ b/sdk/include/opentelemetry/sdk/trace/attribute_utils.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include "opentelemetry/common/attribute_value.h" @@ -21,6 +22,12 @@ using SpanDataAttributeValue = nostd::variant, +#endif std::vector, std::vector, std::vector, @@ -37,17 +44,23 @@ struct AttributeConverter SpanDataAttributeValue operator()(bool v) { return SpanDataAttributeValue(v); } SpanDataAttributeValue operator()(int32_t v) { return SpanDataAttributeValue(v); } SpanDataAttributeValue operator()(uint32_t v) { return SpanDataAttributeValue(v); } - /*SpanDataAttributeValue operator()(int v) - { - return SpanDataAttributeValue(static_cast(v)); - }*/ SpanDataAttributeValue operator()(int64_t v) { return SpanDataAttributeValue(v); } SpanDataAttributeValue operator()(uint64_t v) { return SpanDataAttributeValue(v); } SpanDataAttributeValue operator()(double v) { return SpanDataAttributeValue(v); } SpanDataAttributeValue operator()(nostd::string_view v) { - return SpanDataAttributeValue(std::string(v)); + return SpanDataAttributeValue(std::string(v.data(), v.size())); + } + SpanDataAttributeValue operator()(const char *s) + { + return SpanDataAttributeValue(std::string(s)); } +#ifdef HAVE_SPAN_BYTE + SpanDataAttributeValue operator()(nostd::span v) + { + return convertSpan(v); + } +#endif SpanDataAttributeValue operator()(nostd::span v) { return convertSpan(v); } SpanDataAttributeValue operator()(nostd::span v) { @@ -74,12 +87,7 @@ struct AttributeConverter template SpanDataAttributeValue convertSpan(nostd::span vals) { - std::vector copy; - for (auto &val : vals) - { - copy.push_back(T(val)); - } - + const std::vector copy(vals.begin(), vals.end()); return SpanDataAttributeValue(std::move(copy)); } }; diff --git a/sdk/include/opentelemetry/sdk/trace/simple_processor.h b/sdk/include/opentelemetry/sdk/trace/simple_processor.h index aec0d51cc6..7ad5848c07 100644 --- a/sdk/include/opentelemetry/sdk/trace/simple_processor.h +++ b/sdk/include/opentelemetry/sdk/trace/simple_processor.h @@ -72,7 +72,7 @@ class SimpleSpanProcessor : public SpanProcessor private: std::unique_ptr exporter_; opentelemetry::common::SpinLockMutex lock_; - std::atomic_flag shutdown_latch_{ATOMIC_FLAG_INIT}; + std::atomic_flag shutdown_latch_ = ATOMIC_FLAG_INIT; }; } // namespace trace } // namespace sdk diff --git a/sdk/include/opentelemetry/sdk/trace/span_data.h b/sdk/include/opentelemetry/sdk/trace/span_data.h index 24796d65d7..b5594804fe 100644 --- a/sdk/include/opentelemetry/sdk/trace/span_data.h +++ b/sdk/include/opentelemetry/sdk/trace/span_data.h @@ -13,6 +13,8 @@ #include "opentelemetry/trace/span_id.h" #include "opentelemetry/trace/trace_id.h" +#include + OPENTELEMETRY_BEGIN_NAMESPACE namespace sdk { @@ -201,7 +203,10 @@ class SpanData final : public Recordable status_desc_ = std::string(description); } - void SetName(nostd::string_view name) noexcept override { name_ = std::string(name); } + void SetName(nostd::string_view name) noexcept override + { + name_ = std::string(name.data(), name.length()); + } void SetSpanKind(opentelemetry::trace::SpanKind span_kind) noexcept override { diff --git a/sdk/src/common/BUILD b/sdk/src/common/BUILD index a8981b4d55..b0724c3810 100644 --- a/sdk/src/common/BUILD +++ b/sdk/src/common/BUILD @@ -16,7 +16,10 @@ package(default_visibility = ["//visibility:public"]) cc_library( name = "random", - srcs = ["random.cc"], + srcs = [ + "core.cc", + "random.cc", + ], hdrs = [ "fast_random_number_generator.h", "random.h", diff --git a/sdk/src/common/CMakeLists.txt b/sdk/src/common/CMakeLists.txt index 042a857539..4a47500a73 100644 --- a/sdk/src/common/CMakeLists.txt +++ b/sdk/src/common/CMakeLists.txt @@ -1,4 +1,4 @@ -set(COMMON_SRCS random.cc) +set(COMMON_SRCS random.cc core.cc) if(WIN32) list(APPEND COMMON_SRCS platform/fork_windows.cc) else() @@ -6,4 +6,5 @@ else() endif() add_library(opentelemetry_common ${COMMON_SRCS}) -target_link_libraries(opentelemetry_common Threads::Threads) +target_link_libraries(opentelemetry_common Threads::Threads + ${CORE_RUNTIME_LIBS}) diff --git a/sdk/src/common/core.cc b/sdk/src/common/core.cc new file mode 100644 index 0000000000..a8db9a0448 --- /dev/null +++ b/sdk/src/common/core.cc @@ -0,0 +1,12 @@ +#include "opentelemetry/nostd/variant.h" +#include "opentelemetry/version.h" + +#if defined(HAVE_ABSEIL) +namespace absl +{ +namespace variant_internal +{ +void __cdecl ThrowBadVariantAccess(){/* TODO: std::terminate or re-throw? */}; +} +} // namespace absl +#endif diff --git a/sdk/src/trace/CMakeLists.txt b/sdk/src/trace/CMakeLists.txt index e4d6bdc5ed..97f4f3d3b3 100644 --- a/sdk/src/trace/CMakeLists.txt +++ b/sdk/src/trace/CMakeLists.txt @@ -3,4 +3,5 @@ add_library( tracer_provider.cc tracer.cc span.cc batch_span_processor.cc samplers/parent.cc samplers/trace_id_ratio.cc) -target_link_libraries(opentelemetry_trace opentelemetry_common) +target_link_libraries(opentelemetry_trace opentelemetry_common + ${CORE_RUNTIME_LIBS}) diff --git a/sdk/test/common/CMakeLists.txt b/sdk/test/common/CMakeLists.txt index 5c6ffe868c..f1028bf6d8 100644 --- a/sdk/test/common/CMakeLists.txt +++ b/sdk/test/common/CMakeLists.txt @@ -4,7 +4,7 @@ foreach(testname add_executable(${testname} "${testname}.cc") target_link_libraries( ${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} - opentelemetry_common opentelemetry_trace) + ${CORE_RUNTIME_LIBS} opentelemetry_common opentelemetry_trace) gtest_add_tests( TARGET ${testname} TEST_PREFIX trace. @@ -16,9 +16,11 @@ target_link_libraries(random_fork_test opentelemetry_common) add_test(random_fork_test random_fork_test) add_executable(random_benchmark random_benchmark.cc) -target_link_libraries(random_benchmark benchmark::benchmark - ${CMAKE_THREAD_LIBS_INIT} opentelemetry_common) +target_link_libraries( + random_benchmark benchmark::benchmark ${CORE_RUNTIME_LIBS} + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_common) add_executable(circular_buffer_benchmark circular_buffer_benchmark.cc) -target_link_libraries(circular_buffer_benchmark benchmark::benchmark - ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) +target_link_libraries( + circular_buffer_benchmark benchmark::benchmark ${CORE_RUNTIME_LIBS} + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) diff --git a/sdk/test/trace/CMakeLists.txt b/sdk/test/trace/CMakeLists.txt index 747ec96f31..b68a57f9cc 100644 --- a/sdk/test/trace/CMakeLists.txt +++ b/sdk/test/trace/CMakeLists.txt @@ -12,8 +12,13 @@ foreach( attribute_utils_test) add_executable(${testname} "${testname}.cc") target_link_libraries( - ${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} - opentelemetry_common opentelemetry_trace opentelemetry_exporter_in_memory) + ${testname} + ${CORE_RUNTIME_LIBS} + ${GTEST_BOTH_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_common + opentelemetry_trace + opentelemetry_exporter_in_memory) gtest_add_tests( TARGET ${testname} TEST_PREFIX trace. @@ -23,4 +28,4 @@ endforeach() add_executable(sampler_benchmark sampler_benchmark.cc) target_link_libraries( sampler_benchmark benchmark::benchmark ${CMAKE_THREAD_LIBS_INIT} - opentelemetry_trace opentelemetry_exporter_in_memory) + ${CORE_RUNTIME_LIBS} opentelemetry_trace opentelemetry_exporter_in_memory) diff --git a/third_party/benchmark b/third_party/benchmark index 348aa2c964..bf585a2789 160000 --- a/third_party/benchmark +++ b/third_party/benchmark @@ -1 +1 @@ -Subproject commit 348aa2c964494b5947c0e7f96b82c1fe844d684f +Subproject commit bf585a2789e30585b4e3ce6baf11ef2750b54677 diff --git a/third_party/opentelemetry-proto b/third_party/opentelemetry-proto index f11e0538fd..286810dc20 160000 --- a/third_party/opentelemetry-proto +++ b/third_party/opentelemetry-proto @@ -1 +1 @@ -Subproject commit f11e0538fd7dc30127ca6bfb2062e5d9f782b77b +Subproject commit 286810dc20d40f6483abf719f2b8de28f543fc78 diff --git a/tools/WORKSPACE b/tools/WORKSPACE new file mode 100644 index 0000000000..abebe189fa --- /dev/null +++ b/tools/WORKSPACE @@ -0,0 +1,4 @@ +local_repository( + name = "vcpkg", + path = "./vcpkg", +) diff --git a/tools/format.sh b/tools/format.sh index 2e9ad3fb54..523cceb75d 100755 --- a/tools/format.sh +++ b/tools/format.sh @@ -6,7 +6,7 @@ fi set -e -FIND="find . -name third_party -prune -o -name tools -prune -o -name .git -prune -o -name _deps -prune -o -name .build -prune -o -name out -prune -o" +FIND="find . -name third_party -prune -o -name tools -prune -o -name .git -prune -o -name _deps -prune -o -name .build -prune -o -name out -prune -o -name .vs -prune -o" # GNU syntax. SED=(sed -i) diff --git a/tools/install.sh b/tools/install.sh old mode 100644 new mode 100755 diff --git a/tools/setup-ninja.sh b/tools/setup-ninja.sh new file mode 100755 index 0000000000..fe3fe9cdfc --- /dev/null +++ b/tools/setup-ninja.sh @@ -0,0 +1,4 @@ +#!/bin/bash +# TODO: add support for Ninja on Mac OS X +wget -O /tmp/ninja.zip https://github.com/ninja-build/ninja/releases/download/v1.10.1/ninja-linux.zip +sudo unzip /tmp/ninja.zip -d /usr/local/bin/