edn_turbo 0.5.7 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
  }