~ubuntu-branches/ubuntu/trusty/enblend-enfuse/trusty

« back to all changes in this revision

Viewing changes to include/vigra_ext/FunctorAccessor.h

  • Committer: Package Import Robot
  • Author(s): Jackson Doak
  • Date: 2014-01-22 06:23:44 UTC
  • mfrom: (5.1.6 sid)
  • Revision ID: package-import@ubuntu.com-20140122062344-gdj5nf671oxprqq7
Tags: 4.1.2+dfsg-2ubuntu1
* Merge from Debian, remaining changes:
  - Build-depend on libglew-dev rather than libglew1.5-dev | libglew1.4-dev
    | libglew-dev.
  - Build using -O1 on arm

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// -*- c-basic-offset: 4 -*-
2
 
/** @file FunctorAccessor.h
3
 
 *
4
 
 *  @author Pablo d'Angelo <pablo.dangelo@web.de>
5
 
 *
6
 
 *  $Id: FunctorAccessor.h,v 1.5 2007/01/27 05:00:35 acmihal Exp $
7
 
 *
8
 
 *  This is free software; you can redistribute it and/or
9
 
 *  modify it under the terms of the GNU General Public
10
 
 *  License as published by the Free Software Foundation; either
11
 
 *  version 2 of the License, or (at your option) any later version.
12
 
 *
13
 
 *  This software 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 GNU
16
 
 *  Lesser General Public License for more details.
17
 
 *
18
 
 *  You should have received a copy of the GNU General Public
19
 
 *  License along with this software; if not, write to the Free Software
20
 
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
 
 *
22
 
 */
23
 
 
24
 
#ifndef _FUNCTORACCESSOR_H
25
 
#define _FUNCTORACCESSOR_H
26
 
 
27
 
#include <vigra/numerictraits.hxx>
28
 
 
29
 
