/* Copyright (c) 2019, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. * Neither the name of Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 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 OWNER 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. */ /** @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; }