镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Buffer - feature request: Buffer.compare with offsets. #521

Description

@rootslab

I'm really impressed with the new iojs features, an awesome work!
Buffer.compare is a great iojs addition ( memcmp is very fast!), but, unfortunately, the current method implementation doesn't offer a way to compare 2 portions of Buffers: you are forced to slice one or both Buffers to compare desired portions of data.

Now, Buffer.compare accepts 2 buffers as arguments, instead, it could accept 4 args (+1 optional), or something like that:

function ( Buffer b1, Number start1, Buffer b2, Number start2 [, Number length ] ) {}
/*
 * For example, comparing 10 bytes:
 *  - b1 from index 0 to 9 
 *  - b2 from index 16 to 25
 */
Buffer.compare( b1, 0, b2, 16, 10 )
// or, to mantain current signature:
Buffer.compare( b1, b2, 0, 16, 10 )

@trevnorris It would be great if it was planned to add this functionality, it simplify things a lot!!

Activity

  1. feross commented on Jan 20, 2015

    @feross
    Contributor

    What about just slicing the buffers before comparing? Slicing will
    reference memory in the parent buffer so there's no copy. How much overhead
    would this actually save?
    On Mon, Jan 19, 2015 at 7:45 PM gu notifications@github.com wrote:

    I'm really impressed with the new iojs features, an awesome work!
    Buffer.compare is another great iojs addition ( memcmp is very
    fast!), but, unfortunately, the current method implementation doesn't offer
    a way to compare 2 portions of Buffers: you are forced to slice one or both
    Buffers to compare desired portions of data.

    Now, Buffer.compare accepts 2 buffers as arguments, instead, it could
    accept 4 args (+1 optional), or something like that:

    function ( Buffer b1, Number start1, Buffer b2, Number start2 [, Number length ] ) {}/* * For example, comparing 10 bytes: * - b1 from index 0 to 9 * - b2 from index 16 to 25 */
    Buffer.compare( b1, 0, b2, 16, 10 )

    @trevnorris https://github.com/trevnorris It would be great if it was
    planned to add this functionality, it speeds up things a lot!!

    —
    Reply to this email directly or view it on GitHub
    #521.

  2. rootslab commented on Jan 20, 2015

    @rootslab
    ContributorAuthor

    Hi @feross,
    "What about just slicing the buffers before comparing? "
    I obviously know that :) ".. you are forced to slice one or both Buffers to compare desired portions of data.
    For example, If you compare a fixed pattern against a data stream, you have to repeatedly slice, the same chunk of incoming data, to the current start offset, instead of simple incrementing an index and executing memcmp / Buffer.compare on a portion of it (anyway, native memcmp gets 3 arguments, 2 pointers and a number for specifying length).

  3. rootslab commented on Jan 20, 2015

    @rootslab
    ContributorAuthor

    P.S
    @feross, It is also possible to use Buffer.copy without indexes if you slice input buffers to desired offsets :)), but we prefer to use direct offset indexes; for an analogue reason, I think, we could get a Buffer.compare method with offset indexes.
    Probably, as you says, it doesn't saves a lot in terms of average execution time, I don't know that, I really mean "simplify things". Thanks for your interest.

  4. jorangreef commented on Jan 20, 2015

    @jorangreef
    Contributor

    Whenever I compare buffers, it's also almost always using an offset and common length argument, exactly as @rootslab suggested, for example compare(buffer1, offset1, buffer2, offset2, comparisonLength), so this would really fit my typical use case. Slicing to compare within a binary search (usually where I need to compare) would make no sense.

  5. self-assigned this
    on Jan 20, 2015
  6. trevnorris commented on Jan 20, 2015

    @trevnorris
    Contributor

    I'm cool with the idea. Though having that many overloads would become a pain to check. How about we start with the simple case:

    Buffer#compare(buf[, offset[, length]])
    

    We can work on the syntax for Buffer.compare() afterwards.

  7. trevnorris commented on Jan 20, 2015

    @trevnorris
    Contributor

    Oh, and it's not an iojs addition. The feature is also in v0.11. :-)

  8. rvagg commented on Jan 20, 2015

    @rvagg
    Member

    https://github.com/bnoordhuis/node-buffertools is my go-to for this kind of thing but I'm a big +1 on putting the most useful stuff in core because having to compile an addon just to do simple things often makes me resort to this kind of thing which I'm sure would make @trevnorris scream: buf1.toString('hex') == buf2.toString('hex').

  9. rootslab commented on Jan 20, 2015

    @rootslab
    ContributorAuthor

    @jorangreef, then, I'm not alone ;))

    @trevnorris ops.. I didn't see it in v0.11! ;)
    Unfortunately (or fortunately?) my c++/v8 skills are very poor , but I have written some js code for checking index ranges before calling native compare. It's very "tight code", I know, but it works and it could be easy modified or probably used as a simple reference.

    @rvagg thanks for suggestion, I know buffertools by @bnoordhuis, however, let me scream together with @trevnorris about toString('hex') ;)) it also converts every byte of raw data to 2 bytes (ASCII) chars, before comparing.

    Thanks to all! ;)

  10. rootslab commented on Jan 20, 2015

    @rootslab
    ContributorAuthor

    @trevnorris @rvagg, I hope it is useful for something :)

    compare : function ( buf1, buf2, bpos1, bpos2, bytes ) {
    
        if ( ! ( buf1 instanceof Buffer &&
                 buf2 instanceof Buffer ) )
            throw new TypeError( 'Arguments must be Buffers' );
    
        var abs = Math.abs
            , min = Math.min
            , blen1 = b1.length
            , blen2 = b2.length
            // normalize arg values
            , s1 = bpos1 >>> 0 ? abs( + bpos1 ) : 0
            , s2 = bpos2 >>> 0 ? abs( + bpos2 ) : 0
            , len = bytes >>> 0 ? abs( + bytes ) : min( blen1 - s1, blen2 - s2 )
            ;
    
        if ( ! blen1 || ! blen2 )
            throw new Error( '..0 length buffer..' );
    
        if ( ( len <= 0 ) ||
             ( s1 + len > blen1 ) ||
             ( s2 + len > blen2 ) )
            throw new RangeError( 'out of range index' );
      /*
        * Indexes range:
        *
        * - buf1 -> slice(s1, s1 + len)
        * - buf2 -> slice(s2, s2 + len)
        *
        * call native compare, with safe indexes:
        */
        return internal.compare( buf1, buf2, s1, s2, len );
    }
  11. Trott commented on Feb 26, 2016

    @Trott
    Member

    @trevnorris et al.: Assuming this is still a desirable feature, how would the arguments for Buffer#compare(buf[, offset[, length]]) work? Specifically, would offset and length apply to both buffers or just to buf?

  12. 5 remaining items

  13. trevnorris commented on Mar 23, 2016

    @trevnorris
    Contributor

    I can't see a technical reason why this API isn't a valid proposition. We already support similar with Buffer#copy() to also allow bypassing .slice() because the operation is expensive enough to hinder the hot path.

  14. jasnell commented on Mar 23, 2016

    @jasnell
    Member

    Ok. That works for me then.
    On Mar 22, 2016 11:18 PM, "Trevor Norris" notifications@github.com wrote:

    I can't see a technical reason why this API isn't a valid proposition. We
    already support similar with Buffer#copy() to also allow bypassing
    .slice() because the operation is expensive enough to hinder the hot path.

    —
    You are receiving this because you commented.
    Reply to this email directly or view it on GitHub
    #521 (comment)

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

Metadata

Metadata

Assignees

Labels

bufferIssues and PRs related to the buffer subsystem.feature requestIssues requesting new Node.js features.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions