Skip to content

Commit 3daa875

Browse files
authored
Merge pull request #61554 from apple/egorzhdan/cxx-random-access-collection
[cxx-interop] Add `CxxRandomAccessCollection` protocol
2 parents 5eb942c + 6bb0b8e commit 3daa875

File tree

6 files changed

+268
-0
lines changed

6 files changed

+268
-0
lines changed

stdlib/public/Cxx/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
add_swift_target_library(swiftCxx ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_SDK_OVERLAY
2+
CxxRandomAccessCollection.swift
23
CxxSequence.swift
34

45
SWIFT_COMPILE_FLAGS ${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS} ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
/// Bridged C++ iterator that allows computing the distance between two of its
14+
/// instances, and advancing an instance by a given number of elements.
15+
///
16+
/// Mostly useful for conforming a type to the `CxxRandomAccessCollection`
17+
/// protocol and should not generally be used directly.
18+
///
19+
/// - SeeAlso: https://en.cppreference.com/w/cpp/named_req/RandomAccessIterator
20+
public protocol UnsafeCxxRandomAccessIterator: UnsafeCxxInputIterator {
21+
associatedtype Distance: BinaryInteger
22+
23+
static func -(lhs: Self, rhs: Self) -> Distance
24+
static func +=(lhs: inout Self, rhs: Distance)
25+
}
26+
27+
extension UnsafePointer: UnsafeCxxRandomAccessIterator {}
28+
29+
extension UnsafeMutablePointer: UnsafeCxxRandomAccessIterator {}
30+
31+
public protocol CxxRandomAccessCollection: CxxSequence, RandomAccessCollection {
32+
override associatedtype RawIterator: UnsafeCxxRandomAccessIterator
33+
override associatedtype Element = RawIterator.Pointee
34+
35+
/// Do not implement this function manually in Swift.
36+
func __beginUnsafe() -> RawIterator
37+
38+
/// Do not implement this function manually in Swift.
39+
func __endUnsafe() -> RawIterator
40+
}
41+
42+
extension CxxRandomAccessCollection {
43+
@inlinable
44+
public var startIndex: Int {
45+
return 0
46+
}
47+
48+
@inlinable
49+
public var endIndex: Int {
50+
return count
51+
}
52+
53+
@inlinable
54+
public var count: Int {
55+
return Int(__endUnsafe() - __beginUnsafe())
56+
}
57+
58+
/// A C++ implementation of the subscript might be more performant. This
59+
/// overload should only be used if the C++ type does not define `operator[]`.
60+
@inlinable
61+
public subscript(_ index: Int) -> Element {
62+
_read {
63+
// Not using CxxIterator here to avoid making a copy of the collection.
64+
var rawIterator = __beginUnsafe()
65+
rawIterator += RawIterator.Distance(index)
66+
yield rawIterator.pointee as! Element
67+
}
68+
}
69+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#ifndef TEST_INTEROP_CXX_STDLIB_INPUTS_CUSTOM_COLLECTION_H
2+
#define TEST_INTEROP_CXX_STDLIB_INPUTS_CUSTOM_COLLECTION_H
3+
4+
#include "custom-iterator.h"
5+
#include <iterator>
6+
7+
struct SimpleCollectionNoSubscript {
8+
private:
9+
int x[5] = {1, 2, 3, 4, 5};
10+
11+
public:
12+
using iterator = ConstRACIterator;
13+
14+
iterator begin() const { return iterator(*x); }
15+
iterator end() const { return iterator(*x + 5); }
16+
};
17+
18+
struct SimpleCollectionReadOnly {
19+
private:
20+
int x[5] = {1, 2, 3, 4, 5};
21+
22+
public:
23+
using iterator = ConstRACIteratorRefPlusEq;
24+
25+
iterator begin() const { return iterator(*x); }
26+
iterator end() const { return iterator(*x + 5); }
27+
28+
const int& operator[](int index) const { return x[index]; }
29+
};
30+
31+
#endif // TEST_INTEROP_CXX_STDLIB_INPUTS_CUSTOM_COLLECTION_H

test/Interop/Cxx/stdlib/overlay/Inputs/custom-iterator.h

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,121 @@ struct ConstIterator {
4040
}
4141
};
4242

43+
struct ConstRACIterator {
44+
private:
45+
int value;
46+
47+
public:
48+
using iterator_category = std::random_access_iterator_tag;
49+
using value_type = int;
50+
using pointer = int *;
51+
using reference = const int &;
52+
using difference_type = int;
53+
54+
ConstRACIterator(int value) : value(value) {}
55+
ConstRACIterator(const ConstRACIterator &other) = default;
56+
57+
const int &operator*() const { return value; }
58+
59+
ConstRACIterator &operator++() {
60+
value++;
61+
return *this;
62+
}
63+
ConstRACIterator operator++(int) {
64+
auto tmp = ConstRACIterator(value);
65+
value++;
66+
return tmp;
67+
}
68+
69+
void operator+=(difference_type v) { value += v; }
70+
void operator-=(difference_type v) { value -= v; }
71+
ConstRACIterator operator+(difference_type v) const {
72+
return ConstRACIterator(value + v);
73+
}
74+
ConstRACIterator operator-(difference_type v) const {
75+
return ConstRACIterator(value - v);
76+
}
77+
friend ConstRACIterator operator+(difference_type v,
78+
const ConstRACIterator &it) {
79+
return it + v;
80+
}
81+
int operator-(const ConstRACIterator &other) const {
82+
return value - other.value;
83+
}
84+
85+
bool operator<(const ConstRACIterator &other) const {
86+
return value < other.value;
87+
}
88+
89+
bool operator==(const ConstRACIterator &other) const {
90+
return value == other.value;
91+
}
92+
bool operator!=(const ConstRACIterator &other) const {
93+
return value != other.value;
94+
}
95+
};
96+
97+
// Same as ConstRACIterator, but operator+= returns a reference to this.
98+
struct ConstRACIteratorRefPlusEq {
99+
private:
100+
int value;
101+
102+
public:
103+
using iterator_category = std::random_access_iterator_tag;
104+
using value_type = int;
105+
using pointer = int *;
106+
using reference = const int &;
107+
using difference_type = int;
108+
109+
ConstRACIteratorRefPlusEq(int value) : value(value) {}
110+
ConstRACIteratorRefPlusEq(const ConstRACIteratorRefPlusEq &other) = default;
111+
112+
const int &operator*() const { return value; }
113+
114+
ConstRACIteratorRefPlusEq &operator++() {
115+
value++;
116+
return *this;
117+
}
118+
ConstRACIteratorRefPlusEq operator++(int) {
119+
auto tmp = ConstRACIteratorRefPlusEq(value);
120+
value++;
121+
return tmp;
122+
}
123+
124+
ConstRACIteratorRefPlusEq &operator+=(difference_type v) {
125+
value += v;
126+
return *this;
127+
}
128+
ConstRACIteratorRefPlusEq &operator-=(difference_type v) {
129+
value -= v;
130+
return *this;
131+
}
132+
ConstRACIteratorRefPlusEq operator+(difference_type v) const {
133+
return ConstRACIteratorRefPlusEq(value + v);
134+
}
135+
ConstRACIteratorRefPlusEq operator-(difference_type v) const {
136+
return ConstRACIteratorRefPlusEq(value - v);
137+
}
138+
friend ConstRACIteratorRefPlusEq
139+
operator+(difference_type v, const ConstRACIteratorRefPlusEq &it) {
140+
return it + v;
141+
}
142+
int operator-(const ConstRACIteratorRefPlusEq &other) const {
143+
return value - other.value;
144+
}
145+
146+
bool operator<(const ConstRACIteratorRefPlusEq &other) const {
147+
return value < other.value;
148+
}
149+
150+
bool operator==(const ConstRACIteratorRefPlusEq &other) const {
151+
return value == other.value;
152+
}
153+
bool operator!=(const ConstRACIteratorRefPlusEq &other) const {
154+
return value != other.value;
155+
}
156+
};
157+
43158
/// Same as ConstIterator, but defines `operator==` as a non-member.
44159
struct ConstIteratorOutOfLineEq {
45160
int value;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module CustomSequence {
22
header "custom-iterator.h" // TODO: extract into another module
33
header "custom-sequence.h"
4+
header "custom-collection.h"
45
requires cplusplus
56
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop)
2+
//
3+
// REQUIRES: executable_test
4+
// REQUIRES: OS=macosx || OS=linux-gnu
5+
6+
import StdlibUnittest
7+
import CustomSequence
8+
import Cxx
9+
10+
var CxxCollectionTestSuite = TestSuite("CxxCollection")
11+
12+
// === SimpleCollectionNoSubscript ===
13+
14+
extension SimpleCollectionNoSubscript.iterator : UnsafeCxxRandomAccessIterator {
15+
public typealias Distance = difference_type
16+
}
17+
extension SimpleCollectionNoSubscript : CxxRandomAccessCollection {
18+
}
19+
20+
CxxCollectionTestSuite.test("SimpleCollectionNoSubscript as Swift.Collection") {
21+
let c = SimpleCollectionNoSubscript()
22+
expectEqual(c.first, 1)
23+
expectEqual(c.last, 5)
24+
}
25+
26+
// === SimpleCollectionReadOnly ===
27+
28+
extension SimpleCollectionReadOnly.iterator : UnsafeCxxRandomAccessIterator {
29+
public typealias Distance = difference_type
30+
}
31+
extension SimpleCollectionReadOnly : CxxRandomAccessCollection {
32+
}
33+
34+
CxxCollectionTestSuite.test("SimpleCollectionReadOnly as Swift.Collection") {
35+
let c = SimpleCollectionReadOnly()
36+
expectEqual(c.first, 1)
37+
expectEqual(c.last, 5)
38+
}
39+
40+
// === SimpleArrayWrapper ===
41+
42+
extension SimpleArrayWrapper : CxxRandomAccessCollection {
43+
}
44+
45+
CxxCollectionTestSuite.test("SimpleArrayWrapper as Swift.Collection") {
46+
let c = SimpleArrayWrapper()
47+
expectEqual(c.first, 10)
48+
expectEqual(c.last, 50)
49+
}
50+
51+
runAllTests()

0 commit comments

Comments
 (0)