summaryrefslogtreecommitdiff
path: root/boost/gil/channel.hpp
blob: 0ec67aeea6b7516105e83483e3a271734a407864 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
//
// Copyright 2005-2007 Adobe Systems Incorporated
//
// Distributed under the Boost Software License, Version 1.0
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
#ifndef BOOST_GIL_CHANNEL_HPP
#define BOOST_GIL_CHANNEL_HPP

#include <boost/gil/utilities.hpp>

#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#include <boost/integer/integer_mask.hpp>
#include <boost/type_traits/remove_cv.hpp>

#include <cassert>
#include <cstdint>
#include <limits>

#ifdef BOOST_GIL_DOXYGEN_ONLY
/// \def BOOST_GIL_CONFIG_HAS_UNALIGNED_ACCESS
/// \brief Define to allow unaligned memory access for models of packed channel value.
/// Theoretically (or historically?) on platforms which support dereferencing on
/// non-word memory boundary, unaligned access may result in performance improvement.
/// \warning Unfortunately, this optimization may be a C/C++ strict aliasing rules
/// violation, if accessed data buffer has effective type that cannot be aliased
/// without leading to undefined behaviour.
#define BOOST_GIL_CONFIG_HAS_UNALIGNED_ACCESS
#endif

#ifdef BOOST_GIL_CONFIG_HAS_UNALIGNED_ACCESS
#if defined(sun) || defined(__sun) || \             // SunOS
    defined(__osf__) || defined(__osf) || \         // Tru64
    defined(_hpux) || defined(hpux) || \            // HP-UX
    defined(__arm__) || defined(__ARM_ARCH) || \    // ARM
    defined(_AIX)                                   // AIX
#error Unaligned access strictly disabled for some UNIX platforms or ARM architecture
#elif defined(__i386__) || defined(__x86_64__) || defined(__vax__)
    // The check for little-endian architectures that tolerate unaligned memory
    // accesses is just an optimization. Nothing will break if it fails to detect
    // a suitable architecture.
    //
    // Unfortunately, this optimization may be a C/C++ strict aliasing rules violation
    // if accessed data buffer has effective type that cannot be aliased
    // without leading to undefined behaviour.
BOOST_PRAGMA_MESSAGE("CAUTION: Unaligned access tolerated on little-endian may cause undefined behaviour")
#else
#error Unaligned access disabled for unknown platforms and architectures
#endif
#endif // defined(BOOST_GIL_CONFIG_HAS_UNALIGNED_ACCESS)

namespace boost { namespace gil {

///////////////////////////////////////////
////  channel_traits
////
////  \ingroup ChannelModel
////  \class channel_traits
////  \brief defines properties of channels, such as their range and associated types
////
////  The channel traits must be defined for every model of ChannelConcept
////  Default traits are provided. For built-in types the default traits use
////  built-in pointer and reference and the channel range is the physical
////  range of the type. For classes, the default traits forward the associated types
////  and range to the class.
////
///////////////////////////////////////////

namespace detail {
    template <typename T, bool is_class> struct channel_traits_impl;

    // channel traits for custom class
    template <typename T>
    struct channel_traits_impl<T, true> {
        typedef typename T::value_type      value_type;
        typedef typename T::reference       reference;
        typedef typename T::pointer         pointer;
        typedef typename T::const_reference const_reference;
        typedef typename T::const_pointer   const_pointer;
        BOOST_STATIC_CONSTANT(bool, is_mutable=T::is_mutable);
        static value_type min_value() { return T::min_value(); }
        static value_type max_value() { return T::max_value(); }
    };

    // channel traits implementation for built-in integral or floating point channel type
    template <typename T>
    struct channel_traits_impl<T, false> {
        typedef T           value_type;
        typedef T&          reference;
        typedef T*          pointer;
        typedef const T&    const_reference;
        typedef T const*    const_pointer;
        BOOST_STATIC_CONSTANT(bool, is_mutable=true);
        static value_type min_value() { return (std::numeric_limits<T>::min)(); }
        static value_type max_value() { return (std::numeric_limits<T>::max)(); }
    };

