/
shared_array.rb
68 lines (55 loc) · 1.82 KB
/
shared_array.rb
1
2
3
4
5
6
7
8
9
10
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
module ProcessShared
class SharedArray < SharedMemory
include Enumerable
# A fixed-size array in shared memory. Processes forked from this
# one will be able to read and write shared data to the array.
# Access should be synchronized using a {Mutex}, {Semaphore}, or
# other means.
#
# Note that {Enumerable} methods such as {#map}, {#sort},
# etc. return new {Array} objects rather than modifying the shared
# array.
#
# @param [Symbol] type_or_count the data type as a symbol
# understood by FFI (e.g. :int, :double)
#
# @param [Integer] count number of array elements
def initialize(type_or_count = 1, count = 1)
super(type_or_count, count)
# See https://github.com/ffi/ffi/issues/118
ffi_type = FFI.find_type(self.type)
name, _ = FFI::TypeDefs.find do |(name, t)|
t == ffi_type
end
unless name
raise ArgumentError, "could not find FFI::Type for #{self.type}"
end
getter = "get_#{name}"
setter = "put_#{name}"
# singleton class
sclass = class << self; self; end
unless sclass.method_defined?(getter)
raise ArgumentError, "no element getter for #{self.type} (#{getter})"
end
unless sclass.method_defined?(setter)
raise ArgumentError, "no element setter for #{self.type} (#{setter})"
end
sclass.send(:alias_method, :get_type, getter)
sclass.send(:alias_method, :put_type, setter)
end
def each
# NOTE: using @count because Enumerable defines its own count
# method...
@count.times { |i| yield self[i] }
end
def each_with_index
@count.times { |i| yield self[i], i }
end
def [](i)
get_type(i * self.type_size)
end
def []=(i, val)
put_type(i * self.type_size, val)
end
end
end