From f1aa01909199da888614cc7735bd8fd0e143a6f5 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Thu, 30 Apr 2020 16:20:31 +0000 Subject: [PATCH] added ecs and htb --- mio/lib/Makefile.am | 7 + mio/lib/Makefile.in | 44 ++- mio/lib/ecs-imp.h | 453 +++++++++++++++++++++++++++ mio/lib/ecs.c | 103 +++++++ mio/lib/htb.c | 732 ++++++++++++++++++++++++++++++++++++++++++++ mio/lib/htrd.c | 28 +- mio/lib/htre.c | 78 +++-- mio/lib/http.c | 74 ++--- mio/lib/mio-cmn.h | 7 + mio/lib/mio-ecs.h | 640 ++++++++++++++++++++++++++++++++++++++ mio/lib/mio-htb.h | 682 +++++++++++++++++++++++++++++++++++++++++ mio/lib/mio-htre.h | 48 +-- mio/lib/mio-http.h | 25 +- 13 files changed, 2783 insertions(+), 138 deletions(-) create mode 100644 mio/lib/ecs-imp.h create mode 100644 mio/lib/ecs.c create mode 100644 mio/lib/htb.c create mode 100644 mio/lib/mio-ecs.h create mode 100644 mio/lib/mio-htb.h diff --git a/mio/lib/Makefile.am b/mio/lib/Makefile.am index ab3f0b7..0779e6a 100644 --- a/mio/lib/Makefile.am +++ b/mio/lib/Makefile.am @@ -23,7 +23,11 @@ include_HEADERS = \ mio-cfg.h \ mio-cmn.h \ mio-dns.h \ + mio-ecs.h \ mio-fmt.h \ + mio-htb.h \ + mio-htre.h \ + mio-http.h \ mio-nwif.h \ mio-pac1.h \ mio-pro.h \ @@ -37,9 +41,12 @@ lib_LTLIBRARIES = libmio.la libmio_la_SOURCES = \ dns.c \ dns-cli.c \ + ecs.c \ + ecs-imp.h \ err.c \ fmt.c \ fmt-imp.h \ + htb.c \ mio-prv.h \ mio.c \ nwif.c \ diff --git a/mio/lib/Makefile.in b/mio/lib/Makefile.in index 882b753..151043e 100644 --- a/mio/lib/Makefile.in +++ b/mio/lib/Makefile.in @@ -139,12 +139,12 @@ am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) libmio_la_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am_libmio_la_OBJECTS = libmio_la-dns.lo libmio_la-dns-cli.lo \ - libmio_la-err.lo libmio_la-fmt.lo libmio_la-mio.lo \ - libmio_la-nwif.lo libmio_la-pro.lo libmio_la-sck.lo \ - libmio_la-skad.lo libmio_la-sys.lo libmio_la-sys-ass.lo \ - libmio_la-sys-err.lo libmio_la-sys-log.lo libmio_la-sys-mux.lo \ - libmio_la-sys-tim.lo libmio_la-tmr.lo libmio_la-utf8.lo \ - libmio_la-utl.lo + libmio_la-ecs.lo libmio_la-err.lo libmio_la-fmt.lo \ + libmio_la-htb.lo libmio_la-mio.lo libmio_la-nwif.lo \ + libmio_la-pro.lo libmio_la-sck.lo libmio_la-skad.lo \ + libmio_la-sys.lo libmio_la-sys-ass.lo libmio_la-sys-err.lo \ + libmio_la-sys-log.lo libmio_la-sys-mux.lo libmio_la-sys-tim.lo \ + libmio_la-tmr.lo libmio_la-utf8.lo libmio_la-utl.lo libmio_la_OBJECTS = $(am_libmio_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -169,8 +169,9 @@ DEFAULT_INCLUDES = depcomp = $(SHELL) $(top_srcdir)/ac/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/libmio_la-dns-cli.Plo \ - ./$(DEPDIR)/libmio_la-dns.Plo ./$(DEPDIR)/libmio_la-err.Plo \ - ./$(DEPDIR)/libmio_la-fmt.Plo ./$(DEPDIR)/libmio_la-mio.Plo \ + ./$(DEPDIR)/libmio_la-dns.Plo ./$(DEPDIR)/libmio_la-ecs.Plo \ + ./$(DEPDIR)/libmio_la-err.Plo ./$(DEPDIR)/libmio_la-fmt.Plo \ + ./$(DEPDIR)/libmio_la-htb.Plo ./$(DEPDIR)/libmio_la-mio.Plo \ ./$(DEPDIR)/libmio_la-nwif.Plo ./$(DEPDIR)/libmio_la-pro.Plo \ ./$(DEPDIR)/libmio_la-sck.Plo ./$(DEPDIR)/libmio_la-skad.Plo \ ./$(DEPDIR)/libmio_la-sys-ass.Plo \ @@ -399,7 +400,11 @@ include_HEADERS = \ mio-cfg.h \ mio-cmn.h \ mio-dns.h \ + mio-ecs.h \ mio-fmt.h \ + mio-htb.h \ + mio-htre.h \ + mio-http.h \ mio-nwif.h \ mio-pac1.h \ mio-pro.h \ @@ -413,9 +418,12 @@ lib_LTLIBRARIES = libmio.la libmio_la_SOURCES = \ dns.c \ dns-cli.c \ + ecs.c \ + ecs-imp.h \ err.c \ fmt.c \ fmt-imp.h \ + htb.c \ mio-prv.h \ mio.c \ nwif.c \ @@ -532,8 +540,10 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-dns-cli.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-dns.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-ecs.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-err.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-fmt.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-htb.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-mio.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-nwif.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-pro.Plo@am__quote@ # am--include-marker @@ -593,6 +603,13 @@ libmio_la-dns-cli.lo: dns-cli.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmio_la-dns-cli.lo `test -f 'dns-cli.c' || echo '$(srcdir)/'`dns-cli.c +libmio_la-ecs.lo: ecs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmio_la-ecs.lo -MD -MP -MF $(DEPDIR)/libmio_la-ecs.Tpo -c -o libmio_la-ecs.lo `test -f 'ecs.c' || echo '$(srcdir)/'`ecs.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmio_la-ecs.Tpo $(DEPDIR)/libmio_la-ecs.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ecs.c' object='libmio_la-ecs.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmio_la-ecs.lo `test -f 'ecs.c' || echo '$(srcdir)/'`ecs.c + libmio_la-err.lo: err.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmio_la-err.lo -MD -MP -MF $(DEPDIR)/libmio_la-err.Tpo -c -o libmio_la-err.lo `test -f 'err.c' || echo '$(srcdir)/'`err.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmio_la-err.Tpo $(DEPDIR)/libmio_la-err.Plo @@ -607,6 +624,13 @@ libmio_la-fmt.lo: fmt.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmio_la-fmt.lo `test -f 'fmt.c' || echo '$(srcdir)/'`fmt.c +libmio_la-htb.lo: htb.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmio_la-htb.lo -MD -MP -MF $(DEPDIR)/libmio_la-htb.Tpo -c -o libmio_la-htb.lo `test -f 'htb.c' || echo '$(srcdir)/'`htb.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmio_la-htb.Tpo $(DEPDIR)/libmio_la-htb.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='htb.c' object='libmio_la-htb.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmio_la-htb.lo `test -f 'htb.c' || echo '$(srcdir)/'`htb.c + libmio_la-mio.lo: mio.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmio_la-mio.lo -MD -MP -MF $(DEPDIR)/libmio_la-mio.Tpo -c -o libmio_la-mio.lo `test -f 'mio.c' || echo '$(srcdir)/'`mio.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmio_la-mio.Tpo $(DEPDIR)/libmio_la-mio.Plo @@ -862,8 +886,10 @@ clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ distclean: distclean-am -rm -f ./$(DEPDIR)/libmio_la-dns-cli.Plo -rm -f ./$(DEPDIR)/libmio_la-dns.Plo + -rm -f ./$(DEPDIR)/libmio_la-ecs.Plo -rm -f ./$(DEPDIR)/libmio_la-err.Plo -rm -f ./$(DEPDIR)/libmio_la-fmt.Plo + -rm -f ./$(DEPDIR)/libmio_la-htb.Plo -rm -f ./$(DEPDIR)/libmio_la-mio.Plo -rm -f ./$(DEPDIR)/libmio_la-nwif.Plo -rm -f ./$(DEPDIR)/libmio_la-pro.Plo @@ -926,8 +952,10 @@ installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/libmio_la-dns-cli.Plo -rm -f ./$(DEPDIR)/libmio_la-dns.Plo + -rm -f ./$(DEPDIR)/libmio_la-ecs.Plo -rm -f ./$(DEPDIR)/libmio_la-err.Plo -rm -f ./$(DEPDIR)/libmio_la-fmt.Plo + -rm -f ./$(DEPDIR)/libmio_la-htb.Plo -rm -f ./$(DEPDIR)/libmio_la-mio.Plo -rm -f ./$(DEPDIR)/libmio_la-nwif.Plo -rm -f ./$(DEPDIR)/libmio_la-pro.Plo diff --git a/mio/lib/ecs-imp.h b/mio/lib/ecs-imp.h new file mode 100644 index 0000000..d1ec1d4 --- /dev/null +++ b/mio/lib/ecs-imp.h @@ -0,0 +1,453 @@ +/* + * $Id$ + * + Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +str_t* FN(open) (mio_t* gem, mio_oow_t xtnsize, mio_oow_t capa) +{ + str_t* str; + + str = (str_t*)mio_allocmem(gem, MIO_SIZEOF(str_t) + xtnsize); + if (str) + { + if (FN(init)(str, gem, capa) <= -1) + { + mio_freemem (gem, str); + str = MIO_NULL; + } + else + { + MIO_MEMSET (str + 1, 0, xtnsize); + } + } + return str; +} + +void FN(close) (str_t* str) +{ + FN(fini) (str); + mio_freemem (str->gem, str); +} + +int FN(init) (str_t* str, mio_t* gem, mio_oow_t capa) +{ + MIO_MEMSET (str, 0, MIO_SIZEOF(str_t)); + + str->gem = gem; + str->sizer = MIO_NULL; + + if (capa == 0) str->val.ptr = MIO_NULL; + else + { + str->val.ptr = (char_t*)mio_allocmem(gem, MIO_SIZEOF(char_t) * (capa + 1)); + if (!str->val.ptr) return -1; + str->val.ptr[0] = '\0'; + } + + str->val.len = 0; + str->capa = capa; + + return 0; +} + +void FN(fini) (str_t* str) +{ + if (str->val.ptr) mio_freemem (str->gem, str->val.ptr); +} + +int FN(yield) (str_t* str, cstr_t* buf, mio_oow_t newcapa) +{ + char_t* tmp; + + if (newcapa == 0) tmp = MIO_NULL; + else + { + tmp = (char_t*)mio_allocmem(str->gem, MIO_SIZEOF(char_t) * (newcapa + 1)); + if (!tmp) return -1; + tmp[0] = '\0'; + } + + if (buf) *buf = str->val; + + str->val.ptr = tmp; + str->val.len = 0; + str->capa = newcapa; + + return 0; +} + +char_t* FN(yieldptr) (str_t* str, mio_oow_t newcapa) +{ + cstr_t mx; + if (FN(yield)(str, &mx, newcapa) <= -1) return MIO_NULL; + return mx.ptr; +} + + +mio_oow_t FN(setcapa) (str_t* str, mio_oow_t capa) +{ + char_t* tmp; + + if (capa == str->capa) return capa; + + tmp = (char_t*)mio_reallocmem(str->gem, str->val.ptr, MIO_SIZEOF(char_t) * (capa+1)); + if (!tmp) return (mio_oow_t)-1; + + if (capa < str->val.len) + { + str->val.len = capa; + tmp[capa] = '\0'; + } + + str->capa = capa; + str->val.ptr = tmp; + + return str->capa; +} + +mio_oow_t FN(setlen) (str_t* str, mio_oow_t len) +{ + if (len == str->val.len) return len; + if (len < str->val.len) + { + str->val.len = len; + str->val.ptr[len] = '\0'; + return len; + } + + if (len > str->capa) + { + if (FN(setcapa)(str, len) == (mio_oow_t)-1) return (mio_oow_t)-1; + } + + while (str->val.len < len) str->val.ptr[str->val.len++] = ' '; + str->val.ptr[str->val.len] = '\0'; + return str->val.len; +} + +void FN(clear) (str_t* str) +{ + str->val.len = 0; + if (str->val.ptr) + { + MIO_ASSERT (str->gem, str->capa >= 1); + str->val.ptr[0] = '\0'; + } +} + +void FN(swap) (str_t* str, str_t* str1) +{ + str_t tmp; + + tmp.val.ptr = str->val.ptr; + tmp.val.len = str->val.len; + tmp.capa = str->capa; + tmp.gem = str->gem; + + str->val.ptr = str1->val.ptr; + str->val.len = str1->val.len; + str->capa = str1->capa; + str->gem = str1->gem; + + str1->val.ptr = tmp.val.ptr; + str1->val.len = tmp.val.len; + str1->capa = tmp.capa; + str1->gem = tmp.gem; +} + + +mio_oow_t FN(cpy) (str_t* str, const char_t* s) +{ + /* TODO: improve it */ + return FN(ncpy)(str, s, count_chars(s)); +} + +mio_oow_t FN(ncpy) (str_t* str, const char_t* s, mio_oow_t len) +{ + if (len > str->capa || str->capa <= 0) + { + mio_oow_t tmp; + + /* if the current capacity is 0 and the string len to copy is 0 + * we can't simply pass 'len' as the new capapcity. + * ecs_setcapa() won't do anything the current capacity of 0 + * is the same as new capacity required. note that when str->capa + * is 0, str->val.ptr is MIO_NULL. However, this is copying operation. + * Copying a zero-length string may indicate that str->val.ptr must + * not be MIO_NULL. so I simply pass 1 as the new capacity */ + tmp = FN(setcapa)(str, ((str->capa <= 0 && len <= 0)? 1: len)); + if (tmp == (mio_oow_t)-1) return (mio_oow_t)-1; + } + + MIO_MEMCPY (&str->val.ptr[0], s, len * MIO_SIZEOF(*s)); + str->val.ptr[len] = '\0'; + str->val.len = len; + return len; +} + +mio_oow_t FN(cat) (str_t* str, const char_t* s) +{ + /* TODO: improve it. no counting */ + return FN(ncat)(str, s, count_chars(s)); +} + +static int FN(resize_for_ncat) (str_t* str, mio_oow_t len) +{ + if (len > str->capa - str->val.len) + { + mio_oow_t ncapa, mincapa; + + /* let the minimum capacity be as large as + * to fit in the new substring */ + mincapa = str->val.len + len; + + if (!str->sizer) + { + /* increase the capacity by the length to add */ + ncapa = mincapa; + /* if the new capacity is less than the double, + * just double it */ + if (ncapa < str->capa * 2) ncapa = str->capa * 2; + } + else + { + /* let the user determine the new capacity. + * pass the minimum capacity required as a hint */ + ncapa = str->sizer(str, mincapa); + /* if no change in capacity, return current length */ + if (ncapa == str->capa) return 0; + } + + /* change the capacity */ + do + { + if (FN(setcapa)(str, ncapa) != (mio_oow_t)-1) break; + if (ncapa <= mincapa) return -1; + ncapa--; + } + while (1); + } + else if (str->capa <= 0 && len <= 0) + { + MIO_ASSERT (str->gem, str->val.ptr == MIO_NULL); + MIO_ASSERT (str->gem, str->val.len <= 0); + if (FN(setcapa)(str, 1) == (mio_oow_t)-1) return -1; + } + + return 1; +} + +mio_oow_t FN(ncat) (str_t* str, const char_t* s, mio_oow_t len) +{ + int n; + mio_oow_t i, j; + + n = FN(resize_for_ncat)(str, len); + if (n <= -1) return (mio_oow_t)-1; + if (n == 0) return str->val.len; + + if (len > str->capa - str->val.len) + { + /* copy as many characters as the number of cells available. + * if the capacity has been decreased, len is adjusted here */ + len = str->capa - str->val.len; + } + + /* + MIO_MEMCPY (&str->val.ptr[str->val.len], s, len*MIO_SIZEOF(*s)); + str->val.len += len; + str->val.ptr[str->val.len] = T('\0'); + */ + for (i = 0, j = str->val.len ; i < len; j++, i++) str->val.ptr[j] = s[i]; + str->val.ptr[j] = '\0'; + str->val.len = j; + + return str->val.len; +} + +mio_oow_t FN(nrcat) (str_t* str, const char_t* s, mio_oow_t len) +{ + int n; + mio_oow_t i, j; + + n = FN(resize_for_ncat)(str, len); + if (n <= -1) return (mio_oow_t)-1; + if (n == 0) return str->val.len; + + if (len > str->capa - str->val.len) len = str->capa - str->val.len; + + for (i = len, j = str->val.len ; i > 0; j++) str->val.ptr[j] = s[--i]; + str->val.ptr[j] = '\0'; + str->val.len = j; + + return str->val.len; +} + +mio_oow_t FN(ccat) (str_t* str, char_t c) +{ + return FN(ncat)(str, &c, 1); +} + +mio_oow_t FN(nccat) (str_t* str, char_t c, mio_oow_t len) +{ + while (len > 0) + { + if (FN(ncat)(str, &c, 1) == (mio_oow_t)-1) return (mio_oow_t)-1; + len--; + } + return str->val.len; +} + +mio_oow_t FN(del) (str_t* str, mio_oow_t index, mio_oow_t size) +{ + if (str->val.ptr && index < str->val.len && size > 0) + { + mio_oow_t nidx = index + size; + if (nidx >= str->val.len) + { + str->val.ptr[index] = '\0'; + str->val.len = index; + } + else + { + MIO_MEMMOVE (&str->val.ptr[index], &str->val.ptr[nidx], MIO_SIZEOF(*str->val.ptr) * (str->val.len - nidx + 1)); + str->val.len -= size; + } + } + + return str->val.len; +} + +mio_oow_t FN(amend) (str_t* str, mio_oow_t pos, mio_oow_t len, const char_t* repl) +{ + mio_oow_t max_len; + mio_oow_t repl_len = count_chars(repl); + + if (pos >= str->val.len) pos = str->val.len; + max_len = str->val.len - pos; + if (len > max_len) len = max_len; + + if (len > repl_len) + { + FN(del) (str, pos, len - repl_len); + } + else if (len < repl_len) + { + mio_oow_t old_ecs_len = str->val.len; + if (FN(setlen)(str, str->val.len + repl_len - len) == (mio_oow_t)-1) return (mio_oow_t)-1; + MIO_MEMMOVE (&str->val.ptr[pos + repl_len], &str->val.ptr[pos + len], MIO_SIZEOF(*repl) * (old_ecs_len - (pos + len))); + } + + if (repl_len > 0) MIO_MEMMOVE (&str->val.ptr[pos], repl, MIO_SIZEOF(*repl) * repl_len); + return str->val.len; +} + +#if 0 +static int FN(put_bchars) (mio_fmtout_t* fmtout, const mio_bch_t* ptr, mio_oow_t len) +{ +#if defined(BUILD_UECS) + mio_uecs_t* uecs = (mio_uecs_t*)fmtout->ctx; + if (mio_uecs_ncatbchars(uecs, ptr, len, uecs->gem->cmgr, 1) == (mio_oow_t)-1) return -1; +#else + mio_becs_t* becs = (mio_becs_t*)fmtout->ctx; + if (mio_becs_ncat(becs, ptr, len) == (mio_oow_t)-1) return -1; +#endif + return 1; /* success. carry on */ +} + +static int FN(put_uchars) (mio_fmtout_t* fmtout, const mio_uch_t* ptr, mio_oow_t len) +{ +#if defined(BUILD_UECS) + mio_uecs_t* uecs = (mio_uecs_t*)fmtout->ctx; + if (mio_uecs_ncat(uecs, ptr, len) == (mio_oow_t)-1) return -1; +#else + mio_becs_t* becs = (mio_becs_t*)fmtout->ctx; + if (mio_becs_ncatuchars(becs, ptr, len, becs->gem->cmgr) == (mio_oow_t)-1) return -1; +#endif + return 1; /* success. carry on */ +} + +mio_oow_t FN(vfcat) (str_t* str, const char_t* fmt, va_list ap) +{ + mio_fmtout_t fo; + + MIO_MEMSET (&fo, 0, MIO_SIZEOF(fo)); + fo.mmgr = str->gem->mmgr; + fo.putbchars = FN(put_bchars); + fo.putuchars = FN(put_uchars); + fo.ctx = str; + +#if defined(BUILD_UECS) + if (mio_ufmt_outv(&fo, fmt, ap) <= -1) return -1; +#else + if (mio_bfmt_outv(&fo, fmt, ap) <= -1) return -1; +#endif + return str->val.len; +} + +mio_oow_t FN(fcat) (str_t* str, const char_t* fmt, ...) +{ + mio_oow_t x; + va_list ap; + + va_start (ap, fmt); + x = FN(vfcat)(str, fmt, ap); + va_end (ap); + + return x; +} + +mio_oow_t FN(vfmt) (str_t* str, const char_t* fmt, va_list ap) +{ + mio_fmtout_t fo; + + MIO_MEMSET (&fo, 0, MIO_SIZEOF(fo)); + fo.mmgr = str->gem->mmgr; + fo.putbchars = FN(put_bchars); + fo.putuchars = FN(put_uchars); + fo.ctx = str; + + FN(clear) (str); + +#if defined(BUILD_UECS) + if (mio_ufmt_outv(&fo, fmt, ap) <= -1) return -1; +#else + if (mio_bfmt_outv(&fo, fmt, ap) <= -1) return -1; +#endif + return str->val.len; +} + +mio_oow_t FN(fmt) (str_t* str, const char_t* fmt, ...) +{ + mio_oow_t x; + va_list ap; + + va_start (ap, fmt); + x = FN(vfmt)(str, fmt, ap); + va_end (ap); + + return x; +} +#endif diff --git a/mio/lib/ecs.c b/mio/lib/ecs.c new file mode 100644 index 0000000..1b53777 --- /dev/null +++ b/mio/lib/ecs.c @@ -0,0 +1,103 @@ +/* + * $Id$ + * + Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mio-ecs.h" +#include "mio-prv.h" + +#define _FN(type,verb) mio_ ## type ## _ ## verb + +/* ------------------------------------------------------------------------- */ + +#undef FN +#undef T +#undef str_t +#undef char_t +#undef cstr_t +#undef count_chars +#define FN(verb) _FN(becs,verb) +#define T(x) MIO_BT(x) +#define str_t mio_becs_t +#define char_t mio_bch_t +#define cstr_t mio_bcs_t +#define count_chars(x) mio_count_bcstr(x) +#define BUILD_BECS +#include "ecs-imp.h" + +/* ------------------------------------------------------------------------- */ + +#undef FN +#undef T +#undef str_t +#undef char_t +#undef cstr_t +#undef count_chars +#define FN(verb) _FN(uecs,verb) +#define T(x) MIO_UT(x) +#define str_t mio_uecs_t +#define char_t mio_uch_t +#define cstr_t mio_ucs_t +#define count_chars(x) mio_count_ucstr(x) +#define BUILD_UECS +#include "ecs-imp.h" + +/* ------------------------------------------------------------------------- */ + + +mio_oow_t mio_becs_ncatuchars (mio_becs_t* str, const mio_uch_t* s, mio_oow_t len, mio_cmgr_t* cmgr) +{ + mio_oow_t bcslen, ucslen; + + ucslen = len; + if (mio_conv_uchars_to_bchars_with_cmgr(s, &ucslen, MIO_NULL, &bcslen, cmgr) <= -1) return (mio_oow_t)-1; + + if (mio_becs_resize_for_ncat(str, bcslen) <= 0) return -1; + + ucslen = len; + bcslen = str->capa - str->val.len; + mio_conv_uchars_to_bchars_with_cmgr (s, &ucslen, &str->val.ptr[str->val.len], &bcslen, cmgr); + str->val.len += bcslen; + str->val.ptr[str->val.len] = '\0'; + + return str->val.len; +} + +mio_oow_t mio_uecs_ncatbchars (mio_uecs_t* str, const mio_bch_t* s, mio_oow_t len, mio_cmgr_t* cmgr, int all) +{ + mio_oow_t bcslen, ucslen; + + bcslen = len; + if (mio_conv_bchars_to_uchars_with_cmgr(s, &bcslen, MIO_NULL, &ucslen, cmgr, all) <= -1) return (mio_oow_t)-1; + + if (mio_uecs_resize_for_ncat(str, ucslen) <= 0) return -1; + + bcslen = len; + ucslen = str->capa - str->val.len; + mio_conv_bchars_to_uchars_with_cmgr (s, &bcslen, &str->val.ptr[str->val.len], &ucslen, cmgr, all); + str->val.len += ucslen; + str->val.ptr[str->val.len] = '\0'; + + return str->val.len; +} diff --git a/mio/lib/htb.c b/mio/lib/htb.c new file mode 100644 index 0000000..0515679 --- /dev/null +++ b/mio/lib/htb.c @@ -0,0 +1,732 @@ +/* + * $Id$ + * + Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "mio-prv.h" + +#define pair_t mio_htb_pair_t +#define copier_t mio_htb_copier_t +#define freeer_t mio_htb_freeer_t +#define hasher_t mio_htb_hasher_t +#define comper_t mio_htb_comper_t +#define keeper_t mio_htb_keeper_t +#define sizer_t mio_htb_sizer_t +#define walker_t mio_htb_walker_t +#define cbserter_t mio_htb_cbserter_t +#define style_t mio_htb_style_t +#define style_kind_t mio_htb_style_kind_t + +#define KPTR(p) MIO_HTB_KPTR(p) +#define KLEN(p) MIO_HTB_KLEN(p) +#define VPTR(p) MIO_HTB_VPTR(p) +#define VLEN(p) MIO_HTB_VLEN(p) +#define NEXT(p) MIO_HTB_NEXT(p) + +#define KTOB(htb,len) ((len)*(htb)->scale[MIO_HTB_KEY]) +#define VTOB(htb,len) ((len)*(htb)->scale[MIO_HTB_VAL]) + +MIO_INLINE pair_t* mio_htb_allocpair (mio_htb_t* htb, void* kptr, mio_oow_t klen, void* vptr, mio_oow_t vlen) +{ + pair_t* n; + copier_t kcop, vcop; + mio_oow_t as; + + kcop = htb->style->copier[MIO_HTB_KEY]; + vcop = htb->style->copier[MIO_HTB_VAL]; + + as = MIO_SIZEOF(pair_t); + if (kcop == MIO_HTB_COPIER_INLINE) as += MIO_ALIGN_POW2(KTOB(htb,klen), MIO_SIZEOF_VOID_P); + if (vcop == MIO_HTB_COPIER_INLINE) as += VTOB(htb,vlen); + + n = (pair_t*) mio_allocmem(htb->mio, as); + if (MIO_UNLIKELY(!n)) return MIO_NULL; + + NEXT(n) = MIO_NULL; + + KLEN(n) = klen; + if (kcop == MIO_HTB_COPIER_SIMPLE) + { + KPTR(n) = kptr; + } + else if (kcop == MIO_HTB_COPIER_INLINE) + { + KPTR(n) = n + 1; + /* if kptr is MIO_NULL, the inline copier does not fill + * the actual key area */ + if (kptr) MIO_MEMCPY (KPTR(n), kptr, KTOB(htb,klen)); + } + else + { + KPTR(n) = kcop(htb, kptr, klen); + if (KPTR(n) == MIO_NULL) + { + mio_freemem (htb->mio, n); + return MIO_NULL; + } + } + + VLEN(n) = vlen; + if (vcop == MIO_HTB_COPIER_SIMPLE) + { + VPTR(n) = vptr; + } + else if (vcop == MIO_HTB_COPIER_INLINE) + { + VPTR(n) = n + 1; + if (kcop == MIO_HTB_COPIER_INLINE) + VPTR(n) = (mio_uint8_t*)VPTR(n) + MIO_ALIGN_POW2(KTOB(htb,klen), MIO_SIZEOF_VOID_P); + /* if vptr is MIO_NULL, the inline copier does not fill + * the actual value area */ + if (vptr) MIO_MEMCPY (VPTR(n), vptr, VTOB(htb,vlen)); + } + else + { + VPTR(n) = vcop (htb, vptr, vlen); + if (VPTR(n) != MIO_NULL) + { + if (htb->style->freeer[MIO_HTB_KEY] != MIO_NULL) + htb->style->freeer[MIO_HTB_KEY] (htb, KPTR(n), KLEN(n)); + mio_freemem (htb->mio, n); + return MIO_NULL; + } + } + + return n; +} + +MIO_INLINE void mio_htb_freepair (mio_htb_t* htb, pair_t* pair) +{ + if (htb->style->freeer[MIO_HTB_KEY] != MIO_NULL) + htb->style->freeer[MIO_HTB_KEY] (htb, KPTR(pair), KLEN(pair)); + if (htb->style->freeer[MIO_HTB_VAL] != MIO_NULL) + htb->style->freeer[MIO_HTB_VAL] (htb, VPTR(pair), VLEN(pair)); + mio_freemem (htb->mio, pair); +} + +static MIO_INLINE pair_t* change_pair_val (mio_htb_t* htb, pair_t* pair, void* vptr, mio_oow_t vlen) +{ + if (VPTR(pair) == vptr && VLEN(pair) == vlen) + { + /* if the old value and the new value are the same, + * it just calls the handler for this condition. + * No value replacement occurs. */ + if (htb->style->keeper != MIO_NULL) + { + htb->style->keeper (htb, vptr, vlen); + } + } + else + { + copier_t vcop = htb->style->copier[MIO_HTB_VAL]; + void* ovptr = VPTR(pair); + mio_oow_t ovlen = VLEN(pair); + + /* place the new value according to the copier */ + if (vcop == MIO_HTB_COPIER_SIMPLE) + { + VPTR(pair) = vptr; + VLEN(pair) = vlen; + } + else if (vcop == MIO_HTB_COPIER_INLINE) + { + if (ovlen == vlen) + { + if (vptr) MIO_MEMCPY (VPTR(pair), vptr, VTOB(htb,vlen)); + } + else + { + /* need to reconstruct the pair */ + pair_t* p = mio_htb_allocpair(htb, KPTR(pair), KLEN(pair), vptr, vlen); + if (MIO_UNLIKELY(!p)) return MIO_NULL; + mio_htb_freepair (htb, pair); + return p; + } + } + else + { + void* nvptr = vcop(htb, vptr, vlen); + if (MIO_UNLIKELY(!nvptr)) return MIO_NULL; + VPTR(pair) = nvptr; + VLEN(pair) = vlen; + } + + /* free up the old value */ + if (htb->style->freeer[MIO_HTB_VAL] != MIO_NULL) + { + htb->style->freeer[MIO_HTB_VAL] (htb, ovptr, ovlen); + } + } + + return pair; +} + +static style_t style[] = +{ + /* == MIO_HTB_STYLE_DEFAULT == */ + { + { + MIO_HTB_COPIER_DEFAULT, + MIO_HTB_COPIER_DEFAULT + }, + { + MIO_HTB_FREEER_DEFAULT, + MIO_HTB_FREEER_DEFAULT + }, + MIO_HTB_COMPER_DEFAULT, + MIO_HTB_KEEPER_DEFAULT, + MIO_HTB_SIZER_DEFAULT, + MIO_HTB_HASHER_DEFAULT + }, + + /* == MIO_HTB_STYLE_INLINE_COPIERS == */ + { + { + MIO_HTB_COPIER_INLINE, + MIO_HTB_COPIER_INLINE + }, + { + MIO_HTB_FREEER_DEFAULT, + MIO_HTB_FREEER_DEFAULT + }, + MIO_HTB_COMPER_DEFAULT, + MIO_HTB_KEEPER_DEFAULT, + MIO_HTB_SIZER_DEFAULT, + MIO_HTB_HASHER_DEFAULT + }, + + /* == MIO_HTB_STYLE_INLINE_KEY_COPIER == */ + { + { + MIO_HTB_COPIER_INLINE, + MIO_HTB_COPIER_DEFAULT + }, + { + MIO_HTB_FREEER_DEFAULT, + MIO_HTB_FREEER_DEFAULT + }, + MIO_HTB_COMPER_DEFAULT, + MIO_HTB_KEEPER_DEFAULT, + MIO_HTB_SIZER_DEFAULT, + MIO_HTB_HASHER_DEFAULT + }, + + /* == MIO_HTB_STYLE_INLINE_VALUE_COPIER == */ + { + { + MIO_HTB_COPIER_DEFAULT, + MIO_HTB_COPIER_INLINE + }, + { + MIO_HTB_FREEER_DEFAULT, + MIO_HTB_FREEER_DEFAULT + }, + MIO_HTB_COMPER_DEFAULT, + MIO_HTB_KEEPER_DEFAULT, + MIO_HTB_SIZER_DEFAULT, + MIO_HTB_HASHER_DEFAULT + } +}; + +const style_t* mio_get_htb_style (style_kind_t kind) +{ + return &style[kind]; +} + +mio_htb_t* mio_htb_open (mio_t* mio, mio_oow_t xtnsize, mio_oow_t capa, int factor, int kscale, int vscale) +{ + mio_htb_t* htb; + + htb = (mio_htb_t*)mio_allocmem(mio, MIO_SIZEOF(mio_htb_t) + xtnsize); + if (MIO_UNLIKELY(!htb)) return MIO_NULL; + + if (mio_htb_init(htb, mio, capa, factor, kscale, vscale) <= -1) + { + mio_freemem (mio, htb); + return MIO_NULL; + } + + MIO_MEMSET (htb + 1, 0, xtnsize); + return htb; +} + +void mio_htb_close (mio_htb_t* htb) +{ + mio_htb_fini (htb); + mio_freemem (htb->mio, htb); +} + +int mio_htb_init (mio_htb_t* htb, mio_t* mio, mio_oow_t capa, int factor, int kscale, int vscale) +{ + /* The initial capacity should be greater than 0. + * Otherwise, it is adjusted to 1 in the release mode */ + MIO_ASSERT (mio, capa > 0); + + /* The load factor should be between 0 and 100 inclusive. + * In the release mode, a value out of the range is adjusted to 100 */ + MIO_ASSERT (mio, factor >= 0 && factor <= 100); + + MIO_ASSERT (mio, kscale >= 0 && kscale <= MIO_TYPE_MAX(mio_uint8_t)); + MIO_ASSERT (mio, vscale >= 0 && vscale <= MIO_TYPE_MAX(mio_uint8_t)); + + /* some initial adjustment */ + if (capa <= 0) capa = 1; + if (factor > 100) factor = 100; + + /* do not zero out the extension */ + MIO_MEMSET (htb, 0, MIO_SIZEOF(*htb)); + htb->mio = mio; + + htb->bucket = mio_allocmem(mio, capa * MIO_SIZEOF(pair_t*)); + if (MIO_UNLIKELY(!htb->bucket)) return -1; + + /*for (i = 0; i < capa; i++) htb->bucket[i] = MIO_NULL;*/ + MIO_MEMSET (htb->bucket, 0, capa * MIO_SIZEOF(pair_t*)); + + htb->factor = factor; + htb->scale[MIO_HTB_KEY] = (kscale < 1)? 1: kscale; + htb->scale[MIO_HTB_VAL] = (vscale < 1)? 1: vscale; + + htb->size = 0; + htb->capa = capa; + htb->threshold = htb->capa * htb->factor / 100; + if (htb->capa > 0 && htb->threshold <= 0) htb->threshold = 1; + + htb->style = &style[0]; + return 0; +} + +void mio_htb_fini (mio_htb_t* htb) +{ + mio_htb_clear (htb); + mio_freemem (htb->mio, htb->bucket); +} + +const style_t* mio_htb_getstyle (const mio_htb_t* htb) +{ + return htb->style; +} + +void mio_htb_setstyle (mio_htb_t* htb, const style_t* style) +{ + MIO_ASSERT (htb->mio, style != MIO_NULL); + htb->style = style; +} + +mio_oow_t mio_htb_getsize (const mio_htb_t* htb) +{ + return htb->size; +} + +mio_oow_t mio_htb_getcapa (const mio_htb_t* htb) +{ + return htb->capa; +} + +pair_t* mio_htb_search (const mio_htb_t* htb, const void* kptr, mio_oow_t klen) +{ + pair_t* pair; + mio_oow_t hc; + + hc = htb->style->hasher(htb,kptr,klen) % htb->capa; + pair = htb->bucket[hc]; + + while (pair != MIO_NULL) + { + if (htb->style->comper(htb, KPTR(pair), KLEN(pair), kptr, klen) == 0) + { + return pair; + } + + pair = NEXT(pair); + } + + mio_seterrnum (htb->mio, MIO_ENOENT); + return MIO_NULL; +} + +static MIO_INLINE int reorganize (mio_htb_t* htb) +{ + mio_oow_t i, hc, new_capa; + pair_t** new_buck; + + if (htb->style->sizer) + { + new_capa = htb->style->sizer (htb, htb->capa + 1); + + /* if no change in capacity, return success + * without reorganization */ + if (new_capa == htb->capa) return 0; + + /* adjust to 1 if the new capacity is not reasonable */ + if (new_capa <= 0) new_capa = 1; + } + else + { + /* the bucket is doubled until it grows up to 65536 slots. + * once it has reached it, it grows by 65536 slots */ + new_capa = (htb->capa >= 65536)? (htb->capa + 65536): (htb->capa << 1); + } + + new_buck = (pair_t**)mio_allocmem(htb->mio, new_capa * MIO_SIZEOF(pair_t*)); + if (MIO_UNLIKELY(!new_buck)) + { + /* reorganization is disabled once it fails */ + htb->threshold = 0; + return -1; + } + + /*for (i = 0; i < new_capa; i++) new_buck[i] = MIO_NULL;*/ + MIO_MEMSET (new_buck, 0, new_capa * MIO_SIZEOF(pair_t*)); + + for (i = 0; i < htb->capa; i++) + { + pair_t* pair = htb->bucket[i]; + + while (pair != MIO_NULL) + { + pair_t* next = NEXT(pair); + + hc = htb->style->hasher(htb, KPTR(pair), KLEN(pair)) % new_capa; + + NEXT(pair) = new_buck[hc]; + new_buck[hc] = pair; + + pair = next; + } + } + + mio_freemem (htb->mio, htb->bucket); + htb->bucket = new_buck; + htb->capa = new_capa; + htb->threshold = htb->capa * htb->factor / 100; + + return 0; +} + +/* insert options */ +#define UPSERT 1 +#define UPDATE 2 +#define ENSERT 3 +#define INSERT 4 + +static MIO_INLINE pair_t* insert (mio_htb_t* htb, void* kptr, mio_oow_t klen, void* vptr, mio_oow_t vlen, int opt) +{ + pair_t* pair, * p, * prev, * next; + mio_oow_t hc; + + hc = htb->style->hasher(htb,kptr,klen) % htb->capa; + pair = htb->bucket[hc]; + prev = MIO_NULL; + + while (pair != MIO_NULL) + { + next = NEXT(pair); + + if (htb->style->comper (htb, KPTR(pair), KLEN(pair), kptr, klen) == 0) + { + /* found a pair with a matching key */ + switch (opt) + { + case UPSERT: + case UPDATE: + p = change_pair_val (htb, pair, vptr, vlen); + if (p == MIO_NULL) + { + /* error in changing the value */ + return MIO_NULL; + } + if (p != pair) + { + /* old pair destroyed. new pair reallocated. + * relink to include the new pair but to drop + * the old pair. */ + if (prev == MIO_NULL) htb->bucket[hc] = p; + else NEXT(prev) = p; + NEXT(p) = next; + } + return p; + + case ENSERT: + /* return existing pair */ + return pair; + + case INSERT: + /* return failure */ + mio_seterrnum (htb->mio, MIO_EEXIST); + return MIO_NULL; + } + } + + prev = pair; + pair = next; + } + + if (opt == UPDATE) + { + mio_seterrnum (htb->mio, MIO_ENOENT); + return MIO_NULL; + } + + if (htb->threshold > 0 && htb->size >= htb->threshold) + { + /* ingore reorganization error as it simply means + * more bucket collision and performance penalty. */ + if (reorganize(htb) == 0) + { + hc = htb->style->hasher(htb,kptr,klen) % htb->capa; + } + } + + MIO_ASSERT (htb->mio, pair == MIO_NULL); + + pair = mio_htb_allocpair (htb, kptr, klen, vptr, vlen); + if (MIO_UNLIKELY(!pair)) return MIO_NULL; /* error */ + + NEXT(pair) = htb->bucket[hc]; + htb->bucket[hc] = pair; + htb->size++; + + return pair; /* new key added */ +} + +pair_t* mio_htb_upsert (mio_htb_t* htb, void* kptr, mio_oow_t klen, void* vptr, mio_oow_t vlen) +{ + return insert (htb, kptr, klen, vptr, vlen, UPSERT); +} + +pair_t* mio_htb_ensert (mio_htb_t* htb, void* kptr, mio_oow_t klen, void* vptr, mio_oow_t vlen) +{ + return insert (htb, kptr, klen, vptr, vlen, ENSERT); +} + +pair_t* mio_htb_insert (mio_htb_t* htb, void* kptr, mio_oow_t klen, void* vptr, mio_oow_t vlen) +{ + return insert (htb, kptr, klen, vptr, vlen, INSERT); +} + + +pair_t* mio_htb_update (mio_htb_t* htb, void* kptr, mio_oow_t klen, void* vptr, mio_oow_t vlen) +{ + return insert (htb, kptr, klen, vptr, vlen, UPDATE); +} + +pair_t* mio_htb_cbsert (mio_htb_t* htb, void* kptr, mio_oow_t klen, cbserter_t cbserter, void* ctx) +{ + pair_t* pair, * p, * prev, * next; + mio_oow_t hc; + + hc = htb->style->hasher(htb,kptr,klen) % htb->capa; + pair = htb->bucket[hc]; + prev = MIO_NULL; + + while (pair != MIO_NULL) + { + next = NEXT(pair); + + if (htb->style->comper(htb, KPTR(pair), KLEN(pair), kptr, klen) == 0) + { + /* found a pair with a matching key */ + p = cbserter(htb, pair, kptr, klen, ctx); + if (p == MIO_NULL) + { + /* error returned by the callback function */ + return MIO_NULL; + } + if (p != pair) + { + /* old pair destroyed. new pair reallocated. + * relink to include the new pair but to drop + * the old pair. */ + if (prev == MIO_NULL) htb->bucket[hc] = p; + else NEXT(prev) = p; + NEXT(p) = next; + } + return p; + } + + prev = pair; + pair = next; + } + + if (htb->threshold > 0 && htb->size >= htb->threshold) + { + /* ingore reorganization error as it simply means + * more bucket collision and performance penalty. */ + if (reorganize(htb) == 0) + { + hc = htb->style->hasher(htb,kptr,klen) % htb->capa; + } + } + + MIO_ASSERT (htb->mio, pair == MIO_NULL); + + pair = cbserter(htb, MIO_NULL, kptr, klen, ctx); + if (MIO_UNLIKELY(!pair)) return MIO_NULL; /* error */ + + NEXT(pair) = htb->bucket[hc]; + htb->bucket[hc] = pair; + htb->size++; + + return pair; /* new key added */ +} + +int mio_htb_delete (mio_htb_t* htb, const void* kptr, mio_oow_t klen) +{ + pair_t* pair, * prev; + mio_oow_t hc; + + hc = htb->style->hasher(htb,kptr,klen) % htb->capa; + pair = htb->bucket[hc]; + prev = MIO_NULL; + + while (pair != MIO_NULL) + { + if (htb->style->comper(htb, KPTR(pair), KLEN(pair), kptr, klen) == 0) + { + if (prev == MIO_NULL) + htb->bucket[hc] = NEXT(pair); + else NEXT(prev) = NEXT(pair); + + mio_htb_freepair (htb, pair); + htb->size--; + + return 0; + } + + prev = pair; + pair = NEXT(pair); + } + + mio_seterrnum (htb->mio, MIO_ENOENT); + return -1; +} + +void mio_htb_clear (mio_htb_t* htb) +{ + mio_oow_t i; + pair_t* pair, * next; + + for (i = 0; i < htb->capa; i++) + { + pair = htb->bucket[i]; + + while (pair != MIO_NULL) + { + next = NEXT(pair); + mio_htb_freepair (htb, pair); + htb->size--; + pair = next; + } + + htb->bucket[i] = MIO_NULL; + } +} + +void mio_htb_walk (mio_htb_t* htb, walker_t walker, void* ctx) +{ + mio_oow_t i; + pair_t* pair, * next; + + for (i = 0; i < htb->capa; i++) + { + pair = htb->bucket[i]; + + while (pair != MIO_NULL) + { + next = NEXT(pair); + if (walker(htb, pair, ctx) == MIO_HTB_WALK_STOP) return; + pair = next; + } + } +} + + +void mio_init_htb_itr (mio_htb_itr_t* itr) +{ + itr->pair = MIO_NULL; + itr->buckno = 0; +} + +pair_t* mio_htb_getfirstpair (mio_htb_t* htb, mio_htb_itr_t* itr) +{ + mio_oow_t i; + pair_t* pair; + + for (i = 0; i < htb->capa; i++) + { + pair = htb->bucket[i]; + if (pair) + { + itr->buckno = i; + itr->pair = pair; + return pair; + } + } + + return MIO_NULL; +} + +pair_t* mio_htb_getnextpair (mio_htb_t* htb, mio_htb_itr_t* itr) +{ + mio_oow_t i; + pair_t* pair; + + pair = NEXT(itr->pair); + if (pair) + { + /* no change in bucket number */ + itr->pair = pair; + return pair; + } + + for (i = itr->buckno + 1; i < htb->capa; i++) + { + pair = htb->bucket[i]; + if (pair) + { + itr->buckno = i; + itr->pair = pair; + return pair; + } + } + + return MIO_NULL; +} + +mio_oow_t mio_htb_dflhash (const mio_htb_t* htb, const void* kptr, mio_oow_t klen) +{ + mio_oow_t h; + MIO_HASH_BYTES (h, kptr, klen); + return h ; +} + +int mio_htb_dflcomp (const mio_htb_t* htb, const void* kptr1, mio_oow_t klen1, const void* kptr2, mio_oow_t klen2) +{ + if (klen1 == klen2) return MIO_MEMCMP (kptr1, kptr2, KTOB(htb,klen1)); + /* it just returns 1 to indicate that they are different. */ + return 1; +} + diff --git a/mio/lib/htrd.c b/mio/lib/htrd.c index 10e5559..76aafc2 100644 --- a/mio/lib/htrd.c +++ b/mio/lib/htrd.c @@ -88,9 +88,9 @@ static MIO_INLINE int xdigit_to_num (mio_bch_t c) } -static MIO_INLINE int push_to_buffer (mio_htrd_t* htrd, mio_htob_t* octb, const mio_bch_t* ptr, mio_size_t len) +static MIO_INLINE int push_to_buffer (mio_htrd_t* htrd, mio_htob_t* octb, const mio_bch_t* ptr, mio_oow_t len) { - if (mio_mbs_ncat (octb, ptr, len) == (mio_size_t)-1) + if (mio_mbs_ncat (octb, ptr, len) == (mio_oow_t)-1) { htrd->errnum = MIO_HTRD_ENOMEM; return -1; @@ -98,7 +98,7 @@ static MIO_INLINE int push_to_buffer (mio_htrd_t* htrd, mio_htob_t* octb, const return 0; } -static MIO_INLINE int push_content (mio_htrd_t* htrd, const mio_bch_t* ptr, mio_size_t len) +static MIO_INLINE int push_content (mio_htrd_t* htrd, const mio_bch_t* ptr, mio_oow_t len) { MIO_ASSERT (len > 0); @@ -126,7 +126,7 @@ static MIO_INLINE void clear_feed (mio_htrd_t* htrd) MIO_MEMSET (&htrd->fed.s, 0, MIO_SIZEOF(htrd->fed.s)); } -mio_htrd_t* mio_htrd_open (mio_mmgr_t* mmgr, mio_size_t xtnsize) +mio_htrd_t* mio_htrd_open (mio_mmgr_t* mmgr, mio_oow_t xtnsize) { mio_htrd_t* htrd; @@ -558,7 +558,7 @@ static int capture_connection (mio_htrd_t* htrd, mio_htb_pair_t* pair) static int capture_content_length (mio_htrd_t* htrd, mio_htb_pair_t* pair) { - mio_size_t len = 0, off = 0, tmp; + mio_oow_t len = 0, off = 0, tmp; const mio_bch_t* ptr; mio_htre_hdrval_t* val; @@ -671,7 +671,7 @@ static MIO_INLINE int capture_key_header (mio_htrd_t* htrd, mio_htb_pair_t* pair static struct { const mio_bch_t* ptr; - mio_size_t len; + mio_oow_t len; int (*handler) (mio_htrd_t*, mio_htb_pair_t*); } hdrtab[] = { @@ -683,7 +683,7 @@ static MIO_INLINE int capture_key_header (mio_htrd_t* htrd, mio_htb_pair_t* pair }; int n; - mio_size_t mid, count, base = 0; + mio_oow_t mid, count, base = 0; /* perform binary search */ for (count = MIO_COUNTOF(hdrtab); count > 0; count /= 2) @@ -712,12 +712,12 @@ struct hdr_cbserter_ctx_t { mio_htrd_t* htrd; void* vptr; - mio_size_t vlen; + mio_oow_t vlen; }; static mio_htb_pair_t* hdr_cbserter ( mio_htb_t* htb, mio_htb_pair_t* pair, - void* kptr, mio_size_t klen, void* ctx) + void* kptr, mio_oow_t klen, void* ctx) { struct hdr_cbserter_ctx_t* tx = (struct hdr_cbserter_ctx_t*)ctx; @@ -824,7 +824,7 @@ mio_bch_t* parse_header_field (mio_htrd_t* htrd, mio_bch_t* line, mio_htb_t* tab struct { mio_bch_t* ptr; - mio_size_t len; + mio_oow_t len; } name, value; #if 0 @@ -928,7 +928,7 @@ badhdr: } static MIO_INLINE int parse_initial_line_and_headers ( - mio_htrd_t* htrd, const mio_bch_t* req, mio_size_t rlen) + mio_htrd_t* htrd, const mio_bch_t* req, mio_oow_t rlen) { mio_bch_t* p; @@ -980,7 +980,7 @@ static MIO_INLINE int parse_initial_line_and_headers ( #define GET_CHUNK_CRLF 3 #define GET_CHUNK_TRAILERS 4 -static const mio_bch_t* getchunklen (mio_htrd_t* htrd, const mio_bch_t* ptr, mio_size_t len) +static const mio_bch_t* getchunklen (mio_htrd_t* htrd, const mio_bch_t* ptr, mio_oow_t len) { const mio_bch_t* end = ptr + len; @@ -1122,12 +1122,12 @@ done: } /* feed the percent encoded string */ -int mio_htrd_feed (mio_htrd_t* htrd, const mio_bch_t* req, mio_size_t len) +int mio_htrd_feed (mio_htrd_t* htrd, const mio_bch_t* req, mio_oow_t len) { const mio_bch_t* end = req + len; const mio_bch_t* ptr = req; int header_completed_during_this_feed = 0; - mio_size_t avail; + mio_oow_t avail; MIO_ASSERT (len > 0); diff --git a/mio/lib/htre.c b/mio/lib/htre.c index a535d57..bd2287c 100644 --- a/mio/lib/htre.c +++ b/mio/lib/htre.c @@ -27,7 +27,7 @@ #include #include "mio-prv.h" -static void free_hdrval (mio_htb_t* htb, void* vptr, mio_size_t vlen) +static void free_hdrval (mio_htb_t* htb, void* vptr, mio_oow_t vlen) { mio_htre_hdrval_t* val; mio_htre_hdrval_t* tmp; @@ -37,11 +37,11 @@ static void free_hdrval (mio_htb_t* htb, void* vptr, mio_size_t vlen) { tmp = val; val = val->next; - MIO_MMGR_FREE (htb->mmgr, tmp); + mio_freemem (htb->mio, tmp); } } -int mio_htre_init (mio_htre_t* re, mio_mmgr_t* mmgr) +int mio_htre_init (mio_htre_t* re, mio_t* mio) { static mio_htb_style_t style = { @@ -60,17 +60,17 @@ int mio_htre_init (mio_htre_t* re, mio_mmgr_t* mmgr) }; MIO_MEMSET (re, 0, MIO_SIZEOF(*re)); - re->mmgr = mmgr; + re->mio = mio; - if (mio_htb_init (&re->hdrtab, mmgr, 60, 70, 1, 1) <= -1) return -1; - if (mio_htb_init (&re->trailers, mmgr, 20, 70, 1, 1) <= -1) return -1; + if (mio_htb_init(&re->hdrtab, mio, 60, 70, 1, 1) <= -1) return -1; + if (mio_htb_init(&re->trailers, mio, 20, 70, 1, 1) <= -1) return -1; mio_htb_setstyle (&re->hdrtab, &style); mio_htb_setstyle (&re->trailers, &style); - mio_mbs_init (&re->content, mmgr, 0); + mio_becs_init (&re->content, mio, 0); #if 0 - mio_mbs_init (&re->iniline, mmgr, 0); + mio_becs_init (&re->iniline, mio, 0); #endif return 0; @@ -79,14 +79,13 @@ int mio_htre_init (mio_htre_t* re, mio_mmgr_t* mmgr) void mio_htre_fini (mio_htre_t* re) { #if 0 - mio_mbs_fini (&re->iniline); + mio_becs_fini (&re->iniline); #endif - mio_mbs_fini (&re->content); + mio_becs_fini (&re->content); mio_htb_fini (&re->trailers); mio_htb_fini (&re->hdrtab); - if (re->orgqpath.buf) - MIO_MMGR_FREE (re->mmgr, re->orgqpath.buf); + if (re->orgqpath.buf) mio_freemem (re->mio, re->orgqpath.buf); } void mio_htre_clear (mio_htre_t* re) @@ -113,26 +112,24 @@ void mio_htre_clear (mio_htre_t* re) mio_htb_clear (&re->hdrtab); mio_htb_clear (&re->trailers); - mio_mbs_clear (&re->content); + mio_becs_clear (&re->content); #if 0 - mio_mbs_clear (&re->iniline); + mio_becs_clear (&re->iniline); #endif } -const mio_htre_hdrval_t* mio_htre_getheaderval ( - const mio_htre_t* re, const mio_mchar_t* name) +const mio_htre_hdrval_t* mio_htre_getheaderval (const mio_htre_t* re, const mio_bch_t* name) { mio_htb_pair_t* pair; - pair = mio_htb_search (&re->hdrtab, name, mio_mbslen(name)); + pair = mio_htb_search(&re->hdrtab, name, mio_count_bcstr(name)); if (pair == MIO_NULL) return MIO_NULL; return MIO_HTB_VPTR(pair); } -const mio_htre_hdrval_t* mio_htre_gettrailerval ( - const mio_htre_t* re, const mio_mchar_t* name) +const mio_htre_hdrval_t* mio_htre_gettrailerval (const mio_htre_t* re, const mio_bch_t* name) { mio_htb_pair_t* pair; - pair = mio_htb_search (&re->trailers, name, mio_mbslen(name)); + pair = mio_htb_search(&re->trailers, name, mio_count_bcstr(name)); if (pair == MIO_NULL) return MIO_NULL; return MIO_HTB_VPTR(pair); } @@ -145,8 +142,7 @@ struct header_walker_ctx_t int ret; }; -static mio_htb_walk_t walk_headers ( - mio_htb_t* htb, mio_htb_pair_t* pair, void* ctx) +static mio_htb_walk_t walk_headers (mio_htb_t* htb, mio_htb_pair_t* pair, void* ctx) { struct header_walker_ctx_t* hwctx = (struct header_walker_ctx_t*)ctx; if (hwctx->walker (hwctx->re, MIO_HTB_KPTR(pair), MIO_HTB_VPTR(pair), hwctx->ctx) <= -1) @@ -157,8 +153,7 @@ static mio_htb_walk_t walk_headers ( return MIO_HTB_WALK_FORWARD; } -int mio_htre_walkheaders ( - mio_htre_t* re, mio_htre_header_walker_t walker, void* ctx) +int mio_htre_walkheaders (mio_htre_t* re, mio_htre_header_walker_t walker, void* ctx) { struct header_walker_ctx_t hwctx; hwctx.re = re; @@ -169,8 +164,7 @@ int mio_htre_walkheaders ( return hwctx.ret; } -int mio_htre_walktrailers ( - mio_htre_t* re, mio_htre_header_walker_t walker, void* ctx) +int mio_htre_walktrailers (mio_htre_t* re, mio_htre_header_walker_t walker, void* ctx) { struct header_walker_ctx_t hwctx; hwctx.re = re; @@ -181,8 +175,7 @@ int mio_htre_walktrailers ( return hwctx.ret; } -int mio_htre_addcontent ( - mio_htre_t* re, const mio_mchar_t* ptr, mio_size_t len) +int mio_htre_addcontent (mio_htre_t* re, const mio_bch_t* ptr, mio_oow_t len) { /* see comments in mio_htre_discardcontent() */ @@ -191,12 +184,12 @@ int mio_htre_addcontent ( if (re->concb) { /* if the callback is set, the content goes to the callback. */ - if (re->concb (re, ptr, len, re->concb_ctx) <= -1) return -1; + if (re->concb(re, ptr, len, re->concb_ctx) <= -1) return -1; } else { /* if the callback is not set, the contents goes to the internal buffer */ - if (mio_mbs_ncat (&re->content, ptr, len) == (mio_size_t)-1) return -1; + if (mio_becs_ncat(&re->content, ptr, len) == (mio_oow_t)-1) return -1; } return 1; /* added successfully */ @@ -225,8 +218,7 @@ void mio_htre_discardcontent (mio_htre_t* re) * you can't add contents to this if it's completed or discarded */ - if (!(re->state & MIO_HTRE_COMPLETED) && - !(re->state & MIO_HTRE_DISCARDED)) + if (!(re->state & MIO_HTRE_COMPLETED) && !(re->state & MIO_HTRE_DISCARDED)) { re->state |= MIO_HTRE_DISCARDED; @@ -243,7 +235,7 @@ void mio_htre_discardcontent (mio_htre_t* re) * designed to serve a certain usage pattern not including * weird combinations. */ - mio_mbs_clear (&re->content); + mio_becs_clear (&re->content); if (re->concb) { /* indicate end of content */ @@ -266,34 +258,34 @@ void mio_htre_setconcb (mio_htre_t* re, mio_htre_concb_t concb, void* ctx) int mio_htre_perdecqpath (mio_htre_t* re) { - mio_size_t dec_count; + mio_oow_t dec_count; /* percent decode the query path*/ if (re->type != MIO_HTRE_Q || (re->flags & MIO_HTRE_QPATH_PERDEC)) return -1; - MIO_ASSERT (re->orgqpath.len <= 0); - MIO_ASSERT (re->orgqpath.ptr == MIO_NULL); + MIO_ASSERT (re->mio, re->orgqpath.len <= 0); + MIO_ASSERT (re->mio, re->orgqpath.ptr == MIO_NULL); - if (mio_isperencedhttpstr(re->u.q.path.ptr)) + if (mio_is_perenced_http_bcstr(re->u.q.path.ptr)) { /* the string is percent-encoded. keep the original request * in a separately allocated buffer */ if (re->orgqpath.buf && re->u.q.path.len <= re->orgqpath.capa) { - re->orgqpath.len = mio_mbscpy (re->orgqpath.buf, re->u.q.path.ptr); + re->orgqpath.len = mio_copy_bcstr_unlimited(re->orgqpath.buf, re->u.q.path.ptr); re->orgqpath.ptr = re->orgqpath.buf; } else { if (re->orgqpath.buf) { - MIO_MMGR_FREE (re->mmgr, re->orgqpath.buf); + mio_freemem (re->mio, re->orgqpath.buf); re->orgqpath.capa = 0; } - re->orgqpath.buf = mio_mbsxdup (re->u.q.path.ptr, re->u.q.path.len, re->mmgr); + re->orgqpath.buf = mio_mbsxdup(re->u.q.path.ptr, re->u.q.path.len, re->mio); if (!re->orgqpath.buf) return -1; re->orgqpath.capa = re->u.q.path.len; @@ -309,10 +301,10 @@ int mio_htre_perdecqpath (mio_htre_t* re) re->u.q.path.len = mio_perdechttpstr (re->u.q.path.ptr, re->u.q.path.ptr, &dec_count); if (dec_count > 0) { - /* this assertion is to ensure that mio_isperencedhttpstr() + /* this assertion is to ensure that mio_is_perenced_http_bstr() * returned true when dec_count is greater than 0 */ - MIO_ASSERT (re->orgqpath.buf != MIO_NULL); - MIO_ASSERT (re->orgqpath.ptr != MIO_NULL); + MIO_ASSERT (re->mio, re->orgqpath.buf != MIO_NULL); + MIO_ASSERT (re->mio, re->orgqpath.ptr != MIO_NULL); re->flags |= MIO_HTRE_QPATH_PERDEC; } diff --git a/mio/lib/http.c b/mio/lib/http.c index 4336e87..0f6d308 100644 --- a/mio/lib/http.c +++ b/mio/lib/http.c @@ -33,9 +33,9 @@ int mio_comparehttpversions ( return v1->major - v2->major; } -const mio_mchar_t* mio_httpstatustombs (int code) +const mio_bch_t* mio_httpstatustombs (int code) { - const mio_mchar_t* msg; + const mio_bch_t* msg; switch (code) { @@ -95,10 +95,10 @@ const mio_mchar_t* mio_httpstatustombs (int code) return msg; } -const mio_mchar_t* mio_httpmethodtombs (mio_http_method_t type) +const mio_bch_t* mio_httpmethodtombs (mio_http_method_t type) { /* keep this table in the same order as mio_httpd_method_t enumerators */ - static mio_mchar_t* names[] = + static mio_bch_t* names[] = { "OTHER", @@ -117,7 +117,7 @@ const mio_mchar_t* mio_httpmethodtombs (mio_http_method_t type) struct mtab_t { - const mio_mchar_t* name; + const mio_bch_t* name; mio_http_method_t type; }; @@ -134,7 +134,7 @@ static struct mtab_t mtab[] = { "TRACE", MIO_HTTP_TRACE } }; -mio_http_method_t mio_mbstohttpmethod (const mio_mchar_t* name) +mio_http_method_t mio_bcstr_to_http_method (const mio_bch_t* name) { /* perform binary search */ @@ -151,10 +151,10 @@ mio_http_method_t mio_mbstohttpmethod (const mio_mchar_t* name) mid = left + (right - left) / 2; entry = &mtab[mid]; - n = mio_mbscmp (name, entry->name); + n = mio_comp_bcstr(name, entry->name); if (n < 0) { - /* if left, right, mid were of mio_size_t, + /* if left, right, mid were of mio_oow_t, * you would need the following line. if (mid == 0) break; */ @@ -167,7 +167,7 @@ mio_http_method_t mio_mbstohttpmethod (const mio_mchar_t* name) return MIO_HTTP_OTHER; } -mio_http_method_t mio_mcstrtohttpmethod (const mio_mcstr_t* name) +mio_http_method_t mio_bchars_to_http_method (const mio_bch_t* nameptr, mio_oow_t namelen) { /* perform binary search */ @@ -184,10 +184,10 @@ mio_http_method_t mio_mcstrtohttpmethod (const mio_mcstr_t* name) mid = left + (right - left) / 2; entry = &mtab[mid]; - n = mio_mbsxcmp (name->ptr, name->len, entry->name); + n = mio_mbsxcmp(nameptr, namelen, entry->name); if (n < 0) { - /* if left, right, mid were of mio_size_t, + /* if left, right, mid were of mio_oow_t, * you would need the following line. if (mid == 0) break; */ @@ -200,7 +200,7 @@ mio_http_method_t mio_mcstrtohttpmethod (const mio_mcstr_t* name) return MIO_HTTP_OTHER; } -int mio_parsehttprange (const mio_mchar_t* str, mio_http_range_t* range) +int mio_parse_http_range_bcstr (const mio_bch_t* str, mio_http_range_t* range) { /* NOTE: this function does not support a range set * like bytes=1-20,30-50 */ @@ -255,8 +255,8 @@ int mio_parsehttprange (const mio_mchar_t* str, mio_http_range_t* range) typedef struct mname_t mname_t; struct mname_t { - const mio_mchar_t* s; - const mio_mchar_t* l; + const mio_bch_t* s; + const mio_bch_t* l; }; static mname_t wday_name[] = @@ -286,11 +286,11 @@ static mname_t mon_name[] = { "Dec", "December" } }; -int mio_parsehttptime (const mio_mchar_t* str, mio_ntime_t* nt) +int mio_parse_http_time_bcstr (const mio_bch_t* str, mio_ntime_t* nt) { mio_btime_t bt; - const mio_mchar_t* word; - mio_size_t wlen, i; + const mio_bch_t* word; + mio_oow_t wlen, i; /* TODO: support more formats */ @@ -302,7 +302,7 @@ int mio_parsehttptime (const mio_mchar_t* str, mio_ntime_t* nt) wlen = str - word; for (i = 0; i < MIO_COUNTOF(wday_name); i++) { - if (mio_mbsxcmp (word, wlen, wday_name[i].s) == 0) + if (mio_mbsxcmp(word, wlen, wday_name[i].s) == 0) { bt.wday = i; break; @@ -325,7 +325,7 @@ int mio_parsehttptime (const mio_mchar_t* str, mio_ntime_t* nt) wlen = str - word; for (i = 0; i < MIO_COUNTOF(mon_name); i++) { - if (mio_mbsxcmp (word, wlen, mon_name[i].s) == 0) + if (mio_mbsxcmp(word, wlen, mon_name[i].s) == 0) { bt.mon = i; break; @@ -362,15 +362,15 @@ int mio_parsehttptime (const mio_mchar_t* str, mio_ntime_t* nt) while (MIO_ISMSPACE(*str)) str++; for (word = str; MIO_ISMALPHA(*str); str++); wlen = str - word; - if (mio_mbsxcmp (word, wlen, "GMT" != 0) return -1; + if (mio_mbsxcmp(word, wlen, "GMT") != 0) return -1; while (MIO_ISMSPACE(*str)) str++; if (*str != '\0') return -1; - return mio_timegm (&bt, nt); + return mio_timegm(&bt, nt); } -mio_mchar_t* mio_fmthttptime (const mio_ntime_t* nt, mio_mchar_t* buf, mio_size_t bufsz) +mio_bch_t* mio_fmthttptime (const mio_ntime_t* nt, mio_bch_t* buf, mio_oow_t bufsz) { mio_btime_t bt; @@ -389,9 +389,9 @@ mio_mchar_t* mio_fmthttptime (const mio_ntime_t* nt, mio_mchar_t* buf, mio_size_ return buf; } -int mio_isperencedhttpstr (const mio_mchar_t* str) +int mio_is_perenced_http_bcstr (const mio_bch_t* str) { - const mio_mchar_t* p = str; + const mio_bch_t* p = str; while (*p != '\0') { @@ -412,11 +412,11 @@ int mio_isperencedhttpstr (const mio_mchar_t* str) return 1; } -mio_size_t mio_perdechttpstr (const mio_mchar_t* str, mio_mchar_t* buf, mio_size_t* ndecs) +mio_oow_t mio_perdechttpstr (const mio_bch_t* str, mio_bch_t* buf, mio_oow_t* ndecs) { - const mio_mchar_t* p = str; - mio_mchar_t* out = buf; - mio_size_t dec_count = 0; + const mio_bch_t* p = str; + mio_bch_t* out = buf; + mio_oow_t dec_count = 0; while (*p != '\0') { @@ -454,11 +454,11 @@ mio_size_t mio_perdechttpstr (const mio_mchar_t* str, mio_mchar_t* buf, mio_size #define TO_HEX(v) ("0123456789ABCDEF"[(v) & 15]) -mio_size_t mio_perenchttpstr (int opt, const mio_mchar_t* str, mio_mchar_t* buf, mio_size_t* nencs) +mio_oow_t mio_perenchttpstr (int opt, const mio_bch_t* str, mio_bch_t* buf, mio_oow_t* nencs) { - const mio_mchar_t* p = str; - mio_mchar_t* out = buf; - mio_size_t enc_count = 0; + const mio_bch_t* p = str; + mio_bch_t* out = buf; + mio_oow_t enc_count = 0; /* this function doesn't accept the size of the buffer. the caller must * ensure that the buffer is large enough */ @@ -498,11 +498,11 @@ mio_size_t mio_perenchttpstr (int opt, const mio_mchar_t* str, mio_mchar_t* buf, return out - buf; } -mio_mchar_t* mio_perenchttpstrdup (int opt, const mio_mchar_t* str, mio_mmgr_t* mmgr) +mio_bch_t* mio_perenchttpstrdup (int opt, const mio_bch_t* str, mio_mmgr_t* mmgr) { - mio_mchar_t* buf; - mio_size_t len = 0; - mio_size_t count = 0; + mio_bch_t* buf; + mio_oow_t len = 0; + mio_oow_t count = 0; /* count the number of characters that should be encoded */ if (opt & MIO_PERENCHTTPSTR_KEEP_SLASH) @@ -521,7 +521,7 @@ mio_mchar_t* mio_perenchttpstrdup (int opt, const mio_mchar_t* str, mio_mmgr_t* } /* if there are no characters to escape, just return the original string */ - if (count <= 0) return (mio_mchar_t*)str; + if (count <= 0) return (mio_bch_t*)str; /* allocate a buffer of an optimal size for escaping, otherwise */ buf = MIO_MMGR_ALLOC (mmgr, (len + (count * 2) + 1) * MIO_SIZEOF(*buf)); diff --git a/mio/lib/mio-cmn.h b/mio/lib/mio-cmn.h index ebbdd41..9cd2d00 100644 --- a/mio/lib/mio-cmn.h +++ b/mio/lib/mio-cmn.h @@ -430,6 +430,13 @@ typedef struct mio_bcs_t mio_bcs_t; typedef unsigned int mio_bitmask_t; +typedef struct mio_ptl_t mio_ptl_t; +struct mio_ptl_t +{ + void* ptr; + mio_oow_t len; +}; + /* ========================================================================= * TIME-RELATED TYPES * =========================================================================*/ diff --git a/mio/lib/mio-ecs.h b/mio/lib/mio-ecs.h new file mode 100644 index 0000000..626c037 --- /dev/null +++ b/mio/lib/mio-ecs.h @@ -0,0 +1,640 @@ +/* + * $Id$ + * + Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MIO_ECS_H_ +#define _MIO_ECS_H_ + +#include +#include + +/** string pointer and length as a aggregate */ +#define MIO_BECS_BCS(s) (&((s)->val)) +/** string length */ +#define MIO_BECS_LEN(s) ((s)->val.len) +/** string pointer */ +#define MIO_BECS_PTR(s) ((s)->val.ptr) +/** pointer to a particular position */ +#define MIO_BECS_CPTR(s,idx) (&(s)->val.ptr[idx]) +/** string capacity */ +#define MIO_BECS_CAPA(s) ((s)->capa) +/** character at the given position */ +#define MIO_BECS_CHAR(s,idx) ((s)->val.ptr[idx]) +/**< last character. unsafe if length <= 0 */ +#define MIO_BECS_LASTCHAR(s) ((s)->val.ptr[(s)->val.len-1]) + +/** string pointer and length as a aggregate */ +#define MIO_UECS_UCS(s) (&((s)->val)) +/** string length */ +#define MIO_UECS_LEN(s) ((s)->val.len) +/** string pointer */ +#define MIO_UECS_PTR(s) ((s)->val.ptr) +/** pointer to a particular position */ +#define MIO_UECS_CPTR(s,idx) (&(s)->val.ptr[idx]) +/** string capacity */ +#define MIO_UECS_CAPA(s) ((s)->capa) +/** character at the given position */ +#define MIO_UECS_CHAR(s,idx) ((s)->val.ptr[idx]) +/**< last character. unsafe if length <= 0 */ +#define MIO_UECS_LASTCHAR(s) ((s)->val.ptr[(s)->val.len-1]) + +typedef struct mio_becs_t mio_becs_t; +typedef struct mio_uecs_t mio_uecs_t; + +typedef mio_oow_t (*mio_becs_sizer_t) ( + mio_becs_t* data, + mio_oow_t hint +); + +typedef mio_oow_t (*mio_uecs_sizer_t) ( + mio_uecs_t* data, + mio_oow_t hint +); + +#if defined(MIO_OOCH_IS_UCH) +# define MIO_OOECS_OOCS(s) MIO_UECS_UCS(s) +# define MIO_OOECS_LEN(s) MIO_UECS_LEN(s) +# define MIO_OOECS_PTR(s) MIO_UECS_PTR(s) +# define MIO_OOECS_CPTR(s,idx) MIO_UECS_CPTR(s,idx) +# define MIO_OOECS_CAPA(s) MIO_UECS_CAPA(s) +# define MIO_OOECS_CHAR(s,idx) MIO_UECS_CHAR(s,idx) +# define MIO_OOECS_LASTCHAR(s) MIO_UECS_LASTCHAR(s) +# define mio_ooecs_t mio_uecs_t +# define mio_ooecs_sizer_t mio_uecs_sizer_t +#else +# define MIO_OOECS_OOCS(s) MIO_BECS_BCS(s) +# define MIO_OOECS_LEN(s) MIO_BECS_LEN(s) +# define MIO_OOECS_PTR(s) MIO_BECS_PTR(s) +# define MIO_OOECS_CPTR(s,idx) MIO_BECS_CPTR(s,idx) +# define MIO_OOECS_CAPA(s) MIO_BECS_CAPA(s) +# define MIO_OOECS_CHAR(s,idx) MIO_BECS_CHAR(s,idx) +# define MIO_OOECS_LASTCHAR(s) MIO_BECS_LASTCHAR(s) +# define mio_ooecs_t mio_becs_t +# define mio_ooecs_sizer_t mio_becs_sizer_t +#endif + + +/** + * The mio_becs_t type defines a dynamically resizable multi-byte string. + */ +struct mio_becs_t +{ + mio_t* gem; + mio_becs_sizer_t sizer; /**< buffer resizer function */ + mio_bcs_t val; /**< buffer/string pointer and lengh */ + mio_oow_t capa; /**< buffer capacity */ +}; + +/** + * The mio_uecs_t type defines a dynamically resizable wide-character string. + */ +struct mio_uecs_t +{ + mio_t* gem; + mio_uecs_sizer_t sizer; /**< buffer resizer function */ + mio_ucs_t val; /**< buffer/string pointer and lengh */ + mio_oow_t capa; /**< buffer capacity */ +}; + + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * The mio_becs_open() function creates a dynamically resizable multibyte string. + */ +MIO_EXPORT mio_becs_t* mio_becs_open ( + mio_t* gem, + mio_oow_t xtnsize, + mio_oow_t capa +); + +MIO_EXPORT void mio_becs_close ( + mio_becs_t* becs +); + +/** + * The mio_becs_init() function initializes a dynamically resizable string + * If the parameter capa is 0, it doesn't allocate the internal buffer + * in advance and always succeeds. + * \return 0 on success, -1 on failure. + */ +MIO_EXPORT int mio_becs_init ( + mio_becs_t* becs, + mio_t* gem, + mio_oow_t capa +); + +/** + * The mio_becs_fini() function finalizes a dynamically resizable string. + */ +MIO_EXPORT void mio_becs_fini ( + mio_becs_t* becs +); + +#if defined(MIO_HAVE_INLINE) +static MIO_INLINE void* mio_becs_getxtn (mio_becs_t* becs) { return (void*)(becs + 1); } +#else +#define mio_becs_getxtn(becs) ((void*)((mio_becs_t*)(becs) + 1)) +#endif + +/** + * The mio_becs_yield() function assigns the buffer to an variable of the + * #mio_bcs_t type and recreate a new buffer of the \a new_capa capacity. + * The function fails if it fails to allocate a new buffer. + * \return 0 on success, and -1 on failure. + */ +MIO_EXPORT int mio_becs_yield ( + mio_becs_t* becs, /**< string */ + mio_bcs_t* buf, /**< buffer pointer */ + mio_oow_t newcapa /**< new capacity */ +); + +MIO_EXPORT mio_bch_t* mio_becs_yieldptr ( + mio_becs_t* becs, /**< string */ + mio_oow_t newcapa /**< new capacity */ +); + +/** + * The mio_becs_getsizer() function gets the sizer. + * \return sizer function set or MIO_NULL if no sizer is set. + */ +#if defined(MIO_HAVE_INLINE) +static MIO_INLINE mio_becs_sizer_t mio_becs_getsizer (mio_becs_t* becs) { return becs->sizer; } +#else +# define mio_becs_getsizer(becs) ((becs)->sizer) +#endif + +/** + * The mio_becs_setsizer() function specify a new sizer for a dynamic string. + * With no sizer specified, the dynamic string doubles the current buffer + * when it needs to increase its size. The sizer function is passed a dynamic + * string and the minimum capacity required to hold data after resizing. + * The string is truncated if the sizer function returns a smaller number + * than the hint passed. + */ +#if defined(MIO_HAVE_INLINE) +static MIO_INLINE void mio_becs_setsizer (mio_becs_t* becs, mio_becs_sizer_t sizer) { becs->sizer = sizer; } +#else +# define mio_becs_setsizer(becs,sizerfn) ((becs)->sizer = (sizerfn)) +#endif + +/** + * The mio_becs_getcapa() function returns the current capacity. + * You may use MIO_STR_CAPA(str) macro for performance sake. + * \return current capacity in number of characters. + */ +#if defined(MIO_HAVE_INLINE) +static MIO_INLINE mio_oow_t mio_becs_getcapa (mio_becs_t* becs) { return MIO_BECS_CAPA(becs); } +#else +# define mio_becs_getcapa(becs) MIO_BECS_CAPA(becs) +#endif + +/** + * The mio_becs_setcapa() function sets the new capacity. If the new capacity + * is smaller than the old, the overflowing characters are removed from + * from the buffer. + * \return (mio_oow_t)-1 on failure, new capacity on success + */ +MIO_EXPORT mio_oow_t mio_becs_setcapa ( + mio_becs_t* becs, + mio_oow_t capa +); + +/** + * The mio_becs_getlen() function return the string length. + */ +#if defined(MIO_HAVE_INLINE) +static MIO_INLINE mio_oow_t mio_becs_getlen (mio_becs_t* becs) { return MIO_BECS_LEN(becs); } +#else +# define mio_becs_getlen(becs) MIO_BECS_LEN(becs) +#endif + +/** + * The mio_becs_setlen() function changes the string length. + * \return (mio_oow_t)-1 on failure, new length on success + */ +MIO_EXPORT mio_oow_t mio_becs_setlen ( + mio_becs_t* becs, + mio_oow_t len +); + +/** + * The mio_becs_clear() funtion deletes all characters in a string and sets + * the length to 0. It doesn't resize the internal buffer. + */ +MIO_EXPORT void mio_becs_clear ( + mio_becs_t* becs +); + +/** + * The mio_becs_swap() function exchanges the pointers to a buffer between + * two strings. It updates the length and the capacity accordingly. + */ +MIO_EXPORT void mio_becs_swap ( + mio_becs_t* becs1, + mio_becs_t* becs2 +); + +MIO_EXPORT mio_oow_t mio_becs_cpy ( + mio_becs_t* becs, + const mio_bch_t* s +); + +MIO_EXPORT mio_oow_t mio_becs_ncpy ( + mio_becs_t* becs, + const mio_bch_t* s, + mio_oow_t len +); + +MIO_EXPORT mio_oow_t mio_becs_cat ( + mio_becs_t* becs, + const mio_bch_t* s +); + +MIO_EXPORT mio_oow_t mio_becs_ncat ( + mio_becs_t* becs, + const mio_bch_t* s, + mio_oow_t len +); + +MIO_EXPORT mio_oow_t mio_becs_nrcat ( + mio_becs_t* becs, + const mio_bch_t* s, + mio_oow_t len +); + +MIO_EXPORT mio_oow_t mio_becs_ccat ( + mio_becs_t* becs, + mio_bch_t c +); + +MIO_EXPORT mio_oow_t mio_becs_nccat ( + mio_becs_t* becs, + mio_bch_t c, + mio_oow_t len +); + +MIO_EXPORT mio_oow_t mio_becs_del ( + mio_becs_t* becs, + mio_oow_t index, + mio_oow_t size +); + +MIO_EXPORT mio_oow_t mio_becs_amend ( + mio_becs_t* becs, + mio_oow_t index, + mio_oow_t size, + const mio_bch_t* repl +); + +MIO_EXPORT mio_oow_t mio_becs_vfcat ( + mio_becs_t* str, + const mio_bch_t* fmt, + va_list ap +); + +MIO_EXPORT mio_oow_t mio_becs_fcat ( + mio_becs_t* str, + const mio_bch_t* fmt, + ... +); + +MIO_EXPORT mio_oow_t mio_becs_vfmt ( + mio_becs_t* str, + const mio_bch_t* fmt, + va_list ap +); + +MIO_EXPORT mio_oow_t mio_becs_fmt ( + mio_becs_t* str, + const mio_bch_t* fmt, + ... +); + +/* ------------------------------------------------------------------------ */ + +/** + * The mio_uecs_open() function creates a dynamically resizable multibyte string. + */ +MIO_EXPORT mio_uecs_t* mio_uecs_open ( + mio_t* gem, + mio_oow_t xtnsize, + mio_oow_t capa +); + +MIO_EXPORT void mio_uecs_close ( + mio_uecs_t* uecs +); + +/** + * The mio_uecs_init() function initializes a dynamically resizable string + * If the parameter capa is 0, it doesn't allocate the internal buffer + * in advance and always succeeds. + * \return 0 on success, -1 on failure. + */ +MIO_EXPORT int mio_uecs_init ( + mio_uecs_t* uecs, + mio_t* gem, + mio_oow_t capa +); + +/** + * The mio_uecs_fini() function finalizes a dynamically resizable string. + */ +MIO_EXPORT void mio_uecs_fini ( + mio_uecs_t* uecs +); + +#if defined(MIO_HAVE_INLINE) +static MIO_INLINE void* mio_uecs_getxtn (mio_uecs_t* uecs) { return (void*)(uecs + 1); } +#else +#define mio_uecs_getxtn(uecs) ((void*)((mio_uecs_t*)(uecs) + 1)) +#endif + +/** + * The mio_uecs_yield() function assigns the buffer to an variable of the + * #mio_ucs_t type and recreate a new buffer of the \a new_capa capacity. + * The function fails if it fails to allocate a new buffer. + * \return 0 on success, and -1 on failure. + */ +MIO_EXPORT int mio_uecs_yield ( + mio_uecs_t* uecs, /**< string */ + mio_ucs_t* buf, /**< buffer pointer */ + mio_oow_t newcapa /**< new capacity */ +); + +MIO_EXPORT mio_uch_t* mio_uecs_yieldptr ( + mio_uecs_t* uecs, /**< string */ + mio_oow_t newcapa /**< new capacity */ +); + +/** + * The mio_uecs_getsizer() function gets the sizer. + * \return sizer function set or MIO_NULL if no sizer is set. + */ +#if defined(MIO_HAVE_INLINE) +static MIO_INLINE mio_uecs_sizer_t mio_uecs_getsizer (mio_uecs_t* uecs) { return uecs->sizer; } +#else +# define mio_uecs_getsizer(uecs) ((uecs)->sizer) +#endif + +/** + * The mio_uecs_setsizer() function specify a new sizer for a dynamic string. + * With no sizer specified, the dynamic string doubles the current buffer + * when it needs to increase its size. The sizer function is passed a dynamic + * string and the minimum capacity required to hold data after resizing. + * The string is truncated if the sizer function returns a smaller number + * than the hint passed. + */ +#if defined(MIO_HAVE_INLINE) +static MIO_INLINE void mio_uecs_setsizer (mio_uecs_t* uecs, mio_uecs_sizer_t sizer) { uecs->sizer = sizer; } +#else +# define mio_uecs_setsizer(uecs,sizerfn) ((uecs)->sizer = (sizerfn)) +#endif + +/** + * The mio_uecs_getcapa() function returns the current capacity. + * You may use MIO_STR_CAPA(str) macro for performance sake. + * \return current capacity in number of characters. + */ +#if defined(MIO_HAVE_INLINE) +static MIO_INLINE mio_oow_t mio_uecs_getcapa (mio_uecs_t* uecs) { return MIO_UECS_CAPA(uecs); } +#else +# define mio_uecs_getcapa(uecs) MIO_UECS_CAPA(uecs) +#endif + +/** + * The mio_uecs_setcapa() function sets the new capacity. If the new capacity + * is smaller than the old, the overflowing characters are removed from + * from the buffer. + * \return (mio_oow_t)-1 on failure, new capacity on success + */ +MIO_EXPORT mio_oow_t mio_uecs_setcapa ( + mio_uecs_t* uecs, + mio_oow_t capa +); + +/** + * The mio_uecs_getlen() function return the string length. + */ +#if defined(MIO_HAVE_INLINE) +static MIO_INLINE mio_oow_t mio_uecs_getlen (mio_uecs_t* uecs) { return MIO_UECS_LEN(uecs); } +#else +# define mio_uecs_getlen(uecs) MIO_UECS_LEN(uecs) +#endif + +/** + * The mio_uecs_setlen() function changes the string length. + * \return (mio_oow_t)-1 on failure, new length on success + */ +MIO_EXPORT mio_oow_t mio_uecs_setlen ( + mio_uecs_t* uecs, + mio_oow_t len +); + + +/** + * The mio_uecs_clear() funtion deletes all characters in a string and sets + * the length to 0. It doesn't resize the internal buffer. + */ +MIO_EXPORT void mio_uecs_clear ( + mio_uecs_t* uecs +); + +/** + * The mio_uecs_swap() function exchanges the pointers to a buffer between + * two strings. It updates the length and the capacity accordingly. + */ +MIO_EXPORT void mio_uecs_swap ( + mio_uecs_t* uecs1, + mio_uecs_t* uecs2 +); + +MIO_EXPORT mio_oow_t mio_uecs_cpy ( + mio_uecs_t* uecs, + const mio_uch_t* s +); + +MIO_EXPORT mio_oow_t mio_uecs_ncpy ( + mio_uecs_t* uecs, + const mio_uch_t* s, + mio_oow_t len +); + +MIO_EXPORT mio_oow_t mio_uecs_cat ( + mio_uecs_t* uecs, + const mio_uch_t* s +); + +MIO_EXPORT mio_oow_t mio_uecs_ncat ( + mio_uecs_t* uecs, + const mio_uch_t* s, + mio_oow_t len +); + +MIO_EXPORT mio_oow_t mio_uecs_nrcat ( + mio_uecs_t* uecs, + const mio_uch_t* s, + mio_oow_t len +); + +MIO_EXPORT mio_oow_t mio_uecs_ccat ( + mio_uecs_t* uecs, + mio_uch_t c +); + +MIO_EXPORT mio_oow_t mio_uecs_nccat ( + mio_uecs_t* uecs, + mio_uch_t c, + mio_oow_t len +); + +MIO_EXPORT mio_oow_t mio_uecs_del ( + mio_uecs_t* uecs, + mio_oow_t index, + mio_oow_t size +); + +MIO_EXPORT mio_oow_t mio_uecs_amend ( + mio_uecs_t* uecs, + mio_oow_t index, + mio_oow_t size, + const mio_uch_t* repl +); + +#if 0 +MIO_EXPORT mio_oow_t mio_uecs_vfcat ( + mio_uecs_t* str, + const mio_uch_t* fmt, + va_list ap +); + +MIO_EXPORT mio_oow_t mio_uecs_fcat ( + mio_uecs_t* str, + const mio_uch_t* fmt, + ... +); + +MIO_EXPORT mio_oow_t mio_uecs_vfmt ( + mio_uecs_t* str, + const mio_uch_t* fmt, + va_list ap +); + +MIO_EXPORT mio_oow_t mio_uecs_fmt ( + mio_uecs_t* str, + const mio_uch_t* fmt, + ... +); +#endif + +#if defined(MIO_OOCH_IS_UCH) +# define mio_ooecs_open mio_uecs_open +# define mio_ooecs_close mio_uecs_close +# define mio_ooecs_init mio_uecs_init +# define mio_ooecs_fini mio_uecs_fini +# define mio_ooecs_getxtn mio_uecs_getxtn +# define mio_ooecs_yield mio_uecs_yield +# define mio_ooecs_yieldptr mio_uecs_yieldptr +# define mio_ooecs_getsizer mio_uecs_getsizer +# define mio_ooecs_setsizer mio_uecs_setsizer +# define mio_ooecs_getcapa mio_uecs_getcapa +# define mio_ooecs_setcapa mio_uecs_setcapa +# define mio_ooecs_getlen mio_uecs_getlen +# define mio_ooecs_setlen mio_uecs_setlen +# define mio_ooecs_clear mio_uecs_clear +# define mio_ooecs_swap mio_uecs_swap +# define mio_ooecs_cpy mio_uecs_cpy +# define mio_ooecs_ncpy mio_uecs_ncpy +# define mio_ooecs_cat mio_uecs_cat +# define mio_ooecs_ncat mio_uecs_ncat +# define mio_ooecs_nrcat mio_uecs_nrcat +# define mio_ooecs_ccat mio_uecs_ccat +# define mio_ooecs_nccat mio_uecs_nccat +# define mio_ooecs_del mio_uecs_del +# define mio_ooecs_amend mio_uecs_amend +#if 0 +# define mio_ooecs_vfcat mio_uecs_vfcat +# define mio_ooecs_fcat mio_uecs_fcat +# define mio_ooecs_vfmt mio_uecs_vfmt +# define mio_ooecs_fmt mio_uecs_fmt +#endif +#else +# define mio_ooecs_open mio_becs_open +# define mio_ooecs_close mio_becs_close +# define mio_ooecs_init mio_becs_init +# define mio_ooecs_fini mio_becs_fini +# define mio_ooecs_getxtn mio_becs_getxtn +# define mio_ooecs_yield mio_becs_yield +# define mio_ooecs_yieldptr mio_becs_yieldptr +# define mio_ooecs_getsizer mio_becs_getsizer +# define mio_ooecs_setsizer mio_becs_setsizer +# define mio_ooecs_getcapa mio_becs_getcapa +# define mio_ooecs_setcapa mio_becs_setcapa +# define mio_ooecs_getlen mio_becs_getlen +# define mio_ooecs_setlen mio_becs_setlen +# define mio_ooecs_clear mio_becs_clear +# define mio_ooecs_swap mio_becs_swap +# define mio_ooecs_cpy mio_becs_cpy +# define mio_ooecs_ncpy mio_becs_ncpy +# define mio_ooecs_cat mio_becs_cat +# define mio_ooecs_ncat mio_becs_ncat +# define mio_ooecs_nrcat mio_becs_nrcat +# define mio_ooecs_ccat mio_becs_ccat +# define mio_ooecs_nccat mio_becs_nccat +# define mio_ooecs_del mio_becs_del +# define mio_ooecs_amend mio_becs_amend + +#if 0 +# define mio_ooecs_vfcat mio_becs_vfcat +# define mio_ooecs_fcat mio_becs_fcat +# define mio_ooecs_vfmt mio_becs_vfmt +# define mio_ooecs_fmt mio_becs_fmt +#endif + +#endif + +MIO_EXPORT mio_oow_t mio_becs_ncatuchars ( + mio_becs_t* str, + const mio_uch_t* s, + mio_oow_t len, + mio_cmgr_t* cmgr +); + +MIO_EXPORT mio_oow_t mio_uecs_ncatbchars ( + mio_uecs_t* str, + const mio_bch_t* s, + mio_oow_t len, + mio_cmgr_t* cmgr, + int all +); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/mio/lib/mio-htb.h b/mio/lib/mio-htb.h new file mode 100644 index 0000000..78f84e1 --- /dev/null +++ b/mio/lib/mio-htb.h @@ -0,0 +1,682 @@ +/* + * $Id$ + * + Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MIO_HTB_H_ +#define _MIO_HTB_H_ + +#include + +/**@file + * This file provides a hash table encapsulated in the #mio_htb_t type that + * maintains buckets for key/value pairs with the same key hash chained under + * the same bucket. Its interface is very close to #mio_rbt_t. + * + * This sample code adds a series of keys and values and print them + * in the randome order. + * @code + * #include + * + * static mio_htb_walk_t walk (mio_htb_t* htb, mio_htb_pair_t* pair, void* ctx) + * { + * mio_printf (MIO_T("key = %d, value = %d\n"), + * *(int*)MIO_HTB_KPTR(pair), *(int*)MIO_HTB_VPTR(pair)); + * return MIO_HTB_WALK_FORWARD; + * } + * + * int main () + * { + * mio_htb_t* s1; + * int i; + * + * mio_open_stdsios (); + * s1 = mio_htb_open (MIO_MMGR_GETDFL(), 0, 30, 75, 1, 1); // error handling skipped + * mio_htb_setstyle (s1, mio_get_htb_style(MIO_HTB_STYLE_INLINE_COPIERS)); + * + * for (i = 0; i < 20; i++) + * { + * int x = i * 20; + * mio_htb_insert (s1, &i, MIO_SIZEOF(i), &x, MIO_SIZEOF(x)); // eror handling skipped + * } + * + * mio_htb_walk (s1, walk, MIO_NULL); + * + * mio_htb_close (s1); + * mio_close_stdsios (); + * return 0; + * } + * @endcode + */ + +typedef struct mio_htb_t mio_htb_t; +typedef struct mio_htb_pair_t mio_htb_pair_t; + +/** + * The mio_htb_walk_t type defines values that the callback function can + * return to control mio_htb_walk(). + */ +enum mio_htb_walk_t +{ + MIO_HTB_WALK_STOP = 0, + MIO_HTB_WALK_FORWARD = 1 +}; +typedef enum mio_htb_walk_t mio_htb_walk_t; + +/** + * The mio_htb_id_t type defines IDs to indicate a key or a value in various + * functions. + */ +enum mio_htb_id_t +{ + MIO_HTB_KEY = 0, + MIO_HTB_VAL = 1 +}; +typedef enum mio_htb_id_t mio_htb_id_t; + +/** + * The mio_htb_copier_t type defines a pair contruction callback. + * A special copier #MIO_HTB_COPIER_INLINE is provided. This copier enables + * you to copy the data inline to the internal node. No freeer is invoked + * when the node is freeed. + */ +typedef void* (*mio_htb_copier_t) ( + mio_htb_t* htb /* hash table */, + void* dptr /* pointer to a key or a value */, + mio_oow_t dlen /* length of a key or a value */ +); + +/** + * The mio_htb_freeer_t defines a key/value destruction callback + * The freeer is called when a node containing the element is destroyed. + */ +typedef void (*mio_htb_freeer_t) ( + mio_htb_t* htb, /**< hash table */ + void* dptr, /**< pointer to a key or a value */ + mio_oow_t dlen /**< length of a key or a value */ +); + + +/** + * The mio_htb_comper_t type defines a key comparator that is called when + * the htb needs to compare keys. A hash table is created with a default + * comparator which performs bitwise comparison of two keys. + * The comparator should return 0 if the keys are the same and a non-zero + * integer otherwise. + */ +typedef int (*mio_htb_comper_t) ( + const mio_htb_t* htb, /**< hash table */ + const void* kptr1, /**< key pointer */ + mio_oow_t klen1, /**< key length */ + const void* kptr2, /**< key pointer */ + mio_oow_t klen2 /**< key length */ +); + +/** + * The mio_htb_keeper_t type defines a value keeper that is called when + * a value is retained in the context that it should be destroyed because + * it is identical to a new value. Two values are identical if their + * pointers and lengths are equal. + */ +typedef void (*mio_htb_keeper_t) ( + mio_htb_t* htb, /**< hash table */ + void* vptr, /**< value pointer */ + mio_oow_t vlen /**< value length */ +); + +/** + * The mio_htb_sizer_t type defines a bucket size claculator that is called + * when hash table should resize the bucket. The current bucket size + 1 is + * passed as the hint. + */ +typedef mio_oow_t (*mio_htb_sizer_t) ( + mio_htb_t* htb, /**< htb */ + mio_oow_t hint /**< sizing hint */ +); + +/** + * The mio_htb_hasher_t type defines a key hash function + */ +typedef mio_oow_t (*mio_htb_hasher_t) ( + const mio_htb_t* htb, /**< hash table */ + const void* kptr, /**< key pointer */ + mio_oow_t klen /**< key length in bytes */ +); + +/** + * The mio_htb_walker_t defines a pair visitor. + */ +typedef mio_htb_walk_t (*mio_htb_walker_t) ( + mio_htb_t* htb, /**< htb */ + mio_htb_pair_t* pair, /**< pointer to a key/value pair */ + void* ctx /**< pointer to user-defined data */ +); + +/** + * The mio_htb_cbserter_t type defines a callback function for mio_htb_cbsert(). + * The mio_htb_cbserter() function calls it to allocate a new pair for the + * key pointed to by @a kptr of the length @a klen and the callback context + * @a ctx. The second parameter @a pair is passed the pointer to the existing + * pair for the key or #MIO_NULL in case of no existing key. The callback + * must return a pointer to a new or a reallocated pair. When reallocating the + * existing pair, this callback must destroy the existing pair and return the + * newly reallocated pair. It must return #MIO_NULL for failure. + */ +typedef mio_htb_pair_t* (*mio_htb_cbserter_t) ( + mio_htb_t* htb, /**< hash table */ + mio_htb_pair_t* pair, /**< pair pointer */ + void* kptr, /**< key pointer */ + mio_oow_t klen, /**< key length */ + void* ctx /**< callback context */ +); + + +/** + * The mio_htb_pair_t type defines hash table pair. A pair is composed of a key + * and a value. It maintains pointers to the beginning of a key and a value + * plus their length. The length is scaled down with the scale factor + * specified in an owning hash table. + */ +struct mio_htb_pair_t +{ + mio_ptl_t key; + mio_ptl_t val; + + /* management information below */ + mio_htb_pair_t* next; +}; + +typedef struct mio_htb_style_t mio_htb_style_t; + +struct mio_htb_style_t +{ + mio_htb_copier_t copier[2]; + mio_htb_freeer_t freeer[2]; + mio_htb_comper_t comper; /**< key comparator */ + mio_htb_keeper_t keeper; /**< value keeper */ + mio_htb_sizer_t sizer; /**< bucket capacity recalculator */ + mio_htb_hasher_t hasher; /**< key hasher */ +}; + +/** + * The mio_htb_style_kind_t type defines the type of predefined + * callback set for pair manipulation. + */ +enum mio_htb_style_kind_t +{ + /** store the key and the value pointer */ + MIO_HTB_STYLE_DEFAULT, + /** copy both key and value into the pair */ + MIO_HTB_STYLE_INLINE_COPIERS, + /** copy the key into the pair but store the value pointer */ + MIO_HTB_STYLE_INLINE_KEY_COPIER, + /** copy the value into the pair but store the key pointer */ + MIO_HTB_STYLE_INLINE_VALUE_COPIER +}; + +typedef enum mio_htb_style_kind_t mio_htb_style_kind_t; + +/** + * The mio_htb_t type defines a hash table. + */ +struct mio_htb_t +{ + mio_t* mio; + + const mio_htb_style_t* style; + + mio_uint8_t scale[2]; /**< length scale */ + mio_uint8_t factor; /**< load factor in percentage */ + + mio_oow_t size; + mio_oow_t capa; + mio_oow_t threshold; + + mio_htb_pair_t** bucket; +}; + +struct mio_htb_itr_t +{ + mio_htb_pair_t* pair; + mio_oow_t buckno; +}; + +typedef struct mio_htb_itr_t mio_htb_itr_t; + +/** + * The MIO_HTB_COPIER_SIMPLE macros defines a copier that remembers the + * pointer and length of data in a pair. + **/ +#define MIO_HTB_COPIER_SIMPLE ((mio_htb_copier_t)1) + +/** + * The MIO_HTB_COPIER_INLINE macros defines a copier that copies data into + * a pair. + **/ +#define MIO_HTB_COPIER_INLINE ((mio_htb_copier_t)2) + +#define MIO_HTB_COPIER_DEFAULT (MIO_HTB_COPIER_SIMPLE) +#define MIO_HTB_FREEER_DEFAULT (MIO_NULL) +#define MIO_HTB_COMPER_DEFAULT (mio_htb_dflcomp) +#define MIO_HTB_KEEPER_DEFAULT (MIO_NULL) +#define MIO_HTB_SIZER_DEFAULT (MIO_NULL) +#define MIO_HTB_HASHER_DEFAULT (mio_htb_dflhash) + +/** + * The MIO_HTB_SIZE() macro returns the number of pairs in a hash table. + */ +#define MIO_HTB_SIZE(m) (*(const mio_oow_t*)&(m)->size) + +/** + * The MIO_HTB_CAPA() macro returns the maximum number of pairs that can be + * stored in a hash table without further reorganization. + */ +#define MIO_HTB_CAPA(m) (*(const mio_oow_t*)&(m)->capa) + +#define MIO_HTB_FACTOR(m) (*(const int*)&(m)->factor) +#define MIO_HTB_KSCALE(m) (*(const int*)&(m)->scale[MIO_HTB_KEY]) +#define MIO_HTB_VSCALE(m) (*(const int*)&(m)->scale[MIO_HTB_VAL]) + +#define MIO_HTB_KPTL(p) (&(p)->key) +#define MIO_HTB_VPTL(p) (&(p)->val) + +#define MIO_HTB_KPTR(p) ((p)->key.ptr) +#define MIO_HTB_KLEN(p) ((p)->key.len) +#define MIO_HTB_VPTR(p) ((p)->val.ptr) +#define MIO_HTB_VLEN(p) ((p)->val.len) + +#define MIO_HTB_NEXT(p) ((p)->next) + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * The mio_get_htb_style() functions returns a predefined callback set for + * pair manipulation. + */ +MIO_EXPORT const mio_htb_style_t* mio_get_htb_style ( + mio_htb_style_kind_t kind +); + +/** + * The mio_htb_open() function creates a hash table with a dynamic array + * bucket and a list of values chained. The initial capacity should be larger + * than 0. The load factor should be between 0 and 100 inclusive and the load + * factor of 0 disables bucket resizing. If you need extra space associated + * with hash table, you may pass a non-zero value for @a xtnsize. + * The MIO_HTB_XTN() macro and the mio_htb_getxtn() function return the + * pointer to the beginning of the extension. + * The @a kscale and @a vscale parameters specify the unit of the key and + * value size. + * @return #mio_htb_t pointer on success, #MIO_NULL on failure. + */ +MIO_EXPORT mio_htb_t* mio_htb_open ( + mio_t* mio, + mio_oow_t xtnsize, /**< extension size in bytes */ + mio_oow_t capa, /**< initial capacity */ + int factor, /**< load factor */ + int kscale, /**< key scale - 1 to 255 */ + int vscale /**< value scale - 1 to 255 */ +); + + +/** + * The mio_htb_close() function destroys a hash table. + */ +MIO_EXPORT void mio_htb_close ( + mio_htb_t* htb /**< hash table */ +); + +/** + * The mio_htb_init() function initializes a hash table + */ +MIO_EXPORT int mio_htb_init ( + mio_htb_t* htb, /**< hash table */ + mio_t* mio, + mio_oow_t capa, /**< initial capacity */ + int factor, /**< load factor */ + int kscale, /**< key scale */ + int vscale /**< value scale */ +); + +/** + * The mio_htb_fini() funtion finalizes a hash table + */ +MIO_EXPORT void mio_htb_fini ( + mio_htb_t* htb +); + +#if defined(MIO_HAVE_INLINE) +static MIO_INLINE void* mio_htb_getxtn (mio_htb_t* htb) { return (void*)(htb + 1); } +#else +#define mio_htb_getxtn(htb) ((void*)((mio_htb_t*)(htb) + 1)) +#endif + +/** + * The mio_htb_getstyle() function gets manipulation callback function set. + */ +MIO_EXPORT const mio_htb_style_t* mio_htb_getstyle ( + const mio_htb_t* htb /**< hash table */ +); + +/** + * The mio_htb_setstyle() function sets internal manipulation callback + * functions for data construction, destruction, resizing, hashing, etc. + * The callback structure pointed to by \a style must outlive the hash + * table pointed to by \a htb as the hash table doesn't copy the contents + * of the structure. + */ +MIO_EXPORT void mio_htb_setstyle ( + mio_htb_t* htb, /**< hash table */ + const mio_htb_style_t* style /**< callback function set */ +); + +/** + * The mio_htb_getsize() function gets the number of pairs in hash table. + */ +MIO_EXPORT mio_oow_t mio_htb_getsize ( + const mio_htb_t* htb +); + +/** + * The mio_htb_getcapa() function gets the number of slots allocated + * in a hash bucket. + */ +MIO_EXPORT mio_oow_t mio_htb_getcapa ( + const mio_htb_t* htb /**< hash table */ +); + +/** + * The mio_htb_search() function searches a hash table to find a pair with a + * matching key. It returns the pointer to the pair found. If it fails + * to find one, it returns MIO_NULL. + * @return pointer to the pair with a maching key, + * or #MIO_NULL if no match is found. + */ +MIO_EXPORT mio_htb_pair_t* mio_htb_search ( + const mio_htb_t* htb, /**< hash table */ + const void* kptr, /**< key pointer */ + mio_oow_t klen /**< key length */ +); + +/** + * The mio_htb_upsert() function searches a hash table for the pair with a + * matching key. If one is found, it updates the pair. Otherwise, it inserts + * a new pair with the key and value given. It returns the pointer to the + * pair updated or inserted. + * @return pointer to the updated or inserted pair on success, + * #MIO_NULL on failure. + */ +MIO_EXPORT mio_htb_pair_t* mio_htb_upsert ( + mio_htb_t* htb, /**< hash table */ + void* kptr, /**< key pointer */ + mio_oow_t klen, /**< key length */ + void* vptr, /**< value pointer */ + mio_oow_t vlen /**< value length */ +); + +/** + * The mio_htb_ensert() function inserts a new pair with the key and the value + * given. If there exists a pair with the key given, the function returns + * the pair containing the key. + * @return pointer to a pair on success, #MIO_NULL on failure. + */ +MIO_EXPORT mio_htb_pair_t* mio_htb_ensert ( + mio_htb_t* htb, /**< hash table */ + void* kptr, /**< key pointer */ + mio_oow_t klen, /**< key length */ + void* vptr, /**< value pointer */ + mio_oow_t vlen /**< value length */ +); + +/** + * The mio_htb_insert() function inserts a new pair with the key and the value + * given. If there exists a pair with the key given, the function returns + * #MIO_NULL without channging the value. + * @return pointer to the pair created on success, #MIO_NULL on failure. + */ +MIO_EXPORT mio_htb_pair_t* mio_htb_insert ( + mio_htb_t* htb, /**< hash table */ + void* kptr, /**< key pointer */ + mio_oow_t klen, /**< key length */ + void* vptr, /**< value pointer */ + mio_oow_t vlen /**< value length */ +); + +/** + * The mio_htb_update() function updates the value of an existing pair + * with a matching key. + * @return pointer to the pair on success, #MIO_NULL on no matching pair + */ +MIO_EXPORT mio_htb_pair_t* mio_htb_update ( + mio_htb_t* htb, /**< hash table */ + void* kptr, /**< key pointer */ + mio_oow_t klen, /**< key length */ + void* vptr, /**< value pointer */ + mio_oow_t vlen /**< value length */ +); + +/** + * The mio_htb_cbsert() function inserts a key/value pair by delegating pair + * allocation to a callback function. Depending on the callback function, + * it may behave like mio_htb_insert(), mio_htb_upsert(), mio_htb_update(), + * mio_htb_ensert(), or totally differently. The sample code below inserts + * a new pair if the key is not found and appends the new value to the + * existing value delimited by a comma if the key is found. + * + * @code + * #include + * + * mio_htb_walk_t print_map_pair (mio_htb_t* map, mio_htb_pair_t* pair, void* ctx) + * { + * mio_printf (MIO_T("%.*s[%d] => %.*s[%d]\n"), + * MIO_HTB_KLEN(pair), MIO_HTB_KPTR(pair), (int)MIO_HTB_KLEN(pair), + * MIO_HTB_VLEN(pair), MIO_HTB_VPTR(pair), (int)MIO_HTB_VLEN(pair)); + * return MIO_HTB_WALK_FORWARD; + * } + * + * mio_htb_pair_t* cbserter ( + * mio_htb_t* htb, mio_htb_pair_t* pair, + * void* kptr, mio_oow_t klen, void* ctx) + * { + * mio_cstr_t* v = (mio_cstr_t*)ctx; + * if (pair == MIO_NULL) + * { + * // no existing key for the key + * return mio_htb_allocpair (htb, kptr, klen, v->ptr, v->len); + * } + * else + * { + * // a pair with the key exists. + * // in this sample, i will append the new value to the old value + * // separated by a comma + * mio_htb_pair_t* new_pair; + * mio_ooch_t comma = MIO_T(','); + * mio_uint8_t* vptr; + * + * // allocate a new pair, but without filling the actual value. + * // note vptr is given MIO_NULL for that purpose + * new_pair = mio_htb_allocpair ( + * htb, kptr, klen, MIO_NULL, MIO_HTB_VLEN(pair) + 1 + v->len); + * if (new_pair == MIO_NULL) return MIO_NULL; + * + * // fill in the value space + * vptr = MIO_HTB_VPTR(new_pair); + * mio_memcpy (vptr, MIO_HTB_VPTR(pair), MIO_HTB_VLEN(pair)*MIO_SIZEOF(mio_ooch_t)); + * vptr += MIO_HTB_VLEN(pair)*MIO_SIZEOF(mio_ooch_t); + * mio_memcpy (vptr, &comma, MIO_SIZEOF(mio_ooch_t)); + * vptr += MIO_SIZEOF(mio_ooch_t); + * mio_memcpy (vptr, v->ptr, v->len*MIO_SIZEOF(mio_ooch_t)); + * + * // this callback requires the old pair to be destroyed + * mio_htb_freepair (htb, pair); + * + * // return the new pair + * return new_pair; + * } + * } + * + * int main () + * { + * mio_htb_t* s1; + * int i; + * mio_ooch_t* keys[] = { MIO_T("one"), MIO_T("two"), MIO_T("three") }; + * mio_ooch_t* vals[] = { MIO_T("1"), MIO_T("2"), MIO_T("3"), MIO_T("4"), MIO_T("5") }; + * + * mio_open_stdsios (); + * s1 = mio_htb_open ( + * MIO_MMGR_GETDFL(), 0, 10, 70, + * MIO_SIZEOF(mio_ooch_t), MIO_SIZEOF(mio_ooch_t) + * ); // note error check is skipped + * mio_htb_setstyle (s1, mio_get_htb_style(MIO_HTB_STYLE_INLINE_COPIERS)); + * + * for (i = 0; i < MIO_COUNTOF(vals); i++) + * { + * mio_cstr_t ctx; + * ctx.ptr = vals[i]; ctx.len = mio_count_oocstr(vals[i]); + * mio_htb_cbsert (s1, + * keys[i%MIO_COUNTOF(keys)], mio_count_oocstr(keys[i%MIO_COUNTOF(keys)]), + * cbserter, &ctx + * ); // note error check is skipped + * } + * mio_htb_walk (s1, print_map_pair, MIO_NULL); + * + * mio_htb_close (s1); + * mio_close_stdsios (); + * return 0; + * } + * @endcode + */ +MIO_EXPORT mio_htb_pair_t* mio_htb_cbsert ( + mio_htb_t* htb, /**< hash table */ + void* kptr, /**< key pointer */ + mio_oow_t klen, /**< key length */ + mio_htb_cbserter_t cbserter, /**< callback function */ + void* ctx /**< callback context */ +); + +/** + * The mio_htb_delete() function deletes a pair with a matching key + * @return 0 on success, -1 on failure + */ +MIO_EXPORT int mio_htb_delete ( + mio_htb_t* htb, /**< hash table */ + const void* kptr, /**< key pointer */ + mio_oow_t klen /**< key length */ +); + +/** + * The mio_htb_clear() function empties a hash table + */ +MIO_EXPORT void mio_htb_clear ( + mio_htb_t* htb /**< hash table */ +); + +/** + * The mio_htb_walk() function traverses a hash table. + */ +MIO_EXPORT void mio_htb_walk ( + mio_htb_t* htb, /**< hash table */ + mio_htb_walker_t walker, /**< callback function for each pair */ + void* ctx /**< pointer to user-specific data */ +); + +MIO_EXPORT void mio_init_htb_itr ( + mio_htb_itr_t* itr +); + +/** + * The mio_htb_getfirstpair() function returns the pointer to the first pair + * in a hash table. + */ +MIO_EXPORT mio_htb_pair_t* mio_htb_getfirstpair ( + mio_htb_t* htb, /**< hash table */ + mio_htb_itr_t* itr /**< iterator*/ +); + +/** + * The mio_htb_getnextpair() function returns the pointer to the next pair + * to the current pair @a pair in a hash table. + */ +MIO_EXPORT mio_htb_pair_t* mio_htb_getnextpair ( + mio_htb_t* htb, /**< hash table */ + mio_htb_itr_t* itr /**< iterator*/ +); + +/** + * The mio_htb_allocpair() function allocates a pair for a key and a value + * given. But it does not chain the pair allocated into the hash table @a htb. + * Use this function at your own risk. + * + * Take note of he following special behavior when the copier is + * #MIO_HTB_COPIER_INLINE. + * - If @a kptr is #MIO_NULL, the key space of the size @a klen is reserved but + * not propagated with any data. + * - If @a vptr is #MIO_NULL, the value space of the size @a vlen is reserved + * but not propagated with any data. + */ +MIO_EXPORT mio_htb_pair_t* mio_htb_allocpair ( + mio_htb_t* htb, + void* kptr, + mio_oow_t klen, + void* vptr, + mio_oow_t vlen +); + +/** + * The mio_htb_freepair() function destroys a pair. But it does not detach + * the pair destroyed from the hash table @a htb. Use this function at your + * own risk. + */ +MIO_EXPORT void mio_htb_freepair ( + mio_htb_t* htb, + mio_htb_pair_t* pair +); + +/** + * The mio_htb_dflhash() function is a default hash function. + */ +MIO_EXPORT mio_oow_t mio_htb_dflhash ( + const mio_htb_t* htb, + const void* kptr, + mio_oow_t klen +); + +/** + * The mio_htb_dflcomp() function is default comparator. + */ +MIO_EXPORT int mio_htb_dflcomp ( + const mio_htb_t* htb, + const void* kptr1, + mio_oow_t klen1, + const void* kptr2, + mio_oow_t klen2 +); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/mio/lib/mio-htre.h b/mio/lib/mio-htre.h index 9d04d6d..f76c036 100644 --- a/mio/lib/mio-htre.h +++ b/mio/lib/mio-htre.h @@ -49,21 +49,21 @@ typedef enum mio_htre_state_t mio_htre_state_t; typedef int (*mio_htre_concb_t) ( mio_htre_t* re, - const mio_mchar_t* ptr, - mio_size_t len, + const mio_bch_t* ptr, + mio_oow_t len, void* ctx ); struct mio_htre_hdrval_t { - const mio_mchar_t* ptr; - mio_size_t len; + const mio_bch_t* ptr; + mio_oow_t len; mio_htre_hdrval_t* next; }; struct mio_htre_t { - mio_mmgr_t* mmgr; + mio_t* mio; enum { @@ -73,7 +73,7 @@ struct mio_htre_t /* version */ mio_http_version_t version; - const mio_mchar_t* verstr; /* version string include HTTP/ */ + const mio_bch_t* verstr; /* version string include HTTP/ */ union { @@ -82,19 +82,19 @@ struct mio_htre_t struct { mio_http_method_t type; - const mio_mchar_t* name; + const mio_bch_t* name; } method; - mio_mcstr_t path; - mio_mcstr_t param; + mio_bcs_t path; + mio_bcs_t param; } q; struct { struct { int val; - mio_mchar_t* str; + mio_bch_t* str; } code; - mio_mchar_t* mesg; + mio_bch_t* mesg; } s; } u; @@ -111,18 +111,18 @@ struct mio_htre_t * meaningful if MIO_HTRE_QPATH_PERDEC is set in the flags */ struct { - mio_mchar_t* buf; /* buffer pointer */ - mio_size_t capa; /* buffer capacity */ + mio_bch_t* buf; /* buffer pointer */ + mio_oow_t capa; /* buffer capacity */ - mio_mchar_t* ptr; - mio_size_t len; + mio_bch_t* ptr; + mio_oow_t len; } orgqpath; /* special attributes derived from the header */ struct { - mio_size_t content_length; - const mio_mchar_t* status; /* for cgi */ + mio_oow_t content_length; + const mio_bch_t* status; /* for cgi */ } attr; /* header table */ @@ -130,7 +130,7 @@ struct mio_htre_t mio_htb_t trailers; /* content octets */ - mio_mbs_t content; + mio_htob_t content; /* content callback */ mio_htre_concb_t concb; @@ -164,7 +164,7 @@ struct mio_htre_t typedef int (*mio_htre_header_walker_t) ( mio_htre_t* re, - const mio_mchar_t* key, + const mio_bch_t* key, const mio_htre_hdrval_t* val, void* ctx ); @@ -175,7 +175,7 @@ extern "C" { MIO_EXPORT int mio_htre_init ( mio_htre_t* re, - mio_mmgr_t* mmgr + mio_t* mio ); MIO_EXPORT void mio_htre_fini ( @@ -188,12 +188,12 @@ MIO_EXPORT void mio_htre_clear ( MIO_EXPORT const mio_htre_hdrval_t* mio_htre_getheaderval ( const mio_htre_t* re, - const mio_mchar_t* key + const mio_bch_t* key ); MIO_EXPORT const mio_htre_hdrval_t* mio_htre_gettrailerval ( const mio_htre_t* re, - const mio_mchar_t* key + const mio_bch_t* key ); MIO_EXPORT int mio_htre_walkheaders ( @@ -217,8 +217,8 @@ MIO_EXPORT int mio_htre_walktrailers ( */ MIO_EXPORT int mio_htre_addcontent ( mio_htre_t* re, - const mio_mchar_t* ptr, - mio_size_t len + const mio_bch_t* ptr, + mio_oow_t len ); MIO_EXPORT void mio_htre_completecontent ( diff --git a/mio/lib/mio-http.h b/mio/lib/mio-http.h index 89b12aa..f780cc0 100644 --- a/mio/lib/mio-http.h +++ b/mio/lib/mio-http.h @@ -25,17 +25,17 @@ #ifndef _MIO_HTTP_H_ #define _MIO_HTTP_H_ -#include +#include /** \file * This file provides basic data types and functions for the http protocol. */ /* octet buffer */ -typedef mio_mbs_t mio_htob_t; +typedef mio_becs_t mio_htob_t; /* octet string */ -typedef mio_mcstr_t mio_htos_t; +typedef mio_bcs_t mio_htos_t; /** * The mio_http_version_t type defines http version. @@ -176,22 +176,23 @@ MIO_EXPORT const mio_bch_t* mio_httpmethodtombs ( mio_http_method_t type ); -MIO_EXPORT mio_http_method_t mio_mbstohttpmethod ( +MIO_EXPORT mio_http_method_t mio_bcstr_to_http_method ( const mio_bch_t* name ); -MIO_EXPORT mio_http_method_t mio_mcstrtohttpmethod ( - const mio_mcstr_t* name +MIO_EXPORT mio_http_method_t mio_bchars_to_http_method ( + const mio_bch_t* nameptr, + mio_oow_t namelen ); -MIO_EXPORT int mio_parsehttprange ( - const mio_bch_t* str, +MIO_EXPORT int mio_parse_http_range_bcstr ( + const mio_bch_t* str, mio_http_range_t* range ); -MIO_EXPORT int mio_parsehttptime ( +MIO_EXPORT int mio_parse_http_time_bcstr ( const mio_bch_t* str, - mio_ntime_t* nt + mio_ntime_t* nt ); MIO_EXPORT mio_bch_t* mio_fmthttptime ( @@ -201,10 +202,10 @@ MIO_EXPORT mio_bch_t* mio_fmthttptime ( ); /** - * The mio_isperencedhttpstr() function determines if the given string + * The mio_is_perenced_http_bcstr() function determines if the given string * contains a valid percent-encoded sequence. */ -MIO_EXPORT int mio_isperencedhttpstr ( +MIO_EXPORT int mio_is_perenced_http_bcstr ( const mio_bch_t* str );