os/ossrv/lowlevellibsandfws/genericusabilitylib/example/src/euserhl_walkthrough.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
//
sl@0
    15
sl@0
    16
#include <e32std.h>
sl@0
    17
#include <f32file.h>
sl@0
    18
#include <e32test.h>
sl@0
    19
#include <euserhl.h>
sl@0
    20
sl@0
    21
sl@0
    22
sl@0
    23
// Note: Methods are defined inline within classes here simply to make
sl@0
    24
// the code shorter, keep related code closer together, and hopefully
sl@0
    25
// make things easier to follow.
sl@0
    26
sl@0
    27
RTest test(_L("EuserHl Walkthrough"));
sl@0
    28
sl@0
    29
// Some dummy methods and data used in the walkthroughs below
sl@0
    30
_LIT(KFill, "XXX");
sl@0
    31
_LIT(KPath, "c:\\a\\b\\c");
sl@0
    32
_LIT(KOne, "One ");
sl@0
    33
_LIT(KTwo, "Two ");
sl@0
    34
_LIT(KTesting, "Testing ");
sl@0
    35
sl@0
    36
void MaybeLeaveL()
sl@0
    37
	{
sl@0
    38
	// Some code that may leave
sl@0
    39
	}
sl@0
    40
sl@0
    41
HBufC* AllocateNameL(const TDesC& aDes)
sl@0
    42
	{
sl@0
    43
	return aDes.AllocL();
sl@0
    44
	}
sl@0
    45
sl@0
    46
void ReadToMax(TDes& aDes)
sl@0
    47
	{
sl@0
    48
	aDes.SetMax();
sl@0
    49
	aDes.Repeat(KFill);
sl@0
    50
	}
sl@0
    51
sl@0
    52
void GetCurrentPath(TDes& aDes)
sl@0
    53
	{
sl@0
    54
	aDes = KPath;
sl@0
    55
	}
sl@0
    56
sl@0
    57
void GetCurrentPathStringL(LString& aString)
sl@0
    58
	{
sl@0
    59
	aString = L"c:\\a\\b\\c"; // Will auto-grow if necessary, may leave
sl@0
    60
	}
sl@0
    61
sl@0
    62
LString AppendCurrentPathStringL(LString aString)
sl@0
    63
	{
sl@0
    64
	return aString+= L"c:\\a\\b\\c";
sl@0
    65
	}
sl@0
    66
sl@0
    67
class CTicker : public CBase
sl@0
    68
	{
sl@0
    69
public:
sl@0
    70
	void Tick() { ++iTicks; }
sl@0
    71
	void Tock() { ++iTocks; }
sl@0
    72
sl@0
    73
	void Zap() { delete this; }
sl@0
    74
sl@0
    75
public:
sl@0
    76
	TInt iTicks;
sl@0
    77
	TInt iTocks;
sl@0
    78
	};
sl@0
    79
sl@0
    80
// Defines a custom pointer cleanup policy that calls the Zap member
sl@0
    81
class TTickerZapStrategy
sl@0
    82
	{
sl@0
    83
public:
sl@0
    84
	static void Cleanup(CTicker* aPtr)
sl@0
    85
		{
sl@0
    86
		// The general template/class scaffolding remains the same
sl@0
    87
		// for all custom cleanups, just this cleanup body varies
sl@0
    88
		aPtr->Zap();
sl@0
    89
		test.Printf(_L("Zapped CTicker\n"));
sl@0
    90
		}
sl@0
    91
	};
sl@0
    92
sl@0
    93
void RegisterTicker(CTicker& aTicker)
sl@0
    94
	{
sl@0
    95
	(void)aTicker;
sl@0
    96
	}
sl@0
    97
sl@0
    98
void RegisterTickerPtr(CTicker* aTicker)
sl@0
    99
	{
sl@0
   100
	(void)aTicker;
sl@0
   101
	}
sl@0
   102
sl@0
   103
void TakeTickerOwnership(CTicker* aTicker)
sl@0
   104
	{
sl@0
   105
	delete aTicker;
sl@0
   106
	}
sl@0
   107
sl@0
   108
void RegisterTimer(RTimer& aTimer)
sl@0
   109
	{
sl@0
   110
	(void)aTimer;
sl@0
   111
	}
sl@0
   112
sl@0
   113
// Defines a custom handle cleanup policy that calls Cancel then Close
sl@0
   114
class TCancelClose
sl@0
   115
	{
sl@0
   116
public:
sl@0
   117
	template <class T>
sl@0
   118
	static void Cleanup(T* aHandle)
sl@0
   119
		{
sl@0
   120
		// The general template/class scaffolding remains the same
sl@0
   121
		// for all custom cleanups, just this cleanup body varies
sl@0
   122
		aHandle->Cancel();
sl@0
   123
		aHandle->Close();
sl@0
   124
		test.Printf(_L("Cancel Closed RTimer\n"));
sl@0
   125
		}
sl@0
   126
	};
sl@0
   127
sl@0
   128
void BespokeCleanupFunction(TAny* aData)
sl@0
   129
	{
sl@0
   130
	(void)aData;
sl@0
   131
	test.Printf(_L("BespokeCleanupFunction\n"));
sl@0
   132
	}
sl@0
   133
sl@0
   134
// The walkthroughs themselves
sl@0
   135
sl@0
   136
// This class demonstrates the use of an embedded LString in the
sl@0
   137
// conventional Symbian two-phase construction pattern. We've chosen
sl@0
   138
// to implement the temporary leave protection in NewL in terms of
sl@0
   139
// LCleanedupPtr instead of the the CleanupStack API in this example.
sl@0
   140
class CStringUserTwoPhase : public CBase
sl@0
   141
	{
sl@0
   142
public:
sl@0
   143
	static CStringUserTwoPhase* NewL(const TDesC& aName)
sl@0
   144
		{
sl@0
   145
		// We can use the resource management utility classes in
sl@0
   146
		// two-phase if we want to
sl@0
   147
		LCleanedupPtr<CStringUserTwoPhase> self(new(ELeave) CStringUserTwoPhase);
sl@0
   148
		self->ConstructL(aName);
sl@0
   149
		// Calling Unmanage() disables cleanup and yields the
sl@0
   150
		// previously managed pointer so that it can be safely
sl@0
   151
		// returned
sl@0
   152
		return self.Unmanage(); 
sl@0
   153
		}
sl@0
   154
sl@0
   155
	virtual void ConstructL(const TDesC& aName)
sl@0
   156
		{
sl@0
   157
		// This assignment may leave if LString fails to allocate a
sl@0
   158
		// heap buffer large enough to hold the data in aName
sl@0
   159
		iName = aName; 
sl@0
   160
		}
sl@0
   161
sl@0
   162
	~CStringUserTwoPhase()
sl@0
   163
		{
sl@0
   164
		// The iName LString cleans up after itself automatically 
sl@0
   165
		}
sl@0
   166
sl@0
   167
	const TDesC& Name() 
sl@0
   168
		{
sl@0
   169
		// We can just return an LString directly as a const TDesC
sl@0
   170
		return iName; 
sl@0
   171
		}
sl@0
   172
sl@0
   173
protected:
sl@0
   174
	CStringUserTwoPhase()
sl@0
   175
		{
sl@0
   176
		// Everything interesting happens in ConstructL in this
sl@0
   177
		// version. 
sl@0
   178
sl@0
   179
		// Default initialization of the iName LString does not
sl@0
   180
		// allocate a heap buffer, and so cannot leave. As long as
sl@0
   181
		// initialization is deferred to ConstructL, LStrings can be
sl@0
   182
		// used safely with two-phase construction.
sl@0
   183
		}
sl@0
   184
sl@0
   185
protected:
sl@0
   186
	LString iName;
sl@0
   187
	};
sl@0
   188
sl@0
   189
// This class demonstrates the use of an embedded LString in the
sl@0
   190
// single-phase construction pattern, where a leave-safe constructor
sl@0
   191
// fully initializes the object. 
sl@0
   192
//
sl@0
   193
// Note that where a class's constructor forms part of its exported
sl@0
   194
// public or protected contract, switching from a non-leaving to a
sl@0
   195
// potentially leaving constructor would be a BC break. On the other
sl@0
   196
// hand, if instantiation is entirely encapsulated within factory
sl@0
   197
// functions like NewL, there is no such BC restriction.
sl@0
   198
