123
This commit is contained in:
374
STLPORT/test/eh/nc_alloc.cpp
Normal file
374
STLPORT/test/eh/nc_alloc.cpp
Normal file
@@ -0,0 +1,374 @@
|
||||
/************************************************************************************************
|
||||
NC_ALLOC.CPP
|
||||
|
||||
* Copyright (c) 1997
|
||||
* Mark of the Unicorn, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute and sell this software
|
||||
* and its documentation for any purpose is hereby granted without fee,
|
||||
* provided that the above copyright notice appear in all copies and
|
||||
* that both that copyright notice and this permission notice appear
|
||||
* in supporting documentation. Mark of the Unicorn makes no
|
||||
* representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
|
||||
************************************************************************************************/
|
||||
|
||||
#include "nc_alloc.h"
|
||||
#include <string>
|
||||
|
||||
#if defined (EH_NEW_HEADERS)
|
||||
# include <new>
|
||||
# include <cassert>
|
||||
# include <cstdlib>
|
||||
#else
|
||||
# include <assert.h>
|
||||
# include <stdlib.h>
|
||||
# include <new.h>
|
||||
#endif
|
||||
|
||||
#if defined (EH_NEW_IOSTREAMS)
|
||||
# include <iostream>
|
||||
#else
|
||||
# include <iostream.h>
|
||||
#endif
|
||||
|
||||
long alloc_count = 0;
|
||||
long object_count = 0;
|
||||
long TestController::possible_failure_count = 0;
|
||||
const char* TestController::current_test = "<unknown>";
|
||||
const char* TestController::current_test_category = "no category";
|
||||
const char* TestController::current_container = 0;
|
||||
bool TestController::nc_verbose = true;
|
||||
bool TestController::never_fail = false;
|
||||
bool TestController::track_allocations = false;
|
||||
bool TestController::leak_detection_enabled = false;
|
||||
TestController gTestController;
|
||||
|
||||
//************************************************************************************************
|
||||
void TestController::maybe_fail(long)
|
||||
{
|
||||
if ( never_fail || Failure_threshold() == kNotInExceptionTest )
|
||||
return;
|
||||
|
||||
// throw if allocation would satisfy the threshold
|
||||
if ( possible_failure_count++ >= Failure_threshold() )
|
||||
{
|
||||
|
||||
// what about doing some standard new_handler() behavior here (to test it!) ???
|
||||
|
||||
// reset and simulate an out-of-memory failure
|
||||
Failure_threshold() = kNotInExceptionTest;
|
||||
# ifndef EH_NO_EXCEPTIONS
|
||||
throw EH_STD::bad_alloc();
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
# if defined( EH_HASHED_CONTAINERS_IMPLEMENTED )
|
||||
|
||||
# if defined (__SGI_STL )
|
||||
|
||||
# if defined (EH_NEW_HEADERS)
|
||||
# include <hash_set>
|
||||
# else
|
||||
# include <hash_set.h>
|
||||
# endif
|
||||
# elif defined (__MSL__)
|
||||
# include <hashset.h>
|
||||
# else
|
||||
# error what do I include to get hash_set?
|
||||
# endif
|
||||
|
||||
# else
|
||||
|
||||
# if defined (EH_NEW_HEADERS)
|
||||
# include <set>
|
||||
# else
|
||||
# include <set.h>
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if !defined( EH_HASHED_CONTAINERS_IMPLEMENTED )
|
||||
typedef EH_STD::set<void*, EH_STD::less<void*> > allocation_set;
|
||||
#else
|
||||
|
||||
USING_CSTD_NAME(size_t)
|
||||
|
||||
struct hash_void
|
||||
{
|
||||
size_t operator()(void* x) const { return (size_t)x; }
|
||||
};
|
||||
|
||||
typedef EH_STD::hash_set<void*, ::hash_void, EH_STD::equal_to<void*> > allocation_set;
|
||||
# endif
|
||||
|
||||
static allocation_set& alloc_set()
|
||||
{
|
||||
static allocation_set s;
|
||||
return s;
|
||||
}
|
||||
|
||||
// Prevents infinite recursion during allocation
|
||||
static bool using_alloc_set = false;
|
||||
|
||||
# if !defined (NO_FAST_ALLOCATOR)
|
||||
//
|
||||
// FastAllocator -- speeds up construction of TestClass objects when
|
||||
// TESTCLASS_DEEP_DATA is enabled, and speeds up tracking of allocations
|
||||
// when the suite is run with the -t option.
|
||||
//
|
||||
class FastAllocator
|
||||
{
|
||||
public:
|
||||
// FastAllocator() : mFree(0), mUsed(0) {}
|
||||
|
||||
static void *Allocate( size_t s )
|
||||
{
|
||||
void *result = 0;
|
||||
|
||||
if ( s <= sizeof( Block ) )
|
||||
{
|
||||
if ( mFree != 0 )
|
||||
{
|
||||
result = mFree;
|
||||
mFree = mFree->next;
|
||||
}
|
||||
else if ( mBlocks != 0 && mUsed < kBlockCount )
|
||||
{
|
||||
result = (void*)&mBlocks[mUsed++];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool Free( void* p )
|
||||
{
|
||||
Block* b = (Block*)p;
|
||||
if ( mBlocks == 0 || b < mBlocks || b >= mBlocks + kBlockCount )
|
||||
return false;
|
||||
b->next = mFree;
|
||||
mFree = b;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct Block;
|
||||
friend struct Block;
|
||||
|
||||
enum
|
||||
{
|
||||
// Number of fast allocation blocks to create.
|
||||
kBlockCount = 1500,
|
||||
|
||||
// You may need to adjust this number for your platform.
|
||||
// A good choice will speed tests. A bad choice will still work.
|
||||
kMinBlockSize = 48
|
||||
};
|
||||
|
||||
struct Block
|
||||
{
|
||||
union {
|
||||
Block *next;
|
||||
double dummy; // fbp - force alignment
|
||||
char dummy2[kMinBlockSize];
|
||||
};
|
||||
};
|
||||
|
||||
static Block* mBlocks;
|
||||
static Block *mFree;
|
||||
static size_t mUsed;
|
||||
};
|
||||
|
||||
FastAllocator::Block *FastAllocator::mBlocks =
|
||||
(FastAllocator::Block*)EH_CSTD::calloc( sizeof(FastAllocator::Block), FastAllocator::kBlockCount );
|
||||
FastAllocator::Block *FastAllocator::mFree;
|
||||
size_t FastAllocator::mUsed;
|
||||
|
||||
|
||||
static FastAllocator gFastAllocator;
|
||||
# endif
|
||||
|
||||
inline char* AllocateBlock( size_t s )
|
||||
{
|
||||
# if !defined (NO_FAST_ALLOCATOR)
|
||||
char * const p = (char*)gFastAllocator.Allocate( s );
|
||||
if ( p != 0 )
|
||||
return p;
|
||||
# endif
|
||||
|
||||
return (char*)EH_CSTD::malloc(s);
|
||||
}
|
||||
|
||||
static void* OperatorNew( size_t s )
|
||||
{
|
||||
if ( !using_alloc_set )
|
||||
{
|
||||
simulate_possible_failure();
|
||||
alloc_count++;
|
||||
}
|
||||
|
||||
char *p = AllocateBlock(s);
|
||||
|
||||
if ( gTestController.TrackingEnabled()
|
||||
&& gTestController.LeakDetectionEnabled()
|
||||
&& !using_alloc_set )
|
||||
{
|
||||
using_alloc_set = true;
|
||||
EH_ASSERT( alloc_set().find( p ) == alloc_set().end() );
|
||||
alloc_set().insert( p );
|
||||
using_alloc_set = false;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void* _STLP_CALL operator new(size_t s)
|
||||
#ifdef EH_DELETE_HAS_THROW_SPEC
|
||||
throw(EH_STD::bad_alloc)
|
||||
#endif
|
||||
{
|
||||
return OperatorNew( s );
|
||||
}
|
||||
|
||||
#ifdef EH_USE_NOTHROW
|
||||
void* _STLP_CALL operator new(size_t size, const EH_STD::nothrow_t&) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
return OperatorNew( size );
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
# if defined (EH_VECTOR_OPERATOR_NEW)
|
||||
void* _STLP_CALL operator new[](size_t size ) throw(EH_STD::bad_alloc)
|
||||
{
|
||||
return OperatorNew( size );
|
||||
}
|
||||
|
||||
#ifdef EH_USE_NOTHROW
|
||||
void* _STLP_CALL operator new[](size_t size, const EH_STD::nothrow_t&) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
return OperatorNew( size );
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void _STLP_CALL operator delete[](void* ptr) throw()
|
||||
{
|
||||
operator delete( ptr );
|
||||
}
|
||||
# endif
|
||||
|
||||
# if defined (EH_DELETE_HAS_THROW_SPEC)
|
||||
void _STLP_CALL operator delete(void* s) throw()
|
||||
# else
|
||||
void _STLP_CALL operator delete(void* s)
|
||||
# endif
|
||||
{
|
||||
if ( s != 0 )
|
||||
{
|
||||
if ( !using_alloc_set )
|
||||
{
|
||||
alloc_count--;
|
||||
|
||||
if ( gTestController.TrackingEnabled() && gTestController.LeakDetectionEnabled() )
|
||||
{
|
||||
using_alloc_set = true;
|
||||
allocation_set::iterator p = alloc_set().find( (char*)s );
|
||||
EH_ASSERT( p != alloc_set().end() );
|
||||
alloc_set().erase( p );
|
||||
using_alloc_set = false;
|
||||
}
|
||||
}
|
||||
# if ! defined (NO_FAST_ALLOCATOR)
|
||||
if ( !gFastAllocator.Free( s ) )
|
||||
# endif
|
||||
EH_CSTD::free(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*===================================================================================
|
||||
ClearAllocationSet (private helper)
|
||||
|
||||
EFFECTS: Empty the set of allocated blocks.
|
||||
====================================================================================*/
|
||||
void TestController::ClearAllocationSet()
|
||||
{
|
||||
if ( !using_alloc_set )
|
||||
{
|
||||
using_alloc_set = true;
|
||||
alloc_set().clear();
|
||||
using_alloc_set = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool TestController::ReportLeaked()
|
||||
{
|
||||
|
||||
EndLeakDetection();
|
||||
|
||||
if (using_alloc_set)
|
||||
EH_ASSERT( alloc_count == static_cast<int>(alloc_set().size()) );
|
||||
|
||||
if ( alloc_count!=0 || object_count!=0 )
|
||||
{
|
||||
EH_STD::cerr<<"\nEH TEST FAILURE !\n";
|
||||
PrintTestName(true);
|
||||
if (alloc_count)
|
||||
EH_STD::cerr<<"ERROR : "<<alloc_count<<" outstanding allocations.\n";
|
||||
if (object_count)
|
||||
EH_STD::cerr<<"ERROR : "<<object_count<<" non-destroyed objects.\n";
|
||||
alloc_count = object_count = 0;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*===================================================================================
|
||||
PrintTestName
|
||||
|
||||
EFFECTS: Prints information about the current test. If err is false, ends with
|
||||
an ellipsis, because the test is ongoing. If err is true an error is being
|
||||
reported, and the output ends with an endl.
|
||||
====================================================================================*/
|
||||
|
||||
void
|
||||
TestController::PrintTestName(bool err) {
|
||||
if (current_container)
|
||||
EH_STD::cerr<<"["<<current_container<<"] :";
|
||||
EH_STD::cerr<<"testing "<<current_test <<" (" << current_test_category <<")";
|
||||
if (err)
|
||||
EH_STD::cerr<<EH_STD::endl;
|
||||
else
|
||||
EH_STD::cerr<<" ... ";
|
||||
}
|
||||
|
||||
void TestController::ReportSuccess(int count) {
|
||||
if (nc_verbose)
|
||||
EH_STD::cerr<<(count+1)<<" try successful"<<EH_STD::endl;
|
||||
}
|
||||
|
||||
long& TestController::Failure_threshold()
|
||||
{
|
||||
static long failure_threshold = kNotInExceptionTest;
|
||||
return failure_threshold;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user