Skip to content

Commit 7a6bcf7

Browse files
committed
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into latest
2 parents e724ca8 + 274a8fd commit 7a6bcf7

File tree

1 file changed

+68
-54
lines changed

1 file changed

+68
-54
lines changed

highs/util/HighsHashTree.h

Lines changed: 68 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)