class CStringUserSinglePhase : public CBase
sl@0
   199
	{
sl@0
   200
public:
sl@0
   201
	// This macro is necessary to ensure cleanup is correctly handled
sl@0
   202
	// in the event that a constructor may leave beneath a call to
sl@0
   203
	// new(ELeave)
sl@0
   204
	CONSTRUCTORS_MAY_LEAVE
sl@0
   205
sl@0
   206
	static CStringUserSinglePhase* NewL(const TDesC& aName)
sl@0
   207
		{
sl@0
   208
		return new(ELeave) CStringUserSinglePhase(aName);
sl@0
   209
		}
sl@0
   210
sl@0
   211
	~CStringUserSinglePhase()
sl@0
   212
		{
sl@0
   213
		// The iName LString cleans up after itself automatically
sl@0
   214
		}
sl@0
   215
sl@0
   216
	const TDesC& Name() 
sl@0
   217
		{
sl@0
   218
		// We can just return an LString directly as a const TDesC
sl@0
   219
		return iName;
sl@0
   220
		}
sl@0
   221
sl@0
   222
protected:
sl@0
   223
	CStringUserSinglePhase(const TDesC& aName)
sl@0
   224
		// This initialization of iName may leave because LString
sl@0
   225
		// needs to allocate a heap buffer to copy the aName string
sl@0
   226
		// data into
sl@0
   227
		: iName(aName) 
sl@0
   228
		{
sl@0
   229
		// If iName initialization is successful but the constructor
sl@0
   230
		// then goes on to leave later, iName (like all fields fully
sl@0
   231
		// constructed at the point of a leave in a constructor) will
sl@0
   232
		// be destructed, and so clean up after itself
sl@0
   233
		MaybeLeaveL();
sl@0
   234
		}
sl@0
   235
sl@0
   236
protected:
sl@0
   237
	LString iName;
sl@0
   238
	};
sl@0
   239
sl@0
   240
sl@0
   241
