tioga 1.6 → 1.7

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 (41) hide show
  1. data/Tioga_README +35 -10
  2. data/split/Dvector/dvector.c +264 -22
  3. data/split/Dvector/lib/Dvector_extras.rb +30 -2
  4. data/split/Flate/extconf.rb +1 -1
  5. data/split/Function/function.c +112 -2
  6. data/split/Tioga/figures.c +76 -77
  7. data/split/Tioga/figures.h +375 -490
  8. data/split/Tioga/generic.c +254 -0
  9. data/split/Tioga/generic.h +236 -0
  10. data/split/Tioga/init.c +434 -320
  11. data/split/Tioga/lib/Creating_Paths.rb +11 -1
  12. data/split/Tioga/lib/FigMkr.rb +263 -65
  13. data/split/Tioga/lib/Legends.rb +4 -2
  14. data/split/Tioga/lib/Markers.rb +3 -2
  15. data/split/Tioga/lib/Special_Paths.rb +22 -23
  16. data/split/Tioga/lib/TeX_Text.rb +79 -1
  17. data/split/Tioga/lib/TexPreamble.rb +14 -0
  18. data/split/Tioga/lib/Utils.rb +5 -1
  19. data/split/Tioga/pdfs.h +7 -45
  20. data/split/Tioga/{axes.c → shared/axes.c} +210 -197
  21. data/split/Tioga/{makers.c → shared/makers.c} +442 -211
  22. data/split/Tioga/{pdf_font_dicts.c → shared/pdf_font_dicts.c} +0 -0
  23. data/split/Tioga/shared/pdfcolor.c +628 -0
  24. data/split/Tioga/shared/pdfcoords.c +443 -0
  25. data/split/Tioga/{pdffile.c → shared/pdffile.c} +56 -52
  26. data/split/Tioga/{pdfimage.c → shared/pdfimage.c} +103 -211
  27. data/split/Tioga/shared/pdfpath.c +766 -0
  28. data/split/Tioga/{pdftext.c → shared/pdftext.c} +121 -99
  29. data/split/Tioga/shared/texout.c +524 -0
  30. data/split/Tioga/wrappers.c +489 -0
  31. data/split/Tioga/wrappers.h +259 -0
  32. data/split/extconf.rb +4 -0
  33. data/split/mkmf2.rb +12 -1
  34. data/tests/benchmark_dvector_reads.rb +112 -0
  35. data/tests/tc_Dvector.rb +35 -3
  36. data/tests/tc_Function.rb +32 -0
  37. metadata +65 -52
  38. data/split/Tioga/pdfcolor.c +0 -486
  39. data/split/Tioga/pdfcoords.c +0 -523
  40. data/split/Tioga/pdfpath.c +0 -913
  41. data/split/Tioga/texout.c +0 -380
@@ -20,16 +20,30 @@ This is the README for the Tioga kernel, version 1.6, March 17, 2007.
20
20
 
21
21
  << What's new >>
22
22
 
23
- Version 1.6 adds numeric label "frequency" and "phase" attributes for
24
- both axes. Previously Tioga assumed that every major tick mark got a numeric
25
- label. Now the i'th major tick on the axis gets a label only if
26
- mod(i+j,k)==0 where j is the phase and k is the frequency. The default
27
- frequency is naturally 1 so that every major tick gets a label.
28
- The full names for these attributes are xaxis_numeric_label_frequency,
29
- xaxis_numeric_label_phase, and similar for yaxis.
30
-
31
-
32
-
23
+ Version 1.7 adds an option in legends for markers without any line;
24
+ just call save_legend_info with 'line_type' => 'None' in addition to
25
+ the marker information. It is also now possible to give a 'legend' argument
26
+ to show_marker. The value of the arg can be either a legend dictionary
27
+ or simply the legend text in which case defaults will be supplied for
28
+ the rest. There is an example of this in samples/plots.rb
29
+ in the Legend_Outside figure.
30
+
31
+ It saw a very significant improvement in that you can now query
32
+ the exact size of a text typeset by LaTeX, with the function text_size. Please
33
+ have a look at its documentation, and at the Text_size and
34
+ Text_size_with_rotation samples in samples/figures/figures.rb.
35
+
36
+ The code base was quite moved around so as to facilitate work on a
37
+ Python version that would share as much code as possible with the Ruby one;
38
+ this should not bring user-visible changes (apart, maybe, from compilation
39
+ problems, but we hope not).
40
+
41
+ Some bug fixes, including potential stack overflows (unprotected
42
+ snprintfs), and some new methods of Function. Dvector.fancy_read has been
43
+ reimplemented in C and benchmarked: it should be around three times faster
44
+ than before.
45
+
46
+ Code should now compile cleanly with Ruby 1.9.
33
47
 
