Module: CShadow::CShadowClassMethods

Defined in:
lib/cgen/cshadow.rb

Instance Method Summary collapse

Instance Method Details

#_alloc_methodObject

Return the object for managing the alloc method of the class.



765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
# File 'lib/cgen/cshadow.rb', line 765

def _alloc_method
  ## same as new_method, but no initialize -- factor this
  ## can we use define_c_class_method?
  return nil unless persistent?
  unless defined?(@_alloc_method) and @_alloc_method
    sf = shadow_library_source_file
    ssn = shadow_struct_name
    mark_name = refer_to_function :mark
    free_name = refer_to_function :free
    @_alloc_method = sf.define_alloc_func(self)
    @_alloc_method.instance_eval {
      scope :extern
      arguments 'VALUE klass'
      return_type 'VALUE'
      klass_c_name = "klass"
      declare :object => "VALUE object"
      declare :shadow => "#{ssn} *shadow"
      body %{
        object = Data_Make_Struct(#{klass_c_name},
                   #{ssn},
                   #{mark_name},
                   #{free_name},
                   shadow);
        shadow->self = object;
      }
      returns "object"
    }
  end
  @_alloc_method
end

#_dump_data_methodObject

Return the object for managing the _dump_data method of the class. See ruby’s marshal.c.



730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
# File 'lib/cgen/cshadow.rb', line 730

def _dump_data_method
  return nil unless persistent?
  unless defined?(@_dump_data_method) and @_dump_data_method
    @_dump_data_method = define_c_method(:_dump_data, AttrMethod) {
      declare :result   => "VALUE result"
      setup   :result   => "result = rb_ary_new()"
      body pre_code!, attr_code!, post_code!
      returns "result"
    }
    if superclass.respond_to? :shadow_struct
      @_dump_data_method.attr_code superclass._dump_data_method.body!
    end
  end
  @_dump_data_method
end

#_load_data_methodObject

Return the object for managing the _load_data method of the class. See ruby’s marshal.c.



748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
# File 'lib/cgen/cshadow.rb', line 748

def _load_data_method
  return nil unless persistent?
  unless defined?(@_load_data_method) and @_load_data_method
    @_load_data_method = define_c_method(:_load_data, AttrMethod) {
      arguments :from_array
      declare :tmp  => "VALUE tmp"
      body pre_code!, attr_code!, post_code!
      returns "from_array"  ## needed?
    }
    if superclass.respond_to? :shadow_struct
      @_load_data_method.attr_code superclass._load_data_method.body!
    end
  end
  @_load_data_method
end

#after_commit(&block) ⇒ Object

Register block to be called after the #commit happens.



377
378
379
# File 'lib/cgen/cshadow.rb', line 377

def after_commit(&block)
  shadow_library.after_commit(&block)
end

#attr_accessor(*args) ⇒ Object



809
810
811
812
# File 'lib/cgen/cshadow.rb', line 809

def attr_accessor(*args)
  check_overwrite_shadow_attrs(*args)
  super
end

#attr_reader(*args) ⇒ Object



814
815
816
817
# File 'lib/cgen/cshadow.rb', line 814

def attr_reader(*args)
  check_overwrite_shadow_attrs(*args)
  super
end

#attr_writer(*args) ⇒ Object



819
820
821
822
# File 'lib/cgen/cshadow.rb', line 819

def attr_writer(*args)
  check_overwrite_shadow_attrs(*args)
  super
end

#base_classObject

Return the base class, which is the ancestor which first included CShadow.



335
336
337
# File 'lib/cgen/cshadow.rb', line 335

def base_class
  @base_class ||= superclass.base_class
end

#before_commit(&block) ⇒ Object

Register block to be called before the #commit happens.



372
373
374
# File 'lib/cgen/cshadow.rb', line 372

def before_commit(&block)
  shadow_library.before_commit(&block)
end

#c_function_templatesObject



580
# File 'lib/cgen/cshadow.rb', line 580

def c_function_templates; @c_function_templates ||= {}; end

#check_inherited_functionsObject

For each function referenced in this class, but not defined, resolve the reference by defining a macro to evaluate to the first implementation found by ascending the class tree.



681
682
683
684
685
686
687
688
689
690
691
692
# File 'lib/cgen/cshadow.rb', line 681

