Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
# specify the C++ standard
cmake_minimum_required(VERSION 3.14)
cmake_policy(SET CMP0168 NEW)
cmake_policy(SET CMP0167 NEW)
if(POLICY CMP0168)
cmake_policy(SET CMP0168 NEW)
endif()

if(POLICY CMP0167)
cmake_policy(SET CMP0167 NEW)
endif()

# set the project name
project(BitLib VERSION 0.3.0)
Expand Down Expand Up @@ -41,13 +46,17 @@ target_sources(bitlib INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/include/bitlib/bit-algorithms/transform.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/bitlib/bit-algorithms/type_traits.hpp

${CMAKE_CURRENT_SOURCE_DIR}/include/bitlib/bit-containers/bit_array_dynamic_extent.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/bitlib/bit-containers/bit-containers.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/bitlib/bit-containers/bit_array.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/bitlib/bit-containers/bit_array_base.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/bitlib/bit-containers/bit_array_dynamic_extent.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/bitlib/bit-containers/bit_array_ref.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/bitlib/bit-containers/bit_bitsof.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/bitlib/bit-containers/bit-containers.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/bitlib/bit-containers/bit_literal.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/bitlib/bit-containers/bit_mdspan_accessor.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/bitlib/bit-containers/bit_span.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/bitlib/bit-containers/bit_vector.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/bitlib/bit-containers/bounds.hpp

${CMAKE_CURRENT_SOURCE_DIR}/include/bitlib/bit-iterator/bit_details.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/bitlib/bit-iterator/bit.hpp
Expand Down
1 change: 1 addition & 0 deletions include/bitlib/bit-containers/bit_array.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "bitlib/bit-containers/bit_array_base.hpp"
#include "bitlib/bit-containers/bit_bitsof.hpp"
#include "bitlib/bit-containers/bit_span.hpp"
#include "bitlib/bit-containers/bounds.hpp"
#include "bitlib/bit-iterator/bit.hpp"
#include "bitlib/bit_concepts.hpp"

Expand Down
21 changes: 19 additions & 2 deletions include/bitlib/bit-containers/bit_array_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "bitlib/bit-algorithms/bit_algorithm.hpp"
#include "bitlib/bit-containers/bit_bitsof.hpp"
#include "bitlib/bit-containers/bit_span.hpp"
#include "bitlib/bit-containers/bounds.hpp"
#include "bitlib/bit-iterator/bit.hpp"

namespace bit {
Expand Down Expand Up @@ -163,17 +164,33 @@ class bit_array_base {
/**
* @brief Slice operations - returns a bit_array_ref
*/
constexpr auto operator()(size_type offset, size_type right) const noexcept {
constexpr auto operator()(const size_type offset, const size_type right) const noexcept {
return bit_array_ref<bit_value, const word_type>(&this->at(offset), right - offset);
}

template <std::integral U = int>
constexpr auto operator()(const bounds<U>& slice) const noexcept {
auto bounds_resolved = slice.resolve(derived().size());
assert(bounds_resolved.first <= bounds_resolved.second);
auto bounds_size = bounds_resolved.second - bounds_resolved.first;
return bit_array_ref<bit_value, const word_type>(&this->at(bounds_resolved.first), bounds_size);
}

/**
* @brief Slice operations - returns a bit_array_ref
*/
constexpr auto operator()(size_type offset, size_type right) noexcept {
constexpr auto operator()(const size_type offset, const size_type right) noexcept {
return bit_array_ref<bit_value, word_type>(&this->at(offset), right - offset);
}

template <std::integral U = int>
constexpr auto operator()(const bounds<U>& slice) noexcept {
auto bounds_resolved = slice.resolve(derived().size());
assert(bounds_resolved.first <= bounds_resolved.second);
auto bounds_size = bounds_resolved.second - bounds_resolved.first;
return bit_array_ref<bit_value, word_type>(&this->at(bounds_resolved.first), bounds_size);
}

// Common operations
constexpr void fill(value_type bit_val) noexcept {
std::fill(derived().begin(), derived().end(), bit_val);
Expand Down
149 changes: 149 additions & 0 deletions include/bitlib/bit-containers/bounds.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// ================================= BIT_SLICE =================================== //
// Project: The Experimental Bit Algorithms Library
// \file bit_array.hpp
// Description: Implementation of bit_array
// Creator: Vincent Reverdy
// Contributor: Peter McLean [2025]
// License: BSD 3-Clause License
// ========================================================================== //
#include <concepts>
#include <tuple>
#include <variant>

#ifndef _BIT_SLICE_HPP_INCLUDED
#define _BIT_SLICE_HPP_INCLUDED

namespace bit {

template <typename Derived, typename T, size_t N, typename W, typename It, typename CIt>
class bit_array_base;

template <std::signed_integral size_type = int>
class bounds {
template <typename Derived, typename T, size_t N, typename W, typename It, typename CIt>
friend class bit_array_base;

public:
using None_t = std::tuple<>;
static constexpr None_t None = None_t{};

private:
using var_t = std::variant<None_t, size_type>;
var_t begin;
var_t end;

public:
constexpr bounds() : begin(None), end(None) {
}
constexpr bounds(const bounds& other) = default;
constexpr bounds(const bounds&& other)
: begin(other.begin), end(other.end) {
}
constexpr bounds(const size_type pos)
: begin(pos), end(None) {
}
constexpr bounds(const size_type begin, const size_type end)

Check warning on line 45 in include/bitlib/bit-containers/bounds.hpp

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, linux, gcc, gcc, g++, libstdcxx, warnings, bitlib-tests, Debug)

declaration of ‘begin’ shadows a member of ‘bit::bounds<size_type>’ [-Wshadow]

Check warning on line 45 in include/bitlib/bit-containers/bounds.hpp

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, linux, gcc, gcc, g++, libstdcxx, warnings, bitlib-tests, Debug)

declaration of ‘end’ shadows a member of ‘bit::bounds<size_type>’ [-Wshadow]

Check warning on line 45 in include/bitlib/bit-containers/bounds.hpp

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, linux, gcc, gcc, g++, libstdcxx, warnings, bitlib-tests, Debug)

declaration of ‘begin’ shadows a member of ‘bit::bounds<size_type>’ [-Wshadow]

Check warning on line 45 in include/bitlib/bit-containers/bounds.hpp

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, linux, gcc, gcc, g++, libstdcxx, warnings, bitlib-tests, Debug)

declaration of ‘end’ shadows a member of ‘bit::bounds<size_type>’ [-Wshadow]

Check warning on line 45 in include/bitlib/bit-containers/bounds.hpp

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, linux, gcc, gcc, g++, libstdcxx, warnings, bitlib-tests, Debug)

declaration of ‘begin’ shadows a member of ‘bit::bounds<size_type>’ [-Wshadow]

Check warning on line 45 in include/bitlib/bit-containers/bounds.hpp

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, linux, gcc, gcc, g++, libstdcxx, warnings, bitlib-tests, Debug)

declaration of ‘end’ shadows a member of ‘bit::bounds<size_type>’ [-Wshadow]

Check warning on line 45 in include/bitlib/bit-containers/bounds.hpp

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, linux, gcc, gcc, g++, libstdcxx, warnings, bitlib-tests, Debug)

declaration of ‘begin’ shadows a member of ‘bit::bounds<size_type>’ [-Wshadow]

Check warning on line 45 in include/bitlib/bit-containers/bounds.hpp

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, linux, gcc, gcc, g++, libstdcxx, warnings, bitlib-tests, Debug)

