Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-11-15 09:12:38

0001 //
0002 // Copyright 2005-2007 Adobe Systems Incorporated
0003 //
0004 // Distributed under the Boost Software License, Version 1.0
0005 // See accompanying file LICENSE_1_0.txt or copy at
0006 // http://www.boost.org/LICENSE_1_0.txt
0007 //
0008 #ifndef BOOST_GIL_CHANNEL_HPP
0009 #define BOOST_GIL_CHANNEL_HPP
0010 
0011 #include <boost/gil/utilities.hpp>
0012 
0013 #include <boost/assert.hpp>
0014 #include <boost/config.hpp>
0015 #include <boost/config/pragma_message.hpp>
0016 #include <boost/integer/integer_mask.hpp>
0017 
0018 #include <cstdint>
0019 #include <limits>
0020 #include <type_traits>
0021 
0022 #ifdef BOOST_GIL_DOXYGEN_ONLY
0023 /// \def BOOST_GIL_CONFIG_HAS_UNALIGNED_ACCESS
0024 /// \brief Define to allow unaligned memory access for models of packed channel value.
0025 /// Theoretically (or historically?) on platforms which support dereferencing on
0026 /// non-word memory boundary, unaligned access may result in performance improvement.
0027 /// \warning Unfortunately, this optimization may be a C/C++ strict aliasing rules
0028 /// violation, if accessed data buffer has effective type that cannot be aliased
0029 /// without leading to undefined behaviour.
0030 #define BOOST_GIL_CONFIG_HAS_UNALIGNED_ACCESS
0031 #endif
0032 
0033 #ifdef BOOST_GIL_CONFIG_HAS_UNALIGNED_ACCESS
0034 #if defined(sun) || defined(__sun) || \             // SunOS
0035     defined(__osf__) || defined(__osf) || \         // Tru64
0036     defined(_hpux) || defined(hpux) || \            // HP-UX
0037     defined(__arm__) || defined(__ARM_ARCH) || \    // ARM
0038     defined(_AIX)                                   // AIX
0039 #error Unaligned access strictly disabled for some UNIX platforms or ARM architecture
0040 #elif defined(__i386__) || defined(__x86_64__) || defined(__vax__)
0041     // The check for little-endian architectures that tolerate unaligned memory
0042     // accesses is just an optimization. Nothing will break if it fails to detect
0043     // a suitable architecture.
0044     //
0045     // Unfortunately, this optimization may be a C/C++ strict aliasing rules violation
0046     // if accessed data buffer has effective type that cannot be aliased
0047     // without leading to undefined behaviour.
0048 BOOST_PRAGMA_MESSAGE("CAUTION: Unaligned access tolerated on little-endian may cause undefined behaviour")
0049 #else
0050 #error Unaligned access disabled for unknown platforms and architectures
0051 #endif
0052 #endif // defined(BOOST_GIL_CONFIG_HAS_UNALIGNED_ACCESS)
0053 
0054 namespace boost { namespace gil {
0055 
0056 ///////////////////////////////////////////
0057 ////  channel_traits
0058 ////
0059 ////  \ingroup ChannelModel
0060 ////  \class channel_traits
0061 ////  \brief defines properties of channels, such as their range and associated types
0062 ////
0063 ////  The channel traits must be defined for every model of ChannelConcept
0064 ////  Default traits are provided. For built-in types the default traits use
0065 ////  built-in pointer and reference and the channel range is the physical
0066 ////  range of the type. For classes, the default traits forward the associated types
0067 ////  and range to the class.
0068 ////
0069 ///////////////////////////////////////////
0070 
0071 namespace detail {
0072 
0073 template <typename T, bool IsClass>
0074 struct channel_traits_impl;
0075 
0076 // channel traits for custom class
0077 template <typename T>
0078 struct channel_traits_impl<T, true>
0079 {
0080     using value_type = typename T::value_type;
0081     using reference = typename T::reference;
0082     using pointer = typename T::pointer;
0083     using const_reference = typename T::const_reference;
0084     using const_pointer = typename T::const_pointer;
0085     static constexpr bool is_mutable = T::is_mutable;
0086     static value_type min_value() { return T::min_value(); }
0087     static value_type max_value() { return T::max_value(); }
0088 };
0089 
0090 // channel traits implementation for built-in integral or floating point channel type
0091 template <typename T>
0092 struct channel_traits_impl<T, false>
0093 {
0094     using value_type = T;
0095     using reference = T&;
0096     using pointer = T*;
0097     using const_reference = T const&;
0098     using const_pointer = T const*;
0099     static constexpr bool is_mutable = true;
0100     static value_type min_value() { return (std::numeric_limits<T>::min)(); }
0101     static value_type max_value() { return (std::numeric_limits<T>::max)(); }
0102 };
0103 
0104 // channel traits implementation for constant built-in scalar or floating point type
0105 template <typename T>
0106 struct channel_traits_impl<T const, false> : channel_traits_impl<T, false>
0107 {
0108     using reference = T const&;
0109     using pointer = T const*;
0110     static constexpr bool is_mutable = false;
0111 };
0112 
0113 } // namespace detail
0114 
0115 /**
0116 \ingroup ChannelModel
0117 \brief Traits for channels. Contains the following members:
0118 \code
0119 template <typename Channel>
0120 struct channel_traits {
0121     using value_type = ...;
0122     using reference = ...;
0123     using pointer = ...;
0124     using const_reference = ...;
0125     using const_pointer = ...;
0126 
0127     static const bool is_mutable;
0128     static value_type min_value();
0129     static value_type max_value();
0130 };
0131 \endcode
0132 */
0133 template <typename T>
0134 struct channel_traits : detail::channel_traits_impl<T, std::is_class<T>::value> {};
0135 
0136 // Channel traits for C++ reference type - remove the reference
0137 template <typename T>
0138 struct channel_traits<T&> : channel_traits<T> {};
0139 
0140 // Channel traits for constant C++ reference type
0141 template <typename T>
0142 struct channel_traits<T const&> : channel_traits<T>
0143 {
0144     using reference = typename channel_traits<T>::const_reference;
0145     using pointer = typename channel_traits<T>::const_pointer;
0146     static constexpr bool is_mutable = false;
0147 };
0148 
0149 ///////////////////////////////////////////
0150 ////  scoped_channel_value
0151 ///////////////////////////////////////////
0152 
0153 /// \defgroup ScopedChannelValue scoped_channel_value
0154 /// \ingroup ChannelModel
0155 /// \brief A channel adaptor that modifies the range of the source channel. Models: ChannelValueConcept
0156 ///
0157 /// Example:
0158 /// \code
0159 /// // Create a double channel with range [-0.5 .. 0.5]
0160 /// struct double_minus_half  { static double apply() { return -0.5; } };
0161 /// struct double_plus_half   { static double apply() { return  0.5; } };
0162 /// using bits64custom_t = scoped_channel_value<double, double_minus_half, double_plus_half>;
0163 ///
0164 /// // channel_convert its maximum should map to the maximum
0165 /// bits64custom_t x = channel_traits<bits64custom_t>::max_value();
0166 /// assert(x == 0.5);
0167 /// uint16_t y = channel_convert<uint16_t>(x);
0168 /// assert(y == 65535);
0169 /// \endcode
0170 
0171 /// \ingroup ScopedChannelValue
0172 /// \brief A channel adaptor that modifies the range of the source channel. Models: ChannelValueConcept
0173 /// \tparam BaseChannelValue base channel (models ChannelValueConcept)
0174 /// \tparam MinVal class with a static apply() function returning the minimum channel values
0175 /// \tparam MaxVal class with a static apply() function returning the maximum channel values
0176 template <typename BaseChannelValue, typename MinVal, typename MaxVal>
0177 struct scoped_channel_value
0178 {
0179     using value_type = scoped_channel_value<BaseChannelValue, MinVal, MaxVal>;
0180     using reference = value_type&;
0181     using pointer = value_type*;
0182     using const_reference = value_type const&;
0183     using const_pointer = value_type const*;
0184     static constexpr bool is_mutable = channel_traits<BaseChannelValue>::is_mutable;
0185 
0186     using base_channel_t = BaseChannelValue;
0187 
0188     static value_type min_value() { return MinVal::apply(); }
0189     static value_type max_value() { return MaxVal::apply(); }
0190 
0191     scoped_channel_value() = default;
0192     scoped_channel_value(scoped_channel_value const& other) : value_(other.value_) {}
0193     scoped_channel_value& operator=(scoped_channel_value const& other) = default;
0194     scoped_channel_value(BaseChannelValue value) : value_(value) {}
0195     scoped_channel_value& operator=(BaseChannelValue value)
0196     {
0197         value_ = value;
0198         return *this;
0199     }
0200 
0201     auto operator++() -> scoped_channel_value& { ++value_; return *this; }
0202     auto operator--() -> scoped_channel_value& { --value_; return *this; }
0203 
0204     auto operator++(int) -> scoped_channel_value
0205     {
0206         scoped_channel_value tmp=*this;
0207         this->operator++(); return tmp;
0208     }
0209     
0210     auto operator--(int) -> scoped_channel_value
0211     {
0212         scoped_channel_value tmp=*this;
0213         this->operator--(); return tmp;
0214     }
0215 
0216     template <typename Scalar2>
0217     auto operator+=(Scalar2 v) -> scoped_channel_value& { value_+=v; return *this; }
0218     
0219     template <typename Scalar2>
0220     auto operator-=(Scalar2 v) -> scoped_channel_value& { value_-=v; return *this; }
0221 
0222     template <typename Scalar2>
0223     auto operator*=(Scalar2 v) -> scoped_channel_value& { value_*=v; return *this; }
0224 
0225     template <typename Scalar2>
0226     auto operator/=(Scalar2 v) -> scoped_channel_value& { value_/=v; return *this; }
0227 
0228     operator BaseChannelValue() const { return value_; }
0229 private:
0230     BaseChannelValue value_{};
0231 };
0232 
0233 template <typename T>
0234 struct float_point_zero
0235 {
0236     static constexpr T apply() { return 0.0f; }
0237 };
0238 
0239 template <typename T>
0240 struct float_point_one
0241 {
0242     static constexpr T apply() { return 1.0f; }
0243 };
0244 
0245 ///////////////////////////////////////////
0246 ////  Support for sub-byte channels. These are integral channels whose value is contained in a range of bits inside an integral type
0247 ///////////////////////////////////////////
0248 
0249 // 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:
0250 // - Any operation that requires returning the result by value will otherwise return the built-in integral type, which will have incorrect range
0251 //   That means that after getting the value of the channel we cannot properly do channel_convert, channel_invert, etc.
0252 // - 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
0253 namespace detail {
0254 
0255 // returns the smallest fast unsigned integral type that has at least NumBits bits
0256 template <int NumBits>
0257 struct min_fast_uint :
0258     std::conditional
0259     <
0260         NumBits <= 8,
0261         std::uint_least8_t,
0262         typename std::conditional
0263         <
0264             NumBits <= 16,
0265             std::uint_least16_t,
0266             typename std::conditional
0267             <
0268                 NumBits <= 32,
0269                 std::uint_least32_t,
0270                 std::uintmax_t
0271             >::type
0272         >::type
0273     >
0274 {};
0275 
0276 template <int NumBits>
0277 struct num_value_fn
0278     : std::conditional<NumBits < 32, std::uint32_t, std::uint64_t>
0279 {};
0280 
0281 template <int NumBits>
0282 struct max_value_fn
0283     : std::conditional<NumBits <= 32, std::uint32_t, std::uint64_t>
0284 {};
0285 
0286 } // namespace detail
0287 
0288 /// \defgroup PackedChannelValueModel packed_channel_value
0289 /// \ingroup ChannelModel
0290 /// \brief Represents the value of an unsigned integral channel operating over a bit range. Models: ChannelValueConcept
0291 /// Example:
0292 /// \code
0293 /// // A 4-bit unsigned integral channel.
0294 /// using bits4 = packed_channel_value<4>;
0295 ///
0296 /// assert(channel_traits<bits4>::min_value()==0);
0297 /// assert(channel_traits<bits4>::max_value()==15);
0298 /// assert(sizeof(bits4)==1);
0299 /// static_assert(gil::is_channel_integral<bits4>::value, "");
0300 /// \endcode
0301 
0302 /// \ingroup PackedChannelValueModel
0303 /// \brief The value of a subbyte channel. Models: ChannelValueConcept
0304 template <int NumBits>
0305 class packed_channel_value
0306 {
0307 public:
0308     using integer_t = typename detail::min_fast_uint<NumBits>::type;
0309 
0310     using value_type = packed_channel_value<NumBits>;
0311     using reference = value_type&;
0312     using const_reference = value_type const&;
0313     using pointer = value_type*;
0314     using const_pointer = value_type const*;
0315     static constexpr bool is_mutable = true;
0316 
0317     static value_type min_value() { return 0; }
0318     static value_type max_value() { return low_bits_mask_t< NumBits >::sig_bits; }
0319 
0320     packed_channel_value() = default;
0321     packed_channel_value(integer_t v)
0322     {
0323         value_ = static_cast<integer_t>(v & low_bits_mask_t<NumBits>::sig_bits_fast);
0324     }
0325 
0326     template <typename Scalar>
0327     packed_channel_value(Scalar v)
0328     {
0329         value_ = packed_channel_value(static_cast<integer_t>(v));
0330     }
0331 
0332     static auto num_bits() -> unsigned int { return NumBits; }
0333 
0334     operator integer_t() const { return value_; }
0335 
0336 private:
0337     integer_t value_{};
0338 };
0339 
0340 namespace detail {
0341 
0342 template <std::size_t K>
0343 struct static_copy_bytes
0344 {
0345     void operator()(unsigned char const* from, unsigned char* to) const
0346     {
0347         *to = *from;
0348         static_copy_bytes<K - 1>()(++from, ++to);
0349     }
0350 };
0351 
0352 template <>
0353 struct static_copy_bytes<0>
0354 {
0355     void operator()(unsigned char const*, unsigned char*) const {}
0356 };
0357 
0358 template <typename Derived, typename BitField, int NumBits, bool IsMutable>
0359 class packed_channel_reference_base
0360 {
0361 protected:
0362     using data_ptr_t = typename std::conditional<IsMutable, void*, void const*>::type;
0363 public:
0364     data_ptr_t _data_ptr;   // void* pointer to the first byte of the bit range
0365 
0366     using value_type = packed_channel_value<NumBits>;
0367     using reference = Derived const;
0368     using pointer = value_type*;
0369     using const_pointer = value_type const*;
0370     static constexpr int num_bits = NumBits;
0371     static constexpr bool is_mutable = IsMutable;
0372 
0373     static auto min_value() -> value_type { return channel_traits<value_type>::min_value(); }
0374     static auto max_value() -> value_type { return channel_traits<value_type>::max_value(); }
0375 
0376     using bitfield_t = BitField;
0377     using integer_t = typename value_type::integer_t;
0378 
0379     packed_channel_reference_base(data_ptr_t data_ptr) : _data_ptr(data_ptr) {}
0380     packed_channel_reference_base(packed_channel_reference_base const& ref) : _data_ptr(ref._data_ptr) {}
0381     
0382     auto operator=(integer_t v) const -> Derived const& { set(v); return derived(); }
0383 
0384     auto operator++() const -> Derived const& { set(get()+1); return derived(); }
0385     auto operator--() const -> Derived const& { set(get()-1); return derived(); }
0386 
0387     auto operator++(int) const -> Derived
0388     {
0389         Derived tmp=derived();
0390         this->operator++(); return tmp;
0391     }
0392     
0393     auto operator--(int) const -> Derived
0394     {
0395         Derived tmp=derived();
0396         this->operator--();
0397         return tmp;
0398     }
0399 
0400     template <typename Scalar2>
0401     auto operator+=(Scalar2 v) const -> Derived const&
0402     {
0403         set( static_cast<integer_t>(  get() + v ));
0404         return derived();
0405     }
0406     
0407     template <typename Scalar2>
0408     auto operator-=(Scalar2 v) const -> Derived const&
0409     {
0410         set( static_cast<integer_t>(  get() - v )); return derived();
0411     }
0412     
0413     template <typename Scalar2>
0414     auto operator*=(Scalar2 v) const -> Derived const&
0415     {
0416         set( static_cast<integer_t>(  get() * v ));
0417         return derived();
0418     }
0419 
0420     template <typename Scalar2>
0421     auto operator/=(Scalar2 v) const -> Derived const&
0422     {
0423         set( static_cast<integer_t>(  get() / v ));
0424         return derived();
0425     }
0426 
0427     operator integer_t() const { return get(); }
0428     auto operator&() const -> data_ptr_t {return _data_ptr;}
0429 
0430 protected:
0431 
0432     using num_value_t = typename detail::num_value_fn<NumBits>::type;
0433     using max_value_t = typename detail::max_value_fn<NumBits>::type;
0434 
0435     static const num_value_t num_values = static_cast< num_value_t >( 1 ) << NumBits ;
0436     static const max_value_t max_val    = static_cast< max_value_t >( num_values - 1 );
0437 
0438 #if defined(BOOST_GIL_CONFIG_HAS_UNALIGNED_ACCESS)
0439     const bitfield_t& get_data()                      const { return *static_cast<const bitfield_t*>(_data_ptr); }
0440     void              set_data(const bitfield_t& val) const {        *static_cast<      bitfield_t*>(_data_ptr) = val; }
0441 #else
0442     auto get_data() const -> bitfield_t
0443     {
0444         bitfield_t ret;
0445         static_copy_bytes<sizeof(bitfield_t) >()(gil_reinterpret_cast_c<const unsigned char*>(_data_ptr),gil_reinterpret_cast<unsigned char*>(&ret));
0446         return ret;
0447     }
0448     
0449     void set_data(bitfield_t const& val) const
0450     {
0451         static_copy_bytes<sizeof(bitfield_t) >()(gil_reinterpret_cast_c<const unsigned char*>(&val),gil_reinterpret_cast<unsigned char*>(_data_ptr));
0452     }
0453 #endif
0454 
0455 private:
0456     void set(integer_t value) const {     // can this be done faster??
0457         this->derived().set_unsafe(((value % num_values) + num_values) % num_values);
0458     }
0459     auto get() const -> integer_t { return derived().get(); }
0460     auto derived() const -> Derived const& { return static_cast<const Derived&>(*this); }
0461 };
0462 }   // namespace detail
0463 
0464 /// \defgroup PackedChannelReferenceModel packed_channel_reference
0465 /// \ingroup ChannelModel
0466 /// \brief Represents a reference proxy to a channel operating over a bit range whose offset is fixed at compile time. Models ChannelConcept
0467 /// Example:
0468 /// \code
0469 /// // Reference to a 2-bit channel starting at bit 1 (i.e. the second bit)
0470 /// using bits2_1_ref_t = packed_channel_reference<uint16_t,1,2,true> const;
0471 ///
0472 /// uint16_t data=0;
0473 /// bits2_1_ref_t channel_ref(&data);
0474 /// channel_ref = channel_traits<bits2_1_ref_t>::max_value();   // == 3
0475 /// assert(data == 6);                                          // == 3<<1 == 6
0476 /// \endcode
0477 
0478 /// \tparam BitField A type that holds the bits of the pixel from which the channel is referenced. Typically an integral type, like std::uint16_t
0479 /// \tparam Defines the sequence of bits in the data value that contain the channel
0480 /// \tparam true if the reference is mutable
0481 template <typename BitField, int FirstBit, int NumBits, bool IsMutable>
0482 class packed_channel_reference;
0483 
0484 /// \tparam A type that holds the bits of the pixel from which the channel is referenced. Typically an integral type, like std::uint16_t
0485 /// \tparam Defines the sequence of bits in the data value that contain the channel
0486 /// \tparam true if the reference is mutable
0487 template <typename BitField, int NumBits, bool IsMutable>
0488 class packed_dynamic_channel_reference;
0489 
0490 /// \ingroup PackedChannelReferenceModel
0491 /// \brief A constant subbyte channel reference whose bit offset is fixed at compile time. Models ChannelConcept
0492 template <typename BitField, int FirstBit, int NumBits>
0493 class packed_channel_reference<BitField, FirstBit, NumBits, false>
0494     : public detail::packed_channel_reference_base
0495         <
0496             packed_channel_reference<BitField, FirstBit, NumBits, false>,
0497             BitField,
0498             NumBits,
0499             false
0500         >
0501 {
0502     using parent_t = detail::packed_channel_reference_base
0503         <
0504             packed_channel_reference<BitField, FirstBit, NumBits, false>,
0505             BitField,
0506             NumBits,
0507             false
0508         >;
0509 
0510     friend class packed_channel_reference<BitField, FirstBit, NumBits, true>;
0511 
0512     static const BitField channel_mask = static_cast<BitField>(parent_t::max_val) << FirstBit;
0513 
0514     void operator=(packed_channel_reference const&);
0515 public:
0516     using const_reference = packed_channel_reference<BitField,FirstBit,NumBits,false> const;
0517     using mutable_reference = packed_channel_reference<BitField,FirstBit,NumBits,true> const;
0518     using integer_t = typename parent_t::integer_t;
0519 
0520     explicit packed_channel_reference(const void* data_ptr) : parent_t(data_ptr) {}
0521     packed_channel_reference(const packed_channel_reference& ref) : parent_t(ref._data_ptr) {}
0522     packed_channel_reference(const mutable_reference& ref) : parent_t(ref._data_ptr) {}
0523 
0524     auto first_bit() const -> unsigned int { return FirstBit; }
0525 
0526     auto get() const -> integer_t { return integer_t((this->get_data()&channel_mask) >> FirstBit); }
0527 };
0528 
0529 /// \ingroup PackedChannelReferenceModel
0530 /// \brief A mutable subbyte channel reference whose bit offset is fixed at compile time. Models ChannelConcept
0531 template <typename BitField, int FirstBit, int NumBits>
0532 class packed_channel_reference<BitField,FirstBit,NumBits,true>
0533    : public detail::packed_channel_reference_base<packed_channel_reference<BitField,FirstBit,NumBits,true>,BitField,NumBits,true>
0534 {
0535     using parent_t = detail::packed_channel_reference_base<packed_channel_reference<BitField,FirstBit,NumBits,true>,BitField,NumBits,true>;
0536     friend class packed_channel_reference<BitField,FirstBit,NumBits,false>;
0537 
0538     static const BitField channel_mask = static_cast< BitField >( parent_t::max_val ) << FirstBit;
0539 
0540 public:
0541     using const_reference = packed_channel_reference<BitField,FirstBit,NumBits,false> const;
0542     using mutable_reference = packed_channel_reference<BitField,FirstBit,NumBits,true> const;
0543     using integer_t = typename parent_t::integer_t;
0544 
0545     explicit packed_channel_reference(void* data_ptr) : parent_t(data_ptr) {}
0546     packed_channel_reference(const packed_channel_reference& ref) : parent_t(ref._data_ptr) {}
0547 
0548     packed_channel_reference const& operator=(integer_t value) const
0549     {
0550         BOOST_ASSERT(value <= parent_t::max_val);
0551         set_unsafe(value);
0552         return *this;
0553     }
0554 
0555     auto operator=(mutable_reference const& ref) const -> packed_channel_reference const& { set_from_reference(ref.get_data()); return *this; }
0556     auto operator=(const_reference const& ref) const -> packed_channel_reference const& { set_from_reference(ref.get_data()); return *this; }
0557 
0558     template <bool Mutable1>
0559     auto operator=(packed_dynamic_channel_reference<BitField,NumBits,Mutable1> const& ref) const -> packed_channel_reference const& { set_unsafe(ref.get()); return *this; }
0560 
0561     auto first_bit() const -> unsigned int { return FirstBit; }
0562 
0563     auto get() const -> integer_t { return integer_t((this->get_data()&channel_mask) >> FirstBit); }
0564     void set_unsafe(integer_t value) const { this->set_data((this->get_data() & ~channel_mask) | (( static_cast< BitField >( value )<<FirstBit))); }
0565 
0566 private:
0567     void set_from_reference(const BitField& other_bits) const { this->set_data((this->get_data() & ~channel_mask) | (other_bits & channel_mask)); }
0568 };
0569 
0570 }}  // namespace boost::gil
0571 
0572 namespace std {
0573 // We are forced to define swap inside std namespace because on some platforms (Visual Studio 8) STL calls swap qualified.
0574 // swap with 'left bias':
0575 // - swap between proxy and anything
0576 // - swap between value type and proxy
0577 // - swap between proxy and proxy
0578 
0579 /// \ingroup PackedChannelReferenceModel
0580 /// \brief swap for packed_channel_reference
0581 template <typename BF, int FB, int NB, bool M, typename R>
0582 inline
0583 void swap(boost::gil::packed_channel_reference<BF, FB, NB, M> const x, R& y)
0584 {
0585     boost::gil::swap_proxy
0586     <
0587         typename boost::gil::packed_channel_reference<BF, FB, NB, M>::value_type
0588     >(x, y);
0589 }
0590 
0591 
0592 /// \ingroup PackedChannelReferenceModel
0593 /// \brief swap for packed_channel_reference
0594 template <typename BF, int FB, int NB, bool M>
0595 inline
0596 void swap(
0597     typename boost::gil::packed_channel_reference<BF, FB, NB, M>::value_type& x,
0598     boost::gil::packed_channel_reference<BF, FB, NB, M> const y)
0599 {
0600     boost::gil::swap_proxy
0601     <
0602         typename boost::gil::packed_channel_reference<BF, FB, NB, M>::value_type
0603     >(x,y);
0604 }
0605 
0606 /// \ingroup PackedChannelReferenceModel
0607 /// \brief swap for packed_channel_reference
0608 template <typename BF, int FB, int NB, bool M> inline
0609 void swap(
0610     boost::gil::packed_channel_reference<BF, FB, NB, M> const x,
0611     boost::gil::packed_channel_reference<BF, FB, NB, M> const y)
0612 {
0613     boost::gil::swap_proxy
0614     <
0615         typename boost::gil::packed_channel_reference<BF, FB, NB, M>::value_type
0616     >(x,y);
0617 }
0618 
0619 }   // namespace std
0620 
0621 namespace boost { namespace gil {
0622 
0623 /// \defgroup PackedChannelDynamicReferenceModel packed_dynamic_channel_reference
0624 /// \ingroup ChannelModel
0625 /// \brief Represents a reference proxy to a channel operating over a bit range whose offset is specified at run time. Models ChannelConcept
0626 ///
0627 /// Example:
0628 /// \code
0629 /// // Reference to a 2-bit channel whose offset is specified at construction time
0630 /// using bits2_dynamic_ref_t = packed_dynamic_channel_reference<uint8_t,2,true> const;
0631 ///
0632 /// uint16_t data=0;
0633 /// bits2_dynamic_ref_t channel_ref(&data,1);
0634 /// channel_ref = channel_traits<bits2_dynamic_ref_t>::max_value();     // == 3
0635 /// assert(data == 6);                                                  // == (3<<1) == 6
0636 /// \endcode
0637 
0638 /// \brief Models a constant subbyte channel reference whose bit offset is a runtime parameter. Models ChannelConcept
0639 ///        Same as packed_channel_reference, except that the offset is a runtime parameter
0640 /// \ingroup PackedChannelDynamicReferenceModel
0641 template <typename BitField, int NumBits>
0642 class packed_dynamic_channel_reference<BitField,NumBits,false>
0643    : public detail::packed_channel_reference_base<packed_dynamic_channel_reference<BitField,NumBits,false>,BitField,NumBits,false>
0644 {
0645     using parent_t = detail::packed_channel_reference_base<packed_dynamic_channel_reference<BitField,NumBits,false>,BitField,NumBits,false>;
0646     friend class packed_dynamic_channel_reference<BitField,NumBits,true>;
0647 
0648     unsigned _first_bit;     // 0..7
0649 
0650     void operator=(const packed_dynamic_channel_reference&);
0651 public:
0652     using const_reference = packed_dynamic_channel_reference<BitField,NumBits,false> const;
0653     using mutable_reference = packed_dynamic_channel_reference<BitField,NumBits,true> const;
0654     using integer_t = typename parent_t::integer_t;
0655 
0656     packed_dynamic_channel_reference(void const* data_ptr, unsigned first_bit) : parent_t(data_ptr), _first_bit(first_bit) {}
0657     packed_dynamic_channel_reference(const_reference const&   ref) : parent_t(ref._data_ptr), _first_bit(ref._first_bit) {}
0658     packed_dynamic_channel_reference(mutable_reference const& ref) : parent_t(ref._data_ptr), _first_bit(ref._first_bit) {}
0659 
0660     auto first_bit() const -> unsigned int { return _first_bit; }
0661 
0662     auto get() const -> integer_t
0663     {
0664         const BitField channel_mask = static_cast< integer_t >( parent_t::max_val ) <<_first_bit;
0665         return static_cast< integer_t >(( this->get_data()&channel_mask ) >> _first_bit );
0666     }
0667 };
0668 
0669 /// \brief Models a mutable subbyte channel reference whose bit offset is a runtime parameter. Models ChannelConcept
0670 ///        Same as packed_channel_reference, except that the offset is a runtime parameter
0671 /// \ingroup PackedChannelDynamicReferenceModel
0672 template <typename BitField, int NumBits>
0673 class packed_dynamic_channel_reference<BitField,NumBits,true>
0674    : public detail::packed_channel_reference_base<packed_dynamic_channel_reference<BitField,NumBits,true>,BitField,NumBits,true>
0675 {
0676     using parent_t = detail::packed_channel_reference_base<packed_dynamic_channel_reference<BitField,NumBits,true>,BitField,NumBits,true>;
0677     friend class packed_dynamic_channel_reference<BitField,NumBits,false>;
0678 
0679     unsigned _first_bit;
0680 
0681 public:
0682     using const_reference = packed_dynamic_channel_reference<BitField,NumBits,false> const;
0683     using mutable_reference = packed_dynamic_channel_reference<BitField,NumBits,true> const;
0684     using integer_t = typename parent_t::integer_t;
0685 
0686     packed_dynamic_channel_reference(void* data_ptr, unsigned first_bit) : parent_t(data_ptr), _first_bit(first_bit) {}
0687     packed_dynamic_channel_reference(packed_dynamic_channel_reference const& ref) : parent_t(ref._data_ptr), _first_bit(ref._first_bit) {}
0688 
0689     auto operator=(integer_t value) const -> packed_dynamic_channel_reference const&
0690     {
0691         BOOST_ASSERT(value <= parent_t::max_val);
0692         set_unsafe(value);
0693         return *this;
0694     }
0695 
0696     auto operator=(mutable_reference const& ref) const -> packed_dynamic_channel_reference const& {  set_unsafe(ref.get()); return *this; }
0697     auto operator=(const_reference const& ref) const -> packed_dynamic_channel_reference const& {  set_unsafe(ref.get()); return *this; }
0698 
0699     template <typename BitField1, int FirstBit1, bool Mutable1>
0700     auto operator=(packed_channel_reference<BitField1, FirstBit1, NumBits, Mutable1> const& ref) const -> packed_dynamic_channel_reference const&
0701     {
0702         set_unsafe(ref.get());
0703         return *this;
0704     }
0705 
0706     auto first_bit() const -> unsigned int { return _first_bit; }
0707 
0708     auto get() const -> integer_t
0709     {
0710         BitField const channel_mask = static_cast< integer_t >( parent_t::max_val ) << _first_bit;
0711         return static_cast< integer_t >(( this->get_data()&channel_mask ) >> _first_bit );
0712     }
0713 
0714     void set_unsafe(integer_t value) const {
0715         const BitField channel_mask = static_cast< integer_t >( parent_t::max_val ) << _first_bit;
0716         this->set_data((this->get_data() & ~channel_mask) | value<<_first_bit);
0717     }
0718 };
0719 } }  // namespace boost::gil
0720 
0721 namespace std {
0722 // We are forced to define swap inside std namespace because on some platforms (Visual Studio 8) STL calls swap qualified.
0723 // swap with 'left bias':
0724 // - swap between proxy and anything
0725 // - swap between value type and proxy
0726 // - swap between proxy and proxy
0727 
0728 
0729 /// \ingroup PackedChannelDynamicReferenceModel
0730 /// \brief swap for packed_dynamic_channel_reference
0731 template <typename BF, int NB, bool M, typename R> inline
0732 void swap(const boost::gil::packed_dynamic_channel_reference<BF,NB,M> x, R& y) {
0733     boost::gil::swap_proxy<typename boost::gil::packed_dynamic_channel_reference<BF,NB,M>::value_type>(x,y);
0734 }
0735 
0736 
0737 /// \ingroup PackedChannelDynamicReferenceModel
0738 /// \brief swap for packed_dynamic_channel_reference
0739 template <typename BF, int NB, bool M> inline
0740 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) {
0741     boost::gil::swap_proxy<typename boost::gil::packed_dynamic_channel_reference<BF,NB,M>::value_type>(x,y);
0742 }
0743 
0744 /// \ingroup PackedChannelDynamicReferenceModel
0745 /// \brief swap for packed_dynamic_channel_reference
0746 template <typename BF, int NB, bool M> inline
0747 void swap(const boost::gil::packed_dynamic_channel_reference<BF,NB,M> x, const boost::gil::packed_dynamic_channel_reference<BF,NB,M> y) {
0748     boost::gil::swap_proxy<typename boost::gil::packed_dynamic_channel_reference<BF,NB,M>::value_type>(x,y);
0749 }
0750 }   // namespace std
0751 
0752 // \brief Determines the fundamental type which may be used, e.g., to cast from larger to smaller channel types.
0753 namespace boost { namespace gil {
0754 template <typename T>
0755 struct base_channel_type_impl { using type = T; };
0756 
0757 template <int N>
0758 struct base_channel_type_impl<packed_channel_value<N> >
0759 { using type = typename packed_channel_value<N>::integer_t; };
0760 
0761 template <typename B, int F, int N, bool M>
0762 struct base_channel_type_impl<packed_channel_reference<B, F, N, M> >
0763 {
0764     using type = typename packed_channel_reference<B,F,N,M>::integer_t;
0765 };
0766 
0767 template <typename B, int N, bool M>
0768 struct base_channel_type_impl<packed_dynamic_channel_reference<B, N, M> >
0769 {
0770     using type = typename packed_dynamic_channel_reference<B,N,M>::integer_t;
0771 };
0772 
0773 template <typename ChannelValue, typename MinV, typename MaxV>
0774 struct base_channel_type_impl<scoped_channel_value<ChannelValue, MinV, MaxV> >
0775 { using type = ChannelValue; };
0776 
0777 template <typename T>
0778 struct base_channel_type : base_channel_type_impl<typename std::remove_cv<T>::type> {};
0779 
0780 }} //namespace boost::gil
0781 
0782 #endif