namespace vigra_ext {
30
 
 
31
 
 
32
 
/** This class can be used to apply a function when reading
33
 
    the input image.
34
 
 
35
 
    Can be used to apply point operations temporarily, like scaling,
36
 
    gamma correction etc.
37
 
 
38
 
    This is a read only accessor, writing is not supported.
39
 
 */
40
 
template <class Functor, class Accessor>
41
 
class ReadFunctorAccessor
42
 
{
43
 
  public:
44
 
    typedef typename Functor::result_type value_type;
45
 
    ReadFunctorAccessor(Functor f, Accessor a)
46
 
        : m_f(f), m_a(a)
47
 
    {
48
 
    }
49
 
 
50
 
    /** Get functor result
51
 
    template <class A, class B>
52
 
    void function(A a, B b)
53
 
    {
54
 
    };
55
 
     */
56
 
 
57
 
    template <typename ITERATOR_, typename DIFFERENCE_>
58
 
    typename Functor::result_type operator()(ITERATOR_ const & i, DIFFERENCE_ d) const
59
 
    {
60
 
        return m_f(m_a(i,d));
61
 
    }
62
 
 
63
 
    /** Get functor result
64
 
     */
65
 
    template <class ITERATOR>
66
 
    typename Functor::result_type operator()(ITERATOR const & i) const {
67
 
                return m_f(m_a(i)); }
68
 
 
69
 
 
70
 
protected:
71
 
    Functor m_f;
72
 
    Accessor m_a;
73
 
};
74
 
 
75
 
/** This class can be used to apply a function when writing
76
 
    to an image
77
 
 
78
 
    Can be used to apply point operations temporarily, like scaling,
79
 
    gamma correction etc.
80
 
 
81
 
    This is a write only accessor, reading is not supported.
82
 
 */
83
 
template <class Functor, class Accessor>
84
 
class WriteFunctorAccessor
85
 
{
86
 
  public:
87
 
    typedef typename Functor::result_type value_type;
88
 
 
89
 
    WriteFunctorAccessor(Functor f, Accessor a)
90
 
        : m_f(f), m_a(a)
91
 
    {
92
 
    }
93
 
 
94
 
    /** Set functor result
95
 
     */
96
 
    template <class Value, class ITERATOR>
97
 
    void set(Value const & v, ITERATOR const & i) const
98
 
    {
99
 
        m_a.set(m_f(vigra::detail::RequiresExplicitCast<typename Functor::argument_type>::cast(v)), i);
100
 
    }
101
 
 
102
 
    /** Set functor result
103
 
     */
104
 
    template <class Value, class ITERATOR_, class DIFFERENCE_>
105
 
    void set(Value const & v, ITERATOR_ const & i, DIFFERENCE_ d) const
106
 
    {
107
 
        m_a.set(m_f(vigra::detail::RequiresExplicitCast<typename Functor::argument_type>::cast(v)),i,d);
108
 
    }
109
 
 
110
 
    Functor m_f;
111
 
    Accessor m_a;
112
 
};
113
 
 
114
 
/** define a write only accessor for a virtual Image<TinyVector<Acc1::value_type>, 2>
115
 
    image, which actually consists of two Images.
116
 
 
117
 
    Useful to split an image into gray and alpha images while loading, like it is
118
 
    shown in the following example:
119
 
 
120
 
    \code
121
 
        vigra::ImageImportInfo info(argv[1]);
122
 
 
123
 
        if(info.numBands() == 2 && info.numExtraBands() == 1)
124
 
        {
125
 
            vigra::BImage image;
126
 
            vigra::BImage mask;
127
 
            image.resize(info.width(), info.height());
128
 
            mask.resize(info.width(), info.height());
129
 
 
130
 
            // construct special reading accessor, to split
131
 
            // the image into two images while reading
132
 
            vigra_ext::SplitVector2Accessor<BImage::Iterator,
133
 
                                            BImage::Accessor,
134
 
                                            BImage::Iterator,
135
 
                                            BImage::Accessor>
136
 
                splitA(image.upperLeft(), image.accessor(),
137
 
                       mask.upperLeft(), mask.accessor());
138
 
 
139
 
            importImage(info, Diff2D(), splitA );
140
 
    \endcode
141
 
 */
142
 
template <class Iter1, class Acc1, class Iter2, class Acc2>
143
 
class SplitVector2Accessor
144
 
{
145
 
public:
146
 
    /** the vector's value_type
147
 
     */
148
 
    typedef vigra::TinyVector<typename Acc1::value_type, 2> value_type;
149
 
    typedef typename value_type::value_type component_type;
150
 
 
151
 
    /** Construct from two image iterators and associated accessors.
152
 
     */
153
 
    SplitVector2Accessor(Iter1 i1, Acc1 a1, Iter2 i2, Acc2 a2)
154
 
        : i1_(i1), a1_(a1), i2_(i2), a2_(a2)
155
 
        {}
156
 
 
157
 
    /** scalar & scalar image */
158
 
    template <class V, class ITERATOR>
159
 
    void setComponent( V const & value, ITERATOR const & i, int idx ) const
160
 
    {
161
 
        switch (idx) {
162
 
        case 0:
163
 
            a1_.set(value, i1_, *i);
164
 
            break;
165
 
        case 1:
166
 
            a2_.set(value, i2_, *i);
167
 
            break;
168
 
        default:
169
 
            vigra_fail("too many components in input value");
170
 
        }
171
 
    }
172
 
 
173
 
        /** return the size (Number of Bands) */
174
 
        template <class ITERATOR>
175
 
        unsigned int size(ITERATOR const & i) const
176
 
        {
177
 
                return 2;
178
 
        }
179
 
 
180
 
    Iter1 i1_;
181
 
    Acc1  a1_;
182
 
    Iter2 i2_;
183
 
    Acc2  a2_;
184
 
};
185
 
 
186
 
/** split a vector image into a vector and a scalar image
187
 
 *
188
 
 *  like SplitVector2Accessor, but for the vector -> vector, scalar
189
 
 *  case.
190
 
 *
191
 
 *  the template parameter SIZE gives the length of each vector
192
 
 *  in the input image. components 0..SIZE-2, are put into the
193
 
 *  image 1 (must be a vector image), and component SIZE-1
194
 
 *  is stored in image 2 (should be a scalar image)
195
 
 */
196
 
template <class Iter1, class Acc1, class Iter2, class Acc2, int SIZE>
197
 
class SplitVectorNAccessor
198
 
{
199
 
public:
200
 
    /** the vector's value_type
201
 
     */
202
 
    typedef vigra::TinyVector<typename Acc1::value_type, SIZE> value_type;
203
 
    typedef typename value_type::value_type component_type;
204
 
 
205
 
    /** Construct from two image iterators and associated accessors.
206
 
     */
207
 
    SplitVectorNAccessor(Iter1 i1, Acc1 a1, Iter2 i2, Acc2 a2)
208
 
        : i1_(i1), a1_(a1), i2_(i2), a2_(a2)
209
 
        {}
210
 
 
211
 
    /** vector & scalar image */
212
 
    template <class V, class ITERATOR>
213
 
    void setComponent( V const & value, ITERATOR const & i, int idx ) const
214
 
    {
215
 
        if ( idx < SIZE - 1 ) {
216
 
            a1_.setComponent(value, i1_, *i, idx);
217
 
        } else if ( idx == SIZE - 1 ) {
218
 
            a2_.set(value, i2_, *i);
219
 
        } else {
220
 
            vigra_fail("too many components in input value");
221
 
        }
222
 
    }
223
 
 
224
 
        /** return the size (Number of Bands) */
225
 
        template <class ITERATOR>
226
 
        unsigned int size(ITERATOR const & i) const
227
 
        {
228
 
                return SIZE;
229
 
        }
230
 
 
231
 
    Iter1 i1_;
232
 
    Acc1  a1_;
233
 
    Iter2 i2_;
234
 
    Acc2  a2_;
235
 
};
236
 
 
237
 
/** merge two scalar images into a vector image.
238
 
 *
239
 
 *  the inverse to SplitVector2Accessor.
240
 
 *
241
 
 */
242
 
template <class Iter1, class Acc1, class Iter2, class Acc2>
243
 
class MergeScalarScalar2VectorAccessor
244
 
{
245
 
public:
246
 
    /** the vector's value_type
247
 
     */
248
 
    typedef vigra::TinyVector<typename Acc1::value_type, 2> value_type;
249
 
    typedef typename value_type::value_type component_type;
250
 
 
251
 
    /** Construct from two image iterators and associated accessors.
252
 
     */
253
 
    MergeScalarScalar2VectorAccessor(Iter1 i1, Acc1 a1, Iter2 i2, Acc2 a2)
254
 
        : i1_(i1), a1_(a1), i2_(i2), a2_(a2)
255
 
        {}
256
 
 
257
 
        /** read the current data item
258
 
        */
259
 
    template <class DIFFERENCE_>
260
 
    value_type operator()(DIFFERENCE_ const & d) const
261
 
    {
262
 
        return value_type(a1_(i1_, d), a2_(i2_, d));
263
 
    }
264
 
 
265
 
        /** read one component */
266
 
    template <class ITERATOR>
267
 
    component_type getComponent(ITERATOR const & i, int idx) const
268
 
    {
269
 
        switch (idx) {
270
 
        case 0:
271
 
            return a1_( i1_, *i );
272
 
        case 1:
273
 
            return a2_( i2_, *i );
274
 
        default:
275
 
            vigra_fail("too many components in input value");
276
 
            // never reached, but here to silence compiler
277
 
            exit(1);
278
 
        }
279
 
    }
280
 
 
281
 
        /** read one component, with offset */
282
 
    template <class ITERATOR, class DIFFERENCE_>
283
 
    component_type const & getComponent(ITERATOR const & i, DIFFERENCE_ const & d, int idx) const
284
 
    {
285
 
        i += d;
286
 
        switch (idx) {
287
 
        case 0:
288
 
            return a1_.getComponent(i1_, *i, idx);
289
 
        case 1:
290
 
            return a2_.getComponent(i2_, *i, idx);
291
 
        default:
292
 
            vigra_fail("too many components in input value");
293
 
        }
294
 
    }
295
 
 
296
 
        /** return the size (Number of Bands) */
297
 
        template <class ITERATOR>
298
 
        unsigned int size(ITERATOR const & i) const
299
 
        {
300
 
                return 2;
301
 
        }
302
 
 
303
 
    Iter1 i1_;
304
 
    Acc1  a1_;
305
 
    Iter2 i2_;
306
 
    Acc2  a2_;
307
 
};
308
 
 
309
 
 
310
 
/** merge a vector and a scalar image into a vector image.
311
 
 *
312
 
 *  This virtually "appends" the scalar image plane to
313
 
 *  the vector image.
314
 
 *
315
 
 *  the inverse to SplitVectorNAccessor.
316
 
 *
317
 
 */
318
 
template <class Iter1, class Acc1, class Iter2, class Acc2, int SIZE>
319
 
class MergeVectorScalar2VectorAccessor
320
 
{
321
 
public:
322
 
    /** the vector's value_type
323
 
     */
324
 
    typedef typename Acc1::value_type image1_type;
325
 
    typedef typename Acc2::value_type image2_type;
326
 
 
327
 
    typedef typename image1_type::value_type component_type;
328
 
 
329
 
    typedef vigra::TinyVector<component_type, SIZE> value_type;
330
 
 
331
 
    /** Construct from two image iterators and associated accessors.
332
 
     */
333
 
    MergeVectorScalar2VectorAccessor(Iter1 i1, Acc1 a1, Iter2 i2, Acc2 a2)
334
 
        : i1_(i1), a1_(a1), i2_(i2), a2_(a2)
335
 
        {}
336
 
 
337
 
        /** read the current data item
338
 
        */
339
 
    template <class DIFFERENCE_>
340
 
    value_type operator()(DIFFERENCE_ const & d) const
341
 
    {
342
 
        value_type ret;
343
 
        typename value_type::iterator it = ret.begin();
344
 
        const image1_type & i1 = a1_(i1_, d);
345
 
        for ( typename image1_type::const_iterator it1 = i1.begin();
346
 
             it1 != i1.end(); ++it1 )
347
 
        {
348
 
            *it = *it1;
349
 
            it++;
350
 
        }
351
 
        *it = a2_(i2_, d);
352
 
        return ret;
353
 
    }
354
 
 
355
 
        /** read one component */
356
 
    template <class ITERATOR>
357
 
    component_type getComponent(ITERATOR const & i, int idx) const
358
 
    {
359
 
        if ( idx < SIZE - 1 ) {
360
 
            return a1_.getComponent(i1_, *i, idx);
361
 
        } else if ( idx == SIZE - 1 ) {
362
 
            return a2_(i2_, *i);
363
 
        } else {
364
 
            vigra_fail("too many components in input value");
365
 
            // just to silence the compiler warning. this is
366
 
            // never reached, since vigra_fail will always
367
 
            // throw an exception.
368
 
            throw 0;
369
 
        }
370
 
    }
371
 
 
372
 
        /** read one component, with offset */
373
 
    template <class ITERATOR, class DIFFERENCE_>
374
 
    component_type const getComponent(ITERATOR i, DIFFERENCE_ const & d, int idx) const
375
 
    {
376
 
        i += d;
377
 
        if ( idx < SIZE - 1 ) {
378
 
            return a1_.getComponent(i1_, *i, idx);
379
 
        } else if ( idx == SIZE - 1 ) {
380
 
            return a2_(i2_, *i);
381
 
        } else {
382
 
            vigra_fail("too many components in input value");
383
 
            // just to silence the compiler warning. this is
384
 
            // never reached, since vigra_fail will always
385
 
            // throw an exception.
386
 
            throw 0;
387
 
        }
388
 
    }
389
 
 
390
 
 
391
 
        /** return the size (Number of Bands) */
392
 
        template <class ITERATOR>
393
 
        unsigned int size(ITERATOR const & i) const
394
 
        {
395
 
                return SIZE;
396
 
        }
397
 
 
398
 
    Iter1 i1_;
399
 
    Acc1  a1_;
400
 
    Iter2 i2_;
401
 
    Acc2  a2_;
402
 
};
403
 
 
404
 
 
405
 
/** An accessor to encapsulate write access to a multiband image,
406
 
    and move divide it into two images.
407
 
 
408
 
    This is particulary useful, if a multiband image should be splitted
409
 
    into separate images during import operations. Then one doesn't
410
 
    need to create a temporary image.
411
 
 
412
 
    This can be used to copy a 4 band image into a 3 band image
413
 
    and a 1 band image, with a single copyImage, or during other
414
 
    operations.
415
 
 
416
 
    For example, some images contain an alpha channel, and depending
417
 
    on the application, this doesn't need to have the same type, for
418
 
    example, float RGB channels, uint8 mask channel. Many algorithms
419
 
    provided by vigra also expect the masks and the image in separate
420
 
    images.
421
 
 
422
 
    The following image combinations are supported so far:
423
 
 
424
 
      - vector -> scalar, scalar
425
 
      - vector -> vector, scalar
426
 
 
427
 
    This accessor is quite slow. It checks the vector indicies on
428
 
    every access.
429
 
 
430
 
    @bug This is not a complete accessor, only write operations are supported.
431
 
    @bug value_type is not specified correctly, I don't know how to merge
432
 
         them properly with template programming.
433
 
 
434
 
    Requirements:
435
 
     both images need to have the same elementary type
436
 
*/
437
 
template <class Iter1, class Acc1, class Iter2, class Acc2, int SIZE>
438
 
class ImageSplittingAccessor
439
 
{
440
 
public:
441
 
    /** value type of image 1 */
442
 
    typedef typename Acc1::value_type image_type1;
443
 
 
444
 
    /** value type of image 2 */
445
 
    typedef typename Acc2::value_type image_type2;
446
 
 
447
 
    /** @BUG: how to combine two value types into one? */
448
 
    //    typedef image_type1 value_type;
449
 
 
450
 
        /** Construct from two image iterators and associated accessors.
451
 
        */
452
 
    ImageSplittingAccessor(Iter1 i1, Acc1 a1, Iter2 i2, Acc2 a2)
453
 
        : i1_(i1), a1_(a1), i2_(i2), a2_(a2)
454
 
    {}
455
 
 
456
 
    /** write value V into the two images.
457
 
     *
458
 
     *  V has to be a stl compatible vector type,
459
 
     *  the two images can be of vector or scalar types.
460
 
     *
461
 
     */
462
 
    template <class V, class ITERATOR>
463
 
    void setComponent(V const & value, ITERATOR const & i, int idx) const
464
 
    {
465
 
        setComponentIsScalar(value, i, idx,
466
 
                             vigra::NumericTraits<image_type1>::isScalar() );
467
 
    }
468
 
 
469
 
 
470
 
#if 0
471
 
        /** Write the current data item. The type <TT>V</TT> must be
472
 
            a sequence type, Likewise the value types
473
 
            of image 1 and image 2.
474
 
 
475
 
            Its size must be size(image_type1) + size(image_type2);
476
 
        
477
 
            The type <TT>V</TT> of the passed
478
 
            in <TT>value</TT> is automatically converted to <TT>VALUETYPE</TT>.
479
 
            In case of a conversion floating point -> intergral this includes rounding and clipping.
480
 
        */
481
 
    template <class V, class ITERATOR>
482
 
    void setVector2VectorVector(V const & value, ITERATOR const & i) const
483
 
    {
484
 
        // get pixels at current position indicated by iterator
485
 
        image_type1 & v1 = a1_(i);
486
 
        image_type2 & v2 = a2_(i2_, i - i1_);
487
 
        // TODO: check if the size of both images is correct
488
 
 
489
 
        // copy into first image
490
 
        typename V::iterator vIt = value.begin();
491
 
        typename image_type1::iterator v1It = v1.begin();
492
 
        while ( v1It != v1.end() && vIt != value.end()) {
493
 
            *v1It = detail::RequiresExplicitCast<VALUETYPE>::cast(*vIt);
494
 
            ++v1It;
495
 
            ++vIt;
496
 
        }
497
 
        // copy rest into second image
498
 
        typename image_type2::iterator v2It = v2.begin();
499
 
        while ( v2It != v1.end() && vIt != value.end()) {
500
 
            *v2It = detail::RequiresExplicitCast<VALUETYPE>::cast(*vIt);
501
 
            ++v2It;
502
 
            ++vIt;
503
 
        }
504
 
        
505
 
        
506
 
 
507
 
        for (int i=0; i < value.size(); i++) {
508
 
            if (i <
509
 
 
510
 
        *i = detail::RequiresExplicitCast<VALUETYPE>::cast(value); }
511
 
 
512
 
        /** Write the data item at an offset (can be 1D or 2D or higher order difference)..
513
 
            The type <TT>V</TT> of the passed
514
 
            in <TT>value</TT> is automatically converted to <TT>VALUETYPE</TT>.
515
 
            In case of a conversion floating point -> intergral this includes rounding and clipping.
516
 
        */
517
 
    template <class V, class ITERATOR, class DIFFERENCE_>
518
 
    void set(V const & value, ITERATOR const & i, DIFFERENCE_ const & diff) const
519
 
    {
520
 
        i[diff]= detail::RequiresExplicitCast<VALUETYPE>::cast(value);
521
 
    }
522
 
 
523
 
#endif
524
 
 
525
 
protected:
526
 
    /** if first dest image is scalar */
527
 
    template <class V, class ITERATOR>
528
 
    void setComponentIsScalar(V const & value, ITERATOR const & i, int idx,
529
 
                              vigra::VigraTrueType) const
530
 
    {
531
 
        setComponentScalarIsScalar(value, i, idx,
532
 
                                   vigra::NumericTraits<image_type2>::isScalar() );
533
 
    }
534
 
 
535
 
    /** if first dest image is vector image */
536
 
    template <class V, class ITERATOR>
537
 
    void setComponentIsScalar(V const & value, ITERATOR const & i, int idx,
538
 
                              vigra::VigraFalseType) const
539
 
    {
540
 
        setComponentVectorIsScalar(value, i, idx,
541
 
                                   vigra::NumericTraits<image_type2>::isScalar() );
542
 
    }
543
 
 
544
 
    /** if scalar & scalar image */
545
 
    template <class V, class ITERATOR>
546
 
    void setComponentScalarIsScalar(V const & value, ITERATOR const & i, int idx,
547
 
                                    vigra::VigraTrueType) const
548
 
    {
549
 
        switch (idx) {
550
 
        case 0:
551
 
            a1_.set(value, i);
552
 
            break;
553
 
        case 1:
554
 
            a2_.set(value, i2_, i - i1_);
555
 
            break;
556
 
        default:
557
 
            vigra_fail("too many components in input value");
558
 
        }
559
 
    }
560
 
 
561
 
    /** if scalar & vector image */
562
 
    template <class V, class ITERATOR>
563
 
    void setComponentScalarIsVector(V const & value, ITERATOR const & i, int idx,
564
 
                                    vigra::VigraTrueType) const
565
 
    {
566
 
        vigra_fail("vector -> scalar, vector accessor not implemented");
567
 
    }
568
 
 
569
 
    /** if vector & scalar image */
570
 
    template <class V, class ITERATOR>
571
 
    void setComponentVectorIsScalar(V const & value, ITERATOR const & i, int idx,
572
 
                                    vigra::VigraTrueType) const
573
 
    {
574
 
        image_type1 & v1 = a1_(i);
575
 
        typename image_type1::size_type s1 = v1.size();
576
 
        if (idx < s1) {
577
 
            a1_.setComponent(value, i, idx);
578
 
        } else if ( idx == s1) {
579
 
            a2_.set(value, i2_, i - i1_);
580
 
        } else {
581
 
            vigra_fail("too many components in input value");
582
 
        }
583
 
    }
584
 
 
585
 
    /** if vector & vector image */
586
 
    template <class V, class ITERATOR>
587
 
    void setComponentVectorIsVector(V const & value, ITERATOR const & i, int idx,
588
 
                                    vigra::VigraTrueType) const
589
 
    {
590
 
        vigra_fail("vector -> vector, vector accessor not implemented");
591
 
    }
592
 
 
593
 
    Iter1 i1_;
594
 
    Acc1  a1_;
595
 
    Iter2 i2_;
596
 
    Acc2  a2_;
597
 
};
598
 
 
599
 
/** a sample functor that can be used to multiply pixel values with a constant*/
600
 
template <class T>
601
 
struct Multiply
602
 
{
603
 
    typedef T result_type;
604
 
 
605
 
    Multiply(T factor)
606
 
        : m_factor(factor)
607
 
    {}
608
 
 
609
 
    template <class PixelType>
610
 
    PixelType operator()(PixelType const& v) const
611
 
    {
612
 
        return vigra::NumericTraits<result_type>::fromRealPromote(v * m_factor);
613
 
    }
614
 
 
615
 
    T m_factor;
616
 
};
617
 
 
618
 
}  // namespace
619
 
 
620
 
 
621
 
 
622
 
#endif // _FUNCTORACCESSOR_H