void WalkthroughStringsL()
sl@0
   242
	{
sl@0
   243
sl@0
   244
		{
sl@0
   245
		// Trivially exercise the LString using classes defined above
sl@0
   246
sl@0
   247
		LCleanedupPtr<CStringUserTwoPhase> one(CStringUserTwoPhase::NewL(KOne));
sl@0
   248
		test.Printf(_L("Single phase name: %S\n"), &one->Name());
sl@0
   249
sl@0
   250
		LCleanedupPtr<CStringUserSinglePhase> two(CStringUserSinglePhase::NewL(KTwo));
sl@0
   251
		test.Printf(_L("Two phase name: %S\n"), &two->Name());
sl@0
   252
sl@0
   253
		// Both instances are automatically deleted as we go out of scope
sl@0
   254
		}
sl@0
   255
sl@0
   256
		{
sl@0
   257
		// A default constructed LString starts empty, doesn't
sl@0
   258
		// allocate any memory on the heap, and therefore the
sl@0
   259
		// following cannot leave
sl@0
   260
		LString s;
sl@0
   261
sl@0
   262
		// But it will grow on demand if you assign to it, so it has
sl@0
   263
		// enough space to hold the copied string data, and so
sl@0
   264
		// assignment may leave
sl@0
   265
		s = L"One ";
sl@0
   266
sl@0
   267
		// Similarly if you append to it with the leaving variant of
sl@0
   268
		// Append, AppendL, if may grow on demand
sl@0
   269
		s.AppendL(L"Two ");
sl@0
   270
sl@0
   271
		// The += operator for LString also maps to AppendL
sl@0
   272
		s += L"Three ";
sl@0
   273
sl@0
   274
		// You can also use new leaving format methods that also grow
sl@0
   275
		// on demand
sl@0
   276
		s.AppendFormatL(KTesting);
sl@0
   277
sl@0
   278
		// This general style of use of LString may be preferable to
sl@0
   279
		// typical descriptor use for a number of reasons e.g. it
sl@0
   280
		// avoids the common temptation to set an artificial maximum
sl@0
   281
		// buffer size; it avoids massive conservative over-allocation
sl@0
   282
		// when the average case length of a string is far less than
sl@0
   283
		// the worst-case maximum; it will not surprise you (compared
sl@0
   284
		// to the alternative of a large stack-allocated TBuf) by
sl@0
   285
		// triggering stack overflow.
sl@0
   286
sl@0
   287
		// An LString can be printed the same way as any descriptor
sl@0
   288
		test.Printf(_L("Value: %S\n"), &s);
sl@0
   289
sl@0
   290
		// An LString supports all TDesC and TDes methods
sl@0
   291
		// LString findToken(L"Two ");
sl@0
   292
		test(s.Find(L"Two ") == 4);
sl@0
   293
		
sl@0
   294
		// LString matchPattern(L"*Two* ");
sl@0
   295
		test(s.Match(L"*Two*") == 4);
sl@0
   296
		test(s.Match(L"*T?o*") == 4);
sl@0
   297
		
sl@0
   298
		// LString compare(L"some string");
sl@0
   299
		test(s.Compare(L"One Two Three Testing ") == 0);
sl@0
   300
		test(s.Compare(L"One Two Three Testing! ") < 0);
sl@0
   301
		test(s.Compare(L"One Two Testing ") > 0);
sl@0
   302
		
sl@0
   303
		// also LString ==,!=,>,<,<=,>=(L"some string");
sl@0
   304
		test(s == L"One Two Three Testing ");
sl@0
   305
		test(s < L"One Two Three Testing! ");
sl@0
   306
		test(s > L"One Two Testing ");
sl@0
   307
		test(s != L"not equal");
sl@0
   308
		
sl@0
   309
		// An LString supports all TDesC and TDes operators
sl@0
   310
		test(s[4] == TChar('T'));
sl@0
   311
sl@0
   312
		TInt untrimmed = s.Length();
sl@0
   313
		s.Trim();
sl@0
   314
		test(s.Length() == untrimmed - 1);
sl@0
   315
sl@0
   316
		s.UpperCase();
sl@0
   317
		test.Printf(_L("UpperCase: %S\n"), &s);
sl@0
   318
		s.LowerCase();
sl@0
   319
		test.Printf(_L("LowerCase: %S\n"), &s);
sl@0
   320
sl@0
   321
		// The underlying heap allocated buffer is released
sl@0
   322
		// automatically when the LString goes out of scope, either
sl@0
   323
		// normally or through a leave
sl@0
   324
		}
sl@0
   325
		{
sl@0
   326
		// Copy, Append,Insert,Replace,Justify the same way as TDesC and TDes
sl@0
   327
		
sl@0
   328
		LString s;
sl@0
   329
		// Copies data into this 8-bit string descriptor, replacing any existing
sl@0
   330
		// data, and expanding its heap buffer to accommodate if necessary.
sl@0
   331
		// leaves on not being able to accomodate the new content
sl@0
   332
		// both AssignL and += use CopyL internally
sl@0
   333
		s.CopyL(L"new way of dealing with strings");
sl@0
   334
		s.CopyUCL(L"new way of dealing with strings");
sl@0
   335
		test(s == L"NEW WAY OF DEALING WITH STRINGS");
sl@0
   336
		
sl@0
   337
		// Insert data into this descriptor.
sl@0
   338
		// The length of this descriptor is changed to reflect the extra data.
sl@0
   339
		// This leaving variant of the standard, non-leaving descriptor method
sl@0
   340
		// differs in that this operation may cause the string descriptor's heap
sl@0
   341
		// buffer to be reallocated in order to accommodate the new data. As a
sl@0
   342
		// result, MaxLength() and Ptr() may return different values afterwards,
sl@0
   343
		// and any existing raw pointers to into the descriptor data may be
sl@0
   344
		// invalidated.
sl@0
   345
		s.CopyL(L"Some Content Can Be Into This String");
sl@0
   346
		s.InsertL(20,L"Inserted ");
sl@0
   347
		test(s == L"Some Content Can Be Inserted Into This String");
sl@0
   348
		
sl@0
   349
		// Replace data in this descriptor.
sl@0
   350
		// The specified length can be different to the length of the replacement data.
sl@0
   351
		// The length of this descriptor changes to reflect the change of data.
sl@0
   352
		// This leaving variant of the standard, non-leaving descriptor method
sl@0
   353
		// differs in that this operation may cause the string descriptor's heap
sl@0
   354
		// buffer to be reallocated in order to accommodate the new data. As a
sl@0
   355
		// result, MaxLength() and Ptr() may return different values afterwards,
sl@0
   356
		// and any existing raw pointers to into the descriptor data may be
sl@0
   357
		// invalidated.
sl@0
   358
		s.CopyL(L"Some Content Can Be Decalper");
sl@0
   359
		s.ReplaceL(20,8,L"Replaced");
sl@0
   360
		test(s == L"Some Content Can Be Replaced");
sl@0
   361
		
sl@0
   362
		// Append data onto the end of this descriptor's data.
sl@0
   363
		// The length of this descriptor is incremented to reflect the new content.
sl@0
   364
		// This leaving variant of the standard, non-leaving descriptor method
sl@0
   365
		// differs in that this operation may cause the string descriptor's heap
sl@0
   366
		// buffer to be reallocated in order to accommodate the new data. As a
sl@0
   367
		// result, MaxLength() and Ptr() may return different values afterwards,
sl@0
   368
		// and any existing raw pointers to into the descriptor data may be
sl@0
   369
		// invalidated.
sl@0
   370
		s.CopyL(L"Try appending ");
sl@0
   371
		s.AppendL(L"Try appending some more",3);
sl@0
   372
		test(s == L"Try appending Try");
sl@0
   373
		
sl@0
   374
		// Copy data into this descriptor and justifies it, replacing any existing data.
sl@0
   375
		// The length of this descriptor is set to reflect the new data.
sl@0
   376
		// The target area is considered to be an area of specified width positioned at
sl@0
   377
		// the beginning of this descriptor's data area. Source data is copied into, and
sl@0
   378
		// aligned within this target area according to the specified alignment
sl@0
   379
		// instruction.
sl@0
   380
		// If the length of the target area is larger than the length of the source, then
sl@0
   381
		// spare space within the target area is padded with the fill character.
sl@0
   382
		// This leaving variant of the standard, non-leaving descriptor method
sl@0
   383
		// differs in that this operation may cause the string descriptor's heap
sl@0
   384
		// buffer to be reallocated in order to accommodate the new data. As a
sl@0
   385
		// result, MaxLength() and Ptr() may return different values afterwards,
sl@0
   386
		// and any existing raw pointers to into the descriptor data may be
sl@0
   387
		// invalidated.
sl@0
   388
		s.CopyL(L"Justified");
sl@0
   389
		s.JustifyL(L"Just",9,ERight,'x');
sl@0
   390
		test(s == L"xxxxxJust");
sl@0
   391
		
sl@0
   392
		// Append data onto the end of this descriptor's data and justifies it.
sl@0
   393
		// The source of the appended data is a memory location.
sl@0
   394
		// The target area is considered to be an area of specified width, immediately 
sl@0
   395
		// following this descriptor's existing data. Source data is copied into, and 
sl@0
   396
		// aligned within, this target area according to the specified alignment instruction.
sl@0
   397
		// If the length of the target area is larger than the length of the source, 
sl@0
   398
		// then spare space within the target area is padded with the fill character.
sl@0
   399
		// This leaving variant of the standard, non-leaving descriptor method
sl@0
   400
		// differs in that this operation may cause the string descriptor's heap
sl@0
   401
		// buffer to be reallocated in order to accommodate the new data. As a
sl@0
   402
		// result, MaxLength() and Ptr() may return different values afterwards,
sl@0
   403
		// and any existing raw pointers to into the descriptor data may be
sl@0
   404
		// invalidated.
sl@0
   405
		s.CopyL(L"One ");
sl@0
   406
		s.AppendJustifyL(L"Two Three",3,7,ERight,'x');
sl@0
   407
		test(s == L"One xxxxTwo" );
sl@0
   408
		
sl@0
   409
		}
sl@0
   410
		{
sl@0
   411
		// You can initialize with a MaxLength value
sl@0
   412
		LString s(KMaxFileName); // This operation may leave
sl@0
   413
		test(s.MaxLength() == KMaxFileName);
sl@0
   414
sl@0
   415
		// And you can dynamically adjust MaxLength later using 
sl@0
   416
		// SetMaxLengthL if you want an exact allocated size
sl@0
   417
		// Setting MaxLength on construction or via SetMaxLengthL is
sl@0
   418
		// exact; calling MaxLength() immediately afterwards is
sl@0
   419
		// guaranteed to return exactly the value you specified
sl@0
   420
		s.SetMaxLengthL(2 * KMaxFileName);
sl@0
   421
		test(s.MaxLength() == 2 * KMaxFileName);
sl@0
   422
sl@0
   423
		// Pre-setting MaxLength is important when passing an LString
sl@0
   424
		// as a TDes to a library function, because the LString can't
sl@0
   425
		// be auto-grown via the TDes API
sl@0
   426
sl@0
   427
		}
sl@0
   428
sl@0
   429
		{
sl@0
   430
		// You can initialize from any descriptor/literal/[wide]character string and the
sl@0
   431
		// string data is copied into the LString
sl@0
   432
		LString s(L"One "); // From a character string
sl@0
   433
		s += L"Two ";
sl@0
   434
		LString half(s.Left(s.Length() / 2)); // Left returns a TPtrC
sl@0
   435
		test.Printf(_L("All: %S, Half: %S\n"), &s, &half);
sl@0
   436
sl@0
   437
		// On the other hand, you can initialize from a returned
sl@0
   438
		// HBufC* and the LString automatically takes ownership
sl@0
   439
		LString own(AllocateNameL(KTesting));
sl@0
   440
		test.Printf(_L("What I own: %S\n"), &own);
sl@0
   441
sl@0
   442
		// Following that you can re-assign an HBufC to an existing
sl@0
   443
		// string using the assignment operator 
sl@0
   444
		// taking ownership of the new content. 
sl@0
   445
		own = AllocateNameL(KTesting);
sl@0
   446
		
sl@0
   447
		// Following that you can re-assign an HBufC to an existing
sl@0
   448
		// string. The string destroys its original content before
sl@0
   449
		// taking ownership of the new content. 
sl@0
   450
		own.Assign(AllocateNameL(KTesting));
sl@0
   451
		
sl@0
   452
		// The content of one string can similarly be assigned
sl@0
   453
		// to another to avoid copying. In this example, the content 
sl@0
   454
		// is detached from 's' and transfered to 'own'.  
sl@0
   455
		own.Assign(s);
sl@0
   456
		
sl@0
   457
		// The same content transfer can be achieved from an RBuf to a
sl@0
   458
		// string. You may need to do this if a legacy method returns
sl@0
   459
		// you an RBuf. The RBuf is emptied of its content.
sl@0
   460
		RBuf16 buf;
sl@0
   461
		buf.CreateL(KOne);
sl@0
   462
		own.Assign(buf);
sl@0
   463
	
sl@0
   464
		// You can also assign a simple text array to a string as its
sl@0
   465
		// new buffer. This method initialises the length to zero.   
sl@0
   466
		own.Assign((TText*)User::Alloc(24*(TInt)sizeof(TText)), 24);
sl@0
   467
		
sl@0
   468
		// If the buffer has already been filled with some characters
sl@0
   469
		// then you supply the length in this alternative Assign method.   
sl@0
   470
		own.Assign((TText*)User::Alloc(24*(TInt)sizeof(TText)), 12,24);
sl@0
   471
sl@0
   472
		// Each Assign destroys the old content before assuming ownership
sl@0
   473
		// of the new.
sl@0
   474
		// As usual the last content of the string is destroyed when the 
sl@0
   475
		// LString goes out of scope
sl@0
   476
		}
sl@0
   477
sl@0
   478
		{
sl@0
   479
		// You can reserve extra free space in preparation for an 
sl@0
   480
		// operation that adds characters to the string. You may
sl@0
   481
		// need to do this when you cannot use any of the auto-buffer
sl@0
   482
		// extending LString methods to achieve your objective.
sl@0
   483
		LString s(L"One ");
sl@0
   484
		s.ReserveFreeCapacityL(4);
sl@0
   485
		test(s.Length() == 4);
sl@0
   486
		test(s.MaxLength() >= 8);
sl@0
   487
sl@0
   488
		// Almost all the methods that may extended the string buffer,
sl@0
   489
		// including the explicit ReserveFreeCapacityL, but excluding
sl@0
   490
		// SetMaxLengthL, attempt to grow the size exponentially. 
sl@0
   491
		// The Exponential growth pattern is expected to give better 
sl@0
   492
		// performance at an amortised complexity of O(n) when adding n characters.
sl@0
   493
		// If the exponential growth is less than the supplied extra size
sl@0
   494
		// then the supplied size is used instead to save time.
sl@0
   495
		// The exponential growth is used in anticipation of further additions
sl@0
   496
		// to a string. This trades-off speed efficiency for space efficiency.
sl@0
   497
		// If required you may be able to swap the oversized buffer for 
sl@0
   498
		// a more compact one using:
sl@0
   499
		s.Compress();
sl@0
   500
		test(s.MaxLength() >= 4);	//note indefinite test
sl@0
   501
		    
sl@0
   502
		// Resize attempts to re-allocate a smaller buffer to copy
sl@0
   503
		// the content into. If the new memory cannot be allocated then the
sl@0
   504
		// original string is left unaffected. 
sl@0
   505
		
sl@0
   506
		// When you have finished using the content of a string you can
sl@0
   507
		// get its buffer released without destroying the string itself. 
sl@0
   508
		// You may want to do this when using member declared strings.
sl@0
   509
		// Automatic strings are destroyed when they go out of scope.
sl@0
   510
		s.Reset();
sl@0
   511
		test(s.Length() == 0);
sl@0
   512
		test(s.MaxLength() == 0);
sl@0
   513
		
sl@0
   514
		}
sl@0
   515
sl@0
   516
		{
sl@0
   517
		// An LString can be passed directly to any function requiring
sl@0
   518
		// a const TDesC&
sl@0
   519
		TInt year = 2009;
sl@0
   520
sl@0
   521
		LString s;
sl@0
   522
		s.FormatL(_L("Happy New Year %d"), year);
sl@0
   523
		// InfoPrint takes a const TDesC&
sl@0
   524
		User::InfoPrint(s);
sl@0
   525
sl@0
   526
		LString pattern;
sl@0
   527
		pattern.FormatL(_L("*Year %d"), year);
sl@0
   528
		// Match takes a const TDesC& as a pattern
sl@0
   529
		TInt loc = s.Match(pattern);
sl@0
   530
		test(loc == 10);
sl@0
   531
		}
sl@0
   532
sl@0
   533
		{
sl@0
   534
		// An LString can be passed directly to any function requiring
sl@0
   535
		// a TDes& but care must always be taken to pre-set MaxLength
sl@0
   536
		// since LStrings can't be automatically grown via the TDes
sl@0
   537
		// interface
sl@0
   538
sl@0
   539
		LString s;
sl@0
   540
		// Calling GetCurrentPath(s) now would panic because LStrings
sl@0
   541
		// are initialized by default to MaxLength 0.  Although s is
sl@0
   542
		// an LString GetCurrentPath takes a TDes& and so inside the function
sl@0
   543
		// s behaves as a TDes and would panic with USER 11 if the resulting 
sl@0
   544
		// new length of s is greater than its maximum length.
sl@0
   545
		test(s.MaxLength() == 0);
sl@0
   546
sl@0
   547
		// Calling SetMaxLengthL will automatically realloc the
sl@0
   548
		// underlying buffer if required, and is guaranteed to leave
sl@0
   549
		// MaxLength() equal to the specified value
sl@0
   550
		s.SetMaxLengthL(KMaxFileName);
sl@0
   551
		GetCurrentPath(s);
sl@0
   552
		//LString pathString(L"c:\\a\\b\\c");
sl@0
   553
		test.Printf(_L("Path: %S\n"), &s);
sl@0
   554
		test(s == L"c:\\a\\b\\c");
sl@0
   555
sl@0
   556
		// If SetMaxLengthL adjusts MaxLength lower than the current
sl@0
   557
		// Length, the data is truncated to the new MaxLength and
sl@0
   558
		// Length set to the new MaxLength
sl@0
   559
		s.SetMaxLengthL(s.Length() / 2);
sl@0
   560
		test.Printf(_L("Truncated path: %S\n"), &s);
sl@0
   561
		test(s.Length() == s.MaxLength());
sl@0
   562
sl@0
   563
		// An initial MaxLength can be specified when constructing an
sl@0
   564
		// LString. Note that unlike the default constructor, this
sl@0
   565
		// variant allocates and may leave.
sl@0
   566
		LString s2(KMaxFileName);
sl@0
   567
		GetCurrentPath(s2);
sl@0
   568
		test.Printf(_L("Path: %S\n"), &s2);
sl@0
   569
		test(s2 == L"c:\\a\\b\\c");
sl@0
   570
sl@0
   571
		// Your code and APIs can benefit from LString's auto-growth
sl@0
   572
		// behaviour by accepting an LString to fill in as an output
sl@0
   573
		// parameter. Using LString rather than TDes parameters means 
sl@0
   574
		// that the function is able to safely increase the size of the 
sl@0
   575
		// string as the LString will re-allocate as necessary
sl@0
   576
		LString s3;
sl@0
   577
		// GetCurrentPathStringL takes an LString&
sl@0
   578
		GetCurrentPathStringL(s3);
sl@0
   579
		test.Printf(_L("Path: %S\n"), &s3);
sl@0
   580
		test(s3 == L"c:\\a\\b\\c");
sl@0
   581
sl@0
   582
		// As a well-defined value class, if you want to, LStrings can
sl@0
   583
		// be passed and returned by value. This is relatively
sl@0
   584
		// inefficient however due to the amount of copying and heap
sl@0
   585
		// reallocation involved. 
sl@0
   586
		LString s4(AppendCurrentPathStringL(s3));
sl@0
   587
		test.Printf(_L("Appended path: %S\n"), &s4);
sl@0
   588
		test(s4.Length() == s3.Length() * 2);
sl@0
   589
		}
sl@0
   590
sl@0
   591
		{
sl@0
   592
		// LStrings can be allocated on the heap if necessary. 
sl@0
   593
		// Then it can managed as part of an array of string pointers
sl@0
   594
		TInt n = 5;
sl@0
   595
		LCleanedupHandle<RPointerArray<LString>, TResetAndDestroy> sarray;
sl@0
   596
sl@0
   597
		for (TInt i = 0; i < n; ++i) 
sl@0
   598
			{
sl@0
   599
			LString* s = new(ELeave) LString;
sl@0
   600
			s->FormatL(_L("String %d"), i);
sl@0
   601
			sarray->Append(s);
sl@0
   602
			}
sl@0
   603
sl@0
   604
		for (TInt i = 0, n = sarray->Count(); i < n; ++i) 
sl@0
   605
			{
sl@0
   606
			LString tmp;
sl@0
   607
			tmp.FormatL(_L("String %d"), i);
sl@0
   608
			test(tmp == *(*sarray)[i]);
sl@0
   609
			test.Printf(_L("String %d = %S\n"), i, (*sarray)[i]);
sl@0
   610
			}
sl@0
   611
sl@0
   612
		}
sl@0
   613
sl@0
   614
		{
sl@0
   615
		// Any allocation failure in new(ELeave)LString throws
sl@0
   616
		// KErrNoMemory and cleans up after itself fully
sl@0
   617
sl@0
   618
		__UHEAP_MARK;
sl@0
   619
		//coverity[resource_leak]
sl@0
   620
		//As mentioned in the comment above any allocation failure is taken care of
sl@0
   621
		TRAPD(status, new(ELeave) LString(100 * 1024 * 1024));
sl@0
   622
		test(status == KErrNoMemory);
sl@0
   623
		__UHEAP_MARKEND;
sl@0
   624
		}
sl@0
   625
sl@0
   626
		{
sl@0
   627
		// Native C arrays (both heap and stack allocated) of LStrings
sl@0
   628
		// also work, although their use is not recommended
sl@0
   629
sl@0
   630
		TInt n = 5;
sl@0
   631
		LCleanedupArray<LString> sarray(new(ELeave) LString[n]);
sl@0
   632
sl@0
   633
		for (TInt i = 0; i < n; ++i) 
sl@0
   634
			{
sl@0
   635
			sarray[i].FormatL(_L("String %d"), i);
sl@0
   636
			}
sl@0
   637
sl@0
   638
		for (TInt i = 0; i < n; ++i) 
sl@0
   639
			{
sl@0
   640
			LString tmp;
sl@0
   641
			tmp.FormatL(_L("String %d"), i);
sl@0
   642
			test(tmp == sarray[i]);
sl@0
   643
			test.Printf(_L("String %d = %S\n"), i, &sarray[i]);
sl@0
   644
			}
sl@0
   645
sl@0
   646
		}
sl@0
   647
		{
sl@0
   648
		// 8-bit wide null terminated character string support
sl@0
   649
		
sl@0
   650
		// A default constructed LString8 starts empty, doesn't
sl@0
   651
		// allocate any memory on the heap, and therefore the
sl@0
   652
		// following cannot leave
sl@0
   653
		LString8 s;
sl@0
   654
sl@0
   655
		// But it will grow on demand if you assign to it, so it has
sl@0
   656
		// enough space to hold the copied string data, and so
sl@0
   657
		// assignment may leave
sl@0
   658
		s ="One ";
sl@0
   659
sl@0
   660
		// Similarly if you append to it with the leaving variant of
sl@0
   661
		// Append, AppendL, if may grow on demand
sl@0
   662
		s.AppendL("Two ");
sl@0
   663
sl@0
   664
		// The += operator for LString8 also maps to AppendL
sl@0
   665
		s +="Three ";
sl@0
   666
		s +="Testing ";
sl@0
   667
sl@0
   668
		// An LString8 can be printed the same way as any descriptor
sl@0
   669
		test.Printf(_L("Value: %S \n"), &s);
sl@0
   670
sl@0
   671
		// An LString8 can be compared the same way as any descriptor
sl@0
   672
		test(s == "One Two Three Testing ");
sl@0
   673
sl@0
   674
		// An LString8 supports all TDesC and TDes methods
sl@0
   675
		// LString findToken("Two ");
sl@0
   676
		test(s.Find("Two ") == 4);
sl@0
   677
		
sl@0
   678
		// LString8 matchPattern("*Two* ");
sl@0
   679
		test(s.Match("*Two*") == 4);
sl@0
   680
		test(s.Match("*T?o*") == 4);
sl@0
   681
		
sl@0
   682
		// LString8 compare("some string");
sl@0
   683
		test(s.Compare("One Two Three Testing ") == 0);
sl@0
   684
		test(s.Compare("One Two Three Testing! ") < 0);
sl@0
   685
		test(s.Compare("One Two Testing ") > 0);
sl@0
   686
		
sl@0
   687
		// also LString8 ==,!=,>,<,<=,>=(L"some string");
sl@0
   688
		test(s == "One Two Three Testing ");
sl@0
   689
		test(s < "One Two Three Testing! ");
sl@0
   690
		test(s > "One Two Testing ");
sl@0
   691
		test(s != "not equal");
sl@0
   692
		
sl@0
   693
		// Copies data into this 8-bit string descriptor, replacing any existing
sl@0
   694
		// data, and expanding its heap buffer to accommodate if necessary.
sl@0
   695
		// leaves on not being able to accomodate the new content
sl@0
   696
		// both AssignL and += use CopyL internally
sl@0
   697
		s.CopyL("new way of dealing with strings");
sl@0
   698
		
sl@0
   699
sl@0
   700
		// Copy, Append,Insert,Replace,Justify the same way as TDesC8 and TDes8
sl@0
   701
sl@0
   702
		// Copies data into this 8-bit string descriptor, replacing any existing
sl@0
   703
		// data, and expanding its heap buffer to accommodate if necessary.
sl@0
   704
		// leaves on not being able to accomodate the new content
sl@0
   705
		// both AssignL and += use CopyL internally
sl@0
   706
		s.CopyL("new way of dealing with strings");
sl@0
   707
		s.CopyUCL("new way of dealing with strings");
sl@0
   708
		test(s == "NEW WAY OF DEALING WITH STRINGS");
sl@0
   709
		
sl@0
   710
		// Insert data into this descriptor.
sl@0
   711
		// The length of this descriptor is changed to reflect the extra data.
sl@0
   712
		// This leaving variant of the standard, non-leaving descriptor method
sl@0
   713
		// differs in that this operation may cause the string descriptor's heap
sl@0
   714
		// buffer to be reallocated in order to accommodate the new data. As a
sl@0
   715
		// result, MaxLength() and Ptr() may return different values afterwards,
sl@0
   716
		// and any existing raw pointers to into the descriptor data may be
sl@0
   717
		// invalidated.
sl@0
   718
		s.CopyL("Some Content Can Be Into This String");
sl@0
   719
		s.InsertL(20,"Inserted ");
sl@0
   720
		test(s == "Some Content Can Be Inserted Into This String");
sl@0
   721
		
sl@0
   722
		// Replace data in this descriptor.
sl@0
   723
		// The specified length can be different to the length of the replacement data.
sl@0
   724
		// The length of this descriptor changes to reflect the change of data.
sl@0
   725
		// This leaving variant of the standard, non-leaving descriptor method
sl@0
   726
		// differs in that this operation may cause the string descriptor's heap
sl@0
   727
		// buffer to be reallocated in order to accommodate the new data. As a
sl@0
   728
		// result, MaxLength() and Ptr() may return different values afterwards,
sl@0
   729
		// and any existing raw pointers to into the descriptor data may be
sl@0
   730
		// invalidated.
sl@0
   731
		s.CopyL("Some Content Can Be Decalper");
sl@0
   732
		s.ReplaceL(20,8,"Replaced");
sl@0
   733
		test(s == "Some Content Can Be Replaced");
sl@0
   734
		
sl@0
   735
		// Append data onto the end of this descriptor's data.
sl@0
   736
		// The length of this descriptor is incremented to reflect the new content.
sl@0
   737
		// This leaving variant of the standard, non-leaving descriptor method
sl@0
   738
		// differs in that this operation may cause the string descriptor's heap
sl@0
   739
		// buffer to be reallocated in order to accommodate the new data. As a
sl@0
   740
		// result, MaxLength() and Ptr() may return different values afterwards,
sl@0
   741
		// and any existing raw pointers to into the descriptor data may be
sl@0
   742
		// invalidated.
sl@0
   743
		s.CopyL("Try appending ");
sl@0
   744
		s.AppendL("Try appending some more",3);
sl@0
   745
		test(s == "Try appending Try");
sl@0
   746
		
sl@0
   747
		// Copy data into this descriptor and justifies it, replacing any existing data.
sl@0
   748
		// The length of this descriptor is set to reflect the new data.
sl@0
   749
		// The target area is considered to be an area of specified width positioned at
sl@0
   750
		// the beginning of this descriptor's data area. Source data is copied into, and
sl@0
   751
		// aligned within this target area according to the specified alignment
sl@0
   752
		// instruction.
sl@0
   753
		// If the length of the target area is larger than the length of the source, then
sl@0
   754
		// spare space within the target area is padded with the fill character.
sl@0
   755
		// This leaving variant of the standard, non-leaving descriptor method
sl@0
   756
		// differs in that this operation may cause the string descriptor's heap
sl@0
   757
		// buffer to be reallocated in order to accommodate the new data. As a
sl@0
   758
		// result, MaxLength() and Ptr() may return different values afterwards,
sl@0
   759
		// and any existing raw pointers to into the descriptor data may be
sl@0
   760
		// invalidated.
sl@0
   761
		s.CopyL("Justified");
sl@0
   762
		s.JustifyL("Just",9,ERight,'x');
sl@0
   763
		test(s == "xxxxxJust");
sl@0
   764
		
sl@0
   765
		// Append data onto the end of this descriptor's data and justifies it.
sl@0
   766
		// The source of the appended data is a memory location.
sl@0
   767
		// The target area is considered to be an area of specified width, immediately 
sl@0
   768
		// following this descriptor's existing data. Source data is copied into, and 
sl@0
   769
		// aligned within, this target area according to the specified alignment instruction.
sl@0
   770
		// If the length of the target area is larger than the length of the source, 
sl@0
   771
		// then spare space within the target area is padded with the fill character.
sl@0
   772
		// This leaving variant of the standard, non-leaving descriptor method
sl@0
   773
		// differs in that this operation may cause the string descriptor's heap
sl@0
   774
		// buffer to be reallocated in order to accommodate the new data. As a
sl@0
   775
		// result, MaxLength() and Ptr() may return different values afterwards,
sl@0
   776
		// and any existing raw pointers to into the descriptor data may be
sl@0
   777
		// invalidated.
sl@0
   778
		s.CopyL("One ");
sl@0
   779
		s.AppendJustifyL("Two Three",3,7,ERight,'x');
sl@0
   780
		test(s == "One xxxxTwo" );
sl@0
   781
		
sl@0
   782
		}
sl@0
   783
		
sl@0
   784
	}
