3 people like it.
Like the snippet!
Computation expression for String.Create
We can use power of computation expressions and InlineIfLambda to get nice syntax and mutable index tracking for allocating strings
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
|
open System
type SpanReader<'T, 'TState, 'TRet> = delegate of span: Span<'T> * state: byref<'TState> -> 'TRet
[<Struct; NoComparison; NoEquality>]
type StringAllocatorState<'TCtx> =
{
mutable Position: int
Ctx: 'TCtx
}
type StringAllocatorReader<'TCtx, 'TRet> = SpanReader<char, StringAllocatorState<'TCtx>, 'TRet>
let inline getContext() =
StringAllocatorReader(fun _ state -> state.Ctx)
type StringAllocator() =
member inline this.Zero() = StringAllocatorReader(fun _ _ -> ())
member inline _.Combine(
[<InlineIfLambda>] f: StringAllocatorReader<'TCtx, unit>,
[<InlineIfLambda>] g: StringAllocatorReader<'TCtx, unit>) =
StringAllocatorReader(fun chars state ->
f.Invoke(chars, &state)
g.Invoke(chars, &state))
member inline _.Delay(
[<InlineIfLambda>] f: unit -> StringAllocatorReader<'TCtx, unit>) =
StringAllocatorReader(fun chars state -> (f()).Invoke(chars, &state))
member inline _.Bind(
[<InlineIfLambda>] reader: StringAllocatorReader<'TCtx, 'TRet>,
[<InlineIfLambda>] cont: 'TRet -> StringAllocatorReader<'TCtx, unit>) =
StringAllocatorReader(fun chars state ->
let ret = reader.Invoke(chars, &state)
(cont ret).Invoke(chars, &state))
member inline _.Yield(ch: char) =
StringAllocatorReader(fun chars state ->
chars[state.Position] <- ch;
state.Position <- state.Position + 1)
member inline _.Yield(str: string) =
StringAllocatorReader(fun chars state ->
str.AsSpan().CopyTo(chars.Slice(state.Position))
state.Position <- state.Position + str.Length)
let stringAlloc = StringAllocator()
let inline run
(length: int)
(ctx: 'TCtx)
([<InlineIfLambda>] action: StringAllocatorReader<'TCtx, unit>) =
String.Create(
length,
ctx,
System.Buffers.SpanAction(fun chars ctx ->
let mutable state = { Position = 0; Ctx = ctx }
action.Invoke(chars, &state)))
let s =
run 5 [| "ab"; "cd"; "e" |]
(stringAlloc {
let! xs = getContext()
yield xs[0]
yield xs[1]
yield xs[2]
})
Console.WriteLine(s)
|
namespace System
type SpanReader<'T,'TState,'TRet> =
delegate of Span<'T> * byref<'TState> -> 'TRet
type byref<'T> = (# "<Common IL Type Omitted>" #)
Multiple items
type StructAttribute =
inherit Attribute
new : unit -> StructAttribute
--------------------
new : unit -> StructAttribute
Multiple items
type NoComparisonAttribute =
inherit Attribute
new : unit -> NoComparisonAttribute
--------------------
new : unit -> NoComparisonAttribute
Multiple items
type NoEqualityAttribute =
inherit Attribute
new : unit -> NoEqualityAttribute
--------------------
new : unit -> NoEqualityAttribute
[<Struct>]
type StringAllocatorState<'TCtx> =
{ mutable Position: int
Ctx: 'TCtx }
StringAllocatorState.Position: int
Multiple items
val int : value:'T -> int (requires member op_Explicit)
--------------------
type int = int32
--------------------
type int<'Measure> = int
StringAllocatorState.Ctx: 'TCtx
type StringAllocatorReader<'TCtx,'TRet> = SpanReader<char,StringAllocatorState<'TCtx>,'TRet>
Multiple items
val char : value:'T -> char (requires member op_Explicit)
--------------------
type char = Char
val getContext : unit -> StringAllocatorReader<'a,'a>
val state : byref<StringAllocatorState<'a>>
Multiple items
type StringAllocator =
new : unit -> StringAllocator
member Bind : reader:StringAllocatorReader<'TCtx,'TRet> * cont:('TRet -> StringAllocatorReader<'TCtx,unit>) -> StringAllocatorReader<'TCtx,unit>
member Combine : f:StringAllocatorReader<'TCtx,unit> * g:StringAllocatorReader<'TCtx,unit> -> StringAllocatorReader<'TCtx,unit>
member Delay : f:(unit -> StringAllocatorReader<'TCtx,unit>) -> StringAllocatorReader<'TCtx,unit>
member Yield : ch:char -> StringAllocatorReader<'b,unit>
member Yield : str:string -> StringAllocatorReader<'a,unit>
member Zero : unit -> StringAllocatorReader<'c,unit>
--------------------
new : unit -> StringAllocator
val this : StringAllocator
val f : StringAllocatorReader<'TCtx,unit>
type unit = Unit
val g : StringAllocatorReader<'TCtx,unit>
val chars : Span<char>
val state : byref<StringAllocatorState<'TCtx>>
val f : (unit -> StringAllocatorReader<'TCtx,unit>)
val reader : StringAllocatorReader<'TCtx,'TRet>
val cont : ('TRet -> StringAllocatorReader<'TCtx,unit>)
val ret : 'TRet
val ch : char
val state : byref<StringAllocatorState<'b>>
val str : string
Multiple items
val string : value:'T -> string
--------------------
type string = String
val stringAlloc : StringAllocator
val run : length:int -> ctx:'TCtx -> action:StringAllocatorReader<'TCtx,unit> -> string
val length : int
val ctx : 'TCtx
val action : StringAllocatorReader<'TCtx,unit>
Multiple items
type String =
new : value:char[] -> string + 8 overloads
member Chars : int -> char
member Clone : unit -> obj
member CompareTo : value:obj -> int + 1 overload
member Contains : value:string -> bool + 3 overloads
member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
member EndsWith : value:string -> bool + 3 overloads
member EnumerateRunes : unit -> StringRuneEnumerator
member Equals : obj:obj -> bool + 2 overloads
member GetEnumerator : unit -> CharEnumerator
...
--------------------
String(value: char []) : String
String(value: nativeptr<char>) : String
String(value: nativeptr<sbyte>) : String
String(value: ReadOnlySpan<char>) : String
String(c: char, count: int) : String
String(value: char [], startIndex: int, length: int) : String
String(value: nativeptr<char>, startIndex: int, length: int) : String
String(value: nativeptr<sbyte>, startIndex: int, length: int) : String
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : String
String.Create<'TState>(length: int, state: 'TState, action: Buffers.SpanAction<char,'TState>) : string
namespace System.Buffers
type SpanAction<'T,'TArg> =
delegate of Span<'T> * 'TArg -> unit
[<Struct>]
val mutable state : StringAllocatorState<'TCtx>
val s : string
val xs : string []
type Console =
static member BackgroundColor : ConsoleColor with get, set
static member Beep : unit -> unit + 1 overload
static member BufferHeight : int with get, set
static member BufferWidth : int with get, set
static member CapsLock : bool
static member Clear : unit -> unit
static member CursorLeft : int with get, set
static member CursorSize : int with get, set
static member CursorTop : int with get, set
static member CursorVisible : bool with get, set
...
Console.WriteLine() : unit
(+0 other overloads)
Console.WriteLine(value: string) : unit
(+0 other overloads)
Console.WriteLine(value: obj) : unit
(+0 other overloads)
Console.WriteLine(value: uint64) : unit
(+0 other overloads)
Console.WriteLine(value: int64) : unit
(+0 other overloads)
Console.WriteLine(value: uint32) : unit
(+0 other overloads)
Console.WriteLine(value: int) : unit
(+0 other overloads)
Console.WriteLine(value: float32) : unit
(+0 other overloads)
Console.WriteLine(value: float) : unit
(+0 other overloads)
Console.WriteLine(value: decimal) : unit
(+0 other overloads)
More information