summaryrefslogtreecommitdiffstats
path: root/scilab/modules/core
diff options
context:
space:
mode:
authorBernard HUGUENEY <bernard.hugueney@scilab.org>2010-03-19 15:05:45 +0100
committerBernard HUGUENEY <bernard.hugueney@scilab.org>2010-03-19 15:05:45 +0100
commitf5f3f1723ec54a6a25d5d521e1369f71d437668a (patch)
treef73e75b5e944b7565d7e84611f129c8af4c534d5 /scilab/modules/core
parent473bcba8ff387bc72ca0ba92973b203b19bdecab (diff)
downloadscilab-f5f3f1723ec54a6a25d5d521e1369f71d437668a.zip
scilab-f5f3f1723ec54a6a25d5d521e1369f71d437668a.tar.gz
1°) Replaced C2F(eqid)() call with (inlined) eq_n<nsiz> from unrolled_algorithms.hxx
2°) Provided most efficient specialization for nsiz ints of this template. 3°) moved unrolled_algorihm.hxx content from scilab::core namespace to unnamed namespace as it is used for inlinng. should an out of line definition be provided in a visible (scilab::core) namespace, it should be done in a .cpp file to avoid ODR violation.
Diffstat (limited to 'scilab/modules/core')
-rw-r--r--scilab/modules/core/src/cpp/hashtable_core.cpp68
-rw-r--r--scilab/modules/core/src/cpp/search_functions.cpp14
-rw-r--r--scilab/modules/core/src/cpp/unrolled_algorithms.hxx124
3 files changed, 110 insertions, 96 deletions
diff --git a/scilab/modules/core/src/cpp/hashtable_core.cpp b/scilab/modules/core/src/cpp/hashtable_core.cpp
index 6a44257..ae7cd75 100644
--- a/scilab/modules/core/src/cpp/hashtable_core.cpp
+++ b/scilab/modules/core/src/cpp/hashtable_core.cpp
@@ -33,7 +33,7 @@ extern int C2F(cvname)(int *,char *,int const*, unsigned long int);
33#include <functional> 33#include <functional>
34#include <cstring> // for std::memset 34#include <cstring> // for std::memset
35#include "partition.hxx" // for scilab::core::partition_point_n 35#include "partition.hxx" // for scilab::core::partition_point_n
36#include "unrolled_algorithms.hxx" //for scilab::core::eq_n less_n copy_n 36#include "unrolled_algorithms.hxx" //for eq_n less_n copy_n
37/*----------------------------------------------------------------------------*/ 37/*----------------------------------------------------------------------------*/
38#define MAXLENGHTFUNCTIONNAME 32 /* 24 in fact in scilab +1 for '\0' round to nearest multiple of 8*/ 38#define MAXLENGHTFUNCTIONNAME 32 /* 24 in fact in scilab +1 for '\0' round to nearest multiple of 8*/
39/*----------------------------------------------------------------------------*/ 39/*----------------------------------------------------------------------------*/
@@ -42,18 +42,18 @@ using namespace scilab::core;
42namespace { 42namespace {
43 struct entry 43 struct entry
44 { 44 {
45 entry() 45 entry()
46 { 46 {
47 std::memset(key, 0, sizeof(key)+sizeof(data)+1); // no alignement issues, init ints to 0 and namefunction to "" 47 std::memset(key, 0, sizeof(key)+sizeof(data)+1); // no alignement issues, init ints to 0 and namefunction to ""
48 } 48 }
49 entry(int d, char const* name): data(d) 49 entry(int d, char const* name): data(d)
50 { 50 {
51 int const zero(0); 51 int const zero(0);
52 if(name) 52 if(name)
53 { 53 {
54 strncpy(namefunction, name, MAXLENGHTFUNCTIONNAME); 54 strncpy(namefunction, name, MAXLENGHTFUNCTIONNAME);
55 } 55 }
56 else 56 else
57 { 57 {
58 namefunction[0]= '\0'; // "" name 58 namefunction[0]= '\0'; // "" name
59 } 59 }
@@ -76,14 +76,14 @@ namespace {
76 * (could be removed with boost:: or C++0x lambdas ) 76 * (could be removed with boost:: or C++0x lambdas )
77 * 77 *
78 */ 78 */
79 struct key_less_than : std::unary_function<entry const&, bool> 79 struct key_less_than : std::unary_function<entry const&, bool>
80 { 80 {
81 key_less_than(int const* const k): key(k) {} 81 key_less_than(int const* const k): key(k) {}
82 bool operator()(entry const& e) const { return less_n<nsiz>(key, e.key);} 82 bool operator()(entry const& e) const { return less_n<nsiz>(key, e.key);}
83 int const* const key; 83 int const* const key;
84 }; 84 };
85 85
86 struct not_less_than_key : std::unary_function<entry const&, bool> 86 struct not_less_than_key : std::unary_function<entry const&, bool>
87 { 87 {
88 not_less_than_key(int const* const k): key(k) {} 88 not_less_than_key(int const* const k): key(k) {}
89 bool operator()(entry const& e) const { return !less_n<nsiz>(e.key, key);} 89 bool operator()(entry const& e) const { return !less_n<nsiz>(e.key, key);}
@@ -91,7 +91,7 @@ namespace {
91 }; 91 };
92 92
93 93
94 struct equal_data 94 struct equal_data
95 { 95 {
96 equal_data(int const d) : data(d) {} 96 equal_data(int const d) : data(d) {}
97 bool operator()(entry const& e) const { return e.data == data ; } 97 bool operator()(entry const& e) const { return e.data == data ; }
@@ -103,16 +103,16 @@ namespace {
103* preallocate memory for DEFAULT_ELEMENTFUNCTIONLIST entries in table 103* preallocate memory for DEFAULT_ELEMENTFUNCTIONLIST entries in table
104*/ 104*/
105/*----------------------------------------------------------------------------*/ 105/*----------------------------------------------------------------------------*/
106BOOL create_hashtable_scilab_functions(void) 106BOOL create_hashtable_scilab_functions(void)
107{ 107{
108 try 108 try
109 { 109 {
110 table_t tmp(0); 110 table_t tmp(0);
111 tmp.reserve( DEFAULT_ELEMENTFUNCTIONLIST ); 111 tmp.reserve( DEFAULT_ELEMENTFUNCTIONLIST );
112 table.swap(tmp); 112 table.swap(tmp);
113 return TRUE; 113 return TRUE;
114 } 114 }
115 catch( std::bad_alloc& e) 115 catch( std::bad_alloc& e)
116 { 116 {
117 return FALSE; 117 return FALSE;
118 } 118 }
@@ -123,7 +123,7 @@ BOOL create_hashtable_scilab_functions(void)
123* free memory for table 123* free memory for table
124*/ 124*/
125/*----------------------------------------------------------------------------*/ 125/*----------------------------------------------------------------------------*/
126void destroy_hashtable_scilab_functions() 126void destroy_hashtable_scilab_functions()
127{ 127{
128 table_t tmp(0); // swap trick needed because resize() does *not* release memory 128 table_t tmp(0); // swap trick needed because resize() does *not* release memory
129 table.swap(tmp); 129 table.swap(tmp);
@@ -133,7 +133,7 @@ static BOOL doFindFunction(int *key,char *name, int *scilab_funptr)
133{ 133{
134 int tmp[nsiz]; 134 int tmp[nsiz];
135 int const* keyToSearch= key; 135 int const* keyToSearch= key;
136 if (name) 136 if (name)
137 { 137 {
138 /* faster than a strcmp */ 138 /* faster than a strcmp */
139 int job = 0; /* convert name to id */ 139 int job = 0; /* convert name to id */
@@ -142,12 +142,12 @@ static BOOL doFindFunction(int *key,char *name, int *scilab_funptr)
142 } 142 }
143 // find lower bound : first elt not < 143 // find lower bound : first elt not <
144 table_t::const_iterator i= partition_point_n(table.begin(), table.size(), not_less_than_key(keyToSearch)); 144 table_t::const_iterator i= partition_point_n(table.begin(), table.size(), not_less_than_key(keyToSearch));
145 if(i != table.end() && eq_n<nsiz>(keyToSearch, i->key)) 145 if(i != table.end() && eq_n<nsiz>(keyToSearch, i->key))
146 { 146 {
147 *scilab_funptr = i->data; 147 *scilab_funptr = i->data;
148 return TRUE; 148 return TRUE;
149 } 149 }
150 else 150 else
151 { 151 {
152 return FALSE; 152 return FALSE;
153 } 153 }
@@ -158,12 +158,12 @@ static BOOL doBackSearchFunction(int *key, int *scilab_funptr)
158{ 158{
159 table_t::const_iterator i= std::find_if(table.begin(), table.end() 159 table_t::const_iterator i= std::find_if(table.begin(), table.end()
160 , equal_data(*scilab_funptr)); 160 , equal_data(*scilab_funptr));
161 if( i != table.end()) 161 if( i != table.end())
162 { 162 {
163 copy_n<nsiz>(i->key, key); 163 copy_n<nsiz>(i->key, key);
164 return TRUE; 164 return TRUE;
165 } 165 }
166 else 166 else
167 { 167 {
168 return FALSE; 168 return FALSE;
169 } 169 }
@@ -171,13 +171,13 @@ static BOOL doBackSearchFunction(int *key, int *scilab_funptr)
171/*----------------------------------------------------------------------------*/ 171/*----------------------------------------------------------------------------*/
172static BOOL doEnterFunction(int *key,char *name, int *scilab_funptr) 172static BOOL doEnterFunction(int *key,char *name, int *scilab_funptr)
173{ 173{
174 if(table.size() < MAXELEMENTFUNCTIONLIST) 174 if(table.size() < MAXELEMENTFUNCTIONLIST)
175 { 175 {
176 entry tmp(*scilab_funptr, name); 176 entry tmp(*scilab_funptr, name);
177 // insert before upper bound : first elt such that key<elt 177 // insert before upper bound : first elt such that key<elt
178 table.insert(partition_point_n(table.begin(), table.size() 178 table.insert(partition_point_n(table.begin(), table.size()
179 , key_less_than(tmp.key)), tmp); 179 , key_less_than(tmp.key)), tmp);
180 if(table.size() > hashtable_core_maxFilled) 180 if(table.size() > hashtable_core_maxFilled)
181 { 181 {
182 hashtable_core_maxFilled = table.size(); 182 hashtable_core_maxFilled = table.size();
183 } 183 }
@@ -194,14 +194,14 @@ static BOOL doDeleteFunction(int *key, int *scilab_funptr)
194 , not_less_than_key(key)) 194 , not_less_than_key(key))
195 , table.end(), equal_data(*scilab_funptr))); 195 , table.end(), equal_data(*scilab_funptr)));
196 196
197 if( i != table.end() ) 197 if( i != table.end() )
198 { 198 {
199 // entry found -> erase it 199 // entry found -> erase it
200 table.erase(i); 200 table.erase(i);
201 return TRUE; 201 return TRUE;
202 } 202 }
203 else 203 else
204 { 204 {
205 // not found 205 // not found
206 return FALSE; 206 return FALSE;
207 } 207 }
@@ -234,24 +234,24 @@ struct has_namefunction : std::unary_function<entry const&, bool> {
234 234
235struct copy_name : std::unary_function<entry const&, char**> { 235struct copy_name : std::unary_function<entry const&, char**> {
236 copy_name(char** n): names(n) { } 236 copy_name(char** n): names(n) { }
237 char** operator()(entry const& e) 237 char** operator()(entry const& e)
238 { 238 {
239 if(e.namefunction[0] != '\0') 239 if(e.namefunction[0] != '\0')
240 { 240 {
241 *names = strdup(e.namefunction); 241 *names = strdup(e.namefunction);
242 ++names; 242 ++names;
243 } 243 }
244 return names; 244 return names;
245 } 245 }
246 246
247 char** names; 247 char** names;
248}; 248};
249/*----------------------------------------------------------------------------*/ 249/*----------------------------------------------------------------------------*/
250char **GetFunctionsList(int *sizeList) 250char **GetFunctionsList(int *sizeList)
251{ 251{
252 *sizeList= std::count_if(table.begin(), table.end(), has_namefunction()); 252 *sizeList= std::count_if(table.begin(), table.end(), has_namefunction());
253 char **ListFunctions = static_cast<char**>(MALLOC(sizeof(char*)*(*sizeList))); 253 char **ListFunctions = static_cast<char**>(MALLOC(sizeof(char*)*(*sizeList)));
254 if ( ListFunctions ) 254 if ( ListFunctions )
255 { 255 {
256 std::for_each(table.begin(), table.end(), copy_name(ListFunctions)); 256 std::for_each(table.begin(), table.end(), copy_name(ListFunctions));
257 } 257 }
@@ -265,7 +265,7 @@ struct equal_name : std::unary_function<entry const&, bool>
265 char const* const name; 265 char const* const name;
266}; 266};
267/*----------------------------------------------------------------------------*/ 267/*----------------------------------------------------------------------------*/
268BOOL ExistFunction(char *name) 268BOOL ExistFunction(char *name)
269{ 269{
270 return (std::find_if(table.begin(), table.end(), equal_name(name)) == table.end()) ? FALSE : TRUE ; 270 return (std::find_if(table.begin(), table.end(), equal_name(name)) == table.end()) ? FALSE : TRUE ;
271} 271}
diff --git a/scilab/modules/core/src/cpp/search_functions.cpp b/scilab/modules/core/src/cpp/search_functions.cpp
index ab84e4a4..e845812 100644
--- a/scilab/modules/core/src/cpp/search_functions.cpp
+++ b/scilab/modules/core/src/cpp/search_functions.cpp
@@ -1,10 +1,11 @@
1#include <cstdlib> 1#include <cstdlib>
2#include <algorithm> 2#include <algorithm>
3#include "unrolled_algorithms.hxx"
3extern "C" { 4extern "C" {
4#include "stack-c.h" 5#include "stack-c.h"
5#include "stack-def.h" /* C2F(basbrk) */ 6#include "stack-def.h" /* C2F(basbrk) */
6#include "intmacr2tree.h" /*#define idstk(x,y) (C2F(vstk).idstk+(x-1)+(y-1)*nsiz) */ 7#include "intmacr2tree.h" /*#define idstk(x,y) (C2F(vstk).idstk+(x-1)+(y-1)*nsiz) */
7int C2F(eqid)(int const*x, int const*y); 8
8void C2F(siflibs)(int* id, int* k_ptr, int* istr, int* lbibn, int* nbibn, int* ilp, int* nn, int* should_return); 9void C2F(siflibs)(int* id, int* k_ptr, int* istr, int* lbibn, int* nbibn, int* ilp, int* nn, int* should_return);
9void C2F(sivars)(int* id, int* should_return); 10void C2F(sivars)(int* id, int* should_return);
10void C2F(namstr)(int* id, int* str, int* n, char const* job); 11void C2F(namstr)(int* id, int* str, int* n, char const* job);
@@ -17,8 +18,9 @@ namespace {
17 int const nclas= 29; 18 int const nclas= 29;
18 char const from_id=1; 19 char const from_id=1;
19 20
21 // directly convert from id to upper char
20 int upper_char(int id){ return std::abs((int)((id & 0x80) ? (id |0xffffff00) : (id & 0xff))); } 22 int upper_char(int id){ return std::abs((int)((id & 0x80) ? (id |0xffffff00) : (id & 0xff))); }
21 23 // gives the discriminating char (either first of second if first=percent)
22 int id_char(int const* id){ 24 int id_char(int const* id){
23 int ch(upper_char(*id)); 25 int ch(upper_char(*id));
24 if(ch == percent){ 26 if(ch == percent){
@@ -27,7 +29,7 @@ namespace {
27 return ch; 29 return ch;
28 } 30 }
29} 31}
30 32// search for an id in the libraries
31void C2F(siflibs)(int* id, int* k_ptr, int* istr, int* lbibn_ptr, int* nbibn_ptr, int* ilp_ptr, int* nn_ptr, int* should_return){ 33void C2F(siflibs)(int* id, int* k_ptr, int* istr, int* lbibn_ptr, int* nbibn_ptr, int* ilp_ptr, int* nn_ptr, int* should_return){
32 static int const* const lstk_ptr = (int*)C2F(vstk).lstk-1; 34 static int const* const lstk_ptr = (int*)C2F(vstk).lstk-1;
33 static int const* const istk_ptr = ((int*)C2F(stack).Stk)-1; 35 static int const* const istk_ptr = ((int*)C2F(stack).Stk)-1;
@@ -47,7 +49,7 @@ void C2F(siflibs)(int* id, int* k_ptr, int* istr, int* lbibn_ptr, int* nbibn_ptr
47 if(n != 0){ 49 if(n != 0){
48 int iln= ilp+nclas+1+(istk_ptr[ilp+ip-1]-1)*nsiz; 50 int iln= ilp+nclas+1+(istk_ptr[ilp+ip-1]-1)*nsiz;
49 for(int i= 1; i<=n; ++i, iln+= nsiz){ 51 for(int i= 1; i<=n; ++i, iln+= nsiz){
50 if(C2F(eqid)(id, istk_ptr+iln)){ // 39 52 if(eq_n<nsiz>(id, istk_ptr+iln)){ // 39
51 if((Fin == -1) || (Fin == -3)){ 53 if((Fin == -1) || (Fin == -3)){
52 C2F(com).fun= k; 54 C2F(com).fun= k;
53 Fin= i; 55 Fin= i;
@@ -81,7 +83,7 @@ void C2F(siflibs)(int* id, int* k_ptr, int* istr, int* lbibn_ptr, int* nbibn_ptr
81 return; 83 return;
82} 84}
83 85
84 86// search for an id in vars
85void C2F(sivars)(int* id, int* should_return){ 87void C2F(sivars)(int* id, int* should_return){
86 int* const lstk_ptr = (int*)C2F(vstk).lstk-1; 88 int* const lstk_ptr = (int*)C2F(vstk).lstk-1;
87 89
@@ -89,7 +91,7 @@ void C2F(sivars)(int* id, int* should_return){
89 // idstk(x,y) (C2F(vstk).idstk+(x-1)+(y-1)*nsiz) 91 // idstk(x,y) (C2F(vstk).idstk+(x-1)+(y-1)*nsiz)
90 int* id_addr=C2F(vstk).idstk; 92 int* id_addr=C2F(vstk).idstk;
91 for( *should_return= f_false, k= Bot-1, id_addr+=(k-1)*nsiz 93 for( *should_return= f_false, k= Bot-1, id_addr+=(k-1)*nsiz
92 ; k <= C2F(vstk).isiz && !C2F(eqid)(id_addr, id); ++k, id_addr+=nsiz){ 94 ; k <= C2F(vstk).isiz && !eq_n<nsiz>(id_addr, id); ++k, id_addr+=nsiz){
93 } 95 }
94 if( k <= C2F(vstk).isiz ){// eq_id 96 if( k <= C2F(vstk).isiz ){// eq_id
95 int il=lstk_ptr[k];//iadr() 97 int il=lstk_ptr[k];//iadr()
diff --git a/scilab/modules/core/src/cpp/unrolled_algorithms.hxx b/scilab/modules/core/src/cpp/unrolled_algorithms.hxx
index f2ef6c1..8bac872 100644
--- a/scilab/modules/core/src/cpp/unrolled_algorithms.hxx
+++ b/scilab/modules/core/src/cpp/unrolled_algorithms.hxx
@@ -1,69 +1,81 @@
1/* 1/*
2* Scilab ( http://www.scilab.org/ ) - This file is part of Scilab 2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3* Copyright (C) 2010 - DIGITEO - Bernard HUGUENEY 3 * Copyright (C) 2010 - DIGITEO - Bernard HUGUENEY
4* 4 *
5* This file must be used under the terms of the CeCILL. 5 * This file must be used under the terms of the CeCILL.
6* This source file is licensed as described in the file COPYING, which 6 * This source file is licensed as described in the file COPYING, which
7* you should have received as part of this distribution. The terms 7 * you should have received as part of this distribution. The terms
8* are also available at 8 * are also available at
9* http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt 9 * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10* 10 *
11*/ 11 */
12/*-----------------------------------------------------------------------------------*/ 12/*-----------------------------------------------------------------------------------*/
13#ifndef UNROLLED_ALGORITHMS_HXX 13#ifndef UNROLLED_ALGORITHMS_HXX
14#define UNROLLED_ALGORITHMS_HXX 14#define UNROLLED_ALGORITHMS_HXX
15 15
16namespace scilab { 16namespace {
17 namespace core { 17 /*
18 /* 18 * generic template unrolling for small vectors
19 * generic template unrolling for small vectors 19 */
20 */
21 20
22 template<typename It1, typename It2, int N> struct eq_n_t { 21 template<typename It1, typename It2, int N> struct eq_n_t {
23 bool operator()(It1 i1, It2 i2) const { 22 bool operator()(It1 i1, It2 i2) const {
24 return (*i1 == *i2) && eq_n_t<It1, It2, N-1>()(++i1, ++i2) ; 23 return (*i1 == *i2) && eq_n_t<It1, It2, N-1>()(++i1, ++i2) ;
25 } 24 }
26 }; 25 };
27 template<typename It1, typename It2> struct eq_n_t<It1, It2, 0> { 26 template<typename It1, typename It2> struct eq_n_t<It1, It2, 0> {
28 bool operator()(It1 i1, It2 i2) const { 27 bool operator()(It1 i1, It2 i2) const {
29 return true ; 28 return true ;
30 } 29 }
31 }; 30 };
32 template<int N, typename It1, typename It2> bool eq_n(It1 i1, It2 i2) { 31 template<int N, typename It1, typename It2> bool eq_n(It1 i1, It2 i2) {
33 return eq_n_t<It1, It2, N>()(i1, i2); 32 return eq_n_t<It1, It2, N>()(i1, i2);
34 } 33 }
34 // ensure most efficient inlining irrespectively of optimization compiler options for ids of nsiz=6 ints
35 template<> bool eq_n<6,int const*, int const*>(int const* id1, int const* id2) {
36 return (id1[0]==id2[0]) && (id1[1]==id2[1]) && (id1[2]==id2[2]) && (id1[3]==id2[3]) && (id1[4]==id2[4]) && (id1[5]==id2[5]);
37 }
35 38
36 template<typename It1, typename It2, int N> struct less_n_t { 39 template<> bool eq_n<6,int const*, int*>(int const* id1, int* id2) {
37 bool operator()(It1 i1, It2 i2) const { 40 return (id1[0]==id2[0]) && (id1[1]==id2[1]) && (id1[2]==id2[2]) && (id1[3]==id2[3]) && (id1[4]==id2[4]) && (id1[5]==id2[5]);
38 return (*i1<*i2) ? true : ( (*i1>*i2) ? false : less_n_t<It1, It2, N-1>()(++i1, ++i2)); 41 }
39 } 42 template<> bool eq_n<6,int*, int const*>(int* id1, int const* id2) {
40 }; 43 return (id1[0]==id2[0]) && (id1[1]==id2[1]) && (id1[2]==id2[2]) && (id1[3]==id2[3]) && (id1[4]==id2[4]) && (id1[5]==id2[5]);
41 template<typename It1, typename It2> struct less_n_t<It1, It2, 0> { 44 }
42 bool operator()(It1 i1, It2 i2) const { 45 template<> bool eq_n<6,int*, int*>(int* id1, int* id2) {
43 return false ; 46 return (id1[0]==id2[0]) && (id1[1]==id2[1]) && (id1[2]==id2[2]) && (id1[3]==id2[3]) && (id1[4]==id2[4]) && (id1[5]==id2[5]);
44 } 47 }
45 };
46 48
47 template<int N, typename It1, typename It2> bool less_n(It1 i1, It2 i2) { 49 template<typename It1, typename It2, int N> struct less_n_t {
48 return less_n_t<It1, It2, N>()(i1, i2); 50 bool operator()(It1 i1, It2 i2) const {
49 } 51 return (*i1<*i2) ? true : ( (*i1>*i2) ? false : less_n_t<It1, It2, N-1>()(++i1, ++i2));
52 }
53 };
54 template<typename It1, typename It2> struct less_n_t<It1, It2, 0> {
55 bool operator()(It1 i1, It2 i2) const {
56 return false ;
57 }
58 };
50 59
51 template<typename In, typename Out, int N> struct copy_n_t { 60 template<int N, typename It1, typename It2> bool less_n(It1 i1, It2 i2) {
52 Out operator()(In in, Out out) const { 61 return less_n_t<It1, It2, N>()(i1, i2);
53 *out= *in; 62 }
54 return copy_n_t<In, Out, N-1>()(++in, ++out); 63
55 } 64 template<typename In, typename Out, int N> struct copy_n_t {
56 }; 65 Out operator()(In in, Out out) const {
57 template<typename In, typename Out> struct copy_n_t<In, Out, 0> { 66 *out= *in;
58 Out operator()(In, Out out) const { 67 return copy_n_t<In, Out, N-1>()(++in, ++out);
59 return out; 68 }
60 } 69 };
61 }; 70 template<typename In, typename Out> struct copy_n_t<In, Out, 0> {
62 template<int N, typename In, typename Out> Out copy_n(In in, Out out) { 71 Out operator()(In, Out out) const {
63 return copy_n_t<In, Out, N>()(in, out); 72 return out;
64 } 73 }
74 };
75 template<int N, typename In, typename Out> Out copy_n(In in, Out out) {
76 return copy_n_t<In, Out, N>()(in, out);
77 }
65 78
66 }
67} 79}
68#endif 80#endif
69/*-----------------------------------------------------------------------------------*/ 81/*-----------------------------------------------------------------------------------*/