sl@0
   785
sl@0
   786
// This class demonstrates the use of the embeddable management
sl@0
   787
// classes in a conventional Symbian two-phase construction
sl@0
   788
// pattern. 
sl@0
   789
class CManagedUserTwoPhase : public CBase
sl@0
   790
	{
sl@0
   791
public:
sl@0
   792
	static CManagedUserTwoPhase* NewL(CTicker* aTicker)
sl@0
   793
		{
sl@0
   794
		// We can use the resource management utility classes in
sl@0
   795
		// two-phase if we want to
sl@0
   796
		LCleanedupPtr<CManagedUserTwoPhase> self(new(ELeave) CManagedUserTwoPhase);
sl@0
   797
		self->ConstructL(aTicker);
sl@0
   798
		// Calling Unmanage() disables cleanup and yields the
sl@0
   799
		// previously managed pointer so that it can be safely
sl@0
   800
		// returned
sl@0
   801
		return self.Unmanage(); 
sl@0
   802
		}
sl@0
   803
sl@0
   804
	~CManagedUserTwoPhase()
sl@0
   805
		{
sl@0
   806
		// The iTicker manager will automatically delete the CTicker
sl@0
   807
		// The iTimer manager will automatically Close() the RTimer
sl@0
   808
		}
sl@0
   809
sl@0
   810
	CTicker& Ticker()
sl@0
   811
		{
sl@0
   812
		// If we dereference the management object we get a CTicker&
sl@0
   813
		return *iTicker;
sl@0
   814
		}
sl@0
   815
sl@0
   816
	RTimer& Timer()
sl@0
   817
		{
sl@0
   818
		// If we dereference the management object we get an RTimer&
sl@0
   819
		return *iTimer;
sl@0
   820
		}
sl@0
   821
sl@0
   822
private:
sl@0
   823
	
sl@0
   824
	virtual void ConstructL(CTicker* aTicker)
sl@0
   825
		{
sl@0
   826
		// Take ownership and manage aTicker 
sl@0
   827
		iTicker = aTicker; 
sl@0
   828
sl@0
   829
		// Note use of -> to indirect through the management wrapper
sl@0
   830
		iTimer->CreateLocal() OR_LEAVE; 
sl@0
   831
		}
sl@0
   832
	
sl@0
   833
	CManagedUserTwoPhase()
sl@0
   834
		{
sl@0
   835
		// Everything interesting happens in ConstructL in this
sl@0
   836
		// version. 
sl@0
   837
sl@0
   838
		// Default initialization of the iName LString does not
sl@0
   839
		// allocate a heap buffer, and so cannot leave. As long as
sl@0
   840
		// initialization is deferred to ConstructL, LStrings can be
sl@0
   841
		// used safely with two-phase construction.
sl@0
   842
		}
sl@0
   843
sl@0
   844
private:
sl@0
   845
	// We have to use LManagedXxx for fields, not LCleanedupXxx
sl@0
   846
	LManagedPtr<CTicker> iTicker;
sl@0
   847
	LManagedHandle<RTimer> iTimer;
sl@0
   848
	};
