diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
commit | 19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch) | |
tree | 42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/boost/tools/quickbook/src/values.cpp | |
parent | Initial commit. (diff) | |
download | ceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.tar.xz ceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.zip |
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/tools/quickbook/src/values.cpp')
-rw-r--r-- | src/boost/tools/quickbook/src/values.cpp | 829 |
1 files changed, 829 insertions, 0 deletions
diff --git a/src/boost/tools/quickbook/src/values.cpp b/src/boost/tools/quickbook/src/values.cpp new file mode 100644 index 000000000..6e2c3ec91 --- /dev/null +++ b/src/boost/tools/quickbook/src/values.cpp @@ -0,0 +1,829 @@ +/*============================================================================= + Copyright (c) 2010-2011 Daniel James + + Use, modification and distribution is subject to the Boost Software + License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#include "values.hpp" +#include <boost/current_function.hpp> +#include <boost/lexical_cast.hpp> +#include "files.hpp" + +#define UNDEFINED_ERROR() \ + throw value_undefined_method( \ + std::string(BOOST_CURRENT_FUNCTION) + " not defined for " + \ + this->type_name() + " values."); + +namespace quickbook +{ + //////////////////////////////////////////////////////////////////////////// + // Value Error + + struct value_undefined_method : value_error + { + value_undefined_method(std::string const&); + }; + + value_error::value_error(std::string const& x) : std::logic_error(x) {} + + value_undefined_method::value_undefined_method(std::string const& x) + : value_error(x) + { + } + + //////////////////////////////////////////////////////////////////////////// + // Node + + namespace detail + { + value_node::value_node(tag_type t) : ref_count_(0), tag_(t), next_() {} + + value_node::~value_node() {} + + file_ptr value_node::get_file() const { UNDEFINED_ERROR(); } + string_iterator value_node::get_position() const { UNDEFINED_ERROR(); } + int value_node::get_int() const { UNDEFINED_ERROR(); } + quickbook::string_view value_node::get_quickbook() const + { + UNDEFINED_ERROR(); + } + std::string value_node::get_encoded() const { UNDEFINED_ERROR(); } + value_node* value_node::get_list() const { UNDEFINED_ERROR(); } + + bool value_node::empty() const { return false; } + bool value_node::check() const { return true; } + bool value_node::is_list() const { return false; } + bool value_node::is_encoded() const { return false; } + bool value_node::equals(value_node*) const { UNDEFINED_ERROR(); } + } + + //////////////////////////////////////////////////////////////////////////// + // List end value + // + // A special value for marking the end of lists. + + namespace detail + { + struct value_list_end_impl : public value_node + { + static value_list_end_impl instance; + + private: + value_list_end_impl() : value_node(value::default_tag) + { + intrusive_ptr_add_ref(&instance); + next_ = this; + } + + virtual char const* type_name() const { return "list end"; } + virtual value_node* clone() const { UNDEFINED_ERROR(); } + + virtual bool equals(value_node* other) const + { + return this == other; + } + + bool empty() const { UNDEFINED_ERROR(); } + bool check() const { UNDEFINED_ERROR(); } + bool is_list() const { UNDEFINED_ERROR(); } + bool is_encoded() const { UNDEFINED_ERROR(); } + }; + + value_list_end_impl value_list_end_impl::instance; + } + + //////////////////////////////////////////////////////////////////////////// + // Empty/nil values + // + // (nil is just a special case of empty, don't be mislead by the name + // the type is not important). + + namespace detail + { + struct empty_value_impl : public value_node + { + static value_node* new_(value::tag_type t); + + protected: + explicit empty_value_impl(value::tag_type t) : value_node(t) {} + + private: + char const* type_name() const { return "empty"; } + + virtual value_node* clone() const + { + return new empty_value_impl(tag_); + } + + virtual bool empty() const { return true; } + + virtual bool check() const { return false; } + + virtual bool equals(value_node* other) const + { + return !other->check(); + } + + friend value quickbook::empty_value(value::tag_type); + }; + + struct value_nil_impl : public empty_value_impl + { + static value_nil_impl instance; + + private: + value_nil_impl() : empty_value_impl(value::default_tag) + { + intrusive_ptr_add_ref(&instance); + next_ = &value_list_end_impl::instance; + } + }; + + value_nil_impl value_nil_impl::instance; + + value_node* empty_value_impl::new_(value::tag_type t) + { + // The return value from this function is always placed in an + // intrusive_ptr which will manage the memory correctly. + // Note that value_nil_impl increments its reference count + // in its constructor, so that it will never be deleted by the + // intrusive pointer. + + if (t == value::default_tag) + return &value_nil_impl::instance; + else + return new empty_value_impl(t); + } + } + + value empty_value(value::tag_type t) + { + return value(detail::empty_value_impl::new_(t)); + } + + //////////////////////////////////////////////////////////////////////////// + // value_counted + + namespace detail + { + value_counted::value_counted() : value_base(&value_nil_impl::instance) + { + // Even though empty is not on the heap, its reference + // counter needs to be incremented so that the destructor + // doesn't try to delete it. + + intrusive_ptr_add_ref(value_); + } + + value_counted::value_counted(value_counted const& x) : value_base(x) + { + intrusive_ptr_add_ref(value_); + } + + value_counted::value_counted(value_base const& x) : value_base(x) + { + intrusive_ptr_add_ref(value_); + } + + value_counted::value_counted(value_node* x) : value_base(x) + { + intrusive_ptr_add_ref(value_); + } + + value_counted::~value_counted() { intrusive_ptr_release(value_); } + } + + //////////////////////////////////////////////////////////////////////////// + // value + + value::value() : detail::value_counted() {} + + value::value(value const& x) : detail::value_counted(x) {} + + value::value(detail::value_base const& x) : detail::value_counted(x) {} + + value::value(detail::value_node* x) : detail::value_counted(x) {} + + value& value::operator=(value x) + { + swap(x); + return *this; + } + + //////////////////////////////////////////////////////////////////////////// + // Integers + + namespace detail + { + struct int_value_impl : public value_node + { + public: + explicit int_value_impl(int, value::tag_type); + + private: + char const* type_name() const { return "integer"; } + virtual value_node* clone() const; + virtual int get_int() const; + virtual std::string get_encoded() const; + virtual bool empty() const; + virtual bool is_encoded() const; + virtual bool equals(value_node*) const; + + int value_; + }; + + int_value_impl::int_value_impl(int v, value::tag_type t) + : value_node(t), value_(v) + { + } + + value_node* int_value_impl::clone() const + { + return new int_value_impl(value_, tag_); + } + + int int_value_impl::get_int() const { return value_; } + + std::string int_value_impl::get_encoded() const + { + return boost::lexical_cast<std::string>(value_); + } + + bool int_value_impl::empty() const { return false; } + + bool int_value_impl::is_encoded() const { return true; } + + bool int_value_impl::equals(value_node* other) const + { + try { + return value_ == other->get_int(); + } catch (value_undefined_method&) { + return false; + } + } + } + + value int_value(int v, value::tag_type t) + { + return value(new detail::int_value_impl(v, t)); + } + + //////////////////////////////////////////////////////////////////////////// + // Strings + + namespace detail + { + struct encoded_value_impl : public value_node + { + public: + explicit encoded_value_impl(std::string const&, value::tag_type); + + private: + char const* type_name() const { return "encoded text"; } + + virtual ~encoded_value_impl(); + virtual value_node* clone() const; + virtual std::string get_encoded() const; + virtual bool empty() const; + virtual bool is_encoded() const; + virtual bool equals(value_node*) const; + + std::string value_; + }; + + struct qbk_value_impl : public value_node + { + public: + explicit qbk_value_impl( + file_ptr const&, + string_iterator begin, + string_iterator end, + value::tag_type); + + private: + char const* type_name() const { return "quickbook"; } + + virtual ~qbk_value_impl(); + virtual value_node* clone() const; + virtual file_ptr get_file() const; + virtual string_iterator get_position() const; + virtual quickbook::string_view get_quickbook() const; + virtual bool empty() const; + virtual bool equals(value_node*) const; + + file_ptr file_; + string_iterator begin_; + string_iterator end_; + }; + + struct encoded_qbk_value_impl : public value_node + { + private: + char const* type_name() const + { + return "encoded text with quickbook reference"; + } + + encoded_qbk_value_impl( + file_ptr const&, + string_iterator, + string_iterator, + std::string const&, + value::tag_type); + + virtual ~encoded_qbk_value_impl(); + virtual value_node* clone() const; + virtual file_ptr get_file() const; + virtual string_iterator get_position() const; + virtual quickbook::string_view get_quickbook() const; + virtual std::string get_encoded() const; + virtual bool empty() const; + virtual bool is_encoded() const; + virtual bool equals(value_node*) const; + + file_ptr file_; + string_iterator begin_; + string_iterator end_; + std::string encoded_value_; + + friend quickbook::value quickbook::encoded_qbk_value( + file_ptr const&, + string_iterator, + string_iterator, + std::string const&, + quickbook::value::tag_type); + }; + + // encoded_value_impl + + encoded_value_impl::encoded_value_impl( + std::string const& val, value::tag_type tag) + : value_node(tag), value_(val) + { + } + + encoded_value_impl::~encoded_value_impl() {} + + value_node* encoded_value_impl::clone() const + { + return new encoded_value_impl(value_, tag_); + } + + std::string encoded_value_impl::get_encoded() const { return value_; } + + bool encoded_value_impl::empty() const { return value_.empty(); } + + bool encoded_value_impl::is_encoded() const { return true; } + + bool encoded_value_impl::equals(value_node* other) const + { + try { + return value_ == other->get_encoded(); + } catch (value_undefined_method&) { + return false; + } + } + + // qbk_value_impl + + qbk_value_impl::qbk_value_impl( + file_ptr const& f, + string_iterator begin, + string_iterator end, + value::tag_type tag) + : value_node(tag), file_(f), begin_(begin), end_(end) + { + } + + qbk_value_impl::~qbk_value_impl() {} + + value_node* qbk_value_impl::clone() const + { + return new qbk_value_impl(file_, begin_, end_, tag_); + } + + file_ptr qbk_value_impl::get_file() const { return file_; } + + string_iterator qbk_value_impl::get_position() const { return begin_; } + + quickbook::string_view qbk_value_impl::get_quickbook() const + { + return quickbook::string_view(begin_, end_ - begin_); + } + + bool qbk_value_impl::empty() const { return begin_ == end_; } + + bool qbk_value_impl::equals(value_node* other) const + { + try { + return this->get_quickbook() == other->get_quickbook(); + } catch (value_undefined_method&) { + return false; + } + } + + // encoded_qbk_value_impl + + encoded_qbk_value_impl::encoded_qbk_value_impl( + file_ptr const& f, + string_iterator begin, + string_iterator end, + std::string const& encoded, + value::tag_type tag) + : value_node(tag) + , file_(f) + , begin_(begin) + , end_(end) + , encoded_value_(encoded) + + { + } + + encoded_qbk_value_impl::~encoded_qbk_value_impl() {} + + value_node* encoded_qbk_value_impl::clone() const + { + return new encoded_qbk_value_impl( + file_, begin_, end_, encoded_value_, tag_); + } + + file_ptr encoded_qbk_value_impl::get_file() const { return file_; } + + string_iterator encoded_qbk_value_impl::get_position() const + { + return begin_; + } + + quickbook::string_view encoded_qbk_value_impl::get_quickbook() const + { + return quickbook::string_view(begin_, end_ - begin_); + } + + std::string encoded_qbk_value_impl::get_encoded() const + { + return encoded_value_; + } + + // Should this test the quickbook, the boostbook or both? + bool encoded_qbk_value_impl::empty() const + { + return encoded_value_.empty(); + } + + bool encoded_qbk_value_impl::is_encoded() const { return true; } + + bool encoded_qbk_value_impl::equals(value_node* other) const + { + try { + return this->get_quickbook() == other->get_quickbook(); + } catch (value_undefined_method&) { + } + + try { + return this->get_encoded() == other->get_encoded(); + } catch (value_undefined_method&) { + } + + return false; + } + } + + value qbk_value( + file_ptr const& f, + string_iterator x, + string_iterator y, + value::tag_type t) + { + return value(new detail::qbk_value_impl(f, x, y, t)); + } + + value encoded_value(std::string const& x, value::tag_type t) + { + return value(new detail::encoded_value_impl(x, t)); + } + + value encoded_qbk_value( + file_ptr const& f, + string_iterator x, + string_iterator y, + std::string const& z, + value::tag_type t) + { + return value(new detail::encoded_qbk_value_impl(f, x, y, z, t)); + } + + ////////////////////////////////////////////////////////////////////////// + // List methods + + namespace detail + { + namespace + { + value_node** list_ref_back(value_node**); + void list_ref(value_node*); + void list_unref(value_node*); + value_node** merge_sort(value_node**); + value_node** merge_sort(value_node**, int); + value_node** merge(value_node**, value_node**, value_node**); + void rotate(value_node**, value_node**, value_node**); + + value_node** list_ref_back(value_node** back) + { + while (*back != &value_list_end_impl::instance) { + intrusive_ptr_add_ref(*back); + back = &(*back)->next_; + } + + return back; + } + + void list_ref(value_node* ptr) + { + while (ptr != &value_list_end_impl::instance) { + intrusive_ptr_add_ref(ptr); + ptr = ptr->next_; + } + } + + void list_unref(value_node* ptr) + { + while (ptr != &value_list_end_impl::instance) { + value_node* next = ptr->next_; + intrusive_ptr_release(ptr); + ptr = next; + } + } + + value_node** merge_sort(value_node** l) + { + if (*l == &value_list_end_impl::instance) + return l; + else + return merge_sort(l, 9999); + } + + value_node** merge_sort(value_node** l, int recurse_limit) + { + value_node** p = &(*l)->next_; + for (int count = 0; count < recurse_limit && + *p != &value_list_end_impl::instance; + ++count) { + p = merge(l, p, merge_sort(p, count)); + } + return p; + } + + value_node** merge( + value_node** first, value_node** second, value_node** third) + { + for (;;) { + for (;;) { + if (first == second) return third; + if ((*second)->tag_ < (*first)->tag_) break; + first = &(*first)->next_; + } + + rotate(first, second, third); + first = &(*first)->next_; + + // Since the two ranges were just swapped, the order is now: + // first...third...second + // + // Also, that since the second section of the list was + // originally before the first, if the heads are equal + // we need to swap to maintain the order. + + for (;;) { + if (first == third) return second; + if ((*third)->tag_ <= (*first)->tag_) break; + first = &(*first)->next_; + } + + rotate(first, third, second); + first = &(*first)->next_; + } + } + + void rotate( + value_node** first, value_node** second, value_node** third) + { + value_node* tmp = *first; + *first = *second; + *second = *third; + *third = tmp; + // if(*second != &value_list_end_impl::instance) back = second; + } + } + } + + ////////////////////////////////////////////////////////////////////////// + // Lists + + namespace detail + { + struct value_list_impl : public value_node + { + value_list_impl(value::tag_type); + value_list_impl(value_list_builder&, value::tag_type); + + private: + value_list_impl(value_list_impl const&); + + char const* type_name() const { return "list"; } + + virtual ~value_list_impl(); + virtual value_node* clone() const; + virtual bool empty() const; + virtual bool equals(value_node*) const; + + virtual bool is_list() const; + virtual value_node* get_list() const; + + value_node* head_; + }; + + value_list_impl::value_list_impl(value::tag_type tag) + : value_node(tag), head_(&value_list_end_impl::instance) + { + } + + value_list_impl::value_list_impl( + value_list_builder& builder, value::tag_type tag) + : value_node(tag), head_(builder.release()) + { + } + + value_list_impl::value_list_impl(value_list_impl const& x) + : value_node(x.tag_), head_(x.head_) + { + list_ref(head_); + } + + value_list_impl::~value_list_impl() { list_unref(head_); } + + value_node* value_list_impl::clone() const + { + return new value_list_impl(*this); + } + + bool value_list_impl::empty() const + { + return head_ == &value_list_end_impl::instance; + } + + bool value_list_impl::is_list() const { return true; } + + value_node* value_list_impl::get_list() const { return head_; } + + bool value_list_impl::equals(value_node* other) const + { + value_node* x1; + + try { + x1 = other->get_list(); + } catch (value_undefined_method&) { + return false; + } + + for (value_node *x2 = head_; x1 != x2; + x1 = x1->next_, x2 = x2->next_) { + if (x2 == &value_list_end_impl::instance || !x1->equals(x2)) + return false; + } + + return true; + } + } + + ////////////////////////////////////////////////////////////////////////// + // List builder + + namespace detail + { + // value_list_builder + + value_list_builder::value_list_builder() + : head_(&value_list_end_impl::instance), back_(&head_) + { + } + + value_list_builder::value_list_builder(value_node* ptr) + : head_(ptr), back_(list_ref_back(&head_)) + { + } + + value_list_builder::~value_list_builder() { list_unref(head_); } + + void value_list_builder::swap(value_list_builder& other) + { + std::swap(head_, other.head_); + std::swap(back_, other.back_); + if (back_ == &other.head_) back_ = &head_; + if (other.back_ == &head_) other.back_ = &other.head_; + } + + value_node* value_list_builder::release() + { + value_node* r = head_; + head_ = &value_list_end_impl::instance; + back_ = &head_; + return r; + } + + void value_list_builder::append(value_node* item) + { + if (item->next_) item = item->clone(); + intrusive_ptr_add_ref(item); + item->next_ = *back_; + *back_ = item; + back_ = &item->next_; + } + + void value_list_builder::sort() + { + back_ = merge_sort(&head_); + assert(*back_ == &value_list_end_impl::instance); + } + + bool value_list_builder::empty() const + { + return head_ == &value_list_end_impl::instance; + } + } + + ////////////////////////////////////////////////////////////////////////// + // Value builder + + value_builder::value_builder() + : current(), list_tag(value::default_tag), saved() + { + } + + void value_builder::swap(value_builder& other) + { + current.swap(other.current); + std::swap(list_tag, other.list_tag); + saved.swap(other.saved); + } + + void value_builder::save() + { + boost::scoped_ptr<value_builder> store(new value_builder); + swap(*store); + saved.swap(store); + } + + void value_builder::restore() + { + boost::scoped_ptr<value_builder> store; + store.swap(saved); + swap(*store); + } + + value value_builder::release() + { + return value(new detail::value_list_impl(current, list_tag)); + } + + void value_builder::insert(value const& item) + { + current.append(item.value_); + } + + void value_builder::extend(value const& list) + { + for (value::iterator begin = list.begin(), end = list.end(); + begin != end; ++begin) { + insert(*begin); + } + } + + void value_builder::start_list(value::tag_type tag) + { + save(); + list_tag = tag; + } + + void value_builder::finish_list() + { + value list = release(); + restore(); + insert(list); + } + + void value_builder::clear_list() { restore(); } + + void value_builder::sort_list() { current.sort(); } + + bool value_builder::empty() const { return current.empty(); } + + //////////////////////////////////////////////////////////////////////////// + // Iterator + + namespace detail + { + value::iterator::iterator() : ptr_(&value_list_end_impl::instance) {} + } +} |