Boost GIL


channel.hpp
1 //
2 // Copyright 2005-2007 Adobe Systems Incorporated
3 //
4 // Distributed under the Boost Software License, Version 1.0
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
7 //
8 #ifndef BOOST_GIL_CHANNEL_HPP
9 #define BOOST_GIL_CHANNEL_HPP
10 
11 #include <boost/gil/utilities.hpp>
12 
13 #include <boost/assert.hpp>
14 #include <boost/config.hpp>
15 #include <boost/config/pragma_message.hpp>
16 #include <boost/integer/integer_mask.hpp>
17 
18 #include <cstdint>
19 #include <limits>
20 #include <type_traits>
21 
22 #ifdef BOOST_GIL_DOXYGEN_ONLY
23 #define BOOST_GIL_CONFIG_HAS_UNALIGNED_ACCESS
31 #endif
32 
33 #ifdef BOOST_GIL_CONFIG_HAS_UNALIGNED_ACCESS
34 #if defined(sun) || defined(__sun) || \ // SunOS
35  defined(__osf__) || defined(__osf) || \ // Tru64
36  defined(_hpux) || defined(hpux) || \ // HP-UX
37  defined(__arm__) || defined(__ARM_ARCH) || \ // ARM
38  defined(_AIX) // AIX
39 #error Unaligned access strictly disabled for some UNIX platforms or ARM architecture
40 #elif defined(__i386__) || defined(__x86_64__) || defined(__vax__)
41  // The check for little-endian architectures that tolerate unaligned memory
42  // accesses is just an optimization. Nothing will break if it fails to detect
43  // a suitable architecture.
44  //
45  // Unfortunately, this optimization may be a C/C++ strict aliasing rules violation
46  // if accessed data buffer has effective type that cannot be aliased
47  // without leading to undefined behaviour.
48 BOOST_PRAGMA_MESSAGE("CAUTION: Unaligned access tolerated on little-endian may cause undefined behaviour")
49 #else
50 #error Unaligned access disabled for unknown platforms and architectures
51 #endif
52 #endif // defined(BOOST_GIL_CONFIG_HAS_UNALIGNED_ACCESS)
53 
54 namespace boost { namespace gil {
55 
70 
71 namespace detail {
72 
73 template <typename T, bool IsClass>
74 struct channel_traits_impl;
75 
76 // channel traits for custom class
77 template <typename T>
78 struct channel_traits_impl<T, true>
79 {
80  using value_type = typename T::value_type;
81  using reference = typename T::reference;
82  using pointer = typename T::pointer;
83  using const_reference = typename T::const_reference;
84  using const_pointer = typename T::const_pointer;
85  static constexpr bool is_mutable = T::is_mutable;
86  static value_type min_value() { return T::min_value(); }
87  static value_type max_value() { return T::max_value(); }
88 };
89 
90 // channel traits implementation for built-in integral or floating point channel type
91 template <typename T>
92 struct channel_traits_impl<T, false>
93 {
94  using value_type = T;
95  using reference = T&;
96  using pointer = T*;
97  using const_reference = T const&;
98  using const_pointer = T const*;
99  static constexpr bool is_mutable = true;
100  static value_type min_value() { return (std::numeric_limits<T>::min)(); }
101  static value_type max_value() { return (std::numeric_limits<T>::max)(); }
102 };
103 
104 // channel traits implementation for constant built-in scalar or floating point type
105 template <typename T>
106 struct channel_traits_impl<T const, false> : channel_traits_impl<T, false>
107 {
108  using reference = T const&;
109  using pointer = T const*;
110  static constexpr bool is_mutable = false;
111 };
112 
113 } // namespace detail
114 
133 template <typename T>
134 struct channel_traits : detail::channel_traits_impl<T, std::is_class<T>::value> {};
135 
136 // Channel traits for C++ reference type - remove the reference
137 template <typename T>
138 struct channel_traits<T&> : channel_traits<T> {};
139 
140 // Channel traits for constant C++ reference type
141 template <typename T>
142 struct channel_traits<T const&> : channel_traits<T>
143 {
144  using reference = typename channel_traits<T>::const_reference;
145  using pointer = typename channel_traits<T>::const_pointer;
146  static constexpr bool is_mutable = false;
147 };
148 
152 
170 
176 template <typename BaseChannelValue, typename MinVal, typename MaxVal>
177 struct scoped_channel_value
178 {
179  using value_type = scoped_channel_value<BaseChannelValue, MinVal, MaxVal>;
180  using reference = value_type&;
181  using pointer = value_type*;
182  using const_reference = value_type const&;
183  using const_pointer = value_type const*;
184  static constexpr bool is_mutable = channel_traits<BaseChannelValue>::is_mutable;
185 
186  using base_channel_t = BaseChannelValue;
187 
188  static value_type min_value() { return MinVal::apply(); }
189  static value_type max_value() { return MaxVal::apply(); }
190 
191  scoped_channel_value() = default;
192  scoped_channel_value(const scoped_channel_value& c) : value_(c.value_) {}
193  scoped_channel_value(BaseChannelValue val) : value_(val) {}
194 
195  scoped_channel_value& operator++() { ++value_; return *this; }
196  scoped_channel_value& operator--() { --value_; return *this; }
197 
198  scoped_channel_value operator++(int) { scoped_channel_value tmp=*this; this->operator++(); return tmp; }
199  scoped_channel_value operator--(int) { scoped_channel_value tmp=*this; this->operator--(); return tmp; }
200 
201  template <typename Scalar2> scoped_channel_value& operator+=(Scalar2 v) { value_+=v; return *this; }
202  template <typename Scalar2> scoped_channel_value& operator-=(Scalar2 v) { value_-=v; return *this; }
203  template <typename Scalar2> scoped_channel_value& operator*=(Scalar2 v) { value_*=v; return *this; }
204  template <typename Scalar2> scoped_channel_value& operator/=(Scalar2 v) { value_/=v; return *this; }
205 
206  scoped_channel_value& operator=(BaseChannelValue v) { value_=v; return *this; }
207  operator BaseChannelValue() const { return value_; }
208 private:
209  BaseChannelValue value_{};
210 };
211 
212 template <typename T>
213 struct float_point_zero
214 {
215  static constexpr T apply() { return 0.0f; }
216 };
217 
218 template <typename T>
219 struct float_point_one
220 {
221  static constexpr T apply() { return 1.0f; }
222 };
223 
227 
228 // 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:
229 // - Any operation that requires returning the result by value will otherwise return the built-in integral type, which will have incorrect range
230 // That means that after getting the value of the channel we cannot properly do channel_convert, channel_invert, etc.
231 // - 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
232 namespace detail {
233 
234 // returns the smallest fast unsigned integral type that has at least NumBits bits
235 template <int NumBits>
236 struct min_fast_uint :
237  std::conditional
238  <
239  NumBits <= 8,
240  std::uint_least8_t,
241  typename std::conditional
242  <
243  NumBits <= 16,
244  std::uint_least16_t,
245  typename std::conditional
246  <
247  NumBits <= 32,
248  std::uint_least32_t,
249  std::uintmax_t
250  >::type
251  >::type
252  >
253 {};
254 
255 template <int NumBits>
256 struct num_value_fn
257  : std::conditional<NumBits < 32, std::uint32_t, std::uint64_t>
258 {};
259 
260 template <int NumBits>
261 struct max_value_fn
262  : std::conditional<NumBits <= 32, std::uint32_t, std::uint64_t>
263 {};
264 
265 } // namespace detail
266 
280 
283 template <int NumBits>
284 class packed_channel_value
285 {
286 public:
287  using integer_t = typename detail::min_fast_uint<NumBits>::type;
288 
289  using value_type = packed_channel_value<NumBits>;
290  using reference = value_type&;
291  using const_reference = value_type const&;
292  using pointer = value_type*;
293  using const_pointer = value_type const*;
294  static constexpr bool is_mutable = true;
295 
296  static value_type min_value() { return 0; }
297  static value_type max_value() { return low_bits_mask_t< NumBits >::sig_bits; }
298 
299  packed_channel_value() = default;
300  packed_channel_value(integer_t v)
301  {
302  value_ = static_cast<integer_t>(v & low_bits_mask_t<NumBits>::sig_bits_fast);
303  }
304 
305  template <typename Scalar>
306  packed_channel_value(Scalar v)
307  {
308  value_ = packed_channel_value(static_cast<integer_t>(v));
309  }
310 
311  static unsigned int num_bits() { return NumBits; }
312 
313  operator integer_t() const { return value_; }
314 
315 private:
316  integer_t value_{};
317 };
318 
319 namespace detail {
320 
321 template <std::size_t K>
322 struct static_copy_bytes
323 {
324  void operator()(unsigned char const* from, unsigned char* to) const
325  {
326  *to = *from;
327  static_copy_bytes<K - 1>()(++from, ++to);
328  }
329 };
330 
331 template <>
332 struct static_copy_bytes<0>
333 {
334  void operator()(unsigned char const*, unsigned char*) const {}
335 };
336 
337 template <typename Derived, typename BitField, int NumBits, bool IsMutable>
338 class packed_channel_reference_base
339 {
340 protected:
341  using data_ptr_t = typename std::conditional<IsMutable, void*, void const*>::type;
342 public:
343  data_ptr_t _data_ptr; // void* pointer to the first byte of the bit range
344 
345  using value_type = packed_channel_value<NumBits>;
346  using reference = const Derived;
347  using pointer = value_type *;
348  using const_pointer = const value_type *;
349  static constexpr int num_bits = NumBits;
350  static constexpr bool is_mutable = IsMutable;
351 
352  static value_type min_value() { return channel_traits<value_type>::min_value(); }
353  static value_type max_value() { return channel_traits<value_type>::max_value(); }
354 
355  using bitfield_t = BitField;
356  using integer_t = typename value_type::integer_t;
357 
358  packed_channel_reference_base(data_ptr_t data_ptr) : _data_ptr(data_ptr) {}
359  packed_channel_reference_base(const packed_channel_reference_base& ref) : _data_ptr(ref._data_ptr) {}
360  const Derived& operator=(integer_t v) const { set(v); return derived(); }
361 
362  const Derived& operator++() const { set(get()+1); return derived(); }
363  const Derived& operator--() const { set(get()-1); return derived(); }
364 
365  Derived operator++(int) const { Derived tmp=derived(); this->operator++(); return tmp; }
366  Derived operator--(int) const { Derived tmp=derived(); this->operator--(); return tmp; }
367 
368  template <typename Scalar2> const Derived& operator+=(Scalar2 v) const { set( static_cast<integer_t>( get() + v )); return derived(); }
369  template <typename Scalar2> const Derived& operator-=(Scalar2 v) const { set( static_cast<integer_t>( get() - v )); return derived(); }
370  template <typename Scalar2> const Derived& operator*=(Scalar2 v) const { set( static_cast<integer_t>( get() * v )); return derived(); }
371  template <typename Scalar2> const Derived& operator/=(Scalar2 v) const { set( static_cast<integer_t>( get() / v )); return derived(); }
372 
373  operator integer_t() const { return get(); }
374  data_ptr_t operator &() const {return _data_ptr;}
375 protected:
376 
377  using num_value_t = typename detail::num_value_fn<NumBits>::type;
378  using max_value_t = typename detail::max_value_fn<NumBits>::type;
379 
380  static const num_value_t num_values = static_cast< num_value_t >( 1 ) << NumBits ;
381  static const max_value_t max_val = static_cast< max_value_t >( num_values - 1 );
382 
383 #if defined(BOOST_GIL_CONFIG_HAS_UNALIGNED_ACCESS)
384  const bitfield_t& get_data() const { return *static_cast<const bitfield_t*>(_data_ptr); }
385  void set_data(const bitfield_t& val) const { *static_cast< bitfield_t*>(_data_ptr) = val; }
386 #else
387  bitfield_t get_data() const {
388  bitfield_t ret;
389  static_copy_bytes<sizeof(bitfield_t) >()(gil_reinterpret_cast_c<const unsigned char*>(_data_ptr),gil_reinterpret_cast<unsigned char*>(&ret));
390  return ret;
391  }
392  void set_data(const bitfield_t& val) const {
393  static_copy_bytes<sizeof(bitfield_t) >()(gil_reinterpret_cast_c<const unsigned char*>(&val),gil_reinterpret_cast<unsigned char*>(_data_ptr));
394  }
395 #endif
396 
397 private:
398  void set(integer_t value) const { // can this be done faster??
399  this->derived().set_unsafe(((value % num_values) + num_values) % num_values);
400  }
401  integer_t get() const { return derived().get(); }
402  const Derived& derived() const { return static_cast<const Derived&>(*this); }
403 };
404 } // namespace detail
405 
419 
423 template <typename BitField, int FirstBit, int NumBits, bool IsMutable>
424 class packed_channel_reference;
425 
429 template <typename BitField, int NumBits, bool IsMutable>
430 class packed_dynamic_channel_reference;
431 
434 template <typename BitField, int FirstBit, int NumBits>
435 class packed_channel_reference<BitField, FirstBit, NumBits, false>
436  : public detail::packed_channel_reference_base
437  <
438  packed_channel_reference<BitField, FirstBit, NumBits, false>,
439  BitField,
440  NumBits,
441  false
442  >
443 {
444  using parent_t = detail::packed_channel_reference_base
445  <
446  packed_channel_reference<BitField, FirstBit, NumBits, false>,
447  BitField,
448  NumBits,
449  false
450  >;
451 
452  friend class packed_channel_reference<BitField, FirstBit, NumBits, true>;
453 
454  static const BitField channel_mask = static_cast<BitField>(parent_t::max_val) << FirstBit;
455 
456  void operator=(packed_channel_reference const&);
457 public:
458  using const_reference = packed_channel_reference<BitField,FirstBit,NumBits,false> const;
459  using mutable_reference = packed_channel_reference<BitField,FirstBit,NumBits,true> const;
460  using integer_t = typename parent_t::integer_t;
461 
462  explicit packed_channel_reference(const void* data_ptr) : parent_t(data_ptr) {}
463  packed_channel_reference(const packed_channel_reference& ref) : parent_t(ref._data_ptr) {}
464  packed_channel_reference(const mutable_reference& ref) : parent_t(ref._data_ptr) {}
465 
466  unsigned first_bit() const { return FirstBit; }
467 
468  integer_t get() const { return integer_t((this->get_data()&channel_mask) >> FirstBit); }
469 };
470 
473 template <typename BitField, int FirstBit, int NumBits>
474 class packed_channel_reference<BitField,FirstBit,NumBits,true>
475  : public detail::packed_channel_reference_base<packed_channel_reference<BitField,FirstBit,NumBits,true>,BitField,NumBits,true>
476 {
477  using parent_t = detail::packed_channel_reference_base<packed_channel_reference<BitField,FirstBit,NumBits,true>,BitField,NumBits,true>;
478  friend class packed_channel_reference<BitField,FirstBit,NumBits,false>;
479 
480  static const BitField channel_mask = static_cast< BitField >( parent_t::max_val ) << FirstBit;
481 
482 public:
483  using const_reference = packed_channel_reference<BitField,FirstBit,NumBits,false> const;
484  using mutable_reference = packed_channel_reference<BitField,FirstBit,NumBits,true> const;
485  using integer_t = typename parent_t::integer_t;
486 
487  explicit packed_channel_reference(void* data_ptr) : parent_t(data_ptr) {}
488  packed_channel_reference(const packed_channel_reference& ref) : parent_t(ref._data_ptr) {}
489 
490  packed_channel_reference const& operator=(integer_t value) const
491  {
492  BOOST_ASSERT(value <= parent_t::max_val);
493  set_unsafe(value);
494  return *this;
495  }
496 
497  const packed_channel_reference& operator=(const mutable_reference& ref) const { set_from_reference(ref.get_data()); return *this; }
498  const packed_channel_reference& operator=(const const_reference& ref) const { set_from_reference(ref.get_data()); return *this; }
499 
500  template <bool Mutable1>
501  const packed_channel_reference& operator=(const packed_dynamic_channel_reference<BitField,NumBits,Mutable1>& ref) const { set_unsafe(ref.get()); return *this; }
502 
503  unsigned first_bit() const { return FirstBit; }
504 
505  integer_t get() const { return integer_t((this->get_data()&channel_mask) >> FirstBit); }
506  void set_unsafe(integer_t value) const { this->set_data((this->get_data() & ~channel_mask) | (( static_cast< BitField >( value )<<FirstBit))); }
507 private:
508  void set_from_reference(const BitField& other_bits) const { this->set_data((this->get_data() & ~channel_mask) | (other_bits & channel_mask)); }
509 };
510 
511 }} // namespace boost::gil
512 
513 namespace std {
514 // We are forced to define swap inside std namespace because on some platforms (Visual Studio 8) STL calls swap qualified.
515 // swap with 'left bias':
516 // - swap between proxy and anything
517 // - swap between value type and proxy
518 // - swap between proxy and proxy
519 
522 template <typename BF, int FB, int NB, bool M, typename R>
523 inline
524 void swap(boost::gil::packed_channel_reference<BF, FB, NB, M> const x, R& y)
525 {
526  boost::gil::swap_proxy
527  <
528  typename boost::gil::packed_channel_reference<BF, FB, NB, M>::value_type
529  >(x, y);
530 }
531 
532 
535 template <typename BF, int FB, int NB, bool M>
536 inline
537 void swap(
538  typename boost::gil::packed_channel_reference<BF, FB, NB, M>::value_type& x,
539  boost::gil::packed_channel_reference<BF, FB, NB, M> const y)
540 {
541  boost::gil::swap_proxy
542  <
543  typename boost::gil::packed_channel_reference<BF, FB, NB, M>::value_type
544  >(x,y);
545 }
546 
549 template <typename BF, int FB, int NB, bool M> inline
550 void swap(
551  boost::gil::packed_channel_reference<BF, FB, NB, M> const x,
552  boost::gil::packed_channel_reference<BF, FB, NB, M> const y)
553 {
554  boost::gil::swap_proxy
555  <
556  typename boost::gil::packed_channel_reference<BF, FB, NB, M>::value_type
557  >(x,y);
558 }
559 
560 } // namespace std
561 
562 namespace boost { namespace gil {
563 
578 
582 template <typename BitField, int NumBits>
583 class packed_dynamic_channel_reference<BitField,NumBits,false>
584  : public detail::packed_channel_reference_base<packed_dynamic_channel_reference<BitField,NumBits,false>,BitField,NumBits,false>
585 {
586  using parent_t = detail::packed_channel_reference_base<packed_dynamic_channel_reference<BitField,NumBits,false>,BitField,NumBits,false>;
587  friend class packed_dynamic_channel_reference<BitField,NumBits,true>;
588 
589  unsigned _first_bit; // 0..7
590 
591  void operator=(const packed_dynamic_channel_reference&);
592 public:
593  using const_reference = packed_dynamic_channel_reference<BitField,NumBits,false> const;
594  using mutable_reference = packed_dynamic_channel_reference<BitField,NumBits,true> const;
595  using integer_t = typename parent_t::integer_t;
596 
597  packed_dynamic_channel_reference(const void* data_ptr, unsigned first_bit) : parent_t(data_ptr), _first_bit(first_bit) {}
598  packed_dynamic_channel_reference(const const_reference& ref) : parent_t(ref._data_ptr), _first_bit(ref._first_bit) {}
599  packed_dynamic_channel_reference(const mutable_reference& ref) : parent_t(ref._data_ptr), _first_bit(ref._first_bit) {}
600 
601  unsigned first_bit() const { return _first_bit; }
602 
603  integer_t get() const {
604  const BitField channel_mask = static_cast< integer_t >( parent_t::max_val ) <<_first_bit;
605  return static_cast< integer_t >(( this->get_data()&channel_mask ) >> _first_bit );
606  }
607 };
608 
612 template <typename BitField, int NumBits>
613 class packed_dynamic_channel_reference<BitField,NumBits,true>
614  : public detail::packed_channel_reference_base<packed_dynamic_channel_reference<BitField,NumBits,true>,BitField,NumBits,true>
615 {
616  using parent_t = detail::packed_channel_reference_base<packed_dynamic_channel_reference<BitField,NumBits,true>,BitField,NumBits,true>;
617  friend class packed_dynamic_channel_reference<BitField,NumBits,false>;
618 
619  unsigned _first_bit;
620 
621 public:
622  using const_reference = packed_dynamic_channel_reference<BitField,NumBits,false> const;
623  using mutable_reference = packed_dynamic_channel_reference<BitField,NumBits,true> const;
624  using integer_t = typename parent_t::integer_t;
625 
626  packed_dynamic_channel_reference(void* data_ptr, unsigned first_bit) : parent_t(data_ptr), _first_bit(first_bit) {}
627  packed_dynamic_channel_reference(const packed_dynamic_channel_reference& ref) : parent_t(ref._data_ptr), _first_bit(ref._first_bit) {}
628 
629  packed_dynamic_channel_reference const& operator=(integer_t value) const
630  {
631  BOOST_ASSERT(value <= parent_t::max_val);
632  set_unsafe(value);
633  return *this;
634  }
635 
636  const packed_dynamic_channel_reference& operator=(const mutable_reference& ref) const { set_unsafe(ref.get()); return *this; }
637  const packed_dynamic_channel_reference& operator=(const const_reference& ref) const { set_unsafe(ref.get()); return *this; }
638 
639  template <typename BitField1, int FirstBit1, bool Mutable1>
640  const packed_dynamic_channel_reference& operator=(const packed_channel_reference<BitField1, FirstBit1, NumBits, Mutable1>& ref) const
641  { set_unsafe(ref.get()); return *this; }
642 
643  unsigned first_bit() const { return _first_bit; }
644 
645  integer_t get() const {
646  const BitField channel_mask = static_cast< integer_t >( parent_t::max_val ) << _first_bit;
647  return static_cast< integer_t >(( this->get_data()&channel_mask ) >> _first_bit );
648  }
649 
650  void set_unsafe(integer_t value) const {
651  const BitField channel_mask = static_cast< integer_t >( parent_t::max_val ) << _first_bit;
652  this->set_data((this->get_data() & ~channel_mask) | value<<_first_bit);
653  }
654 };
655 } } // namespace boost::gil
656 
657 namespace std {
658 // We are forced to define swap inside std namespace because on some platforms (Visual Studio 8) STL calls swap qualified.
659 // swap with 'left bias':
660 // - swap between proxy and anything
661 // - swap between value type and proxy
662 // - swap between proxy and proxy
663 
664 
667 template <typename BF, int NB, bool M, typename R> inline
668 void swap(const boost::gil::packed_dynamic_channel_reference<BF,NB,M> x, R& y) {
669  boost::gil::swap_proxy<typename boost::gil::packed_dynamic_channel_reference<BF,NB,M>::value_type>(x,y);
670 }
671 
672 
675 template <typename BF, int NB, bool M> inline
676 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) {
677  boost::gil::swap_proxy<typename boost::gil::packed_dynamic_channel_reference<BF,NB,M>::value_type>(x,y);
678 }
679 
682 template <typename BF, int NB, bool M> inline
683 void swap(const boost::gil::packed_dynamic_channel_reference<BF,NB,M> x, const boost::gil::packed_dynamic_channel_reference<BF,NB,M> y) {
684  boost::gil::swap_proxy<typename boost::gil::packed_dynamic_channel_reference<BF,NB,M>::value_type>(x,y);
685 }
686 } // namespace std
687 
688 // \brief Determines the fundamental type which may be used, e.g., to cast from larger to smaller channel types.
689 namespace boost { namespace gil {
690 template <typename T>
691 struct base_channel_type_impl { using type = T; };
692 
693 template <int N>
694 struct base_channel_type_impl<packed_channel_value<N> >
695 { using type = typename packed_channel_value<N>::integer_t; };
696 
697 template <typename B, int F, int N, bool M>
698 struct base_channel_type_impl<packed_channel_reference<B, F, N, M> >
699 {
700  using type = typename packed_channel_reference<B,F,N,M>::integer_t;
701 };
702 
703 template <typename B, int N, bool M>
704 struct base_channel_type_impl<packed_dynamic_channel_reference<B, N, M> >
705 {
706  using type = typename packed_dynamic_channel_reference<B,N,M>::integer_t;
707 };
708 
709 template <typename ChannelValue, typename MinV, typename MaxV>
710 struct base_channel_type_impl<scoped_channel_value<ChannelValue, MinV, MaxV> >
711 { using type = ChannelValue; };
712 
713 template <typename T>
714 struct base_channel_type : base_channel_type_impl<typename std::remove_cv<T>::type> {};
715 
716 }} //namespace boost::gil
717 
718 #endif
void swap(const boost::gil::packed_dynamic_channel_reference< BF, NB, M > x, const boost::gil::packed_dynamic_channel_reference< BF, NB, M > y)
swap for packed_dynamic_channel_reference
Definition: channel.hpp:683
Definition: algorithm.hpp:30
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.
Definition: channel.hpp:583
Definition: algorithm.hpp:133
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.
Definition: channel.hpp:613