os/textandloc/textrendering/textformatting/undo/UniqueInstanceImpl.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
/*
sl@0
     2
* Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     3
* All rights reserved.
sl@0
     4
* This component and the accompanying materials are made available
sl@0
     5
* under the terms of "Eclipse Public License v1.0"
sl@0
     6
* which accompanies this distribution, and is available
sl@0
     7
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     8
*
sl@0
     9
* Initial Contributors:
sl@0
    10
* Nokia Corporation - initial contribution.
sl@0
    11
*
sl@0
    12
* Contributors:
sl@0
    13
*
sl@0
    14
* Description: 
sl@0
    15
*
sl@0
    16
*/
sl@0
    17
sl@0
    18
sl@0
    19
#include "UniqueInstanceImpl.h"
sl@0
    20
#include "AssertFileAndLine.h"
sl@0
    21
#include <e32math.h>
sl@0
    22
sl@0
    23
using namespace UniqueInstance;
sl@0
    24
sl@0
    25
namespace UniqueInstance
sl@0
    26
{
sl@0
    27
_LIT(KUniqueInstance, "UniqInst");
sl@0
    28
sl@0
    29
void DestroyRUniqueInstance(void* aUniqueInstance)
sl@0
    30
	{
sl@0
    31
	reinterpret_cast<RInstanceImpl*>(aUniqueInstance)->Close();
sl@0
    32
	}
sl@0
    33
sl@0
    34
/**
sl@0
    35
 * Iterator that traverses an RSkipList's pointers.
sl@0
    36
 *
sl@0
    37
 * @internalComponent
sl@0
    38
 * @since App-frameworks6.1
sl@0
    39
 */
sl@0
    40
class TSkipListIterator
sl@0
    41
	{
sl@0
    42
public:
sl@0
    43
	TSkipListIterator(TCompareFn* aCompare, void* aMatch,
sl@0
    44
		RSkipList::TSection** aFirstLink, TInt aNumLinks);
sl@0
    45
	RSkipList::TSection& operator*();
sl@0
    46
	TInt Level();
sl@0
    47
	TBool DecrementLevel();		// returns true if aMatch found
sl@0
    48
	void SpliceIn(RSkipList::TSection* aSection) const;
sl@0
    49
	void SpliceOut() const;
sl@0
    50
private:
sl@0
    51
	TCompareFn*				iCompare;
sl@0
    52
	void*					iMatch;
sl@0
    53
	RSkipList::TSection**	iCurrentLink;
sl@0
    54
	TInt					iLevel;
sl@0
    55
	};
sl@0
    56
}
sl@0
    57
sl@0
    58
TSkipListIterator::TSkipListIterator(TCompareFn* aCompare, void* aMatch,
sl@0
    59
	RSkipList::TSection** aFirstLink, TInt aNumLinks)
sl@0
    60
	: iCompare(aCompare), iMatch(aMatch),
sl@0
    61
	iCurrentLink(aFirstLink - 1), iLevel(aNumLinks) {}
sl@0
    62
sl@0
    63
RSkipList::TSection& TSkipListIterator::operator*()
sl@0
    64
	{
sl@0
    65
	return **iCurrentLink;
sl@0
    66
	}
sl@0
    67
sl@0
    68
TInt TSkipListIterator::Level()
sl@0
    69
	{
sl@0
    70
	return iLevel;
sl@0
    71
	}
sl@0
    72
sl@0
    73
TBool TSkipListIterator::DecrementLevel()
sl@0
    74
	{
sl@0
    75
	--iLevel;
sl@0
    76
	++iCurrentLink;
sl@0
    77
	for(;;)
sl@0
    78
		{
sl@0
    79
		if (!*iCurrentLink)
sl@0
    80
			return EFalse;
sl@0
    81
		TInt compare = iCompare((*iCurrentLink)->iElement.iObject, iMatch);
sl@0
    82
		if (0 <= compare)
sl@0
    83
			return compare == 0;
sl@0
    84
		iCurrentLink = &(*iCurrentLink)->iLinks[-iLevel];
sl@0
    85
		}
sl@0
    86
	}
sl@0
    87
sl@0
    88
void TSkipListIterator::SpliceIn(RSkipList::TSection* aSection) const
sl@0
    89
	{
sl@0
    90
	aSection->iLinks[-iLevel] = *iCurrentLink;
sl@0
    91
	*iCurrentLink = aSection;
sl@0
    92
	}
sl@0
    93
