diff options
author | zhanyong.wan <zhanyong.wan@8415998a-534a-0410-bf83-d39667b30386> | 2009-06-04 05:48:20 +0000 |
---|---|---|
committer | zhanyong.wan <zhanyong.wan@8415998a-534a-0410-bf83-d39667b30386> | 2009-06-04 05:48:20 +0000 |
commit | b82431625d1842d1498f3c0e6f1923ce81837c6e (patch) | |
tree | 3d89cbedefd32bf7b2fc76fdf4e0312c206bb0a0 /include/gmock/internal/gmock-internal-utils.h | |
parent | c2ad46a5df4414fc2b804c53525f4578f01a3dfe (diff) | |
download | googletest-b82431625d1842d1498f3c0e6f1923ce81837c6e.tar.gz googletest-b82431625d1842d1498f3c0e6f1923ce81837c6e.tar.bz2 googletest-b82431625d1842d1498f3c0e6f1923ce81837c6e.zip |
Makes all container matchers work with (possibly multi-dimensional) native arrays; makes Contains() accept a matcher; adds Value(x, m); improves gmock doctor to diagnose the Type in Template Base disease.
Diffstat (limited to 'include/gmock/internal/gmock-internal-utils.h')
-rw-r--r-- | include/gmock/internal/gmock-internal-utils.h | 247 |
1 files changed, 243 insertions, 4 deletions
diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index b5e38db3..ee6aa1e2 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -99,6 +99,17 @@ struct RemoveConst { typedef T type; }; // NOLINT template <typename T> struct RemoveConst<const T> { typedef T type; }; // NOLINT +// MSVC 8.0 has a bug which causes the above definition to fail to +// remove the const in 'const int[3]'. The following specialization +// works around the bug. However, it causes trouble with gcc and thus +// needs to be conditionally compiled. +#ifdef _MSC_VER +template <typename T, size_t N> +struct RemoveConst<T[N]> { + typedef typename RemoveConst<T>::type type[N]; +}; +#endif // _MSC_VER + // A handy wrapper around RemoveConst that works when the argument // T depends on template parameters. #define GMOCK_REMOVE_CONST_(T) \ @@ -451,10 +462,6 @@ bool LogIsVisible(LogSeverity severity); // conservative. void Log(LogSeverity severity, const string& message, int stack_frames_to_skip); -// The universal value printer (public/gmock-printers.h) needs this -// to declare an unused << operator in the global namespace. -struct Unused {}; - // TODO(wan@google.com): group all type utilities together. // Type traits. @@ -482,6 +489,238 @@ inline T Invalid() { template <> inline void Invalid<void>() {} +// 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 <typename T, typename U> +bool ArrayEq(const T* lhs, size_t size, const U* rhs); + +// This generic version is used when k is 0. +template <typename T, typename U> +inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } + +// This overload is used when k >= 1. +template <typename T, typename U, size_t N> +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 <typename T, typename U> +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 <typename Iter, typename Element> +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 <typename T, typename U> +void CopyArray(const T* from, size_t size, U* to); + +// This generic version is used when k is 0. +template <typename T, typename U> +inline void CopyArray(const T& from, U* to) { *to = from; } + +// This overload is used when k >= 1. +template <typename T, typename U, size_t N> +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 <typename T, typename U> +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. +enum RelationToSource { + kReference, // The NativeArray references the native array. + kCopy // The NativeArray makes a copy of the native array and + // owns the copy. +}; + +// 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 <typename Element> +class NativeArray { + public: + // STL-style container typedefs. + typedef Element value_type; + typedef const Element* const_iterator; + + // Constructs from a native array passed by reference. + template <size_t N> + NativeArray(const Element (&array)[N], RelationToSource relation) { + Init(array, N, relation); + } + + // Constructs from a native array passed by a pointer and a size. + // For generality we don't artificially restrict the types of the + // pointer and the size. + template <typename Pointer, typename Size> + NativeArray(const ::std::tr1::tuple<Pointer, Size>& array, + RelationToSource relation) { + Init(internal::GetRawPointer(::std::tr1::get<0>(array)), + ::std::tr1::get<1>(array), + relation); + } + + // Copy constructor. + NativeArray(const NativeArray& rhs) { + Init(rhs.array_, rhs.size_, rhs.relation_to_source_); + } + + ~NativeArray() { + // Ensures that the user doesn't instantiate NativeArray with a + // const or reference type. + testing::StaticAssertTypeEq<Element, + GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Element))>(); + if (relation_to_source_ == kCopy) + 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: + // Not implemented as we don't want to support assignment. + void operator=(const NativeArray& rhs); + + // Initializes this object; makes a copy of the input array if + // 'relation' is kCopy. + void Init(const Element* array, size_t size, RelationToSource relation) { + if (relation == kReference) { + array_ = array; + } else { + Element* const copy = new Element[size]; + CopyArray(array, size, copy); + array_ = copy; + } + size_ = size; + relation_to_source_ = relation; + } + + const Element* array_; + size_t size_; + RelationToSource relation_to_source_; +}; + +// Given a raw type (i.e. having no top-level reference or const +// modifier) RawContainer that's either an STL-style container or a +// native array, class StlContainerView<RawContainer> has the +// following members: +// +// - type is a type that provides an STL-style container view to +// (i.e. implements the STL container concept for) RawContainer; +// - const_reference is a type that provides a reference to a const +// RawContainer; +// - ConstReference(raw_container) returns a const reference to an STL-style +// container view to raw_container, which is a RawContainer. +// - Copy(raw_container) returns an STL-style container view of a +// copy of raw_container, which is a RawContainer. +// +// This generic version is used when RawContainer itself is already an +// STL-style container. +template <class RawContainer> +class StlContainerView { + public: + typedef RawContainer type; + typedef const type& const_reference; + + static const_reference ConstReference(const RawContainer& container) { + // Ensures that RawContainer is not a const type. + testing::StaticAssertTypeEq<RawContainer, + GMOCK_REMOVE_CONST_(RawContainer)>(); + return container; + } + static type Copy(const RawContainer& container) { return container; } +}; + +// This specialization is used when RawContainer is a native array type. +template <typename Element, size_t N> +class StlContainerView<Element[N]> { + public: + typedef GMOCK_REMOVE_CONST_(Element) RawElement; + typedef internal::NativeArray<RawElement> type; + // NativeArray<T> can represent a native array either by value or by + // reference (selected by a constructor argument), so 'const type' + // can be used to reference a const native array. We cannot + // 'typedef const type& const_reference' here, as that would mean + // ConstReference() has to return a reference to a local variable. + typedef const type const_reference; + + static const_reference ConstReference(const Element (&array)[N]) { + // Ensures that Element is not a const type. + testing::StaticAssertTypeEq<Element, RawElement>(); + return type(array, kReference); + } + static type Copy(const Element (&array)[N]) { + return type(array, kCopy); + } +}; + +// This specialization is used when RawContainer is a native array +// represented as a (pointer, size) tuple. +template <typename ElementPointer, typename Size> +class StlContainerView< ::std::tr1::tuple<ElementPointer, Size> > { + public: + typedef GMOCK_REMOVE_CONST_( + typename internal::PointeeOf<ElementPointer>::type) RawElement; + typedef internal::NativeArray<RawElement> type; + typedef const type const_reference; + + static const_reference ConstReference( + const ::std::tr1::tuple<ElementPointer, Size>& array) { + return type(array, kReference); + } + static type Copy(const ::std::tr1::tuple<ElementPointer, Size>& array) { + return type(array, kCopy); + } +}; + +// The following specialization prevents the user from instantiating +// StlContainer with a reference type. +template <typename T> class StlContainerView<T&>; + } // namespace internal } // namespace testing |