(root)/
gcc-13.2.0/
gcc/
d/
dmd/
root/
longdouble.d
/**
 * 80-bit floating point value implementation if the C/D compiler does not support them natively.
 * Copyright (C) 2021-2023 Free Software Foundation, Inc.
 *
 * GCC is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3, or (at your option)
 * any later version.
 *
 * GCC is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with GCC; see the file COPYING3.  If not see
 * <http://www.gnu.org/licenses/>.
 */

module dmd.root.longdouble;

import core.stdc.config;
import core.stdc.stdint;

extern(C++):
nothrow:
@nogc:

// Type used by the front-end for compile-time reals
struct longdouble
{
nothrow:
@nogc:
    extern (D) this(T)(T r)
    {
        this.set(cast(SetType!T)r);
    }

    // No constructor to be able to use this class in a union.
    extern (D) longdouble opAssign(T)(T r)
        if (is (T : longdouble))
    {
        this.realvalue = r.realvalue; 
        return this;
    }

    extern (D) longdouble opAssign(T)(T r)
        if (!is (T : longdouble))
    {
        this.set(cast(SetType!T)r);
        return this;
    }

    // Arithmetic operators.
    extern (D) longdouble opBinary(string op, T)(T r) const
        if ((op == "+" || op == "-" || op == "*" || op == "/" || op == "%")
            && is (T : longdouble))
    {
        static if (op == "+")
            return this.add(r);
        else static if (op == "-")
            return this.sub(r);
        else static if (op == "*")
            return this.mul(r);
        else static if (op == "/")
            return this.div(r);
        else static if (op == "%")
            return this.mod(r);
    }

    extern (D) longdouble opUnary(string op)() const
        if (op == "-")
    {
        return this.neg();
    }

    extern (D) int opCmp(longdouble r) const
    {
        return this.cmp(r);
    }

    extern (D) int opEquals(longdouble r) const
    {
        return this.equals(r);
    }

    extern (D) bool opCast(T : bool)() const
    {
        return this.to_bool();
    }

    extern (D) T opCast(T)() const
    {
        static if (__traits(isUnsigned, T))
            return cast (T) this.to_uint();
        else
            return cast(T) this.to_int();
    }

    void set(int8_t d);
    void set(int16_t d);
    void set(int32_t d);
    void set(int64_t d);
    void set(uint8_t d);
    void set(uint16_t d);
    void set(uint32_t d);
    void set(uint64_t d);
    void set(bool d);

    int64_t to_int() const;
    uint64_t to_uint() const;
    bool to_bool() const;

    longdouble add(const ref longdouble r) const;
    longdouble sub(const ref longdouble r) const;
    longdouble mul(const ref longdouble r) const;
    longdouble div(const ref longdouble r) const;
    longdouble mod(const ref longdouble r) const;
    longdouble neg() const;
    int cmp(const ref longdouble t) const;
    int equals(const ref longdouble t) const;

private:
    // Statically allocate enough space for REAL_VALUE_TYPE.
    enum REALVALUE_SIZE = (2 + (16 + c_long.sizeof) / c_long.sizeof);
    c_long [REALVALUE_SIZE] realvalue;
}

// Pick the corresponding (u)int64_t type for T, as int64_t may be
// a special enum that requires casting to explicitly.
private template SetType(T)
{
    static if (__traits(isIntegral, T) && T.sizeof == 8)
    {
        static if (__traits(isUnsigned, T))
            alias SetType = uint64_t;
        else
            alias SetType = int64_t;
    }
    else
        alias SetType = T;
}