autoc 1.4 → 2.0.0
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 +5 -5
- data/CHANGES.md +3 -0
- data/README.md +149 -0
- data/cmake/AutoC.cmake +39 -0
- data/lib/autoc/allocators.rb +51 -0
- data/lib/autoc/association.rb +126 -0
- data/lib/autoc/box.rb +311 -0
- data/lib/autoc/cmake.rb +54 -0
- data/lib/autoc/collection.rb +83 -110
- data/lib/autoc/composite.rb +333 -0
- data/lib/autoc/cstring.rb +263 -0
- data/lib/autoc/function.rb +247 -0
- data/lib/autoc/hash_map.rb +328 -0
- data/lib/autoc/hash_set.rb +339 -0
- data/lib/autoc/hashers.rb +102 -0
- data/lib/autoc/list.rb +444 -0
- data/lib/autoc/module.rb +434 -0
- data/lib/autoc/openmp.rb +15 -0
- data/lib/autoc/primitive.rb +27 -0
- data/lib/autoc/ranges.rb +707 -0
- data/lib/autoc/record.rb +247 -0
- data/lib/autoc/scaffold/docs.rb +117 -0
- data/lib/autoc/scaffold/generic_value.rb +86 -0
- data/lib/autoc/scaffold/project.rb +75 -0
- data/lib/autoc/scaffold/test_cstring.rb +113 -0
- data/lib/autoc/scaffold/test_cstring_hash_set.rb +35 -0
- data/lib/autoc/scaffold/test_int_box.rb +22 -0
- data/lib/autoc/scaffold/test_int_hash_set.rb +448 -0
- data/lib/autoc/scaffold/test_int_list.rb +106 -0
- data/lib/autoc/scaffold/test_int_vector.rb +83 -0
- data/lib/autoc/scaffold/test_v2v_hash_map.rb +83 -0
- data/lib/autoc/scaffold/test_value_hash_set.rb +60 -0
- data/lib/autoc/scaffold/test_value_vector.rb +146 -0
- data/{test/test.rb → lib/autoc/scaffold/tests.rb} +179 -158
- data/lib/autoc/scaffold.rb +12 -0
- data/lib/autoc/sequential.rb +99 -0
- data/lib/autoc/set.rb +331 -0
- data/lib/autoc/std.rb +149 -0
- data/lib/autoc/type.rb +93 -531
- data/lib/autoc/vector.rb +290 -0
- data/lib/autoc.rb +4 -35
- metadata +55 -85
- data/.yardopts +0 -4
- data/CHANGES +0 -23
- data/README +0 -28
- data/doc/AutoC/Code.html +0 -523
- data/doc/AutoC/Collection.html +0 -1214
- data/doc/AutoC/HashMap.html +0 -1441
- data/doc/AutoC/HashSet.html +0 -916
- data/doc/AutoC/Iterators/Bidirectional.html +0 -204
- data/doc/AutoC/Iterators/Unidirectional.html +0 -200
- data/doc/AutoC/Iterators.html +0 -126
- data/doc/AutoC/List.html +0 -1039
- data/doc/AutoC/Maps.html +0 -290
- data/doc/AutoC/Module/File.html +0 -415
- data/doc/AutoC/Module/Header.html +0 -437
- data/doc/AutoC/Module/Source.html +0 -707
- data/doc/AutoC/Module.html +0 -948
- data/doc/AutoC/Priority.html +0 -138
- data/doc/AutoC/Queue.html +0 -1172
- data/doc/AutoC/Reference.html +0 -735
- data/doc/AutoC/Sets.html +0 -520
- data/doc/AutoC/String.html +0 -1394
- data/doc/AutoC/TreeMap.html +0 -1565
- data/doc/AutoC/TreeSet.html +0 -1447
- data/doc/AutoC/Type.html +0 -2148
- data/doc/AutoC/UserDefinedType.html +0 -1047
- data/doc/AutoC/Vector.html +0 -987
- data/doc/AutoC.html +0 -331
- data/doc/_index.html +0 -388
- data/doc/class_list.html +0 -51
- data/doc/css/common.css +0 -1
- data/doc/css/full_list.css +0 -58
- data/doc/css/style.css +0 -481
- data/doc/file.CHANGES.html +0 -117
- data/doc/file.README.html +0 -116
- data/doc/file_list.html +0 -61
- data/doc/frames.html +0 -17
- data/doc/index.html +0 -116
- data/doc/js/app.js +0 -243
- data/doc/js/full_list.js +0 -216
- data/doc/js/jquery.js +0 -4
- data/doc/method_list.html +0 -1307
- data/doc/top-level-namespace.html +0 -112
- data/lib/autoc/code.rb +0 -237
- data/lib/autoc/collection/hash_map.rb +0 -385
- data/lib/autoc/collection/hash_set.rb +0 -337
- data/lib/autoc/collection/iterator.rb +0 -39
- data/lib/autoc/collection/list.rb +0 -429
- data/lib/autoc/collection/map.rb +0 -41
- data/lib/autoc/collection/queue.rb +0 -517
- data/lib/autoc/collection/set.rb +0 -134
- data/lib/autoc/collection/tree_map.rb +0 -464
- data/lib/autoc/collection/tree_set.rb +0 -611
- data/lib/autoc/collection/vector.rb +0 -336
- data/lib/autoc/string.rb +0 -492
- data/test/test_auto.c +0 -7141
- data/test/test_auto.h +0 -753
- data/test/test_char_string.rb +0 -270
- data/test/test_int_list.rb +0 -35
- data/test/test_int_tree_set.rb +0 -111
- data/test/test_int_vector.rb +0 -34
- data/test/test_value_hash_map.rb +0 -162
- data/test/test_value_hash_set.rb +0 -173
- data/test/test_value_list.rb +0 -193
- data/test/test_value_queue.rb +0 -275
- data/test/test_value_tree_map.rb +0 -176
- data/test/test_value_tree_set.rb +0 -173
- data/test/test_value_vector.rb +0 -155
- data/test/value.rb +0 -80
data/lib/autoc/module.rb
ADDED
@@ -0,0 +1,434 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
|
4
|
+
require 'set'
|
5
|
+
require 'digest'
|
6
|
+
|
7
|
+
require 'autoc'
|
8
|
+
|
9
|
+
|
10
|
+
module AutoC
|
11
|
+
|
12
|
+
|
13
|
+
class Module
|
14
|
+
|
15
|
+
# @private
|
16
|
+
module EntityContainer
|
17
|
+
|
18
|
+
def entities = @entities ||= ::Set.new
|
19
|
+
|
20
|
+
def <<(entity)
|
21
|
+
entities << entity
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
end # EntityContainer
|
26
|
+
|
27
|
+
# @private
|
28
|
+
class Builder < ::Array
|
29
|
+
|
30
|
+
attr_reader :complexity
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
@complexity = 0
|
34
|
+
super
|
35
|
+
end
|
36
|
+
|
37
|
+
def <<(obj)
|
38
|
+
@complexity += (s = obj.to_s).size
|
39
|
+
super(s)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
include EntityContainer
|
45
|
+
|
46
|
+
CAP = "/* Automagically generated by AutoC #{AutoC::VERSION} */"
|
47
|
+
|
48
|
+
attr_reader :name
|
49
|
+
|
50
|
+
attr_accessor :source_count
|
51
|
+
|
52
|
+
attr_accessor :source_threshold
|
53
|
+
|
54
|
+
def initialize(name) = @name = name
|
55
|
+
|
56
|
+
def header = @header ||= Header.new(self)
|
57
|
+
|
58
|
+
def sources = @sources ||= (1..source_count).collect { |i| Source.new(self, i) }
|
59
|
+
|
60
|
+
def digests = @digests ||= State.new(self).read
|
61
|
+
|
62
|
+
def render
|
63
|
+
distribute_entities
|
64
|
+
header.render
|
65
|
+
sources.each(&:render)
|
66
|
+
State.new(self).collect.write
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
def total_entities
|
71
|
+
@total_entities ||= begin
|
72
|
+
set = ::Set.new
|
73
|
+
entities.each { |e| set.merge(e.total_references) }
|
74
|
+
set
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private def distribute_entities
|
79
|
+
header.entities.merge(total_entities)
|
80
|
+
if source_count.nil?
|
81
|
+
@source_count = source_threshold.nil? ? 1 : (total_entities.sum(&:complexity).to_f / source_threshold).ceil
|
82
|
+
end
|
83
|
+
total_entities.each do |e|
|
84
|
+
sources.sort! { |lt, rt| lt.complexity <=> rt.complexity }
|
85
|
+
sources.first << e
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.render(name, &code)
|
90
|
+
m = self.new(name)
|
91
|
+
yield(m) if block_given?
|
92
|
+
m.render
|
93
|
+
end
|
94
|
+
|
95
|
+
end # Module
|
96
|
+
|
97
|
+
|
98
|
+
# @private
|
99
|
+
class Module::State < ::Hash
|
100
|
+
|
101
|
+
attr_reader :module
|
102
|
+
|
103
|
+
def file_name = "#{self.module.name}.state"
|
104
|
+
|
105
|
+
def initialize(m)
|
106
|
+
super
|
107
|
+
@module = m
|
108
|
+
end
|
109
|
+
|
110
|
+
def collect
|
111
|
+
self[self.module.header.file_name] = self.module.header.digest
|
112
|
+
self.module.sources.each { |source| self[source.file_name] = source.digest }
|
113
|
+
self
|
114
|
+
end
|
115
|
+
|
116
|
+
def read
|
117
|
+
if File.exist?(file_name)
|
118
|
+
# It's OK not to have this file but if it exists it must have proper contents
|
119
|
+
io = File.open(file_name, 'rt', chomp: true)
|
120
|
+
begin
|
121
|
+
hash = {}
|
122
|
+
io.readlines.each do |x|
|
123
|
+
raise 'improper state file format' if (/\s*([^\s]+)\s+\*(.*)/ =~ x).nil?
|
124
|
+
hash[$2] = $1
|
125
|
+
end
|
126
|
+
update(hash)
|
127
|
+
ensure
|
128
|
+
io.close
|
129
|
+
end
|
130
|
+
end
|
131
|
+
self
|
132
|
+
end
|
133
|
+
|
134
|
+
def write
|
135
|
+
io = File.open(file_name, 'wt')
|
136
|
+
begin
|
137
|
+
begin
|
138
|
+
each { |file_name, digest| io << "#{digest} *#{file_name}\n" }
|
139
|
+
ensure
|
140
|
+
io.close
|
141
|
+
end
|
142
|
+
rescue
|
143
|
+
File.unlink(file_name) # Delete improperly rendered state file
|
144
|
+
raise
|
145
|
+
end
|
146
|
+
self
|
147
|
+
end
|
148
|
+
|
149
|
+
end # State
|
150
|
+
|
151
|
+
|
152
|
+
# @private
|
153
|
+
class Module::StreamFile < File
|
154
|
+
|
155
|
+
def digest = @digest.hexdigest
|
156
|
+
|
157
|
+
def initialize(*args, **kws)
|
158
|
+
super(*args, **kws)
|
159
|
+
@digest = Digest::MD5.new
|
160
|
+
end
|
161
|
+
|
162
|
+
def <<(data)
|
163
|
+
super(data)
|
164
|
+
@digest.update(data)
|
165
|
+
self
|
166
|
+
end
|
167
|
+
|
168
|
+
end # StreamFile
|
169
|
+
|
170
|
+
|
171
|
+
# @private
|
172
|
+
module Module::SmartRenderer
|
173
|
+
|
174
|
+
# def render_contents(stream)
|
175
|
+
|
176
|
+
attr_reader :digest
|
177
|
+
|
178
|
+
def render
|
179
|
+
io = stream
|
180
|
+
_file_name = io.path # Memorize temporary file name
|
181
|
+
begin
|
182
|
+
begin
|
183
|
+
render_contents(io)
|
184
|
+
@digest = io.digest
|
185
|
+
ensure
|
186
|
+
io.close
|
187
|
+
end
|
188
|
+
rescue
|
189
|
+
File.unlink(_file_name) # Remove improperly rendered temporary file
|
190
|
+
raise
|
191
|
+
else
|
192
|
+
if !File.exist?(file_name) || self.module.digests[file_name] != digest
|
193
|
+
File.rename(_file_name, file_name) # Rendered temporary has different digest - replace original permanent file with it
|
194
|
+
else
|
195
|
+
File.unlink(_file_name) # New temporary has the same digest as permanent - no need to replace the latter, delete the temporary instead
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
end # SmartRenderer
|
201
|
+
|
202
|
+
|
203
|
+
class Module::Header
|
204
|
+
|
205
|
+
include Module::EntityContainer
|
206
|
+
|
207
|
+
include Module::SmartRenderer
|
208
|
+
|
209
|
+
attr_reader :module
|
210
|
+
|
211
|
+
def file_name = @file_name ||= "#{self.module.name}_auto.h"
|
212
|
+
|
213
|
+
def tag = "#{self.module.name}_auto_h".upcase
|
214
|
+
|
215
|
+
def initialize(m) = @module = m
|
216
|
+
|
217
|
+
private
|
218
|
+
|
219
|
+
def render_contents(stream)
|
220
|
+
render_prologue(stream)
|
221
|
+
entities.to_a.sort.each { |e| e.interface.each { |x| stream << x } }
|
222
|
+
render_epilogue(stream)
|
223
|
+
end
|
224
|
+
|
225
|
+
def render_prologue(stream)
|
226
|
+
stream << %{
|
227
|
+
#{Module::CAP}
|
228
|
+
#ifndef #{tag}
|
229
|
+
#define #{tag}
|
230
|
+
}
|
231
|
+
end
|
232
|
+
|
233
|
+
def render_epilogue(stream)
|
234
|
+
stream << %{
|
235
|
+
#endif
|
236
|
+
}
|
237
|
+
end
|
238
|
+
|
239
|
+
def stream = @stream ||= Module::StreamFile.new(file_name+'~', 'wt')
|
240
|
+
|
241
|
+
end # Header
|
242
|
+
|
243
|
+
|
244
|
+
class Module::Source
|
245
|
+
|
246
|
+
include Module::EntityContainer
|
247
|
+
|
248
|
+
include Module::SmartRenderer
|
249
|
+
|
250
|
+
attr_reader :module
|
251
|
+
|
252
|
+
attr_reader :complexity
|
253
|
+
|
254
|
+
attr_reader :index
|
255
|
+
|
256
|
+
def file_name = self.module.source_count < 2 ? "#{self.module.name}_auto.c" : "#{self.module.name}_auto#{index}.c"
|
257
|
+
|
258
|
+
def initialize(m, index)
|
259
|
+
@module = m
|
260
|
+
@complexity = 0
|
261
|
+
@index = index
|
262
|
+
end
|
263
|
+
|
264
|
+
def <<(entity)
|
265
|
+
@complexity += entity.complexity unless entities.include?(entity)
|
266
|
+
super
|
267
|
+
end
|
268
|
+
|
269
|
+
private
|
270
|
+
|
271
|
+
def render_contents(stream)
|
272
|
+
render_prologue(stream)
|
273
|
+
total_entities = ::Set.new
|
274
|
+
entities.each { |e| total_entities.merge(e.total_references) }
|
275
|
+
total_entities.to_a.sort.each { |e| e.forward_declarations.each { |x| stream << x } }
|
276
|
+
entities.to_a.sort.each { |e| e.implementation.each { |x| stream << x } }
|
277
|
+
end
|
278
|
+
|
279
|
+
def render_prologue(stream)
|
280
|
+
stream << %{
|
281
|
+
#{Module::CAP}
|
282
|
+
#include "#{self.module.header.file_name}"
|
283
|
+
}
|
284
|
+
end
|
285
|
+
|
286
|
+
def stream = @stream ||= Module::StreamFile.new(file_name+'~', 'wt')
|
287
|
+
|
288
|
+
end # Source
|
289
|
+
|
290
|
+
|
291
|
+
module Entity
|
292
|
+
|
293
|
+
include ::Comparable
|
294
|
+
|
295
|
+
# A set of the entity's immediate references which, unlike dependencies, do not enforce the entities relative ordering
|
296
|
+
def references = @references ||= ReferenceSet.new
|
297
|
+
|
298
|
+
# Return the entire entity's reference set staring with self
|
299
|
+
def total_references = @total_references ||= collect_references(::Set.new)
|
300
|
+
|
301
|
+
# A set of the entity's immediate dependencies which enforce the entities relative ordering
|
302
|
+
def dependencies = @dependencies ||= DependencySet.new(self)
|
303
|
+
|
304
|
+
# Return the entire entity's dependency set staring with self
|
305
|
+
def total_dependencies = @total_dependencies ||= collect_dependencies(::Set.new)
|
306
|
+
|
307
|
+
protected def collect_references(set)
|
308
|
+
unless set.include?(self)
|
309
|
+
set << self
|
310
|
+
references.each { |x| x.collect_references(set) }
|
311
|
+
end
|
312
|
+
set
|
313
|
+
end
|
314
|
+
|
315
|
+
protected def collect_dependencies(set)
|
316
|
+
unless set.include?(self)
|
317
|
+
set << self
|
318
|
+
dependencies.each { |x| x.collect_dependencies(set) }
|
319
|
+
end
|
320
|
+
set
|
321
|
+
end
|
322
|
+
|
323
|
+
def <=>(other) = position <=> other.position
|
324
|
+
|
325
|
+
# Compute the entity's relative position with respect to its dependencies
|
326
|
+
def position = @position ||= begin
|
327
|
+
p = 0
|
328
|
+
# This code goes into infinite recursion on circular dependency
|
329
|
+
# which must be resolved manually with Entity#references
|
330
|
+
total_dependencies.each do |d|
|
331
|
+
unless equal?(d)
|
332
|
+
dp = d.position
|
333
|
+
p = dp if p < dp # p <- max(p, dp)
|
334
|
+
end
|
335
|
+
end
|
336
|
+
p + 1 # Arrange entity to follow all its dependencies
|
337
|
+
end
|
338
|
+
|
339
|
+
def complexity = forward_declarations.complexity + implementation.complexity # Interface part is not considered as it is shared across the sources
|
340
|
+
|
341
|
+
def interface
|
342
|
+
@interface ||= begin
|
343
|
+
render_interface(stream = Module::Builder.new)
|
344
|
+
stream
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
def forward_declarations
|
349
|
+
@forward_declarations ||= begin
|
350
|
+
render_forward_declarations(stream = Module::Builder.new)
|
351
|
+
stream
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
def implementation
|
356
|
+
@implementation ||= begin
|
357
|
+
render_implementation(stream = Module::Builder.new)
|
358
|
+
stream
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
private
|
363
|
+
|
364
|
+
### Overridable rendering methods
|
365
|
+
|
366
|
+
def render_interface(stream) = nil
|
367
|
+
|
368
|
+
def render_forward_declarations(stream) = nil
|
369
|
+
|
370
|
+
def render_implementation(stream) = nil
|
371
|
+
|
372
|
+
end # Entity
|
373
|
+
|
374
|
+
|
375
|
+
Entity::ReferenceSet = ::Set
|
376
|
+
|
377
|
+
|
378
|
+
# @private
|
379
|
+
class Entity::DependencySet < ::Set
|
380
|
+
|
381
|
+
def initialize(entity)
|
382
|
+
super()
|
383
|
+
@entity = entity
|
384
|
+
end
|
385
|
+
|
386
|
+
def <<(x)
|
387
|
+
@entity.references << x # Each dependency is also registered as a reference
|
388
|
+
super
|
389
|
+
end
|
390
|
+
|
391
|
+
end # DependencySet
|
392
|
+
|
393
|
+
|
394
|
+
# Helper class to represent plain C side code block
|
395
|
+
class Code
|
396
|
+
|
397
|
+
include Entity
|
398
|
+
|
399
|
+
def initialize(interface: nil, implementation: nil, definitions: nil)
|
400
|
+
@interface_ = interface
|
401
|
+
@definitions_ = definitions
|
402
|
+
@implementation_ = implementation
|
403
|
+
end
|
404
|
+
|
405
|
+
def inspect = "... <#{self.class}>"
|
406
|
+
|
407
|
+
private
|
408
|
+
|
409
|
+
def render_interface(stream)
|
410
|
+
stream << @interface_ unless @interface_.nil?
|
411
|
+
end
|
412
|
+
|
413
|
+
def render_implementation(stream)
|
414
|
+
stream << @implementation_ unless @implementation_.nil?
|
415
|
+
end
|
416
|
+
|
417
|
+
def render_forward_declarations(stream)
|
418
|
+
stream << @definitions_ unless @definitions_.nil?
|
419
|
+
end
|
420
|
+
|
421
|
+
end # Code
|
422
|
+
|
423
|
+
|
424
|
+
# Helper class to inject a system-wide header into the C side interface part of the module
|
425
|
+
class SystemHeader < AutoC::Code
|
426
|
+
def initialize(header)
|
427
|
+
super interface: %{
|
428
|
+
#include <#{header}>
|
429
|
+
}
|
430
|
+
end
|
431
|
+
end # SystemHeader
|
432
|
+
|
433
|
+
|
434
|
+
end
|
data/lib/autoc/openmp.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
|
4
|
+
require 'autoc/type'
|
5
|
+
|
6
|
+
|
7
|
+
module AutoC
|
8
|
+
|
9
|
+
|
10
|
+
class Primitive < Type
|
11
|
+
|
12
|
+
def default_create = @default_create ||= -> (target) { copy.(target, 0) }
|
13
|
+
|
14
|
+
def custom_create = @custom_create ||= -> (target, source) { copy.(target, source) }
|
15
|
+
|
16
|
+
def copy = @copy ||= -> (target, source) { "#{target} = #{source}" }
|
17
|
+
|
18
|
+
def equal = @equal ||= -> (lt, rt) { "#{lt} == #{rt}" }
|
19
|
+
|
20
|
+
def compare = @compare ||= -> (lt, rt) { "(#{lt} == #{rt} ? 0 : (#{lt} > #{rt} ? +1 : -1))" }
|
21
|
+
|
22
|
+
def hash_code = @hash_code ||= -> (target) { "(size_t)(#{target})" }
|
23
|
+
|
24
|
+
end # Primitive
|
25
|
+
|
26
|
+
|
27
|
+
end
|