diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
commit | 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch) | |
tree | e5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/boost/libs/flyweight/example | |
parent | Initial commit. (diff) | |
download | ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.tar.xz ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.zip |
Adding upstream version 14.2.21.upstream/14.2.21upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/flyweight/example')
-rw-r--r-- | src/boost/libs/flyweight/example/Jamfile.v2 | 55 | ||||
-rw-r--r-- | src/boost/libs/flyweight/example/basic.cpp | 152 | ||||
-rw-r--r-- | src/boost/libs/flyweight/example/composite.cpp | 174 | ||||
-rw-r--r-- | src/boost/libs/flyweight/example/custom_factory.cpp | 122 | ||||
-rw-r--r-- | src/boost/libs/flyweight/example/fibonacci.cpp | 58 | ||||
-rw-r--r-- | src/boost/libs/flyweight/example/html.cpp | 321 | ||||
-rw-r--r-- | src/boost/libs/flyweight/example/key_value.cpp | 99 | ||||
-rw-r--r-- | src/boost/libs/flyweight/example/perf.cpp | 312 | ||||
-rw-r--r-- | src/boost/libs/flyweight/example/serialization.cpp | 133 |
9 files changed, 1426 insertions, 0 deletions
diff --git a/src/boost/libs/flyweight/example/Jamfile.v2 b/src/boost/libs/flyweight/example/Jamfile.v2 new file mode 100644 index 00000000..3c9bcd18 --- /dev/null +++ b/src/boost/libs/flyweight/example/Jamfile.v2 @@ -0,0 +1,55 @@ +# Boost.Flyweight examples Jamfile +# +# Copyright 2006-2014 Joaquín M López Muñoz. +# Distributed under 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) +# +# See http://www.boost.org/libs/flyweight for library home page. + +project + : requirements + <os>LINUX:<threading>multi + ; + +exe basic + : basic.cpp + : <include>$(BOOST_ROOT) + ; + +exe composite + : composite.cpp + : <include>$(BOOST_ROOT) + ; + +exe custom_factory + : custom_factory.cpp + : <include>$(BOOST_ROOT) + ; + +exe fibonacci + : fibonacci.cpp + : <include>$(BOOST_ROOT) + ; + +exe html + : html.cpp + : <include>$(BOOST_ROOT) + ; + +exe key_value + : key_value.cpp + : <include>$(BOOST_ROOT) + ; + +exe perf + : perf.cpp + : <include>$(BOOST_ROOT) + : release + ; + +exe serialization + : serialization.cpp + /boost/serialization//boost_serialization/<link>static + : <include>$(BOOST_ROOT) + ; diff --git a/src/boost/libs/flyweight/example/basic.cpp b/src/boost/libs/flyweight/example/basic.cpp new file mode 100644 index 00000000..405dff72 --- /dev/null +++ b/src/boost/libs/flyweight/example/basic.cpp @@ -0,0 +1,152 @@ +/* Boost.Flyweight basic example. + * + * Copyright 2006-2008 Joaquin M Lopez Munoz. + * Distributed under 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) + * + * See http://www.boost.org/libs/flyweight for library home page. + */ + +#include <boost/bind.hpp> +#include <boost/flyweight.hpp> +#include <algorithm> +#include <iostream> +#include <iterator> +#include <sstream> +#include <string> +#include <vector> + +using namespace boost::flyweights; + +/* Information associated to a given user of some massive system. + * first_name and last_name are turned into flyweights to leverage the + * implicit redundancy of names within the user community. + */ + +struct user_entry +{ + flyweight<std::string> first_name; + flyweight<std::string> last_name; + int age; + + user_entry(); + user_entry(const char* first_name,const char* last_name,int age); + user_entry(const user_entry& x); +}; + +/* flyweight<std::string> default ctor simply calls the default ctor of + * std::string. + */ + +user_entry::user_entry() +{} + +/* flyweight<std::string> is constructible from a const char* much as + * a std::string is. + */ + +user_entry::user_entry(const char* f,const char* l,int a): + first_name(f), + last_name(l), + age(a) +{} + +/* flyweight's are copyable and assignable --unlike std::string, + * copy and assignment of flyweight<std::string>s do not ever throw. + */ + +user_entry::user_entry(const user_entry& x): + first_name(x.first_name), + last_name(x.last_name), + age(x.age) +{} + +/* flyweight<std::string> has operator==,!=,<,>,<=,>= with the same + * semantics as those of std::string. + */ + +bool same_name(const user_entry& user1,const user_entry& user2) +{ + bool b=user1.first_name==user2.first_name && + user1.last_name==user2.last_name; + return b; +} + +/* operator<< forwards to the std::string overload */ + +std::ostream& operator<<(std::ostream& os,const user_entry& user) +{ + return os<<user.first_name<<" "<<user.last_name<<" "<<user.age; +} + +/* operator>> internally uses std::string's operator>> */ + +std::istream& operator>>(std::istream& is,user_entry& user) +{ + return is>>user.first_name>>user.last_name>>user.age; +} + +std::string full_name(const user_entry& user) +{ + std::string full; + + /* get() returns the underlying const std::string& */ + + full.reserve( + user.first_name.get().size()+user.last_name.get().size()+1); + + /* here, on the other hand, implicit conversion is used */ + + full+=user.first_name; + full+=" "; + full+=user.last_name; + + return full; +} + +/* flyweight<std::string> value is immutable, but a flyweight object can + * be assigned a different value. + */ + +void change_name(user_entry& user,const std::string& f,const std::string& l) +{ + user.first_name=f; + user.last_name=l; +} + +int main() +{ + /* play a little with a vector of user_entry's */ + + std::string users_txt= + "olegh smith 31\n" + "john brown 28\n" + "anna jones 45\n" + "maria garcia 30\n" + "john fox 56\n" + "anna brown 19\n" + "thomas smith 46\n" + "andrew martin 28"; + + std::vector<user_entry> users; + std::istringstream iss(users_txt); + while(iss){ + user_entry u; + if(iss>>u)users.push_back(u); + } + + change_name(users[0],"oleg","smith"); + + user_entry anna("anna","jones",20); + std::replace_if( + users.begin(),users.end(), + boost::bind(same_name,_1,anna), + anna); + + std::copy( + users.begin(),users.end(), + std::ostream_iterator<user_entry>(std::cout,"\n")); + + return 0; +} diff --git a/src/boost/libs/flyweight/example/composite.cpp b/src/boost/libs/flyweight/example/composite.cpp new file mode 100644 index 00000000..1395f412 --- /dev/null +++ b/src/boost/libs/flyweight/example/composite.cpp @@ -0,0 +1,174 @@ +/* Boost.Flyweight example of a composite design. + * + * Copyright 2006-2014 Joaquin M Lopez Munoz. + * Distributed under 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) + * + * See http://www.boost.org/libs/flyweight for library home page. + */ + +#include <boost/flyweight.hpp> +#include <boost/functional/hash.hpp> +#include <boost/tokenizer.hpp> +#include <boost/variant.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/variant/recursive_wrapper.hpp> +#include <iostream> +#include <stdexcept> +#include <string> +#include <vector> + +using namespace boost::flyweights; + +/* A node of a lisp-like list can be modeled as a boost::variant of + * 1. A string (primitive node) + * 2. A vector of nodes (embedded list) + * To save space, 2 is stored as a vector of flyweights. + * As is usual with recursive data structures, a node can be thought + * of also as a list. To close the flyweight circle, the final + * type list is a flyweight wrapper, so that the final structure can + * be described as follows in BNF-like style: + * + * list ::= flyweight<list_impl> + * list_impl ::= std::string | std::vector<list> + */ + +struct list_elems; + +typedef boost::variant< + std::string, + boost::recursive_wrapper<list_elems> +> list_impl; + +struct list_elems:std::vector<flyweight<list_impl> >{}; + +typedef flyweight<list_impl> list; + +/* list_impl must be hashable to be used by flyweight: If a + * node is a std::string, its hash resolves to that of the string; + * if it is a vector of flyweight nodes, we combine their corresponding + * hash values. As hashing a flyweight does not involve actually hashing + * its pointed-to value, the resulting computation does not recursively + * descend down the entire data structure. + */ + +struct list_hasher:boost::static_visitor<std::size_t> +{ + std::size_t operator()(const std::string& str)const + { + boost::hash<std::string> h; + return h(str); + } + + std::size_t operator()(const list_elems& elms)const + { + std::size_t res=0; + for(list_elems::const_iterator it=elms.begin(),it_end=elms.end(); + it!=it_end;++it){ + boost::hash_combine(res,*it); + } + return res; + } +}; + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +namespace boost{ +#endif + +std::size_t hash_value(const list_impl& limpl) +{ + return boost::apply_visitor(list_hasher(),limpl); +} + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +} /* namespace boost */ +#endif + +/* basic pretty printer with indentation according to the nesting level */ + +struct list_pretty_printer:boost::static_visitor<> +{ + list_pretty_printer():nest(0){} + + void operator()(const std::string& str) + { + indent(); + std::cout<<str<<"\n"; + } + + void operator()(const boost::recursive_wrapper<list_elems>& elmsw) + { + indent(); + std::cout<<"(\n"; + ++nest; + const list_elems& elms=elmsw.get(); + for(list_elems::const_iterator it=elms.begin(),it_end=elms.end(); + it!=it_end;++it){ + boost::apply_visitor(*this,it->get()); + } + --nest; + indent(); + std::cout<<")\n"; + } + +private: + void indent()const + { + for(int i=nest;i--;)std::cout<<" "; + } + + int nest; +}; + +void pretty_print(const list& l) +{ + list_pretty_printer pp; + boost::apply_visitor(pp,l.get()); +} + +/* list parser */ + +template<typename InputIterator> +list parse_list(InputIterator& first,InputIterator last,int nest) +{ + list_elems elms; + while(first!=last){ + std::string str=*first++; + if(str=="("){ + elms.push_back(parse_list(first,last,nest+1)); + } + else if(str==")"){ + if(nest==0)throw std::runtime_error("unmatched )"); + return list(elms); + } + else{ + elms.push_back(list(str)); + } + } + if(nest!=0)throw std::runtime_error("unmatched ("); + return list(elms); +} + +list parse_list(const std::string str) +{ + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + tokenizer tok(str,boost::char_separator<char>(" ","()")); + tokenizer::iterator begin=tok.begin(); + return parse_list(begin,tok.end(),0); +} + +int main() +{ + std::cout<<"enter list: "; + std::string str; + std::getline(std::cin,str); + try{ + pretty_print(parse_list(str)); + } + catch(const std::exception& e){ + std::cout<<"error: "<<e.what()<<"\n"; + } + + return 0; +} diff --git a/src/boost/libs/flyweight/example/custom_factory.cpp b/src/boost/libs/flyweight/example/custom_factory.cpp new file mode 100644 index 00000000..3b9b2d88 --- /dev/null +++ b/src/boost/libs/flyweight/example/custom_factory.cpp @@ -0,0 +1,122 @@ +/* Boost.Flyweight example of custom factory. + * + * Copyright 2006-2008 Joaquin M Lopez Munoz. + * Distributed under 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) + * + * See http://www.boost.org/libs/flyweight for library home page. + */ + +/* We include the default components of Boost.Flyweight except the factory, + * which will be provided by ourselves. + */ +#include <boost/flyweight/flyweight.hpp> +#include <boost/flyweight/factory_tag.hpp> +#include <boost/flyweight/static_holder.hpp> +#include <boost/flyweight/simple_locking.hpp> +#include <boost/flyweight/refcounted.hpp> +#include <boost/tokenizer.hpp> +#include <functional> +#include <iostream> +#include <set> + +using namespace boost::flyweights; + +/* custom factory based on std::set with some logging capabilities */ + +/* Entry is the type of the stored objects. Value is the type + * on which flyweight operates, that is, the T in flyweoght<T>. It + * is guaranteed that Entry implicitly converts to const Value&. + * The factory class could accept other template arguments (for + * instance, a comparison predicate for the values), we leave it like + * that for simplicity. + */ + +template<typename Entry,typename Key> +class verbose_factory_class +{ + /* Entry store. Since Entry is implicitly convertible to const Key&, + * we can directly use std::less<Key> as the comparer for std::set. + */ + + typedef std::set<Entry,std::less<Key> > store_type; + + store_type store; + +public: + typedef typename store_type::iterator handle_type; + + handle_type insert(const Entry& x) + { + /* locate equivalent entry or insert otherwise */ + + std::pair<handle_type, bool> p=store.insert(x); + if(p.second){ /* new entry */ + std::cout<<"new: "<<(const Key&)x<<std::endl; + } + else{ /* existing entry */ + std::cout<<"hit: "<<(const Key&)x<<std::endl; + } + return p.first; + } + + void erase(handle_type h) + { + std::cout<<"del: "<<(const Key&)*h<<std::endl; + store.erase(h); + } + + const Entry& entry(handle_type h) + { + return *h; /* handle_type is an iterator */ + } +}; + +/* Specifier for verbose_factory_class. The simplest way to tag + * this struct as a factory specifier, so that flyweight<> accepts it + * as such, is by deriving from boost::flyweights::factory_marker. + * See the documentation for info on alternative tagging methods. + */ + +struct verbose_factory: factory_marker +{ + template<typename Entry,typename Key> + struct apply + { + typedef verbose_factory_class<Entry,Key> type; + } ; +}; + +/* ready to use it */ + +typedef flyweight<std::string,verbose_factory> fw_string; + +int main() +{ + typedef boost::tokenizer<boost::char_separator<char> > text_tokenizer; + + + std::string text= + "I celebrate myself, and sing myself, " + "And what I assume you shall assume, " + "For every atom belonging to me as good belongs to you. " + + "I loafe and invite my soul, " + "I lean and loafe at my ease observing a spear of summer grass. " + + "My tongue, every atom of my blood, form'd from this soil, this air, " + "Born here of parents born here from parents the same, and their " + " parents the same, " + "I, now thirty-seven years old in perfect health begin, " + "Hoping to cease not till death."; + + std::vector<fw_string> v; + + text_tokenizer tok(text,boost::char_separator<char>(" \t\n.,;:!?'\"-")); + for(text_tokenizer::iterator it=tok.begin();it!=tok.end();){ + v.push_back(fw_string(*it++)); + } + + return 0; +} diff --git a/src/boost/libs/flyweight/example/fibonacci.cpp b/src/boost/libs/flyweight/example/fibonacci.cpp new file mode 100644 index 00000000..618c5f2f --- /dev/null +++ b/src/boost/libs/flyweight/example/fibonacci.cpp @@ -0,0 +1,58 @@ +/* Boost.Flyweight example of flyweight-based memoization. + * + * Copyright 2006-2008 Joaquin M Lopez Munoz. + * Distributed under 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) + * + * See http://www.boost.org/libs/flyweight for library home page. + */ + +#include <boost/flyweight.hpp> +#include <boost/flyweight/key_value.hpp> +#include <boost/flyweight/no_tracking.hpp> +#include <boost/noncopyable.hpp> +#include <iostream> + +using namespace boost::flyweights; + +/* Memoized calculation of Fibonacci numbers */ + +/* This class takes an int n and calculates F(n) at construction time */ + +struct compute_fibonacci; + +/* A Fibonacci number can be modeled as a key-value flyweight + * We choose the no_tracking policy so that the calculations + * persist for future use throughout the program. See + * Tutorial: Configuring Boost.Flyweight: Tracking policies for + * further information on tracking policies. + */ + +typedef flyweight<key_value<int,compute_fibonacci>,no_tracking> fibonacci; + +/* Implementation of compute_fibonacci. Note that the construction + * of compute_fibonacci(n) uses fibonacci(n-1) and fibonacci(n-2), + * which effectively memoizes the computation. + */ + +struct compute_fibonacci:private boost::noncopyable +{ + compute_fibonacci(int n): + result(n==0?0:n==1?1:fibonacci(n-2).get()+fibonacci(n-1).get()) + {} + + operator int()const{return result;} + int result; +}; + +int main() +{ + /* list some Fibonacci numbers */ + + for(int n=0;n<40;++n){ + std::cout<<"F("<<n<<")="<<fibonacci(n)<<std::endl; + } + + return 0; +} diff --git a/src/boost/libs/flyweight/example/html.cpp b/src/boost/libs/flyweight/example/html.cpp new file mode 100644 index 00000000..1fa6d34c --- /dev/null +++ b/src/boost/libs/flyweight/example/html.cpp @@ -0,0 +1,321 @@ +/* Boost.Flyweight example of flyweight-based formatted text processing. + * + * Copyright 2006-2014 Joaquin M Lopez Munoz. + * Distributed under 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) + * + * See http://www.boost.org/libs/flyweight for library home page. + */ + +#include <boost/flyweight.hpp> +#include <boost/functional/hash.hpp> +#include <algorithm> +#include <cctype> +#include <cstdio> +#include <fstream> +#include <iostream> +#include <iterator> +#include <sstream> +#include <string> +#include <vector> + +#if defined(BOOST_NO_STDC_NAMESPACE) +namespace std{using ::exit;using ::tolower;} +#endif + +using namespace boost::flyweights; + +/* An HTML tag consists of a name and optional properties of the form + * name1=value1 ... namen=valuen. We do not need to parse the properties + * for the purposes of the program, hence they are all stored in + * html_tag_data::properties in raw form. + */ + +struct html_tag_data +{ + std::string name; + std::string properties; +}; + +bool operator==(const html_tag_data& x,const html_tag_data& y) +{ + return x.name==y.name&&x.properties==y.properties; +} + +/* See the portability section of Boost.Hash at + * http://boost.org/doc/html/hash/portability.html + * for an explanation of the ADL-related workarounds. + */ + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +namespace boost{ +#endif + +std::size_t hash_value(const html_tag_data& x) +{ + std::size_t res=0; + boost::hash_combine(res,x.name); + boost::hash_combine(res,x.properties); + return res; +} + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +} /* namespace boost */ +#endif + +typedef flyweight<html_tag_data> html_tag; + +/* parse_tag is passed an iterator positioned at the first char of + * the tag after the opening '<' and returns, if succesful, a parsed tag + * and whether it is opening (<xx>) or closing (</xx>). + */ + +enum tag_type{opening,closing,failure}; + +struct parse_tag_res +{ + parse_tag_res(tag_type type_,const html_tag_data& tag_=html_tag_data()): + type(type_),tag(tag_){} + parse_tag_res(const parse_tag_res& x):type(x.type),tag(x.tag){} + + tag_type type; + html_tag tag; +}; + +template<typename ForwardIterator> +parse_tag_res parse_tag(ForwardIterator& first,ForwardIterator last) +{ + html_tag_data tag; + std::string buf; + bool in_quote=false; + for(ForwardIterator it=first;it!=last;){ + char ch=*it++; + if(ch=='>'&&!in_quote){ /* ignore '>'s if inside quotes */ + tag_type type; + std::string::size_type + bname=buf.find_first_not_of("\t\n\r "), + ename=bname==std::string::npos? + std::string::npos: + buf.find_first_of("\t\n\r ",bname), + bprop=ename==std::string::npos? + std::string::npos: + buf.find_first_not_of("\t\n\r ",ename); + if(bname==ename){ /* null name */ + return parse_tag_res(failure); + } + else if(buf[bname]=='/'){ /* closing tag */ + type=closing; + ++bname; + } + else type=opening; + tag.name=buf.substr(bname,ename-bname); + std::transform( /* normalize tag name to lower case */ + tag.name.begin(),tag.name.end(),tag.name.begin(), + (int(*)(int))std::tolower); + if(bprop!=std::string::npos){ + tag.properties=buf.substr(bprop,buf.size()); + } + first=it; /* result good, consume the chars */ + return parse_tag_res(type,tag); + } + else{ + if(ch=='"')in_quote=!in_quote; + buf+=ch; + } + } + return parse_tag_res(failure); /* end reached and found no '>' */ +} + +/* A character context is just a vector containing the tags enclosing the + * character, from the outermost level to the innermost. + */ + +typedef std::vector<html_tag> html_context_data; +typedef flyweight<html_context_data> html_context; + +/* A character is a char code plus its context. + */ + +struct character_data +{ + character_data(char code_=0,html_context context_=html_context()): + code(code_),context(context_){} + character_data(const character_data& x):code(x.code),context(x.context){} + + char code; + html_context context; +}; + +bool operator==(const character_data& x,const character_data& y) +{ + return x.code==y.code&&x.context==y.context; +} + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +namespace boost{ +#endif + +std::size_t hash_value(const character_data& x) +{ + std::size_t res=0; + boost::hash_combine(res,x.code); + boost::hash_combine(res,x.context); + return res; +} + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +} /* namespace boost */ +#endif + +typedef flyweight<character_data> character; + +/* scan_html converts HTML code into a stream of contextualized characters. + */ + +template<typename ForwardIterator,typename OutputIterator> +void scan_html(ForwardIterator first,ForwardIterator last,OutputIterator out) +{ + html_context_data context; + while(first!=last){ + if(*first=='<'){ /* tag found */ + ++first; + parse_tag_res res=parse_tag(first,last); + if(res.type==opening){ /* add to contex */ + context.push_back(res.tag); + continue; + } + else if(res.type==closing){ /* remove from context */ + /* Pop all tags from the innermost to the matching one; this takes + * care of missing </xx>s like vg. in <ul><li>hello</ul>. + */ + + for(html_context_data::reverse_iterator rit=context.rbegin(); + rit!=context.rend();++rit){ + if(rit->get().name==res.tag.get().name){ + context.erase(rit.base()-1,context.end()); + break; + } + } + continue; + } + } + *out++=character(*first++,html_context(context)); + } +} + +/* HTML-producing utilities */ + +void print_opening_tag(std::ostream& os,const html_tag_data& x) +{ + os<<"<"<<x.name; + if(!x.properties.empty())os<<" "<<x.properties; + os<<">"; +} + +void print_closing_tag(std::ostream& os,const html_tag_data& x) +{ + /* SGML declarations (beginning with '!') are not closed */ + + if(x.name[0]!='!')os<<"</"<<x.name<<">"; +} + +/* change_context takes contexts from and to with tags + * + * from<- c1 ... cn fn+1 ... fm + * to <- c1 ... cn tn+1 ... tk + * + * (that is, they share the first n tags, n might be 0), and + * produces code closing fm ... fn+1 and opening tn+1 ... tk. + */ + +template<typename OutputIterator> +void change_context( + const html_context_data& from,const html_context_data& to, + OutputIterator out) +{ + std::ostringstream oss; + html_context_data::const_iterator + it0=from.begin(), + it0_end=from.end(), + it1=to.begin(), + it1_end=to.end(); + for(;it0!=it0_end&&it1!=it1_end&&*it0==*it1;++it0,++it1); + while(it0_end!=it0)print_closing_tag(oss,*--it0_end); + while(it1!=it1_end)print_opening_tag(oss,*it1++); + std::string str=oss.str(); + std::copy(str.begin(),str.end(),out); +} + +/* produce_html is passed a bunch of contextualized characters and emits + * the corresponding HTML. The algorithm is simple: tags are opened and closed + * as a result of the context from one character to the following changing. + */ + +template<typename ForwardIterator,typename OutputIterator> +void produce_html(ForwardIterator first,ForwardIterator last,OutputIterator out) +{ + html_context context; + while(first!=last){ + if(first->get().context!=context){ + change_context(context,first->get().context,out); + context=first->get().context; + } + *out++=(first++)->get().code; + } + change_context(context,html_context(),out); /* close remaining context */ +} + +/* Without these explicit instantiations, MSVC++ 6.5/7.0 does not + * find some friend operators in certain contexts. + */ + +character dummy1; +html_tag dummy2; + +int main() +{ + std::cout<<"input html file: "; + std::string in; + std::getline(std::cin,in); + std::ifstream ifs(in.c_str()); + if(!ifs){ + std::cout<<"can't open "<<in<<std::endl; + std::exit(EXIT_FAILURE); + } + typedef std::istreambuf_iterator<char> istrbuf_iterator; + std::vector<char> html_source; + std::copy( + istrbuf_iterator(ifs),istrbuf_iterator(), + std::back_inserter(html_source)); + + /* parse the HTML */ + + std::vector<character> scanned_html; + scan_html( + html_source.begin(),html_source.end(),std::back_inserter(scanned_html)); + + /* Now that we have the text as a vector of contextualized characters, + * we can shuffle it around and manipulate in almost any way we please. + * For instance, the following reverses the central portion of the doc. + */ + + std::reverse( + scanned_html.begin()+scanned_html.size()/4, + scanned_html.begin()+3*(scanned_html.size()/4)); + + /* emit the resulting HTML */ + + std::cout<<"output html file: "; + std::string out; + std::getline(std::cin,out); + std::ofstream ofs(out.c_str()); + if(!ofs){ + std::cout<<"can't open "<<out<<std::endl; + std::exit(EXIT_FAILURE); + } + typedef std::ostreambuf_iterator<char> ostrbuf_iterator; + produce_html(scanned_html.begin(),scanned_html.end(),ostrbuf_iterator(ofs)); + + return 0; +} diff --git a/src/boost/libs/flyweight/example/key_value.cpp b/src/boost/libs/flyweight/example/key_value.cpp new file mode 100644 index 00000000..5a93d07f --- /dev/null +++ b/src/boost/libs/flyweight/example/key_value.cpp @@ -0,0 +1,99 @@ +/* Boost.Flyweight example of use of key-value flyweights. + * + * Copyright 2006-2008 Joaquin M Lopez Munoz. + * Distributed under 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) + * + * See http://www.boost.org/libs/flyweight for library home page. + */ + +#include <boost/array.hpp> +#include <boost/flyweight.hpp> +#include <boost/flyweight/key_value.hpp> +#include <cstdlib> +#include <iostream> +#include <string> +#include <vector> + +using namespace boost::flyweights; + +/* A class simulating a texture resource loaded from file */ + +class texture +{ +public: + texture(const std::string& filename):filename(filename) + { + std::cout<<"loaded "<<filename<<" file"<<std::endl; + } + + texture(const texture& x):filename(x.filename) + { + std::cout<<"texture["<<filename<<"] copied"<<std::endl; + } + + ~texture() + { + std::cout<<"unloaded "<<filename<<std::endl; + } + + const std::string& get_filename()const{return filename;} + + // rest of the interface + +private: + std::string filename; +}; + +/* key extractor of filename strings from textures */ + +struct texture_filename_extractor +{ + const std::string& operator()(const texture& x)const + { + return x.get_filename(); + } +}; + +/* texture flyweight */ + +typedef flyweight< + key_value<std::string,texture,texture_filename_extractor> +> texture_flyweight; + +int main() +{ + /* texture filenames */ + + const char* texture_filenames[]={ + "grass.texture","sand.texture","water.texture","wood.texture", + "granite.texture","cotton.texture","concrete.texture","carpet.texture" + }; + const int num_texture_filenames= + sizeof(texture_filenames)/sizeof(texture_filenames[0]); + + /* create a massive vector of textures */ + + std::cout<<"creating flyweights...\n"<<std::endl; + + std::vector<texture_flyweight> textures; + for(int i=0;i<50000;++i){ + textures.push_back( + texture_flyweight(texture_filenames[std::rand()%num_texture_filenames])); + } + + /* Just for the sake of making use of the key extractor, + * assign some flyweights with texture objects rather than strings. + */ + + for(int j=0;j<50000;++j){ + textures.push_back( + texture_flyweight( + textures[std::rand()%textures.size()].get())); + } + + std::cout<<"\n"<<textures.size()<<" flyweights created\n"<<std::endl; + + return 0; +} diff --git a/src/boost/libs/flyweight/example/perf.cpp b/src/boost/libs/flyweight/example/perf.cpp new file mode 100644 index 00000000..3e608c0d --- /dev/null +++ b/src/boost/libs/flyweight/example/perf.cpp @@ -0,0 +1,312 @@ +/* Boost.Flyweight example of performance comparison. + * + * Copyright 2006-2008 Joaquin M Lopez Munoz. + * Distributed under 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) + * + * See http://www.boost.org/libs/flyweight for library home page. + */ + +#include <boost/flyweight/flyweight.hpp> +#include <boost/flyweight/hashed_factory.hpp> +#include <boost/flyweight/set_factory.hpp> +#include <boost/flyweight/static_holder.hpp> +#include <boost/flyweight/simple_locking.hpp> +#include <boost/flyweight/refcounted.hpp> +#include <boost/flyweight/no_tracking.hpp> +#include <boost/mpl/bool.hpp> +#include <boost/tokenizer.hpp> +#include <algorithm> +#include <cstddef> +#include <cstdlib> +#include <ctime> +#include <fstream> +#include <iostream> +#include <numeric> +#include <sstream> +#include <string> +#include <vector> + +#if defined(BOOST_NO_STDC_NAMESPACE) +namespace std{ +using ::clock; +using ::clock_t; +using ::exit; +} +#endif + +using namespace boost::flyweights; + +/* Instrumented allocator family keeping track of the memory in + * current use. + */ + +std::size_t count_allocator_mem=0; + +template<typename T> +class count_allocator +{ +public: + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + template<class U>struct rebind{typedef count_allocator<U> other;}; + + count_allocator(){} + count_allocator(const count_allocator<T>&){} + template<class U>count_allocator(const count_allocator<U>&,int=0){} + + pointer address(reference x)const{return &x;} + const_pointer address(const_reference x)const{return &x;} + + pointer allocate(size_type n,const void* =0) + { + pointer p=(T*)(new char[n*sizeof(T)]); + count_allocator_mem+=n*sizeof(T); + return p; + } + + void deallocate(void* p,size_type n) + { + count_allocator_mem-=n*sizeof(T); + delete [](char *)p; + } + + size_type max_size() const{return (size_type )(-1);} + void construct(pointer p,const T& val){new(p)T(val);} + void destroy(pointer p){p->~T();} + + friend bool operator==(const count_allocator&,const count_allocator&) + { + return true; + } + + friend bool operator!=(const count_allocator&,const count_allocator&) + { + return false; + } +}; + +template<> +class count_allocator<void> +{ +public: + typedef void* pointer; + typedef const void* const_pointer; + typedef void value_type; + template<class U>struct rebind{typedef count_allocator<U> other;}; +}; + +/* Define some count_allocator-based types and Boost.Flyweight components */ + +typedef std::basic_string< + char,std::char_traits<char>,count_allocator<char> +> count_string; + +typedef hashed_factory< + boost::hash<boost::mpl::_2>, + std::equal_to<boost::mpl::_2>, + count_allocator<boost::mpl::_1> +> count_hashed_factory; + +typedef set_factory< + std::less<boost::mpl::_2>, + count_allocator<boost::mpl::_1> +> count_set_factory; + +/* Some additional utilities used by the test routine */ + +class timer +{ +public: + timer(){restart();} + + void restart(){t=std::clock();} + + void time(const char* str) + { + std::cout<<str<<": "<<(double)(std::clock()-t)/CLOCKS_PER_SEC<<" s\n"; + } + +private: + std::clock_t t; +}; + +template<typename T> +struct is_flyweight: + boost::mpl::false_{}; + +template< + typename T, + typename Arg1,typename Arg2,typename Arg3,typename Arg4,typename Arg5 +> +struct is_flyweight<flyweight<T,Arg1,Arg2,Arg3,Arg4,Arg5> >: + boost::mpl::true_{}; + +struct length_adder +{ + std::size_t operator()(std::size_t n,const count_string& x)const + { + return n+x.size(); + } +}; + +/* Measure time and memory performance for a String, which is assumed + * to be either a plain string type or a string flyweight. + */ + +template<typename String> +struct test +{ + static std::size_t run(const std::string& file) + { + typedef std::vector<String,count_allocator<String> > count_vector; + + /* Define a tokenizer on std::istreambuf. */ + + typedef std::istreambuf_iterator<char> char_iterator; + typedef boost::tokenizer< + boost::char_separator<char>, + char_iterator + > tokenizer; + + std::ifstream ifs(file.c_str()); + if(!ifs){ + std::cout<<"can't open "<<file<<std::endl; + std::exit(EXIT_FAILURE); + } + + /* Initialization; tokenize using space and common punctuaction as + * separators, and keeping the separators. + */ + + timer t; + + tokenizer tok=tokenizer( + char_iterator(ifs),char_iterator(), + boost::char_separator<char>( + "", + "\t\n\r !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~")); + count_vector txt; + for(tokenizer::iterator it=tok.begin();it!=tok.end();++it){ + txt.push_back(String(it->c_str())); + } + + t.time("initialization time"); + + /* Assignment */ + + t.restart(); + + count_vector txt2; + for(int i=0;i<10;++i){ + txt2.insert(txt2.end(),txt.begin(),txt.end()); + } + + t.time("assignment time"); + + /* Equality comparison */ + + t.restart(); + + std::size_t c=0; + for(int i=0;i<100;++i){ + c+=std::count(txt.begin(),txt.end(),txt[c%txt.size()]); + } + + t.time("equality comparison time"); + + /* Value access */ + + t.restart(); + + std::size_t s=0; + for(int i=0;i<20;++i){ + s+=std::accumulate(txt2.begin(),txt2.end(),s,length_adder()); + } + + t.time("value access time"); + + std::cout<<"bytes used: "<<count_allocator_mem; + if(is_flyweight<String>::value){ + std::size_t flyweight_mem=(txt.capacity()+txt2.capacity())*sizeof(String); + std::cout<<"= flyweights("<<flyweight_mem + <<")+values("<<count_allocator_mem-flyweight_mem<<")"; + } + std::cout<<"\n"; + + return c+s; + } +}; + +/* table of test cases for the user to select from */ + +struct test_case +{ + const char* name; + std::size_t (*test)(const std::string&); +}; + +test_case test_table[]= +{ + { + "simple string", + test<count_string>::run + }, + { + "flyweight, hashed factory", + test<flyweight<count_string,count_hashed_factory> >::run + }, + { + "flyweight, hashed factory, no tracking", + test<flyweight<count_string,count_hashed_factory,no_tracking> >::run + }, + { + "flyweight, set-based factory", + test<flyweight<count_string,count_set_factory> >::run + }, + { + "flyweight, set-based factory, no tracking", + test<flyweight<count_string,count_set_factory,no_tracking> >::run + } +}; + +const int num_test_cases=sizeof(test_table)/sizeof(test_case); + +int main() +{ + try{ + for(int i=0;i<num_test_cases;++i){ + std::cout<<i+1<<". "<<test_table[i].name<<"\n"; + } + int option=-1; + for(;;){ + std::cout<<"select option, enter to exit: "; + std::string str; + std::getline(std::cin,str); + if(str.empty())std::exit(EXIT_SUCCESS); + std::istringstream istr(str); + istr>>option; + if(option>=1&&option<=num_test_cases){ + --option; /* pass from 1-based menu to 0-based test_table */ + break; + } + } + + std::cout<<"enter file name: "; + std::string file; + std::getline(std::cin,file); + std::size_t result=0; + result=test_table[option].test(file); + } + catch(const std::exception& e){ + std::cout<<"error: "<<e.what()<<"\n"; + } + + return 0; +} diff --git a/src/boost/libs/flyweight/example/serialization.cpp b/src/boost/libs/flyweight/example/serialization.cpp new file mode 100644 index 00000000..80227a53 --- /dev/null +++ b/src/boost/libs/flyweight/example/serialization.cpp @@ -0,0 +1,133 @@ +/* Boost.Flyweight example of serialization. + * + * Copyright 2006-2014 Joaquin M Lopez Munoz. + * Distributed under 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) + * + * See http://www.boost.org/libs/flyweight for library home page. + */ + +#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ +#include <algorithm> +#include <boost/archive/text_iarchive.hpp> +#include <boost/archive/text_oarchive.hpp> +#include <boost/flyweight.hpp> +#include <boost/flyweight/serialize.hpp> +#include <boost/serialization/vector.hpp> +#include <boost/tokenizer.hpp> +#include <cstdio> +#include <cstdlib> +#include <fstream> +#include <iostream> +#include <iterator> +#include <sstream> +#include <stdexcept> +#include <string> +#include <vector> + +using namespace boost::flyweights; + +typedef flyweight<std::string> fw_string; +typedef std::vector<fw_string> text_container; + +/* Read a text file into a text_container and serialize to an archive. */ + +void save_serialization_file() +{ + /* Define a tokenizer on std::istreambuf. */ + + typedef std::istreambuf_iterator<char> char_iterator; + typedef boost::tokenizer< + boost::char_separator<char>, + char_iterator + > tokenizer; + + std::cout<<"enter input text file name: "; + std::string in; + std::getline(std::cin,in); + std::ifstream ifs(in.c_str()); + if(!ifs){ + std::cout<<"can't open "<<in<<std::endl; + std::exit(EXIT_FAILURE); + } + + /* Tokenize using space and common punctuaction as separators, and + * keeping the separators. + */ + + tokenizer tok=tokenizer( + char_iterator(ifs),char_iterator(), + boost::char_separator<char>( + "", + "\t\n\r !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~")); + text_container txt; + for(tokenizer::iterator it=tok.begin();it!=tok.end();++it){ + txt.push_back(fw_string(*it)); + } + + std::cout<<"enter output serialization file name: "; + std::string out; + std::getline(std::cin,out); + std::ofstream ofs(out.c_str()); + if(!ofs){ + std::cout<<"can't open "<<out<<std::endl; + std::exit(EXIT_FAILURE); + } + boost::archive::text_oarchive oa(ofs); + oa<<const_cast<const text_container&>(txt); +} + +/* Read a serialization archive and save the result to a text file. */ + +void load_serialization_file() +{ + std::cout<<"enter input serialization file name: "; + std::string in; + std::getline(std::cin,in); + std::ifstream ifs(in.c_str()); + if(!ifs){ + std::cout<<"can't open "<<in<<std::endl; + std::exit(EXIT_FAILURE); + } + boost::archive::text_iarchive ia(ifs); + text_container txt; + ia>>txt; + + std::cout<<"enter output text file name: "; + std::string out; + std::getline(std::cin,out); + std::ofstream ofs(out.c_str()); + if(!ofs){ + std::cout<<"can't open "<<out<<std::endl; + std::exit(EXIT_FAILURE); + } + std::copy( + txt.begin(),txt.end(), + std::ostream_iterator<std::string>(ofs)); +} + +int main() +{ + try{ + std::cout<<"1 load a text file and save it as a serialization file\n" + "2 load a serialization file and save it as a text file\n"; + for(;;){ + std::cout<<"select option, enter to exit: "; + std::string str; + std::getline(std::cin,str); + if(str.empty())break; + std::istringstream istr(str); + int option=-1; + istr>>option; + if(option==1)save_serialization_file(); + else if(option==2)load_serialization_file(); + } + } + catch(const std::exception& e){ + std::cout<<"error: "<<e.what()<<std::endl; + std::exit(EXIT_FAILURE); + } + + return 0; +} |