1 //
2 // Copyright 2007-2008 Christian Henning, Andreas Pokorny, Lubomir Bourdev
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_IO_BIT_OPERATIONS_HPP
9 #define BOOST_GIL_IO_BIT_OPERATIONS_HPP
10 
11 #include <boost/gil/io/typedefs.hpp>
12 
13 #include <array>
14 #include <cstddef>
15 #include <type_traits>
16 
17 namespace boost { namespace gil { namespace detail {
18 
19 // 1110 1100 -> 0011 0111
20 template <typename Buffer, typename IsBitAligned>
21 struct mirror_bits
22 {
mirror_bitsboost::gil::detail::mirror_bits23     mirror_bits(bool) {};
24 
operator ()boost::gil::detail::mirror_bits25     void operator()(Buffer&) {}
operator ()boost::gil::detail::mirror_bits26     void operator()(byte_t*, std::size_t){}
27 };
28 
29 // The functor will generate a lookup table since the
30 // mirror operation is quite costly.
31 template <typename Buffer>
32 struct mirror_bits<Buffer, std::true_type>
33 {
mirror_bitsboost::gil::detail::mirror_bits34     mirror_bits(bool apply_operation = true)
35         : apply_operation_(apply_operation)
36     {
37         if(apply_operation_)
38         {
39             byte_t i = 0;
40             do
41             {
42                 lookup_[i] = mirror(i);
43             }
44             while (i++ != 255);
45         }
46    }
47 
operator ()boost::gil::detail::mirror_bits48     void operator()(Buffer& buffer)
49     {
50         if (apply_operation_)
51             for_each(buffer.begin(), buffer.end(), [this](byte_t& c) { lookup(c); });
52     }
53 
operator ()boost::gil::detail::mirror_bits54     void operator()(byte_t *dst, std::size_t size)
55     {
56         for (std::size_t i = 0; i < size; ++i)
57         {
58             lookup(*dst);
59             ++dst;
60         }
61     }
62 
63 private:
64 
lookupboost::gil::detail::mirror_bits65     void lookup(byte_t& c)
66     {
67         c = lookup_[c];
68     }
69 
mirrorboost::gil::detail::mirror_bits70     static byte_t mirror(byte_t c)
71     {
72         byte_t result = 0;
73         for (int i = 0; i < 8; ++i)
74         {
75             result = result << 1;
76             result |= (c & 1);
77             c = c >> 1;
78         }
79 
80         return result;
81     }
82 
83     std::array<byte_t, 256> lookup_;
84     bool apply_operation_;
85 
86 };
87 
88 // 0011 1111 -> 1100 0000
89 template <typename Buffer, typename IsBitAligned>
90 struct negate_bits
91 {
operator ()boost::gil::detail::negate_bits92     void operator()(Buffer&) {};
93 };
94 
95 template <typename Buffer>
96 struct negate_bits<Buffer, std::true_type>
97 {
operator ()boost::gil::detail::negate_bits98     void operator()(Buffer& buffer)
99     {
100         for_each(buffer.begin(), buffer.end(),
101             negate_bits<Buffer, std::true_type>::negate);
102     }
103 
operator ()boost::gil::detail::negate_bits104     void operator()(byte_t* dst, std::size_t size)
105     {
106         for (std::size_t i = 0; i < size; ++i)
107         {
108             negate(*dst);
109             ++dst;
110         }
111     }
112 
113 private:
114 
negateboost::gil::detail::negate_bits115     static void negate(byte_t& b)
116     {
117         b = ~b;
118     }
119 };
120 
121 // 11101100 -> 11001110
122 template <typename Buffer, typename IsBitAligned>
123 struct swap_half_bytes
124 {
operator ()boost::gil::detail::swap_half_bytes125     void operator()(Buffer&) {};
126 };
127 
128 template <typename Buffer>
129 struct swap_half_bytes<Buffer, std::true_type>
130 {
operator ()boost::gil::detail::swap_half_bytes131     void operator()(Buffer& buffer)
132     {
133         for_each(buffer.begin(), buffer.end(),
134             swap_half_bytes<Buffer, std::true_type>::swap);
135     }
136 
operator ()boost::gil::detail::swap_half_bytes137     void operator()(byte_t* dst, std::size_t size)
138     {
139         for (std::size_t i = 0; i < size; ++i)
140         {
141             swap(*dst);
142             ++dst;
143         }
144     }
145 
146 private:
147 
swapboost::gil::detail::swap_half_bytes148     static void swap(byte_t& c)
149     {
150         c = ((c << 4) & 0xF0) | ((c >> 4) & 0x0F);
151     }
152 };
153 
154 template <typename Buffer>
155 struct do_nothing
156 {
157    do_nothing() = default;
158 
operator ()boost::gil::detail::do_nothing159    void operator()(Buffer&) {}
160 };
161 
162 /// Count consecutive zeros on the right
163 template <typename T>
trailing_zeros(T x)164 inline unsigned int trailing_zeros(T x) noexcept
165 {
166     unsigned int n = 0;
167 
168     x = ~x & (x - 1);
169     while (x)
170     {
171         n = n + 1;
172         x = x >> 1;
173     }
174 
175     return n;
176 }
177 
178 /// Counts ones in a bit-set
179 template <typename T>
180 inline
count_ones(T x)181 unsigned int count_ones(T x) noexcept
182 {
183     unsigned int n = 0;
184 
185     while (x)
186     {
187         // clear the least significant bit set
188         x &= x - 1;
189         ++n;
190     }
191 
192     return n;
193 }
194 
195 }}} // namespace boost::gil::detail
196 
197 #endif
198