fast_method_source 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5d4abbc77bfa1ddd3f7d8c335e4ed45de99d1d6f
4
- data.tar.gz: 412abc3f1f3278f2a25041e3dcfc689e4c00b83d
3
+ metadata.gz: a652f4b019d35eaf42c337bed8e5a556cefaf8bc
4
+ data.tar.gz: c6dd63e38ed0542570e7bc395a1f798341021c6d
5
5
  SHA512:
6
- metadata.gz: 15c8a178256a9f168e2a2bf49a0f7a2dcba1a968664c1887d642de15685bf446d0b020eceb8fc322a1bb9e3172c158c2b28c3dc294ac8e46cc8c2406e7e479e6
7
- data.tar.gz: 2930a5f50f0cf4d7b8745d0b44ca377a312cd06bdde2944ba38686fe782c7ec1fb0d232be6dd535e547aa4214a9f8528734882ed9d9820becf4a255e2c66c20d
6
+ metadata.gz: 4194e5d174e2d5c4ff5699b20bda1ee9676edc224a05b6bd255e3f73dc723329a08468e6e5839283e1136271b1f2c7d68a83cda5979d5aaa0be714dec0e6ec45
7
+ data.tar.gz: 67b9991bff995852cba78548c5fd8aca9886f353f3ce90fdc34e78387ef25c7564102335a36f4d3263bf00eaca9865ceca0dd8f62a483fdd6df58a0dcaad2bad
data/CHANGELOG.md CHANGED
@@ -1,6 +1,12 @@
1
1
  Fast Method Source changelog
2
2
  ============================
3
3
 
4
+ ### v0.3.0 (June 11, 2015)
5
+
6
+ * _Significantly_ reduced memory consumption (`#comment_and_source` for 19K
7
+ methods uses about 100-150 MB of RES RAM)
8
+ * _Significantly_ decreased time of calculations
9
+
4
10
  ### v0.2.0 (June 11, 2015)
5
11
 
6
12
  * Significantly reduced memory consumption
data/README.md CHANGED
@@ -65,7 +65,7 @@ Platform: ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]
65
65
  Counting the number of sample methods...
66
66
  Sample methods: 19438
67
67
  user system total real
68
- FastMethodSource#comment_and_source_for 26.050000 1.420000 27.470000 ( 30.528066)
68
+ FastMethodSource#comment_and_source_for 16.240000 1.180000 17.420000 ( 19.439981)
69
69
  ```
70
70
 
71
71
  #### #source
@@ -75,33 +75,32 @@ FastMethodSource#comment_and_source_for 26.050000 1.420000 27.470000 ( 30.528
75
75
  Processor: Intel(R) Core(TM) i5-2410M CPU @ 2.30GHz
76
76
  Platform: ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]
77
77
  Counting the number of sample methods...
78
- Sample methods: 19596
79
- Rehearsal ------------------------------------------------------------
80
- FastMethodSource#comment 4.730000 0.300000 5.030000 ( 5.590186)
81
- MethodSource#comment 73.660000 0.340000 74.000000 ( 89.475399)
82
- -------------------------------------------------- total: 79.030000sec
78
+ Sample methods: 19438
79
+ Rehearsal -----------------------------------------------------------
80
+ FastMethodSource#source 14.220000 0.880000 15.100000 ( 16.844189)
81
+ MethodSource#source 104.140000 0.420000 104.560000 (126.567209)
82
+ ------------------------------------------------ total: 119.660000sec
83
83
 
84
- user system total real
85
- FastMethodSource#comment 4.450000 0.300000 4.750000 ( 5.278761)
86
- MethodSource#comment 69.880000 0.110000 69.990000 ( 77.663383)
84
+ user system total real
85
+ FastMethodSource#source 14.920000 0.890000 15.810000 ( 17.658905)
86
+ MethodSource#source 96.860000 0.410000 97.270000 (108.131119)
87
87
  ```
88
88
 
89
89
  #### #comment
90
90
  ##### ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]
91
91
 