def check_inherited_functions
  syms = referenced_functions.keys.sort_by{|k|k.to_s}
  syms.reject {|sym| c_function_templates[sym]}.each do |sym|
    fname = "#{sym}_#{shadow_struct_name}"
    pf = find_super_function(sym)
    inherited_function[sym] = true
    pf_str = pf ? pf.name : (sym == :free ? -1 : 0)
      # -1 means free the struct; See README.EXT
    shadow_library_source_file.declare fname.intern =>
      "#define #{fname} #{pf_str}"
  end
end

#commitObject

Generate code and load the dynamically linked library. No further C attrs or methods can be defined after calling #commit.



362
363
364
# File 'lib/cgen/cshadow.rb', line 362

def commit
  shadow_library.commit
end

#committed?Boolean

Returns true if and only if the class haas been committed.

Returns:

  • (Boolean)


367
368
369
# File 'lib/cgen/cshadow.rb', line 367

def committed?
  shadow_library.committed?
end

#define_c_class_method(name, subclass = CGenerator::SingletonMethod, &block) ⇒ Object

Define a class method for this class.



528
529
530
531
532
533
534
535
# File 'lib/cgen/cshadow.rb', line 528

def define_c_class_method name,
      subclass = CGenerator::SingletonMethod, &block
  sf = shadow_library_source_file
  m = sf.define_c_singleton_method self, name, subclass
  m.scope :extern
  m.instance_eval(&block) if block
  m
end

#define_c_function(name, subclass = CGenerator::Function, &block) ⇒ Object

Define a function in the library of this class. By default, the function has extern scope. The name is just the function name (as a C function).



540
541
542
543
544
545
546
# File 'lib/cgen/cshadow.rb', line 540

def define_c_function name, subclass = CGenerator::Function, &block
  sf = shadow_library_source_file
  m = sf.define_c_function name, subclass
  m.scope :extern
  m.instance_eval(&block) if block
  m
end

#define_c_method(name, subclass = CGenerator::Method, &block) ⇒ Object

The block is evaluated in a context that allows commands for listing arguments, declarations, C body code, etc. See CGenerator for details. See examples in examples/matrix.rb and examples/complex.rb. The subclass argument is optional and allows the template to belong to a subclass of the function template it would normally belong to.

In the case of #define_c_method, a pointer to the object’s shadow struct is available in the C variable shadow.



516
517
518
519
520
521
522
523
524
525
# File 'lib/cgen/cshadow.rb', line 516

def define_c_method name, subclass = CGenerator::Method, &block
  sf = shadow_library_source_file
  m = sf.define_c_method self, name, subclass
  m.scope :extern
  m.declare :shadow => "#{shadow_struct_name} *shadow"
  m.setup :shadow =>
    "Data_Get_Struct(self, #{shadow_struct_name}, shadow)"
  m.instance_eval(&block) if block
  m
end

#define_inheritable_c_function(name, subclass = CGenerator::Function, &block) ⇒ Object

Define a function in the library of this class. By default, the function has extern scope. The name is typically a symbol (like :mark) which is used to generate a function name in combination with the shadow struct name.

If a class defines a function with name, and the child class does not do so (i.e. doesn’t instantiate the function template to add code), then the child can call the parent’s implementation using #refer_to_function (see #new_method for an example).



557
558
559
560
561
562
563
564
565
# File 'lib/cgen/cshadow.rb', line 557

def define_inheritable_c_function name,
      subclass = CGenerator::Function, &block
  sf = shadow_library_source_file
  m = sf.define_c_function "#{name}_#{shadow_struct_name}", subclass
  c_function_templates[name] = m
  m.scope :extern
  m.instance_eval(&block) if block
  m
end

#each_shadow_attr(&bl) ⇒ Object

Each class which includes the CShadow module has this method to iterate over its shadow attributes.

Note that the shadow attributes dynamically include inherited ones. (Dynamically in the sense that subsequent changes to superclasses are automatically reflected.) The order is from root to leaf of the inheritance chain, and within each class in order of definition. (TEST THIS)



389
390
391
392
393
394
395
# File 'lib/cgen/cshadow.rb', line 389

def each_shadow_attr(&bl)
  if superclass.respond_to? :each_shadow_attr
    superclass.each_shadow_attr(&bl)
  end
  @shadow_attrs ||= []
  @shadow_attrs.each(&bl)
end

#fill_in_defsObject

Internal methods ==#



569
570
571
572
573
574
575
576
577
578
# File 'lib/cgen/cshadow.rb', line 569

def fill_in_defs
  shadow_struct
  new_method; _alloc_method

  check_inherited_functions

  if self == base_class
    _dump_data_method; _load_data_method
  end
