File: bitop_command.rb

package info (click to toggle)
ruby-fakeredis 0.8.0-7
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 628 kB
  • sloc: ruby: 4,868; makefile: 2
file content (56 lines) | stat: -rw-r--r-- 1,331 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
module FakeRedis
  module BitopCommand
    BIT_OPERATORS = {
      'or'  => :|,
      'and' => :&,
      'xor' => :'^',
      'not' => :~,
    }

    def bitop(operation, destkey, *keys)
      if result = apply(operator(operation), keys)
        set(destkey, result)
        result.length
      else
        0
      end
    rescue ArgumentError => _
      raise_argument_error('bitop')
    end

    private

    def operator(operation)
      BIT_OPERATORS[operation.to_s.downcase]
    end

    def apply(operator, keys)
      case operator
      when :~
        raise ArgumentError if keys.count != 1
        bitwise_not(keys.first)
      when :&, :|, :'^'
        raise ArgumentError if keys.empty?
        bitwise_operation(operator, keys)
      else
        raise ArgumentError
      end
    end

    def bitwise_not(key)
      if value = get(keys.first)
        value.bytes.map { |byte| ~ byte }.pack('c*')
      end
    end

    def bitwise_operation(operation, keys)
      apply_onto, *values = keys.map { |key| get(key) }.reject(&:nil?)
      values.reduce(apply_onto) do |memo, value|
        shorter, longer = [memo, value].sort_by(&:length).map(&:bytes).map(&:to_a)
        longer.each_with_index.map do |byte, index|
          byte.send(operation, shorter[index] || 0)
        end.pack('c*')
      end
    end
  end
end