• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <cassert>
15 #include <stdexcept>
16 #include <string>
17 #include <utility>
18 #include <boost/iterator/iterator_traits.hpp>
19 #include <boost/operators.hpp>
20 #include <boost/scoped_ptr.hpp>
21 #include "files.hpp"
22 #include "fwd.hpp"
23 #include "string_view.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;
55             virtual quickbook::string_view get_quickbook() const;
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 
intrusive_ptr_add_ref(value_node * ptr)71             friend void intrusive_ptr_add_ref(value_node* ptr)
72             {
73                 ++ptr->ref_count_;
74             }
intrusive_ptr_release(value_node * ptr)75             friend void intrusive_ptr_release(value_node* ptr)
76             {
77                 if (--ptr->ref_count_ == 0) delete ptr;
78             }
79         };
80 
81         ////////////////////////////////////////////////////////////////////////
82         // Value base
83         //
84         // This defines most of the public methods for value.
85         // 'begin' and 'end' are defined with the iterators later.
86 
87         struct value_base
88         {
89           public:
90             struct iterator;
91 
92             typedef iterator const_iterator;
93             typedef value_node::tag_type tag_type;
94             enum
95             {
96                 default_tag = 0
97             };
98 
99           protected:
value_basequickbook::detail::value_base100             explicit value_base(value_node* base) : value_(base)
101             {
102                 assert(value_);
103             }
104 
~value_basequickbook::detail::value_base105             ~value_base() {}
106 
swapquickbook::detail::value_base107             void swap(value_base& x) { std::swap(value_, x.value_); }
108 
109           public:
checkquickbook::detail::value_base110             bool check() const { return value_->check(); }
emptyquickbook::detail::value_base111             bool empty() const { return value_->empty(); }
is_encodedquickbook::detail::value_base112             bool is_encoded() const { return value_->is_encoded(); }
is_listquickbook::detail::value_base113             bool is_list() const { return value_->is_list(); }
114 
115             iterator begin() const;
116             iterator end() const;
117 
118             // Item accessors
get_tagquickbook::detail::value_base119             tag_type get_tag() const { return value_->tag_; }
get_filequickbook::detail::value_base120             file_ptr get_file() const { return value_->get_file(); }
get_positionquickbook::detail::value_base121             string_iterator get_position() const
122             {
123                 return value_->get_position();
124             }
get_quickbookquickbook::detail::value_base125             quickbook::string_view get_quickbook() const
126             {
127                 return value_->get_quickbook();
128             }
get_encodedquickbook::detail::value_base129             std::string get_encoded() const { return value_->get_encoded(); }
get_intquickbook::detail::value_base130             int get_int() const { return value_->get_int(); }
131 
132             // Equality is pretty inefficient. Not really designed for anything
133             // more than testing purposes.
operator ==(value_base const & x,value_base const & y)134             friend bool operator==(value_base const& x, value_base const& y)
135             {
136                 return x.value_->equals(y.value_);
137             }
138 
139           protected:
140             value_node* value_;
141 
142             // value_builder needs to access 'value_' to get the node
143             // from a value.
144             friend struct quickbook::value_builder;
145         };
146 
147         ////////////////////////////////////////////////////////////////////////
148         // Reference and proxy values for use in iterators
149 
150         struct value_ref : public value_base
151         {
152           public:
value_refquickbook::detail::value_ref153             explicit value_ref(value_node* base) : value_base(base) {}
154         };
155 
156         struct value_proxy : public value_base
157         {
158           public:
value_proxyquickbook::detail::value_proxy159             explicit value_proxy(value_node* base) : value_base(base) {}
operator ->quickbook::detail::value_proxy160             value_proxy* operator->() { return this; }
operator *quickbook::detail::value_proxy161             value_ref operator*() const { return value_ref(value_); }
162         };
163 
164         ////////////////////////////////////////////////////////////////////////
165         // Iterators
166 
167         struct value_base::iterator : public boost::forward_iterator_helper<
168                                           iterator,
169                                           value,
170                                           int,
171                                           value_proxy,
172                                           value_ref>
173         {
174           public:
175             iterator();
iteratorquickbook::detail::value_base::iterator176             explicit iterator(value_node* p) : ptr_(p) {}
operator ==(iterator x,iterator y)177             friend bool operator==(iterator x, iterator y)
178             {
179                 return x.ptr_ == y.ptr_;
180             }
operator ++quickbook::detail::value_base::iterator181             iterator& operator++()
182             {
183                 ptr_ = ptr_->next_;
184                 return *this;
185             }
operator *quickbook::detail::value_base::iterator186             value_ref operator*() const { return value_ref(ptr_); }
operator ->quickbook::detail::value_base::iterator187             value_proxy operator->() const { return value_proxy(ptr_); }
188 
189           private:
190             value_node* ptr_;
191         };
192 
begin() const193         inline value_base::iterator value_base::begin() const
194         {
195             return iterator(value_->get_list());
196         }
197 
end() const198         inline value_base::iterator value_base::end() const
199         {
200             return iterator();
201         }
202 
203         ////////////////////////////////////////////////////////////////////////
204         // Reference counting for values
205 
206         struct value_counted : public value_base
207         {
208             value_counted& operator=(value_counted const&);
209 
210           protected:
211             value_counted();
212             value_counted(value_counted const&);
213             value_counted(value_base const&);
214             value_counted(value_node*);
215             ~value_counted();
216         };
217 
218         ////////////////////////////////////////////////////////////////////////
219         // List builder
220         //
221         // Values are immutable, so this class is used to build a list of
222         // value nodes before constructing the value.
223 
224         struct value_list_builder
225         {
226             value_list_builder(value_list_builder const&);
227             value_list_builder& operator=(value_list_builder const&);
228 
229           public:
230             value_list_builder();
231             value_list_builder(value_node*);
232             ~value_list_builder();
233             void swap(value_list_builder& b);
234             value_node* release();
235 
236             void append(value_node*);
237             void sort();
238 
239             bool empty() const;
240 
241           private:
242             value_node* head_;
243             value_node** back_;
244         };
245     }
246 
247     ////////////////////////////////////////////////////////////////////////////
248     // Value
249     //
250     // Most of the methods are in value_base.
251 
252     struct value : public detail::value_counted
253     {
254       public:
255         value();
256         value(value const&);
257         value(detail::value_base const&);
258         explicit value(detail::value_node*);
259         value& operator=(value);
swapquickbook::value260         void swap(value& x) { detail::value_counted::swap(x); }
261     };
262 
263     // Empty
264     value empty_value(value::tag_type = value::default_tag);
265 
266     // Integers
267     value int_value(int, value::tag_type = value::default_tag);
268 
269     // String types
270 
271     // Quickbook strings contain a reference to the original quickbook source.
272     value qbk_value(
273         file_ptr const&,
274         string_iterator,
275         string_iterator,
276         value::tag_type = value::default_tag);
277 
278     // Encoded strings are either plain text or boostbook.
279     value encoded_value(
280         std::string const&, value::tag_type = value::default_tag);
281 
282     // An encoded quickbook string is an encoded string that contains a
283     // reference to the quickbook source it was generated from.
284     value encoded_qbk_value(
285         file_ptr const&,
286         string_iterator,
287         string_iterator,
288         std::string const&,
289         value::tag_type = value::default_tag);
290 
291     ////////////////////////////////////////////////////////////////////////////
292     // Value Builder
293     //
294     // Used to incrementally build a valueeter tree.
295 
296     struct value_builder
297     {
298       public:
299         value_builder();
300         void swap(value_builder& b);
301 
302         void save();
303         void restore();
304 
305         value release();
306 
307         void insert(value const&);
308         void extend(value const&);
309 
310         void start_list(value::tag_type = value::default_tag);
311         void finish_list();
312         void clear_list();
313         void sort_list();
314 
315         bool empty() const;
316 
317       private:
318         detail::value_list_builder current;
319         value::tag_type list_tag;
320         boost::scoped_ptr<value_builder> saved;
321     };
322 
323     ////////////////////////////////////////////////////////////////////////////
324     // Value Error
325     //
326 
327     struct value_error : public std::logic_error
328     {
329       public:
330         explicit value_error(std::string const&);
331     };
332 
333     ////////////////////////////////////////////////////////////////////////////
334     // Value Consumer
335     //
336     // Convenience class for unpacking value values.
337 
338     struct value_consumer
339     {
340       public:
341         struct iterator : public boost::input_iterator_helper<
342                               iterator,
343                               boost::iterator_value<value::iterator>::type,
344                               boost::iterator_difference<value::iterator>::type,
345                               boost::iterator_pointer<value::iterator>::type,
346                               boost::iterator_reference<value::iterator>::type>
347         {
348           public:
349             iterator();
iteratorquickbook::value_consumer::iterator350             explicit iterator(value::iterator* p) : ptr_(p) {}
operator ==quickbook::value_consumer351             friend bool operator==(iterator x, iterator y)
352             {
353                 return *x.ptr_ == *y.ptr_;
354             }
operator ++quickbook::value_consumer::iterator355             iterator& operator++()
356             {
357                 ++*ptr_;
358                 return *this;
359             }
operator *quickbook::value_consumer::iterator360             reference operator*() const { return **ptr_; }
operator ->quickbook::value_consumer::iterator361             pointer operator->() const { return ptr_->operator->(); }
362 
363           private:
364             value::iterator* ptr_;
365         };
366 
367         typedef iterator const_iterator;
368         typedef iterator::reference reference;
369 
value_consumerquickbook::value_consumer370         value_consumer(value const& x)
371             : list_(x), pos_(x.begin()), end_(x.end())
372         {
373         }
374 
value_consumerquickbook::value_consumer375         value_consumer(reference x) : list_(x), pos_(x.begin()), end_(x.end())
376         {
377         }
378 
consumequickbook::value_consumer379         reference consume()
380         {
381             assert_check();
382             return *pos_++;
383         }
384 
consumequickbook::value_consumer385         reference consume(value::tag_type t)
386         {
387             assert_check(t);
388             return *pos_++;
389         }
390 
optional_consumequickbook::value_consumer391         value optional_consume()
392         {
393             if (check()) {
394                 return *pos_++;
395             }
396             else {
397                 return value();
398             }
399         }
400 
optional_consumequickbook::value_consumer401         value optional_consume(value::tag_type t)
402         {
403             if (check(t)) {
404                 return *pos_++;
405             }
406             else {
407                 return value();
408             }
409         }
410 
checkquickbook::value_consumer411         bool check() const { return pos_ != end_; }
412 
checkquickbook::value_consumer413         bool check(value::tag_type t) const
414         {
415             return pos_ != end_ && t == pos_->get_tag();
416         }
417 
finishquickbook::value_consumer418         void finish() const
419         {
420             if (pos_ != end_) throw value_error("Not all values handled.");
421         }
422 
beginquickbook::value_consumer423         iterator begin() { return iterator(&pos_); }
endquickbook::value_consumer424         iterator end() { return iterator(&end_); }
425 
426       private:
assert_checkquickbook::value_consumer427         void assert_check() const
428         {
429             if (pos_ == end_)
430                 throw value_error("Attempt to read past end of value list.");
431         }
432 
assert_checkquickbook::value_consumer433         void assert_check(value::tag_type t) const
434         {
435             assert_check();
436             if (t != pos_->get_tag()) throw value_error("Incorrect value tag.");
437         }
438 
439         value list_;
440         value::iterator pos_, end_;
441     };
442 }
443 
444 #endif
445