oinky 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. data/LICENSE +22 -0
  2. data/README.md +141 -0
  3. data/ext/extconf.rb +79 -0
  4. data/ext/include/oinky.h +424 -0
  5. data/ext/include/oinky.hpp +63 -0
  6. data/ext/include/oinky/nky_base.hpp +1116 -0
  7. data/ext/include/oinky/nky_core.hpp +1603 -0
  8. data/ext/include/oinky/nky_cursor.hpp +665 -0
  9. data/ext/include/oinky/nky_dialect.hpp +107 -0
  10. data/ext/include/oinky/nky_error.hpp +164 -0
  11. data/ext/include/oinky/nky_fixed_table.hpp +710 -0
  12. data/ext/include/oinky/nky_handle.hpp +334 -0
  13. data/ext/include/oinky/nky_index.hpp +1038 -0
  14. data/ext/include/oinky/nky_log.hpp +15 -0
  15. data/ext/include/oinky/nky_merge_itr.hpp +403 -0
  16. data/ext/include/oinky/nky_model.hpp +110 -0
  17. data/ext/include/oinky/nky_pool.hpp +760 -0
  18. data/ext/include/oinky/nky_public.hpp +808 -0
  19. data/ext/include/oinky/nky_serializer.hpp +1625 -0
  20. data/ext/include/oinky/nky_strtable.hpp +504 -0
  21. data/ext/include/oinky/nky_table.hpp +1996 -0
  22. data/ext/nky_lib.cpp +390 -0
  23. data/ext/nky_lib_core.hpp +212 -0
  24. data/ext/nky_lib_index.cpp +158 -0
  25. data/ext/nky_lib_table.cpp +224 -0
  26. data/lib/oinky.rb +1284 -0
  27. data/lib/oinky/compiler.rb +106 -0
  28. data/lib/oinky/cpp_emitter.rb +311 -0
  29. data/lib/oinky/dsl.rb +167 -0
  30. data/lib/oinky/error.rb +19 -0
  31. data/lib/oinky/modelbase.rb +12 -0
  32. data/lib/oinky/nbuffer.rb +152 -0
  33. data/lib/oinky/normalize.rb +132 -0
  34. data/lib/oinky/oc_builder.rb +44 -0
  35. data/lib/oinky/query.rb +193 -0
  36. data/lib/oinky/rb_emitter.rb +147 -0
  37. data/lib/oinky/shard.rb +40 -0
  38. data/lib/oinky/testsup.rb +104 -0
  39. data/lib/oinky/version.rb +9 -0
  40. data/oinky.gemspec +36 -0
  41. metadata +120 -0
