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

[FEATURE] dynamic_bitset #1153

Merged
merged 19 commits into from
Aug 16, 2019
Merged

[FEATURE] dynamic_bitset #1153

merged 19 commits into from
Aug 16, 2019

Conversation

eseiler
Copy link
Member

@eseiler eseiler commented Jul 3, 2019

Immediate TODO:

  • resize needs to set bits to 0 if shrinking
  • Check side effects of above change
  • rough docs
  • refine docs
  • snippets
  • Take a guess which functions are not called, because codecov isn't marking them
  • increase coverage
  • replace ctor + resize with string ctor in tests
  • to_string() - with custom debug_stream overload if this does not work automatically when to_string() is defined. Standard range debug_stream'ing needs to be reversed.

Maybe TODO:

Lavish features such as:

  • std::string to_string(CharT zero = CharT('0'), CharT one = CharT('1')) const; which allows you to set specific characters for 0 and 1
  • unsigned long to_ulong() const and unsigned long long to_ullong() const, but these are one-liners
  • std::hash support

Note:

1️⃣ begin() points to the least significant bit, i.e. right to left instead left to right.
Example:

seqan3::dynamic_bitset t1{0b1100'0001};
t1[0]; // 1
t1[1]; // 0
...
t1[6]; // 1
t1[7]; // 1

for (auto it = t1.begin(); it != it.end(); ++it)
    *it; // 10000011

Future TODO:

  • extend for arbitrary size
  • For operator>> we have the line:
  if (is.eof())
      break;

I copied from the small_string implementation.
It's used correctly in this context (we check is.eof() after we read EOF), but we only read up to max(is.width(), arg.max_size()) many characters, which already ensures we never read EOF, so the branch is never reached. @smehringer

@eseiler eseiler added this to ⏳ In Progress in Module: Range via automation Jul 3, 2019
@marehr
Copy link
Member

marehr commented Jul 3, 2019

Just curious, why is 58 the upper limit?

@eseiler
Copy link
Member Author

eseiler commented Jul 3, 2019

Just curious, why is 58 the upper limit?

We use the most significant 6 bit of the uint64_t to encode the size.

@marehr
Copy link
Member

marehr commented Jul 3, 2019

A normal bitset can also be greater than 64bit, this one can't. I imagine you don't need this for your use case.

@codecov
Copy link

codecov bot commented Jul 3, 2019

Codecov Report

Merging #1153 into master will increase coverage by 0.1%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff            @@
##           master    #1153     +/-   ##
=========================================
+ Coverage   96.72%   96.83%   +0.1%     
=========================================
  Files         210      211      +1     
  Lines        8003     8280    +277     
=========================================
+ Hits         7741     8018    +277     
  Misses        262      262
Impacted Files Coverage Δ
include/seqan3/range/container/dynamic_bitset.hpp 100% <100%> (ø)
...de/seqan3/argument_parser/detail/version_check.hpp 92.74% <0%> (+0.11%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1527991...7dd31a7. Read the comment docs.

@eseiler
Copy link
Member Author

eseiler commented Jul 3, 2019

A normal bitset can also be greater than 64bit, this one can't. I imagine you don't need this for your implementation.

For now this is enough, main application will be the shapes, where 32 is fine.
But future plan is to then extend it for > 64

@eseiler eseiler force-pushed the feature/constexpr_bitset branch 4 times, most recently from 5a21b56 to 3b7cd9b Compare July 5, 2019 15:17
@eseiler eseiler requested a review from marehr July 5, 2019 15:34
Copy link
Member

@marehr marehr left a comment

Choose a reason for hiding this comment

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

A general design question:

If you want to encode the size and value into one integer, I think it would be better to use bitfields, because the compiler will do all the hard work for you and it is a standard feature!

https://godbolt.org/z/aNcMKl

include/seqan3/range/container/dynamic_bitset.hpp Outdated Show resolved Hide resolved
include/seqan3/range/container/dynamic_bitset.hpp Outdated Show resolved Hide resolved
include/seqan3/range/container/dynamic_bitset.hpp Outdated Show resolved Hide resolved
@eseiler eseiler requested a review from marehr July 9, 2019 16:39
@eseiler eseiler force-pushed the feature/constexpr_bitset branch 6 times, most recently from ddd9dec to 048f99e Compare July 11, 2019 13:20
Copy link
Member Author

@eseiler eseiler left a comment

Choose a reason for hiding this comment

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

Change for next push after review

test/snippet/range/container/dynamic_bitset_subscript.cpp Outdated Show resolved Hide resolved
test/snippet/range/container/dynamic_bitset_begin.cpp Outdated Show resolved Hide resolved
Copy link
Member

@marehr marehr left a comment

Choose a reason for hiding this comment

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

lgtm 👍

include/seqan3/range/container/dynamic_bitset.hpp Outdated Show resolved Hide resolved
include/seqan3/range/container/dynamic_bitset.hpp Outdated Show resolved Hide resolved
include/seqan3/range/container/dynamic_bitset.hpp Outdated Show resolved Hide resolved
include/seqan3/range/container/dynamic_bitset.hpp Outdated Show resolved Hide resolved
include/seqan3/range/container/dynamic_bitset.hpp Outdated Show resolved Hide resolved
include/seqan3/range/container/dynamic_bitset.hpp Outdated Show resolved Hide resolved
@eseiler eseiler requested a review from marehr July 15, 2019 21:14
@eseiler
Copy link
Member Author

eseiler commented Jul 18, 2019

@marehr ping

Copy link
Member

@marehr marehr left a comment

Choose a reason for hiding this comment

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

lgtm

@eseiler eseiler requested a review from rrahn July 18, 2019 16:00
* ### Thread safety
*
* This container provides no thread-safety beyond the promise given also by the STL that all
* calls to `const` member function are safe from multiple threads (as long as no thread calls
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* calls to `const` member function are safe from multiple threads (as long as no thread calls
* calls to `const` member functions are safe from multiple threads (as long as no thread calls

{
return !static_cast<bool>(internal.bits & mask);
}

Copy link
Contributor

Choose a reason for hiding this comment

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

double newline


//!\cond
// this signals to range-v3 that something is a container :|
using allocator_type = void;
Copy link
Contributor

Choose a reason for hiding this comment

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

As far as I can tell, the container concept of the ranges library does not check for a type allocator_type. Can you give me an example where the expected behavior does not work without this type?


/*!\brief Construct from a different range.
* \tparam other_range_t The type of range to be inserted; must satisfy std::ranges::InputRange and `value_type`
* must be constructible from reference_t<other_range_t>.
Copy link
Contributor

Choose a reason for hiding this comment

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

still open

/*!\brief Construct from a different range.
* \tparam other_range_t The type of range to be inserted; must satisfy std::ranges::InputRange and `value_type`
* must be constructible from reference_t<other_range_t>.
* \param[in] range The sequence to construct/assign from.
Copy link
Contributor

Choose a reason for hiding this comment

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

I mean, leave it as is right now but for the future please do not align different doxygen entities. That looks just awful.


/*!\brief Assign from pair of iterators.
* \tparam begin_it_type Must satisfy std::ForwardIterator and the `value_type` must be constructible from
* the reference type of begin_it_type.
Copy link
Contributor

Choose a reason for hiding this comment

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

can you please check all comments again, i.e. that code expressions are wrapped in a code-block. So that it is consistent through the documentation

*
* \details
*
* Calling pop_back() on an empty container is undefined. In debug mode an assertion will be thrown.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* Calling pop_back() on an empty container is undefined. In debug mode an assertion will be thrown.
* Calling `pop_back()` on an empty container is undefined. In debug mode an assertion will be thrown.

}

//!\overload
constexpr void swap(dynamic_bitset && rhs) noexcept
Copy link
Contributor

Choose a reason for hiding this comment

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

what are you saving? The constructor and the assignment are defaulted anyway. Non one us using the swap internally. the copy-n-swap idiom is not necessary here. Hence, std::swap would work already for this class and should be the preferred way.
Mhmm but I see know, that it is the stupid container requirement. I'll make this a discussion point in the next dev meeting

*
* ### Thread-safety
*
* Not thread-safe.
Copy link
Contributor

Choose a reason for hiding this comment

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

no you don't need to mark them not-thread safe as it is clear by the top level documentation. In general if there is no explicit statement you always assume not thread-safe

@eseiler eseiler requested a review from rrahn August 14, 2019 12:35
@eseiler
Copy link
Member Author

eseiler commented Aug 14, 2019

@rrahn all the doc issues should be resolved now

@rrahn rrahn merged commit 6f2d188 into seqan:master Aug 16, 2019
Module: Range automation moved this from ⏳ In Progress to 🍻 Done Aug 16, 2019
@eseiler eseiler deleted the feature/constexpr_bitset branch August 16, 2019 09:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Module: Range
  
🍻 Done
Development

Successfully merging this pull request may close these issues.

None yet

4 participants