forked from boostorg/regex
Added object cache - internal state to traits classes is now cached.
Added first start to Unicode support. Enabled external template instance support. Fixed VC6 support. [SVN r25914]
This commit is contained in:
1 parent
70508f307a
commit
c05af49444
35 files changed
+3942
-2590
No files matched your search
@@ -374,9 +374,9 @@ BOOST_REGEX_DECL void BOOST_REGEX_CALL print_regex_library_info();
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_REGEX_DIAG)
|
||||
# pragma message ("BOOST_REGEX_DECL set as: " BOOST_STRINGIZE(BOOST_REGEX_DECL))
|
||||
# pragma message ("BOOST_REGEX_CALL set as: " BOOST_STRINGIZE(BOOST_REGEX_CALL))
|
||||
# pragma message ("BOOST_REGEX_CCALL set as: " BOOST_STRINGIZE(BOOST_REGEX_CCALL))
|
||||
# pragma message ("BOOST_REGEX_DECL" BOOST_STRINGIZE(=BOOST_REGEX_DECL))
|
||||
# pragma message ("BOOST_REGEX_CALL" BOOST_STRINGIZE(=BOOST_REGEX_CALL))
|
||||
# pragma message ("BOOST_REGEX_CCALL" BOOST_STRINGIZE(=BOOST_REGEX_CCALL))
|
||||
#ifdef BOOST_REGEX_USE_C_LOCALE
|
||||
# pragma message ("Using C locale in regex traits class")
|
||||
#elif BOOST_REGEX_USE_CPP_LOCALE
|
||||
@@ -384,20 +384,15 @@ BOOST_REGEX_DECL void BOOST_REGEX_CALL print_regex_library_info();
|
||||
#else
|
||||
# pragma message ("Using Win32 locale in regex traits class")
|
||||
#endif
|
||||
#ifdef BOOST_REGEX_DYN_LINK
|
||||
#if defined(BOOST_REGEX_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)
|
||||
# pragma message ("Dynamic linking enabled")
|
||||
#endif
|
||||
#ifdef BOOST_REGEX_NO_LIB
|
||||
#if defined(BOOST_REGEX_NO_LIB) || defined(BOOST_ALL_NO_LIB)
|
||||
# pragma message ("Auto-linking disabled")
|
||||
#endif
|
||||
#ifdef BOOST_REGEX_NO_EXTERNAL_TEMPLATES
|
||||
# pragma message ("Extern templates disabled")
|
||||
#endif
|
||||
#ifdef BOOST_REGEX_V3
|
||||
# pragma message ("Using Version 3 regex code")
|
||||
#else
|
||||
# pragma message ("Using Version 4 regex code")
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2004
|
||||
* Dr John Maddock
|
||||
*
|
||||
* Use, modification and distribution are 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)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE icu.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Unicode regular expressions on top of the ICU Library.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_ICU_HPP
|
||||
#define BOOST_REGEX_ICU_HPP
|
||||
|
||||
#include <unicode/utypes.h>
|
||||
#include <unicode/uchar.h>
|
||||
#include <unicode/coll.h>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/regex/pending/unicode_iterator.hpp>
|
||||
#include <bitset>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace re_detail{
|
||||
|
||||
//
|
||||
// Implementation details:
|
||||
//
|
||||
class icu_regex_traits_implementation
|
||||
{
|
||||
typedef UChar32 char_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef std::vector<char_type> string_type;
|
||||
typedef ::Locale locale_type;
|
||||
typedef boost::uint_least32_t char_class_type;
|
||||
public:
|
||||
icu_regex_traits_implementation(const ::Locale& l)
|
||||
: m_locale(l)
|
||||
{
|
||||
UErrorCode success = U_ZERO_ERROR;
|
||||
m_collator.reset( ::Collator::createInstance(l, success));
|
||||
if(U_SUCCESS(success) == 0)
|
||||
init_error();
|
||||
m_collator->setStrength(::Collator::IDENTICAL);
|
||||
success = U_ZERO_ERROR;
|
||||
m_primary_collator.reset( ::Collator::createInstance(l, success));
|
||||
if(U_SUCCESS(success) == 0)
|
||||
init_error();
|
||||
m_primary_collator->setStrength(::Collator::PRIMARY);
|
||||
}
|
||||
::Locale getloc()const
|
||||
{
|
||||
return m_locale;
|
||||
}
|
||||
string_type do_transform(const char_type* p1, const char_type* p2, const ::Collator* pcoll) const;
|
||||
string_type transform(const char_type* p1, const char_type* p2) const
|
||||
{
|
||||
return do_transform(p1, p2, m_collator.get());
|
||||
}
|
||||
string_type transform_primary(const char_type* p1, const char_type* p2) const
|
||||
{
|
||||
return do_transform(p1, p2, m_primary_collator.get());
|
||||
}
|
||||
private:
|
||||
void init_error()
|
||||
{
|
||||
std::runtime_error e("Could not initialize ICU resources");
|
||||
boost::throw_exception(e);
|
||||
}
|
||||
::Locale m_locale; // The ICU locale that we're using
|
||||
boost::scoped_ptr< ::Collator> m_collator; // The full collation object
|
||||
boost::scoped_ptr< ::Collator> m_primary_collator; // The primary collation object
|
||||
};
|
||||
|
||||
inline boost::shared_ptr<icu_regex_traits_implementation> get_icu_regex_traits_implementation(const ::Locale& loc)
|
||||
{
|
||||
return boost::shared_ptr<icu_regex_traits_implementation>(new icu_regex_traits_implementation(loc));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class icu_regex_traits
|
||||
{
|
||||
public:
|
||||
typedef UChar32 char_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef std::vector<char_type> string_type;
|
||||
typedef ::Locale locale_type;
|
||||
typedef std::bitset<64> char_class_type;
|
||||
|
||||
struct boost_extensions_tag{};
|
||||
|
||||
icu_regex_traits()
|
||||
: m_pimpl(re_detail::get_icu_regex_traits_implementation(::Locale()))
|
||||
{
|
||||
}
|
||||
static size_type length(const char_type* p);
|
||||
|
||||
::boost::regex_constants::syntax_type syntax_type(char_type c)const
|
||||
{
|
||||
return ((c < 0x7f) && (c > 0)) ? re_detail::get_default_syntax_type(static_cast<char>(c)) : regex_constants::syntax_char;
|
||||
}
|
||||
::boost::regex_constants::escape_syntax_type escape_syntax_type(char_type c) const
|
||||
{
|
||||
return ((c < 0x7f) && (c > 0)) ? re_detail::get_default_escape_syntax_type(static_cast<char>(c)) : regex_constants::syntax_char;
|
||||
}
|
||||
char_type translate(char_type c) const
|
||||
{
|
||||
return c;
|
||||
}
|
||||
char_type translate_nocase(char_type c) const
|
||||
{
|
||||
return ::u_tolower(c);
|
||||
}
|
||||
char_type translate(char_type c, bool icase) const
|
||||
{
|
||||
return icase ? translate_nocase(c) : translate(c);
|
||||
}
|
||||
char_type tolower(char_type c) const
|
||||
{
|
||||
return ::u_tolower(c);
|
||||
}
|
||||
char_type toupper(char_type c) const
|
||||
{
|
||||
return ::u_toupper(c);
|
||||
}
|
||||
string_type transform(const char_type* p1, const char_type* p2) const
|
||||
{
|
||||
return m_pimpl->transform(p1, p2);
|
||||
}
|
||||
string_type transform_primary(const char_type* p1, const char_type* p2) const
|
||||
{
|
||||
return m_pimpl->transform_primary(p1, p2);
|
||||
}
|
||||
char_class_type lookup_classname(const char_type* p1, const char_type* p2) const;
|
||||
string_type lookup_collatename(const char_type* p1, const char_type* p2) const;
|
||||
bool isctype(char_type c, char_class_type f) const;
|
||||
int toi(const char_type*& p1, const char_type* p2, int radix)const
|
||||
{
|
||||
return re_detail::global_toi(p1, p2, radix, *this);
|
||||
}
|
||||
int value(char_type c, int radix)const
|
||||
{
|
||||
return u_digit(c, static_cast< ::int8_t>(radix));
|
||||
}
|
||||
locale_type imbue(locale_type l)
|
||||
{
|
||||
locale_type result(m_pimpl->getloc());
|
||||
m_pimpl = re_detail::get_icu_regex_traits_implementation(l);
|
||||
return result;
|
||||
}
|
||||
locale_type getloc()const
|
||||
{
|
||||
return locale_type();
|
||||
}
|
||||
std::string error_string(::boost::regex_constants::error_type n) const
|
||||
{
|
||||
return re_detail::get_default_error_string(n);
|
||||
}
|
||||
private:
|
||||
icu_regex_traits(const icu_regex_traits&);
|
||||
icu_regex_traits& operator=(const icu_regex_traits&);
|
||||
|
||||
//
|
||||
// define the bitmasks offsets we need for additional character properties:
|
||||
//
|
||||
enum{
|
||||
offset_blank = U_CHAR_CATEGORY_COUNT,
|
||||
offset_space = U_CHAR_CATEGORY_COUNT+1,
|
||||
offset_xdigit = U_CHAR_CATEGORY_COUNT+2,
|
||||
offset_underscore = U_CHAR_CATEGORY_COUNT+3,
|
||||
offset_unicode = U_CHAR_CATEGORY_COUNT+4,
|
||||
};
|
||||
|
||||
//
|
||||
// and now the masks:
|
||||
//
|
||||
static const char_class_type mask_blank;
|
||||
static const char_class_type mask_space;
|
||||
static const char_class_type mask_xdigit;
|
||||
static const char_class_type mask_underscore;
|
||||
static const char_class_type mask_unicode;
|
||||
|
||||
boost::shared_ptr< ::boost::re_detail::icu_regex_traits_implementation> m_pimpl;
|
||||
};
|
||||
|
||||
// types:
|
||||
typedef basic_regex< ::UChar32, icu_regex_traits> u32regex;
|
||||
typedef match_results<const ::UChar32*> u32match;
|
||||
|
||||
} // namespace boost.
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2004
|
||||
* Dr John Maddock
|
||||
*
|
||||
* Use, modification and distribution are 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)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE object_cache.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Implements a generic object cache.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_OBJECT_CACHE_HPP
|
||||
#define BOOST_REGEX_OBJECT_CACHE_HPP
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
#include <boost/regex/pending/static_mutex.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
|
||||
template <class Key, class Object>
|
||||
class object_cache
|
||||
{
|
||||
typedef std::pair< ::boost::shared_ptr<Object>, Key const*> value_type;
|
||||
typedef std::list<value_type> list_type;
|
||||
typedef typename list_type::iterator list_iterator;
|
||||
typedef std::map<Key, list_iterator> map_type;
|
||||
typedef typename map_type::iterator map_iterator;
|
||||
typedef typename list_type::size_type size_type;
|
||||
public:
|
||||
static boost::shared_ptr<Object> get(const Key& k, size_type max_cache_size);
|
||||
|
||||
private:
|
||||
static boost::shared_ptr<Object> do_get(const Key& k, size_type max_cache_size);
|
||||
|
||||
struct data
|
||||
{
|
||||
list_type cont;
|
||||
map_type index;
|
||||
};
|
||||
};
|
||||
|
||||
template <class Key, class Object>
|
||||
boost::shared_ptr<Object> object_cache<Key, Object>::get(const Key& k, size_type max_cache_size)
|
||||
{
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
static boost::static_mutex mut = BOOST_STATIC_MUTEX_INIT;
|
||||
|
||||
boost::static_mutex::scoped_lock l(mut);
|
||||
if(l)
|
||||
{
|
||||
return do_get(k, max_cache_size);
|
||||
}
|
||||
//
|
||||
// what do we do if the lock fails?
|
||||
// for now just throw, but we should never really get here...
|
||||
//
|
||||
::boost::throw_exception(std::runtime_error("Error in thread safety code: could not acquire a lock"));
|
||||
return boost::shared_ptr<Object>();
|
||||
#else
|
||||
return do_get(k, max_cache_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class Key, class Object>
|
||||
boost::shared_ptr<Object> object_cache<Key, Object>::do_get(const Key& k, size_type max_cache_size)
|
||||
{
|
||||
typedef typename object_cache<Key, Object>::data object_data;
|
||||
typedef typename list_type::size_type list_size_type;
|
||||
static object_data s_data;
|
||||
|
||||
//
|
||||
// see if the object is already in the cache:
|
||||
//
|
||||
map_iterator mpos = s_data.index.find(k);
|
||||
if(mpos != s_data.index.end())
|
||||
{
|
||||
//
|
||||
// Eureka!
|
||||
// We have a cached item, bump it up the list and return it:
|
||||
//
|
||||
if(--(s_data.cont.end()) != mpos->second)
|
||||
{
|
||||
// splice out the item we want to move:
|
||||
list_type temp;
|
||||
temp.splice(temp.end(), s_data.cont, mpos->second);
|
||||
// and now place it at the end of the list:
|
||||
s_data.cont.splice(s_data.cont.end(), temp, temp.begin());
|
||||
BOOST_ASSERT(*(s_data.cont.back().second) == k);
|
||||
// update index with new position:
|
||||
mpos->second = --(s_data.cont.end());
|
||||
BOOST_ASSERT(&(mpos->first) == mpos->second->second);
|
||||
BOOST_ASSERT(&(mpos->first) == s_data.cont.back().second);
|
||||
}
|
||||
return s_data.cont.back().first;
|
||||
}
|
||||
//
|
||||
// if we get here then the item is not in the cache,
|
||||
// so create it:
|
||||
//
|
||||
boost::shared_ptr<Object> result(new Object(k));
|
||||
//
|
||||
// Add it to the list, and index it:
|
||||
//
|
||||
s_data.cont.push_back(value_type(result, 0));
|
||||
s_data.index[k] = --(s_data.cont.end());
|
||||
s_data.cont.back().second = &(s_data.index.find(k)->first);
|
||||
list_size_type s = s_data.cont.size();
|
||||
BOOST_ASSERT(s_data.index[k]->first.get() == result.get());
|
||||
BOOST_ASSERT(&(s_data.index.find(k)->first) == s_data.cont.back().second);
|
||||
BOOST_ASSERT(s_data.index.find(k)->first == k);
|
||||
if(s > max_cache_size)
|
||||
{
|
||||
//
|
||||
// We have too many items in the list, so we need to start
|
||||
// popping them off the back of the list, but only if they're
|
||||
// being held uniquely by us:
|
||||
//
|
||||
list_iterator pos = s_data.cont.begin();
|
||||
list_iterator last = s_data.cont.end();
|
||||
while((pos != last) && (s > max_cache_size))
|
||||
{
|
||||
if(pos->first.unique())
|
||||
{
|
||||
list_iterator condemmed(pos);
|
||||
++pos;
|
||||
// now remove the items from our containers,
|
||||
// then order has to be as follows:
|
||||
BOOST_ASSERT(s_data.index.find(*(condemmed->second)) != s_data.index.end());
|
||||
s_data.index.erase(*(condemmed->second));
|
||||
s_data.cont.erase(condemmed);
|
||||
--s;
|
||||
}
|
||||
else
|
||||
--pos;
|
||||
}
|
||||
BOOST_ASSERT(s_data.index[k]->first.get() == result.get());
|
||||
BOOST_ASSERT(&(s_data.index.find(k)->first) == s_data.cont.back().second);
|
||||
BOOST_ASSERT(s_data.index.find(k)->first == k);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2004
|
||||
* Dr John Maddock
|
||||
*
|
||||
* Use, modification and distribution are 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)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE static_mutex.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Declares static_mutex lock type, there are three different
|
||||
* implementations: POSIX pthreads, WIN32 threads, and portable,
|
||||
* these are described in more detail below.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_STATIC_MUTEX_HPP
|
||||
#define BOOST_REGEX_STATIC_MUTEX_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/regex/config.hpp> // dll import/export options.
|
||||
|
||||
#ifdef BOOST_HAS_PTHREADS
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS) && defined(PTHREAD_MUTEX_INITIALIZER)
|
||||
//
|
||||
// pthreads version:
|
||||
// simple wrap around a pthread_mutex_t initialized with
|
||||
// PTHREAD_MUTEX_INITIALIZER.
|
||||
//
|
||||
namespace boost{
|
||||
|
||||
class BOOST_REGEX_DECL scoped_static_mutex_lock;
|
||||
|
||||
class static_mutex
|
||||
{
|
||||
public:
|
||||
typedef scoped_static_mutex_lock scoped_lock;
|
||||
pthread_mutex_t m_mutex;
|
||||
};
|
||||
|
||||
#define BOOST_STATIC_MUTEX_INIT { PTHREAD_MUTEX_INITIALIZER, }
|
||||
|
||||
class BOOST_REGEX_DECL scoped_static_mutex_lock
|
||||
{
|
||||
public:
|
||||
scoped_static_mutex_lock(static_mutex& mut, bool lk = true);
|
||||
~scoped_static_mutex_lock();
|
||||
operator void const*()const;
|
||||
bool locked()const;
|
||||
void lock();
|
||||
void unlock();
|
||||
private:
|
||||
static_mutex& m_mutex;
|
||||
bool m_have_lock;
|
||||
};
|
||||
|
||||
inline scoped_static_mutex_lock::operator void const*()const
|
||||
{
|
||||
return locked() ? this : 0;
|
||||
}
|
||||
|
||||
inline bool scoped_static_mutex_lock::locked()const
|
||||
{
|
||||
return m_have_lock;
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
#elif defined(BOOST_HAS_WINTHREADS)
|
||||
//
|
||||
// Win32 version:
|
||||
// Use a 32-bit int as a lock, along with a test-and-set
|
||||
// implementation using InterlockedCompareExchange.
|
||||
//
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
namespace boost{
|
||||
|
||||
class BOOST_REGEX_DECL scoped_static_mutex_lock;
|
||||
|
||||
class static_mutex
|
||||
{
|
||||
public:
|
||||
typedef scoped_static_mutex_lock scoped_lock;
|
||||
boost::int32_t m_mutex;
|
||||
};
|
||||
|
||||
#define BOOST_STATIC_MUTEX_INIT { 0, }
|
||||
|
||||
class BOOST_REGEX_DECL scoped_static_mutex_lock
|
||||
{
|
||||
public:
|
||||
scoped_static_mutex_lock(static_mutex& mut, bool lk = true);
|
||||
~scoped_static_mutex_lock();
|
||||
operator void const*()const;
|
||||
bool locked()const;
|
||||
void lock();
|
||||
void unlock();
|
||||
private:
|
||||
static_mutex& m_mutex;
|
||||
bool m_have_lock;
|
||||
scoped_static_mutex_lock(const scoped_static_mutex_lock&);
|
||||
scoped_static_mutex_lock& operator=(const scoped_static_mutex_lock&);
|
||||
};
|
||||
|
||||
inline scoped_static_mutex_lock::operator void const*()const
|
||||
{
|
||||
return locked() ? this : 0;
|
||||
}
|
||||
|
||||
inline bool scoped_static_mutex_lock::locked()const
|
||||
{
|
||||
return m_have_lock;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#else
|
||||
//
|
||||
// Portable version of a static mutex based on Boost.Thread library:
|
||||
// This has to use a single mutex shared by all instances of static_mutex
|
||||
// because boost::call_once doesn't alow us to pass instance information
|
||||
// down to the initialisation proceedure. In fact the initialisation routine
|
||||
// may need to be called more than once - but only once per instance.
|
||||
//
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
|
||||
namespace boost{
|
||||
|
||||
class BOOST_REGEX_DECL scoped_static_mutex_lock;
|
||||
extern "C" BOOST_REGEX_DECL void free_static_mutex();
|
||||
|
||||
class BOOST_REGEX_DECL static_mutex
|
||||
{
|
||||
public:
|
||||
typedef scoped_static_mutex_lock scoped_lock;
|
||||
static void init();
|
||||
static boost::recursive_mutex* m_pmutex;
|
||||
static boost::once_flag m_once;
|
||||
};
|
||||
|
||||
#define BOOST_STATIC_MUTEX_INIT { }
|
||||
|
||||
class BOOST_REGEX_DECL scoped_static_mutex_lock
|
||||
{
|
||||
public:
|
||||
scoped_static_mutex_lock(static_mutex& mut, bool lk = true);
|
||||
~scoped_static_mutex_lock();
|
||||
operator void const*()const;
|
||||
bool locked()const;
|
||||
void lock();
|
||||
void unlock();
|
||||
private:
|
||||
boost::recursive_mutex::scoped_lock* m_plock;
|
||||
bool m_have_lock;
|
||||
};
|
||||
|
||||
inline scoped_static_mutex_lock::operator void const*()const
|
||||
{
|
||||
return locked() ? this : 0;
|
||||
}
|
||||
|
||||
inline bool scoped_static_mutex_lock::locked()const
|
||||
{
|
||||
return m_have_lock;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2004
|
||||
* Dr John Maddock
|
||||
*
|
||||
* Use, modification and distribution are 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)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE unicode_iterator.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Iterator adapters for converting between different Unicode encodings.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_UNICODE_ITERATOR_HPP
|
||||
#define BOOST_REGEX_UNICODE_ITERATOR_HPP
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <stdexcept>
|
||||
#ifndef BOOST_NO_STD_LOCALE
|
||||
#include <sstream>
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace detail{
|
||||
|
||||
static const ::boost::uint16_t high_surrogate_base = 0xD7C0u;
|
||||
static const ::boost::uint16_t low_surrogate_base = 0xDC00u;
|
||||
static const ::boost::uint32_t ten_bit_mask = 0x3FFu;
|
||||
|
||||
inline bool is_high_surrogate(::boost::uint16_t v)
|
||||
{
|
||||
return (v & 0xFC00u) == 0xd800u;
|
||||
}
|
||||
inline bool is_low_surrogate(::boost::uint16_t v)
|
||||
{
|
||||
return (v & 0xFC00u) == 0xdc00u;
|
||||
}
|
||||
template <class T>
|
||||
inline bool is_surrogate(T v)
|
||||
{
|
||||
return (v & 0xF800u) == 0xd800;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <class BaseIterator, class U16Type = ::boost::uint16_t>
|
||||
class u32_to_u16_iterator
|
||||
: public boost::iterator_facade<u32_to_u16_iterator<BaseIterator, U16Type>, U16Type, std::bidirectional_iterator_tag, const U16Type>
|
||||
{
|
||||
typedef boost::iterator_facade<u32_to_u16_iterator<BaseIterator>, U16Type, std::bidirectional_iterator_tag, const U16Type> base_type;
|
||||
typedef typename std::iterator_traits<BaseIterator>::value_type base_value_type;
|
||||
|
||||
BOOST_STATIC_ASSERT(sizeof(base_value_type)*CHAR_BIT == 32);
|
||||
BOOST_STATIC_ASSERT(sizeof(U16Type)*CHAR_BIT == 16);
|
||||
public:
|
||||
typename base_type::reference
|
||||
dereference()const
|
||||
{
|
||||
if(m_current == 2)
|
||||
const_cast<u32_to_u16_iterator*>(this)->extract_current();
|
||||
return m_values[m_current];
|
||||
}
|
||||
bool equal(const u32_to_u16_iterator& that)const
|
||||
{
|
||||
if(m_position == that.m_position)
|
||||
{
|
||||
if((m_current >= 2) && (that.m_current < 2))
|
||||
const_cast<u32_to_u16_iterator*>(this)->extract_current();
|
||||
else if((m_current < 2) && (that.m_current >= 2))
|
||||
const_cast<u32_to_u16_iterator&>(that).extract_current();
|
||||
if(m_current == that.m_current)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void increment()
|
||||
{
|
||||
// if we have a pending read then read now, so that we know whether
|
||||
// to skip a position, or move to a low-surrogate:
|
||||
if(m_current == 2)
|
||||
{
|
||||
// pending read:
|
||||
extract_current();
|
||||
}
|
||||
// move to the next surrogate position:
|
||||
++m_current;
|
||||
// if we've reached the end skip a position:
|
||||
if(m_values[m_current] == 0)
|
||||
{
|
||||
m_current = 2;
|
||||
++m_position;
|
||||
}
|
||||
}
|
||||
void decrement()
|
||||
{
|
||||
if(m_current != 1)
|
||||
{
|
||||
// decrementing an iterator always leads to a valid position:
|
||||
--m_position;
|
||||
extract_current();
|
||||
m_current = m_values[1] ? 1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_current = 0;
|
||||
}
|
||||
}
|
||||
BaseIterator base()const
|
||||
{
|
||||
return m_position;
|
||||
}
|
||||
// construct:
|
||||
u32_to_u16_iterator() : m_position(), m_current(0)
|
||||
{
|
||||
m_values[2] = 0;
|
||||
}
|
||||
u32_to_u16_iterator(BaseIterator b) : m_position(b), m_current(2)
|
||||
{
|
||||
m_values[2] = 0;
|
||||
}
|
||||
private:
|
||||
void invalid_code_point(::boost::uint32_t val)
|
||||
{
|
||||
#ifndef BOOST_NO_STD_LOCALE
|
||||
std::stringstream ss;
|
||||
ss << "Invalid UTF-32 code point U+" << std::showbase << std::hex << val << " encountered while trying to encode UTF-16 sequence";
|
||||
std::out_of_range e(ss.str());
|
||||
#else
|
||||
std::out_of_range e("Invalid UTF-32 code point encountered while trying to encode UTF-16 sequence");
|
||||
#endif
|
||||
boost::throw_exception(e);
|
||||
}
|
||||
|
||||
void extract_current()
|
||||
{
|
||||
// begin by checking for a code point out of range:
|
||||
if(static_cast< ::boost::uint32_t>(*m_position) >= 0x10000u)
|
||||
{
|
||||
if(static_cast< ::boost::uint32_t>(*m_position) > 0x10FFFFu)
|
||||
invalid_code_point(*m_position);
|
||||
// split into two surrogates:
|
||||
base_value_type v = *m_position;
|
||||
m_values[0] = static_cast<U16Type>(v >> 10) + detail::high_surrogate_base;
|
||||
m_values[1] = static_cast<U16Type>(v & detail::ten_bit_mask) + detail::low_surrogate_base;
|
||||
m_current = 0;
|
||||
BOOST_ASSERT(detail::is_high_surrogate(m_values[0]));
|
||||
BOOST_ASSERT(detail::is_low_surrogate(m_values[1]));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 16-bit code point:
|
||||
m_values[0] = static_cast<U16Type>(*m_position);
|
||||
m_values[1] = 0;
|
||||
m_current = 0;
|
||||
// value must not be a surrogate:
|
||||
if(detail::is_surrogate(m_values[0]))
|
||||
invalid_code_point(*m_position);
|
||||
}
|
||||
}
|
||||
BaseIterator m_position;
|
||||
U16Type m_values[3];
|
||||
unsigned m_current;
|
||||
};
|
||||
|
||||
template <class BaseIterator, class U32Type = ::boost::uint32_t>
|
||||
class u16_to_u32_iterator
|
||||
: public boost::iterator_facade<u16_to_u32_iterator<BaseIterator, U32Type>, U32Type, std::bidirectional_iterator_tag, const U32Type>
|
||||
{
|
||||
typedef boost::iterator_facade<u16_to_u32_iterator<BaseIterator>, U32Type, std::bidirectional_iterator_tag, const U32Type> base_type;
|
||||
// special values for pending iterator reads:
|
||||
BOOST_STATIC_CONSTANT(::boost::uint32_t, pending_read = 0xffffffffu);
|
||||
|
||||
typedef typename std::iterator_traits<BaseIterator>::value_type base_value_type;
|
||||
|
||||
BOOST_STATIC_ASSERT(sizeof(base_value_type)*CHAR_BIT == 16);
|
||||
BOOST_STATIC_ASSERT(sizeof(U32Type)*CHAR_BIT == 32);
|
||||
|
||||
public:
|
||||
typename base_type::reference
|
||||
dereference()const
|
||||
{
|
||||
if(m_value == pending_read)
|
||||
const_cast<u16_to_u32_iterator*>(this)->extract_current();
|
||||
return m_value;
|
||||
}
|
||||
bool equal(const u16_to_u32_iterator& that)const
|
||||
{
|
||||
return m_position == that.m_position;
|
||||
}
|
||||
void increment()
|
||||
{
|
||||
// skip high surrogate first if there is one:
|
||||
if(detail::is_high_surrogate(*m_position)) ++m_position;
|
||||
++m_position;
|
||||
m_value = pending_read;
|
||||
}
|
||||
void decrement()
|
||||
{
|
||||
--m_position;
|
||||
// if we have a low surrogate then go back one more:
|
||||
if(detail::is_low_surrogate(*m_position))
|
||||
--m_position;
|
||||
m_value = pending_read;
|
||||
}
|
||||
BaseIterator base()const
|
||||
{
|
||||
return m_position;
|
||||
}
|
||||
// construct:
|
||||
u16_to_u32_iterator() : m_position()
|
||||
{
|
||||
}
|
||||
u16_to_u32_iterator(BaseIterator b) : m_position(b)
|
||||
{
|
||||
m_value = pending_read;
|
||||
}
|
||||
private:
|
||||
void invalid_code_point(::boost::uint16_t val)
|
||||
{
|
||||
#ifndef BOOST_NO_STD_LOCALE
|
||||
std::stringstream ss;
|
||||
ss << "Misplaced UTF-16 surrogate U+" << std::showbase << std::hex << val << " encountered while trying to encode UTF-32 sequence";
|
||||
std::out_of_range e(ss.str());
|
||||
#else
|
||||
std::out_of_range e("Misplaced UTF-16 surrogate encountered while trying to encode UTF-32 sequence");
|
||||
#endif
|
||||
boost::throw_exception(e);
|
||||
}
|
||||
void extract_current()
|
||||
{
|
||||
m_value = static_cast<U32Type>(static_cast< ::boost::uint16_t>(*m_position));
|
||||
// if the last value is a high surrogate then adjust m_position and m_value as needed:
|
||||
if(detail::is_high_surrogate(*m_position))
|
||||
{
|
||||
// precondition; next value must have be a low-surrogate:
|
||||
::boost::uint16_t t = *++m_position;
|
||||
if((*m_position & 0xFC00u) != 0xDC00u)
|
||||
invalid_code_point(t);
|
||||
m_value = (m_value - detail::high_surrogate_base) << 10;
|
||||
m_value |= (static_cast<U32Type>(static_cast< ::boost::uint16_t>(t)) & detail::ten_bit_mask);
|
||||
--m_position;
|
||||
}
|
||||
// postcondition; result must not be a surrogate:
|
||||
if(detail::is_surrogate(m_value))
|
||||
invalid_code_point(static_cast< ::boost::uint16_t>(m_value));
|
||||
}
|
||||
BaseIterator m_position;
|
||||
U32Type m_value;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // BOOST_REGEX_UNICODE_ITERATOR_HPP
|
||||
@@ -1257,7 +1257,7 @@ bool valid_value(charT, int v, const mpl::true_&)
|
||||
return (v >> (sizeof(charT) * CHAR_BIT)) == 0;
|
||||
}
|
||||
template <class charT>
|
||||
bool valid_value(charT, int v, const mpl::false_&)
|
||||
bool valid_value(charT, int, const mpl::false_&)
|
||||
{
|
||||
return true; // v will alsways fit in a charT
|
||||
}
|
||||
|
||||
@@ -71,6 +71,8 @@ template class BOOST_REGEX_DECL basic_regex< BOOST_REGEX_CHAR_T >;
|
||||
template class BOOST_REGEX_DECL basic_regex< BOOST_REGEX_CHAR_T >;
|
||||
template class BOOST_REGEX_DECL match_results< const BOOST_REGEX_CHAR_T* >;
|
||||
template class BOOST_REGEX_DECL match_results< std::basic_string<BOOST_REGEX_CHAR_T>::const_iterator >;
|
||||
template class BOOST_REGEX_DECL ::boost::re_detail::perl_matcher<BOOST_REGEX_CHAR_T const *, match_results< const BOOST_REGEX_CHAR_T* >::allocator_type, boost::regex_traits<BOOST_REGEX_CHAR_T > >;
|
||||
|
||||
|
||||
# ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
|
||||
@@ -72,6 +72,13 @@ struct regex_iterator_traits<wchar_t*> : pointer_iterator_traits<wchar_t>{};
|
||||
template<>
|
||||
struct regex_iterator_traits<const wchar_t*> : const_pointer_iterator_traits<wchar_t>{};
|
||||
|
||||
#ifdef BOOST_REGEX_HAS_OTHER_WCHAR_T
|
||||
template<>
|
||||
struct regex_iterator_traits<unsigned short*> : pointer_iterator_traits<unsigned short>{};
|
||||
template<>
|
||||
struct regex_iterator_traits<const unsigned short*> : const_pointer_iterator_traits<unsigned short>{};
|
||||
#endif
|
||||
|
||||
#if defined(__SGI_STL_PORT) && defined(__STL_DEBUG)
|
||||
template<>
|
||||
struct regex_iterator_traits<std::string::iterator> : pointer_iterator_traits<char>{};
|
||||
|
||||
@@ -149,7 +149,7 @@ public:
|
||||
string_type format(const string_type& fmt,
|
||||
match_flag_type flags = format_default) const
|
||||
{
|
||||
return regex_format(*this, fmt, flags);
|
||||
return regex_format<BidiIterator, char_type>(*this, fmt, flags);
|
||||
}
|
||||
// format with locale:
|
||||
template <class OutputIterator, class RegexT>
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace re_detail{
|
||||
//
|
||||
// error checking API:
|
||||
//
|
||||
BOOST_REGEX_DECL void BOOST_REGEX_CALL verify_options(boost::regex::flag_type ef, match_flag_type mf);
|
||||
BOOST_REGEX_DECL void BOOST_REGEX_CALL verify_options(boost::regex_constants::syntax_option_type ef, match_flag_type mf);
|
||||
//
|
||||
// function can_start:
|
||||
//
|
||||
@@ -85,11 +85,11 @@ template <class Seq, class C>
|
||||
inline int string_compare(const Seq& s, const C* p)
|
||||
{
|
||||
std::size_t i = 0;
|
||||
while(p[i] && (p[i] == s[i]))
|
||||
while((i < s.size()) && (p[i] == s[i]))
|
||||
{
|
||||
++i;
|
||||
}
|
||||
return s[i] - p[i];
|
||||
return (i == s.size()) ? -p[i] : s[i] - p[i];
|
||||
}
|
||||
#endif
|
||||
# define STR_COMP(s,p) string_compare(s,p)
|
||||
@@ -354,7 +354,9 @@ private:
|
||||
bool match_backstep();
|
||||
bool match_assert_backref();
|
||||
bool match_toggle_case();
|
||||
#ifdef BOOST_REGEX_RECURSIVE
|
||||
bool backtrack_till_match(std::size_t count);
|
||||
#endif
|
||||
|
||||
// find procs stored in s_find_vtable:
|
||||
bool find_restart_any();
|
||||
@@ -450,9 +452,14 @@ private:
|
||||
unsigned used_block_count;
|
||||
#endif
|
||||
|
||||
// these operations aren't allowed, so are declared private:
|
||||
perl_matcher& operator=(const perl_matcher&);
|
||||
perl_matcher(const perl_matcher&);
|
||||
// these operations aren't allowed, so are declared private,
|
||||
// bodies are provided to keep explicit-instantiation requests happy:
|
||||
perl_matcher& operator=(const perl_matcher&)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
perl_matcher(const perl_matcher& that)
|
||||
: m_result(that.m_result), re(that.re), traits_inst(that.traits_inst), rep_obj(0) {}
|
||||
};
|
||||
|
||||
} // namespace re_detail
|
||||
|
||||
@@ -87,7 +87,6 @@
|
||||
#ifndef BOOST_REGEX_MATCHER_HPP
|
||||
#include <boost/regex/v4/perl_matcher.hpp>
|
||||
#endif
|
||||
|
||||
//
|
||||
// template instances:
|
||||
//
|
||||
|
||||
@@ -534,7 +534,7 @@ OutputIterator regex_format(OutputIterator out,
|
||||
)
|
||||
{
|
||||
re_detail::trivial_format_traits<charT> traits;
|
||||
return regex_format_imp(out, m, fmt, fmt + traits.length(fmt), flags, traits);
|
||||
return re_detail::regex_format_imp(out, m, fmt, fmt + traits.length(fmt), flags, traits);
|
||||
}
|
||||
|
||||
template <class OutputIterator, class Iterator, class charT>
|
||||
@@ -545,7 +545,7 @@ OutputIterator regex_format(OutputIterator out,
|
||||
)
|
||||
{
|
||||
re_detail::trivial_format_traits<charT> traits;
|
||||
return regex_format_imp(out, m, fmt.data(), fmt.data() + fmt.size(), flags, traits);
|
||||
return re_detail::regex_format_imp(out, m, fmt.data(), fmt.data() + fmt.size(), flags, traits);
|
||||
}
|
||||
|
||||
template <class Iterator, class charT>
|
||||
@@ -556,7 +556,7 @@ std::basic_string<charT> regex_format(const match_results<Iterator>& m,
|
||||
std::basic_string<charT> result;
|
||||
re_detail::string_out_iterator<std::basic_string<charT> > i(result);
|
||||
re_detail::trivial_format_traits<charT> traits;
|
||||
regex_format_imp(i, m, fmt, fmt + traits.length(fmt), flags, traits);
|
||||
re_detail::regex_format_imp(i, m, fmt, fmt + traits.length(fmt), flags, traits);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -568,7 +568,7 @@ std::basic_string<charT> regex_format(const match_results<Iterator>& m,
|
||||
std::basic_string<charT> result;
|
||||
re_detail::string_out_iterator<std::basic_string<charT> > i(result);
|
||||
re_detail::trivial_format_traits<charT> traits;
|
||||
regex_format_imp(i, m, fmt.data(), fmt.data() + fmt.size(), flags, traits);
|
||||
re_detail::regex_format_imp(i, m, fmt.data(), fmt.data() + fmt.size(), flags, traits);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -229,6 +229,11 @@ BOOST_REGEX_DECL char BOOST_REGEX_CALL global_upper(char c);
|
||||
BOOST_REGEX_DECL wchar_t BOOST_REGEX_CALL global_lower(wchar_t c);
|
||||
BOOST_REGEX_DECL wchar_t BOOST_REGEX_CALL global_upper(wchar_t c);
|
||||
#endif
|
||||
#ifdef BOOST_REGEX_HAS_OTHER_WCHAR_T
|
||||
BOOST_REGEX_DECL unsigned short BOOST_REGEX_CALL global_lower(unsigned short c);
|
||||
BOOST_REGEX_DECL unsigned short BOOST_REGEX_CALL global_upper(unsigned short c);
|
||||
#endif
|
||||
|
||||
template <class charT>
|
||||
int global_value(charT c)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user