FINAL CUT
fstring.h
1 /***********************************************************************
2 * fstring.h - Unicode string class with UTF-8 support *
3 * *
4 * This file is part of the FINAL CUT widget toolkit *
5 * *
6 * Copyright 2012-2024 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 /* Standalone class
24  * ════════════════
25  *
26  * ▕▔▔▔▔▔▔▔▔▔▏
27  * ▕ FString ▏
28  * ▕▁▁▁▁▁▁▁▁▁▏
29  */
30 
31 #ifndef FSTRING_H
32 #define FSTRING_H
33 
34 #if !defined (USE_FINAL_H) && !defined (COMPILE_FINAL_CUT)
35  #error "Only <final/final.h> can be included directly."
36 #endif
37 
38 #include <langinfo.h>
39 
40 #include <cassert>
41 #include <cerrno> // for read errno
42 #include <cfloat>
43 #include <climits>
44 #include <cmath>
45 #include <cstdarg> // need for va_list, va_start and va_end
46 #include <cstdint>
47 #include <cstdio> // need for vsprintf
48 #include <cstring>
49 #include <cwchar>
50 #include <cwctype>
51 
52 #include <array>
53 #include <iostream>
54 #include <limits>
55 #include <new>
56 #include <stdexcept>
57 #include <string>
58 #include <type_traits>
59 #include <utility>
60 #include <vector>
61 
62 #include "final/fc.h"
63 #include "final/ftypes.h"
64 
65 namespace finalcut
66 {
67 
68 // class forward declaration
69 class FString;
70 
71 // Global using-declaration
72 using FStringList = std::vector<FString>;
73 
74 
75 //----------------------------------------------------------------------
76 // class FString
77 //----------------------------------------------------------------------
78 
79 class FString
80 {
81  public:
82  // Using-declarations
83  using size_type = std::wstring::size_type;
84  using difference_type = std::wstring::difference_type;
85  using iterator = std::wstring::iterator;
86  using const_iterator = std::wstring::const_iterator;
87  using reference = std::wstring::reference;
88  using const_reference = std::wstring::const_reference;
89 
90  // Constructors
91  FString () = default;
92  explicit FString (int);
93  explicit FString (std::size_t);
94  FString (std::size_t, wchar_t);
95  FString (std::size_t, const UniChar&);
96  FString (const FString&); // copy constructor
97  FString (FString&&) noexcept; // move constructor
98  FString (const std::wstring&); // implicit conversion constructor
99 #if __cplusplus >= 201703L
100  FString (const std::wstring_view&); // implicit conversion constructor
101 #endif
102  FString (std::wstring&&); // implicit conversion constructor
103  FString (const wchar_t[]); // implicit conversion constructor
104  FString (const std::string&); // implicit conversion constructor
105 #if __cplusplus >= 201703L
106  FString (const std::string_view&); // implicit conversion constructor
107 #endif
108  FString (const char[]); // implicit conversion constructor
109  FString (const UniChar&); // implicit conversion constructor
110  FString (const wchar_t); // implicit conversion constructor
111  FString (const char); // implicit conversion constructor
112 
113  // Destructor
114  virtual ~FString ();
115 
116  // Overloaded operators
117  auto operator = (const FString&) -> FString&;
118  auto operator = (FString&&) noexcept -> FString&;
119 
120  auto operator += (const FString&) -> const FString&;
121 
122  auto operator << (const FString&) -> FString&;
123  auto operator << (const UniChar&) -> FString&;
124  auto operator << (const wchar_t) -> FString&;
125  auto operator << (const char) -> FString&;
126  template <typename NumT
127  , std::enable_if_t< ( std::is_integral<NumT>::value
128  && ! std::is_same<NumT, bool>::value
129  && ! std::is_pointer<NumT>::value )
130  || ( std::is_floating_point<NumT>::value
131  && ! std::is_pointer<NumT>::value )
132  , int> = 0 >
133  auto operator << (const NumT) -> FString&;
134 
135  friend inline auto operator >> (const FString& lhs, FString& rhs) -> const FString&
136  {
137  rhs.string.append(lhs.toWString());
138  return lhs;
139  }
140 
141  friend inline auto operator >> (const FString& lhs, std::wstring& rhs) -> const FString&
142  {
143  rhs.append(lhs.toWString());
144  return lhs;
145  }
146 
147  friend inline auto operator >> (const FString& lhs, std::string& rhs) -> const FString&
148  {
149  rhs.append(lhs.toString());
150  return lhs;
151  }
152 
153  friend inline auto operator >> (const FString& lhs, wchar_t& rhs) -> const FString&
154  {
155  rhs = ( ! lhs.isEmpty() ) ? lhs.string[0] : L'\0';
156  return lhs;
157  }
158 
159  friend inline auto operator >> (const FString& lhs, char& rhs) -> const FString&
160  {
161  rhs = ( ! lhs.isEmpty() ) ? char(uChar(lhs.string[0])) : '\0';
162  return lhs;
163  }
164 
165  friend inline auto operator >> (const FString& lhs, sInt16& rhs) -> const FString&
166  {
167  rhs = lhs.toShort();
168  return lhs;
169  }
170 
171  friend inline auto operator >> (const FString& lhs, uInt16& rhs) -> const FString&
172  {
173  rhs = lhs.toUShort();
174  return lhs;
175  }
176 
177  friend inline auto operator >> (const FString& lhs, sInt32& rhs) -> const FString&
178  {
179  rhs = lhs.toInt();
180  return lhs;
181  }
182 
183  friend inline auto operator >> (const FString& lhs, uInt32& rhs) -> const FString&
184  {
185  rhs = lhs.toUInt();
186  return lhs;
187  }
188 
189  friend inline auto operator >> (const FString& lhs, sInt64& rhs) -> const FString&
190  {
191  rhs = lhs.toLong();
192  return lhs;
193  }
194 
195  friend inline auto operator >> (const FString& lhs, uInt64& rhs) -> const FString&
196  {
197  rhs = lhs.toULong();
198  return lhs;
199  }
200 
201  friend inline auto operator >> (const FString& lhs, double& rhs) -> const FString&
202  {
203  rhs = lhs.toDouble();
204  return lhs;
205  }
206 
207  friend inline auto operator >> (const FString& lhs, float& rhs) -> const FString&
208  {
209  rhs = lhs.toFloat();
210  return lhs;
211  }
212 
213  template <typename IndexT>
214  constexpr auto operator [] (const IndexT) -> reference;
215  template <typename IndexT>
216  constexpr auto operator [] (const IndexT) const -> const_reference;
217  explicit operator bool () const;
218  auto operator () () const -> const FString&;
219 
220  friend inline auto operator < (const FString& lhs, const FString& rhs) -> bool
221  {
222  return lhs.string < rhs.string;
223  }
224 
225  template <typename CharT
226  , enable_if_char_ptr_t<CharT> = nullptr>
227  friend inline auto operator < (const FString& lhs, const CharT& rhs) -> bool
228  {
229  lhs.char_string = lhs.internal_toCharString(lhs.string);
230  return rhs ? lhs.char_string.compare(rhs) < 0 : lhs.char_string.compare("") < 0;
231  }
232 
233  template <typename CharT
234  , enable_if_char_array_t<CharT> = nullptr>
235  friend inline auto operator < (const FString& lhs, const CharT& rhs) -> bool
236  {
237  lhs.char_string = lhs.internal_toCharString(lhs.string);
238  return lhs.char_string.compare(rhs) < 0;
239  }
240 
241  template <typename CharT
242  , enable_if_wchar_ptr_t<CharT> = nullptr>
243  friend inline auto operator < (const FString& lhs, const CharT& rhs) -> bool
244  {
245  return rhs ? lhs.string.compare(rhs) < 0 : lhs.string.compare(L"") < 0;
246  }
247 
248  template <typename CharT
249  , enable_if_wchar_array_t<CharT> = nullptr>
250  friend inline auto operator < (const FString& lhs, const CharT& rhs) -> bool
251  {
252  return lhs.string.compare(rhs) < 0;
253  }
254 
255  friend inline auto operator <= (const FString& lhs, const FString& rhs) -> bool
256  {
257  return lhs.string <= rhs.string;
258  }
259 
260  template <typename CharT
261  , enable_if_char_ptr_t<CharT> = nullptr>
262  friend inline auto operator <= (const FString& lhs, const CharT& rhs) -> bool
263  {
264  lhs.char_string = lhs.internal_toCharString(lhs.string);
265  return rhs ? lhs.char_string.compare(rhs) <= 0 : lhs.char_string.compare("") <= 0;
266  }
267 
268  template <typename CharT
269  , enable_if_char_array_t<CharT> = nullptr>
270  friend inline auto operator <= (const FString& lhs, const CharT& rhs) -> bool
271  {
272  lhs.char_string = lhs.internal_toCharString(lhs.string);
273  return lhs.char_string.compare(rhs) <= 0;
274  }
275 
276  template <typename CharT
277  , enable_if_wchar_ptr_t<CharT> = nullptr>
278  friend inline auto operator <= (const FString& lhs, const CharT& rhs) -> bool
279  {
280  return rhs ? lhs.string.compare(rhs) <= 0 : lhs.string.compare(L"") <= 0;
281  }
282 
283  template <typename CharT
284  , enable_if_wchar_array_t<CharT> = nullptr>
285  friend inline auto operator <= (const FString& lhs, const CharT& rhs) -> bool
286  {
287  return lhs.string.compare(rhs) <= 0;
288  }
289 
290  friend inline auto operator == (const FString& lhs, const FString& rhs) -> bool
291  {
292  return lhs.string == rhs.string;
293  }
294 
295  template <typename CharT
296  , enable_if_char_ptr_t<CharT> = nullptr>
297  friend inline auto operator == (const FString& lhs, const CharT& rhs) -> bool
298  {
299  lhs.char_string = lhs.internal_toCharString(lhs.string);
300  return rhs ? lhs.char_string.compare(rhs) == 0 : lhs.char_string.compare("") == 0;
301  }
302 
303  template <typename CharT
304  , enable_if_char_array_t<CharT> = nullptr>
305  friend inline auto operator == (const FString& lhs, const CharT& rhs) -> bool
306  {
307  lhs.char_string = lhs.internal_toCharString(lhs.string);
308  return lhs.char_string.compare(rhs) == 0;
309  }
310 
311  template <typename CharT
312  , enable_if_wchar_ptr_t<CharT> = nullptr>
313  friend inline auto operator == (const FString& lhs, const CharT& rhs) -> bool
314  {
315  return rhs ? lhs.string.compare(rhs) == 0 : lhs.string.compare(L"") == 0;
316  }
317 
318  template <typename CharT
319  , enable_if_wchar_array_t<CharT> = nullptr>
320  friend inline auto operator == (const FString& lhs, const CharT& rhs) -> bool
321  {
322  return lhs.string.compare(rhs) == 0;
323  }
324 
325  friend inline auto operator != (const FString& lhs, const FString& rhs) -> bool
326  {
327  return ! ( lhs == rhs );
328  }
329 
330  template <typename CharT
331  , enable_if_char_ptr_t<CharT> = nullptr>
332  friend inline auto operator != (const FString& lhs, const CharT& rhs) -> bool
333  {
334  lhs.char_string = lhs.internal_toCharString(lhs.string);
335  return rhs ? lhs.char_string.compare(rhs) != 0 : lhs.char_string.compare("") != 0;
336  }
337 
338  template <typename CharT
339  , enable_if_char_array_t<CharT> = nullptr>
340  friend inline auto operator != (const FString& lhs, const CharT& rhs) -> bool
341  {
342  lhs.char_string = lhs.internal_toCharString(lhs.string);
343  return lhs.char_string.compare(rhs) != 0;
344  }
345 
346  template <typename CharT
347  , enable_if_wchar_ptr_t<CharT> = nullptr>
348  friend inline auto operator != (const FString& lhs, const CharT& rhs) -> bool
349  {
350  return rhs ? lhs.string.compare(rhs) != 0 : lhs.string.compare(L"") != 0;
351  }
352 
353  template <typename CharT
354  , enable_if_wchar_array_t<CharT> = nullptr>
355  friend inline auto operator != (const FString& lhs, const CharT& rhs) -> bool
356  {
357  return lhs.string.compare(rhs) != 0;
358  }
359 
360  friend inline auto operator >= (const FString& lhs, const FString& rhs) -> bool
361  {
362  return lhs.string >= rhs.string;
363  }
364 
365  template <typename CharT
366  , enable_if_char_ptr_t<CharT> = nullptr>
367  friend inline auto operator >= (const FString& lhs, const CharT& rhs) -> bool
368  {
369  lhs.char_string = lhs.internal_toCharString(lhs.string);
370  return rhs ? lhs.char_string.compare(rhs) >= 0 : lhs.char_string.compare("") >= 0;
371  }
372 
373  template <typename CharT
374  , enable_if_char_array_t<CharT> = nullptr>
375  friend inline auto operator >= (const FString& lhs, const CharT& rhs) -> bool
376  {
377  lhs.char_string = lhs.internal_toCharString(lhs.string);
378  return lhs.char_string.compare(rhs) >= 0;
379  }
380 
381  template <typename CharT
382  , enable_if_wchar_ptr_t<CharT> = nullptr>
383  friend inline auto operator >= (const FString& lhs, const CharT& rhs) -> bool
384  {
385  return rhs ? lhs.string.compare(rhs) >= 0 : lhs.string.compare(L"") >= 0;
386  }
387 
388  template <typename CharT
389  , enable_if_wchar_array_t<CharT> = nullptr>
390  friend inline auto operator >= (const FString& lhs, const CharT& rhs) -> bool
391  {
392  return lhs.string.compare(rhs) >= 0;
393  }
394 
395  friend inline auto operator > (const FString& lhs, const FString& rhs) -> bool
396  {
397  return lhs.string > rhs.string;
398  }
399 
400  template <typename CharT
401  , enable_if_char_ptr_t<CharT> = nullptr>
402  friend inline auto operator > (const FString& lhs, const CharT& rhs) -> bool
403  {
404  lhs.char_string = lhs.internal_toCharString(lhs.string);
405  return rhs ? lhs.char_string.compare(rhs) > 0 : lhs.char_string.compare("") > 0;
406  }
407 
408  template <typename CharT
409  , enable_if_char_array_t<CharT> = nullptr>
410  friend inline auto operator > (const FString& lhs, const CharT& rhs) -> bool
411  {
412  lhs.char_string = lhs.internal_toCharString(lhs.string);
413  return lhs.char_string.compare(rhs) > 0;
414  }
415 
416  template <typename CharT
417  , enable_if_wchar_ptr_t<CharT> = nullptr>
418  friend inline auto operator > (const FString& lhs, const CharT& rhs) -> bool
419  {
420  return rhs ? lhs.string.compare(rhs) > 0 : lhs.string.compare(L"") > 0;
421  }
422 
423  template <typename CharT
424  , enable_if_wchar_array_t<CharT> = nullptr>
425  friend inline auto operator > (const FString& lhs, const CharT& rhs) -> bool
426  {
427  return lhs.string.compare(rhs) > 0;
428  }
429 
430  // Accessor
431  virtual auto getClassName() const -> FString;
432 
433  // inquiries
434  auto isEmpty() const noexcept -> bool;
435 
436  // Methods
437  auto getLength() const noexcept -> std::size_t;
438  auto capacity() const noexcept -> std::size_t;
439 
440  auto begin() noexcept -> iterator;
441  auto end() noexcept -> iterator;
442  auto begin() const -> const_iterator;
443  auto end() const -> const_iterator;
444  auto cbegin() const noexcept -> const_iterator;
445  auto cend() const noexcept -> const_iterator;
446  auto front() -> reference;
447  auto back() -> reference;
448  auto front() const -> const_reference;
449  auto back() const -> const_reference;
450 
451  template <typename... Args>
452  auto sprintf (const FString&, Args&&...) -> FString&;
453  auto clear() -> FString&;
454 
455  auto wc_str() const -> const wchar_t*;
456  auto wc_str() -> wchar_t*;
457  auto c_str() const -> const char*;
458  auto c_str() -> char*;
459  auto toWString() const -> std::wstring;
460  auto toString() const -> std::string;
461 
462  auto toLower() const -> FString;
463  auto toUpper() const -> FString;
464 
465  auto toShort() const -> sInt16;
466  auto toUShort() const -> uInt16;
467  auto toInt() const -> int;
468  auto toUInt() const -> uInt;
469  auto toLong() const -> long;
470  auto toULong() const -> uLong;
471  auto toFloat() const -> float;
472  auto toDouble() const -> double;
473 
474  auto ltrim() const -> FString;
475  auto rtrim() const -> FString;
476  auto trim() const -> FString;
477 
478  auto left (std::size_t) const -> FString;
479  auto right (std::size_t) const -> FString;
480  auto mid (std::size_t, std::size_t) const -> FString;
481 
482  auto split (const FString&) const -> FStringList;
483  auto setString (const FString&) -> FString&;
484 
485  template <typename NumT>
486  auto setNumber (NumT, int = int(getPrecision<NumT>())) -> FString&;
487  auto setNumber (sInt64) -> FString&;
488  auto setNumber (uInt64) -> FString&;
489  auto setNumber (lDouble, int = int(getPrecision<lDouble>())) -> FString&;
490 
491  template <typename NumT>
492  auto setFormatedNumber (NumT, FString&& = nl_langinfo(THOUSEP)) -> FString&;
493  auto setFormatedNumber (sInt64, FString = nl_langinfo(THOUSEP)) -> FString&;
494  auto setFormatedNumber (uInt64, FString = nl_langinfo(THOUSEP)) -> FString&;
495 
496  auto insert (const FString&, int) -> const FString&;
497  auto insert (const FString&, std::size_t) -> const FString&;
498 
499  auto replace (const FString&, const FString&) const -> FString;
500 
501  auto replaceControlCodes() const -> FString;
502  auto expandTabs (int = 8) const -> FString;
503  auto removeDel() const -> FString;
504  auto removeBackspaces() const -> FString;
505 
506  auto overwrite (const FString&, int) -> const FString&;
507  auto overwrite (const FString&, std::size_t = 0) -> const FString&;
508 
509  auto remove (std::size_t, std::size_t) -> const FString&;
510  auto includes (const FString&) const -> bool;
511 
512  private:
513  // Constants
514  static constexpr auto INPBUFFER = uInt(200);
515  static constexpr auto MALFORMED_STRING = static_cast<std::size_t>(-1);
516 
517  // Methods
518  void internal_assign (std::wstring);
519  auto internal_toCharString (const std::wstring&) const -> std::string;
520  auto internal_toWideString (const char[]) const -> std::wstring;
521 
522  // Data members
523  std::wstring string{};
524  mutable std::string char_string{};
525  static wchar_t null_char;
526  static const wchar_t const_null_char;
527 
528  // Friend Non-member operator functions
529  friend auto operator + (const FString& s1, const FString& s2) -> FString
530  {
531  const auto& tmp = s1.string + s2.string;
532  return tmp;
533  }
534 
535  friend auto operator << (std::ostream& outstr, const FString& s) -> std::ostream&
536  {
537  const auto& width = std::size_t(outstr.width());
538 
539  if ( s.string.length() > 0 )
540  {
541  outstr << s.internal_toCharString(s.string);
542  }
543  else if ( width > 0 )
544  {
545  const std::string fill_str(width, outstr.fill());
546  outstr << fill_str;
547  }
548 
549  return outstr;
550  }
551 
552  friend auto operator >> (std::istream& instr, FString& s) -> std::istream&
553  {
554  std::array<char, FString::INPBUFFER + 1> buf{};
555  instr.getline (buf.data(), FString::INPBUFFER);
556  auto wide_string = s.internal_toWideString(buf.data());
557 
558  if ( ! wide_string.empty() )
559  {
560  s.internal_assign (std::move(wide_string));
561  }
562 
563  return instr;
564  }
565 
566  friend auto operator << (std::wostream& outstr, const FString& s) -> std::wostream&
567  {
568  const auto& width = std::size_t(outstr.width());
569 
570  if ( s.string.length() > 0 )
571  {
572  outstr << s.string;
573  }
574  else if ( width > 0 )
575  {
576  const std::wstring fill_str(width, outstr.fill());
577  outstr << fill_str;
578  }
579 
580  return outstr;
581  }
582 
583  friend auto operator >> (std::wistream& instr, FString& s) -> std::wistream&
584  {
585  std::array<wchar_t, FString::INPBUFFER + 1> buf{};
586  instr.getline (buf.data(), FString::INPBUFFER);
587  std::wstring str(buf.data());
588  s.internal_assign (std::move(str));
589  return instr;
590  }
591 
592  // Friend struct
593  friend struct std::hash<finalcut::FString>;
594 };
595 
596 // non-member function forward declarations
597 //----------------------------------------------------------------------
598 auto FStringCaseCompare (const FString&, const FString&) -> int;
599 
600 // FString inline functions
601 //----------------------------------------------------------------------
602 template <typename NumT
603  , std::enable_if_t< ( std::is_integral<NumT>::value
604  && ! std::is_same<NumT, bool>::value
605  && ! std::is_pointer<NumT>::value )
606  || ( std::is_floating_point<NumT>::value
607  && ! std::is_pointer<NumT>::value )
608  , int> >
609 inline auto FString::operator << (const NumT val) -> FString&
610 {
611  const FString numstr(FString().setNumber(val));
612  string.append(numstr.string);
613  return *this;
614 }
615 
616 //----------------------------------------------------------------------
617 template <typename IndexT>
618 constexpr auto FString::operator [] (const IndexT pos) -> reference
619 {
620  if ( isNegative(pos) || pos > IndexT(string.length()) )
621  throw std::out_of_range(""); // Invalid index position
622 
623  if ( std::size_t(pos) == string.length() )
624  return null_char;
625 
626  return string[std::size_t(pos)];
627 }
628 
629 //----------------------------------------------------------------------
630 template <typename IndexT>
631 constexpr auto FString::operator [] (const IndexT pos) const -> const_reference
632 {
633  if ( isNegative(pos) || pos > IndexT(string.length()) )
634  throw std::out_of_range(""); // Invalid index position
635 
636  if ( std::size_t(pos) == string.length() )
637  return const_null_char;
638 
639  return string[std::size_t(pos)];
640 }
641 
642 //----------------------------------------------------------------------
643 inline auto FString::getClassName() const -> FString
644 { return "FString"; }
645 
646 //----------------------------------------------------------------------
647 inline auto FString::isEmpty() const noexcept -> bool
648 { return string.empty(); }
649 
650 //----------------------------------------------------------------------
651 inline auto FString::getLength() const noexcept -> std::size_t
652 { return string.length(); }
653 
654 //----------------------------------------------------------------------
655 inline auto FString::capacity() const noexcept -> std::size_t
656 { return string.capacity(); }
657 
658 //----------------------------------------------------------------------
659 inline auto FString::begin() noexcept -> iterator
660 { return string.begin(); }
661 
662 //----------------------------------------------------------------------
663 inline auto FString::end() noexcept -> iterator
664 { return string.end(); }
665 
666 //----------------------------------------------------------------------
667 inline auto FString::begin() const -> const_iterator
668 { return this->string.begin(); }
669 
670 //----------------------------------------------------------------------
671 inline auto FString::end() const -> const_iterator
672 { return this->string.end(); }
673 
674 //----------------------------------------------------------------------
675 inline auto FString::cbegin() const noexcept -> const_iterator
676 { return this->string.cbegin(); }
677 
678 //----------------------------------------------------------------------
679 inline auto FString::cend() const noexcept -> const_iterator
680 { return this->string.cend(); }
681 
682 //----------------------------------------------------------------------
683 inline auto FString::front() -> reference
684 {
685  assert ( ! isEmpty() );
686  return string.front();
687 }
688 
689 //----------------------------------------------------------------------
690 inline auto FString::back() -> reference
691 {
692  assert( ! isEmpty() );
693  return string.back();
694 }
695 
696 //----------------------------------------------------------------------
697 inline auto FString::front() const -> const_reference
698 {
699  assert ( ! isEmpty() );
700  return string.front();
701 }
702 
703 //----------------------------------------------------------------------
704 inline auto FString::back() const -> const_reference
705 {
706  assert( ! isEmpty() );
707  return string.back();
708 }
709 
710 //----------------------------------------------------------------------
711 template <typename... Args>
712 inline auto FString::sprintf (const FString& format, Args&&... args) -> FString&
713 {
714  std::array<wchar_t, 4096> buf{};
715 
716  if ( format.isEmpty() )
717  {
718  clear();
719  return *this;
720  }
721 
722  std::swprintf ( buf.data(), buf.size(), format.wc_str()
723  , std::forward<Args>(args)... );
724  return setString(buf.data());
725 }
726 
727 //----------------------------------------------------------------------
728 template <typename NumT>
729 inline auto FString::setNumber (NumT num, int precision) -> FString&
730 {
731  if ( std::is_floating_point<NumT>::value )
732  return setNumber (lDouble(num), precision);
733 
734  if ( isNegative(num) )
735  return setNumber (sInt64(num));
736 
737  return setNumber (uInt64(num));
738 }
739 
740 //----------------------------------------------------------------------
741 template <typename NumT>
742 inline auto FString::setFormatedNumber (NumT num, FString&& separator) -> FString&
743 {
744  if ( isNegative(num) )
745  return setFormatedNumber (sInt64(num), std::move(separator));
746 
747  return setFormatedNumber (uInt64(num), std::move(separator));
748 }
749 
750 //----------------------------------------------------------------------
751 inline void FString::internal_assign (std::wstring s)
752 {
753  s.swap(string);
754 }
755 
756 } // namespace finalcut
757 
758 //----------------------------------------------------------------------
759 template <>
760 struct std::hash<finalcut::FString>
761 {
762  auto operator () (const finalcut::FString& p) const noexcept -> std::size_t
763  {
764  return std::hash<std::wstring>{}(p.string);
765  }
766 };
767 
768 #endif // FSTRING_H
Definition: class_template.cpp:25
Definition: fstring.h:79
Definition: ftypes.h:151