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.
Files changed (110) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES.md +3 -0
  3. data/README.md +149 -0
  4. data/cmake/AutoC.cmake +39 -0
  5. data/lib/autoc/allocators.rb +51 -0
  6. data/lib/autoc/association.rb +126 -0
  7. data/lib/autoc/box.rb +311 -0
  8. data/lib/autoc/cmake.rb +54 -0
  9. data/lib/autoc/collection.rb +83 -110
  10. data/lib/autoc/composite.rb +333 -0
  11. data/lib/autoc/cstring.rb +263 -0
  12. data/lib/autoc/function.rb +247 -0
  13. data/lib/autoc/hash_map.rb +328 -0
  14. data/lib/autoc/hash_set.rb +339 -0
  15. data/lib/autoc/hashers.rb +102 -0
  16. data/lib/autoc/list.rb +444 -0
  17. data/lib/autoc/module.rb +434 -0
  18. data/lib/autoc/openmp.rb +15 -0
  19. data/lib/autoc/primitive.rb +27 -0
  20. data/lib/autoc/ranges.rb +707 -0
  21. data/lib/autoc/record.rb +247 -0
  22. data/lib/autoc/scaffold/docs.rb +117 -0
  23. data/lib/autoc/scaffold/generic_value.rb +86 -0
  24. data/lib/autoc/scaffold/project.rb +75 -0
  25. data/lib/autoc/scaffold/test_cstring.rb +113 -0
  26. data/lib/autoc/scaffold/test_cstring_hash_set.rb +35 -0
  27. data/lib/autoc/scaffold/test_int_box.rb +22 -0
  28. data/lib/autoc/scaffold/test_int_hash_set.rb +448 -0
  29. data/lib/autoc/scaffold/test_int_list.rb +106 -0
  30. data/lib/autoc/scaffold/test_int_vector.rb +83 -0
  31. data/lib/autoc/scaffold/test_v2v_hash_map.rb +83 -0
  32. data/lib/autoc/scaffold/test_value_hash_set.rb +60 -0
  33. data/lib/autoc/scaffold/test_value_vector.rb +146 -0
  34. data/{test/test.rb → lib/autoc/scaffold/tests.rb} +179 -158
  35. data/lib/autoc/scaffold.rb +12 -0
  36. data/lib/autoc/sequential.rb +99 -0
  37. data/lib/autoc/set.rb +331 -0
  38. data/lib/autoc/std.rb +149 -0
  39. data/lib/autoc/type.rb +93 -531
  40. data/lib/autoc/vector.rb +290 -0
  41. data/lib/autoc.rb +4 -35
  42. metadata +55 -85
  43. data/.yardopts +0 -4
  44. data/CHANGES +0 -23
  45. data/README +0 -28
  46. data/doc/AutoC/Code.html +0 -523
  47. data/doc/AutoC/Collection.html +0 -1214
  48. data/doc/AutoC/HashMap.html +0 -1441
  49. data/doc/AutoC/HashSet.html +0 -916
  50. data/doc/AutoC/Iterators/Bidirectional.html +0 -204
  51. data/doc/AutoC/Iterators/Unidirectional.html +0 -200
  52. data/doc/AutoC/Iterators.html +0 -126
  53. data/doc/AutoC/List.html +0 -1039
  54. data/doc/AutoC/Maps.html +0 -290
  55. data/doc/AutoC/Module/File.html +0 -415
  56. data/doc/AutoC/Module/Header.html +0 -437
  57. data/doc/AutoC/Module/Source.html +0 -707
  58. data/doc/AutoC/Module.html +0 -948
  59. data/doc/AutoC/Priority.html +0 -138
  60. data/doc/AutoC/Queue.html +0 -1172
  61. data/doc/AutoC/Reference.html +0 -735
  62. data/doc/AutoC/Sets.html +0 -520
  63. data/doc/AutoC/String.html +0 -1394
  64. data/doc/AutoC/TreeMap.html +0 -1565
  65. data/doc/AutoC/TreeSet.html +0 -1447
  66. data/doc/AutoC/Type.html +0 -2148
  67. data/doc/AutoC/UserDefinedType.html +0 -1047
  68. data/doc/AutoC/Vector.html +0 -987
  69. data/doc/AutoC.html +0 -331
  70. data/doc/_index.html +0 -388
  71. data/doc/class_list.html +0 -51
  72. data/doc/css/common.css +0 -1
  73. data/doc/css/full_list.css +0 -58
  74. data/doc/css/style.css +0 -481
  75. data/doc/file.CHANGES.html +0 -117
  76. data/doc/file.README.html +0 -116
  77. data/doc/file_list.html +0 -61
  78. data/doc/frames.html +0 -17
  79. data/doc/index.html +0 -116
  80. data/doc/js/app.js +0 -243
  81. data/doc/js/full_list.js +0 -216
  82. data/doc/js/jquery.js +0 -4
  83. data/doc/method_list.html +0 -1307
  84. data/doc/top-level-namespace.html +0 -112
  85. data/lib/autoc/code.rb +0 -237
  86. data/lib/autoc/collection/hash_map.rb +0 -385
  87. data/lib/autoc/collection/hash_set.rb +0 -337
  88. data/lib/autoc/collection/iterator.rb +0 -39
  89. data/lib/autoc/collection/list.rb +0 -429
  90. data/lib/autoc/collection/map.rb +0 -41
  91. data/lib/autoc/collection/queue.rb +0 -517
  92. data/lib/autoc/collection/set.rb +0 -134
  93. data/lib/autoc/collection/tree_map.rb +0 -464
  94. data/lib/autoc/collection/tree_set.rb +0 -611
  95. data/lib/autoc/collection/vector.rb +0 -336
  96. data/lib/autoc/string.rb +0 -492
  97. data/test/test_auto.c +0 -7141
  98. data/test/test_auto.h +0 -753
  99. data/test/test_char_string.rb +0 -270
  100. data/test/test_int_list.rb +0 -35
  101. data/test/test_int_tree_set.rb +0 -111
  102. data/test/test_int_vector.rb +0 -34
  103. data/test/test_value_hash_map.rb +0 -162
  104. data/test/test_value_hash_set.rb +0 -173
  105. data/test/test_value_list.rb +0 -193
  106. data/test/test_value_queue.rb +0 -275
  107. data/test/test_value_tree_map.rb +0 -176
  108. data/test/test_value_tree_set.rb +0 -173
  109. data/test/test_value_vector.rb +0 -155
  110. data/test/value.rb +0 -80
@@ -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
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ require 'autoc/module'
5
+
6
+
7
+ module AutoC
8
+
9
+ OMP_H = Code.new interface: %{
10
+ #ifdef _OPENMP
11
+ #include <omp.h>
12
+ #endif
13
+ }
14
+
15
+ end
@@ -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