34
48
  << Quick Installation of Tioga >>
35
49
 
@@ -177,6 +191,17 @@ Bill Paxton
177
191
  Here are the old release messages:
178
192
 
179
193
 
194
+
195
+ --------------------------
196
+
197
+ Version 1.6 adds numeric label "frequency" and "phase" attributes for
198
+ both axes. Previously Tioga assumed that every major tick mark got a numeric
199
+ label. Now the i'th major tick on the axis gets a label only if
200
+ mod(i+j,k)==0 where j is the phase and k is the frequency. The default
201
+ frequency is naturally 1 so that every major tick gets a label.
202
+ The full names for these attributes are xaxis_numeric_label_frequency,
203
+ xaxis_numeric_label_phase, and similar for yaxis.
204
+
180
205
  --------------------------
181
206
 
182
207
  Version 1.5 is mainly Vincent's work, so my part of this release message
@@ -310,6 +310,23 @@ PRIVATE VALUE make_new_dvector(VALUE klass, long len, long capa) {
310
310
  return ary;
311
311
  }
312
312
 
313
+ /* Makes a Dvector with the given data. No additional capacity. */
314
+ PRIVATE VALUE make_dvector_from_data(VALUE klass, long len, double * data) {
315
+ VALUE ary = dvector_alloc(klass);
316
+ Dvector *d = Get_Dvector(ary);
317
+ if (len < 0) {
318
+ rb_raise(rb_eArgError, "negative dvector size (or size too big)");
319
+ }
320
+ d->len = len;
321
+ if (len == 0) len++;
322
+ d->ptr = ALLOC_N(double, len);
323
+ MEMCPY(d->ptr, data, double, len);
324
+ d->capa = len;
325
+ /* we set dirty to 0 */
326
+ d->dirty = 0;
327
+ return ary;
328
+ }
329
+
313
330
  PRIVATE VALUE dvector_new2(long len, long capa) {
314
331
  return make_new_dvector(cDvector, len, capa);
315
332
  }
@@ -1430,7 +1447,7 @@ PRIVATE VALUE dvector_join(VALUE ary, VALUE sep) {
1430
1447
  }
1431
1448
  result = rb_str_buf_new(len);
