added fixed-size block allocator

This commit is contained in:
hyung-hwan 2010-08-26 07:15:40 +00:00
parent 8a19cce569
commit 70ca33c756
13 changed files with 486 additions and 110 deletions

View File

@ -1,7 +1,8 @@
/** @page cmn COMMON FUNCTIONS /** @page cmn COMMON FUNCTIONS
@section xma MEMORY ALLOCATOR @section xma MEMORY ALLOCATOR
QSE provides a memory allocator #qse_xma_t for private heap management. - QSE provides a memory allocator #qse_xma_t for private heap management.
- QSE provides a fixed-size block memory allocator #qse_fma_t.
@section rex REGULAR EXPRESSION @section rex REGULAR EXPRESSION
QSE provides a regular expression processor #qse_rex_t. QSE provides a regular expression processor #qse_rex_t.

View File

@ -92,9 +92,11 @@ foundation for other modules. Specialized functions and data structures are
organized to dedicated modules. See relevant subpages for more information organized to dedicated modules. See relevant subpages for more information
on each module. on each module.
- @subpage cmn "Common Functions" - @subpage cmn "Common Functions"
- @subpage awk "AWK Interpreter" -# xma.h variable-size block memory allocator
- @subpage cut "CUT Text Cutter" -# fma.h fixed-size block memory allocator
- @subpage sed "SED Stream Editor" - @subpage awk "AWK Interpreter"
- @subpage cut "CUT Text Cutter"
- @subpage sed "SED Stream Editor"
*/ */

View File

@ -1,7 +1,7 @@
pkgincludedir = $(includedir)/qse/cmn pkgincludedir = $(includedir)/qse/cmn
pkginclude_HEADERS = \ pkginclude_HEADERS = \
mem.h xma.h chr.h str.h lda.h htb.h rbt.h \ mem.h xma.h fma.h chr.h str.h lda.h htb.h rbt.h \
rex.h sll.h dll.h opt.h tio.h \ rex.h sll.h dll.h opt.h tio.h \
fio.h pio.h sio.h time.h misc.h main.h stdio.h fio.h pio.h sio.h time.h misc.h main.h stdio.h

View File

@ -51,9 +51,9 @@ CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES = CONFIG_CLEAN_VPATH_FILES =
SOURCES = SOURCES =
DIST_SOURCES = DIST_SOURCES =
am__pkginclude_HEADERS_DIST = mem.h xma.h chr.h str.h lda.h htb.h \ am__pkginclude_HEADERS_DIST = mem.h xma.h fma.h chr.h str.h lda.h \
rbt.h rex.h sll.h dll.h opt.h tio.h fio.h pio.h sio.h time.h \ htb.h rbt.h rex.h sll.h dll.h opt.h tio.h fio.h pio.h sio.h \
misc.h main.h stdio.h Mmgr.hpp StdMmgr.hpp Mmged.hpp time.h misc.h main.h stdio.h Mmgr.hpp StdMmgr.hpp Mmged.hpp
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \ am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
@ -220,9 +220,9 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@ top_srcdir = @top_srcdir@
pkginclude_HEADERS = mem.h xma.h chr.h str.h lda.h htb.h rbt.h rex.h \ pkginclude_HEADERS = mem.h xma.h fma.h chr.h str.h lda.h htb.h rbt.h \
sll.h dll.h opt.h tio.h fio.h pio.h sio.h time.h misc.h main.h \ rex.h sll.h dll.h opt.h tio.h fio.h pio.h sio.h time.h misc.h \
stdio.h $(am__append_1) main.h stdio.h $(am__append_1)
all: all-am all: all-am
.SUFFIXES: .SUFFIXES:

175
qse/include/qse/cmn/fma.h Normal file
View File

