@@ -391,14 +391,30 @@ class HighsHashTree {
391391
392392 struct BranchNode {
393393 Occupation occupation;
394- NodePtr child[1 ];
394+
395+ NodePtr* children () { return reinterpret_cast <NodePtr*>(this + 1 ); }
396+
397+ const NodePtr* children () const {
398+ return reinterpret_cast <const NodePtr*>(this + 1 );
399+ }
400+
401+ NodePtr& child (int index) { return children ()[index]; }
402+
403+ const NodePtr& child (int index) const { return children ()[index]; }
404+
405+ NodePtr* childPtr (int index) { return children () + index; }
406+
407+ const NodePtr* childPtr (int index) const { return children () + index; }
395408 };
396409
410+ static_assert (sizeof (BranchNode) % alignof (NodePtr) == 0 ,
411+ " BranchNode trailing storage must stay NodePtr aligned" );
412+
397413 // allocate branch nodes in multiples of 64 bytes to reduce allocator stress
398414 // with different sizes and reduce reallocations of nodes
399415 static constexpr size_t getBranchNodeSize (int numChilds) {
400- return (sizeof (BranchNode) + size_t (numChilds - 1 ) * sizeof (NodePtr) + 63 ) &
401- ~63 ;
416+ return (sizeof (BranchNode) + size_t (numChilds) * sizeof (NodePtr) + 63 ) &
417+ ~size_t ( 63 ) ;
402418 };
403419
404420 static BranchNode* createBranchingNode (int numChilds) {
@@ -421,20 +437,19 @@ class HighsHashTree {
421437 size_t rightSize = rightChilds * sizeof (NodePtr);
422438
423439 if (newSize == getBranchNodeSize (location + rightChilds)) {
424- memmove (& branch->child [ location + 1 ], & branch->child [ location] ,
440+ memmove (branch->childPtr ( location + 1 ), branch->childPtr ( location) ,
425441 rightSize);
426442
427443 return branch;
428444 }
429445
430446 BranchNode* newBranch = (BranchNode*)::operator new (newSize);
431- // sizeof(Branch) already contains the size for 1 pointer. So we just
432- // need to add the left and right sizes up for the number of
433- // additional pointers
434- size_t leftSize = sizeof (BranchNode) + (location - 1 ) * sizeof (NodePtr);
447+ // copy the header plus the pointers left of the insertion index into the
448+ // new storage
449+ size_t leftSize = sizeof (BranchNode) + size_t (location) * sizeof (NodePtr);
435450
436451 memcpy (newBranch, branch, leftSize);
437- memcpy (& newBranch->child [ location + 1 ], & branch->child [ location] ,
452+ memcpy (newBranch->childPtr ( location + 1 ), branch->childPtr ( location) ,
438453 rightSize);
439454
440455 destroyBranchingNode (branch);
@@ -573,7 +588,7 @@ class HighsHashTree {
573588 branch->occupation .num_set_until (static_cast <uint8_t >(pos)) - 1 ;
574589
575590 do {
576- if (find_recurse (branch->child [j] ,
591+ if (find_recurse (branch->child (j) ,
577592 compute_hash (leaf->entries [i].key ()), hashPos + 1 ,
578593 leaf->entries [i].key ()))
579594 return &leaf->entries [i];
@@ -603,7 +618,7 @@ class HighsHashTree {
603618 // threshold
604619 int childEntries = 0 ;
605620 for (int i = 0 ; i <= newNumChild; ++i) {
606- childEntries += branch->child [i] .numEntriesEstimate ();
621+ childEntries += branch->child (i) .numEntriesEstimate ();
607622 if (childEntries > kLeafBurstThreshold ) break ;
608623 }
609624
@@ -617,7 +632,7 @@ class HighsHashTree {
617632 // accesses of nodes that are not in cache.
618633 childEntries = 0 ;
619634 for (int i = 0 ; i <= newNumChild; ++i)
620- childEntries += branch->child [i] .numEntries ();
635+ childEntries += branch->child (i) .numEntries ();
621636
622637 // check again if we exceed due to the extremely unlikely case
623638 // of having less than 5 list nodes with together more than 30 entries
@@ -628,28 +643,28 @@ class HighsHashTree {
628643 InnerLeaf<1 >* newLeafSize1 = new InnerLeaf<1 >;
629644 newNode = newLeafSize1;
630645 for (int i = 0 ; i <= newNumChild; ++i)
631- mergeIntoLeaf (newLeafSize1, hashPos, branch->child [i] );
646+ mergeIntoLeaf (newLeafSize1, hashPos, branch->child (i) );
632647 break ;
633648 }
634649 case 2 : {
635650 InnerLeaf<2 >* newLeafSize2 = new InnerLeaf<2 >;
636651 newNode = newLeafSize2;
637652 for (int i = 0 ; i <= newNumChild; ++i)
638- mergeIntoLeaf (newLeafSize2, hashPos, branch->child [i] );
653+ mergeIntoLeaf (newLeafSize2, hashPos, branch->child (i) );
639654 break ;
640655 }
641656 case 3 : {
642657 InnerLeaf<3 >* newLeafSize3 = new InnerLeaf<3 >;
643658 newNode = newLeafSize3;
644659 for (int i = 0 ; i <= newNumChild; ++i)
645- mergeIntoLeaf (newLeafSize3, hashPos, branch->child [i] );
660+ mergeIntoLeaf (newLeafSize3, hashPos, branch->child (i) );
646661 break ;
647662 }
648663 case 4 : {
649664 InnerLeaf<4 >* newLeafSize4 = new InnerLeaf<4 >;
650665 newNode = newLeafSize4;
651666 for (int i = 0 ; i <= newNumChild; ++i)
652- mergeIntoLeaf (newLeafSize4, hashPos, branch->child [i] );
667+ mergeIntoLeaf (newLeafSize4, hashPos, branch->child (i) );
653668 break ;
654669 }
655670 default :
@@ -667,19 +682,18 @@ class HighsHashTree {
667682 size_t rightSize = (newNumChild - location) * sizeof (NodePtr);
668683 if (newSize == getBranchNodeSize (newNumChild + 1 )) {
669684 // allocated size class is the same, so we do not allocate a new node
670- memmove (& branch->child [ location], & branch->child [ location + 1 ] ,
685+ memmove (branch->childPtr ( location), branch->childPtr ( location + 1 ) ,
671686 rightSize);
672687 newNode = branch;
673688 } else {
674689 // allocated size class changed, so we allocate a smaller branch node
675690 BranchNode* compressedBranch = (BranchNode*)::operator new (newSize);
676691 newNode = compressedBranch;
677692
678- size_t leftSize =
679- offsetof (BranchNode, child) + location * sizeof (NodePtr);
693+ size_t leftSize = sizeof (BranchNode) + size_t (location) * sizeof (NodePtr);
680694 memcpy (compressedBranch, branch, leftSize);
681- memcpy (& compressedBranch->child [ location], &branch-> child [location + 1 ] ,
682- rightSize);
695+ memcpy (compressedBranch->childPtr ( location) ,
696+ branch-> childPtr (location + 1 ), rightSize);
683697
684698 destroyBranchingNode (branch);
685699 }
@@ -775,16 +789,16 @@ class HighsHashTree {
775789 branch->occupation = occupation;
776790
777791 if (hashPos + 1 == kMaxDepth ) {
778- for (int i = 0 ; i < branchSize; ++i) branch->child [i] = nullptr ;
792+ for (int i = 0 ; i < branchSize; ++i) branch->child (i) = nullptr ;
779793
780794 for (int i = 0 ; i < leaf->size ; ++i) {
781795 int pos =
782796 occupation.num_set_until (get_first_chunk16 (leaf->hashes [i])) -
783797 1 ;
784- if (branch->child [ pos] .getType () == kEmpty )
785- branch->child [ pos] = new ListLeaf (std::move (leaf->entries [i]));
798+ if (branch->child ( pos) .getType () == kEmpty )
799+ branch->child ( pos) = new ListLeaf (std::move (leaf->entries [i]));
786800 else {
787- ListLeaf* listLeaf = branch->child [ pos] .getListLeaf ();
801+ ListLeaf* listLeaf = branch->child ( pos) .getListLeaf ();
788802 ListNode* newNode = new ListNode (std::move (listLeaf->first ));
789803 listLeaf->first .next = newNode;
790804 listLeaf->first .entry = std::move (leaf->entries [i]);
@@ -797,11 +811,11 @@ class HighsHashTree {
797811 ListLeaf* listLeaf;
798812
799813 int pos = occupation.num_set_until (get_hash_chunk (hash, hashPos)) - 1 ;
800- if (branch->child [ pos] .getType () == kEmpty ) {
814+ if (branch->child ( pos) .getType () == kEmpty ) {
801815 listLeaf = new ListLeaf (std::move (entry));
802- branch->child [ pos] = listLeaf;
816+ branch->child ( pos) = listLeaf;
803817 } else {
804- listLeaf = branch->child [ pos] .getListLeaf ();
818+ listLeaf = branch->child ( pos) .getListLeaf ();
805819 ListNode* newNode = new ListNode (std::move (listLeaf->first ));
806820 listLeaf->first .next = newNode;
807821 listLeaf->first .entry = std::move (entry);
@@ -821,13 +835,13 @@ class HighsHashTree {
821835 if (maxEntriesPerLeaf <= InnerLeaf<1 >::capacity ()) {
822836 // all items can go into the smallest leaf size
823837 for (int i = 0 ; i < branchSize; ++i)
824- branch->child [i] = new InnerLeaf<1 >;
838+ branch->child (i) = new InnerLeaf<1 >;
825839
826840 for (int i = 0 ; i < leaf->size ; ++i) {
827841 int pos =
828842 occupation.num_set_until (get_first_chunk16 (leaf->hashes [i])) -
829843 1 ;
830- branch->child [ pos] .getInnerLeafSizeClass1 ()->insert_entry (
844+ branch->child ( pos) .getInnerLeafSizeClass1 ()->insert_entry (
831845 compute_hash (leaf->entries [i].key ()), hashPos + 1 ,
832846 leaf->entries [i]);
833847 }
@@ -836,7 +850,7 @@ class HighsHashTree {
836850
837851 int pos =
838852 occupation.num_set_until (get_hash_chunk (hash, hashPos)) - 1 ;
839- return branch->child [ pos] .getInnerLeafSizeClass1 ()->insert_entry (
853+ return branch->child ( pos) .getInnerLeafSizeClass1 ()->insert_entry (
840854 hash, hashPos + 1 , entry);
841855 } else {
842856 // there are many collisions, determine the exact sizes first
@@ -852,16 +866,16 @@ class HighsHashTree {
852866 for (int i = 0 ; i < branchSize; ++i) {
853867 switch (entries_to_size_class (sizes[i])) {
854868 case 1 :
855- branch->child [i] = new InnerLeaf<1 >;
869+ branch->child (i) = new InnerLeaf<1 >;
856870 break ;
857871 case 2 :
858- branch->child [i] = new InnerLeaf<2 >;
872+ branch->child (i) = new InnerLeaf<2 >;
859873 break ;
860874 case 3 :
861- branch->child [i] = new InnerLeaf<3 >;
875+ branch->child (i) = new InnerLeaf<3 >;
862876 break ;
863877 case 4 :
864- branch->child [i] = new InnerLeaf<4 >;
878+ branch->child (i) = new InnerLeaf<4 >;
865879 break ;
866880 default :
867881 // Unexpected result from 'entries_to_size_class'
@@ -874,24 +888,24 @@ class HighsHashTree {
874888 occupation.num_set_until (get_first_chunk16 (leaf->hashes [i])) -
875889 1 ;
876890
877- switch (branch->child [ pos] .getType ()) {
891+ switch (branch->child ( pos) .getType ()) {
878892 case kInnerLeafSizeClass1 :
879- branch->child [ pos] .getInnerLeafSizeClass1 ()->insert_entry (
893+ branch->child ( pos) .getInnerLeafSizeClass1 ()->insert_entry (
880894 compute_hash (leaf->entries [i].key ()), hashPos + 1 ,
881895 leaf->entries [i]);
882896 break ;
883897 case kInnerLeafSizeClass2 :
884- branch->child [ pos] .getInnerLeafSizeClass2 ()->insert_entry (
898+ branch->child ( pos) .getInnerLeafSizeClass2 ()->insert_entry (
885899 compute_hash (leaf->entries [i].key ()), hashPos + 1 ,
886900 leaf->entries [i]);
887901 break ;
888902 case kInnerLeafSizeClass3 :
889- branch->child [ pos] .getInnerLeafSizeClass3 ()->insert_entry (
903+ branch->child ( pos) .getInnerLeafSizeClass3 ()->insert_entry (
890904 compute_hash (leaf->entries [i].key ()), hashPos + 1 ,
891905 leaf->entries [i]);
892906 break ;
893907 case kInnerLeafSizeClass4 :
894- branch->child [ pos] .getInnerLeafSizeClass4 ()->insert_entry (
908+ branch->child ( pos) .getInnerLeafSizeClass4 ()->insert_entry (
895909 compute_hash (leaf->entries [i].key ()), hashPos + 1 ,
896910 leaf->entries [i]);
897911 break ;
@@ -904,14 +918,14 @@ class HighsHashTree {
904918 delete leaf;
905919
906920 int pos = occupation.num_set_until (hashChunk) - 1 ;
907- insertNode = & branch->child [ pos] ;
921+ insertNode = branch->childPtr ( pos) ;
908922 ++hashPos;
909923 } else {
910924 // extremely unlikely that the new branch node only gets one
911925 // child in that case create it and defer the insertion into
912926 // the next depth
913- branch->child [ 0 ] = leaf;
914- insertNode = & branch->child [ 0 ] ;
927+ branch->child ( 0 ) = leaf;
928+ insertNode = branch->childPtr ( 0 ) ;
915929 ++hashPos;
916930 leaf->rehash (hashPos);
917931 }
@@ -930,12 +944,12 @@ class HighsHashTree {
930944 branch = addChildToBranchNode (branch, get_hash_chunk (hash, hashPos),
931945 location);
932946
933- branch->child [ location] = nullptr ;
947+ branch->child ( location) = nullptr ;
934948 branch->occupation .set (get_hash_chunk (hash, hashPos));
935949 }
936950
937951 *insertNode = branch;
938- insertNode = & branch->child [ location] ;
952+ insertNode = branch->childPtr ( location) ;
939953 ++hashPos;
940954 }
941955 }
@@ -1038,9 +1052,9 @@ class HighsHashTree {
10381052
10391053 int location =
10401054 branch->occupation .num_set_until (get_hash_chunk (hash, hashPos)) - 1 ;
1041- erase_recurse (& branch->child [ location] , hash, hashPos + 1 , key);
1055+ erase_recurse (branch->childPtr ( location) , hash, hashPos + 1 , key);
10421056
1043- if (branch->child [ location] .getType () != kEmpty ) return ;
1057+ if (branch->child ( location) .getType () != kEmpty ) return ;
10441058
10451059 branch->occupation .flip (get_hash_chunk (hash, hashPos));
10461060
@@ -1088,7 +1102,7 @@ class HighsHashTree {
10881102 return nullptr ;
10891103 int location =
10901104 branch->occupation .num_set_until (get_hash_chunk (hash, hashPos)) - 1 ;
1091- node = branch->child [ location] ;
1105+ node = branch->child ( location) ;
10921106 ++hashPos;
10931107 }
10941108 }
@@ -1147,8 +1161,8 @@ class HighsHashTree {
11471161 branch2->occupation .num_set_until (static_cast <uint8_t >(pos)) - 1 ;
11481162
11491163 const HighsHashTableEntry<K, V>* match =
1150- find_common_recurse (branch1->child [ location1] ,
1151- branch2->child [ location2] , hashPos + 1 );
1164+ find_common_recurse (branch1->child ( location1) ,
1165+ branch2->child ( location2) , hashPos + 1 );
11521166 if (match != nullptr ) return match;
11531167 }
11541168
@@ -1191,7 +1205,7 @@ class HighsHashTree {
11911205 BranchNode* branch = node.getBranchNode ();
11921206 int size = branch->occupation .num_set ();
11931207
1194- for (int i = 0 ; i < size; ++i) destroy_recurse (branch->child [i] );
1208+ for (int i = 0 ; i < size; ++i) destroy_recurse (branch->child (i) );
11951209
11961210 destroyBranchingNode (branch);
11971211 }
@@ -1240,7 +1254,7 @@ class HighsHashTree {
12401254 (BranchNode*)::operator new (getBranchNodeSize (size));
12411255 newBranch->occupation = branch->occupation ;
12421256 for (int i = 0 ; i < size; ++i)
1243- newBranch->child [i] = copy_recurse (branch->child [i] );
1257+ newBranch->child (i) = copy_recurse (branch->child (i) );
12441258
12451259 return newBranch;
12461260 }
@@ -1292,7 +1306,7 @@ class HighsHashTree {
12921306 BranchNode* branch = node.getBranchNode ();
12931307 int size = branch->occupation .num_set ();
12941308
1295- for (int i = 0 ; i < size; ++i) for_each_recurse<R>(branch->child [i] , f);
1309+ for (int i = 0 ; i < size; ++i) for_each_recurse<R>(branch->child (i) , f);
12961310 }
12971311 }
12981312 }
@@ -1354,7 +1368,7 @@ class HighsHashTree {
13541368 int size = branch->occupation .num_set ();
13551369
13561370 for (int i = 0 ; i < size; ++i) {
1357- auto x = for_each_recurse<R>(branch->child [i] , f);
1371+ auto x = for_each_recurse<R>(branch->child (i) , f);
13581372 if (x) return x;
13591373 }
13601374 }
0 commit comments