| [55ba7339] | 1 | // A small context defining the notion of an ordered otype.  (The standard
 | 
|---|
| [51b73452] | 2 | // library should probably contain a context for this purpose.)
 | 
|---|
| [e5b96bf] | 3 | trait ordered(otype T) {
 | 
|---|
| [51b73452] | 4 |     int ?<?(T, T), ?<=?(T, T);
 | 
|---|
 | 5 | };
 | 
|---|
 | 6 | 
 | 
|---|
| [55ba7339] | 7 | // A subrange otype resembling an Ada subotype with a base otype and a range
 | 
|---|
| [51b73452] | 8 | // constraint.
 | 
|---|
| [55ba7339] | 9 | otype subrange(otype base_t | ordered(base_t), base_t low = 0, base_t high = 8) = base_t;
 | 
|---|
| [51b73452] | 10 | 
 | 
|---|
| [55ba7339] | 11 | // Note that subrange() can be applied to floating-point and pointer otypes, not
 | 
|---|
 | 12 | // just integral otypes.
 | 
|---|
 | 13 | //   This requires a "otype generator" extension to Cforall.  Type generators
 | 
|---|
 | 14 | // must accept otype and non-otype parameters, which is beyond what we discussed
 | 
|---|
| [51b73452] | 15 | // previously.  Type parameters must be usable in the declaration of
 | 
|---|
 | 16 | // subsequent parameters: parameter T is used to declare parameters "low"
 | 
|---|
 | 17 | // and "high".
 | 
|---|
 | 18 | 
 | 
|---|
 | 19 | // Example usage:
 | 
|---|
 | 20 | subrange(unsigned, 1, 31) day_of_month;
 | 
|---|
 | 21 | subrange(char, 'a', 'z')  lcase;
 | 
|---|
 | 22 | subrange(int, 0, (rand() & 0xF) ) foo;
 | 
|---|
 | 23 | 
 | 
|---|
| [55ba7339] | 24 | // What sorts of expressions can be used as arguments of otype generators?  Is
 | 
|---|
| [51b73452] | 25 | // "subrange(int, 0, rand() & 0xF)" legal?  Probably.  The nearest C equivalent
 | 
|---|
 | 26 | // to the "low" and "high" arguments is the array size in a variable-length
 | 
|---|
 | 27 | // array declaration, and C allows assignment expressions there.
 | 
|---|
 | 28 | 
 | 
|---|
 | 29 | // Convenient access to subrange bounds, for instance for iteration:
 | 
|---|
| [55ba7339] | 30 | forall (otype T, T low, T high)
 | 
|---|
| [51b73452] | 31 | T lbound( subrange(T, low, high) v) {
 | 
|---|
 | 32 |     return low;
 | 
|---|
 | 33 | }
 | 
|---|
 | 34 | 
 | 
|---|
| [55ba7339] | 35 | forall (otype T, T low, T high)
 | 
|---|
| [51b73452] | 36 | T hbound( subrange(T, low, high) v) {
 | 
|---|
 | 37 |     return high;
 | 
|---|
 | 38 | }
 | 
|---|
 | 39 | 
 | 
|---|
 | 40 | // Example usage:
 | 
|---|
 | 41 | unsigned lday = lbound(day_of_month);
 | 
|---|
 | 42 | 
 | 
|---|
| [55ba7339] | 43 | // Assignment from the base otype, with bounds checking.  I'll ignore the issue
 | 
|---|
| [51b73452] | 44 | // of exception handling here.  Inlining allows the compiler to eliminate
 | 
|---|
 | 45 | // bounds checks.
 | 
|---|
| [55ba7339] | 46 | forall (otype T | ordered(T), T low, T high)
 | 
|---|
| [51b73452] | 47 | inline subrange(T, low, high) ?=?(subrange(T, low, high)* target, T source) {
 | 
|---|
 | 48 |     if (low <= source && source <= high) *((T*)target) = source;
 | 
|---|
 | 49 |     else abort();
 | 
|---|
 | 50 |     return target;
 | 
|---|
 | 51 | }
 | 
|---|
 | 52 | 
 | 
|---|
| [55ba7339] | 53 | // Assignment between subranges with a common base otype.  The bounds check
 | 
|---|
| [51b73452] | 54 | // compares range bounds so that the compiler can optimize checks away when the
 | 
|---|
 | 55 | // ranges are known to overlap.
 | 
|---|
| [55ba7339] | 56 | forall (otype T | ordered(T), T t_low, T t_high, T s_low, T s_high)
 | 
|---|
| [51b73452] | 57 | inline subrange(T, t_low, t_high) ?=?(subrange(T, t_low, t_high)* target,
 | 
|---|
 | 58 |                                       subrange(T, s_low, s_high) source) {
 | 
|---|
 | 59 |     if ( (t_low <= s_low || t_low <= source)
 | 
|---|
 | 60 |          && (s_high <= t_high || source <= t_high) ) *((T*)target) = source;
 | 
|---|
 | 61 |     else abort();
 | 
|---|
 | 62 |     return target;
 | 
|---|
 | 63 | }
 | 
|---|