sl@0
   849
sl@0
   850
// This class demonstrates the use of embedded management classes in
sl@0
   851
// the single-phase construction pattern, where a leave-safe
sl@0
   852
// constructor fully initializes the object.
sl@0
   853
//
sl@0
   854
// Note that where a class's constructor forms part of its exported
sl@0
   855
// public or protected contract, switching from a non-leaving to a
sl@0
   856
// potentially leaving constructor would be a BC break. On the other
sl@0
   857
// hand, if instantiation is entirely encapsulated within factory
sl@0
   858
// functions like NewL, there is no such BC restriction.
sl@0
   859
sl@0
   860
class CManagedUserSinglePhase : public CBase
sl@0
   861
	{
sl@0
   862
public:
sl@0
   863
	// This macro is necessary to ensure cleanup is correctly handled
sl@0
   864
	// in the event that a constructor may leave beneath a call to
sl@0
   865
	// new(ELeave)
sl@0
   866
	CONSTRUCTORS_MAY_LEAVE
sl@0
   867
sl@0
   868
	static CManagedUserSinglePhase* NewL(CTicker* aTicker)
sl@0
   869
		{
sl@0
   870
		return new(ELeave) CManagedUserSinglePhase(aTicker);
sl@0
   871
		}
sl@0
   872
sl@0
   873
	~CManagedUserSinglePhase()
sl@0
   874
		{
sl@0
   875
		// The iTicker manager destructor will automatically Zap() the CTicker
sl@0
   876
		// The iTimer manager destructor will automatically Close() the RTimer
sl@0
   877
		}
sl@0
   878
sl@0
   879
	CTicker& Ticker()
sl@0
   880
		{
sl@0
   881
		// If we dereference the management object we get a CTicker&
sl@0
   882
		return *iTicker;
sl@0
   883
		}
sl@0
   884
sl@0
   885
	RTimer& Timer()
sl@0
   886
		{
sl@0
   887
		// If we dereference the management object we get an RTimer&
sl@0
   888
		return *iTimer;
sl@0
   889
		}
sl@0
   890
sl@0
   891
private:
sl@0
   892
	CManagedUserSinglePhase(CTicker* aTicker)
sl@0
   893
		// Take ownership and manage aTicker. Note that initialization
sl@0
   894
		// of the LManagedXxx classes does not actually leave, but
sl@0
   895
		// initialization of the LCleanedupXxx classes can.
sl@0
   896
		: iTicker(aTicker)
sl@0
   897
		{
sl@0
   898
		// If iTicker initialization is successful but the constructor
sl@0
   899
		// then goes on to leave later, iTicker (like all fields fully
sl@0
   900
		// constructed at the point of a leave in a constructor) will
sl@0
   901
		// be destructed, and the manager will cleanup the CTicker
sl@0
   902
sl@0
   903
		// Note use of -> to indirect through the management wrapper
sl@0
   904
		iTimer->CreateLocal() OR_LEAVE; 
sl@0
   905
sl@0
   906
		// Likewise if we leave here, both iTicker and iTimer will
sl@0
   907
		// undergo managed cleanup
sl@0
   908
		MaybeLeaveL();
sl@0
   909
		}
sl@0
   910
sl@0
   911
private:
sl@0
   912
	// We have to use LManagedXxx for fields, not LCleanedupXxx
sl@0
   913
	LManagedPtr<CTicker, TTickerZapStrategy> iTicker;
sl@0
   914
	LManagedHandle<RTimer> iTimer;
sl@0
   915
	};
