Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add set/reset/flip functions to change sequences #27

Merged
merged 4 commits into from
Oct 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 37 additions & 0 deletions dynamic_bitset.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
Copyright (c) 2003-2004, 2008 Gennaro Prota
Copyright (c) 2014 Ahmed Charles
Copyright (c) 2014 Riccardo Marcangelo
Copyright (c) 2018 Evgeny Shulgin

Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
Expand Down Expand Up @@ -197,10 +198,13 @@ <h3><a id ="synopsis">Synopsis</a></h3>
dynamic_bitset <a href="#op-sl">operator&lt;&lt;</a>(size_type n) const;
dynamic_bitset <a href="#op-sr">operator&gt;&gt;</a>(size_type n) const;

dynamic_bitset&amp; <a href="#set3">set</a>(size_type n, size_type len, bool val = true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has led to ambiguity. See rdkit/rdkit#2128. We need to resolve this. I will open an issue.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be resolved by Nov 7 or it will be reverted for the Boost 1.69.0 beta.

dynamic_bitset&amp; <a href="#set2">set</a>(size_type n, bool val = true);
dynamic_bitset&amp; <a href="#set1">set</a>();
dynamic_bitset&amp; <a href="#reset3">reset</a>(size_type n, size_type len);
dynamic_bitset&amp; <a href="#reset2">reset</a>(size_type n);
dynamic_bitset&amp; <a href="#reset1">reset</a>();
dynamic_bitset&amp; <a href="#flip3">flip</a>(size_type n, size_type len);
dynamic_bitset&amp; <a href="#flip2">flip</a>(size_type n);
dynamic_bitset&amp; <a href="#flip1">flip</a>();
bool <a href="#test">test</a>(size_type n) const;
Expand Down Expand Up @@ -1062,6 +1066,18 @@ <h3><a id="member-functions">Member Functions</a></h3>
<b>Returns:</b> <tt>*this</tt><br />
<b>Throws:</b> nothing.

<hr />
<pre>
dynamic_bitset&amp; <a id=
"set3">set</a>(size_type n, size_type len, bool val = true);
</pre>

<b>Precondition:</b> <tt>n + len &lt; this-&gt;size()</tt>.<br />
<b>Effects:</b> Sets every bit indexed from <tt>n</tt> to
<tt>n + len - 1</tt> inclusively if <tt>val</tt> is <tt>true</tt>, and
clears them if <tt>val</tt> is <tt>false</tt>. <br />
<b>Returns:</b> <tt>*this</tt>

<hr />
<pre>
dynamic_bitset&amp; <a id=
Expand All @@ -1074,6 +1090,17 @@ <h3><a id="member-functions">Member Functions</a></h3>
<tt>false</tt>. <br />
<b>Returns:</b> <tt>*this</tt>

<hr />
<pre>
dynamic_bitset&amp; <a id=
"reset3">reset</a>(size_type n, size_type len);
</pre>

<b>Precondition:</b> <tt>n + len &lt; this-&gt;size()</tt>.<br />
<b>Effects:</b> Clears every bit indexed from <tt>n</tt> to
<tt>n + len - 1</tt> inclusively.<br />
<b>Returns:</b> <tt>*this</tt>

<hr />
<pre>
dynamic_bitset&amp; <a id="reset2">reset</a>(size_type n)
Expand All @@ -1083,6 +1110,16 @@ <h3><a id="member-functions">Member Functions</a></h3>
<b>Effects:</b> Clears bit <tt>n</tt>.<br />
<b>Returns:</b> <tt>*this</tt>

<hr />
<pre>
dynamic_bitset&amp; <a id="flip3">flip</a>(size_type n, size_type len)
</pre>

<b>Precondition:</b> <tt>n + len &lt; this-&gt;size()</tt>.<br />
<b>Effects:</b> Flips every bit indexed from <tt>n</tt> to
<tt>n + len - 1</tt> inclusively.<br />
<b>Returns:</b> <tt>*this</tt>

<hr />
<pre>
dynamic_bitset&amp; <a id="flip2">flip</a>(size_type n)
Expand Down
134 changes: 134 additions & 0 deletions include/boost/dynamic_bitset/dynamic_bitset.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
// Copyright (c) 2014 Glen Joseph Fernandes
// glenfe at live dot com
// Copyright (c) 2014 Riccardo Marcangelo
// Copyright (c) 2018 Evgeny Shulgin
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
Expand Down Expand Up @@ -279,10 +280,13 @@ class dynamic_bitset
dynamic_bitset operator>>(size_type n) const;

// basic bit operations
dynamic_bitset& set(size_type n, size_type len, bool val = true);
dynamic_bitset& set(size_type n, bool val = true);
dynamic_bitset& set();
dynamic_bitset& reset(size_type n, size_type len);
dynamic_bitset& reset(size_type n);
dynamic_bitset& reset();
dynamic_bitset& flip(size_type n, size_type len);
dynamic_bitset& flip(size_type n);
dynamic_bitset& flip();
bool test(size_type n) const;
Expand Down Expand Up @@ -360,6 +364,9 @@ class dynamic_bitset
private:
BOOST_STATIC_CONSTANT(block_width_type, ulong_width = std::numeric_limits<unsigned long>::digits);

dynamic_bitset& range_operation(size_type pos, size_type len,
Block (*partial_block_operation)(Block, size_type, size_type),
Block (*full_block_operation)(Block));
void m_zero_unused_bits();
bool m_check_invariants() const;

Expand All @@ -369,6 +376,51 @@ class dynamic_bitset
static size_type block_index(size_type pos) BOOST_NOEXCEPT { return pos / bits_per_block; }
static block_width_type bit_index(size_type pos) BOOST_NOEXCEPT { return static_cast<block_width_type>(pos % bits_per_block); }
static Block bit_mask(size_type pos) BOOST_NOEXCEPT { return Block(1) << bit_index(pos); }
static Block bit_mask(size_type first, size_type last) BOOST_NOEXCEPT
{
Block res = (last == bits_per_block - 1)
? static_cast<Block>(~0)
: ((Block(1) << (last + 1)) - 1);
res ^= (Block(1) << first) - 1;
return res;
}
static Block set_block_bits(Block block, size_type first,
size_type last, bool val) BOOST_NOEXCEPT
{
if (val)
return block | bit_mask(first, last);
else
return block & static_cast<Block>(~bit_mask(first, last));
}

// Functions for operations on ranges
inline static Block set_block_partial(Block block, size_type first,
size_type last) BOOST_NOEXCEPT
{
return set_block_bits(block, first, last, true);
}
inline static Block set_block_full(Block) BOOST_NOEXCEPT
{
return static_cast<Block>(~0);
}
inline static Block reset_block_partial(Block block, size_type first,
size_type last) BOOST_NOEXCEPT
{
return set_block_bits(block, first, last, false);
}
inline static Block reset_block_full(Block) BOOST_NOEXCEPT
{
return 0;
}
inline static Block flip_block_partial(Block block, size_type first,
size_type last) BOOST_NOEXCEPT
{
return block ^ bit_mask(first, last);
}
inline static Block flip_block_full(Block block) BOOST_NOEXCEPT
{
return ~block;
}

template <typename CharT, typename Traits, typename Alloc>
void init_from_string(const std::basic_string<CharT, Traits, Alloc>& s,
Expand Down Expand Up @@ -959,6 +1011,17 @@ dynamic_bitset<Block, Allocator>::operator>>(size_type n) const
//-----------------------------------------------------------------------------
// basic bit operations

template <typename Block, typename Allocator>
dynamic_bitset<Block, Allocator>&
dynamic_bitset<Block, Allocator>::set(size_type pos,
size_type len, bool val)
{
if (val)
return range_operation(pos, len, set_block_partial, set_block_full);
else
return range_operation(pos, len, reset_block_partial, reset_block_full);
}

template <typename Block, typename Allocator>
dynamic_bitset<Block, Allocator>&
dynamic_bitset<Block, Allocator>::set(size_type pos, bool val)
Expand All @@ -982,6 +1045,13 @@ dynamic_bitset<Block, Allocator>::set()
return *this;
}

template <typename Block, typename Allocator>
inline dynamic_bitset<Block, Allocator>&
dynamic_bitset<Block, Allocator>::reset(size_type pos, size_type len)
{
return range_operation(pos, len, reset_block_partial, reset_block_full);
}

template <typename Block, typename Allocator>
dynamic_bitset<Block, Allocator>&
dynamic_bitset<Block, Allocator>::reset(size_type pos)
Expand All @@ -1006,6 +1076,13 @@ dynamic_bitset<Block, Allocator>::reset()
return *this;
}

