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
|