mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Unfortunately, I did not find an easy way to fix the warning so suppressed it for now. But I don't think we care about those symbols being duplicated across different shared libraries. rdar://159879290
441 lines
12 KiB
C++
441 lines
12 KiB
C++
//===--- _SwiftStdlibCxxOverlay.h - Additions for Stdlib --------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2022 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef __cplusplus
|
|
#error "no C++"
|
|
#endif
|
|
|
|
#ifdef SWIFT_CXX_INTEROP_OPTIONAL_MIXIN
|
|
|
|
/// True when the Optional has a value.
|
|
SWIFT_INLINE_THUNK operator bool() const noexcept { return *this != none; }
|
|
|
|
/// Returns the value stored in the Optional.
|
|
///
|
|
/// The returned value is copied using the appropriate Swift / C++ copy
|
|
/// semantics.
|
|
SWIFT_INLINE_THUNK T_0_0 get() const
|
|
noexcept(noexcept(getUnsafelyUnwrapped())) {
|
|
// FIXME: Fail with source location.
|
|
return getUnsafelyUnwrapped();
|
|
}
|
|
|
|
#undef SWIFT_CXX_INTEROP_OPTIONAL_MIXIN
|
|
|
|
#elif defined(SWIFT_CXX_INTEROP_STRING_MIXIN)
|
|
|
|
#ifndef SWIFT_CXX_INTEROP_HIDE_STL_OVERLAY
|
|
|
|
/// Constructs a Swift string from a C string.
|
|
SWIFT_INLINE_THUNK String(const char *cString) noexcept {
|
|
if (!cString) {
|
|
#ifdef __EmbeddedSwift__
|
|
auto res = _impl::$eS2SycfC();
|
|
#else
|
|
auto res = _impl::$sS2SycfC();
|
|
#endif
|
|
memcpy(_getOpaquePointer(), &res, sizeof(res));
|
|
return;
|
|
}
|
|
auto res = _impl::$sSS7cStringSSSPys4Int8VG_tcfC(cString);
|
|
memcpy(_getOpaquePointer(), &res, sizeof(res));
|
|
}
|
|
|
|
/// Constructs a Swift string from a C++ string.
|
|
SWIFT_INLINE_THUNK String(const std::string &str) noexcept {
|
|
auto res = _impl::$sSS7cStringSSSPys4Int8VG_tcfC(str.c_str());
|
|
memcpy(_getOpaquePointer(), &res, sizeof(res));
|
|
}
|
|
|
|
/// Casts the Swift String value to a C++ std::string.
|
|
SWIFT_INLINE_THUNK operator std::string() const;
|
|
|
|
#endif // SWIFT_CXX_INTEROP_HIDE_STL_OVERLAY
|
|
|
|
#undef SWIFT_CXX_INTEROP_STRING_MIXIN
|
|
|
|
#else
|
|
// out-of-class overlay for Swift standard library.
|
|
|
|
static_assert(sizeof(_impl::_impl_String) >= 0,
|
|
"included outside of stdlib bindings");
|
|
|
|
#ifndef SWIFT_CXX_INTEROP_HIDE_STL_OVERLAY
|
|
|
|
SWIFT_INLINE_THUNK String::operator std::string() const {
|
|
auto u = getUtf8();
|
|
std::string result;
|
|
result.reserve(u.getCount());
|
|
|
|
auto end_offset = u.getEndIndex().getEncodedOffset();
|
|
for (auto idx = u.getStartIndex(); idx.getEncodedOffset() < end_offset;
|
|
idx = u.indexAfter(idx)) {
|
|
result.push_back(static_cast<char>(u[idx]));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
#endif // SWIFT_CXX_INTEROP_HIDE_STL_OVERLAY
|
|
|
|
namespace cxxOverlay {
|
|
|
|
class IterationEndSentinel;
|
|
|
|
/// Abstract Swift collection iterator.
|
|
template <class Collection, class T> class CollectionIterator {
|
|
public:
|
|
using Index =
|
|
decltype(reinterpret_cast<Collection *>(0x123)->getStartIndex());
|
|
|
|
SWIFT_INLINE_THUNK CollectionIterator(const Collection &c) noexcept(
|
|
noexcept(c.getStartIndex()) &&noexcept(c.getEndIndex()))
|
|
: collection(c) {
|
|
index = collection.getStartIndex();
|
|
endIndex = collection.getEndIndex();
|
|
// FIXME: Begin read access.
|
|
}
|
|
|
|
SWIFT_INLINE_THUNK ~CollectionIterator() noexcept {
|
|
// FIXME: End read access.
|
|
}
|
|
|
|
SWIFT_INLINE_THUNK T operator*() const noexcept {
|
|
return collection[index];
|
|
}
|
|
SWIFT_INLINE_THUNK void operator++() noexcept {
|
|
++index;
|
|
// FIXME: assert(index <= endIndex); // No need to go past the end.
|
|
}
|
|
|
|
SWIFT_INLINE_THUNK bool
|
|
operator!=(const IterationEndSentinel &) const noexcept {
|
|
return index != endIndex;
|
|
}
|
|
|
|
private:
|
|
Index index, endIndex;
|
|
const Collection &collection;
|
|
};
|
|
|
|
class IterationEndSentinel {};
|
|
|
|
template <class T> using ArrayIterator = CollectionIterator<Array<T>, T>;
|
|
|
|
} // namespace cxxOverlay
|
|
|
|
// FIXME: This should apply to more than the Array type.
|
|
template <class T>
|
|
SWIFT_INLINE_THUNK cxxOverlay::ArrayIterator<T> begin(const Array<T> &array
|
|
[[clang::lifetimebound]]) {
|
|
return cxxOverlay::ArrayIterator<T>(array);
|
|
}
|
|
|
|
template <class T>
|
|
SWIFT_INLINE_THUNK cxxOverlay::IterationEndSentinel end(const Array<T> &) {
|
|
return {};
|
|
}
|
|
|
|
#ifdef SWIFT_CXX_INTEROP_EXPERIMENTAL_SWIFT_ERROR
|
|
|
|
extern "C" void *_Nonnull swift_errorRetain(void *_Nonnull swiftError) noexcept;
|
|
|
|
extern "C" void swift_errorRelease(void *_Nonnull swiftError) noexcept;
|
|
|
|
extern "C" int $ss5ErrorMp; // external global %swift.protocol, align 4
|
|
|
|
extern "C" const void *_Nullable swift_getTypeByMangledNameInContext(
|
|
const char *_Nullable typeNameStart, size_t typeNameLength,
|
|
const void *_Nullable context,
|
|
const void *_Nullable const *_Nullable genericArgs) SWIFT_CALL;
|
|
|
|
extern "C" bool swift_dynamicCast(void *_Nullable dest, void *_Nullable src,
|
|
const void *_Nullable srcType,
|
|
const void *_Nullable targetType,
|
|
uint32_t flags);
|
|
|
|
struct SymbolicP {
|
|
alignas(2) uint8_t _1;
|
|
uint32_t _2;
|
|
uint8_t _3[2];
|
|
uint8_t _4;
|
|
} __attribute__((packed));
|
|
|
|
SWIFT_INLINE_THUNK const void *_Nullable getErrorMetadata() {
|
|
// We do not care about these symbols being duplicated across multiple shared
|
|
// libraries for now.
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wunique-object-duplication"
|
|
static SymbolicP errorSymbol;
|
|
static int *_Nonnull got_ss5ErrorMp = &$ss5ErrorMp;
|
|
#pragma clang diagnostic pop
|
|
errorSymbol._1 = 2;
|
|
errorSymbol._2 =
|
|
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(&got_ss5ErrorMp) -
|
|
reinterpret_cast<uintptr_t>(&errorSymbol._2));
|
|
errorSymbol._3[0] = '_';
|
|
errorSymbol._3[1] = 'p';
|
|
errorSymbol._4 = 0;
|
|
static_assert(sizeof(errorSymbol) == 8, "");
|
|
auto charErrorSymbol = reinterpret_cast<const char *>(&errorSymbol);
|
|
|
|
const void *ptr2 = swift_getTypeByMangledNameInContext(
|
|
charErrorSymbol, sizeof(errorSymbol) - 1, nullptr, nullptr);
|
|
return ptr2;
|
|
}
|
|
|
|
#ifndef SWIFT_CXX_INTEROP_HIDE_SWIFT_ERROR
|
|
|
|
class Error {
|
|
public:
|
|
SWIFT_INLINE_THUNK Error() {}
|
|
SWIFT_INLINE_THUNK Error(void *_Nonnull swiftError) {
|
|
opaqueValue = swiftError;
|
|
}
|
|
SWIFT_INLINE_THUNK ~Error() {
|
|
if (opaqueValue)
|
|
swift_errorRelease(opaqueValue);
|
|
}
|
|
SWIFT_INLINE_THUNK void *_Nonnull getPointerToOpaquePointer() {
|
|
return opaqueValue;
|
|
}
|
|
SWIFT_INLINE_THUNK Error(Error &&other) : opaqueValue(other.opaqueValue) {
|
|
other.opaqueValue = nullptr;
|
|
}
|
|
SWIFT_INLINE_THUNK Error(const Error &other) {
|
|
if (other.opaqueValue)
|
|
swift_errorRetain(other.opaqueValue);
|
|
opaqueValue = other.opaqueValue;
|
|
}
|
|
|
|
template <class T> SWIFT_INLINE_THUNK swift::Optional<T> as() {
|
|
alignas(alignof(T)) char buffer[sizeof(T)];
|
|
const void *em = getErrorMetadata();
|
|
void *ep = getPointerToOpaquePointer();
|
|
auto metadata = swift::TypeMetadataTrait<T>::getTypeMetadata();
|
|
|
|
// Dynamic cast will release the error, so we need to retain it.
|
|
swift_errorRetain(ep);
|
|
bool dynamicCast =
|
|
swift_dynamicCast(buffer, &ep, em, metadata,
|
|
/*take on success destroy on failure*/ 6);
|
|
|
|
if (dynamicCast) {
|
|
auto result = swift::_impl::implClassFor<T>::type::returnNewValue(
|
|
[&](char *dest) {
|
|
swift::_impl::implClassFor<T>::type::initializeWithTake(dest,
|
|
buffer);
|
|
});
|
|
return swift::Optional<T>::init(result);
|
|
}
|
|
|
|
return swift::Optional<T>::none();
|
|
}
|
|
|
|
private:
|
|
void *_Nonnull opaqueValue = nullptr;
|
|
};
|
|
|
|
namespace _impl {
|
|
|
|
constexpr inline std::size_t max(std::size_t a, std::size_t b) {
|
|
return a > b ? a : b;
|
|
}
|
|
|
|
} // namespace _impl
|
|
|
|
/// The Expected class has either an error or an value.
|
|
template<class T>
|
|
class Expected {
|
|
public:
|
|
|
|
/// Default
|
|
constexpr Expected() noexcept {
|
|
new (&buffer) Error();
|
|
has_val = false;
|
|
}
|
|
|
|
constexpr Expected(const swift::Error &error_val) noexcept {
|
|
new (&buffer) Error(error_val);
|
|
has_val = false;
|
|
}
|
|
|
|
constexpr Expected(const T &val) noexcept {
|
|
new (&buffer) T(val);
|
|
has_val = true;
|
|
}
|
|
|
|
/// Copy
|
|
constexpr Expected(Expected const& other) noexcept {
|
|
if (other.has_value())
|
|
new (&buffer) T(other.value());
|
|
else
|
|
new (&buffer) Error(other.error());
|
|
|
|
has_val = other.has_value();
|
|
}
|
|
|
|
/// Move
|
|
// FIXME: Implement move semantics when move Swift values is possible
|
|
constexpr Expected(Expected&&) noexcept { abort(); }
|
|
|
|
~Expected() noexcept {
|
|
if (has_value())
|
|
reinterpret_cast<const T *>(buffer)->~T();
|
|
else
|
|
reinterpret_cast<swift::Error *>(buffer)->~Error();
|
|
}
|
|
|
|
/// assignment
|
|
constexpr auto operator=(Expected&& other) noexcept = delete;
|
|
constexpr auto operator=(Expected&) noexcept = delete;
|
|
|
|
/// For accessing T's members
|
|
constexpr T const *_Nonnull operator->() const noexcept {
|
|
if (!has_value())
|
|
abort();
|
|
return reinterpret_cast<const T *>(buffer);
|
|
}
|
|
|
|
constexpr T *_Nonnull operator->() noexcept {
|
|
if (!has_value())
|
|
abort();
|
|
return reinterpret_cast<T *>(buffer);
|
|
}
|
|
|
|
/// Getting reference to T
|
|
constexpr T const &operator*() const & noexcept {
|
|
if (!has_value())
|
|
abort();
|
|
return reinterpret_cast<const T &>(buffer);
|
|
}
|
|
|
|
constexpr T &operator*() & noexcept {
|
|
if (!has_value())
|
|
abort();
|
|
return reinterpret_cast<T &>(buffer);
|
|
}
|
|
|
|
constexpr explicit operator bool() const noexcept { return has_value(); }
|
|
|
|
// Get value, if not exists abort
|
|
constexpr T const& value() const& {
|
|
if (!has_value())
|
|
abort();
|
|
return *reinterpret_cast<const T *>(buffer);
|
|
}
|
|
|
|
constexpr T& value() & {
|
|
if (!has_value())
|
|
abort();
|
|
return *reinterpret_cast<T *>(buffer);
|
|
}
|
|
|
|
// Get error
|
|
constexpr swift::Error const &error() const & {
|
|
if (has_value())
|
|
abort();
|
|
return reinterpret_cast<const swift::Error &>(buffer);
|
|
}
|
|
|
|
constexpr swift::Error &error() & {
|
|
if (has_value())
|
|
abort();
|
|
return reinterpret_cast<swift::Error &>(buffer);
|
|
}
|
|
|
|
constexpr bool has_value() const noexcept { return has_val; }
|
|
|
|
private:
|
|
alignas(_impl::max(alignof(T), alignof(swift::Error))) char buffer[_impl::max(
|
|
sizeof(T), sizeof(swift::Error))];
|
|
bool has_val;
|
|
};
|
|
|
|
template<>
|
|
class Expected<void> {
|
|
public:
|
|
/// Default
|
|
Expected() noexcept {
|
|
new (&buffer) Error();
|
|
has_val = false;
|
|
}
|
|
|
|
Expected(const swift::Error &error_val) noexcept {
|
|
new (&buffer) Error(error_val);
|
|
has_val = false;
|
|
}
|
|
|
|
/// Copy
|
|
Expected(Expected const& other) noexcept {
|
|
if (other.has_value())
|
|
abort();
|
|
else
|
|
new (&buffer) Error(other.error());
|
|
|
|
has_val = other.has_value();
|
|
}
|
|
|
|
/// Move
|
|
// FIXME: Implement move semantics when move swift values is possible
|
|
[[noreturn]] Expected(Expected&&) noexcept { abort(); }
|
|
|
|
~Expected() noexcept { reinterpret_cast<swift::Error *>(buffer)->~Error(); }
|
|
|
|
/// assignment
|
|
constexpr auto operator=(Expected&& other) noexcept = delete;
|
|
constexpr auto operator=(Expected&) noexcept = delete;
|
|
|
|
|
|
constexpr explicit operator bool() const noexcept { return has_value(); }
|
|
|
|
// Get error
|
|
constexpr swift::Error const &error() const & {
|
|
if (has_value())
|
|
abort();
|
|
return reinterpret_cast<const swift::Error &>(buffer);
|
|
}
|
|
|
|
constexpr swift::Error &error() & {
|
|
if (has_value())
|
|
abort();
|
|
return reinterpret_cast<swift::Error &>(buffer);
|
|
}
|
|
|
|
constexpr bool has_value() const noexcept { return has_val; }
|
|
private:
|
|
alignas(alignof(swift::Error)) char buffer[sizeof(swift::Error)];
|
|
bool has_val;
|
|
};
|
|
|
|
#ifdef __cpp_exceptions
|
|
|
|
template<class T>
|
|
using ThrowingResult = T;
|
|
|
|
#define SWIFT_RETURN_THUNK(T, v) v
|
|
#define SWIFT_NORETURN_EXCEPT_ERRORS SWIFT_NORETURN
|
|
|
|
#else
|
|
|
|
template <class T> using ThrowingResult = swift::Expected<T>;
|
|
|
|
#define SWIFT_RETURN_THUNK(T, v) swift::Expected<T>(v)
|
|
#define SWIFT_NORETURN_EXCEPT_ERRORS
|
|
|
|
#endif
|
|
|
|
#endif // SWIFT_CXX_INTEROP_HIDE_SWIFT_ERROR
|
|
#endif // SWIFT_CXX_INTEROP_EXPERIMENTAL_SWIFT_ERROR
|
|
|
|
#endif
|