fork(1) download
  1. #include <exception>
  2. #include <stdexcept>
  3. #include <cstddef>
  4. #include <cstdint>
  5. #include <cstdlib>
  6. #include <iostream>
  7. #include <chrono>
  8.  
  9. using error_type = std::exception_ptr;
  10.  
  11. struct ResultBase
  12. {
  13. bool hasError() const
  14. {
  15. return *reinterpret_cast<const bool*>(this);
  16. }
  17.  
  18. std::exception_ptr error() const
  19. {
  20. return *reinterpret_cast<const error_type*>(
  21. reinterpret_cast<const char*>(this)
  22. + sizeof(std::max_align_t));
  23. }
  24.  
  25. protected:
  26. ResultBase() { }
  27. };
  28.  
  29. template <class T>
  30. struct Result : ResultBase
  31. {
  32. Result(error_type error)
  33. : mHasError(true) { new (&mError) error_type(error); }
  34.  
  35. Result(T value)
  36. : mHasError(false) { new (&mValue) T(value); }
  37.  
  38. ~Result()
  39. {
  40. if (mHasError)
  41. mError.~error_type();
  42. else
  43. mValue.~T();
  44. }
  45.  
  46. void setError(error_type error)
  47. {
  48. if (mHasError) {
  49. mError = error;
  50. } else {
  51. mValue.~T();
  52. new (&mError) error_type(error);
  53. mHasError = true;
  54. }
  55. }
  56.  
  57. void setValue(T value)
  58. {
  59. if (mHasError) {
  60. mError.~error_type();
  61. new (&mValue) T(value);
  62. mHasError = false;
  63. } else {
  64. mValue = value;
  65. }
  66. }
  67.  
  68. private:
  69. union {
  70. bool mHasError;
  71. std::max_align_t mAligner;
  72. };
  73. union {
  74. error_type mError;
  75. T mValue;
  76. };
  77. };
  78.  
  79. static_assert(std::is_standard_layout<Result<int>>::value, "");
  80.  
  81. void check(bool condition)
  82. {
  83. if (!condition) std::terminate();
  84. }
  85.  
  86. class ResultBase2
  87. {
  88. public:
  89. virtual ~ResultBase2() {}
  90.  
  91. virtual bool hasError() const = 0;
  92.  
  93. virtual std::exception_ptr error() const = 0;
  94.  
  95. protected:
  96. ResultBase2() {}
  97. };
  98.  
  99. template <class T>
  100. class Result2 : public ResultBase2
  101. {
  102. public:
  103. Result2(error_type error)
  104. {
  105. this->construct(error);
  106. }
  107. Result2(T value)
  108. {
  109. this->construct(value);
  110. }
  111.  
  112. ~Result2()
  113. {
  114. if (this->mHasError)
  115. this->mData.mError.~error_type();
  116. else
  117. this->mData.mValue.~T();
  118. }
  119.  
  120. bool hasError() const override { return mHasError; }
  121.  
  122. std::exception_ptr error() const override { return mData.mError; }
  123.  
  124. void setError(error_type error)
  125. {
  126. if (this->mHasError)
  127. {
  128. this->mData.mError = error;
  129. }
  130. else
  131. {
  132. this->mData.mValue.~T();
  133. this->construct(error);
  134. }
  135. }
  136.  
  137. void setValue(T value)
  138. {
  139. if (not this->mHasError)
  140. {
  141. this->mData.mValue = value;
  142. }
  143. else
  144. {
  145. this->mData.mError.~error_type();
  146. this->construct(value);
  147. }
  148. }
  149.  
  150. private:
  151. bool mHasError;
  152. union Data
  153. {
  154. Data() {}
  155. ~Data() {}
  156.  
  157. error_type mError;
  158. T mValue;
  159. } mData;
  160.  
  161. void construct(error_type error)
  162. {
  163. mHasError = true;
  164. new (&mData.mError) error_type(error);
  165. }
  166. void construct(T value)
  167. {
  168. mHasError = false;
  169. new (&mData.mValue) T(value);
  170. }
  171. };
  172.  
  173. class ResultBase3;
  174. struct ResultBase3Vtable
  175. {
  176. bool (*hasError)(const ResultBase3&);
  177. error_type (*error)(const ResultBase3&);
  178. };
  179.  
  180. class ResultBase3
  181. {
  182. public:
  183. bool hasError() const { return vtable->hasError(*this); }
  184.  
  185. std::exception_ptr error() const { return vtable->error(*this); }
  186.  
  187. protected:
  188. ResultBase3(ResultBase3Vtable* vtable) : vtable(vtable) {}
  189. private:
  190. ResultBase3Vtable* vtable;
  191. };
  192.  
  193. template <class T>
  194. class Result3 : public ResultBase3
  195. {
  196. public:
  197. Result3(error_type error) : ResultBase3(&Result3<T>::vtable)
  198. {
  199. this->construct(error);
  200. }
  201. Result3(T value) : ResultBase3(&Result3<T>::vtable)
  202. {
  203. this->construct(value);
  204. }
  205.  
  206. ~Result3()
  207. {
  208. if (this->mHasError)
  209. this->mData.mError.~error_type();
  210. else
  211. this->mData.mValue.~T();
  212. }
  213.  
  214. bool hasError() const { return mHasError; }
  215.  
  216. std::exception_ptr error() const { return mData.mError; }
  217.  
  218. void setError(error_type error)
  219. {
  220. if (this->mHasError)
  221. {
  222. this->mData.mError = error;
  223. }
  224. else
  225. {
  226. this->mData.mValue.~T();
  227. this->construct(error);
  228. }
  229. }
  230.  
  231. void setValue(T value)
  232. {
  233. if (not this->mHasError)
  234. {
  235. this->mData.mValue = value;
  236. }
  237. else
  238. {
  239. this->mData.mError.~error_type();
  240. this->construct(value);
  241. }
  242. }
  243.  
  244. private:
  245. bool mHasError;
  246. union Data
  247. {
  248. Data() {}
  249. ~Data() {}
  250.  
  251. error_type mError;
  252. T mValue;
  253. } mData;
  254.  
  255. void construct(error_type error)
  256. {
  257. mHasError = true;
  258. new (&mData.mError) error_type(error);
  259. }
  260. void construct(T value)
  261. {
  262. mHasError = false;
  263. new (&mData.mValue) T(value);
  264. }
  265.  
  266. static bool hasErrorVTable(const ResultBase3& result)
  267. {
  268. return static_cast<const Result3&>(result).hasError();
  269. }
  270. static error_type errorVTable(const ResultBase3& result)
  271. {
  272. return static_cast<const Result3&>(result).error();
  273. }
  274. static ResultBase3Vtable vtable;
  275. };
  276.  
  277. template <typename T>
  278. ResultBase3Vtable Result3<T>::vtable{
  279. &Result3<T>::hasErrorVTable,
  280. &Result3<T>::errorVTable,
  281. };
  282.  
  283.  
  284. template <typename Base, typename Result>
  285. void f(const Base& alias, Result& r)
  286. {
  287. check(!alias.hasError());
  288.  
  289. r.setError(std::exception_ptr());
  290. check(alias.hasError());
  291. check(alias.error() == nullptr);
  292.  
  293. r.setValue(1);
  294. check(!alias.hasError());
  295.  
  296. r.setError(std::make_exception_ptr(std::runtime_error("!")));
  297. check(alias.hasError());
  298. check(alias.error() != nullptr);
  299. }
  300.  
  301. template <std::size_t N, typename Operation>
  302. auto checkTime(Operation op)
  303. {
  304. using namespace std::chrono;
  305. high_resolution_clock::time_point t1 = high_resolution_clock::now();
  306. for (std::size_t i = 0u; i < N; ++i)
  307. op();
  308. high_resolution_clock::time_point t2 = high_resolution_clock::now();
  309. auto duration = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count();
  310. return duration;
  311. }
  312.  
  313. int main()
  314. {
  315. std::cout << checkTime<1>([] { Result<int> r(0); f(r, r); }) << std::endl;
  316. std::cout << checkTime<1>([] { Result2<int> r(0); f(r, r); }) << std::endl;
  317. std::cout << checkTime<1>([] { Result3<int> r(0); f(r, r); }) << std::endl;
  318.  
  319. std::cout << sizeof(Result<int>) << std::endl;
  320. std::cout << sizeof(Result2<int>) << std::endl;
  321. std::cout << sizeof(Result3<int>) << std::endl;
  322. }
  323.  
Success #stdin #stdout 0s 3460KB
stdin
Standard input is empty
stdout
66
9
8
32
12
12