Skip to content

Commit c5ac81b

Browse files
committed
Started stdlib text
1 parent c7e0fb6 commit c5ac81b

File tree

4 files changed

+252
-1
lines changed

4 files changed

+252
-1
lines changed

stdlib/README.md

+136-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,140 @@
22

33
## Contents.
44

5-
## Member pack declarations.
5+
1. [Member pack declarations](#member-pack-declarations)
6+
7+
## 1. Member pack declarations.
8+
9+
Declare a pack of non-static data members with the member pack declaration syntax. Use `...` before the _declarator-id_, as if you were writing a function or template parameter pack. This is compatible with the description in [P1858R2 - Generalized pack declaration and usage](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1858r2.html#member-packs).
10+
11+
### Basic tuple
12+
13+
[**tuple1.cxx**](tuple1.cxx) - [Compiler Explorer](https://godbolt.org/z/j8ddPP9aK)
14+
```cpp
15+
#include <iostream>
16+
17+
template<typename... Types>
18+
struct tuple {
19+
[[no_unique_address]] Types ...m;
20+
};
21+
22+
int main() {
23+
// Declare and use the aggregate initializer.
24+
tuple<int, double, char> A {
25+
5, 3.14, 'X'
26+
};
27+
std::cout<< "A:\n";
28+
std::cout<< " "<< decltype(A).member_type_strings<< ": "<< A.m<< "\n" ...;
29+
30+
// It even works with CTAD! Deduced through the parameter pack.
31+
tuple B {
32+
6ll, 1.618f, true
33+
};
34+
std::cout<< "B:\n";
35+
std::cout<< " "<< decltype(B).member_type_strings<< ": "<< B.m<< "\n" ...;
36+
}
37+
```
38+
```
39+
$ circle tuple1.cxx && ./tuple1
40+
A:
41+
int: 5
42+
double: 3.14
43+
char: X
44+
B:
45+
long long: 6
46+
float: 1.618
47+
bool: 1
48+
```
49+
50+
The basic tuple becomes a one-liner. Access the data members of objects by naming the member pack. This yields a pack expression, which must be expanded with `...`. As a bonus, class template argument deduction even works through member pack declarations. We attempt aggregate initialization of `B` with a `long long`, `float` and `bool`, and the class template is indeed specialized with those arguments.
51+
52+
### Basic variant
53+
54+
[**variant1.cxx**](variant1.cxx) - [Compiler Explorer](https://godbolt.org/z/jK4fvGM1v)
55+
```cpp
56+
#include <iostream>
57+
#include <utility>
58+
59+
template<typename... Types>
60+
struct variant {
61+
union {
62+
Types ...m;
63+
};
64+
uint8_t _index = 0;
65+
66+
// Default initialize the 0th element.
67+
variant() : m...[0]() { }
68+
69+
// Initialize the index indicated by I.
70+
template<size_t I, typename U>
71+
variant(std::in_place_index_t<I>, U&& u) :
72+
m...[I](std::forward<U>(u)), _index(I) { }
73+
74+
// Search for the index of the first type that matches T.
75+
template<typename T>
76+
static constexpr size_t index_of_type = T == Types ...?? int... : -1;
77+
78+
// Count the number of types that match T.
79+
template<typename T>
80+
static constexpr size_t count_of_type = (... + (T == Types));
81+
82+
// Initialize the type indicate by T.
83+
template<typename T, typename U, size_t I = index_of_type<T> >
84+
requires(1 == count_of_type<T>)
85+
variant(std::in_place_type_t<T>, U&& u) :
86+
m...[I](std::forward<U>(u)), _index(I) { }
87+
88+
// Destroy the active variant member.
89+
~variant() {
90+
_index == int... ...? m.~Types() : __builtin_unreachable();
91+
}
92+
93+
// Use a constrained forward reference deduced this to implement all
94+
// get cv-ref combinations.
95+
template<size_t I, typename Self>
96+
auto&& get(this Self&& self : variant) {
97+
return self. ...m...[I];
98+
}
99+
};
100+
101+
// Visit the active variant member.
102+
template<typename F, typename... Types>
103+
decltype(auto) visit(F f, variant<Types...>& var) {
104+
constexpr size_t N = sizeof...(Types);
105+
var._index == int...(N) ...?
106+
f(var.template get<int...>()) :
107+
__builtin_unreachable();
108+
}
109+
110+
int main() {
111+
using Var = variant<int, double, std::string>;
112+
auto print_element = [](auto x) {
113+
std::cout<< decltype(x).string<< ": "<< x<< "\n";
114+
};
115+
116+
// Default initialize element 0 (int 0).
117+
Var v1;
118+
visit(print_element, v1);
119+
120+
// Initialize element 1 (double 6.67e-11)
121+
Var v2(std::in_place_index<1>, 6.67e-11);
122+
visit(print_element, v2);
123+
124+
// Initialize the std::string element.
125+
Var v3(std::in_place_type<std::string>, "Hello variant");
126+
visit(print_element, v3);
127+
}
128+
```
129+
```
130+
$ circle variant1.cxx && ./variant1
131+
int: 0
132+
double: 6.67e-11
133+
std::basic_string<char, std::char_traits<char>, std::allocator<char>>: Hello variant
134+
```
135+
136+
To write a basic variant, make a member pack declaration inside an unnamed union. The [pack subscript operator](https://github.com/seanbaxter/circle/tree/master/universal#pack-subscripts-and-slices) `...[I]` provides direct access to specific instantiated data members. Use it inside the _mem-initializer-list_ to name a member to initialize.
137+
138+
The [multi-conditional operator](https://github.com/seanbaxter/circle/tree/master/conditional#multi-conditional---) `...?:` makes it easy to generate a cascade of ternary operators, which serve as a higher-level switch to bridge runtime values (like `_index)` with compile-time concerns (like a particular data member). The pseudo-destructor call in the variant's destructor, or the callable invocation in `visit` are both satisfied in one line with this operator.
139+
140+
## Basic mdspan
6141

stdlib/mdspan1.cxx

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#include <limits>
2+
3+
constexpr size_t dynamic_extent = size_t.max;
4+
5+
template<size_t Index, size_t Extent>
6+
struct _storage_t {
7+
constexpr _storage_t(size_t value = Extent) noexcept { }
8+
static constexpr size_t extent = Extent;
9+
};
10+
11+
template<size_t Index>
12+
struct _storage_t<Index, dynamic_extent> {
13+
constexpr _storage_t(size_t value = 0) noexcept : extent(value) { }
14+
size_t extent;
15+
};
16+
17+
template<size_t... Extents>
18+
struct extents {
19+
[[no_unique_address]] _storage_t<int..., Extents> ...m;
20+
21+
22+
};

stdlib/tuple1.cxx

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#include <iostream>
2+
3+
template<typename... Types>
4+
struct tuple {
5+
[[no_unique_address]] Types ...m;
6+
};
7+
8+
int main() {
9+
// Declare and use the aggregate initializer.
10+
tuple<int, double, char> A {
11+
5, 3.14, 'X'
12+
};
13+
std::cout<< "A:\n";
14+
std::cout<< " "<< decltype(A).member_type_strings<< ": "<< A.m<< "\n" ...;
15+
16+
// It even works with CTAD! Deduced through the parameter pack.
17+
tuple B {
18+
6ll, 1.618f, true
19+
};
20+
std::cout<< "B:\n";
21+
std::cout<< " "<< decltype(B).member_type_strings<< ": "<< B.m<< "\n" ...;
22+
}

stdlib/variant1.cxx

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#include <iostream>
2+
#include <utility>
3+
4+
template<typename... Types>
5+
struct variant {
6+
union {
7+
Types ...m;
8+
};
9+
uint8_t _index = 0;
10+
11+
// Default initialize the 0th element.
12+
variant() : m...[0]() { }
13+
14+
// Initialize the index indicated by I.
15+
template<size_t I, typename U>
16+
variant(std::in_place_index_t<I>, U&& u) :
17+
m...[I](std::forward<U>(u)), _index(I) { }
18+
19+
// Search for the index of the first type that matches T.
20+
template<typename T>
21+
static constexpr size_t index_of_type = T == Types ...?? int... : -1;
22+
23+
// Count the number of types that match T.
24+
template<typename T>
25+
static constexpr size_t count_of_type = (... + (T == Types));
26+
27+
// Initialize the type indicate by T.
28+
template<typename T, typename U, size_t I = index_of_type<T> >
29+
requires(1 == count_of_type<T>)
30+
variant(std::in_place_type_t<T>, U&& u) :
31+
m...[I](std::forward<U>(u)), _index(I) { }
32+
33+
// Destroy the active variant member.
34+
~variant() {
35+
_index == int... ...? m.~Types() : __builtin_unreachable();
36+
}
37+
38+
// Use a constrained forward reference deduced this to implement all
39+
// get cv-ref combinations.
40+
template<size_t I, typename Self>
41+
auto&& get(this Self&& self : variant) {
42+
return self. ...m...[I];
43+
}
44+
};
45+
46+
// Visit the active variant member.
47+
template<typename F, typename... Types>
48+
decltype(auto) visit(F f, variant<Types...>& var) {
49+
constexpr size_t N = sizeof...(Types);
50+
var._index == int...(N) ...?
51+
f(var.template get<int...>()) :
52+
__builtin_unreachable();
53+
}
54+
55+
int main() {
56+
using Var = variant<int, double, std::string>;
57+
auto print_element = [](auto x) {
58+
std::cout<< decltype(x).string<< ": "<< x<< "\n";
59+
};
60+
61+
// Default initialize element 0 (int 0).
62+
Var v1;
63+
visit(print_element, v1);
64+
65+
// Initialize element 1 (double 6.67e-11)
66+
Var v2(std::in_place_index<1>, 6.67e-11);
67+
visit(print_element, v2);
68+
69+
// Initialize the std::string element.
70+
Var v3(std::in_place_type<std::string>, "Hello variant");
71+
visit(print_element, v3);
72+
}

0 commit comments

Comments
 (0)