template <typename Block, typename Allocator>
dynamic_bitset<Block, Allocator>&
dynamic_bitset<Block, Allocator>::flip(size_type pos, size_type len)
{
return range_operation(pos, len, flip_block_partial, flip_block_full);
}

template <typename Block, typename Allocator>
dynamic_bitset<Block, Allocator>&
dynamic_bitset<Block, Allocator>::flip(size_type pos)
Expand Down Expand Up @@ -1925,6 +2002,63 @@ inline const Block& dynamic_bitset<Block, Allocator>::m_highest_block() const
return m_bits.back();
}

template <typename Block, typename Allocator>
dynamic_bitset<Block, Allocator>& dynamic_bitset<Block, Allocator>::range_operation(
size_type pos, size_type len,
Block (*partial_block_operation)(Block, size_type, size_type),
Block (*full_block_operation)(Block))
{
assert(pos + len <= m_num_bits);

// Do nothing in case of zero length
if (!len)
return *this;

// Use an additional asserts in order to detect size_type overflow
// For example: pos = 10, len = size_type_limit - 2, pos + len = 7
// In case of overflow, 'pos + len' is always smaller than 'len'
assert(pos + len >= len);

// Start and end blocks of the [pos; pos + len - 1] sequence
const size_type first_block = block_index(pos);
const size_type last_block = block_index(pos + len - 1);

const size_type first_bit_index = bit_index(pos);
const size_type last_bit_index = bit_index(pos + len - 1);

if (first_block == last_block) {
// Filling only a sub-block of a block
m_bits[first_block] = partial_block_operation(m_bits[first_block],
first_bit_index, last_bit_index);
} else {
// Check if the corner blocks won't be fully filled with 'val'
const size_type first_block_shift = bit_index(pos) ? 1 : 0;
const size_type last_block_shift = (bit_index(pos + len - 1)
== bits_per_block - 1) ? 0 : 1;

// Blocks that will be filled with ~0 or 0 at once
const size_type first_full_block = first_block + first_block_shift;
const size_type last_full_block = last_block - last_block_shift;

for (size_type i = first_full_block; i <= last_full_block; ++i) {
m_bits[i] = full_block_operation(m_bits[i]);
}

// Fill the first block from the 'first' bit index to the end
if (first_block_shift) {
m_bits[first_block] = partial_block_operation(m_bits[first_block],
first_bit_index, bits_per_block - 1);
}

// Fill the last block from the start to the 'last' bit index
if (last_block_shift) {
m_bits[last_block] = partial_block_operation(m_bits[last_block],
0, last_bit_index);
}
}

return *this;
}

