Editing Topic: RCR222 Project: RCR | 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


Back to RCRchive.


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