BAM
Abstract Machine for Bottom-Up Evaluation with the Push Method
cur_list.h
Go to the documentation of this file.
1 // ============================================================================
2 // Project: Deductive Database
3 // Filename: cur_list.h
4 // Purpose: Cursor for list of objects/tuples
5 // Last Change: 04.08.2017
6 // Language: C++
7 // EMail: brass@informatik.uni-halle.de
8 // WWW: http://www.informatik.uni-halle.de/~brass/
9 // Address: Feldschloesschen 15, D-06120 Halle (Saale), GERMANY
10 // Copyright: (c) 2015-2017 by Stefan Brass
11 // License: See file "LICENSE" for copying conditions.
12 // Note: There is no warranty at all - this code may contain bugs.
13 // ============================================================================
14 
15 
22 //=============================================================================
23 // Include File Frame:
24 //=============================================================================
25 
26 #ifndef CUR_LIST_INCLUDED
27 #define CUR_LIST_INCLUDED
28 
29 //=============================================================================
30 // Used Types and Macros:
31 //=============================================================================
32 
33 #ifndef VER_INCLUDED
34 #include "../base/ver.h"
35 #endif
36 
37 #ifndef STR_INCLUDED
38 #include "../base/str.h"
39 #endif
40 
41 #ifndef CHECK_INCLUDED
42 #include "../base/check.h"
43 #endif
44 
45 #ifndef STACK_INCLUDED
46 #include "../bds/stack.h"
47 #endif
48 
49 #ifndef LIST_INCLUDED
50 #include "../rel/list.h"
51 #endif
52 
53 
54 //=============================================================================
55 // Private Constants:
56 //=============================================================================
57 
58 //-----------------------------------------------------------------------------
59 // CUR_LIST_MAGIC: Magic number (identifies objects of this class).
60 //-----------------------------------------------------------------------------
61 
62 static const long CUR_LIST_MAGIC = 0x434C540AL; // 'CLT\n'
63 
64 //=============================================================================
65 // Class Template for Flexible Arrays (Lists with Index Access):
66 //=============================================================================
67 
68 template<class T> class cur_list_c {
69  public:
70 
71 //-----------------------------------------------------------------------------
72 // Constructor:
73 //-----------------------------------------------------------------------------
74 
75  cur_list_c(const list_c<T> *list) {
76 
77  // Check parameter:
78  CHECK(list != static_cast<list_c<T>*>(0),
79  "cur_list_c::constructor: list is NULL");
80  CHECK_PAR(list, "cur_list_c::constructor");
81 
82  // Initialize attributes:
83  List = list;
84  StartPos = 0;
85  EndPos = 0;
86  TotalRest = 0;
87  LeafPtr = LIST_LEAF_NULL;
88  MidPtr = LIST_MID_NULL;
89  TopPtr = LIST_TOP_NULL;
90  LeafRest = 0;
91  MidRest = 0;
92  TopRest = 0;
93 
94  // Set Magic number:
95  CHECK_CODE(Magic = CUR_LIST_MAGIC);
96  }
97 
98 //-----------------------------------------------------------------------------
99 // Destructor:
100 //-----------------------------------------------------------------------------
101 
102  ~cur_list_c()
103  {
104  // Check this object:
105  CHECK_VALID("cur_list_c::destructor");
106 
107  // Make this object invalid:
108  CHECK_CODE(Magic = 0);
109  }
110 
111 //-----------------------------------------------------------------------------
112 // Open cursor over entire list (to current end):
113 //-----------------------------------------------------------------------------
114 
115  inline void open() {
116 
117  // Check this object:
118  CHECK_VALID("cur_list_c::open()");
119 
120  // The real work is done in method init(start_pos, end_pos):
121  init(0, List->NumRows);
122  }
123 
124 //-----------------------------------------------------------------------------
125 // Open cursor for looping through a sublist (start pos to current end):
126 //-----------------------------------------------------------------------------
127 
128  inline void open(int start_pos) {
129 
130  // Check this object:
131  CHECK_VALID("cur_list_c::open(start_pos)");
132 
133  // Check Parameter:
134  CHECK(start_pos >= 0, "cur_list_c::open: start_pos < 0");
135  CHECK(start_pos <= List->NumRows,
136  "cur_list_c::open: start_pos too big");
137 
138  // Set the index range and the number of remaining tuples:
139  StartPos = start_pos;
140  EndPos = List->NumRows;
141  TotalRest = EndPos - StartPos;
142 
143  // No tuples in each node forces initialization in fetch:
144  LeafRest = 0;
145  MidRest = 0;
146  TopRest = 0;
147 
148  // Not really necessary, but maybe safer:
149  LeafPtr = LIST_LEAF_NULL;
150  MidPtr = LIST_MID_NULL;
151  TopPtr = LIST_TOP_NULL;
152  }
153 
154 //-----------------------------------------------------------------------------
155 // fetch: Get next tuple, returns false if there is no further tuple.
156 //-----------------------------------------------------------------------------
157 
158  inline bool fetch() {
159 
160  // Check whether there are still tuples left:
161  if(TotalRest-- <= 0)
162  return false;
163 
164  // Now we must make LeafPtr point to the current tuple.
165  // Most common case: Simply increment it:
166  if(LeafRest-- > 0) {
167  LeafPtr++;
168  return true;
169  }
170 
171  // Switch to next leaf:
172  if(MidRest-- > 0) {
173  MidPtr++;
174  LeafPtr = *MidPtr;
175  LeafRest = PAGE_SIZE(T) - 1;
176  return true;
177  }
178 
179  // Switch to next mid level branch node:
180  if(TopRest-- > 0) {
181  TopPtr++;
182  MidPtr = *TopPtr;
183  MidRest = PAGE_SIZE(T*) - 1;
184  LeafPtr = *MidPtr;
185  LeafRest = PAGE_SIZE(T) - 1;
186  return true;
187  }
188 
189  // Nothing worked. Must initialize everything for first tuple:
190  int leaf_offset = StartPos % PAGE_SIZE(T);
191  int mid_offset = StartPos / PAGE_SIZE(T);
192  int top_offset = mid_offset / PAGE_SIZE(T*);
193  mid_offset = mid_offset % PAGE_SIZE(T*);
194  CHECK(leaf_offset >= 0, "cur_list_c::fetch: leaf_offset < 0");
195  CHECK(mid_offset >= 0, "cur_list_c::fetch: mid_offset < 0");
196  CHECK(top_offset >= 0, "cur_list_c::fetch: top_offset < 0");
197  CHECK(leaf_offset < PAGE_SIZE(T),
198  "cur_list_c::fetch: leaf_offset too big");
199  CHECK(mid_offset < PAGE_SIZE(T*),
200  "cur_list_c::fetch: mid_offset too big");
201  CHECK(top_offset < PAGE_SIZE(T**),
202  "cur_list_c::fetch: top_offset too big");
203  switch(List->Height) {
204  case 0:
206  "cur_list_c::fetch: TotalRest>0 but list empty");
207  return false;
208  case 1:
209  TopRest = 0;
210  MidRest = 0;
211  LeafPtr = List->LeafNode + leaf_offset;
212  LeafRest = PAGE_SIZE(T) - 1 - leaf_offset;
213  break;
214  case 2:
215  TopRest = 0;
216  MidPtr = List->MidNode + mid_offset;
217  MidRest = PAGE_SIZE(T*) - 1 - mid_offset;
218  LeafPtr = *MidPtr + leaf_offset;
219  LeafRest = PAGE_SIZE(T) - 1 - leaf_offset;
220  break;
221  case 3:
222  TopPtr = List->TopNode + top_offset;
223  TopRest = PAGE_SIZE(T**) - 1 - top_offset;
224  MidPtr = *TopPtr + mid_offset;
225  MidRest = PAGE_SIZE(T*) - 1 - mid_offset;
226  LeafPtr = *MidPtr + leaf_offset;
227  LeafRest = PAGE_SIZE(T) - 1 - leaf_offset;
228  break;
229  default:
231  "cur_list_c::fetch: Invalid height");
232  return false;
233  }
234  return true;
235  }
236 
237 //-----------------------------------------------------------------------------
238 // row: Get current row/tuple:
239 //-----------------------------------------------------------------------------
240 
241  inline T* row() {
242  // Check this object:
243  CHECK_VALID("cur_list_c::row");
244 
245  // Check state:
246  CHECK(LeafPtr != LIST_LEAF_NULL,
247  "cur_list_c::row: No current tuple");
248 
249  // Return pointer to current tuple:
250  return LeafPtr;
251  }
252 
253 
254 
255 //-----------------------------------------------------------------------------
256 // push: Save the cursor state on a stack.
257 //-----------------------------------------------------------------------------
258 
259  bool push(stack_c<int> *stack) {
260 
261  // Check this object:
262  CHECK_VALID("cur_list_c::push");
263 
264  // Save new start position:
265  int start_pos = EndPos - TotalRest;
266  CHECK(start_pos >= 0, "cur_list_c::push: start_pos < 0");
267  CHECK(start_pos <= EndPos,
268  "cur_list_c::push: start_pos too big");
269  if(!stack->push(start_pos))
270  return false;
271 
272  // The end position must also be saved
273  // because new rows might be inserted into the list:
274  if(!stack->push(EndPos))
275  return false;
276 
277  // Ok:
278  return true;
279  }
280 
281 //-----------------------------------------------------------------------------
282 // pop: Restore the cursor state from a stack.
283 //-----------------------------------------------------------------------------
284 
285  void pop(stack_c<int> *stack) {
286 
287  // Check this object:
288  CHECK_VALID("cur_list_c::pop");
289 
290  // Reopen this cursor at the saved start position:
291  int end_pos = stack->pop();
292  int start_pos = stack->pop();
293  CHECK(start_pos >= 0, "cur_list_c::pop: start_pos < 0");
294  CHECK(end_pos >= 0, "cur_list_c::pop: end_pos < 0");
295  CHECK(start_pos <= end_pos,
296  "cur_list_c::pop: start_pos too big");
297  CHECK(end_pos <= List->NumRows,
298  "cur_list_c::pop: end_pos too big");
299  init(start_pos, end_pos);
300  }
301 
302 //-----------------------------------------------------------------------------
303 // Close cursor:
304 //-----------------------------------------------------------------------------
305 
306  inline void close() {
307  // Check this object:
308  CHECK_VALID("cur_list_c::close");
309  }
310 
311 
312 //=============================================================================
313 // Auxiliary Methods:
314 //=============================================================================
315 
316  private:
317 
318 //-----------------------------------------------------------------------------
319 // Set up a cursor for a given sublist (used in open and pop):
320 //-----------------------------------------------------------------------------
321 
322  inline void init(int start_pos, int end_pos) {
323 
324  // Check this object:
325  CHECK_VALID("cur_list_c::init");
326 
327  // Check Parameters:
328  CHECK(start_pos >= 0, "cur_list_c::init: start_pos < 0");
329  CHECK(start_pos <= List->NumRows,
330  "cur_list_c::init: start_pos too big");
331  CHECK(end_pos >= 0, "cur_list_c::init: end_pos < 0");
332  CHECK(end_pos <= List->NumRows,
333  "cur_list_c::init: end_pos too big");
334 
335  // Set the index range and the number of remaining tuples:
336  StartPos = start_pos;
337  EndPos = end_pos;
338  TotalRest = EndPos - StartPos;
339 
340  // No tuples in each node forces initialization in fetch:
341  LeafRest = 0;
342  MidRest = 0;
343  TopRest = 0;
344 
345  // Not really necessary, but maybe safer:
346  LeafPtr = LIST_LEAF_NULL;
347  MidPtr = LIST_MID_NULL;
348  TopPtr = LIST_TOP_NULL;
349  }
350 
351 //=============================================================================
352 // Debugging Support:
353 //=============================================================================
354 
355 //-----------------------------------------------------------------------------
356 // Copy-constructor and assignment operator are not supported for this class:
357 //-----------------------------------------------------------------------------
358 
359  private:
360 
361  cur_list_c(const cur_list_c& obj); // Not implemented
362  cur_list_c& operator=(const cur_list_c& obj); // Not implemented
363 
364 
365 //-----------------------------------------------------------------------------
366 // check: Check the integrity of this object, return error message or NULL.
367 //-----------------------------------------------------------------------------
368 
369 #if VER_DEBUG
370  // Integrity check:
371  public:
372  str_t check() const {
373 
374  // Check magic number:
375  if(Magic != CUR_LIST_MAGIC)
376  return "wrong magic number";
377 
378  // Check that list is defined:
379  if(!List)
380  CHECK_ERR("list is null");
381 
382  // Check global positions:
383  if(StartPos < 0)
384  CHECK_ERR("StartPos is negative");
385  if(StartPos > List->NumRows)
386  CHECK_ERR("StartPos is bigger than list length");
387  if(EndPos < 0)
388  CHECK_ERR("EndPos is negative");
389  if(EndPos > List->NumRows)
390  CHECK_ERR("EndPos is bigger than list length");
391  if(StartPos > EndPos + 1)
392  CHECK_ERR("StartPos > EndPos + 1");
393  if(TotalRest > EndPos - StartPos)
394  CHECK_ERR("TotalRest too big");
395 
396  // Check remaining number of entries in pages:
397  if(LeafRest < 0)
398  CHECK_ERR("LeafRest is negative");
399  if(MidRest < 0)
400  CHECK_ERR("MidRest is negative");
401  if(TopRest < 0)
402  CHECK_ERR("TopRest is negative");
403  if(LeafRest >= PAGE_SIZE(T))
404  CHECK_ERR("LeafRest too big");
405  if(MidRest >= PAGE_SIZE(T*))
406  CHECK_ERR("MidRest too big");
407  if(TopRest >= PAGE_SIZE(T**))
408  CHECK_ERR("TopRest too big");
409 
410  // Check that pointers are defined:
411  if(LeafRest > 0 && LeafPtr == LIST_LEAF_NULL)
412  CHECK_ERR("LeafRest is positive, but pointer is null");
413  if(MidRest > 0 && MidPtr == LIST_MID_NULL)
414  CHECK_ERR("MidRest is positive, but pointer is null");
415  if(TopRest > 0 && TopPtr == LIST_TOP_NULL)
416  CHECK_ERR("TopRest is positive, but pointer is null");
417 
418  // Check consistency of pointers:
419  if(MidPtr != LIST_MID_NULL &&
420  LeafPtr != *MidPtr +
421  (PAGE_SIZE(T) - LeafRest - 1))
422  CHECK_ERR("LeafPtr inconsistent with MidPtr+Rest");
423  if(TopPtr != LIST_TOP_NULL &&
424  MidPtr != *TopPtr +
425  (PAGE_SIZE(T*) - MidRest - 1))
426  CHECK_ERR("MidPtr inconsistent with TopPtr+Rest");
427 
428  // At least, the root pointer must be within the list page:
429  switch(List->Height) {
430  case 0:
431  break;
432  case 1:
433  if(LeafRest > 0) {
434  if(LeafPtr < List->LeafNode)
435  CHECK_ERR("Invalid LeafPtr (<)");
436  if(LeafPtr >= List->LeafNode + PAGE_SIZE(T))
437  CHECK_ERR("Invalid LeafPtr (>=)");
438  if(LeafPtr != List->LeafNode +
439  (PAGE_SIZE(T)-LeafRest-1))
440  CHECK_ERR("Invalid LeafPtr (!=)");
441  }
442  break;
443  case 2:
444  if(MidRest > 0) {
445  if(MidPtr < List->MidNode)
446  CHECK_ERR("Invalid MidPtr (<)");
447  if(MidPtr >= List->MidNode + PAGE_SIZE(T*))
448  CHECK_ERR("Invalid MidPtr (>=)");
449  if(MidPtr != List->MidNode +
450  (PAGE_SIZE(T*)-MidRest-1))
451  CHECK_ERR("Invalid MidPtr (!=)");
452  }
453  break;
454  case 3:
455  if(TopRest > 0) {
456  if(TopPtr < List->TopNode)
457  CHECK_ERR("Invalid TopPtr (<)");
458  if(TopPtr >= List->TopNode + PAGE_SIZE(T**))
459  CHECK_ERR("Invalid TopPtr (>=)");
460  if(TopPtr != List->TopNode +
461  (PAGE_SIZE(T**)-TopRest-1))
462  CHECK_ERR("Invalid TopPtr (!=)");
463  }
464  break;
465  default:
466  CHECK_ERR("Invalid height");
467  }
468 
469  // Ok:
470  return STR_NULL;
471  }
472 
473  // Magic number (identifies objects of this class for debugging).
474  private:
475  long Magic; // Must be "CUR_LIST_MAGIC".
476 #endif
477 
478 //-----------------------------------------------------------------------------
479 // dump: Show data structure.
480 //-----------------------------------------------------------------------------
481 
482 #if VER_DUMP
483 
484  public:
485 
486 void dump(str_t headline = STR_NULL) const
487 {
488  // Headline:
489  if(headline == STR_NULL)
490  headline = "Cursor for List";
491  err_c::dump_begin(headline);
492 
493  // Basic information:
494  err_c::dump_str("List Name: '");
495  err_c::dump_str(List->Name);
496  err_c::dump_str("'");
497  err_c::dump_nl();
498  err_c::dump_str("Start Pos.: ");
499  err_c::dump_int(StartPos);
500  err_c::dump_nl();
501  err_c::dump_str("End Pos.: ");
502  err_c::dump_int(EndPos);
503  err_c::dump_nl();
504  err_c::dump_str("Current Pos.: ");
505  err_c::dump_int(EndPos - TotalRest);
506  err_c::dump_nl();
507  err_c::dump_str("TotalRest: ");
508  err_c::dump_int(TotalRest);
509  err_c::dump_nl();
510  err_c::dump_str("TopRest: ");
511  err_c::dump_int(TopRest);
512  err_c::dump_nl();
513  err_c::dump_str("MidRest: ");
514  err_c::dump_int(MidRest);
515  err_c::dump_nl();
516  err_c::dump_str("LeafRest: ");
517  err_c::dump_int(LeafRest);
518  err_c::dump_nl();
519  err_c::dump_str("TopPtr: ");
520  err_c::dump_ptr(TopPtr);
521  err_c::dump_nl();
522  err_c::dump_str("MidPtr: ");
523  err_c::dump_ptr(MidPtr);
524  err_c::dump_nl();
525  err_c::dump_str("LeafPtr: ");
526  err_c::dump_ptr(LeafPtr);
527  err_c::dump_nl();
528  err_c::dump_str("Height: ");
529  err_c::dump_int(List->Height);
530  err_c::dump_nl();
531  err_c::dump_str("Curr. TopNode: ");
532  err_c::dump_ptr(List->TopNode);
533  err_c::dump_nl();
534  err_c::dump_str("Curr. MidNode: ");
535  err_c::dump_ptr(List->MidNode);
536  err_c::dump_nl();
537  err_c::dump_str("Curr. LeafNode: ");
538  err_c::dump_ptr(List->LeafNode);
539  err_c::dump_nl();
540  err_c::dump_str("Page Size: ");
542  err_c::dump_str(" Bytes");
543  err_c::dump_nl();
544  err_c::dump_str("PAGE_SIZE(T): ");
545  err_c::dump_int(PAGE_SIZE(T));
546  err_c::dump_nl();
547  err_c::dump_str("PAGE_SIZE(T*): ");
548  err_c::dump_int(PAGE_SIZE(T*));
549  err_c::dump_nl();
550  err_c::dump_nl();
551 
552  // Done:
553  err_c::dump_end();
554 }
555 
556 #endif
557 
558 
559 //=============================================================================
560 // Private Object Members:
561 //=============================================================================
562 
563  private:
564 
565  // List: List to which this cursor belongs:
566  const list_c<T> *List;
567 
568  // StartPos: Index/Position in the list where cursor starts
569  // (if cursor is pushed and popped again, this is the popped value):
570  int StartPos;
571 
572  // EndPos: Current length of the list when the cursor was opened
573  // (so that values inserted into the list after the open are not
574  // returned by the cursor):
575  int EndPos;
576 
577  // TotalRest: Number of entries the cursor still has to return
578  // (note that this can become negative, if one fetches several times
579  // at the end of the scan, but this means the same as 0):
580  int TotalRest;
581 
582  // LeafRest: Number of entries still remaining in the current leaf node
583  // (not counting the current entry, to which LeafPtr points).
584  // Note: It is not guaranteed that this number of entries in the node
585  // are actually filled, so it is necessary to check TotalRest first.
586  int LeafRest;
587 
588  // MidRest: Number of slots still remaining in the current mid level
589  // node (not counting the current entry to which MidPtr points).
590  int MidRest;
591 
592  // TopRest: Number of slots still remaining in the top level node
593  // (not counting the current entry to which TopPtr points):
594  int TopRest;
595 
596  // LeafPtr: Pointer to the current value (tuple) in the scan
597  // (this is only usable if LeafRest > 0):
598  T* LeafPtr;
599 
600  // MidPtr: Pointer to the current entry in the mid level node
601  // (i.e. this points to the current leaf, if it is not null,
602  // so there is a mid level node. This is only usable if MidRest > 0):
603  T** MidPtr;
604 
605  // TopPtr: Pointer to the current entry in the top level node
606  // (i.e. this points to the current mid level node, if it is not null,
607  // i.e. there is a top node. This is only usable if TopRest > 0):
608  T*** TopPtr;
609 
610 //=============================================================================
611 // End of Class Template:
612 //=============================================================================
613 
614 };
615 
616 
617 //=============================================================================
618 // End of Include File:
619 //=============================================================================
620 
621 #endif
622 
#define CHECK_CODE(CODE)
Definition: check.h:167
static void dump_ptr(const void *p)
Definition: err.cpp:791
#define CHECK_ERR(MSG)
Definition: check.h:182
static void dump_str(str_t str)
Definition: err.cpp:705
#define VER_PAGESIZE
Definition: ver.h:186
#define CHECK_IMPOSSIBLE(MSG)
Definition: check.h:151
#define CHECK_VALID(EX)
Definition: check.h:85
static void dump_begin(str_t headline)
Definition: err.cpp:685
const char * str_t
Definition: str.h:41
Definition: list.h:90
#define STR_NULL
Definition: str.h:52
Definition: cur_list.h:68
static void dump_end()
Definition: err.cpp:811
static void dump_int(int n)
Definition: err.cpp:739
static void dump_nl()
Definition: err.cpp:717
#define CHECK(EX, MSG)
Definition: check.h:69
#define CHECK_PAR(PAR, PLACE)
Definition: check.h:102