sl@0
|
1 |
// Copyright (c) 1998-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 "US_STD.H"
|
sl@0
|
17 |
|
sl@0
|
18 |
// Class RClusterMap
|
sl@0
|
19 |
|
sl@0
|
20 |
void RClusterMap::InsertL( TClusterId aCluster, TClusterId aPrevious )
|
sl@0
|
21 |
//
|
sl@0
|
22 |
// insert the entry into the map
|
sl@0
|
23 |
//
|
sl@0
|
24 |
{
|
sl@0
|
25 |
TIdPair* map = iMap;
|
sl@0
|
26 |
if ( iEntries == iAlloc )
|
sl@0
|
27 |
{ // ensure there is space
|
sl@0
|
28 |
TInt size = iAlloc + EGranularity;
|
sl@0
|
29 |
iMap = map = ( TIdPair* )User::ReAllocL( map, size * sizeof( TIdPair ) );
|
sl@0
|
30 |
iAlloc = size;
|
sl@0
|
31 |
}
|
sl@0
|
32 |
TInt l = 0;
|
sl@0
|
33 |
TInt r = iEntries;
|
sl@0
|
34 |
while ( r > l )
|
sl@0
|
35 |
{
|
sl@0
|
36 |
TInt m = ( l + r ) >> 1;
|
sl@0
|
37 |
TClusterId id = map[ m ].iId;
|
sl@0
|
38 |
__ASSERT( aCluster != id ); // not already present
|
sl@0
|
39 |
if ( aCluster < id )
|
sl@0
|
40 |
r = m;
|
sl@0
|
41 |
else
|
sl@0
|
42 |
l = m + 1;
|
sl@0
|
43 |
}
|
sl@0
|
44 |
TIdPair* p = map + r;
|
sl@0
|
45 |
TIdPair* e = map + iEntries++;
|
sl@0
|
46 |
Mem::Move( p + 1, p, ( TUint8* )e - ( TUint8* )p );
|
sl@0
|
47 |
p->iId = aCluster;
|
sl@0
|
48 |
p->iPreviousId = aPrevious;
|
sl@0
|
49 |
}
|
sl@0
|
50 |
|
sl@0
|
51 |
RClusterMap::TIdPair* RClusterMap::At( TClusterId aCluster )
|
sl@0
|
52 |
{
|
sl@0
|
53 |
TInt l = 0;
|
sl@0
|
54 |
TInt r = iEntries;
|
sl@0
|
55 |
while ( r > l )
|
sl@0
|
56 |
{
|
sl@0
|
57 |
TInt m = ( l + r ) >> 1;
|
sl@0
|
58 |
TClusterId id = iMap[ m ].iId;
|
sl@0
|
59 |
if ( aCluster < id )
|
sl@0
|
60 |
r = m;
|
sl@0
|
61 |
else if ( aCluster > id )
|
sl@0
|
62 |
l = m + 1;
|
sl@0
|
63 |
else
|
sl@0
|
64 |
return iMap + m;
|
sl@0
|
65 |
}
|
sl@0
|
66 |
return 0;
|
sl@0
|
67 |
}
|
sl@0
|
68 |
|
sl@0
|
69 |
void RClusterMap::ResetL( TClusterId aHeadCluster )
|
sl@0
|
70 |
{
|
sl@0
|
71 |
iComplete = EFalse;
|
sl@0
|
72 |
iEntries = 0;
|
sl@0
|
73 |
InsertL( aHeadCluster, KNullClusterId );
|
sl@0
|
74 |
iLastMapped = iLastBound = aHeadCluster;
|
sl@0
|
75 |
iSkipped = ESeparation - 1;
|
sl@0
|
76 |
}
|
sl@0
|
77 |
|
sl@0
|
78 |
TBool RClusterMap::At( TClusterId aCluster, TClusterId& aPreviousCluster )
|
sl@0
|
79 |
{
|
sl@0
|
80 |
TIdPair* p = At( aCluster );
|
sl@0
|
81 |
if ( p )
|
sl@0
|
82 |
aPreviousCluster = p->iPreviousId;
|
sl@0
|
83 |
else if ( aCluster == iLastBound )
|
sl@0
|
84 |
aPreviousCluster = iLastMapped;
|
sl@0
|
85 |
else
|
sl@0
|
86 |
return EFalse;
|
sl@0
|
87 |
return ETrue;
|
sl@0
|
88 |
}
|
sl@0
|
89 |
|
sl@0
|
90 |
void RClusterMap::AddL( TClusterId aCluster )
|
sl@0
|
91 |
{
|
sl@0
|
92 |
__ASSERT( aCluster != KNullClusterId );
|
sl@0
|
93 |
if ( --iSkipped < 0 )
|
sl@0
|
94 |
{
|
sl@0
|
95 |
InsertL( aCluster, iLastMapped );
|
sl@0
|
96 |
iLastMapped = aCluster;
|
sl@0
|
97 |
iSkipped = ESeparation - 1;
|
sl@0
|
98 |
}
|
sl@0
|
99 |
iLastBound = aCluster;
|
sl@0
|
100 |
}
|
sl@0
|
101 |
|
sl@0
|
102 |
void RClusterMap::DropL( TClusterId aCluster, TClusterId aNext )
|
sl@0
|
103 |
//
|
sl@0
|
104 |
// Cluster has been deleted, modify entry to contain the next cluster
|
sl@0
|
105 |
// last cluster in table is never deleted
|
sl@0
|
106 |
//
|
sl@0
|
107 |
{
|
sl@0
|
108 |
if ( aCluster == iLastBound )
|
sl@0
|
109 |
iLastBound = aNext;
|
sl@0
|
110 |
TIdPair* entry = At( aCluster );
|
sl@0
|
111 |
if ( !entry )
|
sl@0
|
112 |
return; // not in the sparse map
|
sl@0
|
113 |
// remove entry for cluster->prev
|
sl@0
|
114 |
TClusterId prev = entry->iPreviousId;
|
sl@0
|
115 |
Mem::Move( entry, entry + 1, ( TUint8* )( iMap + --iEntries ) - ( TUint8* )entry );
|
sl@0
|
116 |
//
|
sl@0
|
117 |
if ( aCluster == iLastMapped )
|
sl@0
|
118 |
iLastMapped = aNext;
|
sl@0
|
119 |
else
|
sl@0
|
120 |
{ // find the referring entry next->cluster
|
sl@0
|
121 |
TIdPair* pnext = iMap;
|
sl@0
|
122 |
while ( pnext->iPreviousId != aCluster )
|
sl@0
|
123 |
{
|
sl@0
|
124 |
++pnext;
|
sl@0
|
125 |
__ASSERT( pnext < iMap + iEntries );
|
sl@0
|
126 |
}
|
sl@0
|
127 |
if ( pnext->iId == aNext )
|
sl@0
|
128 |
{ // referring entry is the next one => drop a link
|
sl@0
|
129 |
pnext->iPreviousId = prev;
|
sl@0
|
130 |
return;
|
sl@0
|
131 |
}
|
sl@0
|
132 |
// adjust next->new
|
sl@0
|
133 |
pnext->iPreviousId = aNext;
|
sl@0
|
134 |
}
|
sl@0
|
135 |
// add in new link to replace deleted one
|
sl@0
|
136 |
InsertL( aNext, prev ); // will not fail allocation as space available
|
sl@0
|
137 |
}
|
sl@0
|
138 |
|
sl@0
|
139 |
// Class TClusterLinkCache
|
sl@0
|
140 |
|
sl@0
|
141 |
void TClusterLinkCache::Add( TClusterId aCluster, RClusterMap& aMap )
|
sl@0
|
142 |
//
|
sl@0
|
143 |
// Add an entry to the cache
|
sl@0
|
144 |
//
|
sl@0
|
145 |
{
|
sl@0
|
146 |
__ASSERT( iEnd != NULL );
|
sl@0
|
147 |
TClusterId id;
|
sl@0
|
148 |
__ASSERT( aMap.At( iMap[0], id ) );
|
sl@0
|
149 |
//
|
sl@0
|
150 |
TClusterId* p = iEnd;
|
sl@0
|
151 |
if ( p == &iMap[ RClusterMap::ESeparation ] )
|
sl@0
|
152 |
{ // full, requires a shift down
|
sl@0
|
153 |
for ( ; !aMap.At( *p, id ); --p )
|
sl@0
|
154 |
{
|
sl@0
|
155 |
__ASSERT( p > iMap );
|
sl@0
|
156 |
}
|
sl@0
|
157 |
__ASSERT( p > iMap );
|
sl@0
|
158 |
__ASSERT( Has( id ) );
|
sl@0
|
159 |
|
sl@0
|
160 |
TClusterId* c = iMap;
|
sl@0
|
161 |
--c;
|
sl@0
|
162 |
while ( p <= iEnd )
|
sl@0
|
163 |
*++c = *p++;
|
sl@0
|
164 |
p = c;
|
sl@0
|
165 |
}
|
sl@0
|
166 |
*++p = aCluster;
|
sl@0
|
167 |
iEnd = p;
|
sl@0
|
168 |
}
|
sl@0
|
169 |
|
sl@0
|
170 |
void TClusterLinkCache::Add( const TClusterId* aFirst, const TClusterId* aLast )
|
sl@0
|
171 |
//
|
sl@0
|
172 |
// Add several linked TClusterIds
|
sl@0
|
173 |
//
|
sl@0
|
174 |
{
|
sl@0
|
175 |
__ASSERT( iEnd != NULL );
|
sl@0
|
176 |
//
|
sl@0
|
177 |
TClusterId* p = iEnd;
|
sl@0
|
178 |
while ( aFirst < aLast && p < &iMap[ RClusterMap::ESeparation ] )
|
sl@0
|
179 |
*++p = *aFirst++;
|
sl@0
|
180 |
iEnd = p;
|
sl@0
|
181 |
}
|
sl@0
|
182 |
|
sl@0
|
183 |
void TClusterLinkCache::Drop( TClusterId aCluster, TClusterId aNext )
|
sl@0
|
184 |
//
|
sl@0
|
185 |
// Drop the item if it is in the cache
|
sl@0
|
186 |
//
|
sl@0
|
187 |
{
|
sl@0
|
188 |
TClusterId* p = iEnd;
|
sl@0
|
189 |
if ( !p )
|
sl@0
|
190 |
return;
|
sl@0
|
191 |
if ( *p == aCluster )
|
sl@0
|
192 |
{
|
sl@0
|
193 |
*p = aNext;
|
sl@0
|
194 |
return;
|
sl@0
|
195 |
}
|
sl@0
|
196 |
do
|
sl@0
|
197 |
{
|
sl@0
|
198 |
if ( p == iMap )
|
sl@0
|
199 |
return;
|
sl@0
|
200 |
} while ( *--p != aCluster );
|
sl@0
|
201 |
__ASSERT( *( p + 1 ) == aNext );
|
sl@0
|
202 |
for ( ; p < iEnd; ++p )
|
sl@0
|
203 |
*p = *( p + 1 );
|
sl@0
|
204 |
iEnd = p - 1;
|
sl@0
|
205 |
}
|
sl@0
|
206 |
|
sl@0
|
207 |
TBool TClusterLinkCache::Has( TClusterId aCluster ) const
|
sl@0
|
208 |
//
|
sl@0
|
209 |
// Check if the cluster id is in the cache
|
sl@0
|
210 |
// iEnd==0 is a valid state (empty cache)
|
sl@0
|
211 |
//
|
sl@0
|
212 |
{
|
sl@0
|
213 |
for ( const TClusterId* p = iEnd; p >= iMap; )
|
sl@0
|
214 |
{
|
sl@0
|
215 |
if ( *p-- == aCluster )
|
sl@0
|
216 |
return ETrue;
|
sl@0
|
217 |
}
|
sl@0
|
218 |
return EFalse;
|
sl@0
|
219 |
}
|
sl@0
|
220 |
|
sl@0
|
221 |
TBool TClusterLinkCache::At( TClusterId aCluster, TClusterId& aPrevious ) const
|
sl@0
|
222 |
//
|
sl@0
|
223 |
// If aCluster is in the cache, return the previous cluster in aPrevious
|
sl@0
|
224 |
// iEnd==0 is a valid state (empty cache)
|
sl@0
|
225 |
//
|
sl@0
|
226 |
{
|
sl@0
|
227 |
for ( const TClusterId* p = iEnd; p > iMap; )
|
sl@0
|
228 |
{
|
sl@0
|
229 |
if ( *p-- == aCluster )
|
sl@0
|
230 |
{
|
sl@0
|
231 |
aPrevious = *p;
|
sl@0
|
232 |
return ETrue;
|
sl@0
|
233 |
}
|
sl@0
|
234 |
}
|
sl@0
|
235 |
return EFalse;
|
sl@0
|
236 |
}
|
sl@0
|
237 |
|
sl@0
|
238 |
// Class TClusterDes
|
sl@0
|
239 |
|
sl@0
|
240 |
void TClusterDes::InternalizeL(RReadStream& aStream)
|
sl@0
|
241 |
{
|
sl@0
|
242 |
aStream>>iNext;
|
sl@0
|
243 |
iMembership=aStream.ReadUint16L();
|
sl@0
|
244 |
}
|
sl@0
|
245 |
|
sl@0
|
246 |
void TClusterDes::ExternalizeL(RWriteStream& aStream) const
|
sl@0
|
247 |
{
|
sl@0
|
248 |
aStream<<iNext;
|
sl@0
|
249 |
aStream.WriteUint16L(iMembership);
|
sl@0
|
250 |
}
|
sl@0
|
251 |
|
sl@0
|
252 |
|
sl@0
|
253 |
// Class CClusterCache
|
sl@0
|
254 |
|
sl@0
|
255 |
inline CClusterCache::CClusterCache(CDbStoreDatabase& aDatabase)
|
sl@0
|
256 |
: iDatabase(aDatabase),iCache(_FOFF(CCluster,iLink))
|
sl@0
|
257 |
{}
|
sl@0
|
258 |
|
sl@0
|
259 |
CClusterCache* CClusterCache::NewL(CDbStoreDatabase& aDatabase)
|
sl@0
|
260 |
{
|
sl@0
|
261 |
CClusterCache* self=new(ELeave) CClusterCache(aDatabase);
|
sl@0
|
262 |
CleanupStack::PushL(self);
|
sl@0
|
263 |
// Add the initial clusters
|
sl@0
|
264 |
for(TInt i=0;i<(EMaxClusters/2);++i)
|
sl@0
|
265 |
{
|
sl@0
|
266 |
self->AddClusterL();
|
sl@0
|
267 |
}
|
sl@0
|
268 |
CleanupStack::Pop();
|
sl@0
|
269 |
return self;
|
sl@0
|
270 |
}
|
sl@0
|
271 |
|
sl@0
|
272 |
LOCAL_C void DeleteCluster(CCluster* aCluster)
|
sl@0
|
273 |
//
|
sl@0
|
274 |
// helper function which matches the Apply() prototype
|
sl@0
|
275 |
//
|
sl@0
|
276 |
{
|
sl@0
|
277 |
delete aCluster;
|
sl@0
|
278 |
}
|
sl@0
|
279 |
|
sl@0
|
280 |
CClusterCache::~CClusterCache()
|
sl@0
|
281 |
{
|
sl@0
|
282 |
Apply(DeleteCluster);
|
sl@0
|
283 |
}
|
sl@0
|
284 |
|
sl@0
|
285 |
LOCAL_C void DiscardCluster(CCluster* aCluster)
|
sl@0
|
286 |
//
|
sl@0
|
287 |
// helper function which matches the Apply() prototype
|
sl@0
|
288 |
//
|
sl@0
|
289 |
{
|
sl@0
|
290 |
aCluster->Discard();
|
sl@0
|
291 |
}
|
sl@0
|
292 |
|
sl@0
|
293 |
void CClusterCache::Discard()
|
sl@0
|
294 |
//
|
sl@0
|
295 |
// discard the current changes in all clusters
|
sl@0
|
296 |
//
|
sl@0
|
297 |
{
|
sl@0
|
298 |
Apply(DiscardCluster);
|
sl@0
|
299 |
}
|
sl@0
|
300 |
|
sl@0
|
301 |
LOCAL_C void FlushClusterL(CCluster* aCluster)
|
sl@0
|
302 |
//
|
sl@0
|
303 |
// helper function which matches the Apply() prototype
|
sl@0
|
304 |
//
|
sl@0
|
305 |
{
|
sl@0
|
306 |
aCluster->FlushL();
|
sl@0
|
307 |
}
|
sl@0
|
308 |
|
sl@0
|
309 |
void CClusterCache::FlushL()
|
sl@0
|
310 |
//
|
sl@0
|
311 |
// Flush all the clusters in the cache
|
sl@0
|
312 |
//
|
sl@0
|
313 |
{
|
sl@0
|
314 |
Apply(FlushClusterL);
|
sl@0
|
315 |
}
|
sl@0
|
316 |
|
sl@0
|
317 |
CCluster* CClusterCache::Cluster(TClusterId aCluster)
|
sl@0
|
318 |
//
|
sl@0
|
319 |
// Look for a cluster in the cache
|
sl@0
|
320 |
//
|
sl@0
|
321 |
{
|
sl@0
|
322 |
TDblQueIter<CCluster> iter(iCache);
|
sl@0
|
323 |
for (CCluster* cluster;(cluster=iter++)!=0;)
|
sl@0
|
324 |
{
|
sl@0
|
325 |
if (cluster->Id()==aCluster)
|
sl@0
|
326 |
return cluster;
|
sl@0
|
327 |
}
|
sl@0
|
328 |
return 0;
|
sl@0
|
329 |
}
|
sl@0
|
330 |
|
sl@0
|
331 |
CCluster& CClusterCache::ClusterL(TClusterId aCluster)
|
sl@0
|
332 |
//
|
sl@0
|
333 |
// Get a cluster from the cache or store and move it to the top of the cache
|
sl@0
|
334 |
// Track hits to the two clusters which most recently dropped out of the cache
|
sl@0
|
335 |
//
|
sl@0
|
336 |
{
|
sl@0
|
337 |
CCluster* cluster=Cluster(aCluster); // check if it is cached
|
sl@0
|
338 |
iFollowOnHits<<=2;
|
sl@0
|
339 |
if (!cluster)
|
sl@0
|
340 |
{ // get an empty cluster and read it
|
sl@0
|
341 |
if (aCluster==iCachePlus1)
|
sl@0
|
342 |
{ // the cluster has recently been discarded
|
sl@0
|
343 |
iCachePlus1=iCachePlus2; // re-sequence the cache follow-on
|
sl@0
|
344 |
iFollowOnHits|=0x1;
|
sl@0
|
345 |
}
|
sl@0
|
346 |
else if (aCluster==iCachePlus2)
|
sl@0
|
347 |
iFollowOnHits|=0x2; // the cluster has recently been discarded
|
sl@0
|
348 |
cluster=&NewClusterL();
|
sl@0
|
349 |
cluster->ReadL(aCluster);
|
sl@0
|
350 |
}
|
sl@0
|
351 |
return Touch(*cluster);
|
sl@0
|
352 |
}
|
sl@0
|
353 |
|
sl@0
|
354 |
CCluster& CClusterCache::ClusterL()
|
sl@0
|
355 |
//
|
sl@0
|
356 |
// Get a new (empty) cluster from the cache and move it to the top
|
sl@0
|
357 |
//
|
sl@0
|
358 |
{
|
sl@0
|
359 |
return Touch(NewClusterL());
|
sl@0
|
360 |
}
|
sl@0
|
361 |
|
sl@0
|
362 |
CCluster& CClusterCache::Touch(CCluster& aCluster)
|
sl@0
|
363 |
//
|
sl@0
|
364 |
// Move a cluster to the top of the LRU list
|
sl@0
|
365 |
//
|
sl@0
|
366 |
{
|
sl@0
|
367 |
aCluster.iLink.Deque();
|
sl@0
|
368 |
iCache.AddFirst(aCluster);
|
sl@0
|
369 |
return aCluster;
|
sl@0
|
370 |
}
|
sl@0
|
371 |
|
sl@0
|
372 |
CCluster& CClusterCache::AddClusterL()
|
sl@0
|
373 |
//
|
sl@0
|
374 |
// Add a new cluster to the cache
|
sl@0
|
375 |
//
|
sl@0
|
376 |
{
|
sl@0
|
377 |
__ASSERT(iClusters<EMaxClusters);
|
sl@0
|
378 |
CCluster& cluster=*CCluster::NewL(Database());
|
sl@0
|
379 |
iCache.AddLast(cluster);
|
sl@0
|
380 |
++iClusters;
|
sl@0
|
381 |
// move +2 hits into +1 zone and clear +1 hits
|
sl@0
|
382 |
iFollowOnHits=TUint8((TUint(iFollowOnHits)>>1)&0x55);
|
sl@0
|
383 |
return cluster;
|
sl@0
|
384 |
}
|
sl@0
|
385 |
|
sl@0
|
386 |
CCluster& CClusterCache::NewClusterL()
|
sl@0
|
387 |
//
|
sl@0
|
388 |
// Get an empty cluster from the cache, but do not touch it
|
sl@0
|
389 |
// If the hit detector has registered enough near-misses the cache is expanded
|
sl@0
|
390 |
// by adding another cluster object
|
sl@0
|
391 |
//
|
sl@0
|
392 |
{
|
sl@0
|
393 |
CCluster* cluster=Cluster(KNullClusterId); // look for a discarded cluster first
|
sl@0
|
394 |
if (cluster)
|
sl@0
|
395 |
return *cluster;
|
sl@0
|
396 |
// check for cache expansion
|
sl@0
|
397 |
TUint detected=iFollowOnHits;
|
sl@0
|
398 |
if ((detected&(detected-1))!=0 && iClusters<EMaxClusters)
|
sl@0
|
399 |
return AddClusterL();
|
sl@0
|
400 |
// retire the last cache entry
|
sl@0
|
401 |
cluster=iCache.Last();
|
sl@0
|
402 |
cluster->FlushL();
|
sl@0
|
403 |
iCachePlus2=iCachePlus1;
|
sl@0
|
404 |
iCachePlus1=cluster->Id();
|
sl@0
|
405 |
return *cluster;
|
sl@0
|
406 |
}
|
sl@0
|
407 |
|
sl@0
|
408 |
void CClusterCache::Apply(void (*aFunc)(CCluster*))
|
sl@0
|
409 |
//
|
sl@0
|
410 |
// Apply the function paramater to all clusters in the cache
|
sl@0
|
411 |
// This function may leave <==> the parameter function may leave
|
sl@0
|
412 |
//
|
sl@0
|
413 |
{
|
sl@0
|
414 |
TDblQueIter<CCluster> iter(iCache);
|
sl@0
|
415 |
for (CCluster* cluster;(cluster=iter++)!=0;)
|
sl@0
|
416 |
aFunc(cluster);
|
sl@0
|
417 |
}
|
sl@0
|
418 |
|
sl@0
|
419 |
// Class CCluster
|
sl@0
|
420 |
|
sl@0
|
421 |
CCluster* CCluster::NewL(CDbStoreDatabase& aDatabase)
|
sl@0
|
422 |
{
|
sl@0
|
423 |
return new(ELeave) CCluster(aDatabase);
|
sl@0
|
424 |
}
|
sl@0
|
425 |
|
sl@0
|
426 |
CCluster::~CCluster()
|
sl@0
|
427 |
{
|
sl@0
|
428 |
User::Free(iMap[0]);
|
sl@0
|
429 |
}
|
sl@0
|
430 |
|
sl@0
|
431 |
void CCluster::AdjustMap(TUint8** aMapEntry,TInt aAdjust)
|
sl@0
|
432 |
//
|
sl@0
|
433 |
// Adjust all map entries after aMapEntry
|
sl@0
|
434 |
//
|
sl@0
|
435 |
{
|
sl@0
|
436 |
do *aMapEntry+=aAdjust; while (++aMapEntry<=&iMap[KMaxClustering]);
|
sl@0
|
437 |
}
|
sl@0
|
438 |
|
sl@0
|
439 |
TInt CCluster::SetSizeL(TInt aSize)
|
sl@0
|
440 |
//
|
sl@0
|
441 |
// Set the minimum size for the cluster buffer
|
sl@0
|
442 |
// Return the offset between the new and old cells
|
sl@0
|
443 |
//
|
sl@0
|
444 |
{
|
sl@0
|
445 |
if (iSize>=aSize)
|
sl@0
|
446 |
return 0;
|
sl@0
|
447 |
//
|
sl@0
|
448 |
aSize+=EGranularity-1; // round to granularity
|
sl@0
|
449 |
aSize&=~(EGranularity-1);
|
sl@0
|
450 |
TUint8* base=iMap[0];
|
sl@0
|
451 |
TInt offset=(TUint8*)User::ReAllocL(base,aSize)-base;
|
sl@0
|
452 |
iSize=aSize;
|
sl@0
|
453 |
if (offset)
|
sl@0
|
454 |
AdjustMap(&iMap[0],offset);
|
sl@0
|
455 |
return offset;
|
sl@0
|
456 |
}
|
sl@0
|
457 |
|
sl@0
|
458 |
void CCluster::Discard()
|
sl@0
|
459 |
//
|
sl@0
|
460 |
// discard the current changes
|
sl@0
|
461 |
//
|
sl@0
|
462 |
{
|
sl@0
|
463 |
iCluster=KNullClusterId;
|
sl@0
|
464 |
iModified=EFalse;
|
sl@0
|
465 |
}
|
sl@0
|
466 |
|
sl@0
|
467 |
void CCluster::Create(TClusterId aClusterId)
|
sl@0
|
468 |
//
|
sl@0
|
469 |
// Create a new cluster
|
sl@0
|
470 |
//
|
sl@0
|
471 |
{
|
sl@0
|
472 |
__ASSERT(!iModified);
|
sl@0
|
473 |
//
|
sl@0
|
474 |
iCluster=aClusterId;
|
sl@0
|
475 |
iDes.iNext=KNullClusterId;
|
sl@0
|
476 |
iDes.iMembership=0;
|
sl@0
|
477 |
TUint8* base=iMap[0];
|
sl@0
|
478 |
for (TUint8** ptr=&iMap[1];ptr<=&iMap[KMaxClustering];++ptr)
|
sl@0
|
479 |
*ptr=base;
|
sl@0
|
480 |
iModified=ETrue;
|
sl@0
|
481 |
}
|
sl@0
|
482 |
|
sl@0
|
483 |
void CCluster::Relink(TClusterId aNextClusterId)
|
sl@0
|
484 |
//
|
sl@0
|
485 |
// Update the cluster to link to a different cluster
|
sl@0
|
486 |
//
|
sl@0
|
487 |
{
|
sl@0
|
488 |
iDes.iNext=aNextClusterId;
|
sl@0
|
489 |
iModified=ETrue;
|
sl@0
|
490 |
}
|
sl@0
|
491 |
|
sl@0
|
492 |
void CCluster::AlterL(MAlter& aAlterer)
|
sl@0
|
493 |
//
|
sl@0
|
494 |
// alter all records in the cluster
|
sl@0
|
495 |
//
|
sl@0
|
496 |
{
|
sl@0
|
497 |
TUint members=iDes.iMembership;
|
sl@0
|
498 |
TUint8* wptr=iMap[0];
|
sl@0
|
499 |
TUint8* rptr=wptr;
|
sl@0
|
500 |
for (TUint8** map=&iMap[0];map<&iMap[KMaxClustering];members>>=1,++map)
|
sl@0
|
501 |
{
|
sl@0
|
502 |
if (members&1)
|
sl@0
|
503 |
{
|
sl@0
|
504 |
TInt size=map[1]-rptr;
|
sl@0
|
505 |
TInt expand=wptr-rptr+aAlterer.RecordExpansion(rptr,size);
|
sl@0
|
506 |
if (expand>0)
|
sl@0
|
507 |
{ // requires more space for alteration
|
sl@0
|
508 |
AdjustL(map,expand+EExpandBuffer,rptr);
|
sl@0
|
509 |
wptr=map[0]; // compensate for possible moving cache
|
sl@0
|
510 |
rptr=map[1]-size; // record data is at end of this entry
|
sl@0
|
511 |
}
|
sl@0
|
512 |
wptr=aAlterer.AlterRecordL(wptr,rptr,size);
|
sl@0
|
513 |
rptr+=size;
|
sl@0
|
514 |
__ASSERT(wptr<=rptr);
|
sl@0
|
515 |
}
|
sl@0
|
516 |
else
|
sl@0
|
517 |
{
|
sl@0
|
518 |
__ASSERT(map[1]==rptr);
|
sl@0
|
519 |
}
|
sl@0
|
520 |
map[1]=wptr;
|
sl@0
|
521 |
}
|
sl@0
|
522 |
iModified=ETrue;
|
sl@0
|
523 |
}
|
sl@0
|
524 |
|
sl@0
|
525 |
TPtrC8 CCluster::RecordL(TInt aIndex)
|
sl@0
|
526 |
//
|
sl@0
|
527 |
// Read the cluster and return the record data
|
sl@0
|
528 |
//
|
sl@0
|
529 |
{
|
sl@0
|
530 |
if (!((iDes.iMembership>>aIndex)&1))
|
sl@0
|
531 |
__LEAVE(KErrNotFound);
|
sl@0
|
532 |
return TPtrC8(iMap[aIndex],iMap[aIndex+1]-iMap[aIndex]);
|
sl@0
|
533 |
}
|
sl@0
|
534 |
|
sl@0
|
535 |
TUint8* CCluster::UpdateL(TInt aIndex,TInt aNewSize)
|
sl@0
|
536 |
//
|
sl@0
|
537 |
// read the cluster and return a writable descriptor over the new record data
|
sl@0
|
538 |
//
|
sl@0
|
539 |
{
|
sl@0
|
540 |
SetRecordL(aIndex,aNewSize);
|
sl@0
|
541 |
iDes.iMembership|=(1<<aIndex);
|
sl@0
|
542 |
return iMap[aIndex];
|
sl@0
|
543 |
}
|
sl@0
|
544 |
|
sl@0
|
545 |
TBool CCluster::DeleteL(TInt aIndex)
|
sl@0
|
546 |
//
|
sl@0
|
547 |
// return whether the cluster is empty or not
|
sl@0
|
548 |
//
|
sl@0
|
549 |
{
|
sl@0
|
550 |
SetRecordL(aIndex,0);
|
sl@0
|
551 |
iDes.iMembership&=~(1<<aIndex);
|
sl@0
|
552 |
return iDes.iMembership;
|
sl@0
|
553 |
}
|
sl@0
|
554 |
|
sl@0
|
555 |
void CCluster::FlushL()
|
sl@0
|
556 |
{
|
sl@0
|
557 |
if (iModified)
|
sl@0
|
558 |
{ // Externalize the cluster
|
sl@0
|
559 |
RDbStoreWriteStream cluster(iDatabase);
|
sl@0
|
560 |
cluster.ReplaceLC(iDatabase.Store(),iCluster);
|
sl@0
|
561 |
cluster<<iDes;
|
sl@0
|
562 |
TUint8** map=&iMap[0];
|
sl@0
|
563 |
TUint8* base=*map;
|
sl@0
|
564 |
TUint8* ptr=base;
|
sl@0
|
565 |
for (TUint members=iDes.iMembership;members!=0;members>>=1)
|
sl@0
|
566 |
{
|
sl@0
|
567 |
++map;
|
sl@0
|
568 |
if (members&1)
|
sl@0
|
569 |
{
|
sl@0
|
570 |
TUint8* end=*map;
|
sl@0
|
571 |
cluster << TCardinality(end-ptr);
|
sl@0
|
572 |
ptr=end;
|
sl@0
|
573 |
}
|
sl@0
|
574 |
else
|
sl@0
|
575 |
{
|
sl@0
|
576 |
__ASSERT(*map==ptr);
|
sl@0
|
577 |
}
|
sl@0
|
578 |
}
|
sl@0
|
579 |
cluster.FilterL(cluster.EMixed,iCluster);
|
sl@0
|
580 |
cluster.WriteL(base,ptr-base);
|
sl@0
|
581 |
cluster.CommitL();
|
sl@0
|
582 |
CleanupStack::PopAndDestroy();
|
sl@0
|
583 |
iModified=EFalse;
|
sl@0
|
584 |
}
|
sl@0
|
585 |
}
|
sl@0
|
586 |
|
sl@0
|
587 |
void CCluster::ReadL(TClusterId aCluster)
|
sl@0
|
588 |
//
|
sl@0
|
589 |
// Internalize the cluster
|
sl@0
|
590 |
//
|
sl@0
|
591 |
{
|
sl@0
|
592 |
__ASSERT(iCluster!=aCluster);
|
sl@0
|
593 |
__ASSERT(!iModified);
|
sl@0
|
594 |
//
|
sl@0
|
595 |
iCluster=KNullClusterId;
|
sl@0
|
596 |
RDbStoreReadStream cluster(iDatabase);
|
sl@0
|
597 |
cluster.OpenLC(iDatabase.Store(),aCluster);
|
sl@0
|
598 |
cluster>>iDes;
|
sl@0
|
599 |
TUint8** map=&iMap[0];
|
sl@0
|
600 |
TUint8* base=*map;
|
sl@0
|
601 |
TUint8* ptr=base;
|
sl@0
|
602 |
for (TUint members=iDes.iMembership;members!=0;members>>=1)
|
sl@0
|
603 |
{
|
sl@0
|
604 |
if (members&1)
|
sl@0
|
605 |
{
|
sl@0
|
606 |
TCardinality card;
|
sl@0
|
607 |
cluster >> card;
|
sl@0
|
608 |
TInt size=card;
|
sl@0
|
609 |
if (size>KDbStoreMaxRecordLength)
|
sl@0
|
610 |
__LEAVE(KErrCorrupt);
|
sl@0
|
611 |
ptr+=size;
|
sl@0
|
612 |
}
|
sl@0
|
613 |
*++map=ptr;
|
sl@0
|
614 |
}
|
sl@0
|
615 |
while (map<&iMap[KMaxClustering])
|
sl@0
|
616 |
*++map=ptr;
|
sl@0
|
617 |
TInt len=ptr-base;
|
sl@0
|
618 |
base+=SetSizeL(len);
|
sl@0
|
619 |
cluster.FilterL(cluster.EMixed,aCluster);
|
sl@0
|
620 |
cluster.ReadL(base,len);
|
sl@0
|
621 |
CleanupStack::PopAndDestroy();
|
sl@0
|
622 |
iCluster=aCluster;
|
sl@0
|
623 |
}
|
sl@0
|
624 |
|
sl@0
|
625 |
void CCluster::SetRecordL(TInt aIndex,TInt aNewSize)
|
sl@0
|
626 |
{
|
sl@0
|
627 |
AdjustL(&iMap[aIndex],iMap[aIndex]+aNewSize-iMap[aIndex+1],iMap[aIndex+1]);
|
sl@0
|
628 |
iModified=ETrue;
|
sl@0
|
629 |
}
|
sl@0
|
630 |
|
sl@0
|
631 |
void CCluster::AdjustL(TUint8** aMapEntry,TInt aAdjust,TUint8* aData)
|
sl@0
|
632 |
//
|
sl@0
|
633 |
// Adjust the record at map entry by aAdjust bytes
|
sl@0
|
634 |
// Move that entry data as well as the ones following for AlterCluster
|
sl@0
|
635 |
//
|
sl@0
|
636 |
{
|
sl@0
|
637 |
if (!aAdjust)
|
sl@0
|
638 |
return;
|
sl@0
|
639 |
//
|
sl@0
|
640 |
__ASSERT(aAdjust+aMapEntry[1]>=aMapEntry[0]); // record cannot go -ve size
|
sl@0
|
641 |
__ASSERT(aData>=aMapEntry[0]); // must not save data before this record
|
sl@0
|
642 |
//
|
sl@0
|
643 |
aData+=SetSizeL(iMap[KMaxClustering]-iMap[0]+aAdjust);
|
sl@0
|
644 |
Mem::Copy(aData+aAdjust,aData,iMap[KMaxClustering]-aData);
|
sl@0
|
645 |
AdjustMap(aMapEntry+1,aAdjust);
|
sl@0
|
646 |
}
|
sl@0
|
647 |
|
sl@0
|
648 |
// class CCluster::MAlter
|
sl@0
|
649 |
|
sl@0
|
650 |
TInt CCluster::MAlter::RecordExpansion(const TUint8*,TInt)
|
sl@0
|
651 |
//
|
sl@0
|
652 |
// default to no expansion
|
sl@0
|
653 |
//
|
sl@0
|
654 |
{
|
sl@0
|
655 |
return 0;
|
sl@0
|
656 |
}
|