ICU-6483 add ErrorCode class, C++ convenience wrapper for UErrorCode

X-SVN-Rev: 25546
This commit is contained in:
Markus Scherer 2009-03-11 05:27:11 +00:00
parent dfd1678de7
commit 2c2bf3e72a
6 changed files with 323 additions and 6 deletions

View File

@ -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 \

View File

@ -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 &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
Outputs="..\..\include\unicode\$(InputFileName)"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCustomBuildTool"
CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
Outputs="..\..\include\unicode\$(InputFileName)"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCustomBuildTool"
CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
Outputs="..\..\include\unicode\$(InputFileName)"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug|x64"
>
<Tool
Name="VCCustomBuildTool"
CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
Outputs="..\..\include\unicode\$(InputFileName)"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\locmap.c"
>

View 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

View 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__

View File

@ -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)");
}
}

View File

@ -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