Search code examples
scalabit-shiftbitset

Scala BitSet and shift operations


I'm looking for a way to represent a set of integers with a bit vector (which would be the characteristic function of that set of integers) and be able to perform bitwise operations on this set.

Initially I thought scala's BitSet would be the ideal candidate. However, it seems BitSet doesn't support shifting operations according to the documentation 1. Upon further investigation I also found that the related Java BitSet implementation doesn't support shift operations either 2.

Am I left with the only option of implementing my own BitSet class which supports shift operations? Moreover, according to the description given in 3 it doesn't sound that difficult to support shift operations on the Scala's BitSet implementation, or have I misunderstood something here?

Thanks in advance.


Solution

  • The usual trick when faced with a need for retrofitting new functionality is the "Pimp My Library" pattern. Implicitly convert the BitSet to a dedicated type intended to perform the added operation:

    class ShiftableBitSet(bs: BitSet) {
      def shiftLeft(n: Int): BitSet = ... //impl goes here
    }
    
    implicit def bitsetIsShiftable(bs: BitSet) = new ShiftableBitSet(bs)
    
    val sample = BitSet(1,2,3,5,7,9)
    val shifted = sample.shiftLeft(2)
    

    Alter shiftLeft to whatever name and with whatever arguments you prefer.

    UPDATE

    If you know for certain that you'll have an immutable BitSet, then a (slightly hacky) approach to access the raw underlying array is to pattern match. Not too painful either, as there are only 3 possible concrete subclasses for an immutable BitSet:

    import collection.immutable.BitSet
    val bitSet = BitSet(1,2,3)
    bitSet match {
      case bs: BitSet.BitSet1 => Array(bs.elems)
      case bs: BitSet.BitSetN => bs.elems 
      case _ => error("unusable BitSet")
    }
    

    Annoyingly, the elems1 param to BitSet2 isn't a val, and the elems param to a mutable BitSet is marked protected. So it's not perfect, but should do the trick if your set is non-trivial and immutable. For the trivial cases, "normal" access to the set won't be too expensive.

    And yes, this technique would be used within the wrapper as described above.