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

Fix Issue 23304 - Add core.bitops.ReverseBitRange #14380

Closed
wants to merge 3 commits into from

Conversation

keivan-shah
Copy link

No description provided.

@dlang-bot
Copy link
Contributor

dlang-bot commented Aug 24, 2022

Thanks for your pull request and interest in making D better, @keivan-shah! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please verify that your PR follows this checklist:

  • My PR is fully covered with tests (you can see the coverage diff by visiting the details link of the codecov check)
  • My PR is as minimal as possible (smaller, focused PRs are easier to review than big ones)
  • I have provided a detailed rationale explaining my changes
  • New or modified functions have Ddoc comments (with Params: and Returns:)

Please see CONTRIBUTING.md for more information.


If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment.

Bugzilla references

Auto-close Bugzilla Severity Description
23304 enhancement Add core.bitops.ReverseBitRange

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub run digger -- build "master + dmd#14380"

@RazvanN7
Copy link
Contributor

Why do we need a different range for this? Can't we just upgrade BitRange to be a bidirectional range?

@keivan-shah
Copy link
Author

keivan-shah commented Aug 24, 2022

@RazvanN7 Yes even that is an option, would be a bit more difficult to implement so did not attempt. Will try to implement and update the PR. Thanks for the input!

@keivan-shah
Copy link
Author

I think this implements the bidirectional range on the BitArray and should be backwards compatible, but I am not sure about the code runtime. The empty() function now needs to do more checks and also it is storing double the amount of data of the previous BitArray.

@RazvanN7
Copy link
Contributor

RazvanN7 commented Aug 25, 2022

I think this implements the bidirectional range on the BitArray and should be backwards compatible, but I am not sure about the code runtime. The empty() function now needs to do more checks and also it is storing double the amount of data of the previous BitArray.

The size problem can indeed be solved by creating a ReverseBitRange that contains a BitRange field and the extra bidirectional range fields, implements all the bidirectional range primitives and forwards anything else to the BitRange field via alias this. Something along the lines of:

struct BitRangeReverse
{
    BitRange br;

    private { /*  extra fields go here  */}

    /* bidirectional range primitives go here */

    alias br this;
}

@RazvanN7
Copy link
Contributor

@atilaneves do you think adding a BitRangeReverse is worthwhile?

foreach (b; bitsToTest)
{
assert(!br.empty);
assert(b == br.front);
br.popFront();
}
assert(br.empty);
foreach_reverse (b; bitsToTest)
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be a separate unittest.

// reverse iterate
testSum = 0;
nBits = 0;
foreach_reverse (b; BitRange(bitArr, 100))
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be a separate unittest.

@atilaneves
Copy link
Contributor

What about an adapter that takes a BitRange and returns a BidirectionalBitRange?

@keivan-shah
Copy link
Author

So my usecase for the reverse BitRange was to have an optimized range over the bitset in reverse. Now I am not sure if the bidirectional range is the way to go for it since it has both space-time penalty over only a ReverseBitRange. I can check in the BitRangeReverse as @RazvanN7 suggested, but considering it is not optimized, might not be useful enough to be checked into the core library. What do you guys think is the best way to proceed here?

@atilaneves
Copy link
Contributor

So my usecase for the reverse BitRange was to have an optimized range over the bitset in reverse. Now I am not sure if the bidirectional range is the way to go for it since it has both space-time penalty over only a ReverseBitRange. I can check in the BitRangeReverse as @RazvanN7 suggested, but considering it is not optimized, might not be useful enough to be checked into the core library. What do you guys think is the best way to proceed here?

Right. It was the extra data members that got me to ask the question about an adapter.

@RazvanN7
Copy link
Contributor

RazvanN7 commented Aug 26, 2022

Technically, the druntime library usually contains things that the compiler specifically knows about, not necessarily user-facing common used functions. So I would argue that a ReverseBitRange should most likely be in the standard library (phobos), not in the runtime one. BitRange exists because it is used internally in druntime However, we already have BitArray. It does not provide range primitives but can easily be used to create a range of its reverse.

So I would argue that ReverseBitRange should not be included in druntime.

@keivan-shah
Copy link
Author

Makes sense. In that case should I just close this PR and mark the issue as resolved with a comment mentioning not added since would not be a good fit for the druntime?

@RazvanN7
Copy link
Contributor

Yes, I will take care of this. Thank you for your time and I hope you don't see this as a wasted effort.

@RazvanN7 RazvanN7 closed this Aug 26, 2022
@keivan-shah
Copy link
Author

No worries @RazvanN7, It was fun trying to contribute, Thanks for your efforts as well!

In case anyone comes across this PR looking for only the ReverseBitRange code, you can use the following snippet. And incase you need a bidirectional bitrange range, the code checked into this PR can be used, just note that the unidirectional ranges will perform better than the bidirectional range, so use those if possible.

struct ReverseBitRange
{
    /// Number of bits in each size_t
    enum bitsPerWord = size_t.sizeof * 8;

    private
    {
        const(size_t)*bits; // points at next word of bits to check
        size_t cur; // needed to allow searching bits using bsf
        size_t idx; // index of current set bit
        size_t len; // number of bits in the bit set.
    }
    @nogc nothrow pure:

    /**
     * Construct a BitRange.
     *
     * Params:
     *   bitarr = The array of bits to iterate over
     *   numBits = The total number of valid bits in the given bit array
     */
    this(const(size_t)* bitarr, size_t numBits) @system
    {
        bits = bitarr + (numBits - 1) / bitsPerWord;
        len = numBits;
        idx = numBits - 1;
        if (len)
        {
            // prime the first bit
            cur = *bits-- ^ (size_t(1) << idx);
            popFront();
        }
    }

    /// Range functions
    size_t front()
    {
        assert(!empty);
        return idx;
    }

    /// ditto
    bool empty() const
    {
        return idx < 0;
    }

    /// ditto
    void popFront() @system
    {
        // clear the current bit
        auto curbit = idx % bitsPerWord;
        cur ^= size_t(1) << curbit;
        if (!cur)
        {
            // find next size_t with set bit
            idx -= curbit;
            while (!cur)
            {
                if ((idx -= bitsPerWord) >= len) // WARN: Relying on size_t overflow!
                    // now empty
                    return;
                cur = *bits--;
            }
            idx += bsr(cur);
        }
        else
        {
            idx -= curbit - bsr(cur);
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants