/bitfield/trunk

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/bitfield/trunk
3 by Gustav Hartvigsson
* It works. :-)
1
/* (c) Gustav Hartvigsson 2020
2
3
                        Cool Licence 1.0
4
5
0) You is granted to copy, redistrubute, modify, redistrubute
6
   modified copies of the software, in any shape or form.
7
1) You are not obligated to give credit the original author(s) of
8
   the sofware, but it would be cool of you if you did.
9
2) You are allowed to removed the copyright notice if you want to,
10
   it is up to you, but it would be cool if you did not.
11
 */
12
2 by Gustav Hartvigsson
* encountered a bug in Valac:
13
namespace BitField {
14
  
15
  private static GLib.Tree<string, Type?> list_of_types;
16
  
3 by Gustav Hartvigsson
* It works. :-)
17
  private static GLib.Tree<FieldInfo?, uint16> mask_cache;
2 by Gustav Hartvigsson
* encountered a bug in Valac:
18
  
10 by Gustav Hartvigsson
* Made it able to be compiled as a library
19
  public void init () {
2 by Gustav Hartvigsson
* encountered a bug in Valac:
20
    list_of_types = new GLib.Tree<string, Type?> ((a, b) => {
21
      return (GLib.strcmp (a,b));
22
    });
23
    
3 by Gustav Hartvigsson
* It works. :-)
24
    mask_cache = new GLib.Tree<FieldInfo?, uint16> ((a, b) => {
2 by Gustav Hartvigsson
* encountered a bug in Valac:
25
       return a.compare (b);
26
    });
27
  }
28
  
10 by Gustav Hartvigsson
* Made it able to be compiled as a library
29
  public void deinit () {
2 by Gustav Hartvigsson
* encountered a bug in Valac:
30
    list_of_types.foreach ((_key, _val) => {
31
      list_of_types.remove (_key);
32
      
33
      return false;
34
    });
35
  }
36
  
10 by Gustav Hartvigsson
* Made it able to be compiled as a library
37
  public static bool add_type_v (string name, FieldInfo first_field, ...) {
2 by Gustav Hartvigsson
* encountered a bug in Valac:
38
    var va = va_list ();
39
    
40
    GLib.List<FieldInfo?> lst = new GLib.List<FieldInfo?> ();
41
    
42
    lst.append (first_field);
43
    for (FieldInfo? fi = va.arg<FieldInfo> (); fi != null;
44
                                               fi = va.arg<FieldInfo> ()) {
45
      lst.append (fi);
46
    }
47
    
3 by Gustav Hartvigsson
* It works. :-)
48
    FieldInfo[] lst2 = new FieldInfo[lst.length ()];
49
    
7 by Gustav Hartvigsson
* Woops
50
    for (uint i = 0; i < lst.length (); i++) {
51
      lst2[i] = lst.nth_data (i);
52
    }
9 by Gustav Hartvigsson
Woops
53
   
54
    return add_type (name, lst2);
3 by Gustav Hartvigsson
* It works. :-)
55
  }
56
  
57
  /**
58
   * @Return true on error.
59
   */
60
  public bool add_type (string name, FieldInfo[] fields) {
61
    GLib.List<FieldInfo?> lst = new GLib.List<FieldInfo?> ();
62
    
63
    foreach  (FieldInfo fi in fields) {
64
      lst.append (fi);
65
    }
66
    
2 by Gustav Hartvigsson
* encountered a bug in Valac:
67
    if (lst.length () >= 16) {
68
      return true;
69
    }
70
    
71
    lst.sort ((a,b) => {return a.compare (b);});
72
    
73
    
74
    for (uint8 i = 0; i < lst.length (); i++) {
75
      var a = lst.nth_data (i); 
76
      // We valitade the items whilst we are at it.
77
      if (a.validate ()) {
3 by Gustav Hartvigsson
* It works. :-)
78
        GLib.critical ("Validtion of FieldInfo object failed: (%s)",
79
                       a.to_string ());
2 by Gustav Hartvigsson
* encountered a bug in Valac:
80
        return true;
81
      }
82
      for (uint8 j = i + 1; i < lst.length (); j++) {
3 by Gustav Hartvigsson
* It works. :-)
83
        var b = lst.nth_data (j);
84
        if (b == null) {
85
          break;
86
        }
2 by Gustav Hartvigsson
* encountered a bug in Valac:
87
        if (a.overlap (b)) {
3 by Gustav Hartvigsson
* It works. :-)
88
          GLib.critical ("Overlappinng fields in \"%s\": (%s) (%s).\n" +
2 by Gustav Hartvigsson
* encountered a bug in Valac:
89
                         "\t Will not add bitmap type defitions.",
3 by Gustav Hartvigsson
* It works. :-)
90
                         name,
91
                         a.to_string (),
92
                         b.to_string ());
