Changed the format of how the parsed configuration file is stored in memory - lines are now part of the categories, avoiding a costly scan over the whole array if lines are added to a category in the middle
git-svn-id: file:///srv/devel/repo-conversion/nusu@304 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
parent
0753aeb220
commit
73a17b7a3e
|
@ -70,7 +70,6 @@ namespace Nuclex.Support.Settings {
|
||||||
/// <param name="state">Current parser state</param>
|
/// <param name="state">Current parser state</param>
|
||||||
/// <param name="line">Line that has been read</param>
|
/// <param name="line">Line that has been read</param>
|
||||||
private static void parseLine(ParserState state, string line) {
|
private static void parseLine(ParserState state, string line) {
|
||||||
state.Store.lines.Add(line);
|
|
||||||
|
|
||||||
// If the line is empty, ignore it
|
// If the line is empty, ignore it
|
||||||
int length = line.Length;
|
int length = line.Length;
|
||||||
|
@ -98,6 +97,8 @@ namespace Nuclex.Support.Settings {
|
||||||
} else {
|
} else {
|
||||||
parseOption(state, line, firstCharacterIndex);
|
parseOption(state, line, firstCharacterIndex);
|
||||||
}
|
}
|
||||||
|
state.Category.Lines.Add(line);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Parses a category definition encountered on a line</summary>
|
/// <summary>Parses a category definition encountered on a line</summary>
|
||||||
|
@ -130,13 +131,12 @@ namespace Nuclex.Support.Settings {
|
||||||
// Now we know that the line holds a category definition and where exactly in
|
// Now we know that the line holds a category definition and where exactly in
|
||||||
// the line the category name is located. Create the category.
|
// the line the category name is located. Create the category.
|
||||||
state.Category = new Category() {
|
state.Category = new Category() {
|
||||||
LineIndex = state.Store.lines.Count - 1,
|
|
||||||
CategoryName = new StringSegment(
|
CategoryName = new StringSegment(
|
||||||
line, nameStartIndex, nameEndIndex - nameStartIndex + 1
|
line, nameStartIndex, nameEndIndex - nameStartIndex + 1
|
||||||
),
|
),
|
||||||
OptionLookup = new Dictionary<string, Option>()
|
OptionLookup = new Dictionary<string, Option>(),
|
||||||
|
Lines = new List<string>()
|
||||||
};
|
};
|
||||||
state.Store.categories.Add(state.Category);
|
|
||||||
state.Store.categoryLookup.Add(state.Category.CategoryName.ToString(), state.Category);
|
state.Store.categoryLookup.Add(state.Category.CategoryName.ToString(), state.Category);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ namespace Nuclex.Support.Settings {
|
||||||
|
|
||||||
// We have enough information to know that this is an assignment of some kind
|
// We have enough information to know that this is an assignment of some kind
|
||||||
Option option = new Option() {
|
Option option = new Option() {
|
||||||
LineIndex = state.Store.lines.Count - 1,
|
LineIndex = state.Category.Lines.Count - 1,
|
||||||
OptionName = new StringSegment(
|
OptionName = new StringSegment(
|
||||||
line, firstCharacterIndex, nameEndIndex - firstCharacterIndex + 1
|
line, firstCharacterIndex, nameEndIndex - firstCharacterIndex + 1
|
||||||
)
|
)
|
||||||
|
|
|
@ -209,6 +209,17 @@ namespace Nuclex.Support.Settings {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verifies that options can be added to the configuration file
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void OptionsCanBeAdded() {
|
||||||
|
var configurationFile = new ConfigurationFileStore();
|
||||||
|
|
||||||
|
configurationFile.Set<string>(null, "test", "123");
|
||||||
|
Assert.That(configurationFile.Get<string>(null, "test"), Is.EqualTo("123"));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Nuclex.Support.Settings
|
} // namespace Nuclex.Support.Settings
|
||||||
|
|
|
@ -37,15 +37,15 @@ namespace Nuclex.Support.Settings {
|
||||||
/// <summary>Stores informations about a category found in the configuration file</summary>
|
/// <summary>Stores informations about a category found in the configuration file</summary>
|
||||||
private class Category {
|
private class Category {
|
||||||
|
|
||||||
/// <summary>Index of the line the category is defined in</summary>
|
|
||||||
public int LineIndex;
|
|
||||||
|
|
||||||
/// <summary>Name of the category as a string</summary>
|
/// <summary>Name of the category as a string</summary>
|
||||||
public StringSegment CategoryName;
|
public StringSegment CategoryName;
|
||||||
|
|
||||||
/// <summary>Lookup table for the options in this category</summary>
|
/// <summary>Lookup table for the options in this category</summary>
|
||||||
public IDictionary<string, Option> OptionLookup;
|
public IDictionary<string, Option> OptionLookup;
|
||||||
|
|
||||||
|
/// <summary>Lines this category and its options consist of</summary>
|
||||||
|
public IList<string> Lines;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion // class Category
|
#endregion // class Category
|
||||||
|
@ -70,30 +70,31 @@ namespace Nuclex.Support.Settings {
|
||||||
|
|
||||||
/// <summary>Initializes a new, empty configuration file</summary>
|
/// <summary>Initializes a new, empty configuration file</summary>
|
||||||
public ConfigurationFileStore() {
|
public ConfigurationFileStore() {
|
||||||
this.lines = new List<string>();
|
|
||||||
this.categories = new List<Category>();
|
|
||||||
this.options = new List<Option>();
|
this.options = new List<Option>();
|
||||||
this.categoryLookup = new Dictionary<string, Category>();
|
this.categoryLookup = new Dictionary<string, Category>();
|
||||||
this.RootCategory = new Category() {
|
this.RootCategory = new Category() {
|
||||||
LineIndex = -1,
|
OptionLookup = new Dictionary<string, Option>(),
|
||||||
OptionLookup = new Dictionary<string, Option>()
|
Lines = new List<string>()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Saves the configuration file into the specified writer</summary>
|
/// <summary>Saves the configuration file into the specified writer</summary>
|
||||||
/// <param name="writer">Writer the configuration file will be saved into</param>
|
/// <param name="writer">Writer the configuration file will be saved into</param>
|
||||||
public void Save(TextWriter writer) {
|
public void Save(TextWriter writer) {
|
||||||
for(int index = 0; index < this.lines.Count; ++index) {
|
for(int index = 0; index < this.RootCategory.Lines.Count; ++index) {
|
||||||
writer.WriteLine(this.lines[index]);
|
writer.WriteLine(this.RootCategory.Lines[index]);
|
||||||
|
}
|
||||||
|
foreach(Category category in this.categoryLookup.Values) {
|
||||||
|
for(int index = 0; index < category.Lines.Count; ++index) {
|
||||||
|
writer.WriteLine(category.Lines[index]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Enumerates the categories defined in the configuration</summary>
|
/// <summary>Enumerates the categories defined in the configuration</summary>
|
||||||
/// <returns>An enumerable list of all used categories</returns>
|
/// <returns>An enumerable list of all used categories</returns>
|
||||||
public IEnumerable<string> EnumerateCategories() {
|
public IEnumerable<string> EnumerateCategories() {
|
||||||
for(int index = 0; index < this.categories.Count; ++index) {
|
return this.categoryLookup.Keys;
|
||||||
yield return this.categories[index].CategoryName.ToString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Enumerates the options stored under the specified category</summary>
|
/// <summary>Enumerates the options stored under the specified category</summary>
|
||||||
|
@ -242,18 +243,29 @@ namespace Nuclex.Support.Settings {
|
||||||
}
|
}
|
||||||
|
|
||||||
Option newOption = new Option() {
|
Option newOption = new Option() {
|
||||||
LineIndex = this.lines.Count,
|
|
||||||
OptionName = new StringSegment(line, 0, name.Length),
|
OptionName = new StringSegment(line, 0, name.Length),
|
||||||
OptionValue = new StringSegment(line, name.Length + 3, valueLength)
|
OptionValue = new StringSegment(line, name.Length + 3, valueLength)
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Find end line of category and add line
|
// Figure out which line the new option should be put in
|
||||||
|
int lastLineIndex = category.Lines.Count - 1;
|
||||||
|
if((lastLineIndex > 0) && (category.Lines[lastLineIndex].Length == 0)) {
|
||||||
|
newOption.LineIndex = lastLineIndex;
|
||||||
|
category.Lines.Insert(lastLineIndex, line);
|
||||||
|
} else {
|
||||||
|
newOption.LineIndex = category.Lines.Count;
|
||||||
|
category.Lines.Add(line);
|
||||||
|
category.Lines.Add(string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
category.OptionLookup.Add(name, newOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Changes the value of an option</summary>
|
/// <summary>Changes the value of an option</summary>
|
||||||
|
/// <param name="category">Category that holds the option</param>
|
||||||
/// <param name="option">Option whose value will be changed</param>
|
/// <param name="option">Option whose value will be changed</param>
|
||||||
/// <param name="newValue">New value that will be assigned to the option</param>
|
/// <param name="newValue">New value that will be assigned to the option</param>
|
||||||
private void changeOption(Option option, string newValue) {
|
private void changeOption(Category category, Option option, string newValue) {
|
||||||
int newValueLength;
|
int newValueLength;
|
||||||
if(newValue == null) {
|
if(newValue == null) {
|
||||||
newValueLength = 0;
|
newValueLength = 0;
|
||||||
|
@ -287,8 +299,8 @@ namespace Nuclex.Support.Settings {
|
||||||
line = builder.ToString();
|
line = builder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.lines[option.LineIndex] = line;
|
|
||||||
option.OptionValue = new StringSegment(line, option.OptionValue.Offset, newValueLength);
|
option.OptionValue = new StringSegment(line, option.OptionValue.Offset, newValueLength);
|
||||||
|
category.Lines[option.LineIndex] = line;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Creates a new category in the configuration file</summary>
|
/// <summary>Creates a new category in the configuration file</summary>
|
||||||
|
@ -304,26 +316,20 @@ namespace Nuclex.Support.Settings {
|
||||||
categoryDefinition = builder.ToString();
|
categoryDefinition = builder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// An empty line before the category definition for better readability
|
|
||||||
this.lines.Add(string.Empty);
|
|
||||||
|
|
||||||
Category newCategory = new Category() {
|
Category newCategory = new Category() {
|
||||||
LineIndex = this.lines.Count,
|
|
||||||
CategoryName = new StringSegment(categoryDefinition, 1, category.Length),
|
CategoryName = new StringSegment(categoryDefinition, 1, category.Length),
|
||||||
OptionLookup = new Dictionary<string, Option>()
|
OptionLookup = new Dictionary<string, Option>(),
|
||||||
|
Lines = new List<string>()
|
||||||
};
|
};
|
||||||
this.lines.Add(categoryDefinition);
|
|
||||||
|
newCategory.Lines.Add(categoryDefinition);
|
||||||
|
newCategory.Lines.Add(string.Empty);
|
||||||
|
|
||||||
this.categoryLookup.Add(category, newCategory);
|
this.categoryLookup.Add(category, newCategory);
|
||||||
|
|
||||||
return newCategory;
|
return newCategory;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Lines contained in the configuration file</summary>
|
|
||||||
private IList<string> lines;
|
|
||||||
|
|
||||||
/// <summary>Records where categories are stored in the configuration file</summary>
|
|
||||||
private IList<Category> categories;
|
|
||||||
/// <summary>Records where options are stored in the configuration file</summary>
|
/// <summary>Records where options are stored in the configuration file</summary>
|
||||||
private IList<Option> options;
|
private IList<Option> options;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user