The attached file contains the test for the lib.inner.product algorithm.
With best wishes, Anton Pevtsov
/*************************************************************************** * * 26.inner.product.cpp - test exercising 26.4.2 [lib.inner.product] * * $Id: * *************************************************************************** * * * Copyright 2006 The Apache Software Foundation or its licensors, * as applicable. * * Copyright 2006 Rogue Wave Software. * * 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 <numeric> // for inner_product #include <cstddef> // for size_t #include <alg_test.h> #include <driver.h> // for rw_test() /**************************************************************************/ // plus-assign template <class T> struct plus_asgn: T { plus_asgn& operator+= (const plus_asgn& rhs) { unused = rhs.unused; return *this; } private: // unused member prevents bogus HP aCC warnings (see Onyx #23561) int unused; }; template <class T> const plus_asgn<T>& operator* (const plus_asgn<T>& lhs, const plus_asgn<T>& rhs) { _RWSTD_UNUSED(rhs); return lhs; } _RWSTD_NAMESPACE (std) { // disable explicit instantiation for compilers (like MSVC) // that can't handle it #ifndef _RWSTD_NO_EXPLICIT_INSTANTIATION template plus_asgn<assign<base<cpy_ctor> > > inner_product (InputIter<plus_asgn<assign<base<cpy_ctor> > > >, InputIter<plus_asgn<assign<base<cpy_ctor> > > >, InputIter<plus_asgn<assign<base<cpy_ctor> > > >, plus_asgn<assign<base<cpy_ctor> > >); template assign<base<cpy_ctor> > inner_product (InputIter<assign<base<cpy_ctor> > >, InputIter<assign<base<cpy_ctor> > >, InputIter<assign<base<cpy_ctor> > >, assign<base<cpy_ctor> >, binary_func<assign<base<cpy_ctor> > >, binary_func<assign<base<cpy_ctor> > >); #endif // _RWSTD_NO_EXPLICIT_INSTANTIATION } // namespace std /**************************************************************************/ struct Y: public X { // number of times the object's += and * operators has been invoked, // regardless of whether the operation threw an exception or not std::size_t n_op_plus_assign_; std::size_t n_op_multiple_; static std::size_t n_total_op_plus_assign_; // ... += operators ... static std::size_t n_total_op_multiple_; // ... * operators ... // class thrown from the respective functions struct OpPlusAssign: Exception { }; struct OpMultiple: Exception { }; // throw object's `id' wrapped in the appropriate struct when the // corresponding n_total_xxx_ counter reaches the value pointed to // by the respective pointer below static std::size_t* op_plus_assign_throw_ptr_; static std::size_t* op_multiple_throw_ptr_; // objects to which the pointers above initally point static std::size_t op_plus_assign_throw_count_; static std::size_t op_multiple_throw_count_; Y (): X () { /* empty */ } Y (const Y &rhs): X (rhs) { /* empty */ } Y& operator+= (const Y& rhs) { // verify id validity and uniqueness RW_ASSERT (id_ && id_ <= id_gen_); RW_ASSERT (rhs.id_ && rhs.id_ <= id_gen_); RW_ASSERT (this == &rhs || id_ != rhs.id_); // increment the number of times each distinct object // has been used as the argument to operator+= // (do so even if the function throws an exception below) ++n_op_plus_assign_; if (this != &rhs) ++_RWSTD_CONST_CAST (Y*, &rhs)->n_op_plus_assign_; // increment the total number of invocations of the operator // (do so even if the function throws an exception below) ++n_total_op_plus_assign_; #ifndef _RWSTD_NO_EXCEPTIONS // throw an exception if the number of calls // to operator== reaches the given value if ( op_plus_assign_throw_ptr_ && n_total_op_plus_assign_ == *op_plus_assign_throw_ptr_) { OpPlusAssign ex; ex.id_ = id_; throw ex; } #endif // _RWSTD_NO_EXCEPTIONS val_ += rhs.val_; return *this; } }; /* static */ size_t Y::n_total_op_plus_assign_; /* static */ size_t* Y::op_plus_assign_throw_ptr_ = &Y::op_plus_assign_throw_count_; /* static */ size_t Y::op_plus_assign_throw_count_ = std::size_t (-1); /* static */ size_t Y::n_total_op_multiple_; /* static */ size_t* Y::op_multiple_throw_ptr_ = &Y::op_multiple_throw_count_; /* static */ size_t Y::op_multiple_throw_count_ = std::size_t (-1); /**************************************************************************/ Y operator* (const Y& lhs, const Y& rhs) { // increment the number of times each distinct object // has been used as the argument to operator* // (do so even if the function throws an exception below) ++_RWSTD_CONST_CAST (Y*, &lhs)->n_op_multiple_; if (&lhs != &rhs) ++_RWSTD_CONST_CAST (Y*, &rhs)->n_op_multiple_; // increment the total number of invocations of the operator // (do so even if the function throws an exception below) ++Y::n_total_op_multiple_; #ifndef _RWSTD_NO_EXCEPTIONS // throw an exception if the number of calls // to operator== reaches the given value if ( lhs.op_multiple_throw_ptr_ && Y::n_total_op_multiple_ == *lhs.op_multiple_throw_ptr_) { Y::OpMultiple ex; ex.id_ = lhs.id_; throw ex; } #endif // _RWSTD_NO_EXCEPTIONS Y res(lhs); res.val_ *= rhs.val_; return res; } /**************************************************************************/ template <class T> struct conv_to_T { static conv_to_T make (T val) { return conv_to_T (val); } // strictly convertible to a T value operator T () const { return val_; } private: // not (publicly) Default-Constructible conv_to_T (T val): val_ (val) { } void operator= (conv_to_T); // not Assignable void operator!() const; // not defined T val_; }; /**************************************************************************/ struct Accumulator { static std::size_t funcalls_; // dummy arguments provided to prevent the class from being // default constructible and implicit conversion from int Accumulator (int /* dummy */, int /* dummy */) { funcalls_ = 0; } // return a type convertible to Y conv_to_T<Y> operator() (const Y &x, const Y &y) /* non-const */ { ++funcalls_; Y res (x); res.val_ += y.val_; return conv_to_T<Y>::make (res); } private: void operator= (Accumulator&); // not assignable }; std::size_t Accumulator::funcalls_; struct Multiplicator { static std::size_t funcalls_; // dummy arguments provided to prevent the class from being // default constructible and implicit conversion from int Multiplicator (int /* dummy */, int /* dummy */) { funcalls_ = 0; } // return a type convertible to Y conv_to_T<Y> operator() (const Y &x, const Y &y) /* non-const */ { ++funcalls_; Y res (x); res.val_ *= y.val_; return conv_to_T<Y>::make (res); } private: void operator= (Multiplicator&); // not assignable }; std::size_t Multiplicator::funcalls_; /**************************************************************************/ struct InnerProductBase { virtual ~InnerProductBase() {} const char* iter_names [2]; // pure virtual virtual Y inner_product (const Y *xsrc1, const Y *xsrc1_end, const Y *xsrc2, const Y *xsrc2_end, const Y& init, const Accumulator *op1, const Multiplicator *op2) const = 0; }; template <class InputIterator1, class InputIterator2> struct InnerProduct : InnerProductBase { InnerProduct () { iter_names [0] = type_name (InputIterator1 (0, 0, 0), (Y*)0); iter_names [1] = type_name (InputIterator2 (0, 0, 0), (Y*)0); } virtual ~InnerProduct() {} virtual Y inner_product (const Y *xsrc1, const Y *xsrc1_end, const Y *xsrc2, const Y *xsrc2_end, const Y& init, const Accumulator *op1, const Multiplicator *op2) const { const InputIterator1 first1 (xsrc1, xsrc1, xsrc1_end); const InputIterator1 last1 (xsrc1_end, xsrc1, xsrc1_end); const InputIterator2 first2 (xsrc2, xsrc2, xsrc2_end); const Y res = op1 ? std::inner_product (first1, last1, first2, init, *op1, *op2) : std::inner_product (first1, last1, first2, init); // silence EDG eccp 3.7 and prior remark #550-D: // variable was set but never used _RWSTD_UNUSED (res); return res; } }; /**************************************************************************/ // exercises inner_product (26.4.2) void test_inner_product (const std::size_t N, const InnerProductBase &alg, bool binop) { const char* const it1name = alg.iter_names [0]; const char* const it2name = alg.iter_names [1]; const char* const tname = "Y"; const char* const op1name = "Plus"; const char* const op2name = "Multiple"; rw_info (0, 0, 0, "std::inner_product (%s, %1$s, %s, %s%{?}, %s, %s%{;})", it1name, it2name, tname, binop, op1name, op2name); // construct initial Y const Y init; int sum = init.val_; Y::gen_ = gen_seq; Y* const buf1 = new Y [N]; Y* const buf2 = new Y [N]; for (std::size_t i = 0; i != N; ++i) { Y* const buf1_end = buf1 + i; Y* const buf2_end = buf2 + i; const Accumulator acc (0, 0); const Multiplicator mult (0, 0); const Accumulator* const pbinop1 = binop ? &acc : 0; const Multiplicator* const pbinop2 = binop ? &mult : 0; const Y res = alg.inner_product (buf1, buf1_end, buf2, buf2_end, init, pbinop1, pbinop2); // verify the result 26.4.1, p1 bool success = sum == res.val_; rw_assert (success, 0, __LINE__, "step %zu: inner_product <%s, %s, %s%{?}, %s, %s%{;}> = %u" " expected %u%{?} (%d * %d + %d * %d + ... + %d * %d)%{;}", i + 1, it1name, it2name, tname, binop, op1name, op2name, res.val_, sum, i >= 2, buf1[0].val_, buf2[0].val_, buf1[1].val_, buf2[1].val_, buf1[i].val_, buf2[i].val_); sum += (buf1 [i].val_ * buf2 [i].val_); if (!success) break; } delete[] buf1; delete[] buf2; } /**************************************************************************/ /* extern */ int rw_opt_nloops = 64; // --nloops /* extern */ int rw_opt_no_binary_op; // --no-binary_op /* extern */ int rw_opt_no_input_iter; // --no-InputIterator /* extern */ int rw_opt_no_fwd_iter; // --no-ForwardIterator /* extern */ int rw_opt_no_bidir_iter; // --no-BidirectionalIterator /* extern */ int rw_opt_no_rnd_iter; // --no-RandomAccessIterator /**************************************************************************/ template <class InputIterator1, class InputIterator2> void gen_inner_product_test (const std::size_t N, const InputIterator1&, const InputIterator2&, bool binop) { const InnerProduct<InputIterator1, InputIterator2> alg; test_inner_product (N, alg, binop); } template <class InputIterator1> void gen_inner_product_test (const std::size_t N, const InputIterator1 &it1, bool binop) { if (0 == rw_opt_no_input_iter) gen_inner_product_test ( N, it1, InputIter<Y>(0, 0, 0), binop); if (0 == rw_opt_no_fwd_iter) gen_inner_product_test ( N, it1, ConstFwdIter<Y>(0, 0, 0), binop); if (0 == rw_opt_no_bidir_iter) gen_inner_product_test ( N, it1, ConstBidirIter<Y>(0, 0, 0), binop); if (0 == rw_opt_no_rnd_iter) gen_inner_product_test ( N, it1, ConstRandomAccessIter<Y>(0, 0, 0), binop); } // generates a specialization of the inner_product test for each of the required // iterator categopries void gen_inner_product_test (const std::size_t N, bool binop) { rw_info (0, 0, 0, "template <class %s, class %s, class %s%{?}, class %s, " "class %s%{;}> %3$s inner_product (%1$s, %1$s, %2$s, " "%3$s%{?}, %s, %s%{;})", "InputIterator1", "InputIterator2", "Y", binop, "BinaryOperation1", "BinaryOperation2", binop, "BinaryOperation1", "BinaryOperation2"); if (rw_opt_no_input_iter) rw_note (0, 0, 0, "InputIterator test disabled"); else gen_inner_product_test (N, InputIter<Y>(0, 0, 0), binop); if (rw_opt_no_fwd_iter) rw_note (0, 0, 0, "ForwardIterator test disabled"); else gen_inner_product_test (N, ConstFwdIter<Y>(0, 0, 0), binop); if (rw_opt_no_bidir_iter) rw_note (0, 0, 0, "BidirectionalIterator test disabled"); else gen_inner_product_test (N, ConstBidirIter<Y>(0, 0, 0), binop); if (rw_opt_no_rnd_iter) rw_note (0, 0, 0, "RandomAccessIterator test disabled"); else gen_inner_product_test (N, ConstRandomAccessIter<Y>(0, 0, 0), binop); } /**************************************************************************/ static int run_test (int, char*[]) { const std::size_t N = std::size_t (rw_opt_nloops); gen_inner_product_test (N, false); if (rw_opt_no_binary_op) rw_note (0, 0, 0, "inner_product with binary operations test disabled"); else gen_inner_product_test (N, true); return 0; } /**************************************************************************/ int main (int argc, char *argv[]) { return rw_test (argc, argv, __FILE__, "lib.inner.product", 0 /* no comment */, run_test, "|-nloops#0 " // must be non-negative "|-no-binary_op#" "|-no-InputIterator# " "|-no-ForwardIterator# " "|-no-BidirectionalIterator# " "|-no-RandomAccessIterator#", &rw_opt_nloops, &rw_opt_no_binary_op, &rw_opt_no_input_iter, &rw_opt_no_fwd_iter, &rw_opt_no_bidir_iter, &rw_opt_no_rnd_iter); }
