Skip to content

Commit a023223

Browse files
committed
Backporting to Xcode 13
1 parent d03bf31 commit a023223

File tree

14 files changed

+297
-35
lines changed

14 files changed

+297
-35
lines changed

include/objc-helpers/BoxUtil.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <ostream>
2626
#include <sstream>
2727
#include <filesystem>
28+
#include <compare>
2829

2930

3031
/**
@@ -120,7 +121,7 @@ namespace BoxMakerDetail __attribute__((visibility("hidden"))) {
120121
template<class T>
121122
class __attribute__((visibility("hidden"))) BoxMaker {
122123
private:
123-
static consteval auto detectBoxedType() {
124+
static constexpr auto detectBoxedType() {
124125
if constexpr (std::totally_ordered<T>) {
125126
if constexpr (std::is_copy_constructible_v<T>) {
126127
return (NSObject<BoxedValue, BoxedComparable, NSCopying> *)nullptr;
@@ -284,8 +285,13 @@ class __attribute__((visibility("hidden"))) BoxMaker {
284285
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"comparison operand is of invalid type" userInfo:nullptr];
285286
auto * val = (T *)classData.addrOfValue(self);
286287
auto * otherVal = (T *)classData.addrOfValue(other);
288+
#if _LIBCPP_VERSION >= 14000
287289
const auto res = std::compare_strong_order_fallback(*val, *otherVal);
288290
return NSComparisonResult(-(res < 0) + (res > 0));
291+
#else
292+
return NSComparisonResult(-(*val < *otherVal) + (*val > *otherVal));
293+
#endif
294+
289295
}
290296
public:
291297
template<class... Args>
@@ -334,7 +340,7 @@ class __attribute__((visibility("hidden"))) BoxMaker {
334340
*/
335341
template<class T, class... Args>
336342
requires(std::is_constructible_v<T, Args...>)
337-
inline auto box(Args &&... args) -> BoxMaker<T>::BoxedType
343+
inline auto box(Args &&... args) -> typename BoxMaker<T>::BoxedType
338344
{ return BoxMaker<T>::box(std::forward<Args>(args)...); }
339345

340346

@@ -358,7 +364,7 @@ inline auto box(Args &&... args) -> BoxMaker<T>::BoxedType
358364
*/
359365
template<class T>
360366
requires(std::is_constructible_v<std::remove_cvref_t<T>, T &&>)
361-
inline auto box(T && src) -> BoxMaker<T>::BoxedType
367+
inline auto box(T && src) -> typename BoxMaker<T>::BoxedType
362368
{ return BoxMaker<std::remove_cvref_t<T>>::box(std::forward<T>(src)); }
363369