// If size() is not a multiple of bits_per_block
// then not all the bits in the last block are used.
Expand Down
49 changes: 49 additions & 0 deletions test/bitset_test.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// Copyright (c) 2003-2006, 2008 Gennaro Prota
// Copyright (c) 2014 Ahmed Charles
// Copyright (c) 2014 Riccardo Marcangelo
// Copyright (c) 2018 Evgeny Shulgin
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
Expand Down Expand Up @@ -619,6 +620,22 @@ struct bitset_test {
}
}

static void set_segment(const Bitset& b, std::size_t pos,
std::size_t len, bool value)
{
Bitset lhs(b);
std::size_t N = lhs.size();
Bitset prev(lhs);
lhs.set(pos, len, value);
for (std::size_t I = 0; I < N; ++I)
{
if (I < pos || I >= pos + len)
BOOST_CHECK(lhs[I] == prev[I]);
else
BOOST_CHECK(lhs[I] == value);
}
}

static void reset_all(const Bitset& b)
{
Bitset lhs(b);
Expand Down Expand Up @@ -647,6 +664,22 @@ struct bitset_test {
}
}

static void reset_segment(const Bitset& b, std::size_t pos,
std::size_t len)
{
Bitset lhs(b);
std::size_t N = lhs.size();
Bitset prev(lhs);
lhs.reset(pos, len);
for (std::size_t I = 0; I < N; ++I)
{
if (I < pos || I >= pos + len)
BOOST_CHECK(lhs[I] == prev[I]);
else
BOOST_CHECK(!lhs[I]);
}
}

static void operator_flip(const Bitset& b)
{
Bitset lhs(b);
Expand Down Expand Up @@ -684,6 +717,22 @@ struct bitset_test {
}
}

static void flip_segment(const Bitset& b, std::size_t pos,
std::size_t len)
{
Bitset lhs(b);
std::size_t N = lhs.size();
Bitset prev(lhs);
lhs.flip(pos, len);
for (std::size_t I = 0; I < N; ++I)
{
if (I < pos || I >= pos + len)
BOOST_CHECK(lhs[I] == prev[I]);
else
BOOST_CHECK(lhs[I] != prev[I]);
}
}

// empty
static void empty(const Bitset& b)
{
Expand Down