declaration of ‘end’ shadows a member of ‘bit::bounds<size_type>’ [-Wshadow]

Check warning on line 45 in include/bitlib/bit-containers/bounds.hpp

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, linux, gcc, gcc, g++, libstdcxx, warnings, bitlib-tests, Debug)

declaration of ‘begin’ shadows a member of ‘bit::bounds<size_type>’ [-Wshadow]

Check warning on line 45 in include/bitlib/bit-containers/bounds.hpp

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, linux, gcc, gcc, g++, libstdcxx, warnings, bitlib-tests, Debug)

declaration of ‘end’ shadows a member of ‘bit::bounds<size_type>’ [-Wshadow]
: begin(begin), end(end) {
}
constexpr bounds(std::initializer_list<var_t> components) {
if (components.size() > 3) {
throw std::invalid_argument("Initializer list must have at most 2 elements");
}

Check warning on line 51 in include/bitlib/bit-containers/bounds.hpp

View check run for this annotation

Codecov / codecov/patch

include/bitlib/bit-containers/bounds.hpp#L50-L51

Added lines #L50 - L51 were not covered by tests
auto it = components.begin();
begin = None;
end = None;
if (components.size() >= 1) {
begin = *it;
}
if (components.size() >= 2) {
it++;
end = *it;
}
if (std::holds_alternative<size_type>(begin)) {
std::cout << "pos " << std::get<size_type>(begin) << ", ";
} else {
std::cout << "None, ";
}
if (std::holds_alternative<size_type>(end)) {
std::cout << "pos" << std::get<size_type>(end) << std::endl;
} else {
std::cout << "None" << std::endl;
}
}

constexpr bool operator==(const bounds& other) const = default;
constexpr auto operator<=>(const bounds& other) const = default;

