//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
// C Primitive Types
//===----------------------------------------------------------------------===//

/// The C 'char' type.
///
/// This will be the same as either `CSignedChar` (in the common
/// case) or `CUnsignedChar`, depending on the platform.
public typealias CChar = Int8

/// The C 'unsigned char' type.
public typealias CUnsignedChar = UInt8

/// The C 'unsigned short' type.
public typealias CUnsignedShort = UInt16

/// The C 'unsigned int' type.
#if  _pointerBitWidth(_16)
public typealias CUnsignedInt = UInt
#else
public typealias CUnsignedInt = UInt32
#endif

/// The C 'unsigned long' type.
#if (os(Windows) && (arch(x86_64) || arch(arm64))) || _pointerBitWidth(_16)
public typealias CUnsignedLong = UInt32
#else
public typealias CUnsignedLong = UInt
#endif

/// The C 'unsigned long long' type.
public typealias CUnsignedLongLong = UInt64

/// The C 'unsigned __int128' type.
@available(SwiftStdlib 6.0, *)
public typealias CUnsignedInt128 = UInt128

/// The C 'signed char' type.
public typealias CSignedChar = Int8

/// The C 'short' type.
public typealias CShort = Int16

/// The C 'int' type.
#if  _pointerBitWidth(_16)
public typealias CInt = Int
#else
public typealias CInt = Int32
#endif

/// The C 'long' type.
#if (os(Windows) && (arch(x86_64) || arch(arm64))) || _pointerBitWidth(_16)
public typealias CLong = Int32
#else
public typealias CLong = Int
#endif

/// The C 'long long' type.
public typealias CLongLong = Int64

/// The C '__int128' type.
@available(SwiftStdlib 6.0, *)
public typealias CInt128 = Int128

#if !((os(macOS) || targetEnvironment(macCatalyst)) && arch(x86_64))
/// The C '_Float16' type.
@available(SwiftStdlib 5.3, *)
public typealias CFloat16 = Float16
#endif

/// The C 'float' type.
public typealias CFloat = Float

/// The C 'double' type.
public typealias CDouble = Double

