Project

General

Profile

root / branches / compiler / cSharp / ooasCompiler / src / libs / c5 / UserGuideExamples / IndexedObjects.cs @ 3

1
/*
2
 Copyright (c) 2003-2007 Niels Kokholm and Peter Sestoft
3
*/
4

    
5
// IndexedObjects.cs sketch 2007-07-26 
6

    
7
// Other approaches: Define an Indexed<T> class to which indexers can
8
// be attached.  An object can add (or remove) itself to the indexers
9
// that are attached to the Indexed class at the time of addition (or
10
// removal).
11

    
12
// Maintaining multiple indices on objects, each index defined by a
13
// delegate.
14

    
15
// Compile with 
16
//   csc /r:C5.dll IndexedObjects.cs 
17

    
18
using System;                           // Console
19
using System.Text;                      // StringBuilder
20
using C5; 
21
using SCG = System.Collections.Generic;
22

    
23
namespace IndexedObjects {
24
  static class IndexedObjectsMain {
25
    static void Main(String[] args) {
26
      Indexed<Person> persons 
27
        = new Indexed<Person>
28
        (new IndexMaker<Person,String>
29
         ("name", delegate(Person p) { return p.name; }),
30
         new IndexMaker<Person,int>
31
         ("year", delegate(Person p) { return p.date/10000; }),
32
         new IndexMaker<Person,int>
33
         ("day", delegate(Person p) { return p.date%100; }),
34
         new IndexMaker<Person,String>
35
         ("month", delegate(Person p) { return months[p.date/100%100-1]; })
36
         );
37
      persons.Add(new Person("Niels",   19470206));
38
      persons.Add(new Person("Lone",    19600810));
39
      persons.Add(new Person("Peter",   19620625));
40
      persons.Add(new Person("Carsten", 19640627));
41
      persons.Add(new Person("Hanne",   19641209));
42
      persons.Add(new Person("Dorte",   19660930));
43
      persons.Add(new Person("Dorte",   19610312));
44
      persons.Add(new Person("J?rgen",  19340930));
45
      persons.Add(new Person("Kirsten", 19360114));
46
      persons.Add(new Person("Henrik",  19360630));
47
      persons.Add(new Person("Lars",    19640625));
48
      persons.Add(new Person("Thora",   19091129));
49
      Console.WriteLine("Born in 1964:");
50
      foreach (Person p in persons["year"][1964]) 
51
        Console.WriteLine(p);
52
      Console.WriteLine("Born in June:");
53
      foreach (Person p in persons["month"]["Jun"]) 
54
        Console.WriteLine(p);
55
      Console.WriteLine("Named Dorte:");
56
      foreach (Person p in persons["name"]["Dorte"]) 
57
        Console.WriteLine(p);
58
      Console.WriteLine(persons);
59
    }
60
    
61
    private static readonly String[] months = { 
62
      "Jan", "Feb", "Mar", "Apr", "May", "Jun", 
63
      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 
64
    };
65
  }
66

    
67
  public interface IIndexer<Q,R> { 
68
    ICollectionValue<R> this[Q x] { get; }
69
  }
70

    
71
  // An index maker has a name, it supports adding and removing items
72
  // from the index, and looking up items by key (here of type
73
  // Object).
74

    
75
  public abstract class IndexMaker<T> : IIndexer<Object, T> {
76
    public readonly String name;
77
    public abstract bool Add(T item);
78
    public abstract bool Remove(T item);
79
    public abstract ICollectionValue<T> this[Object key] { get; }
80

    
81
    public IndexMaker(String name) {
82
      this.name = name;
83
    }
84
  }
85

    
86
  // The implementation of an index maker consists of a function to
87
  // map an item of type T to the index key type Q, and a dictionary
88
  // that maps an index key (of type Q) to a set of items (each of
89
  // type T).
90

    
91
  public class IndexMaker<T,Q> : IndexMaker<T> 
92
    where T : class 
93
    where Q : IComparable<Q> 
94
  {
95
    private readonly Fun<T,Q> fun;
96
    private TreeDictionary<Q, HashSet<T>> dict;
97

    
98
    public IndexMaker(String name, Fun<T,Q> fun) : base(name) {
99
      this.fun = fun;
100
      dict = new TreeDictionary<Q, HashSet<T>>();
101
    }
102

    
103
    public override bool Add(T item) { 
104
      Q key = fun(item);
105
      if (!dict.Contains(key))
106
        dict.Add(key, new HashSet<T>(ReferenceEqualityComparer<T>.Default));
107
      return dict[key].Add(item);
108
    }
109

    
110
    public override bool Remove(T item) { 
111
      Q key = fun(item);
112
      if (!dict.Contains(key))
113
        return false;
114
      return dict[key].Remove(item);
115
    }
116

    
117
    public ICollectionValue<T> this[Q key] {
118
      get { 
119
        return dict[key];
120
      }
121
    }
122

    
123
    public override ICollectionValue<T> this[Object key] {
124
      get { 
125
        return dict[(Q)key];
126
      }
127
    }
128

    
129
    public override String ToString() {
130
      return dict.ToString();
131
    }
132
  }
133

    
134
  // Weakly typed implementation of multiple indexers on a class T.  
135

    
136
  // The implementation is an array of index makers, each consisting
137
  // of the index's name and its implementation which supports adding
138
  // and removing T objects, and looking up T objects by the key
139
  // relevant for that index.
140

    
141
  public class Indexed<T> where T : class {
142
    IndexMaker<T>[] indexMakers;
143

    
144
    public Indexed(params IndexMaker<T>[] indexMakers) {
145
      this.indexMakers = indexMakers;
146
    }
147
    
148
    public bool Add(T item) { 
149
      bool result = false;
150
      foreach (IndexMaker<T> indexMaker in indexMakers)
151
        result |= indexMaker.Add(item);
152
      return result;    
153
    }
154

    
155
    public bool Remove(T item) { 
156
      bool result = false;
157
      foreach (IndexMaker<T> indexMaker in indexMakers)
158
        result |= indexMaker.Remove(item);
159
      return result;    
160
    }
161

    
162
    public IIndexer<Object, T> this[String name] {
163
      get {
164
        foreach (IndexMaker<T> indexMaker in indexMakers)
165
          if (indexMaker.name == name) 
166
            return indexMaker;
167
        throw new Exception("Unknown index");
168
      }
169
    }
170

    
171
    // For debugging
172

    
173
    public override String ToString() {
174
      StringBuilder sb = new StringBuilder();
175
      foreach (IndexMaker<T> indexMaker in indexMakers) {
176
        sb.Append("\n----- ").Append(indexMaker.name).Append("-----\n");
177
        sb.Append(indexMaker);
178
      }
179
      return sb.ToString();
180
    }
181
  }
182

    
183
  // Sample class with two fields but many possible indexes
184
  
185
  public class Person {
186
    public readonly String name;
187
    public readonly int date; // YYYYMMDD as in 20070725
188

    
189
    public Person(String name, int date) {
190
      this.name = name;
191
      this.date = date;
192
    }
193

    
194
    public override String ToString() {
195
      return name + " (" + date + ")";
196
    }
197
  }
198

    
199
  // The interface of a strongly typed indexing of Person objects:
200
  // (Not yet used)
201

    
202
  public interface PersonIndexers {
203
    IIndexer<String, Person> Name { get; }
204
    IIndexer<int,    Person> Year { get; }
205
    IIndexer<int,    Person> Day { get; }
206
    IIndexer<String, Person> Month { get; }
207
  }
208
}