sl@0
   916
sl@0
   917
//Class definition of trivial R-Class
sl@0
   918
class RSimple
sl@0
   919
	{
sl@0
   920
public:
sl@0
   921
	
sl@0
   922
	RSimple(){iData = NULL;}
sl@0
   923
	
sl@0
   924
	//Open function sets value
sl@0
   925
	void OpenL(TInt aValue)
sl@0
   926
		{
sl@0
   927
		iData = new(ELeave) TInt(aValue);
sl@0
   928
		}
sl@0
   929
	
sl@0
   930
	//Cleanup function – frees resource
sl@0
   931
	void Close()
sl@0
   932
		{
sl@0
   933
		delete iData;
sl@0
   934
		iData = NULL;
sl@0
   935
		}
sl@0
   936
sl@0
   937
	//Cleanup function – frees resource
sl@0
   938
	void Free()
sl@0
   939
		{
sl@0
   940
		delete iData;
sl@0
   941
		iData = NULL;
sl@0
   942
		}
sl@0
   943
sl@0
   944
	//Cleanup function – frees resource
sl@0
   945
	void ReleaseData()
sl@0
   946
		{
sl@0
   947
		delete iData;
sl@0
   948
		iData = NULL;
sl@0
   949
		}
sl@0
   950
	
sl@0
   951
	//static cleanup function – frees aRSimple resources
sl@0
   952
	static void Cleanup(TAny* aRSimple)
sl@0
   953
		{
sl@0
   954
		static_cast<RSimple*>(aRSimple)->Close();
sl@0
   955
		}
sl@0
   956
sl@0
   957
sl@0
   958
private:
sl@0
   959
	TInt* iData;
sl@0
   960
sl@0
   961
	};
sl@0
   962
sl@0
   963
sl@0
   964
//This sets the default cleanup behaviour for the RSimple class to 
sl@0
   965
//be RSimple::ReleaseData.
sl@0
   966
//If this Macro is not used then the default cleanup behaviour
sl@0
   967
//would be to call RSimple::Close().
sl@0
   968
DEFINE_CLEANUP_FUNCTION(RSimple, ReleaseData);
sl@0
   969
sl@0
   970
sl@0
   971
