Update idioms.md with changes to match the code now (#4587)

- Rename TypedInstArgsInfo references to InstLikeTypeInfo. The type was
renamed in 07efa026de.
- Update and correct the link to search for ValueStore (and similar) in
the Context class. We must avoid the google-doc-style checks rewriting
`repo:` to `repository:` in the URL.
- Mention the existance of many types of Store collections now.
- Remove pre-C++20 idioms in Field detection. Correct the concept based
idioms to work.
- Fix code indenting consistency.

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
Dana Jansens
2024-11-25 20:09:17 +00:00
committed by GitHub
co-authored by Richard Smith
parent dcfdf12315
commit 2cb6507392
+26 -41
View File
@@ -167,14 +167,25 @@ Some name mirroring examples are:
- `strings` is a `ValueStore<StringId>`, which has an index type of
`StringId`, but for copy-related reasons, uses `llvm::StringRef` for values.
A fairly complete list of `ValueStore` uses should be available on
[checking's Context class](https://github.com/search?q=repository%3Acarbon-language%2Fcarbon-lang%20path%3Acheck%2Fcontext.h%20symbol%3Aidentifiers&type=code).
There are also a number of wrappers around `ValueStore` that provide some
additional functionality and which are named with the `Store` suffix, such as
`InstStore` or `CanonicalValueStore`.
A fairly complete list of `ValueStore` (and `ValueStore` wrapper) uses should be
available on [checking's Context class].
<!-- google-doc-style-ignore -->
[checking's Context class]:
https://github.com/search?q=repo%3Acarbon-language%2Fcarbon-lang+path%3Atoolchain%2Fcheck%2Fcontext.h+%2F%5Cw%2BStore%2F&type=code
<!-- google-doc-style-resume -->
## Template metaprogramming
TODO: show example patterns
- TypedInstArgsInfo from toolchain/sem_ir/inst.h
- InstLikeTypeInfo from toolchain/sem_ir/inst.h
- templated using
- std::declval
- decltype
@@ -197,41 +208,15 @@ The presence of specific fields in a struct with a specified type is detected
using the following idiom:
```cpp
template <typename T, typename = FieldType T::*>
constexpr bool HasField = false;
template <typename T>
constexpr bool HasField<T, decltype(&T::field)> = true;
```
This is intended to check the same property as the following concept, which we
can't use because we currently need to compile in C++17 mode:
```cpp
// HasField<T> is true if T has a `U field` field of type FieldType.
template <typename T> concept HasField = requires (T x) {
{ x.field } -> std::same_as<FieldType>;
{ &T::field } -> std::same_as<FieldType T::*>;
};
```
To detect a field with a specific name with a type derived from a specified base
type, use this idiom:
```cpp
// HasField<T> is true if T has a `U field` field,
// where `U` extends `BaseClass`.
template <typename T, bool Enabled = true>
inline constexpr bool HasField = false;
template <typename T>
inline constexpr bool HasField<
T, bool(std::is_base_of_v<BaseClass, decltype(T::field)>)> = true;
```
The equivalent concept is:
```cpp
template <typename T> concept HasField = requires (T x) {
{ x.field } -> std::derived_from<BaseClass>;
};
```
See `HasKindMemberAsField` in
[`toolchain/sem_ir/typed_insts.h`](/toolchain/sem_ir/typed_insts.h) for an
example.
## Local lambdas to reduce duplicate code
@@ -266,17 +251,17 @@ This can be used for complex initialization, as in:
```cpp
// variable declaration
static const llvm::ArrayRef<std::byte> entropy_bytes =
// initializer starts with a lambda
// initializer starts with a lambda
[]() -> llvm::ArrayRef<std::byte> {
static llvm::SmallVector<std::byte> bytes;
static llvm::SmallVector<std::byte> bytes;
// a bunch of code
// a bunch of code
// return the value to initialize the variable with
return bytes;
// return the value to initialize the variable with
return bytes;
// finish defining the lambda, and then immediately invoke it
}();
// finish defining the lambda, and then immediately invoke it
}();
```
It can also be used inside a `CARBON_DCHECK` to avoid computation that is only