vigilem-support 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/vigilem/ffi.rb +19 -0
- data/lib/vigilem/ffi/array_pointer_sync.rb +382 -0
- data/lib/vigilem/ffi/struct.rb +54 -0
- data/lib/vigilem/ffi/utils.rb +240 -0
- data/lib/vigilem/ffi/utils/struct.rb +93 -0
- data/lib/vigilem/support.rb +31 -0
- data/lib/vigilem/support/core_ext.rb +13 -0
- data/lib/vigilem/support/core_ext/debug_puts.rb +5 -0
- data/lib/vigilem/support/core_ext/enumerable.rb +25 -0
- data/lib/vigilem/support/key_map.rb +323 -0
- data/lib/vigilem/support/key_map_info.rb +85 -0
- data/lib/vigilem/support/lazy_simple_delegator.rb +81 -0
- data/lib/vigilem/support/max_size_error.rb +17 -0
- data/lib/vigilem/support/metadata.rb +13 -0
- data/lib/vigilem/support/obj_space.rb +28 -0
- data/lib/vigilem/support/patch/cucumber/c_lexer.rb +30 -0
- data/lib/vigilem/support/patch/ffi/pointer.rb +19 -0
- data/lib/vigilem/support/size_error.rb +6 -0
- data/lib/vigilem/support/sys.rb +5 -0
- data/lib/vigilem/support/system.rb +92 -0
- data/lib/vigilem/support/transmutable_hash.rb +206 -0
- data/lib/vigilem/support/utils.rb +224 -0
- data/lib/vigilem/support/version.rb +5 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/vigilem/ffi/array_pointer_sync_spec.rb +728 -0
- data/spec/vigilem/ffi/struct_spec.rb +22 -0
- data/spec/vigilem/ffi/utils/struct_spec.rb +79 -0
- data/spec/vigilem/ffi/utils_spec.rb +240 -0
- data/spec/vigilem/support/core_ext/enumerable_spec.rb +38 -0
- data/spec/vigilem/support/data/cached.kmap +130 -0
- data/spec/vigilem/support/data/cached_UTF-8_del.kmap +142 -0
- data/spec/vigilem/support/data/cached_short.kmap +38 -0
- data/spec/vigilem/support/data/dump_keys_short.kmap +128 -0
- data/spec/vigilem/support/key_map_spec.rb +767 -0
- data/spec/vigilem/support/lazy_simple_delegator_spec.rb +77 -0
- data/spec/vigilem/support/obj_space_spec.rb +47 -0
- data/spec/vigilem/support/sys_spec.rb +21 -0
- data/spec/vigilem/support/system_spec.rb +31 -0
- data/spec/vigilem/support/transmutable_hash_spec.rb +175 -0
- data/spec/vigilem/support/utils_spec.rb +214 -0
- metadata +240 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ca7c5b14a32d34b7a9160a7eb60b96bc0654b3a5
|
4
|
+
data.tar.gz: 612804d8a3aef4f01e8587d595ecf1044147df9c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6d99905696f122267df2d1ff04eaa1b62e65d7c7c678d353272ccc639a93592ac840ca4bce74daecef07510f75d9b79bf533a734b3477cfb07ce18e8087d327a
|
7
|
+
data.tar.gz: 9cd01bad9a80179757b155212f3cf60e2c3407813b060b465c76f3962846bbbfdb0aef33bf5242fec47afc03f82b40f5437e627077824d91e757b150e9f6ad93
|
data/lib/vigilem/ffi.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module Vigilem
|
4
|
+
module FFI
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'vigilem/support'
|
9
|
+
|
10
|
+
require 'vigilem/ffi/utils'
|
11
|
+
FFIUtils = ::Vigilem::FFI::Utils
|
12
|
+
|
13
|
+
require 'vigilem/ffi/utils/struct'
|
14
|
+
FFIStructUtils = FFIUtils::Struct
|
15
|
+
|
16
|
+
require 'vigilem/ffi/struct'
|
17
|
+
VFFIStruct = ::Vigilem::FFI::Struct
|
18
|
+
|
19
|
+
require 'vigilem/ffi/array_pointer_sync'
|
@@ -0,0 +1,382 @@
|
|
1
|
+
module Vigilem::FFI
|
2
|
+
# creates an ary of fixed size that is synched with
|
3
|
+
# an underlying FFI::Pointer, kind of reinventing the wheel here
|
4
|
+
# if you think about it
|
5
|
+
# this can be split further for a more dynamic ary that can increase in
|
6
|
+
# size, but thats for the future
|
7
|
+
# @note ary is used to match ptr used by struct
|
8
|
+
module ArrayPointerSync
|
9
|
+
|
10
|
+
require 'vigilem/support/max_size_error'
|
11
|
+
|
12
|
+
attr_accessor :cache_hash, :max_size
|
13
|
+
|
14
|
+
#
|
15
|
+
# @raise [TypeError] '@max_size is nil'
|
16
|
+
# @return
|
17
|
+
def max_size!
|
18
|
+
@max_size || raise(TypeError, '@max_size is nil')
|
19
|
+
end
|
20
|
+
|
21
|
+
alias_method :max_len, :max_size
|
22
|
+
alias_method :max_len=, :max_size=
|
23
|
+
|
24
|
+
private :cache_hash=, :max_size=, :max_len=
|
25
|
+
|
26
|
+
#
|
27
|
+
# @return [FFI::Pointer]
|
28
|
+
def ptr
|
29
|
+
@ptr ||= FFI::MemoryPointer.new(self.class.ary_type, self.max_size!)
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# @param base
|
34
|
+
# @return
|
35
|
+
def self.included(base)
|
36
|
+
base.extend ClassMethods
|
37
|
+
base.class_eval do
|
38
|
+
native_type FFI::Type::POINTER
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
@point_cuts = (Array.instance_methods -
|
43
|
+
[*Array.instance_methods.grep(/method|taint|trust|instance_variable|send|class|respond/),
|
44
|
+
:__id__, :object_id, :extend, :freeze, :kind_of?, :instance_of?, :is_a?, :replace, :eql?, :equal?
|
45
|
+
]).sort
|
46
|
+
|
47
|
+
#
|
48
|
+
# @param [Symbol] method_name
|
49
|
+
# @param [Array] args
|
50
|
+
# @param [Proc] block
|
51
|
+
# @raise [RuntimeException]
|
52
|
+
# @see #out_of_bounds_check
|
53
|
+
# @return
|
54
|
+
def after_ary_method(method_name, return_value, *args, &block)
|
55
|
+
out_of_bounds_check
|
56
|
+
update
|
57
|
+
return_value
|
58
|
+
end
|
59
|
+
|
60
|
+
@point_cuts.each do |point_cut|
|
61
|
+
define_method(point_cut) do |*args, &block|
|
62
|
+
begin
|
63
|
+
update
|
64
|
+
ret = ary().__send__(point_cut, *args, &block)
|
65
|
+
method_name = __method__
|
66
|
+
if not [:size, :length].include? method_name
|
67
|
+
after_ary_method(method_name, ret, *args, &block)
|
68
|
+
else
|
69
|
+
ret
|
70
|
+
end
|
71
|
+
rescue StandardError => e
|
72
|
+
e.set_backtrace([__method__.to_s] + e.backtrace)
|
73
|
+
raise e
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# @todo change max_len_or_ptr_or_first_item, and default max_size to init_values.length
|
79
|
+
# @param [Integer || FFI::Pointer] max_len_or_ptr
|
80
|
+
# @param [Array] init_values
|
81
|
+
# @return [ArrayPointerSync] self
|
82
|
+
def initialize_ary_ptr_sync(max_len_or_ptr, *init_values)
|
83
|
+
if max_len_or_ptr.is_a? FFI::Pointer
|
84
|
+
if not (max_len_or_ptr and init_values.empty?)
|
85
|
+
raise ArgumentError, "Cannot have both a pointer and *init_values:`#{max_len_or_ptr.inspect}' `#{init_values.inspect}'"
|
86
|
+
end
|
87
|
+
@ptr = max_len_or_ptr
|
88
|
+
update_ary
|
89
|
+
@max_size = ary().size
|
90
|
+
else
|
91
|
+
raise TypeError, "max_len_or_ptr, doesn't respond_to? :to_i" unless max_len_or_ptr.respond_to? :to_i
|
92
|
+
@max_size = max_len_or_ptr.to_i
|
93
|
+
@ary = init_values
|
94
|
+
@ptr = ::FFI::MemoryPointer.new(self.class.ary_type, @max_size)
|
95
|
+
update_ptr if not init_values.empty?
|
96
|
+
end
|
97
|
+
update_cache
|
98
|
+
self
|
99
|
+
end
|
100
|
+
|
101
|
+
#
|
102
|
+
#
|
103
|
+
module ClassMethods
|
104
|
+
include FFI::DataConverter
|
105
|
+
|
106
|
+
# @todo create and ary_type_wrapper for symbols so an if stmnt
|
107
|
+
# isn;t always needed
|
108
|
+
# @raise [RuntimeError]
|
109
|
+
# @return [Class || Symbol]
|
110
|
+
def ary_type
|
111
|
+
raise NotImplementedError, "No ary_type configured for this class #{self}"
|
112
|
+
end
|
113
|
+
|
114
|
+
#
|
115
|
+
# @return [Class]
|
116
|
+
def ary_type_object
|
117
|
+
if ary_type.is_a? Symbol
|
118
|
+
::FFI.find_type(ary_type)
|
119
|
+
else
|
120
|
+
ary_type
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
#
|
125
|
+
# @return [Integer] the size
|
126
|
+
def ary_type_size
|
127
|
+
ary_type_object.size
|
128
|
+
end
|
129
|
+
|
130
|
+
#
|
131
|
+
# @param [Pointer] pointer
|
132
|
+
# @return [Integer]
|
133
|
+
def ptr_capacity(pointer)
|
134
|
+
pointer.size/ary_type_size
|
135
|
+
end
|
136
|
+
|
137
|
+
#
|
138
|
+
# @return [Array<#ary_type>]
|
139
|
+
def ary_of_type(pointer)
|
140
|
+
Utils.ary_of_type(ary_type, ary_type_size, pointer)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# @see Array#replace
|
145
|
+
# @param [Array] other
|
146
|
+
# @return [ArrayPointerSync]
|
147
|
+
def replace(other)
|
148
|
+
ary.replace(other)
|
149
|
+
update
|
150
|
+
self
|
151
|
+
end
|
152
|
+
#
|
153
|
+
# @return [String]
|
154
|
+
def bytes
|
155
|
+
update
|
156
|
+
ptr.read_bytes(ptr.size)
|
157
|
+
end
|
158
|
+
|
159
|
+
# bytes of the idtem referenced by index
|
160
|
+
# @param [Integer] idx
|
161
|
+
# @return [String]
|
162
|
+
def bytes_of(idx)
|
163
|
+
update
|
164
|
+
ptr.get_bytes(idx * (type_size = self.class.ary_type_size), type_size)
|
165
|
+
end
|
166
|
+
|
167
|
+
#
|
168
|
+
# @return [Array<Integer>]
|
169
|
+
def offsets
|
170
|
+
if update or @ptr_offsets.nil?
|
171
|
+
_ptr_offsets
|
172
|
+
else
|
173
|
+
@ptr_offsets
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
#
|
178
|
+
# @raise [RuntimeError] when both ptr and ary changed
|
179
|
+
# @return [Hash] what item changed
|
180
|
+
def what_changed?
|
181
|
+
results = {ary: ary_changed?, ptr: ptr_changed? }
|
182
|
+
raise 'both ary and pointer changed' if results.values.all?
|
183
|
+
results
|
184
|
+
end
|
185
|
+
|
186
|
+
# checks to see if the the ptr contents
|
187
|
+
# or ary conents have changed
|
188
|
+
#
|
189
|
+
# @return [TrueClass || FalseClass]
|
190
|
+
def changed?
|
191
|
+
what_changed?.values.any?
|
192
|
+
end
|
193
|
+
|
194
|
+
#
|
195
|
+
# @return [TrueClass || FalseClass]
|
196
|
+
def ptr_changed?
|
197
|
+
ptr_cache_hash() != ptr_hash()
|
198
|
+
end
|
199
|
+
|
200
|
+
#
|
201
|
+
# @return [TrueClass || FalseClass]
|
202
|
+
def ary_changed?
|
203
|
+
self.cache_hash != ary().hash
|
204
|
+
end
|
205
|
+
|
206
|
+
# checks whether or not ary.size > max_size
|
207
|
+
# @return [TrueClass || FalseClass]
|
208
|
+
def out_of_bounds?
|
209
|
+
_size > max_size!
|
210
|
+
end
|
211
|
+
|
212
|
+
#
|
213
|
+
# @raises RuntimeException
|
214
|
+
# @return [NilClass]
|
215
|
+
def out_of_bounds_check
|
216
|
+
_raise_size_error if out_of_bounds?
|
217
|
+
end
|
218
|
+
|
219
|
+
#
|
220
|
+
# @param [Array] other
|
221
|
+
# @return [ArrayPointerSync]
|
222
|
+
def replace(other)
|
223
|
+
ary.replace(other)
|
224
|
+
update
|
225
|
+
self
|
226
|
+
end
|
227
|
+
|
228
|
+
#
|
229
|
+
#
|
230
|
+
# @return [Array]
|
231
|
+
def to_a
|
232
|
+
update
|
233
|
+
ary
|
234
|
+
end
|
235
|
+
|
236
|
+
# @todo
|
237
|
+
#def to_ary
|
238
|
+
#
|
239
|
+
#end
|
240
|
+
|
241
|
+
#
|
242
|
+
# @return [ArrayPointerSync]
|
243
|
+
def dup
|
244
|
+
self.class.new(ptr.dup)
|
245
|
+
end
|
246
|
+
|
247
|
+
# dup copies everything to a new pointer, is this needed? does it copy
|
248
|
+
# @return [ArrayPointerSync]
|
249
|
+
def deep_dup
|
250
|
+
pointer = FFI::MemoryPointer.new(self.class.ary_type, max_size)
|
251
|
+
pointer.write_bytes(self.bytes)
|
252
|
+
self.class.new(pointer)
|
253
|
+
end
|
254
|
+
|
255
|
+
# @return [String] just like that of an array
|
256
|
+
def to_s
|
257
|
+
update
|
258
|
+
ary.to_s
|
259
|
+
end
|
260
|
+
|
261
|
+
#
|
262
|
+
# @see Object#inspect
|
263
|
+
# @return [String]
|
264
|
+
def inspect
|
265
|
+
update
|
266
|
+
vars = instance_variables.except(:@ary).map {|var| "#{var}=#{instance_variable_get(var)}" }.join(' ')
|
267
|
+
"#{_to_s.chomp('>')} #{vars}>"
|
268
|
+
end
|
269
|
+
|
270
|
+
# the basic inspect structure without the vars
|
271
|
+
# @return [String]
|
272
|
+
def _to_s
|
273
|
+
"#<#{self.class}:0x#{object_id << 1} #{ary}>"
|
274
|
+
end
|
275
|
+
|
276
|
+
private
|
277
|
+
attr_accessor :ptr_cache_hash
|
278
|
+
|
279
|
+
#
|
280
|
+
# @return [Array]
|
281
|
+
def ary
|
282
|
+
@ary ||= []
|
283
|
+
end
|
284
|
+
|
285
|
+
#
|
286
|
+
# @return [Array<Integer>]
|
287
|
+
def _ptr_offsets
|
288
|
+
@ptr_offsets = 0.upto((ary.size - 1)).map {|n| self.class.ary_type_size * n }
|
289
|
+
end
|
290
|
+
|
291
|
+
# @see String#hash
|
292
|
+
# @return [Integer]
|
293
|
+
def ptr_hash
|
294
|
+
ptr.read_bytes(ptr.size).hash
|
295
|
+
end
|
296
|
+
|
297
|
+
# detects what changed and updates as needed
|
298
|
+
# @return [TrueClass || FalseClass] updated?
|
299
|
+
def update
|
300
|
+
if (results = what_changed?)[:ary]
|
301
|
+
update_ptr
|
302
|
+
update_ary_cache
|
303
|
+
true
|
304
|
+
elsif results[:ptr]
|
305
|
+
update_ary
|
306
|
+
update_ptr_cache
|
307
|
+
true
|
308
|
+
else
|
309
|
+
false
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
#
|
314
|
+
# this is slightly dangerous, if anything was still pointing to old pointer location
|
315
|
+
# now its being reclaimed, this will change it
|
316
|
+
# @return [Integer] hash
|
317
|
+
def update_ptr
|
318
|
+
ptr.clear
|
319
|
+
if (not (arry_type = self.class.ary_type).is_a?(Symbol))
|
320
|
+
if arry_type.respond_to? :to_native
|
321
|
+
ary.each {|item| ptr.write_pointer(arry_type.to_native(item, nil)) }
|
322
|
+
elsif arry_type.method_defined? :bytes
|
323
|
+
ptr.write_bytes(ary.map {|item| item.respond.bytes }.join)
|
324
|
+
elsif arry_type.method_defined? :pointer
|
325
|
+
ary.each do |item|
|
326
|
+
if item.size == item.pointer.size
|
327
|
+
ptr.write_bytes((itm_ptr = item.pointer).read_bytes(itm_ptr.size))
|
328
|
+
else
|
329
|
+
raise ArgumentError, "Cannot reliably convert `#{item}' to a native_type"
|
330
|
+
end
|
331
|
+
end
|
332
|
+
else
|
333
|
+
raise ArgumentError, "Cannot reliably convert `#{arry_type}' to a native_type"
|
334
|
+
end
|
335
|
+
else
|
336
|
+
Utils.put_array_typedef(ptr, arry_type, ary)
|
337
|
+
end
|
338
|
+
update_ptr_cache
|
339
|
+
#self.ptr_cache_hash = @bytes.hash # @FIXME ptr_hash() and @bytes.hash should be the same...
|
340
|
+
end
|
341
|
+
|
342
|
+
#
|
343
|
+
# @return [Array<self.class.ary_type>]
|
344
|
+
def update_ary
|
345
|
+
arry = ary.replace(self.class.ary_of_type(ptr))
|
346
|
+
_ptr_offsets
|
347
|
+
update_ary_cache
|
348
|
+
arry
|
349
|
+
end
|
350
|
+
|
351
|
+
# size method on ary without update
|
352
|
+
# @return [Integer] size
|
353
|
+
def _size
|
354
|
+
ary.size
|
355
|
+
end
|
356
|
+
|
357
|
+
#
|
358
|
+
# @return [Array<Integer>]
|
359
|
+
def update_cache
|
360
|
+
[update_ary_cache, update_ptr_cache]
|
361
|
+
end
|
362
|
+
|
363
|
+
#
|
364
|
+
# @return [Integer] hash
|
365
|
+
def update_ptr_cache
|
366
|
+
self.ptr_cache_hash = ptr_hash()
|
367
|
+
end
|
368
|
+
|
369
|
+
#
|
370
|
+
# @return [Integer] hash
|
371
|
+
def update_ary_cache
|
372
|
+
self.cache_hash = ary().hash
|
373
|
+
end
|
374
|
+
|
375
|
+
#
|
376
|
+
# @raise [RuntimeError]
|
377
|
+
# @return
|
378
|
+
def _raise_size_error
|
379
|
+
raise Vigilem::Support::MaxSizeError, [_to_s, self.max_size!]
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Vigilem
|
2
|
+
module FFI
|
3
|
+
# ::FFI::Struct with some sugar
|
4
|
+
class Struct < ::FFI::Struct
|
5
|
+
|
6
|
+
include Utils::Struct
|
7
|
+
|
8
|
+
# should make assign private, but since FFI::Struct.rb
|
9
|
+
# doesn;t know it's memory location
|
10
|
+
# this may have to be updated from the outside
|
11
|
+
attr_accessor :ptr_offset
|
12
|
+
|
13
|
+
#
|
14
|
+
# @param [FFI::Pointer || Integer] ptr_or_offset
|
15
|
+
# @param [Integer] offset
|
16
|
+
def initialize(ptr_or_offset=nil, offset=0)
|
17
|
+
if ptr_or_offset.is_a? Integer
|
18
|
+
super()
|
19
|
+
@ptr_offset = ptr_or_offset
|
20
|
+
else
|
21
|
+
super(*ptr_or_offset)
|
22
|
+
@ptr_offset = offset
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# allows initial values in a new object like Hash::[]
|
27
|
+
# @todo move to utils/struct::ClassMethods
|
28
|
+
# @param [Array<Hash||Array>] *vals
|
29
|
+
# @return [Struct]
|
30
|
+
def self.[](*vals)
|
31
|
+
frst = vals.first
|
32
|
+
vals = frst if frst.is_a? Hash and vals.size == 1
|
33
|
+
new.bulk_assign(vals)
|
34
|
+
end
|
35
|
+
|
36
|
+
# converts struct to a String bytes "\x00" or "\u0000"
|
37
|
+
# the struct needs to know where in the pointer it is...
|
38
|
+
# @param [FFI::Struct] struct
|
39
|
+
# @return [String]
|
40
|
+
def bytes
|
41
|
+
ptr = self.to_ptr
|
42
|
+
ptr.get_bytes(self.ptr_offset, self.size)
|
43
|
+
end
|
44
|
+
|
45
|
+
# shows the members and thier values in addition to the traditional inspect
|
46
|
+
# @see Object#inspect
|
47
|
+
# @return [String]
|
48
|
+
def inspect
|
49
|
+
"#{super.chop} #{members.map {|mem| "#{mem}=#{self[mem]}" }.join(' ')}>"
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|