]> granicus.if.org Git - icu/commitdiff
ICU-20293 Adds common base class to implement C API validation methods.
authorShane Carr <shane@unicode.org>
Tue, 4 Dec 2018 07:32:13 +0000 (23:32 -0800)
committerShane F. Carr <shane@unicode.org>
Tue, 4 Dec 2018 23:57:06 +0000 (15:57 -0800)
icu4c/source/common/capi_helper.h [new file with mode: 0644]
icu4c/source/common/common.vcxproj
icu4c/source/common/common.vcxproj.filters
icu4c/source/common/common_uwp.vcxproj
icu4c/source/i18n/number_capi.cpp
icu4c/source/i18n/number_utypes.h
icu4c/source/i18n/uspoof_impl.cpp
icu4c/source/i18n/uspoof_impl.h

diff --git a/icu4c/source/common/capi_helper.h b/icu4c/source/common/capi_helper.h
new file mode 100644 (file)
index 0000000..8904882
--- /dev/null
@@ -0,0 +1,86 @@
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#ifndef __CAPI_HELPER_H__
+#define __CAPI_HELPER_H__
+
+#include "unicode/utypes.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * An internal helper class to help convert between C and C++ APIs.
+ */
+template<typename CType, typename CPPType, int32_t kMagic>
+class IcuCApiHelper {
+  public:
+    /**
+     * Convert from the C type to the C++ type (const version).
+     */
+    static const CPPType* validate(const CType* input, UErrorCode& status);
+
+    /**
+     * Convert from the C type to the C++ type (non-const version).
+     */
+    static CPPType* validate(CType* input, UErrorCode& status);
+
+    /**
+     * Convert from the C++ type to the C type.
+     */
+    CType* exportForC();
+
+    /**
+     * Invalidates the object.
+     */
+    ~IcuCApiHelper();
+
+  private:
+    /**
+     * While the object is valid, fMagic equals kMagic.
+     */
+    int32_t fMagic = kMagic;
+};
+
+
+template<typename CType, typename CPPType, int32_t kMagic>
+const CPPType*
+IcuCApiHelper<CType, CPPType, kMagic>::validate(const CType* input, UErrorCode& status) {
+    if (U_FAILURE(status)) {
+        return nullptr;
+    }
+    if (input == nullptr) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return nullptr;
+    }
+    auto* impl = reinterpret_cast<const CPPType*>(input);
+    if (impl->fMagic != kMagic) {
+        status = U_INVALID_FORMAT_ERROR;
+        return nullptr;
+    }
+    return impl;
+}
+
+template<typename CType, typename CPPType, int32_t kMagic>
+CPPType*
+IcuCApiHelper<CType, CPPType, kMagic>::validate(CType* input, UErrorCode& status) {
+    auto* constInput = static_cast<const CType*>(input);
+    auto* validated = validate(constInput, status);
+    return const_cast<CPPType*>(validated);
+}
+
+template<typename CType, typename CPPType, int32_t kMagic>
+CType*
+IcuCApiHelper<CType, CPPType, kMagic>::exportForC() {
+    return reinterpret_cast<CType*>(static_cast<CPPType*>(this));
+}
+
+template<typename CType, typename CPPType, int32_t kMagic>
+IcuCApiHelper<CType, CPPType, kMagic>::~IcuCApiHelper() {
+    // head off application errors by preventing use of of deleted objects.
+    fMagic = 0;
+}
+
+
+U_NAMESPACE_END
+
+#endif // __CAPI_HELPER_H__
index 399c175ac720562220853cc529f3d543f92cb55c..eb9b456ce55b89e3b1b6b44c6db28bf8f8383d84 100644 (file)
     <ClInclude Include="ustr_cnv.h" />
     <ClInclude Include="ustr_imp.h" />
     <ClInclude Include="static_unicode_sets.h" />
+    <ClInclude Include="capi_helper.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="common.rc" />
index 99ed94fbd7056eeee5c4401a93de3865cbcaa1a9..85d0d9b5eef7951bf2cc7072f12e44abc68c3a2d 100644 (file)
     <ClInclude Include="static_unicode_sets.h">
       <Filter>formatting</Filter>
     </ClInclude>
