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