sleepdefic1t
1/13/2020 - 9:19 PM

Print Int64's as Floats (long doubles)

Print Int64's as Floats (long doubles)

/*******************************************************************************
 * This file is part of the ARK Ecosystem.
 *
 * Copyright (c) ARK Ecosystem <info@ark.io>
 * Copyright (c) Simon Downey <simon@ark.io> (https://github.com/sleepdefic1t)
 *
 * The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 ******************************************************************************/

#ifndef PRINT_INT64_TO_FLOAT_HPP
#define PRINT_INT64_TO_FLOAT_HPP

#include <cstdbool>
#include <cstddef>
#include <cstdint>

////////////////////////////////////////////////////////////////////////////////
static bool adjustDecimals(char *src,
                           size_t srcSize,
                           char *target,
                           size_t targetSize,
                           uint8_t decimals) {
    size_t startOffset;
    size_t lastZeroOffset = 0;
    size_t offset = 0;

    if ((srcSize == 1) && (*src == '0')) {
        if (targetSize < 2) {
            return false;
        }
        target[offset++] = '0';
        target[offset++] = '\0';
        return true;
    }

    if (srcSize <= decimals) {
        size_t delta = decimals - srcSize;
        if (targetSize < srcSize + 1 + 2 + delta) {
            return false;
        }

        target[offset++] = '0';
        if (decimals > 0) {
          target[offset++] = '.';
        }
        
        for (size_t i = 0; i < delta; i++) {
            target[offset++] = '0';
        }

        startOffset = offset;
        for (size_t i = 0; i < srcSize; i++) {
            target[offset++] = src[i];
        }

        target[offset] = '\0';
    }
    else {
        size_t sourceOffset = 0;
        size_t delta = srcSize - decimals;

        if (targetSize < srcSize + 1 + 1) {
            return false;
        }

        while (offset < delta) {
            target[offset++] = src[sourceOffset++];
        }

        if (decimals != 0) {
            target[offset++] = '.';
        }

        startOffset = offset;
        while (sourceOffset < srcSize) {
            target[offset++] = src[sourceOffset++];
        }

        target[offset] = '\0';
    }

    for (size_t i = startOffset; i < offset; i++) {
        if (target[i] == '0') {
            if (lastZeroOffset == 0) {
                lastZeroOffset = i;
            }
        }
        else {
            lastZeroOffset = 0;
        }
    }

    if (lastZeroOffset != 0) {
        target[lastZeroOffset] = '\0';
        if (target[lastZeroOffset - 1] == '.') {
            target[lastZeroOffset - 1] = '\0';
        }
    }

    return true;
}

////////////////////////////////////////////////////////////////////////////////
std::string PrintInt64ToFloat(int64_t value,
                              size_t targetSize,
                              uint8_t decimals) {
    size_t    numDigits = 0UL;
    size_t    i = 0UL;
    int64_t   base = 1LL;
    int64_t   tempInt = value;

    // '-' + int64-max-chars(20) + '.' + '\0'
    const size_t maxTmpSize = 23;
    char tmp[maxTmpSize] = { '\0' };

    std::string out;
    out.reserve(targetSize);

    size_t negOffset = tempInt < 0LL ? 1UL : 0UL;

    if (negOffset == 1UL) {
      out[0] = '-';
      tempInt = -tempInt;
    }

    while (base <= tempInt) {
        base *= 0x0A;
        numDigits++;
    }

    if (numDigits > sizeof(tmp) - 1) {
        return 0;
    }

    base /= 0x0A;
    for (; i < numDigits; i++) {
        tmp[i] = '0' + ((tempInt / base) % 0x0A);
        base /= 0x0A;
    }

    adjustDecimals(tmp, i, &out[negOffset], targetSize, decimals);

    if (numDigits + 1 + negOffset > targetSize - 1) {
        out[0] = '\0';
    }

    return out;
}

#endif  // #define PRINT_INT64_TO_FLOAT_HPP