Class: GRX::Storage

Inherits:
Object
  • Object
show all
Defined in:
lib/grx/storage.rb

Overview

Storage — Buffer de memoria nativa

Cuando CAPI está cargado:

@ptr  → Fiddle::Pointer a un bloque de doubles alineado a 32 bytes
        reservado con grx_alloc() (malloc alineado en C).
        Los datos viven en el heap de C, NO en el GC de Ruby.

Cuando CAPI NO está cargado (fallback):

@data → Array de Ruby normal (lento pero siempre correcto).

La separación entre los dos modos es transparente para Tensor.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(array_plano) ⇒ Storage

Returns a new instance of Storage.



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
# File 'lib/grx/storage.rb', line 25

def initialize(array_plano)
  @size = array_plano.size

  if CAPI::LOADED
    # --- MODO RÁPIDO: memoria C alineada ---
    # grx_alloc devuelve un double* alineado a 32 bytes
    @ptr = CAPI.grx_alloc(@size)
    raise StorageError, "grx_alloc falló (OOM)" if @ptr.null?

    # Empaquetamos el Array de Ruby en el buffer C como doubles (little-endian)
    # Array#pack("d*") → String binaria de IEEE 754 doubles
    bytes = array_plano.pack("d*")
    @ptr[0, bytes.bytesize] = bytes

    # Registramos un finalizer para liberar la memoria C cuando el objeto
    # Ruby sea recolectado por el GC. Usamos ObjectSpace para evitar
    # que el closure capture self (lo que impediría la recolección).
    ptr_to_free = @ptr
    ObjectSpace.define_finalizer(self, self.class.make_finalizer(ptr_to_free))
  else
    # --- MODO FALLBACK: Array de Ruby ---
    @data = array_plano.map(&:to_f)
    @ptr  = nil
  end
end

Instance Attribute Details

#ptrObject (readonly)

ptr expuesto para que CAPI pueda leerlo directamente



23
24
25
# File 'lib/grx/storage.rb', line 23

def ptr
  @ptr
end

#sizeObject (readonly)

Returns the value of attribute size.



20
21
22
# File 'lib/grx/storage.rb', line 20

def size
  @size
end

Class Method Details

.make_finalizer(ptr) ⇒ Object



51
52
53
# File 'lib/grx/storage.rb', line 51

def self.make_finalizer(ptr)
  proc { CAPI.grx_free(ptr) }
end

Instance Method Details

#read(indice) ⇒ Object


Lectura / escritura — usadas solo en modo fallback y por get() Las operaciones masivas (add, mul, etc.) van directo por @ptr en C.




59
60
61
62
63
64
65
66
# File 'lib/grx/storage.rb', line 59

def read(indice)
  if CAPI::LOADED
    # Leemos 8 bytes desde el offset correcto y los desempaquetamos como double
    @ptr[indice * 8, 8].unpack1("d")
  else
    @data[indice]
  end
end

#to_ruby_arrayObject

Vuelca todo el buffer a un Array de Ruby (para to_a, inspect, tests)



77
78
79
80
81
82
83
# File 'lib/grx/storage.rb', line 77

def to_ruby_array
  if CAPI::LOADED
    @ptr[0, @size * 8].unpack("d#{@size}")
  else
    @data.dup
  end
end

#write(indice, valor) ⇒ Object



68
69
70
71
72
73
74
# File 'lib/grx/storage.rb', line 68

def write(indice, valor)
  if CAPI::LOADED
    @ptr[indice * 8, 8] = [valor.to_f].pack("d")
  else
    @data[indice] = valor.to_f
  end
end