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.
@@ -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
- attr_reader :type
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
- def entities; [CommonCode] end
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
- func = @type + str[0,1].capitalize + str[1..-1] # Ruby 1.8 compatible
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
- func # Emit bare function name
187
+ fn # Emit bare function name
67
188
  elsif args.size == 1 && args.first == nil
68
- func + "()" # Use sole nil argument to emit function call with no arguments
189
+ fn + '()' # Use sole nil argument to emit function call with no arguments
69
190
  else
70
- func + "(" + args.join(", ") + ")" # Emit normal function call with supplied arguments
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
- case @visibility
76
- when :public
77
- write_exported_types(stream)
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
- case @visibility
84
- when :private
85
- write_exported_types(stream)
86
- write_exported_declarations(stream, extern, inline)
87
- when :static
88
- write_exported_types(stream)
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
- case @visibility
95
- when :public, :private
96
- write_implementations(stream, nil)
97
- when :static
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 write_exported_types(stream) end
220
+ # def write_intf_types(stream)
103
221
 
104
- def write_exported_declarations(stream, declare, define) end
222
+ # def write_intf_decls(stream, declare, define)
105
223
 
106
- def write_implementations(stream, define) end
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 + [Type::CommonCode] end
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 eql?(other) self.class == other.class && @forward == other.instance_variable_get(:@forward) end
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 + @deps end
297
+ def entities; super.concat(@deps) end
298
+
299
+ def prefix; @prefix.nil? ? super : @prefix end
151
300
 
152
301
  def initialize(opt)
153
- @deps = []
154
- v = :public
155
- if [Symbol, String].include?(opt.class)
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 "failed to decode the argument"
306
+ raise "argument must be a Symbol, String or Hash"
167
307
  end
168
- super(t, v)
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
- def ctor(obj)
172
- @ctor.nil? ? "(#{obj} = 0)" : "#{@ctor}(#{obj})"
173
- end
322
+ private
174
323
 
175
- def dtor(obj)
176
- @dtor.nil? ? nil : "#{@dtor}(#{obj})"
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
- def copy(dst, src)
180
- @copy.nil? ? "(#{dst} = #{src})" : "#{@copy}(#{dst}, #{src})"
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 equal(lt, rt)
184
- @equal.nil? ? "(#{lt} == #{rt})" : "#{@equal}(#{lt}, #{rt})"
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 less(lt, rt)
188
- @less.nil? ? "(#{lt} < #{rt})" : "#{@less}(#{lt}, #{rt})"
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
- def identify(obj)
192
- @identify.nil? ? "(size_t)(#{obj})" : "#{@identify}(#{obj})"
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 # UserDefinedType
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