/* TiMidity++ -- MIDI to WAVE converter and player Copyright (C) 1999-2002 Masanao Izumo Copyright (C) 1995 Tuukka Toivonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "timidity.h" #include "common.h" namespace TimidityPlus { struct MBlock { MBlockNode* free_mblock_list = NULL; ~MBlock() { int cnt; cnt = 0; while (free_mblock_list) { MBlockNode* tmp; tmp = free_mblock_list; free_mblock_list = free_mblock_list->next; free(tmp); cnt++; } } }; static MBlock free_list; #define ADDRALIGN 8 /* #define DEBUG */ void init_mblock(MBlockList *mblock) { mblock->first = NULL; mblock->allocated = 0; } static MBlockNode *new_mblock_node(size_t n) { MBlockNode *p; if (n > MIN_MBLOCK_SIZE) { if ((p = (MBlockNode *)safe_malloc(n + sizeof(MBlockNode))) == NULL) return NULL; p->block_size = n; } else if (free_list.free_mblock_list == NULL) { if ((p = (MBlockNode *)safe_malloc(sizeof(MBlockNode) + MIN_MBLOCK_SIZE)) == NULL) return NULL; p->block_size = MIN_MBLOCK_SIZE; } else { p = free_list.free_mblock_list; free_list.free_mblock_list = free_list.free_mblock_list->next; } p->offset = 0; p->next = NULL; return p; } static int enough_block_memory(MBlockList *mblock, size_t n) { size_t newoffset; if(mblock->first == NULL) return 0; newoffset = mblock->first->offset + n; if(newoffset < mblock->first->offset) /* exceed representable in size_t */ return 0; if(newoffset > mblock->first->block_size) return 0; return 1; } void *new_segment(MBlockList *mblock, size_t nbytes) { MBlockNode *p; void *addr; /* round up to ADDRALIGN */ nbytes = ((nbytes + ADDRALIGN - 1) & ~(ADDRALIGN - 1)); if (!enough_block_memory(mblock, nbytes)) { p = new_mblock_node(nbytes); p->next = mblock->first; mblock->first = p; mblock->allocated += p->block_size; } else p = mblock->first; addr = (void *)(p->buffer + p->offset); p->offset += nbytes; return addr; } static void reuse_mblock1(MBlockNode *p) { if (p->block_size > MIN_MBLOCK_SIZE) free(p); else /* p->block_size <= MIN_MBLOCK_SIZE */ { p->next = free_list.free_mblock_list; free_list.free_mblock_list = p; } } void reuse_mblock(MBlockList *mblock) { MBlockNode *p; if ((p = mblock->first) == NULL) return; /* There is nothing to collect memory */ while (p) { MBlockNode *tmp; tmp = p; p = p->next; reuse_mblock1(tmp); } init_mblock(mblock); } char *strdup_mblock(MBlockList *mblock, const char *str) { int len; char *p; len = (int)strlen(str); p = (char *)new_segment(mblock, len + 1); /* for '\0' */ memcpy(p, str, len + 1); return p; } }