@ -0,0 +1,175 @@
/*
* $Id$
*
Copyright 2006-2009 Chung, Hyung-Hwan.
This file is part of QSE.
QSE is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
QSE 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _QSE_CMN_FMA_H_
#define _QSE_CMN_FMA_H_
/** @file
* This file defines a fixed-size block memory allocator. As the block size
* is known in advance, it achieves block allocation with little overhead.
*
* <pre>
* chunk head(cnkhead)
* | chunk
* | +---------------------------------------------+
* +--> | | f1 | f2 | | |
* +--|---------^------|----^--------------------+
* | | | |
* | +------+ +---+ +--------------+ chunk
* | | | |
* | +-----------------|----V--------------|-------+
* +---> | | | f3 | | f4 |
* +---------------------------------------^-----+
* |
* free block head (freeblk)
* </pre>
*
* The diagram above assumes that f1, f2, f3, and f4 are free blocks.
* The chaining order depends on the allocation and deallocation order.
*
* See #qse_fma_t for more information. Use #qse_xma_t for variable-size block
* allocation.
*/
#include <qse/types.h>
#include <qse/macros.h>
/** @struct qse_fma_cnk_t
* The qse_fma_cnk_t type defines a memory chunk header to hold memory blocks.
* The chunks added are maintained in a singly-linked list
*/
typedef struct qse_fma_cnk_t qse_fma_cnk_t;
struct qse_fma_cnk_t
{
qse_fma_cnk_t* next; /**< point to the next chunk */
};
/** @struct qse_fma_blk_t
* The qse_fma_blk_t type defines a memory block header to weave free blocks
* into a singly-linked list.
*/
typedef struct qse_fma_blk_t qse_fma_blk_t;
struct qse_fma_blk_t
{
qse_fma_blk_t* next; /**< point to the next block */
};
/** @struct qse_fma_t
* The qse_fma_t type defines a fixed-size block memory allocator.
* See the example below. Note that it omits error handling.
* @code
* qse_fma_t* fma;
* int* ptr1, * ptr2;
*
* // create a memory allocator for integer blocks up to 50.
* fma = qse_fma_open (QSE_NULL, 0, sizeof(int), 10, 5);
*
* // allocate two integer blocks
* ptr1 = (int*) qse_fma_alloc (fma);
* ptr2 = (int*) qse_fma_alloc (fma);
*
* *ptr1 = 20; *ptr2 = 99;
*
* // free the two blocks.
* qse_fma_free (fma, ptr1);
* qse_fma_free (fma, ptr2);
*
* // destroy the memory allocator
* qse_fma_close (fma);
* @endcode
*/
typedef struct qse_fma_t qse_fma_t;
struct qse_fma_t
{
QSE_DEFINE_COMMON_FIELDS (fma)
qse_size_t blksize; /**< block size */
qse_size_t maxblks; /**< maximum blocks in a chunk */
qse_size_t maxcnks; /**< maximum chunks */
qse_size_t numcnks; /**< current numbers of chunks */
qse_fma_cnk_t* cnkhead; /**< point to the first chunk added */
qse_fma_blk_t* freeblk; /**< point to the first free block */
};
#ifdef __cplusplus
extern "C" {
#endif
QSE_DEFINE_COMMON_FUNCTIONS (fma)
/**
* The qse_fma_open() function creates a memory allocator with an outer
* memory manager.
*/
qse_fma_t* qse_fma_open (
qse_mmgr_t* mmgr, /**< outer memory manager */
qse_size_t xtnsize, /**< extension size in bytes */
qse_size_t blksize, /**< block size in bytes */
qse_size_t maxblks, /**< maximum numbers of blocks in a chunk */
qse_size_t maxcnks /**< maximum numbers of chunks */
);
/**
* The qse_fma_close() function destroys an memory allocator.
*/
void qse_fma_close (
qse_fma_t* fma /**< memory allocator */
);
/**
* The qse_fma_init() function initializes an memory allocator.
*/
qse_fma_t* qse_fma_init (
qse_fma_t* fma, /**< memory allocator */
qse_mmgr_t* mmgr, /**< outer memory manager */
qse_size_t blksize, /**< block size in bytes */
qse_size_t maxblks, /**< maximum numbers of blocks in a chunk */
qse_size_t maxcnks /**< maximum numbers of chunks */
);
/**
* The qse_fma_fini() function finalizes an memory allocator.
*/
void qse_fma_fini (
qse_fma_t* fma /**< memory allocator */
);
/**
* The qse_fma_alloc() function allocates a block.
* @return block pointer on success, QSE_NULL on failure
*/
void* qse_fma_alloc (
qse_fma_t* fma /**< memory allocator */
);
/**
* The qse_fma_alloc() function deallocates a block.
*/
void qse_fma_free (
qse_fma_t* fma, /**< memory allocator */
void* blk /**< memory block to free */
);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -23,6 +23,11 @@
/** @file /** @file
* This file defines an extravagant memory allocator. Why? It may be so. * This file defines an extravagant memory allocator. Why? It may be so.
* The memory allocator allows you to maintain memory blocks from a
* larger memory chunk allocated with an outer memory allocator.
* Typically, an outer memory allocator is a standard memory allocator
* like malloc(). You can isolate memory blocks into a particular chunk.
* See #qse_xma_t for an example.
*/ */
#include <qse/types.h> #include <qse/types.h>
#include <qse/macros.h> #include <qse/macros.h>
@ -173,7 +178,8 @@ void qse_xma_free (
/** /**
* The qse_xma_dump() function dumps the contents of the memory zone * The qse_xma_dump() function dumps the contents of the memory zone
* with the output function @a printf provided. * with the output function @a printf provided. The debug build shows
* more statistical counters.
*/ */
void qse_xma_dump ( void qse_xma_dump (
qse_xma_t* xma, /**< memory allocator */ qse_xma_t* xma, /**< memory allocator */

View File

@ -5,7 +5,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include
lib_LTLIBRARIES = libqsecmn.la lib_LTLIBRARIES = libqsecmn.la
libqsecmn_la_SOURCES = \ libqsecmn_la_SOURCES = \
syscall.h mem.h \ syscall.h mem.h \
xma.c mem.c chr.c chr_cnv.c rex.c \ mem.c xma.c fma.c chr.c chr_cnv.c rex.c \
str_bas.c str_cnv.c str_dyn.c str_utl.c \ str_bas.c str_cnv.c str_dyn.c str_utl.c \
lda.c htb.c rbt.c sll.c dll.c opt.c \ lda.c htb.c rbt.c sll.c dll.c opt.c \
tio.c tio_get.c tio_put.c \ tio.c tio_get.c tio_put.c \

View File

@ -73,11 +73,11 @@ am__base_list = \
am__installdirs = "$(DESTDIR)$(libdir)" am__installdirs = "$(DESTDIR)$(libdir)"
LTLIBRARIES = $(lib_LTLIBRARIES) LTLIBRARIES = $(lib_LTLIBRARIES)
libqsecmn_la_DEPENDENCIES = libqsecmn_la_DEPENDENCIES =
am_libqsecmn_la_OBJECTS = xma.lo mem.lo chr.lo chr_cnv.lo rex.lo \ am_libqsecmn_la_OBJECTS = mem.lo xma.lo fma.lo chr.lo chr_cnv.lo \
str_bas.lo str_cnv.lo str_dyn.lo str_utl.lo lda.lo htb.lo \ rex.lo str_bas.lo str_cnv.lo str_dyn.lo str_utl.lo lda.lo \
rbt.lo sll.lo dll.lo opt.lo tio.lo tio_get.lo tio_put.lo \ htb.lo rbt.lo sll.lo dll.lo opt.lo tio.lo tio_get.lo \
fio.lo pio.lo sio.lo time.lo misc.lo assert.lo main.lo \ tio_put.lo fio.lo pio.lo sio.lo time.lo misc.lo assert.lo \
stdio.lo main.lo stdio.lo
libqsecmn_la_OBJECTS = $(am_libqsecmn_la_OBJECTS) libqsecmn_la_OBJECTS = $(am_libqsecmn_la_OBJECTS)
libqsecmn_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ libqsecmn_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
@ -262,7 +262,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include
lib_LTLIBRARIES = libqsecmn.la $(am__append_1) lib_LTLIBRARIES = libqsecmn.la $(am__append_1)
libqsecmn_la_SOURCES = \ libqsecmn_la_SOURCES = \
syscall.h mem.h \ syscall.h mem.h \
xma.c mem.c chr.c chr_cnv.c rex.c \ mem.c xma.c fma.c chr.c chr_cnv.c rex.c \
str_bas.c str_cnv.c str_dyn.c str_utl.c \ str_bas.c str_cnv.c str_dyn.c str_utl.c \
lda.c htb.c rbt.c sll.c dll.c opt.c \ lda.c htb.c rbt.c sll.c dll.c opt.c \
tio.c tio_get.c tio_put.c \ tio.c tio_get.c tio_put.c \
@ -362,6 +362,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chr_cnv.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chr_cnv.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dll.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dll.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fio.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fio.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fma.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htb.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htb.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lda.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lda.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Plo@am__quote@

139
qse/lib/cmn/fma.c Normal file
View File

@ -0,0 +1,139 @@
/*
* $Id$
*
Copyright 2006-2009 Chung, Hyung-Hwan.
This file is part of QSE.
QSE is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
QSE 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
*/
#include <qse/cmn/fma.h>
#include "mem.h"
QSE_IMPLEMENT_COMMON_FUNCTIONS (fma)
qse_fma_t* qse_fma_open (
qse_mmgr_t* mmgr, qse_size_t xtnsize,
qse_size_t blksize, qse_size_t maxblks, qse_size_t maxcnks)
{
qse_fma_t* fma;
if (mmgr == QSE_NULL)
{
mmgr = QSE_MMGR_GETDFL();
QSE_ASSERTX (mmgr != QSE_NULL,
"Set the memory manager with QSE_MMGR_SETDFL()");
if (mmgr == QSE_NULL) return QSE_NULL;
}
fma = (qse_fma_t*) QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(*fma) + xtnsize);
if (fma == QSE_NULL) return QSE_NULL;
if (qse_fma_init (fma, mmgr, blksize, maxblks, maxcnks) == QSE_NULL)
{
QSE_MMGR_FREE (mmgr, fma);
return QSE_NULL;
}
return fma;
}
void qse_fma_close (qse_fma_t* fma)
{
qse_fma_fini (fma);
QSE_MMGR_FREE (fma->mmgr, fma);
}
qse_fma_t* qse_fma_init (
qse_fma_t* fma, qse_mmgr_t* mmgr,
qse_size_t blksize, qse_size_t maxblks, qse_size_t maxcnks)
{
QSE_MEMSET (fma, 0, QSE_SIZEOF(*fma));
fma->mmgr = mmgr;
if (blksize <= QSE_SIZEOF(qse_fma_blk_t))
blksize = QSE_SIZEOF(qse_fma_blk_t);
if (maxblks <= 0) maxblks = 1;
if (maxcnks <= 0) maxcnks = 1;
fma->blksize = blksize;
fma->maxblks = maxblks;
fma->maxcnks = maxcnks;
return fma;
}
void qse_fma_fini (qse_fma_t* fma)
{
while (fma->cnkhead)
{
qse_fma_cnk_t* next = fma->cnkhead->next;
QSE_MMGR_FREE (fma->mmgr, fma->cnkhead);
fma->cnkhead = next;
}
}
static QSE_INLINE qse_fma_cnk_t* add_chunk (qse_fma_t* fma)
{
qse_fma_cnk_t* cnk;
qse_fma_blk_t* blk;
qse_size_t i;
/* check if there are too many chunks */
if (fma->numcnks >= fma->maxcnks) return QSE_NULL;
/* allocate a chunk */
cnk = (qse_fma_cnk_t*) QSE_MMGR_ALLOC (fma->mmgr,
QSE_SIZEOF(*cnk) + fma->blksize * fma->maxblks);
if (cnk == QSE_NULL) return QSE_NULL;
/* weave the blocks in the chunk to the free block list */
fma->freeblk = (qse_fma_blk_t*)(cnk + 1);
blk = fma->freeblk;
for (i = 1; i < fma->maxblks; i++)
{
blk->next = (qse_fma_blk_t*)((qse_byte_t*)blk + fma->blksize);
blk = blk->next;
}
blk->next = QSE_NULL;
/* weave the chunk to the chunk list */
cnk->next = fma->cnkhead;
fma->cnkhead = cnk;
fma->numcnks++;
return cnk;
}
void* qse_fma_alloc (qse_fma_t* fma)
{
void* blk;
if ((blk = fma->freeblk) == QSE_NULL)
{
if (add_chunk (fma) == QSE_NULL) return QSE_NULL;
blk = fma->freeblk;
}
fma->freeblk = fma->freeblk->next;
return blk;
}
void qse_fma_free (qse_fma_t* fma, void* blk)
{
((qse_fma_blk_t*)blk)->next = fma->freeblk;
fma->freeblk = blk;
}

View File

@ -142,7 +142,9 @@ qse_xma_t* qse_xma_init (qse_xma_t* xma, qse_mmgr_t* mmgr, qse_size_t zonesize)
qse_xma_blk_t* free; qse_xma_blk_t* free;
qse_size_t xfi; qse_size_t xfi;
/* round 'zonesize' to be the multiples of ALIGN */
zonesize = ((zonesize + ALIGN - 1) / ALIGN) * ALIGN; zonesize = ((zonesize + ALIGN - 1) / ALIGN) * ALIGN;
/* adjust 'zonesize' to be large enough to hold a single smallest block */ /* adjust 'zonesize' to be large enough to hold a single smallest block */
if (zonesize < MINBLKLEN) zonesize = MINBLKLEN; if (zonesize < MINBLKLEN) zonesize = MINBLKLEN;
@ -162,10 +164,14 @@ qse_xma_t* qse_xma_init (qse_xma_t* xma, qse_mmgr_t* mmgr, qse_size_t zonesize)
xma->mmgr = mmgr; xma->mmgr = mmgr;
xma->bdec = szlog2(FIXED*ALIGN); /* precalculate the decrement value */ xma->bdec = szlog2(FIXED*ALIGN); /* precalculate the decrement value */
/* the entire chunk is a free block */ /* at this point, the 'free' chunk is a only block available */
/* get the free block index */
xfi = getxfi(xma,free->size); xfi = getxfi(xma,free->size);
xma->xfree[xfi] = free; /* locate it at the right slot */ /* locate it into an apporopriate slot */
xma->head = free; /* store it for furture reference */ xma->xfree[xfi] = free;
/* let it be the head, which is natural with only a block */
xma->head = free;
/* initialize some statistical variables */ /* initialize some statistical variables */
#ifdef QSE_XMA_ENABLE_STAT #ifdef QSE_XMA_ENABLE_STAT
@ -181,14 +187,22 @@ qse_xma_t* qse_xma_init (qse_xma_t* xma, qse_mmgr_t* mmgr, qse_size_t zonesize)
void qse_xma_fini (qse_xma_t* xma) void qse_xma_fini (qse_xma_t* xma)
{ {
/* the head must point to the free chunk allocated in init().
* let's deallocate it */
QSE_MMGR_FREE (xma->mmgr, xma->head); QSE_MMGR_FREE (xma->mmgr, xma->head);
} }
static QSE_INLINE void attach_to_freelist (qse_xma_t* xma, qse_xma_blk_t* b) static QSE_INLINE void attach_to_freelist (qse_xma_t* xma, qse_xma_blk_t* b)
{ {
qse_size_t xfi = getxfi(xma,b->size); /*
* attach a block to a free list
*/
b->f.prev = QSE_NULL; /* get the free list index for the block size */
qse_size_t xfi = getxfi(xma,b->size);
/* let it be the head of the free list doubly-linked */
b->f.prev = QSE_NULL;
b->f.next = xma->xfree[xfi]; b->f.next = xma->xfree[xfi];
if (xma->xfree[xfi]) xma->xfree[xfi]->f.prev = b; if (xma->xfree[xfi]) xma->xfree[xfi]->f.prev = b;
xma->xfree[xfi] = b; xma->xfree[xfi] = b;
@ -196,22 +210,35 @@ static QSE_INLINE void attach_to_freelist (qse_xma_t* xma, qse_xma_blk_t* b)
static QSE_INLINE void detach_from_freelist (qse_xma_t* xma, qse_xma_blk_t* b) static QSE_INLINE void detach_from_freelist (qse_xma_t* xma, qse_xma_blk_t* b)
{ {
/*
* detach a block from a free list
*/
qse_xma_blk_t* p, * n; qse_xma_blk_t* p, * n;
/* alias the previous and the next with short variable names */
p = b->f.prev; p = b->f.prev;
n = b->f.next; n = b->f.next;
if (p) if (p)
{ {
/* the previous item exists. let its 'next' pointer point to
* the block's next item. */
p->f.next = n; p->f.next = n;
} }
else else
{ {
/* the previous item does not exist. the block is the first
* item in the free list. */
qse_size_t xfi = getxfi(xma,b->size); qse_size_t xfi = getxfi(xma,b->size);
QSE_ASSERT (b == xma->xfree[xfi]); QSE_ASSERT (b == xma->xfree[xfi]);
/* let's update the free list head */
xma->xfree[xfi] = n; xma->xfree[xfi] = n;
} }
if (n) n->f.prev = p;
/* let the 'prev' pointer of the block's next item point to the
* block's previous item */
if (n) n->f.prev = p;
} }
static qse_xma_blk_t* alloc_from_freelist ( static qse_xma_blk_t* alloc_from_freelist (
@ -363,22 +390,32 @@ static void* _realloc_merge (qse_xma_t* xma, void* b, qse_size_t size)
if (size > blk->size) if (size > blk->size)
{ {
/*
* grow the current block
*/
qse_size_t req = size - blk->size; qse_size_t req = size - blk->size;
qse_xma_blk_t* n; qse_xma_blk_t* n;
qse_size_t rem; qse_size_t rem;
n = blk->b.next; n = blk->b.next;
if (!n || !n->avail || req > n->size) return QSE_NULL;
/* merge the current block with the next block /* check if the next adjacent block is available */
* if it is available */ if (!n || !n->avail || req > n->size) return QSE_NULL; /* no! */
/* let's merge the current block with the next block */
detach_from_freelist (xma, n); detach_from_freelist (xma, n);
rem = (HDRSIZE + n->size) - req; rem = (HDRSIZE + n->size) - req;
if (rem >= MINBLKLEN) if (rem >= MINBLKLEN)
{ {
/*
* the remaining part of the next block is large enough
* to hold a block. break the next block.
*/
qse_xma_blk_t* tmp; qse_xma_blk_t* tmp;
/* store n->b.next in case 'tmp' begins somewhere /* store n->b.next in case 'tmp' begins somewhere
* in the header part of n */ * in the header part of n */
qse_xma_blk_t* nn = n->b.next; qse_xma_blk_t* nn = n->b.next;
@ -404,6 +441,8 @@ static void* _realloc_merge (qse_xma_t* xma, void* b, qse_size_t size)
} }
else else
{ {
/* the remaining part of the next block is negligible.
* utilize the whole block by merging to the resizing block */
blk->size += HDRSIZE + n->size; blk->size += HDRSIZE + n->size;
blk->b.next = n->b.next; blk->b.next = n->b.next;
if (n->b.next) n->b.next->b.prev = blk; if (n->b.next) n->b.next->b.prev = blk;
@ -414,80 +453,13 @@ static void* _realloc_merge (qse_xma_t* xma, void* b, qse_size_t size)
xma->stat.avail -= n->size; xma->stat.avail -= n->size;
#endif #endif
} }
#if 0
qse_size_t total = 0;
qse_xma_blk_t* x = QSE_NULL;
/* find continuous blocks available to accomodate
* additional space required */
for (n = blk->b.next; n && n->avail; n = n->b.next)
{
total += n->size + HDRSIZE;
if (req <= total)
{
x = n;
break;
}
n = n->b.next;
}
if (!x)
{
/* no such blocks. return failure */
return QSE_NULL;
}
for (n = blk->b.next; n != x; n = n->b.next)
{
detach_from_freelist (xma, n);
#ifdef QSE_XMA_ENABLE_STAT
xma->stat.nfree--;
#endif
}
detach_from_freelist (xma, x);
rem = total - req;
if (rem >= MINBLKLEN)
{
qse_xma_blk_t* tmp;
tmp = (qse_xma_blk_t*)(((qse_byte_t*)(blk->b.next + 1)) + req);
tmp->avail = 1;
tmp->size = rem - HDRSIZE;
attach_to_freelist (xma, tmp);
blk->size += req;
tmp->b.next = x->b.next;
if (x->b.next) x->b.next->b.prev = tmp;
blk->b.next = tmp;
tmp->b.prev = blk;
#ifdef QSE_XMA_ENABLE_STAT
xma->stat.alloc += req;
xma->stat.avail -= req + HDRSIZE;
#endif
}
else
{
blk->size += total;
blk->b.next = x->b.next;
if (x->b.next) x->b.next->b.prev = blk;
#ifdef QSE_XMA_ENABLE_STAT
xma->stat.nfree--;
xma->stat.alloc += total;
xma->stat.avail -= total;
#endif
}
#endif
} }
else if (size < blk->size) else if (size < blk->size)
{ {
/*
* shrink the block
*/
qse_size_t rem = blk->size - size; qse_size_t rem = blk->size - size;
if (rem >= MINBLKLEN) if (rem >= MINBLKLEN)
{ {

View File

@ -1,11 +1,12 @@
AM_CPPFLAGS = -I$(top_srcdir)/include -DNDEBUG AM_CPPFLAGS = -I$(top_srcdir)/include -DNDEBUG
bin_PROGRAMS = xma chr str sll lda htb rbt fio pio sio time main rex01 bin_PROGRAMS = xma fma chr str sll lda htb rbt fio pio sio time main rex01
LDFLAGS = -L../../lib/cmn LDFLAGS = -L../../lib/cmn
LDADD = -lqsecmn LDADD = -lqsecmn
xma_SOURCES = xma.c xma_SOURCES = xma.c
fma_SOURCES = fma.c
chr_SOURCES = chr.c chr_SOURCES = chr.c
str_SOURCES = str.c str_SOURCES = str.c
sll_SOURCES = sll.c sll_SOURCES = sll.c

View File

@ -34,10 +34,10 @@ PRE_UNINSTALL = :
POST_UNINSTALL = : POST_UNINSTALL = :
build_triplet = @build@ build_triplet = @build@
host_triplet = @host@ host_triplet = @host@
bin_PROGRAMS = xma$(EXEEXT) chr$(EXEEXT) str$(EXEEXT) sll$(EXEEXT) \ bin_PROGRAMS = xma$(EXEEXT) fma$(EXEEXT) chr$(EXEEXT) str$(EXEEXT) \
lda$(EXEEXT) htb$(EXEEXT) rbt$(EXEEXT) fio$(EXEEXT) \ sll$(EXEEXT) lda$(EXEEXT) htb$(EXEEXT) rbt$(EXEEXT) \
pio$(EXEEXT) sio$(EXEEXT) time$(EXEEXT) main$(EXEEXT) \ fio$(EXEEXT) pio$(EXEEXT) sio$(EXEEXT) time$(EXEEXT) \
rex01$(EXEEXT) main$(EXEEXT) rex01$(EXEEXT)
subdir = samples/cmn subdir = samples/cmn
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@ -62,6 +62,10 @@ am_fio_OBJECTS = fio.$(OBJEXT)
fio_OBJECTS = $(am_fio_OBJECTS) fio_OBJECTS = $(am_fio_OBJECTS)
fio_LDADD = $(LDADD) fio_LDADD = $(LDADD)
fio_DEPENDENCIES = fio_DEPENDENCIES =
am_fma_OBJECTS = fma.$(OBJEXT)
fma_OBJECTS = $(am_fma_OBJECTS)
fma_LDADD = $(LDADD)
fma_DEPENDENCIES =
am_htb_OBJECTS = htb.$(OBJEXT) am_htb_OBJECTS = htb.$(OBJEXT)
htb_OBJECTS = $(am_htb_OBJECTS) htb_OBJECTS = $(am_htb_OBJECTS)
htb_LDADD = $(LDADD) htb_LDADD = $(LDADD)
@ -119,14 +123,14 @@ CCLD = $(CC)
LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@ $(LDFLAGS) -o $@
SOURCES = $(chr_SOURCES) $(fio_SOURCES) $(htb_SOURCES) $(lda_SOURCES) \ SOURCES = $(chr_SOURCES) $(fio_SOURCES) $(fma_SOURCES) $(htb_SOURCES) \
$(main_SOURCES) $(pio_SOURCES) $(rbt_SOURCES) $(rex01_SOURCES) \
$(sio_SOURCES) $(sll_SOURCES) $(str_SOURCES) $(time_SOURCES) \
$(xma_SOURCES)
DIST_SOURCES = $(chr_SOURCES) $(fio_SOURCES) $(htb_SOURCES) \
$(lda_SOURCES) $(main_SOURCES) $(pio_SOURCES) $(rbt_SOURCES) \ $(lda_SOURCES) $(main_SOURCES) $(pio_SOURCES) $(rbt_SOURCES) \
$(rex01_SOURCES) $(sio_SOURCES) $(sll_SOURCES) $(str_SOURCES) \ $(rex01_SOURCES) $(sio_SOURCES) $(sll_SOURCES) $(str_SOURCES) \
$(time_SOURCES) $(xma_SOURCES) $(time_SOURCES) $(xma_SOURCES)
DIST_SOURCES = $(chr_SOURCES) $(fio_SOURCES) $(fma_SOURCES) \
$(htb_SOURCES) $(lda_SOURCES) $(main_SOURCES) $(pio_SOURCES) \
$(rbt_SOURCES) $(rex01_SOURCES) $(sio_SOURCES) $(sll_SOURCES) \
$(str_SOURCES) $(time_SOURCES) $(xma_SOURCES)
ETAGS = etags ETAGS = etags
CTAGS = ctags CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@ -272,6 +276,7 @@ top_srcdir = @top_srcdir@
AM_CPPFLAGS = -I$(top_srcdir)/include -DNDEBUG AM_CPPFLAGS = -I$(top_srcdir)/include -DNDEBUG
LDADD = -lqsecmn LDADD = -lqsecmn
xma_SOURCES = xma.c xma_SOURCES = xma.c
fma_SOURCES = fma.c
chr_SOURCES = chr.c chr_SOURCES = chr.c
str_SOURCES = str.c str_SOURCES = str.c
sll_SOURCES = sll.c sll_SOURCES = sll.c
@ -367,6 +372,9 @@ chr$(EXEEXT): $(chr_OBJECTS) $(chr_DEPENDENCIES)
fio$(EXEEXT): $(fio_OBJECTS) $(fio_DEPENDENCIES) fio$(EXEEXT): $(fio_OBJECTS) $(fio_DEPENDENCIES)
@rm -f fio$(EXEEXT) @rm -f fio$(EXEEXT)
$(LINK) $(fio_OBJECTS) $(fio_LDADD) $(LIBS) $(LINK) $(fio_OBJECTS) $(fio_LDADD) $(LIBS)
fma$(EXEEXT): $(fma_OBJECTS) $(fma_DEPENDENCIES)
@rm -f fma$(EXEEXT)
$(LINK) $(fma_OBJECTS) $(fma_LDADD) $(LIBS)
htb$(EXEEXT): $(htb_OBJECTS) $(htb_DEPENDENCIES) htb$(EXEEXT): $(htb_OBJECTS) $(htb_DEPENDENCIES)
@rm -f htb$(EXEEXT) @rm -f htb$(EXEEXT)
$(LINK) $(htb_OBJECTS) $(htb_LDADD) $(LIBS) $(LINK) $(htb_OBJECTS) $(htb_LDADD) $(LIBS)
@ -409,6 +417,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chr.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fio.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fio.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fma.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htb.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htb.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lda.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lda.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@

70
qse/samples/cmn/fma.c Normal file
View File

@ -0,0 +1,70 @@
#include <qse/cmn/fma.h>
#include <qse/cmn/stdio.h>
#define R(f) \
do { \
qse_printf (QSE_T("== %s ==\n"), QSE_T(#f)); \
if (f() == -1) return -1; \
} while (0)
static int test1 ()
{
int i;
int* ptr[100];
qse_fma_t* fma = qse_fma_open (QSE_NULL, 0, sizeof(int), 10, 5);
if (fma == QSE_NULL)
{
qse_printf (QSE_T("cannot open fma\n"));
return -1;
}
for (i = 0; i < 100; i++)
{
ptr[i] = qse_fma_alloc (fma);
if (ptr[i])
{
qse_printf (QSE_T("%d %p\n"), i, ptr[i]);
*(ptr[i]) = i;
}
else qse_printf (QSE_T("%d FAIL\n"), i);
}
for (i = 0; i < 30; i+=2)
{
if (ptr[i])
{
qse_fma_free (fma, ptr[i]);
ptr[i] = QSE_NULL;
}
}
for (i = 0; i < 100; i++)
{
if (ptr[i])
{
qse_fma_free (fma, ptr[i]);
ptr[i] = QSE_NULL;
}
}
for (i = 0; i < 100; i++)
{
ptr[i] = qse_fma_alloc (fma);
if (ptr[i])
{
qse_printf (QSE_T("%d %p\n"), i, ptr[i]);
*(ptr[i]) = i;
}
else qse_printf (QSE_T("%d FAIL\n"), i);
}
qse_fma_close (fma);
return 0;
}
int main ()
{
R (test1);
return 0;
}