dnd : Added more functions to drag and drop.
[platform/core/uifw/dali-adaptor.git] / dali / devel-api / adaptor-framework / accessibility-bitset.h
1 #ifndef DALI_ADAPTOR_ACCESSIBILITY_BITSET_H
2 #define DALI_ADAPTOR_ACCESSIBILITY_BITSET_H
3
4 /*
5  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */
20
21 // EXTERNAL INCLUDES
22 #include <algorithm>
23 #include <array>
24 #include <functional>
25 #include <type_traits>
26
27 // INTERNAL INCLUDES
28 #include <dali/public-api/dali-adaptor-common.h>
29
30 namespace Dali::Accessibility
31 {
32 template<std::size_t>
33 class BitSet;
34
35 namespace Internal
36 {
37 // Number of 32-bit chunks required to hold N bits
38 template<typename Enum, Enum EnumMax, typename = std::enable_if_t<std::is_enum_v<Enum>>>
39 inline constexpr std::size_t BitSetSize = (static_cast<std::size_t>(EnumMax) + 31u) / 32u;
40
41 /**
42  * @brief A writable reference to a single bit.
43  *
44  * C++ does not offer a built-in mechanism to directly access specific bits in integral types, i.e.
45  * @code std::uint32_t x = 0; x[5] = true; @endcode is not possible. The BitSet type uses this proxy
46  * class to make such operations possible.
47  *
48  * @see Accessibility::BitSet
49  */
50 class DALI_ADAPTOR_API BitReference
51 {
52   template<std::size_t>
53   friend class Accessibility::BitSet;
54
55 public:
56   using ElementType = std::uint32_t; ///< Integral type used for storing bits.
57   using IndexType   = std::size_t;   ///< Type used for indexing.
58
59   BitReference() = delete;
60
61   /**
62    * @brief Assigns a new value to this bit.
63    *
64    * This operator is used in expressions like @code bitset[i] = true; @endcode
65    *
66    * @param x The new value.
67    */
68   BitReference& operator=(bool x)
69   {
70     if(x)
71     {
72       *mData |= (1U << mIndex);
73     }
74     else
75     {
76       *mData &= ~(1U << mIndex);
77     }
78
79     return *this;
80   }
81
82   /**
83    * @brief Assigns a new value to this bit.
84    *
85    * This operator is used in expressions like @code bitset[i] = otherBitset[j]; @endcode
86    *
87    * @param reference A reference to the new value.
88    */
89   BitReference& operator=(const BitReference& reference)
90   {
91     return (*this = static_cast<bool>(reference));
92   }
93
94   /**
95    * @brief Queries the value of this bit.
96    *
97    * @return true if this bit is set to 1, false if it is set to 0.
98    */
99   operator bool() const
100   {
101     return *mData & (1U << mIndex);
102   }
103
104 private:
105   BitReference(ElementType* data, IndexType index)
106   : mData{data},
107     mIndex{index}
108   {
109     DALI_ASSERT_DEBUG(data && index < 32);
110   }
111
112   ElementType* mData;
113   IndexType    mIndex;
114 };
115
116 } // namespace Internal
117
118 /**
119  * @brief A collection of bits stored in 32-bit chunks for convenient serialization.
120  *
121  * @tparam N Number of 32-bit chunks (the capacity of this BitSet is 32*N).
122  */
123 template<std::size_t N>
124 class DALI_ADAPTOR_API BitSet
125 {
126 public:
127   // Types
128
129   using ReferenceType = Internal::BitReference;     ///< @copybrief Dali::Accessibility::Internal::BitReference
130   using ElementType   = ReferenceType::ElementType; ///< @copydoc Dali::Accessibility::Internal::BitReference::ElementType
131   using IndexType     = ReferenceType::IndexType;   ///< @copydoc Dali::Accessibility::Internal::BitReference::IndexType
132   using ArrayType     = std::array<ElementType, N>; ///< An array of N integers that can store 32*N bits.
133
134   // Constructors
135
136   /**
137    * @brief Constructor.
138    */
139   BitSet() = default;
140
141   BitSet(const BitSet&) = default;
142
143   BitSet(BitSet&&) noexcept = default;
144
145   /**
146    * @brief Constructs a new BitSet with all bits inialized with values from the specified array.
147    *
148    * Equivalent to the pseudocode:
149    * @code
150    * for(i = 0; i < max; ++i) bits[i] = (array[i / 32] >> (i % 32)) & 0x1;
151    * @endcode
152    *
153    * @param array Array with the initial values.
154    */
155   explicit BitSet(const ArrayType& array)
156   {
157     std::copy(array.begin(), array.end(), mData.begin());
158   }
159
160   /**
161    * @copydoc BitSet(const ArrayType&)
162    */
163   // Useful for deserializing DBus data that comes in as signed integers
164   explicit BitSet(const std::array<std::int32_t, N>& array)
165   {
166     std::transform(array.begin(), array.end(), mData.begin(), [](std::int32_t x) { return static_cast<ElementType>(x); });
167   }
168
169   /**
170    * @brief Constructs a new BitSet with all bits initialized with bits from the specified integer.
171    *
172    * This constructor is only available for BitSets with 64-bit capacity. Equivalent to the pseudocode:
173    * @code
174    * for(i = 0; i < 64; ++i) bits[i] = (data >> i) & 0x1;
175    * @endcode
176    *
177    * @param data 64-bit integer with the initial values.
178    */
179   template<std::size_t I = N, typename = std::enable_if_t<(I == N && N == 2u)>>
180   explicit BitSet(std::uint64_t data)
181   {
182     mData[0] = static_cast<ElementType>(data);
183     mData[1] = static_cast<ElementType>(data >> 32);
184   }
185
186   // Non-virtual destructor
187
188   ~BitSet() noexcept = default;
189
190   // Operators
191
192   BitSet& operator=(const BitSet&) = default;
193
194   BitSet& operator=(BitSet&&) noexcept = default;
195
196   /**
197    * @brief Checks whether any bits are set to 1.
198    *
199    * Equivalent to the pseudocode:
200    * @code
201    * for(i = 0; i < max; ++i)
202    *   if(bits[i] == 1)
203    *     return true;
204    *  return false;
205    * @endcode
206    *
207    * @return true if at least one bit is set to 1, false otherwise.
208    */
209   explicit operator bool() const
210   {
211     return std::any_of(mData.begin(), mData.end(), [](ElementType s) { return s != 0u; });
212   }
213
214   /**
215    * @brief Compares two bitsets for equality.
216    *
217    * Equivalent to the pseudocode:
218    * @code
219    * for(i = 0; i < max; ++i)
220    *   if(bits[i] != other.bits[i])
221    *     return false;
222    * return true;
223    * @endcode
224    *
225    * @param other The other operand.
226    * @return true if all bits in the two bitsets have the same values, false otherwise.
227    */
228   bool operator==(const BitSet& other) const
229   {
230     return std::equal(mData.begin(), mData.end(), other.mData.begin());
231   }
232
233   /**
234    * @brief Compares two bitsets for inequality.
235    *
236    * @param other The other operand.
237    * @return false if all bits in the two bitsets have the same values, true otherwise.
238    *
239    * @see BitSet::operator==(const BitSet&)
240    */
241   // TODO(C++20): Remove this. Having only operator== will be sufficient.
242   bool operator!=(const BitSet& other) const
243   {
244     return !(*this == other);
245   }
246
247   /**
248    * @brief Computes the bitwise NOT of this bitset.
249    *
250    * Equivalent to the pseudocode:
251    * @code
252    * for(i = 0; i < max; ++i) result.bits[i] = ~bits[i]
253    * @endcode
254    *
255    * @return Result of the bitwise NOT operation.
256    */
257   BitSet operator~() const
258   {
259     BitSet result;
260
261     std::transform(mData.begin(), mData.end(), result.mData.begin(), std::bit_not<ElementType>{});
262
263     return result;
264   }
265
266   /**
267    * @brief Computes the bitwise OR of two bitsets.
268    *
269    * Equivalent to the pseudocode:
270    * @code
271    * for(i = 0; i < max; ++i) result.bits[i] = bits[i] | other.bits[i];
272    * @endcode
273    *
274    * @param other The other operand.
275    * @return Result of the bitwise OR operation.
276    */
277   BitSet operator|(const BitSet& other) const
278   {
279     return ApplyBinaryOperator(other, std::bit_or<ElementType>{});
280   }
281
282   /**
283    * @brief Computes the bitwise AND of two bitsets.
284    *
285    * Equivalent to the pseudocode:
286    * @code
287    * for(i = 0; i < max; ++i) result.bits[i] = bits[i] & other.bits[i];
288    * @endcode
289    *
290    * @param other The other operand.
291    * @return Result of the bitwise AND operation.
292    */
293   BitSet operator&(const BitSet& other) const
294   {
295     return ApplyBinaryOperator(other, std::bit_and<ElementType>{});
296   }
297
298   /**
299    * @brief Computes the bitwise XOR of two bitsets.
300    *
301    * Equivalent to the pseudocode:
302    * @code
303    * for(i = 0; i < max; ++i) result.bits[i] = bits[i] ^ other.bits[i];
304    * @endcode
305    *
306    * @param other The other operand.
307    * @return Result of the bitwise XOR operation.
308    */
309   BitSet operator^(const BitSet& other) const
310   {
311     return ApplyBinaryOperator(other, std::bit_xor<ElementType>{});
312   }
313
314   /**
315    * @brief Queries the value of the specified bit.
316    *
317    * This operator is used in expressions like @code bool b = bitset[i]; @endcode
318    *
319    * @param index Index of the bit to query.
320    * @return true if the specified bit is set to 1, false if it is set to 0.
321    */
322   bool operator[](IndexType index) const
323   {
324     // Reuse implicit BitReference::operator bool
325     return const_cast<BitSet*>(this)->operator[](index);
326   }
327
328   /**
329    * @brief Obtains a writable reference to the specified bit.
330    *
331    * This operator is used in expressions like @code bitset[i] = true; @endcode
332    *
333    * @param index Index of the bit to query.
334    * @return A writable reference to the specified bit.
335    *
336    * @see BitSet::ReferenceType
337    */
338   ReferenceType operator[](IndexType index)
339   {
340     DALI_ASSERT_ALWAYS(index / 32u < mData.size());
341
342     return {&mData[index / 32u], index % 32u};
343   }
344
345   // Other methods
346
347   /**
348    * @brief Obtains a copy of the internal storage.
349    *
350    * @return A copy of the internal storage.
351    *
352    * @see BitSet::ArrayType
353    * @see BitSet::BitSet(const ArrayType&)
354    */
355   ArrayType GetRawData() const
356   {
357     return mData;
358   }
359
360   /**
361    * @brief Obtains a copy of the internal storage serialized as a single integer.
362    *
363    * This method is only available for BitSets with 64-bit capacity.
364    *
365    * @return A copy of the internal storage.
366    *
367    * @see BitSet::BitSet(std::uint64_t)
368    */
369   template<std::size_t I = N, typename = std::enable_if_t<(I == N && N == 2u)>>
370   std::uint64_t GetRawData64() const
371   {
372     return (static_cast<std::uint64_t>(mData[1]) << 32) | mData[0];
373   }
374
375 private:
376   template<typename BinaryOperator>
377   BitSet ApplyBinaryOperator(const BitSet& other, BinaryOperator binaryOperator) const
378   {
379     BitSet result;
380
381     // Same as the pseudocode:
382     // for(i = 0; i < max; ++i) output[i] = input1[i] @ input2[i];
383     // (substitute '@' with the desired operator)
384     std::transform(
385       mData.begin(), mData.end(), // input1
386       other.mData.begin(),        // input2
387       result.mData.begin(),       // output
388       binaryOperator);
389
390     return result;
391   }
392
393   ArrayType mData{};
394 };
395
396 /**
397  * @brief Helper class for storing enumeration values as a BitSet.
398  *
399  * The enumeration values will be used as indices to the BitSet, so they should be consecutive integers and start from
400  * zero. C++ does not offer a way to query the maximum enumeration value using type traits, hence the additional
401  * template parameter.
402  *
403  * @tparam Enum The enumeration type to use.
404  * @tparam EnumMax The maximum value for this enumeration.
405  *
406  * @see Dali::Accessibility::Accessible::GetStates
407  * @see Dali::Accessibility::Accessible::GetRoles
408  */
409 template<typename Enum, Enum EnumMax>
410 class DALI_ADAPTOR_API EnumBitSet : public BitSet<Internal::BitSetSize<Enum, EnumMax>>
411 {
412   static constexpr std::size_t N = Internal::BitSetSize<Enum, EnumMax>;
413
414 public:
415   // Types
416
417   using IndexType     = typename BitSet<N>::IndexType;     ///< @copydoc BitSet::IndexType
418   using ReferenceType = typename BitSet<N>::ReferenceType; ///< @copydoc BitSet::ReferenceType
419
420   // Constructors
421
422   using BitSet<N>::BitSet;
423
424   // Operators
425
426   /**
427    * @copydoc BitSet::operator[](IndexType) const
428    */
429   bool operator[](Enum index) const
430   {
431     return BitSet<N>::operator[](static_cast<IndexType>(index));
432   }
433
434   /**
435    * @copydoc BitSet::operator[](IndexType)
436    */
437   ReferenceType operator[](Enum index)
438   {
439     return BitSet<N>::operator[](static_cast<IndexType>(index));
440   }
441
442 private:
443   // No data members (non-virtual destructor)
444 };
445
446 } // namespace Dali::Accessibility
447
448 #endif // DALI_ADAPTOR_ACCESSIBILITY_BITSET_H