    // channel traits implementation for constant built-in scalar or floating point type
    template <typename T>
    struct channel_traits_impl<const T, false> : public channel_traits_impl<T, false> {
        typedef const T&    reference;
        typedef const T*    pointer;
        BOOST_STATIC_CONSTANT(bool, is_mutable=false);
    };
}

/**
\ingroup ChannelModel
\brief Traits for channels. Contains the following members:
\code
template <typename Channel>
struct channel_traits {
    typedef ... value_type;
    typedef ... reference;
    typedef ... pointer;
    typedef ... const_reference;
    typedef ... const_pointer;

    static const bool is_mutable;
    static value_type min_value();
    static value_type max_value();
};
\endcode
*/
template <typename T>
struct channel_traits : public detail::channel_traits_impl<T, is_class<T>::value> {};

// Channel traits for C++ reference type - remove the reference
template <typename T> struct channel_traits<      T&> : public channel_traits<T> {};

// Channel traits for constant C++ reference type
template <typename T> struct channel_traits<const T&> : public channel_traits<T> {
    typedef typename channel_traits<T>::const_reference reference;
    typedef typename channel_traits<T>::const_pointer   pointer;
    BOOST_STATIC_CONSTANT(bool, is_mutable=false);
};

///////////////////////////////////////////
////
////  scoped_channel_value
////
///////////////////////////////////////////

/**
\defgroup ScopedChannelValue scoped_channel_value
\ingroup ChannelModel
\brief A channel adaptor that modifies the range of the source channel. Models: ChannelValueConcept

Example:
\code
// Create a double channel with range [-0.5 .. 0.5]
struct double_minus_half  { static double apply() { return -0.5; } };
struct double_plus_half   { static double apply() { return  0.5; } };
typedef scoped_channel_value<double, double_minus_half, double_plus_half> bits64custom_t;

// channel_convert its maximum should map to the maximum
bits64custom_t x = channel_traits<bits64custom_t>::max_value();
assert(x == 0.5);
uint16_t y = channel_convert<uint16_t>(x);
assert(y == 65535);
\endcode
*/

/// \ingroup ScopedChannelValue
/// \brief A channel adaptor that modifies the range of the source channel. Models: ChannelValueConcept
template <typename BaseChannelValue,        // base channel (models ChannelValueConcept)
          typename MinVal, typename MaxVal> // classes with a static apply() function returning the minimum/maximum channel values
struct scoped_channel_value {
    typedef scoped_channel_value    value_type;
    typedef value_type&             reference;
    typedef value_type*             pointer;
    typedef const value_type&       const_reference;
    typedef const value_type*       const_pointer;
    BOOST_STATIC_CONSTANT(bool, is_mutable=channel_traits<BaseChannelValue>::is_mutable);

    typedef BaseChannelValue base_channel_t;

    static value_type min_value() { return MinVal::apply(); }
    static value_type max_value() { return MaxVal::apply(); }

    scoped_channel_value() {}
    scoped_channel_value(const scoped_channel_value& c) : _value(c._value) {}
    scoped_channel_value(BaseChannelValue val) : _value(val) {}

    scoped_channel_value& operator++() { ++_value; return *this; }
    scoped_channel_value& operator--() { --_value; return *this; }

    scoped_channel_value operator++(int) { scoped_channel_value tmp=*this; this->operator++(); return tmp; }
    scoped_channel_value operator--(int) { scoped_channel_value tmp=*this; this->operator--(); return tmp; }

    template <typename Scalar2> scoped_channel_value& operator+=(Scalar2 v) { _value+=v; return *this; }
    template <typename Scalar2> scoped_channel_value& operator-=(Scalar2 v) { _value-=v; return *this; }
    template <typename Scalar2> scoped_channel_value& operator*=(Scalar2 v) { _value*=v; return *this; }
    template <typename Scalar2> scoped_channel_value& operator/=(Scalar2 v) { _value/=v; return *this; }

    scoped_channel_value& operator=(BaseChannelValue v) { _value=v; return *this; }
    operator BaseChannelValue() const { return _value; }
private:
    BaseChannelValue _value;
};

template <typename T>
struct float_point_zero
{
    static constexpr T apply() { return 0.0f; }
};

template <typename T>
struct float_point_one
{
    static constexpr T apply() { return 1.0f; }
};

///////////////////////////////////////////
////
////  Support for sub-byte channels. These are integral channels whose value is contained in a range of bits inside an integral type
////
///////////////////////////////////////////

// It is necessary for packed channels to have their own value type. They cannot simply use an integral large enough to store the data. Here is why:
// - Any operation that requires returning the result by value will otherwise return the built-in integral type, which will have incorrect range
//   That means that after getting the value of the channel we cannot properly do channel_convert, channel_invert, etc.
// - Two channels are declared compatible if they have the same value type. That means that a packed channel is incorrectly declared compatible with an integral type
namespace detail {
    // returns the smallest fast unsigned integral type that has at least NumBits bits
    template <int NumBits>
    struct min_fast_uint : public mpl::if_c< (NumBits<=8),
            uint_least8_t,
            typename mpl::if_c< (NumBits<=16),
                    uint_least16_t,
                    typename mpl::if_c< (NumBits<=32),
                            uint_least32_t,
                            uintmax_t
                    >::type
            >::type
          > {};

