From: Eugene Syromyatnikov <evgsyr@gmail.com>
Date: Mon, 2 Apr 2018 18:01:56 +0000 (+0200)
Subject: Add support for value-indexed xlats
X-Git-Tag: v4.23~263
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=25d6ed1600eed45a485879113d1c6846b06b8bdc;p=strace

Add support for value-indexed xlats

There are quite a few xlats that start from 0 and not too sparse,
we can push the search time for them down to O(1).

* defs.h (printxval_indexn_ex): New declaration.
(printxval_indexn, printxval_index, printxval_index_ex): New macros.
* xlat.c (printxval_sized): Rename from printxval_searchn_ex,
add fn argument, call it instead of xlat_search.
(printxval_searchn_ex): Implement as a thin wrapper around
printxval_sized using xlat_search as a search function.
(xlat_idx): New function.
(printxval_indexn_ex): New function, a thin wrapper around
printxval_sized using xlat_idx as a search function.
* xlat/gen.sh: Add support for "#value_indexed" directive.
---

diff --git a/defs.h b/defs.h
index b2d683db..72789e26 100644
--- a/defs.h
+++ b/defs.h
@@ -645,6 +645,16 @@ extern int printxval_searchn_ex(const struct xlat *xlat, size_t xlat_size,
 #define printxval_search_ex(xlat__, val__, dflt__) \
 	printxval_searchn_ex((xlat__), ARRAY_SIZE(xlat__) - 1, (val__), \
 			     (dflt__), XLAT_STYLE_DEFAULT)
+extern int printxval_indexn_ex(const struct xlat *xlat, size_t xlat_size,
+	uint64_t val, const char *dflt, enum xlat_style style);
+#define printxval_indexn(xlat_, xlat_size_, val_, dflt_) \
+	printxval_indexn_ex((xlat_), (xlat_size_), (val_), (dflt_), \
+			    XLAT_STYLE_DEFAULT)
+#define printxval_index(xlat__, val__, dflt__) \
+	printxval_indexn(xlat__, ARRAY_SIZE(xlat__) - 1, val__, dflt__)
+#define printxval_index_ex(xlat__, val__, dflt__) \
+	printxval_indexn_ex((xlat__), ARRAY_SIZE(xlat__) - 1, (val__), \
+			    (dflt__), XLAT_STYLE_DEFAULT)
 extern int sprintxval_ex(char *buf, size_t size, const struct xlat *xlat,
 			 unsigned int val, const char *dflt,
 			 enum xlat_style style);
diff --git a/xlat.c b/xlat.c
index d52d1b10..476a89cd 100644
--- a/xlat.c
+++ b/xlat.c
@@ -184,12 +184,14 @@ sprintxval_ex(char *const buf, const size_t size, const struct xlat *const x,
  * @param dflt      String (abbreviated in comment syntax) which should be
  *                  emitted if no appropriate xlat value has been found.
  * @param style     Style in which xlat value should be printed.
+ * @param fn        Search function.
  * @return          1 if appropriate xlat value has been found, 0
  *                  otherwise.
  */
-int
-printxval_searchn_ex(const struct xlat *xlat, size_t xlat_size, uint64_t val,
-		     const char *dflt, enum xlat_style style)
+static int
+printxval_sized(const struct xlat *xlat, size_t xlat_size, uint64_t val,
+		const char *dflt, enum xlat_style style,
+		const char *(* fn)(const struct xlat *, size_t, uint64_t))
 {
 	style = get_xlat_style(style);
 
@@ -198,7 +200,7 @@ printxval_searchn_ex(const struct xlat *xlat, size_t xlat_size, uint64_t val,
 		return 0;
 	}
 
-	const char *s = xlat_search(xlat, xlat_size, val);
+	const char *s = fn(xlat, xlat_size, val);
 
 	if (s) {
 		if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
@@ -216,6 +218,37 @@ printxval_searchn_ex(const struct xlat *xlat, size_t xlat_size, uint64_t val,
 	return 0;
 }
 
+int
+printxval_searchn_ex(const struct xlat *xlat, size_t xlat_size, uint64_t val,
+		     const char *dflt, enum xlat_style style)
+{
+	return printxval_sized(xlat, xlat_size, val, dflt, style,
+				  xlat_search);
+}
+
+static const char *
+xlat_idx(const struct xlat *xlat, size_t nmemb, uint64_t val)
+{
+	if (val >= nmemb)
+		return NULL;
+
+	if (val != xlat[val].val) {
+		error_func_msg("Unexpected xlat value %" PRIu64
+			       " at index %" PRIu64,
+			       xlat[val].val, val);
+		return NULL;
+	}
+
+	return xlat[val].str;
+}
+
+int
+printxval_indexn_ex(const struct xlat *xlat, size_t xlat_size, uint64_t val,
+		    const char *dflt, enum xlat_style style)
+{
+	return printxval_sized(xlat, xlat_size, val, dflt, style, xlat_idx);
+}
+
 /*
  * Interpret `xlat' as an array of flags.
  * Print to static string the entries whose bits are on in `flags'
diff --git a/xlat/gen.sh b/xlat/gen.sh
index 170163cb..aff79922 100755
--- a/xlat/gen.sh
+++ b/xlat/gen.sh
@@ -65,6 +65,7 @@ print_xlat()
 	local val
 	val="$1"; shift
 
+	[ 1 = "$value_indexed" ] && printf " [%s] =" "${val}"
 	if [ -z "${val_type-}" ]; then
 		echo " XLAT(${val}),"
 	else
@@ -78,6 +79,7 @@ print_xlat_pair()
 	val="$1"; shift
 	str="$1"; shift
 
+	[ 1 = "$value_indexed" ] && printf " [%s] =" "${val}"
 	if [ -z "${val_type-}" ]; then
 		echo " XLAT_PAIR(${val}, \"${str}\"),"
 	else
@@ -123,6 +125,8 @@ gen_header()
 	local decl="extern const struct xlat ${name}[];"
 	local in_defs= in_mpers=
 
+	value_indexed=0
+
 	if grep -F -x "$decl" "$defs" > /dev/null; then
 		in_defs=1
 	elif grep -F -x "$decl" "$mpers" > /dev/null; then
@@ -151,6 +155,9 @@ gen_header()
 		'#val_type '*)
 			# to be processed during 2nd pass
 			;;
+		'#value_indexed')
+			value_indexed=1
+			;;
 		'#'*)
 			echo "${line}"
 			;;
@@ -206,6 +213,8 @@ gen_header()
 		'#unconditional')
 			unconditional=1
 			;;
+		'#value_indexed')
+			;;
 		'#val_type '*)
 			val_type="${line#\#val_type }"
 			;;