364370
/**

include/objc-helpers/CoDispatch.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <cassert>
2727
#include <limits>
2828
#include <utility>
29+
#include <exception>
2930

3031
#include <dispatch/dispatch.h>
3132
#ifndef __OBJC__
@@ -658,7 +659,7 @@ inline namespace CO_DISPATCH_NS {
658659

659660
template<class... Args>
660661
requires(DelayedValue::template IsEmplaceableFrom<Args...>)
661-
void success(Args && ...args) const noexcept(noexcept(m_sharedState->emplaceReturnValue(std::forward<Args>(args)...)))
662+
void success(Args && ...args) const noexcept(noexcept(m_sharedState->emplaceReturnValue(std::forward<Args>(args)...)))
662663
{ m_sharedState->emplaceReturnValue(std::forward<Args>(args)...); }
663664

664665
template<class X=DelayedValue>
@@ -958,7 +959,7 @@ inline namespace CO_DISPATCH_NS {
958959
return awaiter{*this};
959960
}
960961

961-
void return_void() noexcept
962+
void return_void() noexcept
962963
{}
963964

964965
void destroy() const noexcept {
@@ -1141,7 +1142,7 @@ inline namespace CO_DISPATCH_NS {
11411142
};
11421143

11431144
/**
1144-
@function
1145+
@function
11451146
Coroutine version of `dispatch_io_read`
11461147
11471148
Unlike `dispatch_io_read` the progressHandler parameter is optional and is only needed if you
@@ -1160,7 +1161,7 @@ inline namespace CO_DISPATCH_NS {
11601161
}
11611162

11621163
/**
1163-
@function
1164+
@function
11641165
Coroutine version of `dispatch_read`
11651166
11661167
@return DispatchIOResult object with operation result
@@ -1174,7 +1175,7 @@ inline namespace CO_DISPATCH_NS {
11741175
}
11751176

11761177
/**
1177-
@function
1178+
@function
11781179
Coroutine version of `dispatch_io_write`
11791180
11801181
Unlike `dispatch_io_write` the progressHandler parameter is optional and is only needed if you
@@ -1194,7 +1195,7 @@ inline namespace CO_DISPATCH_NS {
11941195
}
11951196

11961197
/**
1197-
@function
1198+
@function
11981199
Coroutine version of `dispatch_write`
11991200
12001201
@return DispatchIOResult object with operation result

include/objc-helpers/NSStringUtil.h

Lines changed: 159 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@
1515

1616
#include <version>
1717

18-
#if __cpp_lib_ranges < 201911L
19-
#error This header requires C++20 mode or above with ranges support
18+
#if !__cpp_concepts
19+
#error This header requires C++20 mode or above with concepts support
2020
#endif
2121

22+
2223
#include "NSObjectUtil.h"
2324

2425
#ifdef __OBJC__
@@ -30,6 +31,10 @@
3031
#include <ranges>
3132
#include <string_view>
3233
#include <ostream>
34+
#if __cpp_lib_ranges < 201911L
35+
#include <vector>
36+
#include <span>
37+
#endif
3338

3439
#pragma clang diagnostic push
3540
#pragma clang diagnostic ignored "-Wnullability-extension"
@@ -446,6 +451,8 @@ inline auto makeStdString(NSStringCharAccess::const_iterator first, NSStringChar
446451
return makeStdString<Char>(first.getCFString(), first.index(), last.index() - first.index());
447452
}
448453

454+
#if __cpp_lib_ranges >= 201911L
455+
449456
/**
450457
Converts NSStringCharAccess or a view derived from it to `std::basic_string<Char>`
451458
@@ -489,6 +496,90 @@ inline auto makeCFString(const CharRange & range) -> CFStringRef __nullable {
489496
}
490497
}
491498

499+
#else
500+
501+
/**
502+
Converts `NSStringCharAccess` to `std::basic_string<Char>`
503+
504+
@tparam Char character type of the resultant std::basic_string
505+
506+
Conversions to char16_t are exact and never fail. Conversions to other character types are transcodings and can fail if source string contains invalid UTF-16
507+
sequences. In such cases an empty string is returned. Encodings of char and wchar_t are UTF-8 and UTF-32 respectively.
508+
*/
509+
template<CharTypeConvertibleWithNSString Char>
510+
inline auto makeStdString(const NSStringCharAccess & access) {
511+
return makeStdString<Char>(access.begin(), access.end());
512+
}
513+
514+
/**
515+
Converts `std::basic_string_view` to `CFString`
516+
517+
The type of range's characters can be any of: char, char16_t, char32_t, char8_t, wchar_t.
518+
519+
@returns nullptr on failure
520+
521+
Conversions from char16_t are exact and can only fail if out of memory. Conversions from other character types are
522+
transcodings and can fail if source string contains invalid UTF sequences. Encodings of char and wchar_t are UTF-8 and UTF-32 respectively.
523+
*/
524+
template<CharTypeConvertibleWithNSString Char>
525+
inline auto makeCFString(std::basic_string_view<Char> str) -> CFStringRef __nullable {
526+
if (str.empty())
527+
return CFSTR("");
528+
if constexpr (std::is_same_v<Char, char16_t>) {
529+
return CFStringCreateWithCharacters(nullptr, (const UniChar *)str.data(), CFIndex(str.size()));
530+
} else {
531+
return CFStringCreateWithBytes(nullptr, (const UInt8 *)str.data(), CFIndex(str.size() * sizeof(Char)),
532+
kCFStringEncodingFor<Char>, false);
533+
}
534+
}
535+
536+
/**
537+
Converts `std::basic_string` to `CFString`
538+
539+
The type of range's characters can be any of: char, char16_t, char32_t, char8_t, wchar_t.
540+
541+
@returns nullptr on failure
542+
543+
Conversions from char16_t are exact and can only fail if out of memory. Conversions from other character types are
544+
transcodings and can fail if source string contains invalid UTF sequences. Encodings of char and wchar_t are UTF-8 and UTF-32 respectively.
545+
*/
546+
template<CharTypeConvertibleWithNSString Char>
547+
inline auto makeCFString(std::basic_string<Char> str) -> CFStringRef __nullable {
548+
return makeCFString(std::basic_string_view<Char>(str));
549+
}
550+
551+
/**
552+
Converts `std::vector<Char>` to `CFString`
553+
554+
The type of range's characters can be any of: char, char16_t, char32_t, char8_t, wchar_t.
555+
556+
@returns nullptr on failure
557+
558+
Conversions from char16_t are exact and can only fail if out of memory. Conversions from other character types are
559+
transcodings and can fail if source string contains invalid UTF sequences. Encodings of char and wchar_t are UTF-8 and UTF-32 respectively.
560+
*/
561+
template<CharTypeConvertibleWithNSString Char>
562+
inline auto makeCFString(std::vector<Char> str) -> CFStringRef __nullable {
563+
return makeCFString(std::basic_string_view<Char>(str.data(), str.size()));
564+
}
565+
566+
/**
567+
Converts `std::span<Char>` to `CFString`
568+
569+
The type of range's characters can be any of: char, char16_t, char32_t, char8_t, wchar_t.
570+
571+
@returns nullptr on failure
572+
573+
Conversions from char16_t are exact and can only fail if out of memory. Conversions from other character types are
574+
transcodings and can fail if source string contains invalid UTF sequences. Encodings of char and wchar_t are UTF-8 and UTF-32 respectively.
575+
*/
576+
template<CharTypeConvertibleWithNSString Char>
577+
inline auto makeCFString(std::span<Char> str) -> CFStringRef __nullable {
578+
return makeCFString(std::basic_string_view<Char>(str.data(), str.size()));
579+
}
580+
581+
#endif
582+
492583
/**
493584
Converts a null terminated character string to CFString
494585
@@ -524,6 +615,8 @@ inline auto makeCFString(const std::initializer_list<Char> & str) {
524615

525616
#ifdef __OBJC__
526617

618+
#if __cpp_lib_ranges >= 201911L
619+
527620
/**
528621
Converts any contiguous range of characters to NSString
529622
@@ -540,6 +633,70 @@ inline auto makeNSString(const CharRange & range) {
540633
return (__bridge_transfer NSString *)makeCFString(range);
541634
}
542635

636+
#else
637+
638+
/**
639+
Converts `std::basic_string_view` to NSString
640+
641+
@returns nil on failure
642+
643+
The type of range's characters can be any of: char, char16_t, char32_t, char8_t, wchar_t.
644+
645+
Conversions from char16_t are exact and can only fail if out of memory. Conversions from other character types are
646+
transcodings and can fail if source string contains invalid UTF sequences. Encodings of char and wchar_t are UTF-8 and UTF-32 respectively.
647+
*/
648+
template<CharTypeConvertibleWithNSString Char>
649+
inline auto makeNSString(std::basic_string_view<Char> str) {
650+
return (__bridge_transfer NSString *)makeCFString(str);
651+
}
652+
653+
/**
654+
Converts `std::basic_string` to NSString
655+
656+
@returns nil on failure
657+
658+
The type of range's characters can be any of: char, char16_t, char32_t, char8_t, wchar_t.
659+
660+
Conversions from char16_t are exact and can only fail if out of memory. Conversions from other character types are
661+
transcodings and can fail if source string contains invalid UTF sequences. Encodings of char and wchar_t are UTF-8 and UTF-32 respectively.
662+
*/
663+
template<CharTypeConvertibleWithNSString Char>
664+
inline auto makeNSString(std::basic_string<Char> str) {
665+
return (__bridge_transfer NSString *)makeCFString(str);
666+
}
667+
668+
/**
669+
Converts `std::vector<Char>` to NSString
670+
671+
@returns nil on failure
672+
673+
The type of range's characters can be any of: char, char16_t, char32_t, char8_t, wchar_t.
674+
675+
Conversions from char16_t are exact and can only fail if out of memory. Conversions from other character types are
676+
transcodings and can fail if source string contains invalid UTF sequences. Encodings of char and wchar_t are UTF-8 and UTF-32 respectively.
677+
*/
678+
template<CharTypeConvertibleWithNSString Char>
679+
inline auto makeNSString(std::vector<Char> str) {
680+
return (__bridge_transfer NSString *)makeCFString(str);
681+
}
682+
683+
/**
684+
Converts `std::span<Char>` to NSString
685+
686+
@returns nil on failure
687+
688+
The type of range's characters can be any of: char, char16_t, char32_t, char8_t, wchar_t.
689+
690+
Conversions from char16_t are exact and can only fail if out of memory. Conversions from other character types are
691+
transcodings and can fail if source string contains invalid UTF sequences. Encodings of char and wchar_t are UTF-8 and UTF-32 respectively.
692+
*/
693+
template<CharTypeConvertibleWithNSString Char>
694+
inline auto makeNSString(std::span<Char> str) {
695+
return (__bridge_transfer NSString *)makeCFString(str);
696+
}
697+
698+
#endif
699+
543700
/**
544701
Converts a null terminated character string to NSString
545702

include/objc-helpers/XCTestUtil.h

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
#error This header requires C++20 mode or above with concepts support
1414
#endif
1515

16+
#if !__has_feature(cxx_exceptions)
17+
#error This header requires C++ exceptions to be enabled
18+
#endif
19+
1620
#ifdef __OBJC__
1721

1822
#import <XCTest/XCTest.h>
@@ -67,20 +71,49 @@ namespace TestUtil {
6771
return [NSString stringWithFormat:@"%s object", demangle(typeid(T).name()).c_str()];
6872
}
6973
}
74+
75+
inline NSString * getCurrentExceptionReason() {
76+
std::exception_ptr ex = std::current_exception();
77+
try {
78+
std::rethrow_exception(ex);
79+
} catch (NSException * nex) {
80+
return nex.reason;
81+
} catch (const std::exception & cex) {
82+
return [NSString stringWithFormat:@"%s: %s", demangle(typeid(cex).name()).c_str(), cex.what()];
83+
} catch(...) {
84+
return @"unknown exception type";
85+
}
86+
}
7087
}
7188

89+
#if defined(_XCT_TRY) && defined(_XCT_CATCH) && defined(_XCT_THROW)
90+
#define OBJCH_XCT_TRY _XCT_TRY
91+
#define OBJCH_CATCH(T) _XCT_CATCH(T)
92+
#define OBJCH_XCT_THROW _XCT_THROW
93+
#else
94+
#define OBJCH_XCT_TRY try
95+
#define OBJCH_XCT_CATCH(T) catch(T)
96+
#define OBJCH_XCT_THROW throw
97+
#endif
98+
99+
#ifdef _XCTGetCurrentExceptionReason
100+
#define objchGetCurrentExceptionReason _XCTGetCurrentExceptionReason
101+
#else
102+
#define objchGetCurrentExceptionReason TestUtil::getCurrentExceptionReason
103+
#endif
104+
72105
#define XCTPrimitiveAssertCpp(test, op, type, expression1, expressionStr1, expression2, expressionStr2, ...) \
73106
({ \
74-
_XCT_TRY { \
107+
OBJCH_XCT_TRY { \
75108
__typeof__(expression1) expressionValue1 = (expression1); \
76109
__typeof__(expression2) expressionValue2 = (expression2); \
77110
if (expressionValue1 op expressionValue2) { \
78111
_XCTRegisterFailure(test, _XCTFailureDescription((type), 0, expressionStr1, expressionStr2, TestUtil::describeForTest(expressionValue1), TestUtil::describeForTest(expressionValue2)), __VA_ARGS__); \
79112
} \
80113
} \
81-
_XCT_CATCH (_XCTestCaseInterruptionException *interruption) { [interruption raise]; } \
82-
_XCT_CATCH (...) { \
83-
NSString *_xct_reason = _XCTGetCurrentExceptionReason(); \
114+
OBJCH_XCT_CATCH (_XCTestCaseInterruptionException *interruption) { [interruption raise]; } \
115+
OBJCH_XCT_CATCH (...) { \
116+
NSString *_xct_reason = objchGetCurrentExceptionReason(); \
84117
_XCTRegisterUnexpectedFailure(test, _XCTFailureDescription((type), 1, expressionStr1, expressionStr2, _xct_reason), __VA_ARGS__); \
85118
} \
86119
})

0 commit comments

Comments
 (0)