Class: Bud::PushApplyMethod

Inherits:
LatticePushElement show all
Defined in:
lib/bud/lattice-core.rb

Overview

A push-based dataflow element that applies a method to a lattice value

Constant Summary collapse

SOURCE_TYPES =
[Bud::LatticeWrapper, Bud::BudCollection,
Bud::LatticePushElement, Bud::PushElement]

Instance Attribute Summary

Attributes inherited from LatticePushElement

#invalidated, #outputs, #rescan, #wired_by

Instance Method Summary collapse

Methods inherited from LatticePushElement

#add_rescan_invalidate, #check_wiring, #flush, #invalidate_at_tick, #invalidate_cache, #method_missing, #print_wiring, #push_out, #rescan_at_tick, #stratum_end, #tick, #tick_deltas, #wire_to, #wirings

Constructor Details

#initialize(bud_instance, recv, meth, args, blk) ⇒ PushApplyMethod

Returns a new instance of PushApplyMethod.



282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
# File 'lib/bud/lattice-core.rb', line 282

def initialize(bud_instance, recv, meth, args, blk)
  super(bud_instance)
  @recv = recv
  @meth = meth
  @blk = blk
  @args = args.dup
  @is_morph = Bud::Lattice.global_morphs.include? @meth
  @recv_is_scanner = @recv.kind_of? Bud::LatticeScanner

  recv.wire_to(self, :output)
  bud_instance.push_elems[[self.object_id, recv, meth, blk]] = self

  # Arguments that are normal Ruby values are assumed to remain invariant as
  # rule evaluation progresses; hence, we just pass along those values when
  # invoking the function. Arguments that are derived from lattices or
  # collections might change; hence, we need to wire up the push dataflow to
  # have the current values of the function's arguments passed to this node.

  # Map from input node to a list of indexes; the indexes identify the
  # positions in the args array that should be filled with the node's value
  @input_sources = {}

  # Similarly, map from input node to a cached value -- this is the last value
  # we've seen from this input. If the input gave us a delta, we merge
  # together all the deltas we've seen and cache the resulting value.  XXX: In
  # the common case that the input is a scanner over a lattice wrapper, this
  # means we do redundant work merging together deltas.
  @input_caches = {}

  # Inputs for which we haven't seen a value yet.
  @waiting_for_input = Set.new
  @recv_cache = nil
  @seen_recv = false

  @args.each_with_index do |a, i|
    if SOURCE_TYPES.any?{|s| a.kind_of? s}
      if a.kind_of? Bud::LatticeWrapper
        a = a.to_push_elem
      end
      a.wire_to(self, :output)
      @input_sources[a] ||= []
      @input_sources[a] << i
      @waiting_for_input << a
      @args[i] = nil          # Substitute actual value before calling method
    end
  end

  @seen_all_inputs = @waiting_for_input.empty?
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Bud::LatticePushElement

Instance Method Details

#insert(v, source) ⇒ Object



332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
# File 'lib/bud/lattice-core.rb', line 332

def insert(v, source)
  if source == @recv
    if @seen_recv
      # Update the cached value for the method receiver. Note that if we're
      # applying a method directly to a LatticeScanner (i.e., method applied
      # to lattice wrapper), we can avoid maintaining a separate cache and
      # instead use the wrapper's current value.
      if @recv_is_scanner
        @recv_cache = @recv.collection.current_value
      else
        @recv_cache = @recv_cache.merge(v)
      end
    else
      @recv_cache = v
    end
    @seen_recv = true
    if @seen_all_inputs
      if @is_morph
        recv_val = v
      else
        recv_val = @recv_cache
      end
      res = recv_val.send(@meth, *@args, &@blk)
      push_out(res)
    end
  else
    arg_indexes = @input_sources[source]
    raise Bud::Error, "unknown input #{source}" if arg_indexes.nil?
    arg_val = v
    unless @is_morph
      if @input_caches[source]
        arg_val = @input_caches[source].merge(arg_val)
      end
    end
    arg_indexes.each do |i|
      @args[i] = arg_val
    end

    unless @seen_all_inputs
      @waiting_for_input.delete(source)
      @seen_all_inputs = @waiting_for_input.empty?
    end

    if @seen_all_inputs && @seen_recv
      res = @recv_cache.send(@meth, *@args, &@blk)
      push_out(res)
    end

    if @input_caches.has_key? source
      @input_caches[source] = @input_caches[source].merge(v)
    else
      @input_caches[source] = v
    end
    arg_indexes.each do |i|
      @args[i] = @input_caches[source]
    end
  end
end

#inspectObject



391
392
393
# File 'lib/bud/lattice-core.rb', line 391

def inspect
  "#{super} [#{@meth}]"
end