92
92
  ```
93
- Processor: Intel(R) Core(TM) i5-2410M CPU @ 2.30GHz
94
93
  Platform: ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]
95
94
  Counting the number of sample methods...
96
- Sample methods: 19438
97
- Rehearsal -----------------------------------------------------------
98
- FastMethodSource#source 20.610000 1.290000 21.900000 ( 24.341358)
99
- MethodSource#source 92.730000 0.470000 93.200000 (111.384362)
100
- ------------------------------------------------ total: 115.100000sec
95
+ Sample methods: 19596
96
+ Rehearsal ------------------------------------------------------------
97
+ FastMethodSource#comment 1.790000 0.210000 2.000000 ( 2.229802)
98
+ MethodSource#comment 85.020000 0.370000 85.390000 (103.061652)
99
+ -------------------------------------------------- total: 87.390000sec
101
100
 
102
- user system total real
103
- FastMethodSource#source 20.990000 1.150000 22.140000 ( 24.612721)
104
- MethodSource#source 86.390000 0.290000 86.680000 ( 96.241494)
101
+ user system total real
102
+ FastMethodSource#comment 1.620000 0.250000 1.870000 ( 2.072023)
103
+ MethodSource#comment 84.560000 0.320000 84.880000 ( 94.465574)
105
104
  ```
106
105
 
107
106
  ### Correctness of output
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.0
@@ -19,145 +19,180 @@ static const char *null_filename = "/dev/null";
19
19
  #define DUP2(fd, newfd) dup2(fd, newfd)
20
20
  #endif
21
21
 
22
- #define MAXLINES 600
23
- #define MAXLINELEN 90
24
- #define COMMENT_SIZE 1000
22
+ #define EXPRESSION_SIZE 80 * 50
23
+
25
24
  #define SAFE_CHAR 'z'
26
25
 
27
26
  typedef struct {
28
- int forward : 1;
29
- int backward : 1;
30
- } read_order;
27
+ int source : 1;
28
+ int comment : 1;
29
+ } finder;
31
30
 