    template <int NumBits>
    struct num_value_fn : public mpl::if_c< ( NumBits < 32 )
                                          , uint32_t
                                          , uint64_t
                                          > {};

    template <int NumBits>
    struct max_value_fn : public mpl::if_c< ( NumBits <= 32 )
                                          , uint32_t
                                          , uint64_t
                                          > {};
}

/**
\defgroup PackedChannelValueModel packed_channel_value
\ingroup ChannelModel
\brief Represents the value of an unsigned integral channel operating over a bit range. Models: ChannelValueConcept
Example:
\code
// A 4-bit unsigned integral channel.
typedef packed_channel_value<4> bits4;

assert(channel_traits<bits4>::min_value()==0);
assert(channel_traits<bits4>::max_value()==15);
assert(sizeof(bits4)==1);
BOOST_STATIC_ASSERT((boost::is_integral<bits4>::value));
\endcode
*/

/// \ingroup PackedChannelValueModel
/// \brief The value of a subbyte channel. Models: ChannelValueConcept
template <int NumBits>
class packed_channel_value {

public:
    typedef typename detail::min_fast_uint<NumBits>::type integer_t;


    typedef packed_channel_value   value_type;
    typedef value_type&            reference;
    typedef const value_type&      const_reference;
    typedef value_type*            pointer;
    typedef const value_type*      const_pointer;

    static value_type min_value() { return 0; }
    static value_type max_value() { return low_bits_mask_t< NumBits >::sig_bits; }

    BOOST_STATIC_CONSTANT(bool, is_mutable=true);

    packed_channel_value() {}

    packed_channel_value(integer_t v) { _value = static_cast< integer_t >( v & low_bits_mask_t<NumBits>::sig_bits_fast ); }
    template <typename Scalar> packed_channel_value(Scalar v) { _value = packed_channel_value( static_cast< integer_t >( v ) ); }

    static unsigned int num_bits() { return NumBits; }

    operator integer_t() const { return _value; }
private:
    integer_t _value;
};

namespace detail {

template <std::size_t K>
struct static_copy_bytes {
    void operator()(const unsigned char* from, unsigned char* to) const {
        *to = *from;
        static_copy_bytes<K-1>()(++from,++to);
    }
};

template <>
struct static_copy_bytes<0> {
    void operator()(const unsigned char* , unsigned char*) const {}
};

template <typename Derived, typename BitField, int NumBits, bool Mutable>
class packed_channel_reference_base {
protected:
    typedef typename mpl::if_c<Mutable,void*,const void*>::type data_ptr_t;
public:
    data_ptr_t _data_ptr;   // void* pointer to the first byte of the bit range

    typedef packed_channel_value<NumBits>   value_type;
    typedef const Derived                   reference;
    typedef value_type*                     pointer;
    typedef const value_type*               const_pointer;
    BOOST_STATIC_CONSTANT(int,  num_bits=NumBits);
    BOOST_STATIC_CONSTANT(bool, is_mutable=Mutable);

    static value_type min_value()       { return channel_traits<value_type>::min_value(); }
    static value_type max_value()       { return channel_traits<value_type>::max_value(); }

    typedef BitField                       bitfield_t;
    typedef typename value_type::integer_t integer_t;

    packed_channel_reference_base(data_ptr_t data_ptr) : _data_ptr(data_ptr) {}
    packed_channel_reference_base(const packed_channel_reference_base& ref) : _data_ptr(ref._data_ptr) {}
    const Derived& operator=(integer_t v) const { set(v); return derived(); }

    const Derived& operator++() const { set(get()+1); return derived(); }
    const Derived& operator--() const { set(get()-1); return derived(); }

