summaryrefslogtreecommitdiffstats
path: root/tools/Sandcastle/Source/BuildAssembler/BuildComponents/IndexedFileCache.cs
diff options
context:
space:
mode:
Diffstat (limited to 'tools/Sandcastle/Source/BuildAssembler/BuildComponents/IndexedFileCache.cs')
-rw-r--r--tools/Sandcastle/Source/BuildAssembler/BuildComponents/IndexedFileCache.cs189
1 files changed, 189 insertions, 0 deletions
diff --git a/tools/Sandcastle/Source/BuildAssembler/BuildComponents/IndexedFileCache.cs b/tools/Sandcastle/Source/BuildAssembler/BuildComponents/IndexedFileCache.cs
new file mode 100644
index 0000000..62425d8
--- /dev/null
+++ b/tools/Sandcastle/Source/BuildAssembler/BuildComponents/IndexedFileCache.cs
@@ -0,0 +1,189 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Xml;
+using System.Xml.XPath;
+
+namespace Microsoft.Ddue.Tools
+{
+ // the storage system
+
+ internal class IndexedFileCache
+ {
+
+ public IndexedFileCache(string keyXPath, string valueXPath, int cacheSize)
+ {
+ valueExpression = XPathExpression.Compile(valueXPath);
+
+ keyExpression = XPathExpression.Compile(keyXPath);
+
+ _cacheSize = cacheSize;
+
+ cache = new Dictionary<string, IndexedFile>(_cacheSize);
+
+ lruLinkedList = new LinkedList<string>();
+ }
+
+ // search pattern for value nodes to be mapped
+ private XPathExpression valueExpression;
+
+ // search pattern for the key identifier (relative to the value node)
+ private XPathExpression keyExpression;
+
+ // an index mapping topic IDs to files
+ private Dictionary<string, string> idToFileMap = new Dictionary<string, string>();
+
+ public int ParseDocuments(string wildcardPath)
+ {
+ string directoryPart = Path.GetDirectoryName(wildcardPath);
+ if (String.IsNullOrEmpty(directoryPart)) directoryPart = Environment.CurrentDirectory;
+ directoryPart = Path.GetFullPath(directoryPart);
+ string filePart = Path.GetFileName(wildcardPath);
+ string[] files = Directory.GetFiles(directoryPart, filePart);
+ // WriteMessage(MessageLevel.Info, String.Format("Found {0} files.", files.Length) );
+ foreach (string file in files)
+ {
+ ParseDocument(file);
+ }
+ return (files.Length);
+ }
+
+ private void ParseDocument(string file)
+ {
+ try
+ {
+ XPathDocument document = new XPathDocument(file);
+ XPathNodeIterator valueNodes = document.CreateNavigator().Select(valueExpression);
+ foreach (XPathNavigator valueNode in valueNodes)
+ {
+ XPathNavigator keyNode = valueNode.SelectSingleNode(keyExpression);
+ if (keyNode == null) continue;
+ string key = keyNode.Value;
+
+ // log multiple occurences of a single id
+ if (idToFileMap.ContainsKey(key))
+ {
+ // WriteMessage(MessageLevel.Warn, String.Format("Entries for the key '{0}' occur in both '{1}' and '{2}'. The first entry will be used.", key, idToFileMap[key], file));
+ }
+ else
+ {
+ idToFileMap[key] = file;
+ }
+ }
+ }
+ catch (XmlException)
+ {
+ // WriteMessage(MessageLevel.Error, e.Message);
+ }
+ }
+
+ // a simple document caching mechanism
+
+ private int _cacheSize = 10;
+
+ private LinkedList<String> lruLinkedList;
+
+ private Dictionary<string, IndexedFile> cache;
+
+
+ private IndexedFile GetCachedDocument(string identifier)
+ {
+ string file;
+ if (idToFileMap.TryGetValue(identifier, out file))
+ {
+ IndexedFile document;
+ if (cache.TryGetValue(file, out document))
+ {
+ // move the file from its current position to the head of the lru linked list
+ lruLinkedList.Remove(document.ListNode);
+ lruLinkedList.AddFirst(document.ListNode);
+ }
+ else
+ {
+ // not in the cache, so load and index a new source file
+ document = new IndexedFile(file, valueExpression, keyExpression);
+ if (cache.Count >= _cacheSize)
+ {
+ // the cache is full
+ // the last node in the linked list has the path of the next file to remove from the cache
+ if (lruLinkedList.Last != null)
+ {
+ cache.Remove(lruLinkedList.Last.Value);
+ lruLinkedList.RemoveLast();
+ }
+ }
+ // add the new file to the cache and to the head of the lru linked list
+ cache.Add(file, document);
+ document.ListNode = lruLinkedList.AddFirst(file);
+ }
+ return (document);
+ }
+ else
+ {
+ return (null);
+ }
+ }
+
+ public XPathNavigator GetContent(string identifier)
+ {
+
+ // get the document containing the identifier
+ IndexedFile document = GetCachedDocument(identifier);
+ if (document == null) return (null);
+
+ // select the comment part of the document
+ return document.GetContent(identifier);
+ }
+
+ public int Count
+ {
+ get
+ {
+ return (idToFileMap.Count);
+ }
+ }
+
+ }
+
+ internal class IndexedFile
+ {
+ Dictionary<string, XPathNavigator> valueIndex = new Dictionary<string, XPathNavigator>();
+
+ public IndexedFile(string filepath, XPathExpression valueExpression, XPathExpression keyExpression)
+ {
+ XPathDocument xpDoc = new XPathDocument(filepath);
+ XPathNodeIterator valueNodes = xpDoc.CreateNavigator().Select(valueExpression);
+ foreach (XPathNavigator valueNode in valueNodes)
+ {
+ XPathNavigator keyNode = valueNode.SelectSingleNode(keyExpression);
+ if (keyNode == null)
+ continue;
+ string key = keyNode.Value;
+ if (!valueIndex.ContainsKey(key))
+ valueIndex.Add(key, valueNode);
+ }
+ }
+
+ public XPathNavigator GetContent(string key)
+ {
+ return valueIndex[key];
+ }
+
+ private LinkedListNode<string> listNode;
+ public LinkedListNode<string> ListNode
+ {
+ get
+ {
+ return (listNode);
+ }
+ set
+ {
+ listNode = value;
+ }
+ }
+
+ }
+
+}