CXXR (C++ R) API
BinaryFunction.hpp
Go to the documentation of this file.
1 /*CXXR $Id: BinaryFunction.hpp 1353 2013-03-18 16:59:38Z arr $
2  *CXXR
3  *CXXR This file is part of CXXR, a project to refactor the R interpreter
4  *CXXR into C++. It may consist in whole or in part of program code and
5  *CXXR documentation taken from the R project itself, incorporated into
6  *CXXR CXXR (and possibly MODIFIED) under the terms of the GNU General Public
7  *CXXR Licence.
8  *CXXR
9  *CXXR CXXR is Copyright (C) 2008-13 Andrew R. Runnalls, subject to such other
10  *CXXR copyrights and copyright restrictions as may be stated below.
11  *CXXR
12  *CXXR CXXR is not part of the R project, and bugs and other issues should
13  *CXXR not be reported via r-bugs or other R project channels; instead refer
14  *CXXR to the CXXR website.
15  *CXXR */
16 
17 /*
18  * R : A Computer Language for Statistical Data Analysis
19  *
20  * This program is free software; you can redistribute it and/or modify
21  * it under the terms of the GNU General Public License as published by
22  * the Free Software Foundation; either version 2.1 of the License, or
23  * (at your option) any later version.
24  *
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28  * GNU Lesser General Public License for more details.
29  *
30  * You should have received a copy of the GNU General Public License
31  * along with this program; if not, a copy is available at
32  * http://www.r-project.org/Licenses/
33  */
34 
40 #ifndef BINARYFUNCTION_HPP
41 #define BINARYFUNCTION_HPP 1
42 
43 #include "CXXR/VectorBase.h"
44 #include "CXXR/errors.h"
45 
46 namespace CXXR {
53  namespace VectorOps {
78  void checkOperandsConformable(const VectorBase* vl,
79  const VectorBase* vr);
80 
120  public:
130  static void copyAttributes(VectorBase* vout,
131  const VectorBase* vl,
132  const VectorBase* vr)
133  {
134  if (!vl->attributes() && !vr->attributes())
135  return;
136  apply(vout, vl, vr);
137  }
138  private:
139  // Deal with non-trivial cases:
140  static void apply(VectorBase* vout,
141  const VectorBase* vl,
142  const VectorBase* vr);
143  };
144 
184  template <typename first_argument_type,
185  typename second_argument_type,
186  typename result_type,
187  typename Functor>
189  : public std::binary_function<first_argument_type,
190  second_argument_type,
191  result_type> {
192  public:
199  BinaryNAPropagator(const Functor& f)
200  : m_func(f)
201  {}
202 
220  result_type operator()(const first_argument_type& left,
221  const second_argument_type& right) const
222  {
223  return (isNA(left) || isNA(right)
224  ? NA<result_type>()
225  : result_type((m_func)(ElementTraits::data(left),
226  ElementTraits::data(right))));
227  }
228 
245  void warnings()
246  {}
247  private:
248  Functor m_func;
249  };
250 
276  template <typename first_argument_type,
277  typename second_argument_type,
278  typename result_type,
279  typename Functor>
281  : public std::binary_function<first_argument_type,
282  second_argument_type,
283  result_type> {
284  public:
291  NullBinaryFunctorWrapper(const Functor& f)
292  : m_func(f)
293  {}
294 
304  result_type operator()(const first_argument_type& left,
305  const second_argument_type& right) const
306  {
307  return (m_func)(ElementTraits::data(left),
308  ElementTraits::data(right));
309  }
310 
315  void warnings()
316  {}
317  private:
318  Functor m_func;
319  };
320 
363  template <typename Functor,
364  class AttributeCopier = GeneralBinaryAttributeCopier,
365  template <typename, typename,
366  typename, typename> class FunctorWrapper
367  = BinaryNAPropagator>
369  public:
377  BinaryFunction(const Functor& f = Functor())
378  : m_f(f)
379  {}
380 
404  template <class Vout, class Vl, class Vr>
405  Vout* apply(const Vl* vl, const Vr* vr) const;
406  private:
407  Functor m_f;
408 
409  // This is called by apply() to calculate the elements of
410  // the result, with 'flag' set as follows: -1 if the first
411  // operand is shorter, 0 if the operands are of equal
412  // length, or +1 if the second operand is shorter.
413  template <int flag, class Vout, class Vl, class Vr>
414  void mapElements(Vout* vout, const Vl* vl, const Vr* vr) const;
415  };
416 
444  template <class AttributeCopier,
445  template <typename, typename,
446  typename, typename> class FunctorWrapper,
447  typename Functor>
448  static BinaryFunction<Functor, AttributeCopier, FunctorWrapper>
449  makeBinaryFunction(Functor f)
450  {
451  return BinaryFunction<Functor, AttributeCopier, FunctorWrapper>(f);
452  }
453 
476  template <class AttributeCopier, typename Functor>
477  static BinaryFunction<Functor, AttributeCopier>
478  makeBinaryFunction(Functor f)
479  {
480  return BinaryFunction<Functor, AttributeCopier>(f);
481  }
482  } // namespace VectorOps
483 } // namespace CXXR
484 
485 
486 // ***** Implementations of non-inlined templated functions. *****
487 
488 template <typename Functor, class AttributeCopier,
489  template <typename, typename,
490  typename, typename> class FunctorWrapper>
491 template <class Vout, class Vl, class Vr>
492 Vout* CXXR::VectorOps::BinaryFunction<Functor,
493  AttributeCopier,
494  FunctorWrapper>::apply(const Vl* vl,
495  const Vr* vr) const
496 {
497  checkOperandsConformable(vl, vr);
498  std::size_t lsize = vl->size();
499  std::size_t rsize = vr->size();
500  GCStackRoot<Vout> ans;
501  if (lsize == 0 || rsize == 0) {
502  ans = CXXR_NEW(Vout(0));
503  } else if (lsize == rsize) {
504  ans = CXXR_NEW(Vout(lsize));
505  mapElements<0>(ans.get(), vl, vr);
506  } else if (lsize > rsize) {
507  ans = CXXR_NEW(Vout(lsize));
508  mapElements<1>(ans.get(), vl, vr);
509  } else {
510  ans = CXXR_NEW(Vout(rsize));
511  mapElements<-1>(ans.get(), vl, vr);
512  }
513  AttributeCopier::copyAttributes(ans, vl, vr);
514  return ans;
515 }
516 
517 template <typename Functor, class AttributeCopier,
518  template <typename, typename,
519  typename, typename> class FunctorWrapper>
520 template <int flag, class Vout, class Vl, class Vr>
521 void CXXR::VectorOps::BinaryFunction<Functor,
522  AttributeCopier,
523  FunctorWrapper>::mapElements(Vout* vout,
524  const Vl* vl,
525  const Vr* vr) const
526 {
527  typedef typename Vl::value_type Lelt;
528  typedef typename Vl::const_iterator Lit;
529  typedef typename Vr::value_type Relt;
530  typedef typename Vr::const_iterator Rit;
531  typedef typename Vout::value_type Oelt;
532  typedef typename Vout::iterator Oit;
533  FunctorWrapper<Lelt, Relt, Oelt, Functor> fwrapper(m_f);
534  Lit lit = vl->begin();
535  Lit lend = vl->end();
536  Rit rit = vr->begin();
537  Rit rend = vr->end();
538  Oit oend = vout->end();
539  for (Oit oit = vout->begin(); oit != oend; ++oit) {
540  *oit = fwrapper(*lit++, *rit++);
541  if (flag < 0 && lit == lend)
542  lit = vl->begin();
543  if (flag > 0 && rit == rend)
544  rit = vr->begin();
545  }
546  if ((flag < 0 && lit != vl->begin())
547  || (flag > 0 && rit != vr->begin()))
548  Rf_warning(_("longer object length is not"
549  " a multiple of shorter object length"));
550  fwrapper.warnings();
551 }
552 
553 #endif // BINARYFUNCTION_HPP