    Derived operator++(int) const { Derived tmp=derived(); this->operator++(); return tmp; }
    Derived operator--(int) const { Derived tmp=derived(); this->operator--(); return tmp; }

    template <typename Scalar2> const Derived& operator+=(Scalar2 v) const { set( static_cast<integer_t>(  get() + v )); return derived(); }
    template <typename Scalar2> const Derived& operator-=(Scalar2 v) const { set( static_cast<integer_t>(  get() - v )); return derived(); }
    template <typename Scalar2> const Derived& operator*=(Scalar2 v) const { set( static_cast<integer_t>(  get() * v )); return derived(); }
    template <typename Scalar2> const Derived& operator/=(Scalar2 v) const { set( static_cast<integer_t>(  get() / v )); return derived(); }

    operator integer_t() const { return get(); }
    data_ptr_t operator &() const {return _data_ptr;}
protected:

    typedef  typename detail::num_value_fn< NumBits >::type num_value_t;
    typedef  typename detail::max_value_fn< NumBits >::type max_value_t;

    static const num_value_t num_values = static_cast< num_value_t >( 1 ) << NumBits ;
    static const max_value_t max_val    = static_cast< max_value_t >( num_values - 1 );

#if defined(BOOST_GIL_CONFIG_HAS_UNALIGNED_ACCESS)
    const bitfield_t& get_data()                      const { return *static_cast<const bitfield_t*>(_data_ptr); }
    void              set_data(const bitfield_t& val) const {        *static_cast<      bitfield_t*>(_data_ptr) = val; }
#else
    bitfield_t get_data() const {
        bitfield_t ret;
        static_copy_bytes<sizeof(bitfield_t) >()(gil_reinterpret_cast_c<const unsigned char*>(_data_ptr),gil_reinterpret_cast<unsigned char*>(&ret));
        return ret;
    }
    void set_data(const bitfield_t& val) const {
        static_copy_bytes<sizeof(bitfield_t) >()(gil_reinterpret_cast_c<const unsigned char*>(&val),gil_reinterpret_cast<unsigned char*>(_data_ptr));
    }
#endif

private:
    void set(integer_t value) const {     // can this be done faster??
        this->derived().set_unsafe(((value % num_values) + num_values) % num_values);
    }
    integer_t get() const { return derived().get(); }
    const Derived& derived() const { return static_cast<const Derived&>(*this); }
};
}   // namespace detail

/**
\defgroup PackedChannelReferenceModel packed_channel_reference
\ingroup ChannelModel
\brief Represents a reference proxy to a channel operating over a bit range whose offset is fixed at compile time. Models ChannelConcept
Example:
\code
// Reference to a 2-bit channel starting at bit 1 (i.e. the second bit)
typedef const packed_channel_reference<uint16_t,1,2,true> bits2_1_ref_t;

uint16_t data=0;
bits2_1_ref_t channel_ref(&data);
channel_ref = channel_traits<bits2_1_ref_t>::max_value();   // == 3
assert(data == 6);                                          // == 3<<1 == 6
\endcode
*/

template <typename BitField,        // A type that holds the bits of the pixel from which the channel is referenced. Typically an integral type, like std::uint16_t
          int FirstBit, int NumBits,// Defines the sequence of bits in the data value that contain the channel
          bool Mutable>             // true if the reference is mutable
class packed_channel_reference;

template <typename BitField,        // A type that holds the bits of the pixel from which the channel is referenced. Typically an integral type, like std::uint16_t
          int NumBits,              // Defines the sequence of bits in the data value that contain the channel
          bool Mutable>             // true if the reference is mutable
class packed_dynamic_channel_reference;

/// \ingroup PackedChannelReferenceModel
/// \brief A constant subbyte channel reference whose bit offset is fixed at compile time. Models ChannelConcept
template <typename BitField, int FirstBit, int NumBits>
class packed_channel_reference<BitField,FirstBit,NumBits,false>
   : public detail::packed_channel_reference_base<packed_channel_reference<BitField,FirstBit,NumBits,false>,BitField,NumBits,false> {
    typedef detail::packed_channel_reference_base<packed_channel_reference<BitField,FirstBit,NumBits,false>,BitField,NumBits,false> parent_t;
    friend class packed_channel_reference<BitField,FirstBit,NumBits,true>;

    static const BitField channel_mask = static_cast< BitField >( parent_t::max_val ) << FirstBit;

    void operator=(const packed_channel_reference&);
public:
    typedef const packed_channel_reference<BitField,FirstBit,NumBits,false> const_reference;
    typedef const packed_channel_reference<BitField,FirstBit,NumBits,true>  mutable_reference;
    typedef typename parent_t::integer_t                           integer_t;

    explicit packed_channel_reference(const void* data_ptr) : parent_t(data_ptr) {}
    packed_channel_reference(const packed_channel_reference& ref) : parent_t(ref._data_ptr) {}
    packed_channel_reference(const mutable_reference& ref) : parent_t(ref._data_ptr) {}

    unsigned first_bit() const { return FirstBit; }

    integer_t get() const { return integer_t((this->get_data()&channel_mask) >> FirstBit); }
};

/// \ingroup PackedChannelReferenceModel
/// \brief A mutable subbyte channel reference whose bit offset is fixed at compile time. Models ChannelConcept
template <typename BitField, int FirstBit, int NumBits>
class packed_channel_reference<BitField,FirstBit,NumBits,true>
   : public detail::packed_channel_reference_base<packed_channel_reference<BitField,FirstBit,NumBits,true>,BitField,NumBits,true> {
    typedef detail::packed_channel_reference_base<packed_channel_reference<BitField,FirstBit,NumBits,true>,BitField,NumBits,true> parent_t;
    friend class packed_channel_reference<BitField,FirstBit,NumBits,false>;

    static const BitField channel_mask = static_cast< BitField >( parent_t::max_val ) << FirstBit;

public:
    typedef const packed_channel_reference<BitField,FirstBit,NumBits,false> const_reference;
    typedef const packed_channel_reference<BitField,FirstBit,NumBits,true>  mutable_reference;
    typedef typename parent_t::integer_t                           integer_t;

    explicit packed_channel_reference(void* data_ptr) : parent_t(data_ptr) {}
    packed_channel_reference(const packed_channel_reference& ref) : parent_t(ref._data_ptr) {}

    const packed_channel_reference& operator=(integer_t value) const { assert(value<=parent_t::max_val); set_unsafe(value); return *this; }
    const packed_channel_reference& operator=(const mutable_reference& ref) const { set_from_reference(ref.get_data()); return *this; }
    const packed_channel_reference& operator=(const const_reference&   ref) const { set_from_reference(ref.get_data()); return *this; }

    template <bool Mutable1>
    const packed_channel_reference& operator=(const packed_dynamic_channel_reference<BitField,NumBits,Mutable1>& ref) const { set_unsafe(ref.get()); return *this; }

    unsigned first_bit() const { return FirstBit; }

    integer_t get()                  const { return integer_t((this->get_data()&channel_mask) >> FirstBit); }
    void set_unsafe(integer_t value) const { this->set_data((this->get_data() & ~channel_mask) | (( static_cast< BitField >( value )<<FirstBit))); }
private:
    void set_from_reference(const BitField& other_bits) const { this->set_data((this->get_data() & ~channel_mask) | (other_bits & channel_mask)); }
};

} }  // namespace boost::gil

