Commit 5cd3e108 authored by Kenton Varda's avatar Kenton Varda

Sadly, MSVC cannot handle pointer-to-members in constexprs.

This is true even if the pointer-to-member is never actually used, but only has its type matched, which was what kj::size() was trying to do.

Oh well, define some damned constants instead.
parent f58201fc
......@@ -530,13 +530,8 @@ template <typename T, size_t s>
inline constexpr size_t size(T (&arr)[s]) { return s; }
template <typename T>
inline constexpr size_t size(T&& arr) { return arr.size(); }
template <typename T, typename U, size_t s>
inline constexpr size_t size(U (T::*arr)[s]) { return s; }
// Returns the size of the parameter, whether the parameter is a regular C array or a container
// with a `.size()` method.
//
// Can also be invoked on a pointer-to-member-array to get the declared size of that array,
// without having an instance of the containing type. E.g.: kj::size(&MyType::someArray)
class MaxValue_ {
private:
......
......@@ -202,12 +202,12 @@ void BTreeImpl::reserve(size_t size) {
// least half-full. (Note that it's correct for this calculation to round down, not up: The
// remainder will necessarily be distributed among the non-full leaves, rather than creating a
// new leaf, because if it went into a new leaf, that leaf would be less than half-full.)
uint leaves = size / (kj::size(&Leaf::rows) / 2);
uint leaves = size / (Leaf::NROWS / 2);
// Calculate the worst-case number of parents to cover the leaves, given that a parent is always
// at least half-full. Since the parents form a tree with branching factor B, the size of the
// tree is N/B + N/B^2 + N/B^3 + N/B^4 + ... = N / (B - 1). Math.
constexpr uint branchingFactor = kj::size(&Parent::children) / 2;
constexpr uint branchingFactor = Parent::NCHILDREN / 2;
uint parents = leaves / (branchingFactor - 1);
// Height is log-base-branching-factor of leaves, plus 1 for the root node.
......@@ -516,7 +516,7 @@ Node& BTreeImpl::eraseHelper(
return sib;
}
}
} else if (indexInParent < kj::size(&Parent::keys) && parent->keys[indexInParent] != nullptr) {
} else if (indexInParent < Parent::NKEYS && parent->keys[indexInParent] != nullptr) {
// There's a sibling to the right.
uint sibPos = parent->children[indexInParent + 1];
Node& sib = tree[sibPos];
......@@ -580,20 +580,20 @@ void BTreeImpl::renumber(uint oldRow, uint newRow, const SearchKey& searchKey) {
}
uint BTreeImpl::split(Parent& dst, uint dstPos, Parent& src, uint srcPos) {
constexpr size_t mid = kj::size(&Parent::keys) / 2;
constexpr size_t mid = Parent::NKEYS / 2;
uint pivot = *src.keys[mid];
acopy(dst.keys, src.keys + mid + 1, kj::size(&Parent::keys) - mid - 1);
azero(src.keys + mid, kj::size(&Parent::keys) - mid);
acopy(dst.children, src.children + mid + 1, kj::size(&Parent::children) - mid - 1);
azero(src.children + mid + 1, kj::size(&Parent::children) - mid - 1);
acopy(dst.keys, src.keys + mid + 1, Parent::NKEYS - mid - 1);
azero(src.keys + mid, Parent::NKEYS - mid);
acopy(dst.children, src.children + mid + 1, Parent::NCHILDREN - mid - 1);
azero(src.children + mid + 1, Parent::NCHILDREN - mid - 1);
return pivot;
}
uint BTreeImpl::split(Leaf& dst, uint dstPos, Leaf& src, uint srcPos) {
constexpr size_t mid = kj::size(&Leaf::rows) / 2;
constexpr size_t mid = Leaf::NROWS / 2;
uint pivot = *src.rows[mid - 1];
acopy(dst.rows, src.rows + mid, kj::size(&Leaf::rows) - mid);
azero(src.rows + mid, kj::size(&Leaf::rows) - mid);
acopy(dst.rows, src.rows + mid, Leaf::NROWS - mid);
azero(src.rows + mid, Leaf::NROWS - mid);
if (src.next == 0) {
endLeaf = dstPos;
......@@ -614,7 +614,7 @@ void BTreeImpl::merge(Parent& dst, uint dstPos, uint pivot, Parent& src) {
KJ_DASSERT(src.isHalfFull());
KJ_DASSERT(dst.isHalfFull());
constexpr size_t mid = kj::size(&Parent::keys)/2;
constexpr size_t mid = Parent::NKEYS/2;
dst.keys[mid] = pivot;
acopy(dst.keys + mid + 1, src.keys, mid);
acopy(dst.children + mid + 1, src.children, mid + 1);
......@@ -627,7 +627,7 @@ void BTreeImpl::merge(Leaf& dst, uint dstPos, uint pivot, Leaf& src) {
KJ_DASSERT(src.isHalfFull());
KJ_DASSERT(dst.isHalfFull());
constexpr size_t mid = kj::size(&Leaf::rows)/2;
constexpr size_t mid = Leaf::NROWS/2;
dst.rows[mid] = pivot;
acopy(dst.rows + mid, src.rows, mid);
......@@ -665,15 +665,15 @@ void BTreeImpl::rotateLeft(
KJ_DASSERT(left.isHalfFull());
KJ_DASSERT(right.isMostlyFull());
constexpr size_t mid = kj::size(&Parent::keys)/2;
constexpr size_t mid = Parent::NKEYS/2;
left.keys[mid] = parent.keys[indexInParent];
if (fixup == &parent.keys[indexInParent]) fixup = &left.keys[mid];
parent.keys[indexInParent] = right.keys[0];
left.children[mid + 1] = right.children[0];
amove(right.keys, right.keys + 1, kj::size(&Parent::keys) - 1);
right.keys[kj::size(&Parent::keys) - 1] = nullptr;
amove(right.children, right.children + 1, kj::size(&Parent::children) - 1);
right.children[kj::size(&Parent::children) - 1] = 0;
amove(right.keys, right.keys + 1, Parent::NKEYS - 1);
right.keys[Parent::NKEYS - 1] = nullptr;
amove(right.children, right.children + 1, Parent::NCHILDREN - 1);
right.children[Parent::NCHILDREN - 1] = 0;
}
void BTreeImpl::rotateLeft(
......@@ -684,11 +684,11 @@ void BTreeImpl::rotateLeft(
KJ_DASSERT(left.isHalfFull());
KJ_DASSERT(right.isMostlyFull());
constexpr size_t mid = kj::size(&Leaf::rows)/2;
constexpr size_t mid = Leaf::NROWS/2;
parent.keys[indexInParent] = left.rows[mid] = right.rows[0];
if (fixup == &parent.keys[indexInParent]) fixup = nullptr;
amove(right.rows, right.rows + 1, kj::size(&Leaf::rows) - 1);
right.rows[kj::size(&Leaf::rows) - 1] = nullptr;
amove(right.rows, right.rows + 1, Leaf::NROWS - 1);
right.rows[Leaf::NROWS - 1] = nullptr;
}
void BTreeImpl::rotateRight(Parent& left, Parent& right, Parent& parent, uint indexInParent) {
......@@ -698,7 +698,7 @@ void BTreeImpl::rotateRight(Parent& left, Parent& right, Parent& parent, uint in
KJ_DASSERT(right.isHalfFull());
KJ_DASSERT(left.isMostlyFull());
constexpr size_t mid = kj::size(&Parent::keys)/2;
constexpr size_t mid = Parent::NKEYS/2;
amove(right.keys + 1, right.keys, mid);
amove(right.children + 1, right.children, mid + 1);
......@@ -718,7 +718,7 @@ void BTreeImpl::rotateRight(Leaf& left, Leaf& right, Parent& parent, uint indexI
KJ_DASSERT(right.isHalfFull());
KJ_DASSERT(left.isMostlyFull());
constexpr size_t mid = kj::size(&Leaf::rows)/2;
constexpr size_t mid = Leaf::NROWS/2;
amove(right.rows + 1, right.rows, mid);
uint back = left.size() - 1;
......@@ -738,25 +738,25 @@ void BTreeImpl::Parent::initRoot(uint key, uint leftChild, uint rightChild) {
keys[0] = key;
children[0] = leftChild;
children[1] = rightChild;
azero(keys + 1, kj::size(&Parent::keys) - 1);
azero(children + 2, kj::size(&Parent::children) - 2);
azero(keys + 1, Parent::NKEYS - 1);
azero(children + 2, Parent::NCHILDREN - 2);
}
void BTreeImpl::Parent::insertAfter(uint i, uint splitKey, uint child) {
KJ_IREQUIRE(children[kj::size(&Parent::children) - 1] == 0); // check not full
KJ_IREQUIRE(children[Parent::NCHILDREN - 1] == 0); // check not full
amove(keys + i + 1, keys + i, kj::size(&Parent::keys) - (i + 1));
amove(keys + i + 1, keys + i, Parent::NKEYS - (i + 1));
keys[i] = splitKey;
amove(children + i + 2, children + i + 1, kj::size(&Parent::children) - (i + 2));
amove(children + i + 2, children + i + 1, Parent::NCHILDREN - (i + 2));
children[i + 1] = child;
}
void BTreeImpl::Parent::eraseAfter(uint i) {
amove(keys + i, keys + i + 1, kj::size(&Parent::keys) - (i + 1));
keys[kj::size(&Parent::keys) - 1] = nullptr;
amove(children + i + 1, children + i + 2, kj::size(&Parent::children) - (i + 2));
children[kj::size(&Parent::children) - 1] = 0;
amove(keys + i, keys + i + 1, Parent::NKEYS - (i + 1));
keys[Parent::NKEYS - 1] = nullptr;
amove(children + i + 1, children + i + 2, Parent::NCHILDREN - (i + 2));
children[Parent::NCHILDREN - 1] = 0;
}
} // namespace _
......
......@@ -1033,7 +1033,8 @@ struct BTreeImpl::Leaf {
uint prev;
// Pointers to next and previous nodes at the same level, used for fast iteration.
MaybeUint rows[14];
static constexpr size_t NROWS = 14;
MaybeUint rows[NROWS];
// Pointers to table rows, offset by 1 so that 0 is an empty value.
inline bool isFull() const;
......@@ -1041,21 +1042,21 @@ struct BTreeImpl::Leaf {
inline bool isHalfFull() const;
inline void insert(uint i, uint newRow) {
KJ_IREQUIRE(rows[kj::size(&Leaf::rows) - 1] == nullptr); // check not full
KJ_IREQUIRE(rows[Leaf::NROWS - 1] == nullptr); // check not full
amove(rows + i + 1, rows + i, kj::size(&Leaf::rows) - (i + 1));
amove(rows + i + 1, rows + i, Leaf::NROWS - (i + 1));
rows[i] = newRow;
}
inline void erase(uint i) {
KJ_IREQUIRE(rows[0] != nullptr); // check not empty
amove(rows + i, rows + i + 1, kj::size(&Leaf::rows) - (i + 1));
rows[kj::size(&Leaf::rows) - 1] = nullptr;
amove(rows + i, rows + i + 1, Leaf::NROWS - (i + 1));
rows[Leaf::NROWS - 1] = nullptr;
}
inline uint size() const {
static_assert(kj::size(&Leaf::rows) == 14, "logic here needs updating");
static_assert(Leaf::NROWS == 14, "logic here needs updating");
// Binary search for first empty element in `rows`, or return 14 if no empty elements. We do
// this in a branch-free manner. Since there are 15 possible results (0 through 14, inclusive),
......@@ -1072,7 +1073,7 @@ struct BTreeImpl::Leaf {
inline uint binarySearch(Func& predicate) const {
// Binary search to find first row for which predicate(row) is false.
static_assert(kj::size(&Leaf::rows) == 14, "logic here needs updating");
static_assert(Leaf::NROWS == 14, "logic here needs updating");
// See comments in size().
uint i = (rows[6].check(predicate)) * 7;
......@@ -1089,10 +1090,12 @@ struct BTreeImpl::Parent {
uint unused;
// Not used. May be arbitrarily non-zero due to overlap with Freelisted::nextOffset.
MaybeUint keys[7];
static constexpr size_t NKEYS = 7;
MaybeUint keys[NKEYS];
// Pointers to table rows, offset by 1 so that 0 is an empty value.
uint children[kj::size(&Parent::keys) + 1];
static constexpr size_t NCHILDREN = NKEYS + 1;
uint children[NCHILDREN];
// Pointers to children. Not offset because the root is always at position 0, and a pointer
// to the root would be nonsensical.
......@@ -1104,7 +1107,7 @@ struct BTreeImpl::Parent {
inline void eraseAfter(uint i);
inline uint keyCount() const {
static_assert(kj::size(&Parent::keys) == 7, "logic here needs updating");
static_assert(Parent::NKEYS == 7, "logic here needs updating");
// Binary search for first empty element in `keys`, or return 7 if no empty elements. We do
// this in a branch-free manner. Since there are 8 possible results (0 through 7, inclusive),
......@@ -1119,7 +1122,7 @@ struct BTreeImpl::Parent {
inline uint binarySearch(Func& predicate) const {
// Binary search to find first key for which predicate(key) is false.
static_assert(kj::size(&Parent::keys) == 7, "logic here needs updating");
static_assert(Parent::NKEYS == 7, "logic here needs updating");
// See comments in size().
uint i = (keys[3].check(predicate)) * 4;
......@@ -1167,25 +1170,25 @@ static_assert(sizeof(BTreeImpl::NodeUnion) == 64,
"BTreeImpl::NodeUnion should be optimized to fit a cache line");
bool BTreeImpl::Leaf::isFull() const {
return rows[kj::size(&Leaf::rows) - 1] != nullptr;
return rows[Leaf::NROWS - 1] != nullptr;
}
bool BTreeImpl::Leaf::isMostlyFull() const {
return rows[kj::size(&Leaf::rows) / 2] != nullptr;
return rows[Leaf::NROWS / 2] != nullptr;
}
bool BTreeImpl::Leaf::isHalfFull() const {
KJ_IASSERT(rows[kj::size(&Leaf::rows) / 2 - 1] != nullptr);
return rows[kj::size(&Leaf::rows) / 2] == nullptr;
KJ_IASSERT(rows[Leaf::NROWS / 2 - 1] != nullptr);
return rows[Leaf::NROWS / 2] == nullptr;
}
bool BTreeImpl::Parent::isFull() const {
return keys[kj::size(&Parent::keys) - 1] != nullptr;
return keys[Parent::NKEYS - 1] != nullptr;
}
bool BTreeImpl::Parent::isMostlyFull() const {
return keys[kj::size(&Parent::keys) / 2] != nullptr;
return keys[Parent::NKEYS / 2] != nullptr;
}
bool BTreeImpl::Parent::isHalfFull() const {
KJ_IASSERT(keys[kj::size(&Parent::keys) / 2 - 1] != nullptr);
return keys[kj::size(&Parent::keys) / 2] == nullptr;
KJ_IASSERT(keys[Parent::NKEYS / 2 - 1] != nullptr);
return keys[Parent::NKEYS / 2] == nullptr;
}
class BTreeImpl::Iterator {
......@@ -1194,7 +1197,7 @@ public:
: tree(tree), leaf(leaf), row(row) {}
size_t operator*() const {
KJ_IREQUIRE(row < kj::size(&Leaf::rows) && leaf->rows[row] != nullptr,
KJ_IREQUIRE(row < Leaf::NROWS && leaf->rows[row] != nullptr,
"tried to dereference end() iterator");
return *leaf->rows[row];
}
......@@ -1202,7 +1205,7 @@ public:
inline Iterator& operator++() {
KJ_IREQUIRE(leaf->rows[row] != nullptr, "B-tree iterator overflow");
++row;
if (row >= kj::size(&Leaf::rows) || leaf->rows[row] == nullptr) {
if (row >= Leaf::NROWS || leaf->rows[row] == nullptr) {
if (leaf->next == 0) {
// at end; stay on current leaf
} else {
......@@ -1242,7 +1245,7 @@ public:
}
bool isEnd() {
return row == kj::size(&Leaf::rows) || leaf->rows[row] == nullptr;
return row == Leaf::NROWS || leaf->rows[row] == nullptr;
}
void insert(BTreeImpl& impl, uint newRow) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment