2011-01-13 29 views
4

私はテンプレート言語を工夫しています。タグ、ディレクティブ、変数の3種類のトークンがあります。これらのトークンにはそれぞれ名前が付いていて、それらのトークンがかなりたくさんあります。それらも拡張性があります。名前空間dict?

名前の再利用を許可するために、名前空間を追加します。

今のところ、すべての変数はちょうどdictに格納されています。キーは変数名であり、値は変数値です。そうすれば、変数の値をすばやく取得できます。しかし、ドット表記を許可したい場合は、namespace.variable、これらの変数をどのようにして保存することができますか?そのような名前空間はオプションですか?名前空間が含まれている場合は、辞書はその名前空間だけをスキャンする必要があります。そうでなければ、すべての名前空間をスキャンすると思います。

これを行うコンテナはありますか?

+1

ネストされた名前空間は使用できますか? – Ani

+0

@Ani:何も石に設定されていません...それほど多くの作業がなければ、ネストした名前空間を許可したいと思います。 – mpen

答えて

2

シンボルデータを内部的に文字列辞書の辞書として構造化する必要があります。最上位辞書は名前空間用であり、各名前空間名の下の各辞書は、その名前空間内のすべての記号のコンテナです。

修飾されていないシンボルを検索することは、特定の順序で各名前空間のシンボルを検索することに過ぎません。 C#またはDelphiでは、順序は、宣言の逆の順序で名前空間がソースファイルの先頭に宣言された順序によって決定されます(最も新しいものが最初に検索されます)。

+0

ええ、私はそれをC#スタイルにしたいと思います。私はこのアプローチを試してみると思います。 – mpen

1

フレームワークのDictionary<TKey, TValue>ではなく、IDictionary<string, object>という独自の実装を作成できます。

外部的には、消費する方法に変更はありません。

内部では、Dictionary<string, Dictionary<string, object>>で構成されます。

あなたの辞書がキー"namespace.variable"と一致する値を求めているのであれば、内部的には、その文字列を分割キー「名前空間」とDictionary<string, Dictionary<string, object>>を取得し、キーのためにそのDictionary<string, object>に値を返します「変数」。

名前空間をオプションにするには、キーがstring.Emptyの1つのエントリが必要です。アイテムの追加または取得のいずれの場合でも、.が含まれていないキーが提供される場合は、キーstring.Emptyのエントリを使用します。

+0

String.Emptyの辞書ノードを使用して、オプションの名前空間をシミュレートすると、同じ名前が複数の名前空間に存在する場合に問題が発生します。私たちは名前の定義を所有しているので、すべての名前が名前空間に定義されていることを確認してから、オプションの非修飾トークンをシンボルテーブルのデータ構造そのものの特殊なケースではなく、 – dthorpe

+0

@dthorpe私は単に「オプション」を違った方法で解釈したと思います。私は、いくつかの変数が名前空間に関連付けられないことを意味しています。もう一度見て、私は最後の文で要件を見過ごしたことがわかります。 – Jay

1

私のソリューション:

クラス

public class NamespaceDictionary<T> : IDictionary<string, T> 
{ 
    private SortedDictionary<string, Dictionary<string, T>> _dict; 
    private const char _separator = '.'; 

    public NamespaceDictionary() 
    { 
     _dict = new SortedDictionary<string, Dictionary<string, T>>(); 
    } 

    public NamespaceDictionary(IEnumerable<KeyValuePair<string, T>> collection) 
     : this() 
    { 
     foreach (var item in collection) 
      Add(item); 
    } 

    #region Implementation of IEnumerable 

