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> ...@@ -530,13 +530,8 @@ template <typename T, size_t s>
inline constexpr size_t size(T (&arr)[s]) { return s; } inline constexpr size_t size(T (&arr)[s]) { return s; }
template <typename T> template <typename T>
inline constexpr size_t size(T&& arr) { return arr.size(); } 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 // Returns the size of the parameter, whether the parameter is a regular C array or a container
// with a `.size()` method. // 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_ { class MaxValue_ {
private: private:
......
...@@ -202,12 +202,12 @@ void BTreeImpl::reserve(size_t size) { ...@@ -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 // 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 // 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.) // 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 // 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 // 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. // 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); uint parents = leaves / (branchingFactor - 1);
// Height is log-base-branching-factor of leaves, plus 1 for the root node. // Height is log-base-branching-factor of leaves, plus 1 for the root node.
...@@ -516,7 +516,7 @@ Node& BTreeImpl::eraseHelper( ...@@ -516,7 +516,7 @@ Node& BTreeImpl::eraseHelper(
return sib; 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. // There's a sibling to the right.
uint sibPos = parent->children[indexInParent + 1]; uint sibPos = parent->children[indexInParent + 1];
Node& sib = tree[sibPos]; Node& sib = tree[sibPos];
...@@ -580,20 +580,20 @@ void BTreeImpl::renumber(uint oldRow, uint newRow, const SearchKey& searchKey) { ...@@ -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) { 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]; uint pivot = *src.keys[mid];
acopy(dst.keys, src.keys + mid + 1, kj::size(&Parent::keys) - mid - 1); acopy(dst.keys, src.keys + mid + 1, Parent::NKEYS - mid - 1);
azero(src.keys + mid, kj::size(&Parent::keys) - mid); azero(src.keys + mid, Parent::NKEYS - mid);
acopy(dst.children, src.children + mid + 1, kj::size(&Parent::children) - mid - 1); acopy(dst.children, src.children + mid + 1, Parent::NCHILDREN - mid - 1);
azero(src.children + mid + 1, kj::size(&Parent::children) - mid - 1); azero(src.children + mid + 1, Parent::NCHILDREN - mid - 1);
return pivot; return pivot;
} }
uint BTreeImpl::split(Leaf& dst, uint dstPos, Leaf& src, uint srcPos) { 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]; uint pivot = *src.rows[mid - 1];
acopy(dst.rows, src.rows + mid, kj::size(&Leaf::rows) - mid); acopy(dst.rows, src.rows + mid, Leaf::NROWS - mid);
azero(src.rows + mid, kj::size(&Leaf::rows) - mid); azero(src.rows + mid, Leaf::NROWS - mid);
if (src.next == 0) { if (src.next == 0) {
endLeaf = dstPos; endLeaf = dstPos;
...@@ -614,7 +614,7 @@ void BTreeImpl::merge(Parent& dst, uint dstPos, uint pivot, Parent& src) { ...@@ -614,7 +614,7 @@ void BTreeImpl::merge(Parent& dst, uint dstPos, uint pivot, Parent& src) {
KJ_DASSERT(src.isHalfFull()); KJ_DASSERT(src.isHalfFull());
KJ_DASSERT(dst.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; dst.keys[mid] = pivot;
acopy(dst.keys + mid + 1, src.keys, mid); acopy(dst.keys + mid + 1, src.keys, mid);
acopy(dst.children + mid + 1, src.children, mid + 1); acopy(dst.children + mid + 1, src.children, mid + 1);
...@@ -627,7 +627,7 @@ void BTreeImpl::merge(Leaf& dst, uint dstPos, uint pivot, Leaf& src) { ...@@ -627,7 +627,7 @@ void BTreeImpl::merge(Leaf& dst, uint dstPos, uint pivot, Leaf& src) {
KJ_DASSERT(src.isHalfFull()); KJ_DASSERT(src.isHalfFull());
KJ_DASSERT(dst.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; dst.rows[mid] = pivot;
acopy(dst.rows + mid, src.rows, mid); acopy(dst.rows + mid, src.rows, mid);
...@@ -665,15 +665,15 @@ void BTreeImpl::rotateLeft( ...@@ -665,15 +665,15 @@ void BTreeImpl::rotateLeft(
KJ_DASSERT(left.isHalfFull()); KJ_DASSERT(left.isHalfFull());
KJ_DASSERT(right.isMostlyFull()); 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]; left.keys[mid] = parent.keys[indexInParent];
if (fixup == &parent.keys[indexInParent]) fixup = &left.keys[mid]; if (fixup == &parent.keys[indexInParent]) fixup = &left.keys[mid];
parent.keys[indexInParent] = right.keys[0]; parent.keys[indexInParent] = right.keys[0];
left.children[mid + 1] = right.children[0]; left.children[mid + 1] = right.children[0];
amove(right.keys, right.keys + 1, kj::size(&Parent::keys) - 1); amove(right.keys, right.keys + 1, Parent::NKEYS - 1);
right.keys[kj::size(&Parent::keys) - 1] = nullptr; right.keys[Parent::NKEYS - 1] = nullptr;
amove(right.children, right.children + 1, kj::size(&Parent::children) - 1); amove(right.children, right.children + 1, Parent::NCHILDREN - 1);
right.children[kj::size(&Parent::children) - 1] = 0; right.children[Parent::NCHILDREN - 1] = 0;
} }
void BTreeImpl::rotateLeft( void BTreeImpl::rotateLeft(
...@@ -684,11 +684,11 @@ void BTreeImpl::rotateLeft( ...@@ -684,11 +684,11 @@ void BTreeImpl::rotateLeft(
KJ_DASSERT(left.isHalfFull()); KJ_DASSERT(left.isHalfFull());
KJ_DASSERT(right.isMostlyFull()); 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]; parent.keys[indexInParent] = left.rows[mid] = right.rows[0];
if (fixup == &parent.keys[indexInParent]) fixup = nullptr; if (fixup == &parent.keys[indexInParent]) fixup = nullptr;
amove(right.rows, right.rows + 1, kj::size(&Leaf::rows) - 1); amove(right.rows, right.rows + 1, Leaf::NROWS - 1);
right.rows[kj::size(&Leaf::rows) - 1] = nullptr; right.rows[Leaf::NROWS - 1] = nullptr;
} }
void BTreeImpl::rotateRight(Parent& left, Parent& right, Parent& parent, uint indexInParent) { 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 ...@@ -698,7 +698,7 @@ void BTreeImpl::rotateRight(Parent& left, Parent& right, Parent& parent, uint in
KJ_DASSERT(right.isHalfFull()); KJ_DASSERT(right.isHalfFull());
KJ_DASSERT(left.isMostlyFull()); 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.keys + 1, right.keys, mid);
amove(right.children + 1, right.children, mid + 1); amove(right.children + 1, right.children, mid + 1);
...@@ -718,7 +718,7 @@ void BTreeImpl::rotateRight(Leaf& left, Leaf& right, Parent& parent, uint indexI ...@@ -718,7 +718,7 @@ void BTreeImpl::rotateRight(Leaf& left, Leaf& right, Parent& parent, uint indexI
KJ_DASSERT(right.isHalfFull()); KJ_DASSERT(right.isHalfFull());
KJ_DASSERT(left.isMostlyFull()); 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); amove(right.rows + 1, right.rows, mid);
uint back = left.size() - 1; uint back = left.size() - 1;
...@@ -738,25 +738,25 @@ void BTreeImpl::Parent::initRoot(uint key, uint leftChild, uint rightChild) { ...@@ -738,25 +738,25 @@ void BTreeImpl::Parent::initRoot(uint key, uint leftChild, uint rightChild) {
keys[0] = key; keys[0] = key;
children[0] = leftChild; children[0] = leftChild;
children[1] = rightChild; children[1] = rightChild;
azero(keys + 1, kj::size(&Parent::keys) - 1); azero(keys + 1, Parent::NKEYS - 1);
azero(children + 2, kj::size(&Parent::children) - 2); azero(children + 2, Parent::NCHILDREN - 2);
} }
void BTreeImpl::Parent::insertAfter(uint i, uint splitKey, uint child) { 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; 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; children[i + 1] = child;
} }
void BTreeImpl::Parent::eraseAfter(uint i) { void BTreeImpl::Parent::eraseAfter(uint i) {
amove(keys + i, keys + i + 1, kj::size(&Parent::keys) - (i + 1)); amove(keys + i, keys + i + 1, Parent::NKEYS - (i + 1));
keys[kj::size(&Parent::keys) - 1] = nullptr; keys[Parent::NKEYS - 1] = nullptr;
amove(children + i + 1, children + i + 2, kj::size(&Parent::children) - (i + 2)); amove(children + i + 1, children + i + 2, Parent::NCHILDREN - (i + 2));
children[kj::size(&Parent::children) - 1] = 0; children[Parent::NCHILDREN - 1] = 0;
} }
} // namespace _ } // namespace _
......
...@@ -1033,7 +1033,8 @@ struct BTreeImpl::Leaf { ...@@ -1033,7 +1033,8 @@ struct BTreeImpl::Leaf {
uint prev; uint prev;
// Pointers to next and previous nodes at the same level, used for fast iteration. // 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. // Pointers to table rows, offset by 1 so that 0 is an empty value.
inline bool isFull() const; inline bool isFull() const;
...@@ -1041,21 +1042,21 @@ struct BTreeImpl::Leaf { ...@@ -1041,21 +1042,21 @@ struct BTreeImpl::Leaf {
inline bool isHalfFull() const; inline bool isHalfFull() const;
inline void insert(uint i, uint newRow) { 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; rows[i] = newRow;
} }
inline void erase(uint i) { inline void erase(uint i) {
KJ_IREQUIRE(rows[0] != nullptr); // check not empty KJ_IREQUIRE(rows[0] != nullptr); // check not empty
amove(rows + i, rows + i + 1, kj::size(&Leaf::rows) - (i + 1)); amove(rows + i, rows + i + 1, Leaf::NROWS - (i + 1));
rows[kj::size(&Leaf::rows) - 1] = nullptr; rows[Leaf::NROWS - 1] = nullptr;
} }
inline uint size() const { 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 // 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), // this in a branch-free manner. Since there are 15 possible results (0 through 14, inclusive),
...@@ -1072,7 +1073,7 @@ struct BTreeImpl::Leaf { ...@@ -1072,7 +1073,7 @@ struct BTreeImpl::Leaf {
inline uint binarySearch(Func& predicate) const { inline uint binarySearch(Func& predicate) const {
// Binary search to find first row for which predicate(row) is false. // 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(). // See comments in size().
uint i = (rows[6].check(predicate)) * 7; uint i = (rows[6].check(predicate)) * 7;
...@@ -1089,10 +1090,12 @@ struct BTreeImpl::Parent { ...@@ -1089,10 +1090,12 @@ struct BTreeImpl::Parent {
uint unused; uint unused;
// Not used. May be arbitrarily non-zero due to overlap with Freelisted::nextOffset. // 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. // 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 // Pointers to children. Not offset because the root is always at position 0, and a pointer
// to the root would be nonsensical. // to the root would be nonsensical.
...@@ -1104,7 +1107,7 @@ struct BTreeImpl::Parent { ...@@ -1104,7 +1107,7 @@ struct BTreeImpl::Parent {
inline void eraseAfter(uint i); inline void eraseAfter(uint i);
inline uint keyCount() const { 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 // 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), // this in a branch-free manner. Since there are 8 possible results (0 through 7, inclusive),
...@@ -1119,7 +1122,7 @@ struct BTreeImpl::Parent { ...@@ -1119,7 +1122,7 @@ struct BTreeImpl::Parent {
inline uint binarySearch(Func& predicate) const { inline uint binarySearch(Func& predicate) const {
// Binary search to find first key for which predicate(key) is false. // 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(). // See comments in size().
uint i = (keys[3].check(predicate)) * 4; uint i = (keys[3].check(predicate)) * 4;
...@@ -1167,25 +1170,25 @@ static_assert(sizeof(BTreeImpl::NodeUnion) == 64, ...@@ -1167,25 +1170,25 @@ static_assert(sizeof(BTreeImpl::NodeUnion) == 64,
"BTreeImpl::NodeUnion should be optimized to fit a cache line"); "BTreeImpl::NodeUnion should be optimized to fit a cache line");
bool BTreeImpl::Leaf::isFull() const { bool BTreeImpl::Leaf::isFull() const {
return rows[kj::size(&Leaf::rows) - 1] != nullptr; return rows[Leaf::NROWS - 1] != nullptr;
} }
bool BTreeImpl::Leaf::isMostlyFull() const { bool BTreeImpl::Leaf::isMostlyFull() const {
return rows[kj::size(&Leaf::rows) / 2] != nullptr; return rows[Leaf::NROWS / 2] != nullptr;
} }
bool BTreeImpl::Leaf::isHalfFull() const { bool BTreeImpl::Leaf::isHalfFull() const {
KJ_IASSERT(rows[kj::size(&Leaf::rows) / 2 - 1] != nullptr); KJ_IASSERT(rows[Leaf::NROWS / 2 - 1] != nullptr);
return rows[kj::size(&Leaf::rows) / 2] == nullptr; return rows[Leaf::NROWS / 2] == nullptr;
} }
bool BTreeImpl::Parent::isFull() const { bool BTreeImpl::Parent::isFull() const {
return keys[kj::size(&Parent::keys) - 1] != nullptr; return keys[Parent::NKEYS - 1] != nullptr;
} }
bool BTreeImpl::Parent::isMostlyFull() const { bool BTreeImpl::Parent::isMostlyFull() const {
return keys[kj::size(&Parent::keys) / 2] != nullptr; return keys[Parent::NKEYS / 2] != nullptr;
} }
bool BTreeImpl::Parent::isHalfFull() const { bool BTreeImpl::Parent::isHalfFull() const {
KJ_IASSERT(keys[kj::size(&Parent::keys) / 2 - 1] != nullptr); KJ_IASSERT(keys[Parent::NKEYS / 2 - 1] != nullptr);
return keys[kj::size(&Parent::keys) / 2] == nullptr; return keys[Parent::NKEYS / 2] == nullptr;
} }
class BTreeImpl::Iterator { class BTreeImpl::Iterator {
...@@ -1194,7 +1197,7 @@ public: ...@@ -1194,7 +1197,7 @@ public:
: tree(tree), leaf(leaf), row(row) {} : tree(tree), leaf(leaf), row(row) {}
size_t operator*() const { 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"); "tried to dereference end() iterator");
return *leaf->rows[row]; return *leaf->rows[row];
} }
...@@ -1202,7 +1205,7 @@ public: ...@@ -1202,7 +1205,7 @@ public:
inline Iterator& operator++() { inline Iterator& operator++() {
KJ_IREQUIRE(leaf->rows[row] != nullptr, "B-tree iterator overflow"); KJ_IREQUIRE(leaf->rows[row] != nullptr, "B-tree iterator overflow");
++row; ++row;
if (row >= kj::size(&Leaf::rows) || leaf->rows[row] == nullptr) { if (row >= Leaf::NROWS || leaf->rows[row] == nullptr) {
if (leaf->next == 0) { if (leaf->next == 0) {
// at end; stay on current leaf // at end; stay on current leaf
} else { } else {
...@@ -1242,7 +1245,7 @@ public: ...@@ -1242,7 +1245,7 @@ public:
} }
bool isEnd() { 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) { 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