autoc 1.1 → 1.2
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 +4 -4
- data/.yardopts +3 -1
- data/CHANGES +15 -0
- data/README +2 -0
- data/doc/AutoC.html +84 -14
- data/doc/AutoC/Code.html +31 -31
- data/doc/AutoC/Collection.html +250 -182
- data/doc/AutoC/HashMap.html +565 -245
- data/doc/AutoC/HashSet.html +266 -264
- data/doc/AutoC/List.html +317 -249
- data/doc/AutoC/Module.html +66 -72
- data/doc/AutoC/Module/File.html +25 -25
- data/doc/AutoC/Module/Header.html +25 -25
- data/doc/AutoC/Module/Source.html +43 -43
- data/doc/AutoC/Priority.html +3 -3
- data/doc/AutoC/Queue.html +352 -286
- data/doc/AutoC/Reference.html +578 -0
- data/doc/AutoC/Type.html +941 -131
- data/doc/AutoC/UserDefinedType.html +64 -313
- data/doc/AutoC/Vector.html +336 -306
- data/doc/_index.html +22 -4
- data/doc/class_list.html +6 -2
- data/doc/file.CHANGES.html +102 -0
- data/doc/file.README.html +7 -4
- data/doc/file_list.html +8 -1
- data/doc/frames.html +1 -1
- data/doc/index.html +7 -4
- data/doc/js/full_list.js +4 -1
- data/doc/method_list.html +236 -118
- data/doc/top-level-namespace.html +3 -3
- data/lib/autoc.rb +3 -3
- data/lib/autoc/code.rb +11 -5
- data/lib/autoc/collection.rb +62 -56
- data/lib/autoc/collection/hash_map.rb +83 -63
- data/lib/autoc/collection/hash_set.rb +74 -64
- data/lib/autoc/collection/list.rb +48 -41
- data/lib/autoc/collection/queue.rb +53 -47
- data/lib/autoc/collection/vector.rb +63 -42
- data/lib/autoc/type.rb +326 -61
- data/test/test.c +120 -0
- data/test/test.rb +16 -2
- data/test/test_auto.c +1683 -987
- data/test/test_auto.h +491 -176
- metadata +22 -19
data/lib/autoc/type.rb
CHANGED
@@ -1,9 +1,104 @@
|
|
1
|
+
require "set"
|
2
|
+
require "forwardable"
|
1
3
|
require "autoc/code"
|
2
4
|
|
3
5
|
|
4
6
|
module AutoC
|
5
7
|
|
6
8
|
|
9
|
+
# @private
|
10
|
+
class Dispatcher
|
11
|
+
|
12
|
+
# @private
|
13
|
+
class ParameterArray < Array
|
14
|
+
def self.coerce(*params)
|
15
|
+
out = []
|
16
|
+
i = 0
|
17
|
+
params.each do |t|
|
18
|
+
i += 1
|
19
|
+
out << (t.is_a?(Array) ? t.collect {|x| x.to_s} : [t.to_s, "_#{i}"])
|
20
|
+
end
|
21
|
+
self.new(out)
|
22
|
+
end
|
23
|
+
# Test for parameter list compatibility
|
24
|
+
def ===(other) other.is_a?(ParameterArray) && types == other.types end
|
25
|
+
def types; collect {|x| x.first} end
|
26
|
+
def names; collect {|x| x.last} end
|
27
|
+
def pass; names.join(',') end
|
28
|
+
def declaration; types.join(',') end
|
29
|
+
def definition; collect {|x| "#{x.first} #{x.last}"}.join(',') end
|
30
|
+
end # ParameterArray
|
31
|
+
|
32
|
+
# def call(*params)
|
33
|
+
|
34
|
+
def dispatch(*params)
|
35
|
+
if params.empty?
|
36
|
+
self
|
37
|
+
else
|
38
|
+
params = [] if params.size == 1 && params.first.nil?
|
39
|
+
call(*params)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end # Dispatcher
|
44
|
+
|
45
|
+
|
46
|
+
# @private
|
47
|
+
class Statement < Dispatcher
|
48
|
+
|
49
|
+
attr_reader :parameters
|
50
|
+
|
51
|
+
def initialize(params = [])
|
52
|
+
@parameters = ParameterArray.coerce(*params)
|
53
|
+
end
|
54
|
+
|
55
|
+
end # Statement
|
56
|
+
|
57
|
+
|
58
|
+
# @private
|
59
|
+
class Function < Dispatcher
|
60
|
+
|
61
|
+
# @private
|
62
|
+
class Signature
|
63
|
+
|
64
|
+
attr_reader :parameters, :result
|
65
|
+
|
66
|
+
def initialize(params = [], result = nil)
|
67
|
+
@parameters = Dispatcher::ParameterArray.coerce(*params)
|
68
|
+
@result = (result.nil? ? :void : result).to_s
|
69
|
+
end
|
70
|
+
|
71
|
+
end # Signature
|
72
|
+
|
73
|
+
extend Forwardable
|
74
|
+
|
75
|
+
def_delegators :@signature,
|
76
|
+
:parameters, :result
|
77
|
+
|
78
|
+
attr_reader :name, :signature
|
79
|
+
|
80
|
+
def initialize(name, a = [], b = nil)
|
81
|
+
@name = AutoC.c_id(name)
|
82
|
+
@signature = a.is_a?(Signature) ? a : Signature.new(a, b)
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_s; name end
|
86
|
+
|
87
|
+
def call(*params)
|
88
|
+
"#{name}(#{params.join(',')})"
|
89
|
+
end
|
90
|
+
|
91
|
+
def definition
|
92
|
+
"#{result} #{name}(#{parameters.definition})"
|
93
|
+
end
|
94
|
+
|
95
|
+
def declaration
|
96
|
+
"#{result} #{name}(#{parameters.declaration})"
|
97
|
+
end
|
98
|
+
|
99
|
+
end # Function
|
100
|
+
|
101
|
+
|
7
102
|
class Type < Code
|
8
103
|
|
9
104
|
# @private
|
@@ -50,60 +145,83 @@ class Type < Code
|
|
50
145
|
end
|
51
146
|
end.new
|
52
147
|
|
53
|
-
|
148
|
+
def self.coerce(type)
|
149
|
+
type.is_a?(Type) ? type : UserDefinedType.new(type)
|
150
|
+
end
|
151
|
+
|
152
|
+
def hash; self.class.hash ^ type.hash end
|
153
|
+
|
154
|
+
def ==(other) self.class == other.class && type == other.type end
|
54
155
|
|
55
|
-
|
156
|
+
alias :eql? :==
|
157
|
+
|
158
|
+
def entities; super << CommonCode end
|
56
159
|
|
160
|
+
attr_reader :type, :type_ref
|
161
|
+
|
162
|
+
def prefix
|
163
|
+
# Lazy evaluator for simple types like char* which do not actually use
|
164
|
+
# this method and hence do not require the prefix to be valid C identifier
|
165
|
+
AutoC.c_id(type)
|
166
|
+
end
|
167
|
+
|
57
168
|
def initialize(type, visibility = :public)
|
58
169
|
@type = type.to_s
|
170
|
+
@type_ref = "#{self.type}*"
|
59
171
|
@visibility = [:public, :private, :static].include?(visibility) ? visibility : raise("unsupported visibility")
|
172
|
+
@capability = Set[:constructible, :destructible, :copyable, :comparable, :hashable, :orderable] # Can be used to disable specific capabilities for a type
|
173
|
+
# Canonic special method signatures
|
174
|
+
@ctor_signature = Function::Signature.new([type^:self])
|
175
|
+
@dtor_signature = Function::Signature.new([type^:self])
|
176
|
+
@copy_signature = Function::Signature.new([type^:dst, type^:src])
|
177
|
+
@equal_signature = Function::Signature.new([type^:lt, type^:rt], :int)
|
178
|
+
@identify_signature = Function::Signature.new([type^:self], :size_t)
|
179
|
+
@less_signature = Function::Signature.new([type^:lt, type^:rt], :int)
|
60
180
|
end
|
61
181
|
|
62
182
|
def method_missing(method, *args)
|
63
183
|
str = method.to_s
|
64
|
-
|
184
|
+
str = str.sub(/[\!\?]$/, '') # Strip trailing ? or !
|
185
|
+
fn = prefix + str[0,1].capitalize + str[1..-1] # Ruby 1.8 compatible
|
65
186
|
if args.empty?
|
66
|
-
|
187
|
+
fn # Emit bare function name
|
67
188
|
elsif args.size == 1 && args.first == nil
|
68
|
-
|
189
|
+
fn + '()' # Use sole nil argument to emit function call with no arguments
|
69
190
|
else
|
70
|
-
|
191
|
+
fn + '(' + args.join(',') + ')' # Emit normal function call with supplied arguments
|
71
192
|
end
|
72
193
|
end
|
73
194
|
|
74
195
|
def write_intf(stream)
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
write_exported_declarations(stream, extern, inline)
|
196
|
+
if public?
|
197
|
+
write_intf_types(stream)
|
198
|
+
write_intf_decls(stream, extern, inline)
|
79
199
|
end
|
80
200
|
end
|
81
201
|
|
82
202
|
def write_decls(stream)
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
write_exported_declarations(stream, static, inline)
|
203
|
+
if private?
|
204
|
+
write_intf_types(stream)
|
205
|
+
write_intf_decls(stream, extern, inline)
|
206
|
+
elsif static?
|
207
|
+
write_intf_types(stream)
|
208
|
+
write_intf_decls(stream, static, inline)
|
90
209
|
end
|
91
210
|
end
|
92
211
|
|
93
212
|
def write_defs(stream)
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
write_implementations(stream, static)
|
213
|
+
if public? || private?
|
214
|
+
write_impls(stream, nil)
|
215
|
+
elsif static?
|
216
|
+
write_impls(stream, static)
|
99
217
|
end
|
100
218
|
end
|
101
219
|
|
102
|
-
def
|
220
|
+
# def write_intf_types(stream)
|
103
221
|
|
104
|
-
def
|
222
|
+
# def write_intf_decls(stream, declare, define)
|
105
223
|
|
106
|
-
def
|
224
|
+
# def write_impls(stream, define)
|
107
225
|
|
108
226
|
def extern; "AUTOC_EXTERN" end
|
109
227
|
|
@@ -121,78 +239,225 @@ class Type < Code
|
|
121
239
|
|
122
240
|
def abort; "abort" end
|
123
241
|
|
124
|
-
protected
|
125
|
-
|
126
242
|
def public?; @visibility == :public end
|
127
243
|
|
128
244
|
def private?; @visibility == :private end
|
129
245
|
|
130
246
|
def static?; @visibility == :static end
|
131
247
|
|
248
|
+
def constructible?; @capability.include?(:constructible) end
|
249
|
+
|
250
|
+
def destructible?; @capability.include?(:destructible) end
|
251
|
+
|
252
|
+
def copyable?; @capability.include?(:copyable) end
|
253
|
+
|
254
|
+
def comparable?; @capability.include?(:comparable) end
|
255
|
+
|
256
|
+
def orderable?; @capability.include?(:orderable) && comparable? end
|
257
|
+
|
258
|
+
def hashable?; @capability.include?(:hashable) && comparable? end
|
259
|
+
|
260
|
+
# Create forwarding readers which take arbitrary number of arguments
|
261
|
+
[:ctor, :dtor, :copy, :equal, :identify, :less].each do |name|
|
262
|
+
class_eval %$
|
263
|
+
def #{name}(*args)
|
264
|
+
@#{name}.dispatch(*args)
|
265
|
+
end
|
266
|
+
$
|
267
|
+
end
|
268
|
+
|
269
|
+
private
|
270
|
+
|
271
|
+
def define_function(name, signature)
|
272
|
+
Function.new(method_missing(name), signature)
|
273
|
+
end
|
274
|
+
|
132
275
|
end # Type
|
133
276
|
|
134
277
|
|
278
|
+
=begin
|
279
|
+
|
280
|
+
UserDefinedType represents a user-defined custom type.
|
281
|
+
|
282
|
+
=end
|
135
283
|
class UserDefinedType < Type
|
136
284
|
|
137
285
|
# @private
|
138
286
|
class PublicDeclaration < Code
|
139
|
-
def entities; super
|
287
|
+
def entities; super << Type::CommonCode end
|
140
288
|
def initialize(forward) @forward = forward.to_s end
|
141
289
|
def hash; @forward.hash end
|
142
|
-
def
|
290
|
+
def ==(other) self.class == other.class && @forward == other.instance_variable_get(:@forward) end
|
291
|
+
alias :eql? :==
|
143
292
|
def write_intf(stream)
|
144
|
-
stream << "\n"
|
145
|
-
stream << @forward
|
146
|
-
stream << "\n"
|
293
|
+
stream << "\n#{@forward}\n"
|
147
294
|
end
|
148
295
|
end # PublicDeclaration
|
149
296
|
|
150
|
-
def entities; super
|
297
|
+
def entities; super.concat(@deps) end
|
298
|
+
|
299
|
+
def prefix; @prefix.nil? ? super : @prefix end
|
151
300
|
|
152
301
|
def initialize(opt)
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
t = opt
|
157
|
-
elsif opt.is_a?(Hash)
|
158
|
-
t = opt[:type].nil? ? raise("type is not specified") : opt[:type]
|
159
|
-
[:ctor, :dtor, :copy, :equal, :less, :identify].each do |key|
|
160
|
-
instance_variable_set("@#{key}".to_sym, opt[key].to_s) unless opt[key].nil?
|
161
|
-
end
|
162
|
-
@deps << PublicDeclaration.new(opt[:forward]) unless opt[:forward].nil?
|
163
|
-
optv = opt[:visibility]
|
164
|
-
v = optv.nil? ? :public : optv
|
302
|
+
opt = {:type => opt} if opt.is_a?(Symbol) || opt.is_a?(String)
|
303
|
+
if opt.is_a?(Hash)
|
304
|
+
t = opt[:type].nil? ? raise("type is not specified") : opt[:type].to_s
|
165
305
|
else
|
166
|
-
raise "
|
306
|
+
raise "argument must be a Symbol, String or Hash"
|
167
307
|
end
|
168
|
-
super(t
|
308
|
+
super(t)
|
309
|
+
@prefix = AutoC.c_id(opt[:prefix]) unless opt[:prefix].nil?
|
310
|
+
@deps = []; @deps << PublicDeclaration.new(opt[:forward]) unless opt[:forward].nil?
|
311
|
+
opt.default = :unset # This allows to use nil as a value to indicate that the specific method is not avaliable
|
312
|
+
opt[:ctor].nil? ? @capability.subtract([:constructible]) : define_callable(:ctor, opt) {def call(obj) "((#{obj}) = 0)" end}
|
313
|
+
opt[:dtor].nil? ? @capability.subtract([:destructible]) : define_callable(:dtor, opt) {def call(obj) end}
|
314
|
+
opt[:copy].nil? ? @capability.subtract([:copyable]) : define_callable(:copy, opt) {def call(dst, src) "((#{dst}) = (#{src}))" end}
|
315
|
+
opt[:equal].nil? ? @capability.subtract([:comparable]) : define_callable(:equal, opt) {def call(lt, rt) "((#{lt}) == (#{rt}))" end}
|
316
|
+
opt[:less].nil? ? @capability.subtract([:orderable]) : define_callable(:less, opt) {def call(lt, rt) "((#{lt}) < (#{rt}))" end}
|
317
|
+
opt[:identify].nil? ? @capability.subtract([:hashable]) : define_callable(:identify, opt) {def call(obj) "((size_t)(#{obj}))" end}
|
318
|
+
# Handle specific requirements
|
319
|
+
@capability.subtract([:constructible]) if @ctor.parameters.size > 1 # Constructible type must not have extra parameters besides self
|
169
320
|
end
|
170
321
|
|
171
|
-
|
172
|
-
@ctor.nil? ? "(#{obj} = 0)" : "#{@ctor}(#{obj})"
|
173
|
-
end
|
322
|
+
private
|
174
323
|
|
175
|
-
|
176
|
-
|
324
|
+
# Default methods creator
|
325
|
+
def define_callable(name, opt, &code)
|
326
|
+
iv = "@#{name}"
|
327
|
+
ivs = "@#{name}_signature"
|
328
|
+
c = if opt[name] == :unset
|
329
|
+
# Synthesize statement block with default (canonic) parameter list
|
330
|
+
Class.new(Statement, &code).new(instance_variable_get(ivs).parameters)
|
331
|
+
elsif opt[name].is_a?(Function)
|
332
|
+
opt[name] # If a Function instance is given, pass it through
|
333
|
+
else
|
334
|
+
# If only a name is specified, assume it is the function name with default signature
|
335
|
+
Function.new(opt[name], instance_variable_get(ivs))
|
336
|
+
end
|
337
|
+
instance_variable_set(iv, c)
|
177
338
|
end
|
178
339
|
|
179
|
-
|
180
|
-
|
340
|
+
end # UserDefinedType
|
341
|
+
|
342
|
+
|
343
|
+
=begin
|
344
|
+
|
345
|
+
Reference represents a managed counted reference for any type.
|
346
|
+
It can be used with any type, including AutoC collections themselves.
|
347
|
+
|
348
|
+
== Generated C interface
|
349
|
+
|
350
|
+
=== Type management
|
351
|
+
|
352
|
+
[cols="2*"]
|
353
|
+
|===
|
354
|
+
|*_Type_* * ~type~New(...)
|
355
|
+
|
|
356
|
+
Create and return a reference to *_Type_* with reference count set to one.
|
357
|
+
|
358
|
+
The storage for the returned instance is malloc()'ed. The instance is constructed with the type's constructor ~type~Ctor(...).
|
359
|
+
|
360
|
+
NOTE: The generated method borrows the second and subsequent arguments from the respective constructor.
|
361
|
+
|
362
|
+
|*_Type_* * ~type~Ref(*_Type_* * self)
|
363
|
+
|
|
364
|
+
Increment the +self+'s reference count and return +self+.
|
365
|
+
|
366
|
+
|*_void_* ~type~Free(*_Type_* * self)
|
367
|
+
|
|
368
|
+
Decrement the +self+'s reference count.
|
369
|
+
If the reference count reaches zero, free the storage and destroy the instance with the type's destructor ~type~Dtor().
|
370
|
+
|
371
|
+
=end
|
372
|
+
class Reference < Type
|
373
|
+
|
374
|
+
extend Forwardable
|
375
|
+
|
376
|
+
def_delegators :@target,
|
377
|
+
:prefix,
|
378
|
+
:public?, :private?, :static?,
|
379
|
+
:constructible?, :destructible?, :copyable?, :comparable?, :orderable?, :hashable?
|
380
|
+
|
381
|
+
def initialize(target)
|
382
|
+
@target = Type.coerce(target)
|
383
|
+
super(@target.type_ref) # NOTE : the type of the Reference instance itself is actually a pointer type
|
384
|
+
@ctor_params = Dispatcher::ParameterArray.new(@target.ctor.parameters[1..-1]) # Capture extra parameters from the target type constructor
|
385
|
+
define_callable(:ctor, @ctor_params) {def call(obj, *params) "((#{obj}) = #{@ref.new?}(#{params.join(',')}))" end}
|
386
|
+
define_callable(:dtor, [type]) {def call(obj) "#{@ref.free?}(#{obj})" end}
|
387
|
+
define_callable(:copy, [type, type]) {def call(dst, src) "((#{dst}) = #{@ref.ref?}(#{src}))" end}
|
388
|
+
define_callable(:equal, [type, type]) {def call(lt, rt) @target.equal("*#{lt}", "*#{rt}") end}
|
389
|
+
define_callable(:less, [type, type]) {def call(lt, rt) @target.less("*#{lt}", "*#{rt}") end}
|
390
|
+
define_callable(:identify, [type]) {def call(obj) @target.identify("*#{obj}") end}
|
181
391
|
end
|
182
392
|
|
183
|
-
def
|
184
|
-
|
393
|
+
def ==(other) @target == other.instance_variable_get(:@target) end
|
394
|
+
|
395
|
+
alias :eql? :==
|
396
|
+
|
397
|
+
def entities; super << @target end
|
398
|
+
|
399
|
+
def write_intf_decls(stream, declare, define)
|
400
|
+
stream << %$
|
401
|
+
/***
|
402
|
+
**** <#{type}> (#{self.class})
|
403
|
+
***/
|
404
|
+
#{declare} #{type} #{new?}(#{@ctor_params.declaration});
|
405
|
+
#{declare} #{type} #{ref?}(#{type});
|
406
|
+
#{declare} void #{free?}(#{type});
|
407
|
+
$
|
185
408
|
end
|
186
409
|
|
187
|
-
def
|
188
|
-
|
410
|
+
def write_impls(stream, define)
|
411
|
+
stream << %$
|
412
|
+
#define AUTOC_COUNTER(p) (*(size_t*)((char*)(p) + sizeof(#{@target.type})))
|
413
|
+
#{define} #{type} #{new?}(#{@ctor_params.definition}) {
|
414
|
+
#{type} self = (#{type})#{malloc}(sizeof(#{@target.type}) + sizeof(size_t)); #{assert}(self);
|
415
|
+
#{@target.ctor("*self", *@ctor_params.names)};
|
416
|
+
AUTOC_COUNTER(self) = 1;
|
417
|
+
return self;
|
418
|
+
}
|
419
|
+
#{define} #{type} #{ref?}(#{type} self) {
|
420
|
+
#{assert}(self);
|
421
|
+
++AUTOC_COUNTER(self);
|
422
|
+
return self;
|
423
|
+
}
|
424
|
+
#{define} void #{free?}(#{type} self) {
|
425
|
+
#{assert}(self);
|
426
|
+
if(--AUTOC_COUNTER(self) == 0) {
|
427
|
+
#{@target.dtor("*self")};
|
428
|
+
#{free}(self);
|
429
|
+
}
|
430
|
+
}
|
431
|
+
#undef AUTOC_COUNTER
|
432
|
+
$
|
189
433
|
end
|
190
434
|
|
191
|
-
|
192
|
-
|
435
|
+
private
|
436
|
+
|
437
|
+
# @private
|
438
|
+
class BoundStatement < Statement
|
439
|
+
def initialize(ref, target, params)
|
440
|
+
super(params)
|
441
|
+
@ref = ref
|
442
|
+
@target = target
|
443
|
+
end
|
444
|
+
end # BoundStatement
|
445
|
+
|
446
|
+
def define_callable(name, params, &code)
|
447
|
+
instance_variable_set("@#{name}", Class.new(BoundStatement, &code).new(self, @target, params))
|
193
448
|
end
|
194
449
|
|
195
|
-
end #
|
450
|
+
end # Reference
|
451
|
+
|
452
|
+
|
453
|
+
# Class adjustments for the function signature definition DSL
|
454
|
+
[Symbol, String, Type].each do |type|
|
455
|
+
type.class_eval do
|
456
|
+
def ^(name)
|
457
|
+
[self, name]
|
458
|
+
end
|
459
|
+
end
|
460
|
+
end
|
196
461
|
|
197
462
|
|
198
463
|
end # AutoC
|