// Because CLongDouble varies by platform, its documentation comments are
// repeated so they appear before each declaration.  The documentation can't
// appear just once here, before the #if.  (rdar://128616139)
#if os(anyAppleOS)
// On Darwin, long double is Float80 on x86, and Double otherwise.
#if arch(x86_64) || arch(i386)
/// The C 'long double' type.
///
/// This type's definition varies by platform
/// to match the variable definition of the C `long double` type.
/// `CLongDouble` is a type alias for `Double` (`Float64`)
/// on Apple silicon,
/// on Windows,
/// on Linux running on IBM System/390,
/// on Android running on ARM,
/// and on OpenBSD running on 64-bit ARM.
/// `CLongDouble` is a type alias for `Float80`
/// on Apple platforms running on Intel-based processors,
/// on Linux running on Intel-based processors,
/// on OpenBSD running on 64-bit Intel-based processors,
/// and on FreeBSD running on Intel-based processors.
public typealias CLongDouble = Float80
#else
/// The C 'long double' type.
///
/// This type's definition varies by platform
/// to match the variable definition of the C `long double` type.
/// `CLongDouble` is a type alias for `Double` (`Float64`)
/// on Apple silicon,
/// on Windows,
/// on Linux running on IBM System/390,
/// on Android running on ARM,
/// and on OpenBSD running on 64-bit ARM.
/// `CLongDouble` is a type alias for `Float80`
/// on Apple platforms running on Intel-based processors,
/// on Linux running on Intel-based processors,
/// on OpenBSD running on 64-bit Intel-based processors,
/// and on FreeBSD running on Intel-based processors.
public typealias CLongDouble = Double
#endif
#elseif os(Windows)
// On Windows, long double is always Double.
/// The C 'long double' type.
///
/// This type's definition varies by platform
/// to match the variable definition of the C `long double` type.
/// `CLongDouble` is a type alias for `Double` (`Float64`)
/// on Apple silicon,
/// on Windows,
/// on Linux running on IBM System/390,
/// on Android running on ARM,
/// and on OpenBSD running on 64-bit ARM.
/// `CLongDouble` is a type alias for `Float80`
/// on Apple platforms running on Intel-based processors,
/// on Linux running on Intel-based processors,
/// on OpenBSD running on 64-bit Intel-based processors,
/// and on FreeBSD running on Intel-based processors.
public typealias CLongDouble = Double
#elseif os(Linux)
// On Linux/x86, long double is Float80.
// TODO: Fill in definitions for additional architectures as needed. IIRC
// armv7 should map to Double, but arm64 and ppc64le should map to Float128,
// which we don't yet have in Swift.
#if arch(x86_64) || arch(i386)
/// The C 'long double' type.
///
/// This type's definition varies by platform
/// to match the variable definition of the C `long double` type.
/// `CLongDouble` is a type alias for `Double` (`Float64`)
/// on Apple silicon,
/// on Windows,
/// on Linux running on IBM System/390,
/// on Android running on ARM,
/// and on OpenBSD running on 64-bit ARM.
/// `CLongDouble` is a type alias for `Float80`
/// on Apple platforms running on Intel-based processors,
/// on Linux running on Intel-based processors,
/// on OpenBSD running on 64-bit Intel-based processors,
/// and on FreeBSD running on Intel-based processors.
public typealias CLongDouble = Float80
#elseif arch(s390x)
// On s390x '-mlong-double-64' option with size of 64-bits makes the
// Long Double type equivalent to Double type.
/// The C 'long double' type.
///
/// This type's definition varies by platform
/// to match the variable definition of the C `long double` type.
/// `CLongDouble` is a type alias for `Double` (`Float64`)
/// on Apple silicon,
/// on Windows,
/// on Linux running on IBM System/390,
/// on Android running on ARM,
/// and on OpenBSD running on 64-bit ARM.
/// `CLongDouble` is a type alias for `Float80`
/// on Apple platforms running on Intel-based processors,
/// on Linux running on Intel-based processors,
/// on OpenBSD running on 64-bit Intel-based processors,
/// and on FreeBSD running on Intel-based processors.
public typealias CLongDouble = Double
#endif
#elseif os(Android)
// On Android, long double is Float128 for AAPCS64, which we don't have yet in
// Swift (https://github.com/apple/swift/issues/51573); and Double for ARMv7.
#if arch(arm)
/// The C 'long double' type.
///
/// This type's definition varies by platform
/// to match the variable definition of the C `long double` type.
/// `CLongDouble` is a type alias for `Double` (`Float64`)
/// on Apple silicon,
/// on Windows,
/// on Linux running on IBM System/390,
/// on Android running on ARM,
/// and on OpenBSD running on 64-bit ARM.
/// `CLongDouble` is a type alias for `Float80`
/// on Apple platforms running on Intel-based processors,
/// on Linux running on Intel-based processors,
/// on OpenBSD running on 64-bit Intel-based processors,
/// and on FreeBSD running on Intel-based processors.
public typealias CLongDouble = Double
#endif
#elseif os(OpenBSD)
#if arch(x86_64)
/// The C 'long double' type.
///
/// This type's definition varies by platform
/// to match the variable definition of the C `long double` type.
/// `CLongDouble` is a type alias for `Double` (`Float64`)
/// on Apple silicon,
/// on Windows,
/// on Linux running on IBM System/390,
/// on Android running on ARM,
/// and on OpenBSD running on 64-bit ARM.
/// `CLongDouble` is a type alias for `Float80`
/// on Apple platforms running on Intel-based processors,
/// on Linux running on Intel-based processors,
/// on OpenBSD running on 64-bit Intel-based processors,
/// and on FreeBSD running on Intel-based processors.
public typealias CLongDouble = Float80
#elseif arch(arm64)
/// The C 'long double' type.
///
/// This type's definition varies by platform
/// to match the variable definition of the C `long double` type.
/// `CLongDouble` is a type alias for `Double` (`Float64`)
/// on Apple silicon,
/// on Windows,
/// on Linux running on IBM System/390,
/// on Android running on ARM,
/// and on OpenBSD running on 64-bit ARM.
/// `CLongDouble` is a type alias for `Float80`
/// on Apple platforms running on Intel-based processors,
/// on Linux running on Intel-based processors,
/// on OpenBSD running on 64-bit Intel-based processors,
/// and on FreeBSD running on Intel-based processors.
public typealias CLongDouble = Double
#else
#error("CLongDouble needs to be defined for this OpenBSD architecture")
#endif
#elseif os(FreeBSD)
// On FreeBSD, long double is Float128 for arm64, which we don't have yet in
// Swift
#if arch(x86_64) || arch(i386)
/// The C 'long double' type.
///
/// This type's definition varies by platform
/// to match the variable definition of the C `long double` type.
/// `CLongDouble` is a type alias for `Double` (`Float64`)
/// on Apple silicon,
/// on Windows,
/// on Linux running on IBM System/390,
/// on Android running on ARM,
/// and on OpenBSD running on 64-bit ARM.
/// `CLongDouble` is a type alias for `Float80`
/// on Apple platforms running on Intel-based processors,
/// on Linux running on Intel-based processors,
/// on OpenBSD running on 64-bit Intel-based processors,
/// and on FreeBSD running on Intel-based processors.
public typealias CLongDouble = Float80
#endif
#elseif $Embedded
#if arch(x86_64) || arch(i386)
/// The C 'long double' type.
///
/// This type's definition varies by platform
/// to match the variable definition of the C `long double` type.
/// `CLongDouble` is a type alias for `Double` (`Float64`)
/// on Apple silicon,
/// on Windows,
/// on Linux running on IBM System/390,
/// on Android running on ARM,
/// and on OpenBSD running on 64-bit ARM.
/// `CLongDouble` is a type alias for `Float80`
/// on Apple platforms running on Intel-based processors,
/// on Linux running on Intel-based processors,
/// on OpenBSD running on 64-bit Intel-based processors,
/// and on FreeBSD running on Intel-based processors.
public typealias CLongDouble = Double
#endif
#else
// TODO: define CLongDouble for other OSes
#endif

