1+ // Copyright (C) 2016 Daniel C. Dillon
2+ //
3+ // This file is part of RcppHoney.
4+ //
5+ // RcppHoney is free software: you can redistribute it and/or modify it
6+ // under the terms of the GNU General Public License as published by
7+ // the Free Software Foundation, either version 2 of the License, or
8+ // (at your option) any later version.
9+ //
10+ // RcppHoney is distributed in the hope that it will be useful, but
11+ // WITHOUT ANY WARRANTY; without even the implied warranty of
12+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+ // GNU General Public License for more details.
14+ //
15+ // You should have received a copy of the GNU General Public License
16+ // along with RcppHoney. If not, see <http://www.gnu.org/licenses/>.
17+
18+ #pragma once
19+
20+ #include < RcppHoneyForward.hpp>
21+ #include " traits/widest_numeric_type.hpp"
22+ #include " traits/ctype.hpp"
23+ #include " na.hpp"
24+ #include " exceptions.hpp"
25+ #include " scalar_operator.hpp"
26+
27+ namespace RcppHoney {
28+
29+ template < typename LhsIterator, typename RhsIterator, bool NA_VALUE >
30+ class cbinder_result_type {
31+ public:
32+ typedef typename std::iterator_traits< LhsIterator >::value_type lhs_type;
33+ typedef typename std::iterator_traits< RhsIterator >::value_type rhs_type;
34+ typedef typename traits::widest_numeric_type< lhs_type, rhs_type >::type result_type;
35+ };
36+
37+ template < typename LhsIterator, typename RhsIterator, bool NA_VALUE >
38+ class cbinder_iterator :
39+ public std::iterator< std::bidirectional_iterator_tag,
40+ typename cbinder_result_type< LhsIterator, RhsIterator, NA_VALUE >::result_type >{
41+
42+ public:
43+ typedef typename cbinder_result_type< LhsIterator,
44+ RhsIterator, NA_VALUE >::result_type result_type;
45+ typedef typename std::iterator_traits< LhsIterator >::value_type lhs_type;
46+ typedef typename std::iterator_traits< RhsIterator >::value_type rhs_type;
47+
48+ private:
49+ bool m_dirty;
50+ bool m_onLhs;
51+ LhsIterator m_lhsPos;
52+ LhsIterator m_lhsEnd;
53+ RhsIterator m_rhsPos;
54+ RhsIterator m_rhsEnd;
55+ result_type m_value;
56+
57+ public:
58+ inline cbinder_iterator () : m_dirty(true ), m_onLhs(true ) {}
59+
60+ inline cbinder_iterator (const LhsIterator &lhsPos, const LhsIterator &lhsEnd,
61+ const RhsIterator &rhsPos, const RhsIterator &rhsEnd)
62+ : m_dirty(true ), m_onLhs(lhsPos != lhsEnd), m_lhsPos(lhsPos), m_lhsEnd(lhsEnd),
63+ m_rhsPos(rhsPos), m_rhsEnd(rhsEnd) {}
64+
65+ inline result_type operator *() {
66+ if (m_dirty) {
67+ if (m_onLhs) {
68+ if (NA_VALUE) {
69+ lhs_type val = *m_lhsPos;
70+
71+ if (na< typename traits::ctype< lhs_type >::type >::is_na (val)) {
72+ m_value = na< result_type >::VALUE ();
73+ } else {
74+ m_value = val;
75+ }
76+ } else {
77+ m_value = *m_lhsPos;
78+ }
79+ } else {
80+ if (NA_VALUE) {
81+ rhs_type val = *m_rhsPos;
82+
83+ if (na< typename traits::ctype< rhs_type >::type >::is_na (val)) {
84+ m_value = na< result_type >::VALUE ();
85+ } else {
86+ m_value = val;
87+ }
88+ } else {
89+ m_value = *m_rhsPos;
90+ }
91+ }
92+
93+ m_dirty = false ;
94+ }
95+
96+ return m_value;
97+ }
98+
99+ inline cbinder_iterator &operator ++() {
100+ if (m_onLhs) {
101+ ++m_lhsPos;
102+
103+ if (m_lhsPos == m_lhsEnd) {
104+ m_onLhs = false ;
105+ }
106+ } else {
107+ ++m_rhsPos;
108+ }
109+
110+ m_dirty = true ;
111+
112+ return *this ;
113+ }
114+
115+ inline cbinder_iterator operator ++(int ) {
116+ cbinder_iterator i = *this ;
117+ operator ++();
118+ return i;
119+ }
120+
121+ inline cbinder_iterator &operator --() {
122+ if (m_onLhs) {
123+ --m_lhsPos;
124+
125+ if (m_lhsPos == m_lhsEnd) {
126+ m_onLhs = false ;
127+ }
128+ } else {
129+ --m_rhsPos;
130+ }
131+
132+ m_dirty = true ;
133+
134+ return *this ;
135+ }
136+
137+ inline cbinder_iterator operator --(int ) {
138+ cbinder_iterator i = *this ;
139+ operator --();
140+ return this ;
141+ }
142+
143+ inline bool operator ==(const cbinder_iterator &rhs) const {
144+ if (m_onLhs) {
145+ return m_lhsPos == rhs.m_lhsPos ;
146+ } else {
147+ return m_rhsPos == rhs.m_rhsPos ;
148+ }
149+ }
150+
151+ inline bool operator !=(const cbinder_iterator &rhs) const {
152+ return !operator ==(rhs);
153+ }
154+ };
155+
156+ template < typename LhsIterator, typename RhsIterator, bool NA_VALUE >
157+ class cbinder : public operand < cbinder< LhsIterator, RhsIterator, NA_VALUE >,
158+ cbinder_iterator< LhsIterator, RhsIterator, NA_VALUE >,
159+ typename cbinder_result_type< LhsIterator, RhsIterator, NA_VALUE >::result_type > {
160+
161+ public:
162+ typedef cbinder_iterator< LhsIterator, RhsIterator, NA_VALUE > const_iterator;
163+ typedef const_iterator iterator;
164+ typedef typename cbinder_result_type< LhsIterator, RhsIterator, NA_VALUE >::result_type result_type;
165+ static const bool NA = NA_VALUE;
166+
167+ private:
168+ LhsIterator m_lhsBegin;
169+ LhsIterator m_lhsEnd;
170+ RhsIterator m_rhsBegin;
171+ RhsIterator m_rhsEnd;
172+ dims_t m_dims;
173+
174+ public:
175+ cbinder (LhsIterator lhsBegin, LhsIterator lhsEnd, dims_t lhsDims,
176+ RhsIterator rhsBegin, RhsIterator rhsEnd, dims_t rhsDims) :
177+ m_lhsBegin (lhsBegin), m_lhsEnd(lhsEnd), m_rhsBegin(rhsBegin),
178+ m_rhsEnd (rhsEnd) {
179+
180+ if (lhsDims.first == -1 ) {
181+ if (rhsDims.first > 0 ) {
182+ m_dims.first = rhsDims.first
183+ + ((rhsDims.second == 0 ) ? 1 : rhsDims.second );
184+ } else {
185+ throw bounds_exception ();
186+ }
187+ } else if (rhsDims.first == -1 ) {
188+ if (lhsDims.first > 0 ) {
189+ m_dims.first = lhsDims.first
190+ + ((lhsDims.second == 0 ) ? 1 : lhsDims.second );
191+ } else {
192+ throw bounds_exception ();
193+ }
194+ } else if (lhsDims.second == 0 && rhsDims.second == 0 ) {
195+ if (lhsDims.first == rhsDims.first ) {
196+ m_dims.first = lhsDims.first ;
197+ m_dims.second = 2 ;
198+ } else {
199+ throw bounds_exception ();
200+ }
201+ }
202+ else if (lhsDims.second == 0 ) {
203+ if (lhsDims.first == rhsDims.first ) {
204+ m_dims.first = lhsDims.first ;
205+ m_dims.second = rhsDims.second + 1 ;
206+ } else {
207+ throw bounds_exception ();
208+ }
209+ } else if (rhsDims.second == 0 ) {
210+ if (lhsDims.first == rhsDims.first ) {
211+ m_dims.first = lhsDims.first ;
212+ m_dims.second = lhsDims.second + 1 ;
213+ } else {
214+ throw bounds_exception ();
215+ }
216+ } else if (lhsDims.first == rhsDims.first ) {
217+ m_dims.first = lhsDims.first ;
218+ m_dims.second = lhsDims.second + rhsDims.second ;
219+ } else {
220+ throw bounds_exception ();
221+ }
222+ }
223+
224+ dims_t dims () const {return m_dims;}
225+ int64_t size () const {
226+ return (m_dims.second != 0 ) ? m_dims.first * m_dims.second
227+ : m_dims.first ;
228+ }
229+
230+ const_iterator begin () const {
231+ return const_iterator (m_lhsBegin, m_lhsEnd, m_rhsBegin, m_rhsEnd);
232+ }
233+
234+ const_iterator end () const {
235+ return const_iterator (m_lhsEnd, m_lhsEnd, m_rhsEnd, m_rhsEnd);
236+ }
237+ };
238+
239+ template < bool NA >
240+ struct make_cbinder
241+ {
242+ template < typename LHS, typename RHS >
243+ cbinder< typename LHS::const_iterator, typename RHS::const_iterator, NA >
244+ operator ()(const LHS &lhs, const RHS &rhs) {
245+
246+ return cbinder< typename LHS::const_iterator, typename RHS::const_iterator, NA >(
247+ lhs.begin (), lhs.end (), hooks::extract_dims (lhs),
248+ rhs.begin (), rhs.end (), hooks::extract_dims (rhs));
249+ }
250+ };
251+
252+ template < typename T, typename T_ITER, typename T_RESULT, typename U,
253+ typename U_ITER, typename U_RESULT >
254+ RcppHoney::cbinder< T_ITER, U_ITER, (T::NA || U::NA) >
255+ cbind (const RcppHoney::operand< T, T_ITER, T_RESULT > &lhs,
256+ const RcppHoney::operand< U, U_ITER, U_RESULT > &rhs) {
257+ return RcppHoney::make_cbinder< (T::NA || U::NA) >()(lhs, rhs);
258+ }
259+ template < typename T, typename T_ITER, typename T_RESULT, typename U >
260+ typename RcppHoney::traits::enable_if< RcppHoney::traits::is_primitive< U >::value,
261+ RcppHoney::cbinder< T_ITER, typename RcppHoney::scalar_operator< U >::const_iterator, T::NA >
262+ >::type
263+ cbind (const RcppHoney::operand< T, T_ITER, T_RESULT > &lhs, const U &rhs) {
264+ return RcppHoney::make_cbinder< T::NA >()(lhs, RcppHoney::make_scalar_operator ()(rhs, lhs.dims ().first ));
265+ }
266+ template < typename T, typename U, typename U_ITER, typename U_RESULT >
267+ typename RcppHoney::traits::enable_if< RcppHoney::traits::is_primitive< T >::value,
268+ RcppHoney::cbinder< typename RcppHoney::scalar_operator< T >::const_iterator, U_ITER, U::NA >
269+ >::type
270+ cbind (const T &lhs, const RcppHoney::operand< U, U_ITER, U_RESULT > &rhs) {
271+ return RcppHoney::make_cbinder< U::NA >()(RcppHoney::make_scalar_operator ()(lhs, rhs.dims ().first ), rhs);
272+ }
273+ template < typename T, typename U >
274+ typename RcppHoney::traits::enable_if<
275+ (RcppHoney::hook< T >::value && RcppHoney::hook< U >::value),
276+ RcppHoney::cbinder<
277+ typename RcppHoney::hook< T >::const_iterator,
278+ typename RcppHoney::hook< U >::const_iterator,
279+ (RcppHoney::hook< T >::NA || RcppHoney::hook< U >::NA)
280+ >
281+ >::type
282+ cbind (const T &lhs, const U &rhs) {
283+ return RcppHoney::make_cbinder< (RcppHoney::hook< T >::NA || RcppHoney::hook< U >::NA) >()(
284+ lhs,
285+ rhs);
286+ }
287+ template < typename T, typename T_ITER, typename T_RESULT, typename U >
288+ typename RcppHoney::traits::enable_if< RcppHoney::hook< U >::value,
289+ RcppHoney::cbinder<
290+ T_ITER,
291+ typename RcppHoney::hook< U >::const_iterator,
292+ (T::NA || RcppHoney::hook< U >::NA)
293+ >
294+ >::type
295+ cbind (const RcppHoney::operand< T, T_ITER, T_RESULT > &lhs, const U &rhs) {
296+ return RcppHoney::make_cbinder< (T::NA || RcppHoney::hook< U >::NA) >()(
297+ lhs,
298+ rhs);
299+ }
300+ template < typename T, typename U, typename U_ITER, typename U_RESULT >
301+ typename RcppHoney::traits::enable_if< RcppHoney::hook< T >::value,
302+ RcppHoney::cbinder<
303+ typename RcppHoney::hook< T >::const_iterator,
304+ U_ITER,
305+ (U::NA || RcppHoney::hook< T >::NA)
306+ >
307+ >::type
308+ cbind (const T &lhs, const RcppHoney::operand< U, U_ITER, U_RESULT > &rhs) {
309+ return RcppHoney::make_cbinder< (U::NA || RcppHoney::hook< T >::NA) >()(
310+ lhs,
311+ rhs);
312+ }
313+ template < typename T, typename U >
314+ typename RcppHoney::traits::enable_if<
315+ RcppHoney::traits::is_primitive< T >::value
316+ && RcppHoney::hook< U >::value,
317+ RcppHoney::cbinder<
318+ typename RcppHoney::scalar_operator< T >::const_iterator,
319+ typename RcppHoney::hook< U >::const_iterator,
320+ RcppHoney::hook< U >::NA
321+ >
322+ >::type
323+ cbind (const T &lhs, const U &rhs) {
324+ dims_t dims = RcppHoney::hooks::extract_dims (rhs);
325+ return RcppHoney::make_cbinder< RcppHoney::hook< U >::NA >()(
326+ RcppHoney::make_scalar_operator ()(lhs, dims.first ),
327+ rhs);
328+ }
329+ template < typename T, typename U >
330+ typename RcppHoney::traits::enable_if<
331+ RcppHoney::traits::is_primitive< U >::value
332+ && RcppHoney::hook< T >::value,
333+ RcppHoney::cbinder<
334+ typename RcppHoney::hook< T >::const_iterator,
335+ typename RcppHoney::scalar_operator< U >::const_iterator,
336+ RcppHoney::hook< T >::NA
337+ >
338+ >::type
339+ cbind (const T &lhs, const U &rhs) {
340+ dims_t dims = RcppHoney::hooks::extract_dims (lhs);
341+ return RcppHoney::make_cbinder< RcppHoney::hook< T >::NA >()(
342+ lhs,
343+ RcppHoney::make_scalar_operator ()(rhs, dims.first ));
344+ }
345+
346+ } // namespace RcppHoney
0 commit comments