diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..733c45e1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,134 @@ +cmake_minimum_required(VERSION 2.8) +project(s2-geometry) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +include(CheckCXXCompilerFlag) +include(FindPackageHandleStandardArgs) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/third_party/cmake") + +find_package(GFlags REQUIRED) +find_package(Glog REQUIRED) +find_package(OpenSSL REQUIRED) +find_package(Threads REQUIRED) + +add_definitions(-Wno-deprecated-declarations -std=c++11) +# Controls HASH_NAMESPACE in port.h. +# Use std::hash instead of __gnu_cxx::hash. +add_definitions(-DUSE_STD_HASH) + +include_directories(${GFLAGS_INCLUDE_DIRS} ${GLOG_INCLUDE_DIRS}) +include_directories(src) + +# Explicitly list S2 files until we move test files to test dir. +# TODO: Move test files to another dir. +file(GLOB S2FilesGlob + src/base/*.cc + src/r2rect.cc + src/s1angle.cc + src/s1chordangle.cc + src/s1interval.cc + src/s2.cc + src/s2cap.cc + src/s2cell.cc + src/s2cellid.cc + src/s2cellunion.cc + src/s2closestedgequery.cc + src/s2edgequery.cc + src/s2edgeutil.cc + src/s2error.cc + src/s2latlng.cc + src/s2latlngrect.cc + src/s2loop.cc + src/s2paddedcell.cc + src/s2pointcompression.cc + src/s2pointregion.cc + src/s2polygon.cc + src/s2polygonbuilder.cc + src/s2polyline.cc + src/s2r2rect.cc + src/s2region.cc + src/s2regioncoverer.cc + src/s2regionintersection.cc + src/s2regionunion.cc + src/s2shapeindex.cc + src/s2shapeutil.cc + src/s2textformat.cc + src/strings/*.cc + src/util/bits/*.cc + src/util/coding/*.cc + src/util/hash/*.cc + src/util/math/exactfloat/*.cc + src/util/math/*.cc) + +add_library(s2geometry STATIC ${S2FilesGlob}) + +file(GLOB S2Headers src/*.h) + +# We don't need to install all headers, only those +# transitively included by s2 headers we are exporting. +install(FILES ${S2Headers} + DESTINATION include/s2geometry) +install(FILES src/base/atomicops.h + src/base/casts.h + src/base/int128.h + src/base/integral_types.h + src/base/macros.h + src/base/mutex.h + src/base/port.h + src/base/port_hash.h + src/base/spinlock.h + src/base/stl_decl_msvc.h + src/base/template_util.h + src/base/type_traits.h + DESTINATION include/s2geometry/base) +install(FILES src/util/bits/bits.h + src/util/bits/bits-internal-unknown.h + src/util/bits/bits-internal-windows.h + DESTINATION include/s2geometry/util/bits) +install(FILES src/util/gtl/inlined_vector.h + src/util/gtl/manual_constructor.h + DESTINATION include/s2geometry/util/gtl) +install(FILES src/util/hash/builtin_type_hash.h + src/util/hash/city.h + src/util/hash/hash.h + src/util/hash/hash128to64.h + src/util/hash/jenkins.h + src/util/hash/jenkins_lookup2.h + src/util/hash/string_hash.h + DESTINATION include/s2geometry/util/hash) +install(FILES src/util/math/mathlimits.h + src/util/math/mathutil.h + src/util/math/matrix3x3.h + src/util/math/vector2.h + src/util/math/vector3.h + src/util/math/vector3_hash.h + src/util/math/vector4.h + DESTINATION include/s2geometry/util/hash) +install(FILES src/util/units/length-units.h + src/util/units/physical-units.h + DESTINATION include/s2geometry/util/units) +install(TARGETS s2geometry DESTINATION lib) + +message("GTEST_ROOT: ${GTEST_ROOT}") +if (GTEST_ROOT) + add_library(gtest_main STATIC ${GTEST_ROOT}/src/gtest-all.cc ${GTEST_ROOT}/src/gtest_main.cc) + add_library(s2testing STATIC src/s2testing.cc) + + file(GLOB S2TestFilesGlob src/*_test.cc) + + enable_testing() + include_directories(${GTEST_ROOT}/include) + include_directories(${GTEST_ROOT}) + + foreach (test_cc ${S2TestFilesGlob}) + get_filename_component(test ${test_cc} NAME_WE) + add_executable(${test} ${test_cc}) + target_link_libraries( + ${test} + s2testing s2geometry gtest_main + ${GFLAGS_LIBRARIES} ${GLOG_LIBRARIES} ${OPENSSL_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT}) + add_test(${test} ${test}) + endforeach() +endif() + diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 14685127..6c74cedb 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -24,3 +24,4 @@ Eric Veach Jesse Rosenstock +Julien Basch diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index c6b08631..00000000 --- a/src/Makefile.am +++ /dev/null @@ -1,325 +0,0 @@ -# Make sure that when we re-make ./configure, we get the macros we need -ACLOCAL_AMFLAGS = -I m4 - -AM_CXXFLAGS = -std=c++11 -Wno-deprecated -AM_CPPFLAGS = -DGOOGLE_NAMESPACE=base \ - -D_START_GOOGLE_NAMESPACE_='namespace base {' \ - -D_END_GOOGLE_NAMESPACE_='}' -DNDEBUG - -lib_LTLIBRARIES = libs2.la -check_LIBRARIES = libgtest.a - -s2_includedir = $(includedir)/s2 -s2_base_includedir = $(includedir)/s2/base -s2_strings_includedir = $(includedir)/s2/strings -s2_util_bits_includedir = $(includedir)/s2/util/bits -s2_util_coding_includedir = $(includedir)/s2/util/coding -s2_util_endian_includedir = $(includedir)/s2/util/endian -s2_util_gtl_includedir = $(includedir)/s2/util/gtl -s2_util_hash_includedir = $(includedir)/s2/util/hash -s2_util_math_includedir = $(includedir)/s2/util/math - -s2_base_include_HEADERS = \ - base/atomicops.h \ - base/casts.h \ - base/int128.h \ - base/integral_types.h \ - base/macros.h \ - base/mutex.h \ - base/port.h \ - base/port_hash.h \ - base/scoped_ptr.h \ - base/scoped_ptr_internals.h \ - base/spinlock.h \ - base/stringprintf.h \ - base/template_util.h \ - base/type_traits.h - -s2_strings_include_HEADERS = \ - strings/ascii_ctype.h \ - strings/case.h \ - strings/charset.h \ - strings/fastmem.h \ - strings/join_internal.h \ - strings/numbers.h \ - strings/split_internal.h \ - strings/strcat.h \ - strings/stringpiece.h \ - strings/stringpiece_utils.h \ - strings/strip.h - -s2_util_bits_include_HEADERS = \ - util/bits/bits-internal-unknown.h \ - util/bits/bits-internal-windows.h \ - util/bits/bits.h - -s2_util_coding_include_HEADERS = \ - util/coding/varint.h - -s2_util_endian_include_HEADERS = \ - util/endian/endian.h - -s2_util_gtl_include_HEADERS = \ - util/gtl/algorithm.h \ - util/gtl/container_logging.h \ - util/gtl/inlined_vector.h \ - util/gtl/manual_constructor.h - -s2_util_hash_include_HEADERS = \ - util/hash/builtin_type_hash.h \ - util/hash/city.h \ - util/hash/farmhash.h \ - util/hash/hash.h \ - util/hash/hash128to64.h \ - util/hash/jenkins.h \ - util/hash/jenkins_lookup2.h \ - util/hash/murmur.h \ - util/hash/string_hash.h - -s2_util_math_include_HEADERS = \ - util/math/mathlimits.h \ - util/math/mathutil.h \ - util/math/matrix3x3.h \ - util/math/vector2.h \ - util/math/vector3.h \ - util/math/vector3_hash.h \ - util/math/vector4.h - -s2_include_HEADERS = \ - r1interval.h \ - r2.h \ - r2rect.h \ - s1chordangle.h \ - s1angle.h \ - s1interval.h \ - s2.h \ - s2cap.h \ - s2cell.h \ - s2cellid.h \ - s2closestedgequery.h \ - s2cellunion.h \ - s2edgequery.h \ - s2edgeutil.h \ - s2error.h \ - s2latlng.h \ - s2latlngrect.h \ - s2loop.h \ - s2paddedcell.h \ - s2pointcompression.h \ - s2pointregion.h \ - s2polygon.h \ - s2polygonbuilder.h \ - s2polyline.h \ - s2r2rect.h \ - s2region.h \ - s2regioncoverer.h \ - s2regionintersection.h \ - s2regionunion.h \ - s2shapeindex.h \ - s2shapeutil.h \ - s2testing.h - -# TODO(jrosenstock): split out non-s2 libraries / testing library -libs2_la_SOURCES = \ - base/int128.cc \ - base/stringprintf.cc \ - base/strtoint.cc \ - strings/ascii_ctype.cc \ - strings/case.cc \ - strings/charset.cc \ - strings/escaping.cc \ - strings/join.cc \ - strings/memutil.cc \ - strings/numbers.cc \ - strings/serialize.cc \ - strings/split.cc \ - strings/strcat.cc \ - strings/stringpiece.cc \ - strings/stringpiece_utils.cc \ - strings/strip.cc \ - strings/util.cc \ - util/bits/bit-interleave.cc \ - util/bits/bits.cc \ - util/coding/coder.cc \ - util/coding/varint.cc \ - util/hash/city.cc \ - util/hash/hash.cc \ - util/hash/jenkins.cc \ - util/hash/murmur.cc \ - util/math/mathutil.cc \ - util/math/mathlimits.cc \ - util/math/exactfloat/exactfloat.cc \ - s1angle.cc \ - s1chordangle.cc \ - s2.cc \ - s2cellid.cc \ - s2latlng.cc \ - r2rect.cc \ - s1interval.cc \ - s2cap.cc \ - s2cell.cc \ - s2cellunion.cc \ - s2closestedgequery.cc \ - s2edgequery.cc \ - s2edgeutil.cc \ - s2error.cc \ - s2latlngrect.cc \ - s2loop.cc \ - s2paddedcell.cc \ - s2pointcompression.cc \ - s2pointregion.cc \ - s2polygon.cc \ - s2polygonbuilder.cc \ - s2polyline.cc \ - s2r2rect.cc \ - s2region.cc \ - s2regioncoverer.cc \ - s2regionintersection.cc \ - s2regionunion.cc \ - s2shapeindex.cc \ - s2shapeutil.cc \ - s2testing.cc - -TEST_CXXFLAGS = \ - -I$(top_srcdir)/gtest/include -I$(top_srcdir)/gtest \ - -std=c++11 -Wno-deprecated -TEST_LDADD = $(lib_LTLIBRARIES) $(check_LIBRARIES) -lpthread - -libgtest_a_SOURCES = \ - gtest/src/gtest-all.cc \ - gtest/src/gtest_main.cc -libgtest_a_CXXFLAGS = $(TEST_CXXFLAGS) - -TESTS = \ - r1interval_test \ - r2rect_test \ - s1angle_test \ - s1interval_test \ - s2_test \ - s2cap_test \ - s2cell_test \ - s2cellid_test \ - s2cellunion_test \ - s2edgequery_test \ - s2edgeutil_test \ - s2latlng_test \ - s2latlngrect_test \ - s2loop_test \ - s2paddedcell_test \ - s2pointcompression_test \ - s2pointregion_test \ - s2polygon_test \ - s2polygonbuilder_test \ - s2polyline_test \ - s2r2rect_test \ - s2regioncoverer_test \ - s2regionunion_test \ - s2shapeindex_test \ - s2shapeutil_test \ - s2testing_test - -check_PROGRAMS = $(TESTS) - -r1interval_test_SOURCES = r1interval_test.cc -r1interval_test_CXXFLAGS = $(TEST_CXXFLAGS) -r1interval_test_LDADD = $(TEST_LDADD) - -r2rect_test_SOURCES = r2rect_test.cc -r2rect_test_CXXFLAGS = $(TEST_CXXFLAGS) -r2rect_test_LDADD = $(TEST_LDADD) - -s1angle_test_SOURCES = s1angle_test.cc -s1angle_test_CXXFLAGS = $(TEST_CXXFLAGS) -s1angle_test_LDADD = $(TEST_LDADD) - -s1interval_test_SOURCES = s1interval_test.cc -s1interval_test_CXXFLAGS = $(TEST_CXXFLAGS) -s1interval_test_LDADD = $(TEST_LDADD) - -s2_test_SOURCES = s2_test.cc -s2_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2_test_LDADD = $(TEST_LDADD) - -s2cap_test_SOURCES = s2cap_test.cc -s2cap_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2cap_test_LDADD = $(TEST_LDADD) - -s2cell_test_SOURCES = s2cell_test.cc -s2cell_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2cell_test_LDADD = $(TEST_LDADD) - -s2cellid_test_SOURCES = s2cellid_test.cc -s2cellid_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2cellid_test_LDADD = $(TEST_LDADD) - -s2cellunion_test_SOURCES = s2cellunion_test.cc -s2cellunion_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2cellunion_test_LDADD = $(TEST_LDADD) - -s2edgequery_test_SOURCES = s2edgequery_test.cc -s2edgequery_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2edgequery_test_LDADD = $(TEST_LDADD) - -s2edgeutil_test_SOURCES = s2edgeutil_test.cc -s2edgeutil_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2edgeutil_test_LDADD = $(TEST_LDADD) - -s2latlng_test_SOURCES = s2latlng_test.cc -s2latlng_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2latlng_test_LDADD = $(TEST_LDADD) - -s2latlngrect_test_SOURCES = s2latlngrect_test.cc -s2latlngrect_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2latlngrect_test_LDADD = $(TEST_LDADD) - -s2loop_test_SOURCES = s2loop_test.cc -s2loop_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2loop_test_LDADD = $(TEST_LDADD) - -s2paddedcell_test_SOURCES = s2paddedcell_test.cc -s2paddedcell_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2paddedcell_test_LDADD = $(TEST_LDADD) - -s2pointcompression_test_SOURCES = s2pointcompression_test.cc -s2pointcompression_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2pointcompression_test_LDADD = $(TEST_LDADD) - -s2pointregion_test_SOURCES = s2pointregion_test.cc -s2pointregion_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2pointregion_test_LDADD = $(TEST_LDADD) - -s2polygon_test_SOURCES = s2polygon_test.cc -s2polygon_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2polygon_test_LDADD = $(TEST_LDADD) - -s2polygonbuilder_test_SOURCES = s2polygonbuilder_test.cc -s2polygonbuilder_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2polygonbuilder_test_LDADD = $(TEST_LDADD) - -s2polyline_test_SOURCES = s2polyline_test.cc -s2polyline_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2polyline_test_LDADD = $(TEST_LDADD) - -s2r2rect_test_SOURCES = s2r2rect_test.cc -s2r2rect_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2r2rect_test_LDADD = $(TEST_LDADD) - -s2regioncoverer_test_SOURCES = s2regioncoverer_test.cc -s2regioncoverer_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2regioncoverer_test_LDADD = $(TEST_LDADD) - -s2regionunion_test_SOURCES = s2regionunion_test.cc -s2regionunion_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2regionunion_test_LDADD = $(TEST_LDADD) - -s2shapeindex_test_SOURCES = s2shapeindex_test.cc -s2shapeindex_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2shapeindex_test_LDADD = $(TEST_LDADD) - -s2shapeutil_test_SOURCES = s2shapeutil_test.cc -s2shapeutil_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2shapeutil_test_LDADD = $(TEST_LDADD) - -s2testing_test_SOURCES = s2testing_test.cc -s2testing_test_CXXFLAGS = $(TEST_CXXFLAGS) -s2testing_test_LDADD = $(TEST_LDADD) diff --git a/src/base/atomicops.h b/src/base/atomicops.h index 0d26afa6..ee027625 100644 --- a/src/base/atomicops.h +++ b/src/base/atomicops.h @@ -12,8 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#ifndef UTIL_GEOMETRY_OPENSOURCE_BASE_ATOMICOPS_H_ -#define UTIL_GEOMETRY_OPENSOURCE_BASE_ATOMICOPS_H_ + +#ifndef BASE_ATOMICOPS_H_ +#define BASE_ATOMICOPS_H_ #include @@ -46,4 +47,4 @@ inline void Release_Store(Atomic32* atomic, int32_t value) { } // namespace subtle } // namespace base -#endif // UTIL_GEOMETRY_OPENSOURCE_BASE_ATOMICOPS_H_ \ No newline at end of file +#endif // BASE_ATOMICOPS_H_ diff --git a/src/base/casts.h b/src/base/casts.h index a54f3cb4..ab88b3b7 100644 --- a/src/base/casts.h +++ b/src/base/casts.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // Various Google-specific casting templates. // @@ -103,8 +104,8 @@ inline To down_cast(From* f) { // so we only accept pointers // compiler will just bind From to const T. template inline To down_cast(From& f) { - COMPILE_ASSERT(base::is_reference::value, target_type_not_a_reference); - typedef typename base::remove_reference::type* ToAsPointer; + COMPILE_ASSERT(std::is_reference::value, target_type_not_a_reference); + typedef typename std::remove_reference::type* ToAsPointer; if (false) { // Compile-time check that To inherits from From. See above for details. ::implicit_cast(NULL); @@ -403,4 +404,4 @@ inline Enum tight_enum_cast(int e_val) { return static_cast(e_val); } -#endif // BASE_CASTS_H_ \ No newline at end of file +#endif // BASE_CASTS_H_ diff --git a/src/base/int128.cc b/src/base/int128.cc index 248c8639..edb94dcf 100644 --- a/src/base/int128.cc +++ b/src/base/int128.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // All Rights Reserved. // @@ -86,22 +87,20 @@ void uint128::DivModImpl(uint128 dividend, uint128 divisor, } uint128 denominator = divisor; - uint128 position = 1; uint128 quotient = 0; // Left aligns the MSB of the denominator and the dividend. - int shift = Fls128(dividend) - Fls128(denominator); + const int shift = Fls128(dividend) - Fls128(denominator); denominator <<= shift; - position <<= shift; // Uses shift-subtract algorithm to divide dividend by denominator. The // remainder will be left in dividend. - while (position > 0) { + for (int i = 0; i <= shift; ++i) { + quotient <<= 1; if (dividend >= denominator) { dividend -= denominator; - quotient |= position; + quotient |= 1; } - position >>= 1; denominator >>= 1; } @@ -181,4 +180,4 @@ std::ostream& operator<<(std::ostream& o, const uint128& b) { // Stream the final representation in a single "<<" call. return o << rep; -} \ No newline at end of file +} diff --git a/src/base/int128.h b/src/base/int128.h index 83abdcd0..0760725d 100644 --- a/src/base/int128.h +++ b/src/base/int128.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // All Rights Reserved. // @@ -358,4 +359,4 @@ inline uint128& uint128::operator--() { return *this; } -#endif // BASE_INT128_H_ \ No newline at end of file +#endif // BASE_INT128_H_ diff --git a/src/base/integral_types.h b/src/base/integral_types.h index 09fbef9b..9a232b95 100644 --- a/src/base/integral_types.h +++ b/src/base/integral_types.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // Basic integer type definitions for various platforms // @@ -116,4 +117,4 @@ typedef uint64 Fprint; static const Fprint kIllegalFprint = 0; static const Fprint kMaxFprint = GG_ULONGLONG(0xFFFFFFFFFFFFFFFF); -#endif // BASE_INTEGRAL_TYPES_H_ \ No newline at end of file +#endif // BASE_INTEGRAL_TYPES_H_ diff --git a/src/base/macros.h b/src/base/macros.h index 3c6d6a0b..16ed1ac2 100644 --- a/src/base/macros.h +++ b/src/base/macros.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // Various Google-specific macros. // @@ -106,8 +107,8 @@ // semantically, one should either use disallow both or neither. Try to // avoid these in new code. // -// When building with C++11 toolchains, just use the language support -// for explicitly deleted methods. +// When building with C++11 toolchains, users should consider using the language +// support for explicitly deleted methods instead of this macro. #if LANG_CXX11 #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&) = delete; \ @@ -352,4 +353,4 @@ enum LinkerInitialized { LINKER_INITIALIZED }; # endif #endif -#endif // BASE_MACROS_H_ \ No newline at end of file +#endif // BASE_MACROS_H_ diff --git a/src/base/mutex.h b/src/base/mutex.h index a0ec6b2c..f26c38f4 100644 --- a/src/base/mutex.h +++ b/src/base/mutex.h @@ -12,26 +12,25 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#ifndef UTIL_GEOMETRY_OPENSOURCE_BASE_MUTEX_H_ -#define UTIL_GEOMETRY_OPENSOURCE_BASE_MUTEX_H_ + +#ifndef BASE_MUTEX_H_ +#define BASE_MUTEX_H_ #include #include class Mutex { public: - inline Mutex() : lock_(mutex_, std::defer_lock) {} + Mutex() = default; ~Mutex() = default; Mutex(Mutex const&) = delete; Mutex& operator=(Mutex const&) = delete; - inline void Lock() { lock_.lock(); } - inline void Unlock() { lock_.unlock(); } + inline void Lock() { mutex_.lock(); } + inline void Unlock() { mutex_.unlock(); } private: std::mutex mutex_; - // Use unique_lock because we need to interact with condition_variables. - std::unique_lock lock_; friend class CondVar; }; @@ -43,7 +42,11 @@ class CondVar { CondVar(CondVar const&) = delete; CondVar& operator=(CondVar const&) = delete; - inline void Wait(Mutex* mu) { cond_var_.wait(mu->lock_); }; + inline void Wait(Mutex* mu) { + std::unique_lock lock(mu->mutex_, std::adopt_lock); + cond_var_.wait(lock); + lock.release(); + } inline void Signal() { cond_var_.notify_one(); } inline void SignalAll() { cond_var_.notify_all(); } @@ -51,4 +54,4 @@ class CondVar { std::condition_variable cond_var_; }; -#endif // UTIL_GEOMETRY_OPENSOURCE_BASE_MUTEX_H_ \ No newline at end of file +#endif // BASE_MUTEX_H_ diff --git a/src/base/port.h b/src/base/port.h index fba8c22e..f0cb5ec7 100644 --- a/src/base/port.h +++ b/src/base/port.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // // @@ -27,6 +28,18 @@ #include // for free() #if defined(__APPLE__) +// traditionally defined __APPLE__ themselves via other build systems, since mac +// TODO(user): Remove this when all toolchains make the proper defines. +#include +#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE +#ifndef OS_IOS +#define OS_IOS 1 +#endif +#define SUPPRESS_MOBILE_IOS_BASE_PORT_H +#endif // defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE +#endif // defined(__APPLE__) + +#if defined(__APPLE__) || defined(OS_IOS) #include // for getpagesize() on mac #elif defined(OS_CYGWIN) || defined(__ANDROID__) #include // for memalign() @@ -36,16 +49,16 @@ #include "base/integral_types.h" -// We support gcc 4.4 and later. +// We support gcc 4.6 and later. #if defined(__GNUC__) && !defined(__clang__) -#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4) -#error "This package requires gcc 4.4 or higher" +#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6) +#error "This package requires gcc 4.6 or higher" #endif #endif -// We support MSVC++ 10.0 and later. -#if defined(_MSC_VER) && _MSC_VER < 1600 -#error "This package requires _MSC_VER of 1600 or higher" +// We support MSVC++ 12.0 and later. +#if defined(_MSC_VER) && _MSC_VER < 1800 +#error "This package requires _MSC_VER of 1800 or higher" #endif // We support Apple Xcode clang 4.2.1 (version 421.11.65) and later. @@ -68,10 +81,13 @@ /* We use SIGPWR since that seems unlikely to be used for other reasons. */ #define GOOGLE_OBSCURE_SIGNAL SIGPWR -#if defined OS_LINUX || defined OS_CYGWIN - +#if defined OS_LINUX || defined OS_CYGWIN || defined OS_ANDROID || \ + defined(__ANDROID__) // _BIG_ENDIAN #include +#endif + +#if defined OS_LINUX || defined OS_CYGWIN // GLIBC-related macros. #include @@ -117,7 +133,7 @@ typedef unsigned long ulong; // _BIG_ENDIAN #include -#elif defined __APPLE__ +#elif defined(__APPLE__) || defined(OS_IOS) // BIG_ENDIAN #include // NOLINT(build/include) @@ -137,7 +153,7 @@ typedef unsigned long ulong; #define bswap_32(x) _byteswap_ulong(x) #define bswap_64(x) _byteswap_uint64(x) -#elif defined(__APPLE__) +#elif defined(__APPLE__) || defined(OS_IOS) // Mac OS X / Darwin features #include #define bswap_16(x) OSSwapInt16(x) @@ -237,9 +253,9 @@ typedef int uid_t; #endif -// Mac OS X / Darwin features +// Mac OS X / Darwin and iOS features -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(OS_IOS) // For mmap, Linux defines both MAP_ANONYMOUS and MAP_ANON and says MAP_ANON is // deprecated. In Darwin, MAP_ANON is all there is. @@ -321,7 +337,9 @@ inline size_t strnlen(const char *s, size_t maxlen) { return maxlen; } +#if !defined(OS_IOS) namespace std {} // Avoid error if we didn't see std. +#endif // Doesn't exist on OSX. #define MSG_NOSIGNAL 0 @@ -375,7 +393,8 @@ inline void* memrchr(const void* bytes, int find_char, size_t len) { // GCC-specific features -#if (defined(__GNUC__) || defined(__APPLE__)) && !defined(SWIG) +#if (defined(__GNUC__) || defined(__APPLE__) || defined(OS_IOS)) && \ + !defined(SWIG) // // Tell the compiler to do printf format string checking if the @@ -391,11 +410,6 @@ inline void* memrchr(const void* bytes, int find_char, size_t len) { #define SCANF_ATTRIBUTE(string_index, first_to_check) \ __attribute__((__format__ (__scanf__, string_index, first_to_check))) -// -// Prevent the compiler from padding a structure to natural alignment -// -#define PACKED __attribute__ ((packed)) - // Cache line alignment #if defined(__i386__) || defined(__x86_64__) #define CACHELINE_SIZE 64 @@ -510,6 +524,14 @@ inline void* memrchr(const void* bytes, int find_char, size_t len) { #define ATTRIBUTE_NO_SANITIZE_MEMORY #endif +// Tell ThreadSanitizer to not instrument a given function. +// If you are adding this attribute, please cc dynamic-tools@ on the cl. +#ifdef THREAD_SANITIZER +#define ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread)) +#else +#define ATTRIBUTE_NO_SANITIZE_THREAD +#endif + #ifndef HAVE_ATTRIBUTE_SECTION // may have been pre-set to 0, e.g. for Darwin #define HAVE_ATTRIBUTE_SECTION 1 #endif @@ -585,6 +607,16 @@ inline void* memrchr(const void* bytes, int find_char, size_t len) { #define MUST_USE_RESULT #endif +// +// Prevent the compiler from padding a structure to natural alignment +// +#if __GNUC__ && !defined(SWIG) +#define ATTRIBUTE_PACKED __attribute__((__packed__)) +#else +#define ATTRIBUTE_PACKED +#endif + + #if defined(__GNUC__) || defined(__llvm__) // Defined behavior on some of the uarchs: // PREFETCH_HINT_T0: @@ -603,6 +635,11 @@ enum PrefetchHint { // prefetch is a no-op for this target. Feel free to add more sections above. #endif +// The default behavior of prefetch is to speculatively load for read only. This +// is safe for all currently supported platforms. However, prefetch for store +// may have problems depending on the target platform (x86, PPC, arm). Check +// with the platforms team (platforms-servers@) before introducing any changes +// to this function to identify potential impact on current and future servers. extern inline void prefetch(const void *x, int hint) { #if defined(__llvm__) // In the gcc version of prefetch(), hint is only a constant _after_ inlining @@ -703,7 +740,6 @@ extern inline void prefetch(const void *x) { #define PRINTF_ATTRIBUTE(string_index, first_to_check) #define SCANF_ATTRIBUTE(string_index, first_to_check) -#define PACKED #define CACHELINE_SIZE 64 #define CACHELINE_ALIGNED #define ATTRIBUTE_UNUSED @@ -719,6 +755,7 @@ extern inline void prefetch(const void *x) { #define ATTRIBUTE_NO_SANITIZE_ADDRESS #define ATTRIBUTE_NO_SANITIZE_MEMORY #define HAVE_ATTRIBUTE_SECTION 0 +#define ATTRIBUTE_PACKED #define ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC #define REQUIRE_STACK_ALIGN_TRAMPOLINE (0) #define MUST_USE_RESULT @@ -733,10 +770,12 @@ extern inline void prefetch(const void*) {} #endif // GCC -#if ((defined(__GNUC__) || defined(__APPLE__)) && !defined(SWIG)) || \ +#if ((defined(__GNUC__) || defined(__APPLE__) || defined(OS_IOS) || \ + defined(__NVCC__)) && !defined(SWIG)) || \ ((__GNUC__ >= 3 || defined(__clang__)) && defined(__ANDROID__)) -#if !defined(__cplusplus) && !defined(__APPLE__) && !defined(OS_CYGWIN) +#if !defined(__cplusplus) && !defined(__APPLE__) && !defined(OS_IOS) && \ + !defined(OS_CYGWIN) // stdlib.h only declares this in C++, not in C, so we declare it here. // Also make sure to avoid declaring it on platforms which don't support it. extern int posix_memalign(void **memptr, size_t alignment, size_t size); @@ -776,7 +815,8 @@ inline void aligned_free(void *aligned_memory) { } #endif -// #if ((defined(__GNUC__) || defined(__APPLE__)) && !defined(SWIG)) || +// #if ((defined(__GNUC__) || defined(__APPLE__) || defined(OS_IOS) || +// defined(__NVCC__)) && !defined(SWIG)) || // ((__GNUC__ >= 3 || defined(__clang__)) && defined(__ANDROID__)) // @@ -1095,9 +1135,9 @@ typedef short int16_t; struct PortableHashBase { }; #endif -#if defined(OS_WINDOWS) || defined(__APPLE__) +#if defined(OS_WINDOWS) || defined(__APPLE__) || defined(OS_IOS) // gethostbyname() *is* thread-safe for Windows native threads. It is also -// safe on Mac OS X, where it uses thread-local storage, even though the +// safe on Mac OS X and iOS, where it uses thread-local storage, even though the // manpages claim otherwise. For details, see // http://lists.apple.com/archives/Darwin-dev/2006/May/msg00008.html #else @@ -1123,7 +1163,7 @@ struct PortableHashBase { }; #if defined(__GNUC__) && defined(GOOGLE_GLIBCXX_VERSION) // Crosstool v17 or later. #define HASH_NAMESPACE __gnu_cxx -#elif defined(__GNUC__) && defined(STLPORT) +#elif defined(__GNUC__) && (defined(STLPORT) || defined(USE_STD_HASH)) // A version of gcc with stlport. #define HASH_NAMESPACE std #define HASH_NAMESPACE_IS_STD_NAMESPACE_INTERNAL @@ -1153,7 +1193,8 @@ struct PortableHashBase { }; #endif // Our STL-like classes use __STD. -#if defined(__GNUC__) || defined(__APPLE__) || defined(_MSC_VER) +#if defined(__GNUC__) || defined(__APPLE__) || defined(OS_IOS) || \ + defined(_MSC_VER) #define __STD std #endif @@ -1168,6 +1209,13 @@ struct PortableHashBase { }; // Portable handling of unaligned loads, stores, and copies. // On some platforms, like ARM, the copy functions can be more efficient // then a load and a store. +// +// It is possible to implement all of these these using constant-length memcpy +// calls, which is portable and will usually be inlined into simple loads and +// stores if the architecture supports it. However, such inlining usually +// happens in a pass that's quite late in compilation, which means the resulting +// loads and stores cannot participate in many other optimizations, leading to +// overall worse code. #if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||\ defined(MEMORY_SANITIZER) @@ -1259,12 +1307,43 @@ inline void UNALIGNED_STORE64(void *p, uint64 v) { // so in time, maybe we can move on to that. // // This is a mess, but there's not much we can do about it. - -#define UNALIGNED_LOAD16(_p) (*reinterpret_cast(_p)) -#define UNALIGNED_LOAD32(_p) (*reinterpret_cast(_p)) - -#define UNALIGNED_STORE16(_p, _val) (*reinterpret_cast(_p) = (_val)) -#define UNALIGNED_STORE32(_p, _val) (*reinterpret_cast(_p) = (_val)) +// +// To further complicate matters, only LDR instructions (single reads) are +// allowed to be unaligned, not LDRD (two reads) or LDM (many reads). Unless we +// explicitly tell the compiler that these accesses can be unaligned, it can and +// will combine accesses. On armcc, the way to signal this is done by accessing +// through the type (uint32 __packed *), but GCC has no such attribute +// (it ignores __attribute__((packed)) on individual variables). However, +// we can tell it that a _struct_ is unaligned, which has the same effect, +// so we do that. + +namespace base { +namespace internal { + +struct Unaligned16Struct { + uint16 value; + uint8 dummy; // To make the size non-power-of-two. +} ATTRIBUTE_PACKED; + +struct Unaligned32Struct { + uint32 value; + uint8 dummy; // To make the size non-power-of-two. +} ATTRIBUTE_PACKED; + +} // namespace internal +} // namespace base + +#define UNALIGNED_LOAD16(_p) \ + ((reinterpret_cast(_p))->value) +#define UNALIGNED_LOAD32(_p) \ + ((reinterpret_cast(_p))->value) + +#define UNALIGNED_STORE16(_p, _val) \ + ((reinterpret_cast< ::base::internal::Unaligned16Struct *>(_p))->value = \ + (_val)) +#define UNALIGNED_STORE32(_p, _val) \ + ((reinterpret_cast< ::base::internal::Unaligned32Struct *>(_p))->value = \ + (_val)) // TODO(user): NEON supports unaligned 64-bit loads and stores. // See if that would be more efficient on platforms supporting it, @@ -1357,7 +1436,7 @@ inline void UnalignedCopy64(const void *src, void *dst) { #endif // defined(__cpluscplus) // printf macros for size_t, in the style of inttypes.h -#ifdef _LP64 +#if defined(_LP64) || defined(OS_IOS) #define __PRIS_PREFIX "z" #else #define __PRIS_PREFIX @@ -1401,8 +1480,10 @@ std::ostream& operator << (std::ostream& out, const pthread_t& thread_id); // in gcc before 4.7 (Crosstool 16) and clang before 3.1, but is // defined according to the language version in effect thereafter. I // believe MSVC will also define __cplusplus according to the language -// version, but haven't checked that. -#if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L +// version, but haven't checked that. Stlport is used by many Android projects +// and does not have full C++11 STL support. +#if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L) && \ + !defined(STLPORT) // Define this to 1 if the code is compiled in C++11 mode; leave it // undefined otherwise. Do NOT define it to 0 -- that causes // '#ifdef LANG_CXX11' to behave differently from '#if LANG_CXX11'. @@ -1502,4 +1583,3 @@ using std::string; #endif // SWIG, __cplusplus #endif // BASE_PORT_H_ - diff --git a/src/base/port_hash.h b/src/base/port_hash.h index 09b4ab77..bf482ff5 100644 --- a/src/base/port_hash.h +++ b/src/base/port_hash.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // // Author: Jeffrey Rennie @@ -70,19 +71,6 @@ template<> struct hash { } }; -// Avoid collision with definition in util/hash/hash.h. -// Please include that file if you need this specialization. -// TODO(koda): Remove this after making its users include hash.h. -#if !defined(HAVE_DEFINED_HASH_FOR_POINTERS) && !defined(LIBCXX) -#define HAVE_DEFINED_HASH_FOR_POINTERS -template struct hash { - size_t operator()(T *x) const { - size_t k = reinterpret_cast(x); - return k + (k >> 6); - } -}; -#endif - // If the 3rd template parameter of the GNU interface (KeyEqual) is // omitted, then we know that it's using the == operator, so we can // safely use the < operator. @@ -154,4 +142,4 @@ class hash_multimap : public NATIVE_HASH_NAMESPACE } // end namespace msvchash -#endif // BASE_PORT_HASH_H_ \ No newline at end of file +#endif // BASE_PORT_HASH_H_ diff --git a/src/base/scoped_ptr.h b/src/base/scoped_ptr.h deleted file mode 100644 index 80294682..00000000 --- a/src/base/scoped_ptr.h +++ /dev/null @@ -1,357 +0,0 @@ -// Copyright 2007 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// All Rights Reserved. -// -// -#ifndef BASE_SCOPED_PTR_H__ -#define BASE_SCOPED_PTR_H__ - -// This implementation was designed to match the then-anticipated TR2 -// implementation of the scoped_ptr class, and its closely-related brethren, -// scoped_array and scoped_ptr_malloc. The anticipated standardization of -// scoped_ptr has been superseded by unique_ptr, and the APIs in this file are -// being revised to be a subset of unique_ptr, as a step towards replacing them -// -// drove this file. - -#include -#include -#include - -#include "base/port.h" -#include "base/scoped_ptr_internals.h" -#include "base/type_traits.h" - -#ifdef OS_EMBEDDED_QNX -// NOTE(user): -// The C++ standard says that declares both ::foo and std::foo -// But this isn't done in QNX version 6.3.2 200709062316. -using std::free; -using std::malloc; -using std::realloc; -#endif - -template class scoped_ptr; - -namespace base { - -namespace internal { - -// Function object which deletes its parameter, which must be a pointer. -// If C is an array type, invokes 'delete[]' on the parameter; otherwise, -// invokes 'delete'. The default deleter for scoped_ptr. -// -// This class should be considered an implementation detail of scoped_ptr; -template -struct DefaultDeleter { - inline void operator()(C* ptr) const { - enum { type_must_be_complete = sizeof(C) }; - delete ptr; - } -}; - -// Specialization of DefaultDeleter for array types. -template -struct DefaultDeleter { - inline void operator()(C* ptr) const { - enum { type_must_be_complete = sizeof(C) }; - delete[] ptr; - } -}; - -} // namespace internal -} // namespace base - -// A scoped_ptr is like a T*, except that the destructor of scoped_ptr -// automatically deletes the pointer it holds (if any). -// That is, scoped_ptr owns the T object that it points to. -// Like a T*, a scoped_ptr may hold either NULL or a pointer to a T object. -// Also like T*, scoped_ptr is thread-compatible, and once you -// dereference it, you get the threadsafety guarantees of T. -// -// By default, scoped_ptr deletes its stored pointer using 'delete', but -// this behavior can be customized via the second template parameter: -// A scoped_ptr invokes D::operator() on the stored pointer when the -// scoped_ptr is destroyed. For example, a -// scoped_ptr can be used to store pointers to -// memory allocated with malloc(). Note that scoped_ptr will not invoke D on -// a NULL pointer. -// -// If D is an empty class (i.e. has no non-static data members), then -// on most compilers, scoped_ptr is the same size as a plain pointer. -// Otherwise, it will be at least as large as sizeof(C*) + sizeof(D). -template > -class scoped_ptr { - public: - - // The element type - typedef C element_type; - typedef D deleter_type; - - // Constructor. Defaults to initializing with NULL. - // There is no way to create an uninitialized scoped_ptr. - scoped_ptr() : impl_(NULL) { } - explicit scoped_ptr(C* p) : impl_(p) { } - -#ifdef LANG_CXX11 - // Constructor. Initializes with NULL. There is no way to create an - // uninitialized scoped_ptr. - explicit scoped_ptr(std::nullptr_t) : impl_(NULL) {} -#endif - - // Reset. Deletes the current owned object, if any. - // Then takes ownership of a new object, if given. - // Note that this->reset(this->get()) will not work except for the trivial - // case (this->get() == nullptr). - void reset(C* p = NULL) { - impl_.reset(p); - } - - // Accessors to get the owned object. - // operator* and operator-> will assert() if there is no current object. - C& operator*() const { - assert(impl_.get() != NULL); - return *impl_.get(); - } - C* operator->() const { - assert(impl_.get() != NULL); - return impl_.get(); - } - C* get() const { return impl_.get(); } - - // Comparison operators. - // These return whether a scoped_ptr and a raw pointer refer to - // the same object, not just to two different but equal objects. - bool operator==(const C* p) const { return impl_.get() == p; } - bool operator!=(const C* p) const { return impl_.get() != p; } - - // Swap two scoped pointers. - void swap(scoped_ptr& p2) { - impl_.swap(p2.impl_); - } - - // Release a pointer. - // The return value is the current pointer held by this object. - // If this object holds a NULL pointer, the return value is NULL. - // After this operation, this object will hold a NULL pointer, - // and will not own the object any more. - // - // CAVEAT: It is incorrect to use and release a pointer in one statement, eg. - // objects[ptr->name()] = ptr.release(); - // as it is undefined whether the .release() or ->name() runs first. - C* release() { - return impl_.release(); - } - - private: - base::internal::scoped_ptr_impl impl_; - - // Forbid construction with explicit NULL or 0 (either use the no-argument - // constructor or use nullptr). This is because in C++11 it is ambiguous to - // construct unique_ptr with NULL or 0, and we're in the process of - // transitioning from scoped_ptr to unique_ptr. This struct and constructor - // make it ambiguous to construct a scoped_ptr with NULL in C++98. A struct - // with an implicit constructor which takes a pointer is used instead of just - // a pointer so that it is not ambiguous to construct a scoped_ptr with the - // result of util::gtl::NewContainer(). - struct do_not_construct_scoped_ptr_with_explicit_NULL_or_0 { - do_not_construct_scoped_ptr_with_explicit_NULL_or_0( - do_not_construct_scoped_ptr_with_explicit_NULL_or_0*) {} - }; - explicit scoped_ptr(do_not_construct_scoped_ptr_with_explicit_NULL_or_0) - : impl_(NULL) {} - - // Forbid comparison of scoped_ptr types. If C2 != C, it totally doesn't - // make sense, and if C2 == C, it still doesn't make sense because you should - // never have the same object owned by two different scoped_ptrs. - template bool operator==( - scoped_ptr const& p2) const; - template bool operator!=( - scoped_ptr const& p2) const; - - // Disallow copy and assignment. - scoped_ptr(const scoped_ptr&); - void operator=(const scoped_ptr&); -}; - -// Free functions -template -inline void swap(scoped_ptr& p1, scoped_ptr& p2) { - p1.swap(p2); -} - -template -inline bool operator==(const C* p1, const scoped_ptr& p2) { - return p1 == p2.get(); -} - -template -inline bool operator==(const C* p1, const scoped_ptr& p2) { - return p1 == p2.get(); -} - -template -inline bool operator!=(const C* p1, const scoped_ptr& p2) { - return p1 != p2.get(); -} - -template -inline bool operator!=(const C* p1, const scoped_ptr& p2) { - return p1 != p2.get(); -} - -// Specialization of scoped_ptr used for holding arrays: -// -// scoped_ptr array(new int[10]); -// -// This specialization provides operator[] instead of operator* and -// operator->, and by default it deletes the stored array using 'delete[]' -// rather than 'delete'. It also provides some additional type-safety: -// the pointer used to initialize a scoped_ptr must have type T* and -// not, for example, some class derived from T; this helps avoid -// accessing an array through a pointer whose dynamic type is different -// from its static type, which can lead to undefined behavior. -template -class scoped_ptr { - public: - - // The element type - typedef C element_type; - typedef D deleter_type; - - // Default constructor. Initializes stored pointer to NULL. - // There is no way to create an uninitialized scoped_ptr. - scoped_ptr() : impl_(NULL) { } - - // Constructor. Stores the given array. Note that the type of 'array' must - // be exactly C* (possibly with top-level 'const' or 'volatile' removed). - // In particular: - // - It cannot be a pointer to a type derived from C, because it is - // inherently unsafe to access an array through a pointer whose dynamic - // type does not match its static type. - // - It cannot be NULL, because NULL is an integral expression, not a C*. - // Use the no-argument version instead of explicitly passing NULL. - // - Similarly, it cannot be nullptr, because nullptr has type nullptr_t. - // - It cannot be const-qualified differently from C. There is no principled - // reason for this; it's an artifact of how the above restrictions are - // implemented. As a convenience exception, if C has a top-level 'const' or - // 'volatile' qualifier, we permit the argument to remove that qualifier, - // so you can do things like - // - // scoped_ptr arr(new Foo[10]); - // - // If this exception does not cover your case, you can work around it - // with implicit_cast (from base/casts.h): - // - // const Foo** i; - // ... - // scoped_ptr arr(implicit_cast(new Foo*[10])); - template - explicit scoped_ptr(T* array) : impl_(array) { - static_assert((base::is_same::type, - typename base::remove_cv::type>::value), - "scoped_ptr initialized from type other than T*."); - } - - // Reset. Deletes the current owned object, if any, then takes ownership of - // the new object, if given. Note that the type of 'array' must exactly - // match C; see the comments on the constructor for details. - // Note that this->reset(this->get()) will not work except for the trivial - // case (this->get() == nullptr). - template - void reset(T* array) { - static_assert((base::is_same::type, - typename base::remove_cv::type>::value), - "scoped_ptr initialized from type other than T*."); - impl_.reset(array); - } - - void reset() { - impl_.reset(NULL); - } - - // Array indexing operation. Returns the specified element of the underlying - // array. Will assert if no array is currently stored. - C& operator[] (size_t i) const { - assert(impl_.get() != NULL); - return impl_.get()[i]; - } - - C* get() const { return impl_.get(); } - - // Comparison operators. - // These return whether a scoped_ptr and a raw pointer refer to - // the same object, not just to two different but equal objects. - bool operator==(const C* array) const { return impl_.get() == array; } - bool operator!=(const C* array) const { return impl_.get() != array; } - - // Swap two scoped pointers. - void swap(scoped_ptr& p2) { - impl_.swap(p2.impl_); - } - - // Release a pointer. - // The return value is a pointer to the array currently held by this object. - // If this object holds a NULL pointer, the return value is NULL. - // After this operation, this object will hold a NULL pointer, - // and will not own the array any more. - // - // CAVEAT: It is incorrect to use and release a pointer in one statement, eg. - // objects[ptr->name()] = ptr.release(); - // as it is undefined whether the .release() or ->name() runs first. - C* release() { - return impl_.release(); - } - - private: - // Force C to be a complete type. - enum { type_must_be_complete = sizeof(C) }; - - base::internal::scoped_ptr_impl impl_; - - // Forbid comparison of scoped_ptr types. If C2 != C, it totally doesn't - // make sense, and if C2 == C, it still doesn't make sense because you should - // never have the same object owned by two different scoped_ptrs. - template bool operator==( - scoped_ptr const& p2) const; - template bool operator!=( - scoped_ptr const& p2) const; - - // Disallow copy and assignment. - scoped_ptr(const scoped_ptr&); - void operator=(const scoped_ptr&); -}; - -template -inline bool operator==(const C* p1, const scoped_ptr& p2) { - return p1 == p2.get(); -} - -template -inline bool operator==(const C* p1, const scoped_ptr& p2) { - return p1 == p2.get(); -} - -template -inline bool operator!=(const C* p1, const scoped_ptr& p2) { - return p1 != p2.get(); -} - -template -inline bool operator!=(const C* p1, const scoped_ptr& p2) { - return p1 != p2.get(); -} - -#endif // BASE_SCOPED_PTR_H__ \ No newline at end of file diff --git a/src/base/scoped_ptr_internals.h b/src/base/scoped_ptr_internals.h deleted file mode 100644 index bd84d67c..00000000 --- a/src/base/scoped_ptr_internals.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// -// DO NOT INCLUDE THIS FILE. It contains implementation details of -// scoped_ptr and related classes; its contents, as well as the file -// itself, should be considered implementation details of scoped_ptr.h - -#ifndef BASE_SCOPED_PTR_INTERNALS_H_ -#define BASE_SCOPED_PTR_INTERNALS_H_ - -#include // for std::swap - -namespace base { -namespace internal { - - -// Minimal implementation of the core logic of scoped_ptr, suitable for -// reuse in both scoped_ptr and its specialization. -template -class scoped_ptr_impl { - public: - explicit scoped_ptr_impl(C* p) : data_(p) { } - - ~scoped_ptr_impl() { - if (data_.ptr != NULL) { - (static_cast(data_))(data_.ptr); - } - } - - void reset(C* p) { - if (data_.ptr != NULL) { - // Note that this can lead to undefined behavior and memory leaks - // in the unlikely but possible case that get_deleter()(get()) - // indirectly deletes this. The fix is to reset ptr_ before deleting - // its old value, but first we need to clean up the code that relies - // on the current sequencing. - (static_cast(data_))(data_.ptr); - } - data_.ptr = p; - } - - C* get() const { return data_.ptr; } - - void swap(scoped_ptr_impl& p2) { - // Standard swap idiom: 'using std::swap' ensures that std::swap is - // present in the overload set, but we call swap unqualified so that - // any more-specific overloads can be used, if available. - using std::swap; - swap(static_cast(data_), static_cast(p2.data_)); - swap(data_.ptr, p2.data_.ptr); - } - - C* release() { - C* retVal = data_.ptr; - data_.ptr = NULL; - return retVal; - } - - private: - // Use the empty base class optimization to allow us to have a D member, - // while avoiding any space overhead for it when D is an empty class. - // See e.g. http://www.cantrip.org/emptyopt.html for a good discussion of - // this technique. - struct Data : public D { - explicit Data(C* ptr_in) : ptr(ptr_in) {} - - C* ptr; - }; - - Data data_; - - // Disallow copy and assignment. - scoped_ptr_impl(const scoped_ptr_impl&); - scoped_ptr_impl& operator=(const scoped_ptr_impl&); -}; - -} // namespace internal -} // namespace base - -#endif // BASE_SCOPED_PTR_INTERNALS_H_ \ No newline at end of file diff --git a/src/base/spinlock.h b/src/base/spinlock.h index b1766977..e13d1992 100644 --- a/src/base/spinlock.h +++ b/src/base/spinlock.h @@ -12,8 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#ifndef UTIL_GEOMETRY_OPENSOURCE_BASE_SPINLOCK_H_ -#define UTIL_GEOMETRY_OPENSOURCE_BASE_SPINLOCK_H_ + +#ifndef BASE_SPINLOCK_H_ +#define BASE_SPINLOCK_H_ #include @@ -40,4 +41,4 @@ class SpinLock { std::atomic_flag flag_ = ATOMIC_FLAG_INIT; }; -#endif // UTIL_GEOMETRY_OPENSOURCE_BASE_SPINLOCK_H_ \ No newline at end of file +#endif // BASE_SPINLOCK_H_ diff --git a/src/base/stl_decl_msvc.h b/src/base/stl_decl_msvc.h index bcf990a9..e469175f 100644 --- a/src/base/stl_decl_msvc.h +++ b/src/base/stl_decl_msvc.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Vestige of base/stl_decl.h #ifndef _STL_DECL_MSVC_H @@ -23,4 +24,4 @@ using namespace std; -#endif /* #ifdef _STL_DECL_MSVC_H */ \ No newline at end of file +#endif /* #ifdef _STL_DECL_MSVC_H */ diff --git a/src/base/stringprintf.cc b/src/base/stringprintf.cc index 31b8d04e..003aa5b9 100644 --- a/src/base/stringprintf.cc +++ b/src/base/stringprintf.cc @@ -13,6 +13,7 @@ // limitations under the License. // + #include "base/stringprintf.h" #include @@ -103,4 +104,4 @@ void StringAppendF(string* dst, const char* format, ...) { va_start(ap, format); StringAppendV(dst, format, ap); va_end(ap); -} \ No newline at end of file +} diff --git a/src/base/stringprintf.h b/src/base/stringprintf.h index b7ac2cb9..218a63e8 100644 --- a/src/base/stringprintf.h +++ b/src/base/stringprintf.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // Printf variants that place their output in a C++ string. // @@ -48,4 +49,4 @@ extern void StringAppendF(string* dst, const char* format, ...) // string. All other routines are just convenience wrappers around it. extern void StringAppendV(string* dst, const char* format, va_list ap); -#endif // BASE_STRINGPRINTF_H_ \ No newline at end of file +#endif // BASE_STRINGPRINTF_H_ diff --git a/src/base/strtoint.cc b/src/base/strtoint.cc index 1204f09e..b4eb62eb 100644 --- a/src/base/strtoint.cc +++ b/src/base/strtoint.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // Architecture-neutral plug compatible replacements for strtol() friends. // See strtoint.h for details on how to use this component. @@ -57,4 +58,4 @@ uint32 strtou32_adapter(const char *nptr, char **endptr, int base) { if (errno == 0) errno = saved_errno; return static_cast(result); -} \ No newline at end of file +} diff --git a/src/base/strtoint.h b/src/base/strtoint.h index 063e3a0b..4658eed1 100644 --- a/src/base/strtoint.h +++ b/src/base/strtoint.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // Architecture-neutral plug compatible replacements for strtol() friends. // @@ -102,4 +103,4 @@ inline int64 atoi64(const string &s) { return atoi64(s.c_str()); } -#endif // BASE_STRTOINT_H_ \ No newline at end of file +#endif // BASE_STRTOINT_H_ diff --git a/src/base/template_util.h b/src/base/template_util.h index f67db970..77170ea6 100644 --- a/src/base/template_util.h +++ b/src/base/template_util.h @@ -1,4 +1,4 @@ -// Copyright 2005 Google Inc. All Rights Reserved. +// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,57 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// 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. -// ---- -// -// 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 chosen 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 BASE_TEMPLATE_UTIL_H_ #define BASE_TEMPLATE_UTIL_H_ -_START_GOOGLE_NAMESPACE_ +#include + +namespace base { // Types small_ and big_ are guaranteed such that sizeof(small_) < // sizeof(big_) @@ -78,69 +34,6 @@ 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 { -}; - - -_END_GOOGLE_NAMESPACE_ +} // namespace base -#endif // BASE_TEMPLATE_UTIL_H_ \ No newline at end of file +#endif // BASE_TEMPLATE_UTIL_H_ diff --git a/src/base/type_traits.h b/src/base/type_traits.h index c6960f66..4591e5ed 100644 --- a/src/base/type_traits.h +++ b/src/base/type_traits.h @@ -1,4 +1,4 @@ -// Copyright 2006 Google Inc. All Rights Reserved. +// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,345 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// 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. - -// ---- -// -// -// 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: -// enable_if -// is_integral -// is_floating_point -// is_pointer -// 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 BASE_TYPE_TRAITS_H_ #define BASE_TYPE_TRAITS_H_ -#include // For pair - -#include "base/template_util.h" // For true_type and false_type - -_START_GOOGLE_NAMESPACE_ - -template struct enable_if; -template struct is_integral; -template struct is_floating_point; -template struct is_pointer; -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(__GNUC__) && __GNUC__ <= 3) -template struct is_convertible; -#endif - -// enable_if, equivalent semantics to c++11 std::enable_if, specifically: -// "If B is true, the member typedef type shall equal T; otherwise, there -// shall be no member typedef type." -// Specified by 20.9.7.6 [Other transformations] -template struct enable_if { typedef T type; }; -template struct enable_if {}; - -// 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 { }; - -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_); -}; - -#if defined(_MSC_VER) || (defined(__GNUC__) && __GNUC__ <= 3) - -// is_enum not meaningfully available on MSVC or old GCC: always false_type. -template struct is_enum : base::false_type { }; - -#else // case for non-GCC or old GCC follows - -// 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 { }; - -// Implementation note: -// -// Supported types are 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_enum_impl's is_convertible 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 - : is_enum_impl::value && - !is_integral::value && - !is_floating_point::value && - !is_reference::value && - !is_class_or_union::value> { }; - -#endif - -template struct is_enum : is_enum { }; -template struct is_enum : is_enum { }; -template struct is_enum : is_enum { }; - -} // namespace internal - -// 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 || - internal::is_enum::value || - 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 - -_END_GOOGLE_NAMESPACE_ +#include -// 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 +#define ENFORCE_POD(TypeName) \ + static_assert(std::is_pod::value, #TypeName " must be POD") -#endif // BASE_TYPE_TRAITS_H_ \ No newline at end of file +#endif // BASE_TYPE_TRAITS_H_ diff --git a/src/configure.ac b/src/configure.ac deleted file mode 100644 index 4a655bfa..00000000 --- a/src/configure.ac +++ /dev/null @@ -1,45 +0,0 @@ -AC_INIT([s2-geometry-library], [1.0], [opensource@google.com]) -AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([dist-bzip2 foreign silent-rules subdir-objects]) - -AM_SILENT_RULES([yes]) - -AC_PROG_CXX - -LT_INIT([disable-shared]) -PKG_PROG_PKG_CONFIG - -AC_LANG([C++]) - -# https://code.google.com/p/gflags/ -PKG_CHECK_MODULES([GFLAGS], [libgflags], [dnl - CPPFLAGS="$CPPFLAGS $GFLAGS_CFLAGS" - LIBS="$LIBS $GFLAGS_LIBS" -]) - -# https://code.google.com/p/google-glog/ -PKG_CHECK_MODULES([GLOG], [libglog], [dnl - CPPFLAGS="$CPPFLAGS $GLOG_CFLAGS" - LIBS="$LIBS $GLOG_LIBS" -]) - -# http://www.openssl.org/ -PKG_CHECK_MODULES([LIBCRYPTO], [libcrypto], [dnl - CPPFLAGS="$CPPFLAGS $LIBCRYPTO_CFLAGS" - LIBS="$LIBS $LIBCRYPTO_LIBS" -]) - -# http://swtch.com/plan9port/unix/ -# Does not use pkg-config. -AC_CHECK_HEADERS([utf.h], [], - AC_MSG_ERROR([libutf is required])) - -AX_C___ATTRIBUTE__ -if test x"$ac_cv___attribute__" = x"yes"; then - AC_SUBST(ac_google_attribute, 1) -else - AC_SUBST(ac_google_attribute, 0) -fi - -AC_CONFIG_FILES([Makefile]) -AC_OUTPUT diff --git a/src/fpcontractoff.h b/src/fpcontractoff.h new file mode 100644 index 00000000..60e2b3d1 --- /dev/null +++ b/src/fpcontractoff.h @@ -0,0 +1,59 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Author: ericv@google.com (Eric Veach) + +#ifndef S2_GEOMETRY_FPCONTRACTOFF_H_ +#define S2_GEOMETRY_FPCONTRACTOFF_H_ + +// Turn off the fused multiply-add optimization ("fp-contract"). With +// fp-contract on, any expression of the form "a * b + c" has two possible +// results, and the compiler is free to choose either of them. Effectively +// this makes it impossible to write deterministic functions that involve +// floating-point math. +// +// S2 requires deterministic arithmetic for correctness. We need to turn off +// fp-contract for the entire compilation unit, because S2 has public inline +// functions, and the optimization is controlled by the setting in effect when +// inline functions are instantiated (not when they are defined). +// +// Note that there is a standard C pragma to turn off FP contraction: +// #pragma STDC FP_CONTRACT OFF +// but it is not implemented in GCC because the standard pragma allows control +// at the level of compound statements rather than entire functions. +// +// This file may be included with other files in any order, as long as it +// appears before the first non-inline function definition. + +// TODO(compiler-team): Figure out how to do this in a portable way. +#if defined(HAVE_ARMEABI_V7A) +// Some android builds use a buggy compiler that runs out of memory while +// parsing the pragma (--cpu=armeabi-v7a). + +#elif defined(ANDROID) +// Other android builds use a buggy compiler that crashes with an internal +// error (Android NDK R9). + +#elif defined(__clang__) +// Clang supports the standard C++ pragma for turning off this optimization. +#pragma STDC FP_CONTRACT OFF + +#elif defined(__GNUC__) +// GCC defines its own pragma that operates at the function level rather than +// the statement level. +#pragma GCC optimize("fp-contract=off") +#endif + +#endif // S2_GEOMETRY_FPCONTRACTOFF_H_ diff --git a/src/gtest/include/gtest/gtest-death-test.h b/src/gtest/include/gtest/gtest-death-test.h deleted file mode 100644 index 28a9a734..00000000 --- a/src/gtest/include/gtest/gtest-death-test.h +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright 2005 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// -// -// The Google C++ Testing Framework (Google Test) -// -// This header file defines the public API for death tests. It is -// #included by gtest.h so a user doesn't need to include this -// directly. - -#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ - -#include "gtest/internal/gtest-death-test-internal.h" - -namespace testing { - -// This flag controls the style of death tests. Valid values are "threadsafe", -// meaning that the death test child process will re-execute the test binary -// from the start, running only a single death test, or "fast", -// meaning that the child process will execute the test logic immediately -// after forking. -GTEST_DECLARE_string_(death_test_style); - -#if GTEST_HAS_DEATH_TEST - -namespace internal { - -// Returns a Boolean value indicating whether the caller is currently -// executing in the context of the death test child process. Tools such as -// Valgrind heap checkers may need this to modify their behavior in death -// tests. IMPORTANT: This is an internal utility. Using it may break the -// implementation of death tests. User code MUST NOT use it. -GTEST_API_ bool InDeathTestChild(); - -} // namespace internal - -// The following macros are useful for writing death tests. - -// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is -// executed: -// -// 1. It generates a warning if there is more than one active -// thread. This is because it's safe to fork() or clone() only -// when there is a single thread. -// -// 2. The parent process clone()s a sub-process and runs the death -// test in it; the sub-process exits with code 0 at the end of the -// death test, if it hasn't exited already. -// -// 3. The parent process waits for the sub-process to terminate. -// -// 4. The parent process checks the exit code and error message of -// the sub-process. -// -// Examples: -// -// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number"); -// for (int i = 0; i < 5; i++) { -// EXPECT_DEATH(server.ProcessRequest(i), -// "Invalid request .* in ProcessRequest()") -// << "Failed to die on request " << i; -// } -// -// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting"); -// -// bool KilledBySIGHUP(int exit_code) { -// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP; -// } -// -// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!"); -// -// On the regular expressions used in death tests: -// -// On POSIX-compliant systems (*nix), we use the library, -// which uses the POSIX extended regex syntax. -// -// On other platforms (e.g. Windows), we only support a simple regex -// syntax implemented as part of Google Test. This limited -// implementation should be enough most of the time when writing -// death tests; though it lacks many features you can find in PCRE -// or POSIX extended regex syntax. For example, we don't support -// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and -// repetition count ("x{5,7}"), among others. -// -// Below is the syntax that we do support. We chose it to be a -// subset of both PCRE and POSIX extended regex, so it's easy to -// learn wherever you come from. In the following: 'A' denotes a -// literal character, period (.), or a single \\ escape sequence; -// 'x' and 'y' denote regular expressions; 'm' and 'n' are for -// natural numbers. -// -// c matches any literal character c -// \\d matches any decimal digit -// \\D matches any character that's not a decimal digit -// \\f matches \f -// \\n matches \n -// \\r matches \r -// \\s matches any ASCII whitespace, including \n -// \\S matches any character that's not a whitespace -// \\t matches \t -// \\v matches \v -// \\w matches any letter, _, or decimal digit -// \\W matches any character that \\w doesn't match -// \\c matches any literal character c, which must be a punctuation -// . matches any single character except \n -// A? matches 0 or 1 occurrences of A -// A* matches 0 or many occurrences of A -// A+ matches 1 or many occurrences of A -// ^ matches the beginning of a string (not that of each line) -// $ matches the end of a string (not that of each line) -// xy matches x followed by y -// -// If you accidentally use PCRE or POSIX extended regex features -// not implemented by us, you will get a run-time failure. In that -// case, please try to rewrite your regular expression within the -// above syntax. -// -// This implementation is *not* meant to be as highly tuned or robust -// as a compiled regex library, but should perform well enough for a -// death test, which already incurs significant overhead by launching -// a child process. -// -// Known caveats: -// -// A "threadsafe" style death test obtains the path to the test -// program from argv[0] and re-executes it in the sub-process. For -// simplicity, the current implementation doesn't search the PATH -// when launching the sub-process. This means that the user must -// invoke the test program via a path that contains at least one -// path separator (e.g. path/to/foo_test and -// /absolute/path/to/bar_test are fine, but foo_test is not). This -// is rarely a problem as people usually don't put the test binary -// directory in PATH. -// -// TODO(wan@google.com): make thread-safe death tests search the PATH. - -// Asserts that a given statement causes the program to exit, with an -// integer exit status that satisfies predicate, and emitting error output -// that matches regex. -# define ASSERT_EXIT(statement, predicate, regex) \ - GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) - -// Like ASSERT_EXIT, but continues on to successive tests in the -// test case, if any: -# define EXPECT_EXIT(statement, predicate, regex) \ - GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) - -// Asserts that a given statement causes the program to exit, either by -// explicitly exiting with a nonzero exit code or being killed by a -// signal, and emitting error output that matches regex. -# define ASSERT_DEATH(statement, regex) \ - ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) - -// Like ASSERT_DEATH, but continues on to successive tests in the -// test case, if any: -# define EXPECT_DEATH(statement, regex) \ - EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) - -// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*: - -// Tests that an exit code describes a normal exit with a given exit code. -class GTEST_API_ ExitedWithCode { - public: - explicit ExitedWithCode(int exit_code); - bool operator()(int exit_status) const; - private: - // No implementation - assignment is unsupported. - void operator=(const ExitedWithCode& other); - - const int exit_code_; -}; - -# if !GTEST_OS_WINDOWS -// Tests that an exit code describes an exit due to termination by a -// given signal. -class GTEST_API_ KilledBySignal { - public: - explicit KilledBySignal(int signum); - bool operator()(int exit_status) const; - private: - const int signum_; -}; -# endif // !GTEST_OS_WINDOWS - -// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode. -// The death testing framework causes this to have interesting semantics, -// since the sideeffects of the call are only visible in opt mode, and not -// in debug mode. -// -// In practice, this can be used to test functions that utilize the -// LOG(DFATAL) macro using the following style: -// -// int DieInDebugOr12(int* sideeffect) { -// if (sideeffect) { -// *sideeffect = 12; -// } -// LOG(DFATAL) << "death"; -// return 12; -// } -// -// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) { -// int sideeffect = 0; -// // Only asserts in dbg. -// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); -// -// #ifdef NDEBUG -// // opt-mode has sideeffect visible. -// EXPECT_EQ(12, sideeffect); -// #else -// // dbg-mode no visible sideeffect. -// EXPECT_EQ(0, sideeffect); -// #endif -// } -// -// This will assert that DieInDebugReturn12InOpt() crashes in debug -// mode, usually due to a DCHECK or LOG(DFATAL), but returns the -// appropriate fallback value (12 in this case) in opt mode. If you -// need to test that a function has appropriate side-effects in opt -// mode, include assertions against the side-effects. A general -// pattern for this is: -// -// EXPECT_DEBUG_DEATH({ -// // Side-effects here will have an effect after this statement in -// // opt mode, but none in debug mode. -// EXPECT_EQ(12, DieInDebugOr12(&sideeffect)); -// }, "death"); -// -# ifdef NDEBUG - -# define EXPECT_DEBUG_DEATH(statement, regex) \ - GTEST_EXECUTE_STATEMENT_(statement, regex) - -# define ASSERT_DEBUG_DEATH(statement, regex) \ - GTEST_EXECUTE_STATEMENT_(statement, regex) - -# else - -# define EXPECT_DEBUG_DEATH(statement, regex) \ - EXPECT_DEATH(statement, regex) - -# define ASSERT_DEBUG_DEATH(statement, regex) \ - ASSERT_DEATH(statement, regex) - -# endif // NDEBUG for EXPECT_DEBUG_DEATH -#endif // GTEST_HAS_DEATH_TEST - -// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and -// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if -// death tests are supported; otherwise they just issue a warning. This is -// useful when you are combining death test assertions with normal test -// assertions in one test. -#if GTEST_HAS_DEATH_TEST -# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ - EXPECT_DEATH(statement, regex) -# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ - ASSERT_DEATH(statement, regex) -#else -# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ - GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, ) -# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ - GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return) -#endif - -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ \ No newline at end of file diff --git a/src/gtest/include/gtest/gtest-message.h b/src/gtest/include/gtest/gtest-message.h deleted file mode 100644 index 30c3eb00..00000000 --- a/src/gtest/include/gtest/gtest-message.h +++ /dev/null @@ -1,262 +0,0 @@ -// Copyright 2005 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// -// -// The Google C++ Testing Framework (Google Test) -// -// This header file defines the Message class. -// -// IMPORTANT NOTE: Due to limitation of the C++ language, we have to -// leave some internal implementation details in this header file. -// They are clearly marked by comments like this: -// -// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -// -// Such code is NOT meant to be used by a user directly, and is subject -// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user -// program! - -#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ -#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ - -#include - -#include "gtest/internal/gtest-port.h" - -// Ensures that there is at least one operator<< in the global namespace. -// See Message& operator<<(...) below for why. -void operator<<(const testing::internal::Secret&, int); - -namespace testing { - -// The Message class works like an ostream repeater. -// -// Typical usage: -// -// 1. You stream a bunch of values to a Message object. -// It will remember the text in a stringstream. -// 2. Then you stream the Message object to an ostream. -// This causes the text in the Message to be streamed -// to the ostream. -// -// For example; -// -// testing::Message foo; -// foo << 1 << " != " << 2; -// std::cout << foo; -// -// will print "1 != 2". -// -// Message is not intended to be inherited from. In particular, its -// destructor is not virtual. -// -// Note that stringstream behaves differently in gcc and in MSVC. You -// can stream a NULL char pointer to it in the former, but not in the -// latter (it causes an access violation if you do). The Message -// class hides this difference by treating a NULL char pointer as -// "(null)". -class GTEST_API_ Message { - private: - // The type of basic IO manipulators (endl, ends, and flush) for - // narrow streams. - typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&); - - public: - // Constructs an empty Message. - Message(); - - // Copy constructor. - Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT - *ss_ << msg.GetString(); - } - - // Constructs a Message from a C-string. - explicit Message(const char* str) : ss_(new ::std::stringstream) { - *ss_ << str; - } - -#if GTEST_OS_SYMBIAN - // Streams a value (either a pointer or not) to this object. - template - inline Message& operator <<(const T& value) { - StreamHelper(typename internal::is_pointer::type(), value); - return *this; - } -#else - // Streams a non-pointer value to this object. - template - inline Message& operator <<(const T& val) { - // Some libraries overload << for STL containers. These - // overloads are defined in the global namespace instead of ::std. - // - // C++'s symbol lookup rule (i.e. Koenig lookup) says that these - // overloads are visible in either the std namespace or the global - // namespace, but not other namespaces, including the testing - // namespace which Google Test's Message class is in. - // - // To allow STL containers (and other types that has a << operator - // defined in the global namespace) to be used in Google Test - // assertions, testing::Message must access the custom << operator - // from the global namespace. With this using declaration, - // overloads of << defined in the global namespace and those - // visible via Koenig lookup are both exposed in this function. - using ::operator <<; - *ss_ << val; - return *this; - } - - // Streams a pointer value to this object. - // - // This function is an overload of the previous one. When you - // stream a pointer to a Message, this definition will be used as it - // is more specialized. (The C++ Standard, section - // [temp.func.order].) If you stream a non-pointer, then the - // previous definition will be used. - // - // The reason for this overload is that streaming a NULL pointer to - // ostream is undefined behavior. Depending on the compiler, you - // may get "0", "(nil)", "(null)", or an access violation. To - // ensure consistent result across compilers, we always treat NULL - // as "(null)". - template - inline Message& operator <<(T* const& pointer) { // NOLINT - if (pointer == NULL) { - *ss_ << "(null)"; - } else { - *ss_ << pointer; - } - return *this; - } -#endif // GTEST_OS_SYMBIAN - - // Since the basic IO manipulators are overloaded for both narrow - // and wide streams, we have to provide this specialized definition - // of operator <<, even though its body is the same as the - // templatized version above. Without this definition, streaming - // endl or other basic IO manipulators to Message will confuse the - // compiler. - Message& operator <<(BasicNarrowIoManip val) { - *ss_ << val; - return *this; - } - - // Instead of 1/0, we want to see true/false for bool values. - Message& operator <<(bool b) { - return *this << (b ? "true" : "false"); - } - - // These two overloads allow streaming a wide C string to a Message - // using the UTF-8 encoding. - Message& operator <<(const wchar_t* wide_c_str); - Message& operator <<(wchar_t* wide_c_str); - -#if GTEST_HAS_STD_WSTRING - // Converts the given wide string to a narrow string using the UTF-8 - // encoding, and streams the result to this Message object. - Message& operator <<(const ::std::wstring& wstr); -#endif // GTEST_HAS_STD_WSTRING - -#if GTEST_HAS_GLOBAL_WSTRING - // Converts the given wide string to a narrow string using the UTF-8 - // encoding, and streams the result to this Message object. - Message& operator <<(const ::wstring& wstr); -#endif // GTEST_HAS_GLOBAL_WSTRING - - // Gets the text streamed to this object so far as an std::string. - // Each '\0' character in the buffer is replaced with "\\0". - // - // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - std::string GetString() const; - - private: - -#if GTEST_OS_SYMBIAN - // These are needed as the Nokia Symbian Compiler cannot decide between - // const T& and const T* in a function template. The Nokia compiler _can_ - // decide between class template specializations for T and T*, so a - // tr1::type_traits-like is_pointer works, and we can overload on that. - template - inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) { - if (pointer == NULL) { - *ss_ << "(null)"; - } else { - *ss_ << pointer; - } - } - template - inline void StreamHelper(internal::false_type /*is_pointer*/, - const T& value) { - // See the comments in Message& operator <<(const T&) above for why - // we need this using statement. - using ::operator <<; - *ss_ << value; - } -#endif // GTEST_OS_SYMBIAN - - // We'll hold the text streamed to this object here. - const internal::scoped_ptr< ::std::stringstream> ss_; - - // We declare (but don't implement) this to prevent the compiler - // from implementing the assignment operator. - void operator=(const Message&); -}; - -// Streams a Message to an ostream. -inline std::ostream& operator <<(std::ostream& os, const Message& sb) { - return os << sb.GetString(); -} - -namespace internal { - -// Converts a streamable value to an std::string. A NULL pointer is -// converted to "(null)". When the input value is a ::string, -// ::std::string, ::wstring, or ::std::wstring object, each NUL -// character in it is replaced with "\\0". -template -std::string StreamableToString(const T& streamable) { - return (Message() << streamable).GetString(); -} - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ \ No newline at end of file diff --git a/src/gtest/include/gtest/gtest-param-test.h b/src/gtest/include/gtest/gtest-param-test.h deleted file mode 100644 index fa0bb2e5..00000000 --- a/src/gtest/include/gtest/gtest-param-test.h +++ /dev/null @@ -1,1433 +0,0 @@ -// Copyright 2008 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file was GENERATED by command: -// pump.py gtest-param-test.h.pump -// DO NOT EDIT BY HAND!!! - -// 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. -// -// -// Macros and functions for implementing parameterized tests -// in Google C++ Testing Framework (Google Test) -// -// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! -// -#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ - - -// Value-parameterized tests allow you to test your code with different -// parameters without writing multiple copies of the same test. -// -// Here is how you use value-parameterized tests: - -#if 0 - -// To write value-parameterized tests, first you should define a fixture -// class. It is usually derived from testing::TestWithParam (see below for -// another inheritance scheme that's sometimes useful in more complicated -// class hierarchies), where the type of your parameter values. -// TestWithParam is itself derived from testing::Test. T can be any -// copyable type. If it's a raw pointer, you are responsible for managing the -// lifespan of the pointed values. - -class FooTest : public ::testing::TestWithParam { - // You can implement all the usual class fixture members here. -}; - -// Then, use the TEST_P macro to define as many parameterized tests -// for this fixture as you want. The _P suffix is for "parameterized" -// or "pattern", whichever you prefer to think. - -TEST_P(FooTest, DoesBlah) { - // Inside a test, access the test parameter with the GetParam() method - // of the TestWithParam class: - EXPECT_TRUE(foo.Blah(GetParam())); - ... -} - -TEST_P(FooTest, HasBlahBlah) { - ... -} - -// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test -// case with any set of parameters you want. Google Test defines a number -// of functions for generating test parameters. They return what we call -// (surprise!) parameter generators. Here is a summary of them, which -// are all in the testing namespace: -// -// -// Range(begin, end [, step]) - Yields values {begin, begin+step, -// begin+step+step, ...}. The values do not -// include end. step defaults to 1. -// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. -// ValuesIn(container) - Yields values from a C-style array, an STL -// ValuesIn(begin,end) container, or an iterator range [begin, end). -// Bool() - Yields sequence {false, true}. -// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product -// for the math savvy) of the values generated -// by the N generators. -// -// For more details, see comments at the definitions of these functions below -// in this file. -// -// The following statement will instantiate tests from the FooTest test case -// each with parameter values "meeny", "miny", and "moe". - -INSTANTIATE_TEST_CASE_P(InstantiationName, - FooTest, - Values("meeny", "miny", "moe")); - -// To distinguish different instances of the pattern, (yes, you -// can instantiate it more then once) the first argument to the -// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the -// actual test case name. Remember to pick unique prefixes for different -// instantiations. The tests from the instantiation above will have -// these names: -// -// * InstantiationName/FooTest.DoesBlah/0 for "meeny" -// * InstantiationName/FooTest.DoesBlah/1 for "miny" -// * InstantiationName/FooTest.DoesBlah/2 for "moe" -// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" -// * InstantiationName/FooTest.HasBlahBlah/1 for "miny" -// * InstantiationName/FooTest.HasBlahBlah/2 for "moe" -// -// You can use these names in --gtest_filter. -// -// This statement will instantiate all tests from FooTest again, each -// with parameter values "cat" and "dog": - -const char* pets[] = {"cat", "dog"}; -INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); - -// The tests from the instantiation above will have these names: -// -// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" -// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" -// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" -// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" -// -// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests -// in the given test case, whether their definitions come before or -// AFTER the INSTANTIATE_TEST_CASE_P statement. -// -// Please also note that generator expressions (including parameters to the -// generators) are evaluated in InitGoogleTest(), after main() has started. -// This allows the user on one hand, to adjust generator parameters in order -// to dynamically determine a set of tests to run and on the other hand, -// give the user a chance to inspect the generated tests with Google Test -// reflection API before RUN_ALL_TESTS() is executed. -// -// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc -// for more examples. -// -// In the future, we plan to publish the API for defining new parameter -// generators. But for now this interface remains part of the internal -// implementation and is subject to change. -// -// -// A parameterized test fixture must be derived from testing::Test and from -// testing::WithParamInterface, where T is the type of the parameter -// values. Inheriting from TestWithParam satisfies that requirement because -// TestWithParam inherits from both Test and WithParamInterface. In more -// complicated hierarchies, however, it is occasionally useful to inherit -// separately from Test and WithParamInterface. For example: - -class BaseTest : public ::testing::Test { - // You can inherit all the usual members for a non-parameterized test - // fixture here. -}; - -class DerivedTest : public BaseTest, public ::testing::WithParamInterface { - // The usual test fixture members go here too. -}; - -TEST_F(BaseTest, HasFoo) { - // This is an ordinary non-parameterized test. -} - -TEST_P(DerivedTest, DoesBlah) { - // GetParam works just the same here as if you inherit from TestWithParam. - EXPECT_TRUE(foo.Blah(GetParam())); -} - -#endif // 0 - -#include "gtest/internal/gtest-port.h" - -#if !GTEST_OS_SYMBIAN -# include -#endif - -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. -#include "gtest/internal/gtest-internal.h" -#include "gtest/internal/gtest-param-util.h" -#include "gtest/internal/gtest-param-util-generated.h" - -#if GTEST_HAS_PARAM_TEST - -namespace testing { - -// Functions producing parameter generators. -// -// Google Test uses these generators to produce parameters for value- -// parameterized tests. When a parameterized test case is instantiated -// with a particular generator, Google Test creates and runs tests -// for each element in the sequence produced by the generator. -// -// In the following sample, tests from test case FooTest are instantiated -// each three times with parameter values 3, 5, and 8: -// -// class FooTest : public TestWithParam { ... }; -// -// TEST_P(FooTest, TestThis) { -// } -// TEST_P(FooTest, TestThat) { -// } -// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); -// - -// Range() returns generators providing sequences of values in a range. -// -// Synopsis: -// Range(start, end) -// - returns a generator producing a sequence of values {start, start+1, -// start+2, ..., }. -// Range(start, end, step) -// - returns a generator producing a sequence of values {start, start+step, -// start+step+step, ..., }. -// Notes: -// * The generated sequences never include end. For example, Range(1, 5) -// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) -// returns a generator producing {1, 3, 5, 7}. -// * start and end must have the same type. That type may be any integral or -// floating-point type or a user defined type satisfying these conditions: -// * It must be assignable (have operator=() defined). -// * It must have operator+() (operator+(int-compatible type) for -// two-operand version). -// * It must have operator<() defined. -// Elements in the resulting sequences will also have that type. -// * Condition start < end must be satisfied in order for resulting sequences -// to contain any elements. -// -template -internal::ParamGenerator Range(T start, T end, IncrementT step) { - return internal::ParamGenerator( - new internal::RangeGenerator(start, end, step)); -} - -template -internal::ParamGenerator Range(T start, T end) { - return Range(start, end, 1); -} - -// ValuesIn() function allows generation of tests with parameters coming from -// a container. -// -// Synopsis: -// ValuesIn(const T (&array)[N]) -// - returns a generator producing sequences with elements from -// a C-style array. -// ValuesIn(const Container& container) -// - returns a generator producing sequences with elements from -// an STL-style container. -// ValuesIn(Iterator begin, Iterator end) -// - returns a generator producing sequences with elements from -// a range [begin, end) defined by a pair of STL-style iterators. These -// iterators can also be plain C pointers. -// -// Please note that ValuesIn copies the values from the containers -// passed in and keeps them to generate tests in RUN_ALL_TESTS(). -// -// Examples: -// -// This instantiates tests from test case StringTest -// each with C-string values of "foo", "bar", and "baz": -// -// const char* strings[] = {"foo", "bar", "baz"}; -// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); -// -// This instantiates tests from test case StlStringTest -// each with STL strings with values "a" and "b": -// -// ::std::vector< ::std::string> GetParameterStrings() { -// ::std::vector< ::std::string> v; -// v.push_back("a"); -// v.push_back("b"); -// return v; -// } -// -// INSTANTIATE_TEST_CASE_P(CharSequence, -// StlStringTest, -// ValuesIn(GetParameterStrings())); -// -// -// This will also instantiate tests from CharTest -// each with parameter values 'a' and 'b': -// -// ::std::list GetParameterChars() { -// ::std::list list; -// list.push_back('a'); -// list.push_back('b'); -// return list; -// } -// ::std::list l = GetParameterChars(); -// INSTANTIATE_TEST_CASE_P(CharSequence2, -// CharTest, -// ValuesIn(l.begin(), l.end())); -// -template -internal::ParamGenerator< - typename ::testing::internal::IteratorTraits::value_type> -ValuesIn(ForwardIterator begin, ForwardIterator end) { - typedef typename ::testing::internal::IteratorTraits - ::value_type ParamType; - return internal::ParamGenerator( - new internal::ValuesInIteratorRangeGenerator(begin, end)); -} - -template -internal::ParamGenerator ValuesIn(const T (&array)[N]) { - return ValuesIn(array, array + N); -} - -template -internal::ParamGenerator ValuesIn( - const Container& container) { - return ValuesIn(container.begin(), container.end()); -} - -// Values() allows generating tests from explicitly specified list of -// parameters. -// -// Synopsis: -// Values(T v1, T v2, ..., T vN) -// - returns a generator producing sequences with elements v1, v2, ..., vN. -// -// For example, this instantiates tests from test case BarTest each -// with values "one", "two", and "three": -// -// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); -// -// This instantiates tests from test case BazTest each with values 1, 2, 3.5. -// The exact type of values will depend on the type of parameter in BazTest. -// -// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); -// -// Currently, Values() supports from 1 to 50 parameters. -// -template -internal::ValueArray1 Values(T1 v1) { - return internal::ValueArray1(v1); -} - -template -internal::ValueArray2 Values(T1 v1, T2 v2) { - return internal::ValueArray2(v1, v2); -} - -template -internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { - return internal::ValueArray3(v1, v2, v3); -} - -template -internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { - return internal::ValueArray4(v1, v2, v3, v4); -} - -template -internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5) { - return internal::ValueArray5(v1, v2, v3, v4, v5); -} - -template -internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6) { - return internal::ValueArray6(v1, v2, v3, v4, v5, v6); -} - -template -internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7) { - return internal::ValueArray7(v1, v2, v3, v4, v5, - v6, v7); -} - -template -internal::ValueArray8 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { - return internal::ValueArray8(v1, v2, v3, v4, - v5, v6, v7, v8); -} - -template -internal::ValueArray9 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { - return internal::ValueArray9(v1, v2, v3, - v4, v5, v6, v7, v8, v9); -} - -template -internal::ValueArray10 Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { - return internal::ValueArray10(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10); -} - -template -internal::ValueArray11 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11) { - return internal::ValueArray11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); -} - -template -internal::ValueArray12 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12) { - return internal::ValueArray12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); -} - -template -internal::ValueArray13 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13) { - return internal::ValueArray13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); -} - -template -internal::ValueArray14 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) { - return internal::ValueArray14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14); -} - -template -internal::ValueArray15 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) { - return internal::ValueArray15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15); -} - -template -internal::ValueArray16 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16) { - return internal::ValueArray16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16); -} - -template -internal::ValueArray17 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17) { - return internal::ValueArray17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17); -} - -template -internal::ValueArray18 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18) { - return internal::ValueArray18(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18); -} - -template -internal::ValueArray19 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) { - return internal::ValueArray19(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); -} - -template -internal::ValueArray20 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) { - return internal::ValueArray20(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); -} - -template -internal::ValueArray21 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) { - return internal::ValueArray21(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); -} - -template -internal::ValueArray22 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22) { - return internal::ValueArray22(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22); -} - -template -internal::ValueArray23 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23) { - return internal::ValueArray23(v1, v2, v3, - v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23); -} - -template -internal::ValueArray24 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24) { - return internal::ValueArray24(v1, v2, - v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, - v19, v20, v21, v22, v23, v24); -} - -template -internal::ValueArray25 Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, - T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, - T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) { - return internal::ValueArray25(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, - v18, v19, v20, v21, v22, v23, v24, v25); -} - -template -internal::ValueArray26 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26) { - return internal::ValueArray26(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, - v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); -} - -template -internal::ValueArray27 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27) { - return internal::ValueArray27(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, - v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); -} - -template -internal::ValueArray28 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28) { - return internal::ValueArray28(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, - v28); -} - -template -internal::ValueArray29 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29) { - return internal::ValueArray29(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, - v27, v28, v29); -} - -template -internal::ValueArray30 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, - T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, - T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) { - return internal::ValueArray30(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, - v26, v27, v28, v29, v30); -} - -template -internal::ValueArray31 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) { - return internal::ValueArray31(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, - v25, v26, v27, v28, v29, v30, v31); -} - -template -internal::ValueArray32 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32) { - return internal::ValueArray32(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32); -} - -template -internal::ValueArray33 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33) { - return internal::ValueArray33(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33); -} - -template -internal::ValueArray34 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, - T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, - T31 v31, T32 v32, T33 v33, T34 v34) { - return internal::ValueArray34(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, - v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34); -} - -template -internal::ValueArray35 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) { - return internal::ValueArray35(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, - v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35); -} - -template -internal::ValueArray36 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) { - return internal::ValueArray36(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36); -} - -template -internal::ValueArray37 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37) { - return internal::ValueArray37(v1, v2, v3, - v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36, v37); -} - -template -internal::ValueArray38 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37, T38 v38) { - return internal::ValueArray38(v1, v2, - v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, - v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, - v33, v34, v35, v36, v37, v38); -} - -template -internal::ValueArray39 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37, T38 v38, T39 v39) { - return internal::ValueArray39(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, - v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, - v32, v33, v34, v35, v36, v37, v38, v39); -} - -template -internal::ValueArray40 Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, - T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, - T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, - T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, - T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) { - return internal::ValueArray40(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, - v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, - v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); -} - -template -internal::ValueArray41 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) { - return internal::ValueArray41(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, - v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, - v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41); -} - -template -internal::ValueArray42 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42) { - return internal::ValueArray42(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, - v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, - v42); -} - -template -internal::ValueArray43 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43) { - return internal::ValueArray43(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, - v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, - v41, v42, v43); -} - -template -internal::ValueArray44 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44) { - return internal::ValueArray44(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, - v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, - v40, v41, v42, v43, v44); -} - -template -internal::ValueArray45 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, - T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, - T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, - T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, - T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) { - return internal::ValueArray45(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, - v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, - v39, v40, v41, v42, v43, v44, v45); -} - -template -internal::ValueArray46 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) { - return internal::ValueArray46(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, - v38, v39, v40, v41, v42, v43, v44, v45, v46); -} - -template -internal::ValueArray47 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) { - return internal::ValueArray47(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, - v38, v39, v40, v41, v42, v43, v44, v45, v46, v47); -} - -template -internal::ValueArray48 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, - T48 v48) { - return internal::ValueArray48(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, - v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, - v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48); -} - -template -internal::ValueArray49 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, - T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, - T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, - T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, - T47 v47, T48 v48, T49 v49) { - return internal::ValueArray49(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, - v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, - v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49); -} - -template -internal::ValueArray50 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, - T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, - T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) { - return internal::ValueArray50(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, - v48, v49, v50); -} - -// Bool() allows generating tests with parameters in a set of (false, true). -// -// Synopsis: -// Bool() -// - returns a generator producing sequences with elements {false, true}. -// -// It is useful when testing code that depends on Boolean flags. Combinations -// of multiple flags can be tested when several Bool()'s are combined using -// Combine() function. -// -// In the following example all tests in the test case FlagDependentTest -// will be instantiated twice with parameters false and true. -// -// class FlagDependentTest : public testing::TestWithParam { -// virtual void SetUp() { -// external_flag = GetParam(); -// } -// } -// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); -// -inline internal::ParamGenerator Bool() { - return Values(false, true); -} - -# if GTEST_HAS_COMBINE -// Combine() allows the user to combine two or more sequences to produce -// values of a Cartesian product of those sequences' elements. -// -// Synopsis: -// Combine(gen1, gen2, ..., genN) -// - returns a generator producing sequences with elements coming from -// the Cartesian product of elements from the sequences generated by -// gen1, gen2, ..., genN. The sequence elements will have a type of -// tuple where T1, T2, ..., TN are the types -// of elements from sequences produces by gen1, gen2, ..., genN. -// -// Combine can have up to 10 arguments. This number is currently limited -// by the maximum number of elements in the tuple implementation used by Google -// Test. -// -// Example: -// -// This will instantiate tests in test case AnimalTest each one with -// the parameter values tuple("cat", BLACK), tuple("cat", WHITE), -// tuple("dog", BLACK), and tuple("dog", WHITE): -// -// enum Color { BLACK, GRAY, WHITE }; -// class AnimalTest -// : public testing::TestWithParam > {...}; -// -// TEST_P(AnimalTest, AnimalLooksNice) {...} -// -// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, -// Combine(Values("cat", "dog"), -// Values(BLACK, WHITE))); -// -// This will instantiate tests in FlagDependentTest with all variations of two -// Boolean flags: -// -// class FlagDependentTest -// : public testing::TestWithParam > { -// virtual void SetUp() { -// // Assigns external_flag_1 and external_flag_2 values from the tuple. -// tie(external_flag_1, external_flag_2) = GetParam(); -// } -// }; -// -// TEST_P(FlagDependentTest, TestFeature1) { -// // Test your code using external_flag_1 and external_flag_2 here. -// } -// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, -// Combine(Bool(), Bool())); -// -template -internal::CartesianProductHolder2 Combine( - const Generator1& g1, const Generator2& g2) { - return internal::CartesianProductHolder2( - g1, g2); -} - -template -internal::CartesianProductHolder3 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3) { - return internal::CartesianProductHolder3( - g1, g2, g3); -} - -template -internal::CartesianProductHolder4 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4) { - return internal::CartesianProductHolder4( - g1, g2, g3, g4); -} - -template -internal::CartesianProductHolder5 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5) { - return internal::CartesianProductHolder5( - g1, g2, g3, g4, g5); -} - -template -internal::CartesianProductHolder6 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6) { - return internal::CartesianProductHolder6( - g1, g2, g3, g4, g5, g6); -} - -template -internal::CartesianProductHolder7 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7) { - return internal::CartesianProductHolder7( - g1, g2, g3, g4, g5, g6, g7); -} - -template -internal::CartesianProductHolder8 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8) { - return internal::CartesianProductHolder8( - g1, g2, g3, g4, g5, g6, g7, g8); -} - -template -internal::CartesianProductHolder9 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8, const Generator9& g9) { - return internal::CartesianProductHolder9( - g1, g2, g3, g4, g5, g6, g7, g8, g9); -} - -template -internal::CartesianProductHolder10 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8, const Generator9& g9, - const Generator10& g10) { - return internal::CartesianProductHolder10( - g1, g2, g3, g4, g5, g6, g7, g8, g9, g10); -} -# endif // GTEST_HAS_COMBINE - - - -# define TEST_P(test_case_name, test_name) \ - class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ - : public test_case_name { \ - public: \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ - virtual void TestBody(); \ - private: \ - static int AddToRegistry() { \ - ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ - GetTestCasePatternHolder(\ - #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ - #test_case_name, \ - #test_name, \ - new ::testing::internal::TestMetaFactory< \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ - return 0; \ - } \ - static int gtest_registering_dummy_; \ - GTEST_DISALLOW_COPY_AND_ASSIGN_(\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ - }; \ - int GTEST_TEST_CLASS_NAME_(test_case_name, \ - test_name)::gtest_registering_dummy_ = \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ - void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() - -# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ - ::testing::internal::ParamGenerator \ - gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ - int gtest_##prefix##test_case_name##_dummy_ = \ - ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ - GetTestCasePatternHolder(\ - #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ - #prefix, \ - >est_##prefix##test_case_name##_EvalGenerator_, \ - __FILE__, __LINE__) - -} // namespace testing - -#endif // GTEST_HAS_PARAM_TEST - -#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ \ No newline at end of file diff --git a/src/gtest/include/gtest/gtest-printers.h b/src/gtest/include/gtest/gtest-printers.h deleted file mode 100644 index cc4a895e..00000000 --- a/src/gtest/include/gtest/gtest-printers.h +++ /dev/null @@ -1,903 +0,0 @@ -// Copyright 2007 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// - -// Google Test - The Google C++ Testing Framework -// -// This file implements a universal value printer that can print a -// value of any type T: -// -// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); -// -// A user can teach this function how to print a class type T by -// defining either operator<<() or PrintTo() in the namespace that -// defines T. More specifically, the FIRST defined function in the -// following list will be used (assuming T is defined in namespace -// foo): -// -// 1. foo::PrintTo(const T&, ostream*) -// 2. operator<<(ostream&, const T&) defined in either foo or the -// global namespace. -// -// If none of the above is defined, it will print the debug string of -// the value if it is a protocol buffer, or print the raw bytes in the -// value otherwise. -// -// To aid debugging: when T is a reference type, the address of the -// value is also printed; when T is a (const) char pointer, both the -// pointer value and the NUL-terminated string it points to are -// printed. -// -// We also provide some convenient wrappers: -// -// // Prints a value to a string. For a (const or not) char -// // pointer, the NUL-terminated string (but not the pointer) is -// // printed. -// std::string ::testing::PrintToString(const T& value); -// -// // Prints a value tersely: for a reference type, the referenced -// // value (but not the address) is printed; for a (const or not) char -// // pointer, the NUL-terminated string (but not the pointer) is -// // printed. -// void ::testing::internal::UniversalTersePrint(const T& value, ostream*); -// -// // Prints value using the type inferred by the compiler. The difference -// // from UniversalTersePrint() is that this function prints both the -// // pointer and the NUL-terminated string for a (const or not) char pointer. -// void ::testing::internal::UniversalPrint(const T& value, ostream*); -// -// // Prints the fields of a tuple tersely to a string vector, one -// // element for each field. Tuple support must be enabled in -// // gtest-port.h. -// std::vector UniversalTersePrintTupleFieldsToStrings( -// const Tuple& value); -// -// Known limitation: -// -// The print primitives print the elements of an STL-style container -// using the compiler-inferred type of *iter where iter is a -// const_iterator of the container. When const_iterator is an input -// iterator but not a forward iterator, this inferred type may not -// match value_type, and the print output may be incorrect. In -// practice, this is rarely a problem as for most containers -// const_iterator is a forward iterator. We'll fix this if there's an -// actual need for it. Note that this fix cannot rely on value_type -// being defined as many user-defined container types don't have -// value_type. - -#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ - -#include // NOLINT -#include -#include -#include -#include -#include "gtest/internal/gtest-port.h" -#include "gtest/internal/gtest-internal.h" - -#if GTEST_HAS_STD_TUPLE_ -# include -#endif - -namespace testing { - -// Definitions in the 'internal' and 'internal2' name spaces are -// subject to change without notice. DO NOT USE THEM IN USER CODE! -namespace internal2 { - -// Prints the given number of bytes in the given object to the given -// ostream. -GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes, - size_t count, - ::std::ostream* os); - -// For selecting which printer to use when a given type has neither << -// nor PrintTo(). -enum TypeKind { - kProtobuf, // a protobuf type - kConvertibleToInteger, // a type implicitly convertible to BiggestInt - // (e.g. a named or unnamed enum type) - kOtherType // anything else -}; - -// TypeWithoutFormatter::PrintValue(value, os) is called -// by the universal printer to print a value of type T when neither -// operator<< nor PrintTo() is defined for T, where kTypeKind is the -// "kind" of T as defined by enum TypeKind. -template -class TypeWithoutFormatter { - public: - // This default version is called when kTypeKind is kOtherType. - static void PrintValue(const T& value, ::std::ostream* os) { - PrintBytesInObjectTo(reinterpret_cast(&value), - sizeof(value), os); - } -}; - -// We print a protobuf using its ShortDebugString() when the string -// doesn't exceed this many characters; otherwise we print it using -// DebugString() for better readability. -const size_t kProtobufOneLinerMaxLength = 50; - -template -class TypeWithoutFormatter { - public: - static void PrintValue(const T& value, ::std::ostream* os) { - const ::testing::internal::string short_str = value.ShortDebugString(); - const ::testing::internal::string pretty_str = - short_str.length() <= kProtobufOneLinerMaxLength ? - short_str : ("\n" + value.DebugString()); - *os << ("<" + pretty_str + ">"); - } -}; - -template -class TypeWithoutFormatter { - public: - // Since T has no << operator or PrintTo() but can be implicitly - // converted to BiggestInt, we print it as a BiggestInt. - // - // Most likely T is an enum type (either named or unnamed), in which - // case printing it as an integer is the desired behavior. In case - // T is not an enum, printing it as an integer is the best we can do - // given that it has no user-defined printer. - static void PrintValue(const T& value, ::std::ostream* os) { - const internal::BiggestInt kBigInt = value; - *os << kBigInt; - } -}; - -// Prints the given value to the given ostream. If the value is a -// protocol message, its debug string is printed; if it's an enum or -// of a type implicitly convertible to BiggestInt, it's printed as an -// integer; otherwise the bytes in the value are printed. This is -// what UniversalPrinter::Print() does when it knows nothing about -// type T and T has neither << operator nor PrintTo(). -// -// A user can override this behavior for a class type Foo by defining -// a << operator in the namespace where Foo is defined. -// -// We put this operator in namespace 'internal2' instead of 'internal' -// to simplify the implementation, as much code in 'internal' needs to -// use << in STL, which would conflict with our own << were it defined -// in 'internal'. -// -// Note that this operator<< takes a generic std::basic_ostream type instead of the more restricted std::ostream. If -// we define it to take an std::ostream instead, we'll get an -// "ambiguous overloads" compiler error when trying to print a type -// Foo that supports streaming to std::basic_ostream, as the compiler cannot tell whether -// operator<<(std::ostream&, const T&) or -// operator<<(std::basic_stream, const Foo&) is more -// specific. -template -::std::basic_ostream& operator<<( - ::std::basic_ostream& os, const T& x) { - TypeWithoutFormatter::value ? kProtobuf : - internal::ImplicitlyConvertible::value ? - kConvertibleToInteger : kOtherType)>::PrintValue(x, &os); - return os; -} - -} // namespace internal2 -} // namespace testing - -// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up -// magic needed for implementing UniversalPrinter won't work. -namespace testing_internal { - -// Used to print a value that is not an STL-style container when the -// user doesn't define PrintTo() for it. -template -void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { - // With the following statement, during unqualified name lookup, - // testing::internal2::operator<< appears as if it was declared in - // the nearest enclosing namespace that contains both - // ::testing_internal and ::testing::internal2, i.e. the global - // namespace. For more details, refer to the C++ Standard section - // 7.3.4-1 [namespace.udir]. This allows us to fall back onto - // testing::internal2::operator<< in case T doesn't come with a << - // operator. - // - // We cannot write 'using ::testing::internal2::operator<<;', which - // gcc 3.3 fails to compile due to a compiler bug. - using namespace ::testing::internal2; // NOLINT - - // Assuming T is defined in namespace foo, in the next statement, - // the compiler will consider all of: - // - // 1. foo::operator<< (thanks to Koenig look-up), - // 2. ::operator<< (as the current namespace is enclosed in ::), - // 3. testing::internal2::operator<< (thanks to the using statement above). - // - // The operator<< whose type matches T best will be picked. - // - // We deliberately allow #2 to be a candidate, as sometimes it's - // impossible to define #1 (e.g. when foo is ::std, defining - // anything in it is undefined behavior unless you are a compiler - // vendor.). - *os << value; -} - -} // namespace testing_internal - -namespace testing { -namespace internal { - -// UniversalPrinter::Print(value, ostream_ptr) prints the given -// value to the given ostream. The caller must ensure that -// 'ostream_ptr' is not NULL, or the behavior is undefined. -// -// We define UniversalPrinter as a class template (as opposed to a -// function template), as we need to partially specialize it for -// reference types, which cannot be done with function templates. -template -class UniversalPrinter; - -template -void UniversalPrint(const T& value, ::std::ostream* os); - -// Used to print an STL-style container when the user doesn't define -// a PrintTo() for it. -template -void DefaultPrintTo(IsContainer /* dummy */, - false_type /* is not a pointer */, - const C& container, ::std::ostream* os) { - const size_t kMaxCount = 32; // The maximum number of elements to print. - *os << '{'; - size_t count = 0; - for (typename C::const_iterator it = container.begin(); - it != container.end(); ++it, ++count) { - if (count > 0) { - *os << ','; - if (count == kMaxCount) { // Enough has been printed. - *os << " ..."; - break; - } - } - *os << ' '; - // We cannot call PrintTo(*it, os) here as PrintTo() doesn't - // handle *it being a native array. - internal::UniversalPrint(*it, os); - } - - if (count > 0) { - *os << ' '; - } - *os << '}'; -} - -// Used to print a pointer that is neither a char pointer nor a member -// pointer, when the user doesn't define PrintTo() for it. (A member -// variable pointer or member function pointer doesn't really point to -// a location in the address space. Their representation is -// implementation-defined. Therefore they will be printed as raw -// bytes.) -template -void DefaultPrintTo(IsNotContainer /* dummy */, - true_type /* is a pointer */, - T* p, ::std::ostream* os) { - if (p == NULL) { - *os << "NULL"; - } else { - // C++ doesn't allow casting from a function pointer to any object - // pointer. - // - // IsTrue() silences warnings: "Condition is always true", - // "unreachable code". - if (IsTrue(ImplicitlyConvertible::value)) { - // T is not a function type. We just call << to print p, - // relying on ADL to pick up user-defined << for their pointer - // types, if any. - *os << p; - } else { - // T is a function type, so '*os << p' doesn't do what we want - // (it just prints p as bool). We want to print p as a const - // void*. However, we cannot cast it to const void* directly, - // even using reinterpret_cast, as earlier versions of gcc - // (e.g. 3.4.5) cannot compile the cast when p is a function - // pointer. Casting to UInt64 first solves the problem. - *os << reinterpret_cast( - reinterpret_cast(p)); - } - } -} - -// Used to print a non-container, non-pointer value when the user -// doesn't define PrintTo() for it. -template -void DefaultPrintTo(IsNotContainer /* dummy */, - false_type /* is not a pointer */, - const T& value, ::std::ostream* os) { - ::testing_internal::DefaultPrintNonContainerTo(value, os); -} - -// Prints the given value using the << operator if it has one; -// otherwise prints the bytes in it. This is what -// UniversalPrinter::Print() does when PrintTo() is not specialized -// or overloaded for type T. -// -// A user can override this behavior for a class type Foo by defining -// an overload of PrintTo() in the namespace where Foo is defined. We -// give the user this option as sometimes defining a << operator for -// Foo is not desirable (e.g. the coding style may prevent doing it, -// or there is already a << operator but it doesn't do what the user -// wants). -template -void PrintTo(const T& value, ::std::ostream* os) { - // DefaultPrintTo() is overloaded. The type of its first two - // arguments determine which version will be picked. If T is an - // STL-style container, the version for container will be called; if - // T is a pointer, the pointer version will be called; otherwise the - // generic version will be called. - // - // Note that we check for container types here, prior to we check - // for protocol message types in our operator<<. The rationale is: - // - // For protocol messages, we want to give people a chance to - // override Google Mock's format by defining a PrintTo() or - // operator<<. For STL containers, other formats can be - // incompatible with Google Mock's format for the container - // elements; therefore we check for container types here to ensure - // that our format is used. - // - // The second argument of DefaultPrintTo() is needed to bypass a bug - // in Symbian's C++ compiler that prevents it from picking the right - // overload between: - // - // PrintTo(const T& x, ...); - // PrintTo(T* x, ...); - DefaultPrintTo(IsContainerTest(0), is_pointer(), value, os); -} - -// The following list of PrintTo() overloads tells -// UniversalPrinter::Print() how to print standard types (built-in -// types, strings, plain arrays, and pointers). - -// Overloads for various char types. -GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os); -GTEST_API_ void PrintTo(signed char c, ::std::ostream* os); -inline void PrintTo(char c, ::std::ostream* os) { - // When printing a plain char, we always treat it as unsigned. This - // way, the output won't be affected by whether the compiler thinks - // char is signed or not. - PrintTo(static_cast(c), os); -} - -// Overloads for other simple built-in types. -inline void PrintTo(bool x, ::std::ostream* os) { - *os << (x ? "true" : "false"); -} - -// Overload for wchar_t type. -// Prints a wchar_t as a symbol if it is printable or as its internal -// code otherwise and also as its decimal code (except for L'\0'). -// The L'\0' char is printed as "L'\\0'". The decimal code is printed -// as signed integer when wchar_t is implemented by the compiler -// as a signed type and is printed as an unsigned integer when wchar_t -// is implemented as an unsigned type. -GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os); - -// Overloads for C strings. -GTEST_API_ void PrintTo(const char* s, ::std::ostream* os); -inline void PrintTo(char* s, ::std::ostream* os) { - PrintTo(ImplicitCast_(s), os); -} - -// signed/unsigned char is often used for representing binary data, so -// we print pointers to it as void* to be safe. -inline void PrintTo(const signed char* s, ::std::ostream* os) { - PrintTo(ImplicitCast_(s), os); -} -inline void PrintTo(signed char* s, ::std::ostream* os) { - PrintTo(ImplicitCast_(s), os); -} -inline void PrintTo(const unsigned char* s, ::std::ostream* os) { - PrintTo(ImplicitCast_(s), os); -} -inline void PrintTo(unsigned char* s, ::std::ostream* os) { - PrintTo(ImplicitCast_(s), os); -} - -// MSVC can be configured to define wchar_t as a typedef of unsigned -// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native -// type. When wchar_t is a typedef, defining an overload for const -// wchar_t* would cause unsigned short* be printed as a wide string, -// possibly causing invalid memory accesses. -#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) -// Overloads for wide C strings -GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os); -inline void PrintTo(wchar_t* s, ::std::ostream* os) { - PrintTo(ImplicitCast_(s), os); -} -#endif - -// Overload for C arrays. Multi-dimensional arrays are printed -// properly. - -// Prints the given number of elements in an array, without printing -// the curly braces. -template -void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { - UniversalPrint(a[0], os); - for (size_t i = 1; i != count; i++) { - *os << ", "; - UniversalPrint(a[i], os); - } -} - -// Overloads for ::string and ::std::string. -#if GTEST_HAS_GLOBAL_STRING -GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os); -inline void PrintTo(const ::string& s, ::std::ostream* os) { - PrintStringTo(s, os); -} -#endif // GTEST_HAS_GLOBAL_STRING - -GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os); -inline void PrintTo(const ::std::string& s, ::std::ostream* os) { - PrintStringTo(s, os); -} - -// Overloads for ::wstring and ::std::wstring. -#if GTEST_HAS_GLOBAL_WSTRING -GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os); -inline void PrintTo(const ::wstring& s, ::std::ostream* os) { - PrintWideStringTo(s, os); -} -#endif // GTEST_HAS_GLOBAL_WSTRING - -#if GTEST_HAS_STD_WSTRING -GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); -inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { - PrintWideStringTo(s, os); -} -#endif // GTEST_HAS_STD_WSTRING - -#if GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ -// Helper function for printing a tuple. T must be instantiated with -// a tuple type. -template -void PrintTupleTo(const T& t, ::std::ostream* os); -#endif // GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ - -#if GTEST_HAS_TR1_TUPLE -// Overload for ::std::tr1::tuple. Needed for printing function arguments, -// which are packed as tuples. - -// Overloaded PrintTo() for tuples of various arities. We support -// tuples of up-to 10 fields. The following implementation works -// regardless of whether tr1::tuple is implemented using the -// non-standard variadic template feature or not. - -inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo( - const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} -#endif // GTEST_HAS_TR1_TUPLE - -#if GTEST_HAS_STD_TUPLE_ -template -void PrintTo(const ::std::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} -#endif // GTEST_HAS_STD_TUPLE_ - -// Overload for std::pair. -template -void PrintTo(const ::std::pair& value, ::std::ostream* os) { - *os << '('; - // We cannot use UniversalPrint(value.first, os) here, as T1 may be - // a reference type. The same for printing value.second. - UniversalPrinter::Print(value.first, os); - *os << ", "; - UniversalPrinter::Print(value.second, os); - *os << ')'; -} - -// Implements printing a non-reference type T by letting the compiler -// pick the right overload of PrintTo() for T. -template -class UniversalPrinter { - public: - // MSVC warns about adding const to a function type, so we want to - // disable the warning. - GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180) - - // Note: we deliberately don't call this PrintTo(), as that name - // conflicts with ::testing::internal::PrintTo in the body of the - // function. - static void Print(const T& value, ::std::ostream* os) { - // By default, ::testing::internal::PrintTo() is used for printing - // the value. - // - // Thanks to Koenig look-up, if T is a class and has its own - // PrintTo() function defined in its namespace, that function will - // be visible here. Since it is more specific than the generic ones - // in ::testing::internal, it will be picked by the compiler in the - // following statement - exactly what we want. - PrintTo(value, os); - } - - GTEST_DISABLE_MSC_WARNINGS_POP_() -}; - -// UniversalPrintArray(begin, len, os) prints an array of 'len' -// elements, starting at address 'begin'. -template -void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { - if (len == 0) { - *os << "{}"; - } else { - *os << "{ "; - const size_t kThreshold = 18; - const size_t kChunkSize = 8; - // If the array has more than kThreshold elements, we'll have to - // omit some details by printing only the first and the last - // kChunkSize elements. - // TODO(wan@google.com): let the user control the threshold using a flag. - if (len <= kThreshold) { - PrintRawArrayTo(begin, len, os); - } else { - PrintRawArrayTo(begin, kChunkSize, os); - *os << ", ..., "; - PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os); - } - *os << " }"; - } -} -// This overload prints a (const) char array compactly. -GTEST_API_ void UniversalPrintArray( - const char* begin, size_t len, ::std::ostream* os); - -// This overload prints a (const) wchar_t array compactly. -GTEST_API_ void UniversalPrintArray( - const wchar_t* begin, size_t len, ::std::ostream* os); - -// Implements printing an array type T[N]. -template -class UniversalPrinter { - public: - // Prints the given array, omitting some elements when there are too - // many. - static void Print(const T (&a)[N], ::std::ostream* os) { - UniversalPrintArray(a, N, os); - } -}; - -// Implements printing a reference type T&. -template -class UniversalPrinter { - public: - // MSVC warns about adding const to a function type, so we want to - // disable the warning. - GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180) - - static void Print(const T& value, ::std::ostream* os) { - // Prints the address of the value. We use reinterpret_cast here - // as static_cast doesn't compile when T is a function type. - *os << "@" << reinterpret_cast(&value) << " "; - - // Then prints the value itself. - UniversalPrint(value, os); - } - - GTEST_DISABLE_MSC_WARNINGS_POP_() -}; - -// Prints a value tersely: for a reference type, the referenced value -// (but not the address) is printed; for a (const) char pointer, the -// NUL-terminated string (but not the pointer) is printed. - -template -class UniversalTersePrinter { - public: - static void Print(const T& value, ::std::ostream* os) { - UniversalPrint(value, os); - } -}; -template -class UniversalTersePrinter { - public: - static void Print(const T& value, ::std::ostream* os) { - UniversalPrint(value, os); - } -}; -template -class UniversalTersePrinter { - public: - static void Print(const T (&value)[N], ::std::ostream* os) { - UniversalPrinter::Print(value, os); - } -}; -template <> -class UniversalTersePrinter { - public: - static void Print(const char* str, ::std::ostream* os) { - if (str == NULL) { - *os << "NULL"; - } else { - UniversalPrint(string(str), os); - } - } -}; -template <> -class UniversalTersePrinter { - public: - static void Print(char* str, ::std::ostream* os) { - UniversalTersePrinter::Print(str, os); - } -}; - -#if GTEST_HAS_STD_WSTRING -template <> -class UniversalTersePrinter { - public: - static void Print(const wchar_t* str, ::std::ostream* os) { - if (str == NULL) { - *os << "NULL"; - } else { - UniversalPrint(::std::wstring(str), os); - } - } -}; -#endif - -template <> -class UniversalTersePrinter { - public: - static void Print(wchar_t* str, ::std::ostream* os) { - UniversalTersePrinter::Print(str, os); - } -}; - -template -void UniversalTersePrint(const T& value, ::std::ostream* os) { - UniversalTersePrinter::Print(value, os); -} - -// Prints a value using the type inferred by the compiler. The -// difference between this and UniversalTersePrint() is that for a -// (const) char pointer, this prints both the pointer and the -// NUL-terminated string. -template -void UniversalPrint(const T& value, ::std::ostream* os) { - // A workarond for the bug in VC++ 7.1 that prevents us from instantiating - // UniversalPrinter with T directly. - typedef T T1; - UniversalPrinter::Print(value, os); -} - -typedef ::std::vector Strings; - -// TuplePolicy must provide: -// - tuple_size -// size of tuple TupleT. -// - get(const TupleT& t) -// static function extracting element I of tuple TupleT. -// - tuple_element::type -// type of element I of tuple TupleT. -template -struct TuplePolicy; - -#if GTEST_HAS_TR1_TUPLE -template -struct TuplePolicy { - typedef TupleT Tuple; - static const size_t tuple_size = ::std::tr1::tuple_size::value; - - template - struct tuple_element : ::std::tr1::tuple_element {}; - - template - static typename AddReference< - const typename ::std::tr1::tuple_element::type>::type get( - const Tuple& tuple) { - return ::std::tr1::get(tuple); - } -}; -template -const size_t TuplePolicy::tuple_size; -#endif // GTEST_HAS_TR1_TUPLE - -#if GTEST_HAS_STD_TUPLE_ -template -struct TuplePolicy< ::std::tuple > { - typedef ::std::tuple Tuple; - static const size_t tuple_size = ::std::tuple_size::value; - - template - struct tuple_element : ::std::tuple_element {}; - - template - static const typename ::std::tuple_element::type& get( - const Tuple& tuple) { - return ::std::get(tuple); - } -}; -template -const size_t TuplePolicy< ::std::tuple >::tuple_size; -#endif // GTEST_HAS_STD_TUPLE_ - -#if GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ -// This helper template allows PrintTo() for tuples and -// UniversalTersePrintTupleFieldsToStrings() to be defined by -// induction on the number of tuple fields. The idea is that -// TuplePrefixPrinter::PrintPrefixTo(t, os) prints the first N -// fields in tuple t, and can be defined in terms of -// TuplePrefixPrinter. -// -// The inductive case. -template -struct TuplePrefixPrinter { - // Prints the first N fields of a tuple. - template - static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { - TuplePrefixPrinter::PrintPrefixTo(t, os); - GTEST_INTENTIONAL_CONST_COND_PUSH_() - if (N > 1) { - GTEST_INTENTIONAL_CONST_COND_POP_() - *os << ", "; - } - UniversalPrinter< - typename TuplePolicy::template tuple_element::type> - ::Print(TuplePolicy::template get(t), os); - } - - // Tersely prints the first N fields of a tuple to a string vector, - // one element for each field. - template - static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { - TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); - ::std::stringstream ss; - UniversalTersePrint(TuplePolicy::template get(t), &ss); - strings->push_back(ss.str()); - } -}; - -// Base case. -template <> -struct TuplePrefixPrinter<0> { - template - static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} - - template - static void TersePrintPrefixToStrings(const Tuple&, Strings*) {} -}; - -// Helper function for printing a tuple. -// Tuple must be either std::tr1::tuple or std::tuple type. -template -void PrintTupleTo(const Tuple& t, ::std::ostream* os) { - *os << "("; - TuplePrefixPrinter::tuple_size>::PrintPrefixTo(t, os); - *os << ")"; -} - -// Prints the fields of a tuple tersely to a string vector, one -// element for each field. See the comment before -// UniversalTersePrint() for how we define "tersely". -template -Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { - Strings result; - TuplePrefixPrinter::tuple_size>:: - TersePrintPrefixToStrings(value, &result); - return result; -} -#endif // GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ - -} // namespace internal - -template -::std::string PrintToString(const T& value) { - ::std::stringstream ss; - internal::UniversalTersePrinter::Print(value, &ss); - return ss.str(); -} - -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ \ No newline at end of file diff --git a/src/gtest/include/gtest/gtest-spi.h b/src/gtest/include/gtest/gtest-spi.h deleted file mode 100644 index 1021a23b..00000000 --- a/src/gtest/include/gtest/gtest-spi.h +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright 2007 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// -// -// Utilities for testing Google Test itself and code that uses Google Test -// (e.g. frameworks built on top of Google Test). - -#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ -#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ - -#include "gtest/gtest.h" - -namespace testing { - -// This helper class can be used to mock out Google Test failure reporting -// so that we can test Google Test or code that builds on Google Test. -// -// An object of this class appends a TestPartResult object to the -// TestPartResultArray object given in the constructor whenever a Google Test -// failure is reported. It can either intercept only failures that are -// generated in the same thread that created this object or it can intercept -// all generated failures. The scope of this mock object can be controlled with -// the second argument to the two arguments constructor. -class GTEST_API_ ScopedFakeTestPartResultReporter - : public TestPartResultReporterInterface { - public: - // The two possible mocking modes of this object. - enum InterceptMode { - INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures. - INTERCEPT_ALL_THREADS // Intercepts all failures. - }; - - // The c'tor sets this object as the test part result reporter used - // by Google Test. The 'result' parameter specifies where to report the - // results. This reporter will only catch failures generated in the current - // thread. DEPRECATED - explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); - - // Same as above, but you can choose the interception scope of this object. - ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, - TestPartResultArray* result); - - // The d'tor restores the previous test part result reporter. - virtual ~ScopedFakeTestPartResultReporter(); - - // Appends the TestPartResult object to the TestPartResultArray - // received in the constructor. - // - // This method is from the TestPartResultReporterInterface - // interface. - virtual void ReportTestPartResult(const TestPartResult& result); - private: - void Init(); - - const InterceptMode intercept_mode_; - TestPartResultReporterInterface* old_reporter_; - TestPartResultArray* const result_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter); -}; - -namespace internal { - -// A helper class for implementing EXPECT_FATAL_FAILURE() and -// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given -// TestPartResultArray contains exactly one failure that has the given -// type and contains the given substring. If that's not the case, a -// non-fatal failure will be generated. -class GTEST_API_ SingleFailureChecker { - public: - // The constructor remembers the arguments. - SingleFailureChecker(const TestPartResultArray* results, - TestPartResult::Type type, - const string& substr); - ~SingleFailureChecker(); - private: - const TestPartResultArray* const results_; - const TestPartResult::Type type_; - const string substr_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); -}; - -} // namespace internal - -} // namespace testing - -// A set of macros for testing Google Test assertions or code that's expected -// to generate Google Test fatal failures. It verifies that the given -// statement will cause exactly one fatal Google Test failure with 'substr' -// being part of the failure message. -// -// There are two different versions of this macro. EXPECT_FATAL_FAILURE only -// affects and considers failures generated in the current thread and -// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. -// -// The verification of the assertion is done correctly even when the statement -// throws an exception or aborts the current function. -// -// Known restrictions: -// - 'statement' cannot reference local non-static variables or -// non-static members of the current object. -// - 'statement' cannot return a value. -// - You cannot stream a failure message to this macro. -// -// Note that even though the implementations of the following two -// macros are much alike, we cannot refactor them to use a common -// helper macro, due to some peculiarity in how the preprocessor -// works. The AcceptsMacroThatExpandsToUnprotectedComma test in -// gtest_unittest.cc will fail to compile if we do that. -#define EXPECT_FATAL_FAILURE(statement, substr) \ - do { \ - class GTestExpectFatalFailureHelper {\ - public:\ - static void Execute() { statement; }\ - };\ - ::testing::TestPartResultArray gtest_failures;\ - ::testing::internal::SingleFailureChecker gtest_checker(\ - >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ - {\ - ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ - ::testing::ScopedFakeTestPartResultReporter:: \ - INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ - GTestExpectFatalFailureHelper::Execute();\ - }\ - } while (::testing::internal::AlwaysFalse()) - -#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ - do { \ - class GTestExpectFatalFailureHelper {\ - public:\ - static void Execute() { statement; }\ - };\ - ::testing::TestPartResultArray gtest_failures;\ - ::testing::internal::SingleFailureChecker gtest_checker(\ - >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ - {\ - ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ - ::testing::ScopedFakeTestPartResultReporter:: \ - INTERCEPT_ALL_THREADS, >est_failures);\ - GTestExpectFatalFailureHelper::Execute();\ - }\ - } while (::testing::internal::AlwaysFalse()) - -// A macro for testing Google Test assertions or code that's expected to -// generate Google Test non-fatal failures. It asserts that the given -// statement will cause exactly one non-fatal Google Test failure with 'substr' -// being part of the failure message. -// -// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only -// affects and considers failures generated in the current thread and -// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. -// -// 'statement' is allowed to reference local variables and members of -// the current object. -// -// The verification of the assertion is done correctly even when the statement -// throws an exception or aborts the current function. -// -// Known restrictions: -// - You cannot stream a failure message to this macro. -// -// Note that even though the implementations of the following two -// macros are much alike, we cannot refactor them to use a common -// helper macro, due to some peculiarity in how the preprocessor -// works. If we do that, the code won't compile when the user gives -// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that -// expands to code containing an unprotected comma. The -// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc -// catches that. -// -// For the same reason, we have to write -// if (::testing::internal::AlwaysTrue()) { statement; } -// instead of -// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) -// to avoid an MSVC warning on unreachable code. -#define EXPECT_NONFATAL_FAILURE(statement, substr) \ - do {\ - ::testing::TestPartResultArray gtest_failures;\ - ::testing::internal::SingleFailureChecker gtest_checker(\ - >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ - (substr));\ - {\ - ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ - ::testing::ScopedFakeTestPartResultReporter:: \ - INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ - if (::testing::internal::AlwaysTrue()) { statement; }\ - }\ - } while (::testing::internal::AlwaysFalse()) - -#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ - do {\ - ::testing::TestPartResultArray gtest_failures;\ - ::testing::internal::SingleFailureChecker gtest_checker(\ - >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ - (substr));\ - {\ - ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ - ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \ - >est_failures);\ - if (::testing::internal::AlwaysTrue()) { statement; }\ - }\ - } while (::testing::internal::AlwaysFalse()) - -#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ \ No newline at end of file diff --git a/src/gtest/include/gtest/gtest-test-part.h b/src/gtest/include/gtest/gtest-test-part.h deleted file mode 100644 index 3db5916e..00000000 --- a/src/gtest/include/gtest/gtest-test-part.h +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright 2008 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// -// - -#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ -#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ - -#include -#include -#include "gtest/internal/gtest-internal.h" -#include "gtest/internal/gtest-string.h" - -namespace testing { - -// A copyable object representing the result of a test part (i.e. an -// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). -// -// Don't inherit from TestPartResult as its destructor is not virtual. -class GTEST_API_ TestPartResult { - public: - // The possible outcomes of a test part (i.e. an assertion or an - // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). - enum Type { - kSuccess, // Succeeded. - kNonFatalFailure, // Failed but the test can continue. - kFatalFailure // Failed and the test should be terminated. - }; - - // C'tor. TestPartResult does NOT have a default constructor. - // Always use this constructor (with parameters) to create a - // TestPartResult object. - TestPartResult(Type a_type, - const char* a_file_name, - int a_line_number, - const char* a_message) - : type_(a_type), - file_name_(a_file_name == NULL ? "" : a_file_name), - line_number_(a_line_number), - summary_(ExtractSummary(a_message)), - message_(a_message) { - } - - // Gets the outcome of the test part. - Type type() const { return type_; } - - // Gets the name of the source file where the test part took place, or - // NULL if it's unknown. - const char* file_name() const { - return file_name_.empty() ? NULL : file_name_.c_str(); - } - - // Gets the line in the source file where the test part took place, - // or -1 if it's unknown. - int line_number() const { return line_number_; } - - // Gets the summary of the failure message. - const char* summary() const { return summary_.c_str(); } - - // Gets the message associated with the test part. - const char* message() const { return message_.c_str(); } - - // Returns true iff the test part passed. - bool passed() const { return type_ == kSuccess; } - - // Returns true iff the test part failed. - bool failed() const { return type_ != kSuccess; } - - // Returns true iff the test part non-fatally failed. - bool nonfatally_failed() const { return type_ == kNonFatalFailure; } - - // Returns true iff the test part fatally failed. - bool fatally_failed() const { return type_ == kFatalFailure; } - - private: - Type type_; - - // Gets the summary of the failure message by omitting the stack - // trace in it. - static std::string ExtractSummary(const char* message); - - // The name of the source file where the test part took place, or - // "" if the source file is unknown. - std::string file_name_; - // The line in the source file where the test part took place, or -1 - // if the line number is unknown. - int line_number_; - std::string summary_; // The test failure summary. - std::string message_; // The test failure message. -}; - -// Prints a TestPartResult object. -std::ostream& operator<<(std::ostream& os, const TestPartResult& result); - -// An array of TestPartResult objects. -// -// Don't inherit from TestPartResultArray as its destructor is not -// virtual. -class GTEST_API_ TestPartResultArray { - public: - TestPartResultArray() {} - - // Appends the given TestPartResult to the array. - void Append(const TestPartResult& result); - - // Returns the TestPartResult at the given index (0-based). - const TestPartResult& GetTestPartResult(int index) const; - - // Returns the number of TestPartResult objects in the array. - int size() const; - - private: - std::vector array_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); -}; - -// This interface knows how to report a test part result. -class TestPartResultReporterInterface { - public: - virtual ~TestPartResultReporterInterface() {} - - virtual void ReportTestPartResult(const TestPartResult& result) = 0; -}; - -namespace internal { - -// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a -// statement generates new fatal failures. To do so it registers itself as the -// current test part result reporter. Besides checking if fatal failures were -// reported, it only delegates the reporting to the former result reporter. -// The original result reporter is restored in the destructor. -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -class GTEST_API_ HasNewFatalFailureHelper - : public TestPartResultReporterInterface { - public: - HasNewFatalFailureHelper(); - virtual ~HasNewFatalFailureHelper(); - virtual void ReportTestPartResult(const TestPartResult& result); - bool has_new_fatal_failure() const { return has_new_fatal_failure_; } - private: - bool has_new_fatal_failure_; - TestPartResultReporterInterface* original_reporter_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); -}; - -} // namespace internal - -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ \ No newline at end of file diff --git a/src/gtest/include/gtest/gtest-typed-test.h b/src/gtest/include/gtest/gtest-typed-test.h deleted file mode 100644 index aff5f255..00000000 --- a/src/gtest/include/gtest/gtest-typed-test.h +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright 2008 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// - -#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ - -// This header implements typed tests and type-parameterized tests. - -// Typed (aka type-driven) tests repeat the same test for types in a -// list. You must know which types you want to test with when writing -// typed tests. Here's how you do it: - -#if 0 - -// First, define a fixture class template. It should be parameterized -// by a type. Remember to derive it from testing::Test. -template -class FooTest : public testing::Test { - public: - ... - typedef std::list List; - static T shared_; - T value_; -}; - -// Next, associate a list of types with the test case, which will be -// repeated for each type in the list. The typedef is necessary for -// the macro to parse correctly. -typedef testing::Types MyTypes; -TYPED_TEST_CASE(FooTest, MyTypes); - -// If the type list contains only one type, you can write that type -// directly without Types<...>: -// TYPED_TEST_CASE(FooTest, int); - -// Then, use TYPED_TEST() instead of TEST_F() to define as many typed -// tests for this test case as you want. -TYPED_TEST(FooTest, DoesBlah) { - // Inside a test, refer to TypeParam to get the type parameter. - // Since we are inside a derived class template, C++ requires use to - // visit the members of FooTest via 'this'. - TypeParam n = this->value_; - - // To visit static members of the fixture, add the TestFixture:: - // prefix. - n += TestFixture::shared_; - - // To refer to typedefs in the fixture, add the "typename - // TestFixture::" prefix. - typename TestFixture::List values; - values.push_back(n); - ... -} - -TYPED_TEST(FooTest, HasPropertyA) { ... } - -#endif // 0 - -// Type-parameterized tests are abstract test patterns parameterized -// by a type. Compared with typed tests, type-parameterized tests -// allow you to define the test pattern without knowing what the type -// parameters are. The defined pattern can be instantiated with -// different types any number of times, in any number of translation -// units. -// -// If you are designing an interface or concept, you can define a -// suite of type-parameterized tests to verify properties that any -// valid implementation of the interface/concept should have. Then, -// each implementation can easily instantiate the test suite to verify -// that it conforms to the requirements, without having to write -// similar tests repeatedly. Here's an example: - -#if 0 - -// First, define a fixture class template. It should be parameterized -// by a type. Remember to derive it from testing::Test. -template -class FooTest : public testing::Test { - ... -}; - -// Next, declare that you will define a type-parameterized test case -// (the _P suffix is for "parameterized" or "pattern", whichever you -// prefer): -TYPED_TEST_CASE_P(FooTest); - -// Then, use TYPED_TEST_P() to define as many type-parameterized tests -// for this type-parameterized test case as you want. -TYPED_TEST_P(FooTest, DoesBlah) { - // Inside a test, refer to TypeParam to get the type parameter. - TypeParam n = 0; - ... -} - -TYPED_TEST_P(FooTest, HasPropertyA) { ... } - -// Now the tricky part: you need to register all test patterns before -// you can instantiate them. The first argument of the macro is the -// test case name; the rest are the names of the tests in this test -// case. -REGISTER_TYPED_TEST_CASE_P(FooTest, - DoesBlah, HasPropertyA); - -// Finally, you are free to instantiate the pattern with the types you -// want. If you put the above code in a header file, you can #include -// it in multiple C++ source files and instantiate it multiple times. -// -// To distinguish different instances of the pattern, the first -// argument to the INSTANTIATE_* macro is a prefix that will be added -// to the actual test case name. Remember to pick unique prefixes for -// different instances. -typedef testing::Types MyTypes; -INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); - -// If the type list contains only one type, you can write that type -// directly without Types<...>: -// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); - -#endif // 0 - -#include "gtest/internal/gtest-port.h" -#include "gtest/internal/gtest-type-util.h" - -// Implements typed tests. - -#if GTEST_HAS_TYPED_TEST - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Expands to the name of the typedef for the type parameters of the -// given test case. -# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ - -// The 'Types' template argument below must have spaces around it -// since some compilers may choke on '>>' when passing a template -// instance (e.g. Types) -# define TYPED_TEST_CASE(CaseName, Types) \ - typedef ::testing::internal::TypeList< Types >::type \ - GTEST_TYPE_PARAMS_(CaseName) - -# define TYPED_TEST(CaseName, TestName) \ - template \ - class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ - : public CaseName { \ - private: \ - typedef CaseName TestFixture; \ - typedef gtest_TypeParam_ TypeParam; \ - virtual void TestBody(); \ - }; \ - bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::internal::TypeParameterizedTest< \ - CaseName, \ - ::testing::internal::TemplateSel< \ - GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \ - GTEST_TYPE_PARAMS_(CaseName)>::Register(\ - "", #CaseName, #TestName, 0); \ - template \ - void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::TestBody() - -#endif // GTEST_HAS_TYPED_TEST - -// Implements type-parameterized tests. - -#if GTEST_HAS_TYPED_TEST_P - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Expands to the namespace name that the type-parameterized tests for -// the given type-parameterized test case are defined in. The exact -// name of the namespace is subject to change without notice. -# define GTEST_CASE_NAMESPACE_(TestCaseName) \ - gtest_case_##TestCaseName##_ - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Expands to the name of the variable used to remember the names of -// the defined tests in the given test case. -# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \ - gtest_typed_test_case_p_state_##TestCaseName##_ - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. -// -// Expands to the name of the variable used to remember the names of -// the registered tests in the given test case. -# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \ - gtest_registered_test_names_##TestCaseName##_ - -// The variables defined in the type-parameterized test macros are -// static as typically these macros are used in a .h file that can be -// #included in multiple translation units linked together. -# define TYPED_TEST_CASE_P(CaseName) \ - static ::testing::internal::TypedTestCasePState \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName) - -# define TYPED_TEST_P(CaseName, TestName) \ - namespace GTEST_CASE_NAMESPACE_(CaseName) { \ - template \ - class TestName : public CaseName { \ - private: \ - typedef CaseName TestFixture; \ - typedef gtest_TypeParam_ TypeParam; \ - virtual void TestBody(); \ - }; \ - static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\ - __FILE__, __LINE__, #CaseName, #TestName); \ - } \ - template \ - void GTEST_CASE_NAMESPACE_(CaseName)::TestName::TestBody() - -# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \ - namespace GTEST_CASE_NAMESPACE_(CaseName) { \ - typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ - } \ - static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\ - __FILE__, __LINE__, #__VA_ARGS__) - -// The 'Types' template argument below must have spaces around it -// since some compilers may choke on '>>' when passing a template -// instance (e.g. Types) -# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ - bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::internal::TypeParameterizedTestCase::type>::Register(\ - #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) - -#endif // GTEST_HAS_TYPED_TEST_P - -#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ \ No newline at end of file diff --git a/src/gtest/include/gtest/gtest.h b/src/gtest/include/gtest/gtest.h deleted file mode 100644 index b18588ef..00000000 --- a/src/gtest/include/gtest/gtest.h +++ /dev/null @@ -1,2341 +0,0 @@ -// Copyright 2005 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// -// -// The Google C++ Testing Framework (Google Test) -// -// This header file defines the public API for Google Test. It should be -// included by any test program that uses Google Test. -// -// IMPORTANT NOTE: Due to limitation of the C++ language, we have to -// leave some internal implementation details in this header file. -// They are clearly marked by comments like this: -// -// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -// -// Such code is NOT meant to be used by a user directly, and is subject -// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user -// program! -// -// Acknowledgment: Google Test borrowed the idea of automatic test -// registration from Barthelemy Dagenais' (barthelemy@prologique.com) -// easyUnit framework. - -#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_H_ - -#include -#include -#include - -#include "gtest/internal/gtest-internal.h" -#include "gtest/internal/gtest-string.h" -#include "gtest/gtest-death-test.h" -#include "gtest/gtest-message.h" -#include "gtest/gtest-param-test.h" -#include "gtest/gtest-printers.h" -#include "gtest/gtest_prod.h" -#include "gtest/gtest-test-part.h" -#include "gtest/gtest-typed-test.h" - -// Depending on the platform, different string classes are available. -// On Linux, in addition to ::std::string, Google also makes use of -// class ::string, which has the same interface as ::std::string, but -// has a different implementation. -// -// You can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that -// ::string is available AND is a distinct type to ::std::string, or -// define it to 0 to indicate otherwise. -// -// If ::std::string and ::string are the same class on your platform -// due to aliasing, you should define GTEST_HAS_GLOBAL_STRING to 0. -// -// If you do not define GTEST_HAS_GLOBAL_STRING, it is defined -// heuristically. - -namespace testing { - -// Declares the flags. - -// This flag temporary enables the disabled tests. -GTEST_DECLARE_bool_(also_run_disabled_tests); - -// This flag brings the debugger on an assertion failure. -GTEST_DECLARE_bool_(break_on_failure); - -// This flag controls whether Google Test catches all test-thrown exceptions -// and logs them as failures. -GTEST_DECLARE_bool_(catch_exceptions); - -// This flag enables using colors in terminal output. Available values are -// "yes" to enable colors, "no" (disable colors), or "auto" (the default) -// to let Google Test decide. -GTEST_DECLARE_string_(color); - -// This flag sets up the filter to select by name using a glob pattern -// the tests to run. If the filter is not given all tests are executed. -GTEST_DECLARE_string_(filter); - -// This flag causes the Google Test to list tests. None of the tests listed -// are actually run if the flag is provided. -GTEST_DECLARE_bool_(list_tests); - -// This flag controls whether Google Test emits a detailed XML report to a file -// in addition to its normal textual output. -GTEST_DECLARE_string_(output); - -// This flags control whether Google Test prints the elapsed time for each -// test. -GTEST_DECLARE_bool_(print_time); - -// This flag specifies the random number seed. -GTEST_DECLARE_int32_(random_seed); - -// This flag sets how many times the tests are repeated. The default value -// is 1. If the value is -1 the tests are repeating forever. -GTEST_DECLARE_int32_(repeat); - -// This flag controls whether Google Test includes Google Test internal -// stack frames in failure stack traces. -GTEST_DECLARE_bool_(show_internal_stack_frames); - -// When this flag is specified, tests' order is randomized on every iteration. -GTEST_DECLARE_bool_(shuffle); - -// This flag specifies the maximum number of stack frames to be -// printed in a failure message. -GTEST_DECLARE_int32_(stack_trace_depth); - -// When this flag is specified, a failed assertion will throw an -// exception if exceptions are enabled, or exit the program with a -// non-zero code otherwise. -GTEST_DECLARE_bool_(throw_on_failure); - -// When this flag is set with a "host:port" string, on supported -// platforms test results are streamed to the specified port on -// the specified host machine. -GTEST_DECLARE_string_(stream_result_to); - -// The upper limit for valid stack trace depths. -const int kMaxStackTraceDepth = 100; - -namespace internal { - -class AssertHelper; -class DefaultGlobalTestPartResultReporter; -class ExecDeathTest; -class NoExecDeathTest; -class FinalSuccessChecker; -class GTestFlagSaver; -class StreamingListenerTest; -class TestResultAccessor; -class TestEventListenersAccessor; -class TestEventRepeater; -class UnitTestRecordPropertyTestHelper; -class WindowsDeathTest; -class UnitTestImpl* GetUnitTestImpl(); -void ReportFailureInUnknownLocation(TestPartResult::Type result_type, - const std::string& message); - -} // namespace internal - -// The friend relationship of some of these classes is cyclic. -// If we don't forward declare them the compiler might confuse the classes -// in friendship clauses with same named classes on the scope. -class Test; -class TestCase; -class TestInfo; -class UnitTest; - -// A class for indicating whether an assertion was successful. When -// the assertion wasn't successful, the AssertionResult object -// remembers a non-empty message that describes how it failed. -// -// To create an instance of this class, use one of the factory functions -// (AssertionSuccess() and AssertionFailure()). -// -// This class is useful for two purposes: -// 1. Defining predicate functions to be used with Boolean test assertions -// EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts -// 2. Defining predicate-format functions to be -// used with predicate assertions (ASSERT_PRED_FORMAT*, etc). -// -// For example, if you define IsEven predicate: -// -// testing::AssertionResult IsEven(int n) { -// if ((n % 2) == 0) -// return testing::AssertionSuccess(); -// else -// return testing::AssertionFailure() << n << " is odd"; -// } -// -// Then the failed expectation EXPECT_TRUE(IsEven(Fib(5))) -// will print the message -// -// Value of: IsEven(Fib(5)) -// Actual: false (5 is odd) -// Expected: true -// -// instead of a more opaque -// -// Value of: IsEven(Fib(5)) -// Actual: false -// Expected: true -// -// in case IsEven is a simple Boolean predicate. -// -// If you expect your predicate to be reused and want to support informative -// messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up -// about half as often as positive ones in our tests), supply messages for -// both success and failure cases: -// -// testing::AssertionResult IsEven(int n) { -// if ((n % 2) == 0) -// return testing::AssertionSuccess() << n << " is even"; -// else -// return testing::AssertionFailure() << n << " is odd"; -// } -// -// Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print -// -// Value of: IsEven(Fib(6)) -// Actual: true (8 is even) -// Expected: false -// -// NB: Predicates that support negative Boolean assertions have reduced -// performance in positive ones so be careful not to use them in tests -// that have lots (tens of thousands) of positive Boolean assertions. -// -// To use this class with EXPECT_PRED_FORMAT assertions such as: -// -// // Verifies that Foo() returns an even number. -// EXPECT_PRED_FORMAT1(IsEven, Foo()); -// -// you need to define: -// -// testing::AssertionResult IsEven(const char* expr, int n) { -// if ((n % 2) == 0) -// return testing::AssertionSuccess(); -// else -// return testing::AssertionFailure() -// << "Expected: " << expr << " is even\n Actual: it's " << n; -// } -// -// If Foo() returns 5, you will see the following message: -// -// Expected: Foo() is even -// Actual: it's 5 -// -class GTEST_API_ AssertionResult { - public: - // Copy constructor. - // Used in EXPECT_TRUE/FALSE(assertion_result). - AssertionResult(const AssertionResult& other); - - GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 /* forcing value to bool */) - - // Used in the EXPECT_TRUE/FALSE(bool_expression). - // - // T must be contextually convertible to bool. - // - // The second parameter prevents this overload from being considered if - // the argument is implicitly convertible to AssertionResult. In that case - // we want AssertionResult's copy constructor to be used. - template - explicit AssertionResult( - const T& success, - typename internal::EnableIf< - !internal::ImplicitlyConvertible::value>::type* - /*enabler*/ = NULL) - : success_(success) {} - - GTEST_DISABLE_MSC_WARNINGS_POP_() - - // Assignment operator. - AssertionResult& operator=(AssertionResult other) { - swap(other); - return *this; - } - - // Returns true iff the assertion succeeded. - operator bool() const { return success_; } // NOLINT - - // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. - AssertionResult operator!() const; - - // Returns the text streamed into this AssertionResult. Test assertions - // use it when they fail (i.e., the predicate's outcome doesn't match the - // assertion's expectation). When nothing has been streamed into the - // object, returns an empty string. - const char* message() const { - return message_.get() != NULL ? message_->c_str() : ""; - } - // TODO(vladl@google.com): Remove this after making sure no clients use it. - // Deprecated; please use message() instead. - const char* failure_message() const { return message(); } - - // Streams a custom failure message into this object. - template AssertionResult& operator<<(const T& value) { - AppendMessage(Message() << value); - return *this; - } - - // Allows streaming basic output manipulators such as endl or flush into - // this object. - AssertionResult& operator<<( - ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) { - AppendMessage(Message() << basic_manipulator); - return *this; - } - - private: - // Appends the contents of message to message_. - void AppendMessage(const Message& a_message) { - if (message_.get() == NULL) - message_.reset(new ::std::string); - message_->append(a_message.GetString().c_str()); - } - - // Swap the contents of this AssertionResult with other. - void swap(AssertionResult& other); - - // Stores result of the assertion predicate. - bool success_; - // Stores the message describing the condition in case the expectation - // construct is not satisfied with the predicate's outcome. - // Referenced via a pointer to avoid taking too much stack frame space - // with test assertions. - internal::scoped_ptr< ::std::string> message_; -}; - -// Makes a successful assertion result. -GTEST_API_ AssertionResult AssertionSuccess(); - -// Makes a failed assertion result. -GTEST_API_ AssertionResult AssertionFailure(); - -// Makes a failed assertion result with the given failure message. -// Deprecated; use AssertionFailure() << msg. -GTEST_API_ AssertionResult AssertionFailure(const Message& msg); - -// The abstract class that all tests inherit from. -// -// In Google Test, a unit test program contains one or many TestCases, and -// each TestCase contains one or many Tests. -// -// When you define a test using the TEST macro, you don't need to -// explicitly derive from Test - the TEST macro automatically does -// this for you. -// -// The only time you derive from Test is when defining a test fixture -// to be used a TEST_F. For example: -// -// class FooTest : public testing::Test { -// protected: -// void SetUp() override { ... } -// void TearDown() override { ... } -// ... -// }; -// -// TEST_F(FooTest, Bar) { ... } -// TEST_F(FooTest, Baz) { ... } -// -// Test is not copyable. -class GTEST_API_ Test { - public: - friend class TestInfo; - - // Defines types for pointers to functions that set up and tear down - // a test case. - typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; - typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; - - // The d'tor is virtual as we intend to inherit from Test. - virtual ~Test(); - - // Sets up the stuff shared by all tests in this test case. - // - // Google Test will call Foo::SetUpTestCase() before running the first - // test in test case Foo. Hence a sub-class can define its own - // SetUpTestCase() method to shadow the one defined in the super - // class. - static void SetUpTestCase() {} - - // Tears down the stuff shared by all tests in this test case. - // - // Google Test will call Foo::TearDownTestCase() after running the last - // test in test case Foo. Hence a sub-class can define its own - // TearDownTestCase() method to shadow the one defined in the super - // class. - static void TearDownTestCase() {} - - // Returns true iff the current test has a fatal failure. - static bool HasFatalFailure(); - - // Returns true iff the current test has a non-fatal failure. - static bool HasNonfatalFailure(); - - // Returns true iff the current test has a (either fatal or - // non-fatal) failure. - static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } - - // Logs a property for the current test, test case, or for the entire - // invocation of the test program when used outside of the context of a - // test case. Only the last value for a given key is remembered. These - // are public static so they can be called from utility functions that are - // not members of the test fixture. Calls to RecordProperty made during - // lifespan of the test (from the moment its constructor starts to the - // moment its destructor finishes) will be output in XML as attributes of - // the element. Properties recorded from fixture's - // SetUpTestCase or TearDownTestCase are logged as attributes of the - // corresponding element. Calls to RecordProperty made in the - // global context (before or after invocation of RUN_ALL_TESTS and from - // SetUp/TearDown method of Environment objects registered with Google - // Test) will be output as attributes of the element. - static void RecordProperty(const std::string& key, const std::string& value); - static void RecordProperty(const std::string& key, int value); - - protected: - // Creates a Test object. - Test(); - - // Sets up the test fixture. - virtual void SetUp(); - - // Tears down the test fixture. - virtual void TearDown(); - - private: - // Returns true iff the current test has the same fixture class as - // the first test in the current test case. - static bool HasSameFixtureClass(); - - // Runs the test after the test fixture has been set up. - // - // A sub-class must implement this to define the test logic. - // - // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. - // Instead, use the TEST or TEST_F macro. - virtual void TestBody() = 0; - - // Sets up, executes, and tears down the test. - void Run(); - - // Deletes self. We deliberately pick an unusual name for this - // internal method to avoid clashing with names used in user TESTs. - void DeleteSelf_() { delete this; } - - // Uses a GTestFlagSaver to save and restore all Google Test flags. - const internal::GTestFlagSaver* const gtest_flag_saver_; - - // Often a user misspells SetUp() as Setup() and spends a long time - // wondering why it is never called by Google Test. The declaration of - // the following method is solely for catching such an error at - // compile time: - // - // - The return type is deliberately chosen to be not void, so it - // will be a conflict if void Setup() is declared in the user's - // test fixture. - // - // - This method is private, so it will be another compiler error - // if the method is called from the user's test fixture. - // - // DO NOT OVERRIDE THIS FUNCTION. - // - // If you see an error about overriding the following function or - // about it being private, you have mis-spelled SetUp() as Setup(). - struct Setup_should_be_spelled_SetUp {}; - virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } - - // We disallow copying Tests. - GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); -}; - -typedef internal::TimeInMillis TimeInMillis; - -// A copyable object representing a user specified test property which can be -// output as a key/value string pair. -// -// Don't inherit from TestProperty as its destructor is not virtual. -class TestProperty { - public: - // C'tor. TestProperty does NOT have a default constructor. - // Always use this constructor (with parameters) to create a - // TestProperty object. - TestProperty(const std::string& a_key, const std::string& a_value) : - key_(a_key), value_(a_value) { - } - - // Gets the user supplied key. - const char* key() const { - return key_.c_str(); - } - - // Gets the user supplied value. - const char* value() const { - return value_.c_str(); - } - - // Sets a new value, overriding the one supplied in the constructor. - void SetValue(const std::string& new_value) { - value_ = new_value; - } - - private: - // The key supplied by the user. - std::string key_; - // The value supplied by the user. - std::string value_; -}; - -// The result of a single Test. This includes a list of -// TestPartResults, a list of TestProperties, a count of how many -// death tests there are in the Test, and how much time it took to run -// the Test. -// -// TestResult is not copyable. -class GTEST_API_ TestResult { - public: - // Creates an empty TestResult. - TestResult(); - - // D'tor. Do not inherit from TestResult. - ~TestResult(); - - // Gets the number of all test parts. This is the sum of the number - // of successful test parts and the number of failed test parts. - int total_part_count() const; - - // Returns the number of the test properties. - int test_property_count() const; - - // Returns true iff the test passed (i.e. no test part failed). - bool Passed() const { return !Failed(); } - - // Returns true iff the test failed. - bool Failed() const; - - // Returns true iff the test fatally failed. - bool HasFatalFailure() const; - - // Returns true iff the test has a non-fatal failure. - bool HasNonfatalFailure() const; - - // Returns the elapsed time, in milliseconds. - TimeInMillis elapsed_time() const { return elapsed_time_; } - - // Returns the i-th test part result among all the results. i can range - // from 0 to test_property_count() - 1. If i is not in that range, aborts - // the program. - const TestPartResult& GetTestPartResult(int i) const; - - // Returns the i-th test property. i can range from 0 to - // test_property_count() - 1. If i is not in that range, aborts the - // program. - const TestProperty& GetTestProperty(int i) const; - - private: - friend class TestInfo; - friend class TestCase; - friend class UnitTest; - friend class internal::DefaultGlobalTestPartResultReporter; - friend class internal::ExecDeathTest; - friend class internal::TestResultAccessor; - friend class internal::UnitTestImpl; - friend class internal::WindowsDeathTest; - - // Gets the vector of TestPartResults. - const std::vector& test_part_results() const { - return test_part_results_; - } - - // Gets the vector of TestProperties. - const std::vector& test_properties() const { - return test_properties_; - } - - // Sets the elapsed time. - void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } - - // Adds a test property to the list. The property is validated and may add - // a non-fatal failure if invalid (e.g., if it conflicts with reserved - // key names). If a property is already recorded for the same key, the - // value will be updated, rather than storing multiple values for the same - // key. xml_element specifies the element for which the property is being - // recorded and is used for validation. - void RecordProperty(const std::string& xml_element, - const TestProperty& test_property); - - // Adds a failure if the key is a reserved attribute of Google Test - // testcase tags. Returns true if the property is valid. - // TODO(user): Validate attribute names are legal and human readable. - static bool ValidateTestProperty(const std::string& xml_element, - const TestProperty& test_property); - - // Adds a test part result to the list. - void AddTestPartResult(const TestPartResult& test_part_result); - - // Returns the death test count. - int death_test_count() const { return death_test_count_; } - - // Increments the death test count, returning the new count. - int increment_death_test_count() { return ++death_test_count_; } - - // Clears the test part results. - void ClearTestPartResults(); - - // Clears the object. - void Clear(); - - // Protects mutable state of the property vector and of owned - // properties, whose values may be updated. - internal::Mutex test_properites_mutex_; - - // The vector of TestPartResults - std::vector test_part_results_; - // The vector of TestProperties - std::vector test_properties_; - // Running count of death tests. - int death_test_count_; - // The elapsed time, in milliseconds. - TimeInMillis elapsed_time_; - - // We disallow copying TestResult. - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); -}; // class TestResult - -// A TestInfo object stores the following information about a test: -// -// Test case name -// Test name -// Whether the test should be run -// A function pointer that creates the test object when invoked -// Test result -// -// The constructor of TestInfo registers itself with the UnitTest -// singleton such that the RUN_ALL_TESTS() macro knows which tests to -// run. -class GTEST_API_ TestInfo { - public: - // Destructs a TestInfo object. This function is not virtual, so - // don't inherit from TestInfo. - ~TestInfo(); - - // Returns the test case name. - const char* test_case_name() const { return test_case_name_.c_str(); } - - // Returns the test name. - const char* name() const { return name_.c_str(); } - - // Returns the name of the parameter type, or NULL if this is not a typed - // or a type-parameterized test. - const char* type_param() const { - if (type_param_.get() != NULL) - return type_param_->c_str(); - return NULL; - } - - // Returns the text representation of the value parameter, or NULL if this - // is not a value-parameterized test. - const char* value_param() const { - if (value_param_.get() != NULL) - return value_param_->c_str(); - return NULL; - } - - // Returns true if this test should run, that is if the test is not - // disabled (or it is disabled but the also_run_disabled_tests flag has - // been specified) and its full name matches the user-specified filter. - // - // Google Test allows the user to filter the tests by their full names. - // The full name of a test Bar in test case Foo is defined as - // "Foo.Bar". Only the tests that match the filter will run. - // - // A filter is a colon-separated list of glob (not regex) patterns, - // optionally followed by a '-' and a colon-separated list of - // negative patterns (tests to exclude). A test is run if it - // matches one of the positive patterns and does not match any of - // the negative patterns. - // - // For example, *A*:Foo.* is a filter that matches any string that - // contains the character 'A' or starts with "Foo.". - bool should_run() const { return should_run_; } - - // Returns true iff this test will appear in the XML report. - bool is_reportable() const { - // For now, the XML report includes all tests matching the filter. - // In the future, we may trim tests that are excluded because of - // sharding. - return matches_filter_; - } - - // Returns the result of the test. - const TestResult* result() const { return &result_; } - - private: -#if GTEST_HAS_DEATH_TEST - friend class internal::DefaultDeathTestFactory; -#endif // GTEST_HAS_DEATH_TEST - friend class Test; - friend class TestCase; - friend class internal::UnitTestImpl; - friend class internal::StreamingListenerTest; - friend TestInfo* internal::MakeAndRegisterTestInfo( - const char* test_case_name, - const char* name, - const char* type_param, - const char* value_param, - internal::TypeId fixture_class_id, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc, - internal::TestFactoryBase* factory); - - // Constructs a TestInfo object. The newly constructed instance assumes - // ownership of the factory object. - TestInfo(const std::string& test_case_name, - const std::string& name, - const char* a_type_param, // NULL if not a type-parameterized test - const char* a_value_param, // NULL if not a value-parameterized test - internal::TypeId fixture_class_id, - internal::TestFactoryBase* factory); - - // Increments the number of death tests encountered in this test so - // far. - int increment_death_test_count() { - return result_.increment_death_test_count(); - } - - // Creates the test object, runs it, records its result, and then - // deletes it. - void Run(); - - static void ClearTestResult(TestInfo* test_info) { - test_info->result_.Clear(); - } - - // These fields are immutable properties of the test. - const std::string test_case_name_; // Test case name - const std::string name_; // Test name - // Name of the parameter type, or NULL if this is not a typed or a - // type-parameterized test. - const internal::scoped_ptr type_param_; - // Text representation of the value parameter, or NULL if this is not a - // value-parameterized test. - const internal::scoped_ptr value_param_; - const internal::TypeId fixture_class_id_; // ID of the test fixture class - bool should_run_; // True iff this test should run - bool is_disabled_; // True iff this test is disabled - bool matches_filter_; // True if this test matches the - // user-specified filter. - internal::TestFactoryBase* const factory_; // The factory that creates - // the test object - - // This field is mutable and needs to be reset before running the - // test for the second time. - TestResult result_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); -}; - -// A test case, which consists of a vector of TestInfos. -// -// TestCase is not copyable. -class GTEST_API_ TestCase { - public: - // Creates a TestCase with the given name. - // - // TestCase does NOT have a default constructor. Always use this - // constructor to create a TestCase object. - // - // Arguments: - // - // name: name of the test case - // a_type_param: the name of the test's type parameter, or NULL if - // this is not a type-parameterized test. - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - TestCase(const char* name, const char* a_type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc); - - // Destructor of TestCase. - virtual ~TestCase(); - - // Gets the name of the TestCase. - const char* name() const { return name_.c_str(); } - - // Returns the name of the parameter type, or NULL if this is not a - // type-parameterized test case. - const char* type_param() const { - if (type_param_.get() != NULL) - return type_param_->c_str(); - return NULL; - } - - // Returns true if any test in this test case should run. - bool should_run() const { return should_run_; } - - // Gets the number of successful tests in this test case. - int successful_test_count() const; - - // Gets the number of failed tests in this test case. - int failed_test_count() const; - - // Gets the number of disabled tests that will be reported in the XML report. - int reportable_disabled_test_count() const; - - // Gets the number of disabled tests in this test case. - int disabled_test_count() const; - - // Gets the number of tests to be printed in the XML report. - int reportable_test_count() const; - - // Get the number of tests in this test case that should run. - int test_to_run_count() const; - - // Gets the number of all tests in this test case. - int total_test_count() const; - - // Returns true iff the test case passed. - bool Passed() const { return !Failed(); } - - // Returns true iff the test case failed. - bool Failed() const { return failed_test_count() > 0; } - - // Returns the elapsed time, in milliseconds. - TimeInMillis elapsed_time() const { return elapsed_time_; } - - // Returns the i-th test among all the tests. i can range from 0 to - // total_test_count() - 1. If i is not in that range, returns NULL. - const TestInfo* GetTestInfo(int i) const; - - // Returns the TestResult that holds test properties recorded during - // execution of SetUpTestCase and TearDownTestCase. - const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; } - - private: - friend class Test; - friend class internal::UnitTestImpl; - - // Gets the (mutable) vector of TestInfos in this TestCase. - std::vector& test_info_list() { return test_info_list_; } - - // Gets the (immutable) vector of TestInfos in this TestCase. - const std::vector& test_info_list() const { - return test_info_list_; - } - - // Returns the i-th test among all the tests. i can range from 0 to - // total_test_count() - 1. If i is not in that range, returns NULL. - TestInfo* GetMutableTestInfo(int i); - - // Sets the should_run member. - void set_should_run(bool should) { should_run_ = should; } - - // Adds a TestInfo to this test case. Will delete the TestInfo upon - // destruction of the TestCase object. - void AddTestInfo(TestInfo * test_info); - - // Clears the results of all tests in this test case. - void ClearResult(); - - // Clears the results of all tests in the given test case. - static void ClearTestCaseResult(TestCase* test_case) { - test_case->ClearResult(); - } - - // Runs every test in this TestCase. - void Run(); - - // Runs SetUpTestCase() for this TestCase. This wrapper is needed - // for catching exceptions thrown from SetUpTestCase(). - void RunSetUpTestCase() { (*set_up_tc_)(); } - - // Runs TearDownTestCase() for this TestCase. This wrapper is - // needed for catching exceptions thrown from TearDownTestCase(). - void RunTearDownTestCase() { (*tear_down_tc_)(); } - - // Returns true iff test passed. - static bool TestPassed(const TestInfo* test_info) { - return test_info->should_run() && test_info->result()->Passed(); - } - - // Returns true iff test failed. - static bool TestFailed(const TestInfo* test_info) { - return test_info->should_run() && test_info->result()->Failed(); - } - - // Returns true iff the test is disabled and will be reported in the XML - // report. - static bool TestReportableDisabled(const TestInfo* test_info) { - return test_info->is_reportable() && test_info->is_disabled_; - } - - // Returns true iff test is disabled. - static bool TestDisabled(const TestInfo* test_info) { - return test_info->is_disabled_; - } - - // Returns true iff this test will appear in the XML report. - static bool TestReportable(const TestInfo* test_info) { - return test_info->is_reportable(); - } - - // Returns true if the given test should run. - static bool ShouldRunTest(const TestInfo* test_info) { - return test_info->should_run(); - } - - // Shuffles the tests in this test case. - void ShuffleTests(internal::Random* random); - - // Restores the test order to before the first shuffle. - void UnshuffleTests(); - - // Name of the test case. - std::string name_; - // Name of the parameter type, or NULL if this is not a typed or a - // type-parameterized test. - const internal::scoped_ptr type_param_; - // The vector of TestInfos in their original order. It owns the - // elements in the vector. - std::vector test_info_list_; - // Provides a level of indirection for the test list to allow easy - // shuffling and restoring the test order. The i-th element in this - // vector is the index of the i-th test in the shuffled test list. - std::vector test_indices_; - // Pointer to the function that sets up the test case. - Test::SetUpTestCaseFunc set_up_tc_; - // Pointer to the function that tears down the test case. - Test::TearDownTestCaseFunc tear_down_tc_; - // True iff any test in this test case should run. - bool should_run_; - // Elapsed time, in milliseconds. - TimeInMillis elapsed_time_; - // Holds test properties recorded during execution of SetUpTestCase and - // TearDownTestCase. - TestResult ad_hoc_test_result_; - - // We disallow copying TestCases. - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); -}; - -// An Environment object is capable of setting up and tearing down an -// environment. You should subclass this to define your own -// environment(s). -// -// An Environment object does the set-up and tear-down in virtual -// methods SetUp() and TearDown() instead of the constructor and the -// destructor, as: -// -// 1. You cannot safely throw from a destructor. This is a problem -// as in some cases Google Test is used where exceptions are enabled, and -// we may want to implement ASSERT_* using exceptions where they are -// available. -// 2. You cannot use ASSERT_* directly in a constructor or -// destructor. -class Environment { - public: - // The d'tor is virtual as we need to subclass Environment. - virtual ~Environment() {} - - // Override this to define how to set up the environment. - virtual void SetUp() {} - - // Override this to define how to tear down the environment. - virtual void TearDown() {} - private: - // If you see an error about overriding the following function or - // about it being private, you have mis-spelled SetUp() as Setup(). - struct Setup_should_be_spelled_SetUp {}; - virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } -}; - -// The interface for tracing execution of tests. The methods are organized in -// the order the corresponding events are fired. -class TestEventListener { - public: - virtual ~TestEventListener() {} - - // Fired before any test activity starts. - virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; - - // Fired before each iteration of tests starts. There may be more than - // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration - // index, starting from 0. - virtual void OnTestIterationStart(const UnitTest& unit_test, - int iteration) = 0; - - // Fired before environment set-up for each iteration of tests starts. - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; - - // Fired after environment set-up for each iteration of tests ends. - virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; - - // Fired before the test case starts. - virtual void OnTestCaseStart(const TestCase& test_case) = 0; - - // Fired before the test starts. - virtual void OnTestStart(const TestInfo& test_info) = 0; - - // Fired after a failed assertion or a SUCCEED() invocation. - virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; - - // Fired after the test ends. - virtual void OnTestEnd(const TestInfo& test_info) = 0; - - // Fired after the test case ends. - virtual void OnTestCaseEnd(const TestCase& test_case) = 0; - - // Fired before environment tear-down for each iteration of tests starts. - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; - - // Fired after environment tear-down for each iteration of tests ends. - virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0; - - // Fired after each iteration of tests finishes. - virtual void OnTestIterationEnd(const UnitTest& unit_test, - int iteration) = 0; - - // Fired after all test activities have ended. - virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; -}; - -// The convenience class for users who need to override just one or two -// methods and are not concerned that a possible change to a signature of -// the methods they override will not be caught during the build. For -// comments about each method please see the definition of TestEventListener -// above. -class EmptyTestEventListener : public TestEventListener { - public: - virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, - int /*iteration*/) {} - virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} - virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} - virtual void OnTestStart(const TestInfo& /*test_info*/) {} - virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} - virtual void OnTestEnd(const TestInfo& /*test_info*/) {} - virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} - virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} - virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, - int /*iteration*/) {} - virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} -}; - -// TestEventListeners lets users add listeners to track events in Google Test. -class GTEST_API_ TestEventListeners { - public: - TestEventListeners(); - ~TestEventListeners(); - - // Appends an event listener to the end of the list. Google Test assumes - // the ownership of the listener (i.e. it will delete the listener when - // the test program finishes). - void Append(TestEventListener* listener); - - // Removes the given event listener from the list and returns it. It then - // becomes the caller's responsibility to delete the listener. Returns - // NULL if the listener is not found in the list. - TestEventListener* Release(TestEventListener* listener); - - // Returns the standard listener responsible for the default console - // output. Can be removed from the listeners list to shut down default - // console output. Note that removing this object from the listener list - // with Release transfers its ownership to the caller and makes this - // function return NULL the next time. - TestEventListener* default_result_printer() const { - return default_result_printer_; - } - - // Returns the standard listener responsible for the default XML output - // controlled by the --gtest_output=xml flag. Can be removed from the - // listeners list by users who want to shut down the default XML output - // controlled by this flag and substitute it with custom one. Note that - // removing this object from the listener list with Release transfers its - // ownership to the caller and makes this function return NULL the next - // time. - TestEventListener* default_xml_generator() const { - return default_xml_generator_; - } - - private: - friend class TestCase; - friend class TestInfo; - friend class internal::DefaultGlobalTestPartResultReporter; - friend class internal::NoExecDeathTest; - friend class internal::TestEventListenersAccessor; - friend class internal::UnitTestImpl; - - // Returns repeater that broadcasts the TestEventListener events to all - // subscribers. - TestEventListener* repeater(); - - // Sets the default_result_printer attribute to the provided listener. - // The listener is also added to the listener list and previous - // default_result_printer is removed from it and deleted. The listener can - // also be NULL in which case it will not be added to the list. Does - // nothing if the previous and the current listener objects are the same. - void SetDefaultResultPrinter(TestEventListener* listener); - - // Sets the default_xml_generator attribute to the provided listener. The - // listener is also added to the listener list and previous - // default_xml_generator is removed from it and deleted. The listener can - // also be NULL in which case it will not be added to the list. Does - // nothing if the previous and the current listener objects are the same. - void SetDefaultXmlGenerator(TestEventListener* listener); - - // Controls whether events will be forwarded by the repeater to the - // listeners in the list. - bool EventForwardingEnabled() const; - void SuppressEventForwarding(); - - // The actual list of listeners. - internal::TestEventRepeater* repeater_; - // Listener responsible for the standard result output. - TestEventListener* default_result_printer_; - // Listener responsible for the creation of the XML output file. - TestEventListener* default_xml_generator_; - - // We disallow copying TestEventListeners. - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); -}; - -// A UnitTest consists of a vector of TestCases. -// -// This is a singleton class. The only instance of UnitTest is -// created when UnitTest::GetInstance() is first called. This -// instance is never deleted. -// -// UnitTest is not copyable. -// -// This class is thread-safe as long as the methods are called -// according to their specification. -class GTEST_API_ UnitTest { - public: - // Gets the singleton UnitTest object. The first time this method - // is called, a UnitTest object is constructed and returned. - // Consecutive calls will return the same object. - static UnitTest* GetInstance(); - - // Runs all tests in this UnitTest object and prints the result. - // Returns 0 if successful, or 1 otherwise. - // - // This method can only be called from the main thread. - // - // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - int Run() GTEST_MUST_USE_RESULT_; - - // Returns the working directory when the first TEST() or TEST_F() - // was executed. The UnitTest object owns the string. - const char* original_working_dir() const; - - // Returns the TestCase object for the test that's currently running, - // or NULL if no test is running. - const TestCase* current_test_case() const - GTEST_LOCK_EXCLUDED_(mutex_); - - // Returns the TestInfo object for the test that's currently running, - // or NULL if no test is running. - const TestInfo* current_test_info() const - GTEST_LOCK_EXCLUDED_(mutex_); - - // Returns the random seed used at the start of the current test run. - int random_seed() const; - -#if GTEST_HAS_PARAM_TEST - // Returns the ParameterizedTestCaseRegistry object used to keep track of - // value-parameterized tests and instantiate and register them. - // - // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - internal::ParameterizedTestCaseRegistry& parameterized_test_registry() - GTEST_LOCK_EXCLUDED_(mutex_); -#endif // GTEST_HAS_PARAM_TEST - - // Gets the number of successful test cases. - int successful_test_case_count() const; - - // Gets the number of failed test cases. - int failed_test_case_count() const; - - // Gets the number of all test cases. - int total_test_case_count() const; - - // Gets the number of all test cases that contain at least one test - // that should run. - int test_case_to_run_count() const; - - // Gets the number of successful tests. - int successful_test_count() const; - - // Gets the number of failed tests. - int failed_test_count() const; - - // Gets the number of disabled tests that will be reported in the XML report. - int reportable_disabled_test_count() const; - - // Gets the number of disabled tests. - int disabled_test_count() const; - - // Gets the number of tests to be printed in the XML report. - int reportable_test_count() const; - - // Gets the number of all tests. - int total_test_count() const; - - // Gets the number of tests that should run. - int test_to_run_count() const; - - // Gets the time of the test program start, in ms from the start of the - // UNIX epoch. - TimeInMillis start_timestamp() const; - - // Gets the elapsed time, in milliseconds. - TimeInMillis elapsed_time() const; - - // Returns true iff the unit test passed (i.e. all test cases passed). - bool Passed() const; - - // Returns true iff the unit test failed (i.e. some test case failed - // or something outside of all tests failed). - bool Failed() const; - - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - const TestCase* GetTestCase(int i) const; - - // Returns the TestResult containing information on test failures and - // properties logged outside of individual test cases. - const TestResult& ad_hoc_test_result() const; - - // Returns the list of event listeners that can be used to track events - // inside Google Test. - TestEventListeners& listeners(); - - private: - // Registers and returns a global test environment. When a test - // program is run, all global test environments will be set-up in - // the order they were registered. After all tests in the program - // have finished, all global test environments will be torn-down in - // the *reverse* order they were registered. - // - // The UnitTest object takes ownership of the given environment. - // - // This method can only be called from the main thread. - Environment* AddEnvironment(Environment* env); - - // Adds a TestPartResult to the current TestResult object. All - // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) - // eventually call this to report their results. The user code - // should use the assertion macros instead of calling this directly. - void AddTestPartResult(TestPartResult::Type result_type, - const char* file_name, - int line_number, - const std::string& message, - const std::string& os_stack_trace) - GTEST_LOCK_EXCLUDED_(mutex_); - - // Adds a TestProperty to the current TestResult object when invoked from - // inside a test, to current TestCase's ad_hoc_test_result_ when invoked - // from SetUpTestCase or TearDownTestCase, or to the global property set - // when invoked elsewhere. If the result already contains a property with - // the same key, the value will be updated. - void RecordProperty(const std::string& key, const std::string& value); - - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - TestCase* GetMutableTestCase(int i); - - // Accessors for the implementation object. - internal::UnitTestImpl* impl() { return impl_; } - const internal::UnitTestImpl* impl() const { return impl_; } - - // These classes and funcions are friends as they need to access private - // members of UnitTest. - friend class Test; - friend class internal::AssertHelper; - friend class internal::ScopedTrace; - friend class internal::StreamingListenerTest; - friend class internal::UnitTestRecordPropertyTestHelper; - friend Environment* AddGlobalTestEnvironment(Environment* env); - friend internal::UnitTestImpl* internal::GetUnitTestImpl(); - friend void internal::ReportFailureInUnknownLocation( - TestPartResult::Type result_type, - const std::string& message); - - // Creates an empty UnitTest. - UnitTest(); - - // D'tor - virtual ~UnitTest(); - - // Pushes a trace defined by SCOPED_TRACE() on to the per-thread - // Google Test trace stack. - void PushGTestTrace(const internal::TraceInfo& trace) - GTEST_LOCK_EXCLUDED_(mutex_); - - // Pops a trace from the per-thread Google Test trace stack. - void PopGTestTrace() - GTEST_LOCK_EXCLUDED_(mutex_); - - // Protects mutable state in *impl_. This is mutable as some const - // methods need to lock it too. - mutable internal::Mutex mutex_; - - // Opaque implementation object. This field is never changed once - // the object is constructed. We don't mark it as const here, as - // doing so will cause a warning in the constructor of UnitTest. - // Mutable state in *impl_ is protected by mutex_. - internal::UnitTestImpl* impl_; - - // We disallow copying UnitTest. - GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest); -}; - -// A convenient wrapper for adding an environment for the test -// program. -// -// You should call this before RUN_ALL_TESTS() is called, probably in -// main(). If you use gtest_main, you need to call this before main() -// starts for it to take effect. For example, you can define a global -// variable like this: -// -// testing::Environment* const foo_env = -// testing::AddGlobalTestEnvironment(new FooEnvironment); -// -// However, we strongly recommend you to write your own main() and -// call AddGlobalTestEnvironment() there, as relying on initialization -// of global variables makes the code harder to read and may cause -// problems when you register multiple environments from different -// translation units and the environments have dependencies among them -// (remember that the compiler doesn't guarantee the order in which -// global variables from different translation units are initialized). -inline Environment* AddGlobalTestEnvironment(Environment* env) { - return UnitTest::GetInstance()->AddEnvironment(env); -} - -// Initializes Google Test. This must be called before calling -// RUN_ALL_TESTS(). In particular, it parses a command line for the -// flags that Google Test recognizes. Whenever a Google Test flag is -// seen, it is removed from argv, and *argc is decremented. -// -// No value is returned. Instead, the Google Test flag variables are -// updated. -// -// Calling the function for the second time has no user-visible effect. -GTEST_API_ void InitGoogleTest(int* argc, char** argv); - -// This overloaded version can be used in Windows programs compiled in -// UNICODE mode. -GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); - -namespace internal { - -// FormatForComparison::Format(value) formats a -// value of type ToPrint that is an operand of a comparison assertion -// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in -// the comparison, and is used to help determine the best way to -// format the value. In particular, when the value is a C string -// (char pointer) and the other operand is an STL string object, we -// want to format the C string as a string, since we know it is -// compared by value with the string object. If the value is a char -// pointer but the other operand is not an STL string object, we don't -// know whether the pointer is supposed to point to a NUL-terminated -// string, and thus want to print it as a pointer to be safe. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - -// The default case. -template -class FormatForComparison { - public: - static ::std::string Format(const ToPrint& value) { - return ::testing::PrintToString(value); - } -}; - -// Array. -template -class FormatForComparison { - public: - static ::std::string Format(const ToPrint* value) { - return FormatForComparison::Format(value); - } -}; - -// By default, print C string as pointers to be safe, as we don't know -// whether they actually point to a NUL-terminated string. - -#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \ - template \ - class FormatForComparison { \ - public: \ - static ::std::string Format(CharType* value) { \ - return ::testing::PrintToString(static_cast(value)); \ - } \ - } - -GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); -GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char); -GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t); -GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); - -#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_ - -// If a C string is compared with an STL string object, we know it's meant -// to point to a NUL-terminated string, and thus can print it as a string. - -#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \ - template <> \ - class FormatForComparison { \ - public: \ - static ::std::string Format(CharType* value) { \ - return ::testing::PrintToString(value); \ - } \ - } - -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); - -#if GTEST_HAS_GLOBAL_STRING -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string); -#endif - -#if GTEST_HAS_GLOBAL_WSTRING -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring); -#endif - -#if GTEST_HAS_STD_WSTRING -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); -#endif - -#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_ - -// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) -// operand to be used in a failure message. The type (but not value) -// of the other operand may affect the format. This allows us to -// print a char* as a raw pointer when it is compared against another -// char* or void*, and print it as a C string when it is compared -// against an std::string object, for example. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -template -std::string FormatForComparisonFailureMessage( - const T1& value, const T2& /* other_operand */) { - return FormatForComparison::Format(value); -} - -// Separate the error generating code from the code path to reduce the stack -// frame size of CmpHelperEQ. This helps reduce the overhead of some sanitizers -// when calling EXPECT_* in a tight loop. -template -AssertionResult CmpHelperEQFailure(const char* expected_expression, - const char* actual_expression, - const T1& expected, const T2& actual) { - return EqFailure(expected_expression, - actual_expression, - FormatForComparisonFailureMessage(expected, actual), - FormatForComparisonFailureMessage(actual, expected), - false); -} - -// The helper function for {ASSERT|EXPECT}_EQ. -template -AssertionResult CmpHelperEQ(const char* expected_expression, - const char* actual_expression, - const T1& expected, - const T2& actual) { -GTEST_DISABLE_MSC_WARNINGS_PUSH_(4389 /* signed/unsigned mismatch */) - if (expected == actual) { - return AssertionSuccess(); - } -GTEST_DISABLE_MSC_WARNINGS_POP_() - - return CmpHelperEQFailure(expected_expression, actual_expression, expected, - actual); -} - -// With this overloaded version, we allow anonymous enums to be used -// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums -// can be implicitly cast to BiggestInt. -GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression, - const char* actual_expression, - BiggestInt expected, - BiggestInt actual); - -// The helper class for {ASSERT|EXPECT}_EQ. The template argument -// lhs_is_null_literal is true iff the first argument to ASSERT_EQ() -// is a null pointer literal. The following default implementation is -// for lhs_is_null_literal being false. -template -class EqHelper { - public: - // This templatized version is for the general case. - template - static AssertionResult Compare(const char* expected_expression, - const char* actual_expression, - const T1& expected, - const T2& actual) { - return CmpHelperEQ(expected_expression, actual_expression, expected, - actual); - } - - // With this overloaded version, we allow anonymous enums to be used - // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous - // enums can be implicitly cast to BiggestInt. - // - // Even though its body looks the same as the above version, we - // cannot merge the two, as it will make anonymous enums unhappy. - static AssertionResult Compare(const char* expected_expression, - const char* actual_expression, - BiggestInt expected, - BiggestInt actual) { - return CmpHelperEQ(expected_expression, actual_expression, expected, - actual); - } -}; - -// This specialization is used when the first argument to ASSERT_EQ() -// is a null pointer literal, like NULL, false, or 0. -template <> -class EqHelper { - public: - // We define two overloaded versions of Compare(). The first - // version will be picked when the second argument to ASSERT_EQ() is - // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or - // EXPECT_EQ(false, a_bool). - template - static AssertionResult Compare( - const char* expected_expression, - const char* actual_expression, - const T1& expected, - const T2& actual, - // The following line prevents this overload from being considered if T2 - // is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr) - // expands to Compare("", "", NULL, my_ptr), which requires a conversion - // to match the Secret* in the other overload, which would otherwise make - // this template match better. - typename EnableIf::value>::type* = 0) { - return CmpHelperEQ(expected_expression, actual_expression, expected, - actual); - } - - // This version will be picked when the second argument to ASSERT_EQ() is a - // pointer, e.g. ASSERT_EQ(NULL, a_pointer). - template - static AssertionResult Compare( - const char* expected_expression, - const char* actual_expression, - // We used to have a second template parameter instead of Secret*. That - // template parameter would deduce to 'long', making this a better match - // than the first overload even without the first overload's EnableIf. - // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to - // non-pointer argument" (even a deduced integral argument), so the old - // implementation caused warnings in user code. - Secret* /* expected (NULL) */, - T* actual) { - // We already know that 'expected' is a null pointer. - return CmpHelperEQ(expected_expression, actual_expression, - static_cast(NULL), actual); - } -}; - -// Separate the error generating code from the code path to reduce the stack -// frame size of CmpHelperOP. This helps reduce the overhead of some sanitizers -// when calling EXPECT_OP in a tight loop. -template -AssertionResult CmpHelperOpFailure(const char* expr1, const char* expr2, - const T1& val1, const T2& val2, - const char* op) { - return AssertionFailure() - << "Expected: (" << expr1 << ") " << op << " (" << expr2 - << "), actual: " << FormatForComparisonFailureMessage(val1, val2) - << " vs " << FormatForComparisonFailureMessage(val2, val1); -} - -// A macro for implementing the helper functions needed to implement -// ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste -// of similar code. -// -// For each templatized helper function, we also define an overloaded -// version for BiggestInt in order to reduce code bloat and allow -// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled -// with gcc 4. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - -#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ -template \ -AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ - const T1& val1, const T2& val2) {\ - if (val1 op val2) {\ - return AssertionSuccess();\ - } else {\ - return CmpHelperOpFailure(expr1, expr2, val1, val2, #op);\ - }\ -}\ -GTEST_API_ AssertionResult CmpHelper##op_name(\ - const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2) - -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - -// Implements the helper function for {ASSERT|EXPECT}_NE -GTEST_IMPL_CMP_HELPER_(NE, !=); -// Implements the helper function for {ASSERT|EXPECT}_LE -GTEST_IMPL_CMP_HELPER_(LE, <=); -// Implements the helper function for {ASSERT|EXPECT}_LT -GTEST_IMPL_CMP_HELPER_(LT, <); -// Implements the helper function for {ASSERT|EXPECT}_GE -GTEST_IMPL_CMP_HELPER_(GE, >=); -// Implements the helper function for {ASSERT|EXPECT}_GT -GTEST_IMPL_CMP_HELPER_(GT, >); - -#undef GTEST_IMPL_CMP_HELPER_ - -// The helper function for {ASSERT|EXPECT}_STREQ. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual); - -// The helper function for {ASSERT|EXPECT}_STRCASEEQ. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual); - -// The helper function for {ASSERT|EXPECT}_STRNE. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, - const char* s2_expression, - const char* s1, - const char* s2); - -// The helper function for {ASSERT|EXPECT}_STRCASENE. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, - const char* s2_expression, - const char* s1, - const char* s2); - - -// Helper function for *_STREQ on wide strings. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const wchar_t* expected, - const wchar_t* actual); - -// Helper function for *_STRNE on wide strings. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, - const char* s2_expression, - const wchar_t* s1, - const wchar_t* s2); - -} // namespace internal - -// IsSubstring() and IsNotSubstring() are intended to be used as the -// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by -// themselves. They check whether needle is a substring of haystack -// (NULL is considered a substring of itself only), and return an -// appropriate error message when they fail. -// -// The {needle,haystack}_expr arguments are the stringified -// expressions that generated the two real arguments. -GTEST_API_ AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const char* needle, const char* haystack); -GTEST_API_ AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const wchar_t* needle, const wchar_t* haystack); -GTEST_API_ AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const char* needle, const char* haystack); -GTEST_API_ AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const wchar_t* needle, const wchar_t* haystack); -GTEST_API_ AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::string& needle, const ::std::string& haystack); -GTEST_API_ AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::string& needle, const ::std::string& haystack); - -#if GTEST_HAS_STD_WSTRING -GTEST_API_ AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::wstring& needle, const ::std::wstring& haystack); -GTEST_API_ AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::wstring& needle, const ::std::wstring& haystack); -#endif // GTEST_HAS_STD_WSTRING - -namespace internal { - -// Helper template function for comparing floating-points. -// -// Template parameter: -// -// RawType: the raw floating-point type (either float or double) -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -template -AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression, - const char* actual_expression, - RawType expected, - RawType actual) { - const FloatingPoint lhs(expected), rhs(actual); - - if (lhs.AlmostEquals(rhs)) { - return AssertionSuccess(); - } - - ::std::stringstream expected_ss; - expected_ss << std::setprecision(std::numeric_limits::digits10 + 2) - << expected; - - ::std::stringstream actual_ss; - actual_ss << std::setprecision(std::numeric_limits::digits10 + 2) - << actual; - - return EqFailure(expected_expression, - actual_expression, - StringStreamToString(&expected_ss), - StringStreamToString(&actual_ss), - false); -} - -// Helper function for implementing ASSERT_NEAR. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, - const char* expr2, - const char* abs_error_expr, - double val1, - double val2, - double abs_error); - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// A class that enables one to stream messages to assertion macros -class GTEST_API_ AssertHelper { - public: - // Constructor. - AssertHelper(TestPartResult::Type type, - const char* file, - int line, - const char* message); - ~AssertHelper(); - - // Message assignment is a semantic trick to enable assertion - // streaming; see the GTEST_MESSAGE_ macro below. - void operator=(const Message& message) const; - - private: - // We put our data in a struct so that the size of the AssertHelper class can - // be as small as possible. This is important because gcc is incapable of - // re-using stack space even for temporary variables, so every EXPECT_EQ - // reserves stack space for another AssertHelper. - struct AssertHelperData { - AssertHelperData(TestPartResult::Type t, - const char* srcfile, - int line_num, - const char* msg) - : type(t), file(srcfile), line(line_num), message(msg) { } - - TestPartResult::Type const type; - const char* const file; - int const line; - std::string const message; - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); - }; - - AssertHelperData* const data_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); -}; - -} // namespace internal - -#if GTEST_HAS_PARAM_TEST -// The pure interface class that all value-parameterized tests inherit from. -// A value-parameterized class must inherit from both ::testing::Test and -// ::testing::WithParamInterface. In most cases that just means inheriting -// from ::testing::TestWithParam, but more complicated test hierarchies -// may need to inherit from Test and WithParamInterface at different levels. -// -// This interface has support for accessing the test parameter value via -// the GetParam() method. -// -// Use it with one of the parameter generator defining functions, like Range(), -// Values(), ValuesIn(), Bool(), and Combine(). -// -// class FooTest : public ::testing::TestWithParam { -// protected: -// FooTest() { -// // Can use GetParam() here. -// } -// virtual ~FooTest() { -// // Can use GetParam() here. -// } -// virtual void SetUp() { -// // Can use GetParam() here. -// } -// virtual void TearDown { -// // Can use GetParam() here. -// } -// }; -// TEST_P(FooTest, DoesBar) { -// // Can use GetParam() method here. -// Foo foo; -// ASSERT_TRUE(foo.DoesBar(GetParam())); -// } -// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); - -template -class WithParamInterface { - public: - typedef T ParamType; - virtual ~WithParamInterface() {} - - // The current parameter value. Is also available in the test fixture's - // constructor. This member function is non-static, even though it only - // references static data, to reduce the opportunity for incorrect uses - // like writing 'WithParamInterface::GetParam()' for a test that - // uses a fixture whose parameter type is int. - const ParamType& GetParam() const { - GTEST_CHECK_(parameter_ != NULL) - << "GetParam() can only be called inside a value-parameterized test " - << "-- did you intend to write TEST_P instead of TEST_F?"; - return *parameter_; - } - - private: - // Sets parameter value. The caller is responsible for making sure the value - // remains alive and unchanged throughout the current test. - static void SetParam(const ParamType* parameter) { - parameter_ = parameter; - } - - // Static value used for accessing parameter during a test lifetime. - static const ParamType* parameter_; - - // TestClass must be a subclass of WithParamInterface and Test. - template friend class internal::ParameterizedTestFactory; -}; - -template -const T* WithParamInterface::parameter_ = NULL; - -// Most value-parameterized classes can ignore the existence of -// WithParamInterface, and can just inherit from ::testing::TestWithParam. - -template -class TestWithParam : public Test, public WithParamInterface { -}; - -#endif // GTEST_HAS_PARAM_TEST - -// Macros for indicating success/failure in test code. - -// ADD_FAILURE unconditionally adds a failure to the current test. -// SUCCEED generates a success - it doesn't automatically make the -// current test successful, as a test is only successful when it has -// no failure. -// -// EXPECT_* verifies that a certain condition is satisfied. If not, -// it behaves like ADD_FAILURE. In particular: -// -// EXPECT_TRUE verifies that a Boolean condition is true. -// EXPECT_FALSE verifies that a Boolean condition is false. -// -// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except -// that they will also abort the current function on failure. People -// usually want the fail-fast behavior of FAIL and ASSERT_*, but those -// writing data-driven tests often find themselves using ADD_FAILURE -// and EXPECT_* more. - -// Generates a nonfatal failure with a generic message. -#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") - -// Generates a nonfatal failure at the given source file location with -// a generic message. -#define ADD_FAILURE_AT(file, line) \ - GTEST_MESSAGE_AT_(file, line, "Failed", \ - ::testing::TestPartResult::kNonFatalFailure) - -// Generates a fatal failure with a generic message. -#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") - -// Define this macro to 1 to omit the definition of FAIL(), which is a -// generic name and clashes with some other libraries. -#if !GTEST_DONT_DEFINE_FAIL -# define FAIL() GTEST_FAIL() -#endif - -// Generates a success with a generic message. -#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") - -// Define this macro to 1 to omit the definition of SUCCEED(), which -// is a generic name and clashes with some other libraries. -#if !GTEST_DONT_DEFINE_SUCCEED -# define SUCCEED() GTEST_SUCCEED() -#endif - -// Macros for testing exceptions. -// -// * {ASSERT|EXPECT}_THROW(statement, expected_exception): -// Tests that the statement throws the expected exception. -// * {ASSERT|EXPECT}_NO_THROW(statement): -// Tests that the statement doesn't throw any exception. -// * {ASSERT|EXPECT}_ANY_THROW(statement): -// Tests that the statement throws an exception. - -#define EXPECT_THROW(statement, expected_exception) \ - GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) -#define EXPECT_NO_THROW(statement) \ - GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) -#define EXPECT_ANY_THROW(statement) \ - GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) -#define ASSERT_THROW(statement, expected_exception) \ - GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) -#define ASSERT_NO_THROW(statement) \ - GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) -#define ASSERT_ANY_THROW(statement) \ - GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) - -// Boolean assertions. Condition can be either a Boolean expression or an -// AssertionResult. For more information on how to use AssertionResult with -// these macros see comments on that class. -#define EXPECT_TRUE(condition) \ - GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ - GTEST_NONFATAL_FAILURE_) -#define EXPECT_FALSE(condition) \ - GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ - GTEST_NONFATAL_FAILURE_) -#define ASSERT_TRUE(condition) \ - GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ - GTEST_FATAL_FAILURE_) -#define ASSERT_FALSE(condition) \ - GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ - GTEST_FATAL_FAILURE_) - -// Includes the auto-generated header that implements a family of -// generic predicate assertion macros. -#include "gtest/gtest_pred_impl.h" - -// Macros for testing equalities and inequalities. -// -// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual -// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 -// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 -// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 -// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 -// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 -// -// When they are not, Google Test prints both the tested expressions and -// their actual values. The values must be compatible built-in types, -// or you will get a compiler error. By "compatible" we mean that the -// values can be compared by the respective operator. -// -// Note: -// -// 1. It is possible to make a user-defined type work with -// {ASSERT|EXPECT}_??(), but that requires overloading the -// comparison operators and is thus discouraged by the Google C++ -// Usage Guide. Therefore, you are advised to use the -// {ASSERT|EXPECT}_TRUE() macro to assert that two objects are -// equal. -// -// 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on -// pointers (in particular, C strings). Therefore, if you use it -// with two C strings, you are testing how their locations in memory -// are related, not how their content is related. To compare two C -// strings by content, use {ASSERT|EXPECT}_STR*(). -// -// 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to -// {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you -// what the actual value is when it fails, and similarly for the -// other comparisons. -// -// 4. Do not depend on the order in which {ASSERT|EXPECT}_??() -// evaluate their arguments, which is undefined. -// -// 5. These macros evaluate their arguments exactly once. -// -// Examples: -// -// EXPECT_NE(5, Foo()); -// EXPECT_EQ(NULL, a_pointer); -// ASSERT_LT(i, array_size); -// ASSERT_GT(records.size(), 0) << "There is no record left."; - -#define EXPECT_EQ(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal:: \ - EqHelper::Compare, \ - expected, actual) -#define EXPECT_NE(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual) -#define EXPECT_LE(val1, val2) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) -#define EXPECT_LT(val1, val2) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) -#define EXPECT_GE(val1, val2) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) -#define EXPECT_GT(val1, val2) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) - -#define GTEST_ASSERT_EQ(expected, actual) \ - ASSERT_PRED_FORMAT2(::testing::internal:: \ - EqHelper::Compare, \ - expected, actual) -#define GTEST_ASSERT_NE(val1, val2) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) -#define GTEST_ASSERT_LE(val1, val2) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) -#define GTEST_ASSERT_LT(val1, val2) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) -#define GTEST_ASSERT_GE(val1, val2) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) -#define GTEST_ASSERT_GT(val1, val2) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) - -// Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of -// ASSERT_XY(), which clashes with some users' own code. - -#if !GTEST_DONT_DEFINE_ASSERT_EQ -# define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2) -#endif - -#if !GTEST_DONT_DEFINE_ASSERT_NE -# define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2) -#endif - -#if !GTEST_DONT_DEFINE_ASSERT_LE -# define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2) -#endif - -#if !GTEST_DONT_DEFINE_ASSERT_LT -# define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2) -#endif - -#if !GTEST_DONT_DEFINE_ASSERT_GE -# define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2) -#endif - -#if !GTEST_DONT_DEFINE_ASSERT_GT -# define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2) -#endif - -// C-string Comparisons. All tests treat NULL and any non-NULL string -// as different. Two NULLs are equal. -// -// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2 -// * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2 -// * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case -// * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case -// -// For wide or narrow string objects, you can use the -// {ASSERT|EXPECT}_??() macros. -// -// Don't depend on the order in which the arguments are evaluated, -// which is undefined. -// -// These macros evaluate their arguments exactly once. - -#define EXPECT_STREQ(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) -#define EXPECT_STRNE(s1, s2) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) -#define EXPECT_STRCASEEQ(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) -#define EXPECT_STRCASENE(s1, s2)\ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) - -#define ASSERT_STREQ(expected, actual) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) -#define ASSERT_STRNE(s1, s2) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) -#define ASSERT_STRCASEEQ(expected, actual) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) -#define ASSERT_STRCASENE(s1, s2)\ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) - -// Macros for comparing floating-point numbers. -// -// * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual): -// Tests that two float values are almost equal. -// * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual): -// Tests that two double values are almost equal. -// * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): -// Tests that v1 and v2 are within the given distance to each other. -// -// Google Test uses ULP-based comparison to automatically pick a default -// error bound that is appropriate for the operands. See the -// FloatingPoint template class in gtest-internal.h if you are -// interested in the implementation details. - -#define EXPECT_FLOAT_EQ(expected, actual)\ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) - -#define EXPECT_DOUBLE_EQ(expected, actual)\ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) - -#define ASSERT_FLOAT_EQ(expected, actual)\ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) - -#define ASSERT_DOUBLE_EQ(expected, actual)\ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) - -#define EXPECT_NEAR(val1, val2, abs_error)\ - EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ - val1, val2, abs_error) - -#define ASSERT_NEAR(val1, val2, abs_error)\ - ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ - val1, val2, abs_error) - -// These predicate format functions work on floating-point values, and -// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g. -// -// EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0); - -// Asserts that val1 is less than, or almost equal to, val2. Fails -// otherwise. In particular, it fails if either val1 or val2 is NaN. -GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2, - float val1, float val2); -GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, - double val1, double val2); - - -#if GTEST_OS_WINDOWS - -// Macros that test for HRESULT failure and success, these are only useful -// on Windows, and rely on Windows SDK macros and APIs to compile. -// -// * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr) -// -// When expr unexpectedly fails or succeeds, Google Test prints the -// expected result and the actual result with both a human-readable -// string representation of the error, if available, as well as the -// hex result code. -# define EXPECT_HRESULT_SUCCEEDED(expr) \ - EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) - -# define ASSERT_HRESULT_SUCCEEDED(expr) \ - ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) - -# define EXPECT_HRESULT_FAILED(expr) \ - EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) - -# define ASSERT_HRESULT_FAILED(expr) \ - ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) - -#endif // GTEST_OS_WINDOWS - -// Macros that execute statement and check that it doesn't generate new fatal -// failures in the current thread. -// -// * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement); -// -// Examples: -// -// EXPECT_NO_FATAL_FAILURE(Process()); -// ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed"; -// -#define ASSERT_NO_FATAL_FAILURE(statement) \ - GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) -#define EXPECT_NO_FATAL_FAILURE(statement) \ - GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) - -// Causes a trace (including the source file path, the current line -// number, and the given message) to be included in every test failure -// message generated by code in the current scope. The effect is -// undone when the control leaves the current scope. -// -// The message argument can be anything streamable to std::ostream. -// -// In the implementation, we include the current line number as part -// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s -// to appear in the same block - as long as they are on different -// lines. -#define SCOPED_TRACE(message) \ - ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ - __FILE__, __LINE__, ::testing::Message() << (message)) - -// Compile-time assertion for type equality. -// StaticAssertTypeEq() compiles iff type1 and type2 are -// the same type. The value it returns is not interesting. -// -// Instead of making StaticAssertTypeEq a class template, we make it a -// function template that invokes a helper class template. This -// prevents a user from misusing StaticAssertTypeEq by -// defining objects of that type. -// -// CAVEAT: -// -// When used inside a method of a class template, -// StaticAssertTypeEq() is effective ONLY IF the method is -// instantiated. For example, given: -// -// template class Foo { -// public: -// void Bar() { testing::StaticAssertTypeEq(); } -// }; -// -// the code: -// -// void Test1() { Foo foo; } -// -// will NOT generate a compiler error, as Foo::Bar() is never -// actually instantiated. Instead, you need: -// -// void Test2() { Foo foo; foo.Bar(); } -// -// to cause a compiler error. -template -bool StaticAssertTypeEq() { - (void)internal::StaticAssertTypeEqHelper(); - return true; -} - -// Defines a test. -// -// The first parameter is the name of the test case, and the second -// parameter is the name of the test within the test case. -// -// The convention is to end the test case name with "Test". For -// example, a test case for the Foo class can be named FooTest. -// -// Test code should appear between braces after an invocation of -// this macro. Example: -// -// TEST(FooTest, InitializesCorrectly) { -// Foo foo; -// EXPECT_TRUE(foo.StatusIsOK()); -// } - -// Note that we call GetTestTypeId() instead of GetTypeId< -// ::testing::Test>() here to get the type ID of testing::Test. This -// is to work around a suspected linker bug when using Google Test as -// a framework on Mac OS X. The bug causes GetTypeId< -// ::testing::Test>() to return different values depending on whether -// the call is from the Google Test framework itself or from user test -// code. GetTestTypeId() is guaranteed to always return the same -// value, as it always calls GetTypeId<>() from the Google Test -// framework. -#define GTEST_TEST(test_case_name, test_name)\ - GTEST_TEST_(test_case_name, test_name, \ - ::testing::Test, ::testing::internal::GetTestTypeId()) - -// Define this macro to 1 to omit the definition of TEST(), which -// is a generic name and clashes with some other libraries. -#if !GTEST_DONT_DEFINE_TEST -# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) -#endif - -// Defines a test that uses a test fixture. -// -// The first parameter is the name of the test fixture class, which -// also doubles as the test case name. The second parameter is the -// name of the test within the test case. -// -// A test fixture class must be declared earlier. The user should put -// his test code between braces after using this macro. Example: -// -// class FooTest : public testing::Test { -// protected: -// virtual void SetUp() { b_.AddElement(3); } -// -// Foo a_; -// Foo b_; -// }; -// -// TEST_F(FooTest, InitializesCorrectly) { -// EXPECT_TRUE(a_.StatusIsOK()); -// } -// -// TEST_F(FooTest, ReturnsElementCountCorrectly) { -// EXPECT_EQ(0, a_.size()); -// EXPECT_EQ(1, b_.size()); -// } - -#define TEST_F(test_fixture, test_name)\ - GTEST_TEST_(test_fixture, test_name, test_fixture, \ - ::testing::internal::GetTypeId()) - -} // namespace testing - -// Use this function in main() to run all tests. It returns 0 if all -// tests are successful, or 1 otherwise. -// -// RUN_ALL_TESTS() should be invoked after the command line has been -// parsed by InitGoogleTest(). -// -// This function was formerly a macro; thus, it is in the global -// namespace and has an all-caps name. -int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_; - -inline int RUN_ALL_TESTS() { - return ::testing::UnitTest::GetInstance()->Run(); -} - -#endif // GTEST_INCLUDE_GTEST_GTEST_H_ \ No newline at end of file diff --git a/src/gtest/include/gtest/gtest_pred_impl.h b/src/gtest/include/gtest/gtest_pred_impl.h deleted file mode 100644 index eceb4a95..00000000 --- a/src/gtest/include/gtest/gtest_pred_impl.h +++ /dev/null @@ -1,371 +0,0 @@ -// Copyright 2006 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. - -// This file is AUTOMATICALLY GENERATED on 10/31/2011 by command -// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! -// -// Implements a family of generic predicate assertion macros. - -#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ - -// Makes sure this header is not included before gtest.h. -#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ -# error Do not include gtest_pred_impl.h directly. Include gtest.h instead. -#endif // GTEST_INCLUDE_GTEST_GTEST_H_ - -// This header implements a family of generic predicate assertion -// macros: -// -// ASSERT_PRED_FORMAT1(pred_format, v1) -// ASSERT_PRED_FORMAT2(pred_format, v1, v2) -// ... -// -// where pred_format is a function or functor that takes n (in the -// case of ASSERT_PRED_FORMATn) values and their source expression -// text, and returns a testing::AssertionResult. See the definition -// of ASSERT_EQ in gtest.h for an example. -// -// If you don't care about formatting, you can use the more -// restrictive version: -// -// ASSERT_PRED1(pred, v1) -// ASSERT_PRED2(pred, v1, v2) -// ... -// -// where pred is an n-ary function or functor that returns bool, -// and the values v1, v2, ..., must support the << operator for -// streaming to std::ostream. -// -// We also define the EXPECT_* variations. -// -// For now we only support predicates whose arity is at most 5. -// Please email googletestframework@googlegroups.com if you need -// support for higher arities. - -// GTEST_ASSERT_ is the basic statement to which all of the assertions -// in this file reduce. Don't use this in your code. - -#define GTEST_ASSERT_(expression, on_failure) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (const ::testing::AssertionResult gtest_ar = (expression)) \ - ; \ - else \ - on_failure(gtest_ar.failure_message()) - - -// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use -// this in your code. -template -AssertionResult AssertPred1Helper(const char* pred_text, - const char* e1, - Pred pred, - const T1& v1) { - if (pred(v1)) return AssertionSuccess(); - - return AssertionFailure() << pred_text << "(" - << e1 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1; -} - -// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. -// Don't use this in your code. -#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, v1), \ - on_failure) - -// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use -// this in your code. -#define GTEST_PRED1_(pred, v1, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \ - #v1, \ - pred, \ - v1), on_failure) - -// Unary predicate assertion macros. -#define EXPECT_PRED_FORMAT1(pred_format, v1) \ - GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED1(pred, v1) \ - GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) -#define ASSERT_PRED_FORMAT1(pred_format, v1) \ - GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED1(pred, v1) \ - GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) - - - -// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use -// this in your code. -template -AssertionResult AssertPred2Helper(const char* pred_text, - const char* e1, - const char* e2, - Pred pred, - const T1& v1, - const T2& v2) { - if (pred(v1, v2)) return AssertionSuccess(); - - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2; -} - -// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. -// Don't use this in your code. -#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \ - on_failure) - -// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use -// this in your code. -#define GTEST_PRED2_(pred, v1, v2, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \ - #v1, \ - #v2, \ - pred, \ - v1, \ - v2), on_failure) - -// Binary predicate assertion macros. -#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ - GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED2(pred, v1, v2) \ - GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_) -#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \ - GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED2(pred, v1, v2) \ - GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) - - - -// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use -// this in your code. -template -AssertionResult AssertPred3Helper(const char* pred_text, - const char* e1, - const char* e2, - const char* e3, - Pred pred, - const T1& v1, - const T2& v2, - const T3& v3) { - if (pred(v1, v2, v3)) return AssertionSuccess(); - - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3; -} - -// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. -// Don't use this in your code. -#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \ - on_failure) - -// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use -// this in your code. -#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \ - #v1, \ - #v2, \ - #v3, \ - pred, \ - v1, \ - v2, \ - v3), on_failure) - -// Ternary predicate assertion macros. -#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ - GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED3(pred, v1, v2, v3) \ - GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_) -#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \ - GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED3(pred, v1, v2, v3) \ - GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) - - - -// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use -// this in your code. -template -AssertionResult AssertPred4Helper(const char* pred_text, - const char* e1, - const char* e2, - const char* e3, - const char* e4, - Pred pred, - const T1& v1, - const T2& v2, - const T3& v3, - const T4& v4) { - if (pred(v1, v2, v3, v4)) return AssertionSuccess(); - - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ", " - << e4 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3 - << "\n" << e4 << " evaluates to " << v4; -} - -// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. -// Don't use this in your code. -#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \ - on_failure) - -// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use -// this in your code. -#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \ - #v1, \ - #v2, \ - #v3, \ - #v4, \ - pred, \ - v1, \ - v2, \ - v3, \ - v4), on_failure) - -// 4-ary predicate assertion macros. -#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ - GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED4(pred, v1, v2, v3, v4) \ - GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) -#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ - GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED4(pred, v1, v2, v3, v4) \ - GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) - - - -// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use -// this in your code. -template -AssertionResult AssertPred5Helper(const char* pred_text, - const char* e1, - const char* e2, - const char* e3, - const char* e4, - const char* e5, - Pred pred, - const T1& v1, - const T2& v2, - const T3& v3, - const T4& v4, - const T5& v5) { - if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); - - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ", " - << e4 << ", " - << e5 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3 - << "\n" << e4 << " evaluates to " << v4 - << "\n" << e5 << " evaluates to " << v5; -} - -// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. -// Don't use this in your code. -#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \ - on_failure) - -// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use -// this in your code. -#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \ - #v1, \ - #v2, \ - #v3, \ - #v4, \ - #v5, \ - pred, \ - v1, \ - v2, \ - v3, \ - v4, \ - v5), on_failure) - -// 5-ary predicate assertion macros. -#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ - GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \ - GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) -#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ - GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ - GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) - - - -#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ \ No newline at end of file diff --git a/src/gtest/include/gtest/gtest_prod.h b/src/gtest/include/gtest/gtest_prod.h deleted file mode 100644 index 390f4de2..00000000 --- a/src/gtest/include/gtest/gtest_prod.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2006 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// -// -// Google C++ Testing Framework definitions useful in production code. - -#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ - -// When you need to test the private or protected members of a class, -// use the FRIEND_TEST macro to declare your tests as friends of the -// class. For example: -// -// class MyClass { -// private: -// void MyMethod(); -// FRIEND_TEST(MyClassTest, MyMethod); -// }; -// -// class MyClassTest : public testing::Test { -// // ... -// }; -// -// TEST_F(MyClassTest, MyMethod) { -// // Can call MyClass::MyMethod() here. -// } - -#define FRIEND_TEST(test_case_name, test_name)\ -friend class test_case_name##_##test_name##_Test - -#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ \ No newline at end of file diff --git a/src/gtest/include/gtest/internal/gtest-death-test-internal.h b/src/gtest/include/gtest/internal/gtest-death-test-internal.h deleted file mode 100644 index a0571ed7..00000000 --- a/src/gtest/include/gtest/internal/gtest-death-test-internal.h +++ /dev/null @@ -1,331 +0,0 @@ -// Copyright 2005 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// -// -// The Google C++ Testing Framework (Google Test) -// -// This header file defines internal utilities needed for implementing -// death tests. They are subject to change without notice. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ - -#include "gtest/internal/gtest-internal.h" - -#include - -namespace testing { -namespace internal { - -GTEST_DECLARE_string_(internal_run_death_test); - -// Names of the flags (needed for parsing Google Test flags). -const char kDeathTestStyleFlag[] = "death_test_style"; -const char kDeathTestUseFork[] = "death_test_use_fork"; -const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; - -#if GTEST_HAS_DEATH_TEST - -// DeathTest is a class that hides much of the complexity of the -// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method -// returns a concrete class that depends on the prevailing death test -// style, as defined by the --gtest_death_test_style and/or -// --gtest_internal_run_death_test flags. - -// In describing the results of death tests, these terms are used with -// the corresponding definitions: -// -// exit status: The integer exit information in the format specified -// by wait(2) -// exit code: The integer code passed to exit(3), _exit(2), or -// returned from main() -class GTEST_API_ DeathTest { - public: - // Create returns false if there was an error determining the - // appropriate action to take for the current death test; for example, - // if the gtest_death_test_style flag is set to an invalid value. - // The LastMessage method will return a more detailed message in that - // case. Otherwise, the DeathTest pointer pointed to by the "test" - // argument is set. If the death test should be skipped, the pointer - // is set to NULL; otherwise, it is set to the address of a new concrete - // DeathTest object that controls the execution of the current test. - static bool Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test); - DeathTest(); - virtual ~DeathTest() { } - - // A helper class that aborts a death test when it's deleted. - class ReturnSentinel { - public: - explicit ReturnSentinel(DeathTest* test) : test_(test) { } - ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); } - private: - DeathTest* const test_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel); - } GTEST_ATTRIBUTE_UNUSED_; - - // An enumeration of possible roles that may be taken when a death - // test is encountered. EXECUTE means that the death test logic should - // be executed immediately. OVERSEE means that the program should prepare - // the appropriate environment for a child process to execute the death - // test, then wait for it to complete. - enum TestRole { OVERSEE_TEST, EXECUTE_TEST }; - - // An enumeration of the three reasons that a test might be aborted. - enum AbortReason { - TEST_ENCOUNTERED_RETURN_STATEMENT, - TEST_THREW_EXCEPTION, - TEST_DID_NOT_DIE - }; - - // Assumes one of the above roles. - virtual TestRole AssumeRole() = 0; - - // Waits for the death test to finish and returns its status. - virtual int Wait() = 0; - - // Returns true if the death test passed; that is, the test process - // exited during the test, its exit status matches a user-supplied - // predicate, and its stderr output matches a user-supplied regular - // expression. - // The user-supplied predicate may be a macro expression rather - // than a function pointer or functor, or else Wait and Passed could - // be combined. - virtual bool Passed(bool exit_status_ok) = 0; - - // Signals that the death test did not die as expected. - virtual void Abort(AbortReason reason) = 0; - - // Returns a human-readable outcome message regarding the outcome of - // the last death test. - static const char* LastMessage(); - - static void set_last_death_test_message(const std::string& message); - - private: - // A string containing a description of the outcome of the last death test. - static std::string last_death_test_message_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); -}; - -// Factory interface for death tests. May be mocked out for testing. -class DeathTestFactory { - public: - virtual ~DeathTestFactory() { } - virtual bool Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test) = 0; -}; - -// A concrete DeathTestFactory implementation for normal use. -class DefaultDeathTestFactory : public DeathTestFactory { - public: - virtual bool Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test); -}; - -// Returns true if exit_status describes a process that was terminated -// by a signal, or exited normally with a nonzero exit code. -GTEST_API_ bool ExitedUnsuccessfully(int exit_status); - -// Traps C++ exceptions escaping statement and reports them as test -// failures. Note that trapping SEH exceptions is not implemented here. -# if GTEST_HAS_EXCEPTIONS -# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ - try { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } catch (const ::std::exception& gtest_exception) { \ - fprintf(\ - stderr, \ - "\n%s: Caught std::exception-derived exception escaping the " \ - "death test statement. Exception message: %s\n", \ - ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \ - gtest_exception.what()); \ - fflush(stderr); \ - death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ - } catch (...) { \ - death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ - } - -# else -# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) - -# endif - -// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, -// ASSERT_EXIT*, and EXPECT_EXIT*. -# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - const ::testing::internal::RE& gtest_regex = (regex); \ - ::testing::internal::DeathTest* gtest_dt; \ - if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \ - __FILE__, __LINE__, >est_dt)) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ - } \ - if (gtest_dt != NULL) { \ - ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \ - gtest_dt_ptr(gtest_dt); \ - switch (gtest_dt->AssumeRole()) { \ - case ::testing::internal::DeathTest::OVERSEE_TEST: \ - if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ - } \ - break; \ - case ::testing::internal::DeathTest::EXECUTE_TEST: { \ - ::testing::internal::DeathTest::ReturnSentinel \ - gtest_sentinel(gtest_dt); \ - GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ - gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ - break; \ - } \ - default: \ - break; \ - } \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \ - fail(::testing::internal::DeathTest::LastMessage()) -// The symbol "fail" here expands to something into which a message -// can be streamed. - -// This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in -// NDEBUG mode. In this case we need the statements to be executed, the regex is -// ignored, and the macro must accept a streamed message even though the message -// is never printed. -# define GTEST_EXECUTE_STATEMENT_(statement, regex) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } else \ - ::testing::Message() - -// A class representing the parsed contents of the -// --gtest_internal_run_death_test flag, as it existed when -// RUN_ALL_TESTS was called. -class InternalRunDeathTestFlag { - public: - InternalRunDeathTestFlag(const std::string& a_file, - int a_line, - int an_index, - int a_write_fd) - : file_(a_file), line_(a_line), index_(an_index), - write_fd_(a_write_fd) {} - - ~InternalRunDeathTestFlag() { - if (write_fd_ >= 0) - posix::Close(write_fd_); - } - - const std::string& file() const { return file_; } - int line() const { return line_; } - int index() const { return index_; } - int write_fd() const { return write_fd_; } - - private: - std::string file_; - int line_; - int index_; - int write_fd_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag); -}; - -// Returns a newly created InternalRunDeathTestFlag object with fields -// initialized from the GTEST_FLAG(internal_run_death_test) flag if -// the flag is specified; otherwise returns NULL. -InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); - -#else // GTEST_HAS_DEATH_TEST - -// This macro is used for implementing macros such as -// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where -// death tests are not supported. Those macros must compile on such systems -// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on -// systems that support death tests. This allows one to write such a macro -// on a system that does not support death tests and be sure that it will -// compile on a death-test supporting system. -// -// Parameters: -// statement - A statement that a macro such as EXPECT_DEATH would test -// for program termination. This macro has to make sure this -// statement is compiled but not executed, to ensure that -// EXPECT_DEATH_IF_SUPPORTED compiles with a certain -// parameter iff EXPECT_DEATH compiles with it. -// regex - A regex that a macro such as EXPECT_DEATH would use to test -// the output of statement. This parameter has to be -// compiled but not evaluated by this macro, to ensure that -// this macro only accepts expressions that a macro such as -// EXPECT_DEATH would accept. -// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED -// and a return statement for ASSERT_DEATH_IF_SUPPORTED. -// This ensures that ASSERT_DEATH_IF_SUPPORTED will not -// compile inside functions where ASSERT_DEATH doesn't -// compile. -// -// The branch that has an always false condition is used to ensure that -// statement and regex are compiled (and thus syntactically correct) but -// never executed. The unreachable code macro protects the terminator -// statement from generating an 'unreachable code' warning in case -// statement unconditionally returns or throws. The Message constructor at -// the end allows the syntax of streaming additional messages into the -// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. -# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - GTEST_LOG_(WARNING) \ - << "Death tests are not supported on this platform.\n" \ - << "Statement '" #statement "' cannot be verified."; \ - } else if (::testing::internal::AlwaysFalse()) { \ - ::testing::internal::RE::PartialMatch(".*", (regex)); \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - terminator; \ - } else \ - ::testing::Message() - -#endif // GTEST_HAS_DEATH_TEST - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ \ No newline at end of file diff --git a/src/gtest/include/gtest/internal/gtest-filepath.h b/src/gtest/include/gtest/internal/gtest-filepath.h deleted file mode 100644 index 8407aa12..00000000 --- a/src/gtest/include/gtest/internal/gtest-filepath.h +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright 2008 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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: keith.ray@gmail.com (Keith Ray) -// -// Google Test filepath utilities -// -// This header file declares classes and functions used internally by -// Google Test. They are subject to change without notice. -// -// This file is #included in . -// Do not include this header file separately! - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ - -#include "gtest/internal/gtest-string.h" - -namespace testing { -namespace internal { - -// FilePath - a class for file and directory pathname manipulation which -// handles platform-specific conventions (like the pathname separator). -// Used for helper functions for naming files in a directory for xml output. -// Except for Set methods, all methods are const or static, which provides an -// "immutable value object" -- useful for peace of mind. -// A FilePath with a value ending in a path separator ("like/this/") represents -// a directory, otherwise it is assumed to represent a file. In either case, -// it may or may not represent an actual file or directory in the file system. -// Names are NOT checked for syntax correctness -- no checking for illegal -// characters, malformed paths, etc. - -class GTEST_API_ FilePath { - public: - FilePath() : pathname_("") { } - FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } - - explicit FilePath(const std::string& pathname) : pathname_(pathname) { - Normalize(); - } - - FilePath& operator=(const FilePath& rhs) { - Set(rhs); - return *this; - } - - void Set(const FilePath& rhs) { - pathname_ = rhs.pathname_; - } - - const std::string& string() const { return pathname_; } - const char* c_str() const { return pathname_.c_str(); } - - // Returns the current working directory, or "" if unsuccessful. - static FilePath GetCurrentDir(); - - // Given directory = "dir", base_name = "test", number = 0, - // extension = "xml", returns "dir/test.xml". If number is greater - // than zero (e.g., 12), returns "dir/test_12.xml". - // On Windows platform, uses \ as the separator rather than /. - static FilePath MakeFileName(const FilePath& directory, - const FilePath& base_name, - int number, - const char* extension); - - // Given directory = "dir", relative_path = "test.xml", - // returns "dir/test.xml". - // On Windows, uses \ as the separator rather than /. - static FilePath ConcatPaths(const FilePath& directory, - const FilePath& relative_path); - - // Returns a pathname for a file that does not currently exist. The pathname - // will be directory/base_name.extension or - // directory/base_name_.extension if directory/base_name.extension - // already exists. The number will be incremented until a pathname is found - // that does not already exist. - // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. - // There could be a race condition if two or more processes are calling this - // function at the same time -- they could both pick the same filename. - static FilePath GenerateUniqueFileName(const FilePath& directory, - const FilePath& base_name, - const char* extension); - - // Returns true iff the path is "". - bool IsEmpty() const { return pathname_.empty(); } - - // If input name has a trailing separator character, removes it and returns - // the name, otherwise return the name string unmodified. - // On Windows platform, uses \ as the separator, other platforms use /. - FilePath RemoveTrailingPathSeparator() const; - - // Returns a copy of the FilePath with the directory part removed. - // Example: FilePath("path/to/file").RemoveDirectoryName() returns - // FilePath("file"). If there is no directory part ("just_a_file"), it returns - // the FilePath unmodified. If there is no file part ("just_a_dir/") it - // returns an empty FilePath (""). - // On Windows platform, '\' is the path separator, otherwise it is '/'. - FilePath RemoveDirectoryName() const; - - // RemoveFileName returns the directory path with the filename removed. - // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". - // If the FilePath is "a_file" or "/a_file", RemoveFileName returns - // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does - // not have a file, like "just/a/dir/", it returns the FilePath unmodified. - // On Windows platform, '\' is the path separator, otherwise it is '/'. - FilePath RemoveFileName() const; - - // Returns a copy of the FilePath with the case-insensitive extension removed. - // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns - // FilePath("dir/file"). If a case-insensitive extension is not - // found, returns a copy of the original FilePath. - FilePath RemoveExtension(const char* extension) const; - - // Creates directories so that path exists. Returns true if successful or if - // the directories already exist; returns false if unable to create - // directories for any reason. Will also return false if the FilePath does - // not represent a directory (that is, it doesn't end with a path separator). - bool CreateDirectoriesRecursively() const; - - // Create the directory so that path exists. Returns true if successful or - // if the directory already exists; returns false if unable to create the - // directory for any reason, including if the parent directory does not - // exist. Not named "CreateDirectory" because that's a macro on Windows. - bool CreateFolder() const; - - // Returns true if FilePath describes something in the file-system, - // either a file, directory, or whatever, and that something exists. - bool FileOrDirectoryExists() const; - - // Returns true if pathname describes a directory in the file-system - // that exists. - bool DirectoryExists() const; - - // Returns true if FilePath ends with a path separator, which indicates that - // it is intended to represent a directory. Returns false otherwise. - // This does NOT check that a directory (or file) actually exists. - bool IsDirectory() const; - - // Returns true if pathname describes a root directory. (Windows has one - // root directory per disk drive.) - bool IsRootDirectory() const; - - // Returns true if pathname describes an absolute path. - bool IsAbsolutePath() const; - - private: - // Replaces multiple consecutive separators with a single separator. - // For example, "bar///foo" becomes "bar/foo". Does not eliminate other - // redundancies that might be in a pathname involving "." or "..". - // - // A pathname with multiple consecutive separators may occur either through - // user error or as a result of some scripts or APIs that generate a pathname - // with a trailing separator. On other platforms the same API or script - // may NOT generate a pathname with a trailing "/". Then elsewhere that - // pathname may have another "/" and pathname components added to it, - // without checking for the separator already being there. - // The script language and operating system may allow paths like "foo//bar" - // but some of the functions in FilePath will not handle that correctly. In - // particular, RemoveTrailingPathSeparator() only removes one separator, and - // it is called in CreateDirectoriesRecursively() assuming that it will change - // a pathname from directory syntax (trailing separator) to filename syntax. - // - // On Windows this method also replaces the alternate path separator '/' with - // the primary path separator '\\', so that for example "bar\\/\\foo" becomes - // "bar\\foo". - - void Normalize(); - - // Returns a pointer to the last occurence of a valid path separator in - // the FilePath. On Windows, for example, both '/' and '\' are valid path - // separators. Returns NULL if no path separator was found. - const char* FindLastPathSeparator() const; - - std::string pathname_; -}; // class FilePath - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ \ No newline at end of file diff --git a/src/gtest/include/gtest/internal/gtest-internal.h b/src/gtest/include/gtest/internal/gtest-internal.h deleted file mode 100644 index 5119d0bb..00000000 --- a/src/gtest/include/gtest/internal/gtest-internal.h +++ /dev/null @@ -1,1204 +0,0 @@ -// Copyright 2005 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// -// -// The Google C++ Testing Framework (Google Test) -// -// This header file declares functions and macros used internally by -// Google Test. They are subject to change without notice. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ - -#include "gtest/internal/gtest-port.h" - -#if GTEST_OS_LINUX -# include -# include -# include -# include -#endif // GTEST_OS_LINUX - -#if GTEST_HAS_EXCEPTIONS -# include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gtest/gtest-message.h" -#include "gtest/internal/gtest-string.h" -#include "gtest/internal/gtest-filepath.h" -#include "gtest/internal/gtest-type-util.h" - -// Due to C++ preprocessor weirdness, we need double indirection to -// concatenate two tokens when one of them is __LINE__. Writing -// -// foo ## __LINE__ -// -// will result in the token foo__LINE__, instead of foo followed by -// the current line number. For more details, see -// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 -#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) -#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar - -class ProtocolMessage; -namespace proto2 { class Message; } - -namespace testing { - -// Forward declarations. - -class AssertionResult; // Result of an assertion. -class Message; // Represents a failure message. -class Test; // Represents a test. -class TestInfo; // Information about a test. -class TestPartResult; // Result of a test part. -class UnitTest; // A collection of test cases. - -template -::std::string PrintToString(const T& value); - -namespace internal { - -struct TraceInfo; // Information about a trace point. -class ScopedTrace; // Implements scoped trace. -class TestInfoImpl; // Opaque implementation of TestInfo -class UnitTestImpl; // Opaque implementation of UnitTest - -// How many times InitGoogleTest() has been called. -GTEST_API_ extern int g_init_gtest_count; - -// The text used in failure messages to indicate the start of the -// stack trace. -GTEST_API_ extern const char kStackTraceMarker[]; - -// Two overloaded helpers for checking at compile time whether an -// expression is a null pointer literal (i.e. NULL or any 0-valued -// compile-time integral constant). Their return values have -// different sizes, so we can use sizeof() to test which version is -// picked by the compiler. These helpers have no implementations, as -// we only need their signatures. -// -// Given IsNullLiteralHelper(x), the compiler will pick the first -// version if x can be implicitly converted to Secret*, and pick the -// second version otherwise. Since Secret is a secret and incomplete -// type, the only expression a user can write that has type Secret* is -// a null pointer literal. Therefore, we know that x is a null -// pointer literal if and only if the first version is picked by the -// compiler. -char IsNullLiteralHelper(Secret* p); -char (&IsNullLiteralHelper(...))[2]; // NOLINT - -// A compile-time bool constant that is true if and only if x is a -// null pointer literal (i.e. NULL or any 0-valued compile-time -// integral constant). -#ifdef GTEST_ELLIPSIS_NEEDS_POD_ -// We lose support for NULL detection where the compiler doesn't like -// passing non-POD classes through ellipsis (...). -# define GTEST_IS_NULL_LITERAL_(x) false -#else -# define GTEST_IS_NULL_LITERAL_(x) \ - (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1) -#endif // GTEST_ELLIPSIS_NEEDS_POD_ - -// Appends the user-supplied message to the Google-Test-generated message. -GTEST_API_ std::string AppendUserMessage( - const std::string& gtest_msg, const Message& user_msg); - -#if GTEST_HAS_EXCEPTIONS - -// This exception is thrown by (and only by) a failed Google Test -// assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions -// are enabled). We derive it from std::runtime_error, which is for -// errors presumably detectable only at run time. Since -// std::runtime_error inherits from std::exception, many testing -// frameworks know how to extract and print the message inside it. -class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error { - public: - explicit GoogleTestFailureException(const TestPartResult& failure); -}; - -#endif // GTEST_HAS_EXCEPTIONS - -// A helper class for creating scoped traces in user programs. -class GTEST_API_ ScopedTrace { - public: - // The c'tor pushes the given source file location and message onto - // a trace stack maintained by Google Test. - ScopedTrace(const char* file, int line, const Message& message); - - // The d'tor pops the info pushed by the c'tor. - // - // Note that the d'tor is not virtual in order to be efficient. - // Don't inherit from ScopedTrace! - ~ScopedTrace(); - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); -} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its - // c'tor and d'tor. Therefore it doesn't - // need to be used otherwise. - -namespace edit_distance { -// Returns the optimal edits to go from 'left' to 'right'. -// All edits cost the same, with replace having lower priority than -// add/remove. -// Simple implementation of the Wagner–Fischer algorithm. -// See http://en.wikipedia.org/wiki/Wagner-Fischer_algorithm -enum EditType { kMatch, kAdd, kRemove, kReplace }; -GTEST_API_ std::vector CalculateOptimalEdits( - const std::vector& left, const std::vector& right); - -// Same as above, but the input is represented as strings. -GTEST_API_ std::vector CalculateOptimalEdits( - const std::vector& left, - const std::vector& right); - -// Create a diff of the input strings in Unified diff format. -GTEST_API_ std::string CreateUnifiedDiff(const std::vector& left, - const std::vector& right, - size_t context = 2); - -} // namespace edit_distance - -// Calculate the diff between 'left' and 'right' and return it in unified diff -// format. -// If not null, stores in 'total_line_count' the total number of lines found -// in left + right. -GTEST_API_ std::string DiffStrings(const std::string& left, - const std::string& right, - size_t* total_line_count); - -// Constructs and returns the message for an equality assertion -// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. -// -// The first four parameters are the expressions used in the assertion -// and their values, as strings. For example, for ASSERT_EQ(foo, bar) -// where foo is 5 and bar is 6, we have: -// -// expected_expression: "foo" -// actual_expression: "bar" -// expected_value: "5" -// actual_value: "6" -// -// The ignoring_case parameter is true iff the assertion is a -// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will -// be inserted into the message. -GTEST_API_ AssertionResult EqFailure(const char* expected_expression, - const char* actual_expression, - const std::string& expected_value, - const std::string& actual_value, - bool ignoring_case); - -// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. -GTEST_API_ std::string GetBoolAssertionFailureMessage( - const AssertionResult& assertion_result, - const char* expression_text, - const char* actual_predicate_value, - const char* expected_predicate_value); - -// This template class represents an IEEE floating-point number -// (either single-precision or double-precision, depending on the -// template parameters). -// -// The purpose of this class is to do more sophisticated number -// comparison. (Due to round-off error, etc, it's very unlikely that -// two floating-points will be equal exactly. Hence a naive -// comparison by the == operation often doesn't work.) -// -// Format of IEEE floating-point: -// -// The most-significant bit being the leftmost, an IEEE -// floating-point looks like -// -// sign_bit exponent_bits fraction_bits -// -// Here, sign_bit is a single bit that designates the sign of the -// number. -// -// For float, there are 8 exponent bits and 23 fraction bits. -// -// For double, there are 11 exponent bits and 52 fraction bits. -// -// More details can be found at -// http://en.wikipedia.org/wiki/IEEE_floating-point_standard. -// -// Template parameter: -// -// RawType: the raw floating-point type (either float or double) -template -class FloatingPoint { - public: - // Defines the unsigned integer type that has the same size as the - // floating point number. - typedef typename TypeWithSize::UInt Bits; - - // Constants. - - // # of bits in a number. - static const size_t kBitCount = 8*sizeof(RawType); - - // # of fraction bits in a number. - static const size_t kFractionBitCount = - std::numeric_limits::digits - 1; - - // # of exponent bits in a number. - static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount; - - // The mask for the sign bit. - static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); - - // The mask for the fraction bits. - static const Bits kFractionBitMask = - ~static_cast(0) >> (kExponentBitCount + 1); - - // The mask for the exponent bits. - static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); - - // How many ULP's (Units in the Last Place) we want to tolerate when - // comparing two numbers. The larger the value, the more error we - // allow. A 0 value means that two numbers must be exactly the same - // to be considered equal. - // - // The maximum error of a single floating-point operation is 0.5 - // units in the last place. On Intel CPU's, all floating-point - // calculations are done with 80-bit precision, while double has 64 - // bits. Therefore, 4 should be enough for ordinary use. - // - // See the following article for more details on ULP: - // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ - static const size_t kMaxUlps = 4; - - // Constructs a FloatingPoint from a raw floating-point number. - // - // On an Intel CPU, passing a non-normalized NAN (Not a Number) - // around may change its bits, although the new value is guaranteed - // to be also a NAN. Therefore, don't expect this constructor to - // preserve the bits in x when x is a NAN. - explicit FloatingPoint(const RawType& x) { u_.value_ = x; } - - // Static methods - - // Reinterprets a bit pattern as a floating-point number. - // - // This function is needed to test the AlmostEquals() method. - static RawType ReinterpretBits(const Bits bits) { - FloatingPoint fp(0); - fp.u_.bits_ = bits; - return fp.u_.value_; - } - - // Returns the floating-point number that represent positive infinity. - static RawType Infinity() { - return ReinterpretBits(kExponentBitMask); - } - - // Returns the maximum representable finite floating-point number. - static RawType Max(); - - // Non-static methods - - // Returns the bits that represents this number. - const Bits &bits() const { return u_.bits_; } - - // Returns the exponent bits of this number. - Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } - - // Returns the fraction bits of this number. - Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } - - // Returns the sign bit of this number. - Bits sign_bit() const { return kSignBitMask & u_.bits_; } - - // Returns true iff this is NAN (not a number). - bool is_nan() const { - // It's a NAN if the exponent bits are all ones and the fraction - // bits are not entirely zeros. - return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); - } - - // Returns true iff this number is at most kMaxUlps ULP's away from - // rhs. In particular, this function: - // - // - returns false if either number is (or both are) NAN. - // - treats really large numbers as almost equal to infinity. - // - thinks +0.0 and -0.0 are 0 DLP's apart. - bool AlmostEquals(const FloatingPoint& rhs) const { - // The IEEE standard says that any comparison operation involving - // a NAN must return false. - if (is_nan() || rhs.is_nan()) return false; - - return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) - <= kMaxUlps; - } - - private: - // The data type used to store the actual floating-point number. - union FloatingPointUnion { - RawType value_; // The raw floating-point number. - Bits bits_; // The bits that represent the number. - }; - - // Converts an integer from the sign-and-magnitude representation to - // the biased representation. More precisely, let N be 2 to the - // power of (kBitCount - 1), an integer x is represented by the - // unsigned number x + N. - // - // For instance, - // - // -N + 1 (the most negative number representable using - // sign-and-magnitude) is represented by 1; - // 0 is represented by N; and - // N - 1 (the biggest number representable using - // sign-and-magnitude) is represented by 2N - 1. - // - // Read http://en.wikipedia.org/wiki/Signed_number_representations - // for more details on signed number representations. - static Bits SignAndMagnitudeToBiased(const Bits &sam) { - if (kSignBitMask & sam) { - // sam represents a negative number. - return ~sam + 1; - } else { - // sam represents a positive number. - return kSignBitMask | sam; - } - } - - // Given two numbers in the sign-and-magnitude representation, - // returns the distance between them as an unsigned number. - static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1, - const Bits &sam2) { - const Bits biased1 = SignAndMagnitudeToBiased(sam1); - const Bits biased2 = SignAndMagnitudeToBiased(sam2); - return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); - } - - FloatingPointUnion u_; -}; - -// We cannot use std::numeric_limits::max() as it clashes with the max() -// macro defined by . -template <> -inline float FloatingPoint::Max() { return FLT_MAX; } -template <> -inline double FloatingPoint::Max() { return DBL_MAX; } - -// Typedefs the instances of the FloatingPoint template class that we -// care to use. -typedef FloatingPoint Float; -typedef FloatingPoint Double; - -// In order to catch the mistake of putting tests that use different -// test fixture classes in the same test case, we need to assign -// unique IDs to fixture classes and compare them. The TypeId type is -// used to hold such IDs. The user should treat TypeId as an opaque -// type: the only operation allowed on TypeId values is to compare -// them for equality using the == operator. -typedef const void* TypeId; - -template -class TypeIdHelper { - public: - // dummy_ must not have a const type. Otherwise an overly eager - // compiler (e.g. MSVC 7.1 & 8.0) may try to merge - // TypeIdHelper::dummy_ for different Ts as an "optimization". - static bool dummy_; -}; - -template -bool TypeIdHelper::dummy_ = false; - -// GetTypeId() returns the ID of type T. Different values will be -// returned for different types. Calling the function twice with the -// same type argument is guaranteed to return the same ID. -template -TypeId GetTypeId() { - // The compiler is required to allocate a different - // TypeIdHelper::dummy_ variable for each T used to instantiate - // the template. Therefore, the address of dummy_ is guaranteed to - // be unique. - return &(TypeIdHelper::dummy_); -} - -// Returns the type ID of ::testing::Test. Always call this instead -// of GetTypeId< ::testing::Test>() to get the type ID of -// ::testing::Test, as the latter may give the wrong result due to a -// suspected linker bug when compiling Google Test as a Mac OS X -// framework. -GTEST_API_ TypeId GetTestTypeId(); - -// Defines the abstract factory interface that creates instances -// of a Test object. -class TestFactoryBase { - public: - virtual ~TestFactoryBase() {} - - // Creates a test instance to run. The instance is both created and destroyed - // within TestInfoImpl::Run() - virtual Test* CreateTest() = 0; - - protected: - TestFactoryBase() {} - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase); -}; - -// This class provides implementation of TeastFactoryBase interface. -// It is used in TEST and TEST_F macros. -template -class TestFactoryImpl : public TestFactoryBase { - public: - virtual Test* CreateTest() { return new TestClass; } -}; - -#if GTEST_OS_WINDOWS - -// Predicate-formatters for implementing the HRESULT checking macros -// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED} -// We pass a long instead of HRESULT to avoid causing an -// include dependency for the HRESULT type. -GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr, - long hr); // NOLINT -GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, - long hr); // NOLINT - -#endif // GTEST_OS_WINDOWS - -// Types of SetUpTestCase() and TearDownTestCase() functions. -typedef void (*SetUpTestCaseFunc)(); -typedef void (*TearDownTestCaseFunc)(); - -// Creates a new TestInfo object and registers it with Google Test; -// returns the created object. -// -// Arguments: -// -// test_case_name: name of the test case -// name: name of the test -// type_param the name of the test's type parameter, or NULL if -// this is not a typed or a type-parameterized test. -// value_param text representation of the test's value parameter, -// or NULL if this is not a type-parameterized test. -// fixture_class_id: ID of the test fixture class -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -// factory: pointer to the factory that creates a test object. -// The newly created TestInfo instance will assume -// ownership of the factory object. -GTEST_API_ TestInfo* MakeAndRegisterTestInfo( - const char* test_case_name, - const char* name, - const char* type_param, - const char* value_param, - TypeId fixture_class_id, - SetUpTestCaseFunc set_up_tc, - TearDownTestCaseFunc tear_down_tc, - TestFactoryBase* factory); - -// If *pstr starts with the given prefix, modifies *pstr to be right -// past the prefix and returns true; otherwise leaves *pstr unchanged -// and returns false. None of pstr, *pstr, and prefix can be NULL. -GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr); - -#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P - -// State of the definition of a type-parameterized test case. -class GTEST_API_ TypedTestCasePState { - public: - TypedTestCasePState() : registered_(false) {} - - // Adds the given test name to defined_test_names_ and return true - // if the test case hasn't been registered; otherwise aborts the - // program. - bool AddTestName(const char* file, int line, const char* case_name, - const char* test_name) { - if (registered_) { - fprintf(stderr, "%s Test %s must be defined before " - "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n", - FormatFileLocation(file, line).c_str(), test_name, case_name); - fflush(stderr); - posix::Abort(); - } - defined_test_names_.insert(test_name); - return true; - } - - // Verifies that registered_tests match the test names in - // defined_test_names_; returns registered_tests if successful, or - // aborts the program otherwise. - const char* VerifyRegisteredTestNames( - const char* file, int line, const char* registered_tests); - - private: - bool registered_; - ::std::set defined_test_names_; -}; - -// Skips to the first non-space char after the first comma in 'str'; -// returns NULL if no comma is found in 'str'. -inline const char* SkipComma(const char* str) { - const char* comma = strchr(str, ','); - if (comma == NULL) { - return NULL; - } - while (IsSpace(*(++comma))) {} - return comma; -} - -// Returns the prefix of 'str' before the first comma in it; returns -// the entire string if it contains no comma. -inline std::string GetPrefixUntilComma(const char* str) { - const char* comma = strchr(str, ','); - return comma == NULL ? str : std::string(str, comma); -} - -// TypeParameterizedTest::Register() -// registers a list of type-parameterized tests with Google Test. The -// return value is insignificant - we just need to return something -// such that we can call this function in a namespace scope. -// -// Implementation note: The GTEST_TEMPLATE_ macro declares a template -// template parameter. It's defined in gtest-type-util.h. -template -class TypeParameterizedTest { - public: - // 'index' is the index of the test in the type list 'Types' - // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, - // Types). Valid values for 'index' are [0, N - 1] where N is the - // length of Types. - static bool Register(const char* prefix, const char* case_name, - const char* test_names, int index) { - typedef typename Types::Head Type; - typedef Fixture FixtureClass; - typedef typename GTEST_BIND_(TestSel, Type) TestClass; - - // First, registers the first type-parameterized test in the type - // list. - MakeAndRegisterTestInfo( - (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/" - + StreamableToString(index)).c_str(), - StripTrailingSpaces(GetPrefixUntilComma(test_names)).c_str(), - GetTypeName().c_str(), - NULL, // No value parameter. - GetTypeId(), - TestClass::SetUpTestCase, - TestClass::TearDownTestCase, - new TestFactoryImpl); - - // Next, recurses (at compile time) with the tail of the type list. - return TypeParameterizedTest - ::Register(prefix, case_name, test_names, index + 1); - } -}; - -// The base case for the compile time recursion. -template -class TypeParameterizedTest { - public: - static bool Register(const char* /*prefix*/, const char* /*case_name*/, - const char* /*test_names*/, int /*index*/) { - return true; - } -}; - -// TypeParameterizedTestCase::Register() -// registers *all combinations* of 'Tests' and 'Types' with Google -// Test. The return value is insignificant - we just need to return -// something such that we can call this function in a namespace scope. -template -class TypeParameterizedTestCase { - public: - static bool Register(const char* prefix, const char* case_name, - const char* test_names) { - typedef typename Tests::Head Head; - - // First, register the first test in 'Test' for each type in 'Types'. - TypeParameterizedTest::Register( - prefix, case_name, test_names, 0); - - // Next, recurses (at compile time) with the tail of the test list. - return TypeParameterizedTestCase - ::Register(prefix, case_name, SkipComma(test_names)); - } -}; - -// The base case for the compile time recursion. -template -class TypeParameterizedTestCase { - public: - static bool Register(const char* /*prefix*/, const char* /*case_name*/, - const char* /*test_names*/) { - return true; - } -}; - -#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P - -// Returns the current OS stack trace as an std::string. -// -// The maximum number of stack frames to be included is specified by -// the gtest_stack_trace_depth flag. The skip_count parameter -// specifies the number of top frames to be skipped, which doesn't -// count against the number of frames to be included. -// -// For example, if Foo() calls Bar(), which in turn calls -// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in -// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. -GTEST_API_ std::string GetCurrentOsStackTraceExceptTop( - UnitTest* unit_test, int skip_count); - -// Helpers for suppressing warnings on unreachable code or constant -// condition. - -// Always returns true. -GTEST_API_ bool AlwaysTrue(); - -// Always returns false. -inline bool AlwaysFalse() { return !AlwaysTrue(); } - -// Helper for suppressing false warning from Clang on a const char* -// variable declared in a conditional expression always being NULL in -// the else branch. -struct GTEST_API_ ConstCharPtr { - ConstCharPtr(const char* str) : value(str) {} - operator bool() const { return true; } - const char* value; -}; - -// A simple Linear Congruential Generator for generating random -// numbers with a uniform distribution. Unlike rand() and srand(), it -// doesn't use global state (and therefore can't interfere with user -// code). Unlike rand_r(), it's portable. An LCG isn't very random, -// but it's good enough for our purposes. -class GTEST_API_ Random { - public: - static const UInt32 kMaxRange = 1u << 31; - - explicit Random(UInt32 seed) : state_(seed) {} - - void Reseed(UInt32 seed) { state_ = seed; } - - // Generates a random number from [0, range). Crashes if 'range' is - // 0 or greater than kMaxRange. - UInt32 Generate(UInt32 range); - - private: - UInt32 state_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); -}; - -// Defining a variable of type CompileAssertTypesEqual will cause a -// compiler error iff T1 and T2 are different types. -template -struct CompileAssertTypesEqual; - -template -struct CompileAssertTypesEqual { -}; - -// Removes the reference from a type if it is a reference type, -// otherwise leaves it unchanged. This is the same as -// tr1::remove_reference, which is not widely available yet. -template -struct RemoveReference { typedef T type; }; // NOLINT -template -struct RemoveReference { typedef T type; }; // NOLINT - -// A handy wrapper around RemoveReference that works when the argument -// T depends on template parameters. -#define GTEST_REMOVE_REFERENCE_(T) \ - typename ::testing::internal::RemoveReference::type - -// Removes const from a type if it is a const type, otherwise leaves -// it unchanged. This is the same as tr1::remove_const, which is not -// widely available yet. -template -struct RemoveConst { typedef T type; }; // NOLINT -template -struct RemoveConst { typedef T type; }; // NOLINT - -// MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above -// definition to fail to remove the const in 'const int[3]' and 'const -// char[3][4]'. The following specialization works around the bug. -template -struct RemoveConst { - typedef typename RemoveConst::type type[N]; -}; - -#if defined(_MSC_VER) && _MSC_VER < 1400 -// This is the only specialization that allows VC++ 7.1 to remove const in -// 'const int[3] and 'const int[3][4]'. However, it causes trouble with GCC -// and thus needs to be conditionally compiled. -template -struct RemoveConst { - typedef typename RemoveConst::type type[N]; -}; -#endif - -// A handy wrapper around RemoveConst that works when the argument -// T depends on template parameters. -#define GTEST_REMOVE_CONST_(T) \ - typename ::testing::internal::RemoveConst::type - -// Turns const U&, U&, const U, and U all into U. -#define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ - GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) - -// Adds reference to a type if it is not a reference type, -// otherwise leaves it unchanged. This is the same as -// tr1::add_reference, which is not widely available yet. -template -struct AddReference { typedef T& type; }; // NOLINT -template -struct AddReference { typedef T& type; }; // NOLINT - -// A handy wrapper around AddReference that works when the argument T -// depends on template parameters. -#define GTEST_ADD_REFERENCE_(T) \ - typename ::testing::internal::AddReference::type - -// Adds a reference to const on top of T as necessary. For example, -// it transforms -// -// char ==> const char& -// const char ==> const char& -// char& ==> const char& -// const char& ==> const char& -// -// The argument T must depend on some template parameters. -#define GTEST_REFERENCE_TO_CONST_(T) \ - GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T)) - -// ImplicitlyConvertible::value is a compile-time bool -// constant that's true iff type From can be implicitly converted to -// type To. -template -class ImplicitlyConvertible { - private: - // We need the following helper functions only for their types. - // They have no implementations. - - // MakeFrom() is an expression whose type is From. We cannot simply - // use From(), as the type From may not have a public default - // constructor. - static typename AddReference::type MakeFrom(); - - // These two functions are overloaded. Given an expression - // Helper(x), the compiler will pick the first version if x can be - // implicitly converted to type To; otherwise it will pick the - // second version. - // - // The first version returns a value of size 1, and the second - // version returns a value of size 2. Therefore, by checking the - // size of Helper(x), which can be done at compile time, we can tell - // which version of Helper() is used, and hence whether x can be - // implicitly converted to type To. - static char Helper(To); - static char (&Helper(...))[2]; // NOLINT - - // We have to put the 'public' section after the 'private' section, - // or MSVC refuses to compile the code. - public: -#if defined(__BORLANDC__) - // C++Builder cannot use member overload resolution during template - // instantiation. The simplest workaround is to use its C++0x type traits - // functions (C++Builder 2009 and above only). - static const bool value = __is_convertible(From, To); -#else - // MSVC warns about implicitly converting from double to int for - // possible loss of data, so we need to temporarily disable the - // warning. - GTEST_DISABLE_MSC_WARNINGS_PUSH_(4244) - static const bool value = - sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; - GTEST_DISABLE_MSC_WARNINGS_POP_() -#endif // __BORLANDC__ -}; -template -const bool ImplicitlyConvertible::value; - -// IsAProtocolMessage::value is a compile-time bool constant that's -// true iff T is type ProtocolMessage, proto2::Message, or a subclass -// of those. -template -struct IsAProtocolMessage - : public bool_constant< - ImplicitlyConvertible::value || - ImplicitlyConvertible::value> { -}; - -// When the compiler sees expression IsContainerTest(0), if C is an -// STL-style container class, the first overload of IsContainerTest -// will be viable (since both C::iterator* and C::const_iterator* are -// valid types and NULL can be implicitly converted to them). It will -// be picked over the second overload as 'int' is a perfect match for -// the type of argument 0. If C::iterator or C::const_iterator is not -// a valid type, the first overload is not viable, and the second -// overload will be picked. Therefore, we can determine whether C is -// a container class by checking the type of IsContainerTest(0). -// The value of the expression is insignificant. -// -// Note that we look for both C::iterator and C::const_iterator. The -// reason is that C++ injects the name of a class as a member of the -// class itself (e.g. you can refer to class iterator as either -// 'iterator' or 'iterator::iterator'). If we look for C::iterator -// only, for example, we would mistakenly think that a class named -// iterator is an STL container. -// -// Also note that the simpler approach of overloading -// IsContainerTest(typename C::const_iterator*) and -// IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. -typedef int IsContainer; -template -IsContainer IsContainerTest(int /* dummy */, - typename C::iterator* /* it */ = NULL, - typename C::const_iterator* /* const_it */ = NULL) { - return 0; -} - -typedef char IsNotContainer; -template -IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } - -// EnableIf::type is void when 'Cond' is true, and -// undefined when 'Cond' is false. To use SFINAE to make a function -// overload only apply when a particular expression is true, add -// "typename EnableIf::type* = 0" as the last parameter. -template struct EnableIf; -template<> struct EnableIf { typedef void type; }; // NOLINT - -// Utilities for native arrays. - -// ArrayEq() compares two k-dimensional native arrays using the -// elements' operator==, where k can be any integer >= 0. When k is -// 0, ArrayEq() degenerates into comparing a single pair of values. - -template -bool ArrayEq(const T* lhs, size_t size, const U* rhs); - -// This generic version is used when k is 0. -template -inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } - -// This overload is used when k >= 1. -template -inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) { - return internal::ArrayEq(lhs, N, rhs); -} - -// This helper reduces code bloat. If we instead put its logic inside -// the previous ArrayEq() function, arrays with different sizes would -// lead to different copies of the template code. -template -bool ArrayEq(const T* lhs, size_t size, const U* rhs) { - for (size_t i = 0; i != size; i++) { - if (!internal::ArrayEq(lhs[i], rhs[i])) - return false; - } - return true; -} - -// Finds the first element in the iterator range [begin, end) that -// equals elem. Element may be a native array type itself. -template -Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) { - for (Iter it = begin; it != end; ++it) { - if (internal::ArrayEq(*it, elem)) - return it; - } - return end; -} - -// CopyArray() copies a k-dimensional native array using the elements' -// operator=, where k can be any integer >= 0. When k is 0, -// CopyArray() degenerates into copying a single value. - -template -void CopyArray(const T* from, size_t size, U* to); - -// This generic version is used when k is 0. -template -inline void CopyArray(const T& from, U* to) { *to = from; } - -// This overload is used when k >= 1. -template -inline void CopyArray(const T(&from)[N], U(*to)[N]) { - internal::CopyArray(from, N, *to); -} - -// This helper reduces code bloat. If we instead put its logic inside -// the previous CopyArray() function, arrays with different sizes -// would lead to different copies of the template code. -template -void CopyArray(const T* from, size_t size, U* to) { - for (size_t i = 0; i != size; i++) { - internal::CopyArray(from[i], to + i); - } -} - -// The relation between an NativeArray object (see below) and the -// native array it represents. -// We use 2 different structs to allow non-copyable types to be used, as long -// as RelationToSourceReference() is passed. -struct RelationToSourceReference {}; -struct RelationToSourceCopy {}; - -// Adapts a native array to a read-only STL-style container. Instead -// of the complete STL container concept, this adaptor only implements -// members useful for Google Mock's container matchers. New members -// should be added as needed. To simplify the implementation, we only -// support Element being a raw type (i.e. having no top-level const or -// reference modifier). It's the client's responsibility to satisfy -// this requirement. Element can be an array type itself (hence -// multi-dimensional arrays are supported). -template -class NativeArray { - public: - // STL-style container typedefs. - typedef Element value_type; - typedef Element* iterator; - typedef const Element* const_iterator; - - // Constructs from a native array. References the source. - NativeArray(const Element* array, size_t count, RelationToSourceReference) { - InitRef(array, count); - } - - // Constructs from a native array. Copies the source. - NativeArray(const Element* array, size_t count, RelationToSourceCopy) { - InitCopy(array, count); - } - - // Copy constructor. - NativeArray(const NativeArray& rhs) { - (this->*rhs.clone_)(rhs.array_, rhs.size_); - } - - ~NativeArray() { - if (clone_ != &NativeArray::InitRef) - delete[] array_; - } - - // STL-style container methods. - size_t size() const { return size_; } - const_iterator begin() const { return array_; } - const_iterator end() const { return array_ + size_; } - bool operator==(const NativeArray& rhs) const { - return size() == rhs.size() && - ArrayEq(begin(), size(), rhs.begin()); - } - - private: - enum { - kCheckTypeIsNotConstOrAReference = StaticAssertTypeEqHelper< - Element, GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>::value, - }; - - // Initializes this object with a copy of the input. - void InitCopy(const Element* array, size_t a_size) { - Element* const copy = new Element[a_size]; - CopyArray(array, a_size, copy); - array_ = copy; - size_ = a_size; - clone_ = &NativeArray::InitCopy; - } - - // Initializes this object with a reference of the input. - void InitRef(const Element* array, size_t a_size) { - array_ = array; - size_ = a_size; - clone_ = &NativeArray::InitRef; - } - - const Element* array_; - size_t size_; - void (NativeArray::*clone_)(const Element*, size_t); - - GTEST_DISALLOW_ASSIGN_(NativeArray); -}; - -} // namespace internal -} // namespace testing - -#define GTEST_MESSAGE_AT_(file, line, message, result_type) \ - ::testing::internal::AssertHelper(result_type, file, line, message) \ - = ::testing::Message() - -#define GTEST_MESSAGE_(message, result_type) \ - GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type) - -#define GTEST_FATAL_FAILURE_(message) \ - return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) - -#define GTEST_NONFATAL_FAILURE_(message) \ - GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure) - -#define GTEST_SUCCESS_(message) \ - GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) - -// Suppresses MSVC warnings 4072 (unreachable code) for the code following -// statement if it returns or throws (or doesn't return or throw in some -// situations). -#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ - if (::testing::internal::AlwaysTrue()) { statement; } - -#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::ConstCharPtr gtest_msg = "") { \ - bool gtest_caught_expected = false; \ - try { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } \ - catch (expected_exception const&) { \ - gtest_caught_expected = true; \ - } \ - catch (...) { \ - gtest_msg.value = \ - "Expected: " #statement " throws an exception of type " \ - #expected_exception ".\n Actual: it throws a different type."; \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ - } \ - if (!gtest_caught_expected) { \ - gtest_msg.value = \ - "Expected: " #statement " throws an exception of type " \ - #expected_exception ".\n Actual: it throws nothing."; \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ - fail(gtest_msg.value) - -#define GTEST_TEST_NO_THROW_(statement, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - try { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } \ - catch (...) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ - fail("Expected: " #statement " doesn't throw an exception.\n" \ - " Actual: it throws.") - -#define GTEST_TEST_ANY_THROW_(statement, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - bool gtest_caught_any = false; \ - try { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } \ - catch (...) { \ - gtest_caught_any = true; \ - } \ - if (!gtest_caught_any) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \ - fail("Expected: " #statement " throws an exception.\n" \ - " Actual: it doesn't.") - - -// Implements Boolean test assertions such as EXPECT_TRUE. expression can be -// either a boolean expression or an AssertionResult. text is a textual -// represenation of expression as it was passed into the EXPECT_TRUE. -#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (const ::testing::AssertionResult gtest_ar_ = \ - ::testing::AssertionResult(expression)) \ - ; \ - else \ - fail(::testing::internal::GetBoolAssertionFailureMessage(\ - gtest_ar_, text, #actual, #expected).c_str()) - -#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \ - fail("Expected: " #statement " doesn't generate new fatal " \ - "failures in the current thread.\n" \ - " Actual: it does.") - -// Expands to the name of the class that implements the given test. -#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ - test_case_name##_##test_name##_Test - -// Helper macro for defining tests. -#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ -class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ - public:\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ - private:\ - virtual void TestBody();\ - static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\ - GTEST_DISALLOW_COPY_AND_ASSIGN_(\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ -};\ -\ -::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ - ::test_info_ =\ - ::testing::internal::MakeAndRegisterTestInfo(\ - #test_case_name, #test_name, NULL, NULL, \ - (parent_id), \ - parent_class::SetUpTestCase, \ - parent_class::TearDownTestCase, \ - new ::testing::internal::TestFactoryImpl<\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ -void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ diff --git a/src/gtest/include/gtest/internal/gtest-linked_ptr.h b/src/gtest/include/gtest/internal/gtest-linked_ptr.h deleted file mode 100644 index 5ccfa22f..00000000 --- a/src/gtest/include/gtest/internal/gtest-linked_ptr.h +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright 2003 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// -// -// A "smart" pointer type with reference tracking. Every pointer to a -// particular object is kept on a circular linked list. When the last pointer -// to an object is destroyed or reassigned, the object is deleted. -// -// Used properly, this deletes the object when the last reference goes away. -// There are several caveats: -// - Like all reference counting schemes, cycles lead to leaks. -// - Each smart pointer is actually two pointers (8 bytes instead of 4). -// - Every time a pointer is assigned, the entire list of pointers to that -// object is traversed. This class is therefore NOT SUITABLE when there -// will often be more than two or three pointers to a particular object. -// - References are only tracked as long as linked_ptr<> objects are copied. -// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS -// will happen (double deletion). -// -// A good use of this class is storing object references in STL containers. -// You can safely put linked_ptr<> in a vector<>. -// Other uses may not be as good. -// -// Note: If you use an incomplete type with linked_ptr<>, the class -// *containing* linked_ptr<> must have a constructor and destructor (even -// if they do nothing!). -// -// Bill Gibbons suggested we use something like this. -// -// Thread Safety: -// Unlike other linked_ptr implementations, in this implementation -// a linked_ptr object is thread-safe in the sense that: -// - it's safe to copy linked_ptr objects concurrently, -// - it's safe to copy *from* a linked_ptr and read its underlying -// raw pointer (e.g. via get()) concurrently, and -// - it's safe to write to two linked_ptrs that point to the same -// shared object concurrently. -// TODO(wan@google.com): rename this to safe_linked_ptr to avoid -// confusion with normal linked_ptr. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ - -#include -#include - -#include "gtest/internal/gtest-port.h" - -namespace testing { -namespace internal { - -// Protects copying of all linked_ptr objects. -GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); - -// This is used internally by all instances of linked_ptr<>. It needs to be -// a non-template class because different types of linked_ptr<> can refer to -// the same object (linked_ptr(obj) vs linked_ptr(obj)). -// So, it needs to be possible for different types of linked_ptr to participate -// in the same circular linked list, so we need a single class type here. -// -// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr. -class linked_ptr_internal { - public: - // Create a new circle that includes only this instance. - void join_new() { - next_ = this; - } - - // Many linked_ptr operations may change p.link_ for some linked_ptr - // variable p in the same circle as this object. Therefore we need - // to prevent two such operations from occurring concurrently. - // - // Note that different types of linked_ptr objects can coexist in a - // circle (e.g. linked_ptr, linked_ptr, and - // linked_ptr). Therefore we must use a single mutex to - // protect all linked_ptr objects. This can create serious - // contention in production code, but is acceptable in a testing - // framework. - - // Join an existing circle. - void join(linked_ptr_internal const* ptr) - GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { - MutexLock lock(&g_linked_ptr_mutex); - - linked_ptr_internal const* p = ptr; - while (p->next_ != ptr) { - assert(p->next_ != this && - "Trying to join() a linked ring we are already in. " - "Is GMock thread safety enabled?"); - p = p->next_; - } - p->next_ = this; - next_ = ptr; - } - - // Leave whatever circle we're part of. Returns true if we were the - // last member of the circle. Once this is done, you can join() another. - bool depart() - GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { - MutexLock lock(&g_linked_ptr_mutex); - - if (next_ == this) return true; - linked_ptr_internal const* p = next_; - while (p->next_ != this) { - assert(p->next_ != next_ && - "Trying to depart() a linked ring we are not in. " - "Is GMock thread safety enabled?"); - p = p->next_; - } - p->next_ = next_; - return false; - } - - private: - mutable linked_ptr_internal const* next_; -}; - -template -class linked_ptr { - public: - typedef T element_type; - - // Take over ownership of a raw pointer. This should happen as soon as - // possible after the object is created. - explicit linked_ptr(T* ptr = NULL) { capture(ptr); } - ~linked_ptr() { depart(); } - - // Copy an existing linked_ptr<>, adding ourselves to the list of references. - template linked_ptr(linked_ptr const& ptr) { copy(&ptr); } - linked_ptr(linked_ptr const& ptr) { // NOLINT - assert(&ptr != this); - copy(&ptr); - } - - // Assignment releases the old value and acquires the new. - template linked_ptr& operator=(linked_ptr const& ptr) { - depart(); - copy(&ptr); - return *this; - } - - linked_ptr& operator=(linked_ptr const& ptr) { - if (&ptr != this) { - depart(); - copy(&ptr); - } - return *this; - } - - // Smart pointer members. - void reset(T* ptr = NULL) { - depart(); - capture(ptr); - } - T* get() const { return value_; } - T* operator->() const { return value_; } - T& operator*() const { return *value_; } - - bool operator==(T* p) const { return value_ == p; } - bool operator!=(T* p) const { return value_ != p; } - template - bool operator==(linked_ptr const& ptr) const { - return value_ == ptr.get(); - } - template - bool operator!=(linked_ptr const& ptr) const { - return value_ != ptr.get(); - } - - private: - template - friend class linked_ptr; - - T* value_; - linked_ptr_internal link_; - - void depart() { - if (link_.depart()) delete value_; - } - - void capture(T* ptr) { - value_ = ptr; - link_.join_new(); - } - - template void copy(linked_ptr const* ptr) { - value_ = ptr->get(); - if (value_) - link_.join(&ptr->link_); - else - link_.join_new(); - } -}; - -template inline -bool operator==(T* ptr, const linked_ptr& x) { - return ptr == x.get(); -} - -template inline -bool operator!=(T* ptr, const linked_ptr& x) { - return ptr != x.get(); -} - -// A function to convert T* into linked_ptr -// Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation -// for linked_ptr >(new FooBarBaz(arg)) -template -linked_ptr make_linked_ptr(T* ptr) { - return linked_ptr(ptr); -} - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ \ No newline at end of file diff --git a/src/gtest/include/gtest/internal/gtest-param-util-generated.h b/src/gtest/include/gtest/internal/gtest-param-util-generated.h deleted file mode 100644 index 8fc0b86a..00000000 --- a/src/gtest/include/gtest/internal/gtest-param-util-generated.h +++ /dev/null @@ -1,5155 +0,0 @@ -// Copyright 2008 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file was GENERATED by command: -// pump.py gtest-param-util-generated.h.pump -// DO NOT EDIT BY HAND!!! - -// 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. -// - -// Type and function utilities for implementing parameterized tests. -// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! -// -// Currently Google Test supports at most 50 arguments in Values, -// and at most 10 arguments in Combine. Please contact -// googletestframework@googlegroups.com if you need more. -// Please note that the number of arguments to Combine is limited -// by the maximum arity of the implementation of tuple which is -// currently set at 10. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ - -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. -#include "gtest/internal/gtest-param-util.h" -#include "gtest/internal/gtest-port.h" - -#if GTEST_HAS_PARAM_TEST - -namespace testing { - -// Forward declarations of ValuesIn(), which is implemented in -// include/gtest/gtest-param-test.h. -template -internal::ParamGenerator< - typename ::testing::internal::IteratorTraits::value_type> -ValuesIn(ForwardIterator begin, ForwardIterator end); - -template -internal::ParamGenerator ValuesIn(const T (&array)[N]); - -template -internal::ParamGenerator ValuesIn( - const Container& container); - -namespace internal { - -// Used in the Values() function to provide polymorphic capabilities. -template -class ValueArray1 { - public: - explicit ValueArray1(T1 v1) : v1_(v1) {} - - template - operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray1& other); - - const T1 v1_; -}; - -template -class ValueArray2 { - public: - ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray2& other); - - const T1 v1_; - const T2 v2_; -}; - -template -class ValueArray3 { - public: - ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray3& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; -}; - -template -class ValueArray4 { - public: - ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray4& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; -}; - -template -class ValueArray5 { - public: - ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray5& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; -}; - -template -class ValueArray6 { - public: - ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray6& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; -}; - -template -class ValueArray7 { - public: - ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray7& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; -}; - -template -class ValueArray8 { - public: - ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray8& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; -}; - -template -class ValueArray9 { - public: - ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray9& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; -}; - -template -class ValueArray10 { - public: - ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray10& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; -}; - -template -class ValueArray11 { - public: - ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), - v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray11& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; -}; - -template -class ValueArray12 { - public: - ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), - v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray12& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; -}; - -template -class ValueArray13 { - public: - ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), - v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), - v12_(v12), v13_(v13) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray13& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; -}; - -template -class ValueArray14 { - public: - ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray14& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; -}; - -template -class ValueArray15 { - public: - ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray15& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; -}; - -template -class ValueArray16 { - public: - ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), - v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), - v16_(v16) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray16& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; -}; - -template -class ValueArray17 { - public: - ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, - T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray17& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; -}; - -template -class ValueArray18 { - public: - ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray18& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; -}; - -template -class ValueArray19 { - public: - ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), - v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), - v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray19& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; -}; - -template -class ValueArray20 { - public: - ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), - v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), - v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), - v19_(v19), v20_(v20) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray20& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; -}; - -template -class ValueArray21 { - public: - ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), - v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), - v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), - v18_(v18), v19_(v19), v20_(v20), v21_(v21) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray21& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; -}; - -template -class ValueArray22 { - public: - ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray22& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; -}; - -template -class ValueArray23 { - public: - ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray23& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; -}; - -template -class ValueArray24 { - public: - ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), - v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), - v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), - v22_(v22), v23_(v23), v24_(v24) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray24& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; -}; - -template -class ValueArray25 { - public: - ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, - T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray25& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; -}; - -template -class ValueArray26 { - public: - ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray26& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; -}; - -template -class ValueArray27 { - public: - ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), - v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), - v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), - v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), - v26_(v26), v27_(v27) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray27& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; -}; - -template -class ValueArray28 { - public: - ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), - v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), - v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), - v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), - v25_(v25), v26_(v26), v27_(v27), v28_(v28) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray28& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; -}; - -template -class ValueArray29 { - public: - ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), - v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), - v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), - v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), - v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray29& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; -}; - -template -class ValueArray30 { - public: - ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray30& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; -}; - -template -class ValueArray31 { - public: - ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30), v31_(v31) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray31& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; -}; - -template -class ValueArray32 { - public: - ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), - v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), - v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), - v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), - v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray32& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; -}; - -template -class ValueArray33 { - public: - ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, - T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray33& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; -}; - -template -class ValueArray34 { - public: - ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33), v34_(v34) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray34& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; -}; - -template -class ValueArray35 { - public: - ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), - v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), - v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), - v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), - v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), - v32_(v32), v33_(v33), v34_(v34), v35_(v35) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray35& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; -}; - -template -class ValueArray36 { - public: - ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), - v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), - v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), - v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), - v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), - v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray36& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; -}; - -template -class ValueArray37 { - public: - ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), - v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), - v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), - v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), - v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), - v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), - v36_(v36), v37_(v37) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray37& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; -}; - -template -class ValueArray38 { - public: - ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), - v35_(v35), v36_(v36), v37_(v37), v38_(v38) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray38& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; -}; - -template -class ValueArray39 { - public: - ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), - v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray39& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; -}; - -template -class ValueArray40 { - public: - ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), - v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), - v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), - v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), - v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), - v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), - v40_(v40) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray40& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; -}; - -template -class ValueArray41 { - public: - ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, - T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), - v39_(v39), v40_(v40), v41_(v41) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray41& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; -}; - -template -class ValueArray42 { - public: - ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), - v39_(v39), v40_(v40), v41_(v41), v42_(v42) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray42& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; -}; - -template -class ValueArray43 { - public: - ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), - v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), - v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), - v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), - v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), - v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), - v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray43& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; -}; - -template -class ValueArray44 { - public: - ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), - v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), - v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), - v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), - v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), - v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), - v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), - v43_(v43), v44_(v44) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray44& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; -}; - -template -class ValueArray45 { - public: - ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), - v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), - v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), - v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), - v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), - v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), - v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), - v42_(v42), v43_(v43), v44_(v44), v45_(v45) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_), - static_cast(v45_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray45& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; -}; - -template -class ValueArray46 { - public: - ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), - v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), - v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_), - static_cast(v45_), static_cast(v46_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray46& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; - const T46 v46_; -}; - -template -class ValueArray47 { - public: - ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), - v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), - v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), - v47_(v47) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_), - static_cast(v45_), static_cast(v46_), static_cast(v47_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray47& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; - const T46 v46_; - const T47 v47_; -}; - -template -class ValueArray48 { - public: - ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), - v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), - v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), - v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), - v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), - v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), - v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), - v46_(v46), v47_(v47), v48_(v48) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_), - static_cast(v45_), static_cast(v46_), static_cast(v47_), - static_cast(v48_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray48& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; - const T46 v46_; - const T47 v47_; - const T48 v48_; -}; - -template -class ValueArray49 { - public: - ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, - T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), - v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), - v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_), - static_cast(v45_), static_cast(v46_), static_cast(v47_), - static_cast(v48_), static_cast(v49_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray49& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; - const T46 v46_; - const T47 v47_; - const T48 v48_; - const T49 v49_; -}; - -template -class ValueArray50 { - public: - ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, - T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), - v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), - v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_), - static_cast(v45_), static_cast(v46_), static_cast(v47_), - static_cast(v48_), static_cast(v49_), static_cast(v50_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray50& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; - const T46 v46_; - const T47 v47_; - const T48 v48_; - const T49 v49_; - const T50 v50_; -}; - -# if GTEST_HAS_COMBINE -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Generates values from the Cartesian product of values produced -// by the argument generators. -// -template -class CartesianProductGenerator2 - : public ParamGeneratorInterface< ::testing::tuple > { - public: - typedef ::testing::tuple ParamType; - - CartesianProductGenerator2(const ParamGenerator& g1, - const ParamGenerator& g2) - : g1_(g1), g2_(g2) {} - virtual ~CartesianProductGenerator2() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current2_; - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - ParamType current_value_; - }; // class CartesianProductGenerator2::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator2& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; -}; // class CartesianProductGenerator2 - - -template -class CartesianProductGenerator3 - : public ParamGeneratorInterface< ::testing::tuple > { - public: - typedef ::testing::tuple ParamType; - - CartesianProductGenerator3(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3) - : g1_(g1), g2_(g2), g3_(g3) {} - virtual ~CartesianProductGenerator3() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current3_; - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - ParamType current_value_; - }; // class CartesianProductGenerator3::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator3& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; -}; // class CartesianProductGenerator3 - - -template -class CartesianProductGenerator4 - : public ParamGeneratorInterface< ::testing::tuple > { - public: - typedef ::testing::tuple ParamType; - - CartesianProductGenerator4(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} - virtual ~CartesianProductGenerator4() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current4_; - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - ParamType current_value_; - }; // class CartesianProductGenerator4::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator4& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; -}; // class CartesianProductGenerator4 - - -template -class CartesianProductGenerator5 - : public ParamGeneratorInterface< ::testing::tuple > { - public: - typedef ::testing::tuple ParamType; - - CartesianProductGenerator5(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} - virtual ~CartesianProductGenerator5() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current5_; - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - ParamType current_value_; - }; // class CartesianProductGenerator5::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator5& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; -}; // class CartesianProductGenerator5 - - -template -class CartesianProductGenerator6 - : public ParamGeneratorInterface< ::testing::tuple > { - public: - typedef ::testing::tuple ParamType; - - CartesianProductGenerator6(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5, - const ParamGenerator& g6) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} - virtual ~CartesianProductGenerator6() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5, - const ParamGenerator& g6, - const typename ParamGenerator::iterator& current6) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5), - begin6_(g6.begin()), end6_(g6.end()), current6_(current6) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current6_; - if (current6_ == end6_) { - current6_ = begin6_; - ++current5_; - } - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_ && - current6_ == typed_other->current6_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_), - begin6_(other.begin6_), - end6_(other.end6_), - current6_(other.current6_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_ || - current6_ == end6_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - const typename ParamGenerator::iterator begin6_; - const typename ParamGenerator::iterator end6_; - typename ParamGenerator::iterator current6_; - ParamType current_value_; - }; // class CartesianProductGenerator6::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator6& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; - const ParamGenerator g6_; -}; // class CartesianProductGenerator6 - - -template -class CartesianProductGenerator7 - : public ParamGeneratorInterface< ::testing::tuple > { - public: - typedef ::testing::tuple ParamType; - - CartesianProductGenerator7(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5, - const ParamGenerator& g6, const ParamGenerator& g7) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} - virtual ~CartesianProductGenerator7() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, - g7_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5, - const ParamGenerator& g6, - const typename ParamGenerator::iterator& current6, - const ParamGenerator& g7, - const typename ParamGenerator::iterator& current7) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5), - begin6_(g6.begin()), end6_(g6.end()), current6_(current6), - begin7_(g7.begin()), end7_(g7.end()), current7_(current7) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current7_; - if (current7_ == end7_) { - current7_ = begin7_; - ++current6_; - } - if (current6_ == end6_) { - current6_ = begin6_; - ++current5_; - } - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_ && - current6_ == typed_other->current6_ && - current7_ == typed_other->current7_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_), - begin6_(other.begin6_), - end6_(other.end6_), - current6_(other.current6_), - begin7_(other.begin7_), - end7_(other.end7_), - current7_(other.current7_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_ || - current6_ == end6_ || - current7_ == end7_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - const typename ParamGenerator::iterator begin6_; - const typename ParamGenerator::iterator end6_; - typename ParamGenerator::iterator current6_; - const typename ParamGenerator::iterator begin7_; - const typename ParamGenerator::iterator end7_; - typename ParamGenerator::iterator current7_; - ParamType current_value_; - }; // class CartesianProductGenerator7::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator7& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; - const ParamGenerator g6_; - const ParamGenerator g7_; -}; // class CartesianProductGenerator7 - - -template -class CartesianProductGenerator8 - : public ParamGeneratorInterface< ::testing::tuple > { - public: - typedef ::testing::tuple ParamType; - - CartesianProductGenerator8(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5, - const ParamGenerator& g6, const ParamGenerator& g7, - const ParamGenerator& g8) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), - g8_(g8) {} - virtual ~CartesianProductGenerator8() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, - g7_.begin(), g8_, g8_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, - g8_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5, - const ParamGenerator& g6, - const typename ParamGenerator::iterator& current6, - const ParamGenerator& g7, - const typename ParamGenerator::iterator& current7, - const ParamGenerator& g8, - const typename ParamGenerator::iterator& current8) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5), - begin6_(g6.begin()), end6_(g6.end()), current6_(current6), - begin7_(g7.begin()), end7_(g7.end()), current7_(current7), - begin8_(g8.begin()), end8_(g8.end()), current8_(current8) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current8_; - if (current8_ == end8_) { - current8_ = begin8_; - ++current7_; - } - if (current7_ == end7_) { - current7_ = begin7_; - ++current6_; - } - if (current6_ == end6_) { - current6_ = begin6_; - ++current5_; - } - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_ && - current6_ == typed_other->current6_ && - current7_ == typed_other->current7_ && - current8_ == typed_other->current8_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_), - begin6_(other.begin6_), - end6_(other.end6_), - current6_(other.current6_), - begin7_(other.begin7_), - end7_(other.end7_), - current7_(other.current7_), - begin8_(other.begin8_), - end8_(other.end8_), - current8_(other.current8_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_, *current8_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_ || - current6_ == end6_ || - current7_ == end7_ || - current8_ == end8_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - const typename ParamGenerator::iterator begin6_; - const typename ParamGenerator::iterator end6_; - typename ParamGenerator::iterator current6_; - const typename ParamGenerator::iterator begin7_; - const typename ParamGenerator::iterator end7_; - typename ParamGenerator::iterator current7_; - const typename ParamGenerator::iterator begin8_; - const typename ParamGenerator::iterator end8_; - typename ParamGenerator::iterator current8_; - ParamType current_value_; - }; // class CartesianProductGenerator8::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator8& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; - const ParamGenerator g6_; - const ParamGenerator g7_; - const ParamGenerator g8_; -}; // class CartesianProductGenerator8 - - -template -class CartesianProductGenerator9 - : public ParamGeneratorInterface< ::testing::tuple > { - public: - typedef ::testing::tuple ParamType; - - CartesianProductGenerator9(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5, - const ParamGenerator& g6, const ParamGenerator& g7, - const ParamGenerator& g8, const ParamGenerator& g9) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), - g9_(g9) {} - virtual ~CartesianProductGenerator9() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, - g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, - g8_.end(), g9_, g9_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5, - const ParamGenerator& g6, - const typename ParamGenerator::iterator& current6, - const ParamGenerator& g7, - const typename ParamGenerator::iterator& current7, - const ParamGenerator& g8, - const typename ParamGenerator::iterator& current8, - const ParamGenerator& g9, - const typename ParamGenerator::iterator& current9) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5), - begin6_(g6.begin()), end6_(g6.end()), current6_(current6), - begin7_(g7.begin()), end7_(g7.end()), current7_(current7), - begin8_(g8.begin()), end8_(g8.end()), current8_(current8), - begin9_(g9.begin()), end9_(g9.end()), current9_(current9) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current9_; - if (current9_ == end9_) { - current9_ = begin9_; - ++current8_; - } - if (current8_ == end8_) { - current8_ = begin8_; - ++current7_; - } - if (current7_ == end7_) { - current7_ = begin7_; - ++current6_; - } - if (current6_ == end6_) { - current6_ = begin6_; - ++current5_; - } - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_ && - current6_ == typed_other->current6_ && - current7_ == typed_other->current7_ && - current8_ == typed_other->current8_ && - current9_ == typed_other->current9_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_), - begin6_(other.begin6_), - end6_(other.end6_), - current6_(other.current6_), - begin7_(other.begin7_), - end7_(other.end7_), - current7_(other.current7_), - begin8_(other.begin8_), - end8_(other.end8_), - current8_(other.current8_), - begin9_(other.begin9_), - end9_(other.end9_), - current9_(other.current9_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_, *current8_, - *current9_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_ || - current6_ == end6_ || - current7_ == end7_ || - current8_ == end8_ || - current9_ == end9_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - const typename ParamGenerator::iterator begin6_; - const typename ParamGenerator::iterator end6_; - typename ParamGenerator::iterator current6_; - const typename ParamGenerator::iterator begin7_; - const typename ParamGenerator::iterator end7_; - typename ParamGenerator::iterator current7_; - const typename ParamGenerator::iterator begin8_; - const typename ParamGenerator::iterator end8_; - typename ParamGenerator::iterator current8_; - const typename ParamGenerator::iterator begin9_; - const typename ParamGenerator::iterator end9_; - typename ParamGenerator::iterator current9_; - ParamType current_value_; - }; // class CartesianProductGenerator9::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator9& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; - const ParamGenerator g6_; - const ParamGenerator g7_; - const ParamGenerator g8_; - const ParamGenerator g9_; -}; // class CartesianProductGenerator9 - - -template -class CartesianProductGenerator10 - : public ParamGeneratorInterface< ::testing::tuple > { - public: - typedef ::testing::tuple ParamType; - - CartesianProductGenerator10(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5, - const ParamGenerator& g6, const ParamGenerator& g7, - const ParamGenerator& g8, const ParamGenerator& g9, - const ParamGenerator& g10) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), - g9_(g9), g10_(g10) {} - virtual ~CartesianProductGenerator10() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, - g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, - g8_.end(), g9_, g9_.end(), g10_, g10_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5, - const ParamGenerator& g6, - const typename ParamGenerator::iterator& current6, - const ParamGenerator& g7, - const typename ParamGenerator::iterator& current7, - const ParamGenerator& g8, - const typename ParamGenerator::iterator& current8, - const ParamGenerator& g9, - const typename ParamGenerator::iterator& current9, - const ParamGenerator& g10, - const typename ParamGenerator::iterator& current10) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5), - begin6_(g6.begin()), end6_(g6.end()), current6_(current6), - begin7_(g7.begin()), end7_(g7.end()), current7_(current7), - begin8_(g8.begin()), end8_(g8.end()), current8_(current8), - begin9_(g9.begin()), end9_(g9.end()), current9_(current9), - begin10_(g10.begin()), end10_(g10.end()), current10_(current10) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current10_; - if (current10_ == end10_) { - current10_ = begin10_; - ++current9_; - } - if (current9_ == end9_) { - current9_ = begin9_; - ++current8_; - } - if (current8_ == end8_) { - current8_ = begin8_; - ++current7_; - } - if (current7_ == end7_) { - current7_ = begin7_; - ++current6_; - } - if (current6_ == end6_) { - current6_ = begin6_; - ++current5_; - } - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_ && - current6_ == typed_other->current6_ && - current7_ == typed_other->current7_ && - current8_ == typed_other->current8_ && - current9_ == typed_other->current9_ && - current10_ == typed_other->current10_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_), - begin6_(other.begin6_), - end6_(other.end6_), - current6_(other.current6_), - begin7_(other.begin7_), - end7_(other.end7_), - current7_(other.current7_), - begin8_(other.begin8_), - end8_(other.end8_), - current8_(other.current8_), - begin9_(other.begin9_), - end9_(other.end9_), - current9_(other.current9_), - begin10_(other.begin10_), - end10_(other.end10_), - current10_(other.current10_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_, *current8_, - *current9_, *current10_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_ || - current6_ == end6_ || - current7_ == end7_ || - current8_ == end8_ || - current9_ == end9_ || - current10_ == end10_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - const typename ParamGenerator::iterator begin6_; - const typename ParamGenerator::iterator end6_; - typename ParamGenerator::iterator current6_; - const typename ParamGenerator::iterator begin7_; - const typename ParamGenerator::iterator end7_; - typename ParamGenerator::iterator current7_; - const typename ParamGenerator::iterator begin8_; - const typename ParamGenerator::iterator end8_; - typename ParamGenerator::iterator current8_; - const typename ParamGenerator::iterator begin9_; - const typename ParamGenerator::iterator end9_; - typename ParamGenerator::iterator current9_; - const typename ParamGenerator::iterator begin10_; - const typename ParamGenerator::iterator end10_; - typename ParamGenerator::iterator current10_; - ParamType current_value_; - }; // class CartesianProductGenerator10::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator10& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; - const ParamGenerator g6_; - const ParamGenerator g7_; - const ParamGenerator g8_; - const ParamGenerator g9_; - const ParamGenerator g10_; -}; // class CartesianProductGenerator10 - - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Helper classes providing Combine() with polymorphic features. They allow -// casting CartesianProductGeneratorN to ParamGenerator if T is -// convertible to U. -// -template -class CartesianProductHolder2 { - public: -CartesianProductHolder2(const Generator1& g1, const Generator2& g2) - : g1_(g1), g2_(g2) {} - template - operator ParamGenerator< ::testing::tuple >() const { - return ParamGenerator< ::testing::tuple >( - new CartesianProductGenerator2( - static_cast >(g1_), - static_cast >(g2_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder2& other); - - const Generator1 g1_; - const Generator2 g2_; -}; // class CartesianProductHolder2 - -template -class CartesianProductHolder3 { - public: -CartesianProductHolder3(const Generator1& g1, const Generator2& g2, - const Generator3& g3) - : g1_(g1), g2_(g2), g3_(g3) {} - template - operator ParamGenerator< ::testing::tuple >() const { - return ParamGenerator< ::testing::tuple >( - new CartesianProductGenerator3( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder3& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; -}; // class CartesianProductHolder3 - -template -class CartesianProductHolder4 { - public: -CartesianProductHolder4(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} - template - operator ParamGenerator< ::testing::tuple >() const { - return ParamGenerator< ::testing::tuple >( - new CartesianProductGenerator4( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder4& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; -}; // class CartesianProductHolder4 - -template -class CartesianProductHolder5 { - public: -CartesianProductHolder5(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} - template - operator ParamGenerator< ::testing::tuple >() const { - return ParamGenerator< ::testing::tuple >( - new CartesianProductGenerator5( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder5& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; -}; // class CartesianProductHolder5 - -template -class CartesianProductHolder6 { - public: -CartesianProductHolder6(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5, - const Generator6& g6) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} - template - operator ParamGenerator< ::testing::tuple >() const { - return ParamGenerator< ::testing::tuple >( - new CartesianProductGenerator6( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_), - static_cast >(g6_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder6& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; - const Generator6 g6_; -}; // class CartesianProductHolder6 - -template -class CartesianProductHolder7 { - public: -CartesianProductHolder7(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5, - const Generator6& g6, const Generator7& g7) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} - template - operator ParamGenerator< ::testing::tuple >() const { - return ParamGenerator< ::testing::tuple >( - new CartesianProductGenerator7( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_), - static_cast >(g6_), - static_cast >(g7_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder7& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; - const Generator6 g6_; - const Generator7 g7_; -}; // class CartesianProductHolder7 - -template -class CartesianProductHolder8 { - public: -CartesianProductHolder8(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5, - const Generator6& g6, const Generator7& g7, const Generator8& g8) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), - g8_(g8) {} - template - operator ParamGenerator< ::testing::tuple >() const { - return ParamGenerator< ::testing::tuple >( - new CartesianProductGenerator8( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_), - static_cast >(g6_), - static_cast >(g7_), - static_cast >(g8_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder8& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; - const Generator6 g6_; - const Generator7 g7_; - const Generator8 g8_; -}; // class CartesianProductHolder8 - -template -class CartesianProductHolder9 { - public: -CartesianProductHolder9(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5, - const Generator6& g6, const Generator7& g7, const Generator8& g8, - const Generator9& g9) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), - g9_(g9) {} - template - operator ParamGenerator< ::testing::tuple >() const { - return ParamGenerator< ::testing::tuple >( - new CartesianProductGenerator9( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_), - static_cast >(g6_), - static_cast >(g7_), - static_cast >(g8_), - static_cast >(g9_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder9& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; - const Generator6 g6_; - const Generator7 g7_; - const Generator8 g8_; - const Generator9 g9_; -}; // class CartesianProductHolder9 - -template -class CartesianProductHolder10 { - public: -CartesianProductHolder10(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5, - const Generator6& g6, const Generator7& g7, const Generator8& g8, - const Generator9& g9, const Generator10& g10) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), - g9_(g9), g10_(g10) {} - template - operator ParamGenerator< ::testing::tuple >() const { - return ParamGenerator< ::testing::tuple >( - new CartesianProductGenerator10( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_), - static_cast >(g6_), - static_cast >(g7_), - static_cast >(g8_), - static_cast >(g9_), - static_cast >(g10_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder10& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; - const Generator6 g6_; - const Generator7 g7_; - const Generator8 g8_; - const Generator9 g9_; - const Generator10 g10_; -}; // class CartesianProductHolder10 - -# endif // GTEST_HAS_COMBINE - -} // namespace internal -} // namespace testing - -#endif // GTEST_HAS_PARAM_TEST - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ \ No newline at end of file diff --git a/src/gtest/include/gtest/internal/gtest-param-util.h b/src/gtest/include/gtest/internal/gtest-param-util.h deleted file mode 100644 index ee93cb02..00000000 --- a/src/gtest/include/gtest/internal/gtest-param-util.h +++ /dev/null @@ -1,631 +0,0 @@ -// Copyright 2008 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// - -// Type and function utilities for implementing parameterized tests. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ - -#include -#include -#include - -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. -#include "gtest/internal/gtest-internal.h" -#include "gtest/internal/gtest-linked_ptr.h" -#include "gtest/internal/gtest-port.h" -#include "gtest/gtest-printers.h" - -#if GTEST_HAS_PARAM_TEST - -namespace testing { -namespace internal { - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Outputs a message explaining invalid registration of different -// fixture class for the same test case. This may happen when -// TEST_P macro is used to define two tests with the same name -// but in different namespaces. -GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name, - const char* file, int line); - -template class ParamGeneratorInterface; -template class ParamGenerator; - -// Interface for iterating over elements provided by an implementation -// of ParamGeneratorInterface. -template -class ParamIteratorInterface { - public: - virtual ~ParamIteratorInterface() {} - // A pointer to the base generator instance. - // Used only for the purposes of iterator comparison - // to make sure that two iterators belong to the same generator. - virtual const ParamGeneratorInterface* BaseGenerator() const = 0; - // Advances iterator to point to the next element - // provided by the generator. The caller is responsible - // for not calling Advance() on an iterator equal to - // BaseGenerator()->End(). - virtual void Advance() = 0; - // Clones the iterator object. Used for implementing copy semantics - // of ParamIterator. - virtual ParamIteratorInterface* Clone() const = 0; - // Dereferences the current iterator and provides (read-only) access - // to the pointed value. It is the caller's responsibility not to call - // Current() on an iterator equal to BaseGenerator()->End(). - // Used for implementing ParamGenerator::operator*(). - virtual const T* Current() const = 0; - // Determines whether the given iterator and other point to the same - // element in the sequence generated by the generator. - // Used for implementing ParamGenerator::operator==(). - virtual bool Equals(const ParamIteratorInterface& other) const = 0; -}; - -// Class iterating over elements provided by an implementation of -// ParamGeneratorInterface. It wraps ParamIteratorInterface -// and implements the const forward iterator concept. -template -class ParamIterator { - public: - typedef T value_type; - typedef const T& reference; - typedef ptrdiff_t difference_type; - - // ParamIterator assumes ownership of the impl_ pointer. - ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {} - ParamIterator& operator=(const ParamIterator& other) { - if (this != &other) - impl_.reset(other.impl_->Clone()); - return *this; - } - - const T& operator*() const { return *impl_->Current(); } - const T* operator->() const { return impl_->Current(); } - // Prefix version of operator++. - ParamIterator& operator++() { - impl_->Advance(); - return *this; - } - // Postfix version of operator++. - ParamIterator operator++(int /*unused*/) { - ParamIteratorInterface* clone = impl_->Clone(); - impl_->Advance(); - return ParamIterator(clone); - } - bool operator==(const ParamIterator& other) const { - return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_); - } - bool operator!=(const ParamIterator& other) const { - return !(*this == other); - } - - private: - friend class ParamGenerator; - explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} - scoped_ptr > impl_; -}; - -// ParamGeneratorInterface is the binary interface to access generators -// defined in other translation units. -template -class ParamGeneratorInterface { - public: - typedef T ParamType; - - virtual ~ParamGeneratorInterface() {} - - // Generator interface definition - virtual ParamIteratorInterface* Begin() const = 0; - virtual ParamIteratorInterface* End() const = 0; -}; - -// Wraps ParamGeneratorInterface and provides general generator syntax -// compatible with the STL Container concept. -// This class implements copy initialization semantics and the contained -// ParamGeneratorInterface instance is shared among all copies -// of the original object. This is possible because that instance is immutable. -template -class ParamGenerator { - public: - typedef ParamIterator iterator; - - explicit ParamGenerator(ParamGeneratorInterface* impl) : impl_(impl) {} - ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {} - - ParamGenerator& operator=(const ParamGenerator& other) { - impl_ = other.impl_; - return *this; - } - - iterator begin() const { return iterator(impl_->Begin()); } - iterator end() const { return iterator(impl_->End()); } - - private: - linked_ptr > impl_; -}; - -// Generates values from a range of two comparable values. Can be used to -// generate sequences of user-defined types that implement operator+() and -// operator<(). -// This class is used in the Range() function. -template -class RangeGenerator : public ParamGeneratorInterface { - public: - RangeGenerator(T begin, T end, IncrementT step) - : begin_(begin), end_(end), - step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} - virtual ~RangeGenerator() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, begin_, 0, step_); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, end_, end_index_, step_); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, T value, int index, - IncrementT step) - : base_(base), value_(value), index_(index), step_(step) {} - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - virtual void Advance() { - value_ = value_ + step_; - index_++; - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const T* Current() const { return &value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const int other_index = - CheckedDowncastToActualType(&other)->index_; - return index_ == other_index; - } - - private: - Iterator(const Iterator& other) - : ParamIteratorInterface(), - base_(other.base_), value_(other.value_), index_(other.index_), - step_(other.step_) {} - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - T value_; - int index_; - const IncrementT step_; - }; // class RangeGenerator::Iterator - - static int CalculateEndIndex(const T& begin, - const T& end, - const IncrementT& step) { - int end_index = 0; - for (T i = begin; i < end; i = i + step) - end_index++; - return end_index; - } - - // No implementation - assignment is unsupported. - void operator=(const RangeGenerator& other); - - const T begin_; - const T end_; - const IncrementT step_; - // The index for the end() iterator. All the elements in the generated - // sequence are indexed (0-based) to aid iterator comparison. - const int end_index_; -}; // class RangeGenerator - - -// Generates values from a pair of STL-style iterators. Used in the -// ValuesIn() function. The elements are copied from the source range -// since the source can be located on the stack, and the generator -// is likely to persist beyond that stack frame. -template -class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { - public: - template - ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) - : container_(begin, end) {} - virtual ~ValuesInIteratorRangeGenerator() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, container_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, container_.end()); - } - - private: - typedef typename ::std::vector ContainerType; - - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - typename ContainerType::const_iterator iterator) - : base_(base), iterator_(iterator) {} - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - virtual void Advance() { - ++iterator_; - value_.reset(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - // We need to use cached value referenced by iterator_ because *iterator_ - // can return a temporary object (and of type other then T), so just - // having "return &*iterator_;" doesn't work. - // value_ is updated here and not in Advance() because Advance() - // can advance iterator_ beyond the end of the range, and we cannot - // detect that fact. The client code, on the other hand, is - // responsible for not calling Current() on an out-of-range iterator. - virtual const T* Current() const { - if (value_.get() == NULL) - value_.reset(new T(*iterator_)); - return value_.get(); - } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - return iterator_ == - CheckedDowncastToActualType(&other)->iterator_; - } - - private: - Iterator(const Iterator& other) - // The explicit constructor call suppresses a false warning - // emitted by gcc when supplied with the -Wextra option. - : ParamIteratorInterface(), - base_(other.base_), - iterator_(other.iterator_) {} - - const ParamGeneratorInterface* const base_; - typename ContainerType::const_iterator iterator_; - // A cached value of *iterator_. We keep it here to allow access by - // pointer in the wrapping iterator's operator->(). - // value_ needs to be mutable to be accessed in Current(). - // Use of scoped_ptr helps manage cached value's lifetime, - // which is bound by the lifespan of the iterator itself. - mutable scoped_ptr value_; - }; // class ValuesInIteratorRangeGenerator::Iterator - - // No implementation - assignment is unsupported. - void operator=(const ValuesInIteratorRangeGenerator& other); - - const ContainerType container_; -}; // class ValuesInIteratorRangeGenerator - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Stores a parameter value and later creates tests parameterized with that -// value. -template -class ParameterizedTestFactory : public TestFactoryBase { - public: - typedef typename TestClass::ParamType ParamType; - explicit ParameterizedTestFactory(ParamType parameter) : - parameter_(parameter) {} - virtual Test* CreateTest() { - TestClass::SetParam(¶meter_); - return new TestClass(); - } - - private: - const ParamType parameter_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory); -}; - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// TestMetaFactoryBase is a base class for meta-factories that create -// test factories for passing into MakeAndRegisterTestInfo function. -template -class TestMetaFactoryBase { - public: - virtual ~TestMetaFactoryBase() {} - - virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0; -}; - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// TestMetaFactory creates test factories for passing into -// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives -// ownership of test factory pointer, same factory object cannot be passed -// into that method twice. But ParameterizedTestCaseInfo is going to call -// it for each Test/Parameter value combination. Thus it needs meta factory -// creator class. -template -class TestMetaFactory - : public TestMetaFactoryBase { - public: - typedef typename TestCase::ParamType ParamType; - - TestMetaFactory() {} - - virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { - return new ParameterizedTestFactory(parameter); - } - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory); -}; - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// ParameterizedTestCaseInfoBase is a generic interface -// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase -// accumulates test information provided by TEST_P macro invocations -// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations -// and uses that information to register all resulting test instances -// in RegisterTests method. The ParameterizeTestCaseRegistry class holds -// a collection of pointers to the ParameterizedTestCaseInfo objects -// and calls RegisterTests() on each of them when asked. -class ParameterizedTestCaseInfoBase { - public: - virtual ~ParameterizedTestCaseInfoBase() {} - - // Base part of test case name for display purposes. - virtual const string& GetTestCaseName() const = 0; - // Test case id to verify identity. - virtual TypeId GetTestCaseTypeId() const = 0; - // UnitTest class invokes this method to register tests in this - // test case right before running them in RUN_ALL_TESTS macro. - // This method should not be called more then once on any single - // instance of a ParameterizedTestCaseInfoBase derived class. - virtual void RegisterTests() = 0; - - protected: - ParameterizedTestCaseInfoBase() {} - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase); -}; - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P -// macro invocations for a particular test case and generators -// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that -// test case. It registers tests with all values generated by all -// generators when asked. -template -class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { - public: - // ParamType and GeneratorCreationFunc are private types but are required - // for declarations of public methods AddTestPattern() and - // AddTestCaseInstantiation(). - typedef typename TestCase::ParamType ParamType; - // A function that returns an instance of appropriate generator type. - typedef ParamGenerator(GeneratorCreationFunc)(); - - explicit ParameterizedTestCaseInfo(const char* name) - : test_case_name_(name) {} - - // Test case base name for display purposes. - virtual const string& GetTestCaseName() const { return test_case_name_; } - // Test case id to verify identity. - virtual TypeId GetTestCaseTypeId() const { return GetTypeId(); } - // TEST_P macro uses AddTestPattern() to record information - // about a single test in a LocalTestInfo structure. - // test_case_name is the base name of the test case (without invocation - // prefix). test_base_name is the name of an individual test without - // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is - // test case base name and DoBar is test base name. - void AddTestPattern(const char* test_case_name, - const char* test_base_name, - TestMetaFactoryBase* meta_factory) { - tests_.push_back(linked_ptr(new TestInfo(test_case_name, - test_base_name, - meta_factory))); - } - // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information - // about a generator. - int AddTestCaseInstantiation(const string& instantiation_name, - GeneratorCreationFunc* func, - const char* /* file */, - int /* line */) { - instantiations_.push_back(::std::make_pair(instantiation_name, func)); - return 0; // Return value used only to run this method in namespace scope. - } - // UnitTest class invokes this method to register tests in this test case - // test cases right before running tests in RUN_ALL_TESTS macro. - // This method should not be called more then once on any single - // instance of a ParameterizedTestCaseInfoBase derived class. - // UnitTest has a guard to prevent from calling this method more then once. - virtual void RegisterTests() { - for (typename TestInfoContainer::iterator test_it = tests_.begin(); - test_it != tests_.end(); ++test_it) { - linked_ptr test_info = *test_it; - for (typename InstantiationContainer::iterator gen_it = - instantiations_.begin(); gen_it != instantiations_.end(); - ++gen_it) { - const string& instantiation_name = gen_it->first; - ParamGenerator generator((*gen_it->second)()); - - string test_case_name; - if ( !instantiation_name.empty() ) - test_case_name = instantiation_name + "/"; - test_case_name += test_info->test_case_base_name; - - int i = 0; - for (typename ParamGenerator::iterator param_it = - generator.begin(); - param_it != generator.end(); ++param_it, ++i) { - Message test_name_stream; - test_name_stream << test_info->test_base_name << "/" << i; - MakeAndRegisterTestInfo( - test_case_name.c_str(), - test_name_stream.GetString().c_str(), - NULL, // No type parameter. - PrintToString(*param_it).c_str(), - GetTestCaseTypeId(), - TestCase::SetUpTestCase, - TestCase::TearDownTestCase, - test_info->test_meta_factory->CreateTestFactory(*param_it)); - } // for param_it - } // for gen_it - } // for test_it - } // RegisterTests - - private: - // LocalTestInfo structure keeps information about a single test registered - // with TEST_P macro. - struct TestInfo { - TestInfo(const char* a_test_case_base_name, - const char* a_test_base_name, - TestMetaFactoryBase* a_test_meta_factory) : - test_case_base_name(a_test_case_base_name), - test_base_name(a_test_base_name), - test_meta_factory(a_test_meta_factory) {} - - const string test_case_base_name; - const string test_base_name; - const scoped_ptr > test_meta_factory; - }; - typedef ::std::vector > TestInfoContainer; - // Keeps pairs of - // received from INSTANTIATE_TEST_CASE_P macros. - typedef ::std::vector > - InstantiationContainer; - - const string test_case_name_; - TestInfoContainer tests_; - InstantiationContainer instantiations_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo); -}; // class ParameterizedTestCaseInfo - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase -// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P -// macros use it to locate their corresponding ParameterizedTestCaseInfo -// descriptors. -class ParameterizedTestCaseRegistry { - public: - ParameterizedTestCaseRegistry() {} - ~ParameterizedTestCaseRegistry() { - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - delete *it; - } - } - - // Looks up or creates and returns a structure containing information about - // tests and instantiations of a particular test case. - template - ParameterizedTestCaseInfo* GetTestCasePatternHolder( - const char* test_case_name, - const char* file, - int line) { - ParameterizedTestCaseInfo* typed_test_info = NULL; - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - if ((*it)->GetTestCaseName() == test_case_name) { - if ((*it)->GetTestCaseTypeId() != GetTypeId()) { - // Complain about incorrect usage of Google Test facilities - // and terminate the program since we cannot guaranty correct - // test case setup and tear-down in this case. - ReportInvalidTestCaseType(test_case_name, file, line); - posix::Abort(); - } else { - // At this point we are sure that the object we found is of the same - // type we are looking for, so we downcast it to that type - // without further checks. - typed_test_info = CheckedDowncastToActualType< - ParameterizedTestCaseInfo >(*it); - } - break; - } - } - if (typed_test_info == NULL) { - typed_test_info = new ParameterizedTestCaseInfo(test_case_name); - test_case_infos_.push_back(typed_test_info); - } - return typed_test_info; - } - void RegisterTests() { - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - (*it)->RegisterTests(); - } - } - - private: - typedef ::std::vector TestCaseInfoContainer; - - TestCaseInfoContainer test_case_infos_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry); -}; - -} // namespace internal -} // namespace testing - -#endif // GTEST_HAS_PARAM_TEST - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ \ No newline at end of file diff --git a/src/gtest/include/gtest/internal/gtest-port.h b/src/gtest/include/gtest/internal/gtest-port.h deleted file mode 100644 index 2a5fd30d..00000000 --- a/src/gtest/include/gtest/internal/gtest-port.h +++ /dev/null @@ -1,2495 +0,0 @@ -// Copyright 2005 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// -// -// Low-level types and utilities for porting Google Test to various -// platforms. All macros ending with _ and symbols defined in an -// internal namespace are subject to change without notice. Code -// outside Google Test MUST NOT USE THEM DIRECTLY. Macros that don't -// end with _ are part of Google Test's public API and can be used by -// code outside Google Test. -// -// This file is fundamental to Google Test. All other Google Test source -// files are expected to #include this. Therefore, it cannot #include -// any other Google Test header. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ - -// Environment-describing macros -// ----------------------------- -// -// Google Test can be used in many different environments. Macros in -// this section tell Google Test what kind of environment it is being -// used in, such that Google Test can provide environment-specific -// features and implementations. -// -// Google Test tries to automatically detect the properties of its -// environment, so users usually don't need to worry about these -// macros. However, the automatic detection is not perfect. -// Sometimes it's necessary for a user to define some of the following -// macros in the build script to override Google Test's decisions. -// -// If the user doesn't define a macro in the list, Google Test will -// provide a default definition. After this header is #included, all -// macros in this list will be defined to either 1 or 0. -// -// Notes to maintainers: -// - Each macro here is a user-tweakable knob; do not grow the list -// lightly. -// - Use #if to key off these macros. Don't use #ifdef or "#if -// defined(...)", which will not work as these macros are ALWAYS -// defined. -// -// GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) -// is/isn't available. -// GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions -// are enabled. -// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string -// is/isn't available (some systems define -// ::string, which is different to std::string). -// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string -// is/isn't available (some systems define -// ::wstring, which is different to std::wstring). -// GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular -// expressions are/aren't available. -// GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that -// is/isn't available. -// GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't -// enabled. -// GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that -// std::wstring does/doesn't work (Google Test can -// be used where std::wstring is unavailable). -// GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple -// is/isn't available. -// GTEST_HAS_SEH - Define it to 1/0 to indicate whether the -// compiler supports Microsoft's "Structured -// Exception Handling". -// GTEST_HAS_STREAM_REDIRECTION -// - Define it to 1/0 to indicate whether the -// platform supports I/O stream redirection using -// dup() and dup2(). -// GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google -// Test's own tr1 tuple implementation should be -// used. Unused when the user sets -// GTEST_HAS_TR1_TUPLE to 0. -// GTEST_LANG_CXX11 - Define it to 1/0 to indicate that Google Test -// is building in C++11/C++98 mode. -// GTEST_LINKED_AS_SHARED_LIBRARY -// - Define to 1 when compiling tests that use -// Google Test as a shared library (known as -// DLL on Windows). -// GTEST_CREATE_SHARED_LIBRARY -// - Define to 1 when compiling Google Test itself -// as a shared library. - -// Platform-indicating macros -// -------------------------- -// -// Macros indicating the platform on which Google Test is being used -// (a macro is defined to 1 if compiled on the given platform; -// otherwise UNDEFINED -- it's never defined to 0.). Google Test -// defines these macros automatically. Code outside Google Test MUST -// NOT define them. -// -// GTEST_OS_AIX - IBM AIX -// GTEST_OS_CYGWIN - Cygwin -// GTEST_OS_FREEBSD - FreeBSD -// GTEST_OS_HPUX - HP-UX -// GTEST_OS_LINUX - Linux -// GTEST_OS_LINUX_ANDROID - Google Android -// GTEST_OS_MAC - Mac OS X -// GTEST_OS_IOS - iOS -// GTEST___nacl__ - Google Native Client (NaCl) -// GTEST_OS_OPENBSD - OpenBSD -// GTEST_OS_QNX - QNX -// GTEST_OS_SOLARIS - Sun Solaris -// GTEST_OS_SYMBIAN - Symbian -// GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) -// GTEST_OS_WINDOWS_DESKTOP - Windows Desktop -// GTEST_OS_WINDOWS_MINGW - MinGW -// GTEST_OS_WINDOWS_MOBILE - Windows Mobile -// GTEST_OS_WINDOWS_PHONE - Windows Phone -// GTEST_OS_WINDOWS_RT - Windows Store App/WinRT -// GTEST_OS_ZOS - z/OS -// -// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the -// most stable support. Since core members of the Google Test project -// don't have access to other platforms, support for them may be less -// stable. If you notice any problems on your platform, please notify -// googletestframework@googlegroups.com (patches for fixing them are -// even more welcome!). -// -// It is possible that none of the GTEST_OS_* macros are defined. - -// Feature-indicating macros -// ------------------------- -// -// Macros indicating which Google Test features are available (a macro -// is defined to 1 if the corresponding feature is supported; -// otherwise UNDEFINED -- it's never defined to 0.). Google Test -// defines these macros automatically. Code outside Google Test MUST -// NOT define them. -// -// These macros are public so that portable tests can be written. -// Such tests typically surround code using a feature with an #if -// which controls that code. For example: -// -// #if GTEST_HAS_DEATH_TEST -// EXPECT_DEATH(DoSomethingDeadly()); -// #endif -// -// GTEST_HAS_COMBINE - the Combine() function (for value-parameterized -// tests) -// GTEST_HAS_DEATH_TEST - death tests -// GTEST_HAS_PARAM_TEST - value-parameterized tests -// GTEST_HAS_TYPED_TEST - typed tests -// GTEST_HAS_TYPED_TEST_P - type-parameterized tests -// GTEST_IS_THREADSAFE - Google Test is thread-safe. -// GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with -// GTEST_HAS_POSIX_RE (see above) which users can -// define themselves. -// GTEST_USES_SIMPLE_RE - our own simple regex is used; -// the above two are mutually exclusive. -// GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). - -// Misc public macros -// ------------------ -// -// GTEST_FLAG(flag_name) - references the variable corresponding to -// the given Google Test flag. - -// Internal utilities -// ------------------ -// -// The following macros and utilities are for Google Test's INTERNAL -// use only. Code outside Google Test MUST NOT USE THEM DIRECTLY. -// -// Macros for basic C++ coding: -// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. -// GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a -// variable don't have to be used. -// GTEST_DISALLOW_ASSIGN_ - disables operator=. -// GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. -// GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. -// GTEST_INTENTIONAL_CONST_COND_PUSH_ - start code section where MSVC C4127 is -// suppressed (constant conditional). -// GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127 -// is suppressed. -// -// C++11 feature wrappers: -// -// testing::internal::move - portability wrapper for std::move. -// -// Synchronization: -// Mutex, MutexLock, ThreadLocal, GetThreadCount() -// - synchronization primitives. -// -// Template meta programming: -// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. -// IteratorTraits - partial implementation of std::iterator_traits, which -// is not available in libCstd when compiled with Sun C++. -// -// Smart pointers: -// scoped_ptr - as in TR2. -// -// Regular expressions: -// RE - a simple regular expression class using the POSIX -// Extended Regular Expression syntax on UNIX-like -// platforms, or a reduced regular exception syntax on -// other platforms, including Windows. -// -// Logging: -// GTEST_LOG_() - logs messages at the specified severity level. -// LogToStderr() - directs all log messages to stderr. -// FlushInfoLog() - flushes informational log messages. -// -// Stdout and stderr capturing: -// CaptureStdout() - starts capturing stdout. -// GetCapturedStdout() - stops capturing stdout and returns the captured -// string. -// CaptureStderr() - starts capturing stderr. -// GetCapturedStderr() - stops capturing stderr and returns the captured -// string. -// -// Integer types: -// TypeWithSize - maps an integer to a int type. -// Int32, UInt32, Int64, UInt64, TimeInMillis -// - integers of known sizes. -// BiggestInt - the biggest signed integer type. -// -// Command-line utilities: -// GTEST_DECLARE_*() - declares a flag. -// GTEST_DEFINE_*() - defines a flag. -// GetInjectableArgvs() - returns the command line as a vector of strings. -// -// Environment variable utilities: -// GetEnv() - gets the value of an environment variable. -// BoolFromGTestEnv() - parses a bool environment variable. -// Int32FromGTestEnv() - parses an Int32 environment variable. -// StringFromGTestEnv() - parses a string environment variable. - -#include // for isspace, etc -#include // for ptrdiff_t -#include -#include -#include -#ifndef _WIN32_WCE -# include -# include -#endif // !_WIN32_WCE - -#if defined __APPLE__ -# include -# include -#endif - -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include - -#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" -#define GTEST_FLAG_PREFIX_ "gtest_" -#define GTEST_FLAG_PREFIX_DASH_ "gtest-" -#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" -#define GTEST_NAME_ "Google Test" -#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" - -// Determines the version of gcc that is used to compile this. -#ifdef __GNUC__ -// 40302 means version 4.3.2. -# define GTEST_GCC_VER_ \ - (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) -#endif // __GNUC__ - -// Determines the platform on which Google Test is compiled. -#ifdef __CYGWIN__ -# define GTEST_OS_CYGWIN 1 -#elif defined __SYMBIAN32__ -# define GTEST_OS_SYMBIAN 1 -#elif defined _WIN32 -# define GTEST_OS_WINDOWS 1 -# ifdef _WIN32_WCE -# define GTEST_OS_WINDOWS_MOBILE 1 -# elif defined(__MINGW__) || defined(__MINGW32__) -# define GTEST_OS_WINDOWS_MINGW 1 -# elif defined(WINAPI_FAMILY) -# include -# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -# define GTEST_OS_WINDOWS_DESKTOP 1 -# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) -# define GTEST_OS_WINDOWS_PHONE 1 -# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) -# define GTEST_OS_WINDOWS_RT 1 -# else - // WINAPI_FAMILY defined but no known partition matched. - // Default to desktop. -# define GTEST_OS_WINDOWS_DESKTOP 1 -# endif -# else -# define GTEST_OS_WINDOWS_DESKTOP 1 -# endif // _WIN32_WCE -#elif defined __APPLE__ -# define GTEST_OS_MAC 1 -# if TARGET_OS_IPHONE -# define GTEST_OS_IOS 1 -# endif -#elif defined __FreeBSD__ -# define GTEST_OS_FREEBSD 1 -#elif defined __linux__ -# define GTEST_OS_LINUX 1 -# if defined __ANDROID__ -# define GTEST_OS_LINUX_ANDROID 1 -# endif -#elif defined __MVS__ -# define GTEST_OS_ZOS 1 -#elif defined(__sun) && defined(__SVR4) -# define GTEST_OS_SOLARIS 1 -#elif defined(_AIX) -# define GTEST_OS_AIX 1 -#elif defined(__hpux) -# define GTEST_OS_HPUX 1 -#elif defined __native_client__ -# define GTEST___nacl__ 1 -#elif defined __OpenBSD__ -# define GTEST_OS_OPENBSD 1 -#elif defined __QNX__ -# define GTEST_OS_QNX 1 -#endif // __CYGWIN__ - -// Macros for disabling Microsoft Visual C++ warnings. -// -// GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 4385) -// /* code that triggers warnings C4800 and C4385 */ -// GTEST_DISABLE_MSC_WARNINGS_POP_() -#if _MSC_VER >= 1500 -# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) \ - __pragma(warning(push)) \ - __pragma(warning(disable: warnings)) -# define GTEST_DISABLE_MSC_WARNINGS_POP_() \ - __pragma(warning(pop)) -#else -// Older versions of MSVC don't have __pragma. -# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) -# define GTEST_DISABLE_MSC_WARNINGS_POP_() -#endif - -#ifndef GTEST_LANG_CXX11 -// gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when -// -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a -// value for __cplusplus, and recent versions of clang, gcc, and -// probably other compilers set that too in C++11 mode. -# if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L -// Compiling in at least C++11 mode. -# define GTEST_LANG_CXX11 1 -# else -# define GTEST_LANG_CXX11 0 -# endif -#endif - -// Distinct from C++11 language support, some environments don't provide -// proper C++11 library support. Notably, it's possible to build in -// C++11 mode when targeting Mac OS X 10.6, which has an old libstdc++ -// with no C++11 support. -// -// libstdc++ has sufficient C++11 support as of GCC 4.6.0, __GLIBCXX__ -// 20110325, but maintenance releases in the 4.4 and 4.5 series followed -// this date, so check for those versions by their date stamps. -// https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html#abi.versioning -#if GTEST_LANG_CXX11 && \ - (!defined(__GLIBCXX__) || ( \ - __GLIBCXX__ >= 20110325ul && /* GCC >= 4.6.0 */ \ - /* Blacklist of patch releases of older branches: */ \ - __GLIBCXX__ != 20110416ul && /* GCC 4.4.6 */ \ - __GLIBCXX__ != 20120313ul && /* GCC 4.4.7 */ \ - __GLIBCXX__ != 20110428ul && /* GCC 4.5.3 */ \ - __GLIBCXX__ != 20120702ul)) /* GCC 4.5.4 */ -# define GTEST_STDLIB_CXX11 1 -#endif - -// Only use C++11 library features if the library provides them. -#if GTEST_STDLIB_CXX11 -# define GTEST_HAS_STD_BEGIN_AND_END_ 1 -# define GTEST_HAS_STD_FORWARD_LIST_ 1 -# define GTEST_HAS_STD_FUNCTION_ 1 -# define GTEST_HAS_STD_INITIALIZER_LIST_ 1 -# define GTEST_HAS_STD_MOVE_ 1 -# define GTEST_HAS_STD_UNIQUE_PTR_ 1 -#endif - -// C++11 specifies that provides std::tuple. -// Some platforms still might not have it, however. -#if GTEST_LANG_CXX11 -# define GTEST_HAS_STD_TUPLE_ 1 -# if defined(__clang__) -// Inspired by http://clang.llvm.org/docs/LanguageExtensions.html#__has_include -# if defined(__has_include) && !__has_include() -# undef GTEST_HAS_STD_TUPLE_ -# endif -# elif defined(_MSC_VER) -// Inspired by boost/config/stdlib/dinkumware.hpp -# if defined(_CPPLIB_VER) && _CPPLIB_VER < 520 -# undef GTEST_HAS_STD_TUPLE_ -# endif -# elif defined(__GLIBCXX__) -// Inspired by boost/config/stdlib/libstdcpp3.hpp, -// http://gcc.gnu.org/gcc-4.2/changes.html and -// http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt01ch01.html#manual.intro.status.standard.200x -# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2) -# undef GTEST_HAS_STD_TUPLE_ -# endif -# endif -#endif - -// Brings in definitions for functions used in the testing::internal::posix -// namespace (read, write, close, chdir, isatty, stat). We do not currently -// use them on Windows Mobile. -#if GTEST_OS_WINDOWS -# if !GTEST_OS_WINDOWS_MOBILE -# include -# include -# endif -// In order to avoid having to include , use forward declaration -// assuming CRITICAL_SECTION is a typedef of _RTL_CRITICAL_SECTION. -// This assumption is verified by -// WindowsTypesTest.CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION. -struct _RTL_CRITICAL_SECTION; -#else -// This assumes that non-Windows OSes provide unistd.h. For OSes where this -// is not the case, we need to include headers that provide the functions -// mentioned above. -# include -# include -#endif // GTEST_OS_WINDOWS - -#if GTEST_OS_LINUX_ANDROID -// Used to define __ANDROID_API__ matching the target NDK API level. -# include // NOLINT -#endif - -// Defines this to true iff Google Test can use POSIX regular expressions. -#ifndef GTEST_HAS_POSIX_RE -# if GTEST_OS_LINUX_ANDROID -// On Android, is only available starting with Gingerbread. -# define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9) -# else -# define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS) -# endif -#endif - -#if GTEST_HAS_POSIX_RE - -// On some platforms, needs someone to define size_t, and -// won't compile otherwise. We can #include it here as we already -// included , which is guaranteed to define size_t through -// . -# include // NOLINT - -# define GTEST_USES_POSIX_RE 1 - -#elif GTEST_OS_WINDOWS - -// is not available on Windows. Use our own simple regex -// implementation instead. -# define GTEST_USES_SIMPLE_RE 1 - -#else - -// may not be available on this platform. Use our own -// simple regex implementation instead. -# define GTEST_USES_SIMPLE_RE 1 - -#endif // GTEST_HAS_POSIX_RE - -#ifndef GTEST_HAS_EXCEPTIONS -// The user didn't tell us whether exceptions are enabled, so we need -// to figure it out. -# if defined(_MSC_VER) || defined(__BORLANDC__) -// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS -// macro to enable exceptions, so we'll do the same. -// Assumes that exceptions are enabled by default. -# ifndef _HAS_EXCEPTIONS -# define _HAS_EXCEPTIONS 1 -# endif // _HAS_EXCEPTIONS -# define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS -# elif defined(__clang__) -// clang defines __EXCEPTIONS iff exceptions are enabled before clang 220714, -// but iff cleanups are enabled after that. In Obj-C++ files, there can be -// cleanups for ObjC exceptions which also need cleanups, even if C++ exceptions -// are disabled. clang has __has_feature(cxx_exceptions) which checks for C++ -// exceptions starting at clang r206352, but which checked for cleanups prior to -// that. To reliably check for C++ exception availability with clang, check for -// __EXCEPTIONS && __has_feature(cxx_exceptions). -# define GTEST_HAS_EXCEPTIONS (__EXCEPTIONS && __has_feature(cxx_exceptions)) -# elif defined(__GNUC__) && __EXCEPTIONS -// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. -# define GTEST_HAS_EXCEPTIONS 1 -# elif defined(__SUNPRO_CC) -// Sun Pro CC supports exceptions. However, there is no compile-time way of -// detecting whether they are enabled or not. Therefore, we assume that -// they are enabled unless the user tells us otherwise. -# define GTEST_HAS_EXCEPTIONS 1 -# elif defined(__IBMCPP__) && __EXCEPTIONS -// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. -# define GTEST_HAS_EXCEPTIONS 1 -# elif defined(__HP_aCC) -// Exception handling is in effect by default in HP aCC compiler. It has to -// be turned of by +noeh compiler option if desired. -# define GTEST_HAS_EXCEPTIONS 1 -# else -// For other compilers, we assume exceptions are disabled to be -// conservative. -# define GTEST_HAS_EXCEPTIONS 0 -# endif // defined(_MSC_VER) || defined(__BORLANDC__) -#endif // GTEST_HAS_EXCEPTIONS - -#if !defined(GTEST_HAS_STD_STRING) -// Even though we don't use this macro any longer, we keep it in case -// some clients still depend on it. -# define GTEST_HAS_STD_STRING 1 -#elif !GTEST_HAS_STD_STRING -// The user told us that ::std::string isn't available. -# error "Google Test cannot be used where ::std::string isn't available." -#endif // !defined(GTEST_HAS_STD_STRING) - -#ifndef GTEST_HAS_GLOBAL_STRING -// The user didn't tell us whether ::string is available, so we need -// to figure it out. - -# define GTEST_HAS_GLOBAL_STRING 0 - -#endif // GTEST_HAS_GLOBAL_STRING - -#ifndef GTEST_HAS_STD_WSTRING -// The user didn't tell us whether ::std::wstring is available, so we need -// to figure it out. -// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring -// is available. - -// Cygwin 1.7 and below doesn't support ::std::wstring. -// Solaris' libc++ doesn't support it either. Android has -// no support for it at least as recent as Froyo (2.2). -# define GTEST_HAS_STD_WSTRING \ - (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS)) - -#endif // GTEST_HAS_STD_WSTRING - -#ifndef GTEST_HAS_GLOBAL_WSTRING -// The user didn't tell us whether ::wstring is available, so we need -// to figure it out. -# define GTEST_HAS_GLOBAL_WSTRING \ - (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING) -#endif // GTEST_HAS_GLOBAL_WSTRING - -// Determines whether RTTI is available. -#ifndef GTEST_HAS_RTTI -// The user didn't tell us whether RTTI is enabled, so we need to -// figure it out. - -# ifdef _MSC_VER - -# ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled. -# define GTEST_HAS_RTTI 1 -# else -# define GTEST_HAS_RTTI 0 -# endif - -// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled. -# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) - -# ifdef __GXX_RTTI -// When building against STLport with the Android NDK and with -// -frtti -fno-exceptions, the build fails at link time with undefined -// references to __cxa_bad_typeid. Note sure if STL or toolchain bug, -// so disable RTTI when detected. -# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && \ - !defined(__EXCEPTIONS) -# define GTEST_HAS_RTTI 0 -# else -# define GTEST_HAS_RTTI 1 -# endif // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS -# else -# define GTEST_HAS_RTTI 0 -# endif // __GXX_RTTI - -// Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends -// using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the -// first version with C++ support. -# elif defined(__clang__) - -# define GTEST_HAS_RTTI __has_feature(cxx_rtti) - -// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if -// both the typeid and dynamic_cast features are present. -# elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) - -# ifdef __RTTI_ALL__ -# define GTEST_HAS_RTTI 1 -# else -# define GTEST_HAS_RTTI 0 -# endif - -# else - -// For all other compilers, we assume RTTI is enabled. -# define GTEST_HAS_RTTI 1 - -# endif // _MSC_VER - -#endif // GTEST_HAS_RTTI - -// It's this header's responsibility to #include when RTTI -// is enabled. -#if GTEST_HAS_RTTI -# include -#endif - -// Determines whether Google Test can use the pthreads library. -#ifndef GTEST_HAS_PTHREAD -// The user didn't tell us explicitly, so we make reasonable assumptions about -// which platforms have pthreads support. -// -// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 -// to your compiler flags. -# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \ - || GTEST_OS_QNX || GTEST_OS_FREEBSD || GTEST___nacl__) -#endif // GTEST_HAS_PTHREAD - -#if GTEST_HAS_PTHREAD -// gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is -// true. -# include // NOLINT - -// For timespec and nanosleep, used below. -# include // NOLINT -#endif - -// Determines whether Google Test can use tr1/tuple. You can define -// this macro to 0 to prevent Google Test from using tuple (any -// feature depending on tuple with be disabled in this mode). -#ifndef GTEST_HAS_TR1_TUPLE -# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) -// STLport, provided with the Android NDK, has neither or . -# define GTEST_HAS_TR1_TUPLE 0 -# else -// The user didn't tell us not to do it, so we assume it's OK. -# define GTEST_HAS_TR1_TUPLE 1 -# endif -#endif // GTEST_HAS_TR1_TUPLE - -// Determines whether Google Test's own tr1 tuple implementation -// should be used. -#ifndef GTEST_USE_OWN_TR1_TUPLE -// The user didn't tell us, so we need to figure it out. - -// We use our own TR1 tuple if we aren't sure the user has an -// implementation of it already. At this time, libstdc++ 4.0.0+ and -// MSVC 2010 are the only mainstream standard libraries that come -// with a TR1 tuple implementation. NVIDIA's CUDA NVCC compiler -// pretends to be GCC by defining __GNUC__ and friends, but cannot -// compile GCC's tuple implementation. MSVC 2008 (9.0) provides TR1 -// tuple in a 323 MB Feature Pack download, which we cannot assume the -// user has. QNX's QCC compiler is a modified GCC but it doesn't -// support TR1 tuple. libc++ only provides std::tuple, in C++11 mode, -// and it can be used with some compilers that define __GNUC__. -# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \ - && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) || _MSC_VER >= 1600 -# define GTEST_ENV_HAS_TR1_TUPLE_ 1 -# endif - -// C++11 specifies that provides std::tuple. Use that if gtest is used -// in C++11 mode and libstdc++ isn't very old (binaries targeting OS X 10.6 -// can build with clang but need to use gcc4.2's libstdc++). -# if GTEST_LANG_CXX11 && (!defined(__GLIBCXX__) || __GLIBCXX__ > 20110325) -# define GTEST_ENV_HAS_STD_TUPLE_ 1 -# endif - -# if GTEST_ENV_HAS_TR1_TUPLE_ || GTEST_ENV_HAS_STD_TUPLE_ -# define GTEST_USE_OWN_TR1_TUPLE 0 -# else -# define GTEST_USE_OWN_TR1_TUPLE 1 -# endif - -#endif // GTEST_USE_OWN_TR1_TUPLE - -// To avoid conditional compilation everywhere, we make it -// gtest-port.h's responsibility to #include the header implementing -// tuple. -#if GTEST_HAS_STD_TUPLE_ -# include // IWYU pragma: export -# define GTEST_TUPLE_NAMESPACE_ ::std -#endif // GTEST_HAS_STD_TUPLE_ - -// We include tr1::tuple even if std::tuple is available to define printers for -// them. -#if GTEST_HAS_TR1_TUPLE -# ifndef GTEST_TUPLE_NAMESPACE_ -# define GTEST_TUPLE_NAMESPACE_ ::std::tr1 -# endif // GTEST_TUPLE_NAMESPACE_ - -# if GTEST_USE_OWN_TR1_TUPLE -# include "gtest/internal/gtest-tuple.h" // IWYU pragma: export // NOLINT -# elif GTEST_ENV_HAS_STD_TUPLE_ -# include -// C++11 puts its tuple into the ::std namespace rather than -// ::std::tr1. gtest expects tuple to live in ::std::tr1, so put it there. -// This causes undefined behavior, but supported compilers react in -// the way we intend. -namespace std { -namespace tr1 { -using ::std::get; -using ::std::make_tuple; -using ::std::tuple; -using ::std::tuple_element; -using ::std::tuple_size; -} -} - -# elif GTEST_OS_SYMBIAN - -// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to -// use STLport's tuple implementation, which unfortunately doesn't -// work as the copy of STLport distributed with Symbian is incomplete. -// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to -// use its own tuple implementation. -# ifdef BOOST_HAS_TR1_TUPLE -# undef BOOST_HAS_TR1_TUPLE -# endif // BOOST_HAS_TR1_TUPLE - -// This prevents , which defines -// BOOST_HAS_TR1_TUPLE, from being #included by Boost's . -# define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED -# include // IWYU pragma: export // NOLINT - -# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) -// GCC 4.0+ implements tr1/tuple in the header. This does -// not conform to the TR1 spec, which requires the header to be . - -# if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 -// Until version 4.3.2, gcc has a bug that causes , -// which is #included by , to not compile when RTTI is -// disabled. _TR1_FUNCTIONAL is the header guard for -// . Hence the following #define is a hack to prevent -// from being included. -# define _TR1_FUNCTIONAL 1 -# include -# undef _TR1_FUNCTIONAL // Allows the user to #include - // if he chooses to. -# else -# include // NOLINT -# endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 - -# else -// If the compiler is not GCC 4.0+, we assume the user is using a -// spec-conforming TR1 implementation. -# include // IWYU pragma: export // NOLINT -# endif // GTEST_USE_OWN_TR1_TUPLE - -#endif // GTEST_HAS_TR1_TUPLE - -// Determines whether clone(2) is supported. -// Usually it will only be available on Linux, excluding -// Linux on the Itanium architecture. -// Also see http://linux.die.net/man/2/clone. -#ifndef GTEST_HAS_CLONE -// The user didn't tell us, so we need to figure it out. - -# if GTEST_OS_LINUX && !defined(__ia64__) -# if GTEST_OS_LINUX_ANDROID -// On Android, clone() is only available on ARM starting with Gingerbread. -# if defined(__arm__) && __ANDROID_API__ >= 9 -# define GTEST_HAS_CLONE 1 -# else -# define GTEST_HAS_CLONE 0 -# endif -# else -# define GTEST_HAS_CLONE 1 -# endif -# else -# define GTEST_HAS_CLONE 0 -# endif // GTEST_OS_LINUX && !defined(__ia64__) - -#endif // GTEST_HAS_CLONE - -// Determines whether to support stream redirection. This is used to test -// output correctness and to implement death tests. -#ifndef GTEST_HAS_STREAM_REDIRECTION -// By default, we assume that stream redirection is supported on all -// platforms except known mobile ones. -# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || \ - GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT -# define GTEST_HAS_STREAM_REDIRECTION 0 -# else -# define GTEST_HAS_STREAM_REDIRECTION 1 -# endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN -#endif // GTEST_HAS_STREAM_REDIRECTION - -// Determines whether to support death tests. -// Google Test does not support death tests for VC 7.1 and earlier as -// abort() in a VC 7.1 application compiled as GUI in debug config -// pops up a dialog window that cannot be suppressed programmatically. -#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ - (GTEST_OS_MAC && !GTEST_OS_IOS) || \ - (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ - GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \ - GTEST_OS_OPENBSD || GTEST_OS_QNX || GTEST_OS_FREEBSD) -# define GTEST_HAS_DEATH_TEST 1 -# include // NOLINT -#endif - -// We don't support MSVC 7.1 with exceptions disabled now. Therefore -// all the compilers we care about are adequate for supporting -// value-parameterized tests. -#define GTEST_HAS_PARAM_TEST 1 - -// Determines whether to support type-driven tests. - -// Typed tests need and variadic macros, which GCC, VC++ 8.0, -// Sun Pro CC, IBM Visual Age, and HP aCC support. -#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ - defined(__IBMCPP__) || defined(__HP_aCC) -# define GTEST_HAS_TYPED_TEST 1 -# define GTEST_HAS_TYPED_TEST_P 1 -#endif - -// Determines whether to support Combine(). This only makes sense when -// value-parameterized tests are enabled. The implementation doesn't -// work on Sun Studio since it doesn't understand templated conversion -// operators. -#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) -# define GTEST_HAS_COMBINE 1 -#endif - -// Determines whether the system compiler uses UTF-16 for encoding wide strings. -#define GTEST_WIDE_STRING_USES_UTF16_ \ - (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX) - -// Determines whether test results can be streamed to a socket. -#if GTEST_OS_LINUX -# define GTEST_CAN_STREAM_RESULTS_ 1 -#endif - -// Defines some utility macros. - -// The GNU compiler emits a warning if nested "if" statements are followed by -// an "else" statement and braces are not used to explicitly disambiguate the -// "else" binding. This leads to problems with code like: -// -// if (gate) -// ASSERT_*(condition) << "Some message"; -// -// The "switch (0) case 0:" idiom is used to suppress this. -#ifdef __INTEL_COMPILER -# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ -#else -# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default: // NOLINT -#endif - -// Use this annotation at the end of a struct/class definition to -// prevent the compiler from optimizing away instances that are never -// used. This is useful when all interesting logic happens inside the -// c'tor and / or d'tor. Example: -// -// struct Foo { -// Foo() { ... } -// } GTEST_ATTRIBUTE_UNUSED_; -// -// Also use it after a variable or parameter declaration to tell the -// compiler the variable/parameter does not have to be used. -#if defined(__GNUC__) && !defined(__INTEL_COMPILER) -# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) -#elif defined(__clang__) -# if __has_attribute(unused) -# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) -# endif -#endif -#ifndef GTEST_ATTRIBUTE_UNUSED_ -# define GTEST_ATTRIBUTE_UNUSED_ -#endif - -// A macro to disallow operator= -// This should be used in the private: declarations for a class. -#define GTEST_DISALLOW_ASSIGN_(type)\ - void operator=(type const &) - -// A macro to disallow copy constructor and operator= -// This should be used in the private: declarations for a class. -#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ - type(type const &);\ - GTEST_DISALLOW_ASSIGN_(type) - -// Tell the compiler to warn about unused return values for functions declared -// with this macro. The macro should be used on function declarations -// following the argument list: -// -// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; -#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(__INTEL_COMPILER) -# define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) -#else -# define GTEST_MUST_USE_RESULT_ -#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !__INTEL_COMPILER - -// MS C++ compiler emits warning when a conditional expression is compile time -// constant. In some contexts this warning is false positive and needs to be -// suppressed. Use the following two macros in such cases: -// -// GTEST_INTENTIONAL_CONST_COND_PUSH_() -// while (true) { -// GTEST_INTENTIONAL_CONST_COND_POP_() -// } -# define GTEST_INTENTIONAL_CONST_COND_PUSH_() \ - GTEST_DISABLE_MSC_WARNINGS_PUSH_(4127) -# define GTEST_INTENTIONAL_CONST_COND_POP_() \ - GTEST_DISABLE_MSC_WARNINGS_POP_() - -// Determine whether the compiler supports Microsoft's Structured Exception -// Handling. This is supported by several Windows compilers but generally -// does not exist on any other system. -#ifndef GTEST_HAS_SEH -// The user didn't tell us, so we need to figure it out. - -# if defined(_MSC_VER) || defined(__BORLANDC__) -// These two compilers are known to support SEH. -# define GTEST_HAS_SEH 1 -# else -// Assume no SEH. -# define GTEST_HAS_SEH 0 -# endif - -#define GTEST_IS_THREADSAFE \ - (0 \ - || (GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT) \ - || GTEST_HAS_PTHREAD) - -#endif // GTEST_HAS_SEH - -#ifdef _MSC_VER - -# if GTEST_LINKED_AS_SHARED_LIBRARY -# define GTEST_API_ __declspec(dllimport) -# elif GTEST_CREATE_SHARED_LIBRARY -# define GTEST_API_ __declspec(dllexport) -# endif - -#endif // _MSC_VER - -#ifndef GTEST_API_ -# define GTEST_API_ -#endif - -#ifdef __GNUC__ -// Ask the compiler to never inline a given function. -# define GTEST_NO_INLINE_ __attribute__((noinline)) -#else -# define GTEST_NO_INLINE_ -#endif - -// _LIBCPP_VERSION is defined by the libc++ library from the LLVM project. -#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) -# define GTEST_HAS_CXXABI_H_ 1 -#else -# define GTEST_HAS_CXXABI_H_ 0 -#endif - -// A function level attribute to disable checking for use of uninitialized -// memory when built with MemorySanitizer. -#if defined(__clang__) -# if __has_feature(memory_sanitizer) -# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ \ - __attribute__((no_sanitize_memory)) -# else -# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ -# endif // __has_feature(memory_sanitizer) -#else -# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ -#endif // __clang__ - -// A function level attribute to disable AddressSanitizer instrumentation. -#if defined(__clang__) -# if __has_feature(address_sanitizer) -# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ \ - __attribute__((no_sanitize_address)) -# else -# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ -# endif // __has_feature(address_sanitizer) -#else -# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ -#endif // __clang__ - -// A function level attribute to disable ThreadSanitizer instrumentation. -#if defined(__clang__) -# if __has_feature(thread_sanitizer) -# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ \ - __attribute__((no_sanitize_thread)) -# else -# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ -# endif // __has_feature(thread_sanitizer) -#else -# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ -#endif // __clang__ - -namespace testing { - -class Message; - -#if defined(GTEST_TUPLE_NAMESPACE_) -// Import tuple and friends into the ::testing namespace. -// It is part of our interface, having them in ::testing allows us to change -// their types as needed. -using GTEST_TUPLE_NAMESPACE_::get; -using GTEST_TUPLE_NAMESPACE_::make_tuple; -using GTEST_TUPLE_NAMESPACE_::tuple; -using GTEST_TUPLE_NAMESPACE_::tuple_size; -using GTEST_TUPLE_NAMESPACE_::tuple_element; -#endif // defined(GTEST_TUPLE_NAMESPACE_) - -namespace internal { - -// A secret type that Google Test users don't know about. It has no -// definition on purpose. Therefore it's impossible to create a -// Secret object, which is what we want. -class Secret; - -// The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time -// expression is true. For example, you could use it to verify the -// size of a static array: -// -// GTEST_COMPILE_ASSERT_(GTEST_ARRAY_SIZE_(names) == NUM_NAMES, -// names_incorrect_size); -// -// or to make sure a struct is smaller than a certain size: -// -// GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large); -// -// The second argument to the macro is the name of the variable. If -// the expression is false, most compilers will issue a warning/error -// containing the name of the variable. - -#if GTEST_LANG_CXX11 -# define GTEST_COMPILE_ASSERT_(expr, msg) static_assert(expr, #msg) -#else // !GTEST_LANG_CXX11 -template - struct CompileAssert { -}; - -# define GTEST_COMPILE_ASSERT_(expr, msg) \ - typedef ::testing::internal::CompileAssert<(static_cast(expr))> \ - msg[static_cast(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_ -#endif // !GTEST_LANG_CXX11 - -// Implementation details of GTEST_COMPILE_ASSERT_: -// -// (In C++11, we simply use static_assert instead of the following) -// -// - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1 -// elements (and thus is invalid) when the expression is false. -// -// - The simpler definition -// -// #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1] -// -// does not work, as gcc supports variable-length arrays whose sizes -// are determined at run-time (this is gcc's extension and not part -// of the C++ standard). As a result, gcc fails to reject the -// following code with the simple definition: -// -// int foo; -// GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is -// // not a compile-time constant. -// -// - By using the type CompileAssert<(bool(expr))>, we ensures that -// expr is a compile-time constant. (Template arguments must be -// determined at compile-time.) -// -// - The outter parentheses in CompileAssert<(bool(expr))> are necessary -// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written -// -// CompileAssert -// -// instead, these compilers will refuse to compile -// -// GTEST_COMPILE_ASSERT_(5 > 0, some_message); -// -// (They seem to think the ">" in "5 > 0" marks the end of the -// template argument list.) -// -// - The array size is (bool(expr) ? 1 : -1), instead of simply -// -// ((expr) ? 1 : -1). -// -// This is to avoid running into a bug in MS VC 7.1, which -// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. - -// StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h. -// -// This template is declared, but intentionally undefined. -template -struct StaticAssertTypeEqHelper; - -template -struct StaticAssertTypeEqHelper { - enum { value = true }; -}; - -// Evaluates to the number of elements in 'array'. -#define GTEST_ARRAY_SIZE_(array) (sizeof(array) / sizeof(array[0])) - -#if GTEST_HAS_GLOBAL_STRING -typedef ::string string; -#else -typedef ::std::string string; -#endif // GTEST_HAS_GLOBAL_STRING - -#if GTEST_HAS_GLOBAL_WSTRING -typedef ::wstring wstring; -#elif GTEST_HAS_STD_WSTRING -typedef ::std::wstring wstring; -#endif // GTEST_HAS_GLOBAL_WSTRING - -// A helper for suppressing warnings on constant condition. It just -// returns 'condition'. -GTEST_API_ bool IsTrue(bool condition); - -// Defines scoped_ptr. - -// This implementation of scoped_ptr is PARTIAL - it only contains -// enough stuff to satisfy Google Test's need. -template -class scoped_ptr { - public: - typedef T element_type; - - explicit scoped_ptr(T* p = NULL) : ptr_(p) {} - ~scoped_ptr() { reset(); } - - T& operator*() const { return *ptr_; } - T* operator->() const { return ptr_; } - T* get() const { return ptr_; } - - T* release() { - T* const ptr = ptr_; - ptr_ = NULL; - return ptr; - } - - void reset(T* p = NULL) { - if (p != ptr_) { - if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type. - delete ptr_; - } - ptr_ = p; - } - } - - friend void swap(scoped_ptr& a, scoped_ptr& b) { - using std::swap; - swap(a.ptr_, b.ptr_); - } - - private: - T* ptr_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); -}; - -// Defines RE. - -// A simple C++ wrapper for . It uses the POSIX Extended -// Regular Expression syntax. -class GTEST_API_ RE { - public: - // A copy constructor is required by the Standard to initialize object - // references from r-values. - RE(const RE& other) { Init(other.pattern()); } - - // Constructs an RE from a string. - RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT - -#if GTEST_HAS_GLOBAL_STRING - - RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT - -#endif // GTEST_HAS_GLOBAL_STRING - - RE(const char* regex) { Init(regex); } // NOLINT - ~RE(); - - // Returns the string representation of the regex. - const char* pattern() const { return pattern_; } - - // FullMatch(str, re) returns true iff regular expression re matches - // the entire str. - // PartialMatch(str, re) returns true iff regular expression re - // matches a substring of str (including str itself). - // - // TODO(wan@google.com): make FullMatch() and PartialMatch() work - // when str contains NUL characters. - static bool FullMatch(const ::std::string& str, const RE& re) { - return FullMatch(str.c_str(), re); - } - static bool PartialMatch(const ::std::string& str, const RE& re) { - return PartialMatch(str.c_str(), re); - } - -#if GTEST_HAS_GLOBAL_STRING - - static bool FullMatch(const ::string& str, const RE& re) { - return FullMatch(str.c_str(), re); - } - static bool PartialMatch(const ::string& str, const RE& re) { - return PartialMatch(str.c_str(), re); - } - -#endif // GTEST_HAS_GLOBAL_STRING - - static bool FullMatch(const char* str, const RE& re); - static bool PartialMatch(const char* str, const RE& re); - - private: - void Init(const char* regex); - - // We use a const char* instead of an std::string, as Google Test used to be - // used where std::string is not available. TODO(wan@google.com): change to - // std::string. - const char* pattern_; - bool is_valid_; - -#if GTEST_USES_POSIX_RE - - regex_t full_regex_; // For FullMatch(). - regex_t partial_regex_; // For PartialMatch(). - -#else // GTEST_USES_SIMPLE_RE - - const char* full_pattern_; // For FullMatch(); - -#endif - - GTEST_DISALLOW_ASSIGN_(RE); -}; - -// Formats a source file path and a line number as they would appear -// in an error message from the compiler used to compile this code. -GTEST_API_ ::std::string FormatFileLocation(const char* file, int line); - -// Formats a file location for compiler-independent XML output. -// Although this function is not platform dependent, we put it next to -// FormatFileLocation in order to contrast the two functions. -GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file, - int line); - -// Defines logging utilities: -// GTEST_LOG_(severity) - logs messages at the specified severity level. The -// message itself is streamed into the macro. -// LogToStderr() - directs all log messages to stderr. -// FlushInfoLog() - flushes informational log messages. - -enum GTestLogSeverity { - GTEST_INFO, - GTEST_WARNING, - GTEST_ERROR, - GTEST_FATAL -}; - -// Formats log entry severity, provides a stream object for streaming the -// log message, and terminates the message with a newline when going out of -// scope. -class GTEST_API_ GTestLog { - public: - GTestLog(GTestLogSeverity severity, const char* file, int line); - - // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. - ~GTestLog(); - - ::std::ostream& GetStream() { return ::std::cerr; } - - private: - const GTestLogSeverity severity_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); -}; - -#define GTEST_LOG_(severity) \ - ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ - __FILE__, __LINE__).GetStream() - -inline void LogToStderr() {} -inline void FlushInfoLog() { fflush(NULL); } - -// INTERNAL IMPLEMENTATION - DO NOT USE. -// -// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition -// is not satisfied. -// Synopsys: -// GTEST_CHECK_(boolean_condition); -// or -// GTEST_CHECK_(boolean_condition) << "Additional message"; -// -// This checks the condition and if the condition is not satisfied -// it prints message about the condition violation, including the -// condition itself, plus additional message streamed into it, if any, -// and then it aborts the program. It aborts the program irrespective of -// whether it is built in the debug mode or not. -#define GTEST_CHECK_(condition) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::IsTrue(condition)) \ - ; \ - else \ - GTEST_LOG_(FATAL) << "Condition " #condition " failed. " - -// An all-mode assert to verify that the given POSIX-style function -// call returns 0 (indicating success). Known limitation: this -// doesn't expand to a balanced 'if' statement, so enclose the macro -// in {} if you need to use it as the only statement in an 'if' -// branch. -#define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \ - if (const int gtest_error = (posix_call)) \ - GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ - << gtest_error - -#if GTEST_HAS_STD_MOVE_ -using std::move; -#else // GTEST_HAS_STD_MOVE_ -template -const T& move(const T& t) { - return t; -} -#endif // GTEST_HAS_STD_MOVE_ - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Use ImplicitCast_ as a safe version of static_cast for upcasting in -// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a -// const Foo*). When you use ImplicitCast_, the compiler checks that -// the cast is safe. Such explicit ImplicitCast_s are necessary in -// surprisingly many situations where C++ demands an exact type match -// instead of an argument type convertable to a target type. -// -// The syntax for using ImplicitCast_ is the same as for static_cast: -// -// ImplicitCast_(expr) -// -// ImplicitCast_ would have been part of the C++ standard library, -// but the proposal was submitted too late. It will probably make -// its way into the language in the future. -// -// This relatively ugly name is intentional. It prevents clashes with -// similar functions users may have (e.g., implicit_cast). The internal -// namespace alone is not enough because the function can be found by ADL. -template -inline To ImplicitCast_(To x) { return ::testing::internal::move(x); } - -// When you upcast (that is, cast a pointer from type Foo to type -// SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts -// always succeed. When you downcast (that is, cast a pointer from -// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because -// how do you know the pointer is really of type SubclassOfFoo? It -// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, -// when you downcast, you should use this macro. In debug mode, we -// use dynamic_cast<> to double-check the downcast is legal (we die -// if it's not). In normal mode, we do the efficient static_cast<> -// instead. Thus, it's important to test in debug mode to make sure -// the cast is legal! -// This is the only place in the code we should use dynamic_cast<>. -// In particular, you SHOULDN'T be using dynamic_cast<> in order to -// do RTTI (eg code like this: -// if (dynamic_cast(foo)) HandleASubclass1Object(foo); -// if (dynamic_cast(foo)) HandleASubclass2Object(foo); -// You should design the code some other way not to need this. -// -// This relatively ugly name is intentional. It prevents clashes with -// similar functions users may have (e.g., down_cast). The internal -// namespace alone is not enough because the function can be found by ADL. -template // use like this: DownCast_(foo); -inline To DownCast_(From* f) { // so we only accept pointers - // Ensures that To is a sub-type of From *. This test is here only - // for compile-time type checking, and has no overhead in an - // optimized build at run-time, as it will be optimized away - // completely. - GTEST_INTENTIONAL_CONST_COND_PUSH_() - if (false) { - GTEST_INTENTIONAL_CONST_COND_POP_() - const To to = NULL; - ::testing::internal::ImplicitCast_(to); - } - -#if GTEST_HAS_RTTI - // RTTI: debug mode only! - GTEST_CHECK_(f == NULL || dynamic_cast(f) != NULL); -#endif - return static_cast(f); -} - -// Downcasts the pointer of type Base to Derived. -// Derived must be a subclass of Base. The parameter MUST -// point to a class of type Derived, not any subclass of it. -// When RTTI is available, the function performs a runtime -// check to enforce this. -template -Derived* CheckedDowncastToActualType(Base* base) { -#if GTEST_HAS_RTTI - GTEST_CHECK_(typeid(*base) == typeid(Derived)); - return dynamic_cast(base); // NOLINT -#else - return static_cast(base); // Poor man's downcast. -#endif -} - -#if GTEST_HAS_STREAM_REDIRECTION - -// Defines the stderr capturer: -// CaptureStdout - starts capturing stdout. -// GetCapturedStdout - stops capturing stdout and returns the captured string. -// CaptureStderr - starts capturing stderr. -// GetCapturedStderr - stops capturing stderr and returns the captured string. -// -GTEST_API_ void CaptureStdout(); -GTEST_API_ std::string GetCapturedStdout(); -GTEST_API_ void CaptureStderr(); -GTEST_API_ std::string GetCapturedStderr(); - -#endif // GTEST_HAS_STREAM_REDIRECTION - - -#if GTEST_HAS_DEATH_TEST - -const ::std::vector& GetInjectableArgvs(); -void SetInjectableArgvs(const ::std::vector* - new_argvs); - -// A copy of all command line arguments. Set by InitGoogleTest(). -extern ::std::vector g_argvs; - -#endif // GTEST_HAS_DEATH_TEST - -// Defines synchronization primitives. -#if GTEST_IS_THREADSAFE -# if GTEST_HAS_PTHREAD -// Sleeps for (roughly) n milliseconds. This function is only for testing -// Google Test's own constructs. Don't use it in user tests, either -// directly or indirectly. -inline void SleepMilliseconds(int n) { - const timespec time = { - 0, // 0 seconds. - n * 1000L * 1000L, // And n ms. - }; - nanosleep(&time, NULL); -} -# endif // GTEST_HAS_PTHREAD - -# if 0 // OS detection -# elif GTEST_HAS_PTHREAD -// Allows a controller thread to pause execution of newly created -// threads until notified. Instances of this class must be created -// and destroyed in the controller thread. -// -// This class is only for testing Google Test's own constructs. Do not -// use it in user tests, either directly or indirectly. -class Notification { - public: - Notification() : notified_(false) { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); - } - ~Notification() { - pthread_mutex_destroy(&mutex_); - } - - // Notifies all threads created with this notification to start. Must - // be called from the controller thread. - void Notify() { - pthread_mutex_lock(&mutex_); - notified_ = true; - pthread_mutex_unlock(&mutex_); - } - - // Blocks until the controller thread notifies. Must be called from a test - // thread. - void WaitForNotification() { - for (;;) { - pthread_mutex_lock(&mutex_); - const bool notified = notified_; - pthread_mutex_unlock(&mutex_); - if (notified) - break; - SleepMilliseconds(10); - } - } - - private: - pthread_mutex_t mutex_; - bool notified_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); -}; - -# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT - -GTEST_API_ void SleepMilliseconds(int n); - -// Provides leak-safe Windows kernel handle ownership. -// Used in death tests and in threading support. -class GTEST_API_ AutoHandle { - public: - // Assume that Win32 HANDLE type is equivalent to void*. Doing so allows us to - // avoid including in this header file. Including is - // undesirable because it defines a lot of symbols and macros that tend to - // conflict with client code. This assumption is verified by - // WindowsTypesTest.HANDLEIsVoidStar. - typedef void* Handle; - AutoHandle(); - explicit AutoHandle(Handle handle); - - ~AutoHandle(); - - Handle Get() const; - void Reset(); - void Reset(Handle handle); - - private: - // Returns true iff the handle is a valid handle object that can be closed. - bool IsCloseable() const; - - Handle handle_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); -}; - -// Allows a controller thread to pause execution of newly created -// threads until notified. Instances of this class must be created -// and destroyed in the controller thread. -// -// This class is only for testing Google Test's own constructs. Do not -// use it in user tests, either directly or indirectly. -class GTEST_API_ Notification { - public: - Notification(); - void Notify(); - void WaitForNotification(); - - private: - AutoHandle event_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); -}; -# endif // OS detection - -// On MinGW, we can have both GTEST_OS_WINDOWS and GTEST_HAS_PTHREAD -// defined, but we don't want to use MinGW's pthreads implementation, which -// has conformance problems with some versions of the POSIX standard. -# if GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW - -// As a C-function, ThreadFuncWithCLinkage cannot be templated itself. -// Consequently, it cannot select a correct instantiation of ThreadWithParam -// in order to call its Run(). Introducing ThreadWithParamBase as a -// non-templated base class for ThreadWithParam allows us to bypass this -// problem. -class ThreadWithParamBase { - public: - virtual ~ThreadWithParamBase() {} - virtual void Run() = 0; -}; - -// pthread_create() accepts a pointer to a function type with the C linkage. -// According to the Standard (7.5/1), function types with different linkages -// are different even if they are otherwise identical. Some compilers (for -// example, SunStudio) treat them as different types. Since class methods -// cannot be defined with C-linkage we need to define a free C-function to -// pass into pthread_create(). -extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { - static_cast(thread)->Run(); - return NULL; -} - -// Helper class for testing Google Test's multi-threading constructs. -// To use it, write: -// -// void ThreadFunc(int param) { /* Do things with param */ } -// Notification thread_can_start; -// ... -// // The thread_can_start parameter is optional; you can supply NULL. -// ThreadWithParam thread(&ThreadFunc, 5, &thread_can_start); -// thread_can_start.Notify(); -// -// These classes are only for testing Google Test's own constructs. Do -// not use them in user tests, either directly or indirectly. -template -class ThreadWithParam : public ThreadWithParamBase { - public: - typedef void UserThreadFunc(T); - - ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start) - : func_(func), - param_(param), - thread_can_start_(thread_can_start), - finished_(false) { - ThreadWithParamBase* const base = this; - // The thread can be created only after all fields except thread_ - // have been initialized. - GTEST_CHECK_POSIX_SUCCESS_( - pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); - } - ~ThreadWithParam() { Join(); } - - void Join() { - if (!finished_) { - GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); - finished_ = true; - } - } - - virtual void Run() { - if (thread_can_start_ != NULL) - thread_can_start_->WaitForNotification(); - func_(param_); - } - - private: - UserThreadFunc* const func_; // User-supplied thread function. - const T param_; // User-supplied parameter to the thread function. - // When non-NULL, used to block execution until the controller thread - // notifies. - Notification* const thread_can_start_; - bool finished_; // true iff we know that the thread function has finished. - pthread_t thread_; // The native thread object. - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); -}; -# endif // GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW - -# if 0 // OS detection -# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT - -// Mutex implements mutex on Windows platforms. It is used in conjunction -// with class MutexLock: -// -// Mutex mutex; -// ... -// MutexLock lock(&mutex); // Acquires the mutex and releases it at the -// // end of the current scope. -// -// A static Mutex *must* be defined or declared using one of the following -// macros: -// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); -// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); -// -// (A non-static Mutex is defined/declared in the usual way). -class GTEST_API_ Mutex { - public: - enum MutexType { kStatic = 0, kDynamic = 1 }; - // We rely on kStaticMutex being 0 as it is to what the linker initializes - // type_ in static mutexes. critical_section_ will be initialized lazily - // in ThreadSafeLazyInit(). - enum StaticConstructorSelector { kStaticMutex = 0 }; - - // This constructor intentionally does nothing. It relies on type_ being - // statically initialized to 0 (effectively setting it to kStatic) and on - // ThreadSafeLazyInit() to lazily initialize the rest of the members. - explicit Mutex(StaticConstructorSelector /*dummy*/) {} - - Mutex(); - ~Mutex(); - - void Lock(); - - void Unlock(); - - // Does nothing if the current thread holds the mutex. Otherwise, crashes - // with high probability. - void AssertHeld(); - - private: - // Initializes owner_thread_id_ and critical_section_ in static mutexes. - void ThreadSafeLazyInit(); - - // Per http://blogs.msdn.com/b/oldnewthing/archive/2004/02/23/78395.aspx, - // we assume that 0 is an invalid value for thread IDs. - unsigned int owner_thread_id_; - - // For static mutexes, we rely on these members being initialized to zeros - // by the linker. - MutexType type_; - long critical_section_init_phase_; // NOLINT - _RTL_CRITICAL_SECTION* critical_section_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); -}; - -# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ - extern ::testing::internal::Mutex mutex - -# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ - ::testing::internal::Mutex mutex(::testing::internal::Mutex::kStaticMutex) - -// We cannot name this class MutexLock because the ctor declaration would -// conflict with a macro named MutexLock, which is defined on some -// platforms. That macro is used as a defensive measure to prevent against -// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than -// "MutexLock l(&mu)". Hence the typedef trick below. -class GTestMutexLock { - public: - explicit GTestMutexLock(Mutex* mutex) - : mutex_(mutex) { mutex_->Lock(); } - - ~GTestMutexLock() { mutex_->Unlock(); } - - private: - Mutex* const mutex_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); -}; - -typedef GTestMutexLock MutexLock; - -// Base class for ValueHolder. Allows a caller to hold and delete a value -// without knowing its type. -class ThreadLocalValueHolderBase { - public: - virtual ~ThreadLocalValueHolderBase() {} -}; - -// Provides a way for a thread to send notifications to a ThreadLocal -// regardless of its parameter type. -class ThreadLocalBase { - public: - // Creates a new ValueHolder object holding a default value passed to - // this ThreadLocal's constructor and returns it. It is the caller's - // responsibility not to call this when the ThreadLocal instance already - // has a value on the current thread. - virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const = 0; - - protected: - ThreadLocalBase() {} - virtual ~ThreadLocalBase() {} - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocalBase); -}; - -// Maps a thread to a set of ThreadLocals that have values instantiated on that -// thread and notifies them when the thread exits. A ThreadLocal instance is -// expected to persist until all threads it has values on have terminated. -class GTEST_API_ ThreadLocalRegistry { - public: - // Registers thread_local_instance as having value on the current thread. - // Returns a value that can be used to identify the thread from other threads. - static ThreadLocalValueHolderBase* GetValueOnCurrentThread( - const ThreadLocalBase* thread_local_instance); - - // Invoked when a ThreadLocal instance is destroyed. - static void OnThreadLocalDestroyed( - const ThreadLocalBase* thread_local_instance); -}; - -class GTEST_API_ ThreadWithParamBase { - public: - void Join(); - - protected: - class Runnable { - public: - virtual ~Runnable() {} - virtual void Run() = 0; - }; - - ThreadWithParamBase(Runnable *runnable, Notification* thread_can_start); - virtual ~ThreadWithParamBase(); - - private: - AutoHandle thread_; -}; - -// Helper class for testing Google Test's multi-threading constructs. -template -class ThreadWithParam : public ThreadWithParamBase { - public: - typedef void UserThreadFunc(T); - - ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start) - : ThreadWithParamBase(new RunnableImpl(func, param), thread_can_start) { - } - virtual ~ThreadWithParam() {} - - private: - class RunnableImpl : public Runnable { - public: - RunnableImpl(UserThreadFunc* func, T param) - : func_(func), - param_(param) { - } - virtual ~RunnableImpl() {} - virtual void Run() { - func_(param_); - } - - private: - UserThreadFunc* const func_; - const T param_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(RunnableImpl); - }; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); -}; - -// Implements thread-local storage on Windows systems. -// -// // Thread 1 -// ThreadLocal tl(100); // 100 is the default value for each thread. -// -// // Thread 2 -// tl.set(150); // Changes the value for thread 2 only. -// EXPECT_EQ(150, tl.get()); -// -// // Thread 1 -// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. -// tl.set(200); -// EXPECT_EQ(200, tl.get()); -// -// The template type argument T must have a public copy constructor. -// In addition, the default ThreadLocal constructor requires T to have -// a public default constructor. -// -// The users of a TheadLocal instance have to make sure that all but one -// threads (including the main one) using that instance have exited before -// destroying it. Otherwise, the per-thread objects managed for them by the -// ThreadLocal instance are not guaranteed to be destroyed on all platforms. -// -// Google Test only uses global ThreadLocal objects. That means they -// will die after main() has returned. Therefore, no per-thread -// object managed by Google Test will be leaked as long as all threads -// using Google Test have exited when main() returns. -template -class ThreadLocal : public ThreadLocalBase { - public: - ThreadLocal() : default_() {} - explicit ThreadLocal(const T& value) : default_(value) {} - - ~ThreadLocal() { ThreadLocalRegistry::OnThreadLocalDestroyed(this); } - - T* pointer() { return GetOrCreateValue(); } - const T* pointer() const { return GetOrCreateValue(); } - const T& get() const { return *pointer(); } - void set(const T& value) { *pointer() = value; } - - private: - // Holds a value of T. Can be deleted via its base class without the caller - // knowing the type of T. - class ValueHolder : public ThreadLocalValueHolderBase { - public: - explicit ValueHolder(const T& value) : value_(value) {} - - T* pointer() { return &value_; } - - private: - T value_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); - }; - - - T* GetOrCreateValue() const { - return static_cast( - ThreadLocalRegistry::GetValueOnCurrentThread(this))->pointer(); - } - - virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const { - return new ValueHolder(default_); - } - - const T default_; // The default value for each thread. - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); -}; - -# elif GTEST_HAS_PTHREAD - -// MutexBase and Mutex implement mutex on pthreads-based platforms. -class MutexBase { - public: - // Acquires this mutex. - void Lock() { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); - owner_ = pthread_self(); - has_owner_ = true; - } - - // Releases this mutex. - void Unlock() { - // Since the lock is being released the owner_ field should no longer be - // considered valid. We don't protect writing to has_owner_ here, as it's - // the caller's responsibility to ensure that the current thread holds the - // mutex when this is called. - has_owner_ = false; - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); - } - - // Does nothing if the current thread holds the mutex. Otherwise, crashes - // with high probability. - void AssertHeld() const { - GTEST_CHECK_(has_owner_ && pthread_equal(owner_, pthread_self())) - << "The current thread is not holding the mutex @" << this; - } - - // A static mutex may be used before main() is entered. It may even - // be used before the dynamic initialization stage. Therefore we - // must be able to initialize a static mutex object at link time. - // This means MutexBase has to be a POD and its member variables - // have to be public. - public: - pthread_mutex_t mutex_; // The underlying pthread mutex. - // has_owner_ indicates whether the owner_ field below contains a valid thread - // ID and is therefore safe to inspect (e.g., to use in pthread_equal()). All - // accesses to the owner_ field should be protected by a check of this field. - // An alternative might be to memset() owner_ to all zeros, but there's no - // guarantee that a zero'd pthread_t is necessarily invalid or even different - // from pthread_self(). - bool has_owner_; - pthread_t owner_; // The thread holding the mutex. -}; - -// Forward-declares a static mutex. -# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ - extern ::testing::internal::MutexBase mutex - -// Defines and statically (i.e. at link time) initializes a static mutex. -// The initialization list here does not explicitly initialize each field, -// instead relying on default initialization for the unspecified fields. In -// particular, the owner_ field (a pthread_t) is not explicitly initialized. -// This allows initialization to work whether pthread_t is a scalar or struct. -// The flag -Wmissing-field-initializers must not be specified for this to work. -# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ - ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false } - -// The Mutex class can only be used for mutexes created at runtime. It -// shares its API with MutexBase otherwise. -class Mutex : public MutexBase { - public: - Mutex() { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); - has_owner_ = false; - } - ~Mutex() { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); - } - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); -}; - -// We cannot name this class MutexLock because the ctor declaration would -// conflict with a macro named MutexLock, which is defined on some -// platforms. That macro is used as a defensive measure to prevent against -// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than -// "MutexLock l(&mu)". Hence the typedef trick below. -class GTestMutexLock { - public: - explicit GTestMutexLock(MutexBase* mutex) - : mutex_(mutex) { mutex_->Lock(); } - - ~GTestMutexLock() { mutex_->Unlock(); } - - private: - MutexBase* const mutex_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); -}; - -typedef GTestMutexLock MutexLock; - -// Helpers for ThreadLocal. - -// pthread_key_create() requires DeleteThreadLocalValue() to have -// C-linkage. Therefore it cannot be templatized to access -// ThreadLocal. Hence the need for class -// ThreadLocalValueHolderBase. -class ThreadLocalValueHolderBase { - public: - virtual ~ThreadLocalValueHolderBase() {} -}; - -// Called by pthread to delete thread-local data stored by -// pthread_setspecific(). -extern "C" inline void DeleteThreadLocalValue(void* value_holder) { - delete static_cast(value_holder); -} - -// Implements thread-local storage on pthreads-based systems. -template -class ThreadLocal { - public: - ThreadLocal() : key_(CreateKey()), - default_() {} - explicit ThreadLocal(const T& value) : key_(CreateKey()), - default_(value) {} - - ~ThreadLocal() { - // Destroys the managed object for the current thread, if any. - DeleteThreadLocalValue(pthread_getspecific(key_)); - - // Releases resources associated with the key. This will *not* - // delete managed objects for other threads. - GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_)); - } - - T* pointer() { return GetOrCreateValue(); } - const T* pointer() const { return GetOrCreateValue(); } - const T& get() const { return *pointer(); } - void set(const T& value) { *pointer() = value; } - - private: - // Holds a value of type T. - class ValueHolder : public ThreadLocalValueHolderBase { - public: - explicit ValueHolder(const T& value) : value_(value) {} - - T* pointer() { return &value_; } - - private: - T value_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); - }; - - static pthread_key_t CreateKey() { - pthread_key_t key; - // When a thread exits, DeleteThreadLocalValue() will be called on - // the object managed for that thread. - GTEST_CHECK_POSIX_SUCCESS_( - pthread_key_create(&key, &DeleteThreadLocalValue)); - return key; - } - - T* GetOrCreateValue() const { - ThreadLocalValueHolderBase* const holder = - static_cast(pthread_getspecific(key_)); - if (holder != NULL) { - return CheckedDowncastToActualType(holder)->pointer(); - } - - ValueHolder* const new_holder = new ValueHolder(default_); - ThreadLocalValueHolderBase* const holder_base = new_holder; - GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); - return new_holder->pointer(); - } - - // A key pthreads uses for looking up per-thread values. - const pthread_key_t key_; - const T default_; // The default value for each thread. - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); -}; - -# endif // OS detection - -#else // GTEST_IS_THREADSAFE - -// A dummy implementation of synchronization primitives (mutex, lock, -// and thread-local variable). Necessary for compiling Google Test where -// mutex is not supported - using Google Test in multiple threads is not -// supported on such platforms. - -class Mutex { - public: - Mutex() {} - void Lock() {} - void Unlock() {} - void AssertHeld() const {} -}; - -# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ - extern ::testing::internal::Mutex mutex - -# define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex - -// We cannot name this class MutexLock because the ctor declaration would -// conflict with a macro named MutexLock, which is defined on some -// platforms. That macro is used as a defensive measure to prevent against -// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than -// "MutexLock l(&mu)". Hence the typedef trick below. -class GTestMutexLock { - public: - explicit GTestMutexLock(Mutex*) {} // NOLINT -}; - -typedef GTestMutexLock MutexLock; - -template -class ThreadLocal { - public: - ThreadLocal() : value_() {} - explicit ThreadLocal(const T& value) : value_(value) {} - T* pointer() { return &value_; } - const T* pointer() const { return &value_; } - const T& get() const { return value_; } - void set(const T& value) { value_ = value; } - private: - T value_; -}; - -#endif // GTEST_IS_THREADSAFE - -// Returns the number of threads running in the process, or 0 to indicate that -// we cannot detect it. -GTEST_API_ size_t GetThreadCount(); - -// Passing non-POD classes through ellipsis (...) crashes the ARM -// compiler and generates a warning in Sun Studio. The Nokia Symbian -// and the IBM XL C/C++ compiler try to instantiate a copy constructor -// for objects passed through ellipsis (...), failing for uncopyable -// objects. We define this to ensure that only POD is passed through -// ellipsis on these systems. -#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC) -// We lose support for NULL detection where the compiler doesn't like -// passing non-POD classes through ellipsis (...). -# define GTEST_ELLIPSIS_NEEDS_POD_ 1 -#else -# define GTEST_CAN_COMPARE_NULL 1 -#endif - -// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between -// const T& and const T* in a function template. These compilers -// _can_ decide between class template specializations for T and T*, -// so a tr1::type_traits-like is_pointer works. -#if defined(__SYMBIAN32__) || defined(__IBMCPP__) -# define GTEST_NEEDS_IS_POINTER_ 1 -#endif - -template -struct bool_constant { - typedef bool_constant type; - static const bool value = bool_value; -}; -template const bool bool_constant::value; - -typedef bool_constant false_type; -typedef bool_constant true_type; - -template -struct is_pointer : public false_type {}; - -template -struct is_pointer : public true_type {}; - -template -struct IteratorTraits { - typedef typename Iterator::value_type value_type; -}; - -template -struct IteratorTraits { - typedef T value_type; -}; - -template -struct IteratorTraits { - typedef T value_type; -}; - -#if GTEST_OS_WINDOWS -# define GTEST_PATH_SEP_ "\\" -# define GTEST_HAS_ALT_PATH_SEP_ 1 -// The biggest signed integer type the compiler supports. -typedef __int64 BiggestInt; -#else -# define GTEST_PATH_SEP_ "/" -# define GTEST_HAS_ALT_PATH_SEP_ 0 -typedef long long BiggestInt; // NOLINT -#endif // GTEST_OS_WINDOWS - -// Utilities for char. - -// isspace(int ch) and friends accept an unsigned char or EOF. char -// may be signed, depending on the compiler (or compiler flags). -// Therefore we need to cast a char to unsigned char before calling -// isspace(), etc. - -inline bool IsAlpha(char ch) { - return isalpha(static_cast(ch)) != 0; -} -inline bool IsAlNum(char ch) { - return isalnum(static_cast(ch)) != 0; -} -inline bool IsDigit(char ch) { - return isdigit(static_cast(ch)) != 0; -} -inline bool IsLower(char ch) { - return islower(static_cast(ch)) != 0; -} -inline bool IsSpace(char ch) { - return isspace(static_cast(ch)) != 0; -} -inline bool IsUpper(char ch) { - return isupper(static_cast(ch)) != 0; -} -inline bool IsXDigit(char ch) { - return isxdigit(static_cast(ch)) != 0; -} -inline bool IsXDigit(wchar_t ch) { - const unsigned char low_byte = static_cast(ch); - return ch == low_byte && isxdigit(low_byte) != 0; -} - -inline char ToLower(char ch) { - return static_cast(tolower(static_cast(ch))); -} -inline char ToUpper(char ch) { - return static_cast(toupper(static_cast(ch))); -} - -inline std::string StripTrailingSpaces(std::string str) { - std::string::iterator it = str.end(); - while (it != str.begin() && IsSpace(*--it)) - it = str.erase(it); - return str; -} - -// The testing::internal::posix namespace holds wrappers for common -// POSIX functions. These wrappers hide the differences between -// Windows/MSVC and POSIX systems. Since some compilers define these -// standard functions as macros, the wrapper cannot have the same name -// as the wrapped function. - -namespace posix { - -// Functions with a different name on Windows. - -#if GTEST_OS_WINDOWS - -typedef struct _stat StatStruct; - -# ifdef __BORLANDC__ -inline int IsATTY(int fd) { return isatty(fd); } -inline int StrCaseCmp(const char* s1, const char* s2) { - return stricmp(s1, s2); -} -inline char* StrDup(const char* src) { return strdup(src); } -# else // !__BORLANDC__ -# if GTEST_OS_WINDOWS_MOBILE -inline int IsATTY(int /* fd */) { return 0; } -# else -inline int IsATTY(int fd) { return _isatty(fd); } -# endif // GTEST_OS_WINDOWS_MOBILE -inline int StrCaseCmp(const char* s1, const char* s2) { - return _stricmp(s1, s2); -} -inline char* StrDup(const char* src) { return _strdup(src); } -# endif // __BORLANDC__ - -# if GTEST_OS_WINDOWS_MOBILE -inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } -// Stat(), RmDir(), and IsDir() are not needed on Windows CE at this -// time and thus not defined there. -# else -inline int FileNo(FILE* file) { return _fileno(file); } -inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } -inline int RmDir(const char* dir) { return _rmdir(dir); } -inline bool IsDir(const StatStruct& st) { - return (_S_IFDIR & st.st_mode) != 0; -} -# endif // GTEST_OS_WINDOWS_MOBILE - -#else - -typedef struct stat StatStruct; - -inline int FileNo(FILE* file) { return fileno(file); } -inline int IsATTY(int fd) { return isatty(fd); } -inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } -inline int StrCaseCmp(const char* s1, const char* s2) { - return strcasecmp(s1, s2); -} -inline char* StrDup(const char* src) { return strdup(src); } -inline int RmDir(const char* dir) { return rmdir(dir); } -inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } - -#endif // GTEST_OS_WINDOWS - -// Functions deprecated by MSVC 8.0. - -GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996 /* deprecated function */) - -inline const char* StrNCpy(char* dest, const char* src, size_t n) { - return strncpy(dest, src, n); -} - -// ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and -// StrError() aren't needed on Windows CE at this time and thus not -// defined there. - -#if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT -inline int ChDir(const char* dir) { return chdir(dir); } -#endif -inline FILE* FOpen(const char* path, const char* mode) { - return fopen(path, mode); -} -#if !GTEST_OS_WINDOWS_MOBILE -inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { - return freopen(path, mode, stream); -} -inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } -#endif -inline int FClose(FILE* fp) { return fclose(fp); } -#if !GTEST_OS_WINDOWS_MOBILE -inline int Read(int fd, void* buf, unsigned int count) { - return static_cast(read(fd, buf, count)); -} -inline int Write(int fd, const void* buf, unsigned int count) { - return static_cast(write(fd, buf, count)); -} -inline int Close(int fd) { return close(fd); } -inline const char* StrError(int errnum) { return strerror(errnum); } -#endif -inline const char* GetEnv(const char* name) { -#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE | GTEST_OS_WINDOWS_RT - // We are on Windows CE, which has no environment variables. - static_cast(name); // To prevent 'unused argument' warning. - return NULL; -#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) - // Environment variables which we programmatically clear will be set to the - // empty string rather than unset (NULL). Handle that case. - const char* const env = getenv(name); - return (env != NULL && env[0] != '\0') ? env : NULL; -#else - return getenv(name); -#endif -} - -GTEST_DISABLE_MSC_WARNINGS_POP_() - -#if GTEST_OS_WINDOWS_MOBILE -// Windows CE has no C library. The abort() function is used in -// several places in Google Test. This implementation provides a reasonable -// imitation of standard behaviour. -void Abort(); -#else -inline void Abort() { abort(); } -#endif // GTEST_OS_WINDOWS_MOBILE - -} // namespace posix - -// MSVC "deprecates" snprintf and issues warnings wherever it is used. In -// order to avoid these warnings, we need to use _snprintf or _snprintf_s on -// MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate -// function in order to achieve that. We use macro definition here because -// snprintf is a variadic function. -#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE -// MSVC 2005 and above support variadic macros. -# define GTEST_SNPRINTF_(buffer, size, format, ...) \ - _snprintf_s(buffer, size, size, format, __VA_ARGS__) -#elif defined(_MSC_VER) -// Windows CE does not define _snprintf_s and MSVC prior to 2005 doesn't -// complain about _snprintf. -# define GTEST_SNPRINTF_ _snprintf -#else -# define GTEST_SNPRINTF_ snprintf -#endif - -// The maximum number a BiggestInt can represent. This definition -// works no matter BiggestInt is represented in one's complement or -// two's complement. -// -// We cannot rely on numeric_limits in STL, as __int64 and long long -// are not part of standard C++ and numeric_limits doesn't need to be -// defined for them. -const BiggestInt kMaxBiggestInt = - ~(static_cast(1) << (8*sizeof(BiggestInt) - 1)); - -// This template class serves as a compile-time function from size to -// type. It maps a size in bytes to a primitive type with that -// size. e.g. -// -// TypeWithSize<4>::UInt -// -// is typedef-ed to be unsigned int (unsigned integer made up of 4 -// bytes). -// -// Such functionality should belong to STL, but I cannot find it -// there. -// -// Google Test uses this class in the implementation of floating-point -// comparison. -// -// For now it only handles UInt (unsigned int) as that's all Google Test -// needs. Other types can be easily added in the future if need -// arises. -template -class TypeWithSize { - public: - // This prevents the user from using TypeWithSize with incorrect - // values of N. - typedef void UInt; -}; - -// The specialization for size 4. -template <> -class TypeWithSize<4> { - public: - // unsigned int has size 4 in both gcc and MSVC. - // - // As base/basictypes.h doesn't compile on Windows, we cannot use - // uint32, uint64, and etc here. - typedef int Int; - typedef unsigned int UInt; -}; - -// The specialization for size 8. -template <> -class TypeWithSize<8> { - public: -#if GTEST_OS_WINDOWS - typedef __int64 Int; - typedef unsigned __int64 UInt; -#else - typedef long long Int; // NOLINT - typedef unsigned long long UInt; // NOLINT -#endif // GTEST_OS_WINDOWS -}; - -// Integer types of known sizes. -typedef TypeWithSize<4>::Int Int32; -typedef TypeWithSize<4>::UInt UInt32; -typedef TypeWithSize<8>::Int Int64; -typedef TypeWithSize<8>::UInt UInt64; -typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. - -// Utilities for command line flags and environment variables. - -// Macro for referencing flags. -#define GTEST_FLAG(name) FLAGS_gtest_##name - -// Macros for declaring flags. -#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) -#define GTEST_DECLARE_int32_(name) \ - GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) -#define GTEST_DECLARE_string_(name) \ - GTEST_API_ extern ::std::string GTEST_FLAG(name) - -// Macros for defining flags. -#define GTEST_DEFINE_bool_(name, default_val, doc) \ - GTEST_API_ bool GTEST_FLAG(name) = (default_val) -#define GTEST_DEFINE_int32_(name, default_val, doc) \ - GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) -#define GTEST_DEFINE_string_(name, default_val, doc) \ - GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val) - -// Thread annotations -#define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) -#define GTEST_LOCK_EXCLUDED_(locks) - -// Parses 'str' for a 32-bit signed integer. If successful, writes the result -// to *value and returns true; otherwise leaves *value unchanged and returns -// false. -// TODO(user): Find a better way to refactor flag and environment parsing -// out of both gtest-port.cc and gtest.cc to avoid exporting this utility -// function. -bool ParseInt32(const Message& src_text, const char* str, Int32* value); - -// Parses a bool/Int32/string from the environment variable -// corresponding to the given Google Test flag. -bool BoolFromGTestEnv(const char* flag, bool default_val); -GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); -const char* StringFromGTestEnv(const char* flag, const char* default_val); - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ diff --git a/src/gtest/include/gtest/internal/gtest-string.h b/src/gtest/include/gtest/internal/gtest-string.h deleted file mode 100644 index ef788f8d..00000000 --- a/src/gtest/include/gtest/internal/gtest-string.h +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2005 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// -// -// The Google C++ Testing Framework (Google Test) -// -// This header file declares the String class and functions used internally by -// Google Test. They are subject to change without notice. They should not used -// by code external to Google Test. -// -// This header file is #included by . -// It should not be #included by other files. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ - -#ifdef __BORLANDC__ -// string.h is not guaranteed to provide strcpy on C++ Builder. -# include -#endif - -#include -#include - -#include "gtest/internal/gtest-port.h" - -namespace testing { -namespace internal { - -// String - an abstract class holding static string utilities. -class GTEST_API_ String { - public: - // Static utility methods - - // Clones a 0-terminated C string, allocating memory using new. The - // caller is responsible for deleting the return value using - // delete[]. Returns the cloned string, or NULL if the input is - // NULL. - // - // This is different from strdup() in string.h, which allocates - // memory using malloc(). - static const char* CloneCString(const char* c_str); - -#if GTEST_OS_WINDOWS_MOBILE - // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be - // able to pass strings to Win32 APIs on CE we need to convert them - // to 'Unicode', UTF-16. - - // Creates a UTF-16 wide string from the given ANSI string, allocating - // memory using new. The caller is responsible for deleting the return - // value using delete[]. Returns the wide string, or NULL if the - // input is NULL. - // - // The wide string is created using the ANSI codepage (CP_ACP) to - // match the behaviour of the ANSI versions of Win32 calls and the - // C runtime. - static LPCWSTR AnsiToUtf16(const char* c_str); - - // Creates an ANSI string from the given wide string, allocating - // memory using new. The caller is responsible for deleting the return - // value using delete[]. Returns the ANSI string, or NULL if the - // input is NULL. - // - // The returned string is created using the ANSI codepage (CP_ACP) to - // match the behaviour of the ANSI versions of Win32 calls and the - // C runtime. - static const char* Utf16ToAnsi(LPCWSTR utf16_str); -#endif - - // Compares two C strings. Returns true iff they have the same content. - // - // Unlike strcmp(), this function can handle NULL argument(s). A - // NULL C string is considered different to any non-NULL C string, - // including the empty string. - static bool CStringEquals(const char* lhs, const char* rhs); - - // Converts a wide C string to a String using the UTF-8 encoding. - // NULL will be converted to "(null)". If an error occurred during - // the conversion, "(failed to convert from wide string)" is - // returned. - static std::string ShowWideCString(const wchar_t* wide_c_str); - - // Compares two wide C strings. Returns true iff they have the same - // content. - // - // Unlike wcscmp(), this function can handle NULL argument(s). A - // NULL C string is considered different to any non-NULL C string, - // including the empty string. - static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); - - // Compares two C strings, ignoring case. Returns true iff they - // have the same content. - // - // Unlike strcasecmp(), this function can handle NULL argument(s). - // A NULL C string is considered different to any non-NULL C string, - // including the empty string. - static bool CaseInsensitiveCStringEquals(const char* lhs, - const char* rhs); - - // Compares two wide C strings, ignoring case. Returns true iff they - // have the same content. - // - // Unlike wcscasecmp(), this function can handle NULL argument(s). - // A NULL C string is considered different to any non-NULL wide C string, - // including the empty string. - // NB: The implementations on different platforms slightly differ. - // On windows, this method uses _wcsicmp which compares according to LC_CTYPE - // environment variable. On GNU platform this method uses wcscasecmp - // which compares according to LC_CTYPE category of the current locale. - // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the - // current locale. - static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, - const wchar_t* rhs); - - // Returns true iff the given string ends with the given suffix, ignoring - // case. Any string is considered to end with an empty suffix. - static bool EndsWithCaseInsensitive( - const std::string& str, const std::string& suffix); - - // Formats an int value as "%02d". - static std::string FormatIntWidth2(int value); // "%02d" for width == 2 - - // Formats an int value as "%X". - static std::string FormatHexInt(int value); - - // Formats a byte as "%02X". - static std::string FormatByte(unsigned char value); - - private: - String(); // Not meant to be instantiated. -}; // class String - -// Gets the content of the stringstream's buffer as an std::string. Each '\0' -// character in the buffer is replaced with "\\0". -GTEST_API_ std::string StringStreamToString(::std::stringstream* stream); - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ \ No newline at end of file diff --git a/src/gtest/include/gtest/internal/gtest-tuple.h b/src/gtest/include/gtest/internal/gtest-tuple.h deleted file mode 100644 index 18496330..00000000 --- a/src/gtest/include/gtest/internal/gtest-tuple.h +++ /dev/null @@ -1,1032 +0,0 @@ -// Copyright 2009 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file was GENERATED by command: -// pump.py gtest-tuple.h.pump -// DO NOT EDIT BY HAND!!! - -// 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. -// - -// Implements a subset of TR1 tuple needed by Google Test and Google Mock. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ - -#include // For ::std::pair. - -// The compiler used in Symbian has a bug that prevents us from declaring the -// tuple template as a friend (it complains that tuple is redefined). This -// hack bypasses the bug by declaring the members that should otherwise be -// private as public. -// Sun Studio versions < 12 also have the above bug. -#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) -# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: -#else -# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ - template friend class tuple; \ - private: -#endif - -// Visual Studio 2010, 2012, and 2013 define symbols in std::tr1 that conflict -// with our own definitions. Therefore using our own tuple does not work on -// those compilers. -#if defined(_MSC_VER) && _MSC_VER >= 1600 /* 1600 is Visual Studio 2010 */ -# error "gtest's tuple doesn't compile on Visual Studio 2010 or later. \ -GTEST_USE_OWN_TR1_TUPLE must be set to 0 on those compilers." -#endif - -// GTEST_n_TUPLE_(T) is the type of an n-tuple. -#define GTEST_0_TUPLE_(T) tuple<> -#define GTEST_1_TUPLE_(T) tuple -#define GTEST_2_TUPLE_(T) tuple -#define GTEST_3_TUPLE_(T) tuple -#define GTEST_4_TUPLE_(T) tuple -#define GTEST_5_TUPLE_(T) tuple -#define GTEST_6_TUPLE_(T) tuple -#define GTEST_7_TUPLE_(T) tuple -#define GTEST_8_TUPLE_(T) tuple -#define GTEST_9_TUPLE_(T) tuple -#define GTEST_10_TUPLE_(T) tuple - -// GTEST_n_TYPENAMES_(T) declares a list of n typenames. -#define GTEST_0_TYPENAMES_(T) -#define GTEST_1_TYPENAMES_(T) typename T##0 -#define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1 -#define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2 -#define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3 -#define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4 -#define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4, typename T##5 -#define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4, typename T##5, typename T##6 -#define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4, typename T##5, typename T##6, typename T##7 -#define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4, typename T##5, typename T##6, \ - typename T##7, typename T##8 -#define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4, typename T##5, typename T##6, \ - typename T##7, typename T##8, typename T##9 - -// In theory, defining stuff in the ::std namespace is undefined -// behavior. We can do this as we are playing the role of a standard -// library vendor. -namespace std { -namespace tr1 { - -template -class tuple; - -// Anything in namespace gtest_internal is Google Test's INTERNAL -// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. -namespace gtest_internal { - -// ByRef::type is T if T is a reference; otherwise it's const T&. -template -struct ByRef { typedef const T& type; }; // NOLINT -template -struct ByRef { typedef T& type; }; // NOLINT - -// A handy wrapper for ByRef. -#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type - -// AddRef::type is T if T is a reference; otherwise it's T&. This -// is the same as tr1::add_reference::type. -template -struct AddRef { typedef T& type; }; // NOLINT -template -struct AddRef { typedef T& type; }; // NOLINT - -// A handy wrapper for AddRef. -#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type - -// A helper for implementing get(). -template class Get; - -// A helper for implementing tuple_element. kIndexValid is true -// iff k < the number of fields in tuple type T. -template -struct TupleElement; - -template -struct TupleElement { - typedef T0 type; -}; - -template -struct TupleElement { - typedef T1 type; -}; - -template -struct TupleElement { - typedef T2 type; -}; - -template -struct TupleElement { - typedef T3 type; -}; - -template -struct TupleElement { - typedef T4 type; -}; - -template -struct TupleElement { - typedef T5 type; -}; - -template -struct TupleElement { - typedef T6 type; -}; - -template -struct TupleElement { - typedef T7 type; -}; - -template -struct TupleElement { - typedef T8 type; -}; - -template -struct TupleElement { - typedef T9 type; -}; - -} // namespace gtest_internal - -template <> -class tuple<> { - public: - tuple() {} - tuple(const tuple& /* t */) {} - tuple& operator=(const tuple& /* t */) { return *this; } -}; - -template -class GTEST_1_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {} - - tuple(const tuple& t) : f0_(t.f0_) {} - - template - tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_1_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) { - f0_ = t.f0_; - return *this; - } - - T0 f0_; -}; - -template -class GTEST_2_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0), - f1_(f1) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {} - - template - tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {} - template - tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_2_TUPLE_(U)& t) { - return CopyFrom(t); - } - template - tuple& operator=(const ::std::pair& p) { - f0_ = p.first; - f1_ = p.second; - return *this; - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - return *this; - } - - T0 f0_; - T1 f1_; -}; - -template -class GTEST_3_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} - - template - tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_3_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; -}; - -template -class GTEST_4_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2), - f3_(f3) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} - - template - tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_4_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; -}; - -template -class GTEST_5_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, - GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_) {} - - template - tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_5_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; -}; - -template -class GTEST_6_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, - GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), - f5_(f5) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_), f5_(t.f5_) {} - - template - tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_6_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - f5_ = t.f5_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; - T5 f5_; -}; - -template -class GTEST_7_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, - GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2), - f3_(f3), f4_(f4), f5_(f5), f6_(f6) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} - - template - tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_7_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - f5_ = t.f5_; - f6_ = t.f6_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; - T5 f5_; - T6 f6_; -}; - -template -class GTEST_8_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, - GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, - GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), - f5_(f5), f6_(f6), f7_(f7) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} - - template - tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_8_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - f5_ = t.f5_; - f6_ = t.f6_; - f7_ = t.f7_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; - T5 f5_; - T6 f6_; - T7 f7_; -}; - -template -class GTEST_9_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, - GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, - GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), - f5_(f5), f6_(f6), f7_(f7), f8_(f8) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} - - template - tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_9_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - f5_ = t.f5_; - f6_ = t.f6_; - f7_ = t.f7_; - f8_ = t.f8_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; - T5 f5_; - T6 f6_; - T7 f7_; - T8 f8_; -}; - -template -class tuple { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(), - f9_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, - GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, - GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2), - f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} - - template - tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), - f9_(t.f9_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_10_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - f5_ = t.f5_; - f6_ = t.f6_; - f7_ = t.f7_; - f8_ = t.f8_; - f9_ = t.f9_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; - T5 f5_; - T6 f6_; - T7 f7_; - T8 f8_; - T9 f9_; -}; - -// 6.1.3.2 Tuple creation functions. - -// Known limitations: we don't support passing an -// std::tr1::reference_wrapper to make_tuple(). And we don't -// implement tie(). - -inline tuple<> make_tuple() { return tuple<>(); } - -template -inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) { - return GTEST_1_TUPLE_(T)(f0); -} - -template -inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) { - return GTEST_2_TUPLE_(T)(f0, f1); -} - -template -inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) { - return GTEST_3_TUPLE_(T)(f0, f1, f2); -} - -template -inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3) { - return GTEST_4_TUPLE_(T)(f0, f1, f2, f3); -} - -template -inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4) { - return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4); -} - -template -inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4, const T5& f5) { - return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5); -} - -template -inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4, const T5& f5, const T6& f6) { - return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6); -} - -template -inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) { - return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7); -} - -template -inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, - const T8& f8) { - return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8); -} - -template -inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, - const T8& f8, const T9& f9) { - return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9); -} - -// 6.1.3.3 Tuple helper classes. - -template struct tuple_size; - -template -struct tuple_size { - static const int value = 0; -}; - -template -struct tuple_size { - static const int value = 1; -}; - -template -struct tuple_size { - static const int value = 2; -}; - -template -struct tuple_size { - static const int value = 3; -}; - -template -struct tuple_size { - static const int value = 4; -}; - -template -struct tuple_size { - static const int value = 5; -}; - -template -struct tuple_size { - static const int value = 6; -}; - -template -struct tuple_size { - static const int value = 7; -}; - -template -struct tuple_size { - static const int value = 8; -}; - -template -struct tuple_size { - static const int value = 9; -}; - -template -struct tuple_size { - static const int value = 10; -}; - -template -struct tuple_element { - typedef typename gtest_internal::TupleElement< - k < (tuple_size::value), k, Tuple>::type type; -}; - -#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type - -// 6.1.3.4 Element access. - -namespace gtest_internal { - -template <> -class Get<0> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) - Field(Tuple& t) { return t.f0_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) - ConstField(const Tuple& t) { return t.f0_; } -}; - -template <> -class Get<1> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) - Field(Tuple& t) { return t.f1_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) - ConstField(const Tuple& t) { return t.f1_; } -}; - -template <> -class Get<2> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) - Field(Tuple& t) { return t.f2_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) - ConstField(const Tuple& t) { return t.f2_; } -}; - -template <> -class Get<3> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) - Field(Tuple& t) { return t.f3_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) - ConstField(const Tuple& t) { return t.f3_; } -}; - -template <> -class Get<4> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) - Field(Tuple& t) { return t.f4_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) - ConstField(const Tuple& t) { return t.f4_; } -}; - -template <> -class Get<5> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) - Field(Tuple& t) { return t.f5_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) - ConstField(const Tuple& t) { return t.f5_; } -}; - -template <> -class Get<6> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) - Field(Tuple& t) { return t.f6_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) - ConstField(const Tuple& t) { return t.f6_; } -}; - -template <> -class Get<7> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) - Field(Tuple& t) { return t.f7_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) - ConstField(const Tuple& t) { return t.f7_; } -}; - -template <> -class Get<8> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) - Field(Tuple& t) { return t.f8_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) - ConstField(const Tuple& t) { return t.f8_; } -}; - -template <> -class Get<9> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) - Field(Tuple& t) { return t.f9_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) - ConstField(const Tuple& t) { return t.f9_; } -}; - -} // namespace gtest_internal - -template -GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) -get(GTEST_10_TUPLE_(T)& t) { - return gtest_internal::Get::Field(t); -} - -template -GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) -get(const GTEST_10_TUPLE_(T)& t) { - return gtest_internal::Get::ConstField(t); -} - -// 6.1.3.5 Relational operators - -// We only implement == and !=, as we don't have a need for the rest yet. - -namespace gtest_internal { - -// SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the -// first k fields of t1 equals the first k fields of t2. -// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if -// k1 != k2. -template -struct SameSizeTuplePrefixComparator; - -template <> -struct SameSizeTuplePrefixComparator<0, 0> { - template - static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { - return true; - } -}; - -template -struct SameSizeTuplePrefixComparator { - template - static bool Eq(const Tuple1& t1, const Tuple2& t2) { - return SameSizeTuplePrefixComparator::Eq(t1, t2) && - ::std::tr1::get(t1) == ::std::tr1::get(t2); - } -}; - -} // namespace gtest_internal - -template -inline bool operator==(const GTEST_10_TUPLE_(T)& t, - const GTEST_10_TUPLE_(U)& u) { - return gtest_internal::SameSizeTuplePrefixComparator< - tuple_size::value, - tuple_size::value>::Eq(t, u); -} - -template -inline bool operator!=(const GTEST_10_TUPLE_(T)& t, - const GTEST_10_TUPLE_(U)& u) { return !(t == u); } - -// 6.1.4 Pairs. -// Unimplemented. - -} // namespace tr1 -} // namespace std - -#undef GTEST_0_TUPLE_ -#undef GTEST_1_TUPLE_ -#undef GTEST_2_TUPLE_ -#undef GTEST_3_TUPLE_ -#undef GTEST_4_TUPLE_ -#undef GTEST_5_TUPLE_ -#undef GTEST_6_TUPLE_ -#undef GTEST_7_TUPLE_ -#undef GTEST_8_TUPLE_ -#undef GTEST_9_TUPLE_ -#undef GTEST_10_TUPLE_ - -#undef GTEST_0_TYPENAMES_ -#undef GTEST_1_TYPENAMES_ -#undef GTEST_2_TYPENAMES_ -#undef GTEST_3_TYPENAMES_ -#undef GTEST_4_TYPENAMES_ -#undef GTEST_5_TYPENAMES_ -#undef GTEST_6_TYPENAMES_ -#undef GTEST_7_TYPENAMES_ -#undef GTEST_8_TYPENAMES_ -#undef GTEST_9_TYPENAMES_ -#undef GTEST_10_TYPENAMES_ - -#undef GTEST_DECLARE_TUPLE_AS_FRIEND_ -#undef GTEST_BY_REF_ -#undef GTEST_ADD_REF_ -#undef GTEST_TUPLE_ELEMENT_ - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ \ No newline at end of file diff --git a/src/gtest/include/gtest/internal/gtest-type-util.h b/src/gtest/include/gtest/internal/gtest-type-util.h deleted file mode 100644 index e4694b04..00000000 --- a/src/gtest/include/gtest/internal/gtest-type-util.h +++ /dev/null @@ -1,3343 +0,0 @@ -// Copyright 2008 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file was GENERATED by command: -// pump.py gtest-type-util.h.pump -// DO NOT EDIT BY HAND!!! - -// 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. -// - -// Type utilities needed for implementing typed and type-parameterized -// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! -// -// Currently we support at most 50 types in a list, and at most 50 -// type-parameterized tests in one type-parameterized test case. -// Please contact googletestframework@googlegroups.com if you need -// more. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ - -#include "gtest/internal/gtest-port.h" - -// #ifdef __GNUC__ is too general here. It is possible to use gcc without using -// libstdc++ (which is where cxxabi.h comes from). -# if GTEST_HAS_CXXABI_H_ -# include -# elif defined(__HP_aCC) -# include -# endif // GTEST_HASH_CXXABI_H_ - -namespace testing { -namespace internal { - -// GetTypeName() returns a human-readable name of type T. -// NB: This function is also used in Google Mock, so don't move it inside of -// the typed-test-only section below. -template -std::string GetTypeName() { -# if GTEST_HAS_RTTI - - const char* const name = typeid(T).name(); -# if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) - int status = 0; - // gcc's implementation of typeid(T).name() mangles the type name, - // so we have to demangle it. -# if GTEST_HAS_CXXABI_H_ - using abi::__cxa_demangle; -# endif // GTEST_HAS_CXXABI_H_ - char* const readable_name = __cxa_demangle(name, 0, 0, &status); - const std::string name_str(status == 0 ? readable_name : name); - free(readable_name); - return name_str; -# else - return name; -# endif // GTEST_HAS_CXXABI_H_ || __HP_aCC - -# else - - return ""; - -# endif // GTEST_HAS_RTTI -} - -#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P - -// AssertyTypeEq::type is defined iff T1 and T2 are the same -// type. This can be used as a compile-time assertion to ensure that -// two types are equal. - -template -struct AssertTypeEq; - -template -struct AssertTypeEq { - typedef bool type; -}; - -// A unique type used as the default value for the arguments of class -// template Types. This allows us to simulate variadic templates -// (e.g. Types, Type, and etc), which C++ doesn't -// support directly. -struct None {}; - -// The following family of struct and struct templates are used to -// represent type lists. In particular, TypesN -// represents a type list with N types (T1, T2, ..., and TN) in it. -// Except for Types0, every struct in the family has two member types: -// Head for the first type in the list, and Tail for the rest of the -// list. - -// The empty type list. -struct Types0 {}; - -// Type lists of length 1, 2, 3, and so on. - -template -struct Types1 { - typedef T1 Head; - typedef Types0 Tail; -}; -template -struct Types2 { - typedef T1 Head; - typedef Types1 Tail; -}; - -template -struct Types3 { - typedef T1 Head; - typedef Types2 Tail; -}; - -template -struct Types4 { - typedef T1 Head; - typedef Types3 Tail; -}; - -template -struct Types5 { - typedef T1 Head; - typedef Types4 Tail; -}; - -template -struct Types6 { - typedef T1 Head; - typedef Types5 Tail; -}; - -template -struct Types7 { - typedef T1 Head; - typedef Types6 Tail; -}; - -template -struct Types8 { - typedef T1 Head; - typedef Types7 Tail; -}; - -template -struct Types9 { - typedef T1 Head; - typedef Types8 Tail; -}; - -template -struct Types10 { - typedef T1 Head; - typedef Types9 Tail; -}; - -template -struct Types11 { - typedef T1 Head; - typedef Types10 Tail; -}; - -template -struct Types12 { - typedef T1 Head; - typedef Types11 Tail; -}; - -template -struct Types13 { - typedef T1 Head; - typedef Types12 Tail; -}; - -template -struct Types14 { - typedef T1 Head; - typedef Types13 Tail; -}; - -template -struct Types15 { - typedef T1 Head; - typedef Types14 Tail; -}; - -template -struct Types16 { - typedef T1 Head; - typedef Types15 Tail; -}; - -template -struct Types17 { - typedef T1 Head; - typedef Types16 Tail; -}; - -template -struct Types18 { - typedef T1 Head; - typedef Types17 Tail; -}; - -template -struct Types19 { - typedef T1 Head; - typedef Types18 Tail; -}; - -template -struct Types20 { - typedef T1 Head; - typedef Types19 Tail; -}; - -template -struct Types21 { - typedef T1 Head; - typedef Types20 Tail; -}; - -template -struct Types22 { - typedef T1 Head; - typedef Types21 Tail; -}; - -template -struct Types23 { - typedef T1 Head; - typedef Types22 Tail; -}; - -template -struct Types24 { - typedef T1 Head; - typedef Types23 Tail; -}; - -template -struct Types25 { - typedef T1 Head; - typedef Types24 Tail; -}; - -template -struct Types26 { - typedef T1 Head; - typedef Types25 Tail; -}; - -template -struct Types27 { - typedef T1 Head; - typedef Types26 Tail; -}; - -template -struct Types28 { - typedef T1 Head; - typedef Types27 Tail; -}; - -template -struct Types29 { - typedef T1 Head; - typedef Types28 Tail; -}; - -template -struct Types30 { - typedef T1 Head; - typedef Types29 Tail; -}; - -template -struct Types31 { - typedef T1 Head; - typedef Types30 Tail; -}; - -template -struct Types32 { - typedef T1 Head; - typedef Types31 Tail; -}; - -template -struct Types33 { - typedef T1 Head; - typedef Types32 Tail; -}; - -template -struct Types34 { - typedef T1 Head; - typedef Types33 Tail; -}; - -template -struct Types35 { - typedef T1 Head; - typedef Types34 Tail; -}; - -template -struct Types36 { - typedef T1 Head; - typedef Types35 Tail; -}; - -template -struct Types37 { - typedef T1 Head; - typedef Types36 Tail; -}; - -template -struct Types38 { - typedef T1 Head; - typedef Types37 Tail; -}; - -template -struct Types39 { - typedef T1 Head; - typedef Types38 Tail; -}; - -template -struct Types40 { - typedef T1 Head; - typedef Types39 Tail; -}; - -template -struct Types41 { - typedef T1 Head; - typedef Types40 Tail; -}; - -template -struct Types42 { - typedef T1 Head; - typedef Types41 Tail; -}; - -template -struct Types43 { - typedef T1 Head; - typedef Types42 Tail; -}; - -template -struct Types44 { - typedef T1 Head; - typedef Types43 Tail; -}; - -template -struct Types45 { - typedef T1 Head; - typedef Types44 Tail; -}; - -template -struct Types46 { - typedef T1 Head; - typedef Types45 Tail; -}; - -template -struct Types47 { - typedef T1 Head; - typedef Types46 Tail; -}; - -template -struct Types48 { - typedef T1 Head; - typedef Types47 Tail; -}; - -template -struct Types49 { - typedef T1 Head; - typedef Types48 Tail; -}; - -template -struct Types50 { - typedef T1 Head; - typedef Types49 Tail; -}; - - -} // namespace internal - -// We don't want to require the users to write TypesN<...> directly, -// as that would require them to count the length. Types<...> is much -// easier to write, but generates horrible messages when there is a -// compiler error, as gcc insists on printing out each template -// argument, even if it has the default value (this means Types -// will appear as Types in the compiler -// errors). -// -// Our solution is to combine the best part of the two approaches: a -// user would write Types, and Google Test will translate -// that to TypesN internally to make error messages -// readable. The translation is done by the 'type' member of the -// Types template. -template -struct Types { - typedef internal::Types50 type; -}; - -template <> -struct Types { - typedef internal::Types0 type; -}; -template -struct Types { - typedef internal::Types1 type; -}; -template -struct Types { - typedef internal::Types2 type; -}; -template -struct Types { - typedef internal::Types3 type; -}; -template -struct Types { - typedef internal::Types4 type; -}; -template -struct Types { - typedef internal::Types5 type; -}; -template -struct Types { - typedef internal::Types6 type; -}; -template -struct Types { - typedef internal::Types7 type; -}; -template -struct Types { - typedef internal::Types8 type; -}; -template -struct Types { - typedef internal::Types9 type; -}; -template -struct Types { - typedef internal::Types10 type; -}; -template -struct Types { - typedef internal::Types11 type; -}; -template -struct Types { - typedef internal::Types12 type; -}; -template -struct Types { - typedef internal::Types13 type; -}; -template -struct Types { - typedef internal::Types14 type; -}; -template -struct Types { - typedef internal::Types15 type; -}; -template -struct Types { - typedef internal::Types16 type; -}; -template -struct Types { - typedef internal::Types17 type; -}; -template -struct Types { - typedef internal::Types18 type; -}; -template -struct Types { - typedef internal::Types19 type; -}; -template -struct Types { - typedef internal::Types20 type; -}; -template -struct Types { - typedef internal::Types21 type; -}; -template -struct Types { - typedef internal::Types22 type; -}; -template -struct Types { - typedef internal::Types23 type; -}; -template -struct Types { - typedef internal::Types24 type; -}; -template -struct Types { - typedef internal::Types25 type; -}; -template -struct Types { - typedef internal::Types26 type; -}; -template -struct Types { - typedef internal::Types27 type; -}; -template -struct Types { - typedef internal::Types28 type; -}; -template -struct Types { - typedef internal::Types29 type; -}; -template -struct Types { - typedef internal::Types30 type; -}; -template -struct Types { - typedef internal::Types31 type; -}; -template -struct Types { - typedef internal::Types32 type; -}; -template -struct Types { - typedef internal::Types33 type; -}; -template -struct Types { - typedef internal::Types34 type; -}; -template -struct Types { - typedef internal::Types35 type; -}; -template -struct Types { - typedef internal::Types36 type; -}; -template -struct Types { - typedef internal::Types37 type; -}; -template -struct Types { - typedef internal::Types38 type; -}; -template -struct Types { - typedef internal::Types39 type; -}; -template -struct Types { - typedef internal::Types40 type; -}; -template -struct Types { - typedef internal::Types41 type; -}; -template -struct Types { - typedef internal::Types42 type; -}; -template -struct Types { - typedef internal::Types43 type; -}; -template -struct Types { - typedef internal::Types44 type; -}; -template -struct Types { - typedef internal::Types45 type; -}; -template -struct Types { - typedef internal::Types46 type; -}; -template -struct Types { - typedef internal::Types47 type; -}; -template -struct Types { - typedef internal::Types48 type; -}; -template -struct Types { - typedef internal::Types49 type; -}; - -namespace internal { - -# define GTEST_TEMPLATE_ template class - -// The template "selector" struct TemplateSel is used to -// represent Tmpl, which must be a class template with one type -// parameter, as a type. TemplateSel::Bind::type is defined -// as the type Tmpl. This allows us to actually instantiate the -// template "selected" by TemplateSel. -// -// This trick is necessary for simulating typedef for class templates, -// which C++ doesn't support directly. -template -struct TemplateSel { - template - struct Bind { - typedef Tmpl type; - }; -}; - -# define GTEST_BIND_(TmplSel, T) \ - TmplSel::template Bind::type - -// A unique struct template used as the default value for the -// arguments of class template Templates. This allows us to simulate -// variadic templates (e.g. Templates, Templates, -// and etc), which C++ doesn't support directly. -template -struct NoneT {}; - -// The following family of struct and struct templates are used to -// represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except -// for Templates0, every struct in the family has two member types: -// Head for the selector of the first template in the list, and Tail -// for the rest of the list. - -// The empty template list. -struct Templates0 {}; - -// Template lists of length 1, 2, 3, and so on. - -template -struct Templates1 { - typedef TemplateSel Head; - typedef Templates0 Tail; -}; -template -struct Templates2 { - typedef TemplateSel Head; - typedef Templates1 Tail; -}; - -template -struct Templates3 { - typedef TemplateSel Head; - typedef Templates2 Tail; -}; - -template -struct Templates4 { - typedef TemplateSel Head; - typedef Templates3 Tail; -}; - -template -struct Templates5 { - typedef TemplateSel Head; - typedef Templates4 Tail; -}; - -template -struct Templates6 { - typedef TemplateSel Head; - typedef Templates5 Tail; -}; - -template -struct Templates7 { - typedef TemplateSel Head; - typedef Templates6 Tail; -}; - -template -struct Templates8 { - typedef TemplateSel Head; - typedef Templates7 Tail; -}; - -template -struct Templates9 { - typedef TemplateSel Head; - typedef Templates8 Tail; -}; - -template -struct Templates10 { - typedef TemplateSel Head; - typedef Templates9 Tail; -}; - -template -struct Templates11 { - typedef TemplateSel Head; - typedef Templates10 Tail; -}; - -template -struct Templates12 { - typedef TemplateSel Head; - typedef Templates11 Tail; -}; - -template -struct Templates13 { - typedef TemplateSel Head; - typedef Templates12 Tail; -}; - -template -struct Templates14 { - typedef TemplateSel Head; - typedef Templates13 Tail; -}; - -template -struct Templates15 { - typedef TemplateSel Head; - typedef Templates14 Tail; -}; - -template -struct Templates16 { - typedef TemplateSel Head; - typedef Templates15 Tail; -}; - -template -struct Templates17 { - typedef TemplateSel Head; - typedef Templates16 Tail; -}; - -template -struct Templates18 { - typedef TemplateSel Head; - typedef Templates17 Tail; -}; - -template -struct Templates19 { - typedef TemplateSel Head; - typedef Templates18 Tail; -}; - -template -struct Templates20 { - typedef TemplateSel Head; - typedef Templates19 Tail; -}; - -template -struct Templates21 { - typedef TemplateSel Head; - typedef Templates20 Tail; -}; - -template -struct Templates22 { - typedef TemplateSel Head; - typedef Templates21 Tail; -}; - -template -struct Templates23 { - typedef TemplateSel Head; - typedef Templates22 Tail; -}; - -template -struct Templates24 { - typedef TemplateSel Head; - typedef Templates23 Tail; -}; - -template -struct Templates25 { - typedef TemplateSel Head; - typedef Templates24 Tail; -}; - -template -struct Templates26 { - typedef TemplateSel Head; - typedef Templates25 Tail; -}; - -template -struct Templates27 { - typedef TemplateSel Head; - typedef Templates26 Tail; -}; - -template -struct Templates28 { - typedef TemplateSel Head; - typedef Templates27 Tail; -}; - -template -struct Templates29 { - typedef TemplateSel Head; - typedef Templates28 Tail; -}; - -template -struct Templates30 { - typedef TemplateSel Head; - typedef Templates29 Tail; -}; - -template -struct Templates31 { - typedef TemplateSel Head; - typedef Templates30 Tail; -}; - -template -struct Templates32 { - typedef TemplateSel Head; - typedef Templates31 Tail; -}; - -template -struct Templates33 { - typedef TemplateSel Head; - typedef Templates32 Tail; -}; - -template -struct Templates34 { - typedef TemplateSel Head; - typedef Templates33 Tail; -}; - -template -struct Templates35 { - typedef TemplateSel Head; - typedef Templates34 Tail; -}; - -template -struct Templates36 { - typedef TemplateSel Head; - typedef Templates35 Tail; -}; - -template -struct Templates37 { - typedef TemplateSel Head; - typedef Templates36 Tail; -}; - -template -struct Templates38 { - typedef TemplateSel Head; - typedef Templates37 Tail; -}; - -template -struct Templates39 { - typedef TemplateSel Head; - typedef Templates38 Tail; -}; - -template -struct Templates40 { - typedef TemplateSel Head; - typedef Templates39 Tail; -}; - -template -struct Templates41 { - typedef TemplateSel Head; - typedef Templates40 Tail; -}; - -template -struct Templates42 { - typedef TemplateSel Head; - typedef Templates41 Tail; -}; - -template -struct Templates43 { - typedef TemplateSel Head; - typedef Templates42 Tail; -}; - -template -struct Templates44 { - typedef TemplateSel Head; - typedef Templates43 Tail; -}; - -template -struct Templates45 { - typedef TemplateSel Head; - typedef Templates44 Tail; -}; - -template -struct Templates46 { - typedef TemplateSel Head; - typedef Templates45 Tail; -}; - -template -struct Templates47 { - typedef TemplateSel Head; - typedef Templates46 Tail; -}; - -template -struct Templates48 { - typedef TemplateSel Head; - typedef Templates47 Tail; -}; - -template -struct Templates49 { - typedef TemplateSel Head; - typedef Templates48 Tail; -}; - -template -struct Templates50 { - typedef TemplateSel Head; - typedef Templates49 Tail; -}; - - -// We don't want to require the users to write TemplatesN<...> directly, -// as that would require them to count the length. Templates<...> is much -// easier to write, but generates horrible messages when there is a -// compiler error, as gcc insists on printing out each template -// argument, even if it has the default value (this means Templates -// will appear as Templates in the compiler -// errors). -// -// Our solution is to combine the best part of the two approaches: a -// user would write Templates, and Google Test will translate -// that to TemplatesN internally to make error messages -// readable. The translation is done by the 'type' member of the -// Templates template. -template -struct Templates { - typedef Templates50 type; -}; - -template <> -struct Templates { - typedef Templates0 type; -}; -template -struct Templates { - typedef Templates1 type; -}; -template -struct Templates { - typedef Templates2 type; -}; -template -struct Templates { - typedef Templates3 type; -}; -template -struct Templates { - typedef Templates4 type; -}; -template -struct Templates { - typedef Templates5 type; -}; -template -struct Templates { - typedef Templates6 type; -}; -template -struct Templates { - typedef Templates7 type; -}; -template -struct Templates { - typedef Templates8 type; -}; -template -struct Templates { - typedef Templates9 type; -}; -template -struct Templates { - typedef Templates10 type; -}; -template -struct Templates { - typedef Templates11 type; -}; -template -struct Templates { - typedef Templates12 type; -}; -template -struct Templates { - typedef Templates13 type; -}; -template -struct Templates { - typedef Templates14 type; -}; -template -struct Templates { - typedef Templates15 type; -}; -template -struct Templates { - typedef Templates16 type; -}; -template -struct Templates { - typedef Templates17 type; -}; -template -struct Templates { - typedef Templates18 type; -}; -template -struct Templates { - typedef Templates19 type; -}; -template -struct Templates { - typedef Templates20 type; -}; -template -struct Templates { - typedef Templates21 type; -}; -template -struct Templates { - typedef Templates22 type; -}; -template -struct Templates { - typedef Templates23 type; -}; -template -struct Templates { - typedef Templates24 type; -}; -template -struct Templates { - typedef Templates25 type; -}; -template -struct Templates { - typedef Templates26 type; -}; -template -struct Templates { - typedef Templates27 type; -}; -template -struct Templates { - typedef Templates28 type; -}; -template -struct Templates { - typedef Templates29 type; -}; -template -struct Templates { - typedef Templates30 type; -}; -template -struct Templates { - typedef Templates31 type; -}; -template -struct Templates { - typedef Templates32 type; -}; -template -struct Templates { - typedef Templates33 type; -}; -template -struct Templates { - typedef Templates34 type; -}; -template -struct Templates { - typedef Templates35 type; -}; -template -struct Templates { - typedef Templates36 type; -}; -template -struct Templates { - typedef Templates37 type; -}; -template -struct Templates { - typedef Templates38 type; -}; -template -struct Templates { - typedef Templates39 type; -}; -template -struct Templates { - typedef Templates40 type; -}; -template -struct Templates { - typedef Templates41 type; -}; -template -struct Templates { - typedef Templates42 type; -}; -template -struct Templates { - typedef Templates43 type; -}; -template -struct Templates { - typedef Templates44 type; -}; -template -struct Templates { - typedef Templates45 type; -}; -template -struct Templates { - typedef Templates46 type; -}; -template -struct Templates { - typedef Templates47 type; -}; -template -struct Templates { - typedef Templates48 type; -}; -template -struct Templates { - typedef Templates49 type; -}; - -// The TypeList template makes it possible to use either a single type -// or a Types<...> list in TYPED_TEST_CASE() and -// INSTANTIATE_TYPED_TEST_CASE_P(). - -template -struct TypeList { - typedef Types1 type; -}; - -template -struct TypeList > { - typedef typename Types::type type; -}; - -#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ \ No newline at end of file diff --git a/src/gtest/src/gtest-all.cc b/src/gtest/src/gtest-all.cc deleted file mode 100644 index 1456875a..00000000 --- a/src/gtest/src/gtest-all.cc +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2008 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// -// -// Google C++ Testing Framework (Google Test) -// -// Sometimes it's desirable to build Google Test by compiling a single file. -// This file serves this purpose. - -// This line ensures that gtest.h can be compiled on its own, even -// when it's fused. -#include "gtest/gtest.h" - -// The following lines pull in the real gtest *.cc files. -#include "src/gtest.cc" -#include "src/gtest-death-test.cc" -#include "src/gtest-filepath.cc" -#include "src/gtest-port.cc" -#include "src/gtest-printers.cc" -#include "src/gtest-test-part.cc" -#include "src/gtest-typed-test.cc" \ No newline at end of file diff --git a/src/gtest/src/gtest-death-test.cc b/src/gtest/src/gtest-death-test.cc deleted file mode 100644 index 4c9a4071..00000000 --- a/src/gtest/src/gtest-death-test.cc +++ /dev/null @@ -1,1358 +0,0 @@ -// Copyright 2005 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// -// -// This file implements death tests. - -#include "gtest/gtest-death-test.h" -#include "gtest/internal/gtest-port.h" - -#if GTEST_HAS_DEATH_TEST - -# if GTEST_OS_MAC -# include -# endif // GTEST_OS_MAC - -# include -# include -# include - -# if GTEST_OS_LINUX -# include -# endif // GTEST_OS_LINUX - -# include - -# if GTEST_OS_WINDOWS -# include -# else -# include -# include -# endif // GTEST_OS_WINDOWS - -# if GTEST_OS_QNX -# include -# endif // GTEST_OS_QNX - -#endif // GTEST_HAS_DEATH_TEST - -#include "gtest/gtest-message.h" -#include "gtest/internal/gtest-string.h" - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick exists to -// prevent the accidental inclusion of gtest-internal-inl.h in the -// user's code. -#define GTEST_IMPLEMENTATION_ 1 -#include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ - -namespace testing { - -// Constants. - -// The default death test style. -static const char kDefaultDeathTestStyle[] = "fast"; - -GTEST_DEFINE_string_( - death_test_style, - internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), - "Indicates how to run a death test in a forked child process: " - "\"threadsafe\" (child process re-executes the test binary " - "from the beginning, running only the specific death test) or " - "\"fast\" (child process runs the death test immediately " - "after forking)."); - -GTEST_DEFINE_bool_( - death_test_use_fork, - internal::BoolFromGTestEnv("death_test_use_fork", false), - "Instructs to use fork()/_exit() instead of clone() in death tests. " - "Ignored and always uses fork() on POSIX systems where clone() is not " - "implemented. Useful when running under valgrind or similar tools if " - "those do not support clone(). Valgrind 3.3.1 will just fail if " - "it sees an unsupported combination of clone() flags. " - "It is not recommended to use this flag w/o valgrind though it will " - "work in 99% of the cases. Once valgrind is fixed, this flag will " - "most likely be removed."); - -namespace internal { -GTEST_DEFINE_string_( - internal_run_death_test, "", - "Indicates the file, line number, temporal index of " - "the single death test to run, and a file descriptor to " - "which a success code may be sent, all separated by " - "the '|' characters. This flag is specified if and only if the current " - "process is a sub-process launched for running a thread-safe " - "death test. FOR INTERNAL USE ONLY."); -} // namespace internal - -#if GTEST_HAS_DEATH_TEST - -namespace internal { - -// Valid only for fast death tests. Indicates the code is running in the -// child process of a fast style death test. -static bool g_in_fast_death_test_child = false; - -// Returns a Boolean value indicating whether the caller is currently -// executing in the context of the death test child process. Tools such as -// Valgrind heap checkers may need this to modify their behavior in death -// tests. IMPORTANT: This is an internal utility. Using it may break the -// implementation of death tests. User code MUST NOT use it. -bool InDeathTestChild() { -# if GTEST_OS_WINDOWS - - // On Windows, death tests are thread-safe regardless of the value of the - // death_test_style flag. - return !GTEST_FLAG(internal_run_death_test).empty(); - -# else - - if (GTEST_FLAG(death_test_style) == "threadsafe") - return !GTEST_FLAG(internal_run_death_test).empty(); - else - return g_in_fast_death_test_child; -#endif -} - -} // namespace internal - -// ExitedWithCode constructor. -ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { -} - -// ExitedWithCode function-call operator. -bool ExitedWithCode::operator()(int exit_status) const { -# if GTEST_OS_WINDOWS - - return exit_status == exit_code_; - -# else - - return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; - -# endif // GTEST_OS_WINDOWS -} - -# if !GTEST_OS_WINDOWS -// KilledBySignal constructor. -KilledBySignal::KilledBySignal(int signum) : signum_(signum) { -} - -// KilledBySignal function-call operator. -bool KilledBySignal::operator()(int exit_status) const { - return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; -} -# endif // !GTEST_OS_WINDOWS - -namespace internal { - -// Utilities needed for death tests. - -// Generates a textual description of a given exit code, in the format -// specified by wait(2). -static std::string ExitSummary(int exit_code) { - Message m; - -# if GTEST_OS_WINDOWS - - m << "Exited with exit status " << exit_code; - -# else - - if (WIFEXITED(exit_code)) { - m << "Exited with exit status " << WEXITSTATUS(exit_code); - } else if (WIFSIGNALED(exit_code)) { - m << "Terminated by signal " << WTERMSIG(exit_code); - } -# ifdef WCOREDUMP - if (WCOREDUMP(exit_code)) { - m << " (core dumped)"; - } -# endif -# endif // GTEST_OS_WINDOWS - - return m.GetString(); -} - -// Returns true if exit_status describes a process that was terminated -// by a signal, or exited normally with a nonzero exit code. -bool ExitedUnsuccessfully(int exit_status) { - return !ExitedWithCode(0)(exit_status); -} - -# if !GTEST_OS_WINDOWS -// Generates a textual failure message when a death test finds more than -// one thread running, or cannot determine the number of threads, prior -// to executing the given statement. It is the responsibility of the -// caller not to pass a thread_count of 1. -static std::string DeathTestThreadWarning(size_t thread_count) { - Message msg; - msg << "Death tests use fork(), which is unsafe particularly" - << " in a threaded context. For this test, " << GTEST_NAME_ << " "; - if (thread_count == 0) - msg << "couldn't detect the number of threads."; - else - msg << "detected " << thread_count << " threads."; - return msg.GetString(); -} -# endif // !GTEST_OS_WINDOWS - -// Flag characters for reporting a death test that did not die. -static const char kDeathTestLived = 'L'; -static const char kDeathTestReturned = 'R'; -static const char kDeathTestThrew = 'T'; -static const char kDeathTestInternalError = 'I'; - -// An enumeration describing all of the possible ways that a death test can -// conclude. DIED means that the process died while executing the test -// code; LIVED means that process lived beyond the end of the test code; -// RETURNED means that the test statement attempted to execute a return -// statement, which is not allowed; THREW means that the test statement -// returned control by throwing an exception. IN_PROGRESS means the test -// has not yet concluded. -// TODO(vladl@google.com): Unify names and possibly values for -// AbortReason, DeathTestOutcome, and flag characters above. -enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; - -// Routine for aborting the program which is safe to call from an -// exec-style death test child process, in which case the error -// message is propagated back to the parent process. Otherwise, the -// message is simply printed to stderr. In either case, the program -// then exits with status 1. -void DeathTestAbort(const std::string& message) { - // On a POSIX system, this function may be called from a threadsafe-style - // death test child process, which operates on a very small stack. Use - // the heap for any additional non-minuscule memory requirements. - const InternalRunDeathTestFlag* const flag = - GetUnitTestImpl()->internal_run_death_test_flag(); - if (flag != NULL) { - FILE* parent = posix::FDOpen(flag->write_fd(), "w"); - fputc(kDeathTestInternalError, parent); - fprintf(parent, "%s", message.c_str()); - fflush(parent); - _exit(1); - } else { - fprintf(stderr, "%s", message.c_str()); - fflush(stderr); - posix::Abort(); - } -} - -// A replacement for CHECK that calls DeathTestAbort if the assertion -// fails. -# define GTEST_DEATH_TEST_CHECK_(expression) \ - do { \ - if (!::testing::internal::IsTrue(expression)) { \ - DeathTestAbort( \ - ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ - + ::testing::internal::StreamableToString(__LINE__) + ": " \ - + #expression); \ - } \ - } while (::testing::internal::AlwaysFalse()) - -// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for -// evaluating any system call that fulfills two conditions: it must return -// -1 on failure, and set errno to EINTR when it is interrupted and -// should be tried again. The macro expands to a loop that repeatedly -// evaluates the expression as long as it evaluates to -1 and sets -// errno to EINTR. If the expression evaluates to -1 but errno is -// something other than EINTR, DeathTestAbort is called. -# define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ - do { \ - int gtest_retval; \ - do { \ - gtest_retval = (expression); \ - } while (gtest_retval == -1 && errno == EINTR); \ - if (gtest_retval == -1) { \ - DeathTestAbort( \ - ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ - + ::testing::internal::StreamableToString(__LINE__) + ": " \ - + #expression + " != -1"); \ - } \ - } while (::testing::internal::AlwaysFalse()) - -// Returns the message describing the last system error in errno. -std::string GetLastErrnoDescription() { - return errno == 0 ? "" : posix::StrError(errno); -} - -// This is called from a death test parent process to read a failure -// message from the death test child process and log it with the FATAL -// severity. On Windows, the message is read from a pipe handle. On other -// platforms, it is read from a file descriptor. -static void FailFromInternalError(int fd) { - Message error; - char buffer[256]; - int num_read; - - do { - while ((num_read = posix::Read(fd, buffer, 255)) > 0) { - buffer[num_read] = '\0'; - error << buffer; - } - } while (num_read == -1 && errno == EINTR); - - if (num_read == 0) { - GTEST_LOG_(FATAL) << error.GetString(); - } else { - const int last_error = errno; - GTEST_LOG_(FATAL) << "Error while reading death test internal: " - << GetLastErrnoDescription() << " [" << last_error << "]"; - } -} - -// Death test constructor. Increments the running death test count -// for the current test. -DeathTest::DeathTest() { - TestInfo* const info = GetUnitTestImpl()->current_test_info(); - if (info == NULL) { - DeathTestAbort("Cannot run a death test outside of a TEST or " - "TEST_F construct"); - } -} - -// Creates and returns a death test by dispatching to the current -// death test factory. -bool DeathTest::Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test) { - return GetUnitTestImpl()->death_test_factory()->Create( - statement, regex, file, line, test); -} - -const char* DeathTest::LastMessage() { - return last_death_test_message_.c_str(); -} - -void DeathTest::set_last_death_test_message(const std::string& message) { - last_death_test_message_ = message; -} - -std::string DeathTest::last_death_test_message_; - -// Provides cross platform implementation for some death functionality. -class DeathTestImpl : public DeathTest { - protected: - DeathTestImpl(const char* a_statement, const RE* a_regex) - : statement_(a_statement), - regex_(a_regex), - spawned_(false), - status_(-1), - outcome_(IN_PROGRESS), - read_fd_(-1), - write_fd_(-1) {} - - // read_fd_ is expected to be closed and cleared by a derived class. - ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } - - void Abort(AbortReason reason); - virtual bool Passed(bool status_ok); - - const char* statement() const { return statement_; } - const RE* regex() const { return regex_; } - bool spawned() const { return spawned_; } - void set_spawned(bool is_spawned) { spawned_ = is_spawned; } - int status() const { return status_; } - void set_status(int a_status) { status_ = a_status; } - DeathTestOutcome outcome() const { return outcome_; } - void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } - int read_fd() const { return read_fd_; } - void set_read_fd(int fd) { read_fd_ = fd; } - int write_fd() const { return write_fd_; } - void set_write_fd(int fd) { write_fd_ = fd; } - - // Called in the parent process only. Reads the result code of the death - // test child process via a pipe, interprets it to set the outcome_ - // member, and closes read_fd_. Outputs diagnostics and terminates in - // case of unexpected codes. - void ReadAndInterpretStatusByte(); - - private: - // The textual content of the code this object is testing. This class - // doesn't own this string and should not attempt to delete it. - const char* const statement_; - // The regular expression which test output must match. DeathTestImpl - // doesn't own this object and should not attempt to delete it. - const RE* const regex_; - // True if the death test child process has been successfully spawned. - bool spawned_; - // The exit status of the child process. - int status_; - // How the death test concluded. - DeathTestOutcome outcome_; - // Descriptor to the read end of the pipe to the child process. It is - // always -1 in the child process. The child keeps its write end of the - // pipe in write_fd_. - int read_fd_; - // Descriptor to the child's write end of the pipe to the parent process. - // It is always -1 in the parent process. The parent keeps its end of the - // pipe in read_fd_. - int write_fd_; -}; - -// Called in the parent process only. Reads the result code of the death -// test child process via a pipe, interprets it to set the outcome_ -// member, and closes read_fd_. Outputs diagnostics and terminates in -// case of unexpected codes. -void DeathTestImpl::ReadAndInterpretStatusByte() { - char flag; - int bytes_read; - - // The read() here blocks until data is available (signifying the - // failure of the death test) or until the pipe is closed (signifying - // its success), so it's okay to call this in the parent before - // the child process has exited. - do { - bytes_read = posix::Read(read_fd(), &flag, 1); - } while (bytes_read == -1 && errno == EINTR); - - if (bytes_read == 0) { - set_outcome(DIED); - } else if (bytes_read == 1) { - switch (flag) { - case kDeathTestReturned: - set_outcome(RETURNED); - break; - case kDeathTestThrew: - set_outcome(THREW); - break; - case kDeathTestLived: - set_outcome(LIVED); - break; - case kDeathTestInternalError: - FailFromInternalError(read_fd()); // Does not return. - break; - default: - GTEST_LOG_(FATAL) << "Death test child process reported " - << "unexpected status byte (" - << static_cast(flag) << ")"; - } - } else { - GTEST_LOG_(FATAL) << "Read from death test child process failed: " - << GetLastErrnoDescription(); - } - GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); - set_read_fd(-1); -} - -// Signals that the death test code which should have exited, didn't. -// Should be called only in a death test child process. -// Writes a status byte to the child's status file descriptor, then -// calls _exit(1). -void DeathTestImpl::Abort(AbortReason reason) { - // The parent process considers the death test to be a failure if - // it finds any data in our pipe. So, here we write a single flag byte - // to the pipe, then exit. - const char status_ch = - reason == TEST_DID_NOT_DIE ? kDeathTestLived : - reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned; - - GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); - // We are leaking the descriptor here because on some platforms (i.e., - // when built as Windows DLL), destructors of global objects will still - // run after calling _exit(). On such systems, write_fd_ will be - // indirectly closed from the destructor of UnitTestImpl, causing double - // close if it is also closed here. On debug configurations, double close - // may assert. As there are no in-process buffers to flush here, we are - // relying on the OS to close the descriptor after the process terminates - // when the destructors are not run. - _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) -} - -// Returns an indented copy of stderr output for a death test. -// This makes distinguishing death test output lines from regular log lines -// much easier. -static ::std::string FormatDeathTestOutput(const ::std::string& output) { - ::std::string ret; - for (size_t at = 0; ; ) { - const size_t line_end = output.find('\n', at); - ret += "[ DEATH ] "; - if (line_end == ::std::string::npos) { - ret += output.substr(at); - break; - } - ret += output.substr(at, line_end + 1 - at); - at = line_end + 1; - } - return ret; -} - -// Assesses the success or failure of a death test, using both private -// members which have previously been set, and one argument: -// -// Private data members: -// outcome: An enumeration describing how the death test -// concluded: DIED, LIVED, THREW, or RETURNED. The death test -// fails in the latter three cases. -// status: The exit status of the child process. On *nix, it is in the -// in the format specified by wait(2). On Windows, this is the -// value supplied to the ExitProcess() API or a numeric code -// of the exception that terminated the program. -// regex: A regular expression object to be applied to -// the test's captured standard error output; the death test -// fails if it does not match. -// -// Argument: -// status_ok: true if exit_status is acceptable in the context of -// this particular death test, which fails if it is false -// -// Returns true iff all of the above conditions are met. Otherwise, the -// first failing condition, in the order given above, is the one that is -// reported. Also sets the last death test message string. -bool DeathTestImpl::Passed(bool status_ok) { - if (!spawned()) - return false; - - const std::string error_message = GetCapturedStderr(); - - bool success = false; - Message buffer; - - buffer << "Death test: " << statement() << "\n"; - switch (outcome()) { - case LIVED: - buffer << " Result: failed to die.\n" - << " Error msg:\n" << FormatDeathTestOutput(error_message); - break; - case THREW: - buffer << " Result: threw an exception.\n" - << " Error msg:\n" << FormatDeathTestOutput(error_message); - break; - case RETURNED: - buffer << " Result: illegal return in test statement.\n" - << " Error msg:\n" << FormatDeathTestOutput(error_message); - break; - case DIED: - if (status_ok) { - const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); - if (matched) { - success = true; - } else { - buffer << " Result: died but not with expected error.\n" - << " Expected: " << regex()->pattern() << "\n" - << "Actual msg:\n" << FormatDeathTestOutput(error_message); - } - } else { - buffer << " Result: died but not with expected exit code:\n" - << " " << ExitSummary(status()) << "\n" - << "Actual msg:\n" << FormatDeathTestOutput(error_message); - } - break; - case IN_PROGRESS: - default: - GTEST_LOG_(FATAL) - << "DeathTest::Passed somehow called before conclusion of test"; - } - - DeathTest::set_last_death_test_message(buffer.GetString()); - return success; -} - -# if GTEST_OS_WINDOWS -// WindowsDeathTest implements death tests on Windows. Due to the -// specifics of starting new processes on Windows, death tests there are -// always threadsafe, and Google Test considers the -// --gtest_death_test_style=fast setting to be equivalent to -// --gtest_death_test_style=threadsafe there. -// -// A few implementation notes: Like the Linux version, the Windows -// implementation uses pipes for child-to-parent communication. But due to -// the specifics of pipes on Windows, some extra steps are required: -// -// 1. The parent creates a communication pipe and stores handles to both -// ends of it. -// 2. The parent starts the child and provides it with the information -// necessary to acquire the handle to the write end of the pipe. -// 3. The child acquires the write end of the pipe and signals the parent -// using a Windows event. -// 4. Now the parent can release the write end of the pipe on its side. If -// this is done before step 3, the object's reference count goes down to -// 0 and it is destroyed, preventing the child from acquiring it. The -// parent now has to release it, or read operations on the read end of -// the pipe will not return when the child terminates. -// 5. The parent reads child's output through the pipe (outcome code and -// any possible error messages) from the pipe, and its stderr and then -// determines whether to fail the test. -// -// Note: to distinguish Win32 API calls from the local method and function -// calls, the former are explicitly resolved in the global namespace. -// -class WindowsDeathTest : public DeathTestImpl { - public: - WindowsDeathTest(const char* a_statement, - const RE* a_regex, - const char* file, - int line) - : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} - - // All of these virtual functions are inherited from DeathTest. - virtual int Wait(); - virtual TestRole AssumeRole(); - - private: - // The name of the file in which the death test is located. - const char* const file_; - // The line number on which the death test is located. - const int line_; - // Handle to the write end of the pipe to the child process. - AutoHandle write_handle_; - // Child process handle. - AutoHandle child_handle_; - // Event the child process uses to signal the parent that it has - // acquired the handle to the write end of the pipe. After seeing this - // event the parent can release its own handles to make sure its - // ReadFile() calls return when the child terminates. - AutoHandle event_handle_; -}; - -// Waits for the child in a death test to exit, returning its exit -// status, or 0 if no child process exists. As a side effect, sets the -// outcome data member. -int WindowsDeathTest::Wait() { - if (!spawned()) - return 0; - - // Wait until the child either signals that it has acquired the write end - // of the pipe or it dies. - const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; - switch (::WaitForMultipleObjects(2, - wait_handles, - FALSE, // Waits for any of the handles. - INFINITE)) { - case WAIT_OBJECT_0: - case WAIT_OBJECT_0 + 1: - break; - default: - GTEST_DEATH_TEST_CHECK_(false); // Should not get here. - } - - // The child has acquired the write end of the pipe or exited. - // We release the handle on our side and continue. - write_handle_.Reset(); - event_handle_.Reset(); - - ReadAndInterpretStatusByte(); - - // Waits for the child process to exit if it haven't already. This - // returns immediately if the child has already exited, regardless of - // whether previous calls to WaitForMultipleObjects synchronized on this - // handle or not. - GTEST_DEATH_TEST_CHECK_( - WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), - INFINITE)); - DWORD status_code; - GTEST_DEATH_TEST_CHECK_( - ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE); - child_handle_.Reset(); - set_status(static_cast(status_code)); - return status(); -} - -// The AssumeRole process for a Windows death test. It creates a child -// process with the same executable as the current process to run the -// death test. The child process is given the --gtest_filter and -// --gtest_internal_run_death_test flags such that it knows to run the -// current death test only. -DeathTest::TestRole WindowsDeathTest::AssumeRole() { - const UnitTestImpl* const impl = GetUnitTestImpl(); - const InternalRunDeathTestFlag* const flag = - impl->internal_run_death_test_flag(); - const TestInfo* const info = impl->current_test_info(); - const int death_test_index = info->result()->death_test_count(); - - if (flag != NULL) { - // ParseInternalRunDeathTestFlag() has performed all the necessary - // processing. - set_write_fd(flag->write_fd()); - return EXECUTE_TEST; - } - - // WindowsDeathTest uses an anonymous pipe to communicate results of - // a death test. - SECURITY_ATTRIBUTES handles_are_inheritable = { - sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; - HANDLE read_handle, write_handle; - GTEST_DEATH_TEST_CHECK_( - ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, - 0) // Default buffer size. - != FALSE); - set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), - O_RDONLY)); - write_handle_.Reset(write_handle); - event_handle_.Reset(::CreateEvent( - &handles_are_inheritable, - TRUE, // The event will automatically reset to non-signaled state. - FALSE, // The initial state is non-signalled. - NULL)); // The even is unnamed. - GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); - const std::string filter_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + - info->test_case_name() + "." + info->name(); - const std::string internal_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + - "=" + file_ + "|" + StreamableToString(line_) + "|" + - StreamableToString(death_test_index) + "|" + - StreamableToString(static_cast(::GetCurrentProcessId())) + - // size_t has the same width as pointers on both 32-bit and 64-bit - // Windows platforms. - // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. - "|" + StreamableToString(reinterpret_cast(write_handle)) + - "|" + StreamableToString(reinterpret_cast(event_handle_.Get())); - - char executable_path[_MAX_PATH + 1]; // NOLINT - GTEST_DEATH_TEST_CHECK_( - _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, - executable_path, - _MAX_PATH)); - - std::string command_line = - std::string(::GetCommandLineA()) + " " + filter_flag + " \"" + - internal_flag + "\""; - - DeathTest::set_last_death_test_message(""); - - CaptureStderr(); - // Flush the log buffers since the log streams are shared with the child. - FlushInfoLog(); - - // The child process will share the standard handles with the parent. - STARTUPINFOA startup_info; - memset(&startup_info, 0, sizeof(STARTUPINFO)); - startup_info.dwFlags = STARTF_USESTDHANDLES; - startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); - startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); - startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); - - PROCESS_INFORMATION process_info; - GTEST_DEATH_TEST_CHECK_(::CreateProcessA( - executable_path, - const_cast(command_line.c_str()), - NULL, // Retuned process handle is not inheritable. - NULL, // Retuned thread handle is not inheritable. - TRUE, // Child inherits all inheritable handles (for write_handle_). - 0x0, // Default creation flags. - NULL, // Inherit the parent's environment. - UnitTest::GetInstance()->original_working_dir(), - &startup_info, - &process_info) != FALSE); - child_handle_.Reset(process_info.hProcess); - ::CloseHandle(process_info.hThread); - set_spawned(true); - return OVERSEE_TEST; -} -# else // We are not on Windows. - -// ForkingDeathTest provides implementations for most of the abstract -// methods of the DeathTest interface. Only the AssumeRole method is -// left undefined. -class ForkingDeathTest : public DeathTestImpl { - public: - ForkingDeathTest(const char* statement, const RE* regex); - - // All of these virtual functions are inherited from DeathTest. - virtual int Wait(); - - protected: - void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } - - private: - // PID of child process during death test; 0 in the child process itself. - pid_t child_pid_; -}; - -// Constructs a ForkingDeathTest. -ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) - : DeathTestImpl(a_statement, a_regex), - child_pid_(-1) {} - -// Waits for the child in a death test to exit, returning its exit -// status, or 0 if no child process exists. As a side effect, sets the -// outcome data member. -int ForkingDeathTest::Wait() { - if (!spawned()) - return 0; - - ReadAndInterpretStatusByte(); - - int status_value; - GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); - set_status(status_value); - return status_value; -} - -// A concrete death test class that forks, then immediately runs the test -// in the child process. -class NoExecDeathTest : public ForkingDeathTest { - public: - NoExecDeathTest(const char* a_statement, const RE* a_regex) : - ForkingDeathTest(a_statement, a_regex) { } - virtual TestRole AssumeRole(); -}; - -// The AssumeRole process for a fork-and-run death test. It implements a -// straightforward fork, with a simple pipe to transmit the status byte. -DeathTest::TestRole NoExecDeathTest::AssumeRole() { - const size_t thread_count = GetThreadCount(); - if (thread_count != 1) { - GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); - } - - int pipe_fd[2]; - GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); - - DeathTest::set_last_death_test_message(""); - CaptureStderr(); - // When we fork the process below, the log file buffers are copied, but the - // file descriptors are shared. We flush all log files here so that closing - // the file descriptors in the child process doesn't throw off the - // synchronization between descriptors and buffers in the parent process. - // This is as close to the fork as possible to avoid a race condition in case - // there are multiple threads running before the death test, and another - // thread writes to the log file. - FlushInfoLog(); - - const pid_t child_pid = fork(); - GTEST_DEATH_TEST_CHECK_(child_pid != -1); - set_child_pid(child_pid); - if (child_pid == 0) { - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); - set_write_fd(pipe_fd[1]); - // Redirects all logging to stderr in the child process to prevent - // concurrent writes to the log files. We capture stderr in the parent - // process and append the child process' output to a log. - LogToStderr(); - // Event forwarding to the listeners of event listener API mush be shut - // down in death test subprocesses. - GetUnitTestImpl()->listeners()->SuppressEventForwarding(); - g_in_fast_death_test_child = true; - return EXECUTE_TEST; - } else { - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); - set_read_fd(pipe_fd[0]); - set_spawned(true); - return OVERSEE_TEST; - } -} - -// A concrete death test class that forks and re-executes the main -// program from the beginning, with command-line flags set that cause -// only this specific death test to be run. -class ExecDeathTest : public ForkingDeathTest { - public: - ExecDeathTest(const char* a_statement, const RE* a_regex, - const char* file, int line) : - ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } - virtual TestRole AssumeRole(); - private: - static ::std::vector - GetArgvsForDeathTestChildProcess() { - ::std::vector args = GetInjectableArgvs(); - return args; - } - // The name of the file in which the death test is located. - const char* const file_; - // The line number on which the death test is located. - const int line_; -}; - -// Utility class for accumulating command-line arguments. -class Arguments { - public: - Arguments() { - args_.push_back(NULL); - } - - ~Arguments() { - for (std::vector::iterator i = args_.begin(); i != args_.end(); - ++i) { - free(*i); - } - } - void AddArgument(const char* argument) { - args_.insert(args_.end() - 1, posix::StrDup(argument)); - } - - template - void AddArguments(const ::std::vector& arguments) { - for (typename ::std::vector::const_iterator i = arguments.begin(); - i != arguments.end(); - ++i) { - args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); - } - } - char* const* Argv() { - return &args_[0]; - } - - private: - std::vector args_; -}; - -// A struct that encompasses the arguments to the child process of a -// threadsafe-style death test process. -struct ExecDeathTestArgs { - char* const* argv; // Command-line arguments for the child's call to exec - int close_fd; // File descriptor to close; the read end of a pipe -}; - -# if GTEST_OS_MAC -inline char** GetEnviron() { - // When Google Test is built as a framework on MacOS X, the environ variable - // is unavailable. Apple's documentation (man environ) recommends using - // _NSGetEnviron() instead. - return *_NSGetEnviron(); -} -# else -// Some POSIX platforms expect you to declare environ. extern "C" makes -// it reside in the global namespace. -extern "C" char** environ; -inline char** GetEnviron() { return environ; } -# endif // GTEST_OS_MAC - -# if !GTEST_OS_QNX -// The main function for a threadsafe-style death test child process. -// This function is called in a clone()-ed process and thus must avoid -// any potentially unsafe operations like malloc or libc functions. -static int ExecDeathTestChildMain(void* child_arg) { - ExecDeathTestArgs* const args = static_cast(child_arg); - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); - - // We need to execute the test program in the same environment where - // it was originally invoked. Therefore we change to the original - // working directory first. - const char* const original_dir = - UnitTest::GetInstance()->original_working_dir(); - // We can safely call chdir() as it's a direct system call. - if (chdir(original_dir) != 0) { - DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + - GetLastErrnoDescription()); - return EXIT_FAILURE; - } - - // We can safely call execve() as it's a direct system call. We - // cannot use execvp() as it's a libc function and thus potentially - // unsafe. Since execve() doesn't search the PATH, the user must - // invoke the test program via a valid path that contains at least - // one path separator. - execve(args->argv[0], args->argv, GetEnviron()); - DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " + - original_dir + " failed: " + - GetLastErrnoDescription()); - return EXIT_FAILURE; -} -# endif // !GTEST_OS_QNX - -// Two utility routines that together determine the direction the stack -// grows. -// This could be accomplished more elegantly by a single recursive -// function, but we want to guard against the unlikely possibility of -// a smart compiler optimizing the recursion away. -// -// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining -// StackLowerThanAddress into StackGrowsDown, which then doesn't give -// correct answer. -void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_; -void StackLowerThanAddress(const void* ptr, bool* result) { - int dummy; - *result = (&dummy < ptr); -} - -// Make sure AddressSanitizer does not tamper with the stack here. -GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ -bool StackGrowsDown() { - int dummy; - bool result; - StackLowerThanAddress(&dummy, &result); - return result; -} - -// Spawns a child process with the same executable as the current process in -// a thread-safe manner and instructs it to run the death test. The -// implementation uses fork(2) + exec. On systems where clone(2) is -// available, it is used instead, being slightly more thread-safe. On QNX, -// fork supports only single-threaded environments, so this function uses -// spawn(2) there instead. The function dies with an error message if -// anything goes wrong. -static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { - ExecDeathTestArgs args = { argv, close_fd }; - pid_t child_pid = -1; - -# if GTEST_OS_QNX - // Obtains the current directory and sets it to be closed in the child - // process. - const int cwd_fd = open(".", O_RDONLY); - GTEST_DEATH_TEST_CHECK_(cwd_fd != -1); - GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC)); - // We need to execute the test program in the same environment where - // it was originally invoked. Therefore we change to the original - // working directory first. - const char* const original_dir = - UnitTest::GetInstance()->original_working_dir(); - // We can safely call chdir() as it's a direct system call. - if (chdir(original_dir) != 0) { - DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + - GetLastErrnoDescription()); - return EXIT_FAILURE; - } - - int fd_flags; - // Set close_fd to be closed after spawn. - GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD)); - GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD, - fd_flags | FD_CLOEXEC)); - struct inheritance inherit = {0}; - // spawn is a system call. - child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron()); - // Restores the current working directory. - GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); - -# else // GTEST_OS_QNX -# if GTEST_OS_LINUX - // When a SIGPROF signal is received while fork() or clone() are executing, - // the process may hang. To avoid this, we ignore SIGPROF here and re-enable - // it after the call to fork()/clone() is complete. - struct sigaction saved_sigprof_action; - struct sigaction ignore_sigprof_action; - memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action)); - sigemptyset(&ignore_sigprof_action.sa_mask); - ignore_sigprof_action.sa_handler = SIG_IGN; - GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction( - SIGPROF, &ignore_sigprof_action, &saved_sigprof_action)); -# endif // GTEST_OS_LINUX - -# if GTEST_HAS_CLONE - const bool use_fork = GTEST_FLAG(death_test_use_fork); - - if (!use_fork) { - static const bool stack_grows_down = StackGrowsDown(); - const size_t stack_size = getpagesize(); - // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. - void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_PRIVATE, -1, 0); - GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); - - // Maximum stack alignment in bytes: For a downward-growing stack, this - // amount is subtracted from size of the stack space to get an address - // that is within the stack space and is aligned on all systems we care - // about. As far as I know there is no ABI with stack alignment greater - // than 64. We assume stack and stack_size already have alignment of - // kMaxStackAlignment. - const size_t kMaxStackAlignment = 64; - void* const stack_top = - static_cast(stack) + - (stack_grows_down ? stack_size - kMaxStackAlignment : 0); - GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment && - reinterpret_cast(stack_top) % kMaxStackAlignment == 0); - - child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); - - GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); - } -# else - const bool use_fork = true; -# endif // GTEST_HAS_CLONE - - if (use_fork && (child_pid = fork()) == 0) { - ExecDeathTestChildMain(&args); - _exit(0); - } -# endif // GTEST_OS_QNX -# if GTEST_OS_LINUX - GTEST_DEATH_TEST_CHECK_SYSCALL_( - sigaction(SIGPROF, &saved_sigprof_action, NULL)); -# endif // GTEST_OS_LINUX - - GTEST_DEATH_TEST_CHECK_(child_pid != -1); - return child_pid; -} - -// The AssumeRole process for a fork-and-exec death test. It re-executes the -// main program from the beginning, setting the --gtest_filter -// and --gtest_internal_run_death_test flags to cause only the current -// death test to be re-run. -DeathTest::TestRole ExecDeathTest::AssumeRole() { - const UnitTestImpl* const impl = GetUnitTestImpl(); - const InternalRunDeathTestFlag* const flag = - impl->internal_run_death_test_flag(); - const TestInfo* const info = impl->current_test_info(); - const int death_test_index = info->result()->death_test_count(); - - if (flag != NULL) { - set_write_fd(flag->write_fd()); - return EXECUTE_TEST; - } - - int pipe_fd[2]; - GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); - // Clear the close-on-exec flag on the write end of the pipe, lest - // it be closed when the child process does an exec: - GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); - - const std::string filter_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" - + info->test_case_name() + "." + info->name(); - const std::string internal_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" - + file_ + "|" + StreamableToString(line_) + "|" - + StreamableToString(death_test_index) + "|" - + StreamableToString(pipe_fd[1]); - Arguments args; - args.AddArguments(GetArgvsForDeathTestChildProcess()); - args.AddArgument(filter_flag.c_str()); - args.AddArgument(internal_flag.c_str()); - - DeathTest::set_last_death_test_message(""); - - CaptureStderr(); - // See the comment in NoExecDeathTest::AssumeRole for why the next line - // is necessary. - FlushInfoLog(); - - const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]); - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); - set_child_pid(child_pid); - set_read_fd(pipe_fd[0]); - set_spawned(true); - return OVERSEE_TEST; -} - -# endif // !GTEST_OS_WINDOWS - -// Creates a concrete DeathTest-derived class that depends on the -// --gtest_death_test_style flag, and sets the pointer pointed to -// by the "test" argument to its address. If the test should be -// skipped, sets that pointer to NULL. Returns true, unless the -// flag is set to an invalid value. -bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, - const char* file, int line, - DeathTest** test) { - UnitTestImpl* const impl = GetUnitTestImpl(); - const InternalRunDeathTestFlag* const flag = - impl->internal_run_death_test_flag(); - const int death_test_index = impl->current_test_info() - ->increment_death_test_count(); - - if (flag != NULL) { - if (death_test_index > flag->index()) { - DeathTest::set_last_death_test_message( - "Death test count (" + StreamableToString(death_test_index) - + ") somehow exceeded expected maximum (" - + StreamableToString(flag->index()) + ")"); - return false; - } - - if (!(flag->file() == file && flag->line() == line && - flag->index() == death_test_index)) { - *test = NULL; - return true; - } - } - -# if GTEST_OS_WINDOWS - - if (GTEST_FLAG(death_test_style) == "threadsafe" || - GTEST_FLAG(death_test_style) == "fast") { - *test = new WindowsDeathTest(statement, regex, file, line); - } - -# else - - if (GTEST_FLAG(death_test_style) == "threadsafe") { - *test = new ExecDeathTest(statement, regex, file, line); - } else if (GTEST_FLAG(death_test_style) == "fast") { - *test = new NoExecDeathTest(statement, regex); - } - -# endif // GTEST_OS_WINDOWS - - else { // NOLINT - this is more readable than unbalanced brackets inside #if. - DeathTest::set_last_death_test_message( - "Unknown death test style \"" + GTEST_FLAG(death_test_style) - + "\" encountered"); - return false; - } - - return true; -} - -// Splits a given string on a given delimiter, populating a given -// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have -// ::std::string, so we can use it here. -static void SplitString(const ::std::string& str, char delimiter, - ::std::vector< ::std::string>* dest) { - ::std::vector< ::std::string> parsed; - ::std::string::size_type pos = 0; - while (::testing::internal::AlwaysTrue()) { - const ::std::string::size_type colon = str.find(delimiter, pos); - if (colon == ::std::string::npos) { - parsed.push_back(str.substr(pos)); - break; - } else { - parsed.push_back(str.substr(pos, colon - pos)); - pos = colon + 1; - } - } - dest->swap(parsed); -} - -# if GTEST_OS_WINDOWS -// Recreates the pipe and event handles from the provided parameters, -// signals the event, and returns a file descriptor wrapped around the pipe -// handle. This function is called in the child process only. -int GetStatusFileDescriptor(unsigned int parent_process_id, - size_t write_handle_as_size_t, - size_t event_handle_as_size_t) { - AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, - FALSE, // Non-inheritable. - parent_process_id)); - if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { - DeathTestAbort("Unable to open parent process " + - StreamableToString(parent_process_id)); - } - - // TODO(vladl@google.com): Replace the following check with a - // compile-time assertion when available. - GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); - - const HANDLE write_handle = - reinterpret_cast(write_handle_as_size_t); - HANDLE dup_write_handle; - - // The newly initialized handle is accessible only in in the parent - // process. To obtain one accessible within the child, we need to use - // DuplicateHandle. - if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, - ::GetCurrentProcess(), &dup_write_handle, - 0x0, // Requested privileges ignored since - // DUPLICATE_SAME_ACCESS is used. - FALSE, // Request non-inheritable handler. - DUPLICATE_SAME_ACCESS)) { - DeathTestAbort("Unable to duplicate the pipe handle " + - StreamableToString(write_handle_as_size_t) + - " from the parent process " + - StreamableToString(parent_process_id)); - } - - const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); - HANDLE dup_event_handle; - - if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, - ::GetCurrentProcess(), &dup_event_handle, - 0x0, - FALSE, - DUPLICATE_SAME_ACCESS)) { - DeathTestAbort("Unable to duplicate the event handle " + - StreamableToString(event_handle_as_size_t) + - " from the parent process " + - StreamableToString(parent_process_id)); - } - - const int write_fd = - ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); - if (write_fd == -1) { - DeathTestAbort("Unable to convert pipe handle " + - StreamableToString(write_handle_as_size_t) + - " to a file descriptor"); - } - - // Signals the parent that the write end of the pipe has been acquired - // so the parent can release its own write end. - ::SetEvent(dup_event_handle); - - return write_fd; -} -# endif // GTEST_OS_WINDOWS - -// Returns a newly created InternalRunDeathTestFlag object with fields -// initialized from the GTEST_FLAG(internal_run_death_test) flag if -// the flag is specified; otherwise returns NULL. -InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { - if (GTEST_FLAG(internal_run_death_test) == "") return NULL; - - // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we - // can use it here. - int line = -1; - int index = -1; - ::std::vector< ::std::string> fields; - SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); - int write_fd = -1; - -# if GTEST_OS_WINDOWS - - unsigned int parent_process_id = 0; - size_t write_handle_as_size_t = 0; - size_t event_handle_as_size_t = 0; - - if (fields.size() != 6 - || !ParseNaturalNumber(fields[1], &line) - || !ParseNaturalNumber(fields[2], &index) - || !ParseNaturalNumber(fields[3], &parent_process_id) - || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) - || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { - DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + - GTEST_FLAG(internal_run_death_test)); - } - write_fd = GetStatusFileDescriptor(parent_process_id, - write_handle_as_size_t, - event_handle_as_size_t); -# else - - if (fields.size() != 4 - || !ParseNaturalNumber(fields[1], &line) - || !ParseNaturalNumber(fields[2], &index) - || !ParseNaturalNumber(fields[3], &write_fd)) { - DeathTestAbort("Bad --gtest_internal_run_death_test flag: " - + GTEST_FLAG(internal_run_death_test)); - } - -# endif // GTEST_OS_WINDOWS - - return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); -} - -} // namespace internal - -#endif // GTEST_HAS_DEATH_TEST - -} // namespace testing \ No newline at end of file diff --git a/src/gtest/src/gtest-filepath.cc b/src/gtest/src/gtest-filepath.cc deleted file mode 100644 index 97f99ecf..00000000 --- a/src/gtest/src/gtest-filepath.cc +++ /dev/null @@ -1,400 +0,0 @@ -// Copyright 2008 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// -// Authors: keith.ray@gmail.com (Keith Ray) - -#include "gtest/gtest-message.h" -#include "gtest/internal/gtest-filepath.h" -#include "gtest/internal/gtest-port.h" - -#include - -#if GTEST_OS_WINDOWS_MOBILE -# include -#elif GTEST_OS_WINDOWS -# include -# include -#elif GTEST_OS_SYMBIAN -// Symbian OpenC has PATH_MAX in sys/syslimits.h -# include -#else -# include -# include // Some Linux distributions define PATH_MAX here. -#endif // GTEST_OS_WINDOWS_MOBILE - -#if GTEST_OS_WINDOWS -# define GTEST_PATH_MAX_ _MAX_PATH -#elif defined(PATH_MAX) -# define GTEST_PATH_MAX_ PATH_MAX -#elif defined(_XOPEN_PATH_MAX) -# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX -#else -# define GTEST_PATH_MAX_ _POSIX_PATH_MAX -#endif // GTEST_OS_WINDOWS - -#include "gtest/internal/gtest-string.h" - -namespace testing { -namespace internal { - -#if GTEST_OS_WINDOWS -// On Windows, '\\' is the standard path separator, but many tools and the -// Windows API also accept '/' as an alternate path separator. Unless otherwise -// noted, a file path can contain either kind of path separators, or a mixture -// of them. -const char kPathSeparator = '\\'; -const char kAlternatePathSeparator = '/'; -const char kAlternatePathSeparatorString[] = "/"; -# if GTEST_OS_WINDOWS_MOBILE -// Windows CE doesn't have a current directory. You should not use -// the current directory in tests on Windows CE, but this at least -// provides a reasonable fallback. -const char kCurrentDirectoryString[] = "\\"; -// Windows CE doesn't define INVALID_FILE_ATTRIBUTES -const DWORD kInvalidFileAttributes = 0xffffffff; -# else -const char kCurrentDirectoryString[] = ".\\"; -# endif // GTEST_OS_WINDOWS_MOBILE -#else -const char kPathSeparator = '/'; -const char kCurrentDirectoryString[] = "./"; -#endif // GTEST_OS_WINDOWS - -// Returns whether the given character is a valid path separator. -static bool IsPathSeparator(char c) { -#if GTEST_HAS_ALT_PATH_SEP_ - return (c == kPathSeparator) || (c == kAlternatePathSeparator); -#else - return c == kPathSeparator; -#endif -} - -// Returns the current working directory, or "" if unsuccessful. -FilePath FilePath::GetCurrentDir() { -#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT - // Windows CE doesn't have a current directory, so we just return - // something reasonable. - return FilePath(kCurrentDirectoryString); -#elif GTEST_OS_WINDOWS - char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; - return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); -#else - char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; - char* result = getcwd(cwd, sizeof(cwd)); -# if GTEST___nacl__ - // getcwd will likely fail in NaCl due to the sandbox, so return something - // reasonable. The user may have provided a shim implementation for getcwd, - // however, so fallback only when failure is detected. - return FilePath(result == NULL ? kCurrentDirectoryString : cwd); -# endif // GTEST___nacl__ - return FilePath(result == NULL ? "" : cwd); -#endif // GTEST_OS_WINDOWS_MOBILE -} - -// Returns a copy of the FilePath with the case-insensitive extension removed. -// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns -// FilePath("dir/file"). If a case-insensitive extension is not -// found, returns a copy of the original FilePath. -FilePath FilePath::RemoveExtension(const char* extension) const { - const std::string dot_extension = std::string(".") + extension; - if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) { - return FilePath(pathname_.substr( - 0, pathname_.length() - dot_extension.length())); - } - return *this; -} - -// Returns a pointer to the last occurence of a valid path separator in -// the FilePath. On Windows, for example, both '/' and '\' are valid path -// separators. Returns NULL if no path separator was found. -const char* FilePath::FindLastPathSeparator() const { - const char* const last_sep = strrchr(c_str(), kPathSeparator); -#if GTEST_HAS_ALT_PATH_SEP_ - const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); - // Comparing two pointers of which only one is NULL is undefined. - if (last_alt_sep != NULL && - (last_sep == NULL || last_alt_sep > last_sep)) { - return last_alt_sep; - } -#endif - return last_sep; -} - -// Returns a copy of the FilePath with the directory part removed. -// Example: FilePath("path/to/file").RemoveDirectoryName() returns -// FilePath("file"). If there is no directory part ("just_a_file"), it returns -// the FilePath unmodified. If there is no file part ("just_a_dir/") it -// returns an empty FilePath (""). -// On Windows platform, '\' is the path separator, otherwise it is '/'. -FilePath FilePath::RemoveDirectoryName() const { - const char* const last_sep = FindLastPathSeparator(); - return last_sep ? FilePath(last_sep + 1) : *this; -} - -// RemoveFileName returns the directory path with the filename removed. -// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". -// If the FilePath is "a_file" or "/a_file", RemoveFileName returns -// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does -// not have a file, like "just/a/dir/", it returns the FilePath unmodified. -// On Windows platform, '\' is the path separator, otherwise it is '/'. -FilePath FilePath::RemoveFileName() const { - const char* const last_sep = FindLastPathSeparator(); - std::string dir; - if (last_sep) { - dir = std::string(c_str(), last_sep + 1 - c_str()); - } else { - dir = kCurrentDirectoryString; - } - return FilePath(dir); -} - -// Helper functions for naming files in a directory for xml output. - -// Given directory = "dir", base_name = "test", number = 0, -// extension = "xml", returns "dir/test.xml". If number is greater -// than zero (e.g., 12), returns "dir/test_12.xml". -// On Windows platform, uses \ as the separator rather than /. -FilePath FilePath::MakeFileName(const FilePath& directory, - const FilePath& base_name, - int number, - const char* extension) { - std::string file; - if (number == 0) { - file = base_name.string() + "." + extension; - } else { - file = base_name.string() + "_" + StreamableToString(number) - + "." + extension; - } - return ConcatPaths(directory, FilePath(file)); -} - -// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". -// On Windows, uses \ as the separator rather than /. -FilePath FilePath::ConcatPaths(const FilePath& directory, - const FilePath& relative_path) { - if (directory.IsEmpty()) - return relative_path; - const FilePath dir(directory.RemoveTrailingPathSeparator()); - return FilePath(dir.string() + kPathSeparator + relative_path.string()); -} - -// Returns true if pathname describes something findable in the file-system, -// either a file, directory, or whatever. -bool FilePath::FileOrDirectoryExists() const { -#if GTEST_OS_WINDOWS_MOBILE - LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); - const DWORD attributes = GetFileAttributes(unicode); - delete [] unicode; - return attributes != kInvalidFileAttributes; -#else - posix::StatStruct file_stat; - return posix::Stat(pathname_.c_str(), &file_stat) == 0; -#endif // GTEST_OS_WINDOWS_MOBILE -} - -// Returns true if pathname describes a directory in the file-system -// that exists. -bool FilePath::DirectoryExists() const { - bool result = false; -#if GTEST_OS_WINDOWS - // Don't strip off trailing separator if path is a root directory on - // Windows (like "C:\\"). - const FilePath& path(IsRootDirectory() ? *this : - RemoveTrailingPathSeparator()); -#else - const FilePath& path(*this); -#endif - -#if GTEST_OS_WINDOWS_MOBILE - LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); - const DWORD attributes = GetFileAttributes(unicode); - delete [] unicode; - if ((attributes != kInvalidFileAttributes) && - (attributes & FILE_ATTRIBUTE_DIRECTORY)) { - result = true; - } -#else - posix::StatStruct file_stat; - result = posix::Stat(path.c_str(), &file_stat) == 0 && - posix::IsDir(file_stat); -#endif // GTEST_OS_WINDOWS_MOBILE - - return result; -} - -// Returns true if pathname describes a root directory. (Windows has one -// root directory per disk drive.) -bool FilePath::IsRootDirectory() const { -#if GTEST_OS_WINDOWS - // TODO(wan@google.com): on Windows a network share like - // \\server\share can be a root directory, although it cannot be the - // current directory. Handle this properly. - return pathname_.length() == 3 && IsAbsolutePath(); -#else - return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); -#endif -} - -// Returns true if pathname describes an absolute path. -bool FilePath::IsAbsolutePath() const { - const char* const name = pathname_.c_str(); -#if GTEST_OS_WINDOWS - return pathname_.length() >= 3 && - ((name[0] >= 'a' && name[0] <= 'z') || - (name[0] >= 'A' && name[0] <= 'Z')) && - name[1] == ':' && - IsPathSeparator(name[2]); -#else - return IsPathSeparator(name[0]); -#endif -} - -// Returns a pathname for a file that does not currently exist. The pathname -// will be directory/base_name.extension or -// directory/base_name_.extension if directory/base_name.extension -// already exists. The number will be incremented until a pathname is found -// that does not already exist. -// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. -// There could be a race condition if two or more processes are calling this -// function at the same time -- they could both pick the same filename. -FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, - const FilePath& base_name, - const char* extension) { - FilePath full_pathname; - int number = 0; - do { - full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); - } while (full_pathname.FileOrDirectoryExists()); - return full_pathname; -} - -// Returns true if FilePath ends with a path separator, which indicates that -// it is intended to represent a directory. Returns false otherwise. -// This does NOT check that a directory (or file) actually exists. -bool FilePath::IsDirectory() const { - return !pathname_.empty() && - IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]); -} - -// Create directories so that path exists. Returns true if successful or if -// the directories already exist; returns false if unable to create directories -// for any reason. -bool FilePath::CreateDirectoriesRecursively() const { - if (!this->IsDirectory()) { - return false; - } - - if (pathname_.length() == 0 || this->DirectoryExists()) { - return true; - } - - const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); - return parent.CreateDirectoriesRecursively() && this->CreateFolder(); -} - -// Create the directory so that path exists. Returns true if successful or -// if the directory already exists; returns false if unable to create the -// directory for any reason, including if the parent directory does not -// exist. Not named "CreateDirectory" because that's a macro on Windows. -bool FilePath::CreateFolder() const { -#if GTEST_OS_WINDOWS_MOBILE - FilePath removed_sep(this->RemoveTrailingPathSeparator()); - LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); - int result = CreateDirectory(unicode, NULL) ? 0 : -1; - delete [] unicode; -#elif GTEST_OS_WINDOWS - int result = _mkdir(pathname_.c_str()); -#else - int result = mkdir(pathname_.c_str(), 0777); -#endif // GTEST_OS_WINDOWS_MOBILE - - if (result == -1) { - return this->DirectoryExists(); // An error is OK if the directory exists. - } - return true; // No error. -} - -// If input name has a trailing separator character, remove it and return the -// name, otherwise return the name string unmodified. -// On Windows platform, uses \ as the separator, other platforms use /. -FilePath FilePath::RemoveTrailingPathSeparator() const { - return IsDirectory() - ? FilePath(pathname_.substr(0, pathname_.length() - 1)) - : *this; -} - -// Removes any redundant separators that might be in the pathname. -// For example, "bar///foo" becomes "bar/foo". Does not eliminate other -// redundancies that might be in a pathname involving "." or "..". -// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). -void FilePath::Normalize() { - if (pathname_.c_str() == NULL) { - pathname_ = ""; - return; - } - const char* src = pathname_.c_str(); - char* const dest = new char[pathname_.length() + 1]; - char* dest_ptr = dest; - memset(dest_ptr, 0, pathname_.length() + 1); - - while (*src != '\0') { - *dest_ptr = *src; - if (!IsPathSeparator(*src)) { - src++; - } else { -#if GTEST_HAS_ALT_PATH_SEP_ - if (*dest_ptr == kAlternatePathSeparator) { - *dest_ptr = kPathSeparator; - } -#endif - while (IsPathSeparator(*src)) - src++; - } - dest_ptr++; - } - *dest_ptr = '\0'; - pathname_ = dest; - delete[] dest; -} - -} // namespace internal -} // namespace testing \ No newline at end of file diff --git a/src/gtest/src/gtest-internal-inl.h b/src/gtest/src/gtest-internal-inl.h deleted file mode 100644 index da83b957..00000000 --- a/src/gtest/src/gtest-internal-inl.h +++ /dev/null @@ -1,1204 +0,0 @@ -// Copyright 2005 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. - -// Utility functions and classes used by the Google C++ testing framework. -// -// -// This file contains purely Google Test's internal implementation. Please -// DO NOT #INCLUDE IT IN A USER PROGRAM. - -#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ -#define GTEST_SRC_GTEST_INTERNAL_INL_H_ - -// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is -// part of Google Test's implementation; otherwise it's undefined. -#if !GTEST_IMPLEMENTATION_ -// If this file is included from the user's code, just say no. -# error "gtest-internal-inl.h is part of Google Test's internal implementation." -# error "It must not be included except by Google Test itself." -#endif // GTEST_IMPLEMENTATION_ - -#ifndef _WIN32_WCE -# include -#endif // !_WIN32_WCE -#include -#include // For strtoll/_strtoul64/malloc/free. -#include // For memmove. - -#include -#include -#include - -#include "gtest/internal/gtest-port.h" - -#if GTEST_CAN_STREAM_RESULTS_ -# include // NOLINT -# include // NOLINT -#endif - -#if GTEST_OS_WINDOWS -# include // NOLINT -#endif // GTEST_OS_WINDOWS - -#include "gtest/gtest.h" // NOLINT -#include "gtest/gtest-spi.h" - -namespace testing { - -// Declares the flags. -// -// We don't want the users to modify this flag in the code, but want -// Google Test's own unit tests to be able to access it. Therefore we -// declare it here as opposed to in gtest.h. -GTEST_DECLARE_bool_(death_test_use_fork); - -namespace internal { - -// The value of GetTestTypeId() as seen from within the Google Test -// library. This is solely for testing GetTestTypeId(). -GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; - -// Names of the flags (needed for parsing Google Test flags). -const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; -const char kBreakOnFailureFlag[] = "break_on_failure"; -const char kCatchExceptionsFlag[] = "catch_exceptions"; -const char kColorFlag[] = "color"; -const char kFilterFlag[] = "filter"; -const char kListTestsFlag[] = "list_tests"; -const char kOutputFlag[] = "output"; -const char kPrintTimeFlag[] = "print_time"; -const char kRandomSeedFlag[] = "random_seed"; -const char kRepeatFlag[] = "repeat"; -const char kShuffleFlag[] = "shuffle"; -const char kStackTraceDepthFlag[] = "stack_trace_depth"; -const char kStreamResultToFlag[] = "stream_result_to"; -const char kThrowOnFailureFlag[] = "throw_on_failure"; - -// A valid random seed must be in [1, kMaxRandomSeed]. -const int kMaxRandomSeed = 99999; - -// g_help_flag is true iff the --help flag or an equivalent form is -// specified on the command line. -GTEST_API_ extern bool g_help_flag; - -// Returns the current time in milliseconds. -GTEST_API_ TimeInMillis GetTimeInMillis(); - -// Returns true iff Google Test should use colors in the output. -GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); - -// Formats the given time in milliseconds as seconds. -GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); - -// Converts the given time in milliseconds to a date string in the ISO 8601 -// format, without the timezone information. N.B.: due to the use the -// non-reentrant localtime() function, this function is not thread safe. Do -// not use it in any code that can be called from multiple threads. -GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms); - -// Parses a string for an Int32 flag, in the form of "--flag=value". -// -// On success, stores the value of the flag in *value, and returns -// true. On failure, returns false without changing *value. -GTEST_API_ bool ParseInt32Flag( - const char* str, const char* flag, Int32* value); - -// Returns a random seed in range [1, kMaxRandomSeed] based on the -// given --gtest_random_seed flag value. -inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { - const unsigned int raw_seed = (random_seed_flag == 0) ? - static_cast(GetTimeInMillis()) : - static_cast(random_seed_flag); - - // Normalizes the actual seed to range [1, kMaxRandomSeed] such that - // it's easy to type. - const int normalized_seed = - static_cast((raw_seed - 1U) % - static_cast(kMaxRandomSeed)) + 1; - return normalized_seed; -} - -// Returns the first valid random seed after 'seed'. The behavior is -// undefined if 'seed' is invalid. The seed after kMaxRandomSeed is -// considered to be 1. -inline int GetNextRandomSeed(int seed) { - GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) - << "Invalid random seed " << seed << " - must be in [1, " - << kMaxRandomSeed << "]."; - const int next_seed = seed + 1; - return (next_seed > kMaxRandomSeed) ? 1 : next_seed; -} - -// This class saves the values of all Google Test flags in its c'tor, and -// restores them in its d'tor. -class GTestFlagSaver { - public: - // The c'tor. - GTestFlagSaver() { - also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); - break_on_failure_ = GTEST_FLAG(break_on_failure); - catch_exceptions_ = GTEST_FLAG(catch_exceptions); - color_ = GTEST_FLAG(color); - death_test_style_ = GTEST_FLAG(death_test_style); - death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); - filter_ = GTEST_FLAG(filter); - internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); - list_tests_ = GTEST_FLAG(list_tests); - output_ = GTEST_FLAG(output); - print_time_ = GTEST_FLAG(print_time); - random_seed_ = GTEST_FLAG(random_seed); - repeat_ = GTEST_FLAG(repeat); - shuffle_ = GTEST_FLAG(shuffle); - stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); - stream_result_to_ = GTEST_FLAG(stream_result_to); - throw_on_failure_ = GTEST_FLAG(throw_on_failure); - } - - // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. - ~GTestFlagSaver() { - GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; - GTEST_FLAG(break_on_failure) = break_on_failure_; - GTEST_FLAG(catch_exceptions) = catch_exceptions_; - GTEST_FLAG(color) = color_; - GTEST_FLAG(death_test_style) = death_test_style_; - GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; - GTEST_FLAG(filter) = filter_; - GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; - GTEST_FLAG(list_tests) = list_tests_; - GTEST_FLAG(output) = output_; - GTEST_FLAG(print_time) = print_time_; - GTEST_FLAG(random_seed) = random_seed_; - GTEST_FLAG(repeat) = repeat_; - GTEST_FLAG(shuffle) = shuffle_; - GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; - GTEST_FLAG(stream_result_to) = stream_result_to_; - GTEST_FLAG(throw_on_failure) = throw_on_failure_; - } - - private: - // Fields for saving the original values of flags. - bool also_run_disabled_tests_; - bool break_on_failure_; - bool catch_exceptions_; - std::string color_; - std::string death_test_style_; - bool death_test_use_fork_; - std::string filter_; - std::string internal_run_death_test_; - bool list_tests_; - std::string output_; - bool print_time_; - internal::Int32 random_seed_; - internal::Int32 repeat_; - bool shuffle_; - internal::Int32 stack_trace_depth_; - std::string stream_result_to_; - bool throw_on_failure_; -} GTEST_ATTRIBUTE_UNUSED_; - -// Converts a Unicode code point to a narrow string in UTF-8 encoding. -// code_point parameter is of type UInt32 because wchar_t may not be -// wide enough to contain a code point. -// If the code_point is not a valid Unicode code point -// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted -// to "(Invalid Unicode 0xXXXXXXXX)". -GTEST_API_ std::string CodePointToUtf8(UInt32 code_point); - -// Converts a wide string to a narrow string in UTF-8 encoding. -// The wide string is assumed to have the following encoding: -// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) -// UTF-32 if sizeof(wchar_t) == 4 (on Linux) -// Parameter str points to a null-terminated wide string. -// Parameter num_chars may additionally limit the number -// of wchar_t characters processed. -1 is used when the entire string -// should be processed. -// If the string contains code points that are not valid Unicode code points -// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output -// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding -// and contains invalid UTF-16 surrogate pairs, values in those pairs -// will be encoded as individual Unicode characters from Basic Normal Plane. -GTEST_API_ std::string WideStringToUtf8(const wchar_t* str, int num_chars); - -// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file -// if the variable is present. If a file already exists at this location, this -// function will write over it. If the variable is present, but the file cannot -// be created, prints an error and exits. -void WriteToShardStatusFileIfNeeded(); - -// Checks whether sharding is enabled by examining the relevant -// environment variable values. If the variables are present, -// but inconsistent (e.g., shard_index >= total_shards), prints -// an error and exits. If in_subprocess_for_death_test, sharding is -// disabled because it must only be applied to the original test -// process. Otherwise, we could filter out death tests we intended to execute. -GTEST_API_ bool ShouldShard(const char* total_shards_str, - const char* shard_index_str, - bool in_subprocess_for_death_test); - -// Parses the environment variable var as an Int32. If it is unset, -// returns default_val. If it is not an Int32, prints an error and -// and aborts. -GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); - -// Given the total number of shards, the shard index, and the test id, -// returns true iff the test should be run on this shard. The test id is -// some arbitrary but unique non-negative integer assigned to each test -// method. Assumes that 0 <= shard_index < total_shards. -GTEST_API_ bool ShouldRunTestOnShard( - int total_shards, int shard_index, int test_id); - -// STL container utilities. - -// Returns the number of elements in the given container that satisfy -// the given predicate. -template -inline int CountIf(const Container& c, Predicate predicate) { - // Implemented as an explicit loop since std::count_if() in libCstd on - // Solaris has a non-standard signature. - int count = 0; - for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) { - if (predicate(*it)) - ++count; - } - return count; -} - -// Applies a function/functor to each element in the container. -template -void ForEach(const Container& c, Functor functor) { - std::for_each(c.begin(), c.end(), functor); -} - -// Returns the i-th element of the vector, or default_value if i is not -// in range [0, v.size()). -template -inline E GetElementOr(const std::vector& v, int i, E default_value) { - return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; -} - -// Performs an in-place shuffle of a range of the vector's elements. -// 'begin' and 'end' are element indices as an STL-style range; -// i.e. [begin, end) are shuffled, where 'end' == size() means to -// shuffle to the end of the vector. -template -void ShuffleRange(internal::Random* random, int begin, int end, - std::vector* v) { - const int size = static_cast(v->size()); - GTEST_CHECK_(0 <= begin && begin <= size) - << "Invalid shuffle range start " << begin << ": must be in range [0, " - << size << "]."; - GTEST_CHECK_(begin <= end && end <= size) - << "Invalid shuffle range finish " << end << ": must be in range [" - << begin << ", " << size << "]."; - - // Fisher-Yates shuffle, from - // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle - for (int range_width = end - begin; range_width >= 2; range_width--) { - const int last_in_range = begin + range_width - 1; - const int selected = begin + random->Generate(range_width); - std::swap((*v)[selected], (*v)[last_in_range]); - } -} - -// Performs an in-place shuffle of the vector's elements. -template -inline void Shuffle(internal::Random* random, std::vector* v) { - ShuffleRange(random, 0, static_cast(v->size()), v); -} - -// A function for deleting an object. Handy for being used as a -// functor. -template -static void Delete(T* x) { - delete x; -} - -// A predicate that checks the key of a TestProperty against a known key. -// -// TestPropertyKeyIs is copyable. -class TestPropertyKeyIs { - public: - // Constructor. - // - // TestPropertyKeyIs has NO default constructor. - explicit TestPropertyKeyIs(const std::string& key) : key_(key) {} - - // Returns true iff the test name of test property matches on key_. - bool operator()(const TestProperty& test_property) const { - return test_property.key() == key_; - } - - private: - std::string key_; -}; - -// Class UnitTestOptions. -// -// This class contains functions for processing options the user -// specifies when running the tests. It has only static members. -// -// In most cases, the user can specify an option using either an -// environment variable or a command line flag. E.g. you can set the -// test filter using either GTEST_FILTER or --gtest_filter. If both -// the variable and the flag are present, the latter overrides the -// former. -class GTEST_API_ UnitTestOptions { - public: - // Functions for processing the gtest_output flag. - - // Returns the output format, or "" for normal printed output. - static std::string GetOutputFormat(); - - // Returns the absolute path of the requested output file, or the - // default (test_detail.xml in the original working directory) if - // none was explicitly specified. - static std::string GetAbsolutePathToOutputFile(); - - // Functions for processing the gtest_filter flag. - - // Returns true iff the wildcard pattern matches the string. The - // first ':' or '\0' character in pattern marks the end of it. - // - // This recursive algorithm isn't very efficient, but is clear and - // works well enough for matching test names, which are short. - static bool PatternMatchesString(const char *pattern, const char *str); - - // Returns true iff the user-specified filter matches the test case - // name and the test name. - static bool FilterMatchesTest(const std::string &test_case_name, - const std::string &test_name); - -#if GTEST_OS_WINDOWS - // Function for supporting the gtest_catch_exception flag. - - // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the - // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. - // This function is useful as an __except condition. - static int GTestShouldProcessSEH(DWORD exception_code); -#endif // GTEST_OS_WINDOWS - - // Returns true if "name" matches the ':' separated list of glob-style - // filters in "filter". - static bool MatchesFilter(const std::string& name, const char* filter); -}; - -// Returns the current application's name, removing directory path if that -// is present. Used by UnitTestOptions::GetOutputFile. -GTEST_API_ FilePath GetCurrentExecutableName(); - -// The role interface for getting the OS stack trace as a string. -class OsStackTraceGetterInterface { - public: - OsStackTraceGetterInterface() {} - virtual ~OsStackTraceGetterInterface() {} - - // Returns the current OS stack trace as an std::string. Parameters: - // - // max_depth - the maximum number of stack frames to be included - // in the trace. - // skip_count - the number of top frames to be skipped; doesn't count - // against max_depth. - virtual string CurrentStackTrace(int max_depth, int skip_count) = 0; - - // UponLeavingGTest() should be called immediately before Google Test calls - // user code. It saves some information about the current stack that - // CurrentStackTrace() will use to find and hide Google Test stack frames. - virtual void UponLeavingGTest() = 0; - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); -}; - -// A working implementation of the OsStackTraceGetterInterface interface. -class OsStackTraceGetter : public OsStackTraceGetterInterface { - public: - OsStackTraceGetter() : caller_frame_(NULL) {} - - virtual string CurrentStackTrace(int max_depth, int skip_count) - GTEST_LOCK_EXCLUDED_(mutex_); - - virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_); - - // This string is inserted in place of stack frames that are part of - // Google Test's implementation. - static const char* const kElidedFramesMarker; - - private: - Mutex mutex_; // protects all internal state - - // We save the stack frame below the frame that calls user code. - // We do this because the address of the frame immediately below - // the user code changes between the call to UponLeavingGTest() - // and any calls to CurrentStackTrace() from within the user code. - void* caller_frame_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); -}; - -// Information about a Google Test trace point. -struct TraceInfo { - const char* file; - int line; - std::string message; -}; - -// This is the default global test part result reporter used in UnitTestImpl. -// This class should only be used by UnitTestImpl. -class DefaultGlobalTestPartResultReporter - : public TestPartResultReporterInterface { - public: - explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); - // Implements the TestPartResultReporterInterface. Reports the test part - // result in the current test. - virtual void ReportTestPartResult(const TestPartResult& result); - - private: - UnitTestImpl* const unit_test_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); -}; - -// This is the default per thread test part result reporter used in -// UnitTestImpl. This class should only be used by UnitTestImpl. -class DefaultPerThreadTestPartResultReporter - : public TestPartResultReporterInterface { - public: - explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); - // Implements the TestPartResultReporterInterface. The implementation just - // delegates to the current global test part result reporter of *unit_test_. - virtual void ReportTestPartResult(const TestPartResult& result); - - private: - UnitTestImpl* const unit_test_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); -}; - -// The private implementation of the UnitTest class. We don't protect -// the methods under a mutex, as this class is not accessible by a -// user and the UnitTest class that delegates work to this class does -// proper locking. -class GTEST_API_ UnitTestImpl { - public: - explicit UnitTestImpl(UnitTest* parent); - virtual ~UnitTestImpl(); - - // There are two different ways to register your own TestPartResultReporter. - // You can register your own repoter to listen either only for test results - // from the current thread or for results from all threads. - // By default, each per-thread test result repoter just passes a new - // TestPartResult to the global test result reporter, which registers the - // test part result for the currently running test. - - // Returns the global test part result reporter. - TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); - - // Sets the global test part result reporter. - void SetGlobalTestPartResultReporter( - TestPartResultReporterInterface* reporter); - - // Returns the test part result reporter for the current thread. - TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); - - // Sets the test part result reporter for the current thread. - void SetTestPartResultReporterForCurrentThread( - TestPartResultReporterInterface* reporter); - - // Gets the number of successful test cases. - int successful_test_case_count() const; - - // Gets the number of failed test cases. - int failed_test_case_count() const; - - // Gets the number of all test cases. - int total_test_case_count() const; - - // Gets the number of all test cases that contain at least one test - // that should run. - int test_case_to_run_count() const; - - // Gets the number of successful tests. - int successful_test_count() const; - - // Gets the number of failed tests. - int failed_test_count() const; - - // Gets the number of disabled tests that will be reported in the XML report. - int reportable_disabled_test_count() const; - - // Gets the number of disabled tests. - int disabled_test_count() const; - - // Gets the number of tests to be printed in the XML report. - int reportable_test_count() const; - - // Gets the number of all tests. - int total_test_count() const; - - // Gets the number of tests that should run. - int test_to_run_count() const; - - // Gets the time of the test program start, in ms from the start of the - // UNIX epoch. - TimeInMillis start_timestamp() const { return start_timestamp_; } - - // Gets the elapsed time, in milliseconds. - TimeInMillis elapsed_time() const { return elapsed_time_; } - - // Returns true iff the unit test passed (i.e. all test cases passed). - bool Passed() const { return !Failed(); } - - // Returns true iff the unit test failed (i.e. some test case failed - // or something outside of all tests failed). - bool Failed() const { - return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); - } - - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - const TestCase* GetTestCase(int i) const { - const int index = GetElementOr(test_case_indices_, i, -1); - return index < 0 ? NULL : test_cases_[i]; - } - - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - TestCase* GetMutableTestCase(int i) { - const int index = GetElementOr(test_case_indices_, i, -1); - return index < 0 ? NULL : test_cases_[index]; - } - - // Provides access to the event listener list. - TestEventListeners* listeners() { return &listeners_; } - - // Returns the TestResult for the test that's currently running, or - // the TestResult for the ad hoc test if no test is running. - TestResult* current_test_result(); - - // Returns the TestResult for the ad hoc test. - const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } - - // Sets the OS stack trace getter. - // - // Does nothing if the input and the current OS stack trace getter - // are the same; otherwise, deletes the old getter and makes the - // input the current getter. - void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); - - // Returns the current OS stack trace getter if it is not NULL; - // otherwise, creates an OsStackTraceGetter, makes it the current - // getter, and returns it. - OsStackTraceGetterInterface* os_stack_trace_getter(); - - // Returns the current OS stack trace as an std::string. - // - // The maximum number of stack frames to be included is specified by - // the gtest_stack_trace_depth flag. The skip_count parameter - // specifies the number of top frames to be skipped, which doesn't - // count against the number of frames to be included. - // - // For example, if Foo() calls Bar(), which in turn calls - // CurrentOsStackTraceExceptTop(1), Foo() will be included in the - // trace but Bar() and CurrentOsStackTraceExceptTop() won't. - std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_; - - // Finds and returns a TestCase with the given name. If one doesn't - // exist, creates one and returns it. - // - // Arguments: - // - // test_case_name: name of the test case - // type_param: the name of the test's type parameter, or NULL if - // this is not a typed or a type-parameterized test. - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - TestCase* GetTestCase(const char* test_case_name, - const char* type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc); - - // Adds a TestInfo to the unit test. - // - // Arguments: - // - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - // test_info: the TestInfo object - void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc, - TestInfo* test_info) { - // In order to support thread-safe death tests, we need to - // remember the original working directory when the test program - // was first invoked. We cannot do this in RUN_ALL_TESTS(), as - // the user may have changed the current directory before calling - // RUN_ALL_TESTS(). Therefore we capture the current directory in - // AddTestInfo(), which is called to register a TEST or TEST_F - // before main() is reached. - if (original_working_dir_.IsEmpty()) { - original_working_dir_.Set(FilePath::GetCurrentDir()); - GTEST_CHECK_(!original_working_dir_.IsEmpty()) - << "Failed to get the current working directory."; - } - - GetTestCase(test_info->test_case_name(), - test_info->type_param(), - set_up_tc, - tear_down_tc)->AddTestInfo(test_info); - } - -#if GTEST_HAS_PARAM_TEST - // Returns ParameterizedTestCaseRegistry object used to keep track of - // value-parameterized tests and instantiate and register them. - internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { - return parameterized_test_registry_; - } -#endif // GTEST_HAS_PARAM_TEST - - // Sets the TestCase object for the test that's currently running. - void set_current_test_case(TestCase* a_current_test_case) { - current_test_case_ = a_current_test_case; - } - - // Sets the TestInfo object for the test that's currently running. If - // current_test_info is NULL, the assertion results will be stored in - // ad_hoc_test_result_. - void set_current_test_info(TestInfo* a_current_test_info) { - current_test_info_ = a_current_test_info; - } - - // Registers all parameterized tests defined using TEST_P and - // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter - // combination. This method can be called more then once; it has guards - // protecting from registering the tests more then once. If - // value-parameterized tests are disabled, RegisterParameterizedTests is - // present but does nothing. - void RegisterParameterizedTests(); - - // Runs all tests in this UnitTest object, prints the result, and - // returns true if all tests are successful. If any exception is - // thrown during a test, this test is considered to be failed, but - // the rest of the tests will still be run. - bool RunAllTests(); - - // Clears the results of all tests, except the ad hoc tests. - void ClearNonAdHocTestResult() { - ForEach(test_cases_, TestCase::ClearTestCaseResult); - } - - // Clears the results of ad-hoc test assertions. - void ClearAdHocTestResult() { - ad_hoc_test_result_.Clear(); - } - - // Adds a TestProperty to the current TestResult object when invoked in a - // context of a test or a test case, or to the global property set. If the - // result already contains a property with the same key, the value will be - // updated. - void RecordProperty(const TestProperty& test_property); - - enum ReactionToSharding { - HONOR_SHARDING_PROTOCOL, - IGNORE_SHARDING_PROTOCOL - }; - - // Matches the full name of each test against the user-specified - // filter to decide whether the test should run, then records the - // result in each TestCase and TestInfo object. - // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests - // based on sharding variables in the environment. - // Returns the number of tests that should run. - int FilterTests(ReactionToSharding shard_tests); - - // Prints the names of the tests matching the user-specified filter flag. - void ListTestsMatchingFilter(); - - const TestCase* current_test_case() const { return current_test_case_; } - TestInfo* current_test_info() { return current_test_info_; } - const TestInfo* current_test_info() const { return current_test_info_; } - - // Returns the vector of environments that need to be set-up/torn-down - // before/after the tests are run. - std::vector& environments() { return environments_; } - - // Getters for the per-thread Google Test trace stack. - std::vector& gtest_trace_stack() { - return *(gtest_trace_stack_.pointer()); - } - const std::vector& gtest_trace_stack() const { - return gtest_trace_stack_.get(); - } - -#if GTEST_HAS_DEATH_TEST - void InitDeathTestSubprocessControlInfo() { - internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); - } - // Returns a pointer to the parsed --gtest_internal_run_death_test - // flag, or NULL if that flag was not specified. - // This information is useful only in a death test child process. - // Must not be called before a call to InitGoogleTest. - const InternalRunDeathTestFlag* internal_run_death_test_flag() const { - return internal_run_death_test_flag_.get(); - } - - // Returns a pointer to the current death test factory. - internal::DeathTestFactory* death_test_factory() { - return death_test_factory_.get(); - } - - void SuppressTestEventsIfInSubprocess(); - - friend class ReplaceDeathTestFactory; -#endif // GTEST_HAS_DEATH_TEST - - // Initializes the event listener performing XML output as specified by - // UnitTestOptions. Must not be called before InitGoogleTest. - void ConfigureXmlOutput(); - -#if GTEST_CAN_STREAM_RESULTS_ - // Initializes the event listener for streaming test results to a socket. - // Must not be called before InitGoogleTest. - void ConfigureStreamingOutput(); -#endif - - // Performs initialization dependent upon flag values obtained in - // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to - // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest - // this function is also called from RunAllTests. Since this function can be - // called more than once, it has to be idempotent. - void PostFlagParsingInit(); - - // Gets the random seed used at the start of the current test iteration. - int random_seed() const { return random_seed_; } - - // Gets the random number generator. - internal::Random* random() { return &random_; } - - // Shuffles all test cases, and the tests within each test case, - // making sure that death tests are still run first. - void ShuffleTests(); - - // Restores the test cases and tests to their order before the first shuffle. - void UnshuffleTests(); - - // Returns the value of GTEST_FLAG(catch_exceptions) at the moment - // UnitTest::Run() starts. - bool catch_exceptions() const { return catch_exceptions_; } - - private: - friend class ::testing::UnitTest; - - // Used by UnitTest::Run() to capture the state of - // GTEST_FLAG(catch_exceptions) at the moment it starts. - void set_catch_exceptions(bool value) { catch_exceptions_ = value; } - - // The UnitTest object that owns this implementation object. - UnitTest* const parent_; - - // The working directory when the first TEST() or TEST_F() was - // executed. - internal::FilePath original_working_dir_; - - // The default test part result reporters. - DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; - DefaultPerThreadTestPartResultReporter - default_per_thread_test_part_result_reporter_; - - // Points to (but doesn't own) the global test part result reporter. - TestPartResultReporterInterface* global_test_part_result_repoter_; - - // Protects read and write access to global_test_part_result_reporter_. - internal::Mutex global_test_part_result_reporter_mutex_; - - // Points to (but doesn't own) the per-thread test part result reporter. - internal::ThreadLocal - per_thread_test_part_result_reporter_; - - // The vector of environments that need to be set-up/torn-down - // before/after the tests are run. - std::vector environments_; - - // The vector of TestCases in their original order. It owns the - // elements in the vector. - std::vector test_cases_; - - // Provides a level of indirection for the test case list to allow - // easy shuffling and restoring the test case order. The i-th - // element of this vector is the index of the i-th test case in the - // shuffled order. - std::vector test_case_indices_; - -#if GTEST_HAS_PARAM_TEST - // ParameterizedTestRegistry object used to register value-parameterized - // tests. - internal::ParameterizedTestCaseRegistry parameterized_test_registry_; - - // Indicates whether RegisterParameterizedTests() has been called already. - bool parameterized_tests_registered_; -#endif // GTEST_HAS_PARAM_TEST - - // Index of the last death test case registered. Initially -1. - int last_death_test_case_; - - // This points to the TestCase for the currently running test. It - // changes as Google Test goes through one test case after another. - // When no test is running, this is set to NULL and Google Test - // stores assertion results in ad_hoc_test_result_. Initially NULL. - TestCase* current_test_case_; - - // This points to the TestInfo for the currently running test. It - // changes as Google Test goes through one test after another. When - // no test is running, this is set to NULL and Google Test stores - // assertion results in ad_hoc_test_result_. Initially NULL. - TestInfo* current_test_info_; - - // Normally, a user only writes assertions inside a TEST or TEST_F, - // or inside a function called by a TEST or TEST_F. Since Google - // Test keeps track of which test is current running, it can - // associate such an assertion with the test it belongs to. - // - // If an assertion is encountered when no TEST or TEST_F is running, - // Google Test attributes the assertion result to an imaginary "ad hoc" - // test, and records the result in ad_hoc_test_result_. - TestResult ad_hoc_test_result_; - - // The list of event listeners that can be used to track events inside - // Google Test. - TestEventListeners listeners_; - - // The OS stack trace getter. Will be deleted when the UnitTest - // object is destructed. By default, an OsStackTraceGetter is used, - // but the user can set this field to use a custom getter if that is - // desired. - OsStackTraceGetterInterface* os_stack_trace_getter_; - - // True iff PostFlagParsingInit() has been called. - bool post_flag_parse_init_performed_; - - // The random number seed used at the beginning of the test run. - int random_seed_; - - // Our random number generator. - internal::Random random_; - - // The time of the test program start, in ms from the start of the - // UNIX epoch. - TimeInMillis start_timestamp_; - - // How long the test took to run, in milliseconds. - TimeInMillis elapsed_time_; - -#if GTEST_HAS_DEATH_TEST - // The decomposed components of the gtest_internal_run_death_test flag, - // parsed when RUN_ALL_TESTS is called. - internal::scoped_ptr internal_run_death_test_flag_; - internal::scoped_ptr death_test_factory_; -#endif // GTEST_HAS_DEATH_TEST - - // A per-thread stack of traces created by the SCOPED_TRACE() macro. - internal::ThreadLocal > gtest_trace_stack_; - - // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests() - // starts. - bool catch_exceptions_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); -}; // class UnitTestImpl - -// Convenience function for accessing the global UnitTest -// implementation object. -inline UnitTestImpl* GetUnitTestImpl() { - return UnitTest::GetInstance()->impl(); -} - -#if GTEST_USES_SIMPLE_RE - -// Internal helper functions for implementing the simple regular -// expression matcher. -GTEST_API_ bool IsInSet(char ch, const char* str); -GTEST_API_ bool IsAsciiDigit(char ch); -GTEST_API_ bool IsAsciiPunct(char ch); -GTEST_API_ bool IsRepeat(char ch); -GTEST_API_ bool IsAsciiWhiteSpace(char ch); -GTEST_API_ bool IsAsciiWordChar(char ch); -GTEST_API_ bool IsValidEscape(char ch); -GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); -GTEST_API_ bool ValidateRegex(const char* regex); -GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); -GTEST_API_ bool MatchRepetitionAndRegexAtHead( - bool escaped, char ch, char repeat, const char* regex, const char* str); -GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); - -#endif // GTEST_USES_SIMPLE_RE - -// Parses the command line for Google Test flags, without initializing -// other parts of Google Test. -GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); -GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); - -#if GTEST_HAS_DEATH_TEST - -// Returns the message describing the last system error, regardless of the -// platform. -GTEST_API_ std::string GetLastErrnoDescription(); - -// Attempts to parse a string into a positive integer pointed to by the -// number parameter. Returns true if that is possible. -// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use -// it here. -template -bool ParseNaturalNumber(const ::std::string& str, Integer* number) { - // Fail fast if the given string does not begin with a digit; - // this bypasses strtoXXX's "optional leading whitespace and plus - // or minus sign" semantics, which are undesirable here. - if (str.empty() || !IsDigit(str[0])) { - return false; - } - errno = 0; - - char* end; - // BiggestConvertible is the largest integer type that system-provided - // string-to-number conversion routines can return. - -# if GTEST_OS_WINDOWS && !defined(__GNUC__) - - // MSVC and C++ Builder define __int64 instead of the standard long long. - typedef unsigned __int64 BiggestConvertible; - const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); - -# else - - typedef unsigned long long BiggestConvertible; // NOLINT - const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); - -# endif // GTEST_OS_WINDOWS && !defined(__GNUC__) - - const bool parse_success = *end == '\0' && errno == 0; - - // TODO(vladl@google.com): Convert this to compile time assertion when it is - // available. - GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); - - const Integer result = static_cast(parsed); - if (parse_success && static_cast(result) == parsed) { - *number = result; - return true; - } - return false; -} -#endif // GTEST_HAS_DEATH_TEST - -// TestResult contains some private methods that should be hidden from -// Google Test user but are required for testing. This class allow our tests -// to access them. -// -// This class is supplied only for the purpose of testing Google Test's own -// constructs. Do not use it in user tests, either directly or indirectly. -class TestResultAccessor { - public: - static void RecordProperty(TestResult* test_result, - const std::string& xml_element, - const TestProperty& property) { - test_result->RecordProperty(xml_element, property); - } - - static void ClearTestPartResults(TestResult* test_result) { - test_result->ClearTestPartResults(); - } - - static const std::vector& test_part_results( - const TestResult& test_result) { - return test_result.test_part_results(); - } -}; - -#if GTEST_CAN_STREAM_RESULTS_ - -// Streams test results to the given port on the given host machine. -class StreamingListener : public EmptyTestEventListener { - public: - // Abstract base class for writing strings to a socket. - class AbstractSocketWriter { - public: - virtual ~AbstractSocketWriter() {} - - // Sends a string to the socket. - virtual void Send(const string& message) = 0; - - // Closes the socket. - virtual void CloseConnection() {} - - // Sends a string and a newline to the socket. - void SendLn(const string& message) { - Send(message + "\n"); - } - }; - - // Concrete class for actually writing strings to a socket. - class SocketWriter : public AbstractSocketWriter { - public: - SocketWriter(const string& host, const string& port) - : sockfd_(-1), host_name_(host), port_num_(port) { - MakeConnection(); - } - - virtual ~SocketWriter() { - if (sockfd_ != -1) - CloseConnection(); - } - - // Sends a string to the socket. - virtual void Send(const string& message) { - GTEST_CHECK_(sockfd_ != -1) - << "Send() can be called only when there is a connection."; - - const int len = static_cast(message.length()); - if (write(sockfd_, message.c_str(), len) != len) { - GTEST_LOG_(WARNING) - << "stream_result_to: failed to stream to " - << host_name_ << ":" << port_num_; - } - } - - private: - // Creates a client socket and connects to the server. - void MakeConnection(); - - // Closes the socket. - void CloseConnection() { - GTEST_CHECK_(sockfd_ != -1) - << "CloseConnection() can be called only when there is a connection."; - - close(sockfd_); - sockfd_ = -1; - } - - int sockfd_; // socket file descriptor - const string host_name_; - const string port_num_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter); - }; // class SocketWriter - - // Escapes '=', '&', '%', and '\n' characters in str as "%xx". - static string UrlEncode(const char* str); - - StreamingListener(const string& host, const string& port) - : socket_writer_(new SocketWriter(host, port)) { Start(); } - - explicit StreamingListener(AbstractSocketWriter* socket_writer) - : socket_writer_(socket_writer) { Start(); } - - void OnTestProgramStart(const UnitTest& /* unit_test */) { - SendLn("event=TestProgramStart"); - } - - void OnTestProgramEnd(const UnitTest& unit_test) { - // Note that Google Test current only report elapsed time for each - // test iteration, not for the entire test program. - SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed())); - - // Notify the streaming server to stop. - socket_writer_->CloseConnection(); - } - - void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { - SendLn("event=TestIterationStart&iteration=" + - StreamableToString(iteration)); - } - - void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { - SendLn("event=TestIterationEnd&passed=" + - FormatBool(unit_test.Passed()) + "&elapsed_time=" + - StreamableToString(unit_test.elapsed_time()) + "ms"); - } - - void OnTestCaseStart(const TestCase& test_case) { - SendLn(std::string("event=TestCaseStart&name=") + test_case.name()); - } - - void OnTestCaseEnd(const TestCase& test_case) { - SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) - + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) - + "ms"); - } - - void OnTestStart(const TestInfo& test_info) { - SendLn(std::string("event=TestStart&name=") + test_info.name()); - } - - void OnTestEnd(const TestInfo& test_info) { - SendLn("event=TestEnd&passed=" + - FormatBool((test_info.result())->Passed()) + - "&elapsed_time=" + - StreamableToString((test_info.result())->elapsed_time()) + "ms"); - } - - void OnTestPartResult(const TestPartResult& test_part_result) { - const char* file_name = test_part_result.file_name(); - if (file_name == NULL) - file_name = ""; - SendLn("event=TestPartResult&file=" + UrlEncode(file_name) + - "&line=" + StreamableToString(test_part_result.line_number()) + - "&message=" + UrlEncode(test_part_result.message())); - } - - private: - // Sends the given message and a newline to the socket. - void SendLn(const string& message) { socket_writer_->SendLn(message); } - - // Called at the start of streaming to notify the receiver what - // protocol we are using. - void Start() { SendLn("gtest_streaming_protocol_version=1.0"); } - - string FormatBool(bool value) { return value ? "1" : "0"; } - - const scoped_ptr socket_writer_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); -}; // class StreamingListener - -#endif // GTEST_CAN_STREAM_RESULTS_ - -} // namespace internal -} // namespace testing - -#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ \ No newline at end of file diff --git a/src/gtest/src/gtest-port.cc b/src/gtest/src/gtest-port.cc deleted file mode 100644 index 8796becc..00000000 --- a/src/gtest/src/gtest-port.cc +++ /dev/null @@ -1,1196 +0,0 @@ -// Copyright 2008 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// - -#include "gtest/internal/gtest-port.h" - -#include -#include -#include -#include - -#if GTEST_OS_WINDOWS -# include -# include -# include -# include // Used in ThreadLocal. -#else -# include -#endif // GTEST_OS_WINDOWS - -#if GTEST_OS_MAC -# include -# include -# include -#endif // GTEST_OS_MAC - -#if GTEST_OS_QNX -# include -# include -# include -#endif // GTEST_OS_QNX - -#include "gtest/gtest-spi.h" -#include "gtest/gtest-message.h" -#include "gtest/internal/gtest-internal.h" -#include "gtest/internal/gtest-string.h" - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick exists to -// prevent the accidental inclusion of gtest-internal-inl.h in the -// user's code. -#define GTEST_IMPLEMENTATION_ 1 -#include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ - -namespace testing { -namespace internal { - -#if defined(_MSC_VER) || defined(__BORLANDC__) -// MSVC and C++Builder do not provide a definition of STDERR_FILENO. -const int kStdOutFileno = 1; -const int kStdErrFileno = 2; -#else -const int kStdOutFileno = STDOUT_FILENO; -const int kStdErrFileno = STDERR_FILENO; -#endif // _MSC_VER - -#if GTEST_OS_MAC - -// Returns the number of threads running in the process, or 0 to indicate that -// we cannot detect it. -size_t GetThreadCount() { - const task_t task = mach_task_self(); - mach_msg_type_number_t thread_count; - thread_act_array_t thread_list; - const kern_return_t status = task_threads(task, &thread_list, &thread_count); - if (status == KERN_SUCCESS) { - // task_threads allocates resources in thread_list and we need to free them - // to avoid leaks. - vm_deallocate(task, - reinterpret_cast(thread_list), - sizeof(thread_t) * thread_count); - return static_cast(thread_count); - } else { - return 0; - } -} - -#elif GTEST_OS_QNX - -// Returns the number of threads running in the process, or 0 to indicate that -// we cannot detect it. -size_t GetThreadCount() { - const int fd = open("/proc/self/as", O_RDONLY); - if (fd < 0) { - return 0; - } - procfs_info process_info; - const int status = - devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL); - close(fd); - if (status == EOK) { - return static_cast(process_info.num_threads); - } else { - return 0; - } -} - -#else - -size_t GetThreadCount() { - // There's no portable way to detect the number of threads, so we just - // return 0 to indicate that we cannot detect it. - return 0; -} - -#endif // GTEST_OS_MAC - -#if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS - -void SleepMilliseconds(int n) { - ::Sleep(n); -} - -AutoHandle::AutoHandle() - : handle_(INVALID_HANDLE_VALUE) {} - -AutoHandle::AutoHandle(Handle handle) - : handle_(handle) {} - -AutoHandle::~AutoHandle() { - Reset(); -} - -AutoHandle::Handle AutoHandle::Get() const { - return handle_; -} - -void AutoHandle::Reset() { - Reset(INVALID_HANDLE_VALUE); -} - -void AutoHandle::Reset(HANDLE handle) { - // Resetting with the same handle we already own is invalid. - if (handle_ != handle) { - if (IsCloseable()) { - ::CloseHandle(handle_); - } - handle_ = handle; - } else { - GTEST_CHECK_(!IsCloseable()) - << "Resetting a valid handle to itself is likely a programmer error " - "and thus not allowed."; - } -} - -bool AutoHandle::IsCloseable() const { - // Different Windows APIs may use either of these values to represent an - // invalid handle. - return handle_ != NULL && handle_ != INVALID_HANDLE_VALUE; -} - -Notification::Notification() - : event_(::CreateEvent(NULL, // Default security attributes. - TRUE, // Do not reset automatically. - FALSE, // Initially unset. - NULL)) { // Anonymous event. - GTEST_CHECK_(event_.Get() != NULL); -} - -void Notification::Notify() { - GTEST_CHECK_(::SetEvent(event_.Get()) != FALSE); -} - -void Notification::WaitForNotification() { - GTEST_CHECK_( - ::WaitForSingleObject(event_.Get(), INFINITE) == WAIT_OBJECT_0); -} - -Mutex::Mutex() - : type_(kDynamic), - owner_thread_id_(0), - critical_section_init_phase_(0), - critical_section_(new CRITICAL_SECTION) { - ::InitializeCriticalSection(critical_section_); -} - -Mutex::~Mutex() { - // Static mutexes are leaked intentionally. It is not thread-safe to try - // to clean them up. - // TODO(user): Switch to Slim Reader/Writer (SRW) Locks, which requires - // nothing to clean it up but is available only on Vista and later. - // http://msdn.microsoft.com/en-us/library/windows/desktop/aa904937.aspx - if (type_ == kDynamic) { - ::DeleteCriticalSection(critical_section_); - delete critical_section_; - critical_section_ = NULL; - } -} - -void Mutex::Lock() { - ThreadSafeLazyInit(); - ::EnterCriticalSection(critical_section_); - owner_thread_id_ = ::GetCurrentThreadId(); -} - -void Mutex::Unlock() { - ThreadSafeLazyInit(); - // We don't protect writing to owner_thread_id_ here, as it's the - // caller's responsibility to ensure that the current thread holds the - // mutex when this is called. - owner_thread_id_ = 0; - ::LeaveCriticalSection(critical_section_); -} - -// Does nothing if the current thread holds the mutex. Otherwise, crashes -// with high probability. -void Mutex::AssertHeld() { - ThreadSafeLazyInit(); - GTEST_CHECK_(owner_thread_id_ == ::GetCurrentThreadId()) - << "The current thread is not holding the mutex @" << this; -} - -// Initializes owner_thread_id_ and critical_section_ in static mutexes. -void Mutex::ThreadSafeLazyInit() { - // Dynamic mutexes are initialized in the constructor. - if (type_ == kStatic) { - switch ( - ::InterlockedCompareExchange(&critical_section_init_phase_, 1L, 0L)) { - case 0: - // If critical_section_init_phase_ was 0 before the exchange, we - // are the first to test it and need to perform the initialization. - owner_thread_id_ = 0; - critical_section_ = new CRITICAL_SECTION; - ::InitializeCriticalSection(critical_section_); - // Updates the critical_section_init_phase_ to 2 to signal - // initialization complete. - GTEST_CHECK_(::InterlockedCompareExchange( - &critical_section_init_phase_, 2L, 1L) == - 1L); - break; - case 1: - // Somebody else is already initializing the mutex; spin until they - // are done. - while (::InterlockedCompareExchange(&critical_section_init_phase_, - 2L, - 2L) != 2L) { - // Possibly yields the rest of the thread's time slice to other - // threads. - ::Sleep(0); - } - break; - - case 2: - break; // The mutex is already initialized and ready for use. - - default: - GTEST_CHECK_(false) - << "Unexpected value of critical_section_init_phase_ " - << "while initializing a static mutex."; - } - } -} - -namespace { - -class ThreadWithParamSupport : public ThreadWithParamBase { - public: - static HANDLE CreateThread(Runnable* runnable, - Notification* thread_can_start) { - ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start); - DWORD thread_id; - // TODO(user): Consider to use _beginthreadex instead. - HANDLE thread_handle = ::CreateThread( - NULL, // Default security. - 0, // Default stack size. - &ThreadWithParamSupport::ThreadMain, - param, // Parameter to ThreadMainStatic - 0x0, // Default creation flags. - &thread_id); // Need a valid pointer for the call to work under Win98. - GTEST_CHECK_(thread_handle != NULL) << "CreateThread failed with error " - << ::GetLastError() << "."; - if (thread_handle == NULL) { - delete param; - } - return thread_handle; - } - - private: - struct ThreadMainParam { - ThreadMainParam(Runnable* runnable, Notification* thread_can_start) - : runnable_(runnable), - thread_can_start_(thread_can_start) { - } - scoped_ptr runnable_; - // Does not own. - Notification* thread_can_start_; - }; - - static DWORD WINAPI ThreadMain(void* ptr) { - // Transfers ownership. - scoped_ptr param(static_cast(ptr)); - if (param->thread_can_start_ != NULL) - param->thread_can_start_->WaitForNotification(); - param->runnable_->Run(); - return 0; - } - - // Prohibit instantiation. - ThreadWithParamSupport(); - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParamSupport); -}; - -} // namespace - -ThreadWithParamBase::ThreadWithParamBase(Runnable *runnable, - Notification* thread_can_start) - : thread_(ThreadWithParamSupport::CreateThread(runnable, - thread_can_start)) { -} - -ThreadWithParamBase::~ThreadWithParamBase() { - Join(); -} - -void ThreadWithParamBase::Join() { - GTEST_CHECK_(::WaitForSingleObject(thread_.Get(), INFINITE) == WAIT_OBJECT_0) - << "Failed to join the thread with error " << ::GetLastError() << "."; -} - -// Maps a thread to a set of ThreadIdToThreadLocals that have values -// instantiated on that thread and notifies them when the thread exits. A -// ThreadLocal instance is expected to persist until all threads it has -// values on have terminated. -class ThreadLocalRegistryImpl { - public: - // Registers thread_local_instance as having value on the current thread. - // Returns a value that can be used to identify the thread from other threads. - static ThreadLocalValueHolderBase* GetValueOnCurrentThread( - const ThreadLocalBase* thread_local_instance) { - DWORD current_thread = ::GetCurrentThreadId(); - MutexLock lock(&mutex_); - ThreadIdToThreadLocals* const thread_to_thread_locals = - GetThreadLocalsMapLocked(); - ThreadIdToThreadLocals::iterator thread_local_pos = - thread_to_thread_locals->find(current_thread); - if (thread_local_pos == thread_to_thread_locals->end()) { - thread_local_pos = thread_to_thread_locals->insert( - std::make_pair(current_thread, ThreadLocalValues())).first; - StartWatcherThreadFor(current_thread); - } - ThreadLocalValues& thread_local_values = thread_local_pos->second; - ThreadLocalValues::iterator value_pos = - thread_local_values.find(thread_local_instance); - if (value_pos == thread_local_values.end()) { - value_pos = - thread_local_values - .insert(std::make_pair( - thread_local_instance, - linked_ptr( - thread_local_instance->NewValueForCurrentThread()))) - .first; - } - return value_pos->second.get(); - } - - static void OnThreadLocalDestroyed( - const ThreadLocalBase* thread_local_instance) { - std::vector > value_holders; - // Clean up the ThreadLocalValues data structure while holding the lock, but - // defer the destruction of the ThreadLocalValueHolderBases. - { - MutexLock lock(&mutex_); - ThreadIdToThreadLocals* const thread_to_thread_locals = - GetThreadLocalsMapLocked(); - for (ThreadIdToThreadLocals::iterator it = - thread_to_thread_locals->begin(); - it != thread_to_thread_locals->end(); - ++it) { - ThreadLocalValues& thread_local_values = it->second; - ThreadLocalValues::iterator value_pos = - thread_local_values.find(thread_local_instance); - if (value_pos != thread_local_values.end()) { - value_holders.push_back(value_pos->second); - thread_local_values.erase(value_pos); - // This 'if' can only be successful at most once, so theoretically we - // could break out of the loop here, but we don't bother doing so. - } - } - } - // Outside the lock, let the destructor for 'value_holders' deallocate the - // ThreadLocalValueHolderBases. - } - - static void OnThreadExit(DWORD thread_id) { - GTEST_CHECK_(thread_id != 0) << ::GetLastError(); - std::vector > value_holders; - // Clean up the ThreadIdToThreadLocals data structure while holding the - // lock, but defer the destruction of the ThreadLocalValueHolderBases. - { - MutexLock lock(&mutex_); - ThreadIdToThreadLocals* const thread_to_thread_locals = - GetThreadLocalsMapLocked(); - ThreadIdToThreadLocals::iterator thread_local_pos = - thread_to_thread_locals->find(thread_id); - if (thread_local_pos != thread_to_thread_locals->end()) { - ThreadLocalValues& thread_local_values = thread_local_pos->second; - for (ThreadLocalValues::iterator value_pos = - thread_local_values.begin(); - value_pos != thread_local_values.end(); - ++value_pos) { - value_holders.push_back(value_pos->second); - } - thread_to_thread_locals->erase(thread_local_pos); - } - } - // Outside the lock, let the destructor for 'value_holders' deallocate the - // ThreadLocalValueHolderBases. - } - - private: - // In a particular thread, maps a ThreadLocal object to its value. - typedef std::map > ThreadLocalValues; - // Stores all ThreadIdToThreadLocals having values in a thread, indexed by - // thread's ID. - typedef std::map ThreadIdToThreadLocals; - - // Holds the thread id and thread handle that we pass from - // StartWatcherThreadFor to WatcherThreadFunc. - typedef std::pair ThreadIdAndHandle; - - static void StartWatcherThreadFor(DWORD thread_id) { - // The returned handle will be kept in thread_map and closed by - // watcher_thread in WatcherThreadFunc. - HANDLE thread = ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, - FALSE, - thread_id); - GTEST_CHECK_(thread != NULL); - // We need to to pass a valid thread ID pointer into CreateThread for it - // to work correctly under Win98. - DWORD watcher_thread_id; - HANDLE watcher_thread = ::CreateThread( - NULL, // Default security. - 0, // Default stack size - &ThreadLocalRegistryImpl::WatcherThreadFunc, - reinterpret_cast(new ThreadIdAndHandle(thread_id, thread)), - CREATE_SUSPENDED, - &watcher_thread_id); - GTEST_CHECK_(watcher_thread != NULL); - // Give the watcher thread the same priority as ours to avoid being - // blocked by it. - ::SetThreadPriority(watcher_thread, - ::GetThreadPriority(::GetCurrentThread())); - ::ResumeThread(watcher_thread); - ::CloseHandle(watcher_thread); - } - - // Monitors exit from a given thread and notifies those - // ThreadIdToThreadLocals about thread termination. - static DWORD WINAPI WatcherThreadFunc(LPVOID param) { - const ThreadIdAndHandle* tah = - reinterpret_cast(param); - GTEST_CHECK_( - ::WaitForSingleObject(tah->second, INFINITE) == WAIT_OBJECT_0); - OnThreadExit(tah->first); - ::CloseHandle(tah->second); - delete tah; - return 0; - } - - // Returns map of thread local instances. - static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() { - mutex_.AssertHeld(); - static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals; - return map; - } - - // Protects access to GetThreadLocalsMapLocked() and its return value. - static Mutex mutex_; - // Protects access to GetThreadMapLocked() and its return value. - static Mutex thread_map_mutex_; -}; - -Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex); -Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex); - -ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread( - const ThreadLocalBase* thread_local_instance) { - return ThreadLocalRegistryImpl::GetValueOnCurrentThread( - thread_local_instance); -} - -void ThreadLocalRegistry::OnThreadLocalDestroyed( - const ThreadLocalBase* thread_local_instance) { - ThreadLocalRegistryImpl::OnThreadLocalDestroyed(thread_local_instance); -} - -#endif // GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS - -#if GTEST_USES_POSIX_RE - -// Implements RE. Currently only needed for death tests. - -RE::~RE() { - if (is_valid_) { - // regfree'ing an invalid regex might crash because the content - // of the regex is undefined. Since the regex's are essentially - // the same, one cannot be valid (or invalid) without the other - // being so too. - regfree(&partial_regex_); - regfree(&full_regex_); - } - free(const_cast(pattern_)); -} - -// Returns true iff regular expression re matches the entire str. -bool RE::FullMatch(const char* str, const RE& re) { - if (!re.is_valid_) return false; - - regmatch_t match; - return regexec(&re.full_regex_, str, 1, &match, 0) == 0; -} - -// Returns true iff regular expression re matches a substring of str -// (including str itself). -bool RE::PartialMatch(const char* str, const RE& re) { - if (!re.is_valid_) return false; - - regmatch_t match; - return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; -} - -// Initializes an RE from its string representation. -void RE::Init(const char* regex) { - pattern_ = posix::StrDup(regex); - - // Reserves enough bytes to hold the regular expression used for a - // full match. - const size_t full_regex_len = strlen(regex) + 10; - char* const full_pattern = new char[full_regex_len]; - - snprintf(full_pattern, full_regex_len, "^(%s)$", regex); - is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; - // We want to call regcomp(&partial_regex_, ...) even if the - // previous expression returns false. Otherwise partial_regex_ may - // not be properly initialized can may cause trouble when it's - // freed. - // - // Some implementation of POSIX regex (e.g. on at least some - // versions of Cygwin) doesn't accept the empty string as a valid - // regex. We change it to an equivalent form "()" to be safe. - if (is_valid_) { - const char* const partial_regex = (*regex == '\0') ? "()" : regex; - is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; - } - EXPECT_TRUE(is_valid_) - << "Regular expression \"" << regex - << "\" is not a valid POSIX Extended regular expression."; - - delete[] full_pattern; -} - -#elif GTEST_USES_SIMPLE_RE - -// Returns true iff ch appears anywhere in str (excluding the -// terminating '\0' character). -bool IsInSet(char ch, const char* str) { - return ch != '\0' && strchr(str, ch) != NULL; -} - -// Returns true iff ch belongs to the given classification. Unlike -// similar functions in , these aren't affected by the -// current locale. -bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } -bool IsAsciiPunct(char ch) { - return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); -} -bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } -bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } -bool IsAsciiWordChar(char ch) { - return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || - ('0' <= ch && ch <= '9') || ch == '_'; -} - -// Returns true iff "\\c" is a supported escape sequence. -bool IsValidEscape(char c) { - return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); -} - -// Returns true iff the given atom (specified by escaped and pattern) -// matches ch. The result is undefined if the atom is invalid. -bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { - if (escaped) { // "\\p" where p is pattern_char. - switch (pattern_char) { - case 'd': return IsAsciiDigit(ch); - case 'D': return !IsAsciiDigit(ch); - case 'f': return ch == '\f'; - case 'n': return ch == '\n'; - case 'r': return ch == '\r'; - case 's': return IsAsciiWhiteSpace(ch); - case 'S': return !IsAsciiWhiteSpace(ch); - case 't': return ch == '\t'; - case 'v': return ch == '\v'; - case 'w': return IsAsciiWordChar(ch); - case 'W': return !IsAsciiWordChar(ch); - } - return IsAsciiPunct(pattern_char) && pattern_char == ch; - } - - return (pattern_char == '.' && ch != '\n') || pattern_char == ch; -} - -// Helper function used by ValidateRegex() to format error messages. -std::string FormatRegexSyntaxError(const char* regex, int index) { - return (Message() << "Syntax error at index " << index - << " in simple regular expression \"" << regex << "\": ").GetString(); -} - -// Generates non-fatal failures and returns false if regex is invalid; -// otherwise returns true. -bool ValidateRegex(const char* regex) { - if (regex == NULL) { - // TODO(wan@google.com): fix the source file location in the - // assertion failures to match where the regex is used in user - // code. - ADD_FAILURE() << "NULL is not a valid simple regular expression."; - return false; - } - - bool is_valid = true; - - // True iff ?, *, or + can follow the previous atom. - bool prev_repeatable = false; - for (int i = 0; regex[i]; i++) { - if (regex[i] == '\\') { // An escape sequence - i++; - if (regex[i] == '\0') { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) - << "'\\' cannot appear at the end."; - return false; - } - - if (!IsValidEscape(regex[i])) { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) - << "invalid escape sequence \"\\" << regex[i] << "\"."; - is_valid = false; - } - prev_repeatable = true; - } else { // Not an escape sequence. - const char ch = regex[i]; - - if (ch == '^' && i > 0) { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i) - << "'^' can only appear at the beginning."; - is_valid = false; - } else if (ch == '$' && regex[i + 1] != '\0') { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i) - << "'$' can only appear at the end."; - is_valid = false; - } else if (IsInSet(ch, "()[]{}|")) { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i) - << "'" << ch << "' is unsupported."; - is_valid = false; - } else if (IsRepeat(ch) && !prev_repeatable) { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i) - << "'" << ch << "' can only follow a repeatable token."; - is_valid = false; - } - - prev_repeatable = !IsInSet(ch, "^$?*+"); - } - } - - return is_valid; -} - -// Matches a repeated regex atom followed by a valid simple regular -// expression. The regex atom is defined as c if escaped is false, -// or \c otherwise. repeat is the repetition meta character (?, *, -// or +). The behavior is undefined if str contains too many -// characters to be indexable by size_t, in which case the test will -// probably time out anyway. We are fine with this limitation as -// std::string has it too. -bool MatchRepetitionAndRegexAtHead( - bool escaped, char c, char repeat, const char* regex, - const char* str) { - const size_t min_count = (repeat == '+') ? 1 : 0; - const size_t max_count = (repeat == '?') ? 1 : - static_cast(-1) - 1; - // We cannot call numeric_limits::max() as it conflicts with the - // max() macro on Windows. - - for (size_t i = 0; i <= max_count; ++i) { - // We know that the atom matches each of the first i characters in str. - if (i >= min_count && MatchRegexAtHead(regex, str + i)) { - // We have enough matches at the head, and the tail matches too. - // Since we only care about *whether* the pattern matches str - // (as opposed to *how* it matches), there is no need to find a - // greedy match. - return true; - } - if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) - return false; - } - return false; -} - -// Returns true iff regex matches a prefix of str. regex must be a -// valid simple regular expression and not start with "^", or the -// result is undefined. -bool MatchRegexAtHead(const char* regex, const char* str) { - if (*regex == '\0') // An empty regex matches a prefix of anything. - return true; - - // "$" only matches the end of a string. Note that regex being - // valid guarantees that there's nothing after "$" in it. - if (*regex == '$') - return *str == '\0'; - - // Is the first thing in regex an escape sequence? - const bool escaped = *regex == '\\'; - if (escaped) - ++regex; - if (IsRepeat(regex[1])) { - // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so - // here's an indirect recursion. It terminates as the regex gets - // shorter in each recursion. - return MatchRepetitionAndRegexAtHead( - escaped, regex[0], regex[1], regex + 2, str); - } else { - // regex isn't empty, isn't "$", and doesn't start with a - // repetition. We match the first atom of regex with the first - // character of str and recurse. - return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && - MatchRegexAtHead(regex + 1, str + 1); - } -} - -// Returns true iff regex matches any substring of str. regex must be -// a valid simple regular expression, or the result is undefined. -// -// The algorithm is recursive, but the recursion depth doesn't exceed -// the regex length, so we won't need to worry about running out of -// stack space normally. In rare cases the time complexity can be -// exponential with respect to the regex length + the string length, -// but usually it's must faster (often close to linear). -bool MatchRegexAnywhere(const char* regex, const char* str) { - if (regex == NULL || str == NULL) - return false; - - if (*regex == '^') - return MatchRegexAtHead(regex + 1, str); - - // A successful match can be anywhere in str. - do { - if (MatchRegexAtHead(regex, str)) - return true; - } while (*str++ != '\0'); - return false; -} - -// Implements the RE class. - -RE::~RE() { - free(const_cast(pattern_)); - free(const_cast(full_pattern_)); -} - -// Returns true iff regular expression re matches the entire str. -bool RE::FullMatch(const char* str, const RE& re) { - return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); -} - -// Returns true iff regular expression re matches a substring of str -// (including str itself). -bool RE::PartialMatch(const char* str, const RE& re) { - return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); -} - -// Initializes an RE from its string representation. -void RE::Init(const char* regex) { - pattern_ = full_pattern_ = NULL; - if (regex != NULL) { - pattern_ = posix::StrDup(regex); - } - - is_valid_ = ValidateRegex(regex); - if (!is_valid_) { - // No need to calculate the full pattern when the regex is invalid. - return; - } - - const size_t len = strlen(regex); - // Reserves enough bytes to hold the regular expression used for a - // full match: we need space to prepend a '^', append a '$', and - // terminate the string with '\0'. - char* buffer = static_cast(malloc(len + 3)); - full_pattern_ = buffer; - - if (*regex != '^') - *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. - - // We don't use snprintf or strncpy, as they trigger a warning when - // compiled with VC++ 8.0. - memcpy(buffer, regex, len); - buffer += len; - - if (len == 0 || regex[len - 1] != '$') - *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. - - *buffer = '\0'; -} - -#endif // GTEST_USES_POSIX_RE - -const char kUnknownFile[] = "unknown file"; - -// Formats a source file path and a line number as they would appear -// in an error message from the compiler used to compile this code. -GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { - const std::string file_name(file == NULL ? kUnknownFile : file); - - if (line < 0) { - return file_name + ":"; - } -#ifdef _MSC_VER - return file_name + "(" + StreamableToString(line) + "):"; -#else - return file_name + ":" + StreamableToString(line) + ":"; -#endif // _MSC_VER -} - -// Formats a file location for compiler-independent XML output. -// Although this function is not platform dependent, we put it next to -// FormatFileLocation in order to contrast the two functions. -// Note that FormatCompilerIndependentFileLocation() does NOT append colon -// to the file location it produces, unlike FormatFileLocation(). -GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( - const char* file, int line) { - const std::string file_name(file == NULL ? kUnknownFile : file); - - if (line < 0) - return file_name; - else - return file_name + ":" + StreamableToString(line); -} - - -GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) - : severity_(severity) { - const char* const marker = - severity == GTEST_INFO ? "[ INFO ]" : - severity == GTEST_WARNING ? "[WARNING]" : - severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; - GetStream() << ::std::endl << marker << " " - << FormatFileLocation(file, line).c_str() << ": "; -} - -// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. -GTestLog::~GTestLog() { - GetStream() << ::std::endl; - if (severity_ == GTEST_FATAL) { - fflush(stderr); - posix::Abort(); - } -} -// Disable Microsoft deprecation warnings for POSIX functions called from -// this class (creat, dup, dup2, and close) -GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) - -#if GTEST_HAS_STREAM_REDIRECTION - -// Object that captures an output stream (stdout/stderr). -class CapturedStream { - public: - // The ctor redirects the stream to a temporary file. - explicit CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { -# if GTEST_OS_WINDOWS - char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT - char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT - - ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); - const UINT success = ::GetTempFileNameA(temp_dir_path, - "gtest_redir", - 0, // Generate unique file name. - temp_file_path); - GTEST_CHECK_(success != 0) - << "Unable to create a temporary file in " << temp_dir_path; - const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); - GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " - << temp_file_path; - filename_ = temp_file_path; -# else - // There's no guarantee that a test has write access to the current - // directory, so we create the temporary file in the /tmp directory - // instead. We use /tmp on most systems, and /sdcard on Android. - // That's because Android doesn't have /tmp. -# if GTEST_OS_LINUX_ANDROID - // Note: Android applications are expected to call the framework's - // Context.getExternalStorageDirectory() method through JNI to get - // the location of the world-writable SD Card directory. However, - // this requires a Context handle, which cannot be retrieved - // globally from native code. Doing so also precludes running the - // code as part of a regular standalone executable, which doesn't - // run in a Dalvik process (e.g. when running it through 'adb shell'). - // - // The location /sdcard is directly accessible from native code - // and is the only location (unofficially) supported by the Android - // team. It's generally a symlink to the real SD Card mount point - // which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or - // other OEM-customized locations. Never rely on these, and always - // use /sdcard. - char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX"; -# else - char name_template[] = "/tmp/captured_stream.XXXXXX"; -# endif // GTEST_OS_LINUX_ANDROID - const int captured_fd = mkstemp(name_template); - filename_ = name_template; -# endif // GTEST_OS_WINDOWS - fflush(NULL); - dup2(captured_fd, fd_); - close(captured_fd); - } - - ~CapturedStream() { - remove(filename_.c_str()); - } - - std::string GetCapturedString() { - if (uncaptured_fd_ != -1) { - // Restores the original stream. - fflush(NULL); - dup2(uncaptured_fd_, fd_); - close(uncaptured_fd_); - uncaptured_fd_ = -1; - } - - FILE* const file = posix::FOpen(filename_.c_str(), "r"); - const std::string content = ReadEntireFile(file); - posix::FClose(file); - return content; - } - - private: - // Reads the entire content of a file as an std::string. - static std::string ReadEntireFile(FILE* file); - - // Returns the size (in bytes) of a file. - static size_t GetFileSize(FILE* file); - - const int fd_; // A stream to capture. - int uncaptured_fd_; - // Name of the temporary file holding the stderr output. - ::std::string filename_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); -}; - -// Returns the size (in bytes) of a file. -size_t CapturedStream::GetFileSize(FILE* file) { - fseek(file, 0, SEEK_END); - return static_cast(ftell(file)); -} - -// Reads the entire content of a file as a string. -std::string CapturedStream::ReadEntireFile(FILE* file) { - const size_t file_size = GetFileSize(file); - char* const buffer = new char[file_size]; - - size_t bytes_last_read = 0; // # of bytes read in the last fread() - size_t bytes_read = 0; // # of bytes read so far - - fseek(file, 0, SEEK_SET); - - // Keeps reading the file until we cannot read further or the - // pre-determined file size is reached. - do { - bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); - bytes_read += bytes_last_read; - } while (bytes_last_read > 0 && bytes_read < file_size); - - const std::string content(buffer, bytes_read); - delete[] buffer; - - return content; -} - -GTEST_DISABLE_MSC_WARNINGS_POP_() - -static CapturedStream* g_captured_stderr = NULL; -static CapturedStream* g_captured_stdout = NULL; - -// Starts capturing an output stream (stdout/stderr). -void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { - if (*stream != NULL) { - GTEST_LOG_(FATAL) << "Only one " << stream_name - << " capturer can exist at a time."; - } - *stream = new CapturedStream(fd); -} - -// Stops capturing the output stream and returns the captured string. -std::string GetCapturedStream(CapturedStream** captured_stream) { - const std::string content = (*captured_stream)->GetCapturedString(); - - delete *captured_stream; - *captured_stream = NULL; - - return content; -} - -// Starts capturing stdout. -void CaptureStdout() { - CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); -} - -// Starts capturing stderr. -void CaptureStderr() { - CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); -} - -// Stops capturing stdout and returns the captured string. -std::string GetCapturedStdout() { - return GetCapturedStream(&g_captured_stdout); -} - -// Stops capturing stderr and returns the captured string. -std::string GetCapturedStderr() { - return GetCapturedStream(&g_captured_stderr); -} - -#endif // GTEST_HAS_STREAM_REDIRECTION - -#if GTEST_HAS_DEATH_TEST - -// A copy of all command line arguments. Set by InitGoogleTest(). -::std::vector g_argvs; - -static const ::std::vector* g_injected_test_argvs = - NULL; // Owned. - -void SetInjectableArgvs(const ::std::vector* argvs) { - if (g_injected_test_argvs != argvs) - delete g_injected_test_argvs; - g_injected_test_argvs = argvs; -} - -const ::std::vector& GetInjectableArgvs() { - if (g_injected_test_argvs != NULL) { - return *g_injected_test_argvs; - } - return g_argvs; -} -#endif // GTEST_HAS_DEATH_TEST - -#if GTEST_OS_WINDOWS_MOBILE -namespace posix { -void Abort() { - DebugBreak(); - TerminateProcess(GetCurrentProcess(), 1); -} -} // namespace posix -#endif // GTEST_OS_WINDOWS_MOBILE - -// Returns the name of the environment variable corresponding to the -// given flag. For example, FlagToEnvVar("foo") will return -// "GTEST_FOO" in the open-source version. -static std::string FlagToEnvVar(const char* flag) { - const std::string full_flag = - (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); - - Message env_var; - for (size_t i = 0; i != full_flag.length(); i++) { - env_var << ToUpper(full_flag.c_str()[i]); - } - - return env_var.GetString(); -} - -// Parses 'str' for a 32-bit signed integer. If successful, writes -// the result to *value and returns true; otherwise leaves *value -// unchanged and returns false. -bool ParseInt32(const Message& src_text, const char* str, Int32* value) { - // Parses the environment variable as a decimal integer. - char* end = NULL; - const long long_value = strtol(str, &end, 10); // NOLINT - - // Has strtol() consumed all characters in the string? - if (*end != '\0') { - // No - an invalid character was encountered. - Message msg; - msg << "WARNING: " << src_text - << " is expected to be a 32-bit integer, but actually" - << " has value \"" << str << "\".\n"; - printf("%s", msg.GetString().c_str()); - fflush(stdout); - return false; - } - - // Is the parsed value in the range of an Int32? - const Int32 result = static_cast(long_value); - if (long_value == LONG_MAX || long_value == LONG_MIN || - // The parsed value overflows as a long. (strtol() returns - // LONG_MAX or LONG_MIN when the input overflows.) - result != long_value - // The parsed value overflows as an Int32. - ) { - Message msg; - msg << "WARNING: " << src_text - << " is expected to be a 32-bit integer, but actually" - << " has value " << str << ", which overflows.\n"; - printf("%s", msg.GetString().c_str()); - fflush(stdout); - return false; - } - - *value = result; - return true; -} - -// Reads and returns the Boolean environment variable corresponding to -// the given flag; if it's not set, returns default_value. -// -// The value is considered true iff it's not "0". -bool BoolFromGTestEnv(const char* flag, bool default_value) { - const std::string env_var = FlagToEnvVar(flag); - const char* const string_value = posix::GetEnv(env_var.c_str()); - return string_value == NULL ? - default_value : strcmp(string_value, "0") != 0; -} - -// Reads and returns a 32-bit integer stored in the environment -// variable corresponding to the given flag; if it isn't set or -// doesn't represent a valid 32-bit integer, returns default_value. -Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { - const std::string env_var = FlagToEnvVar(flag); - const char* const string_value = posix::GetEnv(env_var.c_str()); - if (string_value == NULL) { - // The environment variable is not set. - return default_value; - } - - Int32 result = default_value; - if (!ParseInt32(Message() << "Environment variable " << env_var, - string_value, &result)) { - printf("The default value %s is used.\n", - (Message() << default_value).GetString().c_str()); - fflush(stdout); - return default_value; - } - - return result; -} - -// Reads and returns the string environment variable corresponding to -// the given flag; if it's not set, returns default_value. -const char* StringFromGTestEnv(const char* flag, const char* default_value) { - const std::string env_var = FlagToEnvVar(flag); - const char* const value = posix::GetEnv(env_var.c_str()); - return value == NULL ? default_value : value; -} - -} // namespace internal -} // namespace testing \ No newline at end of file diff --git a/src/gtest/src/gtest-printers.cc b/src/gtest/src/gtest-printers.cc deleted file mode 100644 index 3a6ae96b..00000000 --- a/src/gtest/src/gtest-printers.cc +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright 2007 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// - -// Google Test - The Google C++ Testing Framework -// -// This file implements a universal value printer that can print a -// value of any type T: -// -// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); -// -// It uses the << operator when possible, and prints the bytes in the -// object otherwise. A user can override its behavior for a class -// type Foo by defining either operator<<(::std::ostream&, const Foo&) -// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that -// defines Foo. - -#include "gtest/gtest-printers.h" -#include -#include -#include -#include // NOLINT -#include -#include "gtest/internal/gtest-port.h" - -namespace testing { - -namespace { - -using ::std::ostream; - -// Prints a segment of bytes in the given object. -GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ -GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ -GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ -void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, - size_t count, ostream* os) { - char text[5] = ""; - for (size_t i = 0; i != count; i++) { - const size_t j = start + i; - if (i != 0) { - // Organizes the bytes into groups of 2 for easy parsing by - // human. - if ((j % 2) == 0) - *os << ' '; - else - *os << '-'; - } - GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]); - *os << text; - } -} - -// Prints the bytes in the given value to the given ostream. -void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, - ostream* os) { - // Tells the user how big the object is. - *os << count << "-byte object <"; - - const size_t kThreshold = 132; - const size_t kChunkSize = 64; - // If the object size is bigger than kThreshold, we'll have to omit - // some details by printing only the first and the last kChunkSize - // bytes. - // TODO(user): let the user control the threshold using a flag. - if (count < kThreshold) { - PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); - } else { - PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); - *os << " ... "; - // Rounds up to 2-byte boundary. - const size_t resume_pos = (count - kChunkSize + 1)/2*2; - PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); - } - *os << ">"; -} - -} // namespace - -namespace internal2 { - -// Delegates to PrintBytesInObjectToImpl() to print the bytes in the -// given object. The delegation simplifies the implementation, which -// uses the << operator and thus is easier done outside of the -// ::testing::internal namespace, which contains a << operator that -// sometimes conflicts with the one in STL. -void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, - ostream* os) { - PrintBytesInObjectToImpl(obj_bytes, count, os); -} - -} // namespace internal2 - -namespace internal { - -// Depending on the value of a char (or wchar_t), we print it in one -// of three formats: -// - as is if it's a printable ASCII (e.g. 'a', '2', ' '), -// - as a hexidecimal escape sequence (e.g. '\x7F'), or -// - as a special escape sequence (e.g. '\r', '\n'). -enum CharFormat { - kAsIs, - kHexEscape, - kSpecialEscape -}; - -// Returns true if c is a printable ASCII character. We test the -// value of c directly instead of calling isprint(), which is buggy on -// Windows Mobile. -inline bool IsPrintableAscii(wchar_t c) { - return 0x20 <= c && c <= 0x7E; -} - -// Prints a wide or narrow char c as a character literal without the -// quotes, escaping it when necessary; returns how c was formatted. -// The template argument UnsignedChar is the unsigned version of Char, -// which is the type of c. -template -static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { - switch (static_cast(c)) { - case L'\0': - *os << "\\0"; - break; - case L'\'': - *os << "\\'"; - break; - case L'\\': - *os << "\\\\"; - break; - case L'\a': - *os << "\\a"; - break; - case L'\b': - *os << "\\b"; - break; - case L'\f': - *os << "\\f"; - break; - case L'\n': - *os << "\\n"; - break; - case L'\r': - *os << "\\r"; - break; - case L'\t': - *os << "\\t"; - break; - case L'\v': - *os << "\\v"; - break; - default: - if (IsPrintableAscii(c)) { - *os << static_cast(c); - return kAsIs; - } else { - *os << "\\x" + String::FormatHexInt(static_cast(c)); - return kHexEscape; - } - } - return kSpecialEscape; -} - -// Prints a wchar_t c as if it's part of a string literal, escaping it when -// necessary; returns how c was formatted. -static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) { - switch (c) { - case L'\'': - *os << "'"; - return kAsIs; - case L'"': - *os << "\\\""; - return kSpecialEscape; - default: - return PrintAsCharLiteralTo(c, os); - } -} - -// Prints a char c as if it's part of a string literal, escaping it when -// necessary; returns how c was formatted. -static CharFormat PrintAsStringLiteralTo(char c, ostream* os) { - return PrintAsStringLiteralTo( - static_cast(static_cast(c)), os); -} - -// Prints a wide or narrow character c and its code. '\0' is printed -// as "'\\0'", other unprintable characters are also properly escaped -// using the standard C++ escape sequence. The template argument -// UnsignedChar is the unsigned version of Char, which is the type of c. -template -void PrintCharAndCodeTo(Char c, ostream* os) { - // First, print c as a literal in the most readable form we can find. - *os << ((sizeof(c) > 1) ? "L'" : "'"); - const CharFormat format = PrintAsCharLiteralTo(c, os); - *os << "'"; - - // To aid user debugging, we also print c's code in decimal, unless - // it's 0 (in which case c was printed as '\\0', making the code - // obvious). - if (c == 0) - return; - *os << " (" << static_cast(c); - - // For more convenience, we print c's code again in hexidecimal, - // unless c was already printed in the form '\x##' or the code is in - // [1, 9]. - if (format == kHexEscape || (1 <= c && c <= 9)) { - // Do nothing. - } else { - *os << ", 0x" << String::FormatHexInt(static_cast(c)); - } - *os << ")"; -} - -void PrintTo(unsigned char c, ::std::ostream* os) { - PrintCharAndCodeTo(c, os); -} -void PrintTo(signed char c, ::std::ostream* os) { - PrintCharAndCodeTo(c, os); -} - -// Prints a wchar_t as a symbol if it is printable or as its internal -// code otherwise and also as its code. L'\0' is printed as "L'\\0'". -void PrintTo(wchar_t wc, ostream* os) { - PrintCharAndCodeTo(wc, os); -} - -// Prints the given array of characters to the ostream. CharType must be either -// char or wchar_t. -// The array starts at begin, the length is len, it may include '\0' characters -// and may not be NUL-terminated. -template -GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ -GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ -GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ -static void PrintCharsAsStringTo( - const CharType* begin, size_t len, ostream* os) { - const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; - *os << kQuoteBegin; - bool is_previous_hex = false; - for (size_t index = 0; index < len; ++index) { - const CharType cur = begin[index]; - if (is_previous_hex && IsXDigit(cur)) { - // Previous character is of '\x..' form and this character can be - // interpreted as another hexadecimal digit in its number. Break string to - // disambiguate. - *os << "\" " << kQuoteBegin; - } - is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape; - } - *os << "\""; -} - -// Prints a (const) char/wchar_t array of 'len' elements, starting at address -// 'begin'. CharType must be either char or wchar_t. -template -GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ -GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ -GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ -static void UniversalPrintCharArray( - const CharType* begin, size_t len, ostream* os) { - // The code - // const char kFoo[] = "foo"; - // generates an array of 4, not 3, elements, with the last one being '\0'. - // - // Therefore when printing a char array, we don't print the last element if - // it's '\0', such that the output matches the string literal as it's - // written in the source code. - if (len > 0 && begin[len - 1] == '\0') { - PrintCharsAsStringTo(begin, len - 1, os); - return; - } - - // If, however, the last element in the array is not '\0', e.g. - // const char kFoo[] = { 'f', 'o', 'o' }; - // we must print the entire array. We also print a message to indicate - // that the array is not NUL-terminated. - PrintCharsAsStringTo(begin, len, os); - *os << " (no terminating NUL)"; -} - -// Prints a (const) char array of 'len' elements, starting at address 'begin'. -void UniversalPrintArray(const char* begin, size_t len, ostream* os) { - UniversalPrintCharArray(begin, len, os); -} - -// Prints a (const) wchar_t array of 'len' elements, starting at address -// 'begin'. -void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) { - UniversalPrintCharArray(begin, len, os); -} - -// Prints the given C string to the ostream. -void PrintTo(const char* s, ostream* os) { - if (s == NULL) { - *os << "NULL"; - } else { - *os << ImplicitCast_(s) << " pointing to "; - PrintCharsAsStringTo(s, strlen(s), os); - } -} - -// MSVC compiler can be configured to define whar_t as a typedef -// of unsigned short. Defining an overload for const wchar_t* in that case -// would cause pointers to unsigned shorts be printed as wide strings, -// possibly accessing more memory than intended and causing invalid -// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when -// wchar_t is implemented as a native type. -#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) -// Prints the given wide C string to the ostream. -void PrintTo(const wchar_t* s, ostream* os) { - if (s == NULL) { - *os << "NULL"; - } else { - *os << ImplicitCast_(s) << " pointing to "; - PrintCharsAsStringTo(s, std::wcslen(s), os); - } -} -#endif // wchar_t is native - -// Prints a ::string object. -#if GTEST_HAS_GLOBAL_STRING -void PrintStringTo(const ::string& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); -} -#endif // GTEST_HAS_GLOBAL_STRING - -void PrintStringTo(const ::std::string& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); -} - -// Prints a ::wstring object. -#if GTEST_HAS_GLOBAL_WSTRING -void PrintWideStringTo(const ::wstring& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); -} -#endif // GTEST_HAS_GLOBAL_WSTRING - -#if GTEST_HAS_STD_WSTRING -void PrintWideStringTo(const ::std::wstring& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); -} -#endif // GTEST_HAS_STD_WSTRING - -} // namespace internal - -} // namespace testing \ No newline at end of file diff --git a/src/gtest/src/gtest-test-part.cc b/src/gtest/src/gtest-test-part.cc deleted file mode 100644 index bbcc5cbb..00000000 --- a/src/gtest/src/gtest-test-part.cc +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2008 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// -// -// The Google C++ Testing Framework (Google Test) - -#include "gtest/gtest-test-part.h" - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick exists to -// prevent the accidental inclusion of gtest-internal-inl.h in the -// user's code. -#define GTEST_IMPLEMENTATION_ 1 -#include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ - -namespace testing { - -using internal::GetUnitTestImpl; - -// Gets the summary of the failure message by omitting the stack trace -// in it. -std::string TestPartResult::ExtractSummary(const char* message) { - const char* const stack_trace = strstr(message, internal::kStackTraceMarker); - return stack_trace == NULL ? message : - std::string(message, stack_trace); -} - -// Prints a TestPartResult object. -std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { - return os - << result.file_name() << ":" << result.line_number() << ": " - << (result.type() == TestPartResult::kSuccess ? "Success" : - result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : - "Non-fatal failure") << ":\n" - << result.message() << std::endl; -} - -// Appends a TestPartResult to the array. -void TestPartResultArray::Append(const TestPartResult& result) { - array_.push_back(result); -} - -// Returns the TestPartResult at the given index (0-based). -const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { - if (index < 0 || index >= size()) { - printf("\nInvalid index (%d) into TestPartResultArray.\n", index); - internal::posix::Abort(); - } - - return array_[index]; -} - -// Returns the number of TestPartResult objects in the array. -int TestPartResultArray::size() const { - return static_cast(array_.size()); -} - -namespace internal { - -HasNewFatalFailureHelper::HasNewFatalFailureHelper() - : has_new_fatal_failure_(false), - original_reporter_(GetUnitTestImpl()-> - GetTestPartResultReporterForCurrentThread()) { - GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); -} - -HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { - GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( - original_reporter_); -} - -void HasNewFatalFailureHelper::ReportTestPartResult( - const TestPartResult& result) { - if (result.fatally_failed()) - has_new_fatal_failure_ = true; - original_reporter_->ReportTestPartResult(result); -} - -} // namespace internal - -} // namespace testing \ No newline at end of file diff --git a/src/gtest/src/gtest-typed-test.cc b/src/gtest/src/gtest-typed-test.cc deleted file mode 100644 index e0cf7b76..00000000 --- a/src/gtest/src/gtest-typed-test.cc +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2008 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// - -#include "gtest/gtest-typed-test.h" -#include "gtest/gtest.h" - -namespace testing { -namespace internal { - -#if GTEST_HAS_TYPED_TEST_P - -// Skips to the first non-space char in str. Returns an empty string if str -// contains only whitespace characters. -static const char* SkipSpaces(const char* str) { - while (IsSpace(*str)) - str++; - return str; -} - -static std::vector SplitIntoTestNames(const char* src) { - std::vector name_vec; - src = SkipSpaces(src); - for (; src != NULL; src = SkipComma(src)) { - name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src))); - } - return name_vec; -} - -// Verifies that registered_tests match the test names in -// defined_test_names_; returns registered_tests if successful, or -// aborts the program otherwise. -const char* TypedTestCasePState::VerifyRegisteredTestNames( - const char* file, int line, const char* registered_tests) { - typedef ::std::set::const_iterator DefinedTestIter; - registered_ = true; - - std::vector name_vec = SplitIntoTestNames(registered_tests); - - Message errors; - - std::set tests; - for (std::vector::const_iterator name_it = name_vec.begin(); - name_it != name_vec.end(); ++name_it) { - const std::string& name = *name_it; - if (tests.count(name) != 0) { - errors << "Test " << name << " is listed more than once.\n"; - continue; - } - - bool found = false; - for (DefinedTestIter it = defined_test_names_.begin(); - it != defined_test_names_.end(); - ++it) { - if (name == *it) { - found = true; - break; - } - } - - if (found) { - tests.insert(name); - } else { - errors << "No test named " << name - << " can be found in this test case.\n"; - } - } - - for (DefinedTestIter it = defined_test_names_.begin(); - it != defined_test_names_.end(); - ++it) { - if (tests.count(*it) == 0) { - errors << "You forgot to list test " << *it << ".\n"; - } - } - - const std::string& errors_str = errors.GetString(); - if (errors_str != "") { - fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), - errors_str.c_str()); - fflush(stderr); - posix::Abort(); - } - - return registered_tests; -} - -#endif // GTEST_HAS_TYPED_TEST_P - -} // namespace internal -} // namespace testing \ No newline at end of file diff --git a/src/gtest/src/gtest.cc b/src/gtest/src/gtest.cc deleted file mode 100644 index ede3dfb7..00000000 --- a/src/gtest/src/gtest.cc +++ /dev/null @@ -1,5314 +0,0 @@ -// Copyright 2005 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. -// -// -// The Google C++ Testing Framework (Google Test) - -#include "gtest/gtest.h" -#include "gtest/gtest-spi.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include // NOLINT -#include -#include - -#if GTEST_OS_LINUX - -// TODO(kenton@google.com): Use autoconf to detect availability of -// gettimeofday(). -# define GTEST_HAS_GETTIMEOFDAY_ 1 - -# include // NOLINT -# include // NOLINT -# include // NOLINT -// Declares vsnprintf(). This header is not available on Windows. -# include // NOLINT -# include // NOLINT -# include // NOLINT -# include // NOLINT -# include - -#elif GTEST_OS_SYMBIAN -# define GTEST_HAS_GETTIMEOFDAY_ 1 -# include // NOLINT - -#elif GTEST_OS_ZOS -# define GTEST_HAS_GETTIMEOFDAY_ 1 -# include // NOLINT - -// On z/OS we additionally need strings.h for strcasecmp. -# include // NOLINT - -#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. - -# include // NOLINT -# undef min - -#elif GTEST_OS_WINDOWS // We are on Windows proper. - -# include // NOLINT -# include // NOLINT -# include // NOLINT -# include // NOLINT - -# if GTEST_OS_WINDOWS_MINGW -// MinGW has gettimeofday() but not _ftime64(). -// TODO(kenton@google.com): Use autoconf to detect availability of -// gettimeofday(). -// TODO(kenton@google.com): There are other ways to get the time on -// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW -// supports these. consider using them instead. -# define GTEST_HAS_GETTIMEOFDAY_ 1 -# include // NOLINT -# endif // GTEST_OS_WINDOWS_MINGW - -// cpplint thinks that the header is already included, so we want to -// silence it. -# include // NOLINT -# undef min - -#else - -// Assume other platforms have gettimeofday(). -// TODO(kenton@google.com): Use autoconf to detect availability of -// gettimeofday(). -# define GTEST_HAS_GETTIMEOFDAY_ 1 - -// cpplint thinks that the header is already included, so we want to -// silence it. -# include // NOLINT -# include // NOLINT - -#endif // GTEST_OS_LINUX - -#if GTEST_HAS_EXCEPTIONS -# include -#endif - -#if GTEST_CAN_STREAM_RESULTS_ -# include // NOLINT -# include // NOLINT -# include // NOLINT -# include // NOLINT -#endif - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 -#include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ - -#if GTEST_OS_WINDOWS -# define vsnprintf _vsnprintf -#endif // GTEST_OS_WINDOWS - -namespace testing { - -using internal::CountIf; -using internal::ForEach; -using internal::GetElementOr; -using internal::Shuffle; - -// Constants. - -// A test whose test case name or test name matches this filter is -// disabled and not run. -static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; - -// A test case whose name matches this filter is considered a death -// test case and will be run before test cases whose name doesn't -// match this filter. -static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; - -// A test filter that matches everything. -static const char kUniversalFilter[] = "*"; - -// The default output file for XML output. -static const char kDefaultOutputFile[] = "test_detail.xml"; - -// The environment variable name for the test shard index. -static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; -// The environment variable name for the total number of test shards. -static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; -// The environment variable name for the test shard status file. -static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; - -namespace internal { - -// The text used in failure messages to indicate the start of the -// stack trace. -const char kStackTraceMarker[] = "\nStack trace:\n"; - -// g_help_flag is true iff the --help flag or an equivalent form is -// specified on the command line. -bool g_help_flag = false; - -} // namespace internal - -static const char* GetDefaultFilter() { - return kUniversalFilter; -} - -GTEST_DEFINE_bool_( - also_run_disabled_tests, - internal::BoolFromGTestEnv("also_run_disabled_tests", false), - "Run disabled tests too, in addition to the tests normally being run."); - -GTEST_DEFINE_bool_( - break_on_failure, - internal::BoolFromGTestEnv("break_on_failure", false), - "True iff a failed assertion should be a debugger break-point."); - -GTEST_DEFINE_bool_( - catch_exceptions, - internal::BoolFromGTestEnv("catch_exceptions", true), - "True iff " GTEST_NAME_ - " should catch exceptions and treat them as test failures."); - -GTEST_DEFINE_string_( - color, - internal::StringFromGTestEnv("color", "auto"), - "Whether to use colors in the output. Valid values: yes, no, " - "and auto. 'auto' means to use colors if the output is " - "being sent to a terminal and the TERM environment variable " - "is set to a terminal type that supports colors."); - -GTEST_DEFINE_string_( - filter, - internal::StringFromGTestEnv("filter", GetDefaultFilter()), - "A colon-separated list of glob (not regex) patterns " - "for filtering the tests to run, optionally followed by a " - "'-' and a : separated list of negative patterns (tests to " - "exclude). A test is run if it matches one of the positive " - "patterns and does not match any of the negative patterns."); - -GTEST_DEFINE_bool_(list_tests, false, - "List all tests without running them."); - -GTEST_DEFINE_string_( - output, - internal::StringFromGTestEnv("output", ""), - "A format (currently must be \"xml\"), optionally followed " - "by a colon and an output file name or directory. A directory " - "is indicated by a trailing pathname separator. " - "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " - "If a directory is specified, output files will be created " - "within that directory, with file-names based on the test " - "executable's name and, if necessary, made unique by adding " - "digits."); - -GTEST_DEFINE_bool_( - print_time, - internal::BoolFromGTestEnv("print_time", true), - "True iff " GTEST_NAME_ - " should display elapsed time in text output."); - -GTEST_DEFINE_int32_( - random_seed, - internal::Int32FromGTestEnv("random_seed", 0), - "Random number seed to use when shuffling test orders. Must be in range " - "[1, 99999], or 0 to use a seed based on the current time."); - -GTEST_DEFINE_int32_( - repeat, - internal::Int32FromGTestEnv("repeat", 1), - "How many times to repeat each test. Specify a negative number " - "for repeating forever. Useful for shaking out flaky tests."); - -GTEST_DEFINE_bool_( - show_internal_stack_frames, false, - "True iff " GTEST_NAME_ " should include internal stack frames when " - "printing test failure stack traces."); - -GTEST_DEFINE_bool_( - shuffle, - internal::BoolFromGTestEnv("shuffle", false), - "True iff " GTEST_NAME_ - " should randomize tests' order on every run."); - -GTEST_DEFINE_int32_( - stack_trace_depth, - internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), - "The maximum number of stack frames to print when an " - "assertion fails. The valid range is 0 through 100, inclusive."); - -GTEST_DEFINE_string_( - stream_result_to, - internal::StringFromGTestEnv("stream_result_to", ""), - "This flag specifies the host name and the port number on which to stream " - "test results. Example: \"localhost:555\". The flag is effective only on " - "Linux."); - -GTEST_DEFINE_bool_( - throw_on_failure, - internal::BoolFromGTestEnv("throw_on_failure", false), - "When this flag is specified, a failed assertion will throw an exception " - "if exceptions are enabled or exit the program with a non-zero code " - "otherwise."); - -namespace internal { - -// Generates a random number from [0, range), using a Linear -// Congruential Generator (LCG). Crashes if 'range' is 0 or greater -// than kMaxRange. -UInt32 Random::Generate(UInt32 range) { - // These constants are the same as are used in glibc's rand(3). - state_ = (1103515245U*state_ + 12345U) % kMaxRange; - - GTEST_CHECK_(range > 0) - << "Cannot generate a number in the range [0, 0)."; - GTEST_CHECK_(range <= kMaxRange) - << "Generation of a number in [0, " << range << ") was requested, " - << "but this can only generate numbers in [0, " << kMaxRange << ")."; - - // Converting via modulus introduces a bit of downward bias, but - // it's simple, and a linear congruential generator isn't too good - // to begin with. - return state_ % range; -} - -// GTestIsInitialized() returns true iff the user has initialized -// Google Test. Useful for catching the user mistake of not initializing -// Google Test before calling RUN_ALL_TESTS(). -// -// A user must call testing::InitGoogleTest() to initialize Google -// Test. g_init_gtest_count is set to the number of times -// InitGoogleTest() has been called. We don't protect this variable -// under a mutex as it is only accessed in the main thread. -GTEST_API_ int g_init_gtest_count = 0; -static bool GTestIsInitialized() { return g_init_gtest_count != 0; } - -// Iterates over a vector of TestCases, keeping a running sum of the -// results of calling a given int-returning method on each. -// Returns the sum. -static int SumOverTestCaseList(const std::vector& case_list, - int (TestCase::*method)() const) { - int sum = 0; - for (size_t i = 0; i < case_list.size(); i++) { - sum += (case_list[i]->*method)(); - } - return sum; -} - -// Returns true iff the test case passed. -static bool TestCasePassed(const TestCase* test_case) { - return test_case->should_run() && test_case->Passed(); -} - -// Returns true iff the test case failed. -static bool TestCaseFailed(const TestCase* test_case) { - return test_case->should_run() && test_case->Failed(); -} - -// Returns true iff test_case contains at least one test that should -// run. -static bool ShouldRunTestCase(const TestCase* test_case) { - return test_case->should_run(); -} - -// AssertHelper constructor. -AssertHelper::AssertHelper(TestPartResult::Type type, - const char* file, - int line, - const char* message) - : data_(new AssertHelperData(type, file, line, message)) { -} - -AssertHelper::~AssertHelper() { - delete data_; -} - -// Message assignment, for assertion streaming support. -void AssertHelper::operator=(const Message& message) const { - UnitTest::GetInstance()-> - AddTestPartResult(data_->type, data_->file, data_->line, - AppendUserMessage(data_->message, message), - UnitTest::GetInstance()->impl() - ->CurrentOsStackTraceExceptTop(1) - // Skips the stack frame for this function itself. - ); // NOLINT -} - -// Mutex for linked pointers. -GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); - -// Application pathname gotten in InitGoogleTest. -std::string g_executable_path; - -// Returns the current application's name, removing directory path if that -// is present. -FilePath GetCurrentExecutableName() { - FilePath result; - -#if GTEST_OS_WINDOWS - result.Set(FilePath(g_executable_path).RemoveExtension("exe")); -#else - result.Set(FilePath(g_executable_path)); -#endif // GTEST_OS_WINDOWS - - return result.RemoveDirectoryName(); -} - -// Functions for processing the gtest_output flag. - -// Returns the output format, or "" for normal printed output. -std::string UnitTestOptions::GetOutputFormat() { - const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); - if (gtest_output_flag == NULL) return std::string(""); - - const char* const colon = strchr(gtest_output_flag, ':'); - return (colon == NULL) ? - std::string(gtest_output_flag) : - std::string(gtest_output_flag, colon - gtest_output_flag); -} - -// Returns the name of the requested output file, or the default if none -// was explicitly specified. -std::string UnitTestOptions::GetAbsolutePathToOutputFile() { - const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); - if (gtest_output_flag == NULL) - return ""; - - const char* const colon = strchr(gtest_output_flag, ':'); - if (colon == NULL) - return internal::FilePath::ConcatPaths( - internal::FilePath( - UnitTest::GetInstance()->original_working_dir()), - internal::FilePath(kDefaultOutputFile)).string(); - - internal::FilePath output_name(colon + 1); - if (!output_name.IsAbsolutePath()) - // TODO(wan@google.com): on Windows \some\path is not an absolute - // path (as its meaning depends on the current drive), yet the - // following logic for turning it into an absolute path is wrong. - // Fix it. - output_name = internal::FilePath::ConcatPaths( - internal::FilePath(UnitTest::GetInstance()->original_working_dir()), - internal::FilePath(colon + 1)); - - if (!output_name.IsDirectory()) - return output_name.string(); - - internal::FilePath result(internal::FilePath::GenerateUniqueFileName( - output_name, internal::GetCurrentExecutableName(), - GetOutputFormat().c_str())); - return result.string(); -} - -// Returns true iff the wildcard pattern matches the string. The -// first ':' or '\0' character in pattern marks the end of it. -// -// This recursive algorithm isn't very efficient, but is clear and -// works well enough for matching test names, which are short. -bool UnitTestOptions::PatternMatchesString(const char *pattern, - const char *str) { - switch (*pattern) { - case '\0': - case ':': // Either ':' or '\0' marks the end of the pattern. - return *str == '\0'; - case '?': // Matches any single character. - return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); - case '*': // Matches any string (possibly empty) of characters. - return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || - PatternMatchesString(pattern + 1, str); - default: // Non-special character. Matches itself. - return *pattern == *str && - PatternMatchesString(pattern + 1, str + 1); - } -} - -bool UnitTestOptions::MatchesFilter( - const std::string& name, const char* filter) { - const char *cur_pattern = filter; - for (;;) { - if (PatternMatchesString(cur_pattern, name.c_str())) { - return true; - } - - // Finds the next pattern in the filter. - cur_pattern = strchr(cur_pattern, ':'); - - // Returns if no more pattern can be found. - if (cur_pattern == NULL) { - return false; - } - - // Skips the pattern separater (the ':' character). - cur_pattern++; - } -} - -// Returns true iff the user-specified filter matches the test case -// name and the test name. -bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name, - const std::string &test_name) { - const std::string& full_name = test_case_name + "." + test_name.c_str(); - - // Split --gtest_filter at '-', if there is one, to separate into - // positive filter and negative filter portions - const char* const p = GTEST_FLAG(filter).c_str(); - const char* const dash = strchr(p, '-'); - std::string positive; - std::string negative; - if (dash == NULL) { - positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter - negative = ""; - } else { - positive = std::string(p, dash); // Everything up to the dash - negative = std::string(dash + 1); // Everything after the dash - if (positive.empty()) { - // Treat '-test1' as the same as '*-test1' - positive = kUniversalFilter; - } - } - - // A filter is a colon-separated list of patterns. It matches a - // test if any pattern in it matches the test. - return (MatchesFilter(full_name, positive.c_str()) && - !MatchesFilter(full_name, negative.c_str())); -} - -#if GTEST_HAS_SEH -// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the -// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. -// This function is useful as an __except condition. -int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { - // Google Test should handle a SEH exception if: - // 1. the user wants it to, AND - // 2. this is not a breakpoint exception, AND - // 3. this is not a C++ exception (VC++ implements them via SEH, - // apparently). - // - // SEH exception code for C++ exceptions. - // (see http://support.microsoft.com/kb/185294 for more information). - const DWORD kCxxExceptionCode = 0xe06d7363; - - bool should_handle = true; - - if (!GTEST_FLAG(catch_exceptions)) - should_handle = false; - else if (exception_code == EXCEPTION_BREAKPOINT) - should_handle = false; - else if (exception_code == kCxxExceptionCode) - should_handle = false; - - return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; -} -#endif // GTEST_HAS_SEH - -} // namespace internal - -// The c'tor sets this object as the test part result reporter used by -// Google Test. The 'result' parameter specifies where to report the -// results. Intercepts only failures from the current thread. -ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( - TestPartResultArray* result) - : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), - result_(result) { - Init(); -} - -// The c'tor sets this object as the test part result reporter used by -// Google Test. The 'result' parameter specifies where to report the -// results. -ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( - InterceptMode intercept_mode, TestPartResultArray* result) - : intercept_mode_(intercept_mode), - result_(result) { - Init(); -} - -void ScopedFakeTestPartResultReporter::Init() { - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - if (intercept_mode_ == INTERCEPT_ALL_THREADS) { - old_reporter_ = impl->GetGlobalTestPartResultReporter(); - impl->SetGlobalTestPartResultReporter(this); - } else { - old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); - impl->SetTestPartResultReporterForCurrentThread(this); - } -} - -// The d'tor restores the test part result reporter used by Google Test -// before. -ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - if (intercept_mode_ == INTERCEPT_ALL_THREADS) { - impl->SetGlobalTestPartResultReporter(old_reporter_); - } else { - impl->SetTestPartResultReporterForCurrentThread(old_reporter_); - } -} - -// Increments the test part result count and remembers the result. -// This method is from the TestPartResultReporterInterface interface. -void ScopedFakeTestPartResultReporter::ReportTestPartResult( - const TestPartResult& result) { - result_->Append(result); -} - -namespace internal { - -// Returns the type ID of ::testing::Test. We should always call this -// instead of GetTypeId< ::testing::Test>() to get the type ID of -// testing::Test. This is to work around a suspected linker bug when -// using Google Test as a framework on Mac OS X. The bug causes -// GetTypeId< ::testing::Test>() to return different values depending -// on whether the call is from the Google Test framework itself or -// from user test code. GetTestTypeId() is guaranteed to always -// return the same value, as it always calls GetTypeId<>() from the -// gtest.cc, which is within the Google Test framework. -TypeId GetTestTypeId() { - return GetTypeId(); -} - -// The value of GetTestTypeId() as seen from within the Google Test -// library. This is solely for testing GetTestTypeId(). -extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); - -// This predicate-formatter checks that 'results' contains a test part -// failure of the given type and that the failure message contains the -// given substring. -AssertionResult HasOneFailure(const char* /* results_expr */, - const char* /* type_expr */, - const char* /* substr_expr */, - const TestPartResultArray& results, - TestPartResult::Type type, - const string& substr) { - const std::string expected(type == TestPartResult::kFatalFailure ? - "1 fatal failure" : - "1 non-fatal failure"); - Message msg; - if (results.size() != 1) { - msg << "Expected: " << expected << "\n" - << " Actual: " << results.size() << " failures"; - for (int i = 0; i < results.size(); i++) { - msg << "\n" << results.GetTestPartResult(i); - } - return AssertionFailure() << msg; - } - - const TestPartResult& r = results.GetTestPartResult(0); - if (r.type() != type) { - return AssertionFailure() << "Expected: " << expected << "\n" - << " Actual:\n" - << r; - } - - if (strstr(r.message(), substr.c_str()) == NULL) { - return AssertionFailure() << "Expected: " << expected << " containing \"" - << substr << "\"\n" - << " Actual:\n" - << r; - } - - return AssertionSuccess(); -} - -// The constructor of SingleFailureChecker remembers where to look up -// test part results, what type of failure we expect, and what -// substring the failure message should contain. -SingleFailureChecker:: SingleFailureChecker( - const TestPartResultArray* results, - TestPartResult::Type type, - const string& substr) - : results_(results), - type_(type), - substr_(substr) {} - -// The destructor of SingleFailureChecker verifies that the given -// TestPartResultArray contains exactly one failure that has the given -// type and contains the given substring. If that's not the case, a -// non-fatal failure will be generated. -SingleFailureChecker::~SingleFailureChecker() { - EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_); -} - -DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( - UnitTestImpl* unit_test) : unit_test_(unit_test) {} - -void DefaultGlobalTestPartResultReporter::ReportTestPartResult( - const TestPartResult& result) { - unit_test_->current_test_result()->AddTestPartResult(result); - unit_test_->listeners()->repeater()->OnTestPartResult(result); -} - -DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( - UnitTestImpl* unit_test) : unit_test_(unit_test) {} - -void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( - const TestPartResult& result) { - unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); -} - -// Returns the global test part result reporter. -TestPartResultReporterInterface* -UnitTestImpl::GetGlobalTestPartResultReporter() { - internal::MutexLock lock(&global_test_part_result_reporter_mutex_); - return global_test_part_result_repoter_; -} - -// Sets the global test part result reporter. -void UnitTestImpl::SetGlobalTestPartResultReporter( - TestPartResultReporterInterface* reporter) { - internal::MutexLock lock(&global_test_part_result_reporter_mutex_); - global_test_part_result_repoter_ = reporter; -} - -// Returns the test part result reporter for the current thread. -TestPartResultReporterInterface* -UnitTestImpl::GetTestPartResultReporterForCurrentThread() { - return per_thread_test_part_result_reporter_.get(); -} - -// Sets the test part result reporter for the current thread. -void UnitTestImpl::SetTestPartResultReporterForCurrentThread( - TestPartResultReporterInterface* reporter) { - per_thread_test_part_result_reporter_.set(reporter); -} - -// Gets the number of successful test cases. -int UnitTestImpl::successful_test_case_count() const { - return CountIf(test_cases_, TestCasePassed); -} - -// Gets the number of failed test cases. -int UnitTestImpl::failed_test_case_count() const { - return CountIf(test_cases_, TestCaseFailed); -} - -// Gets the number of all test cases. -int UnitTestImpl::total_test_case_count() const { - return static_cast(test_cases_.size()); -} - -// Gets the number of all test cases that contain at least one test -// that should run. -int UnitTestImpl::test_case_to_run_count() const { - return CountIf(test_cases_, ShouldRunTestCase); -} - -// Gets the number of successful tests. -int UnitTestImpl::successful_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); -} - -// Gets the number of failed tests. -int UnitTestImpl::failed_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); -} - -// Gets the number of disabled tests that will be reported in the XML report. -int UnitTestImpl::reportable_disabled_test_count() const { - return SumOverTestCaseList(test_cases_, - &TestCase::reportable_disabled_test_count); -} - -// Gets the number of disabled tests. -int UnitTestImpl::disabled_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); -} - -// Gets the number of tests to be printed in the XML report. -int UnitTestImpl::reportable_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::reportable_test_count); -} - -// Gets the number of all tests. -int UnitTestImpl::total_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); -} - -// Gets the number of tests that should run. -int UnitTestImpl::test_to_run_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); -} - -// Returns the current OS stack trace as an std::string. -// -// The maximum number of stack frames to be included is specified by -// the gtest_stack_trace_depth flag. The skip_count parameter -// specifies the number of top frames to be skipped, which doesn't -// count against the number of frames to be included. -// -// For example, if Foo() calls Bar(), which in turn calls -// CurrentOsStackTraceExceptTop(1), Foo() will be included in the -// trace but Bar() and CurrentOsStackTraceExceptTop() won't. -std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { - (void)skip_count; - return ""; -} - -// Returns the current time in milliseconds. -TimeInMillis GetTimeInMillis() { -#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) - // Difference between 1970-01-01 and 1601-01-01 in milliseconds. - // http://analogous.blogspot.com/2005/04/epoch.html - const TimeInMillis kJavaEpochToWinFileTimeDelta = - static_cast(116444736UL) * 100000UL; - const DWORD kTenthMicrosInMilliSecond = 10000; - - SYSTEMTIME now_systime; - FILETIME now_filetime; - ULARGE_INTEGER now_int64; - // TODO(kenton@google.com): Shouldn't this just use - // GetSystemTimeAsFileTime()? - GetSystemTime(&now_systime); - if (SystemTimeToFileTime(&now_systime, &now_filetime)) { - now_int64.LowPart = now_filetime.dwLowDateTime; - now_int64.HighPart = now_filetime.dwHighDateTime; - now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - - kJavaEpochToWinFileTimeDelta; - return now_int64.QuadPart; - } - return 0; -#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ - __timeb64 now; - - // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 - // (deprecated function) there. - // TODO(kenton@google.com): Use GetTickCount()? Or use - // SystemTimeToFileTime() - GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) - _ftime64(&now); - GTEST_DISABLE_MSC_WARNINGS_POP_() - - return static_cast(now.time) * 1000 + now.millitm; -#elif GTEST_HAS_GETTIMEOFDAY_ - struct timeval now; - gettimeofday(&now, NULL); - return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; -#else -# error "Don't know how to get the current time on your system." -#endif -} - -// Utilities - -// class String. - -#if GTEST_OS_WINDOWS_MOBILE -// Creates a UTF-16 wide string from the given ANSI string, allocating -// memory using new. The caller is responsible for deleting the return -// value using delete[]. Returns the wide string, or NULL if the -// input is NULL. -LPCWSTR String::AnsiToUtf16(const char* ansi) { - if (!ansi) return NULL; - const int length = strlen(ansi); - const int unicode_length = - MultiByteToWideChar(CP_ACP, 0, ansi, length, - NULL, 0); - WCHAR* unicode = new WCHAR[unicode_length + 1]; - MultiByteToWideChar(CP_ACP, 0, ansi, length, - unicode, unicode_length); - unicode[unicode_length] = 0; - return unicode; -} - -// Creates an ANSI string from the given wide string, allocating -// memory using new. The caller is responsible for deleting the return -// value using delete[]. Returns the ANSI string, or NULL if the -// input is NULL. -const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { - if (!utf16_str) return NULL; - const int ansi_length = - WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, - NULL, 0, NULL, NULL); - char* ansi = new char[ansi_length + 1]; - WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, - ansi, ansi_length, NULL, NULL); - ansi[ansi_length] = 0; - return ansi; -} - -#endif // GTEST_OS_WINDOWS_MOBILE - -// Compares two C strings. Returns true iff they have the same content. -// -// Unlike strcmp(), this function can handle NULL argument(s). A NULL -// C string is considered different to any non-NULL C string, -// including the empty string. -bool String::CStringEquals(const char * lhs, const char * rhs) { - if ( lhs == NULL ) return rhs == NULL; - - if ( rhs == NULL ) return false; - - return strcmp(lhs, rhs) == 0; -} - -#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING - -// Converts an array of wide chars to a narrow string using the UTF-8 -// encoding, and streams the result to the given Message object. -static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, - Message* msg) { - for (size_t i = 0; i != length; ) { // NOLINT - if (wstr[i] != L'\0') { - *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); - while (i != length && wstr[i] != L'\0') - i++; - } else { - *msg << '\0'; - i++; - } - } -} - -#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING - -} // namespace internal - -// Constructs an empty Message. -// We allocate the stringstream separately because otherwise each use of -// ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's -// stack frame leading to huge stack frames in some cases; gcc does not reuse -// the stack space. -Message::Message() : ss_(new ::std::stringstream) { - // By default, we want there to be enough precision when printing - // a double to a Message. - *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); -} - -// These two overloads allow streaming a wide C string to a Message -// using the UTF-8 encoding. -Message& Message::operator <<(const wchar_t* wide_c_str) { - return *this << internal::String::ShowWideCString(wide_c_str); -} -Message& Message::operator <<(wchar_t* wide_c_str) { - return *this << internal::String::ShowWideCString(wide_c_str); -} - -#if GTEST_HAS_STD_WSTRING -// Converts the given wide string to a narrow string using the UTF-8 -// encoding, and streams the result to this Message object. -Message& Message::operator <<(const ::std::wstring& wstr) { - internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); - return *this; -} -#endif // GTEST_HAS_STD_WSTRING - -#if GTEST_HAS_GLOBAL_WSTRING -// Converts the given wide string to a narrow string using the UTF-8 -// encoding, and streams the result to this Message object. -Message& Message::operator <<(const ::wstring& wstr) { - internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); - return *this; -} -#endif // GTEST_HAS_GLOBAL_WSTRING - -// Gets the text streamed to this object so far as an std::string. -// Each '\0' character in the buffer is replaced with "\\0". -std::string Message::GetString() const { - return internal::StringStreamToString(ss_.get()); -} - -// AssertionResult constructors. -// Used in EXPECT_TRUE/FALSE(assertion_result). -AssertionResult::AssertionResult(const AssertionResult& other) - : success_(other.success_), - message_(other.message_.get() != NULL ? - new ::std::string(*other.message_) : - static_cast< ::std::string*>(NULL)) { -} - -// Swaps two AssertionResults. -void AssertionResult::swap(AssertionResult& other) { - using std::swap; - swap(success_, other.success_); - swap(message_, other.message_); -} - -// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. -AssertionResult AssertionResult::operator!() const { - AssertionResult negation(!success_); - if (message_.get() != NULL) - negation << *message_; - return negation; -} - -// Makes a successful assertion result. -AssertionResult AssertionSuccess() { - return AssertionResult(true); -} - -// Makes a failed assertion result. -AssertionResult AssertionFailure() { - return AssertionResult(false); -} - -// Makes a failed assertion result with the given failure message. -// Deprecated; use AssertionFailure() << message. -AssertionResult AssertionFailure(const Message& message) { - return AssertionFailure() << message; -} - -namespace internal { - -namespace edit_distance { -std::vector CalculateOptimalEdits(const std::vector& left, - const std::vector& right) { - std::vector > costs( - left.size() + 1, std::vector(right.size() + 1)); - std::vector > best_move( - left.size() + 1, std::vector(right.size() + 1)); - - // Populate for empty right. - for (size_t l_i = 0; l_i < costs.size(); ++l_i) { - costs[l_i][0] = static_cast(l_i); - best_move[l_i][0] = kRemove; - } - // Populate for empty left. - for (size_t r_i = 1; r_i < costs[0].size(); ++r_i) { - costs[0][r_i] = static_cast(r_i); - best_move[0][r_i] = kAdd; - } - - for (size_t l_i = 0; l_i < left.size(); ++l_i) { - for (size_t r_i = 0; r_i < right.size(); ++r_i) { - if (left[l_i] == right[r_i]) { - // Found a match. Consume it. - costs[l_i + 1][r_i + 1] = costs[l_i][r_i]; - best_move[l_i + 1][r_i + 1] = kMatch; - continue; - } - - const double add = costs[l_i + 1][r_i]; - const double remove = costs[l_i][r_i + 1]; - const double replace = costs[l_i][r_i]; - if (add < remove && add < replace) { - costs[l_i + 1][r_i + 1] = add + 1; - best_move[l_i + 1][r_i + 1] = kAdd; - } else if (remove < add && remove < replace) { - costs[l_i + 1][r_i + 1] = remove + 1; - best_move[l_i + 1][r_i + 1] = kRemove; - } else { - // We make replace a little more expensive than add/remove to lower - // their priority. - costs[l_i + 1][r_i + 1] = replace + 1.00001; - best_move[l_i + 1][r_i + 1] = kReplace; - } - } - } - - // Reconstruct the best path. We do it in reverse order. - std::vector best_path; - for (size_t l_i = left.size(), r_i = right.size(); l_i > 0 || r_i > 0;) { - EditType move = best_move[l_i][r_i]; - best_path.push_back(move); - l_i -= move != kAdd; - r_i -= move != kRemove; - } - std::reverse(best_path.begin(), best_path.end()); - return best_path; -} - -namespace { - -// Helper class to convert string into ids with deduplication. -class InternalStrings { - public: - size_t GetId(const std::string& str) { - IdMap::iterator it = ids_.find(str); - if (it != ids_.end()) return it->second; - size_t id = ids_.size(); - return ids_[str] = id; - } - - private: - typedef std::map IdMap; - IdMap ids_; -}; - -} // namespace - -std::vector CalculateOptimalEdits( - const std::vector& left, - const std::vector& right) { - std::vector left_ids, right_ids; - { - InternalStrings intern_table; - for (size_t i = 0; i < left.size(); ++i) { - left_ids.push_back(intern_table.GetId(left[i])); - } - for (size_t i = 0; i < right.size(); ++i) { - right_ids.push_back(intern_table.GetId(right[i])); - } - } - return CalculateOptimalEdits(left_ids, right_ids); -} - -namespace { - -// Helper class that holds the state for one hunk and prints it out to the -// stream. -// It reorders adds/removes when possible to group all removes before all -// adds. It also adds the hunk header before printint into the stream. -class Hunk { - public: - Hunk(size_t left_start, size_t right_start) - : left_start_(left_start), - right_start_(right_start), - adds_(), - removes_(), - common_() {} - - void PushLine(char edit, const char* line) { - switch (edit) { - case ' ': - ++common_; - FlushEdits(); - hunk_.push_back(std::make_pair(' ', line)); - break; - case '-': - ++removes_; - hunk_removes_.push_back(std::make_pair('-', line)); - break; - case '+': - ++adds_; - hunk_adds_.push_back(std::make_pair('+', line)); - break; - } - } - - void PrintTo(std::ostream* os) { - PrintHeader(os); - FlushEdits(); - for (std::list >::const_iterator it = - hunk_.begin(); - it != hunk_.end(); ++it) { - *os << it->first << it->second << "\n"; - } - } - - bool has_edits() const { return adds_ || removes_; } - - private: - void FlushEdits() { - hunk_.splice(hunk_.end(), hunk_removes_); - hunk_.splice(hunk_.end(), hunk_adds_); - } - - // Print a unified diff header for one hunk. - // The format is - // "@@ -, +, @@" - // where the left/right parts are ommitted if unnecessary. - void PrintHeader(std::ostream* ss) const { - *ss << "@@ "; - if (removes_) { - *ss << "-" << left_start_ << "," << (removes_ + common_); - } - if (removes_ && adds_) { - *ss << " "; - } - if (adds_) { - *ss << "+" << right_start_ << "," << (adds_ + common_); - } - *ss << " @@\n"; - } - - size_t left_start_, right_start_; - size_t adds_, removes_, common_; - std::list > hunk_, hunk_adds_, hunk_removes_; -}; - -} // namespace - -// Create a list of diff hunks in Unified diff format. -// Each hunk has a header generated by PrintHeader above plus a body with -// lines prefixed with ' ' for no change, '-' for deletion and '+' for -// addition. -// 'context' represents the desired unchanged prefix/suffix around the diff. -// If two hunks are close enough that their contexts overlap, then they are -// joined into one hunk. -std::string CreateUnifiedDiff(const std::vector& left, - const std::vector& right, - size_t context) { - const std::vector edits = CalculateOptimalEdits(left, right); - - size_t l_i = 0, r_i = 0, edit_i = 0; - std::stringstream ss; - while (edit_i < edits.size()) { - // Find first edit. - while (edit_i < edits.size() && edits[edit_i] == kMatch) { - ++l_i; - ++r_i; - ++edit_i; - } - - // Find the first line to include in the hunk. - const size_t prefix_context = std::min(l_i, context); - Hunk hunk(l_i - prefix_context + 1, r_i - prefix_context + 1); - for (size_t i = prefix_context; i > 0; --i) { - hunk.PushLine(' ', left[l_i - i].c_str()); - } - - // Iterate the edits until we found enough suffix for the hunk or the input - // is over. - size_t n_suffix = 0; - for (; edit_i < edits.size(); ++edit_i) { - if (n_suffix >= context) { - // Continue only if the next hunk is very close. - std::vector::const_iterator it = edits.begin() + edit_i; - while (it != edits.end() && *it == kMatch) ++it; - if (it == edits.end() || (it - edits.begin()) - edit_i >= context) { - // There is no next edit or it is too far away. - break; - } - } - - EditType edit = edits[edit_i]; - // Reset count when a non match is found. - n_suffix = edit == kMatch ? n_suffix + 1 : 0; - - if (edit == kMatch || edit == kRemove || edit == kReplace) { - hunk.PushLine(edit == kMatch ? ' ' : '-', left[l_i].c_str()); - } - if (edit == kAdd || edit == kReplace) { - hunk.PushLine('+', right[r_i].c_str()); - } - - // Advance indices, depending on edit type. - l_i += edit != kAdd; - r_i += edit != kRemove; - } - - if (!hunk.has_edits()) { - // We are done. We don't want this hunk. - break; - } - - hunk.PrintTo(&ss); - } - return ss.str(); -} - -} // namespace edit_distance - -namespace { - -// The string representation of the values received in EqFailure() are already -// escaped. Split them on escaped '\n' boundaries. Leave all other escaped -// characters the same. -std::vector SplitEscapedString(const std::string& str) { - std::vector lines; - size_t start = 0, end = str.size(); - if (end > 2 && str[0] == '"' && str[end - 1] == '"') { - ++start; - --end; - } - bool escaped = false; - for (size_t i = start; i + 1 < end; ++i) { - if (escaped) { - escaped = false; - if (str[i] == 'n') { - lines.push_back(str.substr(start, i - start - 1)); - start = i + 1; - } - } else { - escaped = str[i] == '\\'; - } - } - lines.push_back(str.substr(start, end - start)); - return lines; -} - -} // namespace - -// Constructs and returns the message for an equality assertion -// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. -// -// The first four parameters are the expressions used in the assertion -// and their values, as strings. For example, for ASSERT_EQ(foo, bar) -// where foo is 5 and bar is 6, we have: -// -// expected_expression: "foo" -// actual_expression: "bar" -// expected_value: "5" -// actual_value: "6" -// -// The ignoring_case parameter is true iff the assertion is a -// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will -// be inserted into the message. -AssertionResult EqFailure(const char* expected_expression, - const char* actual_expression, - const std::string& expected_value, - const std::string& actual_value, - bool ignoring_case) { - Message msg; - msg << "Value of: " << actual_expression; - if (actual_value != actual_expression) { - msg << "\n Actual: " << actual_value; - } - - msg << "\nExpected: " << expected_expression; - if (ignoring_case) { - msg << " (ignoring case)"; - } - if (expected_value != expected_expression) { - msg << "\nWhich is: " << expected_value; - } - - if (!expected_value.empty() && !actual_value.empty()) { - const std::vector expected_lines = - SplitEscapedString(expected_value); - const std::vector actual_lines = - SplitEscapedString(actual_value); - if (expected_lines.size() > 1 || actual_lines.size() > 1) { - msg << "\nWith diff:\n" - << edit_distance::CreateUnifiedDiff(expected_lines, actual_lines); - } - } - - return AssertionFailure() << msg; -} - -// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. -std::string GetBoolAssertionFailureMessage( - const AssertionResult& assertion_result, - const char* expression_text, - const char* actual_predicate_value, - const char* expected_predicate_value) { - const char* actual_message = assertion_result.message(); - Message msg; - msg << "Value of: " << expression_text - << "\n Actual: " << actual_predicate_value; - if (actual_message[0] != '\0') - msg << " (" << actual_message << ")"; - msg << "\nExpected: " << expected_predicate_value; - return msg.GetString(); -} - -// Helper function for implementing ASSERT_NEAR. -AssertionResult DoubleNearPredFormat(const char* expr1, - const char* expr2, - const char* abs_error_expr, - double val1, - double val2, - double abs_error) { - const double diff = fabs(val1 - val2); - if (diff <= abs_error) return AssertionSuccess(); - - // TODO(user): do not print the value of an expression if it's - // already a literal. - return AssertionFailure() - << "The difference between " << expr1 << " and " << expr2 - << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" - << expr1 << " evaluates to " << val1 << ",\n" - << expr2 << " evaluates to " << val2 << ", and\n" - << abs_error_expr << " evaluates to " << abs_error << "."; -} - - -// Helper template for implementing FloatLE() and DoubleLE(). -template -AssertionResult FloatingPointLE(const char* expr1, - const char* expr2, - RawType val1, - RawType val2) { - // Returns success if val1 is less than val2, - if (val1 < val2) { - return AssertionSuccess(); - } - - // or if val1 is almost equal to val2. - const FloatingPoint lhs(val1), rhs(val2); - if (lhs.AlmostEquals(rhs)) { - return AssertionSuccess(); - } - - // Note that the above two checks will both fail if either val1 or - // val2 is NaN, as the IEEE floating-point standard requires that - // any predicate involving a NaN must return false. - - ::std::stringstream val1_ss; - val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) - << val1; - - ::std::stringstream val2_ss; - val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) - << val2; - - return AssertionFailure() - << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" - << " Actual: " << StringStreamToString(&val1_ss) << " vs " - << StringStreamToString(&val2_ss); -} - -} // namespace internal - -// Asserts that val1 is less than, or almost equal to, val2. Fails -// otherwise. In particular, it fails if either val1 or val2 is NaN. -AssertionResult FloatLE(const char* expr1, const char* expr2, - float val1, float val2) { - return internal::FloatingPointLE(expr1, expr2, val1, val2); -} - -// Asserts that val1 is less than, or almost equal to, val2. Fails -// otherwise. In particular, it fails if either val1 or val2 is NaN. -AssertionResult DoubleLE(const char* expr1, const char* expr2, - double val1, double val2) { - return internal::FloatingPointLE(expr1, expr2, val1, val2); -} - -namespace internal { - -// The helper function for {ASSERT|EXPECT}_EQ with int or enum -// arguments. -AssertionResult CmpHelperEQ(const char* expected_expression, - const char* actual_expression, - BiggestInt expected, - BiggestInt actual) { - if (expected == actual) { - return AssertionSuccess(); - } - - return EqFailure(expected_expression, - actual_expression, - FormatForComparisonFailureMessage(expected, actual), - FormatForComparisonFailureMessage(actual, expected), - false); -} - -// A macro for implementing the helper functions needed to implement -// ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here -// just to avoid copy-and-paste of similar code. -#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ -AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ - BiggestInt val1, BiggestInt val2) {\ - if (val1 op val2) {\ - return AssertionSuccess();\ - } else {\ - return AssertionFailure() \ - << "Expected: (" << expr1 << ") " #op " (" << expr2\ - << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ - << " vs " << FormatForComparisonFailureMessage(val2, val1);\ - }\ -} - -// Implements the helper function for {ASSERT|EXPECT}_NE with int or -// enum arguments. -GTEST_IMPL_CMP_HELPER_(NE, !=) -// Implements the helper function for {ASSERT|EXPECT}_LE with int or -// enum arguments. -GTEST_IMPL_CMP_HELPER_(LE, <=) -// Implements the helper function for {ASSERT|EXPECT}_LT with int or -// enum arguments. -GTEST_IMPL_CMP_HELPER_(LT, < ) -// Implements the helper function for {ASSERT|EXPECT}_GE with int or -// enum arguments. -GTEST_IMPL_CMP_HELPER_(GE, >=) -// Implements the helper function for {ASSERT|EXPECT}_GT with int or -// enum arguments. -GTEST_IMPL_CMP_HELPER_(GT, > ) - -#undef GTEST_IMPL_CMP_HELPER_ - -// The helper function for {ASSERT|EXPECT}_STREQ. -AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual) { - if (String::CStringEquals(expected, actual)) { - return AssertionSuccess(); - } - - return EqFailure(expected_expression, - actual_expression, - PrintToString(expected), - PrintToString(actual), - false); -} - -// The helper function for {ASSERT|EXPECT}_STRCASEEQ. -AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual) { - if (String::CaseInsensitiveCStringEquals(expected, actual)) { - return AssertionSuccess(); - } - - return EqFailure(expected_expression, - actual_expression, - PrintToString(expected), - PrintToString(actual), - true); -} - -// The helper function for {ASSERT|EXPECT}_STRNE. -AssertionResult CmpHelperSTRNE(const char* s1_expression, - const char* s2_expression, - const char* s1, - const char* s2) { - if (!String::CStringEquals(s1, s2)) { - return AssertionSuccess(); - } else { - return AssertionFailure() << "Expected: (" << s1_expression << ") != (" - << s2_expression << "), actual: \"" - << s1 << "\" vs \"" << s2 << "\""; - } -} - -// The helper function for {ASSERT|EXPECT}_STRCASENE. -AssertionResult CmpHelperSTRCASENE(const char* s1_expression, - const char* s2_expression, - const char* s1, - const char* s2) { - if (!String::CaseInsensitiveCStringEquals(s1, s2)) { - return AssertionSuccess(); - } else { - return AssertionFailure() - << "Expected: (" << s1_expression << ") != (" - << s2_expression << ") (ignoring case), actual: \"" - << s1 << "\" vs \"" << s2 << "\""; - } -} - -} // namespace internal - -namespace { - -// Helper functions for implementing IsSubString() and IsNotSubstring(). - -// This group of overloaded functions return true iff needle is a -// substring of haystack. NULL is considered a substring of itself -// only. - -bool IsSubstringPred(const char* needle, const char* haystack) { - if (needle == NULL || haystack == NULL) - return needle == haystack; - - return strstr(haystack, needle) != NULL; -} - -bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { - if (needle == NULL || haystack == NULL) - return needle == haystack; - - return wcsstr(haystack, needle) != NULL; -} - -// StringType here can be either ::std::string or ::std::wstring. -template -bool IsSubstringPred(const StringType& needle, - const StringType& haystack) { - return haystack.find(needle) != StringType::npos; -} - -// This function implements either IsSubstring() or IsNotSubstring(), -// depending on the value of the expected_to_be_substring parameter. -// StringType here can be const char*, const wchar_t*, ::std::string, -// or ::std::wstring. -template -AssertionResult IsSubstringImpl( - bool expected_to_be_substring, - const char* needle_expr, const char* haystack_expr, - const StringType& needle, const StringType& haystack) { - if (IsSubstringPred(needle, haystack) == expected_to_be_substring) - return AssertionSuccess(); - - const bool is_wide_string = sizeof(needle[0]) > 1; - const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; - return AssertionFailure() - << "Value of: " << needle_expr << "\n" - << " Actual: " << begin_string_quote << needle << "\"\n" - << "Expected: " << (expected_to_be_substring ? "" : "not ") - << "a substring of " << haystack_expr << "\n" - << "Which is: " << begin_string_quote << haystack << "\""; -} - -} // namespace - -// IsSubstring() and IsNotSubstring() check whether needle is a -// substring of haystack (NULL is considered a substring of itself -// only), and return an appropriate error message when they fail. - -AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const char* needle, const char* haystack) { - return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const wchar_t* needle, const wchar_t* haystack) { - return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const char* needle, const char* haystack) { - return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const wchar_t* needle, const wchar_t* haystack) { - return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::string& needle, const ::std::string& haystack) { - return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::string& needle, const ::std::string& haystack) { - return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); -} - -#if GTEST_HAS_STD_WSTRING -AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::wstring& needle, const ::std::wstring& haystack) { - return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::wstring& needle, const ::std::wstring& haystack) { - return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); -} -#endif // GTEST_HAS_STD_WSTRING - -namespace internal { - -#if GTEST_OS_WINDOWS - -namespace { - -// Helper function for IsHRESULT{SuccessFailure} predicates -AssertionResult HRESULTFailureHelper(const char* expr, - const char* expected, - long hr) { // NOLINT -# if GTEST_OS_WINDOWS_MOBILE - - // Windows CE doesn't support FormatMessage. - const char error_text[] = ""; - -# else - - // Looks up the human-readable system message for the HRESULT code - // and since we're not passing any params to FormatMessage, we don't - // want inserts expanded. - const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS; - const DWORD kBufSize = 4096; - // Gets the system's human readable message string for this HRESULT. - char error_text[kBufSize] = { '\0' }; - DWORD message_length = ::FormatMessageA(kFlags, - 0, // no source, we're asking system - hr, // the error - 0, // no line width restrictions - error_text, // output buffer - kBufSize, // buf size - NULL); // no arguments for inserts - // Trims tailing white space (FormatMessage leaves a trailing CR-LF) - for (; message_length && IsSpace(error_text[message_length - 1]); - --message_length) { - error_text[message_length - 1] = '\0'; - } - -# endif // GTEST_OS_WINDOWS_MOBILE - - const std::string error_hex("0x" + String::FormatHexInt(hr)); - return ::testing::AssertionFailure() - << "Expected: " << expr << " " << expected << ".\n" - << " Actual: " << error_hex << " " << error_text << "\n"; -} - -} // namespace - -AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT - if (SUCCEEDED(hr)) { - return AssertionSuccess(); - } - return HRESULTFailureHelper(expr, "succeeds", hr); -} - -AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT - if (FAILED(hr)) { - return AssertionSuccess(); - } - return HRESULTFailureHelper(expr, "fails", hr); -} - -#endif // GTEST_OS_WINDOWS - -// Utility functions for encoding Unicode text (wide strings) in -// UTF-8. - -// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 -// like this: -// -// Code-point length Encoding -// 0 - 7 bits 0xxxxxxx -// 8 - 11 bits 110xxxxx 10xxxxxx -// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx -// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - -// The maximum code-point a one-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; - -// The maximum code-point a two-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; - -// The maximum code-point a three-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; - -// The maximum code-point a four-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; - -// Chops off the n lowest bits from a bit pattern. Returns the n -// lowest bits. As a side effect, the original bit pattern will be -// shifted to the right by n bits. -inline UInt32 ChopLowBits(UInt32* bits, int n) { - const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); - *bits >>= n; - return low_bits; -} - -// Converts a Unicode code point to a narrow string in UTF-8 encoding. -// code_point parameter is of type UInt32 because wchar_t may not be -// wide enough to contain a code point. -// If the code_point is not a valid Unicode code point -// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted -// to "(Invalid Unicode 0xXXXXXXXX)". -std::string CodePointToUtf8(UInt32 code_point) { - if (code_point > kMaxCodePoint4) { - return "(Invalid Unicode 0x" + String::FormatHexInt(code_point) + ")"; - } - - char str[5]; // Big enough for the largest valid code point. - if (code_point <= kMaxCodePoint1) { - str[1] = '\0'; - str[0] = static_cast(code_point); // 0xxxxxxx - } else if (code_point <= kMaxCodePoint2) { - str[2] = '\0'; - str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[0] = static_cast(0xC0 | code_point); // 110xxxxx - } else if (code_point <= kMaxCodePoint3) { - str[3] = '\0'; - str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[0] = static_cast(0xE0 | code_point); // 1110xxxx - } else { // code_point <= kMaxCodePoint4 - str[4] = '\0'; - str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[0] = static_cast(0xF0 | code_point); // 11110xxx - } - return str; -} - -// The following two functions only make sense if the the system -// uses UTF-16 for wide string encoding. All supported systems -// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. - -// Determines if the arguments constitute UTF-16 surrogate pair -// and thus should be combined into a single Unicode code point -// using CreateCodePointFromUtf16SurrogatePair. -inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { - return sizeof(wchar_t) == 2 && - (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; -} - -// Creates a Unicode code point from UTF16 surrogate pair. -inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, - wchar_t second) { - const UInt32 mask = (1 << 10) - 1; - return (sizeof(wchar_t) == 2) ? - (((first & mask) << 10) | (second & mask)) + 0x10000 : - // This function should not be called when the condition is - // false, but we provide a sensible default in case it is. - static_cast(first); -} - -// Converts a wide string to a narrow string in UTF-8 encoding. -// The wide string is assumed to have the following encoding: -// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) -// UTF-32 if sizeof(wchar_t) == 4 (on Linux) -// Parameter str points to a null-terminated wide string. -// Parameter num_chars may additionally limit the number -// of wchar_t characters processed. -1 is used when the entire string -// should be processed. -// If the string contains code points that are not valid Unicode code points -// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output -// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding -// and contains invalid UTF-16 surrogate pairs, values in those pairs -// will be encoded as individual Unicode characters from Basic Normal Plane. -std::string WideStringToUtf8(const wchar_t* str, int num_chars) { - if (num_chars == -1) - num_chars = static_cast(wcslen(str)); - - ::std::stringstream stream; - for (int i = 0; i < num_chars; ++i) { - UInt32 unicode_code_point; - - if (str[i] == L'\0') { - break; - } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { - unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], - str[i + 1]); - i++; - } else { - unicode_code_point = static_cast(str[i]); - } - - stream << CodePointToUtf8(unicode_code_point); - } - return StringStreamToString(&stream); -} - -// Converts a wide C string to an std::string using the UTF-8 encoding. -// NULL will be converted to "(null)". -std::string String::ShowWideCString(const wchar_t * wide_c_str) { - if (wide_c_str == NULL) return "(null)"; - - return internal::WideStringToUtf8(wide_c_str, -1); -} - -// Compares two wide C strings. Returns true iff they have the same -// content. -// -// Unlike wcscmp(), this function can handle NULL argument(s). A NULL -// C string is considered different to any non-NULL C string, -// including the empty string. -bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { - if (lhs == NULL) return rhs == NULL; - - if (rhs == NULL) return false; - - return wcscmp(lhs, rhs) == 0; -} - -// Helper function for *_STREQ on wide strings. -AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const wchar_t* expected, - const wchar_t* actual) { - if (String::WideCStringEquals(expected, actual)) { - return AssertionSuccess(); - } - - return EqFailure(expected_expression, - actual_expression, - PrintToString(expected), - PrintToString(actual), - false); -} - -// Helper function for *_STRNE on wide strings. -AssertionResult CmpHelperSTRNE(const char* s1_expression, - const char* s2_expression, - const wchar_t* s1, - const wchar_t* s2) { - if (!String::WideCStringEquals(s1, s2)) { - return AssertionSuccess(); - } - - return AssertionFailure() << "Expected: (" << s1_expression << ") != (" - << s2_expression << "), actual: " - << PrintToString(s1) - << " vs " << PrintToString(s2); -} - -// Compares two C strings, ignoring case. Returns true iff they have -// the same content. -// -// Unlike strcasecmp(), this function can handle NULL argument(s). A -// NULL C string is considered different to any non-NULL C string, -// including the empty string. -bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { - if (lhs == NULL) - return rhs == NULL; - if (rhs == NULL) - return false; - return posix::StrCaseCmp(lhs, rhs) == 0; -} - - // Compares two wide C strings, ignoring case. Returns true iff they - // have the same content. - // - // Unlike wcscasecmp(), this function can handle NULL argument(s). - // A NULL C string is considered different to any non-NULL wide C string, - // including the empty string. - // NB: The implementations on different platforms slightly differ. - // On windows, this method uses _wcsicmp which compares according to LC_CTYPE - // environment variable. On GNU platform this method uses wcscasecmp - // which compares according to LC_CTYPE category of the current locale. - // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the - // current locale. -bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, - const wchar_t* rhs) { - if (lhs == NULL) return rhs == NULL; - - if (rhs == NULL) return false; - -#if GTEST_OS_WINDOWS - return _wcsicmp(lhs, rhs) == 0; -#elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID - return wcscasecmp(lhs, rhs) == 0; -#else - // Android, Mac OS X and Cygwin don't define wcscasecmp. - // Other unknown OSes may not define it either. - wint_t left, right; - do { - left = towlower(*lhs++); - right = towlower(*rhs++); - } while (left && left == right); - return left == right; -#endif // OS selector -} - -// Returns true iff str ends with the given suffix, ignoring case. -// Any string is considered to end with an empty suffix. -bool String::EndsWithCaseInsensitive( - const std::string& str, const std::string& suffix) { - const size_t str_len = str.length(); - const size_t suffix_len = suffix.length(); - return (str_len >= suffix_len) && - CaseInsensitiveCStringEquals(str.c_str() + str_len - suffix_len, - suffix.c_str()); -} - -// Formats an int value as "%02d". -std::string String::FormatIntWidth2(int value) { - std::stringstream ss; - ss << std::setfill('0') << std::setw(2) << value; - return ss.str(); -} - -// Formats an int value as "%X". -std::string String::FormatHexInt(int value) { - std::stringstream ss; - ss << std::hex << std::uppercase << value; - return ss.str(); -} - -// Formats a byte as "%02X". -std::string String::FormatByte(unsigned char value) { - std::stringstream ss; - ss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase - << static_cast(value); - return ss.str(); -} - -// Converts the buffer in a stringstream to an std::string, converting NUL -// bytes to "\\0" along the way. -std::string StringStreamToString(::std::stringstream* ss) { - const ::std::string& str = ss->str(); - const char* const start = str.c_str(); - const char* const end = start + str.length(); - - std::string result; - result.reserve(2 * (end - start)); - for (const char* ch = start; ch != end; ++ch) { - if (*ch == '\0') { - result += "\\0"; // Replaces NUL with "\\0"; - } else { - result += *ch; - } - } - - return result; -} - -// Appends the user-supplied message to the Google-Test-generated message. -std::string AppendUserMessage(const std::string& gtest_msg, - const Message& user_msg) { - // Appends the user message if it's non-empty. - const std::string user_msg_string = user_msg.GetString(); - if (user_msg_string.empty()) { - return gtest_msg; - } - - return gtest_msg + "\n" + user_msg_string; -} - -} // namespace internal - -// class TestResult - -// Creates an empty TestResult. -TestResult::TestResult() - : death_test_count_(0), - elapsed_time_(0) { -} - -// D'tor. -TestResult::~TestResult() { -} - -// Returns the i-th test part result among all the results. i can -// range from 0 to total_part_count() - 1. If i is not in that range, -// aborts the program. -const TestPartResult& TestResult::GetTestPartResult(int i) const { - if (i < 0 || i >= total_part_count()) - internal::posix::Abort(); - return test_part_results_.at(i); -} - -// Returns the i-th test property. i can range from 0 to -// test_property_count() - 1. If i is not in that range, aborts the -// program. -const TestProperty& TestResult::GetTestProperty(int i) const { - if (i < 0 || i >= test_property_count()) - internal::posix::Abort(); - return test_properties_.at(i); -} - -// Clears the test part results. -void TestResult::ClearTestPartResults() { - test_part_results_.clear(); -} - -// Adds a test part result to the list. -void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { - test_part_results_.push_back(test_part_result); -} - -// Adds a test property to the list. If a property with the same key as the -// supplied property is already represented, the value of this test_property -// replaces the old value for that key. -void TestResult::RecordProperty(const std::string& xml_element, - const TestProperty& test_property) { - if (!ValidateTestProperty(xml_element, test_property)) { - return; - } - internal::MutexLock lock(&test_properites_mutex_); - const std::vector::iterator property_with_matching_key = - std::find_if(test_properties_.begin(), test_properties_.end(), - internal::TestPropertyKeyIs(test_property.key())); - if (property_with_matching_key == test_properties_.end()) { - test_properties_.push_back(test_property); - return; - } - property_with_matching_key->SetValue(test_property.value()); -} - -// The list of reserved attributes used in the element of XML -// output. -static const char* const kReservedTestSuitesAttributes[] = { - "disabled", - "errors", - "failures", - "name", - "random_seed", - "tests", - "time", - "timestamp" -}; - -// The list of reserved attributes used in the element of XML -// output. -static const char* const kReservedTestSuiteAttributes[] = { - "disabled", - "errors", - "failures", - "name", - "tests", - "time" -}; - -// The list of reserved attributes used in the element of XML output. -static const char* const kReservedTestCaseAttributes[] = { - "classname", - "name", - "status", - "time", - "type_param", - "value_param" -}; - -template -std::vector ArrayAsVector(const char* const (&array)[kSize]) { - return std::vector(array, array + kSize); -} - -static std::vector GetReservedAttributesForElement( - const std::string& xml_element) { - if (xml_element == "testsuites") { - return ArrayAsVector(kReservedTestSuitesAttributes); - } else if (xml_element == "testsuite") { - return ArrayAsVector(kReservedTestSuiteAttributes); - } else if (xml_element == "testcase") { - return ArrayAsVector(kReservedTestCaseAttributes); - } else { - GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element; - } - // This code is unreachable but some compilers may not realizes that. - return std::vector(); -} - -static std::string FormatWordList(const std::vector& words) { - Message word_list; - for (size_t i = 0; i < words.size(); ++i) { - if (i > 0 && words.size() > 2) { - word_list << ", "; - } - if (i == words.size() - 1) { - word_list << "and "; - } - word_list << "'" << words[i] << "'"; - } - return word_list.GetString(); -} - -bool ValidateTestPropertyName(const std::string& property_name, - const std::vector& reserved_names) { - if (std::find(reserved_names.begin(), reserved_names.end(), property_name) != - reserved_names.end()) { - ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name - << " (" << FormatWordList(reserved_names) - << " are reserved by " << GTEST_NAME_ << ")"; - return false; - } - return true; -} - -// Adds a failure if the key is a reserved attribute of the element named -// xml_element. Returns true if the property is valid. -bool TestResult::ValidateTestProperty(const std::string& xml_element, - const TestProperty& test_property) { - return ValidateTestPropertyName(test_property.key(), - GetReservedAttributesForElement(xml_element)); -} - -// Clears the object. -void TestResult::Clear() { - test_part_results_.clear(); - test_properties_.clear(); - death_test_count_ = 0; - elapsed_time_ = 0; -} - -// Returns true iff the test failed. -bool TestResult::Failed() const { - for (int i = 0; i < total_part_count(); ++i) { - if (GetTestPartResult(i).failed()) - return true; - } - return false; -} - -// Returns true iff the test part fatally failed. -static bool TestPartFatallyFailed(const TestPartResult& result) { - return result.fatally_failed(); -} - -// Returns true iff the test fatally failed. -bool TestResult::HasFatalFailure() const { - return CountIf(test_part_results_, TestPartFatallyFailed) > 0; -} - -// Returns true iff the test part non-fatally failed. -static bool TestPartNonfatallyFailed(const TestPartResult& result) { - return result.nonfatally_failed(); -} - -// Returns true iff the test has a non-fatal failure. -bool TestResult::HasNonfatalFailure() const { - return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; -} - -// Gets the number of all test parts. This is the sum of the number -// of successful test parts and the number of failed test parts. -int TestResult::total_part_count() const { - return static_cast(test_part_results_.size()); -} - -// Returns the number of the test properties. -int TestResult::test_property_count() const { - return static_cast(test_properties_.size()); -} - -// class Test - -// Creates a Test object. - -// The c'tor saves the values of all Google Test flags. -Test::Test() - : gtest_flag_saver_(new internal::GTestFlagSaver) { -} - -// The d'tor restores the values of all Google Test flags. -Test::~Test() { - delete gtest_flag_saver_; -} - -// Sets up the test fixture. -// -// A sub-class may override this. -void Test::SetUp() { -} - -// Tears down the test fixture. -// -// A sub-class may override this. -void Test::TearDown() { -} - -// Allows user supplied key value pairs to be recorded for later output. -void Test::RecordProperty(const std::string& key, const std::string& value) { - UnitTest::GetInstance()->RecordProperty(key, value); -} - -// Allows user supplied key value pairs to be recorded for later output. -void Test::RecordProperty(const std::string& key, int value) { - Message value_message; - value_message << value; - RecordProperty(key, value_message.GetString().c_str()); -} - -namespace internal { - -void ReportFailureInUnknownLocation(TestPartResult::Type result_type, - const std::string& message) { - // This function is a friend of UnitTest and as such has access to - // AddTestPartResult. - UnitTest::GetInstance()->AddTestPartResult( - result_type, - NULL, // No info about the source file where the exception occurred. - -1, // We have no info on which line caused the exception. - message, - ""); // No stack trace, either. -} - -} // namespace internal - -// Google Test requires all tests in the same test case to use the same test -// fixture class. This function checks if the current test has the -// same fixture class as the first test in the current test case. If -// yes, it returns true; otherwise it generates a Google Test failure and -// returns false. -bool Test::HasSameFixtureClass() { - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - const TestCase* const test_case = impl->current_test_case(); - - // Info about the first test in the current test case. - const TestInfo* const first_test_info = test_case->test_info_list()[0]; - const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; - const char* const first_test_name = first_test_info->name(); - - // Info about the current test. - const TestInfo* const this_test_info = impl->current_test_info(); - const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_; - const char* const this_test_name = this_test_info->name(); - - if (this_fixture_id != first_fixture_id) { - // Is the first test defined using TEST? - const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); - // Is this test defined using TEST? - const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); - - if (first_is_TEST || this_is_TEST) { - // Both TEST and TEST_F appear in same test case, which is incorrect. - // Tell the user how to fix this. - - // Gets the name of the TEST and the name of the TEST_F. Note - // that first_is_TEST and this_is_TEST cannot both be true, as - // the fixture IDs are different for the two tests. - const char* const TEST_name = - first_is_TEST ? first_test_name : this_test_name; - const char* const TEST_F_name = - first_is_TEST ? this_test_name : first_test_name; - - ADD_FAILURE() - << "All tests in the same test case must use the same test fixture\n" - << "class, so mixing TEST_F and TEST in the same test case is\n" - << "illegal. In test case " << this_test_info->test_case_name() - << ",\n" - << "test " << TEST_F_name << " is defined using TEST_F but\n" - << "test " << TEST_name << " is defined using TEST. You probably\n" - << "want to change the TEST to TEST_F or move it to another test\n" - << "case."; - } else { - // Two fixture classes with the same name appear in two different - // namespaces, which is not allowed. Tell the user how to fix this. - ADD_FAILURE() - << "All tests in the same test case must use the same test fixture\n" - << "class. However, in test case " - << this_test_info->test_case_name() << ",\n" - << "you defined test " << first_test_name - << " and test " << this_test_name << "\n" - << "using two different test fixture classes. This can happen if\n" - << "the two classes are from different namespaces or translation\n" - << "units and have the same name. You should probably rename one\n" - << "of the classes to put the tests into different test cases."; - } - return false; - } - - return true; -} - -#if GTEST_HAS_SEH - -// Adds an "exception thrown" fatal failure to the current test. This -// function returns its result via an output parameter pointer because VC++ -// prohibits creation of objects with destructors on stack in functions -// using __try (see error C2712). -static std::string* FormatSehExceptionMessage(DWORD exception_code, - const char* location) { - Message message; - message << "SEH exception with code 0x" << std::setbase(16) << - exception_code << std::setbase(10) << " thrown in " << location << "."; - - return new std::string(message.GetString()); -} - -#endif // GTEST_HAS_SEH - -namespace internal { - -#if GTEST_HAS_EXCEPTIONS - -// Adds an "exception thrown" fatal failure to the current test. -static std::string FormatCxxExceptionMessage(const char* description, - const char* location) { - Message message; - if (description != NULL) { - message << "C++ exception with description \"" << description << "\""; - } else { - message << "Unknown C++ exception"; - } - message << " thrown in " << location << "."; - - return message.GetString(); -} - -static std::string PrintTestPartResultToString( - const TestPartResult& test_part_result); - -GoogleTestFailureException::GoogleTestFailureException( - const TestPartResult& failure) - : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} - -#endif // GTEST_HAS_EXCEPTIONS - -// We put these helper functions in the internal namespace as IBM's xlC -// compiler rejects the code if they were declared static. - -// Runs the given method and handles SEH exceptions it throws, when -// SEH is supported; returns the 0-value for type Result in case of an -// SEH exception. (Microsoft compilers cannot handle SEH and C++ -// exceptions in the same function. Therefore, we provide a separate -// wrapper function for handling SEH exceptions.) -template -Result HandleSehExceptionsInMethodIfSupported( - T* object, Result (T::*method)(), const char* location) { -#if GTEST_HAS_SEH - __try { - return (object->*method)(); - } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT - GetExceptionCode())) { - // We create the exception message on the heap because VC++ prohibits - // creation of objects with destructors on stack in functions using __try - // (see error C2712). - std::string* exception_message = FormatSehExceptionMessage( - GetExceptionCode(), location); - internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, - *exception_message); - delete exception_message; - return static_cast(0); - } -#else - (void)location; - return (object->*method)(); -#endif // GTEST_HAS_SEH -} - -// Runs the given method and catches and reports C++ and/or SEH-style -// exceptions, if they are supported; returns the 0-value for type -// Result in case of an SEH exception. -template -Result HandleExceptionsInMethodIfSupported( - T* object, Result (T::*method)(), const char* location) { - // NOTE: The user code can affect the way in which Google Test handles - // exceptions by setting GTEST_FLAG(catch_exceptions), but only before - // RUN_ALL_TESTS() starts. It is technically possible to check the flag - // after the exception is caught and either report or re-throw the - // exception based on the flag's value: - // - // try { - // // Perform the test method. - // } catch (...) { - // if (GTEST_FLAG(catch_exceptions)) - // // Report the exception as failure. - // else - // throw; // Re-throws the original exception. - // } - // - // However, the purpose of this flag is to allow the program to drop into - // the debugger when the exception is thrown. On most platforms, once the - // control enters the catch block, the exception origin information is - // lost and the debugger will stop the program at the point of the - // re-throw in this function -- instead of at the point of the original - // throw statement in the code under test. For this reason, we perform - // the check early, sacrificing the ability to affect Google Test's - // exception handling in the method where the exception is thrown. - if (internal::GetUnitTestImpl()->catch_exceptions()) { -#if GTEST_HAS_EXCEPTIONS - try { - return HandleSehExceptionsInMethodIfSupported(object, method, location); - } catch (const internal::GoogleTestFailureException&) { // NOLINT - // This exception type can only be thrown by a failed Google - // Test assertion with the intention of letting another testing - // framework catch it. Therefore we just re-throw it. - throw; - } catch (const std::exception& e) { // NOLINT - internal::ReportFailureInUnknownLocation( - TestPartResult::kFatalFailure, - FormatCxxExceptionMessage(e.what(), location)); - } catch (...) { // NOLINT - internal::ReportFailureInUnknownLocation( - TestPartResult::kFatalFailure, - FormatCxxExceptionMessage(NULL, location)); - } - return static_cast(0); -#else - return HandleSehExceptionsInMethodIfSupported(object, method, location); -#endif // GTEST_HAS_EXCEPTIONS - } else { - return (object->*method)(); - } -} - -} // namespace internal - -// Runs the test and updates the test result. -void Test::Run() { - if (!HasSameFixtureClass()) return; - - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); - // We will run the test only if SetUp() was successful. - if (!HasFatalFailure()) { - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - this, &Test::TestBody, "the test body"); - } - - // However, we want to clean up as much as possible. Hence we will - // always call TearDown(), even if SetUp() or the test body has - // failed. - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - this, &Test::TearDown, "TearDown()"); -} - -// Returns true iff the current test has a fatal failure. -bool Test::HasFatalFailure() { - return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); -} - -// Returns true iff the current test has a non-fatal failure. -bool Test::HasNonfatalFailure() { - return internal::GetUnitTestImpl()->current_test_result()-> - HasNonfatalFailure(); -} - -// class TestInfo - -// Constructs a TestInfo object. It assumes ownership of the test factory -// object. -TestInfo::TestInfo(const std::string& a_test_case_name, - const std::string& a_name, - const char* a_type_param, - const char* a_value_param, - internal::TypeId fixture_class_id, - internal::TestFactoryBase* factory) - : test_case_name_(a_test_case_name), - name_(a_name), - type_param_(a_type_param ? new std::string(a_type_param) : NULL), - value_param_(a_value_param ? new std::string(a_value_param) : NULL), - fixture_class_id_(fixture_class_id), - should_run_(false), - is_disabled_(false), - matches_filter_(false), - factory_(factory), - result_() {} - -// Destructs a TestInfo object. -TestInfo::~TestInfo() { delete factory_; } - -namespace internal { - -// Creates a new TestInfo object and registers it with Google Test; -// returns the created object. -// -// Arguments: -// -// test_case_name: name of the test case -// name: name of the test -// type_param: the name of the test's type parameter, or NULL if -// this is not a typed or a type-parameterized test. -// value_param: text representation of the test's value parameter, -// or NULL if this is not a value-parameterized test. -// fixture_class_id: ID of the test fixture class -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -// factory: pointer to the factory that creates a test object. -// The newly created TestInfo instance will assume -// ownership of the factory object. -TestInfo* MakeAndRegisterTestInfo( - const char* test_case_name, - const char* name, - const char* type_param, - const char* value_param, - TypeId fixture_class_id, - SetUpTestCaseFunc set_up_tc, - TearDownTestCaseFunc tear_down_tc, - TestFactoryBase* factory) { - TestInfo* const test_info = - new TestInfo(test_case_name, name, type_param, value_param, - fixture_class_id, factory); - GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); - return test_info; -} - -#if GTEST_HAS_PARAM_TEST -void ReportInvalidTestCaseType(const char* test_case_name, - const char* file, int line) { - Message errors; - errors - << "Attempted redefinition of test case " << test_case_name << ".\n" - << "All tests in the same test case must use the same test fixture\n" - << "class. However, in test case " << test_case_name << ", you tried\n" - << "to define a test using a fixture class different from the one\n" - << "used earlier. This can happen if the two fixture classes are\n" - << "from different namespaces and have the same name. You should\n" - << "probably rename one of the classes to put the tests into different\n" - << "test cases."; - - fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), - errors.GetString().c_str()); -} -#endif // GTEST_HAS_PARAM_TEST - -} // namespace internal - -namespace { - -// A predicate that checks the test name of a TestInfo against a known -// value. -// -// This is used for implementation of the TestCase class only. We put -// it in the anonymous namespace to prevent polluting the outer -// namespace. -// -// TestNameIs is copyable. -class TestNameIs { - public: - // Constructor. - // - // TestNameIs has NO default constructor. - explicit TestNameIs(const char* name) - : name_(name) {} - - // Returns true iff the test name of test_info matches name_. - bool operator()(const TestInfo * test_info) const { - return test_info && test_info->name() == name_; - } - - private: - std::string name_; -}; - -} // namespace - -namespace internal { - -// This method expands all parameterized tests registered with macros TEST_P -// and INSTANTIATE_TEST_CASE_P into regular tests and registers those. -// This will be done just once during the program runtime. -void UnitTestImpl::RegisterParameterizedTests() { -#if GTEST_HAS_PARAM_TEST - if (!parameterized_tests_registered_) { - parameterized_test_registry_.RegisterTests(); - parameterized_tests_registered_ = true; - } -#endif -} - -} // namespace internal - -// Creates the test object, runs it, records its result, and then -// deletes it. -void TestInfo::Run() { - if (!should_run_) return; - - // Tells UnitTest where to store test result. - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - impl->set_current_test_info(this); - - TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); - - // Notifies the unit test event listeners that a test is about to start. - repeater->OnTestStart(*this); - - const TimeInMillis start = internal::GetTimeInMillis(); - - impl->os_stack_trace_getter()->UponLeavingGTest(); - - // Creates the test object. - Test* const test = internal::HandleExceptionsInMethodIfSupported( - factory_, &internal::TestFactoryBase::CreateTest, - "the test fixture's constructor"); - - // Runs the test only if the test object was created and its - // constructor didn't generate a fatal failure. - if ((test != NULL) && !Test::HasFatalFailure()) { - // This doesn't throw as all user code that can throw are wrapped into - // exception handling code. - test->Run(); - } - - // Deletes the test object. - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - test, &Test::DeleteSelf_, "the test fixture's destructor"); - - result_.set_elapsed_time(internal::GetTimeInMillis() - start); - - // Notifies the unit test event listener that a test has just finished. - repeater->OnTestEnd(*this); - - // Tells UnitTest to stop associating assertion results to this - // test. - impl->set_current_test_info(NULL); -} - -// class TestCase - -// Gets the number of successful tests in this test case. -int TestCase::successful_test_count() const { - return CountIf(test_info_list_, TestPassed); -} - -// Gets the number of failed tests in this test case. -int TestCase::failed_test_count() const { - return CountIf(test_info_list_, TestFailed); -} - -// Gets the number of disabled tests that will be reported in the XML report. -int TestCase::reportable_disabled_test_count() const { - return CountIf(test_info_list_, TestReportableDisabled); -} - -// Gets the number of disabled tests in this test case. -int TestCase::disabled_test_count() const { - return CountIf(test_info_list_, TestDisabled); -} - -// Gets the number of tests to be printed in the XML report. -int TestCase::reportable_test_count() const { - return CountIf(test_info_list_, TestReportable); -} - -// Get the number of tests in this test case that should run. -int TestCase::test_to_run_count() const { - return CountIf(test_info_list_, ShouldRunTest); -} - -// Gets the number of all tests. -int TestCase::total_test_count() const { - return static_cast(test_info_list_.size()); -} - -// Creates a TestCase with the given name. -// -// Arguments: -// -// name: name of the test case -// a_type_param: the name of the test case's type parameter, or NULL if -// this is not a typed or a type-parameterized test case. -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -TestCase::TestCase(const char* a_name, const char* a_type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc) - : name_(a_name), - type_param_(a_type_param ? new std::string(a_type_param) : NULL), - set_up_tc_(set_up_tc), - tear_down_tc_(tear_down_tc), - should_run_(false), - elapsed_time_(0) { -} - -// Destructor of TestCase. -TestCase::~TestCase() { - // Deletes every Test in the collection. - ForEach(test_info_list_, internal::Delete); -} - -// Returns the i-th test among all the tests. i can range from 0 to -// total_test_count() - 1. If i is not in that range, returns NULL. -const TestInfo* TestCase::GetTestInfo(int i) const { - const int index = GetElementOr(test_indices_, i, -1); - return index < 0 ? NULL : test_info_list_[index]; -} - -// Returns the i-th test among all the tests. i can range from 0 to -// total_test_count() - 1. If i is not in that range, returns NULL. -TestInfo* TestCase::GetMutableTestInfo(int i) { - const int index = GetElementOr(test_indices_, i, -1); - return index < 0 ? NULL : test_info_list_[index]; -} - -// Adds a test to this test case. Will delete the test upon -// destruction of the TestCase object. -void TestCase::AddTestInfo(TestInfo * test_info) { - test_info_list_.push_back(test_info); - test_indices_.push_back(static_cast(test_indices_.size())); -} - -// Runs every test in this TestCase. -void TestCase::Run() { - if (!should_run_) return; - - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - impl->set_current_test_case(this); - - TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); - - repeater->OnTestCaseStart(*this); - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - this, &TestCase::RunSetUpTestCase, "SetUpTestCase()"); - - const internal::TimeInMillis start = internal::GetTimeInMillis(); - for (int i = 0; i < total_test_count(); i++) { - GetMutableTestInfo(i)->Run(); - } - elapsed_time_ = internal::GetTimeInMillis() - start; - - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - this, &TestCase::RunTearDownTestCase, "TearDownTestCase()"); - - repeater->OnTestCaseEnd(*this); - impl->set_current_test_case(NULL); -} - -// Clears the results of all tests in this test case. -void TestCase::ClearResult() { - ad_hoc_test_result_.Clear(); - ForEach(test_info_list_, TestInfo::ClearTestResult); -} - -// Shuffles the tests in this test case. -void TestCase::ShuffleTests(internal::Random* random) { - Shuffle(random, &test_indices_); -} - -// Restores the test order to before the first shuffle. -void TestCase::UnshuffleTests() { - for (size_t i = 0; i < test_indices_.size(); i++) { - test_indices_[i] = static_cast(i); - } -} - -// Formats a countable noun. Depending on its quantity, either the -// singular form or the plural form is used. e.g. -// -// FormatCountableNoun(1, "formula", "formuli") returns "1 formula". -// FormatCountableNoun(5, "book", "books") returns "5 books". -static std::string FormatCountableNoun(int count, - const char * singular_form, - const char * plural_form) { - return internal::StreamableToString(count) + " " + - (count == 1 ? singular_form : plural_form); -} - -// Formats the count of tests. -static std::string FormatTestCount(int test_count) { - return FormatCountableNoun(test_count, "test", "tests"); -} - -// Formats the count of test cases. -static std::string FormatTestCaseCount(int test_case_count) { - return FormatCountableNoun(test_case_count, "test case", "test cases"); -} - -// Converts a TestPartResult::Type enum to human-friendly string -// representation. Both kNonFatalFailure and kFatalFailure are translated -// to "Failure", as the user usually doesn't care about the difference -// between the two when viewing the test result. -static const char * TestPartResultTypeToString(TestPartResult::Type type) { - switch (type) { - case TestPartResult::kSuccess: - return "Success"; - - case TestPartResult::kNonFatalFailure: - case TestPartResult::kFatalFailure: -#ifdef _MSC_VER - return "error: "; -#else - return "Failure\n"; -#endif - default: - return "Unknown result type"; - } -} - -namespace internal { - -// Prints a TestPartResult to an std::string. -static std::string PrintTestPartResultToString( - const TestPartResult& test_part_result) { - return (Message() - << internal::FormatFileLocation(test_part_result.file_name(), - test_part_result.line_number()) - << " " << TestPartResultTypeToString(test_part_result.type()) - << test_part_result.message()).GetString(); -} - -// Prints a TestPartResult. -static void PrintTestPartResult(const TestPartResult& test_part_result) { - const std::string& result = - PrintTestPartResultToString(test_part_result); - printf("%s\n", result.c_str()); - fflush(stdout); - // If the test program runs in Visual Studio or a debugger, the - // following statements add the test part result message to the Output - // window such that the user can double-click on it to jump to the - // corresponding source code location; otherwise they do nothing. -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE - // We don't call OutputDebugString*() on Windows Mobile, as printing - // to stdout is done by OutputDebugString() there already - we don't - // want the same message printed twice. - ::OutputDebugStringA(result.c_str()); - ::OutputDebugStringA("\n"); -#endif -} - -// class PrettyUnitTestResultPrinter - -enum GTestColor { - COLOR_DEFAULT, - COLOR_RED, - COLOR_GREEN, - COLOR_YELLOW -}; - -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ - !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT - -// Returns the character attribute for the given color. -WORD GetColorAttribute(GTestColor color) { - switch (color) { - case COLOR_RED: return FOREGROUND_RED; - case COLOR_GREEN: return FOREGROUND_GREEN; - case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; - default: return 0; - } -} - -#else - -// Returns the ANSI color code for the given color. COLOR_DEFAULT is -// an invalid input. -const char* GetAnsiColorCode(GTestColor color) { - switch (color) { - case COLOR_RED: return "1"; - case COLOR_GREEN: return "2"; - case COLOR_YELLOW: return "3"; - default: return NULL; - }; -} - -#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE - -// Returns true iff Google Test should use colors in the output. -bool ShouldUseColor(bool stdout_is_tty) { - const char* const gtest_color = GTEST_FLAG(color).c_str(); - - if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { -#if GTEST_OS_WINDOWS - // On Windows the TERM variable is usually not set, but the - // console there does support colors. - return stdout_is_tty; -#else - // On non-Windows platforms, we rely on the TERM variable. - const char* const term = posix::GetEnv("TERM"); - const bool term_supports_color = - String::CStringEquals(term, "xterm") || - String::CStringEquals(term, "xterm-color") || - String::CStringEquals(term, "xterm-256color") || - String::CStringEquals(term, "screen") || - String::CStringEquals(term, "screen-256color") || - String::CStringEquals(term, "linux") || - String::CStringEquals(term, "cygwin"); - return stdout_is_tty && term_supports_color; -#endif // GTEST_OS_WINDOWS - } - - return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || - String::CaseInsensitiveCStringEquals(gtest_color, "true") || - String::CaseInsensitiveCStringEquals(gtest_color, "t") || - String::CStringEquals(gtest_color, "1"); - // We take "yes", "true", "t", and "1" as meaning "yes". If the - // value is neither one of these nor "auto", we treat it as "no" to - // be conservative. -} - -// Helpers for printing colored strings to stdout. Note that on Windows, we -// cannot simply emit special characters and have the terminal change colors. -// This routine must actually emit the characters rather than return a string -// that would be colored when printed, as can be done on Linux. -void ColoredPrintf(GTestColor color, const char* fmt, ...) { - va_list args; - va_start(args, fmt); - -#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || \ - GTEST_OS_IOS || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT - const bool use_color = AlwaysFalse(); -#else - static const bool in_color_mode = - ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); - const bool use_color = in_color_mode && (color != COLOR_DEFAULT); -#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS - // The '!= 0' comparison is necessary to satisfy MSVC 7.1. - - if (!use_color) { - vprintf(fmt, args); - va_end(args); - return; - } - -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ - !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT - const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); - - // Gets the current text color. - CONSOLE_SCREEN_BUFFER_INFO buffer_info; - GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); - const WORD old_color_attrs = buffer_info.wAttributes; - - // We need to flush the stream buffers into the console before each - // SetConsoleTextAttribute call lest it affect the text that is already - // printed but has not yet reached the console. - fflush(stdout); - SetConsoleTextAttribute(stdout_handle, - GetColorAttribute(color) | FOREGROUND_INTENSITY); - vprintf(fmt, args); - - fflush(stdout); - // Restores the text color. - SetConsoleTextAttribute(stdout_handle, old_color_attrs); -#else - printf("\033[0;3%sm", GetAnsiColorCode(color)); - vprintf(fmt, args); - printf("\033[m"); // Resets the terminal to default. -#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE - va_end(args); -} - -// Text printed in Google Test's text output and --gunit_list_tests -// output to label the type parameter and value parameter for a test. -static const char kTypeParamLabel[] = "TypeParam"; -static const char kValueParamLabel[] = "GetParam()"; - -void PrintFullTestCommentIfPresent(const TestInfo& test_info) { - const char* const type_param = test_info.type_param(); - const char* const value_param = test_info.value_param(); - - if (type_param != NULL || value_param != NULL) { - printf(", where "); - if (type_param != NULL) { - printf("%s = %s", kTypeParamLabel, type_param); - if (value_param != NULL) - printf(" and "); - } - if (value_param != NULL) { - printf("%s = %s", kValueParamLabel, value_param); - } - } -} - -// This class implements the TestEventListener interface. -// -// Class PrettyUnitTestResultPrinter is copyable. -class PrettyUnitTestResultPrinter : public TestEventListener { - public: - PrettyUnitTestResultPrinter() {} - static void PrintTestName(const char * test_case, const char * test) { - printf("%s.%s", test_case, test); - } - - // The following methods override what's in the TestEventListener class. - virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); - virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestCaseStart(const TestCase& test_case); - virtual void OnTestStart(const TestInfo& test_info); - virtual void OnTestPartResult(const TestPartResult& result); - virtual void OnTestEnd(const TestInfo& test_info); - virtual void OnTestCaseEnd(const TestCase& test_case); - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); - virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} - - private: - static void PrintFailedTests(const UnitTest& unit_test); -}; - - // Fired before each iteration of tests starts. -void PrettyUnitTestResultPrinter::OnTestIterationStart( - const UnitTest& unit_test, int iteration) { - if (GTEST_FLAG(repeat) != 1) - printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); - - const char* const filter = GTEST_FLAG(filter).c_str(); - - // Prints the filter if it's not *. This reminds the user that some - // tests may be skipped. - if (!String::CStringEquals(filter, kUniversalFilter)) { - ColoredPrintf(COLOR_YELLOW, - "Note: %s filter = %s\n", GTEST_NAME_, filter); - } - - if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { - const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); - ColoredPrintf(COLOR_YELLOW, - "Note: This is test shard %d of %s.\n", - static_cast(shard_index) + 1, - internal::posix::GetEnv(kTestTotalShards)); - } - - if (GTEST_FLAG(shuffle)) { - ColoredPrintf(COLOR_YELLOW, - "Note: Randomizing tests' orders with a seed of %d .\n", - unit_test.random_seed()); - } - - ColoredPrintf(COLOR_GREEN, "[==========] "); - printf("Running %s from %s.\n", - FormatTestCount(unit_test.test_to_run_count()).c_str(), - FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( - const UnitTest& /*unit_test*/) { - ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("Global test environment set-up.\n"); - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { - const std::string counts = - FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); - ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("%s from %s", counts.c_str(), test_case.name()); - if (test_case.type_param() == NULL) { - printf("\n"); - } else { - printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param()); - } - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { - ColoredPrintf(COLOR_GREEN, "[ RUN ] "); - PrintTestName(test_info.test_case_name(), test_info.name()); - printf("\n"); - fflush(stdout); -} - -// Called after an assertion failure. -void PrettyUnitTestResultPrinter::OnTestPartResult( - const TestPartResult& result) { - // If the test part succeeded, we don't need to do anything. - if (result.type() == TestPartResult::kSuccess) - return; - - // Print failure message from the assertion (e.g. expected this and got that). - PrintTestPartResult(result); - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { - if (test_info.result()->Passed()) { - ColoredPrintf(COLOR_GREEN, "[ OK ] "); - } else { - ColoredPrintf(COLOR_RED, "[ FAILED ] "); - } - PrintTestName(test_info.test_case_name(), test_info.name()); - if (test_info.result()->Failed()) - PrintFullTestCommentIfPresent(test_info); - - if (GTEST_FLAG(print_time)) { - printf(" (%s ms)\n", internal::StreamableToString( - test_info.result()->elapsed_time()).c_str()); - } else { - printf("\n"); - } - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { - if (!GTEST_FLAG(print_time)) return; - - const std::string counts = - FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); - ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("%s from %s (%s ms total)\n\n", - counts.c_str(), test_case.name(), - internal::StreamableToString(test_case.elapsed_time()).c_str()); - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( - const UnitTest& /*unit_test*/) { - ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("Global test environment tear-down\n"); - fflush(stdout); -} - -// Internal helper for printing the list of failed tests. -void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { - const int failed_test_count = unit_test.failed_test_count(); - if (failed_test_count == 0) { - return; - } - - for (int i = 0; i < unit_test.total_test_case_count(); ++i) { - const TestCase& test_case = *unit_test.GetTestCase(i); - if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { - continue; - } - for (int j = 0; j < test_case.total_test_count(); ++j) { - const TestInfo& test_info = *test_case.GetTestInfo(j); - if (!test_info.should_run() || test_info.result()->Passed()) { - continue; - } - ColoredPrintf(COLOR_RED, "[ FAILED ] "); - printf("%s.%s", test_case.name(), test_info.name()); - PrintFullTestCommentIfPresent(test_info); - printf("\n"); - } - } -} - -void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, - int /*iteration*/) { - ColoredPrintf(COLOR_GREEN, "[==========] "); - printf("%s from %s ran.", - FormatTestCount(unit_test.test_to_run_count()).c_str(), - FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); - if (GTEST_FLAG(print_time)) { - printf(" (%s ms total)", - internal::StreamableToString(unit_test.elapsed_time()).c_str()); - } - printf("\n"); - ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); - printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); - - int num_failures = unit_test.failed_test_count(); - if (!unit_test.Passed()) { - const int failed_test_count = unit_test.failed_test_count(); - ColoredPrintf(COLOR_RED, "[ FAILED ] "); - printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); - PrintFailedTests(unit_test); - printf("\n%2d FAILED %s\n", num_failures, - num_failures == 1 ? "TEST" : "TESTS"); - } - - int num_disabled = unit_test.reportable_disabled_test_count(); - if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { - if (!num_failures) { - printf("\n"); // Add a spacer if no FAILURE banner is displayed. - } - ColoredPrintf(COLOR_YELLOW, - " YOU HAVE %d DISABLED %s\n\n", - num_disabled, - num_disabled == 1 ? "TEST" : "TESTS"); - } - // Ensure that Google Test output is printed before, e.g., heapchecker output. - fflush(stdout); -} - -// End PrettyUnitTestResultPrinter - -// class TestEventRepeater -// -// This class forwards events to other event listeners. -class TestEventRepeater : public TestEventListener { - public: - TestEventRepeater() : forwarding_enabled_(true) {} - virtual ~TestEventRepeater(); - void Append(TestEventListener *listener); - TestEventListener* Release(TestEventListener* listener); - - // Controls whether events will be forwarded to listeners_. Set to false - // in death test child processes. - bool forwarding_enabled() const { return forwarding_enabled_; } - void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } - - virtual void OnTestProgramStart(const UnitTest& unit_test); - virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); - virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); - virtual void OnTestCaseStart(const TestCase& test_case); - virtual void OnTestStart(const TestInfo& test_info); - virtual void OnTestPartResult(const TestPartResult& result); - virtual void OnTestEnd(const TestInfo& test_info); - virtual void OnTestCaseEnd(const TestCase& test_case); - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); - virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - virtual void OnTestProgramEnd(const UnitTest& unit_test); - - private: - // Controls whether events will be forwarded to listeners_. Set to false - // in death test child processes. - bool forwarding_enabled_; - // The list of listeners that receive events. - std::vector listeners_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); -}; - -TestEventRepeater::~TestEventRepeater() { - ForEach(listeners_, Delete); -} - -void TestEventRepeater::Append(TestEventListener *listener) { - listeners_.push_back(listener); -} - -// TODO(vladl@google.com): Factor the search functionality into Vector::Find. -TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { - for (size_t i = 0; i < listeners_.size(); ++i) { - if (listeners_[i] == listener) { - listeners_.erase(listeners_.begin() + i); - return listener; - } - } - - return NULL; -} - -// Since most methods are very similar, use macros to reduce boilerplate. -// This defines a member that forwards the call to all listeners. -#define GTEST_REPEATER_METHOD_(Name, Type) \ -void TestEventRepeater::Name(const Type& parameter) { \ - if (forwarding_enabled_) { \ - for (size_t i = 0; i < listeners_.size(); i++) { \ - listeners_[i]->Name(parameter); \ - } \ - } \ -} -// This defines a member that forwards the call to all listeners in reverse -// order. -#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ -void TestEventRepeater::Name(const Type& parameter) { \ - if (forwarding_enabled_) { \ - for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ - listeners_[i]->Name(parameter); \ - } \ - } \ -} - -GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) -GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) -GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) -GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) -GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) -GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) -GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) -GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) -GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) -GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) -GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) - -#undef GTEST_REPEATER_METHOD_ -#undef GTEST_REVERSE_REPEATER_METHOD_ - -void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, - int iteration) { - if (forwarding_enabled_) { - for (size_t i = 0; i < listeners_.size(); i++) { - listeners_[i]->OnTestIterationStart(unit_test, iteration); - } - } -} - -void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, - int iteration) { - if (forwarding_enabled_) { - for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { - listeners_[i]->OnTestIterationEnd(unit_test, iteration); - } - } -} - -// End TestEventRepeater - -// This class generates an XML output file. -class XmlUnitTestResultPrinter : public EmptyTestEventListener { - public: - explicit XmlUnitTestResultPrinter(const char* output_file); - - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - - private: - // Is c a whitespace character that is normalized to a space character - // when it appears in an XML attribute value? - static bool IsNormalizableWhitespace(char c) { - return c == 0x9 || c == 0xA || c == 0xD; - } - - // May c appear in a well-formed XML document? - static bool IsValidXmlCharacter(char c) { - return IsNormalizableWhitespace(c) || c >= 0x20; - } - - // Returns an XML-escaped copy of the input string str. If - // is_attribute is true, the text is meant to appear as an attribute - // value, and normalizable whitespace is preserved by replacing it - // with character references. - static std::string EscapeXml(const std::string& str, bool is_attribute); - - // Returns the given string with all characters invalid in XML removed. - static std::string RemoveInvalidXmlCharacters(const std::string& str); - - // Convenience wrapper around EscapeXml when str is an attribute value. - static std::string EscapeXmlAttribute(const std::string& str) { - return EscapeXml(str, true); - } - - // Convenience wrapper around EscapeXml when str is not an attribute value. - static std::string EscapeXmlText(const char* str) { - return EscapeXml(str, false); - } - - // Verifies that the given attribute belongs to the given element and - // streams the attribute as XML. - static void OutputXmlAttribute(std::ostream* stream, - const std::string& element_name, - const std::string& name, - const std::string& value); - - // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. - static void OutputXmlCDataSection(::std::ostream* stream, const char* data); - - // Streams an XML representation of a TestInfo object. - static void OutputXmlTestInfo(::std::ostream* stream, - const char* test_case_name, - const TestInfo& test_info); - - // Prints an XML representation of a TestCase object - static void PrintXmlTestCase(::std::ostream* stream, - const TestCase& test_case); - - // Prints an XML summary of unit_test to output stream out. - static void PrintXmlUnitTest(::std::ostream* stream, - const UnitTest& unit_test); - - // Produces a string representing the test properties in a result as space - // delimited XML attributes based on the property key="value" pairs. - // When the std::string is not empty, it includes a space at the beginning, - // to delimit this attribute from prior attributes. - static std::string TestPropertiesAsXmlAttributes(const TestResult& result); - - // The output file. - const std::string output_file_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); -}; - -// Creates a new XmlUnitTestResultPrinter. -XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) - : output_file_(output_file) { - if (output_file_.c_str() == NULL || output_file_.empty()) { - fprintf(stderr, "XML output file may not be null\n"); - fflush(stderr); - exit(EXIT_FAILURE); - } -} - -// Called after the unit test ends. -void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, - int /*iteration*/) { - FILE* xmlout = NULL; - FilePath output_file(output_file_); - FilePath output_dir(output_file.RemoveFileName()); - - if (output_dir.CreateDirectoriesRecursively()) { - xmlout = posix::FOpen(output_file_.c_str(), "w"); - } - if (xmlout == NULL) { - // TODO(user): report the reason of the failure. - // - // We don't do it for now as: - // - // 1. There is no urgent need for it. - // 2. It's a bit involved to make the errno variable thread-safe on - // all three operating systems (Linux, Windows, and Mac OS). - // 3. To interpret the meaning of errno in a thread-safe way, - // we need the strerror_r() function, which is not available on - // Windows. - fprintf(stderr, - "Unable to open file \"%s\"\n", - output_file_.c_str()); - fflush(stderr); - exit(EXIT_FAILURE); - } - std::stringstream stream; - PrintXmlUnitTest(&stream, unit_test); - fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); - fclose(xmlout); -} - -// Returns an XML-escaped copy of the input string str. If is_attribute -// is true, the text is meant to appear as an attribute value, and -// normalizable whitespace is preserved by replacing it with character -// references. -// -// Invalid XML characters in str, if any, are stripped from the output. -// It is expected that most, if not all, of the text processed by this -// module will consist of ordinary English text. -// If this module is ever modified to produce version 1.1 XML output, -// most invalid characters can be retained using character references. -// TODO(user): It might be nice to have a minimally invasive, human-readable -// escaping scheme for invalid characters, rather than dropping them. -std::string XmlUnitTestResultPrinter::EscapeXml( - const std::string& str, bool is_attribute) { - Message m; - - for (size_t i = 0; i < str.size(); ++i) { - const char ch = str[i]; - switch (ch) { - case '<': - m << "<"; - break; - case '>': - m << ">"; - break; - case '&': - m << "&"; - break; - case '\'': - if (is_attribute) - m << "'"; - else - m << '\''; - break; - case '"': - if (is_attribute) - m << """; - else - m << '"'; - break; - default: - if (IsValidXmlCharacter(ch)) { - if (is_attribute && IsNormalizableWhitespace(ch)) - m << "&#x" << String::FormatByte(static_cast(ch)) - << ";"; - else - m << ch; - } - break; - } - } - - return m.GetString(); -} - -// Returns the given string with all characters invalid in XML removed. -// Currently invalid characters are dropped from the string. An -// alternative is to replace them with certain characters such as . or ?. -std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( - const std::string& str) { - std::string output; - output.reserve(str.size()); - for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) - if (IsValidXmlCharacter(*it)) - output.push_back(*it); - - return output; -} - -// The following routines generate an XML representation of a UnitTest -// object. -// -// This is how Google Test concepts map to the DTD: -// -// <-- corresponds to a UnitTest object -// <-- corresponds to a TestCase object -// <-- corresponds to a TestInfo object -// ... -// ... -// ... -// <-- individual assertion failures -// -// -// - -// Formats the given time in milliseconds as seconds. -std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { - ::std::stringstream ss; - ss << ms/1000.0; - return ss.str(); -} - -static bool PortableLocaltime(time_t seconds, struct tm* out) { -#if defined(_MSC_VER) - return localtime_s(out, &seconds) == 0; -#elif defined(__MINGW32__) || defined(__MINGW64__) - // MINGW provides neither localtime_r nor localtime_s, but uses - // Windows' localtime(), which has a thread-local tm buffer. - struct tm* tm_ptr = localtime(&seconds); // NOLINT - if (tm_ptr == NULL) - return false; - *out = *tm_ptr; - return true; -#else - return localtime_r(&seconds, out) != NULL; -#endif -} - -// Converts the given epoch time in milliseconds to a date string in the ISO -// 8601 format, without the timezone information. -std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { - struct tm time_struct; - if (!PortableLocaltime(static_cast(ms / 1000), &time_struct)) - return ""; - // YYYY-MM-DDThh:mm:ss - return StreamableToString(time_struct.tm_year + 1900) + "-" + - String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + - String::FormatIntWidth2(time_struct.tm_mday) + "T" + - String::FormatIntWidth2(time_struct.tm_hour) + ":" + - String::FormatIntWidth2(time_struct.tm_min) + ":" + - String::FormatIntWidth2(time_struct.tm_sec); -} - -// Streams an XML CDATA section, escaping invalid CDATA sequences as needed. -void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, - const char* data) { - const char* segment = data; - *stream << ""); - if (next_segment != NULL) { - stream->write( - segment, static_cast(next_segment - segment)); - *stream << "]]>]]>"); - } else { - *stream << segment; - break; - } - } - *stream << "]]>"; -} - -void XmlUnitTestResultPrinter::OutputXmlAttribute( - std::ostream* stream, - const std::string& element_name, - const std::string& name, - const std::string& value) { - const std::vector& allowed_names = - GetReservedAttributesForElement(element_name); - - GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != - allowed_names.end()) - << "Attribute " << name << " is not allowed for element <" << element_name - << ">."; - - *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\""; -} - -// Prints an XML representation of a TestInfo object. -// TODO(user): There is also value in printing properties with the plain printer. -void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, - const char* test_case_name, - const TestInfo& test_info) { - const TestResult& result = *test_info.result(); - const std::string kTestcase = "testcase"; - - *stream << " \n"; - } - const string location = internal::FormatCompilerIndependentFileLocation( - part.file_name(), part.line_number()); - const string summary = location + "\n" + part.summary(); - *stream << " "; - const string detail = location + "\n" + part.message(); - OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); - *stream << "\n"; - } - } - - if (failures == 0) - *stream << " />\n"; - else - *stream << " \n"; -} - -// Prints an XML representation of a TestCase object -void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream, - const TestCase& test_case) { - const std::string kTestsuite = "testsuite"; - *stream << " <" << kTestsuite; - OutputXmlAttribute(stream, kTestsuite, "name", test_case.name()); - OutputXmlAttribute(stream, kTestsuite, "tests", - StreamableToString(test_case.reportable_test_count())); - OutputXmlAttribute(stream, kTestsuite, "failures", - StreamableToString(test_case.failed_test_count())); - OutputXmlAttribute( - stream, kTestsuite, "disabled", - StreamableToString(test_case.reportable_disabled_test_count())); - OutputXmlAttribute(stream, kTestsuite, "errors", "0"); - OutputXmlAttribute(stream, kTestsuite, "time", - FormatTimeInMillisAsSeconds(test_case.elapsed_time())); - *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()) - << ">\n"; - - for (int i = 0; i < test_case.total_test_count(); ++i) { - if (test_case.GetTestInfo(i)->is_reportable()) - OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); - } - *stream << " \n"; -} - -// Prints an XML summary of unit_test to output stream out. -void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, - const UnitTest& unit_test) { - const std::string kTestsuites = "testsuites"; - - *stream << "\n"; - *stream << "<" << kTestsuites; - - OutputXmlAttribute(stream, kTestsuites, "tests", - StreamableToString(unit_test.reportable_test_count())); - OutputXmlAttribute(stream, kTestsuites, "failures", - StreamableToString(unit_test.failed_test_count())); - OutputXmlAttribute( - stream, kTestsuites, "disabled", - StreamableToString(unit_test.reportable_disabled_test_count())); - OutputXmlAttribute(stream, kTestsuites, "errors", "0"); - OutputXmlAttribute( - stream, kTestsuites, "timestamp", - FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp())); - OutputXmlAttribute(stream, kTestsuites, "time", - FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); - - if (GTEST_FLAG(shuffle)) { - OutputXmlAttribute(stream, kTestsuites, "random_seed", - StreamableToString(unit_test.random_seed())); - } - - *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result()); - - OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); - *stream << ">\n"; - - for (int i = 0; i < unit_test.total_test_case_count(); ++i) { - if (unit_test.GetTestCase(i)->reportable_test_count() > 0) - PrintXmlTestCase(stream, *unit_test.GetTestCase(i)); - } - *stream << "\n"; -} - -// Produces a string representing the test properties in a result as space -// delimited XML attributes based on the property key="value" pairs. -std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( - const TestResult& result) { - Message attributes; - for (int i = 0; i < result.test_property_count(); ++i) { - const TestProperty& property = result.GetTestProperty(i); - attributes << " " << property.key() << "=" - << "\"" << EscapeXmlAttribute(property.value()) << "\""; - } - return attributes.GetString(); -} - -// End XmlUnitTestResultPrinter - -#if GTEST_CAN_STREAM_RESULTS_ - -// Checks if str contains '=', '&', '%' or '\n' characters. If yes, -// replaces them by "%xx" where xx is their hexadecimal value. For -// example, replaces "=" with "%3D". This algorithm is O(strlen(str)) -// in both time and space -- important as the input str may contain an -// arbitrarily long test failure message and stack trace. -string StreamingListener::UrlEncode(const char* str) { - string result; - result.reserve(strlen(str) + 1); - for (char ch = *str; ch != '\0'; ch = *++str) { - switch (ch) { - case '%': - case '=': - case '&': - case '\n': - result.append("%" + String::FormatByte(static_cast(ch))); - break; - default: - result.push_back(ch); - break; - } - } - return result; -} - -void StreamingListener::SocketWriter::MakeConnection() { - GTEST_CHECK_(sockfd_ == -1) - << "MakeConnection() can't be called when there is already a connection."; - - addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. - hints.ai_socktype = SOCK_STREAM; - addrinfo* servinfo = NULL; - - // Use the getaddrinfo() to get a linked list of IP addresses for - // the given host name. - const int error_num = getaddrinfo( - host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); - if (error_num != 0) { - GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " - << gai_strerror(error_num); - } - - // Loop through all the results and connect to the first we can. - for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; - cur_addr = cur_addr->ai_next) { - sockfd_ = socket( - cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); - if (sockfd_ != -1) { - // Connect the client socket to the server socket. - if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { - close(sockfd_); - sockfd_ = -1; - } - } - } - - freeaddrinfo(servinfo); // all done with this structure - - if (sockfd_ == -1) { - GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to " - << host_name_ << ":" << port_num_; - } -} - -// End of class Streaming Listener -#endif // GTEST_CAN_STREAM_RESULTS__ - -// Class ScopedTrace - -// Pushes the given source file location and message onto a per-thread -// trace stack maintained by Google Test. -ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) - GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { - TraceInfo trace; - trace.file = file; - trace.line = line; - trace.message = message.GetString(); - - UnitTest::GetInstance()->PushGTestTrace(trace); -} - -// Pops the info pushed by the c'tor. -ScopedTrace::~ScopedTrace() - GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { - UnitTest::GetInstance()->PopGTestTrace(); -} - - -// class OsStackTraceGetter - -// Returns the current OS stack trace as an std::string. Parameters: -// -// max_depth - the maximum number of stack frames to be included -// in the trace. -// skip_count - the number of top frames to be skipped; doesn't count -// against max_depth. -// -string OsStackTraceGetter::CurrentStackTrace(int /* max_depth */, - int /* skip_count */) - GTEST_LOCK_EXCLUDED_(mutex_) { - return ""; -} - -void OsStackTraceGetter::UponLeavingGTest() - GTEST_LOCK_EXCLUDED_(mutex_) { -} - -const char* const -OsStackTraceGetter::kElidedFramesMarker = - "... " GTEST_NAME_ " internal frames ..."; - -// A helper class that creates the premature-exit file in its -// constructor and deletes the file in its destructor. -class ScopedPrematureExitFile { - public: - explicit ScopedPrematureExitFile(const char* premature_exit_filepath) - : premature_exit_filepath_(premature_exit_filepath) { - // If a path to the premature-exit file is specified... - if (premature_exit_filepath != NULL && *premature_exit_filepath != '\0') { - // create the file with a single "0" character in it. I/O - // errors are ignored as there's nothing better we can do and we - // don't want to fail the test because of this. - FILE* pfile = posix::FOpen(premature_exit_filepath, "w"); - fwrite("0", 1, 1, pfile); - fclose(pfile); - } - } - - ~ScopedPrematureExitFile() { - if (premature_exit_filepath_ != NULL && *premature_exit_filepath_ != '\0') { - remove(premature_exit_filepath_); - } - } - - private: - const char* const premature_exit_filepath_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile); -}; - -} // namespace internal - -// class TestEventListeners - -TestEventListeners::TestEventListeners() - : repeater_(new internal::TestEventRepeater()), - default_result_printer_(NULL), - default_xml_generator_(NULL) { -} - -TestEventListeners::~TestEventListeners() { delete repeater_; } - -// Returns the standard listener responsible for the default console -// output. Can be removed from the listeners list to shut down default -// console output. Note that removing this object from the listener list -// with Release transfers its ownership to the user. -void TestEventListeners::Append(TestEventListener* listener) { - repeater_->Append(listener); -} - -// Removes the given event listener from the list and returns it. It then -// becomes the caller's responsibility to delete the listener. Returns -// NULL if the listener is not found in the list. -TestEventListener* TestEventListeners::Release(TestEventListener* listener) { - if (listener == default_result_printer_) - default_result_printer_ = NULL; - else if (listener == default_xml_generator_) - default_xml_generator_ = NULL; - return repeater_->Release(listener); -} - -// Returns repeater that broadcasts the TestEventListener events to all -// subscribers. -TestEventListener* TestEventListeners::repeater() { return repeater_; } - -// Sets the default_result_printer attribute to the provided listener. -// The listener is also added to the listener list and previous -// default_result_printer is removed from it and deleted. The listener can -// also be NULL in which case it will not be added to the list. Does -// nothing if the previous and the current listener objects are the same. -void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { - if (default_result_printer_ != listener) { - // It is an error to pass this method a listener that is already in the - // list. - delete Release(default_result_printer_); - default_result_printer_ = listener; - if (listener != NULL) - Append(listener); - } -} - -// Sets the default_xml_generator attribute to the provided listener. The -// listener is also added to the listener list and previous -// default_xml_generator is removed from it and deleted. The listener can -// also be NULL in which case it will not be added to the list. Does -// nothing if the previous and the current listener objects are the same. -void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { - if (default_xml_generator_ != listener) { - // It is an error to pass this method a listener that is already in the - // list. - delete Release(default_xml_generator_); - default_xml_generator_ = listener; - if (listener != NULL) - Append(listener); - } -} - -// Controls whether events will be forwarded by the repeater to the -// listeners in the list. -bool TestEventListeners::EventForwardingEnabled() const { - return repeater_->forwarding_enabled(); -} - -void TestEventListeners::SuppressEventForwarding() { - repeater_->set_forwarding_enabled(false); -} - -// class UnitTest - -// Gets the singleton UnitTest object. The first time this method is -// called, a UnitTest object is constructed and returned. Consecutive -// calls will return the same object. -// -// We don't protect this under mutex_ as a user is not supposed to -// call this before main() starts, from which point on the return -// value will never change. -UnitTest* UnitTest::GetInstance() { - // When compiled with MSVC 7.1 in optimized mode, destroying the - // UnitTest object upon exiting the program messes up the exit code, - // causing successful tests to appear failed. We have to use a - // different implementation in this case to bypass the compiler bug. - // This implementation makes the compiler happy, at the cost of - // leaking the UnitTest object. - - // CodeGear C++Builder insists on a public destructor for the - // default implementation. Use this implementation to keep good OO - // design with private destructor. - -#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) - static UnitTest* const instance = new UnitTest; - return instance; -#else - static UnitTest instance; - return &instance; -#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) -} - -// Gets the number of successful test cases. -int UnitTest::successful_test_case_count() const { - return impl()->successful_test_case_count(); -} - -// Gets the number of failed test cases. -int UnitTest::failed_test_case_count() const { - return impl()->failed_test_case_count(); -} - -// Gets the number of all test cases. -int UnitTest::total_test_case_count() const { - return impl()->total_test_case_count(); -} - -// Gets the number of all test cases that contain at least one test -// that should run. -int UnitTest::test_case_to_run_count() const { - return impl()->test_case_to_run_count(); -} - -// Gets the number of successful tests. -int UnitTest::successful_test_count() const { - return impl()->successful_test_count(); -} - -// Gets the number of failed tests. -int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } - -// Gets the number of disabled tests that will be reported in the XML report. -int UnitTest::reportable_disabled_test_count() const { - return impl()->reportable_disabled_test_count(); -} - -// Gets the number of disabled tests. -int UnitTest::disabled_test_count() const { - return impl()->disabled_test_count(); -} - -// Gets the number of tests to be printed in the XML report. -int UnitTest::reportable_test_count() const { - return impl()->reportable_test_count(); -} - -// Gets the number of all tests. -int UnitTest::total_test_count() const { return impl()->total_test_count(); } - -// Gets the number of tests that should run. -int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } - -// Gets the time of the test program start, in ms from the start of the -// UNIX epoch. -internal::TimeInMillis UnitTest::start_timestamp() const { - return impl()->start_timestamp(); -} - -// Gets the elapsed time, in milliseconds. -internal::TimeInMillis UnitTest::elapsed_time() const { - return impl()->elapsed_time(); -} - -// Returns true iff the unit test passed (i.e. all test cases passed). -bool UnitTest::Passed() const { return impl()->Passed(); } - -// Returns true iff the unit test failed (i.e. some test case failed -// or something outside of all tests failed). -bool UnitTest::Failed() const { return impl()->Failed(); } - -// Gets the i-th test case among all the test cases. i can range from 0 to -// total_test_case_count() - 1. If i is not in that range, returns NULL. -const TestCase* UnitTest::GetTestCase(int i) const { - return impl()->GetTestCase(i); -} - -// Returns the TestResult containing information on test failures and -// properties logged outside of individual test cases. -const TestResult& UnitTest::ad_hoc_test_result() const { - return *impl()->ad_hoc_test_result(); -} - -// Gets the i-th test case among all the test cases. i can range from 0 to -// total_test_case_count() - 1. If i is not in that range, returns NULL. -TestCase* UnitTest::GetMutableTestCase(int i) { - return impl()->GetMutableTestCase(i); -} - -// Returns the list of event listeners that can be used to track events -// inside Google Test. -TestEventListeners& UnitTest::listeners() { - return *impl()->listeners(); -} - -// Registers and returns a global test environment. When a test -// program is run, all global test environments will be set-up in the -// order they were registered. After all tests in the program have -// finished, all global test environments will be torn-down in the -// *reverse* order they were registered. -// -// The UnitTest object takes ownership of the given environment. -// -// We don't protect this under mutex_, as we only support calling it -// from the main thread. -Environment* UnitTest::AddEnvironment(Environment* env) { - if (env == NULL) { - return NULL; - } - - impl_->environments().push_back(env); - return env; -} - -// Adds a TestPartResult to the current TestResult object. All Google Test -// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call -// this to report their results. The user code should use the -// assertion macros instead of calling this directly. -void UnitTest::AddTestPartResult( - TestPartResult::Type result_type, - const char* file_name, - int line_number, - const std::string& message, - const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_) { - Message msg; - msg << message; - - internal::MutexLock lock(&mutex_); - if (impl_->gtest_trace_stack().size() > 0) { - msg << "\n" << GTEST_NAME_ << " trace:"; - - for (int i = static_cast(impl_->gtest_trace_stack().size()); - i > 0; --i) { - const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; - msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) - << " " << trace.message; - } - } - - if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { - msg << internal::kStackTraceMarker << os_stack_trace; - } - - const TestPartResult result = - TestPartResult(result_type, file_name, line_number, - msg.GetString().c_str()); - impl_->GetTestPartResultReporterForCurrentThread()-> - ReportTestPartResult(result); - - if (result_type != TestPartResult::kSuccess) { - // gtest_break_on_failure takes precedence over - // gtest_throw_on_failure. This allows a user to set the latter - // in the code (perhaps in order to use Google Test assertions - // with another testing framework) and specify the former on the - // command line for debugging. - if (GTEST_FLAG(break_on_failure)) { -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT - // Using DebugBreak on Windows allows gtest to still break into a debugger - // when a failure happens and both the --gtest_break_on_failure and - // the --gtest_catch_exceptions flags are specified. - DebugBreak(); -#else - // Dereference NULL through a volatile pointer to prevent the compiler - // from removing. We use this rather than abort() or __builtin_trap() for - // portability: Symbian doesn't implement abort() well, and some debuggers - // don't correctly trap abort(). - *static_cast(NULL) = 1; -#endif // GTEST_OS_WINDOWS - } else if (GTEST_FLAG(throw_on_failure)) { -#if GTEST_HAS_EXCEPTIONS - throw internal::GoogleTestFailureException(result); -#else - // We cannot call abort() as it generates a pop-up in debug mode - // that cannot be suppressed in VC 7.1 or below. - exit(1); -#endif - } - } -} - -// Adds a TestProperty to the current TestResult object when invoked from -// inside a test, to current TestCase's ad_hoc_test_result_ when invoked -// from SetUpTestCase or TearDownTestCase, or to the global property set -// when invoked elsewhere. If the result already contains a property with -// the same key, the value will be updated. -void UnitTest::RecordProperty(const std::string& key, - const std::string& value) { - impl_->RecordProperty(TestProperty(key, value)); -} - -// Runs all tests in this UnitTest object and prints the result. -// Returns 0 if successful, or 1 otherwise. -// -// We don't protect this under mutex_, as we only support calling it -// from the main thread. -int UnitTest::Run() { - const bool in_death_test_child_process = - internal::GTEST_FLAG(internal_run_death_test).length() > 0; - - // Google Test implements this protocol for catching that a test - // program exits before returning control to Google Test: - // - // 1. Upon start, Google Test creates a file whose absolute path - // is specified by the environment variable - // TEST_PREMATURE_EXIT_FILE. - // 2. When Google Test has finished its work, it deletes the file. - // - // This allows a test runner to set TEST_PREMATURE_EXIT_FILE before - // running a Google-Test-based test program and check the existence - // of the file at the end of the test execution to see if it has - // exited prematurely. - - // If we are in the child process of a death test, don't - // create/delete the premature exit file, as doing so is unnecessary - // and will confuse the parent process. Otherwise, create/delete - // the file upon entering/leaving this function. If the program - // somehow exits before this function has a chance to return, the - // premature-exit file will be left undeleted, causing a test runner - // that understands the premature-exit-file protocol to report the - // test as having failed. - const internal::ScopedPrematureExitFile premature_exit_file( - in_death_test_child_process ? - NULL : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE")); - - // Captures the value of GTEST_FLAG(catch_exceptions). This value will be - // used for the duration of the program. - impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); - -#if GTEST_HAS_SEH - // Either the user wants Google Test to catch exceptions thrown by the - // tests or this is executing in the context of death test child - // process. In either case the user does not want to see pop-up dialogs - // about crashes - they are expected. - if (impl()->catch_exceptions() || in_death_test_child_process) { -# if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT - // SetErrorMode doesn't exist on CE. - SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | - SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); -# endif // !GTEST_OS_WINDOWS_MOBILE - -# if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE - // Death test children can be terminated with _abort(). On Windows, - // _abort() can show a dialog with a warning message. This forces the - // abort message to go to stderr instead. - _set_error_mode(_OUT_TO_STDERR); -# endif - -# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE - // In the debug version, Visual Studio pops up a separate dialog - // offering a choice to debug the aborted program. We need to suppress - // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement - // executed. Google Test will notify the user of any unexpected - // failure via stderr. - // - // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. - // Users of prior VC versions shall suffer the agony and pain of - // clicking through the countless debug dialogs. - // TODO(vladl@google.com): find a way to suppress the abort dialog() in the - // debug mode when compiled with VC 7.1 or lower. - if (!GTEST_FLAG(break_on_failure)) - _set_abort_behavior( - 0x0, // Clear the following flags: - _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. -# endif - } -#endif // GTEST_HAS_SEH - - return internal::HandleExceptionsInMethodIfSupported( - impl(), - &internal::UnitTestImpl::RunAllTests, - "auxiliary test code (environments or event listeners)") ? 0 : 1; -} - -// Returns the working directory when the first TEST() or TEST_F() was -// executed. -const char* UnitTest::original_working_dir() const { - return impl_->original_working_dir_.c_str(); -} - -// Returns the TestCase object for the test that's currently running, -// or NULL if no test is running. -const TestCase* UnitTest::current_test_case() const - GTEST_LOCK_EXCLUDED_(mutex_) { - internal::MutexLock lock(&mutex_); - return impl_->current_test_case(); -} - -// Returns the TestInfo object for the test that's currently running, -// or NULL if no test is running. -const TestInfo* UnitTest::current_test_info() const - GTEST_LOCK_EXCLUDED_(mutex_) { - internal::MutexLock lock(&mutex_); - return impl_->current_test_info(); -} - -// Returns the random seed used at the start of the current test run. -int UnitTest::random_seed() const { return impl_->random_seed(); } - -#if GTEST_HAS_PARAM_TEST -// Returns ParameterizedTestCaseRegistry object used to keep track of -// value-parameterized tests and instantiate and register them. -internal::ParameterizedTestCaseRegistry& - UnitTest::parameterized_test_registry() - GTEST_LOCK_EXCLUDED_(mutex_) { - return impl_->parameterized_test_registry(); -} -#endif // GTEST_HAS_PARAM_TEST - -// Creates an empty UnitTest. -UnitTest::UnitTest() { - impl_ = new internal::UnitTestImpl(this); -} - -// Destructor of UnitTest. -UnitTest::~UnitTest() { - delete impl_; -} - -// Pushes a trace defined by SCOPED_TRACE() on to the per-thread -// Google Test trace stack. -void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) - GTEST_LOCK_EXCLUDED_(mutex_) { - internal::MutexLock lock(&mutex_); - impl_->gtest_trace_stack().push_back(trace); -} - -// Pops a trace from the per-thread Google Test trace stack. -void UnitTest::PopGTestTrace() - GTEST_LOCK_EXCLUDED_(mutex_) { - internal::MutexLock lock(&mutex_); - impl_->gtest_trace_stack().pop_back(); -} - -namespace internal { - -UnitTestImpl::UnitTestImpl(UnitTest* parent) - : parent_(parent), - GTEST_DISABLE_MSC_WARNINGS_PUSH_(4355 /* using this in initializer */) - default_global_test_part_result_reporter_(this), - default_per_thread_test_part_result_reporter_(this), - GTEST_DISABLE_MSC_WARNINGS_POP_() - global_test_part_result_repoter_( - &default_global_test_part_result_reporter_), - per_thread_test_part_result_reporter_( - &default_per_thread_test_part_result_reporter_), -#if GTEST_HAS_PARAM_TEST - parameterized_test_registry_(), - parameterized_tests_registered_(false), -#endif // GTEST_HAS_PARAM_TEST - last_death_test_case_(-1), - current_test_case_(NULL), - current_test_info_(NULL), - ad_hoc_test_result_(), - os_stack_trace_getter_(NULL), - post_flag_parse_init_performed_(false), - random_seed_(0), // Will be overridden by the flag before first use. - random_(0), // Will be reseeded before first use. - start_timestamp_(0), - elapsed_time_(0), -#if GTEST_HAS_DEATH_TEST - death_test_factory_(new DefaultDeathTestFactory), -#endif - // Will be overridden by the flag before first use. - catch_exceptions_(false) { - listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); -} - -UnitTestImpl::~UnitTestImpl() { - // Deletes every TestCase. - ForEach(test_cases_, internal::Delete); - - // Deletes every Environment. - ForEach(environments_, internal::Delete); - - delete os_stack_trace_getter_; -} - -// Adds a TestProperty to the current TestResult object when invoked in a -// context of a test, to current test case's ad_hoc_test_result when invoke -// from SetUpTestCase/TearDownTestCase, or to the global property set -// otherwise. If the result already contains a property with the same key, -// the value will be updated. -void UnitTestImpl::RecordProperty(const TestProperty& test_property) { - std::string xml_element; - TestResult* test_result; // TestResult appropriate for property recording. - - if (current_test_info_ != NULL) { - xml_element = "testcase"; - test_result = &(current_test_info_->result_); - } else if (current_test_case_ != NULL) { - xml_element = "testsuite"; - test_result = &(current_test_case_->ad_hoc_test_result_); - } else { - xml_element = "testsuites"; - test_result = &ad_hoc_test_result_; - } - test_result->RecordProperty(xml_element, test_property); -} - -#if GTEST_HAS_DEATH_TEST -// Disables event forwarding if the control is currently in a death test -// subprocess. Must not be called before InitGoogleTest. -void UnitTestImpl::SuppressTestEventsIfInSubprocess() { - if (internal_run_death_test_flag_.get() != NULL) - listeners()->SuppressEventForwarding(); -} -#endif // GTEST_HAS_DEATH_TEST - -// Initializes event listeners performing XML output as specified by -// UnitTestOptions. Must not be called before InitGoogleTest. -void UnitTestImpl::ConfigureXmlOutput() { - const std::string& output_format = UnitTestOptions::GetOutputFormat(); - if (output_format == "xml") { - listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( - UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); - } else if (output_format != "") { - printf("WARNING: unrecognized output format \"%s\" ignored.\n", - output_format.c_str()); - fflush(stdout); - } -} - -#if GTEST_CAN_STREAM_RESULTS_ -// Initializes event listeners for streaming test results in string form. -// Must not be called before InitGoogleTest. -void UnitTestImpl::ConfigureStreamingOutput() { - const std::string& target = GTEST_FLAG(stream_result_to); - if (!target.empty()) { - const size_t pos = target.find(':'); - if (pos != std::string::npos) { - listeners()->Append(new StreamingListener(target.substr(0, pos), - target.substr(pos+1))); - } else { - printf("WARNING: unrecognized streaming target \"%s\" ignored.\n", - target.c_str()); - fflush(stdout); - } - } -} -#endif // GTEST_CAN_STREAM_RESULTS_ - -// Performs initialization dependent upon flag values obtained in -// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to -// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest -// this function is also called from RunAllTests. Since this function can be -// called more than once, it has to be idempotent. -void UnitTestImpl::PostFlagParsingInit() { - // Ensures that this function does not execute more than once. - if (!post_flag_parse_init_performed_) { - post_flag_parse_init_performed_ = true; - -#if GTEST_HAS_DEATH_TEST - InitDeathTestSubprocessControlInfo(); - SuppressTestEventsIfInSubprocess(); -#endif // GTEST_HAS_DEATH_TEST - - // Registers parameterized tests. This makes parameterized tests - // available to the UnitTest reflection API without running - // RUN_ALL_TESTS. - RegisterParameterizedTests(); - - // Configures listeners for XML output. This makes it possible for users - // to shut down the default XML output before invoking RUN_ALL_TESTS. - ConfigureXmlOutput(); - -#if GTEST_CAN_STREAM_RESULTS_ - // Configures listeners for streaming test results to the specified server. - ConfigureStreamingOutput(); -#endif // GTEST_CAN_STREAM_RESULTS_ - } -} - -// A predicate that checks the name of a TestCase against a known -// value. -// -// This is used for implementation of the UnitTest class only. We put -// it in the anonymous namespace to prevent polluting the outer -// namespace. -// -// TestCaseNameIs is copyable. -class TestCaseNameIs { - public: - // Constructor. - explicit TestCaseNameIs(const std::string& name) - : name_(name) {} - - // Returns true iff the name of test_case matches name_. - bool operator()(const TestCase* test_case) const { - return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; - } - - private: - std::string name_; -}; - -// Finds and returns a TestCase with the given name. If one doesn't -// exist, creates one and returns it. It's the CALLER'S -// RESPONSIBILITY to ensure that this function is only called WHEN THE -// TESTS ARE NOT SHUFFLED. -// -// Arguments: -// -// test_case_name: name of the test case -// type_param: the name of the test case's type parameter, or NULL if -// this is not a typed or a type-parameterized test case. -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, - const char* type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc) { - // Can we find a TestCase with the given name? - const std::vector::const_iterator test_case = - std::find_if(test_cases_.begin(), test_cases_.end(), - TestCaseNameIs(test_case_name)); - - if (test_case != test_cases_.end()) - return *test_case; - - // No. Let's create one. - TestCase* const new_test_case = - new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc); - - // Is this a death test case? - if (internal::UnitTestOptions::MatchesFilter(test_case_name, - kDeathTestCaseFilter)) { - // Yes. Inserts the test case after the last death test case - // defined so far. This only works when the test cases haven't - // been shuffled. Otherwise we may end up running a death test - // after a non-death test. - ++last_death_test_case_; - test_cases_.insert(test_cases_.begin() + last_death_test_case_, - new_test_case); - } else { - // No. Appends to the end of the list. - test_cases_.push_back(new_test_case); - } - - test_case_indices_.push_back(static_cast(test_case_indices_.size())); - return new_test_case; -} - -// Helpers for setting up / tearing down the given environment. They -// are for use in the ForEach() function. -static void SetUpEnvironment(Environment* env) { env->SetUp(); } -static void TearDownEnvironment(Environment* env) { env->TearDown(); } - -// Runs all tests in this UnitTest object, prints the result, and -// returns true if all tests are successful. If any exception is -// thrown during a test, the test is considered to be failed, but the -// rest of the tests will still be run. -// -// When parameterized tests are enabled, it expands and registers -// parameterized tests first in RegisterParameterizedTests(). -// All other functions called from RunAllTests() may safely assume that -// parameterized tests are ready to be counted and run. -bool UnitTestImpl::RunAllTests() { - // Makes sure InitGoogleTest() was called. - if (!GTestIsInitialized()) { - printf("%s", - "\nThis test program did NOT call ::testing::InitGoogleTest " - "before calling RUN_ALL_TESTS(). Please fix it.\n"); - return false; - } - - // Do not run any test if the --help flag was specified. - if (g_help_flag) - return true; - - // Repeats the call to the post-flag parsing initialization in case the - // user didn't call InitGoogleTest. - PostFlagParsingInit(); - - // Even if sharding is not on, test runners may want to use the - // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding - // protocol. - internal::WriteToShardStatusFileIfNeeded(); - - // True iff we are in a subprocess for running a thread-safe-style - // death test. - bool in_subprocess_for_death_test = false; - -#if GTEST_HAS_DEATH_TEST - in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); -#endif // GTEST_HAS_DEATH_TEST - - const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, - in_subprocess_for_death_test); - - // Compares the full test names with the filter to decide which - // tests to run. - const bool has_tests_to_run = FilterTests(should_shard - ? HONOR_SHARDING_PROTOCOL - : IGNORE_SHARDING_PROTOCOL) > 0; - - // Lists the tests and exits if the --gtest_list_tests flag was specified. - if (GTEST_FLAG(list_tests)) { - // This must be called *after* FilterTests() has been called. - ListTestsMatchingFilter(); - return true; - } - - random_seed_ = GTEST_FLAG(shuffle) ? - GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; - - // True iff at least one test has failed. - bool failed = false; - - TestEventListener* repeater = listeners()->repeater(); - - start_timestamp_ = GetTimeInMillis(); - repeater->OnTestProgramStart(*parent_); - - // How many times to repeat the tests? We don't want to repeat them - // when we are inside the subprocess of a death test. - const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); - // Repeats forever if the repeat count is negative. - const bool forever = repeat < 0; - for (int i = 0; forever || i != repeat; i++) { - // We want to preserve failures generated by ad-hoc test - // assertions executed before RUN_ALL_TESTS(). - ClearNonAdHocTestResult(); - - const TimeInMillis start = GetTimeInMillis(); - - // Shuffles test cases and tests if requested. - if (has_tests_to_run && GTEST_FLAG(shuffle)) { - random()->Reseed(random_seed_); - // This should be done before calling OnTestIterationStart(), - // such that a test event listener can see the actual test order - // in the event. - ShuffleTests(); - } - - // Tells the unit test event listeners that the tests are about to start. - repeater->OnTestIterationStart(*parent_, i); - - // Runs each test case if there is at least one test to run. - if (has_tests_to_run) { - // Sets up all environments beforehand. - repeater->OnEnvironmentsSetUpStart(*parent_); - ForEach(environments_, SetUpEnvironment); - repeater->OnEnvironmentsSetUpEnd(*parent_); - - // Runs the tests only if there was no fatal failure during global - // set-up. - if (!Test::HasFatalFailure()) { - for (int test_index = 0; test_index < total_test_case_count(); - test_index++) { - GetMutableTestCase(test_index)->Run(); - } - } - - // Tears down all environments in reverse order afterwards. - repeater->OnEnvironmentsTearDownStart(*parent_); - std::for_each(environments_.rbegin(), environments_.rend(), - TearDownEnvironment); - repeater->OnEnvironmentsTearDownEnd(*parent_); - } - - elapsed_time_ = GetTimeInMillis() - start; - - // Tells the unit test event listener that the tests have just finished. - repeater->OnTestIterationEnd(*parent_, i); - - // Gets the result and clears it. - if (!Passed()) { - failed = true; - } - - // Restores the original test order after the iteration. This - // allows the user to quickly repro a failure that happens in the - // N-th iteration without repeating the first (N - 1) iterations. - // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in - // case the user somehow changes the value of the flag somewhere - // (it's always safe to unshuffle the tests). - UnshuffleTests(); - - if (GTEST_FLAG(shuffle)) { - // Picks a new random seed for each iteration. - random_seed_ = GetNextRandomSeed(random_seed_); - } - } - - repeater->OnTestProgramEnd(*parent_); - - return !failed; -} - -// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file -// if the variable is present. If a file already exists at this location, this -// function will write over it. If the variable is present, but the file cannot -// be created, prints an error and exits. -void WriteToShardStatusFileIfNeeded() { - const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); - if (test_shard_file != NULL) { - FILE* const file = posix::FOpen(test_shard_file, "w"); - if (file == NULL) { - ColoredPrintf(COLOR_RED, - "Could not write to the test shard status file \"%s\" " - "specified by the %s environment variable.\n", - test_shard_file, kTestShardStatusFile); - fflush(stdout); - exit(EXIT_FAILURE); - } - fclose(file); - } -} - -// Checks whether sharding is enabled by examining the relevant -// environment variable values. If the variables are present, -// but inconsistent (i.e., shard_index >= total_shards), prints -// an error and exits. If in_subprocess_for_death_test, sharding is -// disabled because it must only be applied to the original test -// process. Otherwise, we could filter out death tests we intended to execute. -bool ShouldShard(const char* total_shards_env, - const char* shard_index_env, - bool in_subprocess_for_death_test) { - if (in_subprocess_for_death_test) { - return false; - } - - const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); - const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); - - if (total_shards == -1 && shard_index == -1) { - return false; - } else if (total_shards == -1 && shard_index != -1) { - const Message msg = Message() - << "Invalid environment variables: you have " - << kTestShardIndex << " = " << shard_index - << ", but have left " << kTestTotalShards << " unset.\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); - fflush(stdout); - exit(EXIT_FAILURE); - } else if (total_shards != -1 && shard_index == -1) { - const Message msg = Message() - << "Invalid environment variables: you have " - << kTestTotalShards << " = " << total_shards - << ", but have left " << kTestShardIndex << " unset.\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); - fflush(stdout); - exit(EXIT_FAILURE); - } else if (shard_index < 0 || shard_index >= total_shards) { - const Message msg = Message() - << "Invalid environment variables: we require 0 <= " - << kTestShardIndex << " < " << kTestTotalShards - << ", but you have " << kTestShardIndex << "=" << shard_index - << ", " << kTestTotalShards << "=" << total_shards << ".\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); - fflush(stdout); - exit(EXIT_FAILURE); - } - - return total_shards > 1; -} - -// Parses the environment variable var as an Int32. If it is unset, -// returns default_val. If it is not an Int32, prints an error -// and aborts. -Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { - const char* str_val = posix::GetEnv(var); - if (str_val == NULL) { - return default_val; - } - - Int32 result; - if (!ParseInt32(Message() << "The value of environment variable " << var, - str_val, &result)) { - exit(EXIT_FAILURE); - } - return result; -} - -// Given the total number of shards, the shard index, and the test id, -// returns true iff the test should be run on this shard. The test id is -// some arbitrary but unique non-negative integer assigned to each test -// method. Assumes that 0 <= shard_index < total_shards. -bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { - return (test_id % total_shards) == shard_index; -} - -// Compares the name of each test with the user-specified filter to -// decide whether the test should be run, then records the result in -// each TestCase and TestInfo object. -// If shard_tests == true, further filters tests based on sharding -// variables in the environment - see -// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. -// Returns the number of tests that should run. -int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { - const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? - Int32FromEnvOrDie(kTestTotalShards, -1) : -1; - const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? - Int32FromEnvOrDie(kTestShardIndex, -1) : -1; - - // num_runnable_tests are the number of tests that will - // run across all shards (i.e., match filter and are not disabled). - // num_selected_tests are the number of tests to be run on - // this shard. - int num_runnable_tests = 0; - int num_selected_tests = 0; - for (size_t i = 0; i < test_cases_.size(); i++) { - TestCase* const test_case = test_cases_[i]; - const std::string &test_case_name = test_case->name(); - test_case->set_should_run(false); - - for (size_t j = 0; j < test_case->test_info_list().size(); j++) { - TestInfo* const test_info = test_case->test_info_list()[j]; - const std::string test_name(test_info->name()); - // A test is disabled if test case name or test name matches - // kDisableTestFilter. - const bool is_disabled = - internal::UnitTestOptions::MatchesFilter(test_case_name, - kDisableTestFilter) || - internal::UnitTestOptions::MatchesFilter(test_name, - kDisableTestFilter); - test_info->is_disabled_ = is_disabled; - - const bool matches_filter = - internal::UnitTestOptions::FilterMatchesTest(test_case_name, - test_name); - test_info->matches_filter_ = matches_filter; - - const bool is_runnable = - (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && - matches_filter; - - const bool is_selected = is_runnable && - (shard_tests == IGNORE_SHARDING_PROTOCOL || - ShouldRunTestOnShard(total_shards, shard_index, - num_runnable_tests)); - - num_runnable_tests += is_runnable; - num_selected_tests += is_selected; - - test_info->should_run_ = is_selected; - test_case->set_should_run(test_case->should_run() || is_selected); - } - } - return num_selected_tests; -} - -// Prints the given C-string on a single line by replacing all '\n' -// characters with string "\\n". If the output takes more than -// max_length characters, only prints the first max_length characters -// and "...". -static void PrintOnOneLine(const char* str, int max_length) { - if (str != NULL) { - for (int i = 0; *str != '\0'; ++str) { - if (i >= max_length) { - printf("..."); - break; - } - if (*str == '\n') { - printf("\\n"); - i += 2; - } else { - printf("%c", *str); - ++i; - } - } - } -} - -// Prints the names of the tests matching the user-specified filter flag. -void UnitTestImpl::ListTestsMatchingFilter() { - // Print at most this many characters for each type/value parameter. - const int kMaxParamLength = 250; - - for (size_t i = 0; i < test_cases_.size(); i++) { - const TestCase* const test_case = test_cases_[i]; - bool printed_test_case_name = false; - - for (size_t j = 0; j < test_case->test_info_list().size(); j++) { - const TestInfo* const test_info = - test_case->test_info_list()[j]; - if (test_info->matches_filter_) { - if (!printed_test_case_name) { - printed_test_case_name = true; - printf("%s.", test_case->name()); - if (test_case->type_param() != NULL) { - printf(" # %s = ", kTypeParamLabel); - // We print the type parameter on a single line to make - // the output easy to parse by a program. - PrintOnOneLine(test_case->type_param(), kMaxParamLength); - } - printf("\n"); - } - printf(" %s", test_info->name()); - if (test_info->value_param() != NULL) { - printf(" # %s = ", kValueParamLabel); - // We print the value parameter on a single line to make the - // output easy to parse by a program. - PrintOnOneLine(test_info->value_param(), kMaxParamLength); - } - printf("\n"); - } - } - } - fflush(stdout); -} - -// Sets the OS stack trace getter. -// -// Does nothing if the input and the current OS stack trace getter are -// the same; otherwise, deletes the old getter and makes the input the -// current getter. -void UnitTestImpl::set_os_stack_trace_getter( - OsStackTraceGetterInterface* getter) { - if (os_stack_trace_getter_ != getter) { - delete os_stack_trace_getter_; - os_stack_trace_getter_ = getter; - } -} - -// Returns the current OS stack trace getter if it is not NULL; -// otherwise, creates an OsStackTraceGetter, makes it the current -// getter, and returns it. -OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { - if (os_stack_trace_getter_ == NULL) { - os_stack_trace_getter_ = new OsStackTraceGetter; - } - - return os_stack_trace_getter_; -} - -// Returns the TestResult for the test that's currently running, or -// the TestResult for the ad hoc test if no test is running. -TestResult* UnitTestImpl::current_test_result() { - return current_test_info_ ? - &(current_test_info_->result_) : &ad_hoc_test_result_; -} - -// Shuffles all test cases, and the tests within each test case, -// making sure that death tests are still run first. -void UnitTestImpl::ShuffleTests() { - // Shuffles the death test cases. - ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); - - // Shuffles the non-death test cases. - ShuffleRange(random(), last_death_test_case_ + 1, - static_cast(test_cases_.size()), &test_case_indices_); - - // Shuffles the tests inside each test case. - for (size_t i = 0; i < test_cases_.size(); i++) { - test_cases_[i]->ShuffleTests(random()); - } -} - -// Restores the test cases and tests to their order before the first shuffle. -void UnitTestImpl::UnshuffleTests() { - for (size_t i = 0; i < test_cases_.size(); i++) { - // Unshuffles the tests in each test case. - test_cases_[i]->UnshuffleTests(); - // Resets the index of each test case. - test_case_indices_[i] = static_cast(i); - } -} - -// Returns the current OS stack trace as an std::string. -// -// The maximum number of stack frames to be included is specified by -// the gtest_stack_trace_depth flag. The skip_count parameter -// specifies the number of top frames to be skipped, which doesn't -// count against the number of frames to be included. -// -// For example, if Foo() calls Bar(), which in turn calls -// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in -// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. -std::string GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, - int skip_count) { - // We pass skip_count + 1 to skip this wrapper function in addition - // to what the user really wants to skip. - return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); -} - -// Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to -// suppress unreachable code warnings. -namespace { -class ClassUniqueToAlwaysTrue {}; -} - -bool IsTrue(bool condition) { return condition; } - -bool AlwaysTrue() { -#if GTEST_HAS_EXCEPTIONS - // This condition is always false so AlwaysTrue() never actually throws, - // but it makes the compiler think that it may throw. - if (IsTrue(false)) - throw ClassUniqueToAlwaysTrue(); -#endif // GTEST_HAS_EXCEPTIONS - return true; -} - -// If *pstr starts with the given prefix, modifies *pstr to be right -// past the prefix and returns true; otherwise leaves *pstr unchanged -// and returns false. None of pstr, *pstr, and prefix can be NULL. -bool SkipPrefix(const char* prefix, const char** pstr) { - const size_t prefix_len = strlen(prefix); - if (strncmp(*pstr, prefix, prefix_len) == 0) { - *pstr += prefix_len; - return true; - } - return false; -} - -// Parses a string as a command line flag. The string should have -// the format "--flag=value". When def_optional is true, the "=value" -// part can be omitted. -// -// Returns the value of the flag, or NULL if the parsing failed. -const char* ParseFlagValue(const char* str, - const char* flag, - bool def_optional) { - // str and flag must not be NULL. - if (str == NULL || flag == NULL) return NULL; - - // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. - const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag; - const size_t flag_len = flag_str.length(); - if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; - - // Skips the flag name. - const char* flag_end = str + flag_len; - - // When def_optional is true, it's OK to not have a "=value" part. - if (def_optional && (flag_end[0] == '\0')) { - return flag_end; - } - - // If def_optional is true and there are more characters after the - // flag name, or if def_optional is false, there must be a '=' after - // the flag name. - if (flag_end[0] != '=') return NULL; - - // Returns the string after "=". - return flag_end + 1; -} - -// Parses a string for a bool flag, in the form of either -// "--flag=value" or "--flag". -// -// In the former case, the value is taken as true as long as it does -// not start with '0', 'f', or 'F'. -// -// In the latter case, the value is taken as true. -// -// On success, stores the value of the flag in *value, and returns -// true. On failure, returns false without changing *value. -bool ParseBoolFlag(const char* str, const char* flag, bool* value) { - // Gets the value of the flag as a string. - const char* const value_str = ParseFlagValue(str, flag, true); - - // Aborts if the parsing failed. - if (value_str == NULL) return false; - - // Converts the string value to a bool. - *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); - return true; -} - -// Parses a string for an Int32 flag, in the form of -// "--flag=value". -// -// On success, stores the value of the flag in *value, and returns -// true. On failure, returns false without changing *value. -bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { - // Gets the value of the flag as a string. - const char* const value_str = ParseFlagValue(str, flag, false); - - // Aborts if the parsing failed. - if (value_str == NULL) return false; - - // Sets *value to the value of the flag. - return ParseInt32(Message() << "The value of flag --" << flag, - value_str, value); -} - -// Parses a string for a string flag, in the form of -// "--flag=value". -// -// On success, stores the value of the flag in *value, and returns -// true. On failure, returns false without changing *value. -bool ParseStringFlag(const char* str, const char* flag, std::string* value) { - // Gets the value of the flag as a string. - const char* const value_str = ParseFlagValue(str, flag, false); - - // Aborts if the parsing failed. - if (value_str == NULL) return false; - - // Sets *value to the value of the flag. - *value = value_str; - return true; -} - -// Determines whether a string has a prefix that Google Test uses for its -// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. -// If Google Test detects that a command line flag has its prefix but is not -// recognized, it will print its help message. Flags starting with -// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test -// internal flags and do not trigger the help message. -static bool HasGoogleTestFlagPrefix(const char* str) { - return (SkipPrefix("--", &str) || - SkipPrefix("-", &str) || - SkipPrefix("/", &str)) && - !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && - (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || - SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); -} - -// Prints a string containing code-encoded text. The following escape -// sequences can be used in the string to control the text color: -// -// @@ prints a single '@' character. -// @R changes the color to red. -// @G changes the color to green. -// @Y changes the color to yellow. -// @D changes to the default terminal text color. -// -// TODO(wan@google.com): Write tests for this once we add stdout -// capturing to Google Test. -static void PrintColorEncoded(const char* str) { - GTestColor color = COLOR_DEFAULT; // The current color. - - // Conceptually, we split the string into segments divided by escape - // sequences. Then we print one segment at a time. At the end of - // each iteration, the str pointer advances to the beginning of the - // next segment. - for (;;) { - const char* p = strchr(str, '@'); - if (p == NULL) { - ColoredPrintf(color, "%s", str); - return; - } - - ColoredPrintf(color, "%s", std::string(str, p).c_str()); - - const char ch = p[1]; - str = p + 2; - if (ch == '@') { - ColoredPrintf(color, "@"); - } else if (ch == 'D') { - color = COLOR_DEFAULT; - } else if (ch == 'R') { - color = COLOR_RED; - } else if (ch == 'G') { - color = COLOR_GREEN; - } else if (ch == 'Y') { - color = COLOR_YELLOW; - } else { - --str; - } - } -} - -static const char kColorEncodedHelpMessage[] = -"This program contains tests written using " GTEST_NAME_ ". You can use the\n" -"following command line flags to control its behavior:\n" -"\n" -"Test Selection:\n" -" @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" -" List the names of all tests instead of running them. The name of\n" -" TEST(Foo, Bar) is \"Foo.Bar\".\n" -" @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" - "[@G-@YNEGATIVE_PATTERNS]@D\n" -" Run only the tests whose name matches one of the positive patterns but\n" -" none of the negative patterns. '?' matches any single character; '*'\n" -" matches any substring; ':' separates two patterns.\n" -" @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" -" Run all disabled tests too.\n" -"\n" -"Test Execution:\n" -" @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" -" Run the tests repeatedly; use a negative count to repeat forever.\n" -" @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" -" Randomize tests' orders on every iteration.\n" -" @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" -" Random number seed to use for shuffling test orders (between 1 and\n" -" 99999, or 0 to use a seed based on the current time).\n" -"\n" -"Test Output:\n" -" @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" -" Enable/disable colored output. The default is @Gauto@D.\n" -" -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" -" Don't print the elapsed time of each test.\n" -" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" - GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" -" Generate an XML report in the given directory or with the given file\n" -" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" -#if GTEST_CAN_STREAM_RESULTS_ -" @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" -" Stream test results to the given server.\n" -#endif // GTEST_CAN_STREAM_RESULTS_ -"\n" -"Assertion Behavior:\n" -#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS -" @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" -" Set the default death test style.\n" -#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS -" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" -" Turn assertion failures into debugger break-points.\n" -" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" -" Turn assertion failures into C++ exceptions.\n" -" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" -" Do not report exceptions as test failures. Instead, allow them\n" -" to crash the program or throw a pop-up (on Windows).\n" -"\n" -"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " - "the corresponding\n" -"environment variable of a flag (all letters in upper-case). For example, to\n" -"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ - "color=no@D or set\n" -"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" -"\n" -"For more information, please read the " GTEST_NAME_ " documentation at\n" -"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" -"(not one in your own code or tests), please report it to\n" -"@G<" GTEST_DEV_EMAIL_ ">@D.\n"; - -// Parses the command line for Google Test flags, without initializing -// other parts of Google Test. The type parameter CharType can be -// instantiated to either char or wchar_t. -template -void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { - for (int i = 1; i < *argc; i++) { - const std::string arg_string = StreamableToString(argv[i]); - const char* const arg = arg_string.c_str(); - - using internal::ParseBoolFlag; - using internal::ParseInt32Flag; - using internal::ParseStringFlag; - - // Do we see a Google Test flag? - if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, - >EST_FLAG(also_run_disabled_tests)) || - ParseBoolFlag(arg, kBreakOnFailureFlag, - >EST_FLAG(break_on_failure)) || - ParseBoolFlag(arg, kCatchExceptionsFlag, - >EST_FLAG(catch_exceptions)) || - ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || - ParseStringFlag(arg, kDeathTestStyleFlag, - >EST_FLAG(death_test_style)) || - ParseBoolFlag(arg, kDeathTestUseFork, - >EST_FLAG(death_test_use_fork)) || - ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || - ParseStringFlag(arg, kInternalRunDeathTestFlag, - >EST_FLAG(internal_run_death_test)) || - ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || - ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || - ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || - ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || - ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || - ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || - ParseInt32Flag(arg, kStackTraceDepthFlag, - >EST_FLAG(stack_trace_depth)) || - ParseStringFlag(arg, kStreamResultToFlag, - >EST_FLAG(stream_result_to)) || - ParseBoolFlag(arg, kThrowOnFailureFlag, - >EST_FLAG(throw_on_failure)) - ) { - // Yes. Shift the remainder of the argv list left by one. Note - // that argv has (*argc + 1) elements, the last one always being - // NULL. The following loop moves the trailing NULL element as - // well. - for (int j = i; j != *argc; j++) { - argv[j] = argv[j + 1]; - } - - // Decrements the argument count. - (*argc)--; - - // We also need to decrement the iterator as we just removed - // an element. - i--; - } else if (arg_string == "--help" || arg_string == "-h" || - arg_string == "-?" || arg_string == "/?" || - HasGoogleTestFlagPrefix(arg)) { - // Both help flag and unrecognized Google Test flags (excluding - // internal ones) trigger help display. - g_help_flag = true; - } - } - - if (g_help_flag) { - // We print the help here instead of in RUN_ALL_TESTS(), as the - // latter may not be called at all if the user is using Google - // Test with another testing framework. - PrintColorEncoded(kColorEncodedHelpMessage); - } -} - -// Parses the command line for Google Test flags, without initializing -// other parts of Google Test. -void ParseGoogleTestFlagsOnly(int* argc, char** argv) { - ParseGoogleTestFlagsOnlyImpl(argc, argv); -} -void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { - ParseGoogleTestFlagsOnlyImpl(argc, argv); -} - -// The internal implementation of InitGoogleTest(). -// -// The type parameter CharType can be instantiated to either char or -// wchar_t. -template -void InitGoogleTestImpl(int* argc, CharType** argv) { - g_init_gtest_count++; - - // We don't want to run the initialization code twice. - if (g_init_gtest_count != 1) return; - - if (*argc <= 0) return; - - internal::g_executable_path = internal::StreamableToString(argv[0]); - -#if GTEST_HAS_DEATH_TEST - - g_argvs.clear(); - for (int i = 0; i != *argc; i++) { - g_argvs.push_back(StreamableToString(argv[i])); - } - -#endif // GTEST_HAS_DEATH_TEST - - ParseGoogleTestFlagsOnly(argc, argv); - GetUnitTestImpl()->PostFlagParsingInit(); -} - -} // namespace internal - -// Initializes Google Test. This must be called before calling -// RUN_ALL_TESTS(). In particular, it parses a command line for the -// flags that Google Test recognizes. Whenever a Google Test flag is -// seen, it is removed from argv, and *argc is decremented. -// -// No value is returned. Instead, the Google Test flag variables are -// updated. -// -// Calling the function for the second time has no user-visible effect. -void InitGoogleTest(int* argc, char** argv) { - internal::InitGoogleTestImpl(argc, argv); -} - -// This overloaded version can be used in Windows programs compiled in -// UNICODE mode. -void InitGoogleTest(int* argc, wchar_t** argv) { - internal::InitGoogleTestImpl(argc, argv); -} - -} // namespace testing \ No newline at end of file diff --git a/src/gtest/src/gtest_main.cc b/src/gtest/src/gtest_main.cc deleted file mode 100644 index 208f6159..00000000 --- a/src/gtest/src/gtest_main.cc +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2006 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// 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. - -#include - -#include "gtest/gtest.h" - -GTEST_API_ int main(int argc, char **argv) { - printf("Running main() from gtest_main.cc\n"); - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} \ No newline at end of file diff --git a/src/m4/ac_have_attribute.m4 b/src/m4/ac_have_attribute.m4 deleted file mode 100644 index 19f4021e..00000000 --- a/src/m4/ac_have_attribute.m4 +++ /dev/null @@ -1,16 +0,0 @@ -AC_DEFUN([AX_C___ATTRIBUTE__], [ - AC_MSG_CHECKING(for __attribute__) - AC_CACHE_VAL(ac_cv___attribute__, [ - AC_TRY_COMPILE( - [#include - static void foo(void) __attribute__ ((unused)); - void foo(void) { exit(1); }], - [], - ac_cv___attribute__=yes, - ac_cv___attribute__=no - )]) - if test "$ac_cv___attribute__" = "yes"; then - AC_DEFINE(HAVE___ATTRIBUTE__, 1, [define if your compiler has __attribute__]) - fi - AC_MSG_RESULT($ac_cv___attribute__) -]) diff --git a/src/priority_queue_sequence.h b/src/priority_queue_sequence.h new file mode 100644 index 00000000..e7ee402a --- /dev/null +++ b/src/priority_queue_sequence.h @@ -0,0 +1,72 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Author: ericv@google.com (Eric Veach) + +#ifndef S2_GEOMETRY_PRIORITY_QUEUE_SEQUENCE_H_ +#define S2_GEOMETRY_PRIORITY_QUEUE_SEQUENCE_H_ + +#include +#include +#include "util/gtl/inlined_vector.h" + +// Like std::priority_queue, except that: +// +// (1) the underlying sequence type is accessible via rep() and mutable_rep() +// methods, so that clients can manipulate it directly if desired; and +// (2) the default sequence type is util::gtl::InlinedVector. +// +// Exposing the sequence type gives more flexibility in how it is used, +// e.g. the queue can be emptied by calling clear(), the elements in the +// queue can be examined without removing them, etc. Note that if you modify +// the underlying sequence, then you must call make_heap() before calling any +// of the priority queue methods (push, pop, etc). +// +// Using InlinedVector as the default sequence type increases efficiency in +// cases where the maximum queue size is small. + +template , + class Compare = std::less > +class priority_queue_sequence + : public std::priority_queue { + public: + explicit priority_queue_sequence(const Compare& cmp = Compare(), + const Sequence& seq = Sequence()) + : std::priority_queue(cmp, seq) { + } + + template + priority_queue_sequence(InputIterator first, InputIterator last, + const Compare& cmp = Compare(), + const Sequence& seq = Sequence()) + : std::priority_queue(first, last, cmp, seq) { + } + + // Returns the underlying sequence. + Sequence const& rep() const { return this->c; } + + // Allows the underlying sequence to be modified. If you do this, you must + // call make_heap() before calling any of the other priority queue methods + // defined below. + Sequence* mutable_rep() { return &this->c; } + + // Restores the priority queue invariants after the underlying sequence has + // been modified using mutable_rep(). + void make_heap() { + std::make_heap(this->c.begin(), this->c.end(), this->comp); + } +}; + +#endif // S2_GEOMETRY_PRIORITY_QUEUE_SEQUENCE_H_ diff --git a/src/priority_queue_sequence_test.cc b/src/priority_queue_sequence_test.cc new file mode 100644 index 00000000..ec8072d5 --- /dev/null +++ b/src/priority_queue_sequence_test.cc @@ -0,0 +1,57 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Author: ericv@google.com (Eric Veach) + +#include "priority_queue_sequence.h" + +#include +#include "s2testing.h" +#include + +using std::vector; + +TEST(PriorityQueueSequence, RandomOrder) { + for (int iter = 0; iter < 1000; ++iter) { + // Insert the numbers from 0 to n-1 in a random order, using the priority + // queue to keep track of the k smallest numbers. The verify that at + // the end, the priority queue contains the number from 0 to k-1. + int n = 1 + S2Testing::rnd.Uniform(100); + int k = 1 + S2Testing::rnd.Uniform(n); + vector values(n); + for (int i = 0; i < n; ++i) { + values[i] = i; + } + std::random_shuffle(values.begin(), values.end(), S2Testing::rnd); + priority_queue_sequence queue; + for (int i = 0; i < k; ++i) { + queue.mutable_rep()->push_back(values[i]); + } + queue.make_heap(); + for (int i = k; i < n; ++i) { + if (values[i] >= queue.top()) continue; + queue.pop(); + queue.push(values[i]); + } + // Access the sequence through rep(). + EXPECT_EQ(k, queue.rep().size()); + for (int i = k; i > 0; --i) { + EXPECT_EQ(i, queue.size()); + EXPECT_EQ(i - 1, queue.top()); + queue.pop(); + } + EXPECT_TRUE(queue.empty()); + } +} diff --git a/src/r1interval.h b/src/r1interval.h index bb3a8665..e5730ccd 100644 --- a/src/r1interval.h +++ b/src/r1interval.h @@ -12,10 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_R1INTERVAL_H_ -#define UTIL_GEOMETRY_R1INTERVAL_H_ +#ifndef S2_GEOMETRY_R1INTERVAL_H_ +#define S2_GEOMETRY_R1INTERVAL_H_ #include #include @@ -23,7 +24,7 @@ #include #include -#include "base/type_traits.h" +#include "fpcontractoff.h" #include "util/math/vector2.h" // IWYU pragma: export // An R1Interval represents a closed, bounded interval on the real line. @@ -147,8 +148,8 @@ class R1Interval { // Expand the interval so that it contains the given point "p". void AddPoint(double p) { if (is_empty()) { set_lo(p); set_hi(p); } - else if (p < lo()) { set_lo(p); } - else if (p > hi()) { set_hi(p); } + else if (p < lo()) { set_lo(p); } // NOLINT + else if (p > hi()) { set_hi(p); } // NOLINT } // Expand the interval so that it contains the given interval "y". @@ -218,4 +219,4 @@ inline std::ostream& operator<<(std::ostream& os, R1Interval const& x) { return os << "[" << x.lo() << ", " << x.hi() << "]"; } -#endif // UTIL_GEOMETRY_R1INTERVAL_H_ \ No newline at end of file +#endif // S2_GEOMETRY_R1INTERVAL_H_ diff --git a/src/r1interval_test.cc b/src/r1interval_test.cc index 3608f5f9..bcb2c0dd 100644 --- a/src/r1interval_test.cc +++ b/src/r1interval_test.cc @@ -12,13 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "r1interval.h" #include -#include "gtest/gtest.h" +#include static void TestIntervalOps(R1Interval const& x, R1Interval const& y, const char* expected) { @@ -133,10 +134,10 @@ TEST(R1Interval, TestBasic) { EXPECT_TRUE(unit.Expanded(-0.51).Expanded(0.51).is_empty()); // Union(), Intersection() - EXPECT_EQ(R1Interval(99, 100), R1Interval(99,100).Union(empty)); - EXPECT_EQ(R1Interval(99, 100), empty.Union(R1Interval(99,100))); - EXPECT_TRUE(R1Interval(5,3).Union(R1Interval(0,-2)).is_empty()); - EXPECT_TRUE(R1Interval(0,-2).Union(R1Interval(5,3)).is_empty()); + EXPECT_EQ(R1Interval(99, 100), R1Interval(99, 100).Union(empty)); + EXPECT_EQ(R1Interval(99, 100), empty.Union(R1Interval(99, 100))); + EXPECT_TRUE(R1Interval(5, 3).Union(R1Interval(0, -2)).is_empty()); + EXPECT_TRUE(R1Interval(0, -2).Union(R1Interval(5, 3)).is_empty()); EXPECT_EQ(unit, unit.Union(unit)); EXPECT_EQ(R1Interval(-1, 1), unit.Union(negunit)); EXPECT_EQ(R1Interval(-1, 1), negunit.Union(unit)); @@ -181,4 +182,4 @@ TEST(R1Interval, ApproxEquals) { EXPECT_FALSE(R1Interval(1 + kHi, 2 - kLo).ApproxEquals(R1Interval(1, 2))); EXPECT_FALSE(R1Interval(1 - kLo, 2 + kHi).ApproxEquals(R1Interval(1, 2))); EXPECT_FALSE(R1Interval(1 + kLo, 2 - kHi).ApproxEquals(R1Interval(1, 2))); -} \ No newline at end of file +} diff --git a/src/r2.h b/src/r2.h index 4bd51ec5..55dba2fe 100644 --- a/src/r2.h +++ b/src/r2.h @@ -12,13 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_R2_H_ -#define UTIL_GEOMETRY_R2_H_ +#ifndef S2_GEOMETRY_R2_H_ +#define S2_GEOMETRY_R2_H_ +#include "fpcontractoff.h" #include "util/math/vector2.h" // IWYU pragma: export typedef Vector2_d R2Point; -#endif // UTIL_GEOMETRY_R2_H_ \ No newline at end of file +#endif // S2_GEOMETRY_R2_H_ diff --git a/src/r2rect.cc b/src/r2rect.cc index 6e41b004..c7186d21 100644 --- a/src/r2rect.cc +++ b/src/r2rect.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "r2rect.h" @@ -88,4 +89,4 @@ bool R2Rect::ApproxEquals(R2Rect const& other, double max_error) const { std::ostream& operator<<(std::ostream& os, R2Rect const& r) { return os << "[Lo" << r.lo() << ", Hi" << r.hi() << "]"; -} \ No newline at end of file +} diff --git a/src/r2rect.h b/src/r2rect.h index a9895e06..bec508b7 100644 --- a/src/r2rect.h +++ b/src/r2rect.h @@ -12,14 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_R2RECT_H_ -#define UTIL_GEOMETRY_R2RECT_H_ +#ifndef S2_GEOMETRY_R2RECT_H_ +#define S2_GEOMETRY_R2RECT_H_ #include #include +#include "fpcontractoff.h" #include "r1interval.h" #include "r2.h" @@ -31,18 +33,18 @@ class R2Rect { public: // Construct a rectangle from the given lower-left and upper-right points. - inline R2Rect(R2Point const& lo, R2Point const& hi); + R2Rect(R2Point const& lo, R2Point const& hi); // Construct a rectangle from the given intervals in x and y. The two // intervals must either be both empty or both non-empty. - inline R2Rect(R1Interval const& x, R1Interval const& y); + R2Rect(R1Interval const& x, R1Interval const& y); // The default constructor creates an empty R2Rect. - inline R2Rect(); + R2Rect(); // The canonical empty rectangle. Use is_empty() to test for empty // rectangles, since they have more than one representation. - inline static R2Rect Empty(); + static R2Rect Empty(); // Construct a rectangle from a center point and size in each dimension. // Both components of size should be non-negative, i.e. this method cannot @@ -71,10 +73,10 @@ class R2Rect { // Return true if the rectangle is valid, which essentially just means // that if the bound for either axis is empty then both must be. - inline bool is_valid() const; + bool is_valid() const; // Return true if the rectangle is empty, i.e. it contains no points at all. - inline bool is_empty() const; + bool is_empty() const; // Return the k-th vertex of the rectangle (k = 0,1,2,3) in CCW order. // Vertex 0 is in the lower-left corner. @@ -147,7 +149,7 @@ class R2Rect { R2Rect Intersection(R2Rect const& other) const; // Return true if two rectangles contains the same set of points. - inline bool operator==(R2Rect const& other) const; + bool operator==(R2Rect const& other) const; // Return true if the x- and y-intervals of the two rectangles are the same // up to the given tolerance (see r1interval.h for details). @@ -228,4 +230,4 @@ inline bool R2Rect::operator==(R2Rect const& other) const { std::ostream& operator<<(std::ostream& os, R2Rect const& r); -#endif // UTIL_GEOMETRY_R2RECT_H_ \ No newline at end of file +#endif // S2_GEOMETRY_R2RECT_H_ diff --git a/src/r2rect_test.cc b/src/r2rect_test.cc index d04ffda4..48ade4f9 100644 --- a/src/r2rect_test.cc +++ b/src/r2rect_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) // // Most of the R2Rect methods have trivial implementations in terms of the @@ -19,7 +20,7 @@ #include "r2rect.h" -#include "gtest/gtest.h" +#include #include "r2.h" static void TestIntervalOps(R2Rect const& x, R2Rect const& y, @@ -224,4 +225,4 @@ TEST(R2Rect, Expanded) { ApproxEquals(R2Rect(R2Point(0.1, 0.5), R2Point(0.4, 0.6)))); EXPECT_TRUE(R2Rect(R2Point(0.2, 0.4), R2Point(0.3, 0.7)).Expanded(0.1). ApproxEquals(R2Rect(R2Point(0.1, 0.3), R2Point(0.4, 0.8)))); -} \ No newline at end of file +} diff --git a/src/s1angle.cc b/src/s1angle.cc index bd5d53a3..c23d8fed 100644 --- a/src/s1angle.cc +++ b/src/s1angle.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s1angle.h" @@ -50,4 +51,4 @@ std::ostream& operator<<(std::ostream& os, S1Angle a) { } else { return os << degrees; } -} \ No newline at end of file +} diff --git a/src/s1angle.h b/src/s1angle.h index 35c83642..6e928382 100644 --- a/src/s1angle.h +++ b/src/s1angle.h @@ -12,18 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S1ANGLE_H_ -#define UTIL_GEOMETRY_S1ANGLE_H_ +#ifndef S2_GEOMETRY_S1ANGLE_H_ +#define S2_GEOMETRY_S1ANGLE_H_ -#include #include -#include // to forward declare ostream +#include +#include // No longer needed #include #include "base/integral_types.h" -#include "base/type_traits.h" +#include "fpcontractoff.h" #include "s2.h" #include "util/math/mathutil.h" @@ -34,38 +35,34 @@ class S2LatLng; // or from radians, degrees, and the E5/E6/E7 representations (i.e. degrees // multiplied by 1e5/1e6/1e7 and rounded to the nearest integer). // -// This class has built-in support for the E5, E6, and E7 -// representations. An E5 is the measure of an angle in degrees, -// multiplied by 10**5. -// // This class is intended to be copied by value as desired. It uses // the default copy constructor and assignment operator. class S1Angle { public: // These methods construct S1Angle objects from their measure in radians // or degrees. - inline static S1Angle Radians(double radians); - inline static S1Angle Degrees(double degrees); - inline static S1Angle E5(int32 e5); - inline static S1Angle E6(int32 e6); - inline static S1Angle E7(int32 e7); + static S1Angle Radians(double radians); + static S1Angle Degrees(double degrees); + static S1Angle E5(int32 e5); + static S1Angle E6(int32 e6); + static S1Angle E7(int32 e7); // Convenience functions -- to use when args have been fixed32s in protos. // // The arguments are static_cast into int32, so very large unsigned values // are treated as negative numbers. - inline static S1Angle UnsignedE6(uint32 e6); - inline static S1Angle UnsignedE7(uint32 e7); + static S1Angle UnsignedE6(uint32 e6); + static S1Angle UnsignedE7(uint32 e7); // The default constructor yields a zero angle. This is useful for STL // containers and class methods with output arguments. - inline S1Angle() : radians_(0) {} + S1Angle() : radians_(0) {} // Return an angle larger than any finite angle. - inline static S1Angle Infinity(); + static S1Angle Infinity(); // A explicit shorthand for the default constructor. - inline static S1Angle Zero(); + static S1Angle Zero(); // Return the angle between two points, which is also equal to the distance // between these points on the unit sphere. The points do not need to be @@ -87,25 +84,25 @@ class S1Angle { S1Angle abs() const { return S1Angle(fabs(radians_)); } // Comparison operators. - friend inline bool operator==(S1Angle x, S1Angle y); - friend inline bool operator!=(S1Angle x, S1Angle y); - friend inline bool operator<(S1Angle x, S1Angle y); - friend inline bool operator>(S1Angle x, S1Angle y); - friend inline bool operator<=(S1Angle x, S1Angle y); - friend inline bool operator>=(S1Angle x, S1Angle y); + friend bool operator==(S1Angle x, S1Angle y); + friend bool operator!=(S1Angle x, S1Angle y); + friend bool operator<(S1Angle x, S1Angle y); + friend bool operator>(S1Angle x, S1Angle y); + friend bool operator<=(S1Angle x, S1Angle y); + friend bool operator>=(S1Angle x, S1Angle y); // Simple arithmetic operators for manipulating S1Angles. - friend inline S1Angle operator-(S1Angle a); - friend inline S1Angle operator+(S1Angle a, S1Angle b); - friend inline S1Angle operator-(S1Angle a, S1Angle b); - friend inline S1Angle operator*(double m, S1Angle a); - friend inline S1Angle operator*(S1Angle a, double m); - friend inline S1Angle operator/(S1Angle a, double m); - friend inline double operator/(S1Angle a, S1Angle b); - inline S1Angle& operator+=(S1Angle a); - inline S1Angle& operator-=(S1Angle a); - inline S1Angle& operator*=(double m); - inline S1Angle& operator/=(double m); + friend S1Angle operator-(S1Angle a); + friend S1Angle operator+(S1Angle a, S1Angle b); + friend S1Angle operator-(S1Angle a, S1Angle b); + friend S1Angle operator*(double m, S1Angle a); + friend S1Angle operator*(S1Angle a, double m); + friend S1Angle operator/(S1Angle a, double m); + friend double operator/(S1Angle a, S1Angle b); + S1Angle& operator+=(S1Angle a); + S1Angle& operator-=(S1Angle a); + S1Angle& operator*=(double m); + S1Angle& operator/=(double m); // Trigonmetric functions (not necessary but slightly more convenient). friend double sin(S1Angle a); @@ -118,6 +115,7 @@ class S1Angle { // Normalize this angle to the range (-180, 180] degrees. void Normalize(); + private: explicit S1Angle(double radians) : radians_(radians) {} double radians_; @@ -253,4 +251,4 @@ inline S1Angle S1Angle::UnsignedE7(uint32 e7) { // decimal point, e.g. "17.3745904". std::ostream& operator<<(std::ostream& os, S1Angle a); -#endif // UTIL_GEOMETRY_S1ANGLE_H_ \ No newline at end of file +#endif // S2_GEOMETRY_S1ANGLE_H_ diff --git a/src/s1angle_test.cc b/src/s1angle_test.cc index dee8a5d6..9adf7128 100644 --- a/src/s1angle_test.cc +++ b/src/s1angle_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s1angle.h" @@ -19,7 +20,7 @@ #include #include "base/integral_types.h" #include -#include "gtest/gtest.h" +#include #include "s2latlng.h" #include "s2testing.h" @@ -198,4 +199,4 @@ TEST(S1Angle, TestPerformance) { // The difference factor slightly less than 2 on an x86_64. EXPECT_LE(from_e6_time / to_e6_time, 3); EXPECT_LE(to_e6_time / from_e6_time, 3); -} \ No newline at end of file +} diff --git a/src/s1chordangle.cc b/src/s1chordangle.cc index 22046276..a333d82e 100644 --- a/src/s1chordangle.cc +++ b/src/s1chordangle.cc @@ -12,11 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) +#include "s1chordangle.h" + #include #include "s1angle.h" -#include "s1chordangle.h" using std::max; using std::min; @@ -42,7 +44,7 @@ S1ChordAngle::S1ChordAngle(S1Angle angle) { DCHECK(is_valid()); } -S1Angle S1ChordAngle::ToAngle() { +S1Angle S1ChordAngle::ToAngle() const { if (is_negative()) return S1Angle::Radians(-1); if (is_infinity()) return S1Angle::Infinity(); return S1Angle::Radians(2 * asin(0.5 * sqrt(length2_))); @@ -113,4 +115,4 @@ double tan(S1ChordAngle a) { std::ostream& operator<<(std::ostream& os, S1ChordAngle a) { return os << a.ToAngle(); -} \ No newline at end of file +} diff --git a/src/s1chordangle.h b/src/s1chordangle.h index 767c9918..94ed589c 100644 --- a/src/s1chordangle.h +++ b/src/s1chordangle.h @@ -12,15 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S1CHORDANGLE_H_ -#define UTIL_GEOMETRY_S1CHORDANGLE_H_ +#ifndef S2_GEOMETRY_S1CHORDANGLE_H_ +#define S2_GEOMETRY_S1CHORDANGLE_H_ -#include #include -#include // to forward declare ostream + +#include +#include // No longer needed #include + +#include "fpcontractoff.h" #include "s1angle.h" #include "s2.h" @@ -87,7 +91,7 @@ class S1ChordAngle { // Convert the chord angle to an S1Angle. Infinity() is converted to // S1Angle::Infinity(), and Negative() is converted to a negative S1Angle. // This operation is relatively expensive. - S1Angle ToAngle(); + S1Angle ToAngle() const; // All operators and functions are declared here so that we can put them all // in one place. (The compound assignment operators must be put here.) @@ -126,6 +130,7 @@ class S1ChordAngle { // Infinity() are both considered valid. bool is_valid() const; + private: // S1ChordAngles are represented by the squared chord length, which can // range from 0 to 4. Infinity() uses an infinite squared length. @@ -216,4 +221,4 @@ inline S1ChordAngle& S1ChordAngle::operator-=(S1ChordAngle a) { // Outputs the chord angle as the equivalent S1Angle. std::ostream& operator<<(std::ostream& os, S1ChordAngle a); -#endif // UTIL_GEOMETRY_S1CHORDANGLE_H_ \ No newline at end of file +#endif // S2_GEOMETRY_S1CHORDANGLE_H_ diff --git a/src/s1chordangle_test.cc b/src/s1chordangle_test.cc index b9fb288b..dbb310d7 100644 --- a/src/s1chordangle_test.cc +++ b/src/s1chordangle_test.cc @@ -12,12 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. // + #include "s1chordangle.h" -#include "gtest/gtest.h" +#include + +#include #include "s1angle.h" #include "s2testing.h" +using std::numeric_limits; + TEST(S1ChordAngle, DefaultConstructor) { // Check that the default constructor returns an angle of 0. S1ChordAngle a; @@ -136,4 +141,4 @@ TEST(S1ChordAngle, Trigonometry) { EXPECT_EQ(0, sin(angle180)); EXPECT_EQ(-1, cos(angle180)); EXPECT_EQ(0, tan(angle180)); -} \ No newline at end of file +} diff --git a/src/s1interval.cc b/src/s1interval.cc index 6278f7e5..3201c21f 100644 --- a/src/s1interval.cc +++ b/src/s1interval.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s1interval.h" @@ -290,4 +291,4 @@ bool S1Interval::ApproxEquals(S1Interval const& y, double max_error) const { return (fabs(remainder(y.lo() - lo(), 2 * M_PI)) <= max_error && fabs(remainder(y.hi() - hi(), 2 * M_PI)) <= max_error && fabs(GetLength() - y.GetLength()) <= 2 * max_error); -} \ No newline at end of file +} diff --git a/src/s1interval.h b/src/s1interval.h index d95ae905..d7292b35 100644 --- a/src/s1interval.h +++ b/src/s1interval.h @@ -12,17 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S1INTERVAL_H_ -#define UTIL_GEOMETRY_S1INTERVAL_H_ +#ifndef S2_GEOMETRY_S1INTERVAL_H_ +#define S2_GEOMETRY_S1INTERVAL_H_ #include #include #include #include -#include "base/type_traits.h" +#include "fpcontractoff.h" #include "util/math/vector2.h" // IWYU pragma: export // An S1Interval represents a closed interval on a unit circle (also known @@ -49,7 +50,7 @@ class S1Interval { // Constructor. Both endpoints must be in the range -Pi to Pi inclusive. // The value -Pi is converted internally to Pi except for the Full() // and Empty() intervals. - inline S1Interval(double lo, double hi); + S1Interval(double lo, double hi); // The default constructor creates an empty interval. // @@ -58,13 +59,13 @@ class S1Interval { // constructor above: // // lng_bounds_ = S1Interval(lng_lo, lng_hi); - inline S1Interval(); + S1Interval(); // Returns the empty interval. - static inline S1Interval Empty(); + static S1Interval Empty(); // Returns the full interval. - static inline S1Interval Full(); + static S1Interval Full(); // Convenience method to construct an interval containing a single point. static S1Interval FromPoint(double p); @@ -89,7 +90,7 @@ class S1Interval { // An interval is valid if neither bound exceeds Pi in absolute value, // and the value -Pi appears only in the Empty() and Full() intervals. - inline bool is_valid() const; + bool is_valid() const; // Return true if the interval contains all points on the unit circle. bool is_full() const { return hi() - lo() == 2 * M_PI; } @@ -177,7 +178,7 @@ class S1Interval { S1Interval Intersection(S1Interval const& y) const; // Return true if two intervals contains the same set of points. - inline bool operator==(S1Interval const& y) const; + bool operator==(S1Interval const& y) const; // Return true if this interval can be transformed into the given interval by // moving each endpoint by at most "max_error" (and without the endpoints @@ -207,7 +208,7 @@ class S1Interval { // Internal constructor that assumes that both arguments are in the // correct range, i.e. normalization from -Pi to Pi is already done. - inline S1Interval(double lo, double hi, ArgsChecked dummy); + S1Interval(double lo, double hi, ArgsChecked dummy); // Return true if the interval (which is closed) contains the point 'p'. // Skips the normalization of 'p' from -Pi to Pi. @@ -262,4 +263,4 @@ inline std::ostream& operator<<(std::ostream& os, S1Interval const& x) { return os << "[" << x.lo() << ", " << x.hi() << "]"; } -#endif // UTIL_GEOMETRY_S1INTERVAL_H_ \ No newline at end of file +#endif // S2_GEOMETRY_S1INTERVAL_H_ diff --git a/src/s1interval_test.cc b/src/s1interval_test.cc index 348d4550..96dea8e4 100644 --- a/src/s1interval_test.cc +++ b/src/s1interval_test.cc @@ -12,13 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s1interval.h" #include -#include "gtest/gtest.h" +#include class S1IntervalTestBase : public testing::Test { public: @@ -446,9 +447,9 @@ TEST_F(S1IntervalTestBase, GetDirectedHausdorffDistance) { EXPECT_EQ(0.0, quad12.GetDirectedHausdorffDistance(quad123)); S1Interval in(3.0, -3.0); // an interval whose complement center is 0. EXPECT_FLOAT_EQ(3.0, - S1Interval(-0.1,0.2).GetDirectedHausdorffDistance(in)); + S1Interval(-0.1, 0.2).GetDirectedHausdorffDistance(in)); EXPECT_FLOAT_EQ(3.0 - 0.1, S1Interval(0.1, 0.2).GetDirectedHausdorffDistance(in)); EXPECT_FLOAT_EQ(3.0 - 0.1, S1Interval(-0.2, -0.1).GetDirectedHausdorffDistance(in)); -} \ No newline at end of file +} diff --git a/src/s2.cc b/src/s2.cc index dffa5086..a88bc46c 100644 --- a/src/s2.cc +++ b/src/s2.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2.h" @@ -44,15 +45,15 @@ unsigned int const S2::kMaxSiTi; // |x| denotes either absolute value or the L2-norm as appropriate, and // e = 0.5*DBL_EPSILON. Similarly, // -// fl(B.C) = B.C + d where |d| <= (|B.C| + 2*|B|*|C|) * e . +// fl(B.C) = B.C + d where |d| <= (1.5*|B.C| + 1.5*|B|*|C|) * e . // // Applying these bounds to the unit-length vectors A,B,C and neglecting // relative error (which does not affect the sign of the result), we get // -// fl((AxB).C) = (AxB).C + d where |d| <= (3 + 2/sqrt(3)) * e +// fl((AxB).C) = (AxB).C + d where |d| <= (2.5 + 2/sqrt(3)) * e // -// which is about 4.1548 * e, or 2.0774 * DBL_EPSILON. -double const S2::kMaxDetError = 2.0774 * DBL_EPSILON; +// which is about 3.6548 * e, or 1.8274 * DBL_EPSILON. +double const S2::kMaxDetError = 1.8274 * DBL_EPSILON; int const S2::kFaceUVWFaces[6][3][2] = { { { 4, 1 }, { 5, 2 }, { 3, 0 } }, @@ -349,7 +350,7 @@ int S2::ExactCCW(S2Point const& a, S2Point const& b, S2Point const& c) { // sign of the determinant. det_sign = SymbolicallyPerturbedCCW(xa, xb, xc, xb_cross_xc); } - DCHECK(det_sign != 0); + DCHECK_NE(0, det_sign); return perm_sign * det_sign; } @@ -441,36 +442,36 @@ static int SymbolicallyPerturbedCCW( // some of the signs are different because the opposite cross product is // used (e.g., B x C rather than C x B). - int det_sign = b_cross_c[2].sgn(); // da[2] + int det_sign = b_cross_c[2].sgn(); // da[2] if (det_sign != 0) return det_sign; - det_sign = b_cross_c[1].sgn(); // da[1] + det_sign = b_cross_c[1].sgn(); // da[1] if (det_sign != 0) return det_sign; - det_sign = b_cross_c[0].sgn(); // da[0] + det_sign = b_cross_c[0].sgn(); // da[0] if (det_sign != 0) return det_sign; - det_sign = (c[0]*a[1] - c[1]*a[0]).sgn(); // db[2] + det_sign = (c[0]*a[1] - c[1]*a[0]).sgn(); // db[2] if (det_sign != 0) return det_sign; - det_sign = c[0].sgn(); // db[2] * da[1] + det_sign = c[0].sgn(); // db[2] * da[1] if (det_sign != 0) return det_sign; - det_sign = -(c[1].sgn()); // db[2] * da[0] + det_sign = -(c[1].sgn()); // db[2] * da[0] if (det_sign != 0) return det_sign; - det_sign = (c[2]*a[0] - c[0]*a[2]).sgn(); // db[1] + det_sign = (c[2]*a[0] - c[0]*a[2]).sgn(); // db[1] if (det_sign != 0) return det_sign; - det_sign = c[2].sgn(); // db[1] * da[0] + det_sign = c[2].sgn(); // db[1] * da[0] if (det_sign != 0) return det_sign; // The following test is listed in the paper, but it is redundant because // the previous tests guarantee that C == (0, 0, 0). - DCHECK_EQ(0, (c[1]*a[2] - c[2]*a[1]).sgn()); // db[0] + DCHECK_EQ(0, (c[1]*a[2] - c[2]*a[1]).sgn()); // db[0] - det_sign = (a[0]*b[1] - a[1]*b[0]).sgn(); // dc[2] + det_sign = (a[0]*b[1] - a[1]*b[0]).sgn(); // dc[2] if (det_sign != 0) return det_sign; - det_sign = -(b[0].sgn()); // dc[2] * da[1] + det_sign = -(b[0].sgn()); // dc[2] * da[1] if (det_sign != 0) return det_sign; - det_sign = b[1].sgn(); // dc[2] * da[0] + det_sign = b[1].sgn(); // dc[2] * da[0] if (det_sign != 0) return det_sign; - det_sign = a[0].sgn(); // dc[2] * db[1] + det_sign = a[0].sgn(); // dc[2] * db[1] if (det_sign != 0) return det_sign; - return 1; // dc[2] * db[1] * da[0] + return 1; // dc[2] * db[1] * da[0] } double S2::Angle(S2Point const& a, S2Point const& b, S2Point const& c) { @@ -772,4 +773,4 @@ double const S2::kMaxEdgeAspect = ( 0); double const S2::kMaxDiagAspect = sqrt(3); // 1.732 -// This is true for all projections. \ No newline at end of file +// This is true for all projections. diff --git a/src/s2.h b/src/s2.h index 625f9db8..ac1ac258 100644 --- a/src/s2.h +++ b/src/s2.h @@ -12,23 +12,22 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2_H_ -#define UTIL_GEOMETRY_S2_H_ +#ifndef S2_GEOMETRY_S2_H_ +#define S2_GEOMETRY_S2_H_ #include #include #include #include -#include -using __gnu_cxx::hash; -using __gnu_cxx::hash_map; // To have template struct hash defined #include #include #include "base/macros.h" #include "base/port.h" +#include "fpcontractoff.h" #include "r2.h" #include "util/math/mathutil.h" // IWYU pragma: export #include "util/math/matrix3x3.h" @@ -67,7 +66,7 @@ enum S2debugOverride { // arithmetic expressions (e.g. (1-x)*p1 + x*p2). typedef Vector3_d S2Point; -typedef hash HashS2Point; +typedef GoodFastHash S2PointHash; // The S2 class is simply a namespace for constants and static utility // functions related to spherical geometry, such as area calculations and edge @@ -91,8 +90,6 @@ typedef hash HashS2Point; // This file also contains documentation of the various coordinate systems // and conventions used. // -// This class is not thread-safe for loops and objects that use loops. -// class S2 { public: // Return a unique "origin" on the sphere for operations that need a fixed @@ -216,7 +213,7 @@ class S2 { // points are the same. It uses a combination of multiple-precision // arithmetic and symbolic perturbations to ensure that its results are // always self-consistent (cf. Simulation of Simplicity, Edelsbrunner and - // Muecke). The basic idea is to assign an infinitesmal symbolic + // Muecke). The basic idea is to assign an infinitesimal symbolic // perturbation to every possible S2Point such that no three S2Points are // collinear and no four S2Points are coplanar. These perturbations are so // small that they do not affect the sign of any determinant that was @@ -865,7 +862,8 @@ inline double S2::SiTitoST(unsigned int si) { } inline unsigned int S2::STtoSiTi(double s) { - return MathUtil::FastIntRound(s * kMaxSiTi); + // kMaxSiTi == 2^31, so the result doesn't fit in an int32 when s == 1. + return static_cast(MathUtil::FastInt64Round(s * kMaxSiTi)); } inline S2Point S2::FaceUVtoXYZ(int face, double u, double v) { @@ -1011,4 +1009,4 @@ int S2::Metric::GetClosestLevel(double value) const { #undef S2_CONSTEXPR -#endif // UTIL_GEOMETRY_S2_H_ \ No newline at end of file +#endif // S2_GEOMETRY_S2_H_ diff --git a/src/s2.swig b/src/s2.swig deleted file mode 100755 index 6af8e811..00000000 --- a/src/s2.swig +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2006 Google Inc. All Rights Reserved. - -%include base/swig/google.swig - -%{ -#include - -#include "s2cellid.h" -#include "s2region.h" -#include "s2cap.h" -#include "s2latlng.h" -#include "s2latlngrect.h" -#include "s2loop.h" -#include "s2polygon.h" -#include "s2polyline.h" -#include "s2regioncoverer.h" -#include "s2cell.h" -#include "s2cellunion.h" -%} - -// The PACKED macro makes SWIG think that we're declaring a variable of type -// S2CellId named PACKED. We don't need it so we clobber it with an empty body. -#define PACKED - -// The DECLARE_POD macro makes SWIG think the specified type's defined twice. -// We don't need it, so we can just remove it. -#define DECLARE_POD(TypeName) - -// Warning 510 is "friend function 'operator +' ignored.". We can't do anything -// about that. Warning 389 is 'operator[] ignored' (these are alternate -// accessor methods on R1Interval and S1Interval), which is fine. -#pragma SWIG nowarn=510,389 - -// If we don't ignore this, the wrapper ends up assigning to None -%ignore S2CellId::None; - -#ifdef SWIGPYTHON - -%inline %{ - static PyObject *FromS2CellId(const S2CellId &cell_id) { - return SWIG_NewPointerObj(new S2CellId(cell_id), SWIGTYPE_p_S2CellId, 1); - } -%} - -%typemap(in, numinputs=0) -std::vector *OUTPUT(std::vector temp) { - $1 = &temp; -} - -%typemap(argout, fragment="t_output_helper") -std::vector *OUTPUT { - $result = t_output_helper($result, vector_output_helper($1, &FromS2CellId)); -} - -%apply std::vector *OUTPUT {std::vector *covering}; -%apply std::vector *OUTPUT {std::vector *output}; - -%{ -template -static PyObject* array_output_helper(const T* arr, int size, - PyObject* (*converter)(const TR x)) { - if (arr == NULL) { - // Return a nice out-of-band value if the pointer is NULL. - Py_INCREF(Py_None); - return Py_None; - } - - PyObject* const lst = PyList_New(size); - if (lst == NULL) - return NULL; - - for (int i = 0; i < size; i++) { - PyObject* const obj = converter(arr[i]); - if (!obj) { - Py_DECREF(lst); - return NULL; - } - PyList_SET_ITEM(lst, i, obj); - } - - return lst; -} -%} - -%typemap(in, numinputs=0) -S2CellId *OUTPUT_ARRAY_4(S2CellId temp[4]) { - $1 = temp; -} - -%typemap(argout, fragment="t_output_helper") -S2CellId *OUTPUT_ARRAY_4 { - $result = t_output_helper($result, array_output_helper($1, 4, &FromS2CellId)); -} - -%apply S2CellId *OUTPUT_ARRAY_4 {S2CellId neighbors[4]}; - -// This overload shadows the one the takes vector&, and it -// does not work anyway. -%ignore S2CellUnion::Init(vector const& cell_ids); - -// The SWIG code which picks between overloaded methods doesn't work -// when given a list parameter. SWIG_Python_ConvertPtrAndOwn calls -// SWIG_Python_GetSwigThis, doesn't find the 'this' attribute and gives up. -// To avoid this problem rename the Polyline::Init methods so they aren't -// overloaded. -%rename(InitFromS2LatLngs) S2Polyline::Init(vector const& vertices); -%rename(InitFromS2Points) S2Polyline::Init(vector const& vertices); - -%apply int *OUTPUT {int *next_vertex}; - -// Avoid leaking memory when holding S2Points in python. -class S2Point { - public: - ~S2Point(); -}; - -// The extensions below exist because of the difficulty swigging S2Point. - -// This alternate method of S2Loop::vertex() returns a S2LatLng instead. -%extend S2Loop { - public: - S2LatLng GetS2LatLngVertex(int i) { - return S2LatLng(self->vertex(i)); - } -}; - -// This alternate method of S2Cell::GetVertex() returns a S2LatLng instead. -%extend S2Cell { - public: - S2LatLng GetS2LatLngVertex(int k) { - return S2LatLng(self->GetVertex(k)); - } -}; - -// This alternate method of S2Cell::GetEdge() returns a S2LatLng instead. -%extend S2Cell { - public: - S2LatLng GetS2LatLngEdge(int k) { - return S2LatLng(self->GetEdge(k)); - } -}; - -%template() std::vector; -%template() std::vector; - -#endif - -%include "util/geometry/r1interval.h" -%include "util/geometry/s1angle.h" -%include "util/geometry/s1interval.h" -%include "util/geometry/s2cellid.h" -%include "util/geometry/s2region.h" -%include "util/geometry/s2cap.h" -%include "util/geometry/s2latlng.h" -%include "util/geometry/s2latlngrect.h" -%include "util/geometry/s2loop.h" -%include "util/geometry/s2polygon.h" -%include "util/geometry/s2polyline.h" -%include "util/geometry/s2regioncoverer.h" -%include "util/geometry/s2cell.h" -%include "util/geometry/s2cellunion.h" - -%define USE_STREAM_INSERTOR_FOR_STR(type) - %extend type { - string __str__() { - std::ostrstream output; - output << *self << std::ends; - return output.str(); - } - } -%enddef - -%define USE_EQUALS_FOR_EQ_AND_NE(type) - %extend type { - bool __eq__(const type& other) { - return *self == other; - } - - bool __ne__(const type& other) { - return *self != other; - } - } -%enddef - -%define USE_COMPARISON_FOR_LT_AND_GT(type) - %extend type { - bool __lt__(const type& other) { - return *self < other; - } - - bool __gt__(const type& other) { - return *self > other; - } - } -%enddef - -%define USE_STD_HASH_FOR_HASH(type) - %extend type { - size_t __hash__() { - return HASH_NAMESPACE::hash()(*self); - } - } -%enddef - -USE_STREAM_INSERTOR_FOR_STR(S1Angle) -USE_STREAM_INSERTOR_FOR_STR(S1Interval) -USE_STREAM_INSERTOR_FOR_STR(S2CellId) -USE_STREAM_INSERTOR_FOR_STR(S2Cap) -USE_STREAM_INSERTOR_FOR_STR(S2LatLng) -USE_STREAM_INSERTOR_FOR_STR(S2LatLngRect) - -USE_EQUALS_FOR_EQ_AND_NE(S2CellId) -USE_COMPARISON_FOR_LT_AND_GT(S2CellId) -USE_STD_HASH_FOR_HASH(S2CellId) diff --git a/src/s2_test.cc b/src/s2_test.cc index 14729b44..6b9b7dff 100644 --- a/src/s2_test.cc +++ b/src/s2_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2.h" @@ -19,19 +20,15 @@ #include #include #include -#include -using __gnu_cxx::hash; -using __gnu_cxx::hash_map; -#include -using __gnu_cxx::hash; -using __gnu_cxx::hash_set; #include +#include +#include #include #include "base/casts.h" #include "base/integral_types.h" #include -#include "gtest/gtest.h" +#include #include "s2cell.h" #include "s2cellid.h" #include "s2edgeutil.h" @@ -41,6 +38,8 @@ using __gnu_cxx::hash_set; using std::max; using std::min; +using std::unordered_map; +using std::unordered_set; using std::vector; inline static int SwapAxes(int ij) { @@ -275,8 +274,7 @@ TEST(S2, AreaMethods) { S2Point pr = S2Point(0.257, -0.5723, 0.112).Normalize(); S2Point pq = S2Point(-0.747, 0.401, 0.2235).Normalize(); EXPECT_EQ(S2::Area(pr, pr, pr), 0); - // TODO: The following test is not exact in optimized mode because the - // compiler chooses to mix 64-bit and 80-bit intermediate results. + // The following test is not exact due to rounding error. EXPECT_NEAR(S2::Area(pr, pq, pr), 0, 1e-15); EXPECT_EQ(S2::Area(p000, p045, p090), 0); @@ -915,9 +913,9 @@ TEST(S2, Rotate) { TEST(S2, S2PointHashSpreads) { int kTestPoints = 1 << 16; - hash_set set; - hash_set points; - HashS2Point hasher; + unordered_set set; + unordered_set points; + S2PointHash hasher; S2Point base = S2Point(1, 1, 1); for (int i = 0; i < kTestPoints; ++i) { // All points in a tiny cap to test avalanche property of hash @@ -937,7 +935,7 @@ TEST(S2, S2PointHashCollapsesZero) { double zero = 0; double minus_zero = -zero; EXPECT_NE(bit_cast(zero), bit_cast(minus_zero)); - hash_map map; + unordered_map map; S2Point zero_pt(zero, zero, zero); S2Point minus_zero_pt(minus_zero, minus_zero, minus_zero); @@ -955,7 +953,7 @@ TEST(S2, S2PointHashCollapsesLowOrderBit) { S2Point p2(FlipDoubleLowOrderBit(p1.x()), FlipDoubleLowOrderBit(p1.y()), FlipDoubleLowOrderBit(p1.z())); - EXPECT_EQ(HashS2Point()(p1), HashS2Point()(p2)); + EXPECT_EQ(S2PointHash()(p1), S2PointHash()(p2)); } // Given a point P, return the minimum level at which an edge of some S2Cell @@ -1023,4 +1021,4 @@ TEST(S2, OriginTest) { // colinear with S2::Origin() (except for small cells < 3 meters across). S2Point equator_point(S2::Origin().x(), S2::Origin().y(), 0); EXPECT_GE(GetMinExpensiveLevel(equator_point), 22); -} \ No newline at end of file +} diff --git a/src/s2cap.cc b/src/s2cap.cc index 911e33ec..4a07e772 100644 --- a/src/s2cap.cc +++ b/src/s2cap.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2cap.h" @@ -307,4 +308,4 @@ bool S2Cap::ApproxEquals(S2Cap const& other, double max_error) const { std::ostream& operator<<(std::ostream& os, S2Cap const& cap) { return os << "[Center=" << cap.center() << ", Radius=" << cap.GetRadius() << "]"; -} \ No newline at end of file +} diff --git a/src/s2cap.h b/src/s2cap.h index 179be09d..a62db18f 100644 --- a/src/s2cap.h +++ b/src/s2cap.h @@ -12,20 +12,21 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2CAP_H_ -#define UTIL_GEOMETRY_S2CAP_H_ +#ifndef S2_GEOMETRY_S2CAP_H_ +#define S2_GEOMETRY_S2CAP_H_ #include #include #include #include +#include "fpcontractoff.h" #include "s1angle.h" #include "s2.h" #include "s2region.h" -#include "util/math/vector3.h" // TODO(ericv): Remove class Decoder; class Encoder; @@ -249,4 +250,4 @@ inline S2Cap S2Cap::FromCenterArea(S2Point const& center, double area) { return S2Cap(center, area / (2 * M_PI)); } -#endif // UTIL_GEOMETRY_S2CAP_H_ \ No newline at end of file +#endif // S2_GEOMETRY_S2CAP_H_ diff --git a/src/s2cap_test.cc b/src/s2cap_test.cc index 6c4046b4..85645618 100644 --- a/src/s2cap_test.cc +++ b/src/s2cap_test.cc @@ -12,11 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2cap.h" -#include "gtest/gtest.h" +#include #include "r1interval.h" #include "s1interval.h" #include "s2.h" @@ -324,4 +325,4 @@ TEST(S2Cap, Union) { // Two non-overlapping hemisphere caps with antipodal centers. S2Cap hemi = S2Cap::FromCenterHeight(S2Point(0, 0, 1).Normalize(), 1); EXPECT_TRUE(hemi.Union(hemi.Complement()).is_full()); -} \ No newline at end of file +} diff --git a/src/s2cell.cc b/src/s2cell.cc index 601f7dc1..16425a9e 100644 --- a/src/s2cell.cc +++ b/src/s2cell.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2cell.h" @@ -125,6 +126,10 @@ double S2Cell::ApproxArea() const { } double S2Cell::ExactArea() const { + // There is a straightforward mathematical formula for the exact surface + // area (based on 4 calls to asin), but as the cell size gets small this + // formula has too much cancellation error. So instead we compute the area + // as the sum of two triangles (which is very accurate at all cell levels). S2Point v0 = GetVertex(0); S2Point v1 = GetVertex(1); S2Point v2 = GetVertex(2); @@ -304,8 +309,8 @@ bool S2Cell::VEdgeIsClosest(S2Point const& p, int u_end) const { inline static S1ChordAngle EdgeDistance(double dirIJ, double uv) { DCHECK_GE(dirIJ, 0); // Let P by the target point and let R be the closest point on the given - // edge AB. The desired distance XR can be expressed as PR^2 = PQ^2 + QR^2 - // where Q be the point P projected onto the plane through the great circle + // edge AB. The desired distance PR can be expressed as PR^2 = PQ^2 + QR^2 + // where Q is the point P projected onto the plane through the great circle // through AB. We can compute the distance PQ^2 perpendicular to the plane // from "dirIJ" (the dot product of the target point P with the edge // normal) and the squared length the edge normal (1 + uv**2). @@ -313,7 +318,7 @@ inline static S1ChordAngle EdgeDistance(double dirIJ, double uv) { // We can compute the distance QR as (1 - OQ) where O is the sphere origin, // and we can compute OQ^2 = 1 - PQ^2 using the Pythagorean theorem. - // (This calculation loses accuracy as the angle approaches Pi/2.) + // (This calculation loses accuracy as angle POQ approaches Pi/2.) double qr = 1 - sqrt(1 - pq2); return S1ChordAngle::FromLength2(pq2 + qr * qr); } @@ -321,6 +326,7 @@ inline static S1ChordAngle EdgeDistance(double dirIJ, double uv) { S1ChordAngle S2Cell::GetDistance(S2Point const& target_xyz) const { // All calculations are done in the (u,v,w) coordinates of this cell's face. S2Point target = S2::FaceXYZtoUVW(face_, target_xyz); + // Compute dot products with all four upward or rightward-facing edge // normals. "dirIJ" is the dot product for the edge corresponding to axis // I, endpoint J. For example, dir01 is the right edge of the S2Cell @@ -358,4 +364,4 @@ S1ChordAngle S2Cell::GetDistance(S2Point const& target_xyz) const { min(VertexChordDist2(target, 0, 1), VertexChordDist2(target, 1, 1))); return S1ChordAngle::FromLength2(chord_dist2); -} \ No newline at end of file +} diff --git a/src/s2cell.h b/src/s2cell.h index fe939d24..93c95614 100644 --- a/src/s2cell.h +++ b/src/s2cell.h @@ -12,13 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2CELL_H_ -#define UTIL_GEOMETRY_S2CELL_H_ +#ifndef S2_GEOMETRY_S2CELL_H_ +#define S2_GEOMETRY_S2CELL_H_ #include "base/integral_types.h" #include +#include "fpcontractoff.h" #include "r2rect.h" #include "s1chordangle.h" #include "s2.h" @@ -68,11 +70,11 @@ class S2Cell : public S2Region { explicit S2Cell(S2Point const& p) { Init(S2CellId::FromPoint(p)); } explicit S2Cell(S2LatLng const& ll) { Init(S2CellId::FromLatLng(ll)); } - inline S2CellId id() const { return id_; } - inline int face() const { return face_; } - inline int level() const { return level_; } - inline int orientation() const { return orientation_; } - inline bool is_leaf() const { return level_ == S2CellId::kMaxLevel; } + S2CellId id() const { return id_; } + int face() const { return face_; } + int level() const { return level_; } + int orientation() const { return orientation_; } + bool is_leaf() const { return level_ == S2CellId::kMaxLevel; } // These are equivalent to the S2CellId methods, but have a more efficient // implementation since the level has been precomputed. @@ -161,8 +163,8 @@ class S2Cell : public S2Region { // Return the latitude or longitude of the cell vertex given by (i,j), // where "i" and "j" are either 0 or 1. - inline double GetLatitude(int i, int j) const; - inline double GetLongitude(int i, int j) const; + double GetLatitude(int i, int j) const; + double GetLongitude(int i, int j) const; double VertexChordDist2(S2Point const& target, int i, int j) const; bool UEdgeIsClosest(S2Point const& target, int v_end) const; @@ -184,4 +186,4 @@ inline double S2Cell::GetSizeST() const { return S2CellId::GetSizeST(level()); } -#endif // UTIL_GEOMETRY_S2CELL_H_ \ No newline at end of file +#endif // S2_GEOMETRY_S2CELL_H_ diff --git a/src/s2cell_test.cc b/src/s2cell_test.cc index 984f537c..78f57f26 100644 --- a/src/s2cell_test.cc +++ b/src/s2cell_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2cell.h" @@ -27,7 +28,7 @@ #include #include "base/macros.h" #include "base/stringprintf.h" -#include "gtest/gtest.h" +#include #include "r2.h" #include "r2rect.h" #include "s1angle.h" @@ -489,4 +490,4 @@ TEST(S2Cell, GetDistance) { EXPECT_NEAR(expected.radians(), actual.radians(), 1e-15); } } -} \ No newline at end of file +} diff --git a/src/s2cellid.cc b/src/s2cellid.cc index 5af62a08..42eb62bc 100644 --- a/src/s2cellid.cc +++ b/src/s2cellid.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2cellid.h" @@ -147,7 +148,7 @@ S2CellId S2CellId::advance_wrap(int64 steps) const { if (steps > max_steps) steps -= step_wrap; } } - return S2CellId(id_ + (steps << step_shift)); + return S2CellId(id_ + (static_cast(steps) << step_shift)); } S2CellId S2CellId::maximum_tile(S2CellId const limit) const { @@ -184,25 +185,30 @@ int S2CellId::GetCommonAncestorLevel(S2CellId other) const { return max(60 - Bits::FindMSBSetNonZero64(bits), -1) >> 1; } +// Print the num_digits low order hex digits. +static string HexFormatString(uint64 val, size_t num_digits) { + string result(num_digits, ' '); + for (; num_digits--; val >>= 4) + result[num_digits] = "0123456789abcdef"[val & 0xF]; + return result; +} + string S2CellId::ToToken() const { - // Simple implementation: convert the id to hex and strip trailing zeros. + // Simple implementation: print the id in hex without trailing zeros. // Using hex has the advantage that the tokens are case-insensitive, all // characters are alphanumeric, no characters require any special escaping - // in Mustang queries, and it's easy to compare cell tokens against the - // feature ids of the corresponding features. + // in queries for most indexing systems, and it's easy to compare cell + // tokens against the feature ids of the corresponding features. // // Using base 64 would produce slightly shorter tokens, but for typical cell // sizes used during indexing (up to level 15 or so) the average savings // would be less than 2 bytes per cell which doesn't seem worth it. - char digits[17]; - FastHex64ToBuffer(id_, digits); - for (int len = 16; len > 0; --len) { - if (digits[len-1] != '0') { - return string(digits, len); - } - } - return "X"; // Invalid hex string. + // "0" with trailing 0s stripped is the empty string, which is not a + // reasonable token. Encode as "X". + if (id_ == 0) return "X"; + size_t const num_zero_digits = Bits::FindLSBSetNonZero64(id_) / 4; + return HexFormatString(id_ >> (4 * num_zero_digits), 16 - num_zero_digits); } S2CellId S2CellId::FromToken(const char* token, size_t length) { @@ -524,11 +530,13 @@ string S2CellId::ToString() const { } string out = StringPrintf("%d/", face()); for (int current_level = 1; current_level <= level(); ++current_level) { - out += SimpleItoa(child_position(current_level)); + // Avoid dependencies of SimpleItoA, and slowness of StringAppendF & + // std::to_string. + out += "0123"[child_position(current_level)]; } return out; } std::ostream& operator<<(std::ostream& os, S2CellId id) { return os << id.ToString(); -} \ No newline at end of file +} diff --git a/src/s2cellid.h b/src/s2cellid.h index 3fdacbc9..49763708 100644 --- a/src/s2cellid.h +++ b/src/s2cellid.h @@ -12,30 +12,28 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2CELLID_H_ -#define UTIL_GEOMETRY_S2CELLID_H_ +#ifndef S2_GEOMETRY_S2CELLID_H_ +#define S2_GEOMETRY_S2CELLID_H_ #include #include -#include -using __gnu_cxx::hash; -using __gnu_cxx::hash_map; -#include +#include // No longer needed #include #include +#include #include #include "base/integral_types.h" #include #include "base/port.h" // for HASH_NAMESPACE_DECLARATION_START -#include "base/type_traits.h" #include "util/bits/bits.h" +#include "fpcontractoff.h" #include "r2.h" #include "r2rect.h" #include "s2.h" -#include "util/hash/hash.h" class S2LatLng; @@ -81,15 +79,15 @@ class S2CellId { static int const kPosBits = 2 * kMaxLevel + 1; static int const kMaxSize = 1 << kMaxLevel; - inline explicit S2CellId(uint64 id) : id_(id) {} + explicit S2CellId(uint64 id) : id_(id) {} // The default constructor returns an invalid cell id. - inline S2CellId() : id_(0) {} - inline static S2CellId None() { return S2CellId(); } + S2CellId() : id_(0) {} + static S2CellId None() { return S2CellId(); } // Returns an invalid cell id guaranteed to be larger than any // valid cell id. Useful for creating indexes. - inline static S2CellId Sentinel() { return S2CellId(~uint64(0)); } + static S2CellId Sentinel() { return S2CellId(~uint64(0)); } // Return the cell corresponding to a given S2 cube face. static S2CellId FromFace(int face); @@ -119,10 +117,10 @@ class S2CellId { R2Point GetCenterST() const; // Return the edge length of this cell in (s,t)-space. - inline double GetSizeST() const; + double GetSizeST() const; // Return the edge length in (s,t)-space of cells at the given level. - inline static double GetSizeST(int level); + static double GetSizeST(int level); // Return the bounds of this cell in (s,t)-space. R2Rect GetBoundST() const; @@ -140,50 +138,50 @@ class S2CellId { // that although (si,ti) coordinates span the range [0,2**31] in general, // the cell center coordinates are always in the range [1,2**31-1] and // therefore can be represented using a signed 32-bit integer. - inline int GetCenterSiTi(int* psi, int* pti) const; + int GetCenterSiTi(int* psi, int* pti) const; // Return the S2LatLng corresponding to the center of the given cell. S2LatLng ToLatLng() const; // The 64-bit unique identifier for this cell. - inline uint64 id() const { return id_; } + uint64 id() const { return id_; } // Return true if id() represents a valid cell. - inline bool is_valid() const; + bool is_valid() const; // Which cube face this cell belongs to, in the range 0..5. - inline int face() const; + int face() const; // The position of the cell center along the Hilbert curve over this face, // in the range 0..(2**kPosBits-1). - inline uint64 pos() const; + uint64 pos() const; // Return the subdivision level of the cell (range 0..kMaxLevel). int level() const; // Return the edge length of this cell in (i,j)-space. - inline int GetSizeIJ() const; + int GetSizeIJ() const; // Like the above, but return the size of cells at the given level. - inline static int GetSizeIJ(int level); + static int GetSizeIJ(int level); // Return true if this is a leaf cell (more efficient than checking // whether level() == kMaxLevel). - inline bool is_leaf() const; + bool is_leaf() const; // Return true if this is a top-level face cell (more efficient than // checking whether level() == 0). - inline bool is_face() const; + bool is_face() const; // Return the child position (0..3) of this cell within its parent. // REQUIRES: level() >= 1. - inline int child_position() const; + int child_position() const; // Return the child position (0..3) of this cell's ancestor at the given // level within its parent. For example, child_position(1) returns the // position of this cell's level-1 ancestor within its top-level face cell. // REQUIRES: 1 <= level <= this->level(). - inline int child_position(int level) const; + int child_position(int level) const; // Methods that return the range of cell ids that are contained // within this cell (including itself). The range is *inclusive* @@ -199,23 +197,23 @@ class S2CellId { // this method would need to return (range_max().id() + 1) which is not // always a valid cell id. This also means that iterators would need to be // tested using "<" rather that the usual "!=". - inline S2CellId range_min() const; - inline S2CellId range_max() const; + S2CellId range_min() const; + S2CellId range_max() const; // Return true if the given cell is contained within this one. - inline bool contains(S2CellId other) const; + bool contains(S2CellId other) const; // Return true if the given cell intersects this one. - inline bool intersects(S2CellId other) const; + bool intersects(S2CellId other) const; // Return the cell at the previous level or at the given level (which must // be less than or equal to the current level). - inline S2CellId parent() const; - inline S2CellId parent(int level) const; + S2CellId parent() const; + S2CellId parent(int level) const; // Return the immediate child of this cell at the given traversal order // position (in the range 0 to 3). This cell must not be a leaf cell. - inline S2CellId child(int position) const; + S2CellId child(int position) const; // Iterator-style methods for traversing the immediate children of a cell or // all of the children at a given level (greater than or equal to the current @@ -229,16 +227,16 @@ class S2CellId { // The convention for advancing the iterator is "c = c.next()" rather // than "++c" to avoid possible confusion with incrementing the // underlying 64-bit cell id. - inline S2CellId child_begin() const; - inline S2CellId child_begin(int level) const; - inline S2CellId child_end() const; - inline S2CellId child_end(int level) const; + S2CellId child_begin() const; + S2CellId child_begin(int level) const; + S2CellId child_end() const; + S2CellId child_end(int level) const; // Return the next/previous cell at the same level along the Hilbert curve. // Works correctly when advancing from one face to the next, but // does *not* wrap around from the last face to the first or vice versa. - inline S2CellId next() const; - inline S2CellId prev() const; + S2CellId next() const; + S2CellId prev() const; // This method advances or retreats the indicated number of steps along the // Hilbert curve at the current level, and returns the new position. The @@ -249,8 +247,8 @@ class S2CellId { // to the first and vice versa. They should *not* be used for iteration in // conjunction with child_begin(), child_end(), Begin(), or End(). The // input must be a valid cell id. - inline S2CellId next_wrap() const; - inline S2CellId prev_wrap() const; + S2CellId next_wrap() const; + S2CellId prev_wrap() const; // This method advances or retreats the indicated number of steps along the // Hilbert curve at the current level, and returns the new position. The @@ -283,8 +281,8 @@ class S2CellId { // curve at a given level (across all 6 faces of the cube). Note that the // end value is exclusive (just like standard STL iterators), and is not a // valid cell id. - inline static S2CellId Begin(int level); - inline static S2CellId End(int level); + static S2CellId Begin(int level); + static S2CellId End(int level); // Methods to encode and decode cell ids to compact text strings suitable // for display or indexing. Cells at lower levels (i.e. larger cells) are @@ -348,7 +346,7 @@ class S2CellId { uint64 lsb() const { return id_ & -id_; } // Return the lowest-numbered bit that is on for cells at the given level. - inline static uint64 lsb_for_level(int level) { + static uint64 lsb_for_level(int level) { return uint64(1) << (2 * (kMaxLevel - level)); } @@ -356,6 +354,7 @@ class S2CellId { // the leaf cell with the given (i,j)-coordinates. static R2Rect IJLevelToBoundUV(int ij[2], int level); + private: // This is the offset required to wrap around from the beginning of the // Hilbert curve to the end or vice versa; see next_wrap() and prev_wrap(). @@ -369,10 +368,11 @@ class S2CellId { // Inline helper function that calls FromFaceIJ if "same_face" is true, // or FromFaceIJWrap if "same_face" is false. - inline static S2CellId FromFaceIJSame(int face, int i, int j, bool same_face); + static S2CellId FromFaceIJSame(int face, int i, int j, bool same_face); uint64 id_; -} PACKED; // Necessary so that structures containing S2CellId's can be PACKED. +} ATTRIBUTE_PACKED; // Necessary so that structures containing S2CellId's can + // be ATTRIBUTE_PACKED. inline bool operator==(S2CellId x, S2CellId y) { return x.id() == y.id(); @@ -448,9 +448,7 @@ inline uint64 S2CellId::pos() const { } inline int S2CellId::level() const { - // The "fast path" for leaf cells actually improves the benchmark results - // for all cell levels (as of gcc 4.4.3); the reasons are unclear. - if (is_leaf()) return kMaxLevel; + // A special case for leaf cells is not worthwhile. return kMaxLevel - (Bits::FindLSBSetNonZero64(id_) >> 1); } @@ -596,8 +594,9 @@ inline S2CellId S2CellId::End(int level) { std::ostream& operator<<(std::ostream& os, S2CellId id); -// HASH_NAMESPACE::hash specialization for S2CellId. See -// and the std::hash specialization below. +// Hash specialization for STL hash_* containers. (For std::unordered_* +// containers the hasher must be given explicitly; see S2CellIdHash below +// and go/enabling-unordered.) #ifndef SWIG HASH_NAMESPACE_DECLARATION_START @@ -610,11 +609,12 @@ template<> struct hash { HASH_NAMESPACE_DECLARATION_END #endif // SWIG -// Hasher for S2CellId. The values it produces may change from time to time -struct S2CellIdHasher { +// Hasher for S2CellId. +// Example use: std::unordered_map. +struct S2CellIdHash { size_t operator()(S2CellId id) const { - return util_hash::Hash(id.id()); + return std::hash()(id.id()); } }; -#endif // UTIL_GEOMETRY_S2CELLID_H_ \ No newline at end of file +#endif // S2_GEOMETRY_S2CELLID_H_ diff --git a/src/s2cellid_test.cc b/src/s2cellid_test.cc index bd822a9d..d488b162 100644 --- a/src/s2cellid_test.cc +++ b/src/s2cellid_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2cellid.h" @@ -19,23 +20,22 @@ #include #include #include -#include -using __gnu_cxx::hash; -using __gnu_cxx::hash_map; #include #include +#include #include #include #include #include "base/macros.h" -#include "gtest/gtest.h" +#include #include "s2.h" #include "s2latlng.h" #include "s2testing.h" using std::min; +using std::unordered_map; using std::vector; DEFINE_int32(iters, 20000000, @@ -53,22 +53,22 @@ static S2CellId GetCellId(double lat_degrees, double lng_degrees) { TEST(S2CellId, DefaultConstructor) { S2CellId id; - EXPECT_EQ(id.id(), 0); + EXPECT_EQ(0, id.id()); EXPECT_FALSE(id.is_valid()); } -TEST(S2CellId, S2CellIdHasher) { - EXPECT_EQ(S2CellIdHasher()(GetCellId(0, 90)), - S2CellIdHasher()(GetCellId(0, 90))); +TEST(S2CellId, S2CellIdHash) { + EXPECT_EQ(S2CellIdHash()(GetCellId(0, 90)), + S2CellIdHash()(GetCellId(0, 90))); } TEST(S2CellId, FaceDefinitions) { - EXPECT_EQ(GetCellId(0, 0).face(), 0); - EXPECT_EQ(GetCellId(0, 90).face(), 1); - EXPECT_EQ(GetCellId(90, 0).face(), 2); - EXPECT_EQ(GetCellId(0, 180).face(), 3); - EXPECT_EQ(GetCellId(0, -90).face(), 4); - EXPECT_EQ(GetCellId(-90, 0).face(), 5); + EXPECT_EQ(0, GetCellId(0, 0).face()); + EXPECT_EQ(1, GetCellId(0, 90).face()); + EXPECT_EQ(2, GetCellId(90, 0).face()); + EXPECT_EQ(3, GetCellId(0, 180).face()); + EXPECT_EQ(4, GetCellId(0, -90).face()); + EXPECT_EQ(5, GetCellId(-90, 0).face()); } TEST(S2CellId, FromFace) { @@ -81,26 +81,26 @@ TEST(S2CellId, ParentChildRelationships) { S2CellId id = S2CellId::FromFacePosLevel(3, 0x12345678, S2CellId::kMaxLevel - 4); EXPECT_TRUE(id.is_valid()); - EXPECT_EQ(id.face(), 3); - EXPECT_EQ(id.pos(), 0x12345700); - EXPECT_EQ(id.level(), S2CellId::kMaxLevel - 4); + EXPECT_EQ(3, id.face()); + EXPECT_EQ(0x12345700, id.pos()); + EXPECT_EQ(S2CellId::kMaxLevel - 4, id.level()); EXPECT_FALSE(id.is_leaf()); - EXPECT_EQ(id.child_begin(id.level() + 2).pos(), 0x12345610); - EXPECT_EQ(id.child_begin().pos(), 0x12345640); - EXPECT_EQ(id.parent().pos(), 0x12345400); - EXPECT_EQ(id.parent(id.level() - 2).pos(), 0x12345000); + EXPECT_EQ(0x12345610, id.child_begin(id.level() + 2).pos()); + EXPECT_EQ(0x12345640, id.child_begin().pos()); + EXPECT_EQ(0x12345400, id.parent().pos()); + EXPECT_EQ(0x12345000, id.parent(id.level() - 2).pos()); // Check ordering of children relative to parents. EXPECT_LT(id.child_begin(), id); EXPECT_GT(id.child_end(), id); - EXPECT_EQ(id.child_begin().next().next().next().next(), id.child_end()); - EXPECT_EQ(id.child_begin(S2CellId::kMaxLevel), id.range_min()); - EXPECT_EQ(id.child_end(S2CellId::kMaxLevel), id.range_max().next()); + EXPECT_EQ(id.child_end(), id.child_begin().next().next().next().next()); + EXPECT_EQ(id.range_min(), id.child_begin(S2CellId::kMaxLevel)); + EXPECT_EQ(id.range_max().next(), id.child_end(S2CellId::kMaxLevel)); // Check that cells are represented by the position of their center // along the Hilbert curve. - EXPECT_EQ(id.range_min().id() + id.range_max().id(), 2 * id.id()); + EXPECT_EQ(2 * id.id(), id.range_min().id() + id.range_max().id()); } TEST(S2CellId, CenterSiTi) { @@ -143,55 +143,55 @@ TEST(S2CellId, CenterSiTi) { TEST(S2CellId, Wrapping) { // Check wrapping from beginning of Hilbert curve to end and vice versa. - EXPECT_EQ(S2CellId::Begin(0).prev_wrap(), S2CellId::End(0).prev()); + EXPECT_EQ(S2CellId::End(0).prev(), S2CellId::Begin(0).prev_wrap()); - EXPECT_EQ(S2CellId::Begin(S2CellId::kMaxLevel).prev_wrap(), - S2CellId::FromFacePosLevel( + EXPECT_EQ(S2CellId::FromFacePosLevel( 5, ~static_cast(0) >> S2CellId::kFaceBits, - S2CellId::kMaxLevel)); - EXPECT_EQ(S2CellId::Begin(S2CellId::kMaxLevel).advance_wrap(-1), - S2CellId::FromFacePosLevel( + S2CellId::kMaxLevel), + S2CellId::Begin(S2CellId::kMaxLevel).prev_wrap()); + EXPECT_EQ(S2CellId::FromFacePosLevel( 5, ~static_cast(0) >> S2CellId::kFaceBits, - S2CellId::kMaxLevel)); + S2CellId::kMaxLevel), + S2CellId::Begin(S2CellId::kMaxLevel).advance_wrap(-1)); - EXPECT_EQ(S2CellId::End(4).prev().next_wrap(), S2CellId::Begin(4)); - EXPECT_EQ(S2CellId::End(4).advance(-1).advance_wrap(1), S2CellId::Begin(4)); + EXPECT_EQ(S2CellId::Begin(4), S2CellId::End(4).prev().next_wrap()); + EXPECT_EQ(S2CellId::Begin(4), S2CellId::End(4).advance(-1).advance_wrap(1)); - EXPECT_EQ(S2CellId::End(S2CellId::kMaxLevel).prev().next_wrap(), - S2CellId::FromFacePosLevel(0, 0, S2CellId::kMaxLevel)); - EXPECT_EQ(S2CellId::End(S2CellId::kMaxLevel).advance(-1).advance_wrap(1), - S2CellId::FromFacePosLevel(0, 0, S2CellId::kMaxLevel)); + EXPECT_EQ(S2CellId::FromFacePosLevel(0, 0, S2CellId::kMaxLevel), + S2CellId::End(S2CellId::kMaxLevel).prev().next_wrap()); + EXPECT_EQ(S2CellId::FromFacePosLevel(0, 0, S2CellId::kMaxLevel), + S2CellId::End(S2CellId::kMaxLevel).advance(-1).advance_wrap(1)); } TEST(S2CellId, Advance) { S2CellId id = S2CellId::FromFacePosLevel(3, 0x12345678, S2CellId::kMaxLevel - 4); // Check basic properties of advance(). - EXPECT_EQ(S2CellId::Begin(0).advance(7), S2CellId::End(0)); - EXPECT_EQ(S2CellId::Begin(0).advance(12), S2CellId::End(0)); - EXPECT_EQ(S2CellId::End(0).advance(-7), S2CellId::Begin(0)); - EXPECT_EQ(S2CellId::End(0).advance(-12000000), S2CellId::Begin(0)); + EXPECT_EQ(S2CellId::End(0), S2CellId::Begin(0).advance(7)); + EXPECT_EQ(S2CellId::End(0), S2CellId::Begin(0).advance(12)); + EXPECT_EQ(S2CellId::Begin(0), S2CellId::End(0).advance(-7)); + EXPECT_EQ(S2CellId::Begin(0), S2CellId::End(0).advance(-12000000)); int num_level_5_cells = 6 << (2 * 5); - EXPECT_EQ(S2CellId::Begin(5).advance(500), - S2CellId::End(5).advance(500 - num_level_5_cells)); - EXPECT_EQ(id.child_begin(S2CellId::kMaxLevel).advance(256), - id.next().child_begin(S2CellId::kMaxLevel)); - EXPECT_EQ(S2CellId::FromFacePosLevel(1, 0, S2CellId::kMaxLevel) - .advance(static_cast(4) << (2 * S2CellId::kMaxLevel)), - S2CellId::FromFacePosLevel(5, 0, S2CellId::kMaxLevel)); + EXPECT_EQ(S2CellId::End(5).advance(500 - num_level_5_cells), + S2CellId::Begin(5).advance(500)); + EXPECT_EQ(id.next().child_begin(S2CellId::kMaxLevel), + id.child_begin(S2CellId::kMaxLevel).advance(256)); + EXPECT_EQ(S2CellId::FromFacePosLevel(5, 0, S2CellId::kMaxLevel), + S2CellId::FromFacePosLevel(1, 0, S2CellId::kMaxLevel) + .advance(static_cast(4) << (2 * S2CellId::kMaxLevel))); // Check basic properties of advance_wrap(). - EXPECT_EQ(S2CellId::Begin(0).advance_wrap(7), S2CellId::FromFace(1)); - EXPECT_EQ(S2CellId::Begin(0).advance_wrap(12), S2CellId::Begin(0)); - EXPECT_EQ(S2CellId::FromFace(5).advance_wrap(-7), S2CellId::FromFace(4)); - EXPECT_EQ(S2CellId::Begin(0).advance_wrap(-12000000), S2CellId::Begin(0)); + EXPECT_EQ(S2CellId::FromFace(1), S2CellId::Begin(0).advance_wrap(7)); + EXPECT_EQ(S2CellId::Begin(0), S2CellId::Begin(0).advance_wrap(12)); + EXPECT_EQ(S2CellId::FromFace(4), S2CellId::FromFace(5).advance_wrap(-7)); + EXPECT_EQ(S2CellId::Begin(0), S2CellId::Begin(0).advance_wrap(-12000000)); EXPECT_EQ(S2CellId::Begin(5).advance_wrap(6644), S2CellId::Begin(5).advance_wrap(-11788)); - EXPECT_EQ(id.child_begin(S2CellId::kMaxLevel).advance_wrap(256), - id.next().child_begin(S2CellId::kMaxLevel)); - EXPECT_EQ(S2CellId::FromFacePosLevel(5, 0, S2CellId::kMaxLevel) - .advance_wrap(static_cast(2) << (2 * S2CellId::kMaxLevel)), - S2CellId::FromFacePosLevel(1, 0, S2CellId::kMaxLevel)); + EXPECT_EQ(id.next().child_begin(S2CellId::kMaxLevel), + id.child_begin(S2CellId::kMaxLevel).advance_wrap(256)); + EXPECT_EQ(S2CellId::FromFacePosLevel(1, 0, S2CellId::kMaxLevel), + S2CellId::FromFacePosLevel(5, 0, S2CellId::kMaxLevel) + .advance_wrap(static_cast(2) << (2 * S2CellId::kMaxLevel))); } TEST(S2CellId, MaximumTile) { @@ -262,9 +262,9 @@ TEST(S2CellId, Inverses) { for (int i = 0; i < 200000; ++i) { S2CellId id = S2Testing::GetRandomCellId(S2CellId::kMaxLevel); EXPECT_TRUE(id.is_leaf()); - EXPECT_EQ(id.level(), S2CellId::kMaxLevel); + EXPECT_EQ(S2CellId::kMaxLevel, id.level()); S2LatLng center = id.ToLatLng(); - EXPECT_EQ(S2CellId::FromLatLng(center).id(), id.id()); + EXPECT_EQ(id.id(), S2CellId::FromLatLng(center).id()); } } @@ -274,58 +274,72 @@ TEST(S2CellId, Tokens) { S2CellId id = S2Testing::GetRandomCellId(); string token = id.ToToken(); EXPECT_LE(token.size(), 16); - EXPECT_EQ(S2CellId::FromToken(token), id); - EXPECT_EQ(S2CellId::FromToken(token.data(), token.size()), id); + EXPECT_EQ(id, S2CellId::FromToken(token)); + EXPECT_EQ(id, S2CellId::FromToken(token.data(), token.size())); } - // Check that invalid cell ids can be encoded. + // Check that invalid cell ids can be encoded, and round-trip is + // the identity operation. string token = S2CellId::None().ToToken(); - EXPECT_EQ(S2CellId::FromToken(token), S2CellId::None()); - EXPECT_EQ(S2CellId::FromToken(token.data(), token.size()), S2CellId::None()); + EXPECT_EQ(S2CellId::None(), S2CellId::FromToken(token)); + EXPECT_EQ(S2CellId::None(), S2CellId::FromToken(token.data(), token.size())); + + // Sentinel is invalid. + token = S2CellId::Sentinel().ToToken(); + EXPECT_EQ(S2CellId::FromToken(token), S2CellId::Sentinel()); + EXPECT_EQ(S2CellId::FromToken(token.data(), token.size()), + S2CellId::Sentinel()); + + // Check an invalid face. + token = S2CellId::FromFace(7).ToToken(); + EXPECT_EQ(S2CellId::FromToken(token), S2CellId::FromFace(7)); + EXPECT_EQ(S2CellId::FromToken(token.data(), token.size()), + S2CellId::FromFace(7)); // Check that supplying tokens with non-alphanumeric characters // returns S2CellId::None(). - EXPECT_EQ(S2CellId::FromToken("876b e99"), S2CellId::None()); - EXPECT_EQ(S2CellId::FromToken("876bee99\n"), S2CellId::None()); - EXPECT_EQ(S2CellId::FromToken("876[ee99"), S2CellId::None()); - EXPECT_EQ(S2CellId::FromToken(" 876bee99"), S2CellId::None()); + EXPECT_EQ(S2CellId::None(), S2CellId::FromToken("876b e99")); + EXPECT_EQ(S2CellId::None(), S2CellId::FromToken("876bee99\n")); + EXPECT_EQ(S2CellId::None(), S2CellId::FromToken("876[ee99")); + EXPECT_EQ(S2CellId::None(), S2CellId::FromToken(" 876bee99")); } static const int kMaxExpandLevel = 3; -static void ExpandCell(S2CellId parent, vector* cells, - hash_map* parent_map) { +static void ExpandCell( + S2CellId parent, vector* cells, + unordered_map* parent_map) { cells->push_back(parent); if (parent.level() == kMaxExpandLevel) return; int i, j, orientation; int face = parent.ToFaceIJOrientation(&i, &j, &orientation); - EXPECT_EQ(face, parent.face()); + EXPECT_EQ(parent.face(), face); S2CellId child = parent.child_begin(); for (int pos = 0; child != parent.child_end(); child = child.next(), ++pos) { (*parent_map)[child] = parent; // Do some basic checks on the children. - EXPECT_EQ(parent.child(pos), child); + EXPECT_EQ(child, parent.child(pos)); EXPECT_EQ(pos, child.child_position()); // Test child_position(level) on all the child's ancestors. for (S2CellId ancestor = child; ancestor.level() >= 1; ancestor = (*parent_map)[ancestor]) { - EXPECT_EQ(ancestor.child_position(), - child.child_position(ancestor.level())); + EXPECT_EQ(child.child_position(ancestor.level()), + ancestor.child_position()); } EXPECT_EQ(pos, child.child_position(child.level())); - EXPECT_EQ(child.level(), parent.level() + 1); + EXPECT_EQ(parent.level() + 1, child.level()); EXPECT_FALSE(child.is_leaf()); int child_orientation; - EXPECT_EQ(child.ToFaceIJOrientation(&i, &j, &child_orientation), face); - EXPECT_EQ(child_orientation, orientation ^ S2::kPosToOrientation[pos]); + EXPECT_EQ(face, child.ToFaceIJOrientation(&i, &j, &child_orientation)); + EXPECT_EQ(orientation ^ S2::kPosToOrientation[pos], child_orientation); ExpandCell(child, cells, parent_map); } } TEST(S2CellId, Containment) { // Test contains() and intersects(). - hash_map parent_map; + unordered_map parent_map; vector cells; for (int face = 0; face < 6; ++face) { ExpandCell(S2CellId::FromFace(face), &cells, &parent_map); @@ -339,9 +353,10 @@ TEST(S2CellId, Containment) { break; } } - EXPECT_EQ(cells[i].contains(cells[j]), contained); - EXPECT_EQ(cells[j] >= cells[i].range_min() && - cells[j] <= cells[i].range_max(), contained); + EXPECT_EQ(contained, cells[i].contains(cells[j])); + EXPECT_EQ(contained, + cells[j] >= cells[i].range_min() && + cells[j] <= cells[i].range_max()); EXPECT_EQ(cells[i].intersects(cells[j]), cells[i].contains(cells[j]) || cells[j].contains(cells[i])); } @@ -360,8 +375,8 @@ TEST(S2CellId, Continuity) { S2CellId id = S2CellId::Begin(kMaxWalkLevel); for (; id != end; id = id.next()) { EXPECT_LE(id.ToPointRaw().Angle(id.next_wrap().ToPointRaw()), max_dist); - EXPECT_EQ(id.advance_wrap(1), id.next_wrap()); - EXPECT_EQ(id.next_wrap().advance_wrap(-1), id); + EXPECT_EQ(id.next_wrap(), id.advance_wrap(1)); + EXPECT_EQ(id, id.next_wrap().advance_wrap(-1)); // Check that the ToPointRaw() returns the center of each cell // in (s,t) coordinates. @@ -419,7 +434,7 @@ TEST(S2CellId, Neighbors) { S2CellId::FromFace(1).GetEdgeNeighbors(face_nbrs); for (int i = 0; i < 4; ++i) { EXPECT_TRUE(face_nbrs[i].is_face()); - EXPECT_EQ(face_nbrs[i].face(), out_faces[i]); + EXPECT_EQ(out_faces[i], face_nbrs[i].face()); } // Check the edge neighbors of the corner cells at all levels. This case is @@ -443,9 +458,10 @@ TEST(S2CellId, Neighbors) { S2CellId::FromPoint(S2Point(0, 0, 1)).AppendVertexNeighbors(5, &nbrs); std::sort(nbrs.begin(), nbrs.end()); for (int i = 0; i < 4; ++i) { - EXPECT_EQ(nbrs[i], S2CellId::FromFaceIJ( + EXPECT_EQ(S2CellId::FromFaceIJ( 2, (1 << 29) - (i < 2), (1 << 29) - (i == 0 || i == 3)) - .parent(5)); + .parent(5), + nbrs[i]); } nbrs.clear(); @@ -453,10 +469,10 @@ TEST(S2CellId, Neighbors) { S2CellId id = S2CellId::FromFacePosLevel(0, 0, S2CellId::kMaxLevel); id.AppendVertexNeighbors(0, &nbrs); std::sort(nbrs.begin(), nbrs.end()); - EXPECT_EQ(nbrs.size(), 3); - EXPECT_EQ(nbrs[0], S2CellId::FromFace(0)); - EXPECT_EQ(nbrs[1], S2CellId::FromFace(4)); - EXPECT_EQ(nbrs[2], S2CellId::FromFace(5)); + ASSERT_EQ(3, nbrs.size()); + EXPECT_EQ(S2CellId::FromFace(0), nbrs[0]); + EXPECT_EQ(S2CellId::FromFace(4), nbrs[1]); + EXPECT_EQ(S2CellId::FromFace(5), nbrs[2]); // Check that AppendAllNeighbors produces results that are consistent // with AppendVertexNeighbors for a bunch of random cells. @@ -560,3 +576,4 @@ TEST(S2CellId, FromPointBenchmark) { printf("\tFromPoint: %8.3f usecs\n", 1e6 * test_time / FLAGS_iters); EXPECT_NE(isum, 0); // Don't let the loop get optimized away. } + diff --git a/src/s2cellunion.cc b/src/s2cellunion.cc index feefff40..8025177b 100644 --- a/src/s2cellunion.cc +++ b/src/s2cellunion.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2cellunion.h" @@ -27,22 +28,12 @@ #include "s2cell.h" #include "s2cellid.h" #include "s2latlngrect.h" +#include "util/gtl/algorithm.h" using std::max; using std::min; using std::vector; -// Returns true if the vector of cell_ids is sorted. Used only in -// DCHECKs. -extern bool IsSorted(vector const& cell_ids) { - for (int i = 0; i + 1 < cell_ids.size(); ++i) { - if (cell_ids[i + 1] < cell_ids[i]) { - return false; - } - } - return true; -} - void S2CellUnion::Init(vector const& cell_ids) { InitRaw(cell_ids); Normalize(); @@ -93,33 +84,33 @@ S2CellUnion* S2CellUnion::Clone() const { } bool S2CellUnion::Normalize() { - // Optimize the representation by looking for cases where all subcells - // of a parent cell are present. + return Normalize(&cell_ids_); +} - vector output; - output.reserve(cell_ids_.size()); - std::sort(cell_ids_.begin(), cell_ids_.end()); +/*static*/ bool S2CellUnion::Normalize(vector* ids) { + // Optimize the representation by discarding cells contained by other cells, + // and looking for cases where all subcells of a parent cell are present. - for (int i = 0; i < num_cells(); ++i) { - S2CellId id = cell_id(i); + std::sort(ids->begin(), ids->end()); + int out = 0; + for (int i = 0; i < ids->size(); ++i) { + S2CellId id = (*ids)[i]; // Check whether this cell is contained by the previous cell. - if (!output.empty() && output.back().contains(id)) continue; + if (out > 0 && (*ids)[out-1].contains(id)) continue; // Discard any previous cells contained by this cell. - while (!output.empty() && id.contains(output.back())) { - output.pop_back(); - } + while (out > 0 && id.contains((*ids)[out-1])) --out; // Check whether the last 3 elements of "output" plus "id" can be // collapsed into a single parent cell. - while (output.size() >= 3) { + while (out >= 3) { // A necessary (but not sufficient) condition is that the XOR of the // four cells must be zero. This is also very fast to test. - if ((output.end()[-3].id() ^ output.end()[-2].id() ^ output.back().id()) - != id.id()) + if (((*ids)[out-3].id() ^ (*ids)[out-2].id() ^ (*ids)[out-1].id()) != + id.id()) { break; - + } // Now we do a slightly more expensive but exact test. First, compute a // mask that blocks out the two bits that encode the child position of // "id" with respect to its parent, then check that the other three @@ -127,20 +118,20 @@ bool S2CellUnion::Normalize() { uint64 mask = id.lsb() << 1; mask = ~(mask + (mask << 1)); uint64 id_masked = (id.id() & mask); - if ((output.end()[-3].id() & mask) != id_masked || - (output.end()[-2].id() & mask) != id_masked || - (output.end()[-1].id() & mask) != id_masked || + if (((*ids)[out-3].id() & mask) != id_masked || + ((*ids)[out-2].id() & mask) != id_masked || + ((*ids)[out-1].id() & mask) != id_masked || id.is_face()) break; // Replace four children by their parent cell. - output.erase(output.end() - 3, output.end()); id = id.parent(); + out -= 3; } - output.push_back(id); + (*ids)[out++] = id; } - if (output.size() < num_cells()) { - InitRawSwap(&output); + if (out < ids->size()) { + ids->resize(out); return true; } return false; @@ -237,8 +228,8 @@ bool S2CellUnion::Intersects(S2CellId id) const { } bool S2CellUnion::Contains(S2CellUnion const* y) const { - // TODO: A divide-and-conquer or alternating-skip-search approach may be - // sigificantly faster in both the average and worst case. + // TODO(ericv): A divide-and-conquer or alternating-skip-search + // approach may be sigificantly faster in both the average and worst case. for (int i = 0; i < y->num_cells(); ++i) { if (!Contains(y->cell_id(i))) return false; @@ -247,8 +238,8 @@ bool S2CellUnion::Contains(S2CellUnion const* y) const { } bool S2CellUnion::Intersects(S2CellUnion const* y) const { - // TODO: A divide-and-conquer or alternating-skip-search approach may be - // sigificantly faster in both the average and worst case. + // TODO(ericv): A divide-and-conquer or alternating-skip-search + // approach may be sigificantly faster in both the average and worst case. for (int i = 0; i < y->num_cells(); ++i) { if (Intersects(y->cell_id(i))) return true; @@ -280,49 +271,58 @@ void S2CellUnion::GetIntersection(S2CellUnion const* x, S2CellId id) { } void S2CellUnion::GetIntersection(S2CellUnion const* x, S2CellUnion const* y) { - DCHECK_NE(this, x); - DCHECK_NE(this, y); + GetIntersection(x->cell_ids_, y->cell_ids_, &cell_ids_); + // Since both inputs are normalized, there should not be any cells that + // can be merged. + DCHECK(!Normalize()); +} + +/*static*/ void S2CellUnion::GetIntersection(vector const& x, + vector const& y, + vector* out) { + DCHECK_NE(out, &x); + DCHECK_NE(out, &y); + DCHECK(util::gtl::is_sorted(x.begin(), x.end())); + DCHECK(util::gtl::is_sorted(y.begin(), y.end())); // This is a fairly efficient calculation that uses binary search to skip // over sections of both input vectors. It takes constant time if all the // cells of "x" come before or after all the cells of "y" in S2CellId order. - cell_ids_.clear(); - vector::const_iterator i = x->cell_ids_.begin(); - vector::const_iterator j = y->cell_ids_.begin(); - while (i != x->cell_ids_.end() && j != y->cell_ids_.end()) { + out->clear(); + vector::const_iterator i = x.begin(); + vector::const_iterator j = y.begin(); + while (i != x.end() && j != y.end()) { S2CellId imin = i->range_min(); S2CellId jmin = j->range_min(); if (imin > jmin) { // Either j->contains(*i) or the two cells are disjoint. if (*i <= j->range_max()) { - cell_ids_.push_back(*i++); + out->push_back(*i++); } else { // Advance "j" to the first cell possibly contained by *i. - j = std::lower_bound(j + 1, y->cell_ids_.end(), imin); + j = std::lower_bound(j + 1, y.end(), imin); // The previous cell *(j-1) may now contain *i. if (*i <= (j - 1)->range_max()) --j; } } else if (jmin > imin) { // Identical to the code above with "i" and "j" reversed. if (*j <= i->range_max()) { - cell_ids_.push_back(*j++); + out->push_back(*j++); } else { - i = std::lower_bound(i + 1, x->cell_ids_.end(), jmin); + i = std::lower_bound(i + 1, x.end(), jmin); if (*j <= (i - 1)->range_max()) --i; } } else { // "i" and "j" have the same range_min(), so one contains the other. if (*i < *j) - cell_ids_.push_back(*i++); + out->push_back(*i++); else - cell_ids_.push_back(*j++); + out->push_back(*j++); } } - // The output is generated in sorted order, and there should not be any - // cells that can be merged (provided that both inputs were normalized). - DCHECK(IsSorted(cell_ids_)); - DCHECK(!Normalize()); + // The output is generated in sorted order. + DCHECK(util::gtl::is_sorted(out->begin(), out->end())); } static void GetDifferenceInternal(S2CellId cell, @@ -346,8 +346,8 @@ static void GetDifferenceInternal(S2CellId cell, void S2CellUnion::GetDifference(S2CellUnion const* x, S2CellUnion const* y) { DCHECK_NE(this, x); DCHECK_NE(this, y); - // TODO: this is approximately O(N*log(N)), but could probably use similar - // techniques as GetIntersection() to be more efficient. + // TODO(ericv): this is approximately O(N*log(N)), but could probably + // use similar techniques as GetIntersection() to be more efficient. cell_ids_.clear(); for (int i = 0; i < x->num_cells(); ++i) { @@ -355,7 +355,7 @@ void S2CellUnion::GetDifference(S2CellUnion const* x, S2CellUnion const* y) { } // The output is generated in sorted order, and there should not be any // cells that can be merged (provided that both inputs were normalized). - DCHECK(IsSorted(cell_ids_)); + DCHECK(util::gtl::is_sorted(cell_ids_.begin(), cell_ids_.end())); DCHECK(!Normalize()); } @@ -408,7 +408,7 @@ void S2CellUnion::InitFromBeginEnd(S2CellId begin, S2CellId end) { cell_ids_.push_back(id); } // The output is already normalized. - DCHECK(IsSorted(cell_ids_)); + DCHECK(util::gtl::is_sorted(cell_ids_.begin(), cell_ids_.end())); DCHECK(!Normalize()); } @@ -446,6 +446,10 @@ bool operator==(S2CellUnion const& x, S2CellUnion const& y) { return x.cell_ids() == y.cell_ids(); } +bool operator!=(S2CellUnion const& x, S2CellUnion const& y) { + return x.cell_ids() != y.cell_ids(); +} + bool S2CellUnion::Contains(S2Cell const& cell) const { return Contains(cell.id()); } @@ -456,4 +460,4 @@ bool S2CellUnion::MayIntersect(S2Cell const& cell) const { bool S2CellUnion::Contains(S2Point const& p) const { return Contains(S2CellId::FromPoint(p)); -} \ No newline at end of file +} diff --git a/src/s2cellunion.h b/src/s2cellunion.h index 0f87430e..4f8029a1 100644 --- a/src/s2cellunion.h +++ b/src/s2cellunion.h @@ -12,16 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2CELLUNION_H_ -#define UTIL_GEOMETRY_S2CELLUNION_H_ +#ifndef S2_GEOMETRY_S2CELLUNION_H_ +#define S2_GEOMETRY_S2CELLUNION_H_ #include #include "base/integral_types.h" #include #include "base/macros.h" +#include "fpcontractoff.h" #include "s2.h" #include "s2cellid.h" #include "s2region.h" @@ -80,8 +82,8 @@ class S2CellUnion : public S2Region { // possible, and sorting all the cell ids in increasing order. Returns true // if the number of cells was reduced. // - // This method *must* be called before doing any calculations on the cell - // union, such as Intersects() or Contains(). + // If InitRaw() was used then this method *must* be called before doing any + // calculations on the cell union, such as Intersects() or Contains(). bool Normalize(); // Replaces "output" with an expanded version of the cell union where any @@ -222,6 +224,32 @@ class S2CellUnion : public S2Region { // This is a fast operation (logarithmic in the size of the cell union). bool Contains(S2Point const& p) const; + //////////////////////////////////////////////////////////////////////// + // Static methods intended for high-performance clients that prefer to + // manage their own storage. + + // Like Normalize(), but works directly with a vector of S2CellIds. + // Equivalent to the following: + // S2CellUnion cell_union; + // cell_union.Init(*cell_ids); + // cell_union.Detach(cell_ids); + static bool Normalize(std::vector* cell_ids); + + // Like GetIntersection(), but works directly with vectors of S2CellIds, + // Equivalent to the following: + // S2CellUnion x_union, y_union, result_union; + // x_union.Init(x); + // y_union.Init(y); + // result_union.GetIntersection(&x_union, &y_union); + // result_union.Detach(out); + // except that this method has slightly more relaxed normalization + // requirements: the input vectors may contain groups of 4 child cells that + // all have the same parent. (In a normalized S2CellUnion, such groups are + // always replaced by the parent cell.) + static void GetIntersection(std::vector const& x, + std::vector const& y, + std::vector* out); + private: std::vector cell_ids_; @@ -231,4 +259,7 @@ class S2CellUnion : public S2Region { // Return true if two cell unions are identical. bool operator==(S2CellUnion const& x, S2CellUnion const& y); -#endif // UTIL_GEOMETRY_S2CELLUNION_H_ \ No newline at end of file +// Return true if two cell unions are different. +bool operator!=(S2CellUnion const& x, S2CellUnion const& y); + +#endif // S2_GEOMETRY_S2CELLUNION_H_ diff --git a/src/s2cellunion_test.cc b/src/s2cellunion_test.cc index 0bb298f8..bdc1885c 100644 --- a/src/s2cellunion_test.cc +++ b/src/s2cellunion_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2cellunion.h" @@ -24,7 +25,7 @@ #include "base/integral_types.h" #include #include "base/stringprintf.h" -#include "gtest/gtest.h" +#include #include "s1angle.h" #include "s2cap.h" #include "s2cell.h" @@ -260,7 +261,6 @@ TEST(S2CellUnion, Normalize) { EXPECT_EQ(contains, cellunion.Contains(test[j])); EXPECT_EQ(intersects, cellunion.Intersects(test[j])); } - } printf("avg in %.2f, avg out %.2f\n", in_sum / kIters, out_sum / kIters); } @@ -505,3 +505,4 @@ TEST(S2CellUnion, LeafCellsCovered) { (2ULL << 56) + (1ULL << 58) + (1ULL << 60); EXPECT_EQ(expected, cell_union.LeafCellsCovered()); } + diff --git a/src/s2closestedgequery.cc b/src/s2closestedgequery.cc index e8c0e040..3b8f4992 100644 --- a/src/s2closestedgequery.cc +++ b/src/s2closestedgequery.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2closestedgequery.h" @@ -22,6 +23,10 @@ #include "s2cellid.h" #include "s2edgeutil.h" +S2ClosestEdgeQuery::~S2ClosestEdgeQuery() { + // Prevent inline destructor bloat by providing a definition. +} + void S2ClosestEdgeQuery::Init(S2ShapeIndex const& index) { // This constant was tuned using the benchmarks. static int const kMaxBruteForceEdges = 180; @@ -39,23 +44,41 @@ void S2ClosestEdgeQuery::UseBruteForce(bool use_brute_force) { // Find the range of S2Cells spanned by the index and choose a level such // that the entire index can be covered with just a few cells. These are the - // "top level" cells. There are at most 4 top level cells unless the index - // spans more than one face, in which case up to 6 cells may be needed. + // "top-level" cells. There are two cases: + // + // - If the index spans more than one face, then there is one top-level cell + // per spanned face, just big enough to cover the index cells on that face. + // + // - If the index spans only one face, then we find the smallest cell "C" + // that covers the index cells on that face (just like the case above). + // Then for each of the 4 children of "C", if the child contains any index + // cells then we create a top-level cell that is big enough to just fit + // those index cells (i.e., shrinking the child as much as possible to fit + // its contents). This essentially replicates what would happen if we + // started with "C" as the top-level cell, since "C" would immediately be + // split, except that we take the time to prune the children further since + // this will save work on every subsequent query. top_cells_.clear(); iter_.Init(*index_); - if (iter_.Done()) return; + if (iter_.Done()) return; // Empty index. + S2ShapeIndex::Iterator next = iter_, last = iter_; last.Finish(); last.Prev(); if (next.id() != last.id()) { + // The index has at least two cells. Choose a level such that the entire + // index can be spanned with at most 6 cells (if the index spans multiple + // faces) or 4 cells (it the index spans a single face). int level = next.id().GetCommonAncestorLevel(last.id()) + 1; - // For each top-level cell, we find the range of index cells within it and - // shrink the top-level cell if necessary so that it just covers them. - // "next" is always the next index cell that has not been covered yet. + + // Visit each potential top-level cell except the last (handled below). S2CellId last_id = last.id().parent(level); for (S2CellId id = next.id().parent(level); id != last_id; id = id.next()) { + // Skip any top-level cells that don't contain any index cells. if (id.range_max() < next.id()) continue; - // Compute the range of index cells within the top-level cell "id". + + // Find the range of index cells contained by this top-level cell and + // then shrink the cell if necessary so that it just covers them. S2ShapeIndex::Iterator cell_first = next; next.Seek(id.range_max().next()); S2ShapeIndex::Iterator cell_last = next; @@ -120,7 +143,7 @@ void S2ClosestEdgeQuery::FindClosestEdge(S2Point const& target, if (use_brute_force_) { return FindClosestEdgeBruteForce(target); } - queue_.clear(); + queue_.mutable_rep()->clear(); for (int i = 0; i < top_cells_.size(); ++i) { EnqueueCell(top_cells_[i].first, top_cells_[i].second); } @@ -231,7 +254,7 @@ void S2ClosestEdgeQuery::EnqueueCell(S2CellId id, // Otherwise compute the minimum distance to any point in the cell and add // it to the priority queue. S2Cell cell(id); - S1ChordAngle distance(cell.GetDistance(target_)); // XXX FIX XXX + S1ChordAngle distance(cell.GetDistance(target_)); if (distance >= goal_distance_) return; queue_.push(QueueEntry(distance, id, index_cell)); -} \ No newline at end of file +} diff --git a/src/s2closestedgequery.h b/src/s2closestedgequery.h index 92d006c9..5676f201 100644 --- a/src/s2closestedgequery.h +++ b/src/s2closestedgequery.h @@ -12,14 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2CLOSESTEDGEQUERY_H_ -#define UTIL_GEOMETRY_S2CLOSESTEDGEQUERY_H_ +#ifndef S2_GEOMETRY_S2CLOSESTEDGEQUERY_H_ +#define S2_GEOMETRY_S2CLOSESTEDGEQUERY_H_ #include +#include "priority_queue_sequence.h" #include "s1angle.h" #include "s1chordangle.h" +#include "fpcontractoff.h" #include "s2.h" #include "s2cellid.h" #include "s2shapeindex.h" @@ -34,6 +37,7 @@ class S2ClosestEdgeQuery { // Default constructor; requires Init() to be called. S2ClosestEdgeQuery() {} + ~S2ClosestEdgeQuery(); // REQUIRES: "index" is not modified after this method is called. void Init(S2ShapeIndex const& index); @@ -153,20 +157,9 @@ class S2ClosestEdgeQuery { // A temporary declared here to avoid initializing iterators multiple times. S2ShapeIndex::Iterator iter_; - // We define our own priority queue because the standard STL one does not - // support clearing all the remaining queue entries. - class CellQueue : public util::gtl::InlinedVector { - public: - QueueEntry const& top() const { return front(); } - void pop() { - std::pop_heap(begin(), end()); - pop_back(); - } - void push(QueueEntry const& entry) { - push_back(entry); - std::push_heap(begin(), end()); - } - }; + // We use a priority queue that exposes the underlying vector because the + // standard STL one does not support clearing the remaining queue entries. + typedef priority_queue_sequence CellQueue; CellQueue queue_; }; @@ -186,4 +179,4 @@ inline S2Point S2ClosestEdgeQuery::Project(S2Point const& target) { return ApproxProject(target, S1Angle::Zero()); } -#endif // UTIL_GEOMETRY_S2CLOSESTEDGEQUERY_H_ \ No newline at end of file +#endif // S2_GEOMETRY_S2CLOSESTEDGEQUERY_H_ diff --git a/src/s2closestedgequery_test.cc b/src/s2closestedgequery_test.cc index f2ba6dd3..a50beb96 100644 --- a/src/s2closestedgequery_test.cc +++ b/src/s2closestedgequery_test.cc @@ -12,16 +12,21 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2closestedgequery.h" -#include "gtest/gtest.h" +#include + +#include #include "s1angle.h" #include "s2cap.h" #include "s2loop.h" #include "s2testing.h" +using std::unique_ptr; + class S2ClosestEdgeQueryTest : public ::testing::Test { protected: S2ShapeIndex index_; @@ -49,9 +54,9 @@ TEST_F(S2ClosestEdgeQueryTest, RegularLoop) { static S1Angle const kRadius = S2Testing::KmToAngle(10); for (int i_loop = 0; i_loop < kLoopIters; ++i_loop) { S2Point center = S2Testing::RandomPoint(); - scoped_ptr loop(S2Testing::MakeRegularLoop(center, kRadius, + unique_ptr loop(S2Testing::MakeRegularLoop(center, kRadius, kNumVertices)); - index_.Insert(new S2Loop::Shape(loop.get())); + index_.Add(new S2Loop::Shape(loop.get())); // Choose query points from a region whose area is approximately 4 times // larger than the loop, i.e. such that about 1/4 of the query points will // be inside the loop. @@ -78,3 +83,4 @@ TEST_F(S2ClosestEdgeQueryTest, NoEdges) { EXPECT_EQ(-1, query.shape_id()); EXPECT_EQ(-1, query.edge_id()); } + diff --git a/src/s2earth.h b/src/s2earth.h new file mode 100644 index 00000000..ab01c2f5 --- /dev/null +++ b/src/s2earth.h @@ -0,0 +1,225 @@ +// Copyright 2005 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Author: ericv@google.com (Eric Veach) +// +// The earth modeled as a sphere. There are lots of convenience +// functions so that it doesn't take 2 lines of code just to do +// a single conversion. + +#ifndef S2_GEOMETRY_S2EARTH_H_ +#define S2_GEOMETRY_S2EARTH_H_ + +#include +#include + +#include "s1angle.h" +#include "s2.h" +#include "s2latlng.h" +#include "util/math/vector3.h" +#include "util/units/length-units.h" + +class S2Earth { + public: + inline static S1Angle ToAngle(util::units::Meters const& distance); + inline static util::units::Meters ToDistance(S1Angle const& angle); + // Functions that convert between angles and distances on the Earth's + // surface. This is possible only because the Earth is modeled as a sphere; + // otherwise a given angle would correspond to a range of distances + // depending on where the corresponding line segment was located. + // + // Note that you will lose precision if you use the ToDistance() method, + // since Meters is a single-precision type. If you need more precision, + // use one of the direct conversion methods below. + + inline static double ToRadians(util::units::Meters const& distance); + inline static double ToMeters(S1Angle const& angle); + inline static double ToKm(S1Angle const& angle); + inline static double KmToRadians(double km); + inline static double RadiansToKm(double radians); + inline static double MetersToRadians(double meters); + inline static double RadiansToMeters(double radians); + + inline static double ToLongitudeRadians(util::units::Meters const& distance, + double latitude_radians); + // Convenience function for the frequent case where you need to call + // ToRadians in order to convert an east-west distance on the globe to + // radians. The output is a function of how close to the poles you are + // (i.e. at the bulge at the equator, one unit of longitude represents a + // much farther distance). The function will never return more than 2*PI + // radians, even if you're trying to go 100 million miles west at the north + // pole. + + // Convenience functions. These methods also return a double-precision + // result, unlike the generic ToDistance() method. + + inline static util::units::Meters GetDistance(S2Point const& a, + S2Point const& b); + inline static util::units::Meters GetDistance(S2LatLng const& a, + S2LatLng const& b); + // Return the distance between two points. Example: + // double miles = Miles(geostore::S2Earth::GetDistance(a, b)).value(); + // + // Note that these methods only have single-precision accuracy, since + // Meters is a single-precision type. If you ned more precision, use one + // of the methods below. + + inline static double GetDistanceKm(S2Point const& a, S2Point const& b); + inline static double GetDistanceKm(S2LatLng const& a, S2LatLng const& b); + inline static double GetDistanceMeters(S2Point const& a, S2Point const& b); + inline static double GetDistanceMeters(S2LatLng const& a, S2LatLng const& b); + // Convenience functions. These methods also return a double-precision + // result, unlike the generic GetDistance() method. + + inline static util::units::Meters Radius(); + // Return the Earth's mean radius, which is the radius of the equivalent + // sphere with the same surface area. According to NASA, this value is + // 6371.01 +/- 0.02 km. The equatorial radius is 6378.136 km, and the polar + // radius is 6356.752 km. They differ by one part in 298.257. + // + // Reference: http://ssd.jpl.nasa.gov/phys_props_earth.html, which quotes + // Yoder, C.F. 1995. "Astrometric and Geodetic Properties of Earth and the + // Solar System" in Global Earth Physics, A Handbook of Physical Constants, + // AGU Reference Shelf 1, American Geophysical Union, Table 2. + + inline static double RadiusKm(); + inline static double RadiusMeters(); + // Convenience functions. + + inline static util::units::Meters LowestAltitude(); + // Return the altitude of the lowest known point on Earth. The lowest known + // point on Earth is the Challenger Deep with an altitude of -10898 meters + // above the surface of the spherical earth. + + inline static double LowestAltitudeKm(); + inline static double LowestAltitudeMeters(); + // Convenience functions. + + inline static util::units::Meters HighestAltitude(); + // Return the altitude of the highest known point on Earth. The highest known + // point on Earth is Mount Everest with an altitude of 8846 meters above the + // surface of the spherical earth. + + inline static double HighestAltitudeKm(); + inline static double HighestAltitudeMeters(); + // Convenience functions. +}; + +inline S1Angle S2Earth::ToAngle(util::units::Meters const& distance) { + return S1Angle::Radians(ToRadians(distance)); +} + +inline util::units::Meters S2Earth::ToDistance(S1Angle const& angle) { + return util::units::Meters(ToMeters(angle)); +} + +inline double S2Earth::ToRadians(util::units::Meters const& distance) { + return distance.value() / RadiusMeters(); +} + +inline double S2Earth::ToMeters(S1Angle const& angle) { + return angle.radians() * RadiusMeters(); +} + +inline double S2Earth::ToKm(S1Angle const& angle) { + return angle.radians() * RadiusKm(); +} + +inline double S2Earth::KmToRadians(double km) { + return km / RadiusKm(); +} + +inline double S2Earth::RadiansToKm(double radians) { + return radians * RadiusKm(); +} + +inline double S2Earth::MetersToRadians(double meters) { + return meters / RadiusMeters(); +} + +inline double S2Earth::RadiansToMeters(double radians) { + return radians * RadiusMeters(); +} + +inline double S2Earth::ToLongitudeRadians(util::units::Meters const& distance, + double latitude_radians) { + double scalar = cos(latitude_radians); + if (scalar == 0) return M_PI * 2; + return std::min(ToRadians(distance) / scalar, M_PI * 2); +} + +inline util::units::Meters S2Earth::GetDistance(S2Point const& a, + S2Point const& b) { + return ToDistance(S1Angle(a, b)); +} + +inline util::units::Meters S2Earth::GetDistance(S2LatLng const& a, + S2LatLng const& b) { + return ToDistance(a.GetDistance(b)); +} + +inline double S2Earth::GetDistanceKm(S2Point const& a, S2Point const& b) { + return RadiansToKm(a.Angle(b)); +} + +inline double S2Earth::GetDistanceKm(S2LatLng const& a, S2LatLng const& b) { + return ToKm(a.GetDistance(b)); +} + +inline double S2Earth::GetDistanceMeters(S2Point const& a, S2Point const& b) { + return RadiansToMeters(a.Angle(b)); +} + +inline double S2Earth::GetDistanceMeters(S2LatLng const& a, S2LatLng const& b) { + return ToMeters(a.GetDistance(b)); +} + +inline util::units::Meters S2Earth::Radius() { + return util::units::Meters(RadiusMeters()); +} + +inline double S2Earth::RadiusKm() { + return 0.001 * RadiusMeters(); +} + +inline double S2Earth::RadiusMeters() { + return 6371010.0; +} + +inline util::units::Meters S2Earth::LowestAltitude() { + return util::units::Meters(LowestAltitudeMeters()); +} + +inline double S2Earth::LowestAltitudeKm() { + return 0.001 * LowestAltitudeMeters(); +} + +inline double S2Earth::LowestAltitudeMeters() { + return -10898; +} + +inline util::units::Meters S2Earth::HighestAltitude() { + return util::units::Meters(HighestAltitudeMeters()); +} + +inline double S2Earth::HighestAltitudeKm() { + return 0.001 * HighestAltitudeMeters(); +} + +inline double S2Earth::HighestAltitudeMeters() { + return 8846; +} + +#endif // S2_GEOMETRY_S2EARTH_H_ diff --git a/src/s2earth_test.cc b/src/s2earth_test.cc new file mode 100644 index 00000000..847d28b5 --- /dev/null +++ b/src/s2earth_test.cc @@ -0,0 +1,87 @@ +// Copyright 2005 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Author: ericv@google.com (Eric Veach) + +#include "s2earth.h" + +#include +#include "util/units/physical-units.h" + +TEST(S2EarthTest, TestAngleConversion) { + ASSERT_DOUBLE_EQ(S2Earth::ToAngle(S2Earth::Radius()).radians(), 1); + ASSERT_FLOAT_EQ(util::units::Meters( + S2Earth::ToDistance(S1Angle::Radians(2))).value(), + 2 * S2Earth::RadiusMeters()); + ASSERT_DOUBLE_EQ(S2Earth::ToRadians(util::units::Meters( + S2Earth::RadiusMeters())), 1); + ASSERT_DOUBLE_EQ(S2Earth::ToMeters(S1Angle::Degrees(180)), + S2Earth::RadiusMeters() * M_PI); + ASSERT_DOUBLE_EQ(S2Earth::ToKm(S1Angle::Radians(0.5)), + 0.5 * S2Earth::RadiusKm()); + ASSERT_DOUBLE_EQ(S2Earth::KmToRadians(S2Earth::RadiusMeters() / 1000), 1); + ASSERT_DOUBLE_EQ(S2Earth::RadiansToKm(0.5), 0.5 * S2Earth::RadiusKm()); + ASSERT_DOUBLE_EQ(S2Earth::MetersToRadians(S2Earth::RadiansToKm(0.3) * 1000), + 0.3); + ASSERT_DOUBLE_EQ(S2Earth::RadiansToMeters(S2Earth::KmToRadians(2.5)), 2500); +} + +TEST(S2EarthTest, TestToLongitudeRadians) { + const util::units::Meters earth_radius = util::units::Meters( + S2Earth::RadiusMeters()); + + // At the equator, ToLongitudeRadians behaves exactly like ToRadians. + ASSERT_DOUBLE_EQ(S2Earth::ToLongitudeRadians(earth_radius, 0), 1); + + // The closer we get to the poles, the more radians we need to go the same + // distance. + ASSERT_GT(S2Earth::ToLongitudeRadians(earth_radius, 0.5), + S2Earth::ToLongitudeRadians(earth_radius, 0.4)); + + // At the poles, we should return 2PI radians instead of dividing by 0. + ASSERT_DOUBLE_EQ(S2Earth::ToLongitudeRadians(earth_radius, M_PI_2), + M_PI * 2); + + // Within epsilon of the poles, we should still return 2PI radians instead + // of directing the caller to take thousands of radians around. + ASSERT_DOUBLE_EQ(S2Earth::ToLongitudeRadians(earth_radius, M_PI_2 - 1e-4), + M_PI * 2); +} + +TEST(S2EarthTest, TestGetDistance) { + S2Point north(0, 0, 1); + S2Point south(0, 0, -1); + S2Point west(0, -1, 0); + + ASSERT_FLOAT_EQ(util::units::Miles( + S2Earth::GetDistance(north, south)).value(), + util::units::Miles(M_PI * S2Earth::Radius()).value()); + ASSERT_DOUBLE_EQ(S2Earth::GetDistanceKm(west, west), 0); + ASSERT_DOUBLE_EQ(S2Earth::GetDistanceMeters(north, west), + M_PI_2 * S2Earth::RadiusMeters()); + + ASSERT_FLOAT_EQ(util::units::Feet(S2Earth::GetDistance( + S2LatLng::FromDegrees(0, -90), + S2LatLng::FromDegrees(-90, -38))).value(), + util::units::Feet(S2Earth::GetDistance(west, south)).value()); + + ASSERT_DOUBLE_EQ(S2Earth::GetDistanceKm(S2LatLng::FromRadians(0, 0.6), + S2LatLng::FromRadians(0, -0.4)), + S2Earth::RadiusKm()); + + ASSERT_DOUBLE_EQ(S2Earth::GetDistanceMeters(S2LatLng::FromDegrees(80, 27), + S2LatLng::FromDegrees(55, -153)), + 1000 * S2Earth::RadiusKm() * M_PI / 4); +} diff --git a/src/s2edgequery.cc b/src/s2edgequery.cc index d54eb6e5..43630eab 100644 --- a/src/s2edgequery.cc +++ b/src/s2edgequery.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2edgequery.h" @@ -284,4 +285,4 @@ inline void S2EdgeQuery::SplitBound(R2Rect const& edge_bound, child_bounds[1][1][v_end] = v; DCHECK(!child_bounds[1].is_empty()); DCHECK(edge_bound.Contains(child_bounds[1])); -} \ No newline at end of file +} diff --git a/src/s2edgequery.h b/src/s2edgequery.h index eaa10c41..44ba098d 100644 --- a/src/s2edgequery.h +++ b/src/s2edgequery.h @@ -12,15 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2EDGEQUERY_H_ -#define UTIL_GEOMETRY_S2EDGEQUERY_H_ +#ifndef S2_GEOMETRY_S2EDGEQUERY_H_ +#define S2_GEOMETRY_S2EDGEQUERY_H_ #include #include "base/macros.h" #include +#include "fpcontractoff.h" #include "r2.h" #include "r2rect.h" #include "s2.h" @@ -68,8 +70,8 @@ class S2EdgeQuery { // Internal methods are documented with their definitions. void GetCells(S2Point const& a, S2Point const& b); void GetCells(S2PaddedCell const& pcell, R2Rect const& bound); - inline void ClipVAxis(R2Rect const& edge_bound, double center, int i, - S2PaddedCell const& pcell); + void ClipVAxis(R2Rect const& edge_bound, double center, int i, + S2PaddedCell const& pcell); void SplitUBound(R2Rect const& edge_bound, double u, R2Rect child_bounds[2]) const; void SplitVBound(R2Rect const& edge_bound, double v, @@ -106,4 +108,4 @@ inline void S2EdgeQuery::Init(S2ShapeIndex const& index) { iter_.Init(index); } -#endif // UTIL_GEOMETRY_S2EDGEQUERY_H_ \ No newline at end of file +#endif // S2_GEOMETRY_S2EDGEQUERY_H_ diff --git a/src/s2edgequery_test.cc b/src/s2edgequery_test.cc index 7af1a9c9..a058834f 100644 --- a/src/s2edgequery_test.cc +++ b/src/s2edgequery_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2edgequery.h" @@ -19,7 +20,7 @@ #include // pair<> #include #include "base/stringprintf.h" -#include "gtest/gtest.h" +#include #include "s1angle.h" #include "s2cap.h" #include "s2cell.h" @@ -29,6 +30,7 @@ #include "s2testing.h" #include "util/gtl/algorithm.h" +using s2shapeutil::S2EdgeVectorShape; using std::pair; using std::vector; @@ -90,7 +92,7 @@ void TestAllCrossings(vector const& edges) { S2ShapeIndexOptions options; options.set_max_edges_per_cell(1); S2ShapeIndex index(options); - index.Insert(shape); // Takes ownership + index.Add(shape); // Takes ownership // To check that candidates are being filtered reasonably, we count the // total number of candidates that the total number of edge pairs that // either intersect or are very close to intersecting. @@ -221,4 +223,4 @@ TEST(GetCrossingCandidates, CollinearEdgesOnCellBoundaries) { } } -} // namespace \ No newline at end of file +} // namespace diff --git a/src/s2edgeutil.cc b/src/s2edgeutil.cc index 166d3798..0bd11322 100644 --- a/src/s2edgeutil.cc +++ b/src/s2edgeutil.cc @@ -12,21 +12,28 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2edgeutil.h" +#include #include -#include #include +#include #include #include "r1interval.h" #include "s1chordangle.h" +#include "util/math/exactfloat/exactfloat.h" #include "util/math/vector3.h" +// Avoid "using std::abs" to avoid possible programmer confusion with the +// integer-only C function. using std::max; using std::min; +using std::numeric_limits; +using std::swap; // Error constant definitions. See the header file for details. double const S2EdgeUtil::kFaceClipErrorRadians = 3 * DBL_EPSILON; @@ -36,6 +43,42 @@ double const S2EdgeUtil::kIntersectsRectErrorUVDist = 3 * M_SQRT2 * DBL_EPSILON; double const S2EdgeUtil::kEdgeClipErrorUVCoord = 2.25 * DBL_EPSILON; double const S2EdgeUtil::kEdgeClipErrorUVDist = 2.25 * DBL_EPSILON; +// kIntersectionError can be set somewhat arbitrarily, because the algorithm +// uses more precision if necessary in order to achieve the specified error. +// The only strict requirement is that kIntersectionError >= DBL_EPSILON +// radians. However, using a larger error tolerance makes the algorithm more +// efficient because it reduces the number of cases where exact arithmetic is +// needed. +S1Angle const S2EdgeUtil::kIntersectionError = S1Angle::Radians(4*DBL_EPSILON); + +// This value can be supplied as the vertex_merge_radius() to S2PolygonBuilder +// to ensure that intersection points that are supposed to be coincident are +// merged back together into a single vertex. This is required in order for +// various polygon operations (union, intersection, etc) to work correctly. +// It is twice the intersection error because two coincident intersection +// points might have errors in opposite directions. +S1Angle const S2EdgeUtil::kIntersectionMergeRadius = 2 * kIntersectionError; + +// DEPRECATED. This value is related to an obsolete intersection algorithm +// that made weaker accuracy guarantees. +S1Angle const S2EdgeUtil::kIntersectionTolerance = S1Angle::Radians(1.5e-15); + +S1Angle const S2EdgeUtil::kIntersectionExactError = + S1Angle::Radians(DBL_EPSILON); + +S2EdgeUtil::IntersectionMethod S2EdgeUtil::last_intersection_method_; + +char const* S2EdgeUtil::GetIntersectionMethodName(IntersectionMethod method) { + switch (method) { + case SIMPLE: return "Simple"; + case SIMPLE_LD: return "Simple_ld"; + case STABLE: return "Stable"; + case STABLE_LD: return "Stable_ld"; + case EXACT: return "Exact"; + default: return "Unknown"; + } +} + bool S2EdgeUtil::SimpleCrossing(S2Point const& a, S2Point const& b, S2Point const& c, S2Point const& d) { // We compute SimpleCCW() for triangles ACB, CBD, BDA, and DAC. All @@ -89,73 +132,371 @@ bool S2EdgeUtil::EdgeOrVertexCrossing(S2Point const& a, S2Point const& b, return VertexCrossing(a, b, c, d); } -static void ReplaceIfCloser(S2Point const& x, S2Point const& y, - double *dmin2, S2Point* vmin) { - // If the squared distance from x to y is less than dmin2, then replace - // vmin by y and update dmin2 accordingly. +typedef Vector3 Vector3_ld; +typedef Vector3 Vector3_xf; + +// Computes the cross product of "x" and "y", normalizes it to be unit length, +// and stores the result in "result". Also returns the length of the cross +// product before normalization, which is useful for estimating the amount of +// error in the result. For numerical stability, "x" and "y" should both be +// approximately unit length. +template +static T RobustNormalWithLength(Vector3 const& x, Vector3 const& y, + Vector3* result) { + // This computes 2 * (x.CrossProd(y)), but has much better numerical + // stability when "x" and "y" are unit length. + Vector3 tmp = (x - y).CrossProd(x + y); + T length = tmp.Norm(); + if (length != 0) { + *result = (1 / length) * tmp; + } + return 0.5 * length; // Since tmp == 2 * (x.CrossProd(y)) +} + +// If the intersection point of the edges (a0,a1) and (b0,b1) can be computed +// to within an error of at most S2EdgeUtil::kIntersectionError by this +// function, then set "result" to the intersection point and return true. +// +// The intersection point is not guaranteed to have the correct sign +// (i.e., it may be either "result" or "-result"). +template +static bool GetIntersectionSimple(Vector3 const& a0, Vector3 const& a1, + Vector3 const& b0, Vector3 const& b1, + Vector3* result) { + // The code below computes the intersection point as + // + // (a0.CrossProd(a1)).CrossProd(b0.CrossProd(b1)) + // + // except that it has better numerical stability and also computes a + // guaranteed error bound. + // + // Each cross product is computed as (X-Y).CrossProd(X+Y) using unit-length + // input vectors, which eliminates most of the cancellation error. However + // the error in the direction of the cross product can still become large if + // the two points are extremely close together. We can show that as long as + // the length of the cross product is at least (8*sqrt(3)+12) * DBL_EPSILON + // (about 6e-15), then the directional error is at most 2.5 * + // numeric_limits::epsilon() (about 3e-19 when T == "long double"). + // (DBL_EPSILON appears in the first formula because the inputs are assumed + // to be normalized in double precision rather than in the given type T.) + // + // The third cross product is different because its inputs already have some + // error. Letting "result_len" be the length of the cross product, it can + // be shown that the error is at most + // + // (1 + sqrt(3) + 6 / result_len) * numeric_limits::epsilon() + // + // We want this error to be at most kIntersectionError, which is true as + // long as "result_len" is at least kMinResultLen defined below. + + static const T kMinNormalLength = (8 * sqrt(3) + 12) * DBL_EPSILON; + static const T kMinResultLen = + 6 / (S2EdgeUtil::kIntersectionError.radians() / + numeric_limits::epsilon() - (1 + sqrt(3))); + + // On some platforms "long double" is the same as "double", and on these + // platforms this method always returns false (e.g. ARM, Win32). Rather + // than testing this directly, instead we look at kMinResultLen since this + // is a direct measure of whether "long double" has sufficient accuracy to + // be useful. If kMinResultLen > 0.5, it means that this method will fail + // even for edges that meet at an angle of 30 degrees. (On Intel platforms + // kMinResultLen corresponds to an intersection angle of about 0.04 + // degrees.) + DCHECK_LE(kMinResultLen, 0.5); + + Vector3 a_norm, b_norm; + if (RobustNormalWithLength(a0, a1, &a_norm) >= kMinNormalLength && + RobustNormalWithLength(b0, b1, &b_norm) >= kMinNormalLength && + RobustNormalWithLength(a_norm, b_norm, result) >= kMinResultLen) { + return true; + } + return false; +} + +static bool GetIntersectionSimpleLD(S2Point const& a0, S2Point const& a1, + S2Point const& b0, S2Point const& b1, + S2Point* result) { + Vector3_ld result_ld; + if (GetIntersectionSimple(Vector3_ld::Cast(a0), Vector3_ld::Cast(a1), + Vector3_ld::Cast(b0), Vector3_ld::Cast(b1), + &result_ld)) { + *result = S2Point::Cast(result_ld); + return true; + } + return false; +} + +// Given a point X and a vector "a_norm" (not necessarily unit length), +// compute x.DotProd(a_norm) and return a bound on the error in the result. +// The remaining parameters allow this dot product to be computed more +// accurately and efficiently. They include the length of "a_norm" +// ("a_norm_len") and the edge endpoints "a0" and "a1". +template +static T GetProjection(Vector3 const& x, + Vector3 const& a_norm, T a_norm_len, + Vector3 const& a0, Vector3 const& a1, + T* error) { + // The error in the dot product is proportional to the lengths of the input + // vectors, so rather than using "x" itself (a unit-length vector) we use + // the vectors from "x" to the closer of the two edge endpoints. This + // typically reduces the error by a huge factor. + Vector3 x0 = x - a0; + Vector3 x1 = x - a1; + T x0_dist2 = x0.Norm2(); + T x1_dist2 = x1.Norm2(); + + // If both distances are the same, we need to be careful to choose one + // endpoint deterministically so that the result does not change if the + // order of the endpoints is reversed. + T dist, result; + if (x0_dist2 < x1_dist2 || (x0_dist2 == x1_dist2 && x0 < x1)) { + dist = sqrt(x0_dist2); + result = x0.DotProd(a_norm); + } else { + dist = sqrt(x1_dist2); + result = x1.DotProd(a_norm); + } + // This calculation bounds the error from all sources: the computation of + // the normal, the subtraction of one endpoint, and the dot product itself. + // (DBL_EPSILON appears because the input points are assumed to be + // normalized in double precision rather than in the given type T.) + *error = ((3.5 * a_norm_len + 8 * sqrt(3) * DBL_EPSILON) * dist + + 0.75 * std::abs(result)) * numeric_limits::epsilon(); + return result; +} + +// Helper function for GetIntersectionStable(). It expects that the edges +// (a0,a1) and (b0,b1) have been sorted so that the first edge is longer. +template +static bool GetIntersectionStableSorted( + Vector3 const& a0, Vector3 const& a1, + Vector3 const& b0, Vector3 const& b1, Vector3* result) { + DCHECK_GE((a1 - a0).Norm2(), (b1 - b0).Norm2()); + + // Compute the normal of the plane through (a0, a1) in a stable way. + Vector3 a_norm = (a0 - a1).CrossProd(a0 + a1); + T a_norm_len = a_norm.Norm(); + T b_len = (b1 - b0).Norm(); + + // Compute the projection (i.e., signed distance) of b0 and b1 onto the + // plane through (a0, a1). Distances are scaled by the length of a_norm. + T b0_error, b1_error; + T b0_dist = GetProjection(b0, a_norm, a_norm_len, a0, a1, &b0_error); + T b1_dist = GetProjection(b1, a_norm, a_norm_len, a0, a1, &b1_error); + + // The total distance from b0 to b1 measured perpendicularly to (a0,a1) is + // |b0_dist - b1_dist|. Note that b0_dist and b1_dist generally have + // opposite signs because b0 and b1 are on opposite sides of (a0, a1). The + // code below finds the intersection point by interpolating along the edge + // (b0, b1) to a fractional distance of b0_dist / (b0_dist - b1_dist). + // + // It can be shown that the maximum error in the interpolation fraction is + // + // (b0_dist * b1_error - b1_dist * b0_error) / + // (dist_sum * (dist_sum - error_sum)) + // + // We save ourselves some work by scaling the result and the error bound by + // "dist_sum", since the result is normalized to be unit length anyway. + T dist_sum = std::abs(b0_dist - b1_dist); + T error_sum = b0_error + b1_error; + if (dist_sum <= error_sum) { + return false; // Error is unbounded in this case. + } + Vector3 x = b0_dist * b1 - b1_dist * b0; + T error = b_len * std::abs(b0_dist * b1_error - b1_dist * b0_error) / + (dist_sum - error_sum) + dist_sum * numeric_limits::epsilon(); + + // Finally we normalize the result, compute the corresponding error, and + // check whether the total error is acceptable. + T x_len = x.Norm(); + T const kMaxError = S2EdgeUtil::kIntersectionError.radians(); + if (error > (kMaxError - 0.5 * numeric_limits::epsilon()) * x_len) { + return false; + } + *result = (1 / x_len) * x; + return true; +} + +// Returns whether (a0,a1) is less than (b0,b1) with respect to a total +// ordering on edges that is invariant under edge reversals. +template +static bool CompareEdges(Vector3 const& a0, Vector3 const& a1, + Vector3 const& b0, Vector3 const& b1) { + Vector3 const *pa0 = &a0, *pa1 = &a1; + Vector3 const *pb0 = &b0, *pb1 = &b1; + if (*pa0 >= *pa1) swap(pa0, pa1); + if (*pb0 >= *pb1) swap(pb0, pb1); + return *pa0 < *pb0 || (*pa0 == *pb0 && *pb0 < *pb1); +} - double d2 = (x - y).Norm2(); - if (d2 < *dmin2 || (d2 == *dmin2 && y < *vmin)) { - *dmin2 = d2; - *vmin = y; +// If the intersection point of the edges (a0,a1) and (b0,b1) can be computed +// to within an error of at most S2EdgeUtil::kIntersectionError by this +// function, then set "result" to the intersection point and return true. +// +// The intersection point is not guaranteed to have the correct sign +// (i.e., it may be either "result" or "-result"). +template +static bool GetIntersectionStable(Vector3 const& a0, Vector3 const& a1, + Vector3 const& b0, Vector3 const& b1, + Vector3* result) { + // Sort the two edges so that (a0,a1) is longer, breaking ties in a + // deterministic way that does not depend on the ordering of the endpoints. + // This is desirable for two reasons: + // - So that the result doesn't change when edges are swapped or reversed. + // - It reduces error, since the first edge is used to compute the edge + // normal (where a longer edge means less error), and the second edge + // is used for interpolation (where a shorter edge means less error). + T a_len2 = (a1 - a0).Norm2(); + T b_len2 = (b1 - b0).Norm2(); + if (a_len2 < b_len2 || (a_len2 == b_len2 && CompareEdges(a0, a1, b0, b1))) { + return GetIntersectionStableSorted(b0, b1, a0, a1, result); + } else { + return GetIntersectionStableSorted(a0, a1, b0, b1, result); } } +static bool GetIntersectionStableLD(S2Point const& a0, S2Point const& a1, + S2Point const& b0, S2Point const& b1, + S2Point* result) { + Vector3_ld result_ld; + if (GetIntersectionStable(Vector3_ld::Cast(a0), Vector3_ld::Cast(a1), + Vector3_ld::Cast(b0), Vector3_ld::Cast(b1), + &result_ld)) { + *result = S2Point::Cast(result_ld); + return true; + } + return false; +} + +S2Point S2EdgeUtil::S2PointFromExact(Vector3_xf const& x) { + // TODO(ericv): In theory, this function may return S2Point(0, 0, 0) even + // though "x" is non-zero. This happens when all components of "x" have + // absolute value less than about 1e-154, since in that case x.Norm2() is + // zero in double precision. This could be fixed by scaling "x" by an + // appropriate power of 2 before the conversion. + return S2Point(x[0].ToDouble(), x[1].ToDouble(), x[2].ToDouble()).Normalize(); +} + +// Compute the intersection point of (a0, a1) and (b0, b1) using exact +// arithmetic. Note that the result is not exact because it is rounded to +// double precision. Also, the intersection point is not guaranteed to have +// the correct sign (i.e., the return value may need to be negated). +S2Point S2EdgeUtil::GetIntersectionExact(S2Point const& a0, S2Point const& a1, + S2Point const& b0, S2Point const& b1) { + // Since we are using exact arithmetic, we don't need to worry about + // numerical stability. + Vector3_xf a0_xf = Vector3_xf::Cast(a0); + Vector3_xf a1_xf = Vector3_xf::Cast(a1); + Vector3_xf b0_xf = Vector3_xf::Cast(b0); + Vector3_xf b1_xf = Vector3_xf::Cast(b1); + Vector3_xf a_norm_xf = a0_xf.CrossProd(a1_xf); + Vector3_xf b_norm_xf = b0_xf.CrossProd(b1_xf); + Vector3_xf x_xf = a_norm_xf.CrossProd(b_norm_xf); + + // The final Normalize() call is done in double precision, which creates a + // directional error of up to DBL_EPSILON. (ToDouble() and Normalize() + // each contribute up to 0.5 * DBL_EPSILON of directional error.) + S2Point x = S2EdgeUtil::S2PointFromExact(x_xf); + + if (x == S2Point(0, 0, 0)) { + // The two edges are exactly collinear, but we still consider them to be + // "crossing" because of simulation of simplicity. Out of the four + // endpoints, exactly two lie in the interior of the other edge. Of + // those two we return the one that is lexicographically smallest. + x = S2Point(10, 10, 10); // Greater than any valid S2Point + S2Point a_norm = S2EdgeUtil::S2PointFromExact(a_norm_xf); + S2Point b_norm = S2EdgeUtil::S2PointFromExact(b_norm_xf); + if (S2::OrderedCCW(b0, a0, b1, b_norm) && a0 < x) x = a0; + if (S2::OrderedCCW(b0, a1, b1, b_norm) && a1 < x) x = a1; + if (S2::OrderedCCW(a0, b0, a1, a_norm) && b0 < x) x = b0; + if (S2::OrderedCCW(a0, b1, a1, a_norm) && b1 < x) x = b1; + } + DCHECK(S2::IsUnitLength(x)); + return x; +} + +// Given three points "a", "x", "b", returns true if these three points occur +// in the given order along the edge (a,b) to within the given tolerance. +// More precisely, either "x" must be within "tolerance" of "a" or "b", or +// when "x" is projected onto the great circle through "a" and "b" it must lie +// along the edge (a,b) (i.e., the shortest path from "a" to "b"). +static bool ApproximatelyOrdered(S2Point const& a, S2Point const& x, + S2Point const& b, double tolerance) { + if ((x - a).Norm2() <= tolerance * tolerance) return true; + if ((x - b).Norm2() <= tolerance * tolerance) return true; + return S2::OrderedCCW(a, x, b, S2::RobustCrossProd(a, b).Normalize()); +} + S2Point S2EdgeUtil::GetIntersection(S2Point const& a0, S2Point const& a1, S2Point const& b0, S2Point const& b1) { DCHECK_GT(RobustCrossing(a0, a1, b0, b1), 0); - // We use RobustCrossProd() to get accurate results even when two endpoints - // are close together, or when the two line segments are nearly parallel. - - Vector3_d a_norm = S2::RobustCrossProd(a0, a1).Normalize(); - Vector3_d b_norm = S2::RobustCrossProd(b0, b1).Normalize(); - S2Point x = S2::RobustCrossProd(a_norm, b_norm).Normalize(); + // It is difficult to compute the intersection point of two edges accurately + // when the angle between the edges is very small. Previously we handled + // this by only guaranteeing that the returned intersection point is within + // kIntersectionError of each edge. However, this means that when the edges + // cross at a very small angle, the computed result may be very far from the + // true intersection point. + // + // Instead this function now guarantees that the result is always within + // kIntersectionError of the true intersection. This requires using more + // sophisticated techniques and in some cases extended precision. + // + // Three different techniques are implemented, but only two are used: + // + // - GetIntersectionSimple() computes the intersection point using + // numerically stable cross products in "long double" precision. + // + // - GetIntersectionStable() computes the intersection point using + // projection and interpolation, taking care to minimize cancellation + // error. This method exists in "double" and "long double" versions. + // + // - GetIntersectionExact() computes the intersection point using exact + // arithmetic and converts the final result back to an S2Point. + // + // We don't actually use the first method (GetIntersectionSimple) because it + // turns out that GetIntersectionStable() is twice as fast and also much + // more accurate (even in double precision). The "long double" version + // (only available on Intel platforms) uses 80-bit precision and is about + // twice as slow. The exact arithmetic version is about 100x slower. + // + // So our strategy is to first call GetIntersectionStable() in double + // precision; if that doesn't work and this platform supports "long double", + // then we try again in "long double"; if that doesn't work then we fall + // back to exact arithmetic. + + static bool const kUseSimpleMethod = false; + static bool const kHasLongDouble = (numeric_limits::epsilon() < + numeric_limits::epsilon()); + S2Point result; + if (kUseSimpleMethod && GetIntersectionSimple(a0, a1, b0, b1, &result)) { + last_intersection_method_ = SIMPLE; + } else if (kUseSimpleMethod && kHasLongDouble && + GetIntersectionSimpleLD(a0, a1, b0, b1, &result)) { + last_intersection_method_ = SIMPLE_LD; + } else if (GetIntersectionStable(a0, a1, b0, b1, &result)) { + last_intersection_method_ = STABLE; + } else if (kHasLongDouble && + GetIntersectionStableLD(a0, a1, b0, b1, &result)) { + last_intersection_method_ = STABLE_LD; + } else { + result = GetIntersectionExact(a0, a1, b0, b1); + last_intersection_method_ = EXACT; + } // Make sure the intersection point is on the correct side of the sphere. // Since all vertices are unit length, and edges are less than 180 degrees, // (a0 + a1) and (b0 + b1) both have positive dot product with the // intersection point. We use the sum of all vertices to make sure that the - // result is unchanged when the edges are reversed or exchanged. - - if (x.DotProd((a0 + a1) + (b0 + b1)) < 0) x = -x; - - // The calculation above is sufficient to ensure that "x" is within - // kIntersectionTolerance of the great circles through (a0,a1) and (b0,b1). - // However, if these two great circles are very close to parallel, it is - // possible that "x" does not lie between the endpoints of the given line - // segments. In other words, "x" might be on the great circle through - // (a0,a1) but outside the range covered by (a0,a1). In this case we do - // additional clipping to ensure that it does. - - if (S2::OrderedCCW(a0, x, a1, a_norm) && S2::OrderedCCW(b0, x, b1, b_norm)) - return x; - - // Find the acceptable endpoint closest to x and return it. An endpoint is - // acceptable if it lies between the endpoints of the other line segment. - double dmin2 = 10; - S2Point vmin = x; - if (S2::OrderedCCW(b0, a0, b1, b_norm)) ReplaceIfCloser(x, a0, &dmin2, &vmin); - if (S2::OrderedCCW(b0, a1, b1, b_norm)) ReplaceIfCloser(x, a1, &dmin2, &vmin); - if (S2::OrderedCCW(a0, b0, a1, a_norm)) ReplaceIfCloser(x, b0, &dmin2, &vmin); - if (S2::OrderedCCW(a0, b1, a1, a_norm)) ReplaceIfCloser(x, b1, &dmin2, &vmin); - - DCHECK(S2::OrderedCCW(a0, vmin, a1, a_norm)); - DCHECK(S2::OrderedCCW(b0, vmin, b1, b_norm)); - return vmin; -} + // result is unchanged when the edges are swapped or reversed. + if (result.DotProd((a0 + a1) + (b0 + b1)) < 0) result = -result; -// IEEE floating-point operations have a maximum error of 0.5 ULPS (units in -// the last place). For double-precision numbers, this works out to 2**-53 -// (about 1.11e-16) times the magnitude of the result. It is possible to -// analyze the calculation done by GetIntersection() and work out the -// worst-case rounding error. I have done a rough version of this, and my -// estimate is that the worst case distance from the intersection point X to -// the great circle through (a0, a1) is about 12 ULPS, or about 1.3e-15. -// This needs to be increased by a factor of (1/0.866) to account for the -// edge_splice_fraction() in S2PolygonBuilder. Note that the maximum error -// measured by the unittest in 1,000,000 trials is less than 3e-16. -S1Angle const S2EdgeUtil::kIntersectionTolerance = S1Angle::Radians(1.5e-15); + // Make sure that the intersection point lies on both edges. + DCHECK(ApproximatelyOrdered(a0, result, a1, kIntersectionError.radians())); + DCHECK(ApproximatelyOrdered(b0, result, b1, kIntersectionError.radians())); + + return result; +} double S2EdgeUtil::GetDistanceFraction(S2Point const& x, S2Point const& a0, S2Point const& a1) { @@ -1231,4 +1572,4 @@ bool S2EdgeUtil::ClipEdge(R2Point const& a, R2Point const& b, return true; } return false; -} \ No newline at end of file +} diff --git a/src/s2edgeutil.h b/src/s2edgeutil.h index c1d281d0..a14efadc 100644 --- a/src/s2edgeutil.h +++ b/src/s2edgeutil.h @@ -12,15 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2EDGEUTIL_H__ -#define UTIL_GEOMETRY_S2EDGEUTIL_H__ +#ifndef S2_GEOMETRY_S2EDGEUTIL_H__ +#define S2_GEOMETRY_S2EDGEUTIL_H__ #include #include #include "base/macros.h" +#include "fpcontractoff.h" #include "r2.h" #include "r2rect.h" #include "s1angle.h" @@ -33,6 +35,7 @@ class S1ChordAngle; class S2LatLngRect; +class ExactFloat; // This class contains various utility functions related to edges. It // collects together common code that is needed to implement polygonal @@ -256,22 +259,34 @@ class S2EdgeUtil { // (1) GI(b,a,c,d) == GI(a,b,d,c) == GI(a,b,c,d) // (2) GI(c,d,a,b) == GI(a,b,c,d) // - // The returned intersection point X is guaranteed to be close to the edges - // AB and CD, but if the edges intersect at a very small angle then X may - // not be close to the true mathematical intersection point P. See the - // description of "kIntersectionTolerance" below for details. + // The returned intersection point X is guaranteed to be very close to the + // true intersection point of AB and CD, even if the edges intersect at a + // very small angle. See "kIntersectionError" below for details. static S2Point GetIntersection(S2Point const& a, S2Point const& b, S2Point const& c, S2Point const& d); - // This distance is an upper bound on the distance from the intersection - // point returned by GetIntersection() to either of the two edges that were - // intersected. In particular, if "x" is the intersection point, then - // GetDistance(x, a, b) and GetDistance(x, c, d) will both be smaller than - // this value. The intersection tolerance is also large enough such if it - // is passed as the "vertex_merge_radius" of an S2PolygonBuilder, then the - // intersection point will be spliced into the edges AB and/or CD if they - // are also supplied to the S2PolygonBuilder. - static S1Angle const kIntersectionTolerance; + // kIntersectionError is an upper bound on the distance from the intersection + // point returned by GetIntersection() to the true intersection point. + static S1Angle const kIntersectionError; + + // When using S2PolygonBuilder with computed intersection points, the + // vertex_merge_radius() should be at least this large in order to avoid + // incorrect output. + static S1Angle const kIntersectionMergeRadius; // 2 * kIntersectionError + + // This value is related to a previous implementation of GetIntersection() + // that made weaker accuracy guarantees. Existing code should be updated + // to use either kIntersectionError or kIntersectionMergeRadius, depending + // on how the value is being used: + // + // - If you need a bound on how far the intersection point is from its true + // location, use kIntersectionError. + // + // - If you need a bound on how far apart two intersection points can be + // that are supposed to coincide, use kIntersectionMergeRadius. (This + // is the value that should be used with S2PolygonBuilder.) + // + static S1Angle const kIntersectionTolerance; // DEPRECATED // Given a point X and an edge AB, return the distance ratio AX / (AX + BX). // If X happens to be on the line segment AB, this is the fraction "t" such @@ -486,8 +501,32 @@ class S2EdgeUtil { inline static double InterpolateDouble(double x, double a, double b, double a1, double b1); + // Convert a point from the ExactFloat representation to the closest + // double-precision value. The result is normalized to be unit length. + static S2Point S2PointFromExact(Vector3 const& x); + private: - DISALLOW_IMPLICIT_CONSTRUCTORS(S2EdgeUtil); // Contains only static methods. + friend class S2EdgeUtilTesting; + + // This is an *internal only* method declared here for testing purposes. + static S2Point GetIntersectionExact(S2Point const& a0, S2Point const& a1, + S2Point const& b0, S2Point const& b1); + + // The maximum error in the method above. + static S1Angle const kIntersectionExactError; + + enum IntersectionMethod { + SIMPLE, + SIMPLE_LD, + STABLE, + STABLE_LD, + EXACT, + NUM_INTERSECTION_METHODS + }; + static IntersectionMethod last_intersection_method_; + static char const* GetIntersectionMethodName(IntersectionMethod method); + + DISALLOW_IMPLICIT_CONSTRUCTORS(S2EdgeUtil); // Contains only static members. }; @@ -496,11 +535,15 @@ class S2EdgeUtil { inline S2EdgeUtil::EdgeCrosser::EdgeCrosser(S2Point const* a, S2Point const* b) : a_(a), b_(b), a_cross_b_(a_->CrossProd(*b_)), have_tangents_(false) { + DCHECK(S2::IsUnitLength(*a)); + DCHECK(S2::IsUnitLength(*b)); } inline S2EdgeUtil::EdgeCrosser::EdgeCrosser( S2Point const* a, S2Point const* b, S2Point const* c) : a_(a), b_(b), a_cross_b_(a_->CrossProd(*b_)), have_tangents_(false) { + DCHECK(S2::IsUnitLength(*a)); + DCHECK(S2::IsUnitLength(*b)); RestartAt(c); } @@ -512,11 +555,13 @@ inline void S2EdgeUtil::EdgeCrosser::Init(S2Point const* a, S2Point const* b) { } inline void S2EdgeUtil::EdgeCrosser::RestartAt(S2Point const* c) { + DCHECK(S2::IsUnitLength(*c)); c_ = c; acb_ = -S2::TriageCCW(*a_, *b_, *c_, a_cross_b_); } inline int S2EdgeUtil::EdgeCrosser::RobustCrossing(S2Point const* d) { + DCHECK(S2::IsUnitLength(*d)); // For there to be an edge crossing, the triangles ACB, CBD, BDA, DAC must // all be oriented the same way (CW or CCW). We keep the orientation of ACB // as part of our state. When each new point D arrives, we compute the @@ -571,4 +616,4 @@ inline double S2EdgeUtil::InterpolateDouble(double x, double a, double b, } } -#endif // UTIL_GEOMETRY_S2EDGEUTIL_H__ \ No newline at end of file +#endif // S2_GEOMETRY_S2EDGEUTIL_H__ diff --git a/src/s2edgeutil_test.cc b/src/s2edgeutil_test.cc index 48a2c43b..017505d9 100644 --- a/src/s2edgeutil_test.cc +++ b/src/s2edgeutil_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2edgeutil.h" @@ -19,24 +20,29 @@ #include #include #include +#include #include #include #include -#include "base/scoped_ptr.h" #include "base/stringprintf.h" -#include "gtest/gtest.h" +#include #include "r1interval.h" #include "r2rect.h" #include "s1chordangle.h" #include "s2polyline.h" #include "s2testing.h" +#include "s2textformat.h" +#include "util/math/exactfloat/exactfloat.h" #include "util/math/vector3.h" using std::max; +using std::swap; +using std::unique_ptr; using std::vector; -namespace { +extern void PrintIntersectionStats(); +extern int exact_calls; const int kDegen = -2; void CompareResult(int actual, int expected) { @@ -167,10 +173,10 @@ S2LatLng const kRectError = S2EdgeUtil::RectBounder::MaxErrorForTests(); TEST(RectBounder, MaxLatitudeSimple) { // Check cases where the min/max latitude is attained at a vertex. static double const kCubeLat = asin(1 / sqrt(3)); // 35.26 degrees - EXPECT_TRUE(GetEdgeBound(1,1,1, 1,-1,-1).ApproxEquals( + EXPECT_TRUE(GetEdgeBound(1,1,1, 1,-1,-1).ApproxEquals( // NOLINT S2LatLngRect(R1Interval(-kCubeLat, kCubeLat), S1Interval(-M_PI_4, M_PI_4)), kRectError)); - EXPECT_TRUE(GetEdgeBound(1,-1,1, 1,1,-1).ApproxEquals( + EXPECT_TRUE(GetEdgeBound(1,-1,1, 1,1,-1).ApproxEquals( // NOLINT S2LatLngRect(R1Interval(-kCubeLat, kCubeLat), S1Interval(-M_PI_4, M_PI_4)), kRectError)); @@ -183,17 +189,17 @@ TEST(RectBounder, MaxLatitudeSimple) { GetEdgeBound(1,1,1, 1,-1,1).lat().hi()); // Max latitude, CCW edge EXPECT_DOUBLE_EQ(M_PI_4 + 0.5 * kRectError.lat().radians(), - GetEdgeBound(1,-1,1, 1,1,1).lat().hi()); + GetEdgeBound(1,-1,1, 1,1,1).lat().hi()); // NOLINT // Min latitude, CW edge EXPECT_DOUBLE_EQ(-M_PI_4 - 0.5 * kRectError.lat().radians(), - GetEdgeBound(1,-1,-1, -1,-1,-1).lat().lo()); + GetEdgeBound(1,-1,-1, -1,-1,-1).lat().lo()); // NOLINT // Min latitude, CCW edge EXPECT_DOUBLE_EQ(-M_PI_4 - 0.5 * kRectError.lat().radians(), - GetEdgeBound(-1,1,-1, -1,-1,-1).lat().lo()); + GetEdgeBound(-1,1,-1, -1,-1,-1).lat().lo()); // NOLINT // Check cases where the edge passes through one of the poles. - EXPECT_EQ(M_PI_2, GetEdgeBound(.3,.4,1, -.3,-.4,1).lat().hi()); - EXPECT_EQ(-M_PI_2, GetEdgeBound(.3,.4,-1, -.3,-.4,-1).lat().lo()); + EXPECT_EQ(M_PI_2, GetEdgeBound(.3,.4,1, -.3,-.4,1).lat().hi()); // NOLINT + EXPECT_EQ(-M_PI_2, GetEdgeBound(.3,.4,-1, -.3,-.4,-1).lat().lo()); // NOLINT } TEST(RectBounder, MaxLatitudeRandom) { @@ -632,8 +638,8 @@ TEST(S2EdgeUtil, InterpolateCanExtrapolate) { const S2Point j(0, 1, 0); // Initial vectors at 90 degrees. CheckInterpolate(0, i, j, S2Point(1, 0, 0)); - CheckInterpolate(1, i, j ,S2Point(0, 1, 0)); - CheckInterpolate(1.5, i, j ,S2Point(-1, 1, 0)); + CheckInterpolate(1, i, j, S2Point(0, 1, 0)); + CheckInterpolate(1.5, i, j, S2Point(-1, 1, 0)); CheckInterpolate(2, i, j, S2Point(-1, 0, 0)); CheckInterpolate(3, i, j, S2Point(0, -1, 0)); CheckInterpolate(4, i, j, S2Point(1, 0, 0)); @@ -641,7 +647,7 @@ TEST(S2EdgeUtil, InterpolateCanExtrapolate) { // Negative values of t. CheckInterpolate(-1, i, j, S2Point(0, -1, 0)); CheckInterpolate(-2, i, j, S2Point(-1, 0, 0)); - CheckInterpolate(-3, i, j ,S2Point(0, 1, 0)); + CheckInterpolate(-3, i, j, S2Point(0, 1, 0)); CheckInterpolate(-4, i, j, S2Point(1, 0, 0)); // Initial vectors at 45 degrees. @@ -656,7 +662,6 @@ TEST(S2EdgeUtil, InterpolateCanExtrapolate) { S2Point p(S2EdgeUtil::Interpolate(0.001, i, j)); // We should get back where we started. CheckInterpolate(1000, i, p, j); - } @@ -673,64 +678,208 @@ TEST(S2EdgeUtil, RepeatedInterpolation) { } } -TEST(S2EdgeUtil, IntersectionTolerance) { - // We repeatedly construct two edges that cross near a random point "p", - // and measure the distance from the actual intersection point "x" to the - // the expected intersection point "p" and also to the edges that cross - // near "p". - // - // Note that GetIntersection() does not guarantee that "x" and "p" will be - // close together (since the intersection point is numerically unstable - // when the edges cross at a very small angle), but it does guarantee that - // "x" will be close to both of the edges that cross. +class S2EdgeUtilTesting { + public: + static S2Point GetIntersection(S2Point const& a, S2Point const& b, + S2Point const& c, S2Point const& d) { + S2Point result = S2EdgeUtil::GetIntersection(a, b, c, d); + ++tally_[S2EdgeUtil::last_intersection_method_]; + return result; + } + + static void PrintIntersectionStats() { + int total = 0; + int totals[kNumMethods]; + for (int i = kNumMethods; --i >= 0; ) { + total += tally_[i]; + totals[i] = total; + } + printf("%10s %16s %16s %6s\n", + "Method", "Successes", "Attempts", "Rate"); + for (int i = 0; i < kNumMethods; ++i) { + if (tally_[i] == 0) continue; + printf("%10s %9d %5.1f%% %9d %5.1f%% %5.1f%%\n", + S2EdgeUtil::GetIntersectionMethodName( + static_cast(i)), + tally_[i], 100.0 * tally_[i] / total, + totals[i], 100.0 * totals[i] / total, + 100.0 * tally_[i] / totals[i]); + } + for (int i = 0; i < kNumMethods; ++i) tally_[i] = 0; + } + + // This returns the true intersection point of two line segments (a0,a1) and + // (b0,b1), with a relative error of at most DBL_EPSILON in each coordinate + // (i.e., one ulp, or twice the double precision rounding error). + static S2Point GetIntersectionExact(S2Point const& a0, S2Point const& a1, + S2Point const& b0, S2Point const& b1) { + S2Point x = S2EdgeUtil::GetIntersectionExact(a0, a1, b0, b1); + if (x.DotProd((a0 + a1) + (b0 + b1)) < 0) x = -x; + return x; + } + + private: + static int const kNumMethods = S2EdgeUtil::NUM_INTERSECTION_METHODS; + static int tally_[kNumMethods]; +}; +int S2EdgeUtilTesting::tally_[kNumMethods]; + +// The approximate maximum error in GetDistance() for small distances. +S1Angle kGetDistanceAbsError = S1Angle::Radians(3 * DBL_EPSILON); + +TEST(S2EdgeUtil, IntersectionError) { + // We repeatedly construct two edges that cross near a random point "p", and + // measure the distance from the actual intersection point "x" to the + // exact intersection point and also to the edges. S1Angle max_point_dist, max_edge_dist; S2Testing::Random* rnd = &S2Testing::rnd; - for (int i = 0; i < 1000; ++i) { + for (int iter = 0; iter < 5000; ++iter) { // We construct two edges AB and CD that intersect near "p". The angle // between AB and CD (expressed as a slope) is chosen randomly between - // 1e-15 and 1.0 such that its logarithm is uniformly distributed. This - // implies that small values are much more likely to be chosen. - // - // Once the slope is chosen, the four points ABCD must be offset from P - // by at least (1e-15 / slope) so that the points are guaranteed to have - // the correct circular ordering around P. This is the distance from P - // at which the two edges are separated by about 1e-15, which is - // approximately the minimum distance at which we can expect computed - // points on the two lines to be distinct and have the correct ordering. + // 1e-15 and 1e15 such that its logarithm is uniformly distributed. + // Similarly, two edge lengths approximately between 1e-15 and 1 are + // chosen. The edge endpoints are chosen such that they are often very + // close to the other edge (i.e., barely crossing). Taken together this + // ensures that we test both long and very short edges that intersect at + // both large and very small angles. // - // The actual offset distance from P is chosen randomly in the range - // [1e-15 / slope, 1.0], again uniformly distributing the logarithm. - // This ensures that we test both long and very short segments that - // intersect at both large and very small angles. - + // Sometimes the edges we generate will not actually cross, in which case + // we simply try again. Vector3_d p, d1, d2; S2Testing::GetRandomFrame(&p, &d1, &d2); - double slope = pow(1e-15, rnd->RandDouble()); - d2 = d1 + slope * d2; - S2Point a = (p + pow(1e-15 / slope, rnd->RandDouble()) * d1).Normalize(); - S2Point b = (p - pow(1e-15 / slope, rnd->RandDouble()) * d1).Normalize(); - S2Point c = (p + pow(1e-15 / slope, rnd->RandDouble()) * d2).Normalize(); - S2Point d = (p - pow(1e-15 / slope, rnd->RandDouble()) * d2).Normalize(); - S2Point x = S2EdgeUtil::GetIntersection(a, b, c, d); - S1Angle dist_ab = S2EdgeUtil::GetDistance(x, a, b); - S1Angle dist_cd = S2EdgeUtil::GetDistance(x, c, d); - EXPECT_LE(dist_ab, S2EdgeUtil::kIntersectionTolerance); - EXPECT_LE(dist_cd, S2EdgeUtil::kIntersectionTolerance); + double slope = 1e-15 * pow(1e30, rnd->RandDouble()); + d2 = (d1 + slope * d2).Normalize(); + S2Point a, b, c, d; + do { + double ab_len = pow(1e-15, rnd->RandDouble()); + double cd_len = pow(1e-15, rnd->RandDouble()); + double a_fraction = pow(1e-5, rnd->RandDouble()); + if (rnd->OneIn(2)) a_fraction = 1 - a_fraction; + double c_fraction = pow(1e-5, rnd->RandDouble()); + if (rnd->OneIn(2)) c_fraction = 1 - c_fraction; + a = (p - a_fraction * ab_len * d1).Normalize(); + b = (p + (1 - a_fraction) * ab_len * d1).Normalize(); + c = (p - c_fraction * cd_len * d2).Normalize(); + d = (p + (1 - c_fraction) * cd_len * d2).Normalize(); + } while (S2EdgeUtil::RobustCrossing(a, b, c, d) <= 0); + + // Each constructed edge should be at most 1.5 * DBL_EPSILON away from the + // original point P. + EXPECT_LE(S2EdgeUtil::GetDistance(p, a, b), + S1Angle::Radians(1.5 * DBL_EPSILON) + kGetDistanceAbsError); + EXPECT_LE(S2EdgeUtil::GetDistance(p, c, d), + S1Angle::Radians(1.5 * DBL_EPSILON) + kGetDistanceAbsError); + + // Verify that the expected intersection point is close to both edges and + // also close to the original point P. (It might not be very close to P + // if the angle between the edges is very small.) + S2Point expected = S2EdgeUtilTesting::GetIntersectionExact(a, b, c, d); + EXPECT_LE(S2EdgeUtil::GetDistance(expected, a, b), + S1Angle::Radians(3 * DBL_EPSILON) + kGetDistanceAbsError); + EXPECT_LE(S2EdgeUtil::GetDistance(expected, c, d), + S1Angle::Radians(3 * DBL_EPSILON) + kGetDistanceAbsError); + EXPECT_LE(S1Angle(expected, p), + S1Angle::Radians(3 * DBL_EPSILON / slope) + + S2EdgeUtil::kIntersectionError); + + // Now we actually test the GetIntersection() method. + S2Point actual = S2EdgeUtilTesting::GetIntersection(a, b, c, d); + S1Angle dist_ab = S2EdgeUtil::GetDistance(actual, a, b); + S1Angle dist_cd = S2EdgeUtil::GetDistance(actual, c, d); + EXPECT_LE(dist_ab, S2EdgeUtil::kIntersectionError + kGetDistanceAbsError); + EXPECT_LE(dist_cd, S2EdgeUtil::kIntersectionError + kGetDistanceAbsError); max_edge_dist = max(max_edge_dist, max(dist_ab, dist_cd)); - max_point_dist = max(max_point_dist, S1Angle(p, x)); + S1Angle point_dist(expected, actual); + EXPECT_LE(point_dist, S2EdgeUtil::kIntersectionError); + max_point_dist = max(max_point_dist, point_dist); } + S2EdgeUtilTesting::PrintIntersectionStats(); LOG(INFO) << "Max distance to either edge being intersected: " << max_edge_dist.radians(); LOG(INFO) << "Maximum distance to expected intersection point: " << max_point_dist.radians(); } +// Chooses a point in the XY plane that is separated from X by at least 1e-15 +// (to avoid choosing too many duplicate points) and by at most Pi/2 - 1e-3 +// (to avoid nearly-diametric edges, since the test below is not sophisticated +// enough to test such edges). +static S2Point ChooseSemicirclePoint(S2Point const& x, S2Point const& y) { + S2Testing::Random* rnd = &S2Testing::rnd; + double sign = (2 * rnd->Uniform(2)) - 1; + return (x + sign * 1e3 * pow(1e-18, rnd->RandDouble()) * y).Normalize(); +} + +TEST(S2EdgeUtil, GrazingIntersections) { + // This test choose 5 points along a great circle (i.e., as collinear as + // possible), and uses them to construct an edge AB and a triangle CDE such + // that CD and CE both cross AB. It then checks that the intersection + // points returned by GetIntersection() have the correct relative ordering + // along AB (to within kIntersectionError). + for (int iter = 0; iter < 1000; ++iter) { + Vector3_d x, y, z; + S2Testing::GetRandomFrame(&x, &y, &z); + S2Point a, b, c, d, e, ab; + do { + a = ChooseSemicirclePoint(x, y); + b = ChooseSemicirclePoint(x, y); + c = ChooseSemicirclePoint(x, y); + d = ChooseSemicirclePoint(x, y); + e = ChooseSemicirclePoint(x, y); + ab = (a - b).CrossProd(a + b); + } while (ab.Norm() < 50 * DBL_EPSILON || + S2EdgeUtil::RobustCrossing(a, b, c, d) <= 0 || + S2EdgeUtil::RobustCrossing(a, b, c, e) <= 0); + S2Point xcd = S2EdgeUtilTesting::GetIntersection(a, b, c, d); + S2Point xce = S2EdgeUtilTesting::GetIntersection(a, b, c, e); + // Essentially this says that if CDE and CAB have the same orientation, + // then CD and CE should intersect along AB in that order. + ab = ab.Normalize(); + if (S1Angle(xcd, xce) > 2 * S2EdgeUtil::kIntersectionError) { + EXPECT_EQ(S2::RobustCCW(c, d, e) == S2::RobustCCW(c, a, b), + S2::RobustCCW(ab, xcd, xce) > 0); + } + } + S2EdgeUtilTesting::PrintIntersectionStats(); +} + +TEST(S2EdgeUtil, GetIntersectionInvariants) { + // Test that the result of GetIntersection does not change when the edges + // are swapped and/or reversed. The number of iterations is high because it + // is difficult to generate test cases that show that CompareEdges() is + // necessary and correct, for example. + const int kIters = google::DEBUG_MODE ? 5000 : 50000; + for (int iter = 0; iter < kIters; ++iter) { + S2Point a, b, c, d; + do { + // GetIntersectionStable() sorts the two edges by length, so construct + // edges (a,b) and (c,d) that cross and have exactly the same length. + // This can be done by swapping the "x" and "y" coordinates. + // [Swapping other coordinate pairs doesn't work because it changes the + // order of addition in Norm2() == (x**2 + y**2) + z**2.] + a = c = S2Testing::RandomPoint(); + b = d = S2Testing::RandomPoint(); + swap(c[0], c[1]); + swap(d[0], d[1]); + } while (S2EdgeUtil::RobustCrossing(a, b, c, d) <= 0); + EXPECT_EQ((a - b).Norm2(), (c - d).Norm2()); + + // Now verify that GetIntersection returns exactly the same result when + // the edges are swapped and/or reversed. + S2Point result = S2EdgeUtil::GetIntersection(a, b, c, d); + if (S2Testing::rnd.OneIn(2)) { swap(a, b); } + if (S2Testing::rnd.OneIn(2)) { swap(c, d); } + if (S2Testing::rnd.OneIn(2)) { swap(a, c); swap(b, d); } + EXPECT_EQ(result, S2EdgeUtil::GetIntersection(a, b, c, d)); + } +} + bool IsEdgeBNearEdgeA(string const& a_str, const string& b_str, double max_error_degrees) { - scoped_ptr a(S2Testing::MakePolyline(a_str)); + unique_ptr a(s2textformat::MakePolyline(a_str)); EXPECT_EQ(2, a->num_vertices()); - scoped_ptr b(S2Testing::MakePolyline(b_str)); + unique_ptr b(s2textformat::MakePolyline(b_str)); EXPECT_EQ(2, b->num_vertices()); return S2EdgeUtil::IsEdgeBNearEdgeA(a->vertex(0), a->vertex(1), b->vertex(0), b->vertex(1), @@ -1160,6 +1309,3 @@ TEST(S2EdgeUtil, EdgeClipping) { TestEdgeClipping(R2Rect::Empty()); } - - -} // namespace \ No newline at end of file diff --git a/src/s2error.cc b/src/s2error.cc index 236698b9..05f850c0 100644 --- a/src/s2error.cc +++ b/src/s2error.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2error.h" @@ -25,4 +26,4 @@ void S2Error::Init(Code code, const char* format, ...) { va_start(ap, format); StringAppendV(&text_, format, ap); va_end(ap); -} \ No newline at end of file +} diff --git a/src/s2error.h b/src/s2error.h index 950bd5bd..2e7f21e2 100644 --- a/src/s2error.h +++ b/src/s2error.h @@ -12,17 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) // // S2Error is a simple class consisting of an error code and a human-readable // error message. -#ifndef UTIL_GEOMETRY_S2ERROR_H_ -#define UTIL_GEOMETRY_S2ERROR_H_ +#ifndef S2_GEOMETRY_S2ERROR_H_ +#define S2_GEOMETRY_S2ERROR_H_ -#include #include + +#include #include + #include "base/port.h" class S2Error { @@ -42,6 +45,16 @@ class S2Error { POLYGON_LOOPS_CROSS = 201, // Two polygon loops cross. POLYGON_EMPTY_LOOP = 202, // Polygon has an empty loop. POLYGON_EXCESS_FULL_LOOP = 203, // Non-full polygon has a full loop. + + // InitOriented() was called and detected inconsistent loop orientations. + POLYGON_INCONSISTENT_LOOP_ORIENTATIONS = 204, + + // Loop depths don't correspond to any valid nesting hierarchy. + POLYGON_INVALID_LOOP_DEPTH = 205, + + // Actual polygon nesting does not correspond to the nesting hierarchy + // encoded by the loop depths. + POLYGON_INVALID_LOOP_NESTING = 206, }; S2Error() : code_(NO_ERROR), text_() {} @@ -63,4 +76,4 @@ inline std::ostream& operator<<(std::ostream& os, S2Error const& error) { return os << error.text(); } -#endif // UTIL_GEOMETRY_S2ERROR_H_ \ No newline at end of file +#endif // S2_GEOMETRY_S2ERROR_H_ diff --git a/src/s2error_test.cc b/src/s2error_test.cc index 66c36317..acb024e6 100644 --- a/src/s2error_test.cc +++ b/src/s2error_test.cc @@ -12,11 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2error.h" -#include "gtest/gtest.h" +#include TEST(S2Error, Basic) { S2Error error; @@ -27,4 +28,4 @@ TEST(S2Error, Basic) { "Loop %d: %s", 5, error.text().c_str()); EXPECT_EQ(S2Error::DUPLICATE_VERTICES, error.code()); EXPECT_EQ("Loop 5: Vertex 23 is the same as vertex 47", error.text()); -} \ No newline at end of file +} diff --git a/src/s2latlng.cc b/src/s2latlng.cc index 4204052b..22ba1ede 100644 --- a/src/s2latlng.cc +++ b/src/s2latlng.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2latlng.h" @@ -95,4 +96,4 @@ void S2LatLng::ToStringInDegrees(string* s) const { std::ostream& operator<<(std::ostream& os, S2LatLng const& ll) { return os << "[" << ll.lat() << ", " << ll.lng() << "]"; -} \ No newline at end of file +} diff --git a/src/s2latlng.h b/src/s2latlng.h index 10e2e30d..0dc60b5d 100644 --- a/src/s2latlng.h +++ b/src/s2latlng.h @@ -12,10 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2LATLNG_H__ -#define UTIL_GEOMETRY_S2LATLNG_H__ +#ifndef S2_GEOMETRY_S2LATLNG_H__ +#define S2_GEOMETRY_S2LATLNG_H__ #include #include @@ -23,7 +24,7 @@ #include #include "base/integral_types.h" -#include "base/type_traits.h" +#include "fpcontractoff.h" #include "r2.h" #include "s1angle.h" #include "s2.h" @@ -42,35 +43,35 @@ class S2LatLng { // Constructor. The latitude and longitude are allowed to be outside // the is_valid() range. However, note that most methods that accept // S2LatLngs expect them to be normalized (see Normalized() below). - inline S2LatLng(S1Angle lat, S1Angle lng); + S2LatLng(S1Angle lat, S1Angle lng); // The default constructor sets the latitude and longitude to zero. This is // mainly useful when declaring arrays, STL containers, etc. - inline S2LatLng(); + S2LatLng(); // Convert a direction vector (not necessarily unit length) to an S2LatLng. explicit S2LatLng(S2Point const& p); // Returns an S2LatLng for which is_valid() will return false. - inline static S2LatLng Invalid(); + static S2LatLng Invalid(); // Convenience functions -- shorter than calling S1Angle::Radians(), etc. - inline static S2LatLng FromRadians(double lat_radians, double lng_radians); - inline static S2LatLng FromDegrees(double lat_degrees, double lng_degrees); - inline static S2LatLng FromE5(int32 lat_e5, int32 lng_e5); - inline static S2LatLng FromE6(int32 lat_e6, int32 lng_e6); - inline static S2LatLng FromE7(int32 lat_e7, int32 lng_e7); + static S2LatLng FromRadians(double lat_radians, double lng_radians); + static S2LatLng FromDegrees(double lat_degrees, double lng_degrees); + static S2LatLng FromE5(int32 lat_e5, int32 lng_e5); + static S2LatLng FromE6(int32 lat_e6, int32 lng_e6); + static S2LatLng FromE7(int32 lat_e7, int32 lng_e7); // Convenience functions -- to use when args have been fixed32s in protos. // // The arguments are static_cast into int32, so very large unsigned values // are treated as negative numbers. - inline static S2LatLng FromUnsignedE6(uint32 lat_e6, uint32 lng_e6); - inline static S2LatLng FromUnsignedE7(uint32 lat_e7, uint32 lng_e7); + static S2LatLng FromUnsignedE6(uint32 lat_e6, uint32 lng_e6); + static S2LatLng FromUnsignedE7(uint32 lat_e7, uint32 lng_e7); // Methods to compute the latitude and longitude of a point separately. - inline static S1Angle Latitude(S2Point const& p); - inline static S1Angle Longitude(S2Point const& p); + static S1Angle Latitude(S2Point const& p); + static S1Angle Longitude(S2Point const& p); // Accessor methods. S1Angle lat() const { return S1Angle::Radians(coords_[0]); } @@ -79,7 +80,7 @@ class S2LatLng { // Return true if the latitude is between -90 and 90 degrees inclusive // and the longitude is between -180 and 180 degrees inclusive. - inline bool is_valid() const; + bool is_valid() const; // Clamps the latitude to the range [-90, 90] degrees, and adds or subtracts // a multiple of 360 degrees to the longitude if necessary to reduce it to @@ -100,10 +101,10 @@ class S2LatLng { // Simple arithmetic operations for manipulating latitude-longitude pairs. // The results are not normalized (see Normalized()). - friend inline S2LatLng operator+(S2LatLng const& a, S2LatLng const& b); - friend inline S2LatLng operator-(S2LatLng const& a, S2LatLng const& b); - friend inline S2LatLng operator*(double m, S2LatLng const& a); - friend inline S2LatLng operator*(S2LatLng const& a, double m); + friend S2LatLng operator+(S2LatLng const& a, S2LatLng const& b); + friend S2LatLng operator-(S2LatLng const& a, S2LatLng const& b); + friend S2LatLng operator*(double m, S2LatLng const& a); + friend S2LatLng operator*(S2LatLng const& a, double m); bool operator==(S2LatLng const& o) const { return coords_ == o.coords_; } bool operator!=(S2LatLng const& o) const { return coords_ != o.coords_; } @@ -123,10 +124,10 @@ class S2LatLng { private: // Internal constructor. - inline S2LatLng(R2Point const& coords) : coords_(coords) {} + explicit S2LatLng(R2Point const& coords) : coords_(coords) {} // This is internal to avoid ambiguity about which units are expected. - inline S2LatLng(double lat_radians, double lng_radians) + S2LatLng(double lat_radians, double lng_radians) : coords_(lat_radians, lng_radians) {} R2Point coords_; @@ -203,4 +204,4 @@ inline S2LatLng operator*(S2LatLng const& a, double m) { std::ostream& operator<<(std::ostream& os, S2LatLng const& ll); -#endif // UTIL_GEOMETRY_S2LATLNG_H__ \ No newline at end of file +#endif // S2_GEOMETRY_S2LATLNG_H__ diff --git a/src/s2latlng_test.cc b/src/s2latlng_test.cc index 53214067..921881dc 100644 --- a/src/s2latlng_test.cc +++ b/src/s2latlng_test.cc @@ -12,15 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2latlng.h" +#include + #include #include "base/macros.h" #include "base/stringprintf.h" -#include "strings/split.h" -#include "gtest/gtest.h" +#include #include "s2testing.h" TEST(S2LatLng, TestBasic) { @@ -124,11 +126,8 @@ TEST(S2LatLng, TestToString) { string output; p.ToStringInDegrees(&output); - const char *ptr = output.c_str(); double lat, lng; - EXPECT_TRUE(SplitOneDoubleToken(&ptr, ",", &lat)); - ASSERT_TRUE(ptr != NULL); - EXPECT_TRUE(SplitOneDoubleToken(&ptr, ",", &lng)); + ASSERT_EQ(2, std::sscanf(output.c_str(), "%lf,%lf", &lat, &lng)); EXPECT_NEAR(values[i].expected_lat, lat, 1e-8); EXPECT_NEAR(values[i].expected_lng, lng, 1e-8); } @@ -141,3 +140,4 @@ TEST(S2LatLng, TestToStringReturnsString) { EXPECT_EQ(S2LatLng::FromDegrees(0, 1).ToStringInDegrees(), s); } + diff --git a/src/s2latlngrect.cc b/src/s2latlngrect.cc index 3e80fe13..eb91f1ed 100644 --- a/src/s2latlngrect.cc +++ b/src/s2latlngrect.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2latlngrect.h" @@ -314,8 +315,11 @@ bool S2LatLngRect::Decode(Decoder* decoder) { double lng_hi = decoder->getdouble(); lng_ = S1Interval(lng_lo, lng_hi); - DLOG_IF(ERROR, !is_valid()) - << "Invalid result in S2LatLngRect::Decode: " << *this; + if (!is_valid()) { + DLOG_IF(ERROR, FLAGS_s2debug) + << "Invalid result in S2LatLngRect::Decode: " << *this; + return false; + } return true; } @@ -673,4 +677,4 @@ bool S2LatLngRect::ApproxEquals(S2LatLngRect const& other, std::ostream& operator<<(std::ostream& os, S2LatLngRect const& r) { return os << "[Lo" << r.lo() << ", Hi" << r.hi() << "]"; -} \ No newline at end of file +} diff --git a/src/s2latlngrect.h b/src/s2latlngrect.h index f4a28d4d..ddd26df2 100644 --- a/src/s2latlngrect.h +++ b/src/s2latlngrect.h @@ -12,16 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2LATLNGRECT_H_ -#define UTIL_GEOMETRY_S2LATLNGRECT_H_ +#ifndef S2_GEOMETRY_S2LATLNGRECT_H_ +#define S2_GEOMETRY_S2LATLNGRECT_H_ #include #include #include #include +#include "fpcontractoff.h" #include "r1interval.h" #include "s1angle.h" #include "s1interval.h" @@ -63,16 +65,16 @@ class S2LatLngRect : public S2Region { // line. Both points must be normalized, with lo.lat() <= hi.lat(). // The rectangle contains all the points p such that 'lo' <= p <= 'hi', // where '<=' is defined in the obvious way. - inline S2LatLngRect(S2LatLng const& lo, S2LatLng const& hi); + S2LatLngRect(S2LatLng const& lo, S2LatLng const& hi); // Construct a rectangle from latitude and longitude intervals. The two // intervals must either be both empty or both non-empty, and the latitude // interval must not extend outside [-90, +90] degrees. // Note that both intervals (and hence the rectangle) are closed. - inline S2LatLngRect(R1Interval const& lat, S1Interval const& lng); + S2LatLngRect(R1Interval const& lat, S1Interval const& lng); // The default constructor creates an empty S2LatLngRect. - inline S2LatLngRect(); + S2LatLngRect(); // Construct a rectangle of the given size centered around the given point. // "center" needs to be normalized, but "size" does not. The latitude @@ -111,9 +113,9 @@ class S2LatLngRect : public S2Region { // The canonical empty and full rectangles, as derived from the Empty // and Full R1 and S1 Intervals. // Empty: lat_lo=1, lat_hi=0, lng_lo=Pi, lng_hi=-Pi (radians) - static inline S2LatLngRect Empty(); + static S2LatLngRect Empty(); // Full: lat_lo=-Pi/2, lat_hi=Pi/2, lng_lo=-Pi, lng_hi=Pi (radians) - static inline S2LatLngRect Full(); + static S2LatLngRect Full(); // The full allowable range of latitudes and longitudes. static R1Interval FullLat() { return R1Interval(-M_PI_2, M_PI_2); } @@ -123,16 +125,16 @@ class S2LatLngRect : public S2Region { // that the latitude bounds do not exceed Pi/2 in absolute value and // the longitude bounds do not exceed Pi in absolute value. Also, if // either the latitude or longitude bound is empty then both must be. - inline bool is_valid() const; + bool is_valid() const; // Return true if the rectangle is empty, i.e. it contains no points at all. - inline bool is_empty() const; + bool is_empty() const; // Return true if the rectangle is full, i.e. it contains all points. - inline bool is_full() const; + bool is_full() const; // Return true if the rectangle is a point, i.e. lo() == hi() - inline bool is_point() const; + bool is_point() const; // Return true if lng_.lo() > lng_.hi(), i.e. the rectangle crosses // the 180 degree longitude line. @@ -261,10 +263,10 @@ class S2LatLngRect : public S2Region { S1Angle GetHausdorffDistance(S2LatLngRect const& other) const; // Return true if two rectangles contains the same set of points. - inline bool operator==(S2LatLngRect const& other) const; + bool operator==(S2LatLngRect const& other) const; // Return the opposite of what operator == returns. - inline bool operator!=(S2LatLngRect const& other) const; + bool operator!=(S2LatLngRect const& other) const; // Return true if the latitude and longitude intervals of the two rectangles // are the same up to the given tolerance (see r1interval.h and s1interval.h @@ -308,7 +310,7 @@ class S2LatLngRect : public S2Region { static bool IntersectsLatEdge(S2Point const& a, S2Point const& b, double lat, S1Interval const& lng); - private: + private: // Helper function. See .cc for description. static S1Angle GetDirectedHausdorffDistance(double lng_diff, R1Interval const& a_lat, @@ -380,4 +382,4 @@ inline bool S2LatLngRect::operator!=(S2LatLngRect const& other) const { std::ostream& operator<<(std::ostream& os, S2LatLngRect const& r); -#endif // UTIL_GEOMETRY_S2LATLNGRECT_H_ \ No newline at end of file +#endif // S2_GEOMETRY_S2LATLNGRECT_H_ diff --git a/src/s2latlngrect_test.cc b/src/s2latlngrect_test.cc index 403c2300..0e1d757a 100644 --- a/src/s2latlngrect_test.cc +++ b/src/s2latlngrect_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) // // Most of the S2LatLngRect methods have trivial implementations that @@ -22,7 +23,7 @@ #include -#include "gtest/gtest.h" +#include #include "util/coding/coder.h" #include "s2cap.h" #include "s2cell.h" @@ -826,4 +827,4 @@ TEST(S2LatLngRect, GetDirectedHausdorffDistanceRectToRectDegenerateCases) { RectFromDegrees(-20, 105, 20, 110), RectFromDegrees(-30, 5, 30, 15)); VerifyGetDirectedHausdorffDistance( RectFromDegrees(-20, 95, 20, 105), RectFromDegrees(-30, 5, 30, 15)); -} \ No newline at end of file +} diff --git a/src/s2loop.cc b/src/s2loop.cc index 83f28d8c..84c9935f 100644 --- a/src/s2loop.cc +++ b/src/s2loop.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2loop.h" @@ -58,6 +59,13 @@ DEFINE_bool( "never queried, for example when loops are passed directly to S2Polygon, " "or when geometry is being converted from one format to another."); +// The maximum number of vertices we'll allow when decoding a loop. +// The default value of 50 million is about 30x bigger than the number of +DEFINE_int32( + s2polygon_decode_max_num_vertices, 50000000, + "The upper limit on the number of loops that are allowed by the " + "S2Polygon::Decode method."); + static const unsigned char kCurrentLosslessEncodingVersionNumber = 1; // Boolean properties for compressed loops. @@ -74,6 +82,7 @@ S2Loop::S2Loop() vertices_(NULL), owns_vertices_(false), s2debug_override_(ALLOW_S2DEBUG), + origin_inside_(false), shape_(this) { // Some fields are initialized by Init(). The loop is not valid until then. } @@ -265,7 +274,7 @@ void S2Loop::InitBound() { } void S2Loop::InitIndex() { - index_.Insert(&shape_); + index_.Add(&shape_); if (!FLAGS_s2loop_lazy_indexing) { index_.ForceApplyUpdates(); // Force index construction now. } @@ -408,7 +417,7 @@ double S2Loop::GetArea() const { // loop vertices). The big advantage of this method is that as long as we // use S2::RobustCCW() to compute the turning angle at each vertex, then // degeneracies are always handled correctly. In other words, if a - // degenerate loop is CCW according the the symbolic perturbations used by + // degenerate loop is CCW according to the symbolic perturbations used by // S2::RobustCCW(), then its turning angle will be approximately 2*Pi. // // The disadvantage of the Gauss-Bonnet method is that its absolute error is @@ -753,9 +762,14 @@ bool S2Loop::DecodeWithinScope(Decoder* const decoder) { bool S2Loop::DecodeInternal(Decoder* const decoder, bool within_scope) { - // Perform all checks before modifying vertex state. + // Perform all checks before modifying vertex state. Empty loops are + // explicitly allowed here: a newly created loop has zero vertices + // and such loops encode and decode properly. if (decoder->avail() < sizeof(uint32)) return false; - int const num_vertices = decoder->get32(); + uint32 const num_vertices = decoder->get32(); + if (num_vertices > FLAGS_s2polygon_decode_max_num_vertices) { + return false; + } if (decoder->avail() < (num_vertices * sizeof(*vertices_) + sizeof(uint8) + sizeof(uint32))) { return false; @@ -787,7 +801,15 @@ bool S2Loop::DecodeInternal(Decoder* const decoder, depth_ = decoder->get32(); if (!bound_.Decode(decoder)) return false; subregion_bound_ = S2EdgeUtil::RectBounder::ExpandForSubregions(bound_); - InitIndex(); + + // An initialized loop will have some non-zero count of vertices. A default + // (uninitialized) has zero vertices. This code supports encoding and + // decoding of uninitialized loops, but we only want to call InitIndex for + // initialized loops. Otherwise we defer InitIndex until the call to Init(). + if (num_vertices > 0) { + InitIndex(); + } + return true; } @@ -1388,6 +1410,14 @@ bool S2Loop::ContainsNested(S2Loop const* b) const { b->vertex(0), b->vertex(2)); } +bool S2Loop::Equals(S2Loop const* b) const { + if (num_vertices() != b->num_vertices()) return false; + for (int i = 0; i < num_vertices(); ++i) { + if (vertex(i) != b->vertex(i)) return false; + } + return true; +} + bool S2Loop::BoundaryEquals(S2Loop const* b) const { if (num_vertices() != b->num_vertices()) return false; @@ -1498,9 +1528,6 @@ void S2Loop::GetXYZFaceSiTiVertices(S2XYZFaceSiTi* vertices) const { void S2Loop::EncodeCompressed(Encoder* encoder, S2XYZFaceSiTi const* vertices, int snap_level) const { - // All methods require valid polygons. - if (FLAGS_s2debug) CHECK(IsValid()); - // Ensure enough for the data we write before S2EncodePointsCompressed. // S2EncodePointsCompressed ensures its space. encoder->Ensure(Encoder::kVarintMax32); @@ -1528,6 +1555,10 @@ bool S2Loop::DecodeCompressed(Decoder* decoder, int snap_level) { if (!decoder->get_varint32(&unsigned_num_vertices)) { return false; } + if (unsigned_num_vertices == 0 || + unsigned_num_vertices > FLAGS_s2polygon_decode_max_num_vertices) { + return false; + } ResetMutableFields(); if (owns_vertices_) delete[] vertices_; num_vertices_ = unsigned_num_vertices; @@ -1601,3 +1632,4 @@ S2Loop* S2Loop::MakeRegularLoop(S2Point const& center, } return new S2Loop(vertices); } + diff --git a/src/s2loop.h b/src/s2loop.h index 339d44fe..38cff458 100644 --- a/src/s2loop.h +++ b/src/s2loop.h @@ -12,10 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2LOOP_H__ -#define UTIL_GEOMETRY_S2LOOP_H__ +#ifndef S2_GEOMETRY_S2LOOP_H__ +#define S2_GEOMETRY_S2LOOP_H__ #include #include @@ -26,6 +27,7 @@ #include "base/integral_types.h" #include #include "base/macros.h" +#include "fpcontractoff.h" #include "s1angle.h" #include "s2.h" #include "s2edgeutil.h" @@ -105,11 +107,11 @@ class S2Loop : public S2Region { // // The loop may be safely encoded lossily (e.g. by snapping it to an S2Cell // center) as long as its position does not move by 90 degrees or more. - inline static std::vector kEmpty(); + static std::vector kEmpty(); // A special vertex chain of length 1 that creates a full loop (i.e., a loop // with no edges that contains all points). See kEmpty() for details. - inline static std::vector kFull(); + static std::vector kFull(); // Construct a loop corresponding to the given cell. // @@ -166,13 +168,13 @@ class S2Loop : public S2Region { } // Return true if this is the special "empty" loop that contains no points. - inline bool is_empty() const; + bool is_empty() const; // Return true if this is the special "full" loop that contains all points. - inline bool is_full() const; + bool is_full() const; // Return true if this loop is either "empty" or "full". - inline bool is_empty_or_full() const; + bool is_empty_or_full() const; // The depth of a loop is defined as its nesting level within its containing // polygon. "Outer shell" loops have depth 0, holes within those loops have @@ -263,16 +265,20 @@ class S2Loop : public S2Region { // contained by the given other loop. bool Intersects(S2Loop const* b) const; + // Return true if two loops have the same vertices in the same linear order + // (i.e., cyclic rotations are not allowed). + bool Equals(S2Loop const* b) const; + // Return true if two loops have the same boundary. This is true if and - // only if the loops have the same vertices in the same cyclic order. The - // empty and full loops are considered to have different boundaries. - // (For testing purposes.) + // only if the loops have the same vertices in the same cyclic order (i.e., + // the vertices may be cyclically rotated). The empty and full loops are + // considered to have different boundaries. bool BoundaryEquals(S2Loop const* b) const; // Return true if two loops have the same boundary except for vertex // perturbations. More precisely, the vertices in the two loops must be in // the same cyclic order, and corresponding vertex pairs must be separated - // by no more than "max_error". (For testing purposes.) + // by no more than "max_error". bool BoundaryApproxEquals(S2Loop const* b, double max_error = 1e-15) const; // Return true if the two loop boundaries are within "max_error" of each @@ -282,7 +288,7 @@ class S2Loop : public S2Region { // distance(a(t), b(t)) <= max_error for all t. You can think of this as // testing whether it is possible to drive two cars all the way around the // two loops such that no car ever goes backward and the cars are always - // within "max_error" of each other. (For testing purposes.) + // within "max_error" of each other. bool BoundaryNear(S2Loop const* b, double max_error = 1e-15) const; // This method computes the oriented surface integral of some quantity f(x) @@ -434,10 +440,10 @@ class S2Loop : public S2Region { bool contains_origin() const { return origin_inside_; } // The single vertex in the "empty loop" vertex chain. - inline static S2Point kEmptyVertex(); + static S2Point kEmptyVertex(); // The single vertex in the "full loop" vertex chain. - inline static S2Point kFullVertex(); + static S2Point kFullVertex(); void InitOriginAndBound(); void InitBound(); @@ -706,4 +712,4 @@ T S2Loop::GetSurfaceIntegral(T f_tri(S2Point const&, S2Point const&, return sum; } -#endif // UTIL_GEOMETRY_S2LOOP_H__ \ No newline at end of file +#endif // S2_GEOMETRY_S2LOOP_H__ diff --git a/src/s2loop_test.cc b/src/s2loop_test.cc index 82e2b648..e721ba31 100644 --- a/src/s2loop_test.cc +++ b/src/s2loop_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2loop.h" @@ -28,8 +29,7 @@ #include "base/casts.h" #include #include -#include "base/scoped_ptr.h" -#include "gtest/gtest.h" +#include #include "util/coding/coder.h" #include "r1interval.h" #include "s1angle.h" @@ -41,6 +41,7 @@ #include "s2latlng.h" #include "s2pointcompression.h" #include "s2testing.h" +#include "s2textformat.h" #include "util/gtl/fixedarray.h" #include "util/math/matrix3x3.h" #include "util/math/vector3.h" @@ -49,6 +50,7 @@ using std::map; using std::max; using std::min; using std::set; +using std::unique_ptr; using std::vector; @@ -90,7 +92,7 @@ class S2LoopTestBase : public testing::Test { private: S2Loop const* AddLoop(string const& str) { - return AddLoop(S2Testing::MakeLoop(str)); + return AddLoop(s2textformat::MakeLoop(str)); } S2Loop const* AddLoop(S2Loop const* loop) { @@ -208,13 +210,13 @@ class S2LoopTestBase : public testing::Test { // Like loop_a, but the vertices are at leaf cell centers. vector snapped_loop_a_vertices; snapped_loop_a_vertices.push_back( - S2CellId::FromPoint(S2Testing::MakePoint("0:178")).ToPoint()); + S2CellId::FromPoint(s2textformat::MakePoint("0:178")).ToPoint()); snapped_loop_a_vertices.push_back( - S2CellId::FromPoint(S2Testing::MakePoint("-1:180")).ToPoint()); + S2CellId::FromPoint(s2textformat::MakePoint("-1:180")).ToPoint()); snapped_loop_a_vertices.push_back( - S2CellId::FromPoint(S2Testing::MakePoint("0:-179")).ToPoint()); + S2CellId::FromPoint(s2textformat::MakePoint("0:-179")).ToPoint()); snapped_loop_a_vertices.push_back( - S2CellId::FromPoint(S2Testing::MakePoint("1:-180")).ToPoint()); + S2CellId::FromPoint(s2textformat::MakePoint("1:-180")).ToPoint()); snapped_loop_a = new S2Loop(snapped_loop_a_vertices); AddLoop(snapped_loop_a); } @@ -256,7 +258,7 @@ TEST_F(S2LoopTestBase, GetRectBound) { S2LatLng::FromDegrees(-80, 180)), kRectError)); // Create a loop that contains the complement of the "arctic_80" loop. - scoped_ptr arctic_80_inv(arctic_80->Clone()); + unique_ptr arctic_80_inv(arctic_80->Clone()); arctic_80_inv->Invert(); // The highest latitude of each edge is attained at its midpoint. S2Point mid = 0.5 * (arctic_80_inv->vertex(0) + arctic_80_inv->vertex(1)); @@ -268,7 +270,7 @@ TEST_F(S2LoopTestBase, GetRectBound) { R1Interval(-M_PI_2, 0), kRectError.lat().radians())); } -static void Rotate(scoped_ptr* ptr) { +static void Rotate(unique_ptr* ptr) { S2Loop* loop = ptr->get(); vector vertices; for (int i = 1; i <= loop->num_vertices(); ++i) { @@ -289,7 +291,7 @@ TEST_F(S2LoopTestBase, AreaConsistentWithTurningAngle) { // TODO(ericv): The error bound below is much larger than it should be. // Need to improve the error minimization analysis in S2::Area(). EXPECT_LE(fabs(area - gauss_area), 1e-9) - << "Failed loop: " << S2Testing::ToString(loop) + << "Failed loop: " << s2textformat::ToString(loop) << "\nArea = " << area << ", Gauss Area = " << gauss_area; } } @@ -321,7 +323,7 @@ TEST_F(S2LoopTestBase, GetAreaConsistentWithRobustCCW) { // TODO(ericv): The error bound below is much larger than it should be. // Need to improve the error minimization analysis in S2::Area(). EXPECT_NEAR(ccw ? 0 : 4 * M_PI, loop.GetArea(), 1e-8) - << "Failed loop " << i << ": " << S2Testing::ToString(&loop); + << "Failed loop " << i << ": " << s2textformat::ToString(&loop); EXPECT_EQ(!ccw, loop.Contains(S2Point(0, 0, 1))); } } @@ -385,7 +387,7 @@ TEST_F(S2LoopTestBase, GetAreaAndCentroid) { // rotated, and that the sign is inverted when the vertices are reversed. static void CheckTurningAngleInvariants(S2Loop const* loop) { double expected = loop->GetTurningAngle(); - scoped_ptr loop_copy(down_cast(loop->Clone())); + unique_ptr loop_copy(down_cast(loop->Clone())); for (int i = 0; i < loop->num_vertices(); ++i) { loop_copy->Invert(); EXPECT_EQ(-expected, loop_copy->GetTurningAngle()); @@ -449,9 +451,9 @@ TEST_F(S2LoopTestBase, GetTurningAngle) { // Checks that if a loop is normalized, it doesn't contain a // point outside of it, and vice versa. static void CheckNormalizeAndContains(S2Loop const* loop) { - S2Point p = S2Testing::MakePoint("40:40"); + S2Point p = s2textformat::MakePoint("40:40"); - scoped_ptr flip(loop->Clone()); + unique_ptr flip(loop->Clone()); flip->Invert(); EXPECT_TRUE(loop->IsNormalized() ^ loop->Contains(p)); EXPECT_TRUE(flip->IsNormalized() ^ flip->Contains(p)); @@ -476,10 +478,10 @@ TEST_F(S2LoopTestBase, Contains) { EXPECT_TRUE(candy_cane->Contains(S2LatLng::FromDegrees(5, 71).ToPoint())); // Create copies of these loops so that we can change the vertex order. - scoped_ptr north_copy(north_hemi->Clone()); - scoped_ptr south_copy(south_hemi->Clone()); - scoped_ptr west_copy(west_hemi->Clone()); - scoped_ptr east_copy(east_hemi->Clone()); + unique_ptr north_copy(north_hemi->Clone()); + unique_ptr south_copy(south_hemi->Clone()); + unique_ptr west_copy(west_hemi->Clone()); + unique_ptr east_copy(east_hemi->Clone()); for (int i = 0; i < 4; ++i) { EXPECT_TRUE(north_copy->Contains(S2Point(0, 0, 1))); EXPECT_FALSE(north_copy->Contains(S2Point(0, 0, -1))); @@ -614,7 +616,7 @@ static void TestOneDisjointPair(S2Loop const* a, S2Loop const* b) { static void TestOneCoveringPair(S2Loop const* a, S2Loop const* b) { EXPECT_EQ(a->is_full(), a->Contains(b)); EXPECT_EQ(b->is_full(), b->Contains(a)); - scoped_ptr a1(a->Clone()); + unique_ptr a1(a->Clone()); a1->Invert(); bool complementary = a1->BoundaryEquals(b); EXPECT_EQ(!complementary, a->Intersects(b)); @@ -633,8 +635,8 @@ static void TestOneOverlappingPair(S2Loop const* a, S2Loop const* b) { // Given a pair of loops where A contains B, test various identities // involving A, B, and their complements. static void TestNestedPair(S2Loop const* a, S2Loop const* b) { - scoped_ptr a1(a->Clone()); - scoped_ptr b1(b->Clone()); + unique_ptr a1(a->Clone()); + unique_ptr b1(b->Clone()); a1->Invert(); b1->Invert(); TestOneNestedPair(a, b); @@ -646,7 +648,7 @@ static void TestNestedPair(S2Loop const* a, S2Loop const* b) { // Given a pair of disjoint loops A and B, test various identities // involving A, B, and their complements. static void TestDisjointPair(S2Loop const* a, S2Loop const* b) { - scoped_ptr a1(a->Clone()); + unique_ptr a1(a->Clone()); a1->Invert(); TestNestedPair(a1.get(), b); } @@ -654,7 +656,7 @@ static void TestDisjointPair(S2Loop const* a, S2Loop const* b) { // Given loops A and B whose union covers the sphere, test various identities // involving A, B, and their complements. static void TestCoveringPair(S2Loop const* a, S2Loop const* b) { - scoped_ptr b1(b->Clone()); + unique_ptr b1(b->Clone()); b1->Invert(); TestNestedPair(a, b1.get()); } @@ -662,8 +664,8 @@ static void TestCoveringPair(S2Loop const* a, S2Loop const* b) { // Given loops A and B such that both A and its complement intersect both B // and its complement, test various identities involving these four loops. static void TestOverlappingPair(S2Loop const* a, S2Loop const* b) { - scoped_ptr a1(a->Clone()); - scoped_ptr b1(b->Clone()); + unique_ptr a1(a->Clone()); + unique_ptr b1(b->Clone()); a1->Invert(); b1->Invert(); TestOneOverlappingPair(a, b); @@ -888,8 +890,8 @@ TEST(S2Loop, LoopRelations2) { S2CellId b_end = b_begin.advance(rnd.Skewed(6) + 1); if (!a_end.is_valid() || !b_end.is_valid()) continue; - scoped_ptr a(MakeCellLoop(a_begin, a_end)); - scoped_ptr b(MakeCellLoop(b_begin, b_end)); + unique_ptr a(MakeCellLoop(a_begin, a_end)); + unique_ptr b(MakeCellLoop(b_begin, b_end)); if (a.get() && b.get()) { bool contained = (a_begin <= b_begin && b_end <= a_end); bool intersects = (a_begin < b_end && b_begin < a_end); @@ -989,8 +991,8 @@ void DebugDumpCrossings(S2Loop const* loop) { static void TestNear(char const* a_str, char const* b_str, double max_error, bool expected) { - scoped_ptr a(S2Testing::MakeLoop(a_str)); - scoped_ptr b(S2Testing::MakeLoop(b_str)); + unique_ptr a(s2textformat::MakeLoop(a_str)); + unique_ptr b(s2textformat::MakeLoop(b_str)); EXPECT_EQ(a->BoundaryNear(b.get(), max_error), expected); EXPECT_EQ(b->BoundaryNear(a.get(), max_error), expected); } @@ -1039,12 +1041,13 @@ static void TestEncodeDecode(S2Loop* loop) { loop->Encode(&encoder); Decoder decoder(encoder.base(), encoder.length()); S2Loop loop2; + loop2.set_s2debug_override(loop->s2debug_override()); ASSERT_TRUE(loop2.Decode(&decoder)); CheckIdentical(loop, &loop2); } TEST(S2Loop, EncodeDecode) { - scoped_ptr l(S2Testing::MakeLoop("30:20, 40:20, 39:43, 33:35")); + unique_ptr l(s2textformat::MakeLoop("30:20, 40:20, 39:43, 33:35")); l->set_depth(3); TestEncodeDecode(l.get()); @@ -1052,6 +1055,9 @@ TEST(S2Loop, EncodeDecode) { TestEncodeDecode(&empty); S2Loop full(S2Loop::kFull()); TestEncodeDecode(&full); + + S2Loop uninitialized; + TestEncodeDecode(&uninitialized); } static void TestEmptyFullSnapped(S2Loop* loop, int level) { @@ -1094,7 +1100,7 @@ TEST(S2Loop, EmptyFullLossyConversions) { } TEST(S2Loop, EncodeDecodeWithinScope) { - scoped_ptr l(S2Testing::MakeLoop("30:20, 40:20, 39:43, 33:35")); + unique_ptr l(s2textformat::MakeLoop("30:20, 40:20, 39:43, 33:35")); l->set_depth(3); Encoder encoder; l->Encode(&encoder); @@ -1124,7 +1130,7 @@ TEST(S2Loop, EncodeDecodeWithinScope) { // Initialize loop2 using Decode with a decoder on different data. // Check that the original memory is not deallocated or overwritten. - scoped_ptr l2(S2Testing::MakeLoop("30:40, 40:75, 39:43, 80:35")); + unique_ptr l2(s2textformat::MakeLoop("30:40, 40:75, 39:43, 80:35")); l2->set_depth(2); Encoder encoder2; l2->Encode(&encoder2); @@ -1153,7 +1159,7 @@ TEST_F(S2LoopTestBase, FourVertexCompressedLoopRequires36Bytes) { } TEST_F(S2LoopTestBase, CompressedEncodedLoopDecodesApproxEqual) { - scoped_ptr loop(snapped_loop_a->Clone()); + unique_ptr loop(snapped_loop_a->Clone()); loop->set_depth(3); Encoder encoder; @@ -1185,10 +1191,10 @@ TEST(S2Loop, S2CellConstructorAndContains) { EXPECT_FALSE(loop_copy.GetRectBound().Contains(cell.GetRectBound())); } -// Construct a loop using S2Testing::MakeLoop(str) and check that it produces +// Construct a loop using s2textformat::MakeLoop(str) and check that it produces // a validation error that includes "snippet". static void CheckLoopIsInvalid(const string& str, const string& snippet) { - scoped_ptr loop(S2Testing::MakeLoop(str)); + unique_ptr loop(s2textformat::MakeLoop(str)); S2Error error; EXPECT_TRUE(loop->FindValidationError(&error)); EXPECT_NE(string::npos, error.text().find(snippet)); @@ -1261,7 +1267,7 @@ TEST_F(S2LoopTestBase, DistanceMethods) { // latitude are curved on the sphere, it is not straightforward to project // points onto any edge except along the equator. (The equator is the only // line of latitude that is also a geodesic.) - scoped_ptr square(S2Testing::MakeLoop("-1:-1, -1:1, 1:1, 1:-1")); + unique_ptr square(s2textformat::MakeLoop("-1:-1, -1:1, 1:1, 1:-1")); EXPECT_TRUE(square->IsNormalized()); // A vertex. @@ -1284,7 +1290,7 @@ TEST_F(S2LoopTestBase, DistanceMethods) { TEST_F(S2LoopTestBase, MakeRegularLoop) { S2Point center = S2LatLng::FromDegrees(80, 135).ToPoint(); S1Angle radius = S1Angle::Degrees(20); - scoped_ptr loop(S2Loop::MakeRegularLoop(center, radius, 4)); + unique_ptr loop(S2Loop::MakeRegularLoop(center, radius, 4)); ASSERT_EQ(4, loop.get()->num_vertices()); S2Point p0 = loop.get()->vertex(0); @@ -1322,3 +1328,4 @@ TEST_F(S2LoopTestBase, MakeRegularLoop) { EXPECT_DOUBLE_EQ(75.524190079054392, S2LatLng(p3).lat().degrees()); EXPECT_DOUBLE_EQ(26.392175948257943, S2LatLng(p3).lng().degrees()); } + diff --git a/src/s2paddedcell.cc b/src/s2paddedcell.cc index 30892670..256891c3 100644 --- a/src/s2paddedcell.cc +++ b/src/s2paddedcell.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2paddedcell.h" @@ -150,7 +151,7 @@ S2CellId S2PaddedCell::ShrinkToFit(R2Rect const& rect) const { // if both pairs of endpoints are equal we choose kMaxLevel; if they differ // only at bit 0, we choose (kMaxLevel - 1), and so on. int level_msb = ((ij_xor[0] | ij_xor[1]) << 1) + 1; - int level = S2CellId::kMaxLevel - Bits::Log2FloorNonZero64(level_msb); + int level = S2CellId::kMaxLevel - Bits::Log2FloorNonZero(level_msb); if (level <= level_) return id(); return S2CellId::FromFaceIJ(id().face(), ij_min[0], ij_min[1]).parent(level); -} \ No newline at end of file +} diff --git a/src/s2paddedcell.h b/src/s2paddedcell.h index 3d73c9f0..dfaaf51f 100644 --- a/src/s2paddedcell.h +++ b/src/s2paddedcell.h @@ -12,11 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2PADDEDCELL_H_ -#define UTIL_GEOMETRY_S2PADDEDCELL_H_ +#ifndef S2_GEOMETRY_S2PADDEDCELL_H_ +#define S2_GEOMETRY_S2PADDEDCELL_H_ +#include "fpcontractoff.h" #include "r2rect.h" #include "s2.h" #include "s2cellid.h" @@ -104,4 +106,4 @@ inline void S2PaddedCell::GetChildIJ(int pos, int* i, int* j) const { *j = ij & 1; } -#endif // UTIL_GEOMETRY_S2PADDEDCELL_H_ \ No newline at end of file +#endif // S2_GEOMETRY_S2PADDEDCELL_H_ diff --git a/src/s2paddedcell_test.cc b/src/s2paddedcell_test.cc index 8f27cc36..bdf2344e 100644 --- a/src/s2paddedcell_test.cc +++ b/src/s2paddedcell_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2paddedcell.h" @@ -19,7 +20,7 @@ #include #include -#include "gtest/gtest.h" +#include #include "r1interval.h" #include "r2.h" #include "s2cell.h" @@ -134,4 +135,4 @@ TEST(S2PaddedCell, ShrinkToFit) { } } -} // namespace \ No newline at end of file +} // namespace diff --git a/src/s2pointcompression.cc b/src/s2pointcompression.cc index 3919a4f4..383c04bc 100644 --- a/src/s2pointcompression.cc +++ b/src/s2pointcompression.cc @@ -13,6 +13,7 @@ // limitations under the License. // + #include "s2pointcompression.h" #include @@ -60,9 +61,7 @@ struct FaceRun { bool Decode(Decoder* decoder) { uint64 face_and_count; - if (!decoder->get_varint64(&face_and_count)) { - return false; - } + if (!decoder->get_varint64(&face_and_count)) return false; face = face_and_count % S2CellId::kNumFaces; count = face_and_count / S2CellId::kNumFaces; @@ -137,9 +136,7 @@ void Faces::Encode(Encoder* encoder) const { bool Faces::Decode(int num_vertices, Decoder* decoder) { for (int num_faces_parsed = 0; num_faces_parsed < num_vertices; ) { FaceRun face_run; - if (!face_run.Decode(decoder)) { - return false; - } + if (!face_run.Decode(decoder)) return false; faces_.push_back(face_run); num_faces_parsed += face_run.count; @@ -383,4 +380,4 @@ bool S2DecodePointsCompressed(Decoder* decoder, decoder->getn(&points[index], sizeof(points[index])); } return true; -} \ No newline at end of file +} diff --git a/src/s2pointcompression.h b/src/s2pointcompression.h index 6fa7ccab..f01a472f 100644 --- a/src/s2pointcompression.h +++ b/src/s2pointcompression.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // Given a sequence of S2Points assumed to be the center of level-k cells, // compresses it into a stream using the following method: @@ -42,9 +43,10 @@ // an average of 3.8 bytes for each additional vertex, when computed on // Google's geographic repository. -#ifndef UTIL_GEOMETRY_S2POINTCOMPRESSION_H_ -#define UTIL_GEOMETRY_S2POINTCOMPRESSION_H_ +#ifndef S2_GEOMETRY_S2POINTCOMPRESSION_H_ +#define S2_GEOMETRY_S2POINTCOMPRESSION_H_ +#include "fpcontractoff.h" #include "s2.h" class Decoder; @@ -77,4 +79,4 @@ bool S2DecodePointsCompressed(Decoder* decoder, int level, S2Point* points); -#endif // UTIL_GEOMETRY_S2POINTCOMPRESSION_H_ \ No newline at end of file +#endif // S2_GEOMETRY_S2POINTCOMPRESSION_H_ diff --git a/src/s2pointcompression_test.cc b/src/s2pointcompression_test.cc index ecd97fba..f2fbb076 100644 --- a/src/s2pointcompression_test.cc +++ b/src/s2pointcompression_test.cc @@ -13,6 +13,7 @@ // limitations under the License. // + #include "s2pointcompression.h" #include @@ -21,12 +22,13 @@ #include #include -#include "gtest/gtest.h" +#include #include "util/coding/coder.h" #include "s1angle.h" #include "s2.h" #include "s2cellid.h" #include "s2testing.h" +#include "s2textformat.h" #include "util/gtl/fixedarray.h" using std::vector; @@ -154,9 +156,9 @@ class S2PointCompressionTest : public ::testing::Test { Decode(loop.size(), level, &points[0]); EXPECT_TRUE(PointsEqual(&loop[0], loop.size(), &points[0], points.size())) - << "Decoded points\n" << S2Testing::ToString(points) + << "Decoded points\n" << s2textformat::ToString(points) << "\ndo not match original points\n" - << S2Testing::ToString(loop); + << s2textformat::ToString(loop); } Encoder encoder_; @@ -272,4 +274,4 @@ TEST_F(S2PointCompressionTest, StraightLineCompressesWell) { } -} // namespace \ No newline at end of file +} // namespace diff --git a/src/s2pointregion.cc b/src/s2pointregion.cc index b3e7faaf..7ef4ad69 100644 --- a/src/s2pointregion.cc +++ b/src/s2pointregion.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2pointregion.h" @@ -59,12 +60,12 @@ bool S2PointRegion::Decode(Decoder* decoder) { if (decoder->avail() < sizeof(unsigned char) + 3 * sizeof(double)) return false; unsigned char version = decoder->get8(); - if (version > kCurrentLosslessEncodingVersionNumber) return false; - + if (version > kCurrentLosslessEncodingVersionNumber) return false; + for (int i = 0; i < 3; ++i) { point_[i] = decoder->getdouble(); } if (!S2::IsUnitLength(point_)) return false; return true; -} \ No newline at end of file +} diff --git a/src/s2pointregion.h b/src/s2pointregion.h index 6e1855aa..80fe2f6e 100644 --- a/src/s2pointregion.h +++ b/src/s2pointregion.h @@ -12,13 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2POINTREGION_H__ -#define UTIL_GEOMETRY_S2POINTREGION_H__ +#ifndef S2_GEOMETRY_S2POINTREGION_H__ +#define S2_GEOMETRY_S2POINTREGION_H__ #include #include "base/macros.h" +#include "fpcontractoff.h" #include "s2.h" #include "s2region.h" @@ -33,7 +35,7 @@ class S2LatLngRect; class S2PointRegion : public S2Region { public: // Create a region containing the given point, which must be unit length. - inline explicit S2PointRegion(S2Point const& point); + explicit S2PointRegion(S2Point const& point); ~S2PointRegion(); @@ -51,7 +53,7 @@ class S2PointRegion : public S2Region { return Contains(p); } bool Contains(S2Point const& p) const { return (point_ == p); } - virtual void Encode(Encoder* const encoder) const; + virtual void Encode(Encoder* const encoder) const; // Ensures the decoded point has unit length. virtual bool Decode(Decoder* const decoder); @@ -61,8 +63,8 @@ class S2PointRegion : public S2Region { DISALLOW_COPY_AND_ASSIGN(S2PointRegion); }; -S2PointRegion::S2PointRegion(S2Point const& point) : point_(point) { +inline S2PointRegion::S2PointRegion(S2Point const& point) : point_(point) { DCHECK(S2::IsUnitLength(point)); } -#endif // UTIL_GEOMETRY_S2POINTREGION_H__ \ No newline at end of file +#endif // S2_GEOMETRY_S2POINTREGION_H__ diff --git a/src/s2pointregion_test.cc b/src/s2pointregion_test.cc index 2224a678..3dcf3d9a 100644 --- a/src/s2pointregion_test.cc +++ b/src/s2pointregion_test.cc @@ -12,18 +12,22 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2pointregion.h" -#include "base/scoped_ptr.h" -#include "gtest/gtest.h" +#include + +#include #include "util/coding/coder.h" #include "s2cap.h" #include "s2cell.h" #include "s2latlng.h" #include "s2latlngrect.h" +using std::unique_ptr; + namespace { TEST(S2PointRegionTest, Basic) { @@ -34,7 +38,7 @@ TEST(S2PointRegionTest, Basic) { EXPECT_TRUE(r0.VirtualContainsPoint(p)); EXPECT_TRUE(r0.VirtualContainsPoint(r0.point())); EXPECT_FALSE(r0.VirtualContainsPoint(S2Point(1, 0, 1))); - scoped_ptr r0_clone(r0.Clone()); + unique_ptr r0_clone(r0.Clone()); EXPECT_EQ(r0_clone->point(), r0.point()); EXPECT_EQ(r0.GetCapBound(), S2Cap::FromPoint(p)); S2LatLng ll(p); @@ -94,4 +98,4 @@ TEST(S2PointRegionTest, DecodeNonUnitLength) { ASSERT_FALSE(r.Decode(&decoder)); } -} // namespace \ No newline at end of file +} // namespace diff --git a/src/s2polygon.cc b/src/s2polygon.cc index ad340249..95fc0e5a 100644 --- a/src/s2polygon.cc +++ b/src/s2polygon.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2polygon.h" @@ -19,10 +20,8 @@ #include #include #include -#include -using __gnu_cxx::hash; -using __gnu_cxx::hash_map; #include +#include #include #include @@ -65,6 +64,13 @@ DEFINE_bool( "significant amounts of memory and time when geometry is constructed but " "never queried, for example when converting from one format to another."); +// The maximum number of loops we'll allow when decoding a polygon. +// The default value of 10 million is 200x bigger than the number of +DEFINE_int32( + s2polygon_decode_max_num_loops, 10000000, + "The upper limit on the number of loops that are allowed by the " + "S2Polygon::Decode method."); + // When adding a new encoding, be aware that old binaries will not // be able to decode it. static const unsigned char kCurrentLosslessEncodingVersionNumber = 1; @@ -73,6 +79,7 @@ static const unsigned char kCurrentCompressedEncodingVersionNumber = 4; S2Polygon::S2Polygon() : has_holes_(false), s2debug_override_(ALLOW_S2DEBUG), + error_inconsistent_loop_orientations_(false), num_vertices_(0), unindexed_contains_calls_(0) { } @@ -103,12 +110,14 @@ S2debugOverride S2Polygon::s2debug_override() const { } void S2Polygon::Copy(S2Polygon const* src) { - DCHECK_EQ(0, num_loops()); + ClearLoops(); for (int i = 0; i < src->num_loops(); ++i) { loops_.push_back(src->loop(i)->Clone()); } has_holes_ = src->has_holes_; s2debug_override_ = src->s2debug_override_; + // Don't copy error_inconsistent_loop_orientations_, since this is not a + // property of the polygon but only of the way the polygon was constructed. num_vertices_ = src->num_vertices(); base::subtle::NoBarrier_Store(&unindexed_contains_calls_, 0); bound_ = src->bound_; @@ -142,6 +151,7 @@ void S2Polygon::ClearLoops() { } loops_.clear(); base::subtle::NoBarrier_Store(&unindexed_contains_calls_, 0); + error_inconsistent_loop_orientations_ = false; } S2Polygon::~S2Polygon() { @@ -178,11 +188,49 @@ bool S2Polygon::FindValidationError(S2Error* error) const { return true; } } - // Finally, check for loop self-intersections and loop pairs that cross + + // Check for loop self-intersections and loop pairs that cross // (including duplicate edges and vertices). - // - // TODO(ericv): Also verify the nesting hierarchy. - return s2shapeutil::FindAnyCrossing(index_, loops_, error); + if (s2shapeutil::FindAnyCrossing(index_, loops_, error)) return true; + + // Check whether InitOriented detected inconsistent loop orientations. + if (error_inconsistent_loop_orientations_) { + error->Init(S2Error::POLYGON_INCONSISTENT_LOOP_ORIENTATIONS, + "Inconsistent loop orientations detected"); + return true; + } + + // Finally, verify the loop nesting hierarchy. + return FindLoopNestingError(error); +} + +bool S2Polygon::FindLoopNestingError(S2Error* error) const { + // First check that the loop depths make sense. + for (int last_depth = -1, i = 0; i < num_loops(); ++i) { + int depth = loop(i)->depth(); + if (depth < 0 || depth > last_depth + 1) { + error->Init(S2Error::POLYGON_INVALID_LOOP_DEPTH, + "Loop %d: invalid loop depth (%d)", i, depth); + return true; + } + last_depth = depth; + } + // Then check that they correspond to the actual loop nesting. This test + // is quadratic in the number of loops but the cost per iteration is small. + for (int i = 0; i < num_loops(); ++i) { + int last = GetLastDescendant(i); + for (int j = 0; j < num_loops(); ++j) { + if (i == j) continue; + bool expected = (j >= i+1) && (j <= last); + if (loop(i)->ContainsNested(loop(j)) != expected) { + error->Init(S2Error::POLYGON_INVALID_LOOP_NESTING, + "Invalid nesting: loop %d should %scontain loop %d", + i, expected ? "" : "not ", j); + return true; + } + } + } + return false; } void S2Polygon::InsertLoop(S2Loop* new_loop, S2Loop* parent, @@ -195,11 +243,6 @@ void S2Polygon::InsertLoop(S2Loop* new_loop, S2Loop* parent, return; } } - // No loop may contain the complement of another loop. (Handling this case - // is significantly more complicated.) - if (FLAGS_s2debug && s2debug_override_ == ALLOW_S2DEBUG) { - CHECK(parent == NULL || !new_loop->ContainsNested(parent)); - } // Some of the children of the parent loop may now be children of // the new loop. @@ -227,22 +270,10 @@ void S2Polygon::InitLoop(S2Loop* loop, int depth, LoopMap* loop_map) { } } -bool S2Polygon::ContainsChild(S2Loop* a, S2Loop* b, LoopMap const& loop_map) { - // This function is just used to verify that the loop map was - // constructed correctly. - - if (a == b) return true; - vector const& children = loop_map.find(a)->second; - for (int i = 0; i < children.size(); ++i) { - if (ContainsChild(children[i], b, loop_map)) return true; - } - return false; -} - void S2Polygon::InitIndex() { DCHECK_EQ(0, index_.num_shape_ids()); for (int i = 0; i < num_loops(); ++i) { - index_.Insert(new S2Loop::Shape(loop(i))); + index_.Add(new S2Loop::Shape(loop(i))); } if (!FLAGS_s2polygon_lazy_indexing) { index_.ForceApplyUpdates(); // Force index construction now. @@ -270,17 +301,6 @@ void S2Polygon::InitNested(vector* loops) { loops_.clear(); InitLoop(NULL, -1, &loop_map); - if (FLAGS_s2debug && s2debug_override_ == ALLOW_S2DEBUG) { - // Check that the LoopMap is correct (this is fairly cheap). - for (int i = 0; i < num_loops(); ++i) { - for (int j = 0; j < num_loops(); ++j) { - if (i == j) continue; - CHECK_EQ(ContainsChild(loop(i), loop(j), loop_map), - loop(i)->ContainsNested(loop(j))); - } - } - } - // Compute has_holes_, num_vertices_, bound_, subregion_bound_. InitLoopProperties(); } @@ -290,6 +310,7 @@ void S2Polygon::InitOneLoop() { S2Loop* loop = loops_[0]; loop->set_depth(0); has_holes_ = false; + error_inconsistent_loop_orientations_ = false; num_vertices_ = loop->num_vertices(); bound_ = loop->GetRectBound(); subregion_bound_ = S2EdgeUtil::RectBounder::ExpandForSubregions(bound_); @@ -362,13 +383,16 @@ void S2Polygon::InitOriented(vector* loops) { Invert(); } } - if (FLAGS_s2debug && s2debug_override_ == ALLOW_S2DEBUG) { - // Verify that the original loops had consistent shell/hole orientations. - // Each original loop L should have been inverted if and only if it now - // represents a hole. - for (int i = 0; i < loops_.size(); ++i) { - DCHECK_EQ(contained_origin.count(loop(i)) != loop(i)->contains_origin(), - loop(i)->is_hole()); + // Verify that the original loops had consistent shell/hole orientations. + // Each original loop L should have been inverted if and only if it now + // represents a hole. + for (int i = 0; i < loops_.size(); ++i) { + if ((contained_origin.count(loop(i)) != loop(i)->contains_origin()) != + loop(i)->is_hole()) { + // There is no point in saving the loop index, because the error is a + // property of the entire set of loops. In general there is no way to + // determine which ones are incorrect. + error_inconsistent_loop_orientations_ = true; } } } @@ -451,6 +475,18 @@ S1Angle S2Polygon::GetDistanceToBoundary(S2Point const& x) const { return query.GetDistance(x); } +/*static*/ pair S2Polygon::GetOverlapFractions( + S2Polygon const* a, S2Polygon const* b) { + S2Polygon intersection; + intersection.InitToIntersection(a, b); + double intersection_area = intersection.GetArea(); + double a_area = a->GetArea(); + double b_area = b->GetArea(); + return std::make_pair( + intersection_area >= a_area ? 1 : intersection_area / a_area, + intersection_area >= b_area ? 1 : intersection_area / b_area); +} + S2Point S2Polygon::Project(S2Point const& x) const { if (Contains(x)) return x; S2ClosestEdgeQuery query(index_); @@ -639,11 +675,16 @@ bool S2Polygon::Contains(S2Cell const& target) const { return Contains(it, target.GetCenter()); } -bool S2Polygon::ApproxContains(S2Polygon const* b, - S1Angle vertex_merge_radius) const { +bool S2Polygon::ApproxContains(S2Polygon const* b, S1Angle tolerance) const { S2Polygon difference; - difference.InitToDifferenceSloppy(b, this, vertex_merge_radius); - return difference.num_loops() == 0; + difference.InitToDifferenceSloppy(b, this, tolerance); + return difference.is_empty(); +} + +bool S2Polygon::ApproxDisjoint(S2Polygon const* b, S1Angle tolerance) const { + S2Polygon intersection; + intersection.InitToIntersectionSloppy(b, this, tolerance); + return intersection.is_empty(); } bool S2Polygon::MayIntersect(S2Cell const& target) const { @@ -774,7 +815,7 @@ void S2Polygon::Encode(Encoder* const encoder) const { loops_[i]->GetXYZFaceSiTiVertices(current_loop_vertices); current_loop_vertices += loops_[i]->num_vertices(); } - // Computes an histogram of the cell levels at which the vertices are snapped. + // Computes a histogram of the cell levels at which the vertices are snapped. // (histogram[0] is the number of unsnapped vertices, histogram[i] the number // of vertices snapped at level i-1). int histogram[S2::kMaxCellLevel + 2]; @@ -830,7 +871,7 @@ bool S2Polygon::Decode(Decoder* const decoder) { unsigned char version = decoder->get8(); switch (version) { case kCurrentLosslessEncodingVersionNumber: - return DecodeInternal(decoder, false); + return DecodeLossless(decoder, false); case kCurrentCompressedEncodingVersionNumber: return DecodeCompressed(decoder); } @@ -842,19 +883,22 @@ bool S2Polygon::DecodeWithinScope(Decoder* const decoder) { unsigned char version = decoder->get8(); switch (version) { case kCurrentLosslessEncodingVersionNumber: - return DecodeInternal(decoder, true); + return DecodeLossless(decoder, true); case kCurrentCompressedEncodingVersionNumber: return DecodeCompressed(decoder); } return false; } -bool S2Polygon::DecodeInternal(Decoder* const decoder, bool within_scope) { +bool S2Polygon::DecodeLossless(Decoder* const decoder, bool within_scope) { if (decoder->avail() < 2 * sizeof(uint8) + sizeof(uint32)) return false; ClearLoops(); decoder->get8(); // Ignore irrelevant serialized owns_loops_ value. has_holes_ = decoder->get8(); - int num_loops = decoder->get32(); + // Polygons with no loops are explicitly allowed here: a newly created + // polygon has zero loops and such polygons encode and decode properly. + const uint32 num_loops = decoder->get32(); + if (num_loops > FLAGS_s2polygon_decode_max_num_loops) return false; loops_.reserve(num_loops); num_vertices_ = 0; for (int i = 0; i < num_loops; ++i) { @@ -1407,7 +1451,7 @@ void S2Polygon::InitToSimplifiedInternal(S2Polygon const* a, should_keep); if (NULL == simpler) continue; simplified_loops.push_back(simpler); - index.Insert(new PointVectorLoopShape(simpler)); + index.Add(new PointVectorLoopShape(simpler)); } if (index.num_shape_ids() > 0) { BreakEdgesAndAddToBuilder(index, &builder); @@ -1548,7 +1592,6 @@ void S2Polygon::SubtractFromPolylineSloppy( InternalClipPolyline(true, a, out, vertex_merge_radius); } - S2Polygon* S2Polygon::DestructiveUnion(vector* polygons) { return DestructiveUnionSloppy(polygons, S2EdgeUtil::kIntersectionTolerance); } @@ -1652,6 +1695,18 @@ bool S2Polygon::IsNormalized() const { return true; } +bool S2Polygon::Equals(S2Polygon const* b) const { + if (num_loops() != b->num_loops()) return false; + for (int i = 0; i < num_loops(); ++i) { + S2Loop const* a_loop = loop(i); + S2Loop const* b_loop = b->loop(i); + if ((b_loop->depth() != a_loop->depth()) || !b_loop->Equals(a_loop)) { + return false; + } + } + return true; +} + bool S2Polygon::BoundaryEquals(S2Polygon const* b) const { if (num_loops() != b->num_loops()) return false; @@ -1740,10 +1795,12 @@ bool S2Polygon::DecodeCompressed(Decoder* decoder) { if (decoder->avail() < sizeof(uint8)) return false; ClearLoops(); int snap_level = decoder->get8(); + if (snap_level > S2CellId::kMaxLevel) return false; + // Polygons with no loops are explicitly allowed here: a newly created + // polygon has zero loops and such polygons encode and decode properly. uint32 num_loops; - if (!decoder->get_varint32(&num_loops)) { - return false; - } + if (!decoder->get_varint32(&num_loops)) return false; + if (num_loops > FLAGS_s2polygon_decode_max_num_loops) return false; loops_.reserve(num_loops); for (int i = 0; i < num_loops; ++i) { S2Loop* loop = new S2Loop; @@ -1756,3 +1813,4 @@ bool S2Polygon::DecodeCompressed(Decoder* decoder) { InitLoopProperties(); return true; } + diff --git a/src/s2polygon.h b/src/s2polygon.h index 2fa41f50..6f49edb9 100644 --- a/src/s2polygon.h +++ b/src/s2polygon.h @@ -12,10 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2POLYGON_H_ -#define UTIL_GEOMETRY_S2POLYGON_H_ +#ifndef S2_GEOMETRY_S2POLYGON_H_ +#define S2_GEOMETRY_S2POLYGON_H_ #include #include @@ -23,6 +24,7 @@ #include "base/integral_types.h" #include "base/macros.h" +#include "fpcontractoff.h" #include "s2.h" #include "s2cellid.h" #include "s2latlngrect.h" @@ -148,7 +150,7 @@ class S2Polygon : public S2Region { void InitOriented(std::vector* loops); // Historical synonym for InitNested. - inline void Init(std::vector* loops) { InitNested(loops); } + void Init(std::vector* loops) { InitNested(loops); } // Releases ownership of the loops of this polygon, appends them to "loops" if // non-NULL, and resets the polygon to be empty. Note that the caller is @@ -157,8 +159,8 @@ class S2Polygon : public S2Region { // loop pointers beforehand. void Release(std::vector* loops); - // Makes a deep copy of the given source polygon. Requires that the - // destination polygon is empty. + // Makes a deep copy of the given source polygon. The destination polygon + // will be cleared if necessary. void Copy(S2Polygon const* src); // Destroys the polygon and frees its loops. @@ -255,6 +257,11 @@ class S2Polygon : public S2Region { // has no boundary). "x" should be unit length. S1Angle GetDistanceToBoundary(S2Point const& x) const; + // Return the overlap fractions between two polygons, i.e. the ratios of the + // area of intersection to the area of each polygon. + static std::pair GetOverlapFractions(S2Polygon const* a, + S2Polygon const* b); + // If the given point is contained by the polygon, return it. Otherwise // return the closest point on the polygon boundary. If the polygon is // empty, return the input argument. Note that the result may or may not be @@ -272,16 +279,25 @@ class S2Polygon : public S2Region { // Returns true if this polgyon (A) approximately contains the given other // polygon (B). This is true if it is possible to move the vertices of B - // no further than "vertex_merge_radius" such that A contains the modified B. + // no further than "tolerance" such that A contains the modified B. // // For example, the empty polygon will contain any polygon whose maximum - // width is no more than vertex_merge_radius. - bool ApproxContains(S2Polygon const* b, S1Angle vertex_merge_radius) const; + // width is no more than "tolerance". + bool ApproxContains(S2Polygon const* b, S1Angle tolerance) const; // Return true if this polygon intersects the given other polygon, i.e. // if there is a point that is contained by both polygons. bool Intersects(S2Polygon const* b) const; + // Returns true if this polgyon (A) and the given polygon (B) are + // approximately disjoint. This is true if it is possible to ensure that A + // and B do not intersect by moving their vertices no further than + // "tolerance". + // + // For example, any polygon is approximately disjoint from a polygon whose + // maximum width is no more than "tolerance". + bool ApproxDisjoint(S2Polygon const* b, S1Angle tolerance) const; + // Initialize this polygon to the intersection, union, or difference // (A - B) of the given two polygons. The "vertex_merge_radius" determines // how close two vertices must be to be merged together and how close a @@ -397,9 +413,17 @@ class S2Polygon : public S2Region { // polygons represent the same region. bool IsNormalized() const; + // Return true if two polygons have exactly the same loops. The loops must + // appear in the same order, and corresponding loops must have the same + // linear vertex ordering (i.e., cyclic rotations are not allowed). + bool Equals(S2Polygon const* b) const; + // Return true if two polygons have the same boundary. More precisely, this // method requires that both polygons have loops with the same cyclic vertex - // order and the same nesting hierarchy. + // order and the same nesting hierarchy. (This implies that vertices may be + // cyclically rotated between corresponding loops, and the loop ordering may + // be different between the two polygons as long as the nesting hierarchy is + // the same.) bool BoundaryEquals(S2Polygon const* b) const; // Return true if two polygons have the same boundary except for vertex @@ -465,16 +489,18 @@ class S2Polygon : public S2Region { // Compute has_holes_, num_vertices_, bound_, subregion_bound_. void InitLoopProperties(); - // Deletes the contents of the loops_ vector and clears it. + // Deletes the contents of the loops_ vector and resets the polygon state. void ClearLoops(); + // Return true if there is an error in the loop nesting hierarchy. + bool FindLoopNestingError(S2Error* error) const; + // A map from each loop to its immediate children with respect to nesting. // This map is built during initialization of multi-loop polygons to // determine which are shells and which are holes, and then discarded. typedef std::map > LoopMap; void InsertLoop(S2Loop* new_loop, S2Loop* parent, LoopMap* loop_map); - static bool ContainsChild(S2Loop* a, S2Loop* b, LoopMap const& loop_map); void InitLoop(S2Loop* loop, int depth, LoopMap* loop_map); // Add the polygon's loops to the S2ShapeIndex. (The actual work of @@ -507,10 +533,10 @@ class S2Polygon : public S2Region { // (40 + 43 * num_loops + 24 * num_vertices) bytes. void EncodeLossless(Encoder* encoder) const; - // Internal implementation of the Decode and DecodeWithinScope methods above. - // The within_scope parameter specifies whether to call DecodeWithinScope - // on the loops. - bool DecodeInternal(Decoder* const decoder, bool within_scope); + // Decode a polygon encoded with EncodeLossless(). Used by the Decode and + // DecodeWithinScope methods above. The within_scope parameter specifies + // whether to call DecodeWithinScope on the loops. + bool DecodeLossless(Decoder* const decoder, bool within_scope); // Encode the polygon's vertices using about 4 bytes / vertex plus 24 bytes / // unsnapped vertex. All the loop vertices must be converted first to the @@ -550,6 +576,14 @@ class S2Polygon : public S2Region { // --s2debug flag. uint8 s2debug_override_; // Store enum in 1 byte rather than 4. + // True if InitOriented() was called and the given loops had inconsistent + // orientations (i.e., it is not possible to construct a polygon such that + // the interior is on the left-hand side of all loops). We need to remember + // this error so that it can be returned later by FindValidationError(), + // since it is not possible to detect this error once the polygon has been + // initialized. This field is not preserved by Encode/Decode. + uint8 error_inconsistent_loop_orientations_; + // Cache for num_vertices(). int num_vertices_; @@ -576,4 +610,4 @@ class S2Polygon : public S2Region { DISALLOW_COPY_AND_ASSIGN(S2Polygon); }; -#endif // UTIL_GEOMETRY_S2POLYGON_H_ \ No newline at end of file +#endif // S2_GEOMETRY_S2POLYGON_H_ diff --git a/src/s2polygon_test.cc b/src/s2polygon_test.cc index 435e706f..32aaf7ff 100644 --- a/src/s2polygon_test.cc +++ b/src/s2polygon_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) // @@ -29,10 +30,9 @@ #include #include #include "base/macros.h" -#include "base/scoped_ptr.h" #include "base/stringprintf.h" #include "strings/serialize.h" -#include "gtest/gtest.h" +#include #include "util/coding/coder.h" #include "r1interval.h" #include "s1angle.h" @@ -49,6 +49,8 @@ #include "s2polyline.h" #include "s2regioncoverer.h" #include "s2testing.h" +#include "s2textformat.h" +#include "util/gtl/fixedarray.h" #include "util/math/matrix3x3.h" using std::max; @@ -56,6 +58,7 @@ using std::min; using std::numeric_limits; using std::pair; using std::swap; +using std::unique_ptr; using std::vector; @@ -117,10 +120,18 @@ string const kOverlap2 = "1:1, 2:1, 3:1, 3:0, 2:0, 1:0;"; string const kOverlap2SideHole = "2.2:0.8, 2.8:0.8, 2.8:0.2, 2.2:0.2;"; string const kOverlapCenterHole = "1.2:0.8, 1.8:0.8, 1.8:0.2, 1.2:0.2;"; +// An empty polygon. +string const kEmpty = ""; +// By symmetry, the intersection of the two polygons has almost half the area +// of either polygon. +string const kOverlap3 = "-10:10, 0:10, 0:-10, -10:-10, -10:0"; +string const kOverlap4 = "-10:0, 10:0, 10:-10, -10:-10"; + class S2PolygonTestBase : public testing::Test { public: S2PolygonTestBase(); ~S2PolygonTestBase(); + protected: // Some standard polygons to use in the tests. S2Polygon const* const empty; @@ -170,28 +181,45 @@ class S2PolygonTestBase : public testing::Test { S2Polygon const* const far_H_south_H; }; -static S2Polygon* MakePolygon(string const& str) { - scoped_ptr polygon(S2Testing::MakeVerbatimPolygon(str)); +static bool TestEncodeDecode(const S2Polygon* src) { Encoder encoder; - polygon->Encode(&encoder); + src->Encode(&encoder); Decoder decoder(encoder.base(), encoder.length()); - scoped_ptr decoded_polygon(new S2Polygon); - decoded_polygon->Decode(&decoder); - return decoded_polygon.release(); + S2Polygon dst; + dst.Decode(&decoder); + return src->Equals(&dst); +} + +static S2Polygon* MakePolygon(string const& str) { + unique_ptr polygon(s2textformat::MakeVerbatimPolygon(str)); + +#if 0 + // TODO(ericv): Ensure that S2PolygonBuilder2 passes this test. + // Check that InitToSnapped() is idempotent. + S2Polygon snapped1, snapped2; + snapped1.InitToSnapped(polygon.get()); + snapped2.InitToSnapped(&snapped1); + EXPECT_TRUE(snapped1.Equals(&snapped2)); +#endif + + // Check that Decode(Encode(x)) is the identity function. + EXPECT_TRUE(TestEncodeDecode(polygon.get())); + return polygon.release(); } static void CheckContains(string const& a_str, string const& b_str) { S2Polygon* a = MakePolygon(a_str); S2Polygon* b = MakePolygon(b_str); - scoped_ptr delete_a(a); - scoped_ptr delete_b(b); + unique_ptr delete_a(a); + unique_ptr delete_b(b); EXPECT_TRUE(a->Contains(b)); EXPECT_TRUE(a->ApproxContains(b, S1Angle::Radians(1e-15))); + EXPECT_FALSE(a->ApproxDisjoint(b, S1Angle::Radians(1e-15))); } static void CheckContainsPoint(string const& a_str, string const& b_str) { - scoped_ptr a(S2Testing::MakePolygon(a_str)); - EXPECT_TRUE(a->VirtualContainsPoint(S2Testing::MakePoint(b_str))) + unique_ptr a(s2textformat::MakePolygon(a_str)); + EXPECT_TRUE(a->VirtualContainsPoint(s2textformat::MakePoint(b_str))) << " " << a_str << " did not contain " << b_str; } @@ -224,6 +252,24 @@ TEST(S2Polygon, Init) { CheckContainsPoint(kSouthHemi, kSouthPoint); } +TEST(S2Polygon, OverlapFractions) { + unique_ptr a(MakePolygon(kEmpty)); + unique_ptr b(MakePolygon(kEmpty)); + auto result = S2Polygon::GetOverlapFractions(a.get(), b.get()); + EXPECT_DOUBLE_EQ(1.0, result.first); + EXPECT_DOUBLE_EQ(1.0, result.second); + + b.reset(MakePolygon(kOverlap3)); + result = S2Polygon::GetOverlapFractions(a.get(), b.get()); + EXPECT_DOUBLE_EQ(1.0, result.first); + EXPECT_DOUBLE_EQ(0.0, result.second); + + a.reset(MakePolygon(kOverlap4)); + result = S2Polygon::GetOverlapFractions(a.get(), b.get()); + EXPECT_NEAR(0.5, result.first, 1e-14); + EXPECT_NEAR(0.5, result.second, 1e-14); +} + TEST(S2Polygon, OriginNearPole) { // S2Polygon operations are more efficient if S2::Origin() is near a pole. // (Loops that contain a pole tend to have very loose bounding boxes because @@ -350,35 +396,46 @@ static void CheckComplementary(S2Polygon const* a, S2Polygon const* b) { CheckEqual(a, &b1); } -TEST(S2Polygon, TestApproxContains) { - // Get a random S2Cell as a polygon. - S2CellId id = S2CellId::FromLatLng(S2LatLng::FromE6(69852241, 6751108)); - S2Cell cell(id.parent(10)); - S2Polygon cell_as_polygon(cell); - - // We want to roughly bisect the polygon, so we make a rectangle that is the - // top half of the current polygon's bounding rectangle. - S2LatLngRect const& bounds = cell_as_polygon.GetRectBound(); - S2LatLngRect upper_half = bounds; - upper_half.mutable_lat()->set_lo(bounds.lat().GetCenter()); - - // Turn the S2LatLngRect into an S2Polygon - vector points; - for (int i = 0; i < 4; i++) - points.push_back(upper_half.GetVertex(i).ToPoint()); - vector loops; - loops.push_back(new S2Loop(points)); - S2Polygon upper_half_polygon(&loops); - - // Get the intersection. There is no guarantee that the intersection will be - // contained by A or B. - S2Polygon intersection; - intersection.InitToIntersection(&cell_as_polygon, &upper_half_polygon); - EXPECT_FALSE(cell_as_polygon.Contains(&intersection)); +TEST(S2Polygon, TestApproxContainsAndDisjoint) { + // We repeatedly choose a random cell id and intersect its bounding polygon + // "A" with the bounding polygon "B" of one its child cells. The result may + // not be contained by either A or B, because the vertices of B near the + // edge midpoints of A may be slightly outside A, and even when the crossing + // edges are intersected, the intersection point may also be slightly + // outside A and/or B. + // + // We repeat the test many times and expect that some fraction of the exact + // tests should fail, while all of the approximate test should succeed. + int const kIters = 1000; + int exact_contains = 0, exact_disjoint = 0; + for (int iter = 0; iter < kIters; ++iter) { + S2CellId id = S2Testing::GetRandomCellId(10); + S2Polygon parent_polygon((S2Cell(id))); + S2Polygon child_polygon(S2Cell(id.child(0))); + + // Get the intersection. There is no guarantee that the intersection will + // be contained by A or B. Similarly, the intersection may slightly + // overlap an adjacent disjoint polygon C. + S2Polygon intersection; + intersection.InitToIntersection(&parent_polygon, &child_polygon); + if (parent_polygon.Contains(&intersection)) { + ++exact_contains; + } + EXPECT_TRUE(parent_polygon.ApproxContains( + &intersection, S2EdgeUtil::kIntersectionTolerance)); - EXPECT_TRUE( - cell_as_polygon.ApproxContains(&intersection, - S2EdgeUtil::kIntersectionTolerance)); + S2Polygon adjacent_polygon(S2Cell(id.child(1))); + if (!adjacent_polygon.Intersects(&intersection)) { + ++exact_disjoint; + } + EXPECT_TRUE(adjacent_polygon.ApproxDisjoint( + &intersection, S2EdgeUtil::kIntersectionTolerance)); + } + // Back-of-the-envelope calculations show that about 56% of the exact + // containment tests should succeed, and about 75% of the exact disjoint + // tests should succeed. These are close to the measured values. + EXPECT_LT(exact_contains, 0.60 * kIters); // 51.8% succeed + EXPECT_LT(exact_disjoint, 0.86 * kIters); // 78.6% succeed } // Given a pair of polygons where A contains B, check that various identities @@ -498,7 +555,6 @@ static void TestOverlappingPair(S2Polygon const* a, S2Polygon const* b) { // "a1" is the complement of "a", and "b1" is the complement of "b". static void TestOneComplementPair(S2Polygon const* a, S2Polygon const* a1, S2Polygon const* b, S2Polygon const* b1) { - // Check DeMorgan's Law and that subtraction is the same as intersection // with the complement. This function is called multiple times in order to // test the various combinations of complements. @@ -531,7 +587,7 @@ static void TestDestructiveUnion(S2Polygon const* a, S2Polygon const* b) { vector polygons; polygons.push_back(a->Clone()); polygons.push_back(b->Clone()); - scoped_ptr c_destructive(S2Polygon::DestructiveUnion(&polygons)); + unique_ptr c_destructive(S2Polygon::DestructiveUnion(&polygons)); CheckEqual(&c, c_destructive.get()); } @@ -732,11 +788,11 @@ TEST_F(S2PolygonTestBase, Operations) { for (int i = 0; i < arraysize(test_cases); ++i) { SCOPED_TRACE(StringPrintf("Polygon operation test case %d", i)); TestCase* test = test_cases + i; - scoped_ptr a(MakePolygon(test->a)); - scoped_ptr b(MakePolygon(test->b)); - scoped_ptr expected_a_and_b(MakePolygon(test->a_and_b)); - scoped_ptr expected_a_or_b(MakePolygon(test->a_or_b)); - scoped_ptr expected_a_minus_b(MakePolygon(test->a_minus_b)); + unique_ptr a(MakePolygon(test->a)); + unique_ptr b(MakePolygon(test->b)); + unique_ptr expected_a_and_b(MakePolygon(test->a_and_b)); + unique_ptr expected_a_or_b(MakePolygon(test->a_or_b)); + unique_ptr expected_a_minus_b(MakePolygon(test->a_minus_b)); // The intersections in the "expected" data were computed in lat-lng // space, while the actual intersections are computed using geodesics. @@ -827,9 +883,9 @@ TEST_F(S2PolygonTestBase, PolylineIntersection) { for (int i = 0; i < arraysize(test_cases); ++i) { SCOPED_TRACE(StringPrintf("Polyline intersection test case %d", i)); TestCase* test = test_cases + i; - scoped_ptr a(MakePolygon(test->a)); - scoped_ptr b(MakePolygon(test->b)); - scoped_ptr expected_a_and_b(MakePolygon(test->a_and_b)); + unique_ptr a(MakePolygon(test->a)); + unique_ptr b(MakePolygon(test->b)); + unique_ptr expected_a_and_b(MakePolygon(test->a_and_b)); vector points; vector polylines; @@ -940,8 +996,8 @@ static void SplitAndAssemble(S2Polygon const* polygon) { piece->InitToIntersection(polygon, &window); pieces.push_back(piece); VLOG(4) << "\nPiece " << i << ":\n Window: " - << S2Testing::ToString(&window) - << "\n Piece: " << S2Testing::ToString(piece); + << s2textformat::ToString(&window) + << "\n Piece: " << s2textformat::ToString(piece); } // Now we repeatedly remove two random pieces, compute their union, and @@ -953,22 +1009,22 @@ static void SplitAndAssemble(S2Polygon const* polygon) { // because this always joins a single original piece to the current union // rather than doing the unions according to a random tree structure. while (pieces.size() > 1) { - scoped_ptr a(ChoosePiece(&pieces)); - scoped_ptr b(ChoosePiece(&pieces)); + unique_ptr a(ChoosePiece(&pieces)); + unique_ptr b(ChoosePiece(&pieces)); S2Polygon* c = new S2Polygon; c->InitToUnion(a.get(), b.get()); pieces.push_back(c); - VLOG(4) << "\nJoining piece a: " << S2Testing::ToString(a.get()) - << "\n With piece b: " << S2Testing::ToString(b.get()) - << "\n To get piece c: " << S2Testing::ToString(c); + VLOG(4) << "\nJoining piece a: " << s2textformat::ToString(a.get()) + << "\n With piece b: " << s2textformat::ToString(b.get()) + << "\n To get piece c: " << s2textformat::ToString(c); } - scoped_ptr result(pieces[0]); + unique_ptr result(pieces[0]); pieces.pop_back(); // The moment of truth! EXPECT_TRUE(expected.BoundaryNear(result.get())) - << "\nActual:\n" << S2Testing::ToString(result.get()) - << "\nExpected:\n" << S2Testing::ToString(&expected); + << "\nActual:\n" << s2textformat::ToString(result.get()) + << "\nExpected:\n" << s2textformat::ToString(&expected); } } @@ -1040,6 +1096,29 @@ TEST(S2Polygon, InitToCellUnionBorder) { } } +TEST(S2Polygon, UnionWithAmbgiuousCrossings) { + S2Point const a_data[] = { + S2Point(0.044856812877680216, -0.80679210859571904, 0.5891301722422051), + S2Point(0.044851868273159699, -0.80679240802900054, 0.5891301386444033), + S2Point(0.044854246527738666, -0.80679240292188514, 0.58912996457145106) + }; + S2Point const b_data[3] = { + S2Point(0.044849715793028468, -0.80679253837178111, 0.58913012401412856), + S2Point(0.044855344598821352, -0.80679219751320641, 0.589130162266992), + S2Point(0.044854017712818696, -0.80679210327223405, 0.58913039235179754) + }; + vector a_vertices(a_data, a_data + arraysize(a_data)); + vector b_vertices(b_data, b_data + arraysize(b_data)); + vector loops; + loops.push_back(new S2Loop(a_vertices)); + S2Polygon a(&loops); + loops.push_back(new S2Loop(b_vertices)); + S2Polygon b(&loops); + S2Polygon c; + c.InitToUnion(&a, &b); + EXPECT_FALSE(c.is_empty()); +} + TEST(S2Polygon, InitToSloppySupportsEmptyPolygons) { S2Polygon empty_polygon; S2Polygon polygon; @@ -1047,10 +1126,31 @@ TEST(S2Polygon, InitToSloppySupportsEmptyPolygons) { // InitToSloppy is further tested by SnapSplitsPolygon. } -TEST(S2Polygon, InitToSnappedWithSnapLevel) { - const scoped_ptr polygon( - S2Testing::MakePolygon("0:0, 0:2, 2:0; 0:0, 0:-2, -2:-2, -2:0")); +TEST(S2Polygon, InitToSnappedDoesNotRotateVertices) { + // This particular example came from MapFacts, but in fact InitToSnapped + // used to cyclically rotate the vertices of all "hole" loops. + unique_ptr polygon(s2textformat::MakePolygon( + "49.9305505:-124.8345463, 49.9307448:-124.8299657, " + "49.9332101:-124.8301996, 49.9331224:-124.8341368; " + "49.9311087:-124.8327042, 49.9318176:-124.8312621, " + "49.9318866:-124.8334451")); + S2Polygon polygon2, polygon3; + polygon2.InitToSnapped(polygon.get()); + + // Check that the first vertex is the same when converted to E7. + EXPECT_EQ(S2LatLng::Latitude(polygon->loop(0)->vertex(0)).e7(), + S2LatLng::Latitude(polygon2.loop(0)->vertex(0)).e7()); + EXPECT_EQ(S2LatLng::Longitude(polygon->loop(0)->vertex(0)).e7(), + S2LatLng::Longitude(polygon2.loop(0)->vertex(0)).e7()); + // Check that snapping twice doesn't rotate the vertices. + polygon3.InitToSnapped(&polygon2); + EXPECT_TRUE(polygon2.Equals(&polygon3)); +} + +TEST(S2Polygon, InitToSnappedWithSnapLevel) { + const unique_ptr polygon( + s2textformat::MakePolygon("0:0, 0:2, 2:0; 0:0, 0:-2, -2:-2, -2:0")); for (int level = 0; level <= S2CellId::kMaxLevel; ++level) { S2Polygon snapped_polygon; snapped_polygon.InitToSnapped(polygon.get(), level); @@ -1062,14 +1162,14 @@ TEST(S2Polygon, InitToSnappedWithSnapLevel) { } TEST(S2Polygon, MultipleInit) { - scoped_ptr polygon(S2Testing::MakePolygon("0:0, 0:2, 2:0")); + unique_ptr polygon(s2textformat::MakePolygon("0:0, 0:2, 2:0")); EXPECT_EQ(1, polygon->num_loops()); EXPECT_EQ(3, polygon->num_vertices()); S2LatLngRect bound1 = polygon->GetRectBound(); vector loops; - loops.push_back(S2Testing::MakeLoop("10:0, -10:-20, -10:20")); - loops.push_back(S2Testing::MakeLoop("40:30, 20:10, 20:50")); + loops.push_back(s2textformat::MakeLoop("10:0, -10:-20, -10:20")); + loops.push_back(s2textformat::MakeLoop("40:30, 20:10, 20:50")); polygon->InitNested(&loops); EXPECT_TRUE(polygon->IsValid()); EXPECT_TRUE(loops.empty()); @@ -1078,7 +1178,7 @@ TEST(S2Polygon, MultipleInit) { EXPECT_TRUE(bound1 != polygon->GetRectBound()); } -TEST_F(S2PolygonTestBase, TestEncodeDecode) { +TEST_F(S2PolygonTestBase, TestSimpleEncodeDecode) { Encoder encoder; cross1->Encode(&encoder); Decoder decoder(encoder.base(), encoder.length()); @@ -1088,6 +1188,11 @@ TEST_F(S2PolygonTestBase, TestEncodeDecode) { EXPECT_EQ(cross1->GetRectBound(), decoded_polygon.GetRectBound()); } +TEST_F(S2PolygonTestBase, TestEncodeDecodeDefaultPolygon) { + S2Polygon polygon; + EXPECT_TRUE(TestEncodeDecode(&polygon)); +} + TEST_F(S2PolygonTestBase, CompressedEmptyPolygonRequires3Bytes) { S2Polygon empty_polygon; Encoder encoder; @@ -1104,8 +1209,8 @@ TEST_F(S2PolygonTestBase, CompressedEmptyPolygonRequires3Bytes) { } TEST_F(S2PolygonTestBase, CompressedEncodedPolygonRequires69Bytes) { - const scoped_ptr polygon( - S2Testing::MakePolygon("0:0, 0:2, 2:0; 0:0, 0:-2, -2:-2, -2:0")); + const unique_ptr polygon( + s2textformat::MakePolygon("0:0, 0:2, 2:0; 0:0, 0:-2, -2:-2, -2:0")); S2Polygon snapped_polygon; snapped_polygon.InitToSnapped(polygon.get()); @@ -1165,29 +1270,29 @@ TEST(S2Polygon, TestS2CellConstructorAndContains) { } TEST(S2PolygonTest, Project) { - scoped_ptr polygon(MakePolygon(kNear0 + kNear2)); + unique_ptr polygon(MakePolygon(kNear0 + kNear2)); S2Point point; S2Point projected; // The point inside the polygon should be projected into itself. - point = S2Testing::MakePoint("1.1:0"); + point = s2textformat::MakePoint("1.1:0"); projected = polygon->Project(point); EXPECT_TRUE(S2::ApproxEquals(point, projected)); // The point is on the outside of the polygon. - point = S2Testing::MakePoint("5.1:-2"); + point = s2textformat::MakePoint("5.1:-2"); projected = polygon->Project(point); - EXPECT_TRUE(S2::ApproxEquals(S2Testing::MakePoint("5:-2"), projected)); + EXPECT_TRUE(S2::ApproxEquals(s2textformat::MakePoint("5:-2"), projected)); // The point is inside the hole in the polygon. - point = S2Testing::MakePoint("-0.49:-0.49"); + point = s2textformat::MakePoint("-0.49:-0.49"); projected = polygon->Project(point); - EXPECT_TRUE(S2::ApproxEquals(S2Testing::MakePoint("-0.5:-0.5"), + EXPECT_TRUE(S2::ApproxEquals(s2textformat::MakePoint("-0.5:-0.5"), projected, 1e-6)); - point = S2Testing::MakePoint("0:-3"); + point = s2textformat::MakePoint("0:-3"); projected = polygon->Project(point); - EXPECT_TRUE(S2::ApproxEquals(S2Testing::MakePoint("0:-2"), projected)); + EXPECT_TRUE(S2::ApproxEquals(s2textformat::MakePoint("0:-2"), projected)); } // Helper function for testing the distance methods. "boundary_x" is the @@ -1228,7 +1333,7 @@ TEST_F(S2PolygonTestBase, GetDistance) { // sphere, it is not straightforward to project points onto any edge except // along the equator. (The equator is the only line of latitude that is // also a geodesic.) - scoped_ptr nested(S2Testing::MakePolygon( + unique_ptr nested(s2textformat::MakePolygon( "3:1, 3:-1, -3:-1, -3:1; 4:2, 4:-2, -4:-2, -4:2;")); // All points on the boundary of the polygon should be at distance zero. @@ -1263,6 +1368,8 @@ TEST_F(S2PolygonTestBase, GetDistance) { class IsValidTest : public testing::Test { public: IsValidTest() { + init_oriented_ = false; + modify_polygon_hook_ = NULL; rnd_ = &S2Testing::rnd; rnd_->Reset(FLAGS_s2_random_seed); } @@ -1306,7 +1413,14 @@ class IsValidTest : public testing::Test { loops.push_back(new S2Loop(*vloops_[i], DISABLE_S2DEBUG)); } std::random_shuffle(loops.begin(), loops.end(), *rnd_); - S2Polygon polygon(&loops, DISABLE_S2DEBUG); + S2Polygon polygon; + polygon.set_s2debug_override(DISABLE_S2DEBUG); + if (init_oriented_) { + polygon.InitOriented(&loops); + } else { + polygon.InitNested(&loops); + } + if (modify_polygon_hook_) (*modify_polygon_hook_)(&polygon); S2Error error; EXPECT_TRUE(polygon.FindValidationError(&error)); EXPECT_TRUE(error.text().find(snippet) != string::npos) @@ -1317,6 +1431,8 @@ class IsValidTest : public testing::Test { protected: static int const kIters = 100; + bool init_oriented_; + void (*modify_polygon_hook_)(S2Polygon*); S2Testing::Random* rnd_; vector*> vloops_; }; @@ -1436,6 +1552,44 @@ TEST_F(IsValidTest, DuplicateEdge) { } } +TEST_F(IsValidTest, InconsistentOrientations) { + for (int iter = 0; iter < kIters; ++iter) { + AddConcentricLoops(2 + rnd_->Uniform(5), 3 /*min_vertices*/); + init_oriented_ = true; + CheckInvalid("Inconsistent loop orientations"); + } +} + +static void SetInvalidLoopDepth(S2Polygon* polygon) { + int i = S2Testing::rnd.Uniform(polygon->num_loops()); + if (i == 0 || S2Testing::rnd.OneIn(3)) { + polygon->loop(i)->set_depth(-1); + } else { + polygon->loop(i)->set_depth(polygon->loop(i-1)->depth() + 2); + } +} + +TEST_F(IsValidTest, LoopDepthNegative) { + modify_polygon_hook_ = SetInvalidLoopDepth; + for (int iter = 0; iter < kIters; ++iter) { + AddConcentricLoops(1 + rnd_->Uniform(4), 3 /*min_vertices*/); + CheckInvalid("invalid loop depth"); + } +} + +static void SetInvalidLoopNesting(S2Polygon* polygon) { + int i = S2Testing::rnd.Uniform(polygon->num_loops()); + polygon->loop(i)->Invert(); +} + +TEST_F(IsValidTest, LoopNestingInvalid) { + modify_polygon_hook_ = SetInvalidLoopNesting; + for (int iter = 0; iter < kIters; ++iter) { + AddConcentricLoops(2 + rnd_->Uniform(4), 3 /*min_vertices*/); + CheckInvalid("Invalid nesting"); + } +} + TEST_F(IsValidTest, FuzzTest) { // Check that the S2Loop/S2Polygon constructors and IsValid() don't crash // when they receive arbitrary invalid input. (We don't test large inputs; @@ -1556,7 +1710,7 @@ class S2PolygonSimplifierTest : public ::testing::Test { } void SetInput(string const& poly, double tolerance_in_degrees) { - SetInput(S2Testing::MakePolygon(poly), tolerance_in_degrees); + SetInput(s2textformat::MakePolygon(poly), tolerance_in_degrees); } S2Polygon* simplified; @@ -1578,7 +1732,7 @@ TEST_F(S2PolygonSimplifierTest, SimplifiedLoopSelfIntersects) { // To make sure that this test does something, we check // that the vertex 10:-0.2 is not in the simplification anymore. - S2Point test_point = S2Testing::MakePoint("10:-0.2"); + S2Point test_point = s2textformat::MakePoint("10:-0.2"); EXPECT_LT(0.05, simplified->GetDistance(test_point).degrees()); EXPECT_GE(0.22, MaximumDistanceInDegrees(*simplified, *original, 0)); @@ -1627,8 +1781,8 @@ TEST_F(S2PolygonSimplifierTest, EdgesOverlap) { // Two loops, One edge of the second one ([0:1 - 0:2]) is part of an // edge of the first one.. SetInput("0:0, 0:3, 1:0; 0:1, -1:1, 0:2", 0.01); - scoped_ptr true_poly( - S2Testing::MakePolygon("0:3, 1:0, 0:0, 0:1, -1:1, 0:2")); + unique_ptr true_poly( + s2textformat::MakePolygon("0:3, 1:0, 0:0, 0:1, -1:1, 0:2")); EXPECT_TRUE(simplified->BoundaryApproxEquals(true_poly.get())); } @@ -1657,7 +1811,7 @@ S2Polygon* MakeCellLoop(const S2Cell& cell, string const& str) { TEST(InitToSimplifiedInCell, PointsOnCellBoundaryKept) { S2CellId cell_id = S2CellId::FromToken("89c25c"); S2Cell cell(cell_id); - scoped_ptr loop(MakeCellLoop(cell, "0.1:0, 0.2:0, 0.2:0.5")); + unique_ptr loop(MakeCellLoop(cell, "0.1:0, 0.2:0, 0.2:0.5")); S1Angle tolerance = S1Angle(loop->loop(0)->vertex(0), loop->loop(0)->vertex(1)) * 1.1; S2Polygon simplified_loop; @@ -1674,7 +1828,7 @@ TEST(InitToSimplifiedInCell, PointsOnCellBoundaryKept) { TEST(InitToSimplifiedInCell, PointsInsideCellSimplified) { S2CellId cell_id = S2CellId::FromToken("89c25c"); S2Cell cell(cell_id); - scoped_ptr loop(MakeCellLoop(cell, + unique_ptr loop(MakeCellLoop(cell, "0.1:0, 0.2:0, 0.2:0.5, 0.2:0.8")); S1Angle tolerance = S1Angle(loop->loop(0)->vertex(0), loop->loop(0)->vertex(1)) * 1.1; @@ -1687,9 +1841,8 @@ TEST(InitToSimplifiedInCell, PointsInsideCellSimplified) { S2Polygon* MakeRegularPolygon(const string& center, int num_points, double radius_in_degrees) { - S1Angle radius = S1Angle::Degrees(radius_in_degrees); - S2Loop* l = S2Testing::MakeRegularLoop(S2Testing::MakePoint(center), + S2Loop* l = S2Testing::MakeRegularLoop(s2textformat::MakePoint(center), radius, num_points); vector loops; loops.push_back(l); @@ -1712,3 +1865,124 @@ TEST_F(S2PolygonSimplifierTest, LargeRegularPolygon) { EXPECT_GE(250, simplified->num_vertices()); EXPECT_LE(200, simplified->num_vertices()); } + +class S2PolygonDecodeTest : public ::testing::Test { + protected: + S2PolygonDecodeTest() : data_array_(kMaxBytes) { + encoder_.reset(data_array_.data(), kMaxBytes); + } + + ~S2PolygonDecodeTest() override {} + + void AppendByte(int value) { + encoder_.put8(value); + } + + void AppendInt32(int value) { + encoder_.put32(value); + } + + void AppendRandomData(int size) { + for (int i = 0; i < size && encoder_.avail() > 0; ++i) { + AppendByte(random_.Uniform(256)); + } + } + + void AppendRandomData() { + AppendRandomData(random_.Uniform(kMaxBytes)); + } + + void AppendFakeLosslessEncodingData() { + AppendByte(1); // polygon number + AppendByte(0); // unused + AppendByte(0); // "has holes" flag + AppendInt32(PickRandomCount()); // num loops + AppendByte(1); // loop version + AppendInt32(PickRandomCount()); // num vertices + AppendRandomData(); // junk to fill out the buffer + } + + void AppendFakeCompressedEncodingData() { + AppendByte(4); // polygon number + AppendByte(random_.Uniform(50)); // snap level + AppendInt32(PickRandomCount()); // num loops + AppendInt32(PickRandomCount()); // num vertices + AppendRandomData(); // junk to fill out the buffer + } + + int32 PickRandomCount() { + if (random_.OneIn(10)) { + return -1; + } + if (random_.OneIn(10)) { + return 0; + } + if (random_.OneIn(10)) { + return 1000000000; + } + if (random_.OneIn(2)) { + return random_.Uniform(1000000000); + } + return random_.Uniform(1000); + } + + bool Test() { + decoder_.reset(data_array_.data(), encoder_.length()); + encoder_.clear(); + S2Polygon polygon; + polygon.set_s2debug_override(DISABLE_S2DEBUG); + return polygon.Decode(&decoder_); + } + + // Random number generator. + S2Testing::Random random_; + + // Maximum size of the data array. + const int kMaxBytes = 256; + + // The data array. + FixedArray data_array_; + + // Encoder that is used to put data into the array. + Encoder encoder_; + + // Decoder used to extract data from the array. + Decoder decoder_; +}; + +TEST_F(S2PolygonDecodeTest, FuzzLosslessEncoding) { + // Some parts of the S2 library DCHECK on invalid data, even if we set + // FLAGS_s2debug to false or use S2Polygon::set_s2debug_override. So we + // only run this test in opt mode. +#ifdef NDEBUG + for (int i = 0; i < 100000; ++i) { + AppendFakeLosslessEncodingData(); + Test(); + } +#endif +} + +TEST_F(S2PolygonDecodeTest, FuzzCompressedEncoding) { + // Some parts of the S2 library DCHECK on invalid data, even if we set + // FLAGS_s2debug to false or use S2Polygon::set_s2debug_override. So we + // only run this test in opt mode. +#ifdef NDEBUG + for (int i = 0; i < 100000; ++i) { + AppendFakeCompressedEncodingData(); + Test(); + } +#endif +} + +TEST_F(S2PolygonDecodeTest, FuzzEverything) { + // Some parts of the S2 library DCHECK on invalid data, even if we set + // FLAGS_s2debug to false or use S2Polygon::set_s2debug_override. So we + // only run this test in opt mode. +#ifdef NDEBUG + for (int i = 0; i < 100000; ++i) { + AppendRandomData(); + Test(); + } +#endif +} + diff --git a/src/s2polygonbuilder.cc b/src/s2polygonbuilder.cc index 7e8912cd..ec7f8a43 100644 --- a/src/s2polygonbuilder.cc +++ b/src/s2polygonbuilder.cc @@ -12,27 +12,24 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2polygonbuilder.h" #include #include -#include -using __gnu_cxx::hash; -using __gnu_cxx::hash_map; -#include -using __gnu_cxx::hash; -using __gnu_cxx::hash_set; +#include +#include #include #include #include +#include #include #include #include #include "base/macros.h" -#include "base/scoped_ptr.h" #include "s2.h" #include "s2cellid.h" #include "s2edgeutil.h" @@ -43,6 +40,7 @@ using __gnu_cxx::hash_set; using std::min; using std::pair; +using std::unique_ptr; using std::vector; void S2PolygonBuilderOptions::set_undirected_edges(bool undirected_edges) { @@ -104,15 +102,15 @@ int S2PolygonBuilderOptions::GetSnapLevel() const { } S2PolygonBuilder::S2PolygonBuilder(S2PolygonBuilderOptions const& options) - : options_(options), edges_(new EdgeSet) { + : options_(options) { } S2PolygonBuilder::~S2PolygonBuilder() { } bool S2PolygonBuilder::HasEdge(S2Point const& v0, S2Point const& v1) { - EdgeSet::const_iterator candidates = edges_->find(v0); - return (candidates != edges_->end() && + EdgeSet::const_iterator candidates = edges_.find(v0); + return (candidates != edges_.end() && candidates->second.find(v1) != candidates->second.end()); } @@ -125,11 +123,11 @@ bool S2PolygonBuilder::AddEdge(S2Point const& v0, S2Point const& v1) { EraseEdge(v1, v0); return false; } - if (edges_->find(v0) == edges_->end()) starting_vertices_.push_back(v0); - (*edges_)[v0].insert(v1); + if (edges_.find(v0) == edges_.end()) starting_vertices_.push_back(v0); + edges_[v0].insert(v1); if (options_.undirected_edges()) { - if (edges_->find(v1) == edges_->end()) starting_vertices_.push_back(v1); - (*edges_)[v1].insert(v0); + if (edges_.find(v1) == edges_.end()) starting_vertices_.push_back(v1); + edges_[v1].insert(v0); } return true; } @@ -138,10 +136,18 @@ void S2PolygonBuilder::AddLoop(S2Loop const* loop) { // Ignore loops that do not have a boundary. if (loop->is_empty_or_full()) return; - int sign = loop->sign(); - for (int i = loop->num_vertices(); i > 0; --i) { - // Vertex indices need to be in the range [0, 2*num_vertices()-1]. - AddEdge(loop->vertex(i), loop->vertex(i + sign)); + const int n = loop->num_vertices(); + if (loop->sign() > 0) { + for (int i = 0; i < n; ++i) { + AddEdge(loop->vertex(i), loop->vertex(i + 1)); + } + } else { + // In order to preserve the cyclic order of the loop vertices, we need to + // add the last edge first. This is because AssembleLoops() tries to + // assemble loops starting from vertices in the order they were added. + for (int i = 2 * n - 1; i >= n; --i) { + AddEdge(loop->vertex(i), loop->vertex(i - 1)); + } } } @@ -155,16 +161,16 @@ void S2PolygonBuilder::EraseEdge(S2Point const& v0, S2Point const& v1) { // Note that there may be more than one copy of an edge if we are not XORing // them, so a VertexSet is a multiset. - VertexSet* vset = &(*edges_)[v0]; + VertexSet* vset = &edges_[v0]; DCHECK(vset->find(v1) != vset->end()); vset->erase(vset->find(v1)); - if (vset->empty()) edges_->erase(v0); + if (vset->empty()) edges_.erase(v0); if (options_.undirected_edges()) { - vset = &(*edges_)[v1]; + vset = &edges_[v1]; DCHECK(vset->find(v0) != vset->end()); vset->erase(vset->find(v0)); - if (vset->empty()) edges_->erase(v1); + if (vset->empty()) edges_.erase(v1); } } @@ -184,8 +190,8 @@ void S2PolygonBuilder::DumpVertex(S2Point const& v) const { void S2PolygonBuilder::DumpEdges(S2Point const& v0) const { DumpVertex(v0); std::cout << ":\n"; - EdgeSet::const_iterator candidates = edges_->find(v0); - if (candidates != edges_->end()) { + EdgeSet::const_iterator candidates = edges_.find(v0); + if (candidates != edges_.end()) { VertexSet const& vset = candidates->second; for (VertexSet::const_iterator i = vset.begin(); i != vset.end(); ++i) { std::cout << " "; @@ -196,7 +202,7 @@ void S2PolygonBuilder::DumpEdges(S2Point const& v0) const { } void S2PolygonBuilder::Dump() const { - for (EdgeSet::const_iterator i = edges_->begin(); i != edges_->end(); ++i) { + for (EdgeSet::const_iterator i = edges_.begin(); i != edges_.end(); ++i) { DumpEdges(i->first); } } @@ -223,7 +229,7 @@ S2Loop* S2PolygonBuilder::AssembleLoop(S2Point const& v0, S2Point const& v1, vector path; // The path so far. // Maps a vertex to its index in "path". - hash_map index; + std::unordered_map index; path.push_back(v0); path.push_back(v1); @@ -234,8 +240,8 @@ S2Loop* S2PolygonBuilder::AssembleLoop(S2Point const& v0, S2Point const& v1, S2Point const& v1 = path.end()[-1]; S2Point v2; bool v2_found = false; - EdgeSet::const_iterator candidates = edges_->find(v1); - if (candidates != edges_->end()) { + EdgeSet::const_iterator candidates = edges_.find(v1); + if (candidates != edges_.end()) { VertexSet const& vset = candidates->second; for (VertexSet::const_iterator i = vset.begin(); i != vset.end(); ++i) { // We prefer the leftmost outgoing edge, ignoring any reverse edges. @@ -254,14 +260,12 @@ S2Loop* S2PolygonBuilder::AssembleLoop(S2Point const& v0, S2Point const& v1, // This is the first time we've visited this vertex. path.push_back(v2); } else { - // We've completed a loop. In a simple case last edge is the same as the - // first one (since we did not add the very first vertex to the index we - // would not know that the loop is completed till the second vertex is - // examined). In this case we just remove the last edge to preserve the - // original vertex order. In a more complicated case the edge that closed - // the loop is different and we should remove initial vertices that are - // not part of the loop. - if (index[v2] == 1 && path[0] == path[path.size() - 1]) { + // We've completed a loop. Usually the loop ends at the edge we started + // with, in which case we remove the last vertex in order to ensure that + // the loop starts with the given vertex "v0" whenever possible. More + // rarely, the path may have a prefix of vertices that are not part of + // the loop, in which case those vertices need to be removed. + if (index[v2] == 1 && path.front() == path.back()) { path.pop_back(); } else { path.erase(path.begin(), path.begin() + index[v2]); @@ -284,7 +288,7 @@ S2Loop* S2PolygonBuilder::AssembleLoop(S2Point const& v0, S2Point const& v1, } if (options_.undirected_edges() && !loop->IsNormalized()) { - scoped_ptr deleter(loop); // XXX for debugging + unique_ptr deleter(loop); // XXX for debugging return AssembleLoop(path[1], path[0], unused_edges); } return loop; @@ -430,8 +434,8 @@ void S2PolygonBuilder::BuildMergeMap(PointIndex* index, MergeMap* merge_map) { // First, we build the set of all the distinct vertices in the input. // We need to include the source and destination of every edge. - hash_set vertices; - for (EdgeSet::const_iterator i = edges_->begin(); i != edges_->end(); ++i) { + std::unordered_set vertices; + for (EdgeSet::const_iterator i = edges_.begin(); i != edges_.end(); ++i) { vertices.insert(i->first); VertexSet const& vset = i->second; for (VertexSet::const_iterator j = vset.begin(); j != vset.end(); ++j) @@ -439,7 +443,7 @@ void S2PolygonBuilder::BuildMergeMap(PointIndex* index, MergeMap* merge_map) { } // Build a spatial index containing all the distinct vertices. - for (hash_set::const_iterator i = vertices.begin(); + for (std::unordered_set::const_iterator i = vertices.begin(); i != vertices.end(); ++i) { index->Insert(*i); } @@ -447,7 +451,7 @@ void S2PolygonBuilder::BuildMergeMap(PointIndex* index, MergeMap* merge_map) { // Next, we loop through all the vertices and attempt to grow a maximial // mergeable group starting from each vertex. vector frontier, mergeable; - for (hash_set::const_iterator vstart = vertices.begin(); + for (std::unordered_set::const_iterator vstart = vertices.begin(); vstart != vertices.end(); ++vstart) { // Skip any vertices that have already been merged with another vertex. if (merge_map->find(*vstart) != merge_map->end()) continue; @@ -478,7 +482,7 @@ void S2PolygonBuilder::MoveVertices(MergeMap const& merge_map) { // We need to copy the set of edges affected by the move, since // edges_ could be reallocated when we start modifying it. vector > edges; - for (EdgeSet::const_iterator i = edges_->begin(); i != edges_->end(); ++i) { + for (EdgeSet::const_iterator i = edges_.begin(); i != edges_.end(); ++i) { S2Point const& v0 = i->first; VertexSet const& vset = i->second; for (VertexSet::const_iterator j = vset.begin(); j != vset.end(); ++j) { @@ -512,7 +516,7 @@ void S2PolygonBuilder::SpliceEdges(PointIndex const& index) { // We keep a stack of unprocessed edges. Initially all edges are // pushed onto the stack. vector > edges; - for (EdgeSet::const_iterator i = edges_->begin(); i != edges_->end(); ++i) { + for (EdgeSet::const_iterator i = edges_.begin(); i != edges_.end(); ++i) { S2Point const& v0 = i->first; VertexSet const& vset = i->second; for (VertexSet::const_iterator j = vset.begin(); j != vset.end(); ++j) { @@ -561,7 +565,7 @@ S2Loop* SnapLoopToLevel(S2Loop const& loop, int level) { } return new S2Loop(snapped_vertices); } -} +} // namespace bool S2PolygonBuilder::AssembleLoops(vector* loops, EdgeList* unused_edges) { @@ -583,15 +587,20 @@ bool S2PolygonBuilder::AssembleLoops(vector* loops, // We repeatedly choose an edge and attempt to assemble a loop // starting from that edge. (This is always possible unless the - // input includes extra edges that are not part of any loop.) To - // maintain a consistent scanning order over edges_ between - // different machine architectures (e.g. 'clovertown' vs. 'opteron'), - // we follow the order they were added to the builder. + // input includes extra edges that are not part of any loop.) + // + // In order to maintain a consistent scanning order over edges_ between + // different machine architectures, we visit each vertex in the order they + // were added to the builder, and then try all outgoing edges from that + // vertex. This also helps to preserve the cyclic order of the vertices + // within each loop in the case where the input was already a polygon (e.g., + // when doing snapping). This strategy works well except in the case where + // more than one loop shares a common vertex. unused_edges->clear(); for (int i = 0; i < starting_vertices_.size(); ) { S2Point const& v0 = starting_vertices_[i]; - EdgeSet::const_iterator candidates = edges_->find(v0); - if (candidates == edges_->end()) { + EdgeSet::const_iterator candidates = edges_.find(v0); + if (candidates == edges_.end()) { ++i; continue; } @@ -657,4 +666,4 @@ bool S2PolygonBuilder::AssemblePolygon(S2Polygon* polygon, return false; } return success; -} \ No newline at end of file +} diff --git a/src/s2polygonbuilder.h b/src/s2polygonbuilder.h index 1214bd55..4928be49 100644 --- a/src/s2polygonbuilder.h +++ b/src/s2polygonbuilder.h @@ -12,20 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2POLYGONBUILDER_H__ -#define UTIL_GEOMETRY_S2POLYGONBUILDER_H__ +#ifndef S2_GEOMETRY_S2POLYGONBUILDER_H__ +#define S2_GEOMETRY_S2POLYGONBUILDER_H__ -#include -using __gnu_cxx::hash; -using __gnu_cxx::hash_map; +#include +#include #include #include #include #include "base/macros.h" -#include "base/scoped_ptr.h" +#include "fpcontractoff.h" #include "s1angle.h" #include "s2.h" #include "util/math/matrix3x3.h" @@ -321,7 +321,6 @@ class S2PolygonBuilder { void Dump() const; private: - // Return true if the given edge exists. bool HasEdge(S2Point const& v0, S2Point const& v1); @@ -343,7 +342,7 @@ class S2PolygonBuilder { // containing all of the vertices that do not need to be moved. class PointIndex; - typedef hash_map MergeMap; + typedef std::unordered_map MergeMap; void BuildMergeMap(PointIndex* index, MergeMap* merge_map); // Moves a set of vertices from old to new positions. @@ -356,15 +355,15 @@ class S2PolygonBuilder { S2PolygonBuilderOptions options_; // This is only used for debugging purposes. - scoped_ptr debug_matrix_; + std::unique_ptr debug_matrix_; // The current set of edges, grouped by origin. The set of destination // vertices is a multiset so that the same edge can be present more than // once. We could have also used a multiset >, // but this representation is a bit more convenient. typedef std::multiset VertexSet; - typedef hash_map EdgeSet; - scoped_ptr edges_; + typedef std::unordered_map EdgeSet; + EdgeSet edges_; // Unique collection of the starting (first) vertex of all edges, // in the order they are added to edges_. @@ -390,4 +389,4 @@ inline S2PolygonBuilderOptions S2PolygonBuilderOptions::UNDIRECTED_UNION() { return options; } -#endif // UTIL_GEOMETRY_S2POLYGONBUILDER_H__ \ No newline at end of file +#endif // S2_GEOMETRY_S2POLYGONBUILDER_H__ diff --git a/src/s2polygonbuilder_test.cc b/src/s2polygonbuilder_test.cc index 16455a37..d4e97739 100644 --- a/src/s2polygonbuilder_test.cc +++ b/src/s2polygonbuilder_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2polygonbuilder.h" @@ -19,15 +20,15 @@ #include #include #include +#include #include #include #include #include "base/macros.h" #include "base/port.h" -#include "base/scoped_ptr.h" #include "base/stringprintf.h" -#include "gtest/gtest.h" +#include #include "s2.h" #include "s2cap.h" #include "s2edgeutil.h" @@ -36,11 +37,13 @@ #include "s2polygon.h" #include "s2polyline.h" #include "s2testing.h" +#include "s2textformat.h" #include "util/math/matrix3x3.h" using std::max; using std::min; using std::pair; +using std::unique_ptr; using std::vector; namespace { @@ -241,7 +244,7 @@ void GetVertices(char const* str, Matrix3x3_d const& m, vector* vertices) { // Parse the vertices and transform them into the given frame. - scoped_ptr line(S2Testing::MakePolyline(str)); + unique_ptr line(s2textformat::MakePolyline(str)); for (int i = 0; i < line->num_vertices(); ++i) { vertices->push_back((m * line->vertex(i)).Normalize()); } @@ -344,7 +347,6 @@ bool UnexpectedUnusedEdgeCount(int num_actual, int num_expected, void DumpUnusedEdges(vector > const& unused_edges, Matrix3x3_d const& m, int num_expected) { - // Print the unused edges, transformed back into their original // latitude-longitude space in degrees. @@ -542,7 +544,6 @@ bool TestBuilder(TestCase const* test) { max_splits, max_error, "Expected") | UnexpectedUnusedEdgeCount(unused_edges.size(), test->num_unused_edges, max_splits)) { - // We found a problem. Print out the relevant parameters. DumpUnusedEdges(unused_edges, m, test->num_unused_edges); fprintf(stderr, "During iteration %d:\n undirected: %d\n xor: %d\n" @@ -573,10 +574,8 @@ TEST(S2PolygonBuilder, AssembleLoops) { } TEST(S2PolygonBuilder, BuilderProducesValidPolygons) { - // Polygon is from - // http://oyster-explorer/q?q=0x3921163aa35a0aed:0xe7714a1275a29ec4 - scoped_ptr polygon( - S2Testing::MakePolygon( + unique_ptr polygon( + s2textformat::MakePolygon( "32.2983095:72.3416582, 32.2986281:72.3423059, " "32.2985238:72.3423743, 32.2987176:72.3427807, " "32.2988174:72.3427056, 32.2991269:72.3433480, " @@ -594,28 +593,12 @@ TEST(S2PolygonBuilder, BuilderProducesValidPolygons) { S2Polygon robust_polygon; S2PolygonBuilder polygon_builder(options); polygon_builder.AddPolygon(polygon.get()); - // The bug triggers a DCHECK failure, so look for that in dbg mode, but - // an invalid polygon in opt mode. - EXPECT_DEBUG_DEATH( - ASSERT_TRUE(polygon_builder.AssemblePolygon(&robust_polygon, NULL)); - - // This should be EXPECT_TRUE, but there is a bug. - // The polygon produced contains two identical loops, and is: - // 32.298455799999999:72.341453000000001, - // 32.298523800000005:72.342374300000003, - // 32.298717600000003:72.342780700000006, - // 32.299049799999999:72.343007299999996; - // 32.298455799999999:72.341453000000001, - // 32.298523800000005:72.342374300000003, - // 32.298717600000003:72.342780700000006, - // 32.299049799999999:72.343007299999996 - EXPECT_FALSE(robust_polygon.IsValid()) - << "S2PolygonBuilder created invalid polygon\n" - << S2Testing::ToString(&robust_polygon) - << "\nfrom valid original polygon\n" - << S2Testing::ToString(polygon.get()), - "Check failed: parent == NULL \\|\\| " - "!new_loop->ContainsNested\\(parent\\)"); + ASSERT_TRUE(polygon_builder.AssemblePolygon(&robust_polygon, NULL)); + EXPECT_TRUE(robust_polygon.IsValid()) + << "S2PolygonBuilder created invalid polygon\n" + << s2textformat::ToString(&robust_polygon) + << "\nfrom valid original polygon\n" + << s2textformat::ToString(polygon.get()); } TEST(S2PolygonBuilderOptions, SnapLevel) { @@ -648,4 +631,4 @@ TEST(S2PolygonBuilderOptions, SnapLevel) { EXPECT_EQ(-1, options.GetSnapLevel()); } -} // namespace \ No newline at end of file +} // namespace diff --git a/src/s2polyline.cc b/src/s2polyline.cc index 04df786e..d94c0df1 100644 --- a/src/s2polyline.cc +++ b/src/s2polyline.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2polyline.h" @@ -462,7 +463,7 @@ int FindEndVertex(S2Polyline const& polyline, // included in the line segment, so back up by one vertex. return index - 1; } -} +} // namespace void S2Polyline::SubsampleVertices(S1Angle tolerance, vector* indices) const { @@ -513,22 +514,18 @@ struct SearchState { int j; bool i_in_progress; }; -} // namespace -namespace std { -template<> -struct less { - // This operator is needed for storing SearchStates in a set. The ordering - // chosen has no special meaning. - inline bool operator()(SearchState const& lhs, SearchState const& rhs) const { - if (lhs.i < rhs.i) return true; - if (lhs.i > rhs.i) return false; - if (lhs.j < rhs.j) return true; - if (lhs.j > rhs.j) return false; - return !lhs.i_in_progress && rhs.i_in_progress; +// This operator is needed for storing SearchStates in a set. The ordering +// chosen has no special meaning. +struct SearchStateKeyCompare { + bool operator() (SearchState const& a, SearchState const& b) const { + if (a.i != b.i) return a.i < b.i; + if (a.j != b.j) return a.j < b.j; + return a.i_in_progress < b.i_in_progress; } }; -} // namespace std + +} // namespace bool S2Polyline::NearlyCoversPolyline(S2Polyline const& covered, S1Angle max_error) const { @@ -576,7 +573,7 @@ bool S2Polyline::NearlyCoversPolyline(S2Polyline const& covered, // // TODO(user): Benchmark this, and see if the set is worth it. vector pending; - set done; + set done; // Find all possible starting states. for (int i = 0, next_i = NextDistinctVertex(*this, 0); @@ -626,4 +623,4 @@ bool S2Polyline::NearlyCoversPolyline(S2Polyline const& covered, } } return false; -} \ No newline at end of file +} diff --git a/src/s2polyline.h b/src/s2polyline.h index 4ed7c720..ce64f2e7 100644 --- a/src/s2polyline.h +++ b/src/s2polyline.h @@ -12,15 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2POLYLINE_H__ -#define UTIL_GEOMETRY_S2POLYLINE_H__ +#ifndef S2_GEOMETRY_S2POLYLINE_H__ +#define S2_GEOMETRY_S2POLYLINE_H__ #include #include #include "base/macros.h" +#include "fpcontractoff.h" #include "s2.h" #include "s2latlngrect.h" #include "s2region.h" @@ -42,8 +44,8 @@ class S2Polyline : public S2Region { S2Polyline(); // Convenience constructors that call Init() with the given vertices. - S2Polyline(std::vector const& vertices); - S2Polyline(std::vector const& vertices); + explicit S2Polyline(std::vector const& vertices); + explicit S2Polyline(std::vector const& vertices); // Convenience constructors to disable the automatic validity checking // controlled by the --s2debug flag. Example: @@ -234,7 +236,7 @@ class S2Polyline : public S2Region { private: // Internal constructor used only by Clone() that makes a deep copy of // its argument. - S2Polyline(S2Polyline const* src); + explicit S2Polyline(S2Polyline const* src); // Return true if the given vertices form a valid polyline. static bool IsValid(S2Point const* vertices, int num_vertices); @@ -252,4 +254,4 @@ class S2Polyline : public S2Region { DISALLOW_COPY_AND_ASSIGN(S2Polyline); }; -#endif // UTIL_GEOMETRY_S2POLYLINE_H__ \ No newline at end of file +#endif // S2_GEOMETRY_S2POLYLINE_H__ diff --git a/src/s2polyline_test.cc b/src/s2polyline_test.cc index 47d37d85..1af8be3c 100644 --- a/src/s2polyline_test.cc +++ b/src/s2polyline_test.cc @@ -12,35 +12,38 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2polyline.h" #include +#include #include #include #include -#include "base/scoped_ptr.h" #include "base/stringprintf.h" -#include "gtest/gtest.h" +#include #include "util/coding/coder.h" #include "s1angle.h" #include "s2.h" #include "s2cell.h" #include "s2latlng.h" #include "s2testing.h" +#include "s2textformat.h" +using std::unique_ptr; using std::vector; namespace { S2Polyline* MakePolyline(string const& str) { - scoped_ptr polyline(S2Testing::MakePolyline(str)); + unique_ptr polyline(s2textformat::MakePolyline(str)); Encoder encoder; polyline->Encode(&encoder); Decoder decoder(encoder.base(), encoder.length()); - scoped_ptr decoded_polyline(new S2Polyline); + unique_ptr decoded_polyline(new S2Polyline); decoded_polyline->Decode(&decoder); return decoded_polyline.release(); } @@ -140,7 +143,7 @@ TEST(S2Polyline, UnInterpolate) { vector vertices; vertices.push_back(S2Point(1, 0, 0)); S2Polyline point_line(vertices); - EXPECT_DOUBLE_EQ(0.0, point_line.UnInterpolate(S2Point (0, 1, 0), 1)); + EXPECT_DOUBLE_EQ(0.0, point_line.UnInterpolate(S2Point(0, 1, 0), 1)); vertices.push_back(S2Point(0, 1, 0)); vertices.push_back(S2Point(0, 1, 1).Normalize()); @@ -229,22 +232,22 @@ TEST(S2Polyline, IsOnRight) { } TEST(S2Polyline, IntersectsEmptyPolyline) { - scoped_ptr line1(S2Testing::MakePolyline("1:1, 4:4")); + unique_ptr line1(s2textformat::MakePolyline("1:1, 4:4")); S2Polyline empty_polyline; EXPECT_FALSE(empty_polyline.Intersects(line1.get())); } TEST(S2Polyline, IntersectsOnePointPolyline) { - scoped_ptr line1(S2Testing::MakePolyline("1:1, 4:4")); - scoped_ptr line2(S2Testing::MakePolyline("1:1")); + unique_ptr line1(s2textformat::MakePolyline("1:1, 4:4")); + unique_ptr line2(s2textformat::MakePolyline("1:1")); EXPECT_FALSE(line1->Intersects(line2.get())); } TEST(S2Polyline, Intersects) { - scoped_ptr line1(S2Testing::MakePolyline("1:1, 4:4")); - scoped_ptr small_crossing(S2Testing::MakePolyline("1:2, 2:1")); - scoped_ptr small_noncrossing(S2Testing::MakePolyline("1:2, 2:3")); - scoped_ptr big_crossing(S2Testing::MakePolyline("1:2, 2:3, 4:3")); + unique_ptr line1(s2textformat::MakePolyline("1:1, 4:4")); + unique_ptr small_crossing(s2textformat::MakePolyline("1:2, 2:1")); + unique_ptr small_noncrossing(s2textformat::MakePolyline("1:2, 2:3")); + unique_ptr big_crossing(s2textformat::MakePolyline("1:2, 2:3, 4:3")); EXPECT_TRUE(line1->Intersects(small_crossing.get())); EXPECT_FALSE(line1->Intersects(small_noncrossing.get())); @@ -252,22 +255,22 @@ TEST(S2Polyline, Intersects) { } TEST(S2Polyline, IntersectsAtVertex) { - scoped_ptr line1(S2Testing::MakePolyline("1:1, 4:4, 4:6")); - scoped_ptr line2(S2Testing::MakePolyline("1:1, 1:2")); - scoped_ptr line3(S2Testing::MakePolyline("5:1, 4:4, 2:2")); + unique_ptr line1(s2textformat::MakePolyline("1:1, 4:4, 4:6")); + unique_ptr line2(s2textformat::MakePolyline("1:1, 1:2")); + unique_ptr line3(s2textformat::MakePolyline("5:1, 4:4, 2:2")); EXPECT_TRUE(line1->Intersects(line2.get())); EXPECT_TRUE(line1->Intersects(line3.get())); } TEST(S2Polyline, IntersectsVertexOnEdge) { - scoped_ptr horizontal_left_to_right( - S2Testing::MakePolyline("0:1, 0:3")); - scoped_ptr vertical_bottom_to_top( - S2Testing::MakePolyline("-1:2, 0:2, 1:2")); - scoped_ptr horizontal_right_to_left( - S2Testing::MakePolyline("0:3, 0:1")); - scoped_ptr vertical_top_to_bottom( - S2Testing::MakePolyline("1:2, 0:2, -1:2")); + unique_ptr horizontal_left_to_right( + s2textformat::MakePolyline("0:1, 0:3")); + unique_ptr vertical_bottom_to_top( + s2textformat::MakePolyline("-1:2, 0:2, 1:2")); + unique_ptr horizontal_right_to_left( + s2textformat::MakePolyline("0:3, 0:1")); + unique_ptr vertical_top_to_bottom( + s2textformat::MakePolyline("1:2, 0:2, -1:2")); EXPECT_TRUE(horizontal_left_to_right->Intersects( vertical_bottom_to_top.get())); EXPECT_TRUE(horizontal_left_to_right->Intersects( @@ -294,7 +297,7 @@ void CheckSubsample(char const* polyline_str, double tolerance_degrees, char const* expected_str) { SCOPED_TRACE(StringPrintf("\"%s\", tolerance %f", polyline_str, tolerance_degrees)); - scoped_ptr polyline(MakePolyline(polyline_str)); + unique_ptr polyline(MakePolyline(polyline_str)); vector indices; polyline->SubsampleVertices(S1Angle::Degrees(tolerance_degrees), &indices); EXPECT_EQ(expected_str, JoinInts(indices)); @@ -358,8 +361,8 @@ TEST(S2Polyline, SubsampleVerticesGuarantees) { static bool TestEquals(char const* a_str, char const* b_str, double max_error) { - scoped_ptr a(MakePolyline(a_str)); - scoped_ptr b(MakePolyline(b_str)); + unique_ptr a(MakePolyline(a_str)); + unique_ptr b(MakePolyline(b_str)); return a->ApproxEquals(b.get(), max_error); } @@ -384,7 +387,7 @@ TEST(S2Polyline, ApproxEquals) { } TEST(S2Polyline, EncodeDecode) { - scoped_ptr polyline(MakePolyline("0:0, 0:10, 10:20, 20:30")); + unique_ptr polyline(MakePolyline("0:0, 0:10, 10:20, 20:30")); Encoder encoder; polyline->Encode(&encoder); Decoder decoder(encoder.base(), encoder.length()); @@ -398,8 +401,8 @@ void TestNearlyCovers(string const& a_str, string const& b_str, bool expect_a_covers_b) { SCOPED_TRACE(StringPrintf("a=\"%s\", b=\"%s\", max error=%f", a_str.c_str(), b_str.c_str(), max_error_degrees)); - scoped_ptr a(S2Testing::MakePolyline(a_str)); - scoped_ptr b(S2Testing::MakePolyline(b_str)); + unique_ptr a(s2textformat::MakePolyline(a_str)); + unique_ptr b(s2textformat::MakePolyline(b_str)); S1Angle max_error = S1Angle::Degrees(max_error_degrees); EXPECT_EQ(expect_b_covers_a, b->NearlyCoversPolyline(*a, max_error)); EXPECT_EQ(expect_a_covers_b, a->NearlyCoversPolyline(*b, max_error)); @@ -474,4 +477,4 @@ TEST(S2PolylineCoveringTest, StraightAndWigglyPolylinesCoverEachOther) { 0.2, true, true); } -} // namespace \ No newline at end of file +} // namespace diff --git a/src/s2r2rect.cc b/src/s2r2rect.cc index 4b6db004..b8dfec72 100644 --- a/src/s2r2rect.cc +++ b/src/s2r2rect.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2r2rect.h" @@ -84,4 +85,4 @@ bool S2R2Rect::MayIntersect(S2Cell const& cell) const { std::ostream& operator<<(std::ostream& os, S2R2Rect const& r) { return os << "[Lo" << r.lo() << ", Hi" << r.hi() << "]"; -} \ No newline at end of file +} diff --git a/src/s2r2rect.h b/src/s2r2rect.h index d92c276a..065051cd 100644 --- a/src/s2r2rect.h +++ b/src/s2r2rect.h @@ -12,14 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2R2RECT_H_ -#define UTIL_GEOMETRY_S2R2RECT_H_ +#ifndef S2_GEOMETRY_S2R2RECT_H_ +#define S2_GEOMETRY_S2R2RECT_H_ #include #include +#include "fpcontractoff.h" #include "r1interval.h" #include "r2.h" #include "r2rect.h" @@ -49,8 +51,8 @@ class S2LatLngRect; // The S2R2Rect class is also a convenient way to find the (s,t)-region // covered by a given S2CellId (see the FromCell and FromCellId methods). // -// TODO: If the geometry library is extended to have better support for planar -// geometry, then this class should no longer be necessary. +// TODO(ericv): If the geometry library is extended to have better support +// for planar geometry, then this class should no longer be necessary. // // This class is intended to be copied by value as desired. It uses // the default copy constructor and assignment operator, however it is @@ -58,7 +60,7 @@ class S2LatLngRect; class S2R2Rect : public S2Region { public: // Construct a rectangle from an R2Rect. - S2R2Rect(R2Rect const& rect); + explicit S2R2Rect(R2Rect const& rect); // Construct a rectangle from the given lower-left and upper-right points. S2R2Rect(R2Point const& lo, R2Point const& hi); @@ -292,4 +294,4 @@ inline bool S2R2Rect::ApproxEquals(S2R2Rect const& other, return rect_.ApproxEquals(other.rect_, max_error); } -#endif // UTIL_GEOMETRY_S2R2RECT_H_ \ No newline at end of file +#endif // S2_GEOMETRY_S2R2RECT_H_ diff --git a/src/s2r2rect_test.cc b/src/s2r2rect_test.cc index fe0da7fd..63f2c55c 100644 --- a/src/s2r2rect_test.cc +++ b/src/s2r2rect_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) // // Most of the S2R2Rect methods have trivial implementations in terms of the @@ -21,7 +22,7 @@ #include "base/integral_types.h" #include "base/stringprintf.h" -#include "gtest/gtest.h" +#include #include "r1interval.h" #include "s2.h" #include "s2cap.h" @@ -304,4 +305,4 @@ TEST(S2R2Rect, CellOperations) { TestCellOps(S2R2Rect(R2Point(0.99, -0.01), R2Point(1.01, 0.01)), S2Cell::FromFacePosLevel(0, ~uint64(0) >> S2CellId::kFaceBits, 5), 3); -} \ No newline at end of file +} diff --git a/src/s2region.cc b/src/s2region.cc index 748fad1e..507226ad 100644 --- a/src/s2region.cc +++ b/src/s2region.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2region.h" @@ -21,4 +22,4 @@ S2Region::~S2Region() { bool S2Region::DecodeWithinScope(Decoder* const decoder) { return Decode(decoder); -} \ No newline at end of file +} diff --git a/src/s2region.h b/src/s2region.h index f4597b4b..d16a60c1 100644 --- a/src/s2region.h +++ b/src/s2region.h @@ -12,11 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2REGION_H_ -#define UTIL_GEOMETRY_S2REGION_H_ +#ifndef S2_GEOMETRY_S2REGION_H_ +#define S2_GEOMETRY_S2REGION_H_ +#include "fpcontractoff.h" #include "s2.h" class Decoder; @@ -116,4 +118,4 @@ class S2Region { // subtypes may relax this restriction. }; -#endif // UTIL_GEOMETRY_S2REGION_H_ \ No newline at end of file +#endif // S2_GEOMETRY_S2REGION_H_ diff --git a/src/s2regioncoverer.cc b/src/s2regioncoverer.cc index 2808db8c..708f4685 100644 --- a/src/s2regioncoverer.cc +++ b/src/s2regioncoverer.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2regioncoverer.h" @@ -22,10 +23,8 @@ #include #include #include -#include -using __gnu_cxx::hash; -using __gnu_cxx::hash_set; #include +#include #include #include @@ -34,52 +33,26 @@ using __gnu_cxx::hash_set; #include "s2cap.h" #include "s2cellunion.h" #include "s2region.h" +#include "util/gtl/algorithm.h" using std::max; using std::min; +using std::unordered_set; using std::vector; // Define storage for header file constants (the values are not needed here). int const S2RegionCoverer::kDefaultMaxCells; -// We define our own own comparison function on QueueEntries in order to -// make the results deterministic. Using the default less, -// entries of equal priority would be sorted according to the memory address -// of the candidate. - -struct S2RegionCoverer::CompareQueueEntries : public std::less { - bool operator()(QueueEntry const& x, QueueEntry const& y) const { - return x.first < y.first; - } -}; - -static S2Cell face_cells[6]; - -void Init() { - for (int face = 0; face < 6; ++face) { - face_cells[face] = S2Cell::FromFace(face); - } -} - -static pthread_once_t init_once = PTHREAD_ONCE_INIT; -inline static void MaybeInit() { - pthread_once(&init_once, Init); -} - S2RegionCoverer::S2RegionCoverer() : min_level_(0), max_level_(S2CellId::kMaxLevel), level_mod_(1), max_cells_(kDefaultMaxCells), - region_(NULL), - result_(new vector), - pq_(new CandidateQueue) { - // Initialize the constants - MaybeInit(); + region_(NULL) { } S2RegionCoverer::~S2RegionCoverer() { - // Need to declare explicitly because of scoped pointers. + // Prevent inline destructor bloat by providing a definition. } void S2RegionCoverer::set_min_level(int min_level) { @@ -94,6 +67,11 @@ void S2RegionCoverer::set_max_level(int max_level) { max_level_ = max(0, min(S2CellId::kMaxLevel, max_level)); } +void S2RegionCoverer::set_fixed_level(int level) { + set_min_level(level); + set_max_level(level); +} + void S2RegionCoverer::set_level_mod(int level_mod) { DCHECK_GE(level_mod, 1); DCHECK_LE(level_mod, 3); @@ -173,7 +151,7 @@ void S2RegionCoverer::AddCandidate(Candidate* candidate) { if (candidate == NULL) return; if (candidate->is_terminal) { - result_->push_back(candidate->cell.id()); + result_.push_back(candidate->cell.id()); DeleteCandidate(candidate, true); return; } @@ -201,49 +179,52 @@ void S2RegionCoverer::AddCandidate(Candidate* candidate) { // We negate the priority so that smaller absolute priorities are returned // first. The heuristic is designed to refine the largest cells first, // since those are where we have the largest potential gain. Among cells - // at the same level, we prefer the cells with the smallest number of - // intersecting children. Finally, we prefer cells that have the smallest - // number of children that cannot be refined any further. + // of the same size, we prefer the cells with the fewest children. + // Finally, among cells with equal numbers of children we prefer those + // with the smallest number of children that cannot be refined further. int priority = -((((candidate->cell.level() << max_children_shift()) + candidate->num_children) << max_children_shift()) + num_terminals); - pq_->push(std::make_pair(priority, candidate)); + pq_.push(std::make_pair(priority, candidate)); VLOG(2) << "Push: " << candidate->cell.id() << " (" << priority << ") "; } } -void S2RegionCoverer::GetInitialCandidates() { - // Optimization: if at least 4 cells are desired (the normal case), - // start with a 4-cell covering of the region's bounding cap. This - // lets us skip quite a few levels of refinement when the region to - // be covered is relatively small. - if (max_cells() >= 4) { - // Find the maximum level such that the bounding cap contains at most one - // cell vertex at that level. - S2Cap cap = region_->GetCapBound(); - int level = min(S2::kMinWidth.GetMaxLevel(2 * cap.GetRadius().radians()), - min(max_level(), S2CellId::kMaxLevel - 1)); - if (level_mod() > 1 && level > min_level()) { - level -= (level - min_level()) % level_mod(); - } - // We don't bother trying to optimize the level == 0 case, since more than - // four face cells may be required. - if (level > 0) { - // Find the leaf cell containing the cap axis, and determine which - // subcell of the parent cell contains it. - vector base; - base.reserve(4); - S2CellId id = S2CellId::FromPoint(cap.center()); - id.AppendVertexNeighbors(level, &base); - for (int i = 0; i < base.size(); ++i) { - AddCandidate(NewCandidate(S2Cell(base[i]))); - } - return; - } +inline int S2RegionCoverer::AdjustLevel(int level) const { + if (level_mod() > 1 && level > min_level()) { + level -= (level - min_level()) % level_mod(); } - // Default: start with all six cube faces. - for (int face = 0; face < 6; ++face) { - AddCandidate(NewCandidate(face_cells[face])); + return level; +} + +void S2RegionCoverer::AdjustCellLevels(vector* cells) const { + DCHECK(util::gtl::is_sorted(cells->begin(), cells->end())); + if (level_mod() == 1) return; + + int out = 0; + for (int i = 0; i < cells->size(); ++i) { + S2CellId id = (*cells)[i]; + int level = id.level(); + int new_level = AdjustLevel(level); + if (new_level != level) id = id.parent(new_level); + if (out > 0 && (*cells)[out-1].contains(id)) continue; + while (out > 0 && id.contains((*cells)[out-1])) --out; + (*cells)[out++] = id; + } + cells->resize(out); +} + +void S2RegionCoverer::GetInitialCandidates() { + // Optimization: start with a small (usually 4 cell) covering of the + // region's bounding cap. + S2RegionCoverer tmp_coverer; + tmp_coverer.set_max_cells(min(4, max_cells())); + tmp_coverer.set_max_level(max_level()); + vector cells; + tmp_coverer.GetFastCovering(region_->GetCapBound(), &cells); + AdjustCellLevels(&cells); + for (int i = 0; i < cells.size(); ++i) { + AddCandidate(NewCandidate(S2Cell(cells[i]))); } } @@ -262,16 +243,16 @@ void S2RegionCoverer::GetCoveringInternal(S2Region const& region) { // children first), and then by the number of fully contained children // (fewest children first). - DCHECK(pq_->empty()); - DCHECK(result_->empty()); + DCHECK(pq_.empty()); + DCHECK(result_.empty()); region_ = ®ion; candidates_created_counter_ = 0; GetInitialCandidates(); - while (!pq_->empty() && - (!interior_covering_ || result_->size() < max_cells_)) { - Candidate* candidate = pq_->top().second; - pq_->pop(); + while (!pq_.empty() && + (!interior_covering_ || result_.size() < max_cells_)) { + Candidate* candidate = pq_.top().second; + pq_.pop(); VLOG(2) << "Pop: " << candidate->cell.id(); // For interior covering we keep subdividing no matter how many children // candidate has. If we reach max_cells_ before expanding all children, @@ -284,10 +265,10 @@ void S2RegionCoverer::GetCoveringInternal(S2Region const& region) { if (interior_covering_ || candidate->cell.level() < min_level_ || candidate->num_children == 1 || - result_->size() + pq_->size() + candidate->num_children <= max_cells_) { + result_.size() + pq_.size() + candidate->num_children <= max_cells_) { // Expand this candidate into its children. for (int i = 0; i < candidate->num_children; ++i) { - if (interior_covering_ && result_->size() >= max_cells_) { + if (interior_covering_ && result_.size() >= max_cells_) { DeleteCandidate(candidate->children[i], true); } else { AddCandidate(candidate->children[i]); @@ -299,19 +280,18 @@ void S2RegionCoverer::GetCoveringInternal(S2Region const& region) { AddCandidate(candidate); } } - VLOG(2) << "Created " << result_->size() << " cells, " << + VLOG(2) << "Created " << result_.size() << " cells, " << candidates_created_counter_ << " candidates created, " << - pq_->size() << " left"; - while (!pq_->empty()) { - DeleteCandidate(pq_->top().second, true); - pq_->pop(); + pq_.size() << " left"; + while (!pq_.empty()) { + DeleteCandidate(pq_.top().second, true); + pq_.pop(); } region_ = NULL; } void S2RegionCoverer::GetCovering(S2Region const& region, vector* covering) { - // Rather than just returning the raw list of cell ids generated by // GetCoveringInternal(), we construct a cell union and then denormalize it. // This has the effect of replacing four child cells with their parent @@ -336,19 +316,101 @@ void S2RegionCoverer::GetCellUnion(S2Region const& region, S2CellUnion* covering) { interior_covering_ = false; GetCoveringInternal(region); - covering->InitSwap(result_.get()); + covering->InitSwap(&result_); } void S2RegionCoverer::GetInteriorCellUnion(S2Region const& region, S2CellUnion* interior) { interior_covering_ = true; GetCoveringInternal(region); - interior->InitSwap(result_.get()); + interior->InitSwap(&result_); +} + +void S2RegionCoverer::GetFastCovering(S2Cap const& cap, + vector* covering) { + GetRawFastCovering(cap, max_cells(), covering); + NormalizeCovering(covering); +} + +void S2RegionCoverer::GetRawFastCovering(S2Cap const& cap, + int max_cells_hint, + vector* covering) { + // TODO(ericv): The covering could be made quite a bit tighter by mapping + // the cap to a rectangle in (i,j)-space and finding a covering for that. + covering->clear(); + + // Find the maximum level such that the cap contains at most one cell vertex + // and such that S2CellId::AppendVertexNeighbors() can be called. + int level = S2::kMinWidth.GetMaxLevel(2 * cap.GetRadius().radians()); + level = min(level, S2CellId::kMaxLevel - 1); + + // Don't bother trying to optimize the level == 0 case, since more than + // four face cells may be required. + if (level == 0) { + covering->reserve(6); + for (int face = 0; face < 6; ++face) { + covering->push_back(S2CellId::FromFace(face)); + } + } else { + // The covering consists of the 4 cells at the given level that share the + // cell vertex that is closest to the cap center. + covering->reserve(4); + S2CellId id = S2CellId::FromPoint(cap.center()); + id.AppendVertexNeighbors(level, covering); + } +} + +void S2RegionCoverer::NormalizeCovering(vector* covering) { + // This method makes no attempt to be optimal. In particular, if + // min_level() > 0 or level_mod() > 1 then it may return more than the + // desired number of cells even when this isn't necessary. + // + // Note that when the covering parameters have their default values, almost + // all of the code in this function is skipped. + + // If any cells are too small, or don't satisfy level_mod(), then replace + // them with ancestors. + if (max_level() < S2CellId::kMaxLevel || level_mod() > 1) { + for (int i = 0; i < covering->size(); ++i) { + S2CellId id = (*covering)[i]; + int level = id.level(); + int new_level = AdjustLevel(min(level, max_level())); + if (new_level != level) { + (*covering)[i] = id.parent(new_level); + } + } + } + // Sort the cells and simplify them. + S2CellUnion::Normalize(covering); + + // If there are still too many cells, then repeatedly replace two adjacent + // cells in S2CellId order by their lowest common ancestor. + while (covering->size() > max_cells()) { + int best_index = -1, best_level = -1; + for (int i = 0; i + 1 < covering->size(); ++i) { + int level = (*covering)[i].GetCommonAncestorLevel((*covering)[i+1]); + level = AdjustLevel(level); + if (level > best_level) { + best_level = level; + best_index = i; + } + } + if (best_level < min_level()) break; + (*covering)[best_index] = (*covering)[best_index].parent(best_level); + S2CellUnion::Normalize(covering); + } + // Make sure that the covering satisfies min_level() and level_mod(), + // possibly at the expense of satisfying max_cells(). + if (min_level() > 0 || level_mod() > 1) { + S2CellUnion result; + result.InitRawSwap(covering); + result.Denormalize(min_level(), level_mod(), covering); + } } void S2RegionCoverer::FloodFill(S2Region const& region, S2CellId start, vector* output) { - hash_set all; + unordered_set all; vector frontier; output->clear(); all.insert(start); @@ -374,4 +436,4 @@ void S2RegionCoverer::GetSimpleCovering( S2Region const& region, S2Point const& start, int level, vector* output) { return FloodFill(region, S2CellId::FromPoint(start).parent(level), output); -} \ No newline at end of file +} diff --git a/src/s2regioncoverer.h b/src/s2regioncoverer.h index d96d471d..18c01dea 100644 --- a/src/s2regioncoverer.h +++ b/src/s2regioncoverer.h @@ -12,17 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2REGIONCOVERER_H_ -#define UTIL_GEOMETRY_S2REGIONCOVERER_H_ +#ifndef S2_GEOMETRY_S2REGIONCOVERER_H_ +#define S2_GEOMETRY_S2REGIONCOVERER_H_ #include #include #include #include "base/macros.h" -#include "base/scoped_ptr.h" +#include "fpcontractoff.h" #include "s2.h" #include "s2cell.h" #include "s2cellid.h" @@ -51,6 +52,10 @@ class S2Region; // and because max_cells() is a limit on how much work is done exploring the // possible covering as well as a limit on the final output size. // +// Because it is an approximation algorithm, one should not rely on the +// stability of the output. In particular, the output of the covering algorithm +// may change across different versions of the library. +// // One can also generate interior coverings, which are sets of cells which // are entirely contained within a region. Interior coverings can be // empty, even for non-empty regions, if there are no cells that satisfy @@ -87,6 +92,11 @@ class S2RegionCoverer { int min_level() const { return min_level_; } int max_level() const { return max_level_; } + // Convenience function that sets both the maximum and minimum cell levels. + // Note that since min_level() takes priority over max_cells(), an arbitrary + // number of cells may be returned even if max_cells() is small. + void set_fixed_level(int level); + // If specified, then only cells where (level - min_level) is a multiple of // "level_mod" will be used (default 1). This effectively allows the // branching factor of the S2CellId hierarchy to be increased. Currently @@ -139,8 +149,25 @@ class S2RegionCoverer { void GetCellUnion(S2Region const& region, S2CellUnion* covering); void GetInteriorCellUnion(S2Region const& region, S2CellUnion* interior); + // Like GetCovering(), except that this method is much faster and the + // coverings are not as tight. All of the usual parameters are respected + // (max_cells, min_level, max_level, and level_mod), except that the + // implementation makes no attempt to take advantage of large values of + // max_cells(). (A small number of cells will always be returned.) + // + // This function is useful as a starting point for algorithms that + // recursively subdivide cells. + void GetFastCovering(S2Cap const& cap, std::vector* covering); + // Given a connected region and a starting point, return a set of cells at // the given level that cover the region. + // + // Note that this method is *not* faster than the regular GetCovering() + // method for most region types, such as S2Cap or S2Polygon, and in fact it + // can be much slower when the output consists of a large number of cells. + // Currently it can be faster at generating coverings of long narrow regions + // such as polylines, but this may change in the future, in which case this + // method will most likely be removed. static void GetSimpleCovering(S2Region const& region, S2Point const& start, int level, std::vector* output); @@ -158,7 +185,7 @@ class S2RegionCoverer { Candidate* NewCandidate(S2Cell const& cell); // Return the log base 2 of the maximum number of children of a candidate. - inline int max_children_shift() const { return 2 * level_mod_; } + int max_children_shift() const { return 2 * level_mod_; } // Free the memory associated with a candidate. static void DeleteCandidate(Candidate* candidate, bool delete_children); @@ -179,6 +206,30 @@ class S2RegionCoverer { // Generates a covering and stores it in result_. void GetCoveringInternal(S2Region const& region); + // If level > min_level(), then reduce "level" if necessary so that it also + // satisfies level_mod(). Levels smaller than min_level() are not affected + // (since cells at these levels are eventually expanded). + int AdjustLevel(int level) const; + + // Ensure that all cells with level > min_level() also satisfy level_mod(), + // by replacing them with an ancestor if necessary. Cell levels smaller + // than min_level() are not modified (see AdjustLevel). The output is + // then normalized to ensure that no redundant cells are present. + void AdjustCellLevels(std::vector* cells) const; + + // Compute a covering of the given cap. In general the covering consists of + // at most 4 cells (except for very large caps, which may need up to 6 + // cells). The output is not sorted. + // + // "max_cells_hint" can be used to request a more accurate covering (but is + // currently ignored). + static void GetRawFastCovering(S2Cap const& cap, int max_cells_hint, + std::vector* covering); + + // Normalize "covering" so that it conforms to the current covering + // parameters (max_cells, min_level, max_level, and level_mod). + void NormalizeCovering(std::vector* covering); + // Given a region and a starting cell, return the set of all the // edge-connected cells at the same level that intersect "region". // The output cells are returned in arbitrary order. @@ -197,17 +248,24 @@ class S2RegionCoverer { // A temporary variable used by GetCovering() that holds the cell ids that // have been added to the covering so far. - scoped_ptr > result_; + std::vector result_; // We keep the candidates in a priority queue. We specify a vector to hold // the queue entries since for some reason priority_queue<> uses a deque by - // default. - struct CompareQueueEntries; + // default. We define our own own comparison function on QueueEntries in + // order to make the results deterministic. (Using the default + // less, entries of equal priority would be sorted according to + // the memory address of the candidate.) typedef std::pair QueueEntry; + struct CompareQueueEntries { + bool operator()(QueueEntry const& x, QueueEntry const& y) const { + return x.first < y.first; + } + }; typedef std::priority_queue, CompareQueueEntries> CandidateQueue; - scoped_ptr pq_; + CandidateQueue pq_; // True if we're computing an interior covering. bool interior_covering_; @@ -218,4 +276,4 @@ class S2RegionCoverer { DISALLOW_COPY_AND_ASSIGN(S2RegionCoverer); }; -#endif // UTIL_GEOMETRY_S2REGIONCOVERER_H_ \ No newline at end of file +#endif // S2_GEOMETRY_S2REGIONCOVERER_H_ diff --git a/src/s2regioncoverer_test.cc b/src/s2regioncoverer_test.cc index 023ef804..1f753ee7 100644 --- a/src/s2regioncoverer_test.cc +++ b/src/s2regioncoverer_test.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2regioncoverer.h" @@ -19,11 +20,9 @@ #include #include #include -#include -using __gnu_cxx::hash; -using __gnu_cxx::hash_map; #include #include +#include #include #include @@ -32,7 +31,7 @@ using __gnu_cxx::hash_map; #include "base/stringprintf.h" #include "base/strtoint.h" #include "strings/split.h" -#include "gtest/gtest.h" +#include #include "s1angle.h" #include "s2cap.h" #include "s2cell.h" @@ -45,6 +44,7 @@ using __gnu_cxx::hash_map; using std::max; using std::min; using std::priority_queue; +using std::unordered_map; using std::vector; DEFINE_string(max_cells, "4,8", @@ -74,7 +74,7 @@ static void CheckCovering(S2RegionCoverer const& coverer, vector const& covering, bool interior) { // Keep track of how many cells have the same coverer.min_level() ancestor. - hash_map min_level_cells; + unordered_map min_level_cells; for (int i = 0; i < covering.size(); ++i) { int level = covering[i].level(); EXPECT_GE(level, coverer.min_level()); @@ -85,7 +85,8 @@ static void CheckCovering(S2RegionCoverer const& coverer, if (covering.size() > coverer.max_cells()) { // If the covering has more than the requested number of cells, then check // that the cell count cannot be reduced by using the parent of some cell. - for (hash_map::const_iterator i = min_level_cells.begin(); + for (unordered_map::const_iterator i = + min_level_cells.begin(); i != min_level_cells.end(); ++i) { EXPECT_EQ(i->second, 1); } @@ -185,22 +186,22 @@ static void TestAccuracy(int max_cells) { double max_ratio[kNumMethods] = {0}; vector ratios[kNumMethods]; int cell_total[kNumMethods] = {0}; - int area_winner_tally[3] = {0}; - int cell_winner_tally[3] = {0}; + int area_winner_tally[kNumMethods] = {0}; + int cell_winner_tally[kNumMethods] = {0}; + static int const kMaxWorstCaps = 10; + priority_queue worst_caps[kNumMethods]; + for (int method = 0; method < kNumMethods; ++method) { min_ratio[method] = 1e20; } - - priority_queue worst_caps; - static int const kMaxWorstCaps = 10; - for (int i = 0; i < FLAGS_iters; ++i) { // Choose the log of the cap area to be uniformly distributed over // the allowable range. Don't try to approximate regions that are so // small they can't use the given maximum number of cells efficiently. double const min_cap_area = S2Cell::AverageArea(S2CellId::kMaxLevel) * max_cells * max_cells; - S2Cap cap = S2Testing::GetRandomCap(min_cap_area, 4 * M_PI); + // Coverings for huge caps are not interesting, so limit the max area too. + S2Cap cap = S2Testing::GetRandomCap(min_cap_area, 0.1 * M_PI); double cap_area = cap.GetArea(); double min_area = 1e30; @@ -228,11 +229,11 @@ static void TestAccuracy(int max_cells) { min_ratio[method] = min(ratio, min_ratio[method]); max_ratio[method] = max(ratio, max_ratio[method]); ratios[method].push_back(ratio); - if (worst_caps.size() < kMaxWorstCaps) { - worst_caps.push(WorstCap(ratio, cap, cells[method])); - } else if (ratio > worst_caps.top().ratio) { - worst_caps.pop(); - worst_caps.push(WorstCap(ratio, cap, cells[method])); + if (worst_caps[method].size() < kMaxWorstCaps) { + worst_caps[method].push(WorstCap(ratio, cap, cells[method])); + } else if (ratio > worst_caps[method].top().ratio) { + worst_caps[method].pop(); + worst_caps[method].push(WorstCap(ratio, cap, cells[method])); } } for (int method = 0; method < kNumMethods; ++method) { @@ -256,9 +257,9 @@ static void TestAccuracy(int max_cells) { printf(" Area winner probability: %.4f\n", area_winner_tally[method] / static_cast(FLAGS_iters)); } - printf(" Caps with worst approximation ratios:\n"); - for (; !worst_caps.empty(); worst_caps.pop()) { - WorstCap const& w = worst_caps.top(); + printf(" Caps with the worst approximation ratios:\n"); + for (; !worst_caps[method].empty(); worst_caps[method].pop()) { + WorstCap const& w = worst_caps[method].top(); S2LatLng ll(w.cap.center()); printf(" Ratio %.4f, Cells %d, " "Center (%.8f, %.8f), Km %.6f\n", @@ -271,7 +272,7 @@ static void TestAccuracy(int max_cells) { TEST(S2RegionCoverer, Accuracy) { vector max_cells = - strings::Split(FLAGS_max_cells, ",", strings::SkipEmpty()); + strings::Split(FLAGS_max_cells, ',', strings::SkipEmpty()); for (int i = 0; i < max_cells.size(); ++i) { TestAccuracy(atoi32(max_cells[i].c_str())); } @@ -286,7 +287,8 @@ TEST(S2RegionCoverer, InteriorCovering) { // the best interior covering should contain 3 children of the initial cell, // that were not effected by removal of a grandchild. const int level = 12; - S2CellId small_cell = S2CellId::FromPoint(S2Testing::RandomPoint()).parent(level + 2); + S2CellId small_cell = + S2CellId::FromPoint(S2Testing::RandomPoint()).parent(level + 2); S2CellId large_cell = small_cell.parent(level); vector small_cell_vector(1, small_cell); vector large_cell_vector(1, large_cell); @@ -306,4 +308,4 @@ TEST(S2RegionCoverer, InteriorCovering) { for (int i = 0; i < 3; ++i) { EXPECT_EQ(interior[i].level(), level + 1); } -} \ No newline at end of file +} diff --git a/src/s2regionintersection.cc b/src/s2regionintersection.cc index 0f77e775..28b6ea77 100644 --- a/src/s2regionintersection.cc +++ b/src/s2regionintersection.cc @@ -13,6 +13,7 @@ // limitations under the License. // + #include "s2regionintersection.h" #include "s2cap.h" @@ -59,8 +60,8 @@ S2RegionIntersection* S2RegionIntersection::Clone() const { } S2Cap S2RegionIntersection::GetCapBound() const { - // TODO: This could be optimized to return a tighter bound, but doesn't - // seem worth it unless profiling shows otherwise. + // TODO(ericv): This could be optimized to return a tighter bound, but + // doesn't seem worth it unless profiling shows otherwise. return GetRectBound().GetCapBound(); } @@ -95,4 +96,4 @@ bool S2RegionIntersection::MayIntersect(S2Cell const& cell) const { if (!region(i)->MayIntersect(cell)) return false; } return true; -} \ No newline at end of file +} diff --git a/src/s2regionintersection.h b/src/s2regionintersection.h index c1ba7e83..b30b314d 100644 --- a/src/s2regionintersection.h +++ b/src/s2regionintersection.h @@ -13,13 +13,15 @@ // limitations under the License. // -#ifndef UTIL_GEOMETRY_S2REGIONINTERSECTION_H__ -#define UTIL_GEOMETRY_S2REGIONINTERSECTION_H__ + +#ifndef S2_GEOMETRY_S2REGIONINTERSECTION_H__ +#define S2_GEOMETRY_S2REGIONINTERSECTION_H__ #include #include #include "base/macros.h" +#include "fpcontractoff.h" #include "s2.h" #include "s2region.h" @@ -40,7 +42,7 @@ class S2RegionIntersection : public S2Region { // Create a region representing the intersection of the given regions. // Takes ownership of all regions and clears the given vector. - S2RegionIntersection(std::vector* regions); + explicit S2RegionIntersection(std::vector* regions); virtual ~S2RegionIntersection(); @@ -53,7 +55,7 @@ class S2RegionIntersection : public S2Region { // Accessor methods. int num_regions() const { return regions_.size(); } - inline S2Region const* region(int i) const { return regions_[i]; } + S2Region const* region(int i) const { return regions_[i]; } //////////////////////////////////////////////////////////////////////// // S2Region interface (see s2region.h for details): @@ -73,11 +75,11 @@ class S2RegionIntersection : public S2Region { private: // Internal constructor used only by Clone() that makes a deep copy of // its argument. - S2RegionIntersection(S2RegionIntersection const* src); + explicit S2RegionIntersection(S2RegionIntersection const* src); std::vector regions_; DISALLOW_COPY_AND_ASSIGN(S2RegionIntersection); }; -#endif // UTIL_GEOMETRY_S2REGIONINTERSECTION_H__ \ No newline at end of file +#endif // S2_GEOMETRY_S2REGIONINTERSECTION_H__ diff --git a/src/s2regionunion.cc b/src/s2regionunion.cc index 5b974625..15595c52 100644 --- a/src/s2regionunion.cc +++ b/src/s2regionunion.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2regionunion.h" @@ -64,8 +65,8 @@ S2RegionUnion* S2RegionUnion::Clone() const { } S2Cap S2RegionUnion::GetCapBound() const { - // TODO: This could be optimized to return a tighter bound, but doesn't - // seem worth it unless profiling shows otherwise. + // TODO(ericv): This could be optimized to return a tighter bound, + // but doesn't seem worth it unless profiling shows otherwise. return GetRectBound().GetCapBound(); } @@ -102,4 +103,4 @@ bool S2RegionUnion::MayIntersect(S2Cell const& cell) const { if (region(i)->MayIntersect(cell)) return true; } return false; -} \ No newline at end of file +} diff --git a/src/s2regionunion.h b/src/s2regionunion.h index 21b345aa..a40b4d53 100644 --- a/src/s2regionunion.h +++ b/src/s2regionunion.h @@ -12,15 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2REGIONUNION_H__ -#define UTIL_GEOMETRY_S2REGIONUNION_H__ +#ifndef S2_GEOMETRY_S2REGIONUNION_H__ +#define S2_GEOMETRY_S2REGIONUNION_H__ #include #include #include "base/macros.h" +#include "fpcontractoff.h" #include "s2.h" #include "s2region.h" @@ -39,7 +41,7 @@ class S2RegionUnion : public S2Region { // Create a region representing the union of the given regions. // Takes ownership of all regions and clears the given vector. - S2RegionUnion(std::vector* regions); + explicit S2RegionUnion(std::vector* regions); virtual ~S2RegionUnion(); @@ -57,7 +59,7 @@ class S2RegionUnion : public S2Region { // Accessor methods. int num_regions() const { return regions_.size(); } - inline S2Region const* region(int i) const { return regions_[i]; } + S2Region const* region(int i) const { return regions_[i]; } //////////////////////////////////////////////////////////////////////// // S2Region interface (see s2region.h for details): @@ -77,11 +79,11 @@ class S2RegionUnion : public S2Region { private: // Internal constructor used only by Clone() that makes a deep copy of // its argument. - S2RegionUnion(S2RegionUnion const* src); + explicit S2RegionUnion(S2RegionUnion const* src); std::vector regions_; DISALLOW_COPY_AND_ASSIGN(S2RegionUnion); }; -#endif // UTIL_GEOMETRY_S2REGIONUNION_H__ \ No newline at end of file +#endif // S2_GEOMETRY_S2REGIONUNION_H__ diff --git a/src/s2regionunion_test.cc b/src/s2regionunion_test.cc index e1ba5384..5a26b516 100644 --- a/src/s2regionunion_test.cc +++ b/src/s2regionunion_test.cc @@ -12,14 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2regionunion.h" +#include #include -#include "base/scoped_ptr.h" -#include "gtest/gtest.h" +#include #include "s2cap.h" #include "s2cell.h" #include "s2cellid.h" @@ -28,6 +29,7 @@ #include "s2pointregion.h" #include "s2regioncoverer.h" +using std::unique_ptr; using std::vector; namespace { @@ -38,7 +40,7 @@ TEST(S2RegionUnionTest, Basic) { EXPECT_EQ(0, ru_empty.num_regions()); EXPECT_EQ(S2Cap::Empty(), ru_empty.GetCapBound()); EXPECT_EQ(S2LatLngRect::Empty(), ru_empty.GetRectBound()); - scoped_ptr empty_clone(ru_empty.Clone()); + unique_ptr empty_clone(ru_empty.Clone()); regions.push_back(new S2PointRegion(S2LatLng::FromDegrees(35, 40) .ToPoint())); @@ -49,7 +51,7 @@ TEST(S2RegionUnionTest, Basic) { S2RegionUnion* two_points_orig = new S2RegionUnion(®ions); EXPECT_TRUE(regions.empty()); - scoped_ptr two_points(two_points_orig->Clone()); + unique_ptr two_points(two_points_orig->Clone()); delete two_points_orig; EXPECT_EQ(S2LatLngRect(S2LatLng::FromDegrees(-35, -40), S2LatLng::FromDegrees(35, 40)), @@ -64,7 +66,7 @@ TEST(S2RegionUnionTest, Basic) { EXPECT_FALSE(two_points->Contains(S2LatLng::FromDegrees(0, 0).ToPoint())); // Check that we can Add() another region. - scoped_ptr three_points(two_points->Clone()); + unique_ptr three_points(two_points->Clone()); EXPECT_FALSE(three_points->Contains(S2LatLng::FromDegrees(10, 10).ToPoint())); three_points->Add(new S2PointRegion(S2LatLng::FromDegrees(10, 10) .ToPoint())); @@ -78,4 +80,4 @@ TEST(S2RegionUnionTest, Basic) { EXPECT_EQ(face0.id(), covering[0]); } -} // namespace \ No newline at end of file +} // namespace diff --git a/src/s2shapeindex.cc b/src/s2shapeindex.cc index d6ac8001..2afadb2f 100644 --- a/src/s2shapeindex.cc +++ b/src/s2shapeindex.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2shapeindex.h" @@ -137,7 +138,7 @@ S2ShapeIndexCell::find_clipped(int shape_id) const { // Allocate room for "n" additional clipped shapes in the cell, and return a // pointer to the first new clipped shape. Expects that all new clipped // shapes will have a larger shape id than any current shape, and that shapes -// will be inserted in increasing shape id order. +// will be added in increasing shape id order. S2ClippedShape* S2ShapeIndexCell::add_shapes(int n) { int size = shapes_.size(); shapes_.resize(size + n); @@ -193,14 +194,14 @@ S2ShapeIndex::CellRelation S2ShapeIndex::Iterator::Locate(S2CellId target) { } S2ShapeIndex::S2ShapeIndex() - : pending_insertions_begin_(0), + : pending_additions_begin_(0), index_status_(FRESH), update_state_(NULL) { } S2ShapeIndex::S2ShapeIndex(S2ShapeIndexOptions const& options) : options_(options), - pending_insertions_begin_(0), + pending_additions_begin_(0), index_status_(FRESH), update_state_(NULL) { } @@ -214,8 +215,8 @@ S2ShapeIndex::~S2ShapeIndex() { Reset(); } -void S2ShapeIndex::Insert(S2Shape const* shape) { - // Insertions are processed lazily by ApplyUpdates(). +void S2ShapeIndex::Add(S2Shape const* shape) { + // Additions are processed lazily by ApplyUpdates(). shape->id_ = shapes_.size(); shapes_.push_back(shape); base::subtle::NoBarrier_Store(&index_status_, STALE); @@ -239,7 +240,7 @@ void S2ShapeIndex::Reset() { // Note that vector::clear() does not actually free storage. vector empty_shapes; shapes_.swap(empty_shapes); - pending_insertions_begin_ = 0; + pending_additions_begin_ = 0; pending_removals_.reset(); DCHECK(update_state_ == NULL); base::subtle::NoBarrier_Store(&index_status_, FRESH); @@ -487,7 +488,7 @@ void S2ShapeIndex::ForceApplyUpdates() { } } -// This method updates the index by applying all pending insertions and +// This method updates the index by applying all pending additions and // removals. It does *not* update index_status_ (see ApplyUpdatesThreadSafe). void S2ShapeIndex::ApplyUpdatesInternal() { CHECK(cell_map_.empty()) << "Incremental updates not supported yet"; @@ -495,7 +496,7 @@ void S2ShapeIndex::ApplyUpdatesInternal() { ReserveSpace(all_edges); InteriorTracker tracker; - for (int id = pending_insertions_begin_; id < shapes_.size(); ++id) { + for (int id = pending_additions_begin_; id < shapes_.size(); ++id) { AddShapeEdges(id, all_edges, &tracker); } // Whether to insert or remove a given shape is represented implicitly: @@ -507,7 +508,7 @@ void S2ShapeIndex::ApplyUpdatesInternal() { vector empty; all_edges[face].swap(empty); } - pending_insertions_begin_ = shapes_.size(); + pending_additions_begin_ = shapes_.size(); // It is the caller's responsibility to update index_status_. } @@ -521,7 +522,7 @@ void S2ShapeIndex::ReserveSpace(vector all_edges[6]) const { // to simply reserve space on every face for the maximum possible number of // edges. int num_edges = 0; - for (int id = pending_insertions_begin_; id < shapes_.size(); ++id) { + for (int id = pending_additions_begin_; id < shapes_.size(); ++id) { num_edges += shapes_[id]->num_edges(); } int const kMaxCheapMemoryBytes = 10 << 20; // 10MB @@ -551,7 +552,7 @@ void S2ShapeIndex::ReserveSpace(vector all_edges[6]) const { int edge_id = sample_interval / 2; int const actual_sample_size = (num_edges + edge_id) / sample_interval; int face_count[6] = { 0, 0, 0, 0, 0, 0 }; - for (int id = pending_insertions_begin_; id < shapes_.size(); ++id) { + for (int id = pending_additions_begin_; id < shapes_.size(); ++id) { S2Shape const* shape = shapes_[id]; edge_id += shape->num_edges(); while (edge_id >= sample_interval) { @@ -675,8 +676,8 @@ class S2ShapeIndex::EdgeAllocator { DISALLOW_COPY_AND_ASSIGN(EdgeAllocator); }; -// Given a face and a vector of edges that intersect that face, insert or -// remove all the edges from the index. (An edge is inserted if shape(id) is +// Given a face and a vector of edges that intersect that face, add or +// remove all the edges from the index. (An edge is added if shape(id) is // not NULL, and removed otherwise.) void S2ShapeIndex::UpdateFaceEdges(int face, vector const& face_edges, @@ -714,7 +715,7 @@ void S2ShapeIndex::UpdateFaceEdges(int face, } // Given a cell and a set of ClippedEdges whose bounding boxes intersect that -// cell, insert or remove all the edges from the index. Temporary space for +// cell, add or remove all the edges from the index. Temporary space for // edges that need to be subdivided is allocated from the given EdgeAllocator. void S2ShapeIndex::UpdateEdges(S2PaddedCell const& pcell, vector const& edges, @@ -793,8 +794,8 @@ void S2ShapeIndex::UpdateEdges(S2PaddedCell const& pcell, } // Given an edge and an interval "middle" along the v-axis, clip the edge -// against the boundaries of "middle" and insert the edge into the -// corresponding children. +// against the boundaries of "middle" and add the edge to the corresponding +// children. inline void S2ShapeIndex::ClipVAxis(ClippedEdge const* edge, R1Interval const& middle, vector child_edges[2], @@ -1002,3 +1003,4 @@ int S2ShapeIndex::CountShapes(vector const& edges, count += (cshape_ids.end() - cnext); return count; } + diff --git a/src/s2shapeindex.h b/src/s2shapeindex.h index 6a75ffb0..2dd778f3 100644 --- a/src/s2shapeindex.h +++ b/src/s2shapeindex.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) // // S2ShapeIndex indexes a set of "shapes", where a shape is a collection of @@ -20,7 +21,7 @@ // interiors, the index makes it very fast to determine the shape(s) that // contain a given point or region. // -// The index is dynamic; shapes can be inserted or removed (although each +// The index is dynamic; shapes can be added or removed (although each // individual shape is immutable). It is designed to handle up to millions of // shapes and edges. All data structures are designed to be small, so the // index is compact; generally it is smaller than the underlying data being @@ -29,10 +30,11 @@ // All "const" methods are thread-safe provided that they do not overlap with // calls to non-const methods. Non-const methods are not thread-safe. -#ifndef UTIL_GEOMETRY_S2SHAPEINDEX_H_ -#define UTIL_GEOMETRY_S2SHAPEINDEX_H_ +#ifndef S2_GEOMETRY_S2SHAPEINDEX_H_ +#define S2_GEOMETRY_S2SHAPEINDEX_H_ #include +#include #include #include @@ -41,13 +43,12 @@ #include #include "base/macros.h" #include "base/mutex.h" -#include "base/scoped_ptr.h" #include "base/spinlock.h" +#include +#include "fpcontractoff.h" #include "s2.h" #include "s2cellid.h" -#include - class R1Interval; class S2PaddedCell; class S2ShapeIndex; @@ -55,9 +56,9 @@ class S2ShapeIndex; // S2Shape is an abstract base class that defines a shape. Typically it // wraps some other geometric object in order to provide access to its edges // without duplicating the edge data. Shapes are immutable once they have -// been indexed; to modify a shape it must be removed and then reinserted. -// A shape can be removed from one S2ShapeIndex and then inserted into -// another, but it can belong to only one index at a time. +// been indexed; to modify a shape it must be removed and then added again. +// A shape can be removed from one S2ShapeIndex and then added to another, +// but it can belong to only one index at a time. class S2Shape { public: S2Shape() : id_(-1) {} @@ -86,13 +87,13 @@ class S2Shape { virtual void Release() const = 0; // A unique id assigned to this shape by S2ShapeIndex. Shape ids are - // assigned sequentially starting from 0 in the order shapes are inserted. + // assigned sequentially starting from 0 in the order shapes are added. int id() const { return id_; } private: friend class S2ShapeIndex; // id_ assignment - // id_ is mutable so that "const" geometry can be inserted in the index. + // id_ is mutable so that "const" geometry can be added to the index. mutable int id_; DISALLOW_COPY_AND_ASSIGN(S2Shape); @@ -220,7 +221,7 @@ class S2ShapeIndex { S2ShapeIndex(); // Create an S2ShapeIndex with the given options. - S2ShapeIndex(S2ShapeIndexOptions const& options); + explicit S2ShapeIndex(S2ShapeIndexOptions const& options); ~S2ShapeIndex(); @@ -240,15 +241,16 @@ class S2ShapeIndex { // been removed from the index. S2Shape const* shape(int id) const { return shapes_[id]; } - // Insert the given shape in the index, and also assign a unique id to the + // Add the given shape to the index, and also assign a unique id to the // shape (shape->id()). Shape ids are assigned sequentially starting from 0 - // in the order shapes are inserted. Invalidates all iterators and their + // in the order shapes are added. Invalidates all iterators and their // associated data. Does *not* take ownership of "shape". // // REQUIRES: "shape" is not currently in any other S2ShapeIndex. // REQUIRES: "shape" persists for the lifetime of the index or until // Remove(shape) is called. - void Insert(S2Shape const* shape); + void Add(S2Shape const* shape); + void Insert(S2Shape const* shape); // DEPRECATED // Remove the given shape from the index. Does not free storage for the // shape itself, which is owned by the caller. Invalidates all iterators @@ -360,7 +362,7 @@ class S2ShapeIndex { }; - // Calls to Insert() and Remove() are normally queued and processed on the + // Calls to Add() and Remove() are normally queued and processed on the // first subsequent query (in a thread-safe way). This has many advantages, // the most important of which is that sometimes there *is* no subsequent // query, which lets us avoid building the index completely. @@ -444,9 +446,9 @@ class S2ShapeIndex { // The options supplied for this index. S2ShapeIndexOptions options_; - // The id of the first shape that has been queued for insertion but not + // The id of the first shape that has been queued for addition but not // processed yet. - int pending_insertions_begin_; + int pending_additions_begin_; // The representation of an edge that has been queued for removal. struct PendingRemoval { int32 shape_id; S2Point a, b; }; @@ -455,9 +457,9 @@ class S2ShapeIndex { // processed yet. Note that we need to copy the edge data since the caller // is free to destroy the shape once Remove() has been called. This field // is present only when there are removals pending (to save memory). - scoped_ptr > pending_removals_; + std::unique_ptr > pending_removals_; - // Insertions and removals are queued and processed on the first subsequent + // Additions and removals are queued and processed on the first subsequent // query. There are several reasons to do this: // // - It is significantly more efficient to process updates in batches. @@ -595,6 +597,10 @@ inline bool S2ShapeIndex::is_fresh() const { return base::subtle::NoBarrier_Load(&index_status_) == FRESH; } +inline void S2ShapeIndex::Insert(S2Shape const* shape) { + Add(shape); +} + // Ensure that any pending updates have been applied. This method must be // called before accessing the cell_map_ field, even if the index_status_ // appears to be FRESH, because a memory barrier is required in order to @@ -610,4 +616,4 @@ inline void S2ShapeIndex::MaybeApplyUpdates() const { } } -#endif // UTIL_GEOMETRY_S2SHAPEINDEX_H_ \ No newline at end of file +#endif // S2_GEOMETRY_S2SHAPEINDEX_H_ diff --git a/src/s2shapeindex_test.cc b/src/s2shapeindex_test.cc index f685417a..eb9c9c76 100644 --- a/src/s2shapeindex_test.cc +++ b/src/s2shapeindex_test.cc @@ -12,18 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2shapeindex.h" #include +#include #include #include #include #include "base/mutex.h" -#include "base/scoped_ptr.h" -#include "gtest/gtest.h" +#include #include "r2.h" #include "r2rect.h" #include "s1angle.h" @@ -36,7 +37,10 @@ #include "s2polygon.h" #include "s2shapeutil.h" #include "s2testing.h" +#include "s2textformat.h" +using s2shapeutil::S2EdgeVectorShape; +using std::unique_ptr; using std::vector; @@ -163,9 +167,7 @@ void TestIteratorMethods(S2ShapeIndex const& index) { for (it.Reset(); !it.Done(); it.Next()) { S2CellId cellid = it.id(); S2CellUnion skipped; - if (cellid.range_min() > min_cellid) { // XXX Interface? - skipped.InitFromRange(min_cellid, cellid.range_min().prev()); - } + skipped.InitFromBeginEnd(min_cellid, cellid.range_min()); S2ShapeIndex::Iterator it2(index); for (int i = 0; i < skipped.num_cells(); ++i) { EXPECT_FALSE(it2.Locate(skipped.cell_id(i).ToPoint())); @@ -219,7 +221,7 @@ TEST_F(S2ShapeIndexTest, NoEdges) { } TEST_F(S2ShapeIndexTest, OneEdge) { - index_.Insert(new S2EdgeVectorShape(S2Point(1, 0, 0), S2Point(0, 1, 0))); + index_.Add(new S2EdgeVectorShape(S2Point(1, 0, 0), S2Point(0, 1, 0))); QuadraticValidate(); TestIteratorMethods(index_); } @@ -234,7 +236,7 @@ TEST_F(S2ShapeIndexTest, LoopsSpanningThreeFaces) { vector loops; polygon.Release(&loops); for (int i = 0; i < loops.size(); ++i) { - index_.Insert(new S2Loop::Shape(loops[i])); + index_.Add(new S2Loop::Shape(loops[i])); } QuadraticValidate(); TestIteratorMethods(index_); @@ -247,11 +249,11 @@ TEST_F(S2ShapeIndexTest, ManyIdenticalEdges) { S2Point a = S2Point(0.99, 0.99, 1).Normalize(); S2Point b = S2Point(-0.99, -0.99, 1).Normalize(); for (int i = 0; i < kNumEdges; ++i) { - index_.Insert(new S2EdgeVectorShape(a, b)); + index_.Add(new S2EdgeVectorShape(a, b)); } QuadraticValidate(); TestIteratorMethods(index_); - // Since all edges span the the diagonal of a face, no subdivision should + // Since all edges span the diagonal of a face, no subdivision should // have occurred (with the default index options). for (S2ShapeIndex::Iterator it(index_); !it.Done(); it.Next()) { EXPECT_EQ(0, it.id().level()); @@ -259,7 +261,7 @@ TEST_F(S2ShapeIndexTest, ManyIdenticalEdges) { } TEST_F(S2ShapeIndexTest, ManyTinyEdges) { - // This test inserts many edges into a single leaf cell, to check that + // This test adds many edges to a single leaf cell, to check that // subdivision stops when no further subdivision is possible. int const kNumEdges = 100; // Validation is quadratic // Construct two points in the same leaf cell. @@ -269,7 +271,7 @@ TEST_F(S2ShapeIndexTest, ManyTinyEdges) { for (int i = 0; i < kNumEdges; ++i) { shape->Add(a, b); } - index_.Insert(shape); + index_.Add(shape); QuadraticValidate(); // Check that there is exactly one index cell and that it is a leaf cell. S2ShapeIndex::Iterator it(index_); @@ -283,7 +285,7 @@ TEST_F(S2ShapeIndexTest, ManyTinyEdges) { // Add the loops to the given index. void AddLoops(vector const& loops, S2ShapeIndex* index) { for (int i = 0; i < loops.size(); ++i) { - index->Insert(new S2Loop::Shape(loops[i])); + index->Add(new S2Loop::Shape(loops[i])); } } @@ -316,7 +318,7 @@ void TestHasCrossingPermutations(vector* loops, int i, for (int k = 0; k < orig_loop->num_vertices(); ++k) { vertices.push_back(orig_loop->vertex(j + k)); } - scoped_ptr new_loop(new S2Loop(vertices)); + unique_ptr new_loop(new S2Loop(vertices)); (*loops)[i] = new_loop.get(); TestHasCrossingPermutations(loops, i+1, has_crossing); } @@ -330,7 +332,7 @@ void TestHasCrossingPermutations(vector* loops, int i, // permutations of the loop vertices. void TestHasCrossing(const string& polygon_str, bool has_crossing) { FLAGS_s2debug = false; // Allow invalid polygons (restored by gUnit) - scoped_ptr polygon(S2Testing::MakePolygon(polygon_str)); + unique_ptr polygon(s2textformat::MakePolygon(polygon_str)); vector loops; polygon->Release(&loops); TestHasCrossingPermutations(&loops, 0, has_crossing); @@ -376,26 +378,25 @@ class LazyUpdatesTest : public ::testing::Test { }; void LazyUpdatesTest::ReaderThread() { + lock_.Lock(); for (int last_update = 0; ; last_update = num_updates_) { - lock_.Lock(); while (num_updates_ == last_update) { update_ready_.Wait(&lock_); } + if (num_updates_ < 0) break; + + // The index is built on demand the first time we attempt to use it. // We intentionally release the lock so that many threads have a chance // to access the S2ShapeIndex in parallel. - bool should_exit = (num_updates_ < 0); lock_.Unlock(); - if (should_exit) break; - - // The index is built on demand the first time we attempt to use it. for (S2ShapeIndex::Iterator it(index_); !it.Done(); it.Next()) - ; + continue; lock_.Lock(); if (--num_readers_left_ == 0) { all_readers_done_.Signal(); } - lock_.Unlock(); } + lock_.Unlock(); } static void* StartReader(void* arg) { @@ -424,9 +425,9 @@ TEST_F(LazyUpdatesTest, ConstMethodsThreadSafe) { // Since there are no readers, it is safe to modify the index. index_.Reset(); int num_vertices = 4 * S2Testing::rnd.Skewed(10); // Up to 4K vertices - scoped_ptr loop(S2Testing::MakeRegularLoop( + unique_ptr loop(S2Testing::MakeRegularLoop( S2Testing::RandomPoint(), S2Testing::KmToAngle(5), num_vertices)); - index_.Insert(new S2Loop::Shape(loop.get())); + index_.Add(new S2Loop::Shape(loop.get())); num_readers_left_ = kNumReaders; ++num_updates_; update_ready_.SignalAll(); @@ -444,4 +445,4 @@ TEST_F(LazyUpdatesTest, ConstMethodsThreadSafe) { } -} // namespace \ No newline at end of file +} // namespace diff --git a/src/s2shapeutil.cc b/src/s2shapeutil.cc index 8cfa290c..6d974099 100644 --- a/src/s2shapeutil.cc +++ b/src/s2shapeutil.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2shapeutil.h" @@ -197,4 +198,4 @@ bool FindAnyCrossing(S2ShapeIndex const& index, vector const& loops, return false; } -} // namespace s2shapeutil \ No newline at end of file +} // namespace s2shapeutil diff --git a/src/s2shapeutil.h b/src/s2shapeutil.h index 5bee4054..02334ddd 100644 --- a/src/s2shapeutil.h +++ b/src/s2shapeutil.h @@ -12,22 +12,26 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) // // Useful functions and classes related to S2ShapeIndex. -#ifndef UTIL_GEOMETRY_S2SHAPEUTIL_H_ -#define UTIL_GEOMETRY_S2SHAPEUTIL_H_ +#ifndef S2_GEOMETRY_S2SHAPEUTIL_H_ +#define S2_GEOMETRY_S2SHAPEUTIL_H_ #include // pair<> #include +#include "fpcontractoff.h" #include "s2.h" #include "s2shapeindex.h" class S2Loop; class S2Error; +namespace s2shapeutil { + // S2EdgeVectorShape is an S2Shape representing a set of unrelated edges. // It is mainly used for testing, but it can also be useful if you have, say, // a collection of polylines and don't care about memory efficiency (since @@ -40,8 +44,6 @@ class S2Error; // Note that when an S2EdgeVectorShape is inserted into an S2ShapeIndex, the // index takes ownership. The object will be deleted automatically when the // index no longer needs it (see Release().) -// -// TODO(ericv): Move this into the s2shapeutil namespace. class S2EdgeVectorShape : public S2Shape { public: S2EdgeVectorShape() {} @@ -65,7 +67,6 @@ class S2EdgeVectorShape : public S2Shape { std::vector > edges_; }; -namespace s2shapeutil { // Given an S2ShapeIndex containing a single loop, return true if the loop has // a self-intersection (including duplicate vertices) and set "error" to a @@ -85,4 +86,4 @@ bool FindAnyCrossing(S2ShapeIndex const& index, } // namespace s2shapeutil -#endif // UTIL_GEOMETRY_S2SHAPEUTIL_H_ \ No newline at end of file +#endif // S2_GEOMETRY_S2SHAPEUTIL_H_ diff --git a/src/s2shapeutil_test.cc b/src/s2shapeutil_test.cc index 33288c87..361daa19 100644 --- a/src/s2shapeutil_test.cc +++ b/src/s2shapeutil_test.cc @@ -12,15 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2shapeutil.h" -#include "gtest/gtest.h" +#include #include "s2testing.h" namespace { +using s2shapeutil::S2EdgeVectorShape; + TEST(S2EdgeVectorShape, EdgeAccess) { S2EdgeVectorShape shape; S2Testing::rnd.Reset(FLAGS_s2_random_seed); @@ -54,4 +57,4 @@ TEST(S2EdgeVectorShape, Ownership) { shape->Release(); // Verify there is no memory leak. } -} // namespace \ No newline at end of file +} // namespace diff --git a/src/s2testing.cc b/src/s2testing.cc index ecb788ef..35b96ed5 100644 --- a/src/s2testing.cc +++ b/src/s2testing.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2testing.h" @@ -22,13 +23,13 @@ #include // for rusage, RUSAGE_SELF #include #include +#include #include #include #include #include "base/integral_types.h" #include -#include "base/scoped_ptr.h" #include "base/stringprintf.h" #include "strings/serialize.h" #include "strings/split.h" @@ -44,10 +45,13 @@ #include "s2polygon.h" #include "s2polyline.h" #include "s2region.h" +#include "s2textformat.h" +#include "util/gtl/stl_util.h" #include "util/math/matrix3x3.h" using std::max; using std::pair; +using std::unique_ptr; using std::vector; DEFINE_int32(s2_random_seed, 1, "Initial random seed for S2Testing::rnd"); @@ -67,8 +71,20 @@ void S2Testing::Random::Reset(int seed) { inline uint64 GetBits(int num_bits) { DCHECK_GE(num_bits, 0); DCHECK_LE(num_bits, 64); + + // This code uses random(), which returns an integer in the range + // from 0 to (2^31)-1 inclusive (i.e. all of the lower 31 bits are + // in play, and the 32nd bit and higher are 0) regardless of whether + // its return type (long) is larger than 32 bits. See + // + // www.gnu.org/software/libc/manual/html_node/BSD-Random.html#BSD-Random + // + // Note that at some point the manual page in linux claimed that the range + // is 0 to RAND_MAX as defined in stdlib.h. RAND_MAX however is part only + // of the ISO rand() interface. At least as of glibc-2.21, rand() is + // simply an alias for random(). On other systems, rand() may differ, + // but random() should always adhere to the behavior specified in BSD. static int const RAND_BITS = 31; - COMPILE_ASSERT(RAND_MAX == (1U << RAND_BITS) - 1, non_standard_random); uint64 result = 0; for (int bits = 0; bits < num_bits; bits += RAND_BITS) { @@ -114,84 +130,6 @@ int32 S2Testing::Random::Skewed(int max_log) { S2Testing::Random S2Testing::rnd; -static double ParseDouble(const string& str) { - char* end_ptr = NULL; - double value = strtod(str.c_str(), &end_ptr); - CHECK(end_ptr && *end_ptr == 0) << ": str == \"" << str << "\""; - return value; -} - -void S2Testing::ParseLatLngs(string const& str, vector* latlngs) { - vector > p; - CHECK(DictionaryParse(str, &p)) << ": str == \"" << str << "\""; - latlngs->clear(); - for (int i = 0; i < p.size(); ++i) { - latlngs->push_back(S2LatLng::FromDegrees(ParseDouble(p[i].first), - ParseDouble(p[i].second))); - } -} - -void S2Testing::ParsePoints(string const& str, vector* vertices) { - vector latlngs; - S2Testing::ParseLatLngs(str, &latlngs); - vertices->clear(); - for (int i = 0; i < latlngs.size(); ++i) { - vertices->push_back(latlngs[i].ToPoint()); - } -} - -S2Point S2Testing::MakePoint(string const& str) { - vector vertices; - ParsePoints(str, &vertices); - CHECK_EQ(vertices.size(), 1); - return vertices[0]; -} - -S2LatLngRect S2Testing::MakeLatLngRect(string const& str) { - vector latlngs; - ParseLatLngs(str, &latlngs); - CHECK_GT(latlngs.size(), 0); - S2LatLngRect rect = S2LatLngRect::FromPoint(latlngs[0]); - for (int i = 1; i < latlngs.size(); ++i) { - rect.AddPoint(latlngs[i]); - } - return rect; -} - -S2Loop* S2Testing::MakeLoop(string const& str) { - if (str == "empty") return new S2Loop(S2Loop::kEmpty()); - if (str == "full") return new S2Loop(S2Loop::kFull()); - vector vertices; - ParsePoints(str, &vertices); - return new S2Loop(vertices); -} - -S2Polyline* S2Testing::MakePolyline(string const& str) { - vector vertices; - ParsePoints(str, &vertices); - return new S2Polyline(vertices); -} - -static S2Polygon* InternalMakePolygon(string const& str, - bool normalize_loops) { - vector loop_strs = strings::Split(str, ";", strings::SkipEmpty()); - vector loops; - for (int i = 0; i < loop_strs.size(); ++i) { - S2Loop* loop = S2Testing::MakeLoop(loop_strs[i]); - if (normalize_loops) loop->Normalize(); - loops.push_back(loop); - } - return new S2Polygon(&loops); // Takes ownership. -} - -S2Polygon* S2Testing::MakePolygon(string const& str) { - return InternalMakePolygon(str, true); -} - -S2Polygon* S2Testing::MakeVerbatimPolygon(string const& str) { - return InternalMakePolygon(str, false); -} - void S2Testing::AppendLoopVertices(S2Loop const& loop, vector* vertices) { int n = loop.num_vertices(); @@ -203,7 +141,7 @@ void S2Testing::AppendLoopVertices(S2Loop const& loop, vector S2Testing::MakeRegularPoints(S2Point const& center, S1Angle radius, int num_vertices) { - scoped_ptr loop(MakeRegularLoop(center, radius, num_vertices)); + unique_ptr loop(MakeRegularLoop(center, radius, num_vertices)); vector points; for (int i = 0; i < loop.get()->num_vertices(); i++) { points.push_back(loop.get()->vertex(i)); @@ -235,69 +173,6 @@ S2Loop* S2Testing::MakeRegularLoop(Matrix3x3_d const& frame, return new S2Loop(vertices); } -static void AppendVertex(S2Point const& p, string* out) { - S2LatLng ll(p); - StringAppendF(out, "%.17g:%.17g", ll.lat().degrees(), ll.lng().degrees()); -} - -static void AppendVertices(S2Point const* v, int n, string* out) { - for (int i = 0; i < n; ++i) { - if (i > 0) *out += ", "; - AppendVertex(v[i], out); - } -} - -string S2Testing::ToString(S2Point const& point) { - string out; - AppendVertex(point, &out); - return out; -} - -string S2Testing::ToString(S2LatLngRect const& rect) { - string out; - AppendVertex(rect.lo().ToPoint(), &out); - out += ", "; - AppendVertex(rect.hi().ToPoint(), &out); - return out; -} - -string S2Testing::ToString(S2Loop const* loop) { - string out; - AppendVertices(&loop->vertex(0), loop->num_vertices(), &out); - return out; -} - -string S2Testing::ToString(S2Polyline const* polyline) { - string out; - AppendVertices(&polyline->vertex(0), polyline->num_vertices(), &out); - return out; -} - -string S2Testing::ToString(S2Polygon const* polygon) { - string out; - for (int i = 0; i < polygon->num_loops(); ++i) { - if (i > 0) out += ";\n"; - S2Loop const* loop = polygon->loop(i); - AppendVertices(&loop->vertex(0), loop->num_vertices(), &out); - } - return out; -} - -string S2Testing::ToString(vector const& points) { - string out; - AppendVertices(&points[0], points.size(), &out); - return out; -} - -string S2Testing::ToString(vector const& latlngs) { - string out; - for (int i = 0; i < latlngs.size(); ++i) { - if (i > 0) out += ", "; - AppendVertex(latlngs[i].ToPoint(), &out); - } - return out; -} - S1Angle S2Testing::KmToAngle(double km) { return S1Angle::Radians(km / kEarthRadiusKm); } @@ -308,17 +183,17 @@ S1Angle S2Testing::MetersToAngle(double meters) { void DumpLoop(S2Loop const* loop) { // Only for calling from a debugger. - std::cout << S2Testing::ToString(loop) << "\n"; + std::cout << s2textformat::ToString(loop) << "\n"; } void DumpPolyline(S2Polyline const* polyline) { // Only for calling from a debugger. - std::cout << S2Testing::ToString(polyline) << "\n"; + std::cout << s2textformat::ToString(polyline) << "\n"; } void DumpPolygon(S2Polygon const* polygon) { // Only for calling from a debugger. - std::cout << S2Testing::ToString(polygon) << "\n"; + std::cout << s2textformat::ToString(polygon) << "\n"; } S2Point S2Testing::RandomPoint() { @@ -458,10 +333,8 @@ double S2Testing::GetCpuTime() { } void S2Testing::DeleteLoops(vector* loops) { - for (int i = 0; i < loops->size(); ++i) { - delete (*loops)[i]; - } - loops->clear(); + // TODO(user): Update all callers and delete this function. + STLDeleteElements(loops); } @@ -486,7 +359,7 @@ void S2Testing::Fractal::set_min_level(int min_level_arg) { void S2Testing::Fractal::ComputeMinLevel() { if (min_level_arg_ >= 0 && min_level_arg_ <= max_level_) { - min_level_= min_level_arg_; + min_level_ = min_level_arg_; } else { min_level_ = max_level_; } @@ -595,4 +468,4 @@ S2Loop* S2Testing::Fractal::MakeLoop(Matrix3x3_d const& frame, vertices.push_back(S2::FromFrame(frame, p).Normalize()); } return new S2Loop(vertices); -} \ No newline at end of file +} diff --git a/src/s2testing.h b/src/s2testing.h index 07c373df..a7a87e82 100644 --- a/src/s2testing.h +++ b/src/s2testing.h @@ -12,10 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) -#ifndef UTIL_GEOMETRY_S2TESTING_H__ -#define UTIL_GEOMETRY_S2TESTING_H__ +#ifndef S2_GEOMETRY_S2TESTING_H__ +#define S2_GEOMETRY_S2TESTING_H__ #include #include @@ -23,6 +24,7 @@ #include #include "base/integral_types.h" #include "base/macros.h" +#include "fpcontractoff.h" #include "r2.h" #include "s1angle.h" #include "s2.h" @@ -49,46 +51,6 @@ DECLARE_int32(s2_random_seed); // unit tests. class S2Testing { public: - // Given a latitude-longitude coordinate in degrees, - // return a newly allocated point. Example of the input format: - // "-20:150" - static S2Point MakePoint(string const& str); - - // Given a string of one or more latitude-longitude coordinates in degrees, - // return the minimal bounding S2LatLngRect that contains the coordinates. - // Example of the input format: - // "-20:150" // one point - // "-20:150, -20:151, -19:150" // three points - static S2LatLngRect MakeLatLngRect(string const& str); - - // Given a string of latitude-longitude coordinates in degrees, - // return a newly allocated loop. Example of the input format: - // "-20:150, 10:-120, 0.123:-170.652" - // The strings "empty" or "full" create an empty or full loop respectively. - static S2Loop* MakeLoop(string const& str); - - // Similar to MakeLoop(), but returns an S2Polyline rather than an S2Loop. - static S2Polyline* MakePolyline(string const& str); - - // Given a sequence of loops separated by semicolons, return a newly - // allocated polygon. Loops are automatically normalized by inverting them - // if necessary so that they enclose at most half of the unit sphere. - // (Historically this was once a requirement of polygon loops. It also - // hides the problem that if the user thinks of the coordinates as X:Y - // rather than LAT:LNG, it yields a loop with the opposite orientation.) - // - // Examples of the input format: - // "10:20, 90:0, 20:30" // one loop - // "10:20, 90:0, 20:30; 5.5:6.5, -90:-180, -15.2:20.3" // two loops - // "" // the empty polygon (consisting of no loops) - // "full" // the full polygon (consisting of one full loop) - // "empty" // **INVALID** (a polygon consisting of one empty loop) - static S2Polygon* MakePolygon(string const& str); - - // Like MakePolygon(), except that it does not normalize loops (i.e., it - // gives you exactly what you asked for). - static S2Polygon* MakeVerbatimPolygon(string const& str); - // Returns a vector of points shaped as a regular polygon with // num_vertices vertices, all on a circle of the specified angular // radius around the center. The radius is the actual distance from @@ -199,24 +161,6 @@ class S2Testing { DISALLOW_COPY_AND_ASSIGN(Fractal); }; - // Parse a string in the same format as MakeLatLngRect, and return the - // corresponding vector of S2LatLng points. - static void ParseLatLngs(string const& str, std::vector* latlngs); - - // Parse a string in the same format as MakeLatLngRect, and return the - // corresponding vector of S2Point values. - static void ParsePoints(string const& str, std::vector* vertices); - - // Convert a point, lat-lng rect, loop, polyline, or polygon to the string - // format above. - static string ToString(S2Point const& point); - static string ToString(S2LatLngRect const& rect); - static string ToString(S2Loop const* loop); - static string ToString(S2Polyline const* polyline); - static string ToString(S2Polygon const* polygon); - static string ToString(std::vector const& points); - static string ToString(std::vector const& points); - // Convert a distance on the Earth's surface to an angle. static S1Angle KmToAngle(double km); static S1Angle MetersToAngle(double meters); @@ -334,4 +278,4 @@ class S2Testing::Random { DISALLOW_COPY_AND_ASSIGN(Random); }; -#endif // UTIL_GEOMETRY_S2TESTING_H__ \ No newline at end of file +#endif // S2_GEOMETRY_S2TESTING_H__ diff --git a/src/s2testing_test.cc b/src/s2testing_test.cc index 2b523965..4ac62315 100644 --- a/src/s2testing_test.cc +++ b/src/s2testing_test.cc @@ -12,21 +12,23 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "s2testing.h" #include #include +#include #include -#include "base/scoped_ptr.h" -#include "gtest/gtest.h" +#include #include "s1angle.h" #include "s2loop.h" using std::max; using std::min; +using std::unique_ptr; namespace { @@ -52,7 +54,7 @@ void TestFractal(int min_level, int max_level, double dimension) { fractal.set_max_level(max_level); fractal.set_fractal_dimension(dimension); Matrix3x3_d frame = S2Testing::GetRandomFrame(); - scoped_ptr loop(fractal.MakeLoop(frame, + unique_ptr loop(fractal.MakeLoop(frame, S1Angle::Radians(nominal_radius))); ASSERT_TRUE(loop->IsValid()); @@ -155,4 +157,4 @@ TEST(S2Testing, CesaroMultiFractal) { TestFractal(2, 6, 1.8); } -} // namespace \ No newline at end of file +} // namespace diff --git a/src/s2textformat.cc b/src/s2textformat.cc new file mode 100644 index 00000000..e6d956e3 --- /dev/null +++ b/src/s2textformat.cc @@ -0,0 +1,177 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include "s2textformat.h" + +#include +#include + +#include +#include "base/stringprintf.h" +#include "strings/serialize.h" +#include "strings/split.h" +#include "s2.h" +#include "s2latlng.h" +#include "s2loop.h" +#include "s2polygon.h" +#include "s2polyline.h" + +using std::pair; +using std::vector; + +namespace s2textformat { + +static double ParseDouble(const string& str) { + char* end_ptr = NULL; + double value = strtod(str.c_str(), &end_ptr); + CHECK(end_ptr && *end_ptr == 0) << ": str == \"" << str << "\""; + return value; +} + +void ParseLatLngs(string const& str, vector* latlngs) { + vector > p; + CHECK(DictionaryParse(str, &p)) << ": str == \"" << str << "\""; + latlngs->clear(); + for (int i = 0; i < p.size(); ++i) { + latlngs->push_back(S2LatLng::FromDegrees(ParseDouble(p[i].first), + ParseDouble(p[i].second))); + } +} + +void ParsePoints(string const& str, vector* vertices) { + vector latlngs; + ParseLatLngs(str, &latlngs); + vertices->clear(); + for (int i = 0; i < latlngs.size(); ++i) { + vertices->push_back(latlngs[i].ToPoint()); + } +} + +S2Point MakePoint(string const& str) { + vector vertices; + ParsePoints(str, &vertices); + CHECK_EQ(vertices.size(), 1); + return vertices[0]; +} + +S2LatLngRect MakeLatLngRect(string const& str) { + vector latlngs; + ParseLatLngs(str, &latlngs); + CHECK_GT(latlngs.size(), 0); + S2LatLngRect rect = S2LatLngRect::FromPoint(latlngs[0]); + for (int i = 1; i < latlngs.size(); ++i) { + rect.AddPoint(latlngs[i]); + } + return rect; +} + +S2Loop* MakeLoop(string const& str) { + if (str == "empty") return new S2Loop(S2Loop::kEmpty()); + if (str == "full") return new S2Loop(S2Loop::kFull()); + vector vertices; + ParsePoints(str, &vertices); + return new S2Loop(vertices); +} + +S2Polyline* MakePolyline(string const& str) { + vector vertices; + ParsePoints(str, &vertices); + return new S2Polyline(vertices); +} + +static S2Polygon* InternalMakePolygon(string const& str, + bool normalize_loops) { + vector loop_strs = strings::Split(str, ';', strings::SkipEmpty()); + vector loops; + for (int i = 0; i < loop_strs.size(); ++i) { + S2Loop* loop = MakeLoop(loop_strs[i]); + if (normalize_loops) loop->Normalize(); + loops.push_back(loop); + } + return new S2Polygon(&loops); // Takes ownership. +} + +S2Polygon* MakePolygon(string const& str) { + return InternalMakePolygon(str, true); +} + +S2Polygon* MakeVerbatimPolygon(string const& str) { + return InternalMakePolygon(str, false); +} + +static void AppendVertex(S2Point const& p, string* out) { + S2LatLng ll(p); + StringAppendF(out, "%.17g:%.17g", ll.lat().degrees(), ll.lng().degrees()); +} + +static void AppendVertices(S2Point const* v, int n, string* out) { + for (int i = 0; i < n; ++i) { + if (i > 0) *out += ", "; + AppendVertex(v[i], out); + } +} + +string ToString(S2Point const& point) { + string out; + AppendVertex(point, &out); + return out; +} + +string ToString(S2LatLngRect const& rect) { + string out; + AppendVertex(rect.lo().ToPoint(), &out); + out += ", "; + AppendVertex(rect.hi().ToPoint(), &out); + return out; +} + +string ToString(S2Loop const* loop) { + string out; + AppendVertices(&loop->vertex(0), loop->num_vertices(), &out); + return out; +} + +string ToString(S2Polyline const* polyline) { + string out; + AppendVertices(&polyline->vertex(0), polyline->num_vertices(), &out); + return out; +} + +string ToString(S2Polygon const* polygon) { + string out; + for (int i = 0; i < polygon->num_loops(); ++i) { + if (i > 0) out += ";\n"; + S2Loop const* loop = polygon->loop(i); + AppendVertices(&loop->vertex(0), loop->num_vertices(), &out); + } + return out; +} + +string ToString(vector const& points) { + string out; + AppendVertices(&points[0], points.size(), &out); + return out; +} + +string ToString(vector const& latlngs) { + string out; + for (int i = 0; i < latlngs.size(); ++i) { + if (i > 0) out += ", "; + AppendVertex(latlngs[i].ToPoint(), &out); + } + return out; +} + +} // namespace s2textformat diff --git a/src/s2textformat.h b/src/s2textformat.h new file mode 100644 index 00000000..a97f7b87 --- /dev/null +++ b/src/s2textformat.h @@ -0,0 +1,99 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef S2_GEOMETRY_S2TEXTFORMAT_H_ +#define S2_GEOMETRY_S2TEXTFORMAT_H_ + +// s2textformat contains a collection of functions for converting +// geometry to and from a human-readable format. It is mainly +// intended for testing and debugging. Be aware that the +// human-readable format is *not* designed to preserve the full +// precision of the original object, so it should not be used +// for data storage. + +#include +#include + +#include "s2.h" +#include "s2latlngrect.h" + +class S2LatLng; +class S2Loop; +class S2Polygon; +class S2Polyline; + +namespace s2textformat { + +// Given a latitude-longitude coordinate in degrees, +// return a newly allocated point. Example of the input format: +// "-20:150" +S2Point MakePoint(string const& str); + +// Given a string of one or more latitude-longitude coordinates in degrees, +// return the minimal bounding S2LatLngRect that contains the coordinates. +// Example of the input format: +// "-20:150" // one point +// "-20:150, -20:151, -19:150" // three points +S2LatLngRect MakeLatLngRect(string const& str); + +// Given a string of latitude-longitude coordinates in degrees, +// return a newly allocated loop. Example of the input format: +// "-20:150, 10:-120, 0.123:-170.652" +// The strings "empty" or "full" create an empty or full loop respectively. +S2Loop* MakeLoop(string const& str); + +// Similar to MakeLoop(), but returns an S2Polyline rather than an S2Loop. +S2Polyline* MakePolyline(string const& str); + +// Given a sequence of loops separated by semicolons, return a newly +// allocated polygon. Loops are automatically normalized by inverting them +// if necessary so that they enclose at most half of the unit sphere. +// (Historically this was once a requirement of polygon loops. It also +// hides the problem that if the user thinks of the coordinates as X:Y +// rather than LAT:LNG, it yields a loop with the opposite orientation.) +// +// Examples of the input format: +// "10:20, 90:0, 20:30" // one loop +// "10:20, 90:0, 20:30; 5.5:6.5, -90:-180, -15.2:20.3" // two loops +// "" // the empty polygon (consisting of no loops) +// "full" // the full polygon (consisting of one full loop) +// "empty" // **INVALID** (a polygon consisting of one empty loop) +S2Polygon* MakePolygon(string const& str); + +// Like MakePolygon(), except that it does not normalize loops (i.e., it +// gives you exactly what you asked for). +S2Polygon* MakeVerbatimPolygon(string const& str); + +// Parse a string in the same format as MakeLatLngRect, and return the +// corresponding vector of S2LatLng points. +void ParseLatLngs(string const& str, std::vector* latlngs); + +// Parse a string in the same format as MakeLatLngRect, and return the +// corresponding vector of S2Point values. +void ParsePoints(string const& str, std::vector* vertices); + +// Convert a point, lat-lng rect, loop, polyline, or polygon to the string +// format above. +string ToString(S2Point const& point); +string ToString(S2LatLngRect const& rect); +string ToString(S2Loop const* loop); +string ToString(S2Polyline const* polyline); +string ToString(S2Polygon const* polygon); +string ToString(std::vector const& points); +string ToString(std::vector const& points); + +} // namespace s2textformat + +#endif // S2_GEOMETRY_S2TEXTFORMAT_H_ diff --git a/src/strings/ascii_ctype.cc b/src/strings/ascii_ctype.cc index 75a03760..7985334f 100644 --- a/src/strings/ascii_ctype.cc +++ b/src/strings/ascii_ctype.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // These are a little ugly. // The C++ style guide requires 80-column lines. @@ -132,4 +133,4 @@ const char kAsciiToUpper[256] = { '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef', '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7', '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff', -}; \ No newline at end of file +}; diff --git a/src/strings/ascii_ctype.h b/src/strings/ascii_ctype.h index 8b15eaa5..12f0bd56 100644 --- a/src/strings/ascii_ctype.h +++ b/src/strings/ascii_ctype.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // Character classification functions similar to standard . // Some C++ implementations provide locale-sensitive implementations @@ -42,18 +43,37 @@ // already tightly coupled to these functions. Names would just make it // harder to read and debug. -#define kApb kAsciiPropertyBits extern const unsigned char kAsciiPropertyBits[256]; // Public functions. -static inline bool ascii_isalpha(unsigned char c) { return kApb[c] & 0x01; } -static inline bool ascii_isalnum(unsigned char c) { return kApb[c] & 0x04; } -static inline bool ascii_isspace(unsigned char c) { return kApb[c] & 0x08; } -static inline bool ascii_ispunct(unsigned char c) { return kApb[c] & 0x10; } -static inline bool ascii_isblank(unsigned char c) { return kApb[c] & 0x20; } -static inline bool ascii_iscntrl(unsigned char c) { return kApb[c] & 0x40; } -static inline bool ascii_isxdigit(unsigned char c) { return kApb[c] & 0x80; } +static inline bool ascii_isalpha(unsigned char c) { + return (kAsciiPropertyBits[c] & 0x01) != 0; +} + +static inline bool ascii_isalnum(unsigned char c) { + return (kAsciiPropertyBits[c] & 0x04) != 0; +} + +static inline bool ascii_isspace(unsigned char c) { + return (kAsciiPropertyBits[c] & 0x08) != 0; +} + +static inline bool ascii_ispunct(unsigned char c) { + return (kAsciiPropertyBits[c] & 0x10) != 0; +} + +static inline bool ascii_isblank(unsigned char c) { + return (kAsciiPropertyBits[c] & 0x20) != 0; +} + +static inline bool ascii_iscntrl(unsigned char c) { + return (kAsciiPropertyBits[c] & 0x40) != 0; +} + +static inline bool ascii_isxdigit(unsigned char c) { + return (kAsciiPropertyBits[c] & 0x80) != 0; +} static inline bool ascii_isdigit(unsigned char c) { return c >= '0' && c <= '9'; @@ -78,11 +98,10 @@ static inline bool ascii_islower(unsigned char c) { static inline bool ascii_isascii(unsigned char c) { return c < 128; } -#undef kApb extern const char kAsciiToLower[256]; static inline char ascii_tolower(unsigned char c) { return kAsciiToLower[c]; } extern const char kAsciiToUpper[256]; static inline char ascii_toupper(unsigned char c) { return kAsciiToUpper[c]; } -#endif // STRINGS_ASCII_CTYPE_H_ \ No newline at end of file +#endif // STRINGS_ASCII_CTYPE_H_ diff --git a/src/strings/case.cc b/src/strings/case.cc index 380e6c16..ba3293b2 100644 --- a/src/strings/case.cc +++ b/src/strings/case.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: jyrki@google.com (Jyrki Alakuijala) // Refactored from contributions of various authors in strings/strutil.cc // @@ -37,17 +38,14 @@ CapsType GetCapitalization(const char* s) { if (!*s) return firstcapstype; const CapsType capstype = (ascii_islower(*s)) ? CAPS_LOWER : CAPS_UPPER; - if (firstcapstype == CAPS_LOWER && - capstype == CAPS_UPPER) - return CAPS_MIXED; + if (firstcapstype == CAPS_LOWER && capstype == CAPS_UPPER) return CAPS_MIXED; for (; *s; ++s) if ((ascii_isupper(*s) && capstype != CAPS_UPPER) || (ascii_islower(*s) && capstype != CAPS_LOWER)) return CAPS_MIXED; - if (firstcapstype == CAPS_UPPER && capstype == CAPS_LOWER) - return CAPS_FIRST; + if (firstcapstype == CAPS_UPPER && capstype == CAPS_LOWER) return CAPS_FIRST; return capstype; } @@ -77,15 +75,14 @@ void LowerString(string* s) { } void LowerStringToBuf(const char* s, char* buf, int n) { - for (int i = 0; i < n-1; i++) { + for (int i = 0; i < n - 1; i++) { char c = s[i]; buf[i] = ascii_tolower(c); if (c == '\0') { return; } } - if (n > 0) - buf[n-1] = '\0'; + if (n > 0) buf[n - 1] = '\0'; } void UpperString(char* s) { @@ -101,18 +98,17 @@ void UpperString(string* s) { } void UpperStringToBuf(const char* s, char* buf, int n) { - for (int i = 0; i < n-1; i++) { + for (int i = 0; i < n - 1; i++) { char c = s[i]; buf[i] = ascii_toupper(c); if (c == '\0') { return; } } - if (n > 0) - buf[n-1] = '\0'; + if (n > 0) buf[n - 1] = '\0'; } -void TitlecaseString(string *s, StringPiece delimiters) { +void TitlecaseString(string* s, StringPiece delimiters) { bool upper = true; for (string::iterator ss = s->begin(); ss != s->end(); ++ss) { if (upper) { @@ -120,4 +116,4 @@ void TitlecaseString(string *s, StringPiece delimiters) { } upper = (delimiters.find(*ss) != StringPiece::npos); } -} \ No newline at end of file +} diff --git a/src/strings/case.h b/src/strings/case.h index 78807da5..e5b255e7 100644 --- a/src/strings/case.h +++ b/src/strings/case.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: jyrki@google.com (Jyrki Alakuijala) // Refactored from contributions of various authors in strings/strutil.h // @@ -25,7 +26,9 @@ #define STRINGS_CASE_H_ #include -#include +#ifndef _MSC_VER +#include // for strcasecmp, but msvc does not have this header +#endif #include #include @@ -177,4 +180,4 @@ inline string ToUpper(StringPiece s) { // --------------------------------------------------------------------- void TitlecaseString(string* s, StringPiece delimiters); -#endif // STRINGS_CASE_H_ \ No newline at end of file +#endif // STRINGS_CASE_H_ diff --git a/src/strings/charset.cc b/src/strings/charset.cc index 78407629..477e2c0c 100644 --- a/src/strings/charset.cc +++ b/src/strings/charset.cc @@ -13,6 +13,7 @@ // limitations under the License. // + #include "strings/charset.h" #include @@ -38,4 +39,4 @@ CharSet::CharSet(StringPiece characters) { } } -} // namespace strings \ No newline at end of file +} // namespace strings diff --git a/src/strings/charset.h b/src/strings/charset.h index 2f108ae4..cf41216c 100644 --- a/src/strings/charset.h +++ b/src/strings/charset.h @@ -12,22 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // DO NOT use the CharSet(const char*) constructor in new codes as it will be // obsolete sometime in Q1 of 2013. Use the explicit CharSet(StringPiece) // constructor instead. -// -// The plan of migrating away from CharSet(const char*) is the following. -// -// 1. Check in the replacement constructor -- done at CL/38145114. -// arguments -- 16 identified so far. -// 3. Replace callers of identified functions passing in a const char* like -// foo("a const char*") -// by -// foo(CharSet("a const char*")) -// and send such CLs for review by respective code OWNERs. -// 4. Run TAP global presubmit to catch missing call sites and fix them. -// 5. Remove the CharSet(const char*) constructor from this header file. #ifndef STRINGS_CHARSET_H_ #define STRINGS_CHARSET_H_ @@ -55,8 +44,6 @@ namespace strings { // This class is thread-compatible. // // This class has an implicit constructor. -// Style guide exception granted: -// http://goto/style-guide-exception-20978288 class CharSet { public: @@ -98,4 +85,4 @@ class CharSet { } // namespace strings -#endif // STRINGS_CHARSET_H_ \ No newline at end of file +#endif // STRINGS_CHARSET_H_ diff --git a/src/strings/escaping.cc b/src/strings/escaping.cc deleted file mode 100644 index 341602c6..00000000 --- a/src/strings/escaping.cc +++ /dev/null @@ -1,2105 +0,0 @@ -// Copyright 2008 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#include "strings/escaping.h" - -#include -#include -#include - -#include -#include -#include - -#include "base/integral_types.h" -#include "base/macros.h" -#include "base/port.h" -#include "base/scoped_ptr.h" -#include "strings/join.h" -#include "strings/stringpiece.h" -#include // for runetochar -#include "util/endian/endian.h" -#include "util/gtl/charmap.h" -#include "util/gtl/stl_util.h" - -using std::vector; - -namespace strings { - -// Digit conversion. -static char hex_char[] = "0123456789abcdef"; - -// These are used for the leave_nulls_escaped argument to CUnescapeInternal(). -static bool kUnescapeNulls = false; -static bool kLeaveNullsEscaped = true; - -// ---------------------------------------------------------------------- -// EscapeStrForCSV() -// Escapes the quotes in 'src' by doubling them. This is necessary -// for generating CSV files (see SplitCSVLine). -// Returns the number of characters written into dest (not counting -// the \0) or -1 if there was insufficient space. Dest could end up -// twice as long as src. -// -// Example: [some "string" to test] --> [some ""string"" to test] -// ---------------------------------------------------------------------- -int EscapeStrForCSV(const char* src, char* dest, int dest_len) { - int used = 0; - - while (true) { - if (*src == '\0' && used < dest_len) { - dest[used] = '\0'; - return used; - } - - if (used + 1 >= dest_len) // +1 because we might require two characters - return -1; - - if (*src == '"') - dest[used++] = '"'; - - dest[used++] = *src++; - } -} - -// ---------------------------------------------------------------------- -// UnescapeCEscapeSequences() -// This does all the unescaping that C does: \ooo, \r, \n, etc -// Returns length of resulting string. -// The implementation of \x parses any positive number of hex digits, -// but it is an error if the value requires more than 8 bits, and the -// result is truncated to 8 bits. The same is true for octals. -// -// The second call stores its errors in a supplied string vector. -// If the string vector pointer is NULL, it reports the errors with LOG(). -// -// *** DEPRECATED: Use CUnescape() in new code *** -// -// NOTE: any changes to this function must also be reflected in the newer -// CUnescape(). -// ---------------------------------------------------------------------- - -#define IS_OCTAL_DIGIT(c) (((c) >= '0') && ((c) <= '7')) - -int UnescapeCEscapeSequences(const char* source, char* dest) { - return UnescapeCEscapeSequences(source, dest, NULL); -} - -int UnescapeCEscapeSequences(const char* source, char* dest, - vector *errors) { - char* d = dest; - const char* p = source; - - // Small optimization for case where source = dest and there's no escaping - while ( p == d && *p != '\0' && *p != '\\' ) - p++, d++; - - while (*p != '\0') { - if (*p != '\\') { - *d++ = *p++; - } else { - switch ( *++p ) { // skip past the '\\' - case '\0': - LOG_STRING(ERROR, errors) << "String cannot end with \\: " << source; - *d = '\0'; - return d - dest; // we're done with p - case 'a': *d++ = '\a'; break; - case 'b': *d++ = '\b'; break; - case 'f': *d++ = '\f'; break; - case 'n': *d++ = '\n'; break; - case 'r': *d++ = '\r'; break; - case 't': *d++ = '\t'; break; - case 'v': *d++ = '\v'; break; - case '\\': *d++ = '\\'; break; - case '?': *d++ = '\?'; break; // \? Who knew? - case '\'': *d++ = '\''; break; - case '"': *d++ = '\"'; break; - case '0': case '1': case '2': case '3': // octal digit: 1 to 3 digits - case '4': case '5': case '6': case '7': { - const char *octal_start = p; - unsigned int ch = *p - '0'; - if ( IS_OCTAL_DIGIT(p[1]) ) - ch = ch * 8 + *++p - '0'; - if ( IS_OCTAL_DIGIT(p[1]) ) // safe (and easy) to do this twice - ch = ch * 8 + *++p - '0'; // now points at last digit - if (ch > 0xFF) - LOG_STRING(ERROR, errors) << "Value of " << - "\\" << string(octal_start, p+1-octal_start) << - " exceeds 8 bits"; - *d++ = ch; - break; - } - case 'x': case 'X': { - if (!ascii_isxdigit(p[1])) { - if (p[1] == '\0') { - LOG_STRING(ERROR, errors) << "String cannot end with \\x"; - } else { - LOG_STRING(ERROR, errors) << - "\\x cannot be followed by a non-hex digit: \\" << *p << p[1]; - } - break; - } - unsigned int ch = 0; - const char *hex_start = p; - while (ascii_isxdigit(p[1])) // arbitrarily many hex digits - ch = (ch << 4) + hex_digit_to_int(*++p); - if (ch > 0xFF) - LOG_STRING(ERROR, errors) << "Value of " << - "\\" << string(hex_start, p+1-hex_start) << " exceeds 8 bits"; - *d++ = ch; - break; - } - case 'u': { - // \uhhhh => convert 4 hex digits to UTF-8 - Rune rune = 0; - const char *hex_start = p; - for (int i = 0; i < 4; ++i) { - if (ascii_isxdigit(p[1])) { // Look one char ahead. - rune = (rune << 4) + hex_digit_to_int(*++p); // Advance p. - } else { - LOG_STRING(ERROR, errors) - << "\\u must be followed by 4 hex digits: \\" - << string(hex_start, p+1-hex_start); - break; - } - } - d += runetochar(d, &rune); - break; - } - case 'U': { - // \Uhhhhhhhh => convert 8 hex digits to UTF-8 - Rune rune = 0; - const char *hex_start = p; - for (int i = 0; i < 8; ++i) { - if (ascii_isxdigit(p[1])) { // Look one char ahead. - // Don't change rune until we're sure this - // is within the Unicode limit, but do advance p. - Rune newrune = (rune << 4) + hex_digit_to_int(*++p); - if (newrune > 0x10FFFF) { - LOG_STRING(ERROR, errors) - << "Value of \\" - << string(hex_start, p + 1 - hex_start) - << " exceeds Unicode limit (0x10FFFF)"; - break; - } else { - rune = newrune; - } - } else { - LOG_STRING(ERROR, errors) - << "\\U must be followed by 8 hex digits: \\" - << string(hex_start, p+1-hex_start); - break; - } - } - d += runetochar(d, &rune); - break; - } - default: - LOG_STRING(ERROR, errors) << "Unknown escape sequence: \\" << *p; - } - p++; // read past letter we escaped - } - } - *d = '\0'; - return d - dest; -} - -// ---------------------------------------------------------------------- -// UnescapeCEscapeString() -// This does the same thing as UnescapeCEscapeSequences, but creates -// a new string. The caller does not need to worry about allocating -// a dest buffer. This should be used for non performance critical -// tasks such as printing debug messages. It is safe for src and dest -// to be the same. -// -// The second call stores its errors in a supplied string vector. -// If the string vector pointer is NULL, it reports the errors with LOG(). -// -// In the first and second calls, the length of dest is returned. In the -// the third call, the new string is returned. -// -// *** DEPRECATED: Use CUnescape() in new code *** -// -// ---------------------------------------------------------------------- -int UnescapeCEscapeString(const string& src, string* dest) { - return UnescapeCEscapeString(src, dest, NULL); -} - -int UnescapeCEscapeString(const string& src, string* dest, - vector *errors) { - CHECK(dest); - dest->resize(src.size() + 1); - int len = UnescapeCEscapeSequences(src.c_str(), - string_as_array(dest), errors); - dest->erase(len); - return len; -} - -string UnescapeCEscapeString(const string& src) { - string unescaped(src.size() + 1, '\0'); - - int len = UnescapeCEscapeSequences(src.c_str(), - string_as_array(&unescaped), NULL); - unescaped.erase(len); - return unescaped; -} - -// ---------------------------------------------------------------------- -// CUnescapeInternal() -// Implements both CUnescape() and CUnescapeForNullTerminatedString(). -// -// Unescapes C escape sequences and is the reverse of CEscape(). -// -// If 'source' is valid, stores the unescaped string and its size in -// 'dest' and 'dest_len' respectively, and returns true. Otherwise -// returns false and optionally stores the error description in -// 'error'. Set 'error' to NULL to disable error reporting. -// -// 'dest' should point to a buffer that is at least as big as 'source'. -// 'source' and 'dest' may be the same. -// -// NOTE: any changes to this function must also be reflected in the older -// UnescapeCEscapeSequences(). -// ---------------------------------------------------------------------- -static bool CUnescapeInternal(StringPiece source, - bool leave_nulls_escaped, - char* dest, - int* dest_len, - string* error) { - char* d = dest; - const char* p = source.data(); - const char* end = source.end(); - const char* last_byte = end - 1; - - // Small optimization for case where source = dest and there's no escaping - while (p == d && p < end && *p != '\\') - p++, d++; - - while (p < end) { - if (*p != '\\') { - *d++ = *p++; - } else { - if (++p > last_byte) { // skip past the '\\' - if (error) *error = "String cannot end with \\"; - return false; - } - switch (*p) { - case 'a': *d++ = '\a'; break; - case 'b': *d++ = '\b'; break; - case 'f': *d++ = '\f'; break; - case 'n': *d++ = '\n'; break; - case 'r': *d++ = '\r'; break; - case 't': *d++ = '\t'; break; - case 'v': *d++ = '\v'; break; - case '\\': *d++ = '\\'; break; - case '?': *d++ = '\?'; break; // \? Who knew? - case '\'': *d++ = '\''; break; - case '"': *d++ = '\"'; break; - case '0': case '1': case '2': case '3': // octal digit: 1 to 3 digits - case '4': case '5': case '6': case '7': { - const char *octal_start = p; - unsigned int ch = *p - '0'; - if (p < last_byte && IS_OCTAL_DIGIT(p[1])) - ch = ch * 8 + *++p - '0'; - if (p < last_byte && IS_OCTAL_DIGIT(p[1])) - ch = ch * 8 + *++p - '0'; // now points at last digit - if (ch > 0xff) { - if (error) { - *error = "Value of \\" + - string(octal_start, p + 1 - octal_start) + - " exceeds 0xff"; - } - return false; - } - if ((ch == 0) && leave_nulls_escaped) { - // Copy the escape sequence for the null character - const int octal_size = p + 1 - octal_start; - *d++ = '\\'; - memcpy(d, octal_start, octal_size); - d += octal_size; - break; - } - *d++ = ch; - break; - } - case 'x': case 'X': { - if (p >= last_byte) { - if (error) *error = "String cannot end with \\x"; - return false; - } else if (!ascii_isxdigit(p[1])) { - if (error) *error = "\\x cannot be followed by a non-hex digit"; - return false; - } - unsigned int ch = 0; - const char *hex_start = p; - while (p < last_byte && ascii_isxdigit(p[1])) - // Arbitrarily many hex digits - ch = (ch << 4) + hex_digit_to_int(*++p); - if (ch > 0xFF) { - if (error) { - *error = "Value of \\" + string(hex_start, p + 1 - hex_start) + - " exceeds 0xff"; - } - return false; - } - if ((ch == 0) && leave_nulls_escaped) { - // Copy the escape sequence for the null character - const int hex_size = p + 1 - hex_start; - *d++ = '\\'; - memcpy(d, hex_start, hex_size); - d += hex_size; - break; - } - *d++ = ch; - break; - } - case 'u': { - // \uhhhh => convert 4 hex digits to UTF-8 - Rune rune = 0; - const char *hex_start = p; - if (p + 4 >= end) { - if (error) { - *error = "\\u must be followed by 4 hex digits: \\" + - string(hex_start, p + 1 - hex_start); - } - return false; - } - for (int i = 0; i < 4; ++i) { - // Look one char ahead. - if (ascii_isxdigit(p[1])) { - rune = (rune << 4) + hex_digit_to_int(*++p); // Advance p. - } else { - if (error) { - *error = "\\u must be followed by 4 hex digits: \\" + - string(hex_start, p + 1 - hex_start); - } - return false; - } - } - if ((rune == 0) && leave_nulls_escaped) { - // Copy the escape sequence for the null character - *d++ = '\\'; - memcpy(d, hex_start, 5); // u0000 - d += 5; - break; - } - d += runetochar(d, &rune); - break; - } - case 'U': { - // \Uhhhhhhhh => convert 8 hex digits to UTF-8 - Rune rune = 0; - const char *hex_start = p; - if (p + 8 >= end) { - if (error) { - *error = "\\U must be followed by 8 hex digits: \\" + - string(hex_start, p + 1 - hex_start); - } - return false; - } - for (int i = 0; i < 8; ++i) { - // Look one char ahead. - if (ascii_isxdigit(p[1])) { - // Don't change rune until we're sure this - // is within the Unicode limit, but do advance p. - Rune newrune = (rune << 4) + hex_digit_to_int(*++p); - if (newrune > 0x10FFFF) { - if (error) { - *error = "Value of \\" + - string(hex_start, p + 1 - hex_start) + - " exceeds Unicode limit (0x10FFFF)"; - } - return false; - } else { - rune = newrune; - } - } else { - if (error) { - *error = "\\U must be followed by 8 hex digits: \\" + - string(hex_start, p + 1 - hex_start); - } - return false; - } - } - if ((rune == 0) && leave_nulls_escaped) { - // Copy the escape sequence for the null character - *d++ = '\\'; - memcpy(d, hex_start, 9); // U00000000 - d += 9; - break; - } - d += runetochar(d, &rune); - break; - } - default: { - if (error) *error = string("Unknown escape sequence: \\") + *p; - return false; - } - } - p++; // read past letter we escaped - } - } - *dest_len = d - dest; - return true; -} - -// ---------------------------------------------------------------------- -// CUnescapeInternal() -// -// Same as above but uses a C++ string for output. 'source' and 'dest' -// may be the same. -// ---------------------------------------------------------------------- -bool CUnescapeInternal(StringPiece source, - bool leave_nulls_escaped, - string* dest, - string* error) { - dest->resize(source.size()); - int dest_size; - if (!CUnescapeInternal(source, - leave_nulls_escaped, - const_cast(dest->data()), - &dest_size, - error)) { - return false; - } - dest->erase(dest_size); - return true; -} - -// ---------------------------------------------------------------------- -// CUnescape() -// -// See CUnescapeInternal() for implementation details. -// ---------------------------------------------------------------------- -bool CUnescape(StringPiece source, char* dest, int* dest_len, - string* error) { - return CUnescapeInternal(source, kUnescapeNulls, dest, dest_len, error); -} - -bool CUnescape(StringPiece source, string* dest, string* error) { - return CUnescapeInternal(source, kUnescapeNulls, dest, error); -} - -// ---------------------------------------------------------------------- -// CUnescapeForNullTerminatedString() -// -// See CUnescapeInternal() for implementation details. -// ---------------------------------------------------------------------- -bool CUnescapeForNullTerminatedString(StringPiece source, - char* dest, - int* dest_len, - string* error) { - return CUnescapeInternal(source, kLeaveNullsEscaped, dest, dest_len, error); -} - -bool CUnescapeForNullTerminatedString(StringPiece source, - string* dest, - string* error) { - return CUnescapeInternal(source, kLeaveNullsEscaped, dest, error); -} - -// ---------------------------------------------------------------------- -// CEscape() -// CHexEscape() -// Utf8SafeCEscape() -// Utf8SafeCHexEscape() -// Escapes 'src' using C-style escape sequences. This is useful for -// preparing query flags. The 'Hex' version uses hexadecimal rather than -// octal sequences. The 'Utf8Safe' version does not touch UTF-8 bytes. -// -// Escaped chars: \n, \r, \t, ", ', \, and !ascii_isprint(). -// ---------------------------------------------------------------------- -static string CEscapeInternal(StringPiece src, bool use_hex, bool utf8_safe) { - string dest; - bool last_hex_escape = false; // true if last output char was \xNN. - - for (const char* p = src.begin(); p < src.end(); ++p) { - unsigned char c = *p; - bool is_hex_escape = false; - switch (c) { - case '\n': dest.append("\\" "n"); break; - case '\r': dest.append("\\" "r"); break; - case '\t': dest.append("\\" "t"); break; - case '\"': dest.append("\\" "\""); break; - case '\'': dest.append("\\" "'"); break; - case '\\': dest.append("\\" "\\"); break; - default: - // Note that if we emit \xNN and the src character after that is a hex - // digit then that digit must be escaped too to prevent it being - // interpreted as part of the character code by C. - if ((!utf8_safe || c < 0x80) && - (!ascii_isprint(c) || - (last_hex_escape && ascii_isxdigit(c)))) { - if (use_hex) { - dest.append("\\" "x"); - dest.push_back(hex_char[c / 16]); - dest.push_back(hex_char[c % 16]); - is_hex_escape = true; - } else { - dest.append("\\"); - dest.push_back(hex_char[c / 64]); - dest.push_back(hex_char[(c % 64) / 8]); - dest.push_back(hex_char[c % 8]); - } - } else { - dest.push_back(c); - break; - } - } - last_hex_escape = is_hex_escape; - } - - return dest; -} - -string CEscape(StringPiece src) { - return CEscapeInternal(src, false, false); -} - -string CHexEscape(StringPiece src) { - return CEscapeInternal(src, true, false); -} - -string Utf8SafeCEscape(StringPiece src) { - return CEscapeInternal(src, false, true); -} - -string Utf8SafeCHexEscape(StringPiece src) { - return CEscapeInternal(src, true, true); -} - -// ---------------------------------------------------------------------- -// BackslashEscape, BackslashUnescape, and BackslashUnescapedFind -// ---------------------------------------------------------------------- - -void BackslashEscape(StringPiece src, - const strings::CharSet& to_escape, - string* dest) { - typedef StringPiece::const_iterator Iter; - Iter first = src.begin(); - Iter last = src.end(); - while (first != last) { - // Advance to next character we need to escape, or to end of source - Iter next = first; - while (next != last && !to_escape.Test(*next)) { - ++next; - } - // Append the whole run of non-escaped chars - dest->append(first, next); - if (next != last) { - // Char at *next needs to be escaped. - char c[2] = { '\\', *next++ }; - dest->append(c, c + arraysize(c)); - } - first = next; - } -} - -void BackslashUnescape(StringPiece src, - const strings::CharSet& to_unescape, - string* dest) { - typedef StringPiece::const_iterator Iter; - Iter first = src.begin(); - Iter last = src.end(); - bool escaped = false; - for (; first != last; ++first) { - if (escaped) { - if (to_unescape.Test(*first)) { - dest->push_back(*first); - escaped = false; - } else { - dest->push_back('\\'); - if (*first == '\\') { - escaped = true; - } else { - escaped = false; - dest->push_back(*first); - } - } - } else { - if (*first == '\\') { - escaped = true; - } else { - dest->push_back(*first); - } - } - } - if (escaped) { - dest->push_back('\\'); // trailing backslash - } -} - -static inline StringPiece::const_iterator BackslashUnescapedFindIter( - StringPiece::const_iterator first, - StringPiece::const_iterator last, - const strings::CharSet& chars) { - bool escaped = false; - StringPiece::const_iterator slash_pos; // valid only if escaped - for (; first != last; ++first) { - if (escaped) { - if (chars.Test('\\')) { - if (*first == '\\') { - continue; - } - if ((std::distance(slash_pos, first) & 1) == 0) { - escaped = false; - if (chars.Test(*first)) { - return first; - } - continue; - } - // odd distance to 'first': an unescaped '\' is at (first-1). - if (chars.Test(*first)) { - continue; - } - return first - 1; - } else { - escaped = false; - continue; - } - } - if (*first == '\\') { - escaped = true; - slash_pos = first; - continue; - } - if (chars.Test(*first)) { - return first; - } - } - if (escaped && chars.Test('\\')) { - if ((std::distance(slash_pos, first) & 1) == 1) { - return first - 1; - } - } - return first; -} - -stringpiece_ssize_type BackslashUnescapedFind(StringPiece src, - const strings::CharSet& chars) { - StringPiece::const_iterator pos = - BackslashUnescapedFindIter(src.begin(), src.end(), chars); - if (pos == src.end()) - return StringPiece::npos; - return std::distance(src.begin(), pos); -} - -// ---------------------------------------------------------------------- -// QuotedPrintableUnescapeInternal() -// -// Check out http://tools.ietf.org/html/rfc2045 for more details, only -// briefly implemented. But from the web... -// Quoted-printable is an encoding method defined in the MIME -// standard. It is used primarily to encode 8-bit text (such as text -// that includes foreign characters) into 7-bit US ASCII, creating a -// document that is mostly readable by humans, even in its encoded -// form. All MIME compliant applications can decode quoted-printable -// text, though they may not necessarily be able to properly display the -// document as it was originally intended. As quoted-printable encoding -// is implemented most commonly, printable ASCII characters (values 33 -// through 126, excluding 61), tabs and spaces that do not appear at the -// end of lines, and end-of-line characters are not encoded. Other -// characters are represented by an equal sign (=) immediately followed -// by that character's hexadecimal value. Lines that are longer than 76 -// characters are shortened by line breaks, with the equal sign marking -// where the breaks occurred. -// -// Note that QuotedPrintableUnescape is different from 'Q'-encoding as -// defined in RFC 2047. In particular, This does not treat '_'s as spaces. -// See QEncodingUnescape(). -// ---------------------------------------------------------------------- - -static size_t QuotedPrintableUnescapeInternal(const char* source, size_t slen, - char* dest, size_t szdest) { - char* d = dest; - const char* p = source; - - while ( p < source+slen && *p != '\0' && d < dest+szdest ) { - switch (*p) { - case '=': - // If it's valid, convert to hex and insert or remove line-wrap. - // In the case of line-wrap removal, we allow LF as well as CRLF. - if ( p < source + slen - 1 ) { - if ( p[1] == '\n' ) { - p++; - } else if ( p < source + slen - 2 ) { - if ( ascii_isxdigit(p[1]) && ascii_isxdigit(p[2]) ) { - *d++ = hex_digit_to_int(p[1])*16 + hex_digit_to_int(p[2]); - p += 2; - } else if ( p[1] == '\r' && p[2] == '\n' ) { - p += 2; - } - } - } - p++; - break; - default: - *d++ = *p++; - break; - } - } - return (d-dest); -} - -string QuotedPrintableUnescape(StringPiece src) { - string dest; - STLStringResizeUninitialized(&dest, src.size()); - size_t dest_size = QuotedPrintableUnescapeInternal( - src.data(), src.size(), string_as_array(&dest), dest.size()); - dest.erase(dest_size); - return dest; -} - -// ---------------------------------------------------------------------- -// QEncodingUnescapeInternal() -// -// This is very similar to QuotedPrintableUnescape except that we convert -// '_'s into spaces. (See RFC 2047) -// ---------------------------------------------------------------------- -static size_t QEncodingUnescapeInternal(const char* source, size_t slen, - char* dest, size_t szdest) { - char* d = dest; - const char* p = source; - - while ( p < source+slen && *p != '\0' && d < dest+szdest ) { - switch (*p) { - case '=': - // If it's valid, convert to hex and insert or remove line-wrap. - // In the case of line-wrap removal, the assumption is that this - // is an RFC-compliant message with lines terminated by CRLF. - if (p < source+slen-2) { - if ( ascii_isxdigit(p[1]) && ascii_isxdigit(p[2]) ) { - *d++ = hex_digit_to_int(p[1])*16 + hex_digit_to_int(p[2]); - p += 2; - } else if ( p[1] == '\r' && p[2] == '\n' ) { - p += 2; - } - } - p++; - break; - case '_': // According to RFC 2047, _'s are to be treated as spaces - *d++ = ' '; - p++; - break; - default: - *d++ = *p++; - break; - } - } - return (d-dest); -} - -string QEncodingUnescape(StringPiece src) { - string dest; - STLStringResizeUninitialized(&dest, src.size()); - size_t dest_size = QEncodingUnescapeInternal( - src.data(), src.size(), string_as_array(&dest), dest.size()); - dest.erase(dest_size); - return dest; -} - -int CalculateBase64EscapedLen(int input_len, bool do_padding) { - // Base64 encodes three bytes of input at a time. If the input is not - // divisible by three, we pad as appropriate. - // - // (from http://tools.ietf.org/html/rfc3548) - // Special processing is performed if fewer than 24 bits are available - // at the end of the data being encoded. A full encoding quantum is - // always completed at the end of a quantity. When fewer than 24 input - // bits are available in an input group, zero bits are added (on the - // right) to form an integral number of 6-bit groups. Padding at the - // end of the data is performed using the '=' character. Since all base - // 64 input is an integral number of octets, only the following cases - // can arise: - - - // Base64 encodes each three bytes of input into four bytes of output. - int len = (input_len / 3) * 4; - - if (input_len % 3 == 0) { - // (from http://tools.ietf.org/html/rfc3548) - // (1) the final quantum of encoding input is an integral multiple of 24 - // bits; here, the final unit of encoded output will be an integral - // multiple of 4 characters with no "=" padding, - } else if (input_len % 3 == 1) { - // (from http://tools.ietf.org/html/rfc3548) - // (2) the final quantum of encoding input is exactly 8 bits; here, the - // final unit of encoded output will be two characters followed by two - // "=" padding characters, or - len += 2; - if (do_padding) { - len += 2; - } - } else { // (input_len % 3 == 2) - // (from http://tools.ietf.org/html/rfc3548) - // (3) the final quantum of encoding input is exactly 16 bits; here, the - // final unit of encoded output will be three characters followed by one - // "=" padding character. - len += 3; - if (do_padding) { - len += 1; - } - } - - assert(len >= input_len); // make sure we didn't overflow - return len; -} - -// Base64Escape does padding, so this calculation includes padding. -int CalculateBase64EscapedLen(int input_len) { - return CalculateBase64EscapedLen(input_len, true); -} - -// ---------------------------------------------------------------------- -// int Base64Unescape() - base64 decoder -// int Base64Escape() - base64 encoder -// int WebSafeBase64Unescape() - Google's variation of base64 decoder -// int WebSafeBase64Escape() - Google's variation of base64 encoder -// -// Check out -// http://tools.ietf.org/html/rfc2045 for formal description, but what we -// care about is that... -// Take the encoded stuff in groups of 4 characters and turn each -// character into a code 0 to 63 thus: -// A-Z map to 0 to 25 -// a-z map to 26 to 51 -// 0-9 map to 52 to 61 -// +(- for WebSafe) maps to 62 -// /(_ for WebSafe) maps to 63 -// There will be four numbers, all less than 64 which can be represented -// by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively). -// Arrange the 6 digit binary numbers into three bytes as such: -// aaaaaabb bbbbcccc ccdddddd -// Equals signs (one or two) are used at the end of the encoded block to -// indicate that the text was not an integer multiple of three bytes long. -// ---------------------------------------------------------------------- - -int Base64UnescapeInternal(const char *src_param, int szsrc, - char *dest, int szdest, - const signed char* unbase64) { - static const char kPad64Equals = '='; - static const char kPad64Dot = '.'; - - int decode = 0; - int destidx = 0; - int state = 0; - unsigned int ch = 0; - unsigned int temp = 0; - - // If "char" is signed by default, using *src as an array index results in - // accessing negative array elements. Treat the input as a pointer to - // unsigned char to avoid this. - const unsigned char *src = reinterpret_cast(src_param); - - // The GET_INPUT macro gets the next input character, skipping - // over any whitespace, and stopping when we reach the end of the - // string or when we read any non-data character. The arguments are - // an arbitrary identifier (used as a label for goto) and the number - // of data bytes that must remain in the input to avoid aborting the - // loop. -#define GET_INPUT(label, remain) \ - label: \ - --szsrc; \ - ch = *src++; \ - decode = unbase64[ch]; \ - if (decode < 0) { \ - if (ascii_isspace(ch) && szsrc >= remain) \ - goto label; \ - state = 4 - remain; \ - break; \ - } - - // if dest is null, we're just checking to see if it's legal input - // rather than producing output. (I suspect this could just be done - // with a regexp...). We duplicate the loop so this test can be - // outside it instead of in every iteration. - - if (dest) { - // This loop consumes 4 input bytes and produces 3 output bytes - // per iteration. We can't know at the start that there is enough - // data left in the string for a full iteration, so the loop may - // break out in the middle; if so 'state' will be set to the - // number of input bytes read. - - while (szsrc >= 4) { - // We'll start by optimistically assuming that the next four - // bytes of the string (src[0..3]) are four good data bytes - // (that is, no nulls, whitespace, padding chars, or illegal - // chars). We need to test src[0..2] for nulls individually - // before constructing temp to preserve the property that we - // never read past a null in the string (no matter how long - // szsrc claims the string is). - - if (!src[0] || !src[1] || !src[2] || - (temp = ((unsigned(unbase64[src[0]]) << 18) | - (unsigned(unbase64[src[1]]) << 12) | - (unsigned(unbase64[src[2]]) << 6) | - (unsigned(unbase64[src[3]])))) & 0x80000000) { - // Iff any of those four characters was bad (null, illegal, - // whitespace, padding), then temp's high bit will be set - // (because unbase64[] is -1 for all bad characters). - // - // We'll back up and resort to the slower decoder, which knows - // how to handle those cases. - - GET_INPUT(first, 4); - temp = decode; - GET_INPUT(second, 3); - temp = (temp << 6) | decode; - GET_INPUT(third, 2); - temp = (temp << 6) | decode; - GET_INPUT(fourth, 1); - temp = (temp << 6) | decode; - } else { - // We really did have four good data bytes, so advance four - // characters in the string. - - szsrc -= 4; - src += 4; - decode = -1; - ch = '\0'; - } - - // temp has 24 bits of input, so write that out as three bytes. - - if (destidx+3 > szdest) return -1; - dest[destidx+2] = temp; - temp >>= 8; - dest[destidx+1] = temp; - temp >>= 8; - dest[destidx] = temp; - destidx += 3; - } - } else { - while (szsrc >= 4) { - if (!src[0] || !src[1] || !src[2] || - (temp = ((unsigned(unbase64[src[0]]) << 18) | - (unsigned(unbase64[src[1]]) << 12) | - (unsigned(unbase64[src[2]]) << 6) | - (unsigned(unbase64[src[3]])))) & 0x80000000) { - GET_INPUT(first_no_dest, 4); - GET_INPUT(second_no_dest, 3); - GET_INPUT(third_no_dest, 2); - GET_INPUT(fourth_no_dest, 1); - } else { - szsrc -= 4; - src += 4; - decode = -1; - ch = '\0'; - } - destidx += 3; - } - } - -#undef GET_INPUT - - // if the loop terminated because we read a bad character, return - // now. - if (decode < 0 && ch != '\0' && - ch != kPad64Equals && ch != kPad64Dot && !ascii_isspace(ch)) - return -1; - - if (ch == kPad64Equals || ch == kPad64Dot) { - // if we stopped by hitting an '=' or '.', un-read that character -- we'll - // look at it again when we count to check for the proper number of - // equals signs at the end. - ++szsrc; - --src; - } else { - // This loop consumes 1 input byte per iteration. It's used to - // clean up the 0-3 input bytes remaining when the first, faster - // loop finishes. 'temp' contains the data from 'state' input - // characters read by the first loop. - while (szsrc > 0) { - --szsrc; - ch = *src++; - decode = unbase64[ch]; - if (decode < 0) { - if (ascii_isspace(ch)) { - continue; - } else if (ch == '\0') { - break; - } else if (ch == kPad64Equals || ch == kPad64Dot) { - // back up one character; we'll read it again when we check - // for the correct number of pad characters at the end. - ++szsrc; - --src; - break; - } else { - return -1; - } - } - - // Each input character gives us six bits of output. - temp = (temp << 6) | decode; - ++state; - if (state == 4) { - // If we've accumulated 24 bits of output, write that out as - // three bytes. - if (dest) { - if (destidx+3 > szdest) return -1; - dest[destidx+2] = temp; - temp >>= 8; - dest[destidx+1] = temp; - temp >>= 8; - dest[destidx] = temp; - } - destidx += 3; - state = 0; - temp = 0; - } - } - } - - // Process the leftover data contained in 'temp' at the end of the input. - int expected_equals = 0; - switch (state) { - case 0: - // Nothing left over; output is a multiple of 3 bytes. - break; - - case 1: - // Bad input; we have 6 bits left over. - return -1; - - case 2: - // Produce one more output byte from the 12 input bits we have left. - if (dest) { - if (destidx+1 > szdest) return -1; - temp >>= 4; - dest[destidx] = temp; - } - ++destidx; - expected_equals = 2; - break; - - case 3: - // Produce two more output bytes from the 18 input bits we have left. - if (dest) { - if (destidx+2 > szdest) return -1; - temp >>= 2; - dest[destidx+1] = temp; - temp >>= 8; - dest[destidx] = temp; - } - destidx += 2; - expected_equals = 1; - break; - - default: - // state should have no other values at this point. - LOG(FATAL) << "This can't happen; base64 decoder state = " << state; - } - - // The remainder of the string should be all whitespace, mixed with - // exactly 0 equals signs, or exactly 'expected_equals' equals - // signs. (Always accepting 0 equals signs is a google extension - // not covered in the RFC, as is accepting dot as the pad character.) - - int equals = 0; - while (szsrc > 0 && *src) { - if (*src == kPad64Equals || *src == kPad64Dot) - ++equals; - else if (!ascii_isspace(*src)) - return -1; - --szsrc; - ++src; - } - - return (equals == 0 || equals == expected_equals) ? destidx : -1; -} - -// The arrays below were generated by the following code -// #include -// #include -// #include -// main() -// { -// static const char Base64[] = -// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -// char *pos; -// int idx, i, j; -// printf(" "); -// for (i = 0; i < 255; i += 8) { -// for (j = i; j < i + 8; j++) { -// pos = strchr(Base64, j); -// if ((pos == NULL) || (j == 0)) -// idx = -1; -// else -// idx = pos - Base64; -// if (idx == -1) -// printf(" %2d, ", idx); -// else -// printf(" %2d/*%c*/,", idx, j); -// } -// printf("\n "); -// } -// } -// -// where the value of "Base64[]" was replaced by one of the base-64 conversion -// tables from the functions below. -static const signed char kUnBase64[] = { - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 62/*+*/, -1, -1, -1, 63/*/ */, - 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/, - 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1, - -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/, - 07/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/, - 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/, - 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, -1, - -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/, - 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/, - 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/, - 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 -}; -static const signed char kUnWebSafeBase64[] = { - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 62/*-*/, -1, -1, - 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/, - 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1, - -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/, - 07/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/, - 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/, - 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, 63/*_*/, - -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/, - 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/, - 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/, - 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 -}; - -int WebSafeBase64Unescape(const char *src, int szsrc, char *dest, int szdest) { - return Base64UnescapeInternal(src, szsrc, dest, szdest, kUnWebSafeBase64); -} - -static bool Base64UnescapeInternal(const char* src, int slen, string* dest, - const signed char* unbase64) { - // Determine the size of the output string. Base64 encodes every 3 bytes into - // 4 characters. any leftover chars are added directly for good measure. - // This is documented in the base64 RFC: http://tools.ietf.org/html/rfc3548 - const int dest_len = 3 * (slen / 4) + (slen % 4); - - dest->resize(dest_len); - - // We are getting the destination buffer by getting the beginning of the - // string and converting it into a char *. - const int len = Base64UnescapeInternal(src, slen, string_as_array(dest), - dest_len, unbase64); - if (len < 0) { - dest->clear(); - return false; - } - - // could be shorter if there was padding - DCHECK_LE(len, dest_len); - dest->erase(len); - - return true; -} - -bool Base64Unescape(StringPiece src, string* dest) { - return Base64UnescapeInternal(src.data(), src.size(), dest, kUnBase64); -} - -bool WebSafeBase64Unescape(const char *src, int slen, string* dest) { - return Base64UnescapeInternal(src, slen, dest, kUnWebSafeBase64); -} - -int Base64EscapeInternal(const unsigned char *src, int szsrc, - char *dest, int szdest, const char *base64, - bool do_padding) { - static const char kPad64 = '='; - - if (szsrc <= 0) return 0; - - if (szsrc * 4 > szdest * 3) return 0; - - char *cur_dest = dest; - const unsigned char *cur_src = src; - - char *limit_dest = dest + szdest; - const unsigned char *limit_src = src + szsrc; - - // Three bytes of data encodes to four characters of cyphertext. - // So we can pump through three-byte chunks atomically. - while (cur_src < limit_src - 3) { // keep going as long as we have >= 32 bits - uint32 in = BigEndian::Load32(cur_src) >> 8; - - cur_dest[0] = base64[in >> 18]; - in &= 0x3FFFF; - cur_dest[1] = base64[in >> 12]; - in &= 0xFFF; - cur_dest[2] = base64[in >> 6]; - in &= 0x3F; - cur_dest[3] = base64[in]; - - cur_dest += 4; - cur_src += 3; - } - // To save time, we didn't update szdest or szsrc in the loop. So do it now. - szdest = limit_dest - cur_dest; - szsrc = limit_src - cur_src; - - /* now deal with the tail (<=3 bytes) */ - switch (szsrc) { - case 0: - // Nothing left; nothing more to do. - break; - case 1: { - // One byte left: this encodes to two characters, and (optionally) - // two pad characters to round out the four-character cypherblock. - if ((szdest -= 2) < 0) return 0; - uint32 in = cur_src[0]; - cur_dest[0] = base64[in >> 2]; - in &= 0x3; - cur_dest[1] = base64[in << 4]; - cur_dest += 2; - if (do_padding) { - if ((szdest -= 2) < 0) return 0; - cur_dest[0] = kPad64; - cur_dest[1] = kPad64; - cur_dest += 2; - } - break; - } - case 2: { - // Two bytes left: this encodes to three characters, and (optionally) - // one pad character to round out the four-character cypherblock. - if ((szdest -= 3) < 0) return 0; - uint32 in = BigEndian::Load16(cur_src); - cur_dest[0] = base64[in >> 10]; - in &= 0x3FF; - cur_dest[1] = base64[in >> 4]; - in &= 0x00F; - cur_dest[2] = base64[in << 2]; - cur_dest += 3; - if (do_padding) { - if ((szdest -= 1) < 0) return 0; - cur_dest[0] = kPad64; - cur_dest += 1; - } - break; - } - case 3: { - // Three bytes left: same as in the big loop above. We can't do this in - // the loop because the loop above always reads 4 bytes, and the fourth - // byte is past the end of the input. - if ((szdest -= 4) < 0) return 0; - uint32 in = (cur_src[0] << 16) + BigEndian::Load16(cur_src + 1); - cur_dest[0] = base64[in >> 18]; - in &= 0x3FFFF; - cur_dest[1] = base64[in >> 12]; - in &= 0xFFF; - cur_dest[2] = base64[in >> 6]; - in &= 0x3F; - cur_dest[3] = base64[in]; - cur_dest += 4; - break; - } - default: - // Should not be reached: blocks of 4 bytes are handled - // in the while loop before this switch statement. - LOG_ASSERT(false) << "Logic problem? szsrc = " << szsrc; - break; - } - return (cur_dest - dest); -} - -static const char kBase64Chars[] = -"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -static const char kWebSafeBase64Chars[] = -"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; - -int Base64Escape(const unsigned char *src, int szsrc, char *dest, int szdest) { - return Base64EscapeInternal(src, szsrc, dest, szdest, kBase64Chars, true); -} -int WebSafeBase64Escape(const unsigned char *src, int szsrc, char *dest, - int szdest, bool do_padding) { - return Base64EscapeInternal(src, szsrc, dest, szdest, - kWebSafeBase64Chars, do_padding); -} - -void Base64EscapeInternal(const unsigned char* src, int szsrc, - string* dest, bool do_padding, - const char* base64_chars) { - const int calc_escaped_size = - CalculateBase64EscapedLen(szsrc, do_padding); - dest->resize(calc_escaped_size); - const int escaped_len = Base64EscapeInternal(src, szsrc, - string_as_array(dest), - dest->size(), - base64_chars, - do_padding); - DCHECK_EQ(calc_escaped_size, escaped_len); - dest->erase(escaped_len); -} - -void Base64Escape(const unsigned char *src, int szsrc, - string* dest, bool do_padding) { - Base64EscapeInternal(src, szsrc, dest, do_padding, kBase64Chars); -} - -void WebSafeBase64Escape(const unsigned char *src, int szsrc, - string *dest, bool do_padding) { - Base64EscapeInternal(src, szsrc, dest, do_padding, kWebSafeBase64Chars); -} - -void Base64Escape(StringPiece src, string* dest) { - Base64Escape(reinterpret_cast(src.data()), - src.size(), dest, true); -} - -void WebSafeBase64Escape(StringPiece src, string* dest) { - WebSafeBase64Escape(reinterpret_cast(src.data()), - src.size(), dest, false); -} - -void WebSafeBase64EscapeWithPadding(StringPiece src, string* dest) { - WebSafeBase64Escape(reinterpret_cast(src.data()), - src.size(), dest, true); -} - -// Returns true iff c is in the Base 32 alphabet. -bool ValidBase32Byte(char c) { - return (c >= 'A' && c <= 'Z') || (c >= '2' && c <= '7') || c == '='; -} - -// Mapping from number of Base32 escaped characters (0 through 8) to number of -// unescaped bytes. 8 Base32 escaped characters represent 5 unescaped bytes. -// For N < 8, then number of unescaped bytes is less than 5. Note that in -// valid input, N can only be 0, 2, 4, 5, 7, or 8 (corresponding to 0, 1, 2, -// 3, 4, or 5 unescaped bytes). -// -// We use 5 for invalid values of N to be safe, since this is used to compute -// the length of the buffer to hold unescaped data. -// -// See http://tools.ietf.org/html/rfc4648#section-6 for details. -static const int kBase32NumUnescapedBytes[] = { - 0, 5, 1, 5, 2, 3, 5, 4, 5 -}; - -int Base32Unescape(const char* src, int slen, char* dest, int szdest) { - int destidx = 0; - char escaped_bytes[8]; - unsigned char unescaped_bytes[5]; - while (slen > 0) { - // Collect the next 8 escaped bytes and convert to upper case. If there - // are less than 8 bytes left, pad with '=', but keep track of the number - // of non-padded bytes for later. - int non_padded_len = 8; - for (int i = 0; i < 8; ++i) { - escaped_bytes[i] = (i < slen) ? ascii_toupper(src[i]) : '='; - if (!ValidBase32Byte(escaped_bytes[i])) { - return -1; - } - // Stop counting escaped bytes at first '='. - if (escaped_bytes[i] == '=' && non_padded_len == 8) { - non_padded_len = i; - } - } - - // Convert the 8 escaped bytes to 5 unescaped bytes and copy to dest. - EightBase32DigitsToFiveBytes(escaped_bytes, unescaped_bytes); - const int num_unescaped = kBase32NumUnescapedBytes[non_padded_len]; - for (int i = 0; i < num_unescaped; ++i) { - if (destidx == szdest) { - // No more room in dest, so terminate early. - return -1; - } - dest[destidx] = unescaped_bytes[i]; - ++destidx; - } - src += 8; - slen -= 8; - } - return destidx; -} - -bool Base32Unescape(const char* src, int slen, string* dest) { - // Determine the size of the output string. - const int dest_len = 5 * (slen / 8) + kBase32NumUnescapedBytes[slen % 8]; - - dest->resize(dest_len); - - // We are getting the destination buffer by getting the beginning of the - // string and converting it into a char *. - const int len = Base32Unescape(src, slen, - string_as_array(dest), dest->size()); - if (len < 0) { - dest->clear(); - return false; - } - - // Could be shorter if there was padding. - DCHECK_LE(len, dest_len); - dest->erase(len); - - return true; -} - -void GeneralFiveBytesToEightBase32Digits(const unsigned char *in_bytes, - char *out, const char *alphabet) { - // It's easier to just hard code this. - // The conversion isbased on the following picture of the division of a - // 40-bit block into 8 5-byte words: - // - // 5 3 2 5 1 4 4 1 5 2 3 5 - // |:::::::|:::::::|:::::::|:::::::|::::::: - // +----+----+----+----+----+----+----+---- - // - out[0] = alphabet[in_bytes[0] >> 3]; - out[1] = alphabet[(in_bytes[0] & 0x07) << 2 | in_bytes[1] >> 6]; - out[2] = alphabet[(in_bytes[1] & 0x3E) >> 1]; - out[3] = alphabet[(in_bytes[1] & 0x01) << 4 | in_bytes[2] >> 4]; - out[4] = alphabet[(in_bytes[2] & 0x0F) << 1 | in_bytes[3] >> 7]; - out[5] = alphabet[(in_bytes[3] & 0x7C) >> 2]; - out[6] = alphabet[(in_bytes[3] & 0x03) << 3 | in_bytes[4] >> 5]; - out[7] = alphabet[(in_bytes[4] & 0x1F)]; -} - -static int GeneralBase32Escape(const unsigned char *src, size_t szsrc, - char *dest, size_t szdest, - const char *alphabet) { - static const char kPad32 = '='; - - if (szsrc == 0) return 0; - - char *cur_dest = dest; - const unsigned char *cur_src = src; - - // Five bytes of data encodes to eight characters of cyphertext. - // So we can pump through three-byte chunks atomically. - while (szsrc > 4) { // keep going until we have less than 40 bits - if ( szdest < 8) return 0; - szdest -= 8; - - GeneralFiveBytesToEightBase32Digits(cur_src, cur_dest, alphabet); - - cur_dest += 8; - cur_src += 5; - szsrc -= 5; - } - - // Now deal with the tail (<=4 bytes). - if (szsrc > 0) { - if ( szdest < 8) return 0; - szdest -= 8; - unsigned char last_chunk[5]; - memcpy(last_chunk, cur_src, szsrc); - - for (size_t i = szsrc; i < 5; ++i) { - last_chunk[i] = '\0'; - } - - GeneralFiveBytesToEightBase32Digits(last_chunk, cur_dest, alphabet); - int filled = (szsrc * 8) / 5 + 1; - cur_dest += filled; - - // Add on the padding. - for (int i = 0; i < (8 - filled); ++i) { - *(cur_dest++) = kPad32; - } - } - - return cur_dest - dest; -} - -static bool GeneralBase32Escape(const string& src, string* dest, - const char *alphabet) { - const int max_escaped_size = CalculateBase32EscapedLen(src.length()); - dest->resize(max_escaped_size + 1); - const int escaped_len = - GeneralBase32Escape(reinterpret_cast(src.c_str()), - src.length(), &*dest->begin(), dest->size(), - alphabet); - - DCHECK_LE(max_escaped_size, escaped_len); - - if (escaped_len < 0) { - dest->clear(); - return false; - } - - dest->erase(escaped_len); - return true; -} - -static const char Base32Alphabet[] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', '2', '3', '4', '5', '6', '7' - }; - -int Base32Escape(const unsigned char* src, size_t szsrc, - char* dest, size_t szdest) { - return GeneralBase32Escape(src, szsrc, dest, szdest, Base32Alphabet); -} - -bool Base32Escape(const string& src, string* dest) { - return GeneralBase32Escape(src, dest, Base32Alphabet); -} - -void FiveBytesToEightBase32Digits(const unsigned char *in_bytes, char *out) { - GeneralFiveBytesToEightBase32Digits(in_bytes, out, Base32Alphabet); -} - -static const char Base32HexAlphabet[] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', - 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', - }; - -int Base32HexEscape(const unsigned char* src, size_t szsrc, - char* dest, size_t szdest) { - return GeneralBase32Escape(src, szsrc, dest, szdest, Base32HexAlphabet); -} - -bool Base32HexEscape(const string& src, string* dest) { - return GeneralBase32Escape(src, dest, Base32HexAlphabet); -} - -int CalculateBase32EscapedLen(size_t input_len) { - DCHECK_LE(input_len, std::numeric_limits::max() / 8); - size_t intermediate_result = 8 * input_len + 4; - size_t len = intermediate_result / 5; - len = (len + 7) & ~7; - return len; -} - -// ---------------------------------------------------------------------- -// EightBase32DigitsToTenHexDigits() -// Converts an 8-digit base32 string to a 10-digit hex string. -// -// *in must point to 8 base32 digits. -// *out must point to 10 bytes. -// -// Base32 uses A-Z,2-7 to represent the numbers 0-31. -// See RFC3548 at http://tools.ietf.org/html/rfc3548 -// for details on base32. -// ---------------------------------------------------------------------- - - -void EightBase32DigitsToTenHexDigits(const char *in, char *out) { - unsigned char bytes[5]; - EightBase32DigitsToFiveBytes(in, bytes); - b2a_hex(bytes, out, 5); -} - -void EightBase32DigitsToFiveBytes(const char *in_param, - unsigned char *bytes_out) { - static const unsigned char Base32InverseAlphabet[] = { - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 26/*2*/, 27/*3*/, 28/*4*/, 29/*5*/, 30/*6*/, 31/*7*/, - 99, 99, 99, 99, 99, 00/*=*/, 99, 99, - 99, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/, - 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/, - 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/, - 23/*X*/, 24/*Y*/, 25/*Z*/, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99 - }; - - // If "char" is signed by default, using *src as an array index results in - // accessing negative array elements. Treat the input as a pointer to - // unsigned char to avoid this. - const unsigned char *in = reinterpret_cast(in_param); - - // Convert to raw bytes. It's easier to just hard code this. - bytes_out[0] = Base32InverseAlphabet[in[0]] << 3 | - Base32InverseAlphabet[in[1]] >> 2; - - bytes_out[1] = Base32InverseAlphabet[in[1]] << 6 | - Base32InverseAlphabet[in[2]] << 1 | - Base32InverseAlphabet[in[3]] >> 4; - - bytes_out[2] = Base32InverseAlphabet[in[3]] << 4 | - Base32InverseAlphabet[in[4]] >> 1; - - bytes_out[3] = Base32InverseAlphabet[in[4]] << 7 | - Base32InverseAlphabet[in[5]] << 2 | - Base32InverseAlphabet[in[6]] >> 3; - - bytes_out[4] = Base32InverseAlphabet[in[6]] << 5 | - Base32InverseAlphabet[in[7]]; -} - -// ---------------------------------------------------------------------- -// TenHexDigitsToEightBase32Digits() -// Converts a 10-digit hex string to an 8-digit base32 string. -// -// *in must point to 10 hex digits. -// *out must point to 8 bytes. -// -// See RFC3548 at http://tools.ietf.org/html/rfc3548 -// for details on base32. -// ---------------------------------------------------------------------- -void TenHexDigitsToEightBase32Digits(const char *in, char *out) { - unsigned char bytes[5]; - - // Convert hex to raw bytes. - a2b_hex(in, bytes, 5); - FiveBytesToEightBase32Digits(bytes, out); -} - -// ---------------------------------------------------------------------- -// EscapeFileName / UnescapeFileName -// ---------------------------------------------------------------------- -static const Charmap escape_file_name_exceptions( - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" // letters - "0123456789" // digits - "-_."); - -void EscapeFileName(StringPiece src, string* dst) { - // Reserve at least src.size() chars - dst->reserve(dst->size() + src.size()); - - for (int i = 0; i < src.size(); ++i) { - const char c = src[i]; - // We do not use "isalpha" because we want the behavior to be - // independent of the current locale settings. - if (escape_file_name_exceptions.contains(c)) { - dst->push_back(c); - - } else if (c == '/') { - dst->push_back('~'); - - } else { - char tmp[2]; - b2a_hex(reinterpret_cast(&c), tmp, 1); - dst->push_back('%'); - dst->append(tmp, 2); - } - } -} - -void UnescapeFileName(StringPiece src_piece, string* dst) { - const char* src = src_piece.data(); - const int len = src_piece.size(); - for (int i = 0; i < len; ++i) { - const char c = src[i]; - if (c == '~') { - dst->push_back('/'); - - } else if ((c == '%') && (i + 2 < len)) { - unsigned char tmp[1]; - a2b_hex(src + i + 1, &tmp[0], 1); - dst->push_back(tmp[0]); - i += 2; - - } else { - dst->push_back(c); - } - } -} - -static char hex_value[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // '0'..'9' - 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'A'..'F' - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'a'..'f' - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -// This is a templated function so that T can be either a char* -// or a string. This works because we use the [] operator to access -// individual characters at a time. -template -static void a2b_hex_t(const char* a, T b, int num) { - for (int i = 0; i < num; i++) { - b[i] = (hex_value[a[i * 2] & 0xFF] << 4) - + (hex_value[a[i * 2 + 1] & 0xFF]); - } -} - -string a2b_bin(const string& a, bool byte_order_msb) { - string result; - const char *data = a.c_str(); - int num_bytes = (a.size()+7)/8; - for (int byte_offset = 0; byte_offset < num_bytes; ++byte_offset) { - unsigned char c = 0; - for (int bit_offset = 0; bit_offset < 8; ++bit_offset) { - if (*data == '\0') - break; - if (*data++ != '0') { - int bits_to_shift = (byte_order_msb) ? 7-bit_offset : bit_offset; - c |= (1 << bits_to_shift); - } - } - result.append(1, c); - } - return result; -} - -// This is a templated function so that T can be either a char* -// or a string. This works because we use the [] operator to access -// individual characters at a time. -template -static void b2a_hex_t(const unsigned char* b, T a, int num) { - for (int i = 0; i < num; i++) { - a[i * 2 + 0] = hex_char[b[i] >> 4]; - a[i * 2 + 1] = hex_char[b[i] & 0xf]; - } -} - -string b2a_bin(const string& b, bool byte_order_msb) { - string result; - for (int byte_offset = 0; byte_offset < b.size(); ++byte_offset) { - for (int bit_offset = 0; bit_offset < 8; ++bit_offset) { - int x = (byte_order_msb) ? 7-bit_offset : bit_offset; - result.append(1, (b[byte_offset] & (1 << x)) ? '1' : '0'); - } - } - return result; -} - -void b2a_hex(const unsigned char* b, char* a, int num) { - b2a_hex_t(b, a, num); -} - -void a2b_hex(const char* a, unsigned char* b, int num) { - a2b_hex_t(a, b, num); -} - -void a2b_hex(const char* a, char* b, int num) { - a2b_hex_t(a, b, num); -} - -string b2a_hex(const char* b, int len) { - string result; - result.resize(len << 1); - b2a_hex_t(reinterpret_cast(b), result, len); - return result; -} - -string b2a_hex(StringPiece b) { - return b2a_hex(b.data(), b.size()); -} - -string a2b_hex(StringPiece a) { - string result; - a2b_hex(a.data(), &result, a.size()/2); - return result; -} - -void b2a_hex(const unsigned char* from, string* to, int num) { - to->resize(num << 1); - b2a_hex_t(from, *to, num); -} - -void a2b_hex(const char* from, string* to, int num) { - to->resize(num); - a2b_hex_t(from, *to, num); -} - -const char* kDontNeedShellEscapeChars = -"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.=/:,@"; - -string ShellEscape(StringPiece src) { - if (!src.empty() && // empty string needs quotes - src.find_first_not_of(kDontNeedShellEscapeChars) == StringPiece::npos) { - // only contains chars that don't need quotes; it's fine - return src.ToString(); - } else if (src.find('\'') == StringPiece::npos) { - // no single quotes; just wrap it in single quotes - return StrCat("'", src, "'"); - } else { - // needs double quote escaping - string result = "\""; - for (size_t i = 0; i < src.size(); ++i) { - switch (src[i]) { - case '\\': - case '$': - case '"': - case '`': - result.push_back('\\'); - } - result.push_back(src[i]); - } - result.push_back('"'); - return result; - } -} - -static const char kHexTable[513]= - "000102030405060708090a0b0c0d0e0f" - "101112131415161718191a1b1c1d1e1f" - "202122232425262728292a2b2c2d2e2f" - "303132333435363738393a3b3c3d3e3f" - "404142434445464748494a4b4c4d4e4f" - "505152535455565758595a5b5c5d5e5f" - "606162636465666768696a6b6c6d6e6f" - "707172737475767778797a7b7c7d7e7f" - "808182838485868788898a8b8c8d8e8f" - "909192939495969798999a9b9c9d9e9f" - "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" - "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" - "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" - "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" - "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" - "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; - -//------------------------------------------------------------------------ -// ByteStringToAscii -// Reads at most bytes_to_read from binary_string and prints it to -// ascii_string in downcased hex. -//------------------------------------------------------------------------ -void ByteStringToAscii(string const &binary_string, int bytes_to_read, - string * ascii_string ) { - if (binary_string.size() < bytes_to_read) { - bytes_to_read = binary_string.size(); - } - - CHECK_GE(bytes_to_read, 0); - ascii_string->resize(bytes_to_read*2); - - string::const_iterator in = binary_string.begin(); - string::iterator out = ascii_string->begin(); - - for (int i = 0; i < bytes_to_read; i++) { - int hex_table_index = (0xFF & *in) * 2; // Mask with 0xFF in case *in - // is signed. - *out++ = kHexTable[hex_table_index]; - *out++ = kHexTable[hex_table_index + 1]; - ++in; - } -} - -//------------------------------------------------------------------------ -// ByteStringFromAscii -// Converts the hex from ascii_string into binary data and -// writes the binary data into binary_string. -// Empty input successfully converts to empty output. -// Returns false and may modify output if it is -// unable to parse the hex string. -//------------------------------------------------------------------------ -bool ByteStringFromAscii(string const & hex_string, string * binary_string) { - binary_string->clear(); - - if ((hex_string.size()%2) != 0) { - return false; - } - - int value = 0; - for (int i = 0; i < hex_string.size(); i++) { - char c = hex_string[i]; - - if (!ascii_isxdigit(c)) { - return false; - } - - if (ascii_isdigit(c)) { - value += c - '0'; - } else if (ascii_islower(c)) { - value += 10 + c - 'a'; - } else { - value += 10 + c - 'A'; - } - - if (i & 1) { - binary_string->push_back(value); - value = 0; - } else { - value <<= 4; - } - } - - return true; -} - -// ---------------------------------------------------------------------- -// CleanStringLineEndings() -// Clean up a multi-line string to conform to Unix line endings. -// Reads from src and appends to dst, so usually dst should be empty. -// -// If there is no line ending at the end of a non-empty string, it can -// be added automatically. -// -// Four different types of input are correctly handled: -// -// - Unix/Linux files: line ending is LF, pass through unchanged -// -// - DOS/Windows files: line ending is CRLF: convert to LF -// -// - Legacy Mac files: line ending is CR: convert to LF -// -// - Garbled files: random line endings, covert gracefully -// lonely CR, lonely LF, CRLF: convert to LF -// -// @param src The multi-line string to convert -// @param dst The converted string is appended to this string -// @param auto_end_last_line Automatically terminate the last line -// -// Limitations: -// -// This does not do the right thing for CRCRLF files created by -// broken programs that do another Unix->DOS conversion on files -// that are already in CRLF format. For this, a two-pass approach -// brute-force would be needed that -// -// (1) determines the presence of LF (first one is ok) -// (2) if yes, removes any CR, else convert every CR to LF - -void CleanStringLineEndings(const string& src, string* dst, - bool auto_end_last_line) { - if (dst->empty()) { - dst->append(src); - CleanStringLineEndings(dst, auto_end_last_line); - } else { - string tmp = src; - CleanStringLineEndings(&tmp, auto_end_last_line); - dst->append(tmp); - } -} - -void CleanStringLineEndings(string* str, bool auto_end_last_line) { - int output_pos = 0; - bool r_seen = false; - int len = str->size(); - - char* p = string_as_array(str); - - for (int input_pos = 0; input_pos < len;) { - if (!r_seen && input_pos + 8 < len) { - uint64 v = UNALIGNED_LOAD64(p + input_pos); - // Loop over groups of 8 bytes at a time until we come across - // a word that has a byte whose value is less than or equal to - // '\r' (i.e. could contain a \n (0x0a) or a \r (0x0d) ). - // - // We use a has_less macro that quickly tests a whole 64-bit - // word to see if any of the bytes has a value < N. - // - // For more details, see: - // http://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord -#define has_less(x, n) (((x)-~0ULL/255*(n))&~(x)&~0ULL/255*128) - if (!has_less(v, '\r' + 1)) { -#undef has_less - // No byte in this word has a value that could be a \r or a \n - if (output_pos != input_pos) - UNALIGNED_STORE64(p + output_pos, v); - input_pos += 8; - output_pos += 8; - continue; - } - } - string::const_reference in = p[input_pos]; - if (in == '\r') { - if (r_seen) - p[output_pos++] = '\n'; - r_seen = true; - } else if (in == '\n') { - if (input_pos != output_pos) - p[output_pos++] = '\n'; - else - output_pos++; - r_seen = false; - } else { - if (r_seen) - p[output_pos++] = '\n'; - r_seen = false; - if (input_pos != output_pos) - p[output_pos++] = in; - else - output_pos++; - } - input_pos++; - } - if (r_seen || (auto_end_last_line - && output_pos > 0 - && p[output_pos - 1] != '\n')) { - str->resize(output_pos + 1); - str->operator[](output_pos) = '\n'; - } else if (output_pos < len) { - str->resize(output_pos); - } -} - - -} // namespace strings \ No newline at end of file diff --git a/src/strings/escaping.h b/src/strings/escaping.h deleted file mode 100644 index 6f1d1218..00000000 --- a/src/strings/escaping.h +++ /dev/null @@ -1,745 +0,0 @@ -// Copyright 2006 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// -// This is a grab-bag file for string utilities involved in escaping and -// unescaping strings in various ways. Who knew there were so many? -// -// There are more escaping functions in: -// webutil/html/tagutils.h (Escaping strings for HTML, PRE, JavaScript, etc.) -// webutil/url/url.h (Escaping for URL's, both RFC-2396 and other methods) -// template/template_modifiers.h (All sorts of stuff) -// util/regexp/re2/re2.h (Escaping for literals within regular expressions -// - see RE2::QuoteMeta). -// And probably many more places, as well. - -#ifndef STRINGS_ESCAPING_H_ -#define STRINGS_ESCAPING_H_ - -#include -#include -#include - -#include -#include "strings/ascii_ctype.h" -#include "strings/charset.h" -#include "strings/stringpiece.h" - -namespace strings { - -// ---------------------------------------------------------------------- -// EscapeStrForCSV() -// Escapes the quotes in 'src' by doubling them. This is necessary -// for generating CSV files (see SplitCSVLine). -// Returns the number of characters written into dest (not counting -// the \0) or -1 if there was insufficient space. -// -// Example: [some "string" to test] --> [some ""string"" to test] -// ---------------------------------------------------------------------- -int EscapeStrForCSV(const char* src, char* dest, int dest_len); - -// ---------------------------------------------------------------------- -// UnescapeCEscapeSequences() -// Copies "source" to "dest", rewriting C-style escape sequences -// -- '\n', '\r', '\\', '\ooo', etc -- to their ASCII -// equivalents. "dest" must be sufficiently large to hold all -// the characters in the rewritten string (i.e. at least as large -// as strlen(source) + 1 should be safe, since the replacements -// are always shorter than the original escaped sequences). It's -// safe for source and dest to be the same. RETURNS the length -// of dest. -// -// It allows hex sequences \xhh, or generally \xhhhhh with an -// arbitrary number of hex digits, but all of them together must -// specify a value of a single byte (e.g. \x0045 is equivalent -// to \x45, and \x1234 is erroneous). If the value is too large, -// it is truncated to 8 bits and an error is set. This is also -// true of octal values that exceed 0xff. -// -// It also allows escape sequences of the form \uhhhh (exactly four -// hex digits, upper or lower case) or \Uhhhhhhhh (exactly eight -// hex digits, upper or lower case) to specify a Unicode code -// point. The dest array will contain the UTF8-encoded version of -// that code-point (e.g., if source contains \u2019, then dest will -// contain the three bytes 0xE2, 0x80, and 0x99). For the inverse -// transformation, use UniLib::UTF8EscapeString -// (util/utf8/public/unilib.h), not CEscapeString. -// -// Errors: In the first form of the call, errors are reported with -// LOG(ERROR). The same is true for the second form of the call if -// the pointer to the string vector is NULL; otherwise, error -// messages are stored in the vector. In either case, the effect on -// the dest array is not defined, but rest of the source will be -// processed. -// -// *** DEPRECATED: Use CUnescape() in new code *** -// ---------------------------------------------------------------------- -int UnescapeCEscapeSequences(const char* source, char* dest); -int UnescapeCEscapeSequences(const char* source, char* dest, - std::vector* errors); - -// ---------------------------------------------------------------------- -// UnescapeCEscapeString() -// This does the same thing as UnescapeCEscapeSequences, but creates -// a new string. The caller does not need to worry about allocating -// a dest buffer. This should be used for non performance critical -// tasks such as printing debug messages. It is safe for src and dest -// to be the same. -// -// The second call stores its errors in a supplied string vector. -// If the string vector pointer is NULL, it reports the errors with LOG(). -// -// In the first and second calls, the length of dest is returned. In the -// the third call, the new string is returned. -// -// *** DEPRECATED: Use CUnescape() in new code *** -// ---------------------------------------------------------------------- -int UnescapeCEscapeString(const string& src, string* dest); -int UnescapeCEscapeString(const string& src, string* dest, - std::vector* errors); -string UnescapeCEscapeString(const string& src); - -// ---------------------------------------------------------------------- -// CUnescape() -// Copies "source" to "dest", rewriting C-style escape sequences -// -- '\n', '\r', '\\', '\ooo', etc -- to their ASCII -// equivalents. "dest" must be sufficiently large to hold all -// the characters in the rewritten string (i.e. at least as large -// as source.size() should be safe, since the replacements -// are never longer than the original escaped sequences). It's -// safe for source and dest to be the same. RETURNS true if -// conversion was successful, false otherwise. Stores the size of -// the result in 'dest_len'. -// -// It allows hex sequences \xhh, or generally \xhhhhh with an -// arbitrary number of hex digits, but all of them together must -// specify a value of a single byte (e.g. \x0045 is equivalent -// to \x45, and \x1234 is erroneous). If the value is too large, -// an error is set. This is also true of octal values that exceed 0xff. -// -// It also allows escape sequences of the form \uhhhh (exactly four -// hex digits, upper or lower case) or \Uhhhhhhhh (exactly eight -// hex digits, upper or lower case) to specify a Unicode code -// point. The dest array will contain the UTF8-encoded version of -// that code-point (e.g., if source contains \u2019, then dest will -// contain the three bytes 0xE2, 0x80, and 0x99). For the inverse -// transformation, use UniLib::UTF8EscapeString -// (util/utf8/public/unilib.h), not CEscapeString. -// -// Errors: Sets the description of the first encountered error in -// 'error'. To disable error reporting, set 'error' to NULL. -// ---------------------------------------------------------------------- -bool CUnescape(StringPiece source, char* dest, int* dest_len, - string* error); - -bool CUnescape(StringPiece source, string* dest, string* error); - -// A version with no error reporting. -inline bool CUnescape(StringPiece source, string* dest) { - return CUnescape(source, dest, NULL); -} - -// ---------------------------------------------------------------------- -// CUnescapeForNullTerminatedString() -// -// This has the same behavior as CUnescape, except that each octal, hex, -// or Unicode escape sequence that resolves to a null character ('\0') -// is left in its original escaped form. The result is a -// display-formatted string that can be interpreted as a null-terminated -// const char* and will not be cut short if it contains embedded null -// characters. -// -// ---------------------------------------------------------------------- - -bool CUnescapeForNullTerminatedString(StringPiece source, - char* dest, - int* dest_len, - string* error); - -bool CUnescapeForNullTerminatedString(StringPiece source, - string* dest, - string* error); - -// A version with no error reporting. -inline bool CUnescapeForNullTerminatedString(StringPiece source, - string* dest) { - return CUnescapeForNullTerminatedString(source, dest, NULL); -} - -// ---------------------------------------------------------------------- -// CEscape() -// CHexEscape() -// Utf8SafeCEscape() -// Utf8SafeCHexEscape() -// Escapes 'src' using C-style escape sequences. This is useful for -// preparing query flags. The 'Hex' version uses hexadecimal rather than -// octal sequences. The 'Utf8Safe' version does not touch UTF-8 bytes. -// -// Escaped chars: \n, \r, \t, ", ', \, and !ascii_isprint(). -// ---------------------------------------------------------------------- -string CEscape(StringPiece src); -string CHexEscape(StringPiece src); -string Utf8SafeCEscape(StringPiece src); -string Utf8SafeCHexEscape(StringPiece src); - -// ---------------------------------------------------------------------- -// BackslashEscape(), BackslashUnescape(), BackslashUnescapedFind() -// -// - Use backslashes to selectively escape or unescape a set of -// delimiter characters. -// -// SYNOPSIS: -// -// #include "strings/escaping.h" -// -// #include "strings/charset.h" -// #include "strings/stringpiece.h" -// -// namespace strings { -// void BackslashEscape(StringPiece src, -// const strings::CharSet& delims, -// string* dest); -// void BackslashUnescape(StringPiece src, -// const strings::CharSet& delims, -// string* dest); -// stringpiece_ssize_type BackslashUnescapedFind( -// StringPiece src, -// const strings::CharSet& delims); -// } -// -// PARAMS: -// -// StringPiece src -// The source to be escaped or unescaped. -// -// strings::CharSet& delims -// A strings::CharSet of characters to be considered escaped or -// unescaped by the operation. -// -// NOTE: Please use the explicit strings::CharSet(StringPiece) -// constructor, as in: -// -// strings::BackslashEscape(src, strings::CharSet(":,&\\"), &dest); -// -// string* dest -// Destination string Appended to by strings::BackslashEscape and -// strings::BackslashUnescape. -// -// DESCRIPTION: -// -// void BackslashEscape(StringPiece src, const strings::CharSet& delims, -// string* dest); -// -// Replace any instance of a member 'c' of the strings::CharSet with -// { '\\', c }. -// For example, when exporting maps to /varz, label values need to -// have all dots escaped. Appends the result to dest. -// -// void BackslashUnescape(StringPiece src, const strings::CharSet& delims, -// string* dest); -// -// For all member characters 'c' in the specified 'delims', -// replace any appearance of the 2-character sequence { '\\', c } in -// the specified 'src' with just { c }. -// Does not unescape backslashes unless '\\' is a member of 'delims'. -// Appends the result to the specified 'dest'. -// -// stringpiece_ssize_type BackslashUnescapedFind( -// StringPiece src, -// const strings::CharSet& delims); -// -// Return the position in src of the first unescaped instance of any of -// the indicated characters, or StringPiece::npos (converted to a -// stringpiece_ssize_type) if no unescaped members of 'delims' are found. -// -// NOTE: -// -// These functions do not escape or unescape backslash '\' by default. -// -// strings::BackslashUnescapedFind always ignores escaped backslashes -// (this is true whether 'delims' contains backslash or not). -// -// For all strings, strings::BackslashUnescape is the exact inverse of -// the strings::BackslashEscape with the matching 'delims' argument. -// That is, for any StringPiece 'str' and any strings::CharSet 'delims': -// -// string RoundTrip(StringPiece src, const strings::CharSet& delims) { -// string encoded = strings::BackslashEscape(src, delims); -// return strings::BackslashUnescape(encoded, delims); -// } -// -// ASSERT_EQ(src, RoundTrip(str, delims)); // always true -// -// Note that this is true whether 'delims' contains backslash or not. -// -// BackslashUnescapedFind can be used to find the end of a string encoded -// with BackslashEscape, with certain restrictions: for any strings -// 'prefix' and 'suffix', any character set 'delims' that contains -// backslash, and any delimiter 'd' from 'delims' other than backslash: -// -// string encoded = -// StrCat(strings::BackslashEscape(prefix, delims), d, suffix); -// size_t end = strings::BackslashUnescapedFind(encoded, delims); -// string decoded = strings::BackslashUnescape( -// encoded.substr(0,end), delims); -// -// ASSERT_EQ(prefix, decoded); -// -// EXAMPLES: -// -// Example 1: -// Join arbitrary string fields with ':'. -// Any ':' and '\\' occurring in any of the fields will be escaped. -// Backslashes have to be escaped to prevent backslashes in the input from -// changing the output. -// -// vector fields = ...; -// const strings::CharSet kDelims = ":\\"; -// string encoded; -// const char* sep = ""; -// for (int i = 0; i < fields.size(); ++i) { -// const string& field = fields[i]; -// StrAppend(&encoded, sep); -// strings::BackslashEscape(field, kDelims, &encoded); -// sep = ":"; -// } -// -// Example 2: -// Find the field boundaries in such an encoded string. -// -// StringPiece encoded_sp = ...; // from example 1 -// const strings::CharSet kDelims = ":\\"; -// vector fields; -// while (!encoded_sp.empty()) { -// stringpiece_ssize_type pos = -// strings::BackslashUnescapedFind(encoded_sp, kDelims); -// if (pos == StringPiece::npos) { -// pos = encoded_sp.size(); -// } -// fields.push_back(encoded_sp.substr(0, pos)); -// if (pos < encoded_sp.size()) { -// ++pos; -// } -// encoded_sp.remove_prefix(pos); -// } -// -// Example 3: -// Unescape the fields identified in Example 2. -// -// vector encoded_fields = ...; // from example 2 -// const strings::CharSet kDelims = ":\\"; -// vector decoded_fields; -// for (int i = 0; i < encoded_fields.size(); ++i) { -// StringPiece enc = encoded_fields[i]; -// string f; -// strings::BackslashUnescape(enc, kDelims, &f); -// decoded_fields.push_back(f); -// } -// -// ---------------------------------------------------------------------- -void BackslashEscape(StringPiece src, const CharSet& delims, string* dest); -void BackslashUnescape(StringPiece src, const CharSet& delims, string* dest); -stringpiece_ssize_type BackslashUnescapedFind(StringPiece src, - const CharSet& delims); - -// Convenience overload of BackslashEscape that returns a string value. -inline string BackslashEscape(StringPiece src, const CharSet& delims) { - string s; - BackslashEscape(src, delims, &s); - return s; -} - -// Convenience overload of BackslashUnescape that returns a string value. -inline string BackslashUnescape(StringPiece src, const CharSet& delims) { - string s; - BackslashUnescape(src, delims, &s); - return s; -} - - -// ---------------------------------------------------------------------- -// QuotedPrintableUnescape() -// Check out http://tools.ietf.org/html/rfc2045 for more details, -// only briefly implemented. But from the web... -// Quoted-printable is an encoding method defined in the MIME -// standard. It is used primarily to encode 8-bit text (such as text -// that includes foreign characters) into 7-bit US ASCII, creating a -// document that is mostly readable by humans, even in its encoded -// form. All MIME compliant applications can decode quoted-printable -// text, though they may not necessarily be able to properly display the -// document as it was originally intended. As quoted-printable encoding -// is implemented most commonly, printable ASCII characters (values 33 -// through 126, excluding 61), tabs and spaces that do not appear at the -// end of lines, and end-of-line characters are not encoded. Other -// characters are represented by an equal sign (=) immediately followed -// by that character's hexadecimal value. Lines that are longer than 76 -// characters are shortened by line breaks, with the equal sign marking -// where the breaks occurred. If "src" contains any embedded null characters, -// processing will stop when the null character is encountered. -// -// Note that QuotedPrintableUnescape is different from 'Q'-encoding as -// defined in rfc2047. In particular, This does not treat '_'s as spaces. -// -// See QEncodingUnescape(). -// -// Rewrites quoted printable escape sequences =XX in src to their -// single-byte equivalents and returns the rewritten string. -// ---------------------------------------------------------------------- -string QuotedPrintableUnescape(StringPiece src); - -// ---------------------------------------------------------------------- -// QEncodingUnescape() -// This is very similar to QuotedPrintableUnescape except that we convert -// '_'s into spaces. See http://tools.ietf.org/html/rfc2047 -// -// Rewrites q-encoding escape sequences =XX in src to their single-byte -// equivalents and returns the rewritten string. If "src" contains any -// embedded null characters, processing will stop when the null character -// is encountered. -// ---------------------------------------------------------------------- -string QEncodingUnescape(StringPiece src); - -// ---------------------------------------------------------------------- -// Base64Unescape() -// Converts "src" which is encoded in Base64 to its binary equivalent and -// writes it to "dest". If src contains invalid characters, dest is cleared -// and the function returns false. Returns true on success. -// ---------------------------------------------------------------------- -bool Base64Unescape(StringPiece src, string* dest); - -// ---------------------------------------------------------------------- -// WebSafeBase64Unescape() -// This is a variation of Base64Unescape which uses '-' instead of '+', and -// '_' instead of '/'. src is not null terminated, instead specify len. I -// recommend that slen= 0) && (i <= 15)); - return ((i < 10) ? (i + '0') : ((i - 10) + 'A')); -} - -inline int int_to_lower_hex_digit(int i) { - DCHECK((i >= 0) && (i <= 15)); - return (i < 10) ? (i + '0') : ((i - 10) + 'a'); -} - -inline int hex_digit_to_int(char c) { - /* Assume ASCII. */ - DCHECK('0' == 0x30 && 'A' == 0x41 && 'a' == 0x61); - DCHECK(ascii_isxdigit(c)); - int x = static_cast(c); - if (x > '9') { - x += 9; - } - return x & 0xf; -} - -// ---------------------------------------------------------------------- -// a2b_hex() -// Description: Ascii-to-Binary hex conversion. This converts -// 2*'num' hexadecimal characters to 'num' binary data. -// Return value: 'num' bytes of binary data (via the 'to' argument) -// ---------------------------------------------------------------------- -void a2b_hex(const char* from, unsigned char* to, int num); -void a2b_hex(const char* from, char* to, int num); -void a2b_hex(const char* from, string* to, int num); -string a2b_hex(StringPiece a); - -// ---------------------------------------------------------------------- -// a2b_bin() -// Description: Ascii-to-Binary binary conversion. This converts -// a.size() binary characters (ascii '0' or '1') to -// ceil(a.size()/8) bytes of binary data. The first character is -// considered the most significant if byte_order_msb is set. a is -// considered to be padded with trailing 0s if its size is not a -// multiple of 8. -// Return value: ceil(a.size()/8) bytes of binary data -// ---------------------------------------------------------------------- -string a2b_bin(const string& a, bool byte_order_msb); - -// ---------------------------------------------------------------------- -// b2a_hex() -// Description: Binary-to-Ascii hex conversion. This converts -// 'num' bytes of binary to a 2*'num'-character hexadecimal representation -// Return value: 2*'num' characters of ascii text (via the 'to' argument) -// ---------------------------------------------------------------------- -void b2a_hex(const unsigned char* from, char* to, int num); -void b2a_hex(const unsigned char* from, string* to, int num); - -// ---------------------------------------------------------------------- -// b2a_hex() -// Description: Binary-to-Ascii hex conversion. This converts -// 'num' bytes of binary to a 2*'num'-character hexadecimal representation -// Return value: 2*'num' characters of ascii string -// ---------------------------------------------------------------------- -string b2a_hex(const char* from, int num); -string b2a_hex(StringPiece b); - -// ---------------------------------------------------------------------- -// b2a_bin() -// Description: Binary-to-Ascii binary conversion. This converts -// b.size() bytes of binary to a 8*b.size() character representation -// (ascii '0' or '1'). The highest order bit in each byte is returned -// first in the string if byte_order_msb is set. -// Return value: 8*b.size() characters of ascii text -// ---------------------------------------------------------------------- -string b2a_bin(const string& b, bool byte_order_msb); - -// ---------------------------------------------------------------------- -// ShellEscape -// Make a shell command argument from a string. -// Returns a Bourne shell string literal such that, once the shell finishes -// expanding the argument, the argument passed on to the program being -// run will be the same as whatever you passed in. -// NOTE: This is "ported" from python2.2's commands.mkarg(); it should be -// safe for Bourne shell syntax (i.e. sh, bash), but mileage may vary -// with other shells. -// ---------------------------------------------------------------------- -string ShellEscape(StringPiece src); - -// Runs ShellEscape() on the arguments, concatenates them with a space, and -// returns the resulting string. -template -string ShellEscapeCommandLine(InputIterator begin, const InputIterator& end) { - string result; - for (; begin != end; ++begin) { - if (!result.empty()) result.append(" "); - result.append(ShellEscape(*begin)); - } - return result; -} - -// Reads at most bytes_to_read from binary_string and writes it to -// ascii_string in lower case hex. -void ByteStringToAscii(const string& binary_string, int bytes_to_read, - string* ascii_string); - -inline string ByteStringToAscii(const string& binary_string, - int bytes_to_read) { - string result; - ByteStringToAscii(binary_string, bytes_to_read, &result); - return result; -} - -// Converts the hex from ascii_string into binary data and -// writes the binary data into binary_string. -// Empty input successfully converts to empty output. -// Returns false and may modify output if it is -// unable to parse the hex string. -bool ByteStringFromAscii(const string& ascii_string, string* binary_string); - -// Clean up a multi-line string to conform to Unix line endings. -// Reads from src and appends to dst, so usually dst should be empty. -// If there is no line ending at the end of a non-empty string, it can -// be added automatically. -// -// Four different types of input are correctly handled: -// -// - Unix/Linux files: line ending is LF, pass through unchanged -// -// - DOS/Windows files: line ending is CRLF: convert to LF -// -// - Legacy Mac files: line ending is CR: convert to LF -// -// - Garbled files: random line endings, covert gracefully -// lonely CR, lonely LF, CRLF: convert to LF -// -// @param src The multi-line string to convert -// @param dst The converted string is appended to this string -// @param auto_end_last_line Automatically terminate the last line -// -// Limitations: -// -// This does not do the right thing for CRCRLF files created by -// broken programs that do another Unix->DOS conversion on files -// that are already in CRLF format. -void CleanStringLineEndings(const string& src, string* dst, - bool auto_end_last_line); - -// Same as above, but transforms the argument in place. -void CleanStringLineEndings(string* str, bool auto_end_last_line); - -} // namespace strings - -#endif // STRINGS_ESCAPING_H_ \ No newline at end of file diff --git a/src/strings/fastmem.h b/src/strings/fastmem.h index 16721559..17dc1363 100644 --- a/src/strings/fastmem.h +++ b/src/strings/fastmem.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // Fast memory copying and comparison routines. // strings::fastmemcmp_inlined() replaces memcmp() @@ -47,8 +48,9 @@ namespace strings { // The performance is similar to the performance of memcmp(), but faster for // moderately-sized inputs, or inputs that share a common prefix and differ // somewhere in their last 8 bytes. Further optimizations can be added later -// if it makes sense to do so. Please keep this in sync with -// google_internal::gg_memeq() in //third_party/stl/gcc3/string. +// if it makes sense to do so. Alternatively, if the compiler & runtime improve +// to eliminate the need for this, we can remove it. Please keep this in sync +// with google_internal::gg_memeq() in //third_party/stl/gcc3/string. inline bool memeq(const char* a, const char* b, size_t n) { size_t n_rounded_down = n & ~static_cast(7); if (PREDICT_FALSE(n_rounded_down == 0)) { // n <= 7 @@ -66,9 +68,10 @@ inline bool memeq(const char* a, const char* b, size_t n) { // In 2013 or later, this should be fast on long strings. return memcmp(a, b, n) == 0; } - // Now force n to be a multiple of 16. At worst, this causes a re-compare - // of 8 bytes at the start of a and b. That's minor, and is outweighed by the - // simplification of the code that follows, because it can assume n % 16 is 0. + // Now force n to be a multiple of 16. Arguably, a "switch" would be smart + // here, but there's a difficult-to-evaluate code size vs. speed issue. The + // current approach often re-compares some bytes (worst case is if n initially + // was 16, 32, 48, or 64), but is fairly short. size_t e = n & 8; a += e; b += e; @@ -87,7 +90,7 @@ inline bool memeq(const char* a, const char* b, size_t n) { return true; } -inline int fastmemcmp_inlined(const void *va, const void *vb, size_t n) { +inline int fastmemcmp_inlined(const void* va, const void* vb, size_t n) { const unsigned char* pa = static_cast(va); const unsigned char* pb = static_cast(vb); switch (n) { @@ -136,7 +139,7 @@ inline int fastmemcmp_inlined(const void *va, const void *vb, size_t n) { // This implementation inlines the optimal realization for sizes 1 to 16. // To avoid code bloat don't use it in case of not performance-critical spots, // nor when you don't expect very frequent values of size <= 16. -inline void memcpy_inlined(char *dst, const char *src, size_t size) { +inline void memcpy_inlined(char* dst, const char* src, size_t size) { // Compiler inlines code with minimal amount of data movement when third // parameter of memcpy is a constant. switch (size) { @@ -162,4 +165,4 @@ inline void memcpy_inlined(char *dst, const char *src, size_t size) { } // namespace strings -#endif // STRINGS_FASTMEM_H_ \ No newline at end of file +#endif // STRINGS_FASTMEM_H_ diff --git a/src/strings/join.cc b/src/strings/join.cc deleted file mode 100644 index c146a46b..00000000 --- a/src/strings/join.cc +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2008 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#include "strings/join.h" - -#include -#include "base/scoped_ptr.h" -#include "strings/ascii_ctype.h" -#include "strings/escaping.h" - -using std::vector; - -void JoinCSVLineWithDelimiter(const vector& cols, char delimiter, - string* output) { - CHECK(output); - CHECK(output->empty()); - vector quoted_cols; - - const string delimiter_str(1, delimiter); - const string escape_chars = delimiter_str + "\""; - - // If the string contains the delimiter or " anywhere, or begins or ends with - // whitespace (ie ascii_isspace() returns true), escape all double-quotes and - // bracket the string in double quotes. string.rbegin() evaluates to the last - // character of the string. - for (int i = 0; i < cols.size(); ++i) { - if ((cols[i].find_first_of(escape_chars) != string::npos) || - (!cols[i].empty() && (ascii_isspace(*cols[i].begin()) || - ascii_isspace(*cols[i].rbegin())))) { - // Double the original size, for escaping, plus two bytes for - // the bracketing double-quotes, and one byte for the closing \0. - int size = 2 * cols[i].size() + 3; - scoped_ptr buf(new char[size]); - - // Leave space at beginning and end for bracketing double-quotes. - int escaped_size = strings::EscapeStrForCSV(cols[i].c_str(), - buf.get() + 1, size - 2); - CHECK_GE(escaped_size, 0) << "Buffer somehow wasn't large enough."; - CHECK_GE(size, escaped_size + 3) - << "Buffer should have one space at the beginning for a " - << "double-quote, one at the end for a double-quote, and " - << "one at the end for a closing '\0'"; - *buf.get() = '"'; - *((buf.get() + 1) + escaped_size) = '"'; - *((buf.get() + 1) + escaped_size + 1) = '\0'; - quoted_cols.push_back(string(buf.get(), buf.get() + escaped_size + 2)); - } else { - quoted_cols.push_back(cols[i]); - } - } - *output = strings::Join(quoted_cols, delimiter_str); -} - -void JoinCSVLine(const vector& cols, string* output) { - JoinCSVLineWithDelimiter(cols, ',', output); -} - -string JoinCSVLine(const vector& cols) { - string output; - JoinCSVLine(cols, &output); - return output; -} \ No newline at end of file diff --git a/src/strings/join.h b/src/strings/join.h deleted file mode 100644 index 223c0926..00000000 --- a/src/strings/join.h +++ /dev/null @@ -1,325 +0,0 @@ -// Copyright 2008 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// -// #status: RECOMMENDED -// #category: operations on strings -// #summary: Functions for joining ranges of elements with an element separator. -// -#ifndef STRINGS_JOIN_H_ -#define STRINGS_JOIN_H_ - -#include -#include - -#include -using __gnu_cxx::hash; -using __gnu_cxx::hash_map; // Not used in this file. -#include -using __gnu_cxx::hash; -using __gnu_cxx::hash_set; // Not used in this file. -#include -#include -#include -#include -#include -#include - -#include "base/integral_types.h" -#include "base/macros.h" -#include "base/port.h" -#include "base/template_util.h" -#include "strings/join_internal.h" -#include "strings/numbers.h" -#include "strings/strcat.h" // For backward compatibility. -#include "strings/stringpiece.h" -#include "util/hash/hash.h" - -#ifdef LANG_CXX11 -#include // NOLINT(build/include_order) -#include // NOLINT(build/include_order) -#endif // LANG_CXX11 - -namespace strings { - -// strings::Join() -// -// The strings::Join() function joins the given range of elements, with each -// element separated by the given separator string, and returns the result as a -// string. Ranges may be specified by passing a container or array compatible -// with std::begin() and std::end(), a brace-initialized std::initializer_list, -// as individual begin and end iterators, or as a std::tuple of heterogeneous -// objects. The separator string is taken as a StringPiece, which means it can -// be specified as a string literal, C-string, C++ string, etc. By default, -// non-string elements are converted to strings using AlphaNum, which yields -// the same behavior as using StrCat(). This means that strings::Join() works -// out-of-the-box on collections of strings, ints, floats, doubles, etc. An -// optional final argument of a "Formatter" (details below) function object -// may be given. This object will be responsible for converting each -// argument in the Range to a string. -// -// Example 1: -// // Joins a collection of strings. This also works with a collection of -// // StringPiece or even const char*. -// vector v = util::gtl::Container("foo", "bar", "baz"); -// string s = strings::Join(v, "-"); -// EXPECT_EQ("foo-bar-baz", s); -// -// Example 2: -// // Joins the values in the given std::initializer_list<> specified using -// // brace initialization. This also works with an initializer_list of ints -// // or StringPiece--any AlphaNum-compatible type. -// string s = strings::Join({"foo", "bar", "baz"}, "-"); -// EXPECT_EQ("foo-bar-baz", s); -// -// Example 3: -// // Joins a collection of ints. This also works with floats, doubles, -// // int64s; any StrCat-compatible type. -// vector v = util::gtl::Container(1, 2, 3, -4); -// string s = strings::Join(v, "-"); -// EXPECT_EQ("1-2-3--4", s); -// -// Example 4: -// // Joins a collection of pointer-to-int. By default, pointers are -// // dereferenced and the pointee is formatted using the default format for -// // that type. The upshot of this is that all levels of inderection are -// // collapsed, so this works just as well for vector as -// // vector. -// int x = 1, y = 2, z = 3; -// vector v = util::gtl::Container(&x, &y, &z); -// string s = strings::Join(v, "-"); -// EXPECT_EQ("1-2-3", s); -// -// Example 5: -// // In C++11, dereferecing std::unique_ptr is also supported: -// vector> v -// v.emplace_back(new int(1)); -// v.emplace_back(new int(2)); -// v.emplace_back(new int(3)); -// string s = strings::Join(v, "-"); -// EXPECT_EQ("1-2-3", s); -// -// Example 6: -// // Joins a map, with each key-value pair separated by an equals sign. -// // This would also work with, say, a vector>. -// map m = util::gtl::Container( -// std::make_pair("a", 1), -// std::make_pair("b", 2), -// std::make_pair("c", 3)); -// string s = strings::Join(m, ",", strings::PairFormatter("=")); -// EXPECT_EQ("a=1,b=2,c=3", s); -// -// Example 7: -// // These examples show how strings::Join() handles a few common edge cases. -// vector v_empty; -// EXPECT_EQ("", strings::Join(v_empty, "-")); -// -// vector v_one_item = util::gtl::Container("foo"); -// EXPECT_EQ("foo", strings::Join(v_one_item, "-")); -// -// vector v_empty_string = util::gtl::Container(""); -// EXPECT_EQ("", strings::Join(v_empty_string, "-")); -// -// vector v_one_item_empty_string = util::gtl::Container("a", ""); -// EXPECT_EQ("a-", strings::Join(v_one_item_empty_string, "-")); -// -// vector v_two_empty_string = util::gtl::Container("", ""); -// EXPECT_EQ("-", strings::Join(v_two_empty_string, "-")); -// -// Example 8: -// // Join a std::tuple. -// string s = strings::Join(std::make_tuple(123, "abc", 0.456), "-"); -// EXPECT_EQ("123-abc-0.456", s); -// - -// -// Formatters -// -// A Formatter is a function object that is responsible for formatting its -// argument as a string and appending it to the given output string. Formatters -// are an extensible part of the Join2 API: They allow callers to provide their -// own conversion function to enable strings::Join() work with arbitrary types. -// -// The following is an example Formatter that simply uses StrAppend to format an -// integer as a string. -// -// struct MyFormatter { -// void operator()(string* out, int i) const { -// StrAppend(out, i); -// } -// }; -// -// You would use the above formatter by passing an instance of it as the final -// argument to strings::Join(): -// -// vector v = util::gtl::Container(1, 2, 3, 4); -// string s = strings::Join(v, "-", MyFormatter()); -// EXPECT_EQ("1-2-3-4", s); -// -// The following standard formatters are provided with the Join2 API. -// -// - AlphaNumFormatter (the default) -// - PairFormatter -// - DereferenceFormatter -// - -// AlphaNumFormatter() -// -// Default formatter used if none is specified. Uses AlphaNum to convert numeric -// arguments to strings. -inline internal::AlphaNumFormatterImpl AlphaNumFormatter() { - return internal::AlphaNumFormatterImpl(); -} - -// PairFormatter() -// -// Formats a std::pair by putting the given separator between the pair's .first -// and .second members. The separator argument is required. By default, the -// first and second members are themselves formatted using AlphaNumFormatter(), -// but the caller may specify other formatters to use for the members. -template -inline internal::PairFormatterImpl -PairFormatter(FirstFormatter f1, StringPiece sep, SecondFormatter f2) { - return internal::PairFormatterImpl( - f1, sep, f2); -} -inline internal::PairFormatterImpl< - internal::AlphaNumFormatterImpl, - internal::AlphaNumFormatterImpl> -PairFormatter(StringPiece sep) { - return PairFormatter(AlphaNumFormatter(), sep, AlphaNumFormatter()); -} - -// DereferenceFormatter() -// -// Dereferences its argument then formats it using AlphaNumFormatter (by -// default), or the given formatter if one is explicitly given. This is useful -// for formatting a container of pointer-to-T. This pattern often shows up when -// joining repeated fields in protocol buffers. -template -internal::DereferenceFormatterImpl -DereferenceFormatter(Formatter f) { - return internal::DereferenceFormatterImpl(f); -} -inline internal::DereferenceFormatterImpl -DereferenceFormatter() { - return internal::DereferenceFormatterImpl( - AlphaNumFormatter()); -} - -// -// strings::Join() overloads -// - -template -string Join(Iterator start, Iterator end, StringPiece sep, Formatter fmt) { - return internal::JoinAlgorithm(start, end, sep, fmt); -} - -template -string Join(const Range& range, StringPiece separator, Formatter fmt) { - return internal::JoinRange(range, separator, fmt); -} - -#ifdef LANG_CXX11 -template -string Join(std::initializer_list il, StringPiece separator, Formatter fmt) { - return internal::JoinRange(il, separator, fmt); -} - -template -string Join(const std::tuple& value, StringPiece separator, - Formatter fmt) { - return internal::JoinAlgorithm(value, separator, fmt); -} -#endif // LANG_CXX11 - -template -string Join(Iterator start, Iterator end, StringPiece separator) { - return internal::JoinRange(start, end, separator); -} - -template -string Join(const Range& range, StringPiece separator) { - return internal::JoinRange(range, separator); -} - -#ifdef LANG_CXX11 -template -string Join(std::initializer_list il, StringPiece separator) { - return internal::JoinRange(il, separator); -} - -template -string Join(const std::tuple& value, StringPiece separator) { - return internal::JoinAlgorithm(value, separator, AlphaNumFormatter()); -} -#endif // LANG_CXX11 - -} // namespace strings - -// ---------------------------------------------------------------------- -// LEGACY(jgm): Utilities provided in util/csv/writer.h are now preferred for -// -// Example for CSV formatting a single record (a sequence container of string, -// char*, or StringPiece values) using the util::csv::WriteRecordToString helper -// function: -// std::vector record = ...; -// string line = util::csv::WriteRecordToString(record); -// -// NOTE: When writing many records, use the util::csv::Writer class directly. -// -// JoinCSVLineWithDelimiter() -// This function is the inverse of SplitCSVLineWithDelimiter() in that the -// string returned by JoinCSVLineWithDelimiter() can be passed to -// SplitCSVLineWithDelimiter() to get the original string vector back. -// Quotes and escapes the elements of original_cols according to CSV quoting -// rules, and the joins the escaped quoted strings with commas using -// JoinStrings(). Note that JoinCSVLineWithDelimiter() will not necessarily -// return the same string originally passed in to -// SplitCSVLineWithDelimiter(), since SplitCSVLineWithDelimiter() can handle -// gratuitous spacing and quoting. 'output' must point to an empty string. -// -// Example: -// [Google], [x], [Buchheit, Paul], [string with " quote in it], [ space ] -// ---> [Google,x,"Buchheit, Paul","string with "" quote in it"," space "] -// -// JoinCSVLine() -// A convenience wrapper around JoinCSVLineWithDelimiter which uses -// ',' as the delimiter. -// ---------------------------------------------------------------------- -void JoinCSVLine(const std::vector& original_cols, string* output); -string JoinCSVLine(const std::vector& original_cols); -void JoinCSVLineWithDelimiter(const std::vector& original_cols, - char delimiter, - string* output); - -template -GOOGLE_DEPRECATED("Use strings::Join()") -void JoinStrings(const CONTAINER& components, - StringPiece delim, - string* result) { - *result = strings::Join(components, delim); -} - -template -GOOGLE_DEPRECATED("Use strings::Join()") -void JoinStringsIterator(const ITERATOR& start, - const ITERATOR& end, - StringPiece delim, - string* result) { - *result = strings::Join(start, end, delim); -} - -#endif // STRINGS_JOIN_H_ \ No newline at end of file diff --git a/src/strings/join_internal.h b/src/strings/join_internal.h deleted file mode 100644 index 328483fe..00000000 --- a/src/strings/join_internal.h +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright 2015 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file declares INTERNAL parts of the Join API that are inlined/templated -// or otherwise need to be available at compile time. The main abstractions -// defined in this file are: -// -// - A handful of default Formatters -// - JoinAlgorithm() overloads -// - JoinRange() overloads -// - JoinTuple() -// -// DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including -// strings/join.h. -// -// IWYU pragma: private, include "strings/join.h" - -#ifndef STRINGS_JOIN_INTERNAL_H_ -#define STRINGS_JOIN_INTERNAL_H_ - -#include -#include - -#include "strings/strcat.h" - -#ifdef LANG_CXX11 -#include -#include -#endif - -namespace strings { -namespace internal { - -// -// Formatter objects -// -// The following are implementation classes for standard Formatter objects. The -// factory functions that users will call to create and use these formatters are -// defined and documented in strings/join.h. -// - -// The default formatter. Converts alpha-numeric types to strings. -struct AlphaNumFormatterImpl { - template - void operator()(string* out, const T& t) const { - AlphaNum(t).Piece().AppendToString(out); - } - - void operator()(string* out, const AlphaNum& t) const { - t.Piece().AppendToString(out); - } -}; - - -// A type that's used to overload the JoinAlgorithm() function (defined below) -// for ranges that do not require additional formatting (e.g., a range of -// strings). - -struct NoFormatter : public AlphaNumFormatterImpl {}; - -// Formats a std::pair<>. The 'first' member is formatted using f1_ and the -// 'second' member is formatted using f2_. sep_ is the separator. -template -class PairFormatterImpl { - public: - PairFormatterImpl(F1 f1, StringPiece sep, F2 f2) - : f1_(f1), sep_(sep.ToString()), f2_(f2) {} - - template - void operator()(string* out, const T& p) const { - f1_(out, p.first); - out->append(sep_); - f2_(out, p.second); - } - - private: - F1 f1_; - string sep_; - F2 f2_; -}; - -// Wraps another formatter and dereferences the argument to operator() then -// passes the dereferenced argument to the wrapped formatter. This can be -// useful, for example, to join a vector. -template -class DereferenceFormatterImpl { - public: - DereferenceFormatterImpl() : f_() {} - explicit DereferenceFormatterImpl(Formatter f) : f_(f) {} - - template - void operator()(string* out, const T& t) const { - f_(out, *t); - } - - private: - Formatter f_; -}; - -// DefaultFormatter is a traits class that selects a default Formatter to use -// for the given type T. The ::Type member names the Formatter to use. This is -// used by the strings::Join() functions that do NOT take a Formatter argument, -// in which case a default Formatter must be chosen. -// -// AlphaNumFormatterImpl is the default in the base template, followed by -// specializations for other types. -template -struct DefaultFormatter { - typedef AlphaNumFormatterImpl Type; -}; -template <> -struct DefaultFormatter { - typedef AlphaNumFormatterImpl Type; -}; -template <> -struct DefaultFormatter { - typedef AlphaNumFormatterImpl Type; -}; -template <> -struct DefaultFormatter { - typedef NoFormatter Type; -}; -template <> -struct DefaultFormatter { - typedef NoFormatter Type; -}; -template -struct DefaultFormatter { - typedef DereferenceFormatterImpl::Type> - Type; -}; - -#ifdef LANG_CXX11 -template -struct DefaultFormatter> - : public DefaultFormatter {}; -#endif - -// -// JoinAlgorithm() functions -// - -// The main joining algorithm. This simply joins the elements in the given -// iterator range, each separated by the given separator, into an output string, -// and formats each element using the provided Formatter object. -template -string JoinAlgorithm(Iterator start, Iterator end, StringPiece s, Formatter f) { - string result; - StringPiece sep(""); - for (Iterator it = start; it != end; ++it) { - result.append(sep.data(), sep.size()); - f(&result, *it); - sep = s; - } - return result; -} - -// No-op placeholder for input iterators which can not be iterated over. -template -size_t GetResultSize(Iterator, Iterator, size_t, std::input_iterator_tag) { - return 0; -} - -// Calculates space to reserve, if the iterator supports multiple passes. -template -size_t GetResultSize(Iterator start, Iterator end, size_t s_size, - std::forward_iterator_tag) { - size_t length = 0, num_elements = 0; - for (Iterator it = start; it != end; ++it) { - length += it->size(); - ++num_elements; - } - // Adds the size of all the separators - return length + s_size * (num_elements - 1); -} - -// A joining algorithm that's optimized for an iterator range of string-like -// objects that do not need any additional formatting. This is to optimize the -// common case of joining, say, a vector or a vector. -// -// This is an overload of the previous JoinAlgorithm() function. Here the -// Formatter argument is of type NoFormatter. Since NoFormatter is an internal -// type, this overload is only invoked when strings::Join() is called with a -// range of string-like objects (e.g., string, StringPiece), and an explicit -// Formatter argument was NOT specified. -// -// The optimization is that the needed space will be reserved in the output -// string to avoid the need to resize while appending. To do this, the iterator -// range will be traversed twice: once to calculate the total needed size, and -// then again to copy the elements and delimiters to the output string. -template -string JoinAlgorithm(Iterator start, Iterator end, StringPiece s, NoFormatter) { - string result; - if (start != end) { - typename std::iterator_traits::iterator_category iterator_tag; - result.reserve(GetResultSize(start, end, s.size(), iterator_tag)); - - // Joins strings - StringPiece sep("", 0); - for (Iterator it = start; it != end; ++it) { - result.append(sep.data(), sep.size()); - result.append(it->data(), it->size()); - sep = s; - } - } - - return result; -} - -#ifdef LANG_CXX11 -// JoinTupleLoop implements a loop over the elements of a std::tuple, which -// are heterogeneous. The primary template matches the tuple interior case. It -// continues the iteration after appending a separator (for nonzero indices) -// and formatting an element of the tuple. The specialization for the I=N case -// matches the end-of-tuple, and terminates the iteration. -template -struct JoinTupleLoop { - void operator()(string* out, const Tup& tup, StringPiece sep, - Formatter fmt) const { - if (I > 0) out->append(sep.data(), sep.size()); - fmt(out, std::get(tup)); - JoinTupleLoop()(out, tup, sep, fmt); - } -}; -template -struct JoinTupleLoop { - void operator()(string* out, const Tup& tup, StringPiece sep, - Formatter fmt) const {} -}; - -template -string JoinAlgorithm(const std::tuple& tup, StringPiece sep, - Formatter fmt) { - typedef typename std::tuple Tup; - const size_t kTupSize = std::tuple_size::value; - string result; - JoinTupleLoop()(&result, tup, sep, fmt); - return result; -} -#endif // LANG_CXX11 - -template -string JoinRange(Iterator first, Iterator last, StringPiece separator) { - // No formatter was explicitly given, so a default must be chosen. - typedef typename std::iterator_traits::value_type ValueType; - typedef typename DefaultFormatter::Type Formatter; - return JoinAlgorithm(first, last, separator, Formatter()); -} - -// In C++11, use std::begin(c) and std::end(c). -// Pre-11, fall back to member functions c.begin() and c.end(). -#ifdef LANG_CXX11 -#define STRINGS_JOIN_RANGE_BEGIN(c) std::begin(c) -#define STRINGS_JOIN_RANGE_END(c) std::end(c) -#else -#define STRINGS_JOIN_RANGE_BEGIN(c) c.begin() -#define STRINGS_JOIN_RANGE_END(c) c.end() -#endif - -template -string JoinRange(const Range& range, StringPiece separator, Formatter fmt) { - return JoinAlgorithm(STRINGS_JOIN_RANGE_BEGIN(range), - STRINGS_JOIN_RANGE_END(range), - separator, fmt); -} - -template -string JoinRange(const Range& range, StringPiece separator) { - return JoinRange(STRINGS_JOIN_RANGE_BEGIN(range), - STRINGS_JOIN_RANGE_END(range), - separator); -} - -#undef STRINGS_JOIN_RANGE_BEGIN -#undef STRINGS_JOIN_RANGE_END - -} // namespace internal -} // namespace strings - -#endif // STRINGS_JOIN_INTERNAL_H_ \ No newline at end of file diff --git a/src/strings/memutil.cc b/src/strings/memutil.cc index 38640073..153b4f9c 100644 --- a/src/strings/memutil.cc +++ b/src/strings/memutil.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // @@ -21,86 +22,81 @@ #include "strings/ascii_ctype.h" // for ascii_tolower -int memcasecmp(const char *s1, const char *s2, size_t len) { - const unsigned char *us1 = reinterpret_cast(s1); - const unsigned char *us2 = reinterpret_cast(s2); +int memcasecmp(const char* s1, const char* s2, size_t len) { + const unsigned char* us1 = reinterpret_cast(s1); + const unsigned char* us2 = reinterpret_cast(s2); - for ( int i = 0; i < len; i++ ) { + for (int i = 0; i < len; i++) { const int diff = - static_cast(static_cast(ascii_tolower(us1[i]))) - - static_cast(static_cast(ascii_tolower(us2[i]))); + static_cast(static_cast(ascii_tolower(us1[i]))) - + static_cast(static_cast(ascii_tolower(us2[i]))); if (diff != 0) return diff; } return 0; } -char *memdup(const char *s, size_t slen) { - void *copy; - if ( (copy=malloc(slen)) == NULL ) - return NULL; +char* memdup(const char* s, size_t slen) { + void* copy; + if ((copy = malloc(slen)) == NULL) return NULL; memcpy(copy, s, slen); return reinterpret_cast(copy); } -char *memrchr(const char *s, int c, size_t slen) { - for (const char* e = s + slen-1; e >= s; e--) { - if (*e == c) - return const_cast(e); +char* memrchr(const char* s, int c, size_t slen) { + for (const char* e = s + slen - 1; e >= s; e--) { + if (*e == c) return const_cast(e); } return NULL; } -size_t memspn(const char *s, size_t slen, const char *accept) { - const char *p = s, *spanp; +size_t memspn(const char* s, size_t slen, const char* accept) { + const char* p = s; + const char* spanp; char c, sc; - cont: +cont: c = *p++; - if ( slen-- == 0 ) - return p-1 - s; - for (spanp = accept; (sc=*spanp++) != '\0';) - if (sc == c) - goto cont; - return p-1 - s; + if (slen-- == 0) return p - 1 - s; + for (spanp = accept; (sc = *spanp++) != '\0';) + if (sc == c) goto cont; + return p - 1 - s; } - -size_t memcspn(const char *s, size_t slen, const char *reject) { - const char *p = s, *spanp; +size_t memcspn(const char* s, size_t slen, const char* reject) { + const char* p = s; + const char* spanp; char c, sc; - while ( slen-- != 0 ) { + while (slen-- != 0) { c = *p++; - for (spanp = reject; (sc=*spanp++) != '\0';) - if (sc == c) - return p-1 - s; + for (spanp = reject; (sc = *spanp++) != '\0';) + if (sc == c) return p - 1 - s; } return p - s; } -char *mempbrk(const char *s, size_t slen, const char *accept) { - const char *scanp; +char* mempbrk(const char* s, size_t slen, const char* accept) { + const char* scanp; int sc; - for ( ; slen; ++s, --slen ) { - for (scanp = accept; (sc=*scanp++) != '\0';) - if (sc == *s) - return const_cast(s); + for (; slen; ++s, --slen) { + for (scanp = accept; (sc = *scanp++) != '\0';) + if (sc == *s) return const_cast(s); } return NULL; } -template -const char *int_memmatch(const char *phaystack, size_t haylen, - const char *pneedle, size_t neelen) { +template +const char* int_memmatch(const char* phaystack, size_t haylen, + const char* pneedle, size_t neelen) { if (0 == neelen) { return phaystack; // even if haylen is 0 } - const unsigned char *haystack = (const unsigned char *) phaystack; - const unsigned char *hayend = (const unsigned char *) phaystack + haylen; - const unsigned char *needlestart = (const unsigned char *) pneedle; - const unsigned char *needle = (const unsigned char *) pneedle; - const unsigned char *needleend = (const unsigned char *) pneedle + neelen; + const unsigned char* haystack = (const unsigned char*)phaystack; + const unsigned char* hayend = (const unsigned char*)phaystack + haylen; + const unsigned char* needlestart = (const unsigned char*)pneedle; + const unsigned char* needle = (const unsigned char*)pneedle; + const unsigned char* needleend = (const unsigned char*)pneedle + neelen; for (; haystack < hayend; ++haystack) { unsigned char hay = case_sensitive ? *haystack : @@ -109,7 +105,7 @@ const char *int_memmatch(const char *phaystack, size_t haylen, static_cast(ascii_tolower(*needle)); if (hay == nee) { if (++needle == needleend) { - return (const char *) (haystack + 1 - neelen); + return (const char *)(haystack + 1 - neelen); } } else if (needle != needlestart) { // must back up haystack in case a prefix matched (find "aab" in "aaab") @@ -121,20 +117,19 @@ const char *int_memmatch(const char *phaystack, size_t haylen, } // explicit template instantiations -template const char *int_memmatch(const char *phaystack, size_t haylen, - const char *pneedle, size_t neelen); -template const char *int_memmatch(const char *phaystack, size_t haylen, - const char *pneedle, size_t neelen); +template const char* int_memmatch(const char* phaystack, size_t haylen, + const char* pneedle, size_t neelen); +template const char* int_memmatch(const char* phaystack, size_t haylen, + const char* pneedle, size_t neelen); // This is significantly faster for case-sensitive matches with very // few possible matches. See unit test for benchmarks. -const char *memmatch(const char *phaystack, size_t haylen, - const char *pneedle, size_t neelen) { +const char* memmatch(const char* phaystack, size_t haylen, + const char* pneedle, size_t neelen) { if (0 == neelen) { return phaystack; // even if haylen is 0 } - if (haylen < neelen) - return NULL; + if (haylen < neelen) return NULL; const char* match; const char* hayend = phaystack + haylen - neelen + 1; @@ -148,4 +143,4 @@ const char *memmatch(const char *phaystack, size_t haylen, phaystack = match + 1; } return NULL; -} \ No newline at end of file +} diff --git a/src/strings/memutil.h b/src/strings/memutil.h index 8695eb91..58dca151 100644 --- a/src/strings/memutil.h +++ b/src/strings/memutil.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // // These routines provide mem versions of standard C string routines, @@ -67,51 +68,51 @@ #include "base/port.h" // disable some warnings on Windows -inline char *memcat(char *dest, size_t destlen, - const char *src, size_t srclen) { +inline char* memcat(char* dest, size_t destlen, + const char* src, size_t srclen) { return reinterpret_cast(memcpy(dest + destlen, src, srclen)); } -int memcasecmp(const char *s1, const char *s2, size_t len); -char *memdup(const char *s, size_t slen); -char *memrchr(const char *s, int c, size_t slen); -size_t memspn(const char *s, size_t slen, const char *accept); -size_t memcspn(const char *s, size_t slen, const char *reject); -char *mempbrk(const char *s, size_t slen, const char *accept); +int memcasecmp(const char* s1, const char* s2, size_t len); +char* memdup(const char* s, size_t slen); +char* memrchr(const char* s, int c, size_t slen); +size_t memspn(const char* s, size_t slen, const char* accept); +size_t memcspn(const char* s, size_t slen, const char* reject); +char* mempbrk(const char* s, size_t slen, const char* accept); // This is for internal use only. Don't call this directly -template -const char * int_memmatch(const char * phaystack, size_t haylen, - const char * pneedle, size_t neelen); +template +const char* int_memmatch(const char* phaystack, size_t haylen, + const char* pneedle, size_t neelen); // These are the guys you can call directly -inline const char * memstr(const char *phaystack, size_t haylen, - const char *pneedle) { +inline const char* memstr(const char* phaystack, size_t haylen, + const char* pneedle) { return int_memmatch(phaystack, haylen, pneedle, strlen(pneedle)); } -inline const char * memcasestr(const char *phaystack, size_t haylen, - const char *pneedle) { +inline const char* memcasestr(const char* phaystack, size_t haylen, + const char* pneedle) { return int_memmatch(phaystack, haylen, pneedle, strlen(pneedle)); } -inline const char * memmem(const char *phaystack, size_t haylen, - const char *pneedle, size_t needlelen) { +inline const char* memmem(const char* phaystack, size_t haylen, + const char* pneedle, size_t needlelen) { return int_memmatch(phaystack, haylen, pneedle, needlelen); } -inline const char * memcasemem(const char *phaystack, size_t haylen, - const char *pneedle, size_t needlelen) { +inline const char* memcasemem(const char* phaystack, size_t haylen, + const char* pneedle, size_t needlelen) { return int_memmatch(phaystack, haylen, pneedle, needlelen); } // This is significantly faster for case-sensitive matches with very // few possible matches. See unit test for benchmarks. -const char *memmatch(const char *phaystack, size_t haylen, - const char *pneedle, size_t neelen); +const char* memmatch(const char* phaystack, size_t haylen, + const char* pneedle, size_t neelen); // The ""'s catch people who don't pass in a literal for "str" -#define strliterallen(str) (sizeof("" str "")-1) +#define strliterallen(str) (sizeof("" str "") - 1) // Must use a string literal for prefix. #define memprefix(str, len, prefix) \ @@ -149,4 +150,4 @@ const char *memmatch(const char *phaystack, size_t haylen, ( (((len) == strliterallen(literal)) \ && memcasecmp(str, literal, strliterallen(literal)) == 0) ) -#endif // STRINGS_MEMUTIL_H_ \ No newline at end of file +#endif // STRINGS_MEMUTIL_H_ diff --git a/src/strings/numbers.cc b/src/strings/numbers.cc index b454afca..4626648c 100644 --- a/src/strings/numbers.cc +++ b/src/strings/numbers.cc @@ -1,4 +1,4 @@ -// Copyright 2010 Google Inc. All Rights Reserved. +// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,1070 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// Author: jyrki@google.com (Jyrki Alakuijala) -// Refactored from contributions of various authors in strings/strutil.cc -// -// This file contains string processing functions related to -// numeric values. #include "strings/numbers.h" -#include -#include -#include -#include // for DBL_DIG and FLT_DIG -#include // for HUGE_VAL -#include -#include -#include -#include -#include - -#include "base/int128.h" -#include "base/integral_types.h" -#include -#include "base/scoped_ptr.h" -#include "base/stringprintf.h" #include "base/strtoint.h" #include "strings/ascii_ctype.h" -#include "strings/case.h" -#include "strings/strcat.h" -#include "strings/stringpiece_utils.h" - -// Reads a in *text, which may not be whitespace-initiated. -// *len is the length, or -1 if text is '\0'-terminated, which is more -// efficient. Sets *text to the end of the double, and val to the -// converted value, and the length of the double is subtracted from -// *len. may also be a '?', in which case val will be -// unchanged. Returns true upon success. If initial_minus is -// non-NULL, then *initial_minus will indicate whether the first -// symbol seen was a '-', which will be ignored. Similarly, if -// final_period is non-NULL, then *final_period will indicate whether -// the last symbol seen was a '.', which will be ignored. This is -// useful in case that an initial '-' or final '.' would have another -// meaning (as a separator, e.g.). -static inline bool EatADouble(const char** text, int* len, bool allow_question, - double* val, bool* initial_minus, - bool* final_period) { - const char* pos = *text; - int rem = *len; // remaining length, or -1 if null-terminated - - if (pos == NULL || rem == 0) - return false; - - if (allow_question && (*pos == '?')) { - *text = pos + 1; - if (rem != -1) - *len = rem - 1; - return true; - } - - if (initial_minus) { - if ((*initial_minus = (*pos == '-'))) { // Yes, we want assignment. - if (rem == 1) - return false; - ++pos; - if (rem != -1) - --rem; - } - } - - // a double has to begin one of these (we don't allow 'inf' or whitespace) - // this also serves as an optimization. - if (!strchr("-+.0123456789", *pos)) - return false; - - // strtod is evil in that the second param is a non-const char** - char* end_nonconst; - double retval; - if (rem == -1) { - retval = strtod(pos, &end_nonconst); - } else { - // not '\0'-terminated & no obvious terminator found. must copy. - scoped_ptr buf(new char[rem + 1]); - memcpy(buf.get(), pos, rem); - buf[rem] = '\0'; - retval = strtod(buf.get(), &end_nonconst); - end_nonconst = const_cast(pos) + (end_nonconst - buf.get()); - } - - if (pos == end_nonconst) - return false; - - if (final_period) { - *final_period = (end_nonconst[-1] == '.'); - if (*final_period) { - --end_nonconst; - } - } - - *text = end_nonconst; - *val = retval; - if (rem != -1) - *len = rem - (end_nonconst - pos); - return true; -} - -// If update, consume one of acceptable_chars from string *text of -// length len and return that char, or '\0' otherwise. If len is -1, -// *text is null-terminated. If update is false, don't alter *text and -// *len. If null_ok, then update must be false, and, if text has no -// more chars, then return '\1' (arbitrary nonzero). -static inline char EatAChar(const char** text, int* len, - const char* acceptable_chars, - bool update, bool null_ok) { - assert(!(update && null_ok)); - if ((*len == 0) || (**text == '\0')) - return (null_ok ? '\1' : '\0'); // if null_ok, we're in predicate mode. - - if (strchr(acceptable_chars, **text)) { - char result = **text; - if (update) { - ++(*text); - if (*len != -1) - --(*len); - } - return result; - } - - return '\0'; // no match; no update -} - -// Parse an expression in 'text' of the form: or -// See full comments in header file. -bool ParseDoubleRange(const char* text, int len, const char** end, - double* from, double* to, bool* is_currency, - const DoubleRangeOptions& opts) { - const double from_default = opts.dont_modify_unbounded ? *from : -HUGE_VAL; - - if (!opts.dont_modify_unbounded) { - *from = -HUGE_VAL; - *to = HUGE_VAL; - } - if (opts.allow_currency && (is_currency != NULL)) - *is_currency = false; - - assert(len >= -1); - assert(opts.separators && (*opts.separators != '\0')); - // these aren't valid separators - assert(strlen(opts.separators) == - strcspn(opts.separators, "+0123456789eE$")); - assert(opts.num_required_bounds <= 2); - - // Handle easier cases of comparators (<, >) first - if (opts.allow_comparators) { - char comparator = EatAChar(&text, &len, "<>", true, false); - if (comparator) { - double* dest = (comparator == '>') ? from : to; - EatAChar(&text, &len, "=", true, false); - if (opts.allow_currency && EatAChar(&text, &len, "$", true, false)) - if (is_currency != NULL) - *is_currency = true; - if (!EatADouble(&text, &len, opts.allow_unbounded_markers, dest, NULL, - NULL)) - return false; - *end = text; - return EatAChar(&text, &len, opts.acceptable_terminators, false, - opts.null_terminator_ok); - } - } - - bool seen_dollar = (opts.allow_currency && - EatAChar(&text, &len, "$", true, false)); - - // If we see a '-', two things could be happening: - or - // ... where is negative. Treat initial minus sign as a - // separator if '-' is a valid separator. - // Similarly, we prepare for the possibility of seeing a '.' at the - // end of the number, in case '.' (which really means '..') is a - // separator. - bool initial_minus_sign = false; - bool final_period = false; - bool* check_initial_minus = (strchr(opts.separators, '-') && !seen_dollar - && (opts.num_required_bounds < 2)) ? - (&initial_minus_sign) : NULL; - bool* check_final_period = strchr(opts.separators, '.') ? (&final_period) - : NULL; - bool double_seen = EatADouble(&text, &len, opts.allow_unbounded_markers, - from, check_initial_minus, check_final_period); - - // if 2 bounds required, must see a double (or '?' if allowed) - if ((opts.num_required_bounds == 2) && !double_seen) return false; - - if (seen_dollar && !double_seen) { - --text; - if (len != -1) - ++len; - seen_dollar = false; - } - // If we're here, we've read the first double and now expect a - // separator and another . - char separator = EatAChar(&text, &len, opts.separators, true, false); - if (separator == '.') { - // seen one '.' as separator; must check for another; perhaps set seplen=2 - if (EatAChar(&text, &len, ".", true, false)) { - if (final_period) { - // We may have three periods in a row. The first is part of the - // first number, the others are a separator. Policy: 234...567 - // is "234." to "567", not "234" to ".567". - EatAChar(&text, &len, ".", true, false); - } - } else if (!EatAChar(&text, &len, opts.separators, true, false)) { - // just one '.' and no other separator; uneat the first '.' we saw - --text; - if (len != -1) - ++len; - separator = '\0'; - } - } - // By now, we've consumed whatever separator there may have been, - // and separator is true iff there was one. - if (!separator) { - if (final_period) // final period now considered part of first double - EatAChar(&text, &len, ".", true, false); - if (initial_minus_sign && double_seen) { - *to = *from; - *from = from_default; - } else if (opts.require_separator || - (opts.num_required_bounds > 0 && !double_seen) || - (opts.num_required_bounds > 1) ) { - return false; - } - } else { - if (initial_minus_sign && double_seen) - *from = -(*from); - // read second - bool second_dollar_seen = (seen_dollar - || (opts.allow_currency && !double_seen)) - && EatAChar(&text, &len, "$", true, false); - bool second_double_seen = EatADouble( - &text, &len, opts.allow_unbounded_markers, to, NULL, NULL); - if (opts.num_required_bounds > double_seen + second_double_seen) - return false; - if (second_dollar_seen && !second_double_seen) { - --text; - if (len != -1) - ++len; - second_dollar_seen = false; - } - seen_dollar = seen_dollar || second_dollar_seen; - } - - if (seen_dollar && (is_currency != NULL)) - *is_currency = true; - // We're done. But we have to check that the next char is a proper - // terminator. - *end = text; - char terminator = EatAChar(&text, &len, opts.acceptable_terminators, false, - opts.null_terminator_ok); - if (terminator == '.') - --(*end); - return terminator; -} - -// ---------------------------------------------------------------------- -// ConsumeStrayLeadingZeroes -// Eliminates all leading zeroes (unless the string itself is composed -// of nothing but zeroes, in which case one is kept: 0...0 becomes 0). -// -------------------------------------------------------------------- - -void ConsumeStrayLeadingZeroes(string *const str) { - const string::size_type len(str->size()); - if (len > 1 && (*str)[0] == '0') { - const char - *const begin(str->c_str()), - *const end(begin + len), - *ptr(begin + 1); - while (ptr != end && *ptr == '0') { - ++ptr; - } - string::size_type remove(ptr - begin); - DCHECK_GT(ptr, begin); - if (remove == len) { - --remove; // if they are all zero, leave one... - } - str->erase(0, remove); - } -} - -// ---------------------------------------------------------------------- -// ParseLeadingInt32Value() -// ParseLeadingUInt32Value() -// A simple parser for [u]int32 values. Returns the parsed value -// if a valid value is found; else returns deflt -// This cannot handle decimal numbers with leading 0s. -// -------------------------------------------------------------------- - -int32 ParseLeadingInt32Value(const char *str, int32 deflt) { - using std::numeric_limits; - - char *error = NULL; - long value = strtol(str, &error, 0); - // Limit long values to int32 min/max. Needed for lp64; no-op on 32 bits. - if (value > numeric_limits::max()) { - value = numeric_limits::max(); - } else if (value < numeric_limits::min()) { - value = numeric_limits::min(); - } - return (error == str) ? deflt : value; -} - -uint32 ParseLeadingUInt32Value(const char *str, uint32 deflt) { - using std::numeric_limits; - - if (numeric_limits::max() == numeric_limits::max()) { - // When long is 32 bits, we can use strtoul. - char *error = NULL; - const uint32 value = strtoul(str, &error, 0); - return (error == str) ? deflt : value; - } else { - // When long is 64 bits, we must use strto64 and handle limits - // by hand. The reason we cannot use a 64-bit strtoul is that - // it would be impossible to differentiate "-2" (that should wrap - // around to the value UINT_MAX-1) from a string with ULONG_MAX-1 - // (that should be pegged to UINT_MAX due to overflow). - char *error = NULL; - int64 value = strto64(str, &error, 0); - if (value > numeric_limits::max() || - value < -static_cast(numeric_limits::max())) { - value = numeric_limits::max(); - } - // Within these limits, truncation to 32 bits handles negatives correctly. - return (error == str) ? deflt : value; - } -} - -// ---------------------------------------------------------------------- -// ParseLeadingDec32Value -// ParseLeadingUDec32Value -// A simple parser for [u]int32 values. Returns the parsed value -// if a valid value is found; else returns deflt -// The string passed in is treated as *10 based*. -// This can handle strings with leading 0s. -// -------------------------------------------------------------------- - -int32 ParseLeadingDec32Value(const char *str, int32 deflt) { - using std::numeric_limits; - - char *error = NULL; - long value = strtol(str, &error, 10); - // Limit long values to int32 min/max. Needed for lp64; no-op on 32 bits. - if (value > numeric_limits::max()) { - value = numeric_limits::max(); - } else if (value < numeric_limits::min()) { - value = numeric_limits::min(); - } - return (error == str) ? deflt : value; -} - -uint32 ParseLeadingUDec32Value(const char *str, uint32 deflt) { - using std::numeric_limits; - - if (numeric_limits::max() == numeric_limits::max()) { - // When long is 32 bits, we can use strtoul. - char *error = NULL; - const uint32 value = strtoul(str, &error, 10); - return (error == str) ? deflt : value; - } else { - // When long is 64 bits, we must use strto64 and handle limits - // by hand. The reason we cannot use a 64-bit strtoul is that - // it would be impossible to differentiate "-2" (that should wrap - // around to the value UINT_MAX-1) from a string with ULONG_MAX-1 - // (that should be pegged to UINT_MAX due to overflow). - char *error = NULL; - int64 value = strto64(str, &error, 10); - if (value > numeric_limits::max() || - value < -static_cast(numeric_limits::max())) { - value = numeric_limits::max(); - } - // Within these limits, truncation to 32 bits handles negatives correctly. - return (error == str) ? deflt : value; - } -} - -// ---------------------------------------------------------------------- -// ParseLeadingUInt64Value -// ParseLeadingInt64Value -// ParseLeadingHex64Value -// A simple parser for 64-bit values. Returns the parsed value if a -// valid integer is found; else returns deflt -// UInt64 and Int64 cannot handle decimal numbers with leading 0s. -// -------------------------------------------------------------------- -uint64 ParseLeadingUInt64Value(const char *str, uint64 deflt) { - char *error = NULL; - const uint64 value = strtou64(str, &error, 0); - return (error == str) ? deflt : value; -} - -int64 ParseLeadingInt64Value(const char *str, int64 deflt) { - char *error = NULL; - const int64 value = strto64(str, &error, 0); - return (error == str) ? deflt : value; -} - -uint64 ParseLeadingHex64Value(const char *str, uint64 deflt) { - char *error = NULL; - const uint64 value = strtou64(str, &error, 16); - return (error == str) ? deflt : value; -} - -// ---------------------------------------------------------------------- -// ParseLeadingDec64Value -// ParseLeadingUDec64Value -// A simple parser for [u]int64 values. Returns the parsed value -// if a valid value is found; else returns deflt -// The string passed in is treated as *10 based*. -// This can handle strings with leading 0s. -// -------------------------------------------------------------------- - -int64 ParseLeadingDec64Value(const char *str, int64 deflt) { - char *error = NULL; - const int64 value = strto64(str, &error, 10); - return (error == str) ? deflt : value; -} - -uint64 ParseLeadingUDec64Value(const char *str, uint64 deflt) { - char *error = NULL; - const uint64 value = strtou64(str, &error, 10); - return (error == str) ? deflt : value; -} - -// ---------------------------------------------------------------------- -// ParseLeadingDoubleValue() -// A simple parser for double values. Returns the parsed value -// if a valid value is found; else returns deflt -// -------------------------------------------------------------------- - -double ParseLeadingDoubleValue(const char *str, double deflt) { - char *error = NULL; - errno = 0; - const double value = strtod(str, &error); - if (errno != 0 || // overflow/underflow happened - error == str) { // no valid parse - return deflt; - } else { - return value; - } -} - -// ---------------------------------------------------------------------- -// ParseLeadingBoolValue() -// A recognizer of boolean string values. Returns the parsed value -// if a valid value is found; else returns deflt. This skips leading -// whitespace, is case insensitive, and recognizes these forms: -// 0/1, false/true, no/yes, n/y -// -------------------------------------------------------------------- -bool ParseLeadingBoolValue(StringPiece input, bool deflt) { - strings::RemoveLeadingWhitespace(&input); - // Keep alphanumeric - const char* const start = input.data(); - const char* alpha_num_end = start; - const char* end = alpha_num_end + input.size(); - while (alpha_num_end < end && ascii_isalnum(*alpha_num_end)) { - ++alpha_num_end; - } - const StringPiece value(start, alpha_num_end - start); - switch (value.size()) { - case 1: { - const char c = value[0]; - if (c == '0' || c == 'n' || c == 'N') return false; - if (c == '1' || c == 'y' || c == 'Y') return true; - } break; - case 2: - if (strings::EqualIgnoreCase(value, "no")) return false; - break; - case 3: - if (strings::EqualIgnoreCase(value, "yes")) return true; - break; - case 4: - if (strings::EqualIgnoreCase(value, "true")) return true; - break; - case 5: - if (strings::EqualIgnoreCase(value, "false")) return false; - break; - } - return deflt; -} - - -// ---------------------------------------------------------------------- -// FpToString() -// Uint128ToHexString() -// Convert various types to their string representation, possibly padded -// with spaces, using snprintf format specifiers. -// ---------------------------------------------------------------------- - -string FpToString(Fprint fp) { - char buf[17]; - snprintf(buf, sizeof(buf), "%016llx", fp); - return string(buf); -} - -// Default arguments -string Uint128ToHexString(uint128 ui128) { - using strings::Hex; - return StrCat(Hex(Uint128High64(ui128), Hex::ZERO_PAD_16), - Hex(Uint128Low64(ui128), Hex::ZERO_PAD_16)); -} - -bool HexStringToUint128(StringPiece hex, uint128* value) { - value->Initialize(0, 0); - if (hex.empty() || hex.size() > 32) return false; - // Verify that there are no invalid characters. - if (hex.find_first_not_of("0123456789abcdefABCDEF", 0) != StringPiece::npos) - return false; - // Consume 16 character suffixes and parse them as we go before merging. - uint64 parts[2] = {0, 0}; - for (uint64* p = parts; !hex.empty(); ++p) { - StringPiece next = hex; - next.remove_suffix(hex.size() > 16 ? 16 : hex.size()); - StringPiece curr = hex.substr(next.size()); - hex = next; - if (!safe_strtou64_base(curr, p, 16)) return false; - } - value->Initialize(parts[1], parts[0]); - return true; -} - -namespace { - -// Represents integer values of digits. -// Uses 36 to indicate an invalid character since we support -// bases up to 36. -static const int8 kAsciiToInt[256] = { - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, // 16 36s. - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 36, 36, 36, 36, 36, 36, 36, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 36, 36, 36, 36, 36, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36 }; - -// Parse the sign and optional hex or oct prefix in text. -inline bool safe_parse_sign_and_base(StringPiece* text /*inout*/, - int* base_ptr /*inout*/, - bool* negative_ptr /*output*/) { - const char* start = text->data(); - const char* end = start + text->size(); - int base = *base_ptr; - - // Consume whitespace. - while (start < end && ascii_isspace(start[0])) { - ++start; - } - while (start < end && ascii_isspace(end[-1])) { - --end; - } - if (start >= end) { - return false; - } - - // Consume sign. - *negative_ptr = (start[0] == '-'); - if (*negative_ptr || start[0] == '+') { - ++start; - if (start >= end) { - return false; - } - } - - // Consume base-dependent prefix. - // base 0: "0x" -> base 16, "0" -> base 8, default -> base 10 - // base 16: "0x" -> base 16 - // Also validate the base. - if (base == 0) { - if (end - start >= 2 && start[0] == '0' && - (start[1] == 'x' || start[1] == 'X')) { - base = 16; - start += 2; - if (start >= end) { - // "0x" with no digits after is invalid. - return false; - } - } else if (end - start >= 1 && start[0] == '0') { - base = 8; - start += 1; - } else { - base = 10; - } - } else if (base == 16) { - if (end - start >= 2 && start[0] == '0' && - (start[1] == 'x' || start[1] == 'X')) { - start += 2; - if (start >= end) { - // "0x" with no digits after is invalid. - return false; - } - } - } else if (base >= 2 && base <= 36) { - // okay - } else { - return false; - } - text->set(start, end - start); - *base_ptr = base; - return true; -} - -// Consume digits. -// -// The classic loop: -// -// for each digit -// value = value * base + digit -// value *= sign -// -// The classic loop needs overflow checking. It also fails on the most -// negative integer, -2147483648 in 32-bit two's complement representation. -// -// My improved loop: -// -// if (!negative) -// for each digit -// value = value * base -// value = value + digit -// else -// for each digit -// value = value * base -// value = value - digit -// -// Overflow checking becomes simple. - -template -inline bool safe_parse_positive_int( - StringPiece text, int base, IntType* value_p) { - IntType value = 0; - const IntType vmax = std::numeric_limits::max(); - assert(vmax > 0); - assert(vmax >= base); - const IntType vmax_over_base = vmax / base; - const char* start = text.data(); - const char* end = start + text.size(); - // loop over digits - for (; start < end; ++start) { - unsigned char c = static_cast(start[0]); - int digit = kAsciiToInt[c]; - if (digit >= base) { - *value_p = value; - return false; - } - if (value > vmax_over_base) { - *value_p = vmax; - return false; - } - value *= base; - if (value > vmax - digit) { - *value_p = vmax; - return false; - } - value += digit; - } - *value_p = value; - return true; -} - -template -inline bool safe_parse_negative_int( - StringPiece text, int base, IntType* value_p) { - IntType value = 0; - const IntType vmin = std::numeric_limits::min(); - assert(vmin < 0); - assert(vmin <= 0 - base); - IntType vmin_over_base = vmin / base; - // 2003 c++ standard [expr.mul] - // "... the sign of the remainder is implementation-defined." - // Although (vmin/base)*base + vmin%base is always vmin. - // 2011 c++ standard tightens the spec but we cannot rely on it. - if (vmin % base > 0) { - vmin_over_base += 1; - } - const char* start = text.data(); - const char* end = start + text.size(); - // loop over digits - for (; start < end; ++start) { - unsigned char c = static_cast(start[0]); - int digit = kAsciiToInt[c]; - if (digit >= base) { - *value_p = value; - return false; - } - if (value < vmin_over_base) { - *value_p = vmin; - return false; - } - value *= base; - if (value < vmin + digit) { - *value_p = vmin; - return false; - } - value -= digit; - } - *value_p = value; - return true; -} - -// Input format based on POSIX.1-2008 strtol -// http://pubs.opengroup.org/onlinepubs/9699919799/functions/strtol.html -template -bool safe_int_internal(StringPiece text, IntType* value_p, int base) { - *value_p = 0; - bool negative; - if (!safe_parse_sign_and_base(&text, &base, &negative)) { - return false; - } - if (!negative) { - return safe_parse_positive_int(text, base, value_p); - } else { - return safe_parse_negative_int(text, base, value_p); - } -} - -template -inline bool safe_uint_internal(StringPiece text, IntType* value_p, int base) { - *value_p = 0; - bool negative; - if (!safe_parse_sign_and_base(&text, &base, &negative) || negative) { - return false; - } - return safe_parse_positive_int(text, base, value_p); -} - -} // anonymous namespace - -bool safe_strto32_base(StringPiece text, int32* value, int base) { - return safe_int_internal(text, value, base); -} - -bool safe_strto64_base(StringPiece text, int64* value, int base) { - return safe_int_internal(text, value, base); -} - -bool safe_strtou32_base(StringPiece text, uint32* value, int base) { - return safe_uint_internal(text, value, base); -} - -bool safe_strtou64_base(StringPiece text, uint64* value, int base) { - return safe_uint_internal(text, value, base); -} - -bool safe_strtosize_t_base(StringPiece text, size_t* value, int base) { - return safe_uint_internal(text, value, base); -} - -// ---------------------------------------------------------------------- -// u64tostr_base36() -// Converts unsigned number to string representation in base-36. -// -------------------------------------------------------------------- -size_t u64tostr_base36(uint64 number, size_t buf_size, char* buffer) { - CHECK_GT(buf_size, 0); - CHECK(buffer); - static const char kAlphabet[] = "0123456789abcdefghijklmnopqrstuvwxyz"; - - buffer[buf_size - 1] = '\0'; - size_t result_size = 1; - - do { - if (buf_size == result_size) { // Ran out of space. - return 0; - } - int remainder = number % 36; - number /= 36; - buffer[buf_size - result_size - 1] = kAlphabet[remainder]; - result_size++; - } while (number); - - memmove(buffer, buffer + buf_size - result_size, result_size); - - return result_size - 1; -} - -bool safe_strtof(const char* str, float* value) { - char* endptr; -#ifdef _MSC_VER // has no strtof() - *value = strtod(str, &endptr); -#else - *value = strtof(str, &endptr); -#endif - if (endptr != str) { - while (ascii_isspace(*endptr)) ++endptr; - } - // Ignore range errors from strtod/strtof. - // The values it returns on underflow and - // overflow are the right fallback in a - // robust setting. - return *str != '\0' && *endptr == '\0'; -} - -bool safe_strtod(const char* str, double* value) { - char* endptr; - *value = strtod(str, &endptr); - if (endptr != str) { - while (ascii_isspace(*endptr)) ++endptr; - } - // Ignore range errors from strtod. The values it - // returns on underflow and overflow are the right - // fallback in a robust setting. - return *str != '\0' && *endptr == '\0'; -} - -#if defined(HAS_GLOBAL_STRING) -bool safe_strtof(const string& str, float* value) { - return safe_strtof(str.c_str(), value); -} - -bool safe_strtod(const string& str, double* value) { - return safe_strtod(str.c_str(), value); -} -#endif // HAS_GLOBAL_STRING - -bool safe_strtof(StringPiece str, float* value) { - return safe_strtof(str.ToString(), value); -} - -bool safe_strtod(StringPiece str, double* value) { - return safe_strtod(str.ToString(), value); -} - -bool safe_strtof(const std::string& str, float* value) { - return safe_strtof(str.c_str(), value); -} - -bool safe_strtod(const std::string& str, double* value) { - return safe_strtod(str.c_str(), value); -} - - -bool safe_strtob(StringPiece str, bool* value) { - CHECK(value != NULL) << "NULL output boolean given."; - if (CaseEqual(str, "true") || CaseEqual(str, "t") || - CaseEqual(str, "yes") || CaseEqual(str, "y") || - CaseEqual(str, "1")) { - *value = true; - return true; - } - if (CaseEqual(str, "false") || CaseEqual(str, "f") || - CaseEqual(str, "no") || CaseEqual(str, "n") || - CaseEqual(str, "0")) { - *value = false; - return true; - } - return false; -} - -uint64 atoi_kmgt(const char* s) { - char* endptr; - uint64 n = strtou64(s, &endptr, 10); - uint64 scale = 1; - char c = *endptr; - if (c != '\0') { - c = ascii_toupper(c); - switch (c) { - case 'K': - scale = GG_ULONGLONG(1) << 10; - break; - case 'M': - scale = GG_ULONGLONG(1) << 20; - break; - case 'G': - scale = GG_ULONGLONG(1) << 30; - break; - case 'T': - scale = GG_ULONGLONG(1) << 40; - break; - default: - LOG(FATAL) << "Invalid mnemonic: `" << c << "';" - << " should be one of `K', `M', `G', and `T'."; - } - } - return n * scale; -} - -// ---------------------------------------------------------------------- -// FastHex64ToBuffer() -// FastHex32ToBuffer() -// FastHex64ToBuffer() puts a 64-bit unsigned value in hex-format, -// padded to exactly 16 bytes (plus one byte for '\0') -// -// FastHex32ToBuffer() puts a 32-bit unsigned value in hex-format, -// padded to exactly 8 bytes (plus one byte for '\0') -// -// All functions take the output buffer as an arg. FastInt() -// uses at most 22 bytes, FastTime() uses exactly 30 bytes. -// They all return a pointer to the beginning of the output, -// which may not be the beginning of the input buffer. -// ---------------------------------------------------------------------- - -char *InternalFastHexToBuffer(uint64 value, char* buffer, int num_byte) { - static const char *hexdigits = "0123456789abcdef"; - buffer[num_byte] = '\0'; - for (int i = num_byte - 1; i >= 0; i--) { - buffer[i] = hexdigits[value & 0xf]; - value >>= 4; - } - return buffer; -} - -char *FastHex64ToBuffer(uint64 value, char* buffer) { - return InternalFastHexToBuffer(value, buffer, 16); -} - -char *FastHex32ToBuffer(uint32 value, char* buffer) { - return InternalFastHexToBuffer(value, buffer, 8); -} - -// Several converters use this table to reduce -// division and modulo operations. -extern const char two_ASCII_digits[100][2]; // from strutil.cc - -// ---------------------------------------------------------------------- -// FastInt32ToBufferLeft() -// FastUInt32ToBufferLeft() -// FastInt64ToBufferLeft() -// FastUInt64ToBufferLeft() -// -// Like the Fast*ToBuffer() functions above, these are intended for speed. -// Unlike the Fast*ToBuffer() functions, however, these functions write -// their output to the beginning of the buffer (hence the name, as the -// output is left-aligned). The caller is responsible for ensuring that -// the buffer has enough space to hold the output. -// -// Returns a pointer to the end of the string (i.e. the null character -// terminating the string). -// ---------------------------------------------------------------------- - -char* FastUInt32ToBufferLeft(uint32 u, char* buffer) { - uint32 digits; - // The idea of this implementation is to trim the number of divides to as few - // as possible by using multiplication and subtraction rather than mod (%), - // and by outputting two digits at a time rather than one. - // The huge-number case is first, in the hopes that the compiler will output - // that case in one branch-free block of code, and only output conditional - // branches into it from below. - if (u >= 1000000000) { // >= 1,000,000,000 - digits = u / 100000000; // 100,000,000 - memcpy(buffer, two_ASCII_digits[digits], 2); - buffer += 2; - sublt100_000_000: - u -= digits * 100000000; // 100,000,000 - lt100_000_000: - digits = u / 1000000; // 1,000,000 - memcpy(buffer, two_ASCII_digits[digits], 2); - buffer += 2; - sublt1_000_000: - u -= digits * 1000000; // 1,000,000 - lt1_000_000: - digits = u / 10000; // 10,000 - memcpy(buffer, two_ASCII_digits[digits], 2); - buffer += 2; - sublt10_000: - u -= digits * 10000; // 10,000 - lt10_000: - digits = u / 100; - memcpy(buffer, two_ASCII_digits[digits], 2); - buffer += 2; - sublt100: - u -= digits * 100; - lt100: - digits = u; - memcpy(buffer, two_ASCII_digits[digits], 2); - buffer += 2; - done: - *buffer = 0; - return buffer; - } - - if (u < 100) { - digits = u; - if (u >= 10) goto lt100; - *buffer++ = '0' + digits; - goto done; - } - if (u < 10000) { // 10,000 - if (u >= 1000) goto lt10_000; - digits = u / 100; - *buffer++ = '0' + digits; - goto sublt100; - } - if (u < 1000000) { // 1,000,000 - if (u >= 100000) goto lt1_000_000; - digits = u / 10000; // 10,000 - *buffer++ = '0' + digits; - goto sublt10_000; - } - if (u < 100000000) { // 100,000,000 - if (u >= 10000000) goto lt100_000_000; - digits = u / 1000000; // 1,000,000 - *buffer++ = '0' + digits; - goto sublt1_000_000; - } - // we already know that u < 1,000,000,000 - digits = u / 100000000; // 100,000,000 - *buffer++ = '0' + digits; - goto sublt100_000_000; -} - -char* FastInt32ToBufferLeft(int32 i, char* buffer) { - uint32 u = i; - if (i < 0) { - *buffer++ = '-'; - // We need to do the negation in modular (i.e., "unsigned") - // arithmetic; MSVC++ apprently warns for plain "-u", so - // we write the equivalent expression "0 - u" instead. - u = 0 - u; - } - return FastUInt32ToBufferLeft(u, buffer); -} - -char* FastUInt64ToBufferLeft(uint64 u64, char* buffer) { - uint32 u = static_cast(u64); - if (u == u64) return FastUInt32ToBufferLeft(u, buffer); - - uint64 top_11_digits = u64 / 1000000000; - buffer = FastUInt64ToBufferLeft(top_11_digits, buffer); - u = u64 - (top_11_digits * 1000000000); - - uint32 digits = u / 10000000; // 10,000,000 - memcpy(buffer, two_ASCII_digits[digits], 2); - buffer += 2; - u -= digits * 10000000; // 10,000,000 - digits = u / 100000; // 100,000 - memcpy(buffer, two_ASCII_digits[digits], 2); - buffer += 2; - u -= digits * 100000; // 100,000 - digits = u / 1000; // 1,000 - memcpy(buffer, two_ASCII_digits[digits], 2); - buffer += 2; - u -= digits * 1000; // 1,000 - digits = u / 10; - memcpy(buffer, two_ASCII_digits[digits], 2); - buffer += 2; - u -= digits * 10; - digits = u; - *buffer++ = '0' + digits; - *buffer = 0; - return buffer; -} - -char* FastInt64ToBufferLeft(int64 i, char* buffer) { - uint64 u = i; - if (i < 0) { - *buffer++ = '-'; - u = 0 - u; - } - return FastUInt64ToBufferLeft(u, buffer); -} int HexDigitsPrefix(const char* buf, int num_digits) { for (int i = 0; i < num_digits; i++) @@ -1084,263 +25,8 @@ int HexDigitsPrefix(const char* buf, int num_digits) { return 1; } -// ---------------------------------------------------------------------- -// AutoDigitStrCmp -// AutoDigitLessThan -// StrictAutoDigitLessThan -// autodigit_less -// autodigit_greater -// strict_autodigit_less -// strict_autodigit_greater -// These are like less and greater, except when a -// run of digits is encountered at corresponding points in the two -// arguments. Such digit strings are compared numerically instead -// of lexicographically. Therefore if you sort by -// "autodigit_less", some machine names might get sorted as: -// exaf1 -// exaf2 -// exaf10 -// When using "strict" comparison (AutoDigitStrCmp with the strict flag -// set to true, or the strict version of the other functions), -// strings that represent equal numbers will not be considered equal if -// the string representations are not identical. That is, "01" < "1" in -// strict mode, but "01" == "1" otherwise. -// ---------------------------------------------------------------------- - -int AutoDigitStrCmp(const char* a, size_t alen, - const char* b, size_t blen, - bool strict) { - size_t aindex = 0; - size_t bindex = 0; - while ((aindex < alen) && (bindex < blen)) { - if (ascii_isdigit(a[aindex]) && ascii_isdigit(b[bindex])) { - // Compare runs of digits. Instead of extracting numbers, we - // just skip leading zeroes, and then get the run-lengths. This - // allows us to handle arbitrary precision numbers. We remember - // how many zeroes we found so that we can differentiate between - // "1" and "01" in strict mode. - - // Skip leading zeroes, but remember how many we found - size_t azeroes = aindex; - size_t bzeroes = bindex; - while ((aindex < alen) && (a[aindex] == '0')) aindex++; - while ((bindex < blen) && (b[bindex] == '0')) bindex++; - azeroes = aindex - azeroes; - bzeroes = bindex - bzeroes; - - // Count digit lengths - size_t astart = aindex; - size_t bstart = bindex; - while ((aindex < alen) && ascii_isdigit(a[aindex])) aindex++; - while ((bindex < blen) && ascii_isdigit(b[bindex])) bindex++; - if (aindex - astart < bindex - bstart) { - // a has shorter run of digits: so smaller - return -1; - } else if (aindex - astart > bindex - bstart) { - // a has longer run of digits: so larger - return 1; - } else { - // Same lengths, so compare digit by digit - for (size_t i = 0; i < aindex-astart; i++) { - if (a[astart+i] < b[bstart+i]) { - return -1; - } else if (a[astart+i] > b[bstart+i]) { - return 1; - } - } - // Equal: did one have more leading zeroes? - if (strict && azeroes != bzeroes) { - if (azeroes > bzeroes) { - // a has more leading zeroes: a < b - return -1; - } else { - // b has more leading zeroes: a > b - return 1; - } - } - // Equal: so continue scanning - } - } else if (a[aindex] < b[bindex]) { - return -1; - } else if (a[aindex] > b[bindex]) { - return 1; - } else { - aindex++; - bindex++; - } - } - - if (aindex < alen) { - // b is prefix of a - return 1; - } else if (bindex < blen) { - // a is prefix of b - return -1; - } else { - // a is equal to b - return 0; - } -} - -bool AutoDigitLessThan(const char* a, size_t alen, const char* b, size_t blen) { - return AutoDigitStrCmp(a, alen, b, blen, false) < 0; -} - -bool StrictAutoDigitLessThan(const char* a, size_t alen, - const char* b, size_t blen) { - return AutoDigitStrCmp(a, alen, b, blen, true) < 0; -} - -// ---------------------------------------------------------------------- -// SimpleDtoa() -// SimpleFtoa() -// DoubleToBuffer() -// FloatToBuffer() -// We want to print the value without losing precision, but we also do -// not want to print more digits than necessary. This turns out to be -// trickier than it sounds. Numbers like 0.2 cannot be represented -// exactly in binary. If we print 0.2 with a very large precision, -// e.g. "%.50g", we get "0.2000000000000000111022302462515654042363167". -// On the other hand, if we set the precision too low, we lose -// significant digits when printing numbers that actually need them. -// It turns out there is no precision value that does the right thing -// for all numbers. -// -// Our strategy is to first try printing with a precision that is never -// over-precise, then parse the result with strtod() to see if it -// matches. If not, we print again with a precision that will always -// give a precise result, but may use more digits than necessary. -// -// An arguably better strategy would be to use the algorithm described -// in "How to Print Floating-Point Numbers Accurately" by Steele & -// White, e.g. as implemented by David M. Gay's dtoa(). It turns out, -// however, that the following implementation is about as fast as -// DMG's code. Furthermore, DMG's code locks mutexes, which means it -// will not scale well on multi-core machines. DMG's code is slightly -// more accurate (in that it will never use more digits than -// necessary), but this is probably irrelevant for most users. -// -// Rob Pike and Ken Thompson also have an implementation of dtoa() in -// third_party/fmt/fltfmt.cc. Their implementation is similar to this -// one in that it makes guesses and then uses strtod() to check them. -// Their implementation is faster because they use their own code to -// generate the digits in the first place rather than use snprintf(), -// thus avoiding format string parsing overhead. However, this makes -// it considerably more complicated than the following implementation, -// and it is embedded in a larger library. If speed turns out to be -// an issue, we could re-implement this in terms of their -// implementation. -// ---------------------------------------------------------------------- - -// Although DBL_DIG is typically 15, DBL_MAX is normally represented with 17 -// digits of precision. When converted to a string value with fewer digits -// of precision using strtod(), the result can be bigger than DBL_MAX due to -// a rounding error. Converting this value back to a double will produce an -// Inf which will trigger a SIGFPE if FP exceptions are enabled. We skip -// the precision check for sufficiently large values to avoid the SIGFPE. -static const double kDoublePrecisionCheckMax = DBL_MAX / 1.000000000000001; - -string SimpleDtoa(double value) { - char buffer[kFastToBufferSize]; - return DoubleToBuffer(value, buffer); -} - -string SimpleFtoa(float value) { - char buffer[kFastToBufferSize]; - return FloatToBuffer(value, buffer); -} - -char* DoubleToBuffer(double value, char* buffer) { - // DBL_DIG is 15 for IEEE-754 doubles, which are used on almost all - // platforms these days. Just in case some system exists where DBL_DIG - // is significantly larger -- and risks overflowing our buffer -- we have - // this assert. - COMPILE_ASSERT(DBL_DIG < 20, DBL_DIG_is_too_big); - - bool full_precision_needed = true; - if (std::abs(value) <= kDoublePrecisionCheckMax) { - int snprintf_result = - snprintf(buffer, kFastToBufferSize, "%.*g", DBL_DIG, value); - - // The snprintf should never overflow because the buffer is significantly - // larger than the precision we asked for. - DCHECK(snprintf_result > 0 && snprintf_result < kFastToBufferSize); - - full_precision_needed = strtod(buffer, NULL) != value; - } - - if (full_precision_needed) { - int snprintf_result = - snprintf(buffer, kFastToBufferSize, "%.*g", DBL_DIG + 2, value); - - // Should never overflow; see above. - DCHECK(snprintf_result > 0 && snprintf_result < kFastToBufferSize); - } - return buffer; -} - -char* FloatToBuffer(float value, char* buffer) { - // FLT_DIG is 6 for IEEE-754 floats, which are used on almost all - // platforms these days. Just in case some system exists where FLT_DIG - // is significantly larger -- and risks overflowing our buffer -- we have - // this assert. - COMPILE_ASSERT(FLT_DIG < 10, FLT_DIG_is_too_big); - - int snprintf_result = - snprintf(buffer, kFastToBufferSize, "%.*g", FLT_DIG, value); - - // The snprintf should never overflow because the buffer is significantly - // larger than the precision we asked for. - DCHECK(snprintf_result > 0 && snprintf_result < kFastToBufferSize); - - float parsed_value; - if (!safe_strtof(buffer, &parsed_value) || parsed_value != value) { - snprintf_result = - snprintf(buffer, kFastToBufferSize, "%.*g", FLT_DIG+2, value); - - // Should never overflow; see above. - DCHECK(snprintf_result > 0 && snprintf_result < kFastToBufferSize); - } - return buffer; -} - -string SimpleBtoa(bool value) { - return value ? string("true") : string("false"); +uint64 ParseLeadingHex64Value(const char *str, uint64 deflt) { + char *error = NULL; + const uint64 value = strtou64(str, &error, 16); + return (error == str) ? deflt : value; } - -// ---------------------------------------------------------------------- -// ---------------------------------------------------------------------- -// ItoaKMGT() -// Description: converts an integer to a string -// Truncates values to a readable unit: K, G, M or T -// Opposite of atoi_kmgt() -// e.g. 100 -> "100" 1500 -> "1500" 4000 -> "3K" 57185920 -> "45M" -// -// Return value: string -// ---------------------------------------------------------------------- -string ItoaKMGT(int64 i) { - const char *sign = "", *suffix = ""; - if (i < 0) { - // We lose some accuracy if the caller passes LONG_LONG_MIN, but - // that's OK as this function is only for human readability - if (i == std::numeric_limits::min()) i++; - sign = "-"; - i = -i; - } - - int64 val; - - if ((val = (i >> 40)) > 1) { - suffix = "T"; - } else if ((val = (i >> 30)) > 1) { - suffix = "G"; - } else if ((val = (i >> 20)) > 1) { - suffix = "M"; - } else if ((val = (i >> 10)) > 1) { - suffix = "K"; - } else { - val = i; - } - - return StringPrintf("%s%" GG_LL_FORMAT "d%s", sign, val, suffix); -} \ No newline at end of file diff --git a/src/strings/numbers.h b/src/strings/numbers.h index 77d4d610..9ebe1ea4 100644 --- a/src/strings/numbers.h +++ b/src/strings/numbers.h @@ -1,4 +1,4 @@ -// Copyright 2010 Google Inc. All Rights Reserved. +// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,259 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// Author: jyrki@google.com (Jyrki Alakuijala) -// Maintainer: mec@google.com (Michael Chastain) -// -// Convert strings to numbers or numbers to strings. #ifndef STRINGS_NUMBERS_H_ #define STRINGS_NUMBERS_H_ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "base/int128.h" #include "base/integral_types.h" -#include "base/macros.h" -#include "base/port.h" -#include "base/type_traits.h" -#include "base/stringprintf.h" -#include "strings/ascii_ctype.h" -#include "strings/stringpiece.h" - -// START DOXYGEN NumbersFunctions grouping -/* @defgroup NumbersFunctions - * @{ */ - -// Convert strings to numeric values, with strict error checking. -// Leading and trailing spaces are allowed. -// Negative inputs are not allowed for unsigned ints (unlike strtoul). -// -// Base must be [0, 2-36]. -// Base 0: -// auto-select base from first two chars: -// "0x" -> hex -// "0" -> octal -// else -> decimal -// Base 16: -// Number can start with "0x" -// -// On error, returns false, and sets *value to: -// std::numeric_limits::max() on overflow -// std::numeric_limits::min() on underflow -// conversion of leading substring if available ("123@@@" -> 123) -// 0 if no leading substring available -// The effect on errno is unspecified. -// Do not depend on testing errno. -bool safe_strto32_base(StringPiece text, int32* value, int base); -bool safe_strto64_base(StringPiece text, int64* value, int base); -bool safe_strtou32_base(StringPiece text, uint32* value, int base); -bool safe_strtou64_base(StringPiece text, uint64* value, int base); -bool safe_strtosize_t_base(StringPiece text, size_t* value, int base); - -// Convenience functions with base == 10. -inline bool safe_strto32(StringPiece text, int32* value) { - return safe_strto32_base(text, value, 10); -} - -inline bool safe_strto64(StringPiece text, int64* value) { - return safe_strto64_base(text, value, 10); -} - -inline bool safe_strtou32(StringPiece text, uint32* value) { - return safe_strtou32_base(text, value, 10); -} - -inline bool safe_strtou64(StringPiece text, uint64* value) { - return safe_strtou64_base(text, value, 10); -} - -inline bool safe_strtosize_t(StringPiece text, size_t* value) { - return safe_strtosize_t_base(text, value, 10); -} - -// 8 obsolete functions. -// I would like to deprecate these functions but there are technical -// problems with SplitStringAndParse callbacks. -// -// 4 safe_strtofoo(const char*, ...); -// 4 safe_strtofoo(const string&, ...); -// -// If you want to see the technical problems, delete these overloads -// and build strings:strings. - -// --- - -inline bool safe_strto32(const char* str, int32* value) { - return safe_strto32(StringPiece(str), value); -} - -inline bool safe_strto32(const string& str, int32* value) { - return safe_strto32(StringPiece(str), value); -} - -// --- - -inline bool safe_strto64(const char* str, int64* value) { - return safe_strto64(StringPiece(str), value); -} - -inline bool safe_strto64(const string& str, int64* value) { - return safe_strto64(StringPiece(str), value); -} - -// --- - -inline bool safe_strtou32(const char* str, uint32* value) { - return safe_strtou32(StringPiece(str), value); -} - -inline bool safe_strtou32(const string& str, uint32* value) { - return safe_strtou32(StringPiece(str), value); -} - -// --- - -inline bool safe_strtou64(const char* str, uint64* value) { - return safe_strtou64(StringPiece(str), value); -} - -inline bool safe_strtou64(const string& str, uint64* value) { - return safe_strtou64(StringPiece(str), value); -} - -// --- - -// Convert a fingerprint to 16 hex digits. -string FpToString(Fprint fp); -// Convert between uint128 and 32-digit hex string (sans leading 0x). -string Uint128ToHexString(uint128 ui128); -// Returns true on successful conversion; false on invalid input. -bool HexStringToUint128(StringPiece hex, uint128* value); - -// Convert strings to floating point values. -// Leading and trailing spaces are allowed. -// Values may be rounded on over- and underflow. -bool safe_strtof(StringPiece str, float* value); -bool safe_strtof(const char* str, float* value); -#if defined(HAS_GLOBAL_STRING) -bool safe_strtof(const string& str, float* value); -#endif -// In order to avoid ambiguity between conversion to string and -// StringPiece, define a specialization for std::string. -bool safe_strtof(const std::string& str, float* value); - -bool safe_strtod(StringPiece str, double* value); -bool safe_strtod(const char* str, double* value); -#if defined(HAS_GLOBAL_STRING) -bool safe_strtod(const string& str, double* value); -#endif -// In order to avoid ambiguity between conversion to string and -// StringPiece, define a specialization for std::string. -bool safe_strtod(const std::string& str, double* value); - -// Parses text (case insensitive) into a boolean. The following strings are -// interpreted to boolean true: "true", "t", "yes", "y", "1". The following -// strings are interpreted to boolean false: "false", "f", "no", "n", "0". -// Returns true on success. On failure the boolean value will not have been -// changed. -bool safe_strtob(StringPiece str, bool* value); - -// u64tostr_base36() -// The inverse of safe_strtou64_base, converts the number agument to -// a string representation in base-36. -// Conversion fails if buffer is too small to to hold the string and -// terminating NUL. -// Returns number of bytes written, not including terminating NUL. -// Return value 0 indicates error. -size_t u64tostr_base36(uint64 number, size_t buf_size, char* buffer); - -// Similar to atoi(s), except s could be like "16k", "32M", "2G", "4t". -uint64 atoi_kmgt(const char* s); -inline uint64 atoi_kmgt(const string& s) { return atoi_kmgt(s.c_str()); } - -// ---------------------------------------------------------------------- -// FastIntToBuffer() -// FastTimeToBuffer() -// These are intended for speed. FastTimeToBuffer() puts the output -// into RFC822 format. -// -// All functions take the output buffer as an arg. FastInt() uses -// at most 22 bytes, FastTime() uses exactly 30 bytes. They all -// return a pointer to the beginning of the output, which is the same as -// the beginning of the input buffer. -// -// NOTE: In 64-bit land, sizeof(time_t) is 8, so it is possible -// to pass to FastTimeToBuffer() a time whose year cannot be -// represented in 4 digits. In this case, the output buffer -// will contain the string "Invalid:" -// ---------------------------------------------------------------------- - -// Previously documented minimums -- the buffers provided must be at least this -// long, though these numbers are subject to change: -// Int32, UInt32: 12 bytes -// Int64, UInt64, Int, Uint: 22 bytes -// Time: 30 bytes -// Use kFastToBufferSize rather than hardcoding constants. -static const int kFastToBufferSize = 32; - -char* FastUInt32ToBuffer(uint32 i, char* buffer); -char* FastUInt64ToBuffer(uint64 i, char* buffer); -char* FastTimeToBuffer(time_t t, char* buffer); - -// These are deprecated. Use StrCat instead. -char* FastHex64ToBuffer(uint64 i, char* buffer); -char* FastHex32ToBuffer(uint32 i, char* buffer); - -// ---------------------------------------------------------------------- -// FastInt32ToBufferLeft() -// FastUInt32ToBufferLeft() -// FastInt64ToBufferLeft() -// FastUInt64ToBufferLeft() -// -// Like the Fast*ToBuffer() functions above, these are intended for speed. -// Unlike the Fast*ToBuffer() functions, however, these functions write -// their output to the beginning of the buffer (hence the name, as the -// output is left-aligned). The caller is responsible for ensuring that -// the buffer has enough space to hold the output. -// -// Returns a pointer to the end of the string (i.e. the null character -// terminating the string). -// ---------------------------------------------------------------------- - -char* FastInt32ToBufferLeft(int32 i, char* buffer); // at least 12 bytes -char* FastUInt32ToBufferLeft(uint32 i, char* buffer); // at least 12 bytes -char* FastInt64ToBufferLeft(int64 i, char* buffer); // at least 22 bytes -char* FastUInt64ToBufferLeft(uint64 i, char* buffer); // at least 22 bytes - -// Just define these in terms of the above. - -inline char* FastInt32ToBuffer(int32 i, char* buffer) { - FastInt32ToBufferLeft(i, buffer); - return buffer; -} -inline char* FastUInt32ToBuffer(uint32 i, char* buffer) { - FastUInt32ToBufferLeft(i, buffer); - return buffer; -} -inline char* FastInt64ToBuffer(int64 i, char* buffer) { - FastInt64ToBufferLeft(i, buffer); - return buffer; -} -inline char* FastUInt64ToBuffer(uint64 i, char* buffer) { - FastUInt64ToBufferLeft(i, buffer); - return buffer; -} -inline char* FastIntToBuffer(int i, char* buffer) { - return (sizeof(i) == 4 ? - FastInt32ToBuffer(i, buffer) : FastInt64ToBuffer(i, buffer)); -} // ---------------------------------------------------------------------- // HexDigitsPrefix() @@ -275,394 +27,11 @@ inline char* FastIntToBuffer(int i, char* buffer) { int HexDigitsPrefix(const char* buf, int num_digits); // ---------------------------------------------------------------------- -// ConsumeStrayLeadingZeroes -// Eliminates all leading zeroes (unless the string itself is composed -// of nothing but zeroes, in which case one is kept: 0...0 becomes 0). -void ConsumeStrayLeadingZeroes(string* str); - -// ---------------------------------------------------------------------- -// ParseLeadingInt32Value -// A simple parser for int32 values. Returns the parsed value -// if a valid integer is found; else returns deflt. It does not -// check if str is entirely consumed. -// This cannot handle decimal numbers with leading 0s, since they will be -// treated as octal. If you know it's decimal, use ParseLeadingDec32Value. -// -------------------------------------------------------------------- -int32 ParseLeadingInt32Value(const char* str, int32 deflt); -inline int32 ParseLeadingInt32Value(const string& str, int32 deflt) { - return ParseLeadingInt32Value(str.c_str(), deflt); -} - -// ParseLeadingUInt32Value -// A simple parser for uint32 values. Returns the parsed value -// if a valid integer is found; else returns deflt. It does not -// check if str is entirely consumed. -// This cannot handle decimal numbers with leading 0s, since they will be -// treated as octal. If you know it's decimal, use ParseLeadingUDec32Value. -// -------------------------------------------------------------------- -uint32 ParseLeadingUInt32Value(const char* str, uint32 deflt); -inline uint32 ParseLeadingUInt32Value(const string& str, uint32 deflt) { - return ParseLeadingUInt32Value(str.c_str(), deflt); -} - -// ---------------------------------------------------------------------- -// ParseLeadingDec32Value -// A simple parser for decimal int32 values. Returns the parsed value -// if a valid integer is found; else returns deflt. It does not -// check if str is entirely consumed. -// The string passed in is treated as *10 based*. -// This can handle strings with leading 0s. -// See also: ParseLeadingDec64Value -// -------------------------------------------------------------------- -int32 ParseLeadingDec32Value(const char* str, int32 deflt); -inline int32 ParseLeadingDec32Value(const string& str, int32 deflt) { - return ParseLeadingDec32Value(str.c_str(), deflt); -} - -// ParseLeadingUDec32Value -// A simple parser for decimal uint32 values. Returns the parsed value -// if a valid integer is found; else returns deflt. It does not -// check if str is entirely consumed. -// The string passed in is treated as *10 based*. -// This can handle strings with leading 0s. -// See also: ParseLeadingUDec64Value -// -------------------------------------------------------------------- -uint32 ParseLeadingUDec32Value(const char* str, uint32 deflt); -inline uint32 ParseLeadingUDec32Value(const string& str, uint32 deflt) { - return ParseLeadingUDec32Value(str.c_str(), deflt); -} - -// ---------------------------------------------------------------------- -// ParseLeadingUInt64Value -// ParseLeadingInt64Value // ParseLeadingHex64Value -// ParseLeadingDec64Value -// ParseLeadingUDec64Value -// A simple parser for long long values. -// Returns the parsed value if a +// A simple parser for 64-bit values. Returns the parsed value if a // valid integer is found; else returns deflt +// UInt64 and Int64 cannot handle decimal numbers with leading 0s. // -------------------------------------------------------------------- -uint64 ParseLeadingUInt64Value(const char* str, uint64 deflt); -inline uint64 ParseLeadingUInt64Value(const string& str, uint64 deflt) { - return ParseLeadingUInt64Value(str.c_str(), deflt); -} -int64 ParseLeadingInt64Value(const char* str, int64 deflt); -inline int64 ParseLeadingInt64Value(const string& str, int64 deflt) { - return ParseLeadingInt64Value(str.c_str(), deflt); -} uint64 ParseLeadingHex64Value(const char* str, uint64 deflt); -inline uint64 ParseLeadingHex64Value(const string& str, uint64 deflt) { - return ParseLeadingHex64Value(str.c_str(), deflt); -} -int64 ParseLeadingDec64Value(const char* str, int64 deflt); -inline int64 ParseLeadingDec64Value(const string& str, int64 deflt) { - return ParseLeadingDec64Value(str.c_str(), deflt); -} -uint64 ParseLeadingUDec64Value(const char* str, uint64 deflt); -inline uint64 ParseLeadingUDec64Value(const string& str, uint64 deflt) { - return ParseLeadingUDec64Value(str.c_str(), deflt); -} - -// ---------------------------------------------------------------------- -// ParseLeadingDoubleValue -// A simple parser for double values. Returns the parsed value -// if a valid double is found; else returns deflt. It does not -// check if str is entirely consumed. -// -------------------------------------------------------------------- -double ParseLeadingDoubleValue(const char* str, double deflt); -inline double ParseLeadingDoubleValue(const string& str, double deflt) { - return ParseLeadingDoubleValue(str.c_str(), deflt); -} - -// ---------------------------------------------------------------------- -// ParseLeadingBoolValue() -// A recognizer of boolean string values. Returns the parsed value -// if a valid value is found; else returns deflt. This skips leading -// whitespace, is case insensitive, and recognizes these forms: -// 0/1, false/true, no/yes, n/y -// -------------------------------------------------------------------- -bool ParseLeadingBoolValue(StringPiece str, bool deflt); - -// ---------------------------------------------------------------------- -// AutoDigitStrCmp -// AutoDigitLessThan -// StrictAutoDigitLessThan -// autodigit_less -// autodigit_greater -// strict_autodigit_less -// strict_autodigit_greater -// These are like less and greater, except when a -// run of digits is encountered at corresponding points in the two -// arguments. Such digit strings are compared numerically instead -// of lexicographically. Therefore if you sort by -// "autodigit_less", some machine names might get sorted as: -// exaf1 -// exaf2 -// exaf10 -// When using "strict" comparison (AutoDigitStrCmp with the strict flag -// set to true, or the strict version of the other functions), -// strings that represent equal numbers will not be considered equal if -// the string representations are not identical. That is, "01" < "1" in -// strict mode, but "01" == "1" otherwise. -// ---------------------------------------------------------------------- - -int AutoDigitStrCmp(const char* a, size_t alen, - const char* b, size_t blen, - bool strict); - -bool AutoDigitLessThan(const char* a, size_t alen, - const char* b, size_t blen); - -bool StrictAutoDigitLessThan(const char* a, size_t alen, - const char* b, size_t blen); - -struct autodigit_less - : public std::binary_function { - bool operator()(const string& a, const string& b) const { - return AutoDigitLessThan(a.data(), a.size(), b.data(), b.size()); - } -}; - -struct autodigit_greater - : public std::binary_function { - bool operator()(const string& a, const string& b) const { - return AutoDigitLessThan(b.data(), b.size(), a.data(), a.size()); - } -}; - -struct strict_autodigit_less - : public std::binary_function { - bool operator()(const string& a, const string& b) const { - return StrictAutoDigitLessThan(a.data(), a.size(), b.data(), b.size()); - } -}; - -struct strict_autodigit_greater - : public std::binary_function { - bool operator()(const string& a, const string& b) const { - return StrictAutoDigitLessThan(b.data(), b.size(), a.data(), a.size()); - } -}; - -// ---------------------------------------------------------------------- -// SimpleItoa() -// Description: converts an integer to a string. -// Faster than printf("%d"). -// -// Return value: string -// ---------------------------------------------------------------------- -inline string SimpleItoa(int32 i) { - char buf[16]; // Longest is -2147483648 - return string(buf, FastInt32ToBufferLeft(i, buf)); -} - -// We need this overload because otherwise SimpleItoa(5U) wouldn't compile. -inline string SimpleItoa(uint32 i) { - char buf[16]; // Longest is 4294967295 - return string(buf, FastUInt32ToBufferLeft(i, buf)); -} - -inline string SimpleItoa(int64 i) { - char buf[32]; // Longest is -9223372036854775808 - return string(buf, FastInt64ToBufferLeft(i, buf)); -} - -// We need this overload because otherwise SimpleItoa(5ULL) wouldn't compile. -inline string SimpleItoa(uint64 i) { - char buf[32]; // Longest is 18446744073709551615 - return string(buf, FastUInt64ToBufferLeft(i, buf)); -} - -inline string SimpleItoa(long i) { // NOLINT long is OK here - if (sizeof(i) == 64 / 8) { - return SimpleItoa(static_cast(i)); - } else if (sizeof(i) == 32 / 8) { - return SimpleItoa(static_cast(i)); - } -} - -inline string SimpleItoa(unsigned long i) { // NOLINT long is OK here - if (sizeof(i) == 64 / 8) { - return SimpleItoa(static_cast(i)); - } else if (sizeof(i) == 32 / 8) { - return SimpleItoa(static_cast(i)); - } -} - -// SimpleAtoi converts a string to an integer. -// Uses safe_strto?() for actual parsing, so strict checking is -// applied, which is to say, the string must be a base-10 integer, optionally -// followed or preceded by whitespace, and value has to be in the range of -// the corresponding integer type. -// -// Returns true if parsing was successful. -template -bool MUST_USE_RESULT SimpleAtoi(const char* s, int_type* out) { - static_assert(sizeof(*out) == 4 || sizeof(*out) == 8, - "SimpleAtoi works only with 32-bit or 64-bit integers."); - static_assert(!base::is_floating_point::value, - "Use safe_strtof or safe_strtod instead."); - bool parsed; - // TODO(user): This signed-ness check is used because it works correctly - // with enums, and it also serves to check that int_type is not a pointer. - // If one day something like std::is_signed works, switch to it. - if (static_cast(0) > -1) { // Signed - if (sizeof(*out) == 64 / 8) { // 64-bit - int64 val; - parsed = safe_strto64(s, &val); - *out = static_cast(val); - } else { // 32-bit - int32 val; - parsed = safe_strto32(s, &val); - *out = static_cast(val); - } - } else { // Unsigned - if (sizeof(*out) == 64 / 8) { // 64-bit - uint64 val; - parsed = safe_strtou64(s, &val); - *out = static_cast(val); - } else { // 32-bit - uint32 val; - parsed = safe_strtou32(s, &val); - *out = static_cast(val); - } - } - return parsed; -} - -template -bool MUST_USE_RESULT SimpleAtoi(const string& s, int_type* out) { - return SimpleAtoi(s.c_str(), out); -} - -// ---------------------------------------------------------------------- -// SimpleDtoa() -// SimpleFtoa() -// Description: converts a double or float to a string which, if passed to -// strtod() or strtof() respectively, will produce the exact same original -// double or float. Exception: for NaN values, strtod(SimpleDtoa(NaN)) or -// strtof(SimpleFtoa(NaN)) may produce any NaN value, not necessarily the -// exact same original NaN value. -// -// The output string is not guaranteed to be as short as possible. -// -// The output string, including terminating NUL, will have length -// less than or equal to kFastToBufferSize defined above. Of course, -// we would prefer that your code not depend on this property of -// the output string. This guarantee derives from a similar guarantee -// from the previous generation of char-buffer-based functions. -// We had to carry it forward to preserve compatibility. -// ---------------------------------------------------------------------- -string SimpleDtoa(double value); -string SimpleFtoa(float value); - -// DEPRECATED(mec). Call SimpleDtoa or SimpleFtoa instead. -// Required buffer size for DoubleToBuffer is kFastToBufferSize. -// Required buffer size for FloatToBuffer is kFastToBufferSize. -char* DoubleToBuffer(double i, char* buffer); // DEPRECATED(mec) -char* FloatToBuffer(float i, char* buffer); // DEPRECATED(mec) - -// ---------------------------------------------------------------------- -// SimpleItoaWithCommas() -// Description: converts an integer to a string. -// Puts commas every 3 spaces. -// Faster than printf("%d")? -// -// Return value: string -// ---------------------------------------------------------------------- - -template -inline string SimpleItoaWithCommas(IntType ii) { - string s1 = SimpleItoa(ii); - StringPiece sp1(s1); - string output; - // Copy leading non-digit characters unconditionally. - // This picks up the leading sign. - while (sp1.size() > 0 && !ascii_isdigit(sp1[0])) { - output.push_back(sp1[0]); - sp1.remove_prefix(1); - } - // Copy rest of input characters. - for (stringpiece_ssize_type i = 0; i < sp1.size(); ++i) { - if (i > 0 && (sp1.size() - i) % 3 == 0) { - output.push_back(','); - } - output.push_back(sp1[i]); - } - return output; -} - -// Converts a boolean to a string, which if passed to safe_strtob will produce -// the exact same original boolean. The returned string will be "true" if -// value == true, and "false" otherwise. -string SimpleBtoa(bool value); - -// ---------------------------------------------------------------------- -// ItoaKMGT() -// Description: converts an integer to a string -// Truncates values to K, G, M or T as appropriate -// Opposite of atoi_kmgt() -// e.g. 3000 -> 2K 57185920 -> 45M -// -// Return value: string -// ---------------------------------------------------------------------- -string ItoaKMGT(int64 i); - -// ---------------------------------------------------------------------- -// ParseDoubleRange() -// Parse an expression in 'text' of the form: -// where may be a double-precision number and is a -// single char or "..", and must be one of the chars in parameter -// 'separators', which may contain '-' or '.' (which means "..") or -// any chars not allowed in a double. If allow_unbounded_markers, -// may also be a '?' to indicate unboundedness (if on the -// left of , means unbounded below; if on the right, means -// unbounded above). Depending on num_required_bounds, which may be -// 0, 1, or 2, may also be the empty string, indicating -// unboundedness. If require_separator is false, then a single -// is acceptable and is parsed as a range bounded from -// below. We also check that the character following the range must -// be in acceptable_terminators. If null_terminator_ok, then it is -// also OK if the range ends in \0 or after len chars. If -// allow_currency is true, the first may be optionally -// preceded by a '$', in which case *is_currency will be true, and -// the second may similarly be preceded by a '$'. In these -// cases, the '$' will be ignored (otherwise it's an error). If -// allow_comparators is true, the expression in 'text' may also be -// of the form , where is '<' or -// '>' or '<=' or '>='. separators and require_separator are -// ignored in this format, but all other parameters function as for -// the first format. Return true if the expression parsed -// successfully; false otherwise. If successful, output params are: -// 'end', which points to the char just beyond the expression; -// 'from' and 'to' are set to the values of the s, and are -// -inf and inf (or unchanged, depending on dont_modify_unbounded) -// if unbounded. Output params are undefined if false is -// returned. len is the input length, or -1 if text is -// '\0'-terminated, which is more efficient. -// ---------------------------------------------------------------------- -struct DoubleRangeOptions { - const char* separators; - bool require_separator; - const char* acceptable_terminators; - bool null_terminator_ok; - bool allow_unbounded_markers; - uint32 num_required_bounds; - bool dont_modify_unbounded; - bool allow_currency; - bool allow_comparators; -}; - -// NOTE: The instruction below creates a Module titled -// NumbersFunctions within the auto-generated Doxygen documentation. -// This instruction is needed to expose global functions that are not -// within a namespace. -// -bool ParseDoubleRange(const char* text, int len, const char** end, - double* from, double* to, bool* is_currency, - const DoubleRangeOptions& opts); - -// END DOXYGEN SplitFunctions grouping -/* @} */ -#endif // STRINGS_NUMBERS_H_ \ No newline at end of file +#endif // STRINGS_NUMBERS_H_ diff --git a/src/strings/serialize.cc b/src/strings/serialize.cc index cfdd9416..4e58b9d7 100644 --- a/src/strings/serialize.cc +++ b/src/strings/serialize.cc @@ -1,4 +1,4 @@ -// Copyright 2003 Google Inc. All Rights Reserved. +// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,385 +15,21 @@ #include "strings/serialize.h" -#include -#include -#include -using __gnu_cxx::hash; -using __gnu_cxx::hash_map; #include -#include #include -#include "base/casts.h" -#include "base/integral_types.h" -#include "base/stringprintf.h" -#include "base/strtoint.h" -#include "strings/join.h" #include "strings/split.h" -#include "util/hash/hash.h" -using std::vector; - -// Helper functions for KeyFromDouble/KeyToDouble and KeyFromFloat/KeyToFloat. -namespace { -// Encodes the given IEEE-754 floating-point argument in the specified unsigned -// integer type. E.g., uint64 x = UintFromIEEE754(my_double); -// IEEE standard 754 floating point representation -// [sign-bit] [exponent] [mantissa] -// -// Let "a", "b" be two double values, and F(.) be following -// transformation. We have: -// If 0 < a < b: -// 0x80000000ULL < uint64(F(a)) < uint64(F(b)) -// If a == -0.0, b == +0.0: -// uint64(F(-0.0)) == uint64(F(+0.0)) = 0x80000000ULL -// If a < b < 0: -// uint64(F(a)) < uint64(F(b)) < 0x80000000ULL -template -UintType UintFromIEEE754(FloatType f) { - const UintType n = bit_cast(f); - const UintType sign_bit = ~(~static_cast(0) >> 1); - if ((n & sign_bit) == 0) return n + sign_bit; - return -n; -} - -// Encodes the given unsigned integer argument in the specified IEEE-754 -// floating-point format. E.g., double x = IEEE754FromUint(my_uint64); -// Inverse of above. -template -FloatType IEEE754FromUint(UintType n) { - const UintType sign_bit = ~(~static_cast(0) >> 1); - if (n & sign_bit) { - n -= sign_bit; - } else { - n = -n; - } - return bit_cast(n); -} -} // namespace - -// Convert a uint32 to a 4-byte string. -string Uint32ToKey(uint32 u32) { - string key; - KeyFromUint32(u32, &key); - return key; -} - -string Uint64ToKey(uint64 fp) { - string key; - KeyFromUint64(fp, &key); - return key; -} - -// Convert a uint128 to a 16-byte string. -string Uint128ToKey(uint128 u128) { - string key; - KeyFromUint128(u128, &key); - return key; -} - -// Converts int32 to a 4-byte string key -// NOTE: Lexicographic ordering of the resulting strings does not in -// general correspond to any natural ordering of the corresponding -// integers. For non-negative inputs, lexicographic ordering of the -// resulting strings corresponds to increasing ordering of the -// integers. However, negative inputs are sorted *after* the non-negative -// inputs. To obtain keys such that lexicographic ordering corresponds -// to the natural total order on the integers, use OrderedStringFromInt32() -// or ReverseOrderedStringFromInt32() instead. -void KeyFromInt32(int32 i32, string* key) { - // TODO(user): Redefine using bit_cast<> and KeyFromUint32()? - key->resize(sizeof(i32)); - for (int i = sizeof(i32) - 1; i >= 0; --i) { - (*key)[i] = i32 & 0xff; - i32 = (i32 >> 8); - } -} - -// Converts a 4-byte string key (typically generated by KeyFromInt32) -// into an int32 value -int32 KeyToInt32(StringPiece key) { - int32 i32 = 0; - CHECK_EQ(key.size(), sizeof(i32)); - for (size_t i = 0; i < sizeof(i32); ++i) { - i32 = (i32 << 8) | static_cast(key[i]); - } - return i32; -} - -// Converts int64 to a 8-byte string key -// NOTE: Lexicographic ordering of the resulting strings does not in -// general correspond to any natural ordering of the corresponding -// integers. For non-negative inputs, lexicographic ordering of the -// resulting strings corresponds to increasing ordering of the -// integers. However, negative inputs are sorted *after* the non-negative -// inputs. To obtain keys such that lexicographic ordering corresponds -// to the natural total order on the integers, use OrderedStringFromInt64() -// or ReverseOrderedStringFromInt64() instead. -void KeyFromInt64(int64 i64, string* key) { - key->resize(sizeof(i64)); - for (int i = sizeof(i64) - 1; i >= 0; --i) { - (*key)[i] = i64 & 0xff; - i64 = (i64 >> 8); - } -} - -// Converts a 8-byte string key (typically generated by KeyFromInt64) -// into an int64 value. -int64 KeyToInt64(StringPiece key) { - int64 i64 = 0; - CHECK_EQ(key.size(), sizeof(i64)); - for (size_t i = 0; i < sizeof(i64); ++i) { - i64 = (i64 << 8) | static_cast(key[i]); - } - return i64; -} - -// Converts a double value to an 8-byte string key, so that the string keys sort -// in the same order as the original double values. -// -0.0 and +0.0 convert to the same key. -void KeyFromDouble(double x, string* key) { - const uint64 n = UintFromIEEE754(x); - KeyFromUint64(n, key); -} - -// Version of KeyFromDouble that returns the key. -string DoubleToKey(double x) { - string key; - KeyFromDouble(x, &key); - return key; -} - -// Converts key generated by KeyFromDouble() back to double. -double KeyToDouble(StringPiece key) { - const uint64 n = KeyToUint64(key); - return IEEE754FromUint(n); -} - -// Converts a float value to a 4-byte string key, so that the string keys sort -// in the same order as the original float values. -// -0.0 and +0.0 convert to the same key. -void KeyFromFloat(float x, string* key) { - const uint32 n = UintFromIEEE754(x); - KeyFromUint32(n, key); -} - -// Version of KeyFromFloat that returns the key. -string FloatToKey(float x) { - string key; - KeyFromFloat(x, &key); - return key; -} - -// Converts key generated by FloatToKey() back to float. -float KeyToFloat(StringPiece key) { - const uint32 n = KeyToUint32(key); - return IEEE754FromUint(n); -} - -// Converts int32 to a 4-byte string key such that lexicographic -// ordering of strings is equivalent to sorting in increasing order by -// integer values. This can be useful when constructing secondary -void OrderedStringFromInt32(int32 i32, string* key) { - uint32 ui32 = static_cast(i32) ^ 0x80000000; - key->resize(sizeof(ui32)); - for (int i = sizeof(ui32) - 1; i >= 0; --i) { - (*key)[i] = ui32 & 0xff; - ui32 = (ui32 >> 8); - } -} - -string Int32ToOrderedString(int32 i32) { - string key; - OrderedStringFromInt32(i32, &key); - return key; -} - -// The inverse of the above function. -int32 OrderedStringToInt32(StringPiece key) { - uint32 ui32 = 0; - CHECK_EQ(key.size(), sizeof(ui32)); - for (int i = 0; i < sizeof(ui32); ++i) { - ui32 = (ui32 << 8); - ui32 = ui32 | static_cast(key[i]); - } - return static_cast(ui32 ^ 0x80000000); -} - -// Converts int64 to a 8-byte string key such that lexicographic -// ordering of strings is equivalent to sorting in increasing order by -// integer values. -void OrderedStringFromInt64(int64 i64, string* key) { - uint64 ui64 = static_cast(i64) ^ (GG_ULONGLONG(1) << 63); - key->resize(sizeof(ui64)); - for (int i = sizeof(ui64) - 1; i >= 0; --i) { - (*key)[i] = ui64 & 0xff; - ui64 = (ui64 >> 8); - } -} - -string Int64ToOrderedString(int64 i64) { - string key; - OrderedStringFromInt64(i64, &key); - return key; -} - -// The inverse of the above function. -int64 OrderedStringToInt64(StringPiece key) { - uint64 ui64 = 0; - CHECK_EQ(key.size(), sizeof(ui64)); - for (int i = 0; i < sizeof(ui64); ++i) { - ui64 = (ui64 << 8); - ui64 = ui64 | static_cast(key[i]); - } - return static_cast(ui64 ^ (GG_ULONGLONG(1) << 63)); -} - -// Converts int32 to a 4-byte string key such that lexicographic -// ordering of strings is equivalent to sorting in decreasing order -// by integer values. This can be useful when constructing secondary -void ReverseOrderedStringFromInt32(int32 i32, string* key) { - // ~ is like -, but works even for INT_MIN. (-INT_MIN == INT_MIN, - // but ~x = -x - 1, so ~INT_MIN = -INT_MIN - 1 = INT_MIN - 1 = INT_MAX). - OrderedStringFromInt32(~i32, key); -} - -string Int32ToReverseOrderedString(int32 i32) { - string key; - ReverseOrderedStringFromInt32(i32, &key); - return key; -} - -// The inverse of the above function. -int32 ReverseOrderedStringToInt32(StringPiece key) { - return ~OrderedStringToInt32(key); -} - -// Converts int64 to an 8-byte string key such that lexicographic -// ordering of strings is equivalent to sorting in decreasing order -// by integer values. This can be useful when constructing secondary -void ReverseOrderedStringFromInt64(int64 i64, string* key) { - return OrderedStringFromInt64(~i64, key); -} - -string Int64ToReverseOrderedString(int64 i64) { - string key; - ReverseOrderedStringFromInt64(i64, &key); - return key; -} - -// The inverse of the above function. -int64 ReverseOrderedStringToInt64(StringPiece key) { - return ~OrderedStringToInt64(key); -} - -// -------------------------------------------------------------------------- -// DictionaryInt32Encode -// DictionaryInt64Encode -// DictionaryDoubleEncode -// DictionaryInt32Decode -// DictionaryInt64Decode -// DictionaryDoubleDecode -// Routines to serialize/unserialize simple dictionaries -// (string->T hashmaps). We use ':' to separate keys and values, -// and commas to separate entries. -// -------------------------------------------------------------------------- - -string DictionaryInt32Encode(const hash_map* dictionary) { - vector entries; - for (hash_map::const_iterator iter = dictionary->begin(); - iter != dictionary->end(); ++iter) { - entries.push_back(StringPrintf("%s:%d", iter->first.c_str(), iter->second)); - } - return strings::Join(entries, ","); -} - -string DictionaryInt64Encode(const hash_map* dictionary) { - vector entries; - for (hash_map::const_iterator iter = dictionary->begin(); - iter != dictionary->end(); ++iter) { - entries.push_back(StringPrintf("%s:%" GG_LL_FORMAT "d", - iter->first.c_str(), iter->second)); - } - return strings::Join(entries, ","); -} - -string DictionaryDoubleEncode(const hash_map* dictionary) { - vector entries; - for (hash_map::const_iterator iter = dictionary->begin(); - iter != dictionary->end(); ++iter) { - entries.push_back(StringPrintf("%s:%g", iter->first.c_str(), iter->second)); - } - return strings::Join(entries, ","); -} - -bool DictionaryParse(const string& encoded_str, - vector >* items) { - vector entries; - SplitStringUsing(encoded_str, ",", &entries); +bool DictionaryParse(std::string const& encoded_str, + std::vector>* items) { + if (encoded_str.empty()) + return true; + std::vector const entries = strings::Split(encoded_str, ','); for (int i = 0; i < entries.size(); ++i) { - vector fields = strings::Split(entries[i], ":"); + std::vector const fields = strings::Split(entries[i], ':'); if (fields.size() != 2) // parsing error return false; items->push_back(std::make_pair(fields[0], fields[1])); } return true; } - -bool DictionaryInt32Decode(hash_map* dictionary, - const string& encoded_str) { - vector > items; - if (!DictionaryParse(encoded_str, &items)) - return false; - - dictionary->clear(); - for (int i = 0; i < items.size(); ++i) { - char *error = NULL; - const int32 value = strto32(items[i].second.c_str(), &error, 0); - if (error == items[i].second.c_str() || *error != '\0') { - // parsing error - return false; - } - (*dictionary)[items[i].first] = value; - } - return true; -} - -bool DictionaryInt64Decode(hash_map* dictionary, - const string& encoded_str) { - vector > items; - if (!DictionaryParse(encoded_str, &items)) - return false; - - dictionary->clear(); - for (int i = 0; i < items.size(); ++i) { - char *error = NULL; - const int64 value = strto64(items[i].second.c_str(), &error, 0); - if (error == items[i].second.c_str() || *error != '\0') { - // parsing error - return false; - } - (*dictionary)[items[i].first] = value; - } - return true; -} - - -bool DictionaryDoubleDecode(hash_map* dictionary, - const string& encoded_str) { - vector > items; - if (!DictionaryParse(encoded_str, &items)) - return false; - - dictionary->clear(); - for (int i = 0; i < items.size(); ++i) { - char *error = NULL; - const double value = strtod(items[i].second.c_str(), &error); - if (error == items[i].second.c_str() || *error != '\0') { - // parsing error - return false; - } - (*dictionary)[items[i].first] = value; - } - return true; -} \ No newline at end of file diff --git a/src/strings/serialize.h b/src/strings/serialize.h index 4a83a0db..81333658 100644 --- a/src/strings/serialize.h +++ b/src/strings/serialize.h @@ -1,4 +1,4 @@ -// Copyright 2010 Google Inc. All Rights Reserved. +// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,375 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// Author: jyrki@google.com (Jyrki Alakuijala) -// Refactored from contributions of various authors in strings/strutil.h -// -// This file contains conversion functions from various data types to -// strings and back. #ifndef STRINGS_SERIALIZE_H_ #define STRINGS_SERIALIZE_H_ -#include -#include -using __gnu_cxx::hash; -using __gnu_cxx::hash_map; #include -#include #include -#include "base/int128.h" -#include "base/integral_types.h" -#include -#include "base/type_traits.h" -#include "strings/stringpiece.h" -#include "util/endian/endian.h" -#include "util/gtl/stl_util.h" - -// Converts a 4-byte uint32 to a string such that the string keys sort in -// the same order as the original uint32 value. -// TODO(user): Rework all reinterpret_casts<> in this file. -inline void KeyFromUint32(uint32 u32, string* key) { - uint32 norder = ghtonl(u32); - key->assign(reinterpret_cast(&norder), sizeof(norder)); -} - -// Converts "fp" to an 8-byte string key -inline void KeyFromUint64(uint64 fp, string* key) { - uint64 norder = htonll(fp); - key->assign(reinterpret_cast(&norder), sizeof(norder)); -} - -// Converts a 16-byte uint128 to a string such that the string keys sort in -// the same order as the original uint128 value. -inline void KeyFromUint128(uint128 fp, string* key) { - uint64 norder[] = { htonll(Uint128High64(fp)), - htonll(Uint128Low64(fp)) - }; - key->assign(reinterpret_cast(norder), 2 * sizeof(norder[0])); -} - -// This version of KeyFromUint32 is less efficient but very convenient -string Uint32ToKey(uint32 u32); - -// This version of KeyFromUint64 is less efficient but very convenient -string Uint64ToKey(uint64 fp); - -// This version of KeyFromUint128 is less efficient but very convenient -string Uint128ToKey(uint128 u128); - -// Converts a 4-byte string key (typically generated by KeyFromUint32 or -// Uint32ToKey) into a uint32 value. -inline uint32 KeyToUint32(StringPiece key) { - uint32 value; - DCHECK_EQ(key.size(), sizeof(value)); - memcpy(&value, key.data(), sizeof(value)); - return gntohl(value); -} - -// Converts an 8-byte string key (typically generated by Uint64ToKey or -// KeyFromUint64) into a uint64 value -inline uint64 KeyToUint64(StringPiece key) { - uint64 value; - DCHECK_EQ(key.size(), sizeof(value)); - memcpy(&value, key.data(), sizeof(value)); - return ntohll(value); -} - -// Converts a 16-byte string key (typically generated by Uint128ToKey or -// KeyFromUint128) into a uint128 value -inline uint128 KeyToUint128(StringPiece key) { - uint64 v0, v1; - DCHECK_EQ(key.size(), sizeof(v0) + sizeof(v1)); - memcpy(&v0, key.data(), sizeof(v0)); - memcpy(&v1, key.data() + sizeof(v0), sizeof(v1)); - return uint128(ntohll(v0), ntohll(v1)); -} - -// Converts "i32" to a 4-byte string key -// NOTE: Lexicographic ordering of the resulting strings does not in -// general correspond to any natural ordering of the corresponding -// integers. For non-negative inputs, lexicographic ordering of the -// resulting strings corresponds to increasing ordering of the -// integers. However, negative inputs are sorted *after* the non-negative -// inputs. To obtain keys such that lexicographic ordering corresponds -// to the natural total order on the integers, use OrderedStringFromInt32() -// or ReverseOrderedStringFromInt32() instead. -void KeyFromInt32(int32 i32, string* key); - -// Convenient form of KeyFromInt32. -inline string Int32ToKey(int32 i32) { - string s; - KeyFromInt32(i32, &s); - return s; -} - -// Converts a 4-byte string key (typically generated by KeyFromInt32) -// into an int32 value -int32 KeyToInt32(StringPiece key); - -// Converts "i64" to a 8-byte string key -// NOTE: Lexicographic ordering of the resulting strings does not in -// general correspond to any natural ordering of the corresponding -// integers. For non-negative inputs, lexicographic ordering of the -// resulting strings corresponds to increasing ordering of the -// integers. However, negative inputs are sorted *after* the non-negative -// inputs. To obtain keys such that lexicographic ordering corresponds -// to the natural total order on the integers, use OrderedStringFromInt64() -// or ReverseOrderedStringFromInt64() instead. -void KeyFromInt64(int64 i64, string* key); - -// Convenient form of KeyFromInt64. -inline string Int64ToKey(int64 i64) { - string s; - KeyFromInt64(i64, &s); - return s; -} - -// Converts a 8-byte string key (typically generated by KeyFromInt64) into -// an int64 value. -int64 KeyToInt64(StringPiece key); - -// Converts a double value to an 8-byte string key, so that the string keys sort -// in the same order as the original double values. -// -0.0 and +0.0 convert to the same key. -void KeyFromDouble(double x, string* key); - -// Convenient form of KeyFromDouble. -string DoubleToKey(double x); - -// Converts key generated by KeyFromDouble() back to double. -double KeyToDouble(StringPiece key); - -// Converts a float value to a 4-byte string key, so that the string keys sort -// in the same order as the original float values. Floating-point format is -// IEEE 754. -// -0.0 and +0.0 convert to the same key. -void KeyFromFloat(float x, string* key); - -// Convenient form of KeyFromFloat. -string FloatToKey(float x); - -// Converts key generated by FloatToKey() back to float. -float KeyToFloat(StringPiece key); - -// Converts int32 to a 4-byte string key such that lexicographic -// ordering of strings is equivalent to sorting in increasing order by -// integer values. This can be useful when constructing secondary -void OrderedStringFromInt32(int32 i32, string* key); - -// This version of OrderedStringFromInt32 is less efficient but very convenient -string Int32ToOrderedString(int32 i32); - -// The inverse of the above function. -int32 OrderedStringToInt32(StringPiece key); - -// Converts int64 to an 8-byte string key such that lexicographic -// ordering of strings is equivalent to sorting in increasing order by -// integer values. -void OrderedStringFromInt64(int64 i64, string* key); - -// This version of OrderedStringFromInt64 is less efficient but very convenient -string Int64ToOrderedString(int64 i64); - -// The inverse of the above function. -int64 OrderedStringToInt64(StringPiece key); - -// Converts int32 to a 4-byte string key such that lexicographic -// ordering of strings is equivalent to sorting in decreasing order -// by integer values. This can be useful when constructing secondary -void ReverseOrderedStringFromInt32(int32 i32, string* key); - -// This version of ReverseOrderedStringFromInt32 is less efficient but very -string Int32ToReverseOrderedString(int32 i32); - -// The inverse of the above function. -int32 ReverseOrderedStringToInt32(StringPiece key); - -// Converts int64 to an 8-byte string key such that lexicographic -// ordering of strings is equivalent to sorting in decreasing order -// by integer values. This can be useful when constructing secondary -void ReverseOrderedStringFromInt64(int64 i64, string* key); - -// This version of ReverseOrderedStringFromInt64 is less efficient but very -string Int64ToReverseOrderedString(int64 i64); - -// The inverse of the above function. -int64 ReverseOrderedStringToInt64(StringPiece key); - -// Stores the bytes of a plain old data type value in a C++ string. -// Verifies the given data type is a POD and copies the bytes of the -// value into a newly created string. -// -// Can replace the use of Encode*, and avoid the use of castings, -// or adding additional functions for each type. -// For example, use: -// int32 i = 100; -// string s = EncodePOD(i); -// in place of: -// string s = EncodeUint32(static_cast(i)); -template inline string EncodePOD(const T& value) { - ENFORCE_POD(T); - string s; - STLStringResizeUninitialized(&s, sizeof(T)); - memcpy(string_as_array(&s), &value, sizeof(T)); - return s; -} - -// Retrieves the bytes of a plain old data type value from a StringPiece. -// Verifies the given data type is a POD and copies the bytes of the -// value from the given string. -// Returns true if the operation succeeded. -// Note that other than the data length, no check is (or can be) -// done on the type of data stored in the string. -// -// Can replace the use of Decode*, and avoid the use of castings, -// or adding additional functions for each type. -// For example, use: -// int32 i = 100; -// int32 j; -// string s = EncodePOD(i); -// CHECK(DecodePOD(s, &j)); -// in place of: -// string s = EncodeUint32(static_cast(i)); -// CHECK(DecodesUint32(s, static_cast(&j))); -template inline bool DecodePOD(StringPiece str, T* result) { - ENFORCE_POD(T); - CHECK(result != NULL); - if (sizeof(*result) != str.size()) { - return false; - } - memcpy(result, str.data(), sizeof(T)); - return true; -} - -// Stores the value bytes of a vector of plain old data type in a C++ string. -// Verifies the given data type is a POD and copies the bytes of each value -// in the vector into a newly created string. -template inline std::string EncodeVectorPOD(const std::vector& vec) { - ENFORCE_POD(T); - string s; - STLStringResizeUninitialized(&s, vec.size() * sizeof(T)); - typename std::vector::const_iterator iter; - char* ptr; - for (iter = vec.begin(), ptr = string_as_array(&s); - iter != vec.end(); - ++iter, ptr += sizeof(T)) { - memcpy(ptr, &(*iter), sizeof(T)); - } - return s; -} - -// Reconstructs a vector of a plain old data type values from a C++ string. -// Verifies the given data type is a POD and copies the bytes of each value -// from the given string to the given vector. -// Returns true if the operation succeeded. -// Note that other than the data length, no check is (or can be) -// done on the type of data stored in the string. -template inline bool DecodeVectorPOD(const string& str, - std::vector* result) { - ENFORCE_POD(T); - CHECK(result != NULL); - if (str.size() % sizeof(T) != 0) - return false; - result->clear(); - result->reserve(str.size() / sizeof(T)); - T value; - const char* begin = str.data(); - const char* end = str.data() + str.size(); - for (const char* ptr = begin; ptr != end; ptr += sizeof(T)) { - memcpy(&value, ptr, sizeof(T)); - result->push_back(value); - } - return true; -} - -// ---------------------------------------------------------------------- -// EncodeDouble() -// EncodeFloat() -// EncodeUint32() -// EncodeUint64() -// DecodeDouble() -// DecodeFloat() -// DecodeUint32() -// DecodeUint64() -// The Encode* functions store the bytes of ints, floats or doubles into the -// data bytes of a C++ string. The Decode* functions perform the reverse -// operations, but operate on a StringPiece rather than directly on a C++ -// string. They return true iff s contained the right number of bytes. -// -// These may be preferred to naked calls to EncodePOD/DecodePOD since -// they make the payload type explicit. -// Note that these encodings are NOT endian-neutral. -// ---------------------------------------------------------------------- -inline string EncodeDouble(double d) { - return EncodePOD(d); -} - -inline string EncodeFloat(float f) { - return EncodePOD(f); -} - -inline string EncodeUint32(uint32 i) { - return EncodePOD(i); -} - -inline string EncodeUint64(uint64 i) { - return EncodePOD(i); -} - -inline bool DecodeDouble(StringPiece s, double* d) { - return DecodePOD(s, d); -} - -inline bool DecodeFloat(StringPiece s, float* f) { - return DecodePOD(s, f); -} - -inline bool DecodeUint32(StringPiece s, uint32* i) { - return DecodePOD(s, i); -} - -inline bool DecodeUint64(StringPiece s, uint64* i) { - return DecodePOD(s, i); -} - -// ------------------------------------------------------------------------- -// DictionaryParse -// This routine parses a common dictionary format (key and value separated -// by ':', entries separated by commas). This format is used for many -// complex commandline flags. It is also used to encode dictionaries for -// exporting them or writing them to a checkpoint. Returns a vector of -// pairs. Returns true if there if no error in parsing, false -// otherwise. -// ------------------------------------------------------------------------- -bool DictionaryParse(const string& encoded_str, - std::vector >* items); - -// -------------------------------------------------------------------------- -// DictionaryInt32Encode -// DictionaryInt64Encode -// DictionaryDoubleEncode -// DictionaryInt32Decode -// DictionaryInt64Decode -// DictionaryDoubleDecode -// Routines to serialize/unserialize simple dictionaries -// (string->T hashmaps). These are useful for exporting, checkpointing etc -// *Decode routines clear the input dictionary. They return true if there -// was no error in decoding, false otherwise. -// Note: these routines are not meant for use with very large dictionaries. -// They are written for convenience and not efficiency. -// -------------------------------------------------------------------------- -string DictionaryInt32Encode(const hash_map* dictionary); -string DictionaryInt64Encode(const hash_map* dictionary); -string DictionaryDoubleEncode(const hash_map* dictionary); - -bool DictionaryInt32Decode(hash_map* dictionary, - const string& encoded_str); -bool DictionaryInt64Decode(hash_map* dictionary, - const string& encoded_str); -bool DictionaryDoubleDecode(hash_map* dictionary, - const string& encoded_str); - +bool DictionaryParse(std::string const& encoded_str, + std::vector>* items); -#endif // STRINGS_SERIALIZE_H_ \ No newline at end of file +#endif // STRINGS_SERIALIZE_H_ diff --git a/src/strings/split.cc b/src/strings/split.cc index 0c619602..9f024369 100644 --- a/src/strings/split.cc +++ b/src/strings/split.cc @@ -1,4 +1,4 @@ -// Copyright 2008 Google Inc. All Rights Reserved. +// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,962 +12,31 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// -// Maintainer: Greg Miller #include "strings/split.h" -#include -#include -#include -#include -#include - -#include "base/integral_types.h" -#include -#include "base/macros.h" -#include "base/strtoint.h" -#include "strings/ascii_ctype.h" -#include "strings/util.h" -#include "util/hash/hash.h" - -using std::vector; +#include +#include +#include +#include -// Implementations for some of the Split2 API. Much of the Split2 API is -// templated so it exists in header files, either strings/split.h or -// strings/split_internal.h. namespace strings { -namespace delimiter { - -namespace { - -// This GenericFind() template function encapsulates the finding algorithm -// shared between the Literal and AnyOf delimiters. The FindPolicy template -// parameter allows each delimiter to customize the actual find function to use -// and the length of the found delimiter. For example, the Literal delimiter -// will ultimately use StringPiece::find(), and the AnyOf delimiter will use -// StringPiece::find_first_of(). -template -StringPiece GenericFind( - StringPiece text, - StringPiece delimiter, - size_t pos, - FindPolicy find_policy) { - if (delimiter.empty() && text.length() > 0) { - // Special case for empty string delimiters: always return a zero-length - // StringPiece referring to the item at position 1 past pos. - return StringPiece(text.begin() + pos + 1, 0); - } - size_t found_pos = StringPiece::npos; - StringPiece found(text.end(), 0); // By default, not found - found_pos = find_policy.Find(text, delimiter, pos); - if (found_pos != StringPiece::npos) { - found.set(text.data() + found_pos, find_policy.Length(delimiter)); - } - return found; -} - -// Finds using StringPiece::find(), therefore the length of the found delimiter -// is delimiter.length(). -struct LiteralPolicy { - size_t Find(StringPiece text, StringPiece delimiter, size_t pos) { - return text.find(delimiter, pos); - } - size_t Length(StringPiece delimiter) { - return delimiter.length(); - } -}; -// Finds using StringPiece::find_first_of(), therefore the length of the found -// delimiter is 1. -struct AnyOfPolicy { - size_t Find(StringPiece text, StringPiece delimiter, size_t pos) { - return text.find_first_of(delimiter, pos); - } - size_t Length(StringPiece delimiter) { - return 1; +std::vector Split( + std::string const& text, char const delim, + std::function predicate) { + std::stringstream ss(text); + std::string item; + std::vector elems; + while (std::getline(ss, item, delim)) { + if (predicate(item)) + elems.push_back(std::move(item)); } -}; - -} // namespace - -// -// Literal -// - -Literal::Literal(StringPiece sp) : delimiter_(sp.ToString()) { -} - -StringPiece Literal::Find(StringPiece text, size_t pos) const { - return GenericFind(text, delimiter_, pos, LiteralPolicy()); -} - -// -// Single Char -// - -SingleChar::SingleChar(char c) : c_(c) {} - -StringPiece SingleChar::Find(StringPiece text, size_t pos) const { - size_t found_pos = text.find(c_, pos); - if (found_pos == StringPiece::npos) return StringPiece(text.end(), 0); - return StringPiece(text, found_pos, 1); -} - -// -// AnyOf -// - -AnyOf::AnyOf(StringPiece sp) : delimiters_(sp.ToString()) { -} - -StringPiece AnyOf::Find(StringPiece text, size_t pos) const { - return GenericFind(text, delimiters_, pos, AnyOfPolicy()); -} - -// -// FixedLength -// -FixedLength::FixedLength(int length) : length_(length) { - CHECK_GT(length, 0); + return elems; } -StringPiece FixedLength::Find(StringPiece text, size_t pos) const { - StringPiece substr(text, pos); - // If the string is shorter than the chunk size we say we - // "can't find the delimiter" so this will be the last chunk. - if (substr.length() <= length_) - return StringPiece(text.end(), 0); - - return StringPiece(substr.begin() + length_, 0); +std::vector Split(std::string const& text, char const delim) { + return Split(text, delim, [](const std::string&) { return true; }); } -} // namespace delimiter } // namespace strings - -// -// ==================== LEGACY SPLIT FUNCTIONS ==================== -// - -using ::strings::SkipEmpty; -using ::strings::delimiter::AnyOf; -using ::strings::delimiter::Limit; - -namespace { - -// Appends the results of a split to the specified container. This function has -// the following overloads: -// - vector - for better performance -// - hash_map - to change append semantics -template -void AppendToImpl(Container* container, Splitter splitter) { - Container c = splitter; // Calls implicit conversion operator. - std::copy(c.begin(), c.end(), std::inserter(*container, container->end())); -} - -// Overload of AppendToImpl() that is optimized for appending to vector. -// This version eliminates a couple string copies by using a vector -// as the intermediate container. -template -void AppendToImpl(vector* container, Splitter splitter) { - vector vsp = splitter; // Calls implicit conversion operator. - size_t container_size = container->size(); - container->resize(container_size + vsp.size()); - for (size_t i = 0; i < vsp.size(); ++i) { - vsp[i].CopyToString(&(*container)[container_size++]); - } -} - -// Overload of AppendToImpl() for hash_map so that duplicate keys *do* overwrite -// the previous values, which is not the default behavior with a normal -// std::inserter for maps. -// -// map m; -// m.insert(std::make_pair("a", "1")); -// m.insert(std::make_pair("a", "2")); // <-- doesn't actually insert. -// ASSERT_EQ(m["a"], "1"); // <-- "a" has value "1" not "2". -template -void AppendToImpl(hash_map* map_container, Splitter splitter) { - typedef hash_map Map; - Map tmp = splitter; // Calls implicit conversion operator. - for (typename Map::const_iterator it = tmp.begin(); it != tmp.end(); ++it) { - (*map_container)[it->first] = it->second; - } -} - -// Appends the results of a call to strings::Split() to the specified container. -// This function is used with the new strings::Split() API to implement the -// append semantics of the legacy Split*() functions. -// -// The "Splitter" template parameter is intended to be a -// ::strings::internal::Splitter<>, which is the return value of a call to -// strings::Split(). Sample usage: -// -// vector v; -// ... add stuff to "v" ... -// AppendTo(&v, strings::Split("a,b,c", ",")); -// -template -void AppendTo(Container* container, Splitter splitter) { - if (container->empty()) { - // "Appending" to an empty container is by far the common case. For this we - // assign directly to the output container, which is more efficient than - // explicitly appending. - *container = splitter; // Calls implicit conversion operator. - } else { - AppendToImpl(container, splitter); - } -} - -} // anonymous namespace - -// Constants for ClipString() -static const int kMaxOverCut = 12; -// The ellipsis to add to strings that are too long -static const char kCutStr[] = "..."; -static const int kCutStrSize = sizeof(kCutStr) - 1; - -// ---------------------------------------------------------------------- -// Return the place to clip the string at, or -1 -// if the string doesn't need to be clipped. -// ---------------------------------------------------------------------- -static int ClipStringHelper(const char* str, int max_len, bool use_ellipsis) { - if (strlen(str) <= max_len) - return -1; - - int max_substr_len = max_len; - - if (use_ellipsis && max_len > kCutStrSize) { - max_substr_len -= kCutStrSize; - } - - const char* cut_by = - (max_substr_len < kMaxOverCut ? str : str + max_len - kMaxOverCut); - const char* cut_at = str + max_substr_len; - while (!ascii_isspace(*cut_at) && cut_at > cut_by) - cut_at--; - - if (cut_at == cut_by) { - // No space was found - return max_substr_len; - } else { - return cut_at-str; - } -} - -// ---------------------------------------------------------------------- -// ClipString -// Clip a string to a max length. We try to clip on a word boundary -// if this is possible. If the string is clipped, we append an -// ellipsis. -// ---------------------------------------------------------------------- -void ClipString(string* full_str, int max_len) { - int cut_at = ClipStringHelper(full_str->c_str(), max_len, true); - if (cut_at != -1) { - full_str->erase(cut_at); - if (max_len > kCutStrSize) { - full_str->append(kCutStr); - } - } -} - -void SplitStringIntoNPiecesAllowEmpty(const string& full, - const char* delim, - int pieces, - vector* result) { - if (pieces == 0) { - // No limit when pieces is 0. - AppendTo(result, strings::Split(full, AnyOf(delim))); - } else { - // The input argument "pieces" specifies the max size that *result should - // be. However, the argument to the Limit() delimiter is the max number of - // delimiters, which should be one less than "pieces". Example: "a,b,c" has - // 3 pieces and two comma delimiters. - int limit = std::max(pieces - 1, 0); - AppendTo(result, strings::Split(full, Limit(AnyOf(delim), limit))); - } -} - -// ---------------------------------------------------------------------- -// SplitStringAllowEmpty -// Split a string using a character delimiter. Append the components -// to 'result'. If there are consecutive delimiters, this function -// will return corresponding empty strings. -// ---------------------------------------------------------------------- -void SplitStringAllowEmpty(const string& full, const char* delim, - vector* result) { - AppendTo(result, strings::Split(full, AnyOf(delim))); -} - -void SplitStringUsing(const string& full, - const char* delim, - vector* result) { - AppendTo(result, strings::Split(full, AnyOf(delim), strings::SkipEmpty())); -} - -void SplitStringToHashsetUsing(const string& full, const char* delim, - hash_set* result) { - AppendTo(result, strings::Split(full, AnyOf(delim), strings::SkipEmpty())); -} - -void SplitStringToSetUsing(const string& full, const char* delim, - std::set* result) { - AppendTo(result, strings::Split(full, AnyOf(delim), strings::SkipEmpty())); -} - -void SplitStringToHashmapUsing(const string& full, const char* delim, - hash_map* result) { - AppendTo(result, strings::Split(full, AnyOf(delim), strings::SkipEmpty())); -} - -// ---------------------------------------------------------------------- -// SplitStringPieceToVector() -// Split a StringPiece into sub-StringPieces based on delim -// and appends the pieces to 'vec'. -// If omit empty strings is true, empty strings are omitted -// from the resulting vector. -// ---------------------------------------------------------------------- -void SplitStringPieceToVector(StringPiece full, - const char* delim, - vector* vec, - bool omit_empty_strings) { - if (omit_empty_strings) { - AppendTo(vec, strings::Split(full, AnyOf(delim), SkipEmpty())); - } else { - AppendTo(vec, strings::Split(full, AnyOf(delim))); - } -} - -void SplitToVector(char* full, const char* delim, vector* vec, - bool omit_empty_strings) { - char* next = full; - while ((next = gstrsep(&full, delim)) != NULL) { - if (omit_empty_strings && next[0] == '\0') continue; - vec->push_back(next); - } - // Add last element (or full string if no delimeter found): - if (full != NULL) { - vec->push_back(full); - } -} - -void SplitToVector(char* full, const char* delim, vector* vec, - bool omit_empty_strings) { - char* next = full; - while ((next = gstrsep(&full, delim)) != NULL) { - if (omit_empty_strings && next[0] == '\0') continue; - vec->push_back(next); - } - // Add last element (or full string if no delimeter found): - if (full != NULL) { - vec->push_back(full); - } -} - -// ---------------------------------------------------------------------- -// SplitOneStringToken() -// Mainly a stringified wrapper around strpbrk() -// ---------------------------------------------------------------------- -string SplitOneStringToken(const char ** source, const char * delim) { - assert(source); - assert(delim); - if (!*source) { - return string(); - } - const char * begin = *source; - // Optimize the common case where delim is a single character. - if (delim[0] != '\0' && delim[1] == '\0') { - *source = strchr(*source, delim[0]); - } else { - *source = strpbrk(*source, delim); - } - if (*source) { - return string(begin, (*source)++); - } else { - return string(begin); - } -} - -// ---------------------------------------------------------------------- -// SplitStringWithEscaping() -// SplitStringWithEscapingAllowEmpty() -// SplitStringWithEscapingToSet() -// SplitStringWithWithEscapingToHashset() -// Split the string using the specified delimiters, taking escaping into -// account. '\' is not allowed as a delimiter. -// ---------------------------------------------------------------------- -template -static inline -void SplitStringWithEscapingToIterator(IN_ITER first, IN_ITER last, - const strings::CharSet& delimiters, - OUT_ITER result) { - CHECK(!delimiters.Test('\\')) << "\\ is not allowed as a delimiter."; - string part; - - for ( ; first != last; ++first) { - char current_char = *first; - if (delimiters.Test(current_char)) { - // Push substrings when we encounter delimiters. - if (allow_empty || !part.empty()) { - *result++ = part; - part.clear(); - } - continue; - } - if (current_char != '\\') { - // Just a normal character. - part.push_back(current_char); - continue; - } - // We have read a backslash: look ahead if possible. - if (++first == last) { - // Trailing backslash. Nothing to peek at, just push it and stop. - part.push_back('\\'); - break; - } - current_char = *first; - // The next delimiter or backslash is literal. - if (current_char != '\\' && !delimiters.Test(current_char)) { - // Don't honor unknown escape sequences: emit \f for \f. - part.push_back('\\'); - } - part.push_back(current_char); - } - // Push the trailing part. - if (allow_empty || !part.empty()) { - *result++ = part; - } -} - -template -static inline -void SplitStringWithEscapingToContainer(const IN_CONTAINER& src, - const strings::CharSet& delimiters, - OUT_CONTAINER *result) { - SplitStringWithEscapingToIterator( - src.begin(), src.end(), delimiters, - std::inserter(*result, result->end())); -} - -void SplitStringWithEscaping(StringPiece full, - const strings::CharSet& delimiters, - vector *result) { - SplitStringWithEscapingToContainer(full, delimiters, result); -} - -void SplitStringWithEscapingAllowEmpty(StringPiece full, - const strings::CharSet& delimiters, - vector *result) { - SplitStringWithEscapingToContainer(full, delimiters, result); -} - -void SplitStringWithEscapingToSet(StringPiece full, - const strings::CharSet& delimiters, - std::set *result) { - SplitStringWithEscapingToContainer(full, delimiters, result); -} - -void SplitStringWithEscapingToHashset(StringPiece full, - const strings::CharSet& delimiters, - hash_set *result) { - SplitStringWithEscapingToContainer(full, delimiters, result); -} - - -// ---------------------------------------------------------------------- -// SplitOneIntToken() -// SplitOneInt32Token() -// SplitOneUint32Token() -// SplitOneInt64Token() -// SplitOneUint64Token() -// SplitOneDoubleToken() -// SplitOneFloatToken() -// SplitOneDecimalIntToken() -// SplitOneDecimalInt32Token() -// SplitOneDecimalUint32Token() -// SplitOneDecimalInt64Token() -// SplitOneDecimalUint64Token() -// SplitOneHexUint32Token() -// SplitOneHexUint64Token() -// Mainly a stringified wrapper around strtol/strtoul/strtod -// ---------------------------------------------------------------------- -// Curried functions for the macro below -static inline long strto32_0(const char * source, char ** end) { - return strto32(source, end, 0); } -static inline unsigned long strtou32_0(const char * source, char ** end) { - return strtou32(source, end, 0); } -static inline int64 strto64_0(const char * source, char ** end) { - return strto64(source, end, 0); } -static inline uint64 strtou64_0(const char * source, char ** end) { - return strtou64(source, end, 0); } -static inline long strto32_10(const char * source, char ** end) { - return strto32(source, end, 10); } -static inline unsigned long strtou32_10(const char * source, char ** end) { - return strtou32(source, end, 10); } -static inline int64 strto64_10(const char * source, char ** end) { - return strto64(source, end, 10); } -static inline uint64 strtou64_10(const char * source, char ** end) { - return strtou64(source, end, 10); } -static inline uint32 strtou32_16(const char * source, char ** end) { - return strtou32(source, end, 16); } -static inline uint64 strtou64_16(const char * source, char ** end) { - return strtou64(source, end, 16); } - -#define DEFINE_SPLIT_ONE_NUMBER_TOKEN(name, type, function) \ -bool SplitOne##name##Token(const char ** source, const char * delim, \ - type * value) { \ - assert(source); \ - assert(delim); \ - assert(value); \ - if (!*source) \ - return false; \ - /* Parse int */ \ - char * end; \ - *value = function(*source, &end); \ - if (end == *source) \ - return false; /* number not present at start of string */ \ - if (end[0] && !strchr(delim, end[0])) \ - return false; /* Garbage characters after int */ \ - /* Advance past token */ \ - if (*end != '\0') \ - *source = const_cast(end+1); \ - else \ - *source = NULL; \ - return true; \ -} - -DEFINE_SPLIT_ONE_NUMBER_TOKEN(Int, int, strto32_0) -DEFINE_SPLIT_ONE_NUMBER_TOKEN(Int32, int32, strto32_0) -DEFINE_SPLIT_ONE_NUMBER_TOKEN(Uint32, uint32, strtou32_0) -DEFINE_SPLIT_ONE_NUMBER_TOKEN(Int64, int64, strto64_0) -DEFINE_SPLIT_ONE_NUMBER_TOKEN(Uint64, uint64, strtou64_0) -DEFINE_SPLIT_ONE_NUMBER_TOKEN(Double, double, strtod) -#ifdef _MSC_VER // has no strtof() -// Note: does an implicit cast to float. -DEFINE_SPLIT_ONE_NUMBER_TOKEN(Float, float, strtod) -#else -DEFINE_SPLIT_ONE_NUMBER_TOKEN(Float, float, strtof) -#endif -DEFINE_SPLIT_ONE_NUMBER_TOKEN(DecimalInt, int, strto32_10) -DEFINE_SPLIT_ONE_NUMBER_TOKEN(DecimalInt32, int32, strto32_10) -DEFINE_SPLIT_ONE_NUMBER_TOKEN(DecimalUint32, uint32, strtou32_10) -DEFINE_SPLIT_ONE_NUMBER_TOKEN(DecimalInt64, int64, strto64_10) -DEFINE_SPLIT_ONE_NUMBER_TOKEN(DecimalUint64, uint64, strtou64_10) -DEFINE_SPLIT_ONE_NUMBER_TOKEN(HexUint32, uint32, strtou32_16) -DEFINE_SPLIT_ONE_NUMBER_TOKEN(HexUint64, uint64, strtou64_16) - - -// ---------------------------------------------------------------------- -// SplitRange() -// Splits a string of the form "-". Either or both can be -// missing. A raw number () is interpreted as "-". Modifies -// parameters insofar as they're specified by the string. RETURNS -// true iff the input is a well-formed range. If it RETURNS false, -// from and to remain unchanged. The range in rangestr should be -// terminated either by "\0" or by whitespace. -// ---------------------------------------------------------------------- - -#define EOS(ch) ( (ch) == '\0' || ascii_isspace(ch) ) -bool SplitRange(const char* rangestr, int* from, int* to) { - // We need to do the const-cast because strol takes a char**, not const char** - char* val = const_cast(rangestr); - if (val == NULL || EOS(*val)) return true; // we'll say nothingness is ok - - if ( val[0] == '-' && EOS(val[1]) ) // CASE 1: - - return true; // nothing changes - - if ( val[0] == '-' ) { // CASE 2: - - const int int2 = strto32(val+1, &val, 10); - if ( !EOS(*val) ) return false; // not a valid integer - *to = int2; // only "to" changes - return true; - - } else { - const int int1 = strto32(val, &val, 10); - if ( EOS(*val) || (*val == '-' && EOS(*(val+1))) ) { - *from = int1; // CASE 3: , same as - - return true; // only "from" changes - } else if (*val != '-') { // not a valid range - return false; - } - const int int2 = strto32(val+1, &val, 10); - if ( !EOS(*val) ) return false; // not a valid integer - *from = int1; // CASE 4: - - *to = int2; - return true; - } -} - -void SplitCSVLineWithDelimiter(char* line, char delimiter, - vector* cols) { - char* end_of_line = line + strlen(line); - char* end; - char* start; - - for (; line < end_of_line; line++) { - // Skip leading whitespace, unless said whitespace is the delimiter. - while (ascii_isspace(*line) && *line != delimiter) - ++line; - - if (*line == '"' && delimiter == ',') { // Quoted value... - start = ++line; - end = start; - for (; *line; line++) { - if (*line == '"') { - line++; - if (*line != '"') // [""] is an escaped ["] - break; // but just ["] is end of value - } - *end++ = *line; - } - // All characters after the closing quote and before the comma - // are ignored. - line = strchr(line, delimiter); - if (!line) line = end_of_line; - } else { - start = line; - line = strchr(line, delimiter); - if (!line) line = end_of_line; - // Skip all trailing whitespace, unless said whitespace is the delimiter. - for (end = line; end > start; --end) { - if (!ascii_isspace(end[-1]) || end[-1] == delimiter) - break; - } - } - const bool need_another_column = - (*line == delimiter) && (line == end_of_line - 1); - *end = '\0'; - cols->push_back(start); - // If line was something like [paul,] (comma is the last character - // and is not proceeded by whitespace or quote) then we are about - // to eliminate the last column (which is empty). This would be - // incorrect. - if (need_another_column) - cols->push_back(end); - - assert(*line == '\0' || *line == delimiter); - } -} - -void SplitCSVLine(char* line, vector* cols) { - SplitCSVLineWithDelimiter(line, ',', cols); -} - -void SplitCSVLineWithDelimiterForStrings(const string &line, - char delimiter, - vector *cols) { - // Unfortunately, the interface requires char* instead of const char* - // which requires copying the string. - char *cline = strndup_with_new(line.c_str(), line.size()); - vector v; - SplitCSVLineWithDelimiter(cline, delimiter, &v); - for (vector::const_iterator ci = v.begin(); ci != v.end(); ++ci) { - cols->push_back(*ci); - } - delete[] cline; -} - -// ---------------------------------------------------------------------- -namespace { - -// Helper class used by SplitStructuredLineInternal. -class ClosingSymbolLookup { - public: - explicit ClosingSymbolLookup(const char* symbol_pairs) - : closing_(), - valid_closing_() { - // Initialize the opening/closing arrays. - for (const char* symbol = symbol_pairs; *symbol != 0; ++symbol) { - unsigned char opening = *symbol; - ++symbol; - // If the string ends before the closing character has been found, - // use the opening character as the closing character. - unsigned char closing = *symbol != 0 ? *symbol : opening; - closing_[opening] = closing; - valid_closing_[closing] = true; - if (*symbol == 0) break; - } - } - - // Returns the closing character corresponding to an opening one, - // or 0 if the argument is not an opening character. - char GetClosingChar(char opening) const { - return closing_[static_cast(opening)]; - } - - // Returns true if the argument is a closing character. - bool IsClosing(char c) const { - return valid_closing_[static_cast(c)]; - } - - private: - // Maps an opening character to its closing. If the entry contains 0, - // the character is not in the opening set. - char closing_[256]; - // Valid closing characters. - bool valid_closing_[256]; - - DISALLOW_COPY_AND_ASSIGN(ClosingSymbolLookup); -}; - -char* SplitStructuredLineInternal(char* line, - char delimiter, - const char* symbol_pairs, - vector* cols, - bool with_escapes) { - ClosingSymbolLookup lookup(symbol_pairs); - - // Stack of symbols expected to close the current opened expressions. - vector expected_to_close; - bool in_escape = false; - - CHECK(cols); - cols->push_back(line); - char* current; - for (current = line; *current; ++current) { - char c = *current; - if (in_escape) { - in_escape = false; - } else if (with_escapes && c == '\\') { - // We are escaping the next character. Note the escape still appears - // in the output. - in_escape = true; - } else if (expected_to_close.empty() && c == delimiter) { - // We don't have any open expression, this is a valid separator. - *current = 0; - cols->push_back(current + 1); - } else if (!expected_to_close.empty() && c == expected_to_close.back()) { - // Can we close the currently open expression? - expected_to_close.pop_back(); - } else if (lookup.GetClosingChar(c)) { - // If this is an opening symbol, we open a new expression and push - // the expected closing symbol on the stack. - expected_to_close.push_back(lookup.GetClosingChar(c)); - } else if (lookup.IsClosing(c)) { - // Error: mismatched closing symbol. - return current; - } - } - if (!expected_to_close.empty()) { - return current; // Missing closing symbol(s) - } - return NULL; // Success -} - -bool SplitStructuredLineInternal(StringPiece line, - char delimiter, - const char* symbol_pairs, - vector* cols, - bool with_escapes) { - ClosingSymbolLookup lookup(symbol_pairs); - - // Stack of symbols expected to close the current opened expressions. - vector expected_to_close; - bool in_escape = false; - - CHECK_NOTNULL(cols); - cols->push_back(line); - for (int i = 0; i < line.size(); ++i) { - char c = line[i]; - if (in_escape) { - in_escape = false; - } else if (with_escapes && c == '\\') { - // We are escaping the next character. Note the escape still appears - // in the output. - in_escape = true; - } else if (expected_to_close.empty() && c == delimiter) { - // We don't have any open expression, this is a valid separator. - cols->back().remove_suffix(line.size() - i); - cols->push_back(StringPiece(line, i + 1)); - } else if (!expected_to_close.empty() && c == expected_to_close.back()) { - // Can we close the currently open expression? - expected_to_close.pop_back(); - } else if (lookup.GetClosingChar(c)) { - // If this is an opening symbol, we open a new expression and push - // the expected closing symbol on the stack. - expected_to_close.push_back(lookup.GetClosingChar(c)); - } else if (lookup.IsClosing(c)) { - // Error: mismatched closing symbol. - return false; - } - } - if (!expected_to_close.empty()) { - return false; // Missing closing symbol(s) - } - return true; // Success -} - -} // anonymous namespace - -char* SplitStructuredLine(char* line, - char delimiter, - const char *symbol_pairs, - vector* cols) { - return SplitStructuredLineInternal(line, delimiter, symbol_pairs, cols, - false); -} - -bool SplitStructuredLine(StringPiece line, - char delimiter, - const char* symbol_pairs, - vector* cols) { - return SplitStructuredLineInternal(line, delimiter, symbol_pairs, cols, - false); -} - -char* SplitStructuredLineWithEscapes(char* line, - char delimiter, - const char *symbol_pairs, - vector* cols) { - return SplitStructuredLineInternal(line, delimiter, symbol_pairs, cols, - true); -} - -bool SplitStructuredLineWithEscapes(StringPiece line, - char delimiter, - const char* symbol_pairs, - vector* cols) { - return SplitStructuredLineInternal(line, delimiter, symbol_pairs, cols, - true); -} - - -// ---------------------------------------------------------------------- -// SplitStringIntoKeyValues() -// ---------------------------------------------------------------------- -bool SplitStringIntoKeyValues(const string& line, - const string& key_value_delimiters, - const string& value_value_delimiters, - string *key, vector *values) { - key->clear(); - values->clear(); - - // find the key string - int end_key_pos = line.find_first_of(key_value_delimiters); - if (end_key_pos == string::npos) { - VLOG(1) << "cannot parse key from line: " << line; - return false; // no key - } - key->assign(line, 0, end_key_pos); - - // find the values string - string remains(line, end_key_pos, line.size() - end_key_pos); - int begin_values_pos = remains.find_first_not_of(key_value_delimiters); - if (begin_values_pos == string::npos) { - VLOG(1) << "cannot parse value from line: " << line; - return false; // no value - } - string values_string(remains, - begin_values_pos, - remains.size() - begin_values_pos); - - // construct the values vector - if (value_value_delimiters.empty()) { // one value - values->push_back(values_string); - } else { // multiple values - SplitStringUsing(values_string, value_value_delimiters.c_str(), values); - if (values->size() < 1) { - VLOG(1) << "cannot parse value from line: " << line; - return false; // no value - } - } - return true; -} - -bool SplitStringIntoKeyValuePairs( - const string& line, - const string& key_value_delimiters, - const string& key_value_pair_delimiters, - vector >* kv_pairs) { - kv_pairs->clear(); - - vector pairs; - if (key_value_pair_delimiters.empty()) { - pairs.push_back(line); - } else { - SplitStringUsing(line, key_value_pair_delimiters.c_str(), &pairs); - } - - bool success = true; - for (size_t i = 0; i < pairs.size(); ++i) { - string key; - vector value; - if (!SplitStringIntoKeyValues(pairs[i], - key_value_delimiters, - "", &key, &value)) { - // Don't return here, to allow for keys without associated - // values; just record that our split failed. - success = false; - } - // we expect atmost one value because we passed in an empty vsep to - // SplitStringIntoKeyValues - DCHECK_LE(value.size(), 1); - kv_pairs->push_back(std::make_pair(key, value.empty() ? "" : value[0])); - } - return success; -} - -// ---------------------------------------------------------------------- -// SplitLeadingDec32Values() -// SplitLeadingDec64Values() -// A simple parser for space-separated decimal int32/int64 values. -// Appends parsed integers to the end of the result vector, stopping -// at the first unparsable spot. Skips past leading and repeated -// whitespace (does not consume trailing whitespace), and returns -// a pointer beyond the last character parsed. -// -------------------------------------------------------------------- -const char* SplitLeadingDec32Values(const char *str, vector *result) { - for (;;) { - char *end = NULL; - long value = strtol(str, &end, 10); - if (end == str) - break; - // Limit long values to int32 min/max. Needed for lp64. - if (value > std::numeric_limits::max()) { - value = std::numeric_limits::max(); - } else if (value < std::numeric_limits::min()) { - value = std::numeric_limits::min(); - } - result->push_back(value); - str = end; - if (!ascii_isspace(*end)) - break; - } - return str; -} - -const char* SplitLeadingDec64Values(const char *str, vector *result) { - for (;;) { - char *end = NULL; - const int64 value = strtoll(str, &end, 10); - if (end == str) - break; - result->push_back(value); - str = end; - if (!ascii_isspace(*end)) - break; - } - return str; -} - -void SplitStringToLines(const char* full, - int max_len, - int num_lines, - vector* result) { - if (max_len <= 0) { - return; - } - int pos = 0; - for (int i = 0; (i < num_lines || num_lines <= 0); i++) { - int cut_at = ClipStringHelper(full+pos, max_len, (i == num_lines - 1)); - if (cut_at == -1) { - result->push_back(string(full+pos)); - return; - } - result->push_back(string(full+pos, cut_at)); - if (i == num_lines - 1 && max_len > kCutStrSize) { - result->at(i).append(kCutStr); - } - pos += cut_at; - } -} \ No newline at end of file diff --git a/src/strings/split.h b/src/strings/split.h index 79fd16bd..b1b72a12 100644 --- a/src/strings/split.h +++ b/src/strings/split.h @@ -1,4 +1,4 @@ -// Copyright 2008 Google Inc. All Rights Reserved. +// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,1231 +12,25 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// -// #status: RECOMMENDED -// #category: operations on strings -// #summary: Functions for splitting strings into substrings. -// -// This file contains functions for splitting strings. The new and recommended -// API for string splitting is the strings::Split() function. The old API is a -// large collection of standalone functions declared at the bottom of this file -// in the global scope. See go/split2 for details about why we built a new -// splitting API. -// + #ifndef STRINGS_SPLIT_H_ #define STRINGS_SPLIT_H_ -#include -#include -#include -using __gnu_cxx::hash; -using __gnu_cxx::hash_map; -#include -using __gnu_cxx::hash; -using __gnu_cxx::hash_set; -#include -#include +#include #include -#include #include -#include "base/integral_types.h" -#include -#include "strings/charset.h" -#include "strings/split_internal.h" -#include "strings/stringpiece.h" -#include "strings/strip.h" - namespace strings { -// The new Split API -// aka Split2 -// aka strings::Split() -// -// This string splitting API consists of a Split() function in the ::strings -// namespace and a handful of delimiter objects in the ::strings::delimiter -// namespace (more on delimiter objects below). The Split() function always -// takes two arguments: the text to be split and the delimiter on which to split -// the text. An optional third argument may also be given, which is a Predicate -// functor that will be used to filter the results, e.g., to skip empty strings -// (more on predicates below). The Split() function adapts the returned -// collection to the type specified by the caller. -// -// Example 1: -// // Splits the given string on commas. Returns the results in a -// // vector of strings. -// vector v = strings::Split("a,b,c", ","); // Could also use ',' -// assert(v.size() == 3); -// -// Example 2: -// // By default, empty strings are *included* in the output. See the -// // strings::SkipEmpty predicate below to omit them. -// vector v = strings::Split("a,b,,c", ","); -// assert(v.size() == 4); // "a", "b", "", "c" -// v = strings::Split("", ","); -// assert(v.size() == 1); // v contains a single "" -// -// Example 3: -// // Splits the string as in the previous example, except that the results -// // are returned as StringPiece objects. Note that because we are storing -// // the results within StringPiece objects, we have to ensure that the input -// // string outlives any results. -// vector v = strings::Split("a,b,c", ","); -// assert(v.size() == 3); -// -// Example 4: -// // Stores results in a set. -// set a = strings::Split("a,b,c,a,b,c", ","); -// assert(a.size() == 3); -// -// Example 5: -// // Stores results in a map. The map implementation assumes that the input -// // is provided as a series of key/value pairs. For example, the 0th element -// // resulting from the split will be stored as a key to the 1st element. If -// // an odd number of elements are resolved, the last element is paired with -// // a default-constructed value (e.g., empty string). -// map m = strings::Split("a,b,c", ","); -// assert(m.size() == 2); -// assert(m["a"] == "b"); -// assert(m["c"] == ""); // last component value equals "" -// -// Example 6: -// // Splits on the empty string, which results in each character of the input -// // string becoming one element in the output collection. -// vector v = strings::Split("abc", ""); -// assert(v.size() == 3); -// -// Example 7: -// // Stores first two split strings as the members in an std::pair. -// std::pair p = strings::Split("a,b,c", ","); -// EXPECT_EQ("a", p.first); -// EXPECT_EQ("b", p.second); -// // "c" is omitted because std::pair can hold only two elements. -// -// As illustrated above, the Split() function adapts the returned collection to -// the type specified by the caller. The returned collections may contain -// string, StringPiece, Cord, or any object that has a constructor (explicit or -// not) that takes a single StringPiece argument. This pattern works for all -// standard STL containers including vector, list, deque, set, multiset, map, -// and multimap, non-standard containers including hash_set and hash_map, and -// even std::pair which is not actually a container. -// -// Splitting to std::pair is an interesting case because it can hold only two -// elements and is not a collection type. When splitting to an std::pair the -// first two split strings become the std::pair's .first and .second members -// respectively. The remaining split substrings are discarded. If there are less -// than two split substrings, the empty string is used for the corresponding -// std::pair member. -// -// The strings::Split() function can be used multiple times to perform more -// complicated splitting logic, such as intelligently parsing key-value pairs. -// For example -// -// // The input string "a=b=c,d=e,f=,g" becomes -// // { "a" => "b=c", "d" => "e", "f" => "", "g" => "" } -// map m; -// for (StringPiece sp : strings::Split("a=b=c,d=e,f=,g", ",")) { -// m.insert(strings::Split(sp, strings::delimiter::Limit("=", 1))); -// } -// EXPECT_EQ("b=c", m.find("a")->second); -// EXPECT_EQ("e", m.find("d")->second); -// EXPECT_EQ("", m.find("f")->second); -// EXPECT_EQ("", m.find("g")->second); -// -// The above example stores the results in an std::map. But depending on your -// data requirements, you can just as easily store the results in an -// std::multimap or even a vector>. -// -// -// Delimiters -// -// The Split() function also takes a second argument that is a delimiter. This -// delimiter is actually an object that defines the boundaries between elements -// in the provided input. If a string (const char*, ::string, or StringPiece) is -// passed in place of an explicit Delimiter object, the argument is implicitly -// converted to a ::strings::delimiter::Literal. -// -// With this split API comes the formal concept of a Delimiter (big D). A -// Delimiter is an object with a Find() function that knows how find the first -// occurrence of itself in a given StringPiece. Models of the Delimiter concept -// represent specific kinds of delimiters, such as single characters, -// substrings, or even regular expressions. -// -// The following Delimiter objects are provided as part of the Split() API: -// -// - Literal (default for string arguments) -// - SingleChar (default for char argument) -// - AnyOf -// - Limit -// - FixedLength -// -// In addition to these: -// -// - //util/regexp/re2:delimiter provides the re2::Delimiter class for -// splitting strings using regular expressions. -// -// - //i18n/utf8:strutil provides delimiters for utf8-oriented splitting. -// -// The following are examples of using some provided Delimiter objects: -// -// Example 1: -// // Because a string literal is converted to a strings::delimiter::Literal, -// // the following two splits are equivalent. -// vector v1 = strings::Split("a,b,c", ","); // (1) -// using ::strings::delimiter::Literal; -// vector v2 = strings::Split("a,b,c", Literal(",")); // (2) -// -// Example 2: -// // Because a char literal is converted to a strings::delimiter::SingleChar, -// // the following two splits are equivalent. -// vector v1 = strings::Split("a,b,c", ','); // (1) -// using ::strings::delimiter::SingleChar; -// vector v2 = strings::Split("a,b,c", SingleChar(',')); // (2) -// -// Example 3: -// // Splits on any of the characters specified in the delimiter string. -// using ::strings::delimiter::AnyOf; -// vector v = strings::Split("a,b;c-d", AnyOf(",;-")); -// assert(v.size() == 4); -// -// Example 4: -// // Uses the Limit meta-delimiter to limit the number of matches a delimiter -// // can have. In this case, the delimiter of a Literal comma is limited to -// // matching at most one time. The last element in the returned collection -// // will contain all unsplit pieces, which may contain instances of the -// // delimiter. -// using ::strings::delimiter::Limit; -// vector v = strings::Split("a,b,c", Limit(",", 1)); -// assert(v.size() == 2); // Limited to 1 delimiter; so two elements found -// assert(v[0] == "a"); -// assert(v[1] == "b,c"); -// -// Example 5: -// // Splits into equal-length substrings. -// using ::strings::delimiter::FixedLength; -// vector v = strings::Split("12345", FixedLength(2)); -// assert(v.size() == 3); -// assert(v[0] == "12"); -// assert(v[1] == "34"); -// assert(v[2] == "5"); -// -// Predicates -// -// Predicates can filter the results of a Split() operation by determining -// whether or not a resultant element is included in the result set. A predicate -// may be passed as an *optional* third argument to the Split() function. -// -// Predicates are unary functions (or functors) that take a single StringPiece -// argument and return bool indicating whether the argument should be included -// (true) or excluded (false). -// -// One example where this is useful is when filtering out empty substrings. By -// default, empty substrings may be returned by strings::Split(), which is -// similar to the way split functions work in other programming languages. For -// example: -// -// // Empty strings *are* included in the returned collection. -// vector v = strings::Split(",a,,b,", ","); -// assert(v.size() == 5); // v[0] == "", v[1] == "a", v[2] == "", ... -// -// These empty strings can be filtered out of the results by simply passing the -// provided SkipEmpty predicate as the third argument to the Split() function. -// SkipEmpty does not consider a string containing all whitespace to be empty. -// For that behavior use the SkipWhitespace predicate. For example: -// -// Example 1: -// // Uses SkipEmpty to omit empty strings. Strings containing whitespace are -// // not empty and are therefore not skipped. -// using strings::SkipEmpty; -// vector v = strings::Split(",a, ,b,", ",", SkipEmpty()); -// assert(v.size() == 3); -// assert(v[0] == "a"); -// assert(v[1] == " "); // <-- The whitespace makes the string not empty. -// assert(v[2] == "b"); -// -// Example 2: -// // Uses SkipWhitespace to skip all strings that are either empty or contain -// // only whitespace. -// using strings::SkipWhitespace; -// vector v = strings::Split(",a, ,b,", ",", SkipWhitespace()); -// assert(v.size() == 2); -// assert(v[0] == "a"); -// assert(v[1] == "b"); -// -// -// Differences between Split1 and Split2 -// -// Split2 is the strings::Split() API described above. Split1 is a name for the -// collection of legacy Split*() functions declared later in this file. Most of -// the Split1 functions follow a set of conventions that don't necessarily match -// the conventions used in Split2. The following are some of the important -// differences between Split1 and Split2: -// -// Split1 -> Split2 -// ---------------- -// Append -> Assign: -// The Split1 functions all returned their output collections via a pointer to -// an out parameter as is typical in Google code. In some cases the comments -// explicitly stated that results would be *appended* to the output -// collection. In some cases it was ambiguous whether results were appended. -// This ambiguity is gone in the Split2 API as results are always assigned to -// the output collection, never appended. -// -// AnyOf -> Literal: -// Most Split1 functions treated their delimiter argument as a string of -// individual byte delimiters. For example, a delimiter of ",;" would split on -// "," and ";", not the substring ",;". This behavior is equivalent to the -// Split2 delimiter strings::delimiter::AnyOf, which is *not* the default. By -// default, strings::Split() splits using strings::delimiter::Literal() which -// would treat the whole string ",;" as a single delimiter string. -// -// SkipEmpty -> allow empty: -// Most Split1 functions omitted empty substrings in the results. To keep -// empty substrings one would have to use an explicitly named -// Split*AllowEmpty() function. This behavior is reversed in Split2. By -// default, strings::Split() *allows* empty substrings in the output. To skip -// them, use the strings::SkipEmpty predicate. -// -// string -> user's choice: -// Most Split1 functions return collections of string objects. Some return -// char*, but the type returned is dictated by each Split1 function. With -// Split2 the caller can choose which string-like object to return. (Note: -// char* C-strings are not supported in Split2--use StringPiece instead). -// +std::vector Split( + std::string const& text, char delim, + std::function predicate); +std::vector Split(std::string const& text, char delim); -namespace delimiter { -// A Delimiter object tells the splitter where a string should be broken. Some -// examples are breaking a string wherever a given character or substring is -// found, wherever a regular expression matches, or simply after a fixed length. -// All Delimiter objects must have the following member function: -// -// StringPiece Find(StringPiece text, size_t pos); -// -// A Delimiter's Find() member function will be passed the input text that is to -// be split and the position to begin searching for the next delimiter in the -// input text. The returned StringPiece should refer to the next occurrence -// (after pos) of the represented delimiter; this returned StringPiece -// represents the next location where the input string should be broken. The -// returned StringPiece may be zero-length if the Delimiter does not represent a -// part of the string (e.g., a fixed-length delimiter). If no delimiter is found -// in the given text, a zero-length StringPiece referring to text.end() should -// be returned (e.g., StringPiece(text.end(), 0)). It is important that the -// returned StringPiece always be within the bounds of input text given as an -// argument--it must not refer to a string that is physically located outside of -// the given string. -// -// The following example is a simple Delimiter object that is created with a -// single char and will look for that char in the text passed to the Find() -// function: -// -// struct SimpleDelimiter { -// const char c_; -// explicit SimpleDelimiter(char c) : c_(c) {} -// StringPiece Find(StringPiece text, size_t pos) { -// auto found = text.find(c_, pos); -// if (found == StringPiece::npos) return StringPiece(text.end(), 0); -// return StringPiece(text, found, 1); -// } -// }; - -// Represents a literal string delimiter. The delimiter string is copied and -// owned by this class. Examples: -// -// using ::strings::delimiter::Literal; -// vector v = strings::Split("a=>b=>c", Literal("=>")); -// assert(v.size() == 3); -// assert(v[0] == "a"); -// assert(v[1] == "b"); -// assert(v[2] == "c"); -// -// The next example uses the empty string as a delimiter. -// -// using ::strings::delimiter::Literal; -// vector v = strings::Split("abc", Literal("")); -// assert(v.size() == 3); -// assert(v[0] == "a"); -// assert(v[1] == "b"); -// assert(v[2] == "c"); -// -// This is the *default* delimiter used if a literal string or string-like -// object is used where a Delimiter object is expected. For example, the -// following calls are equivalent. -// -// vector v = strings::Split("a,b", ","); -// vector v = strings::Split("a,b", strings::delimiter::Literal(",")); -// -class Literal { - public: - explicit Literal(StringPiece sp); - StringPiece Find(StringPiece text, size_t pos) const; - - private: - const string delimiter_; -}; - -// Represents a single character delimiter. -// -// using ::strings::delimiter::SingleChar; -// vector v = strings::Split("a-b-c", SingleChar('-')); -// assert(v.size() == 3); -// assert(v[0] == "a"); -// assert(v[1] == "b"); -// assert(v[2] == "c"); -// -// This is also the *default* delimiter used if a single character is given as -// the delimiter to the strings::Split() function. For example, the following -// calls are equivalent. -// -// vector v = strings::Split("a-b", '-'); -// -// using ::strings::delimiter::SingleChar; -// vector v = strings::Split("a-b", SingleChar('-')); -// -class SingleChar { - public: - explicit SingleChar(char c); - StringPiece Find(StringPiece text, size_t pos) const; - - private: - char c_; -}; - -namespace internal { -// A traits-like metafunction for selecting the default Delimiter object type -// for a particular Delimiter type. The base case simply exposes type Delimiter -// itself as the delimiter's Type. However, there are specializations for -// string-like objects that map them to the Literal delimiter object. This -// allows functions like strings::Split() and strings::delimiter::Limit() to -// accept string-like objects (e.g., ",") as delimiter arguments but they will -// be treated as if a Literal delimiter was given. -template -struct SelectDelimiter { - typedef Delimiter Type; -}; -template <> struct SelectDelimiter { typedef SingleChar Type; }; -template <> struct SelectDelimiter { typedef Literal Type; }; -template <> struct SelectDelimiter { typedef Literal Type; }; -template <> struct SelectDelimiter { typedef Literal Type; }; -template <> struct SelectDelimiter { typedef Literal Type; }; -#if defined(HAS_GLOBAL_STRING) -template <> struct SelectDelimiter { typedef Literal Type; }; -#endif -} // namespace internal - -// Represents a delimiter that will match any of the given byte-sized -// characters. AnyOf is similar to Literal, except that AnyOf uses -// StringPiece::find_first_of() and Literal uses StringPiece::find(). AnyOf -// examples: -// -// using ::strings::delimiter::AnyOf; -// vector v = strings::Split("a,b=c", AnyOf(",=")); -// -// assert(v.size() == 3); -// assert(v[0] == "a"); -// assert(v[1] == "b"); -// assert(v[2] == "c"); -// -// If AnyOf is given the empty string, it behaves exactly like Literal and -// matches each individual character in the input string. -// -// Note: The string passed to AnyOf is assumed to be a string of single-byte -// ASCII characters. AnyOf does not work with multi-byte characters. -class AnyOf { - public: - explicit AnyOf(StringPiece sp); - StringPiece Find(StringPiece text, size_t pos) const; - - private: - const string delimiters_; -}; - -// A delimiter for splitting into equal-length strings. The length argument to -// the constructor must be greater than 0. This delimiter works with ascii -// string data, but does not work with variable-width encodings, such as UTF-8. -// Examples: -// -// using ::strings::delimiter::FixedLength; -// vector v = strings::Split("123456789", FixedLength(3)); -// assert(v.size() == 3); -// assert(v[0] == "123"); -// assert(v[1] == "456"); -// assert(v[2] == "789"); -// -// Note that the string does not have to be a multiple of the fixed split -// length. In such a case, the last substring will be shorter. -// -// using ::strings::delimiter::FixedLength; -// vector v = strings::Split("12345", FixedLength(2)); -// assert(v.size() == 3); -// assert(v[0] == "12"); -// assert(v[1] == "34"); -// assert(v[2] == "5"); -// -class FixedLength { - public: - explicit FixedLength(int length); - StringPiece Find(StringPiece text, size_t pos) const; - - private: - const int length_; -}; - -// Wraps another delimiter and sets a max number of matches for that delimiter. -// Create LimitImpls using the Limit() function. Example: -// -// using ::strings::delimiter::Limit; -// vector v = strings::Split("a,b,c,d", Limit(",", 2)); -// -// assert(v.size() == 3); // Split on 2 commas, giving a vector with 3 items -// assert(v[0] == "a"); -// assert(v[1] == "b"); -// assert(v[2] == "c,d"); -// -template -class LimitImpl { - public: - LimitImpl(Delimiter delimiter, int limit) - : delimiter_(delimiter), limit_(limit), count_(0) {} - StringPiece Find(StringPiece text, size_t pos) { - if (count_++ == limit_) { - return StringPiece(text.end(), 0); // No more matches. - } - return delimiter_.Find(text, pos); - } - - private: - Delimiter delimiter_; - const int limit_; - int count_; -}; - -// Limit() function to create LimitImpl<> objects. -template -inline LimitImpl::Type> - Limit(Delimiter delim, int limit) { - typedef typename internal::SelectDelimiter::Type DelimiterType; - return LimitImpl(DelimiterType(delim), limit); -} - -} // namespace delimiter - -// -// Predicates are functors that return bool indicating whether the given -// StringPiece should be included in the split output. If the predicate returns -// false then the string will be excluded from the output from strings::Split(). -// - -// Always returns true, indicating that all strings--including empty -// strings--should be included in the split output. This predicate is not -// strictly needed because this is the default behavior of the strings::Split() -// function. But it might be useful at some call sites to make the intent -// explicit. -// -// vector v = Split(" a , ,,b,", ",", AllowEmpty()); -// EXPECT_THAT(v, ElementsAre(" a ", " ", "", "b", "")); -struct AllowEmpty { - bool operator()(StringPiece sp) const { - return true; - } -}; - -// Returns false if the given StringPiece is empty, indicating that the -// strings::Split() API should omit the empty string. -// -// vector v = Split(" a , ,,b,", ",", SkipEmpty()); -// EXPECT_THAT(v, ElementsAre(" a ", " ", "b")); struct SkipEmpty { - bool operator()(StringPiece sp) const { - return !sp.empty(); - } + bool operator()(std::string const& s) { return !s.empty(); } }; -// Returns false if the given StringPiece is empty or contains only whitespace, -// indicating that the strings::Split() API should omit the string. -// -// vector v = Split(" a , ,,b,", ",", SkipWhitespace()); -// EXPECT_THAT(v, ElementsAre(" a ", "b")); -struct SkipWhitespace { - bool operator()(StringPiece sp) const { - StripWhitespace(&sp); - return !sp.empty(); - } -}; - -// Definitions of the main Split() function. The use of SelectDelimiter<> allows -// these functions to be called with a Delimiter template parameter that is an -// actual Delimiter object (e.g., Literal or AnyOf), OR called with a -// string-like delimiter argument, (e.g., ","), in which case the delimiter used -// will default to strings::delimiter::Literal. -// -// In C++11 mode, ConvertibleToStringPiece extends the lifetime of temporary -// strings passed to it. In C++98 mode, temporary strings only live to the end -// of the current statement, but this is less of a problem without range-based -// for loops and auto. -template -inline internal::Splitter< - typename delimiter::internal::SelectDelimiter::Type> -Split(internal::ConvertibleToStringPiece text, Delimiter d) { - typedef typename delimiter::internal::SelectDelimiter::Type - DelimiterType; - return internal::Splitter(&text, DelimiterType(d)); -} - -template -inline internal::Splitter< - typename delimiter::internal::SelectDelimiter::Type, Predicate> -Split(internal::ConvertibleToStringPiece text, Delimiter d, Predicate p) { - typedef typename delimiter::internal::SelectDelimiter::Type - DelimiterType; - return internal::Splitter(&text, DelimiterType(d), - p); -} - } // namespace strings -// ---------------------------------------------------------------------- -// Clips a string to a max length. We try to clip on a word boundary if this is -// possible. If the string is clipped, we append an ellipsis. -// -// ***NOTE*** -// ClipString counts length with strlen. If you have non-ASCII strings like -// UTF-8, this is wrong. If you are displaying the clipped strings to users in -// a frontend, consider using ClipStringOnWordBoundary in -// webserver/util/snippets/rewriteboldtags, which considers the width of the -// string, not just the number of bytes. -// -// TODO(user) Move ClipString back to strutil. The problem with this is -// that ClipStringHelper is used behind the scenes by SplitStringToLines, but -// probably shouldn't be exposed in the .h files. -// ---------------------------------------------------------------------- -void ClipString(string* full_str, int max_len); - -// ---------------------------------------------------------------------- -// SplitStringToLines() Split a string into lines of maximum length -// 'max_len'. Append the resulting lines to 'result'. Will attempt -// to split on word boundaries. If 'num_lines' -// is zero it splits up the whole string regardless of length. If -// 'num_lines' is positive, it returns at most num_lines lines, and -// appends a "..." to the end of the last line if the string is too -// long to fit completely into 'num_lines' lines. -// ---------------------------------------------------------------------- -void SplitStringToLines(const char* full, - int max_len, - int num_lines, - std::vector* result); - -// ---------------------------------------------------------------------- -// DEPRECATED(jgm): Use strings::Split() instead, e.g.,: -// std::pair p = -// strings::Split("a-b-c", strings::delimiter::Limit("-", 1)) -// // p.first = "a" -// // p.second = "b-c" -// -// See the strings::Split() documentation above for more details. -// -// SplitOneStringToken() -// Returns the first "delim" delimited string from "*source" and modifies -// *source to point after the delimiter that was found. If no delimiter is -// found, *source is set to NULL. -// -// If the start of *source is a delimiter, an empty string is returned. -// If *source is NULL, an empty string is returned. -// -// "delim" is treated as a sequence of 1 or more character delimiters. Any one -// of the characters present in "delim" is considered to be a single -// delimiter; the delimiter is not "delim" as a whole. For example: -// -// const char* s = "abc=;de"; -// string r = SplitOneStringToken(&s, ";="); -// // r = "abc" -// // s points to ";de" -// ---------------------------------------------------------------------- -string SplitOneStringToken(const char** source, const char* delim); - -// ---------------------------------------------------------------------- -// DEPRECATED(jgm): Use strings::Split() instead, e.g.,: -// vector v = strings::Split(text, delim) -// -// See the strings::Split() documentation above for more details. -// -// SplitToVector() -// Split a string into substrings based on the nul-terminated list -// of bytes at delim (uses strsep) and appends the split -// strings to 'vec'. Modifies "full". If omit empty strings is -// true, empty strings are omitted from the resulting vector. -// ---------------------------------------------------------------------- -void SplitToVector(char* full, const char* delimiters, - std::vector* vec, - bool omit_empty_strings); -void SplitToVector(char* full, const char* delimiters, - std::vector* vec, - bool omit_empty_strings); - -// ---------------------------------------------------------------------- -// DEPRECATED(jgm): Use strings::Split() instead, e.g.,: -// vector v = strings::Split(text, delim) -// -// See the strings::Split() documentation above for more details. -// -// SplitStringPieceToVector -// Split a StringPiece into sub-StringPieces based on the -// nul-terminated list of bytes at delim and appends the -// pieces to 'vec'. If omit empty strings is true, empty strings -// are omitted from the resulting vector. -// Expects the original string (from which 'full' is derived) to exist -// for the full lifespan of 'vec'. -// ---------------------------------------------------------------------- -void SplitStringPieceToVector(StringPiece full, - const char* delim, - std::vector* vec, - bool omit_empty_strings); - -// ---------------------------------------------------------------------- -// DEPRECATED(jgm): Use strings::Split() instead, e.g.,: -// vector v = strings::Split(text, delim, strings::SkipEmpty()) -// -// See the strings::Split() documentation above for more details. -// -// SplitStringUsing() -// SplitStringToHashsetUsing() -// SplitStringToSetUsing() -// SplitStringToHashmapUsing() - -// Splits 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 skips over all of them: in other words, -// empty components are dropped. If you want to keep empty components, try -// SplitStringAllowEmpty(). -// -// NOTE: Do not use this for multi-byte delimiters such as UTF-8 strings. Use -// strings::Split() with strings::delimiter::Literal as the delimiter. -// -// ==> NEW API: Use the new Split API defined above. <== -// Example: -// -// using strings::SkipEmpty; -// using strings::Split; -// using strings::delimiter::AnyOf; -// -// vector v = Split(full, AnyOf(delimiter), SkipEmpty()); -// -// For even better performance, store the result in a vector -// to avoid string copies. -// ---------------------------------------------------------------------- -void SplitStringUsing(const string& full, const char* delimiters, - std::vector* result); -void SplitStringToHashsetUsing(const string& full, const char* delimiters, - hash_set* result); -void SplitStringToSetUsing(const string& full, const char* delimiters, - std::set* result); -// The even-positioned (0-based) components become the keys for the -// odd-positioned components that follow them. When there is an odd -// number of components, the value for the last key will be unchanged -// if the key was already present in the hash table, or will be the -// empty string if the key is a newly inserted key. -void SplitStringToHashmapUsing(const string& full, const char* delim, - hash_map* result); - -// ---------------------------------------------------------------------- -// DEPRECATED(jgm): Use strings::Split() instead, e.g.,: -// vector v = strings::Split(text, delim) -// -// See the strings::Split() documentation above for more details. -// -// SplitStringAllowEmpty() -// -// 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. -// -// ==> NEW API: Use the new Split API defined above. <== -// -// using strings::Split; -// using strings::delimiter::AnyOf; -// -// vector v = Split(full, AnyOf(delimiter)); -// -// For even better performance, store the result in a vector to -// avoid string copies. -// ---------------------------------------------------------------------- -void SplitStringAllowEmpty(const string& full, const char* delim, - std::vector* result); - -// ---------------------------------------------------------------------- -// SplitStringWithEscaping() -// SplitStringWithEscapingAllowEmpty() -// SplitStringWithEscapingToSet() -// SplitStringWithEscapingToHashset() - -// Split the string using the specified delimiters, taking escaping into -// account. '\' is not allowed as a delimiter. -// -// Within the string, preserve a delimiter preceded by a backslash as a -// literal delimiter. In addition, preserve two consecutive backslashes as -// a single literal backslash. Do not unescape any other backslash-character -// sequence. -// -// Eg. 'foo\=bar=baz\\qu\ux' split on '=' becomes ('foo=bar', 'baz\qu\ux') -// -// All versions other than "AllowEmpty" discard any empty substrings. -// ---------------------------------------------------------------------- -void SplitStringWithEscaping(StringPiece full, - const strings::CharSet& delimiters, - std::vector* result); -void SplitStringWithEscapingAllowEmpty(StringPiece full, - const strings::CharSet& delimiters, - std::vector* result); -void SplitStringWithEscapingToSet(StringPiece full, - const strings::CharSet& delimiters, - std::set* result); -void SplitStringWithEscapingToHashset(StringPiece full, - const strings::CharSet& delimiters, - hash_set* result); - -// ---------------------------------------------------------------------- -// DEPRECATED(jgm): Use strings::Split() instead, e.g.,: -// vector v = strings::Split(text, strings::delimiter::Limit("-", N)) -// -// See the strings::Split() documentation above for more details. -// -// SplitStringIntoNPiecesAllowEmpty() -// Split a string using a nul-terminated list of byte -// delimiters. 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. -// ---------------------------------------------------------------------- -void SplitStringIntoNPiecesAllowEmpty(const string& full, - const char* delimiters, - int pieces, - std::vector* result); - -// ---------------------------------------------------------------------- -// SplitStringAndParse() -// SplitStringAndParseToContainer() -// SplitStringAndParseToList() -// Split a string using a nul-terminated list of character -// delimiters. For each component, parse using the provided -// parsing function and if successful, append it to 'result'. -// Return true if and only if all components parse successfully. -// If there are consecutive delimiters, this function skips over -// all of them. This function will correctly handle parsing -// strings that have embedded \0s. -// -// SplitStringAndParse fills into a vector. -// SplitStringAndParseToContainer fills into any container that implements -// a single-argument insert function. (i.e. insert(const value_type& x) ). -// SplitStringAndParseToList fills into any container that implements a single- -// argument push_back function (i.e. push_back(const value_type& x) ), plus -// value_type& back() and pop_back(). -// NOTE: This implementation relies on parsing in-place into the "back()" -// reference, so its performance may depend on the efficiency of back(). -// -// Example Usage (verified in split_test.cc): -// vector values; -// CHECK(SplitStringAndParse("1.0,2.0,3.0", ",", &safe_strtod, &values)); -// CHECK_EQ(3, values.size()); -// -// vector values; -// CHECK(SplitStringAndParse("1M,2M,3M", ",", -// &HumanReadableNumBytes::ToInt64, &values)); -// CHECK_EQ(3, values.size()); -// -// set values; -// CHECK(SplitStringAndParseToContainer("3,1,1,2", ",", -// &safe_strto64, &values)); -// CHECK_EQ(3, values.size()); // set<> retains only unique values -// -// deque values; -// CHECK(SplitStringAndParseToList("3,1,1,2", ",", &safe_strto64, &values)); -// CHECK_EQ(4, values.size()); -// ---------------------------------------------------------------------- -template -bool SplitStringAndParse(StringPiece source, StringPiece delim, - bool (*parse)(const string& str, T* value), - std::vector* result); -template -bool SplitStringAndParseToContainer( - StringPiece source, StringPiece delim, - bool (*parse)(const string& str, typename Container::value_type* value), - Container* result); - -template -bool SplitStringAndParseToList( - StringPiece source, StringPiece delim, - bool (*parse)(const string& str, typename List::value_type* value), - List* result); -// ---------------------------------------------------------------------- -// SplitRange() -// Splits a string of the form "-". Either or both can be -// missing. A raw number () is interpreted as "-". Modifies -// parameters insofar as they're specified by the string. RETURNS -// true iff the input is a well-formed range. If it RETURNS false, -// from and to remain unchanged. The range in rangestr should be -// terminated either by "\0" or by whitespace. -// ---------------------------------------------------------------------- -bool SplitRange(const char* rangestr, int* from, int* to); - -// ---------------------------------------------------------------------- -// LEGACY(jgm): The SplitCSV* functions are no longer recommended. -// Use util::csv::Parser defined in util/csv/Parser.h instead. -// -// Example: To parse a single line: -// #include "util/csv/parser.h" -// vector fields = util::csv::ParseLine(line).fields(); -// -// Example: To parse an entire file: -// #include "util/csv/parser.h" -// for (const util::csv::Record& rec : Parser(source)) { -// vector fields = rec.fields(); -// } -// -// SplitCSVLineWithDelimiter() -// CSV lines come in many guises. There's the Comma Separated Values -// variety, in which fields are separated by (surprise!) commas. There's -// also the tab-separated values variant, in which tabs separate the -// fields. This routine handles both. For both delimiters, whitespace is -// trimmed from either side of the field value. If the delimiter is ',', we -// play additional games with quotes. A field value surrounded by double -// quotes is allowed to contain commas, which are not treated as field -// separators. Within a double-quoted string, a series of two double quotes -// signals an escaped single double quote. It'll be clearer in the examples. -// Example: -// Google , x , "Buchheit, Paul", "string with "" quote in it" -// --> [Google], [x], [Buchheit, Paul], [string with " quote in it] -// -// SplitCSVLine() -// A convenience wrapper around SplitCSVLineWithDelimiter which uses -// ',' as the delimiter. -// -// ---------------------------------------------------------------------- -void SplitCSVLine(char* line, std::vector* cols); -void SplitCSVLineWithDelimiter(char* line, char delimiter, - std::vector* cols); -// SplitCSVLine string wrapper that internally makes a copy of string line. -void SplitCSVLineWithDelimiterForStrings(const string& line, char delimiter, - std::vector* cols); - -// ---------------------------------------------------------------------- -// SplitStructuredLine() -// Splits a line using the given delimiter, and places the columns into -// 'cols'. If the symbol_pair string has an odd number of characters, the -// last character (which cannot be paired) will be assumed to be both an -// opening and closing symbol. -// WARNING : The input string 'line' is destroyed in the process. -// The function returns 0 if the line was parsed correctly (i.e all the -// opened braces had their closing braces) otherwise, it returns the position -// of the error. -// Example: -// SplitStructuredLine("item1,item2,{subitem1,subitem2},item4,[5,{6,7}]", -// ',', -// "{}[]", &output) -// --> output = { "item1", "item2", "{subitem1,subitem2}", "item4", -// "[5,{6,7}]" } -// Example2: trying to split "item1,[item2,{4,5],5}" will fail and the -// function will return the position of the problem : ] -// -// ---------------------------------------------------------------------- -char* SplitStructuredLine(char* line, - char delimiter, - const char* symbol_pairs, - std::vector* cols); - -// Similar to the function with the same name above, but splits a StringPiece -// into StringPiece parts. Returns true if successful. -bool SplitStructuredLine(StringPiece line, - char delimiter, - const char* symbol_pairs, - std::vector* cols); - -// ---------------------------------------------------------------------- -// SplitStructuredLineWithEscapes() -// Like SplitStructuredLine but also allows characters to be escaped. -// -// WARNING: the escape characters will be replicated in the output -// columns rather than being consumed, i.e. if {} were the opening and -// closing symbols, using \{ to quote a curly brace in the middle of -// an option would pass this unchanged. -// -// Example: -// SplitStructuredLineWithEscapes( -// "\{item1\},it\\em2,{\{subitem1\},sub\\item2},item4\,item5,[5,{6,7}]", -// ',', -// "{}[]", -// &output) -// --> output = { "\{item1\}", "it\\em2", "{\{subitem1\},sub\\item2}", -// "item4\,item5", "[5,{6,7}]" } -// -// ---------------------------------------------------------------------- -char* SplitStructuredLineWithEscapes(char* line, - char delimiter, - const char* symbol_pairs, - std::vector* cols); - -// Similar to the function with the same name above, but splits a StringPiece -// into StringPiece parts. Returns true if successful. -bool SplitStructuredLineWithEscapes(StringPiece line, - char delimiter, - const char* symbol_pairs, - std::vector* cols); - -// ---------------------------------------------------------------------- -// DEPRECATED(jgm): Use strings::Split() instead, e.g.,: -// using strings::delimiter::Limit; -// -// // kv.first is the key; kv.second contains all the values -// std::pair kv = strings::Split(text, Limit(kv_delim, 1)); -// vector values = Split(kv.second, vv_delim); -// -// See the strings::Split() documentation above for more details. -// -// SplitStringIntoKeyValues() -// Split a line into a key string and a vector of value strings. The line has -// the following format: -// -// +*++...* -// -// where key and value are strings; */+ means zero/one or more; is -// a delimiter character to separate key and value; and is a delimiter -// character to separate between values. The user can specify a bunch of -// delimiter characters using a string. For example, if the user specifies -// the separator string as "\t ", then either ' ' or '\t' or any combination -// of them wil be treated as separator. For , the user can specify a -// empty string to indicate there is only one value. -// -// Note: this function assumes the input string begins exactly with a -// key. Therefore, if you use whitespaces to separate key and value, you -// should not let whitespace precedes the key in the input. Otherwise, you -// will get an empty string as the key. -// -// A line with no will return an empty string as the key, even if -// is non-empty! -// -// The syntax makes it impossible for a value to be the empty string. -// It is possible for the number of values to be zero. -// -// Returns false if the line has no or if the number of values is -// zero. -// -// ---------------------------------------------------------------------- -bool SplitStringIntoKeyValues(const string& line, - const string& key_value_delimiters, - const string& value_value_delimiters, - string* key, std::vector* values); - -// ---------------------------------------------------------------------- -// DEPRECATED(jgm): Use strings::Split() instead, e.g.,: -// using strings::delimiter::Limit; -// -// vector> pairs; // or even map -// for (StringPiece sp : strings::Split(line, pair_delim)) { -// pairs.push_back(strings::Split(sp, Limit(kv_delim, 1))); -// } -// -// See the strings::Split() documentation above for more details. -// -// SplitStringIntoKeyValuePairs() -// Split a line into a vector of pairs. The line has -// the following format: -// -// *+++...* -// -// Where key and value are strings; */+ means zero/one or more. is -// a delimiter character to separate key and value and is a delimiter -// character to separate key value pairs. The user can specify a bunch of -// delimiter characters using a string. -// -// Note: this function assumes each key-value pair begins exactly with a -// key. Therefore, if you use whitespaces to separate key and value, you -// should not let whitespace precede the key in the pair. Otherwise, you -// will get an empty string as the key. -// -// A pair with no will return empty strings as the key and value, -// even if is non-empty! -// -// Returns false for pairs with no specified and for pairs with -// empty strings as values. -// -// ---------------------------------------------------------------------- -bool SplitStringIntoKeyValuePairs( - const string& line, - const string& key_value_delimiters, - const string& key_value_pair_delimiters, - std::vector >* kv_pairs); - - -// ---------------------------------------------------------------------- -// SplitLeadingDec32Values() -// SplitLeadingDec64Values() -// A simple parser for space-separated decimal int32/int64 values. -// Appends parsed integers to the end of the result vector, stopping -// at the first unparsable spot. Skips past leading and repeated -// whitespace (does not consume trailing whitespace), and returns -// a pointer beyond the last character parsed. -// -------------------------------------------------------------------- -const char* SplitLeadingDec32Values(const char* next, - std::vector* result); -const char* SplitLeadingDec64Values(const char* next, - std::vector* result); - -// ---------------------------------------------------------------------- -// SplitOneIntToken() -// SplitOneInt32Token() -// SplitOneUint32Token() -// SplitOneInt64Token() -// SplitOneUint64Token() -// SplitOneDoubleToken() -// SplitOneFloatToken() -// Parse a single "delim" delimited number from "*source" into "*value". -// Modify *source to point after the delimiter. -// If no delimiter is present after the number, set *source to NULL. -// -// If the start of *source is not an number, return false. -// If the int is followed by the null character, return true. -// If the int is not followed by a character from delim, return false. -// If *source is NULL, return false. -// -// They cannot handle decimal numbers with leading 0s, since they will be -// treated as octal. -// ---------------------------------------------------------------------- -bool SplitOneIntToken(const char** source, const char* delim, - int* value); -bool SplitOneInt32Token(const char** source, const char* delim, - int32* value); -bool SplitOneUint32Token(const char** source, const char* delim, - uint32* value); -bool SplitOneInt64Token(const char** source, const char* delim, - int64* value); -bool SplitOneUint64Token(const char** source, const char* delim, - uint64* value); -bool SplitOneDoubleToken(const char** source, const char* delim, - double* value); -bool SplitOneFloatToken(const char** source, const char* delim, - float* value); - -// Some aliases, so that the function names are standardized against the names -// of the reflection setters/getters in proto2. This makes it easier to use -// certain macros with reflection when creating custom text formats for protos. - -inline bool SplitOneUInt32Token(const char** source, const char* delim, - uint32* value) { - return SplitOneUint32Token(source, delim, value); -} - -inline bool SplitOneUInt64Token(const char** source, const char* delim, - uint64* value) { - return SplitOneUint64Token(source, delim, value); -} - -// ---------------------------------------------------------------------- -// SplitOneDecimalIntToken() -// SplitOneDecimalInt32Token() -// SplitOneDecimalUint32Token() -// SplitOneDecimalInt64Token() -// SplitOneDecimalUint64Token() -// Parse a single "delim"-delimited number from "*source" into "*value". -// Unlike SplitOneIntToken, etc., this function always interprets -// the numbers as decimal. -bool SplitOneDecimalIntToken(const char** source, const char* delim, - int* value); -bool SplitOneDecimalInt32Token(const char** source, const char* delim, - int32* value); -bool SplitOneDecimalUint32Token(const char** source, const char* delim, - uint32* value); -bool SplitOneDecimalInt64Token(const char** source, const char* delim, - int64* value); -bool SplitOneDecimalUint64Token(const char** source, const char* delim, - uint64* value); - -// ---------------------------------------------------------------------- -// SplitOneHexUint32Token() -// SplitOneHexUint64Token() -// Once more, for hexadecimal numbers (unsigned only). -bool SplitOneHexUint32Token(const char** source, const char* delim, - uint32* value); -bool SplitOneHexUint64Token(const char** source, const char* delim, - uint64* value); - - -// ###################### TEMPLATE INSTANTIATIONS BELOW ####################### - -// SplitStringAndParse() -- see description above -template -bool SplitStringAndParse(StringPiece source, StringPiece delim, - bool (*parse)(const string& str, T* value), - std::vector* result) { - return SplitStringAndParseToList(source, delim, parse, result); -} - -namespace strings { -namespace internal { - -template -bool SplitStringAndParseToInserter( - StringPiece source, StringPiece delim, - bool (*parse)(const string& str, typename Container::value_type* value), - Container* result, InsertPolicy insert_policy) { - CHECK(NULL != parse); - CHECK(NULL != result); - CHECK(NULL != delim.data()); - CHECK_GT(delim.size(), 0); - bool retval = true; - std::vector pieces = - strings::Split(source, - strings::delimiter::AnyOf(delim), - strings::SkipEmpty()); - for (size_t i = 0; i < pieces.size(); ++i) { - typename Container::value_type t; - if (parse(pieces[i].as_string(), &t)) { - insert_policy(result, t); - } else { - retval = false; - } - } - return retval; -} - -// Cannot use output iterator here (e.g. std::inserter, std::back_inserter) -// because some callers use non-standard containers that don't have iterators, -// only an insert() or push_back() method. -struct BasicInsertPolicy { - template - void operator()(C* c, const V& v) const { c->insert(v); } -}; - -struct BackInsertPolicy { - template - void operator()(C* c, const V& v) const { c->push_back(v); } -}; - -} // namespace internal -} // namespace strings - -// SplitStringAndParseToContainer() -- see description above -template -bool SplitStringAndParseToContainer( - StringPiece source, StringPiece delim, - bool (*parse)(const string& str, typename Container::value_type* value), - Container* result) { - return strings::internal::SplitStringAndParseToInserter( - source, delim, parse, result, strings::internal::BasicInsertPolicy()); -} - -// SplitStringAndParseToList() -- see description above -template -bool SplitStringAndParseToList( - StringPiece source, StringPiece delim, - bool (*parse)(const string& str, typename List::value_type* value), - List* result) { - return strings::internal::SplitStringAndParseToInserter( - source, delim, parse, result, strings::internal::BackInsertPolicy()); -} - -#endif // STRINGS_SPLIT_H_ \ No newline at end of file +#endif // STRINGS_SPLIT_H_ diff --git a/src/strings/split_internal.h b/src/strings/split_internal.h deleted file mode 100644 index 7cc4d425..00000000 --- a/src/strings/split_internal.h +++ /dev/null @@ -1,513 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// -// This file declares INTERNAL parts of the Split API that are inline/templated -// or otherwise need to be available at compile time. The main two abstractions -// defined in here are -// -// - SplitIterator<> -// - Splitter<> -// -// Everything else is plumbing for those two. -// -// DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including -// strings/split.h. -// -// IWYU pragma: private, include "strings/split.h" - -#ifndef STRINGS_SPLIT_INTERNAL_H_ -#define STRINGS_SPLIT_INTERNAL_H_ - -#ifdef _GLIBCXX_DEBUG -#include -#endif // _GLIBCXX_DEBUG - -#include -#include -#include -#include - -#include "base/port.h" // for LANG_CXX11 -#include "base/template_util.h" -#include "base/type_traits.h" // for base::enable_if -#include "strings/stringpiece.h" - -#ifdef LANG_CXX11 -// This must be included after "base/port.h", which defines LANG_CXX11. -#include // NOLINT(build/include_order) -#endif // LANG_CXX11 - -namespace strings { - -namespace internal { - -#ifdef _GLIBCXX_DEBUG -using ::glibcxx_debug_traits::IsStrictlyDebugWrapperBase; -#else // _GLIBCXX_DEBUG -template struct IsStrictlyDebugWrapperBase : base::false_ {}; -#endif // _GLIBCXX_DEBUG - -// The default Predicate object, which doesn't filter out anything. -struct NoFilter { - bool operator()(StringPiece /* ignored */) { - return true; - } -}; - -// This class is implicitly constructible from const char*, -// StringPiece, and string, but not from other types that are -// themselves convertible to StringPiece (because C++ won't implicitly -// use a sequence of 2 user-defined conversion). If it's constructed -// from a temporary string, it moves that temporary into local storage -// so that the temporary isn't destroyed before Split()'s result. -class ConvertibleToStringPiece { - private: - // Used for temporary string arguments. Must be declared before - // 'value' in order to construct 'value' from it. - string copy_; - - public: - StringPiece value; - ConvertibleToStringPiece(const char* s) : value(s) {} // NOLINT - ConvertibleToStringPiece(char* s) : value(s) {} // NOLINT - ConvertibleToStringPiece(StringPiece s) : value(s) {} // NOLINT - ConvertibleToStringPiece(const string& s) : value(s) {} // NOLINT - -#if LANG_CXX11 - // This overload captures temporary arguments. - // gave approval for this use in cl/48636778. - ConvertibleToStringPiece(string&& s) // NOLINT - : copy_(std::move(s)), // NOLINT - value(copy_) {} -#endif - - ConvertibleToStringPiece(const ConvertibleToStringPiece& other) - : copy_(other.copy_) { - if (other.copy_.empty()) { - value = other.value; - } else { - value = copy_; - } - } - - // Effectively a move constructor, using C++98 features. - explicit ConvertibleToStringPiece(ConvertibleToStringPiece* other) { - if (other->copy_.empty()) { - value = other->value; - } else { - using std::swap; - swap(copy_, other->copy_); - value = copy_; - other->value = StringPiece(); - } - } - - void swap(ConvertibleToStringPiece& other) { - using std::swap; - swap(copy_, other.copy_); - swap(value, other.value); - - // Fix up StringPieces when the real data is stored in the string. - if (!copy_.empty()) value = copy_; - if (!other.copy_.empty()) other.value = other.copy_; - } - - ConvertibleToStringPiece& operator=(ConvertibleToStringPiece other) { - swap(other); - return *this; - } -}; - -// This class splits a string using the given delimiter, returning the split -// substrings via an iterator interface. An optional Predicate functor may be -// supplied, which will be used to filter the split strings: strings for which -// the predicate returns false will be skipped. A Predicate object is any -// functor that takes a StringPiece and returns bool. By default, the NoFilter -// Predicate is used, which does not filter out anything. -// -// This class is NOT part of the public splitting API. -// -// Usage: -// -// using strings::delimiter::Literal; -// Literal d(","); -// for (SplitIterator it("a,b,c", d), end(d); it != end; ++it) { -// StringPiece substring = *it; -// DoWork(substring); -// } -// -// The explicit single-argument constructor is used to create an "end" iterator. -// The two-argument constructor is used to split the given text using the given -// delimiter. -template -class SplitIterator - : public std::iterator { - public: - // Two constructors for "end" iterators. - explicit SplitIterator(Delimiter d) - : delimiter_(d), predicate_(), is_end_(true) {} - SplitIterator(Delimiter d, Predicate p) - : delimiter_(d), predicate_(p), is_end_(true) {} - - // Two constructors taking the text to iterate. - SplitIterator(StringPiece text, Delimiter d) - : text_(text), position_(0), delimiter_(d), predicate_(), is_end_(false) { - ++(*this); - } - SplitIterator(StringPiece text, Delimiter d, Predicate p) - : text_(text), position_(0), delimiter_(d), predicate_(p), - is_end_(false) { - ++(*this); - } - - // Constructor copying the delimiter and predicate out of an - // existing SplitIterator, but applying them to new text. - SplitIterator(StringPiece text, const SplitIterator& other) - : text_(text), - position_(0), - delimiter_(other.delimiter_), - predicate_(other.predicate_), - is_end_(false) { - ++(*this); - } - - StringPiece operator*() const { return curr_piece_; } - const StringPiece* operator->() const { return &curr_piece_; } - - SplitIterator& operator++() { - do { - if (text_.end() == curr_piece_.end()) { - // Already consumed all of text_, so we're done. - is_end_ = true; - return *this; - } - StringPiece found_delimiter = delimiter_.Find(text_, position_); - assert(found_delimiter.data() != NULL); - assert(text_.begin() + position_ <= found_delimiter.begin()); - assert(found_delimiter.end() <= text_.end()); - // found_delimiter is allowed to be empty. - // Sets curr_piece_ to all text up to but excluding the delimiter itself. - // Increments position_ by the length of curr_piece_ and found_delimiter. - size_t curr_size = found_delimiter.begin() - (text_.begin() + position_); - curr_piece_.set(text_.begin() + position_, curr_size); - position_ += curr_piece_.size() + found_delimiter.size(); - } while (!predicate_(curr_piece_)); - return *this; - } - - SplitIterator operator++(int /* postincrement */) { - SplitIterator old(*this); - ++(*this); - return old; - } - - bool operator==(const SplitIterator& other) const { - // Two "end" iterators are always equal. If the two iterators being compared - // aren't both end iterators, then we fallback to comparing their fields. - // Importantly, the text being split must be equal and the current piece - // within the text being split must also be equal. The delimiter_ and - // predicate_ fields need not be checked here because they're template - // parameters that are already part of the SplitIterator's type. - return (is_end_ && other.is_end_) || - (is_end_ == other.is_end_ && - text_ == other.text_ && - text_.data() == other.text_.data() && - position_ == other.position_ && - curr_piece_ == other.curr_piece_ && - curr_piece_.data() == other.curr_piece_.data()); - } - - bool operator!=(const SplitIterator& other) const { - return !(*this == other); - } - - private: - // The text being split. - StringPiece text_; - size_t position_; - Delimiter delimiter_; - Predicate predicate_; - bool is_end_; - // Holds the currently split piece of text. Will always refer to string data - // within text_. This value is returned when the iterator is dereferenced. - StringPiece curr_piece_; -}; - -// Declares a functor that can convert a StringPiece to another type. This works -// for any type that has a constructor (explicit or not) taking a single -// StringPiece argument. A specialization exists for converting to string -// because the underlying data needs to be copied. In theory, these -// specializations could be extended to work with other types (e.g., int32), but -// then a solution for error reporting would need to be devised. -template -struct StringPieceTo { - To operator()(StringPiece from) const { - return To(from); - } -}; - -// Specialization for converting to string. -template <> -struct StringPieceTo { - string operator()(StringPiece from) const { - return from.ToString(); - } -}; - -// Specialization for converting to *const* string. -template <> -struct StringPieceTo { - string operator()(StringPiece from) const { - return from.ToString(); - } -}; - -// HasMappedType::value is true iff there exists a type T::mapped_type. -template -struct HasMappedType { - template static base::small_ check(...); // default: No - template static base::big_ check(typename U::mapped_type*); - enum { value = sizeof(base::big_) == sizeof(check(0)) }; -}; - -// HasValueType::value is true iff there exists a type T::value_type. -template -struct HasValueType { - template static base::small_ check(...); // default: No - template static base::big_ check(typename U::value_type*); - enum { value = sizeof(base::big_) == sizeof(check(0)) }; -}; - -// HasConstIterator::value is true iff there exists a type -// T::const_iterator. -template -struct HasConstIterator { - template static base::small_ check(...); // default: No - template static base::big_ check(typename U::const_iterator*); - enum { value = sizeof(base::big_) == sizeof(check(0)) }; -}; - -// IsInitializerList::value is true iff T is an initializer_list. -// More details below in Splitter<> where this is used. -template -struct IsInitializerList { - static base::small_ check(...); // default: No -#ifdef LANG_CXX11 - template static base::big_ check(std::initializer_list*); -#endif // LANG_CXX11 - enum { value = sizeof(base::big_) == sizeof(check(static_cast(0))) }; -}; - -// A SplitterIsConvertibleTo::type typedef exists iff the specified -// condition is true for type 'C'. -// -// Restricts conversion to container-like types (by testing for the presence of -// a const_iterator member type) and also to disable conversion to an -// initializer_list (which also has a const_iterator). Otherwise, code compiled -// in C++11 will get an error due to ambiguous conversion paths (in C++11 -// vector::operator= is overloaded to take either a vector or an -// initializer_list). -// -// This trick was taken from util/gtl/container_literal.h -template -struct SplitterIsConvertibleTo - : base::enable_if< - !IsStrictlyDebugWrapperBase::value && - !IsInitializerList::value && - HasValueType::value && - HasConstIterator::value> {}; // NOLINT - -// This class implements the behavior of the split API by giving callers access -// to the underlying split substrings in various convenient ways, such as -// through iterators or implicit conversion functions. Do not construct this -// class directly, rather use the Split() function instead. -// -// Output containers can be collections of either StringPiece or string objects. -// StringPiece is more efficient because the underlying data will not need to be -// copied; the returned StringPieces will all refer to the data within the -// original input string. If a collection of string objects is used, then each -// substring will be copied. -// -// An optional Predicate functor may be supplied. This predicate will be used to -// filter the split strings: only strings for which the predicate returns true -// will be kept. A Predicate object is any unary functor that takes a -// StringPiece and returns bool. By default, the NoFilter predicate is used, -// which does not filter out anything. -template -class Splitter { - public: - typedef std::forward_iterator_tag iterator_category; - typedef internal::SplitIterator iterator; - typedef internal::SplitIterator const_iterator; - - Splitter(ConvertibleToStringPiece* input_text, Delimiter d) - : text_(input_text), begin_(text_.value, d), end_(d) {} - - Splitter(ConvertibleToStringPiece* input_text, Delimiter d, Predicate p) - : text_(input_text), begin_(text_.value, d, p), end_(d, p) {} - - Splitter(const Splitter& other) - : text_(other.text_), - begin_(text_.value, other.begin_), - end_(other.end_) {} - - // Range functions that iterate the split substrings as StringPiece objects. - // These methods enable a Splitter to be used in a range-based for loop in - // C++11, for example: - // - // for (StringPiece sp : my_splitter) { - // DoWork(sp); - // } - const_iterator begin() const { return begin_; } - const_iterator end() const { return end_; } - -#ifdef LANG_CXX11 - // An implicit conversion operator that uses a default template argument to - // restrict its use to only those containers that the splitter is convertible - // to. Default template arguments on function templates are a C++11 feature, - // which is why this code is under an #ifdef LANG_CXX11. - template ::type> - operator Container() const { - return ContainerConverter< - Container, - typename Container::value_type, - HasMappedType::value>()(*this); - } -#else - // Not under LANG_CXX11. - // Same conversion operator as in the C++11 block above, except this one - // doesn't use SplitterIsConvertibleTo<>. - template - operator Container() const { - return ContainerConverter< - Container, - typename Container::value_type, - HasMappedType::value>()(*this); - } -#endif // LANG_CXX11 - - // Returns a pair with its .first and .second members set to the first two - // strings returned by the begin() iterator. Either/both of .first and .second - // will be constructed with empty strings if the iterator doesn't have a - // corresponding value. - template - operator std::pair() const { - StringPieceTo first_converter; - StringPieceTo second_converter; - StringPiece first, second; - const_iterator it = begin(); - if (it != end()) { - first = *it; - if (++it != end()) { - second = *it; - } - } - return std::make_pair(first_converter(first), second_converter(second)); - } - - private: - // ContainerConverter is a functor converting a Splitter to the requested - // Container and ValueType. It can be specialized to optimize splitting to - // certain combinations of Container and ValueType. - // - // This base template handles the generic case of storing the split results in - // the requested non-map-like container and converting the split substrings to - // the requested type. - template - struct ContainerConverter { - Container operator()(const Splitter& splitter) const { - Container c; - std::transform(splitter.begin(), - splitter.end(), - std::inserter(c, c.end()), - StringPieceTo()); - return c; - } - }; - - // Partial specialization for a vector. - // - // Optimized for the common case of splitting to a vector. In this - // case we first split the results to a vector so the returned - // vector can have space reserved to avoid string copies. - template - struct ContainerConverter, string, false> { - std::vector operator()(const Splitter& splitter) const { - std::vector vsp(splitter.begin(), splitter.end()); - std::vector v(vsp.size()); - for (size_t i = 0; i < vsp.size(); ++i) { - vsp[i].CopyToString(&v[i]); - } - return v; - } - }; - - // Partial specialization for containers of pairs (e.g., maps). - // - // The algorithm is to insert a new pair into the map for each even-numbered - // item, with the even-numbered item as the key with a default-constructed - // value. Each odd-numbered item will then be assigned to the last pair's - // value. - template - struct ContainerConverter, true> { - Container operator()(const Splitter& splitter) const { - Container m; - StringPieceTo key_converter; - StringPieceTo val_converter; - typename Container::iterator curr_pair; - bool is_even = true; - for (const_iterator it = splitter.begin(); it != splitter.end(); ++it) { - if (is_even) { - curr_pair = InsertInMap(std::make_pair(key_converter(*it), Second()), - &m); - } else { - curr_pair->second = val_converter(*it); - } - is_even = !is_even; - } - return m; - } - - // Overloaded InsertInMap() function. The first overload is the commonly - // used one for most map-like objects. The second overload is a special case - // for multimap, because multimap's insert() member function directly - // returns an iterator, rather than a pair like map's. - template - typename Map::iterator InsertInMap( - const typename Map::value_type& value, Map* map) const { - return map->insert(value).first; - } - - // InsertInMap overload for multimap. - template - typename std::multimap::iterator InsertInMap( - const typename std::multimap::value_type& value, - typename std::multimap* map) const { - return map->insert(value); - } - }; - - const ConvertibleToStringPiece text_; - const const_iterator begin_; - const const_iterator end_; -}; - -} // namespace internal - -} // namespace strings - -#endif // STRINGS_SPLIT_INTERNAL_H_ \ No newline at end of file diff --git a/src/strings/strcat.cc b/src/strings/strcat.cc deleted file mode 100644 index 8433dd98..00000000 --- a/src/strings/strcat.cc +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright 2008 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#include "strings/strcat.h" - -#include -#include -#include -#include - -#include -#include "strings/ascii_ctype.h" -#include "util/gtl/stl_util.h" - -namespace strings { - -AlphaNum gEmptyAlphaNum(""); - -AlphaNum::AlphaNum(strings::Hex hex) { - char *const end = &digits_[kFastToBufferSize]; - char *writer = end; - uint64 value = hex.value; - uint64 width = hex.spec; - // We accomplish minimum width by OR'ing in 0x10000 to the user's value, - // where 0x10000 is the smallest hex number that is as wide as the user - // asked for. - uint64 mask = ((static_cast(1) << (width - 1) * 4)) | value; - static const char hexdigits[] = "0123456789abcdef"; - do { - *--writer = hexdigits[value & 0xF]; - value >>= 4; - mask >>= 4; - } while (mask != 0); - piece_.set(writer, end - writer); -} - -} // namespace strings - -// ---------------------------------------------------------------------- -// StrCat() -// This merges the given strings or integers, with no delimiter. This -// is designed to be the fastest possible way to construct a string out -// of a mix of raw C strings, StringPieces, strings, and integer values. -// ---------------------------------------------------------------------- - -// Append is merely a version of memcpy that returns the address of the byte -// after the area just overwritten. It comes in multiple flavors to minimize -// call overhead. -static char *Append1(char *out, const AlphaNum &x) { - memcpy(out, x.data(), x.size()); - return out + x.size(); -} - -static char *Append2(char *out, const AlphaNum &x1, const AlphaNum &x2) { - memcpy(out, x1.data(), x1.size()); - out += x1.size(); - - memcpy(out, x2.data(), x2.size()); - return out + x2.size(); -} - -static char *Append4(char *out, - const AlphaNum &x1, const AlphaNum &x2, - const AlphaNum &x3, const AlphaNum &x4) { - memcpy(out, x1.data(), x1.size()); - out += x1.size(); - - memcpy(out, x2.data(), x2.size()); - out += x2.size(); - - memcpy(out, x3.data(), x3.size()); - out += x3.size(); - - memcpy(out, x4.data(), x4.size()); - return out + x4.size(); -} - -string StrCat(const AlphaNum &a, const AlphaNum &b) { - string result; - STLStringResizeUninitialized(&result, a.size() + b.size()); - char *const begin = &*result.begin(); - char *out = Append2(begin, a, b); - DCHECK_EQ(out, begin + result.size()); - return result; -} - -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c) { - string result; - STLStringResizeUninitialized(&result, a.size() + b.size() + c.size()); - char *const begin = &*result.begin(); - char *out = Append2(begin, a, b); - out = Append1(out, c); - DCHECK_EQ(out, begin + result.size()); - return result; -} - -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d) { - string result; - STLStringResizeUninitialized(&result, - a.size() + b.size() + c.size() + d.size()); - char *const begin = &*result.begin(); - char *out = Append4(begin, a, b, c, d); - DCHECK_EQ(out, begin + result.size()); - return result; -} - -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e) { - string result; - STLStringResizeUninitialized(&result, - a.size() + b.size() + c.size() + d.size() + e.size()); - char *const begin = &*result.begin(); - char *out = Append4(begin, a, b, c, d); - out = Append1(out, e); - DCHECK_EQ(out, begin + result.size()); - return result; -} - -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f) { - string result; - STLStringResizeUninitialized(&result, - a.size() + b.size() + c.size() + d.size() + e.size() + f.size()); - char *const begin = &*result.begin(); - char *out = Append4(begin, a, b, c, d); - out = Append2(out, e, f); - DCHECK_EQ(out, begin + result.size()); - return result; -} - -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g) { - string result; - STLStringResizeUninitialized(&result, - a.size() + b.size() + c.size() + d.size() + e.size() - + f.size() + g.size()); - char *const begin = &*result.begin(); - char *out = Append4(begin, a, b, c, d); - out = Append2(out, e, f); - out = Append1(out, g); - DCHECK_EQ(out, begin + result.size()); - return result; -} - -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h) { - string result; - STLStringResizeUninitialized(&result, - a.size() + b.size() + c.size() + d.size() + e.size() - + f.size() + g.size() + h.size()); - char *const begin = &*result.begin(); - char *out = Append4(begin, a, b, c, d); - out = Append4(out, e, f, g, h); - DCHECK_EQ(out, begin + result.size()); - return result; -} - -namespace strings { -namespace internal { - -// StrCat with this many params is exceedingly rare, but it has been -// requested... therefore we'll rely on default arguments to make calling -// slightly less efficient, to preserve code size. -string StrCatNineOrMore(const AlphaNum *a, ...) { - string result; - - va_list args; - va_start(args, a); - size_t size = a->size(); - while (const AlphaNum *arg = va_arg(args, const AlphaNum *)) { - size += arg->size(); - } - STLStringResizeUninitialized(&result, size); - va_end(args); - va_start(args, a); - char *const begin = &*result.begin(); - char *out = Append1(begin, *a); - while (const AlphaNum *arg = va_arg(args, const AlphaNum *)) { - out = Append1(out, *arg); - } - va_end(args); - DCHECK_EQ(out, begin + size); - return result; -} - -} // namespace internal -} // namespace strings - -// It's possible to call StrAppend with a StringPiece that is itself a fragment -// of the string we're appending to. However the results of this are random. -// Therefore, check for this in debug mode. Use unsigned math so we only have -// to do one comparison. -#define DCHECK_NO_OVERLAP(dest, src) \ - DCHECK_GT(uintptr_t((src).data() - (dest).data()), uintptr_t((dest).size())) - -void StrAppend(string *result, const AlphaNum &a) { - DCHECK_NO_OVERLAP(*result, a); - result->append(a.data(), a.size()); -} - -void StrAppend(string *result, const AlphaNum &a, const AlphaNum &b) { - DCHECK_NO_OVERLAP(*result, a); - DCHECK_NO_OVERLAP(*result, b); - string::size_type old_size = result->size(); - STLStringResizeUninitialized(result, old_size + a.size() + b.size()); - char *const begin = &*result->begin(); - char *out = Append2(begin + old_size, a, b); - DCHECK_EQ(out, begin + result->size()); -} - -void StrAppend(string *result, - const AlphaNum &a, const AlphaNum &b, const AlphaNum &c) { - DCHECK_NO_OVERLAP(*result, a); - DCHECK_NO_OVERLAP(*result, b); - DCHECK_NO_OVERLAP(*result, c); - string::size_type old_size = result->size(); - STLStringResizeUninitialized(result, - old_size + a.size() + b.size() + c.size()); - char *const begin = &*result->begin(); - char *out = Append2(begin + old_size, a, b); - out = Append1(out, c); - DCHECK_EQ(out, begin + result->size()); -} - -void StrAppend(string *result, - const AlphaNum &a, const AlphaNum &b, - const AlphaNum &c, const AlphaNum &d) { - DCHECK_NO_OVERLAP(*result, a); - DCHECK_NO_OVERLAP(*result, b); - DCHECK_NO_OVERLAP(*result, c); - DCHECK_NO_OVERLAP(*result, d); - string::size_type old_size = result->size(); - STLStringResizeUninitialized(result, - old_size + a.size() + b.size() + c.size() + d.size()); - char *const begin = &*result->begin(); - char *out = Append4(begin + old_size, a, b, c, d); - DCHECK_EQ(out, begin + result->size()); -} - -// StrAppend with this many params is even rarer than with StrCat. -// Therefore we'll again rely on default arguments to make calling -// slightly less efficient, to preserve code size. -void StrAppend(string *result, - const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h, const AlphaNum &i) { - DCHECK_NO_OVERLAP(*result, a); - DCHECK_NO_OVERLAP(*result, b); - DCHECK_NO_OVERLAP(*result, c); - DCHECK_NO_OVERLAP(*result, d); - DCHECK_NO_OVERLAP(*result, e); - DCHECK_NO_OVERLAP(*result, f); - DCHECK_NO_OVERLAP(*result, g); - DCHECK_NO_OVERLAP(*result, h); - DCHECK_NO_OVERLAP(*result, i); - string::size_type old_size = result->size(); - STLStringResizeUninitialized(result, - old_size + a.size() + b.size() + c.size() + d.size() - + e.size() + f.size() + g.size() + h.size() + i.size()); - char *const begin = &*result->begin(); - char *out = Append4(begin + old_size, a, b, c, d); - out = Append4(out, e, f, g, h); - out = Append1(out, i); - DCHECK_EQ(out, begin + result->size()); -} \ No newline at end of file diff --git a/src/strings/strcat.h b/src/strings/strcat.h deleted file mode 100644 index 177657e3..00000000 --- a/src/strings/strcat.h +++ /dev/null @@ -1,587 +0,0 @@ -// Copyright 2008 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// -// #status: RECOMMENDED -// #category: operations on strings -// #summary: Merges strings or numbers with no delimiter. -// -#ifndef STRINGS_STRCAT_H_ -#define STRINGS_STRCAT_H_ - -#include - -#include "base/integral_types.h" -#include "base/macros.h" -#include "base/port.h" -#include "strings/numbers.h" -#include "strings/stringpiece.h" - -// The AlphaNum type was designed to be used as the parameter type for StrCat(). -// Any routine accepting either a string or a number may accept it. -// The basic idea is that by accepting a "const AlphaNum &" as an argument -// to your function, your callers will automagically convert bools, integers, -// and floating point values to strings for you. -// -// NOTE: Use of AlphaNum outside of the //strings package is unsupported except -// for the specific case of function parameters of type "AlphaNum" or "const -// AlphaNum &". In particular, instantiating AlphaNum directly as a stack -// variable is not supported. -// -// Conversion from 8-bit values is not accepted because if it were, then an -// attempt to pass ':' instead of ":" might result in a 58 ending up in your -// result. -// -// Bools convert to "0" or "1". -// -// Floating point values are converted to a string which, if passed to strtod(), -// would produce the exact same original double (except in case of NaN; all NaNs -// are considered the same value). We try to keep the string short but it's not -// guaranteed to be as short as possible. -// -// You can convert to Hexadecimal output rather than Decimal output using Hex. -// To do this, pass strings::Hex(my_int) as a parameter to StrCat. You may -// specify a minimum field width using a separate parameter, so the equivalent -// of StringPrintf("%04x", my_int) is StrCat(Hex(my_int, Hex::ZERO_PAD_4)) -// -// This class has implicit constructors. -// Style guide exception granted: -// http://goto/style-guide-exception-20978288 -// -namespace strings { - -struct Hex { - uint64 value; - enum PadSpec { - NONE = 1, - ZERO_PAD_2, - ZERO_PAD_3, - ZERO_PAD_4, - ZERO_PAD_5, - ZERO_PAD_6, - ZERO_PAD_7, - ZERO_PAD_8, - ZERO_PAD_9, - ZERO_PAD_10, - ZERO_PAD_11, - ZERO_PAD_12, - ZERO_PAD_13, - ZERO_PAD_14, - ZERO_PAD_15, - ZERO_PAD_16, - } spec; - template - explicit Hex(Int v, PadSpec s = NONE) - : spec(s) { - // Prevent sign-extension by casting integers to - // their unsigned counterparts. - static_assert( - sizeof(v) == 1 || sizeof(v) == 2 || sizeof(v) == 4 || sizeof(v) == 8, - "Unknown integer type"); - value = sizeof(v) == 1 ? static_cast(v) - : sizeof(v) == 2 ? static_cast(v) - : sizeof(v) == 4 ? static_cast(v) - : static_cast(v); - } -}; - -class AlphaNum { - public: - // No bool ctor -- bools convert to an integral type. - // A bool ctor would also convert incoming pointers (bletch). - - AlphaNum(int32 i32) // NOLINT(runtime/explicit) - : piece_(digits_, FastInt32ToBufferLeft(i32, digits_) - &digits_[0]) {} - AlphaNum(uint32 u32) // NOLINT(runtime/explicit) - : piece_(digits_, FastUInt32ToBufferLeft(u32, digits_) - &digits_[0]) {} - AlphaNum(int64 i64) // NOLINT(runtime/explicit) - : piece_(digits_, FastInt64ToBufferLeft(i64, digits_) - &digits_[0]) {} - AlphaNum(uint64 u64) // NOLINT(runtime/explicit) - : piece_(digits_, FastUInt64ToBufferLeft(u64, digits_) - &digits_[0]) {} - -#ifdef _LP64 - AlphaNum(long x) // NOLINT(runtime/explicit) - : piece_(digits_, FastInt64ToBufferLeft(x, digits_) - &digits_[0]) {} - AlphaNum(unsigned long x) // NOLINT(runtime/explicit) - : piece_(digits_, FastUInt64ToBufferLeft(x, digits_) - &digits_[0]) {} -#else - AlphaNum(long x) // NOLINT(runtime/explicit) - : piece_(digits_, FastInt32ToBufferLeft(x, digits_) - &digits_[0]) {} - AlphaNum(unsigned long x) // NOLINT(runtime/explicit) - : piece_(digits_, FastUInt32ToBufferLeft(x, digits_) - &digits_[0]) {} -#endif - - AlphaNum(float f) // NOLINT(runtime/explicit) - : piece_(digits_, strlen(FloatToBuffer(f, digits_))) {} - AlphaNum(double f) // NOLINT(runtime/explicit) - : piece_(digits_, strlen(DoubleToBuffer(f, digits_))) {} - - AlphaNum(Hex hex); // NOLINT(runtime/explicit) - - AlphaNum(const char *c_str) : piece_(c_str) {} // NOLINT(runtime/explicit) - AlphaNum(const StringPiece &pc) : piece_(pc) {} // NOLINT(runtime/explicit) - -#if defined(HAS_GLOBAL_STRING) - template - AlphaNum(const basic_string, - Allocator> &str) - : piece_(str) {} -#endif - template - AlphaNum(const std::basic_string, - Allocator> &str) // NOLINT(runtime/explicit) - : piece_(str) {} - - - StringPiece::size_type size() const { return piece_.size(); } - const char *data() const { return piece_.data(); } - StringPiece Piece() const { return piece_; } - - private: - StringPiece piece_; - char digits_[kFastToBufferSize]; - - // Use ":" not ':' - AlphaNum(char c); // NOLINT(runtime/explicit) - - DISALLOW_COPY_AND_ASSIGN(AlphaNum); -}; - -extern AlphaNum gEmptyAlphaNum; - -} // namespace strings - -using strings::AlphaNum; -using strings::gEmptyAlphaNum; - -// ---------------------------------------------------------------------- -// StrCat() -// This merges the given strings or numbers, with no delimiter. This -// is designed to be the fastest possible way to construct a string out -// of a mix of raw C strings, StringPieces, strings, bool values, -// and numeric values. -// -// Don't use this for user-visible strings. The localization process -// works poorly on strings built up out of fragments. -// -// For clarity and performance, don't use StrCat when appending to a -// string. In particular, avoid using any of these (anti-)patterns: -// str.append(StrCat(...)) -// str += StrCat(...) -// str = StrCat(str, ...) -// where the last is the worse, with the potential to change a loop -// from a linear time operation with O(1) dynamic allocations into a -// quadratic time operation with O(n) dynamic allocations. StrAppend -// is a better choice than any of the above, subject to the restriction -// of StrAppend(&str, a, b, c, ...) that none of the a, b, c, ... may -// be a reference into str. -// ---------------------------------------------------------------------- - -string StrCat(const AlphaNum &a) MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b) MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c) - MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d) MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e) MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f) - MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g) MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h) MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h, const AlphaNum &i) - MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h, const AlphaNum &i, - const AlphaNum &j) MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h, const AlphaNum &i, - const AlphaNum &j, const AlphaNum &k) MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h, const AlphaNum &i, - const AlphaNum &j, const AlphaNum &k, const AlphaNum &l) - MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h, const AlphaNum &i, - const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m) MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h, const AlphaNum &i, - const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n) MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h, const AlphaNum &i, - const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o) - MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h, const AlphaNum &i, - const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, - const AlphaNum &p) MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h, const AlphaNum &i, - const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, - const AlphaNum &p, const AlphaNum &q) MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h, const AlphaNum &i, - const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, - const AlphaNum &p, const AlphaNum &q, const AlphaNum &r) - MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h, const AlphaNum &i, - const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, - const AlphaNum &p, const AlphaNum &q, const AlphaNum &r, - const AlphaNum &s) MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h, const AlphaNum &i, - const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, - const AlphaNum &p, const AlphaNum &q, const AlphaNum &r, - const AlphaNum &s, const AlphaNum &t) MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h, const AlphaNum &i, - const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, - const AlphaNum &p, const AlphaNum &q, const AlphaNum &r, - const AlphaNum &s, const AlphaNum &t, const AlphaNum &u) - MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h, const AlphaNum &i, - const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, - const AlphaNum &p, const AlphaNum &q, const AlphaNum &r, - const AlphaNum &s, const AlphaNum &t, const AlphaNum &u, - const AlphaNum &v) MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h, const AlphaNum &i, - const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, - const AlphaNum &p, const AlphaNum &q, const AlphaNum &r, - const AlphaNum &s, const AlphaNum &t, const AlphaNum &u, - const AlphaNum &v, const AlphaNum &w) MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h, const AlphaNum &i, - const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, - const AlphaNum &p, const AlphaNum &q, const AlphaNum &r, - const AlphaNum &s, const AlphaNum &t, const AlphaNum &u, - const AlphaNum &v, const AlphaNum &w, const AlphaNum &x) - MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h, const AlphaNum &i, - const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, - const AlphaNum &p, const AlphaNum &q, const AlphaNum &r, - const AlphaNum &s, const AlphaNum &t, const AlphaNum &u, - const AlphaNum &v, const AlphaNum &w, const AlphaNum &x, - const AlphaNum &y) MUST_USE_RESULT; -string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, - const AlphaNum &d, const AlphaNum &e, const AlphaNum &f, - const AlphaNum &g, const AlphaNum &h, const AlphaNum &i, - const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, - const AlphaNum &p, const AlphaNum &q, const AlphaNum &r, - const AlphaNum &s, const AlphaNum &t, const AlphaNum &u, - const AlphaNum &v, const AlphaNum &w, const AlphaNum &x, - const AlphaNum &y, const AlphaNum &z) MUST_USE_RESULT; - -inline string StrCat(const AlphaNum &a) { return string(a.data(), a.size()); } - -namespace strings { -namespace internal { - -// Do not call directly - this is not part of the public API. -string StrCatNineOrMore(const AlphaNum *a1, ...); - -} // namespace internal -} // namespace strings - -// Support 9 or more arguments -inline string StrCat( - const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, const AlphaNum &d, - const AlphaNum &e, const AlphaNum &f, const AlphaNum &g, const AlphaNum &h, - const AlphaNum &i) { - const AlphaNum* null_alphanum = NULL; - return strings::internal::StrCatNineOrMore(&a, &b, &c, &d, &e, &f, &g, &h, &i, - null_alphanum); -} - -inline string StrCat( - const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, const AlphaNum &d, - const AlphaNum &e, const AlphaNum &f, const AlphaNum &g, const AlphaNum &h, - const AlphaNum &i, const AlphaNum &j) { - const AlphaNum* null_alphanum = NULL; - return strings::internal::StrCatNineOrMore(&a, &b, &c, &d, &e, &f, &g, &h, &i, - &j, null_alphanum); -} - -inline string StrCat( - const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, const AlphaNum &d, - const AlphaNum &e, const AlphaNum &f, const AlphaNum &g, const AlphaNum &h, - const AlphaNum &i, const AlphaNum &j, const AlphaNum &k) { - const AlphaNum* null_alphanum = NULL; - return strings::internal::StrCatNineOrMore(&a, &b, &c, &d, &e, &f, &g, &h, &i, - &j, &k, null_alphanum); -} - -inline string StrCat( - const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, const AlphaNum &d, - const AlphaNum &e, const AlphaNum &f, const AlphaNum &g, const AlphaNum &h, - const AlphaNum &i, const AlphaNum &j, const AlphaNum &k, - const AlphaNum &l) { - const AlphaNum* null_alphanum = NULL; - return strings::internal::StrCatNineOrMore(&a, &b, &c, &d, &e, &f, &g, &h, &i, - &j, &k, &l, null_alphanum); -} - -inline string StrCat( - const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, const AlphaNum &d, - const AlphaNum &e, const AlphaNum &f, const AlphaNum &g, const AlphaNum &h, - const AlphaNum &i, const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m) { - const AlphaNum* null_alphanum = NULL; - return strings::internal::StrCatNineOrMore(&a, &b, &c, &d, &e, &f, &g, &h, &i, - &j, &k, &l, &m, null_alphanum); -} - -inline string StrCat( - const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, const AlphaNum &d, - const AlphaNum &e, const AlphaNum &f, const AlphaNum &g, const AlphaNum &h, - const AlphaNum &i, const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n) { - const AlphaNum* null_alphanum = NULL; - return strings::internal::StrCatNineOrMore(&a, &b, &c, &d, &e, &f, &g, &h, &i, - &j, &k, &l, &m, &n, null_alphanum); -} - -inline string StrCat( - const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, const AlphaNum &d, - const AlphaNum &e, const AlphaNum &f, const AlphaNum &g, const AlphaNum &h, - const AlphaNum &i, const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o) { - const AlphaNum* null_alphanum = NULL; - return strings::internal::StrCatNineOrMore(&a, &b, &c, &d, &e, &f, &g, &h, &i, - &j, &k, &l, &m, &n, &o, - null_alphanum); -} - -inline string StrCat( - const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, const AlphaNum &d, - const AlphaNum &e, const AlphaNum &f, const AlphaNum &g, const AlphaNum &h, - const AlphaNum &i, const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, - const AlphaNum &p) { - const AlphaNum* null_alphanum = NULL; - return strings::internal::StrCatNineOrMore(&a, &b, &c, &d, &e, &f, &g, &h, &i, - &j, &k, &l, &m, &n, &o, &p, - null_alphanum); -} - -inline string StrCat( - const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, const AlphaNum &d, - const AlphaNum &e, const AlphaNum &f, const AlphaNum &g, const AlphaNum &h, - const AlphaNum &i, const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, const AlphaNum &p, - const AlphaNum &q) { - const AlphaNum* null_alphanum = NULL; - return strings::internal::StrCatNineOrMore(&a, &b, &c, &d, &e, &f, &g, &h, &i, - &j, &k, &l, &m, &n, &o, &p, &q, - null_alphanum); -} - -inline string StrCat( - const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, const AlphaNum &d, - const AlphaNum &e, const AlphaNum &f, const AlphaNum &g, const AlphaNum &h, - const AlphaNum &i, const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, const AlphaNum &p, - const AlphaNum &q, const AlphaNum &r) { - const AlphaNum* null_alphanum = NULL; - return strings::internal::StrCatNineOrMore(&a, &b, &c, &d, &e, &f, &g, &h, &i, - &j, &k, &l, &m, &n, &o, &p, &q, &r, - null_alphanum); -} - -inline string StrCat( - const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, const AlphaNum &d, - const AlphaNum &e, const AlphaNum &f, const AlphaNum &g, const AlphaNum &h, - const AlphaNum &i, const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, const AlphaNum &p, - const AlphaNum &q, const AlphaNum &r, const AlphaNum &s) { - const AlphaNum* null_alphanum = NULL; - return strings::internal::StrCatNineOrMore(&a, &b, &c, &d, &e, &f, &g, &h, &i, - &j, &k, &l, &m, &n, &o, &p, &q, &r, - &s, null_alphanum); -} - -inline string StrCat( - const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, const AlphaNum &d, - const AlphaNum &e, const AlphaNum &f, const AlphaNum &g, const AlphaNum &h, - const AlphaNum &i, const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, const AlphaNum &p, - const AlphaNum &q, const AlphaNum &r, const AlphaNum &s, - const AlphaNum &t) { - const AlphaNum* null_alphanum = NULL; - return strings::internal::StrCatNineOrMore(&a, &b, &c, &d, &e, &f, &g, &h, &i, - &j, &k, &l, &m, &n, &o, &p, &q, &r, - &s, &t, null_alphanum); -} - -inline string StrCat( - const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, const AlphaNum &d, - const AlphaNum &e, const AlphaNum &f, const AlphaNum &g, const AlphaNum &h, - const AlphaNum &i, const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, const AlphaNum &p, - const AlphaNum &q, const AlphaNum &r, const AlphaNum &s, const AlphaNum &t, - const AlphaNum &u) { - const AlphaNum* null_alphanum = NULL; - return strings::internal::StrCatNineOrMore(&a, &b, &c, &d, &e, &f, &g, &h, &i, - &j, &k, &l, &m, &n, &o, &p, &q, &r, - &s, &t, &u, null_alphanum); -} - -inline string StrCat( - const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, const AlphaNum &d, - const AlphaNum &e, const AlphaNum &f, const AlphaNum &g, const AlphaNum &h, - const AlphaNum &i, const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, const AlphaNum &p, - const AlphaNum &q, const AlphaNum &r, const AlphaNum &s, const AlphaNum &t, - const AlphaNum &u, const AlphaNum &v) { - const AlphaNum* null_alphanum = NULL; - return strings::internal::StrCatNineOrMore(&a, &b, &c, &d, &e, &f, &g, &h, &i, - &j, &k, &l, &m, &n, &o, &p, &q, &r, - &s, &t, &u, &v, null_alphanum); -} - -inline string StrCat( - const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, const AlphaNum &d, - const AlphaNum &e, const AlphaNum &f, const AlphaNum &g, const AlphaNum &h, - const AlphaNum &i, const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, const AlphaNum &p, - const AlphaNum &q, const AlphaNum &r, const AlphaNum &s, const AlphaNum &t, - const AlphaNum &u, const AlphaNum &v, const AlphaNum &w) { - const AlphaNum* null_alphanum = NULL; - return strings::internal::StrCatNineOrMore(&a, &b, &c, &d, &e, &f, &g, &h, &i, - &j, &k, &l, &m, &n, &o, &p, &q, &r, - &s, &t, &u, &v, &w, null_alphanum); -} - -inline string StrCat( - const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, const AlphaNum &d, - const AlphaNum &e, const AlphaNum &f, const AlphaNum &g, const AlphaNum &h, - const AlphaNum &i, const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, const AlphaNum &p, - const AlphaNum &q, const AlphaNum &r, const AlphaNum &s, const AlphaNum &t, - const AlphaNum &u, const AlphaNum &v, const AlphaNum &w, - const AlphaNum &x) { - const AlphaNum* null_alphanum = NULL; - return strings::internal::StrCatNineOrMore(&a, &b, &c, &d, &e, &f, &g, &h, &i, - &j, &k, &l, &m, &n, &o, &p, &q, &r, - &s, &t, &u, &v, &w, &x, - null_alphanum); -} - -inline string StrCat( - const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, const AlphaNum &d, - const AlphaNum &e, const AlphaNum &f, const AlphaNum &g, const AlphaNum &h, - const AlphaNum &i, const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, const AlphaNum &p, - const AlphaNum &q, const AlphaNum &r, const AlphaNum &s, const AlphaNum &t, - const AlphaNum &u, const AlphaNum &v, const AlphaNum &w, const AlphaNum &x, - const AlphaNum &y) { - const AlphaNum* null_alphanum = NULL; - return strings::internal::StrCatNineOrMore(&a, &b, &c, &d, &e, &f, &g, &h, &i, - &j, &k, &l, &m, &n, &o, &p, &q, &r, - &s, &t, &u, &v, &w, &x, &y, - null_alphanum); -} - -inline string StrCat( - const AlphaNum &a, const AlphaNum &b, const AlphaNum &c, const AlphaNum &d, - const AlphaNum &e, const AlphaNum &f, const AlphaNum &g, const AlphaNum &h, - const AlphaNum &i, const AlphaNum &j, const AlphaNum &k, const AlphaNum &l, - const AlphaNum &m, const AlphaNum &n, const AlphaNum &o, const AlphaNum &p, - const AlphaNum &q, const AlphaNum &r, const AlphaNum &s, const AlphaNum &t, - const AlphaNum &u, const AlphaNum &v, const AlphaNum &w, const AlphaNum &x, - const AlphaNum &y, const AlphaNum &z) { - const AlphaNum* null_alphanum = NULL; - return strings::internal::StrCatNineOrMore(&a, &b, &c, &d, &e, &f, &g, &h, &i, - &j, &k, &l, &m, &n, &o, &p, &q, &r, - &s, &t, &u, &v, &w, &x, &y, &z, - null_alphanum); -} - -// ---------------------------------------------------------------------- -// StrAppend() -// Same as above, but adds the output to the given string. -// WARNING: For speed, StrAppend does not try to check each of its input -// arguments to be sure that they are not a subset of the string being -// appended to. That is, while this will work: -// -// string s = "foo"; -// s += s; -// -// This will not (necessarily) work: -// -// string s = "foo"; -// StrAppend(&s, s); -// -// Note: while StrCat supports appending up to 26 arguments, StrAppend -// is currently limited to 9. That's rarely an issue except when -// automatically transforming StrCat to StrAppend, and can easily be -// worked around as consecutive calls to StrAppend are quite efficient. -// ---------------------------------------------------------------------- - -void StrAppend(string *dest, const AlphaNum &a); -void StrAppend(string *dest, const AlphaNum &a, const AlphaNum &b); -void StrAppend(string *dest, const AlphaNum &a, const AlphaNum &b, - const AlphaNum &c); -void StrAppend(string *dest, const AlphaNum &a, const AlphaNum &b, - const AlphaNum &c, const AlphaNum &d); - -// Support up to 9 params by using a default empty AlphaNum. -void StrAppend(string *dest, const AlphaNum &a, const AlphaNum &b, - const AlphaNum &c, const AlphaNum &d, const AlphaNum &e, - const AlphaNum &f = gEmptyAlphaNum, - const AlphaNum &g = gEmptyAlphaNum, - const AlphaNum &h = gEmptyAlphaNum, - const AlphaNum &i = gEmptyAlphaNum); - -#endif // STRINGS_STRCAT_H_ \ No newline at end of file diff --git a/src/strings/stringpiece.cc b/src/strings/stringpiece.cc index 5eb92ddb..c2ddf820 100644 --- a/src/strings/stringpiece.cc +++ b/src/strings/stringpiece.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // @@ -28,7 +29,11 @@ #include "util/hash/hash.h" HASH_NAMESPACE_DECLARATION_START +#ifdef _MSC_VER +size_t hash_compare::operator()(StringPiece s) const { +#else size_t hash::operator()(StringPiece s) const { +#endif // _MSC_VER return HashTo32(s.data(), s.size()); } HASH_NAMESPACE_DECLARATION_END @@ -100,8 +105,7 @@ stringpiece_ssize_type StringPiece::find(StringPiece s, size_type pos) const { if (length_ == 0 && pos == 0 && s.length_ == 0) return 0; return npos; } - const char *result = memmatch(ptr_ + pos, length_ - pos, - s.ptr_, s.length_); + const char* result = memmatch(ptr_ + pos, length_ - pos, s.ptr_, s.length_); return result ? result - ptr_ : npos; } @@ -109,8 +113,8 @@ stringpiece_ssize_type StringPiece::find(char c, size_type pos) const { if (length_ <= 0 || pos >= static_cast(length_)) { return npos; } - const char* result = static_cast( - memchr(ptr_ + pos, c, length_ - pos)); + const char* result = + static_cast(memchr(ptr_ + pos, c, length_ - pos)); return result != NULL ? result - ptr_ : npos; } @@ -129,7 +133,7 @@ stringpiece_ssize_type StringPiece::rfind(char c, size_type pos) const { // Note: memrchr() is not available on Windows. if (length_ <= 0) return npos; for (stringpiece_ssize_type i = - std::min(pos, static_cast(length_ - 1)); + std::min(pos, static_cast(length_ - 1)); i >= 0; --i) { if (ptr_[i] == c) { return i; @@ -258,4 +262,4 @@ StringPiece StringPiece::substr(size_type pos, size_type n) const { return StringPiece(ptr_ + pos, n); } -const StringPiece::size_type StringPiece::npos = size_type(-1); \ No newline at end of file +const StringPiece::size_type StringPiece::npos = size_type(-1); diff --git a/src/strings/stringpiece.h b/src/strings/stringpiece.h index 72a4f00f..0c919638 100644 --- a/src/strings/stringpiece.h +++ b/src/strings/stringpiece.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Maintainer: mec@google.com (Michael Chastain) // // A StringPiece points to part or all of a string, Cord, double-quoted string @@ -130,9 +131,7 @@ #include #include #include -#include -using __gnu_cxx::hash; -using __gnu_cxx::hash_map; +#include #include #include #include @@ -311,12 +310,12 @@ class StringPiece { void AppendToString(string* target) const; bool starts_with(StringPiece x) const { - return (length_ >= x.length_) && (memcmp(ptr_, x.ptr_, x.length_) == 0); + return length_ >= x.length_ && strings::memeq(ptr_, x.ptr_, x.length_); } bool ends_with(StringPiece x) const { - return ((length_ >= x.length_) && - (memcmp(ptr_ + (length_-x.length_), x.ptr_, x.length_) == 0)); + return length_ >= x.length_ && + strings::memeq(ptr_ + (length_ - x.length_), x.ptr_, x.length_); } // Checks whether StringPiece starts with x and if so advances the beginning @@ -423,18 +422,15 @@ template struct GoodFastHash; // cannot safely store a StringPiece into an STL container // ------------------------------------------------------------------ -namespace base { -// Specializations of base:: traits enable the use of StringPiece in -// compact_array, etc. Note that StringPiece is not being declared as POD. -template <> struct has_trivial_copy : base::true_type {}; -template <> struct has_trivial_assign : base::true_type {}; -template <> struct has_trivial_destructor : base::true_type {}; -} // namespace base // SWIG doesn't know how to parse this stuff properly. Omit it. #ifndef SWIG HASH_NAMESPACE_DECLARATION_START +#ifdef _MSC_VER +template<> struct hash_compare> { +#else // _MSC_VER template<> struct hash { +#endif // _MSC_VER size_t operator()(StringPiece s) const; // Less than operator, for MSVC. bool operator()(const StringPiece& s1, const StringPiece& s2) const { @@ -446,7 +442,7 @@ template<> struct hash { HASH_NAMESPACE_DECLARATION_END // An implementation of GoodFastHash for StringPiece. See -// GoodFastHash values. +// util/hash/hash.h for caveats on the use of GoodFastHash values. template<> struct GoodFastHash { size_t operator()(StringPiece s) const { return HashStringThoroughly(s.data(), s.size()); @@ -464,4 +460,4 @@ template<> struct GoodFastHash { extern std::ostream& operator<<(std::ostream& o, StringPiece piece); -#endif // STRINGS_STRINGPIECE_H_ \ No newline at end of file +#endif // STRINGS_STRINGPIECE_H_ diff --git a/src/strings/stringpiece_utils.cc b/src/strings/stringpiece_utils.cc index 77b4983b..9c2e0821 100644 --- a/src/strings/stringpiece_utils.cc +++ b/src/strings/stringpiece_utils.cc @@ -13,6 +13,7 @@ // limitations under the License. // + #include "strings/stringpiece_utils.h" #include @@ -61,8 +62,7 @@ stringpiece_ssize_type RemoveUntil(StringPiece* text, char sentinel) { } // skip the sentinel as well if we found one - if (count < text->size()) - count++; + if (count < text->size()) count++; text->remove_prefix(count); return count; @@ -94,8 +94,8 @@ bool ConsumeLeadingDigits(StringPiece* s, uint64* val) { } bool EqualIgnoreCase(StringPiece piece1, StringPiece piece2) { - return (piece1.size() == piece2.size() - && 0 == memcasecmp(piece1.data(), piece2.data(), piece1.size())); + return (piece1.size() == piece2.size() && + 0 == memcasecmp(piece1.data(), piece2.data(), piece1.size())); // memcasecmp uses ascii_tolower(). } @@ -173,9 +173,8 @@ int64 ParseInt64Prefix(StringPiece str, size_t* len, int radix) { size_t StringPieceCaseHash::operator()(StringPiece sp) const { // based on __stl_string_hash in http://www.sgi.com/tech/stl/string size_t hash_val = 0; - for (StringPiece::const_iterator it = sp.begin(); - it != sp.end(); ++it) { + for (StringPiece::const_iterator it = sp.begin(); it != sp.end(); ++it) { hash_val = 5 * hash_val + ascii_tolower(*it); } return hash_val; -} \ No newline at end of file +} diff --git a/src/strings/stringpiece_utils.h b/src/strings/stringpiece_utils.h index 258ec980..dab083d4 100644 --- a/src/strings/stringpiece_utils.h +++ b/src/strings/stringpiece_utils.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // Utility functions for operating on StringPieces // Collected here for convenience @@ -152,6 +153,15 @@ inline bool ConsumeCasePrefix(StringPiece* s, StringPiece expected) { return false; } +// Like ConsumeSuffix, but case insensitive. +inline bool ConsumeCaseSuffix(StringPiece* s, StringPiece expected) { + if (EndsWithIgnoreCase(*s, expected)) { + s->remove_suffix(expected.size()); + return true; + } + return false; +} + // Yields the longest prefix in common between both input strings. // Pointer-wise, the returned result is a subset of input "a". StringPiece FindLongestCommonPrefix(StringPiece a, StringPiece b); @@ -180,4 +190,4 @@ struct StringPieceCaseEqual { } }; -#endif // STRINGS_STRINGPIECE_UTILS_H_ \ No newline at end of file +#endif // STRINGS_STRINGPIECE_UTILS_H_ diff --git a/src/strings/strip.cc b/src/strings/strip.cc index b3727850..943c715d 100644 --- a/src/strings/strip.cc +++ b/src/strings/strip.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: jyrki@google.com (Jyrki Alakuijala) // based on contributions of various authors in strings/strutil_unittest.cc // @@ -29,31 +30,25 @@ #include "strings/stringpiece.h" string StripPrefixString(StringPiece str, StringPiece prefix) { - if (str.starts_with(prefix)) - str.remove_prefix(prefix.length()); + if (str.starts_with(prefix)) str.remove_prefix(prefix.length()); return str.as_string(); } -bool TryStripPrefixString(StringPiece str, StringPiece prefix, - string* result) { +bool TryStripPrefixString(StringPiece str, StringPiece prefix, string* result) { const bool has_prefix = str.starts_with(prefix); - if (has_prefix) - str.remove_prefix(prefix.length()); + if (has_prefix) str.remove_prefix(prefix.length()); str.as_string().swap(*result); return has_prefix; } string StripSuffixString(StringPiece str, StringPiece suffix) { - if (str.ends_with(suffix)) - str.remove_suffix(suffix.length()); + if (str.ends_with(suffix)) str.remove_suffix(suffix.length()); return str.as_string(); } -bool TryStripSuffixString(StringPiece str, StringPiece suffix, - string* result) { +bool TryStripSuffixString(StringPiece str, StringPiece suffix, string* result) { const bool has_suffix = str.ends_with(suffix); - if (has_suffix) - str.remove_suffix(suffix.length()); + if (has_suffix) str.remove_suffix(suffix.length()); str.as_string().swap(*result); return has_suffix; } @@ -93,7 +88,7 @@ void StripString(string* s, StringPiece remove, char replacewith) { // ---------------------------------------------------------------------- void StripWhitespace(const char** str, int* len) { // strip off trailing whitespace - while ((*len) > 0 && ascii_isspace((*str)[(*len)-1])) { + while ((*len) > 0 && ascii_isspace((*str)[(*len) - 1])) { (*len)--; } @@ -116,10 +111,10 @@ bool StripTrailingNewline(string* s) { } void StripWhitespace(string* str) { - int str_length = str->length(); + size_t str_length = str->length(); // Strip off leading whitespace. - int first = 0; + size_t first = 0; while (first < str_length && ascii_isspace(str->at(first))) { ++first; } @@ -134,11 +129,12 @@ void StripWhitespace(string* str) { } // Strip off trailing whitespace. - int last = str_length - 1; - while (last >= 0 && ascii_isspace(str->at(last))) { + // Here, the string is not empty and the first character is not whitespace. + size_t last = str_length - 1; + while (ascii_isspace(str->at(last))) { --last; } - if (last != (str_length - 1) && last >= 0) { + if (last != (str_length - 1)) { str->erase(last + 1, string::npos); } } @@ -154,8 +150,7 @@ void StripBrackets(char left, char right, string* s) { string::iterator opencurly = std::find(s->begin(), s->end(), left); while (opencurly != s->end()) { string::iterator closecurly = std::find(opencurly, s->end(), right); - if (closecurly == s->end()) - return; + if (closecurly == s->end()) return; opencurly = s->erase(opencurly, closecurly + 1); opencurly = std::find(opencurly, s->end(), left); } @@ -182,7 +177,6 @@ string OutputWithMarkupTagsStripped(const string& s) { return result; } - int TrimStringLeft(string* s, StringPiece remove) { int i = 0; while (i < s->size() && memchr(remove.data(), (*s)[i], remove.size())) { @@ -194,7 +188,7 @@ int TrimStringLeft(string* s, StringPiece remove) { int TrimStringRight(string* s, StringPiece remove) { int i = s->size(), trimmed = 0; - while (i > 0 && memchr(remove.data(), (*s)[i-1], remove.size())) { + while (i > 0 && memchr(remove.data(), (*s)[i - 1], remove.size())) { --i; } if (i < s->size()) { @@ -208,7 +202,8 @@ int TrimStringRight(string* s, StringPiece remove) { // Various removal routines // ---------------------------------------------------------------------- int strrm(char* str, char c) { - char *src, *dest; + char* src; + char* dest; for (src = dest = str; *src != '\0'; ++src) if (*src != c) *(dest++) = *src; *dest = '\0'; @@ -216,14 +211,16 @@ int strrm(char* str, char c) { } int memrm(char* str, int strlen, char c) { - char *src, *dest; + char* src; + char* dest; for (src = dest = str; strlen-- > 0; ++src) if (*src != c) *(dest++) = *src; return dest - str; } int strrmm(char* str, const char* chars) { - char *src, *dest; + char* src; + char* dest; for (src = dest = str; *src != '\0'; ++src) { bool skip = false; for (const char* c = chars; *c != '\0'; c++) { @@ -241,15 +238,13 @@ int strrmm(char* str, const char* chars) { int strrmm(string* str, const string& chars) { size_t str_len = str->length(); size_t in_index = str->find_first_of(chars); - if (in_index == string::npos) - return str_len; + if (in_index == string::npos) return str_len; size_t out_index = in_index++; while (in_index < str_len) { char c = (*str)[in_index++]; - if (chars.find(c) == string::npos) - (*str)[out_index++] = c; + if (chars.find(c) == string::npos) (*str)[out_index++] = c; } str->resize(out_index); @@ -264,8 +259,7 @@ int strrmm(string* str, const string& chars) { // Return the number of characters removed // ---------------------------------------------------------------------- int StripDupCharacters(string* s, char dup_char, int start_pos) { - if (start_pos < 0) - start_pos = 0; + if (start_pos < 0) start_pos = 0; // remove dups by compaction in-place int input_pos = start_pos; // current reader position @@ -297,12 +291,11 @@ void RemoveExtraWhitespace(string* s) { assert(s != NULL); // Empty strings clearly have no whitespace, and this code assumes that // string length is greater than 0 - if (s->empty()) - return; + if (s->empty()) return; - int input_pos = 0; // current reader position - int output_pos = 0; // current writer position - const int input_end = s->size(); + size_t input_pos = 0; // current reader position + size_t output_pos = 0; // current writer position + const size_t input_end = s->size(); // Strip off leading space while (input_pos < input_end && ascii_isspace((*s)[input_pos])) input_pos++; @@ -363,7 +356,7 @@ void StripTrailingWhitespace(string* const s) { void TrimRunsInString(string* s, StringPiece remove) { string::iterator dest = s->begin(); string::iterator src_end = s->end(); - for (string::iterator src = s->begin(); src != src_end; ) { + for (string::iterator src = s->begin(); src != src_end;) { if (remove.find(*src) == StringPiece::npos) { *(dest++) = *(src++); } else { @@ -389,4 +382,4 @@ void TrimRunsInString(string* s, StringPiece remove) { // ---------------------------------------------------------------------- void RemoveNullsInString(string* s) { s->erase(std::remove(s->begin(), s->end(), '\0'), s->end()); -} \ No newline at end of file +} diff --git a/src/strings/strip.h b/src/strings/strip.h index 49562488..955b642d 100644 --- a/src/strings/strip.h +++ b/src/strings/strip.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: jyrki@google.com (Jyrki Alakuijala) // // #status: RECOMMENDED @@ -223,4 +224,4 @@ int memrm(char* str, int strlen, char c); int strrmm(char* str, const char* chars); int strrmm(string* str, const string& chars); -#endif // STRINGS_STRIP_H_ \ No newline at end of file +#endif // STRINGS_STRIP_H_ diff --git a/src/strings/util.cc b/src/strings/util.cc deleted file mode 100644 index fcfbf2da..00000000 --- a/src/strings/util.cc +++ /dev/null @@ -1,882 +0,0 @@ -// Copyright 1999 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// -// - -// TODO(user): visit each const_cast. Some of them are no longer necessary -// because last Single Unix Spec and grte v2 are more const-y. - -#include "strings/util.h" - -#include -#include -#include -#include -#include // for FastTimeToBuffer() -#include -#include -#include - -#include -#include "strings/ascii_ctype.h" -#include "strings/numbers.h" -#include "strings/stringpiece.h" -#include "util/gtl/stl_util.h" // for STLAppendToString - -#ifdef OS_WINDOWS -#ifdef min // windows.h defines this to something silly -#undef min -#endif -#endif - -using std::vector; - -// Use this instead of gmtime_r if you want to build for Windows. -// Windows doesn't have a 'gmtime_r', but it has the similar 'gmtime_s'. -// TODO(user): Probably belongs in //base:time_support.{cc|h}. -static struct tm* PortableSafeGmtime(const time_t* timep, struct tm* result) { -#ifdef OS_WINDOWS - return gmtime_s(result, timep) == 0 ? result : NULL; -#else - return gmtime_r(timep, result); -#endif // OS_WINDOWS -} - -char* strnstr(const char* haystack, const char* needle, - size_t haystack_len) { - if (*needle == '\0') { - return const_cast(haystack); - } - size_t needle_len = strlen(needle); - char* where; - while ((where = strnchr(haystack, *needle, haystack_len)) != NULL) { - if (where - haystack + needle_len > haystack_len) { - return NULL; - } - if (strncmp(where, needle, needle_len) == 0) { - return where; - } - haystack_len -= where + 1 - haystack; - haystack = where + 1; - } - return NULL; -} - -const char* strnprefix(const char* haystack, int haystack_size, - const char* needle, int needle_size) { - if (needle_size > haystack_size) { - return NULL; - } else { - if (strncmp(haystack, needle, needle_size) == 0) { - return haystack + needle_size; - } else { - return NULL; - } - } -} - -const char* strncaseprefix(const char* haystack, int haystack_size, - const char* needle, int needle_size) { - if (needle_size > haystack_size) { - return NULL; - } else { - if (strncasecmp(haystack, needle, needle_size) == 0) { - return haystack + needle_size; - } else { - return NULL; - } - } -} - -char* strcasesuffix(char* str, const char* suffix) { - const int lenstr = strlen(str); - const int lensuffix = strlen(suffix); - char* strbeginningoftheend = str + lenstr - lensuffix; - - if (lenstr >= lensuffix && 0 == strcasecmp(strbeginningoftheend, suffix)) { - return (strbeginningoftheend); - } else { - return (NULL); - } -} - -const char* strnsuffix(const char* haystack, int haystack_size, - const char* needle, int needle_size) { - if (needle_size > haystack_size) { - return NULL; - } else { - const char* start = haystack + haystack_size - needle_size; - if (strncmp(start, needle, needle_size) == 0) { - return start; - } else { - return NULL; - } - } -} - -const char* strncasesuffix(const char* haystack, int haystack_size, - const char* needle, int needle_size) { - if (needle_size > haystack_size) { - return NULL; - } else { - const char* start = haystack + haystack_size - needle_size; - if (strncasecmp(start, needle, needle_size) == 0) { - return start; - } else { - return NULL; - } - } -} - -char* strchrnth(const char* str, const char& c, int n) { - if (str == NULL) - return NULL; - if (n <= 0) - return const_cast(str); - const char* sp; - int k = 0; - for (sp = str; *sp != '\0'; sp ++) { - if (*sp == c) { - ++k; - if (k >= n) - break; - } - } - return (k < n) ? NULL : const_cast(sp); -} - -char* AdjustedLastPos(const char* str, char separator, int n) { - if ( str == NULL ) - return NULL; - const char* pos = NULL; - if ( n > 0 ) - pos = strchrnth(str, separator, n); - - // if n <= 0 or separator appears fewer than n times, get the last occurrence - if ( pos == NULL) - pos = strrchr(str, separator); - return const_cast(pos); -} - - -// ---------------------------------------------------------------------- -// Misc. routines -// ---------------------------------------------------------------------- - -bool IsAscii(const char* str, int len) { - const char* end = str + len; - while (str < end) { - if (!ascii_isascii(*str++)) { - return false; - } - } - return true; -} - -namespace strings { - -bool IsPrint(StringPiece str) { - const char* strp = str.data(); - const char* end = strp + str.size(); - while (strp < end) { - if (!ascii_isprint(*strp++)) { - return false; - } - } - return true; -} - -} // namespace strings - -string StringReplace(StringPiece s, StringPiece oldsub, - StringPiece newsub, bool replace_all) { - string ret; - StringReplace(s, oldsub, newsub, replace_all, &ret); - return ret; -} - -void StringReplace(StringPiece s, StringPiece oldsub, - StringPiece newsub, bool replace_all, - string* res) { - if (oldsub.empty()) { - res->append(s.data(), s.length()); // If empty, append the given string. - return; - } - - StringPiece::size_type start_pos = 0; - StringPiece::size_type pos; - do { - pos = s.find(oldsub, start_pos); - if (pos == StringPiece::npos) { - break; - } - res->append(s.data() + start_pos, pos - start_pos); - res->append(newsub.data(), newsub.length()); - // Start searching again after the "old". - start_pos = pos + oldsub.length(); - } while (replace_all); - res->append(s.data() + start_pos, s.length() - start_pos); -} - -int GlobalReplaceSubstring(StringPiece substring, - StringPiece replacement, - string* s) { - CHECK(s != NULL); - if (s->empty() || substring.empty()) - return 0; - string tmp; - int num_replacements = 0; - int pos = 0; - for (int match_pos = s->find(substring.data(), pos, substring.length()); - match_pos != string::npos; - pos = match_pos + substring.length(), - match_pos = s->find(substring.data(), pos, substring.length())) { - ++num_replacements; - // Append the original content before the match. - tmp.append(*s, pos, match_pos - pos); - // Append the replacement for the match. - tmp.append(replacement.begin(), replacement.end()); - } - // Append the content after the last match. If no replacements were made, the - // original string is left untouched. - if (num_replacements > 0) { - tmp.append(*s, pos, s->length() - pos); - s->swap(tmp); - } - return num_replacements; -} - -char *gstrcasestr(const char* haystack, const char* needle) { - char c, sc; - size_t len; - - if ((c = *needle++) != 0) { - c = ascii_tolower(c); - len = strlen(needle); - do { - do { - if ((sc = *haystack++) == 0) - return NULL; - } while (ascii_tolower(sc) != c); - } while (strncasecmp(haystack, needle, len) != 0); - haystack--; - } - // This is a const violation but strstr() also returns a char*. - return const_cast(haystack); -} - -const char *gstrncasestr(const char* haystack, const char* needle, size_t len) { - char c, sc; - - if ((c = *needle++) != 0) { - c = ascii_tolower(c); - size_t needle_len = strlen(needle); - do { - do { - if (len-- <= needle_len - || 0 == (sc = *haystack++)) - return NULL; - } while (ascii_tolower(sc) != c); - } while (strncasecmp(haystack, needle, needle_len) != 0); - haystack--; - } - return haystack; -} - -char *gstrncasestr_split(const char* str, - const char* prefix, char non_alpha, - const char* suffix, - size_t n) { - int prelen = prefix == NULL ? 0 : strlen(prefix); - int suflen = suffix == NULL ? 0 : strlen(suffix); - - // adjust the string and its length to avoid unnessary searching. - // an added benefit is to avoid unnecessary range checks in the if - // statement in the inner loop. - if (suflen + prelen >= n) return NULL; - str += prelen; - n -= prelen; - n -= suflen; - - const char* where = NULL; - - // for every occurance of non_alpha in the string ... - while ((where = static_cast( - memchr(str, non_alpha, n))) != NULL) { - // ... test whether it is followed by suffix and preceded by prefix - if ((!suflen || strncasecmp(where + 1, suffix, suflen) == 0) && - (!prelen || strncasecmp(where - prelen, prefix, prelen) == 0)) { - return const_cast(where - prelen); - } - // if not, advance the pointer, and adjust the length according - n -= (where + 1) - str; - str = where + 1; - } - - return NULL; -} - -char *strcasestr_alnum(const char *haystack, const char *needle) { - const char *haystack_ptr; - const char *needle_ptr; - - // Skip non-alnums at beginning - while ( !ascii_isalnum(*needle) ) - if ( *needle++ == '\0' ) - return const_cast(haystack); - needle_ptr = needle; - - // Skip non-alnums at beginning - while ( !ascii_isalnum(*haystack) ) - if ( *haystack++ == '\0' ) - return NULL; - haystack_ptr = haystack; - - while ( *needle_ptr != '\0' ) { - // Non-alnums - advance - while ( !ascii_isalnum(*needle_ptr) ) - if ( *needle_ptr++ == '\0' ) - return const_cast(haystack); - - while ( !ascii_isalnum(*haystack_ptr) ) - if ( *haystack_ptr++ == '\0' ) - return NULL; - - if ( ascii_tolower(*needle_ptr) == ascii_tolower(*haystack_ptr) ) { - // Case-insensitive match - advance - needle_ptr++; - haystack_ptr++; - } else { - // No match - rollback to next start point in haystack - haystack++; - while ( !ascii_isalnum(*haystack) ) - if ( *haystack++ == '\0' ) - return NULL; - haystack_ptr = haystack; - needle_ptr = needle; - } - } - return const_cast(haystack); -} - -int CountSubstring(StringPiece text, StringPiece substring) { - CHECK_GT(substring.length(), 0); - - int count = 0; - StringPiece::size_type curr = 0; - while (StringPiece::npos != (curr = text.find(substring, curr))) { - ++count; - ++curr; - } - return count; -} - -const char* strstr_delimited(const char* haystack, - const char* needle, - char delim) { - if (!needle || !haystack) return NULL; - if (*needle == '\0') return haystack; - - int needle_len = strlen(needle); - - while (true) { - // Skip any leading delimiters. - while (*haystack == delim) ++haystack; - - // Walk down the haystack, matching every character in the needle. - const char* this_match = haystack; - int i = 0; - for (; i < needle_len; i++) { - if (*haystack != needle[i]) { - // We ran out of haystack or found a non-matching character. - break; - } - ++haystack; - } - - // If we matched the whole needle, ensure that it's properly delimited. - if (i == needle_len && (*haystack == '\0' || *haystack == delim)) { - return this_match; - } - - // No match. Consume non-delimiter characters until we run out of them. - while (*haystack != delim) { - if (*haystack == '\0') return NULL; - ++haystack; - } - } - LOG(FATAL) << "Unreachable statement"; - return NULL; -} - -// ---------------------------------------------------------------------- -// Older versions of libc have a buggy strsep. -// ---------------------------------------------------------------------- - -char* gstrsep(char** stringp, const char* delim) { - char *s; - const char *spanp; - int c, sc; - char *tok; - - if ((s = *stringp) == NULL) - return NULL; - - tok = s; - while (true) { - c = *s++; - spanp = delim; - do { - if ((sc = *spanp++) == c) { - if (c == 0) - s = NULL; - else - s[-1] = 0; - *stringp = s; - return tok; - } - } while (sc != 0); - } - - return NULL; /* should not happen */ -} - -void FastStringAppend(string* s, const char* data, int len) { - STLAppendToString(s, data, len); -} - -// TODO(jyrki): add a microbenchmark and revisit -// the optimizations done here. -// -// Several converters use this table to reduce -// division and modulo operations. -extern const char two_ASCII_digits[100][2]; - -const char two_ASCII_digits[100][2] = { - {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, - {'0', '5'}, {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, - {'1', '0'}, {'1', '1'}, {'1', '2'}, {'1', '3'}, {'1', '4'}, - {'1', '5'}, {'1', '6'}, {'1', '7'}, {'1', '8'}, {'1', '9'}, - {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'}, {'2', '4'}, - {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'}, - {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, - {'3', '5'}, {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, - {'4', '0'}, {'4', '1'}, {'4', '2'}, {'4', '3'}, {'4', '4'}, - {'4', '5'}, {'4', '6'}, {'4', '7'}, {'4', '8'}, {'4', '9'}, - {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'}, {'5', '4'}, - {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'}, - {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, - {'6', '5'}, {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, - {'7', '0'}, {'7', '1'}, {'7', '2'}, {'7', '3'}, {'7', '4'}, - {'7', '5'}, {'7', '6'}, {'7', '7'}, {'7', '8'}, {'7', '9'}, - {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'}, {'8', '4'}, - {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'}, - {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, - {'9', '5'}, {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'} -}; - -static inline void PutTwoDigits(int i, char* p) { - DCHECK_GE(i, 0); - DCHECK_LT(i, 100); - p[0] = two_ASCII_digits[i][0]; - p[1] = two_ASCII_digits[i][1]; -} - -char* FastTimeToBuffer(time_t s, char* buffer) { - if (s == 0) { - time(&s); - } - - struct tm tm; - if (PortableSafeGmtime(&s, &tm) == NULL) { - // Error message must fit in 30-char buffer. - memcpy(buffer, "Invalid:", sizeof("Invalid:")); - FastInt64ToBufferLeft(s, buffer+strlen(buffer)); - return buffer; - } - - // strftime format: "%a, %d %b %Y %H:%M:%S GMT", - // but strftime does locale stuff which we do not want - // plus strftime takes > 10x the time of hard code - - const char* weekday_name = "Xxx"; - switch (tm.tm_wday) { - default: { DLOG(FATAL) << "tm.tm_wday: " << tm.tm_wday; } break; - case 0: weekday_name = "Sun"; break; - case 1: weekday_name = "Mon"; break; - case 2: weekday_name = "Tue"; break; - case 3: weekday_name = "Wed"; break; - case 4: weekday_name = "Thu"; break; - case 5: weekday_name = "Fri"; break; - case 6: weekday_name = "Sat"; break; - } - - const char* month_name = "Xxx"; - switch (tm.tm_mon) { - default: { DLOG(FATAL) << "tm.tm_mon: " << tm.tm_mon; } break; - case 0: month_name = "Jan"; break; - case 1: month_name = "Feb"; break; - case 2: month_name = "Mar"; break; - case 3: month_name = "Apr"; break; - case 4: month_name = "May"; break; - case 5: month_name = "Jun"; break; - case 6: month_name = "Jul"; break; - case 7: month_name = "Aug"; break; - case 8: month_name = "Sep"; break; - case 9: month_name = "Oct"; break; - case 10: month_name = "Nov"; break; - case 11: month_name = "Dec"; break; - } - - // Write out the buffer. - - memcpy(buffer+0, weekday_name, 3); - buffer[3] = ','; - buffer[4] = ' '; - - PutTwoDigits(tm.tm_mday, buffer+5); - buffer[7] = ' '; - - memcpy(buffer+8, month_name, 3); - buffer[11] = ' '; - - int32 year = tm.tm_year + 1900; - if (year >= 0 && year <= 9999) { - PutTwoDigits(year/100, buffer+12); - } else { - memcpy(buffer, "Invalid:", sizeof("Invalid:")); - FastInt64ToBufferLeft(s, buffer+strlen(buffer)); - return buffer; - } - PutTwoDigits(year%100, buffer+14); - buffer[16] = ' '; - - PutTwoDigits(tm.tm_hour, buffer+17); - buffer[19] = ':'; - - PutTwoDigits(tm.tm_min, buffer+20); - buffer[22] = ':'; - - PutTwoDigits(tm.tm_sec, buffer+23); - - // includes ending NUL - memcpy(buffer+25, " GMT", 5); - - return buffer; -} - -char* strdup_with_new(const char* the_string) { - if (the_string == NULL) - return NULL; - else - return strndup_with_new(the_string, strlen(the_string)); -} - -char* strndup_with_new(const char* the_string, int max_length) { - if (the_string == NULL) - return NULL; - - char* result = new char[max_length + 1]; - result[max_length] = '\0'; // terminate the string because strncpy might not - return strncpy(result, the_string, max_length); -} - -const char* ScanForFirstWord(const char* the_string, const char** end_ptr) { - CHECK(end_ptr != NULL) << ": precondition violated"; - - if (the_string == NULL) // empty string - return NULL; - - const char* curr = the_string; - while ((*curr != '\0') && ascii_isspace(*curr)) // skip initial spaces - ++curr; - - if (*curr == '\0') // no valid word found - return NULL; - - // else has a valid word - const char* first_word = curr; - - // now locate the end of the word - while ((*curr != '\0') && !ascii_isspace(*curr)) - ++curr; - - *end_ptr = curr; - return first_word; -} - -namespace strings { - -StringPiece ScanForFirstWord(StringPiece input) { - const char* curr = input.data(); - const char* const end = curr + input.size(); - - // Skip initial spaces to locate the start of the word. - while ((curr < end) && ascii_isspace(*curr)) - ++curr; - const char* const word = curr; - - // Skip subsequent non-spaces to locate the end of the word. - while ((curr < end) && !ascii_isspace(*curr)) - ++curr; - return StringPiece(word, curr - word); -} - -} // namespace strings - -const char *AdvanceIdentifier(const char *str) { - // Not using isalpha and isalnum so as not to rely on the locale. - // We could have used ascii_isalpha and ascii_isalnum. - char ch = *str++; - if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_')) - return NULL; - while (true) { - ch = *str; - if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || - (ch >= '0' && ch <= '9') || ch == '_')) - return str; - str++; - } -} - -bool IsIdentifier(const char *str) { - const char *end = AdvanceIdentifier(str); - return end && *end == '\0'; -} - -void UniformInsertString(string* s, int interval, const char* separator) { - const size_t separator_len = strlen(separator); - - if (interval < 1 || // invalid interval - s->empty() || // nothing to do - separator_len == 0) // invalid separator - return; - - int num_inserts = (s->size() - 1) / interval; // -1 to avoid appending at end - if (num_inserts == 0) // nothing to do - return; - - string tmp; - tmp.reserve(s->size() + num_inserts * separator_len + 1); - - for (int i = 0; i < num_inserts ; ++i) { - // append this interval - tmp.append(*s, i * interval, interval); - // append a separator - tmp.append(separator, separator_len); - } - - // append the tail - const size_t tail_pos = num_inserts * interval; - tmp.append(*s, tail_pos, s->size() - tail_pos); - - s->swap(tmp); -} - -void InsertString(string *const s, - const vector &indices, - char const *const separator) { - const unsigned num_indices(indices.size()); - if (num_indices == 0) { - return; // nothing to do... - } - - const unsigned separator_len(strlen(separator)); - if (separator_len == 0) { - return; // still nothing to do... - } - - string tmp; - const unsigned s_len(s->size()); - tmp.reserve(s_len + separator_len * num_indices); - - vector::const_iterator const ind_end(indices.end()); - vector::const_iterator ind_pos(indices.begin()); - - uint32 last_pos(0); - while (ind_pos != ind_end) { - const uint32 pos(*ind_pos); - DCHECK_GE(pos, last_pos); - DCHECK_LE(pos, s_len); - - tmp.append(s->substr(last_pos, pos - last_pos)); - tmp.append(separator); - - last_pos = pos; - ++ind_pos; - } - tmp.append(s->substr(last_pos)); - - s->swap(tmp); -} - -int FindNth(StringPiece s, char c, int n) { - int pos = -1; - - for ( int i = 0; i < n; ++i ) { - pos = s.find_first_of(c, pos + 1); - if ( pos == StringPiece::npos ) { - break; - } - } - return pos; -} - -int ReverseFindNth(StringPiece s, char c, int n) { - if ( n <= 0 ) { - return static_cast(StringPiece::npos); - } - - int pos = s.size(); - - for ( int i = 0; i < n; ++i ) { - // If pos == 0, we return StringPiece::npos right away. Otherwise, - // the following find_last_of call would take (pos - 1) as string::npos, - // which means it would again search the entire input string. - if (pos == 0) { - return static_cast(StringPiece::npos); - } - pos = s.find_last_of(c, pos - 1); - if ( pos == string::npos ) { - break; - } - } - return pos; -} - -namespace strings { - -// FindEol() -// Returns the location of the next end-of-line sequence. - -StringPiece FindEol(StringPiece s) { - for (size_t i = 0; i < s.length(); ++i) { - if (s[i] == '\n') { - return StringPiece(s.data() + i, 1); - } - if (s[i] == '\r') { - if (i+1 < s.length() && s[i+1] == '\n') { - return StringPiece(s.data() + i, 2); - } else { - return StringPiece(s.data() + i, 1); - } - } - } - return StringPiece(s.data() + s.length(), 0); -} - -} // namespace strings - -bool OnlyWhitespace(StringPiece s) { - for ( int i = 0; i < s.size(); ++i ) { - if ( !ascii_isspace(s[i]) ) return false; - } - return true; -} - -string PrefixSuccessor(StringPiece prefix) { - // We can increment the last character in the string and be done - // unless that character is 255 (0xff), in which case we have to erase the - // last character and increment the previous character, unless that - // is 255, etc. If the string is empty or consists entirely of - // 255's, we just return the empty string. - bool done = false; - string limit(prefix.data(), prefix.size()); - int index = limit.length() - 1; - while (!done && index >= 0) { - if (limit[index] == '\xff') { // char literal avoids signed/unsigned. - limit.erase(index); - index--; - } else { - limit[index]++; - done = true; - } - } - if (!done) { - return ""; - } else { - return limit; - } -} - -string ImmediateSuccessor(StringPiece s) { - // Return the input string, with an additional NUL byte appended. - string out; - out.reserve(s.size() + 1); - out.append(s.data(), s.size()); - out.push_back('\0'); - return out; -} - -void FindShortestSeparator(StringPiece start, - StringPiece limit, - string* separator) { - // Find length of common prefix - size_t min_length = std::min(start.size(), limit.size()); - size_t diff_index = 0; - while ((diff_index < min_length) && - (start[diff_index] == limit[diff_index])) { - diff_index++; - } - - if (diff_index >= min_length) { - // Handle the case where either string is a prefix of the other - // string, or both strings are identical. - start.CopyToString(separator); - return; - } - - if (diff_index+1 == start.size()) { - // If the first difference is in the last character, do not bother - // incrementing that character since the separator will be no - // shorter than "start". - start.CopyToString(separator); - return; - } - - if (start[diff_index] == '\xff') { // char literal avoids signed/unsigned. - // Avoid overflow when incrementing start[diff_index] - start.CopyToString(separator); - return; - } - - separator->assign(start.data(), diff_index); - separator->push_back(start[diff_index] + 1); - if (*separator >= limit) { - // Never pick a separator that causes confusion with "limit" - start.CopyToString(separator); - } -} - -int SafeSnprintf(char *str, size_t size, const char *format, ...) { - va_list printargs; - va_start(printargs, format); - int ncw = vsnprintf(str, size, format, printargs); - va_end(printargs); - return (ncw < size && ncw >= 0) ? ncw : 0; -} - -bool GetlineFromStdioFile(FILE* file, string* str, char delim) { - str->erase(); - while (true) { - if (feof(file) || ferror(file)) { - return false; - } - int c = getc(file); - if (c == EOF) return false; - if (c == delim) return true; - str->push_back(c); - } -} \ No newline at end of file diff --git a/src/strings/util.h b/src/strings/util.h deleted file mode 100644 index 7c18695c..00000000 --- a/src/strings/util.h +++ /dev/null @@ -1,501 +0,0 @@ -// Copyright 1999 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// -// -// Useful string functions and so forth. This is a grab-bag file. -// -// You might also want to look at memutil.h, which holds mem*() -// equivalents of a lot of the str*() functions in string.h, -// eg memstr, mempbrk, etc. -// -// These functions work fine for UTF-8 strings as long as you can -// consider them to be just byte strings. For example, due to the -// design of UTF-8 you do not need to worry about accidental matches, -// as long as all your inputs are valid UTF-8 (use \uHHHH, not \xHH or \oOOO). -// -// Caveats: -// * all the lengths in these routines refer to byte counts, -// not character counts. -// * case-insensitivity in these routines assumes that all the letters -// in question are in the range A-Z or a-z. -// -// If you need Unicode specific processing (for example being aware of -// Unicode character boundaries, or knowledge of Unicode casing rules, -// or various forms of equivalence and normalization), take a look at -// files in i18n/utf8. - -#ifndef STRINGS_UTIL_H_ -#define STRINGS_UTIL_H_ - -#include -#include -#include -#include -#ifndef _MSC_VER -#include // for strcasecmp, but msvc does not have this header -#endif - -#include -#include -#include - -#include "base/integral_types.h" -#include "base/port.h" -#include "strings/stringpiece.h" - -// Newer functions. - -namespace strings { - -// Finds the next end-of-line sequence. -// An end-of-line sequence is one of: -// \n common on unix, including mac os x -// \r common on macos 9 and before -// \r\n common on windows -// -// Returns a StringPiece that contains the end-of-line sequence (a pointer into -// the input, 1 or 2 characters long). -// -// If the input does not contain an end-of-line sequence, returns an empty -// StringPiece located at the end of the input: -// StringPiece(sp.data() + sp.length(), 0). - -StringPiece FindEol(StringPiece sp); - -} // namespace strings - -// Older functions. - -// Duplicates a non-null, non-empty char* string. Returns a pointer to the new -// string, or NULL if the input is null or empty. -inline char* strdup_nonempty(const char* src) { - if (src && src[0]) return strdup(src); - return NULL; -} - -// Finds the first occurrence of a character in at most a given number of bytes -// of a char* string. Returns a pointer to the first occurrence, or NULL if no -// occurrence found in the first sz bytes. -// Never searches past the first null character in the string; therefore, only -// suitable for null-terminated strings. -// WARNING: Removes const-ness of string argument! -inline char* strnchr(const char* buf, char c, int sz) { - const char* end = buf + sz; - while (buf != end && *buf) { - if (*buf == c) - return const_cast(buf); - ++buf; - } - return NULL; -} - -// Finds the first occurrence of the null-terminated needle in at most the first -// haystack_len bytes of haystack. Returns NULL if needle is not found. Returns -// haystack if needle is empty. -// WARNING: Removes const-ness of string argument! -char* strnstr(const char* haystack, const char* needle, size_t haystack_len); - -// Matches a prefix (which must be a char* literal!) against the beginning of -// str. Returns a pointer past the prefix, or NULL if the prefix wasn't matched. -// (Like the standard strcasecmp(), but for efficiency doesn't call strlen() on -// prefix, and returns a pointer rather than an int.) -// -// For a similar function that works on StringPiece, see StringPiece::Consume. -// -// The ""'s catch people who don't pass in a literal for "prefix" -#ifndef strprefix -#define strprefix(str, prefix) \ - (strncmp(str, prefix, sizeof("" prefix "")-1) == 0 ? \ - str + sizeof(prefix)-1 : \ - NULL) -#endif - -// Same as strprefix() (immediately above), but matches a case-insensitive -// prefix. -#ifndef strcaseprefix -#define strcaseprefix(str, prefix) \ - (strncasecmp(str, prefix, sizeof("" prefix "")-1) == 0 ? \ - str + sizeof(prefix)-1 : \ - NULL) -#endif - -// Matches a prefix (up to the first needle_size bytes of needle) in the first -// haystack_size byte of haystack. Returns a pointer past the prefix, or NULL if -// the prefix wasn't matched. (Unlike strprefix(), prefix doesn't need to be a -// char* literal. Like the standard strncmp(), but also takes a haystack_size, -// and returns a pointer rather than an int.) -// -// Always returns either NULL or haystack + needle_size. -// -// Some windows header sometimes #defines strnprefix to something we -// don't want. -#ifdef strnprefix -#undef strnprefix -#endif -const char* strnprefix(const char* haystack, int haystack_size, - const char* needle, int needle_size); - -// Matches a case-insensitive prefix (up to the first needle_size bytes of -// needle) in the first haystack_size byte of haystack. Returns a pointer past -// the prefix, or NULL if the prefix wasn't matched. -// -// Always returns either NULL or haystack + needle_size. -const char* strncaseprefix(const char* haystack, int haystack_size, - const char* needle, int needle_size); - -// Matches a prefix; returns a pointer past the prefix, or NULL if not found. -// (Like strprefix() and strcaseprefix() but not restricted to searching for -// char* literals). Templated so searching a const char* returns a const char*, -// and searching a non-const char* returns a non-const char*. -template -inline CharStar var_strprefix(CharStar str, const char* prefix) { - const int len = strlen(prefix); - return strncmp(str, prefix, len) == 0 ? str + len : NULL; -} - -// Same as var_strprefix() (immediately above), but matches a case-insensitive -// prefix. -template -inline CharStar var_strcaseprefix(CharStar str, const char* prefix) { - const int len = strlen(prefix); - return strncasecmp(str, prefix, len) == 0 ? str + len : NULL; -} - -// Returns input, or "(null)" if NULL. (Useful for logging.) -inline const char* GetPrintableString(const char* const in) { - return NULL == in ? "(null)" : in; -} - -// Returns whether str begins with prefix. -inline bool HasPrefixString(StringPiece str, - StringPiece prefix) { - return str.starts_with(prefix); -} - -// Returns whether str ends with suffix. -inline bool HasSuffixString(StringPiece str, - StringPiece suffix) { - return str.ends_with(suffix); -} - -// Returns where suffix begins in str, or NULL if str doesn't end with suffix. -inline char* strsuffix(char* str, const char* suffix) { - const int lenstr = strlen(str); - const int lensuffix = strlen(suffix); - char* strbeginningoftheend = str + lenstr - lensuffix; - - if (lenstr >= lensuffix && 0 == strcmp(strbeginningoftheend, suffix)) { - return (strbeginningoftheend); - } else { - return (NULL); - } -} -inline const char* strsuffix(const char* str, const char* suffix) { - return const_cast(strsuffix(const_cast(str), suffix)); -} - -// Same as strsuffix() (immediately above), but matches a case-insensitive -// suffix. -char* strcasesuffix(char* str, const char* suffix); -inline const char* strcasesuffix(const char* str, const char* suffix) { - return const_cast(strcasesuffix(const_cast(str), suffix)); -} - -const char* strnsuffix(const char* haystack, int haystack_size, - const char* needle, int needle_size); -const char* strncasesuffix(const char* haystack, int haystack_size, - const char* needle, int needle_size); - -// Returns the number of times a character occurs in a string for a null -// terminated string. -inline ptrdiff_t strcount(const char* buf, char c) { - if (buf == NULL) - return 0; - ptrdiff_t num = 0; - for (const char* bp = buf; *bp != '\0'; bp++) { - if (*bp == c) - num++; - } - return num; -} -// Returns the number of times a character occurs in a string for a string -// defined by a pointer to the first character and a pointer just past the last -// character. -inline ptrdiff_t strcount(const char* buf_begin, const char* buf_end, char c) { - if (buf_begin == NULL) - return 0; - if (buf_end <= buf_begin) - return 0; - ptrdiff_t num = 0; - for (const char* bp = buf_begin; bp != buf_end; bp++) { - if (*bp == c) - num++; - } - return num; -} -// Returns the number of times a character occurs in a string for a string -// defined by a pointer to the first char and a length: -inline ptrdiff_t strcount(const char* buf, size_t len, char c) { - return strcount(buf, buf + len, c); -} -// Returns the number of times a character occurs in a string for a C++ string: -inline ptrdiff_t strcount(const string& buf, char c) { - return strcount(buf.c_str(), buf.size(), c); -} - -// Returns a pointer to the nth occurrence of a character in a null-terminated -// string. -// WARNING: Removes const-ness of string argument! -char* strchrnth(const char* str, const char& c, int n); - -// Returns a pointer to the nth occurrence of a character in a null-terminated -// string, or the last occurrence if occurs fewer than n times. -// WARNING: Removes const-ness of string argument! -char* AdjustedLastPos(const char* str, char separator, int n); - -// STL-compatible function objects for char* string keys: - -// Compares two char* strings for equality. (Works with NULL, which compares -// equal only to another NULL). Useful in hash tables: -// hash_map, streq> ht; -struct streq : public std::binary_function { - bool operator()(const char* s1, const char* s2) const { - return ((s1 == 0 && s2 == 0) || - (s1 && s2 && *s1 == *s2 && strcmp(s1, s2) == 0)); - } -}; - -// Compares two char* strings. (Works with NULL, which compares greater than any -// non-NULL). Useful in maps: -// map m; -struct strlt : public std::binary_function { - bool operator()(const char* s1, const char* s2) const { - return (s1 != s2) && (s2 == 0 || (s1 != 0 && strcmp(s1, s2) < 0)); - } -}; - -// Returns whether str has only Ascii characters (as defined by ascii_isascii() -// in strings/ascii_ctype.h). -bool IsAscii(const char* str, int len); -inline bool IsAscii(StringPiece str) { - return IsAscii(str.data(), str.size()); -} - -namespace strings { - -// Returns whether str has only printable characters (as defined by -// ascii_isprint() in strings/ascii_ctype.h). -bool IsPrint(StringPiece str); - -} // namespace strings - -// Returns the smallest lexicographically larger string of equal or smaller -// length. Returns an empty string if there is no such successor (if the input -// is empty or consists entirely of 0xff bytes). -// Useful for calculating the smallest lexicographically larger string -// that will not be prefixed by the input string. -// -// Examples: -// "a" -> "b", "aaa" -> "aab", "aa\xff" -> "ab", "\xff" -> "", "" -> "" -string PrefixSuccessor(StringPiece prefix); - -// Returns the immediate lexicographically-following string. This is useful to -// turn an inclusive range into something that can be used with Bigtable's -// SetLimitRow(): -// -// // Inclusive range [min_element, max_element]. -// string min_element = ...; -// string max_element = ...; -// -// // Equivalent range [range_start, range_end). -// string range_start = min_element; -// string range_end = ImmediateSuccessor(max_element); -// -// WARNING: Returns the input string with a '\0' appended; if you call c_str() -// on the result, it will compare equal to s. -// -// WARNING: Transforms "" -> "\0"; this doesn't account for Bigtable's special -// treatment of "" as infinity. -string ImmediateSuccessor(StringPiece s); - -// Fills in *separator with a short string less than limit but greater than or -// equal to start. If limit is greater than start, *separator is the common -// prefix of start and limit, followed by the successor to the next character in -// start. Examples: -// FindShortestSeparator("foobar", "foxhunt", &sep) => sep == "fop" -// FindShortestSeparator("abracadabra", "bacradabra", &sep) => sep == "b" -// If limit is less than or equal to start, fills in *separator with start. -void FindShortestSeparator(StringPiece start, StringPiece limit, - string* separator); - -// Copies at most n-1 bytes from src to dest, and returns dest. If n >=1, null -// terminates dest; otherwise, returns dest unchanged. Unlike strncpy(), only -// puts one null character at the end of dest. -inline char* safestrncpy(char* dest, const char* src, size_t n) { - if (n < 1) return dest; - - // Avoid using non-ANSI memccpy(), which is also deprecated in MSVC - for (size_t i = 0; i < n; ++i) { - if ((dest[i] = src[i]) == '\0') - return dest; - } - - dest[n-1] = '\0'; - return dest; -} - -// Replaces the first occurrence (if replace_all is false) or all occurrences -// (if replace_all is true) of oldsub in s with newsub. -string StringReplace(StringPiece s, StringPiece oldsub, - StringPiece newsub, bool replace_all); -// This version appends the output to *res, and *res must be distinct from all -// the other arguments. -void StringReplace(StringPiece s, StringPiece oldsub, - StringPiece newsub, bool replace_all, - string* res); - -// Replaces all occurrences of substring in s with replacement. Returns the -// number of instances replaced. s must be distinct from the other arguments. -// -// Less flexible, but faster, than RE::GlobalReplace(). -int GlobalReplaceSubstring(StringPiece substring, - StringPiece replacement, - string* s); - -// Case-insensitive strstr(); use system strcasestr() instead. -// WARNING: Removes const-ness of string argument! -char* gstrcasestr(const char* haystack, const char* needle); - -// Finds (case insensitively) the first occurrence of (null terminated) needle -// in at most the first len bytes of haystack. Returns a pointer into haystack, -// or NULL if needle wasn't found. -const char* gstrncasestr(const char* haystack, const char* needle, size_t len); - -// Finds (case insensitively), in str (which is a list of tokens separated by -// non_alpha), a token prefix and a token suffix. Returns a pointer into str of -// the position of prefix, or NULL if not found. -// WARNING: Removes const-ness of string argument! -char* gstrncasestr_split(const char* str, - const char* prefix, char non_alpha, - const char* suffix, - size_t n); - -// Finds (case insensitively) needle in haystack, paying attention only to -// alphanumerics in either string. Returns a pointer into haystack, or NULL if -// not found. -// Example: strcasestr_alnum("This is a longer test string", "IS-A-LONGER") -// returns a pointer to "is a longer". -// WARNING: Removes const-ness of string argument! -char* strcasestr_alnum(const char* haystack, const char* needle); - -// Returns the number times substring appears in text. -// Note: Runs in O(text.length() * substring.length()). Do *not* use on long -// strings. -int CountSubstring(StringPiece text, StringPiece substring); - -// Returns a pointer to the start of needle in haystack. The haystack is -// interpreted as tokens separated by one or more of delim; to be found, -// needle's occurrence must start and end on whole token boundaries. -// If the needle is not found, or if either of the parameters is a null -// pointer, the call returns a null pointer. -// An empty string needle is found at the beginning of any non-null haystack, -// including an empty string haystack. -// -// NOTE: Consider instead using strings::Split() (strings/split.h) -// and std::find(). -const char* strstr_delimited(const char* haystack, - const char* needle, - char delim); - -// Gets the next token from string *stringp, where tokens are strings separated -// by characters from delim. -char* gstrsep(char** stringp, const char* delim); - -// Appends StringPiece(data, len) to *s. -void FastStringAppend(string* s, const char* data, int len); - -// Returns a duplicate of the_string, with memory allocated by new[]. -char* strdup_with_new(const char* the_string); - -// Returns a duplicate of up to the first max_length bytes of the_string, with -// memory allocated by new[]. -char* strndup_with_new(const char* the_string, int max_length); - -// Finds, in the_string, the first "word" (consecutive !ascii_isspace() -// characters). Returns pointer to the beginning of the word, and sets *end_ptr -// to the character after the word (which may be space or '\0'); returns NULL -// (and *end_ptr is undefined) if no next word found. -// end_ptr must not be NULL. -// -// Both these functions are DEPRECATED(mec). -// Call strings::ScanForFirstWord below. -const char* ScanForFirstWord(const char* the_string, const char** end_ptr); - -namespace strings { - -// A version with a StringPiece-based interface. Returns the first "word" -// (consecutive !ascii_isspace() characters, as above) in the input, or an -// empty StringPiece otherwise. When non-empty, the return value will alias -// the array underlying the input. -StringPiece ScanForFirstWord(StringPiece input); - -} // namespace strings - -// For the following functions, an "identifier" is a letter or underscore, -// followed by letters, underscores, or digits. - -// Returns a pointer past the end of the "identifier" (see above) beginning at -// str, or NULL if str doesn't start with an identifier. -const char* AdvanceIdentifier(const char* str); - -// Returns whether str is an "identifier" (see above). -bool IsIdentifier(const char* str); - -// Inserts separator after every interval characters in *s (but never appends to -// the end of the original *s). -void UniformInsertString(string* s, int interval, const char* separator); - -// Inserts separator into s at each specified index. indices must be sorted in -// ascending order. -void InsertString( - string* s, const std::vector& indices, char const* separator); - -// Finds the nth occurrence of c in s; returns the index in s of that -// occurrence, or string::npos if fewer than n occurrences. -int FindNth(StringPiece s, char c, int n); - -// Finds the nth-to-last occurrence of c in s; returns the index in s of that -// occurrence, or string::npos if fewer than n occurrences. -int ReverseFindNth(StringPiece s, char c, int n); - -// Returns whether s contains only whitespace characters (including the case -// where s is empty). -bool OnlyWhitespace(StringPiece s); - -// Formats a string in the same fashion as snprintf(), but returns either the -// number of characters written, or zero if not enough space was available. -// (snprintf() returns the number of characters that would have been written if -// enough space had been available.) -// -// A drop-in replacement for the safe_snprintf() macro. -int SafeSnprintf(char* str, size_t size, const char* format, ...) - PRINTF_ATTRIBUTE(3, 4); - -// Reads a line (terminated by delim) from file into *str. Reads delim from -// file, but doesn't copy it into *str. Returns true if read a delim-terminated -// line, or false on end-of-file or error. -bool GetlineFromStdioFile(FILE* file, string* str, char delim); - -#endif // STRINGS_UTIL_H_ \ No newline at end of file diff --git a/src/dynamic_annotations/dynamic_annotations.h b/src/third_party/dynamic_annotations/dynamic_annotations.h similarity index 100% rename from src/dynamic_annotations/dynamic_annotations.h rename to src/third_party/dynamic_annotations/dynamic_annotations.h diff --git a/src/util/bits/bit-interleave.cc b/src/util/bits/bit-interleave.cc index d1e26b9c..181de38c 100644 --- a/src/util/bits/bit-interleave.cc +++ b/src/util/bits/bit-interleave.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: jyrki@google.com (Jyrki Alakuijala) // // Performance notes: @@ -269,4 +270,4 @@ void DeinterleaveUint8(uint32 x, uint8* a, uint8* b, uint8* c) { *c = UnsplitFor3(x >> 2); } -} // namespace util_bits \ No newline at end of file +} // namespace util_bits diff --git a/src/util/bits/bit-interleave.h b/src/util/bits/bit-interleave.h index 60af9d8b..2f902649 100644 --- a/src/util/bits/bit-interleave.h +++ b/src/util/bits/bit-interleave.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: jyrki@google.com (Jyrki Alakuijala) // // Interleaving bits quickly by table lookup. @@ -49,4 +50,4 @@ void DeinterleaveUint8(uint32 code, uint8 *val0, uint8* val1, uint8* val2); } // namespace util_bits -#endif // UTIL_BITS_BIT_INTERLEAVE_H_ \ No newline at end of file +#endif // UTIL_BITS_BIT_INTERLEAVE_H_ diff --git a/src/util/bits/bits-internal-unknown.h b/src/util/bits/bits-internal-unknown.h index f2cf11a7..de0fd4af 100644 --- a/src/util/bits/bits-internal-unknown.h +++ b/src/util/bits/bits-internal-unknown.h @@ -13,6 +13,7 @@ // limitations under the License. // + #ifndef UTIL_BITS_BITS_INTERNAL_UNKNOWN_H__ #define UTIL_BITS_BITS_INTERNAL_UNKNOWN_H__ @@ -40,4 +41,4 @@ inline int Bits::FindLSBSetNonZero64(uint64 n) { return Bits::FindLSBSetNonZero64_Portable(n); } -#endif // UTIL_BITS_BITS_INTERNAL_UNKNOWN_H__ \ No newline at end of file +#endif // UTIL_BITS_BITS_INTERNAL_UNKNOWN_H__ diff --git a/src/util/bits/bits-internal-windows.h b/src/util/bits/bits-internal-windows.h index 78c6f588..2fbb91b8 100644 --- a/src/util/bits/bits-internal-windows.h +++ b/src/util/bits/bits-internal-windows.h @@ -13,9 +13,18 @@ // limitations under the License. // + #ifndef UTIL_BITS_BITS_INTERNAL_WINDOWS_H__ #define UTIL_BITS_BITS_INTERNAL_WINDOWS_H__ +inline int Bits::FindLSBSetNonZero(uint32 n) { + return Bits::FindLSBSetNonZero_Portable(n); +} + +inline int Bits::FindLSBSetNonZero64(uint64 n) { + return Bits::FindLSBSetNonZero64_Portable(n); +} + inline int Bits::Log2FloorNonZero(uint32 n) { #ifdef _M_IX86 _asm { @@ -53,4 +62,4 @@ inline int Bits::Log2FloorNonZero64(uint64 n) { return Bits::Log2FloorNonZero64_Portable(n); } -#endif // UTIL_BITS_BITS_INTERNAL_WINDOWS_H__ \ No newline at end of file +#endif // UTIL_BITS_BITS_INTERNAL_WINDOWS_H__ diff --git a/src/util/bits/bits.cc b/src/util/bits/bits.cc index 874a33a2..8989cc4e 100644 --- a/src/util/bits/bits.cc +++ b/src/util/bits/bits.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // Derived from code by Moses Charikar @@ -140,4 +141,4 @@ int Bits::CountLeadingZeros64_Portable(uint64 n) { return ((n >> 32) ? Bits::CountLeadingZeros32_Portable(n >> 32) : 32 + Bits::CountLeadingZeros32_Portable(n)); -} \ No newline at end of file +} diff --git a/src/util/bits/bits.h b/src/util/bits/bits.h index 52ac8f95..65d67fef 100644 --- a/src/util/bits/bits.h +++ b/src/util/bits/bits.h @@ -12,11 +12,36 @@ // See the License for the specific language governing permissions and // limitations under the License. // + #ifndef UTIL_BITS_BITS_H_ #define UTIL_BITS_BITS_H_ // -// A collection of useful (static) bit-twiddling functions. +// Various bit-twiddling functions, all of which are static members of the Bits +// class (making it effectively a namespace). Operands are unsigned integers. +// Munging bits in _signed_ integers is fraught with peril! For example, +// -5 << n has undefined behavior (for some values of n). +// +// Bits provide the following: +// +// * Count(Ones.*|LeadingZeros.*)? . In a similar vein, there's also the +// Find[LM]SBSetNonZero.* family of functions. You can think of them as +// (trailing|leading) zero bit count + 1. Also in a similar vein, +// (Capped)?Difference, which count the number of one bits in foo ^ bar. +// +// * ReverseBits${power_of_two} +// +// * Log2(Floor|Ceiling)(NonZero)?.* - The NonZero variants have undefined +// behavior if argument is 0. +// +// * Bytes(ContainByte(LessThan)?|AllInRange) - These scan a sequence of bytes +// looking for one with(out)? some property. +// +// * (Get|Set|Copy)Bits +// +// The only other thing is BitPattern, which is a trait class template (not in +// Bits) containing a few bit patterns (which vary based on value of template +// parameter). #include "base/casts.h" #include "base/integral_types.h" @@ -26,8 +51,10 @@ class Bits { public: - // Forward declaration Helper class for UnsignedType. - template + // A traits class template for unsigned integer type sizes. Primary + // information contained herein is corresponding (unsigned) integer type. + // E.g. UnsignedTypeBySize<32>::Type is uint32. Used by UnsignedType. + template struct UnsignedTypeBySize; // Auxilliary struct for figuring out an unsigned type for a given type. @@ -132,10 +159,6 @@ class Bits { #endif } - // Portable implementations. - static int CountLeadingZeros32_Portable(uint32 n); - static int CountLeadingZeros64_Portable(uint64 n); - // Reverse the bits in the given integer. static uint8 ReverseBits8(uint8 n); static uint32 ReverseBits32(uint32 n); @@ -177,14 +200,6 @@ class Bits { static int FindMSBSetNonZero(uint32 n) { return Log2FloorNonZero(n); } static int FindMSBSetNonZero64(uint64 n) { return Log2FloorNonZero64(n); } - // Portable implementations - static int Log2Floor_Portable(uint32 n); - static int Log2FloorNonZero_Portable(uint32 n); - static int FindLSBSetNonZero_Portable(uint32 n); - static int Log2Floor64_Portable(uint64 n); - static int Log2FloorNonZero64_Portable(uint64 n); - static int FindLSBSetNonZero64_Portable(uint64 n); - // Viewing bytes as a stream of unsigned bytes, does that stream // contain any byte equal to c? template static bool BytesContainByte(T bytes, uint8 c); @@ -265,8 +280,30 @@ class Bits { static inline int PopcountWithBuiltin(UnsignedT n); #endif + // Portable implementations. + static int Log2Floor_Portable(uint32 n); + static int Log2Floor64_Portable(uint64 n); + static int Log2FloorNonZero_Portable(uint32 n); + static int Log2FloorNonZero64_Portable(uint64 n); + static int CountLeadingZeros32_Portable(uint32 n); + static int CountLeadingZeros64_Portable(uint64 n); + static int FindLSBSetNonZero_Portable(uint32 n); + static int FindLSBSetNonZero64_Portable(uint64 n); + static const char num_bits[]; DISALLOW_COPY_AND_ASSIGN(Bits); + + // Allow tests to call _Portable variants directly. + // Originally, I wanted to depend on //testing/production_stub/public + // so that I would be able to + // #include "testing/production_stub/public/gunit_prod.h", which provides + // the previously mentioned header file says to instead + // #include "testing/base/gunit_prod.h". I cannot find a library that a) + // provides the alternative header file b) is visisble. Thus, I have thrown + // my hands up in frustration, and gone with raw friend instead of using the + // usual FRIEND_TEST macro. Hate the game, not the player. + friend class Bits_Port32_Test; + friend class Bits_Port64_Test; }; // A utility class for some handy bit patterns. The names l and h @@ -492,4 +529,4 @@ int Bits::PopcountWithBuiltin(UnsignedT n) { } #endif // __GNUC__ -#endif // UTIL_BITS_BITS_H_ \ No newline at end of file +#endif // UTIL_BITS_BITS_H_ diff --git a/src/util/coding/coder.cc b/src/util/coding/coder.cc index 2fefccd8..b40054ae 100644 --- a/src/util/coding/coder.cc +++ b/src/util/coding/coder.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // @@ -119,4 +120,4 @@ bool Decoder::get_varint64(uint64* v) { *v = result; return true; } -} \ No newline at end of file +} diff --git a/src/util/coding/coder.h b/src/util/coding/coder.h index f801ae13..a4cc6d63 100644 --- a/src/util/coding/coder.h +++ b/src/util/coding/coder.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // // This holds the encoding/decoding routines that used to live in netutil @@ -184,7 +185,6 @@ class Decoder { const unsigned char* buf_; const unsigned char* limit_; }; -DECLARE_POD(Decoder); // so then we might as well be a POD /***** Implementation details. Clients should ignore them. *****/ @@ -448,4 +448,4 @@ inline double Decoder::getdouble() { return d; } -#endif // UTIL_CODING_CODER_H__ \ No newline at end of file +#endif // UTIL_CODING_CODER_H__ diff --git a/src/util/coding/nth-derivative.h b/src/util/coding/nth-derivative.h index cd7c32f4..99ce4e1f 100644 --- a/src/util/coding/nth-derivative.h +++ b/src/util/coding/nth-derivative.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // far-far-superior implementation courtesy of amc@google.com (Adam Costello) // @@ -88,7 +89,6 @@ class NthDerivativeCoder { int m_; // the derivative order in which to code the next value(ramps to n_) int32 memory_[N_MAX]; // value memory. [0] is oldest }; -DECLARE_POD(NthDerivativeCoder); // Implementation below. Callers Ignore. // @@ -132,4 +132,4 @@ inline void NthDerivativeCoder::Reset() { m_ = 0; } -#endif // UTIL_CODING_NTH_DERIVATIVE_H_ \ No newline at end of file +#endif // UTIL_CODING_NTH_DERIVATIVE_H_ diff --git a/src/util/coding/transforms.h b/src/util/coding/transforms.h index 0f4131b3..0df40a7d 100644 --- a/src/util/coding/transforms.h +++ b/src/util/coding/transforms.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // // Data transforms that can help code more efficiently. @@ -38,37 +39,24 @@ // >> encode >> // << decode << -#if defined(_MSC_VER) -// These functions cause MSVC++ (versions 7 through 12, at least) to warn about -// applying unary minus to an unsigned value. In these functions, this is not a -// problem, but the warning is generally useful, so we're disabling it locally -// rather than globally. -#pragma warning(push) -#pragma warning(disable: 4146) // unary minus applied to unsigned type -#endif - static inline uint32 ZigZagEncode(int32 n) { // We need the cast to avoid an arithmetic shift. uint32 sign = (static_cast(n)) >> 31; - return (n << 1) ^ -sign; + return (static_cast(n) << 1) ^ (0u - sign); } static inline int32 ZigZagDecode(uint32 n) { - return (n >> 1) ^ -(n & 1); + return (n >> 1) ^ (0u - (n & 1)); } static inline uint64 ZigZagEncode64(int64 n) { // We need the cast to avoid an arithmetic shift. uint64 sign = (static_cast(n)) >> 63; - return (n << 1) ^ -sign; + return (static_cast(n) << 1) ^ (0u - sign); } static inline int64 ZigZagDecode64(uint64 n) { - return (n >> 1) ^ -(n & 1); + return (n >> 1) ^ (0u - (n & 1)); } -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -#endif // UTIL_CODING_TRANSFORMS_H__ \ No newline at end of file +#endif // UTIL_CODING_TRANSFORMS_H__ diff --git a/src/util/coding/varint.cc b/src/util/coding/varint.cc index 636bcaa4..d96f063f 100644 --- a/src/util/coding/varint.cc +++ b/src/util/coding/varint.cc @@ -13,6 +13,7 @@ // limitations under the License. // + #include "util/coding/varint.h" #include @@ -269,4 +270,4 @@ const char Varint::kLengthBytesRequired[65] = int Varint::Length32NonInline(uint32 v) { return FastLength32(v); -} \ No newline at end of file +} diff --git a/src/util/coding/varint.h b/src/util/coding/varint.h index 6b89ed97..b5b3482b 100644 --- a/src/util/coding/varint.h +++ b/src/util/coding/varint.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // Raw support for varint encoding. Higher level interfaces are // provided by Encoder/Decoder/IOBuffer. Clients should typically use @@ -485,4 +486,4 @@ inline const char* Varint::FastDecodeDeltas(const char* ptr, return ptr; } -#endif // UTIL_CODING_VARINT_H_ \ No newline at end of file +#endif // UTIL_CODING_VARINT_H_ diff --git a/src/util/endian/endian.h b/src/util/endian/endian.h index ddea0261..dfc04c09 100644 --- a/src/util/endian/endian.h +++ b/src/util/endian/endian.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // Utility functions that depend on bytesex. We define htonll and ntohll, // as well as "Google" versions of all the standards: ghtonl, ghtons, and @@ -563,7 +564,7 @@ namespace endian_internal { // apparent size of this function, it compiles into efficient code. template inline T LoadInteger(const char* p) { - static_assert(sizeof(T) <= 8 && base::is_integral::value, + static_assert(sizeof(T) <= 8 && std::is_integral::value, "T needs to be an integral type with size <= 8."); switch (sizeof(T)) { case 1: return *reinterpret_cast(p); @@ -581,7 +582,7 @@ inline T LoadInteger(const char* p) { // apparent size of this function, it compiles into efficient code. template inline void StoreInteger(T value, char* p) { - static_assert(sizeof(T) <= 8 && base::is_integral::value, + static_assert(sizeof(T) <= 8 && std::is_integral::value, "T needs to be an integral type with size <= 8."); switch (sizeof(T)) { case 1: *reinterpret_cast(p) = value; break; @@ -710,4 +711,4 @@ inline void BigEndian::Store(double value, char* p) { endian_internal::StoreDouble(value, p); } -#endif // UTIL_ENDIAN_ENDIAN_H_ \ No newline at end of file +#endif // UTIL_ENDIAN_ENDIAN_H_ diff --git a/src/util/gtl/algorithm.h b/src/util/gtl/algorithm.h index 815c5ee6..7dd91739 100644 --- a/src/util/gtl/algorithm.h +++ b/src/util/gtl/algorithm.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // This file contains some Google extensions to the standard // C++ header. Many of these algorithms were in the @@ -469,4 +470,4 @@ using __gnu_cxx::is_heap; } // namespace gtl } // namespace util -#endif // UTIL_GTL_ALGORITHM_H_ \ No newline at end of file +#endif // UTIL_GTL_ALGORITHM_H_ diff --git a/src/util/gtl/charmap.h b/src/util/gtl/charmap.h index 629e6ad8..0dd3bcf4 100644 --- a/src/util/gtl/charmap.h +++ b/src/util/gtl/charmap.h @@ -1,4 +1,4 @@ -// Copyright 2001 Google Inc. All Rights Reserved. +// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,18 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Character Map Class // -// Originally written by Daniel Dulitz -// Yanked out from url.cc on February 2003 by Wei-Hwa Huang -// -// // A fast, bit-vector map for 8-bit unsigned characters. -// -// Internally stores 256 bits in an array of 8 uint32s. -// See changelist history for micro-optimization attempts. -// Does quick bit-flicking to lookup needed characters. -// // This class is useful for non-character purposes as well. // @@ -33,43 +25,39 @@ #include #include "base/integral_types.h" -#include "base/type_traits.h" +#include "base/macros.h" +#include "base/port.h" + +#ifdef LANG_CXX11 +#define UTIL_GTL_CHARMAP_CONSTEXPR_ constexpr +#else +#define UTIL_GTL_CHARMAP_CONSTEXPR_ +#endif // !LANG_CXX11 class Charmap { public: - // Initializes with given uint32 values. For instance, the first - // variable contains bits for values 0x1F (US) down to 0x00 (NUL). - Charmap(uint32 b0, uint32 b1, uint32 b2, uint32 b3, - uint32 b4, uint32 b5, uint32 b6, uint32 b7) { - m_[0] = b0; - m_[1] = b1; - m_[2] = b2; - m_[3] = b3; - m_[4] = b4; - m_[5] = b5; - m_[6] = b6; - m_[7] = b7; - } + UTIL_GTL_CHARMAP_CONSTEXPR_ Charmap() : m_() {} // Initializes with a given char*. Note that NUL is not treated as // a terminator, but rather a char to be flicked. - Charmap(const char* str, int len) { - Init(str, len); + Charmap(const char* str, int len) : m_() { + while (len--) SetChar(*str++); } // Initializes with a given char*. NUL is treated as a terminator // and will not be in the charmap. - explicit Charmap(const char* str) { - Init(str, strlen(str)); + explicit Charmap(const char* str) : m_() { + while (*str) SetChar(*str++); } + UTIL_GTL_CHARMAP_CONSTEXPR_ bool contains(unsigned char c) const { - return (m_[c >> 5] >> (c & 0x1f)) & 0x1; + return (m_[c / 64] >> (c % 64)) & 0x1; } // Returns true if and only if a character exists in both maps. - bool IntersectsWith(const Charmap & c) const { - for (int i = 0; i < 8; ++i) { + bool IntersectsWith(const Charmap& c) const { + for (int i = 0; i < arraysize(m_); ++i) { if ((m_[i] & c.m_[i]) != 0) return true; } @@ -77,24 +65,134 @@ class Charmap { } bool IsZero() const { - for (int i = 0; i < 8; ++i) { + for (int i = 0; i < arraysize(m_); ++i) { if (m_[i] != 0) return false; } return true; } - protected: - uint32 m_[8]; + // Containing only a single specified char. + static UTIL_GTL_CHARMAP_CONSTEXPR_ Charmap + Char(char x) { + return Charmap(CharMaskForWord(x, 0), CharMaskForWord(x, 1), + CharMaskForWord(x, 2), CharMaskForWord(x, 3)); + } - void Init(const char* str, int len) { - memset(&m_, 0, sizeof m_); - for (int i = 0; i < len; ++i) { - unsigned char value = static_cast(str[i]); - m_[value >> 5] |= 1UL << (value & 0x1f); - } + // Containing all the chars in the C-string 's'. + // CAUTION: deeply recursive. Use only in constexpr initializers. + static UTIL_GTL_CHARMAP_CONSTEXPR_ Charmap + FromString(const char* s) { + return *s == 0 ? Charmap() : (Char(*s) | FromString(s + 1)); + } + + // Containing all the chars in the closed interval [lo,hi]. + static UTIL_GTL_CHARMAP_CONSTEXPR_ Charmap + Range(char lo, char hi) { + return Charmap(RangeForWord(lo, hi, 0), RangeForWord(lo, hi, 1), + RangeForWord(lo, hi, 2), RangeForWord(lo, hi, 3)); + } + + friend UTIL_GTL_CHARMAP_CONSTEXPR_ Charmap + operator&(const Charmap& a, const Charmap& b) { + return Charmap(a.m_[0] & b.m_[0], a.m_[1] & b.m_[1], + a.m_[2] & b.m_[2], a.m_[3] & b.m_[3]); + } + + friend UTIL_GTL_CHARMAP_CONSTEXPR_ Charmap + operator|(const Charmap& a, const Charmap& b) { + return Charmap(a.m_[0] | b.m_[0], a.m_[1] | b.m_[1], + a.m_[2] | b.m_[2], a.m_[3] | b.m_[3]); + } + + friend UTIL_GTL_CHARMAP_CONSTEXPR_ Charmap + operator~(const Charmap& a) { + return Charmap(~a.m_[0], ~a.m_[1], ~a.m_[2], ~a.m_[3]); + } + + private: + UTIL_GTL_CHARMAP_CONSTEXPR_ Charmap( + uint64 b0, uint64 b1, uint64 b2, uint64 b3) +#ifdef LANG_CXX11 + : m_{b0, b1, b2, b3} {} +#else // !LANG_CXX11 (C++98 version) + { + m_[0] = b0; + m_[1] = b1; + m_[2] = b2; + m_[3] = b3; } +#endif // !LANG_CXX11 + + static UTIL_GTL_CHARMAP_CONSTEXPR_ uint64 + RangeForWord(unsigned char lo, unsigned char hi, uint64 word) { + return OpenRangeFromZeroForWord(hi + 1, word) + & ~OpenRangeFromZeroForWord(lo, word); + } + + // All the chars in the specified word of the range [0, upper). + static UTIL_GTL_CHARMAP_CONSTEXPR_ uint64 + OpenRangeFromZeroForWord(uint64 upper, uint64 word) { + return (upper <= 64 * word) ? 0 : + (upper >= 64 * (word + 1)) ? ~static_cast(0) : + (~static_cast(0) >> (64 - upper % 64)); + } + + static UTIL_GTL_CHARMAP_CONSTEXPR_ uint64 + CharMaskForWord(unsigned char x, uint64 word) { + return (x / 64 == word) ? (static_cast(1) << (x % 64)) : 0; + } + + private: + void SetChar(unsigned char c) { + m_[c / 64] |= static_cast(1) << (c % 64); + } + + uint64 m_[4]; }; -DECLARE_POD(Charmap); -#endif // UTIL_GTL_CHARMAP_H_ \ No newline at end of file +namespace util { +namespace gtl { +namespace charmaps { +// Mirror the char-classifying predicates in +inline UTIL_GTL_CHARMAP_CONSTEXPR_ Charmap Upper() { + return Charmap::Range('A', 'Z'); +} +inline UTIL_GTL_CHARMAP_CONSTEXPR_ Charmap Lower() { + return Charmap::Range('a', 'z'); +} +inline UTIL_GTL_CHARMAP_CONSTEXPR_ Charmap Digit() { + return Charmap::Range('0', '9'); +} +inline UTIL_GTL_CHARMAP_CONSTEXPR_ Charmap Alpha() { + return Lower() | Upper(); +} +inline UTIL_GTL_CHARMAP_CONSTEXPR_ Charmap Alnum() { + return Digit() | Alpha(); +} +inline UTIL_GTL_CHARMAP_CONSTEXPR_ Charmap XDigit() { + return Digit() | Charmap::Range('A', 'F') | Charmap::Range('a', 'f'); +} +inline UTIL_GTL_CHARMAP_CONSTEXPR_ Charmap Print() { + return Charmap::Range(0x20, 0x7e); +} +inline UTIL_GTL_CHARMAP_CONSTEXPR_ Charmap Space() { + return Charmap::FromString("\t\n\v\f\r "); +} +inline UTIL_GTL_CHARMAP_CONSTEXPR_ Charmap Cntrl() { + return Charmap::Range(0, 0x7f) & ~Print(); +} +inline UTIL_GTL_CHARMAP_CONSTEXPR_ Charmap Blank() { + return Charmap::FromString("\t "); +} +inline UTIL_GTL_CHARMAP_CONSTEXPR_ Charmap Graph() { + return Print() & ~Space(); +} +inline UTIL_GTL_CHARMAP_CONSTEXPR_ Charmap Punct() { + return Graph() & ~Alnum(); +} +} // namespace charmaps +} // namespace gtl +} // namespace util +#undef UTIL_GTL_CHARMAP_CONSTEXPR_ +#endif // UTIL_GTL_CHARMAP_H_ diff --git a/src/util/gtl/container_logging.h b/src/util/gtl/container_logging.h index 86e53a05..e3c10892 100644 --- a/src/util/gtl/container_logging.h +++ b/src/util/gtl/container_logging.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // All Rights Reserved. // // Utilities for container logging. @@ -94,10 +95,21 @@ struct LogShort : public internal::LogShortBase { int64 MaxElements() const { return kint64max; } }; +// LogShortUpToN(max_elements) formats the same as LogShort but prints no more +// than the max_elements elements. +class LogShortUpToN : public internal::LogShortBase { + public: + explicit LogShortUpToN(int64 max_elements) : max_elements_(max_elements) {} + int64 MaxElements() const { return max_elements_; } + + private: + int64 max_elements_; +}; + // LogShortUpTo100 formats the same as LogShort but prints no more // than 100 elements. -struct LogShortUpTo100 : public internal::LogShortBase { - int64 MaxElements() const { return 100; } +struct LogShortUpTo100 : public LogShortUpToN { + LogShortUpTo100() : LogShortUpToN(100) {} }; // LogMultiline uses [] braces and separates items with @@ -110,10 +122,22 @@ struct LogMultiline : public internal::LogMultilineBase { int64 MaxElements() const { return kint64max; } }; +// LogMultilineUpToN(max_elements) formats the same as LogMultiline but +// prints no more than max_elements elements. +class LogMultilineUpToN : public internal::LogMultilineBase { + public: + explicit LogMultilineUpToN(int64 max_elements) + : max_elements_(max_elements) {} + int64 MaxElements() const { return max_elements_; } + + private: + int64 max_elements_; +}; + // LogMultilineUpTo100 formats the same as LogMultiline but // prints no more than 100 elements. -struct LogMultilineUpTo100 : public internal::LogMultilineBase { - int64 MaxElements() const { return 100; } +struct LogMultilineUpTo100 : public LogMultilineUpToN { + LogMultilineUpTo100() : LogMultilineUpToN(100) {} }; // The legacy behavior of LogSequence() does not use braces and @@ -257,4 +281,4 @@ detail::EnumLogger LogEnum(E e) { } // namespace gtl } // namespace util -#endif // UTIL_GTL_CONTAINER_LOGGING_H_ \ No newline at end of file +#endif // UTIL_GTL_CONTAINER_LOGGING_H_ diff --git a/src/util/gtl/fixedarray.h b/src/util/gtl/fixedarray.h index 5e58655a..53b7a381 100644 --- a/src/util/gtl/fixedarray.h +++ b/src/util/gtl/fixedarray.h @@ -13,6 +13,7 @@ // limitations under the License. // + #ifndef UTIL_GTL_FIXEDARRAY_H_ #define UTIL_GTL_FIXEDARRAY_H_ @@ -23,7 +24,7 @@ #include #include -#include "dynamic_annotations/dynamic_annotations.h" +#include "third_party/dynamic_annotations/dynamic_annotations.h" #include #include "base/macros.h" #include "base/port.h" @@ -172,7 +173,7 @@ class FixedArray { static pointer AsValue(type *p) { return Impl::AsValue(p); } // TODO(user): fix the type aliasing violation - // this assertion hints at (b/9317756). + // this assertion hints at. static_assert(sizeof(type) == sizeof(value_type), "Holder must be same size as value_type"); }; @@ -192,7 +193,7 @@ class FixedArray { // b. Never use 0 length arrays (not ISO C++) // class InlineSpace { - typedef GOOGLE_NAMESPACE::ManualConstructor Buffer; + typedef base::ManualConstructor Buffer; static const size_type kDefaultBytes = 256; template @@ -332,4 +333,4 @@ class FixedArray { DISALLOW_COPY_AND_ASSIGN(FixedArray); }; -#endif // UTIL_GTL_FIXEDARRAY_H_ \ No newline at end of file +#endif // UTIL_GTL_FIXEDARRAY_H_ diff --git a/src/util/gtl/inlined_vector.h b/src/util/gtl/inlined_vector.h index d4b5fadd..12e65293 100644 --- a/src/util/gtl/inlined_vector.h +++ b/src/util/gtl/inlined_vector.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // An InlinedVector is like a vector, except that storage // for sequences of length <= N are provided inline without requiring @@ -67,6 +68,8 @@ class InlinedVector { typedef typename allocator_type::difference_type difference_type; typedef pointer iterator; typedef const_pointer const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; // Create an empty vector InlinedVector(); @@ -87,8 +90,8 @@ class InlinedVector { template InlinedVector(InputIterator range_start, InputIterator range_end, const allocator_type& alloc = allocator_type(), - typename base::enable_if< - !base::is_integral::value>::type* = NULL) + typename std::enable_if< + !std::is_integral::value>::type* = NULL) : allocator_and_tag_(alloc) { AppendRange(range_start, range_end); } @@ -240,9 +243,23 @@ class InlinedVector { iterator begin() { return mutable_array(); } const_iterator begin() const { return array(); } + const_iterator cbegin() const { return begin(); } iterator end() { return mutable_array() + size(); } const_iterator end() const { return array() + size(); } + const_iterator cend() const { return end(); } + + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + const_reverse_iterator crbegin() const { return rbegin(); } + + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + const_reverse_iterator crend() const { return rend(); } iterator insert(iterator pos, const value_type& v); @@ -509,11 +526,11 @@ class InlinedVector { // Use struct to perform indirection that solves a bizarre compilation // error on Visual Studio (all known versions). struct { - GOOGLE_NAMESPACE::ManualConstructor + base::ManualConstructor inlined[N]; } inlined_storage; struct { - GOOGLE_NAMESPACE::ManualConstructor + base::ManualConstructor allocation; } allocation_storage; } rep_; @@ -909,4 +926,4 @@ inline void InlinedVector::AppendRange(Iter first, Iter last) { } // namespace gtl } // namespace util -#endif // UTIL_GTL_INLINED_VECTOR_H_ \ No newline at end of file +#endif // UTIL_GTL_INLINED_VECTOR_H_ diff --git a/src/util/gtl/manual_constructor.h b/src/util/gtl/manual_constructor.h index 2504aaea..f5914cc3 100644 --- a/src/util/gtl/manual_constructor.h +++ b/src/util/gtl/manual_constructor.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -63,7 +64,7 @@ #include "base/port.h" -_START_GOOGLE_NAMESPACE_ +namespace base { namespace util { namespace gtl { @@ -278,6 +279,6 @@ class ManualConstructor { #undef UTIL_GTL_ALIGNED_CHAR_ARRAY #undef UTIL_GTL_ALIGN_OF -_END_GOOGLE_NAMESPACE_ +} -#endif // UTIL_GTL_MANUAL_CONSTRUCTOR_H_ \ No newline at end of file +#endif // UTIL_GTL_MANUAL_CONSTRUCTOR_H_ diff --git a/src/util/gtl/stl_util.h b/src/util/gtl/stl_util.h index 1f306e04..9d380acc 100644 --- a/src/util/gtl/stl_util.h +++ b/src/util/gtl/stl_util.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // #status: RECOMMENDED // #category: Utility functions. @@ -83,6 +84,26 @@ inline void STLSortAndRemoveDuplicates(T* v) { v->erase(std::unique(v->begin(), v->end()), v->end()); } +// Stable sorts and removes duplicates from a sequence container, retaining +// the first equivalent element for each equivalence set. +// The 'less_func' is used to compose an equivalence comparator for the sorting +// and uniqueness tests. +template +inline void STLStableSortAndRemoveDuplicates(T* v, const LessFunc& less_func) { + std::stable_sort(v->begin(), v->end(), less_func); + v->erase(std::unique(v->begin(), v->end(), + util::gtl::internal::Equiv(less_func)), + v->end()); +} +// Stable sorts and removes duplicates from a sequence container, retaining +// the first equivalent element for each equivalence set, using < comparison and +// == equivalence testing. +template +inline void STLStableSortAndRemoveDuplicates(T* v) { + std::stable_sort(v->begin(), v->end()); + v->erase(std::unique(v->begin(), v->end()), v->end()); +} + // Remove every occurrence of element e in v. See // http://en.wikipedia.org/wiki/Erase-remove_idiom. template @@ -455,7 +476,7 @@ class TemplatedElementDeleter : public BaseDeleter { }; // ElementDeleter is an RAII (go/raii) object that deletes the elements in the -// given container when it goes out of scope. This is similar to scoped_ptr<> +// given container when it goes out of scope. This is similar to std::unique_ptr<> // except that a container's elements will be deleted rather than the container // itself. // @@ -584,17 +605,17 @@ namespace stl_util_internal { // Poor-man's std::is_function. // Doesn't handle default parameters or variadics. -template struct IsFunc : base::false_type {}; +template struct IsFunc : std::false_type {}; template -struct IsFunc : base::true_type {}; +struct IsFunc : std::true_type {}; template -struct IsFunc : base::true_type {}; +struct IsFunc : std::true_type {}; template -struct IsFunc : base::true_type {}; +struct IsFunc : std::true_type {}; template -struct IsFunc : base::true_type {}; +struct IsFunc : std::true_type {}; template -struct IsFunc : base::true_type {}; +struct IsFunc : std::true_type {}; // Like std::less, but allows heterogeneous arguments. struct TransparentLess { @@ -650,7 +671,7 @@ void STLSetDifference(const In1& a, const In2& b, Out* out, Compare compare) { // overload resolution if 'out' is a function pointer, gracefully forcing // the 3-argument overload that treats the third argument as a comparator. template -typename base::enable_if::value, +typename std::enable_if::value, void>::type STLSetDifference(const In1& a, const In2& b, Out* out) { STLSetDifference(a, b, out, util::gtl::stl_util_internal::TransparentLess()); @@ -712,7 +733,7 @@ void STLSetUnion(const In1& a, const In2& b, Out* out, Compare compare) { // overload resolution if 'out' is a function pointer, gracefully forcing // the 3-argument overload that treats the third argument as a comparator. template -typename base::enable_if::value, +typename std::enable_if::value, void>::type STLSetUnion(const In1& a, const In2& b, Out *out) { return STLSetUnion(a, b, out, @@ -771,7 +792,7 @@ void STLSetSymmetricDifference(const In1& a, const In2& b, Out* out, // overload resolution if 'out' is a function pointer, gracefully forcing // the 3-argument overload that treats the third argument as a comparator. template -typename base::enable_if::value, +typename std::enable_if::value, void>::type STLSetSymmetricDifference(const In1& a, const In2& b, Out* out) { return STLSetSymmetricDifference( @@ -830,7 +851,7 @@ void STLSetIntersection(const In1& a, const In2& b, Out* out, Compare compare) { // overload resolution if 'out' is a function pointer, gracefully forcing // the 3-argument overload that treats the third argument as a comparator. template -typename base::enable_if::value, +typename std::enable_if::value, void>::type STLSetIntersection(const In1& a, const In2& b, Out* out) { return STLSetIntersection( @@ -1022,4 +1043,4 @@ bool operator!=(const STLCountingAllocator& a, return !(a == b); } -#endif // UTIL_GTL_STL_UTIL_H_ \ No newline at end of file +#endif // UTIL_GTL_STL_UTIL_H_ diff --git a/src/util/hash/builtin_type_hash.h b/src/util/hash/builtin_type_hash.h index cc6d2e38..aa2ccd93 100644 --- a/src/util/hash/builtin_type_hash.h +++ b/src/util/hash/builtin_type_hash.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // Hash functions for C++ builtin types. These are all of the fundamental // integral and floating point types in the language as well as pointers. This @@ -116,4 +117,4 @@ inline uint64 Hash64DoubleWithSeed(double num, uint64 seed) { return a; } -#endif // UTIL_HASH_BUILTIN_TYPE_HASH_H_ \ No newline at end of file +#endif // UTIL_HASH_BUILTIN_TYPE_HASH_H_ diff --git a/src/util/hash/city.cc b/src/util/hash/city.cc index 1a0ffb3c..4c8ed4af 100644 --- a/src/util/hash/city.cc +++ b/src/util/hash/city.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // This file provides CityHash64() and related functions. // @@ -30,7 +31,7 @@ #include "util/hash/farmhash.h" -#include "util/hash/hash.h" // for HashSeed() +#include "util/hash/builtin_type_hash.h" // for HashSeed() namespace util_hash { @@ -48,19 +49,24 @@ uint64 CityHash64WithSeeds(const char *s, size_t len, } uint128 CityHash128(const char *s, size_t len) { - return farmhashcc::CityHash128WithSeed(s, len, uint128(9, 999)); + // This function will never change, so HashSeed() is not used. + return CityHash128WithSeed(s, len, uint128(6, 555)); } uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) { - return farmhashcc::CityHash128WithSeed(s, len, seed); + // This function will never change, so HashSeed() is not used. + return ToGoogleU128( + farmhashcc::CityHash128WithSeed(s, len, ToFarmHashU128(seed))); } uint32 CityHash32(const char *s, size_t len) { - return farmhash::Hash32(s, len) ^ HashSeed(); + return static_cast(farmhash::Hash32(s, len) ^ HashSeed()); } uint32 CityHash32WithSeed(const char *s, size_t len, uint32 seed) { - return farmhash::Hash32WithSeed(s, len, seed - HashSeed()); + return static_cast(farmhash::Hash32WithSeed( + s, len, static_cast(seed - HashSeed()))); } } // namespace util_hash + diff --git a/src/util/hash/city.h b/src/util/hash/city.h index eb520d0a..0531904c 100644 --- a/src/util/hash/city.h +++ b/src/util/hash/city.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // This file provides a few functions for hashing strings. On x86-64 // hardware as of early 2010, CityHash64() is much faster than @@ -76,4 +77,4 @@ uint32 CityHash32WithSeed(const char *s, size_t len, uint32 seed); } // namespace util_hash -#endif // UTIL_HASH_CITY_H_ \ No newline at end of file +#endif // UTIL_HASH_CITY_H_ diff --git a/src/util/hash/farmhash.h b/src/util/hash/farmhash.h index 00bee862..e4f7494f 100644 --- a/src/util/hash/farmhash.h +++ b/src/util/hash/farmhash.h @@ -12,19 +12,28 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // What follows is the concatenation of farmhash.h and farmhash.cc from // FarmHash 1.1; all modifications are listed: // . NAMESPACE_FOR_HASH_FUNCTIONS defaults to farmhash (instead of util) -// . uint128 from //base is used (instead of uint128_t) -// . Removed #include "farmhash.h"; added #include "base/int128.h". +// . Moved farmhash::Fingerprint* from here to farmhash_fingerprint.{h,cc} +// . Removed #include "farmhash.h". // . Added #include "base/port.h"; #define FARMHASH_LITTLE_ENDIAN or // FARMHASH_BIG_ENDIAN. // . Removed "using namespace std" -// . Added #include "util/hash128to64.h"; removed Hash128to64(). +// . Removed Hash128to64(); made its two uses explicitly use the +// same constants as before so that farmhash::Fingerprint() is unchanging. // . Modified Check macros to use std::hex instead of just hex, and // reformatted them. // . Replaced pair with std::pair and make_pair with std::make_pair // (because using namespace std was removed). +// . Marked functions defined here "inline" as is normal for functions +// defined in header files. This prevents ODR violations. +// (Functions to mark were found by +// egrep -nH -e '^uint.*[y ]Hash|^size_t Hash|^uint.* Fing' farmhash.h.) +// . Do not warn about possible data loss on conversion from 'size_t' to +// 'uint32_t' when building with MSVC +// . Do not define LIKELY with __builtin_expect with MSVC. // // This is used by other files in //util/hash, but please do not use it // for anything else. Please ask hashing@ if you want to break this rule. @@ -32,9 +41,7 @@ #ifndef UTIL_HASH_FARMHASH_H_ #define UTIL_HASH_FARMHASH_H_ -#include "base/int128.h" #include "base/port.h" -#include "util/hash/hash128to64.h" #ifdef IS_LITTLE_ENDIAN #define FARMHASH_LITTLE_ENDIAN @@ -96,93 +103,75 @@ namespace NAMESPACE_FOR_HASH_FUNCTIONS { +#if defined(FARMHASH_UINT128_T_DEFINED) +inline uint64_t Uint128Low64(const uint128_t x) { + return static_cast(x); +} +inline uint64_t Uint128High64(const uint128_t x) { + return static_cast(x >> 64); +} +inline uint128_t Uint128(uint64_t lo, uint64_t hi) { + return lo + (((uint128_t)hi) << 64); +} +#else +typedef std::pair uint128_t; +inline uint64_t Uint128Low64(const uint128_t x) { return x.first; } +inline uint64_t Uint128High64(const uint128_t x) { return x.second; } +inline uint128_t Uint128(uint64_t lo, uint64_t hi) { return uint128_t(lo, hi); } +inline uint128 ToGoogleU128(uint128_t x) { return uint128(x.second, x.first); } +inline uint128_t ToFarmHashU128(uint128 x) { + return uint128_t(::Uint128Low64(x), ::Uint128High64(x)); +} +#endif + + // BASIC STRING HASHING // Hash function for a byte array. // May change from time to time, may differ on different platforms, may differ // depending on NDEBUG. -size_t Hash(const char* s, size_t len); +inline size_t Hash(const char* s, size_t len); // Hash function for a byte array. Most useful in 32-bit binaries. // May change from time to time, may differ on different platforms, may differ // depending on NDEBUG. -uint32_t Hash32(const char* s, size_t len); +inline uint32_t Hash32(const char* s, size_t len); // Hash function for a byte array. For convenience, a 32-bit seed is also // hashed into the result. // May change from time to time, may differ on different platforms, may differ // depending on NDEBUG. -uint32_t Hash32WithSeed(const char* s, size_t len, uint32_t seed); +inline uint32_t Hash32WithSeed(const char* s, size_t len, uint32_t seed); // Hash 128 input bits down to 64 bits of output. // Hash function for a byte array. // May change from time to time, may differ on different platforms, may differ // depending on NDEBUG. -uint64_t Hash64(const char* s, size_t len); +inline uint64_t Hash64(const char* s, size_t len); // Hash function for a byte array. For convenience, a 64-bit seed is also // hashed into the result. // May change from time to time, may differ on different platforms, may differ // depending on NDEBUG. -uint64_t Hash64WithSeed(const char* s, size_t len, uint64_t seed); +inline uint64_t Hash64WithSeed(const char* s, size_t len, uint64_t seed); // Hash function for a byte array. For convenience, two seeds are also // hashed into the result. // May change from time to time, may differ on different platforms, may differ // depending on NDEBUG. -uint64_t Hash64WithSeeds(const char* s, size_t len, +inline uint64_t Hash64WithSeeds(const char* s, size_t len, uint64_t seed0, uint64_t seed1); // Hash function for a byte array. // May change from time to time, may differ on different platforms, may differ // depending on NDEBUG. -uint128 Hash128(const char* s, size_t len); +inline uint128_t Hash128(const char* s, size_t len); // Hash function for a byte array. For convenience, a 128-bit seed is also // hashed into the result. // May change from time to time, may differ on different platforms, may differ // depending on NDEBUG. -uint128 Hash128WithSeed(const char* s, size_t len, uint128 seed); - -// BASIC NON-STRING HASHING - -// FINGERPRINTING (i.e., good, portable, forever-fixed hash functions) - -// Fingerprint function for a byte array. Most useful in 32-bit binaries. -uint32_t Fingerprint32(const char* s, size_t len); - -// Fingerprint function for a byte array. -uint64_t Fingerprint64(const char* s, size_t len); - -// Fingerprint function for a byte array. -uint128 Fingerprint128(const char* s, size_t len); - -// This is intended to be a good fingerprinting primitive. -// See below for more overloads. -inline uint64_t Fingerprint(uint128 x) { - // Murmur-inspired hashing. - const uint64_t kMul = 0x9ddfea08eb382d69ULL; - uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul; - a ^= (a >> 47); - uint64_t b = (Uint128High64(x) ^ a) * kMul; - b ^= (b >> 44); - b *= kMul; - b ^= (b >> 41); - b *= kMul; - return b; -} - -// This is intended to be a good fingerprinting primitive. -inline uint64_t Fingerprint(uint64_t x) { - // Murmur-inspired hashing. - const uint64_t kMul = 0x9ddfea08eb382d69ULL; - uint64_t b = x * kMul; - b ^= (b >> 44); - b *= kMul; - b ^= (b >> 41); - b *= kMul; - return b; -} +inline uint128_t Hash128WithSeed(const char* s, size_t len, uint128_t seed); #ifndef FARMHASH_NO_CXX_STRING @@ -253,7 +242,7 @@ inline uint64_t Hash64WithSeeds(const Str& s, uint64_t seed0, uint64_t seed1) { // May change from time to time, may differ on different platforms, may differ // depending on NDEBUG. template -inline uint128 Hash128(const Str& s) { +inline uint128_t Hash128(const Str& s) { assert(sizeof(s[0]) == 1); return Hash128(s.data(), s.length()); } @@ -263,35 +252,11 @@ inline uint128 Hash128(const Str& s) { // May change from time to time, may differ on different platforms, may differ // depending on NDEBUG. template -inline uint128 Hash128WithSeed(const Str& s, uint128 seed) { +inline uint128_t Hash128WithSeed(const Str& s, uint128_t seed) { assert(sizeof(s[0]) == 1); return Hash128(s.data(), s.length(), seed); } -// FINGERPRINTING (i.e., good, portable, forever-fixed hash functions) - -// Fingerprint function for a byte array. Most useful in 32-bit binaries. -template -inline uint32_t Fingerprint32(const Str& s) { - assert(sizeof(s[0]) == 1); - return Fingerprint32(s.data(), s.length()); -} - -// Fingerprint 128 input bits down to 64 bits of output. -// Fingerprint function for a byte array. -template -inline uint64_t Fingerprint64(const Str& s) { - assert(sizeof(s[0]) == 1); - return Fingerprint64(s.data(), s.length()); -} - -// Fingerprint function for a byte array. -template -inline uint128 Fingerprint128(const Str& s) { - assert(sizeof(s[0]) == 1); - return Fingerprint128(s.data(), s.length()); -} - #endif } // namespace NAMESPACE_FOR_HASH_FUNCTIONS @@ -370,7 +335,7 @@ inline uint128 Fingerprint128(const Str& s) { // FARMHASH PORTABILITY LAYER: LIKELY and UNLIKELY #if !defined(LIKELY) -#if defined(FARMHASH_NO_BUILTIN_EXPECT) || (defined(FARMHASH_OPTIONAL_BUILTIN_EXPECT) && !defined(HAVE_BUILTIN_EXPECT)) +#if defined(FARMHASH_NO_BUILTIN_EXPECT) || (defined(FARMHASH_OPTIONAL_BUILTIN_EXPECT) && !defined(HAVE_BUILTIN_EXPECT)) || defined(_MSC_VER) #define LIKELY(x) (x) #else #define LIKELY(x) (__builtin_expect(!!(x), 1)) @@ -643,6 +608,11 @@ STATIC_INLINE __m128i Fetch128(const char* s) { #undef PERMUTE3 #define PERMUTE3(a, b, c) do { std::swap(a, b); std::swap(a, c); } while (0) +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4267) +#endif // defined(_MSC_VER) + namespace NAMESPACE_FOR_HASH_FUNCTIONS { // Some primes between 2^63 and 2^64 for various uses. @@ -686,13 +656,13 @@ template STATIC_INLINE T DebugTweak(T x) { return x; } -template <> uint128 DebugTweak(uint128 x) { +template <> uint128_t DebugTweak(uint128_t x) { if (debug_mode) { uint64_t y = DebugTweak(Uint128Low64(x)); uint64_t z = DebugTweak(Uint128High64(x)); y += z; z += y; - x = uint128(y, z * k1); + x = uint128_t(y, z * k1); } return x; } @@ -714,11 +684,8 @@ STATIC_INLINE uint64_t ShiftMix(uint64_t val) { return val ^ (val >> 47); } -STATIC_INLINE uint64_t HashLen16(uint64_t u, uint64_t v) { - return Hash128to64(uint128(u, v)); -} - -STATIC_INLINE uint64_t HashLen16(uint64_t u, uint64_t v, uint64_t mul) { +STATIC_INLINE uint64_t +HashLen16(uint64_t u, uint64_t v, uint64_t mul = 0x9ddfea08eb382d69ULL) { // Murmur-inspired hashing. uint64_t a = (u ^ v) * mul; a ^= (a >> 47); @@ -806,7 +773,7 @@ STATIC_INLINE uint64_t HashLen33to64(const char *s, size_t len) { e + Rotate(f + a, 18) + g, mul); } -uint64_t Hash64(const char *s, size_t len) { +inline uint64_t Hash64(const char *s, size_t len) { const uint64_t seed = 81; if (len <= 32) { if (len <= 16) { @@ -861,13 +828,13 @@ uint64_t Hash64(const char *s, size_t len) { mul); } -uint64_t Hash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t seed1); +inline uint64_t Hash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t seed1); -uint64_t Hash64WithSeed(const char *s, size_t len, uint64_t seed) { +inline uint64_t Hash64WithSeed(const char *s, size_t len, uint64_t seed) { return Hash64WithSeeds(s, len, k2, seed); } -uint64_t Hash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t seed1) { +inline uint64_t Hash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t seed1) { return HashLen16(Hash64(s, len) - seed0, seed1); } } // namespace farmhashna @@ -885,7 +852,7 @@ STATIC_INLINE uint64_t H(uint64_t x, uint64_t y, uint64_t mul, int r) { return Rotate(b, r) * mul; } -uint64_t Hash64WithSeeds(const char *s, size_t len, +inline uint64_t Hash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t seed1) { if (len <= 64) { return farmhashna::Hash64WithSeeds(s, len, seed0, seed1); @@ -976,12 +943,12 @@ uint64_t Hash64WithSeeds(const char *s, size_t len, 31); } -uint64_t Hash64WithSeed(const char *s, size_t len, uint64_t seed) { +inline uint64_t Hash64WithSeed(const char *s, size_t len, uint64_t seed) { return len <= 64 ? farmhashna::Hash64WithSeed(s, len, seed) : Hash64WithSeeds(s, len, 0, seed); } -uint64_t Hash64(const char *s, size_t len) { +inline uint64_t Hash64(const char *s, size_t len) { return len <= 64 ? farmhashna::Hash64(s, len) : Hash64WithSeeds(s, len, 81, 0); } @@ -1025,7 +992,7 @@ STATIC_INLINE uint64_t HashLen65to96(const char *s, size_t len) { return (h2 * 9 + (h0 >> 17) + (h1 >> 21)) * mul1; } -uint64_t Hash64(const char *s, size_t len) { +inline uint64_t Hash64(const char *s, size_t len) { if (len <= 32) { if (len <= 16) { return farmhashna::HashLen0to16(s, len); @@ -1043,28 +1010,28 @@ uint64_t Hash64(const char *s, size_t len) { } } -uint64_t Hash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t seed1) { +inline uint64_t Hash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t seed1) { return farmhashuo::Hash64WithSeeds(s, len, seed0, seed1); } -uint64_t Hash64WithSeed(const char *s, size_t len, uint64_t seed) { +inline uint64_t Hash64WithSeed(const char *s, size_t len, uint64_t seed) { return farmhashuo::Hash64WithSeed(s, len, seed); } } // namespace farmhashxo namespace farmhashte { #if !can_use_sse41 || !x86_64 -uint64_t Hash64(const char *s, size_t len) { +inline uint64_t Hash64(const char *s, size_t len) { FARMHASH_DIE_IF_MISCONFIGURED; return s == NULL ? 0 : len; } -uint64_t Hash64WithSeed(const char *s, size_t len, uint64_t seed) { +inline uint64_t Hash64WithSeed(const char *s, size_t len, uint64_t seed) { FARMHASH_DIE_IF_MISCONFIGURED; return seed + Hash64(s, len); } -uint64_t Hash64WithSeeds(const char *s, size_t len, +inline uint64_t Hash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t seed1) { FARMHASH_DIE_IF_MISCONFIGURED; return seed0 + seed1 + Hash64(s, len); @@ -1266,17 +1233,17 @@ STATIC_INLINE uint64_t Hash64Long(const char* s, size_t n, return farmhashxo::Hash64(reinterpret_cast(t), sizeof(t)); } -uint64_t Hash64(const char *s, size_t len) { +inline uint64_t Hash64(const char *s, size_t len) { // Empirically, farmhashxo seems faster until length 512. return len >= 512 ? Hash64Long(s, len, k2, k1) : farmhashxo::Hash64(s, len); } -uint64_t Hash64WithSeed(const char *s, size_t len, uint64_t seed) { +inline uint64_t Hash64WithSeed(const char *s, size_t len, uint64_t seed) { return len >= 512 ? Hash64Long(s, len, k1, seed) : farmhashxo::Hash64WithSeed(s, len, seed); } -uint64_t Hash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t seed1) { +inline uint64_t Hash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t seed1) { return len >= 512 ? Hash64Long(s, len, seed0, seed1) : farmhashxo::Hash64WithSeeds(s, len, seed0, seed1); } @@ -1286,23 +1253,23 @@ uint64_t Hash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t see namespace farmhashnt { #if !can_use_sse41 || !x86_64 -uint32_t Hash32(const char *s, size_t len) { +inline uint32_t Hash32(const char *s, size_t len) { FARMHASH_DIE_IF_MISCONFIGURED; return s == NULL ? 0 : len; } -uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { +inline uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { FARMHASH_DIE_IF_MISCONFIGURED; return seed + Hash32(s, len); } #else -uint32_t Hash32(const char *s, size_t len) { +inline uint32_t Hash32(const char *s, size_t len) { return static_cast(farmhashte::Hash64(s, len)); } -uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { +inline uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { return static_cast(farmhashte::Hash64WithSeed(s, len, seed)); } @@ -1354,7 +1321,7 @@ STATIC_INLINE uint32_t Hash32Len5to12(const char *s, size_t len, uint32_t seed = return fmix(seed ^ Mur(c, Mur(b, Mur(a, d)))); } -uint32_t Hash32(const char *s, size_t len) { +inline uint32_t Hash32(const char *s, size_t len) { if (len <= 24) { return len <= 12 ? (len <= 4 ? Hash32Len0to4(s, len) : Hash32Len5to12(s, len)) : @@ -1412,7 +1379,7 @@ uint32_t Hash32(const char *s, size_t len) { return h; } -uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { +inline uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { if (len <= 24) { if (len >= 13) return Hash32Len13to24(s, len, seed * c1); else if (len >= 5) return Hash32Len5to12(s, len, seed); @@ -1425,12 +1392,12 @@ uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { namespace farmhashsu { #if !can_use_sse42 || !can_use_aesni -uint32_t Hash32(const char *s, size_t len) { +inline uint32_t Hash32(const char *s, size_t len) { FARMHASH_DIE_IF_MISCONFIGURED; return s == NULL ? 0 : len; } -uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { +inline uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { FARMHASH_DIE_IF_MISCONFIGURED; return seed + Hash32(s, len); } @@ -1462,7 +1429,7 @@ STATIC_INLINE __m128i Shuffle0321(__m128i x) { return _mm_shuffle_epi32(x, (0 << 6) + (3 << 4) + (2 << 2) + (1 << 0)); } -uint32_t Hash32(const char *s, size_t len) { +inline uint32_t Hash32(const char *s, size_t len) { const uint32_t seed = 81; if (len <= 24) { return len <= 12 ? @@ -1630,7 +1597,7 @@ uint32_t Hash32(const char *s, size_t len) { #undef Mulc2 #undef Mulc1 -uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { +inline uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { if (len <= 24) { if (len >= 13) return farmhashmk::Hash32Len13to24(s, len, seed * c1); else if (len >= 5) return farmhashmk::Hash32Len5to12(s, len, seed); @@ -1645,12 +1612,12 @@ uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { namespace farmhashsa { #if !can_use_sse42 -uint32_t Hash32(const char *s, size_t len) { +inline uint32_t Hash32(const char *s, size_t len) { FARMHASH_DIE_IF_MISCONFIGURED; return s == NULL ? 0 : len; } -uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { +inline uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { FARMHASH_DIE_IF_MISCONFIGURED; return seed + Hash32(s, len); } @@ -1682,7 +1649,7 @@ STATIC_INLINE __m128i Shuffle0321(__m128i x) { return _mm_shuffle_epi32(x, (0 << 6) + (3 << 4) + (2 << 2) + (1 << 0)); } -uint32_t Hash32(const char *s, size_t len) { +inline uint32_t Hash32(const char *s, size_t len) { const uint32_t seed = 81; if (len <= 24) { return len <= 12 ? @@ -1840,7 +1807,7 @@ uint32_t Hash32(const char *s, size_t len) { #undef Mulc2 #undef Mulc1 -uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { +inline uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { if (len <= 24) { if (len >= 13) return farmhashmk::Hash32Len13to24(s, len, seed * c1); else if (len >= 5) return farmhashmk::Hash32Len5to12(s, len, seed); @@ -1897,7 +1864,7 @@ STATIC_INLINE uint32_t Hash32Len5to12(const char *s, size_t len) { return fmix(Mur(c, Mur(b, Mur(a, d)))); } -uint32_t Hash32(const char *s, size_t len) { +inline uint32_t Hash32(const char *s, size_t len) { if (len <= 24) { return len <= 12 ? (len <= 4 ? Hash32Len0to4(s, len) : Hash32Len5to12(s, len)) : @@ -1966,7 +1933,7 @@ uint32_t Hash32(const char *s, size_t len) { return h; } -uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { +inline uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { if (len <= 24) { if (len >= 13) return farmhashmk::Hash32Len13to24(s, len, seed * c1); else if (len >= 5) return farmhashmk::Hash32Len5to12(s, len, seed); @@ -1989,11 +1956,8 @@ STATIC_INLINE uint64_t ShiftMix(uint64_t val) { return val ^ (val >> 47); } -STATIC_INLINE uint64_t HashLen16(uint64_t u, uint64_t v) { - return Hash128to64(uint128(u, v)); -} - -STATIC_INLINE uint64_t HashLen16(uint64_t u, uint64_t v, uint64_t mul) { +STATIC_INLINE uint64_t +HashLen16(uint64_t u, uint64_t v, uint64_t mul = 0x9ddfea08eb382d69ULL) { // Murmur-inspired hashing. uint64_t a = (u ^ v) * mul; a ^= (a >> 47); @@ -2056,7 +2020,7 @@ STATIC_INLINE std::pair WeakHashLen32WithSeeds( // A subroutine for CityHash128(). Returns a decent 128-bit hash for strings // of any length representable in signed long. Based on City and Murmur. -STATIC_INLINE uint128 CityMurmur(const char *s, size_t len, uint128 seed) { +STATIC_INLINE uint128_t CityMurmur(const char *s, size_t len, uint128_t seed) { uint64_t a = Uint128Low64(seed); uint64_t b = Uint128High64(seed); uint64_t c = 0; @@ -2083,10 +2047,10 @@ STATIC_INLINE uint128 CityMurmur(const char *s, size_t len, uint128 seed) { } a = HashLen16(a, c); b = HashLen16(d, b); - return uint128(a ^ b, HashLen16(b, a)); + return uint128_t(a ^ b, HashLen16(b, a)); } -uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) { +inline uint128_t CityHash128WithSeed(const char *s, size_t len, uint128_t seed) { if (len < 128) { return CityMurmur(s, len, seed); } @@ -2145,18 +2109,18 @@ uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) { // different 56-byte-to-8-byte hashes to get a 16-byte final result. x = HashLen16(x, v.first); y = HashLen16(y + z, w.first); - return uint128(HashLen16(x + v.second, w.second) + y, + return uint128_t(HashLen16(x + v.second, w.second) + y, HashLen16(x + w.second, y + v.second)); } -STATIC_INLINE uint128 CityHash128(const char *s, size_t len) { +STATIC_INLINE uint128_t CityHash128(const char *s, size_t len) { return len >= 16 ? CityHash128WithSeed(s + 16, len - 16, - uint128(Fetch(s), Fetch(s + 8) + k0)) : - CityHash128WithSeed(s, len, uint128(k0, k1)); + uint128_t(Fetch(s), Fetch(s + 8) + k0)) : + CityHash128WithSeed(s, len, uint128_t(k0, k1)); } -uint128 Fingerprint128(const char* s, size_t len) { +inline uint128_t Fingerprint128(const char* s, size_t len) { return CityHash128(s, len); } } // namespace farmhashcc @@ -2167,7 +2131,7 @@ namespace NAMESPACE_FOR_HASH_FUNCTIONS { // Hash function for a byte array. See also Hash(), below. // May change from time to time, may differ on different platforms, may differ // depending on NDEBUG. -uint32_t Hash32(const char* s, size_t len) { +inline uint32_t Hash32(const char* s, size_t len) { return DebugTweak( (can_use_sse41 & x86_64) ? farmhashnt::Hash32(s, len) : (can_use_sse42 & can_use_aesni) ? farmhashsu::Hash32(s, len) : @@ -2179,7 +2143,7 @@ uint32_t Hash32(const char* s, size_t len) { // hashed into the result. // May change from time to time, may differ on different platforms, may differ // depending on NDEBUG. -uint32_t Hash32WithSeed(const char* s, size_t len, uint32_t seed) { +inline uint32_t Hash32WithSeed(const char* s, size_t len, uint32_t seed) { return DebugTweak( (can_use_sse41 & x86_64) ? farmhashnt::Hash32WithSeed(s, len, seed) : (can_use_sse42 & can_use_aesni) ? farmhashsu::Hash32WithSeed(s, len, seed) : @@ -2191,7 +2155,7 @@ uint32_t Hash32WithSeed(const char* s, size_t len, uint32_t seed) { // hashed into the result. See also Hash(), below. // May change from time to time, may differ on different platforms, may differ // depending on NDEBUG. -uint64_t Hash64(const char* s, size_t len) { +inline uint64_t Hash64(const char* s, size_t len) { return DebugTweak( (can_use_sse42 & x86_64) ? farmhashte::Hash64(s, len) : @@ -2201,7 +2165,7 @@ uint64_t Hash64(const char* s, size_t len) { // Hash function for a byte array. // May change from time to time, may differ on different platforms, may differ // depending on NDEBUG. -size_t Hash(const char* s, size_t len) { +inline size_t Hash(const char* s, size_t len) { return sizeof(size_t) == 8 ? Hash64(s, len) : Hash32(s, len); } @@ -2209,7 +2173,7 @@ size_t Hash(const char* s, size_t len) { // hashed into the result. // May change from time to time, may differ on different platforms, may differ // depending on NDEBUG. -uint64_t Hash64WithSeed(const char* s, size_t len, uint64_t seed) { +inline uint64_t Hash64WithSeed(const char* s, size_t len, uint64_t seed) { return DebugTweak(farmhashna::Hash64WithSeed(s, len, seed)); } @@ -2217,14 +2181,14 @@ uint64_t Hash64WithSeed(const char* s, size_t len, uint64_t seed) { // hashed into the result. // May change from time to time, may differ on different platforms, may differ // depending on NDEBUG. -uint64_t Hash64WithSeeds(const char* s, size_t len, uint64_t seed0, uint64_t seed1) { +inline uint64_t Hash64WithSeeds(const char* s, size_t len, uint64_t seed0, uint64_t seed1) { return DebugTweak(farmhashna::Hash64WithSeeds(s, len, seed0, seed1)); } // Hash function for a byte array. // May change from time to time, may differ on different platforms, may differ // depending on NDEBUG. -uint128 Hash128(const char* s, size_t len) { +inline uint128_t Hash128(const char* s, size_t len) { return DebugTweak(farmhashcc::Fingerprint128(s, len)); } @@ -2232,34 +2196,19 @@ uint128 Hash128(const char* s, size_t len) { // hashed into the result. // May change from time to time, may differ on different platforms, may differ // depending on NDEBUG. -uint128 Hash128WithSeed(const char* s, size_t len, uint128 seed) { +inline uint128_t Hash128WithSeed(const char* s, size_t len, uint128_t seed) { return DebugTweak(farmhashcc::CityHash128WithSeed(s, len, seed)); } -// BASIC NON-STRING HASHING - -// FINGERPRINTING (i.e., good, portable, forever-fixed hash functions) - -// Fingerprint function for a byte array. Most useful in 32-bit binaries. -uint32_t Fingerprint32(const char* s, size_t len) { - return farmhashmk::Hash32(s, len); -} - -// Fingerprint function for a byte array. -uint64_t Fingerprint64(const char* s, size_t len) { - return farmhashna::Hash64(s, len); -} - -// Fingerprint function for a byte array. -uint128 Fingerprint128(const char* s, size_t len) { - return farmhashcc::Fingerprint128(s, len); -} - // Older and still available but perhaps not as fast as the above: // farmhashns::Hash32{,WithSeed}() } // namespace NAMESPACE_FOR_HASH_FUNCTIONS +#if defined(_MSC_VER) +#pragma warning( pop ) +#endif // defined(_MSC_VER) + #if FARMHASHSELFTEST #ifndef FARMHASH_SELF_TEST_GUARD @@ -2277,7 +2226,7 @@ static const uint64_t kSeed0 = 1234567; static const uint64_t kSeed1 = k0; static const int kDataSize = 1 << 20; static const int kTestSize = 300; -#define kSeed128 uint128(kSeed0, kSeed1) +#define kSeed128 uint128_t(kSeed0, kSeed1) static char data[kDataSize]; @@ -2311,8 +2260,8 @@ template inline bool IsNonZero(T x) { return x != 0; } -template <> inline bool IsNonZero(uint128 x) { - return x != uint128(0, 0); +template <> inline bool IsNonZero(uint128_t x) { + return x != uint128_t(0, 0); } #endif // FARMHASH_SELF_TEST_GUARD @@ -3818,11 +3767,11 @@ bool Test(int offset, int len = 0) { // After the following line is where the uses of "Check" and such will go. static int index = 0; -if (offset == -1) { int alive = 0; IsAlive(farmhashcc::Hash32WithSeed(data, len++, SEED)); IsAlive(farmhashcc::Hash32(data, len++)); { uint128 u = farmhashcc::Fingerprint128(data, len++); uint64_t h = Uint128Low64(u); IsAlive(h >> 32); IsAlive((h << 32) >> 32); h = Uint128High64(u); IsAlive(h >> 32); IsAlive((h << 32) >> 32); } len -= 3; return alive > 0; } +if (offset == -1) { int alive = 0; IsAlive(farmhashcc::Hash32WithSeed(data, len++, SEED)); IsAlive(farmhashcc::Hash32(data, len++)); { uint128_t u = farmhashcc::Fingerprint128(data, len++); uint64_t h = Uint128Low64(u); IsAlive(h >> 32); IsAlive((h << 32) >> 32); h = Uint128High64(u); IsAlive(h >> 32); IsAlive((h << 32) >> 32); } len -= 3; return alive > 0; } Check(farmhashcc::Hash32WithSeed(data + offset, len, SEED)); Check(farmhashcc::Hash32(data + offset, len)); -{ uint128 u = farmhashcc::Fingerprint128(data + offset, len); uint64_t h = Uint128Low64(u); Check(h >> 32); Check((h << 32) >> 32); h = Uint128High64(u); Check(h >> 32); Check((h << 32) >> 32); } -{ uint128 u = farmhashcc::CityHash128WithSeed(data + offset, len, uint128(SEED0, SEED1)); uint64_t h = Uint128Low64(u); Check(h >> 32); Check((h << 32) >> 32); h = Uint128High64(u); Check(h >> 32); Check((h << 32) >> 32); } +{ uint128_t u = farmhashcc::Fingerprint128(data + offset, len); uint64_t h = Uint128Low64(u); Check(h >> 32); Check((h << 32) >> 32); h = Uint128High64(u); Check(h >> 32); Check((h << 32) >> 32); } +{ uint128_t u = farmhashcc::CityHash128WithSeed(data + offset, len, uint128_t(SEED0, SEED1)); uint64_t h = Uint128Low64(u); Check(h >> 32); Check((h << 32) >> 32); h = Uint128High64(u); Check(h >> 32); Check((h << 32) >> 32); } return true; #undef Check @@ -3856,8 +3805,8 @@ int RunTest() { void Dump(int offset, int len) { cout << farmhashcc::Hash32WithSeed(data + offset, len, SEED) << "u," << endl; cout << farmhashcc::Hash32(data + offset, len) << "u," << endl; -{ uint128 u = farmhashcc::Fingerprint128(data + offset, len); uint64_t h = Uint128Low64(u); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u, "; h = Uint128High64(u); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u," << endl; } -{ uint128 u = farmhashcc::CityHash128WithSeed(data + offset, len, uint128(SEED0, SEED1)); uint64_t h = Uint128Low64(u); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u, "; h = Uint128High64(u); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u," << endl; } +{ uint128_t u = farmhashcc::Fingerprint128(data + offset, len); uint64_t h = Uint128Low64(u); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u, "; h = Uint128High64(u); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u," << endl; } +{ uint128_t u = farmhashcc::CityHash128WithSeed(data + offset, len, uint128_t(SEED0, SEED1)); uint64_t h = Uint128Low64(u); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u, "; h = Uint128High64(u); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u," << endl; } } #endif @@ -3902,7 +3851,7 @@ static const uint64_t kSeed0 = 1234567; static const uint64_t kSeed1 = k0; static const int kDataSize = 1 << 20; static const int kTestSize = 300; -#define kSeed128 uint128(kSeed0, kSeed1) +#define kSeed128 uint128_t(kSeed0, kSeed1) static char data[kDataSize]; @@ -3936,8 +3885,8 @@ template inline bool IsNonZero(T x) { return x != 0; } -template <> inline bool IsNonZero(uint128 x) { - return x != uint128(0, 0); +template <> inline bool IsNonZero(uint128_t x) { + return x != uint128_t(0, 0); } #endif // FARMHASH_SELF_TEST_GUARD @@ -4799,7 +4748,7 @@ static const uint64_t kSeed0 = 1234567; static const uint64_t kSeed1 = k0; static const int kDataSize = 1 << 20; static const int kTestSize = 300; -#define kSeed128 uint128(kSeed0, kSeed1) +#define kSeed128 uint128_t(kSeed0, kSeed1) static char data[kDataSize]; @@ -4833,8 +4782,8 @@ template inline bool IsNonZero(T x) { return x != 0; } -template <> inline bool IsNonZero(uint128 x) { - return x != uint128(0, 0); +template <> inline bool IsNonZero(uint128_t x) { + return x != uint128_t(0, 0); } #endif // FARMHASH_SELF_TEST_GUARD @@ -6060,7 +6009,7 @@ static const uint64_t kSeed0 = 1234567; static const uint64_t kSeed1 = k0; static const int kDataSize = 1 << 20; static const int kTestSize = 300; -#define kSeed128 uint128(kSeed0, kSeed1) +#define kSeed128 uint128_t(kSeed0, kSeed1) static char data[kDataSize]; @@ -6094,8 +6043,8 @@ template inline bool IsNonZero(T x) { return x != 0; } -template <> inline bool IsNonZero(uint128 x) { - return x != uint128(0, 0); +template <> inline bool IsNonZero(uint128_t x) { + return x != uint128_t(0, 0); } #endif // FARMHASH_SELF_TEST_GUARD @@ -6957,7 +6906,7 @@ static const uint64_t kSeed0 = 1234567; static const uint64_t kSeed1 = k0; static const int kDataSize = 1 << 20; static const int kTestSize = 300; -#define kSeed128 uint128(kSeed0, kSeed1) +#define kSeed128 uint128_t(kSeed0, kSeed1) static char data[kDataSize]; @@ -6991,8 +6940,8 @@ template inline bool IsNonZero(T x) { return x != 0; } -template <> inline bool IsNonZero(uint128 x) { - return x != uint128(0, 0); +template <> inline bool IsNonZero(uint128_t x) { + return x != uint128_t(0, 0); } #endif // FARMHASH_SELF_TEST_GUARD @@ -7854,7 +7803,7 @@ static const uint64_t kSeed0 = 1234567; static const uint64_t kSeed1 = k0; static const int kDataSize = 1 << 20; static const int kTestSize = 300; -#define kSeed128 uint128(kSeed0, kSeed1) +#define kSeed128 uint128_t(kSeed0, kSeed1) static char data[kDataSize]; @@ -7888,8 +7837,8 @@ template inline bool IsNonZero(T x) { return x != 0; } -template <> inline bool IsNonZero(uint128 x) { - return x != uint128(0, 0); +template <> inline bool IsNonZero(uint128_t x) { + return x != uint128_t(0, 0); } #endif // FARMHASH_SELF_TEST_GUARD @@ -8751,7 +8700,7 @@ static const uint64_t kSeed0 = 1234567; static const uint64_t kSeed1 = k0; static const int kDataSize = 1 << 20; static const int kTestSize = 300; -#define kSeed128 uint128(kSeed0, kSeed1) +#define kSeed128 uint128_t(kSeed0, kSeed1) static char data[kDataSize]; @@ -8785,8 +8734,8 @@ template inline bool IsNonZero(T x) { return x != 0; } -template <> inline bool IsNonZero(uint128 x) { - return x != uint128(0, 0); +template <> inline bool IsNonZero(uint128_t x) { + return x != uint128_t(0, 0); } #endif // FARMHASH_SELF_TEST_GUARD @@ -10012,7 +9961,7 @@ static const uint64_t kSeed0 = 1234567; static const uint64_t kSeed1 = k0; static const int kDataSize = 1 << 20; static const int kTestSize = 300; -#define kSeed128 uint128(kSeed0, kSeed1) +#define kSeed128 uint128_t(kSeed0, kSeed1) static char data[kDataSize]; @@ -10046,8 +9995,8 @@ template inline bool IsNonZero(T x) { return x != 0; } -template <> inline bool IsNonZero(uint128 x) { - return x != uint128(0, 0); +template <> inline bool IsNonZero(uint128_t x) { + return x != uint128_t(0, 0); } #endif // FARMHASH_SELF_TEST_GUARD @@ -10909,7 +10858,7 @@ static const uint64_t kSeed0 = 1234567; static const uint64_t kSeed1 = k0; static const int kDataSize = 1 << 20; static const int kTestSize = 300; -#define kSeed128 uint128(kSeed0, kSeed1) +#define kSeed128 uint128_t(kSeed0, kSeed1) static char data[kDataSize]; @@ -10943,8 +10892,8 @@ template inline bool IsNonZero(T x) { return x != 0; } -template <> inline bool IsNonZero(uint128 x) { - return x != uint128(0, 0); +template <> inline bool IsNonZero(uint128_t x) { + return x != uint128_t(0, 0); } #endif // FARMHASH_SELF_TEST_GUARD @@ -12157,4 +12106,5 @@ int main(int argc, char** argv) { #endif #endif // FARMHASHSELFTEST -#endif // UTIL_HASH_FARMHASH_H_ \ No newline at end of file + +#endif // UTIL_HASH_FARMHASH_H_ diff --git a/src/util/hash/hash.cc b/src/util/hash/hash.cc deleted file mode 100644 index b698376e..00000000 --- a/src/util/hash/hash.cc +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// -// This is the legacy unified hash library implementation. Its components are -// being split up into smaller, dedicated libraries. What remains here are -// things still being migrated. -// -// To find the implementation of the core Bob Jenkins lookup2 hash, look in -// jenkins.cc. - -#include "util/hash/hash.h" - -static const uint32 kFingerprintSeed0 = 0xabc; -static const uint32 kFingerprintSeed1 = 0xdef; - -uint64 FingerprintReferenceImplementation(const char *s, size_t len) { - uint32 hi = Hash32StringWithSeed(s, len, kFingerprintSeed0); - uint32 lo = Hash32StringWithSeed(s, len, kFingerprintSeed1); - return CombineFingerprintHalves(hi, lo); -} - -uint64 FingerprintInterleavedImplementation(const char *s, size_t len) { - uint32 hi = Hash32StringWithSeed(s, len, kFingerprintSeed0); - uint32 lo = Hash32StringWithSeed(s, len, kFingerprintSeed1); - return CombineFingerprintHalves(hi, lo); -} - -#if defined(__GNUC__) && !defined(__QNX__) -HASH_NAMESPACE_DECLARATION_START -template class hash_set; -template class hash_map; -HASH_NAMESPACE_DECLARATION_END -#endif diff --git a/src/util/hash/hash.h b/src/util/hash/hash.h index 7f2098d5..8ec59315 100644 --- a/src/util/hash/hash.h +++ b/src/util/hash/hash.h @@ -1,4 +1,4 @@ -// Copyright 1999 Google Inc. All Rights Reserved. +// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,121 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// -// -// -// This file contains routines for hashing and fingerprinting. -// -// A hash function takes an arbitrary input bitstring (string, char*, -// number) and turns it into a hash value (a fixed-size number) such -// that unequal input values have a high likelihood of generating -// unequal hash values. A fingerprint is a hash whose design is -// biased towards avoiding hash collisions, possibly at the expense of -// other characteristics such as execution speed. -// -// In general, if you are only using the hash values inside a single -// executable -- you're not writing the values to disk, and you don't -// depend on another instance of your program, running on another -// machine, generating the same hash values as you -- you want to use -// a HASH. Otherwise, you want to use a FINGERPRINT. -// -// RECOMMENDED HASH FOR STRINGS: GoodFastHash -// -// It is a functor, so you can use it like this: -// hash_map > -// hash_set > -// -// RECOMMENDED HASH FOR NUMBERS: hash<> -// -// Note that this is likely the identity hash, so if your -// numbers are "non-random" (especially in the low bits), another -// choice is better. You can use it like this: -// hash_map -// hash_set -// -// RECOMMENDED HASH FOR POINTERS: hash<> -// -// This is a lightly mixed hash. An identity function can be a poor choice -// because pointers can have low entropy in the least significant bits, and -// those bits are important for efficiency in some uses, e.g., dense_hash_map<>. -// -// RECOMMENDED HASH FOR std::pair: GoodFastHash>. -// -// This is significantly faster than hash> and calls -// GoodFastHash and GoodFastHash (instead of hash and hash), where -// they are available. -// -// RECOMMENDED HASH FOR std::tuple: hash> -// -// RECOMMENDED HASH FOR std::array: hash> -// -// RECOMMENDED HASH FOR STRUCTS: ::util_hash::Hash -// -// ::util_hash::Hash(x, y, z) hashes x, y, and z (using GoodFastHash<> if it's -// available; otherwise using hash<>) and then combines the hashes. -// -// RECOMMENDED FINGERPRINT: -// -// For string input, use Fingerprint2011 from fingerprint2011.h. Do *not* use -// Fingerprint in new code; it has problems with excess collisions (see below). -// -// For integer input, Fingerprint is still recommended and has no known -// collision problems. -// -// OTHER HASHES AND FINGERPRINTS: -// -// -// The wiki page also has good advice for when to use a fingerprint vs -// a hash. -// -// -// Note: if your file declares hash_map or -// hash_set, it will use the default hash function, -// hash. This is not a great choice. Always provide an -// explicit functor, such as GoodFastHash, as a template argument. -// (Either way, you will need to #include this file to get the -// necessary definition.) -// -// Some of the hash functions below are documented to be fixed -// forever; the rest (whether they're documented as so or not) may -// change over time. If you require a hash function that does not -// change over time, you should have unittests enforcing this -// property. We already have several such functions; see -// hash_unittest.cc for the details and unittests. #ifndef UTIL_HASH_HASH_H_ #define UTIL_HASH_HASH_H_ -#include -#include // for uintptr_t -#include -#include -#include -using __gnu_cxx::hash; -using __gnu_cxx::hash_map; // hacky way to make sure we import standard hash<> fns -#include -using __gnu_cxx::hash; -using __gnu_cxx::hash_set; -#include -#include -#include - -#include "base/casts.h" #include "base/int128.h" #include "base/integral_types.h" -#include "base/macros.h" -#include "base/port.h" -#include "base/type_traits.h" -#include "util/hash/builtin_type_hash.h" -#include "util/hash/city.h" #include "util/hash/hash128to64.h" #include "util/hash/jenkins.h" #include "util/hash/jenkins_lookup2.h" #include "util/hash/string_hash.h" -// TODO(jyrki): This is one of the legacy hashes, kept here only -// temporarily for making it easier to remove the physical dependency -// to legacy_hash.h inline uint32 HashTo32(const char *s, size_t slen) { uint32 retval = Hash32StringWithSeed(s, slen, MIX32); return retval == kIllegalHash32 ? static_cast(retval-1) : retval; @@ -134,125 +30,15 @@ inline uint32 HashTo32(const char *s, size_t slen) { HASH_NAMESPACE_DECLARATION_START -// STLport and MSVC 10.0 above already define these. -#if !defined(_STLP_LONG_LONG) && !(defined(_MSC_VER) && _MSC_VER >= 1600) - -#if defined(_MSC_VER) -// MSVC's stl implementation with _MSC_VER less than 1600 doesn't have -// this hash struct. STLport already defines this. -template -struct hash { - size_t operator()(const T& t) const; -}; -#endif // defined(_MSC_VER) - -template<> struct hash { - size_t operator()(int64 x) const { return static_cast(x); } -}; - -template<> struct hash { - size_t operator()(uint64 x) const { return static_cast(x); } -}; - -#endif // !defined(_STLP_LONG_LONG) && !(defined(_MSC_VER) && _MSC_VER >= 1600) - -template<> struct hash { - size_t operator()(bool x) const { return static_cast(x); } -}; - -HASH_NAMESPACE_DECLARATION_END - - -// ---------------------------------------------------------------------- -// Fingerprint() -// When used for string input, this is not recommended for new code. -// Instead, use Fingerprint2011(), a higher-quality and faster hash function. -// (See fingerprint2011.h.) The functions below that take integer input are -// still recommended. -// -// Fingerprinting a string (or char*) will never return 0 or 1, -// in case you want a couple of special values. However, -// fingerprinting a numeric type may produce 0 or 1. -// ---------------------------------------------------------------------- -extern uint64 FingerprintReferenceImplementation(const char *s, size_t len); -extern uint64 FingerprintInterleavedImplementation(const char *s, size_t len); -inline uint64 Fingerprint(const char *s, size_t len) { - if (sizeof(s) == 8) { // 64-bit systems have 8-byte pointers. - // The better choice when we have a decent number of registers. - return FingerprintInterleavedImplementation(s, len); - } else { - return FingerprintReferenceImplementation(s, len); - } -} - -// Routine that combines together the hi/lo part of a fingerprint -// and changes the result appropriately to avoid returning 0/1. -inline uint64 CombineFingerprintHalves(uint64 hi, uint32 lo) { - uint64 result = (hi << 32) | lo; - // (result >> 1) is here the same as (result > 1), but slightly faster. - if (PREDICT_TRUE(result >> 1)) { - return result; // Not 0 or 1, return as is. - } - return result ^ GG_ULONGLONG(0x130f9bef94a0a928); -} - -inline uint64 Fingerprint(const string& s) { - return Fingerprint(s.data(), s.size()); -} -inline uint64 Hash64StringWithSeed(const string& s, uint64 c) { - return Hash64StringWithSeed(s.data(), s.size(), c); -} -inline uint64 Fingerprint(schar c) { - return Hash64NumWithSeed(static_cast(c), MIX64); -} -inline uint64 Fingerprint(char c) { - return Hash64NumWithSeed(static_cast(c), MIX64); -} -inline uint64 Fingerprint(uint16 c) { - return Hash64NumWithSeed(static_cast(c), MIX64); -} -inline uint64 Fingerprint(int16 c) { - return Hash64NumWithSeed(static_cast(c), MIX64); -} -inline uint64 Fingerprint(uint32 c) { - return Hash64NumWithSeed(static_cast(c), MIX64); -} -inline uint64 Fingerprint(int32 c) { - return Hash64NumWithSeed(static_cast(c), MIX64); -} -inline uint64 Fingerprint(uint64 c) { - return Hash64NumWithSeed(static_cast(c), MIX64); -} -inline uint64 Fingerprint(int64 c) { - return Hash64NumWithSeed(static_cast(c), MIX64); -} - -// This concatenates two 64-bit fingerprints. It is a convenience function to -// get a fingerprint for a combination of already fingerprinted components. -// It assumes that each input is already a good fingerprint itself. -// Note that this is legacy code and new code should use its replacement -// FingerprintCat2011(). -// -// Note that in general it's impossible to construct Fingerprint(str) -// from the fingerprints of substrings of str. One shouldn't expect -// FingerprintCat(Fingerprint(x), Fingerprint(y)) to indicate -// anything about Fingerprint(StrCat(x, y)). -inline uint64 FingerprintCat(uint64 fp1, uint64 fp2) { - return Hash64NumWithSeed(fp1, fp2); -} - -HASH_NAMESPACE_DECLARATION_START - -// This intended to be a "good" hash function. It may change from time to time. template<> struct hash { size_t operator()(const uint128& x) const { if (sizeof(&x) == 8) { // 64-bit systems have 8-byte pointers. return Hash128to64(x); } else { uint32 a = static_cast(Uint128Low64(x)) + - static_cast(0x9e3779b9UL); + static_cast(0xba79e1bd); uint32 b = static_cast(Uint128Low64(x) >> 32) + - static_cast(0x9e3779b9UL); + static_cast(0xba79e1bd); uint32 c = static_cast(Uint128High64(x)) + MIX32; mix(a, b, c); a += static_cast(Uint128High64(x) >> 32); @@ -260,364 +46,8 @@ template<> struct hash { return c; } } - // Less than operator for MSVC use. - bool operator()(const uint128& a, const uint128& b) const { - return a < b; - } - static const size_t bucket_size = 4; // These are required by MSVC - static const size_t min_buckets = 8; // 4 and 8 are defaults. -}; - -// Avoid collision with definition in port_hash.h (via port.h). -#ifndef HAVE_DEFINED_HASH_FOR_POINTERS -#define HAVE_DEFINED_HASH_FOR_POINTERS -// Hash pointers as if they were int's, but bring more entropy to -// the lower bits. -template struct hash { - size_t operator()(T *x) const { - size_t k = reinterpret_cast(x); - return k + (k >> 6); - } -}; -#endif // HAVE_DEFINED_HASH_FOR_POINTERS - -#if defined(__GNUC__) -#if !defined(STLPORT) -// Use our nice hash function for strings -template -struct hash > { - size_t operator()(const basic_string<_CharT, _Traits, _Alloc>& k) const { - return Hash32StringWithSeed(k.data(), k.size(), MIX32); - } -}; -#endif // !defined(STLPORT) - -// they don't define a hash for const string at all -template<> struct hash { - size_t operator()(const string& k) const { - return HashStringThoroughly(k.data(), k.size()); - } -}; -#endif // defined(__GNUC__) - -// MSVC's STL requires an ever-so slightly different decl -#if defined(STL_MSVC) -template<> struct hash { - size_t operator()(char const* const k) const { - return HashTo32(k, strlen(k)); - } - // Less than operator: - bool operator()(char const* const a, char const* const b) const { - return strcmp(a, b) < 0; - } - static const size_t bucket_size = 4; // These are required by MSVC - static const size_t min_buckets = 8; // 4 and 8 are defaults. -}; - -// MSVC 10.0 and above have already defined this. -#if !defined(_MSC_VER) || _MSC_VER < 1600 -template<> struct hash { - size_t operator()(const string& k) const { - return HashTo32(k.data(), k.size()); - } - // Less than operator: - bool operator()(const string& a, const string& b) const { - return a < b; - } - static const size_t bucket_size = 4; // These are required by MSVC - static const size_t min_buckets = 8; // 4 and 8 are defaults. -}; -#endif // !defined(_MSC_VER) || _MSC_VER < 1600 - -#endif // defined(STL_MSVC) - -// Hasher for STL pairs. Requires hashers for both members to be defined. -// Prefer GoodFastHash, particularly if speed is important. -template -struct hash > { - size_t operator()(const pair& p) const { - size_t h1 = hash()(p.first); - size_t h2 = hash()(p.second); - // The decision below is at compile time - return (sizeof(h1) <= sizeof(uint32)) ? - Hash32NumWithSeed(h1, h2) - : Hash64NumWithSeed(h1, h2); - } - // Less than operator for MSVC. - bool operator()(const pair& a, - const pair& b) const { - return a < b; - } - static const size_t bucket_size = 4; // These are required by MSVC - static const size_t min_buckets = 8; // 4 and 8 are defaults. -}; - -HASH_NAMESPACE_DECLARATION_END - -// If you want an excellent string hash function, and you don't mind if it -// might change when you sync and recompile, please use GoodFastHash<>. -// For most applications, GoodFastHash<> is a good choice, better than -// hash or hash or similar. GoodFastHash<> can change -// from time to time and may differ across platforms, and we'll strive -// to keep improving it. -// -// By the way, when deleting the contents of a hash_set of pointers, it is -// unsafe to delete *iterator because the hash function may be called on -// the next iterator advance. Use STLDeleteContainerPointers(). - -template struct GoodFastHash; - -// This intended to be a "good" hash function. It may change from time to time. -template<> struct GoodFastHash { - size_t operator()(const char* s) const { - return HashStringThoroughly(s, strlen(s)); - } - // Less than operator for MSVC. - bool operator()(const char* a, const char* b) const { - return strcmp(a, b) < 0; - } - static const size_t bucket_size = 4; // These are required by MSVC - static const size_t min_buckets = 8; // 4 and 8 are defaults. -}; - -// This intended to be a "good" hash function. It may change from time to time. -template<> struct GoodFastHash { - size_t operator()(const char* s) const { - return HashStringThoroughly(s, strlen(s)); - } - // Less than operator for MSVC. - bool operator()(const char* a, const char* b) const { - return strcmp(a, b) < 0; - } - static const size_t bucket_size = 4; // These are required by MSVC - static const size_t min_buckets = 8; // 4 and 8 are defaults. -}; - -// This intended to be a "good" hash function. It may change from time to time. -template -struct GoodFastHash > { - size_t operator()(const basic_string<_CharT, _Traits, _Alloc>& k) const { - return HashStringThoroughly(k.data(), k.size() * sizeof(k[0])); - } - // Less than operator for MSVC. - bool operator()(const basic_string<_CharT, _Traits, _Alloc>& a, - const basic_string<_CharT, _Traits, _Alloc>& b) const { - return a < b; - } - static const size_t bucket_size = 4; // These are required by MSVC - static const size_t min_buckets = 8; // 4 and 8 are defaults. -}; - -// This intended to be a "good" hash function. It may change from time to time. -template -struct GoodFastHash > { - size_t operator()(const basic_string<_CharT, _Traits, _Alloc>& k) const { - return HashStringThoroughly(k.data(), k.size() * sizeof(k[0])); - } - // Less than operator for MSVC. - bool operator()(const basic_string<_CharT, _Traits, _Alloc>& a, - const basic_string<_CharT, _Traits, _Alloc>& b) const { - return a < b; - } - static const size_t bucket_size = 4; // These are required by MSVC - static const size_t min_buckets = 8; // 4 and 8 are defaults. -}; - -// This intended to be a "good" hash function; it is much faster than -// hash>. It may change from time to time. Requires -// GoodFastHash<> or hash<> to be defined for T and U. -template -struct GoodFastHash > { - size_t operator()(const std::pair& k) const { - size_t h1 = HashPart(k.first, /* dummy */ 0); - size_t h2 = HashPart(k.second, /* dummy */ 0); - - // Mix the hashes together. Multiplicative hashing mixes the high-order - // bits better than the low-order bits, and rotating moves the high-order - // bits down to the low end, where they matter more for most hashtable - // implementations. - static const size_t kMul = static_cast(0xc6a4a7935bd1e995ULL); - if (base::is_integral::value) { - // We want to avoid GoodFastHash({x, y}) == 0 for common values of {x, y}. - // hash is the identity function for integral types X, so without this, - // GoodFastHash({0, 0}) would be 0. - h1 += 109; - } - h1 = h1 * kMul; - h1 = (h1 << 21) | (h1 >> (std::numeric_limits::digits - 21)); - return h1 + h2; - } - - // Less than operator for MSVC. - bool operator()(const std::pair& a, const std::pair& b) const { - return a < b; - } - static const size_t bucket_size = 4; // These are required by MSVC - static const size_t min_buckets = 8; // 4 and 8 are defaults. - - private: - // Use GoodFastHash if it exists and has an operator(); otherwise, use - // hash. This relies on decltype, which requires C++11. -#ifdef LANG_CXX11 - template()(std::declval())) = 0> - size_t HashPart(const V& v, int) const { - return GoodFastHash()(v); - } -#endif - - template - size_t HashPart(const V& v, ...) const { - return HASH_NAMESPACE::hash()(v); - } }; -#ifdef LANG_CXX11 -#include -#include - -HASH_NAMESPACE_DECLARATION_START - -namespace hash_internal { - -// Lightly hash two hash codes together. When used repetitively to mix more -// than two values, the new values should be in the first argument. -inline size_t Mix(size_t new_hash, size_t accu) { - static const size_t kMul = static_cast(0xc6a4a7935bd1e995ULL); - // Multiplicative hashing will mix bits better in the msb end ... - accu *= kMul; - // ... and rotating will move the better mixed msb-bits to lsb-bits. - return ((accu << 21) | - (accu >> (std::numeric_limits::digits - 21))) + - new_hash; -} - -// HashPart uses operator() from GoodFastHash, preferably, or hash. -template ()(std::declval())) = 0> -inline size_t HashPart(const V& v, int) {return GoodFastHash()(v); } - -template -inline size_t HashPart(const V& v, ...) { return hash()(v); } - -// Hash a single value using either GoodFastHash<> or hash<>. -template static size_t InternalHash(const V& v) { - return HashPart(v, /* dummy */ 0); -} - -template struct Helper { - // Hash fields 0 ... N-1 of u. - template - static size_t TupleHash(const U& u, size_t seed) { - static_assert(N >= 1, "N == 0 is special cased, and N < 0 is silly."); - constexpr int n1 = N - 1; - return Helper::TupleHash(u, Mix(InternalHash(std::get(u)), seed)); - } -}; - -template <> struct Helper<0> { - template - static size_t TupleHash(const U&, size_t seed) { return seed; } -}; - -} // namespace hash_internal - -// Hash functions for tuples. These are intended to be "good" hash functions. -// They may change from time to time. GoodFastHash<> or hash<> must be defined -// for the tuple elements. -template -struct hash> { - public: - size_t operator()(const std::tuple& t) const { - const int kSeed = 113; - return hash_internal::Helper:: - template TupleHash>(t, kSeed); - } - // Less than operator for MSVC. - bool operator()(const std::tuple& a, - const std::tuple& b) const { - return a < b; - } - static const size_t bucket_size = 4; // These are required by MSVC - static const size_t min_buckets = 8; // 4 and 8 are defaults. -}; - -// Hash functions for std::array. These are intended to be "good" hash -// functions. They may change from time to time. GoodFastHash<> or hash<> must -// be defined for T. -template -struct hash> { - public: - size_t operator()(const std::array& t) const { - const int kSeed = 71; - return hash_internal::Helper:: - template TupleHash>(t, kSeed); - } - // Less than operator for MSVC. - bool operator()(const std::array& a, - const std::array& b) const { - return a < b; - } - static const size_t bucket_size = 4; // These are required by MSVC - static const size_t min_buckets = 8; // 4 and 8 are defaults. -}; - -HASH_NAMESPACE_DECLARATION_END - -namespace util_hash { -// ::util_hash::Hash(a, b, c, ...) hashes a, b, c, and so on (using -// GoodFastHash<>, if it's available for the given type, otherwise using -// hash<>), and then combines the individual hashes. This is intended to be a -// pretty good hash function, which may change from time to time. (Its quality -// mostly depends on the quality of GoodFastHash<> and/or hash<>.) -// -// In the somewhat unusual case of nested calls to Hash(), it is best if -// the new values should appear first in the arguments list. For example: -// -// size_t Hash(int x, int y, vector v, vector w) { -// auto combine = [](size_t h, const T& elem) { -// return util_hash::Hash(elem, h); // Note that elem is the first arg. -// }; -// size_t vh = -// std::accumulate(v.begin(), v.end(), static_cast(0), combine); -// size_t wh = -// std::accumulate(w.begin(), w.end(), static_cast(0), combine); -// // Note that x and y come before vh and wh. -// return util_hash::Hash(x, y, vh, wh); -// } -// -// A stronger (and slower) way to combine multiple hash codes together is to -// use hash. The order of args in hash doesn't matter. For -// example: -// -// size_t Hash(T x, U y) { -// return hash()(uint128(util_hash::Hash(x), util_hash::Hash(y))); -// } - -inline size_t Hash() { - return 113; -} - -template -size_t Hash(const First& f, const T&... t) { - return HASH_NAMESPACE::hash_internal::Mix( - HASH_NAMESPACE::hash_internal::InternalHash(f), Hash(t...)); -} -} // namespace util_hash - -#endif // LANG_CXX11 - -// Extern template declarations. -// -// gcc only for now. msvc and others: this technique is likely to work with -// your compiler too. changelists welcome. -// -// This technique is limited to template specializations whose hash key -// functions are declared in this file. - -#if defined(__GNUC__) -HASH_NAMESPACE_DECLARATION_START -extern template class hash_set; -extern template class hash_map; HASH_NAMESPACE_DECLARATION_END -#endif // defined(__GNUC__) -#endif // UTIL_HASH_HASH_H_ \ No newline at end of file +#endif // UTIL_HASH_HASH_H_ diff --git a/src/util/hash/hash128to64.h b/src/util/hash/hash128to64.h index ca151c89..51d399d0 100644 --- a/src/util/hash/hash128to64.h +++ b/src/util/hash/hash128to64.h @@ -13,6 +13,7 @@ // limitations under the License. // + #ifndef UTIL_HASH_HASH128TO64_H_ #define UTIL_HASH_HASH128TO64_H_ @@ -35,4 +36,4 @@ inline uint64 Hash128to64(const uint128& x) { } -#endif // UTIL_HASH_HASH128TO64_H_ \ No newline at end of file +#endif // UTIL_HASH_HASH128TO64_H_ diff --git a/src/util/hash/jenkins.cc b/src/util/hash/jenkins.cc index dfa4f14c..c943c134 100644 --- a/src/util/hash/jenkins.cc +++ b/src/util/hash/jenkins.cc @@ -13,6 +13,7 @@ // limitations under the License. // + #include "util/hash/jenkins.h" @@ -72,7 +73,9 @@ uint32 Hash32StringWithSeed(const char *s, size_t len, uint32 seed) { return c; } -uint64 Hash64StringWithSeed(const char *s, size_t len, uint64 seed) { +uint64 Hash64StringWithSeedReferenceImplementation(const char *s, + size_t len, + uint64 seed) { uint64 n = seed; size_t prime1 = 0, prime2 = 8; // Indices into kPrimes64 union { @@ -90,3 +93,21 @@ uint64 Hash64StringWithSeed(const char *s, size_t len, uint64 seed) { } return n; } + +uint64 Hash64StringWithSeed(const char *s, size_t len, uint64 seed) { + uint64 a, b; + b = 0x2c2ca38cd0cc731bULL; + uint64 c = seed; + while (len > 24) { + a = Hash64StringWithSeedReferenceImplementation(s, 24, c); + mix(a, b, c); + s += 24; + len -= 24; + } + if (len > 0) { + a = Hash64StringWithSeedReferenceImplementation(s, len, c); + mix(a, b, c); + } + return c; +} + diff --git a/src/util/hash/jenkins.h b/src/util/hash/jenkins.h index 5a7b3caf..f5476b25 100644 --- a/src/util/hash/jenkins.h +++ b/src/util/hash/jenkins.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // The core Jenkins Lookup2-based hashing routines. These are legacy hashing // routines and should be avoided in new code. Their implementations are dated @@ -51,4 +52,4 @@ const uint16 kIllegalHash16 = static_cast(0xffffU); uint32 Hash32StringWithSeed(const char *s, size_t len, uint32 c); uint64 Hash64StringWithSeed(const char *s, size_t len, uint64 c); -#endif // UTIL_HASH_JENKINS_H_ \ No newline at end of file +#endif // UTIL_HASH_JENKINS_H_ diff --git a/src/util/hash/jenkins_lookup2.h b/src/util/hash/jenkins_lookup2.h index 3a2b8b5d..5e8ca1b1 100644 --- a/src/util/hash/jenkins_lookup2.h +++ b/src/util/hash/jenkins_lookup2.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // Legacy implementation of the core Jenkins lookup2 algorithm. This is used in // many older hash functions which we are unable to remove or change due to the @@ -166,4 +167,4 @@ static inline uint32 Google1At(const char *ptr2) { // use more meaningful concepts. # define WORD_HASH -#endif // UTIL_HASH_JENKINS_LOOKUP2_H_ \ No newline at end of file +#endif // UTIL_HASH_JENKINS_LOOKUP2_H_ diff --git a/src/util/hash/murmur.cc b/src/util/hash/murmur.cc index 608c015e..d8afb1ab 100644 --- a/src/util/hash/murmur.cc +++ b/src/util/hash/murmur.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // jyrki@google.com (Jyrki Alakuijala) #include "util/hash/murmur.h" @@ -62,8 +63,8 @@ void MurmurCat::Append(const char *buf, size_t len) { return; } // Not enough data to murmur, accumulate more. - last_val_ |= LoadBytes(buf, len) << (offset_ * 8); - offset_ += len; + last_val_ |= LoadBytes(buf, static_cast(len)) << (offset_ * 8); + offset_ += static_cast(len); return; // We don't have enough to hash yet. } if (offset_ != 0) { @@ -78,7 +79,7 @@ void MurmurCat::Append(const char *buf, size_t len) { buf += num_bytes; len -= num_bytes; } - const int len_aligned = len & ~0x7; + const size_t len_aligned = len & ~0x7; const char * const end = buf + len_aligned; for (const char *p = buf; p != end; p += 8) { const uint64 data = ShiftMix(LittleEndian::Load64(p) * mul) * mul; @@ -113,7 +114,7 @@ uint64 MurmurHash64WithSeed(const char *buf, static const uint64 mul = 0xc6a4a7935bd1e995ULL; // Let's remove the bytes not divisible by the sizeof(uint64). // This allows the inner loop to process the data as 64 bit integers. - const int len_aligned = len & ~0x7; + const size_t len_aligned = len & ~0x7; const char * const end = buf + len_aligned; uint64 hash = seed ^ (len * mul); for (const char *p = buf; p != end; p += 8) { @@ -131,4 +132,4 @@ uint64 MurmurHash64WithSeed(const char *buf, return hash; } -} // namespace util_hash \ No newline at end of file +} // namespace util_hash diff --git a/src/util/hash/murmur.h b/src/util/hash/murmur.h index 72aaa118..32a1cc15 100644 --- a/src/util/hash/murmur.h +++ b/src/util/hash/murmur.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // jyrki@google.com (Jyrki Alakuijala) // // MurmurHash is a fast multiplication and shifting based algorithm, @@ -104,4 +105,4 @@ class MurmurCat { } // namespace util_hash -#endif // UTIL_HASH_MURMUR_H_ \ No newline at end of file +#endif // UTIL_HASH_MURMUR_H_ diff --git a/src/util/hash/murmur_large_test.cc b/src/util/hash/murmur_large_test.cc deleted file mode 100644 index a38a12c3..00000000 --- a/src/util/hash/murmur_large_test.cc +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2009 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Author: jyrki@google.com (Jyrki Alakuijala) -// -// Tests for the fast hashing algorithm based on Austin Appleby's -// MurmurHash 2.0 algorithm. See http://murmurhash.googlepages.com/ -// -// Testing is split into small and large parts. The small test runs in -// 10 seconds and the large takes around 30 seconds in optimized mode, and -// substantially longer in debug. - -#include - -#include "base/integral_types.h" -#include "gtest/gtest.h" -#include "util/endian/endian.h" -#include "util/hash/hasheval/string_hash_eval.h" -#include "util/hash/murmur.h" -#include "util/random/acmrandom.h" - - -namespace { - -// Reference public domain implementation from -// http://murmurhash.googlepages.com/ -// If you need this code or parts of it in production code, move it first to -// third_party. -uint64_t MurmurHash64Reference(const void * key, int len) { - unsigned int seed = 0; - const uint64_t m = 0xc6a4a7935bd1e995ULL; - const int r = 47; - - uint64_t h = seed ^ (len * m); - - const uint64_t * data = (const uint64_t *)key; - const uint64_t * end = data + (len/8); - - while (data != end) { - uint64_t k = LittleEndian::Load64(data++); - - k *= m; - k ^= k >> r; - k *= m; - - h ^= k; - h *= m; - } - - const unsigned char * data2 = (const unsigned char*)data; - - switch (len & 7) { - case 7: - h ^= uint64_t(data2[6]) << 48; - FALLTHROUGH_INTENDED; - case 6: - h ^= uint64_t(data2[5]) << 40; - FALLTHROUGH_INTENDED; - case 5: - h ^= uint64_t(data2[4]) << 32; - FALLTHROUGH_INTENDED; - case 4: - h ^= uint64_t(data2[3]) << 24; - FALLTHROUGH_INTENDED; - case 3: - h ^= uint64_t(data2[2]) << 16; - FALLTHROUGH_INTENDED; - case 2: - h ^= uint64_t(data2[1]) << 8; - FALLTHROUGH_INTENDED; - case 1: - h ^= uint64_t(data2[0]); - h *= m; - } - - h ^= h >> r; - h *= m; - h ^= h >> r; - - return h; -} - -} // namespace - -namespace util_hash { - -TEST(RandomStrings, AgainstReferenceImplementation) { - char data[1024] = { 0 }; - const int kIters = 1000000; - ACMRandom rnd(ACMRandom::DeterministicSeed()); - for (int i = 0; i < kIters; ++i) { - const int min_length = 1; - const int len = min_length + rnd.Uniform(sizeof(data) - min_length); - InitializeRandomString(len, &data[0], &rnd); - const uint64 hash = MurmurHash64(&data[0], len); - uint64 reference_hash = MurmurHash64Reference(&data[0], len); - if (reference_hash >> 32 == 0) { - reference_hash |= 1ULL << 32; - } - EXPECT_EQ(reference_hash, hash); - } -} - -} // namespace util_hash \ No newline at end of file diff --git a/src/util/hash/murmur_test.cc b/src/util/hash/murmur_test.cc deleted file mode 100644 index d843cb6b..00000000 --- a/src/util/hash/murmur_test.cc +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2009 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Author: jyrki@google.com (Jyrki Alakuijala) -// -// Tests for the fast hashing algorithm based on Austin Appleby's -// MurmurHash 2.0 algorithm. See http://murmurhash.googlepages.com/ - -#include "util/hash/murmur.h" - -#include -#include - -#include "base/integral_types.h" -#include -#include "gtest/gtest.h" -#include "util/hash/fingerprint96.h" -#include "util/hash/fingerprinting.h" -#include "util/hash/hasheval/string_hash_eval.h" -#include "util/random/acmrandom.h" - - -namespace util_hash { - -TEST(Murmur, EmptyData64) { - EXPECT_EQ(0ULL, MurmurHash64(NULL, 0ULL)); - EXPECT_EQ(0ULL, MurmurHash64WithSeed(NULL, 0ULL, 0)); -} - -TEST(MurmurCat, EmptyData64) { - MurmurCat cat; - cat.Init(0ULL, 0ULL); - cat.Append(NULL, 0ULL); - EXPECT_EQ(0ULL, cat.GetHash()); - EXPECT_EQ(0ULL, MurmurHash64WithSeed(NULL, 0ULL, 0)); -} - -TEST(Murmur, VaryWithDifferentSeeds) { - // While in theory different seeds could return the same - // hash for the same data this is unlikely. - char data1 = 'x'; - EXPECT_NE(MurmurHash64WithSeed(&data1, 1, 100), - MurmurHash64WithSeed(&data1, 1, 101)); -} - -TEST(MurmurCat, VaryWithDifferentSeeds) { - MurmurCat cat1; - cat1.Init(100ULL, 1ULL); - cat1.Append("x", 1); - - MurmurCat cat2; - cat2.Init(101ULL, 1ULL); - cat2.Append("x", 1); - - EXPECT_NE(cat1.GetHash(), cat2.GetHash()); -} - -// Hashes don't change. -TEST(Murmur, Idempotence) { - const char data[] = "deadbeef"; - const size_t dlen = strlen(data); - const uint64 orig64 = MurmurHash64(data, dlen); - - EXPECT_EQ(MurmurHash64(data, dlen), MurmurHash64(data, dlen)); - - for (int i = 0; i < 10; i++) { - EXPECT_EQ(MurmurHash64WithSeed(data, dlen, i), - MurmurHash64WithSeed(data, dlen, i)); - } - - const char next_data[] = "deadbeef000---"; - const size_t next_dlen = strlen(next_data); - - EXPECT_EQ(MurmurHash64(next_data, next_dlen), - MurmurHash64(next_data, next_dlen)); - - for (int i = 0; i < 10; i++) { - EXPECT_EQ(MurmurHash64WithSeed(next_data, next_dlen, i), - MurmurHash64WithSeed(next_data, next_dlen, i)); - } - - // Go back to the first test data ('data') and make sure it hasn't changed. - EXPECT_EQ(MurmurHash64(data, dlen), orig64); -} - -TEST(MurmurCat, CompatibilityWithMurmurHash) { - ACMRandom rnd(ACMRandom::DeterministicSeed()); - for (int i = 0; i < 1000; ++i) { - string data(i + 1, 0); - InitializeRandomString(data.size(), &data[0], &rnd); - uint64 expected = MurmurHash64(data.data(), data.size()); - - MurmurCat cat; - cat.Init(0ULL, data.size()); - cat.Append(data.data(), data.size()); - EXPECT_EQ(expected, cat.GetHash()); - } -} - -TEST(MurmurCat, CompatibilityWithMurmurHashSplit2) { - ACMRandom rnd(ACMRandom::DeterministicSeed()); - for (int i = 0; i < 1000; ++i) { - string data(i + 9, 0); - InitializeRandomString(data.size(), &data[0], &rnd); - uint64 expected = MurmurHash64(data.data(), data.size()); - - MurmurCat split_cat; - split_cat.Init(0ULL, data.size()); - int split = 1 + (i % (data.size() - 2)); - split_cat.Append(data.data(), split); - split_cat.Append(data.data() + split, data.size() - split); - EXPECT_EQ(expected, split_cat.GetHash()); - } -} - -TEST(MurmurCat, CompatibilityWithMurmurHashSplit3) { - ACMRandom rnd(ACMRandom::DeterministicSeed()); - for (int i = 0; i < 1000; ++i) { - string data(i + 9, 0); - InitializeRandomString(data.size(), &data[0], &rnd); - uint64 expected = MurmurHash64(data.data(), data.size()); - - MurmurCat triple_cat; - triple_cat.Init(0ULL, data.size()); - int split0 = i & 7; - int split1 = 8 + (i % (data.size() - 2)); - triple_cat.Append(data.data(), split0); - triple_cat.Append(data.data() + split0, split1 - split0); - triple_cat.Append(data.data() + split1, data.size() - split1); - EXPECT_EQ(expected, triple_cat.GetHash()); - } -} - -} // namespace util_hash \ No newline at end of file diff --git a/src/util/hash/string_hash.h b/src/util/hash/string_hash.h index fe812c71..67522bf6 100644 --- a/src/util/hash/string_hash.h +++ b/src/util/hash/string_hash.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // These are the core hashing routines which operate on strings. We define // strings loosely as a sequence of bytes, and these routines are designed to @@ -87,4 +88,4 @@ inline size_t HashStringThoroughlyWithSeeds(const char* s, size_t len, return hash_internal::Thoroughly<>::Hash(s, len, seed0, seed1); } -#endif // UTIL_HASH_STRING_HASH_H_ \ No newline at end of file +#endif // UTIL_HASH_STRING_HASH_H_ diff --git a/src/util/math/exactfloat/exactfloat.cc b/src/util/math/exactfloat/exactfloat.cc index 3a38fa3d..5c8ff370 100644 --- a/src/util/math/exactfloat/exactfloat.cc +++ b/src/util/math/exactfloat/exactfloat.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) #include "util/math/exactfloat/exactfloat.h" @@ -773,4 +774,4 @@ ExactFloat logb(const ExactFloat& a) { ExactFloat ExactFloat::Unimplemented() { LOG(FATAL) << "Unimplemented ExactFloat method called"; return NaN(); -} \ No newline at end of file +} diff --git a/src/util/math/exactfloat/exactfloat.h b/src/util/math/exactfloat/exactfloat.h index 18eb3967..d5e5da01 100644 --- a/src/util/math/exactfloat/exactfloat.h +++ b/src/util/math/exactfloat/exactfloat.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // Author: ericv@google.com (Eric Veach) // // ExactFloat is a multiple-precision floating point type based on the OpenSSL @@ -612,4 +613,4 @@ inline ExactFloat ExactFloat::CopyWithSign(int sign) const { return r; } -#endif // UTIL_MATH_EXACTFLOAT_EXACTFLOAT_H_ \ No newline at end of file +#endif // UTIL_MATH_EXACTFLOAT_EXACTFLOAT_H_ diff --git a/src/util/math/mathlimits.cc b/src/util/math/mathlimits.cc index a55926fd..98f224aa 100644 --- a/src/util/math/mathlimits.cc +++ b/src/util/math/mathlimits.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // All Rights Reserved. // // @@ -119,4 +120,4 @@ DEF_FP_LIMITS(long double, LDBL); #undef DEF_SIGNED_INT_LIMITS #undef DEF_UNSIGNED_INT_LIMITS #undef DEF_FP_LIMITS -#undef DEF_PRECISION_LIMITS \ No newline at end of file +#undef DEF_PRECISION_LIMITS diff --git a/src/util/math/mathlimits.h b/src/util/math/mathlimits.h index 5be77dac..309abfc4 100644 --- a/src/util/math/mathlimits.h +++ b/src/util/math/mathlimits.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // All Rights Reserved. // // @@ -202,8 +203,8 @@ DECL_UNSIGNED_INT_LIMITS(unsigned long long int) // ========================================================================= // #ifdef WIN32 // Lacks built-in isnan() and isinf() #define DECL_FP_LIMIT_FUNCS \ - static bool IsFinite(const Type x) { return _finite(x); } \ - static bool IsNaN(const Type x) { return _isnan(x); } \ + static bool IsFinite(const Type x) { return _finite(x) != 0; } \ + static bool IsNaN(const Type x) { return _isnan(x) != 0; } \ static bool IsInf(const Type x) { return (_fpclass(x) & (_FPCLASS_NINF | _FPCLASS_PINF)) != 0; } \ static bool IsPosInf(const Type x) { return _fpclass(x) == _FPCLASS_PINF; } \ static bool IsNegInf(const Type x) { return _fpclass(x) == _FPCLASS_NINF; } @@ -253,4 +254,4 @@ DECL_FP_LIMITS(long double, LDBL) // ========================================================================= // -#endif // UTIL_MATH_MATHLIMITS_H__ \ No newline at end of file +#endif // UTIL_MATH_MATHLIMITS_H__ diff --git a/src/util/math/mathutil.cc b/src/util/math/mathutil.cc index adf7fc3c..cac70ba2 100644 --- a/src/util/math/mathutil.cc +++ b/src/util/math/mathutil.cc @@ -13,6 +13,7 @@ // limitations under the License. // + #include "util/math/mathutil.h" #include @@ -285,4 +286,4 @@ double MathUtil::LogCombinations(int n, int k) { } return result; } -} \ No newline at end of file +} diff --git a/src/util/math/mathutil.h b/src/util/math/mathutil.h index 2a966671..4855033b 100644 --- a/src/util/math/mathutil.h +++ b/src/util/math/mathutil.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // This class is intended to contain a collection of useful (static) // mathematical functions, properly coded (by consulting numerical @@ -242,7 +243,7 @@ class MathUtil { // This implementation is correct, meaning there is never any precision loss, // and there is never an overflow. However, if the type is signed, having // numerator == MathLimits::kMin and denominator == -1 is not a - // valid input, because kMin has a greater absolute value that kMax. + // valid input, because kMin has a greater absolute value than kMax. // // Input validity is DCHECKed. When not in debug mode, invalid inputs raise // SIGFPE. @@ -770,7 +771,7 @@ class MathUtil { // for finite values of x and y. // // standard_error is the corresponding MathLimits::kStdError constant. - // It is equivalent to 5 bits of mantissa error. See + // It is equivalent to 5 bits of mantissa error. See util/math/mathlimits.cc. // // Caveat: // AlmostEquals() is not appropriate for checking long sequences of @@ -943,4 +944,4 @@ IntegralType MathUtil::CeilOrFloorOfRatio(IntegralType numerator, } } -#endif // UTIL_MATH_MATHUTIL_H__ \ No newline at end of file +#endif // UTIL_MATH_MATHUTIL_H__ diff --git a/src/util/math/matrix3x3.h b/src/util/math/matrix3x3.h index 2b38c0c7..77276f26 100644 --- a/src/util/math/matrix3x3.h +++ b/src/util/math/matrix3x3.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // // A simple class to handle 3x3 matrices // The aim of this class is to be able to manipulate 3x3 matrices @@ -74,21 +75,6 @@ class Matrix3x3 { m_[2][2] = m22; } - // Copy constructor - Matrix3x3(const Matrix3x3 &mb) { - m_[0][0] = mb.m_[0][0]; - m_[0][1] = mb.m_[0][1]; - m_[0][2] = mb.m_[0][2]; - - m_[1][0] = mb.m_[1][0]; - m_[1][1] = mb.m_[1][1]; - m_[1][2] = mb.m_[1][2]; - - m_[2][0] = mb.m_[2][0]; - m_[2][1] = mb.m_[2][1]; - m_[2][2] = mb.m_[2][2]; - } - // Casting constructor template static Self Cast(const Matrix3x3 &mb) { @@ -122,22 +108,6 @@ class Matrix3x3 { return (*this); } - // Copy - inline Self& operator=(const Self &mb) { - m_[0][0] = mb.m_[0][0]; - m_[0][1] = mb.m_[0][1]; - m_[0][2] = mb.m_[0][2]; - - m_[1][0] = mb.m_[1][0]; - m_[1][1] = mb.m_[1][1]; - m_[1][2] = mb.m_[1][2]; - - m_[2][0] = mb.m_[2][0]; - m_[2][1] = mb.m_[2][1]; - m_[2][2] = mb.m_[2][2]; - return (*this); - } - // Compare inline bool operator==(const Self &mb) const { return (m_[0][0] == mb.m_[0][0]) && @@ -588,7 +558,6 @@ typedef Matrix3x3 Matrix3x3_d; // TODO(user): Matrix3x3 does not actually satisfy the definition of a // POD type even when T is a POD. Pretending that Matrix3x3 is a POD // probably won't cause immediate problems, but eventually this should be fixed. -PROPAGATE_POD_FROM_TEMPLATE_ARGUMENT(Matrix3x3); -#endif // UTIL_MATH_MATRIX3X3_H__ \ No newline at end of file +#endif // UTIL_MATH_MATRIX3X3_H__ diff --git a/src/util/math/vector2.h b/src/util/math/vector2.h index f3e00678..2d0c2727 100644 --- a/src/util/math/vector2.h +++ b/src/util/math/vector2.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // All Rights Reserved. // // @@ -69,7 +70,7 @@ class Vector2 { // FloatType is the type returned by Norm() and Angle(). These methods are // special because they return floating-point values even when VType is an // integer. - typedef typename base::if_::value, + typedef typename std::conditional::value, double, VType>::type FloatType; typedef Vector2 Self; typedef VType BaseType; @@ -81,8 +82,6 @@ class Vector2 { Vector2(); // Create a new vector (x,y) Vector2(const VType x, const VType y); - // Create a new copy of the vector vb - Vector2(const Self &vb); // NOLINT(runtime/explicit) // Keep only the two first coordinates of the vector vb explicit Vector2(const Vector3 &vb); // Keep only the two first coordinates of the vector vb @@ -94,7 +93,6 @@ class Vector2 { static int Size() { return SIZE; } // Modify the coordinates of the current vector void Set(const VType x, const VType y); - const Self& operator=(const Self &vb); // Add two vectors, component by component Self& operator+=(const Self &vb); // Subtract two vectors, component by component @@ -213,11 +211,6 @@ Vector2::Vector2(const VType x, const VType y) { c_[1] = y; } template -Vector2::Vector2(const Self &vb) { - c_[0] = vb.c_[0]; - c_[1] = vb.c_[1]; -} -template Vector2::Vector2(const Vector3 &vb) { c_[0] = vb.x(); c_[1] = vb.y(); @@ -240,13 +233,6 @@ void Vector2::Set(const VType x, const VType y) { c_[1] = y; } -template -const Vector2& Vector2::operator=(const Self &vb) { - c_[0] = vb.c_[0]; - c_[1] = vb.c_[1]; - return (*this); -} - template Vector2& Vector2::operator+=(const Self &vb) { c_[0] += vb.c_[0]; @@ -381,7 +367,7 @@ typename Vector2::FloatType Vector2::Angle(const Self &v) const { template Vector2 Vector2::Normalize() const { - COMPILE_ASSERT(!base::is_integral::value, must_be_floating_point); + COMPILE_ASSERT(!std::is_integral::value, must_be_floating_point); VType n = Norm(); if (n != VType(0)) { n = VType(1.0) / n; @@ -444,7 +430,7 @@ Vector2 Vector2::Fabs() const { template Vector2 Vector2::Abs() const { - COMPILE_ASSERT(base::is_integral::value, use_Fabs_for_float_types); + COMPILE_ASSERT(std::is_integral::value, use_Fabs_for_float_types); COMPILE_ASSERT(static_cast(-1) == -1, type_must_be_signed); COMPILE_ASSERT(sizeof(c_[0]) <= sizeof(int), Abs_truncates_to_int); return Self(abs(c_[0]), abs(c_[1])); @@ -530,7 +516,6 @@ typedef Vector2 Vector2_d; // TODO(user): Vector2 does not actually satisfy the definition of a POD // type even when T is a POD. Pretending that Vector2 is a POD probably // won't cause any immediate problems, but eventually this should be fixed. -PROPAGATE_POD_FROM_TEMPLATE_ARGUMENT(Vector2); -#endif // UTIL_MATH_VECTOR2_H__ \ No newline at end of file +#endif // UTIL_MATH_VECTOR2_H__ diff --git a/src/util/math/vector3.h b/src/util/math/vector3.h index e4717849..2b3505f9 100644 --- a/src/util/math/vector3.h +++ b/src/util/math/vector3.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // All Rights Reserved. // // @@ -69,7 +70,7 @@ class Vector3 { // FloatType is the type returned by Norm() and Angle(). These methods are // special because they return floating-point values even when VType is an // integer. - typedef typename base::if_::value, + typedef typename std::conditional::value, double, VType>::type FloatType; typedef Vector3 Self; typedef VType BaseType; @@ -84,8 +85,6 @@ class Vector3 { // Create a new 3D vector using the two first coordinates of a 2D vectors // and an additional z argument. Vector3(const Vector2 &vb, VType z); - // Create a new copy of the vector vb - Vector3(const Vector3 &vb); // Keep only the three first coordinates of the 4D vector vb explicit Vector3(const Vector4 &vb); // Convert from another vector type @@ -108,7 +107,6 @@ class Vector3 { static int Size() { return SIZE; } // Modify the coordinates of the current vector void Set(const VType x, const VType y, const VType z); - Self& operator=(const Self& vb); // Add two vectors, component by component Self& operator+=(const Self &vb); // Subtract two vectors, component by component @@ -219,13 +217,6 @@ Vector3::Vector3(const Vector2 &vb, VType z) { c_[2] = z; } -template -Vector3::Vector3(const Self &vb) { - c_[0] = vb.c_[0]; - c_[1] = vb.c_[1]; - c_[2] = vb.c_[2]; -} - template Vector3::Vector3(const Vector4 &vb) { c_[0] = vb.x(); @@ -290,14 +281,6 @@ void Vector3::Set(const VType x, const VType y, const VType z) { c_[2] = z; } -template -Vector3& Vector3::operator=(const Self& vb) { - c_[0] = vb.c_[0]; - c_[1] = vb.c_[1]; - c_[2] = vb.c_[2]; - return (*this); -} - template Vector3& Vector3::operator+=(const Self &vb) { c_[0] += vb.c_[0]; @@ -438,7 +421,7 @@ typename Vector3::FloatType Vector3::Norm(void) const { template Vector3 Vector3::Normalize() const { - COMPILE_ASSERT(!base::is_integral::value, must_be_floating_point); + COMPILE_ASSERT(!std::is_integral::value, must_be_floating_point); VType n = Norm(); if (n != VType(0.0)) { n = VType(1.0) / n; @@ -501,7 +484,7 @@ Vector3 Vector3::Fabs() const { template Vector3 Vector3::Abs() const { COMPILE_ASSERT( - !base::is_integral::value || static_cast(-1) == -1, + !std::is_integral::value || static_cast(-1) == -1, type_must_be_signed); using std::abs; return Self(abs(c_[0]), abs(c_[1]), abs(c_[2])); @@ -595,7 +578,6 @@ typedef Vector3 Vector3_d; // TODO(user): Vector3 does not actually satisfy the definition of a POD // type even when T is a POD. Pretending that Vector3 is a POD probably // won't cause any immediate problems, but eventually this should be fixed. -PROPAGATE_POD_FROM_TEMPLATE_ARGUMENT(Vector3); -#endif // UTIL_MATH_VECTOR3_H__ \ No newline at end of file +#endif // UTIL_MATH_VECTOR3_H__ diff --git a/src/util/math/vector3_hash.h b/src/util/math/vector3_hash.h index e3ab1d9c..f188d9fa 100644 --- a/src/util/math/vector3_hash.h +++ b/src/util/math/vector3_hash.h @@ -13,6 +13,7 @@ // limitations under the License. // + // This file provides hash functions for Vector3, assuming T is a POD. // // WARNING: hashing floats and doubles is a tricky business due to multiple @@ -73,20 +74,21 @@ inline uint64 CollapseZeroes(uint64 bits) { // A hash for vectors of floats or doubles. We call CollapseZero() on each // element of v because of +0 vs -0 etc. See above. template size_t FloatHash(const Vec& v) { - const bool kIsFloat = base::is_same::value; - const bool kIsDouble = base::is_same::value; + const bool kIsFloat = std::is_same::value; + const bool kIsDouble = std::is_same::value; CHECK(kIsFloat || kIsDouble); if (kIsFloat) { const char* data = reinterpret_cast(v.Data()); uint128 u(CollapseZeroes(UNALIGNED_LOAD64(data)), CollapseZeroes(UNALIGNED_LOAD64(data + 4)) + MIX64); - return hash()(u); + return HASH_NAMESPACE::hash()(u); } else { const char* data = reinterpret_cast(v.Data()); uint128 u(CollapseZero(UNALIGNED_LOAD64(data)), CollapseZero(UNALIGNED_LOAD64(data + 8)) + MIX64); - u = uint128(hash()(u), CollapseZero(UNALIGNED_LOAD64(data + 16))); - return hash()(u); + u = uint128(HASH_NAMESPACE::hash()(u), + CollapseZero(UNALIGNED_LOAD64(data + 16))); + return HASH_NAMESPACE::hash()(u); } } @@ -97,8 +99,8 @@ template struct GoodFastHash; // This hash function may change from time to time. template struct GoodFastHash > { size_t operator()(const Vector3& v) const { - COMPILE_ASSERT(base::is_pod::value, POD_expected); - if (base::is_floating_point::value) + COMPILE_ASSERT(std::is_pod::value, POD_expected); + if (std::is_floating_point::value) return vector3_hash_internal::FloatHash(v); else return HashStringThoroughly(reinterpret_cast(v.Data()), @@ -117,4 +119,4 @@ template struct hash > { }; HASH_NAMESPACE_DECLARATION_END -#endif // UTIL_MATH_VECTOR3_HASH_H_ \ No newline at end of file +#endif // UTIL_MATH_VECTOR3_HASH_H_ diff --git a/src/util/math/vector4.h b/src/util/math/vector4.h index 87b15e6e..0dcfc5c7 100644 --- a/src/util/math/vector4.h +++ b/src/util/math/vector4.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + // All Rights Reserved. // // @@ -68,7 +69,7 @@ class Vector4 { public: // FloatType is the type returned by Norm(). This method is special because // it returns floating-point values even when VType is an integer. - typedef typename base::if_::value, + typedef typename std::conditional::value, double, VType>::type FloatType; typedef Vector4 Self; typedef VType BaseType; @@ -80,8 +81,6 @@ class Vector4 { Vector4(); // Create a new vector (x,y,z,w) Vector4(const VType x, const VType y, const VType z, const VType w); - // Create a new copy of the vector vb - Vector4(const Vector4 &vb); // Create a new 4D vector from 2D vector and two scalars // (vb.x,vb.y,z,w) Vector4(const Vector2 &vb, const VType z, const VType w); @@ -110,7 +109,6 @@ class Vector4 { static int Size() { return SIZE; } // Modify the coordinates of the current vector void Set(const VType x, const VType y, const VType z, const VType w); - Self& operator=(const Self& vb); // add two vectors, component by component Self& operator+=(const Self& vb); // subtract two vectors, component by component @@ -208,14 +206,6 @@ Vector4::Vector4(const VType x, const VType y, const VType z, c_[3] = w; } -template -Vector4::Vector4(const Self &vb) { - c_[0] = vb.c_[0]; - c_[1] = vb.c_[1]; - c_[2] = vb.c_[2]; - c_[3] = vb.c_[3]; -} - template Vector4::Vector4(const Vector2 &vb, const VType z, const VType w) { @@ -309,15 +299,6 @@ void Vector4::Set(const VType x, const VType y, const VType z, c_[3] = w; } -template -Vector4& Vector4::operator=(const Self& vb) { - c_[0] = vb.c_[0]; - c_[1] = vb.c_[1]; - c_[2] = vb.c_[2]; - c_[3] = vb.c_[3]; - return (*this); -} - template Vector4& Vector4::operator+=(const Self& vb) { c_[0] += vb.c_[0]; @@ -467,10 +448,10 @@ typename Vector4::FloatType Vector4::Norm(void) const { template Vector4 Vector4::Normalize() const { - COMPILE_ASSERT(!base::is_integral::value, must_be_floating_point); + COMPILE_ASSERT(!std::is_integral::value, must_be_floating_point); VType n = Norm(); - if (n != 0) { - n = 1.0 / n; + if (n != VType(0.0)) { + n = VType(1.0) / n; } return Self(*this) *= n; } @@ -487,7 +468,7 @@ Vector4 Vector4::Fabs() const { template Vector4 Vector4::Abs() const { - COMPILE_ASSERT(base::is_integral::value, use_Fabs_for_float_types); + COMPILE_ASSERT(std::is_integral::value, use_Fabs_for_float_types); COMPILE_ASSERT(static_cast(-1) == -1, type_must_be_signed); COMPILE_ASSERT(sizeof(c_[0]) <= sizeof(int), Abs_truncates_to_int); return Self(abs(c_[0]), abs(c_[1]), abs(c_[2]), abs(c_[3])); @@ -587,7 +568,6 @@ typedef Vector4 Vector4_d; // TODO(user): Vector4 does not actually satisfy the definition of a POD // type even when T is a POD. Pretending that Vector4 is a POD probably // won't cause any immediate problems, but eventually this should be fixed. -PROPAGATE_POD_FROM_TEMPLATE_ARGUMENT(Vector4); -#endif // UTIL_MATH_VECTOR4_H__ \ No newline at end of file +#endif // UTIL_MATH_VECTOR4_H__ diff --git a/src/util/units/length-units.cc b/src/util/units/length-units.cc new file mode 100644 index 00000000..728a9e16 --- /dev/null +++ b/src/util/units/length-units.cc @@ -0,0 +1,21 @@ +// Copyright 2004 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + + +// Provide definitions for length unit constants + +#include "util/units/length-units.h" + +const char * const util::units::LengthBase::output_suffix = "m"; diff --git a/src/util/units/length-units.h b/src/util/units/length-units.h new file mode 100644 index 00000000..505f4094 --- /dev/null +++ b/src/util/units/length-units.h @@ -0,0 +1,135 @@ +// Copyright 2003 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + + +// Define common length units. New length units can be added as needed +// provided there is a direct, multiplicative scaling to meters. +// +// When adding new units, you should add an appropriate GetMyUnit accessor +// template and (optionally) define a shorthand typedef specialization for +// float. Also update the physical units unittest to check the conversion +// ratio. + +#ifndef UTIL_UNITS_LENGTH_UNITS_H__ +#define UTIL_UNITS_LENGTH_UNITS_H__ + +#include "util/units/physical-units.h" + +namespace util { + +namespace units { + +struct LengthBase { + // the base unit type is meters + static const char* const output_suffix; + + template + static ValueType GetInBaseUnit( + const PhysicalUnit u) { + return GetMeters(u); + } +}; + +template +class Length { + typedef UnitConversion<1, 1> MetersConversion; + typedef UnitConversion<1, 1000> KilometersConversion; + typedef UnitConversion<10000, 254> InchesConversion; + typedef UnitConversion<10000, 3048> FeetConversion; + typedef UnitConversion<1000, 1609344> MilesConversion; + typedef UnitConversion<1000, 1> MillimetersConversion; + typedef UnitConversion<1, 1852> NauticalMilesConversion; + typedef UnitConversion<10000, 9144> YardsConversion; + + public: + typedef PhysicalUnit Meters; + typedef PhysicalUnit Kilometers; + typedef PhysicalUnit Inches; + typedef PhysicalUnit Feet; + typedef PhysicalUnit Miles; + typedef PhysicalUnit Millimeters; + typedef PhysicalUnit + NauticalMiles; + typedef PhysicalUnit Yards; +}; + +// Define some shorthand, standard typenames. The standard length +// type is chosen to be float. If you need greater precision for +// a specific application, either use the fully qualified typename +// Length::* or declare local typedefs. This would be an +// ideal place for a template typedef, if only C++ supported them. +// Note that units with different floating-point types do not +// support implicit conversion (use the precision_cast<...> method). +typedef Length::Meters Meters; +typedef Length::Kilometers Kilometers; +typedef Length::Inches Inches; +typedef Length::Feet Feet; +typedef Length::Miles Miles; +typedef Length::Millimeters Millimeters; +typedef Length::NauticalMiles NauticalMiles; +typedef Length::Yards Yards; + +// Explicit unit accessors. In general these are safer than using +// the value() accessor, particularly in cases where the unit type +// may not be immediately obvious (such as function returns). + +template +inline ValueType GetMeters(const PhysicalUnit u) { + return typename Length::Meters(u).value(); +} + +template +inline ValueType GetKilometers( + const PhysicalUnit u) { + return typename Length::Kilometers(u).value(); +} + +template +inline ValueType GetInches(const PhysicalUnit u) { + return typename Length::Inches(u).value(); +} + +template +inline ValueType GetFeet(const PhysicalUnit u) { + return typename Length::Feet(u).value(); +} + +template +inline ValueType GetMiles(const PhysicalUnit u) { + return typename Length::Miles(u).value(); +} + +template +inline ValueType GetMillimeters( + const PhysicalUnit u) { + return typename Length::Millimeters(u).value(); +} + +template +inline ValueType GetNauticalMiles( + const PhysicalUnit u) { + return typename Length::NauticalMiles(u).value(); +} + +template +inline ValueType GetYards(const PhysicalUnit u) { + return typename Length::Yards(u).value(); +} + +} // end namespace units + +} // end namespace util + +#endif // UTIL_UNITS_LENGTH_UNITS_H__ diff --git a/src/util/units/physical-units.h b/src/util/units/physical-units.h new file mode 100644 index 00000000..7c360e1e --- /dev/null +++ b/src/util/units/physical-units.h @@ -0,0 +1,329 @@ +// Copyright 2003 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + + +// Basic physical unit classes. These classes are not as fancy as +// some general purpose physical unit libraries, but provide a +// simple and efficient interface for unit tracking and conversion. +// In particular, compound units cannot be automatically constructed +// from or decomposed into simpler units (e.g. velocity = distance / +// time), but can be defined explicitly as opaque types. +// +// These classes define overloaded operators and non-explicit single +// argument ctors, which breaks the style guidelines, but an exception +// has been allowed in this case. +// - Douglas Greiman +// +// Specific types of physical units are defined in other headers +// (e.g. angle-units.h). Each unit type can be specialized to either +// float or double. Non-floating-point types are disallowed, since +// the implicit conversion logic generally fails for integer division. +// Attempting to declare integer-based units results in a fairly +// informative compiler error. +// +// All units share common functionality, as demonstrated in this +// example: +// +// #include "angle-units.h" +// +// class Nomad { +// Radians latitude_; +// ... +// // With -O2 optimization, the use of Radians in this method is +// // completely equivalent to using float, but prevents unitless +// // angles from being passed. +// void SetLatitude(Radians angle) { +// CHECK(angle.abs() < Degrees(90.0)); +// latitude_ = angle; +// latitude_radius_ = EARTH_RADIUS * cos(angle.value()); +// } +// +// // This method contains an implicit unit conversion from degrees +// // to radians. In practice it would make more sense to use +// // Radians as the argument type to avoid this extra work if +// // possible (see the two calls of this method below). +// void MoveNorth(Degrees angle) { +// SetLatitude(latitude_ + angle); +// } +// }; +// +// void do_tests(float degrees_to_move, float radians_to_move) { +// Nomad joe; +// +// // The use of Degrees(30.0) to set the latitude in radians requires +// // no runtime conversion. +// joe.SetLatitude(Degrees(30.0)); +// +// // The Degrees(...) parameter will be converted to radians at +// // runtime prior to addition in Nomad::MoveNorth(). +// joe.MoveNorth(Degrees(degrees_to_move)); +// +// // This is ok, but due to the poor choice of units for the MoveNorth +// // method's argument, incurs two pointless multiply operations to +// // convert from radians to degrees and back to radians. +// joe.MoveNorth(Radians(radians_to_move)); +// +// // Implicit conversions from unitless values generate errors at +// // compile time. +// // joe.MoveNorth(degrees_to_move); // compile ERROR! +// } +// + +#ifndef UTIL_UNITS_PHYSICAL_UNITS_H__ +#define UTIL_UNITS_PHYSICAL_UNITS_H__ + +#include +#include +#include +#include +#include + +#include "base/integral_types.h" +#include "base/macros.h" + +namespace util { + +namespace units { + +// Static conversion scale and offset to convert from a standard base +// unit to a specific unit. The scale and offset is specified as a +// rational number to allow static construction at compile time. +template +struct UnitConversion { + static const int SCALE_NUMERATOR = ScaleNumerator; + static const int SCALE_DENOMINATOR = ScaleDenominator; + static const int OFFSET_NUMERATOR = OffsetNumerator; + static const int OFFSET_DENOMINATOR = OffsetDenominator; +}; + +template +struct UnitConverter { + // Linear unit conversion: A' = A * s + t, where + // - s is a static scale factor and + // - t is a static offset + // composed from two UnitConversion structs. + // Cast one multiplicand to 64 bit to ensure that the integer expression + // is computed in 64 bit. Otherwise Feet(Miles(x)) will overflow. + static inline Float Convert(Float value) { + // no conversion + if ((FromUnit::SCALE_NUMERATOR == ToUnit::SCALE_NUMERATOR) && + (FromUnit::SCALE_DENOMINATOR == ToUnit::SCALE_DENOMINATOR) && + (FromUnit::OFFSET_NUMERATOR == ToUnit::OFFSET_NUMERATOR) && + (FromUnit::OFFSET_DENOMINATOR == ToUnit::OFFSET_DENOMINATOR)) { + return value; + } + // scaling no offset + if ((FromUnit::OFFSET_NUMERATOR == 0) && (ToUnit::OFFSET_NUMERATOR == 0)) { + return static_cast(value * + (static_cast(static_cast(ToUnit::SCALE_NUMERATOR) * + FromUnit::SCALE_DENOMINATOR) / + static_cast(static_cast(ToUnit::SCALE_DENOMINATOR) * + FromUnit::SCALE_NUMERATOR))); + } + // scaling and offset + return static_cast( + (static_cast(value * + (static_cast(static_cast(ToUnit::SCALE_NUMERATOR) * + FromUnit::SCALE_DENOMINATOR) / + static_cast(static_cast(ToUnit::SCALE_DENOMINATOR) * + FromUnit::SCALE_NUMERATOR)))) - + (static_cast(static_cast(ToUnit::SCALE_NUMERATOR) * + FromUnit::SCALE_DENOMINATOR * + FromUnit::OFFSET_NUMERATOR) / + static_cast(static_cast(ToUnit::SCALE_DENOMINATOR) * + FromUnit::SCALE_NUMERATOR * + FromUnit::OFFSET_DENOMINATOR)) + + (static_cast(ToUnit::OFFSET_NUMERATOR) / + static_cast(ToUnit::OFFSET_DENOMINATOR))); + } +}; + +// Some unit operations are only defined for base units that have linear +// transformations, as in T(a+b) = T(a) + T(b). Temperatures units are +// an example of units that do not have linear transformations. By +// default unit transformations are assumed to be linear; see +// temperature-units.h for an example of how to override this default. +template +struct is_linear_unit_transformation : std::true_type { }; + +// Template class holding a single value with an associated physical +// unit. The unit and conversion parameters are statically defined +// and optimized at compile time. With optimization (-O2), use of a +// single physical unit type is as efficient as using a native +// floating point type. Conversions between units are optimized to +// (typically) a single multiplication operation. Unit conversions +// for constants are done at compile time and incur no runtime +// overhead (again at -O2). +// +// Template parameters: +// Base is the base unit class, such as Angle or Length. If operator<< +// is used, it must have: +// - a public static field "output_suffix" and +// - a public static method Float Base::GetInBaseUnit(PhysicalUnit). An +// example can be found in length-units.h +// LengthBase::GetInBaseUnit. +// Unit is the UnitConversion class that defines a specific unit +// (such as degrees) in terms of a reference unit (such as radians). +template +class PhysicalUnit { + public: + typedef PhysicalUnit Type; + typedef Float FloatType; + + // Use 'explicit' to prevent unintentional construction from untyped (or + // mistyped) values. Note that this also prevents arguably reasonable + // constructs such as Unit unit = 10.0; use either Unit unit(10.0) or + // Unit unit = Unit(10.0) instead. + PhysicalUnit(): value_(static_cast(0.0)) {} + explicit PhysicalUnit(Float value): value_(value) {} + + // Conversion from other units of the same Base type. + // + // Policy decision: not using 'explicit' allows much more natural + // conversions between units of a given base type. This can result in + // unintended implicit type conversions, but these incur very little + // overhead (inlined multiply at -O2) and should be inconsequential in + // most circumstances. Casts between different base types (including + // different underlying value types) require explicit handling. + template + PhysicalUnit(PhysicalUnit other) + : value_(UnitConverter::Convert(other.value())) {} + + // Copy operation from other units of the same Base type. + template + Type operator = (PhysicalUnit other) { + value_ = UnitConverter::Convert(other.value()); + return *this; + } + + // Value accessor. Consider using an explicitly typed accessor whenever + // the unit type is not immediately obvious (such as function return + // values). For example: + // float x = myclass.GetAngle().value(); // what unit is x? + // float x = GetDegrees(myclass.GetAngle()); // much clearer. + // float x = Degrees(myclass.GetAngle()).value(); // ok too. + // Degrees degrees = myclass.GetAngle(); // using a temporary is + // float x = degrees.value(); // also good. + Float value() const { return value_; } + + // Trivial arithematic operator wrapping. + Type operator - () const { + return Type(-value_); + } + Type operator * (const Float scale) const { + return Type(value_ * scale); + } + Type operator + (const Type other) const { + static_assert(is_linear_unit_transformation::value, + "operation not defined"); + return Type(value_ + other.value()); + } + Type operator - (const Type other) const { + static_assert(is_linear_unit_transformation::value, + "operation not defined"); + return Type(value_ - other.value()); + } + Float operator / (const Type other) const { + return value_ / other.value(); + } + Type operator *= (const Float scale) { + value_ *= scale; + return *this; + } + Type operator += (const Type other) { + static_assert(is_linear_unit_transformation::value, + "operation not defined"); + value_ += other.value(); + return *this; + } + Type operator -= (const Type other) { + static_assert(is_linear_unit_transformation::value, + "operation not defined"); + value_ -= other.value(); + return *this; + } + + // Simple comparisons. Overloaded equality is intentionally omitted; + // use equals() instead. + bool operator < (const Type other) const { + return value_ < other.value(); + } + bool operator > (const Type other) const { + return value_ > other.value(); + } + bool operator <= (const Type other) const { + return value_ <= other.value(); + } + bool operator >= (const Type other) const { + return value_ >= other.value(); + } + + // Test equality to within some epsilon. Always false for + // epsilon < 0. + bool equals(const Type other, + const Type epsilon) const { + Float delta = value_ - other.value_; + if (delta < static_cast(0.0)) { + return -delta <= epsilon.value_; + } + return delta <= epsilon.value_; + } + + // A little more sugar. + Type abs() const { + return (value_ < static_cast(0.0)) ? -(*this) : *this; + } + + // Explicit precision casting within a base unit class. + template + PhysicalUnit precision_cast() const { + typedef PhysicalUnit CastType; + return CastType(static_cast(value_)); + } + + private: + Float value_; + // Enforce Float to be a floating point type, since unit conversions will + // generally fail with integers. + // This is COMPILE_ASSERT because static_assert breaks swig in + // maps/roadtraffic/speedextractor/quarantine.swig -- mec, 2013-12-27 + COMPILE_ASSERT(std::is_floating_point::value, + Only_use_floating_point_types); +}; + +// Allow 2*u (in addition to u*2). +template +inline PhysicalUnit operator * ( + const Scale scale, + const PhysicalUnit value) { + return value * static_cast(scale); +} + +// we'll print the current value and the value converted to the natural +// base type +template +std::ostream& operator<<(std::ostream& os, + PhysicalUnit value) { + return os << value.value() + << " (" << Base::GetInBaseUnit(value) + << Base::output_suffix << ")"; +} + +} // end namespace units + +} // end namespace util + +#endif // UTIL_UNITS_PHYSICAL_UNITS_H__ diff --git a/third_party/cmake/FindGFlags.cmake b/third_party/cmake/FindGFlags.cmake new file mode 100644 index 00000000..7df5b067 --- /dev/null +++ b/third_party/cmake/FindGFlags.cmake @@ -0,0 +1,48 @@ +# - Try to find GFLAGS +# +# The following variables are optionally searched for defaults +# GFLAGS_ROOT_DIR: Base directory where all GFLAGS components are found +# +# The following are set after configuration is done: +# GFLAGS_FOUND +# GFLAGS_INCLUDE_DIRS +# GFLAGS_LIBRARIES +# GFLAGS_LIBRARYRARY_DIRS + +include(FindPackageHandleStandardArgs) + +set(GFLAGS_ROOT_DIR "" CACHE PATH "Folder contains Gflags") + +# We are testing only a couple of files in the include directories +if(WIN32) + find_path(GFLAGS_INCLUDE_DIR gflags/gflags.h + PATHS ${GFLAGS_ROOT_DIR}/src/windows) +else() + find_path(GFLAGS_INCLUDE_DIR gflags/gflags.h + PATHS ${GFLAGS_ROOT_DIR}) +endif() + +if(MSVC) + find_library(GFLAGS_LIBRARY_RELEASE + NAMES libgflags + PATHS ${GFLAGS_ROOT_DIR} + PATH_SUFFIXES Release) + + find_library(GFLAGS_LIBRARY_DEBUG + NAMES libgflags-debug + PATHS ${GFLAGS_ROOT_DIR} + PATH_SUFFIXES Debug) + + set(GFLAGS_LIBRARY optimized ${GFLAGS_LIBRARY_RELEASE} debug ${GFLAGS_LIBRARY_DEBUG}) +else() + find_library(GFLAGS_LIBRARY gflags) +endif() + +find_package_handle_standard_args(GFLAGS DEFAULT_MSG + GFLAGS_INCLUDE_DIR GFLAGS_LIBRARY) + + +if(GFLAGS_FOUND) + set(GFLAGS_INCLUDE_DIRS ${GFLAGS_INCLUDE_DIR}) + set(GFLAGS_LIBRARIES ${GFLAGS_LIBRARY}) +endif() diff --git a/third_party/cmake/FindGlog.cmake b/third_party/cmake/FindGlog.cmake new file mode 100644 index 00000000..4b30e60a --- /dev/null +++ b/third_party/cmake/FindGlog.cmake @@ -0,0 +1,48 @@ + +# - Try to find Glog +# +# The following variables are optionally searched for defaults +# GLOG_ROOT_DIR: Base directory where all GLOG components are found +# +# The following are set after configuration is done: +# GLOG_FOUND +# GLOG_INCLUDE_DIRS +# GLOG_LIBRARIES + +include(FindPackageHandleStandardArgs) + +set(GLOG_ROOT_DIR "" CACHE PATH "Folder contains Google glog") + +if(WIN32) + find_path(GLOG_INCLUDE_DIR glog/logging.h + PATHS ${GLOG_ROOT_DIR}/src/windows) +else() + find_path(GLOG_INCLUDE_DIR glog/logging.h + PATHS ${GLOG_ROOT_DIR}) +endif() + +if(MSVC) + find_library(GLOG_LIBRARY_RELEASE libglog_static + PATHS ${GLOG_ROOT_DIR} + PATH_SUFFIXES Release) + + find_library(GLOG_LIBRARY_DEBUG libglog_static + PATHS ${GLOG_ROOT_DIR} + PATH_SUFFIXES Debug) + + set(GLOG_LIBRARY optimized ${GLOG_LIBRARY_RELEASE} debug ${GLOG_LIBRARY_DEBUG}) +else() + find_library(GLOG_LIBRARY glog + PATHS ${GLOG_ROOT_DIR} + PATH_SUFFIXES + lib + lib64) +endif() + +find_package_handle_standard_args(GLOG DEFAULT_MSG + GLOG_INCLUDE_DIR GLOG_LIBRARY) + +if(GLOG_FOUND) + set(GLOG_INCLUDE_DIRS ${GLOG_INCLUDE_DIR}) + set(GLOG_LIBRARIES ${GLOG_LIBRARY}) +endif()