// FIXME: Is it actually UTF-32 on Darwin?
//
/// The C++ 'wchar_t' type.
#if os(Windows)
public typealias CWideChar = UInt16
#else
public typealias CWideChar = Unicode.Scalar
#endif

/// The C++20 'char8_t' type, which has UTF-8 encoding.
public typealias CChar8 = UInt8

// FIXME: Swift should probably have a UTF-16 type other than UInt16.
//
/// The C++11 'char16_t' type, which has UTF-16 encoding.
public typealias CChar16 = UInt16

/// The C++11 'char32_t' type, which has UTF-32 encoding.
public typealias CChar32 = Unicode.Scalar

/// The C '_Bool' and C++ 'bool' type.
public typealias CBool = Bool

/// A wrapper around an opaque C pointer.
///
/// Opaque pointers are used to represent C pointers to types that
/// cannot be represented in Swift, such as incomplete struct types.
@frozen
@unsafe
public struct OpaquePointer {
  @usableFromInline
  internal var _rawValue: Builtin.RawPointer

  @usableFromInline @_transparent
  internal init(_ v: Builtin.RawPointer) {
    unsafe self._rawValue = v
  }
}

@available(*, unavailable)
extension OpaquePointer: Sendable {}

extension OpaquePointer: ConvertibleToBytes {}

extension OpaquePointer {
  /// Creates a new `OpaquePointer` from the given address, specified as a bit
  /// pattern.
  ///
  /// - Parameter bitPattern: A bit pattern to use for the address of the new
  ///   pointer. If `bitPattern` is zero, the result is `nil`.
  @_transparent
  public init?(bitPattern: Int) {
    if bitPattern == 0 { return nil }
    unsafe self._rawValue = Builtin.inttoptr_Word(bitPattern._builtinWordValue)
  }

  /// Creates a new `OpaquePointer` from the given address, specified as a bit
  /// pattern.
  ///
  /// - Parameter bitPattern: A bit pattern to use for the address of the new
  ///   pointer. If `bitPattern` is zero, the result is `nil`.
  @_transparent
  public init?(bitPattern: UInt) {
    if bitPattern == 0 { return nil }
    unsafe self._rawValue = Builtin.inttoptr_Word(bitPattern._builtinWordValue)
  }
}

extension OpaquePointer {
  /// Converts a typed `UnsafePointer` to an opaque C pointer.
  @_transparent
  @_preInverseGenerics
  @safe
  public init<T: ~Copyable>(@_nonEphemeral _ from: UnsafePointer<T>) {
    unsafe self._rawValue = from._rawValue
  }

  /// Converts a typed `UnsafePointer` to an opaque C pointer.
  ///
  /// The result is `nil` if `from` is `nil`.
  @_transparent
  @_preInverseGenerics
  @safe
  public init?<T: ~Copyable>(@_nonEphemeral _ from: UnsafePointer<T>?) {
    guard let unwrapped = unsafe from else { return nil }
    self.init(unwrapped)
  }
}

extension OpaquePointer {
  /// Converts a typed `UnsafeMutablePointer` to an opaque C pointer.
  @_transparent
  @_preInverseGenerics
  @safe
  public init<T: ~Copyable>(@_nonEphemeral _ from: UnsafeMutablePointer<T>) {
    unsafe self._rawValue = from._rawValue
  }

  /// Converts a typed `UnsafeMutablePointer` to an opaque C pointer.
  ///
  /// The result is `nil` if `from` is `nil`.
  @_transparent
  @_preInverseGenerics
  @safe
  public init?<T: ~Copyable>(@_nonEphemeral _ from: UnsafeMutablePointer<T>?) {
    guard let unwrapped = unsafe from else { return nil }
    self.init(unwrapped)
  }
}

extension OpaquePointer: Equatable {
  @inlinable // unsafe-performance
  @safe
  public static func == (lhs: OpaquePointer, rhs: OpaquePointer) -> Bool {
    return unsafe Bool(Builtin.cmp_eq_RawPointer(lhs._rawValue, rhs._rawValue))
  }
}

