FINAL CUT
ftypes.h
1 /***********************************************************************
2 * ftypes.h - Implements global data types *
3 * *
4 * This file is part of the FINAL CUT widget toolkit *
5 * *
6 * Copyright 2017-2026 Markus Gans *
7 * *
8 * FINAL CUT is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU Lesser General Public License as *
10 * published by the Free Software Foundation; either version 3 of *
11 * the License, or (at your option) any later version. *
12 * *
13 * FINAL CUT is distributed in the hope that it will be useful, but *
14 * WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this program. If not, see *
20 * <http://www.gnu.org/licenses/>. *
21 ***********************************************************************/
22 
23 #ifndef FTYPES_H
24 #define FTYPES_H
25 
26 #if !defined (USE_FINAL_H) && !defined (COMPILE_FINAL_CUT)
27  #error "Only <final/final.h> can be included directly."
28 #endif
29 
30 #include <sys/types.h>
31 
32 #include <cassert>
33 #include <cstddef>
34 #include <cstdint>
35 #include <cstring>
36 #include <cwctype>
37 
38 #include <array>
39 #include <chrono>
40 #include <functional>
41 #include <limits>
42 #include <memory>
43 #include <string>
44 #include <type_traits>
45 #include <utility>
46 #include <vector>
47 
48 #include "final/eventloop/pipedata.h"
49 
50 #if (defined(__APPLE__) && defined(__MACH__)) || defined(__OpenBSD__)
51  #define USE_KQUEUE_TIMER
52 #endif
53 
54 #if !(defined(__APPLE__) && defined(__MACH__)) && !(defined(__OpenBSD__))
55  #define USE_POSIX_TIMER
56 #endif
57 
58 #ifdef __has_builtin
59  #define HAVE_BUILTIN(x) __has_builtin(x)
60 #else
61  #define HAVE_BUILTIN(x) 0
62 #endif
63 
64 #define badAllocOutput(object_name) \
65  std::clog << FLog::LogLevel::Error \
66  << __FILE__ << ":" << __LINE__ \
67  << ": Not enough memory to alloc " \
68  << (object_name) \
69  << " in " \
70  << __func__ << std::endl // ;
71 
72 using uChar = unsigned char;
73 using uShort = unsigned short;
74 using uInt = unsigned int;
75 using uLong = unsigned long;
76 using uInt8 = std::uint8_t;
77 using uInt16 = std::uint16_t;
78 using uInt32 = std::uint32_t;
79 using uInt64 = std::uint64_t;
80 
81 using sInt = signed int;
82 using sLong = signed long;
83 using sInt8 = std::int8_t;
84 using sInt16 = std::int16_t;
85 using sInt32 = std::int32_t;
86 using sInt64 = std::int64_t;
87 
88 using lDouble = long double;
89 using TimeValue = std::chrono::time_point<std::chrono::system_clock>;
90 using FCall = std::function<void()>;
91 
92 namespace finalcut
93 {
94 
95 namespace internal
96 {
97 
98 template <typename T
99  , bool is_signed>
101 {
102  constexpr auto operator () (const T& x) const noexcept -> bool
103  {
104  return x < 0;
105  }
106 };
107 
108 template <typename T>
109 struct is_negative<T, false>
110 {
111  constexpr auto operator () (const T&) const noexcept -> bool
112  {
113  return false;
114  }
115 };
116 
117 } // namespace internal
118 
119 // Check for 7-bit ASCII
120 template<typename CharT>
121 constexpr auto is7bit (CharT ch) noexcept -> bool
122 {
123  using char_type = std::make_unsigned_t<CharT>;
124  return static_cast<char_type>(ch) < 128;
125 }
126 
127 // Printable character verification
128 inline auto isPrintable (char ch) noexcept -> bool
129 {
130  return std::isprint(static_cast<unsigned char>(ch));
131 }
132 
133 inline auto isPrintable (wchar_t ch) noexcept -> bool
134 {
135  return std::iswprint(std::wint_t(ch));
136 }
137 
138 // Typecast to c-string
139 template <typename StringT>
140 constexpr auto C_STR (StringT&& string) noexcept
141 {
142  return const_cast<char*>(std::forward<StringT>(string));
143 }
144 
145 template <typename T>
146 constexpr auto isNegative (const T& x) noexcept -> bool
147 {
149 }
150 
151 template <typename T>
153 {
154  constexpr explicit operator int () const noexcept
155  {
156  return std::numeric_limits<T>::digits10;
157  }
158 };
159 
160 template <typename T>
161 struct EnumHash
162 {
163  constexpr auto operator () (const T& mt) const noexcept -> std::size_t
164  {
165  using underlying_type = std::underlying_type_t<T>;
166  return std::hash<underlying_type>{}(underlying_type(mt));
167  }
168 };
169 
170 template <typename CharT>
171 constexpr auto stringLength (const CharT* s) noexcept -> std::size_t
172 {
173  return std::char_traits<CharT>::length(s);
174 }
175 
176 template <typename CharT>
177 using remove_ptr_t = std::remove_pointer_t<CharT>;
178 
179 template <typename CharT>
180 using remove_ptr_cv_t = std::remove_cv_t<remove_ptr_t<CharT>>;
181 
182 template <typename CharT>
183 using is_char_based_ptr = std::is_same<char, remove_ptr_cv_t<CharT>>;
184 
185 template <typename CharT>
186 using is_wchar_based_ptr = std::is_same<wchar_t, remove_ptr_cv_t<CharT>>;
187 
188 template <typename CharT>
189 using remove_ref_t = std::remove_reference_t<CharT>;
190 
191 template <typename CharT>
192 using remove_ref_extent_t = std::remove_extent_t<remove_ref_t<CharT>>;
193 
194 template <typename CharT>
195 using remove_ref_extent_cv_t = std::remove_cv_t<remove_ref_extent_t<CharT>>;
196 
197 template <typename CharT>
198 using is_char_based_array = typename std::is_same<char, remove_ref_extent_cv_t<CharT>>;
199 
200 template <typename CharT>
201 using is_wchar_based_array = typename std::is_same<wchar_t, remove_ref_extent_cv_t<CharT>>;
202 
203 template <typename CharT>
204 using enable_if_char_ptr_t =
205  std::enable_if_t<
206  std::is_pointer<CharT>::value && is_char_based_ptr<CharT>::value
207  , std::nullptr_t>;
208 
209 template <typename CharT>
210 using enable_if_char_array_t =
211  std::enable_if_t<
212  std::is_array<remove_ref_t<CharT>>::value && is_char_based_array<CharT>::value
213  , std::nullptr_t>;
214 
215 template <typename CharT>
216 using enable_if_CString_t =
217  std::enable_if_t<
218  (std::is_pointer<CharT>::value && is_char_based_ptr<CharT>::value)
219  || (std::is_array<remove_ref_t<CharT>>::value && is_char_based_array<CharT>::value)
220  , std::nullptr_t>;
221 
222 template <typename CharT>
223 struct isCString
224  : std::integral_constant<bool
225  , (std::is_pointer<CharT>::value && is_char_based_ptr<CharT>::value)
226  || (std::is_array<remove_ref_t<CharT>>::value && is_char_based_array<CharT>::value)>
227 { };
228 
229 template <typename CharT>
230 using enable_if_wchar_ptr_t =
231  std::enable_if_t<
232  std::is_pointer<CharT>::value && is_wchar_based_ptr<CharT>::value
233  , std::nullptr_t>;
234 
235 template <typename CharT>
236 using enable_if_wchar_array_t =
237  std::enable_if_t<
238  std::is_array<remove_ref_t<CharT>>::value && is_wchar_based_array<CharT>::value
239  , std::nullptr_t>;
240 
241 template <typename CharT>
242 using enable_if_WCString_t =
243  std::enable_if_t<
244  (std::is_pointer<CharT>::value && is_wchar_based_ptr<CharT>::value)
245  || (std::is_array<remove_ref_t<CharT>>::value && is_wchar_based_array<CharT>::value)
246  , std::nullptr_t>;
247 
248 template <typename CharT>
250  : std::integral_constant<bool
251  , (std::is_pointer<CharT>::value && is_wchar_based_ptr<CharT>::value)
252  || (std::is_array<remove_ref_t<CharT>>::value && is_wchar_based_array<CharT>::value)>
253 { };
254 
255 template <typename NumT>
256 using enable_if_arithmetic_without_char_t =
257  std::enable_if_t< std::is_arithmetic<NumT>::value
258  && ! std::is_same<char, NumT>::value
259  , std::nullptr_t>;
260 
261 // UTF-8 encoding
262 namespace UTF8
263 {
264 
265 inline void expand (std::vector<char>& buffer, std::size_t addend)
266 {
267  buffer.resize(buffer.size() + addend);
268 }
269 
270 inline void expand (std::array<char, 4>&, std::size_t)
271 {
272  // A std::array<char, 4> cannot be expanded
273 }
274 
275 template <typename T>
276 using DecayedT = typename std::decay_t<T>;
277 
278 template <typename CharBufferT>
279 using uInt32_if_vector_or_array = std::enable_if_t<
280  std::is_same<DecayedT<CharBufferT>, std::vector<char>>::value
281  || std::is_same<DecayedT<CharBufferT>, std::array<char, 4>>::value
282  , uInt32>;
283 
284 #if defined(__CYGWIN__)
285 
286 template <typename CharBufferT>
287 inline auto encode (wchar_t ucs, CharBufferT& buffer) -> uInt32_if_vector_or_array<CharBufferT>
288 {
289  // Writes UTF-8 bytes to the target array and returns the length
290  const auto index = std::is_same<CharBufferT, std::vector<char>>::value
291  ? buffer.size()
292  : 0;
293 
294  // 1 Byte (7-bit): 0xxxxxxx
295  if ( ucs < 0x80 )
296  {
297  expand(buffer, 1);
298  const auto dest = &buffer[index];
299  dest[0] = char(ucs);
300  return 1;
301  }
302 
303  // 2 byte (11-bit): 110xxxxx 10xxxxxx
304  if ( ucs < 0x800 )
305  {
306  expand(buffer, 2);
307  const auto dest = &buffer[index];
308  dest[0] = char(0xc0 | uChar(ucs >> 6u));
309  dest[1] = char(0x80 | uChar(ucs & 0x3f));
310  return 2;
311  }
312 
313  // 3 byte (16-bit): 1110xxxx 10xxxxxx 10xxxxxx
314  expand(buffer, 3);
315  const auto dest = &buffer[index];
316  dest[0] = char(0xe0 | uChar(ucs >> 12u));
317  dest[1] = char(0x80 | uChar((ucs >> 6u) & 0x3f));
318  dest[2] = char(0x80 | uChar(ucs & 0x3f));
319  return 3;
320 }
321 
322 #else
323 
324 template <typename CharBufferT>
325 inline auto encode (wchar_t ucs, CharBufferT& buffer) -> uInt32_if_vector_or_array<CharBufferT>
326 {
327  // Writes UTF-8 bytes to the target array and returns the length
328  const auto index = std::is_same<CharBufferT, std::vector<char>>::value
329  ? buffer.size()
330  : 0;
331 
332  // 1 Byte (7-bit): 0xxxxxxx
333  if ( ucs < 0x80 )
334  {
335  expand(buffer, 1);
336  const auto dest = &buffer[index];
337  dest[0] = char(ucs);
338  return 1;
339  }
340 
341  // 2 byte (11-bit): 110xxxxx 10xxxxxx
342  if ( ucs < 0x800 )
343  {
344  expand(buffer, 2);
345  const auto dest = &buffer[index];
346  dest[0] = char(0xc0 | uChar(ucs >> 6u));
347  dest[1] = char(0x80 | uChar(ucs & 0x3f));
348  return 2;
349  }
350 
351  // 3 byte (16-bit): 1110xxxx 10xxxxxx 10xxxxxx
352  if ( ucs < 0x10000 )
353  {
354  expand(buffer, 3);
355  const auto dest = &buffer[index];
356  dest[0] = char(0xe0 | uChar(ucs >> 12u));
357  dest[1] = char(0x80 | uChar((ucs >> 6u) & 0x3f));
358  dest[2] = char(0x80 | uChar(ucs & 0x3f));
359  return 3;
360  }
361 
362  // 4 byte (21-bit): 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
363  if ( ucs < 0x200000 )
364  {
365  expand(buffer, 4);
366  const auto dest = &buffer[index];
367  dest[0] = char(0xf0 | uChar(ucs >> 18u));
368  dest[1] = char(0x80 | uChar((ucs >> 12u) & 0x3f));
369  dest[2] = char(0x80 | uChar((ucs >> 6u) & 0x3f));
370  dest[3] = char(0x80 | uChar(ucs & 0x3f));
371  return 4;
372  }
373 
374  return encode(L'\uFFFD', buffer); // Invalid character
375 }
376 
377 #endif
378 
379 };
380 
381 
382 // FCharAttribute + FAttribute
383 //----------------------------------------------------------------------
385 {
386  // Attribute byte #0
387  uInt8 bold : 1; // bold
388  uInt8 dim : 1; // dim
389  uInt8 italic : 1; // italic
390  uInt8 underline : 1; // underline
391  uInt8 blink : 1; // blink
392  uInt8 reverse : 1; // reverse
393  uInt8 standout : 1; // standout
394  uInt8 invisible : 1; // invisible
395  // Attribute byte #1
396  uInt8 protect : 1; // protect mode
397  uInt8 crossed_out : 1; // crossed out
398  uInt8 dbl_underline : 1; // double underline
399  uInt8 alt_charset : 1; // alternate character set (vt100)
400  uInt8 pc_charset : 1; // pc character set (CP437)
401  uInt8 transparent : 1; // transparent
402  uInt8 color_overlay : 1; // color overlay
403  uInt8 inherit_background : 1; // inherit background
404  // Attribute byte #2
405  uInt8 no_changes : 1; // no changes required
406  uInt8 printed : 1; // is printed to VTerm
407  uInt8 fullwidth_padding : 1; // padding char (after a full-width char)
408  uInt8 char_width : 2; // number of character cells on screen
409  uInt8 : 3; // padding bits
410  // Attribute byte #3
411  uInt8 : 8; // padding byte
412 };
413 
414 constexpr auto FCharAttribute_to_uInt32 (const finalcut::FCharAttribute& fchar_attr) noexcept -> uInt32
415 {
416  return uInt32(fchar_attr.bold) << 0U
417  | uInt32(fchar_attr.dim) << 1U
418  | uInt32(fchar_attr.italic) << 2U
419  | uInt32(fchar_attr.underline) << 3U
420  | uInt32(fchar_attr.blink) << 4U
421  | uInt32(fchar_attr.reverse) << 5U
422  | uInt32(fchar_attr.standout) << 6U
423  | uInt32(fchar_attr.invisible) << 7U
424  | uInt32(fchar_attr.protect) << 8U
425  | uInt32(fchar_attr.crossed_out) << 9U
426  | uInt32(fchar_attr.dbl_underline) << 10U
427  | uInt32(fchar_attr.alt_charset) << 11U
428  | uInt32(fchar_attr.pc_charset) << 12U
429  | uInt32(fchar_attr.transparent) << 13U
430  | uInt32(fchar_attr.color_overlay) << 14U
431  | uInt32(fchar_attr.inherit_background) << 15U
432  | uInt32(fchar_attr.no_changes) << 16U
433  | uInt32(fchar_attr.printed) << 17U
434  | uInt32(fchar_attr.fullwidth_padding) << 18U
435  | uInt32(fchar_attr.char_width) << 19U;
436 }
437 
438 namespace internal
439 {
440 
441 template<typename T>
442 constexpr auto createMask (T setter) noexcept -> uInt32
443 {
444  FCharAttribute mask{};
445  setter(mask);
446  return FCharAttribute_to_uInt32(mask);
447 }
448 
449 constexpr void setBoldMask (FCharAttribute& attr) noexcept
450 {
451  attr.bold = true;
452 }
453 
454 constexpr void setDimMask (FCharAttribute& attr) noexcept
455 {
456  attr.dim = true;
457 }
458 
459 constexpr void setItalicMask (FCharAttribute& attr) noexcept
460 {
461  attr.italic = true;
462 }
463 
464 constexpr void setUnderlineMask (FCharAttribute& attr) noexcept
465 {
466  attr.underline = true;
467 }
468 
469 constexpr void setBlinkMask (FCharAttribute& attr) noexcept
470 {
471  attr.blink = true;
472 }
473 
474 constexpr void setReverseMask (FCharAttribute& attr) noexcept
475 {
476  attr.reverse = true;
477 }
478 
479 constexpr void setStandoutMask (FCharAttribute& attr) noexcept
480 {
481  attr.standout = true;
482 }
483 
484 constexpr void setInvisibleMask (FCharAttribute& attr) noexcept
485 {
486  attr.invisible = true;
487 }
488 
489 constexpr void setProtectMask (FCharAttribute& attr) noexcept
490 {
491  attr.protect = true;
492 }
493 
494 constexpr void setCrossedOutMask (FCharAttribute& attr) noexcept
495 {
496  attr.crossed_out = true;
497 }
498 
499 constexpr void setDblUnderlineMask (FCharAttribute& attr) noexcept
500 {
501  attr.dbl_underline = true;
502 }
503 
504 constexpr void setAltCharsetMask (FCharAttribute& attr) noexcept
505 {
506  attr.alt_charset = true;
507 }
508 
509 constexpr void setPcCharsetMask (FCharAttribute& attr) noexcept
510 {
511  attr.pc_charset = true;
512 }
513 
514 constexpr void setTransparent (FCharAttribute& attr) noexcept
515 {
516  attr.transparent = true;
517 }
518 
519 constexpr void setColorOverlay (FCharAttribute& attr) noexcept
520 {
521  attr.color_overlay = true;
522 }
523 
524 constexpr void setInheritBackground (FCharAttribute& attr) noexcept
525 {
526  attr.inherit_background = true;
527 }
528 
529 constexpr void setNoChanges (FCharAttribute& attr) noexcept
530 {
531  attr.no_changes = true;
532 }
533 
534 constexpr void setPrinted (FCharAttribute& attr) noexcept
535 {
536  attr.printed = true;
537 }
538 
539 constexpr void setFullwidthPadding (FCharAttribute& attr) noexcept
540 {
541  attr.fullwidth_padding = true;
542 }
543 
544 constexpr void setCharWidth (FCharAttribute& attr) noexcept
545 {
546  attr.char_width = 0x03;
547 }
548 
549 } // namespace internal
550 
551 constexpr auto getFAttributeByte ( const FCharAttribute& fchar_attr
552  , std::size_t index ) noexcept -> uInt8
553 {
554  return (FCharAttribute_to_uInt32(fchar_attr) >> (index << 3)) & 0xff;
555 }
556 
557 #if HAVE_BUILTIN(__builtin_bit_cast)
558 constexpr auto setFAttributeByte ( FCharAttribute& fchar_attr
559  , const std::size_t index
560  , const uInt8 value ) noexcept
561 {
562  if ( index >= sizeof(FCharAttribute) )
563  return; // index out of bounds
564 
565  const auto clear_value = __builtin_bit_cast(uInt32, fchar_attr) & ~(uInt32(0xff) << (index << 3));
566  const auto ret = clear_value | (uInt32(value) << (index << 3));
567  fchar_attr = __builtin_bit_cast(FCharAttribute, ret);
568 }
569 #else
570 inline auto setFAttributeByte ( FCharAttribute& fchar_attr
571  , std::size_t index
572  , uInt8 value ) noexcept
573 {
574  assert ( index < sizeof(FCharAttribute) );
575  std::memcpy(reinterpret_cast<uInt8*>(&fchar_attr) + index, &value, sizeof(uInt8));
576 }
577 #endif
578 
579 #if HAVE_BUILTIN(__builtin_bit_cast)
580 constexpr auto getFAttributeData (const FCharAttribute& fchar_attr) noexcept -> uInt32
581 {
582  return FCharAttribute_to_uInt32(fchar_attr);
583 }
584 #else
585 inline auto getFAttributeData (const FCharAttribute& fchar_attr) noexcept -> uInt32
586 {
587  uInt32 data{};
588  std::memcpy(&data, &fchar_attr, sizeof(data));
589  return data;
590 }
591 #endif
592 
593 #if HAVE_BUILTIN(__builtin_bit_cast)
594 constexpr auto WordToFAttribute (uInt32 data) noexcept -> FCharAttribute
595 {
596  return __builtin_bit_cast(FCharAttribute, data);
597 }
598 #else
599 inline auto DataToFAttribute (uInt32 data) noexcept -> FCharAttribute
600 {
601  FCharAttribute fchar_attr{};
602  std::memcpy(&fchar_attr, &data, sizeof(fchar_attr));
603  return fchar_attr;
604 }
605 #endif
606 
608 {
609  struct set
610  {
611  static constexpr auto bold = internal::createMask(internal::setBoldMask);
612  static constexpr auto dim = internal::createMask(internal::setDimMask);
613  static constexpr auto italic = internal::createMask(internal::setItalicMask);
614  static constexpr auto underline = internal::createMask(internal::setUnderlineMask);
615  static constexpr auto blink = internal::createMask(internal::setBlinkMask);
616  static constexpr auto reverse = internal::createMask(internal::setReverseMask);
617  static constexpr auto standout = internal::createMask(internal::setStandoutMask);
618  static constexpr auto invisible = internal::createMask(internal::setInvisibleMask);
619  static constexpr auto protect = internal::createMask(internal::setProtectMask);
620  static constexpr auto crossed_out = internal::createMask(internal::setCrossedOutMask);
621  static constexpr auto dbl_underline = internal::createMask(internal::setDblUnderlineMask);
622  static constexpr auto alt_charset = internal::createMask(internal::setAltCharsetMask);
623  static constexpr auto pc_charset = internal::createMask(internal::setPcCharsetMask);
624  static constexpr auto transparent = internal::createMask(internal::setTransparent);
625  static constexpr auto color_overlay = internal::createMask(internal::setColorOverlay);
626  static constexpr auto inherit_background = internal::createMask(internal::setInheritBackground);
627  static constexpr auto no_changes = internal::createMask(internal::setNoChanges);
628  static constexpr auto printed = internal::createMask(internal::setPrinted);
629  static constexpr auto fullwidth_padding = internal::createMask(internal::setFullwidthPadding);
630  static constexpr auto char_width = internal::createMask(internal::setCharWidth);
631  };
632 
633  struct unset
634  {
635  static constexpr auto bold = ~set::bold;
636  static constexpr auto dim = ~set::dim;
637  static constexpr auto italic = ~set::italic;
638  static constexpr auto underline = ~set::underline;
639  static constexpr auto blink = ~set::blink;
640  static constexpr auto reverse = ~set::reverse;
641  static constexpr auto standout = ~set::standout;
642  static constexpr auto invisible = ~set::invisible;
643  static constexpr auto protect = ~set::protect;
644  static constexpr auto crossed_out = ~set::crossed_out;
645  static constexpr auto dbl_underline = ~set::dbl_underline;
646  static constexpr auto alt_charset = ~set::alt_charset;
647  static constexpr auto pc_charset = ~set::pc_charset;
648  static constexpr auto transparent = ~set::transparent;
649  static constexpr auto color_overlay = ~set::color_overlay;
650  static constexpr auto inherit_background = ~set::inherit_background;
651  static constexpr auto no_changes = ~set::no_changes;
652  static constexpr auto printed = ~set::printed;
653  static constexpr auto fullwidth_padding = ~set::fullwidth_padding;
654  static constexpr auto char_width = ~set::char_width;
655  };
656 
657  constexpr auto hasBit (uInt32 mask) const noexcept -> bool
658  {
659  return (data & mask) != 0;
660  }
661 
662  constexpr void setBit (uInt32 mask) noexcept
663  {
664  data |= mask;
665  }
666 
667  constexpr void clearBit (uInt32 mask) noexcept
668  {
669  data &= ~mask;
670  }
671 
672  constexpr void toggleBit (uInt32 mask) noexcept
673  {
674  data ^= mask;
675  }
676 
677  auto getFCharAttribute() const noexcept -> FCharAttribute
678  {
679  FCharAttribute bit;
680 #if HAVE_BUILTIN(__builtin_bit_cast)
681  bit = __builtin_bit_cast(FCharAttribute, data);
682 #else
683  std::memcpy(&bit, &data, sizeof(uInt32));
684 #endif
685  return bit;
686  }
687 
688  void setFCharAttribute (const FCharAttribute& bit) noexcept
689  {
690 #if HAVE_BUILTIN(__builtin_bit_cast)
691  data = __builtin_bit_cast(uInt32, bit);
692 #else
693  std::memcpy(&data, &bit, sizeof(uInt32));
694 #endif
695  }
696 
697 #if defined(UNIT_TEST)
698  struct BitProxy
699  {
700  FAttribute& parent;
701  FCharAttribute bits;
702 
703  BitProxy (FAttribute& p)
704  : parent(p)
705  {
706  // Loads data during creation
707  std::memcpy(&bits, &parent.data, sizeof(uInt32));
708  }
709 
710  ~BitProxy()
711  {
712  // Writes data back when destroying (end of statement)
713  std::memcpy(&parent.data, &bits, sizeof(uInt32));
714  }
715 
716  auto operator -> () -> FCharAttribute*
717  {
718  // Allows access to bit fields via ->
719  return &bits;
720  }
721  };
722 
723  struct ConstBitProxy
724  {
725  FCharAttribute bits;
726 
727  ConstBitProxy (const FAttribute& p)
728  {
729  // Loads data during creation
730  std::memcpy(&bits, &p.data, sizeof(uInt32));
731  }
732 
733  auto operator -> () const -> const FCharAttribute*
734  {
735  return &bits;
736  }
737  };
738 
739  auto bit() -> BitProxy
740  {
741  return {*this};
742  }
743 
744  auto bit() const -> ConstBitProxy
745  {
746  return {*this};
747  }
748 
749  struct ByteProxy
750  {
751  FAttribute& parent;
752  std::array<uInt8, 4> byte;
753 
754  ByteProxy (FAttribute& p)
755  : parent(p)
756  {
757  // Loads data during creation
758  std::memcpy(&byte, &parent.data, sizeof(uInt32));
759  }
760 
761  ~ByteProxy()
762  {
763  // Writes data back when destroying (end of statement)
764  std::memcpy(&parent.data, &byte, sizeof(uInt32));
765  }
766 
767  auto operator -> () -> std::array<uInt8, 4>*
768  {
769  // Allows access to bit fields via ->
770  return &byte;
771  }
772  };
773 
774  struct ConstByteProxy
775  {
776  std::array<uInt8, 4> byte;
777 
778  ConstByteProxy (const FAttribute& p)
779  {
780  std::memcpy(&byte, &p.data, sizeof(uInt32));
781  }
782 
783  auto operator -> () const -> const std::array<uInt8, 4>*
784  {
785  return &byte;
786  }
787  };
788 
789  auto byte() -> ByteProxy
790  {
791  return {*this};
792  }
793 
794  auto byte() const -> ConstByteProxy
795  {
796  return {*this};
797  }
798 #endif // defined(UNIT_TEST)
799 
800  // Data member
801  uInt32 data{0};
802 };
803 
804 // FUnicode
805 //----------------------------------------------------------------------
806 static constexpr std::size_t UNICODE_MAX = 5;
807 
808 struct FUnicode
809 {
810  // Using-declarations
811  using iterator = wchar_t*;
812  using const_iterator = const wchar_t*;
813  using pointer = wchar_t*;
814  using const_pointer = const wchar_t*;
815  using reference = wchar_t&;
816  using const_reference = const wchar_t&;
817  using value_type = wchar_t;
818 
819  // Overloaded operators
820  constexpr auto operator [] (std::size_t index) noexcept -> reference
821  {
822 #if defined(__clang__)
823  #pragma clang diagnostic push
824  #if __has_warning("-Wunsafe-buffer-usage")
825  #pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
826  #endif
827 #endif
828  return unicode_data[index];
829 #if defined(__clang__)
830  #pragma clang diagnostic pop
831 #endif
832  }
833 
834  constexpr auto operator [] (std::size_t index) const noexcept -> const_reference
835  {
836 #if defined(__clang__)
837  #pragma clang diagnostic push
838  #if __has_warning("-Wunsafe-buffer-usage")
839  #pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
840  #endif
841 #endif
842  return unicode_data[index];
843 #if defined(__clang__)
844  #pragma clang diagnostic pop
845 #endif
846  }
847 
848  // Methods
849  constexpr auto begin() noexcept -> iterator
850  {
851  return &unicode_data[0];
852  }
853 
854  constexpr auto end() noexcept -> iterator
855  {
856 #if defined(__clang__)
857  #pragma clang diagnostic push
858  #if __has_warning("-Wunsafe-buffer-usage")
859  #pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
860  #endif
861 #endif
862  return &unicode_data[UNICODE_MAX];
863 #if defined(__clang__)
864  #pragma clang diagnostic pop
865 #endif
866  }
867 
868  constexpr auto begin() const noexcept -> const_iterator
869  {
870  return &unicode_data[0];
871  }
872 
873  constexpr auto end() const noexcept -> const_iterator
874  {
875 #if defined(__clang__)
876  #pragma clang diagnostic push
877  #if __has_warning("-Wunsafe-buffer-usage")
878  #pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
879  #endif
880 #endif
881  return &unicode_data[UNICODE_MAX];
882 #if defined(__clang__)
883  #pragma clang diagnostic pop
884 #endif
885  }
886 
887  constexpr auto cbegin() const noexcept -> const_iterator
888  {
889  return &unicode_data[0];
890  }
891 
892  constexpr auto cend() const noexcept -> const_iterator
893  {
894 #if defined(__clang__)
895  #pragma clang diagnostic push
896  #if __has_warning("-Wunsafe-buffer-usage")
897  #pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
898  #endif
899 #endif
900  return &unicode_data[UNICODE_MAX];
901 #if defined(__clang__)
902  #pragma clang diagnostic pop
903 #endif
904  }
905 
906  constexpr auto data() noexcept -> pointer
907  {
908  return &unicode_data[0];
909  }
910 
911  constexpr auto data() const noexcept -> const_pointer
912  {
913  return &unicode_data[0];
914  }
915 
916  // Data member
917  wchar_t unicode_data[UNICODE_MAX]{L'\0', L'\0', L'\0', L'\0', L'\0'};
918 
919  // Friend Non-member operator functions
920  friend constexpr auto operator == (const FUnicode& lhs, const FUnicode& rhs) noexcept -> bool
921  {
922 #if defined(__clang__)
923  #pragma clang diagnostic push
924  #if __has_warning("-Wunsafe-buffer-usage")
925  #pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
926  #endif
927 #endif
928  return lhs.unicode_data[0] == rhs.unicode_data[0]
929  && lhs.unicode_data[1] == rhs.unicode_data[1]
930  && lhs.unicode_data[2] == rhs.unicode_data[2]
931  && lhs.unicode_data[3] == rhs.unicode_data[3]
932  && lhs.unicode_data[4] == rhs.unicode_data[4];
933 #if defined(__clang__)
934  #pragma clang diagnostic pop
935 #endif
936  }
937 
938  friend constexpr auto operator != (const FUnicode& lhs, const FUnicode& rhs) noexcept -> bool
939  {
940  return ! ( lhs == rhs );
941  }
942 };
943 
944 
945 // FCellColor
946 //----------------------------------------------------------------------
947 enum class FColor : uInt16; // forward declaration
948 struct FCellColor; // forward declaration
949 
950 struct FColors
951 {
952  FColor fg{}; // Foreground color
953  FColor bg{}; // Background color
954 };
955 
957 {
958  // Constructor
959  FCellColor() = default;
960 
961  explicit constexpr FCellColor (uInt32 value) noexcept
962  : data{value}
963  { }
964 
965  constexpr FCellColor (FColor fg, FColor bg) noexcept
966  : data{(uInt32(bg) << 16) | uInt32(fg)}
967  { }
968 
969  explicit constexpr FCellColor (FColors color) noexcept
970  : data{(uInt32(color.bg) << 16) | uInt32(color.fg)}
971  { }
972 
973  // Accessors
974  constexpr auto getPair() const noexcept -> FColors
975  {
976  FColors pair; // Foreground and background color
977 #if HAVE_BUILTIN(__builtin_bit_cast)
978  pair = __builtin_bit_cast(FColors, data);
979 #else
980  std::memcpy( static_cast<void*>(&pair)
981  , static_cast<const void*>(&data)
982  , sizeof(uInt32));
983 #endif
984  return pair;
985  }
986 
987  constexpr auto getFgColor() const noexcept -> FColor
988  {
989  return FColor(data & 0x0000ffffU);
990  }
991 
992  constexpr auto getBgColor() const noexcept -> FColor
993  {
994  return FColor(data >> 16);
995  }
996 
997  // Mutators
998  constexpr void setPair (const FColors& pair) noexcept
999  {
1000 #if HAVE_BUILTIN(__builtin_bit_cast)
1001  data = __builtin_bit_cast(uInt32, pair);
1002 #else
1003  std::memcpy(&data, &pair, sizeof(uInt32));
1004 #endif
1005  }
1006 
1007  constexpr void setFgColor (const FColor& fg) noexcept
1008  {
1009  data = (data & 0xffff0000U) | uInt32(fg);
1010  }
1011 
1012  constexpr void setBgColor (const FColor& bg) noexcept
1013  {
1014  data = (data & 0x0000ffffU) | (uInt32(bg) << 16);
1015  }
1016 
1017  // Overloaded operator
1018  constexpr auto operator = (std::initializer_list<FColor> list) noexcept -> FCellColor&
1019  {
1020  if ( list.size() == 2 )
1021  {
1022  auto iter = list.begin();
1023  data = uInt32(*iter); // Foreground color
1024  data |= (uInt32(*std::next(iter)) << 16); // Background color
1025  }
1026 
1027  return *this;
1028  }
1029 
1030  // Data member
1031  uInt32 data{0}; // Color data
1032 
1033  // Friend Non-member operator functions
1034  friend constexpr auto operator == (const FCellColor& lhs, const FCellColor& rhs) noexcept -> bool
1035  {
1036  return lhs.data == rhs.data;
1037  }
1038 
1039  friend constexpr auto operator != (const FCellColor& lhs, const FCellColor& rhs) noexcept -> bool
1040  {
1041  return ! ( lhs == rhs );
1042  }
1043 
1044  friend constexpr void copyBgColor (const FCellColor& from, FCellColor& to) noexcept
1045  {
1046  to.data = (to.data & 0x0000ffffU) | (from.data & 0xffff0000U);
1047  }
1048 
1049  friend constexpr void copyFgColor (const FCellColor& from, FCellColor& to) noexcept
1050  {
1051  to.data = (to.data & 0xffff0000U) | (from.data & 0x0000ffffU);
1052  }
1053 };
1054 
1055 
1056 // FChar
1057 //----------------------------------------------------------------------
1058 constexpr auto getCompareBitMask() noexcept -> uInt32
1059 {
1060  FCharAttribute mask{};
1061  mask.bold = true;
1062  mask.dim = true;
1063  mask.italic = true;
1064  mask.underline = true;
1065  mask.blink = true;
1066  mask.reverse = true;
1067  mask.standout = true;
1068  mask.invisible = true;
1069  mask.protect = true;
1070  mask.crossed_out = true;
1071  mask.dbl_underline = true;
1072  mask.alt_charset = true;
1073  mask.pc_charset = true;
1074  mask.transparent = true;
1075  mask.color_overlay = true;
1076  mask.inherit_background = true;
1077  mask.fullwidth_padding = true;
1078  return FCharAttribute_to_uInt32(mask);
1079 }
1080 
1081 struct FChar
1082 {
1083  // Accessors
1084  constexpr auto getCharWidth() const noexcept -> uInt32
1085  {
1086  return (attr.data & FAttribute::set::char_width) >> 19U;
1087  }
1088 
1089  // Mutators
1090  constexpr void setCharWidth (uInt32 width) noexcept
1091  {
1092  attr.data = (attr.data & FAttribute::unset::char_width) \
1093  | ((width << 19U) & FAttribute::set::char_width);
1094  }
1095 
1096  constexpr void setBit (uInt32 mask, bool enable) noexcept
1097  {
1098  if ( enable )
1099  attr.data |= mask;
1100  else
1101  attr.data &= ~mask;
1102  }
1103 
1104  constexpr void setBit (uInt32 mask) noexcept
1105  {
1106  attr.data |= mask;
1107  }
1108 
1109  constexpr void unsetBit (uInt32 mask) noexcept
1110  {
1111  attr.data &= mask;
1112  }
1113 
1114  // Predicate
1115  constexpr auto isBitSet (uInt32 mask) const noexcept -> bool
1116  {
1117  return attr.data & mask;
1118  }
1119 
1120  // Data member
1121  FUnicode ch{}; // Character code
1122  FUnicode encoded_char{}; // Encoded output character
1123  FCellColor color{}; // Foreground and background color
1124  FAttribute attr{}; // Attributes
1125 
1126  // Friend operator functions
1127 #if HAVE_BUILTIN(__builtin_bit_cast)
1128  friend constexpr
1129 #else
1130  friend inline
1131 #endif
1132  auto operator == (const FChar& lhs, const FChar& rhs) noexcept -> bool
1133  {
1134  if ( lhs.color.data != rhs.color.data )
1135  return false;
1136 
1137  constexpr auto mask = getCompareBitMask();
1138 
1139  if ( (lhs.attr.data & mask) != (rhs.attr.data & mask) )
1140  return false;
1141 
1142 #if defined(__clang__)
1143  #pragma clang diagnostic push
1144  #if __has_warning("-Wunsafe-buffer-usage")
1145  #pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
1146  #endif
1147 #endif
1148  return lhs.ch.unicode_data[0] == rhs.ch.unicode_data[0]
1149  && lhs.ch.unicode_data[1] == rhs.ch.unicode_data[1]
1150  && lhs.ch.unicode_data[2] == rhs.ch.unicode_data[2]
1151  && lhs.ch.unicode_data[3] == rhs.ch.unicode_data[3]
1152  && lhs.ch.unicode_data[4] == rhs.ch.unicode_data[4];
1153 #if defined(__clang__)
1154  #pragma clang diagnostic pop
1155 #endif
1156  }
1157 
1158 #if HAVE_BUILTIN(__builtin_bit_cast)
1159  friend constexpr
1160 #else
1161  friend inline
1162 #endif
1163  auto operator != (const FChar& lhs, const FChar& rhs) noexcept -> bool
1164  {
1165  return ! ( lhs == rhs );
1166  }
1167 };
1168 
1169 } // namespace finalcut
1170 
1171 #endif // FTYPES_H
Definition: ftypes.h:249
Definition: ftypes.h:633
Definition: ftypes.h:607
Definition: class_template.cpp:25
Definition: ftypes.h:956
Definition: ftypes.h:1081
Definition: ftypes.h:223
Definition: ftypes.h:152
Definition: ftypes.h:609
Definition: ftypes.h:384
Definition: ftypes.h:950
Definition: ftypes.h:100
Definition: ftypes.h:161
Definition: ftypes.h:808