61
61
// used for extra validation can optionally be provided. This should return:
62
62
// - true if a < b
63
63
// - false otherwise
64
- // ALLOCATOR must check for oom and exit, as RBTree does not handle the allocation failing.
65
64
// K needs to be of a type that is trivially destructible.
66
65
// The tree will call a value's destructor when its node is removed.
67
66
// Nodes are address stable and will not change during its lifetime.
@@ -468,13 +467,17 @@ class RBTree : public AbstractRBTree<K, RBNode<K, V>, COMPARATOR> {
468
467
469
468
RBNode<K, V>* allocate_node (const K& key) {
470
469
void * node_place = _allocator.allocate (sizeof (RBNode<K, V>));
471
- assert (node_place != nullptr , " rb-tree allocator must exit on failure" );
470
+ if (node_place == nullptr ) {
471
+ return nullptr ;
472
+ }
472
473
return new (node_place) RBNode<K, V>(key);
473
474
}
474
475
475
476
RBNode<K, V>* allocate_node (const K& key, const V& val) {
476
477
void * node_place = _allocator.allocate (sizeof (RBNode<K, V>));
477
- assert (node_place != nullptr , " rb-tree allocator must exit on failure" );
478
+ if (node_place == nullptr ) {
479
+ return nullptr ;
480
+ }
478
481
return new (node_place) RBNode<K, V>(key, val);
479
482
}
480
483
@@ -485,16 +488,21 @@ class RBTree : public AbstractRBTree<K, RBNode<K, V>, COMPARATOR> {
485
488
486
489
// Inserts a node with the given key/value into the tree,
487
490
// if the key already exist, the value is updated instead.
488
- void upsert (const K& key, const V& val, const RBNode<K, V>* hint_node = nullptr ) {
491
+ // Returns false if and only if allocation of a new node failed.
492
+ bool upsert (const K& key, const V& val, const RBNode<K, V>* hint_node = nullptr ) {
489
493
Cursor node_cursor = cursor (key, hint_node);
490
494
RBNode<K, V>* node = node_cursor.node ();
491
495
if (node != nullptr ) {
492
496
node->set_val (val);
493
- return ;
497
+ return true ;
494
498
}
495
499
496
500
node = allocate_node (key, val);
501
+ if (node == nullptr ) {
502
+ return false ;
503
+ }
497
504
insert_at_cursor (node, node_cursor);
505
+ return true ;
498
506
}
499
507
500
508
// Finds the value of the node associated with the given key.
@@ -545,12 +553,12 @@ class RBTree : public AbstractRBTree<K, RBNode<K, V>, COMPARATOR> {
545
553
}
546
554
};
547
555
548
- template <MemTag mem_tag>
556
+ template <MemTag mem_tag, AllocFailType strategy >
549
557
class RBTreeCHeapAllocator {
550
558
public:
551
559
void * allocate (size_t sz) {
552
560
void * allocation = os::malloc (sz, mem_tag);
553
- if (allocation == nullptr ) {
561
+ if (allocation == nullptr && strategy == AllocFailStrategy::EXIT_OOM ) {
554
562
vm_exit_out_of_memory (sz, OOM_MALLOC_ERROR,
555
563
" red-black tree failed allocation" );
556
564
}
@@ -560,8 +568,8 @@ class RBTreeCHeapAllocator {
560
568
void free (void * ptr) { os::free (ptr); }
561
569
};
562
570
563
- template <typename K, typename V, typename COMPARATOR, MemTag mem_tag>
564
- using RBTreeCHeap = RBTree<K, V, COMPARATOR, RBTreeCHeapAllocator<mem_tag>>;
571
+ template <typename K, typename V, typename COMPARATOR, MemTag mem_tag, AllocFailType strategy = AllocFailStrategy::EXIT_OOM >
572
+ using RBTreeCHeap = RBTree<K, V, COMPARATOR, RBTreeCHeapAllocator<mem_tag, strategy >>;
565
573
566
574
template <typename K, typename COMPARATOR>
567
575
using IntrusiveRBTree = AbstractRBTree<K, IntrusiveRBNode, COMPARATOR>;
0 commit comments