From b55a20fa2c669b181f47ea9219b8e74d1263da19 Mon Sep 17 00:00:00 2001 From: "xiaofeng@google.com" Date: Sat, 22 Sep 2012 02:40:50 +0000 Subject: Down-integrate from internal branch --- src/google/protobuf/stubs/common.cc | 18 + src/google/protobuf/stubs/common.h | 35 +- src/google/protobuf/stubs/hash.h | 12 + src/google/protobuf/stubs/map-util.h | 24 + src/google/protobuf/stubs/stl_util.h | 121 ++++ src/google/protobuf/stubs/stringprintf.cc | 170 ++++++ src/google/protobuf/stubs/stringprintf.h | 76 +++ src/google/protobuf/stubs/stringprintf_unittest.cc | 152 +++++ src/google/protobuf/stubs/strutil.cc | 38 ++ src/google/protobuf/stubs/strutil.h | 14 +- src/google/protobuf/stubs/substitute.cc | 2 +- src/google/protobuf/stubs/template_util.h | 138 +++++ .../protobuf/stubs/template_util_unittest.cc | 130 +++++ src/google/protobuf/stubs/type_traits.h | 346 +++++++++++ src/google/protobuf/stubs/type_traits_unittest.cc | 647 +++++++++++++++++++++ 15 files changed, 1909 insertions(+), 14 deletions(-) create mode 100644 src/google/protobuf/stubs/stl_util.h create mode 100644 src/google/protobuf/stubs/stringprintf.cc create mode 100644 src/google/protobuf/stubs/stringprintf.h create mode 100644 src/google/protobuf/stubs/stringprintf_unittest.cc create mode 100644 src/google/protobuf/stubs/template_util.h create mode 100644 src/google/protobuf/stubs/template_util_unittest.cc create mode 100644 src/google/protobuf/stubs/type_traits.h create mode 100644 src/google/protobuf/stubs/type_traits_unittest.cc (limited to 'src/google/protobuf/stubs') diff --git a/src/google/protobuf/stubs/common.cc b/src/google/protobuf/stubs/common.cc index 7b15be44..16d78528 100644 --- a/src/google/protobuf/stubs/common.cc +++ b/src/google/protobuf/stubs/common.cc @@ -319,6 +319,24 @@ void Mutex::AssertHeld() { #endif +// =================================================================== +// emulates google3/util/endian/endian.h +// +// TODO(xiaofeng): PROTOBUF_LITTLE_ENDIAN is unfortunately defined in +// google/protobuf/io/coded_stream.h and therefore can not be used here. +// Maybe move that macro definition here in the furture. +uint32 ghtonl(uint32 x) { + union { + uint32 result; + uint8 result_array[4]; + }; + result_array[0] = static_cast(x >> 24); + result_array[1] = static_cast((x >> 16) & 0xFF); + result_array[2] = static_cast((x >> 8) & 0xFF); + result_array[3] = static_cast(x & 0xFF); + return result; +} + // =================================================================== // Shutdown support. diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h index 7f5fd4d2..07ae5307 100644 --- a/src/google/protobuf/stubs/common.h +++ b/src/google/protobuf/stubs/common.h @@ -341,6 +341,12 @@ inline To down_cast(From* f) { // so we only accept pointers return static_cast(f); } +// Simplified down_cast for reference type. +template +inline To down_cast(From& f) { + return static_cast(f); +} + } // namespace internal // We made these internal so that they would show up as such in the docs, @@ -686,6 +692,7 @@ class LIBPROTOBUF_EXPORT LogFinisher { #undef GOOGLE_CHECK_LE #undef GOOGLE_CHECK_GT #undef GOOGLE_CHECK_GE +#undef GOOGLE_CHECK_NOTNULL #undef GOOGLE_DLOG #undef GOOGLE_DCHECK @@ -712,6 +719,18 @@ class LIBPROTOBUF_EXPORT LogFinisher { #define GOOGLE_CHECK_GT(A, B) GOOGLE_CHECK((A) > (B)) #define GOOGLE_CHECK_GE(A, B) GOOGLE_CHECK((A) >= (B)) +namespace internal { +template +T* CheckNotNull(const char *file, int line, const char *name, T* val) { + if (val == NULL) { + GOOGLE_LOG(FATAL) << name; + } + return val; +} +} // namespace internal +#define GOOGLE_CHECK_NOTNULL(A) \ + internal::CheckNotNull(__FILE__, __LINE__, "'" #A "' must not be NULL", (A)) + #ifdef NDEBUG #define GOOGLE_DLOG GOOGLE_LOG_IF(INFO, false) @@ -1136,26 +1155,20 @@ using internal::WriterMutexLock; using internal::MutexLockMaybe; // =================================================================== -// from google3/base/type_traits.h +// from google3/util/utf8/public/unilib.h namespace internal { -// Specified by TR1 [4.7.4] Pointer modifications. -template struct remove_pointer { typedef T type; }; -template struct remove_pointer { typedef T type; }; -template struct remove_pointer { typedef T type; }; -template struct remove_pointer { typedef T type; }; -template struct remove_pointer { - typedef T type; }; - -// =================================================================== - // Checks if the buffer contains structurally-valid UTF-8. Implemented in // structurally_valid.cc. LIBPROTOBUF_EXPORT bool IsStructurallyValidUTF8(const char* buf, int len); } // namespace internal +// =================================================================== +// from google3/util/endian/endian.h +LIBPROTOBUF_EXPORT uint32 ghtonl(uint32 x); + // =================================================================== // Shutdown support. diff --git a/src/google/protobuf/stubs/hash.h b/src/google/protobuf/stubs/hash.h index 822d6050..f7d10712 100644 --- a/src/google/protobuf/stubs/hash.h +++ b/src/google/protobuf/stubs/hash.h @@ -90,12 +90,16 @@ template , typename EqualKey = int > class hash_map : public std::map { + public: + hash_map(int = 0) {} }; template , typename EqualKey = int > class hash_set : public std::set { + public: + hash_set(int = 0) {} }; #elif defined(_MSC_VER) && !defined(_STLPORT_VERSION) @@ -123,6 +127,8 @@ template class hash_map : public HASH_NAMESPACE::hash_map< Key, Data, HashFcn> { + public: + hash_map(int = 0) {} }; template class hash_set : public HASH_NAMESPACE::hash_set< Key, HashFcn> { + public: + hash_set(int = 0) {} }; #else @@ -163,6 +171,8 @@ template > class hash_map : public HASH_NAMESPACE::HASH_MAP_CLASS< Key, Data, HashFcn, EqualKey> { + public: + hash_map(int = 0) {} }; template > class hash_set : public HASH_NAMESPACE::HASH_SET_CLASS< Key, HashFcn, EqualKey> { + public: + hash_set(int = 0) {} }; #endif diff --git a/src/google/protobuf/stubs/map-util.h b/src/google/protobuf/stubs/map-util.h index f5c9d6b6..775848b9 100644 --- a/src/google/protobuf/stubs/map-util.h +++ b/src/google/protobuf/stubs/map-util.h @@ -68,6 +68,30 @@ FindOrNull(const Collection& collection, return &it->second; } +// Perform a lookup in a map or hash_map, assuming that the key exists. +// Crash if it does not. +// +// This is intended as a replacement for operator[] as an rvalue (for reading) +// when the key is guaranteed to exist. +// +// operator[] is discouraged for several reasons: +// * It has a side-effect of inserting missing keys +// * It is not thread-safe (even when it is not inserting, it can still +// choose to resize the underlying storage) +// * It invalidates iterators (when it chooses to resize) +// * It default constructs a value object even if it doesn't need to +// +// This version assumes the key is printable, and includes it in the fatal log +// message. +template +const typename Collection::value_type::second_type& +FindOrDie(const Collection& collection, + const typename Collection::value_type::first_type& key) { + typename Collection::const_iterator it = collection.find(key); + GOOGLE_CHECK(it != collection.end()) << "Map key not found: " << key; + return it->second; +} + // Perform a lookup in a map or hash_map whose values are pointers. // If the key is present a const pointer to the associated value is returned, // otherwise a NULL pointer is returned. diff --git a/src/google/protobuf/stubs/stl_util.h b/src/google/protobuf/stubs/stl_util.h new file mode 100644 index 00000000..9021dada --- /dev/null +++ b/src/google/protobuf/stubs/stl_util.h @@ -0,0 +1,121 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// from google3/util/gtl/stl_util.h + +#ifndef GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__ +#define GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__ + +#include + +namespace google { +namespace protobuf { + +// STLDeleteContainerPointers() +// For a range within a container of pointers, calls delete +// (non-array version) on these pointers. +// NOTE: for these three functions, we could just implement a DeleteObject +// functor and then call for_each() on the range and functor, but this +// requires us to pull in all of algorithm.h, which seems expensive. +// For hash_[multi]set, it is important that this deletes behind the iterator +// because the hash_set may call the hash function on the iterator when it is +// advanced, which could result in the hash function trying to deference a +// stale pointer. +template +void STLDeleteContainerPointers(ForwardIterator begin, + ForwardIterator end) { + while (begin != end) { + ForwardIterator temp = begin; + ++begin; + delete *temp; + } +} + +// Inside Google, this function implements a horrible, disgusting hack in which +// we reach into the string's private implementation and resize it without +// initializing the new bytes. In some cases doing this can significantly +// improve performance. However, since it's totally non-portable it has no +// place in open source code. Feel free to fill this function in with your +// own disgusting hack if you want the perf boost. +inline void STLStringResizeUninitialized(string* s, size_t new_size) { + s->resize(new_size); +} + +// Return a mutable char* pointing to a string's internal buffer, +// which may not be null-terminated. Writing through this pointer will +// modify the string. +// +// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the +// next call to a string method that invalidates iterators. +// +// As of 2006-04, there is no standard-blessed way of getting a +// mutable reference to a string's internal buffer. However, issue 530 +// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530) +// proposes this as the method. According to Matt Austern, this should +// already work on all current implementations. +inline char* string_as_array(string* str) { + // DO NOT USE const_cast(str->data())! See the unittest for why. + return str->empty() ? NULL : &*str->begin(); +} + +// STLDeleteElements() deletes all the elements in an STL container and clears +// the container. This function is suitable for use with a vector, set, +// hash_set, or any other STL container which defines sensible begin(), end(), +// and clear() methods. +// +// If container is NULL, this function is a no-op. +// +// As an alternative to calling STLDeleteElements() directly, consider +// ElementDeleter (defined below), which ensures that your container's elements +// are deleted when the ElementDeleter goes out of scope. +template +void STLDeleteElements(T *container) { + if (!container) return; + STLDeleteContainerPointers(container->begin(), container->end()); + container->clear(); +} + +// Given an STL container consisting of (key, value) pairs, STLDeleteValues +// deletes all the "value" components and clears the container. Does nothing +// in the case it's given a NULL pointer. + +template +void STLDeleteValues(T *v) { + if (!v) return; + for (typename T::iterator i = v->begin(); i != v->end(); ++i) { + delete i->second; + } + v->clear(); +} + +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__ diff --git a/src/google/protobuf/stubs/stringprintf.cc b/src/google/protobuf/stubs/stringprintf.cc new file mode 100644 index 00000000..d66a497a --- /dev/null +++ b/src/google/protobuf/stubs/stringprintf.cc @@ -0,0 +1,170 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// from google3/base/stringprintf.cc + +#include + +#include +#include // For va_list and related operations +#include // MSVC requires this for _vsnprintf +#include +#include +#include + +namespace google { +namespace protobuf { + +#ifdef _MSC_VER +enum { IS_COMPILER_MSVC = 1 }; +#else +enum { IS_COMPILER_MSVC = 0 }; +#endif + +void StringAppendV(string* dst, const char* format, va_list ap) { + // First try with a small fixed size buffer + static const int kSpaceLength = 1024; + char space[kSpaceLength]; + + // It's possible for methods that use a va_list to invalidate + // the data in it upon use. The fix is to make a copy + // of the structure before using it and use that copy instead. + va_list backup_ap; + va_copy(backup_ap, ap); + int result = vsnprintf(space, kSpaceLength, format, backup_ap); + va_end(backup_ap); + + if (result < kSpaceLength) { + if (result >= 0) { + // Normal case -- everything fit. + dst->append(space, result); + return; + } + + if (IS_COMPILER_MSVC) { + // Error or MSVC running out of space. MSVC 8.0 and higher + // can be asked about space needed with the special idiom below: + va_copy(backup_ap, ap); + result = vsnprintf(NULL, 0, format, backup_ap); + va_end(backup_ap); + } + + if (result < 0) { + // Just an error. + return; + } + } + + // Increase the buffer size to the size requested by vsnprintf, + // plus one for the closing \0. + int length = result+1; + char* buf = new char[length]; + + // Restore the va_list before we use it again + va_copy(backup_ap, ap); + result = vsnprintf(buf, length, format, backup_ap); + va_end(backup_ap); + + if (result >= 0 && result < length) { + // It fit + dst->append(buf, result); + } + delete[] buf; +} + + +string StringPrintf(const char* format, ...) { + va_list ap; + va_start(ap, format); + string result; + StringAppendV(&result, format, ap); + va_end(ap); + return result; +} + +const string& SStringPrintf(string* dst, const char* format, ...) { + va_list ap; + va_start(ap, format); + dst->clear(); + StringAppendV(dst, format, ap); + va_end(ap); + return *dst; +} + +void StringAppendF(string* dst, const char* format, ...) { + va_list ap; + va_start(ap, format); + StringAppendV(dst, format, ap); + va_end(ap); +} + +// Max arguments supported by StringPrintVector +const int kStringPrintfVectorMaxArgs = 32; + +// An empty block of zero for filler arguments. This is const so that if +// printf tries to write to it (via %n) then the program gets a SIGSEGV +// and we can fix the problem or protect against an attack. +static const char string_printf_empty_block[256] = { '\0' }; + +string StringPrintfVector(const char* format, const vector& v) { + GOOGLE_CHECK_LE(v.size(), kStringPrintfVectorMaxArgs) + << "StringPrintfVector currently only supports up to " + << kStringPrintfVectorMaxArgs << " arguments. " + << "Feel free to add support for more if you need it."; + + // Add filler arguments so that bogus format+args have a harder time + // crashing the program, corrupting the program (%n), + // or displaying random chunks of memory to users. + + const char* cstr[kStringPrintfVectorMaxArgs]; + for (int i = 0; i < v.size(); ++i) { + cstr[i] = v[i].c_str(); + } + for (int i = v.size(); i < GOOGLE_ARRAYSIZE(cstr); ++i) { + cstr[i] = &string_printf_empty_block[0]; + } + + // I do not know any way to pass kStringPrintfVectorMaxArgs arguments, + // or any way to build a va_list by hand, or any API for printf + // that accepts an array of arguments. The best I can do is stick + // this COMPILE_ASSERT right next to the actual statement. + + GOOGLE_COMPILE_ASSERT(kStringPrintfVectorMaxArgs == 32, arg_count_mismatch); + return StringPrintf(format, + cstr[0], cstr[1], cstr[2], cstr[3], cstr[4], + cstr[5], cstr[6], cstr[7], cstr[8], cstr[9], + cstr[10], cstr[11], cstr[12], cstr[13], cstr[14], + cstr[15], cstr[16], cstr[17], cstr[18], cstr[19], + cstr[20], cstr[21], cstr[22], cstr[23], cstr[24], + cstr[25], cstr[26], cstr[27], cstr[28], cstr[29], + cstr[30], cstr[31]); +} +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/stubs/stringprintf.h b/src/google/protobuf/stubs/stringprintf.h new file mode 100644 index 00000000..573f30f3 --- /dev/null +++ b/src/google/protobuf/stubs/stringprintf.h @@ -0,0 +1,76 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// from google3/base/stringprintf.h +// +// Printf variants that place their output in a C++ string. +// +// Usage: +// string result = StringPrintf("%d %s\n", 10, "hello"); +// SStringPrintf(&result, "%d %s\n", 10, "hello"); +// StringAppendF(&result, "%d %s\n", 20, "there"); + +#ifndef GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H +#define GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H + +#include +#include +#include + +#include + +namespace google { +namespace protobuf { + +// Return a C++ string +extern string StringPrintf(const char* format, ...); + +// Store result into a supplied string and return it +extern const string& SStringPrintf(string* dst, const char* format, ...); + +// Append result to a supplied string +extern void StringAppendF(string* dst, const char* format, ...); + +// Lower-level routine that takes a va_list and appends to a specified +// string. All other routines are just convenience wrappers around it. +extern void StringAppendV(string* dst, const char* format, va_list ap); + +// The max arguments supported by StringPrintfVector +extern const int kStringPrintfVectorMaxArgs; + +// You can use this version when all your arguments are strings, but +// you don't know how many arguments you'll have at compile time. +// StringPrintfVector will LOG(FATAL) if v.size() > kStringPrintfVectorMaxArgs +extern string StringPrintfVector(const char* format, const vector& v); + +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H diff --git a/src/google/protobuf/stubs/stringprintf_unittest.cc b/src/google/protobuf/stubs/stringprintf_unittest.cc new file mode 100644 index 00000000..5cf7fffc --- /dev/null +++ b/src/google/protobuf/stubs/stringprintf_unittest.cc @@ -0,0 +1,152 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// from google3/base/stringprintf_unittest.cc + +#include + +#include +#include + +#include +#include + +namespace google { +namespace protobuf { +namespace { + +TEST(StringPrintfTest, Empty) { +#if 0 + // gcc 2.95.3, gcc 4.1.0, and gcc 4.2.2 all warn about this: + // warning: zero-length printf format string. + // so we do not allow them in google3. + EXPECT_EQ("", StringPrintf("")); +#endif + EXPECT_EQ("", StringPrintf("%s", string().c_str())); + EXPECT_EQ("", StringPrintf("%s", "")); +} + +TEST(StringPrintfTest, Misc) { +// MSVC does not support $ format specifier. +#if !defined(COMPILER_MSVC) + EXPECT_EQ("123hello w", StringPrintf("%3$d%2$s %1$c", 'w', "hello", 123)); +#endif // !COMPILER_MSVC +} + +TEST(StringAppendFTest, Empty) { + string value("Hello"); + const char* empty = ""; + StringAppendF(&value, "%s", empty); + EXPECT_EQ("Hello", value); +} + +TEST(StringAppendFTest, EmptyString) { + string value("Hello"); + StringAppendF(&value, "%s", ""); + EXPECT_EQ("Hello", value); +} + +TEST(StringAppendFTest, String) { + string value("Hello"); + StringAppendF(&value, " %s", "World"); + EXPECT_EQ("Hello World", value); +} + +TEST(StringAppendFTest, Int) { + string value("Hello"); + StringAppendF(&value, " %d", 123); + EXPECT_EQ("Hello 123", value); +} + +TEST(StringPrintfTest, Multibyte) { + // If we are in multibyte mode and feed invalid multibyte sequence, + // StringPrintf should return an empty string instead of running + // out of memory while trying to determine destination buffer size. + // see b/4194543. + + char* old_locale = setlocale(LC_CTYPE, NULL); + // Push locale with multibyte mode + setlocale(LC_CTYPE, "en_US.utf8"); + + const char kInvalidCodePoint[] = "\375\067s"; + string value = StringPrintf("%.*s", 3, kInvalidCodePoint); + + // In some versions of glibc (e.g. eglibc-2.11.1, aka GRTEv2), snprintf + // returns error given an invalid codepoint. Other versions + // (e.g. eglibc-2.15, aka pre-GRTEv3) emit the codepoint verbatim. + // We test that the output is one of the above. + EXPECT_TRUE(value.empty() || value == kInvalidCodePoint); + + // Repeat with longer string, to make sure that the dynamically + // allocated path in StringAppendV is handled correctly. + int n = 2048; + char* buf = new char[n+1]; + memset(buf, ' ', n-3); + memcpy(buf + n - 3, kInvalidCodePoint, 4); + value = StringPrintf("%.*s", n, buf); + // See GRTEv2 vs. GRTEv3 comment above. + EXPECT_TRUE(value.empty() || value == buf); + delete[] buf; + + setlocale(LC_CTYPE, old_locale); +} + +TEST(StringPrintfTest, NoMultibyte) { + // No multibyte handling, but the string contains funny chars. + char* old_locale = setlocale(LC_CTYPE, NULL); + setlocale(LC_CTYPE, "POSIX"); + string value = StringPrintf("%.*s", 3, "\375\067s"); + setlocale(LC_CTYPE, old_locale); + EXPECT_EQ("\375\067s", value); +} + +TEST(StringPrintfTest, DontOverwriteErrno) { + // Check that errno isn't overwritten unless we're printing + // something significantly larger than what people are normally + // printing in their badly written PLOG() statements. + errno = ECHILD; + string value = StringPrintf("Hello, %s!", "World"); + EXPECT_EQ(ECHILD, errno); +} + +TEST(StringPrintfTest, LargeBuf) { + // Check that the large buffer is handled correctly. + int n = 2048; + char* buf = new char[n+1]; + memset(buf, ' ', n); + buf[n] = 0; + string value = StringPrintf("%s", buf); + EXPECT_EQ(buf, value); + delete[] buf; +} + +} // anonymous namespace +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/stubs/strutil.cc b/src/google/protobuf/stubs/strutil.cc index ee07ce75..917b3e9f 100644 --- a/src/google/protobuf/stubs/strutil.cc +++ b/src/google/protobuf/stubs/strutil.cc @@ -189,6 +189,44 @@ void SplitStringUsing(const string& full, SplitStringToIteratorUsing(full, delim, it); } +// Split a string using a character delimiter. Append the components +// to 'result'. If there are consecutive delimiters, this function +// will return corresponding empty strings. The string is split into +// at most the specified number of pieces greedily. This means that the +// last piece may possibly be split further. To split into as many pieces +// as possible, specify 0 as the number of pieces. +// +// If "full" is the empty string, yields an empty string as the only value. +// +// If "pieces" is negative for some reason, it returns the whole string +// ---------------------------------------------------------------------- +template +static inline +void SplitStringToIteratorAllowEmpty(const StringType& full, + const char* delim, + int pieces, + ITR& result) { + string::size_type begin_index, end_index; + begin_index = 0; + + for (int i = 0; (i < pieces-1) || (pieces == 0); i++) { + end_index = full.find_first_of(delim, begin_index); + if (end_index == string::npos) { + *result++ = full.substr(begin_index); + return; + } + *result++ = full.substr(begin_index, (end_index - begin_index)); + begin_index = end_index + 1; + } + *result++ = full.substr(begin_index); +} + +void SplitStringAllowEmpty(const string& full, const char* delim, + vector* result) { + back_insert_iterator > it(*result); + SplitStringToIteratorAllowEmpty(full, delim, 0, it); +} + // ---------------------------------------------------------------------- // JoinStrings() // This merges a vector of string components with delim inserted diff --git a/src/google/protobuf/stubs/strutil.h b/src/google/protobuf/stubs/strutil.h index 4a79c224..a401c63a 100644 --- a/src/google/protobuf/stubs/strutil.h +++ b/src/google/protobuf/stubs/strutil.h @@ -168,6 +168,18 @@ LIBPROTOBUF_EXPORT string StringReplace(const string& s, const string& oldsub, LIBPROTOBUF_EXPORT void SplitStringUsing(const string& full, const char* delim, vector* res); +// Split a string using one or more byte delimiters, presented +// as a nul-terminated c string. Append the components to 'result'. +// If there are consecutive delimiters, this function will return +// corresponding empty strings. If you want to drop the empty +// strings, try SplitStringUsing(). +// +// If "full" is the empty string, yields an empty string as the only value. +// ---------------------------------------------------------------------- +LIBPROTOBUF_EXPORT void SplitStringAllowEmpty(const string& full, + const char* delim, + vector* result); + // ---------------------------------------------------------------------- // JoinStrings() // These methods concatenate a vector of strings into a C++ string, using @@ -453,5 +465,3 @@ LIBPROTOBUF_EXPORT double NoLocaleStrtod(const char* text, char** endptr); } // namespace google #endif // GOOGLE_PROTOBUF_STUBS_STRUTIL_H__ - - diff --git a/src/google/protobuf/stubs/substitute.cc b/src/google/protobuf/stubs/substitute.cc index b542aaa4..259245b3 100644 --- a/src/google/protobuf/stubs/substitute.cc +++ b/src/google/protobuf/stubs/substitute.cc @@ -32,7 +32,7 @@ #include #include -#include +#include namespace google { namespace protobuf { diff --git a/src/google/protobuf/stubs/template_util.h b/src/google/protobuf/stubs/template_util.h new file mode 100644 index 00000000..4f30ffa3 --- /dev/null +++ b/src/google/protobuf/stubs/template_util.h @@ -0,0 +1,138 @@ +// Copyright 2005 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// ---- +// Author: lar@google.com (Laramie Leavitt) +// +// Template metaprogramming utility functions. +// +// This code is compiled directly on many platforms, including client +// platforms like Windows, Mac, and embedded systems. Before making +// any changes here, make sure that you're not breaking any platforms. +// +// +// The names choosen here reflect those used in tr1 and the boost::mpl +// library, there are similar operations used in the Loki library as +// well. I prefer the boost names for 2 reasons: +// 1. I think that portions of the Boost libraries are more likely to +// be included in the c++ standard. +// 2. It is not impossible that some of the boost libraries will be +// included in our own build in the future. +// Both of these outcomes means that we may be able to directly replace +// some of these with boost equivalents. +// +#ifndef GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_ +#define GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_ + +namespace google { +namespace protobuf { +namespace internal { + +// Types small_ and big_ are guaranteed such that sizeof(small_) < +// sizeof(big_) +typedef char small_; + +struct big_ { + char dummy[2]; +}; + +// Identity metafunction. +template +struct identity_ { + typedef T type; +}; + +// integral_constant, defined in tr1, is a wrapper for an integer +// value. We don't really need this generality; we could get away +// with hardcoding the integer type to bool. We use the fully +// general integer_constant for compatibility with tr1. + +template +struct integral_constant { + static const T value = v; + typedef T value_type; + typedef integral_constant type; +}; + +template const T integral_constant::value; + + +// Abbreviations: true_type and false_type are structs that represent boolean +// true and false values. Also define the boost::mpl versions of those names, +// true_ and false_. +typedef integral_constant true_type; +typedef integral_constant false_type; +typedef true_type true_; +typedef false_type false_; + +// if_ is a templatized conditional statement. +// if_ is a compile time evaluation of cond. +// if_<>::type contains A if cond is true, B otherwise. +template +struct if_{ + typedef A type; +}; + +template +struct if_ { + typedef B type; +}; + + +// type_equals_ is a template type comparator, similar to Loki IsSameType. +// type_equals_::value is true iff "A" is the same type as "B". +// +// New code should prefer base::is_same, defined in base/type_traits.h. +// It is functionally identical, but is_same is the standard spelling. +template +struct type_equals_ : public false_ { +}; + +template +struct type_equals_ : public true_ { +}; + +// and_ is a template && operator. +// and_::value evaluates "A::value && B::value". +template +struct and_ : public integral_constant { +}; + +// or_ is a template || operator. +// or_::value evaluates "A::value || B::value". +template +struct or_ : public integral_constant { +}; + + +} // namespace internal +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_ diff --git a/src/google/protobuf/stubs/template_util_unittest.cc b/src/google/protobuf/stubs/template_util_unittest.cc new file mode 100644 index 00000000..b1745e2b --- /dev/null +++ b/src/google/protobuf/stubs/template_util_unittest.cc @@ -0,0 +1,130 @@ +// Copyright 2005 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// ---- +// Author: lar@google.com (Laramie Leavitt) +// +// These tests are really compile time tests. +// If you try to step through this in a debugger +// you will not see any evaluations, merely that +// value is assigned true or false sequentially. + +#include + +#include +#include + +namespace GOOGLE_NAMESPACE = google::protobuf::internal; + +namespace google { +namespace protobuf { +namespace internal { +namespace { + +TEST(TemplateUtilTest, TestSize) { + EXPECT_GT(sizeof(GOOGLE_NAMESPACE::big_), sizeof(GOOGLE_NAMESPACE::small_)); +} + +TEST(TemplateUtilTest, TestIntegralConstants) { + // test the built-in types. + EXPECT_TRUE(true_type::value); + EXPECT_FALSE(false_type::value); + + typedef integral_constant one_type; + EXPECT_EQ(1, one_type::value); +} + +TEST(TemplateUtilTest, TestTemplateIf) { + typedef if_::type if_true; + EXPECT_TRUE(if_true::value); + + typedef if_::type if_false; + EXPECT_FALSE(if_false::value); +} + +TEST(TemplateUtilTest, TestTemplateTypeEquals) { + // Check that the TemplateTypeEquals works correctly. + bool value = false; + + // Test the same type is true. + value = type_equals_::value; + EXPECT_TRUE(value); + + // Test different types are false. + value = type_equals_::value; + EXPECT_FALSE(value); + + // Test type aliasing. + typedef const int foo; + value = type_equals_::value; + EXPECT_TRUE(value); +} + +TEST(TemplateUtilTest, TestTemplateAndOr) { + // Check that the TemplateTypeEquals works correctly. + bool value = false; + + // Yes && Yes == true. + value = and_::value; + EXPECT_TRUE(value); + // Yes && No == false. + value = and_::value; + EXPECT_FALSE(value); + // No && Yes == false. + value = and_::value; + EXPECT_FALSE(value); + // No && No == false. + value = and_::value; + EXPECT_FALSE(value); + + // Yes || Yes == true. + value = or_::value; + EXPECT_TRUE(value); + // Yes || No == true. + value = or_::value; + EXPECT_TRUE(value); + // No || Yes == true. + value = or_::value; + EXPECT_TRUE(value); + // No || No == false. + value = or_::value; + EXPECT_FALSE(value); +} + +TEST(TemplateUtilTest, TestIdentity) { + EXPECT_TRUE( + (type_equals_::type, int>::value)); + EXPECT_TRUE( + (type_equals_::type, void>::value)); +} + +} // anonymous namespace +} // namespace internal +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/stubs/type_traits.h b/src/google/protobuf/stubs/type_traits.h new file mode 100644 index 00000000..997f35d4 --- /dev/null +++ b/src/google/protobuf/stubs/type_traits.h @@ -0,0 +1,346 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// ---- +// Author: Matt Austern +// +// This code is compiled directly on many platforms, including client +// platforms like Windows, Mac, and embedded systems. Before making +// any changes here, make sure that you're not breaking any platforms. +// +// Define a small subset of tr1 type traits. The traits we define are: +// is_integral +// is_floating_point +// is_pointer +// is_enum +// is_reference +// is_pod +// has_trivial_constructor +// has_trivial_copy +// has_trivial_assign +// has_trivial_destructor +// remove_const +// remove_volatile +// remove_cv +// remove_reference +// add_reference +// remove_pointer +// is_same +// is_convertible +// We can add more type traits as required. + +#ifndef GOOGLE_PROTOBUF_TYPE_TRAITS_H_ +#define GOOGLE_PROTOBUF_TYPE_TRAITS_H_ + +#include // For pair + +#include // For true_type and false_type + +namespace google { +namespace protobuf { +namespace internal { + +template struct is_integral; +template struct is_floating_point; +template struct is_pointer; +// MSVC can't compile this correctly, and neither can gcc 3.3.5 (at least) +#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) +// is_enum uses is_convertible, which is not available on MSVC. +template struct is_enum; +#endif +template struct is_reference; +template struct is_pod; +template struct has_trivial_constructor; +template struct has_trivial_copy; +template struct has_trivial_assign; +template struct has_trivial_destructor; +template struct remove_const; +template struct remove_volatile; +template struct remove_cv; +template struct remove_reference; +template struct add_reference; +template struct remove_pointer; +template struct is_same; +#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) +template struct is_convertible; +#endif + +// is_integral is false except for the built-in integer types. A +// cv-qualified type is integral if and only if the underlying type is. +template struct is_integral : false_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +#if defined(_MSC_VER) +// wchar_t is not by default a distinct type from unsigned short in +// Microsoft C. +// See http://msdn2.microsoft.com/en-us/library/dh8che7s(VS.80).aspx +template<> struct is_integral<__wchar_t> : true_type { }; +#else +template<> struct is_integral : true_type { }; +#endif +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +#ifdef HAVE_LONG_LONG +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +#endif +template struct is_integral : is_integral { }; +template struct is_integral : is_integral { }; +template struct is_integral : is_integral { }; + +// is_floating_point is false except for the built-in floating-point types. +// A cv-qualified type is integral if and only if the underlying type is. +template struct is_floating_point : false_type { }; +template<> struct is_floating_point : true_type { }; +template<> struct is_floating_point : true_type { }; +template<> struct is_floating_point : true_type { }; +template struct is_floating_point + : is_floating_point { }; +template struct is_floating_point + : is_floating_point { }; +template struct is_floating_point + : is_floating_point { }; + +// is_pointer is false except for pointer types. A cv-qualified type (e.g. +// "int* const", as opposed to "int const*") is cv-qualified if and only if +// the underlying type is. +template struct is_pointer : false_type { }; +template struct is_pointer : true_type { }; +template struct is_pointer : is_pointer { }; +template struct is_pointer : is_pointer { }; +template struct is_pointer : is_pointer { }; + +#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) + +namespace internal { + +template struct is_class_or_union { + template static small_ tester(void (U::*)()); + template static big_ tester(...); + static const bool value = sizeof(tester(0)) == sizeof(small_); +}; + +// is_convertible chokes if the first argument is an array. That's why +// we use add_reference here. +template struct is_enum_impl + : is_convertible::type, int> { }; + +template struct is_enum_impl : false_type { }; + +} // namespace internal + +// Specified by TR1 [4.5.1] primary type categories. + +// Implementation note: +// +// Each type is either void, integral, floating point, array, pointer, +// reference, member object pointer, member function pointer, enum, +// union or class. Out of these, only integral, floating point, reference, +// class and enum types are potentially convertible to int. Therefore, +// if a type is not a reference, integral, floating point or class and +// is convertible to int, it's a enum. Adding cv-qualification to a type +// does not change whether it's an enum. +// +// Is-convertible-to-int check is done only if all other checks pass, +// because it can't be used with some types (e.g. void or classes with +// inaccessible conversion operators). +template struct is_enum + : internal::is_enum_impl< + is_same::value || + is_integral::value || + is_floating_point::value || + is_reference::value || + internal::is_class_or_union::value, + T> { }; + +template struct is_enum : is_enum { }; +template struct is_enum : is_enum { }; +template struct is_enum : is_enum { }; + +#endif + +// is_reference is false except for reference types. +template struct is_reference : false_type {}; +template struct is_reference : true_type {}; + + +// We can't get is_pod right without compiler help, so fail conservatively. +// We will assume it's false except for arithmetic types, enumerations, +// pointers and cv-qualified versions thereof. Note that std::pair +// is not a POD even if T and U are PODs. +template struct is_pod + : integral_constant::value || + is_floating_point::value || +#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) + // is_enum is not available on MSVC. + is_enum::value || +#endif + is_pointer::value)> { }; +template struct is_pod : is_pod { }; +template struct is_pod : is_pod { }; +template struct is_pod : is_pod { }; + + +// We can't get has_trivial_constructor right without compiler help, so +// fail conservatively. We will assume it's false except for: (1) types +// for which is_pod is true. (2) std::pair of types with trivial +// constructors. (3) array of a type with a trivial constructor. +// (4) const versions thereof. +template struct has_trivial_constructor : is_pod { }; +template struct has_trivial_constructor > + : integral_constant::value && + has_trivial_constructor::value)> { }; +template struct has_trivial_constructor + : has_trivial_constructor { }; +template struct has_trivial_constructor + : has_trivial_constructor { }; + +// We can't get has_trivial_copy right without compiler help, so fail +// conservatively. We will assume it's false except for: (1) types +// for which is_pod is true. (2) std::pair of types with trivial copy +// constructors. (3) array of a type with a trivial copy constructor. +// (4) const versions thereof. +template struct has_trivial_copy : is_pod { }; +template struct has_trivial_copy > + : integral_constant::value && + has_trivial_copy::value)> { }; +template struct has_trivial_copy + : has_trivial_copy { }; +template struct has_trivial_copy : has_trivial_copy { }; + +// We can't get has_trivial_assign right without compiler help, so fail +// conservatively. We will assume it's false except for: (1) types +// for which is_pod is true. (2) std::pair of types with trivial copy +// constructors. (3) array of a type with a trivial assign constructor. +template struct has_trivial_assign : is_pod { }; +template struct has_trivial_assign > + : integral_constant::value && + has_trivial_assign::value)> { }; +template struct has_trivial_assign + : has_trivial_assign { }; + +// We can't get has_trivial_destructor right without compiler help, so +// fail conservatively. We will assume it's false except for: (1) types +// for which is_pod is true. (2) std::pair of types with trivial +// destructors. (3) array of a type with a trivial destructor. +// (4) const versions thereof. +template struct has_trivial_destructor : is_pod { }; +template struct has_trivial_destructor > + : integral_constant::value && + has_trivial_destructor::value)> { }; +template struct has_trivial_destructor + : has_trivial_destructor { }; +template struct has_trivial_destructor + : has_trivial_destructor { }; + +// Specified by TR1 [4.7.1] +template struct remove_const { typedef T type; }; +template struct remove_const { typedef T type; }; +template struct remove_volatile { typedef T type; }; +template struct remove_volatile { typedef T type; }; +template struct remove_cv { + typedef typename remove_const::type>::type type; +}; + + +// Specified by TR1 [4.7.2] Reference modifications. +template struct remove_reference { typedef T type; }; +template struct remove_reference { typedef T type; }; + +template struct add_reference { typedef T& type; }; +template struct add_reference { typedef T& type; }; + +// Specified by TR1 [4.7.4] Pointer modifications. +template struct remove_pointer { typedef T type; }; +template struct remove_pointer { typedef T type; }; +template struct remove_pointer { typedef T type; }; +template struct remove_pointer { typedef T type; }; +template struct remove_pointer { + typedef T type; }; + +// Specified by TR1 [4.6] Relationships between types +template struct is_same : public false_type { }; +template struct is_same : public true_type { }; + +// Specified by TR1 [4.6] Relationships between types +#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) +namespace internal { + +// This class is an implementation detail for is_convertible, and you +// don't need to know how it works to use is_convertible. For those +// who care: we declare two different functions, one whose argument is +// of type To and one with a variadic argument list. We give them +// return types of different size, so we can use sizeof to trick the +// compiler into telling us which function it would have chosen if we +// had called it with an argument of type From. See Alexandrescu's +// _Modern C++ Design_ for more details on this sort of trick. + +template +struct ConvertHelper { + static small_ Test(To); + static big_ Test(...); + static From Create(); +}; +} // namespace internal + +// Inherits from true_type if From is convertible to To, false_type otherwise. +template +struct is_convertible + : integral_constant::Test( + internal::ConvertHelper::Create())) + == sizeof(small_)> { +}; +#endif + +} // namespace internal +} // namespace protobuf +} // namespace google + +// Right now these macros are no-ops, and mostly just document the fact +// these types are PODs, for human use. They may be made more contentful +// later. The typedef is just to make it legal to put a semicolon after +// these macros. +#define DECLARE_POD(TypeName) typedef int Dummy_Type_For_DECLARE_POD +#define DECLARE_NESTED_POD(TypeName) DECLARE_POD(TypeName) +#define PROPAGATE_POD_FROM_TEMPLATE_ARGUMENT(TemplateName) \ + typedef int Dummy_Type_For_PROPAGATE_POD_FROM_TEMPLATE_ARGUMENT +#define ENFORCE_POD(TypeName) typedef int Dummy_Type_For_ENFORCE_POD + +#endif // GOOGLE_PROTOBUF_TYPE_TRAITS_H_ diff --git a/src/google/protobuf/stubs/type_traits_unittest.cc b/src/google/protobuf/stubs/type_traits_unittest.cc new file mode 100644 index 00000000..00e5a476 --- /dev/null +++ b/src/google/protobuf/stubs/type_traits_unittest.cc @@ -0,0 +1,647 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// ---- +// Author: Matt Austern + +#include + +#include // for exit() +#include +#include +#include + +#include +#include + +typedef int int32; +typedef long int64; + +using std::string; +using std::vector; +using std::pair; + +using google::protobuf::internal::add_reference; +using google::protobuf::internal::has_trivial_assign; +using google::protobuf::internal::has_trivial_constructor; +using google::protobuf::internal::has_trivial_copy; +using google::protobuf::internal::has_trivial_destructor; +#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) +using google::protobuf::internal::is_convertible; +using google::protobuf::internal::is_enum; +#endif +using google::protobuf::internal::is_floating_point; +using google::protobuf::internal::is_integral; +using google::protobuf::internal::is_pointer; +using google::protobuf::internal::is_pod; +using google::protobuf::internal::is_reference; +using google::protobuf::internal::is_same; +using google::protobuf::internal::remove_const; +using google::protobuf::internal::remove_cv; +using google::protobuf::internal::remove_pointer; +using google::protobuf::internal::remove_reference; +using google::protobuf::internal::remove_volatile; + + +// This assertion produces errors like "error: invalid use of +// incomplete type 'struct ::AssertTypesEq'" +// when it fails. +template struct AssertTypesEq; +template struct AssertTypesEq {}; +#define COMPILE_ASSERT_TYPES_EQ(T, U) static_cast(AssertTypesEq()) + +// A user-defined POD type. +struct A { + int n_; +}; + +// A user-defined non-POD type with a trivial copy constructor. +class B { + public: + explicit B(int n) : n_(n) { } + private: + int n_; +}; + +// Another user-defined non-POD type with a trivial copy constructor. +// We will explicitly declare C to have a trivial copy constructor +// by specializing has_trivial_copy. +class C { + public: + explicit C(int n) : n_(n) { } + private: + int n_; +}; + +namespace google { +namespace protobuf { +namespace internal { +template<> struct has_trivial_copy : true_type { }; +} // namespace internal +} // namespace protobuf +} // namespace google + +// Another user-defined non-POD type with a trivial assignment operator. +// We will explicitly declare C to have a trivial assignment operator +// by specializing has_trivial_assign. +class D { + public: + explicit D(int n) : n_(n) { } + private: + int n_; +}; + +namespace google { +namespace protobuf { +namespace internal { +template<> struct has_trivial_assign : true_type { }; +} // namespace internal +} // namespace protobuf +} // namespace google + +// Another user-defined non-POD type with a trivial constructor. +// We will explicitly declare E to have a trivial constructor +// by specializing has_trivial_constructor. +class E { + public: + int n_; +}; + +namespace google { +namespace protobuf { +namespace internal { +template<> struct has_trivial_constructor : true_type { }; +} // namespace internal +} // namespace protobuf +} // namespace google + +// Another user-defined non-POD type with a trivial destructor. +// We will explicitly declare E to have a trivial destructor +// by specializing has_trivial_destructor. +class F { + public: + explicit F(int n) : n_(n) { } + private: + int n_; +}; + +namespace google { +namespace protobuf { +namespace internal { +template<> struct has_trivial_destructor : true_type { }; +} // namespace internal +} // namespace protobuf +} // namespace google + +enum G {}; + +union H {}; + +class I { + public: + operator int() const; +}; + +class J { + private: + operator int() const; +}; + +namespace google { +namespace protobuf { +namespace { + +// A base class and a derived class that inherits from it, used for +// testing conversion type traits. +class Base { + public: + virtual ~Base() { } +}; + +class Derived : public Base { +}; + +TEST(TypeTraitsTest, TestIsInteger) { + // Verify that is_integral is true for all integer types. + EXPECT_TRUE(is_integral::value); + EXPECT_TRUE(is_integral::value); + EXPECT_TRUE(is_integral::value); + EXPECT_TRUE(is_integral::value); + EXPECT_TRUE(is_integral::value); + EXPECT_TRUE(is_integral::value); + EXPECT_TRUE(is_integral::value); + EXPECT_TRUE(is_integral::value); + EXPECT_TRUE(is_integral::value); + EXPECT_TRUE(is_integral::value); + EXPECT_TRUE(is_integral::value); + + // Verify that is_integral is false for a few non-integer types. + EXPECT_FALSE(is_integral::value); + EXPECT_FALSE(is_integral::value); + EXPECT_FALSE(is_integral::value); + EXPECT_FALSE(is_integral::value); + EXPECT_FALSE(is_integral::value); + EXPECT_FALSE((is_integral >::value)); + + // Verify that cv-qualified integral types are still integral, and + // cv-qualified non-integral types are still non-integral. + EXPECT_TRUE(is_integral::value); + EXPECT_TRUE(is_integral::value); + EXPECT_TRUE(is_integral::value); + EXPECT_FALSE(is_integral::value); + EXPECT_FALSE(is_integral::value); + EXPECT_FALSE(is_integral::value); +} + +TEST(TypeTraitsTest, TestIsFloating) { + // Verify that is_floating_point is true for all floating-point types. + EXPECT_TRUE(is_floating_point::value); + EXPECT_TRUE(is_floating_point::value); + EXPECT_TRUE(is_floating_point::value); + + // Verify that is_floating_point is false for a few non-float types. + EXPECT_FALSE(is_floating_point::value); + EXPECT_FALSE(is_floating_point::value); + EXPECT_FALSE(is_floating_point::value); + EXPECT_FALSE(is_floating_point::value); + EXPECT_FALSE(is_floating_point::value); + EXPECT_FALSE((is_floating_point >::value)); + + // Verify that cv-qualified floating point types are still floating, and + // cv-qualified non-floating types are still non-floating. + EXPECT_TRUE(is_floating_point::value); + EXPECT_TRUE(is_floating_point::value); + EXPECT_TRUE(is_floating_point::value); + EXPECT_FALSE(is_floating_point::value); + EXPECT_FALSE(is_floating_point::value); + EXPECT_FALSE(is_floating_point::value); +} + +TEST(TypeTraitsTest, TestIsPointer) { + // Verify that is_pointer is true for some pointer types. + EXPECT_TRUE(is_pointer::value); + EXPECT_TRUE(is_pointer::value); + EXPECT_TRUE(is_pointer::value); + EXPECT_TRUE(is_pointer::value); + EXPECT_TRUE(is_pointer::value); + + // Verify that is_pointer is false for some non-pointer types. + EXPECT_FALSE(is_pointer::value); + EXPECT_FALSE(is_pointer::value); + EXPECT_FALSE(is_pointer::value); + EXPECT_FALSE(is_pointer >::value); + EXPECT_FALSE(is_pointer::value); + + // A function pointer is a pointer, but a function type, or a function + // reference type, is not. + EXPECT_TRUE(is_pointer::value); + EXPECT_FALSE(is_pointer::value); + EXPECT_FALSE(is_pointer::value); + + // Verify that is_pointer is true for some cv-qualified pointer types, + // and false for some cv-qualified non-pointer types. + EXPECT_TRUE(is_pointer::value); + EXPECT_TRUE(is_pointer::value); + EXPECT_TRUE(is_pointer::value); + EXPECT_FALSE(is_pointer::value); + EXPECT_FALSE(is_pointer >::value); + EXPECT_FALSE(is_pointer::value); +} + +TEST(TypeTraitsTest, TestIsEnum) { +// is_enum isn't supported on MSVC or gcc 3.x +#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) + // Verify that is_enum is true for enum types. + EXPECT_TRUE(is_enum::value); + EXPECT_TRUE(is_enum::value); + EXPECT_TRUE(is_enum::value); + EXPECT_TRUE(is_enum::value); + + // Verify that is_enum is false for a few non-enum types. + EXPECT_FALSE(is_enum::value); + EXPECT_FALSE(is_enum::value); + EXPECT_FALSE(is_enum::value); + EXPECT_FALSE(is_enum::value); + EXPECT_FALSE(is_enum::value); + EXPECT_FALSE(is_enum::value); + EXPECT_FALSE(is_enum::value); + EXPECT_FALSE(is_enum::value); + EXPECT_FALSE(is_enum::value); + EXPECT_FALSE(is_enum::value); + EXPECT_FALSE(is_enum::value); + EXPECT_FALSE(is_enum::value); + EXPECT_FALSE(is_enum::value); + EXPECT_FALSE(is_enum::value); + EXPECT_FALSE(is_enum::value); + EXPECT_FALSE(is_enum::value); + EXPECT_FALSE(is_enum::value); +#endif +} + +TEST(TypeTraitsTest, TestIsReference) { + // Verifies that is_reference is true for all reference types. + typedef float& RefFloat; + EXPECT_TRUE(is_reference::value); + EXPECT_TRUE(is_reference::value); + EXPECT_TRUE(is_reference::value); + EXPECT_TRUE(is_reference::value); + EXPECT_TRUE(is_reference::value); + EXPECT_TRUE(is_reference::value); + EXPECT_TRUE(is_reference::value); + EXPECT_TRUE(is_reference::value); + + + // Verifies that is_reference is false for all non-reference types. + EXPECT_FALSE(is_reference::value); + EXPECT_FALSE(is_reference::value); + EXPECT_FALSE(is_reference::value); + EXPECT_FALSE(is_reference::value); + EXPECT_FALSE(is_reference::value); + EXPECT_FALSE(is_reference::value); + EXPECT_FALSE(is_reference::value); +} + +TEST(TypeTraitsTest, TestAddReference) { + COMPILE_ASSERT_TYPES_EQ(int&, add_reference::type); + COMPILE_ASSERT_TYPES_EQ(const int&, add_reference::type); + COMPILE_ASSERT_TYPES_EQ(volatile int&, + add_reference::type); + COMPILE_ASSERT_TYPES_EQ(const volatile int&, + add_reference::type); + COMPILE_ASSERT_TYPES_EQ(int&, add_reference::type); + COMPILE_ASSERT_TYPES_EQ(const int&, add_reference::type); + COMPILE_ASSERT_TYPES_EQ(volatile int&, + add_reference::type); + COMPILE_ASSERT_TYPES_EQ(const volatile int&, + add_reference::type); +} + +TEST(TypeTraitsTest, TestIsPod) { + // Verify that arithmetic types and pointers are marked as PODs. + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); +#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); + EXPECT_TRUE(is_pod::value); +#endif + + // Verify that some non-POD types are not marked as PODs. + EXPECT_FALSE(is_pod::value); + EXPECT_FALSE(is_pod::value); + EXPECT_FALSE((is_pod >::value)); + EXPECT_FALSE(is_pod::value); + EXPECT_FALSE(is_pod::value); + EXPECT_FALSE(is_pod::value); + EXPECT_FALSE(is_pod::value); + EXPECT_FALSE(is_pod::value); + EXPECT_FALSE(is_pod::value); +} + +TEST(TypeTraitsTest, TestHasTrivialConstructor) { + // Verify that arithmetic types and pointers have trivial constructors. + EXPECT_TRUE(has_trivial_constructor::value); + EXPECT_TRUE(has_trivial_constructor::value); + EXPECT_TRUE(has_trivial_constructor::value); + EXPECT_TRUE(has_trivial_constructor::value); + EXPECT_TRUE(has_trivial_constructor::value); + EXPECT_TRUE(has_trivial_constructor::value); + EXPECT_TRUE(has_trivial_constructor::value); + EXPECT_TRUE(has_trivial_constructor::value); + EXPECT_TRUE(has_trivial_constructor::value); + EXPECT_TRUE(has_trivial_constructor::value); + EXPECT_TRUE(has_trivial_constructor::value); + EXPECT_TRUE(has_trivial_constructor::value); + EXPECT_TRUE(has_trivial_constructor::value); + EXPECT_TRUE(has_trivial_constructor::value); + EXPECT_TRUE(has_trivial_constructor::value); + EXPECT_TRUE(has_trivial_constructor::value); + EXPECT_TRUE(has_trivial_constructor::value); + EXPECT_TRUE(has_trivial_constructor::value); + + // Verify that pairs and arrays of such types have trivial + // constructors. + typedef int int10[10]; + EXPECT_TRUE((has_trivial_constructor >::value)); + EXPECT_TRUE(has_trivial_constructor::value); + + // Verify that pairs of types without trivial constructors + // are not marked as trivial. + EXPECT_FALSE((has_trivial_constructor >::value)); + EXPECT_FALSE((has_trivial_constructor >::value)); + + // Verify that types without trivial constructors are + // correctly marked as such. + EXPECT_FALSE(has_trivial_constructor::value); + EXPECT_FALSE(has_trivial_constructor >::value); + + // Verify that E, which we have declared to have a trivial + // constructor, is correctly marked as such. + EXPECT_TRUE(has_trivial_constructor::value); +} + +TEST(TypeTraitsTest, TestHasTrivialCopy) { + // Verify that arithmetic types and pointers have trivial copy + // constructors. + EXPECT_TRUE(has_trivial_copy::value); + EXPECT_TRUE(has_trivial_copy::value); + EXPECT_TRUE(has_trivial_copy::value); + EXPECT_TRUE(has_trivial_copy::value); + EXPECT_TRUE(has_trivial_copy::value); + EXPECT_TRUE(has_trivial_copy::value); + EXPECT_TRUE(has_trivial_copy::value); + EXPECT_TRUE(has_trivial_copy::value); + EXPECT_TRUE(has_trivial_copy::value); + EXPECT_TRUE(has_trivial_copy::value); + EXPECT_TRUE(has_trivial_copy::value); + EXPECT_TRUE(has_trivial_copy::value); + EXPECT_TRUE(has_trivial_copy::value); + EXPECT_TRUE(has_trivial_copy::value); + EXPECT_TRUE(has_trivial_copy::value); + EXPECT_TRUE(has_trivial_copy::value); + EXPECT_TRUE(has_trivial_copy::value); + EXPECT_TRUE(has_trivial_copy::value); + + // Verify that pairs and arrays of such types have trivial + // copy constructors. + typedef int int10[10]; + EXPECT_TRUE((has_trivial_copy >::value)); + EXPECT_TRUE(has_trivial_copy::value); + + // Verify that pairs of types without trivial copy constructors + // are not marked as trivial. + EXPECT_FALSE((has_trivial_copy >::value)); + EXPECT_FALSE((has_trivial_copy >::value)); + + // Verify that types without trivial copy constructors are + // correctly marked as such. + EXPECT_FALSE(has_trivial_copy::value); + EXPECT_FALSE(has_trivial_copy >::value); + + // Verify that C, which we have declared to have a trivial + // copy constructor, is correctly marked as such. + EXPECT_TRUE(has_trivial_copy::value); +} + +TEST(TypeTraitsTest, TestHasTrivialAssign) { + // Verify that arithmetic types and pointers have trivial assignment + // operators. + EXPECT_TRUE(has_trivial_assign::value); + EXPECT_TRUE(has_trivial_assign::value); + EXPECT_TRUE(has_trivial_assign::value); + EXPECT_TRUE(has_trivial_assign::value); + EXPECT_TRUE(has_trivial_assign::value); + EXPECT_TRUE(has_trivial_assign::value); + EXPECT_TRUE(has_trivial_assign::value); + EXPECT_TRUE(has_trivial_assign::value); + EXPECT_TRUE(has_trivial_assign::value); + EXPECT_TRUE(has_trivial_assign::value); + EXPECT_TRUE(has_trivial_assign::value); + EXPECT_TRUE(has_trivial_assign::value); + EXPECT_TRUE(has_trivial_assign::value); + EXPECT_TRUE(has_trivial_assign::value); + EXPECT_TRUE(has_trivial_assign::value); + EXPECT_TRUE(has_trivial_assign::value); + EXPECT_TRUE(has_trivial_assign::value); + EXPECT_TRUE(has_trivial_assign::value); + + // Verify that pairs and arrays of such types have trivial + // assignment operators. + typedef int int10[10]; + EXPECT_TRUE((has_trivial_assign >::value)); + EXPECT_TRUE(has_trivial_assign::value); + + // Verify that pairs of types without trivial assignment operators + // are not marked as trivial. + EXPECT_FALSE((has_trivial_assign >::value)); + EXPECT_FALSE((has_trivial_assign >::value)); + + // Verify that types without trivial assignment operators are + // correctly marked as such. + EXPECT_FALSE(has_trivial_assign::value); + EXPECT_FALSE(has_trivial_assign >::value); + + // Verify that D, which we have declared to have a trivial + // assignment operator, is correctly marked as such. + EXPECT_TRUE(has_trivial_assign::value); +} + +TEST(TypeTraitsTest, TestHasTrivialDestructor) { + // Verify that arithmetic types and pointers have trivial destructors. + EXPECT_TRUE(has_trivial_destructor::value); + EXPECT_TRUE(has_trivial_destructor::value); + EXPECT_TRUE(has_trivial_destructor::value); + EXPECT_TRUE(has_trivial_destructor::value); + EXPECT_TRUE(has_trivial_destructor::value); + EXPECT_TRUE(has_trivial_destructor::value); + EXPECT_TRUE(has_trivial_destructor::value); + EXPECT_TRUE(has_trivial_destructor::value); + EXPECT_TRUE(has_trivial_destructor::value); + EXPECT_TRUE(has_trivial_destructor::value); + EXPECT_TRUE(has_trivial_destructor::value); + EXPECT_TRUE(has_trivial_destructor::value); + EXPECT_TRUE(has_trivial_destructor::value); + EXPECT_TRUE(has_trivial_destructor::value); + EXPECT_TRUE(has_trivial_destructor::value); + EXPECT_TRUE(has_trivial_destructor::value); + EXPECT_TRUE(has_trivial_destructor::value); + EXPECT_TRUE(has_trivial_destructor::value); + + // Verify that pairs and arrays of such types have trivial + // destructors. + typedef int int10[10]; + EXPECT_TRUE((has_trivial_destructor >::value)); + EXPECT_TRUE(has_trivial_destructor::value); + + // Verify that pairs of types without trivial destructors + // are not marked as trivial. + EXPECT_FALSE((has_trivial_destructor >::value)); + EXPECT_FALSE((has_trivial_destructor >::value)); + + // Verify that types without trivial destructors are + // correctly marked as such. + EXPECT_FALSE(has_trivial_destructor::value); + EXPECT_FALSE(has_trivial_destructor >::value); + + // Verify that F, which we have declared to have a trivial + // destructor, is correctly marked as such. + EXPECT_TRUE(has_trivial_destructor::value); +} + +// Tests remove_pointer. +TEST(TypeTraitsTest, TestRemovePointer) { + COMPILE_ASSERT_TYPES_EQ(int, remove_pointer::type); + COMPILE_ASSERT_TYPES_EQ(int, remove_pointer::type); + COMPILE_ASSERT_TYPES_EQ(const int, remove_pointer::type); + COMPILE_ASSERT_TYPES_EQ(int, remove_pointer::type); + COMPILE_ASSERT_TYPES_EQ(int, remove_pointer::type); +} + +TEST(TypeTraitsTest, TestRemoveConst) { + COMPILE_ASSERT_TYPES_EQ(int, remove_const::type); + COMPILE_ASSERT_TYPES_EQ(int, remove_const::type); + COMPILE_ASSERT_TYPES_EQ(int *, remove_const::type); + // TR1 examples. + COMPILE_ASSERT_TYPES_EQ(const int *, remove_const::type); + COMPILE_ASSERT_TYPES_EQ(volatile int, + remove_const::type); +} + +TEST(TypeTraitsTest, TestRemoveVolatile) { + COMPILE_ASSERT_TYPES_EQ(int, remove_volatile::type); + COMPILE_ASSERT_TYPES_EQ(int, remove_volatile::type); + COMPILE_ASSERT_TYPES_EQ(int *, remove_volatile::type); + // TR1 examples. + COMPILE_ASSERT_TYPES_EQ(volatile int *, + remove_volatile::type); + COMPILE_ASSERT_TYPES_EQ(const int, + remove_volatile::type); +} + +TEST(TypeTraitsTest, TestRemoveCV) { + COMPILE_ASSERT_TYPES_EQ(int, remove_cv::type); + COMPILE_ASSERT_TYPES_EQ(int, remove_cv::type); + COMPILE_ASSERT_TYPES_EQ(int, remove_cv::type); + COMPILE_ASSERT_TYPES_EQ(int *, remove_cv::type); + // TR1 examples. + COMPILE_ASSERT_TYPES_EQ(const volatile int *, + remove_cv::type); + COMPILE_ASSERT_TYPES_EQ(int, + remove_cv::type); +} + +TEST(TypeTraitsTest, TestRemoveReference) { + COMPILE_ASSERT_TYPES_EQ(int, remove_reference::type); + COMPILE_ASSERT_TYPES_EQ(int, remove_reference::type); + COMPILE_ASSERT_TYPES_EQ(const int, remove_reference::type); + COMPILE_ASSERT_TYPES_EQ(int*, remove_reference::type); +} + +TEST(TypeTraitsTest, TestIsSame) { + EXPECT_TRUE((is_same::value)); + EXPECT_FALSE((is_same::value)); + EXPECT_FALSE((is_same::value)); + EXPECT_FALSE((is_same::value)); + + EXPECT_TRUE((is_same::value)); + EXPECT_FALSE((is_same::value)); + EXPECT_FALSE((is_same::value)); + + EXPECT_TRUE((is_same::value)); + EXPECT_TRUE((is_same::value)); + EXPECT_FALSE((is_same::value)); + EXPECT_FALSE((is_same::value)); + EXPECT_FALSE((is_same::value)); + EXPECT_FALSE((is_same::value)); + + EXPECT_TRUE((is_same::value)); + EXPECT_TRUE((is_same::value)); + EXPECT_FALSE((is_same::value)); + EXPECT_FALSE((is_same::value)); +} + +TEST(TypeTraitsTest, TestConvertible) { +#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) + EXPECT_TRUE((is_convertible::value)); + EXPECT_TRUE((is_convertible::value)); + EXPECT_TRUE((is_convertible::value)); + + EXPECT_TRUE((is_convertible::value)); + EXPECT_FALSE((is_convertible::value)); + + EXPECT_TRUE((is_convertible::value)); + EXPECT_FALSE((is_convertible::value)); + EXPECT_TRUE((is_convertible::value)); + EXPECT_FALSE((is_convertible::value)); +#endif +} + +} // anonymous namespace +} // namespace protobuf +} // namespace google -- cgit v1.2.3