PageRenderTime 55ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/src/merge.c

https://github.com/R-Finance/xts
C | 1238 lines | 1012 code | 77 blank | 149 comment | 165 complexity | 264cbdd119727acfbf1076419073fd4f MD5 | raw file
  1. /*
  2. # xts: eXtensible time-series
  3. #
  4. # Copyright (C) 2008 Jeffrey A. Ryan jeff.a.ryan @ gmail.com
  5. #
  6. # Contributions from Joshua M. Ulrich
  7. #
  8. # This program is free software: you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License as published by
  10. # the Free Software Foundation, either version 3 of the License, or
  11. # (at your option) any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License
  19. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #include <R.h>
  22. #include <Rinternals.h>
  23. #include <Rdefines.h>
  24. #include "xts.h"
  25. /*
  26. This is a merge_join algorithm used to
  27. allow two xts objects to be merged as one
  28. along a common index efficiently and fast
  29. The code is branched for REAL and INTEGER indexed values
  30. which allows for efficient memory usage and minimal
  31. testing/coercion
  32. Copyright Jeffrey A. Ryan 2008
  33. */
  34. /* do_merge_xts {{{ */
  35. SEXP do_merge_xts (SEXP x, SEXP y,
  36. SEXP all,
  37. SEXP fill,
  38. SEXP retclass,
  39. SEXP colnames,
  40. SEXP suffixes,
  41. SEXP retside,
  42. SEXP env,
  43. int coerce)
  44. {
  45. int nrx, ncx, nry, ncy, len;
  46. int left_join, right_join;
  47. int i = 0, j = 0, xp = 1, yp = 1; /* x and y positions in index */
  48. int mode;
  49. int ij_original, ij_result;
  50. int p = 0;
  51. SEXP xindex, yindex, index, result, attr, len_xindex;
  52. SEXP s, t, unique;
  53. int *int_result=NULL, *int_x=NULL, *int_y=NULL, int_fill=0;
  54. int *int_index=NULL, *int_xindex=NULL, *int_yindex=NULL;
  55. double *real_result=NULL, *real_x=NULL, *real_y=NULL;
  56. double *real_index=NULL, *real_xindex=NULL, *real_yindex=NULL;
  57. /* we do not check that 'x' is an xts object. Dispatch and mergeXts
  58. (should) make this unecessary. So we just get the index value
  59. This assumption seems to be invalid when dispatched from cbind.xts
  60. So we need to check that the objects are not NULL, or at least
  61. treat NULL objects as zero-width with an index that matches the non-null
  62. 2009/01/07: calling merge(NA,x) or merge(1,1,xts) causes a segfault;
  63. calling merge(1,x) causes the xts-info (none!) from the 1st arg
  64. to be used, resulting in a classless object. [fixed - jar]
  65. */
  66. if( isNull(x) || isNull(y) ) {
  67. if(!isNull(x)) return(x);
  68. return(y);
  69. }
  70. PROTECT( xindex = getAttrib(x, install("index")) );
  71. /* convert to xts object if needed */
  72. if( !isXts(y) ) {
  73. PROTECT(s = t = allocList(4)); p++;
  74. SET_TYPEOF(s, LANGSXP);
  75. SETCAR(t, install("try.xts")); t = CDR(t);
  76. SETCAR(t, y); t = CDR(t);
  77. PROTECT( len_xindex = allocVector(INTSXP, 1)); p++;
  78. INTEGER(len_xindex)[0] = length(xindex);
  79. SETCAR(t, len_xindex);
  80. SET_TAG(t, install("length.out")); t = CDR(t);
  81. SETCAR(t, install(".merge.xts.scalar"));
  82. SET_TAG(t, install("error"));
  83. PROTECT(y = eval(s, env)); p++;
  84. } /* end conversion process */
  85. mode = TYPEOF(x);
  86. if( isXts(y) ) {
  87. PROTECT( yindex = getAttrib(y, xts_IndexSymbol) );
  88. } else {
  89. PROTECT( yindex = getAttrib(x, xts_IndexSymbol) );
  90. }
  91. if( TYPEOF(retside) != LGLSXP )
  92. error("retside must be a logical value of TRUE or FALSE");
  93. nrx = nrows(x);
  94. ncx = ncols(x);
  95. /* if object is zero-width */
  96. if( LENGTH(x)==0 || INTEGER(retside)[0]==0 ) {
  97. nrx = nrows(xindex);
  98. ncx = 0;
  99. }
  100. nry = nrows(y);
  101. ncy = ncols(y);
  102. /* if object is zero-width */
  103. if( LENGTH(y)==0 || INTEGER(retside)[1]==0) {
  104. nry = nrows(yindex);
  105. ncy = 0;
  106. }
  107. len = nrx + nry;
  108. /* at present we are failing the call if the indexing is of
  109. mixed type. This should probably instead simply coerce
  110. to REAL so as not to lose any information (at the expense
  111. of conversion cost and memory), and issue a warning. */
  112. if( TYPEOF(xindex) != TYPEOF(yindex) )
  113. {
  114. PROTECT(xindex = coerceVector(xindex, REALSXP)); p++;
  115. PROTECT(yindex = coerceVector(yindex, REALSXP)); p++;
  116. }
  117. if( TYPEOF(all) != LGLSXP )
  118. error("all must be a logical value of TRUE or FALSE");
  119. left_join = INTEGER(all)[ 0 ];
  120. right_join = INTEGER(all)[ 1 ];
  121. /* determine num_rows of final merged xts object
  122. this seems to only cost 1/1000 of a sec per
  123. 1e6 observations. Acceptable 'waste' given
  124. that now we can properly allocate space
  125. for our results
  126. We also check the index type and use the appropriate macros
  127. */
  128. if( TYPEOF(xindex) == REALSXP ) {
  129. real_xindex = REAL(xindex);
  130. real_yindex = REAL(yindex);
  131. while( (xp + yp) <= (len + 1) ) {
  132. if( xp > nrx ) {
  133. yp++;
  134. if(right_join) i++;
  135. } else
  136. if( yp > nry ) {
  137. xp++;
  138. if(left_join) i++;
  139. } else
  140. if( real_xindex[ xp-1 ] == real_yindex[ yp-1 ] ) {
  141. /* INNER JOIN --- only result if all=FALSE */
  142. yp++;
  143. xp++;
  144. i++;
  145. } else
  146. if( real_xindex[ xp-1 ] < real_yindex[ yp-1 ] ) {
  147. /* LEFT JOIN */
  148. xp++;
  149. if(left_join) i++;
  150. } else
  151. if( real_xindex[ xp-1 ] > real_yindex[ yp-1 ] ) {
  152. /* RIGHT JOIN */
  153. yp++;
  154. if(right_join) i++;
  155. } else
  156. if(ISNA(real_xindex[ xp-1 ]) || ISNA(real_yindex[ yp-1 ])) {
  157. Rprintf("%f, %f\n",real_xindex[xp-1],real_yindex[yp-1]);
  158. error("'NA' not allowed in 'index'");
  159. }
  160. }
  161. } else
  162. if( TYPEOF(xindex) == INTSXP ) {
  163. int_xindex = INTEGER(xindex);
  164. int_yindex = INTEGER(yindex);
  165. while( (xp + yp) <= (len + 1) ) {
  166. if( xp > nrx ) {
  167. yp++;
  168. if(right_join) i++;
  169. } else
  170. if( yp > nry ) {
  171. xp++;
  172. if(left_join) i++;
  173. } else
  174. if( int_xindex[ xp-1 ] == int_yindex[ yp-1 ] ) {
  175. yp++;
  176. xp++;
  177. i++;
  178. } else
  179. if( int_xindex[ xp-1 ] < int_yindex[ yp-1 ] ) {
  180. xp++;
  181. if(left_join) i++;
  182. } else
  183. if( int_xindex[ xp-1 ] > int_yindex[ yp-1 ] ) {
  184. yp++;
  185. if(right_join) i++;
  186. } else
  187. if(real_xindex[ xp-1 ]==NA_INTEGER ||
  188. real_yindex[ yp-1 ]==NA_INTEGER) {
  189. error("'NA' not allowed in 'index'");
  190. }
  191. }
  192. }
  193. if(i == 0) {
  194. /* if no rows match, return an empty xts object, similar in style to zoo */
  195. PROTECT( result = allocVector(TYPEOF(x), 0) ); p++;
  196. PROTECT( index = allocVector(TYPEOF(xindex), 0) ); p++;
  197. SET_xtsIndex(result, index);
  198. if(LOGICAL(retclass)[0])
  199. setAttrib(result, R_ClassSymbol, getAttrib(x, R_ClassSymbol));
  200. UNPROTECT(2 + p);
  201. return result;
  202. }
  203. int num_rows = i;
  204. xp = 1; yp = 1;
  205. PROTECT( index = allocVector(TYPEOF(xindex), num_rows) );
  206. /* coercion/matching of TYPE for x and y needs to be checked,
  207. either here or in the calling R code. I suspect here is
  208. more useful if other function can call the C code as well.
  209. If objects are not the same type, convert to REALSXP. */
  210. if( coerce || TYPEOF(x) != TYPEOF(y) ) {
  211. PROTECT( x = coerceVector(x, REALSXP) ); p++;
  212. PROTECT( y = coerceVector(y, REALSXP) ); p++;
  213. }
  214. PROTECT( result = allocVector(TYPEOF(x), (ncx + ncy) * num_rows) );
  215. if( TYPEOF(fill) != TYPEOF(x) ) {
  216. PROTECT( fill = coerceVector(fill, TYPEOF(x)) ); p++;
  217. }
  218. mode = TYPEOF(x);
  219. /* use pointers instead of function calls */
  220. switch(TYPEOF(x)) {
  221. case INTSXP:
  222. int_x = INTEGER(x);
  223. int_y = INTEGER(y);
  224. int_fill = INTEGER(fill)[0];
  225. int_result = INTEGER(result);
  226. break;
  227. case REALSXP:
  228. real_x = REAL(x);
  229. real_y = REAL(y);
  230. /*real_fill = REAL(fill)[0];*/
  231. real_result = REAL(result);
  232. break;
  233. default:
  234. break;
  235. }
  236. switch(TYPEOF(xindex)) {
  237. case INTSXP:
  238. int_index = INTEGER(index);
  239. break;
  240. case REALSXP:
  241. real_index = REAL(index);
  242. break;
  243. default:
  244. break;
  245. }
  246. /* There are two type of supported index types, each branched from here */
  247. if( TYPEOF(xindex) == REALSXP ) {
  248. /* REAL INDEXING */
  249. for(i = 0; i < num_rows; i++) {
  250. /* If we are past the last row in x, assign NA to merged data
  251. and copy the y column values to the second side of result
  252. */
  253. if( xp > nrx ) {
  254. if(right_join) {
  255. real_index[ i ] = real_yindex[ yp-1 ];
  256. for(j = 0; j < ncx; j++) { /* x-values */
  257. ij_result = i + j * num_rows;
  258. switch( mode ) {
  259. case LGLSXP:
  260. LOGICAL(result)[ ij_result ] = LOGICAL(fill)[ 0 ];
  261. break;
  262. case INTSXP:
  263. /*INTEGER(result)[ ij_result ] = INTEGER(fill)[ 0 ];*/
  264. int_result[ ij_result ] = int_fill;
  265. break;
  266. case REALSXP:
  267. REAL(result)[ ij_result ] = REAL(fill)[ 0 ];
  268. break;
  269. case CPLXSXP:
  270. COMPLEX(result)[ ij_result ].r = REAL(fill)[ 0 ];
  271. COMPLEX(result)[ ij_result ].i = REAL(fill)[ 0 ];
  272. break;
  273. case STRSXP:
  274. SET_STRING_ELT(result, ij_result, STRING_ELT(fill, 0));
  275. break;
  276. default:
  277. error("unsupported data type");
  278. break;
  279. }
  280. }
  281. for(j = 0; j < ncy; j++) { /* y-values */
  282. ij_result = i + (j+ncx) * num_rows;
  283. ij_original = (yp-1) + j * nry;
  284. switch( mode ) {
  285. case LGLSXP:
  286. LOGICAL(result)[ ij_result ] = LOGICAL(y)[ ij_original ];
  287. break;
  288. case INTSXP:
  289. int_result[ ij_result ] = int_y[ ij_original ];
  290. break;
  291. case REALSXP:
  292. real_result[ ij_result ] = real_y[ ij_original ];
  293. break;
  294. case CPLXSXP:
  295. COMPLEX(result)[ ij_result ] = COMPLEX(y)[ ij_original ];
  296. break;
  297. case STRSXP:
  298. SET_STRING_ELT(result, ij_result, STRING_ELT(y, ij_original));
  299. break;
  300. default:
  301. error("unsupported data type");
  302. break;
  303. }
  304. }
  305. }
  306. yp++;
  307. if(!right_join) i--; /* if all=FALSE, we must decrement i for each non-match */
  308. } else
  309. /* past the last row of y */
  310. if( yp > nry ) {
  311. if(left_join) {
  312. /* record new index value */
  313. real_index[ i ] = real_xindex[ xp-1 ];
  314. /* copy values from x and y to result */
  315. for(j = 0; j < ncx; j++) { /* x-values */
  316. ij_result = i + j * num_rows;
  317. ij_original = (xp-1) + j * nrx;
  318. switch( mode ) {
  319. case LGLSXP:
  320. LOGICAL(result)[ ij_result ] = LOGICAL(x)[ ij_original ];
  321. break;
  322. case INTSXP:
  323. int_result[ ij_result ] = int_x[ ij_original ];
  324. break;
  325. case REALSXP:
  326. real_result[ ij_result ] = real_x[ ij_original ];
  327. break;
  328. case CPLXSXP:
  329. COMPLEX(result)[ ij_result ] = COMPLEX(x)[ ij_original ];
  330. break;
  331. case STRSXP:
  332. SET_STRING_ELT(result, ij_result, STRING_ELT(x, ij_original));
  333. break;
  334. default:
  335. error("unsupported data type");
  336. break;
  337. }
  338. }
  339. /* we are out of y-values, so fill merged result with NAs */
  340. for(j = 0; j < ncy; j++) { /* y-values */
  341. ij_result = i + (j+ncx) * num_rows;
  342. switch( mode ) {
  343. case LGLSXP:
  344. LOGICAL(result)[ ij_result ] = LOGICAL(fill)[ 0 ];
  345. break;
  346. case INTSXP:
  347. /*INTEGER(result)[ ij_result ] = INTEGER(fill)[ 0 ];*/
  348. int_result[ ij_result ] = int_fill;
  349. break;
  350. case REALSXP:
  351. REAL(result)[ ij_result ] = REAL(fill)[ 0 ];
  352. break;
  353. case CPLXSXP:
  354. COMPLEX(result)[ ij_result ].r = REAL(fill)[ 0 ];
  355. COMPLEX(result)[ ij_result ].i = REAL(fill)[ 0 ];
  356. break;
  357. case STRSXP:
  358. SET_STRING_ELT(result, ij_result, STRING_ELT(fill, 0));
  359. break;
  360. default:
  361. error("unsupported data type");
  362. break;
  363. }
  364. }
  365. }
  366. xp++;
  367. if(!left_join) i--;
  368. } else
  369. /* matching index values copy all column values from x and y to results */
  370. if( real_xindex[ xp-1 ] == real_yindex[ yp-1 ] ) {
  371. real_index[ i ] = real_xindex[ xp-1 ];
  372. /* copy x-values to result */
  373. for(j = 0; j < ncx; j++) { /* x-values */
  374. ij_result = i + j * num_rows;
  375. ij_original = (xp-1) + j * nrx;
  376. switch( mode ) {
  377. case LGLSXP:
  378. LOGICAL(result)[ ij_result ] = LOGICAL(x)[ ij_original ];
  379. break;
  380. case INTSXP:
  381. int_result[ ij_result ] = int_x[ ij_original ];
  382. break;
  383. case REALSXP:
  384. real_result[ ij_result ] = real_x[ ij_original ];
  385. break;
  386. case CPLXSXP:
  387. COMPLEX(result)[ ij_result ] = COMPLEX(x)[ ij_original ];
  388. break;
  389. case STRSXP:
  390. SET_STRING_ELT(result, ij_result, STRING_ELT(x, ij_original));
  391. break;
  392. default:
  393. error("unsupported data type");
  394. break;
  395. }
  396. }
  397. /* copy y-values to result */
  398. for(j = 0; j < ncy; j++) { /* y-values */
  399. ij_result = i + (j+ncx) * num_rows;
  400. ij_original = (yp-1) + j * nry;
  401. switch( mode ) {
  402. case LGLSXP:
  403. LOGICAL(result)[ ij_result ] = LOGICAL(y)[ ij_original ];
  404. break;
  405. case INTSXP:
  406. int_result[ ij_result ] = int_y[ ij_original ];
  407. break;
  408. case REALSXP:
  409. real_result[ ij_result ] = real_y[ ij_original ];
  410. break;
  411. case CPLXSXP:
  412. COMPLEX(result)[ ij_result ] = COMPLEX(y)[ ij_original ];
  413. break;
  414. case STRSXP:
  415. SET_STRING_ELT(result, ij_result, STRING_ELT(y, ij_original));
  416. break;
  417. default:
  418. error("unsupported data type");
  419. break;
  420. }
  421. }
  422. xp++;
  423. yp++;
  424. } else
  425. if( real_xindex[ xp-1 ] < real_yindex[ yp-1 ] ) {
  426. if(left_join) {
  427. real_index[ i ] = real_xindex[ xp-1 ];
  428. for(j = 0; j < ncx; j++) { /* x-values */
  429. ij_result = i + j * num_rows;
  430. ij_original = (xp-1) + j * nrx;
  431. switch( mode ) {
  432. case LGLSXP:
  433. LOGICAL(result)[ ij_result ] = LOGICAL(x)[ ij_original ];
  434. break;
  435. case INTSXP:
  436. int_result[ ij_result ] = int_x[ ij_original ];
  437. break;
  438. case REALSXP:
  439. real_result[ ij_result ] = real_x[ ij_original ];
  440. break;
  441. case CPLXSXP:
  442. COMPLEX(result)[ ij_result ] = COMPLEX(x)[ ij_original ];
  443. break;
  444. case STRSXP:
  445. SET_STRING_ELT(result, ij_result, STRING_ELT(x, ij_original));
  446. break;
  447. default:
  448. error("unsupported data type");
  449. break;
  450. }
  451. }
  452. for(j = 0; j < ncy; j++) { /* y-values */
  453. ij_result = i + (j+ncx) * num_rows;
  454. switch( mode ) {
  455. case LGLSXP:
  456. LOGICAL(result)[ ij_result ] = LOGICAL(fill)[ 0 ];
  457. break;
  458. case INTSXP:
  459. /*INTEGER(result)[ ij_result ] = INTEGER(fill)[ 0 ]; */
  460. int_result[ ij_result ] = int_fill;
  461. break;
  462. case REALSXP:
  463. REAL(result)[ ij_result ] = REAL(fill)[ 0 ];
  464. break;
  465. case CPLXSXP:
  466. COMPLEX(result)[ ij_result ].r = REAL(fill)[ 0 ];
  467. COMPLEX(result)[ ij_result ].i = REAL(fill)[ 0 ];
  468. break;
  469. case STRSXP:
  470. SET_STRING_ELT(result, ij_result, STRING_ELT(fill, 0));
  471. break;
  472. default:
  473. error("unsupported data type");
  474. break;
  475. }
  476. }
  477. }
  478. xp++;
  479. if(!left_join) i--;
  480. } else
  481. if( real_xindex[ xp-1 ] > real_yindex[ yp-1 ] ) {
  482. if(right_join) {
  483. real_index[ i ] = real_yindex[ yp-1 ];
  484. for(j = 0; j < ncx; j++) { /* x-values */
  485. ij_result = i + j * num_rows;
  486. switch( mode ) {
  487. case LGLSXP:
  488. LOGICAL(result)[ ij_result ] = LOGICAL(fill)[ 0 ];
  489. break;
  490. case INTSXP:
  491. /*INTEGER(result)[ ij_result ] = INTEGER(fill)[ 0 ];*/
  492. int_result[ ij_result ] = int_fill;
  493. break;
  494. case REALSXP:
  495. REAL(result)[ ij_result ] = REAL(fill)[ 0 ];
  496. break;
  497. case CPLXSXP:
  498. COMPLEX(result)[ ij_result ].r = REAL(fill)[ 0 ];
  499. COMPLEX(result)[ ij_result ].i = REAL(fill)[ 0 ];
  500. break;
  501. case STRSXP:
  502. SET_STRING_ELT(result, ij_result, STRING_ELT(fill, 0));
  503. break;
  504. default:
  505. error("unsupported data type");
  506. break;
  507. }
  508. }
  509. for(j = 0; j < ncy; j++) { /* y-values */
  510. ij_result = i + (j+ncx) * num_rows;
  511. ij_original = (yp-1) + j * nry;
  512. switch( mode ) {
  513. case LGLSXP:
  514. LOGICAL(result)[ ij_result ] = LOGICAL(y)[ ij_original ];
  515. break;
  516. case INTSXP:
  517. int_result[ ij_result ] = int_y[ ij_original ];
  518. break;
  519. case REALSXP:
  520. real_result[ ij_result ] = real_y[ ij_original ];
  521. break;
  522. case CPLXSXP:
  523. COMPLEX(result)[ ij_result ] = COMPLEX(y)[ ij_original ];
  524. break;
  525. case STRSXP:
  526. SET_STRING_ELT(result, ij_result, STRING_ELT(y, ij_original));
  527. break;
  528. default:
  529. error("unsupported data type");
  530. break;
  531. }
  532. }
  533. }
  534. yp++;
  535. if(!right_join) i--;
  536. }
  537. }
  538. } else
  539. if( TYPEOF(xindex) == INTSXP ) {
  540. for(i = 0; i < num_rows; i++) {
  541. /* If we are past the last row in x, assign NA to merged data
  542. and copy the y column values to the second side of result
  543. */
  544. if( xp > nrx ) {
  545. if(right_join) {
  546. int_index[ i ] = int_yindex[ yp-1 ];
  547. for(j = 0; j < ncx; j++) { /* x-values */
  548. ij_result = i + j * num_rows;
  549. switch( mode ) {
  550. case LGLSXP:
  551. case INTSXP:
  552. /*INTEGER(result)[ ij_result ] = INTEGER(fill)[ 0 ];*/
  553. int_result[ ij_result ] = int_fill;
  554. break;
  555. case REALSXP:
  556. REAL(result)[ ij_result ] = REAL(fill)[ 0 ];
  557. break;
  558. case CPLXSXP:
  559. COMPLEX(result)[ ij_result ].r = REAL(fill)[ 0 ];
  560. COMPLEX(result)[ ij_result ].i = REAL(fill)[ 0 ];
  561. break;
  562. case STRSXP:
  563. SET_STRING_ELT(result, ij_result, STRING_ELT(fill, 0));
  564. break;
  565. default:
  566. error("unsupported data type");
  567. break;
  568. }
  569. }
  570. for(j = 0; j < ncy; j++) { /* y-values */
  571. ij_result = i + (j+ncx) * num_rows;
  572. ij_original = (yp-1) + j * nry;
  573. switch( mode ) {
  574. case LGLSXP:
  575. LOGICAL(result)[ ij_result ] = LOGICAL(y)[ ij_original ];
  576. break;
  577. case INTSXP:
  578. int_result[ ij_result ] = int_y[ ij_original ];
  579. break;
  580. case REALSXP:
  581. real_result[ ij_result ] = real_y[ ij_original ];
  582. break;
  583. case CPLXSXP:
  584. COMPLEX(result)[ ij_result ] = COMPLEX(y)[ ij_original ];
  585. break;
  586. case STRSXP:
  587. SET_STRING_ELT(result, ij_result, STRING_ELT(y, ij_original));
  588. break;
  589. default:
  590. error("unsupported data type");
  591. break;
  592. }
  593. }
  594. }
  595. yp++;
  596. if(!right_join) i--; /* if all=FALSE, we must decrement i for each non-match */
  597. } else
  598. /* past the last row of y */
  599. if( yp > nry ) {
  600. if(left_join) {
  601. /* record new index value */
  602. int_index[ i ] = int_xindex[ xp-1 ];
  603. /* copy values from x and y to result */
  604. for(j = 0; j < ncx; j++) { // x-values
  605. ij_result = i + j * num_rows;
  606. ij_original = (xp-1) + j * nrx; //num_rows;
  607. switch( mode ) {
  608. case LGLSXP:
  609. LOGICAL(result)[ ij_result ] = LOGICAL(x)[ ij_original ];
  610. break;
  611. case INTSXP:
  612. int_result[ ij_result ] = int_x[ ij_original];
  613. //INTEGER(result)[ ij_result ] = INTEGER(x)[ ij_original ];
  614. break;
  615. case REALSXP:
  616. //REAL(result)[ ij_result ] = REAL(x)[ ij_original ];
  617. real_result[ ij_result ] = real_x[ ij_original ];
  618. break;
  619. case CPLXSXP:
  620. COMPLEX(result)[ ij_result ] = COMPLEX(x)[ ij_original ];
  621. break;
  622. case STRSXP:
  623. SET_STRING_ELT(result, ij_result, STRING_ELT(x, ij_original));
  624. break;
  625. default:
  626. error("unsupported data type");
  627. break;
  628. }
  629. }
  630. /* we are out of y-values, so fill merged result with NAs */
  631. for(j = 0; j < ncy; j++) { // y-values
  632. ij_result = i + (j+ncx) * num_rows;
  633. //REAL(result)[ ij_result ] = NA_REAL;
  634. switch( mode ) {
  635. case LGLSXP:
  636. LOGICAL(result)[ ij_result ] = LOGICAL(fill)[ 0 ]; //NA_INTEGER;
  637. break;
  638. case INTSXP:
  639. int_result[ ij_result ] = int_fill;
  640. break;
  641. case REALSXP:
  642. REAL(result)[ ij_result ] = REAL(fill)[ 0 ]; //NA_REAL;
  643. break;
  644. case CPLXSXP:
  645. COMPLEX(result)[ ij_result ].r = REAL(fill)[ 0 ]; //NA_REAL;
  646. COMPLEX(result)[ ij_result ].i = REAL(fill)[ 0 ]; //NA_REAL;
  647. break;
  648. case STRSXP:
  649. SET_STRING_ELT(result, ij_result, STRING_ELT(fill, 0)); //NA_STRING);
  650. break;
  651. default:
  652. error("unsupported data type");
  653. break;
  654. }
  655. }
  656. }
  657. xp++;
  658. if(!left_join) i--;
  659. } else
  660. /* matching index values copy all column values from x and y to results */
  661. //if( INTEGER(xindex)[ xp-1 ] == INTEGER(yindex)[ yp-1 ] ) {
  662. if( int_xindex[ xp-1 ] == int_yindex[ yp-1 ] ) {
  663. /* copy index FIXME this needs to handle INTEGER efficiently as well*/
  664. //INTEGER(index)[ i ] = INTEGER(xindex)[ xp-1 ];
  665. int_index[ i ] = int_xindex[ xp-1 ];
  666. /* copy x-values to result */
  667. for(j = 0; j < ncx; j++) { // x-values
  668. ij_result = i + j * num_rows;
  669. ij_original = (xp-1) + j * nrx; //num_rows;
  670. //REAL(result)[ ij_result ] = REAL(x)[ ij_original ];
  671. switch( mode ) {
  672. case LGLSXP:
  673. LOGICAL(result)[ ij_result ] = LOGICAL(x)[ ij_original ];
  674. break;
  675. case INTSXP:
  676. int_result[ ij_result ] = int_x[ ij_original ];
  677. //INTEGER(result)[ ij_result ] = INTEGER(x)[ ij_original ];
  678. break;
  679. case REALSXP:
  680. //REAL(result)[ ij_result ] = REAL(x)[ ij_original ];
  681. real_result[ ij_result ] = real_x[ ij_original ];
  682. break;
  683. case CPLXSXP:
  684. COMPLEX(result)[ ij_result ] = COMPLEX(x)[ ij_original ];
  685. break;
  686. case STRSXP:
  687. SET_STRING_ELT(result, ij_result, STRING_ELT(x, ij_original));
  688. break;
  689. default:
  690. error("unsupported data type");
  691. break;
  692. }
  693. }
  694. /* copy y-values to result */
  695. for(j = 0; j < ncy; j++) { // y-values
  696. ij_result = i + (j+ncx) * num_rows;
  697. ij_original = (yp-1) + j * nry; //num_rows;
  698. //REAL(result)[ ij_result ] = REAL(y)[ ij_original ];
  699. switch( mode ) {
  700. case LGLSXP:
  701. LOGICAL(result)[ ij_result ] = LOGICAL(y)[ ij_original ];
  702. break;
  703. case INTSXP:
  704. int_result[ ij_result ] = int_y[ ij_original ];
  705. //INTEGER(result)[ ij_result ] = INTEGER(y)[ ij_original ];
  706. break;
  707. case REALSXP:
  708. //REAL(result)[ ij_result ] = REAL(y)[ ij_original ];
  709. real_result[ ij_result ] = real_y[ ij_original ];
  710. break;
  711. case CPLXSXP:
  712. COMPLEX(result)[ ij_result ] = COMPLEX(y)[ ij_original ];
  713. break;
  714. case STRSXP:
  715. SET_STRING_ELT(result, ij_result, STRING_ELT(y, ij_original));
  716. break;
  717. default:
  718. error("unsupported data type");
  719. break;
  720. }
  721. }
  722. xp++;
  723. yp++;
  724. } else
  725. //if( INTEGER(xindex)[ xp-1 ] < INTEGER(yindex)[ yp-1 ] ) {
  726. if( int_xindex[ xp-1 ] < int_yindex[ yp-1 ] ) {
  727. if(left_join) {
  728. //copyIndex(index, xindex, i, xp-1);
  729. //INTEGER(index)[ i ] = INTEGER(xindex)[ xp-1 ];
  730. int_index[ i ] = int_xindex[ xp-1 ];
  731. for(j = 0; j < ncx; j++) { // x-values
  732. ij_result = i + j * num_rows;
  733. ij_original = (xp-1) + j * nrx; //num_rows;
  734. //REAL(result)[ ij_result ] = REAL(x)[ ij_original ];
  735. switch( mode ) {
  736. case LGLSXP:
  737. LOGICAL(result)[ ij_result ] = LOGICAL(x)[ ij_original ];
  738. break;
  739. case INTSXP:
  740. //INTEGER(result)[ ij_result ] = INTEGER(x)[ ij_original ];
  741. int_result[ ij_result ] = int_x[ ij_original ];
  742. break;
  743. case REALSXP:
  744. //REAL(result)[ ij_result ] = REAL(x)[ ij_original ];
  745. real_result[ ij_result ] = real_x[ ij_original ];
  746. break;
  747. case CPLXSXP:
  748. COMPLEX(result)[ ij_result ] = COMPLEX(x)[ ij_original ];
  749. break;
  750. case STRSXP:
  751. SET_STRING_ELT(result, ij_result, STRING_ELT(x, ij_original));
  752. break;
  753. default:
  754. error("unsupported data type");
  755. break;
  756. }
  757. }
  758. for(j = 0; j < ncy; j++) { /* y-values */
  759. ij_result = i + (j+ncx) * num_rows;
  760. switch( mode ) {
  761. case LGLSXP:
  762. LOGICAL(result)[ ij_result ] = LOGICAL(fill)[ 0 ];
  763. break;
  764. case INTSXP:
  765. int_result[ ij_result ] = int_fill;
  766. break;
  767. case REALSXP:
  768. REAL(result)[ ij_result ] = REAL(fill)[ 0 ];
  769. break;
  770. case CPLXSXP:
  771. COMPLEX(result)[ ij_result ].r = REAL(fill)[ 0 ];
  772. COMPLEX(result)[ ij_result ].i = REAL(fill)[ 0 ];
  773. break;
  774. case STRSXP:
  775. SET_STRING_ELT(result, ij_result, STRING_ELT(fill, 0));
  776. break;
  777. default:
  778. error("unsupported data type");
  779. break;
  780. }
  781. }
  782. }
  783. xp++;
  784. if(!left_join) i--;
  785. } else
  786. //if( INTEGER(xindex)[ xp-1 ] > INTEGER(yindex)[ yp-1 ] ) {
  787. if( int_xindex[ xp-1 ] > int_yindex[ yp-1 ] ) {
  788. if(right_join) {
  789. //INTEGER(index)[ i ] = INTEGER(yindex)[ yp-1 ];
  790. int_index[ i ] = int_yindex[ yp-1 ];
  791. for(j = 0; j < ncx; j++) { // x-values
  792. ij_result = i + j * num_rows;
  793. //REAL(result)[ ij_result ] = NA_REAL;
  794. switch( mode ) {
  795. case LGLSXP:
  796. LOGICAL(result)[ ij_result ] = LOGICAL(fill)[ 0 ]; //NA_INTEGER;
  797. case INTSXP:
  798. int_result[ ij_result ] = int_fill;
  799. break;
  800. case REALSXP:
  801. REAL(result)[ ij_result ] = REAL(fill)[ 0 ]; //NA_REAL;
  802. break;
  803. case CPLXSXP:
  804. COMPLEX(result)[ ij_result ].r = REAL(fill)[ 0 ]; //NA_REAL;
  805. COMPLEX(result)[ ij_result ].i = REAL(fill)[ 0 ]; //NA_REAL;
  806. break;
  807. case STRSXP:
  808. SET_STRING_ELT(result, ij_result, STRING_ELT(fill, 0)); //NA_STRING);
  809. break;
  810. default:
  811. error("unsupported data type");
  812. break;
  813. }
  814. }
  815. for(j = 0; j < ncy; j++) { // y-values
  816. ij_result = i + (j+ncx) * num_rows;
  817. ij_original = (yp-1) + j * nry; //num_rows;
  818. //REAL(result)[ ij_result ] = REAL(y)[ ij_original ];
  819. switch( mode ) {
  820. case LGLSXP:
  821. LOGICAL(result)[ ij_result ] = LOGICAL(y)[ ij_original ];
  822. break;
  823. case INTSXP:
  824. //INTEGER(result)[ ij_result ] = INTEGER(y)[ ij_original ];
  825. int_result[ ij_result ] = int_y[ ij_original ];
  826. break;
  827. case REALSXP:
  828. //REAL(result)[ ij_result ] = REAL(y)[ ij_original ];
  829. real_result[ ij_result ] = real_y[ ij_original ];
  830. break;
  831. case CPLXSXP:
  832. COMPLEX(result)[ ij_result ] = COMPLEX(y)[ ij_original ];
  833. break;
  834. case STRSXP:
  835. SET_STRING_ELT(result, ij_result, STRING_ELT(y, ij_original));
  836. break;
  837. default:
  838. error("unsupported data type");
  839. break;
  840. }
  841. }
  842. }
  843. yp++;
  844. if(!right_join) i--;
  845. }
  846. }
  847. }
  848. /* following logic to allow for
  849. dimensionless xts objects (unsupported)
  850. to be used in Ops.xts calls
  851. This maps to how zoo behaves */
  852. if(LOGICAL(retside)[0] &&
  853. !LOGICAL(retside)[1] &&
  854. isNull(getAttrib(x,R_DimSymbol))) {
  855. /* retside=c(T,F) AND is.null(dim(x)) */
  856. setAttrib(result, R_DimSymbol, R_NilValue);
  857. } else
  858. if(LOGICAL(retside)[1] &&
  859. !LOGICAL(retside)[0] &&
  860. isNull(getAttrib(y,R_DimSymbol))) {
  861. /* retside=c(F,T) AND is.null(dim(y)) */
  862. setAttrib(result, R_DimSymbol, R_NilValue);
  863. } else /* set Dim and DimNames */
  864. if(num_rows >= 0 && (ncx + ncy) >= 0) {
  865. /* DIM */
  866. PROTECT(attr = allocVector(INTSXP, 2));
  867. INTEGER(attr)[0] = num_rows;
  868. INTEGER(attr)[1] = ncx + ncy;
  869. setAttrib(result, R_DimSymbol, attr);
  870. UNPROTECT(1);
  871. /* DIMNAMES */
  872. if(!isNull(colnames)) { // only set DimNamesSymbol if passed colnames is not NULL
  873. SEXP dimnames, dimnames_x, dimnames_y, newcolnames;
  874. PROTECT(dimnames = allocVector(VECSXP, 2));
  875. PROTECT(dimnames_x = getAttrib(x, R_DimNamesSymbol)); p++;
  876. PROTECT(dimnames_y = getAttrib(y, R_DimNamesSymbol)); p++;
  877. PROTECT(newcolnames = allocVector(STRSXP, ncx+ncy));
  878. for(i = 0; i < (ncx + ncy); i++) {
  879. if( i < ncx ) {
  880. if(!isNull(dimnames_x) && !isNull(VECTOR_ELT(dimnames_x,1))) {
  881. SET_STRING_ELT(newcolnames, i, STRING_ELT(VECTOR_ELT(dimnames_x,1),i));
  882. } else {
  883. SET_STRING_ELT(newcolnames, i, STRING_ELT(colnames, i));
  884. }
  885. } else { // i >= ncx;
  886. if(!isNull(dimnames_y) && !isNull(VECTOR_ELT(dimnames_y,1))) {
  887. SET_STRING_ELT(newcolnames, i, STRING_ELT(VECTOR_ELT(dimnames_y,1),i-ncx));
  888. } else {
  889. SET_STRING_ELT(newcolnames, i, STRING_ELT(colnames, i));
  890. }
  891. }
  892. }
  893. SET_VECTOR_ELT(dimnames, 0, R_NilValue); // ROWNAMES are NULL
  894. PROTECT(s = t = allocList(3)); p++;
  895. SET_TYPEOF(s, LANGSXP);
  896. SETCAR(t, install("make.names")); t = CDR(t);
  897. SETCAR(t, newcolnames); t = CDR(t);
  898. PROTECT(unique = allocVector(LGLSXP, 1)); p++; LOGICAL(unique)[0] = 1;
  899. SETCAR(t, unique); SET_TAG(t, install("unique"));
  900. SET_VECTOR_ELT(dimnames, 1, eval(s, env));
  901. //SET_VECTOR_ELT(dimnames, 1, newcolnames); // COLNAMES are passed in
  902. setAttrib(result, R_DimNamesSymbol, dimnames);
  903. UNPROTECT(2);
  904. }
  905. } else {
  906. // only used for zero-width results! xts always has dimension
  907. setAttrib(result, R_DimSymbol, R_NilValue);
  908. }
  909. setAttrib(result, xts_IndexSymbol, index);
  910. if(LOGICAL(retclass)[0])
  911. setAttrib(result, R_ClassSymbol, getAttrib(x, R_ClassSymbol));
  912. setAttrib(result, xts_IndexClassSymbol, getAttrib(x, xts_IndexClassSymbol));
  913. setAttrib(result, xts_IndexTZSymbol, getAttrib(x, xts_IndexTZSymbol));
  914. setAttrib(result, xts_IndexFormatSymbol, getAttrib(x, xts_IndexFormatSymbol));
  915. setAttrib(result, xts_ClassSymbol, getAttrib(x, xts_ClassSymbol));
  916. copy_xtsAttributes(x, result);
  917. UNPROTECT(4 + p);
  918. return result;
  919. } //}}}
  920. //SEXP mergeXts (SEXP all, SEXP fill, SEXP retclass, SEXP colnames, SEXP retside, SEXP env, SEXP args)
  921. /* called via .External("mergeXts", ...) */
  922. SEXP mergeXts (SEXP args) // mergeXts {{{
  923. {
  924. SEXP _x, _y, xtmp, result, _INDEX;
  925. /* colnames should be renamed as suffixes, as colnames need to be added at the C level */
  926. SEXP all, fill, retc, retclass, symnames,
  927. suffixes, rets, retside, env, tzone;
  928. int nr, nc, ncs=0;
  929. int index_len;
  930. int i, n=0, P=0;
  931. SEXP argstart;
  932. args = CDR(args);
  933. PROTECT(all = CAR(args)); P++;
  934. args = CDR(args);
  935. PROTECT(fill = CAR(args)); P++;
  936. args = CDR(args);
  937. PROTECT(retclass = CAR(args)); P++;
  938. args = CDR(args);
  939. PROTECT(symnames = CAR(args)); P++;
  940. args = CDR(args);
  941. PROTECT(suffixes = CAR(args)); P++;
  942. args = CDR(args);
  943. PROTECT(retside = CAR(args)); P++;
  944. args = CDR(args);
  945. PROTECT(env = CAR(args)); P++;
  946. args = CDR(args);
  947. PROTECT(tzone = CAR(args)); P++;
  948. args = CDR(args);
  949. // args should now correspond to the ... objects we are looking to merge
  950. argstart = args; // use this to rewind list...
  951. n = 0;
  952. int type_of;
  953. int coerce_to_double=0;
  954. if(args != R_NilValue) type_of = TYPEOF(CAR(args));
  955. while(args != R_NilValue) {
  956. if( length(CAR(args)) > 0 )
  957. ncs += ncols(CAR(args));
  958. if(TYPEOF(CAR(args)) != type_of)
  959. coerce_to_double = 1; /* need to convert all objects if one needs to be converted */
  960. args = CDR(args);
  961. n++;
  962. }
  963. /* build an index to be used in all subsequent calls */
  964. args = argstart;
  965. PROTECT(_x = CAR(args)); P++;
  966. args = CDR(args);
  967. int leading_non_xts = 0;
  968. while( !isXts(_x) ) {
  969. if( args == R_NilValue ) error("no xts object to merge");
  970. leading_non_xts = 1;
  971. /*warning("leading non-xts objects may have been dropped");*/
  972. PROTECT(_x = CAR(args)); P++;
  973. args = CDR(args);
  974. }
  975. /* test for NULLs that may be present from cbind dispatch */
  976. if(!leading_non_xts) { /* leading non-xts in 2 case scenario was igoring non-xts value */
  977. if(n < 3 && (args == R_NilValue || (isNull(CAR(args)) && length(args) == 1))) {/* no y arg or y==NULL */
  978. UNPROTECT(P);
  979. return(_x);
  980. }
  981. }
  982. if( args != R_NilValue) {
  983. PROTECT(_y = CAR(args)); P++;
  984. args = CDR(args);
  985. } else {
  986. PROTECT(_y = duplicate(_x)); P++;
  987. }
  988. if(n > 2 || leading_non_xts) { /*args != R_NilValue) {*/
  989. /* generalized n-case optimization
  990. currently if n>2 this is faster and more memory efficient
  991. than recursively building a merged object, object by object. */
  992. PROTECT(retc = allocVector(LGLSXP, 1)); P++;
  993. LOGICAL(retc)[0] = 1; /* return class == TRUE */
  994. PROTECT(rets = allocVector(LGLSXP, 2)); P++;
  995. LOGICAL(rets)[0] = 0; /* don't return left */
  996. LOGICAL(rets)[1] = 0; /* don't return right */
  997. if( isNull(_y) ) {
  998. PROTECT(_y = duplicate(_x)); P++;
  999. }
  1000. PROTECT(_INDEX = do_merge_xts(_x,
  1001. _y,
  1002. all,
  1003. fill,
  1004. retc,
  1005. R_NilValue,
  1006. R_NilValue,
  1007. rets,
  1008. env,
  1009. coerce_to_double)); P++;
  1010. /* merge all objects into one zero-width common index */
  1011. while(args != R_NilValue) {
  1012. if( !isNull(CAR(args)) ) {
  1013. PROTECT(_INDEX = do_merge_xts(_INDEX,
  1014. CAR(args),
  1015. all,
  1016. fill,
  1017. retc,
  1018. R_NilValue,
  1019. R_NilValue,
  1020. rets,
  1021. env,
  1022. coerce_to_double)); P++;
  1023. }
  1024. args = CDR(args);
  1025. }
  1026. index_len = length(GET_xtsIndex(_INDEX));
  1027. args = argstart; // reset args
  1028. int ii, jj, iijj, jj_result;
  1029. int *int_result=NULL, *int_xtmp=NULL;
  1030. double *real_result=NULL, *real_xtmp=NULL;
  1031. PROTECT(result = allocVector(TYPEOF(_INDEX), index_len * ncs)); P++;
  1032. switch(TYPEOF(result)) {
  1033. case LGLSXP:
  1034. case INTSXP:
  1035. int_result = INTEGER(result);
  1036. break;
  1037. case REALSXP:
  1038. real_result = REAL(result);
  1039. break;
  1040. default:
  1041. error("unsupported data type");
  1042. }
  1043. SEXP ColNames, NewColNames;
  1044. PROTECT(NewColNames = allocVector(STRSXP, ncs)); P++;
  1045. ncs = 0;
  1046. for(i = 0, nc=0; args != R_NilValue; i = i+nc, args = CDR(args)) { // merge each object with index
  1047. // i is object current being merged/copied
  1048. // nc is offset in current object
  1049. if( isNull(CAR(args)) ) {
  1050. i = i-nc;
  1051. continue; // if NULL is passed, skip to the next object.
  1052. }
  1053. xtmp = do_merge_xts(_INDEX,
  1054. CAR(args),
  1055. all,
  1056. fill,
  1057. retclass,
  1058. /*colnames*/R_NilValue,
  1059. R_NilValue,
  1060. retside,
  1061. env,
  1062. coerce_to_double);
  1063. nc = ncols(xtmp);
  1064. ncs += nc;
  1065. nr = nrows(xtmp);
  1066. PROTECT(ColNames = getAttrib(CAR(args),R_DimNamesSymbol));
  1067. switch(TYPEOF(xtmp)) { // by type, insert merged data into result object
  1068. case LGLSXP:
  1069. case INTSXP:
  1070. int_xtmp = INTEGER(xtmp);
  1071. for(jj=0; jj < nc; jj++) {
  1072. if(!isNull(ColNames) && !isNull(VECTOR_ELT(ColNames,1))) {
  1073. /* if merged object has colnames, use these, otherwise use deparse names */
  1074. SET_STRING_ELT(NewColNames, i+jj, STRING_ELT(VECTOR_ELT(ColNames,1),jj));
  1075. } else {
  1076. SET_STRING_ELT(NewColNames, i+jj, STRING_ELT(symnames,i+jj));
  1077. }
  1078. for(ii=0; ii < nr; ii++) {
  1079. iijj = ii + jj * nr;
  1080. jj_result = ii + ( (i+jj) * nr);
  1081. int_result[ jj_result ] = int_xtmp[ iijj ];
  1082. }
  1083. }
  1084. break;
  1085. case REALSXP:
  1086. real_xtmp = REAL(xtmp);
  1087. for(jj=0; jj < nc; jj++) {
  1088. if(!isNull(ColNames) && !isNull(VECTOR_ELT(ColNames,1))) {
  1089. SET_STRING_ELT(NewColNames, i+jj, STRING_ELT(VECTOR_ELT(ColNames,1),jj));
  1090. } else {
  1091. SET_STRING_ELT(NewColNames, i+jj, STRING_ELT(symnames,i+jj));
  1092. }
  1093. for(ii=0; ii < nr; ii++) {
  1094. iijj = ii + jj * nr;
  1095. jj_result = ii + ( (i+jj) * nr);
  1096. real_result[ jj_result ] = real_xtmp[ iijj ];
  1097. }
  1098. }
  1099. break;
  1100. }
  1101. UNPROTECT(1); /* ColNames */
  1102. }
  1103. SEXP dim;
  1104. PROTECT(dim = allocVector(INTSXP, 2)); P++;
  1105. INTEGER(dim)[0] = index_len;
  1106. INTEGER(dim)[1] = ncs;
  1107. setAttrib(result, R_DimSymbol, dim);
  1108. SEXP dimnames;
  1109. PROTECT(dimnames = allocVector(VECSXP, 2)); P++;
  1110. SET_VECTOR_ELT(dimnames, 0, R_NilValue); // rownames are always NULL in xts
  1111. /* colnames, assure they are unique before returning */
  1112. SEXP s, t, unique;
  1113. PROTECT(s = t = allocList(3)); P++;
  1114. SET_TYPEOF(s, LANGSXP);
  1115. SETCAR(t, install("make.names")); t = CDR(t);
  1116. SETCAR(t, NewColNames); t = CDR(t);
  1117. PROTECT(unique = allocVector(LGLSXP, 1)); P++; LOGICAL(unique)[0] = 1;
  1118. SETCAR(t, unique); SET_TAG(t, install("unique"));
  1119. SET_VECTOR_ELT(dimnames, 1, eval(s, env));
  1120. setAttrib(result, R_DimNamesSymbol, dimnames);
  1121. SET_xtsIndex(result, GET_xtsIndex(_INDEX));
  1122. SET_xtsIndexTZ(result, GET_xtsIndexTZ(_INDEX));
  1123. copy_xtsCoreAttributes(_INDEX, result);
  1124. copy_xtsAttributes(_INDEX, result);
  1125. } else { /* 2-case optimization --- simply call main routine */
  1126. /* likely bug in handling of merge(1, xts) case */
  1127. PROTECT(result = do_merge_xts(_x,
  1128. _y,
  1129. all,
  1130. fill,
  1131. retclass,
  1132. symnames /*R_NilValue*/,
  1133. suffixes,
  1134. retside,
  1135. env,
  1136. coerce_to_double)); P++;
  1137. }
  1138. SEXP index_tmp = getAttrib(result, install("index"));
  1139. PROTECT(index_tmp);
  1140. if(isNull(tzone)) {
  1141. setAttrib(index_tmp, install("tzone"),
  1142. getAttrib(getAttrib(_x,install("index")), install("tzone")));
  1143. } else {
  1144. setAttrib(index_tmp, install("tzone"), tzone);
  1145. }
  1146. copyMostAttrib(getAttrib(_x,install("index")), index_tmp);
  1147. setAttrib(result, install("index"), index_tmp);
  1148. setAttrib(result, install(".indexTZ"), getAttrib(index_tmp, install("tzone")));
  1149. UNPROTECT(1);
  1150. if(P > 0) UNPROTECT(P);
  1151. return(result);
  1152. } //}}} end of mergeXts