1 /*
2 TiMidity++ -- MIDI to WAVE converter and player
3 Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
4 Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include <string.h>
26
27 #include "timidity.h"
28 #include "common.h"
29
30 namespace TimidityPlus
31 {
32
33 struct MBlock
34 {
35 MBlockNode* free_mblock_list = NULL;
36
~MBlockTimidityPlus::MBlock37 ~MBlock()
38 {
39 int cnt;
40
41 cnt = 0;
42 while (free_mblock_list)
43 {
44 MBlockNode* tmp;
45
46 tmp = free_mblock_list;
47 free_mblock_list = free_mblock_list->next;
48 free(tmp);
49 cnt++;
50 }
51 }
52 };
53
54 static MBlock free_list;
55
56 #define ADDRALIGN 8
57 /* #define DEBUG */
58
init_mblock(MBlockList * mblock)59 void init_mblock(MBlockList *mblock)
60 {
61 mblock->first = NULL;
62 mblock->allocated = 0;
63 }
64
new_mblock_node(size_t n)65 static MBlockNode *new_mblock_node(size_t n)
66 {
67 MBlockNode *p;
68
69 if (n > MIN_MBLOCK_SIZE)
70 {
71 if ((p = (MBlockNode *)safe_malloc(n + sizeof(MBlockNode))) == NULL)
72 return NULL;
73 p->block_size = n;
74 }
75 else if (free_list.free_mblock_list == NULL)
76 {
77 if ((p = (MBlockNode *)safe_malloc(sizeof(MBlockNode) + MIN_MBLOCK_SIZE)) == NULL)
78 return NULL;
79 p->block_size = MIN_MBLOCK_SIZE;
80 }
81 else
82 {
83 p = free_list.free_mblock_list;
84 free_list.free_mblock_list = free_list.free_mblock_list->next;
85 }
86
87 p->offset = 0;
88 p->next = NULL;
89
90 return p;
91 }
92
enough_block_memory(MBlockList * mblock,size_t n)93 static int enough_block_memory(MBlockList *mblock, size_t n)
94 {
95 size_t newoffset;
96
97 if(mblock->first == NULL)
98 return 0;
99
100 newoffset = mblock->first->offset + n;
101
102 if(newoffset < mblock->first->offset) /* exceed representable in size_t */
103 return 0;
104
105 if(newoffset > mblock->first->block_size)
106 return 0;
107
108 return 1;
109 }
110
new_segment(MBlockList * mblock,size_t nbytes)111 void *new_segment(MBlockList *mblock, size_t nbytes)
112 {
113 MBlockNode *p;
114 void *addr;
115
116 /* round up to ADDRALIGN */
117 nbytes = ((nbytes + ADDRALIGN - 1) & ~(ADDRALIGN - 1));
118 if (!enough_block_memory(mblock, nbytes))
119 {
120 p = new_mblock_node(nbytes);
121 p->next = mblock->first;
122 mblock->first = p;
123 mblock->allocated += p->block_size;
124 }
125 else
126 p = mblock->first;
127
128 addr = (void *)(p->buffer + p->offset);
129 p->offset += nbytes;
130
131 return addr;
132 }
133
reuse_mblock1(MBlockNode * p)134 static void reuse_mblock1(MBlockNode *p)
135 {
136 if (p->block_size > MIN_MBLOCK_SIZE)
137 free(p);
138 else /* p->block_size <= MIN_MBLOCK_SIZE */
139 {
140 p->next = free_list.free_mblock_list;
141 free_list.free_mblock_list = p;
142 }
143 }
144
reuse_mblock(MBlockList * mblock)145 void reuse_mblock(MBlockList *mblock)
146 {
147 MBlockNode *p;
148
149 if ((p = mblock->first) == NULL)
150 return; /* There is nothing to collect memory */
151
152 while (p)
153 {
154 MBlockNode *tmp;
155
156 tmp = p;
157 p = p->next;
158 reuse_mblock1(tmp);
159 }
160 init_mblock(mblock);
161 }
162
strdup_mblock(MBlockList * mblock,const char * str)163 char *strdup_mblock(MBlockList *mblock, const char *str)
164 {
165 int len;
166 char *p;
167
168 len = (int)strlen(str);
169 p = (char *)new_segment(mblock, len + 1); /* for '\0' */
170 memcpy(p, str, len + 1);
171 return p;
172 }
173
174 }