~drizzle-trunk/drizzle/development

1410.4.2 by Djellel E. Difallah
removing my
1
/* Copyright (C) 2000 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
1802.10.2 by Monty Taylor
Update all of the copyright headers to include the correct address.
14
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
1410.4.2 by Djellel E. Difallah
removing my
15
16
/*
17
  Code for handling red-black (balanced) binary trees.
18
  key in tree is allocated accrding to following:
19
20
  1) If size < 0 then tree will not allocate keys and only a pointer to
21
     each key is saved in tree.
22
     compare and search functions uses and returns key-pointer
23
24
  2) If size == 0 then there are two options:
25
       - key_size != 0 to tree_insert: The key will be stored in the tree.
26
       - key_size == 0 to tree_insert:  A pointer to the key is stored.
27
     compare and search functions uses and returns key-pointer.
28
29
  3) if key_size is given to init_tree then each node will continue the
30
     key and calls to insert_key may increase length of key.
31
     if key_size > sizeof(pointer) and key_size is a multiple of 8 (double
32
     allign) then key will be put on a 8 alligned adress. Else
33
     the key will be on adress (element+1). This is transparent for user
34
     compare and search functions uses a pointer to given key-argument.
35
36
  - If you use a free function for tree-elements and you are freeing
37
    the element itself, you should use key_size = 0 to init_tree and
38
    tree_search
39
40
  The actual key in TREE_ELEMENT is saved as a pointer or after the
41
  TREE_ELEMENT struct.
42
  If one uses only pointers in tree one can use tree_set_pointer() to
43
  change address of data.
44
45
  Implemented by monty.
46
*/
47
48
/*
49
  NOTE:
50
  tree->compare function should be ALWAYS called as
51
    (*tree->compare)(custom_arg, ELEMENT_KEY(tree,element), key)
52
  and not other way around, as
53
    (*tree->compare)(custom_arg, key, ELEMENT_KEY(tree,element))
54
*/
55
2173.2.1 by Monty Taylor
Fixes incorrect usage of include
56
#include <config.h>
1410.4.2 by Djellel E. Difallah
removing my
57
2173.2.1 by Monty Taylor
Fixes incorrect usage of include
58
#include <drizzled/tree.h>
59
#include <drizzled/internal/my_sys.h>
60
#include <drizzled/internal/m_string.h>
61
#include <drizzled/memory/root.h>
1410.4.2 by Djellel E. Difallah
removing my
62
63
#define BLACK		1
64
#define RED		0
65
#define DEFAULT_ALLOC_SIZE 8192
66
#define DEFAULT_ALIGN_SIZE 8192
67
68
#define ELEMENT_KEY(tree,element)\
69
(tree->offset_to_key ? (void*)((unsigned char*) element+tree->offset_to_key) :\
70
			*((void**) (element+1)))
