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 *);

Reply via email to