void WalkthroughManagedL()
sl@0
   972
	{
sl@0
   973
		{
sl@0
   974
		// Trivially exercise the manager-using classes defined above
sl@0
   975
		CTicker* ticker1 = new(ELeave) CTicker;
sl@0
   976
		LCleanedupPtr<CManagedUserTwoPhase> one(CManagedUserTwoPhase::NewL(ticker1));
sl@0
   977
		test(&one->Ticker() == ticker1);
sl@0
   978
		one->Timer().Cancel(); // Just to check we can get at it
sl@0
   979
sl@0
   980
		CTicker* ticker2 = new(ELeave) CTicker;
sl@0
   981
		LCleanedupPtr<CManagedUserSinglePhase> two(CManagedUserSinglePhase::NewL(ticker2));
sl@0
   982
		test(&two->Ticker() == ticker2);
sl@0
   983
		two->Timer().Cancel(); // Just to check we can get at it
sl@0
   984
sl@0
   985
		// Both instances are automatically deleted as we go out of scope
sl@0
   986
		}
sl@0
   987
sl@0
   988
		// Always use LCleanedupXxx for locals, not LManagedXxx
sl@0
   989
sl@0
   990
		{
sl@0
   991
		// Begin the scenes the LCleanedupXxx constructors push a
sl@0
   992
		// cleanup item onto the cleanup stack and so may leave. If
sl@0
   993
		// there is a leave during construction, the supplied pointer
sl@0
   994
		// will still get cleaned up.
sl@0
   995
		LCleanedupPtr<CTicker> t(new(ELeave) CTicker);
sl@0
   996
sl@0
   997
		// We can access CTicker's members via the management object
sl@0
   998
		// using ->
sl@0
   999
		t->Tick();
sl@0
  1000
		t->Tock();
sl@0
  1001
		test(t->iTicks == t->iTocks);
sl@0
  1002
sl@0
  1003
		// We can get at a reference to the managed object using *
sl@0
  1004
		// when we need to, e.g. if we need to pass it to a function
sl@0
  1005
		RegisterTicker(*t); // Takes a CTicker&
sl@0
  1006
sl@0
  1007
		// If some unfriendly interface needs a pointer rather than a
sl@0
  1008
		// ref, we have a couple of options
sl@0
  1009
		RegisterTickerPtr(&*t); // Takes a CTicker*
sl@0
  1010
		RegisterTickerPtr(t.Get()); // Takes a CTicker*
sl@0
  1011
sl@0
  1012
		// Note the use of . in t.Get() above; this distinguishes
sl@0
  1013
		// operations on the managing type from operations on the
sl@0
  1014
		// managed object
sl@0
  1015
		
sl@0
  1016
		// When the management object goes out of scope, either
sl@0
  1017
		// normally or as the result of a leave, the managed object is
sl@0
  1018
		// automatically deleted
sl@0
  1019
		}
sl@0
  1020
sl@0
  1021
		{
sl@0
  1022
		// Sometimes you need to protect something temporarily before
sl@0
  1023
		// transferring ownership e.g. by returning the pointer or
sl@0
  1024
		// passing it to a function that takes ownership.
sl@0
  1025
sl@0
  1026
		LCleanedupPtr<CTicker> t(new(ELeave) CTicker);
sl@0
  1027
sl@0
  1028
		// Protected while we do this
sl@0
  1029
		MaybeLeaveL(); 
sl@0
  1030
sl@0
  1031
		// But now we want to hand it off, so we use Unmanage() to
sl@0
  1032
		// both return a pointer and break the management link
sl@0
  1033
		TakeTickerOwnership(t.Unmanage());
sl@0
  1034
		
sl@0
  1035
		// Now when it goes out of scope, no cleanup action is
sl@0
  1036
		// performed
sl@0
  1037
		}
sl@0
  1038
sl@0
  1039
		{
sl@0
  1040
		// If needed, it is possible to reuse a manager by using = to
sl@0
  1041
		// assign it a new managed object.
sl@0
  1042
sl@0
  1043
		// Not managing anything to start with
sl@0
  1044
		LCleanedupPtr<CTicker> t;
sl@0
  1045
		test(t.Get() == NULL);
sl@0
  1046
		test(&*t == NULL);
sl@0
  1047
sl@0
  1048
		for (TInt i = 0; i < 10; ++i)
sl@0
  1049
			{
sl@0
  1050
			// If an object is already being managed, it is cleaned up
sl@0
  1051
			// before taking ownership of the new object
sl@0
  1052
			t = new(ELeave) CTicker;
sl@0
  1053
			}
sl@0
  1054
		// We're left owning the final ticker instance, all prior
sl@0
  1055
		// instances having been automatically deleted
sl@0
  1056
		}
sl@0
  1057
sl@0
  1058
		{
sl@0
  1059
		// If you have stateful code where a pointer can sometimes be
sl@0
  1060
		// NULL, as a convenience you can test the managing object
sl@0
  1061
		// itself as a shortcut test for NULL
sl@0
  1062
		LCleanedupPtr<CTicker> t(new(ELeave) CTicker);
sl@0
  1063
sl@0
  1064
		// Does t refer to NULL?
sl@0
  1065
		if (!t)
sl@0
  1066
			{
sl@0
  1067
			test(EFalse);
sl@0
  1068
			}
sl@0
  1069
sl@0
  1070
		t = NULL; // Also releases the currently managed CTicker 
sl@0
  1071
sl@0
  1072
		// Does t refer to a non-NULL pointer?
sl@0
  1073
		if (t)
sl@0
  1074
			{
sl@0
  1075
			test(EFalse);
sl@0
  1076
			}
sl@0
  1077
		}
sl@0
  1078
sl@0
  1079
		{
sl@0
  1080
		// LCleanedupPtr uses delete to cleanup by default, but
sl@0
  1081
		// alternative cleanups can be specified
sl@0
  1082
sl@0
  1083
		// We just want to free this one and not invoke the destructor
sl@0
  1084
		LCleanedupPtr<CTicker, TPointerFree> t(static_cast<CTicker*>(User::AllocL(sizeof(CTicker))));
sl@0
  1085
sl@0
  1086
		// Now User::Free() is called when t goes out of scope
sl@0
  1087
		}
sl@0
  1088
sl@0
  1089
		{
sl@0
  1090
		// As well as the stock options, custom cleanup policies can
sl@0
  1091
		// also be defined. See above for the definition of
sl@0
  1092
		// TTickerZap.
sl@0
  1093
		LCleanedupPtr<CTicker, TTickerZapStrategy> t(new(ELeave) CTicker);
sl@0
  1094
sl@0
  1095
		// Now Zap() is called on the CTicker instance when t goes out of scope
sl@0
  1096
		}
sl@0
  1097
sl@0
  1098
		{
sl@0
  1099
		// LCleanedupHandle is very similar in behaviour to
sl@0
  1100
		// LCleanedupPtr, the main difference being that it can define
sl@0
  1101
		// and contain its own instance of a handle rather than
sl@0
  1102
		// being supplied one
sl@0
  1103
		LCleanedupHandle<RTimer> t;
sl@0
  1104
sl@0
  1105
		// Again, access to managed handle members is via ->
sl@0
  1106
		t->CreateLocal() OR_LEAVE;
sl@0
  1107
		t->Cancel();
sl@0
  1108
sl@0
  1109
		// We can get a reference to the handle for passing to
sl@0
  1110
		// functions using *
sl@0
  1111
		RegisterTimer(*t);
sl@0
  1112
sl@0
  1113
		// When the management object goes out of scope, either
sl@0
  1114
		// normally or as the result of a leave, the managed object is
sl@0
  1115
		// automatically cleanup by calling Close() on it
sl@0
  1116
		}
sl@0
  1117
sl@0
  1118
		{
sl@0
  1119
		// LCleanedupHandle calls Close() by default, but alternative
sl@0
  1120
		// cleanups can be specified
sl@0
  1121
		
sl@0
  1122
		// We want this RPointerArray cleanup with with
sl@0
  1123
		// ResetAndDestroy instead of Close()
sl@0
  1124
		LCleanedupHandle<RPointerArray<HBufC>, TResetAndDestroy> array;
sl@0
  1125
		for (TInt i = 0; i < 10; ++i) 
sl@0
  1126
			{
sl@0
  1127
			array->AppendL(HBufC::NewL(5));
sl@0
  1128
			}
sl@0
  1129
sl@0
  1130
		// Now when array goes out of scope, ResetAndDestroy is called
sl@0
  1131
		// to clean it up
sl@0
  1132
		}
sl@0
  1133
sl@0
  1134
		{
sl@0
  1135
		// As well as the stock options, custom cleanup policies can
sl@0
  1136
		// also be defined. See above for the definition of
sl@0
  1137
		// TCancelClose.
sl@0
  1138
		LCleanedupHandle<RTimer, TCancelClose> t;
sl@0
  1139
		t->CreateLocal();
sl@0
  1140
sl@0
  1141
		// Now Cancel() followed by Close() are called when t goes out
sl@0
  1142
		// of scope
sl@0
  1143
		}
sl@0
  1144
sl@0
  1145
sl@0
  1146
		{
sl@0
  1147
		// LCleanedupHandleRef calls Close() by default, but alternative
sl@0
  1148
		// cleanups can be specified
sl@0
  1149
		
sl@0
  1150
		// We want this RPointerArray cleanup with with
sl@0
  1151
		// ResetAndDestroy instead of Close()
sl@0
  1152
		RPointerArray<HBufC> rar;
sl@0
  1153
		// calls to functions that cannot leave here
sl@0
  1154
		rar.Append(HBufC::NewL(5));
sl@0
  1155
		rar.Append(HBufC::NewL(5));
sl@0
  1156
sl@0
  1157
sl@0
  1158
		LCleanedupRef<RPointerArray<HBufC>, TResetAndDestroy> array(rar);
sl@0
  1159
		// calls to functions that could leave here
sl@0
  1160
		for (TInt i = 0; i < 10; ++i) 
sl@0
  1161
			{
sl@0
  1162
			array->AppendL(HBufC::NewL(5));
sl@0
  1163
			}
sl@0
  1164
sl@0
  1165
		// Now when array goes out of scope, ResetAndDestroy is called
sl@0
  1166
		// to clean it up
sl@0
  1167
		}
sl@0
  1168
sl@0
  1169
		{
sl@0
  1170
		// Never mix direct cleanup stack API calls with management
sl@0
  1171
		// class use within the same function, because their
sl@0
  1172
		// interaction can be confusing and counter intuitive. Avoid
sl@0
  1173
		// the use of LC methods that leave objects on the cleanup
sl@0
  1174
		// stack, and use L methods instead.
sl@0
  1175
sl@0
  1176
		// If a badly-behaved API were to offer only an LC variant,
sl@0
  1177
		// you would have to use it as follows
sl@0
  1178
		HBufC* raw = HBufC::NewLC(5);
sl@0
  1179
		// Must pop immediately to balance the cleanup stack, before
sl@0
  1180
		// instantiating the manager
sl@0
  1181
		CleanupStack::Pop(); 
sl@0
  1182
		LCleanedupPtr<HBufC> wrapped(raw);
sl@0
  1183
sl@0
  1184
		// Never do this:
sl@0
  1185
		//LCleanedupPtr<HBufC> buf(HBufC::NewLC(5));
sl@0
  1186
		//CleanupStack::Pop();
sl@0
  1187
		// because the manager will be popped (having been pushed
sl@0
  1188
		// last), not the raw buf pointer as you might have hoped
sl@0
  1189
sl@0
  1190
		// A cleaner alternative may be to write your own L function
sl@0
  1191
		// wrapper around the LC function supplied.
sl@0
  1192
sl@0
  1193
		// Luckily this situation (an LC method without a
sl@0
  1194
		// corresponding L method) is rare in practice.
sl@0
  1195
		}
sl@0
  1196
sl@0
  1197
		{
sl@0
  1198
		// Although rarely used on Symbian OS, C++ arrays are
sl@0
  1199
		// supported with a custom management class
sl@0
  1200
		LCleanedupArray<CTicker> array(new CTicker[5]);
sl@0
  1201
sl@0
  1202
		// The array is cleaned up with delete[] on scope exit
sl@0
  1203
		}
sl@0
  1204
sl@0
  1205
		{
sl@0
  1206
		// Although most cases are best covered by applying custom
sl@0
  1207
		// cleanup policies to the management classes already
sl@0
  1208
		// described, there is also a general TCleanupItem style
sl@0
  1209
		// cleanup option
sl@0
  1210
		TAny* data = NULL; // But could be anything
sl@0
  1211
		LCleanedupGuard guard1(BespokeCleanupFunction, data);
sl@0
  1212
		// On scope exit BespokeCleanupFunction is called on data
sl@0
  1213
sl@0
  1214
		LCleanedupGuard guard2(BespokeCleanupFunction, data);
sl@0
  1215
		// But cleanup can also be disabled in this case, as follows
sl@0
  1216
		guard2.Dismiss();
sl@0
  1217
		}
sl@0
  1218
		
sl@0
  1219
		{
sl@0
  1220
		TInt r =KErrNone;	
sl@0
  1221
		LCleanedupHandle<RFs> managedFs;
sl@0
  1222
		r = managedFs->Connect();
sl@0
  1223
		if (r != KErrNone)
sl@0
  1224
		 {
sl@0
  1225
			User::Leave(r);
sl@0
  1226
		 }
sl@0
  1227
		//default cleanup strategy is to call RFs::Close() on scope exit
sl@0
  1228
		}
sl@0
  1229
		
sl@0
  1230
		{
sl@0
  1231
		LCleanedupHandle<RSimple, TFree> simple;
sl@0
  1232
		simple->OpenL(23);
sl@0
  1233
		//Specified cleanup strategy is to call RSimple::Free() on scope exit
sl@0
  1234
		}
sl@0
  1235
	
sl@0
  1236
		//Because the DEFINE_CLEANUP_FUNCTION is defined above, the default
sl@0
  1237
		//cleanup function for RSimple is RSimple::ReleaseData() rather than
sl@0
  1238
		//RSimple::Close()
sl@0
  1239
		{
sl@0
  1240
		LCleanedupHandle<RSimple> simple;
sl@0
  1241
		simple->OpenL(23);
sl@0
  1242
		//Custom cleanup strategy is to call RSimple::ReleaseData() on scope exit
sl@0
  1243
		}
sl@0
  1244
		
sl@0
  1245
		{
sl@0
  1246
		RSimple simple;
sl@0
  1247
		
sl@0
  1248
		//The RSimple class above defines a static cleanup function
sl@0
  1249
		//RSimple::Cleanup.
sl@0
  1250
		LCleanedupGuard guard(RSimple::Cleanup, &simple);
sl@0
  1251
sl@0
  1252
		simple.OpenL(10);
sl@0
  1253
		
sl@0
  1254
		//On scope exit RSimple::Cleanup() is called passing &simple
sl@0
  1255
		}
sl@0
  1256
	}
