Example #1
0
FASTFORMAT_CALL(size_t) fastformat_fillReplacements(
    string_slice_t*                 resultElements      // Pointer to receiver of result slices
,   format_element_t const*         formatElements      // Pointer to format elements
,   size_t                          numFormatElements
,   string_slice_t const*           arguments           // Pointer to arguments
,   size_t                          numArguments
,   fastformat_mismatchedHandler_t  handler
,   void*                           param
,   size_t*                         pnumResultElements
)
{
    FASTFORMAT_COVER_MARK_ENTRY();

    FASTFORMAT_CONTRACT_ENFORCE_PRECONDITION_PARAMS_API(NULL != resultElements, "result elements may not be null");
    FASTFORMAT_CONTRACT_ENFORCE_PRECONDITION_PARAMS_API(NULL != pnumResultElements, "result element count pointer may not be null");
    FASTFORMAT_CONTRACT_ENFORCE_PRECONDITION_PARAMS_API((NULL != formatElements || 0 == numFormatElements), "pattern elements may not be null, unless numFormatElements is 0");
    FASTFORMAT_CONTRACT_ENFORCE_PRECONDITION_PARAMS_API((0 != numArguments) == (NULL != arguments), "arguments can only be null when there are 0 arguments, and vice versa");

    mismatched_handler_info_t   handler_info        =   { handler, param };
    size_t                      cchTotal            =   0;
    string_slice_t              defaultSlice        =   {   0,  NULL    };
    int                         handlerReturned     =   0;
    string_slice_t* const       resultElementsBase  =   resultElements;

#ifndef FASTFORMAT_DO_NOT_DETECT_UNREFERENCED_ARGUMENTS
    stlsoft::auto_buffer<unreferenced_argument_flag_t>   argumentReferenceFlags(numArguments);

    std::fill(argumentReferenceFlags.begin(), argumentReferenceFlags.end(), 0);
#endif /* !FASTFORMAT_DO_NOT_DETECT_UNREFERENCED_ARGUMENTS */

    if(NULL == handler_info.handler)
    {
        FASTFORMAT_COVER_MARK_ENTRY();

        handler_info = fastformat_getThreadMismatchedHandler();
    }

    if(NULL == handler_info.handler)
    {
        FASTFORMAT_COVER_MARK_ENTRY();

        handler_info = fastformat_getProcessMismatchedHandler();
    }

    if(NULL == handler_info.handler)
    {
        FASTFORMAT_COVER_MARK_ENTRY();

    handler_info = fastformat_getDefaultMismatchedHandler();
    }

    // Process every format element:
    //
    //  - if literal, copy over
    //  - if replacement, lookup argument and copy over/report mismatch
    //  - if spacer, evaluate whether spacing needed, and then
    { for(size_t i = 0; i != numFormatElements; ++i, ++resultElements)
    {
        FASTFORMAT_COVER_MARK_ENTRY();

        format_element_t const& pattern_element = formatElements[i];

        if(FASTFORMAT_INTERNAL_FORMAT_ELEMENT_INDEX_LITERAL_ == pattern_element.index)
        {
            // A literal fragment, so just copy into destination

            FASTFORMAT_COVER_MARK_ENTRY();

            resultElements->len  =   pattern_element.len;
            resultElements->ptr  =   pattern_element.ptr;

            cchTotal += pattern_element.len;
        }
        else
        {
            // A replacement parameter, so work out whether to truncate or
            // to insert any fill slices (before, after, or both)
            //
            // 1. If a maximum width is specified and the source slice
            //    length is greater than the maximum, then we truncate
            // 2. If a minimum width is specified and the source slice
            //    length is less than the minimum, then we insert one or
            //    more slices:
            // 2.a. If left-aligned, then we insert a pad slice after
            //      the current slice
            // 2.b. If right-aligned, then we insert a pad slice before
            //      the current slice
            // 2.c. If centre-aligned, then we insert pad slices before
            //      and after the current slice
            // 3. If none of these are satisfied, then copy over the
            //    source slice as-is

            // But, first, we need to validate the index
            if(pattern_element.index >= static_cast<int>(numArguments))
            {
                // Pattern element index is out of range, e.g. fmtln(sink, "val0={2}", v0, v1);

                FASTFORMAT_COVER_MARK_ENTRY();

                FASTFORMAT_CONTRACT_ENFORCE_ASSUMPTION(NULL != handler_info.handler);

                if(handlerReturned >= 0)
                {
                    handlerReturned = (*handler_info.handler)(handler_info.param, FF_REPLACEMENTCODE_MISSING_ARGUMENT, numArguments, pattern_element.index, &defaultSlice, NULL, 0, NULL);
                }

                // Handler has returned, so no exception has been thrown
                //
                // If 0, insert the pattern_element, otherwise insert the
                // default slice.

                if(handlerReturned != 0)
                {
                    FASTFORMAT_COVER_MARK_ENTRY();

#if 0
                    // We cannot take the default slice, because the application has
                    // not provided any space for us to write it, so ...
                    resultElements->len  =   defaultSlice.len;
                    resultElements->ptr  =   defaultSlice.ptr;
#else /* ? 0 */
                    // ... we skip it (by decrementing in anticipation of the increment
                    // as we loop round again).
                    --resultElements;
#endif /* 0 */
                }
                else
                {
                    FASTFORMAT_COVER_MARK_ENTRY();

                    resultElements->len  =   pattern_element.len;
                    resultElements->ptr  =   pattern_element.ptr;
                }
            }
            else
            {
                string_slice_t const&   src_slice = arguments[pattern_element.index];
                ff_char_t const*        (FASTFORMAT_CALLCONV* pfnFill)(size_t) = ('#' == pattern_element.fill) ? fastformat_getHashesSlice : fastformat_getSpacesSlice;

                if( pattern_element.maxWidth >= 0 &&
                    size_t(pattern_element.maxWidth) < src_slice.len)
                {
                    // Truncating, so see if we're truncating left/centre/right

                    resultElements->len = pattern_element.maxWidth;

                    switch(pattern_element.alignment)
                    {
                        default:
                            FASTFORMAT_CONTRACT_ENFORCE_UNEXPECTED_CONDITION_INTERNAL("invalid enumerator");
                        case    FASTFORMAT_ALIGNMENT_NONE:
                        case    FASTFORMAT_ALIGNMENT_RIGHT:
                            resultElements->ptr = src_slice.ptr + (src_slice.len - pattern_element.maxWidth);
                            break;
                        case    FASTFORMAT_ALIGNMENT_CENTRE:
                            resultElements->ptr = src_slice.ptr + (src_slice.len - pattern_element.maxWidth) / 2;
                            break;
                        case    FASTFORMAT_ALIGNMENT_LEFT:
                            resultElements->ptr = src_slice.ptr;
                            break;
                    }

                    cchTotal += pattern_element.maxWidth;
                }
                else if(0 != pattern_element.minWidth &&
                        size_t(pattern_element.minWidth) > src_slice.len)
                {
                    switch(pattern_element.alignment)
                    {
                        default:
                            FASTFORMAT_CONTRACT_ENFORCE_UNEXPECTED_CONDITION_INTERNAL("invalid enumerator");
                        case    FASTFORMAT_ALIGNMENT_NONE:
                        case    FASTFORMAT_ALIGNMENT_RIGHT:
                            // insert a spaces slice before the source slice
                            resultElements->len = size_t(pattern_element.minWidth) - src_slice.len;
                            resultElements->ptr = pfnFill(resultElements->len);

                            ++resultElements;

                            resultElements->len = src_slice.len;
                            resultElements->ptr = src_slice.ptr;
                            break;
                        case    FASTFORMAT_ALIGNMENT_CENTRE:
                            // insert a spaces slice before and after the source slice
                            resultElements->len = (size_t(pattern_element.minWidth) - src_slice.len) / 2;
                            resultElements->ptr = pfnFill(resultElements->len);

                            ++resultElements;

                            resultElements->len = src_slice.len;
                            resultElements->ptr = src_slice.ptr;

                            ++resultElements;

                            resultElements->len = size_t(pattern_element.minWidth) - (resultElements[-1].len + resultElements[-2].len);
                            resultElements->ptr = pfnFill(resultElements->len);
                            break;
                        case    FASTFORMAT_ALIGNMENT_LEFT:
                            // insert a spaces slice after the source slice
                            resultElements->len = src_slice.len;
                            resultElements->ptr = src_slice.ptr;

                            ++resultElements;

                            resultElements->len = size_t(pattern_element.minWidth) - src_slice.len;
                            resultElements->ptr = pfnFill(resultElements->len);
                            break;
                    }

                    cchTotal += pattern_element.minWidth;
                }
                else
                {
                    // Not truncating, so just copy over

                    resultElements->len = src_slice.len;
                    resultElements->ptr = src_slice.ptr;

                    cchTotal += src_slice.len;
                }
            }

#ifndef FASTFORMAT_DO_NOT_DETECT_UNREFERENCED_ARGUMENTS
            // Have to do a runtime test here, in case where additional
            // arguments are specified (and exception suppressed by use of
            // fastformat::ignore_missing_arguments_scope).
            if(size_t(pattern_element.index) < argumentReferenceFlags.size())
            {
                argumentReferenceFlags[size_t(pattern_element.index)] = 1;
            }
#endif /* !FASTFORMAT_DO_NOT_DETECT_UNREFERENCED_ARGUMENTS */
        }
    }}

#ifndef FASTFORMAT_DO_NOT_DETECT_UNREFERENCED_ARGUMENTS
    stlsoft::auto_buffer<unreferenced_argument_flag_t>::iterator it;

    if(argumentReferenceFlags.end() != (it = std::find(argumentReferenceFlags.begin(), argumentReferenceFlags.end(), 0)))
    {
        int firstMismatchedReplacementIndex = static_cast<int>(it - argumentReferenceFlags.begin());

        FASTFORMAT_CONTRACT_ENFORCE_ASSUMPTION(NULL != handler_info.handler);

        (*handler_info.handler)(handler_info.param, FF_REPLACEMENTCODE_UNREFERENCED_ARGUMENT, numArguments, firstMismatchedReplacementIndex, NULL, NULL, 0, NULL);
    }
#endif /* !FASTFORMAT_DO_NOT_DETECT_UNREFERENCED_ARGUMENTS */

    if(0 != handlerReturned)
    {
        FASTFORMAT_COVER_MARK_ENTRY();

        FASTFORMAT_CONTRACT_ENFORCE_ASSUMPTION(NULL != handler_info.handler);

        (*handler_info.handler)(handler_info.param, FF_REPLACEMENTCODE_SUCCESS, numArguments, -1, NULL, NULL, 0, NULL);
    }

    *pnumResultElements = static_cast<size_t>(resultElements - resultElementsBase);

    return cchTotal;
}
Example #2
0
inline stlsoft::basic_shim_string<ff_char_t, 64> real_helper_4(
    double const&       value
,   int                 minimumWidth
,   int                 precision
,   ff_char_t const*    specifier
)
{
    ff_char_t   type    =   'f';
    ff_char_t   fmt_[]  =   FASTFORMAT_LITERAL_STRING("%-01234567890123456789.01234567890123456789f");
    ff_char_t*  fmt     =   fmt_;

    if(NULL != specifier)
    {
        type = *specifier;
    }

    if( default_width_sentinel_() == minimumWidth &&
        precision < 0)
    {
        fmt[1] = type;
        fmt[2] = '\0';
    }
    else
    {
        if(default_width_sentinel_() == minimumWidth)
        {
            minimumWidth = 0;
        }
        if(precision < 0)
        {
            precision = 0;
        }

        // Performance tests show a substantial advantage in using
        // integer_to_string() over fastformat_util_snprintf()

#if 0

        int n = fastformat_util_snprintf(&fmt[0], STLSOFT_NUM_ELEMENTS(fmt_) - 1, FASTFORMAT_LITERAL_STRING("%%%d.%d%c"), minimumWidth, precision, type);

        FASTFORMAT_CONTRACT_ENFORCE_ASSUMPTION((n > 0) && (n < int(STLSOFT_NUM_ELEMENTS(fmt_)) - 1));

        fmt[n] = '\0';

#else /* ? 0 */

        const size_t    fmtDim  =   STLSOFT_NUM_ELEMENTS(fmt_) - 1;
        ff_char_t*      end     =   &fmt[fmtDim];
        size_t          n1;
        size_t          n2;

        stlsoft::integer_to_string(end - 21, 21, precision, &n1);
        *--end = type;
        end -= n1;
        stlsoft::integer_to_string(end - 21, 21, minimumWidth, &n2);
        *--end = '.';
        end -= n2;
        *--end = '%';
        fmt = end;

#endif /* 0 */
    }

    return real_helper_2(value, fmt);
}