2 by Gustav Hartvigsson
* encountered a bug in Valac:
93
          return true;
94
        }
95
      }
96
    }
97
    
98
    Type t = Type ();
99
    for (uint8 i = 0; i < lst.length (); i++) {
100
      t.fields[i] = lst.nth_data (i);
101
    }
102
    
3 by Gustav Hartvigsson
* It works. :-)
103
    list_of_types.insert (name, t);
104
    
105
    // add the masks to the mask cach, so we don't have to re-calculate them
106
    // each time we need them.
107
    lst.foreach ((ii) => {
108
      mask_cache.insert (ii, ii.generate_mask ());
109
    });
110
    
111
    
2 by Gustav Hartvigsson
* encountered a bug in Valac:
112
    return false;
113
  }
114
  
3 by Gustav Hartvigsson
* It works. :-)
115
  public void set (ref uint16 data,
116
                   string type_name,
117
                   int field_id,
118
                   uint16 in_data) {
119
    
120
    var tt = list_of_types.lookup (type_name);
121
    if (tt == null) {
122
      GLib.critical ("Name \"%s\" dose not exist among the types valid types.",
123
                     type_name);
124
      return;
125
    }
126
    var fi = tt.get_field_info (field_id);
127
    uint16 mask = mask_cache.lookup (fi);
128
    uint16 invert_mask = ~mask;
129
    uint16 tmp = data & invert_mask; // everything exept the field.
130
    
131
    uint16 tmp_mask = 1;
132
    for (uint8 i = 0; i < fi.length; i++) {
133
      tmp_mask <<= 1;
134
      tmp_mask += 1;
135
    }
136
    
137
    uint16 tmp2 = in_data & tmp_mask;
138
    
139
    
140
    uint16 distance = 15 - fi.end;
141
    
142
    
143
    tmp2 = tmp2 << distance;
144
    
145
    
146
    tmp2 = tmp2 | tmp;
147
    
148
    data = tmp2;
149
  }
150
  
151
  public uint16 get (uint16 data,
152
                     string type_name,
153
                     int field_id) {
154
    
155
    var fi = list_of_types.lookup (type_name).get_field_info (field_id);
156
    uint16 mask = mask_cache.lookup (fi);
157
    uint16 tmp = data & mask; // only what is in the field.
158
    
159
    
160
    uint16 distance = 15 - fi.end;
161
    
162
    
163
    tmp = tmp >> distance;
164
    return tmp;
165
  }
166
  
167
  Type? get_type (string name) {
168
    return list_of_types.lookup (name);
169
  } 
170
  
171
  /**
172
   * Create a new FieldInfo using the following syntax:
173
   * {{{
174
   * }}}
175
   * 
176
   */
2 by Gustav Hartvigsson
* encountered a bug in Valac:
177
  public struct FieldInfo {
3 by Gustav Hartvigsson
* It works. :-)
178
    int field_id;
2 by Gustav Hartvigsson
* encountered a bug in Valac:
179
    uint8 start;
180
    uint8 end;
181
    uint8 length;
3 by Gustav Hartvigsson
* It works. :-)
182
    
183
    public FieldInfo (int field_id, uint8 start, uint8 end, uint8 length) {
184
      this.field_id = field_id;
185
      this.start = start;
186
      this.end = end;
187
      this.length = length; 
188
    }
2 by Gustav Hartvigsson
* encountered a bug in Valac:
189
    
190
    public int compare (FieldInfo other) {
191
      if (this.field_id != other.field_id) {
3 by Gustav Hartvigsson
* It works. :-)
192
        return  this.field_id - other.field_id; 
2 by Gustav Hartvigsson
* encountered a bug in Valac:
193
      } else if (this.start != other.start) {
3 by Gustav Hartvigsson
* It works. :-)
194
        return  this.start - other.start;
2 by Gustav Hartvigsson
* encountered a bug in Valac:
195
      } else if (this.end != other.end) {
3 by Gustav Hartvigsson
* It works. :-)
196
        return this.end - other.end;
2 by Gustav Hartvigsson
* encountered a bug in Valac:
197
      } else if (this.length != other.length) {
3 by Gustav Hartvigsson
* It works. :-)
198
        return this.length - other.length;
2 by Gustav Hartvigsson
* encountered a bug in Valac:
199
      }
