1 // © 2018 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 
4 #ifndef __CAPI_HELPER_H__
5 #define __CAPI_HELPER_H__
6 
7 #include "unicode/utypes.h"
8 
9 U_NAMESPACE_BEGIN
10 
11 /**
12  * An internal helper class to help convert between C and C++ APIs.
13  */
14 template<typename CType, typename CPPType, int32_t kMagic>
15 class IcuCApiHelper {
16   public:
17     /**
18      * Convert from the C type to the C++ type (const version).
19      */
20     static const CPPType* validate(const CType* input, UErrorCode& status);
21 
22     /**
23      * Convert from the C type to the C++ type (non-const version).
24      */
25     static CPPType* validate(CType* input, UErrorCode& status);
26 
27     /**
28      * Convert from the C++ type to the C type (const version).
29      */
30     const CType* exportConstForC() const;
31 
32     /**
33      * Convert from the C++ type to the C type (non-const version).
34      */
35     CType* exportForC();
36 
37     /**
38      * Invalidates the object.
39      */
40     ~IcuCApiHelper();
41 
42   private:
43     /**
44      * While the object is valid, fMagic equals kMagic.
45      */
46     int32_t fMagic = kMagic;
47 };
48 
49 
50 template<typename CType, typename CPPType, int32_t kMagic>
51 const CPPType*
validate(const CType * input,UErrorCode & status)52 IcuCApiHelper<CType, CPPType, kMagic>::validate(const CType* input, UErrorCode& status) {
53     if (U_FAILURE(status)) {
54         return nullptr;
55     }
56     if (input == nullptr) {
57         status = U_ILLEGAL_ARGUMENT_ERROR;
58         return nullptr;
59     }
60     auto* impl = reinterpret_cast<const CPPType*>(input);
61     if (static_cast<const IcuCApiHelper<CType, CPPType, kMagic>*>(impl)->fMagic != kMagic) {
62         status = U_INVALID_FORMAT_ERROR;
63         return nullptr;
64     }
65     return impl;
66 }
67 
68 template<typename CType, typename CPPType, int32_t kMagic>
69 CPPType*
validate(CType * input,UErrorCode & status)70 IcuCApiHelper<CType, CPPType, kMagic>::validate(CType* input, UErrorCode& status) {
71     auto* constInput = static_cast<const CType*>(input);
72     auto* validated = validate(constInput, status);
73     return const_cast<CPPType*>(validated);
74 }
75 
76 template<typename CType, typename CPPType, int32_t kMagic>
77 const CType*
exportConstForC()78 IcuCApiHelper<CType, CPPType, kMagic>::exportConstForC() const {
79     return reinterpret_cast<const CType*>(static_cast<const CPPType*>(this));
80 }
81 
82 template<typename CType, typename CPPType, int32_t kMagic>
83 CType*
exportForC()84 IcuCApiHelper<CType, CPPType, kMagic>::exportForC() {
85     return reinterpret_cast<CType*>(static_cast<CPPType*>(this));
86 }
87 
88 template<typename CType, typename CPPType, int32_t kMagic>
~IcuCApiHelper()89 IcuCApiHelper<CType, CPPType, kMagic>::~IcuCApiHelper() {
90     // head off application errors by preventing use of of deleted objects.
91     fMagic = 0;
92 }
93 
94 
95 U_NAMESPACE_END
96 
97 #endif // __CAPI_HELPER_H__
98