]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================= |
2 | Copyright (c) 2001-2011 Joel de Guzman | |
3 | Copyright (c) 2001-2011 Hartmut Kaiser | |
4 | Copyright (c) 2011 Bryce Lelbach | |
5 | ||
6 | Distributed under the Boost Software License, Version 1.0. (See accompanying | |
7 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
8 | =============================================================================*/ | |
9 | #if !defined(BOOST_SPIRIT_UTREE_DETAIL2) | |
10 | #define BOOST_SPIRIT_UTREE_DETAIL2 | |
11 | ||
12 | #if defined(BOOST_MSVC) | |
13 | # pragma warning(push) | |
14 | # pragma warning(disable: 4800) | |
15 | #endif | |
16 | ||
17 | #include <boost/type_traits/remove_pointer.hpp> | |
18 | #include <boost/type_traits/is_pointer.hpp> | |
19 | #include <boost/utility/enable_if.hpp> | |
20 | #include <boost/throw_exception.hpp> | |
21 | #include <boost/iterator/iterator_traits.hpp> | |
22 | ||
23 | namespace boost { namespace spirit { namespace detail | |
24 | { | |
25 | inline char& fast_string::info() | |
26 | { | |
27 | return buff[small_string_size]; | |
28 | } | |
29 | ||
30 | inline char fast_string::info() const | |
31 | { | |
32 | return buff[small_string_size]; | |
33 | } | |
34 | ||
35 | inline int fast_string::get_type() const | |
36 | { | |
37 | return info() >> 1; | |
38 | } | |
39 | ||
40 | inline void fast_string::set_type(int t) | |
41 | { | |
42 | info() = (t << 1) | (info() & 1); | |
43 | } | |
44 | ||
45 | inline short fast_string::tag() const | |
46 | { | |
47 | return (int(buff[small_string_size-2]) << 8) + (unsigned char)buff[small_string_size-1]; | |
48 | } | |
49 | ||
50 | inline void fast_string::tag(short tag) | |
51 | { | |
52 | buff[small_string_size-2] = tag >> 8; | |
53 | buff[small_string_size-1] = tag & 0xff; | |
54 | } | |
55 | ||
56 | inline bool fast_string::is_heap_allocated() const | |
57 | { | |
58 | return info() & 1; | |
59 | } | |
60 | ||
61 | inline std::size_t fast_string::size() const | |
62 | { | |
63 | if (is_heap_allocated()) | |
64 | return heap.size; | |
65 | else | |
66 | return max_string_len - buff[max_string_len]; | |
67 | } | |
68 | ||
69 | inline char const* fast_string::str() const | |
70 | { | |
71 | if (is_heap_allocated()) | |
72 | return heap.str; | |
73 | else | |
74 | return buff; | |
75 | } | |
76 | ||
77 | template <typename Iterator> | |
78 | inline void fast_string::construct(Iterator f, Iterator l) | |
79 | { | |
80 | unsigned const size = l-f; | |
81 | char* str; | |
82 | if (size < max_string_len) | |
83 | { | |
84 | // if it fits, store it in-situ; small_string_size minus the length | |
85 | // of the string is placed in buff[small_string_size - 1] | |
86 | str = buff; | |
87 | buff[max_string_len] = static_cast<char>(max_string_len - size); | |
88 | info() &= ~0x1; | |
89 | } | |
90 | else | |
91 | { | |
92 | // else, store it in the heap | |
93 | str = new char[size + 1]; // add one for the null char | |
94 | heap.str = str; | |
95 | heap.size = size; | |
96 | info() |= 0x1; | |
97 | } | |
98 | for (std::size_t i = 0; i != size; ++i) | |
99 | { | |
100 | *str++ = *f++; | |
101 | } | |
102 | *str = '\0'; // add the null char | |
103 | } | |
104 | ||
105 | inline void fast_string::swap(fast_string& other) | |
106 | { | |
107 | std::swap(*this, other); | |
108 | } | |
109 | ||
110 | inline void fast_string::free() | |
111 | { | |
112 | if (is_heap_allocated()) | |
113 | { | |
114 | delete [] heap.str; | |
115 | } | |
116 | } | |
117 | ||
118 | inline void fast_string::copy(fast_string const& other) | |
119 | { | |
120 | construct(other.str(), other.str() + other.size()); | |
121 | } | |
122 | ||
123 | inline void fast_string::initialize() | |
124 | { | |
125 | for (std::size_t i = 0; i != buff_size / (sizeof(long)/sizeof(char)); ++i) | |
126 | lbuff[i] = 0; | |
127 | } | |
128 | ||
129 | struct list::node : boost::noncopyable | |
130 | { | |
131 | template <typename T> | |
132 | node(T const& val, node* next, node* prev) | |
133 | : val(val), next(next), prev(prev) {} | |
134 | ||
135 | void unlink() | |
136 | { | |
137 | prev->next = next; | |
138 | next->prev = prev; | |
139 | } | |
140 | ||
141 | utree val; | |
142 | node* next; | |
143 | node* prev; | |
144 | }; | |
145 | ||
146 | template <typename Value> | |
147 | class list::node_iterator | |
148 | : public boost::iterator_facade< | |
149 | node_iterator<Value> | |
150 | , Value | |
151 | , boost::bidirectional_traversal_tag> | |
152 | { | |
153 | public: | |
154 | ||
155 | node_iterator() | |
156 | : node(0), prev(0) {} | |
157 | ||
158 | node_iterator(list::node* node, list::node* prev) | |
159 | : node(node), prev(prev) {} | |
160 | ||
161 | private: | |
162 | ||
163 | friend class boost::iterator_core_access; | |
164 | friend class boost::spirit::utree; | |
165 | friend struct boost::spirit::detail::list; | |
166 | ||
167 | void increment() | |
168 | { | |
169 | if (node != 0) // not at end | |
170 | { | |
171 | prev = node; | |
172 | node = node->next; | |
173 | } | |
174 | } | |
175 | ||
176 | void decrement() | |
177 | { | |
178 | if (prev != 0) // not at begin | |
179 | { | |
180 | node = prev; | |
181 | prev = prev->prev; | |
182 | } | |
183 | } | |
184 | ||
185 | bool equal(node_iterator const& other) const | |
186 | { | |
187 | return node == other.node; | |
188 | } | |
189 | ||
190 | typename node_iterator::reference dereference() const | |
191 | { | |
192 | return node->val; | |
193 | } | |
194 | ||
195 | list::node* node; | |
196 | list::node* prev; | |
197 | }; | |
198 | ||
199 | template <typename Value> | |
200 | class list::node_iterator<boost::reference_wrapper<Value> > | |
201 | : public boost::iterator_facade< | |
202 | node_iterator<boost::reference_wrapper<Value> > | |
203 | , boost::reference_wrapper<Value> | |
204 | , boost::bidirectional_traversal_tag> | |
205 | { | |
206 | public: | |
207 | ||
208 | node_iterator() | |
209 | : node(0), prev(0), curr(nil_node) {} | |
210 | ||
211 | node_iterator(list::node* node, list::node* prev) | |
212 | : node(node), prev(prev), curr(node ? node->val : nil_node) {} | |
213 | ||
214 | private: | |
215 | ||
216 | friend class boost::iterator_core_access; | |
217 | friend class boost::spirit::utree; | |
218 | friend struct boost::spirit::detail::list; | |
219 | ||
220 | void increment() | |
221 | { | |
222 | if (node != 0) // not at end | |
223 | { | |
224 | prev = node; | |
225 | node = node->next; | |
226 | curr = boost::ref(node ? node->val : nil_node); | |
227 | } | |
228 | } | |
229 | ||
230 | void decrement() | |
231 | { | |
232 | if (prev != 0) // not at begin | |
233 | { | |
234 | node = prev; | |
235 | prev = prev->prev; | |
236 | curr = boost::ref(node ? node->val : nil_node); | |
237 | } | |
238 | } | |
239 | ||
240 | bool equal(node_iterator const& other) const | |
241 | { | |
242 | return node == other.node; | |
243 | } | |
244 | ||
245 | typename node_iterator::reference dereference() const | |
246 | { | |
247 | return curr; | |
248 | } | |
249 | ||
250 | list::node* node; | |
251 | list::node* prev; | |
252 | ||
253 | static Value nil_node; | |
254 | mutable boost::reference_wrapper<Value> curr; | |
255 | }; | |
256 | ||
257 | template <typename Value> | |
258 | Value list::node_iterator<boost::reference_wrapper<Value> >::nil_node = Value(); | |
259 | ||
260 | inline void list::free() | |
261 | { | |
262 | node* p = first; | |
263 | while (p != 0) | |
264 | { | |
265 | node* next = p->next; | |
266 | delete p; | |
267 | p = next; | |
268 | } | |
269 | } | |
270 | ||
271 | inline void list::copy(list const& other) | |
272 | { | |
273 | node* p = other.first; | |
274 | while (p != 0) | |
275 | { | |
276 | push_back(p->val); | |
277 | p = p->next; | |
278 | } | |
279 | } | |
280 | ||
281 | inline void list::default_construct() | |
282 | { | |
283 | first = last = 0; | |
284 | size = 0; | |
285 | } | |
286 | ||
287 | template <typename T, typename Iterator> | |
288 | inline void list::insert(T const& val, Iterator pos) | |
289 | { | |
290 | if (!pos.node) | |
291 | { | |
292 | push_back(val); | |
293 | return; | |
294 | } | |
295 | ||
296 | detail::list::node* new_node = | |
297 | new detail::list::node(val, pos.node, pos.node->prev); | |
298 | ||
299 | if (pos.node->prev) | |
300 | pos.node->prev->next = new_node; | |
301 | else | |
302 | first = new_node; | |
303 | ||
304 | pos.node->prev = new_node; | |
305 | ++size; | |
306 | } | |
307 | ||
308 | template <typename T> | |
309 | inline void list::push_front(T const& val) | |
310 | { | |
311 | detail::list::node* new_node; | |
312 | if (first == 0) | |
313 | { | |
314 | new_node = new detail::list::node(val, 0, 0); | |
315 | first = last = new_node; | |
316 | ++size; | |
317 | } | |
318 | else | |
319 | { | |
320 | new_node = new detail::list::node(val, first, first->prev); | |
321 | first->prev = new_node; | |
322 | first = new_node; | |
323 | ++size; | |
324 | } | |
325 | } | |
326 | ||
327 | template <typename T> | |
328 | inline void list::push_back(T const& val) | |
329 | { | |
330 | if (last == 0) | |
331 | push_front(val); | |
332 | else { | |
333 | detail::list::node* new_node = | |
334 | new detail::list::node(val, last->next, last); | |
335 | last->next = new_node; | |
336 | last = new_node; | |
337 | ++size; | |
338 | } | |
339 | } | |
340 | ||
341 | inline void list::pop_front() | |
342 | { | |
343 | BOOST_ASSERT(size != 0); | |
344 | if (first == last) // there's only one item | |
345 | { | |
346 | delete first; | |
347 | size = 0; | |
348 | first = last = 0; | |
349 | } | |
350 | else | |
351 | { | |
352 | node* np = first; | |
353 | first = first->next; | |
354 | first->prev = 0; | |
355 | delete np; | |
356 | --size; | |
357 | } | |
358 | } | |
359 | ||
360 | inline void list::pop_back() | |
361 | { | |
362 | BOOST_ASSERT(size != 0); | |
363 | if (first == last) // there's only one item | |
364 | { | |
365 | delete first; | |
366 | size = 0; | |
367 | first = last = 0; | |
368 | } | |
369 | else | |
370 | { | |
371 | node* np = last; | |
372 | last = last->prev; | |
373 | last->next = 0; | |
374 | delete np; | |
375 | --size; | |
376 | } | |
377 | } | |
378 | ||
379 | inline list::node* list::erase(node* pos) | |
380 | { | |
381 | BOOST_ASSERT(pos != 0); | |
382 | if (pos == first) | |
383 | { | |
384 | pop_front(); | |
385 | return first; | |
386 | } | |
387 | else if (pos == last) | |
388 | { | |
389 | pop_back(); | |
390 | return 0; | |
391 | } | |
392 | else | |
393 | { | |
394 | node* next(pos->next); | |
395 | pos->unlink(); | |
396 | delete pos; | |
397 | --size; | |
398 | return next; | |
399 | } | |
400 | } | |
401 | ||
402 | /////////////////////////////////////////////////////////////////////////// | |
403 | // simple binder for binary visitation (we don't want to bring in the big guns) | |
404 | template <typename F, typename X> | |
405 | struct bind_impl | |
406 | { | |
407 | typedef typename F::result_type result_type; | |
408 | X& x; // always by reference | |
409 | F f; | |
410 | bind_impl(F f, X& x) : x(x), f(f) {} | |
411 | ||
412 | template <typename Y> | |
413 | typename F::result_type operator()(Y& y) const | |
414 | { | |
415 | return f(x, y); | |
416 | } | |
417 | ||
418 | template <typename Y> | |
419 | typename F::result_type operator()(Y const& y) const | |
420 | { | |
421 | return f(x, y); | |
422 | } | |
423 | }; | |
424 | ||
425 | template <typename F, typename X> | |
426 | bind_impl<F, X const> bind(F f, X const& x) | |
427 | { | |
428 | return bind_impl<F, X const>(f, x); | |
429 | } | |
430 | ||
431 | template <typename F, typename X> | |
432 | bind_impl<F, X> bind(F f, X& x) | |
433 | { | |
434 | return bind_impl<F, X>(f, x); | |
435 | } | |
436 | ||
437 | template <typename UTreeX, typename UTreeY = UTreeX> | |
438 | struct visit_impl | |
439 | { | |
440 | template <typename F> | |
441 | typename F::result_type | |
442 | static apply(UTreeX& x, F f) // single dispatch | |
443 | { | |
444 | typedef typename | |
445 | boost::mpl::if_<boost::is_const<UTreeX>, | |
446 | typename UTreeX::const_iterator, | |
447 | typename UTreeX::iterator>::type | |
448 | iterator; | |
449 | ||
450 | typedef boost::iterator_range<iterator> list_range; | |
451 | typedef utree_type type; | |
452 | ||
453 | switch (x.get_type()) | |
454 | { | |
455 | default: | |
456 | BOOST_THROW_EXCEPTION( | |
457 | bad_type_exception("corrupt utree type", x.get_type())); | |
458 | break; | |
459 | ||
460 | case type::invalid_type: | |
461 | return f(invalid); | |
462 | ||
463 | case type::nil_type: | |
464 | return f(nil); | |
465 | ||
466 | case type::bool_type: | |
467 | return f(x.b); | |
468 | ||
469 | case type::int_type: | |
470 | return f(x.i); | |
471 | ||
472 | case type::double_type: | |
473 | return f(x.d); | |
474 | ||
475 | case type::list_type: | |
476 | return f(list_range(iterator(x.l.first, 0), iterator(0, x.l.last))); | |
477 | ||
478 | case type::range_type: | |
479 | return f(list_range(iterator(x.r.first, 0), iterator(0, x.r.last))); | |
480 | ||
481 | case type::string_type: | |
482 | return f(utf8_string_range_type(x.s.str(), x.s.size())); | |
483 | ||
484 | case type::string_range_type: | |
485 | return f(utf8_string_range_type(x.sr.first, x.sr.last)); | |
486 | ||
487 | case type::symbol_type: | |
488 | return f(utf8_symbol_range_type(x.s.str(), x.s.size())); | |
489 | ||
490 | case type::binary_type: | |
491 | return f(binary_range_type(x.s.str(), x.s.size())); | |
492 | ||
493 | case type::reference_type: | |
494 | return apply(*x.p, f); | |
495 | ||
496 | case type::any_type: | |
497 | return f(any_ptr(x.v.p, x.v.i)); | |
498 | ||
499 | case type::function_type: | |
500 | return f(*x.pf); | |
501 | } | |
502 | } | |
503 | ||
504 | template <typename F> | |
505 | typename F::result_type | |
506 | static apply(UTreeX& x, UTreeY& y, F f) // double dispatch | |
507 | { | |
508 | typedef typename | |
509 | boost::mpl::if_<boost::is_const<UTreeX>, | |
510 | typename UTreeX::const_iterator, | |
511 | typename UTreeX::iterator>::type | |
512 | iterator; | |
513 | ||
514 | typedef boost::iterator_range<iterator> list_range; | |
515 | typedef utree_type type; | |
516 | ||
517 | switch (x.get_type()) | |
518 | { | |
519 | default: | |
520 | BOOST_THROW_EXCEPTION( | |
521 | bad_type_exception("corrupt utree type", x.get_type())); | |
522 | break; | |
523 | ||
524 | case type::invalid_type: | |
525 | return visit_impl::apply(y, detail::bind(f, invalid)); | |
526 | ||
527 | case type::nil_type: | |
528 | return visit_impl::apply(y, detail::bind(f, nil)); | |
529 | ||
530 | case type::bool_type: | |
531 | return visit_impl::apply(y, detail::bind(f, x.b)); | |
532 | ||
533 | case type::int_type: | |
534 | return visit_impl::apply(y, detail::bind(f, x.i)); | |
535 | ||
536 | case type::double_type: | |
537 | return visit_impl::apply(y, detail::bind(f, x.d)); | |
538 | ||
539 | case type::list_type: | |
540 | return visit_impl::apply( | |
541 | y, detail::bind<F, list_range>(f, | |
542 | list_range(iterator(x.l.first, 0), iterator(0, x.l.last)))); | |
543 | ||
544 | case type::range_type: | |
545 | return visit_impl::apply( | |
546 | y, detail::bind<F, list_range>(f, | |
547 | list_range(iterator(x.r.first, 0), iterator(0, x.r.last)))); | |
548 | ||
549 | case type::string_type: | |
550 | return visit_impl::apply(y, detail::bind( | |
551 | f, utf8_string_range_type(x.s.str(), x.s.size()))); | |
552 | ||
553 | case type::string_range_type: | |
554 | return visit_impl::apply(y, detail::bind( | |
555 | f, utf8_string_range_type(x.sr.first, x.sr.last))); | |
556 | ||
557 | case type::symbol_type: | |
558 | return visit_impl::apply(y, detail::bind( | |
559 | f, utf8_symbol_range_type(x.s.str(), x.s.size()))); | |
560 | ||
561 | case type::binary_type: | |
562 | return visit_impl::apply(y, detail::bind( | |
563 | f, binary_range_type(x.s.str(), x.s.size()))); | |
564 | ||
565 | case type::reference_type: | |
566 | return apply(*x.p, y, f); | |
567 | ||
568 | case type::any_type: | |
569 | return visit_impl::apply( | |
570 | y, detail::bind(f, any_ptr(x.v.p, x.v.i))); | |
571 | ||
572 | case type::function_type: | |
573 | return visit_impl::apply(y, detail::bind(f, *x.pf)); | |
574 | } | |
575 | } | |
576 | }; | |
577 | ||
578 | struct index_impl | |
579 | { | |
580 | static utree& apply(utree& ut, std::size_t i) | |
581 | { | |
582 | switch (ut.get_type()) | |
583 | { | |
584 | case utree_type::reference_type: | |
585 | return apply(ut.deref(), i); | |
586 | case utree_type::range_type: | |
587 | return apply(ut.r.first, i); | |
588 | case utree_type::list_type: | |
589 | return apply(ut.l.first, i); | |
590 | default: | |
591 | BOOST_THROW_EXCEPTION( | |
592 | bad_type_exception | |
593 | ("index operation performed on non-list utree type", | |
594 | ut.get_type())); | |
595 | } | |
596 | } | |
597 | ||
598 | static utree const& apply(utree const& ut, std::size_t i) | |
599 | { | |
600 | switch (ut.get_type()) | |
601 | { | |
602 | case utree_type::reference_type: | |
603 | return apply(ut.deref(), i); | |
604 | case utree_type::range_type: | |
605 | return apply(ut.r.first, i); | |
606 | case utree_type::list_type: | |
607 | return apply(ut.l.first, i); | |
608 | default: | |
609 | BOOST_THROW_EXCEPTION( | |
610 | bad_type_exception | |
611 | ("index operation performed on non-list utree type", | |
612 | ut.get_type())); | |
613 | } | |
614 | } | |
615 | ||
616 | static utree& apply(list::node* node, std::size_t i) | |
617 | { | |
618 | for (; i > 0; --i) | |
619 | node = node->next; | |
620 | return node->val; | |
621 | } | |
622 | ||
623 | static utree const& apply(list::node const* node, std::size_t i) | |
624 | { | |
625 | for (; i > 0; --i) | |
626 | node = node->next; | |
627 | return node->val; | |
628 | } | |
629 | }; | |
630 | }}} | |
631 | ||
632 | namespace boost { namespace spirit | |
633 | { | |
634 | template <typename F> | |
635 | stored_function<F>::stored_function(F f) | |
636 | : f(f) | |
637 | { | |
638 | } | |
639 | ||
640 | template <typename F> | |
641 | stored_function<F>::~stored_function() | |
642 | { | |
643 | } | |
644 | ||
645 | template <typename F> | |
646 | utree stored_function<F>::operator()(utree const& env) const | |
647 | { | |
648 | return f(env); | |
649 | } | |
650 | ||
651 | template <typename F> | |
652 | utree stored_function<F>::operator()(utree& env) const | |
653 | { | |
654 | return f(env); | |
655 | } | |
656 | ||
657 | template <typename F> | |
658 | function_base* | |
659 | stored_function<F>::clone() const | |
660 | { | |
661 | return new stored_function<F>(f); | |
662 | } | |
663 | ||
664 | template <typename F> | |
665 | referenced_function<F>::referenced_function(F& f) | |
666 | : f(f) | |
667 | { | |
668 | } | |
669 | ||
670 | template <typename F> | |
671 | referenced_function<F>::~referenced_function() | |
672 | { | |
673 | } | |
674 | ||
675 | template <typename F> | |
676 | utree referenced_function<F>::operator()(utree const& env) const | |
677 | { | |
678 | return f(env); | |
679 | } | |
680 | ||
681 | template <typename F> | |
682 | utree referenced_function<F>::operator()(utree& env) const | |
683 | { | |
684 | return f(env); | |
685 | } | |
686 | ||
687 | template <typename F> | |
688 | function_base* | |
689 | referenced_function<F>::clone() const | |
690 | { | |
691 | return new referenced_function<F>(f); | |
692 | } | |
693 | ||
694 | inline utree::utree(utree::invalid_type) | |
695 | { | |
696 | s.initialize(); | |
697 | set_type(type::invalid_type); | |
698 | } | |
699 | ||
700 | inline utree::utree(utree::nil_type) | |
701 | { | |
702 | s.initialize(); | |
703 | set_type(type::nil_type); | |
704 | } | |
705 | ||
706 | inline utree::utree(bool b_) | |
707 | { | |
708 | s.initialize(); | |
709 | b = b_; | |
710 | set_type(type::bool_type); | |
711 | } | |
712 | ||
713 | inline utree::utree(char c) | |
714 | { | |
715 | s.initialize(); | |
716 | // char constructs a single element string | |
717 | s.construct(&c, &c+1); | |
718 | set_type(type::string_type); | |
719 | } | |
720 | ||
721 | inline utree::utree(unsigned int i_) | |
722 | { | |
723 | s.initialize(); | |
724 | i = i_; | |
725 | set_type(type::int_type); | |
726 | } | |
727 | ||
728 | inline utree::utree(int i_) | |
729 | { | |
730 | s.initialize(); | |
731 | i = i_; | |
732 | set_type(type::int_type); | |
733 | } | |
734 | ||
735 | inline utree::utree(double d_) | |
736 | { | |
737 | s.initialize(); | |
738 | d = d_; | |
739 | set_type(type::double_type); | |
740 | } | |
741 | ||
742 | inline utree::utree(char const* str) | |
743 | { | |
744 | s.initialize(); | |
745 | s.construct(str, str + strlen(str)); | |
746 | set_type(type::string_type); | |
747 | } | |
748 | ||
749 | inline utree::utree(char const* str, std::size_t len) | |
750 | { | |
751 | s.initialize(); | |
752 | s.construct(str, str + len); | |
753 | set_type(type::string_type); | |
754 | } | |
755 | ||
756 | inline utree::utree(std::string const& str) | |
757 | { | |
758 | s.initialize(); | |
759 | s.construct(str.begin(), str.end()); | |
760 | set_type(type::string_type); | |
761 | } | |
762 | ||
763 | template <typename Base, utree_type::info type_> | |
764 | inline utree::utree(basic_string<Base, type_> const& bin) | |
765 | { | |
766 | s.initialize(); | |
767 | s.construct(bin.begin(), bin.end()); | |
768 | set_type(type_); | |
769 | } | |
770 | ||
771 | inline utree::utree(boost::reference_wrapper<utree> ref) | |
772 | { | |
773 | s.initialize(); | |
774 | p = ref.get_pointer(); | |
775 | set_type(type::reference_type); | |
776 | } | |
777 | ||
778 | inline utree::utree(any_ptr const& p) | |
779 | { | |
780 | s.initialize(); | |
781 | v.p = p.p; | |
782 | v.i = p.i; | |
783 | set_type(type::any_type); | |
784 | } | |
785 | ||
786 | inline utree::utree(function_base const& pf_) | |
787 | { | |
788 | s.initialize(); | |
789 | pf = pf_.clone(); | |
790 | set_type(type::function_type); | |
791 | } | |
792 | ||
793 | inline utree::utree(function_base* pf_) | |
794 | { | |
795 | s.initialize(); | |
796 | pf = pf_; | |
797 | set_type(type::function_type); | |
798 | } | |
799 | ||
800 | template <typename Iter> | |
801 | inline utree::utree(boost::iterator_range<Iter> r) | |
802 | { | |
803 | s.initialize(); | |
804 | ||
805 | assign(r.begin(), r.end()); | |
806 | } | |
807 | ||
808 | inline utree::utree(range r, shallow_tag) | |
809 | { | |
810 | s.initialize(); | |
811 | this->r.first = r.begin().node; | |
812 | this->r.last = r.end().prev; | |
813 | set_type(type::range_type); | |
814 | } | |
815 | ||
816 | inline utree::utree(const_range r, shallow_tag) | |
817 | { | |
818 | s.initialize(); | |
819 | this->r.first = r.begin().node; | |
820 | this->r.last = r.end().prev; | |
821 | set_type(type::range_type); | |
822 | } | |
823 | ||
824 | inline utree::utree(utf8_string_range_type const& str, shallow_tag) | |
825 | { | |
826 | s.initialize(); | |
827 | this->sr.first = str.begin(); | |
828 | this->sr.last = str.end(); | |
829 | set_type(type::string_range_type); | |
830 | } | |
831 | ||
832 | inline utree::utree(utree const& other) | |
833 | { | |
834 | s.initialize(); | |
835 | copy(other); | |
836 | } | |
837 | ||
838 | inline utree::~utree() | |
839 | { | |
840 | free(); | |
841 | } | |
842 | ||
843 | inline utree& utree::operator=(utree const& other) | |
844 | { | |
845 | if (this != &other) | |
846 | { | |
847 | free(); | |
848 | copy(other); | |
849 | } | |
850 | return *this; | |
851 | } | |
852 | ||
853 | inline utree& utree::operator=(nil_type) | |
854 | { | |
855 | free(); | |
856 | set_type(type::nil_type); | |
857 | return *this; | |
858 | } | |
859 | ||
860 | inline utree& utree::operator=(bool b_) | |
861 | { | |
862 | free(); | |
863 | b = b_; | |
864 | set_type(type::bool_type); | |
865 | return *this; | |
866 | } | |
867 | ||
868 | inline utree& utree::operator=(char c) | |
869 | { | |
870 | // char constructs a single element string | |
871 | free(); | |
872 | s.construct(&c, &c+1); | |
873 | set_type(type::string_type); | |
874 | return *this; | |
875 | } | |
876 | ||
877 | inline utree& utree::operator=(unsigned int i_) | |
878 | { | |
879 | free(); | |
880 | i = i_; | |
881 | set_type(type::int_type); | |
882 | return *this; | |
883 | } | |
884 | ||
885 | inline utree& utree::operator=(int i_) | |
886 | { | |
887 | free(); | |
888 | i = i_; | |
889 | set_type(type::int_type); | |
890 | return *this; | |
891 | } | |
892 | ||
893 | inline utree& utree::operator=(double d_) | |
894 | { | |
895 | free(); | |
896 | d = d_; | |
897 | set_type(type::double_type); | |
898 | return *this; | |
899 | } | |
900 | ||
901 | inline utree& utree::operator=(char const* s_) | |
902 | { | |
903 | free(); | |
904 | s.construct(s_, s_ + strlen(s_)); | |
905 | set_type(type::string_type); | |
906 | return *this; | |
907 | } | |
908 | ||
909 | inline utree& utree::operator=(std::string const& s_) | |
910 | { | |
911 | free(); | |
912 | s.construct(s_.begin(), s_.end()); | |
913 | set_type(type::string_type); | |
914 | return *this; | |
915 | } | |
916 | ||
917 | template <typename Base, utree_type::info type_> | |
918 | inline utree& utree::operator=(basic_string<Base, type_> const& bin) | |
919 | { | |
920 | free(); | |
921 | s.construct(bin.begin(), bin.end()); | |
922 | set_type(type_); | |
923 | return *this; | |
924 | } | |
925 | ||
926 | inline utree& utree::operator=(boost::reference_wrapper<utree> ref) | |
927 | { | |
928 | free(); | |
929 | p = ref.get_pointer(); | |
930 | set_type(type::reference_type); | |
931 | return *this; | |
932 | } | |
933 | ||
934 | inline utree& utree::operator=(any_ptr const& p) | |
935 | { | |
936 | free(); | |
937 | v.p = p.p; | |
938 | v.i = p.i; | |
939 | set_type(type::any_type); | |
940 | return *this; | |
941 | } | |
942 | ||
943 | inline utree& utree::operator=(function_base const& pf_) | |
944 | { | |
945 | free(); | |
946 | pf = pf_.clone(); | |
947 | set_type(type::function_type); | |
948 | return *this; | |
949 | } | |
950 | ||
951 | inline utree& utree::operator=(function_base* pf_) | |
952 | { | |
953 | free(); | |
954 | pf = pf_; | |
955 | set_type(type::function_type); | |
956 | return *this; | |
957 | } | |
958 | ||
959 | template <typename Iter> | |
960 | inline utree& utree::operator=(boost::iterator_range<Iter> r) | |
961 | { | |
962 | free(); | |
963 | assign(r.begin(), r.end()); | |
964 | return *this; | |
965 | } | |
966 | ||
967 | template <typename F> | |
968 | typename boost::result_of<F(utree const&)>::type | |
969 | inline utree::visit(utree const& x, F f) | |
970 | { | |
971 | return detail::visit_impl<utree const>::apply(x, f); | |
972 | } | |
973 | ||
974 | template <typename F> | |
975 | typename boost::result_of<F(utree&)>::type | |
976 | inline utree::visit(utree& x, F f) | |
977 | { | |
978 | return detail::visit_impl<utree>::apply(x, f); | |
979 | } | |
980 | ||
981 | template <typename F> | |
982 | typename boost::result_of<F(utree const&, utree const&)>::type | |
983 | inline utree::visit(utree const& x, utree const& y, F f) | |
984 | { | |
985 | return detail::visit_impl<utree const, utree const>::apply(x, y, f); | |
986 | } | |
987 | ||
988 | template <typename F> | |
989 | typename boost::result_of<F(utree const&, utree&)>::type | |
990 | inline utree::visit(utree const& x, utree& y, F f) | |
991 | { | |
992 | return detail::visit_impl<utree const, utree>::apply(x, y, f); | |
993 | } | |
994 | ||
995 | template <typename F> | |
996 | typename boost::result_of<F(utree&, utree const&)>::type | |
997 | inline utree::visit(utree& x, utree const& y, F f) | |
998 | { | |
999 | return detail::visit_impl<utree, utree const>::apply(x, y, f); | |
1000 | } | |
1001 | ||
1002 | template <typename F> | |
1003 | typename boost::result_of<F(utree&, utree&)>::type | |
1004 | inline utree::visit(utree& x, utree& y, F f) | |
1005 | { | |
1006 | return detail::visit_impl<utree, utree>::apply(x, y, f); | |
1007 | } | |
1008 | ||
1009 | inline utree::reference get(utree::reference ut, utree::size_type i) | |
1010 | { return detail::index_impl::apply(ut, i); } | |
1011 | ||
1012 | inline utree::const_reference | |
1013 | get(utree::const_reference ut, utree::size_type i) | |
1014 | { return detail::index_impl::apply(ut, i); } | |
1015 | ||
1016 | template <typename T> | |
1017 | inline void utree::push_front(T const& val) | |
1018 | { | |
1019 | if (get_type() == type::reference_type) | |
1020 | return p->push_front(val); | |
1021 | ||
1022 | ensure_list_type("push_front()"); | |
1023 | l.push_front(val); | |
1024 | } | |
1025 | ||
1026 | template <typename T> | |
1027 | inline void utree::push_back(T const& val) | |
1028 | { | |
1029 | if (get_type() == type::reference_type) | |
1030 | return p->push_back(val); | |
1031 | ||
1032 | ensure_list_type("push_back()"); | |
1033 | l.push_back(val); | |
1034 | } | |
1035 | ||
1036 | template <typename T> | |
1037 | inline utree::iterator utree::insert(iterator pos, T const& val) | |
1038 | { | |
1039 | if (get_type() == type::reference_type) | |
1040 | return p->insert(pos, val); | |
1041 | ||
1042 | ensure_list_type("insert()"); | |
1043 | if (!pos.node) | |
1044 | { | |
1045 | l.push_back(val); | |
1046 | return utree::iterator(l.last, l.last->prev); | |
1047 | } | |
1048 | l.insert(val, pos); | |
1049 | return utree::iterator(pos.node->prev, pos.node->prev->prev); | |
1050 | } | |
1051 | ||
1052 | template <typename T> | |
1053 | inline void utree::insert(iterator pos, std::size_t n, T const& val) | |
1054 | { | |
1055 | if (get_type() == type::reference_type) | |
1056 | return p->insert(pos, n, val); | |
1057 | ||
1058 | ensure_list_type("insert()"); | |
1059 | for (std::size_t i = 0; i != n; ++i) | |
1060 | insert(pos, val); | |
1061 | } | |
1062 | ||
1063 | template <typename Iterator> | |
1064 | inline void utree::insert(iterator pos, Iterator first, Iterator last) | |
1065 | { | |
1066 | if (get_type() == type::reference_type) | |
1067 | return p->insert(pos, first, last); | |
1068 | ||
1069 | ensure_list_type("insert()"); | |
1070 | while (first != last) | |
1071 | insert(pos, *first++); | |
1072 | } | |
1073 | ||
1074 | template <typename Iterator> | |
1075 | inline void utree::assign(Iterator first, Iterator last) | |
1076 | { | |
1077 | if (get_type() == type::reference_type) | |
1078 | return p->assign(first, last); | |
1079 | ||
1080 | clear(); | |
1081 | set_type(type::list_type); | |
1082 | ||
1083 | while (first != last) | |
1084 | { | |
1085 | push_back(*first); | |
1086 | ++first; | |
1087 | } | |
1088 | } | |
1089 | ||
1090 | inline void utree::clear() | |
1091 | { | |
1092 | if (get_type() == type::reference_type) | |
1093 | return p->clear(); | |
1094 | ||
1095 | // clear will always make this an invalid type | |
1096 | free(); | |
1097 | set_type(type::invalid_type); | |
1098 | } | |
1099 | ||
1100 | inline void utree::pop_front() | |
1101 | { | |
1102 | if (get_type() == type::reference_type) | |
1103 | return p->pop_front(); | |
1104 | if (get_type() != type::list_type) | |
1105 | BOOST_THROW_EXCEPTION( | |
1106 | bad_type_exception | |
1107 | ("pop_front() called on non-list utree type", | |
1108 | get_type())); | |
1109 | ||
1110 | l.pop_front(); | |
1111 | } | |
1112 | ||
1113 | inline void utree::pop_back() | |
1114 | { | |
1115 | if (get_type() == type::reference_type) | |
1116 | return p->pop_back(); | |
1117 | if (get_type() != type::list_type) | |
1118 | BOOST_THROW_EXCEPTION( | |
1119 | bad_type_exception | |
1120 | ("pop_back() called on non-list utree type", | |
1121 | get_type())); | |
1122 | ||
1123 | l.pop_back(); | |
1124 | } | |
1125 | ||
1126 | inline utree::iterator utree::erase(iterator pos) | |
1127 | { | |
1128 | if (get_type() == type::reference_type) | |
1129 | return p->erase(pos); | |
1130 | if (get_type() != type::list_type) | |
1131 | BOOST_THROW_EXCEPTION( | |
1132 | bad_type_exception | |
1133 | ("erase() called on non-list utree type", | |
1134 | get_type())); | |
1135 | ||
1136 | detail::list::node* np = l.erase(pos.node); | |
1137 | return iterator(np, np?np->prev:l.last); | |
1138 | } | |
1139 | ||
1140 | inline utree::iterator utree::erase(iterator first, iterator last) | |
1141 | { | |
1142 | if (get_type() == type::reference_type) | |
1143 | return p->erase(first, last); | |
1144 | ||
1145 | if (get_type() != type::list_type) | |
1146 | BOOST_THROW_EXCEPTION( | |
1147 | bad_type_exception | |
1148 | ("erase() called on non-list utree type", | |
1149 | get_type())); | |
1150 | while (first != last) | |
1151 | erase(first++); | |
1152 | return last; | |
1153 | } | |
1154 | ||
1155 | inline utree::iterator utree::begin() | |
1156 | { | |
1157 | if (get_type() == type::reference_type) | |
1158 | return p->begin(); | |
1159 | else if (get_type() == type::range_type) | |
1160 | return iterator(r.first, 0); | |
1161 | ||
1162 | // otherwise... | |
1163 | ensure_list_type("begin()"); | |
1164 | return iterator(l.first, 0); | |
1165 | } | |
1166 | ||
1167 | inline utree::iterator utree::end() | |
1168 | { | |
1169 | if (get_type() == type::reference_type) | |
1170 | return p->end(); | |
1171 | else if (get_type() == type::range_type) | |
1172 | return iterator(0, r.first); | |
1173 | ||
1174 | // otherwise... | |
1175 | ensure_list_type("end()"); | |
1176 | return iterator(0, l.last); | |
1177 | } | |
1178 | ||
1179 | inline utree::ref_iterator utree::ref_begin() | |
1180 | { | |
1181 | if (get_type() == type::reference_type) | |
1182 | return p->ref_begin(); | |
1183 | else if (get_type() == type::range_type) | |
1184 | return ref_iterator(r.first, 0); | |
1185 | ||
1186 | // otherwise... | |
1187 | ensure_list_type("ref_begin()"); | |
1188 | return ref_iterator(l.first, 0); | |
1189 | } | |
1190 | ||
1191 | inline utree::ref_iterator utree::ref_end() | |
1192 | { | |
1193 | if (get_type() == type::reference_type) | |
1194 | return p->ref_end(); | |
1195 | else if (get_type() == type::range_type) | |
1196 | return ref_iterator(0, r.first); | |
1197 | ||
1198 | // otherwise... | |
1199 | ensure_list_type("ref_end()"); | |
1200 | return ref_iterator(0, l.last); | |
1201 | } | |
1202 | ||
1203 | inline utree::const_iterator utree::begin() const | |
1204 | { | |
1205 | if (get_type() == type::reference_type) | |
1206 | return ((utree const*)p)->begin(); | |
1207 | if (get_type() == type::range_type) | |
1208 | return const_iterator(r.first, 0); | |
1209 | ||
1210 | // otherwise... | |
1211 | if (get_type() != type::list_type) | |
1212 | BOOST_THROW_EXCEPTION( | |
1213 | bad_type_exception | |
1214 | ("begin() called on non-list utree type", | |
1215 | get_type())); | |
1216 | ||
1217 | return const_iterator(l.first, 0); | |
1218 | } | |
1219 | ||
1220 | inline utree::const_iterator utree::end() const | |
1221 | { | |
1222 | if (get_type() == type::reference_type) | |
1223 | return ((utree const*)p)->end(); | |
1224 | if (get_type() == type::range_type) | |
1225 | return const_iterator(0, r.first); | |
1226 | ||
1227 | // otherwise... | |
1228 | if (get_type() != type::list_type) | |
1229 | BOOST_THROW_EXCEPTION( | |
1230 | bad_type_exception | |
1231 | ("end() called on non-list utree type", | |
1232 | get_type())); | |
1233 | ||
1234 | return const_iterator(0, l.last); | |
1235 | } | |
1236 | ||
1237 | inline bool utree::empty() const | |
1238 | { | |
1239 | type::info t = get_type(); | |
1240 | if (t == type::reference_type) | |
1241 | return ((utree const*)p)->empty(); | |
1242 | ||
1243 | if (t == type::range_type) | |
1244 | return r.first == 0; | |
1245 | if (t == type::list_type) | |
1246 | return l.size == 0; | |
1247 | ||
1248 | return t == type::nil_type || t == type::invalid_type; | |
1249 | } | |
1250 | ||
1251 | inline std::size_t utree::size() const | |
1252 | { | |
1253 | type::info t = get_type(); | |
1254 | if (t == type::reference_type) | |
1255 | return ((utree const*)p)->size(); | |
1256 | ||
1257 | if (t == type::range_type) | |
1258 | { | |
1259 | // FIXME: O(n), and we have the room to store the size of a range | |
1260 | // in the union if we compute it when assigned/constructed. | |
1261 | std::size_t size = 0; | |
1262 | detail::list::node* n = r.first; | |
1263 | while (n) | |
1264 | { | |
1265 | n = n->next; | |
1266 | ++size; | |
1267 | } | |
1268 | return size; | |
1269 | } | |
1270 | if (t == type::list_type) | |
1271 | return l.size; | |
1272 | ||
1273 | if (t == type::string_type) | |
1274 | return s.size(); | |
1275 | ||
1276 | if (t == type::symbol_type) | |
1277 | return s.size(); | |
1278 | ||
1279 | if (t == type::binary_type) | |
1280 | return s.size(); | |
1281 | ||
1282 | if (t == type::string_range_type) | |
1283 | return sr.last - sr.first; | |
1284 | ||
1285 | if (t != type::nil_type) | |
1286 | BOOST_THROW_EXCEPTION( | |
1287 | bad_type_exception | |
1288 | ("size() called on non-list and non-string utree type", | |
1289 | get_type())); | |
1290 | ||
1291 | return 0; | |
1292 | } | |
1293 | ||
1294 | inline utree_type::info utree::which() const | |
1295 | { | |
1296 | return get_type(); | |
1297 | } | |
1298 | ||
1299 | inline utree& utree::front() | |
1300 | { | |
1301 | if (get_type() == type::reference_type) | |
1302 | return p->front(); | |
1303 | if (get_type() == type::range_type) | |
1304 | { | |
1305 | if (!r.first) | |
1306 | BOOST_THROW_EXCEPTION( | |
1307 | empty_exception("front() called on empty utree range")); | |
1308 | return r.first->val; | |
1309 | } | |
1310 | ||
1311 | // otherwise... | |
1312 | if (get_type() != type::list_type) | |
1313 | BOOST_THROW_EXCEPTION( | |
1314 | bad_type_exception | |
1315 | ("front() called on non-list utree type", get_type())); | |
1316 | else if (!l.first) | |
1317 | BOOST_THROW_EXCEPTION( | |
1318 | empty_exception("front() called on empty utree list")); | |
1319 | ||
1320 | return l.first->val; | |
1321 | } | |
1322 | ||
1323 | inline utree& utree::back() | |
1324 | { | |
1325 | if (get_type() == type::reference_type) | |
1326 | return p->back(); | |
1327 | if (get_type() == type::range_type) | |
1328 | { | |
1329 | if (!r.last) | |
1330 | BOOST_THROW_EXCEPTION( | |
1331 | empty_exception("back() called on empty utree range")); | |
1332 | return r.last->val; | |
1333 | } | |
1334 | ||
1335 | // otherwise... | |
1336 | if (get_type() != type::list_type) | |
1337 | BOOST_THROW_EXCEPTION( | |
1338 | bad_type_exception | |
1339 | ("back() called on non-list utree type", get_type())); | |
1340 | else if (!l.last) | |
1341 | BOOST_THROW_EXCEPTION( | |
1342 | empty_exception("back() called on empty utree list")); | |
1343 | ||
1344 | return l.last->val; | |
1345 | } | |
1346 | ||
1347 | inline utree const& utree::front() const | |
1348 | { | |
1349 | if (get_type() == type::reference_type) | |
1350 | return ((utree const*)p)->front(); | |
1351 | if (get_type() == type::range_type) | |
1352 | { | |
1353 | if (!r.first) | |
1354 | BOOST_THROW_EXCEPTION( | |
1355 | empty_exception("front() called on empty utree range")); | |
1356 | return r.first->val; | |
1357 | } | |
1358 | ||
1359 | // otherwise... | |
1360 | if (get_type() != type::list_type) | |
1361 | BOOST_THROW_EXCEPTION( | |
1362 | bad_type_exception | |
1363 | ("front() called on non-list utree type", get_type())); | |
1364 | else if (!l.first) | |
1365 | BOOST_THROW_EXCEPTION( | |
1366 | empty_exception("front() called on empty utree list")); | |
1367 | ||
1368 | return l.first->val; | |
1369 | } | |
1370 | ||
1371 | inline utree const& utree::back() const | |
1372 | { | |
1373 | if (get_type() == type::reference_type) | |
1374 | return ((utree const*)p)->back(); | |
1375 | if (get_type() == type::range_type) | |
1376 | { | |
1377 | if (!r.last) | |
1378 | BOOST_THROW_EXCEPTION( | |
1379 | empty_exception("back() called on empty utree range")); | |
1380 | return r.last->val; | |
1381 | } | |
1382 | ||
1383 | // otherwise... | |
1384 | if (get_type() != type::list_type) | |
1385 | BOOST_THROW_EXCEPTION( | |
1386 | bad_type_exception | |
1387 | ("back() called on non-list utree type", get_type())); | |
1388 | else if (!l.last) | |
1389 | BOOST_THROW_EXCEPTION( | |
1390 | empty_exception("back() called on empty utree list")); | |
1391 | ||
1392 | return l.last->val; | |
1393 | } | |
1394 | ||
1395 | inline void utree::swap(utree& other) | |
1396 | { | |
1397 | s.swap(other.s); | |
1398 | } | |
1399 | ||
1400 | inline utree::type::info utree::get_type() const | |
1401 | { | |
1402 | // the fast string holds the type info | |
1403 | return static_cast<utree::type::info>(s.get_type()); | |
1404 | } | |
1405 | ||
1406 | inline void utree::set_type(type::info t) | |
1407 | { | |
1408 | // the fast string holds the type info | |
1409 | s.set_type(t); | |
1410 | } | |
1411 | ||
1412 | inline void utree::ensure_list_type(char const* failed_in) | |
1413 | { | |
1414 | type::info t = get_type(); | |
1415 | if (t == type::invalid_type) | |
1416 | { | |
1417 | set_type(type::list_type); | |
1418 | l.default_construct(); | |
1419 | } | |
1420 | else if (get_type() != type::list_type) | |
1421 | { | |
1422 | std::string msg = failed_in; | |
1423 | msg += "called on non-list and non-invalid utree type"; | |
1424 | BOOST_THROW_EXCEPTION(bad_type_exception(msg.c_str(), get_type())); | |
1425 | } | |
1426 | } | |
1427 | ||
1428 | inline void utree::free() | |
1429 | { | |
1430 | switch (get_type()) | |
1431 | { | |
1432 | case type::binary_type: | |
1433 | case type::symbol_type: | |
1434 | case type::string_type: | |
1435 | s.free(); | |
1436 | break; | |
1437 | case type::list_type: | |
1438 | l.free(); | |
1439 | break; | |
1440 | case type::function_type: | |
1441 | delete pf; | |
1442 | break; | |
1443 | default: | |
1444 | break; | |
1445 | }; | |
1446 | s.initialize(); | |
1447 | } | |
1448 | ||
1449 | inline void utree::copy(utree const& other) | |
1450 | { | |
1451 | set_type(other.get_type()); | |
1452 | switch (other.get_type()) | |
1453 | { | |
1454 | default: | |
1455 | BOOST_THROW_EXCEPTION( | |
1456 | bad_type_exception("corrupt utree type", other.get_type())); | |
1457 | break; | |
1458 | case type::invalid_type: | |
1459 | case type::nil_type: | |
1460 | s.tag(other.s.tag()); | |
1461 | break; | |
1462 | case type::bool_type: | |
1463 | b = other.b; | |
1464 | s.tag(other.s.tag()); | |
1465 | break; | |
1466 | case type::int_type: | |
1467 | i = other.i; | |
1468 | s.tag(other.s.tag()); | |
1469 | break; | |
1470 | case type::double_type: | |
1471 | d = other.d; | |
1472 | s.tag(other.s.tag()); | |
1473 | break; | |
1474 | case type::reference_type: | |
1475 | p = other.p; | |
1476 | s.tag(other.s.tag()); | |
1477 | break; | |
1478 | case type::any_type: | |
1479 | v = other.v; | |
1480 | s.tag(other.s.tag()); | |
1481 | break; | |
1482 | case type::range_type: | |
1483 | r = other.r; | |
1484 | s.tag(other.s.tag()); | |
1485 | break; | |
1486 | case type::string_range_type: | |
1487 | sr = other.sr; | |
1488 | s.tag(other.s.tag()); | |
1489 | break; | |
1490 | case type::function_type: | |
1491 | pf = other.pf->clone(); | |
1492 | s.tag(other.s.tag()); | |
1493 | break; | |
1494 | case type::string_type: | |
1495 | case type::symbol_type: | |
1496 | case type::binary_type: | |
1497 | s.copy(other.s); | |
1498 | s.tag(other.s.tag()); | |
1499 | break; | |
1500 | case type::list_type: | |
1501 | l.copy(other.l); | |
1502 | s.tag(other.s.tag()); | |
1503 | break; | |
1504 | } | |
1505 | } | |
1506 | ||
1507 | template <typename T> | |
1508 | struct is_iterator_range | |
1509 | : boost::mpl::false_ | |
1510 | {}; | |
1511 | ||
1512 | template <typename Iterator> | |
1513 | struct is_iterator_range<boost::iterator_range<Iterator> > | |
1514 | : boost::mpl::true_ | |
1515 | {}; | |
1516 | ||
1517 | template <typename To> | |
1518 | struct utree_cast | |
1519 | { | |
1520 | typedef To result_type; | |
1521 | ||
1522 | template <typename From> | |
1523 | To dispatch(From const& val, boost::mpl::true_) const | |
1524 | { | |
1525 | return To(val); // From is convertible to To | |
1526 | } | |
1527 | ||
1528 | template <typename From> | |
1529 | To dispatch(From const&, boost::mpl::false_) const | |
1530 | { | |
1531 | // From is NOT convertible to To !!! | |
1532 | throw std::bad_cast(); | |
1533 | return To(); | |
1534 | } | |
1535 | ||
1536 | template <typename From> | |
1537 | To operator()(From const& val) const | |
1538 | { | |
1539 | // boost::iterator_range has a templated constructor, accepting | |
1540 | // any argument and hence any type is 'convertible' to it. | |
1541 | typedef typename boost::mpl::eval_if< | |
1542 | is_iterator_range<To> | |
1543 | , boost::is_same<From, To>, boost::is_convertible<From, To> | |
1544 | >::type is_convertible; | |
1545 | return dispatch(val, is_convertible()); | |
1546 | } | |
1547 | }; | |
1548 | ||
1549 | template <typename T> | |
1550 | struct utree_cast<T*> | |
1551 | { | |
1552 | typedef T* result_type; | |
1553 | ||
1554 | template <typename From> | |
1555 | T* operator()(From const&) const | |
1556 | { | |
1557 | // From is NOT convertible to T !!! | |
1558 | throw std::bad_cast(); | |
1559 | return 0; | |
1560 | } | |
1561 | ||
1562 | T* operator()(any_ptr const& p) const | |
1563 | { | |
1564 | return p.get<T*>(); | |
1565 | } | |
1566 | }; | |
1567 | ||
1568 | template <typename T> | |
1569 | inline T utree::get() const | |
1570 | { | |
1571 | return utree::visit(*this, utree_cast<T>()); | |
1572 | } | |
1573 | ||
1574 | inline utree& utree::deref() | |
1575 | { | |
1576 | return (get_type() == type::reference_type) ? *p : *this; | |
1577 | } | |
1578 | ||
1579 | inline utree const& utree::deref() const | |
1580 | { | |
1581 | return (get_type() == type::reference_type) ? *p : *this; | |
1582 | } | |
1583 | ||
1584 | inline short utree::tag() const | |
1585 | { | |
1586 | return s.tag(); | |
1587 | } | |
1588 | ||
1589 | inline void utree::tag(short tag) | |
1590 | { | |
1591 | s.tag(tag); | |
1592 | } | |
1593 | ||
1594 | inline utree utree::eval(utree const& env) const | |
1595 | { | |
1596 | if (get_type() == type::reference_type) | |
1597 | return deref().eval(env); | |
1598 | ||
1599 | if (get_type() != type::function_type) | |
1600 | BOOST_THROW_EXCEPTION( | |
1601 | bad_type_exception( | |
1602 | "eval() called on non-function utree type", get_type())); | |
1603 | return (*pf)(env); | |
1604 | } | |
1605 | ||
1606 | inline utree utree::eval(utree& env) const | |
1607 | { | |
1608 | if (get_type() == type::reference_type) | |
1609 | return deref().eval(env); | |
1610 | ||
1611 | if (get_type() != type::function_type) | |
1612 | BOOST_THROW_EXCEPTION( | |
1613 | bad_type_exception( | |
1614 | "eval() called on non-function utree type", get_type())); | |
1615 | return (*pf)(env); | |
1616 | } | |
1617 | ||
1618 | inline utree utree::operator() (utree const& env) const | |
1619 | { | |
1620 | return eval(env); | |
1621 | } | |
1622 | ||
1623 | inline utree utree::operator() (utree& env) const | |
1624 | { | |
1625 | return eval(env); | |
1626 | } | |
1627 | }} | |
1628 | ||
1629 | #if defined(BOOST_MSVC) | |
1630 | # pragma warning(pop) | |
1631 | #endif | |
1632 | #endif |