Comment on this RCR (edit wiki page) | RCRchive home

RCR 222: Add bitwise AND/XOR/OR/NOT for String

submitted by David Garamond on Thu Feb 26 2004 01:38:26 AM -0800

Status: pending


Abstract

Add String#^, #!, #&, and #~ for fast bitwise operations on byte strings.

Problem

Unlike in Perl, there is currently no fast way in Ruby to do bitwise operations on byte strings. The bitwise-op methods #^, #!, #&, and #~ works only on numbers and not string.

Proposal

Implement String#^, #!, #&, and #~ in C.

Analysis

I think this is a low-impact change and mainly affect performance, because Ruby's String is a raw/byte string (not Unicode, etc). C implementation should be simple and straightforward. A couple of additional issues to consider though: 1) we can allow strings of different length to be XOR/AND/OR-ed. If the second string is shorter than the first, then we can just reuse/rollover to the beginning of the second string; 2) Ara T. Howard in ruby-talk suggested adding String#and!, #xor!, #not!, #or! too for in-place replacement.

Implementation

class String
  def ^(other)
    raise ArgumentError, "Can't bitwise-XOR a String with a non-String" \
      unless other.kind_of? String
    raise ArgumentError, "Can't bitwise-XOR strings of different length" \
      unless self.length == other.length
    result = (0..self.length-1).collect { |i| self[i] ^ other[i] }
    result.pack("C*")
  end

  def &(other)
    raise ArgumentError, "Can't bitwise-AND a String with a non-String" \
      unless other.kind_of? String
    raise ArgumentError, "Can't bitwise-AND strings of different length" \
      unless self.length == other.length
    result = (0..self.length-1).collect { |i| self[i] & other[i] }
    result.pack("C*")
  end

  def |(other)
    raise ArgumentError, "Can't bitwise-OR a String with a non-String" \
      unless other.kind_of? String
    raise ArgumentError, "Can't bitwise-OR strings of different length" \
      unless self.length == other.length
    result = (0..self.length-1).collect { |i| self[i] | other[i] }
    result.pack("C*")
  end

  def ~
    result = (0..self.length-1).collect { |i| ~ self[i] }
    result.pack("C*")
  end
end

Vote for this RCR

Strongly opposed [1]
Opposed [7]
Neutral [2]
In favor [1]
Strongly advocate [1]

Change the status of this RCR to:

accepted

rejected

withdrawn


two points:

-- matz.


Maybe it would be possible to have some sort of BitVector class that has these operations as part of the standard library for Ruby2? I'm also thinking that we should have a ByteString class because some uses of Ruby Strings take advantage of the fact that they are simply binary arrays (such as storing FXRuby icons as resource strings). -- Austin Ziegler
Thanks for the comments, matz. Since Ruby2 will have separate String and ByteString class, I still think we should add a pretty complete set of methods for ByteString, including bitwise operations. I don't know exactly how often we will use bitwise, but I think there will be uses in file processing, cryptography, and image processing. -- davegaramond
There is a library that I'm looking at implementing in Ruby that this would help with immensely (magic file detection, similar to libmmagic). -- Austin Ziegler

Back to RCRchive.


RCR Submission page and RCRchive powered by Ruby, Apache, RuWiki (modified), and RubLog