Class: NDAV

Inherits:
Object
  • Object
show all
Includes:
MemoryViewable
Defined in:
lib/ndav.rb,
lib/ndav/ffi.rb,
lib/ndav/flags.rb,
lib/ndav/converter.rb,
lib/ndav/memory_viewable.rb,
ext/ndav.c

Overview

TODO: Manage flags of internal data object

Defined Under Namespace

Modules: Converter, FFI, Flags, MemoryViewable

Constant Summary collapse

ITEM_SIZES =
TODO: Want to use return value of rb_memory_view_parse_item_format
["c", "C", "s", "S", "l", "L", "q", "Q", "f", "d", "s!", "S!", "n", "v", "i", "i!", "I", "I!", "l!", "L!", "N", "V", "e", "g", "q!", "Q!", "E", "G"].collect {|format|
  [format, [0].pack(format).bytesize]
}.to_h

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from MemoryViewable

included

Constructor Details

#initialize(obj, shape: nil, strides: nil, format: nil, lifetime: nil) ⇒ NDAV

TODO: More options to trick for the case of MemoryView export is wrong but developer don't fix it

Raises:

  • (ArgumentError)


63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/ndav.rb', line 63

def initialize(obj, shape: nil, strides: nil, format: nil, lifetime: nil)
  fmv = obj.kind_of?(::Fiddle::MemoryView) ? obj : ::Fiddle::MemoryView.new(obj)
  # Fiddle::MemoryView#to_s is zero-copy
  # Fiddle::MemoryView#to_s embeds obj into the String, so we can prevent GC from collecting it
  @to_s = fmv.to_s
  @lifetime = lifetime

  @format = format || fmv.format
  raise ArgumentError, %Q|unsupported format: #{@format.to_s.dump}, currently supported: #{ITEM_SIZES.keys}| unless ITEM_SIZES.key?(@format)

  item_size_by_format = ITEM_SIZES[@format]

  @byte_size = fmv.byte_size
  @item_size = obj.kind_of?(::Fiddle::Pointer) ? item_size_by_format : fmv.item_size || item_size_by_format
  @shape = shape || fmv.shape
  case [@shape, @byte_size]
  in [nil, nil]
    raise ArgumentError, "either shape or byte_size must be present in obj or arguments"
  in [_, nil]
    @byte_size = @shape.reduce(@item_size, :*)
  in [nil, _]
    n, r = @byte_size.divmod(@item_size)
    raise ArgumentError, "byte_size must be n-times of item_size" unless r.zero?
    @shape = [n]
  else
    # noop
  end
  @ndim = @shape.size
  @readonly = fmv.readonly?
  @strides = strides || fmv.strides || self.class.default_strides(shape: @shape, item_size: @item_size)
  @sub_offsets = fmv.sub_offsets
  @row_major_contiguous = self.class.row_major_contiguous?(format: @format, shape: @shape, strides: @strides)
  @column_major_contiguous = self.class.column_major_contiguous?(format: @format, shape: @shape, strides: @strides)

  validate fmv
end

Instance Attribute Details

#byte_sizeObject (readonly)

Returns the value of attribute byte_size.


16
17
18
# File 'lib/ndav.rb', line 16

def byte_size
  @byte_size
end

#formatObject (readonly)

Returns the value of attribute format.


16
17
18
# File 'lib/ndav.rb', line 16

def format
  @format
end

#item_sizeObject (readonly)

Returns the value of attribute item_size.


16
17
18
# File 'lib/ndav.rb', line 16

def item_size
  @item_size
end

#lifetimeObject (readonly)

Returns the value of attribute lifetime.


16
17
18
# File 'lib/ndav.rb', line 16

def lifetime
  @lifetime
end

#ndimObject (readonly)

Returns the value of attribute ndim.


16
17
18
# File 'lib/ndav.rb', line 16

def ndim
  @ndim
end

#shapeObject (readonly)

