Module: Police::DataFlow::Labeling

Defined in:
lib/police/dataflow/labeling.rb

Overview

Label algebra.

Class Method Summary collapse

Class Method Details

.add_label_to_set(label, label_set) ⇒ Boolean

Adds a label to the set of labels held by an object’s proxy.

Parameters:

Returns:

  • (Boolean)

    false if the set already had a label of the same type, so the proxy holding the set can still be used; true if the set had to be expanded, so a new proxy is needed



70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/police/dataflow/labeling.rb', line 70

def self.add_label_to_set(label, label_set)
  label_class = label.class
  label_key = label_class.__id__
  if label_set.has_key? label_key
    label_set[label_key][label] = true
    return false
  end

  label_entry = { label => true }
  label_set[label_key] = label_entry
  true
end

.bulk_sticky_label(data, sticky_set) ⇒ BasicObject

Applies sticky labels to a piece of data.

This is an version of Police::DataFlow.label optimized for sticky label propagation. User code should not depend on it.

Parameters:

Returns:

  • (BasicObject)

    either the given piece of data, or a proxy that should be used instead of it



120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/police/dataflow/labeling.rb', line 120

def self.bulk_sticky_label(data, sticky_set)
  label_set = data.__police_labels__
  if nil == label_set
    # Unlabeled data.
    return Police::DataFlow::Proxying.proxy(data, dup_set(sticky_set))
  end

  # TODO(pwnall): implement copy-on-write to waste less memory on gated ops
  if merge_sets! label_set, sticky_set
    Police::DataFlow::Proxying.proxy data.__police_proxied__, label_set
  else
    data
  end
end

.dup_set(label_set) ⇒ Hash<Integer,Hash<Police::DataFlow::Label,Boolean>>

Creates a shallow copy of a label set.

The resulting copy is slightly deeper than what Hash#clone would produce, because the groups are copied as well.

Parameters:

Returns:

  • (Hash<Integer,Hash<Police::DataFlow::Label,Boolean>>)

    label_set a copy of the given label set that can be used with another object’s proxy



145
146
147
# File 'lib/police/dataflow/labeling.rb', line 145

def self.dup_set(label_set)
  Hash[label_set.map { |k, v| [k, v.dup] } ]
end

.merge_sets!(target_set, source_set) ⇒ Boolean

Merges a set of labels into another set.

Parameters:

  • target_set (Hash<Integer,Hash<Police::DataFlow::Label,Boolean>>)

    one of the label sets to be merged; this set will be modified by the method

  • source_set (Hash<Integer,Hash<Police::DataFlow::Label,Boolean>>)

    the other label set that will be merged; this set will not be modified

Returns:

  • (Boolean)

    false if the target set already had labels of all the types in the source set, so the proxy holding the target object can still be used; true if the target set had to be expanded, so a new proxy is needed



93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/police/dataflow/labeling.rb', line 93

def self.merge_sets!(target_set, source_set)
  expanded = false
  source_set.each do |class_id, label_classes|
    target_classes = target_set[class_id]
    if nil == target_classes
      target_set[class_id] = label_classes.dup
      expanded = true
    else
      target_classes.merge! label_classes
    end
  end
  expanded
end

.proxy_class(data) ⇒ Class

The actual class of a proxy object.

This is necessary because the class method for a proxy object must return the proxied object’s class.

This is intended to help testing the proxying code. It should not be used by client code.

Parameters:

  • data (BasicObject)

    a proxy returned by Police::DataFlow#label

Returns:

  • (Class)

    a subclass of ProxyBase, or nil if the given object is not a proxy



54
55
56
57
58
59
60
# File 'lib/police/dataflow/labeling.rb', line 54

def self.proxy_class(data)
  if data.__police_labels__.nil?
    nil
  else
    data.__police_class__
  end
end