| 1385 | } |
| 1386 | |
| 1387 | void appendNulls( |
| 1388 | const uint64_t* nulls, |
| 1389 | int32_t begin, |
| 1390 | int32_t end, |
| 1391 | int32_t numNonNull) { |
| 1392 | BOLT_DCHECK_EQ(numNonNull, bits::countBits(nulls, begin, end)); |
| 1393 | const auto numRows = end - begin; |
| 1394 | const auto numNulls = numRows - numNonNull; |
| 1395 | if (numNulls == 0 && nullCount_ == 0) { |
| 1396 | nonNullCount_ += numNonNull; |
| 1397 | return; |
| 1398 | } |
| 1399 | if (FOLLY_UNLIKELY(numNulls > 0 && nonNullCount_ > 0 && nullCount_ == 0)) { |
| 1400 | // There were only non-nulls up until now. Add the bits for them. |
| 1401 | nulls_.appendBool(false, nonNullCount_); |
| 1402 | } |
| 1403 | nullCount_ += numNulls; |
| 1404 | nonNullCount_ += numNonNull; |
| 1405 | |
| 1406 | if (FOLLY_LIKELY(end <= 64)) { |
| 1407 | const uint64_t inverted = ~nulls[0]; |
| 1408 | nulls_.appendBitsFresh(&inverted, begin, end); |
| 1409 | return; |
| 1410 | } |
| 1411 | |
| 1412 | const int32_t firstWord = begin >> 6; |
| 1413 | const int32_t firstBit = begin & 63; |
| 1414 | const auto numWords = bits::nwords(numRows + firstBit); |
| 1415 | // The polarity of nulls is reverse in wire format. Make an inverted copy. |
| 1416 | uint64_t smallNulls[16]; |
| 1417 | uint64_t* invertedNulls = smallNulls; |
| 1418 | if (numWords > sizeof(smallNulls) / sizeof(smallNulls[0])) { |
| 1419 | auto& tempNulls = threadTempNulls(); |
| 1420 | tempNulls.resize(numWords + 1); |
| 1421 | invertedNulls = tempNulls.data(); |
| 1422 | } |
| 1423 | for (auto i = 0; i < numWords; ++i) { |
| 1424 | invertedNulls[i] = ~nulls[i + firstWord]; |
| 1425 | } |
| 1426 | nulls_.appendBitsFresh(invertedNulls, firstBit, firstBit + numRows); |
| 1427 | } |
| 1428 | |
| 1429 | // Appends a zero length for each null bit and a length from lengthFunc(row) |
| 1430 | // for non-nulls in rows. |
no test coverage detected