ICU-6483 add ErrorCode class, C++ convenience wrapper for UErrorCode
X-SVN-Rev: 25546
This commit is contained in:
parent
dfd1678de7
commit
2c2bf3e72a
@ -67,7 +67,7 @@ LDFLAGS += $(LDFLAGSICUUC)
|
||||
# $(LIBICUDT) is either stub data or the real DLL common data.
|
||||
LIBS = $(LIBICUDT) $(DEFAULT_LIBS)
|
||||
|
||||
OBJECTS = putil.o umath.o utypes.o uinvchar.o umutex.o ucln_cmn.o uinit.o uobject.o cmemory.o \
|
||||
OBJECTS = errorcode.o putil.o umath.o utypes.o uinvchar.o umutex.o ucln_cmn.o uinit.o uobject.o cmemory.o \
|
||||
udata.o ucmndata.o udatamem.o umapfile.o udataswp.o ucol_swp.o utrace.o \
|
||||
uhash.o uhash_us.o uenum.o ustrenum.o uvector.o ustack.o uvectr32.o \
|
||||
ucnv.o ucnv_bld.o ucnv_cnv.o ucnv_io.o ucnv_cb.o ucnv_err.o ucnvlat1.o \
|
||||
|
@ -1044,6 +1044,50 @@
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\errorcode.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\unicode\errorcode.h"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
CommandLine="copy "$(InputPath)" ..\..\include\unicode
"
|
||||
Outputs="..\..\include\unicode\$(InputFileName)"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
CommandLine="copy "$(InputPath)" ..\..\include\unicode
"
|
||||
Outputs="..\..\include\unicode\$(InputFileName)"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
CommandLine="copy "$(InputPath)" ..\..\include\unicode
"
|
||||
Outputs="..\..\include\unicode\$(InputFileName)"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
CommandLine="copy "$(InputPath)" ..\..\include\unicode
"
|
||||
Outputs="..\..\include\unicode\$(InputFileName)"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\locmap.c"
|
||||
>
|
||||
|
43
icu4c/source/common/errorcode.cpp
Normal file
43
icu4c/source/common/errorcode.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2009, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
*
|
||||
*******************************************************************************
|
||||
* file name: errorcode.cpp
|
||||
* encoding: US-ASCII
|
||||
* tab size: 8 (not used)
|
||||
* indentation:4
|
||||
*
|
||||
* created on: 2009mar10
|
||||
* created by: Markus W. Scherer
|
||||
*/
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
#include "unicode/errorcode.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
ErrorCode::~ErrorCode() {}
|
||||
/* Logically
|
||||
if(isFailure()) {
|
||||
handleFailure(kDestructor);
|
||||
}
|
||||
but in the destructor, even if it's virtual, this does not call
|
||||
the subclass' handleFailure(), and our own handleFailure()
|
||||
does not do anything.
|
||||
The subclass must have this code.
|
||||
*/
|
||||
|
||||
UErrorCode ErrorCode::reset() {
|
||||
UErrorCode code = errorCode;
|
||||
errorCode = U_ZERO_ERROR;
|
||||
return code;
|
||||
}
|
||||
|
||||
void ErrorCode::check() const {
|
||||
if(isFailure()) { handleFailure(kCheck); }
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
103
icu4c/source/common/unicode/errorcode.h
Normal file
103
icu4c/source/common/unicode/errorcode.h
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2009, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
*
|
||||
*******************************************************************************
|
||||
* file name: errorcode.h
|
||||
* encoding: US-ASCII
|
||||
* tab size: 8 (not used)
|
||||
* indentation:4
|
||||
*
|
||||
* created on: 2009mar10
|
||||
* created by: Markus W. Scherer
|
||||
*/
|
||||
|
||||
#ifndef __ERRORCODE_H__
|
||||
#define __ERRORCODE_H__
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief C++ API: ErrorCode class intended to make it easier to use
|
||||
* ICU C and C++ APIs from C++ user code.
|
||||
*/
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
#include "unicode/uobject.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
/**
|
||||
* Wrapper class for UErrorCode, with conversion operators for direct use
|
||||
* in ICU C and C++ APIs.
|
||||
* Intended to be used as a base class, where a subclass overrides
|
||||
* the handleFailure() function so that it throws an exception,
|
||||
* does an assert(), logs an error, etc.
|
||||
* This is not an abstract base class. This class can be used and instantiated
|
||||
* by itself, although it will be more useful when subclassed.
|
||||
*
|
||||
* Features:
|
||||
* - The constructor initializes the internal UErrorCode to U_ZERO_ERROR,
|
||||
* removing one common source of errors.
|
||||
* - Same use in C APIs taking a UErrorCode * (pointer)
|
||||
* and C++ taking UErrorCode & (reference) via conversion operators.
|
||||
* - Automatic checking for success when it goes out of scope.
|
||||
*
|
||||
* Code sample, using an appropriate IcuErrorCode subclass:
|
||||
* \code
|
||||
* IcuErrorCode error_code;
|
||||
* UConverter *cnv = ucnv_open("Shift-JIS", error_code);
|
||||
* length = ucnv_fromUChars(dest, capacity, src, length, error_code);
|
||||
* ucnv_close(cnv);
|
||||
* // IcuErrorCode destructor checks for success.
|
||||
* \endcode
|
||||
*
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
class U_COMMON_API ErrorCode: public UMemory {
|
||||
public:
|
||||
/**
|
||||
* Default constructor. Initializes its UErrorCode to U_ZERO_ERROR.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
ErrorCode() : errorCode(U_ZERO_ERROR) {}
|
||||
/**
|
||||
* Destructor, does nothing.
|
||||
* A subclass destructor should do
|
||||
* if(isFailure()) { handleFailure(kDestructor); }
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
virtual ~ErrorCode();
|
||||
/** Conversion operator, returns a reference. @draft ICU 4.2 */
|
||||
operator UErrorCode & () { return errorCode; }
|
||||
/** Conversion operator, returns a pointer. @draft ICU 4.2 */
|
||||
operator UErrorCode * () { return &errorCode; }
|
||||
/** Tests for U_SUCCESS(). @draft ICU 4.2 */
|
||||
UBool isSuccess() const { return U_SUCCESS(errorCode); }
|
||||
/** Tests for U_FAILURE(). @draft ICU 4.2 */
|
||||
UBool isFailure() const { return U_FAILURE(errorCode); }
|
||||
/** Returns the UErrorCode value. @draft ICU 4.2 */
|
||||
UErrorCode get() const { return errorCode; }
|
||||
/** Sets the UErrorCode value. @draft ICU 4.2 */
|
||||
void set(UErrorCode value) { errorCode=value; }
|
||||
/** Returns the UErrorCode value and resets it to U_ZERO_ERROR. @draft ICU 4.2 */
|
||||
UErrorCode reset();
|
||||
/**
|
||||
* Checks for a failure code:
|
||||
* if(isFailure()) { handleFailure(kCheck); }
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
void check() const;
|
||||
|
||||
protected:
|
||||
UErrorCode errorCode;
|
||||
enum EOrigin { kCheck, kDestructor };
|
||||
// Note: A C++ class destructor must not throw an exception.
|
||||
// Use the origin parameter to avoid this if necessary.
|
||||
virtual void handleFailure(EOrigin origin) const {}
|
||||
};
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif // __ERRORCODE_H__
|
@ -1,6 +1,6 @@
|
||||
/********************************************************************
|
||||
* COPYRIGHT:
|
||||
* Copyright (c) 1997-2008, International Business Machines Corporation and
|
||||
* Copyright (c) 1997-2009, International Business Machines Corporation and
|
||||
* others. All Rights Reserved.
|
||||
********************************************************************/
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
#include "unicode/errorcode.h"
|
||||
#include "itutil.h"
|
||||
#include "strtest.h"
|
||||
#include "loctest.h"
|
||||
@ -55,8 +56,130 @@ void IntlTestUtilities::runIndexedTest( int32_t index, UBool exec, const char* &
|
||||
CASE(11, UVectorTest);
|
||||
CASE(12, UTextTest);
|
||||
CASE(13, LocaleAliasTest);
|
||||
CASE(14, UnicodeSetTest);
|
||||
CASE(14, UnicodeSetTest);
|
||||
CASE(15, ErrorCodeTest);
|
||||
default: name = ""; break; //needed to end loop
|
||||
}
|
||||
}
|
||||
|
||||
void ErrorCodeTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* par) {
|
||||
if (exec) logln("TestSuite Utilities: ");
|
||||
switch (index) {
|
||||
case 0: name = "TestErrorCode"; if (exec) TestErrorCode(); break;
|
||||
case 1: name = "TestSubclass"; if (exec) TestSubclass(); break;
|
||||
default: name = ""; break; //needed to end loop
|
||||
}
|
||||
}
|
||||
|
||||
static void RefPlusOne(UErrorCode &code) { code=(UErrorCode)(code+1); }
|
||||
static void PtrPlusTwo(UErrorCode *code) { *code=(UErrorCode)(*code+2); }
|
||||
|
||||
void ErrorCodeTest::TestErrorCode() {
|
||||
ErrorCode errorCode;
|
||||
if(errorCode.get()!=U_ZERO_ERROR || !errorCode.isSuccess() || errorCode.isFailure()) {
|
||||
errln("ErrorCode did not initialize properly");
|
||||
return;
|
||||
}
|
||||
errorCode.check();
|
||||
RefPlusOne(errorCode);
|
||||
if(errorCode.get()!=U_ILLEGAL_ARGUMENT_ERROR || errorCode.isSuccess() || !errorCode.isFailure()) {
|
||||
errln("ErrorCode did not yield a writable reference");
|
||||
}
|
||||
PtrPlusTwo(errorCode);
|
||||
if(errorCode.get()!=U_INVALID_FORMAT_ERROR || errorCode.isSuccess() || !errorCode.isFailure()) {
|
||||
errln("ErrorCode did not yield a writable pointer");
|
||||
}
|
||||
errorCode.set(U_PARSE_ERROR);
|
||||
if(errorCode.get()!=U_PARSE_ERROR || errorCode.isSuccess() || !errorCode.isFailure()) {
|
||||
errln("ErrorCode.set() failed");
|
||||
}
|
||||
if( errorCode.reset()!=U_PARSE_ERROR || errorCode.get()!=U_ZERO_ERROR ||
|
||||
!errorCode.isSuccess() || errorCode.isFailure()
|
||||
) {
|
||||
errln("ErrorCode did not reset properly");
|
||||
}
|
||||
}
|
||||
|
||||
class MyErrorCode: public ErrorCode {
|
||||
public:
|
||||
MyErrorCode(int32_t &countChecks, int32_t &countDests)
|
||||
: checks(countChecks), dests(countDests) {}
|
||||
~MyErrorCode() {
|
||||
if(isFailure()) {
|
||||
handleFailure(kDestructor);
|
||||
}
|
||||
}
|
||||
private:
|
||||
virtual void handleFailure(EOrigin origin) const {
|
||||
switch(origin) {
|
||||
case kCheck:
|
||||
++checks;
|
||||
break;
|
||||
case kDestructor:
|
||||
++dests;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
int32_t &checks;
|
||||
int32_t &dests;
|
||||
};
|
||||
|
||||
void ErrorCodeTest::TestSubclass() {
|
||||
int32_t countChecks=0;
|
||||
int32_t countDests=0;
|
||||
{
|
||||
MyErrorCode errorCode(countChecks, countDests);
|
||||
if( errorCode.get()!=U_ZERO_ERROR || !errorCode.isSuccess() || errorCode.isFailure() ||
|
||||
countChecks!=0 || countDests!=0
|
||||
) {
|
||||
errln("ErrorCode did not initialize properly");
|
||||
return;
|
||||
}
|
||||
errorCode.check();
|
||||
if(countChecks!=0) {
|
||||
errln("ErrorCode.check() called handleFailure(kCheck) despite success");
|
||||
}
|
||||
RefPlusOne(errorCode);
|
||||
if(errorCode.get()!=U_ILLEGAL_ARGUMENT_ERROR || errorCode.isSuccess() || !errorCode.isFailure()) {
|
||||
errln("ErrorCode did not yield a writable reference");
|
||||
}
|
||||
errorCode.check();
|
||||
if(countChecks!=1) {
|
||||
errln("ErrorCode.check() did not handleFailure(kCheck)");
|
||||
}
|
||||
PtrPlusTwo(errorCode);
|
||||
if(errorCode.get()!=U_INVALID_FORMAT_ERROR || errorCode.isSuccess() || !errorCode.isFailure()) {
|
||||
errln("ErrorCode did not yield a writable pointer");
|
||||
}
|
||||
errorCode.check();
|
||||
if(countChecks!=2) {
|
||||
errln("ErrorCode.check() did not handleFailure(kCheck)");
|
||||
}
|
||||
errorCode.set(U_PARSE_ERROR);
|
||||
if(errorCode.get()!=U_PARSE_ERROR || errorCode.isSuccess() || !errorCode.isFailure()) {
|
||||
errln("ErrorCode.set() failed");
|
||||
}
|
||||
if( errorCode.reset()!=U_PARSE_ERROR || errorCode.get()!=U_ZERO_ERROR ||
|
||||
!errorCode.isSuccess() || errorCode.isFailure()
|
||||
) {
|
||||
errln("ErrorCode did not reset properly");
|
||||
}
|
||||
errorCode.check();
|
||||
if(countChecks!=2) {
|
||||
errln("ErrorCode.check() called handleFailure(kCheck) despite success");
|
||||
}
|
||||
}
|
||||
if(countDests!=0) {
|
||||
errln("ErrorCode.check() called handleFailure(kDestructor) despite success");
|
||||
}
|
||||
countChecks=countDests=0;
|
||||
{
|
||||
MyErrorCode errorCode(countChecks, countDests);
|
||||
errorCode.set(U_PARSE_ERROR);
|
||||
}
|
||||
if(countDests!=1) {
|
||||
errln("ErrorCode destructor did not handleFailure(kDestructor)");
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/********************************************************************
|
||||
* COPYRIGHT:
|
||||
* Copyright (c) 1997-2001, International Business Machines Corporation and
|
||||
* Copyright (c) 1997-2009, International Business Machines Corporation and
|
||||
* others. All Rights Reserved.
|
||||
********************************************************************/
|
||||
|
||||
@ -11,14 +11,18 @@
|
||||
#ifndef _INTLTESTUTILITIES
|
||||
#define _INTLTESTUTILITIES
|
||||
|
||||
|
||||
#include "intltest.h"
|
||||
|
||||
|
||||
class IntlTestUtilities: public IntlTest {
|
||||
public:
|
||||
void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
|
||||
};
|
||||
|
||||
class ErrorCodeTest: public IntlTest {
|
||||
public:
|
||||
void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par = NULL);
|
||||
void TestErrorCode();
|
||||
void TestSubclass();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user