Module Name: src Committed By: rillig Date: Sun Apr 11 12:06:53 UTC 2021
Modified Files: src/usr.bin/make: make.h nonints.h Added Files: src/usr.bin/make: str.h Log Message: make: add types Substring and LazyBuf These will be used for making the string handling more efficient, avoiding allocations, especially when evaluating variable expressions. Since the string handling has grown quite a bit in the last months, extract it into its own header file. No functional change. To generate a diff of this commit: cvs rdiff -u -r1.260 -r1.261 src/usr.bin/make/make.h cvs rdiff -u -r1.211 -r1.212 src/usr.bin/make/nonints.h cvs rdiff -u -r0 -r1.1 src/usr.bin/make/str.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.bin/make/make.h diff -u src/usr.bin/make/make.h:1.260 src/usr.bin/make/make.h:1.261 --- src/usr.bin/make/make.h:1.260 Sun Apr 4 10:05:08 2021 +++ src/usr.bin/make/make.h Sun Apr 11 12:06:53 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: make.h,v 1.260 2021/04/04 10:05:08 rillig Exp $ */ +/* $NetBSD: make.h,v 1.261 2021/04/11 12:06:53 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -149,10 +149,11 @@ typedef unsigned int Boolean; #include "lst.h" #include "enum.h" +#include "make_malloc.h" +#include "str.h" #include "hash.h" #include "config.h" #include "buf.h" -#include "make_malloc.h" /* * The typical flow of states is: Index: src/usr.bin/make/nonints.h diff -u src/usr.bin/make/nonints.h:1.211 src/usr.bin/make/nonints.h:1.212 --- src/usr.bin/make/nonints.h:1.211 Sun Apr 4 11:56:43 2021 +++ src/usr.bin/make/nonints.h Sun Apr 11 12:06:53 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: nonints.h,v 1.211 2021/04/04 11:56:43 rillig Exp $ */ +/* $NetBSD: nonints.h,v 1.212 2021/04/11 12:06:53 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -166,112 +166,6 @@ void Parse_SetInput(const char *, int, i void Parse_MainName(GNodeList *); int Parse_GetFatals(void); -/* str.c */ - -/* A read-only string that may need to be freed after use. */ -typedef struct FStr { - const char *str; - void *freeIt; -} FStr; - -/* A modifiable string that may need to be freed after use. */ -typedef struct MFStr { - char *str; - void *freeIt; -} MFStr; - -typedef struct Words { - char **words; - size_t len; - void *freeIt; -} Words; - -#if __STDC_VERSION__ >= 199901L -# define FStr_Literal(str, freeIt) (FStr) { str, freeIt } -#else -MAKE_INLINE FStr -FStr_Literal(const char *str, void *freeIt) -{ - FStr fstr; - fstr.str = str; - fstr.freeIt = freeIt; - return fstr; -} -#endif - -/* Return a string that is the sole owner of str. */ -MAKE_INLINE FStr -FStr_InitOwn(char *str) -{ - return FStr_Literal(str, str); -} - -/* Return a string that refers to the shared str. */ -MAKE_INLINE FStr -FStr_InitRefer(const char *str) -{ - return FStr_Literal(str, NULL); -} - -MAKE_INLINE void -FStr_Done(FStr *fstr) -{ - free(fstr->freeIt); -#ifdef CLEANUP - fstr->str = NULL; - fstr->freeIt = NULL; -#endif -} - -#if __STDC_VERSION__ >= 199901L -# define MFStr_Literal(str, freeIt) (MFStr) { str, freeIt } -#else -MAKE_INLINE MFStr -MFStr_Literal(char *str, void *freeIt) -{ - MFStr mfstr; - mfstr.str = str; - mfstr.freeIt = freeIt; - return mfstr; -} -#endif - -/* Return a string that is the sole owner of str. */ -MAKE_INLINE MFStr -MFStr_InitOwn(char *str) -{ - return MFStr_Literal(str, str); -} - -/* Return a string that refers to the shared str. */ -MAKE_INLINE MFStr -MFStr_InitRefer(char *str) -{ - return MFStr_Literal(str, NULL); -} - -MAKE_INLINE void -MFStr_Done(MFStr *mfstr) -{ - free(mfstr->freeIt); -#ifdef CLEANUP - mfstr->str = NULL; - mfstr->freeIt = NULL; -#endif -} - -Words Str_Words(const char *, bool); -MAKE_INLINE void -Words_Free(Words w) -{ - free(w.words); - free(w.freeIt); -} - -char *str_concat2(const char *, const char *); -char *str_concat3(const char *, const char *, const char *); -char *str_concat4(const char *, const char *, const char *, const char *); -bool Str_Match(const char *, const char *); /* suff.c */ void Suff_Init(void); Added files: Index: src/usr.bin/make/str.h diff -u /dev/null src/usr.bin/make/str.h:1.1 --- /dev/null Sun Apr 11 12:06:53 2021 +++ src/usr.bin/make/str.h Sun Apr 11 12:06:53 2021 @@ -0,0 +1,269 @@ +/* $NetBSD: str.h,v 1.1 2021/04/11 12:06:53 rillig Exp $ */ + +/* + Copyright (c) 2021 Roland Illig <ril...@netbsd.org> + 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 COPYRIGHT HOLDERS AND CONTRIBUTORS + "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 COPYRIGHT HOLDER OR CONTRIBUTORS + 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. + */ + + +/* + * Memory-efficient string handling. + */ + + +/* A read-only string that may need to be freed after use. */ +typedef struct FStr { + const char *str; + void *freeIt; +} FStr; + +/* A modifiable string that may need to be freed after use. */ +typedef struct MFStr { + char *str; + void *freeIt; +} MFStr; + +/* A read-only range of a character array, NOT null-terminated. */ +typedef struct { + const char *start; + const char *end; +} Substring; + +/* + * Builds a string, only allocating memory if the string is different from the + * expected string. + */ +typedef struct LazyBuf { + char *data; + size_t len; + size_t cap; + Substring expected; + void *freeIt; +} LazyBuf; + +/* The result of splitting a string into words. */ +typedef struct Words { + char **words; + size_t len; + void *freeIt; +} Words; + + +MAKE_INLINE FStr +FStr_Init(const char *str, void *freeIt) +{ + FStr fstr; + fstr.str = str; + fstr.freeIt = freeIt; + return fstr; +} + +/* Return a string that is the sole owner of str. */ +MAKE_INLINE FStr +FStr_InitOwn(char *str) +{ + return FStr_Init(str, str); +} + +/* Return a string that refers to the shared str. */ +MAKE_INLINE FStr +FStr_InitRefer(const char *str) +{ + return FStr_Init(str, NULL); +} + +MAKE_INLINE void +FStr_Done(FStr *fstr) +{ + free(fstr->freeIt); +#ifdef CLEANUP + fstr->str = NULL; + fstr->freeIt = NULL; +#endif +} + + +MAKE_INLINE MFStr +MFStr_Init(char *str, void *freeIt) +{ + MFStr mfstr; + mfstr.str = str; + mfstr.freeIt = freeIt; + return mfstr; +} + +/* Return a string that is the sole owner of str. */ +MAKE_INLINE MFStr +MFStr_InitOwn(char *str) +{ + return MFStr_Init(str, str); +} + +/* Return a string that refers to the shared str. */ +MAKE_INLINE MFStr +MFStr_InitRefer(char *str) +{ + return MFStr_Init(str, NULL); +} + +MAKE_INLINE void +MFStr_Done(MFStr *mfstr) +{ + free(mfstr->freeIt); +#ifdef CLEANUP + mfstr->str = NULL; + mfstr->freeIt = NULL; +#endif +} + + +MAKE_INLINE Substring +Substring_Init(const char *start, const char *end) +{ + Substring sub; + + sub.start = start; + sub.end = end; + return sub; +} + +MAKE_INLINE Substring +Substring_InitStr(const char *str) +{ + return Substring_Init(str, str + strlen(str)); +} + +MAKE_INLINE size_t +Substring_Length(Substring sub) +{ + return (size_t)(sub.end - sub.start); +} + +MAKE_INLINE bool +Substring_Equals(Substring sub, const char *str) +{ + size_t len = strlen(str); + return Substring_Length(sub) == len && + memcmp(sub.start, str, len) == 0; +} + +MAKE_INLINE Substring +Substring_Sub(Substring sub, size_t start, size_t end) +{ + assert(start <= Substring_Length(sub)); + assert(end <= Substring_Length(sub)); + return Substring_Init(sub.start + start, sub.start + end); +} + +MAKE_INLINE FStr +Substring_Str(Substring sub) +{ + return FStr_InitOwn(bmake_strsedup(sub.start, sub.end)); +} + + +MAKE_INLINE void +LazyBuf_Init(LazyBuf *buf, Substring expected) +{ + buf->data = NULL; + buf->len = 0; + buf->cap = 0; + buf->expected = expected; + buf->freeIt = NULL; +} + +MAKE_INLINE void +LazyBuf_Done(LazyBuf *buf) +{ + free(buf->freeIt); +} + +MAKE_INLINE void +LazyBuf_Add(LazyBuf *buf, char ch) +{ + + if (buf->data != NULL) { + if (buf->len == buf->cap) { + buf->cap *= 2; + buf->data = bmake_realloc(buf->data, buf->cap); + } + buf->data[buf->len++] = ch; + + } else if (buf->len < Substring_Length(buf->expected) && + ch == buf->expected.start[buf->len]) { + buf->len++; + return; + + } else { + buf->cap = buf->len + 16; + buf->data = bmake_malloc(buf->cap); + memcpy(buf->data, buf->expected.start, buf->len); + buf->data[buf->len++] = ch; + } +} + +MAKE_INLINE void +LazyBuf_AddStr(LazyBuf *buf, const char *str) +{ + const char *p; + + for (p = str; *p != '\0'; p++) + LazyBuf_Add(buf, *p); +} + +MAKE_INLINE Substring +LazyBuf_Get(const LazyBuf *buf) +{ + const char *start = buf->data != NULL + ? buf->data : buf->expected.start; + return Substring_Init(start, start + buf->len); +} + +MAKE_INLINE FStr +LazyBuf_DoneGet(LazyBuf *buf) +{ + if (buf->data != NULL) { + LazyBuf_Add(buf, '\0'); + return FStr_InitOwn(buf->data); + } + return Substring_Str(LazyBuf_Get(buf)); +} + + +Words Str_Words(const char *, bool); + +MAKE_INLINE void +Words_Free(Words w) +{ + free(w.words); + free(w.freeIt); +} + + +char *str_concat2(const char *, const char *); +char *str_concat3(const char *, const char *, const char *); +char *str_concat4(const char *, const char *, const char *, const char *); + +bool Str_Match(const char *, const char *);