Class: Safe::SafeArray

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/safestruct/safe_array.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(size = self.class.klass_size) ⇒ SafeArray

Returns a new instance of SafeArray.



61
62
63
64
65
# File 'lib/safestruct/safe_array.rb', line 61

def initialize( size=self.class.klass_size )
  @ary  = []
  self.size = size   if size > 0  ## auto-init with zeros
  self   # return reference to self
end

Class Method Details

.build_class(klass_value, size = 0) ⇒ Object

e.g.

Array.of( Address ), Array.of( Integer),
Array.of( Integer, 3 ) or Array.of( Integer, 3*3 ) etc.


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
# File 'lib/safestruct/safe_array.rb', line 11

def self.build_class( klass_value, size=0 )
  ## note: keep a class cache
  ##  note: klasses may have different init sizes (default 0)
  cache           = @@cache ||= {}
  cache_all_sizes = cache[ klass_value ] ||= {}
  klass           = cache_all_sizes[ size ]

  if klass.nil?

    klass = Class.new( SafeArray )
    klass.define_singleton_method( :klass_value ) do
      @klass_value ||= klass_value
    end
    klass.define_singleton_method( :klass_size ) do
      @klass_size  ||= size
    end

    ##### was: not working for anymous class e.g. klass_value.to_s => #<Class:>
#      klass.class_eval( <<RUBY )
#        def self.klass_value
#          @klass_value ||= #{klass_value}
#        end
#        def self.klass_size
#          @klass_size  ||= #{size}
#        end
# RUBY

    ## add to cache for later (re)use
    cache[ klass_value ][ size ] = klass

    ## note: also add a Constant to Safe for easy debugging and (re)use - will "auto"name class
    class_name = "Array"

    name = klass_value.name
    name = name.sub( /\bSafe::/, '' )   ## remove safe module from name if present
    name = name.gsub( '::', '' )        ## remove module separator if present
    class_name << "#{name}"
    class_name << "×#{size}"  if size > 0   ## add size if non-zero
    Safe.const_set( class_name, klass )
  end
  klass
end

.new_zeroObject



55
# File 'lib/safestruct/safe_array.rb', line 55

def self.new_zero()  new;  end

.zeroObject



56
# File 'lib/safestruct/safe_array.rb', line 56

def self.zero()      @zero ||= new_zero.freeze;  end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?



74
75
76
77
78
79
80
# File 'lib/safestruct/safe_array.rb', line 74

def ==( other )
  if other.is_a?( self.class )                       ## note: must be same array class
    @ary == other.instance_variable_get( '@ary' )    ## compare "wrapped" array
  else
    false
  end
end

#[](index) ⇒ Object



113
114
115
116
117
# File 'lib/safestruct/safe_array.rb', line 113

def [](index)
  ## note: throws / raises an IndexError exception
  #    if the referenced index lies outside of the array bounds
  @ary.fetch( index )
end

#[]=(index, value) ⇒ Object



104
105
106
107
108
109
110
111
# File 'lib/safestruct/safe_array.rb', line 104

def []=(index, value)
  ## note: use fetch
  #    throws / raises an IndexError exception
  #    if the referenced index lies outside of the array bounds
  # todo/fix: is there a better way to check for index out-of-bounds error?
  old_value = @ary.fetch( index )
  @ary[index] = value
end

#clearObject



128
129
130
131
132
133
134
# File 'lib/safestruct/safe_array.rb', line 128

def clear
  ## note: reset ary to zero  (NOT empty e.g. [])
  ##         differes for "fixed" size arrays
  @ary = []
  self.size = self.class.klass_size   if self.class.klass_size > 0  ## auto-init with zeros
  self  # return reference to self
end

#freezeObject



67
68
69
70
71
# File 'lib/safestruct/safe_array.rb', line 67

def freeze
  super
  @ary.freeze  ## note: pass on freeze to "wrapped" array
  self   # return reference to self
end

#push(item) ⇒ Object



119
120
121
122
123
124
125
126
# File 'lib/safestruct/safe_array.rb', line 119

def push( item )
  ## todo/fix: check if item.is_a? @type
  ##   note: Address might be a String too (Address | String)
  ##     store Address always as String!!! - why? why not?
  @ary.push( item )
  ## note: returns array.size (NOT array itself!!!) to keep compatible with solidity - why? why not?
  @ary.size
end

#size=(value) ⇒ Object Also known as: length=



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/safestruct/safe_array.rb', line 84

def size=(value)
  ## todo/check: value must be greater 0 and greater than current size
  diff = value - @ary.size

  ## todo/check:
  ##    always return (deep) frozen zero object - why? why not?
  ##     let user change the returned zero object - why? why not?
  if self.class.klass_value.respond_to?( :new_zero )
    ## note: use a new unfrozen copy of the zero object
    ##    changes to the object MUST be possible (new "empty" modifable object expected)
    diff.times { @ary << self.class.klass_value.new_zero }
  else  # assume value semantics e.g. Integer, Bool, etc. zero values gets replaced
    ## puts "use value semantics"
    diff.times { @ary << self.class.klass_value.zero }
  end
  self  # return reference to self
end

#zero?Boolean

Returns:

  • (Boolean)


58
# File 'lib/safestruct/safe_array.rb', line 58

def zero?()   self == self.class.zero; end