71
#define ELEMENT_CHILD(element, offs) (*(TREE_ELEMENT**)((char*)element + offs))
72
73
namespace drizzled
74
{
75
76
77
static void delete_tree_element(TREE *,TREE_ELEMENT *);
78
static int tree_walk_left_root_right(TREE *,TREE_ELEMENT *,
79
				     tree_walk_action,void *);
80
static int tree_walk_right_root_left(TREE *,TREE_ELEMENT *,
81
				     tree_walk_action,void *);
82
static void left_rotate(TREE_ELEMENT **parent,TREE_ELEMENT *leaf);
83
static void right_rotate(TREE_ELEMENT **parent, TREE_ELEMENT *leaf);
84
static void rb_insert(TREE *tree,TREE_ELEMENT ***parent,
85
		      TREE_ELEMENT *leaf);
86
87
88
void init_tree(TREE *tree, size_t default_alloc_size, uint32_t memory_limit,
89
               uint32_t size, qsort_cmp2 compare, bool with_delete,
90
	       tree_element_free free_element, void *custom_arg)
91
{
92
  if (default_alloc_size < DEFAULT_ALLOC_SIZE)
93
    default_alloc_size= DEFAULT_ALLOC_SIZE;
94
  default_alloc_size= MY_ALIGN(default_alloc_size, DEFAULT_ALIGN_SIZE);
95
  memset(&tree->null_element, 0, sizeof(tree->null_element));
96
  tree->root= &tree->null_element;
97
  tree->compare= compare;
98
  tree->size_of_element= size > 0 ? (uint32_t) size : 0;
99
  tree->memory_limit= memory_limit;
100
  tree->free= free_element;
101
  tree->allocated= 0;
102
  tree->elements_in_tree= 0;
103
  tree->custom_arg = custom_arg;
104
  tree->null_element.colour= BLACK;
105
  tree->null_element.left=tree->null_element.right= 0;
106
  tree->flag= 0;
107
  if (!free_element &&
108
      (size <= sizeof(void*) || ((uint32_t) size & (sizeof(void*)-1))))
109
  {
110
    /*
111
      We know that the data doesn't have to be aligned (like if the key
112
      contains a double), so we can store the data combined with the
113
      TREE_ELEMENT.
114
    */
115
    tree->offset_to_key= sizeof(TREE_ELEMENT); /* Put key after element */
116
    /* Fix allocation size so that we don't lose any memory */
117
    default_alloc_size/= (sizeof(TREE_ELEMENT)+size);
118
    if (!default_alloc_size)
119
      default_alloc_size= 1;
120
    default_alloc_size*= (sizeof(TREE_ELEMENT)+size);
121
  }
122
  else
123
  {
124
    tree->offset_to_key= 0;		/* use key through pointer */
125
    tree->size_of_element+= sizeof(void*);
126
  }
127
  if (! (tree->with_delete= with_delete))
128
  {
2318.6.23 by Olaf van der Spek
Refactor
129
    tree->mem_root.init(default_alloc_size);
1410.4.2 by Djellel E. Difallah
removing my
130
    tree->mem_root.min_malloc= (sizeof(TREE_ELEMENT)+tree->size_of_element);
131
  }
132
}
133
134
static void free_tree(TREE *tree, myf free_flags)
135
{
136
  if (tree->root)				/* If initialized */
137
  {
138
    if (tree->with_delete)
139
      delete_tree_element(tree,tree->root);
140
    else
141
    {
142
      if (tree->free)
143
      {
144
        if (tree->memory_limit)
145
          (*tree->free)(NULL, free_init, tree->custom_arg);
146
	delete_tree_element(tree,tree->root);
147
        if (tree->memory_limit)
148
          (*tree->free)(NULL, free_end, tree->custom_arg);
149
      }
1487 by Brian Aker
More updates for memory::Root
150
      tree->mem_root.free_root(free_flags);
1410.4.2 by Djellel E. Difallah
removing my
151
    }
152
  }
153
  tree->root= &tree->null_element;
154
  tree->elements_in_tree= 0;
155
  tree->allocated= 0;
156
}
157
158
void delete_tree(TREE* tree)
159
{
160
  free_tree(tree, MYF(0)); /* free() mem_root if applicable */
161
}
162
163
void reset_tree(TREE* tree)
164
{
165
  /* do not free mem_root, just mark blocks as free */
166
  free_tree(tree, MYF(memory::MARK_BLOCKS_FREE));
167
}
168
169
170
static void delete_tree_element(TREE *tree, TREE_ELEMENT *element)
171
{
172
  if (element != &tree->null_element)
173
  {
174
    delete_tree_element(tree,element->left);
175
    if (tree->free)
176
      (*tree->free)(ELEMENT_KEY(tree,element), free_free, tree->custom_arg);
177
    delete_tree_element(tree,element->right);
178
    if (tree->with_delete)
179
      free((char*) element);
180
  }
181
}
182
183
184
/*
185
  insert, search and delete of elements
186
187
  The following should be true:
188
    parent[0] = & parent[-1][0]->left ||
189
    parent[0] = & parent[-1][0]->right
190
*/
191
192
TREE_ELEMENT *tree_insert(TREE *tree, void *key, uint32_t key_size,
193
                          void* custom_arg)
194
{
195
  int cmp;
196
  TREE_ELEMENT *element,***parent;
197
198
  parent= tree->parents;
199
  *parent = &tree->root; element= tree->root;
200
  for (;;)
201
  {
202
    if (element == &tree->null_element ||
203
	(cmp = (*tree->compare)(custom_arg, ELEMENT_KEY(tree,element),
204
                                key)) == 0)
205
      break;
206
    if (cmp < 0)
207
    {
208
      *++parent= &element->right; element= element->right;
209
    }
210
    else
211
    {
212
      *++parent = &element->left; element= element->left;
213
    }
214
  }
215
  if (element == &tree->null_element)
216
  {
217
    size_t alloc_size= sizeof(TREE_ELEMENT)+key_size+tree->size_of_element;
218
    tree->allocated+= alloc_size;
219
220
    if (tree->memory_limit && tree->elements_in_tree
221
                           && tree->allocated > tree->memory_limit)
222
    {
223
      reset_tree(tree);
224
      return tree_insert(tree, key, key_size, custom_arg);
225
    }
226
227
    key_size+= tree->size_of_element;
228
    if (tree->with_delete)
229
      element= (TREE_ELEMENT *) malloc(alloc_size);
230
    else
2318.6.40 by Olaf van der Spek
Refactor
231
      element= (TREE_ELEMENT *) tree->mem_root.alloc(alloc_size);
1410.4.2 by Djellel E. Difallah
removing my
232
    **parent= element;
233
    element->left= element->right= &tree->null_element;
234
    if (!tree->offset_to_key)
235
    {
236
      if (key_size == sizeof(void*))		 /* no length, save pointer */
237
	*((void**) (element+1))= key;
238
      else
239
      {
240
	*((void**) (element+1))= (void*) ((void **) (element+1)+1);
241
	memcpy(*((void **) (element+1)),key, key_size - sizeof(void*));
242
      }
243
    }
244
    else
245
      memcpy((unsigned char*) element + tree->offset_to_key, key, key_size);
246
    element->count= 1;			/* May give warning in purify */
247
    tree->elements_in_tree++;
248
    rb_insert(tree,parent,element);	/* rebalance tree */
249
  }
250
  else
251
  {
252
    if (tree->flag & TREE_NO_DUPS)
253
      return(NULL);
254
    element->count++;
255
    /* Avoid a wrap over of the count. */
256
    if (! element->count)
257
      element->count--;
258
  }
259
260
  return element;
261
}
262
263
void *tree_search_key(TREE *tree, const void *key,
264
                      TREE_ELEMENT **parents, TREE_ELEMENT ***last_pos,
265
                      enum ha_rkey_function flag, void *custom_arg)
266
{
267
  TREE_ELEMENT *element= tree->root;
268
  TREE_ELEMENT **last_left_step_parent= NULL, **last_right_step_parent= NULL;
269
  TREE_ELEMENT **last_equal_element= NULL;
270
271
/*
272
  TODO: support for HA_READ_KEY_OR_PREV, HA_READ_PREFIX flags if needed.
273
*/
274
275
  *parents = &tree->null_element;
276
  while (element != &tree->null_element)
277
  {
278
    int cmp;
279
280
    *++parents= element;
281
282
    if ((cmp= (*tree->compare)(custom_arg, ELEMENT_KEY(tree, element),
283
			       key)) == 0)
284
    {
285
      switch (flag) {
286
      case HA_READ_KEY_EXACT:
287
      case HA_READ_KEY_OR_NEXT:
288
      case HA_READ_BEFORE_KEY:
289
	last_equal_element= parents;
290
	cmp= 1;
291
	break;
292
      case HA_READ_AFTER_KEY:
293
	cmp= -1;
294
	break;
295
      case HA_READ_PREFIX_LAST:
296
      case HA_READ_PREFIX_LAST_OR_PREV:
297
	last_equal_element= parents;
298
	cmp= -1;
299
	break;
300
      default:
301
	return NULL;
302
      }
303
    }
304
    if (cmp < 0) /* element < key */
305
    {
306
      last_right_step_parent= parents;
307
      element= element->right;
308
    }
309
    else
310
    {
311
      last_left_step_parent= parents;
312
      element= element->left;
313
    }
314
  }
315
  switch (flag) {
316
  case HA_READ_KEY_EXACT:
317
  case HA_READ_PREFIX_LAST:
318
    *last_pos= last_equal_element;
319
    break;
320
  case HA_READ_KEY_OR_NEXT:
321
    *last_pos= last_equal_element ? last_equal_element : last_left_step_parent;
322
    break;
323
  case HA_READ_AFTER_KEY:
324
    *last_pos= last_left_step_parent;
325
    break;
326
  case HA_READ_PREFIX_LAST_OR_PREV:
327
    *last_pos= last_equal_element ? last_equal_element : last_right_step_parent;
328
    break;
329
  case HA_READ_BEFORE_KEY:
330
    *last_pos= last_right_step_parent;
331
    break;
332
  default:
333
    return NULL;
334
  }
335
336
  return *last_pos ? ELEMENT_KEY(tree, **last_pos) : NULL;
337
}
338
339
void *tree_search_next(TREE *tree, TREE_ELEMENT ***last_pos, int l_offs,
340
                       int r_offs)
341
{
342
  TREE_ELEMENT *x= **last_pos;
343
344
  if (ELEMENT_CHILD(x, r_offs) != &tree->null_element)
345
  {
346
    x= ELEMENT_CHILD(x, r_offs);
347
    *++*last_pos= x;
348
    while (ELEMENT_CHILD(x, l_offs) != &tree->null_element)
349
    {
350
      x= ELEMENT_CHILD(x, l_offs);
351
      *++*last_pos= x;
352
    }
353
    return ELEMENT_KEY(tree, x);
354
  }
355
  else
356
  {
357
    TREE_ELEMENT *y= *--*last_pos;
358
    while (y != &tree->null_element && x == ELEMENT_CHILD(y, r_offs))
359
    {
360
      x= y;
361
      y= *--*last_pos;
362
    }
363
    return y == &tree->null_element ? NULL : ELEMENT_KEY(tree, y);
364
  }
365
}
366
367
/*
368
  Expected that tree is fully balanced
369
  (each path from root to leaf has the same length)
370
*/
371
ha_rows tree_record_pos(TREE *tree, const void *key,
372
			enum ha_rkey_function flag, void *custom_arg)
373
{
374
  TREE_ELEMENT *element= tree->root;
375
  double left= 1;
376
  double right= tree->elements_in_tree;
377
378
  while (element != &tree->null_element)
379
  {
380
    int cmp;
381
382
    if ((cmp= (*tree->compare)(custom_arg, ELEMENT_KEY(tree, element),
383
			       key)) == 0)
384
    {
385
      switch (flag) {
386
      case HA_READ_KEY_EXACT:
387
      case HA_READ_BEFORE_KEY:
388
        cmp= 1;
389
        break;
390
      case HA_READ_AFTER_KEY:
391
        cmp= -1;
392
        break;
393
      default:
394
        return HA_POS_ERROR;
395
      }
396
    }
397
    if (cmp < 0) /* element < key */
398
    {
399
      element= element->right;
400
      left= (left + right) / 2;
401
    }
402
    else
403
    {
404
      element= element->left;
405
      right= (left + right) / 2;
406
    }
407
  }
408
409
  switch (flag) {
410
  case HA_READ_KEY_EXACT:
411
  case HA_READ_BEFORE_KEY:
412
    return (ha_rows) right;
413
  case HA_READ_AFTER_KEY:
414
    return (ha_rows) left;
415
  default:
416
    return HA_POS_ERROR;
417
  }
418
}
419
420
int tree_walk(TREE *tree, tree_walk_action action, void *argument, TREE_WALK visit)
421
{
422
  switch (visit) {
423
  case left_root_right:
424
    return tree_walk_left_root_right(tree,tree->root,action,argument);
425
  case right_root_left:
426
    return tree_walk_right_root_left(tree,tree->root,action,argument);
427
  }
428
429
  return 0;			/* Keep gcc happy */
430
}
431
432
static int tree_walk_left_root_right(TREE *tree, TREE_ELEMENT *element, tree_walk_action action, void *argument)
433
{
434
  int error;
435
  if (element->left)				/* Not null_element */
436
  {
437
    if ((error=tree_walk_left_root_right(tree,element->left,action,
438
					  argument)) == 0 &&
439
	(error=(*action)(ELEMENT_KEY(tree,element),
440
			  element->count,
441
			  argument)) == 0)
442
      error=tree_walk_left_root_right(tree,element->right,action,argument);
443
    return error;
444
  }
445
446
  return 0;
447
}
448
449
static int tree_walk_right_root_left(TREE *tree, TREE_ELEMENT *element, tree_walk_action action, void *argument)
450
{
451
  int error;
452
  if (element->right)				/* Not null_element */
453
  {
454
    if ((error=tree_walk_right_root_left(tree,element->right,action,
455
					  argument)) == 0 &&
456
	(error=(*action)(ELEMENT_KEY(tree,element),
457
			  element->count,
458
			  argument)) == 0)
459
     error=tree_walk_right_root_left(tree,element->left,action,argument);
460
    return error;
461
  }
462
463
  return 0;
464
}
465
466
467
/* Functions to fix up the tree after insert and delete */
468
469
static void left_rotate(TREE_ELEMENT **parent, TREE_ELEMENT *leaf)
470
{
471
  TREE_ELEMENT *y;
472
473
  y= leaf->right;
474
  leaf->right= y->left;
475
  parent[0]= y;
476
  y->left= leaf;
477
}
478
479
static void right_rotate(TREE_ELEMENT **parent, TREE_ELEMENT *leaf)
480
{
481
  TREE_ELEMENT *x;
482
483
  x= leaf->left;
484
  leaf->left= x->right;
485
  parent[0]= x;
486
  x->right= leaf;
487
}
488
489
static void rb_insert(TREE *tree, TREE_ELEMENT ***parent, TREE_ELEMENT *leaf)
490
{
491
  TREE_ELEMENT *y,*par,*par2;
492
493
  leaf->colour=RED;
494
  while (leaf != tree->root && (par=parent[-1][0])->colour == RED)
495
  {
496
    if (par == (par2=parent[-2][0])->left)
497
    {
498
      y= par2->right;
499
      if (y->colour == RED)
500
      {
501
	par->colour= BLACK;
502
	y->colour= BLACK;
503
	leaf= par2;
504
	parent-= 2;
505
	leaf->colour= RED;		/* And the loop continues */
506
      }
507
      else
508
      {
509
	if (leaf == par->right)
510
	{
511
	  left_rotate(parent[-1],par);
512
	  par= leaf;			/* leaf is now parent to old leaf */
513
	}
514
	par->colour= BLACK;
515
	par2->colour= RED;
516
	right_rotate(parent[-2],par2);
517
	break;
518
      }
519
    }
520
    else
521
    {
522
      y= par2->left;
523
      if (y->colour == RED)
524
      {
525
	par->colour= BLACK;
526
	y->colour= BLACK;
527
	leaf= par2;
528
	parent-= 2;
529
	leaf->colour= RED;		/* And the loop continues */
530
      }
531
      else
532
      {
533
	if (leaf == par->left)
534
	{
535
	  right_rotate(parent[-1],par);
536
	  par= leaf;
537
	}
538
	par->colour= BLACK;
539
	par2->colour= RED;
540
	left_rotate(parent[-2],par2);
541
	break;
542
      }
543
    }
544
  }
545
  tree->root->colour=BLACK;
546
}
547
548
} /* namespace drizzled */