Class: Meangirls::ORSet

Inherits:
Set show all
Defined in:
lib/meangirls/or_set.rb

Defined Under Namespace

Classes: Pair

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Set

#&, #+, #-, #===, #each, #empty?, #size, #to_a, #|

Methods inherited from CRDT

merge, #to_json

Constructor Details

#initialize(hash = nil) ⇒ ORSet

Returns a new instance of ORSet.



23
24
25
26
27
28
29
30
31
32
33
# File 'lib/meangirls/or_set.rb', line 23

def initialize(hash = nil)
  @e = {}

  if hash
    raise ArgumentError, 'hash must contain e' unless hash['e']
    hash['e'].each do |list|
      element, adds, removes = list
      merge_internal! element, Pair.new(adds, removes)
    end 
  end
end

Instance Attribute Details

#eObject

Returns the value of attribute e.



22
23
24
# File 'lib/meangirls/or_set.rb', line 22

def e
  @e
end

Class Method Details

.biasesObject



18
19
20
# File 'lib/meangirls/or_set.rb', line 18

def self.biases
  ['a']
end

Instance Method Details

#<<(e) ⇒ Object

Inserts e into the set.



36
37
38
# File 'lib/meangirls/or_set.rb', line 36

def <<(e)
  add e
end

#==(other) ⇒ Object

Strict equality: all adds/removes match for every element. TODO: slow



42
43
44
45
46
47
48
49
# File 'lib/meangirls/or_set.rb', line 42

def ==(other)
  other.kind_of? self.class and
  (@e.keys | other.e.keys).all? do |e, pair|
    a = @e[e] and b = other.e[e] and
    uaeq(a.adds, b.adds) and
    uaeq(a.removes, b.removes)
  end
end

#add(e, tag = Meangirls.tag) ⇒ Object

Inserts e into the set. Tag will be randomly generated if not given.



52
53
54
55
56
# File 'lib/meangirls/or_set.rb', line 52

def add(e, tag = Meangirls.tag)
  pair = (@e[e] ||= Pair.new)
  pair.adds |= [tag]
  self
end

#as_jsonObject



58
59
60
61
62
63
64
65
# File 'lib/meangirls/or_set.rb', line 58

def as_json
  {
    'type' => type,
    'e' => @e.map do |e, pair|
      [e, pair.adds, pair.removes]
    end
  }
end

#biasObject



67
68
69
# File 'lib/meangirls/or_set.rb', line 67

def bias
  'a'
end

#cloneObject

UGH defensive copying



72
73
74
75
76
77
78
79
# File 'lib/meangirls/or_set.rb', line 72

def clone
  c = super
  c.e = {}
  @e.each do |e, pair|
    c.merge_internal! e, pair.clone
  end
  c
end

#delete(e, tag = nil) ⇒ Object

Deletes e from self by cancelling all known tags (or a specific tag if given.) Returns nil if no changes, e otherwise.



83
84
85
86
87
88
89
# File 'lib/meangirls/or_set.rb', line 83

def delete(e, tag = nil)
  pair = @e[e] or return
  new = pair.adds - pair.removes
  return if new.empty?
  pair.removes += new
  e
end

#merge(other) ⇒ Object

Merge with another OR-Set and return the merged copy.



92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/meangirls/or_set.rb', line 92

def merge(other)
  unless other.kind_of? self.class
    raise ArgumentError, "other must be a #{self.class}"
  end

  copy = clone
  @e.each do |e, pair|
    copy.merge_internal! e, pair
  end
  other.e.each do |e, pair|
    copy.merge_internal! e, pair
  end
  copy
end

#merge_internal!(element, pair) ⇒ Object

Updates self with new adds and removes for an element.



108
109
110
111
112
113
114
115
# File 'lib/meangirls/or_set.rb', line 108

def merge_internal!(element, pair)
  if my = @e[element]
    my.adds |= pair.adds
    my.removes |= pair.removes
  else
    @e[element] = pair
  end
end

#to_setObject



117
118
119
120
121
122
123
# File 'lib/meangirls/or_set.rb', line 117

def to_set
  s = Set.new
  @e.each do |element, pair|
    s << element unless (pair.adds - pair.removes).empty?
  end
  s
end

#typeObject



125
126
127
# File 'lib/meangirls/or_set.rb', line 125

def type
  'or-set'
end

#uaeq(a, b) ⇒ Object

Unordered array equality TODO: slow



131
132
133
# File 'lib/meangirls/or_set.rb', line 131

def uaeq(a, b)
  (a - b).empty? and (b - a).empty?
end