| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "BpackingDefault.hh" |
| #include "RLEv2.hh" |
| #include "Utils.hh" |
| |
| namespace orc { |
| |
| UnpackDefault::UnpackDefault(RleDecoderV2* dec) : decoder_(dec) { |
| // PASS |
| } |
| |
| UnpackDefault::~UnpackDefault() { |
| // PASS |
| } |
| |
| void UnpackDefault::unrolledUnpack4(int64_t* data, uint64_t offset, uint64_t len) { |
| uint64_t curIdx = offset; |
| while (curIdx < offset + len) { |
| // Make sure bitsLeft is 0 before the loop. bitsLeft can only be 0, 4, or 8. |
| while (decoder_->getBitsLeft() > 0 && curIdx < offset + len) { |
| decoder_->setBitsLeft(decoder_->getBitsLeft() - 4); |
| data[curIdx++] = (decoder_->getCurByte() >> decoder_->getBitsLeft()) & 15; |
| } |
| if (curIdx == offset + len) return; |
| |
| // Exhaust the buffer |
| uint64_t numGroups = (offset + len - curIdx) / 2; |
| numGroups = std::min(numGroups, static_cast<uint64_t>(decoder_->bufLength())); |
| // Avoid updating 'bufferStart' inside the loop. |
| auto* buffer = reinterpret_cast<unsigned char*>(decoder_->getBufStart()); |
| uint32_t localByte; |
| for (uint64_t i = 0; i < numGroups; ++i) { |
| localByte = *buffer++; |
| data[curIdx] = (localByte >> 4) & 15; |
| data[curIdx + 1] = localByte & 15; |
| curIdx += 2; |
| } |
| decoder_->setBufStart(reinterpret_cast<char*>(buffer)); |
| if (curIdx == offset + len) return; |
| |
| // readByte() will update 'bufferStart' and 'bufferEnd' |
| decoder_->setCurByte(decoder_->readByte()); |
| decoder_->setBitsLeft(8); |
| } |
| } |
| |
| void UnpackDefault::unrolledUnpack8(int64_t* data, uint64_t offset, uint64_t len) { |
| uint64_t curIdx = offset; |
| while (curIdx < offset + len) { |
| // Exhaust the buffer |
| int64_t bufferNum = decoder_->bufLength(); |
| bufferNum = std::min(bufferNum, static_cast<int64_t>(offset + len - curIdx)); |
| // Avoid updating 'bufferStart' inside the loop. |
| auto* buffer = reinterpret_cast<unsigned char*>(decoder_->getBufStart()); |
| for (int i = 0; i < bufferNum; ++i) { |
| data[curIdx++] = *buffer++; |
| } |
| decoder_->setBufStart(reinterpret_cast<char*>(buffer)); |
| if (curIdx == offset + len) return; |
| |
| // readByte() will update 'bufferStart' and 'bufferEnd'. |
| data[curIdx++] = decoder_->readByte(); |
| } |
| } |
| |
| void UnpackDefault::unrolledUnpack16(int64_t* data, uint64_t offset, uint64_t len) { |
| uint64_t curIdx = offset; |
| while (curIdx < offset + len) { |
| // Exhaust the buffer |
| int64_t bufferNum = decoder_->bufLength() / 2; |
| bufferNum = std::min(bufferNum, static_cast<int64_t>(offset + len - curIdx)); |
| uint16_t b0, b1; |
| // Avoid updating 'bufferStart' inside the loop. |
| auto* buffer = reinterpret_cast<unsigned char*>(decoder_->getBufStart()); |
| for (int i = 0; i < bufferNum; ++i) { |
| b0 = static_cast<uint16_t>(*buffer); |
| b1 = static_cast<uint16_t>(*(buffer + 1)); |
| buffer += 2; |
| data[curIdx++] = (b0 << 8) | b1; |
| } |
| decoder_->setBufStart(reinterpret_cast<char*>(buffer)); |
| if (curIdx == offset + len) return; |
| |
| // One of the following readByte() will update 'bufferStart' and 'bufferEnd'. |
| b0 = decoder_->readByte(); |
| b1 = decoder_->readByte(); |
| data[curIdx++] = (b0 << 8) | b1; |
| } |
| } |
| |
| void UnpackDefault::unrolledUnpack24(int64_t* data, uint64_t offset, uint64_t len) { |
| uint64_t curIdx = offset; |
| while (curIdx < offset + len) { |
| // Exhaust the buffer |
| int64_t bufferNum = decoder_->bufLength() / 3; |
| bufferNum = std::min(bufferNum, static_cast<int64_t>(offset + len - curIdx)); |
| uint32_t b0, b1, b2; |
| // Avoid updating 'bufferStart' inside the loop. |
| auto* buffer = reinterpret_cast<unsigned char*>(decoder_->getBufStart()); |
| for (int i = 0; i < bufferNum; ++i) { |
| b0 = static_cast<uint32_t>(*buffer); |
| b1 = static_cast<uint32_t>(*(buffer + 1)); |
| b2 = static_cast<uint32_t>(*(buffer + 2)); |
| buffer += 3; |
| data[curIdx++] = static_cast<int64_t>((b0 << 16) | (b1 << 8) | b2); |
| } |
| //////decoder->bufferStart += bufferNum * 3; |
| decoder_->setBufStart(reinterpret_cast<char*>(buffer)); |
| if (curIdx == offset + len) return; |
| |
| // One of the following readByte() will update 'bufferStart' and 'bufferEnd'. |
| b0 = decoder_->readByte(); |
| b1 = decoder_->readByte(); |
| b2 = decoder_->readByte(); |
| data[curIdx++] = static_cast<int64_t>((b0 << 16) | (b1 << 8) | b2); |
| } |
| } |
| |
| void UnpackDefault::unrolledUnpack32(int64_t* data, uint64_t offset, uint64_t len) { |
| uint64_t curIdx = offset; |
| while (curIdx < offset + len) { |
| // Exhaust the buffer |
| int64_t bufferNum = decoder_->bufLength() / 4; |
| bufferNum = std::min(bufferNum, static_cast<int64_t>(offset + len - curIdx)); |
| uint32_t b0, b1, b2, b3; |
| // Avoid updating 'bufferStart' inside the loop. |
| auto* buffer = reinterpret_cast<unsigned char*>(decoder_->getBufStart()); |
| for (int i = 0; i < bufferNum; ++i) { |
| b0 = static_cast<uint32_t>(*buffer); |
| b1 = static_cast<uint32_t>(*(buffer + 1)); |
| b2 = static_cast<uint32_t>(*(buffer + 2)); |
| b3 = static_cast<uint32_t>(*(buffer + 3)); |
| buffer += 4; |
| data[curIdx++] = static_cast<int64_t>((b0 << 24) | (b1 << 16) | (b2 << 8) | b3); |
| } |
| decoder_->setBufStart(reinterpret_cast<char*>(buffer)); |
| if (curIdx == offset + len) return; |
| |
| // One of the following readByte() will update 'bufferStart' and 'bufferEnd'. |
| b0 = decoder_->readByte(); |
| b1 = decoder_->readByte(); |
| b2 = decoder_->readByte(); |
| b3 = decoder_->readByte(); |
| data[curIdx++] = static_cast<int64_t>((b0 << 24) | (b1 << 16) | (b2 << 8) | b3); |
| } |
| } |
| |
| void UnpackDefault::unrolledUnpack40(int64_t* data, uint64_t offset, uint64_t len) { |
| uint64_t curIdx = offset; |
| while (curIdx < offset + len) { |
| // Exhaust the buffer |
| int64_t bufferNum = decoder_->bufLength() / 5; |
| bufferNum = std::min(bufferNum, static_cast<int64_t>(offset + len - curIdx)); |
| uint64_t b0, b1, b2, b3, b4; |
| // Avoid updating 'bufferStart' inside the loop. |
| auto* buffer = reinterpret_cast<unsigned char*>(decoder_->getBufStart()); |
| for (int i = 0; i < bufferNum; ++i) { |
| b0 = static_cast<uint32_t>(*buffer); |
| b1 = static_cast<uint32_t>(*(buffer + 1)); |
| b2 = static_cast<uint32_t>(*(buffer + 2)); |
| b3 = static_cast<uint32_t>(*(buffer + 3)); |
| b4 = static_cast<uint32_t>(*(buffer + 4)); |
| buffer += 5; |
| data[curIdx++] = |
| static_cast<int64_t>((b0 << 32) | (b1 << 24) | (b2 << 16) | (b3 << 8) | b4); |
| } |
| decoder_->setBufStart(reinterpret_cast<char*>(buffer)); |
| if (curIdx == offset + len) return; |
| |
| // One of the following readByte() will update 'bufferStart' and 'bufferEnd'. |
| b0 = decoder_->readByte(); |
| b1 = decoder_->readByte(); |
| b2 = decoder_->readByte(); |
| b3 = decoder_->readByte(); |
| b4 = decoder_->readByte(); |
| data[curIdx++] = static_cast<int64_t>((b0 << 32) | (b1 << 24) | (b2 << 16) | (b3 << 8) | b4); |
| } |
| } |
| |
| void UnpackDefault::unrolledUnpack48(int64_t* data, uint64_t offset, uint64_t len) { |
| uint64_t curIdx = offset; |
| while (curIdx < offset + len) { |
| // Exhaust the buffer |
| int64_t bufferNum = decoder_->bufLength() / 6; |
| bufferNum = std::min(bufferNum, static_cast<int64_t>(offset + len - curIdx)); |
| uint64_t b0, b1, b2, b3, b4, b5; |
| // Avoid updating 'bufferStart' inside the loop. |
| auto* buffer = reinterpret_cast<unsigned char*>(decoder_->getBufStart()); |
| for (int i = 0; i < bufferNum; ++i) { |
| b0 = static_cast<uint32_t>(*buffer); |
| b1 = static_cast<uint32_t>(*(buffer + 1)); |
| b2 = static_cast<uint32_t>(*(buffer + 2)); |
| b3 = static_cast<uint32_t>(*(buffer + 3)); |
| b4 = static_cast<uint32_t>(*(buffer + 4)); |
| b5 = static_cast<uint32_t>(*(buffer + 5)); |
| buffer += 6; |
| data[curIdx++] = static_cast<int64_t>((b0 << 40) | (b1 << 32) | (b2 << 24) | (b3 << 16) | |
| (b4 << 8) | b5); |
| } |
| decoder_->setBufStart(reinterpret_cast<char*>(buffer)); |
| if (curIdx == offset + len) return; |
| |
| // One of the following readByte() will update 'bufferStart' and 'bufferEnd'. |
| b0 = decoder_->readByte(); |
| b1 = decoder_->readByte(); |
| b2 = decoder_->readByte(); |
| b3 = decoder_->readByte(); |
| b4 = decoder_->readByte(); |
| b5 = decoder_->readByte(); |
| data[curIdx++] = |
| static_cast<int64_t>((b0 << 40) | (b1 << 32) | (b2 << 24) | (b3 << 16) | (b4 << 8) | b5); |
| } |
| } |
| |
| void UnpackDefault::unrolledUnpack56(int64_t* data, uint64_t offset, uint64_t len) { |
| uint64_t curIdx = offset; |
| while (curIdx < offset + len) { |
| // Exhaust the buffer |
| int64_t bufferNum = decoder_->bufLength() / 7; |
| bufferNum = std::min(bufferNum, static_cast<int64_t>(offset + len - curIdx)); |
| uint64_t b0, b1, b2, b3, b4, b5, b6; |
| // Avoid updating 'bufferStart' inside the loop. |
| auto* buffer = reinterpret_cast<unsigned char*>(decoder_->getBufStart()); |
| for (int i = 0; i < bufferNum; ++i) { |
| b0 = static_cast<uint32_t>(*buffer); |
| b1 = static_cast<uint32_t>(*(buffer + 1)); |
| b2 = static_cast<uint32_t>(*(buffer + 2)); |
| b3 = static_cast<uint32_t>(*(buffer + 3)); |
| b4 = static_cast<uint32_t>(*(buffer + 4)); |
| b5 = static_cast<uint32_t>(*(buffer + 5)); |
| b6 = static_cast<uint32_t>(*(buffer + 6)); |
| buffer += 7; |
| data[curIdx++] = static_cast<int64_t>((b0 << 48) | (b1 << 40) | (b2 << 32) | (b3 << 24) | |
| (b4 << 16) | (b5 << 8) | b6); |
| } |
| decoder_->setBufStart(reinterpret_cast<char*>(buffer)); |
| if (curIdx == offset + len) return; |
| |
| // One of the following readByte() will update 'bufferStart' and 'bufferEnd'. |
| b0 = decoder_->readByte(); |
| b1 = decoder_->readByte(); |
| b2 = decoder_->readByte(); |
| b3 = decoder_->readByte(); |
| b4 = decoder_->readByte(); |
| b5 = decoder_->readByte(); |
| b6 = decoder_->readByte(); |
| data[curIdx++] = static_cast<int64_t>((b0 << 48) | (b1 << 40) | (b2 << 32) | (b3 << 24) | |
| (b4 << 16) | (b5 << 8) | b6); |
| } |
| } |
| |
| void UnpackDefault::unrolledUnpack64(int64_t* data, uint64_t offset, uint64_t len) { |
| uint64_t curIdx = offset; |
| while (curIdx < offset + len) { |
| // Exhaust the buffer |
| int64_t bufferNum = decoder_->bufLength() / 8; |
| bufferNum = std::min(bufferNum, static_cast<int64_t>(offset + len - curIdx)); |
| uint64_t b0, b1, b2, b3, b4, b5, b6, b7; |
| // Avoid updating 'bufferStart' inside the loop. |
| auto* buffer = reinterpret_cast<unsigned char*>(decoder_->getBufStart()); |
| for (int i = 0; i < bufferNum; ++i) { |
| b0 = static_cast<uint32_t>(*buffer); |
| b1 = static_cast<uint32_t>(*(buffer + 1)); |
| b2 = static_cast<uint32_t>(*(buffer + 2)); |
| b3 = static_cast<uint32_t>(*(buffer + 3)); |
| b4 = static_cast<uint32_t>(*(buffer + 4)); |
| b5 = static_cast<uint32_t>(*(buffer + 5)); |
| b6 = static_cast<uint32_t>(*(buffer + 6)); |
| b7 = static_cast<uint32_t>(*(buffer + 7)); |
| buffer += 8; |
| data[curIdx++] = static_cast<int64_t>((b0 << 56) | (b1 << 48) | (b2 << 40) | (b3 << 32) | |
| (b4 << 24) | (b5 << 16) | (b6 << 8) | b7); |
| } |
| decoder_->setBufStart(reinterpret_cast<char*>(buffer)); |
| if (curIdx == offset + len) return; |
| |
| // One of the following readByte() will update 'bufferStart' and 'bufferEnd'. |
| b0 = decoder_->readByte(); |
| b1 = decoder_->readByte(); |
| b2 = decoder_->readByte(); |
| b3 = decoder_->readByte(); |
| b4 = decoder_->readByte(); |
| b5 = decoder_->readByte(); |
| b6 = decoder_->readByte(); |
| b7 = decoder_->readByte(); |
| data[curIdx++] = static_cast<int64_t>((b0 << 56) | (b1 << 48) | (b2 << 40) | (b3 << 32) | |
| (b4 << 24) | (b5 << 16) | (b6 << 8) | b7); |
| } |
| } |
| |
| void UnpackDefault::plainUnpackLongs(int64_t* data, uint64_t offset, uint64_t len, uint64_t fbs) { |
| for (uint64_t i = offset; i < (offset + len); i++) { |
| uint64_t result = 0; |
| uint64_t bitsLeftToRead = fbs; |
| while (bitsLeftToRead > decoder_->getBitsLeft()) { |
| result <<= decoder_->getBitsLeft(); |
| result |= decoder_->getCurByte() & ((1 << decoder_->getBitsLeft()) - 1); |
| bitsLeftToRead -= decoder_->getBitsLeft(); |
| decoder_->setCurByte(decoder_->readByte()); |
| decoder_->setBitsLeft(8); |
| } |
| |
| // handle the left over bits |
| if (bitsLeftToRead > 0) { |
| result <<= bitsLeftToRead; |
| decoder_->setBitsLeft(decoder_->getBitsLeft() - static_cast<uint32_t>(bitsLeftToRead)); |
| result |= (decoder_->getCurByte() >> decoder_->getBitsLeft()) & ((1 << bitsLeftToRead) - 1); |
| } |
| data[i] = static_cast<int64_t>(result); |
| } |
| } |
| |
| void BitUnpackDefault::readLongs(RleDecoderV2* decoder, int64_t* data, uint64_t offset, |
| uint64_t len, uint64_t fbs) { |
| UnpackDefault unpackDefault(decoder); |
| switch (fbs) { |
| case 4: |
| unpackDefault.unrolledUnpack4(data, offset, len); |
| break; |
| case 8: |
| unpackDefault.unrolledUnpack8(data, offset, len); |
| break; |
| case 16: |
| unpackDefault.unrolledUnpack16(data, offset, len); |
| break; |
| case 24: |
| unpackDefault.unrolledUnpack24(data, offset, len); |
| break; |
| case 32: |
| unpackDefault.unrolledUnpack32(data, offset, len); |
| break; |
| case 40: |
| unpackDefault.unrolledUnpack40(data, offset, len); |
| break; |
| case 48: |
| unpackDefault.unrolledUnpack48(data, offset, len); |
| break; |
| case 56: |
| unpackDefault.unrolledUnpack56(data, offset, len); |
| break; |
| case 64: |
| unpackDefault.unrolledUnpack64(data, offset, len); |
| break; |
| default: |
| // Fallback to the default implementation for deprecated bit size. |
| unpackDefault.plainUnpackLongs(data, offset, len, fbs); |
| break; |
| } |
| } |
| |
| } // namespace orc |