    public IEnumerator<KeyValuePair<string, T>> GetEnumerator() 
    { 
     return _dict.SelectMany(x => x.Value).GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 

    #endregion 

    private static Tuple<string, string> Split(string name) 
    { 
     int pos = name.LastIndexOf(_separator); 
     string ns = pos == -1 ? "" : name.Substring(0, pos); 
     string var = name.Substring(pos + 1); 
     return new Tuple<string, string>(ns, var); 
    } 

    #region Implementation of ICollection<KeyValuePair<string,TValue>> 

    public void Add(KeyValuePair<string, T> item) 
    { 
     Add(item.Key, item.Value); 
    } 

    public void Clear() 
    { 
     _dict.Clear(); 
    } 

    public bool Contains(KeyValuePair<string, T> item) 
    { 
     throw new NotImplementedException(); 
    } 

    public void CopyTo(KeyValuePair<string, T>[] array, int arrayIndex) 
    { 
     throw new NotImplementedException(); 
    } 

    public bool Remove(KeyValuePair<string, T> item) 
    { 
     return Remove(item.Key); 
    } 

    public int Count 
    { 
     get { return _dict.Sum(p => p.Value.Count); } 
    } 

    public bool IsReadOnly 
    { 
     get { return false; } 
    } 

    #endregion 

    #region Implementation of IDictionary<string,TValue> 

    public bool ContainsKey(string name) 
    { 
     var tuple = Split(name); 
     return ContainsKey(tuple.Item1, tuple.Item2); 
    } 

    public bool ContainsKey(string ns, string key) 
    { 
     if (ns == "") 
      return _dict.Any(pair => pair.Value.ContainsKey(key)); 
     return _dict.ContainsKey(ns) && _dict[ns].ContainsKey(key); 
    } 

    public void Add(string name, T value) 
    { 
     var tuple = Split(name); 
     Add(tuple.Item1, tuple.Item2, value); 
    } 

    public void Add(string ns, string key, T value) 
    { 
     if (!_dict.ContainsKey(ns)) 
      _dict[ns] = new Dictionary<string, T>(); 
     _dict[ns].Add(key, value); 
    } 

    public bool Remove(string ns, string key) 
    { 
     if (_dict.ContainsKey(ns) && _dict[ns].ContainsKey(key)) 
     { 
      if (_dict[ns].Count == 1) _dict.Remove(ns); 
      else _dict[ns].Remove(key); 
      return true; 
     } 
     return false; 
    } 

    public bool Remove(string key) 
    { 
     var tuple = Split(key); 
     return Remove(tuple.Item1, tuple.Item2); 
    } 

    public bool TryGetValue(string name, out T value) 
    { 
     var tuple = Split(name); 
     return TryGetValue(tuple.Item1, tuple.Item2, out value); 
    } 

    public bool TryGetValue(string ns, string key, out T value) 
    { 
     if (ns == "") 
     { 
      foreach (var pair in _dict) 
      { 
       if (pair.Value.ContainsKey(key)) 
       { 
        value = pair.Value[key]; 
        return true; 
       } 
      } 
     } 
     else if (_dict.ContainsKey(ns) && _dict[ns].ContainsKey(key)) 
     { 
      value = _dict[ns][key]; 
      return true; 
     } 
     value = default(T); 
     return false; 
    } 

    public T this[string ns, string key] 
    { 
     get 
     { 
      if (ns == "") 
      { 
       foreach (var pair in _dict) 
        if (pair.Value.ContainsKey(key)) 
         return pair.Value[key]; 
      } 
      else if (_dict.ContainsKey(ns) && _dict[ns].ContainsKey(key)) 
       return _dict[ns][key]; 
      throw new KeyNotFoundException(); 
     } 
     set 
     { 
      if (!_dict.ContainsKey(ns)) 
       _dict[ns] = new Dictionary<string, T>(); 
      _dict[ns][key] = value; 
     } 
    } 

    public T this[string name] 
    { 
     get 
     { 
      var tuple = Split(name); 
      return this[tuple.Item1, tuple.Item2]; 
     } 
     set 
     { 
      var tuple = Split(name); 
      this[tuple.Item1, tuple.Item2] = value; 
     } 
    } 

    public ICollection<string> Keys 
    { 
     get { return _dict.SelectMany(p => p.Value.Keys).ToArray(); } 
    } 

    public ICollection<T> Values 
    { 
     get { return _dict.SelectMany(p => p.Value.Values).ToArray(); } 
    } 

    #endregion 
} 

テスト

 var dict = new NamespaceDictionary<int>(); 
     dict.Add("ns1.var1", 1); 
     dict.Add("ns2.var1", 2); 
     dict.Add("var2", 3); 
     dict.Add("ns2.var2", 4); 
     dict.Add("ns3", "var1", 5); 
     dict["ns4.var1"] = 6; 
     Console.WriteLine(dict["var1"]); 
     Console.WriteLine(dict["ns2.var1"]); 
     Console.WriteLine(dict["var2"]); 
     Console.WriteLine(dict["ns2.var2"]); 
     Console.WriteLine(dict["ns2", "var2"]); 
     Console.WriteLine(dict["ns3.var1"]); 
     Console.WriteLine(dict["ns4", "var1"]); 

出力

ヘルプ

私はそれは名前空間が追加された順序を保持だろうと考えSortedDictionaryを使用しますが、それは実際にはアルファベット順に名前空間を並べ替えています。アイテムが追加された順序は保持されますが、並べ替えられないdictクラスはありますか?

+1

独自の並べ替えlamba式を提供し、挿入時の位置を追跡し、ソート関数として使用することができます – Sebastian

+0

文字列キーをカスタムデータ型に置き換える必要がありますか?そして、すべてを包んで、うーん! – mpen

+1

または、2つのリストを維持してください:名前による高速検索のための1つの辞書と、挿入順の高速検索のための1つのリスト。 – dthorpe