Skip to content

Commit 2ce9eab

Browse files
authored
Merge pull request #407 from elbeno/design-docs-extra
📝 Add more design thoughts
2 parents f317c4e + 78af6fd commit 2ce9eab

3 files changed

Lines changed: 116 additions & 0 deletions

File tree

docs/design/bit.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# bit
2+
3+
Source code: https://github.com/intel/cpp-std-extensions/blob/main/include/stdx/bit.hpp
4+
Documentation: https://intel.github.io/cpp-std-extensions/#_bit_hpp
5+
6+
## No more manual bit twiddling!
7+
8+
A lot of the functionality in this header exists to put an end to manual bit
9+
shifting, masking, etc. Yes it's easy, but it's not simple. Manual bit
10+
operations are prone to sign and integer promotion errors, and sprinkling
11+
`static_cast` everywhere to guard against this makes things ugly and less
12+
understandable.
13+
14+
## `to_be`, `from_be`, `to_le`, `from_le`
15+
16+
`to_be` and `from_be` have identical implementations. As do `to_le` and
17+
`from_le`. But they are different in showing the intent of user code. And also
18+
different in pre and post conditions:
19+
20+
```cpp
21+
// pre: x is big-endian
22+
// post: x is platform-endian
23+
auto x = stdx::from_be(y);
24+
25+
// pre: x is platform-endian
26+
// post: x is big-endian
27+
auto x = stdx::to_be(y);
28+
```
29+
30+
In other words, the use of `from_be`/`to_be` is very different from the use of
31+
`std::byteswap` in cross-platform friendly code.
32+
33+
## `bit_pack` and `bit_unpack`
34+
35+
These functions have some interesting endianness concerns. It is important that
36+
the functions round-trip properly.
37+
38+
```cpp
39+
std::uint8_t a{0x12u}, b{0x34u}, c{0x56u}, d{0x78u};
40+
auto x = stdx::bit_pack<std::uint32_t>(a, b, c, d);
41+
auto [a_, b_, c_, d_] = stdx::bit_unpack<std::uint8_t>(x);
42+
// a == a_, b == b_; c == c_, d == d_
43+
```
44+
45+
This also means that that "written order" (big-endian) is the expected ordering.
46+
47+
```cpp
48+
auto [a, b, c, d] = stdx::bit_unpack<std::uint8_t>(0x12345678u);
49+
// a == 0x12, b == 0x34; c == 0x56, d == 0x78
50+
```
51+
52+
## `bit_destructure`
53+
54+
`bit_destructure` and `bit_unpack` are similar, but where `bit_unpack` is
55+
"big-endian" (for the above reasons), `bit_destructure` is "little-endian".
56+
Because it makes sense to count **up** in bits.
57+
58+
Also, N split points mean N+1 values.
59+
60+
```cpp
61+
auto [a, b, c, d] = stdx::bit_destructure<8, 16, 24>(0x12345678u);
62+
// a == 0x78, b == 0x56; c == 0x34, d == 0x12
63+
```

docs/design/cached_latched.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# cached and latched
2+
3+
Source code: https://github.com/intel/cpp-std-extensions/blob/main/include/stdx/latched.hpp
4+
Documentation: https://intel.github.io/cpp-std-extensions/#_latched_hpp
5+
6+
Source code: https://github.com/intel/cpp-std-extensions/blob/main/include/stdx/cached.hpp
7+
Documentation: https://intel.github.io/cpp-std-extensions/#_latched_hpp
8+
9+
## Lazy values
10+
11+
Both `cached` and `latched` model lazy computation of values. Under the hood
12+
they are just `std::optional`.
13+
14+
Note that use of `cached` and `latched` generally incurs a branch check for each
15+
use.
16+
17+
`latched` does not provide for `reset`/`refresh`: it's intended for values that
18+
are read once at startup time.
19+
20+
`cached` values can be `reset` or `refresh`ed. The default should probably be to
21+
`reset` and lazily recompute but `refresh` is for the use case of "recompute
22+
now".
23+
24+
### Other ideas
25+
26+
We don't use `stdx::optional` here; that requires tombstone value(s). Maybe
27+
there is a way to select the optional implementation based on detecting a
28+
tombstone? in practice many use cases for `cached`/`latched` are register
29+
(`std::uint32_t`) reads rather than strong types that could use tombstones.

docs/design/utility.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# utility
2+
3+
Source code: https://github.com/intel/cpp-std-extensions/blob/main/include/stdx/utility.hpp
4+
Documentation: https://intel.github.io/cpp-std-extensions/#_utility_hpp
5+
6+
## sized
7+
8+
This exists so that we don't have to reason about "raw" size calculations
9+
everywhere:
10+
11+
```cpp
12+
// not this
13+
auto size_in_dwords = (size_in_bytes + 3) / 4;
14+
// but this
15+
auto size_in_dwords = stdx::sized8{size_in_bytes}.in<std::uint32_t>();
16+
```
17+
18+
More verbose, but almost certainly less error-prone and easier to read. These
19+
are simple operations, and sometimes they should be terse. If the values are
20+
known at compile time:
21+
22+
```cpp
23+
constexpr auto size_in_dwords = 42_z8->z32;
24+
```

0 commit comments

Comments
 (0)