/* Copyright (c) 2019-2023, Intel Corporation SPDX-License-Identifier: BSD-3-Clause */ /** @file builtins-c-common.cpp @brief Basic methods for print implementations. Currenly is used by __do_print This library provides instruments for parsing ISPC print format strings, some useful adapters, and other minor helper instruments. FIXME: this file can be included only after StaticString, StaticStringRef, SizeT, RES_STR_SIZE, ARG_STR_SIZE are defined. Can be fixed with an additional template argument, but only when CMC includes are fixed. */ #include "src/builtins-info.h" namespace details { template inline T ValueAdapterImpl(T val) { return val; } static inline const char *ValueAdapterImpl(bool val) { return val ? "true" : "false"; } // Copies everything from src (starting from srcIdx) to dst (starting from dstIdx), until it meets a separator. // Separators are defined by SEPS. // T is anything indexable, meaning you can write src[idx] template inline int CopyTillSep(T src, int srcIdx, StaticStringRef dst, int dstIdx, int leftSpace) { const auto origDstIdx = dstIdx; while (((src[srcIdx] != SEPS) && ...) && leftSpace) { dst[dstIdx++] = src[srcIdx++]; --leftSpace; } return dstIdx - origDstIdx; } // FIXME: ugly copy-paste to work around cmc frontend issues. Remove it when CMC includes are fixed. template inline int CopyTillSep(StaticStringRef src, int srcIdx, StaticStringRef dst, int dstIdx, int leftSpace) { const auto origDstIdx = dstIdx; while (((src[srcIdx] != SEPS) && ...) && leftSpace) { dst[dstIdx++] = src[srcIdx++]; --leftSpace; } return dstIdx - origDstIdx; } // If type encodes uniform T, function puts result of uniform2Str() in res and returns true, // otherwise it does nothing with res and returns false. template inline bool UniArg2StrIfSuitable(char type, ArgWriter &argWriter, StaticStringRef res) { if (type == PrintInfo::getEncoding4Uniform()) { res = argWriter.template uniform2Str(); return true; } return false; } // If type encodes varying T, function puts result of varying2Str() in res and returns true, // otherwise it does nothing with res and returns false. template inline bool VarArg2StrIfSuitable(char type, ArgWriter &argWriter, StaticStringRef res) { if (type == PrintInfo::getEncoding4Varying()) { res = argWriter.template varying2Str(); return true; } return false; } // If type encodes uniform T or varying T, function calls corresponding *2Str method, writes its result into res, // returns true, otherwise function does nothing with res and returns false. template inline bool Arg2StrIfSuitable(char type, ArgWriter &argWriter, StaticStringRef res) { return UniArg2StrIfSuitable(type, argWriter, res) || VarArg2StrIfSuitable(type, argWriter, res); } // Requests the next argument from argWriter. Relies on uniform2Str and varying2Str methods of argWriter. // T is deduced from provided type argument. Returns the string representation of the argument returned from // uniform2Str or varying2Str. template inline StaticString Arg2Str(char type, ArgWriter &argWriter) { StaticString res; Arg2StrIfSuitable(type, argWriter, res) || Arg2StrIfSuitable(type, argWriter, res) || Arg2StrIfSuitable(type, argWriter, res) || Arg2StrIfSuitable(type, argWriter, res) || Arg2StrIfSuitable(type, argWriter, res) || Arg2StrIfSuitable(type, argWriter, res) || Arg2StrIfSuitable(type, argWriter, res) || Arg2StrIfSuitable(type, argWriter, res); return res; } } // namespace details const char UnsupportedTypeStr[] = "UNSUPPORTED TYPE"; const char OffLaneBoolStr[] = "_________"; // For every T except bool it just returns the same value. // In this case value must have T type. // For T==bool it returns const char* to "true" or "false". // // Function is presumed to be used only for integral types. template inline auto ValueAdapter(T val) { return details::ValueAdapterImpl(val); } // Copies everything from src to dst (starting from dstIdx), until it meets '%' or '\0' // Doesn't copy '%' or '\0'. Doesn't null terminate dst string. template inline int CopyPlainText(const char *const src, StaticStringRef dst, const int dstIdx, const int leftSpace) { return details::CopyTillSep<'%', '\0'>(src, 0, dst, dstIdx, leftSpace); } // Copies everything from src to dst (starting from dstIdx), until it meets '\0' (whole string). // Doesn't copy '\0', so dst string is not null terminated. template inline int CopyFullText(const char *const src, StaticStringRef dst, const int dstIdx, const int leftSpace) { return details::CopyTillSep<'\0'>(src, 0, dst, dstIdx, leftSpace); } // Copies everything from src (starting from srcIdx) to dst (starting from dstIdx), until it meets '\0' (whole string). // Doesn't copy '\0', so dst string is not null terminated. template inline int CopyFullText(StaticStringRef src, const int srcIdx, StaticStringRef dst, const int dstIdx, const int leftSpace) { return details::CopyTillSep<'\0'>(src, srcIdx, dst, dstIdx, leftSpace); } // This function parses format string and string of arg types. // User must implement ArgWriter class, which has such template methods as uniform2Str and varying2Str. // Those functions must return text representation (c-string) of the next argument, the type of argument is provided // with the template parameter. Returned c-string is placed instead of '%' in format string. // The function returns resulting string. template inline StaticString GetFormatedStr(const char *format, const char *types, ArgWriter &argWriter) { StaticString resultingStr; int haveBeenWritten = 0; int leftSpace = RES_STR_SIZE - 1; // space for null terminator for (;; ++format, ++types) { auto wereCopied = CopyPlainText(format, resultingStr, haveBeenWritten, leftSpace); format += wereCopied; haveBeenWritten += wereCopied; leftSpace -= wereCopied; if (!leftSpace || *format == '\0') { // reached the end of format or limits of resultingStr break; } StaticString argStr = details::Arg2Str(*types, argWriter); wereCopied = CopyFullText(argStr, 0, resultingStr, haveBeenWritten, leftSpace); haveBeenWritten += wereCopied; leftSpace -= wereCopied; } resultingStr[haveBeenWritten] = '\0'; return resultingStr; }