constexpr bounds& operator+=(const size_t& _size) {
const size_type size = static_cast<size_type>(_size);
if (std::holds_alternative<size_type>(end)) {
size_type end_pos = std::get<size_type>(end);

Check warning on line 80 in include/bitlib/bit-containers/bounds.hpp

View check run for this annotation

Codecov / codecov/patch

include/bitlib/bit-containers/bounds.hpp#L80

Added line #L80 was not covered by tests
if (end_pos >= 0) {
end = end_pos + size;
} else {

Check warning on line 83 in include/bitlib/bit-containers/bounds.hpp

View check run for this annotation

Codecov / codecov/patch

include/bitlib/bit-containers/bounds.hpp#L82-L83

Added lines #L82 - L83 were not covered by tests
end = ((size_type(-1) - size) < end_pos) ? size_type(-1) : (end_pos + size);
}

Check warning on line 85 in include/bitlib/bit-containers/bounds.hpp

View check run for this annotation

Codecov / codecov/patch

include/bitlib/bit-containers/bounds.hpp#L85

Added line #L85 was not covered by tests
} else if (std::holds_alternative<size_type>(begin)) {
end = std::get<size_type>(begin) + size;
}
return *this;
}

constexpr bounds& operator-=(const size_t& _size) {
const size_type size = static_cast<size_type>(_size);
if (std::holds_alternative<size_type>(begin)) {
size_type begin_pos = std::get<size_type>(begin);
if (!std::holds_alternative<size_type>(end)) {
end = begin_pos + 1;
begin = begin_pos + 1 - size;
} else {
if (begin_pos < 0) {
begin = begin_pos - size;
} else {

Check warning on line 102 in include/bitlib/bit-containers/bounds.hpp

View check run for this annotation

Codecov / codecov/patch

include/bitlib/bit-containers/bounds.hpp#L101-L102

Added lines #L101 - L102 were not covered by tests
begin = ((size_type(0) + size) > begin_pos) ? size_type(0) : (begin_pos - size);
}
}

Check warning on line 105 in include/bitlib/bit-containers/bounds.hpp

View check run for this annotation

Codecov / codecov/patch

include/bitlib/bit-containers/bounds.hpp#L104-L105

Added lines #L104 - L105 were not covered by tests
}
return *this;
}

constexpr std::pair<size_type, size_type> resolve(size_t _length) const {
const size_type length = static_cast<size_type>(_length);
// Helper: translate a possibly-negative int into a signed index
auto translate_index = [&](size_type idx) -> size_type {
size_type x = (idx);
if (x < size_type(0)) {
x += length;
}

Check warning on line 117 in include/bitlib/bit-containers/bounds.hpp

View check run for this annotation

Codecov / codecov/patch

include/bitlib/bit-containers/bounds.hpp#L116-L117

Added lines #L116 - L117 were not covered by tests
return x;
};

// 1) Compute raw_start
size_type raw_start;
if (std::holds_alternative<None_t>(begin)) {
raw_start = size_type(0);
} else {
raw_start = translate_index(std::get<size_type>(begin));
}

// 2) Compute raw_end
size_type raw_end;
if (std::holds_alternative<None_t>(end)) {
raw_end = length;
} else {
raw_end = translate_index(std::get<size_type>(end));
}

// 3) Clamp into [0..L]
return {std::clamp(raw_start,
size_type(0),
length),
std::clamp(raw_end,
size_type(0),
length)};
}
};

} // namespace bit

#endif
22 changes: 22 additions & 0 deletions test/src/test-array.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,28 @@ TEST(BitArrayTest, Slice) {
EXPECT_EQ(arr, 0x20'DEADBEAF_b);
}

TEST(BitArrayTest, SliceWithClass) {
auto arr = 0x20'DEADBEEF_b;
auto span2 = arr(bit::bounds{4} += 4);
EXPECT_EQ(span2.size(), 4);
EXPECT_EQ(span2[0], (0xE & (1 << 0)) ? bit::bit1 : bit::bit0);
EXPECT_EQ(span2[1], (0xE & (1 << 1)) ? bit::bit1 : bit::bit0);
EXPECT_EQ(span2[2], (0xE & (1 << 2)) ? bit::bit1 : bit::bit0);
EXPECT_EQ(span2[3], (0xE & (1 << 3)) ? bit::bit1 : bit::bit0);
span2 = 0x4'A_b;
EXPECT_EQ(arr, 0x20'DEADBEAF_b);
auto span3 = arr({4, 8});
EXPECT_EQ(span3, span2);
auto span4 = arr(bit::bounds{7} -= 4);
EXPECT_EQ(span4, span2);
auto span5 = arr({4, {}});
auto span6 = arr(4, 32);
EXPECT_EQ(span5, span6);
bit::bounds bounds(0, 5);
bit::bounds bounds2{{}, 5};
EXPECT_EQ(bounds.resolve(32), bounds2.resolve(32));
}

TEST(BitArrayTest, SliceModify) {
auto arr = 0x24'DEADBEEF_b;
auto span2 = arr(4, 8);
Expand Down
Loading