Rework RE2::Arg with templates instead of macros.
Bump SONAME accordingly.
Change-Id: Ic62e8de87dda68951c2a49715a826c8f42c2dbe3
Reviewed-on: https://code-review.googlesource.com/c/re2/+/57850
Reviewed-by: Paul Wankadia <junyer@google.com>
diff --git a/Makefile b/Makefile
index fe766d2..18f566f 100644
--- a/Makefile
+++ b/Makefile
@@ -44,7 +44,7 @@
# ABI version
# http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html
-SONAME=8
+SONAME=9
# To rebuild the Tables generated by Perl and Python scripts (requires Internet
# access for Unicode data), uncomment the following line:
diff --git a/re2/re2.cc b/re2/re2.cc
index 7ec193c..2a6381f 100644
--- a/re2/re2.cc
+++ b/re2/re2.cc
@@ -1040,41 +1040,49 @@
/***** Parsers for various types *****/
-bool RE2::Arg::parse_null(const char* str, size_t n, void* dest) {
+namespace internal {
+
+template <>
+bool Parse(const char* str, size_t n, void* dest) {
// We fail if somebody asked us to store into a non-NULL void* pointer
return (dest == NULL);
}
-bool RE2::Arg::parse_string(const char* str, size_t n, void* dest) {
+template <>
+bool Parse(const char* str, size_t n, std::string* dest) {
if (dest == NULL) return true;
- reinterpret_cast<std::string*>(dest)->assign(str, n);
+ dest->assign(str, n);
return true;
}
-bool RE2::Arg::parse_stringpiece(const char* str, size_t n, void* dest) {
+template <>
+bool Parse(const char* str, size_t n, StringPiece* dest) {
if (dest == NULL) return true;
- *(reinterpret_cast<StringPiece*>(dest)) = StringPiece(str, n);
+ *dest = StringPiece(str, n);
return true;
}
-bool RE2::Arg::parse_char(const char* str, size_t n, void* dest) {
+template <>
+bool Parse(const char* str, size_t n, char* dest) {
if (n != 1) return false;
if (dest == NULL) return true;
- *(reinterpret_cast<char*>(dest)) = str[0];
+ *dest = str[0];
return true;
}
-bool RE2::Arg::parse_schar(const char* str, size_t n, void* dest) {
+template <>
+bool Parse(const char* str, size_t n, signed char* dest) {
if (n != 1) return false;
if (dest == NULL) return true;
- *(reinterpret_cast<signed char*>(dest)) = str[0];
+ *dest = str[0];
return true;
}
-bool RE2::Arg::parse_uchar(const char* str, size_t n, void* dest) {
+template <>
+bool Parse(const char* str, size_t n, unsigned char* dest) {
if (n != 1) return false;
if (dest == NULL) return true;
- *(reinterpret_cast<unsigned char*>(dest)) = str[0];
+ *dest = str[0];
return true;
}
@@ -1138,10 +1146,40 @@
return buf;
}
-bool RE2::Arg::parse_long_radix(const char* str,
- size_t n,
- void* dest,
- int radix) {
+template <>
+bool Parse(const char* str, size_t n, float* dest) {
+ if (n == 0) return false;
+ static const int kMaxLength = 200;
+ char buf[kMaxLength+1];
+ str = TerminateNumber(buf, sizeof buf, str, &n, true);
+ char* end;
+ errno = 0;
+ float r = strtof(str, &end);
+ if (end != str + n) return false; // Leftover junk
+ if (errno) return false;
+ if (dest == NULL) return true;
+ *dest = r;
+ return true;
+}
+
+template <>
+bool Parse(const char* str, size_t n, double* dest) {
+ if (n == 0) return false;
+ static const int kMaxLength = 200;
+ char buf[kMaxLength+1];
+ str = TerminateNumber(buf, sizeof buf, str, &n, true);
+ char* end;
+ errno = 0;
+ double r = strtod(str, &end);
+ if (end != str + n) return false; // Leftover junk
+ if (errno) return false;
+ if (dest == NULL) return true;
+ *dest = r;
+ return true;
+}
+
+template <>
+bool Parse(const char* str, size_t n, long* dest, int radix) {
if (n == 0) return false;
char buf[kMaxNumberLength+1];
str = TerminateNumber(buf, sizeof buf, str, &n, false);
@@ -1151,14 +1189,12 @@
if (end != str + n) return false; // Leftover junk
if (errno) return false;
if (dest == NULL) return true;
- *(reinterpret_cast<long*>(dest)) = r;
+ *dest = r;
return true;
}
-bool RE2::Arg::parse_ulong_radix(const char* str,
- size_t n,
- void* dest,
- int radix) {
+template <>
+bool Parse(const char* str, size_t n, unsigned long* dest, int radix) {
if (n == 0) return false;
char buf[kMaxNumberLength+1];
str = TerminateNumber(buf, sizeof buf, str, &n, false);
@@ -1174,62 +1210,52 @@
if (end != str + n) return false; // Leftover junk
if (errno) return false;
if (dest == NULL) return true;
- *(reinterpret_cast<unsigned long*>(dest)) = r;
+ *dest = r;
return true;
}
-bool RE2::Arg::parse_short_radix(const char* str,
- size_t n,
- void* dest,
- int radix) {
+template <>
+bool Parse(const char* str, size_t n, short* dest, int radix) {
long r;
- if (!parse_long_radix(str, n, &r, radix)) return false; // Could not parse
- if ((short)r != r) return false; // Out of range
+ if (!Parse(str, n, &r, radix)) return false; // Could not parse
+ if ((short)r != r) return false; // Out of range
if (dest == NULL) return true;
- *(reinterpret_cast<short*>(dest)) = (short)r;
+ *dest = (short)r;
return true;
}
-bool RE2::Arg::parse_ushort_radix(const char* str,
- size_t n,
- void* dest,
- int radix) {
+template <>
+bool Parse(const char* str, size_t n, unsigned short* dest, int radix) {
unsigned long r;
- if (!parse_ulong_radix(str, n, &r, radix)) return false; // Could not parse
- if ((unsigned short)r != r) return false; // Out of range
+ if (!Parse(str, n, &r, radix)) return false; // Could not parse
+ if ((unsigned short)r != r) return false; // Out of range
if (dest == NULL) return true;
- *(reinterpret_cast<unsigned short*>(dest)) = (unsigned short)r;
+ *dest = (unsigned short)r;
return true;
}
-bool RE2::Arg::parse_int_radix(const char* str,
- size_t n,
- void* dest,
- int radix) {
+template <>
+bool Parse(const char* str, size_t n, int* dest, int radix) {
long r;
- if (!parse_long_radix(str, n, &r, radix)) return false; // Could not parse
- if ((int)r != r) return false; // Out of range
+ if (!Parse(str, n, &r, radix)) return false; // Could not parse
+ if ((int)r != r) return false; // Out of range
if (dest == NULL) return true;
- *(reinterpret_cast<int*>(dest)) = (int)r;
+ *dest = (int)r;
return true;
}
-bool RE2::Arg::parse_uint_radix(const char* str,
- size_t n,
- void* dest,
- int radix) {
+template <>
+bool Parse(const char* str, size_t n, unsigned int* dest, int radix) {
unsigned long r;
- if (!parse_ulong_radix(str, n, &r, radix)) return false; // Could not parse
- if ((unsigned int)r != r) return false; // Out of range
+ if (!Parse(str, n, &r, radix)) return false; // Could not parse
+ if ((unsigned int)r != r) return false; // Out of range
if (dest == NULL) return true;
- *(reinterpret_cast<unsigned int*>(dest)) = (unsigned int)r;
+ *dest = (unsigned int)r;
return true;
}
-bool RE2::Arg::parse_longlong_radix(const char* str,
- size_t n,
- void* dest,
- int radix) {
+template <>
+bool Parse(const char* str, size_t n, long long* dest, int radix) {
if (n == 0) return false;
char buf[kMaxNumberLength+1];
str = TerminateNumber(buf, sizeof buf, str, &n, false);
@@ -1239,14 +1265,12 @@
if (end != str + n) return false; // Leftover junk
if (errno) return false;
if (dest == NULL) return true;
- *(reinterpret_cast<long long*>(dest)) = r;
+ *dest = r;
return true;
}
-bool RE2::Arg::parse_ulonglong_radix(const char* str,
- size_t n,
- void* dest,
- int radix) {
+template <>
+bool Parse(const char* str, size_t n, unsigned long long* dest, int radix) {
if (n == 0) return false;
char buf[kMaxNumberLength+1];
str = TerminateNumber(buf, sizeof buf, str, &n, false);
@@ -1261,68 +1285,11 @@
if (end != str + n) return false; // Leftover junk
if (errno) return false;
if (dest == NULL) return true;
- *(reinterpret_cast<unsigned long long*>(dest)) = r;
+ *dest = r;
return true;
}
-static bool parse_double_float(const char* str, size_t n, bool isfloat,
- void* dest) {
- if (n == 0) return false;
- static const int kMaxLength = 200;
- char buf[kMaxLength+1];
- str = TerminateNumber(buf, sizeof buf, str, &n, true);
- char* end;
- errno = 0;
- double r;
- if (isfloat) {
- r = strtof(str, &end);
- } else {
- r = strtod(str, &end);
- }
- if (end != str + n) return false; // Leftover junk
- if (errno) return false;
- if (dest == NULL) return true;
- if (isfloat) {
- *(reinterpret_cast<float*>(dest)) = (float)r;
- } else {
- *(reinterpret_cast<double*>(dest)) = r;
- }
- return true;
-}
-
-bool RE2::Arg::parse_double(const char* str, size_t n, void* dest) {
- return parse_double_float(str, n, false, dest);
-}
-
-bool RE2::Arg::parse_float(const char* str, size_t n, void* dest) {
- return parse_double_float(str, n, true, dest);
-}
-
-#define DEFINE_INTEGER_PARSER(name) \
- bool RE2::Arg::parse_##name(const char* str, size_t n, void* dest) { \
- return parse_##name##_radix(str, n, dest, 10); \
- } \
- bool RE2::Arg::parse_##name##_hex(const char* str, size_t n, void* dest) { \
- return parse_##name##_radix(str, n, dest, 16); \
- } \
- bool RE2::Arg::parse_##name##_octal(const char* str, size_t n, void* dest) { \
- return parse_##name##_radix(str, n, dest, 8); \
- } \
- bool RE2::Arg::parse_##name##_cradix(const char* str, size_t n, \
- void* dest) { \
- return parse_##name##_radix(str, n, dest, 0); \
- }
-
-DEFINE_INTEGER_PARSER(short)
-DEFINE_INTEGER_PARSER(ushort)
-DEFINE_INTEGER_PARSER(int)
-DEFINE_INTEGER_PARSER(uint)
-DEFINE_INTEGER_PARSER(long)
-DEFINE_INTEGER_PARSER(ulong)
-DEFINE_INTEGER_PARSER(longlong)
-DEFINE_INTEGER_PARSER(ulonglong)
-
-#undef DEFINE_INTEGER_PARSER
+} // namespace internal
namespace hooks {
diff --git a/re2/re2.h b/re2/re2.h
index 89f4fbb..2197b3f 100644
--- a/re2/re2.h
+++ b/re2/re2.h
@@ -208,6 +208,7 @@
#include <map>
#include <mutex>
#include <string>
+#include <type_traits>
#include <vector>
#if defined(__APPLE__)
@@ -734,32 +735,12 @@
const Options& options() const { return options_; }
// Argument converters; see below.
- static inline Arg CRadix(short* x);
- static inline Arg CRadix(unsigned short* x);
- static inline Arg CRadix(int* x);
- static inline Arg CRadix(unsigned int* x);
- static inline Arg CRadix(long* x);
- static inline Arg CRadix(unsigned long* x);
- static inline Arg CRadix(long long* x);
- static inline Arg CRadix(unsigned long long* x);
-
- static inline Arg Hex(short* x);
- static inline Arg Hex(unsigned short* x);
- static inline Arg Hex(int* x);
- static inline Arg Hex(unsigned int* x);
- static inline Arg Hex(long* x);
- static inline Arg Hex(unsigned long* x);
- static inline Arg Hex(long long* x);
- static inline Arg Hex(unsigned long long* x);
-
- static inline Arg Octal(short* x);
- static inline Arg Octal(unsigned short* x);
- static inline Arg Octal(int* x);
- static inline Arg Octal(unsigned int* x);
- static inline Arg Octal(long* x);
- static inline Arg Octal(unsigned long* x);
- static inline Arg Octal(long long* x);
- static inline Arg Octal(unsigned long long* x);
+ template <typename T>
+ static Arg CRadix(T* ptr);
+ template <typename T>
+ static Arg Hex(T* ptr);
+ template <typename T>
+ static Arg Octal(T* ptr);
private:
void Init(const StringPiece& pattern, const Options& options);
@@ -802,130 +783,106 @@
/***** Implementation details *****/
-// Hex/Octal/Binary?
+namespace internal {
-// Special class for parsing into objects that define a ParseFrom() method
+// Types for which the 3-ary Parse() function template has specializations.
+template <typename T> struct Parse3ary : public std::false_type {};
+template <> struct Parse3ary<void> : public std::true_type {};
+template <> struct Parse3ary<std::string> : public std::true_type {};
+template <> struct Parse3ary<StringPiece> : public std::true_type {};
+template <> struct Parse3ary<char> : public std::true_type {};
+template <> struct Parse3ary<signed char> : public std::true_type {};
+template <> struct Parse3ary<unsigned char> : public std::true_type {};
+template <> struct Parse3ary<float> : public std::true_type {};
+template <> struct Parse3ary<double> : public std::true_type {};
+
template <typename T>
-class _RE2_MatchObject {
- public:
- static inline bool Parse(const char* str, size_t n, void* dest) {
- if (dest == NULL) return true;
- T* object = reinterpret_cast<T*>(dest);
- return object->ParseFrom(str, n);
- }
-};
+bool Parse(const char* str, size_t n, T* dest);
+
+// Types for which the 4-ary Parse() function template has specializations.
+template <typename T> struct Parse4ary : public std::false_type {};
+template <> struct Parse4ary<long> : public std::true_type {};
+template <> struct Parse4ary<unsigned long> : public std::true_type {};
+template <> struct Parse4ary<short> : public std::true_type {};
+template <> struct Parse4ary<unsigned short> : public std::true_type {};
+template <> struct Parse4ary<int> : public std::true_type {};
+template <> struct Parse4ary<unsigned int> : public std::true_type {};
+template <> struct Parse4ary<long long> : public std::true_type {};
+template <> struct Parse4ary<unsigned long long> : public std::true_type {};
+
+template <typename T>
+bool Parse(const char* str, size_t n, T* dest, int radix);
+
+} // namespace internal
class RE2::Arg {
public:
- // Empty constructor so we can declare arrays of RE2::Arg
- Arg();
+ Arg() : Arg(nullptr) {}
+ Arg(std::nullptr_t ptr)
+ : arg_(ptr), parser_([](const char* str, size_t n, void* dest) -> bool {
+ return true;
+ }) {}
- // Constructor specially designed for NULL arguments
- Arg(void*);
- Arg(std::nullptr_t);
+ template <typename T,
+ typename std::enable_if<internal::Parse3ary<T>::value,
+ int>::type = 0>
+ Arg(T* ptr)
+ : arg_(ptr), parser_([](const char* str, size_t n, void* dest) -> bool {
+ return internal::Parse(str, n, reinterpret_cast<T*>(dest));
+ }) {}
+
+ template <typename T,
+ typename std::enable_if<internal::Parse4ary<T>::value,
+ int>::type = 0>
+ Arg(T* ptr)
+ : arg_(ptr), parser_([](const char* str, size_t n, void* dest) -> bool {
+ return internal::Parse(str, n, reinterpret_cast<T*>(dest), 10);
+ }) {}
+
+ template <typename T,
+ typename std::enable_if<!(internal::Parse3ary<T>::value ||
+ internal::Parse4ary<T>::value),
+ int>::type = 0>
+ Arg(T* ptr)
+ : arg_(ptr), parser_([](const char* str, size_t n, void* dest) -> bool {
+ if (dest == NULL) return true;
+ return reinterpret_cast<T*>(dest)->ParseFrom(str, n);
+ }) {}
typedef bool (*Parser)(const char* str, size_t n, void* dest);
-// Type-specific parsers
-#define MAKE_PARSER(type, name) \
- Arg(type* p) : arg_(p), parser_(name) {} \
- Arg(type* p, Parser parser) : arg_(p), parser_(parser) {}
+ template <typename T>
+ Arg(T* ptr, Parser parser) : arg_(ptr), parser_(parser) {}
- MAKE_PARSER(char, parse_char)
- MAKE_PARSER(signed char, parse_schar)
- MAKE_PARSER(unsigned char, parse_uchar)
- MAKE_PARSER(float, parse_float)
- MAKE_PARSER(double, parse_double)
- MAKE_PARSER(std::string, parse_string)
- MAKE_PARSER(StringPiece, parse_stringpiece)
-
- MAKE_PARSER(short, parse_short)
- MAKE_PARSER(unsigned short, parse_ushort)
- MAKE_PARSER(int, parse_int)
- MAKE_PARSER(unsigned int, parse_uint)
- MAKE_PARSER(long, parse_long)
- MAKE_PARSER(unsigned long, parse_ulong)
- MAKE_PARSER(long long, parse_longlong)
- MAKE_PARSER(unsigned long long, parse_ulonglong)
-
-#undef MAKE_PARSER
-
- // Generic constructor templates
- template <typename T> Arg(T* p)
- : arg_(p), parser_(_RE2_MatchObject<T>::Parse) { }
- template <typename T> Arg(T* p, Parser parser)
- : arg_(p), parser_(parser) { }
-
- // Parse the data
- bool Parse(const char* str, size_t n) const;
+ bool Parse(const char* str, size_t n) const {
+ return (*parser_)(str, n, arg_);
+ }
private:
void* arg_;
Parser parser_;
-
- static bool parse_null (const char* str, size_t n, void* dest);
- static bool parse_char (const char* str, size_t n, void* dest);
- static bool parse_schar (const char* str, size_t n, void* dest);
- static bool parse_uchar (const char* str, size_t n, void* dest);
- static bool parse_float (const char* str, size_t n, void* dest);
- static bool parse_double (const char* str, size_t n, void* dest);
- static bool parse_string (const char* str, size_t n, void* dest);
- static bool parse_stringpiece (const char* str, size_t n, void* dest);
-
-#define DECLARE_INTEGER_PARSER(name) \
- private: \
- static bool parse_##name(const char* str, size_t n, void* dest); \
- static bool parse_##name##_radix(const char* str, size_t n, void* dest, \
- int radix); \
- \
- public: \
- static bool parse_##name##_hex(const char* str, size_t n, void* dest); \
- static bool parse_##name##_octal(const char* str, size_t n, void* dest); \
- static bool parse_##name##_cradix(const char* str, size_t n, void* dest);
-
- DECLARE_INTEGER_PARSER(short)
- DECLARE_INTEGER_PARSER(ushort)
- DECLARE_INTEGER_PARSER(int)
- DECLARE_INTEGER_PARSER(uint)
- DECLARE_INTEGER_PARSER(long)
- DECLARE_INTEGER_PARSER(ulong)
- DECLARE_INTEGER_PARSER(longlong)
- DECLARE_INTEGER_PARSER(ulonglong)
-
-#undef DECLARE_INTEGER_PARSER
-
};
-inline RE2::Arg::Arg() : arg_(NULL), parser_(parse_null) { }
-inline RE2::Arg::Arg(void* p) : arg_(p), parser_(parse_null) { }
-inline RE2::Arg::Arg(std::nullptr_t p) : arg_(p), parser_(parse_null) { }
-
-inline bool RE2::Arg::Parse(const char* str, size_t n) const {
- return (*parser_)(str, n, arg_);
+template <typename T>
+inline RE2::Arg RE2::CRadix(T* ptr) {
+ return RE2::Arg(ptr, [](const char* str, size_t n, void* dest) -> bool {
+ return internal::Parse(str, n, reinterpret_cast<T*>(dest), 0);
+ });
}
-// This part of the parser, appropriate only for ints, deals with bases
-#define MAKE_INTEGER_PARSER(type, name) \
- inline RE2::Arg RE2::Hex(type* ptr) { \
- return RE2::Arg(ptr, RE2::Arg::parse_##name##_hex); \
- } \
- inline RE2::Arg RE2::Octal(type* ptr) { \
- return RE2::Arg(ptr, RE2::Arg::parse_##name##_octal); \
- } \
- inline RE2::Arg RE2::CRadix(type* ptr) { \
- return RE2::Arg(ptr, RE2::Arg::parse_##name##_cradix); \
- }
+template <typename T>
+inline RE2::Arg RE2::Hex(T* ptr) {
+ return RE2::Arg(ptr, [](const char* str, size_t n, void* dest) -> bool {
+ return internal::Parse(str, n, reinterpret_cast<T*>(dest), 16);
+ });
+}
-MAKE_INTEGER_PARSER(short, short)
-MAKE_INTEGER_PARSER(unsigned short, ushort)
-MAKE_INTEGER_PARSER(int, int)
-MAKE_INTEGER_PARSER(unsigned int, uint)
-MAKE_INTEGER_PARSER(long, long)
-MAKE_INTEGER_PARSER(unsigned long, ulong)
-MAKE_INTEGER_PARSER(long long, longlong)
-MAKE_INTEGER_PARSER(unsigned long long, ulonglong)
-
-#undef MAKE_INTEGER_PARSER
+template <typename T>
+inline RE2::Arg RE2::Octal(T* ptr) {
+ return RE2::Arg(ptr, [](const char* str, size_t n, void* dest) -> bool {
+ return internal::Parse(str, n, reinterpret_cast<T*>(dest), 8);
+ });
+}
#ifndef SWIG
// Silence warnings about missing initializers for members of LazyRE2.
diff --git a/re2/testing/re2_arg_test.cc b/re2/testing/re2_arg_test.cc
index 7a38de7..a82f033 100644
--- a/re2/testing/re2_arg_test.cc
+++ b/re2/testing/re2_arg_test.cc
@@ -132,4 +132,24 @@
PARSE_FOR_TYPE(uint64_t, 5);
}
+TEST(RE2ArgTest, ParseFromTest) {
+ struct {
+ bool ParseFrom(const char* str, size_t n) {
+ LOG(INFO) << "str = " << str << ", n = " << n;
+ return true;
+ }
+ } obj1;
+ RE2::Arg arg1(&obj1);
+ EXPECT_TRUE(arg1.Parse("one", 3));
+
+ struct {
+ bool ParseFrom(const char* str, size_t n) {
+ LOG(INFO) << "str = " << str << ", n = " << n;
+ return false;
+ }
+ } obj2;
+ RE2::Arg arg2(&obj2);
+ EXPECT_FALSE(arg2.Parse("two", 3));
+}
+
} // namespace re2