17a2f3a57SNicolas Bonnefon /*
27a2f3a57SNicolas Bonnefon * Copyright (C) 2015 Nicolas Bonnefon and other contributors
37a2f3a57SNicolas Bonnefon *
47a2f3a57SNicolas Bonnefon * This file is part of glogg.
57a2f3a57SNicolas Bonnefon *
67a2f3a57SNicolas Bonnefon * glogg is free software: you can redistribute it and/or modify
77a2f3a57SNicolas Bonnefon * it under the terms of the GNU General Public License as published by
87a2f3a57SNicolas Bonnefon * the Free Software Foundation, either version 3 of the License, or
97a2f3a57SNicolas Bonnefon * (at your option) any later version.
107a2f3a57SNicolas Bonnefon *
117a2f3a57SNicolas Bonnefon * glogg is distributed in the hope that it will be useful,
127a2f3a57SNicolas Bonnefon * but WITHOUT ANY WARRANTY; without even the implied warranty of
137a2f3a57SNicolas Bonnefon * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
147a2f3a57SNicolas Bonnefon * GNU General Public License for more details.
157a2f3a57SNicolas Bonnefon *
167a2f3a57SNicolas Bonnefon * You should have received a copy of the GNU General Public License
177a2f3a57SNicolas Bonnefon * along with glogg. If not, see <http://www.gnu.org/licenses/>.
187a2f3a57SNicolas Bonnefon */
197a2f3a57SNicolas Bonnefon
203c46a469SNicolas Bonnefon #include <cassert>
217a2f3a57SNicolas Bonnefon #include <cstdlib>
22*8b941e12SAnton Filimonov #include <QtEndian>
2387e663a3SNicolas Bonnefon
249ba963cbSNicolas Bonnefon #include "utils.h"
259ba963cbSNicolas Bonnefon
267a2f3a57SNicolas Bonnefon #include "data/compressedlinestorage.h"
277a2f3a57SNicolas Bonnefon
287a2f3a57SNicolas Bonnefon namespace {
297a2f3a57SNicolas Bonnefon // Functions to manipulate blocks
307a2f3a57SNicolas Bonnefon
317a2f3a57SNicolas Bonnefon // Create a new 32 bits block of the passed size,
327a2f3a57SNicolas Bonnefon // initialised at the passed position
block32_new(int block_size,uint32_t initial_position,char ** block_ptr)337a2f3a57SNicolas Bonnefon char* block32_new( int block_size, uint32_t initial_position,
347a2f3a57SNicolas Bonnefon char** block_ptr )
357a2f3a57SNicolas Bonnefon {
367a2f3a57SNicolas Bonnefon // malloc a block of the maximum possible size
377a2f3a57SNicolas Bonnefon // (where every line is >16384)
387a2f3a57SNicolas Bonnefon char* ptr = static_cast<char*>( malloc( 4 + block_size * 6 ) );
397a2f3a57SNicolas Bonnefon
407a2f3a57SNicolas Bonnefon if ( ptr ) {
417a2f3a57SNicolas Bonnefon // Write the initial_position
427a2f3a57SNicolas Bonnefon *(reinterpret_cast<uint32_t*>(ptr)) = initial_position;
437a2f3a57SNicolas Bonnefon *block_ptr = ptr + 4;
447a2f3a57SNicolas Bonnefon }
457a2f3a57SNicolas Bonnefon
467a2f3a57SNicolas Bonnefon return ptr;
477a2f3a57SNicolas Bonnefon }
487a2f3a57SNicolas Bonnefon
496e2e573cSNicolas Bonnefon // Create a new 64 bits block of the passed size,
506e2e573cSNicolas Bonnefon // initialised at the passed position
block64_new(int block_size,uint64_t initial_position,char ** block_ptr)516e2e573cSNicolas Bonnefon char* block64_new( int block_size, uint64_t initial_position,
526e2e573cSNicolas Bonnefon char** block_ptr )
536e2e573cSNicolas Bonnefon {
546e2e573cSNicolas Bonnefon // malloc a block of the maximum possible size
556e2e573cSNicolas Bonnefon // (where every line is >16384)
566e2e573cSNicolas Bonnefon char* ptr = static_cast<char*>( malloc( 8 + block_size * 10 ) );
576e2e573cSNicolas Bonnefon
586e2e573cSNicolas Bonnefon if ( ptr ) {
596e2e573cSNicolas Bonnefon // Write the initial_position
606e2e573cSNicolas Bonnefon *(reinterpret_cast<uint64_t*>(ptr)) = initial_position;
616e2e573cSNicolas Bonnefon *block_ptr = ptr + 8;
626e2e573cSNicolas Bonnefon }
636e2e573cSNicolas Bonnefon
646e2e573cSNicolas Bonnefon return ptr;
656e2e573cSNicolas Bonnefon }
666e2e573cSNicolas Bonnefon
676e2e573cSNicolas Bonnefon
687a2f3a57SNicolas Bonnefon // Add a one byte relative delta (0-127) and inc pointer
697a2f3a57SNicolas Bonnefon // First bit is always 0
block_add_one_byte_relative(char ** ptr,uint8_t value)707a2f3a57SNicolas Bonnefon void block_add_one_byte_relative( char** ptr, uint8_t value )
717a2f3a57SNicolas Bonnefon {
727a2f3a57SNicolas Bonnefon **ptr = value;
737a2f3a57SNicolas Bonnefon *ptr += sizeof( value );
747a2f3a57SNicolas Bonnefon }
757a2f3a57SNicolas Bonnefon
767a2f3a57SNicolas Bonnefon // Add a two bytes relative delta (0-16383) and inc pointer
777a2f3a57SNicolas Bonnefon // First 2 bits are always 10
block_add_two_bytes_relative(char ** ptr,uint16_t value)787a2f3a57SNicolas Bonnefon void block_add_two_bytes_relative( char** ptr, uint16_t value )
797a2f3a57SNicolas Bonnefon {
807a2f3a57SNicolas Bonnefon // Stored in big endian format in order to recognise the initial pattern:
817a2f3a57SNicolas Bonnefon // 10xx xxxx xxxx xxxx
827a2f3a57SNicolas Bonnefon // HO byte | LO byte
83*8b941e12SAnton Filimonov *(reinterpret_cast<uint16_t*>(*ptr)) = qToBigEndian( static_cast<uint16_t>( value | (1 << 15) ) );
847a2f3a57SNicolas Bonnefon *ptr += sizeof( value );
857a2f3a57SNicolas Bonnefon }
867a2f3a57SNicolas Bonnefon
877a2f3a57SNicolas Bonnefon // Add a signal and a 4 bytes absolute position and inc pointer
block32_add_absolute(char ** ptr,uint32_t value)887a2f3a57SNicolas Bonnefon void block32_add_absolute( char** ptr, uint32_t value )
897a2f3a57SNicolas Bonnefon {
907a2f3a57SNicolas Bonnefon // 2 bytes marker (actually only the first two bits are tested)
917a2f3a57SNicolas Bonnefon *(reinterpret_cast<uint16_t*>(*ptr)) = 0xFF;
927a2f3a57SNicolas Bonnefon *ptr += sizeof( uint16_t );
937a2f3a57SNicolas Bonnefon // Absolute value (machine endian)
947a2f3a57SNicolas Bonnefon *(reinterpret_cast<uint32_t*>(*ptr)) = value;
957a2f3a57SNicolas Bonnefon *ptr += sizeof( uint32_t );
967a2f3a57SNicolas Bonnefon }
977a2f3a57SNicolas Bonnefon
987a2f3a57SNicolas Bonnefon // Initialise the passed block for reading, returning
997a2f3a57SNicolas Bonnefon // the initial position and a pointer to the second entry.
block32_initial_pos(char * block,char ** ptr)1007a2f3a57SNicolas Bonnefon uint64_t block32_initial_pos( char* block, char** ptr )
1017a2f3a57SNicolas Bonnefon {
1027a2f3a57SNicolas Bonnefon *ptr = block + sizeof( uint32_t );
1037a2f3a57SNicolas Bonnefon return *(reinterpret_cast<uint32_t*>(block));
1047a2f3a57SNicolas Bonnefon }
1057a2f3a57SNicolas Bonnefon
1067a2f3a57SNicolas Bonnefon // Give the next position in the block based on the previous
1077a2f3a57SNicolas Bonnefon // position, then increase the pointer.
block32_next_pos(char ** ptr,uint64_t previous_pos)1087a2f3a57SNicolas Bonnefon uint64_t block32_next_pos( char** ptr, uint64_t previous_pos )
1097a2f3a57SNicolas Bonnefon {
1107a2f3a57SNicolas Bonnefon uint64_t pos = previous_pos;
1117a2f3a57SNicolas Bonnefon
1127a2f3a57SNicolas Bonnefon uint8_t byte = **ptr;
1137a2f3a57SNicolas Bonnefon ++(*ptr);
1147a2f3a57SNicolas Bonnefon if ( ! ( byte & 0x80 ) ) {
1157a2f3a57SNicolas Bonnefon // High order bit is 0
1167a2f3a57SNicolas Bonnefon pos += byte;
1177a2f3a57SNicolas Bonnefon }
1187a2f3a57SNicolas Bonnefon else if ( ( byte & 0xC0 ) == 0x80 ) {
1197a2f3a57SNicolas Bonnefon // We need to read the low order byte
1207a2f3a57SNicolas Bonnefon uint8_t lo_byte = **ptr;
1217a2f3a57SNicolas Bonnefon ++(*ptr);
1227a2f3a57SNicolas Bonnefon // Remove the starting 10b
1237a2f3a57SNicolas Bonnefon byte &= ~0xC0;
1247a2f3a57SNicolas Bonnefon // And form the displacement (stored as big endian)
1257a2f3a57SNicolas Bonnefon pos += ( (uint16_t) byte << 8 ) | (uint16_t) lo_byte;
1267a2f3a57SNicolas Bonnefon }
1277a2f3a57SNicolas Bonnefon else {
1287a2f3a57SNicolas Bonnefon // Skip the next byte (not used)
1297a2f3a57SNicolas Bonnefon ++(*ptr);
1307a2f3a57SNicolas Bonnefon // And read the new absolute pos (machine endian)
1317a2f3a57SNicolas Bonnefon pos = *(reinterpret_cast<uint32_t*>(*ptr));
1327a2f3a57SNicolas Bonnefon *ptr += sizeof( uint32_t );
1337a2f3a57SNicolas Bonnefon }
1347a2f3a57SNicolas Bonnefon
1357a2f3a57SNicolas Bonnefon return pos;
1367a2f3a57SNicolas Bonnefon }
1376e2e573cSNicolas Bonnefon
1386e2e573cSNicolas Bonnefon // Add a signal and a 8 bytes absolute position and inc pointer
block64_add_absolute(char ** ptr,uint64_t value)1396e2e573cSNicolas Bonnefon void block64_add_absolute( char** ptr, uint64_t value )
1406e2e573cSNicolas Bonnefon {
1416e2e573cSNicolas Bonnefon // This is unaligned, can cause problem on some CPUs
1426e2e573cSNicolas Bonnefon
1436e2e573cSNicolas Bonnefon // 2 bytes marker (actually only the first two bits are tested)
1446e2e573cSNicolas Bonnefon *(reinterpret_cast<uint16_t*>(*ptr)) = 0xFF;
1456e2e573cSNicolas Bonnefon *ptr += sizeof( uint16_t );
1466e2e573cSNicolas Bonnefon // Absolute value (machine endian)
1476e2e573cSNicolas Bonnefon *(reinterpret_cast<uint64_t*>(*ptr)) = value;
1486e2e573cSNicolas Bonnefon *ptr += sizeof( uint64_t );
1496e2e573cSNicolas Bonnefon }
1506e2e573cSNicolas Bonnefon
1516e2e573cSNicolas Bonnefon // Initialise the passed block for reading, returning
1526e2e573cSNicolas Bonnefon // the initial position and a pointer to the second entry.
block64_initial_pos(char * block,char ** ptr)1536e2e573cSNicolas Bonnefon uint64_t block64_initial_pos( char* block, char** ptr )
1546e2e573cSNicolas Bonnefon {
1556e2e573cSNicolas Bonnefon *ptr = block + sizeof( uint64_t );
1566e2e573cSNicolas Bonnefon return *(reinterpret_cast<uint64_t*>(block));
1576e2e573cSNicolas Bonnefon }
1586e2e573cSNicolas Bonnefon
1596e2e573cSNicolas Bonnefon // Give the next position in the block based on the previous
1606e2e573cSNicolas Bonnefon // position, then increase the pointer.
block64_next_pos(char ** ptr,uint64_t previous_pos)1616e2e573cSNicolas Bonnefon uint64_t block64_next_pos( char** ptr, uint64_t previous_pos )
1626e2e573cSNicolas Bonnefon {
1636e2e573cSNicolas Bonnefon uint64_t pos = previous_pos;
1646e2e573cSNicolas Bonnefon
1656e2e573cSNicolas Bonnefon uint8_t byte = **ptr;
1666e2e573cSNicolas Bonnefon ++(*ptr);
1676e2e573cSNicolas Bonnefon if ( ! ( byte & 0x80 ) ) {
1686e2e573cSNicolas Bonnefon // High order bit is 0
1696e2e573cSNicolas Bonnefon pos += byte;
1706e2e573cSNicolas Bonnefon }
1716e2e573cSNicolas Bonnefon else if ( ( byte & 0xC0 ) == 0x80 ) {
1726e2e573cSNicolas Bonnefon // We need to read the low order byte
1736e2e573cSNicolas Bonnefon uint8_t lo_byte = **ptr;
1746e2e573cSNicolas Bonnefon ++(*ptr);
1756e2e573cSNicolas Bonnefon // Remove the starting 10b
1766e2e573cSNicolas Bonnefon byte &= ~0xC0;
1776e2e573cSNicolas Bonnefon // And form the displacement (stored as big endian)
1786e2e573cSNicolas Bonnefon pos += ( (uint16_t) byte << 8 ) | (uint16_t) lo_byte;
1796e2e573cSNicolas Bonnefon }
1806e2e573cSNicolas Bonnefon else {
1816e2e573cSNicolas Bonnefon // Skip the next byte (not used)
1826e2e573cSNicolas Bonnefon ++(*ptr);
1836e2e573cSNicolas Bonnefon // And read the new absolute pos (machine endian)
1846e2e573cSNicolas Bonnefon pos = *(reinterpret_cast<uint64_t*>(*ptr));
1856e2e573cSNicolas Bonnefon *ptr += sizeof( uint64_t );
1866e2e573cSNicolas Bonnefon }
1876e2e573cSNicolas Bonnefon
1886e2e573cSNicolas Bonnefon return pos;
1896e2e573cSNicolas Bonnefon }
1907a2f3a57SNicolas Bonnefon }
1917a2f3a57SNicolas Bonnefon
move_from(CompressedLinePositionStorage && orig)1923c46a469SNicolas Bonnefon void CompressedLinePositionStorage::move_from(
1933c46a469SNicolas Bonnefon CompressedLinePositionStorage&& orig )
1943c46a469SNicolas Bonnefon {
1953c46a469SNicolas Bonnefon nb_lines_ = orig.nb_lines_;
1963c46a469SNicolas Bonnefon first_long_line_ = orig.first_long_line_;
1973c46a469SNicolas Bonnefon current_pos_ = orig.current_pos_;
1983c46a469SNicolas Bonnefon block_pointer_ = orig.block_pointer_;
1993c46a469SNicolas Bonnefon previous_block_pointer_ = orig.previous_block_pointer_;
2003c46a469SNicolas Bonnefon
2013c46a469SNicolas Bonnefon orig.nb_lines_ = 0;
2023c46a469SNicolas Bonnefon }
2033c46a469SNicolas Bonnefon
2043c46a469SNicolas Bonnefon // Move constructor
CompressedLinePositionStorage(CompressedLinePositionStorage && orig)2053c46a469SNicolas Bonnefon CompressedLinePositionStorage::CompressedLinePositionStorage(
2063c46a469SNicolas Bonnefon CompressedLinePositionStorage&& orig )
207fcf40f17SNicolas Bonnefon : block32_index_( std::move( orig.block32_index_ ) ),
208fcf40f17SNicolas Bonnefon block64_index_( std::move( orig.block64_index_ ) )
2093c46a469SNicolas Bonnefon {
2103c46a469SNicolas Bonnefon move_from( std::move( orig ) );
2113c46a469SNicolas Bonnefon }
2123c46a469SNicolas Bonnefon
free_blocks()21325d0072cSNicolas Bonnefon void CompressedLinePositionStorage::free_blocks()
21425d0072cSNicolas Bonnefon {
21525d0072cSNicolas Bonnefon for ( char* block : block32_index_ ) {
21625d0072cSNicolas Bonnefon void* p = static_cast<void*>( block );
21725d0072cSNicolas Bonnefon free( p );
21825d0072cSNicolas Bonnefon }
21925d0072cSNicolas Bonnefon
22025d0072cSNicolas Bonnefon for ( char* block : block64_index_ ) {
22125d0072cSNicolas Bonnefon void* p = static_cast<void*>( block );
22225d0072cSNicolas Bonnefon free( p );
22325d0072cSNicolas Bonnefon }
22425d0072cSNicolas Bonnefon }
22525d0072cSNicolas Bonnefon
2263c46a469SNicolas Bonnefon // Move assignement
operator =(CompressedLinePositionStorage && orig)2273c46a469SNicolas Bonnefon CompressedLinePositionStorage& CompressedLinePositionStorage::operator=(
2283c46a469SNicolas Bonnefon CompressedLinePositionStorage&& orig )
2293c46a469SNicolas Bonnefon {
23025d0072cSNicolas Bonnefon free_blocks();
23125d0072cSNicolas Bonnefon
2323c46a469SNicolas Bonnefon block32_index_ = std::move( orig.block32_index_ );
233fcf40f17SNicolas Bonnefon block64_index_ = std::move( orig.block64_index_ );
2343c46a469SNicolas Bonnefon move_from( std::move( orig ) );
2353c46a469SNicolas Bonnefon
2363c46a469SNicolas Bonnefon return *this;
2373c46a469SNicolas Bonnefon }
2383c46a469SNicolas Bonnefon
~CompressedLinePositionStorage()2393c46a469SNicolas Bonnefon CompressedLinePositionStorage::~CompressedLinePositionStorage()
2403c46a469SNicolas Bonnefon {
24125d0072cSNicolas Bonnefon free_blocks();
2423c46a469SNicolas Bonnefon }
2433c46a469SNicolas Bonnefon
2447a2f3a57SNicolas Bonnefon // template<int BLOCK_SIZE>
append(uint64_t pos)2457a2f3a57SNicolas Bonnefon void CompressedLinePositionStorage::append( uint64_t pos )
2467a2f3a57SNicolas Bonnefon {
247fcf40f17SNicolas Bonnefon // Lines must be stored in order
248fcf40f17SNicolas Bonnefon assert( ( pos > current_pos_ ) || ( pos == 0 ) );
249fcf40f17SNicolas Bonnefon
2503c46a469SNicolas Bonnefon // Save the pointer in case we need to "pop_back"
2513c46a469SNicolas Bonnefon previous_block_pointer_ = block_pointer_;
2523c46a469SNicolas Bonnefon
2536e2e573cSNicolas Bonnefon bool store_in_big = false;
2546e2e573cSNicolas Bonnefon if ( pos > UINT32_MAX ) {
2556e2e573cSNicolas Bonnefon store_in_big = true;
2566e2e573cSNicolas Bonnefon if ( first_long_line_ == UINT32_MAX ) {
2576e2e573cSNicolas Bonnefon // First "big" end of line, we will start a new (64) block
2586e2e573cSNicolas Bonnefon first_long_line_ = nb_lines_;
2596e2e573cSNicolas Bonnefon block_pointer_ = nullptr;
2606e2e573cSNicolas Bonnefon }
2616e2e573cSNicolas Bonnefon }
2626e2e573cSNicolas Bonnefon
2637a2f3a57SNicolas Bonnefon if ( ! block_pointer_ ) {
2647a2f3a57SNicolas Bonnefon // We need to start a new block
2656e2e573cSNicolas Bonnefon if ( ! store_in_big )
2667a2f3a57SNicolas Bonnefon block32_index_.push_back(
2677a2f3a57SNicolas Bonnefon block32_new( BLOCK_SIZE, pos, &block_pointer_ ) );
2686e2e573cSNicolas Bonnefon else
2696e2e573cSNicolas Bonnefon block64_index_.push_back(
2706e2e573cSNicolas Bonnefon block64_new( BLOCK_SIZE, pos, &block_pointer_ ) );
2717a2f3a57SNicolas Bonnefon }
2727a2f3a57SNicolas Bonnefon else {
2737a2f3a57SNicolas Bonnefon uint64_t delta = pos - current_pos_;
2747a2f3a57SNicolas Bonnefon if ( delta < 128 ) {
2757a2f3a57SNicolas Bonnefon // Code relative on one byte
2767a2f3a57SNicolas Bonnefon block_add_one_byte_relative( &block_pointer_, delta );
2777a2f3a57SNicolas Bonnefon }
2787a2f3a57SNicolas Bonnefon else if ( delta < 16384 ) {
2797a2f3a57SNicolas Bonnefon // Code relative on two bytes
2807a2f3a57SNicolas Bonnefon block_add_two_bytes_relative( &block_pointer_, delta );
2817a2f3a57SNicolas Bonnefon }
2827a2f3a57SNicolas Bonnefon else {
2837a2f3a57SNicolas Bonnefon // Code absolute
2846e2e573cSNicolas Bonnefon if ( ! store_in_big )
2857a2f3a57SNicolas Bonnefon block32_add_absolute( &block_pointer_, pos );
2866e2e573cSNicolas Bonnefon else
2876e2e573cSNicolas Bonnefon block64_add_absolute( &block_pointer_, pos );
2887a2f3a57SNicolas Bonnefon }
2897a2f3a57SNicolas Bonnefon }
2907a2f3a57SNicolas Bonnefon
2917a2f3a57SNicolas Bonnefon current_pos_ = pos;
2927a2f3a57SNicolas Bonnefon ++nb_lines_;
2937a2f3a57SNicolas Bonnefon
2946e2e573cSNicolas Bonnefon if ( ! store_in_big ) {
2957a2f3a57SNicolas Bonnefon if ( nb_lines_ % BLOCK_SIZE == 0 ) {
2967a2f3a57SNicolas Bonnefon // We have finished the block
29787e663a3SNicolas Bonnefon
29887e663a3SNicolas Bonnefon // Let's reduce its size to what is actually used
29987e663a3SNicolas Bonnefon int block_index = nb_lines_ / BLOCK_SIZE - 1;
30087e663a3SNicolas Bonnefon char* block = block32_index_[block_index];
30187e663a3SNicolas Bonnefon // We allocate extra space for the last element in case it
30287e663a3SNicolas Bonnefon // is replaced by an absolute value in the future (following a pop_back)
30387e663a3SNicolas Bonnefon size_t new_size = ( previous_block_pointer_
30487e663a3SNicolas Bonnefon + sizeof( uint16_t ) + sizeof( uint32_t ) ) - block;
30587e663a3SNicolas Bonnefon void* new_location = realloc( block, new_size );
30687e663a3SNicolas Bonnefon if ( new_location )
30787e663a3SNicolas Bonnefon block32_index_[block_index] = static_cast<char*>( new_location );
30887e663a3SNicolas Bonnefon
3097a2f3a57SNicolas Bonnefon block_pointer_ = nullptr;
31005467f52SNicolas Bonnefon previous_block_pointer_ = static_cast<char*>( new_location ) + ( previous_block_pointer_ - block );
3117a2f3a57SNicolas Bonnefon }
3127a2f3a57SNicolas Bonnefon }
3136e2e573cSNicolas Bonnefon else {
3146e2e573cSNicolas Bonnefon if ( ( nb_lines_ - first_long_line_ ) % BLOCK_SIZE == 0 ) {
3156e2e573cSNicolas Bonnefon // We have finished the block
3166e2e573cSNicolas Bonnefon
3176e2e573cSNicolas Bonnefon // Let's reduce its size to what is actually used
3186e2e573cSNicolas Bonnefon int block_index = ( nb_lines_ - first_long_line_ ) / BLOCK_SIZE - 1;
3196e2e573cSNicolas Bonnefon char* block = block64_index_[block_index];
3206e2e573cSNicolas Bonnefon // We allocate extra space for the last element in case it
3216e2e573cSNicolas Bonnefon // is replaced by an absolute value in the future (following a pop_back)
3226e2e573cSNicolas Bonnefon size_t new_size = ( previous_block_pointer_
3236e2e573cSNicolas Bonnefon + sizeof( uint16_t ) + sizeof( uint64_t ) ) - block;
3246e2e573cSNicolas Bonnefon void* new_location = realloc( block, new_size );
3256e2e573cSNicolas Bonnefon if ( new_location )
3266e2e573cSNicolas Bonnefon block64_index_[block_index] = static_cast<char*>( new_location );
3276e2e573cSNicolas Bonnefon
3286e2e573cSNicolas Bonnefon block_pointer_ = nullptr;
32905467f52SNicolas Bonnefon previous_block_pointer_ = static_cast<char*>( new_location ) + ( previous_block_pointer_ - block );
3306e2e573cSNicolas Bonnefon }
3316e2e573cSNicolas Bonnefon }
3326e2e573cSNicolas Bonnefon }
3337a2f3a57SNicolas Bonnefon
3347a2f3a57SNicolas Bonnefon // template<int BLOCK_SIZE>
at(uint32_t index) const3357151e3acSNicolas Bonnefon uint64_t CompressedLinePositionStorage::at( uint32_t index ) const
3367a2f3a57SNicolas Bonnefon {
3377a2f3a57SNicolas Bonnefon char* ptr;
3387151e3acSNicolas Bonnefon uint64_t position;
3397a2f3a57SNicolas Bonnefon
3407151e3acSNicolas Bonnefon Cache* last_read = last_read_.getPtr();
3417151e3acSNicolas Bonnefon
3426e2e573cSNicolas Bonnefon if ( index < first_long_line_ ) {
3437151e3acSNicolas Bonnefon if ( ( index == last_read->index + 1 ) && ( index % BLOCK_SIZE != 0 ) ) {
3447151e3acSNicolas Bonnefon position = last_read->position;
3457151e3acSNicolas Bonnefon ptr = last_read->ptr;
3467151e3acSNicolas Bonnefon
3477151e3acSNicolas Bonnefon position = block32_next_pos( &ptr, position );
3487151e3acSNicolas Bonnefon }
3497151e3acSNicolas Bonnefon else {
3507151e3acSNicolas Bonnefon char* block = block32_index_[ index / BLOCK_SIZE ];
3517151e3acSNicolas Bonnefon position = block32_initial_pos( block, &ptr );
3527151e3acSNicolas Bonnefon
3537151e3acSNicolas Bonnefon for ( uint32_t i = 0; i < index % BLOCK_SIZE; i++ ) {
3547a2f3a57SNicolas Bonnefon // Go through all the lines in the block till the one we want
3557a2f3a57SNicolas Bonnefon position = block32_next_pos( &ptr, position );
3567a2f3a57SNicolas Bonnefon }
3577151e3acSNicolas Bonnefon }
3586e2e573cSNicolas Bonnefon }
3596e2e573cSNicolas Bonnefon else {
3606e2e573cSNicolas Bonnefon const uint32_t index_in_64 = index - first_long_line_;
3616e2e573cSNicolas Bonnefon if ( ( index == last_read->index + 1 ) && ( index_in_64 % BLOCK_SIZE != 0 ) ) {
3626e2e573cSNicolas Bonnefon position = last_read->position;
3636e2e573cSNicolas Bonnefon ptr = last_read->ptr;
3646e2e573cSNicolas Bonnefon
3656e2e573cSNicolas Bonnefon position = block64_next_pos( &ptr, position );
3666e2e573cSNicolas Bonnefon }
3676e2e573cSNicolas Bonnefon else {
3686e2e573cSNicolas Bonnefon char* block = block64_index_[ index_in_64 / BLOCK_SIZE ];
3696e2e573cSNicolas Bonnefon position = block64_initial_pos( block, &ptr );
3706e2e573cSNicolas Bonnefon
3716e2e573cSNicolas Bonnefon for ( uint32_t i = 0; i < index_in_64 % BLOCK_SIZE; i++ ) {
3726e2e573cSNicolas Bonnefon // Go through all the lines in the block till the one we want
3736e2e573cSNicolas Bonnefon position = block64_next_pos( &ptr, position );
3746e2e573cSNicolas Bonnefon }
3756e2e573cSNicolas Bonnefon }
3766e2e573cSNicolas Bonnefon }
3777151e3acSNicolas Bonnefon
3787151e3acSNicolas Bonnefon // Populate our cache ready for next consecutive read
3797151e3acSNicolas Bonnefon last_read->index = index;
3807151e3acSNicolas Bonnefon last_read->position = position;
3817151e3acSNicolas Bonnefon last_read->ptr = ptr;
3827a2f3a57SNicolas Bonnefon
3837a2f3a57SNicolas Bonnefon return position;
3847a2f3a57SNicolas Bonnefon }
3857a2f3a57SNicolas Bonnefon
append_list(const std::vector<uint64_t> & positions)3867a2f3a57SNicolas Bonnefon void CompressedLinePositionStorage::append_list(
387e49f4922SNicolas Bonnefon const std::vector<uint64_t>& positions )
3887a2f3a57SNicolas Bonnefon {
3897a2f3a57SNicolas Bonnefon // This is not very clever, but caching should make it
3907a2f3a57SNicolas Bonnefon // reasonably fast.
391e49f4922SNicolas Bonnefon for ( uint32_t i = 0; i < positions.size(); i++ )
392e49f4922SNicolas Bonnefon append( positions.at( i ) );
3937a2f3a57SNicolas Bonnefon }
3947a2f3a57SNicolas Bonnefon
3957a2f3a57SNicolas Bonnefon // template<int BLOCK_SIZE>
pop_back()3967a2f3a57SNicolas Bonnefon void CompressedLinePositionStorage::pop_back()
3977a2f3a57SNicolas Bonnefon {
3983c46a469SNicolas Bonnefon // Removing the last entered data, there are two cases
3993c46a469SNicolas Bonnefon if ( previous_block_pointer_ ) {
4003c46a469SNicolas Bonnefon // The last append was a normal entry in an existing block,
4013c46a469SNicolas Bonnefon // so we can just revert the pointer
4023c46a469SNicolas Bonnefon block_pointer_ = previous_block_pointer_;
4033c46a469SNicolas Bonnefon previous_block_pointer_ = nullptr;
4043c46a469SNicolas Bonnefon }
4053c46a469SNicolas Bonnefon else {
4063c46a469SNicolas Bonnefon // A new block has been created for the last entry, we need
4073c46a469SNicolas Bonnefon // to de-alloc it.
4083c46a469SNicolas Bonnefon
409fcf40f17SNicolas Bonnefon if ( first_long_line_ == UINT32_MAX ) {
4103c46a469SNicolas Bonnefon // If we try to pop_back() twice, we're dead!
4113c46a469SNicolas Bonnefon assert( ( nb_lines_ - 1 ) % BLOCK_SIZE == 0 );
4123c46a469SNicolas Bonnefon
4133c46a469SNicolas Bonnefon char* block = block32_index_.back();
4143c46a469SNicolas Bonnefon block32_index_.pop_back();
4153c46a469SNicolas Bonnefon free( block );
416fcf40f17SNicolas Bonnefon }
417fcf40f17SNicolas Bonnefon else {
418fcf40f17SNicolas Bonnefon // If we try to pop_back() twice, we're dead!
419fcf40f17SNicolas Bonnefon assert( ( nb_lines_ - first_long_line_ - 1 ) % BLOCK_SIZE == 0 );
420fcf40f17SNicolas Bonnefon
421fcf40f17SNicolas Bonnefon char* block = block64_index_.back();
422fcf40f17SNicolas Bonnefon block64_index_.pop_back();
423fcf40f17SNicolas Bonnefon free( block );
424fcf40f17SNicolas Bonnefon }
4253c46a469SNicolas Bonnefon
4263c46a469SNicolas Bonnefon block_pointer_ = nullptr;
4273c46a469SNicolas Bonnefon }
4283c46a469SNicolas Bonnefon
4293c46a469SNicolas Bonnefon --nb_lines_;
4303c46a469SNicolas Bonnefon current_pos_ = at( nb_lines_ - 1 );
4317a2f3a57SNicolas Bonnefon }
432