From 5a6ea019fd48b269121f95dc4afabce760531bbe Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 9 May 2012 11:49:37 +0200 Subject: Make regex class template --- NEWS | 5 ++ cutl/re.hxx | 177 +++++++++++++++++++++++++-------------------- cutl/re/re.cxx | 202 +++++++++++++++++++++++++++++++--------------------- cutl/re/re.txx | 69 ++++++++++++++++++ tests/re/driver.cxx | 2 +- 5 files changed, 293 insertions(+), 162 deletions(-) create mode 100644 cutl/re/re.txx diff --git a/NEWS b/NEWS index e750d76..3c6b429 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,8 @@ +Version 1.7.0 + + * Make regex a class template with character type as a template argument + (currently can only be char or wchar_t). + Version 1.6.3 * Minor fixes to make libcutl compilable with more pedantic GCC 4.7. diff --git a/cutl/re.hxx b/cutl/re.hxx index 3c47852..7638bb4 100644 --- a/cutl/re.hxx +++ b/cutl/re.hxx @@ -6,7 +6,7 @@ #define CUTL_RE_HXX #include -#include // std::ostream +#include #include #include @@ -15,21 +15,12 @@ namespace cutl { namespace re { - struct LIBCUTL_EXPORT format: exception + struct LIBCUTL_EXPORT format_base: exception { virtual - ~format () throw (); + ~format_base () throw (); - format (std::string const& e, std::string const& d) - : regex_ (e), description_ (d) - { - } - - std::string const& - regex () const - { - return regex_; - } + format_base (std::string const& d): description_ (d) {} std::string const& description () const @@ -40,56 +31,72 @@ namespace cutl virtual char const* what () const throw (); - private: - std::string regex_; + protected: std::string description_; }; - // Regular expression pattern. - // - struct LIBCUTL_EXPORT regex + template + struct basic_format: format_base { - ~regex (); + virtual + ~basic_format () throw () {} + + basic_format (std::basic_string const& e, std::string const& d) + : format_base (d), regex_ (e) {} - regex () - : impl_ (0) + std::basic_string const& + regex () const { - init (0); + return regex_; } + private: + std::basic_string regex_; + }; + + typedef basic_format format; + typedef basic_format wformat; + + // Regular expression pattern. + // + template + struct basic_regex + { + typedef std::basic_string string_type; + + ~basic_regex (); + + basic_regex (): impl_ (0) {init (0);} + explicit - regex (std::string const& s) - : impl_ (0) - { - init (&s); - } + basic_regex (string_type const& s): impl_ (0) {init (&s);} - regex& - operator= (std::string const& s) + basic_regex& + operator= (string_type const& s) { init (&s); return *this; } - regex (regex const&); + basic_regex (basic_regex const&); - regex& - operator= (regex const&); + basic_regex& + operator= (basic_regex const&); public: bool - match (std::string const&) const; + match (string_type const&) const; bool - search (std::string const&) const; + search (string_type const&) const; - std::string - replace (std::string const& s, - std::string const& sub, + string_type + replace (string_type const& s, + string_type const& sub, bool first_only = false) const; public: - std::string + string_type str () const; bool @@ -97,25 +104,32 @@ namespace cutl private: void - init (std::string const*); + init (string_type const*); private: struct impl; impl* impl_; }; - LIBCUTL_EXPORT std::ostream& - operator<< (std::ostream&, regex const&); + template + inline std::basic_ostream& + operator<< (std::basic_ostream& os, basic_regex const& r) + { + return os << r.str (); + } + + typedef basic_regex regex; + typedef basic_regex wregex; // Regular expression pattern and substituation. // - struct LIBCUTL_EXPORT regexsub + template + struct basic_regexsub { - typedef re::regex regex_type; + typedef basic_regex regex_type; + typedef std::basic_string string_type; - regexsub () - { - } + basic_regexsub () {} // Expression is of the form /regex/substitution/ where '/' can // be replaced with any delimiter. Delimiters must be escaped in @@ -124,23 +138,20 @@ namespace cutl // sequence (e.g., "\\"). // explicit - regexsub (std::string const& e) - { - init (e); - } + basic_regexsub (string_type const& e) {init (e);} - regexsub (std::string const& regex, std::string const& sub) + basic_regexsub (string_type const& regex, string_type const& sub) : regex_ (regex), sub_ (sub) { } - regexsub (regex_type const& regex, std::string const& sub) + basic_regexsub (regex_type const& regex, string_type const& sub) : regex_ (regex), sub_ (sub) { } - regexsub& - operator= (std::string const& e) + basic_regexsub& + operator= (string_type const& e) { init (e); return *this; @@ -148,19 +159,19 @@ namespace cutl public: bool - match (std::string const& s) const + match (string_type const& s) const { return regex_.match (s); } bool - search (std::string const& s) const + search (string_type const& s) const { return regex_.search (s); } - std::string - replace (std::string const& s, bool first_only = false) const + string_type + replace (string_type const& s, bool first_only = false) const { return regex_.replace (s, sub_, first_only); } @@ -172,7 +183,7 @@ namespace cutl return regex_; } - const std::string& + const string_type& substitution () const { return sub_; @@ -186,45 +197,52 @@ namespace cutl private: void - init (std::string const&); + init (string_type const&); private: regex_type regex_; - std::string sub_; + string_type sub_; }; + typedef basic_regexsub regexsub; + typedef basic_regexsub wregexsub; + // Once-off regex execution. // + template inline bool - match (std::string const& s, std::string const& regex) + match (std::basic_string const& s, std::basic_string const& regex) { - re::regex r (regex); + basic_regex r (regex); return r.match (s); } + template inline bool - search (std::string const& s, std::string const& regex) + search (std::basic_string const& s, std::basic_string const& regex) { - re::regex r (regex); + basic_regex r (regex); return r.search (s); } - inline std::string - replace (std::string const& s, - std::string const& regex, - std::string const& sub, + template + inline std::basic_string + replace (std::basic_string const& s, + std::basic_string const& regex, + std::basic_string const& sub, bool first_only = false) { - re::regex r (regex); + basic_regex r (regex); return r.replace (s, sub, first_only); } - inline std::string - replace (std::string const& s, - std::string const& regexsub, // /regex/subst/ + template + inline std::basic_string + replace (std::basic_string const& s, + std::basic_string const& regexsub, // /regex/subst/ bool first_only = false) { - re::regexsub r (regexsub); + basic_regexsub r (regexsub); return r.replace (s, first_only); } @@ -234,11 +252,14 @@ namespace cutl // the unescaped chunk in result or throws the format exception if // the expression is invalid. // - LIBCUTL_EXPORT std::string::size_type - parse (std::string const& s, - std::string::size_type start, - std::string& result); + template + typename std::basic_string::size_type + parse (std::basic_string const& s, + typename std::basic_string::size_type start, + std::basic_string& result); } } +#include + #endif // CUTL_RE_HXX diff --git a/cutl/re/re.cxx b/cutl/re/re.cxx index 8a15158..8e46d59 100644 --- a/cutl/re/re.cxx +++ b/cutl/re/re.cxx @@ -2,8 +2,6 @@ // copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC // license : MIT; see accompanying LICENSE file -#include - #include #ifndef LIBCUTL_EXTERNAL_BOOST @@ -19,53 +17,83 @@ namespace cutl namespace re { // - // format + // format_base // - format:: - ~format () throw () + format_base:: + ~format_base () throw () { } - char const* format:: + char const* format_base:: what () const throw () { return description_.c_str (); } // - // regex + // basic_regex // - struct regex::impl + template + struct basic_regex::impl { + typedef basic_string string_type; + typedef tr1::basic_regex regex_type; + impl () {} - impl (string const& s): r (s, tr1::regex_constants::ECMAScript) {} - impl (tr1::regex const& r): r (r) {} + impl (string_type const& s): r (s, tr1::regex_constants::ECMAScript) {} + impl (regex_type const& r): r (r) {} - tr1::regex r; + regex_type r; }; - regex:: - ~regex () + template <> + basic_regex:: + ~basic_regex () { delete impl_; } - regex:: - regex (regex const& r) + template <> + basic_regex:: + ~basic_regex () + { + delete impl_; + } + + template <> + basic_regex:: + basic_regex (basic_regex const& r) : impl_ (new impl (r.impl_->r)) { } - regex& regex:: - operator= (regex const& r) + template <> + basic_regex:: + basic_regex (basic_regex const& r) + : impl_ (new impl (r.impl_->r)) + { + } + + template <> + basic_regex& basic_regex:: + operator= (basic_regex const& r) + { + impl_->r = r.impl_->r; + return *this; + } + + template <> + basic_regex& basic_regex:: + operator= (basic_regex const& r) { impl_->r = r.impl_->r; return *this; } - void regex:: - init (string const* s) + template <> + void basic_regex:: + init (string_type const* s) { try { @@ -76,24 +104,60 @@ namespace cutl } catch (tr1::regex_error const& e) { - throw format (s == 0 ? "" : *s, e.what ()); + throw basic_format (s == 0 ? "" : *s, e.what ()); } } - bool regex:: - match (string const& s) const + template <> + void basic_regex:: + init (string_type const* s) + { + try + { + if (impl_ == 0) + impl_ = s == 0 ? new impl : new impl (*s); + else + impl_->r = *s; + } + catch (tr1::regex_error const& e) + { + throw basic_format (s == 0 ? L"" : *s, e.what ()); + } + } + + template <> + bool basic_regex:: + match (string_type const& s) const + { + return tr1::regex_match (s, impl_->r); + } + + template <> + bool basic_regex:: + match (string_type const& s) const { return tr1::regex_match (s, impl_->r); } - bool regex:: - search (string const& s) const + template <> + bool basic_regex:: + search (string_type const& s) const + { + return tr1::regex_search (s, impl_->r); + } + + template <> + bool basic_regex:: + search (string_type const& s) const { return tr1::regex_search (s, impl_->r); } - string regex:: - replace (string const& s, string const& sub, bool first_only) const + template <> + string basic_regex:: + replace (string_type const& s, + string_type const& sub, + bool first_only) const { tr1::regex_constants::match_flag_type f ( tr1::regex_constants::format_default); @@ -101,78 +165,50 @@ namespace cutl if (first_only) f |= tr1::regex_constants::format_first_only; - return regex_replace (s, impl_->r, sub, f); + return tr1::regex_replace (s, impl_->r, sub, f); } - string regex:: - str () const + template <> + wstring basic_regex:: + replace (string_type const& s, + string_type const& sub, + bool first_only) const { - return impl_->r.str (); + tr1::regex_constants::match_flag_type f ( + tr1::regex_constants::format_default); + + if (first_only) + f |= tr1::regex_constants::format_first_only; + + return tr1::regex_replace (s, impl_->r, sub, f); } - bool regex:: - empty () const + template <> + string basic_regex:: + str () const { - return impl_->r.empty (); + return impl_->r.str (); } - ostream& - operator<< (ostream& os, regex const& r) + template <> + wstring basic_regex:: + str () const { - return os << r.str ().c_str (); + return impl_->r.str (); } - // - // regexsub - // - void regexsub:: - init (string const& s) + template <> + bool basic_regex:: + empty () const { - string r; - string::size_type p (parse (s, 0, r)); - regex_ = r; - p = parse (s, p, sub_); - if (p + 1 < s.size ()) - throw format (s, "junk after third delimiter"); + return impl_->r.empty (); } - // - // parse() - // - string::size_type - parse (string const& s, string::size_type p, string& r) + template <> + bool basic_regex:: + empty () const { - r.clear (); - string::size_type n (s.size ()); - - if (p >= n) - throw format (s, "empty expression"); - - char d (s[p++]); - - for (; p < n; ++p) - { - if (s[p] == d) - break; - - if (s[p] == '\\') - { - if (++p < n) - { - if (s[p] != d && s[p] != '\\') - r += '\\'; - r += s[p]; - } - // else {we ran out of stuff before finding the delimiter} - } - else - r += s[p]; - } - - if (p == n) - throw format (s, "missing closing delimiter"); - - return p; + return impl_->r.empty (); } } } diff --git a/cutl/re/re.txx b/cutl/re/re.txx new file mode 100644 index 0000000..9c4122b --- /dev/null +++ b/cutl/re/re.txx @@ -0,0 +1,69 @@ +// file : cutl/re/re.txx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +namespace cutl +{ + namespace re + { + // + // basic_regexsub + // + template + void basic_regexsub:: + init (string_type const& s) + { + string_type r; + typename string_type::size_type p (parse (s, 0, r)); + regex_ = r; + p = parse (s, p, sub_); + if (p + 1 < s.size ()) + throw basic_format (s, "junk after third delimiter"); + } + + // + // parse() + // + template + typename std::basic_string::size_type + parse (std::basic_string const& s, + typename std::basic_string::size_type p, + std::basic_string& r) + { + r.clear (); + typename std::basic_string::size_type n (s.size ()); + + if (p >= n) + throw basic_format (s, "empty expression"); + + char d (s[p++]); + + for (; p < n; ++p) + { + if (s[p] == d) + break; + + if (s[p] == '\\') + { + if (++p < n) + { + // Pass the escape sequence through unless it is the delimiter. + // + if (s[p] != d) + r += '\\'; + + r += s[p]; + } + // else {We ran out of stuff before finding the delimiter.} + } + else + r += s[p]; + } + + if (p == n) + throw basic_format (s, "missing closing delimiter"); + + return p; + } + } +} diff --git a/tests/re/driver.cxx b/tests/re/driver.cxx index 5ba8ba5..99ac014 100644 --- a/tests/re/driver.cxx +++ b/tests/re/driver.cxx @@ -62,7 +62,7 @@ main () // regexsub escaping // { - regexsub r ("#a\\#\\\\\\\\#a?\\\\\\\\#"); + regexsub r ("#a\\#\\\\#a?\\\\#"); assert (r.replace ("a#\\") == "a?\\"); } -- cgit v1.1