/data/common/demos/life2 |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/programs/bcc32/include/kos_heap.inc |
---|
34,6 → 34,7 |
proc @MemoryHeap@mem_Free$qpv uses ebx |
mov eax,SF_SYS_MISC |
mov ebx,SSF_MEM_FREE |
mov ecx,[esp+8] |
int 0x40 |
ret |
endp |
/programs/demos/life2/include/kolibri_win.cpp |
---|
File deleted |
/programs/demos/life2/include/kolibri.h |
---|
1,7 → 1,7 |
#ifndef __KOLIBRI_H_INCLUDED_ |
#define __KOLIBRI_H_INCLUDED_ |
#include <kos_lib.h> |
#include "kos_lib.h" |
// Kolibri interface. |
37,6 → 37,7 |
// Note: pass only thread data of current thread as (thread_data) parameter to these functions. |
void Main(); // Main function is called at program startup. |
void DrawButton(long id, long color, long x, long y, long c_x, long c_y); // Draw Standard button |
void* ThreadMain(void *user = 0, void *stack_begin = 0); |
// Called at thread startup, (user) is placed in thread data as a user dword, |
//_ (stack_begin) is placed in thread data as a stack beginning. |
54,7 → 55,7 |
//_ if (frame) is negative do nothing. |
void MoveWindow(const int window_rect[/* 4 */]); // Move and resize current window. |
void Abort(); // Abnormally terminate a program. |
void ExitDebug(); // Abnormally terminate a program. |
void ExitProcess(); // Exit from the process, don't call any destructors of global varyables |
void ExitThread(); // Exit from the current thread |
void ExitThread(TThreadData thread_data); |
134,6 → 135,7 |
//_ of the stack if (stack_end) is zero or (stack_size) is not zero, in this case stack |
//_ will be deleted automaticaly from dynamic memory at the finish of the thread. |
void DrawText(short x, short y, int color, const char* string); |
void SetWindowCaption(const char* caption); |
} |
// Function, defined outside. |
145,6 → 147,7 |
void KolibriOnSize(int window_rect[/* 4 */], Kolibri::TThreadData thread_data); // When the window is resized. |
void KolibriOnKeyPress(Kolibri::TThreadData thread_data); // When user press a key. |
void KolibriOnMouse(Kolibri::TThreadData thread_data); // When user move a mouse. |
void KolibriOnButton(long id, Kolibri::TThreadData th); |
#ifdef __KOLIBRI__ |
249,7 → 252,7 |
// Constants from fasm. |
#include <kos_func.inc> |
#include "kos_func.inc" |
// Functions. |
/programs/demos/life2/include/kos_file.h |
---|
1,97 → 1,69 |
#ifndef __KOLIBRI_FILE_H_INCLUDED_ |
#define __KOLIBRI_FILE_H_INCLUDED_ |
#include <kolibri.h> |
#include <kos_heap.h> |
#include "kolibri.h" |
#include "kos_heap.h" |
// Kolibri file interface. |
namespace Kolibri // All kolibri functions, types and data are nested in the (Kolibri) namespace. |
{ |
struct _FileDataStruct; |
typedef _FileDataStruct *TFileData; |
TFileData FileOpen(const char *name, unsigned int buffer_length = 1024); |
int FileClose(TFileData file_data); |
bool FileEof(TFileData file_data); |
unsigned int FileGetPosition(TFileData file_data); |
void FileSetPosition(TFileData file_data, unsigned int pos); |
void FileReset(TFileData file_data); |
unsigned int FileGetLength(TFileData file_data); |
int FileTestRead(TFileData file_data); |
int FileRead(TFileData file_data, void *mem, int size); |
} |
#ifdef __KOLIBRI__ |
namespace Kolibri |
struct FileDateTime{ |
unsigned long int time; |
unsigned long int date; |
}; |
struct FileInfoBlock |
{ |
// Define the file data structure. |
struct _FileDataStruct |
unsigned long int Function; |
unsigned long int Position; |
unsigned long int Flags; |
unsigned long int Count; |
char *Buffer; |
char *FileName1; |
char *FileName2; |
}; |
struct FileInfoA |
{ |
unsigned int length; |
unsigned int position; |
unsigned int *buffer; |
unsigned int access_param[5]; |
enum {PosName = (unsigned int)(((_FileDataStruct*)0)->access_param + 5)}; |
unsigned long int Attributes; |
unsigned long int Flags; |
FileDateTime DateCreate; |
FileDateTime DateAccess; |
FileDateTime DateModify; |
unsigned long int FileSizeLow; |
unsigned long int FileSizeHigh; |
char FileName[520]; |
}; |
// Inline functions. |
// Functions. |
inline bool FileEof(TFileData file_data) |
{ |
return file_data && file_data->position >= file_data->length; |
} |
int _FileAccess(FileInfoBlock *file_access); |
inline unsigned int FileGetPosition(TFileData file_data) |
FileInfoBlock* FileOpen(const char *name) |
{ |
return file_data ? file_data->position : 0; |
if (!name || !name[0]){ |
DebugPutString("name is 0"); |
return 0; |
} |
inline void FileReset(TFileData file_data) |
{ |
if (!file_data) return; |
file_data->length = -1; |
file_data->position = 0; |
if (file_data->buffer) file_data->buffer[1] = 0; |
FileInfoBlock* file = (FileInfoBlock*)Alloc(sizeof(FileInfoBlock)+sizeof(FileInfoA)); |
if (!file){ |
DebugPutString("mem_Alloc -> 0"); |
return 0; |
} |
file->Function = 5; //SSF_GET_INFO |
file->Position = 0; |
file->Flags = 0; |
file->Count = 0; |
file->Buffer = (char*)file+sizeof(FileInfoBlock); |
file->FileName1 = (char*)name; |
file->FileName2 = (char*)name; |
file->FileName1 = (char*)((long)file->FileName1 << 8); |
file->FileName2 = (char*)((long)file->FileName2 >> 24); |
// Functions. |
int _FileAccess(void *file_access_param); |
TFileData FileOpen(const char *name, unsigned int buffer_length) |
{ |
if (!name || !name[0]) return 0; |
unsigned int name_len = StrLen(name) + 1; |
unsigned int data_len = (_FileDataStruct::PosName + name_len + 3) & ~3; |
buffer_length = (buffer_length / KOLIBRI_FILE_BLOCK_SIZE) * KOLIBRI_FILE_BLOCK_SIZE; |
if (buffer_length) data_len += buffer_length + 2*sizeof(unsigned int); |
TFileData file = (TFileData)Alloc(_FileDataStruct::PosName + data_len); |
if (!file) return 0; |
file->length = -1; |
file->position = 0; |
if (buffer_length) |
{ |
file->buffer = (unsigned int*)((char*)file + data_len) - 2; |
file->buffer[0] = buffer_length; |
file->buffer[1] = 0; |
} |
MemCopy(file->access_param + 5, name, name_len); |
unsigned int attr[40/4]; |
file->access_param[0] = 5; |
file->access_param[1] = 0; |
file->access_param[2] = 0; |
file->access_param[3] = 0; |
file->access_param[4] = (int)attr; |
_FileAccess(file->access_param); |
file->length = attr[32/4]; |
_FileAccess(file); |
return file; |
} |
int FileClose(TFileData file_data) |
int FileClose(FileInfoBlock* file_data) |
{ |
if (!file_data) return -1; |
Free(file_data); |
98,181 → 70,26 |
return 0; |
} |
void FileSetPosition(TFileData file_data, unsigned int pos) |
unsigned long int FileRead(FileInfoBlock* file_data, void *mem, int size) |
{ |
if (!file_data) return; |
if (file_data->buffer && file_data->buffer[1]) |
{ |
if (pos >= file_data->position && pos < file_data->position + file_data->buffer[1]) |
{ |
file_data->buffer[1] -= pos - file_data->position; |
} |
else file_data->buffer[1] = 0; |
} |
file_data->position = pos; |
} |
file_data->Function = 0; //SSF_READ_FILE |
file_data->Position = 0; |
file_data->Flags = 0; |
file_data->Count = size; |
file_data->Buffer = (char*)mem; |
int _FileReadBuffer(TFileData file_data, void *mem, int size, void *temp_mem = 0) |
{ |
unsigned int *buffer; |
if (!file_data || !mem || size <= 0) return -1; |
if (file_data->buffer) buffer = file_data->buffer; |
else if (temp_mem) |
{ |
buffer = (unsigned int*)((char*)temp_mem + KOLIBRI_FILE_BLOCK_SIZE); |
} |
if(!_FileAccess(file_data)) return file_data->Function; |
else return 0; |
if (!buffer[1]) return 0; |
if (file_data->position >= file_data->length) |
{ |
buffer[1] = 0; |
return 0; |
} |
unsigned int buf_size = file_data->length - file_data->position; |
if (buf_size > buffer[1]) buf_size = buffer[1]; |
if ((unsigned int)size >= buf_size) size = buf_size; |
MemCopy(mem, (char*)buffer - buffer[1], size); |
file_data->position += size; |
if ((unsigned int)size >= buf_size) buffer[1] = 0; |
else buffer[1] -= size; |
return size; |
} |
int _FileReadSystem(TFileData file_data, void *mem, int size) |
{ |
int res; |
unsigned int len0, len1; |
size /= KOLIBRI_FILE_BLOCK_SIZE; |
if (!file_data || !mem || size <= 0) return -1; |
file_data->access_param[0] = 0; |
file_data->access_param[1] = (file_data->position / KOLIBRI_FILE_BLOCK_SIZE) * KOLIBRI_FILE_BLOCK_SIZE; |
file_data->access_param[2] = 0; |
file_data->access_param[3] = size * KOLIBRI_FILE_BLOCK_SIZE; |
file_data->access_param[4] = (unsigned int)mem; |
res = _FileAccess(file_data->access_param); |
if (res != 0 && res != 6) return (res & 255) - 1024; |
if (file_data->length <= file_data->position) return 0; |
len0 = file_data->length - file_data->position; |
len1 = size * KOLIBRI_FILE_BLOCK_SIZE - (file_data->position % KOLIBRI_FILE_BLOCK_SIZE); |
return (len0 <= len1) ? len0 : len1; |
} |
int _FileBufferSystem(TFileData file_data, void *&temp_mem) |
{ |
int res; |
unsigned int *buffer; |
if (!file_data) return -1; |
if (file_data->buffer) buffer = file_data->buffer; |
else |
{ |
if (!temp_mem) |
{ |
temp_mem = Alloc(KOLIBRI_FILE_BLOCK_SIZE + 2*sizeof(unsigned int)); |
if (!temp_mem) return -10; |
} |
buffer = (unsigned int*)((char*)temp_mem + KOLIBRI_FILE_BLOCK_SIZE); |
buffer[0] = KOLIBRI_FILE_BLOCK_SIZE; |
} |
buffer[1] = buffer[0]; |
res = _FileReadSystem(file_data, (char*)buffer - buffer[1], buffer[1]); |
if (res < 0) buffer[1] = 0; |
else buffer[1] -= file_data->position % KOLIBRI_FILE_BLOCK_SIZE; |
return res; |
} |
int FileTestRead(TFileData file_data) |
{ |
int res; |
void *temp_mem = 0; |
if (!file_data) return -1; |
if (file_data->buffer && file_data->buffer[1]) return 0; |
res = _FileBufferSystem(file_data, temp_mem); |
if (temp_mem) Free(temp_mem); |
return (res < 0) ? res : 0; |
} |
int FileRead(TFileData file_data, void *mem, int size) |
{ |
int tlen, res, read_len; |
void *temp_mem = 0; |
res = _FileReadBuffer(file_data, mem, size); |
if (res < 0 || res >= size) return res; |
read_len = res; |
mem = (char*)mem + res; |
size -= res; |
tlen = file_data->position % KOLIBRI_FILE_BLOCK_SIZE; |
if (tlen) |
{ |
res = _FileBufferSystem(file_data, temp_mem); |
if (res < 0) |
{ |
if (temp_mem) Free(temp_mem); |
return read_len ? read_len : res; |
} |
res = _FileReadBuffer(file_data, mem, size); |
read_len += res; |
if (res >= size || file_data->length <= file_data->position || |
file_data->length - file_data->position <= res) |
{ |
if (temp_mem) Free(temp_mem); |
return read_len; |
} |
mem = (char*)mem + res; |
size -= res; |
} |
if (size >= (file_data->buffer ? file_data->buffer[0] : KOLIBRI_FILE_BLOCK_SIZE)) |
{ |
res = _FileReadSystem(file_data, mem, size); |
if (res < 0) |
{ |
if (temp_mem) Free(temp_mem); |
return read_len ? read_len : res; |
} |
file_data->position += res; |
read_len += res; |
if (res < (size / KOLIBRI_FILE_BLOCK_SIZE) * KOLIBRI_FILE_BLOCK_SIZE) |
{ |
if (temp_mem) Free(temp_mem); |
return read_len; |
} |
mem = (char*)mem + res; |
size -= res; |
} |
if (size) |
{ |
res = _FileBufferSystem(file_data, temp_mem); |
if (res < 0) |
{ |
if (temp_mem) Free(temp_mem); |
return read_len ? read_len : res; |
} |
read_len += _FileReadBuffer(file_data, mem, size, temp_mem); |
} |
if (temp_mem) Free(temp_mem); |
return read_len; |
} |
// Inline functions. |
inline unsigned int FileGetLength(TFileData file_data) |
inline unsigned long int FileGetLength(FileInfoBlock* file_data) |
{ |
if (!file_data) return -1; |
if (file_data->length == -1) FileTestRead(file_data); |
return file_data->length; |
return (unsigned long int)*(long*)((char*)file_data+sizeof(FileInfoBlock)+32); |
} |
} |
#else // def __KOLIBRI__ |
namespace Kolibri |
{ |
struct _FileDataStruct |
{ |
unsigned int data; |
}; |
} |
#endif // else: def __KOLIBRI__ |
#endif // ndef __KOLIBRI_FILE_H_INCLUDED_ |
/programs/demos/life2/include/kos_func.inc |
---|
41,12 → 41,6 |
;const int |
KOLIBRI_MUTEX_MAX_TIME_WAIT = 20; |
;const int |
KOLIBRI_FILE_BLOCK_SIZE = 512; |
;const int |
KOLIBRI_FILE_MEMORY_OS_NEED = 4096; |
;/*** |
macro segment name |
1122,7 → 1116,7 |
jmp .create_thread_fill_stack |
endp |
proc @Kolibri@_FileAccess$qpv uses ebx |
proc @Kolibri@_FileAccess$qp21Kolibri@FileInfoBlock uses ebx |
mov eax,SF_FILE |
mov ebx,[esp+8] |
int 0x40 |
/programs/demos/life2/include/kos_heap.h |
---|
1,90 → 1,32 |
#ifndef __KOLIBRI_HEAP_H_INCLUDED_ |
#define __KOLIBRI_HEAP_H_INCLUDED_ |
#include <kolibri.h> |
#include <memheap.h> |
#include "kolibri.h" |
#include "memheap.h" |
// Kolibri memory heap interface. |
namespace Kolibri // All kolibri functions, types and data are nested in the (Kolibri) namespace. |
{ |
void *Alloc(unsigned int size); |
void *ReAlloc(void *mem, unsigned int size); |
void Free(void *mem); |
} |
#ifdef __KOLIBRI__ |
namespace Kolibri |
long _HeapInit() |
{ |
// Global variables |
MemoryHeap::TFreeSpace _KolibriFreeSpace; |
MemoryHeap::TMemBlock _KolibriMemBlock; |
TMutex _MemHeapMutex = KOLIBRI_MUTEX_INIT; |
// Functions |
void *_HeapInit(void *begin, void *use_end, void *end) |
{ |
MemoryHeap::InitFreeSpace(_KolibriFreeSpace); |
_KolibriMemBlock = MemoryHeap::CreateBlock(begin, end, _KolibriFreeSpace); |
unsigned int use_beg = (unsigned int)MemoryHeap::BlockBegin(_KolibriMemBlock) + |
MemoryHeap::BlockAddSize - MemoryHeap::BlockEndSize; |
unsigned int use_size = (unsigned int)use_end; |
if (use_size <= use_beg) return 0; |
else use_size -= use_beg; |
return MemoryHeap::Alloc(_KolibriFreeSpace, use_size); |
return MemoryHeap::mem_Init(); |
} |
bool _SetUseMemory(unsigned int use_mem); |
int _RecalculateUseMemory(unsigned int use_mem); |
void *Alloc(unsigned int size) |
{ |
if (!size) return 0; |
Lock(&_MemHeapMutex); |
void *res = MemoryHeap::Alloc(_KolibriFreeSpace, size); |
if (!res) |
{ |
unsigned use_mem = (unsigned int)MemoryHeap::BlockEndFor(_KolibriMemBlock, size); |
if (_SetUseMemory(_RecalculateUseMemory(use_mem))) |
{ |
res = MemoryHeap::Alloc(_KolibriFreeSpace, size); |
return MemoryHeap::mem_Alloc(size); |
} |
} |
UnLock(&_MemHeapMutex); |
return res; |
} |
void *ReAlloc(void *mem, unsigned int size) |
{ |
Lock(&_MemHeapMutex); |
void *res = MemoryHeap::ReAlloc(_KolibriFreeSpace, mem, size); |
if (!res && size) |
{ |
unsigned use_mem = (unsigned int)MemoryHeap::BlockEndFor(_KolibriMemBlock, size); |
if (_SetUseMemory(_RecalculateUseMemory(use_mem))) |
{ |
res = MemoryHeap::ReAlloc(_KolibriFreeSpace, mem, size); |
return MemoryHeap::mem_ReAlloc(size, mem); |
} |
} |
UnLock(&_MemHeapMutex); |
return res; |
} |
void Free(void *mem) |
{ |
Lock(&_MemHeapMutex); |
MemoryHeap::Free(_KolibriFreeSpace, mem); |
UnLock(&_MemHeapMutex); |
MemoryHeap::mem_Free(mem); |
} |
void _FreeAndThreadFinish(void *mem, int *exit_proc_now); |
} |
#endif // def __KOLIBRI__ |
#endif // ndef __KOLIBRI_HEAP_H_INCLUDED_ |
/programs/demos/life2/include/kos_heap.inc |
---|
1,6 → 1,6 |
;/*** |
KolibriHeapInit = @@Kolibri@_HeapInit$qpvt1t1 |
KolibriHeapInit = @@Kolibri@_HeapInit$qv |
KolibriHeapAlloc = @@Kolibri@Alloc$qui |
8,90 → 8,35 |
KolibriHeapFree = @@Kolibri@Free$qpv |
KolibriHeapFreeAndThreadFinish = @Kolibri@_FreeAndThreadFinish$qpvpi |
proc @Kolibri@_SetUseMemory$qui |
push ebx |
mov eax,64 |
mov ebx,1 |
mov ecx,[esp+8] |
proc @MemoryHeap@mem_Init$qv uses ebx |
mov eax,SF_SYS_MISC |
mov ebx,SSF_HEAP_INIT |
int 0x40 |
pop ebx |
test eax,eax |
jnz .set_use_memory_nomem |
push ecx |
push dword [@Kolibri@_KolibriMemBlock] |
call @@MemoryHeap@ResizeBlock$q20MemoryHeap@TMemBlockpv |
add esp,8 |
mov al,1 |
ret |
.set_use_memory_nomem: |
xor al,al |
ret |
endp |
proc @Kolibri@_RecalculateUseMemory$qui |
mov eax,dword [esp+4] |
mov ecx,(U_END + 3) and not 3 |
cmp eax,ecx |
jna .recalculate_use_memory_min |
push ebx |
sub eax,ecx |
mov ebx,6 |
mul ebx |
dec ebx |
div ebx |
add eax,((U_END + 3) and not 3) + 3 |
and eax,not 3 |
pop ebx |
proc @MemoryHeap@mem_Alloc$qul uses ebx |
mov eax,SF_SYS_MISC |
mov ebx,SSF_MEM_ALLOC |
int 0x40 |
ret |
.recalculate_use_memory_min: |
mov eax,ecx |
ret |
endp |
proc @Kolibri@_FreeAndThreadFinish$qpvpi |
mov ebx,1 |
proc @MemoryHeap@mem_ReAlloc$qulpv uses ebx |
mov eax,SF_SYS_MISC |
mov ebx,SSF_MEM_REALLOC |
mov ecx,[esp+8] |
jmp .heap_free_tf_wait |
.heap_free_tf_wait_loop: |
mov eax,5 |
mov edx,[esp+12] |
int 0x40 |
shl ebx,1 |
cmp ebx,KOLIBRI_MUTEX_MAX_TIME_WAIT |
jna .heap_free_tf_wait |
mov ebx,KOLIBRI_MUTEX_MAX_TIME_WAIT |
.heap_free_tf_wait: |
cmp dword [ecx],0 |
jnz @Kolibri@ExitProcess$qv |
lock bts dword [@Kolibri@_MemHeapMutex],0 |
jc .heap_free_tf_wait_loop |
push dword [esp+4] |
push @Kolibri@_KolibriFreeSpace |
call @@MemoryHeap@Free$qr21MemoryHeap@TFreeSpacepv |
add esp,8 |
mov byte [@Kolibri@_MemHeapMutex],0x40 |
or eax,-1 |
int 0x40 |
ret |
endp |
macro call func |
{ |
if func eq @MemoryHeap@_FirstNotZeroBit$qui |
bsf eax,[esp] |
else if func eq @MemoryHeap@_CopyMemItemArray$quiuiui |
xchg edi,[esp] |
xchg esi,[esp+4] |
proc @MemoryHeap@mem_Free$qpv uses ebx |
mov eax,SF_SYS_MISC |
mov ebx,SSF_MEM_FREE |
mov ecx,[esp+8] |
cld |
sub ecx,esi |
shr ecx,2 |
rep movs dword [edi],[esi] |
xchg edi,[esp] |
xchg esi,[esp+4] |
else |
call func |
end if |
} |
int 0x40 |
ret |
endp |
;/**/ |
/programs/demos/life2/include/kos_start.inc |
---|
8,7 → 8,7 |
dd U_END+STACKSIZE |
dd @Kolibri@CommandLine,0 |
include "..\..\..\KOSfuncs.inc" |
include "..\..\KOSfuncs.inc" |
include "..\..\proc32.inc" |
ptr equ |
/programs/demos/life2/include/memheap.h |
---|
1,626 → 1,13 |
#ifndef __MEMORY_HEAP_RBTREE_H_INCLUDED_ |
#define __MEMORY_HEAP_RBTREE_H_INCLUDED_ |
#ifndef __MEMORY_HEAP_H_INCLUDED_ |
#define __MEMORY_HEAP_H_INCLUDED_ |
namespace MemoryHeap |
{ |
typedef unsigned int TMemItem; |
enum {NumTreeSmall = 8 * sizeof(TMemItem)}; |
// Memory heap interface. |
struct TFreeSpace |
{ |
TMemItem Small[NumTreeSmall], Min, SmallMask; |
}; |
struct TMemBlock |
{ |
TMemItem *Begin; |
}; |
bool BlockValid(const TMemBlock &block); // Is the given memory block valid? |
void *BlockBegin(const TMemBlock &block); // Return the beginning address of the block. |
void *BlockEnd(const TMemBlock &block); // Return the ending address of the block. |
TFreeSpace &BlockFreeSpace(const TMemBlock &block); // Return the free space of the block. |
void InitFreeSpace(TFreeSpace &fs); // Initialize the free space. |
TMemBlock NullBlock(); // Return null invalid block. |
TMemBlock CreateBlock(void *begin, void *end, TFreeSpace &fs); |
// Create a memory block with the given begin and end and add free space of it to (fs), |
//_ give (BlockAddSize) bytes of the block for it's data. |
//_ (Program can alloc (end - begin - BlockAddSize) bytes after it, |
//_ that must be not less than (MemMinSize) ). |
TMemBlock CreateBlock(void *begin, void *end); |
// Create a memory block with the given begin and end and new free space for it, |
//_ give (BlockAddSizeFS) bytes of the block for it's data. |
//_ (Program can alloc (end - begin - BlockAddSizeFS) bytes after it, |
//_ that must be not less than (MemMinSize) ). |
void ResizeBlock(TMemBlock block, void *new_end); // Resize the memory block to the given new end. |
void RemoveBlock(TMemBlock block); // Remove the given memory block. |
void *BlockEndFor(TMemBlock block, unsigned int size); |
// Return the new end of the block needed for (ResizeBlock) to alloc the given size of memory. |
unsigned int BlockSize(TMemBlock block); // Return the size of the given block. |
unsigned int MemSize(void *mem); // Return the size of the allocced memory. |
void *Alloc(TFreeSpace &fs, unsigned int size); |
// Alloc a memory in the given free space, give (MemAddSize) bytes for it's data. |
void *ReAlloc(TFreeSpace &fs, unsigned int size, void *mem); |
// ReAlloc the given memory, it must lie in the block with the given free space. |
void Free(TFreeSpace &fs, void *mem); |
// Free the given memory, it must lie in the block with the given free space. |
// Macro definitions. |
#define MEMORY_HEAP_ALIGN_DOWN(s) (MemoryHeap::TMemItem(s) & ~(MemoryHeap::MemAlign - 1)) |
#define MEMORY_HEAP_ALIGN_UP(s) ((MemoryHeap::TMemItem(s) + (MemoryHeap::MemAlign - 1)) & ~(MemoryHeap::MemAlign - 1)) |
#define MEMORY_HEAP_ITEM(s,k) ( ((MemoryHeap::TMemItem*)(s))[(k)] ) |
#define MEMORY_HEAP_NEXT(s) (MEMORY_HEAP_ITEM((s),-1)) |
#define MEMORY_HEAP_PREV(s) (MEMORY_HEAP_ITEM((s),-2)) |
#define MEMORY_HEAP_FREE(s) (MEMORY_HEAP_ITEM((s),-1) & 1) |
// Constants. |
enum {MemAlign = sizeof(TMemItem)}; |
enum {MemAddSize = MEMORY_HEAP_ALIGN_UP(2 * sizeof(TMemItem))}; |
enum {BlockEndSize = MemAddSize}; |
enum {BlockAddSize = MEMORY_HEAP_ALIGN_UP(4 * sizeof(TMemItem)) + BlockEndSize}; |
enum {BlockAddSizeFS = BlockAddSize + BlockEndSize + MEMORY_HEAP_ALIGN_UP(sizeof(TFreeSpace))}; |
enum {MemMinSize = MEMORY_HEAP_ALIGN_UP(2 * sizeof(TMemItem))}; |
// Inline functions. |
inline bool BlockValid(const TMemBlock &block) {return block.Begin != 0;} |
inline void *BlockBegin(const TMemBlock &block) {return (void*)block.Begin;} |
inline void *BlockEnd(const TMemBlock &block) {return block.Begin ? (void*)block.Begin[1] : 0;} |
inline TFreeSpace &BlockFreeSpace(const TMemBlock &block) {return *(TFreeSpace*)block.Begin[0];} |
inline TMemBlock NullBlock() {TMemBlock block; block.Begin = 0; return block;} |
inline void *BlockEndFor(TMemBlock block, unsigned int size) |
{ |
TMemItem last = (TMemItem)block.Begin[1]; |
TMemItem prevlast = MEMORY_HEAP_PREV(last); |
return (void*)( (MEMORY_HEAP_FREE(prevlast) ? prevlast : last) + MemAddSize + |
((size <= MemMinSize) ? MemMinSize : MEMORY_HEAP_ALIGN_UP(size)) ); |
long mem_Init(); |
void *mem_Alloc(unsigned long size); |
void *mem_ReAlloc(unsigned long size, void *mem); |
bool mem_Free(void *mem); |
} |
inline unsigned int BlockSize(TMemBlock block) |
{ |
if (!block.Begin) return 0; |
return (unsigned int)(block.Begin[1] - (TMemItem)block.Begin); |
} |
#endif // ndef __MEMORY_HEAP_H_INCLUDED_ |
inline unsigned int MemSize(void *mem) |
{ |
if (!mem) return 0; |
TMemItem c = (TMemItem)mem; |
return MEMORY_HEAP_NEXT(c) - c - MemAddSize; |
} |
// Free space item functions. |
TMemItem _FirstNotZeroBit(TMemItem i) |
{ |
TMemItem r = 0; |
while ((i >>= 1) != 0) r++; |
return r; |
} |
void _RBTreeRotate(TMemItem parent, TMemItem item, int side) |
{ |
TMemItem temp = MEMORY_HEAP_ITEM(parent,0); |
MEMORY_HEAP_ITEM(item,0) = temp; |
if (temp) |
{ |
if (MEMORY_HEAP_ITEM(temp,2) == parent) |
{ |
MEMORY_HEAP_ITEM(temp,2) = item; |
} |
else MEMORY_HEAP_ITEM(temp,3) = item; |
} |
temp = MEMORY_HEAP_ITEM(item,side^1); |
if (temp) MEMORY_HEAP_ITEM(temp,0) = parent; |
MEMORY_HEAP_ITEM(parent,side) = temp; |
MEMORY_HEAP_ITEM(parent,0) = item; |
MEMORY_HEAP_ITEM(item,side^1) = parent; |
temp = MEMORY_HEAP_ITEM(parent,1); |
MEMORY_HEAP_ITEM(parent,1) = MEMORY_HEAP_ITEM(item,1); |
MEMORY_HEAP_ITEM(item,1) = temp; |
} |
void InitFreeSpace(TFreeSpace &fs) |
{ |
TMemItem i; |
for (i = 0; i <= NumTreeSmall; i++) fs.Small[i] = 0; |
fs.Min = 0; fs.SmallMask = 0; |
} |
void _FreeAdd(TFreeSpace &fs, TMemItem item) |
{ |
TMemItem size = MEMORY_HEAP_NEXT(item) - item; |
if (size < MemAddSize + MemMinSize + MemAlign * NumTreeSmall) |
{ |
TMemItem s = (size - (MemAddSize + MemMinSize)) / MemAlign; |
TMemItem &addto = fs.Small[s]; |
MEMORY_HEAP_ITEM(item,1) = (TMemItem)(&addto); |
MEMORY_HEAP_ITEM(item,0) = (TMemItem)addto; |
if (addto) MEMORY_HEAP_ITEM(addto,1) = item; |
addto = item; |
fs.SmallMask |= TMemItem(1) << s; |
return; |
} |
TMemItem addto = fs.Min, parent, temp; |
MEMORY_HEAP_ITEM(item,2) = 0; |
MEMORY_HEAP_ITEM(item,3) = 0; |
if (!addto) |
{ |
MEMORY_HEAP_ITEM(item,0) = 0; |
MEMORY_HEAP_ITEM(item,1) = 1; |
fs.Min = item; |
return; |
} |
MEMORY_HEAP_ITEM(item,1) = 0; |
TMemItem side = 2; |
if (MEMORY_HEAP_NEXT(addto) - addto >= size) fs.Min = item; |
else |
{ |
for (;;) |
{ |
parent = MEMORY_HEAP_ITEM(addto,0); |
if (!parent) break; |
if (MEMORY_HEAP_NEXT(parent) - parent < size) addto = parent; |
else break; |
} |
for (;;) |
{ |
if (MEMORY_HEAP_NEXT(addto) - addto < size) |
{ |
temp = MEMORY_HEAP_ITEM(addto,3); |
if (!temp) {side = 3; break;} |
addto = temp; |
} |
else |
{ |
temp = MEMORY_HEAP_ITEM(addto,2); |
if (!temp) break; |
addto = temp; |
} |
} |
} |
MEMORY_HEAP_ITEM(item,0) = addto; |
MEMORY_HEAP_ITEM(addto,side) = item; |
for (;;) |
{ |
if (MEMORY_HEAP_ITEM(addto,1) != 0) return; |
parent = MEMORY_HEAP_ITEM(addto,0); |
temp = MEMORY_HEAP_ITEM(parent,2); |
if (temp == addto) |
{ |
temp = MEMORY_HEAP_ITEM(parent,3); |
side = 2; |
} |
else side = 3; |
if (!temp || MEMORY_HEAP_ITEM(temp,1) != 0) break; |
MEMORY_HEAP_ITEM(addto,1) = 1; |
MEMORY_HEAP_ITEM(temp,1) = 1; |
item = parent; |
addto = MEMORY_HEAP_ITEM(item,0); |
if (!addto) return; |
MEMORY_HEAP_ITEM(item,1) = 0; |
} |
if (MEMORY_HEAP_ITEM(addto,side) != item) |
{ |
temp = MEMORY_HEAP_ITEM(item,side); |
if (temp) MEMORY_HEAP_ITEM(temp,0) = addto; |
MEMORY_HEAP_ITEM(addto,side^1) = temp; |
MEMORY_HEAP_ITEM(addto,0) = item; |
MEMORY_HEAP_ITEM(item,side) = addto; |
MEMORY_HEAP_ITEM(item,0) = parent; |
MEMORY_HEAP_ITEM(parent,side) = item; |
} |
else item = addto; |
_RBTreeRotate(parent, item, side); |
} |
void _FreeDel(TFreeSpace &fs, TMemItem item) |
{ |
TMemItem size = MEMORY_HEAP_NEXT(item) - item; |
if (size < MemAddSize + MemMinSize + MemAlign * NumTreeSmall) |
{ |
TMemItem prev = MEMORY_HEAP_ITEM(item,1); |
TMemItem next = MEMORY_HEAP_ITEM(item,0); |
MEMORY_HEAP_ITEM(prev,0) = next; |
if (next) MEMORY_HEAP_ITEM(next,1) = prev; |
else |
{ |
TMemItem s = (size - (MemAddSize + MemMinSize)) / MemAlign; |
if (!fs.Small[s]) fs.SmallMask &= ~(TMemItem(1) << s); |
} |
return; |
} |
TMemItem parent, temp, second, add; |
TMemItem side = 2; |
temp = MEMORY_HEAP_ITEM(item,3); |
if (temp) |
{ |
for (;;) |
{ |
second = temp; |
temp = MEMORY_HEAP_ITEM(temp,2); |
if (!temp) break; |
} |
if (fs.Min == item) fs.Min = second; |
add = MEMORY_HEAP_ITEM(second,3); |
parent = MEMORY_HEAP_ITEM(second,0); |
if (parent == item) {parent = second; side = 3;} |
else |
{ |
temp = MEMORY_HEAP_ITEM(item,3); |
MEMORY_HEAP_ITEM(second,3) = temp; |
MEMORY_HEAP_ITEM(temp,0) = second; |
} |
temp = MEMORY_HEAP_ITEM(item,2); |
MEMORY_HEAP_ITEM(second,2) = temp; |
if (temp) MEMORY_HEAP_ITEM(temp,0) = second; |
temp = MEMORY_HEAP_ITEM(item,0); |
MEMORY_HEAP_ITEM(second,0) = temp; |
if (temp) |
{ |
if (MEMORY_HEAP_ITEM(temp,2) == item) |
{ |
MEMORY_HEAP_ITEM(temp,2) = second; |
} |
else MEMORY_HEAP_ITEM(temp,3) = second; |
} |
MEMORY_HEAP_ITEM(parent,side) = add; |
if (add) MEMORY_HEAP_ITEM(add,0) = parent; |
bool color = MEMORY_HEAP_ITEM(second,1); |
MEMORY_HEAP_ITEM(second,1) = MEMORY_HEAP_ITEM(item,1); |
if (!color) return; |
} |
else |
{ |
if (fs.Min == item) fs.Min = MEMORY_HEAP_ITEM(item,0); |
add = MEMORY_HEAP_ITEM(item,2); |
parent = MEMORY_HEAP_ITEM(item,0); |
if (add) MEMORY_HEAP_ITEM(add,0) = parent; |
if (parent) |
{ |
if (MEMORY_HEAP_ITEM(parent,2) == item) |
{ |
MEMORY_HEAP_ITEM(parent,2) = add; |
} |
else |
{ |
MEMORY_HEAP_ITEM(parent,3) = add; |
side = 3; |
} |
} |
else |
{ |
if (add) MEMORY_HEAP_ITEM(add,1) = 1; |
return; |
} |
if (!MEMORY_HEAP_ITEM(item,1)) return; |
} |
if (add && !MEMORY_HEAP_ITEM(add,1)) |
{ |
MEMORY_HEAP_ITEM(add,1) = 1; |
return; |
} |
for (;;) |
{ |
second = MEMORY_HEAP_ITEM(parent,side^1); |
if (!MEMORY_HEAP_ITEM(second,1)) |
{ |
_RBTreeRotate(parent, second, side^1); |
second = MEMORY_HEAP_ITEM(parent,side^1); |
} |
temp = MEMORY_HEAP_ITEM(second,side^1); |
if (temp && !MEMORY_HEAP_ITEM(temp,1)) |
{ |
MEMORY_HEAP_ITEM(temp,1) = 1; |
break; |
} |
temp = MEMORY_HEAP_ITEM(second,side); |
if (temp && !MEMORY_HEAP_ITEM(temp,1)) |
{ |
_RBTreeRotate(second, temp, side); |
MEMORY_HEAP_ITEM(second,1) = 1; |
second = temp; |
break; |
} |
MEMORY_HEAP_ITEM(second,1) = 0; |
if (!MEMORY_HEAP_ITEM(parent,1)) |
{ |
MEMORY_HEAP_ITEM(parent,1) = 1; |
return; |
} |
second = parent; |
parent = MEMORY_HEAP_ITEM(second,0); |
if (!parent) return; |
if (MEMORY_HEAP_ITEM(parent,2) == second) side = 2; |
else side = 3; |
} |
_RBTreeRotate(parent, second, side^1); |
} |
TMemItem _FreeFindAfter(TMemItem item, TMemItem size) |
{ |
if (!item) return 0; |
TMemItem paritem, s; |
if (MEMORY_HEAP_NEXT(item) - item >= size) return item; |
for (;;) |
{ |
paritem = MEMORY_HEAP_ITEM(item,0); |
if (!paritem) break; |
s = MEMORY_HEAP_NEXT(paritem) - paritem; |
if (s == size) return paritem; |
if (s < size) item = paritem; |
else break; |
} |
MEMORY_HEAP_ITEM(item,3); |
for (;;) |
{ |
if (!item) return paritem; |
s = MEMORY_HEAP_NEXT(item) - item; |
if (s == size) return item; |
if (s < size) item = MEMORY_HEAP_ITEM(item,3); |
else |
{ |
paritem = item; |
item = MEMORY_HEAP_ITEM(item,2); |
} |
} |
} |
TMemItem _FreeFind(TFreeSpace &fs, TMemItem size) |
{ |
TMemItem item, nextitem, s; |
if (size < MemAddSize + MemMinSize + MemAlign * NumTreeSmall) |
{ |
TMemItem m, t; |
s = (size - (MemAddSize + MemMinSize)) / MemAlign; |
item = fs.Small[s]; |
if (item) return item; |
if (size < MemAlign * NumTreeSmall) |
{ |
t = size / MemAlign; |
m = fs.SmallMask >> t; |
if (m) return fs.Small[t + _FirstNotZeroBit(m)]; |
else if (fs.Min) return fs.Min; |
} |
else |
{ |
item = _FreeFindAfter(fs.Min, size + 1 + MemAddSize + MemMinSize); |
if (item) return item; |
} |
m = fs.SmallMask >> s; |
if (m) return fs.Small[s + _FirstNotZeroBit(m)]; |
else return fs.Min; |
} |
item = _FreeFindAfter(fs.Min, ++size); |
if (!item) return 0; |
s = MEMORY_HEAP_NEXT(item) - item; |
if (s == size) return item; |
size += MemAddSize + MemMinSize; |
if (s >= size) return item; |
nextitem = _FreeFindAfter(item, size); |
return nextitem ? nextitem : item; |
} |
// Block functions. |
inline void _CreateBlockEnd(TMemBlock &block, TFreeSpace &fs, TMemItem c, TMemItem e) |
{ |
block.Begin[0] = (TMemItem)(&fs); |
if (e - c < TMemItem(MemAddSize + MemMinSize)) |
{ |
MEMORY_HEAP_NEXT(c) = 0; |
block.Begin[1] = c; |
} |
else |
{ |
MEMORY_HEAP_NEXT(c) = e + 1; |
_FreeAdd(fs, c); |
MEMORY_HEAP_PREV(e) = c; |
MEMORY_HEAP_NEXT(e) = 0; |
block.Begin[1] = e; |
} |
} |
TMemBlock CreateBlock(void *begin, void *end, TFreeSpace &fs) |
{ |
TMemBlock block = {0}; |
TMemItem b = MEMORY_HEAP_ALIGN_UP(begin); |
TMemItem e = MEMORY_HEAP_ALIGN_DOWN(end); |
if (e <= b || e - b < TMemItem(BlockAddSize - MemAddSize)) return block; |
block.Begin = (TMemItem*)b; |
b += MEMORY_HEAP_ALIGN_UP(4 * sizeof(TMemItem)); |
MEMORY_HEAP_PREV(b) = 0; |
_CreateBlockEnd(block, fs, b, e); |
return block; |
} |
TMemBlock CreateBlock(void *begin, void *end) |
{ |
TMemBlock block = {0}; |
TMemItem b = MEMORY_HEAP_ALIGN_UP(begin); |
TMemItem e = MEMORY_HEAP_ALIGN_DOWN(end); |
if (e <= b || e - b < TMemItem(BlockAddSizeFS - MemAddSize)) return block; |
block.Begin = (TMemItem*)b; |
b += MEMORY_HEAP_ALIGN_UP(4 * sizeof(TMemItem)); |
TMemItem c = b + MemAddSize + MEMORY_HEAP_ALIGN_UP(sizeof(TFreeSpace)); |
MEMORY_HEAP_PREV(b) = 0; |
MEMORY_HEAP_NEXT(b) = c; |
MEMORY_HEAP_PREV(c) = b; |
InitFreeSpace(*(TFreeSpace*)b); |
_CreateBlockEnd(block, *(TFreeSpace*)b, c, e); |
return block; |
} |
void ResizeBlock(TMemBlock block, void *new_end) |
{ |
if (!BlockValid(block)) return; |
TMemItem e = MEMORY_HEAP_ALIGN_DOWN(new_end); |
TMemItem c = block.Begin[1]; |
TFreeSpace &fs = *(TFreeSpace*)block.Begin[0]; |
do |
{ |
if (c == e) return; |
else if (c > e) |
{ |
while ((c = MEMORY_HEAP_PREV(c)) > e) |
{ |
if (MEMORY_HEAP_FREE(c)) _FreeDel(fs, c); |
} |
if (!c) {block.Begin = 0; return;} |
if (MEMORY_HEAP_FREE(c)) |
{ |
_FreeDel(fs, c); |
if (e - c < TMemItem(MemAddSize + MemMinSize)) e = c; |
else |
{ |
MEMORY_HEAP_NEXT(c) = e + 1; |
_FreeAdd(*(TFreeSpace*)block.Begin[0], c); |
break; |
} |
} |
else if (e - c >= TMemItem(MemAddSize + MemMinSize)) |
{ |
MEMORY_HEAP_NEXT(c) = e; break; |
} |
MEMORY_HEAP_NEXT(c) = 0; |
block.Begin[1] = c; |
if (c == e) return; |
} |
TMemItem pc = MEMORY_HEAP_PREV(c); |
if (pc && MEMORY_HEAP_FREE(pc)) _FreeDel(fs, c = pc); |
else if (e - c < TMemItem(MemAddSize + MemMinSize)) return; |
MEMORY_HEAP_NEXT(c) = e + 1; |
_FreeAdd(fs, c); |
} while(false); |
MEMORY_HEAP_PREV(e) = c; |
MEMORY_HEAP_NEXT(e) = 0; |
block.Begin[1] = e; |
} |
void RemoveBlock(TMemBlock block) |
{ |
if (!BlockValid(block)) return; |
TMemItem e = block.Begin[1]; |
TFreeSpace &fs = *(TFreeSpace*)block.Begin[0]; |
while ((e = MEMORY_HEAP_PREV(e)) != 0) |
{ |
if (MEMORY_HEAP_FREE(e)) _FreeDel(fs, e); |
} |
block.Begin = 0; |
} |
// Free space functions. |
void _CopyMemItemArray(TMemItem dest, TMemItem src, TMemItem end) |
{ |
TMemItem k = (end - src) / sizeof(TMemItem); |
TMemItem *d = (TMemItem*)dest; |
TMemItem *s = (TMemItem*)src; |
while (k--) *(d++) = *(s++); |
} |
void *Alloc(TFreeSpace &fs, unsigned int size) |
{ |
if (!size) return 0; |
TMemItem s = MEMORY_HEAP_ALIGN_UP(size) + MemAddSize; |
if (s < MemAddSize + MemMinSize) s = MemAddSize + MemMinSize; |
TMemItem c = _FreeFind(fs, s); |
if (!c) return 0; |
_FreeDel(fs, c); |
TMemItem nc = --MEMORY_HEAP_NEXT(c); |
TMemItem mc = c + s; |
if (nc - (MemAddSize + MemMinSize) >= mc) |
{ |
MEMORY_HEAP_NEXT(c) = mc; |
MEMORY_HEAP_PREV(mc) = c; |
MEMORY_HEAP_NEXT(mc) = nc + 1; |
MEMORY_HEAP_PREV(nc) = mc; |
_FreeAdd(fs, mc); |
} |
return (void*)c; |
} |
void *ReAlloc(TFreeSpace &fs, void *mem, unsigned int size) |
{ |
if (!mem) return Alloc(fs, size); |
if (!size) {Free(fs, mem); return 0;} |
TMemItem s = MEMORY_HEAP_ALIGN_UP(size) + MemAddSize; |
TMemItem c = (TMemItem)mem; |
TMemItem mc = MEMORY_HEAP_NEXT(c); |
TMemItem nc = MEMORY_HEAP_NEXT(mc); |
if (--nc & 1) nc = mc; |
if (s < MemAddSize + MemMinSize) s = MemAddSize + MemMinSize; |
if (nc - c < s) |
{ |
mem = Alloc(fs, size); |
if (mem) |
{ |
_CopyMemItemArray((TMemItem)mem, c, mc - MemAddSize); |
Free(fs, (void*)c); |
return mem; |
} |
else |
{ |
TMemItem pc = MEMORY_HEAP_PREV(c); |
if (pc && MEMORY_HEAP_FREE(pc) && nc - pc >= s) |
{ |
_FreeDel(fs, pc); |
_CopyMemItemArray(pc, c, mc - MemAddSize); |
c = pc; |
} |
else return 0; |
} |
} |
if (mc < nc) _FreeDel(fs, mc); |
mc = c + s; |
if (nc - (MemAddSize + MemMinSize) >= mc) |
{ |
MEMORY_HEAP_NEXT(c) = mc; |
MEMORY_HEAP_PREV(mc) = c; |
MEMORY_HEAP_NEXT(mc) = nc + 1; |
MEMORY_HEAP_PREV(nc) = mc; |
_FreeAdd(fs, mc); |
} |
else |
{ |
MEMORY_HEAP_NEXT(c) = nc; |
MEMORY_HEAP_PREV(nc) = c; |
} |
return (void*)c; |
} |
int free_a = 0; |
void Free(TFreeSpace &fs, void *mem) |
{ |
TMemItem c = (TMemItem)mem; |
if (!c) return; |
TMemItem pc = MEMORY_HEAP_PREV(c); |
TMemItem mc = MEMORY_HEAP_NEXT(c); |
TMemItem nc = MEMORY_HEAP_NEXT(mc); |
if (--nc & 1) nc = mc; |
else _FreeDel(fs, mc); |
if (free_a == 1) return; |
if (pc && MEMORY_HEAP_FREE(pc)) _FreeDel(fs, c = pc); |
MEMORY_HEAP_NEXT(c) = nc + 1; |
MEMORY_HEAP_PREV(nc) = c; |
if (free_a == 2) return; |
_FreeAdd(fs, c); |
} |
} |
#endif // ndef __MEMORY_HEAP_RBTREE_H_INCLUDED_ |
/programs/demos/life2/life2.cpp |
---|
1362,7 → 1362,7 |
if (state != 2) return; |
char *name = OpenFileGetName(open_file_str); |
if (!name) return; |
TFileData file = FileOpen(name); |
FileInfoBlock* file = FileOpen(name); |
if (!file) return; |
int k = FileGetLength(file); |
unsigned char *pict = 0; |