summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2014-03-11 15:54:58 +0000
committer Aaron Giles <aaron@aarongiles.com>2014-03-11 15:54:58 +0000
commit4ea9df02a1daf1893246a01e21ffe201781f9266 (patch)
tree70dcb5feb88dcabe713fc172c30fd159ed1a0a43 /src/lib
parentb05606404a780c5309d39d8ee45411292279f117 (diff)
Moved core template container classes up from emutempl.h to coretmpl.h:
[Aaron Giles] * these classes now no longer take a resource_pool; everything is managed globally -- this means that objects added to lists must be allocated with global_alloc * added new auto_pointer<> template which wraps a pointer and auto-frees it upon destruction; it also defaults to NULL so it doesn't need to be explicitly initialized * moved tagged_list template to tagmap.h Redo of the low-level memory tracking system: [Aaron Giles] * moved low-level tracking out of emu\emualloc into lib\util\corealloc so it can be shared among all components and used by core libraries * global_alloc and friends no longer use a resource pool to track allocations; turns out this was a wholly redundant system that wasted a lot of memory * removed global_resource_pool entirely * added global_free_array to delete arrays allocated with global_alloc_array * added tracking of object versus array allocation; we will now error if you use global_free on an array, or global_free_array on an object Added new utility helper const_string_pool which can be used to efficiently accumulate strings that are not intended to be modified. Used by updated makelist and software list code. [Aaron Giles] Updated png2bdc and makelist tools to not leak memory and use more modern techniques (no more MAX_DRIVERS in makelist, for example). [Aaron Giles] Deprecated auto_strdup and removed all uses by way of caller-managed astrings and the software list rewrite. [Aaron Giles] Rewrote software list management: [Aaron Giles] * removed the notion of a software_list that is separate from a software_list_device; they are one and the same now * moved several functions into device_image_interface since they really didn't belong in the core software list class * lots of simplification as a result of the above changes Additional notes (no whatsnew): Moved definition of FPTR to osdcomm.h. Some changes happened in the OSD code to fix issues, especially regarding freeing arrays. SDL folks may need to fix up some of these. The following devices still are using tokens and should be modernized (I found them because they kept their token as void * and tried to delete it, which you can't): namco_52xx_device (mame/audio/namco52.c) namco_54xx_device (mame/audio/namco54.c) namco_06xx_device (mame/machine/namco06.c) namco_50xx_device (mame/machine/namco50.c) namco_51xx_device (mame/machine/namco51.c) namco_53xx_device (mame/machine/namco53.c) voodoo_device (emu/video/voodoo.c) mos6581_device (emu/sound/mos6581.c) aica_device (emu/sound/aica.c) scsp_device (emu/sound/scsp.c) dmadac_sound_device (emu/sound/dmadac.c) s3c2440_device (emu/machine/s3c2440.c) wd1770_device (emu/machine/wd17xx.c) latch8_device (emu/machine/latch8.c) duart68681_device (emu/machine/68681.c) s3c2400_device (emu/machine/s3c2400.c) s3c2410_device (emu/machine/s3c2410.c) strataflash_device (mess/machine/strata.c) hd63450_device (mess/machine/hd63450.c) tap_990_device (mess/machine/ti99/990_tap.c) omti8621_device (mess/machine/omti8621.c) vdt911_device (mess/video/911_vdt.c) apollo_graphics_15i (mess/video/apollo.c) asr733_device (mess/video/733_asr.c)
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/formats/cassimg.c74
-rw-r--r--src/lib/formats/cassimg.h12
-rw-r--r--src/lib/formats/cbm_crt.c7
-rw-r--r--src/lib/formats/cbm_crt.h2
-rw-r--r--src/lib/formats/ccvf_dsk.c12
-rw-r--r--src/lib/formats/d64_dsk.c9
-rw-r--r--src/lib/formats/dfi_dsk.c15
-rw-r--r--src/lib/formats/flopimg.c25
-rw-r--r--src/lib/formats/g64_dsk.c8
-rw-r--r--src/lib/formats/hxcmfm_dsk.c12
-rw-r--r--src/lib/formats/imd_dsk.c3
-rw-r--r--src/lib/formats/ipf_dsk.c28
-rw-r--r--src/lib/formats/mfi_dsk.c13
-rw-r--r--src/lib/formats/pasti_dsk.c14
-rw-r--r--src/lib/formats/td0_dsk.c3
-rw-r--r--src/lib/formats/upd765_dsk.c4
-rw-r--r--src/lib/formats/wd177x_dsk.c3
-rw-r--r--src/lib/lib.mak2
-rw-r--r--src/lib/util/aviio.c17
-rw-r--r--src/lib/util/corealloc.c375
-rw-r--r--src/lib/util/corealloc.h121
-rw-r--r--src/lib/util/coretmpl.h335
-rw-r--r--src/lib/util/cstrpool.c100
-rw-r--r--src/lib/util/cstrpool.h63
-rw-r--r--src/lib/util/options.c179
-rw-r--r--src/lib/util/options.h15
-rw-r--r--src/lib/util/simple_set.h25
-rw-r--r--src/lib/util/tagmap.h109
-rw-r--r--src/lib/util/xmlfile.c32
29 files changed, 1272 insertions, 345 deletions
diff --git a/src/lib/formats/cassimg.c b/src/lib/formats/cassimg.c
index 1594cf6121c..0b428272ed5 100644
--- a/src/lib/formats/cassimg.c
+++ b/src/lib/formats/cassimg.c
@@ -10,7 +10,6 @@
#include <string.h>
#include "imageutl.h"
-#include "pool.h"
#include "cassimg.h"
@@ -84,16 +83,11 @@ static cassette_image *cassette_init(const struct CassetteFormat *format, void *
{
cassette_image *cassette;
- cassette = (cassette_image *)malloc(sizeof(cassette_image));
- if (!cassette)
- return NULL;
-
- memset(cassette, 0, sizeof(*cassette));
+ cassette = global_alloc_clear(cassette_image);
cassette->format = format;
cassette->io.file = file;
cassette->io.procs = procs;
cassette->flags = flags;
- cassette->pool = pool_alloc_lib(NULL);
return cassette;
}
@@ -282,8 +276,9 @@ void cassette_close(cassette_image *cassette)
{
if ((cassette->flags & CASSETTE_FLAG_DIRTY) && (cassette->flags & CASSETTE_FLAG_SAVEONEXIT))
cassette_save(cassette);
- pool_free_lib(cassette->pool);
- free(cassette);
+ for (int i = 0; i < cassette->blocks.count(); i++)
+ global_free(cassette->blocks[i]);
+ global_free(cassette);
}
}
@@ -375,59 +370,26 @@ static casserr_t compute_manipulation_ranges(cassette_image *cassette, int chann
-static casserr_t lookup_sample(cassette_image *cassette, int channel, size_t sample, int allocate, INT32 **ptr)
+static casserr_t lookup_sample(cassette_image *cassette, int channel, size_t sample, INT32 **ptr)
{
- size_t sample_block;
- size_t sample_index;
- size_t sample_size;
- size_t new_block_count;
- size_t new_block_sample_count;
- INT32 *new_block;
- struct sample_block *new_blocks;
- struct sample_block *block;
-
*ptr = NULL;
- sample_block = (sample / SAMPLES_PER_BLOCK) * cassette->channels + channel;
- sample_index = sample % SAMPLES_PER_BLOCK;
- sample_size = sizeof(block->block[0]);
+ size_t sample_blocknum = (sample / SAMPLES_PER_BLOCK) * cassette->channels + channel;
+ size_t sample_index = sample % SAMPLES_PER_BLOCK;
/* is this block beyond the edge of our waveform? */
- if (sample_block >= cassette->block_count)
- {
- if (!allocate)
- return CASSETTE_ERROR_SUCCESS;
-
- /* allocate new blocks */
- new_block_count = sample_block + 1;
- new_blocks = (struct sample_block *)pool_realloc_lib(cassette->pool, cassette->blocks, new_block_count * sizeof(cassette->blocks[0]));
- if (!new_blocks)
- return CASSETTE_ERROR_OUTOFMEMORY;
-
- cassette->blocks = new_blocks;
- memset(&cassette->blocks[cassette->block_count], 0, (new_block_count - cassette->block_count) * sizeof(cassette->blocks[0]));
- cassette->block_count = new_block_count;
- }
+ if (sample_blocknum >= cassette->blocks.count())
+ cassette->blocks.resize_keep_and_clear_new(sample_blocknum + 1);
+
+ if (cassette->blocks[sample_blocknum] == NULL)
+ cassette->blocks[sample_blocknum] = global_alloc(sample_block);
- block = &cassette->blocks[sample_block];
+ sample_block &block = *cassette->blocks[sample_blocknum];
/* is this sample access off the current block? */
- if (sample_index >= block->sample_count)
- {
- if (!allocate)
- return CASSETTE_ERROR_SUCCESS;
-
- new_block_sample_count = SAMPLES_PER_BLOCK;
-
- new_block = (INT32*)pool_realloc_lib(cassette->pool, block->block, new_block_sample_count * sample_size);
- if (!new_block)
- return CASSETTE_ERROR_OUTOFMEMORY;
-
- block->block = new_block;
- memset(&block->block[block->sample_count], 0, (new_block_sample_count - block->sample_count) * sample_size);
- block->sample_count = new_block_sample_count;
- }
+ if (sample_index >= block.count())
+ block.resize_keep_and_clear_new(SAMPLES_PER_BLOCK);
- *ptr = &block->block[sample_index];
+ *ptr = &block[sample_index];
return CASSETTE_ERROR_SUCCESS;
}
@@ -467,7 +429,7 @@ casserr_t cassette_get_samples(cassette_image *cassette, int channel,
/* find the sample that we are putting */
d = map_double(ranges.sample_last + 1 - ranges.sample_first, 0, sample_count, sample_index) + ranges.sample_first;
cassette_sample_index = (size_t) d;
- err = lookup_sample(cassette, channel, cassette_sample_index, TRUE, (INT32 **) &source_ptr);
+ err = lookup_sample(cassette, channel, cassette_sample_index, (INT32 **) &source_ptr);
if (err)
return err;
@@ -573,7 +535,7 @@ casserr_t cassette_put_samples(cassette_image *cassette, int channel,
for (channel = ranges.channel_first; channel <= ranges.channel_last; channel++)
{
/* find the sample that we are putting */
- err = lookup_sample(cassette, channel, sample_index, TRUE, &dest_ptr);
+ err = lookup_sample(cassette, channel, sample_index, &dest_ptr);
if (err)
return err;
*dest_ptr = dest_value;
diff --git a/src/lib/formats/cassimg.h b/src/lib/formats/cassimg.h
index 93e55a5d601..bd7fc68db93 100644
--- a/src/lib/formats/cassimg.h
+++ b/src/lib/formats/cassimg.h
@@ -10,7 +10,7 @@
#define CASSIMG_H
#include "osdcore.h"
-#include "pool.h"
+#include "coretmpl.h"
#include "ioprocs.h"
#ifndef LOG_FORMATS
@@ -69,11 +69,7 @@ typedef enum
}
casserr_t;
-struct sample_block
-{
- INT32 *block;
- size_t sample_count;
-};
+typedef dynamic_array<INT32> sample_block;
struct CassetteOptions
{
@@ -94,14 +90,12 @@ struct cassette_image
{
const struct CassetteFormat *format;
struct io_generic io;
- object_pool *pool;
int channels;
int flags;
UINT32 sample_frequency;
- struct sample_block *blocks;
- size_t block_count;
+ dynamic_array<sample_block *> blocks;
size_t sample_count;
};
diff --git a/src/lib/formats/cbm_crt.c b/src/lib/formats/cbm_crt.c
index 54b127c5af5..fd44e061376 100644
--- a/src/lib/formats/cbm_crt.c
+++ b/src/lib/formats/cbm_crt.c
@@ -90,7 +90,7 @@ static const char * CRT_C64_SLOT_NAMES[_CRT_C64_COUNT] =
// cbm_crt_get_card - get slot interface card
//-------------------------------------------------
-const char * cbm_crt_get_card(core_file *file)
+void cbm_crt_get_card(astring &result, core_file *file)
{
// read the header
cbm_crt_header header;
@@ -100,10 +100,11 @@ const char * cbm_crt_get_card(core_file *file)
{
UINT16 hardware = pick_integer_be(header.hardware, 0, 2);
- return CRT_C64_SLOT_NAMES[hardware];
+ result.cpy(CRT_C64_SLOT_NAMES[hardware]);
+ return;
}
- return NULL;
+ result.reset();
}
diff --git a/src/lib/formats/cbm_crt.h b/src/lib/formats/cbm_crt.h
index f099daaf818..bfb8732442c 100644
--- a/src/lib/formats/cbm_crt.h
+++ b/src/lib/formats/cbm_crt.h
@@ -136,7 +136,7 @@ struct cbm_crt_chip
// FUNCTION PROTOTYPES
//**************************************************************************
-const char * cbm_crt_get_card(core_file *file);
+void cbm_crt_get_card(astring &result, core_file *file);
bool cbm_crt_read_header(core_file* file, size_t *roml_size, size_t *romh_size, int *exrom, int *game);
bool cbm_crt_read_data(core_file* file, UINT8 *roml, UINT8 *romh);
diff --git a/src/lib/formats/ccvf_dsk.c b/src/lib/formats/ccvf_dsk.c
index 0895e1ee4d6..7c9c0cd274f 100644
--- a/src/lib/formats/ccvf_dsk.c
+++ b/src/lib/formats/ccvf_dsk.c
@@ -90,11 +90,11 @@ bool ccvf_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
const format &f = formats[0];
UINT64 size = io_generic_size(io);
- UINT8 *img = global_alloc_array(UINT8, size);
+ dynamic_buffer img(size);
io_generic_read(io, img, 0, size);
- astring ccvf = astring((const char *)img, size);
- UINT8 *bytes = global_alloc_array(UINT8, 78720);
+ astring ccvf = astring((const char *)&img[0], size);
+ dynamic_buffer bytes(78720);
int start = 0, end = 0;
astring line;
@@ -119,7 +119,7 @@ bool ccvf_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
int total_size = 200000000/f.cell_size;
for(int track=0; track < f.track_count; track++) {
- UINT32 *buffer = global_alloc_array_clear(UINT32, total_size);
+ dynamic_array<UINT32> buffer(total_size);
int offset = 0;
for (int i=0; i<1920 && pos<size; i++, pos++) {
@@ -137,14 +137,10 @@ bool ccvf_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
}
generate_track_from_levels(track, 0, buffer, total_size, 0, image);
- global_free(buffer);
}
image->set_variant(f.variant);
- global_free(bytes);
- global_free(img);
-
return true;
}
diff --git a/src/lib/formats/d64_dsk.c b/src/lib/formats/d64_dsk.c
index c0ef28283cf..0d6295e2c38 100644
--- a/src/lib/formats/d64_dsk.c
+++ b/src/lib/formats/d64_dsk.c
@@ -189,14 +189,13 @@ bool d64_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
const format &f = formats[type];
UINT64 size = io_generic_size(io);
- UINT8 *img;
+ dynamic_buffer img;
if(size == (UINT32)f.sector_count*f.sector_base_size) {
- img = global_alloc_array(UINT8, size + f.sector_count);
- memset(&img[size], ERROR_00, f.sector_count);
+ img.resize_and_clear(size + f.sector_count, ERROR_00);
}
else {
- img = global_alloc_array(UINT8, size);
+ img.resize(size);
}
io_generic_read(io, img, 0, size);
@@ -235,8 +234,6 @@ bool d64_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
}
}
- global_free(img);
-
image->set_variant(f.variant);
return true;
diff --git a/src/lib/formats/dfi_dsk.c b/src/lib/formats/dfi_dsk.c
index 36e26359cdf..28a774c906e 100644
--- a/src/lib/formats/dfi_dsk.c
+++ b/src/lib/formats/dfi_dsk.c
@@ -68,8 +68,7 @@ bool dfi_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
{
UINT64 size = io_generic_size(io);
UINT64 pos = 4;
- UINT8 *data = 0;
- int data_size = 0; // size of currently allocated array for a track
+ dynamic_buffer data;
int onerev_time = 0; // time for one revolution, used to guess clock and rpm for DFE2 files
unsigned long clock_rate = 100000000; // sample clock rate in megahertz
int rpm=360; // drive rpm
@@ -84,18 +83,11 @@ bool dfi_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
// if the position-so-far-in-file plus 10 (for the header) plus track size
// is larger than the size of the file, free buffers and bail out
if(pos+tsize+10 > size) {
- if(data)
- global_free(data);
return false;
}
// reallocate the data array if it gets too small
- if(tsize > data_size) {
- if(data)
- global_free(data);
- data_size = tsize;
- data = global_alloc_array(UINT8, data_size);
- }
+ data.resize(tsize);
pos += 10; // skip the header, we already read it
io_generic_read(io, data, pos, tsize);
@@ -229,9 +221,6 @@ bool dfi_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
image->set_track_size(track, head, tpos);
}
- if(data)
- global_free(data);
-
return true;
}
diff --git a/src/lib/formats/flopimg.c b/src/lib/formats/flopimg.c
index 04b88d3b337..ca9af339518 100644
--- a/src/lib/formats/flopimg.c
+++ b/src/lib/formats/flopimg.c
@@ -430,7 +430,7 @@ static floperr_t floppy_readwrite_sector(floppy_image_legacy *floppy, int head,
floperr_t err;
const struct FloppyCallbacks *fmt;
size_t this_buffer_len;
- UINT8 *alloc_buf = NULL;
+ dynamic_buffer alloc_buf;
UINT32 sector_length;
UINT8 *buffer_ptr = (UINT8 *)buffer;
floperr_t (*read_sector)(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen);
@@ -486,13 +486,7 @@ static floperr_t floppy_readwrite_sector(floppy_image_legacy *floppy, int head,
{
/* we will be doing an partial read/write; in other words we
* will not be reading/writing a full sector */
- if (alloc_buf) free(alloc_buf);
- alloc_buf = (UINT8*)malloc(sector_length);
- if (!alloc_buf)
- {
- err = FLOPPY_ERROR_OUTOFMEMORY;
- goto done;
- }
+ alloc_buf.resize(sector_length);
/* read the sector (we need to do this even when writing */
err = read_sector(floppy, head, track, sector, alloc_buf, sector_length);
@@ -543,8 +537,6 @@ static floperr_t floppy_readwrite_sector(floppy_image_legacy *floppy, int head,
err = FLOPPY_ERROR_SUCCESS;
done:
- if (alloc_buf)
- free(alloc_buf);
return err;
}
@@ -965,7 +957,7 @@ floppy_image::~floppy_image()
{
for (int i=0;i<MAX_FLOPPY_TRACKS;i++) {
for (int j=0;j<MAX_FLOPPY_HEADS;j++) {
- global_free(cell_data[i][j]);
+ global_free_array(cell_data[i][j]);
}
}
}
@@ -1006,7 +998,7 @@ void floppy_image::ensure_alloc(int track, int head)
UINT32 *new_array = global_alloc_array(UINT32, new_size);
if(track_alloc_size[track][head]) {
memcpy(new_array, cell_data[track][head], track_alloc_size[track][head]*4);
- global_free(cell_data[track][head]);
+ global_free_array(cell_data[track][head]);
}
cell_data[track][head] = new_array;
track_alloc_size[track][head] = new_size;
@@ -1355,7 +1347,7 @@ int floppy_image_format_t::calc_sector_index(int num, int interleave, int skew,
void floppy_image_format_t::generate_track(const desc_e *desc, int track, int head, const desc_s *sect, int sect_count, int track_size, floppy_image *image)
{
- UINT32 *buffer = global_alloc_array_clear(UINT32, track_size);
+ dynamic_array<UINT32> buffer(track_size);
gen_crc_info crcs[MAX_CRC_COUNT];
collect_crcs(desc, crcs);
@@ -1638,7 +1630,6 @@ void floppy_image_format_t::generate_track(const desc_e *desc, int track, int he
fixup_crcs(buffer, crcs);
generate_track_from_levels(track, head, buffer, track_size, 0, image);
- global_free(buffer);
}
void floppy_image_format_t::normalize_times(UINT32 *buffer, int bitlen)
@@ -2606,7 +2597,7 @@ void floppy_image_format_t::build_wd_track_mfm(int track, int head, floppy_image
void floppy_image_format_t::build_pc_track_fm(int track, int head, floppy_image *image, int cell_count, int sector_count, const desc_pc_sector *sects, int gap_3, int gap_4a, int gap_1, int gap_2)
{
- UINT32 *track_data = global_alloc_array(UINT32, cell_count+10000);
+ dynamic_array<UINT32> track_data(cell_count+10000);
int tpos = 0;
// gap 4a , IAM and gap 1
@@ -2670,12 +2661,11 @@ void floppy_image_format_t::build_pc_track_fm(int track, int head, floppy_image
raw_w(track_data, tpos, cell_count-tpos, 0xffff >> (16+tpos-cell_count));
generate_track_from_levels(track, head, track_data, cell_count, 0, image);
- global_free(track_data);
}
void floppy_image_format_t::build_pc_track_mfm(int track, int head, floppy_image *image, int cell_count, int sector_count, const desc_pc_sector *sects, int gap_3, int gap_4a, int gap_1, int gap_2)
{
- UINT32 *track_data = global_alloc_array(UINT32, cell_count+10000);
+ dynamic_array<UINT32> track_data(cell_count+10000);
int tpos = 0;
// gap 4a , IAM and gap 1
@@ -2742,5 +2732,4 @@ void floppy_image_format_t::build_pc_track_mfm(int track, int head, floppy_image
raw_w(track_data, tpos, cell_count-tpos, 0x9254 >> (16+tpos-cell_count));
generate_track_from_levels(track, head, track_data, cell_count, 0, image);
- global_free(track_data);
}
diff --git a/src/lib/formats/g64_dsk.c b/src/lib/formats/g64_dsk.c
index 5cf2d3d856e..c1c55acc4e8 100644
--- a/src/lib/formats/g64_dsk.c
+++ b/src/lib/formats/g64_dsk.c
@@ -41,7 +41,7 @@ int g64_format::identify(io_generic *io, UINT32 form_factor)
bool g64_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
{
UINT64 size = io_generic_size(io);
- UINT8 *img = global_alloc_array(UINT8, size);
+ dynamic_buffer img(size);
io_generic_read(io, img, 0, size);
if (img[VERSION]) {
@@ -74,8 +74,6 @@ bool g64_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
generate_track_from_bitstream(track, head, &img[track_offset+2], track_size, image);
}
- global_free(img);
-
image->set_variant(floppy_image::SSSD);
return true;
@@ -102,6 +100,7 @@ bool g64_format::save(io_generic *io, floppy_image *image)
int head = 0;
int tracks_written = 0;
+ dynamic_buffer trackbuf(TRACK_LENGTH-2);
for (int track = 0; track < 84; track++) {
offs_t tpos = TRACK_OFFSET + track * 4;
offs_t spos = SPEED_ZONE + track * 4;
@@ -113,7 +112,6 @@ bool g64_format::save(io_generic *io, floppy_image *image)
if (image->get_track_size(track, head) <= 1)
continue;
- UINT8 *trackbuf = global_alloc_array(UINT8, TRACK_LENGTH-2);
int track_size;
int speed_zone;
@@ -141,8 +139,6 @@ bool g64_format::save(io_generic *io, floppy_image *image)
io_generic_write(io, trackbuf, dpos + 2, track_size);
tracks_written++;
-
- global_free(trackbuf);
}
return true;
diff --git a/src/lib/formats/hxcmfm_dsk.c b/src/lib/formats/hxcmfm_dsk.c
index a49dfd5c3e5..967f05539a3 100644
--- a/src/lib/formats/hxcmfm_dsk.c
+++ b/src/lib/formats/hxcmfm_dsk.c
@@ -71,23 +71,17 @@ bool mfm_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
{
MFMIMG header;
MFMTRACKIMG trackdesc;
- UINT8 *trackbuf = 0;
- int trackbuf_size = 0;
// read header
io_generic_read(io, &header, 0, sizeof(header));
int counter = 0;
+ dynamic_buffer trackbuf;
for(int track=0; track < header.number_of_track; track++) {
for(int side=0; side < header.number_of_side; side++) {
// read location of
io_generic_read(io, &trackdesc,(header.mfmtracklistoffset)+( counter *sizeof(trackdesc)),sizeof(trackdesc));
- if(trackdesc.mfmtracksize > trackbuf_size) {
- if(trackbuf)
- global_free(trackbuf);
- trackbuf_size = trackdesc.mfmtracksize;
- trackbuf = global_alloc_array(UINT8, trackbuf_size);
- }
+ trackbuf.resize(trackdesc.mfmtracksize);
// actual data read
io_generic_read(io, trackbuf, trackdesc.mfmtrackoffset, trackdesc.mfmtracksize);
@@ -97,8 +91,6 @@ bool mfm_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
counter++;
}
}
- if(trackbuf)
- global_free(trackbuf);
image->set_variant(floppy_image::DSDD);
return true;
diff --git a/src/lib/formats/imd_dsk.c b/src/lib/formats/imd_dsk.c
index f3da7d8d113..2f0ee10635d 100644
--- a/src/lib/formats/imd_dsk.c
+++ b/src/lib/formats/imd_dsk.c
@@ -334,7 +334,7 @@ int imd_format::identify(io_generic *io, UINT32 form_factor)
bool imd_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
{
UINT64 size = io_generic_size(io);
- UINT8 *img = global_alloc_array(UINT8, size);
+ dynamic_buffer img(size);
io_generic_read(io, img, 0, size);
UINT64 pos;
@@ -413,7 +413,6 @@ bool imd_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
global_free(sects[i].data);
}
- global_free(img);
return true;
}
diff --git a/src/lib/formats/ipf_dsk.c b/src/lib/formats/ipf_dsk.c
index 88af68e4713..f8e7423157b 100644
--- a/src/lib/formats/ipf_dsk.c
+++ b/src/lib/formats/ipf_dsk.c
@@ -42,10 +42,9 @@ int ipf_format::identify(io_generic *io, UINT32 form_factor)
bool ipf_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
{
UINT64 size = io_generic_size(io);
- UINT8 *data = global_alloc_array(UINT8, size);
+ dynamic_buffer data(size);
io_generic_read(io, data, 0, size);
bool res = parse(data, size, image);
- global_free(data);
return res;
}
@@ -387,27 +386,19 @@ bool ipf_format::generate_track(track_info *t, floppy_image *image)
if(t->index_cells >= t->size_cells)
return false;
- UINT32 *track = global_alloc_array(UINT32, t->size_cells);
- UINT32 *data_pos = global_alloc_array(UINT32, t->block_count+1);
- UINT32 *gap_pos = global_alloc_array(UINT32, t->block_count);
- UINT32 *splice_pos = global_alloc_array(UINT32, t->block_count);
+ dynamic_array<UINT32> track(t->size_cells);
+ dynamic_array<UINT32> data_pos(t->block_count+1);
+ dynamic_array<UINT32> gap_pos(t->block_count);
+ dynamic_array<UINT32> splice_pos(t->block_count);
bool context = false;
UINT32 pos = 0;
for(UINT32 i = 0; i != t->block_count; i++) {
if(!generate_block(t, i, i == t->block_count-1 ? t->size_cells - t->index_cells : 0xffffffff, track, pos, data_pos[i], gap_pos[i], splice_pos[i], context)) {
- global_free(track);
- global_free(data_pos);
- global_free(gap_pos);
- global_free(splice_pos);
return false;
}
}
if(pos != t->size_cells) {
- global_free(track);
- global_free(data_pos);
- global_free(gap_pos);
- global_free(splice_pos);
return false;
}
@@ -416,10 +407,6 @@ bool ipf_format::generate_track(track_info *t, floppy_image *image)
mark_track_splice(track, splice_pos[t->block_count-1], t->size_cells);
if(!generate_timings(t, track, data_pos, gap_pos)) {
- global_free(track);
- global_free(data_pos);
- global_free(gap_pos);
- global_free(splice_pos);
return false;
}
@@ -428,11 +415,6 @@ bool ipf_format::generate_track(track_info *t, floppy_image *image)
generate_track_from_levels(t->cylinder, t->head, track, t->size_cells, splice_pos[t->block_count-1] + t->index_cells, image);
- global_free(track);
- global_free(data_pos);
- global_free(gap_pos);
- global_free(splice_pos);
-
return true;
}
diff --git a/src/lib/formats/mfi_dsk.c b/src/lib/formats/mfi_dsk.c
index 12666d53017..eca7a00d705 100644
--- a/src/lib/formats/mfi_dsk.c
+++ b/src/lib/formats/mfi_dsk.c
@@ -113,8 +113,7 @@ bool mfi_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
image->set_variant(h.variant);
- UINT8 *compressed = 0;
- int compressed_size = 0;
+ dynamic_buffer compressed;
entry *ent = entries;
for(unsigned int cyl=0; cyl != h.cyl_count; cyl++)
@@ -126,12 +125,7 @@ bool mfi_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
continue;
}
- if(ent->compressed_size > compressed_size) {
- if(compressed)
- global_free(compressed);
- compressed_size = ent->compressed_size;
- compressed = global_alloc_array(UINT8, compressed_size);
- }
+ compressed.resize(ent->compressed_size);
io_generic_read(io, compressed, ent->offset, ent->compressed_size);
@@ -155,9 +149,6 @@ bool mfi_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
ent++;
}
- if(compressed)
- global_free(compressed);
-
return true;
}
diff --git a/src/lib/formats/pasti_dsk.c b/src/lib/formats/pasti_dsk.c
index 96f64d887c5..c1c3e164ab7 100644
--- a/src/lib/formats/pasti_dsk.c
+++ b/src/lib/formats/pasti_dsk.c
@@ -62,8 +62,7 @@ bool pasti_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
UINT8 fh[16];
io_generic_read(io, fh, 0, 16);
- UINT8 *raw_track = 0;
- int raw_track_size = 0;
+ dynamic_buffer raw_track;
int tracks = fh[10];
int heads = 1+(tracks >= 160);
@@ -85,12 +84,7 @@ bool pasti_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
int track_num = th[14];
int flags2 = th[15];
- if(entry_len-16 > raw_track_size) {
- if(raw_track)
- global_free(raw_track);
- raw_track_size = entry_len-16;
- raw_track = global_alloc_array(UINT8, entry_len-16);
- }
+ raw_track.resize(entry_len-16);
io_generic_read(io, raw_track, pos+16, entry_len-16);
@@ -275,7 +269,7 @@ void pasti_format::wd_generate_track_from_sectors_and_track(int track, int head,
{
if(0)
printf("Track %d head %d sectors %d\n", track, head, obs.sector_count);
- UINT32 *trackbuf = global_alloc_array(UINT32, 200000);
+ dynamic_array<UINT32> trackbuf(200000);
int pos = 0;
wd_sect_info sect_infos[256];
@@ -347,8 +341,6 @@ void pasti_format::wd_generate_track_from_sectors_and_track(int track, int head,
wd_generate_gap(trackbuf, pos, obs, 0, obs.track_size, false, 1000, 1000);
generate_track_from_levels(track, head, trackbuf, pos, 0, image);
-
- global_free(trackbuf);
}
void pasti_format::wd_generate_track_from_sectors_only(int track, int head, floppy_image *image, wd_obs &obs)
diff --git a/src/lib/formats/td0_dsk.c b/src/lib/formats/td0_dsk.c
index d69504f4965..d72cef70996 100644
--- a/src/lib/formats/td0_dsk.c
+++ b/src/lib/formats/td0_dsk.c
@@ -820,7 +820,7 @@ bool td0_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
int track_spt;
int offset = 0;
const int max_size = 4*1024*1024; // 4MB ought to be large enough for any floppy
- UINT8 *imagebuf = global_alloc_array(UINT8, max_size);
+ dynamic_buffer imagebuf(max_size);
UINT8 header[12];
try
@@ -1005,7 +1005,6 @@ bool td0_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
}
catch(bool ret)
{
- global_free(imagebuf);
return ret;
}
return false;
diff --git a/src/lib/formats/upd765_dsk.c b/src/lib/formats/upd765_dsk.c
index cec4dd4373e..5966e1de1a3 100644
--- a/src/lib/formats/upd765_dsk.c
+++ b/src/lib/formats/upd765_dsk.c
@@ -236,7 +236,7 @@ bool upd765_format::save(io_generic *io, floppy_image *image)
// Allocate the storage for the list of testable formats for a
// given cell size
- int *candidates = global_alloc_array(int, formats_count);
+ dynamic_array<int> candidates(formats_count);
// Format we're finally choosing
int chosen_candidate = -1;
@@ -341,8 +341,6 @@ bool upd765_format::save(io_generic *io, floppy_image *image)
io_generic_write(io, sectdata, (track*f.head_count + head)*track_size, track_size);
}
- global_free(candidates);
-
return true;
}
diff --git a/src/lib/formats/wd177x_dsk.c b/src/lib/formats/wd177x_dsk.c
index d4619acae97..57223fecc2f 100644
--- a/src/lib/formats/wd177x_dsk.c
+++ b/src/lib/formats/wd177x_dsk.c
@@ -226,7 +226,7 @@ bool wd177x_format::save(io_generic *io, floppy_image *image)
// Allocate the storage for the list of testable formats for a
// given cell size
- int *candidates = global_alloc_array(int, formats_count);
+ dynamic_array<int> candidates(formats_count);
// Format we're finally choosing
int chosen_candidate = -1;
@@ -331,7 +331,6 @@ bool wd177x_format::save(io_generic *io, floppy_image *image)
io_generic_write(io, sectdata, get_image_offset(f, head, track), track_size);
}
- global_free(candidates);
return true;
}
diff --git a/src/lib/lib.mak b/src/lib/lib.mak
index 84897a8d74e..13a0fa9283c 100644
--- a/src/lib/lib.mak
+++ b/src/lib/lib.mak
@@ -41,9 +41,11 @@ UTILOBJS = \
$(LIBOBJ)/util/chd.o \
$(LIBOBJ)/util/chdcd.o \
$(LIBOBJ)/util/chdcodec.o \
+ $(LIBOBJ)/util/corealloc.o \
$(LIBOBJ)/util/corefile.o \
$(LIBOBJ)/util/corestr.o \
$(LIBOBJ)/util/coreutil.o \
+ $(LIBOBJ)/util/cstrpool.o \
$(LIBOBJ)/util/flac.o \
$(LIBOBJ)/util/harddisk.o \
$(LIBOBJ)/util/hashing.o \
diff --git a/src/lib/util/aviio.c b/src/lib/util/aviio.c
index 3e6b11ed881..7dd2e3bb9c1 100644
--- a/src/lib/util/aviio.c
+++ b/src/lib/util/aviio.c
@@ -370,9 +370,15 @@ INLINE avi_error set_stream_chunk_info(avi_stream *stream, UINT32 index, UINT64
if (index >= stream->chunksalloc)
{
UINT32 newcount = MAX(index, stream->chunksalloc + 1000);
- stream->chunk = (avi_chunk_list *)realloc(stream->chunk, newcount * sizeof(stream->chunk[0]));
- if (stream->chunk == NULL)
+ avi_chunk_list *newchunks = (avi_chunk_list *)malloc(newcount * sizeof(stream->chunk[0]));
+ if (newchunks == NULL)
return AVIERR_NO_MEMORY;
+ if (stream->chunk != NULL)
+ {
+ memcpy(newchunks, stream->chunk, stream->chunksalloc * sizeof(stream->chunk[0]));
+ free(stream->chunk);
+ }
+ stream->chunk = newchunks;
stream->chunksalloc = newcount;
}
@@ -446,9 +452,12 @@ INLINE avi_error expand_tempbuffer(avi_file *file, UINT32 length)
if (length > file->tempbuffersize)
{
file->tempbuffersize = 2 * length;
- file->tempbuffer = (UINT8 *)realloc(file->tempbuffer, file->tempbuffersize);
- if (file->tempbuffer == NULL)
+ UINT8 *newbuffer = (UINT8 *)malloc(file->tempbuffersize);
+ if (newbuffer == NULL)
return AVIERR_NO_MEMORY;
+ if (file->tempbuffer != NULL)
+ free(file->tempbuffer);
+ file->tempbuffer = newbuffer;
}
return AVIERR_NONE;
}
diff --git a/src/lib/util/corealloc.c b/src/lib/util/corealloc.c
new file mode 100644
index 00000000000..089770b20ed
--- /dev/null
+++ b/src/lib/util/corealloc.c
@@ -0,0 +1,375 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ corealloc.c
+
+ Memory allocation helpers for the helper library.
+
+***************************************************************************/
+
+#include "corealloc.h"
+#include "osdcore.h"
+
+
+//**************************************************************************
+// DEBUGGING
+//**************************************************************************
+
+#define LOG_ALLOCS (0)
+
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+// number of memory_entries to allocate in a block
+const int memory_block_alloc_chunk = 256;
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// this struct is allocated in pools to track memory allocations
+// it must be a POD type!!
+class memory_entry
+{
+public:
+ // internal state
+ memory_entry * m_next; // link to the next entry
+ memory_entry * m_prev; // link to the previous entry
+ size_t m_size; // size of the allocation (not including this header)
+ void * m_base; // base of the allocation
+ const char * m_file; // file the allocation was made from
+ int m_line; // line number within that file
+ UINT64 m_id; // unique id
+ bool m_array; // array?
+
+ // hashing prime number
+ static const int k_hash_prime = 6151;
+
+ // global state
+ static UINT64 s_curid; // current ID
+ static osd_lock * s_lock; // lock for managing the list
+ static bool s_lock_alloc; // set to true temporarily during lock allocation
+ static bool s_tracking; // set to true when tracking is live
+ static memory_entry *s_hash[k_hash_prime];// hash table based on pointer
+ static memory_entry *s_freehead; // pointer to the head of the free list
+
+ // static helpers
+ static memory_entry *allocate(size_t size, void *base, const char *file, int line, bool array);
+ static memory_entry *find(void *ptr);
+ static void release(memory_entry *entry, const char *file, int line);
+ static void report_unfreed(UINT64 start);
+
+private:
+ static void acquire_lock();
+ static void release_lock();
+};
+
+
+
+//**************************************************************************
+// GLOBALS
+//**************************************************************************
+
+// dummy zeromem object
+const zeromem_t zeromem = { };
+
+// globals for memory_entry
+UINT64 memory_entry::s_curid = 1;
+osd_lock *memory_entry::s_lock = NULL;
+bool memory_entry::s_lock_alloc = false;
+bool memory_entry::s_tracking = false;
+memory_entry *memory_entry::s_hash[memory_entry::k_hash_prime] = { NULL };
+memory_entry *memory_entry::s_freehead = NULL;
+
+
+
+//**************************************************************************
+// GLOBAL HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// malloc_file_line - allocate memory with file
+// and line number information
+//-------------------------------------------------
+
+void *malloc_file_line(size_t size, const char *file, int line, bool array, bool throw_on_fail, bool clear)
+{
+ // allocate the memory and fail if we can't
+ void *result = array ? osd_malloc_array(size) : osd_malloc(size);
+ if (result == NULL)
+ {
+ fprintf(stderr, "Failed to allocate %d bytes (%s:%d)\n", size, file, line);
+ osd_break_into_debugger("Failed to allocate RAM");
+ if (throw_on_fail)
+ throw std::bad_alloc();
+ return NULL;
+ }
+
+ // zap the memory if requested
+ if (clear)
+ memset(result, 0, size);
+ else
+ {
+#if !__has_feature(memory_sanitizer) && defined(INITIALIZE_ALLOCATED_MEMORY)
+ memset(result, 0xdd, size);
+#endif
+ }
+
+ // add a new entry
+ memory_entry::allocate(size, result, file, line, array);
+
+ return result;
+}
+
+
+//-------------------------------------------------
+// free_file_line - free memory with file
+// and line number information
+//-------------------------------------------------
+
+void free_file_line(void *memory, const char *file, int line, bool array)
+{
+ // find the memory entry
+ memory_entry *entry = memory_entry::find(memory);
+
+ // warn about untracked frees
+ if (entry == NULL)
+ {
+ fprintf(stderr, "Error: attempt to free untracked memory %p in %s(%d)!\n", memory, file, line);
+ osd_break_into_debugger("Error: attempt to free untracked memory");
+ return;
+ }
+
+ // warn about mismatched arrays
+ if (!array && entry->m_array)
+ {
+ fprintf(stderr, "Error: attempt to free array %p with global_free in %s(%d)!\n", memory, file, line);
+ osd_break_into_debugger("Error: attempt to free array with global_free");
+ }
+ if (array && !entry->m_array)
+ {
+ fprintf(stderr, "Error: attempt to free single object %p with global_free_array in %s(%d)!\n", memory, file, line);
+ osd_break_into_debugger("Error: attempt to free single object with global_free_array");
+ }
+
+#ifdef OVERWRITE_FREED_MEMORY
+ // clear memory to a bogus value
+ memset(memory, 0xfc, entry->m_size);
+#endif
+
+ // free the entry and the memory
+ memory_entry::release(entry, file, line);
+ osd_free(memory);
+}
+
+
+//-------------------------------------------------
+// dump_unfreed_mem - called from the exit path
+// of any code that wants to check for unfreed
+// memory
+//-------------------------------------------------
+
+void track_memory(bool track)
+{
+ memory_entry::s_tracking = track;
+}
+
+
+//-------------------------------------------------
+// next_memory_id - return the ID of the next
+// allocated block
+//-------------------------------------------------
+
+UINT64 next_memory_id()
+{
+ return memory_entry::s_curid;
+}
+
+
+//-------------------------------------------------
+// dump_unfreed_mem - called from the exit path
+// of any code that wants to check for unfreed
+// memory
+//-------------------------------------------------
+
+void dump_unfreed_mem(UINT64 start)
+{
+ memory_entry::report_unfreed(start);
+}
+
+
+
+//**************************************************************************
+// MEMORY ENTRY
+//**************************************************************************
+
+//-------------------------------------------------
+// acquire_lock - acquire the memory entry lock,
+// creating a new one if needed
+//-------------------------------------------------
+
+void memory_entry::acquire_lock()
+{
+ // allocate a lock on first usage
+ // note that osd_lock_alloc() may re-enter this path, so protect against recursion!
+ if (s_lock == NULL)
+ {
+ if (s_lock_alloc)
+ return;
+ s_lock_alloc = true;
+ s_lock = osd_lock_alloc();
+ s_lock_alloc = false;
+ }
+ osd_lock_acquire(s_lock);
+}
+
+
+//-------------------------------------------------
+// release_lock - release the memory entry lock
+//-------------------------------------------------
+
+void memory_entry::release_lock()
+{
+ osd_lock_release(s_lock);
+}
+
+
+//-------------------------------------------------
+// allocate - allocate a new memory entry
+//-------------------------------------------------
+
+memory_entry *memory_entry::allocate(size_t size, void *base, const char *file, int line, bool array)
+{
+ acquire_lock();
+
+ // if we're out of free entries, allocate a new chunk
+ if (s_freehead == NULL)
+ {
+ // create a new chunk, and fail if we can't
+ memory_entry *entry = reinterpret_cast<memory_entry *>(osd_malloc_array(memory_block_alloc_chunk * sizeof(memory_entry)));
+ if (entry == NULL)
+ {
+ release_lock();
+ return NULL;
+ }
+
+ // add all the entries to the list
+ for (int entrynum = 0; entrynum < memory_block_alloc_chunk; entrynum++)
+ {
+ entry->m_next = s_freehead;
+ s_freehead = entry++;
+ }
+ }
+
+ // grab a free entry
+ memory_entry *entry = s_freehead;
+ s_freehead = entry->m_next;
+
+ // populate it
+ entry->m_size = size;
+ entry->m_base = base;
+ entry->m_file = s_tracking ? file : NULL;
+ entry->m_line = s_tracking ? line : 0;
+ entry->m_id = s_curid++;
+ entry->m_array = array;
+ if (LOG_ALLOCS)
+ fprintf(stderr, "#%06d, alloc %d bytes (%s:%d)\n", (UINT32)entry->m_id, static_cast<UINT32>(entry->m_size), entry->m_file, (int)entry->m_line);
+
+ // add it to the alloc list
+ int hashval = reinterpret_cast<FPTR>(base) % k_hash_prime;
+ entry->m_next = s_hash[hashval];
+ if (entry->m_next != NULL)
+ entry->m_next->m_prev = entry;
+ entry->m_prev = NULL;
+ s_hash[hashval] = entry;
+
+ release_lock();
+ return entry;
+}
+
+
+//-------------------------------------------------
+// find - find a memory entry
+//-------------------------------------------------
+
+memory_entry *memory_entry::find(void *ptr)
+{
+ // NULL maps to nothing
+ if (ptr == NULL)
+ return NULL;
+
+ // scan the list under the lock
+ acquire_lock();
+
+ int hashval = reinterpret_cast<FPTR>(ptr) % k_hash_prime;
+ memory_entry *entry;
+ for (entry = s_hash[hashval]; entry != NULL; entry = entry->m_next)
+ if (entry->m_base == ptr)
+ break;
+
+ release_lock();
+ return entry;
+}
+
+
+//-------------------------------------------------
+// release - release a memory entry
+//-------------------------------------------------
+
+void memory_entry::release(memory_entry *entry, const char *file, int line)
+{
+ acquire_lock();
+
+ if (LOG_ALLOCS)
+ fprintf(stderr, "#%06d, release %d bytes (%s:%d)\n", (UINT32)entry->m_id, static_cast<UINT32>(entry->m_size), file, line);
+
+ // remove ourselves from the alloc list
+ int hashval = reinterpret_cast<FPTR>(entry->m_base) % k_hash_prime;
+ if (entry->m_prev != NULL)
+ entry->m_prev->m_next = entry->m_next;
+ else
+ s_hash[hashval] = entry->m_next;
+ if (entry->m_next != NULL)
+ entry->m_next->m_prev = entry->m_prev;
+
+ // add ourself to the free list
+ entry->m_next = s_freehead;
+ s_freehead = entry;
+
+ release_lock();
+}
+
+
+//-------------------------------------------------
+// report_unfreed - print a list of unfreed
+// memory to the target file
+//-------------------------------------------------
+
+void memory_entry::report_unfreed(UINT64 start)
+{
+ acquire_lock();
+
+ // check for leaked memory
+ UINT32 total = 0;
+
+ for (int hashnum = 0; hashnum < k_hash_prime; hashnum++)
+ for (memory_entry *entry = s_hash[hashnum]; entry != NULL; entry = entry->m_next)
+ if (entry->m_file != NULL && entry->m_id >= start)
+ {
+ if (total == 0)
+ fprintf(stderr, "--- memory leak warning ---\n");
+ total += entry->m_size;
+ fprintf(stderr, "#%06d, nofree %d bytes (%s:%d)\n", (UINT32)entry->m_id, static_cast<UINT32>(entry->m_size), entry->m_file, (int)entry->m_line);
+ }
+
+ release_lock();
+
+ if (total > 0)
+ fprintf(stderr, "a total of %u bytes were not freed\n", total);
+}
diff --git a/src/lib/util/corealloc.h b/src/lib/util/corealloc.h
new file mode 100644
index 00000000000..0d2c2003057
--- /dev/null
+++ b/src/lib/util/corealloc.h
@@ -0,0 +1,121 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ corealloc.h
+
+ Memory allocation helpers for the helper library.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __COREALLOC_H__
+#define __COREALLOC_H__
+
+#include <new>
+#include "osdcore.h"
+
+
+//**************************************************************************
+// DEBUGGING
+//**************************************************************************
+
+// define this to initialize allocated memory to a fixed non-0 value
+//#define INITIALIZE_ALLOCATED_MEMORY
+
+// define this to zap memory to a fixed non-0 value before freeing
+//#define OVERWRITE_FREED_MEMORY
+
+
+
+//**************************************************************************
+// MACROS
+//**************************************************************************
+
+// global allocation helpers -- use these instead of new and delete
+#define global_alloc(_type) new(__FILE__, __LINE__) _type
+#define global_alloc_clear(_type) new(__FILE__, __LINE__, zeromem) _type
+#define global_alloc_array(_type, _num) new(__FILE__, __LINE__) _type[_num]
+#define global_alloc_array_clear(_type, _num) new(__FILE__, __LINE__, zeromem) _type[_num]
+#define global_free(_ptr) do { delete _ptr; } while (0)
+#define global_free_array(_ptr) do { delete[] _ptr; } while (0)
+
+
+
+//**************************************************************************
+// FUNCTION PROTOTYPES
+//**************************************************************************
+
+// allocate memory with file and line number information
+void *malloc_file_line(size_t size, const char *file, int line, bool array, bool throw_on_fail, bool clear);
+
+// free memory with file and line number information
+void free_file_line(void *memory, const char *file, int line, bool array);
+inline void free_file_line(const void *memory, const char *file, int line, bool array) { free_file_line(const_cast<void *>(memory), file, line, array); }
+
+// called from the exit path of any code that wants to check for unfreed memory
+void track_memory(bool track);
+UINT64 next_memory_id();
+void dump_unfreed_mem(UINT64 start = 0);
+
+
+
+//**************************************************************************
+// INLINE FUNCTIONS
+//**************************************************************************
+
+// zeromem_t is a dummy class used to tell new to zero memory after allocation
+class zeromem_t { };
+
+#ifndef NO_MEM_TRACKING
+
+// standard new/delete operators (try to avoid using)
+ATTR_FORCE_INLINE inline void *operator new(std::size_t size) throw (std::bad_alloc) { return malloc_file_line(size, NULL, 0, false, true, false); }
+ATTR_FORCE_INLINE inline void *operator new[](std::size_t size) throw (std::bad_alloc) { return malloc_file_line(size, NULL, 0, true, true, false); }
+ATTR_FORCE_INLINE inline void operator delete(void *ptr) throw() { if (ptr != NULL) free_file_line(ptr, NULL, 0, false); }
+ATTR_FORCE_INLINE inline void operator delete[](void *ptr) throw() { if (ptr != NULL) free_file_line(ptr, NULL, 0, true); }
+
+#endif
+
+// file/line new/delete operators
+ATTR_FORCE_INLINE inline void *operator new(std::size_t size, const char *file, int line) throw (std::bad_alloc) { return malloc_file_line(size, file, line, false, true, false); }
+ATTR_FORCE_INLINE inline void *operator new[](std::size_t size, const char *file, int line) throw (std::bad_alloc) { return malloc_file_line(size, file, line, true, true, false); }
+ATTR_FORCE_INLINE inline void operator delete(void *ptr, const char *file, int line) { if (ptr != NULL) free_file_line(ptr, file, line, false); }
+ATTR_FORCE_INLINE inline void operator delete[](void *ptr, const char *file, int line) { if (ptr != NULL) free_file_line(ptr, file, line, true); }
+
+// file/line new/delete operators with zeroing
+ATTR_FORCE_INLINE inline void *operator new(std::size_t size, const char *file, int line, const zeromem_t &) throw (std::bad_alloc) { return malloc_file_line(size, file, line, false, true, true); }
+ATTR_FORCE_INLINE inline void *operator new[](std::size_t size, const char *file, int line, const zeromem_t &) throw (std::bad_alloc) { return malloc_file_line(size, file, line, true, true, true); }
+ATTR_FORCE_INLINE inline void operator delete(void *ptr, const char *file, int line, const zeromem_t &) { if (ptr != NULL) free_file_line(ptr, file, line, false); }
+ATTR_FORCE_INLINE inline void operator delete[](void *ptr, const char *file, int line, const zeromem_t &) { if (ptr != NULL) free_file_line(ptr, file, line, true); }
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// dummy objects to pass to the specialized new variants
+extern const zeromem_t zeromem;
+
+
+
+//**************************************************************************
+// ADDDITIONAL MACROS
+//**************************************************************************
+
+#ifndef NO_MEM_TRACKING
+// re-route classic malloc-style allocations
+#undef malloc
+#undef calloc
+#undef realloc
+#undef free
+
+#define malloc(x) malloc_file_line(x, __FILE__, __LINE__, true, false, false)
+#define calloc(x,y) __error_use_auto_alloc_clear_or_global_alloc_clear_instead__
+#define realloc(x,y) __error_realloc_is_dangerous__
+#define free(x) free_file_line(x, __FILE__, __LINE__, true)
+#endif
+
+#endif /* __COREALLOC_H__ */
diff --git a/src/lib/util/coretmpl.h b/src/lib/util/coretmpl.h
index 2c52c81dc5e..1115ae0e62e 100644
--- a/src/lib/util/coretmpl.h
+++ b/src/lib/util/coretmpl.h
@@ -15,13 +15,49 @@
#include <assert.h>
#include "osdcore.h"
+#include "corealloc.h"
// TEMPORARY helper to catch is_pod assertions in the debugger
#if 0
#undef assert
-#define assert(x) do { if (!(x)) { printf("Assert: %s\n", #x); asm("int $3"); } } while (0)
+#define assert(x) do { if (!(x)) { fprintf(stderr, "Assert: %s\n", #x); osd_break_into_debugger("Assertion failed"); } } while (0)
#endif
+
+// ======================> auto_pointer
+
+// an object that transparently wraps a pointer and auto-frees it upon destruction
+template<class _ElementType>
+class auto_pointer
+{
+private:
+ // we don't support deep copying
+ auto_pointer(const auto_pointer &);
+ auto_pointer &operator=(const auto_pointer &);
+
+public:
+ // construction/destruction
+ auto_pointer(_ElementType *value = NULL)
+ : m_ptr(value) { }
+ virtual ~auto_pointer() { reset(); }
+
+ // operators
+ operator _ElementType *() const { return m_ptr; }
+ _ElementType &operator*() const { assert(m_ptr != NULL); return *m_ptr; }
+ _ElementType *operator->() const { return m_ptr; }
+
+ // simple getters
+ _ElementType *get() const { return m_ptr; }
+
+ // core operations
+ void reset(_ElementType *ptr = NULL) { if (m_ptr != ptr) { global_free(m_ptr); m_ptr = ptr; } }
+
+private:
+ // internal state
+ _ElementType * m_ptr; // pointer we are tracking
+};
+
+
// ======================> dynamic_array
// an array that is dynamically sized and can optionally auto-expand
@@ -51,8 +87,9 @@ public:
int count() const { return m_count; }
// core operations
- const _ElementType &append(const _ElementType &element) { if (m_count == m_allocated) expand_and_keep_internal((m_allocated == 0) ? 16 : (m_allocated << 1)); m_array[m_count++] = element; return element; }
- void reset() { delete[] m_array; m_array = NULL; m_count = m_allocated = 0; }
+ _ElementType &append() { if (m_count == m_allocated) expand_and_keep_internal((m_allocated == 0) ? 16 : (m_allocated << 1)); return m_array[m_count++]; }
+ const _ElementType &append(const _ElementType &element) { return (append() = element); }
+ void reset() { global_free_array(m_array); m_array = NULL; m_count = m_allocated = 0; }
void resize(int count) { if (count > m_allocated) expand_internal(count); m_count = count; }
void resize_keep(int count) { if (count > m_allocated) expand_and_keep_internal(count); m_count = count; }
void clear(UINT8 data = 0) { clear_internal(0, m_count, data); }
@@ -65,8 +102,8 @@ private:
// internal helpers
void expand_internal(int count)
{
- delete[] m_array;
- m_array = new _ElementType[count];
+ global_free_array(m_array);
+ m_array = global_alloc_array(_ElementType, count);
m_allocated = count;
}
@@ -74,11 +111,11 @@ private:
{
_ElementType *oldarray = m_array;
int oldcount = m_count;
- m_array = new _ElementType[count];
+ m_array = global_alloc_array(_ElementType, count);
m_allocated = count;
for (int index = 0; index < oldcount; index++)
m_array[index] = oldarray[index];
- delete[] oldarray;
+ global_free_array(oldarray);
}
#ifdef __GNUC__
@@ -93,11 +130,291 @@ private:
int m_allocated; // amount of space allocated for the array
};
+typedef dynamic_array<UINT8> dynamic_buffer;
-// ======================> dynamic_buffer
-typedef dynamic_array<UINT8> dynamic_buffer;
+// ======================> simple_list
+
+// a simple_list is a singly-linked list whose 'next' pointer is owned
+// by the object
+template<class _ElementType>
+class simple_list
+{
+ // we don't support deep copying
+ simple_list(const simple_list &);
+ simple_list &operator=(const simple_list &);
+
+public:
+ // construction/destruction
+ simple_list()
+ : m_head(NULL),
+ m_tail(NULL),
+ m_count(0) { }
+
+ virtual ~simple_list() { reset(); }
+
+ // simple getters
+ _ElementType *first() const { return m_head; }
+ _ElementType *last() const { return m_tail; }
+ int count() const { return m_count; }
+
+ // remove (free) all objects in the list, leaving an empty list
+ void reset()
+ {
+ while (m_head != NULL)
+ remove(*m_head);
+ }
+
+ // add the given object to the head of the list
+ _ElementType &prepend(_ElementType &object)
+ {
+ object.m_next = m_head;
+ m_head = &object;
+ if (m_tail == NULL)
+ m_tail = m_head;
+ m_count++;
+ return object;
+ }
+
+ // add the given list to the head of the list
+ void prepend_list(simple_list<_ElementType> &list)
+ {
+ int count = list.count();
+ if (count == 0)
+ return;
+ _ElementType *tail = list.last();
+ _ElementType *head = list.detach_all();
+ tail->m_next = m_head;
+ m_head = head;
+ if (m_tail == NULL)
+ m_tail = tail;
+ m_count += count;
+ }
+
+ // add the given object to the tail of the list
+ _ElementType &append(_ElementType &object)
+ {
+ object.m_next = NULL;
+ if (m_tail != NULL)
+ m_tail = m_tail->m_next = &object;
+ else
+ m_tail = m_head = &object;
+ m_count++;
+ return object;
+ }
+
+ // add the given list to the tail of the list
+ void append_list(simple_list<_ElementType> &list)
+ {
+ int count = list.count();
+ if (count == 0)
+ return;
+ _ElementType *tail = list.last();
+ _ElementType *head = list.detach_all();
+ if (m_tail != NULL)
+ m_tail->m_next = head;
+ else
+ m_head = head;
+ m_tail = tail;
+ m_count += count;
+ }
+
+ // insert the given object after a particular object (NULL means prepend)
+ _ElementType &insert_after(_ElementType &object, _ElementType *insert_after)
+ {
+ if (insert_after == NULL)
+ return prepend(object);
+ object.m_next = insert_after->m_next;
+ insert_after->m_next = &object;
+ if (m_tail == insert_after)
+ m_tail = &object;
+ m_count++;
+ return object;
+ }
+
+ // insert the given object before a particular object (NULL means append)
+ _ElementType &insert_before(_ElementType &object, _ElementType *insert_before)
+ {
+ if (insert_before == NULL)
+ return append(object);
+ for (_ElementType **curptr = &m_head; *curptr != NULL; curptr = &(*curptr)->m_next)
+ if (*curptr == insert_before)
+ {
+ object.m_next = insert_before;
+ *curptr = &object;
+ if (m_head == insert_before)
+ m_head = &object;
+ m_count++;
+ return object;
+ }
+ return object;
+ }
+ // replace an item in the list at the same location, and remove it
+ _ElementType &replace_and_remove(_ElementType &object, _ElementType &toreplace)
+ {
+ _ElementType *prev = NULL;
+ for (_ElementType *cur = m_head; cur != NULL; prev = cur, cur = cur->m_next)
+ if (cur == &toreplace)
+ {
+ if (prev != NULL)
+ prev->m_next = &object;
+ else
+ m_head = &object;
+ if (m_tail == &toreplace)
+ m_tail = &object;
+ object.m_next = toreplace.m_next;
+ global_free(&toreplace);
+ return object;
+ }
+ return append(object);
+ }
+
+ // detach the head item from the list, but don't free its memory
+ _ElementType *detach_head()
+ {
+ _ElementType *result = m_head;
+ if (result != NULL)
+ {
+ m_head = result->m_next;
+ m_count--;
+ if (m_head == NULL)
+ m_tail = NULL;
+ }
+ return result;
+ }
+
+ // detach the given item from the list, but don't free its memory
+ _ElementType &detach(_ElementType &object)
+ {
+ _ElementType *prev = NULL;
+ for (_ElementType *cur = m_head; cur != NULL; prev = cur, cur = cur->m_next)
+ if (cur == &object)
+ {
+ if (prev != NULL)
+ prev->m_next = object.m_next;
+ else
+ m_head = object.m_next;
+ if (m_tail == &object)
+ m_tail = prev;
+ m_count--;
+ return object;
+ }
+ return object;
+ }
+
+ // deatch the entire list, returning the head, but don't free memory
+ _ElementType *detach_all()
+ {
+ _ElementType *result = m_head;
+ m_head = m_tail = NULL;
+ m_count = 0;
+ return result;
+ }
+
+ // remove the given object and free its memory
+ void remove(_ElementType &object)
+ {
+ global_free(&detach(object));
+ }
+
+ // find an object by index in the list
+ _ElementType *find(int index) const
+ {
+ for (_ElementType *cur = m_head; cur != NULL; cur = cur->m_next)
+ if (index-- == 0)
+ return cur;
+ return NULL;
+ }
+
+ // return the index of the given object in the list
+ int indexof(const _ElementType &object) const
+ {
+ int index = 0;
+ for (_ElementType *cur = m_head; cur != NULL; cur = cur->m_next)
+ {
+ if (cur == &object)
+ return index;
+ index++;
+ }
+ return -1;
+ }
+
+private:
+ // internal state
+ _ElementType * m_head; // head of the singly-linked list
+ _ElementType * m_tail; // tail of the singly-linked list
+ int m_count; // number of objects in the list
+};
+
+
+// ======================> simple_list_wrapper
+
+// a simple_list_wrapper wraps an existing object with a next pointer so it
+// can live in a simple_list without requiring the object to have a next
+// pointer
+template<class _ObjectType>
+class simple_list_wrapper
+{
+public:
+ template<class U> friend class simple_list;
+
+ // construction/destruction
+ simple_list_wrapper(_ObjectType *object)
+ : m_next(NULL),
+ m_object(object) { }
+
+ // operators
+ operator _ObjectType *() { return m_object; }
+ operator _ObjectType *() const { return m_object; }
+ _ObjectType *operator *() { return m_object; }
+ _ObjectType *operator *() const { return m_object; }
+
+ // getters
+ simple_list_wrapper *next() const { return m_next; }
+ _ObjectType *object() const { return m_object; }
+
+private:
+ // internal state
+ simple_list_wrapper * m_next;
+ _ObjectType * m_object;
+};
+
+
+// ======================> fixed_allocator
+
+// a fixed_allocator is a simple class that maintains a free pool of objects
+template<class _ItemType>
+class fixed_allocator
+{
+ // we don't support deep copying
+ fixed_allocator(const fixed_allocator &);
+ fixed_allocator &operator=(const fixed_allocator &);
+
+public:
+ // construction/destruction
+ fixed_allocator() { }
+
+ // allocate a new item, either by recycling an old one, or by allocating a new one
+ _ItemType *alloc()
+ {
+ _ItemType *result = m_freelist.detach_head();
+ if (result == NULL)
+ result = global_alloc(_ItemType);
+ return result;
+ }
+
+ // reclaim an item by adding it to the free list
+ void reclaim(_ItemType *item) { if (item != NULL) m_freelist.append(*item); }
+ void reclaim(_ItemType &item) { m_freelist.append(item); }
+
+ // reclaim all items from a list
+ void reclaim_all(simple_list<_ItemType> &list) { m_freelist.append_list(list); }
+
+private:
+ // internal state
+ simple_list<_ItemType> m_freelist; // list of free objects
+};
#endif
diff --git a/src/lib/util/cstrpool.c b/src/lib/util/cstrpool.c
new file mode 100644
index 00000000000..17b43b325a6
--- /dev/null
+++ b/src/lib/util/cstrpool.c
@@ -0,0 +1,100 @@
+/***************************************************************************
+
+ cstrpool.c
+
+ Constant string pool helper class.
+
+***************************************************************************/
+
+#include "cstrpool.h"
+
+
+//**************************************************************************
+// CONST STRING POOL
+//**************************************************************************
+
+//-------------------------------------------------
+// const_string_pool - constructor
+//-------------------------------------------------
+
+const_string_pool::const_string_pool()
+{
+}
+
+
+//-------------------------------------------------
+// add - add a string to the string pool
+//-------------------------------------------------
+
+const char *const_string_pool::add(const char *string)
+{
+ // if NULL or a small number (for some hash strings), just return as-is
+ if (FPTR(string) < 0x100)
+ return string;
+
+ // scan to find space
+ for (pool_chunk *chunk = m_chunklist.first(); chunk != NULL; chunk = chunk->next())
+ {
+ const char *result = chunk->add(string);
+ if (result != NULL)
+ return result;
+ }
+
+ // no space anywhere, create a new pool and prepend it (so it gets used first)
+ const char *result = m_chunklist.prepend(*global_alloc(pool_chunk)).add(string);
+ assert(result != NULL);
+ return result;
+}
+
+
+//-------------------------------------------------
+// contains - determine if the given string
+// pointer lives in the pool
+//-------------------------------------------------
+
+bool const_string_pool::contains(const char *string)
+{
+ // if NULL or a small number (for some hash strings), then yes, effectively
+ if (FPTR(string) < 0x100)
+ return true;
+
+ // scan to find it
+ for (pool_chunk *chunk = m_chunklist.first(); chunk != NULL; chunk = chunk->next())
+ if (chunk->contains(string))
+ return true;
+
+ return false;
+}
+
+
+//-------------------------------------------------
+// pool_chunk - constructor
+//-------------------------------------------------
+
+const_string_pool::pool_chunk::pool_chunk()
+ : m_next(NULL),
+ m_used(0)
+{
+}
+
+
+//-------------------------------------------------
+// add - add a string to this pool
+//-------------------------------------------------
+
+const char *const_string_pool::pool_chunk::add(const char *string)
+{
+ // get the length of the string (no string can be longer than a full pool)
+ int bytes = strlen(string) + 1;
+ assert(bytes < POOL_SIZE);
+
+ // if too big, return NULL
+ if (m_used + bytes > POOL_SIZE)
+ return NULL;
+
+ // allocate, copy, and return the memory
+ char *dest = &m_buffer[m_used];
+ m_used += bytes;
+ memcpy(dest, string, bytes);
+ return dest;
+}
diff --git a/src/lib/util/cstrpool.h b/src/lib/util/cstrpool.h
new file mode 100644
index 00000000000..c4b4805362d
--- /dev/null
+++ b/src/lib/util/cstrpool.h
@@ -0,0 +1,63 @@
+/*********************************************************************
+
+ cstrpool.h
+
+ Constant string pool helper class.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __CSTRPOOL_H_
+#define __CSTRPOOL_H_
+
+#include "coretmpl.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> const_string_pool
+
+// a pool to hold constant strings efficiently
+class const_string_pool
+{
+public:
+ // construction
+ const_string_pool();
+
+ // operations
+ void reset() { m_chunklist.reset(); }
+ const char *add(const char *string);
+ bool contains(const char *string);
+
+private:
+ // shared string pool
+ class pool_chunk
+ {
+ static const int POOL_SIZE = 4096;
+ friend class simple_list<pool_chunk>;
+
+ public:
+ // construction
+ pool_chunk();
+
+ // getters
+ pool_chunk *next() const { return m_next; }
+
+ // operations
+ const char *add(const char *string);
+ bool contains(const char *string) const { return (string >= m_buffer && string < &m_buffer[POOL_SIZE]); }
+
+ private:
+ // internal state
+ pool_chunk * m_next;
+ UINT32 m_used;
+ char m_buffer[POOL_SIZE];
+ };
+ simple_list<pool_chunk> m_chunklist;
+};
+
+
+#endif
diff --git a/src/lib/util/options.c b/src/lib/util/options.c
index c0cd1f9d3d8..7aa08ad0500 100644
--- a/src/lib/util/options.c
+++ b/src/lib/util/options.c
@@ -50,19 +50,19 @@ const char *const core_options::s_option_unadorned[MAX_UNADORNED_OPTIONS] =
// entry - constructor
//-------------------------------------------------
-core_options::entry::entry(const options_entry &entrylist)
+core_options::entry::entry(const char *name, const char *description, UINT32 flags, const char *defvalue)
: m_next(NULL),
- m_flags(entrylist.flags),
+ m_flags(flags),
m_seqid(0),
m_error_reported(false),
m_priority(OPTION_PRIORITY_DEFAULT),
- m_description(entrylist.description)
+ m_description(description)
{
// copy in the name(s) as appropriate
- if (entrylist.name != NULL)
+ if (name != NULL)
{
// first extract any range
- astring namestr(entrylist.name);
+ astring namestr(name);
int lparen = namestr.chr(0, '(');
int dash = namestr.chr(lparen + 1, '-');
int rparen = namestr.chr(dash + 1, ')');
@@ -88,8 +88,8 @@ core_options::entry::entry(const options_entry &entrylist)
}
// set the default value
- if (entrylist.defvalue != NULL)
- m_defdata = entrylist.defvalue;
+ if (defvalue != NULL)
+ m_defdata = defvalue;
m_data = m_defdata;
}
@@ -156,29 +156,21 @@ void core_options::entry::revert(int priority)
//-------------------------------------------------
core_options::core_options()
- : m_entrylist(NULL),
- m_entrylist_tailptr(&m_entrylist)
{
}
core_options::core_options(const options_entry *entrylist)
- : m_entrylist(NULL),
- m_entrylist_tailptr(&m_entrylist)
{
add_entries(entrylist);
}
core_options::core_options(const options_entry *entrylist1, const options_entry *entrylist2)
- : m_entrylist(NULL),
- m_entrylist_tailptr(&m_entrylist)
{
add_entries(entrylist1);
add_entries(entrylist2);
}
core_options::core_options(const options_entry *entrylist1, const options_entry *entrylist2, const options_entry *entrylist3)
- : m_entrylist(NULL),
- m_entrylist_tailptr(&m_entrylist)
{
add_entries(entrylist1);
add_entries(entrylist2);
@@ -186,8 +178,6 @@ core_options::core_options(const options_entry *entrylist1, const options_entry
}
core_options::core_options(const core_options &src)
- : m_entrylist(NULL),
- m_entrylist_tailptr(&m_entrylist)
{
copyfrom(src);
}
@@ -199,13 +189,6 @@ core_options::core_options(const core_options &src)
core_options::~core_options()
{
- // delete all entries from the list
- while (m_entrylist != NULL)
- {
- core_options::entry *e = m_entrylist;
- remove_entry(*m_entrylist);
- delete e;
- }
}
@@ -229,11 +212,11 @@ core_options &core_options::operator=(const core_options &rhs)
bool core_options::operator==(const core_options &rhs)
{
// iterate over options in the first list
- for (entry *curentry = m_entrylist; curentry != NULL; curentry = curentry->next())
+ for (entry *curentry = m_entrylist.first(); curentry != NULL; curentry = curentry->next())
if (!curentry->is_header())
{
// if the values differ, return false
- if (strcmp(curentry->m_data, rhs.value(curentry->name())) != 0)
+ if (strcmp(curentry->value(), rhs.value(curentry->name())) != 0)
return false;
}
@@ -252,44 +235,49 @@ bool core_options::operator!=(const core_options &rhs)
//-------------------------------------------------
-// add_entries - add entries to the current
-// options sets
+// add_entry - add an entry to the current
+// options set
//-------------------------------------------------
-void core_options::add_entries(const options_entry *entrylist, bool override_existing)
+void core_options::add_entry(const char *name, const char *description, UINT32 flags, const char *defvalue, bool override_existing)
{
- // loop over entries until we hit a NULL name
- for ( ; entrylist->name != NULL || (entrylist->flags & OPTION_HEADER) != 0; entrylist++)
+ // allocate a new entry
+ entry *newentry = global_alloc(entry(name, description, flags, defvalue));
+ if (newentry->name() != NULL)
{
- // allocate a new entry
- entry *newentry = new entry(*entrylist);
- if (newentry->name() != NULL)
+ // see if we match an existing entry
+ entry *existing = m_entrymap.find(newentry->name());
+ if (existing != NULL)
{
- // see if we match an existing entry
- entry *existing = m_entrymap.find(newentry->name());
- if (existing != NULL)
- {
- // if we're overriding existing entries, then remove the old one
- if (override_existing)
- {
- core_options::entry *e = m_entrylist;
- remove_entry(*existing);
- delete e;
- }
+ // if we're overriding existing entries, then remove the old one
+ if (override_existing)
+ m_entrylist.remove(*existing);
- // otherwise, just override the default and current values and throw out the new entry
- else
- {
- existing->set_default_value(newentry->value());
- delete newentry;
- continue;
- }
+ // otherwise, just override the default and current values and throw out the new entry
+ else
+ {
+ existing->set_default_value(newentry->value());
+ global_free(newentry);
+ return;
}
}
-
- // add us to the list and maps
- append_entry(*newentry);
}
+
+ // add us to the list and maps
+ append_entry(*newentry);
+}
+
+
+//-------------------------------------------------
+// add_entries - add entries to the current
+// options sets
+//-------------------------------------------------
+
+void core_options::add_entries(const options_entry *entrylist, bool override_existing)
+{
+ // loop over entries until we hit a NULL name
+ for ( ; entrylist->name != NULL || (entrylist->flags & OPTION_HEADER) != 0; entrylist++)
+ add_entry(*entrylist, override_existing);
}
@@ -323,7 +311,7 @@ bool core_options::parse_command_line(int argc, char **argv, int priority, astri
// iterate through arguments
int unadorned_index = 0;
- bool retVal = true;
+ bool retval = true;
for (int arg = 1; arg < argc; arg++)
{
// determine the entry name to search for
@@ -336,7 +324,7 @@ bool core_options::parse_command_line(int argc, char **argv, int priority, astri
if (curentry == NULL)
{
error_string.catprintf("Error: unknown option: %s\n", curarg);
- retVal = false;
+ retval = false;
if (!is_unadorned) arg++;
continue;
}
@@ -371,7 +359,7 @@ bool core_options::parse_command_line(int argc, char **argv, int priority, astri
// set the new data
validate_and_set_data(*curentry, newdata, priority, error_string);
}
- return retVal;
+ return retval;
}
@@ -448,7 +436,7 @@ bool core_options::parse_ini_file(core_file &inifile, int priority, int ignore_p
void core_options::revert(int priority)
{
// iterate over options and revert to defaults if below the given priority
- for (entry *curentry = m_entrylist; curentry != NULL; curentry = curentry->next())
+ for (entry *curentry = m_entrylist.first(); curentry != NULL; curentry = curentry->next())
curentry->revert(priority);
}
@@ -469,7 +457,7 @@ const char *core_options::output_ini(astring &buffer, const core_options *diff)
const char *last_header = NULL;
// loop over all items
- for (entry *curentry = m_entrylist; curentry != NULL; curentry = curentry->next())
+ for (entry *curentry = m_entrylist.first(); curentry != NULL; curentry = curentry->next())
{
const char *name = curentry->name();
const char *value = curentry->value();
@@ -529,7 +517,7 @@ const char *core_options::output_help(astring &buffer)
buffer.reset();
// loop over all items
- for (entry *curentry = m_entrylist; curentry != NULL; curentry = curentry->next())
+ for (entry *curentry = m_entrylist.first(); curentry != NULL; curentry = curentry->next())
{
// header: just print
if (curentry->is_header())
@@ -629,6 +617,7 @@ void core_options::set_flag(const char *name, UINT32 mask, UINT32 flag)
curentry->set_flag(mask, flag);
}
+
//-------------------------------------------------
// reset - reset the options state, removing
// everything
@@ -636,15 +625,7 @@ void core_options::set_flag(const char *name, UINT32 mask, UINT32 flag)
void core_options::reset()
{
- // remove all entries from the list
- while (m_entrylist != NULL)
- {
- core_options::entry *e = m_entrylist;
- remove_entry(*m_entrylist);
- delete e;
- }
-
- // reset the map
+ m_entrylist.reset();
m_entrymap.reset();
}
@@ -656,20 +637,17 @@ void core_options::reset()
void core_options::append_entry(core_options::entry &newentry)
{
- // append to the list
- *m_entrylist_tailptr = &newentry;
- m_entrylist_tailptr = &newentry.m_next;
+ m_entrylist.append(newentry);
// if we have names, add them to the map
- astring tempstr;
for (int name = 0; name < ARRAY_LENGTH(newentry.m_name); name++)
- if (newentry.m_name[name])
+ if (newentry.name(name) != NULL)
{
- m_entrymap.add(newentry.m_name[name], &newentry);
+ m_entrymap.add(newentry.name(name), &newentry);
// for boolean options add a "no" variant as well
if (newentry.type() == OPTION_BOOLEAN)
- m_entrymap.add(tempstr.cpy("no").cat(newentry.m_name[name]), &newentry);
+ m_entrymap.add(astring("no", newentry.name(name)), &newentry);
}
}
@@ -681,32 +659,13 @@ void core_options::append_entry(core_options::entry &newentry)
void core_options::remove_entry(core_options::entry &delentry)
{
- // remove us from the list
- entry *preventry = NULL;
- for (entry *curentry = m_entrylist; curentry != NULL; curentry = curentry->next())
- if (curentry == &delentry)
- {
- // update link from previous to us
- if (preventry != NULL)
- preventry->m_next = delentry.m_next;
- else
- m_entrylist = delentry.m_next;
+ // remove all names from the map
+ for (int name = 0; name < ARRAY_LENGTH(delentry.m_name); name++)
+ if (delentry.m_name[name])
+ m_entrymap.remove(delentry.m_name[name]);
- // if we're the last item, update the next pointer
- if (delentry.m_next == NULL)
- {
- if (preventry != NULL)
- m_entrylist_tailptr = &preventry->m_next;
- else
- m_entrylist_tailptr = &m_entrylist;
- }
-
- // remove all entries from the map
- for (int name = 0; name < ARRAY_LENGTH(delentry.m_name); name++)
- if (delentry.m_name[name])
- m_entrymap.remove(delentry.m_name[name]);
- break;
- }
+ // remove the entry from the list
+ m_entrylist.remove(delentry);
}
@@ -720,8 +679,8 @@ void core_options::copyfrom(const core_options &src)
reset();
// iterate through the src options and make our own
- for (entry *curentry = src.m_entrylist; curentry != NULL; curentry = curentry->next())
- append_entry(*new entry(*curentry));
+ for (entry *curentry = src.m_entrylist.first(); curentry != NULL; curentry = curentry->next())
+ append_entry(*global_alloc(entry(curentry->name(), curentry->description(), curentry->flags(), curentry->default_value())));
}
@@ -802,15 +761,3 @@ bool core_options::validate_and_set_data(core_options::entry &curentry, const ch
curentry.set_value(data, priority);
return true;
}
-
-//-------------------------------------------------
-// options_count - take number of existing
-// number of options in structure
-//-------------------------------------------------
-
-int core_options::options_count()
-{
- int number = 0;
- for (entry *curentry = m_entrylist; curentry != NULL; curentry = curentry->next()) number++;
- return number;
-}
diff --git a/src/lib/util/options.h b/src/lib/util/options.h
index 75191bf1d5b..f90e56a0a23 100644
--- a/src/lib/util/options.h
+++ b/src/lib/util/options.h
@@ -68,14 +68,15 @@ public:
class entry
{
friend class core_options;
+ friend class simple_list<entry>;
// construction/destruction
- entry(const options_entry &entry);
+ entry(const char *name, const char *description, UINT32 flags = 0, const char *defvalue = NULL);
public:
// getters
entry *next() const { return m_next; }
- const char *name() const { return m_name[0] ? m_name[0].cstr() : NULL; }
+ const char *name(int index = 0) const { return (index < ARRAY_LENGTH(m_name) && m_name[index]) ? m_name[index].cstr() : NULL; }
const char *description() const { return m_description; }
const char *value() const { return m_data; }
const char *default_value() const { return m_defdata; }
@@ -125,10 +126,12 @@ public:
bool operator!=(const core_options &rhs);
// getters
- entry *first() const { return m_entrylist; }
+ entry *first() const { return m_entrylist.first(); }
const char *command() const { return m_command; }
// configuration
+ void add_entry(const char *name, const char *description, UINT32 flags = 0, const char *defvalue = NULL, bool override_existing = false);
+ void add_entry(const options_entry &data, bool override_existing = false) { add_entry(data.name, data.description, data.flags, data.defvalue, override_existing); }
void add_entries(const options_entry *entrylist, bool override_existing = false);
void set_default_value(const char *name, const char *defvalue);
void remove_entry(entry &delentry);
@@ -162,7 +165,8 @@ public:
// misc
static const char *unadorned(int x = 0) { return s_option_unadorned[MIN(x, MAX_UNADORNED_OPTIONS)]; }
- int options_count();
+ int options_count() const { return m_entrylist.count(); }
+
private:
// internal helpers
void reset();
@@ -171,8 +175,7 @@ private:
bool validate_and_set_data(entry &curentry, const char *newdata, int priority, astring &error_string);
// internal state
- entry * m_entrylist; // head of list of entries
- entry ** m_entrylist_tailptr; // pointer to tail of entry list
+ simple_list<entry> m_entrylist; // head of list of entries
tagmap_t<entry *> m_entrymap; // map for fast lookup
astring m_command; // command found
static const char *const s_option_unadorned[]; // array of unadorned option "names"
diff --git a/src/lib/util/simple_set.h b/src/lib/util/simple_set.h
index b0e2793cd76..9f9f127f6ec 100644
--- a/src/lib/util/simple_set.h
+++ b/src/lib/util/simple_set.h
@@ -40,9 +40,8 @@ class simple_set
public:
// Construction
- simple_set(resource_pool &pool = global_resource_pool())
- : m_root(NULL),
- m_pool(pool)
+ simple_set()
+ : m_root(NULL)
{ }
simple_set(const simple_set& rhs)
@@ -57,10 +56,6 @@ public:
}
- // A reference to the resource pool
- resource_pool &pool() const { return m_pool; }
-
-
// Returns number of elements in the tree -- O(n)
int size() const
{
@@ -116,7 +111,7 @@ public:
// If it's a leaf node, simply remove it
removeNode(currNode);
- pool_free(m_pool, currNode);
+ global_free(currNode);
}
else
{
@@ -145,7 +140,7 @@ public:
tree_node* right = currNode->right;
// We no longer need this node
- pool_free(m_pool, currNode);
+ global_free(currNode);
// Check to see if we removed the root node
if (!parentNode)
@@ -216,7 +211,7 @@ public:
}
else
{
- pool_free(m_pool, c);
+ global_free(c);
}
return retVal;
@@ -258,10 +253,6 @@ private:
// The AVL tree's root
tree_node* m_root;
- // Resource pool where objects are freed
- resource_pool& m_pool;
-
-
// Find a node in the tree
tree_node* findNode(const T& x) const
{
@@ -282,7 +273,7 @@ private:
{
if (t == NULL)
{
- t = pool_alloc(m_pool, tree_node(x, NULL, NULL, NULL));
+ t = global_alloc(tree_node(x, NULL, NULL, NULL));
// An empty sub-tree here, insertion successful
return true;
@@ -353,7 +344,7 @@ private:
clearRecurse(t->left);
clearRecurse(t->right);
- pool_free(m_pool, t);
+ global_free(t);
}
t = NULL;
}
@@ -485,7 +476,7 @@ private:
else
{
// Create a node with the left and right nodes and a parent set to NULL
- tree_node* retVal = pool_alloc(m_pool, tree_node(t->element, NULL, clone(t->left), clone(t->right)));
+ tree_node* retVal = global_alloc(tree_node(t->element, NULL, clone(t->left), clone(t->right)));
// Now set our children's parent node reference
if (retVal->left) { retVal->left->setParent(retVal); }
diff --git a/src/lib/util/tagmap.h b/src/lib/util/tagmap.h
index 07acdaa26da..d35922a49b0 100644
--- a/src/lib/util/tagmap.h
+++ b/src/lib/util/tagmap.h
@@ -14,6 +14,7 @@
#define __TAGMAP_H__
#include "osdcore.h"
+#include "coretmpl.h"
#include "astring.h"
#ifdef MAME_DEBUG
#include "eminline.h"
@@ -183,7 +184,7 @@ private:
{
entry_t *entry = *entryptr;
*entryptr = entry->next();
- delete entry;
+ global_free(entry);
}
// internal state
@@ -191,6 +192,110 @@ private:
};
+// ======================> tagged_list
+
+// a tagged_list is a class that maintains a list of objects that can be quickly looked up by tag
+template<class _ElementType>
+class tagged_list
+{
+ // we don't support deep copying
+ tagged_list(const tagged_list &);
+ tagged_list &operator=(const tagged_list &);
+
+public:
+ class add_exception
+ {
+ public:
+ add_exception(const char *tag) : m_tag(tag) { }
+ const char *tag() const { return m_tag; }
+ private:
+ const char *m_tag;
+ };
+
+ // construction
+ tagged_list() { }
+
+ // simple getters
+ _ElementType *first() const { return m_list.first(); }
+ _ElementType *last() const { return m_list.last(); }
+ int count() const { return m_list.count(); }
+
+ // remove (free) all objects in the list, leaving an empty list
+ void reset() { m_list.reset(); m_map.reset(); }
+
+ // add the given object to the head of the list
+ _ElementType &prepend(const char *tag, _ElementType &object)
+ {
+ if (m_map.add_unique_hash(tag, &object, false) != TMERR_NONE)
+ throw add_exception(tag);
+ return m_list.prepend(object);
+ }
+
+ // add the given object to the tail of the list
+ _ElementType &append(const char *tag, _ElementType &object)
+ {
+ if (m_map.add_unique_hash(tag, &object, false) != TMERR_NONE)
+ throw add_exception(tag);
+ return m_list.append(object);
+ }
+
+ // insert the given object after a particular object (NULL means prepend)
+ _ElementType &insert_after(const char *tag, _ElementType &object, _ElementType *insert_after)
+ {
+ if (m_map.add_unique_hash(tag, &object, false) != TMERR_NONE)
+ throw add_exception(tag);
+ return m_list.insert_after(object, insert_after);
+ }
+
+ // replace an item in the list at the same location, and remove it
+ _ElementType &replace_and_remove(const char *tag, _ElementType &object, _ElementType &toreplace)
+ {
+ m_map.remove(&toreplace);
+ m_list.replace_and_remove(object, toreplace);
+ if (m_map.add_unique_hash(tag, &object, false) != TMERR_NONE)
+ throw add_exception(tag);
+ return object;
+ }
+
+ // detach the given item from the list, but don't free its memory
+ _ElementType &detach(_ElementType &object)
+ {
+ m_map.remove(&object);
+ return m_list.detach(object);
+ }
+
+ // remove the given object and free its memory
+ void remove(_ElementType &object)
+ {
+ m_map.remove(&object);
+ return m_list.remove(object);
+ }
+
+ // find an object by index in the list
+ _ElementType *find(int index) const
+ {
+ return m_list.find(index);
+ }
+
+ // return the index of the given object in the list
+ int indexof(const _ElementType &object) const
+ {
+ return m_list.indexof(object);
+ }
+
+ // operations by tag
+ _ElementType &replace_and_remove(const char *tag, _ElementType &object) { _ElementType *existing = find(tag); return (existing == NULL) ? append(tag, object) : replace_and_remove(tag, object, *existing); }
+ void remove(const char *tag) { _ElementType *object = find(tag); if (object != NULL) remove(*object); }
+ _ElementType *find(const char *tag) const { return m_map.find_hash_only(tag); }
+ int indexof(const char *tag) const { _ElementType *object = find(tag); return (object != NULL) ? m_list.indexof(*object) : NULL; }
+
+private:
+ // internal state
+ simple_list<_ElementType> m_list;
+ tagmap_t<_ElementType *> m_map;
+};
+
+
//**************************************************************************
// IMPLEMENTATION
@@ -218,7 +323,7 @@ tagmap_error tagmap_t<_ElementType, _HashSize>::add_common(const char *tag, _Ele
}
// now allocate a new entry and add to the head of the list
- entry_t *entry = new entry_t(tag, fullhash, object);
+ entry_t *entry = global_alloc(entry_t(tag, fullhash, object));
entry->m_next = m_table[hashindex];
m_table[hashindex] = entry;
return TMERR_NONE;
diff --git a/src/lib/util/xmlfile.c b/src/lib/util/xmlfile.c
index 568d0737144..2c8d78cdcdb 100644
--- a/src/lib/util/xmlfile.c
+++ b/src/lib/util/xmlfile.c
@@ -564,17 +564,29 @@ const char *xml_normalize_string(const char *string)
static void *expat_malloc(size_t size)
{
- return malloc(size);
+ UINT32 *result = (UINT32 *)malloc(size + 4 * sizeof(UINT32));
+ *result = size;
+ return &result[4];
}
-static void *expat_realloc(void *ptr, size_t size)
+static void expat_free(void *ptr)
{
- return realloc(ptr, size);
+ if (ptr != NULL)
+ free(&((UINT32 *)ptr)[-4]);
}
-static void expat_free(void *ptr)
+static void *expat_realloc(void *ptr, size_t size)
{
- free(ptr);
+ void *newptr = expat_malloc(size);
+ if (newptr == NULL)
+ return NULL;
+ if (ptr != NULL)
+ {
+ UINT32 oldsize = ((UINT32 *)ptr)[-4];
+ memcpy(newptr, ptr, oldsize);
+ expat_free(ptr);
+ }
+ return newptr;
}
@@ -658,7 +670,7 @@ static void expat_element_start(void *data, const XML_Char *name, const XML_Char
/*-------------------------------------------------
- expat_data - expat callback for a additional
+ expat_data - expat callback for an additional
element data
-------------------------------------------------*/
@@ -678,9 +690,15 @@ static void expat_data(void *data, const XML_Char *s, int len)
oldlen = (int)strlen((*curnode)->value);
/* realloc */
- newdata = (char *)realloc((void *)(*curnode)->value, oldlen + len + 1);
+ newdata = (char *)malloc(oldlen + len + 1);
if (newdata == NULL)
return;
+ if ((*curnode)->value != NULL)
+ {
+ memcpy(newdata, (*curnode)->value, oldlen);
+ free((*curnode)->value);
+ }
+ (*curnode)->value = newdata;
/* copy in the new data a NULL-terminate */
memcpy(&newdata[oldlen], s, len);