Adobe Source Libraries 1.49.0
A collection of C++ libraries.
Loading...
Searching...
No Matches
xstring.hpp
Go to the documentation of this file.
1/*
2 Copyright 2013 Adobe
3 Distributed under the Boost Software License, Version 1.0.
4 (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5*/
6/**************************************************************************************************/
7
8#ifndef ADOBE_XSTRING_HPP
9#define ADOBE_XSTRING_HPP
10
11/**************************************************************************************************/
12
13#include <adobe/config.hpp>
14
15#include <adobe/functional.hpp>
16#include <adobe/implementation/string_pool.hpp>
17#include <adobe/istream.hpp>
18#include <adobe/name.hpp>
19#include <adobe/string.hpp>
20#include <adobe/unicode.hpp>
21#include <adobe/xml_parser.hpp>
22
23#include <boost/noncopyable.hpp>
24
25#include <cassert>
26#include <cctype>
27#include <functional>
28#include <map>
29#include <sstream>
30#include <vector>
31
32/**************************************************************************************************/
33
34namespace adobe {
35
36/**************************************************************************************************/
37
38namespace implementation {
39
40/**************************************************************************************************/
41
42inline bool xstring_preorder_predicate(const token_range_t& range) {
43 // we want to check for both xstr and marker tags because both are
44 // handled by the xstring system
45
46 return token_range_equal(range, static_token_range("xstr")) ||
47 token_range_equal(range, static_token_range("marker"));
48}
49
50/**************************************************************************************************/
51
52struct null_output_t {
53 typedef std::output_iterator_tag iterator_category;
54 typedef null_output_t value_type;
55 typedef std::ptrdiff_t difference_type;
56 typedef value_type* pointer;
57 typedef value_type& reference;
58
59 null_output_t& operator++(int) { return *this; }
60 null_output_t& operator++() { return *this; }
61 reference operator*() { return *this; }
62
63 template <typename T>
64 null_output_t& operator=(const T&) {
65 return *this;
66 }
67};
68
69/**************************************************************************************************/
70
71token_range_t xml_xstr_store(const token_range_t& entire_element_range, const token_range_t& name,
72 const attribute_set_t& attribute_set, const token_range_t& value);
73
74token_range_t xml_xstr_lookup(const token_range_t& entire_element_range, const token_range_t& name,
75 const attribute_set_t& attribute_set, const token_range_t& value);
76
77token_range_t xml_element_finalize(const token_range_t& entire_element_range,
78 const token_range_t& name, const attribute_set_t& attribute_set,
79 const token_range_t& value);
80
81/**************************************************************************************************/
82
83struct context_frame_t {
84 struct comp_t {
85 bool operator()(const token_range_t& x, const token_range_t& y) const {
86 return token_range_less(x, y);
87 }
88 };
89
90 typedef std::pair<attribute_set_t, token_range_t> element_t;
91 typedef std::multimap<token_range_t, element_t, comp_t> store_t;
92 typedef store_t::iterator store_iterator;
93 typedef store_t::value_type store_value_type;
94 typedef std::pair<store_iterator, store_iterator> store_range_pair_t;
95
96 typedef xml_parser_t<char*>::callback_proc_t callback_proc_t;
97 typedef xml_parser_t<char*>::preorder_predicate_t preorder_predicate_t;
98
99 context_frame_t() : parse_info_m("xstring context_frame_t"), parsed_m(false) {}
100
101 context_frame_t(const context_frame_t& rhs)
102 : parse_info_m(rhs.parse_info_m), parsed_m(rhs.parsed_m),
103 attribute_set_m(rhs.attribute_set_m), glossary_m(rhs.glossary_m),
104 callback_m(rhs.callback_m), predicate_m(rhs.predicate_m)
105 // slurp_m(rhs.slurp_m), // not to be transferred from context to context
106 // pool_m(rhs.pool_m), // not to be transferred from context to context
107 {}
108
109 context_frame_t& operator=(const context_frame_t& rhs) {
110 parse_info_m = rhs.parse_info_m;
111 parsed_m = rhs.parsed_m;
112 attribute_set_m = rhs.attribute_set_m;
113 glossary_m = rhs.glossary_m;
114 callback_m = rhs.callback_m;
115 predicate_m = rhs.predicate_m;
116 // slurp_m = rhs.slurp_m; // not to be transferred from context to context
117 // pool_m = rhs.pool_m; // not to be transferred from context to context
118
119 return *this;
120 }
121
122 ~context_frame_t() {
123 if (slurp_m.first)
124 delete[] slurp_m.first;
125 }
126
127 inline store_range_pair_t range_for_key(const store_t::key_type& key) {
128 return glossary_m.equal_range(key);
129 }
130
131 std::pair<bool, store_iterator> exact_match_exists(const attribute_set_t& attribute_set,
132 const token_range_t& value);
133
134 store_t::mapped_type* store(const store_t::key_type& key, const attribute_set_t& attribute_set,
135 const token_range_t& value, bool copy = false);
136
137 store_iterator closest_match(store_range_pair_t range, const attribute_set_t& searching);
138
139 token_range_t element_handler(const token_range_t& entire_element_range,
140 const token_range_t& name, const attribute_set_t& attribute_set,
141 const token_range_t& value) const {
142 if (xstring_preorder_predicate(name))
143 // Note that this implicitly handles "marker" elements (by echoing them)
144 return xml_xstr_lookup(entire_element_range, name, attribute_set, value);
145 else if (predicate_m && predicate_m(name))
146 return callback_m(entire_element_range, name, attribute_set, value);
147 else
148 return xml_element_strip(entire_element_range, name, attribute_set, value);
149 }
150
151 token_range_t clone(const token_range_t& token);
152
153 line_position_t parse_info_m;
154 bool parsed_m;
155 attribute_set_t attribute_set_m;
156 store_t glossary_m;
157 callback_proc_t callback_m;
158 preorder_predicate_t predicate_m;
159 token_range_t slurp_m;
160 unique_string_pool_t pool_m;
161};
162
163/**************************************************************************************************/
164
165inline bool operator==(const context_frame_t::element_t& x, const context_frame_t::element_t& y) {
166 return x.first == y.first && token_range_equal(x.second, y.second);
167}
168
169/**************************************************************************************************/
170
171implementation::context_frame_t& top_frame();
172
173/**************************************************************************************************/
174
175} // namespace implementation
176
177/**************************************************************************************************/
178#ifndef NDEBUG
179
181
182#endif
183/**************************************************************************************************/
184
185// XML fragment parsing
186
187template <typename O> // O models OutputIterator
188inline void parse_xml_fragment(uchar_ptr_t fragment, std::size_t n, O output) {
189 using namespace std::placeholders;
190
191 const implementation::context_frame_t& context(implementation::top_frame());
192
193 make_xml_parser(fragment, fragment + n, line_position_t("parse_xml_fragment"),
195 std::bind(&implementation::context_frame_t::element_handler,
196 std::cref(context), _1, _2, _3, _4),
197 output)
198 .parse_content(); // REVISIT (fbrereto) : More or less legible than
199 // having it after the above declaration?
200}
201
202template <typename O> // O models OutputIterator
203inline void parse_xml_fragment(const std::string& fragment, O output) {
204 return parse_xml_fragment(reinterpret_cast<uchar_ptr_t>(fragment.c_str()), fragment.size(),
205 output);
206}
207
208template <typename O> // O models OutputIterator
209inline void parse_xml_fragment(const char* fragment, O output) {
210 return parse_xml_fragment(reinterpret_cast<uchar_ptr_t>(fragment), std::strlen(fragment),
211 output);
212}
213
214/**************************************************************************************************/
215
216// xstring lookup with OutputIterator; all of these functions return a valid XML fragment
217
218template <typename O> // O models OutputIterator; required: sizeof(value_type(O)) >= 21 bits
219inline void xstring(const char* xstr, std::size_t n, O output) {
220 parse_xml_fragment(reinterpret_cast<uchar_ptr_t>(xstr), n, output);
221}
222
223template <typename O> // O models OutputIterator; required: sizeof(value_type(O)) >= 21 bits
224inline void xstring(const char* xstr, O output) {
225 xstring(xstr, std::strlen(xstr), output);
226}
227
228/**************************************************************************************************/
229
230// xstring lookup; all of these functions return a valid XML fragment
231
232inline std::string xstring(const char* xstr, std::size_t n) {
233 std::string result;
234
235 xstring(xstr, n, std::back_inserter(result));
236
237 return result;
238}
239
240inline std::string xstring(const std::string& xstr) { return xstring(xstr.c_str(), xstr.size()); }
241
242/**************************************************************************************************/
243
244// Context-sensitive marker replacement
245
246std::string xstring_replace(const std::string& xstr, const std::string& marker);
247
248std::string xstring_replace(const std::string& xstr, const std::string* first,
249 const std::string* last);
250
251std::string xstring_replace(const name_t& xstr_id, const std::string& marker);
252
253std::string xstring_replace(const name_t& xstr_id, const std::string* first,
254 const std::string* last);
255
256/**************************************************************************************************/
257
258struct xstring_context_t : boost::noncopyable {
259 typedef implementation::context_frame_t::callback_proc_t callback_proc_t;
260 typedef implementation::context_frame_t::preorder_predicate_t preorder_predicate_t;
261
262 xstring_context_t(const char* parse_first, const char* parse_last,
263 const line_position_t& parse_info = line_position_t("xstring_context_t"))
264 : back_frame_m(implementation::top_frame()) // save snapshot of stack
265 {
266 implementation::context_frame_t& context(implementation::top_frame());
267
268 context.slurp_m.first = reinterpret_cast<uchar_ptr_t>(parse_first);
269 context.slurp_m.second = reinterpret_cast<uchar_ptr_t>(parse_last);
270 context.parse_info_m = parse_info;
271 context.parsed_m = false;
272
273 glossary_parse();
274 }
275
276 template <typename I> // I models InputIterator
277 xstring_context_t(I first_attribute, I last_attribute)
278 : back_frame_m(implementation::top_frame()) // save snapshot of stack
279 {
280 implementation::top_frame().attribute_set_m.insert(first_attribute, last_attribute);
281 }
282
283 template <typename I> // I models InputIterator
284 xstring_context_t(I first_attribute, I last_attribute, const unsigned char* parse_first,
285 const unsigned char* parse_last,
286 const line_position_t& parse_info = line_position_t("xstring_context_t"))
287 : back_frame_m(implementation::top_frame()) // save snapshot of stack
288 {
289 implementation::context_frame_t& context(implementation::top_frame());
290
291 context.attribute_set_m.insert(first_attribute, last_attribute);
292 context.slurp_m.first = parse_first;
293 context.slurp_m.second = parse_last;
294 context.parse_info_m = parse_info;
295 context.parsed_m = false;
296
297 glossary_parse();
298 }
299
301 implementation::top_frame().predicate_m = proc;
302 }
303
305 implementation::top_frame().callback_m = proc;
306 }
307
308 ~xstring_context_t() { implementation::top_frame() = back_frame_m; } // restore stack as it was
309
310private:
311 void glossary_parse() {
312 implementation::context_frame_t& context(implementation::top_frame());
313
314 if (context.parsed_m || !adobe::token_range_size(context.slurp_m)) {
315 return;
316 }
317
318 make_xml_parser(context.slurp_m.first, context.slurp_m.second, context.parse_info_m,
319 implementation::xstring_preorder_predicate, &implementation::xml_xstr_store,
320 implementation::null_output_t())
321 .parse_element_sequence(); // REVISIT (fbrereto) : More or less legible than having it
322 // after the above declaration?
323
324 context.parsed_m = true;
325 }
326
327 implementation::context_frame_t back_frame_m;
328};
329
330/**************************************************************************************************/
331
332} // namespace adobe
333
334/**************************************************************************************************/
335#ifdef __ADOBE_COMPILER_CONCEPTS__
336namespace std {
337// It would be nice to be able to instantiate this for all T. Not sure why it doesn't work.
338concept_map OutputIterator<adobe::implementation::null_output_t, char>{};
339concept_map OutputIterator<adobe::implementation::null_output_t, unsigned char>{};
340} // namespace std
341#endif
342
343/**************************************************************************************************/
344
345#endif
346
347/**************************************************************************************************/
std::function< bool(const token_range_t &)> preorder_predicate_t
xml_element_proc_t callback_proc_t
xml_parser_t< O > make_xml_parser(uchar_ptr_t first, uchar_ptr_t last, const line_position_t &position, typename xml_parser_t< O >::preorder_predicate_t predicate, typename xml_parser_t< O >::callback_proc_t callback, O output)
Create an object that will parse the indicated content range using the preorder and content functions...
std::string xstring_replace(const std::string &xstr, const std::string &marker)
void xstring(const char *xstr, std::size_t n, O output)
Definition xstring.hpp:219
void xstring_clear_glossary()
void parse_xml_fragment(uchar_ptr_t fragment, std::size_t n, O output)
Definition xstring.hpp:188
OutputIterator copy(const InputRange &range, OutputIterator result)
copy implementation
Definition copy.hpp:42
token_range_t xml_element_strip(const token_range_t &, const token_range_t &, const attribute_set_t &, const token_range_t &value)
STL namespace.
A type detailing parser position information.
Definition istream.hpp:127
A character string class for immutable strings.
Definition name.hpp:220
implementation::context_frame_t::preorder_predicate_t preorder_predicate_t
Definition xstring.hpp:260
xstring_context_t(I first_attribute, I last_attribute, const unsigned char *parse_first, const unsigned char *parse_last, const line_position_t &parse_info=line_position_t("xstring_context_t"))
Definition xstring.hpp:284
implementation::context_frame_t::callback_proc_t callback_proc_t
Definition xstring.hpp:259
xstring_context_t(I first_attribute, I last_attribute)
Definition xstring.hpp:277
void set_element_handler(callback_proc_t proc)
Definition xstring.hpp:304
void set_preorder_predicate(preorder_predicate_t proc)
Definition xstring.hpp:300
xstring_context_t(const char *parse_first, const char *parse_last, const line_position_t &parse_info=line_position_t("xstring_context_t"))
Definition xstring.hpp:262