namespace std {
// We are forced to define swap inside std namespace because on some platforms (Visual Studio 8) STL calls swap qualified.
// swap with 'left bias':
// - swap between proxy and anything
// - swap between value type and proxy
// - swap between proxy and proxy

/// \ingroup PackedChannelReferenceModel
/// \brief swap for packed_channel_reference
template <typename BF, int FB, int NB, bool M, typename R> inline
void swap(const boost::gil::packed_channel_reference<BF,FB,NB,M> x, R& y) {
    boost::gil::swap_proxy<typename boost::gil::packed_channel_reference<BF,FB,NB,M>::value_type>(x,y);
}


/// \ingroup PackedChannelReferenceModel
/// \brief swap for packed_channel_reference
template <typename BF, int FB, int NB, bool M> inline
void swap(typename boost::gil::packed_channel_reference<BF,FB,NB,M>::value_type& x, const boost::gil::packed_channel_reference<BF,FB,NB,M> y) {
    boost::gil::swap_proxy<typename boost::gil::packed_channel_reference<BF,FB,NB,M>::value_type>(x,y);
}

/// \ingroup PackedChannelReferenceModel
/// \brief swap for packed_channel_reference
template <typename BF, int FB, int NB, bool M> inline
void swap(const boost::gil::packed_channel_reference<BF,FB,NB,M> x, const boost::gil::packed_channel_reference<BF,FB,NB,M> y) {
    boost::gil::swap_proxy<typename boost::gil::packed_channel_reference<BF,FB,NB,M>::value_type>(x,y);
}
}   // namespace std

