Skip to content

Commit

Permalink
Replace some Seq calls to increase performance.
Browse files Browse the repository at this point in the history
  • Loading branch information
nojaf committed Nov 22, 2022
1 parent 88d5f18 commit 18657b1
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,17 @@ let queryTrie (trie: TrieNode) (path: ModuleSegment list) : QueryTrieNodeResult
match path with
| [] -> failwith "path should not be empty"
| [ lastNodeFromPath ] ->
let childResults =
currentNode.Children
|> Seq.tryFind (fun (KeyValue (segment, _childNode)) -> segment = lastNodeFromPath)

match childResults with
| None -> QueryTrieNodeResult.NodeDoesNotExist
| Some (KeyValue (_, childNode)) ->
match currentNode.Children.TryGetValue(lastNodeFromPath) with
| false, _ -> QueryTrieNodeResult.NodeDoesNotExist
| true, childNode ->
if Set.isEmpty childNode.Files then
QueryTrieNodeResult.NodeDoesNotExposeData
else
QueryTrieNodeResult.NodeExposesData(childNode.Files)
| currentPath :: restPath ->
let childResults =
currentNode.Children
|> Seq.tryFind (fun (KeyValue (segment, _childNode)) -> segment = currentPath)

match childResults with
| None -> QueryTrieNodeResult.NodeDoesNotExist
| Some (KeyValue (_, childNode)) -> visit childNode restPath
match currentNode.Children.TryGetValue(currentPath) with
| false, _ -> QueryTrieNodeResult.NodeDoesNotExist
| true, childNode -> visit childNode restPath

visit trie path

Expand Down Expand Up @@ -91,7 +83,7 @@ let rec processStateEntry (queryTrie: QueryTrie) (state: FileContentQueryState)
// The extended path could add a new link (in case of a module or namespace with types)
// It might also not add anything at all (in case it the extended path is still a partial one)
(stateAfterFullOpenPath, state.OpenNamespaces)
||> Seq.fold (fun acc openNS -> processOpenPath queryTrie [ yield! openNS; yield! path ] acc)
||> Set.fold (fun acc openNS -> processOpenPath queryTrie [ yield! openNS; yield! path ] acc)

| FileContentEntry.PrefixedIdentifier path ->
match path with
Expand All @@ -101,14 +93,14 @@ let rec processStateEntry (queryTrie: QueryTrie) (state: FileContentQueryState)
| _ ->
// path could consist out of multiple segments
(state, [| 1 .. path.Length |])
||> Seq.fold (fun state takeParts ->
||> Array.fold (fun state takeParts ->
let path = List.take takeParts path
// process the name was if it were a FQN
let stateAfterFullIdentifier = processIdentifier queryTrie path state

// Process the name in combination with the existing open namespaces
(stateAfterFullIdentifier, state.OpenNamespaces)
||> Seq.fold (fun acc openNS -> processIdentifier queryTrie [ yield! openNS; yield! path ] acc))
||> Set.fold (fun acc openNS -> processIdentifier queryTrie [ yield! openNS; yield! path ] acc))

| FileContentEntry.NestedModule (nestedContent = nestedContent) ->
// We don't want our current state to be affect by any open statements in the nested module
Expand All @@ -133,32 +125,28 @@ let time msg f a =

/// Returns a list of all the files that child nodes contain
let indexesUnderNode (node: TrieNode) : Set<int> =
let rec collect (node: TrieNode) (continuation: int seq -> int seq) : int seq =
let continuations: ((int seq -> int seq) -> int seq) list =
node.Children
|> Seq.map (fun (KeyValue (_, node)) -> collect node)
|> Seq.toList
let rec collect (node: TrieNode) (continuation: int list -> int list) : int list =
let continuations: ((int list -> int list) -> int list) list =
[
for node in node.Children.Values do
yield collect node
]

let finalContinuation indexes =
continuation (
seq {
yield! node.Files
yield! Seq.collect id indexes
}
)
continuation [ yield! node.Files; yield! List.collect id indexes ]

Continuation.sequence continuations finalContinuation

Set.ofSeq (collect node id)
Set.ofList (collect node id)

/// A "ghost" dependency is a link between files that actually should be avoided.
/// The user has a partial namespace or opens a namespace that does not produce anything.
/// In order to still be able to compile the current file, the given namespace should be known to the file.
/// We did not find it via the trie, because there are no files that contribute to this namespace.
let collectGhostDependencies (fileIndex: int) (trie: TrieNode) (queryTrie: QueryTrie) (result: FileContentQueryState) =
// Go over all open namespaces, and assert all those links eventually went anywhere
result.OpenedNamespaces
|> Seq.collect (fun path ->
Set.toArray result.OpenedNamespaces
|> Array.collect (fun path ->
match queryTrie path with
| QueryTrieNodeResult.NodeExposesData _
| QueryTrieNodeResult.NodeDoesNotExist -> Array.empty
Expand Down Expand Up @@ -188,7 +176,6 @@ let collectGhostDependencies (fileIndex: int) (trie: TrieNode) (queryTrie: Query
else
// The partial open did eventually lead to a link in a file
Array.empty)
|> Seq.toArray

let mkGraph (files: FileWithAST array) =
// Implementation files backed by signatures should be excluded to construct the trie.
Expand Down Expand Up @@ -229,6 +216,7 @@ let mkGraph (files: FileWithAST array) =

// Process all entries of a file and query the trie when required to find the dependent files.
let result =
// Seq is faster than List in this case.
Seq.fold (processStateEntry queryTrie) (FileContentQueryState.Create file.Idx knownFiles) fileContent

// after processing the file we should verify if any of the open statements are found in the trie but do not yield any file link.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ open System.Collections.Generic
open FSharp.Compiler.Syntax
open Microsoft.FSharp.Collections

let mergeTrieNodes (defaultChildSize: int) (tries: TrieNode seq) =
let mergeTrieNodes (defaultChildSize: int) (tries: TrieNode array) =
let rec mergeTrieNodesAux (root: TrieNode) (KeyValue (k, v)) =
if root.Children.ContainsKey k then
let node = root.Children.[k]
Expand All @@ -22,7 +22,7 @@ let mergeTrieNodes (defaultChildSize: int) (tries: TrieNode seq) =
else
root.Children.Add(k, v)

match Seq.tryExactlyOne tries with
match Array.tryExactlyOne tries with
| Some singleTrie ->
assert (singleTrie.Current = TrieNodeInfo.Root)
singleTrie
Expand Down Expand Up @@ -118,6 +118,7 @@ let rec mkTrieNodeFor (file: FileWithAST) : TrieNode =
visit id longId

Some { Current = Root; Children = rootNode })
|> List.toArray
|> mergeTrieNodes contents.Length
| ParsedInput.ImplFile (ParsedImplFileInput (contents = contents)) ->
contents
Expand Down Expand Up @@ -189,6 +190,7 @@ let rec mkTrieNodeFor (file: FileWithAST) : TrieNode =
visit id longId

Some { Current = Root; Children = rootNode })
|> List.toArray
|> mergeTrieNodes contents.Length

and mkTrieForSynModuleDecl (fileIndex: int) (decl: SynModuleDecl) : KeyValuePair<string, TrieNode> option =
Expand Down

0 comments on commit 18657b1

Please sign in to comment.