1 module fdb.rangeinfo;
2 
3 import
4     std.array,
5     std.exception;
6 
7 import
8     fdb.fdb_c,
9     fdb.fdb_c_options;
10 
11 struct Selector
12 {
13     Key  key;
14     bool orEqual;
15     int  offset;
16 }
17 
18 struct RangeInfo
19 {
20     Selector      begin;
21     Selector      end;
22     int           limit;
23     StreamingMode mode;
24     int           iteration;
25     bool          reverse;
26 }
27 
28 /*
29  * #define FDB_KEYSEL_LAST_LESS_THAN(k, l) k, l, 0, 0
30  * #define FDB_KEYSEL_LAST_LESS_OR_EQUAL(k, l) k, l, 1, 0
31  * #define FDB_KEYSEL_FIRST_GREATER_THAN(k, l) k, l, 1, 1
32  * #define FDB_KEYSEL_FIRST_GREATER_OR_EQUAL(k, l) k, l, 0, 1
33  */
34 
35 auto lastLessThan(const Key key)
36 {
37     return Selector(key.dup, false, 0);
38 }
39 
40 auto lastLessOrEqual(const Key key)
41 {
42     return Selector(key.dup, true, 0);
43 }
44 
45 auto firstGreaterThan(const Key key)
46 {
47     return Selector(key.dup, true, 1);
48 }
49 
50 auto firstGreaterOrEqual(const Key key)
51 {
52     return Selector(key.dup, false, 1);
53 }
54 
55 auto createRangeInfo(
56         const Key           begin,
57         const Key           end       = null,
58         const int           limit     = 0,
59         const StreamingMode mode      = StreamingMode.ITERATOR,
60         const bool          reverse   = false,
61         const int           iteration = 1)
62 {
63     auto sanBegin = sanitizeKey(begin, [ 0x00 ]);
64     auto sanEnd   = sanitizeKey(end, sanBegin.getEndPrefix);
65 
66     auto beginSel = sanBegin.firstGreaterOrEqual;
67     auto endSel   = sanEnd.firstGreaterOrEqual;
68 
69     auto rangeInfo = RangeInfo(
70             beginSel, endSel, limit, mode, iteration, reverse);
71     return rangeInfo;
72 }
73 
74 auto createRangeInfoInclusive(
75         const Key           begin,
76         const Key           end       = null,
77         const int           limit     = 0,
78         const StreamingMode mode      = StreamingMode.ITERATOR,
79         const bool          reverse   = false,
80         const int           iteration = 1)
81 {
82     auto sanBegin = sanitizeKey(begin, [ 0x00 ]);
83     auto sanEnd   = sanitizeKey(end, sanBegin.getEndPrefix);
84 
85     auto beginSel = sanBegin.firstGreaterOrEqual;
86     auto endSel   = sanEnd.firstGreaterThan;
87 
88     auto rangeInfo = RangeInfo(
89             beginSel, endSel, limit, mode, iteration, reverse);
90     return rangeInfo;
91 }
92 
93 auto createRangeInfo(
94         Selector            beginSel,
95         Selector            endSel,
96         const int           limit     = 0,
97         const StreamingMode mode      = StreamingMode.ITERATOR,
98         const bool          reverse   = false,
99         const int           iteration = 1)
100 {
101     auto rangeInfo = RangeInfo(
102             beginSel, endSel, limit, mode, iteration, reverse);
103     return rangeInfo;
104 }
105 
106 alias range          = createRangeInfo;
107 alias rangeInclusive = createRangeInfoInclusive;
108 
109 auto sanitizeKey(const Key key, lazy Key fallback) pure
110 {
111     if (key is null || key.empty)
112         return fallback;
113     return key;
114 }
115 
116 auto getEndPrefix(const Key prefix) pure
117 in
118 {
119     enforce(prefix !is null);
120     enforce(prefix.length > 0);
121 }
122 body
123 {
124     ulong i = prefix.length;
125     if (i == 1) return [ cast(ubyte) 0xff ];
126 
127     do --i;
128     while (i != 0 && prefix[i] == 0xff);
129 
130     enforce(prefix[i] != 0xff, "All prefix bytes cannot equal 0xff");
131 
132     auto endPrefix = prefix[0 .. i + 1].dup;
133     ++endPrefix[i];
134     return endPrefix;
135 }