rod 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,72 @@
1
+ module Rod
2
+ # This class allows for lazy fetching the objects from
3
+ # a collection of Rod objects. It holds only a Ruby proc, which
4
+ # called returns the object with given index.
5
+ class CollectionProxy
6
+ include Enumerable
7
+ attr_reader :size
8
+ alias count size
9
+
10
+ # Intializes the proxy with +size+ of the collection
11
+ # and +fetch+ block for retrieving the object from the database.
12
+ def initialize(size,&fetch)
13
+ @size = size
14
+ @original_size = size
15
+ @fetch = fetch
16
+ @appended = []
17
+ raise InvalidArgument.new("Cannot use proxy collection without a block!") unless block_given?
18
+ @proxy = SimpleWeakHash.new
19
+ end
20
+
21
+ # Returns an object with given +index+.
22
+ def [](index)
23
+ return nil if index >= @size
24
+ return @proxy[index] unless @proxy[index].nil?
25
+ rod_id, klass = id_and_class_for(index)
26
+ result = rod_id == 0 ? nil : klass.find_by_rod_id(rod_id)
27
+ @proxy[index] = result
28
+ end
29
+
30
+ # Appends element to the end of the collection.
31
+ def <<(rod_id_and_class)
32
+ @appended << rod_id_and_class
33
+ @size += 1
34
+ end
35
+
36
+ # Simple each implementation.
37
+ def each
38
+ if block_given?
39
+ @size.times do |index|
40
+ yield self[index]
41
+ end
42
+ else
43
+ enum_for(:each)
44
+ end
45
+ end
46
+
47
+ # Iterate over the rod_ids.
48
+ def each_id
49
+ if block_given?
50
+ @size.times do |index|
51
+ yield id_and_class_for(index)[0]
52
+ end
53
+ else
54
+ enum_for(:each_id)
55
+ end
56
+ end
57
+
58
+ # String representation.
59
+ def to_s
60
+ "Proxy:[#{@size}][#{@original_size}]"
61
+ end
62
+
63
+ protected
64
+ def id_and_class_for(index)
65
+ if index >= @original_size && !@appended[index - @original_size].nil?
66
+ @appended[index - @original_size]
67
+ else
68
+ @fetch.call(index)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,32 @@
1
+ module Rod
2
+ VERSION = "0.6.0"
3
+
4
+ # The name of file containing the data base.
5
+ DATABASE_FILE = "database.yml"
6
+
7
+ # Invalid names of fields.
8
+ INVALID_NAMES = {"rod_id" => true}
9
+
10
+ TYPE_MAPPING = {
11
+ :string => 'char *',
12
+ :integer => 'long',
13
+ :float => 'double',
14
+ :ulong => 'unsigned long',
15
+ :object => 'char *'
16
+ }
17
+
18
+ RUBY_TO_C_MAPPING = {
19
+ :string => 'StringValuePtr',
20
+ :integer => 'NUM2LONG',
21
+ :float => 'NUM2DBL',
22
+ :ulong => 'NUM2ULONG'
23
+ }
24
+
25
+ C_TO_RUBY_MAPPING = {
26
+ :string => 'rb_str_new2',
27
+ :integer => 'INT2NUM',
28
+ :float => 'rb_float_new',
29
+ :ulong => 'ULONG2NUM'
30
+ }
31
+
32
+ end
@@ -0,0 +1,598 @@
1
+ require File.join(File.dirname(__FILE__),'constants')
2
+ require 'rod/abstract_database'
3
+
4
+ module Rod
5
+ # This class implements (in C) the Database abstraction defined
6
+ # in Rod::Database.
7
+ #
8
+ # Instance of the class should not be used *as* the database (i.e.
9
+ # not in the macro-style function Rod::Model#database_class).
10
+ # A user should strongly consider subclassing it, since refraining
11
+ # from doing that, will not allow to use different databases for different
12
+ # models simultaneously. This is due to the way RubyInline creates and
13
+ # names (after the name of the class) the C code.
14
+ class Database < AbstractDatabase
15
+ # This flag indicates, if Database and Model works in development
16
+ # mode, i.e. the dynamically loaded library has a unique, different id each time
17
+ # the rod library is used.
18
+ @@rod_development_mode = false
19
+
20
+ # Writer of the +rod_development_mode+ flag.
21
+ def self.development_mode=(value)
22
+ @@rod_development_mode = value
23
+ end
24
+
25
+ # Reader of the +rod_development_mode+ flag.
26
+ def self.development_mode
27
+ @@rod_development_mode
28
+ end
29
+
30
+ protected
31
+
32
+ ## Helper methods printing some generated code ##
33
+
34
+ def model_struct_name(path)
35
+ "model_" + path.gsub(/\W/,"_").squeeze("_")
36
+ end
37
+
38
+ # Initializes the C structures, which are based on the classes.
39
+ def init_structs(classes)
40
+ classes.map do |klass|
41
+ <<-END
42
+ | // number of allocated pages
43
+ | model_p->#{klass.struct_name}_page_count = 0;
44
+ | // the number of allready stored structures
45
+ | model_p->#{klass.struct_name}_count = 0;
46
+ |
47
+ | // initialize the tables with NULL to forbid unmapping
48
+ | model_p->#{klass.struct_name}_table = NULL;
49
+ |
50
+ | // initialize the file descriptor to -1 to force its creation
51
+ | model_p->#{klass.struct_name}_lib_file = -1;
52
+ END
53
+ end.join("\n").margin
54
+ end
55
+
56
+ # Opens the file associated with the class. Creates it if it doesn't
57
+ # exist.
58
+ def open_class_file(klass)
59
+ str =<<-END
60
+ |// create the file unless it exists
61
+ |if(model_p->#{klass.struct_name}_lib_file == -1){
62
+ | char * path = malloc(sizeof(char) * (strlen(model_p->path) +
63
+ | #{klass.path_for_data("").size} + 1));
64
+ | strcpy(path,model_p->path);
65
+ | strcat(path,"#{klass.path_for_data("")}");
66
+ | model_p->#{klass.struct_name}_lib_file =
67
+ | open(path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
68
+ | if(model_p->#{klass.struct_name}_lib_file == -1) {
69
+ | rb_raise(rodException(),"Could not open file for class #{klass} on path %s writing.",path);
70
+ | }
71
+ | free(path);
72
+ |}
73
+ END
74
+ str.margin
75
+ end
76
+
77
+ # Updates the pointer to table of structs for a given +klass+ when
78
+ # the klass is (re)mmaped.
79
+ def update_pointer(klass)
80
+ str =<<-END
81
+ | {
82
+ | VALUE cClass = rb_cObject;
83
+ | #{klass.to_s.split("::").map do |name|
84
+ "cClass = rb_const_get(cClass, rb_intern(\"#{name}\"));"
85
+ end.join("\n| ")}
86
+ | rb_funcall(cClass, rb_intern("rod_pointer="),1,
87
+ | ULONG2NUM((unsigned long)model_p->#{klass.struct_name}_table));
88
+ | }
89
+ END
90
+ str.margin
91
+ end
92
+
93
+ # Mmaps the class to its page during database creation.
94
+ def mmap_class(klass)
95
+ str =<<-END
96
+ | //printf("mmaping #{klass}\\n");
97
+ | //unmap the segment(s) first
98
+ | if(model_p->#{klass.struct_name}_table != NULL){
99
+ | if(munmap(model_p->#{klass.struct_name}_table,
100
+ | page_size()*(model_p->#{klass.struct_name}_page_count)) == -1){
101
+ | perror(NULL);
102
+ | rb_raise(rodException(),"Could not unmap segment for #{klass.struct_name}.");
103
+ | }
104
+ | }
105
+ | \n#{open_class_file(klass)}
106
+ |
107
+ |
108
+ | // exted the file
109
+ |
110
+ | // increase the pages count by 1
111
+ | model_p->#{klass.struct_name}_page_count += ALLOCATED_PAGES;
112
+ |
113
+ | // open the file for writing
114
+ | FILE * #{klass.struct_name}_file =
115
+ | fdopen(model_p->#{klass.struct_name}_lib_file,"w+");
116
+ | if(#{klass.struct_name}_file == NULL){
117
+ | rb_raise(rodException(),"Could not open file for #{klass.struct_name}.");
118
+ | }
119
+ | // seek to the end
120
+ | if(fseek(#{klass.struct_name}_file,0,SEEK_END) == -1){
121
+ | rb_raise(rodException(),"Could not seek to end file for #{klass.struct_name}.");
122
+ | }
123
+ | // write empty data at the end
124
+ | char* #{klass.struct_name}_empty_data = calloc(page_size() * ALLOCATED_PAGES,1);
125
+ | if(write(model_p->#{klass.struct_name}_lib_file,#{klass.struct_name}_empty_data,
126
+ | page_size() * ALLOCATED_PAGES) == -1){
127
+ | rb_raise(rodException(),"Could not write to file for #{klass.struct_name}.");
128
+ | }
129
+ | // seek to the beginning
130
+ | if(fseek(#{klass.struct_name}_file,0,SEEK_SET) == -1){
131
+ | rb_raise(rodException(),"Could not seek to start file for #{klass.struct_name}.");
132
+ | }
133
+ | // mmap the extended file
134
+ | model_p->#{klass.struct_name}_table = mmap(NULL,
135
+ | model_p->#{klass.struct_name}_page_count * page_size(),
136
+ | PROT_WRITE | PROT_READ, MAP_SHARED, model_p->#{klass.struct_name}_lib_file,0);
137
+ | if(model_p->#{klass.struct_name}_table == MAP_FAILED){
138
+ | perror(NULL);
139
+ | rb_raise(rodException(),"Could not mmap segment for #{klass.struct_name}.");
140
+ | }
141
+ |#{update_pointer(klass) unless special_class?(klass)}
142
+ END
143
+ str.margin
144
+ end
145
+
146
+ # Returns true if the class is one of speciall classes
147
+ # (JoinElement, PolymorphicJoinElement, StringElement).
148
+ def special_class?(klass)
149
+ self.class.special_classes.include?(klass)
150
+ end
151
+
152
+ #########################################################################
153
+ # Implementations of abstract methods
154
+ #########################################################################
155
+
156
+ # Generates the code C responsible for management of the database.
157
+ def generate_c_code(path, classes)
158
+ if !@code_generated || @@rod_development_mode
159
+ self.class.inline(:C) do |builder|
160
+ builder.include '<stdlib.h>'
161
+ builder.include '<stdio.h>'
162
+ builder.include '<string.h>'
163
+ builder.include '<fcntl.h>'
164
+ builder.include '<unistd.h>'
165
+ builder.include '<errno.h>'
166
+ builder.include '<sys/mman.h>'
167
+ classes.each do |klass|
168
+ builder.prefix(klass.typedef_struct)
169
+ end
170
+
171
+ builder.prefix("const ALLOCATED_PAGES = 25;")
172
+
173
+ str =<<-END
174
+ |unsigned int page_size(){
175
+ | return sysconf(_SC_PAGE_SIZE);
176
+ |}
177
+ END
178
+ builder.prefix(str.margin)
179
+
180
+ str =<<-END
181
+ |VALUE rodException(){
182
+ | VALUE klass = rb_const_get(rb_cObject, rb_intern("Rod"));
183
+ | klass = rb_const_get(klass, rb_intern("DatabaseError"));
184
+ | return klass;
185
+ |}
186
+ END
187
+ builder.prefix(str.margin)
188
+
189
+
190
+ #########################################
191
+ # Model struct
192
+ #########################################
193
+ model_struct = model_struct_name(path);
194
+ str = <<-END
195
+ |typedef struct {\n
196
+ #{classes.map do |klass|
197
+ <<-SUBEND
198
+ | #{klass.struct_name} * #{klass.struct_name}_table;
199
+ | unsigned long #{klass.struct_name}_page_count;
200
+ | unsigned long #{klass.struct_name}_count;
201
+ | int #{klass.struct_name}_lib_file;
202
+ SUBEND
203
+ end.join("\n|\n")}
204
+ | // the path to the DB
205
+ | char * path;
206
+ |
207
+ |} #{model_struct};
208
+ END
209
+ builder.prefix(str.margin)
210
+
211
+ #########################################
212
+ # Join indices
213
+ #########################################
214
+ str =<<-END
215
+ |VALUE _join_element_index(unsigned long element_offset, unsigned long element_index, VALUE handler){
216
+ | #{model_struct} * model_p;
217
+ | Data_Get_Struct(handler,#{model_struct},model_p);
218
+ | return UINT2NUM((model_p->_join_element_table + element_offset + element_index)->offset);
219
+ |}
220
+ END
221
+ builder.c(str.margin)
222
+
223
+ str =<<-END
224
+ |VALUE _polymorphic_join_element_index(unsigned long element_offset,
225
+ | unsigned long element_index, VALUE handler){
226
+ | #{model_struct} * model_p;
227
+ | Data_Get_Struct(handler,#{model_struct},model_p);
228
+ | return UINT2NUM((model_p->_polymorphic_join_element_table +
229
+ | element_offset + element_index)->offset);
230
+ |}
231
+ END
232
+ builder.c(str.margin)
233
+
234
+ str =<<-END
235
+ |VALUE _polymorphic_join_element_class(unsigned long element_offset,
236
+ | unsigned long element_index, VALUE handler){
237
+ | #{model_struct} * model_p;
238
+ | Data_Get_Struct(handler,#{model_struct},model_p);
239
+ | return UINT2NUM((model_p->_polymorphic_join_element_table +
240
+ | element_offset + element_index)->class);
241
+ |}
242
+ END
243
+ builder.c(str.margin)
244
+
245
+ str =<<-END
246
+ |void _set_join_element_offset(unsigned long element_offset,
247
+ | unsigned long element_index, unsigned long offset,
248
+ | VALUE handler){
249
+ | #{model_struct} * model_p;
250
+ | Data_Get_Struct(handler,#{model_struct},model_p);
251
+ | _join_element * element_p;
252
+ | element_p = model_p->_join_element_table + element_offset + element_index;
253
+ | if(element_p->index != element_index){
254
+ | VALUE eClass = rb_const_get(rb_cObject, rb_intern("Exception"));
255
+ | rb_raise(eClass, "Join element indices are inconsistent: %lu %lu!",
256
+ | element_index, element_p->index);
257
+ | }
258
+ | element_p->offset = offset;
259
+ |}
260
+ END
261
+ builder.c(str.margin)
262
+
263
+ str =<<-END
264
+ |void _set_polymorphic_join_element_offset(unsigned long element_offset,
265
+ | unsigned long element_index, unsigned long offset, unsigned long class_id,
266
+ | VALUE handler){
267
+ | #{model_struct} * model_p;
268
+ | Data_Get_Struct(handler,#{model_struct},model_p);
269
+ | _polymorphic_join_element * element_p;
270
+ | element_p = model_p->_polymorphic_join_element_table + element_offset + element_index;
271
+ | if(element_p->index != element_index){
272
+ | VALUE eClass = rb_const_get(rb_cObject, rb_intern("Exception"));
273
+ | rb_raise(eClass, "Polymorphic join element indices are inconsistent: %lu %lu!",
274
+ | element_index, element_p->index);
275
+ | }
276
+ | element_p->offset = offset;
277
+ | element_p->class = class_id;
278
+ |}
279
+ END
280
+ builder.c(str.margin)
281
+
282
+ str =<<-END
283
+ |unsigned long _allocate_join_elements(VALUE size, VALUE handler){
284
+ | _join_element * element;
285
+ | unsigned long index;
286
+ | #{model_struct} * model_p;
287
+ | Data_Get_Struct(handler,#{model_struct},model_p);
288
+ | unsigned long result = model_p->_join_element_count;
289
+ | for(index = 0; index < size; index++){
290
+ | if(model_p->_join_element_count * sizeof(_join_element) >=
291
+ | page_size() * model_p->_join_element_page_count){
292
+ | \n#{mmap_class(JoinElement)}
293
+ | }
294
+ | element = model_p->_join_element_table + model_p->_join_element_count;
295
+ | model_p->_join_element_count++;
296
+ | element->index = index;
297
+ | element->offset = 0;
298
+ | }
299
+ | return result;
300
+ |}
301
+ END
302
+ builder.c(str.margin)
303
+
304
+ str =<<-END
305
+ |unsigned long _allocate_polymorphic_join_elements(VALUE size, VALUE handler){
306
+ | _polymorphic_join_element * element;
307
+ | unsigned long index;
308
+ | #{model_struct} * model_p;
309
+ | Data_Get_Struct(handler,#{model_struct},model_p);
310
+ | unsigned long result = model_p->_polymorphic_join_element_count;
311
+ | for(index = 0; index < size; index++){
312
+ | if(model_p->_polymorphic_join_element_count *
313
+ | sizeof(_polymorphic_join_element) >=
314
+ | page_size() * model_p->_polymorphic_join_element_page_count){
315
+ | \n#{mmap_class(PolymorphicJoinElement)}
316
+ | }
317
+ | element = model_p->_polymorphic_join_element_table +
318
+ | model_p->_polymorphic_join_element_count;
319
+ | model_p->_polymorphic_join_element_count++;
320
+ | element->index = index;
321
+ | element->offset = 0;
322
+ | element->class = 0;
323
+ | }
324
+ | return result;
325
+ |}
326
+ END
327
+ builder.c(str.margin)
328
+
329
+ #########################################
330
+ # Strings
331
+ #########################################
332
+ str =<<-END
333
+ |VALUE _read_string(unsigned long length, unsigned long offset, VALUE handler){
334
+ | #{model_struct} * model_p;
335
+ | Data_Get_Struct(handler,#{model_struct},model_p);
336
+ | char * str = model_p->#{StringElement.struct_name}_table + offset;
337
+ | return rb_str_new(str, length);
338
+ |}
339
+ END
340
+ builder.c(str.margin)
341
+
342
+ str =<<-END
343
+ |// The first argument is the string to be stored.
344
+ |// The return value is a pair: length and offset.
345
+ |VALUE _set_string(VALUE ruby_value, VALUE handler){
346
+ | #{model_struct} * model_p;
347
+ | Data_Get_Struct(handler,#{model_struct},model_p);
348
+ | unsigned long length = RSTRING_LEN(ruby_value);
349
+ | char * value = RSTRING_PTR(ruby_value);
350
+ | unsigned long string_offset, page_offset, current_page;
351
+ | char * dest;
352
+ | // table:
353
+ | // - address of the first page
354
+ | // page_count:
355
+ | // - during write - number of allocated pages
356
+ | // count:
357
+ | // - total number of bytes
358
+ | long length_left = length;
359
+ | // first free byte in current page
360
+ | string_offset = model_p->#{StringElement.struct_name}_count % page_size();
361
+ | page_offset = model_p->#{StringElement.struct_name}_count / page_size();
362
+ | current_page = page_offset;
363
+ | while(length_left > 0){
364
+ | if(length_left + string_offset >= page_size()){
365
+ | \n#{mmap_class(StringElement)}
366
+ | }
367
+ | dest = model_p->#{StringElement.struct_name}_table +
368
+ | current_page * page_size() + string_offset;
369
+ | if(length_left > page_size()){
370
+ | memcpy(dest,value,page_size());
371
+ | } else {
372
+ | memcpy(dest,value,length_left);
373
+ | }
374
+ | value += page_size();
375
+ | current_page++;
376
+ | length_left -= page_size();
377
+ | }
378
+ |
379
+ | model_p->#{StringElement.struct_name}_count += length;
380
+ |
381
+ | VALUE result = rb_ary_new();
382
+ | rb_ary_push(result, UINT2NUM(length));
383
+ | rb_ary_push(result, UINT2NUM(string_offset + page_offset * page_size()));
384
+ | return result;
385
+ |}
386
+ END
387
+ builder.c(str.margin)
388
+
389
+ #########################################
390
+ # Object accessors
391
+ #########################################
392
+ classes.each do |klass|
393
+ self.class.field_reader("#{klass.struct_name}_count",
394
+ "unsigned long",builder,model_struct)
395
+ self.class.field_writer("#{klass.struct_name}_count",
396
+ "unsigned long",builder,model_struct)
397
+ self.class.field_reader("#{klass.struct_name}_page_count",
398
+ "unsigned long",builder,model_struct)
399
+ self.class.field_writer("#{klass.struct_name}_page_count",
400
+ "unsigned long",builder,model_struct)
401
+ end
402
+
403
+ #########################################
404
+ # Storage
405
+ #########################################
406
+ classes.each do |klass|
407
+ next if special_class?(klass)
408
+ str =<<-END
409
+ |// Store the object in the database.
410
+ |void _store_#{klass.struct_name}(VALUE object, VALUE handler){
411
+ |
412
+ | #{model_struct} * model_p;
413
+ | Data_Get_Struct(handler,#{model_struct},model_p);
414
+ | if((model_p->#{klass.struct_name}_count+1) * sizeof(#{klass.struct_name}) >=
415
+ | model_p->#{klass.struct_name}_page_count * page_size()){
416
+ | \n#{mmap_class(klass)}
417
+ | }
418
+ | #{klass.struct_name} * struct_p = model_p->#{klass.struct_name}_table +
419
+ | model_p->#{klass.struct_name}_count;
420
+ | //printf("struct assigned\\n");
421
+ | model_p->#{klass.struct_name}_count++;
422
+ |
423
+ | //the number is incresed by 1, because 0 indicates that the
424
+ | //(referenced) object is nil
425
+ | struct_p->rod_id = model_p->#{klass.struct_name}_count;
426
+ | rb_iv_set(object, \"@rod_id\",UINT2NUM(struct_p->rod_id));
427
+ |}
428
+ END
429
+ builder.c(str.margin)
430
+ end
431
+
432
+ #########################################
433
+ # init handler
434
+ #########################################
435
+ str = <<-END
436
+ |VALUE _init_handler(char * dir_path){
437
+ | #{model_struct} * model_p;
438
+ | model_p = ALLOC(#{model_struct});
439
+ |
440
+ | #{init_structs(classes)}
441
+ |
442
+ | // set dir path
443
+ | model_p->path = malloc(sizeof(char)*(strlen(dir_path)+1));
444
+ | strcpy(model_p->path,dir_path);
445
+ |
446
+ | //create the wrapping object
447
+ | VALUE cClass = rb_define_class("#{model_struct_name(path).camelcase(true)}",
448
+ | rb_cObject);
449
+ | return Data_Wrap_Struct(cClass, 0, free, model_p);
450
+ |}
451
+ END
452
+ builder.c(str.margin)
453
+
454
+ #########################################
455
+ # create
456
+ #########################################
457
+ str = <<-END
458
+ |void _create(VALUE handler){
459
+ | #{model_struct} * model_p;
460
+ | Data_Get_Struct(handler,#{model_struct},model_p);
461
+ |
462
+ | //mmap the structures
463
+ | \n#{classes.map{|klass| mmap_class(klass)}.join("\n|\n")}
464
+ |}
465
+ END
466
+ builder.c(str.margin)
467
+
468
+ #########################################
469
+ # open
470
+ #########################################
471
+ str =<<-END
472
+ |void _open(VALUE handler){
473
+ | #{model_struct} * model_p;
474
+ | Data_Get_Struct(handler,#{model_struct},model_p);
475
+ |
476
+ | \n#{classes.map do |klass|
477
+ <<-SUBEND
478
+ | model_p->#{klass.struct_name}_lib_file = -1;
479
+ |
480
+ | if(model_p->#{klass.struct_name}_page_count > 0){
481
+ | \n#{open_class_file(klass)}
482
+ | if((model_p->#{klass.struct_name}_table = mmap(NULL,
483
+ | model_p->#{klass.struct_name}_page_count * page_size(), PROT_WRITE | PROT_READ,
484
+ | MAP_SHARED, model_p->#{klass.struct_name}_lib_file, 0)) == MAP_FAILED){
485
+ | perror(NULL);
486
+ | rb_raise(rodException(),"Could not mmap class '#{klass}'.");
487
+ | }
488
+ | #{update_pointer(klass) unless special_class?(klass)}
489
+ | } else {
490
+ | model_p->#{klass.struct_name}_table = NULL;
491
+ | }
492
+ SUBEND
493
+ end.join("\n")}
494
+ |}
495
+ END
496
+ builder.c(str.margin)
497
+
498
+ #########################################
499
+ # close
500
+ #########################################
501
+ str =<<-END
502
+ |// if +classes+ are Qnil, the DB was open in readonly mode.
503
+ |void _close(VALUE handler){
504
+ | #{model_struct} * model_p;
505
+ | Data_Get_Struct(handler,#{model_struct},model_p);
506
+ |
507
+ | \n#{classes.map do |klass|
508
+ <<-SUBEND
509
+ | if(model_p->#{klass.struct_name}_table != NULL){
510
+ | if(munmap(model_p->#{klass.struct_name}_table,
511
+ | page_size() * model_p->#{klass.struct_name}_page_count) == -1){
512
+ | rb_raise(rodException(),"Could not unmap #{klass.struct_name}.");
513
+ | }
514
+ | }
515
+ | if(close(model_p->#{klass.struct_name}_lib_file) == -1){
516
+ | rb_raise(rodException(),"Could not close model file for #{klass}.");
517
+ | }
518
+ SUBEND
519
+ end.join("\n")}
520
+ |}
521
+ END
522
+ builder.c(str.margin)
523
+
524
+
525
+ #########################################
526
+ # Utilities
527
+ #########################################
528
+ str = <<-END
529
+ |void _print_layout(VALUE handler){
530
+ | #{model_struct} * model_p;
531
+ | Data_Get_Struct(handler,#{model_struct},model_p);
532
+ | printf("============= Data layout START =============\\n");
533
+ | \n#{classes.map do |klass|
534
+ str =<<-SUBEND
535
+ | printf("-- #{klass} --\\n");
536
+ | printf("Size of #{klass.struct_name} %lu\\n",(unsigned long)sizeof(#{klass.struct_name}));
537
+ | \n#{klass.layout}
538
+ | printf("Page count: %lu, count %lu, pointer: %lx\\n",
539
+ | model_p->#{klass.struct_name}_page_count,
540
+ | model_p->#{klass.struct_name}_count,
541
+ | (unsigned long)model_p->#{klass.struct_name}_table);
542
+ SUBEND
543
+ str.margin
544
+ end.join("\n")}
545
+ | printf("============= Data layout END =============\\n");
546
+ |}
547
+ END
548
+ builder.c(str.margin)
549
+
550
+ str =<<-END
551
+ |void _print_system_error(){
552
+ | perror(NULL);
553
+ |}
554
+ END
555
+ builder.c(str.margin)
556
+
557
+ str =<<-END
558
+ |unsigned int _page_size(){
559
+ | return page_size();
560
+ |}
561
+ END
562
+ builder.c(str.margin)
563
+
564
+ if @@rod_development_mode
565
+ # This method is created to force rebuild of the C code, since
566
+ # it is rebuild on the basis of methods' signatures change.
567
+ builder.c_singleton("void __unused_method_#{rand(1000)}(){}")
568
+ end
569
+ end
570
+ @code_generated = true
571
+ end
572
+ end
573
+
574
+ # Reads the value of a specified field of the C-structure.
575
+ def self.field_reader(name,result_type,builder,model_struct)
576
+ str =<<-END
577
+ |#{result_type} _#{name}(VALUE handler){
578
+ | #{model_struct} * model_p;
579
+ | Data_Get_Struct(handler,#{model_struct},model_p);
580
+ | return model_p->#{name};
581
+ |}
582
+ END
583
+ builder.c(str.margin)
584
+ end
585
+
586
+ # Writes the value of a specified field of the C-structure.
587
+ def self.field_writer(name,arg_type,builder,model_struct)
588
+ str =<<-END
589
+ |void _#{name}_equals(VALUE handler,#{arg_type} value){
590
+ | #{model_struct} * model_p;
591
+ | Data_Get_Struct(handler,#{model_struct},model_p);
592
+ | model_p->#{name} = value;
593
+ |}
594
+ END
595
+ builder.c(str.margin)
596
+ end
597
+ end
598
+ end