// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package abi

// These functions are the build-time version of the Go type data structures.

// Their contents must be kept in sync with their definitions.
// Because the host and target type sizes can differ, the compiler and
// linker cannot use the host information that they might get from
// either unsafe.Sizeof and Alignof, nor runtime, reflect, or reflectlite.

// CommonSize returns sizeof(Type) for a compilation target with a given ptrSize
func ( int) int { return 4* + 8 + 8 }

// StructFieldSize returns sizeof(StructField) for a compilation target with a given ptrSize
func ( int) int { return 3 *  }

// UncommonSize returns sizeof(UncommonType).  This currently does not depend on ptrSize.
// This exported function is in an internal package, so it may change to depend on ptrSize in the future.
func () uint64 { return 4 + 2 + 2 + 4 + 4 }

// IMethodSize returns sizeof(IMethod) for a compilation target with a given ptrSize
func ( int) int { return 4 + 4 }

// KindOff returns the offset of Type.Kind_ for a compilation target with a given ptrSize
func ( int) int { return 2* + 7 }

// SizeOff returns the offset of Type.Size_ for a compilation target with a given ptrSize
func ( int) int { return 0 }

// PtrBytes returns the offset of Type.PtrBytes for a compilation target with a given ptrSize
func ( int) int { return  }

// TFlagOff returns the offset of Type.TFlag for a compilation target with a given ptrSize
func ( int) int { return 2* + 4 }

// Offset is for computing offsets of type data structures at compile/link time;
// the target platform may not be the host platform.  Its state includes the
// current offset, necessary alignment for the sequence of types, and the size
// of pointers and alignment of slices, interfaces, and strings (this is for tearing-
// resistant access to these types, if/when that is supported).
type Offset struct {
	off        uint64 // the current offset
	align      uint8  // the required alignmentof the container
	ptrSize    uint8  // the size of a pointer in bytes
	sliceAlign uint8  // the alignment of slices (and interfaces and strings)
}

// NewOffset returns a new Offset with offset 0 and alignment 1.
func ( uint8,  bool) Offset {
	if  {
		return Offset{off: 0, align: 1, ptrSize: , sliceAlign: 2 * }
	}
	return Offset{off: 0, align: 1, ptrSize: , sliceAlign: }
}

func assertIsAPowerOfTwo( uint8) {
	if  == 0 {
		panic("Zero is not a power of two")
	}
	if &- ==  {
		return
	}
	panic("Not a power of two")
}

// InitializedOffset returns a new Offset with specified offset, alignment, pointer size, and slice alignment.
func ( int,  uint8,  uint8,  bool) Offset {
	assertIsAPowerOfTwo()
	 := NewOffset(, )
	.off = uint64()
	.align = 
	return 
}

func ( Offset) ( uint8) Offset {
	.off = (.off + uint64() - 1) & ^(uint64() - 1)
	if .align <  {
		.align = 
	}
	return 
}

// Align returns the offset obtained by aligning offset to a multiple of a.
// a must be a power of two.
func ( Offset) ( uint8) Offset {
	assertIsAPowerOfTwo()
	return .align_()
}

// plus returns the offset obtained by appending a power-of-2-sized-and-aligned object to o.
func ( Offset) ( uint64) Offset {
	 = .align_(uint8())
	.off += 
	return 
}

// D8 returns the offset obtained by appending an 8-bit field to o.
func ( Offset) () Offset {
	return .plus(1)
}

// D16 returns the offset obtained by appending a 16-bit field to o.
func ( Offset) () Offset {
	return .plus(2)
}

// D32 returns the offset obtained by appending a 32-bit field to o.
func ( Offset) () Offset {
	return .plus(4)
}

// D64 returns the offset obtained by appending a 64-bit field to o.
func ( Offset) () Offset {
	return .plus(8)
}

// D64 returns the offset obtained by appending a pointer field to o.
func ( Offset) () Offset {
	if .ptrSize == 0 {
		panic("This offset has no defined pointer size")
	}
	return .plus(uint64(.ptrSize))
}

// Slice returns the offset obtained by appending a slice field to o.
func ( Offset) () Offset {
	 = .align_(.sliceAlign)
	.off += 3 * uint64(.ptrSize)
	// There's been discussion of whether slices should be 2-word aligned to allow
	// use of aligned 2-word load/store to prevent tearing, this is future proofing.
	// In general, for purposes of struct layout (and very likely default C layout
	// compatibility) the "size" of a Go type is rounded up to its alignment.
	return .Align(.sliceAlign)
}

// String returns the offset obtained by appending a string field to o.
func ( Offset) () Offset {
	 = .align_(.sliceAlign)
	.off += 2 * uint64(.ptrSize)
	return  // We "know" it needs no further alignment
}

// Interface returns the offset obtained by appending an interface field to o.
func ( Offset) () Offset {
	 = .align_(.sliceAlign)
	.off += 2 * uint64(.ptrSize)
	return  // We "know" it needs no further alignment
}

// Offset returns the struct-aligned offset (size) of o.
// This is at least as large as the current internal offset; it may be larger.
func ( Offset) () uint64 {
	return .Align(.align).off
}

func ( Offset) () Offset {
	.off += UncommonSize()
	return 
}

// CommonOffset returns the Offset to the data after the common portion of type data structures.
func ( int,  bool) Offset {
	return InitializedOffset(CommonSize(), uint8(), uint8(), )
}