Returns the value of attribute shape.


16
17
18
# File 'lib/ndav.rb', line 16

def shape
  @shape
end

#stridesObject (readonly)

Returns the value of attribute strides.


16
17
18
# File 'lib/ndav.rb', line 16

def strides
  @strides
end

#to_sObject (readonly)

Returns the value of attribute to_s.


16
17
18
# File 'lib/ndav.rb', line 16

def to_s
  @to_s
end

Class Method Details

.column_major_contiguous?(format:, shape:, strides:) ⇒ Boolean

Algorithm stolen from memory_view.c

Returns:

  • (Boolean)


47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/ndav.rb', line 47

def column_major_contiguous?(format:, shape:, strides:, **)
  ndim = shape.length
  n = ITEM_SIZES[format]
  return strides[0] == n if ndim == 1

  0.upto(ndim - 1) do |i|
    return false unless strides[i] == n

    n *= shape[i]
  end

  true
end

.default_strides(shape:, item_size:, row_major: true) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
# File 'lib/ndav.rb', line 19

def default_strides(shape:, item_size:, row_major: true)
  each_shape = row_major ? shape.reverse_each : shape.each
  each_shape.reduce([[], item_size]) {|(strides, stride), s|
    if row_major
      strides.unshift stride
    else
      strides << stride
    end
    [strides, stride * s]
  }[0]
end

.from_string(str) ⇒ Object



7
8
9
# File 'lib/ndav/converter.rb', line 7

def from_string(str, *, **)
  new(Fiddle::Pointer[str], *, **)
end

.register(cls, mdl, name:) ⇒ Object



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

def register(cls, mdl, name:)
  if mdl.const_defined?(:FromNDAV)
    cls.extend mdl::FromNDAV

    define_method "to_#{name}" do |*args, **kwargs|
      cls.from_ndav(self, *args, **kwargs)
    end
  end

  if mdl.const_defined?(:MemoryViewable)
    cls.include ::NDAV::MemoryViewable
    cls.include mdl::MemoryViewable

    unless mdl.const_defined?(:ToNDAV)
      mdl.const_set(:ToNDAV, Module.new {
        def to_ndav(lifetime: self, **)
          ::NDAV.new(self, lifetime:, **)
        end
      })
    end
  end

  if mdl.const_defined?(:ToNDAV)
    cls.include mdl::ToNDAV

    define_singleton_method "from_#{name}" do |array, *args, **kwargs|
      array.to_ndav(*args, **kwargs)
    end
  end

  if mdl.const_defined?(:Converter)
    Converter.prepend mdl::Converter
    Converter.singleton_class.prepend mdl::Converter
  end
end

.row_major_contiguous?(format:, shape:, strides:) ⇒ Boolean

Algorithm stolen from memory_view.c

Returns:

  • (Boolean)


32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/ndav.rb', line 32

def row_major_contiguous?(format:, shape:, strides:, **)
  ndim = shape.length
  n = ITEM_SIZES[format]
  return strides[0] == n if ndim == 1

  (ndim - 1).downto 0 do |i|
    return false unless strides[i] == n

    n *= shape[i]
  end

  true
end

Instance Method Details

#column_major_contiguous?Boolean

Returns:

  • (Boolean)


108
109
110
# File 'lib/ndav.rb', line 108

def column_major_contiguous?
  @column_major_contiguous
end

#readonly?Boolean

Returns:

  • (Boolean)


100
101
102
# File 'lib/ndav.rb', line 100

def readonly?
  @readonly
end

#row_major_contiguous?Boolean

Returns:

  • (Boolean)


104
105
106
# File 'lib/ndav.rb', line 104

def row_major_contiguous?
  @row_major_contiguous
end

#to_ptrObject Also known as: to_fiddle_pointer



112
113
114
# File 'lib/ndav.rb', line 112

def to_ptr
  ::Fiddle::Pointer[@to_s]
end