]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================= |
2 | Copyright (c) 2010-2011 Daniel James | |
3 | ||
4 | Use, modification and distribution is subject to the Boost Software | |
5 | License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
6 | http://www.boost.org/LICENSE_1_0.txt) | |
7 | =============================================================================*/ | |
8 | ||
9 | // An easy way to store data parsed for quickbook. | |
10 | ||
11 | #if !defined(BOOST_SPIRIT_QUICKBOOK_VALUES_HPP) | |
12 | #define BOOST_SPIRIT_QUICKBOOK_VALUES_HPP | |
13 | ||
14 | #include <utility> | |
15 | #include <string> | |
16 | #include <cassert> | |
b32b8144 | 17 | #include <stdexcept> |
7c673cae | 18 | #include <boost/scoped_ptr.hpp> |
b32b8144 | 19 | #include <boost/operators.hpp> |
7c673cae | 20 | #include <boost/iterator/iterator_traits.hpp> |
b32b8144 | 21 | #include "string_view.hpp" |
7c673cae FG |
22 | #include "fwd.hpp" |
23 | #include "files.hpp" | |
24 | ||
25 | namespace quickbook | |
26 | { | |
27 | struct value; | |
28 | struct value_builder; | |
29 | struct value_error; | |
30 | ||
31 | namespace detail | |
32 | { | |
33 | //////////////////////////////////////////////////////////////////////// | |
34 | // Node | |
35 | ||
36 | struct value_node | |
37 | { | |
38 | private: | |
39 | value_node(value_node const&); | |
40 | value_node& operator=(value_node const&); | |
41 | ||
42 | public: | |
43 | typedef int tag_type; | |
44 | ||
45 | protected: | |
46 | explicit value_node(tag_type); | |
47 | virtual ~value_node(); | |
48 | ||
49 | public: | |
50 | virtual char const* type_name() const = 0; | |
51 | virtual value_node* clone() const = 0; | |
52 | ||
53 | virtual file_ptr get_file() const; | |
54 | virtual string_iterator get_position() const; | |
b32b8144 | 55 | virtual quickbook::string_view get_quickbook() const; |
7c673cae FG |
56 | virtual std::string get_encoded() const; |
57 | virtual int get_int() const; | |
58 | ||
59 | virtual bool check() const; | |
60 | virtual bool empty() const; | |
61 | virtual bool is_encoded() const; | |
62 | virtual bool is_list() const; | |
63 | virtual bool equals(value_node*) const; | |
64 | ||
65 | virtual value_node* get_list() const; | |
66 | ||
67 | int ref_count_; | |
68 | const tag_type tag_; | |
69 | value_node* next_; | |
70 | ||
71 | friend void intrusive_ptr_add_ref(value_node* ptr) | |
72 | { ++ptr->ref_count_; } | |
73 | friend void intrusive_ptr_release(value_node* ptr) | |
74 | { if(--ptr->ref_count_ == 0) delete ptr; } | |
75 | }; | |
76 | ||
77 | //////////////////////////////////////////////////////////////////////// | |
78 | // Value base | |
79 | // | |
80 | // This defines most of the public methods for value. | |
81 | // 'begin' and 'end' are defined with the iterators later. | |
82 | ||
83 | struct value_base | |
84 | { | |
85 | public: | |
86 | struct iterator; | |
87 | ||
88 | typedef iterator const_iterator; | |
89 | typedef value_node::tag_type tag_type; | |
90 | enum { default_tag = 0 }; | |
91 | ||
92 | protected: | |
93 | explicit value_base(value_node* base) | |
94 | : value_(base) | |
95 | { | |
96 | assert(value_); | |
97 | } | |
98 | ||
99 | ~value_base() {} | |
100 | ||
101 | void swap(value_base& x) { std::swap(value_, x.value_); } | |
102 | public: | |
103 | bool check() const { return value_->check(); } | |
104 | bool empty() const { return value_->empty(); } | |
105 | bool is_encoded() const { return value_->is_encoded(); } | |
106 | bool is_list() const { return value_->is_list(); } | |
107 | ||
108 | iterator begin() const; | |
109 | iterator end() const; | |
110 | ||
111 | // Item accessors | |
b32b8144 | 112 | tag_type get_tag() const { return value_->tag_; } |
7c673cae FG |
113 | file_ptr get_file() const |
114 | { return value_->get_file(); } | |
115 | string_iterator get_position() const | |
116 | { return value_->get_position(); } | |
b32b8144 | 117 | quickbook::string_view get_quickbook() const |
7c673cae FG |
118 | { return value_->get_quickbook(); } |
119 | std::string get_encoded() const | |
120 | { return value_->get_encoded(); } | |
121 | int get_int() const | |
122 | { return value_->get_int(); } | |
123 | ||
124 | // Equality is pretty inefficient. Not really designed for anything | |
125 | // more than testing purposes. | |
126 | friend bool operator==(value_base const& x, value_base const& y) | |
127 | { return x.value_->equals(y.value_); } | |
128 | ||
129 | protected: | |
130 | value_node* value_; | |
131 | ||
132 | // value_builder needs to access 'value_' to get the node | |
133 | // from a value. | |
134 | friend struct quickbook::value_builder; | |
135 | }; | |
136 | ||
137 | //////////////////////////////////////////////////////////////////////// | |
138 | // Reference and proxy values for use in iterators | |
139 | ||
140 | struct value_ref : public value_base | |
141 | { | |
142 | public: | |
143 | explicit value_ref(value_node* base) : value_base(base) {} | |
144 | }; | |
145 | ||
146 | struct value_proxy : public value_base | |
147 | { | |
148 | public: | |
149 | explicit value_proxy(value_node* base) : value_base(base) {} | |
150 | value_proxy* operator->() { return this; } | |
151 | value_ref operator*() const { return value_ref(value_); } | |
152 | }; | |
153 | ||
154 | //////////////////////////////////////////////////////////////////////// | |
155 | // Iterators | |
156 | ||
157 | struct value_base::iterator | |
158 | : public boost::forward_iterator_helper< | |
159 | iterator, value, int, value_proxy, value_ref> | |
160 | { | |
161 | public: | |
162 | iterator(); | |
163 | explicit iterator(value_node* p) : ptr_(p) {} | |
164 | friend bool operator==(iterator x, iterator y) | |
165 | { return x.ptr_ == y.ptr_; } | |
166 | iterator& operator++() { ptr_ = ptr_->next_; return *this; } | |
167 | value_ref operator*() const { return value_ref(ptr_); } | |
168 | value_proxy operator->() const { return value_proxy(ptr_); } | |
169 | private: | |
170 | value_node* ptr_; | |
171 | }; | |
172 | ||
173 | inline value_base::iterator value_base::begin() const | |
174 | { | |
175 | return iterator(value_->get_list()); | |
176 | } | |
177 | ||
178 | inline value_base::iterator value_base::end() const | |
179 | { | |
180 | return iterator(); | |
181 | } | |
182 | ||
183 | //////////////////////////////////////////////////////////////////////// | |
184 | // Reference counting for values | |
185 | ||
186 | struct value_counted : public value_base | |
187 | { | |
188 | value_counted& operator=(value_counted const&); | |
189 | protected: | |
190 | value_counted(); | |
191 | value_counted(value_counted const&); | |
192 | value_counted(value_base const&); | |
193 | value_counted(value_node*); | |
194 | ~value_counted(); | |
195 | }; | |
196 | ||
197 | //////////////////////////////////////////////////////////////////////// | |
198 | // List builder | |
199 | // | |
200 | // Values are immutable, so this class is used to build a list of | |
201 | // value nodes before constructing the value. | |
202 | ||
203 | struct value_list_builder { | |
204 | value_list_builder(value_list_builder const&); | |
205 | value_list_builder& operator=(value_list_builder const&); | |
206 | public: | |
207 | value_list_builder(); | |
208 | value_list_builder(value_node*); | |
209 | ~value_list_builder(); | |
210 | void swap(value_list_builder& b); | |
211 | value_node* release(); | |
212 | ||
213 | void append(value_node*); | |
214 | void sort(); | |
215 | ||
216 | bool empty() const; | |
217 | private: | |
218 | value_node* head_; | |
219 | value_node** back_; | |
220 | }; | |
221 | } | |
222 | ||
223 | //////////////////////////////////////////////////////////////////////////// | |
224 | // Value | |
225 | // | |
226 | // Most of the methods are in value_base. | |
227 | ||
228 | struct value : public detail::value_counted | |
229 | { | |
230 | public: | |
231 | value(); | |
232 | value(value const&); | |
233 | value(detail::value_base const&); | |
234 | explicit value(detail::value_node*); | |
235 | value& operator=(value); | |
236 | void swap(value& x) { detail::value_counted::swap(x); } | |
237 | }; | |
238 | ||
239 | // Empty | |
240 | value empty_value(value::tag_type = value::default_tag); | |
241 | ||
242 | // Integers | |
243 | value int_value(int, value::tag_type = value::default_tag); | |
244 | ||
245 | // String types | |
246 | ||
247 | // Quickbook strings contain a reference to the original quickbook source. | |
248 | value qbk_value(file_ptr const&, string_iterator, string_iterator, | |
249 | value::tag_type = value::default_tag); | |
250 | ||
251 | // Encoded strings are either plain text or boostbook. | |
252 | value encoded_value(std::string const&, | |
253 | value::tag_type = value::default_tag); | |
254 | ||
255 | // An encoded quickbook string is an encoded string that contains a | |
256 | // reference to the quickbook source it was generated from. | |
257 | value encoded_qbk_value(file_ptr const&, string_iterator, string_iterator, | |
258 | std::string const&, value::tag_type = value::default_tag); | |
259 | ||
260 | //////////////////////////////////////////////////////////////////////////// | |
261 | // Value Builder | |
262 | // | |
263 | // Used to incrementally build a valueeter tree. | |
264 | ||
265 | struct value_builder { | |
266 | public: | |
267 | value_builder(); | |
268 | void swap(value_builder& b); | |
269 | ||
270 | void save(); | |
271 | void restore(); | |
272 | ||
273 | value release(); | |
274 | ||
275 | void insert(value const&); | |
276 | void extend(value const&); | |
277 | ||
278 | void start_list(value::tag_type = value::default_tag); | |
279 | void finish_list(); | |
280 | void clear_list(); | |
281 | void sort_list(); | |
282 | ||
283 | bool empty() const; | |
284 | ||
285 | private: | |
286 | detail::value_list_builder current; | |
287 | value::tag_type list_tag; | |
288 | boost::scoped_ptr<value_builder> saved; | |
289 | }; | |
290 | ||
291 | //////////////////////////////////////////////////////////////////////////// | |
292 | // Value Error | |
293 | // | |
294 | ||
295 | struct value_error : public std::logic_error | |
296 | { | |
297 | public: | |
298 | explicit value_error(std::string const&); | |
299 | }; | |
300 | ||
301 | //////////////////////////////////////////////////////////////////////////// | |
302 | // Value Consumer | |
303 | // | |
304 | // Convenience class for unpacking value values. | |
305 | ||
306 | struct value_consumer { | |
307 | public: | |
308 | struct iterator | |
309 | : public boost::input_iterator_helper<iterator, | |
310 | boost::iterator_value<value::iterator>::type, | |
311 | boost::iterator_difference<value::iterator>::type, | |
312 | boost::iterator_pointer<value::iterator>::type, | |
313 | boost::iterator_reference<value::iterator>::type> | |
314 | { | |
315 | public: | |
316 | iterator(); | |
317 | explicit iterator(value::iterator* p) : ptr_(p) {} | |
318 | friend bool operator==(iterator x, iterator y) | |
319 | { return *x.ptr_ == *y.ptr_; } | |
320 | iterator& operator++() { ++*ptr_; return *this; } | |
321 | reference operator*() const { return **ptr_; } | |
322 | pointer operator->() const { return ptr_->operator->(); } | |
323 | private: | |
324 | value::iterator* ptr_; | |
325 | }; | |
326 | ||
327 | typedef iterator const_iterator; | |
328 | typedef iterator::reference reference; | |
329 | ||
330 | value_consumer(value const& x) | |
331 | : list_(x) | |
332 | , pos_(x.begin()) | |
333 | , end_(x.end()) | |
334 | {} | |
335 | ||
336 | value_consumer(reference x) | |
337 | : list_(x) | |
338 | , pos_(x.begin()) | |
339 | , end_(x.end()) | |
340 | {} | |
341 | ||
342 | reference consume() | |
343 | { | |
344 | assert_check(); | |
345 | return *pos_++; | |
346 | } | |
347 | ||
348 | reference consume(value::tag_type t) | |
349 | { | |
350 | assert_check(t); | |
351 | return *pos_++; | |
352 | } | |
353 | ||
354 | value optional_consume() | |
355 | { | |
356 | if(check()) { | |
357 | return *pos_++; | |
358 | } | |
359 | else { | |
360 | return value(); | |
361 | } | |
362 | } | |
363 | ||
364 | value optional_consume(value::tag_type t) | |
365 | { | |
366 | if(check(t)) { | |
367 | return *pos_++; | |
368 | } | |
369 | else { | |
370 | return value(); | |
371 | } | |
372 | } | |
373 | ||
374 | bool check() const | |
375 | { | |
376 | return pos_ != end_; | |
377 | } | |
378 | ||
379 | bool check(value::tag_type t) const | |
380 | { | |
381 | return pos_ != end_ && t == pos_->get_tag(); | |
382 | } | |
383 | ||
384 | void finish() const | |
385 | { | |
386 | if (pos_ != end_) | |
387 | throw value_error("Not all values handled."); | |
388 | } | |
389 | ||
390 | iterator begin() { return iterator(&pos_); } | |
391 | iterator end() { return iterator(&end_); } | |
392 | private: | |
393 | ||
394 | void assert_check() const | |
395 | { | |
396 | if (pos_ == end_) | |
397 | throw value_error("Attempt to read past end of value list."); | |
398 | } | |
399 | ||
400 | void assert_check(value::tag_type t) const | |
401 | { | |
402 | assert_check(); | |
403 | if (t != pos_->get_tag()) | |
404 | throw value_error("Incorrect value tag."); | |
405 | } | |
406 | ||
407 | value list_; | |
408 | value::iterator pos_, end_; | |
409 | }; | |
410 | } | |
411 | ||
412 | #endif |