sl@0
    94
void TSkipListIterator::SpliceOut() const
sl@0
    95
	{
sl@0
    96
	*iCurrentLink = (*iCurrentLink)->iLinks[-iLevel];
sl@0
    97
	}
sl@0
    98
sl@0
    99
sl@0
   100
///////////////////////
sl@0
   101
//					 //
sl@0
   102
//	CRepositoryImpl  //
sl@0
   103
//					 //
sl@0
   104
///////////////////////
sl@0
   105
sl@0
   106
CRepositoryImpl::CRepositoryImpl(TCompareFn* aCompare,
sl@0
   107
	TDeleteFn* aDelete, TCopyFnL* aCopyL, TInt aObjectSize)
sl@0
   108
	: iCompare(aCompare), iDelete(aDelete), iCopyL(aCopyL), iObjectSize(aObjectSize)
sl@0
   109
	{
sl@0
   110
	iNullElement.iObject = 0;
sl@0
   111
	ASSERT(iCompare);
sl@0
   112
	ASSERT(iDelete);
sl@0
   113
	ASSERT(iCopyL);
sl@0
   114
	}
sl@0
   115
sl@0
   116
CRepositoryImpl::~CRepositoryImpl()
sl@0
   117
	{
sl@0
   118
	iSkipList.Close();
sl@0
   119
	}
sl@0
   120
sl@0
   121
void CRepositoryImpl::ConstructL(TInt aMaxLinks)
sl@0
   122
	{
sl@0
   123
	iSkipList.Open(*iCompare, aMaxLinks);
sl@0
   124
	}
sl@0
   125
sl@0
   126
SElement* CRepositoryImpl::NullElement()
sl@0
   127
	{
sl@0
   128
	return &iNullElement;
sl@0
   129
	}
sl@0
   130
sl@0
   131
TBool CRepositoryImpl::IsNull(SElement* a) const
sl@0
   132
	{
sl@0
   133
	return a == &iNullElement;
sl@0
   134
	}
sl@0
   135
sl@0
   136
void CRepositoryImpl::Test() const
sl@0
   137
	{
sl@0
   138
	iSkipList.Test();
sl@0
   139
	}
sl@0
   140
sl@0
   141
SElement* CRepositoryImpl::InsertOrIncL(void* aElt)
sl@0
   142
	{
sl@0
   143
	SElement* r = iSkipList.AddExisting(aElt);
sl@0
   144
	if (!r)
sl@0
   145
		return iSkipList.AddNewL(aElt);
sl@0
   146
	iDelete(aElt);
sl@0
   147
	return r;
sl@0
   148
	}
sl@0
   149
sl@0
   150
SElement* CRepositoryImpl::IncOrCopyL(void* aElt)
sl@0
   151
	{
sl@0
   152
	SElement* r = iSkipList.AddExisting(aElt);
sl@0
   153
	if (r)
sl@0
   154
		return r;
sl@0
   155
	void* copy = iCopyL(aElt, iObjectSize);
sl@0
   156
	CleanupStack::PushL(TCleanupItem(iDelete, copy));
sl@0
   157
	r = iSkipList.AddNewL(copy);
sl@0
   158
	CleanupStack::Pop();
sl@0
   159
	return r;
sl@0
   160
	}
sl@0
   161
sl@0
   162
void CRepositoryImpl::DeleteOrDec(SElement* aNoLongerNeeded)
sl@0
   163
	{
sl@0
   164
	if (IsNull(aNoLongerNeeded))
sl@0
   165
		return;
sl@0
   166
	if (--(aNoLongerNeeded->iRefCount))
sl@0
   167
		return;
sl@0
   168
	void* object = aNoLongerNeeded->iObject;
sl@0
   169
	iSkipList.Remove(object);
sl@0
   170
	iDelete(object);
sl@0
   171
	}
sl@0
   172
sl@0
   173
void* CRepositoryImpl::DetatchOrCopyL(SElement* aWritableCopyNeeded)
sl@0
   174
	{
sl@0
   175
	void* retval = 0;
sl@0
   176
	if (!IsNull(aWritableCopyNeeded))
sl@0
   177
		{
sl@0
   178
		if (1 < aWritableCopyNeeded->iRefCount)
sl@0
   179
			{
sl@0
   180
			retval = iCopyL(aWritableCopyNeeded->iObject, iObjectSize);
sl@0
   181
			--(aWritableCopyNeeded->iRefCount);
sl@0
   182
			}
sl@0
   183
		else
sl@0
   184
			{
sl@0
   185
			retval = aWritableCopyNeeded->iObject;
sl@0
   186
			iSkipList.Remove(aWritableCopyNeeded->iObject);
sl@0
   187
			}
sl@0
   188
		}
sl@0
   189
	return retval;
sl@0
   190
	}