end

#find_super_function(sym) ⇒ Object

Note that {} nondeterministic, so these should only be used to check existence or get value, not to iterate.



584
585
586
587
588
# File 'lib/cgen/cshadow.rb', line 584

def find_super_function sym
  c_function_templates[sym] || (
    defined?(superclass.find_super_function) &&
      superclass.find_super_function(sym))
end

#free_functionObject

Return the object for managing the free function of the class.



712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
# File 'lib/cgen/cshadow.rb', line 712

def free_function
  unless defined?(@free_function) and @free_function
    raise if inherited_function[:free]
    sf = shadow_library_source_file
    ssn = shadow_struct_name
    @free_function = define_inheritable_c_function(:free, FreeFunction) do
      arguments "#{ssn} *shadow"
      return_type "void"
    end
    if superclass.respond_to? :shadow_struct
      @free_function.free superclass.free_function.free!
    end
  end
  @free_function
end

#inherited_functionObject



674
675
676
# File 'lib/cgen/cshadow.rb', line 674

def inherited_function
  @inherited_function ||= {}
end

#mark_functionObject

Return the object for managing the mark function of the class.



695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
# File 'lib/cgen/cshadow.rb', line 695

def mark_function
  unless defined?(@mark_function) and @mark_function
    raise if inherited_function[:mark]
    sf = shadow_library_source_file
    ssn = shadow_struct_name
    @mark_function = define_inheritable_c_function(:mark, MarkFunction) do
      arguments "#{ssn} *shadow"
      return_type "void"
    end
    if superclass.respond_to? :shadow_struct
      @mark_function.mark superclass.mark_function.mark!
    end
  end
  @mark_function
end

#newObject

:nodoc:



304
305
306
307
# File 'lib/cgen/cshadow.rb', line 304

def new # :nodoc:
  raise Library::CommitError,
    "Cannot create shadow objects before committing library"
end

#new_from_hash(h) ⇒ Object

Primarily for loading yaml data. The hash is of the form

{ 'attr' => value, ... }

where attr is either the name of a shadow attr, or the name (without @) of an attribute.

Warning: The hash h is modified.



317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
# File 'lib/cgen/cshadow.rb', line 317

def new_from_hash(h)
  obj = allocate

  psa = shadow_attrs.select {|attr| attr.persists}
  shadow_vars = psa.map{|attr|attr.var.to_s}
  from_array = h.values_at(*shadow_vars)
  obj._load_data(from_array)
  shadow_vars.each {|v| h.delete(v) }

  h.each do |ivar, value|
    obj.instance_variable_set("@#{ivar}", value)
  end

  obj
end

#new_methodObject

Return the object for managing the new method of the class.



624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
# File 'lib/cgen/cshadow.rb', line 624

def new_method
  unless defined?(@new_method) and @new_method
    sf = shadow_library_source_file
    ssn = shadow_struct_name
    mark_name = refer_to_function :mark
    free_name = refer_to_function :free
    @new_method = sf.define_c_singleton_method self,
      :new, AttrClassMethod
    @new_method.instance_eval {
      scope :extern
      c_array_args
      declare :object => "VALUE object"
      declare :shadow => "#{ssn} *shadow"
      setup :shadow_struct => %{
        object = Data_Make_Struct(self,
                   #{ssn},
                   #{mark_name},
                   #{free_name},
                   shadow);
        shadow->self = object;
      }
      body attr_code!
      body %{
        rb_obj_call_init(object, argc, argv);
      }
      returns "object"
    }
    if superclass.respond_to? :shadow_struct
      @new_method.attr_code superclass.new_method.attr_code!
    end
  end
  @new_method
end

#persistent?Boolean

Returns:

  • (Boolean)


351
352
353
354
355
356
357
358
# File 'lib/cgen/cshadow.rb', line 351

def persistent?
  bc = @base_class
  if self == bc
    @persistent
  else
    bc.persistent?
  end
end

#refer_to_function(sym) ⇒ Object

Generate a string which, by convention, names the function for instances of this particular class. Also, keeps track of referenced_functions.



669
670
671
672
# File 'lib/cgen/cshadow.rb', line 669

def refer_to_function sym
  referenced_functions[sym] = true
  "#{sym}_#{shadow_struct_name}"
end

#referenced_functionsObject

Set of function names (symbols) that have been referenced in the implementation of this class. The names are like :free or :mark, rather than :free_in_class_C, to give a common identity to all free functions.