1432
1449
  for (i=0; i < d->len; i++) {
1433
- sprintf(buff, "%g", d->ptr[i]);
1450
+ snprintf(buff,sizeof(buff), "%g", d->ptr[i]);
1434
1451
  tmp = rb_str_new2(buff);
1435
1452
  if (i > 0 && !NIL_P(sep)) rb_str_buf_append(result, sep);
1436
1453
  rb_str_buf_append(result, tmp);
@@ -2097,19 +2114,12 @@ PRIVATE
2097
2114
  VALUE dvector_replace(VALUE dest, VALUE orig) {
2098
2115
  VALUE shared;
2099
2116
  Dvector *org, *d;
2100
- dvector_modify(dest);
2117
+ dvector_modify(dest); // take care of any sharing issues.
2101
2118
  orig = dvector_to_dvector(orig); /* it might be some kind of Array rather than a Dvector */
2102
2119
  if (dest == orig) return dest;
2103
2120
  org = Get_Dvector(orig);
2104
2121
  d = Get_Dvector(dest);
2105
- if (d->ptr) {
2106
- if (0 && d->capa >= org->len && d->shared == Qnil) {
2107
- d->len = org->len;
2108
- MEMCPY(d->ptr, org->ptr, double, d->len);
2109
- return dest;
2110
- }
2111
- free(d->ptr);
2112
- }
2122
+ if (d->ptr) free(d->ptr); // we know it isn't shared because we did dvector_modify above
2113
2123
  shared = dvector_make_shared(orig);
2114
2124
  org = Get_Dvector(shared);
2115
2125
  d->ptr = org->ptr;
@@ -4321,6 +4331,49 @@ VALUE dvector_div_bang(VALUE ary, VALUE arg) {
4321
4331
  return dvector_apply_math_op2_bang(ary, arg, do_div);
4322
4332
  }
4323
4333
 
4334
+ static char *fill_read_buffer(char **buff_ptr, int *len_ptr, FILE *file) {
4335
+ char *buff, *new_buff;
4336
+ buff = *buff_ptr;
4337
+ int len, i, max_tries, line_len;
4338
+ long filepos = ftell(file);
4339
+ if (filepos == -1) {
4340
+ printf("ftell failed\n");
4341
+ return NULL;
4342
+ }
4343
+ max_tries = 10;
4344
+ for (i = 0; i < max_tries; i++) {
4345
+ len = *len_ptr;
4346
+ buff[len-1] = '1'; // mark the last character position
4347
+ buff = fgets(buff, len, file);
4348
+ if (buff == NULL) return NULL; // end of file
4349
+ if (buff[len-1] != '\0') {
4350
+ if (0) {
4351
+ line_len = strlen(buff);
4352
+ printf("len %i line_len %i\n", len, line_len);
4353
+ if (line_len < 80) {
4354
+ printf("line buff contains: %s\n", buff);
4355
+ } else {
4356
+ printf("line buff ends with: %s\n", buff+line_len-80);
4357
+ }
4358
+ }
4359
+ return buff;
4360
+ }
4361
+ // ran out of room -- make buffer larger and try again
4362
+ len = 10*len + 100;
4363
+ //printf("fill_read_buffer ran out of room -- increase buffer len to %i and try again\n", len);
4364
+ *len_ptr = len;
4365
+ new_buff = (char *)realloc(buff, len);
4366
+ if (new_buff == NULL) break;
4367
+ buff = new_buff;
4368
+ *buff_ptr = buff;
4369
+ if (fseek(file, filepos, SEEK_SET) != 0) {
4370
+ printf("fseek failed\n");
4371
+ return NULL;
4372
+ }
4373
+ }
4374
+ return NULL;
4375
+ }
4376
+
4324
4377
  PRIVATE
4325
4378
  /*======================================================================*/
4326
4379
  VALUE Read_Dvectors(char *filename, VALUE destinations, int first_row_of_file, int number_of_rows) {
@@ -4329,8 +4382,8 @@ VALUE Read_Dvectors(char *filename, VALUE destinations, int first_row_of_file, i
4329
4382
  Dvector *d;
4330
4383
  double v;
4331
4384
  int last_row_of_file;
4332
- const int buff_len = 10000;
4333
- char buff[buff_len], *num_str, *pend, c, *cptr;
4385
+ int buff_len = 100;
4386
+ char *buff, *num_str, *pend, c, *cptr;
4334
4387
  int num_cols = 0, i, row, col, buff_loc, skip = first_row_of_file - 1;
4335
4388
  last_row_of_file = (number_of_rows == -1)? -1 : first_row_of_file + number_of_rows - 1;
4336
4389
  if ((last_row_of_file != -1 && last_row_of_file < first_row_of_file) || filename == NULL) return false;
@@ -4355,15 +4408,21 @@ VALUE Read_Dvectors(char *filename, VALUE destinations, int first_row_of_file, i
4355
4408
  if ((file=fopen(filename,"r")) == NULL) {
4356
4409
  rb_raise(rb_eArgError, "ERROR: read cannot open %s", filename);
4357
4410
  }
4411
+ buff = (char *)malloc(buff_len);
4412
+ if (buff == NULL) {
4413
+ fclose(file);
4414
+ rb_raise(rb_eArgError, "ERROR: allocation of read buffer failed");
4415
+ }
4358
4416
  for (i = 0; i < skip; i++) { /* skip over initial lines */
4359
- if (fgets(buff, buff_len, file)==NULL) {
4417
+ if (fill_read_buffer(&buff, &buff_len, file)==NULL) {
4360
4418
  fclose(file);
4419
+ free(buff);
4361
4420
  rb_raise(rb_eArgError, "ERROR: read reached end of file before reaching line %i in %s",
4362
4421
  first_row_of_file, filename);
4363
4422
  }
4364
4423
  }
4365
4424
  for (row = 0, i = first_row_of_file; last_row_of_file == -1 || i <= last_row_of_file; row++, i++) {
4366
- if (fgets(buff, buff_len, file)==NULL) break; /* have reached end of file */
4425
+ if (fill_read_buffer(&buff, &buff_len, file)==NULL) break; /* have reached end of file */
4367
4426
  if (destinations == Qnil) { /* create destinations */
4368
4427
  buff_loc = 0;
4369
4428
  while (true) {
@@ -4386,12 +4445,14 @@ VALUE Read_Dvectors(char *filename, VALUE destinations, int first_row_of_file, i
4386
4445
  while (isspace(buff[buff_loc])) buff_loc++; /* skip leading blanks */
4387
4446
  if (buff[buff_loc] == '\0') {
4388
4447
  fclose(file);
4448
+ free(buff);
4389
4449
  rb_raise(rb_eArgError, "read reached end of line looking for column %i in line %i of %s", col+1, i, filename);
4390
4450
  }
4391
4451
  num_str = buff+buff_loc;
4392
4452
  while (isgraph(buff[buff_loc])) buff_loc++; /* include non-blanks */
4393
4453
  if (buff[buff_loc] == '\0') {
4394
4454
  fclose(file);
4455
+ free(buff);
4395
4456
  rb_raise(rb_eArgError, "ERROR: read reached end of line looking for column %i in line %i of %s", col+1, i, filename);
4396
4457
  }
4397
4458
  col_obj = cols_ptr[col];
@@ -4410,6 +4471,7 @@ VALUE Read_Dvectors(char *filename, VALUE destinations, int first_row_of_file, i
4410
4471
  v = strtod(num_str,&pend); *cptr = c; buff_loc = pend - buff;
4411
4472
  } else {
4412
4473
  fclose(file);
4474
+ free(buff);
4413
4475
  pend[0] = 0;
4414
4476
  rb_raise(rb_eArgError, "ERROR: unreadable value in file %s in line %i: %s", filename, i , buff+buff_loc);
4415
4477
  }
@@ -4418,6 +4480,7 @@ VALUE Read_Dvectors(char *filename, VALUE destinations, int first_row_of_file, i
4418
4480
 
4419
4481
  if (!is_okay_number(v)) {
4420
4482
  fclose(file);
4483
+ free(buff);
4421
4484
  rb_raise(rb_eArgError, "ERROR: bad value %g in line %i of %s -- %s", v, i, filename, num_str);
4422
4485
  }
4423
4486
  if (row >= d->capa)
@@ -4430,6 +4493,7 @@ VALUE Read_Dvectors(char *filename, VALUE destinations, int first_row_of_file, i
4430
4493
  }
4431
4494
  }
4432
4495
  fclose(file);
4496
+ free(buff);
4433
4497
  return destinations;
4434
4498
  }
4435
4499
 
@@ -4467,8 +4531,8 @@ VALUE Read_Rows_of_Dvectors(char *filename, VALUE destinations, int first_row_of
4467
4531
  VALUE row_obj, rows_obj, *rows_ptr = NULL;
4468
4532
  Dvector *d;
4469
4533
  double v, *row_data;
4470
- const int buff_len = 10000;
4471
- char buff[buff_len], *num_str, *pend, c, *cptr;
4534
+ int buff_len = 1000;
4535
+ char *buff, *num_str, *pend, c, *cptr;
4472
4536
  int num_rows = 0, i, row, col, buff_loc, c_loc, skip = first_row_of_file - 1;
4473
4537
  rows_obj = rb_Array(destinations);
4474
4538
  num_rows = RARRAY(rows_obj)->len;
@@ -4489,16 +4553,23 @@ VALUE Read_Rows_of_Dvectors(char *filename, VALUE destinations, int first_row_of
4489
4553
  if ((file=fopen(filename,"r")) == NULL) {
4490
4554
  rb_raise(rb_eArgError, "ERROR: read_rows cannot open %s", filename);
4491
4555
  }
4556
+ buff = (char *)malloc(buff_len);
4557
+ if (buff == NULL) {
4558
+ fclose(file);
4559
+ rb_raise(rb_eArgError, "ERROR: allocation of read buffer failed");
4560
+ }
4492
4561
  for (i = 0; i < skip; i++) { /* skip over initial lines */
4493
- if (fgets(buff, buff_len, file)==NULL) {
4562
+ if (fill_read_buffer(&buff, &buff_len, file)==NULL) {
4494
4563
  fclose(file);
4564
+ free(buff);
4495
4565
  rb_raise(rb_eArgError, "ERROR: read_rows reached end of file before reaching line %i in %s",
4496
4566
  first_row_of_file, filename);
4497
4567
  }
4498
4568
  }
4499
4569
  for (row = 0, i = first_row_of_file; row < num_rows; row++, i++) {
4500
- if (fgets(buff, buff_len, file)==NULL) {
4570
+ if (fill_read_buffer(&buff, &buff_len, file)==NULL) {
4501
4571
  fclose(file);
4572
+ free(buff);
4502
4573
  rb_raise(rb_eArgError, "ERROR: read_rows reached end of file at line %i in %s", i, filename);
4503
4574
  }
4504
4575
  row_obj = rows_ptr[row];
@@ -4529,6 +4600,7 @@ VALUE Read_Rows_of_Dvectors(char *filename, VALUE destinations, int first_row_of
4529
4600
 
4530
4601
  if (!is_okay_number(v)) {
4531
4602
  fclose(file);
4603
+ free(buff);
4532
4604
  rb_raise(rb_eArgError, "ERROR: bad value %g in line i% of file %s", v, i, filename);
4533
4605
  }
4534
4606
  if (col < d->capa) { row_data[col] = v; d->len = col+1; }
@@ -4544,6 +4616,7 @@ VALUE Read_Rows_of_Dvectors(char *filename, VALUE destinations, int first_row_of
4544
4616
  }
4545
4617
  }
4546
4618
  fclose(file);
4619
+ free(buff);
4547
4620
  return destinations;
4548
4621
  }
4549
4622
 
@@ -4569,11 +4642,12 @@ VALUE dvector_read_rows(int argc, VALUE *argv, VALUE klass) {
4569
4642
  return Read_Rows_of_Dvectors(StringValueCStr(argv[0]),argv[1],arg3);
4570
4643
  klass = Qnil;
4571
4644
  }
4645
+
4572
4646
  PRIVATE
4573
4647
  VALUE Read_Row(char *filename, int row, VALUE row_ary) {
4574
4648
  FILE *file = NULL;
4575
- const int buff_len = 10000;
4576
- char buff[buff_len], *num_str, *pend, c, *cptr;
4649
+ int buff_len = 1000;
4650
+ char *buff, *num_str, *pend, c, *cptr;
4577
4651
  int i, col, buff_loc;
4578
4652
  double v;
4579
4653
  if (row <= 0) {
@@ -4582,9 +4656,15 @@ VALUE Read_Row(char *filename, int row, VALUE row_ary) {
4582
4656
  if (filename == NULL || (file=fopen(filename,"r")) == NULL) {
4583
4657
  rb_raise(rb_eArgError, "ERROR: read_row cannot open %s", filename);
4584
4658
  }
4659
+ buff = (char *)malloc(buff_len);
4660
+ if (buff == NULL) {
4661
+ fclose(file);
4662
+ rb_raise(rb_eArgError, "ERROR: allocation of read buffer failed");
4663
+ }
4585
4664
  for (i = 0; i < row; i++) { /* read lines until reach desired row */
4586
- if (fgets(buff, buff_len, file)==NULL) {
4665
+ if (fill_read_buffer(&buff, &buff_len, file)==NULL) {
4587
4666
  fclose(file);
4667
+ free(buff);
4588
4668
  rb_raise(rb_eArgError, "ERROR: read_row reached end of file before reaching line %i in %s",
4589
4669
  row, filename);
4590
4670
  }
@@ -4593,6 +4673,7 @@ VALUE Read_Row(char *filename, int row, VALUE row_ary) {
4593
4673
  else if (is_a_dvector(row_ary)) dvector_clear(row_ary);
4594
4674
  else {
4595
4675
  fclose(file);
4676
+ free(buff);
4596
4677
  rb_raise(rb_eArgError, "ERROR: destination for read_row must be a Dvector");
4597
4678
  }
4598
4679
  buff_loc = 0;
@@ -4614,6 +4695,7 @@ VALUE Read_Row(char *filename, int row, VALUE row_ary) {
4614
4695
  v = strtod(num_str,&pend); *cptr = c; buff_loc = pend - buff;
4615
4696
  } else {
4616
4697
  fclose(file);
4698
+ free(buff);
4617
4699
  pend[0] = 0;
4618
4700
  rb_raise(rb_eArgError, "ERROR: unreadable value in file %s in line %i: %s", filename, i , buff+buff_loc);
4619
4701
  }
@@ -4622,11 +4704,13 @@ VALUE Read_Row(char *filename, int row, VALUE row_ary) {
4622
4704
 
4623
4705
  if (!is_okay_number(v)) {
4624
4706
  fclose(file);
4707
+ free(buff);
4625
4708
  rb_raise(rb_eArgError, "ERROR: bad value %g in line %i of file %s", v, i, filename);
4626
4709
  }
4627
4710
  Dvector_Store_Double(row_ary, col, v);
4628
4711
  }
4629
4712
  fclose(file);
4713
+ free(buff);
4630
4714
  return row_ary;
4631
4715
  }
4632
4716
 
@@ -5161,6 +5245,158 @@ static VALUE dvector_convolve(VALUE self, VALUE kernel, VALUE middle)
5161
5245
  return retval;
5162
5246
  }
5163
5247
 
5248
+
5249
+ /*
5250
+ :call-seq:
5251
+ Dvector.fast_fancy_read(stream, options) => Array_of_Dvectors
5252
+
5253
+ Reads data from an IO stream and separate it into columns of data
5254
+ according to the _options_, a hash holding the following elements
5255
+ (compulsory, but you can use FANCY_READ_DEFAULTS):
5256
+ * 'sep': a regular expression that separate the entries
5257
+ * 'comments': any line matching this will be skipped
5258
+ * 'skip_first': skips that many lines before reading anything
5259
+ * 'index_col': if true, the first column returned contains the
5260
+ number of the line read
5261
+ * 'remove_space': whether to remove spaces at the beginning of a line. *This
5262
+ option is currently not implemented !*
5263
+ * 'default': what to put when nothing was found but a number must be used
5264
+
5265
+ As a side note, the read time is highly non-linear, which suggests that
5266
+ the read is memory-allocation/copying-limited, at least for big files.
5267
+ Well, the read time is non-linear for
5268
+
5269
+
5270
+ An internal memory allocation with aggressive policy should solve that,
5271
+ that is, not using directly Dvectors (and it would be way faster to store
5272
+ anyway).
5273
+ */
5274
+ static VALUE dvector_fast_fancy_read(VALUE self, VALUE stream, VALUE options)
5275
+ {
5276
+ /* First, we read up options: */
5277
+ double def = rb_num2dbl(rb_hash_aref(options,
5278
+ rb_str_new2("default")));
5279
+ int remove_space = RTEST(rb_hash_aref(options,
5280
+ rb_str_new2("remove_space")));
5281
+ int index_col = RTEST(rb_hash_aref(options,
5282
+ rb_str_new2("index_col")));
5283
+ long skip_first = FIX2LONG(rb_hash_aref(options,
5284
+ rb_str_new2("skip_first")));
5285
+ VALUE sep = rb_hash_aref(options, rb_str_new2("sep"));
5286
+ VALUE comments = rb_hash_aref(options, rb_str_new2("comments"));
5287
+
5288
+ /* Then, some various variables: */
5289
+ VALUE line;
5290
+
5291
+ ID chomp_id = rb_intern("chomp!");
5292
+ ID gets_id = rb_intern("gets");
5293
+ long line_number = 0;
5294
+
5295
+ /*
5296
+ Now come the fun part - rudimentary vectors management
5297
+ */
5298
+ int nb_vectors = 0; /* The number of vectors currently created */
5299
+ int current_size = 10; /* The number of slots available */
5300
+ double ** vectors = ALLOC_N(double *, current_size);
5301
+ long index = 0; /* The current index in the vectors */
5302
+ int allocated_size = 5004; /* The size available in the vectors */
5303
+
5304
+
5305
+ int i;
5306
+
5307
+ /* The return value */
5308
+ VALUE ary;
5309
+
5310
+ /* We use a real gets so we can also rely on StringIO, for instance */
5311
+ while(RTEST(line = rb_funcall(stream, gets_id, 0))) {
5312
+ VALUE pre, post, match;
5313
+ const char * line_ptr;
5314
+ int col = 0;
5315
+ line_number++;
5316
+ /* Whether we should skip the line... */
5317
+ if(skip_first >= line_number)
5318
+ continue;
5319
+
5320
+ /* We check for a blank line using isspace: */
5321
+ line_ptr = StringValueCStr(line);
5322
+ while(line_ptr && *line_ptr) {
5323
+ if(! isspace(*line_ptr))
5324
+ break;
5325
+ line_ptr++;
5326
+ }
5327
+ if(! *line_ptr)
5328
+ continue; /* We found a blank line */
5329
+ if(remove_space) /* We replace the contents of the line */
5330
+ line = rb_str_new2(line_ptr);
5331
+
5332
+ /* ... or a comment line */
5333
+ if(RTEST(comments) && RTEST(rb_reg_match(comments, line)))
5334
+ continue;
5335
+
5336
+ /* Then, we remove the newline: */
5337
+ post = line;
5338
+ rb_funcall(post, chomp_id, 0);
5339
+
5340
+ /* We iterate over the different portions between
5341
+ matches
5342
+ */
5343
+ while(RTEST(post)) {
5344
+ const char * a;
5345
+ char * b;
5346
+ if(RTEST(rb_reg_match(sep, post))) {
5347
+ match = rb_gv_get("$~");
5348
+ pre = rb_reg_match_pre(match);
5349
+ post = rb_reg_match_post(match);
5350
+ }
5351
+ else {
5352
+ pre = post;
5353
+ post = Qnil;
5354
+ }
5355
+ a = StringValueCStr(pre);
5356
+ double c = strtod(a, &b);
5357
+ if(b == a)
5358
+ c = def;
5359
+ if(col >= nb_vectors) {
5360
+ nb_vectors++;
5361
+ /* We need to create a new vector */
5362
+ if(col >= current_size) { /* Increase the available size */
5363
+ current_size += 5;
5364
+ REALLOC_N(vectors, double * , current_size);
5365
+ }
5366
+
5367
+ double * vals = vectors[col] = ALLOC_N(double, allocated_size);
5368
+ /* Filling it with the default value */
5369
+ for(i = 0; i < index; i++) {
5370
+ vals[i] = def;
5371
+ }
5372
+ }
5373
+ vectors[col][index] = c;
5374
+ col++;
5375
+ }
5376
+ /* Now, we finish the line */
5377
+ for(; col < nb_vectors; col++)
5378
+ vectors[col][index] = def;
5379
+ index++;
5380
+ /* Now, we reallocate memory if necessary */
5381
+ if(index >= allocated_size) {
5382
+ allocated_size *= 2; /* We double the size */
5383
+ for(col = 0; col < nb_vectors; col++)
5384
+ REALLOC_N(vectors[col], double, allocated_size);
5385
+ }
5386
+ }
5387
+ /* Now, we make up the array */
5388
+ ary = rb_ary_new();
5389
+ for(i = 0; i < nb_vectors; i++) {
5390
+ /* We create a vector */
5391
+ rb_ary_store(ary, i, make_dvector_from_data(cDvector, index, vectors[i]));
5392
+ /* And free the memory */
5393
+ free(vectors[i]);
5394
+ }
5395
+ free(vectors);
5396
+ return ary;
5397
+ }
5398
+
5399
+
5164
5400
  /*
5165
5401
  * Document-class: Dobjects::Dvector
5166
5402
  *
@@ -5236,7 +5472,8 @@ void Init_Dvector() {
5236
5472
  rb_define_singleton_method(cDvector, "is_a_dvector", dvector_is_a_dvector, 1);
5237
5473
 
5238
5474
 
5239
- rb_define_method(cDvector, "make_bezier_control_points_for_cubic_in_x", dvector_make_bezier_control_points_for_cubic_in_x, 6);
5475
+ rb_define_method(cDvector, "make_bezier_control_points_for_cubic_in_x",
5476
+ dvector_make_bezier_control_points_for_cubic_in_x, 6);
5240
5477
 
5241
5478
  rb_define_method(cDvector, "initialize", dvector_initialize, -1);
5242
5479
  rb_define_method(cDvector, "initialize_copy", dvector_replace, 1);
@@ -5475,6 +5712,11 @@ void Init_Dvector() {
5475
5712
  /* simple convolution */
5476
5713
  rb_define_method(cDvector, "convolve", dvector_convolve, 2);
5477
5714
 
5715
+ /* Fast fancy read: */
5716
+ rb_define_singleton_method(cDvector, "fast_fancy_read",
5717
+ dvector_fast_fancy_read, 2);
5718
+
5719
+
5478
5720
  dvector_output_fs = Qnil;
5479
5721
  rb_global_variable(&dvector_output_fs);
5480
5722
  dvector_output_fs = rb_str_new2(" ");