extension OpaquePointer: @unsafe Hashable {
  /// Hashes the essential components of this value by feeding them into the
  /// given hasher.
  ///
  /// - Parameter hasher: The hasher to use when combining the components
  ///   of this instance.
  @inlinable
  @safe
  public func hash(into hasher: inout Hasher) {
    unsafe hasher.combine(Int(Builtin.ptrtoint_Word(_rawValue)))
  }
}

@_unavailableInEmbedded
extension OpaquePointer: CustomDebugStringConvertible {
  /// A textual representation of the pointer, suitable for debugging.
  @safe
  public var debugDescription: String {
    return unsafe _rawPointerToString(_rawValue)
  }
}

extension Int {
  /// Creates a new value with the bit pattern of the given pointer.
  ///
  /// The new value represents the address of the pointer passed as `pointer`.
  /// If `pointer` is `nil`, the result is `0`.
  ///
  /// - Parameter pointer: The pointer to use as the source for the new
  ///   integer.
  @inlinable // unsafe-performance
  @safe
  public init(bitPattern pointer: OpaquePointer?) {
    unsafe self.init(bitPattern: UnsafeRawPointer(pointer))
  }
}

extension UInt {
  /// Creates a new value with the bit pattern of the given pointer.
  ///
  /// The new value represents the address of the pointer passed as `pointer`.
  /// If `pointer` is `nil`, the result is `0`.
  ///
  /// - Parameter pointer: The pointer to use as the source for the new
  ///   integer.
  @inlinable // unsafe-performance
  @safe
  public init(bitPattern pointer: OpaquePointer?) {
    unsafe self.init(bitPattern: UnsafeRawPointer(pointer))
  }
}

/// A wrapper around a C `va_list` pointer.
#if arch(arm64) && !(os(anyAppleOS) || os(Windows))
@frozen
@unsafe
public struct CVaListPointer {
  @unsafe @usableFromInline // unsafe-performance
  internal var _value: (__stack: UnsafeMutablePointer<Int>?,
                        __gr_top: UnsafeMutablePointer<Int>?,
                        __vr_top: UnsafeMutablePointer<Int>?,
                        __gr_off: Int32,
                        __vr_off: Int32)

  @inlinable // unsafe-performance
  public // @testable
  init(__stack: UnsafeMutablePointer<Int>?,
       __gr_top: UnsafeMutablePointer<Int>?,
       __vr_top: UnsafeMutablePointer<Int>?,
       __gr_off: Int32,
       __vr_off: Int32) {
    unsafe _value = (__stack, __gr_top, __vr_top, __gr_off, __vr_off)
  }
}

@_unavailableInEmbedded
extension CVaListPointer: CustomDebugStringConvertible {
  @safe
  public var debugDescription: String {
    return "(\(unsafe _value.__stack.debugDescription), " +
           "\(unsafe _value.__gr_top.debugDescription), " +
           "\(unsafe _value.__vr_top.debugDescription), " +
           "\(unsafe _value.__gr_off), " +
           "\(unsafe _value.__vr_off))"
  }
}

#else

@frozen
@unsafe
public struct CVaListPointer {
  @unsafe @usableFromInline // unsafe-performance
  internal var _value: UnsafeMutableRawPointer

  @inlinable // unsafe-performance
  public // @testable
  init(_fromUnsafeMutablePointer from: UnsafeMutableRawPointer) {
    unsafe _value = from
  }
}

@_unavailableInEmbedded
extension CVaListPointer: CustomDebugStringConvertible {
  /// A textual representation of the pointer, suitable for debugging.
  @safe
  public var debugDescription: String {
    return unsafe _value.debugDescription
  }
}

#endif

@available(*, unavailable)
extension CVaListPointer: Sendable { }

/// Copy `size` bytes of memory from `src` into `dest`.
///
/// The memory regions `src..<src + size` and
/// `dest..<dest + size` should not overlap.
@inlinable
internal func _memcpy(
  dest destination: UnsafeMutableRawPointer,
  src: UnsafeRawPointer,
  size: UInt
) {
  let dest = destination._rawValue
  let src = src._rawValue
  let size = UInt64(size)._value
  Builtin.int_memcpy_RawPointer_RawPointer_Int64(
    dest, src, size,
    /*volatile:*/ false._value)
}

/// Copy `size` bytes of memory from `src` into `dest`.
///
/// The memory regions `src..<src + size` and
/// `dest..<dest + size` may overlap.
@inlinable
internal func _memmove(
  dest destination: UnsafeMutableRawPointer,
  src: UnsafeRawPointer,
  size: UInt
) {
  let dest = destination._rawValue
  let src = src._rawValue
  let size = UInt64(size)._value
  Builtin.int_memmove_RawPointer_RawPointer_Int64(
    dest, src, size,
    /*volatile:*/ false._value)
}