32
- struct filebuf {
31
+ struct method_data {
33
32
  unsigned method_location;
34
33
  const char *filename;
35
34
  VALUE method_name;
36
- char **lines;
37
- unsigned relevant_lines;
38
35
  };
39
36
 
40
- struct retval {
41
- VALUE val;
42
- VALUE method_name;
43
- };
44
-
45
- static void read_lines(read_order order, struct filebuf *filebuf);
46
- static void read_lines_before(struct filebuf *filebuf);
47
- static void read_lines_after(struct filebuf *filebuf);
48
- static void reallocate_filebuf(char **lines[], unsigned rl_len);
49
- static void reallocate_linebuf(char **linebuf, const unsigned cl_len);
50
- static VALUE find_source(struct filebuf *filebuf);
51
- static VALUE find_comment(struct filebuf *filebuf);
52
- static VALUE mMethodExtensions_source(VALUE self);
37
+ static VALUE read_lines(finder finder, struct method_data *data);
38
+ static VALUE read_lines_before(struct method_data *data);
39
+ static VALUE read_lines_after(struct method_data *data);
40
+ static VALUE find_method_comment(struct method_data *data);
41
+ static VALUE find_method_source(struct method_data *data);
53
42
  static NODE *parse_expr(VALUE rb_str);
54
43
  static NODE *parse_with_silenced_stderr(VALUE rb_str);
55
44
  static void filter_interp(char *line);
56
- static char **allocate_memory_for_file(void);
57
- static void free_memory_for_file(char **file[], const unsigned relevant_lines_n);
58
45
  static int contains_end_kw(const char *line);
59
46
  static int is_comment(const char *line, const size_t line_len);
60
47
  static int is_static_definition(const char *line);
61
48
  static int is_accessor(const char *line);
62
49
  static int is_dangling_literal_end(const char *line);
63
50
  static int is_dangling_literal_begin(const char *line);
64
- static void strnprep(char *s, const char *t, size_t len);
65
51
  static void raise_if_nil(VALUE val, VALUE method_name);
66
- static VALUE raise_if_nil_safe(VALUE args);
67
- static void realloc_comment(char **comment, unsigned len);
68
- static void filebuf_init(VALUE self, struct filebuf *filebuf);
69
- static void free_filebuf(VALUE retval, struct filebuf *filebuf);
52
+ static void realloc_expression(char **expression, size_t len);
53
+ static void method_data_init(VALUE self, struct method_data *data);
54
+ static VALUE mMethodExtensions_source(VALUE self);
70
55
 
71
56
  static VALUE rb_eSourceNotFoundError;
72
57
 
73
- static void
74
- read_lines_after(struct filebuf *filebuf)
58
+ static VALUE
59
+ find_method_source(struct method_data *data)
75
60
  {
76
- read_order order = {1, 0};
77
- read_lines(order, filebuf);
61
+ return read_lines_after(data);
78
62
  }
79
63
 
80
- static void
81
- read_lines_before(struct filebuf *filebuf)
64
+ static VALUE
65
+ find_method_comment(struct method_data *data)
82
66
  {
83
- read_order order = {0, 1};
84
- read_lines(order, filebuf);
67
+ return read_lines_before(data);
85
68
  }
86
69
 
87
- static void
88
- read_lines(read_order order, struct filebuf *filebuf)
70
+ static VALUE
71
+ read_lines_after(struct method_data *data)
72
+ {
73
+ finder finder = {1, 0};
74
+ return read_lines(finder, data);
75
+ }
76
+
77
+ static VALUE
78
+ read_lines_before(struct method_data *data)
79
+ {
80
+ finder finder = {0, 1};
81
+ return read_lines(finder, data);
82
+ }
83
+
84
+ static VALUE
85
+ read_lines(finder finder, struct method_data *data)
89
86
  {
90
87
  FILE *fp;
91
88
 
92
- if ((fp = fopen(filebuf->filename, "r")) == NULL) {
93
- rb_raise(rb_eIOError, "No such file or directory - %s", filebuf->filename);
89
+ if ((fp = fopen(data->filename, "r")) == NULL) {
90
+ rb_raise(rb_eIOError, "No such file or directory - %s", data->filename);
94
91
  }
95
92
 
96
93
  ssize_t cl_len;
94
+ VALUE rb_expr;
95
+
96
+ size_t bufsize, parse_bufsize, future_bufsize, future_parse_bufsize,
97
+ current_linebuf_size, line_count;
98
+
99
+ bufsize = parse_bufsize = EXPRESSION_SIZE;
100
+ line_count = current_linebuf_size = 0;
101
+
102
+ int should_parse, dangling_literal, found_expression;
103
+ should_parse = dangling_literal = found_expression = 0;
104
+
105
+ char *expression = ALLOC_N(char, bufsize);
106
+ expression[0] = '\0';
107
+
108
+ char *parse_expression = ALLOC_N(char, bufsize);
109
+ parse_expression[0] = '\0';
97
110
 
98
111
  char *current_line = NULL;
99
- char **current_linebuf = NULL;
100
- size_t current_linebuf_size = 0;
101
- unsigned rl_n = 0;
102
- unsigned line_count = 0;
103
112
 
104
113
  while ((cl_len = getline(&current_line, &current_linebuf_size, fp)) != -1) {
105
114
  line_count++;
106
- if (order.forward) {
107
- if (line_count < filebuf->method_location) {
108
- continue;
115
+
116
+ if (finder.source && line_count >= data->method_location) {
117
+ future_bufsize = strlen(expression) + cl_len;
118
+ if (future_bufsize >= bufsize) {
119
+ bufsize = future_bufsize + EXPRESSION_SIZE + 1;
120
+ realloc_expression(&expression, bufsize);
109
121
  }
110
- } else if (order.backward) {
111
- if (line_count > filebuf->method_location) {
112
- break;
122
+ strncat(expression, current_line, cl_len);
123
+
124
+ if (current_line[0] == '\n')
125
+ continue;
126
+
127
+ if (line_count == data->method_location) {
128
+ if (is_static_definition(current_line) || is_accessor(current_line)) {
129
+ should_parse = 1;
130
+ }
113
131
  }
114
- }
115
132
 
116
- if ((rl_n != 0) && (rl_n % (MAXLINES-1) == 0)) {
117
- reallocate_filebuf(&filebuf->lines, rl_n);
118
- }
133
+ if (is_comment(current_line, cl_len))
134
+ continue;
119
135
 
120
- current_linebuf = &(filebuf->lines)[rl_n];
136
+ if (is_dangling_literal_end(current_line)) {
137
+ dangling_literal = 0;
138
+ } else if (is_dangling_literal_begin(current_line)) {
139
+ dangling_literal = 1;
140
+ } else if (dangling_literal) {
141
+ continue;
142
+ }
121
143
 
122
- if (cl_len >= MAXLINELEN) {
123
- reallocate_linebuf(current_linebuf, cl_len);
144
+ filter_interp(current_line);
145
+ future_parse_bufsize = strlen(parse_expression) + cl_len;
146
+ if (future_parse_bufsize >= parse_bufsize) {
147
+ parse_bufsize = future_parse_bufsize + EXPRESSION_SIZE + 1;
148
+ realloc_expression(&parse_expression, parse_bufsize);
149
+ }
150
+ strncat(parse_expression, current_line, cl_len);
151
+
152
+ if (should_parse || contains_end_kw(current_line)) {
153
+ if (parse_expr(rb_str_new2(parse_expression)) != NULL) {
154
+ found_expression = 1;
155
+ break;
156
+ }
157
+ }
158
+ } else if (finder.comment) {
159
+ if (line_count < data->method_location) {
160
+ if (is_comment(current_line, cl_len)) {
161
+ future_bufsize = strlen(expression) + cl_len;
162
+ if (future_bufsize >= bufsize) {
163
+ bufsize = future_bufsize + EXPRESSION_SIZE + 1;
164
+ realloc_expression(&expression, bufsize);
165
+ }
166
+ strncat(expression, current_line, cl_len);
167
+ } else {
168
+ expression[0] = '\0';
169
+ bufsize = EXPRESSION_SIZE;
170
+ }
171
+ } else if (line_count == data->method_location) {
172
+ found_expression = 1;
173
+ break;
174
+ }
124
175
  }
176
+ }
125
177
 
126
- strncpy(*current_linebuf, current_line, cl_len);
127
- (*current_linebuf)[cl_len] = '\0';
128
- rl_n++;
178
+ if (found_expression) {
179
+ rb_expr = rb_str_new2(expression);
180
+ } else {
181
+ rb_expr = Qnil;
129
182
  }
130
183
 
184
+ xfree(parse_expression);
185
+ xfree(expression);
131
186
  free(current_line);
132
187
  fclose(fp);
133
- filebuf->relevant_lines = rl_n;
134
- }
135
-
136
- static void
137
- reallocate_linebuf(char **linebuf, const unsigned cl_len)
138
- {
139
- char *tmp_line = REALLOC_N(*linebuf, char, cl_len + 1);
140
- *linebuf = tmp_line;
141
- }
142
-
143
- static void
144
- reallocate_filebuf(char **lines[], unsigned rl_len)
145
- {
146
- unsigned new_size = rl_len + MAXLINES + 1;
147
- char **temp_lines = REALLOC_N(*lines, char *, new_size);
148
-
149
- *lines = temp_lines;
150
-
151
- for (int i = 0; i < MAXLINES; i++) {
152
- (*lines)[rl_len + i] = ALLOC_N(char, MAXLINELEN);
153
- }
188
+ return (rb_expr);
154
189
  }
155
190
 
156
191
  static void
157
- realloc_comment(char **comment, unsigned len)
192
+ realloc_expression(char **expression, size_t len)
158
193
  {
159
- char *tmp_comment = REALLOC_N(*comment, char, len);
160
- *comment = tmp_comment;
194
+ char *tmp_comment = REALLOC_N(*expression, char, len);
195
+ *expression = tmp_comment;
161
196
  }
162
197
 
163
198
  static NODE *
@@ -282,160 +317,6 @@ is_dangling_literal_begin(const char *line)
282
317
  return strstr(line, "%{") != NULL && strstr(line, "}") == NULL;
283
318
  }
284
319
 
285
- static VALUE
286
- find_source(struct filebuf *filebuf)
287
- {
288
- VALUE rb_expr;
289
-
290
- const unsigned expr_size = filebuf->relevant_lines * MAXLINELEN;
291
- char *expr = ALLOC_N(char, expr_size);
292
- expr[0] = '\0';
293
- char *parseable_expr = ALLOC_N(char, expr_size);
294
- parseable_expr[0] = '\0';
295
-
296
- int l = 0;
297
- while (filebuf->lines[l][0] == '\n') {
298
- l++;
299
- continue;
300
- }
301
- char *first_line = (filebuf->lines)[l];
302
-
303
- char *current_line = NULL;
304
- int should_parse = 0;
305
- int dangling_literal = 0;
306
- size_t current_line_len;
307
-
308
- if (is_static_definition(first_line) || is_accessor(first_line)) {
309
- should_parse = 1;
310
- }
311
-
312
- for (unsigned i = l; i < filebuf->relevant_lines; i++) {
313
- current_line = filebuf->lines[i];
314
- current_line_len = strlen(current_line);
315
-
316
- strncat(expr, current_line, current_line_len);
317
-
318
- if (is_comment(current_line, current_line_len))
319
- continue;
320
-
321
- if (is_dangling_literal_end(current_line)) {
322
- dangling_literal = 0;
323
- } else if (is_dangling_literal_begin(current_line)) {
324
- dangling_literal = 1;
325
- } else if (dangling_literal) {
326
- continue;
327
- }
328
-
329
- filter_interp(current_line);
330
- strncat(parseable_expr, current_line, current_line_len);
331
-
332
- if (should_parse || contains_end_kw(current_line)) {
333
- if (parse_expr(rb_str_new2(parseable_expr)) != NULL) {
334
- rb_expr = rb_str_new2(expr);
335
- xfree(expr);
336
- xfree(parseable_expr);
337
- return rb_expr;
338
- }
339
- }
340
- }
341
-
342
- xfree(expr);
343
- xfree(parseable_expr);
344
-
345
- return Qnil;
346
- }
347
-
348
- static void
349
- strnprep(char *s, const char *t, size_t len)
350
- {
351
- size_t i;
352
-
353
- memmove(s + len, s, strlen(s) + 1);
354
-
355
- for (i = 0; i < len; ++i) {
356
- s[i] = t[i];
357
- }
358
- }
359
-
360
- static VALUE
361
- find_comment(struct filebuf *filebuf)
362
- {
363
- size_t comment_len;
364
- size_t current_line_len;
365
- size_t future_bufsize;
366
- char *current_line = NULL;
367
- VALUE rb_comment;
368
-
369
- unsigned long bufsize = COMMENT_SIZE;
370
- char *comment = ALLOC_N(char, COMMENT_SIZE);
371
- comment[0] = '\0';
372
-
373
- int i = filebuf->method_location - 2;
374
-
375
- while (filebuf->lines[i][0] == '\n') {
376
- i--;
377
- continue;
378
- }
379
-
380
- if (!is_comment(filebuf->lines[i], strlen(filebuf->lines[i]))) {
381
- return rb_str_new("", 0);
382
- } else {
383
- while ((current_line = filebuf->lines[i]) &&
384
- is_comment(current_line, (current_line_len = strlen(current_line)))) {
385
- comment_len = strlen(comment);
386
- future_bufsize = comment_len + current_line_len;
387
-
388
- if (future_bufsize >= bufsize) {
389
- bufsize = future_bufsize + COMMENT_SIZE + 1;
390
- realloc_comment(&comment, bufsize);
391
- }
392
- strnprep(comment, current_line, current_line_len);
393
- i--;
394
- }
395
-
396
- rb_comment = rb_str_new2(comment);
397
- xfree(comment);
398
- return rb_comment;
399
- }
400
-
401
- xfree(comment);
402
- free_memory_for_file(&filebuf->lines, filebuf->relevant_lines);
403
- return Qnil;
404
- }
405
-
406
- static char **
407
- allocate_memory_for_file(void)
408
- {
409
- char **file = ALLOC_N(char *, MAXLINES);
410
-
411
- for (int i = 0; i < MAXLINES; i++) {
412
- file[i] = ALLOC_N(char, MAXLINELEN);
413
- }
414
-
415
- return file;
416
- }
417
-
418
- static void
419
- free_memory_for_file(char **file[], const unsigned relevant_lines_n)
420
- {
421
- int lines_to_free = relevant_lines_n >= MAXLINES ? relevant_lines_n : MAXLINES;
422
-
423
- for (int i = 0; i < lines_to_free; i++) {
424
- xfree((*file)[i]);
425
- }
426
-
427
- xfree(*file);
428
- }
429
-
430
- static VALUE
431
- raise_if_nil_safe(VALUE args)
432
- {
433
- struct retval *retval = (struct retval *) args;
434
- raise_if_nil(retval->val, retval->method_name);
435
-
436
- return Qnil;
437
- }
438
-
439
320
  static void
440
321
  raise_if_nil(VALUE val, VALUE method_name)
441
322
  {
@@ -446,7 +327,7 @@ raise_if_nil(VALUE val, VALUE method_name)
446
327
  }
447
328
 
448
329
  static void
449
- filebuf_init(VALUE self, struct filebuf *filebuf)
330
+ method_data_init(VALUE self, struct method_data *data)
450
331
  {
451
332
  VALUE source_location = rb_funcall(self, rb_intern("source_location"), 0);
452
333
  VALUE name = rb_funcall(self, rb_intern("name"), 0);
@@ -459,37 +340,19 @@ filebuf_init(VALUE self, struct filebuf *filebuf)
459
340
  raise_if_nil(rb_filename, name);
460
341
  raise_if_nil(rb_method_location, name);
461
342
 
462
- filebuf->filename = RSTRING_PTR(rb_filename);
463
- filebuf->method_location = FIX2INT(rb_method_location);
464
- filebuf->method_name = name;
465
- filebuf->lines = allocate_memory_for_file();
466
- }
467
-
468
- static void
469
- free_filebuf(VALUE val, struct filebuf *filebuf)
470
- {
471
- int failed;
472
- struct retval retval = {val, filebuf->method_name};
473
-
474
- rb_protect(raise_if_nil_safe, (VALUE) &retval, &failed);
475
- free_memory_for_file(&filebuf->lines, filebuf->relevant_lines);
476
-
477
- if (failed) {
478
- rb_jump_tag(failed);
479
- }
343
+ data->filename = RSTRING_PTR(rb_filename);
344
+ data->method_location = FIX2INT(rb_method_location);
345
+ data->method_name = name;
480
346
  }
481
347
 
482
348
  static VALUE
483
349
  mMethodExtensions_source(VALUE self)
484
350
  {
485
- struct filebuf filebuf;
351
+ struct method_data data;
352
+ method_data_init(self, &data);
486
353
 
487
- filebuf_init(self, &filebuf);
488
- read_lines_after(&filebuf);
489
-
490
- VALUE source = find_source(&filebuf);
491
-
492
- free_filebuf(source, &filebuf);
354
+ VALUE source = find_method_source(&data);
355
+ raise_if_nil(source, data.method_name);
493
356
 
494
357
  return source;
495
358
  }
@@ -497,14 +360,11 @@ mMethodExtensions_source(VALUE self)
497
360
  static VALUE
498
361
  mMethodExtensions_comment(VALUE self)
499
362
  {
500
- struct filebuf filebuf;
501
-
502
- filebuf_init(self, &filebuf);
503
- read_lines_before(&filebuf);
504
-
505
- VALUE comment = find_comment(&filebuf);
363
+ struct method_data data;
364
+ method_data_init(self, &data);
506
365
 
507
- free_filebuf(comment, &filebuf);
366
+ VALUE comment = find_method_comment(&data);
367
+ raise_if_nil(comment, data.method_name);
508
368
 
509
369
  return comment;
510
370
  }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fast_method_source
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kyrylo Silin