/*---------------------------------------------------------------------------

 *

 * Common routines for Ryu floating-point output.

 *

 * Portions Copyright (c) 2024, openGauss Contributors

 * Portions Copyright (c) 2018-2024, PostgreSQL Global Development Group

 *

 * IDENTIFICATION

 *    src/common/backend/utils/adt/ryu/ryu_common.h

 *

 * This is a modification of code taken from github.com/ulfjack/ryu under the

 * terms of the Boost license (not the Apache license). The original copyright

 * notice follows:

 *

 * Copyright 2018 Ulf Adams

 *

 * The contents of this file may be used under the terms of the Apache

 * License, Version 2.0.

 *

 *     (See accompanying file LICENSE-Apache or copy at

 *      http://www.apache.org/licenses/LICENSE-2.0)

 *

 * Alternatively, the contents of this file may be used under the terms of the

 * Boost Software License, Version 1.0.

 *

 *     (See accompanying file LICENSE-Boost or copy at

 *      https://www.boost.org/LICENSE_1_0.txt)

 *

 * Unless required by applicable law or agreed to in writing, this software is

 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

 * KIND, either express or implied.

 *

 *---------------------------------------------------------------------------

 */

#ifndef RYU_COMMON_H

#define RYU_COMMON_H



#include "postgres.h"



#include "utils/elog.h"



/*

 * Upstream Ryu's output is always the shortest possible. But we adjust that

 * slightly to improve portability: we avoid outputting the exact midpoint

 * value between two representable floats, since that relies on the reader

 * getting the round-to-even rule correct, which seems to be the common

 * failure mode.

 *

 * Defining this to 1 would restore the upstream behavior.

 */

#define STRICTLY_SHORTEST 0



#if SIZEOF_SIZE_T < 8

#define RYU_32_BIT_PLATFORM

#endif



/*  Returns e == 0 ? 1 : ceil(log_2(5^e)). */

inline uint32 pow5bits(const int32 e)

{

    /*

     * This approximation works up to the point that the multiplication

     * overflows at e = 3529.

     *

     * If the multiplication were done in 64 bits, it would fail at 5^4004

     * which is just greater than 2^9297.

     */

    Assert(e >= 0);

    Assert(e <= 3528);

    return ((((uint32)e) * 1217359) >> 19) + 1;

}



/*  Returns floor(log_10(2^e)). */

inline int32 log10Pow2(const int32 e)

{

    /*

     * The first value this approximation fails for is 2^1651 which is just

     * greater than 10^297.

     */

    Assert(e >= 0);

    Assert(e <= 1650);

    return (int32)((((uint32)e) * 78913) >> 18);

}



/*  Returns floor(log_10(5^e)). */

inline int32 log10Pow5(const int32 e)

{

    /*

     * The first value this approximation fails for is 5^2621 which is just

     * greater than 10^1832.

     */

    Assert(e >= 0);

    Assert(e <= 2620);

    return (int32)((((uint32)e) * 732923) >> 20);

}



inline int copy_special_str(char* const result, const bool sign, const bool exponent, const bool mantissa)

{

    if (mantissa) {

        errno_t rc = memcpy_sp(result, 3, "NaN", 3);

        securec_check(rc, "\0", "\0");

        return 3;

    }

    if (sign) {

        result[0] = '-';

    }

    if (exponent) {

        errno_t rc = memcpy_sp(result + sign, 8, "Infinity", 8);

        securec_check(rc, "\0", "\0");

        return sign + 8;

    }

    result[sign] = '0';

    return sign + 1;

}



inline uint32 float_to_bits(const float f)

{

    uint32 bits = 0;



    errno_t rc = memcpy_sp(&bits, sizeof(float), &f, sizeof(float));

    securec_check(rc, "\0", "\0");

    return bits;

}



inline uint64 double_to_bits(const double d)

{

    uint64 bits = 0;



    errno_t rc = memcpy_sp(&bits, sizeof(double), &d, sizeof(double));

    securec_check(rc, "\0", "\0");

    return bits;

}



#endif /* RYU_COMMON_H */