Skip to content

Commit

Permalink
Merge pull request #42 from Thorium/perf-opt
Browse files Browse the repository at this point in the history
Some minor performance optimisations
  • Loading branch information
omaus authored Jul 11, 2024
2 parents 35517d8 + d83b5a0 commit 710612c
Show file tree
Hide file tree
Showing 9 changed files with 55 additions and 43 deletions.
1 change: 1 addition & 0 deletions src/FSharpAux.Core/Colors.fs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module Colors =
| B v -> v

/// Color structure
[<Struct>]
type Color = {
/// The alpha component value of this Color structure.
A : byte
Expand Down
4 changes: 3 additions & 1 deletion src/FSharpAux.Core/Dict.fs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ module Dict =
member s.ContainsKey(k) = d.ContainsKey(Some(k))
member s.TryGetValue(k,r) =
let key = Some(k)
if d.ContainsKey(key) then (r <- d.[key]; true) else false
match d.TryGetValue key with
| true, v -> r <- v; true
| false, _ -> false
member s.Remove(k : 'Key) = (raise (NotSupportedException(notMutable)) : bool)

interface ICollection<KeyValuePair<'Key, 'T>> with
Expand Down
14 changes: 8 additions & 6 deletions src/FSharpAux.Core/Regex.fs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ module Regex =
//http://stackoverflow.com/questions/5684014/f-mapping-regular-expression-matches-with-active-patterns
module Active =
/// Returns the first occurencing match of the pattern
[<return: Struct>]
let (|RegexMatchValue|_|) (regex:Regex) input =
let m = regex.Match(input)
if m.Success then Some m.Value
else None
if m.Success then ValueSome m.Value
else ValueNone



Expand Down Expand Up @@ -68,12 +69,13 @@ module Regex =
/// Returns a seq of group values matching the pattern
let parseAll regexStr line =
let rec loop (m:Match) =
seq {
match m.Success with
| true ->
yield (List.tail [ for g in m.Groups -> g.Value ])
yield! loop (m.NextMatch())
| false -> () }
seq {
yield (List.tail [ for g in m.Groups -> g.Value ])
yield! loop (m.NextMatch())
}
| false -> Seq.empty
let m = Regex.Match(line,regexStr)
loop m

Expand Down
7 changes: 4 additions & 3 deletions src/FSharpAux.Core/Seq.fs
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,10 @@ module Seq =
keyList
|> Seq.map (
fun k ->
if m.ContainsKey(k) then
aggregation m.[k]
else
match m.TryGetValue k with
| true, mk ->
aggregation mk
| false, _ ->
defaultValue
)

Expand Down
45 changes: 25 additions & 20 deletions src/FSharpAux.Core/String.fs
Original file line number Diff line number Diff line change
Expand Up @@ -79,46 +79,51 @@ module String =


// Active patterns & operators for parsing strings
let (@?) (s:string) i = if i >= s.Length then None else Some s.[i]
let (@?) (s:string) i = if i >= s.Length then ValueNone else ValueSome s.[i]

let inline satisfies predicate (charOption:option<char>) =
let inline satisfies predicate (charOption:voption<char>) =
match charOption with
| Some c when predicate c -> charOption
| _ -> None
| ValueSome c when predicate c -> charOption
| _ -> ValueNone

[<return: Struct>]
let (|EOF|_|) = function
| Some _ -> None
| _ -> Some ()
| ValueSome _ -> ValueNone
| _ -> ValueSome ()

[<return: Struct>]
let (|LetterDigit|_|) = satisfies Char.IsLetterOrDigit
[<return: Struct>]
let (|Upper|_|) = satisfies Char.IsUpper
[<return: Struct>]
let (|Lower|_|) = satisfies Char.IsLower

/// Turns a string into a nice PascalCase identifier
let niceName (s:string) =
if s = s.ToUpper() then s else
// Starting to parse a new segment
let rec restart i = seq {
let rec restart i =
match s @? i with
| EOF -> ()
| LetterDigit _ & Upper _ -> yield! upperStart i (i + 1)
| LetterDigit _ -> yield! consume i false (i + 1)
| _ -> yield! restart (i + 1) }
| EOF -> Seq.empty
| LetterDigit _ & Upper _ -> upperStart i (i + 1)
| LetterDigit _ -> consume i false (i + 1)
| _ -> restart (i + 1)

// Parsed first upper case letter, continue either all lower or all upper
and upperStart from i = seq {
and upperStart from i =
match s @? i with
| Upper _ -> yield! consume from true (i + 1)
| Lower _ -> yield! consume from false (i + 1)
| _ -> yield! restart (i + 1) }
| Upper _ -> consume from true (i + 1)
| Lower _ -> consume from false (i + 1)
| _ -> restart (i + 1)
// Consume are letters of the same kind (either all lower or all upper)
and consume from takeUpper i = seq {
and consume from takeUpper i =
match s @? i with
| Lower _ when not takeUpper -> yield! consume from takeUpper (i + 1)
| Upper _ when takeUpper -> yield! consume from takeUpper (i + 1)
| Lower _ when not takeUpper -> consume from takeUpper (i + 1)
| Upper _ when takeUpper -> consume from takeUpper (i + 1)
| _ ->
yield from, i
yield! restart i }
seq {
yield struct (from, i)
yield! restart i }

// Split string into segments and turn them to PascalCase
seq { for i1, i2 in restart 0 do
Expand Down
10 changes: 5 additions & 5 deletions src/FSharpAux.IO/FileIO.fs
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ module FileIO =
/// Detects whether the given path does not contains invalid characters.
let isValidPath (path:string) =
Path.GetInvalidPathChars()
|> Array.filter (fun char -> path.Contains(char.ToString()))
|> Array.isEmpty
|> Array.exists (fun char -> path.Contains(char.ToString()))
|> not


/// Creates a directory if it does not exist.
Expand Down Expand Up @@ -140,7 +140,7 @@ module FileIO =
let FileEnumerator (filePath) =
use reader = File.OpenText(filePath)
Seq.unfold(fun line ->
if line = null then
if isNull line then
reader.Close()
None
else
Expand Down Expand Up @@ -206,11 +206,11 @@ module FileIO =


/// Appends a text if the value is not null
let inline appendIfNotNull value s = appendIfTrue (value <> null) (sprintf "%s%A" s value)
let inline appendIfNotNull value s = appendIfTrue (not (isNull value)) (sprintf "%s%A" s value)


/// Appends a text if the value is not null
let inline appendStringIfValueIsNotNull value = appendIfTrue (value <> null)
let inline appendStringIfValueIsNotNull value = appendIfTrue (not (isNull value))


/// Appends a text if the value is not null or empty
Expand Down
5 changes: 3 additions & 2 deletions src/FSharpAux.IO/PathFileName.fs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ module PathFileName =
| _ -> failwith "No file or directory given."

/// Active Pattern for determining file extension.
[<return: Struct>]
let (|EndsWith|_|) (extension : string) (file : string) =
if file.EndsWith extension then Some()
else None
if file.EndsWith extension then ValueSome()
else ValueNone

/// Active Pattern for determining file name.
let (|FileInfoFullName|) (f : FileInfo) = f.FullName
Expand Down
4 changes: 2 additions & 2 deletions src/FSharpAux.IO/SchemaReader.fs
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ module SchemaReader =
let header = convertHeaderLine separator header

Seq.unfold(fun line ->
if line = null then
if isNull line then
reader.Close()
None
else
Expand All @@ -276,7 +276,7 @@ module SchemaReader =
| true ->
for i = 1 to skipLinesBeforeHeader do reader.ReadLine() |> ignore
let tmpLine = reader.ReadLine()
if tmpLine = null then
if isNull tmpLine then
reader.Close()
String.Empty
else
Expand Down
8 changes: 4 additions & 4 deletions src/FSharpAux/PSeq.fs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ module PSeq =
ParallelEnumerable.ElementAt(toP(s), n)

let map2 f s1 s2 =
ParallelEnumerable.Zip(toP(s1),toP(s2), Func<_,_,_>(fun x y -> f x y))
ParallelEnumerable.Zip(toP(s1),toP(s2), Func<_,_,_>(f))

let zip s1 s2 =
ParallelEnumerable.Zip(toP(s1),toP(s2), Func<_,_,_>(fun x y -> (x,y)))
Expand Down Expand Up @@ -167,7 +167,7 @@ module PSeq =
ParallelEnumerable.Select(distinct, Func<_,_>(fun (x,px) -> x))

let sort s =
ParallelEnumerable.OrderBy(toP(s), Func<_,_>(fun x -> x), ComparisonIdentity.Structural<_>) :> pseq<'T>
ParallelEnumerable.OrderBy(toP(s), Func<_,_>(id), ComparisonIdentity.Structural<_>) :> pseq<'T>

let sortBy (f : 'T -> 'Key) s =
ParallelEnumerable.OrderBy(toP(s), Func<_,_>(f), ComparisonIdentity.Structural<_>) :> pseq<'T>
Expand Down Expand Up @@ -235,7 +235,7 @@ module PSeq =
| :? seq<float> as s -> unbox(ParallelEnumerable.Min(toP(s)))
| :? seq<float32> as s -> unbox(ParallelEnumerable.Min(toP(s)))
| :? seq<decimal> as s -> unbox(ParallelEnumerable.Min(toP(s)))
| _ -> ParallelEnumerable.Min(toP(s), Func<_,_>(fun x -> x))
| _ -> ParallelEnumerable.Min(toP(s), Func<_,_>(id))

let inline minBy (f : ^T -> ^U) (s : seq< ^T >) : ^T when ^U : comparison =
let elemsAndVals = ParallelEnumerable.Select(toP(s), Func<_,_>(fun x -> f x, x))
Expand All @@ -250,7 +250,7 @@ module PSeq =
| :? seq<float> as s -> unbox(ParallelEnumerable.Max(toP(s)))
| :? seq<float32> as s -> unbox(ParallelEnumerable.Max(toP(s)))
| :? seq<decimal> as s -> unbox(ParallelEnumerable.Max(toP(s)))
| _ -> ParallelEnumerable.Max(toP(s), Func<_,_>(fun x -> x))
| _ -> ParallelEnumerable.Max(toP(s), Func<_,_>(id))

let inline maxBy (f : ^T -> ^U) (s : seq< ^T >) : ^T =
let elemsAndVals = ParallelEnumerable.Select(toP(s), Func<_,_>(fun x -> f x, x))
Expand Down

0 comments on commit 710612c

Please sign in to comment.