Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/boost/regex/pending/unicode_iterator.hpp @ 29

Last change on this file since 29 was 29, checked in by landauf, 17 years ago

updated boost from 1_33_1 to 1_34_1

File size: 20.4 KB
Line 
1/*
2 *
3 * Copyright (c) 2004
4 * John Maddock
5 *
6 * Use, modification and distribution are subject to the
7 * Boost Software License, Version 1.0. (See accompanying file
8 * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 *
10 */
11 
12 /*
13  *   LOCATION:    see http://www.boost.org for most recent version.
14  *   FILE         unicode_iterator.hpp
15  *   VERSION      see <boost/version.hpp>
16  *   DESCRIPTION: Iterator adapters for converting between different Unicode encodings.
17  */
18
19/****************************************************************************
20
21Contents:
22~~~~~~~~~
23
241) Read Only, Input Adapters:
25~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
26
27template <class BaseIterator, class U8Type = ::boost::uint8_t>
28class u32_to_u8_iterator;
29
30Adapts sequence of UTF-32 code points to "look like" a sequence of UTF-8.
31
32template <class BaseIterator, class U32Type = ::boost::uint32_t>
33class u8_to_u32_iterator;
34
35Adapts sequence of UTF-8 code points to "look like" a sequence of UTF-32.
36
37template <class BaseIterator, class U16Type = ::boost::uint16_t>
38class u32_to_u16_iterator;
39
40Adapts sequence of UTF-32 code points to "look like" a sequence of UTF-16.
41
42template <class BaseIterator, class U32Type = ::boost::uint32_t>
43class u16_to_u32_iterator;
44
45Adapts sequence of UTF-16 code points to "look like" a sequence of UTF-32.
46
472) Single pass output iterator adapters:
48
49template <class BaseIterator>
50class utf8_output_iterator;
51
52Accepts UTF-32 code points and forwards them on as UTF-8 code points.
53
54template <class BaseIterator>
55class utf16_output_iterator;
56
57Accepts UTF-32 code points and forwards them on as UTF-16 code points.
58
59****************************************************************************/
60
61#ifndef BOOST_REGEX_UNICODE_ITERATOR_HPP
62#define BOOST_REGEX_UNICODE_ITERATOR_HPP
63#include <boost/cstdint.hpp>
64#include <boost/assert.hpp>
65#include <boost/iterator/iterator_facade.hpp>
66#include <boost/static_assert.hpp>
67#include <boost/throw_exception.hpp>
68#include <stdexcept>
69#ifndef BOOST_NO_STD_LOCALE
70#include <sstream>
71#endif
72#include <limits.h> // CHAR_BIT
73
74namespace boost{
75
76namespace detail{
77
78static const ::boost::uint16_t high_surrogate_base = 0xD7C0u;
79static const ::boost::uint16_t low_surrogate_base = 0xDC00u;
80static const ::boost::uint32_t ten_bit_mask = 0x3FFu;
81
82inline bool is_high_surrogate(::boost::uint16_t v)
83{
84   return (v & 0xFC00u) == 0xd800u;
85}
86inline bool is_low_surrogate(::boost::uint16_t v)
87{
88   return (v & 0xFC00u) == 0xdc00u;
89}
90template <class T>
91inline bool is_surrogate(T v)
92{
93   return (v & 0xF800u) == 0xd800;
94}
95
96inline unsigned utf8_byte_count(boost::uint8_t c)
97{
98   // if the most significant bit with a zero in it is in position
99   // 8-N then there are N bytes in this UTF-8 sequence:
100   boost::uint8_t mask = 0x80u;
101   unsigned result = 0;
102   while(c & mask)
103   {
104      ++result;
105      mask >>= 1;
106   }
107   return (result == 0) ? 1 : ((result > 4) ? 4 : result);
108}
109
110inline unsigned utf8_trailing_byte_count(boost::uint8_t c)
111{
112   return utf8_byte_count(c) - 1;
113}
114
115inline void invalid_utf32_code_point(::boost::uint32_t val)
116{
117#ifndef BOOST_NO_STD_LOCALE
118   std::stringstream ss;
119   ss << "Invalid UTF-32 code point U+" << std::showbase << std::hex << val << " encountered while trying to encode UTF-16 sequence";
120   std::out_of_range e(ss.str());
121#else
122   std::out_of_range e("Invalid UTF-32 code point encountered while trying to encode UTF-16 sequence");
123#endif
124   boost::throw_exception(e);
125}
126
127
128} // namespace detail
129
130template <class BaseIterator, class U16Type = ::boost::uint16_t>
131class u32_to_u16_iterator
132   : public boost::iterator_facade<u32_to_u16_iterator<BaseIterator, U16Type>, U16Type, std::bidirectional_iterator_tag, const U16Type>
133{
134   typedef boost::iterator_facade<u32_to_u16_iterator<BaseIterator, U16Type>, U16Type, std::bidirectional_iterator_tag, const U16Type> base_type;
135
136#if !defined(BOOST_NO_STD_ITERATOR_TRAITS) && !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
137   typedef typename std::iterator_traits<BaseIterator>::value_type base_value_type;
138
139   BOOST_STATIC_ASSERT(sizeof(base_value_type)*CHAR_BIT == 32);
140   BOOST_STATIC_ASSERT(sizeof(U16Type)*CHAR_BIT == 16);
141#endif
142
143public:
144   typename base_type::reference
145      dereference()const
146   {
147      if(m_current == 2)
148         extract_current();
149      return m_values[m_current];
150   }
151   bool equal(const u32_to_u16_iterator& that)const
152   {
153      if(m_position == that.m_position)
154      {
155         // Both m_currents must be equal, or both even
156         // this is the same as saying their sum must be even:
157         return (m_current + that.m_current) & 1u ? false : true;
158      }
159      return false;
160   }
161   void increment()
162   {
163      // if we have a pending read then read now, so that we know whether
164      // to skip a position, or move to a low-surrogate:
165      if(m_current == 2)
166      {
167         // pending read:
168         extract_current();
169      }
170      // move to the next surrogate position:
171      ++m_current;
172      // if we've reached the end skip a position:
173      if(m_values[m_current] == 0)
174      {
175         m_current = 2;
176         ++m_position;
177      }
178   }
179   void decrement()
180   {
181      if(m_current != 1)
182      {
183         // decrementing an iterator always leads to a valid position:
184         --m_position;
185         extract_current();
186         m_current = m_values[1] ? 1 : 0;
187      }
188      else
189      {
190         m_current = 0;
191      }
192   }
193   BaseIterator base()const
194   {
195      return m_position;
196   }
197   // construct:
198   u32_to_u16_iterator() : m_position(), m_current(0)
199   {
200      m_values[0] = 0;
201      m_values[1] = 0;
202      m_values[2] = 0;
203   }
204   u32_to_u16_iterator(BaseIterator b) : m_position(b), m_current(2)
205   {
206      m_values[0] = 0;
207      m_values[1] = 0;
208      m_values[2] = 0;
209   }
210private:
211
212   void extract_current()const
213   {
214      // begin by checking for a code point out of range:
215      ::boost::uint32_t v = *m_position;
216      if(v >= 0x10000u)
217      {
218         if(v > 0x10FFFFu)
219            detail::invalid_utf32_code_point(*m_position);
220         // split into two surrogates:
221         m_values[0] = static_cast<U16Type>(v >> 10) + detail::high_surrogate_base;
222         m_values[1] = static_cast<U16Type>(v & detail::ten_bit_mask) + detail::low_surrogate_base;
223         m_current = 0;
224         BOOST_ASSERT(detail::is_high_surrogate(m_values[0]));
225         BOOST_ASSERT(detail::is_low_surrogate(m_values[1]));
226      }
227      else
228      {
229         // 16-bit code point:
230         m_values[0] = static_cast<U16Type>(*m_position);
231         m_values[1] = 0;
232         m_current = 0;
233         // value must not be a surrogate:
234         if(detail::is_surrogate(m_values[0]))
235            detail::invalid_utf32_code_point(*m_position);
236      }
237   }
238   BaseIterator m_position;
239   mutable U16Type m_values[3];
240   mutable unsigned m_current;
241};
242
243template <class BaseIterator, class U32Type = ::boost::uint32_t>
244class u16_to_u32_iterator
245   : public boost::iterator_facade<u16_to_u32_iterator<BaseIterator, U32Type>, U32Type, std::bidirectional_iterator_tag, const U32Type>
246{
247   typedef boost::iterator_facade<u16_to_u32_iterator<BaseIterator, U32Type>, U32Type, std::bidirectional_iterator_tag, const U32Type> base_type;
248   // special values for pending iterator reads:
249   BOOST_STATIC_CONSTANT(U32Type, pending_read = 0xffffffffu);
250
251#if !defined(BOOST_NO_STD_ITERATOR_TRAITS) && !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
252   typedef typename std::iterator_traits<BaseIterator>::value_type base_value_type;
253
254   BOOST_STATIC_ASSERT(sizeof(base_value_type)*CHAR_BIT == 16);
255   BOOST_STATIC_ASSERT(sizeof(U32Type)*CHAR_BIT == 32);
256#endif
257
258public:
259   typename base_type::reference
260      dereference()const
261   {
262      if(m_value == pending_read)
263         extract_current();
264      return m_value;
265   }
266   bool equal(const u16_to_u32_iterator& that)const
267   {
268      return m_position == that.m_position;
269   }
270   void increment()
271   {
272      // skip high surrogate first if there is one:
273      if(detail::is_high_surrogate(*m_position)) ++m_position;
274      ++m_position;
275      m_value = pending_read;
276   }
277   void decrement()
278   {
279      --m_position;
280      // if we have a low surrogate then go back one more:
281      if(detail::is_low_surrogate(*m_position)) 
282         --m_position;
283      m_value = pending_read;
284   }
285   BaseIterator base()const
286   {
287      return m_position;
288   }
289   // construct:
290   u16_to_u32_iterator() : m_position()
291   {
292      m_value = pending_read;
293   }
294   u16_to_u32_iterator(BaseIterator b) : m_position(b)
295   {
296      m_value = pending_read;
297   }
298private:
299   static void invalid_code_point(::boost::uint16_t val)
300   {
301#ifndef BOOST_NO_STD_LOCALE
302      std::stringstream ss;
303      ss << "Misplaced UTF-16 surrogate U+" << std::showbase << std::hex << val << " encountered while trying to encode UTF-32 sequence";
304      std::out_of_range e(ss.str());
305#else
306      std::out_of_range e("Misplaced UTF-16 surrogate encountered while trying to encode UTF-32 sequence");
307#endif
308      boost::throw_exception(e);
309   }
310   void extract_current()const
311   {
312      m_value = static_cast<U32Type>(static_cast< ::boost::uint16_t>(*m_position));
313      // if the last value is a high surrogate then adjust m_position and m_value as needed:
314      if(detail::is_high_surrogate(*m_position))
315      {
316         // precondition; next value must have be a low-surrogate:
317         BaseIterator next(m_position);
318         ::boost::uint16_t t = *++next;
319         if((t & 0xFC00u) != 0xDC00u)
320            invalid_code_point(t);
321         m_value = (m_value - detail::high_surrogate_base) << 10;
322         m_value |= (static_cast<U32Type>(static_cast< ::boost::uint16_t>(t)) & detail::ten_bit_mask);
323      }
324      // postcondition; result must not be a surrogate:
325      if(detail::is_surrogate(m_value))
326         invalid_code_point(static_cast< ::boost::uint16_t>(m_value));
327   }
328   BaseIterator m_position;
329   mutable U32Type m_value;
330};
331
332template <class BaseIterator, class U8Type = ::boost::uint8_t>
333class u32_to_u8_iterator
334   : public boost::iterator_facade<u32_to_u8_iterator<BaseIterator, U8Type>, U8Type, std::bidirectional_iterator_tag, const U8Type>
335{
336   typedef boost::iterator_facade<u32_to_u8_iterator<BaseIterator, U8Type>, U8Type, std::bidirectional_iterator_tag, const U8Type> base_type;
337   
338#if !defined(BOOST_NO_STD_ITERATOR_TRAITS) && !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
339   typedef typename std::iterator_traits<BaseIterator>::value_type base_value_type;
340
341   BOOST_STATIC_ASSERT(sizeof(base_value_type)*CHAR_BIT == 32);
342   BOOST_STATIC_ASSERT(sizeof(U8Type)*CHAR_BIT == 8);
343#endif
344
345public:
346   typename base_type::reference
347      dereference()const
348   {
349      if(m_current == 4)
350         extract_current();
351      return m_values[m_current];
352   }
353   bool equal(const u32_to_u8_iterator& that)const
354   {
355      if(m_position == that.m_position)
356      {
357         // either the m_current's must be equal, or one must be 0 and
358         // the other 4: which means neither must have bits 1 or 2 set:
359         return (m_current == that.m_current)
360            || (((m_current | that.m_current) & 3) == 0);
361      }
362      return false;
363   }
364   void increment()
365   {
366      // if we have a pending read then read now, so that we know whether
367      // to skip a position, or move to a low-surrogate:
368      if(m_current == 4)
369      {
370         // pending read:
371         extract_current();
372      }
373      // move to the next surrogate position:
374      ++m_current;
375      // if we've reached the end skip a position:
376      if(m_values[m_current] == 0)
377      {
378         m_current = 4;
379         ++m_position;
380      }
381   }
382   void decrement()
383   {
384      if((m_current & 3) == 0)
385      {
386         --m_position;
387         extract_current();
388         m_current = 3;
389         while(m_current && (m_values[m_current] == 0))
390            --m_current;
391      }
392      else
393         --m_current;
394   }
395   BaseIterator base()const
396   {
397      return m_position;
398   }
399   // construct:
400   u32_to_u8_iterator() : m_position(), m_current(0)
401   {
402      m_values[0] = 0;
403      m_values[1] = 0;
404      m_values[2] = 0;
405      m_values[3] = 0;
406      m_values[4] = 0;
407   }
408   u32_to_u8_iterator(BaseIterator b) : m_position(b), m_current(4)
409   {
410      m_values[0] = 0;
411      m_values[1] = 0;
412      m_values[2] = 0;
413      m_values[3] = 0;
414      m_values[4] = 0;
415   }
416private:
417
418   void extract_current()const
419   {
420      boost::uint32_t c = *m_position;
421      if(c > 0x10FFFFu)
422         detail::invalid_utf32_code_point(c);
423      if(c < 0x80u)
424      {
425         m_values[0] = static_cast<unsigned char>(c);
426         m_values[1] = static_cast<unsigned char>(0u);
427         m_values[2] = static_cast<unsigned char>(0u);
428         m_values[3] = static_cast<unsigned char>(0u);
429      }
430      else if(c < 0x800u)
431      {
432         m_values[0] = static_cast<unsigned char>(0xC0u + (c >> 6));
433         m_values[1] = static_cast<unsigned char>(0x80u + (c & 0x3Fu));
434         m_values[2] = static_cast<unsigned char>(0u);
435         m_values[3] = static_cast<unsigned char>(0u);
436      }
437      else if(c < 0x10000u)
438      {
439         m_values[0] = static_cast<unsigned char>(0xE0u + (c >> 12));
440         m_values[1] = static_cast<unsigned char>(0x80u + ((c >> 6) & 0x3Fu));
441         m_values[2] = static_cast<unsigned char>(0x80u + (c & 0x3Fu));
442         m_values[3] = static_cast<unsigned char>(0u);
443      }
444      else
445      {
446         m_values[0] = static_cast<unsigned char>(0xF0u + (c >> 18));
447         m_values[1] = static_cast<unsigned char>(0x80u + ((c >> 12) & 0x3Fu));
448         m_values[2] = static_cast<unsigned char>(0x80u + ((c >> 6) & 0x3Fu));
449         m_values[3] = static_cast<unsigned char>(0x80u + (c & 0x3Fu));
450      }
451      m_current= 0;
452   }
453   BaseIterator m_position;
454   mutable U8Type m_values[5];
455   mutable unsigned m_current;
456};
457
458template <class BaseIterator, class U32Type = ::boost::uint32_t>
459class u8_to_u32_iterator
460   : public boost::iterator_facade<u8_to_u32_iterator<BaseIterator, U32Type>, U32Type, std::bidirectional_iterator_tag, const U32Type>
461{
462   typedef boost::iterator_facade<u8_to_u32_iterator<BaseIterator, U32Type>, U32Type, std::bidirectional_iterator_tag, const U32Type> base_type;
463   // special values for pending iterator reads:
464   BOOST_STATIC_CONSTANT(U32Type, pending_read = 0xffffffffu);
465
466#if !defined(BOOST_NO_STD_ITERATOR_TRAITS) && !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
467   typedef typename std::iterator_traits<BaseIterator>::value_type base_value_type;
468
469   BOOST_STATIC_ASSERT(sizeof(base_value_type)*CHAR_BIT == 8);
470   BOOST_STATIC_ASSERT(sizeof(U32Type)*CHAR_BIT == 32);
471#endif
472
473public:
474   typename base_type::reference
475      dereference()const
476   {
477      if(m_value == pending_read)
478         extract_current();
479      return m_value;
480   }
481   bool equal(const u8_to_u32_iterator& that)const
482   {
483      return m_position == that.m_position;
484   }
485   void increment()
486   {
487      // skip high surrogate first if there is one:
488      unsigned c = detail::utf8_byte_count(*m_position);
489      std::advance(m_position, c);
490      m_value = pending_read;
491   }
492   void decrement()
493   {
494      // Keep backtracking until we don't have a trailing character:
495      unsigned count = 0;
496      while((*--m_position & 0xC0u) == 0x80u) ++count;
497      // now check that the sequence was valid:
498      if(count != detail::utf8_trailing_byte_count(*m_position))
499         invalid_sequnce();
500      m_value = pending_read;
501   }
502   BaseIterator base()const
503   {
504      return m_position;
505   }
506   // construct:
507   u8_to_u32_iterator() : m_position()
508   {
509      m_value = pending_read;
510   }
511   u8_to_u32_iterator(BaseIterator b) : m_position(b)
512   {
513      m_value = pending_read;
514   }
515private:
516   static void invalid_sequnce()
517   {
518      std::out_of_range e("Invalid UTF-8 sequence encountered while trying to encode UTF-32 character");
519      boost::throw_exception(e);
520   }
521   void extract_current()const
522   {
523      m_value = static_cast<U32Type>(static_cast< ::boost::uint8_t>(*m_position));
524      // we must not have a continuation character:
525      if((m_value & 0xC0u) == 0x80u)
526         invalid_sequnce();
527      // see how many extra byts we have:
528      unsigned extra = detail::utf8_trailing_byte_count(*m_position);
529      // extract the extra bits, 6 from each extra byte:
530      BaseIterator next(m_position);
531      for(unsigned c = 0; c < extra; ++c)
532      {
533         ++next;
534         m_value <<= 6;
535         m_value += static_cast<boost::uint8_t>(*next) & 0x3Fu;
536      }
537      // we now need to remove a few of the leftmost bits, but how many depends
538      // upon how many extra bytes we've extracted:
539      static const boost::uint32_t masks[4] = 
540      {
541         0x7Fu,
542         0x7FFu,
543         0xFFFFu,
544         0x1FFFFFu,
545      };
546      m_value &= masks[extra];
547      // check the result:
548      if(m_value > static_cast<U32Type>(0x10FFFFu))
549         invalid_sequnce();
550   }
551   BaseIterator m_position;
552   mutable U32Type m_value;
553};
554
555template <class BaseIterator>
556class utf16_output_iterator
557{
558public:
559   typedef void                                   difference_type;
560   typedef void                                   value_type;
561   typedef boost::uint32_t*                       pointer;
562   typedef boost::uint32_t&                       reference;
563   typedef std::output_iterator_tag               iterator_category;
564
565   utf16_output_iterator(const BaseIterator& b)
566      : m_position(b){}
567   utf16_output_iterator(const utf16_output_iterator& that)
568      : m_position(that.m_position){}
569   utf16_output_iterator& operator=(const utf16_output_iterator& that)
570   {
571      m_position = that.m_position;
572      return *this;
573   }
574   const utf16_output_iterator& operator*()const
575   {
576      return *this;
577   }
578   void operator=(boost::uint32_t val)const
579   {
580      push(val);
581   }
582   utf16_output_iterator& operator++()
583   {
584      return *this;
585   }
586   utf16_output_iterator& operator++(int)
587   {
588      return *this;
589   }
590   BaseIterator base()const
591   {
592      return m_position;
593   }
594private:
595   void push(boost::uint32_t v)const
596   {
597      if(v >= 0x10000u)
598      {
599         // begin by checking for a code point out of range:
600         if(v > 0x10FFFFu)
601            detail::invalid_utf32_code_point(v);
602         // split into two surrogates:
603         *m_position++ = static_cast<boost::uint16_t>(v >> 10) + detail::high_surrogate_base;
604         *m_position++ = static_cast<boost::uint16_t>(v & detail::ten_bit_mask) + detail::low_surrogate_base;
605      }
606      else
607      {
608         // 16-bit code point:
609         // value must not be a surrogate:
610         if(detail::is_surrogate(v))
611            detail::invalid_utf32_code_point(v);
612         *m_position++ = static_cast<boost::uint16_t>(v);
613      }
614   }
615   mutable BaseIterator m_position;
616};
617
618template <class BaseIterator>
619class utf8_output_iterator
620{
621public:
622   typedef void                                   difference_type;
623   typedef void                                   value_type;
624   typedef boost::uint32_t*                       pointer;
625   typedef boost::uint32_t&                       reference;
626   typedef std::output_iterator_tag               iterator_category;
627
628   utf8_output_iterator(const BaseIterator& b)
629      : m_position(b){}
630   utf8_output_iterator(const utf8_output_iterator& that)
631      : m_position(that.m_position){}
632   utf8_output_iterator& operator=(const utf8_output_iterator& that)
633   {
634      m_position = that.m_position;
635      return *this;
636   }
637   const utf8_output_iterator& operator*()const
638   {
639      return *this;
640   }
641   void operator=(boost::uint32_t val)const
642   {
643      push(val);
644   }
645   utf8_output_iterator& operator++()
646   {
647      return *this;
648   }
649   utf8_output_iterator& operator++(int)
650   {
651      return *this;
652   }
653   BaseIterator base()const
654   {
655      return m_position;
656   }
657private:
658   void push(boost::uint32_t c)const
659   {
660      if(c > 0x10FFFFu)
661         detail::invalid_utf32_code_point(c);
662      if(c < 0x80u)
663      {
664         *m_position++ = static_cast<unsigned char>(c);
665      }
666      else if(c < 0x800u)
667      {
668         *m_position++ = static_cast<unsigned char>(0xC0u + (c >> 6));
669         *m_position++ = static_cast<unsigned char>(0x80u + (c & 0x3Fu));
670      }
671      else if(c < 0x10000u)
672      {
673         *m_position++ = static_cast<unsigned char>(0xE0u + (c >> 12));
674         *m_position++ = static_cast<unsigned char>(0x80u + ((c >> 6) & 0x3Fu));
675         *m_position++ = static_cast<unsigned char>(0x80u + (c & 0x3Fu));
676      }
677      else
678      {
679         *m_position++ = static_cast<unsigned char>(0xF0u + (c >> 18));
680         *m_position++ = static_cast<unsigned char>(0x80u + ((c >> 12) & 0x3Fu));
681         *m_position++ = static_cast<unsigned char>(0x80u + ((c >> 6) & 0x3Fu));
682         *m_position++ = static_cast<unsigned char>(0x80u + (c & 0x3Fu));
683      }
684   }
685   mutable BaseIterator m_position;
686};
687
688} // namespace boost
689
690#endif // BOOST_REGEX_UNICODE_ITERATOR_HPP
691
Note: See TracBrowser for help on using the repository browser.