@@ -0,0 +1,15 @@
1
+ // This source is distributed under the terms of the MIT License. Refer
2
+ // to the 'LICENSE' file for details.
3
+ //
4
+ // Copyright (c) Jacob Lacouture, 2012
5
+
6
+ namespace Oinky
7
+ {
8
+ namespace Internal
9
+ {
10
+ using namespace Oinky::Errors;
11
+ using namespace Oinky::Utils;
12
+
13
+
14
+ } //namespace Internal
15
+ } //namespace Oinky
@@ -0,0 +1,403 @@
1
+ // This source is distributed under the terms of the MIT License. Refer
2
+ // to the 'LICENSE' file for details.
3
+ //
4
+ // Copyright (c) Jacob Lacouture, 2012
5
+
6
+ namespace Oinky
7
+ {
8
+ namespace Utils
9
+ {
10
+ using namespace Oinky::Errors;
11
+
12
+ //
13
+ // The merge iterator is bidirectional. We need a concept of a range, where
14
+ // the iterator can be valid, or at end(), or additionally, before the
15
+ // beginning of the sequence. In general, we cannot safely decrement an
16
+ // iterator from begin().
17
+ //
18
+
19
+ template<typename ITR>
20
+ class symmetric_iterator
21
+ {
22
+ typedef ITR iterator;
23
+
24
+ iterator _i;
25
+ iterator _begin;
26
+ iterator _end;
27
+ bool _sub_begin;
28
+
29
+ iterator begin() const { return _begin; }
30
+ iterator end() const { return _end; }
31
+
32
+ public:
33
+ symmetric_iterator(
34
+ const iterator &__i,
35
+ const iterator &__begin,
36
+ const iterator &__end) :
37
+ _i(__i),
38
+ _begin(__begin),
39
+ _end(__end),
40
+ _sub_begin(false)
41
+ {}
42
+
43
+ symmetric_iterator() : _sub_begin(false) {}
44
+
45
+ // This need not return iterator &. It merely must return whatever
46
+ // the comparer expects.
47
+ const iterator &i() const { return _i; }
48
+
49
+ bool before_begin() const { return _sub_begin; }
50
+ bool at_end() const { return _i == _end; }
51
+ bool is_valid() const { return !before_begin() && !at_end(); }
52
+
53
+ void increment() {
54
+ OINKY_ASSERT( _sub_begin || (_i != _end) );
55
+ if (_sub_begin) {
56
+ _sub_begin = false;
57
+ } else {
58
+ ++_i;
59
+ }
60
+ }
61
+ void decrement() {
62
+ OINKY_ASSERT( !_sub_begin );
63
+ if (_i == _begin) {
64
+ _sub_begin = true;
65
+ } else {
66
+ --_i;
67
+ }
68
+ }
69
+ };
70
+
71
+ template<typename DERIVED, typename VALUE_TYPE, typename RANGE1, typename RANGE2, typename COMPARE>
72
+ class merge_iterator_template : public
73
+ boost::iterator_facade<
74
+ DERIVED,
75
+ VALUE_TYPE,
76
+ boost::bidirectional_traversal_tag,
77
+ VALUE_TYPE
78
+ >
79
+ {
80
+ typedef merge_iterator_template<DERIVED,VALUE_TYPE,RANGE1,RANGE2,COMPARE> this_t;
81
+ typedef boost::iterator_facade<
82
+ DERIVED,
83
+ VALUE_TYPE,
84
+ boost::bidirectional_traversal_tag,
85
+ VALUE_TYPE
86
+ > base_t;
87
+
88
+ friend class boost::iterator_core_access;
89
+
90
+ public:
91
+ // base iterators should all have good defaults.
92
+ merge_iterator_template() {}
93
+
94
+ merge_iterator_template(
95
+ const RANGE1 &_l,
96
+ const RANGE2 &_r) :
97
+ l(_l),
98
+ r(_r)
99
+ {
100
+ set_fwd_state();
101
+ }
102
+
103
+ private:
104
+ RANGE1 l;
105
+ RANGE2 r;
106
+
107
+ // -1: *this == *l
108
+ // 0: *this == *l, *this == *r
109
+ // 1: *this == *r
110
+ int active;
111
+ // -1: *l < *r
112
+ // 0: *l == *r
113
+ // 1: *l > r
114
+ int lsubr;
115
+
116
+ void set_fwd_state()
117
+ {
118
+ lsubr = 0;
119
+ bool compare = true;
120
+ if (l.before_begin()) {
121
+ lsubr -= 1;
122
+ compare = false;
123
+ } else if (l.at_end()) {
124
+ lsubr += 1;
125
+ compare = false;
126
+ }
127
+ if (r.before_begin()) {
128
+ lsubr += 1;
129
+ compare = false;
130
+ } else if (r.at_end()) {
131
+ lsubr -= 1;
132
+ compare = false;
133
+ }
134
+ if (compare) {
135
+ // Compute l-r
136
+ COMPARE c;
137
+ lsubr = c(l.i(), r.i());
138
+ }
139
+ // current position is the smaller of the two. -1 if left
140
+ // is smaller, 1 if right is smaller, 0 if equal.
141
+ active = lsubr;
142
+ }
143
+ void set_reverse_state()
144
+ {
145
+ set_fwd_state();
146
+ active = -active;
147
+ }
148
+ protected:
149
+ void increment()
150
+ {
151
+ // Advance the iterator.
152
+ COMPARE c;
153
+ (void) c;
154
+
155
+ // Left is active.
156
+ if (active < 0) {
157
+ // If right < left, then this is a change of direction.
158
+ if (lsubr > 0) {
159
+ // Grow right.
160
+ r.increment();
161
+ // The invariant is that left and right are always less than
162
+ // one step apart. Stepping either toward the other changes
163
+ // sign of lsubr, or makes it nonzero.
164
+ OINKY_ASSERT((r.at_end()) || (c(l.i(),r.i()) < 0));
165
+ }
166
+ l.increment();
167
+ } else if (active > 0) {
168
+ // If right > left, then this is a change of direction.
169
+ if (lsubr < 0) {
170
+ // Grow left to beyond right.
171
+ l.increment();
172
+ OINKY_ASSERT((l.at_end()) || (c(l.i(),r.i()) > 0));
173
+ }
174
+ r.increment();
175
+ } else {
176
+ // Increment both.
177
+ l.increment();
178
+ r.increment();
179
+ }
180
+ // Make the smallest iterator active.
181
+ set_fwd_state();
182
+ }
183
+ void advance(int n) {
184
+ while (n>0) {
185
+ increment();
186
+ --n;
187
+ }
188
+ while (n<0) {
189
+ decrement();
190
+ ++n;
191
+ }
192
+ }
193
+
194
+ void decrement()
195
+ {
196
+ COMPARE c;
197
+ (void) c;
198
+
199
+ // Left is active.
200
+ if (active < 0) {
201
+ // If right > left, then this is a change of direction.
202
+ if (lsubr < 0) {
203
+ // Decrement right until it's less than left;
204
+ r.decrement();
205
+ // Having decremented, we know r.i != r.end or r.sub_begin.
206
+ // Also, if the iterators were separated by less than one
207
+ // position, then right should now be < left.
208
+ OINKY_ASSERT(r.before_begin() || (c(l.i(),r.i()) > 0));
209
+ }
210
+ // Now decrement left.
211
+ l.decrement();
212
+ } else if (active > 0) {
213
+ // If right < left, then this is a change of direction.
214
+ if (lsubr > 0) {
215
+ // Decrement left until it's less than right.
216
+ l.decrement();
217
+ OINKY_ASSERT(l.before_begin() || (c(l.i(),r.i()) < 0));
218
+ }
219
+ // Now decrement right.
220
+ r.decrement();
221
+ } else {
222
+ // Decrement both.
223
+ l.decrement();
224
+ r.decrement();
225
+ }
226
+ // Make the largest iterator active.
227
+ set_reverse_state();
228
+ }
229
+
230
+ // This is nontrivial, since the iterators may be traveling different
231
+ // directions. They may thus be equal (referring to the same element)
232
+ // but have one of the the component iterators being different.
233
+ bool equal(const this_t &other) const { return compare_to(_equal(), other); }
234
+
235
+ public:
236
+ const RANGE1 &left() const { return l; }
237
+ const RANGE2 &right() const { return r; }
238
+
239
+ // Remember, it's possible that BOTH left and right will be simultaneously active.
240
+ bool left_active() const { return (active <= 0) && l.is_valid(); }
241
+ bool right_active() const { return (active >= 0) && r.is_valid(); }
242
+
243
+ bool at_end() const { return l.at_end() && r.at_end(); }
244
+ bool before_begin() const { return l.before_begin() && r.before_begin(); }
245
+
246
+ template<typename FN>
247
+ bool compare_to(const FN &fn, const this_t &other) const {
248
+ int x = compare_to(other);
249
+ return fn(x,0);
250
+ }
251
+
252
+ int compare_to(const this_t &other) const {
253
+ COMPARE c;
254
+
255
+ int stat =
256
+ (left_active() ? 8 : 0) |
257
+ (right_active() ? 4 : 0) |
258
+ (other.left_active() ? 2 : 0) |
259
+ (other.right_active() ? 1 : 0);
260
+ switch (stat) {
261
+ case 0x0 + 0x0 :
262
+ // Both at end.
263
+ return 0;
264
+ case 0x8 + 0x0:
265
+ case 0x4 + 0x0:
266
+ case 0xc + 0x0:
267
+ // other at end. This not.
268
+ return -1;
269
+ case 0x0 + 0x2:
270
+ case 0x0 + 0x1:
271
+ case 0x0 + 0x3:
272
+ // this at end. Other not.
273
+ return 1;
274
+ case 0x8 + 0x2:
275
+ case 0xc + 0x2:
276
+ case 0x8 + 0x3:
277
+ case 0xc + 0x3:
278
+ // Left active on both.
279
+ return c(l.i(), other.l.i());
280
+ case 0x4 + 0x1:
281
+ case 0xc + 0x1:
282
+ case 0x4 + 0x3:
283
+ //case 0xc + 0x3: dup
284
+ // Right active on both.
285
+ return c(r.i(), other.r.i());
286
+ case 0x8 + 0x1:
287
+ // This left. Other right.
288
+ return c(l.i(), other.r.i());
289
+ case 0x4 + 0x2:
290
+ // This right. Other left.
291
+ return c(r.i(), other.l.i());
292
+ }
293
+ OINKY_ASSERT(false);
294
+ throw_error(implementation_bug());
295
+ return 0;
296
+ }
297
+
298
+ /* This is slow, and not required of bidirectional iterators, so we don't
299
+ implement it.
300
+ int distance_to(const this_t &other) const {
301
+ // This works, but is not efficient, and should not be used.
302
+ OINKY_ASSERT(false);
303
+ throw_error(unsupported_operation());
304
+
305
+ if (other < *this) {
306
+ return -other.distance_to(*this);
307
+ }
308
+
309
+ this_t tmp = *this;
310
+ int count = 0;
311
+ while (tmp < other) {
312
+ ++tmp;
313
+ ++count;
314
+ }
315
+ return count;
316
+ }*/
317
+
318
+ private:
319
+ struct _equal {template<typename T> bool operator()(const T&l, const T&r) const {return l == r;}};
320
+
321
+ struct _less {template<typename T> bool operator()(const T&l, const T&r) const {return l < r;}};
322
+ struct _gt {template<typename T> bool operator()(const T&l, const T&r) const {return l > r;}};
323
+ struct _leq {template<typename T> bool operator()(const T&l, const T&r) const {return l <= r;}};
324
+ struct _geq {template<typename T> bool operator()(const T&l, const T&r) const {return l >= r;}};
325
+
326
+ public:
327
+ bool operator<(const this_t &other) const {
328
+ return compare_to(_less(), other);
329
+ }
330
+ bool operator>(const this_t &other) const {
331
+ return compare_to(_gt(), other);
332
+ }
333
+ bool operator<=(const this_t &other) const {
334
+ return compare_to(_leq(), other);
335
+ }
336
+ bool operator>=(const this_t &other) const {
337
+ return compare_to(_geq(), other);
338
+ }
339
+ };
340
+
341
+
342
+ template<typename ITR1, typename ITR2, typename COMPARE>
343
+ class merge_iterator : public merge_iterator_template<
344
+ merge_iterator<ITR1, ITR2, COMPARE>,
345
+ typename boost::iterator_value<ITR1>::type,
346
+ symmetric_iterator<ITR1>,
347
+ symmetric_iterator<ITR2>,
348
+ COMPARE
349
+ >
350
+ {
351
+ typedef symmetric_iterator<ITR1> range1_t;
352
+ typedef symmetric_iterator<ITR2> range2_t;
353
+
354
+ typedef merge_iterator_template<
355
+ merge_iterator<ITR1, ITR2, COMPARE>,
356
+ typename boost::iterator_value<ITR1>::type,
357
+ range1_t,
358
+ range2_t,
359
+ COMPARE
360
+ > base_t;
361
+ public:
362
+ merge_iterator() {}
363
+
364
+ merge_iterator(
365
+ const range1_t &_l,
366
+ const range2_t &_r) :
367
+ base_t(_l,_r)
368
+ {}
369
+
370
+ merge_iterator(
371
+ const ITR1 &_li, const ITR1 &_lb, const ITR1 &_le,
372
+ const ITR2 &_ri, const ITR2 &_rb, const ITR2 &_re) :
373
+ base_t(range1_t(_li, _lb, _le),range2_t(_ri, _rb, _re))
374
+ {}
375
+
376
+ BOOST_STATIC_ASSERT((boost::is_same<
377
+ typename boost::iterator_value<ITR1>::type,
378
+ typename boost::iterator_value<ITR2>::type>::value));
379
+
380
+ typedef typename boost::iterator_value<ITR1>::type value_type;
381
+
382
+ const ITR1 &left() const { return base_t::left().i(); }
383
+ const ITR2 &right() const { return base_t::right().i(); }
384
+
385
+ private:
386
+ value_type dereference() const {
387
+ if (base_t::left_active()) {
388
+ return *left();
389
+ } else if (base_t::right_active()) {
390
+ return *right();
391
+ }
392
+
393
+ // Dereferencing an iterator at the end.
394
+ OINKY_ASSERT(false);
395
+ return value_type();
396
+ }
397
+
398
+ friend class boost::iterator_core_access;
399
+ };
400
+
401
+ } //namespace Utils
402
+ } //namespace Oinky
403
+
@@ -0,0 +1,110 @@
1
+ // This source is distributed under the terms of the MIT License. Refer
2
+ // to the 'LICENSE' file for details.
3
+ //
4
+ // Copyright (c) Jacob Lacouture, 2012
5
+
6
+ // These are some support classes for the code generated by the model compiler,
7
+ // which is still experimental.
8
+ //
9
+ // Everything in this file is subject to change.
10
+
11
+ namespace Oinky
12
+ {
13
+ namespace Model
14
+ {
15
+ typedef db_t::column_selector_t column_selector_t;
16
+ typedef db_t::index_handle index_handle;
17
+ typedef db_t::table_handle table_handle;
18
+
19
+ class TableBase
20
+ {
21
+ public:
22
+ static void create_column_if(
23
+ table_handle &th,
24
+ const char *colname,
25
+ column_type_code_t coltype,
26
+ const variant_cv_t &default_value)
27
+ {
28
+ db_t::column_itr i = th.columns().find(colname);
29
+ if (i == th.columns().end()) {
30
+ i = th.columns().create(colname, coltype, default_value);
31
+ }
32
+ }
33
+
34
+ static void create_index_if(
35
+ table_handle &th,
36
+ const db_string &ixname,
37
+ bool is_unique,
38
+ const index_column_def *cols_begin,
39
+ const index_column_def *cols_end)
40
+ {
41
+ db_t::index_itr i = th.indices().find(ixname);
42
+ if (i == th.indices().end()) {
43
+ i = th.indices().create(ixname, is_unique ? Oinky::Unique : Oinky::NonUnique, cols_begin, cols_end);
44
+ }
45
+ }
46
+
47
+ static index_handle get_index_handle(table_handle &th, const char *indexname) {
48
+ return th.indices()[indexname];
49
+ }
50
+
51
+ protected:
52
+ table_handle th;
53
+ db_t &__db;
54
+
55
+ public:
56
+ db_t &db() const { return __db; }
57
+
58
+ void check_init_row_accessor(column_selector_t &cs, const char **cn_begin, const char **cn_end)
59
+ {
60
+ // Column count will be zero if we haven't initialized yet. But
61
+ // we must also account for the fact that selectors are invalidated
62
+ // by schema changes to the table.
63
+ if ((cs.column_count() == 0) ||
64
+ (th.last_colset_change() != cs.last_colset_change()))
65
+ {
66
+ // This will raise an exception if one of our columns has been
67
+ // deleted since we mounted.
68
+ cs = th.make_selector(cn_begin, cn_end);
69
+ }
70
+ }
71
+
72
+ TableBase(const table_handle &_th, db_t &_db) : th(_th), __db(_db)
73
+ {}
74
+ };
75
+
76
+ class SchemaBase
77
+ {
78
+ db_t &db;
79
+
80
+ public:
81
+ static table_handle get_table_handle(db_t &db, const char *tablename) {
82
+ return *db.tables().create_if(tablename).first;
83
+ }
84
+
85
+ // Variable part of table-schema update. We invoke the callback when we
86
+ // detect something wrong, which is a defensive tactic.
87
+ typedef void (*schema_cb_fn)(db_t &db);
88
+
89
+ protected:
90
+ void up_schema(schema_cb_fn schema_cb)
91
+ {
92
+ // Ensure the schema migration is atomic.
93
+ sp_marker_t lkg = db.new_sp();
94
+ try {
95
+ (*schema_cb)(db);
96
+ } catch (...) {
97
+ db.sp_rollback(lkg);
98
+ // Re-throw.
99
+ throw;
100
+ }
101
+ }
102
+
103
+ public:
104
+ SchemaBase(db_t &_db, schema_cb_fn update_schema) : db(_db) {
105
+ (*update_schema)(db);
106
+ }
107
+ };
108
+
109
+ } //namespace Model
110
+ } //namespace Oinky