edn_turbo 0.5.7 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,25 @@
1
+ // The MIT License (MIT)
2
+
3
+ // Copyright (c) 2015-2019 Ed Porras
4
+
5
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ // of this software and associated documentation files (the "Software"), to deal
7
+ // in the Software without restriction, including without limitation the rights
8
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ // copies of the Software, and to permit persons to whom the Software is
10
+ // furnished to do so, subject to the following conditions:
11
+
12
+ // The above copyright notice and this permission notice shall be included in
13
+ // all copies or substantial portions of the Software.
14
+
15
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ // THE SOFTWARE.
22
+
1
23
  #include <iostream>
2
24
  #include <string>
3
25
  #include <sstream>
@@ -11,230 +33,230 @@
11
33
 
12
34
  namespace edn
13
35
  {
14
- //
15
- // used to determine max number of chars in string value of a type
16
- template <typename T>
17
- static std::size_t get_max_chars(T)
18
- {
19
- std::stringstream s;
20
- s << std::fixed << std::numeric_limits<T>::max();
21
- return s.str().length();
22
- }
23
-
24
- static const std::size_t LL_max_chars = get_max_chars<>((long) 1);
25
- static const std::size_t LD_max_chars = get_max_chars<>((double) 1);
26
-
27
- //
28
- // throw runtime error
29
- static void throw_error(int error)
30
- {
31
- if (error == 0)
32
- return;
33
-
34
- VALUE err = rb_errinfo();
35
- rb_raise(CLASS_OF(err), "%s", RSTRING_PTR(rb_obj_as_string(err)));
36
- }
37
-
38
- // =================================================================
39
- // work-around for idiotic rb_protect convention in order to avoid
40
- // using ruby/rice
41
- //
42
- typedef VALUE (edn_rb_f_type)( VALUE arg );
43
-
44
- // we're using at most 2 args
45
- struct prot_args {
46
- prot_args(VALUE r, ID m) :
47
- receiver(r), method(m), count(0) {
48
- }
49
- prot_args(VALUE r, ID m, VALUE arg) :
50
- receiver(r), method(m), count(1) {
51
- args[0] = arg;
52
- }
53
- prot_args(VALUE r, ID m, VALUE arg1, VALUE arg2) :
54
- receiver(r), method(m), count(2) {
55
- args[0] = arg1;
56
- args[1] = arg2;
57
- }
58
-
59
- VALUE call() const {
60
- return ((count == 0) ?
61
- rb_funcall( receiver, method, 0 ) :
62
- rb_funcall2( receiver, method, count, args ));
63
- }
64
-
65
- private:
66
- VALUE receiver;
67
- ID method;
68
- int count;
69
- VALUE args[2];
70
- };
71
-
72
- // this allows us to wrap with rb_protect()
73
- static inline VALUE edn_wrap_funcall2( VALUE arg ) {
74
- const prot_args* a = reinterpret_cast<const prot_args*>(arg);
75
- if (a)
76
- return a->call();
77
- return Qnil;
78
- }
79
-
80
- static inline VALUE edn_prot_rb_funcall( edn_rb_f_type func, VALUE args ) {
81
- int error;
82
- VALUE s = rb_protect( func, args, &error );
83
- if (error) throw_error(error);
84
- return s;
85
- }
86
-
87
- static inline VALUE edn_prot_rb_new_str(const char* str) {
88
- int error;
89
- VALUE s = rb_protect( reinterpret_cast<VALUE (*)(VALUE)>(rb_str_new_cstr),
90
- reinterpret_cast<VALUE>(str), &error );
91
- if (error) throw_error(error);
92
- return s;
93
- }
94
-
95
- static inline VALUE edn_rb_enc_associate_utf8(VALUE str) {
96
- return rb_enc_associate(str, rb_utf8_encoding() );
97
- }
98
-
99
- // =================================================================
100
- // utils
101
- namespace util
102
- {
103
- // utility method to convert a primitive in string form to a
104
- // ruby type
105
- template <class T>
106
- static inline T buftotype(const char* p, std::size_t len) {
107
- T val;
108
- std::string buf;
109
- buf.append(p, len);
110
- std::istringstream(buf) >> val;
111
- return val;
112
- }
113
-
114
- //
115
- // convert to int.. if string rep has more digits than long can
116
- // hold, call into ruby to get a big num
117
- VALUE integer_to_ruby(const char* str, std::size_t len)
118
- {
119
- // if something bigger than a long is needed, call into
120
- // ruby side to get the correct value
121
- if (str[len-1] == 'M' || len >= LL_max_chars)
122
- {
123
- std::string buf(str, len);
124
- VALUE vs = edn_prot_rb_new_str(buf.c_str());
125
- prot_args args(vs, RUBY_STRING_TO_I_METHOD);
126
- return edn_prot_rb_funcall( edn_wrap_funcall2, reinterpret_cast<VALUE>(&args) );
127
- }
128
-
129
- return LONG2NUM(buftotype<long>(str, len));
130
- }
131
-
132
- //
133
- // as above.. TODO: check exponential..
134
- VALUE float_to_ruby(const char* str, std::size_t len)
135
- {
136
- // if big decimal is needed, call into ruby side to get
137
- // the correct value
138
- if (str[len-1] == 'M' || len >= LD_max_chars)
139
- {
140
- std::string buf(str, len);
141
- VALUE vs = edn_prot_rb_new_str(buf.c_str());
142
-
143
- if (str[len-1] == 'M') {
144
- return call_module_fn(rb_mEDN, EDN_MAKE_BIG_DECIMAL_METHOD, vs);
145
- }
146
-
147
- prot_args args(vs, RUBY_STRING_TO_F_METHOD);
148
- return edn_prot_rb_funcall( edn_wrap_funcall2, reinterpret_cast<VALUE>(&args) );
149
- }
150
-
151
- return rb_float_new(buftotype<double>(str, len));
152
- }
153
-
154
-
155
- //
156
- // read from a StringIO - expensive!!!
157
- //
158
- VALUE ruby_io_read(VALUE io)
159
- {
160
- prot_args args(io, RUBY_READ_METHOD);
36
+ //
37
+ // used to determine max number of chars in string value of a type
38
+ template <typename T>
39
+ static std::size_t get_max_chars(T)
40
+ {
41
+ std::stringstream s;
42
+ s << std::fixed << std::numeric_limits<T>::max();
43
+ return s.str().length();
44
+ }
45
+
46
+ static const std::size_t LL_max_chars = get_max_chars<>(1l);
47
+ static const std::size_t LD_max_chars = get_max_chars<>(1.0);
48
+
49
+ //
50
+ // throw runtime error
51
+ static void throw_error(int error)
52
+ {
53
+ if (error == 0)
54
+ return;
55
+
56
+ VALUE err = rb_errinfo();
57
+ rb_raise(CLASS_OF(err), "%s", RSTRING_PTR(rb_obj_as_string(err)));
58
+ }
59
+
60
+ // =================================================================
61
+ // work-around for idiotic rb_protect convention in order to avoid
62
+ // using ruby/rice
63
+ //
64
+ typedef VALUE (edn_rb_f_type)( VALUE arg );
65
+
66
+ // we're using at most 2 args
67
+ struct prot_args {
68
+ prot_args(VALUE r, ID m) :
69
+ receiver(r), method(m), count(0) {
70
+ }
71
+ prot_args(VALUE r, ID m, VALUE arg) :
72
+ receiver(r), method(m), count(1) {
73
+ args[0] = arg;
74
+ }
75
+ prot_args(VALUE r, ID m, VALUE arg1, VALUE arg2) :
76
+ receiver(r), method(m), count(2) {
77
+ args[0] = arg1;
78
+ args[1] = arg2;
79
+ }
80
+
81
+ VALUE call() const {
82
+ return ((count == 0) ?
83
+ rb_funcall( receiver, method, 0 ) :
84
+ rb_funcall2( receiver, method, count, args ));
85
+ }
86
+
87
+ private:
88
+ VALUE receiver;
89
+ ID method;
90
+ int count;
91
+ VALUE args[2];
92
+ };
93
+
94
+ // this allows us to wrap with rb_protect()
95
+ static inline VALUE edn_wrap_funcall2( VALUE arg ) {
96
+ const prot_args* a = reinterpret_cast<const prot_args*>(arg);
97
+ if (a)
98
+ return a->call();
99
+ return Qnil;
100
+ }
101
+
102
+ static inline VALUE edn_prot_rb_funcall( edn_rb_f_type func, VALUE args ) {
103
+ int error;
104
+ VALUE s = rb_protect( func, args, &error );
105
+ if (error) throw_error(error);
106
+ return s;
107
+ }
108
+
109
+ static inline VALUE edn_prot_rb_new_str(const char* str) {
110
+ int error;
111
+ VALUE s = rb_protect( reinterpret_cast<VALUE (*)(VALUE)>(rb_str_new_cstr),
112
+ reinterpret_cast<VALUE>(str), &error );
113
+ if (error) throw_error(error);
114
+ return s;
115
+ }
116
+
117
+ static inline VALUE edn_rb_enc_associate_utf8(VALUE str) {
118
+ return rb_enc_associate(str, rb_utf8_encoding() );
119
+ }
120
+
121
+ // =================================================================
122
+ // utils
123
+ namespace util
124
+ {
125
+ // utility method to convert a primitive in string form to a
126
+ // ruby type
127
+ template <class T>
128
+ static inline T buftotype(const char* p, std::size_t len) {
129
+ T val;
130
+ std::string buf;
131
+ buf.append(p, len);
132
+ std::istringstream(buf) >> val;
133
+ return val;
134
+ }
135
+
136
+ //
137
+ // convert to int.. if string rep has more digits than long can
138
+ // hold, call into ruby to get a big num
139
+ VALUE integer_to_ruby(const char* str, std::size_t len)
140
+ {
141
+ // if something bigger than a long is needed, call into
142
+ // ruby side to get the correct value
143
+ if (str[len-1] == 'M' || len >= LL_max_chars)
144
+ {
145
+ std::string buf(str, len);
146
+ VALUE vs = edn_prot_rb_new_str(buf.c_str());
147
+ prot_args args(vs, RUBY_STRING_TO_I_METHOD);
161
148
  return edn_prot_rb_funcall( edn_wrap_funcall2, reinterpret_cast<VALUE>(&args) );
162
- }
163
-
164
- //
165
- // copies the string data, unescaping any present values that need to be replaced
166
- //
167
- bool parse_byte_stream(const char *p_start, const char *p_end, VALUE& v_utf8, bool encode)
168
- {
169
- if (p_end > p_start) {
170
- std::string buf;
171
-
172
- if (encode) {
173
- if (!util::unicode::to_utf8(p_start, (uint32_t) (p_end - p_start), buf))
174
- return false;
175
- }
176
- else {
177
- buf.append(p_start, p_end - p_start);
178
- }
179
-
180
- // utf-8 encode
181
- VALUE vs = edn_prot_rb_new_str(buf.c_str());
182
- int error;
183
- v_utf8 = rb_protect( edn_rb_enc_associate_utf8, vs, &error);
184
- if (error) throw_error(error);
185
- return true;
186
- } else if (p_end == p_start) {
187
- v_utf8 = rb_str_new("", 0);
188
- return true;
149
+ }
150
+
151
+ return LONG2NUM(buftotype<long>(str, len));
152
+ }
153
+
154
+ //
155
+ // as above.. TODO: check exponential..
156
+ VALUE float_to_ruby(const char* str, std::size_t len)
157
+ {
158
+ // if big decimal is needed, call into ruby side to get
159
+ // the correct value
160
+ if (str[len-1] == 'M' || len >= LD_max_chars)
161
+ {
162
+ std::string buf(str, len);
163
+ VALUE vs = edn_prot_rb_new_str(buf.c_str());
164
+
165
+ if (str[len-1] == 'M') {
166
+ return call_module_fn(rb_mEDN, EDN_MAKE_BIG_DECIMAL_METHOD, vs);
189
167
  }
190
168
 
191
- return false;
192
- }
193
-
194
- //
195
- // handles things like \c, \newline
196
- //
197
- bool parse_escaped_char(const char *p, const char *pe, VALUE& v)
198
- {
169
+ prot_args args(vs, RUBY_STRING_TO_F_METHOD);
170
+ return edn_prot_rb_funcall( edn_wrap_funcall2, reinterpret_cast<VALUE>(&args) );
171
+ }
172
+
173
+ return rb_float_new(buftotype<double>(str, len));
174
+ }
175
+
176
+
177
+ //
178
+ // read from a StringIO - handled from ruby side
179
+ //
180
+ VALUE ruby_io_read(VALUE io)
181
+ {
182
+ prot_args args(io, RUBY_READ_METHOD);
183
+ return edn_prot_rb_funcall( edn_wrap_funcall2, reinterpret_cast<VALUE>(&args) );
184
+ }
185
+
186
+ //
187
+ // copies the string data, unescaping any present values that need to be replaced
188
+ //
189
+ bool parse_byte_stream(const char *p_start, const char *p_end, VALUE& v_utf8, bool encode)
190
+ {
191
+ if (p_end > p_start) {
199
192
  std::string buf;
200
- std::size_t len = pe - p;
201
- buf.append(p, len);
202
-
203
- if (len > 1) {
204
- if (buf == "newline") buf = '\n';
205
- else if (buf == "tab") buf = '\t';
206
- else if (buf == "return") buf = '\r';
207
- else if (buf == "space") buf = ' ';
208
- else if (buf == "formfeed") buf = '\f';
209
- else if (buf == "backspace") buf = '\b';
210
- // TODO: is this supported?
211
- else if (buf == "verticaltab") buf = '\v';
212
- else return false;
193
+
194
+ if (encode) {
195
+ if (!util::unicode::to_utf8(p_start, static_cast<uint32_t>(p_end - p_start), buf))
196
+ return false;
197
+ }
198
+ else {
199
+ buf.append(p_start, p_end - p_start);
213
200
  }
214
201
 
215
- v = edn_prot_rb_new_str( buf.c_str() );
202
+ // utf-8 encode
203
+ VALUE vs = edn_prot_rb_new_str(buf.c_str());
204
+ int error;
205
+ v_utf8 = rb_protect( edn_rb_enc_associate_utf8, vs, &error);
206
+ if (error) throw_error(error);
216
207
  return true;
217
- }
218
-
219
-
220
- //
221
- // get a set representation from the ruby side. See edn_turbo.rb
222
- VALUE call_module_fn(VALUE module, ID method)
223
- {
224
- prot_args args(module, method);
225
- return edn_prot_rb_funcall( edn_wrap_funcall2, reinterpret_cast<VALUE>(&args) );
226
- }
227
-
228
- VALUE call_module_fn(VALUE module, ID method, VALUE value)
229
- {
230
- prot_args args(module, method, value);
231
- return edn_prot_rb_funcall( edn_wrap_funcall2, reinterpret_cast<VALUE>(&args) );
232
- }
233
-
234
- VALUE call_module_fn(VALUE module, ID method, VALUE name, VALUE data)
235
- {
236
- prot_args args(module, method, name, data);
237
- return edn_prot_rb_funcall( edn_wrap_funcall2, reinterpret_cast<VALUE>(&args) );
238
- }
239
- }
208
+ } else if (p_end == p_start) {
209
+ v_utf8 = rb_str_new("", 0);
210
+ return true;
211
+ }
212
+
213
+ return false;
214
+ }
215
+
216
+ //
217
+ // handles things like \c, \newline
218
+ //
219
+ bool parse_escaped_char(const char *p, const char *pe, VALUE& v)
220
+ {
221
+ std::string buf;
222
+ std::size_t len = pe - p;
223
+ buf.append(p, len);
224
+
225
+ if (len > 1) {
226
+ if (buf == "newline") buf = '\n';
227
+ else if (buf == "tab") buf = '\t';
228
+ else if (buf == "return") buf = '\r';
229
+ else if (buf == "space") buf = ' ';
230
+ else if (buf == "formfeed") buf = '\f';
231
+ else if (buf == "backspace") buf = '\b';
232
+ // TODO: is this supported?
233
+ else if (buf == "verticaltab") buf = '\v';
234
+ else return false;
235
+ }
236
+
237
+ v = edn_prot_rb_new_str( buf.c_str() );
238
+ return true;
239
+ }
240
+
241
+
242
+ //
243
+ // get a set representation from the ruby side. See edn_turbo.rb
244
+ VALUE call_module_fn(VALUE module, ID method)
245
+ {
246
+ prot_args args(module, method);
247
+ return edn_prot_rb_funcall( edn_wrap_funcall2, reinterpret_cast<VALUE>(&args) );
248
+ }
249
+
250
+ VALUE call_module_fn(VALUE module, ID method, VALUE value)
251
+ {
252
+ prot_args args(module, method, value);
253
+ return edn_prot_rb_funcall( edn_wrap_funcall2, reinterpret_cast<VALUE>(&args) );
254
+ }
255
+
256
+ VALUE call_module_fn(VALUE module, ID method, VALUE name, VALUE data)
257
+ {
258
+ prot_args args(module, method, name, data);
259
+ return edn_prot_rb_funcall( edn_wrap_funcall2, reinterpret_cast<VALUE>(&args) );
260
+ }
261
+ }
240
262
  }