sl@0
  1257
sl@0
  1258
void WalkthroughUsageL()
sl@0
  1259
	{
sl@0
  1260
	RFile file;
sl@0
  1261
	
sl@0
  1262
	test.Printf(_L("Size of RFile = %d"), sizeof(file));
sl@0
  1263
	
sl@0
  1264
	LCleanedupHandle<RFile> cFile;
sl@0
  1265
	
sl@0
  1266
	test.Printf(_L("Size of LCleanedupHandle<RFile> = %d"), sizeof(cFile));
sl@0
  1267
	
sl@0
  1268
	LCleanedupRef<RFile> crFile(file);
sl@0
  1269
	
sl@0
  1270
	test.Printf(_L("Size of LCleanedupRef<RFile> = %d"), sizeof(crFile));
sl@0
  1271
	
sl@0
  1272
	CTicker* tracker = new(ELeave) CTicker;
sl@0
  1273
	//coverity[resource_leak]
sl@0
  1274
	//As mentioned in the comment above any allocation failure is taken care of
sl@0
  1275
	test.Printf(_L("Size of CTracker* = %d"), sizeof(tracker));
sl@0
  1276
	
sl@0
  1277
	LCleanedupPtr<CTicker> cTracker(tracker);
sl@0
  1278
	
sl@0
  1279
	test.Printf(_L("Size of LCleanedupHandle<RFile> = %d"), sizeof(LCleanedupPtr<CTicker>));
sl@0
  1280
	}
sl@0
  1281
sl@0
  1282
TInt TestL()
sl@0
  1283
	{
sl@0
  1284
	WalkthroughStringsL();
sl@0
  1285
	WalkthroughManagedL();
sl@0
  1286
	WalkthroughUsageL();
sl@0
  1287
sl@0
  1288
	return KErrNone;
sl@0
  1289
	}
sl@0
  1290
sl@0
  1291
TInt E32Main()
sl@0
  1292
	{
sl@0
  1293
sl@0
  1294
	test.Start(_L("EUserHl Walkthrough"));
sl@0
  1295
	test.Title();
sl@0
  1296
sl@0
  1297
	CTrapCleanup* trapHandler=CTrapCleanup::New();
sl@0
  1298
	test(trapHandler!=NULL);
sl@0
  1299
	
sl@0
  1300
	__UHEAP_MARK;
sl@0
  1301
	
sl@0
  1302
	TRAPD(status, TestL());
sl@0
  1303
	
sl@0
  1304
	__UHEAP_MARKEND;
sl@0
  1305
sl@0
  1306
	if (status != KErrNone) test.Printf(_L("Error: %d\n"), status);
sl@0
  1307
	
sl@0
  1308
	test.Printf(_L("Test Completed with Error: %d"),status);
sl@0
  1309
	
sl@0
  1310
	return status;
sl@0
  1311
	}
sl@0
  1312
sl@0
  1313
sl@0
  1314
// eof