Skip to content

Instantly share code, notes, and snippets.

@neoeinstein
Created May 16, 2015 00:44
Show Gist options
  • Save neoeinstein/a7670efcd77526518b27 to your computer and use it in GitHub Desktop.
Save neoeinstein/a7670efcd77526518b27 to your computer and use it in GitHub Desktop.
FastPrintF
// FastPrintf - a fast F# printf replacement
// Copyright (C) 2011-2012, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
// Report bugs and download new versions at http://hg.zeuxcg.org/fastprintf
// This library is distributed under the MIT License.
[<AutoOpen>]
module FastPrintf
// Configuration defines:
// FASTPRINTF_COMPAT_FS2 - enables F# 2.0 compatibility (no padding for %c)
// FASTPRINTF_COMPAT_FX3 - enables .NET 3.x compatibility (no ConcurrentDictionary)
open System
open System.Globalization
open System.Reflection
open System.Text
open System.IO
open Microsoft.FSharp.Core.Printf
#if FASTPRINTF_COMPAT_FX3
open System.Collections.Generic
#else
open System.Collections.Concurrent
#endif
module private PrintfImpl =
[<Flags>]
type FormatFlags =
| None = 0
| ZeroFill = 1
| LeftJustify = 2
| AddSignIfPositive = 4
| AddSpaceIfPositive = 8
type FormatElement =
{ flags: FormatFlags
width: int
precision: int
typ: char
postfix: string }
let inline hasFlag e f = (e &&& f) = f
let inline (===) l r = Object.ReferenceEquals(l, r)
let parseFormatFlag ch =
match ch with
| '0' -> FormatFlags.ZeroFill
| '-' -> FormatFlags.LeftJustify
| '+' -> FormatFlags.AddSignIfPositive
| ' ' -> FormatFlags.AddSpaceIfPositive
| _ -> FormatFlags.None
let rec parseFormatFlags (fmt: string) i acc =
match parseFormatFlag fmt.[i] with
| FormatFlags.None -> i, acc
| x -> parseFormatFlags fmt (i + 1) (acc ||| x)
let rec parseNumber (fmt: string) i acc =
match fmt.[i] with
| ch when ch >= '0' && ch <= '9' -> parseNumber fmt (i + 1) (acc * 10 + int ch - int '0')
| _ -> i, acc
let rec parseString (fmt: string) i =
if i >= fmt.Length || fmt.[i] = '%' then i
else parseString fmt (i + 1)
let parsePrecision (fmt: string) i def =
if fmt.[i] = '.' then parseNumber fmt (i + 1) 0
else i, def
let parseElement (fmt: string) i =
let i, flags = parseFormatFlags fmt i FormatFlags.None
let i, width = parseNumber fmt i 0
let i, precision = parsePrecision fmt i -1
i + 1, { new FormatElement with flags = flags and width = width and precision = precision and typ = fmt.[i] and postfix = "" }
let parseFormatString (fmt: string) =
let rec loop i acc =
if i >= fmt.Length then acc
else
assert (fmt.[i] = '%')
let i, el = parseElement fmt (i + 1)
let e = parseString fmt i
loop e ({el with postfix = fmt.Substring(i, e - i)} :: acc)
let prefix = parseString fmt 0
let elements = loop prefix []
let prefixs = fmt.Substring(0, prefix)
let rec mergeRev (els: FormatElement list) acc =
match els with
| x :: y :: xs when x.typ = '%' -> mergeRev ({ y with postfix = y.postfix + "%" + x.postfix } :: xs) acc
| x :: xs -> mergeRev xs (x :: acc)
| [] -> acc
match mergeRev elements [] with
| x :: xs when x.typ = '%' -> prefixs + "%" + x.postfix, xs
| xs -> prefixs, xs
let addPadding (e: FormatElement) (conv: 'a -> string) =
if e.width = 0 then
conv
else
let ch = if hasFlag e.flags FormatFlags.ZeroFill then '0' else ' '
if hasFlag e.flags FormatFlags.LeftJustify then
fun x -> (conv x).PadRight(e.width, ch)
else
fun x -> (conv x).PadLeft(e.width, ch)
let formatChar c =
match c with
| '\'' -> "\\\'"
| '\\' -> "\\\\"
| '\b' -> "\\b"
| _ when System.Char.IsControl(c) ->
let d1 = (int c / 100) % 10
let d2 = (int c / 10) % 10
let d3 = int c % 10
"\\" + d1.ToString() + d2.ToString() + d3.ToString()
| _ -> c.ToString()
let genericPrintOpt (o: obj) =
match o with
| null -> "<null>"
| :? double as d ->
let s = d.ToString("g10", CultureInfo.InvariantCulture)
if System.Double.IsNaN(d) then "nan"
elif System.Double.IsNegativeInfinity(d) then "-infinity"
elif System.Double.IsPositiveInfinity(d) then "infinity"
elif String.forall(fun c -> System.Char.IsDigit(c) || c = '-') s
then s + ".0"
else s
| :? single as d ->
(if System.Single.IsNaN(d) then "nan"
elif System.Single.IsNegativeInfinity(d) then "-infinity"
elif System.Single.IsPositiveInfinity(d) then "infinity"
elif float32(System.Int32.MinValue) < d && d < float32(System.Int32.MaxValue) && float32(int32(d)) = d
then (System.Convert.ToInt32 d).ToString(CultureInfo.InvariantCulture) + ".0"
else d.ToString("g10", CultureInfo.InvariantCulture))
+ "f"
| :? System.Decimal as d -> d.ToString("g", CultureInfo.InvariantCulture) + "M"
| :? uint64 as d -> d.ToString(CultureInfo.InvariantCulture) + "UL"
| :? int64 as d -> d.ToString(CultureInfo.InvariantCulture) + "L"
| :? int32 as d -> d.ToString(CultureInfo.InvariantCulture)
| :? uint32 as d -> d.ToString(CultureInfo.InvariantCulture) + "u"
| :? int16 as d -> d.ToString(CultureInfo.InvariantCulture) + "s"
| :? uint16 as d -> d.ToString(CultureInfo.InvariantCulture) + "us"
| :? sbyte as d -> d.ToString(CultureInfo.InvariantCulture) + "y"
| :? byte as d -> d.ToString(CultureInfo.InvariantCulture) + "uy"
| :? nativeint as d -> d.ToString() + "n"
| :? unativeint as d -> d.ToString() + "un"
| :? bool as b -> (if b then "true" else "false")
| :? char as c -> "\'" + formatChar c + "\'"
| :? string as s -> "\"" + s + "\""
| :? Enum as e -> e.ToString()
| _ -> null
[<AllowNullLiteral>]
type FormatContext<'Result> =
abstract Apply: (obj -> obj) * FormatElement -> unit
abstract Append: string * FormatElement -> unit
abstract Finish: unit -> 'Result
type FormatTransformer<'Result> = FormatContext<'Result> -> FormatContext<'Result>
type FormatFactoryString<'Result> =
static member Next<'T, 'Cont> (e: FormatElement) (func: 'T -> string) (next: FormatTransformer<'Result> -> 'Cont) =
fun (state: FormatTransformer<'Result>) ->
fun (v: 'T) ->
let state' acc =
let r = state acc
r.Append(func v, e)
r
next state'
static member Opt1<'A0> e0 f0 =
fun (state: FormatTransformer<'Result>) ->
fun (a0: 'A0) ->
let s = state null
s.Append(f0 a0, e0)
s.Finish()
static member Opt2<'A0, 'A1> e0 e1 f0 f1 =
fun (state: FormatTransformer<'Result>) ->
fun (a0: 'A0) (a1: 'A1) ->
let s = state null
s.Append(f0 a0, e0)
s.Append(f1 a1, e1)
s.Finish()
static member Opt3<'A0, 'A1, 'A2> e0 e1 e2 f0 f1 f2 =
fun (state: FormatTransformer<'Result>) ->
fun (a0: 'A0) (a1: 'A1) (a2: 'A2) ->
let s = state null
s.Append(f0 a0, e0)
s.Append(f1 a1, e1)
s.Append(f2 a2, e2)
s.Finish()
static member Opt4<'A0, 'A1, 'A2, 'A3> e0 e1 e2 e3 f0 f1 f2 f3 =
fun (state: FormatTransformer<'Result>) ->
fun (a0: 'A0) (a1: 'A1) (a2: 'A2) (a3: 'A3) ->
let s = state null
s.Append(f0 a0, e0)
s.Append(f1 a1, e1)
s.Append(f2 a2, e2)
s.Append(f3 a3, e3)
s.Finish()
static member Opt5<'A0, 'A1, 'A2, 'A3, 'A4> e0 e1 e2 e3 e4 f0 f1 f2 f3 f4 =
fun (state: FormatTransformer<'Result>) ->
fun (a0: 'A0) (a1: 'A1) (a2: 'A2) (a3: 'A3) (a4: 'A4) ->
let s = state null
s.Append(f0 a0, e0)
s.Append(f1 a1, e1)
s.Append(f2 a2, e2)
s.Append(f3 a3, e3)
s.Append(f4 a4, e4)
s.Finish()
type FormatFactoryGeneric<'State, 'Residue, 'Result> =
static member CreateT<'Cont> (e: FormatElement) (next: FormatTransformer<'Result> -> 'Cont) =
fun (state: FormatTransformer<'Result>) ->
fun (f: 'State -> 'Residue) ->
let state' acc =
let r = state acc
r.Apply((fun s -> f (unbox s) |> box), e)
r
next state'
static member CreateA<'T, 'Cont> (e: FormatElement) (next: FormatTransformer<'Result> -> 'Cont) =
fun (state: FormatTransformer<'Result>) ->
fun (f: 'State -> 'T -> 'Residue) (v: 'T) ->
let state' acc =
let r = state acc
r.Apply((fun s -> f (unbox s) v |> box), e)
r
next state'
type Factory =
static member CreateBoxString<'T> (e: FormatElement) =
let basic = fun (o: 'T) -> if o === null then "<null>" else o.ToString()
basic |> addPadding e
static member CreateGenericString<'T> (e: FormatElement) =
let fmt =
String.Concat("%",
(if hasFlag e.flags FormatFlags.AddSignIfPositive then "+" else ""),
(if hasFlag e.flags FormatFlags.ZeroFill then "0" else if e.width > 0 then string e.width else ""),
(if e.precision >= 0 then "." + string e.precision else ""),
"A")
if fmt = "%A" then
fun (o: 'T) ->
let s = genericPrintOpt (box o)
if s <> null then s
else sprintf (StringFormat<'T -> string>(fmt)) o
else
fun (o: 'T) -> sprintf (StringFormat<'T -> string>(fmt)) o
let bindingFlags = BindingFlags.Static ||| BindingFlags.NonPublic
let getStringFormatterNext<'Result> e func next arg cont =
typeof<FormatFactoryString<'Result>>.GetMethod("Next", bindingFlags).MakeGenericMethod([|arg; cont|]).Invoke(null, [|box e; box func; box next|])
let getStringFormatterOptN<'Result> n types args =
assert (n >= 1 && n <= 5)
typeof<FormatFactoryString<'Result>>.GetMethod("Opt" + n.ToString(), bindingFlags).MakeGenericMethod(types).Invoke(null, args)
let getGenericFormatterT<'State, 'Residue, 'Result> e next cont =
typeof<FormatFactoryGeneric<'State, 'Residue, 'Result>>.GetMethod("CreateT", bindingFlags).MakeGenericMethod([|cont|]).Invoke(null, [|box e; box next|])
let getGenericFormatterA<'State, 'Residue, 'Result> e next arg cont =
typeof<FormatFactoryGeneric<'State, 'Residue, 'Result>>.GetMethod("CreateA", bindingFlags).MakeGenericMethod([|arg; cont|]).Invoke(null, [|box e; box next|])
let getBoxStringFunction (e: FormatElement) (typ: Type) =
typeof<Factory>.GetMethod("CreateBoxString", bindingFlags).MakeGenericMethod([|typ|]).Invoke(null, [|box e|])
let getGenericStringFunction (e: FormatElement) (typ: Type) =
typeof<Factory>.GetMethod("CreateGenericString", bindingFlags).MakeGenericMethod([|typ|]).Invoke(null, [|box e|])
let inline toStringInvariant (x: 'T) =
(^T: (member ToString: IFormatProvider -> string) (x, CultureInfo.InvariantCulture))
let inline toStringFormatInvariant (x: 'T) format =
(^T: (member ToString: string -> IFormatProvider -> string) (x, format, CultureInfo.InvariantCulture))
let inline toStringIntegerBasic (e: FormatElement) unsigned : 'T -> string =
match e.typ with
| 'd' | 'i' -> fun (x: 'T) -> toStringInvariant x
| 'u' -> fun (x: 'T) -> toStringInvariant (x |> unsigned)
| 'x' -> fun (x: 'T) -> toStringFormatInvariant x "x"
| 'X' -> fun (x: 'T) -> toStringFormatInvariant x "X"
| 'o' -> fun (x: 'T) -> Convert.ToString(x |> unsigned |> int64, 8)
| _ -> failwithf "Unrecognized integer type specifier '%c'" e.typ
let inline toStringInteger (e: FormatElement) unsigned : 'T -> string =
let basic = toStringIntegerBasic e unsigned
if e.width = 0 && e.flags = FormatFlags.None then
basic
else fun (x: 'T) ->
let mutable s = basic x
let mutable sign = false
if s.[0] = '-' then
sign <- true
else if hasFlag e.flags FormatFlags.AddSignIfPositive || hasFlag e.flags FormatFlags.AddSpaceIfPositive then
s <- (if hasFlag e.flags FormatFlags.AddSignIfPositive then "+" else " ") + s
sign <- true
if e.width = 0 then
s
else if hasFlag e.flags FormatFlags.LeftJustify then
s.PadRight(e.width, ' ')
else if hasFlag e.flags FormatFlags.ZeroFill then
if sign then
if e.width <= s.Length then s
else
s.Insert(1, String('0', e.width - s.Length))
else s.PadLeft(e.width, '0')
else
s.PadLeft(e.width, ' ')
let getFloatFormat (e: FormatElement) =
e.typ.ToString() + (if e.precision < 0 then "6" else (max (min e.precision 99) 0).ToString())
let getFloatSign (e: FormatElement) =
if hasFlag e.flags FormatFlags.AddSpaceIfPositive then " " else "+"
let inline toStringFloatBasic fmt (e: FormatElement) : 'T -> string =
if hasFlag e.flags FormatFlags.AddSignIfPositive || hasFlag e.flags FormatFlags.AddSpaceIfPositive then
fun (x: 'T) ->
let s = toStringFormatInvariant x fmt
if s.[0] <> '-' && s.[0] <> 'N' then
getFloatSign e + s
else
s
else
fun (x: 'T) -> toStringFormatInvariant x fmt
let inline floatIsFinite (x: 'T) =
not (^T: (static member IsPositiveInfinity: 'T -> bool) x) &&
not (^T: (static member IsNegativeInfinity: 'T -> bool) x) &&
not (^T: (static member IsNaN: 'T -> bool) x)
let inline toStringFloat (e: FormatElement) : 'T -> string =
let basic = toStringFloatBasic (getFloatFormat e) e
if e.width = 0 && e.flags = FormatFlags.None then
basic
else fun (x: 'T) ->
let mutable s = basic x
let ch = if hasFlag e.flags FormatFlags.ZeroFill && floatIsFinite x then '0' else ' '
if hasFlag e.flags FormatFlags.LeftJustify then s.PadRight(e.width, ch)
else s.PadLeft(e.width, ch)
let toString (e: FormatElement) (typ: Type) =
match e.typ with
| 'b' -> (fun x -> if x then "true" else "false") |> addPadding e |> box
| 'c' ->
(fun (x: char) -> x.ToString())
#if FASTPRINTF_COMPAT_FS2
#else
|> addPadding e
#endif
|> box
| 'd' | 'i' | 'u' | 'x' | 'X' | 'o' ->
if typ === typeof<int8> then toStringInteger e uint8 |> box<int8 -> string>
else if typ === typeof<uint8> then toStringInteger e uint8 |> box<uint8 -> string>
else if typ === typeof<int16> then toStringInteger e uint16 |> box<int16 -> string>
else if typ === typeof<uint16> then toStringInteger e uint16 |> box<uint16 -> string>
else if typ === typeof<int32> then toStringInteger e uint32 |> box<int32 -> string>
else if typ === typeof<uint32> then toStringInteger e uint32 |> box<uint32 -> string>
else if typ === typeof<int64> then toStringInteger e uint64 |> box<int64 -> string>
else if typ === typeof<uint64> then toStringInteger e uint64 |> box<uint64 -> string>
else if typ === typeof<nativeint> then
match sizeof<nativeint> with
| 4 -> (fun x -> int32 x |> toStringInteger e uint32) |> box<nativeint -> string>
| 8 -> (fun x -> int64 x |> toStringInteger e uint64) |> box<nativeint -> string>
| x -> failwith "Unexpected size for nativeint: %d" x
else if typ === typeof<unativeint> then
match sizeof<unativeint> with
| 4 -> (fun x -> uint32 x |> toStringInteger e uint32) |> box<unativeint -> string>
| 8 -> (fun x -> uint64 x |> toStringInteger e uint64) |> box<unativeint -> string>
| x -> failwith "Unexpected size for unativeint: %d" x
else failwithf "Unrecognized type %A" typ
| 'e' | 'E' | 'f' | 'F' | 'g' | 'G' ->
if typ === typeof<float32> then toStringFloat e |> box<float32 -> string>
else if typ === typeof<float> then toStringFloat e |> box<float -> string>
else if typ === typeof<decimal> then toStringFloatBasic (getFloatFormat e) e |> addPadding e |> box<decimal -> string>
else failwithf "Unrecognized type %A" typ
| 'M' ->
if typ === typeof<decimal> then toStringFloatBasic "G" e |> addPadding e |> box<decimal -> string>
else failwithf "Unrecognized type %A" typ
| 's' ->
if typ === typeof<string> then (fun (x: string) -> if x = null then "" else x) |> addPadding e |> box
else failwithf "Unrecognized type %A" typ
| 'O' -> getBoxStringFunction e typ
| 'A' -> getGenericStringFunction e typ
| _ -> failwithf "Unrecognized format type %c" e.typ
let getFunctionElements (typ: Type) =
match typ.GetGenericArguments() with
| [|car; cdr|] -> car, cdr
| _ -> failwithf "Type %A is not a function type" typ
let rec unpackFunctionArguments (typ: Type) =
match typ.GetGenericArguments() with
| [|car; cdr|] -> car :: unpackFunctionArguments cdr
| _ -> []
let rec getFormatter<'State, 'Residue, 'Result> (els: FormatElement list) (typ: Type) =
match els with
| [] ->
fun (state: FormatTransformer<'Result>) -> (state null).Finish()
|> box
| _ when els.Length <= 5 && List.forall (fun e -> e.typ <> 't' && e.typ <> 'a') els ->
let args = unpackFunctionArguments typ |> List.toArray
let els = els |> List.toArray
getStringFormatterOptN<'Result> args.Length args (Array.append (els |> Array.map box) (Array.map2 toString els args))
| x :: xs ->
let arg, cont = getFunctionElements typ
match x.typ with
| 't' ->
let next = getFormatter<'State, 'Residue, 'Result> xs cont
getGenericFormatterT<'State, 'Residue, 'Result> x next cont
| 'a' ->
let arg, cont = getFunctionElements cont
let next = getFormatter<'State, 'Residue, 'Result> xs cont
getGenericFormatterA<'State, 'Residue, 'Result> x next arg cont
| _ ->
let str = toString x arg
let next = getFormatter<'State, 'Residue, 'Result> xs cont
getStringFormatterNext<'Result> x str next arg cont
type StringConcatFormatContext<'Result>(prefix: string, finish) =
let mutable state = prefix
interface FormatContext<'Result> with
member this.Apply(f, e) = (this :> FormatContext<'Result>).Append(f null :?> string, e)
member this.Append(s, e) = state <- String.Concat(state, s, e.postfix)
member this.Finish() = finish state
type StringJoinFormatContext<'Result>(prefix: string, count, finish) =
let state = Array.zeroCreate (count * 2 + 1)
do state.[0] <- prefix
let mutable index = 1
interface FormatContext<'Result> with
member this.Apply(f, e) = (this :> FormatContext<'Result>).Append(f null :?> string, e)
member this.Append(s, e) =
state.[index] <- s
state.[index + 1] <- e.postfix
index <- index + 2
member this.Finish() =
assert (index = state.Length)
finish (String.Join("", state))
type TextWriterFormatContext<'Result>(writer: TextWriter, prefix: string, finish) =
do writer.Write(prefix)
interface FormatContext<'Result> with
member this.Apply(f, e) = f (box writer) |> ignore; writer.Write(e.postfix)
member this.Append(s, e) = writer.Write(s); writer.Write(e.postfix)
member this.Finish() = finish ()
type StringBuilderFormatContext<'Result>(builder: StringBuilder, prefix: string, finish) =
do builder.Append(prefix) |> ignore
interface FormatContext<'Result> with
member this.Apply(f, e) = f (box builder) |> ignore; builder.Append(e.postfix) |> ignore
member this.Append(s, e) = builder.Append(s).Append(e.postfix) |> ignore
member this.Finish() = finish ()
let inline getStringFormatContext prefix count (formatter: FormatTransformer<'Result> -> 'Printer) cont =
if count <= 1 then
formatter (fun _ -> StringConcatFormatContext<'Result>(prefix, cont) :> FormatContext<'Result>)
else
formatter (fun _ -> StringJoinFormatContext<'Result>(prefix, count, cont) :> FormatContext<'Result>)
#if FASTPRINTF_COMPAT_FX3
type Cache<'K, 'V when 'K : equality>(generator) =
let data = Dictionary<'K, 'V>()
member this.Item key =
lock data (fun _ ->
let mutable value = Unchecked.defaultof<'V>
if data.TryGetValue(key, &value) then value
else
let value = generator key
data.Add(key, value)
value)
#else
type Cache<'K, 'V when 'K : equality>(generator) =
let data = ConcurrentDictionary<'K, 'V>()
let creator = Func<'K, 'V>(generator)
member this.Item key =
data.GetOrAdd(key, creator)
#endif
type LocalCache<'K, 'V when 'K: equality>() =
let mutable key = Unchecked.defaultof<'K>
let mutable value = Unchecked.defaultof<'V>
member this.Item k (cache: Cache<'K, 'V>) =
if key === k then
value
else
let v = cache.Item k
key <- k
value <- v
v
type PrintfCache<'Printer, 'State, 'Residue, 'Result>() =
static let cache = Cache<string, _>(fun fmt ->
let prefix, els = parseFormatString fmt
let count = els.Length
let formatter = getFormatter<'State, 'Residue, 'Result> els typeof<'Printer> :?> FormatTransformer<'Result> -> 'Printer
prefix, count, formatter)
[<ThreadStatic; DefaultValue>]
static val mutable private local: LocalCache<string, string * int * (FormatTransformer<'Result> -> 'Printer)>
static member Item fmt =
let lc = PrintfCache<'Printer, 'State, 'Residue, 'Result>.local
if lc === null then
let lc = LocalCache<_, _>()
PrintfCache<'Printer, 'State, 'Residue, 'Result>.local <- lc
lc.Item fmt cache
else
lc.Item fmt cache
let gprintf (fmt: #Format<'Printer, 'State, 'Residue, 'Result>) =
PrintfCache<'Printer, 'State, 'Residue, 'Result>.Item fmt.Value
let idString: string -> string = id
let idUnit : unit -> unit = id
type PrintfCacheString<'Printer>() =
static let cache = Cache<string, _>(fun fmt ->
let prefix, count, formatter = PrintfCache<'Printer, unit, string, string>.Item fmt
getStringFormatContext prefix count formatter idString)
[<ThreadStatic; DefaultValue>]
static val mutable private local: LocalCache<string, 'Printer>
static member Item fmt =
let lc = PrintfCacheString<'Printer>.local
if lc === null then
let lc = LocalCache<_, _>()
PrintfCacheString<'Printer>.local <- lc
lc.Item fmt cache
else
lc.Item fmt cache
module Printf =
open PrintfImpl
let kbprintf (cont: unit -> 'Result) (builder: StringBuilder) (fmt: #BuilderFormat<'Printer, 'Result>): 'Printer =
let prefix, count, formatter = gprintf fmt
formatter (fun _ -> StringBuilderFormatContext<'Result>(builder, prefix, cont) :> FormatContext<'Result>)
let kfprintf (cont: unit -> 'Result) (writer: TextWriter) (fmt: #TextWriterFormat<'Printer, 'Result>): 'Printer =
let prefix, count, formatter = gprintf fmt
formatter (fun _ -> TextWriterFormatContext<'Result>(writer, prefix, cont) :> FormatContext<'Result>)
let ksprintf (cont: string -> 'Result) (fmt: #StringFormat<'Printer, 'Result>): 'Printer =
let prefix, count, formatter = gprintf fmt
getStringFormatContext prefix count formatter cont
let bprintf (builder: StringBuilder) (fmt: #BuilderFormat<'Printer>): 'Printer = kbprintf idUnit builder fmt
let fprintf (writer: TextWriter) (fmt: #TextWriterFormat<'Printer>): 'Printer = kfprintf idUnit writer fmt
let fprintfn (writer: TextWriter) (fmt: #TextWriterFormat<'Printer>): 'Printer = kfprintf (fun _ -> writer.WriteLine()) writer fmt
let printf (fmt: #TextWriterFormat<'Printer>): 'Printer = fprintf Console.Out fmt
let printfn (fmt: #TextWriterFormat<'Printer>): 'Printer = fprintfn Console.Out fmt
let eprintf (fmt: #TextWriterFormat<'Printer>): 'Printer = fprintf Console.Error fmt
let eprintfn (fmt: #TextWriterFormat<'Printer>): 'Printer = fprintfn Console.Error fmt
let sprintf (fmt: #StringFormat<'Printer>): 'Printer =
PrintfCacheString<'Printer>.Item fmt.Value
let kprintf (cont: string -> 'Result) (fmt: #StringFormat<'Printer, 'Result>): 'Printer = ksprintf cont fmt
let failwithf (fmt: #StringFormat<'Printer, 'Result>): 'Printer = ksprintf failwith fmt
let printf (fmt: #TextWriterFormat<'Printer>): 'Printer = Printf.printf fmt
let printfn (fmt: #TextWriterFormat<'Printer>): 'Printer = Printf.printfn fmt
let eprintf (fmt: #TextWriterFormat<'Printer>): 'Printer = Printf.eprintf fmt
let eprintfn (fmt: #TextWriterFormat<'Printer>): 'Printer = Printf.eprintfn fmt
let sprintf (fmt: #StringFormat<'Printer>): 'Printer = Printf.sprintf fmt
let failwithf (fmt: #StringFormat<'Printer, 'Result>): 'Printer = Printf.failwithf fmt
let fprintf (writer: TextWriter) (fmt: #TextWriterFormat<'Printer>): 'Printer = Printf.fprintf writer fmt
let fprintfn (writer: TextWriter) (fmt: #TextWriterFormat<'Printer>): 'Printer = Printf.fprintfn writer fmt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment