FINAL CUT
fdata.h
1 /***********************************************************************
2 * fdata.h - A general-purpose data wrapper *
3 * *
4 * This file is part of the FINAL CUT widget toolkit *
5 * *
6 * Copyright 2020-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 /* Inheritance diagram
24  * ═══════════════════
25  *
26  * ▕▔▔▔▔▔▔▔▔▔▔▔▔▔▏
27  * ▕ FDataAccess ▏
28  * ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▏
29  * ▲
30  * │
31  * ▕▔▔▔▔▔▔▔▏
32  * ▕ FData ▏
33  * ▕▁▁▁▁▁▁▁▏
34  */
35 
36 #ifndef FDATA_H
37 #define FDATA_H
38 
39 #if !defined (USE_FINAL_H) && !defined (COMPILE_FINAL_CUT)
40  #error "Only <final/final.h> can be included directly."
41 #endif
42 
43 #include <functional>
44 #include <memory>
45 #include <stdexcept>
46 #include <type_traits>
47 #include <utility>
48 
49 #include "final/util/fstring.h"
50 
51 namespace finalcut
52 {
53 
54 template <typename T>
55 class FData; // Class forward declaration
56 
57 // non-member functions
58 //----------------------------------------------------------------------
59 namespace internal
60 {
61 
62 // Define the clean condition
63 template <typename T>
64 using cleanCondition_t = \
65  std::conditional_t<std::is_array<T>::value
66  , std::remove_extent_t<T>*
67  , std::conditional_t<std::is_function<T>::value
68  , std::add_pointer_t<T>
69  , T>>;
70 
71 // Type trait helpers for better error messages
72 //----------------------------------------------------------------------
73 template <typename T>
74 struct is_reference_wrapper_helper : std::false_type
75 { };
76 
77 template <typename T>
78 struct is_reference_wrapper_helper<std::reference_wrapper<T>> : std::true_type
79 { };
80 
81 template <typename T>
83 { };
84 
85 template<typename T>
86 constexpr bool is_reference_wrapper_v = is_reference_wrapper<T>::value;
87 
88 } // namespace internal
89 
90 //----------------------------------------------------------------------
91 template <typename T>
93 {
94  private:
95  using remove_ref = std::remove_reference_t<T>;
96 
97  public:
98  // Similar to std::decay, but keeps const and volatile
99  using type = internal::cleanCondition_t<remove_ref>;
100 
101  // Static assertions for better error messages
102  static_assert ( ! std::is_void<remove_ref>::value
103  , "FData cannot store void types" );
104  static_assert ( ! internal::is_reference_wrapper_v<remove_ref>
105  , "FData cannot store reference_wrapper types directly" );
106 };
107 
108 //----------------------------------------------------------------------
109 template <typename T>
110 using clean_fdata_t = typename cleanFData<T>::type;
111 
112 //----------------------------------------------------------------------
113 template <typename T>
114 inline auto makeFData (T&& data) -> std::unique_ptr<FData<clean_fdata_t<T>>>
115 {
116  using CleanT = clean_fdata_t<T>;
117  static_assert ( std::is_constructible<CleanT, T&&>::value
118  , "Cannot construct FData with the provided type" );
119 
120  return std::make_unique<FData<clean_fdata_t<T>>>(std::forward<T>(data));
121 }
122 
123 
124 //----------------------------------------------------------------------
125 // class FDataAccess
126 //----------------------------------------------------------------------
127 
129 {
130  public:
131  // Constructor
132  FDataAccess() = default;
133 
134  // Destructor
135  virtual ~FDataAccess() noexcept;
136 
137  // Accessors
138  virtual auto getClassName() const -> FString
139  {
140  return "FDataAccess";
141  }
142 
143  template<typename T>
144  constexpr auto get() noexcept -> clean_fdata_t<T>&
145  {
146  static_assert ( ! std::is_void<T>::value
147  , "Cannot get void type from FDataAccess" );
148 
149  return static_cast<FData<clean_fdata_t<T>>*>(this)->get();
150  }
151 
152  template<typename T>
153  constexpr auto get() const noexcept -> const clean_fdata_t<T>&
154  {
155  static_assert ( ! std::is_void<T>::value
156  , "Cannot get void type from FDataAccess" );
157 
158  return static_cast<const FData<clean_fdata_t<T>>*>(this)->get();
159  }
160 
161  // Mutator
162  template <typename T
163  , typename V>
164  constexpr void set (V&& data) noexcept(noexcept(std::declval<FData<T>>().set(std::forward<V>(data))))
165  {
166  static_assert ( std::is_convertible<V&&, T>::value
167  , "Type V must be convertible to type T" );
168 
169  static_cast<FData<T>*>(this)->set(std::forward<V>(data));
170  }
171 };
172 
173 
174 //----------------------------------------------------------------------
175 // class FData
176 //----------------------------------------------------------------------
177 
178 template <typename T>
179 class FData final : public FDataAccess
180 {
181  public:
182  // Using-declarations
183  using value_type = T;
184  using reference = value_type&;
185  using const_reference = const value_type&;
186  using T_nocv = std::remove_cv_t<value_type>;
187 
188  // Noexcept trait shortcuts
189  static constexpr bool nothrow_copy_ctor_v = \
190  std::is_nothrow_copy_constructible<value_type>::value;
191 
192  static constexpr bool nothrow_move_ctor_v = \
193  std::is_nothrow_move_constructible<value_type>::value;
194 
195  static constexpr bool nothrow_copy_asgn_v = \
196  std::is_nothrow_copy_assignable<value_type>::value;
197 
198  static constexpr bool nothrow_move_asgn_v = \
199  std::is_nothrow_move_assignable<value_type>::value;
200 
201  // Static assertions for better error messages
202  static_assert ( ! std::is_void<value_type>::value
203  , "FData cannot store void types") ;
204  static_assert ( ! std::is_reference<value_type>::value
205  , "FData cannot store reference types directly" );
206 
207  // Constructors
208  explicit FData (value_type& v) noexcept // constructor
209  : value_ref{v}
210  { }
211 
212  explicit FData (value_type&& v) noexcept(nothrow_move_ctor_v) // constructor
213  : value{std::move(v)}
214  , value_ref{value}
215  { }
216 
217  ~FData() noexcept override = default; // Destructor
218 
219  FData (const FData& d) noexcept(nothrow_copy_ctor_v) // Copy constructor
220  : FDataAccess{d}
221  , value{d.value}
222  , value_ref{d.isInitializedCopy() ? std::ref(value) : d.value_ref}
223  { }
224 
225  FData (FData&& d) noexcept // Move constructor
226  : FDataAccess{std::move(d)}
227  , value{std::move(d.value)}
228  , value_ref{d.isInitializedCopy() ? std::ref(value) : d.value_ref}
229  { }
230 
231  // Copy assignment operator (=)
232  auto operator = (const FData& d) noexcept(nothrow_copy_asgn_v) -> FData&
233  {
234  if ( &d != this )
235  {
236  value = d.value;
237 
238  if ( d.isInitializedCopy() )
239  value_ref = value;
240  else
241  value_ref = d.value_ref;
242  }
243 
244  return *this;
245  }
246 
247  // Move assignment operator (=)
248  auto operator = (FData&& d) noexcept -> FData&
249  {
250  if ( &d != this )
251  {
252  value = std::move(d.value);
253 
254  if ( d.isInitializedCopy() )
255  value_ref = value;
256  else
257  value_ref = std::move(d.value_ref);
258  }
259 
260  return *this;
261  }
262 
263  // Function call operator
264  constexpr auto operator () () const noexcept(nothrow_copy_ctor_v) -> value_type
265  {
266  return value_ref;
267  }
268 
269  constexpr explicit operator value_type () const noexcept(nothrow_copy_ctor_v)
270  {
271  return value_ref;
272  }
273 
274  constexpr auto operator << (const_reference v) noexcept(nothrow_copy_asgn_v) -> FData&
275  {
276  value_ref.get() = v;
277  return *this;
278  }
279 
280  // Accessors
281  auto getClassName() const -> FString override
282  {
283  return "FData";
284  }
285 
286  constexpr auto get() const noexcept -> const_reference
287  {
288  return value_ref.get();
289  }
290 
291  constexpr auto get() noexcept -> reference
292  {
293  return value_ref.get();
294  }
295 
296  // Mutator
297  constexpr void set (const value_type& v) noexcept(nothrow_copy_asgn_v)
298  {
299  value_ref.get() = v;
300  }
301 
302  constexpr void set (value_type&& v) noexcept(nothrow_move_asgn_v)
303  {
304  value_ref.get() = std::move(v);
305  }
306 
307  // Predicates
308  constexpr auto isInitializedCopy() const noexcept -> bool
309  {
310  return std::addressof(value) == std::addressof(value_ref.get());
311  }
312 
313  constexpr auto isInitializedReference() const noexcept -> bool
314  {
315  return ! isInitializedCopy();
316  }
317 
318  // Friend Non-member operator functions
319  constexpr friend auto operator << (std::ostream &os, const FData& data) -> std::ostream&
320  {
321  os << data.value_ref.get();
322  return os;
323  }
324 
325  private:
326  // Data members
327  value_type value{};
328  std::reference_wrapper<value_type> value_ref;
329 };
330 
331 } // namespace finalcut
332 
333 #endif // FDATA_H
Definition: fdata.h:128
Definition: fstring.h:906
Definition: fdata.h:92
Definition: class_template.cpp:25
Definition: fstring.h:82
Definition: fdata.h:55