bool TestReallocMsize(size_t startSz) {
    bool passed = true;

    char *buf = (char*)scalable_malloc(startSz);
    ASSERT(buf, "");
    size_t realSz = scalable_msize(buf);
    ASSERT(realSz>=startSz, "scalable_msize must be not less then allocated size");
    memset(buf, 'a', realSz-1);
    buf[realSz-1] = 0;
    char *buf1 = (char*)scalable_realloc(buf, 2*realSz);
    ASSERT(buf1, "");
    ASSERT(scalable_msize(buf1)>=2*realSz,
           "scalable_msize must be not less then allocated size");
    buf1[2*realSz-1] = 0;
    if ( strspn(buf1, "a") < realSz-1 ) {
        REPORT( "Error: data broken for %d Bytes object.\n", startSz);
        passed = false;
    }
    scalable_free(buf1);

    return passed;
}
void FMallocTBB::Free( void* Ptr )
{
	if( !Ptr )
	{
		return;
	}
	MEM_TIME(MemTime -= FPlatformTime::Seconds())
#if UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT
	FMemory::Memset(Ptr, DEBUG_FILL_FREED, scalable_msize(Ptr)); 
#endif
	IncrementTotalFreeCalls();
	scalable_free(Ptr);

	MEM_TIME(MemTime += FPlatformTime::Seconds())
}
// regression test against incorrect work of msize/realloc
// for aligned objects
void TestAlignedMsize()
{
    const int NUM = 4;
    char *p[NUM];
    size_t objSizes[NUM];
    size_t allocSz[] = {4, 8, 512, 2*1024, 4*1024, 8*1024, 16*1024, 0};
    size_t align[] = {8, 512, 2*1024, 4*1024, 8*1024, 16*1024, 0};

    for (int a=0; align[a]; a++)
        for (int s=0; allocSz[s]; s++) {
            for (int i=0; i<NUM; i++) {
                p[i] = (char*)scalable_aligned_malloc(allocSz[s], align[a]);
                ASSERT(is_aligned(p[i], align[a]), NULL);
            }

            for (int i=0; i<NUM; i++) {
                objSizes[i] = scalable_msize(p[i]);
                ASSERT(objSizes[i] >= allocSz[s],
                       "allocated size must be not less than requested");
                memset(p[i], i, objSizes[i]);
            }
            for (int i=0; i<NUM; i++) {
                for (unsigned j=0; j<objSizes[i]; j++)
                    ASSERT(((char*)p[i])[j] == i, "Error: data broken");
            }

            for (int i=0; i<NUM; i++) {
                p[i] = (char*)scalable_aligned_realloc(p[i], 2*allocSz[s], align[a]);
                ASSERT(is_aligned(p[i], align[a]), NULL);
                memset((char*)p[i]+allocSz[s], i+1, allocSz[s]);
            }
            for (int i=0; i<NUM; i++) {
                for (unsigned j=0; j<allocSz[s]; j++)
                    ASSERT(((char*)p[i])[j] == i, "Error: data broken");
                for (size_t j=allocSz[s]; j<2*allocSz[s]; j++)
                    ASSERT(((char*)p[i])[j] == i+1, "Error: data broken");
            }
            for (int i=0; i<NUM; i++)
                scalable_free(p[i]);
        }
}
void* FMallocTBB::Realloc( void* Ptr, SIZE_T NewSize, uint32 Alignment )
{
	IncrementTotalReallocCalls();

	MEM_TIME(MemTime -= FPlatformTime::Seconds())
#if UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT
	SIZE_T OldSize = 0;
	if (Ptr)
	{
		OldSize = scalable_msize(Ptr);
		if (NewSize < OldSize)
		{
			FMemory::Memset((uint8*)Ptr + NewSize, DEBUG_FILL_FREED, OldSize - NewSize); 
		}
	}
#endif
	void* NewPtr = NULL;
	if (Alignment != DEFAULT_ALIGNMENT)
	{
		Alignment = FMath::Max(NewSize >= 16 ? (uint32)16 : (uint32)8, Alignment);
		NewPtr = scalable_aligned_realloc(Ptr, NewSize, Alignment);
	}
	else
	{
		NewPtr = scalable_realloc(Ptr, NewSize);
	}
#if UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT
	if (NewPtr && NewSize > OldSize )
	{
		FMemory::Memset((uint8*)NewPtr + OldSize, DEBUG_FILL_NEW, NewSize - OldSize); 
	}
#endif
	if( !NewPtr && NewSize )
	{
		OutOfMemory(NewSize, Alignment);
	}
	MEM_TIME(MemTime += FPlatformTime::Seconds())
	return NewPtr;
}
void TestObjectRecognition() {
    size_t headersSize = sizeof(LargeMemoryBlock)+sizeof(LargeObjectHdr);
    unsigned falseObjectSize = 113; // unsigned is the type expected by getObjectSize
    size_t obtainedSize;

    ASSERT(sizeof(BackRefIdx)==4, "Unexpected size of BackRefIdx");
    ASSERT(getObjectSize(falseObjectSize)!=falseObjectSize, "Error in test: bad choice for false object size");

    void* mem = scalable_malloc(2*slabSize);
    ASSERT(mem, "Memory was not allocated");
    Block* falseBlock = (Block*)alignUp((uintptr_t)mem, slabSize);
    falseBlock->objectSize = falseObjectSize;
    char* falseSO = (char*)falseBlock + falseObjectSize*7;
    ASSERT(alignDown(falseSO, slabSize)==(void*)falseBlock, "Error in test: false object offset is too big");

    void* bufferLOH = scalable_malloc(2*slabSize + headersSize);
    ASSERT(bufferLOH, "Memory was not allocated");
    LargeObjectHdr* falseLO = 
        (LargeObjectHdr*)alignUp((uintptr_t)bufferLOH + headersSize, slabSize);
    LargeObjectHdr* headerLO = (LargeObjectHdr*)falseLO-1;
    headerLO->memoryBlock = (LargeMemoryBlock*)bufferLOH;
    headerLO->memoryBlock->unalignedSize = 2*slabSize + headersSize;
    headerLO->memoryBlock->objectSize = slabSize + headersSize;
    headerLO->backRefIdx = BackRefIdx::newBackRef(/*largeObj=*/true);
    setBackRef(headerLO->backRefIdx, headerLO);
    ASSERT(scalable_msize(falseLO) == slabSize + headersSize,
           "Error in test: LOH falsification failed");
    removeBackRef(headerLO->backRefIdx);

    const int NUM_OF_IDX = BR_MAX_CNT+2;
    BackRefIdx idxs[NUM_OF_IDX];
    for (int cnt=0; cnt<2; cnt++) {
        for (int master = -10; master<10; master++) {
            falseBlock->backRefIdx.master = (uint16_t)master;
            headerLO->backRefIdx.master = (uint16_t)master;
        
            for (int bl = -10; bl<BR_MAX_CNT+10; bl++) {
                falseBlock->backRefIdx.offset = (uint16_t)bl;
                headerLO->backRefIdx.offset = (uint16_t)bl;

                for (int largeObj = 0; largeObj<2; largeObj++) {
                    falseBlock->backRefIdx.largeObj = largeObj;
                    headerLO->backRefIdx.largeObj = largeObj;

                    obtainedSize = safer_scalable_msize(falseSO, NULL);
                    ASSERT(obtainedSize==0, "Incorrect pointer accepted");
                    obtainedSize = safer_scalable_msize(falseLO, NULL);
                    ASSERT(obtainedSize==0, "Incorrect pointer accepted");
                }
            }
        }
        if (cnt == 1) {
            for (int i=0; i<NUM_OF_IDX; i++)
                removeBackRef(idxs[i]);
            break;
        }
        for (int i=0; i<NUM_OF_IDX; i++) {
            idxs[i] = BackRefIdx::newBackRef(/*largeObj=*/false);
            setBackRef(idxs[i], NULL);
        }
    }
    char *smallPtr = (char*)scalable_malloc(falseObjectSize);
    obtainedSize = safer_scalable_msize(smallPtr, NULL);
    ASSERT(obtainedSize==getObjectSize(falseObjectSize), "Correct pointer not accepted?");
    scalable_free(smallPtr);

    obtainedSize = safer_scalable_msize(mem, NULL);
    ASSERT(obtainedSize>=2*slabSize, "Correct pointer not accepted?");
    scalable_free(mem);
    scalable_free(bufferLOH);
}
bool FMallocTBB::GetAllocationSize(void *Original, SIZE_T &SizeOut)
{
	SizeOut = scalable_msize(Original);
	return true;
}