OGLplus  (0.59.0) a C++ wrapper for rendering APIs

c_api_wrap.hpp
Go to the documentation of this file.
1 
9 #ifndef EAGINE_C_API_WRAP_HPP
10 #define EAGINE_C_API_WRAP_HPP
11 
12 #include "assert.hpp"
13 #include "cleanup_group.hpp"
14 #include "enum_bitfield.hpp"
15 #include "enum_class.hpp"
16 #include "extract.hpp"
17 #include "handle.hpp"
18 #include "int_constant.hpp"
19 #include "is_within_limits.hpp"
20 #include "nothing.hpp"
21 #include "string_span.hpp"
22 #include "type_identity.hpp"
24 #include "valid_if/always.hpp"
25 #include "valid_if/never.hpp"
26 #include <tuple>
27 #include <type_traits>
28 
29 namespace eagine {
30 //------------------------------------------------------------------------------
37 public:
38  constexpr c_api_constant_base(string_view name) noexcept
39  : _name{name} {}
40 
42  constexpr auto name() const noexcept {
43  return _name;
44  }
45 
46 private:
47  string_view _name{};
48 };
49 //------------------------------------------------------------------------------
52 template <typename T, typename Tag = nothing_t, bool IsIndexed = false>
55  , no_enum_value<T, Tag> {
56 public:
57  template <typename ApiTraits, typename Api>
58  constexpr no_c_api_constant(string_view name, ApiTraits&, Api&) noexcept
60 
62  template <typename I>
63  constexpr auto operator+(I) const noexcept -> std::
64  enable_if_t<(IsIndexed && std::is_integral_v<I>), no_enum_value<T, Tag>> {
65  return {};
66  }
67 };
68 //------------------------------------------------------------------------------
71 template <
72  typename ClassList,
73  typename T,
74  T value,
75  typename Tag = nothing_t,
76  bool IsIndexed = false>
79  , enum_value<T, ClassList, Tag> {
80 public:
81  template <typename ApiTraits, typename Api>
82  constexpr static_c_api_constant(string_view name, ApiTraits&, Api&) noexcept
85 
87  template <typename I>
88  constexpr auto operator+(I index) const noexcept -> std::enable_if_t<
89  (IsIndexed && std::is_integral_v<I>),
91  using O = std::conditional_t<
92  std::is_signed_v<T>,
93  std::make_signed_t<I>,
94  std::make_unsigned_t<I>>;
95  return {limit_cast<T>(value + limit_cast<O>(index))};
96  }
97 };
98 //------------------------------------------------------------------------------
101 template <
102  typename ClassList,
103  typename T,
104  typename Tag = nothing_t,
105  bool IsIndexed = false>
108  , opt_enum_value<T, ClassList, Tag> {
109 public:
110  using tag_type = Tag;
111 
112  template <typename ApiTraits, typename Api>
113  constexpr dynamic_c_api_constant(
115  ApiTraits& traits,
116  Api& api) noexcept
119  traits.load_constant(api, name, type_identity<T>())} {}
120 
122  template <typename I>
123  constexpr auto operator+(I index) const noexcept -> std::enable_if_t<
124  (IsIndexed && std::is_integral_v<I>),
126  using O = std::conditional_t<
127  std::is_signed_v<T>,
128  std::make_signed_t<I>,
129  std::make_unsigned_t<I>>;
130  return {limit_cast<T>(this->value + limit_cast<O>(index))};
131  }
132 };
133 //------------------------------------------------------------------------------
134 template <typename ClassList, typename Constant, typename Tag, bool IsIndexed>
135 struct get_opt_c_api_constant;
136 
137 template <typename ClassList, typename T, T value, typename Tag, bool IsIndexed>
138 struct get_opt_c_api_constant<
139  ClassList,
140  std::integral_constant<T, value>,
141  Tag,
142  IsIndexed>
143  : type_identity<static_c_api_constant<ClassList, T, value, Tag, IsIndexed>> {
144 };
145 
146 template <typename ClassList, typename T, typename Tag, bool IsIndexed>
147 struct get_opt_c_api_constant<ClassList, type_identity<T>, Tag, IsIndexed>
148  : type_identity<dynamic_c_api_constant<ClassList, T, Tag, IsIndexed>> {};
149 
169 template <
170  typename ClassList,
171  typename Constant,
172  typename Tag = nothing_t,
173  bool IsIndexed = false>
174 using opt_c_api_constant =
175  typename get_opt_c_api_constant<ClassList, Constant, Tag, IsIndexed>::type;
176 //------------------------------------------------------------------------------
179 template <typename Info>
181  : public std::runtime_error
182  , public Info {
183 public:
184  bad_result(Info&& info) noexcept
185  : std::runtime_error("bad operation result")
186  , Info(std::move(info)) {}
187 };
188 //------------------------------------------------------------------------------
194  always,
196  maybe,
198  never
199 };
200 //------------------------------------------------------------------------------
201 template <typename Result, api_result_validity>
202 class api_result_value;
203 
206 template <
207  typename Result,
208  typename Info,
211 
217 template <typename Result, typename Info>
219 
225 template <typename Result, typename Info>
227 //------------------------------------------------------------------------------
228 // api no result
229 //------------------------------------------------------------------------------
230 template <typename Result>
231 class api_result_value<Result, api_result_validity::never> {
232 public:
233  constexpr api_result_value() noexcept = default;
234 
235 protected:
236  template <typename Info, typename T>
237  auto _cast_to(
239  type_identity<T>) const {
241  static_cast<Info&>(result) = static_cast<const Info&>(src);
242  return result;
243  }
244 
245  template <typename Info, typename Transform>
246  auto _transformed(
248  Transform& transform) const {
249  using T = decltype(transform(std::declval<Result>()));
251  static_cast<Info&>(result) = static_cast<const Info&>(src);
252  return result;
253  }
254 
255  template <typename Info, typename Check, typename IfFalse>
256  auto _collapsed(
258  Check&,
259  IfFalse&) const {
261  static_cast<Info&>(result) = static_cast<const Info&>(src);
262  return result;
263  }
264 };
265 //------------------------------------------------------------------------------
267 //
268 template <typename Result>
269 static constexpr auto
270 extract(api_result_value<Result, api_result_validity::never>&) noexcept
271  -> Result& {
272  return unreachable_reference(type_identity<Result>{});
273 }
274 
275 template <typename Result>
276 static constexpr auto
277 extract(const api_result_value<Result, api_result_validity::never>&) noexcept
278  -> const Result& {
279  return unreachable_reference(type_identity<Result>{});
280 }
281 
282 template <typename Result, typename Info>
283 inline auto operator>>(
284  api_result<Result, Info, api_result_validity::never> result,
285  Result& dest) -> Result& {
286  throw bad_result<Info>(static_cast<Info&&>(result));
287  return dest = std::move(result._value);
288 }
289 //------------------------------------------------------------------------------
290 template <>
291 class api_result_value<void, api_result_validity::never> {
292 public:
293 protected:
294  template <typename Info, typename T>
295  auto _cast_to(
296  const api_result<void, Info, api_result_validity::never>& src,
297  type_identity<T>) const {
298  api_result<T, Info, api_result_validity::never> result{};
299  static_cast<Info&>(result) = static_cast<const Info&>(src);
300  return result;
301  }
302 
303  template <typename Info, typename Transform>
304  auto _transformed(
305  const api_result<void, Info, api_result_validity::never>& src,
306  Transform& transform) const {
307  using T = decltype(transform());
308  api_result<T, Info, api_result_validity::never> result{};
309  static_cast<Info&>(result) = static_cast<const Info&>(src);
310  return result;
311  }
312 
313  template <typename Info, typename Check, typename IfFalse>
314  auto _collapsed(
315  const api_result<void, Info, api_result_validity::never>& src,
316  Check&,
317  IfFalse&) const -> auto& {
318  return src;
319  }
320 };
321 //------------------------------------------------------------------------------
322 template <typename Result, typename Info>
323 class api_result<Result, Info, api_result_validity::never>
324  : public Info
325  , public api_result_value<Result, api_result_validity::never> {
326  using base = api_result_value<Result, api_result_validity::never>;
327 
328 public:
329  using base::base;
330 
331  explicit constexpr operator bool() const noexcept {
332  return false;
333  }
334 
335  template <typename T>
336  auto replaced_with(T) const {
337  api_result<T, Info, api_result_validity::never> result{};
338  static_cast<Info&>(result) = static_cast<const Info&>(*this);
339  return result;
340  }
341 
342  template <typename T>
343  auto cast_to(type_identity<T> tid) const {
344  return this->_cast_to(*this, tid);
345  }
346 
347  auto cast_to(type_identity<void>) const noexcept -> auto& {
348  return *this;
349  }
350 
351  auto cast_to(type_identity<nothing_t>) const noexcept -> auto& {
352  return *this;
353  }
354 
355  template <typename Transform>
356  auto transformed(Transform transform) const {
357  return this->_transformed(*this, transform);
358  }
359 
360  template <typename Check, typename IfFalse>
361  auto collapsed(Check check, IfFalse if_false) const {
362  return this->_collapsed(*this, check, if_false);
363  }
364 };
365 //------------------------------------------------------------------------------
366 static constexpr auto
367 extract(const api_result_value<void, api_result_validity::never>&) noexcept
368  -> nothing_t {
369  return {};
370 }
371 //------------------------------------------------------------------------------
372 template <typename Result, typename Info>
373 struct ok_traits<api_result<Result, Info, api_result_validity::never>> {
374  static constexpr auto nok_info(
375  const api_result<Result, Info, api_result_validity::never>& r) noexcept
376  -> const Info& {
377  return r;
378  }
379 };
380 //------------------------------------------------------------------------------
381 template <typename Result, typename Info, typename Fallback>
382 static constexpr auto extract_or(
383  const api_result<Result, Info, api_result_validity::never>&,
384  Fallback&& fallback) noexcept -> Result {
385  return {std::forward<Fallback>(fallback)};
386 }
387 //------------------------------------------------------------------------------
388 // api_result
389 //------------------------------------------------------------------------------
392 template <typename Result>
393 class api_result_value<Result, api_result_validity::always> {
394 public:
395  constexpr api_result_value() noexcept(noexcept(Result{})) = default;
396 
397  constexpr api_result_value(Result value) noexcept
398  : _value{std::move(value)} {}
399 
402  constexpr auto is_valid() const noexcept {
403  return true;
404  }
405 
406 protected:
407  template <typename Info, typename T>
408  auto _cast_to(
410  type_identity<T>) const {
412  static_cast<Info&>(result) = static_cast<const Info&>(src);
413  return result;
414  }
415 
416  template <typename Info, typename Transform>
417  auto _transformed(
418  const api_result<Result, Info, api_result_validity::always>& src,
419  Transform& transform) const {
420  using T = decltype(transform(std::declval<Result>()));
421  api_result<T, Info, api_result_validity::always> result{
422  transform(_value)};
423  static_cast<Info&>(result) = static_cast<const Info&>(src);
424  return result;
425  }
426 
427  template <typename Info, typename Check, typename IfFalse>
428  auto _collapsed(
429  const api_result<Result, Info, api_result_validity::always>& src,
430  Check& check,
431  IfFalse& if_false) const {
432  api_result<void, Info, api_result_validity::always> result{};
433  static_cast<Info&>(result) = static_cast<const Info&>(src);
434  if(!check(_value)) {
435  if_false(static_cast<Info&>(result));
436  }
437  return result;
438  }
439 
440 public:
441  Result _value{};
442 };
443 //------------------------------------------------------------------------------
444 template <typename Result>
445 static constexpr auto
446 extract(api_result_value<Result, api_result_validity::always>&& result) noexcept
447  -> Result {
448  return std::move(result._value);
449 }
450 
451 template <typename Result>
452 static constexpr auto
453 extract(api_result_value<Result, api_result_validity::always>& result) noexcept
454  -> Result& {
455  return result._value;
456 }
457 
458 template <typename Result>
459 static constexpr auto extract(
460  const api_result_value<Result, api_result_validity::always>& result) noexcept
461  -> const Result& {
462  return result._value;
463 }
464 
465 template <typename Result>
466 inline auto operator>>(
467  api_result_value<Result, api_result_validity::always> result,
468  Result& dest) noexcept -> Result& {
469  return dest = std::move(result._value);
470 }
471 //------------------------------------------------------------------------------
472 template <>
473 class api_result_value<void, api_result_validity::always> {
474 public:
475  constexpr auto is_valid() const noexcept {
476  return true;
477  }
478 
479 protected:
480  template <typename Info, typename T>
481  auto _cast_to(
482  const api_result<void, Info, api_result_validity::always>& src,
483  type_identity<T>) const {
484  api_result<T, Info, api_result_validity::always> result{};
485  static_cast<Info&>(result) = static_cast<const Info&>(src);
486  return result;
487  }
488 
489  template <typename Info, typename Transform>
490  auto _transformed(
491  const api_result<void, Info, api_result_validity::always>& src,
492  Transform& transform) const {
493  using T = decltype(transform());
494  api_result<T, Info, api_result_validity::always> result{transform()};
495  static_cast<Info&>(result) = static_cast<const Info&>(src);
496  return result;
497  }
498 
499  template <typename Info, typename Check, typename IfFalse>
500  auto _collapsed(
501  const api_result<void, Info, api_result_validity::always>& src,
502  Check&,
503  IfFalse&) const -> auto& {
504  return src;
505  }
506 };
507 //------------------------------------------------------------------------------
512 template <typename Result, typename Info>
513 class api_result<Result, Info, api_result_validity::always>
514  : public Info
515  , public api_result_value<Result, api_result_validity::always> {
517 
518 public:
519  using base::base;
520 
522  explicit constexpr operator bool() const noexcept {
523  return bool(*static_cast<const Info*>(this));
524  }
525 
527  template <typename T>
528  auto replaced_with(T value) const {
530  std::move(value)};
531  static_cast<Info&>(result) = static_cast<const Info&>(*this);
532  return result;
533  }
534 
536  template <typename T>
537  auto cast_to(type_identity<T> tid) const {
538  return this->_cast_to(*this, tid);
539  }
540 
541  auto cast_to(type_identity<void>) const noexcept -> auto& {
542  return *this;
543  }
544 
545  auto cast_to(type_identity<nothing_t>) const noexcept -> auto& {
546  return *this;
547  }
548 
550  template <typename Transform>
551  auto transformed(Transform transform) const {
552  return this->_transformed(*this, transform);
553  }
554 
555  template <typename Check, typename IfFalse>
556  auto collapsed(Check check, IfFalse if_false) const {
557  return this->_collapsed(*this, check, if_false);
558  }
559 };
560 //------------------------------------------------------------------------------
561 static constexpr auto
562 extract(const api_result_value<void, api_result_validity::always>&) noexcept
563  -> nothing_t {
564  return {};
565 }
566 //------------------------------------------------------------------------------
567 template <typename Result, typename Info>
568 struct ok_traits<api_result<Result, Info, api_result_validity::always>> {
569  static constexpr auto nok_info(
570  const api_result<Result, Info, api_result_validity::always>& r) noexcept
571  -> const Info& {
572  return r;
573  }
574 };
575 //------------------------------------------------------------------------------
576 template <typename Result, typename Info, typename Fallback>
577 static constexpr auto extract_or(
578  const api_result<Result, Info, api_result_validity::always>& result,
579  Fallback&& fallback) noexcept -> Result {
580  if(result) {
581  return extract(result);
582  }
583  return {std::forward<Fallback>(fallback)};
584 }
585 //------------------------------------------------------------------------------
586 // api opt result
587 //------------------------------------------------------------------------------
590 template <typename Result>
591 class api_result_value<Result, api_result_validity::maybe> {
592 public:
593  constexpr api_result_value() noexcept = default;
594 
595  constexpr api_result_value(Result value, bool valid) noexcept
596  : _value{std::move(value)}
597  , _valid{valid} {}
598 
600  constexpr auto is_valid() const noexcept {
601  return _valid;
602  }
603 
604 protected:
605  template <typename Info, typename T>
606  auto _cast_to(
608  type_identity<T>) const {
610  T(_value), src.is_valid()};
611  static_cast<Info&>(result) = static_cast<const Info&>(src);
612  return result;
613  }
614 
615  template <typename Info, typename Transform>
616  auto _transformed(
617  const api_result<Result, Info, api_result_validity::maybe>& src,
618  Transform& transform) const {
619  using T = decltype(transform(std::declval<Result>()));
620  api_result<T, Info, api_result_validity::maybe> result{
621  transform(_value), src.is_valid()};
622  static_cast<Info&>(result) = static_cast<const Info&>(src);
623  return result;
624  }
625 
626  template <typename Info, typename Check, typename IfFalse>
627  auto _collapsed(
628  const api_result<Result, Info, api_result_validity::maybe>& src,
629  Check& check,
630  IfFalse& if_false) const {
631  api_result<void, Info, api_result_validity::maybe> result{};
632  static_cast<Info&>(result) = static_cast<const Info&>(src);
633  if(src.is_valid() && !check(_value)) {
634  if_false(static_cast<Info&>(result));
635  }
636  return result;
637  }
638 
639 public:
640  Result _value{};
641  bool _valid{false};
642 };
643 //------------------------------------------------------------------------------
646 template <typename Result>
647 static constexpr auto
649  -> Result {
650  return EAGINE_CONSTEXPR_ASSERT(result._valid, std::move(result._value));
651 }
652 
655 template <typename Result>
656 static constexpr auto
658  -> Result& {
659  return EAGINE_CONSTEXPR_ASSERT(result._valid, result._value);
660 }
661 
664 template <typename Result>
665 static constexpr auto extract(
667  -> const Result& {
668  return EAGINE_CONSTEXPR_ASSERT(result._valid, result._value);
669 }
670 
676 template <typename Result, typename Info>
677 inline auto operator>>(
679  Result& dest) -> Result& {
680  if(!result._valid) {
681  throw bad_result<Info>(static_cast<Info&&>(result));
682  }
683  return dest = std::move(result._value);
684 }
685 //------------------------------------------------------------------------------
686 template <>
687 class api_result_value<void, api_result_validity::maybe> {
688 public:
689  constexpr api_result_value() noexcept = default;
690 
691  constexpr api_result_value(bool valid) noexcept
692  : _valid{valid} {}
693 
694  constexpr auto is_valid() const noexcept {
695  return _valid;
696  }
697 
698 protected:
699  template <typename Info, typename T>
700  auto _cast_to(
701  const api_result<void, Info, api_result_validity::maybe>& src,
702  type_identity<T>) const {
703  api_result<T, Info, api_result_validity::maybe> result{
704  T{}, src.is_valid()};
705  static_cast<Info&>(result) = static_cast<const Info&>(src);
706  return result;
707  }
708 
709  template <typename Info, typename Transform>
710  auto _transformed(
711  const api_result<void, Info, api_result_validity::maybe>& src,
712  Transform& transform) const {
713  using T = decltype(transform());
714  api_result<T, Info, api_result_validity::maybe> result{
715  transform(), src.is_valid()};
716  static_cast<Info&>(result) = static_cast<const Info&>(src);
717  return result;
718  }
719 
720  template <typename Info, typename Check, typename IfFalse>
721  auto _collapsed(
722  const api_result<void, Info, api_result_validity::maybe>& src,
723  Check&,
724  IfFalse&) const -> auto& {
725  return src;
726  }
727 
728 public:
729  bool _valid{false};
730 };
731 //------------------------------------------------------------------------------
732 template <typename Result, typename Info>
733 class api_result<Result, Info, api_result_validity::maybe>
734  : public Info
735  , public api_result_value<Result, api_result_validity::maybe> {
736  using base = api_result_value<Result, api_result_validity::maybe>;
737 
738 public:
739  using base::base;
740 
741  explicit constexpr operator bool() const noexcept {
742  return this->is_valid() && bool(*static_cast<const Info*>(this));
743  }
744 
745  template <typename T>
746  auto replaced_with(T value) const {
747  api_result<T, Info, api_result_validity::maybe> result{
748  std::move(value), this->is_valid()};
749  static_cast<Info&>(result) = static_cast<const Info&>(*this);
750  return result;
751  }
752 
753  template <typename T>
754  auto cast_to(type_identity<T> tid) const {
755  return this->_cast_to(*this, tid);
756  }
757 
758  auto cast_to(type_identity<void>) const noexcept -> auto& {
759  return *this;
760  }
761 
762  auto cast_to(type_identity<nothing_t>) const noexcept -> auto& {
763  return *this;
764  }
765 
766  template <typename Transform>
767  auto transformed(Transform transform) const {
768  return this->_transformed(*this, transform);
769  }
770 
771  template <typename Check, typename IfFalse>
772  auto collapsed(Check check, IfFalse if_false) const {
773  return this->_collapsed(*this, check, if_false);
774  }
775 };
776 //------------------------------------------------------------------------------
777 static constexpr auto
778 extract(const api_result_value<void, api_result_validity::maybe>&) noexcept
779  -> nothing_t {
780  return {};
781 }
782 //------------------------------------------------------------------------------
783 template <typename Result, typename Info>
784 struct ok_traits<api_result<Result, Info, api_result_validity::maybe>> {
785  static constexpr auto nok_info(
786  const api_result<Result, Info, api_result_validity::maybe>& r) noexcept
787  -> const Info& {
788  return r;
789  }
790 };
791 //------------------------------------------------------------------------------
792 template <typename Result, typename Info, typename Fallback>
793 static constexpr auto extract_or(
794  const api_result<Result, Info, api_result_validity::maybe>& result,
795  Fallback&& fallback) noexcept -> Result {
796  if(result) {
797  return extract(result);
798  }
799  return {std::forward<Fallback>(fallback)};
800 }
801 //------------------------------------------------------------------------------
802 // api_combined_result
803 //------------------------------------------------------------------------------
804 template <typename Result, typename Info>
805 class api_combined_result
806  : public api_result<Result, Info, api_result_validity::maybe> {
807  using base = api_result<Result, Info, api_result_validity::maybe>;
808 
809 public:
810  api_combined_result(api_result<Result, Info, api_result_validity::never> src)
811  : base{} {
812  static_cast<Info&>(*this) = static_cast<Info&&>(src);
813  }
814 
815  api_combined_result(api_result<Result, Info> src)
816  : base{
817  extract(
818  static_cast<api_result_value<Result, api_result_validity::always>&&>(
819  src)),
820  src.is_valid()} {
821  static_cast<Info&>(*this) = static_cast<Info&&>(src);
822  }
823 
824  api_combined_result(api_result<Result, Info, api_result_validity::maybe> src)
825  : base{std::move(src)} {}
826 };
827 //------------------------------------------------------------------------------
828 template <typename Info>
829 class api_combined_result<void, Info>
830  : public api_result<void, Info, api_result_validity::maybe> {
831  using base = api_result<void, Info, api_result_validity::maybe>;
832 
833 public:
834  template <typename R>
835  api_combined_result(
836  const api_result<R, Info, api_result_validity::never>& src)
837  : base{} {
838  static_cast<Info&>(*this) = static_cast<const Info&>(src);
839  }
840 
841  template <typename R>
842  api_combined_result(const api_result<R, Info>& src)
843  : base{src.is_valid()} {
844  static_cast<Info&>(*this) = static_cast<const Info&>(src);
845  }
846 
847  template <typename R>
848  api_combined_result(
849  const api_result<R, Info, api_result_validity::maybe>& src)
850  : base{src.is_valid()} {
851  static_cast<Info&>(*this) = static_cast<const Info&>(src);
852  }
853 };
854 //------------------------------------------------------------------------------
855 template <typename Result, typename Info>
856 struct ok_traits<api_combined_result<Result, Info>> {
857  static constexpr auto nok_info(
858  const api_combined_result<Result, Info>& r) noexcept -> const Info& {
859  return r;
860  }
861 };
862 //------------------------------------------------------------------------------
863 template <typename ApiTraits, typename Tag, typename Signature>
864 using c_api_function_ptr =
865  typename ApiTraits::template function_pointer<Tag, Signature>::type;
866 //------------------------------------------------------------------------------
867 template <typename ApiTraits, typename Tag, typename Signature>
868 class unimplemented_c_api_function;
869 //------------------------------------------------------------------------------
878 template <
879  typename ApiTraits,
880  typename Tag,
881  typename Signature,
882  c_api_function_ptr<ApiTraits, Tag, Signature> function>
884 //------------------------------------------------------------------------------
893 template <typename ApiTraits, typename Tag, typename Signature>
895 //------------------------------------------------------------------------------
896 template <typename Api, typename ApiTraits, typename Tag>
897 class derived_c_api_function;
898 //------------------------------------------------------------------------------
902  template <typename Tag, typename Signature>
903  using function_pointer = std::add_pointer<Signature>;
904 
905  template <typename Api, typename Type>
906  auto load_constant(Api&, string_view, type_identity<Type>)
907  -> std::tuple<Type, bool> {
908  return {{}, false};
909  }
910 
911  template <typename Api, typename Tag, typename Signature>
912  auto link_function(Api&, Tag, string_view, type_identity<Signature>)
913  -> std::add_pointer_t<Signature> {
914  return nullptr;
915  }
916 
917  template <typename Tag, typename RV>
918  static constexpr auto fallback(Tag, type_identity<RV>) -> RV {
919  return {};
920  }
921 
922  template <typename Tag>
923  static constexpr void fallback(Tag, type_identity<void>) {}
924 
925  template <typename RV, typename Tag, typename... Params, typename... Args>
926  static constexpr auto
927  call_static(Tag tag, RV (*function)(Params...), Args&&... args) -> RV {
928  if(function) {
929  return function(
930  std::forward<Args>(args)...); // NOLINT(hicpp-no-array-decay)
931  }
932  return fallback(tag, type_identity<RV>());
933  }
934 
935  template <typename RV, typename Tag, typename... Params, typename... Args>
936  static constexpr auto
937  call_dynamic(Tag tag, RV (*function)(Params...), Args&&... args) -> RV {
938  if(function) {
939  return function(
940  std::forward<Args>(args)...); // NOLINT(hicpp-no-array-decay)
941  }
942  return fallback(tag, type_identity<RV>());
943  }
944 
945  template <typename RV>
946  using no_result = never_valid<RV>;
947 
948  template <typename RV>
950 
951  template <typename RV>
952  using result = always_valid<RV>;
953 };
954 //------------------------------------------------------------------------------
955 template <bool IsAvailable>
956 class c_api_function_base : public bool_constant<IsAvailable> {
957 public:
958  constexpr c_api_function_base(string_view name) noexcept
959  : _name{name} {}
960 
961  constexpr explicit operator bool() const noexcept {
962  return IsAvailable;
963  }
964 
965  constexpr auto name() const noexcept -> string_view {
966  return _name;
967  }
968 
969 private:
970  const string_view _name{};
971 };
972 //------------------------------------------------------------------------------
973 template <typename ApiTraits, typename Tag, typename RV, typename... Params>
974 class unimplemented_c_api_function<ApiTraits, Tag, RV(Params...)>
975  : public c_api_function_base<false> {
976  using base = c_api_function_base<false>;
977 
978 public:
979  using signature = RV(Params...);
980 
981  template <typename Api>
982  constexpr unimplemented_c_api_function(
983  string_view name,
984  const ApiTraits&,
985  Api&)
986  : base(name) {}
987 
988  template <typename... Args>
989  constexpr auto operator()(Args&&...) const noexcept
990  -> std::enable_if_t<sizeof...(Params) == sizeof...(Args), RV> {
991  return ApiTraits::fallback(Tag(), type_identity<RV>());
992  }
993 };
994 //------------------------------------------------------------------------------
999 template <
1000  typename ApiTraits,
1001  typename Tag,
1002  typename RV,
1003  typename... Params,
1004  c_api_function_ptr<ApiTraits, Tag, RV(Params...)> function>
1005 class static_c_api_function<ApiTraits, Tag, RV(Params...), function>
1006  : public c_api_function_base<true> {
1007  using base = c_api_function_base<true>;
1008 
1009 public:
1011  using signature = RV(Params...);
1012 
1013  template <typename Api>
1014  constexpr static_c_api_function(string_view name, const ApiTraits&, Api&)
1015  : base(name) {}
1016 
1018  template <typename... Args>
1019  constexpr auto operator()(Args&&... args) const noexcept
1020  -> std::enable_if_t<sizeof...(Params) == sizeof...(Args), RV> {
1021  return ApiTraits::call_static(
1022  Tag(), function, std::forward<Args>(args)...);
1023  }
1024 };
1025 //------------------------------------------------------------------------------
1030 template <typename ApiTraits, typename Tag, typename RV, typename... Params>
1031 class dynamic_c_api_function<ApiTraits, Tag, RV(Params...)>
1032  : public c_api_function_base<true> {
1033 
1034  using base = c_api_function_base<true>;
1035  using function_pointer = c_api_function_ptr<ApiTraits, Tag, RV(Params...)>;
1036 
1037 public:
1039  using signature = RV(Params...);
1040 
1041  template <typename Api>
1042  constexpr dynamic_c_api_function(
1043  string_view name,
1044  ApiTraits& traits,
1045  Api& api)
1046  : base(name)
1047  , _function{traits.link_function(
1048  api,
1049  Tag(),
1050  name,
1051  type_identity<RV(Params...)>())} {}
1052 
1054  constexpr explicit operator bool() const noexcept {
1055  return bool(_function);
1056  }
1057 
1059  template <typename... Args>
1060  constexpr auto operator()(Args&&... args) const noexcept
1061  -> std::enable_if_t<sizeof...(Params) == sizeof...(Args), RV> {
1062  return ApiTraits::call_dynamic(
1063  Tag(), _function, std::forward<Args>(args)...);
1064  }
1065 
1066 private:
1067  function_pointer _function{nullptr};
1068 };
1069 //------------------------------------------------------------------------------
1083 template <
1084  typename ApiTraits,
1085  typename Tag,
1086  typename Signature,
1087  c_api_function_ptr<ApiTraits, Tag, Signature> function,
1088  bool IsAvailable,
1089  bool IsStatic>
1090 using opt_c_api_function = std::conditional_t<
1091  IsAvailable,
1092  std::conditional_t<
1093  IsStatic,
1094  static_c_api_function<ApiTraits, Tag, Signature, function>,
1095  dynamic_c_api_function<ApiTraits, Tag, Signature>>,
1096  unimplemented_c_api_function<ApiTraits, Tag, Signature>>;
1097 //------------------------------------------------------------------------------
1098 template <typename Api, typename ApiTraits, typename Tag>
1099 class derived_c_api_function {
1100 protected:
1101  template <typename RV, typename... Params, typename... Args>
1102  static constexpr auto _call(
1103  const unimplemented_c_api_function<ApiTraits, Tag, RV(Params...)>&,
1104  Args&&...) noexcept -> typename ApiTraits::template no_result<RV> {
1105  return {};
1106  }
1107 
1108  template <
1109  typename RV,
1110  typename... Params,
1111  typename... Args,
1112  RV (*Func)(Params...)>
1113  static constexpr auto _call(
1114  static_c_api_function<ApiTraits, Tag, RV(Params...), Func>& function,
1115  Args&&... args) noexcept -> std::
1116  enable_if_t<!std::is_void_v<RV>, typename ApiTraits::template result<RV>> {
1117  return {std::move(function(std::forward<Args>(args)...))};
1118  }
1119 
1120  template <typename... Params, typename... Args, void (*Func)(Params...)>
1121  static constexpr auto _call(
1122  static_c_api_function<ApiTraits, Tag, void(Params...), Func>& function,
1123  Args&&... args) noexcept -> typename ApiTraits::template result<void> {
1124  function(std::forward<Args>(args)...);
1125  return {};
1126  }
1127 
1128  template <typename RV, typename... Params, typename... Args>
1129  static constexpr auto _call(
1130  dynamic_c_api_function<ApiTraits, Tag, RV(Params...)>& function,
1131  Args&&... args) noexcept -> typename ApiTraits::template opt_result<RV> {
1132  return {
1133  std::move(function(std::forward<Args>(args)...)), bool(function)};
1134  }
1135 
1136  template <typename... Params, typename... Args>
1137  static constexpr auto _call(
1138  dynamic_c_api_function<ApiTraits, Tag, void(Params...)>& function,
1139  Args&&... args) noexcept ->
1140  typename ApiTraits::template opt_result<void> {
1141  function(std::forward<Args>(args)...);
1142  return {bool(function)};
1143  }
1144 
1145  template <typename RV, typename... Params>
1146  static constexpr auto _fake(
1147  const unimplemented_c_api_function<ApiTraits, Tag, RV(Params...)>&,
1148  RV fallback) noexcept -> typename ApiTraits::template result<RV> {
1149  return {std::move(fallback)};
1150  }
1151 
1152  template <typename RV, typename... Params>
1153  static constexpr auto _fake(
1154  const unimplemented_c_api_function<ApiTraits, Tag, RV(Params...)>&) noexcept
1155  -> typename ApiTraits::template result<RV> {
1156  return {RV{}};
1157  }
1158 
1159  template <typename RV, typename... Params, RV (*Func)(Params...), typename F>
1160  static constexpr auto _fake(
1161  const static_c_api_function<ApiTraits, Tag, RV(Params...), Func>&,
1162  F&& fallback) noexcept -> typename ApiTraits::template result<RV> {
1163  return {std::forward<F>(fallback)};
1164  }
1165 
1166  template <typename RV, typename... Params, RV (*Func)(Params...)>
1167  static constexpr auto _fake(
1168  const static_c_api_function<ApiTraits, Tag, RV(Params...), Func>&) noexcept
1169  -> typename ApiTraits::template result<RV> {
1170  return {RV{}};
1171  }
1172 
1173  template <typename RV, typename... Params, typename F>
1174  static constexpr auto _fake(
1175  const dynamic_c_api_function<ApiTraits, Tag, RV(Params...)>&,
1176  F&& fallback) noexcept -> typename ApiTraits::template result<RV> {
1177  return {std::forward<F>(fallback)};
1178  }
1179 
1180  template <typename RV, typename... Params>
1181  static constexpr auto
1182  _fake(const dynamic_c_api_function<ApiTraits, Tag, RV(Params...)>&) noexcept
1183  -> typename ApiTraits::template result<RV> {
1184  return {RV{}};
1185  }
1186 
1187 public:
1188  constexpr derived_c_api_function(
1189  string_view name,
1190  ApiTraits&,
1191  Api& parent) noexcept
1192  : _name{name}
1193  , _parent{parent} {}
1194 
1195  constexpr auto name() const noexcept -> string_view {
1196  return _name;
1197  }
1198 
1199 protected:
1200  constexpr auto api() const noexcept -> Api& {
1201  return _parent;
1202  }
1203 
1204 private:
1205  const string_view _name{};
1206  Api& _parent;
1207 };
1208 //------------------------------------------------------------------------------
1209 template <
1210  typename Api,
1211  typename ApiTraits,
1212  typename Tag,
1213  typename WrapperType,
1214  WrapperType Api::*Function>
1215 class wrapped_c_api_function
1216  : public derived_c_api_function<Api, ApiTraits, Tag> {
1217  using base = derived_c_api_function<Api, ApiTraits, Tag>;
1218 
1219 protected:
1220  template <typename... Args>
1221  constexpr auto _call(Args&&... args) const noexcept {
1222  return base::_call(this->api().*Function, std::forward<Args>(args)...);
1223  }
1224 
1225  template <typename F>
1226  constexpr auto _fake(F&& fallback) const noexcept {
1227  return base::_fake(this->api().*Function, std::forward<F>(fallback));
1228  }
1229 
1230  constexpr auto _fake() const noexcept {
1231  return base::_fake(this->api().*Function);
1232  }
1233 
1234  constexpr auto _fake_empty_c_str() const noexcept ->
1235  typename ApiTraits::template result<const char*> {
1236  return {static_cast<const char*>("")};
1237  }
1238 
1239  template <typename Arg>
1240  static constexpr auto _conv(Arg arg) noexcept
1241  -> std::enable_if_t<std::is_scalar_v<Arg>, Arg> {
1242  return arg;
1243  }
1244 
1245  template <typename S, typename T, identifier_t L, identifier_t I>
1246  static constexpr auto _conv(enum_class<S, T, L, I> value) noexcept {
1247  return T(value);
1248  }
1249 
1250  template <typename EC>
1251  static constexpr auto _conv(enum_bitfield<EC> bits) noexcept {
1252  return _conv(bits._value);
1253  }
1254 
1255  template <typename Tg, typename T, T inv>
1256  static constexpr auto _conv(basic_handle<Tg, T, inv> hndl) noexcept {
1257  return T(hndl);
1258  }
1259 
1260  static constexpr auto _conv(string_view str) noexcept {
1261  return c_str(str);
1262  }
1263 
1264  static constexpr auto _conv(memory::block blk) noexcept {
1265  return blk.data();
1266  }
1267 
1268  static constexpr auto _conv(memory::const_block blk) noexcept {
1269  return blk.data();
1270  }
1271 
1272 public:
1273  using base::base;
1274 
1275  explicit constexpr operator bool() const noexcept {
1276  return bool((this->api()).*Function);
1277  }
1278 };
1279 //------------------------------------------------------------------------------
1280 
1281 } // namespace eagine
1282 
1283 #endif // EAGINE_C_API_WRAP_HPP
Specialization of api_result for always-valid result values.
Definition: c_api_wrap.hpp:513
auto replaced_with(T value) const
Returns a transformed api_result with a new stored value.
Definition: c_api_wrap.hpp:528
Class wrapping the result of a C-API function call.
Definition: c_api_wrap.hpp:210
Wrapper for statically-linked C-API functions.
Definition: c_api_wrap.hpp:883
typename get_opt_c_api_constant< ClassList, Constant, Tag, IsIndexed >::type opt_c_api_constant
Template alias used for switching between static and dynamic constants.
Definition: c_api_wrap.hpp:175
Exception wrapping information about failed C-API function call result.
Definition: c_api_wrap.hpp:180
Class holding optional value of a (typically C-API) symbolic constant.
Definition: enum_class.hpp:99
basic_string_span< const char > string_view
Alias for const string views.
Definition: string_span.hpp:116
static constexpr auto c_str(memory::basic_span< C, P, S > s) -> std::enable_if_t< std::is_convertible_v< memory::basic_span< C, P, S >, basic_string_span< C, P, S >>, basic_c_str< C, P, S >>
Functions that construct a basic_c_str from a basic_string_span.
Definition: string_span.hpp:226
auto transformed(Transform transform) const
Returns an api_result with the value transformed by the specified function.
Definition: c_api_wrap.hpp:551
std::conditional_t< IsAvailable, std::conditional_t< IsStatic, static_c_api_function< ApiTraits, Tag, Signature, function >, dynamic_c_api_function< ApiTraits, Tag, Signature > >, unimplemented_c_api_function< ApiTraits, Tag, Signature > > opt_c_api_function
Template alias used for switching between static and dynamic function.
Definition: c_api_wrap.hpp:1096
Common code is placed in this namespace.
Definition: eagine.hpp:21
static constexpr auto extract(api_result_value< Result, api_result_validity::never > &) noexcept -> Result &
Overload of extract for api_result_value.
Definition: c_api_wrap.hpp:270
basic_block< true > const_block
Alias for const byte memory span.
Definition: block.hpp:32
@ info
Informational log entries.
Primary template for conditionally valid values.
Definition: decl.hpp:49
constexpr auto operator+(I) const noexcept -> std::enable_if_t<(IsIndexed &&std::is_integral_v< I >), no_enum_value< T, Tag >>
Adds the specified value to the constant (it it IsIndexed).
Definition: c_api_wrap.hpp:63
@ always
Result is always valid.
RV(Params...) signature
Alias for the wrapped function type.
Definition: c_api_wrap.hpp:1011
constexpr auto operator+(I index) const noexcept -> std::enable_if_t<(IsIndexed &&std::is_integral_v< I >), enum_value< T, ClassList, Tag >>
Adds the specified value to the constant (it it IsIndexed).
Definition: c_api_wrap.hpp:88
Class representing undefined value of a (typically C-API) symbolic constant.
Definition: enum_class.hpp:177
basic_block< false > block
Alias for non-const byte memory span.
Definition: block.hpp:27
static constexpr auto nok_info(const Outcome &) noexcept -> nothing_t
Returns additional info type for values that are not-OK.
Definition: extract.hpp:105
@ maybe
Result is conditionally valid.
Class wrapping a constant with missing or unknown value.
Definition: c_api_wrap.hpp:53
std::integral_constant< bool, B > bool_constant
Alias for boolean constant type.
Definition: int_constant.hpp:20
RV(Params...) signature
Alias for the wrapped function type.
Definition: c_api_wrap.hpp:1039
Specialization for always-valid result value.
Definition: c_api_wrap.hpp:393
api_result_validity
Enumeration of C-API function call result validity.
Definition: c_api_wrap.hpp:192
@ never
Result is never valid.
constexpr auto operator+(I index) const noexcept -> std::enable_if_t<(IsIndexed &&std::is_integral_v< I >), opt_enum_value< T, ClassList, Tag >>
Adds the specified value to the constant (it it IsIndexed).
Definition: c_api_wrap.hpp:123
auto cast_to(type_identity< T > tid) const
Returns an api_result with the stored value cast to different type.
Definition: c_api_wrap.hpp:537
Class wrapping a constant with value loaded at run-time.
Definition: c_api_wrap.hpp:106
constexpr auto operator()(Args &&... args) const noexcept -> std::enable_if_t< sizeof...(Params)==sizeof...(Args), RV >
Calls the wrapped function.
Definition: c_api_wrap.hpp:1060
api_result< Result, Info, api_result_validity::maybe > api_opt_result
Alias for conditionally-valid result of a C-API function call.
Definition: c_api_wrap.hpp:218
api_result< Result, Info, api_result_validity::never > api_no_result
Alias for always-invalid result of a C-API function call.
Definition: c_api_wrap.hpp:226
Template type used mostly for function type-tag dispatching.
Definition: type_identity.hpp:19
Specialization for conditionally-valid result value.
Definition: c_api_wrap.hpp:591
constexpr auto is_valid() const noexcept
Indicates if the result value is valid.
Definition: c_api_wrap.hpp:402
constexpr auto name() const noexcept
Returns the name of the constant as a string.
Definition: c_api_wrap.hpp:42
Common base class for wrapping C-API constant values.
Definition: c_api_wrap.hpp:36
constexpr auto operator()(Args &&... args) const noexcept -> std::enable_if_t< sizeof...(Params)==sizeof...(Args), RV >
Calls the wrapped function.
Definition: c_api_wrap.hpp:1019
Class wrapping a constant with value known at compile-time.
Definition: c_api_wrap.hpp:77
Policy class customizing C-API constant value loading and function linking.
Definition: c_api_wrap.hpp:901
constexpr auto is_valid() const noexcept
Indicates if the result value is valid.
Definition: c_api_wrap.hpp:600
Wrapper for dynamically-linked C-API functions.
Definition: c_api_wrap.hpp:894
Class holding the value of a (typically C-API) symbolic constant.
Definition: enum_class.hpp:35

Copyright © 2015-2021 Matúš Chochlík.
<chochlik -at -gmail.com>
Documentation generated on Tue Apr 13 2021 by Doxygen (version 1.8.17).