namespace boost { namespace gil {

/**
\defgroup PackedChannelDynamicReferenceModel packed_dynamic_channel_reference
\ingroup ChannelModel
\brief Represents a reference proxy to a channel operating over a bit range whose offset is specified at run time. Models ChannelConcept

Example:
\code
// Reference to a 2-bit channel whose offset is specified at construction time
typedef const packed_dynamic_channel_reference<uint8_t,2,true> bits2_dynamic_ref_t;

uint16_t data=0;
bits2_dynamic_ref_t channel_ref(&data,1);
channel_ref = channel_traits<bits2_dynamic_ref_t>::max_value();     // == 3
assert(data == 6);                                                  // == (3<<1) == 6
\endcode
*/

/// \brief Models a constant subbyte channel reference whose bit offset is a runtime parameter. Models ChannelConcept
///        Same as packed_channel_reference, except that the offset is a runtime parameter
/// \ingroup PackedChannelDynamicReferenceModel
template <typename BitField, int NumBits>
class packed_dynamic_channel_reference<BitField,NumBits,false>
   : public detail::packed_channel_reference_base<packed_dynamic_channel_reference<BitField,NumBits,false>,BitField,NumBits,false> {
    typedef detail::packed_channel_reference_base<packed_dynamic_channel_reference<BitField,NumBits,false>,BitField,NumBits,false> parent_t;
    friend class packed_dynamic_channel_reference<BitField,NumBits,true>;

    unsigned _first_bit;     // 0..7

    void operator=(const packed_dynamic_channel_reference&);
public:
    typedef const packed_dynamic_channel_reference<BitField,NumBits,false> const_reference;
    typedef const packed_dynamic_channel_reference<BitField,NumBits,true>  mutable_reference;
    typedef typename parent_t::integer_t                          integer_t;

    packed_dynamic_channel_reference(const void* data_ptr, unsigned first_bit) : parent_t(data_ptr), _first_bit(first_bit) {}
    packed_dynamic_channel_reference(const const_reference&   ref) : parent_t(ref._data_ptr), _first_bit(ref._first_bit) {}
    packed_dynamic_channel_reference(const mutable_reference& ref) : parent_t(ref._data_ptr), _first_bit(ref._first_bit) {}

    unsigned first_bit() const { return _first_bit; }

    integer_t get() const {
        const BitField channel_mask = static_cast< integer_t >( parent_t::max_val ) <<_first_bit;
        return static_cast< integer_t >(( this->get_data()&channel_mask ) >> _first_bit );
    }
};

/// \brief Models a mutable subbyte channel reference whose bit offset is a runtime parameter. Models ChannelConcept
///        Same as packed_channel_reference, except that the offset is a runtime parameter
/// \ingroup PackedChannelDynamicReferenceModel
template <typename BitField, int NumBits>
class packed_dynamic_channel_reference<BitField,NumBits,true>
   : public detail::packed_channel_reference_base<packed_dynamic_channel_reference<BitField,NumBits,true>,BitField,NumBits,true> {
    typedef detail::packed_channel_reference_base<packed_dynamic_channel_reference<BitField,NumBits,true>,BitField,NumBits,true> parent_t;
    friend class packed_dynamic_channel_reference<BitField,NumBits,false>;

    unsigned _first_bit;

public:
    typedef const packed_dynamic_channel_reference<BitField,NumBits,false> const_reference;
    typedef const packed_dynamic_channel_reference<BitField,NumBits,true>  mutable_reference;
    typedef typename parent_t::integer_t                          integer_t;

    packed_dynamic_channel_reference(void* data_ptr, unsigned first_bit) : parent_t(data_ptr), _first_bit(first_bit) {}
    packed_dynamic_channel_reference(const packed_dynamic_channel_reference& ref) : parent_t(ref._data_ptr), _first_bit(ref._first_bit) {}

    const packed_dynamic_channel_reference& operator=(integer_t value) const { assert(value<=parent_t::max_val); set_unsafe(value); return *this; }
    const packed_dynamic_channel_reference& operator=(const mutable_reference& ref) const {  set_unsafe(ref.get()); return *this; }
    const packed_dynamic_channel_reference& operator=(const const_reference&   ref) const {  set_unsafe(ref.get()); return *this; }

    template <typename BitField1, int FirstBit1, bool Mutable1>
    const packed_dynamic_channel_reference& operator=(const packed_channel_reference<BitField1, FirstBit1, NumBits, Mutable1>& ref) const
        {  set_unsafe(ref.get()); return *this; }

    unsigned first_bit() const { return _first_bit; }

    integer_t get() const {
        const BitField channel_mask = static_cast< integer_t >( parent_t::max_val ) << _first_bit;
        return static_cast< integer_t >(( this->get_data()&channel_mask ) >> _first_bit );
    }

    void set_unsafe(integer_t value) const {
        const BitField channel_mask = static_cast< integer_t >( parent_t::max_val ) << _first_bit;
        this->set_data((this->get_data() & ~channel_mask) | value<<_first_bit);
    }
};
} }  // namespace boost::gil

