Skip to content

Commit 2e834e6

Browse files
authored
Merge pull request #23 from dcdillon/feature/cbind
Added cbind and a new class of "functions"
2 parents 2fc17d5 + 3a8a1d9 commit 2e834e6

6 files changed

Lines changed: 541 additions & 10 deletions

File tree

inst/include/RcppHoney.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919

2020
#include "RcppHoneyForward.hpp"
2121
#include <Rcpp.h>
22+
#include "RcppHoney/hook.hpp"
23+
#include "RcppHoney/bind.hpp"
2224
#include "RcppHoney/operators.hpp"
2325
#include "RcppHoney/functions.hpp"
2426
#include "RcppHoney/storage.hpp"
27+

inst/include/RcppHoney/bind.hpp

Lines changed: 346 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
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

Comments
 (0)