200
      
201
      #if 0
202
      if (this.start > other.start) {
203
        return -1;
204
      } else if (this.start < other.start) {
205
        return 1;
206
      } else {
207
        if (this.end > other.end) {
208
          return -1;
209
        } else if (this.end < other.end) {
210
          return 1;
211
        } else {
212
          if (this.length > other.length) {
213
            return -1;
214
          } else if (this.length < other.length) {
215
            return 1;
216
          }
217
        }
218
      }
219
      #endif
220
      
221
      return 0;
222
    }
223
    
224
    [CCode (cname = "bit_field_field_info_compare")]
8 by Gustav Hartvigsson
* Fixed type : campare->compare.
225
    public static extern int static_compare (FieldInfo a, FieldInfo b);
226
    
2 by Gustav Hartvigsson
* encountered a bug in Valac:
227
    
228
    
229
    public bool overlap (FieldInfo other) {
230
      return (!((this.start < other.end) || (this.end > other.start)));
231
    }
232
    
233
    [CCode (cname = "bit_field_field_info_overlap")]
8 by Gustav Hartvigsson
* Fixed type : campare->compare.
234
    public static extern bool static_overlap (FieldInfo a, FieldInfo b);
2 by Gustav Hartvigsson
* encountered a bug in Valac:
235
    
236
    
237
    public string to_string () {
3 by Gustav Hartvigsson
* It works. :-)
238
      return "field_id: %i start: %i, end: %i, length: %i".printf (
239
                                                      this.field_id,
240
                                                      this.start,
2 by Gustav Hartvigsson
* encountered a bug in Valac:
241
                                                      this.end,
242
                                                      this.length);
243
    }
244
    
245
    /**
246
     * returns true on error;
247
     */
248
    public bool validate () {
3 by Gustav Hartvigsson
* It works. :-)
249
      var distance = this.end - this.start + 1;
2 by Gustav Hartvigsson
* encountered a bug in Valac:
250
      if (distance < 1 || distance != this.length) {
251
        return true;
252
      }
253
      return false;
254
    }
255
    
256
    [CCode (cname = "bit_field_field_info_validate")]
257
    public extern static bool static_validate (FieldInfo info);
258
    
259
    public uint16 generate_mask () {
260
      uint16 mask = 0;
261
      for (size_t i = 0; i < this.length; i++) {
3 by Gustav Hartvigsson
* It works. :-)
262
        mask >>= 1; // shit it over to the right one.
2 by Gustav Hartvigsson
* encountered a bug in Valac:
263
        mask += 0x8000; // set the left-most bit in the field
264
      }
265
      
3 by Gustav Hartvigsson
* It works. :-)
266
      // Shift over the mask to where it should start.
267
      mask >>= this.start; 
2 by Gustav Hartvigsson
* encountered a bug in Valac:
268
      
269
      return mask;
270
    }
271
    
272
    [CCode (cname = "bit_field_field_generate_mask")]
273
    public extern static uint16 static_generate_mask (FieldInfo info);
274
  }
275
  
3 by Gustav Hartvigsson
* It works. :-)
276
  public struct Type {
2 by Gustav Hartvigsson
* encountered a bug in Valac:
277
    FieldInfo[] fields;
278
    
279
    Type () {
280
        fields = new FieldInfo[16];
3 by Gustav Hartvigsson
* It works. :-)
281
        for (uint8 i = 0; i < 16; i++) {
282
          fields[i] = {255,255,255,255};
283
        }
2 by Gustav Hartvigsson
* encountered a bug in Valac:
284
    }
285
    
286
    public string to_string () {
287
      var sb = new GLib.StringBuilder ();
288
      
289
      sb.append (typeof (Type).name ())
290
        .append (": (\n");
291
      for (size_t i = 0; i < fields.length; i++) {
292
          sb.append ("\t (")
293
            .append (fields[i].to_string ())
294
            .append (")\n");
295
      }
296
      
297
      sb.append (")\n");
298
      return sb.str;
299
    }
3 by Gustav Hartvigsson
* It works. :-)
300
    
301
    public FieldInfo get_field_info (int field_id) {
302
      
303
      FieldInfo ii = {0};
304
      
305
      foreach (FieldInfo ij in fields) {
306
        if (ij.field_id == field_id) {
307
          ii = ij;
308
        }
309
      }
310
      
311
      return ii;
312
    }
313
    
2 by Gustav Hartvigsson
* encountered a bug in Valac:
314
  }
315
  
1 by Gustav Hartvigsson
start of project
316
}