+    <CustomBuild Include="capi_helper.h">
+      <Filter>data &amp; memory</Filter>
+    </CustomBuild>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="common.rc">
index 91c538d5177535a84e5e7456c50f21a605cd77c8..7508a9494032692f860caaacb49cb35044f3544c 100644 (file)
     <ClInclude Include="ustr_cnv.h" />
     <ClInclude Include="ustr_imp.h" />
     <ClInclude Include="static_unicode_sets.h" />
+    <ClInclude Include="capi_helper.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="common.rc" />
index ca7918bc82e8796a0d308f21650abcf616dc6804..d96da6816e1fd9b62bdf443f8b8cce4c1a10a77e 100644 (file)
@@ -20,69 +20,6 @@ using namespace icu::number;
 using namespace icu::number::impl;
 
 
-//////////////////////////////////
-/// C API CONVERSION FUNCTIONS ///
-//////////////////////////////////
-
-UNumberFormatterData* UNumberFormatterData::validate(UNumberFormatter* input, UErrorCode& status) {
-    auto* constInput = static_cast<const UNumberFormatter*>(input);
-    auto* validated = validate(constInput, status);
-    return const_cast<UNumberFormatterData*>(validated);
-}
-
-const UNumberFormatterData*
-UNumberFormatterData::validate(const UNumberFormatter* input, UErrorCode& status) {
-    if (U_FAILURE(status)) {
-        return nullptr;
-    }
-    if (input == nullptr) {
-        status = U_ILLEGAL_ARGUMENT_ERROR;
-        return nullptr;
-    }
-    auto* impl = reinterpret_cast<const UNumberFormatterData*>(input);
-    if (impl->fMagic != UNumberFormatterData::kMagic) {
-        status = U_INVALID_FORMAT_ERROR;
-        return nullptr;
-    }
-    return impl;
-}
-
-UNumberFormatter* UNumberFormatterData::exportForC() {
-    return reinterpret_cast<UNumberFormatter*>(this);
-}
-
-UFormattedNumberData* UFormattedNumberData::validate(UFormattedNumber* input, UErrorCode& status) {
-    auto* constInput = static_cast<const UFormattedNumber*>(input);
-    auto* validated = validate(constInput, status);
-    return const_cast<UFormattedNumberData*>(validated);
-}
-
-const UFormattedNumberData*
-UFormattedNumberData::validate(const UFormattedNumber* input, UErrorCode& status) {
-    if (U_FAILURE(status)) {
-        return nullptr;
-    }
-    if (input == nullptr) {
-        status = U_ILLEGAL_ARGUMENT_ERROR;
-        return nullptr;
-    }
-    auto* impl = reinterpret_cast<const UFormattedNumberData*>(input);
-    if (impl->fMagic != UFormattedNumberData::kMagic) {
-        status = U_INVALID_FORMAT_ERROR;
-        return nullptr;
-    }
-    return impl;
-}
-
-UFormattedNumber* UFormattedNumberData::exportForC() {
-    return reinterpret_cast<UFormattedNumber*>(this);
-}
-
-/////////////////////////////////////
-/// END CAPI CONVERSION FUNCTIONS ///
-/////////////////////////////////////
-
-
 U_CAPI UNumberFormatter* U_EXPORT2
 unumf_openForSkeletonAndLocale(const UChar* skeleton, int32_t skeletonLen, const char* locale,
                                UErrorCode* ec) {
index 48bfce1969754a42054b54967306afd09ce47065..303f82e6a955218e5582de94cb38b83e5be353b4 100644 (file)
 #include "number_types.h"
 #include "number_decimalquantity.h"
 #include "number_stringbuilder.h"
+#include "capi_helper.h"
 
 U_NAMESPACE_BEGIN namespace number {
 namespace impl {
 
 
 /**
- * Implementation class for UNumberFormatter with a magic number for safety.
- *
- * Wraps a LocalizedNumberFormatter by value.
+ * Implementation class for UNumberFormatter. Wraps a LocalizedNumberFormatter.
  */
-struct UNumberFormatterData : public UMemory {
-    // The magic number to identify incoming objects.
-    // Reads in ASCII as "NFR" (NumberFormatteR with room at the end)
-    static constexpr int32_t kMagic = 0x4E465200;
-
-    // Data members:
-    int32_t fMagic = kMagic;
+struct UNumberFormatterData : public UMemory,
+        // Magic number as ASCII == "NFR" (NumberFormatteR)
+        public IcuCApiHelper<UNumberFormatter, UNumberFormatterData, 0x4E465200> {
     LocalizedNumberFormatter fFormatter;
-
-    /** Convert from UNumberFormatter -> UNumberFormatterData. */
-    static UNumberFormatterData* validate(UNumberFormatter* input, UErrorCode& status);
-
-    /** Convert from UNumberFormatter -> UNumberFormatterData (const version). */
-    static const UNumberFormatterData* validate(const UNumberFormatter* input, UErrorCode& status);
-
-    /** Convert from UNumberFormatterData -> UNumberFormatter. */
-    UNumberFormatter* exportForC();
 };
 
 
 /**
- * Implementation class for UFormattedNumber with magic number for safety.
+ * Implementation class for UFormattedNumber.
  *
  * This struct is also held internally by the C++ version FormattedNumber since the member types are not
  * declared in the public header file.
@@ -50,24 +36,11 @@ struct UNumberFormatterData : public UMemory {
  * The DecimalQuantity is not currently being used by FormattedNumber, but at some point it could be used
  * to add a toDecNumber() or similar method.
  */
-struct UFormattedNumberData : public UMemory {
-    // The magic number to identify incoming objects.
-    // Reads in ASCII as "FDN" (FormatteDNumber with room at the end)
-    static constexpr int32_t kMagic = 0x46444E00;
-
-    // Data members:
-    int32_t fMagic = kMagic;
+struct UFormattedNumberData : public UMemory,
+        // Magic number as ASCII == "FDN" (FormatteDNumber)
+        public IcuCApiHelper<UFormattedNumber, UFormattedNumberData, 0x46444E00> {
     DecimalQuantity quantity;
     NumberStringBuilder string;
-
-    /** Convert from UFormattedNumber -> UFormattedNumberData. */
-    static UFormattedNumberData* validate(UFormattedNumber* input, UErrorCode& status);
-
-    /** Convert from UFormattedNumber -> UFormattedNumberData (const version). */
-    static const UFormattedNumberData* validate(const UFormattedNumber* input, UErrorCode& status);
-
-    /** Convert from UFormattedNumberData -> UFormattedNumber. */
-    UFormattedNumber* exportForC();
 };
 
 
index 2c1f088b12db24bb4746892396cbdd63780026b8..463a2f93c6fcd6b30626e76095ea14aa717d3568 100644 (file)
@@ -52,7 +52,6 @@ SpoofImpl::SpoofImpl() {
 }
 
 void SpoofImpl::construct(UErrorCode& status) {
-    fMagic = USPOOF_MAGIC;
     fChecks = USPOOF_ALL_CHECKS;
     fSpoofData = NULL;
     fAllowedCharsSet = NULL;
@@ -74,12 +73,11 @@ void SpoofImpl::construct(UErrorCode& status) {
 
 // Copy Constructor, used by the user level clone() function.
 SpoofImpl::SpoofImpl(const SpoofImpl &src, UErrorCode &status)  :
-        fMagic(0), fChecks(USPOOF_ALL_CHECKS), fSpoofData(NULL), fAllowedCharsSet(NULL) , 
+        fChecks(USPOOF_ALL_CHECKS), fSpoofData(NULL), fAllowedCharsSet(NULL) , 
         fAllowedLocales(NULL) {
     if (U_FAILURE(status)) {
         return;
     }
-    fMagic = src.fMagic;
     fChecks = src.fChecks;
     if (src.fSpoofData != NULL) {
         fSpoofData = src.fSpoofData->addReference();
@@ -93,8 +91,6 @@ SpoofImpl::SpoofImpl(const SpoofImpl &src, UErrorCode &status)  :
 }
 
 SpoofImpl::~SpoofImpl() {
-    fMagic = 0;                // head off application errors by preventing use of
-                               //    of deleted objects.
     if (fSpoofData != NULL) {
         fSpoofData->removeReference();   // Will delete if refCount goes to zero.
     }
@@ -104,7 +100,7 @@ SpoofImpl::~SpoofImpl() {
 
 //  Cast this instance as a USpoofChecker for the C API.
 USpoofChecker *SpoofImpl::asUSpoofChecker() {
-    return reinterpret_cast<USpoofChecker*>(this);
+    return exportForC();
 }
 
 //
@@ -112,18 +108,10 @@ USpoofChecker *SpoofImpl::asUSpoofChecker() {
 //    received from the C API.
 //
 const SpoofImpl *SpoofImpl::validateThis(const USpoofChecker *sc, UErrorCode &status) {
+    auto* This = validate(sc, status);
     if (U_FAILURE(status)) {
         return NULL;
     }
-    if (sc == NULL) {
-        status = U_ILLEGAL_ARGUMENT_ERROR;
-        return NULL;
-    }
-    SpoofImpl *This = (SpoofImpl *)sc;
-    if (This->fMagic != USPOOF_MAGIC) {
-        status = U_INVALID_FORMAT_ERROR;
-        return NULL;
-    }
     if (This->fSpoofData != NULL && !This->fSpoofData->validateDataVersion(status)) {
         return NULL;
     }
@@ -454,12 +442,12 @@ UChar32 SpoofImpl::ScanHex(const UChar *s, int32_t start, int32_t limit, UErrorC
 //
 //-----------------------------------------
 
-CheckResult::CheckResult() : fMagic(USPOOF_CHECK_MAGIC) {
+CheckResult::CheckResult() {
     clear();
 }
 
 USpoofCheckResult* CheckResult::asUSpoofCheckResult() {
-    return reinterpret_cast<USpoofCheckResult*>(this);
+    return exportForC();
 }
 
 //
@@ -467,22 +455,11 @@ USpoofCheckResult* CheckResult::asUSpoofCheckResult() {
 //    received from the C API.
 //
 const CheckResult* CheckResult::validateThis(const USpoofCheckResult *ptr, UErrorCode &status) {
-    if (U_FAILURE(status)) { return NULL; }
-    if (ptr == NULL) {
-        status = U_ILLEGAL_ARGUMENT_ERROR;
-        return NULL;
-    }
-    CheckResult *This = (CheckResult*) ptr;
-    if (This->fMagic != USPOOF_CHECK_MAGIC) {
-        status = U_INVALID_FORMAT_ERROR;
-        return NULL;
-    }
-    return This;
+    return validate(ptr, status);
 }
 
 CheckResult* CheckResult::validateThis(USpoofCheckResult *ptr, UErrorCode &status) {
-    return const_cast<CheckResult *>
-        (CheckResult::validateThis(const_cast<const USpoofCheckResult*>(ptr), status));
+    return validate(ptr, status);
 }
 
 void CheckResult::clear() {
index 0eee0e58a8a36ac35b88611500f21ec8eed16060..b111d4b16a937669b96d996ccd1e0d8d21a3c23b 100644 (file)
@@ -27,6 +27,8 @@
 
 #ifdef __cplusplus
 
+#include "capi_helper.h"
+
 U_NAMESPACE_BEGIN
 
 // The maximium length (in UTF-16 UChars) of the skeleton replacement string resulting from
@@ -52,7 +54,8 @@ class ConfusableDataUtils;
   *  Class SpoofImpl corresponds directly to the plain C API opaque type
   *  USpoofChecker.  One can be cast to the other.
   */
-class SpoofImpl : public UObject  {
+class SpoofImpl : public UObject,
+        public IcuCApiHelper<USpoofChecker, SpoofImpl, USPOOF_MAGIC> {
 public:
     SpoofImpl(SpoofData *data, UErrorCode& status);
     SpoofImpl(UErrorCode& status);
@@ -96,7 +99,6 @@ public:
     // Data Members
     //
 
-    int32_t           fMagic;             // Internal sanity check.
     int32_t           fChecks;            // Bit vector of checks to perform.
 
     SpoofData        *fSpoofData;
@@ -112,7 +114,8 @@ public:
  *  Class CheckResult corresponds directly to the plain C API opaque type
  *  USpoofCheckResult.  One can be cast to the other.
  */
-class CheckResult : public UObject {
+class CheckResult : public UObject,
+        public IcuCApiHelper<USpoofCheckResult, CheckResult, USPOOF_CHECK_MAGIC> {
 public:
     CheckResult();
     virtual ~CheckResult();
@@ -127,7 +130,6 @@ public:
     int32_t toCombinedBitmask(int32_t expectedChecks);
 
     // Data Members
-    int32_t fMagic;                        // Internal sanity check.
     int32_t fChecks;                       // Bit vector of checks that were failed.
     UnicodeSet fNumerics;                  // Set of numerics found in the string.
     URestrictionLevel fRestrictionLevel;   // The restriction level of the string.