1 /*=============================================================================
2 Copyright (c) 2001-2011 Joel de Guzman
4 Distributed under the Boost Software License, Version 1.0. (See accompanying
5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 =============================================================================*/
7 #include <boost/config/warning_disable.hpp>
8 #include <boost/spirit/include/qi.hpp>
9 #include <boost/spirit/include/phoenix.hpp>
10 #include <boost/unordered_map.hpp>
11 #include <boost/algorithm/string/trim.hpp>
12 #include <boost/cstdint.hpp>
13 #include <boost/foreach.hpp>
14 #include <boost/array.hpp>
15 #include <boost/scoped_array.hpp>
16 #include <boost/range/iterator_range.hpp>
25 // We place the data here. Each line comprises various fields
26 typedef std::vector<std::string> ucd_line;
27 typedef std::vector<ucd_line> ucd_vector;
28 typedef std::vector<ucd_line>::iterator ucd_iterator;
30 // spirit and phoenix using declarations
31 using boost::spirit::qi::parse;
32 using boost::spirit::qi::hex;
33 using boost::spirit::qi::char_;
34 using boost::spirit::qi::eol;
35 using boost::spirit::qi::rule;
36 using boost::spirit::qi::omit;
37 using boost::spirit::qi::_1;
38 using boost::spirit::qi::_val;
39 using boost::phoenix::push_back;
40 using boost::phoenix::ref;
42 // basic unsigned types
44 using boost::uint16_t;
45 using boost::uint32_t;
50 ucd_range(uint32_t start, uint32_t finish)
51 : start(start), finish(finish) {}
53 // we need this so we can use ucd_range as a multimap key
54 friend bool operator<(ucd_range const& a, ucd_range const& b)
56 return a.start < b.start;
67 ucd_info(char const* filename)
69 std::ifstream in(filename, std::ios_base::in);
72 std::cerr << "Error: Could not open input file: "
73 << filename << std::endl;
77 std::string data; // We will read the contents here.
78 in.unsetf(std::ios::skipws); // No white space skipping!
80 std::istream_iterator<char>(in),
81 std::istream_iterator<char>(),
82 std::back_inserter(data));
84 typedef std::string::const_iterator iterator_type;
85 iterator_type f = data.begin();
86 iterator_type l = data.end();
88 rule<iterator_type> endl = -('#' >> *(char_-eol)) >> eol;
89 rule<iterator_type, std::string()> field = *(char_-(';'|endl)) >> (';'|&endl);
90 rule<iterator_type, ucd_line()> line = +(field-endl) >> endl;
91 rule<iterator_type, std::vector<ucd_line>()> file = +(endl | line[push_back(_val, _1)]);
93 parse(f, l, file, info);
97 template <typename Array>
98 void collect(Array& data, int field, bool collect_properties = true) const
100 BOOST_ASSERT(!info.empty());
101 ucd_vector::const_iterator current = info.begin();
102 ucd_vector::const_iterator end = info.end();
104 while (current != end)
106 std::string range = (*current)[0];
109 std::string::const_iterator f = range.begin();
110 std::string::const_iterator l = range.end();
112 // get the code-point range
115 parse(f, l, hex[ref(start) = ref(finish) = _1] >> -(".." >> hex[ref(finish) = _1]));
117 // special case for UnicodeData.txt ranges:
118 if ((*current)[1].find("First>") != std::string::npos)
121 BOOST_ASSERT(current != end);
122 BOOST_ASSERT((*current)[1].find("Last>") != std::string::npos);
124 std::string range = (*current)[0];
129 parse(f, l, hex[ref(finish) = _1]);
133 if (field < int(current->size()))
134 code = (*current)[field];
136 // Only collect properties we are interested in
137 if (collect_properties) // code for properties
139 if (!ignore_property(code))
141 for (uint32_t i = start; i <= finish; ++i)
142 data[i] |= map_property(code);
145 else // code for actual numeric values
147 for (uint32_t i = start; i <= finish; ++i)
151 data[i] = 0; // signal that this code maps to itself
157 parse(f, l, hex, data[i]);
167 static bool ignore_property(std::string const& p)
169 // We don't handle all properties
170 std::map<std::string, int>& pm = get_property_map();
171 std::map<std::string, int>::iterator i = pm.find(p);
172 return i == pm.end();
176 map_property(std::string const& p)
178 std::map<std::string, int>& pm = get_property_map();
179 std::map<std::string, int>::iterator i = pm.find(p);
180 BOOST_ASSERT(i != pm.end());
184 static std::map<std::string, int>&
187 // The properties we are interested in:
188 static std::map<std::string, int> map;
229 // Derived Properties.
230 map["Alphabetic"] = 64;
231 map["Uppercase"] = 128;
232 map["Lowercase"] = 256;
233 map["White_Space"] = 512;
234 map["Hex_Digit"] = 1024;
235 map["Noncharacter_Code_Point"] = 2048;
236 map["Default_Ignorable_Code_Point"] = 4096;
240 map["Imperial_Aramaic"] = 1;
250 map["Canadian_Aboriginal"] = 11;
253 map["Cherokee"] = 14;
256 map["Cyrillic"] = 17;
257 map["Devanagari"] = 18;
259 map["Egyptian_Hieroglyphs"] = 20;
260 map["Ethiopic"] = 21;
261 map["Georgian"] = 22;
262 map["Glagolitic"] = 23;
265 map["Gujarati"] = 26;
266 map["Gurmukhi"] = 27;
271 map["Hiragana"] = 32;
272 map["Katakana_Or_Hiragana"] = 33;
273 map["Old_Italic"] = 34;
274 map["Javanese"] = 35;
275 map["Kayah_Li"] = 36;
276 map["Katakana"] = 37;
277 map["Kharoshthi"] = 38;
281 map["Tai_Tham"] = 42;
286 map["Linear_B"] = 47;
290 map["Malayalam"] = 51;
291 map["Mongolian"] = 52;
292 map["Meetei_Mayek"] = 53;
296 map["Ol_Chiki"] = 57;
297 map["Old_Turkic"] = 58;
300 map["Phags_Pa"] = 61;
301 map["Inscriptional_Pahlavi"] = 62;
302 map["Phoenician"] = 63;
303 map["Inscriptional_Parthian"] = 64;
306 map["Samaritan"] = 67;
307 map["Old_South_Arabian"] = 68;
308 map["Saurashtra"] = 69;
311 map["Sundanese"] = 72;
312 map["Syloti_Nagri"] = 73;
314 map["Tagbanwa"] = 75;
316 map["New_Tai_Lue"] = 77;
318 map["Tai_Viet"] = 79;
320 map["Tifinagh"] = 81;
325 map["Ugaritic"] = 86;
327 map["Old_Persian"] = 88;
328 map["Cuneiform"] = 89;
330 map["Inherited"] = 91;
340 template <typename T, uint32_t block_size_ = 256>
341 class ucd_table_builder
345 static uint32_t const block_size = block_size_;
346 static uint32_t const full_span = 0x110000;
347 typedef T value_type;
349 ucd_table_builder() : p(new T[full_span])
351 for (uint32_t i = 0; i < full_span; ++i)
355 void collect(char const* filename, int field, bool collect_properties = true)
357 std::cout << "collecting " << filename << std::endl;
358 ucd_info info(filename);
359 info.collect(p, field, collect_properties);
362 void build(std::vector<uint8_t>& stage1, std::vector<T const*>& stage2)
364 std::cout << "building tables" << std::endl;
365 std::map<block_ptr, std::vector<T const*> > blocks;
366 for (T const* i = p.get(); i < (p.get() + full_span); i += block_size)
367 blocks[block_ptr(i)].push_back(i);
369 // Not enough bits to store the block indices.
370 BOOST_ASSERT(blocks.size() < (1 << (sizeof(uint8_t) * 8)));
372 typedef std::pair<block_ptr, std::vector<T const*> > blocks_value_type;
373 std::map<T const*, std::vector<T const*> > sorted_blocks;
374 BOOST_FOREACH(blocks_value_type const& val, blocks)
376 sorted_blocks[val.first.p] = val.second;
380 stage1.reserve(full_span / block_size);
381 stage1.resize(full_span / block_size);
383 stage2.reserve(blocks.size());
385 typedef std::pair<T const*, std::vector<T const*> > sorted_blocks_value_type;
386 BOOST_FOREACH(sorted_blocks_value_type const& val, sorted_blocks)
388 stage2.push_back(val.first);
389 BOOST_FOREACH(T const* val2, val.second)
391 stage1[(val2 - p.get()) / block_size] = stage2.size() - 1;
400 block_ptr(T const* p) : p(p) {}
402 friend bool operator<(block_ptr a, block_ptr b)
404 return std::lexicographical_compare(
405 a.p, a.p + block_size, b.p, b.p + block_size);
411 boost::scoped_array<T> p;
414 template <typename Out>
415 void print_tab(Out& out, int tab)
417 for (int i = 0; i < tab; ++i)
421 template <typename Out, typename C>
422 void print_table(Out& out, C const& c, bool trailing_comma, int width = 4, int group = 16)
425 C::size_type size = c.size();
426 BOOST_ASSERT(size > 1);
428 out << std::setw(width) << int(c[0]);
429 for (C::size_type i = 1; i < size; ++i)
432 if ((i % group) == 0)
437 out << std::setw(width) << int(c[i]);
441 out << ", " << std::endl;
444 template <typename Out>
445 void print_head(Out& out)
448 << "/*=============================================================================\n"
449 << " Copyright (c) 2001-2011 Joel de Guzman\n"
451 << " Distributed under the Boost Software License, Version 1.0. (See accompanying\n"
452 << " file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n"
454 << " AUTOGENERATED. DO NOT EDIT!!!\n"
455 << "==============================================================================*/\n"
456 << "#include <boost/cstdint.hpp>\n"
458 << "namespace boost { namespace spirit { namespace ucd { namespace detail\n"
463 template <typename Out>
464 void print_tail(Out& out)
468 << "}}}} // namespace boost::spirit::unicode::detail\n"
472 char const* get_int_type_name(int size)
476 case 1: return "::boost::uint8_t";
477 case 2: return "::boost::uint16_t";
478 case 4: return "::boost::uint32_t";
479 case 5: return "::boost::uint64_t";
480 default: BOOST_ASSERT(false); return 0; // invalid size
484 template <typename Out, typename Builder>
485 void print_file(Out& out, Builder& builder, int field_width, char const* name)
487 std::cout << "Generating " << name << " tables" << std::endl;
489 uint32_t const block_size = Builder::block_size;
490 typedef typename Builder::value_type value_type;
493 std::vector<uint8_t> stage1;
494 std::vector<value_type const*> stage2;
495 builder.build(stage1, stage2);
496 std::cout << "Block Size: " << block_size << std::endl;
497 std::cout << "Total Bytes: "
498 << stage1.size()+(stage2.size()*block_size*sizeof(value_type))
503 << " static const ::boost::uint8_t " << name << "_stage1[] = {\n"
507 print_table(out, stage1, false, 3);
508 char const* int_name = get_int_type_name(sizeof(value_type));
515 << " static const " << int_name << ' ' << name << "_stage2[] = {"
519 for (int i = 0; i < int(stage2.size()); ++i)
521 value_type const* p = stage2[i];
522 bool last = (i+1 == stage2.size());
523 out << "\n\n // block " << block_n++ << std::endl;
525 boost::iterator_range<value_type const*>(p, p+block_size), !last, field_width);
536 << " inline " << int_name << ' ' << name << "_lookup(::boost::uint32_t ch)\n"
538 << " ::boost::uint32_t block_offset = " << name << "_stage1[ch / " << block_size << "] * " << block_size << ";\n"
539 << " return " << name << "_stage2[block_offset + ch % " << block_size << "];\n"
548 // The category tables
550 std::ofstream out("category_table.hpp");
551 ucd_table_builder<uint16_t, 256> builder;
552 builder.collect("UnicodeData.txt", 2);
553 builder.collect("DerivedCoreProperties.txt", 1);
554 builder.collect("PropList.txt", 1);
555 print_file(out, builder, 4, "category");
560 std::ofstream out("script_table.hpp");
561 ucd_table_builder<uint8_t, 256> builder;
562 builder.collect("Scripts.txt", 1);
563 print_file(out, builder, 3, "script");
566 // The lowercase tables
568 std::ofstream out("lowercase_table.hpp");
569 ucd_table_builder<uint32_t, 256> builder;
570 builder.collect("UnicodeData.txt", 13, false);
571 print_file(out, builder, 6, "lowercase");
574 // The uppercase tables
576 std::ofstream out("uppercase_table.hpp");
577 ucd_table_builder<uint32_t, 256> builder;
578 builder.collect("UnicodeData.txt", 12, false);
579 print_file(out, builder, 6, "uppercase");