Skip to content

Commit

Permalink
Merge pull request dotnet#2 from CyrusNajmabadi/patch-2
Browse files Browse the repository at this point in the history
Update CL-LDM-05-31-2023.md
  • Loading branch information
CyrusNajmabadi authored May 30, 2023
2 parents 36178ef + 4ba0c14 commit 3ba3c38
Showing 1 changed file with 37 additions and 1 deletion.
38 changes: 37 additions & 1 deletion meetings/working-groups/collection-literals/CL-LDM-05-31-2023.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,22 +77,58 @@ Open Questions:

### Target-typing with BCL attribute Create method

Main examples:

```c#
List<int> list = [1, 2, 3]; // equivalent to:
CollectionsMarshal.Create<int>(capacity: 3, out List<int> list, out Span<T> __storage);
__storage[0] = 1;
__storage[1] = 2;
__storage[2] = 3;

// Works identically for ImmutableArray<T>.
// However, some types cannot give you the storage to write sequentially into. For those, the pattern is:
ImmutableDictionary<string, int> namesToAge = [ "Dustin": 42, "Cyrus": 43 ]; // equivalent to:
// Storage is initialized (ideally on stack when safe), and passed to type to type to own creating its internal structure
ReadOnlySpan<KeyValuePair<string, int>> storage = [ new("Dustin", 42), new("Cyrus", 43) ]; // could be heap or stack.
CollectionsMarshal.Create<string, int>(out ImmutableDictionary<string, int> namesToAge, storage);
```

The pattern is:

```cs
// Attribute placed on collection target type, stating where to find the factory method.
// Specifies the type where it is found, and the factory method name. Up to BCL to include.
[CollectionLiteralBuilder(
typeof(CollectionsMarshal),
nameof(CollectionsMarshal.Create))]
public class MyCollection<T> : IEnumerable<T> { }
public class MyCollection<T> : IEnumerable<T> { } // or
[CollectionLiteralBuilder(
typeof(CollectionsMarshal),
nameof(CollectionsMarshal.Create))]
public class MyDictionary<TKey, TValue> : IEnumerable<KVP<TKey, TValue>> { }

// Factory method shape:
public static class CollectionsMarshal
{
// For cases where the instance can share out its storage and as a sequential buffer for caller to place the values in.
// Storage span is passed out for caller to populate with no overhead.
public static void Create<T>(
int capacity,
out ImmutableArray<T> collection,
out Span<T> storage);

// For cases where the final instance has to manage non-sequentual structure. Storage is passed in and copied over to
// internal structure.
public static void Create<T>(
out ImmutableHashSet<T> collection,
ReadOnlySpan<T> storage);

// Example of the shape for things like dictionaries.
public static void Create<TKey, TValue>(
out ImmutableDictionary<TKey, TValue> collection,
ReadOnlySpan<KeyValuePair<TKey, TValue>> storage);
Expand Down

0 comments on commit 3ba3c38

Please sign in to comment.