56template<
typename CHAR_T,
unsigned CHAR_SIZE_BITS = sizeof(CHAR_T) * 8>
85 template<
typename Container>
219 ResultLCP
par_k_compare(
const BitString& other,
size_t lcp,
size_t max_compare, uintmax_t* d_a, uintmax_t* d_largeblock,
size_t& max_copied)
const noexcept;
246 const uintmax_t*
data() const noexcept {
return m_data.data(); }
274 static constexpr std::array<uintmax_t, ALPHA>
GET_MASKS();
287 static constexpr CHAR_T
GET_CHAR(uintmax_t word,
unsigned bit_index);
291 template<
typename CT,
unsigned CSB>
314 void to_file(
const std::string& filename)
const;
379 : m_bs(bs), m_index(index)
390 return m_bs[m_index];
423 return m_index == other.m_index;
454template<
typename CHAR_T,
unsigned CHAR_SIZE_BITS>
457 std::array<unsigned, ALPHA> shifts;
458 for (
unsigned i = 0; i < ALPHA; ++i)
460 shifts[ALPHA - i - 1] = i * CHAR_SIZE_BITS;
465template<
typename CHAR_T,
unsigned CHAR_SIZE_BITS>
469 for (
unsigned i = 0; i < CHAR_SIZE_BITS; ++i)
471 mask |=
static_cast<uintmax_t
>(1) << i;
474 std::array<uintmax_t, ALPHA> masks;
475 for (
unsigned i = 0; i < ALPHA; ++i)
477 masks[i] = mask << m_shifts[i];
482template<
typename CHAR_T,
unsigned CHAR_SIZE_BITS>
485 const uintmax_t masked_word = word & m_masks[bit_index];
486 const uintmax_t shifted_word = masked_word >> m_shifts[bit_index];
487 return static_cast<CHAR_T
>(shifted_word);
490template<
typename CHAR_T,
unsigned CHAR_SIZE_BITS>
497 for (
size_t i = 0; i <
size(); ++i)
499 const size_t word_index = i /
ALPHA;
500 const size_t bit_index = i %
ALPHA;
501 const uintmax_t mask =
static_cast<uintmax_t
>(
data[i]) <<
m_shifts[bit_index];
502 m_data[word_index] |= mask;
506template<
typename CHAR_T,
unsigned CHAR_SIZE_BITS>
507template<
typename Container>
509 : m_size(data.size())
514 for (
size_t i = 0; i <
size(); ++i)
516 const size_t word_index = i /
ALPHA;
517 const size_t bit_index = i %
ALPHA;
518 const uintmax_t mask =
static_cast<uintmax_t
>(
data[i]) <<
m_shifts[bit_index];
519 m_data[word_index] |= mask;
523template<
typename CHAR_T,
unsigned CHAR_SIZE_BITS>
526 const size_t word_index = size() / ALPHA;
527 const size_t bit_index = size() % ALPHA;
528 const uintmax_t mask =
static_cast<uintmax_t
>(c) << m_shifts[bit_index];
530 if (word_index >= m_data.size())
535 m_data[word_index] |= mask;
539template<
typename CHAR_T,
unsigned CHAR_SIZE_BITS>
542 return GET_CHAR(m_data[index / ALPHA], index % ALPHA);
545template<
typename CHAR_T,
unsigned CHAR_SIZE_BITS>
548 const size_t min_size = std::min(size(), other.size());
549 const size_t max_compare_until = lcp + max_compare;
550 size_t word_index = lcp / ALPHA;
554 while (lcp < min_size && lcp < max_compare_until)
556 const uintmax_t XOR = m_data[word_index] ^ other.m_data[word_index];
565 const size_t l_zero = std::countl_zero(XOR);
567 lcp += l_zero / CHAR_SIZE_BITS;
569 const size_t bit_index = lcp % ALPHA;
572 const CHAR_T lhs = GET_CHAR(m_data[word_index], bit_index);
573 const CHAR_T rhs = GET_CHAR(other.m_data[word_index], bit_index);
575 return { lhs <=> rhs, lcp };
580 return { size() <=> other.size(), min_size };
583 return { std::strong_ordering::equal, lcp };
586template<
typename CHAR_T,
unsigned CHAR_SIZE_BITS>
590 if (max_compare <= MIN_PAR_COMPARE_CHAR_SIZE)
592 return seq_k_compare(other, lcp, max_compare);
595 const size_t min_size = std::min(size(), other.size());
596 const size_t min_word_count = std::min(word_count(), other.word_count());
597 size_t word_index = lcp / ALPHA;
600 const size_t num_remaining_words = (min_word_count > word_index) ? (min_word_count - word_index) : 0;
604 const size_t end_char_index = lcp + max_compare;
605 const size_t end_word_index = (end_char_index + ALPHA - 1) / ALPHA;
606 const size_t max_compare_words = (end_word_index > word_index) ? (end_word_index - word_index) : 0;
609 const size_t actual_max_compare_words = std::min(max_compare_words, num_remaining_words);
614 return seq_k_compare(other, lcp, max_compare);
618 if (max_copied < word_index + actual_max_compare_words)
620 size_t end_copy_index = word_index + actual_max_compare_words;
623 size_t end_copy = std::min(std::bit_ceil(end_copy_index), word_count());
624 if (end_copy > max_copied) {
625 copy_to_device(d_a + max_copied, data() + max_copied, end_copy - max_copied);
626 max_copied = end_copy;
633 auto msw =
par_find_mismatch(d_a + word_index, other.data() + word_index, d_largeblock, actual_max_compare_words);
639 if (msw == actual_max_compare_words)
644 return { size() <=> other.size(), min_size };
647 return { std::strong_ordering::equal, lcp };
651 word_index = lcp / ALPHA;
654 const uintmax_t XOR = m_data[word_index] ^ other.m_data[word_index];
655 const size_t l_zero = std::countl_zero(XOR);
657 lcp += l_zero / CHAR_SIZE_BITS;
659 const size_t bit_index = lcp % ALPHA;
662 const CHAR_T lhs = GET_CHAR(m_data[word_index], bit_index);
663 const CHAR_T rhs = GET_CHAR(other.m_data[word_index], bit_index);
665 return { lhs <=> rhs, lcp };
668template<
typename CHAR_T,
unsigned CHAR_SIZE_BITS>
671 static constexpr unsigned shift = WORD_SIZE_BITS - 8;
673 for (
size_t i = 0, a = 0; i + ALPHA <= size(); i += ALPHA, ++a)
675 uintmax_t word = m_data[a];
677 for (
unsigned c = 0; c < WORD_SIZE_BITS / 8; c++, word <<= 8)
679 os << static_cast<uint8_t>(word >> shift);
684 if (size() % ALPHA != 0 && !m_data.empty())
686 uintmax_t word = m_data.back();
687 unsigned remaining_chars = size() % ALPHA;
688 unsigned remaining_bits = remaining_chars * CHAR_SIZE_BITS;
689 unsigned bytes_to_print = (remaining_bits + 7) / 8;
692 for (
unsigned byte_idx = 0; byte_idx < bytes_to_print; ++byte_idx)
694 os << static_cast<uint8_t>(word >> (shift - byte_idx * 8));
709template<
typename CHAR_T,
unsigned CHAR_SIZE_BITS>
719template<
typename CHAR_T,
unsigned CHAR_SIZE_BITS>
722 file.write(
reinterpret_cast<const char*
>(&m_size),
sizeof(
size_t));
723 file.write(
reinterpret_cast<const char*
>(m_data.data()), m_data.size() *
sizeof(uintmax_t));
726template<
typename CHAR_T,
unsigned CHAR_SIZE_BITS>
729 std::ofstream file(filename, std::ios::binary);
732 throw std::runtime_error(
"Failed to open file for writing: " + filename);
738template<
typename CHAR_T,
unsigned CHAR_SIZE_BITS>
743 file.read(
reinterpret_cast<char*
>(&bs.
m_size),
sizeof(
size_t));
745 throw std::runtime_error(
"Failed to read size from file stream.");
748 const size_t word_count = (bs.
size() + ALPHA - 1) / ALPHA;
749 bs.
m_data.resize(word_count, 0);
751 if (word_count > 0) {
752 file.read(
reinterpret_cast<char*
>(bs.
m_data.data()), word_count *
sizeof(uintmax_t));
754 throw std::runtime_error(
"Failed to read data from file stream.");
762template<
typename CHAR_T,
unsigned CHAR_SIZE_BITS>
765 std::ifstream file(filename, std::ios::binary);
768 throw std::runtime_error(
"Failed to open file for reading: " + filename);
770 return from_file(file);
774template<
typename CHAR_T,
unsigned CHAR_SIZE_BITS>
780 for (CHAR_T c : *
this)
783 str.push_back(
static_cast<char>(c));
static constexpr size_t MIN_PAR_COMPARE_WORD_SIZE
Minimum number of words required to trigger parallel comparison.
std::ostream & operator<<(std::ostream &os, const BitString< CHAR_T, CHAR_SIZE_BITS > &bs)
Overloaded stream insertion operator for printing BitString content.
An iterator class for traversing the characters within a BitString.
bool operator==(const Iterator &other) const noexcept
Compares this iterator with another for equality.
const BitString & m_bs
Reference to the BitString being iterated over.
std::ptrdiff_t difference_type
std::forward_iterator_tag iterator_category
size_t m_index
Current character index.
Iterator & operator++() noexcept
Pre-increments the iterator to point to the next character.
Iterator operator++(int) noexcept
Post-increments the iterator.
Iterator(const BitString &bs, size_t index)
Constructs an iterator pointing to a specific character index.
CHAR_T operator*() const noexcept
Dereferences the iterator to get the character at the current position.
A class to store strings compactly into integers, packing multiple characters into a single word.
size_t word_count() const noexcept
Returns the number of uintmax_t words used for storage.
void to_file(std::ofstream &file) const
Writes the BitString contents to an already open output file stream.
void print_bytes(std::ostream &os) const
Prints the raw byte representation of the BitString to an output stream.
void to_file(const std::string &filename) const
Writes the BitString contents to a file in binary format.
CHAR_T operator[](size_t index) const
Accesses the character at a specific index.
static BitString from_file(std::ifstream &file)
Reads a BitString from an already open input file stream.
size_t size() const noexcept
Returns the number of characters stored in the BitString.
BitString()=default
Default constructor.
Iterator end() const noexcept
Returns an iterator pointing past the end of the BitString.
void clear() noexcept
Clears the contents of the BitString, making it empty.
BitString(const CHAR_T *data, size_t size)
Constructs a BitString object from a raw character array.
void push_back(CHAR_T c) noexcept
Appends a single character to the end of the BitString.
friend std::ostream & operator<<(std::ostream &os, const BitString< CT, CSB > &bs)
static constexpr std::array< unsigned, ALPHA > m_shifts
Compile-time generated array of bit shift amounts.
static constexpr std::array< unsigned, ALPHA > GET_SHIFTS()
Generates the bit shift amounts needed for character extraction/insertion at compile time.
size_t m_size
The number of characters stored in the BitString.
static constexpr unsigned ALPHA
Number of characters that can be packed into a single storage word.
std::vector< uintmax_t > m_data
Internal storage vector holding the packed character data.
ResultLCP par_k_compare(const BitString &other, size_t lcp, size_t max_compare, uintmax_t *d_a, uintmax_t *d_largeblock, size_t &max_copied) const noexcept
Performs parallel comparison (potentially using CUDA) with another BitString, starting from a given L...
Iterator begin() const noexcept
Returns an iterator pointing to the beginning of the BitString.
static constexpr CHAR_T GET_CHAR(uintmax_t word, unsigned bit_index)
Extracts a single character from a given word at a specific bit index (sub-word position).
BitString(const Container &data)
Constructs a BitString object from a container of characters.
static constexpr std::array< uintmax_t, ALPHA > m_masks
Compile-time generated array of bit masks.
ResultLCP par_k_compare(const BitString &other, size_t lcp, uintmax_t *d_a, uintmax_t *d_largeblock, size_t &max_copied) const noexcept
Performs parallel comparison (potentially using CUDA) with another BitString, starting from a given L...
static BitString from_file(const std::string &filename)
Reads a BitString from a file in binary format.
ResultLCP seq_k_compare(const BitString &other, size_t lcp, size_t max_compare) const noexcept
Performs sequential comparison with another BitString, starting from a given LCP offset,...
static constexpr std::array< uintmax_t, ALPHA > GET_MASKS()
Generates the bit masks needed for character extraction at compile time.
std::string to_string() const noexcept
Converts the BitString back to a standard std::string.
const uintmax_t * data() const noexcept
Provides direct access to the underlying packed data array.
static constexpr unsigned WORD_SIZE_BITS
Size of the underlying storage word (uintmax_t) in bits.
BitString(const std::string &data)
Constructs a BitString object from a std::string.
static constexpr size_t MIN_PAR_COMPARE_CHAR_SIZE
Minimum number of characters required to trigger parallel comparison. Derived from MIN_PAR_COMPARE_WO...
ResultLCP seq_k_compare(const BitString &other, size_t lcp) const noexcept
Performs sequential comparison with another BitString, starting from a given LCP offset.
Provides utility functions and classes for CUDA operations.
T * copy_to_device(T *d_arr, const T *arr, size_t size)
Copies data from host memory to existing device memory.
size_t par_find_mismatch(const uintmax_t *const d_a, const uintmax_t *const b, uintmax_t *d_large_block, size_t n)
GPU-accelerated implementation of finding the first mismatching word with pre-allocated memory.
CUDA-accelerated Most Significant Word finding algorithms.
Structure to hold the result of a comparison, including the ordering and the length of the common pre...
size_t lcp
The length of the longest common prefix in characters.
std::strong_ordering result
The comparison result (less, greater, equal).