sl@0
   191
sl@0
   192
sl@0
   193
/////////////////
sl@0
   194
//			   //
sl@0
   195
//	RSkipList  //
sl@0
   196
//			   //
sl@0
   197
/////////////////
sl@0
   198
sl@0
   199
RSkipList::~RSkipList()
sl@0
   200
	{
sl@0
   201
	ASSERT(!iSentinel);
sl@0
   202
	}
sl@0
   203
sl@0
   204
void RSkipList::Open(TCompareFn* aCompare, TInt aMaxLinks)
sl@0
   205
	{
sl@0
   206
	ASSERT(0 < aMaxLinks);
sl@0
   207
	iLinkCount = aMaxLinks;
sl@0
   208
	TSection** sentinelBuffer = reinterpret_cast<TSection**>(
sl@0
   209
		operator new((aMaxLinks - 1) * sizeof(TSection*) + sizeof(TSection)));
sl@0
   210
	iSentinel = reinterpret_cast<TSection*>(sentinelBuffer + (iLinkCount - 1));
sl@0
   211
	iCompare = aCompare;
sl@0
   212
	for (TInt i = 0; i != iLinkCount; ++i)
sl@0
   213
		iSentinel->iLinks[-i] = 0;
sl@0
   214
	// iSentinel will be released in Close(). so,
sl@0
   215
	// coverity[memory_leak]
sl@0
   216
	}
sl@0
   217
sl@0
   218
void RSkipList::Close()
sl@0
   219
	{
sl@0
   220
	ASSERT(IsEmpty());
sl@0
   221
	if (iSentinel)
sl@0
   222
		operator delete(FirstLink());
sl@0
   223
	iSentinel = 0;
sl@0
   224
	}
sl@0
   225
sl@0
   226
SElement* RSkipList::AddExisting(void* aNewElt)
sl@0
   227
	{
sl@0
   228
	TSkipListIterator it(iCompare, aNewElt, FirstLink(), iLinkCount);
sl@0
   229
	while (it.Level())
sl@0
   230
		{
sl@0
   231
		if (it.DecrementLevel())
sl@0
   232
			{
sl@0
   233
			SElement* e = &(*it).iElement;
sl@0
   234
			++(e->iRefCount);
sl@0
   235
			return e;
sl@0
   236
			}
sl@0
   237
		}
sl@0
   238
	return 0;
sl@0
   239
	}
sl@0
   240
sl@0
   241
void* RSkipList::Remove(void* aNoLongerNeeded)
sl@0
   242
	{
sl@0
   243
	void* object = 0;
sl@0
   244
	TSection** toBeDeleted = 0;
sl@0
   245
sl@0
   246
	TSkipListIterator it(iCompare, aNoLongerNeeded, FirstLink(), iLinkCount);
sl@0
   247
	while (it.Level())
sl@0
   248
		{
sl@0
   249
		if (it.DecrementLevel())
sl@0
   250
			{
sl@0
   251
			if (!toBeDeleted)
sl@0
   252
				{
sl@0
   253
				TSection& s = *it;
sl@0
   254
				toBeDeleted = s.iLinks - it.Level();
sl@0
   255
				object = s.iElement.iObject;
sl@0
   256
				}
sl@0
   257
			it.SpliceOut();
sl@0
   258
			}
sl@0
   259
		}
sl@0
   260
sl@0
   261
	ASSERT(toBeDeleted);
sl@0
   262
	operator delete(toBeDeleted);
sl@0
   263
sl@0
   264
	return object;
sl@0
   265
	}
sl@0
   266
sl@0
   267
