HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
VE_Result.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: VE_Result.h (C++)
7  *
8  * COMMENTS:
9  *
10  *
11  */
12 
13 #ifndef __VE_RESULT_H__
14 #define __VE_RESULT_H__
15 
16 #include <UT/UT_UniquePtr.h>
17 #include <UT/UT_WorkBuffer.h>
18 
19 #include "VE_API.h"
20 #include "VE_VK.h"
21 #include <variant>
22 
23 template <typename T, typename E>
24 class [[nodiscard]] VE_ResultBase
25 {
26 public:
27  VE_ResultBase(T &&t) : myItem(std::move(t)){};
28  VE_ResultBase(E &&e) : myItem(std::move(e)){};
29 
30  static VE_ResultBase<T, E> copyFrom(T t) { return VE_ResultBase(std::move(t)); }
31 
32  /// Returns true if we have a valid result. Otherwise, we have an error.
33  bool ok() const { return std::holds_alternative<T>(myItem); }
34 
35  /// Moves the value out of result. Once this is called, the VE_ResultBase
36  /// object is in an undefined state and MUST NOT be accessed again.
37  T &&unpack()
38  {
39  auto t = std::get_if<T>(&myItem);
40  UT_ASSERT(t);
41  return std::move(*t);
42  }
43 
44  /// Moves the error out of result. Once this is called, the VE_ResultBase
45  /// object is in an undefined state and MUST NOT be accessed again.
46  E &&error()
47  {
48  auto t = std::get_if<E>(&myItem);
49  UT_ASSERT(t);
50  return std::move(*t);
51  }
52 
53  /// Copies the value out for classes that suuport copying, allowing result
54  /// to still be used.
55  /// I am not sure if this is an actually a useful method to have, and am
56  /// worried it might provide a false sense of safety around accessing result
57  /// values multiply times.
58  T peek()
59  {
60  auto t = std::get_if<T>(&myItem);
61  UT_ASSERT(t);
62  return *t;
63  }
64 
65 protected:
66  std::variant<T, E> myItem;
67 };
68 
70 {
71 public:
72  using CodeType = uint32_t;
73 
74  enum class Code : CodeType
75  {
76  success,
77  generic_error,
78  instance_creation_failed,
79  extension_unavailable,
80  extension_not_enabled,
81  extension_name_collision,
82  layer_not_present,
83  feature_unavailable,
84  failed_to_enumerate_devices,
85  failed_to_enumerate_device_extension_properties,
86  device_creation_failed,
87  vma_allocator_creation_failed,
88  image_creation_failed,
89  buffer_creation_failed,
90  memory_map_failed,
91  out_of_host_memory,
92  out_of_device_memory,
93  ray_tracing_support_unavailable,
94  swift_shader_unavailable,
95  };
96 
97  static constexpr Code code_from_vk_result(VkResult);
98  static constexpr const char *message_from_code(Code);
99 
100  VE_Error() : myCode(Code::generic_error) {}
101  VE_Error(Code c) : myCode(c) {}
102  VE_Error(VkResult r) : myCode(code_from_vk_result(r)) {}
103  VE_Error(Code c, VkResult r) : myCode(c), myVkResult(r) {}
104 
105  template <typename... Args>
106  VE_Error(Code c, const char *fmt, const Args &...args) : myCode(c)
107  {
108  if (!myMsg)
109  myMsg = UTmakeUnique<UT_WorkBuffer>();
110  myMsg->format(fmt, args...);
111  }
112 
113  template <typename... Args>
114  VE_Error(const char *fmt, const Args &...args) : myCode(Code::generic_error)
115  {
116  if (!myMsg)
117  myMsg = UTmakeUnique<UT_WorkBuffer>();
118  myMsg->format(fmt, args...);
119  }
120 
121  template <typename... Args>
122  void appendFormat(const char *fmt, const Args &...args)
123  {
124  if (!myMsg)
125  myMsg = UTmakeUnique<UT_WorkBuffer>();
126  myMsg->appendFormat(fmt, args...);
127  }
128 
129  const char *message() const
130  {
131  if (!myMsg)
132  {
133  return message_from_code(myCode);
134  }
135  return myMsg->buffer();
136  }
137 
138  void printMsg() const
139  {
140  fprintf(stderr, "VE_Error: %s\n", message());
141  if (myVkResult != VK_SUCCESS)
142  {
143  fprintf(stderr, "VkResult code: %d\n", myVkResult);
144  }
145  }
146 
147  Code code() const { return myCode; }
148 
149 private:
150  Code myCode;
151  VkResult myVkResult = VK_SUCCESS;
153 };
154 
155 /// A class to contain either a value or an error.
156 /// It is meant to provide a value-semantics based approached to error handling,
157 /// allowing functions to return either a value or an error in the same type.
158 ///
159 /// It currently works with any value type provided it is moveable. Future work
160 /// could be done to support classes that are copy-able but not moveable, though
161 /// I think such types are rarer in practice.
162 ///
163 /// Example usage:
164 ///
165 /// VE_Result<SomeType>
166 /// fooBar()
167 /// {
168 /// Usage pattern is generally this:
169 ///
170 /// auto result = functionThatCanError();
171 /// if (!result.ok())
172 /// // Error can be handled or bubbled up to caller.
173 /// return result.error();
174 ///
175 /// // Note that this moves the value out of result and so
176 /// // result must not be accessed again beyond this point.
177 /// auto payload = result.unpack();
178 ///
179 /// SomeType st(payload);
180 ///
181 /// // Type is automatically converted to Result<Type>
182 /// return st;
183 /// }
184 ///
185 template <typename T>
186 class [[nodiscard]] VE_Result : public VE_ResultBase<T, VE_Error>
187 {
188 public:
190 
191  VE_Result() : Base(VE_Error(VE_Error::Code::generic_error)) {}
192 
193  VE_Result(T &&t) : Base(std::move(t)) {}
194  VE_Result(VE_Error &&e) : Base(std::move(e)){}
196 
197  static VE_Result<T> copyFrom(T t) { return VE_Result(std::move(t)); }
198 
200  {
201  return Base::peek();
202  }
203 };
204 
206 
207 static inline VE_VoidResult
208 VEvoidSuccess()
209 {
210  return VE_VoidResult(std::monostate());
211 }
212 
213 constexpr inline VE_Error::Code
215 {
216  using c = VE_Error::Code;
217 
218  switch (r)
219  {
220  case VK_SUCCESS:
221  return c::success;
223  return c::out_of_host_memory;
225  return c::out_of_device_memory;
227  return c::memory_map_failed;
229  return c::layer_not_present;
230  default:
231  return c::generic_error;
232  }
233 }
234 
236 {
237  switch (c)
238  {
239  case VE_Error::Code::success: return "success";
240  case VE_Error::Code::instance_creation_failed: return "failed to create vulkan instance";
241  case VE_Error::Code::extension_unavailable: return "extension unavailable";
242  case VE_Error::Code::extension_name_collision: return "extension name collision";
243  case VE_Error::Code::layer_not_present: return "instance layer is not present";
244  case VE_Error::Code::feature_unavailable: return "feature is unavailable";
245  case VE_Error::Code::failed_to_enumerate_devices: return "failed to enumerate devices";
246  case VE_Error::Code::failed_to_enumerate_device_extension_properties: return "failed to enumerate extension properties";
247  case VE_Error::Code::device_creation_failed: return "device creation failed";
248  case VE_Error::Code::vma_allocator_creation_failed: return "vma allocator creation failed";
249  case VE_Error::Code::image_creation_failed: return "image creation failed";
250  case VE_Error::Code::buffer_creation_failed: return "buffer creation failed";
251  case VE_Error::Code::memory_map_failed: return "memory mapping failed";
252  case VE_Error::Code::out_of_host_memory: return "out of host memory";
253  case VE_Error::Code::out_of_device_memory: return "out of video memory";
254  case VE_Error::Code::extension_not_enabled: return "extension is not enabled";
255  case VE_Error::Code::generic_error: return "error";
256  case VE_Error::Code::ray_tracing_support_unavailable: return "ray tracing support unavailable";
257  case VE_Error::Code::swift_shader_unavailable: return "swift shader unavailable";
258  }
259 
260  return "error";
261 }
262 
263 #endif
E && error()
Definition: VE_Result.h:46
GLuint GLsizei const GLchar * message
Definition: glcorearb.h:2543
VE_Result< std::monostate > VE_VoidResult
Definition: VE_Result.h:205
VkResult
Definition: vulkan_core.h:139
VE_Error(VkResult r)
Definition: VE_Result.h:102
uint32_t CodeType
Definition: VE_Result.h:72
std::variant< T, E > myItem
Definition: VE_Result.h:66
VE_Result(VE_Error::Code c)
Definition: VE_Result.h:195
static constexpr Code code_from_vk_result(VkResult)
Definition: VE_Result.h:214
bool ok() const
Returns true if we have a valid result. Otherwise, we have an error.
Definition: VE_Result.h:33
T value()
Definition: VE_Result.h:199
static VE_Result< T > copyFrom(T t)
Definition: VE_Result.h:197
VE_Result(T &&t)
Definition: VE_Result.h:193
std::unique_ptr< T, Deleter > UT_UniquePtr
A smart pointer for unique ownership of dynamically allocated objects.
Definition: UT_UniquePtr.h:39
#define VE_API
Definition: VE_API.h:20
VE_Error(const char *fmt, const Args &...args)
Definition: VE_Result.h:114
T && unpack()
Definition: VE_Result.h:37
static VE_ResultBase< T, E > copyFrom(T t)
Definition: VE_Result.h:30
VE_ResultBase(T &&t)
Definition: VE_Result.h:27
auto fprintf(std::FILE *f, const S &fmt, const T &...args) -> int
Definition: printf.h:602
GLdouble t
Definition: glad.h:2397
const char * message() const
Definition: VE_Result.h:129
void printMsg() const
Definition: VE_Result.h:138
VE_ResultBase(E &&e)
Definition: VE_Result.h:28
VE_Error(Code c, VkResult r)
Definition: VE_Result.h:103
void appendFormat(const char *fmt, const Args &...args)
Definition: VE_Result.h:122
**If you just want to fire and args
Definition: thread.h:609
static constexpr const char * message_from_code(Code)
Definition: VE_Result.h:235
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:156
GLboolean r
Definition: glcorearb.h:1222
Code code() const
Definition: VE_Result.h:147
VE_Error()
Definition: VE_Result.h:100
VE_Result(VE_Error &&e)
Definition: VE_Result.h:194
VE_Error(Code c)
Definition: VE_Result.h:101
VE_Error(Code c, const char *fmt, const Args &...args)
Definition: VE_Result.h:106