-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Implement bitwise operators #6534
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
Conversation
|
Pretty cool. It might help if the PR had some ReQL bitwise query tests to go with it. See: https://github.com/rethinkdb/rethinkdb/tree/next/test/rql_test/src/math_logic |
|
@bchavez Thank you for the feedback. Yes, I saw the tests in that directory, but I cannot run the tests for some reason. I have no idea what I was doing wrong, and this is what I've been stuck (logs from a Docker container, but also occurs on my host machine): |
|
@lyubomyr-shaydariv You're under no obligation to write tests, I'd be happy to add the tests for you in order to get this merged. I'll try and look into the test failure. |
|
@srh It would be fantastic! Thank you! (I do believe I just run the tests in a wrong way, and, if necessary, I'll provide the Docker files I've tried to build (succeeds) and test (fails) with.) |
|
OK, here's some feedback about bit shifting. I think I'm going to make some changes before merging this so I want to get your opinion.
I think maybe we should make the behavior like this:
I'll note, if we ever add the datatype for unbounded integers ("bignums"), this produces the identical value to what bignum shift behavior looks like. This means we don't have multiple distinct notions of bitshifting floating around. Until we add fixed width integers.
Having the range be 2^53<=..<2^53 is kind of weird-looking -- it lets
|
I was thinking of logical operations as operations that are consistent to their arithmetic counterparts with slightly different semantics doing exactly the same what JavaScript/node.js do. I don’t have any solid opinion here (+ neither for big numbers nor for binaries), but I think that having both arithmetic and logic bitwise operations may have sense for systems where numbers already have a specific integer range (at least from what I understood in your comment). Sorry it’s really hard to tell much about it, because I was just trying to add a simple bitwise operations scenario to get rid of
|
…long` and `unsigned long`
|
It should throw an error (because C++ exceptions are used to implement errors in the ReQL interpreter). I'm implementing it right now. |
|
@srh I've made some edits at the bitwise-review branch, but I'm really confused on how bitshift operations must really work. I don't believe I made it right (especially At that branch const P = 9007199254740992;
const N = -P;
r.range(55)
.map(e => ({
'#': e,
'?<<': r.branch(e.le(53), r(1).bitSal(e), 'undefined'),
'N>>': r(N).bitShr(e),
'N>>>': r(N).bitSar(e),
'P>>': r(P).bitShr(e),
'P>>>': r(P).bitSar(e),
}))produces
Could you please review? If you could make the necessary fixes at the |
|
Your use of DBL_MANT_DIG+1 is correct if you want it to be possible to shift 2^53 to zero. Negative numbers will stop at -1. Your code looks very good, especially for somebody that doesn't write C++. The problem that you're encountering is with bitShr -- it's converting to uint64_t (by adding 2^64) and then doing a right shift. This can make sense for 32-bit shifting (if we're copying Javascript) or 64-bit shifting (if we've only got a 64-bit signed integer type, like Java does) but it's pretty weird when the bound on integer range is 2^53. Before your last update, I had already made a branch to improve performance and also to change the semantic behavior of the functions (to what I think they should be). You can see them in my branch here: https://github.com/srh/rethinkdb/commits/sam/bitwise I'll go over them now. Some of this is obvious but I want to overexplain the changes because you say you're not used to C++. The first commit avoids smart quotes in the docs, to be consistent with the rest of the docs, which also avoid smart quotes. (Maybe the docs should use smart quotes consistently instead.) The second commit address the and/or/not/xor operators. The parameters are now restricted to the range 2^53<=..<2^53. The type of The third commit changes the API so that bit_sal and bit_sar are the only functions, and they only take two parameters. I think this is better than making the functions variadic, because using a different number of parameters would be a very rare use case. In the C++ implementation, you can see that this time I didn't use lambdas, because the functions are pretty big. Also, I used nullptr (new in C++11) instead of 0. Personally I would have used NULL before, but that's just me. The third commit also changes the behavior of shifting to that I described before. My fourth commit is just idiotic. In my sleep-deprived stupor I looked at your most recent changes, noticed bit_not_term_t, and thought, "I didn't change this to check the range properly!" And somehow I managed to make that change to bit_not_term_t without noticing it already had bit_arith_ranged_int in there. The fifth commit just adds a static assertion. Edit: It still needs tests. And I might get rid of the function pointer and just use if-then (because the CPU usually runs that faster). |
|
I added tests, and squashed/merged onto next as of 1601118. Thank you! There is still room for debate in terms of the question, what should the user API be. A name other than "sal" and "sar" might be appropriate for the shifting operations. Some people would like binary objects to be supported for the and/or/xor/not operations. I didn't update the ReQL version, but that shouldn't be necessary because these are brand new commands. But... that should be investigated. Made issue #6550 to make a note of that. |
|
@srh Wow, thank you! I didn't have much time the last days to complete everything to meet your detailed review comments, but I really appreciate how you took over all the necessary fixes and made it as it has to be keeping a sharp eye on my mistakes, typos and even tests I was not able to run. This is absolutely fantastic! It was a great time to bring a new microcontribuion to a great tool RethinkDB is and learn new stuff. Thank you very and very much! |
Description
RethinkDB does not support bitwise operations that may be very important and useful in some cases. Despite bitwise operations cannot be implemented easily using the existing RethinkDB expression terms/operators, RethinkDB suggests a workaround of using
r.js()where bitwise operations can be expressed with. For example:The
r.js()approach is not recommended by the official documentation due to performance costs and losing RethinkDB expressiveness. As an alternate approach, the basic bitwise operations can be implemented as built-in first class terms/operators.The suggested bitwise operations are:
Since the
r.and(),r.or(), andr.not()terms are already occupied, the operations above are suggested to have the bit prefix in order to avoid name clashing:bitAndbitOrbitXorbitNotbitSal/bitShlbitSarbitShrThe shift operation names (
bitSal/bitShl,bitSar, andbitShr) borrow the naming mnemonics from the x86 Assembly languge (SAL/SHL,SAR, andSHR).All the operations, except
r.bitNot(), are variadic and can accept any number of arguments and implement both prefix (r.bitOP(a, b, ...)) and infix (a.bitOP(b, ...)ora.bitOP(b).bitOP(...)) forms.Updated example from the above now becomes:
As the result, the query now looks simpler and is cheaper to execute.
RethinkDB protocol update
The protocol now maps the above operations to their respective Protocol Buffers term types:
BIT_AND=191BIT_OR=192BIT_XOR=193BIT_NOT=194BIT_SAL(virtuallyBIT_SHL) =195BIT_SAR=196BIT_SHR=197Drivers
Java driver
The Java driver is not included to the main build script for some reason, therefore its source code should be generated and built then separately. No implementation details.
JavaScript driver
The easiest driver to test since it can be tested directly in the Data Explorer. No implementation details.
Python driver
This driver, like the Ruby driver, uses snake case for the bitwise operations:
bit_andbit_orbit_xorbit_notbit_sal/bit_shlbit_sarbit_shrDespite Python supports operator overloading, the bitwise operations are not bound to Python operators since some of them are already occupied by the logical operation terms counterparts (
r.and()-&,r.or()-|, andr.not()-~).Ruby driver
The easiest driver to implement. The Ruby driver uses snake case similarly to the Python driver. However, the Ruby driver does not implement
r.bit_shl(), an equivalent tor.bit_sal(). due to the specifics of the driver implementation (similarly, the Ruby driver implementsr.to_json_string()but does not implement ther.to_json()overload as the other drivers do). The shift operators remain unchanged since the rest of operators might already have their operators overloaded for logical operation purposes.External issues: