carray 3.0.1 → 3.0.3
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 +4 -4
- data/CHANGELOG.md +824 -0
- data/README.md +5 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +258 -4
- data/ext/ca_axis_group.c +368 -184
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +90 -41
- data/ext/ca_compare.c +8 -2
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +27 -11
- data/ext/ca_kernel_iterator.c +960 -245
- data/ext/ca_kernel_iterator.h +352 -181
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +194 -42
- data/ext/ca_obj_bincmp.c +152 -121
- data/ext/ca_obj_binop.c +107 -210
- data/ext/ca_obj_bitarray.c +37 -24
- data/ext/ca_obj_bitfield.c +95 -62
- data/ext/ca_obj_block.c +5 -4
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +180 -50
- data/ext/ca_obj_face.c +428 -62
- data/ext/ca_obj_face.h +107 -47
- data/ext/ca_obj_fake.c +21 -50
- data/ext/ca_obj_farray.c +1 -0
- data/ext/ca_obj_field.c +16 -3
- data/ext/ca_obj_fixlen_string.c +39 -26
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +235 -55
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +551 -233
- data/ext/ca_obj_record.c +51 -16
- data/ext/ca_obj_reduce.c +5 -8
- data/ext/ca_obj_refer.c +117 -33
- data/ext/ca_obj_remap.c +57 -17
- data/ext/ca_obj_repeat.c +21 -5
- data/ext/ca_obj_roll.c +115 -11
- data/ext/ca_obj_select.c +88 -75
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -123
- data/ext/ca_obj_stride.c +267 -35
- data/ext/ca_obj_string.c +25 -22
- data/ext/ca_obj_tile.c +32 -16
- data/ext/ca_obj_time.c +23 -25
- data/ext/ca_obj_timedelta.c +21 -23
- data/ext/ca_obj_transpose.c +12 -3
- data/ext/ca_obj_triop.c +110 -117
- data/ext/ca_obj_window.c +157 -29
- data/ext/ca_op_ipower.c +25 -13
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +385 -198
- data/ext/ca_sweep_engine.h +31 -23
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +463 -0
- data/ext/carray.h +90 -28
- data/ext/carray_access.c +487 -231
- data/ext/carray_address_basis.c +731 -0
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +49 -17
- data/ext/carray_call_cfunc.c +667 -511
- data/ext/carray_cast.c +1556 -247
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +84 -38
- data/ext/carray_core.c +591 -119
- data/ext/carray_count.c +148 -96
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +604 -291
- data/ext/carray_generate.c +76 -40
- data/ext/carray_histogram.c +152 -94
- data/ext/carray_hold.c +2 -1
- data/ext/carray_index_classifier.c +63 -96
- data/ext/carray_internal.h +400 -1
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +88 -66
- data/ext/carray_mask.c +705 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +263 -63
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1093 -363
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +582 -204
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +183 -70
- data/ext/carray_sort.c +235 -240
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +99 -21
- data/ext/carray_test.c +167 -64
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_utils.c +363 -98
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +103 -118
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1349 -851
- data/ext/ruby_carray.c +17 -2
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +39 -0
- data/lib/carray/autoload_carray.rb +24 -3
- data/lib/carray/autoload_method_extension.rb +18 -0
- data/lib/carray/axis_group.rb +245 -20
- data/lib/carray/basics.rb +95 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +200 -54
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +244 -59
- data/lib/carray/categorical_iterator.rb +391 -757
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +177 -27
- data/lib/carray/construct.rb +40 -0
- data/lib/carray/data_type_extension.rb +3 -0
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +590 -76
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +205 -35
- data/lib/carray/frame/group.rb +199 -40
- data/lib/carray/frame/io.rb +452 -60
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +54 -19
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +726 -56
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +111 -2
- data/lib/carray/fusion.rb +229 -38
- data/lib/carray/inspect.rb +71 -20
- data/lib/carray/iterator.rb +157 -2
- data/lib/carray/lazy.rb +54 -67
- data/lib/carray/mask_gap_fill.rb +66 -50
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +40 -7
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bincount.rb +2 -2
- data/lib/carray/methods/bit_string.rb +14 -3
- data/lib/carray/methods/composition.rb +16 -10
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/gather_nd.rb +13 -2
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_in.rb +130 -6
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +235 -21
- data/lib/carray/methods/mask_duplicates.rb +35 -1
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +22 -1
- data/lib/carray/methods/repeat.rb +91 -0
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +52 -3
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/runtime.rb +14 -11
- data/lib/carray/segment_iterator.rb +990 -0
- data/lib/carray/serialize.rb +197 -27
- data/lib/carray/slab_iterator.rb +109 -40
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +9 -4
- data/lib/carray/struct.rb +142 -51
- data/lib/carray/struct_builder.rb +110 -14
- data/lib/carray/table.rb +2 -2
- data/lib/carray/time.rb +535 -105
- data/lib/carray/window_iterator.rb +259 -82
- data/lib/carray.rb +4 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_block.rb +2 -7
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +1 -1
- data/yard-stubs/ca_obj_refer.rb +3 -3
- data/yard-stubs/ca_obj_roll.rb +0 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +11 -4
- data/yard-stubs/carray_access.rb +6 -5
- data/yard-stubs/carray_broadcast.rb +2 -2
- data/yard-stubs/carray_cast.rb +78 -43
- data/yard-stubs/carray_conversion.rb +13 -1
- data/yard-stubs/carray_copy.rb +8 -3
- data/yard-stubs/carray_core.rb +3 -83
- data/yard-stubs/carray_count.rb +16 -2
- data/yard-stubs/carray_lazy.rb +210 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +1499 -4
- data/yard-stubs/carray_median_percentile.rb +26 -8
- data/yard-stubs/carray_order.rb +43 -82
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +11 -8
- data/yard-stubs/carray_sort.rb +50 -8
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -19
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_build_flags.h +0 -3
- data/ext/carray_config.h +0 -28
- data/ext/carray_kernels_bincmp.c +0 -4446
- data/ext/carray_kernels_binop.c +0 -11001
- data/ext/carray_kernels_init.c +0 -1131
- data/ext/carray_kernels_map.c +0 -3467
- data/ext/carray_kernels_moncmp.c +0 -2097
- data/ext/carray_kernels_monop.c +0 -18313
- data/ext/carray_kernels_reduce_aggregate.c +0 -25837
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14593
- data/ext/carray_kernels_reduce_extreme.c +0 -16948
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32138
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
|
@@ -0,0 +1,1182 @@
|
|
|
1
|
+
#include "carray.h"
|
|
2
|
+
#include "carray_internal.h"
|
|
3
|
+
|
|
4
|
+
/* ------------------------------------------------------------------------
|
|
5
|
+
Reading year-first dates and times from text
|
|
6
|
+
|
|
7
|
+
A cell is read when it is written year first:
|
|
8
|
+
|
|
9
|
+
date YYYY sep M sep D sep is '-' or '/', the same twice;
|
|
10
|
+
month and day take one or two digits
|
|
11
|
+
time ( 'T' | ' '+ ) h ':' mm ( ':' ss ( ( '.' | ',' ) fraction )? )?
|
|
12
|
+
| 'T' hh hour takes one or two digits,
|
|
13
|
+
fraction one to nine
|
|
14
|
+
zone ' '? ( 'Z' | ( '+' | '-' ) hh ( ':'? mm )? ) after a time only
|
|
15
|
+
|
|
16
|
+
Surrounding ASCII whitespace is ignored. A time without a zone is UTC,
|
|
17
|
+
and a zone is folded into UTC. Nothing written in another order is read:
|
|
18
|
+
whether "01/02/2024" is January or February cannot be told from the text.
|
|
19
|
+
|
|
20
|
+
Read wide (when the caller has said the column is time), the year may
|
|
21
|
+
also carry a sign and more than four digits, and a date may stop after
|
|
22
|
+
the month ("2024-01") or the year ("2024", four digits unless signed) --
|
|
23
|
+
what CATime writes for a unit of months or years, or for a year past
|
|
24
|
+
9999. Text is not read
|
|
25
|
+
wide when it is being tried as time, since "2024" is as likely a number.
|
|
26
|
+
|
|
27
|
+
The unit of the result is the finest the text shows, unless one is
|
|
28
|
+
given: :D when no cell has a time of day, :s with one, and :ms / :us /
|
|
29
|
+
:ns when a fraction of a second has up to 3 / 6 / 9 digits; read wide,
|
|
30
|
+
:M when no cell has a day and :Y when none has a month either.
|
|
31
|
+
------------------------------------------------------------------------ */
|
|
32
|
+
|
|
33
|
+
enum {
|
|
34
|
+
CA_TIME_TEXT_OK = 0,
|
|
35
|
+
CA_TIME_TEXT_BLANK,
|
|
36
|
+
CA_TIME_TEXT_UNREADABLE
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
typedef struct {
|
|
40
|
+
int64_t days; /* days since 1970-01-01 */
|
|
41
|
+
int64_t nsod; /* nanoseconds into that day, 0 <= nsod < 86400e9 */
|
|
42
|
+
int clock; /* a time of day is written */
|
|
43
|
+
int fraction; /* digits written after the seconds */
|
|
44
|
+
int coarse; /* 0 a day is written, 1 only a month, 2 only a year */
|
|
45
|
+
int64_t months; /* months since 1970-01 */
|
|
46
|
+
} ca_time_text_t;
|
|
47
|
+
|
|
48
|
+
static const int64_t ca_ns_per_day = INT64_C(86400000000000);
|
|
49
|
+
|
|
50
|
+
static int
|
|
51
|
+
ca_time_text_is_space (char c)
|
|
52
|
+
{
|
|
53
|
+
return c == ' ' || c == '\t' || c == '\n' || c == '\r'
|
|
54
|
+
|| c == '\v' || c == '\f';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Read min..max digits at s[*i] into *out. */
|
|
58
|
+
static int
|
|
59
|
+
ca_time_text_digits (const char *s, long n, long *i, int min, int max,
|
|
60
|
+
int64_t *out)
|
|
61
|
+
{
|
|
62
|
+
int64_t v = 0;
|
|
63
|
+
int count = 0;
|
|
64
|
+
while ( *i < n && count < max && s[*i] >= '0' && s[*i] <= '9' ) {
|
|
65
|
+
v = v * 10 + ( s[*i] - '0' );
|
|
66
|
+
(*i)++;
|
|
67
|
+
count++;
|
|
68
|
+
}
|
|
69
|
+
if ( count < min ) {
|
|
70
|
+
return 0;
|
|
71
|
+
}
|
|
72
|
+
if ( *i < n && s[*i] >= '0' && s[*i] <= '9' ) {
|
|
73
|
+
return 0; /* more digits than the field takes */
|
|
74
|
+
}
|
|
75
|
+
*out = v;
|
|
76
|
+
return count;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
static int
|
|
80
|
+
ca_time_text_leap (int64_t y)
|
|
81
|
+
{
|
|
82
|
+
return ( y % 4 == 0 && y % 100 != 0 ) || y % 400 == 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
static int
|
|
86
|
+
ca_time_text_month_days (int64_t y, int64_t m)
|
|
87
|
+
{
|
|
88
|
+
static const int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
|
89
|
+
return ( m == 2 && ca_time_text_leap(y) ) ? 29 : days[m - 1];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* Days since 1970-01-01 of a proleptic Gregorian date. */
|
|
93
|
+
static int64_t
|
|
94
|
+
ca_time_text_days_from_civil (int64_t y, int64_t m, int64_t d)
|
|
95
|
+
{
|
|
96
|
+
int64_t era, yoe, doy, doe;
|
|
97
|
+
y -= ( m <= 2 );
|
|
98
|
+
era = ( y >= 0 ? y : y - 399 ) / 400;
|
|
99
|
+
yoe = y - era * 400;
|
|
100
|
+
doy = ( 153 * ( m > 2 ? m - 3 : m + 9 ) + 2 ) / 5 + d - 1;
|
|
101
|
+
doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
|
|
102
|
+
return era * 146097 + doe - 719468;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
static int
|
|
106
|
+
ca_time_text_read (VALUE str, ca_time_text_t *t, int wide)
|
|
107
|
+
{
|
|
108
|
+
const char *s = RSTRING_PTR(str);
|
|
109
|
+
long n = RSTRING_LEN(str);
|
|
110
|
+
long i = 0;
|
|
111
|
+
int64_t year, mon, day, hour = 0, min = 0, sec = 0, frac_ns = 0;
|
|
112
|
+
int64_t offset = 0;
|
|
113
|
+
int year_digits;
|
|
114
|
+
char sep;
|
|
115
|
+
|
|
116
|
+
while ( n > 0 && ca_time_text_is_space(s[0]) ) {
|
|
117
|
+
s++;
|
|
118
|
+
n--;
|
|
119
|
+
}
|
|
120
|
+
while ( n > 0 && ca_time_text_is_space(s[n-1]) ) {
|
|
121
|
+
n--;
|
|
122
|
+
}
|
|
123
|
+
if ( n == 0 ) {
|
|
124
|
+
return CA_TIME_TEXT_BLANK;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
t->clock = 0;
|
|
128
|
+
t->fraction = 0;
|
|
129
|
+
t->coarse = 0;
|
|
130
|
+
|
|
131
|
+
if ( wide ) {
|
|
132
|
+
int sign = 0;
|
|
133
|
+
if ( s[i] == '+' || s[i] == '-' ) {
|
|
134
|
+
sign = ( s[i] == '-' ) ? -1 : 1;
|
|
135
|
+
i++;
|
|
136
|
+
}
|
|
137
|
+
year_digits = ca_time_text_digits(s, n, &i, 4, 12, &year);
|
|
138
|
+
if ( year_digits == 0 ) {
|
|
139
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
140
|
+
}
|
|
141
|
+
if ( sign < 0 ) {
|
|
142
|
+
year = -year;
|
|
143
|
+
}
|
|
144
|
+
/* A year alone is four digits unless signed: "20240101" is a date
|
|
145
|
+
written without separators, which is not read. */
|
|
146
|
+
if ( i == n && year_digits > 4 && sign == 0 ) {
|
|
147
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else if ( ca_time_text_digits(s, n, &i, 4, 4, &year) == 0 ) {
|
|
151
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
152
|
+
}
|
|
153
|
+
if ( wide && i == n ) {
|
|
154
|
+
t->coarse = 2;
|
|
155
|
+
t->months = ( year - 1970 ) * 12;
|
|
156
|
+
t->days = ca_time_text_days_from_civil(year, 1, 1);
|
|
157
|
+
t->nsod = 0;
|
|
158
|
+
return CA_TIME_TEXT_OK;
|
|
159
|
+
}
|
|
160
|
+
if ( i >= n || ( s[i] != '-' && s[i] != '/' ) ) {
|
|
161
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
162
|
+
}
|
|
163
|
+
sep = s[i++];
|
|
164
|
+
if ( ca_time_text_digits(s, n, &i, 1, 2, &mon) == 0 ) {
|
|
165
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
166
|
+
}
|
|
167
|
+
if ( mon < 1 || mon > 12 ) {
|
|
168
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
169
|
+
}
|
|
170
|
+
t->months = ( year - 1970 ) * 12 + ( mon - 1 );
|
|
171
|
+
if ( wide && i == n ) {
|
|
172
|
+
t->coarse = 1;
|
|
173
|
+
t->days = ca_time_text_days_from_civil(year, mon, 1);
|
|
174
|
+
t->nsod = 0;
|
|
175
|
+
return CA_TIME_TEXT_OK;
|
|
176
|
+
}
|
|
177
|
+
if ( i >= n || s[i] != sep ) {
|
|
178
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
179
|
+
}
|
|
180
|
+
i++;
|
|
181
|
+
if ( ca_time_text_digits(s, n, &i, 1, 2, &day) == 0 ) {
|
|
182
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
183
|
+
}
|
|
184
|
+
if ( day < 1 || day > ca_time_text_month_days(year, mon) ) {
|
|
185
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if ( i < n ) {
|
|
189
|
+
int by_t = ( s[i] == 'T' ), hour_digits;
|
|
190
|
+
if ( by_t ) {
|
|
191
|
+
i++;
|
|
192
|
+
}
|
|
193
|
+
else if ( s[i] == ' ' ) {
|
|
194
|
+
while ( i < n && s[i] == ' ' ) {
|
|
195
|
+
i++;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
200
|
+
}
|
|
201
|
+
hour_digits = ca_time_text_digits(s, n, &i, 1, 2, &hour);
|
|
202
|
+
if ( hour_digits == 0 ) {
|
|
203
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
204
|
+
}
|
|
205
|
+
if ( i >= n || s[i] != ':' ) {
|
|
206
|
+
/* 'T' hh alone is an hour (ISO 8601 reduced to the hour). */
|
|
207
|
+
if ( ! ( by_t && hour_digits == 2 ) ) {
|
|
208
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
i++;
|
|
213
|
+
if ( ca_time_text_digits(s, n, &i, 2, 2, &min) == 0 ) {
|
|
214
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
215
|
+
}
|
|
216
|
+
if ( i < n && s[i] == ':' ) {
|
|
217
|
+
i++;
|
|
218
|
+
if ( ca_time_text_digits(s, n, &i, 2, 2, &sec) == 0 ) {
|
|
219
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
220
|
+
}
|
|
221
|
+
if ( i < n && ( s[i] == '.' || s[i] == ',' ) ) {
|
|
222
|
+
int64_t f;
|
|
223
|
+
int digits;
|
|
224
|
+
i++;
|
|
225
|
+
digits = ca_time_text_digits(s, n, &i, 1, 9, &f);
|
|
226
|
+
if ( digits == 0 ) {
|
|
227
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
228
|
+
}
|
|
229
|
+
t->fraction = digits;
|
|
230
|
+
frac_ns = f;
|
|
231
|
+
while ( digits++ < 9 ) {
|
|
232
|
+
frac_ns *= 10;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if ( hour > 24 || min > 59 || sec > 59 ) {
|
|
238
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
239
|
+
}
|
|
240
|
+
/* Hour 24 is the end of the day, 24:00:00, and nothing past it, as in
|
|
241
|
+
the strptime reader below. */
|
|
242
|
+
if ( hour == 24 && ( min || sec || frac_ns ) ) {
|
|
243
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
244
|
+
}
|
|
245
|
+
t->clock = 1;
|
|
246
|
+
|
|
247
|
+
if ( i < n && s[i] == ' ' ) {
|
|
248
|
+
i++; /* one space before a zone */
|
|
249
|
+
if ( i >= n ) {
|
|
250
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if ( i < n ) {
|
|
254
|
+
if ( s[i] == 'Z' ) {
|
|
255
|
+
i++;
|
|
256
|
+
}
|
|
257
|
+
else if ( s[i] == '+' || s[i] == '-' ) {
|
|
258
|
+
int negative = ( s[i] == '-' );
|
|
259
|
+
int64_t oh, om = 0, hhmm;
|
|
260
|
+
int digits;
|
|
261
|
+
i++;
|
|
262
|
+
digits = ca_time_text_digits(s, n, &i, 2, 4, &hhmm);
|
|
263
|
+
if ( digits == 4 ) { /* +hhmm */
|
|
264
|
+
oh = hhmm / 100;
|
|
265
|
+
om = hhmm % 100;
|
|
266
|
+
}
|
|
267
|
+
else if ( digits == 2 ) { /* +hh or +hh:mm */
|
|
268
|
+
oh = hhmm;
|
|
269
|
+
if ( i < n && s[i] == ':' ) {
|
|
270
|
+
i++;
|
|
271
|
+
if ( ca_time_text_digits(s, n, &i, 2, 2, &om) == 0 ) {
|
|
272
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
278
|
+
}
|
|
279
|
+
if ( oh > 23 || om > 59 ) {
|
|
280
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
281
|
+
}
|
|
282
|
+
offset = ( oh * 3600 + om * 60 ) * ( negative ? -1 : 1 );
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if ( i != n ) {
|
|
290
|
+
return CA_TIME_TEXT_UNREADABLE;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
{
|
|
294
|
+
int64_t nsod = ( hour * 3600 + min * 60 + sec - offset ) * INT64_C(1000000000)
|
|
295
|
+
+ frac_ns;
|
|
296
|
+
int64_t days = ca_time_text_days_from_civil(year, mon, day);
|
|
297
|
+
if ( nsod < 0 ) {
|
|
298
|
+
nsod += ca_ns_per_day;
|
|
299
|
+
days -= 1;
|
|
300
|
+
}
|
|
301
|
+
else if ( nsod >= ca_ns_per_day ) {
|
|
302
|
+
nsod -= ca_ns_per_day;
|
|
303
|
+
days += 1;
|
|
304
|
+
}
|
|
305
|
+
t->days = days;
|
|
306
|
+
t->nsod = nsod;
|
|
307
|
+
}
|
|
308
|
+
return CA_TIME_TEXT_OK;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/* Ticks per day and nanoseconds per tick of the units this reader writes. */
|
|
312
|
+
static int
|
|
313
|
+
ca_time_text_unit (ID unit, int64_t *per_day, int64_t *ns_per_tick)
|
|
314
|
+
{
|
|
315
|
+
if ( unit == rb_intern("D") ) {
|
|
316
|
+
*per_day = 1;
|
|
317
|
+
*ns_per_tick = ca_ns_per_day;
|
|
318
|
+
}
|
|
319
|
+
else if ( unit == rb_intern("s") ) {
|
|
320
|
+
*per_day = 86400;
|
|
321
|
+
*ns_per_tick = INT64_C(1000000000);
|
|
322
|
+
}
|
|
323
|
+
else if ( unit == rb_intern("ms") ) {
|
|
324
|
+
*per_day = INT64_C(86400000);
|
|
325
|
+
*ns_per_tick = INT64_C(1000000);
|
|
326
|
+
}
|
|
327
|
+
else if ( unit == rb_intern("us") ) {
|
|
328
|
+
*per_day = INT64_C(86400000000);
|
|
329
|
+
*ns_per_tick = INT64_C(1000);
|
|
330
|
+
}
|
|
331
|
+
else if ( unit == rb_intern("ns") ) {
|
|
332
|
+
*per_day = ca_ns_per_day;
|
|
333
|
+
*ns_per_tick = 1;
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
return 0;
|
|
337
|
+
}
|
|
338
|
+
return 1;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/* CArray#__parse_time_text__(unit, report, wide = false)
|
|
342
|
+
-> [int64 ticks, unit] or nil
|
|
343
|
+
|
|
344
|
+
Reads an object array of year-first text into tick counts since the
|
|
345
|
+
epoch, wide as the grammar above says when wide is true. With unit nil
|
|
346
|
+
the unit is the finest the text shows; a unit this reader does not write
|
|
347
|
+
answers nil, and the caller parses another way.
|
|
348
|
+
With an Array as report, the addresses of cells that hold something but
|
|
349
|
+
do not read are pushed onto it; blank, nil and masked cells are missing,
|
|
350
|
+
not unreadable. A cell that reads but does not fit int64 ticks of the
|
|
351
|
+
unit raises RangeError. */
|
|
352
|
+
static VALUE
|
|
353
|
+
rb_ca_parse_time_text (int argc, VALUE *argv, VALUE self)
|
|
354
|
+
{
|
|
355
|
+
volatile VALUE src = self, out, vdays, vnsod, vmonths, vmask;
|
|
356
|
+
VALUE runit, report, rwide;
|
|
357
|
+
CArray *ca, *co, *cdays, *cnsod, *cmonths, *cmask;
|
|
358
|
+
VALUE *cells;
|
|
359
|
+
boolean8_t *m_in, *m_out;
|
|
360
|
+
int64_t *days, *nsod, *months, *ticks;
|
|
361
|
+
int64_t per_day = 1, ns_per_tick = 1;
|
|
362
|
+
ID unit;
|
|
363
|
+
int clock = 0, fraction = 0, coarse = 2, any = 0, wide;
|
|
364
|
+
int calendar = 0; /* 1 ticks of months, 2 of years */
|
|
365
|
+
ca_size_t i;
|
|
366
|
+
|
|
367
|
+
rb_scan_args(argc, argv, "21", &runit, &report, &rwide);
|
|
368
|
+
wide = RTEST(rwide);
|
|
369
|
+
|
|
370
|
+
if ( ! NIL_P(report) ) {
|
|
371
|
+
Check_Type(report, T_ARRAY);
|
|
372
|
+
}
|
|
373
|
+
if ( ! NIL_P(runit) ) {
|
|
374
|
+
unit = SYM2ID(rb_to_symbol(runit));
|
|
375
|
+
if ( ! ca_time_text_unit(unit, &per_day, &ns_per_tick) ) {
|
|
376
|
+
return Qnil;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
TypedData_Get_Struct(src, CArray, &carray_data_type, ca);
|
|
381
|
+
if ( ca->data_type != CA_OBJECT ) {
|
|
382
|
+
rb_raise(rb_eArgError, "time text reading needs an object array");
|
|
383
|
+
}
|
|
384
|
+
if ( ! ca_is_entity(ca) ) {
|
|
385
|
+
src = rb_ca_copy(src);
|
|
386
|
+
TypedData_Get_Struct(src, CArray, &carray_data_type, ca);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
out = rb_carray_new(CA_INT64, ca->ndim, ca->dim, 0, NULL);
|
|
390
|
+
TypedData_Get_Struct(out, CArray, &carray_data_type, co);
|
|
391
|
+
vmask = rb_carray_new(CA_BOOLEAN, ca->ndim, ca->dim, 0, NULL);
|
|
392
|
+
vdays = rb_carray_new(CA_INT64, ca->ndim, ca->dim, 0, NULL);
|
|
393
|
+
TypedData_Get_Struct(vdays, CArray, &carray_data_type, cdays);
|
|
394
|
+
vnsod = rb_carray_new(CA_INT64, ca->ndim, ca->dim, 0, NULL);
|
|
395
|
+
TypedData_Get_Struct(vnsod, CArray, &carray_data_type, cnsod);
|
|
396
|
+
vmonths = rb_carray_new(CA_INT64, ca->ndim, ca->dim, 0, NULL);
|
|
397
|
+
TypedData_Get_Struct(vmonths, CArray, &carray_data_type, cmonths);
|
|
398
|
+
|
|
399
|
+
cells = (VALUE *) ca->ptr;
|
|
400
|
+
m_in = ca_has_mask(ca) ? (boolean8_t *) ca->mask->ptr : NULL;
|
|
401
|
+
TypedData_Get_Struct(vmask, CArray, &carray_data_type, cmask);
|
|
402
|
+
m_out = (boolean8_t *) cmask->ptr;
|
|
403
|
+
days = (int64_t *) cdays->ptr;
|
|
404
|
+
nsod = (int64_t *) cnsod->ptr;
|
|
405
|
+
months = (int64_t *) cmonths->ptr;
|
|
406
|
+
ticks = (int64_t *) co->ptr;
|
|
407
|
+
|
|
408
|
+
for (i = 0; i < ca->elements; i++) {
|
|
409
|
+
VALUE v = cells[i];
|
|
410
|
+
int rc;
|
|
411
|
+
ca_time_text_t t;
|
|
412
|
+
if ( ( m_in && m_in[i] ) || NIL_P(v) ) {
|
|
413
|
+
rc = CA_TIME_TEXT_BLANK;
|
|
414
|
+
}
|
|
415
|
+
else if ( RB_TYPE_P(v, T_STRING) ) {
|
|
416
|
+
rc = ca_time_text_read(v, &t, wide);
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
419
|
+
rc = CA_TIME_TEXT_UNREADABLE;
|
|
420
|
+
}
|
|
421
|
+
if ( rc == CA_TIME_TEXT_OK ) {
|
|
422
|
+
m_out[i] = 0;
|
|
423
|
+
days[i] = t.days;
|
|
424
|
+
nsod[i] = t.nsod;
|
|
425
|
+
months[i] = t.months;
|
|
426
|
+
clock |= t.clock;
|
|
427
|
+
if ( t.coarse < coarse ) {
|
|
428
|
+
coarse = t.coarse;
|
|
429
|
+
}
|
|
430
|
+
any = 1;
|
|
431
|
+
if ( t.fraction > fraction ) {
|
|
432
|
+
fraction = t.fraction;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
m_out[i] = 1;
|
|
437
|
+
if ( rc == CA_TIME_TEXT_UNREADABLE && ! NIL_P(report) ) {
|
|
438
|
+
rb_ary_push(report, SIZET2NUM(i));
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if ( NIL_P(runit) ) {
|
|
444
|
+
const char *name = fraction > 6 ? "ns" : fraction > 3 ? "us"
|
|
445
|
+
: fraction > 0 ? "ms" : clock ? "s" : "D";
|
|
446
|
+
if ( any && ! clock && coarse > 0 ) {
|
|
447
|
+
name = ( coarse == 1 ) ? "M" : "Y";
|
|
448
|
+
calendar = coarse;
|
|
449
|
+
}
|
|
450
|
+
unit = rb_intern(name);
|
|
451
|
+
if ( ! calendar ) {
|
|
452
|
+
ca_time_text_unit(unit, &per_day, &ns_per_tick);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
for (i = 0; i < ca->elements; i++) {
|
|
457
|
+
int64_t whole;
|
|
458
|
+
if ( m_out[i] ) {
|
|
459
|
+
ticks[i] = 0;
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
if ( calendar ) {
|
|
463
|
+
ticks[i] = ( calendar == 1 ) ? months[i]
|
|
464
|
+
: ( months[i] >= 0 ? months[i] / 12 : -( ( 11 - months[i] ) / 12 ) );
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
/* A time that reads but does not fit int64 ticks of the unit is out of
|
|
468
|
+
range, not unreadable, so it raises under every policy rather than
|
|
469
|
+
becoming a masked cell: with the unit chosen from the finest text in
|
|
470
|
+
the column, one cell with nanoseconds would otherwise mask every date
|
|
471
|
+
outside 1677..2262 without a word. */
|
|
472
|
+
if ( __builtin_mul_overflow(days[i], per_day, &whole)
|
|
473
|
+
|| __builtin_add_overflow(whole, nsod[i] / ns_per_tick, &ticks[i]) ) {
|
|
474
|
+
rb_raise(rb_eRangeError, "time %" PRIsVALUE " does not fit int64 ticks of %" PRIsVALUE,
|
|
475
|
+
rb_inspect(cells[i]), rb_id2str(unit));
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
ca_mask_from_bytes(co, m_out);
|
|
480
|
+
RB_GC_GUARD(src);
|
|
481
|
+
RB_GC_GUARD(vdays);
|
|
482
|
+
RB_GC_GUARD(vnsod);
|
|
483
|
+
RB_GC_GUARD(vmonths);
|
|
484
|
+
RB_GC_GUARD(vmask);
|
|
485
|
+
return rb_assoc_new(out, ID2SYM(unit));
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/* Floor division of an int128 by a positive int64. */
|
|
489
|
+
static __int128
|
|
490
|
+
ca_time_floor_div (__int128 a, int64_t b)
|
|
491
|
+
{
|
|
492
|
+
__int128 q = a / b;
|
|
493
|
+
if ( ( a % b ) != 0 && a < 0 ) {
|
|
494
|
+
q -= 1;
|
|
495
|
+
}
|
|
496
|
+
return q;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/* CArray.__time_ticks_from_fields__(year, mon, day, sec_of_day, frac_ns,
|
|
500
|
+
offset, present, kind, per)
|
|
501
|
+
-> int64 ticks
|
|
502
|
+
|
|
503
|
+
Ticks since the epoch from date and time fields already parsed, one
|
|
504
|
+
int64 array per field (offset in seconds east of UTC). Cells whose
|
|
505
|
+
present byte is 0 come back masked, and so do cells whose tick does not
|
|
506
|
+
fit int64. kind :fixed counts ticks of `per` nanoseconds; kind
|
|
507
|
+
:calendar counts ticks of `per` months and reads the year and month
|
|
508
|
+
only. */
|
|
509
|
+
static VALUE
|
|
510
|
+
rb_ca_s_time_ticks_from_fields (VALUE klass,
|
|
511
|
+
VALUE vyear, VALUE vmon, VALUE vday,
|
|
512
|
+
VALUE vsod, VALUE vfrac, VALUE voff,
|
|
513
|
+
VALUE vpresent, VALUE rkind, VALUE rper)
|
|
514
|
+
{
|
|
515
|
+
volatile VALUE out, vmask;
|
|
516
|
+
CArray *cy, *cm, *cd, *cs, *cf, *co_, *cp, *co, *cmask;
|
|
517
|
+
int64_t *y, *mo, *d, *sod, *frac, *off, *ticks;
|
|
518
|
+
uint8_t *present;
|
|
519
|
+
boolean8_t *m_out;
|
|
520
|
+
int64_t per = NUM2LL(rper);
|
|
521
|
+
int calendar = ( SYM2ID(rb_to_symbol(rkind)) == rb_intern("calendar") );
|
|
522
|
+
ca_size_t i, n;
|
|
523
|
+
|
|
524
|
+
if ( per <= 0 ) {
|
|
525
|
+
rb_raise(rb_eArgError, "tick length must be positive");
|
|
526
|
+
}
|
|
527
|
+
#define CA_TIME_FIELD(v, c, field, T) \
|
|
528
|
+
TypedData_Get_Struct(v, CArray, &carray_data_type, c); \
|
|
529
|
+
if ( ! ca_is_entity(c) ) { \
|
|
530
|
+
rb_raise(rb_eArgError, "time fields must be entities"); \
|
|
531
|
+
} \
|
|
532
|
+
field = (T *) c->ptr;
|
|
533
|
+
CA_TIME_FIELD(vyear, cy, y, int64_t);
|
|
534
|
+
CA_TIME_FIELD(vmon, cm, mo, int64_t);
|
|
535
|
+
CA_TIME_FIELD(vday, cd, d, int64_t);
|
|
536
|
+
CA_TIME_FIELD(vsod, cs, sod, int64_t);
|
|
537
|
+
CA_TIME_FIELD(vfrac, cf, frac, int64_t);
|
|
538
|
+
CA_TIME_FIELD(voff, co_, off, int64_t);
|
|
539
|
+
CA_TIME_FIELD(vpresent, cp, present, uint8_t);
|
|
540
|
+
#undef CA_TIME_FIELD
|
|
541
|
+
n = cy->elements;
|
|
542
|
+
if ( cy->data_type != CA_INT64 || cm->data_type != CA_INT64
|
|
543
|
+
|| cd->data_type != CA_INT64 || cs->data_type != CA_INT64
|
|
544
|
+
|| cf->data_type != CA_INT64 || co_->data_type != CA_INT64
|
|
545
|
+
|| cp->data_type != CA_UINT8
|
|
546
|
+
|| cm->elements != n || cd->elements != n || cs->elements != n
|
|
547
|
+
|| cf->elements != n || co_->elements != n || cp->elements != n ) {
|
|
548
|
+
rb_raise(rb_eArgError, "time fields must be int64 arrays of one size "
|
|
549
|
+
"(present uint8)");
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
out = rb_carray_new(CA_INT64, 1, &n, 0, NULL);
|
|
553
|
+
TypedData_Get_Struct(out, CArray, &carray_data_type, co);
|
|
554
|
+
vmask = rb_carray_new(CA_BOOLEAN, 1, &n, 0, NULL);
|
|
555
|
+
ticks = (int64_t *) co->ptr;
|
|
556
|
+
TypedData_Get_Struct(vmask, CArray, &carray_data_type, cmask);
|
|
557
|
+
m_out = (boolean8_t *) cmask->ptr;
|
|
558
|
+
|
|
559
|
+
for (i = 0; i < n; i++) {
|
|
560
|
+
__int128 t;
|
|
561
|
+
if ( ! present[i] ) {
|
|
562
|
+
m_out[i] = 1;
|
|
563
|
+
ticks[i] = 0;
|
|
564
|
+
continue;
|
|
565
|
+
}
|
|
566
|
+
if ( calendar ) {
|
|
567
|
+
t = ca_time_floor_div((__int128) ( y[i] - 1970 ) * 12 + ( mo[i] - 1 ), per);
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
__int128 ns = (__int128) ca_time_text_days_from_civil(y[i], mo[i], d[i])
|
|
571
|
+
* ca_ns_per_day
|
|
572
|
+
+ (__int128) ( sod[i] - off[i] ) * 1000000000
|
|
573
|
+
+ frac[i];
|
|
574
|
+
t = ca_time_floor_div(ns, per);
|
|
575
|
+
}
|
|
576
|
+
if ( t > INT64_MAX || t < INT64_MIN ) {
|
|
577
|
+
m_out[i] = 1;
|
|
578
|
+
ticks[i] = 0;
|
|
579
|
+
}
|
|
580
|
+
else {
|
|
581
|
+
m_out[i] = 0;
|
|
582
|
+
ticks[i] = (int64_t) t;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
ca_mask_from_bytes(co, m_out);
|
|
586
|
+
RB_GC_GUARD(vmask);
|
|
587
|
+
return out;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/* ------------------------------------------------------------------------
|
|
591
|
+
Reading text in a strptime format
|
|
592
|
+
|
|
593
|
+
This reads the directives Date._strptime reads for a date and a time of
|
|
594
|
+
day, the same way, so that a format answers the same in either: %Y %y %m
|
|
595
|
+
%d %e %H %k %I %l %M %S %N %L %p %P %b %B %h %a %A %z %Z %n %t %%, and
|
|
596
|
+
%D %F %R %T %X %x, which stand for longer formats. A format with any
|
|
597
|
+
other directive is not read here (the caller uses Date._strptime).
|
|
598
|
+
Text left over after the format makes a cell unreadable, unless it is
|
|
599
|
+
whitespace. A zone this reader does not know the offset of (a name
|
|
600
|
+
other than Z, UTC and GMT, an offset written another way) is deferred to
|
|
601
|
+
Date._strptime for that cell.
|
|
602
|
+
|
|
603
|
+
Strict reading, used to find the format a column is written in, holds
|
|
604
|
+
the text to the shape of the format: %Y is four digits and %y two, %N
|
|
605
|
+
one to nine digits, the other numbers one or two digits (two when a
|
|
606
|
+
number follows directly), no sign and no leading space before a number,
|
|
607
|
+
%p takes AM or PM only, an unknown zone is unreadable rather than
|
|
608
|
+
deferred, and blank text is missing. Whitespace in the format matches
|
|
609
|
+
any run of whitespace, none included, in both readings.
|
|
610
|
+
------------------------------------------------------------------------ */
|
|
611
|
+
|
|
612
|
+
enum {
|
|
613
|
+
CA_STRP_OK = 0,
|
|
614
|
+
CA_STRP_FAIL,
|
|
615
|
+
CA_STRP_DEFER
|
|
616
|
+
};
|
|
617
|
+
|
|
618
|
+
typedef struct {
|
|
619
|
+
int64_t year, mon, mday, hour, min, sec, frac_ns, offset;
|
|
620
|
+
int has_year, has_hour, merid, frac_digits;
|
|
621
|
+
} ca_strp_t;
|
|
622
|
+
|
|
623
|
+
static const char *ca_strp_months[] = {
|
|
624
|
+
"January", "February", "March", "April", "May", "June", "July",
|
|
625
|
+
"August", "September", "October", "November", "December"
|
|
626
|
+
};
|
|
627
|
+
static const char *ca_strp_days[] = {
|
|
628
|
+
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
|
|
629
|
+
"Saturday"
|
|
630
|
+
};
|
|
631
|
+
|
|
632
|
+
/* Whether a number follows directly: a digit, or a numeric directive. */
|
|
633
|
+
static int
|
|
634
|
+
ca_strp_number_next (const char *f, long flen, long fi)
|
|
635
|
+
{
|
|
636
|
+
char c;
|
|
637
|
+
if ( fi >= flen ) {
|
|
638
|
+
return 0;
|
|
639
|
+
}
|
|
640
|
+
c = f[fi];
|
|
641
|
+
if ( c >= '0' && c <= '9' ) {
|
|
642
|
+
return 1;
|
|
643
|
+
}
|
|
644
|
+
if ( c == '%' && fi + 1 < flen ) {
|
|
645
|
+
c = f[fi + 1];
|
|
646
|
+
if ( c == 'E' || c == 'O' ) {
|
|
647
|
+
c = ( fi + 2 < flen ) ? f[fi + 2] : '\0';
|
|
648
|
+
}
|
|
649
|
+
return c != '\0' && ( strchr("CDdeFGgHIjkLlMmNQRrSsTUuVvWwXxYy", c) != NULL
|
|
650
|
+
|| ( c >= '0' && c <= '9' ) );
|
|
651
|
+
}
|
|
652
|
+
return 0;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/* Up to `width` digits (width 0: as many as there are). Returns the count
|
|
656
|
+
read, with the value of the first 18 in *v. */
|
|
657
|
+
static long
|
|
658
|
+
ca_strp_digits (const char *s, long n, long *si, long width, int64_t *v)
|
|
659
|
+
{
|
|
660
|
+
long count = 0;
|
|
661
|
+
*v = 0;
|
|
662
|
+
while ( *si < n && s[*si] >= '0' && s[*si] <= '9'
|
|
663
|
+
&& ( width == 0 || count < width ) ) {
|
|
664
|
+
if ( count < 18 ) {
|
|
665
|
+
*v = *v * 10 + ( s[*si] - '0' );
|
|
666
|
+
}
|
|
667
|
+
(*si)++;
|
|
668
|
+
count++;
|
|
669
|
+
}
|
|
670
|
+
return count;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/* A one-or-two-digit field: %d %e %H %k %I %l %M %m %S. */
|
|
674
|
+
static int
|
|
675
|
+
ca_strp_small (const char *s, long n, long *si, int space_form, int strict,
|
|
676
|
+
int number_next, int64_t lo, int64_t hi, int64_t *v)
|
|
677
|
+
{
|
|
678
|
+
long count;
|
|
679
|
+
if ( space_form && ! strict && s[*si] == ' ' ) {
|
|
680
|
+
(*si)++;
|
|
681
|
+
count = ca_strp_digits(s, n, si, 1, v);
|
|
682
|
+
}
|
|
683
|
+
else {
|
|
684
|
+
count = ca_strp_digits(s, n, si, 2, v);
|
|
685
|
+
if ( strict && number_next && count != 2 ) {
|
|
686
|
+
return CA_STRP_FAIL;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
if ( count == 0 || *v < lo || *v > hi ) {
|
|
690
|
+
return CA_STRP_FAIL;
|
|
691
|
+
}
|
|
692
|
+
return CA_STRP_OK;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
static int
|
|
696
|
+
ca_strp_name (const char *s, long n, long *si, const char **names, int count)
|
|
697
|
+
{
|
|
698
|
+
int i;
|
|
699
|
+
for (i = 0; i < count; i++) {
|
|
700
|
+
long len = (long) strlen(names[i]);
|
|
701
|
+
if ( n - *si >= len && strncasecmp(names[i], s + *si, len) == 0 ) {
|
|
702
|
+
*si += len;
|
|
703
|
+
return i;
|
|
704
|
+
}
|
|
705
|
+
if ( n - *si >= 3 && strncasecmp(names[i], s + *si, 3) == 0 ) {
|
|
706
|
+
*si += 3;
|
|
707
|
+
return i;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
return -1;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
static int
|
|
714
|
+
ca_strp_is_alpha (char c)
|
|
715
|
+
{
|
|
716
|
+
return ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' );
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
/* %z: [+-]hh, [+-]hhmm, [+-]hh:mm, Z, UTC, GMT. */
|
|
720
|
+
static int
|
|
721
|
+
ca_strp_zone (const char *s, long n, long *si, int strict, int64_t *offset)
|
|
722
|
+
{
|
|
723
|
+
int unknown = strict ? CA_STRP_FAIL : CA_STRP_DEFER;
|
|
724
|
+
long i = *si;
|
|
725
|
+
if ( s[i] == '+' || s[i] == '-' ) {
|
|
726
|
+
int negative = ( s[i] == '-' );
|
|
727
|
+
int64_t hh, mm = 0;
|
|
728
|
+
long count;
|
|
729
|
+
i++;
|
|
730
|
+
count = ca_strp_digits(s, n, &i, 0, &hh);
|
|
731
|
+
if ( count == 4 ) {
|
|
732
|
+
mm = hh % 100;
|
|
733
|
+
hh = hh / 100;
|
|
734
|
+
}
|
|
735
|
+
else if ( count == 2 ) {
|
|
736
|
+
if ( i < n && s[i] == ':' ) {
|
|
737
|
+
i++;
|
|
738
|
+
if ( ca_strp_digits(s, n, &i, 0, &mm) != 2 ) {
|
|
739
|
+
return unknown;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
else {
|
|
744
|
+
return unknown;
|
|
745
|
+
}
|
|
746
|
+
if ( i < n && ( s[i] == ':' || s[i] == '.' || s[i] == ','
|
|
747
|
+
|| ( s[i] >= '0' && s[i] <= '9' ) ) ) {
|
|
748
|
+
return unknown;
|
|
749
|
+
}
|
|
750
|
+
if ( hh > 23 || mm > 59 ) {
|
|
751
|
+
return unknown;
|
|
752
|
+
}
|
|
753
|
+
*offset = ( hh * 3600 + mm * 60 ) * ( negative ? -1 : 1 );
|
|
754
|
+
*si = i;
|
|
755
|
+
return CA_STRP_OK;
|
|
756
|
+
}
|
|
757
|
+
if ( ca_strp_is_alpha(s[i]) ) {
|
|
758
|
+
long len = 0;
|
|
759
|
+
while ( i + len < n && ca_strp_is_alpha(s[i + len]) ) {
|
|
760
|
+
len++;
|
|
761
|
+
}
|
|
762
|
+
if ( ( len == 1 && s[i] == 'Z' )
|
|
763
|
+
|| ( len == 3 && ( strncmp(s + i, "UTC", 3) == 0
|
|
764
|
+
|| strncmp(s + i, "GMT", 3) == 0 ) ) ) {
|
|
765
|
+
long j = i + len;
|
|
766
|
+
/* "UTC+09:00", "GMT standard time", "UTC dst" mean something else */
|
|
767
|
+
if ( j < n && ( s[j] == '+' || s[j] == '-' || s[j] == '.' ) ) {
|
|
768
|
+
return unknown;
|
|
769
|
+
}
|
|
770
|
+
if ( j < n && s[j] == ' ' ) {
|
|
771
|
+
long k = j;
|
|
772
|
+
while ( k < n && s[k] == ' ' ) {
|
|
773
|
+
k++;
|
|
774
|
+
}
|
|
775
|
+
if ( k < n && ca_strp_is_alpha(s[k]) ) {
|
|
776
|
+
return unknown;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
*offset = 0;
|
|
780
|
+
*si = j;
|
|
781
|
+
return CA_STRP_OK;
|
|
782
|
+
}
|
|
783
|
+
return unknown;
|
|
784
|
+
}
|
|
785
|
+
return CA_STRP_FAIL;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
static int ca_strp_run (const char *s, long n, long *si,
|
|
789
|
+
const char *f, long flen, int strict, ca_strp_t *t);
|
|
790
|
+
|
|
791
|
+
static int
|
|
792
|
+
ca_strp_sub (const char *s, long n, long *si, const char *sub, int strict,
|
|
793
|
+
ca_strp_t *t)
|
|
794
|
+
{
|
|
795
|
+
return ca_strp_run(s, n, si, sub, (long) strlen(sub), strict, t);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
static int
|
|
799
|
+
ca_strp_run (const char *s, long n, long *si, const char *f, long flen,
|
|
800
|
+
int strict, ca_strp_t *t)
|
|
801
|
+
{
|
|
802
|
+
long fi = 0;
|
|
803
|
+
while ( fi < flen ) {
|
|
804
|
+
char c = f[fi];
|
|
805
|
+
if ( ca_time_text_is_space(c) ) {
|
|
806
|
+
while ( *si < n && ca_time_text_is_space(s[*si]) ) {
|
|
807
|
+
(*si)++;
|
|
808
|
+
}
|
|
809
|
+
while ( fi < flen && ca_time_text_is_space(f[fi]) ) {
|
|
810
|
+
fi++;
|
|
811
|
+
}
|
|
812
|
+
continue;
|
|
813
|
+
}
|
|
814
|
+
if ( *si >= n ) {
|
|
815
|
+
return CA_STRP_FAIL;
|
|
816
|
+
}
|
|
817
|
+
if ( c != '%' ) {
|
|
818
|
+
if ( s[*si] != c ) {
|
|
819
|
+
return CA_STRP_FAIL;
|
|
820
|
+
}
|
|
821
|
+
(*si)++;
|
|
822
|
+
fi++;
|
|
823
|
+
continue;
|
|
824
|
+
}
|
|
825
|
+
{
|
|
826
|
+
int rc = CA_STRP_OK;
|
|
827
|
+
int number_next;
|
|
828
|
+
int64_t v;
|
|
829
|
+
char d = ( fi + 1 < flen ) ? f[fi + 1] : '\0';
|
|
830
|
+
fi += 2;
|
|
831
|
+
number_next = ca_strp_number_next(f, flen, fi);
|
|
832
|
+
switch ( d ) {
|
|
833
|
+
case 'a': case 'A':
|
|
834
|
+
if ( ca_strp_name(s, n, si, ca_strp_days, 7) < 0 ) {
|
|
835
|
+
return CA_STRP_FAIL;
|
|
836
|
+
}
|
|
837
|
+
break;
|
|
838
|
+
case 'b': case 'B': case 'h': {
|
|
839
|
+
int m = ca_strp_name(s, n, si, ca_strp_months, 12);
|
|
840
|
+
if ( m < 0 ) {
|
|
841
|
+
return CA_STRP_FAIL;
|
|
842
|
+
}
|
|
843
|
+
t->mon = m + 1;
|
|
844
|
+
break;
|
|
845
|
+
}
|
|
846
|
+
case 'd': case 'e':
|
|
847
|
+
rc = ca_strp_small(s, n, si, 1, strict, number_next, 1, 31, &t->mday);
|
|
848
|
+
break;
|
|
849
|
+
case 'H': case 'k':
|
|
850
|
+
rc = ca_strp_small(s, n, si, 1, strict, number_next, 0, 24, &t->hour);
|
|
851
|
+
t->has_hour = 1;
|
|
852
|
+
break;
|
|
853
|
+
case 'I': case 'l':
|
|
854
|
+
rc = ca_strp_small(s, n, si, 1, strict, number_next, 1, 12, &t->hour);
|
|
855
|
+
t->has_hour = 1;
|
|
856
|
+
break;
|
|
857
|
+
case 'M':
|
|
858
|
+
rc = ca_strp_small(s, n, si, 0, strict, number_next, 0, 59, &t->min);
|
|
859
|
+
break;
|
|
860
|
+
case 'm':
|
|
861
|
+
rc = ca_strp_small(s, n, si, 0, strict, number_next, 1, 12, &t->mon);
|
|
862
|
+
break;
|
|
863
|
+
case 'S':
|
|
864
|
+
rc = ca_strp_small(s, n, si, 0, strict, number_next, 0, 60, &t->sec);
|
|
865
|
+
break;
|
|
866
|
+
case 'L': case 'N': {
|
|
867
|
+
int negative = 0;
|
|
868
|
+
long count, start, k;
|
|
869
|
+
int64_t ns = 0;
|
|
870
|
+
int rest = 0;
|
|
871
|
+
if ( ! strict && ( s[*si] == '+' || s[*si] == '-' ) ) {
|
|
872
|
+
negative = ( s[*si] == '-' );
|
|
873
|
+
(*si)++;
|
|
874
|
+
}
|
|
875
|
+
start = *si;
|
|
876
|
+
count = ca_strp_digits(s, n, si,
|
|
877
|
+
strict ? 9 : ( number_next ? ( d == 'L' ? 3 : 9 ) : 0 ),
|
|
878
|
+
&v);
|
|
879
|
+
if ( count == 0 ) {
|
|
880
|
+
return CA_STRP_FAIL;
|
|
881
|
+
}
|
|
882
|
+
for (k = 0; k < 9; k++) {
|
|
883
|
+
ns = ns * 10 + ( k < count ? s[start + k] - '0' : 0 );
|
|
884
|
+
}
|
|
885
|
+
for (k = 9; k < count; k++) {
|
|
886
|
+
rest |= ( s[start + k] != '0' );
|
|
887
|
+
}
|
|
888
|
+
if ( negative ) {
|
|
889
|
+
ns = - ns - ( rest ? 1 : 0 ); /* floor, as (fraction * 1e9).floor */
|
|
890
|
+
}
|
|
891
|
+
t->frac_ns = ns;
|
|
892
|
+
t->frac_digits = (int) count;
|
|
893
|
+
break;
|
|
894
|
+
}
|
|
895
|
+
case 'p': case 'P': {
|
|
896
|
+
char a, m;
|
|
897
|
+
int hour;
|
|
898
|
+
if ( n - *si < 2 ) {
|
|
899
|
+
return CA_STRP_FAIL;
|
|
900
|
+
}
|
|
901
|
+
a = s[*si];
|
|
902
|
+
hour = ( a == 'P' || a == 'p' ) ? 12 : 0;
|
|
903
|
+
if ( ! hour && ! ( a == 'A' || a == 'a' ) ) {
|
|
904
|
+
return CA_STRP_FAIL;
|
|
905
|
+
}
|
|
906
|
+
m = s[*si + 1];
|
|
907
|
+
if ( m == '.' && ! strict ) {
|
|
908
|
+
if ( n - *si < 4 || s[*si + 3] != '.' ) {
|
|
909
|
+
return CA_STRP_FAIL;
|
|
910
|
+
}
|
|
911
|
+
*si += 2;
|
|
912
|
+
m = s[*si];
|
|
913
|
+
}
|
|
914
|
+
if ( ! ( m == 'M' || m == 'm' ) ) {
|
|
915
|
+
return CA_STRP_FAIL;
|
|
916
|
+
}
|
|
917
|
+
*si += 2;
|
|
918
|
+
t->merid = hour;
|
|
919
|
+
break;
|
|
920
|
+
}
|
|
921
|
+
case 'Y': {
|
|
922
|
+
int negative = 0;
|
|
923
|
+
long count;
|
|
924
|
+
if ( ! strict && ( s[*si] == '+' || s[*si] == '-' ) ) {
|
|
925
|
+
negative = ( s[*si] == '-' );
|
|
926
|
+
(*si)++;
|
|
927
|
+
}
|
|
928
|
+
count = ca_strp_digits(s, n, si, ( strict || number_next ) ? 4 : 0, &v);
|
|
929
|
+
if ( count == 0 || ( strict && count != 4 ) ) {
|
|
930
|
+
return CA_STRP_FAIL;
|
|
931
|
+
}
|
|
932
|
+
if ( count > 9 ) {
|
|
933
|
+
return CA_STRP_DEFER; /* a year past int64 days */
|
|
934
|
+
}
|
|
935
|
+
t->year = negative ? -v : v;
|
|
936
|
+
t->has_year = 1;
|
|
937
|
+
break;
|
|
938
|
+
}
|
|
939
|
+
case 'y': {
|
|
940
|
+
long count = ca_strp_digits(s, n, si, 2, &v);
|
|
941
|
+
if ( count == 0 || ( strict && count != 2 ) ) {
|
|
942
|
+
return CA_STRP_FAIL;
|
|
943
|
+
}
|
|
944
|
+
t->year = v + ( v >= 69 ? 1900 : 2000 );
|
|
945
|
+
t->has_year = 1;
|
|
946
|
+
break;
|
|
947
|
+
}
|
|
948
|
+
case 'z': case 'Z':
|
|
949
|
+
rc = ca_strp_zone(s, n, si, strict, &t->offset);
|
|
950
|
+
break;
|
|
951
|
+
case 'n': case 't':
|
|
952
|
+
rc = ca_strp_sub(s, n, si, " ", strict, t);
|
|
953
|
+
break;
|
|
954
|
+
case 'D': case 'x':
|
|
955
|
+
rc = ca_strp_sub(s, n, si, "%m/%d/%y", strict, t);
|
|
956
|
+
break;
|
|
957
|
+
case 'F':
|
|
958
|
+
rc = ca_strp_sub(s, n, si, "%Y-%m-%d", strict, t);
|
|
959
|
+
break;
|
|
960
|
+
case 'R':
|
|
961
|
+
rc = ca_strp_sub(s, n, si, "%H:%M", strict, t);
|
|
962
|
+
break;
|
|
963
|
+
case 'T': case 'X':
|
|
964
|
+
rc = ca_strp_sub(s, n, si, "%H:%M:%S", strict, t);
|
|
965
|
+
break;
|
|
966
|
+
case '%':
|
|
967
|
+
if ( s[*si] != '%' ) {
|
|
968
|
+
return CA_STRP_FAIL;
|
|
969
|
+
}
|
|
970
|
+
(*si)++;
|
|
971
|
+
break;
|
|
972
|
+
default:
|
|
973
|
+
return CA_STRP_FAIL; /* not reached: checked up front */
|
|
974
|
+
}
|
|
975
|
+
if ( rc != CA_STRP_OK ) {
|
|
976
|
+
return rc;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
return CA_STRP_OK;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
/* Whether every directive of the format is one ca_strp_run reads. */
|
|
984
|
+
static int
|
|
985
|
+
ca_strp_supported (const char *f, long flen)
|
|
986
|
+
{
|
|
987
|
+
long i;
|
|
988
|
+
for (i = 0; i < flen; i++) {
|
|
989
|
+
if ( f[i] == '%' ) {
|
|
990
|
+
char d = ( i + 1 < flen ) ? f[i + 1] : '\0';
|
|
991
|
+
if ( d == '\0' || strchr("YymdeHkIlMSNLpPbBhaAzZntDFRTXx%", d) == NULL ) {
|
|
992
|
+
return 0;
|
|
993
|
+
}
|
|
994
|
+
i++;
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
return 1;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
/* One text in a format: CA_STRP_OK with the fields in *t, CA_STRP_FAIL,
|
|
1001
|
+
or CA_STRP_DEFER. */
|
|
1002
|
+
static int
|
|
1003
|
+
ca_strp_text (VALUE str, const char *f, long flen, int strict, ca_strp_t *t)
|
|
1004
|
+
{
|
|
1005
|
+
const char *s = RSTRING_PTR(str);
|
|
1006
|
+
long n = RSTRING_LEN(str);
|
|
1007
|
+
long si = 0;
|
|
1008
|
+
int rc;
|
|
1009
|
+
memset(t, 0, sizeof(*t));
|
|
1010
|
+
t->mon = 1;
|
|
1011
|
+
t->mday = 1;
|
|
1012
|
+
t->merid = -1;
|
|
1013
|
+
rc = ca_strp_run(s, n, &si, f, flen, strict, t);
|
|
1014
|
+
if ( rc != CA_STRP_OK ) {
|
|
1015
|
+
return rc;
|
|
1016
|
+
}
|
|
1017
|
+
while ( si < n && ca_time_text_is_space(s[si]) ) {
|
|
1018
|
+
si++;
|
|
1019
|
+
}
|
|
1020
|
+
if ( si < n || ! t->has_year ) {
|
|
1021
|
+
return CA_STRP_FAIL;
|
|
1022
|
+
}
|
|
1023
|
+
if ( t->merid >= 0 && t->has_hour ) {
|
|
1024
|
+
t->hour = t->hour % 12 + t->merid;
|
|
1025
|
+
}
|
|
1026
|
+
/* Hour 24 is the end of the day, 24:00:00, and nothing past it: 24:30
|
|
1027
|
+
would otherwise roll into the next day. */
|
|
1028
|
+
if ( t->hour == 24 && ( t->min || t->sec || t->frac_ns ) ) {
|
|
1029
|
+
return CA_STRP_FAIL;
|
|
1030
|
+
}
|
|
1031
|
+
if ( t->mday > ca_time_text_month_days(t->year, t->mon) ) {
|
|
1032
|
+
return CA_STRP_FAIL;
|
|
1033
|
+
}
|
|
1034
|
+
return CA_STRP_OK;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
/* CArray#__strptime_fields__(format, strict)
|
|
1038
|
+
-> [year, mon, day, sec_of_day, frac_ns, offset, present,
|
|
1039
|
+
unreadable, deferred, fraction_digits] or nil
|
|
1040
|
+
|
|
1041
|
+
Reads every cell of an object array in a strptime format into the int64
|
|
1042
|
+
field arrays CArray.__time_ticks_from_fields__ takes (present is uint8).
|
|
1043
|
+
nil when the format has a directive this reader does not read. A cell
|
|
1044
|
+
that holds text and does not read is listed by its address in
|
|
1045
|
+
`unreadable`; a cell that is not a String, or holds a zone or a year
|
|
1046
|
+
this reader leaves to Date._strptime, in `deferred`; nil and masked
|
|
1047
|
+
cells in neither, and blank text too when strict (a blank cell does not
|
|
1048
|
+
read in a format, as Date._strptime has it). fraction_digits is the widest fraction of a
|
|
1049
|
+
second read. */
|
|
1050
|
+
static VALUE
|
|
1051
|
+
rb_ca_strptime_fields (VALUE self, VALUE rformat, VALUE rstrict)
|
|
1052
|
+
{
|
|
1053
|
+
volatile VALUE src = self, rf = rformat;
|
|
1054
|
+
VALUE fields[7];
|
|
1055
|
+
volatile VALUE unreadable, deferred;
|
|
1056
|
+
CArray *ca, *cf[7];
|
|
1057
|
+
int64_t *y, *mo, *d, *sod, *frac, *off;
|
|
1058
|
+
uint8_t *present;
|
|
1059
|
+
VALUE *cells;
|
|
1060
|
+
boolean8_t *m_in;
|
|
1061
|
+
const char *f;
|
|
1062
|
+
long flen;
|
|
1063
|
+
int strict = RTEST(rstrict);
|
|
1064
|
+
int fraction = 0;
|
|
1065
|
+
ca_size_t i;
|
|
1066
|
+
int k;
|
|
1067
|
+
|
|
1068
|
+
StringValue(rf);
|
|
1069
|
+
f = RSTRING_PTR(rf);
|
|
1070
|
+
flen = RSTRING_LEN(rf);
|
|
1071
|
+
if ( ! ca_strp_supported(f, flen) ) {
|
|
1072
|
+
return Qnil;
|
|
1073
|
+
}
|
|
1074
|
+
TypedData_Get_Struct(src, CArray, &carray_data_type, ca);
|
|
1075
|
+
if ( ca->data_type != CA_OBJECT ) {
|
|
1076
|
+
rb_raise(rb_eArgError, "strptime reading needs an object array");
|
|
1077
|
+
}
|
|
1078
|
+
if ( ! ca_is_entity(ca) ) {
|
|
1079
|
+
src = rb_ca_copy(src);
|
|
1080
|
+
TypedData_Get_Struct(src, CArray, &carray_data_type, ca);
|
|
1081
|
+
}
|
|
1082
|
+
for (k = 0; k < 7; k++) {
|
|
1083
|
+
fields[k] = rb_carray_new(k == 6 ? CA_UINT8 : CA_INT64, 1, &ca->elements, 0, NULL);
|
|
1084
|
+
TypedData_Get_Struct(fields[k], CArray, &carray_data_type, cf[k]);
|
|
1085
|
+
}
|
|
1086
|
+
y = (int64_t *) cf[0]->ptr;
|
|
1087
|
+
mo = (int64_t *) cf[1]->ptr;
|
|
1088
|
+
d = (int64_t *) cf[2]->ptr;
|
|
1089
|
+
sod = (int64_t *) cf[3]->ptr;
|
|
1090
|
+
frac = (int64_t *) cf[4]->ptr;
|
|
1091
|
+
off = (int64_t *) cf[5]->ptr;
|
|
1092
|
+
present = (uint8_t *) cf[6]->ptr;
|
|
1093
|
+
unreadable = rb_ary_new();
|
|
1094
|
+
deferred = rb_ary_new();
|
|
1095
|
+
|
|
1096
|
+
cells = (VALUE *) ca->ptr;
|
|
1097
|
+
m_in = ca_has_mask(ca) ? (boolean8_t *) ca->mask->ptr : NULL;
|
|
1098
|
+
for (i = 0; i < ca->elements; i++) {
|
|
1099
|
+
VALUE v = cells[i];
|
|
1100
|
+
ca_strp_t t;
|
|
1101
|
+
int rc;
|
|
1102
|
+
y[i] = 1970; mo[i] = 1; d[i] = 1; sod[i] = 0; frac[i] = 0; off[i] = 0;
|
|
1103
|
+
present[i] = 0;
|
|
1104
|
+
if ( ( m_in && m_in[i] ) || NIL_P(v) ) {
|
|
1105
|
+
continue;
|
|
1106
|
+
}
|
|
1107
|
+
if ( ! RB_TYPE_P(v, T_STRING) ) {
|
|
1108
|
+
rb_ary_push(deferred, SIZET2NUM(i));
|
|
1109
|
+
continue;
|
|
1110
|
+
}
|
|
1111
|
+
if ( strict ) { /* finding a format: blank is missing */
|
|
1112
|
+
const char *s = RSTRING_PTR(v);
|
|
1113
|
+
long n = RSTRING_LEN(v), j = 0;
|
|
1114
|
+
while ( j < n && ca_time_text_is_space(s[j]) ) {
|
|
1115
|
+
j++;
|
|
1116
|
+
}
|
|
1117
|
+
if ( j == n ) {
|
|
1118
|
+
continue;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
rc = ca_strp_text(v, f, flen, strict, &t);
|
|
1122
|
+
if ( rc == CA_STRP_OK ) {
|
|
1123
|
+
y[i] = t.year;
|
|
1124
|
+
mo[i] = t.mon;
|
|
1125
|
+
d[i] = t.mday;
|
|
1126
|
+
sod[i] = t.hour * 3600 + t.min * 60 + t.sec;
|
|
1127
|
+
frac[i] = t.frac_ns;
|
|
1128
|
+
off[i] = t.offset;
|
|
1129
|
+
present[i] = 1;
|
|
1130
|
+
if ( t.frac_digits > fraction ) {
|
|
1131
|
+
fraction = t.frac_digits;
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
else if ( rc == CA_STRP_DEFER ) {
|
|
1135
|
+
rb_ary_push(deferred, SIZET2NUM(i));
|
|
1136
|
+
}
|
|
1137
|
+
else {
|
|
1138
|
+
rb_ary_push(unreadable, SIZET2NUM(i));
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
RB_GC_GUARD(src);
|
|
1142
|
+
RB_GC_GUARD(rf);
|
|
1143
|
+
return rb_ary_new_from_args(10, fields[0], fields[1], fields[2], fields[3],
|
|
1144
|
+
fields[4], fields[5], fields[6],
|
|
1145
|
+
unreadable, deferred, INT2NUM(fraction));
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
/* CArray.__strptime_fits__(text, formats) -> indices
|
|
1149
|
+
|
|
1150
|
+
The indices of the formats `text` reads in, strictly. */
|
|
1151
|
+
static VALUE
|
|
1152
|
+
rb_ca_s_strptime_fits (VALUE klass, VALUE text, VALUE formats)
|
|
1153
|
+
{
|
|
1154
|
+
volatile VALUE out = rb_ary_new();
|
|
1155
|
+
long i;
|
|
1156
|
+
StringValue(text);
|
|
1157
|
+
Check_Type(formats, T_ARRAY);
|
|
1158
|
+
for (i = 0; i < RARRAY_LEN(formats); i++) {
|
|
1159
|
+
VALUE f = rb_ary_entry(formats, i);
|
|
1160
|
+
ca_strp_t t;
|
|
1161
|
+
StringValue(f);
|
|
1162
|
+
if ( ca_strp_supported(RSTRING_PTR(f), RSTRING_LEN(f))
|
|
1163
|
+
&& ca_strp_text(text, RSTRING_PTR(f), RSTRING_LEN(f), 1, &t) == CA_STRP_OK ) {
|
|
1164
|
+
rb_ary_push(out, LONG2NUM(i));
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
return out;
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
void
|
|
1171
|
+
Init_carray_time_text (void)
|
|
1172
|
+
{
|
|
1173
|
+
/* Internal: CAFrame reads text columns as time with this reader. */
|
|
1174
|
+
rb_define_method(rb_cCArray, "__parse_time_text__", rb_ca_parse_time_text, -1);
|
|
1175
|
+
/* Internal: CArray.time turns parsed fields into ticks with this. */
|
|
1176
|
+
rb_define_singleton_method(rb_cCArray, "__time_ticks_from_fields__",
|
|
1177
|
+
rb_ca_s_time_ticks_from_fields, 9);
|
|
1178
|
+
/* Internal: CArray.time and CAFrame read a strptime format with these. */
|
|
1179
|
+
rb_define_method(rb_cCArray, "__strptime_fields__", rb_ca_strptime_fields, 2);
|
|
1180
|
+
rb_define_singleton_method(rb_cCArray, "__strptime_fits__",
|
|
1181
|
+
rb_ca_s_strptime_fits, 2);
|
|
1182
|
+
}
|