662
663
664
# File 'lib/cgen/cshadow.rb', line 662

def referenced_functions
  @referenced_functions ||= {}
end

#shadow_attrsObject

Returns a proxy Enumerable object referring to the same attributes as #each_shadow_attr. For example:

sub_class.shadow_attrs.collect { |attr| attr.var }

returns an array of variable names for all attributes of the class.



403
404
405
406
407
408
409
410
411
# File 'lib/cgen/cshadow.rb', line 403

def shadow_attrs
  proxy = Object.new.extend Enumerable
  shadow_class = self
  proxy.instance_eval {@target = shadow_class}
  def proxy.each(&bl)
    @target.each_shadow_attr(&bl)
  end
  proxy
end

#shadow_library(lib = nil) ⇒ Object

If lib provided and this class doesn’t have a library yet, set the library to lib..

If lib not proivided, and the class has a library, return it.

If lib not proivided, and the class doesn’t have a library, construct a library with a reasonable name, and return it. The name is based on the full path of this class.



422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
# File 'lib/cgen/cshadow.rb', line 422

def shadow_library lib = nil
  bc = base_class
  if self == bc
    if defined?(@shadow_library) and @shadow_library
      if lib
        raise RuntimeError,
              "Class #{name} is already associated" +
              " with library #{@shadow_library.name}."
      end
    else
      case lib
      when Library
        @shadow_library = lib
      when Class
        begin
          @shadow_library = lib.shadow_library
        rescue NameError
          raise ScriptError, "#{lib} does not include CShadow."
        end
      when String
        @shadow_library = Library.new(lib)
      when nil
        n = name.dup
        n.gsub!(/_/, '__')
        n.gsub!(/::/, '_') # almost reversible
        @shadow_library = Library.new(n)
      else
        raise ArgumentError,
              "#{lib} is not a CShadow::Library, String, or Class. " +
              "Its class is #{lib.class}"
      end
    end
    @shadow_library
  else
    bc.shadow_library lib
  end
end

#shadow_library_file(file = nil) ⇒ Object

Set or return the shadow library file.



461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
# File 'lib/cgen/cshadow.rb', line 461

def shadow_library_file file = nil
  if defined? @shadow_library_file
    if file
      raise RuntimeError,
            "Cannot assign class #{self} to file #{file.inspect}; class" +
            " is already associated" +
            " with file #{@shadow_library_file[0].name}."
    end
    @shadow_library_file
  elsif file
    case file
    when CGenerator::CFile
      file_name = file.name
    when String
      file_name = file
    else
      raise ArgumentError, "#{file} is not a String or CFile."
    end
    file_name = file_name.sub(/\.[ch]$/, "")
    @shadow_library_file = shadow_library.add_file file_name
  else
    if superclass.respond_to? :shadow_library_file
      superclass.shadow_library_file
    else
      [shadow_library.include_file, shadow_library.source_file]
    end
  end
end

#shadow_library_include_fileObject

Return the main C include file for the library.



491
492
493
# File 'lib/cgen/cshadow.rb', line 491

def shadow_library_include_file
  shadow_library_file[0]
end

#shadow_library_source_fileObject

Return the main C source file for the library.



496
497
498
# File 'lib/cgen/cshadow.rb', line 496

def shadow_library_source_file
  shadow_library_file[1]
end

#shadow_structObject

Return the object for managing the shadow struct.



598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
# File 'lib/cgen/cshadow.rb', line 598

def shadow_struct
  unless defined?(@shadow_struct) and @shadow_struct
    raise if @inherited_shadow_struct
    sf = shadow_library_source_file
    ssn = shadow_struct_name
    @shadow_struct = sf.declare_extern_struct(ssn)
    if self == base_class
      @shadow_struct.declare :self => "VALUE self"
    else
      sss = superclass.shadow_struct
      shadow_struct.inherit\
        sss.inherit!,
        "/* #{superclass.shadow_struct_name} members */",
        sss.declare!, " "

      unless superclass.shadow_library_source_file ==
             shadow_library_source_file
        shadow_library_include_file.include(
          superclass.shadow_library_include_file)
      end
    end
  end
  @shadow_struct
end

#shadow_struct_nameObject

Construct the name used for the shadow struct. Attempts to preserve the full class path.



592
593
594
595
# File 'lib/cgen/cshadow.rb', line 592

def shadow_struct_name
  @shadow_struct_name ||=
    name.gsub(/_/, '__').gsub(/::/, '_o_') + CShadow::SHADOW_SUFFIX
end