[DEV] add an allocator checker

This commit is contained in:
Edouard DUPIN 2017-10-19 14:51:48 +02:00
parent 2a02c0c0be
commit 49f30a03e0
16 changed files with 1098 additions and 110 deletions

View File

@ -11,6 +11,7 @@
#include <echrono/Steady.hpp>
#include <echrono/Duration.hpp>
#include <etk/os/FSNode.hpp>
#include <etk/Allocator.hpp>
static int32_t nbTimeInit = 0;
@ -207,19 +208,31 @@ int32_t etest::runAllTest() {
if (it->getTestGroup() != itGroup) {
continue;
}
ETEST_PRINT("[ RUN ] " << itGroup << "." << it->getTestName());
it->clearLocal();
g_currentTest = it;
echrono::Steady ticTest = echrono::Steady::now();
it->run();
echrono::Steady tocTest = echrono::Steady::now();
g_currentTest = nullptr;
if (it->getError() == true) {
ETEST_PRINT("[ FAIL ] " << itGroup << "." << it->getTestName() << " (" << (tocTest - ticTest) << ")");
errorCount++;
} else {
ETEST_PRINT("[ OK ] " << itGroup << "." << it->getTestName() << " (" << (tocTest - ticTest) << ")");
#if ETK_MEMORY_CHECKER >= 0
uint64_t* memorySnapShoot = etk::memory::createSnapshoot();
#endif
{
ETEST_PRINT("[ RUN ] " << itGroup << "." << it->getTestName());
it->clearLocal();
g_currentTest = it;
echrono::Steady ticTest = echrono::Steady::now();
it->run();
echrono::Steady tocTest = echrono::Steady::now();
g_currentTest = nullptr;
if (it->getError() == true) {
ETEST_PRINT("[ FAIL ] " << itGroup << "." << it->getTestName() << " (" << (tocTest - ticTest) << ")");
errorCount++;
} else {
ETEST_PRINT("[ OK ] " << itGroup << "." << it->getTestName() << " (" << (tocTest - ticTest) << ")");
}
}
#if ETK_MEMORY_CHECKER >= 0
ETEST_DEBUG("[ MEM ] CHECK memory properties");
bool ret = etk::memory::checkSnapshoot(memorySnapShoot);
etk::memory::clearSnapshoot(memorySnapShoot);
memorySnapShoot = nullptr;
ETEST_DEBUG("[ MEM ] CHECK memory properties (done)");
#endif
}
echrono::Steady tocGroup = echrono::Steady::now();
ETEST_PRINT("[++++++++++] " << count << " test from " << itGroup << " (" << (tocGroup - ticGroup) << ")");
@ -229,6 +242,7 @@ int32_t etest::runAllTest() {
if (errorCount != 0) {
ETEST_PRINT("[== FAIL ==] Have " << errorCount << " test fail");
}
ETK_MEM_SHOW_LOG();
return -errorCount;
}

View File

@ -140,7 +140,8 @@ namespace etest {
void run() override; \
}; \
\
uint32_t TEST_CLASS_NAME(groupName, localName)::registerElement = etest::registerTest(new TEST_CLASS_NAME(groupName, localName)); \
uint32_t TEST_CLASS_NAME(groupName, localName)::registerElement = etest::registerTest(\
etk::memory::allocatorNewFull<TEST_CLASS_NAME(groupName, localName)>("etest_test_class", nullptr, __LINE__, __FILE__)); \
\
void TEST_CLASS_NAME(groupName, localName)::run()

View File

@ -26,3 +26,721 @@ void operator delete[] (void* ptr) {
*/
#if ETK_MEMORY_CHECKER > 0
#include <pthread.h>
#define ETK_MEM_DEBUG_LEVEL 4
#define ETK_MEMORY_PRINT(...) \
do { \
printf("[PRINT] "); \
printf(__VA_ARGS__); \
printf("\n"); \
} while (false)
#if ETK_MEM_DEBUG_LEVEL > 0
#define ETK_MEMORY_ERROR(...) \
do { \
printf("[ERROR] "); \
printf(__VA_ARGS__); \
printf("\n"); \
} while (false)
#else
#define ETK_MEMORY_ERROR(...) do {} while (false)
#endif
#if ETK_MEM_DEBUG_LEVEL > 1
#define ETK_MEMORY_WARNING(...) \
do { \
printf("[WARNING] "); \
printf(__VA_ARGS__); \
printf("\n"); \
} while (false)
#else
#define ETK_MEMORY_WARNING(...) do {} while (false)
#endif
#if ETK_MEM_DEBUG_LEVEL > 2
#define ETK_MEMORY_INFO(...) \
do { \
printf("[INFO] "); \
printf(__VA_ARGS__); \
printf("\n"); \
} while (false)
#else
#define ETK_MEMORY_INFO(...) do {} while (false)
#endif
#if ETK_MEM_DEBUG_LEVEL > 3
#define ETK_MEMORY_DEBUG(...) \
do { \
printf("[DEBUG] "); \
printf(__VA_ARGS__); \
printf("\n"); \
} while (false)
#else
#define ETK_MEMORY_DEBUG(...) do {} while (false)
#endif
#if ETK_MEM_DEBUG_LEVEL > 4
#define ETK_MEMORY_VERBOSE(...) \
do { \
printf("[VERBOSE] "); \
printf(__VA_ARGS__); \
printf("\n"); \
} while (false)
#else
#define ETK_MEMORY_VERBOSE(...) do {} while (false)
#endif
#if ETK_MEMORY_CHECKER > 1
// Max stric size of filename, variable Name, and fonction Name
#define ETK_MEM_MAX_STRING_SIZE (77)
#endif
/**
* @brief Class to save allocation elements
*/
class MemoryElementSystem {
public:
bool used; //!< for list system
char* pointerAllocated; //!< pointer really allocated
char* pointerGiveToUser; //!< pointer sent to the USER (in case of check of memory overflow)
size_t sizeUser; //!< User request size
size_t sizeAllocate; //!< data size really allocated by the tool
size_t sizeData; //!< current data size of allocated memory
#if ETK_MEMORY_CHECKER > 1
size_t id; //!< Element ID to know the allocation Order
char variableName[ETK_MEM_MAX_STRING_SIZE]; //!< Variable name when allocate
char functionName[ETK_MEM_MAX_STRING_SIZE]; //!< function name that allocate this buffer
char fileName[ETK_MEM_MAX_STRING_SIZE]; //!< function name that allocate this buffer
size_t functionLine; //!< function line where the buffer was allocated
#endif
};
class memoryAllocatorHandle {
private:
// to prevent double access:
pthread_mutex_t m_mutex;
#if ETK_MEMORY_CHECKER > 1
// Basic header to check the memory everflow (abstract element)
uint8_t* m_blockCheckMemory;
// To know the size of pre header and Post-header
uint32_t m_checkBorneSize;
#endif
// To do statictic memory allocation (Total of memory allocate from the start of program)
uint64_t m_totalMemAllocated;
// To do statictic memory allocation (Current size of allocated memory)
uint64_t m_currentMemAllocated;
// To do statictic memory allocation (Current size of allocated memory)
int64_t m_currentMemAllocatedCount;
int64_t m_currentMemAllocatedCountSize[64];
int64_t m_totalMemAllocatedCountSize[64];
// To do statictic memory allocation (Max of memory allocated in the same Time)
uint64_t m_maxMemoryAllocated;
// To do statictic memory allocation (number of allocation)
int64_t m_dynamicID;
// To know if this memory system is initialized
bool m_memSystemInitialize;
// List of element to remember allocate...
size_t m_memListElementSize;
MemoryElementSystem* m_memListElements;
public:
memoryAllocatorHandle():
m_mutex(PTHREAD_MUTEX_INITIALIZER),
#if ETK_MEMORY_CHECKER > 1
// Basic header to check the memory everflow (abstract element)
m_blockCheckMemory(nullptr),
m_checkBorneSize(10*8),
#endif
m_totalMemAllocated(0),
m_currentMemAllocated(0),
m_currentMemAllocatedCount(0),
m_maxMemoryAllocated(0),
m_dynamicID(0),
m_memSystemInitialize(false),
m_memListElementSize(1024),
m_memListElements(nullptr) {
#if ETK_MEMORY_CHECKER > 1
static const uint8_t blockCheckMemory[] = {
0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88,
0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00,
0x55, 0xAA, 0x5A, 0xA5, 0x11, 0xFF, 0x15, 0xB2,
0x55, 0xAA, 0x5A, 0xA5, 0x11, 0xFF, 0x15, 0xB2,
0x55, 0xAA, 0x5A, 0xA5, 0x11, 0xFF, 0x15, 0xB2,
0x55, 0xAA, 0x5A, 0xA5, 0x11, 0xFF, 0x15, 0xB2,
0x55, 0xAA, 0x5A, 0xA5, 0x11, 0xFF, 0x15, 0xB2,
0x55, 0xAA, 0x5A, 0xA5, 0x11, 0xFF, 0x15, 0xB2,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
};
m_blockCheckMemory = (uint8_t*)blockCheckMemory;
#endif
lock();
memset(m_totalMemAllocatedCountSize, 0, sizeof(m_totalMemAllocatedCountSize));
memset(m_currentMemAllocatedCountSize, 0, sizeof(m_currentMemAllocatedCountSize));
if (m_memSystemInitialize == true) {
return;
}
int systemRet;
if (m_memListElements == nullptr) {
m_memListElements = new MemoryElementSystem[m_memListElementSize];
}
for (size_t iii=0; iii<m_memListElementSize; ++iii) {
m_memListElements[iii].used = false;
}
m_memSystemInitialize = true;
unLock();
}
/**
* @brief Update statistique
* @param[in] _dataSize Allocated size
*/
void addMemory(size_t _dataSize) {
m_totalMemAllocated += _dataSize;
m_currentMemAllocated += _dataSize;
if (m_currentMemAllocated > m_maxMemoryAllocated) {
m_maxMemoryAllocated = m_currentMemAllocated;
}
m_currentMemAllocatedCount++;
for (int32_t iii=0; iii<64; ++iii) {
if (_dataSize <= (uint64_t(1) << iii)) {
m_totalMemAllocatedCountSize[iii]++;
break;
}
}
for (int32_t iii=0; iii<64; ++iii) {
if (_dataSize <= (uint64_t(1) << iii)) {
m_currentMemAllocatedCountSize[iii]++;
break;
}
}
}
void lock() {
pthread_mutex_lock(&m_mutex);
}
void unLock() {
pthread_mutex_unlock(&m_mutex);
}
/**
* @brief Update memory statistique
* @param[in] dataSize Removed size.
*/
void removeMemory(size_t _dataSize) {
m_currentMemAllocated -= _dataSize;
m_currentMemAllocatedCount--;
for (int32_t iii=0; iii<64; ++iii) {
if (_dataSize <= (uint64_t(1) << iii)) {
m_currentMemAllocatedCountSize[iii]--;
break;
}
}
}
/**
* @brief Get a current free element of the structure
* @return the free Element find or nullptr
*/
MemoryElementSystem* getFreeElement() {
for (size_t iii=0; iii<m_memListElementSize; ++iii) {
if (m_memListElements[iii].used == false) {
return &(m_memListElements[iii]);
}
}
// resize Linker size:
m_memListElementSize *= 2;
ETK_MEMORY_DEBUG("Realloate the allocator memory system: %ld", uint64_t(m_memListElementSize));
MemoryElementSystem* tmp = new MemoryElementSystem[m_memListElementSize];
if (tmp == nullptr) {
m_memListElementSize /= 2;
return nullptr;
}
for (size_t iii=0; iii<m_memListElementSize; ++iii) {
tmp[iii].used = false;
}
memcpy(tmp, m_memListElements, sizeof(MemoryElementSystem) * m_memListElementSize / 2);
delete[] m_memListElements;
m_memListElements = tmp;
// try again
for (size_t iii=0; iii<m_memListElementSize; ++iii) {
if (m_memListElements[iii].used == false) {
return &(m_memListElements[iii]);
}
}
return nullptr;
}
/**
* @brief Get the element structure reference if it existed
* @param[in] pointerAdresse pointer to retreave the element
* @return get the element reference for the curent adress pointer
*/
MemoryElementSystem *getAdressedElement(char* _pointerAdresse) {
for (size_t iii=0; iii<m_memListElementSize; ++iii) {
if (m_memListElements[iii].used == true) {
if (m_memListElements[iii].pointerGiveToUser == _pointerAdresse) {
return &(m_memListElements[iii]);
}
}
}
return nullptr;
}
#if ETK_MEMORY_CHECKER > 1
/**
* @brief Verify the curent Memory header
* This function vereify the memeory with the common header and header size.
* @param[in] pointerAdresse Start pointer to verify data
* @return the check result :
* - true : if an error existe
* - false : if no error
*/
bool checkMem(char* _pointerAdresse) {
uint8_t *pointer = (uint8_t*)_pointerAdresse;
for (size_t iii=0; iii<m_checkBorneSize; ++iii) {
if (*(pointer++) != m_blockCheckMemory[iii]) {
return true;
}
}
return false;
}
#endif
#if ETK_MEMORY_CHECKER > 1
/**
* @brief Display the current buffer to check error.
* Desactivated by debault (only for extreme debug)
* @param[in] _pointerAdresse pointer to start the print
* @param[in] _size number of char to display
*/
void displayBuffer(char* _pointerAdresse, uint32_t _size) {
/*
uint8_t *pointer = (uint8_t *)_pointerAdresse;
uint32_t i;
for (i=0; i<_size ;i++) {
if (i%50 == 0) {
printf("\n");
}
printf("%02X ", pointer[i]);
}
printf("\n");
*/
}
#endif
#if ETK_MEMORY_CHECKER > 1
/**
* @brief Get the filename (without all the Path)
* @param[in] _fileLink pointer on the name with the Path
* @return The last pointer of the filename
*/
const char *getFileName(const char* _fileLink) {
const char *element_2 = _fileLink;
const char *element_1 = _fileLink;
const char *element_0 = _fileLink;
const char * pch = nullptr;
pch = _fileLink;
while (pch != nullptr) {
element_2 = element_1;
element_1 = element_0;
element_0 = pch;
pch = strchr(pch+1, '/');
}
return element_2;
}
#endif
void displayMemoryProperty(MemoryElementSystem& _element) {
#if ETK_MEMORY_CHECKER > 1
bool errorOccured = false;
ETK_MEMORY_WARNING("Not FREE : %p ==> %p : %ld Bytes var=%s",
_element.pointerAllocated,
_element.pointerGiveToUser,
_element.sizeUser,
_element.variableName);
ETK_MEMORY_WARNING("%8d : %s() line=%ld file=%s",
(uint32_t)_element.id,
_element.functionName,
_element.functionLine,
_element.fileName);
if (checkMem(_element.pointerAllocated) == true) {
ETK_MEMORY_ERROR("MEM LOG (L): %s : %ld Bytes @ %p ==> user @ %p (depassement pre)",
_element.variableName,
_element.sizeUser,
_element.pointerAllocated,
_element.pointerGiveToUser);
errorOccured = true;
}
if (checkMem(_element.pointerAllocated + _element.sizeUser + m_checkBorneSize) == true) {
ETK_MEMORY_ERROR("MEM LOG (L): %s : %ld Bytes @ %p ==> user @ %p (depassement post)",
_element.variableName,
_element.sizeUser,
_element.pointerAllocated,
_element.pointerGiveToUser);
errorOccured = true;
}
if (errorOccured == true) {
displayBuffer(_element.pointerAllocated,
_element.sizeAllocate);
assert(false);
}
#else
ETK_MEMORY_WARNING("Not LOG : %p ==> %p : %d Bytes",
_element.pointerAllocated,
_element.pointerGiveToUser,
_element.sizeUser);
#endif
}
uint64_t* createSnapshoot() {
lock();
size_t countElement = 0;
for (size_t iii=0; iii<m_memListElementSize; ++iii) {
if (m_memListElements[iii].used == true) {
countElement++;
}
}
if (countElement == 0) {
unLock();
return nullptr;
}
ETK_MEMORY_VERBOSE("find %ld element in memory", (uint64_t)countElement);
uint64_t* out = new uint64_t[countElement+10];
memset(out, 0, sizeof(uint64_t)*(countElement+10));
countElement = 0;
for (size_t iii=0; iii<m_memListElementSize; ++iii) {
if (m_memListElements[iii].used == true) {
out[countElement++] = uint64_t(m_memListElements[iii].pointerAllocated);
}
}
unLock();
return out;
}
bool checkSnapshoot(uint64_t* _handle) {
if (_handle == nullptr) {
return false;
}
lock();
bool haveError = false;
for (size_t iii=0; iii<m_memListElementSize; ++iii) {
if (m_memListElements[iii].used == true) {
uint64_t* dataBase = _handle;
bool find = false;
size_t jjj = 0;
while (dataBase[jjj] != 0) {
if (dataBase[jjj] == uint64_t(m_memListElements[iii].pointerAllocated)) {
find = true;
break;
}
jjj++;
//dataBase++;
}
if (find == false) {
haveError = true;
displayMemoryProperty(m_memListElements[iii]);
}
}
}
unLock();
return haveError == false;
}
void clearSnapshoot(uint64_t* _handle) {
if (_handle == nullptr) {
return;
}
delete[] (uint64_t*)_handle;
}
void* allocate(size_t _num,
size_t _size,
const char* _variableName,
const char* _functionName,
int32_t _line,
const char* _fileName) {
MemoryElementSystem* myElement;
lock();
m_dynamicID++;
myElement = getFreeElement();
// check free handle
if (myElement != nullptr) {
#if ETK_MEMORY_CHECKER > 1
const char *fileNameShort = nullptr;
myElement->id = m_dynamicID;
#endif
// if an element is free :
myElement->sizeUser = _size * _num;
myElement->sizeData = _size;
#if ETK_MEMORY_CHECKER > 1
myElement->sizeAllocate = myElement->sizeUser + m_checkBorneSize*2;
if (_variableName == nullptr) {
strncpy(myElement->variableName, "---", ETK_MEM_MAX_STRING_SIZE);
} else {
strncpy(myElement->variableName, _variableName, ETK_MEM_MAX_STRING_SIZE);
}
myElement->variableName[ETK_MEM_MAX_STRING_SIZE-1] = 0;
if (_functionName == nullptr) {
strncpy(myElement->functionName, "---", ETK_MEM_MAX_STRING_SIZE);
} else {
strncpy(myElement->functionName, _functionName, ETK_MEM_MAX_STRING_SIZE);
}
myElement->functionName[ETK_MEM_MAX_STRING_SIZE-1] = 0;
if (_fileName == nullptr) {
strncpy(myElement->fileName, "---", ETK_MEM_MAX_STRING_SIZE);
} else {
fileNameShort = getFileName(_fileName);
strncpy(myElement->fileName, fileNameShort, ETK_MEM_MAX_STRING_SIZE);
}
myElement->fileName[ETK_MEM_MAX_STRING_SIZE-1] = 0;
myElement->functionLine = _line;
#else
myElement->sizeAllocate = myElement->sizeUser;
#endif
myElement->pointerAllocated = nullptr;
myElement->pointerGiveToUser = nullptr;
// real allocation :
myElement->pointerAllocated = new char[myElement->sizeAllocate];
if (myElement->pointerAllocated != nullptr) {
// set edded memory
addMemory(myElement->sizeUser);
// save curent pointer
#if ETK_MEMORY_CHECKER > 1
myElement->pointerGiveToUser = myElement->pointerAllocated + m_checkBorneSize;
#else
myElement->pointerGiveToUser = myElement->pointerAllocated;
#endif
ETK_MEMORY_VERBOSE("MEM allocate (L): %s : %ld Bytes @ %p ==> user @ %p", _variableName, _num*_size, myElement->pointerAllocated, myElement->pointerGiveToUser);
// set bornes:
#if ETK_MEMORY_CHECKER > 1
memcpy(myElement->pointerAllocated, m_blockCheckMemory, m_checkBorneSize);
#endif
#if ETK_MEMORY_CHECKER > 1
memcpy(myElement->pointerAllocated + myElement->sizeUser + m_checkBorneSize, m_blockCheckMemory, m_checkBorneSize);
#endif
// add to the elements list
myElement->used = true;
} else {
ETK_MEMORY_VERBOSE("MEM allocate (L): %s : %zu Bytes @ (ERROR)", _variableName, myElement->sizeUser);
}
unLock();
// else : no memory allocated ==> nothing to save
return myElement->pointerGiveToUser;
} else {
// if no free handle:
void * localPointer = nullptr;
localPointer = new char[_num * _size];
if (localPointer != nullptr) {
ETK_MEMORY_VERBOSE("MEM allocate (-): %s : %lu Bytes @ %p (No log...)", _variableName, _num*_size, localPointer);
// set edded memory
//addMemory(_num * _size); // not availlable can not un add memory
m_totalMemAllocated += _num * _size;
} else {
ETK_MEMORY_VERBOSE("MEM allocate (-): %s : %lu Bytes @ (ERROR)", _variableName, _num*_size);
}
unLock();
return localPointer;
}
}
void remove(void* _pointerData, const char* _variableName, const char* _functionName, int32_t _line, const char* _fileName) {
MemoryElementSystem * myElement;
lock();
char* asyncFree = nullptr;
myElement = getAdressedElement((char*)_pointerData);
// check free handle
if (myElement != nullptr) {
bool errorOccured = false;
// We know this element :
#if ETK_MEMORY_CHECKER > 1
// check end and Start :
if (checkMem(myElement->pointerAllocated) == true) {
ETK_MEMORY_ERROR("MEM free (L): %s : %zu Bytes @ %p ==> user @ %p (depassement pre)",_variableName, myElement->sizeUser, myElement->pointerAllocated, myElement->pointerGiveToUser);
errorOccured = true;
}
if (checkMem(myElement->pointerAllocated + myElement->sizeUser + m_checkBorneSize) == true) {
ETK_MEMORY_ERROR("MEM free (L): %s : %zu Bytes @ %p ==> user @ %p (depassement post)",_variableName, myElement->sizeUser, myElement->pointerAllocated, myElement->pointerGiveToUser);
errorOccured = true;
}
if (errorOccured == false) {
ETK_MEMORY_VERBOSE("MEM free (L): %s : %zu Bytes @ %p ==> user @ %p",_variableName, myElement->sizeUser, myElement->pointerAllocated, myElement->pointerGiveToUser);
} else {
displayBuffer(myElement->pointerAllocated, myElement->sizeAllocate);
//ETK_ASSERT(1 == 0, "Memory error detected");
}
#else
ETK_MEMORY_VERBOSE("MEM free (L): %s : %d Bytes @ %p ==> user @ %p",_variableName, myElement->sizeUser, myElement->pointerAllocated, myElement->pointerGiveToUser);
#endif
asyncFree = myElement->pointerAllocated;
myElement->pointerAllocated = nullptr;
removeMemory(myElement->sizeUser);
myElement->used = false;
}
unLock();
if (asyncFree != nullptr) {
// free Buffer:
delete[] asyncFree;
return;
}
//Unknown element
ETK_MEMORY_WARNING("MEM free (-): %s : ?? Bytes @ %p ==> unsaved element",_variableName, _pointerData);
delete (char*)_pointerData;
}
void displayMemorySize(size_t _size, const char* _name) {
if (_size > 1024*1024*1024) {
uint32_t teraByte = _size/(1024*1024*1024);
uint32_t megaByte = (_size/(1024*1024)%1024);
uint32_t kiloByte = (_size/1024) % 1024;
uint32_t byte = _size % 1024;
ETK_MEMORY_DEBUG("MEM : %s: %4dT %4dM %4dk %4dB", _name, teraByte, megaByte, kiloByte, byte);
} else if (_size > 1024*1024) {
uint32_t megaByte = _size/(1024*1024);
uint32_t kiloByte = (_size/1024) % 1024;
uint32_t byte = _size % 1024;
ETK_MEMORY_DEBUG("MEM : %s: %4dM %4dk %4dB", _name, megaByte, kiloByte, byte);
} else if (m_totalMemAllocated > 1024) {
uint32_t megaByte = _size/(1024*1024);
uint32_t kiloByte = (_size/1024) % 1024;
uint32_t byte = _size % 1024;
ETK_MEMORY_DEBUG("MEM : %s: %4dk %4dB", _name, kiloByte, byte);
} else {
uint32_t megaByte = _size/(1024*1024);
uint32_t kiloByte = (_size/1024) % 1024;
uint32_t byte = _size % 1024;
ETK_MEMORY_DEBUG("MEM : %s: %4dB", _name, byte);
}
}
void display(bool _statusOnly) {
lock();
ETK_MEMORY_DEBUG("MEM: Log : ------------------------------");
ETK_MEMORY_DEBUG("MEM: (current/total) allocation: %ld / %ld ", int64_t(m_currentMemAllocatedCount), uint64_t(m_dynamicID));
for (int32_t iii=0; iii<64; ++iii) {
if (m_currentMemAllocatedCountSize[iii] != 0) {
ETK_MEMORY_DEBUG("MEM: Number (current/Total) of allocation: 2<<%2d: %8ld / %8ld %9ld Bytes",
iii,
uint64_t(m_currentMemAllocatedCountSize[iii]),
uint64_t(m_totalMemAllocatedCountSize[iii]),
(uint64_t(1)<<iii));
}
}
ETK_MEMORY_DEBUG("MEM: number of element that can be registered %ld", m_memListElementSize);
displayMemorySize(m_memListElementSize*sizeof(MemoryElementSystem) + sizeof(memoryAllocatorHandle), "System allocator ");
displayMemorySize(m_totalMemAllocated, "Total allocated ");
displayMemorySize(m_currentMemAllocated, "Total Current Use ");
displayMemorySize(m_maxMemoryAllocated, "Max simultaneous Use ");
if (_statusOnly == true) {
unLock();
return;
}
ETK_MEMORY_DEBUG("MEM : Log : ----------- Memory -----------");
for (size_t iii=0; iii<m_memListElementSize; ++iii) {
if (m_memListElements[iii].used == true) {
displayMemoryProperty(m_memListElements[iii]);
}
}
ETK_MEMORY_DEBUG("MEM : -----------------------------------");
unLock();
}
bool check() {
bool detectError = false;
lock();
for (size_t iii=0; iii<m_memListElementSize; ++iii) {
if (m_memListElements[iii].used == true) {
#if ETK_MEMORY_CHECKER > 1
bool errorOccured = false;
if (checkMem(m_memListElements[iii].pointerAllocated) == true) {
ETK_MEMORY_ERROR("MEM CHECK (L): %s : %ld Bytes @ %p ==> user @ %p (depassement pre)",m_memListElements[iii].variableName, m_memListElements[iii].sizeUser, m_memListElements[iii].pointerAllocated, m_memListElements[iii].pointerGiveToUser);
errorOccured = true;
}
if (checkMem(m_memListElements[iii].pointerAllocated + m_memListElements[iii].sizeUser + m_checkBorneSize) == true) {
ETK_MEMORY_ERROR("MEM CHECK (L): %s : %ld Bytes @ %p ==> user @ %p (depassement post)",m_memListElements[iii].variableName, m_memListElements[iii].sizeUser, m_memListElements[iii].pointerAllocated, m_memListElements[iii].pointerGiveToUser);
errorOccured = true;
}
if (errorOccured == true) {
detectError = true;
displayBuffer(m_memListElements[iii].pointerAllocated, m_memListElements[iii].sizeAllocate);
// Clean all the erreor to prevent the other error display
memcpy(m_memListElements[iii].pointerAllocated, m_blockCheckMemory, m_checkBorneSize);
// Clean all the erreor to prevent the other error display
memcpy(m_memListElements[iii].pointerAllocated + m_memListElements[iii].sizeUser + m_checkBorneSize, m_blockCheckMemory, m_checkBorneSize);
}
#endif
}
}
unLock();
return detectError;
}
bool checkPointer(void* _pointer) {
lock();
for (size_t iii=0; iii<m_memListElementSize; ++iii) {
if (m_memListElements[iii].used == true) {
bool find = false;
if (m_memListElements[iii].pointerAllocated == _pointer) {
find = true;
}
if (m_memListElements[iii].pointerGiveToUser == _pointer) {
find = true;
}
if (find == true) {
unLock();
return true;
}
}
}
unLock();
ETK_MEMORY_ERROR("MEM Check pointer: Can not find the pointer in the system DB...");
return false;
}
};
// This permit to initialize the handle just in time ...
static memoryAllocatorHandle& getHandle() {
static memoryAllocatorHandle tmp;
return tmp;
}
uint64_t* etk::memory::createSnapshoot() {
return getHandle().createSnapshoot();
}
bool etk::memory::checkSnapshoot(uint64_t* _handle) {
return getHandle().checkSnapshoot(_handle);
}
void etk::memory::clearSnapshoot(uint64_t* _handle) {
getHandle().clearSnapshoot(_handle);
}
void* etk::memory::allocate(size_t _num,
size_t _size,
const char* _variableName,
const char* _functionName,
int32_t _line,
const char* _fileName) {
return getHandle().allocate(_num, _size, _variableName, _functionName, _line, _fileName);
}
void etk::memory::remove(void* _pointerData, const char* _variableName, const char* _functionName, int32_t _line, const char* _fileName) {
getHandle().remove(_pointerData, _variableName, _functionName, _line, _fileName);
}
void etk::memory::display(bool _statusOnly) {
getHandle().display(_statusOnly);
}
bool etk::memory::check() {
return getHandle().check();
}
bool etk::memory::checkPointer(void* _pointer) {
return getHandle().checkPointer(_pointer);
}
#endif

View File

@ -16,3 +16,170 @@
}
#endif
#define ETK_MEMORY_CHECKER 2
#ifndef ETK_MEMORY_CHECKER
#define ETK_MEMORY_CHECKER 0
#endif
#if ETK_MEMORY_CHECKER >= 0
namespace etk {
namespace memory {
/**
* @brief Create an allocation memory and set start and stop header. Log in the curent structure.
* If no more free element in the basic structure, the system allocate without saving information and header start and stop
* @param[in] _num number of alament needed to allocate
* @param[in] _size Size of one element to allocate
* @param[in] _variableName Variable name to allocate (must be a real static cont never removed)
* @param[in] _functionName Fonction Name where allocation is done (must be a real static cont never removed)
* @param[in] _line Line where allocation is done.
* @param[in] _fileName File where allocation is done. (must be a real static cont never removed)
* @return pointer on the current memory allocation. (or NULL if an error occured)
*/
void* allocate(size_t _num, size_t _size, const char* _variableName, const char* _functionName, int32_t _line, const char* _fileName);
/**
* @brief Free Memory with the dedicate pointer
* If the memory is not saved the current pointer is free, else we get the real pointer and free it
* @param[in,out] _pointerData User pointer Data.
* @param[in] _variableName Variable name where free is done. (must be a real static cont never removed)
* @param[in] _functionName Fonction name where free is done. (must be a real static cont never removed)
* @param[in] _line line where free is done.
* @param[in] _fileName file where free is done. (must be a real static cont never removed)
*/
void remove(void* _pointerData, const char* _variableName, const char* _functionName, int32_t _line, const char* _fileName);
/**
* @brief Display all memory not free by this system.
* @param[in] _statusOnly Display only the memory allocation status.
*/
void display(bool _statusOnly=true);
/**
* @brief Check if memory have not write out of the range.
*/
bool check();
/**
* @brief Check if the pointer is already register in the allocator (can not predist the size, but permti to know where the error came from in debug mode
* @param[in] _pointerPointer on the data to check
* @return true the pointer is set
* @return false the pointer is not set
*/
bool checkPointer(void* _pointer);
/**
* @brief Create a snapshoot of the memory
* @return handle on the snapshoot
*/
uint64_t* createSnapshoot();
/**
* @brief Check if a snapshoot is correct (no change)
* @param[in] _handle Handle on the snapshoot
* @return true the memory is identical
*/
bool checkSnapshoot(uint64_t* _handle);
/**
* @brief Free the snapshoot handle
* @param[in] _handle Handle on the snapshoot
*/
void clearSnapshoot(uint64_t* _handle);
template<class ETK_TYPE,
class... ETK_MEMORY_ARGS>
ETK_TYPE* allocatorNew(ETK_MEMORY_ARGS&& ... _args) {
char* tmp = (char*)etk::memory::allocate(1, sizeof(ETK_TYPE), "new", __func__, __LINE__, __FILE__);
return new (tmp) ETK_TYPE(etk::forward<ETK_MEMORY_ARGS>(_args)...);
}
template<class ETK_TYPE,
class... ETK_MEMORY_ARGS>
ETK_TYPE* allocatorNewSize(size_t _size, ETK_MEMORY_ARGS&& ... _args) {
char* tmp = (char*)etk::memory::allocate(_size, sizeof(ETK_TYPE), "new", __func__, __LINE__, __FILE__);
return new (tmp) ETK_TYPE(etk::forward<ETK_MEMORY_ARGS>(_args)...);
}
template<class ETK_TYPE,
class... ETK_MEMORY_ARGS>
ETK_TYPE* allocatorNewFull(const char* _variableName,
const char* _functionName,
int32_t _line,
const char* _fileName,
ETK_MEMORY_ARGS&& ... _args) {
char* tmp = (char*)etk::memory::allocate(1, sizeof(ETK_TYPE), _variableName, _functionName, _line, _fileName);
return new (tmp) ETK_TYPE(etk::forward<ETK_MEMORY_ARGS>(_args)...);
}
template<class ETK_TYPE>
void allocatorDelete(ETK_TYPE* _element,
const char* _variableName = "",
const char* _functionName = "",
int32_t _line = __LINE__,
const char* _fileName = __FILE__) {
if (_element == nullptr) {
return;
}
_element->~ETK_TYPE();
etk::memory::remove((void*)_element, _variableName, _functionName, _line, _fileName);
_element = nullptr;
}
}
}
#define ETK_NEW(type, ...) \
new ((char*)etk::memory::allocate(1, sizeof(type), #type, __func__, __LINE__, __FILE__)) type(__VA_ARGS__)
#define ETK_DELETE(type, pointerData) \
etk::memory::allocatorDelete((type*)(pointerData), #type, __func__, __LINE__, __FILE__)
#define ETK_MALLOC(type, nbElements) \
((type *)etk::memory::allocate( (nbElements), sizeof(type), #type, __func__, __LINE__, __FILE__))
#define ETK_FREE(type, pointerData) \
etk::memory::remove( (pointerData), #type, __func__, __LINE__, __FILE__)
#define ETK_MEM_SHOW_LOG(...) \
etk::memory::display(__VA_ARGS__)
#define ETK_MEM_CHECK() \
etk::memory::check()
#else
namespace etk {
namespace memory {
template<class ETK_TYPE,
class... T_ARGS>
ETK_TYPE* allocatorNew(T_ARGS&& ... _args) {
return new ETK_TYPE(etk::forward<ETK_MEMORY_ARGS>(_args)...);
}
template<class ETK_TYPE,
class... T_ARGS>
ETK_TYPE* allocatorNewFull(const char* _variableName,
const char* _functionName,
int32_t _line,
const char* _fileName,
ETK_MEMORY_ARGS&& ... _args) {
return new ETK_TYPE(etk::forward<ETK_MEMORY_ARGS>(_args)...);
}
template<class ETK_TYPE>
void allocatorDelete(ETK_TYPE* _element,
const char* _variableName = "",
const char* _functionName = "",
int32_t _line = __LINE__,
const char* _fileName = __FILE__) {
delete _element;
}
}
}
#define ETK_NEW(type, ...) \
new type(__VA_ARGS__)
#define ETK_DELETE(type, pointerData) \
delete ((type*)(pointerData))
#define ETK_MALLOC(dataType, nbElements) \
((dataType *)new dataType[nbElements]
#define ETK_FREE(type, pointerData) \
delete[] (type*)pointerData
#define ETK_MEM_SHOW_LOG(...) \
do { } while(false)
#define ETK_MEM_CHECK() \
do {} while(false)
#endif

View File

@ -40,12 +40,12 @@ namespace etk {
public:
FunctionPrivateLambda(ETK_TYPE_FUNCTION_FUNCTOR _functor):
m_dataPointer(_functor) {
ETK_FUNCTION_DEBUG(" NEW FunctionPrivateLambda \n");
ETK_FUNCTION_DEBUG(" CREATE FunctionPrivateLambda \n");
}
/*
FunctionPrivateLambda(const ETK_TYPE_FUNCTION_FUNCTOR& _functor):
m_dataPointer(_functor) {
ETK_FUNCTION_DEBUG(" NEW FunctionPrivateLambda \n");
ETK_FUNCTION_DEBUG(" CREATE FunctionPrivateLambda \n");
}
*/
~FunctionPrivateLambda() {
@ -56,7 +56,7 @@ namespace etk {
}
FunctionPrivate<ETK_TYPE_FUNCTION_RETURN(ETK_TYPE_FUNCTION_ARGS...)>* copy() {
ETK_FUNCTION_DEBUG(" COPY FunctionPrivateLambda \n");
return new FunctionPrivateLambda(m_dataPointer);
return ETK_NEW(FunctionPrivateLambda, m_dataPointer);
}
};
@ -67,34 +67,35 @@ namespace etk {
template <typename ETK_TYPE_FUNCTION_RETURN, typename... ETK_TYPE_FUNCTION_ARGS>
class Function<ETK_TYPE_FUNCTION_RETURN(ETK_TYPE_FUNCTION_ARGS...)> {
private:
FunctionPrivate<ETK_TYPE_FUNCTION_RETURN(ETK_TYPE_FUNCTION_ARGS...)>* m_pointerPrivate;
typedef FunctionPrivate<ETK_TYPE_FUNCTION_RETURN(ETK_TYPE_FUNCTION_ARGS...)> FunctionPrivateTypedef;
FunctionPrivateTypedef* m_pointerPrivate;
uint32_t m_pppppp;
public:
Function():
m_pointerPrivate(nullptr) {
m_pppppp = MM___pppppp++;
ETK_FUNCTION_DEBUG("[%d=0X%lx] new Function 1 \n", m_pppppp, (uint64_t)this);
ETK_FUNCTION_DEBUG("[%d=0X%lx] create Function 1 \n", m_pppppp, (uint64_t)this);
}
Function(const etk::NullPtr&):
m_pointerPrivate(nullptr) {
m_pppppp = MM___pppppp++;
ETK_FUNCTION_DEBUG("[%d=0X%lx] new Function 2\n", m_pppppp, (uint64_t)this);
ETK_FUNCTION_DEBUG("[%d=0X%lx] create Function 2\n", m_pppppp, (uint64_t)this);
}
Function(const Function& _obj):
m_pointerPrivate(nullptr) {
m_pppppp = MM___pppppp++;
ETK_FUNCTION_DEBUG("[%d=0X%lx] new Function (copy constructor) ---------------------- [%d=0X%lx]\n", m_pppppp, (uint64_t)this, _obj.m_pppppp, (uint64_t)&_obj);
ETK_FUNCTION_DEBUG("[%d=0X%lx] create Function (copy constructor) ---------------------- [%d=0X%lx]\n", m_pppppp, (uint64_t)this, _obj.m_pppppp, (uint64_t)&_obj);
if (_obj.m_pointerPrivate != nullptr) {
m_pointerPrivate = _obj.m_pointerPrivate->copy();
}
ETK_FUNCTION_DEBUG("[%d=0X%lx] new Function (copy constructor) ------- (done) ------- [%d=0X%lx]\n", m_pppppp, (uint64_t)this, _obj.m_pppppp, (uint64_t)&_obj);
ETK_FUNCTION_DEBUG("[%d=0X%lx] create Function (copy constructor) ------- (done) ------- [%d=0X%lx]\n", m_pppppp, (uint64_t)this, _obj.m_pppppp, (uint64_t)&_obj);
}
Function(Function&& _obj):
m_pointerPrivate(nullptr) {
m_pppppp = MM___pppppp++;
ETK_FUNCTION_DEBUG("[%d] new Function 2\n", m_pppppp);
ETK_FUNCTION_DEBUG("[%d] create Function 2\n", m_pppppp);
_obj.swap(*this);
ETK_FUNCTION_DEBUG("[%d] new Function 2 (done)\n", m_pppppp);
ETK_FUNCTION_DEBUG("[%d] create Function 2 (done)\n", m_pppppp);
}
template <typename ETK_TYPE_FUNCTION_FUNCTOR,
typename etk::EnableIf< !etk::IsSame<ETK_TYPE_FUNCTION_FUNCTOR,Function>::value
@ -104,13 +105,14 @@ namespace etk {
Function(ETK_TYPE_FUNCTION_FUNCTOR _functor):
m_pointerPrivate(nullptr) {
m_pppppp = MM___pppppp++;
ETK_FUNCTION_DEBUG("[%d=0X%lx] new Function 4 \n", m_pppppp, (uint64_t)this);
m_pointerPrivate = new FunctionPrivateLambda<ETK_TYPE_FUNCTION_FUNCTOR, ETK_TYPE_FUNCTION_RETURN(ETK_TYPE_FUNCTION_ARGS...)>(_functor);
ETK_FUNCTION_DEBUG("[%d=0X%lx] new Function 4 (done)\n", m_pppppp, (uint64_t)this);
ETK_FUNCTION_DEBUG("[%d=0X%lx] create Function 4 \n", m_pppppp, (uint64_t)this);
typedef FunctionPrivateLambda<ETK_TYPE_FUNCTION_FUNCTOR, ETK_TYPE_FUNCTION_RETURN(ETK_TYPE_FUNCTION_ARGS...)> FunctionPrivateLambdaTypedef;
m_pointerPrivate = ETK_NEW(FunctionPrivateLambdaTypedef, _functor);
ETK_FUNCTION_DEBUG("[%d=0X%lx] create Function 4 (done)\n", m_pppppp, (uint64_t)this);
}
~Function() {
ETK_FUNCTION_DEBUG("[%d=0X%lx] DELETE Function \n", m_pppppp, (uint64_t)this);
delete m_pointerPrivate;
ETK_DELETE(FunctionPrivateTypedef, m_pointerPrivate);
m_pointerPrivate = nullptr;
}
ETK_TYPE_FUNCTION_RETURN operator()(ETK_TYPE_FUNCTION_ARGS... _args) const {
@ -134,7 +136,7 @@ namespace etk {
return *this;
}
Function& operator= (etk::NullPtr _obj) {
delete m_pointerPrivate;
ETK_DELETE(FunctionPrivateTypedef, m_pointerPrivate);
m_pointerPrivate = nullptr;
ETK_FUNCTION_DEBUG("[%d=0X%lx] operator = nullptr 0X%lx\n", m_pppppp, (uint64_t)this, (uint64_t)m_pointerPrivate);
return *this;

View File

@ -8,6 +8,7 @@
#include <etk/types.hpp>
#include <etk/Pair.hpp>
#include <etk/Vector.hpp>
#include <etk/Allocator.hpp>
namespace etk {
/**
@ -111,7 +112,7 @@ namespace etk {
}
/**
* @brief Incremental operator
* @return Reference on a new iterator and increment the other one
* @return Reference on an iterator and increment the other one
*/
Iterator operator++ (int32_t) {
Iterator it(*this);
@ -120,7 +121,7 @@ namespace etk {
}
/**
* @brief Decremental operator
* @return Reference on a new iterator and decrement the other one
* @return Reference on an iterator and decrement the other one
*/
Iterator operator-- (int32_t) {
Iterator it(*this);
@ -242,7 +243,8 @@ namespace etk {
typedef bool (*sortFunction)(etk::Pair<ETK_MAP_TYPE_KEY, ETK_MAP_TYPE_DATA>* const & _key1,
etk::Pair<ETK_MAP_TYPE_KEY, ETK_MAP_TYPE_DATA>* const & _key2);
private:
etk::Vector<etk::Pair<ETK_MAP_TYPE_KEY, ETK_MAP_TYPE_DATA>*> m_data; //!< Data of the Map ==> the Map table is composed of pointer, this permit to have high speed when resize the vector ...
typedef etk::Pair<ETK_MAP_TYPE_KEY, ETK_MAP_TYPE_DATA> pairType;
etk::Vector<pairType*> m_data; //!< Data of the Map ==> the Map table is composed of pointer, this permit to have high speed when resize the vector ...
sortFunction m_comparator;
public:
/**
@ -296,7 +298,7 @@ namespace etk {
if (it == nullptr) {
continue;
}
m_data.pushBack(new etk::Pair<ETK_MAP_TYPE_KEY, ETK_MAP_TYPE_DATA>(it->first, it->second));
m_data.pushBack(ETK_NEW(pairType, it->first, it->second));
}
}
void setOrdered(bool _ordered) {
@ -350,7 +352,7 @@ namespace etk {
void clear() {
for (auto &it : m_data) {
if (it != nullptr) {
delete(it);
ETK_DELETE(pairType, it);
it=nullptr;
}
}
@ -425,7 +427,7 @@ namespace etk {
void add(const ETK_MAP_TYPE_KEY& _key, const ETK_MAP_TYPE_DATA& _value) {
int64_t elementId = getId(_key);
if (elementId <0) {
etk::Pair<ETK_MAP_TYPE_KEY, ETK_MAP_TYPE_DATA>* tmp = new etk::Pair<ETK_MAP_TYPE_KEY, ETK_MAP_TYPE_DATA>(etk::move(_key), etk::move(_value));
etk::Pair<ETK_MAP_TYPE_KEY, ETK_MAP_TYPE_DATA>* tmp = ETK_NEW(pairType, etk::move(_key), etk::move(_value));
if (tmp == nullptr) {
return;
}
@ -457,7 +459,7 @@ namespace etk {
//nothing to do ==> not existed
return;
}
delete(m_data[elementId]);
ETK_DELETE(pairType, m_data[elementId]);
m_data[elementId] = nullptr;
m_data.erase(m_data.begin()+elementId);
}
@ -467,7 +469,7 @@ namespace etk {
*/
Iterator erase(const Iterator& _it) {
int64_t elementId = _it.m_current;
delete(m_data[elementId]);
ETK_DELETE(pairType, m_data[elementId]);
m_data[elementId] = nullptr;
m_data.erase(m_data.begin()+elementId);
return position(elementId);

View File

View File

@ -792,7 +792,7 @@ template<class CLASS_TYPE> class NodePTheseElement : public Node<CLASS_TYPE> {
~NodePTheseElement() {
/*
for (auto it : m_subNode) {
delete *it;
ETK_DELETE(Node<CLASS_TYPE>, *it);
*it = nullptr;
}
*/
@ -813,7 +813,7 @@ template<class CLASS_TYPE> class NodePTheseElement : public Node<CLASS_TYPE> {
tmpData.pushBack(Node<CLASS_TYPE>::m_regExData[kkk]);
}
// add to the under-node list :
m_subNode.pushBack(new NodePThese<CLASS_TYPE>(tmpData, Node<CLASS_TYPE>::m_nodeLevel+1));
m_subNode.pushBack(ETK_NEW(NodePThese<CLASS_TYPE>, tmpData, Node<CLASS_TYPE>::m_nodeLevel+1));
// move current position ...
pos += elementSize+1;
}
@ -827,7 +827,7 @@ template<class CLASS_TYPE> class NodePTheseElement : public Node<CLASS_TYPE> {
tmpData.pushBack(Node<CLASS_TYPE>::m_regExData[kkk]);
}
// add to the under-node list :
m_subNode.pushBack(new NodeBracket<CLASS_TYPE>(tmpData, Node<CLASS_TYPE>::m_nodeLevel+1));
m_subNode.pushBack(ETK_NEW(NodeBracket<CLASS_TYPE>, tmpData, Node<CLASS_TYPE>::m_nodeLevel+1));
// move current position ...
pos += elementSize+1;
}
@ -869,7 +869,7 @@ template<class CLASS_TYPE> class NodePTheseElement : public Node<CLASS_TYPE> {
return false;
case regexOpcodeEOF:
{
NodeRangeValue<CLASS_TYPE>* tmpNode = new NodeRangeValue<CLASS_TYPE>(Node<CLASS_TYPE>::m_nodeLevel+1);
NodeRangeValue<CLASS_TYPE>* tmpNode = ETK_NEW(NodeRangeValue<CLASS_TYPE>, Node<CLASS_TYPE>::m_nodeLevel+1);
tmpNode->setDescriptiveName("EOF");
tmpNode->addValue('\0');
tmpNode->setCountOutput(false);
@ -879,7 +879,7 @@ template<class CLASS_TYPE> class NodePTheseElement : public Node<CLASS_TYPE> {
break;
case regexOpcodeDot:
{
NodeRangeValue<CLASS_TYPE>* tmpNode = new NodeRangeValue<CLASS_TYPE>(Node<CLASS_TYPE>::m_nodeLevel+1);
NodeRangeValue<CLASS_TYPE>* tmpNode = ETK_NEW(NodeRangeValue<CLASS_TYPE>, Node<CLASS_TYPE>::m_nodeLevel+1);
tmpNode->setDescriptiveName("dot");
tmpNode->addValue('\0');
tmpNode->setInvert(true);
@ -887,11 +887,11 @@ template<class CLASS_TYPE> class NodePTheseElement : public Node<CLASS_TYPE> {
}
break;
case regexOpcodeStartOfLine:
m_subNode.pushBack(new NodeSOL<CLASS_TYPE>(Node<CLASS_TYPE>::m_nodeLevel+1));
m_subNode.pushBack(ETK_NEW(NodeSOL<CLASS_TYPE>, Node<CLASS_TYPE>::m_nodeLevel+1));
break;
case regexOpcodeEndOfLine:
{
NodeRangeValue<CLASS_TYPE>* tmpNode = new NodeRangeValue<CLASS_TYPE>(Node<CLASS_TYPE>::m_nodeLevel+1);
NodeRangeValue<CLASS_TYPE>* tmpNode = ETK_NEW(NodeRangeValue<CLASS_TYPE>, Node<CLASS_TYPE>::m_nodeLevel+1);
tmpNode->setDescriptiveName("EOL");
tmpNode->addValue('\n');
m_subNode.pushBack(tmpNode);
@ -899,7 +899,7 @@ template<class CLASS_TYPE> class NodePTheseElement : public Node<CLASS_TYPE> {
break;
case regexOpcodeDigit:
{
NodeRangeValue<CLASS_TYPE>* tmpNode = new NodeRangeValue<CLASS_TYPE>(Node<CLASS_TYPE>::m_nodeLevel+1);
NodeRangeValue<CLASS_TYPE>* tmpNode = ETK_NEW(NodeRangeValue<CLASS_TYPE>, Node<CLASS_TYPE>::m_nodeLevel+1);
tmpNode->setDescriptiveName("digit");
tmpNode->addRange('0', '9');
m_subNode.pushBack(tmpNode);
@ -907,7 +907,7 @@ template<class CLASS_TYPE> class NodePTheseElement : public Node<CLASS_TYPE> {
break;
case regexOpcodeDigitNot:
{
NodeRangeValue<CLASS_TYPE>* tmpNode = new NodeRangeValue<CLASS_TYPE>(Node<CLASS_TYPE>::m_nodeLevel+1);
NodeRangeValue<CLASS_TYPE>* tmpNode = ETK_NEW(NodeRangeValue<CLASS_TYPE>, Node<CLASS_TYPE>::m_nodeLevel+1);
tmpNode->setDescriptiveName("digit-not");
tmpNode->addRange('0', '9');
tmpNode->setInvert(true);
@ -916,7 +916,7 @@ template<class CLASS_TYPE> class NodePTheseElement : public Node<CLASS_TYPE> {
break;
case regexOpcodeLetter:
{
NodeRangeValue<CLASS_TYPE>* tmpNode = new NodeRangeValue<CLASS_TYPE>(Node<CLASS_TYPE>::m_nodeLevel+1);
NodeRangeValue<CLASS_TYPE>* tmpNode = ETK_NEW(NodeRangeValue<CLASS_TYPE>, Node<CLASS_TYPE>::m_nodeLevel+1);
tmpNode->setDescriptiveName("letter");
tmpNode->addRange('a', 'z');
tmpNode->addRange('A', 'Z');
@ -925,7 +925,7 @@ template<class CLASS_TYPE> class NodePTheseElement : public Node<CLASS_TYPE> {
break;
case regexOpcodeLetterNot:
{
NodeRangeValue<CLASS_TYPE>* tmpNode = new NodeRangeValue<CLASS_TYPE>(Node<CLASS_TYPE>::m_nodeLevel+1);
NodeRangeValue<CLASS_TYPE>* tmpNode = ETK_NEW(NodeRangeValue<CLASS_TYPE>, Node<CLASS_TYPE>::m_nodeLevel+1);
tmpNode->setDescriptiveName("letter-not");
tmpNode->addRange('a', 'z');
tmpNode->addRange('A', 'Z');
@ -935,7 +935,7 @@ template<class CLASS_TYPE> class NodePTheseElement : public Node<CLASS_TYPE> {
break;
case regexOpcodeSpace:
{
NodeRangeValue<CLASS_TYPE>* tmpNode = new NodeRangeValue<CLASS_TYPE>(Node<CLASS_TYPE>::m_nodeLevel+1);
NodeRangeValue<CLASS_TYPE>* tmpNode = ETK_NEW(NodeRangeValue<CLASS_TYPE>, Node<CLASS_TYPE>::m_nodeLevel+1);
tmpNode->setDescriptiveName("space");
tmpNode->addValue(' ');
tmpNode->addValue('\t');
@ -948,7 +948,7 @@ template<class CLASS_TYPE> class NodePTheseElement : public Node<CLASS_TYPE> {
break;
case regexOpcodeSpaceNot:
{
NodeRangeValue<CLASS_TYPE>* tmpNode = new NodeRangeValue<CLASS_TYPE>(Node<CLASS_TYPE>::m_nodeLevel+1);
NodeRangeValue<CLASS_TYPE>* tmpNode = ETK_NEW(NodeRangeValue<CLASS_TYPE>, Node<CLASS_TYPE>::m_nodeLevel+1);
tmpNode->setDescriptiveName("space-not");
tmpNode->addValue(' ');
tmpNode->addValue('\t');
@ -962,7 +962,7 @@ template<class CLASS_TYPE> class NodePTheseElement : public Node<CLASS_TYPE> {
break;
case regexOpcodeWord:
{
NodeRangeValue<CLASS_TYPE>* tmpNode = new NodeRangeValue<CLASS_TYPE>(Node<CLASS_TYPE>::m_nodeLevel+1);
NodeRangeValue<CLASS_TYPE>* tmpNode = ETK_NEW(NodeRangeValue<CLASS_TYPE>, Node<CLASS_TYPE>::m_nodeLevel+1);
tmpNode->setDescriptiveName("word");
tmpNode->addRange('a', 'z');
tmpNode->addRange('A', 'Z');
@ -972,7 +972,7 @@ template<class CLASS_TYPE> class NodePTheseElement : public Node<CLASS_TYPE> {
break;
case regexOpcodeWordNot:
{
NodeRangeValue<CLASS_TYPE>* tmpNode = new NodeRangeValue<CLASS_TYPE>(Node<CLASS_TYPE>::m_nodeLevel+1);
NodeRangeValue<CLASS_TYPE>* tmpNode = ETK_NEW(NodeRangeValue<CLASS_TYPE>, Node<CLASS_TYPE>::m_nodeLevel+1);
tmpNode->setDescriptiveName("word-not");
tmpNode->addRange('a', 'z');
tmpNode->addRange('A', 'Z');
@ -987,7 +987,7 @@ template<class CLASS_TYPE> class NodePTheseElement : public Node<CLASS_TYPE> {
tmpData.pushBack(Node<CLASS_TYPE>::m_regExData[kkk]);
}
// add to the under-node list :
m_subNode.pushBack(new NodeValue<CLASS_TYPE>(tmpData, Node<CLASS_TYPE>::m_nodeLevel+1));
m_subNode.pushBack(ETK_NEW(NodeValue<CLASS_TYPE>, tmpData, Node<CLASS_TYPE>::m_nodeLevel+1));
// move current position ...
pos += elementSize-1;
}
@ -1142,7 +1142,7 @@ template<class CLASS_TYPE> class NodePThese : public Node<CLASS_TYPE> {
~NodePThese() {
/*
for (auto it : m_subNode) {
delete *it;
ETK_DELETE(Node<CLASS_TYPE>, *it);
*it = nullptr;
}
*/
@ -1162,7 +1162,7 @@ template<class CLASS_TYPE> class NodePThese : public Node<CLASS_TYPE> {
tmpData.pushBack(Node<CLASS_TYPE>::m_regExData[kkk]);
}
// add to the under-node list :
m_subNode.pushBack(new NodePTheseElement<CLASS_TYPE>(tmpData, Node<CLASS_TYPE>::m_nodeLevel+1));
m_subNode.pushBack(ETK_NEW(NodePTheseElement<CLASS_TYPE>, tmpData, Node<CLASS_TYPE>::m_nodeLevel+1));
pos += elementSize+1;
TK_REG_DEBUG("plop=" << createString(Node<CLASS_TYPE>::m_regExData, pos, pos+1) );
elementSize = getLenOfPTheseElement(Node<CLASS_TYPE>::m_regExData, pos);
@ -1434,8 +1434,8 @@ template<class CLASS_TYPE> class RegEx {
m_maximize = _value;
}
/**
* @brief Set a new regular expression matching
* @param[in] _expression the new expression to search
* @brief Set a regular expression matching
* @param[in] _expression the expression to search
*/
// TODO : Add an error ...
void compile(const etk::String &_expression) {

View File

@ -8,12 +8,12 @@
#include <etk/String.hpp>
etk::Stream::Stream(size_t _basicSize) :
m_data(new etk::String) {
m_data(ETK_NEW(etk::String)) {
m_data->reserve(_basicSize);
}
etk::Stream::~Stream() {
delete m_data;
ETK_DELETE(etk::String, m_data);
m_data = nullptr;
}

View File

@ -3,13 +3,41 @@
#include <etk/String.hpp>
#include <etk/UString.hpp>
#if ETK_ENABLE_INTERNAL_DATA_IN_STRING > 0
const size_t etk::String::m_sizeLocal = 64-sizeof(etk::Vector<char>);
#else
const char* getStaticEmptyString() {
static const char* tmp = "\0\0\0\0\0\0";
return tmp;
}
#endif
etk::String::String():
m_data() {
m_data.resize(1, '\0');
#if ETK_ENABLE_INTERNAL_DATA_IN_STRING > 0
static_assert(sizeof(etk::String) == ETK_ENABLE_INTERNAL_DATA_IN_STRING, "Wrong basic size of string");
//printf("size of string=%ld %ld %ld\n", uint64_t(sizeof(etk::String)), m_sizeLocal, uint64_t(sizeof(etk::Vector<char>)));
memset(m_localData, 0, sizeof(m_localData));
#else
//m_data.resize(1, '\0');
#endif
}
etk::String::String(const etk::String& _obj) {
m_data = _obj.m_data;
#if ETK_ENABLE_INTERNAL_DATA_IN_STRING > 0
if (_obj.size() < sizeof(m_localData)) {
if (_obj.m_data.size() != 0) {
memcpy(m_localData, &_obj.m_data[0], _obj.m_data.size());
} else {
memcpy(m_localData, _obj.m_localData, sizeof(m_localData));
}
} else {
m_data = _obj.m_data;
}
#else
m_data = _obj.m_data;
#endif
}
etk::String::String(const etk::String& _obj, size_t _pos, size_t _size) {
@ -17,10 +45,25 @@ etk::String::String(const etk::String& _obj, size_t _pos, size_t _size) {
_size = etk::String::npos;
}
if (_size != etk::String::npos) {
resize(_size);
for (size_t iii=0; iii<_size; ++iii) {
m_data[iii] = _obj.m_data[_pos+iii];
}
#if ETK_ENABLE_INTERNAL_DATA_IN_STRING > 0
if (_size < sizeof(m_localData)) {
if (_obj.m_data.size() != 0) {
} else {
}
} else {
resize(_size);
for (size_t iii=0; iii<_size; ++iii) {
m_data[iii] = _obj.m_data[_pos+iii];
}
}
#else
resize(_size);
for (size_t iii=0; iii<_size; ++iii) {
m_data[iii] = _obj.m_data[_pos+iii];
}
#endif
return;
}
resize(_obj.size()-_pos);
@ -35,11 +78,16 @@ etk::String::String(const char* _obj) {
return;
}
uint32_t size = strlen(_obj);
/*if (size == 0) {
return;
}*/
resize(size);
for (size_t iii=0; iii<size; ++iii) {
m_data[iii] = _obj[iii];
}
//printf(" size=%d with='%s' ==> '%s'\n", size, _obj, &m_data[0]);
}
/*
etk::String::String(const etk::String _obj) {
resize(_obj.size());
@ -161,7 +209,11 @@ etk::String& etk::String::operator+= (char _value) {
// Return the current pointer
return *this;
}
size_t etk::String::size() const {
if (m_data.size() == 0) {
return 0;
}
return m_data.size() - 1; // remove '\0'
}
@ -199,7 +251,7 @@ void etk::String::pushBack(const char* _item, size_t _nbElement) {
}
void etk::String::popBack() {
if(size()>0) {
if(size() > 0) {
resize(size()-1);
}
}
@ -209,7 +261,7 @@ void etk::String::reserve(size_t _size) {
}
void etk::String::clear() {
resize(0);
m_data.clear();
}
void etk::String::insert(size_t _pos, const char* _item, size_t _nbElement) {
@ -267,7 +319,7 @@ void etk::String::erase(size_t _pos, size_t _nbElement) {
}
void etk::String::eraseRange(size_t _pos, size_t _posEnd) {
if (_pos>size()) {
if (_pos > size()) {
//TK_ERROR(" can not Erase Element at this position : " << _pos << " > " << size());
return;
}
@ -278,7 +330,7 @@ void etk::String::eraseRange(size_t _pos, size_t _posEnd) {
size_t tmpSize = size();
// move current data
size_t sizeToMove = (tmpSize - (_pos+nbElement));
if ( 0 < sizeToMove) {
if (sizeToMove > 0) {
for (size_t iii=0; iii<sizeToMove; iii++) {
m_data[_pos+iii] = m_data[_pos+nbElement+iii];
}
@ -289,10 +341,10 @@ void etk::String::eraseRange(size_t _pos, size_t _posEnd) {
etk::String etk::String::extract(size_t _posStart, size_t _posEnd) const {
etk::String out;
if (_posStart >= size() ) {
if (_posStart >= size()) {
return out;
}
if (_posEnd >= size() ) {
if (_posEnd >= size()) {
_posEnd = size();
}
out.pushBack(&m_data[_posStart], _posEnd-_posStart);
@ -300,6 +352,9 @@ etk::String etk::String::extract(size_t _posStart, size_t _posEnd) const {
}
const char* etk::String::c_str() const {
if (m_data.size() == 0) {
return getStaticEmptyString();
}
return &m_data[0];
}
@ -320,14 +375,18 @@ const etk::String::Iterator etk::String::begin() const {
}
etk::String::Iterator etk::String::end() {
return position( size() );
return position(size());
}
const etk::String::Iterator etk::String::end() const {
return position( size() );
return position(size());
}
void etk::String::resize(size_t _newSize, char _value) {
if (_newSize == 0) {
m_data.clear();
return;
}
size_t oldSize = m_data.size();
if (oldSize != 0) {
m_data[m_data.size()-1] = _value;
@ -342,7 +401,7 @@ bool etk::String::operator== (const etk::String& _obj) const {
if( this == &_obj ) {
return true;
}
// first step : check the size ...
// first step: check the size...
if (m_data.size() != _obj.m_data.size()) {
return false;
}
@ -359,7 +418,7 @@ bool etk::String::operator!= (const etk::String& _obj) const {
if( this == &_obj ) {
return false;
}
// first step : check the size ...
// first step: check the size...
if (m_data.size() != _obj.m_data.size()) {
return true;
}
@ -371,6 +430,26 @@ bool etk::String::operator!= (const etk::String& _obj) const {
return false;
}
char& etk::String::get(size_t _pos) {
if (m_data.size() == 0) {
return (char&)(getStaticEmptyString()[_pos]);
}
return m_data[_pos];
}
char& etk::String::operator[] (size_t _pos) {
if (m_data.size() == 0) {
return (char&)(getStaticEmptyString()[_pos]);
}
return m_data[_pos];
}
const char& etk::String::operator[] (size_t _pos) const {
if (m_data.size() == 0) {
return getStaticEmptyString()[_pos];
}
return m_data[_pos];
}
char etk::toLower(char _value) {
if ( _value >= 'A'
@ -1157,7 +1236,7 @@ char etk::toHexChar(uint8_t _value) {
etk::String etk::toHex(uint64_t _value, uint32_t _size) {
etk::String out;
for (int32_t iii = 15; iii >=0; --iii) {
if ( _size >= iii
if ( _size >= uint64_t(iii)
|| _value >= uint64_t(1)<<iii) {
out += etk::toHexChar((_value>>(iii*4)) & 0x0F);
}
@ -1169,7 +1248,7 @@ etk::String etk::toHex(uint64_t _value, uint32_t _size) {
etk::String etk::toBin(uint64_t _value, uint32_t _size) {
etk::String out;
for (int32_t iii = 63; iii >=0; --iii) {
if ( _size >= iii
if ( _size >= uint64_t(iii)
|| _value >= uint64_t(1)<<iii) {
out += etk::toHexChar((_value>>(iii)) & 0x01);
}

View File

@ -9,6 +9,11 @@
//#include <etk/debug.hpp>
#include <etk/Vector.hpp>
// This permit to define a minimal size in the string to permit to optimise the unneeded allocation of memory (32 remove allocation of 1 byte and 64 remove multiple allocation of 16 bytes (common)
#ifndef ETK_ENABLE_INTERNAL_DATA_IN_STRING
// TODO: NOTE: This is really not functionnal for now...
//#define ETK_ENABLE_INTERNAL_DATA_IN_STRING 64
#endif
namespace etk {
/**
@ -19,7 +24,7 @@ namespace etk {
class Iterator {
private:
size_t m_current; //!< current Id on the string
String* m_string; //!< Pointer on the current element of the stringBin
String* m_string; //!< Pointer on the current element of the string
public:
/**
* @brief Basic iterator constructor with no link with an etk::String
@ -201,6 +206,10 @@ namespace etk {
};
private:
etk::Vector<char> m_data; //!< pointer on the current data (contain all time 1 element '\0')
#if ETK_ENABLE_INTERNAL_DATA_IN_STRING >= 32
char m_localData[ETK_ENABLE_INTERNAL_DATA_IN_STRING-sizeof(etk::Vector<char>)]; //!< Reserve the memory to have all time a buffer of N byte to remove un-needed allocation
static const size_t m_sizeLocal;
#endif
public:
static const size_t npos = size_t(-1);
/**
@ -314,25 +323,19 @@ namespace etk {
* @param[in] _pos Desired position read
* @return Reference on the Element
*/
char& get(size_t _pos) {
return m_data[_pos];
}
char& get(size_t _pos);
/**
* @brief Get an copy Element an a special position
* @param[in] _pos Position in the string that might be get [0..Size()]
* @return An reference on the copy of selected element
*/
char& operator[] (size_t _pos) {
return m_data[_pos];
}
char& operator[] (size_t _pos);
/**
* @brief Get an Element an a special position
* @param[in] _pos Position in the string that might be get [0..Size()]
* @return An reference on the selected element
*/
const char& operator[] (size_t _pos) const {
return m_data[_pos];
}
const char& operator[] (size_t _pos) const;
/**
* @brief Add at the First position of the String
* @param[in] _item Element to add at the end of string

View File

@ -48,7 +48,7 @@ namespace etk {
*/
template<class ETK_VECTOR_TYPE> class Vector {
public:
static const size_t npos = size_t(-1);
//static const size_t npos = size_t(-1);
class Iterator {
private:
size_t m_current; //!< current Id on the vector
@ -241,7 +241,7 @@ namespace etk {
changeAllocation(_count);
// instanciate all objects
for (size_t iii=0; iii<_count; ++iii) {
new ((char*)&m_data[iii]) ETK_VECTOR_TYPE();
new ((char*)&m_data[iii]) ETK_VECTOR_TYPE();
}
m_size = _count;
}
@ -299,7 +299,7 @@ namespace etk {
}
#endif
}
delete[] (char*)m_data;
ETK_FREE(char, m_data);
m_data = nullptr;
}
m_allocated = 0;
@ -825,7 +825,7 @@ namespace etk {
// check if something is allocated :
if (m_data == nullptr) {
// no data allocated ==> request an allocation (might be the first)
m_data = (ETK_VECTOR_TYPE*)(new char[sizeof(ETK_VECTOR_TYPE)*requestSize]);
m_data = (ETK_VECTOR_TYPE*)ETK_MALLOC(char, sizeof(ETK_VECTOR_TYPE)*requestSize);
if (m_data == nullptr) {
//TK_CRITICAL("Vector : Error in data allocation request allocation:" << requestSize << "*" << (int32_t)(sizeof(ETK_VECTOR_TYPE)) << "bytes" );
m_allocated = 0;
@ -840,7 +840,7 @@ namespace etk {
#endif
} else {
// allocate a new pool of data:
ETK_VECTOR_TYPE* dataTmp = (ETK_VECTOR_TYPE*)(new char[sizeof(ETK_VECTOR_TYPE)*requestSize]);
ETK_VECTOR_TYPE* dataTmp = (ETK_VECTOR_TYPE*)ETK_MALLOC(char, sizeof(ETK_VECTOR_TYPE)*requestSize);;
if (dataTmp == nullptr) {
//TK_CRITICAL("Vector : Error in data allocation request allocation:" << requestSize << "*" << (int32_t)(sizeof(ETK_VECTOR_TYPE)) << "bytes" );
return;
@ -872,7 +872,7 @@ namespace etk {
m_data = dataTmp;
// remove old pool
if (dataTmp2 != nullptr) {
delete[] (char*)dataTmp2;
ETK_FREE(char, dataTmp2);
}
}
// set the new allocation size

View File

@ -68,7 +68,7 @@ etk::Archive* etk::Archive::load(const etk::String& _fileName) {
// select the corect Loader :
if( tmpName.endWith(".zip") == true
|| tmpName.endWith(".apk") == true ) {
output = new etk::archive::Zip(_fileName);
output = ETK_NEW(etk::archive::Zip, _fileName);
if (output == nullptr) {
TK_ERROR("An error occured when load archive : " << _fileName);
}
@ -104,7 +104,7 @@ etk::Archive* etk::Archive::loadPackage(const etk::String& _fileName) {
}
fclose(file);
file = nullptr;
output = new etk::archive::Zip(_fileName, position);
output = ETK_NEW(etk::archive::Zip, _fileName, position);
if (nullptr==output) {
TK_ERROR("An error occured when load archive : " << _fileName);
}

View File

@ -11,6 +11,7 @@
#include <elog/elog.hpp>
#include <etk/os/FSNode.hpp>
#include <etk/typeInfo.hpp>
#include <etk/Allocator.hpp>
static int32_t nbTimeInit = 0;
@ -27,6 +28,7 @@ void etk::unInit() {
return;
}
TK_INFO("ETK system un-init (BEGIN)");
ETK_MEM_SHOW_LOG();
TK_INFO("ETK system un-init (END)");
}

View File

@ -1562,7 +1562,7 @@ etk::Vector<etk::FSNode *> etk::FSNode::folderGetSubList(bool _showHidenFile, bo
if (m_systemFileName.size() == 0) {
etk::Vector<etk::String> listDrive = getListDrive();
for (auto &it : listDrive) {
tmpp.pushBack(new etk::FSNode(it));
tmpp.pushBack(ETK_NEW(etk::FSNode, it));
}
return tmpp;
}
@ -1607,8 +1607,8 @@ etk::Vector<etk::FSNode *> etk::FSNode::folderGetSubList(bool _showHidenFile, bo
}
if (findIt == false) {
listAdded.pushBack(tmpString);
tmpEmement = new etk::FSNode(tmpString);
if (nullptr == tmpEmement) {
tmpEmement = ETK_NEW(etk::FSNode, tmpString);
if (tmpEmement == nullptr) {
TK_ERROR("allocation error ... of ewol::FSNode");
continue;
}
@ -1634,24 +1634,24 @@ etk::Vector<etk::FSNode *> etk::FSNode::folderGetSubList(bool _showHidenFile, bo
// do nothing ...
continue;
}
if( false == start_with(tmpName, ".")
|| true == _showHidenFile) {
tmpEmement = new etk::FSNode(getRelativeFolder()+tmpName);
if (nullptr == tmpEmement) {
if( start_with(tmpName, ".") == false
|| _showHidenFile == true) {
tmpEmement = ETK_NEW(etk::FSNode, getRelativeFolder()+tmpName);
if (tmpEmement == nullptr) {
TK_ERROR("allocation error ... of ewol::FSNode");
continue;
}
if(tmpEmement->getNodeType() == etk::typeNode_file) {
if (true == _getFile) {
if (_getFile == true) {
tmpp.pushBack(tmpEmement);
} else {
delete(tmpEmement);
ETK_DELETE(etk::FSNode, tmpEmement);
tmpEmement = nullptr;
}
} else if (_getFolderAndOther) {
tmpp.pushBack(tmpEmement);
} else {
delete(tmpEmement);
ETK_DELETE(etk::FSNode, tmpEmement);
tmpEmement = nullptr;
}
}
@ -1803,18 +1803,18 @@ void etk::FSNode::folderGetRecursiveFiles(etk::Vector<etk::String>& _output, boo
continue;
}
//TK_DEBUG(" find : " << ent->d_name << " ==> " << (GetRelativeFolder()+tmpName));
tmpEmement = new etk::FSNode(getRelativeFolder()+tmpName);
if (nullptr != tmpEmement) {
tmpEmement = ETK_NEW(etk::FSNode, getRelativeFolder()+tmpName);
if (tmpEmement != nullptr) {
if(tmpEmement->getNodeType() == etk::typeNode_file) {
etk::String tmpVal = tmpEmement->getName();
_output.pushBack(tmpVal);
}
if(tmpEmement->getNodeType() == etk::typeNode_folder) {
if (true==_recursiveEnable) {
if (_recursiveEnable == true) {
tmpEmement->folderGetRecursiveFiles(_output, _recursiveEnable);
}
}
delete(tmpEmement);
ETK_DELETE(etk::FSNode, tmpEmement);
tmpEmement = nullptr;
} else {
TK_ERROR("allocation error ... of ewol::FSNode");

View File

@ -28,7 +28,7 @@ namespace etk {
/**
* @brief Add an element declared type in the system database.
* @param[in] Name of the type
* @return The Id of the Object (new unique ID)
* @return The Id of the Object (create a unique ID)
*/
size_t addType(const char* _name);
}