mirror of
https://github.com/twiglet/cs2j.git
synced 2025-01-18 13:15:17 +01:00
Upgrade DirectoryHT to support variants at the leaves
This commit is contained in:
parent
1001d5151f
commit
f2a3c580da
@ -6,6 +6,26 @@ using System;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
DirectoryHT is a dictionary, designed to model C#'s class name space.
|
||||||
|
|
||||||
|
Keys are dot separated strings (e.g. System.IO.TextWriter). The value stored has
|
||||||
|
a parameterized type (in CS2J we are storing TypeRepTemplates).
|
||||||
|
|
||||||
|
Each Key can point to a list of possible values, indexed by variant.
|
||||||
|
|
||||||
|
Valid variants are stored in the Alts property. The Alts are ordered by priority,
|
||||||
|
lowest to highest. We return the value with highest priority variant.
|
||||||
|
|
||||||
|
There is a default variant (with variant specified by the Default property). This is
|
||||||
|
always valid and has lowest ptiority.
|
||||||
|
|
||||||
|
Default Default (ahem!) is the empty string.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
namespace Twiglet.CS2J.Translator.Utils
|
namespace Twiglet.CS2J.Translator.Utils
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -13,18 +33,28 @@ namespace Twiglet.CS2J.Translator.Utils
|
|||||||
public class DirectoryHT<TValue> : IDictionary<string, TValue>
|
public class DirectoryHT<TValue> : IDictionary<string, TValue>
|
||||||
{
|
{
|
||||||
|
|
||||||
private DirectoryHT<TValue> _parent = null;
|
private DirectoryHT<TValue> parent = null;
|
||||||
|
|
||||||
private Dictionary<string, TValue> leaves = new Dictionary<string, TValue>();
|
// Leaves are a dictionary from Variant to Entry
|
||||||
|
private Dictionary<string, Dictionary<string, TValue>> leaves = new Dictionary<string, Dictionary<string, TValue>>();
|
||||||
|
|
||||||
|
// Children point to sub directories.
|
||||||
private Dictionary<string, DirectoryHT<TValue>> children = new Dictionary<string, DirectoryHT<TValue>>();
|
private Dictionary<string, DirectoryHT<TValue>> children = new Dictionary<string, DirectoryHT<TValue>>();
|
||||||
|
|
||||||
|
// The enabled Variants, in priority order.
|
||||||
private IList<string> alts = new List<string>();
|
private IList<string> alts = new List<string>();
|
||||||
|
|
||||||
|
// Default Variant (always enabled)
|
||||||
|
private string _default = String.Empty;
|
||||||
|
|
||||||
public DirectoryHT(DirectoryHT<TValue> p)
|
public DirectoryHT(DirectoryHT<TValue> p)
|
||||||
{
|
{
|
||||||
_parent = p;
|
parent = p;
|
||||||
alts.Add("");
|
if (p != null)
|
||||||
|
{
|
||||||
|
Default = p.Default;
|
||||||
|
Alts = p.Alts;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DirectoryHT()
|
public DirectoryHT()
|
||||||
@ -32,7 +62,7 @@ namespace Twiglet.CS2J.Translator.Utils
|
|||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
||||||
public Dictionary<string, TValue> Leaves
|
public Dictionary<string, Dictionary<string, TValue>> Leaves
|
||||||
{
|
{
|
||||||
get { return leaves; }
|
get { return leaves; }
|
||||||
}
|
}
|
||||||
@ -40,14 +70,36 @@ namespace Twiglet.CS2J.Translator.Utils
|
|||||||
// p is key to a sub directory
|
// p is key to a sub directory
|
||||||
public DirectoryHT<TValue> Parent
|
public DirectoryHT<TValue> Parent
|
||||||
{
|
{
|
||||||
get { return _parent; }
|
get { return parent; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// When searching for A.B.C.D.E we will first search for each A.B.C.D.<alt>.E where <alt> comes from Alts
|
// When looking for A.B.C.D.E We get a dictionary of variants. We will first look for each
|
||||||
|
// variant in Alts before falling back on the default (variant = Default)
|
||||||
// This allows to override the default translations where necessary
|
// This allows to override the default translations where necessary
|
||||||
|
// Alts appearing later in the list have priority.
|
||||||
public IList<string> Alts
|
public IList<string> Alts
|
||||||
{
|
{
|
||||||
get { return alts; }
|
get { return alts; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
alts = value;
|
||||||
|
foreach (KeyValuePair<string, DirectoryHT<TValue>> child in children)
|
||||||
|
child.Value.Alts = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Default
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _default;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_default = value;
|
||||||
|
foreach (KeyValuePair<string,DirectoryHT<TValue>> child in children)
|
||||||
|
child.Value.Default = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// p is key to a sub directory
|
// p is key to a sub directory
|
||||||
@ -65,14 +117,49 @@ namespace Twiglet.CS2J.Translator.Utils
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool hasLeaf(Dictionary<string,TValue> variants)
|
||||||
|
{
|
||||||
|
if (variants == null)
|
||||||
|
return false;
|
||||||
|
if (variants.ContainsKey(Default))
|
||||||
|
return true;
|
||||||
|
foreach (string alt in Alts)
|
||||||
|
{
|
||||||
|
if (variants.ContainsKey(alt))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TValue getLeaf(Dictionary<string,TValue> variants)
|
||||||
|
{
|
||||||
|
return getLeaf(variants, default(TValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
private TValue getLeaf(Dictionary<string,TValue> variants, TValue def)
|
||||||
|
{
|
||||||
|
if (variants == null)
|
||||||
|
return def;
|
||||||
|
for (int i = Alts.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (variants.ContainsKey(Alts[i]))
|
||||||
|
return variants[Alts[i]];
|
||||||
|
}
|
||||||
|
if (variants.ContainsKey(Default))
|
||||||
|
return variants[Default];
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
#region IDictionary Members
|
#region IDictionary Members
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public bool ContainsKey(string key)
|
public bool ContainsKey(string key)
|
||||||
{
|
{
|
||||||
string[] components = key.Split(new char[] { '.' }, 2);
|
string[] components = key.Split(new char[] { '.' }, 2);
|
||||||
if (components.Length == 1)
|
if (components.Length == 1)
|
||||||
{
|
{
|
||||||
return leaves.ContainsKey(components[0]);
|
return leaves.ContainsKey(components[0]) ? hasLeaf(leaves[components[0]]) : false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -111,7 +198,10 @@ namespace Twiglet.CS2J.Translator.Utils
|
|||||||
{
|
{
|
||||||
List<string> keys = new List<string>();
|
List<string> keys = new List<string>();
|
||||||
foreach (string k in leaves.Keys)
|
foreach (string k in leaves.Keys)
|
||||||
keys.Add(k);
|
{
|
||||||
|
if (hasLeaf(leaves[k]))
|
||||||
|
keys.Add(k);
|
||||||
|
}
|
||||||
foreach (KeyValuePair<string, DirectoryHT<TValue>> de in children)
|
foreach (KeyValuePair<string, DirectoryHT<TValue>> de in children)
|
||||||
foreach (string k in de.Value.Keys)
|
foreach (string k in de.Value.Keys)
|
||||||
keys.Add(de.Key + "." + k);
|
keys.Add(de.Key + "." + k);
|
||||||
@ -128,7 +218,14 @@ namespace Twiglet.CS2J.Translator.Utils
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return children[components[0]].Remove(components[1]);
|
if (children.ContainsKey(components[0]))
|
||||||
|
{
|
||||||
|
return children[components[0]].Remove(components[1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,8 +235,13 @@ namespace Twiglet.CS2J.Translator.Utils
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
List<TValue> vals = new List<TValue>();
|
List<TValue> vals = new List<TValue>();
|
||||||
foreach (TValue v in leaves.Values)
|
foreach (Dictionary<string,TValue> variants in leaves.Values)
|
||||||
vals.Add(v);
|
{
|
||||||
|
if (hasLeaf(variants))
|
||||||
|
{
|
||||||
|
vals.Add(getLeaf(variants));
|
||||||
|
}
|
||||||
|
}
|
||||||
foreach (KeyValuePair<string, DirectoryHT<TValue>> de in children)
|
foreach (KeyValuePair<string, DirectoryHT<TValue>> de in children)
|
||||||
foreach (TValue v in de.Value.Values)
|
foreach (TValue v in de.Value.Values)
|
||||||
vals.Add(v);
|
vals.Add(v);
|
||||||
@ -155,9 +257,14 @@ namespace Twiglet.CS2J.Translator.Utils
|
|||||||
string[] components = key.Split(new char[] { '.' }, 2);
|
string[] components = key.Split(new char[] { '.' }, 2);
|
||||||
if (components.Length == 1)
|
if (components.Length == 1)
|
||||||
{
|
{
|
||||||
TValue val = leaves[key];
|
if (leaves.ContainsKey(key) && hasLeaf(leaves[key]))
|
||||||
// keving: this isn't typesafe!: return (val != null ? val : children[components[0]]);
|
{
|
||||||
return val;
|
return getLeaf(leaves[key]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new KeyNotFoundException(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -170,25 +277,27 @@ namespace Twiglet.CS2J.Translator.Utils
|
|||||||
Add(key, value);
|
Add(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetValue(string key, out TValue value)
|
public bool TryGetValue(string key, out TValue value)
|
||||||
{
|
{
|
||||||
string[] components = key.Split(new char[] { '.' }, 2);
|
string[] components = key.Split(new char[] { '.' }, 2);
|
||||||
if (components.Length == 1)
|
if (components.Length == 1)
|
||||||
{
|
{
|
||||||
return leaves.TryGetValue(key, out value);
|
if (leaves.ContainsKey(components[0]) && hasLeaf(leaves[components[0]]))
|
||||||
|
{
|
||||||
|
value = getLeaf(leaves[components[0]]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (children.ContainsKey(components[0]))
|
if (children.ContainsKey(components[0]))
|
||||||
{
|
{
|
||||||
return children[components[0]].TryGetValue(components[1], out value);
|
return children[components[0]].TryGetValue(components[1], out value);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
value = default(TValue);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
value = default(TValue);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// search for name, given searchPath
|
// search for name, given searchPath
|
||||||
@ -198,54 +307,28 @@ namespace Twiglet.CS2J.Translator.Utils
|
|||||||
// This allows to override the default translations where necessary
|
// This allows to override the default translations where necessary
|
||||||
public TValue Search(IList<string> searchPath, string name, TValue def) {
|
public TValue Search(IList<string> searchPath, string name, TValue def) {
|
||||||
|
|
||||||
|
bool doneGlobal = false;
|
||||||
// First check against each element of the search path
|
// First check against each element of the search path
|
||||||
if (searchPath != null)
|
if (searchPath != null)
|
||||||
{
|
{
|
||||||
// check against each alt override in turn
|
|
||||||
foreach (string altIterator in Alts) {
|
|
||||||
string alt = altIterator.EndsWith(".") ? altIterator : altIterator + ".";
|
|
||||||
|
|
||||||
for (int i = searchPath.Count-1; i >= 0; i--) {
|
|
||||||
String ns = searchPath[i];
|
|
||||||
String fullName = (ns ?? "") + (String.IsNullOrEmpty(ns) ? "" : ".") + name;
|
|
||||||
// insert alt after last period
|
|
||||||
int lastPeriod = fullName.LastIndexOf('.')+1;
|
|
||||||
fullName = fullName.Substring(0,lastPeriod) + alt + fullName.Substring(lastPeriod);
|
|
||||||
// Console.WriteLine(fullName);
|
|
||||||
if (this.ContainsKey(fullName)) {
|
|
||||||
return this[fullName];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not in alts, check kosher
|
|
||||||
for (int i = searchPath.Count-1; i >= 0; i--) {
|
for (int i = searchPath.Count-1; i >= 0; i--) {
|
||||||
String ns = searchPath[i];
|
String ns = searchPath[i];
|
||||||
|
if (String.IsNullOrEmpty(ns))
|
||||||
|
doneGlobal = true;
|
||||||
String fullName = (ns ?? "") + (String.IsNullOrEmpty(ns) ? "" : ".") + name;
|
String fullName = (ns ?? "") + (String.IsNullOrEmpty(ns) ? "" : ".") + name;
|
||||||
// Console.WriteLine(fullName);
|
|
||||||
if (this.ContainsKey(fullName)) {
|
if (this.ContainsKey(fullName)) {
|
||||||
return this[fullName];
|
return this[fullName];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Not in search path, check for fully qualified name
|
||||||
// Check if name is fully qualified
|
if (!doneGlobal)
|
||||||
foreach (string altIterator in Alts) {
|
{
|
||||||
string alt = altIterator.EndsWith(".") ? altIterator : altIterator + ".";
|
if (this.ContainsKey(name)) {
|
||||||
// insert alt after last period
|
return this[name];
|
||||||
int lastPeriod = name.LastIndexOf('.')+1;
|
|
||||||
string fullName = name.Substring(0,lastPeriod) + alt + name.Substring(lastPeriod);
|
|
||||||
// Console.WriteLine(fullName);
|
|
||||||
if (this.ContainsKey(fullName)) {
|
|
||||||
return this[fullName];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Not found *anywhere*!
|
||||||
// Not in alt, check kosher
|
|
||||||
// Console.WriteLine(name);
|
|
||||||
if (this.ContainsKey(name)) {
|
|
||||||
return this[name];
|
|
||||||
}
|
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,11 +346,6 @@ namespace Twiglet.CS2J.Translator.Utils
|
|||||||
return Search(new List<string>(), name, def);
|
return Search(new List<string>(), name, def);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(KeyValuePair<string, TValue> item)
|
|
||||||
{
|
|
||||||
this.Add(item.Key, item.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains(KeyValuePair<string, TValue> item)
|
public bool Contains(KeyValuePair<string, TValue> item)
|
||||||
{
|
{
|
||||||
TValue value;
|
TValue value;
|
||||||
@ -290,18 +368,32 @@ namespace Twiglet.CS2J.Translator.Utils
|
|||||||
Copy(this, array, arrayIndex);
|
Copy(this, array, arrayIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Add(KeyValuePair<string, TValue> item)
|
||||||
|
{
|
||||||
|
Add(item.Key, item.Value);
|
||||||
|
}
|
||||||
|
|
||||||
public void Add(string key, TValue value)
|
public void Add(string key, TValue value)
|
||||||
|
{
|
||||||
|
Add(key, value, Default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(string key, TValue value, string variant)
|
||||||
{
|
{
|
||||||
string[] components = key.Split(new char[] { '.' }, 2);
|
string[] components = key.Split(new char[] { '.' }, 2);
|
||||||
if (components.Length == 1)
|
if (components.Length == 1)
|
||||||
{
|
{
|
||||||
leaves[components[0]] = value;
|
if (!leaves.ContainsKey(components[0]))
|
||||||
|
{
|
||||||
|
leaves[components[0]] = new Dictionary<string, TValue>();
|
||||||
|
}
|
||||||
|
leaves[components[0]][variant] = value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!children.ContainsKey(components[0]))
|
if (!children.ContainsKey(components[0]))
|
||||||
children[components[0]] = new DirectoryHT<TValue>(this);
|
children[components[0]] = new DirectoryHT<TValue>(this);
|
||||||
children[components[0]].Add(components[1], value);
|
children[components[0]].Add(components[1], value, variant);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,9 +406,12 @@ namespace Twiglet.CS2J.Translator.Utils
|
|||||||
yield return new KeyValuePair<string, TValue>(de.Key + "." + cur.Key, cur.Value);
|
yield return new KeyValuePair<string, TValue>(de.Key + "." + cur.Key, cur.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (KeyValuePair<string, TValue> de in leaves)
|
foreach (KeyValuePair<string, Dictionary<string, TValue>> de in leaves)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<string, TValue>(de.Key, de.Value);
|
if (hasLeaf(de.Value))
|
||||||
|
{
|
||||||
|
yield return new KeyValuePair<string, TValue>(de.Key, getLeaf(de.Value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user