SElement* RSkipList::AddNewL(void* aNewElt)
sl@0
   268
	{
sl@0
   269
	TInt numLinks = GenerateNumLinks();
sl@0
   270
	TSection** currentLink = reinterpret_cast<TSection**>
sl@0
   271
		( operator new((numLinks - 1) * sizeof(TSection*) + sizeof(TSection), ELeave) );
sl@0
   272
	TSection* newSection = reinterpret_cast<TSection*>(currentLink + (numLinks - 1));
sl@0
   273
	newSection->iElement.iObject = aNewElt;
sl@0
   274
	newSection->iElement.iRefCount = 1;
sl@0
   275
sl@0
   276
	TSkipListIterator it(iCompare, aNewElt, FirstLink(), iLinkCount);
sl@0
   277
#ifdef _DEBUG
sl@0
   278
	// to ensure allocated memory will be attached to the link list.
sl@0
   279
	TBool attachedToLinkList = EFalse;
sl@0
   280
#endif
sl@0
   281
	while (it.Level())
sl@0
   282
		{
sl@0
   283
		it.DecrementLevel();
sl@0
   284
		if (it.Level() < numLinks)
sl@0
   285
			{
sl@0
   286
			it.SpliceIn(newSection);
sl@0
   287
#ifdef _DEBUG
sl@0
   288
			attachedToLinkList = ETrue;
sl@0
   289
#endif
sl@0
   290
			}
sl@0
   291
		}
sl@0
   292
#ifdef _DEBUG
sl@0
   293
	ASSERT(attachedToLinkList);
sl@0
   294
#endif
sl@0
   295
	// The memory currentLink will be attached to the link list,
sl@0
   296
	// and will be released in Remove(). so,
sl@0
   297
	// coverity[memory_leak]
sl@0
   298
	return &newSection->iElement;
sl@0
   299
	}
sl@0
   300
sl@0
   301
TBool RSkipList::IsEmpty() const
sl@0
   302
	{
sl@0
   303
	TSection** link = FirstLink();
sl@0
   304
	for (TInt i = iLinkCount; i; --i, ++link)
sl@0
   305
		{
sl@0
   306
		if (*link)
sl@0
   307
			return EFalse;
sl@0
   308
		}
sl@0
   309
	return ETrue;
sl@0
   310
	}
sl@0
   311
sl@0
   312
RSkipList::TSection** RSkipList::FirstLink() const
sl@0
   313
	{
sl@0
   314
	ASSERT(iSentinel);
sl@0
   315
	return &iSentinel->iLinks[ 1 - iLinkCount ];
sl@0
   316
	}
sl@0
   317
sl@0
   318
// 3/4 chance that 1 is returned
sl@0
   319
// (1/4)^n * (3/4) chance that (n-1) is returned
sl@0
   320
TInt RSkipList::GenerateNumLinks() const
sl@0
   321
	{
sl@0
   322
	TInt32 bits = 0;
sl@0
   323
	TInt r = 1;
sl@0
   324
sl@0
   325
	for (;;)
sl@0
   326
		{
sl@0
   327
		if (r == iLinkCount)
sl@0
   328
			return r;
sl@0
   329
		if ((r & 7) == 0)
sl@0
   330
			bits = Math::Random();
sl@0
   331
		if ((bits & 3) != 0)
sl@0
   332
			return r;
sl@0
   333
		++r;
sl@0
   334
		bits >>= 2;
sl@0
   335
		}
sl@0
   336
	}
sl@0
   337
sl@0
   338
void RSkipList::TestLinks(TSection* aStart, TSection* aEnd, TInt aLink) const
sl@0
   339
	{
sl@0
   340
	while (aStart != aEnd)
sl@0
   341
		{
sl@0
   342
		__ASSERT_ALWAYS(aStart, User::Panic(KUniqueInstance, 0));
sl@0
   343
		TSection* aNext = aStart->iLinks[-aLink];
sl@0
   344
		if (aLink)
sl@0
   345
			TestLinks(aStart, aNext, aLink - 1);
sl@0
   346
		aStart = aNext;
sl@0
   347
		}
sl@0
   348
	}
sl@0
   349
sl@0
   350
TInt RSkipList::Test() const
sl@0
   351
	{
sl@0
   352
	TestLinks(iSentinel, 0, iLinkCount - 1);
sl@0
   353
sl@0
   354
	TSection* last = iSentinel->iLinks[0];
sl@0
   355
	if (!last)
sl@0
   356
		return 0;
sl@0
   357
	TInt count = 1;
sl@0
   358
	for (TSection* p = last->iLinks[0]; p; last = p, p = p->iLinks[0])
sl@0
   359
		{
sl@0
   360
		++count;
sl@0
   361
		__ASSERT_ALWAYS(iCompare(last->iElement.iObject, p->iElement.iObject) < 0, User::Panic(KUniqueInstance, 0));
sl@0
   362
		}
sl@0
   363
	return count;
sl@0
   364
	}
sl@0
   365