namespace std {
// We are forced to define swap inside std namespace because on some platforms (Visual Studio 8) STL calls swap qualified.
// swap with 'left bias':
// - swap between proxy and anything
// - swap between value type and proxy
// - swap between proxy and proxy


/// \ingroup PackedChannelDynamicReferenceModel
/// \brief swap for packed_dynamic_channel_reference
template <typename BF, int NB, bool M, typename R> inline
void swap(const boost::gil::packed_dynamic_channel_reference<BF,NB,M> x, R& y) {
    boost::gil::swap_proxy<typename boost::gil::packed_dynamic_channel_reference<BF,NB,M>::value_type>(x,y);
}


/// \ingroup PackedChannelDynamicReferenceModel
/// \brief swap for packed_dynamic_channel_reference
template <typename BF, int NB, bool M> inline
void swap(typename boost::gil::packed_dynamic_channel_reference<BF,NB,M>::value_type& x, const boost::gil::packed_dynamic_channel_reference<BF,NB,M> y) {
    boost::gil::swap_proxy<typename boost::gil::packed_dynamic_channel_reference<BF,NB,M>::value_type>(x,y);
}

/// \ingroup PackedChannelDynamicReferenceModel
/// \brief swap for packed_dynamic_channel_reference
template <typename BF, int NB, bool M> inline
void swap(const boost::gil::packed_dynamic_channel_reference<BF,NB,M> x, const boost::gil::packed_dynamic_channel_reference<BF,NB,M> y) {
    boost::gil::swap_proxy<typename boost::gil::packed_dynamic_channel_reference<BF,NB,M>::value_type>(x,y);
}
}   // namespace std

namespace boost {

template <int NumBits>
struct is_integral<gil::packed_channel_value<NumBits> > : public mpl::true_ {};

template <typename BitField, int FirstBit, int NumBits, bool IsMutable>
struct is_integral<gil::packed_channel_reference<BitField,FirstBit,NumBits,IsMutable> > : public mpl::true_ {};

template <typename BitField, int NumBits, bool IsMutable>
struct is_integral<gil::packed_dynamic_channel_reference<BitField,NumBits,IsMutable> > : public mpl::true_ {};

template <typename BaseChannelValue, typename MinVal, typename MaxVal>
struct is_integral<gil::scoped_channel_value<BaseChannelValue,MinVal,MaxVal> > : public is_integral<BaseChannelValue> {};

} // namespace boost

// \brief Determines the fundamental type which may be used, e.g., to cast from larger to smaller channel types.
namespace boost { namespace gil {
template <typename T>
struct base_channel_type_impl { typedef T type; };

template <int N>
struct base_channel_type_impl<packed_channel_value<N> >
{ typedef typename packed_channel_value<N>::integer_t type; };

template <typename B, int F, int N, bool M>
struct base_channel_type_impl<packed_channel_reference<B, F, N, M> >
{ typedef typename packed_channel_reference<B,F,N,M>::integer_t type; };

template <typename B, int N, bool M>
struct base_channel_type_impl<packed_dynamic_channel_reference<B, N, M> >
{ typedef typename packed_dynamic_channel_reference<B,N,M>::integer_t type; };

template <typename ChannelValue, typename MinV, typename MaxV>
struct base_channel_type_impl<scoped_channel_value<ChannelValue, MinV, MaxV> >
{ typedef ChannelValue type; };

template <typename T>
struct base_channel_type : base_channel_type_impl<typename remove_cv<T>::type > {};

}} //namespace boost::gil

#endif