compiler: build separation runtime with clite
This commit is contained in:
@@ -3,7 +3,7 @@ package main
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/compiler/internal/abi"
|
||||
"github.com/goplus/llgo/runtime/abi"
|
||||
)
|
||||
|
||||
type T struct {
|
||||
|
||||
@@ -3,7 +3,7 @@ package main
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/compiler/internal/runtime"
|
||||
"github.com/goplus/llgo/runtime/internal/runtime"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -3,7 +3,7 @@ package main
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/compiler/internal/runtime"
|
||||
"github.com/goplus/llgo/runtime/internal/runtime"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -3,7 +3,7 @@ package main
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/compiler/internal/abi"
|
||||
"github.com/goplus/llgo/runtime/abi"
|
||||
)
|
||||
|
||||
type T string
|
||||
|
||||
@@ -2,7 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/compiler/internal/abi"
|
||||
"github.com/goplus/llgo/runtime/abi"
|
||||
)
|
||||
|
||||
func Basic(kind abi.Kind) *abi.Type {
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
|
||||
"golang.org/x/tools/go/ssa"
|
||||
|
||||
"github.com/goplus/llgo/compiler/internal/env"
|
||||
llssa "github.com/goplus/llgo/compiler/ssa"
|
||||
)
|
||||
|
||||
@@ -617,7 +618,7 @@ func pkgKindByPath(pkgPath string) int {
|
||||
func replaceGoName(v string, pos int) string {
|
||||
switch v[:pos] {
|
||||
case "runtime":
|
||||
return "github.com/goplus/llgo/compiler/internal/runtime" + v[pos:]
|
||||
return env.LLGoRuntimePkg + "/internal/runtime" + v[pos:]
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
module github.com/goplus/llgo/compiler
|
||||
|
||||
go 1.23.4
|
||||
go 1.23
|
||||
|
||||
require (
|
||||
github.com/goplus/gogen v1.16.4
|
||||
github.com/goplus/llgo v0.9.9
|
||||
github.com/goplus/llgo/runtime v0.0.0-00010101000000-000000000000
|
||||
github.com/goplus/llvm v0.8.1
|
||||
github.com/goplus/mod v0.13.13
|
||||
github.com/qiniu/x v1.13.10
|
||||
golang.org/x/tools v0.28.0
|
||||
golang.org/x/tools v0.29.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -17,3 +18,5 @@ require (
|
||||
)
|
||||
|
||||
replace github.com/goplus/llgo => ../
|
||||
|
||||
replace github.com/goplus/llgo/runtime => ../runtime
|
||||
|
||||
@@ -12,5 +12,5 @@ golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
|
||||
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
|
||||
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
|
||||
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
// 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
|
||||
|
||||
// Map constants common to several packages
|
||||
// runtime/runtime-gdb.py:MapTypePrinter contains its own copy
|
||||
const (
|
||||
MapBucketCountBits = 3 // log2 of number of elements in a bucket.
|
||||
MapBucketCount = 1 << MapBucketCountBits
|
||||
MapMaxKeyBytes = 128 // Must fit in a uint8.
|
||||
MapMaxElemBytes = 128 // Must fit in a uint8.
|
||||
)
|
||||
@@ -1,610 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package abi
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// IsExported reports whether name starts with an upper-case letter.
|
||||
func IsExported(name string) bool {
|
||||
if len(name) > 0 {
|
||||
c := name[0]
|
||||
return 'A' <= c && c <= 'Z'
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Type is the runtime representation of a Go type.
|
||||
//
|
||||
// Type is also referenced implicitly
|
||||
// (in the form of expressions involving constants and arch.PtrSize)
|
||||
// in cmd/compile/internal/reflectdata/reflect.go
|
||||
// and cmd/link/internal/ld/decodesym.go
|
||||
// (e.g. data[2*arch.PtrSize+4] references the TFlag field)
|
||||
// unsafe.OffsetOf(Type{}.TFlag) cannot be used directly in those
|
||||
// places because it varies with cross compilation and experiments.
|
||||
type Type struct {
|
||||
Size_ uintptr
|
||||
PtrBytes uintptr // number of (prefix) bytes in the type that can contain pointers
|
||||
Hash uint32 // hash of type; avoids computation in hash tables
|
||||
TFlag TFlag // extra type information flags
|
||||
Align_ uint8 // alignment of variable with this type
|
||||
FieldAlign_ uint8 // alignment of struct field with this type
|
||||
Kind_ uint8 // enumeration for C
|
||||
// function for comparing objects of this type
|
||||
// (ptr to object A, ptr to object B) -> ==?
|
||||
Equal func(unsafe.Pointer, unsafe.Pointer) bool
|
||||
// GCData stores the GC type data for the garbage collector.
|
||||
// If the KindGCProg bit is set in kind, GCData is a GC program.
|
||||
// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
|
||||
GCData *byte
|
||||
Str_ string // string form
|
||||
PtrToThis_ *Type // type for pointer to this type, may be nil
|
||||
}
|
||||
|
||||
// A Kind represents the specific kind of type that a Type represents.
|
||||
// The zero Kind is not a valid kind.
|
||||
type Kind uint
|
||||
|
||||
const (
|
||||
Invalid Kind = iota
|
||||
Bool
|
||||
Int
|
||||
Int8
|
||||
Int16
|
||||
Int32
|
||||
Int64
|
||||
Uint
|
||||
Uint8
|
||||
Uint16
|
||||
Uint32
|
||||
Uint64
|
||||
Uintptr
|
||||
Float32
|
||||
Float64
|
||||
Complex64
|
||||
Complex128
|
||||
Array
|
||||
Chan
|
||||
Func
|
||||
Interface
|
||||
Map
|
||||
Pointer
|
||||
Slice
|
||||
String
|
||||
Struct
|
||||
UnsafePointer
|
||||
)
|
||||
|
||||
const (
|
||||
// TODO (khr, drchase) why aren't these in TFlag? Investigate, fix if possible.
|
||||
KindDirectIface = 1 << 5
|
||||
KindGCProg = 1 << 6 // Type.gc points to GC program
|
||||
KindMask = (1 << 5) - 1
|
||||
)
|
||||
|
||||
// String returns the name of k.
|
||||
func (k Kind) String() string {
|
||||
if int(k) < len(kindNames) {
|
||||
return kindNames[k]
|
||||
}
|
||||
return kindNames[0]
|
||||
}
|
||||
|
||||
var kindNames = []string{
|
||||
Invalid: "invalid",
|
||||
Bool: "bool",
|
||||
Int: "int",
|
||||
Int8: "int8",
|
||||
Int16: "int16",
|
||||
Int32: "int32",
|
||||
Int64: "int64",
|
||||
Uint: "uint",
|
||||
Uint8: "uint8",
|
||||
Uint16: "uint16",
|
||||
Uint32: "uint32",
|
||||
Uint64: "uint64",
|
||||
Uintptr: "uintptr",
|
||||
Float32: "float32",
|
||||
Float64: "float64",
|
||||
Complex64: "complex64",
|
||||
Complex128: "complex128",
|
||||
Array: "array",
|
||||
Chan: "chan",
|
||||
Func: "func",
|
||||
Interface: "interface",
|
||||
Map: "map",
|
||||
Pointer: "ptr",
|
||||
Slice: "slice",
|
||||
String: "string",
|
||||
Struct: "struct",
|
||||
UnsafePointer: "unsafe.Pointer",
|
||||
}
|
||||
|
||||
// TFlag is used by a Type to signal what extra type information is
|
||||
// available in the memory directly following the Type value.
|
||||
type TFlag uint8
|
||||
|
||||
const (
|
||||
// TFlagUncommon means that there is a data with a type, UncommonType,
|
||||
// just beyond the shared-per-type common data. That is, the data
|
||||
// for struct types will store their UncommonType at one offset, the
|
||||
// data for interface types will store their UncommonType at a different
|
||||
// offset. UncommonType is always accessed via a pointer that is computed
|
||||
// using trust-us-we-are-the-implementors pointer arithmetic.
|
||||
//
|
||||
// For example, if t.Kind() == Struct and t.tflag&TFlagUncommon != 0,
|
||||
// then t has UncommonType data and it can be accessed as:
|
||||
//
|
||||
// type structTypeUncommon struct {
|
||||
// structType
|
||||
// u UncommonType
|
||||
// }
|
||||
// u := &(*structTypeUncommon)(unsafe.Pointer(t)).u
|
||||
TFlagUncommon TFlag = 1 << 0
|
||||
|
||||
// TFlagExtraStar means the name in the str field has an
|
||||
// extraneous '*' prefix. This is because for most types T in
|
||||
// a program, the type *T also exists and reusing the str data
|
||||
// saves binary size.
|
||||
TFlagExtraStar TFlag = 1 << 1
|
||||
|
||||
// TFlagNamed means the type has a name.
|
||||
TFlagNamed TFlag = 1 << 2
|
||||
|
||||
// TFlagRegularMemory means that equal and hash functions can treat
|
||||
// this type as a single region of t.size bytes.
|
||||
TFlagRegularMemory TFlag = 1 << 3
|
||||
|
||||
// TFlagVariadic means a funcType with variadic parameters
|
||||
TFlagVariadic TFlag = 1 << 4
|
||||
|
||||
// TFflagClosure means the structType is a closure
|
||||
TFlagClosure TFlag = 1 << 5
|
||||
|
||||
// TFlagUninited means this type is not fully initialized.
|
||||
TFlagUninited TFlag = 1 << 7
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// ArrayType represents a fixed array type.
|
||||
type ArrayType struct {
|
||||
Type
|
||||
Elem *Type // array element type
|
||||
Slice *Type // slice type
|
||||
Len uintptr
|
||||
}
|
||||
|
||||
type SliceType struct {
|
||||
Type
|
||||
Elem *Type // slice element type
|
||||
}
|
||||
|
||||
type MapType struct {
|
||||
Type
|
||||
Key *Type
|
||||
Elem *Type
|
||||
Bucket *Type // internal type representing a hash bucket
|
||||
// function for hashing keys (ptr to key, seed) -> hash
|
||||
Hasher func(unsafe.Pointer, uintptr) uintptr
|
||||
KeySize uint8 // size of key slot
|
||||
ValueSize uint8 // size of elem slot
|
||||
BucketSize uint16 // size of bucket
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
// Note: flag values must match those used in the TMAP case
|
||||
// in ../cmd/compile/internal/reflectdata/reflect.go:writeType.
|
||||
func (mt *MapType) IndirectKey() bool { // store ptr to key instead of key itself
|
||||
return mt.Flags&1 != 0
|
||||
}
|
||||
func (mt *MapType) IndirectElem() bool { // store ptr to elem instead of elem itself
|
||||
return mt.Flags&2 != 0
|
||||
}
|
||||
func (mt *MapType) ReflexiveKey() bool { // true if k==k for all keys
|
||||
return mt.Flags&4 != 0
|
||||
}
|
||||
func (mt *MapType) NeedKeyUpdate() bool { // true if we need to update key on an overwrite
|
||||
return mt.Flags&8 != 0
|
||||
}
|
||||
func (mt *MapType) HashMightPanic() bool { // true if hash function might panic
|
||||
return mt.Flags&16 != 0
|
||||
}
|
||||
|
||||
func (t *Type) Key() *Type {
|
||||
if t.Kind() == Map {
|
||||
return (*MapType)(unsafe.Pointer(t)).Key
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type PtrType struct {
|
||||
Type
|
||||
Elem *Type // pointer element (pointed at) type
|
||||
}
|
||||
|
||||
type ChanDir int
|
||||
|
||||
const (
|
||||
RecvDir ChanDir = 1 << iota // <-chan
|
||||
SendDir // chan<-
|
||||
BothDir = RecvDir | SendDir // chan
|
||||
InvalidDir ChanDir = 0
|
||||
)
|
||||
|
||||
// ChanType represents a channel type
|
||||
type ChanType struct {
|
||||
Type
|
||||
Elem *Type
|
||||
Dir ChanDir
|
||||
}
|
||||
|
||||
// funcType represents a function type.
|
||||
type FuncType struct {
|
||||
Type
|
||||
In []*Type
|
||||
Out []*Type
|
||||
}
|
||||
|
||||
// Variadic reports whether the function type is variadic.
|
||||
func (p *FuncType) Variadic() bool {
|
||||
return p.TFlag&TFlagVariadic != 0
|
||||
}
|
||||
|
||||
type StructField struct {
|
||||
Name_ string // name is always non-empty
|
||||
Typ *Type // type of field
|
||||
Offset uintptr // byte offset of field
|
||||
|
||||
Tag_ string
|
||||
Embedded_ bool
|
||||
}
|
||||
|
||||
// Embedded reports whether the field is embedded.
|
||||
func (f *StructField) Embedded() bool {
|
||||
return f.Embedded_
|
||||
}
|
||||
|
||||
// Exported reports whether the field is exported.
|
||||
func (f *StructField) Exported() bool {
|
||||
return IsExported(f.Name_)
|
||||
}
|
||||
|
||||
type StructType struct {
|
||||
Type
|
||||
PkgPath_ string
|
||||
Fields []StructField
|
||||
}
|
||||
|
||||
type InterfaceType struct {
|
||||
Type
|
||||
PkgPath_ string // import path
|
||||
Methods []Imethod // sorted by hash
|
||||
}
|
||||
|
||||
type Text = unsafe.Pointer // TODO(xsw): to be confirmed
|
||||
|
||||
// Method on non-interface type
|
||||
type Method struct {
|
||||
Name_ string // name of method
|
||||
Mtyp_ *FuncType // method type (without receiver)
|
||||
Ifn_ Text // fn used in interface call (one-word receiver)
|
||||
Tfn_ Text // fn used for normal method call
|
||||
}
|
||||
|
||||
// Exported reports whether the method is exported.
|
||||
func (p *Method) Exported() bool {
|
||||
return lastDot(p.Name_) == -1
|
||||
}
|
||||
|
||||
// Name returns the tag string for method.
|
||||
func (p *Method) Name() string {
|
||||
_, name := splitName(p.Name_)
|
||||
return name
|
||||
}
|
||||
|
||||
// PkgPath returns the pkgpath string for method, or empty if there is none.
|
||||
func (p *Method) PkgPath() string {
|
||||
pkg, _ := splitName(p.Name_)
|
||||
return pkg
|
||||
}
|
||||
|
||||
// UncommonType is present only for defined types or types with methods
|
||||
// (if T is a defined type, the uncommonTypes for T and *T have methods).
|
||||
// Using a pointer to this struct reduces the overall size required
|
||||
// to describe a non-defined type with no methods.
|
||||
type UncommonType struct {
|
||||
PkgPath_ string // import path; empty for built-in types like int, string
|
||||
Mcount uint16 // number of methods
|
||||
Xcount uint16 // number of exported methods
|
||||
Moff uint32 // offset from this uncommontype to [mcount]Method
|
||||
}
|
||||
|
||||
func (t *UncommonType) Methods() []Method {
|
||||
if t.Mcount == 0 {
|
||||
return nil
|
||||
}
|
||||
return (*[1 << 16]Method)(addChecked(unsafe.Pointer(t), uintptr(t.Moff), "t.mcount > 0"))[:t.Mcount:t.Mcount]
|
||||
}
|
||||
|
||||
func (t *UncommonType) ExportedMethods() []Method {
|
||||
if t.Xcount == 0 {
|
||||
return nil
|
||||
}
|
||||
return (*[1 << 16]Method)(addChecked(unsafe.Pointer(t), uintptr(t.Moff), "t.xcount > 0"))[:t.Xcount:t.Xcount]
|
||||
}
|
||||
|
||||
// Imethod represents a method on an interface type
|
||||
type Imethod struct {
|
||||
Name_ string // name of method
|
||||
Typ_ *FuncType // .(*FuncType) underneath
|
||||
}
|
||||
|
||||
// Exported reports whether the imethod is exported.
|
||||
func (p *Imethod) Exported() bool {
|
||||
return lastDot(p.Name_) == -1
|
||||
}
|
||||
|
||||
// Name returns the tag string for imethod.
|
||||
func (p *Imethod) Name() string {
|
||||
_, name := splitName(p.Name_)
|
||||
return name
|
||||
}
|
||||
|
||||
// PkgPath returns the pkgpath string for imethod, or empty if there is none.
|
||||
func (p *Imethod) PkgPath() string {
|
||||
pkg, _ := splitName(p.Name_)
|
||||
return pkg
|
||||
}
|
||||
|
||||
func (t *Type) Kind() Kind { return Kind(t.Kind_ & KindMask) }
|
||||
|
||||
func (t *Type) HasName() bool {
|
||||
return t.TFlag&TFlagNamed != 0
|
||||
}
|
||||
|
||||
func (t *Type) Pointers() bool { return t.PtrBytes != 0 }
|
||||
|
||||
// IfaceIndir reports whether t is stored indirectly in an interface value.
|
||||
func (t *Type) IfaceIndir() bool {
|
||||
return t.Kind_&KindDirectIface == 0
|
||||
}
|
||||
|
||||
// IsDirectIface reports whether t is stored directly in an interface value.
|
||||
func (t *Type) IsDirectIface() bool {
|
||||
return t.Kind_&KindDirectIface != 0
|
||||
}
|
||||
|
||||
// IsClosure reports whether t is closure struct
|
||||
func (t *Type) IsClosure() bool {
|
||||
return t.TFlag&TFlagClosure != 0
|
||||
}
|
||||
|
||||
// Size returns the size of data with type t.
|
||||
func (t *Type) Size() uintptr { return t.Size_ }
|
||||
|
||||
// Align returns the alignment of data with type t.
|
||||
func (t *Type) Align() int { return int(t.Align_) }
|
||||
|
||||
func (t *Type) FieldAlign() int { return int(t.FieldAlign_) }
|
||||
|
||||
// String returns string form of type t.
|
||||
func (t *Type) String() string {
|
||||
if t.TFlag&TFlagExtraStar != 0 {
|
||||
return "*" + t.Str_ // TODO(xsw): misunderstand
|
||||
}
|
||||
return t.Str_
|
||||
}
|
||||
|
||||
func (t *Type) Common() *Type {
|
||||
return t
|
||||
}
|
||||
|
||||
type structTypeUncommon struct {
|
||||
StructType
|
||||
u UncommonType
|
||||
}
|
||||
|
||||
// ChanDir returns the direction of t if t is a channel type, otherwise InvalidDir (0).
|
||||
func (t *Type) ChanDir() ChanDir {
|
||||
if t.Kind() == Chan {
|
||||
ch := (*ChanType)(unsafe.Pointer(t))
|
||||
return ch.Dir
|
||||
}
|
||||
return InvalidDir
|
||||
}
|
||||
|
||||
// Uncommon returns a pointer to T's "uncommon" data if there is any, otherwise nil
|
||||
func (t *Type) Uncommon() *UncommonType {
|
||||
if t.TFlag&TFlagUncommon == 0 {
|
||||
return nil
|
||||
}
|
||||
switch t.Kind() {
|
||||
case Struct:
|
||||
return &(*structTypeUncommon)(unsafe.Pointer(t)).u
|
||||
case Pointer:
|
||||
type u struct {
|
||||
PtrType
|
||||
u UncommonType
|
||||
}
|
||||
return &(*u)(unsafe.Pointer(t)).u
|
||||
case Func:
|
||||
type u struct {
|
||||
FuncType
|
||||
u UncommonType
|
||||
}
|
||||
return &(*u)(unsafe.Pointer(t)).u
|
||||
case Slice:
|
||||
type u struct {
|
||||
SliceType
|
||||
u UncommonType
|
||||
}
|
||||
return &(*u)(unsafe.Pointer(t)).u
|
||||
case Array:
|
||||
type u struct {
|
||||
ArrayType
|
||||
u UncommonType
|
||||
}
|
||||
return &(*u)(unsafe.Pointer(t)).u
|
||||
case Chan:
|
||||
type u struct {
|
||||
ChanType
|
||||
u UncommonType
|
||||
}
|
||||
return &(*u)(unsafe.Pointer(t)).u
|
||||
case Map:
|
||||
type u struct {
|
||||
MapType
|
||||
u UncommonType
|
||||
}
|
||||
return &(*u)(unsafe.Pointer(t)).u
|
||||
case Interface:
|
||||
type u struct {
|
||||
InterfaceType
|
||||
u UncommonType
|
||||
}
|
||||
return &(*u)(unsafe.Pointer(t)).u
|
||||
default:
|
||||
type u struct {
|
||||
Type
|
||||
u UncommonType
|
||||
}
|
||||
return &(*u)(unsafe.Pointer(t)).u
|
||||
}
|
||||
}
|
||||
|
||||
// Len returns the length of t if t is an array type, otherwise 0
|
||||
func (t *Type) Len() int {
|
||||
if t.Kind() == Array {
|
||||
return int((*ArrayType)(unsafe.Pointer(t)).Len)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Elem returns the element type for t if t is an array, channel, map, pointer, or slice, otherwise nil.
|
||||
func (t *Type) Elem() *Type {
|
||||
switch t.Kind() {
|
||||
case Pointer:
|
||||
tt := (*PtrType)(unsafe.Pointer(t))
|
||||
return tt.Elem
|
||||
case Slice:
|
||||
tt := (*SliceType)(unsafe.Pointer(t))
|
||||
return tt.Elem
|
||||
case Map:
|
||||
tt := (*MapType)(unsafe.Pointer(t))
|
||||
return tt.Elem
|
||||
case Array:
|
||||
tt := (*ArrayType)(unsafe.Pointer(t))
|
||||
return tt.Elem
|
||||
case Chan:
|
||||
tt := (*ChanType)(unsafe.Pointer(t))
|
||||
return tt.Elem
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StructType returns t cast to a *StructType, or nil if its tag does not match.
|
||||
func (t *Type) StructType() *StructType {
|
||||
if t.Kind() != Struct {
|
||||
return nil
|
||||
}
|
||||
return (*StructType)(unsafe.Pointer(t))
|
||||
}
|
||||
|
||||
// MapType returns t cast to a *MapType, or nil if its tag does not match.
|
||||
func (t *Type) MapType() *MapType {
|
||||
if t.Kind() != Map {
|
||||
return nil
|
||||
}
|
||||
return (*MapType)(unsafe.Pointer(t))
|
||||
}
|
||||
|
||||
// ArrayType returns t cast to a *ArrayType, or nil if its tag does not match.
|
||||
func (t *Type) ArrayType() *ArrayType {
|
||||
if t.Kind() != Array {
|
||||
return nil
|
||||
}
|
||||
return (*ArrayType)(unsafe.Pointer(t))
|
||||
}
|
||||
|
||||
// FuncType returns t cast to a *FuncType, or nil if its tag does not match.
|
||||
func (t *Type) FuncType() *FuncType {
|
||||
if t.Kind() != Func {
|
||||
return nil
|
||||
}
|
||||
return (*FuncType)(unsafe.Pointer(t))
|
||||
}
|
||||
|
||||
// InterfaceType returns t cast to a *InterfaceType, or nil if its tag does not match.
|
||||
func (t *Type) InterfaceType() *InterfaceType {
|
||||
if t.Kind() != Interface {
|
||||
return nil
|
||||
}
|
||||
return (*InterfaceType)(unsafe.Pointer(t))
|
||||
}
|
||||
|
||||
func (t *Type) ExportedMethods() []Method {
|
||||
ut := t.Uncommon()
|
||||
if ut == nil {
|
||||
return nil
|
||||
}
|
||||
return ut.ExportedMethods()
|
||||
}
|
||||
|
||||
func (t *Type) NumMethod() int {
|
||||
if t.Kind() == Interface {
|
||||
tt := (*InterfaceType)(unsafe.Pointer(t))
|
||||
return len(tt.Methods)
|
||||
}
|
||||
return len(t.ExportedMethods())
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// addChecked returns p+x.
|
||||
//
|
||||
// The whySafe string is ignored, so that the function still inlines
|
||||
// as efficiently as p+x, but all call sites should use the string to
|
||||
// record why the addition is safe, which is to say why the addition
|
||||
// does not cause x to advance to the very end of p's allocation
|
||||
// and therefore point incorrectly at the next block in memory.
|
||||
func addChecked(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer {
|
||||
_ = whySafe
|
||||
return unsafe.Pointer(uintptr(p) + x)
|
||||
}
|
||||
|
||||
func splitName(s string) (pkg string, name string) {
|
||||
i := lastDot(s)
|
||||
if i == -1 {
|
||||
return "", s
|
||||
}
|
||||
return s[:i], s[i+1:]
|
||||
}
|
||||
|
||||
func lastDot(s string) int {
|
||||
i := len(s) - 1
|
||||
for i >= 0 && s[i] != '.' {
|
||||
i--
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -191,8 +191,8 @@ func Do(args []string, conf *Config) ([]Package, error) {
|
||||
// updates. Since `github.com/goplus/llgo/c/*` contains many application libraries
|
||||
// that may change frequently, a possible solution is to have both depend on a
|
||||
// stable and limited c core API.
|
||||
if !llgoPkgImported(initial) {
|
||||
cfg.Dir = env.LLGoROOT()
|
||||
if !llgoRuntimeImported(initial) {
|
||||
cfg.Dir = env.LLGoRuntimeDir()
|
||||
}
|
||||
altPkgs, err := packages.LoadEx(dedup, sizes, cfg, altPkgPaths...)
|
||||
check(err)
|
||||
@@ -251,10 +251,10 @@ func Do(args []string, conf *Config) ([]Package, error) {
|
||||
return dpkg, nil
|
||||
}
|
||||
|
||||
func llgoPkgImported(pkgs []*packages.Package) bool {
|
||||
func llgoRuntimeImported(pkgs []*packages.Package) bool {
|
||||
for _, pkg := range pkgs {
|
||||
for _, imp := range pkg.Imports {
|
||||
if imp.Module != nil && imp.Module.Path == env.LLGoCompilerPkg {
|
||||
if imp.Module != nil && imp.Module.Path == env.LLGoRuntimePkg {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
16
compiler/internal/env/env.go
vendored
16
compiler/internal/env/env.go
vendored
@@ -7,9 +7,19 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoCompilerPkg = "github.com/goplus/llgo"
|
||||
LLGoCompilerPkg = "github.com/goplus/llgo"
|
||||
LLGoRuntimePkgName = "runtime"
|
||||
LLGoRuntimePkg = LLGoCompilerPkg + "/" + LLGoRuntimePkgName
|
||||
)
|
||||
|
||||
func LLGoRuntimeDir() string {
|
||||
root := LLGoROOT()
|
||||
if root != "" {
|
||||
return filepath.Join(root, LLGoRuntimePkgName)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func LLGoROOT() string {
|
||||
if root, ok := isLLGoRoot(os.Getenv("LLGO_ROOT")); ok {
|
||||
return root
|
||||
@@ -46,12 +56,12 @@ func isLLGoRoot(root string) (string, bool) {
|
||||
return "", false
|
||||
}
|
||||
// Check for go.mod
|
||||
data, err := os.ReadFile(filepath.Join(root, "go.mod"))
|
||||
data, err := os.ReadFile(filepath.Join(root, LLGoRuntimePkgName, "go.mod"))
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
// Check module name
|
||||
if !strings.Contains(string(data), "module "+LLGoCompilerPkg+"\n") {
|
||||
if !strings.Contains(string(data), "module "+LLGoRuntimePkg+"\n") {
|
||||
return "", false
|
||||
}
|
||||
return root, true
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
package hmac
|
||||
|
||||
// llgo:skipall
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"hash"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/openssl"
|
||||
)
|
||||
|
||||
type eface struct {
|
||||
_type unsafe.Pointer
|
||||
funcPtr *unsafe.Pointer
|
||||
}
|
||||
|
||||
func funcOf(a any) unsafe.Pointer {
|
||||
e := (*eface)(unsafe.Pointer(&a))
|
||||
return *e.funcPtr
|
||||
}
|
||||
|
||||
type digest openssl.HMAC_CTX
|
||||
|
||||
func (d *digest) Size() int { panic("todo: hmac.(*digest).Size") }
|
||||
|
||||
func (d *digest) BlockSize() int { panic("todo: hmac.(*digest).BlockSize") }
|
||||
|
||||
func (d *digest) Reset() {
|
||||
(*openssl.HMAC_CTX)(d).Reset()
|
||||
}
|
||||
|
||||
func (d *digest) Write(p []byte) (nn int, err error) {
|
||||
(*openssl.HMAC_CTX)(d).UpdateBytes(p)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (d *digest) Sum(in []byte) []byte {
|
||||
const Size = openssl.EVP_MAX_MD_SIZE
|
||||
var digestLen c.Uint
|
||||
hash := (*[Size]byte)(c.Alloca(Size))
|
||||
(*openssl.HMAC_CTX)(d).Final(&hash[0], &digestLen)
|
||||
return append(in, hash[:digestLen]...)
|
||||
}
|
||||
|
||||
// New returns a new HMAC hash using the given [hash.Hash] type and key.
|
||||
// New functions like sha256.New from [crypto/sha256] can be used as h.
|
||||
// h must return a new Hash every time it is called.
|
||||
// Note that unlike other hash implementations in the standard library,
|
||||
// the returned Hash does not implement [encoding.BinaryMarshaler]
|
||||
// or [encoding.BinaryUnmarshaler].
|
||||
func New(h func() hash.Hash, key []byte) hash.Hash {
|
||||
var md *openssl.EVP_MD
|
||||
switch funcOf(h) {
|
||||
case c.Func(sha256.New):
|
||||
md = openssl.EVP_sha256()
|
||||
default:
|
||||
panic("todo: hmac.New: unsupported hash function")
|
||||
}
|
||||
ctx := openssl.NewHMAC_CTX()
|
||||
ctx.InitBytes(key, md)
|
||||
return (*digest)(ctx)
|
||||
}
|
||||
|
||||
// Equal compares two MACs for equality without leaking timing information.
|
||||
func Equal(mac1, mac2 []byte) bool {
|
||||
// We don't have to be constant time if the lengths of the MACs are
|
||||
// different as that suggests that a completely different hash function
|
||||
// was used.
|
||||
return subtle.ConstantTimeCompare(mac1, mac2) == 1
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package md5
|
||||
|
||||
// llgo:skipall
|
||||
import (
|
||||
"crypto"
|
||||
"hash"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/openssl"
|
||||
)
|
||||
|
||||
func init() {
|
||||
crypto.RegisterHash(crypto.MD5, New)
|
||||
}
|
||||
|
||||
// The blocksize of MD5 in bytes.
|
||||
const BlockSize = 64
|
||||
|
||||
// The size of an MD5 checksum in bytes.
|
||||
const Size = 16
|
||||
|
||||
type digest struct {
|
||||
ctx openssl.MD5_CTX
|
||||
}
|
||||
|
||||
func (d *digest) Size() int { return Size }
|
||||
|
||||
func (d *digest) BlockSize() int { return BlockSize }
|
||||
|
||||
func (d *digest) Reset() {
|
||||
d.ctx.Init()
|
||||
}
|
||||
|
||||
func (d *digest) Write(p []byte) (nn int, err error) {
|
||||
d.ctx.UpdateBytes(p)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (d *digest) Sum(in []byte) []byte {
|
||||
hash := (*[Size]byte)(c.Alloca(Size))
|
||||
d.ctx.Final((*byte)(unsafe.Pointer(hash)))
|
||||
return append(in, hash[:]...)
|
||||
}
|
||||
|
||||
func New() hash.Hash {
|
||||
d := new(digest)
|
||||
d.ctx.Init()
|
||||
return d
|
||||
}
|
||||
|
||||
func Sum(data []byte) (ret [Size]byte) {
|
||||
openssl.MD5Bytes(data, &ret[0])
|
||||
return
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package rand
|
||||
|
||||
// llgo:skipall
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/openssl"
|
||||
"github.com/qiniu/x/errors"
|
||||
)
|
||||
|
||||
type rndReader struct{}
|
||||
|
||||
func (rndReader) Read(p []byte) (n int, err error) {
|
||||
return Read(p)
|
||||
}
|
||||
|
||||
// Reader is a global, shared instance of a cryptographically
|
||||
// secure random number generator.
|
||||
var Reader io.Reader = rndReader{}
|
||||
|
||||
type opensslError struct {
|
||||
file *c.Char
|
||||
line c.Int
|
||||
flags c.Int
|
||||
function *c.Char
|
||||
data *c.Char
|
||||
err openssl.Errno
|
||||
}
|
||||
|
||||
// [error code]:[library name]:[function name]:[reason string]:[[filename:line]]: [text message]
|
||||
func (p *opensslError) Error() string {
|
||||
const bufsize = 1024
|
||||
buf := (*c.Char)(c.Alloca(bufsize))
|
||||
lib := openssl.ERRLibErrorString(p.err)
|
||||
reason := openssl.ERRReasonErrorString(p.err)
|
||||
n := uintptr(c.Snprintf(
|
||||
buf, bufsize,
|
||||
c.Str("%d:%s:%s:%s:[%s:%d]: "),
|
||||
p.err, lib, p.function, reason, p.file, p.line))
|
||||
n += c.Strlen(openssl.ERRErrorString(p.err, c.Advance(buf, n)))
|
||||
return c.GoString(buf, n)
|
||||
}
|
||||
|
||||
func getError() *opensslError {
|
||||
ret := new(opensslError)
|
||||
err := openssl.ERRGetErrorAll(&ret.file, &ret.line, &ret.function, &ret.data, &ret.flags)
|
||||
if err == 0 {
|
||||
return nil
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func getErrors() error {
|
||||
var errs errors.List
|
||||
for openssl.ERRPeekError() != 0 {
|
||||
errs.Add(getError())
|
||||
}
|
||||
return errs.ToError()
|
||||
}
|
||||
|
||||
// Read is a helper function that calls Reader.Read using io.ReadFull.
|
||||
// On return, n == len(b) if and only if err == nil.
|
||||
func Read(b []byte) (n int, err error) {
|
||||
if openssl.RANDBytes(b) != 0 {
|
||||
return len(b), nil
|
||||
}
|
||||
return 0, getErrors()
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
// batched returns a function that calls f to populate a []byte by chunking it
|
||||
// into subslices of, at most, readMax bytes.
|
||||
func batched(f func([]byte) error, readMax int) func([]byte) error {
|
||||
return func(out []byte) error {
|
||||
for len(out) > 0 {
|
||||
read := len(out)
|
||||
if read > readMax {
|
||||
read = readMax
|
||||
}
|
||||
if err := f(out[:read]); err != nil {
|
||||
return err
|
||||
}
|
||||
out = out[read:]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -1,98 +0,0 @@
|
||||
// Copyright 2011 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 rand
|
||||
|
||||
/* TODO(xsw):
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// Prime returns a number of the given bit length that is prime with high probability.
|
||||
// Prime will return error for any error returned by rand.Read or if bits < 2.
|
||||
func Prime(rand io.Reader, bits int) (*big.Int, error) {
|
||||
if bits < 2 {
|
||||
return nil, errors.New("crypto/rand: prime size must be at least 2-bit")
|
||||
}
|
||||
|
||||
b := uint(bits % 8)
|
||||
if b == 0 {
|
||||
b = 8
|
||||
}
|
||||
|
||||
bytes := make([]byte, (bits+7)/8)
|
||||
p := new(big.Int)
|
||||
|
||||
for {
|
||||
if _, err := io.ReadFull(rand, bytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Clear bits in the first byte to make sure the candidate has a size <= bits.
|
||||
bytes[0] &= uint8(int(1<<b) - 1)
|
||||
// Don't let the value be too small, i.e, set the most significant two bits.
|
||||
// Setting the top two bits, rather than just the top bit,
|
||||
// means that when two of these values are multiplied together,
|
||||
// the result isn't ever one bit short.
|
||||
if b >= 2 {
|
||||
bytes[0] |= 3 << (b - 2)
|
||||
} else {
|
||||
// Here b==1, because b cannot be zero.
|
||||
bytes[0] |= 1
|
||||
if len(bytes) > 1 {
|
||||
bytes[1] |= 0x80
|
||||
}
|
||||
}
|
||||
// Make the value odd since an even number this large certainly isn't prime.
|
||||
bytes[len(bytes)-1] |= 1
|
||||
|
||||
p.SetBytes(bytes)
|
||||
if p.ProbablyPrime(20) {
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Int returns a uniform random value in [0, max). It panics if max <= 0.
|
||||
func Int(rand io.Reader, max *big.Int) (n *big.Int, err error) {
|
||||
if max.Sign() <= 0 {
|
||||
panic("crypto/rand: argument to Int is <= 0")
|
||||
}
|
||||
n = new(big.Int)
|
||||
n.Sub(max, n.SetUint64(1))
|
||||
// bitLen is the maximum bit length needed to encode a value < max.
|
||||
bitLen := n.BitLen()
|
||||
if bitLen == 0 {
|
||||
// the only valid result is 0
|
||||
return
|
||||
}
|
||||
// k is the maximum byte length needed to encode a value < max.
|
||||
k := (bitLen + 7) / 8
|
||||
// b is the number of bits in the most significant byte of max-1.
|
||||
b := uint(bitLen % 8)
|
||||
if b == 0 {
|
||||
b = 8
|
||||
}
|
||||
|
||||
bytes := make([]byte, k)
|
||||
|
||||
for {
|
||||
_, err = io.ReadFull(rand, bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Clear bits in the first byte to increase the probability
|
||||
// that the candidate is < max.
|
||||
bytes[0] &= uint8(int(1<<b) - 1)
|
||||
|
||||
n.SetBytes(bytes)
|
||||
if n.Cmp(max) < 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sha1
|
||||
|
||||
// llgo:skipall
|
||||
import (
|
||||
"crypto"
|
||||
"hash"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/openssl"
|
||||
)
|
||||
|
||||
func init() {
|
||||
crypto.RegisterHash(crypto.SHA1, New)
|
||||
}
|
||||
|
||||
// The blocksize of SHA-1 in bytes.
|
||||
const BlockSize = 64
|
||||
|
||||
// The size of a SHA-1 checksum in bytes.
|
||||
const Size = 20
|
||||
|
||||
type digest struct {
|
||||
ctx openssl.SHA_CTX
|
||||
}
|
||||
|
||||
func (d *digest) Size() int { return Size }
|
||||
|
||||
func (d *digest) BlockSize() int { return BlockSize }
|
||||
|
||||
func (d *digest) Reset() {
|
||||
d.ctx.Init()
|
||||
}
|
||||
|
||||
func (d *digest) Write(p []byte) (nn int, err error) {
|
||||
d.ctx.UpdateBytes(p)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (d *digest) Sum(in []byte) []byte {
|
||||
hash := (*[Size]byte)(c.Alloca(Size))
|
||||
d.ctx.Final((*byte)(unsafe.Pointer(hash)))
|
||||
return append(in, hash[:]...)
|
||||
}
|
||||
|
||||
// New returns a new hash.Hash computing the SHA1 checksum.
|
||||
func New() hash.Hash {
|
||||
d := new(digest)
|
||||
d.ctx.Init()
|
||||
return d
|
||||
}
|
||||
|
||||
// Sum returns the SHA-1 checksum of the data.
|
||||
func Sum(data []byte) (ret [Size]byte) {
|
||||
openssl.SHA1Bytes(data, &ret[0])
|
||||
return
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sha256
|
||||
|
||||
import (
|
||||
"hash"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/openssl"
|
||||
)
|
||||
|
||||
// The size of a SHA224 checksum in bytes.
|
||||
const Size224 = 28
|
||||
|
||||
type digest224 struct {
|
||||
ctx openssl.SHA224_CTX
|
||||
}
|
||||
|
||||
func (d *digest224) Size() int { return Size224 }
|
||||
|
||||
func (d *digest224) BlockSize() int { return BlockSize }
|
||||
|
||||
func (d *digest224) Reset() {
|
||||
d.ctx.Init()
|
||||
}
|
||||
|
||||
func (d *digest224) Write(p []byte) (nn int, err error) {
|
||||
d.ctx.UpdateBytes(p)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (d *digest224) Sum(in []byte) []byte {
|
||||
hash := (*[Size]byte)(c.Alloca(Size))
|
||||
d.ctx.Final((*byte)(unsafe.Pointer(hash)))
|
||||
return append(in, hash[:]...)
|
||||
}
|
||||
|
||||
// New224 returns a new hash.Hash computing the SHA224 checksum.
|
||||
func New224() hash.Hash {
|
||||
d := new(digest224)
|
||||
d.ctx.Init()
|
||||
return d
|
||||
}
|
||||
|
||||
// Sum224 returns the SHA224 checksum of the data.
|
||||
func Sum224(data []byte) (ret [Size224]byte) {
|
||||
openssl.SHA224Bytes(data, &ret[0])
|
||||
return
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sha256
|
||||
|
||||
// llgo:skipall
|
||||
import (
|
||||
"crypto"
|
||||
"hash"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/openssl"
|
||||
)
|
||||
|
||||
func init() {
|
||||
crypto.RegisterHash(crypto.SHA224, New224)
|
||||
crypto.RegisterHash(crypto.SHA256, New)
|
||||
}
|
||||
|
||||
// The blocksize of SHA256 and SHA224 in bytes.
|
||||
const BlockSize = 64
|
||||
|
||||
// The size of a SHA256 checksum in bytes.
|
||||
const Size = 32
|
||||
|
||||
type digest256 struct {
|
||||
ctx openssl.SHA256_CTX
|
||||
}
|
||||
|
||||
func (d *digest256) Size() int { return Size }
|
||||
|
||||
func (d *digest256) BlockSize() int { return BlockSize }
|
||||
|
||||
func (d *digest256) Reset() {
|
||||
d.ctx.Init()
|
||||
}
|
||||
|
||||
func (d *digest256) Write(p []byte) (nn int, err error) {
|
||||
d.ctx.UpdateBytes(p)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (d *digest256) Sum(in []byte) []byte {
|
||||
hash := (*[Size]byte)(c.Alloca(Size))
|
||||
d.ctx.Final((*byte)(unsafe.Pointer(hash)))
|
||||
return append(in, hash[:]...)
|
||||
}
|
||||
|
||||
// New returns a new hash.Hash computing the SHA256 checksum.
|
||||
func New() hash.Hash {
|
||||
d := new(digest256)
|
||||
d.ctx.Init()
|
||||
return d
|
||||
}
|
||||
|
||||
// Sum256 returns the SHA256 checksum of the data.
|
||||
func Sum256(data []byte) (ret [Size]byte) {
|
||||
openssl.SHA256Bytes(data, &ret[0])
|
||||
return
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sha512
|
||||
|
||||
import (
|
||||
"hash"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/openssl"
|
||||
)
|
||||
|
||||
type digest384 struct {
|
||||
ctx openssl.SHA384_CTX
|
||||
}
|
||||
|
||||
func (d *digest384) Size() int { return Size384 }
|
||||
|
||||
func (d *digest384) BlockSize() int { return BlockSize }
|
||||
|
||||
func (d *digest384) Reset() {
|
||||
d.ctx.Init()
|
||||
}
|
||||
|
||||
func (d *digest384) Write(p []byte) (nn int, err error) {
|
||||
d.ctx.UpdateBytes(p)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (d *digest384) Sum(in []byte) []byte {
|
||||
hash := (*[Size]byte)(c.Alloca(Size))
|
||||
d.ctx.Final((*byte)(unsafe.Pointer(hash)))
|
||||
return append(in, hash[:]...)
|
||||
}
|
||||
|
||||
func New384() hash.Hash {
|
||||
d := new(digest384)
|
||||
d.ctx.Init()
|
||||
return d
|
||||
}
|
||||
|
||||
func Sum384(data []byte) (ret [Size384]byte) {
|
||||
openssl.SHA384Bytes(data, &ret[0])
|
||||
return
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sha512
|
||||
|
||||
// llgo:skipall
|
||||
import (
|
||||
"crypto"
|
||||
"hash"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/openssl"
|
||||
)
|
||||
|
||||
func init() {
|
||||
crypto.RegisterHash(crypto.SHA384, New384)
|
||||
crypto.RegisterHash(crypto.SHA512, New)
|
||||
crypto.RegisterHash(crypto.SHA512_224, New512_224)
|
||||
crypto.RegisterHash(crypto.SHA512_256, New512_256)
|
||||
}
|
||||
|
||||
const (
|
||||
// Size is the size, in bytes, of a SHA-512 checksum.
|
||||
Size = 64
|
||||
|
||||
// Size224 is the size, in bytes, of a SHA-512/224 checksum.
|
||||
Size224 = 28
|
||||
|
||||
// Size256 is the size, in bytes, of a SHA-512/256 checksum.
|
||||
Size256 = 32
|
||||
|
||||
// Size384 is the size, in bytes, of a SHA-384 checksum.
|
||||
Size384 = 48
|
||||
|
||||
// BlockSize is the block size, in bytes, of the SHA-512/224,
|
||||
// SHA-512/256, SHA-384 and SHA-512 hash functions.
|
||||
BlockSize = 128
|
||||
)
|
||||
|
||||
type digest512 struct {
|
||||
ctx openssl.SHA512_CTX
|
||||
}
|
||||
|
||||
func (d *digest512) Size() int { return Size }
|
||||
|
||||
func (d *digest512) BlockSize() int { return BlockSize }
|
||||
|
||||
func (d *digest512) Reset() {
|
||||
d.ctx.Init()
|
||||
}
|
||||
|
||||
func (d *digest512) Write(p []byte) (nn int, err error) {
|
||||
d.ctx.UpdateBytes(p)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (d *digest512) Sum(in []byte) []byte {
|
||||
hash := (*[Size]byte)(c.Alloca(Size))
|
||||
d.ctx.Final((*byte)(unsafe.Pointer(hash)))
|
||||
return append(in, hash[:]...)
|
||||
}
|
||||
|
||||
func New() hash.Hash {
|
||||
d := new(digest512)
|
||||
d.ctx.Init()
|
||||
return d
|
||||
}
|
||||
|
||||
func Sum512(data []byte) (ret [Size]byte) {
|
||||
openssl.SHA512Bytes(data, &ret[0])
|
||||
return
|
||||
}
|
||||
|
||||
func New512_224() hash.Hash {
|
||||
panic("todo: crypto/sha512.New512_224")
|
||||
}
|
||||
|
||||
func Sum512_224(data []byte) [Size224]byte {
|
||||
panic("todo: crypto/sha512.Sum512_224")
|
||||
}
|
||||
|
||||
func New512_256() hash.Hash {
|
||||
panic("todo: crypto/sha512.New512_256")
|
||||
}
|
||||
|
||||
func Sum512_256(data []byte) [Size256]byte {
|
||||
panic("todo: crypto/sha512.Sum512_256")
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package subtle
|
||||
|
||||
// llgo:skip XORBytes
|
||||
import (
|
||||
_ "unsafe"
|
||||
)
|
||||
@@ -1,78 +0,0 @@
|
||||
// Copyright 2018 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 fmt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Errorf formats according to a format specifier and returns the string as a
|
||||
// value that satisfies error.
|
||||
//
|
||||
// If the format specifier includes a %w verb with an error operand,
|
||||
// the returned error will implement an Unwrap method returning the operand.
|
||||
// If there is more than one %w verb, the returned error will implement an
|
||||
// Unwrap method returning a []error containing all the %w operands in the
|
||||
// order they appear in the arguments.
|
||||
// It is invalid to supply the %w verb with an operand that does not implement
|
||||
// the error interface. The %w verb is otherwise a synonym for %v.
|
||||
func Errorf(format string, a ...any) error {
|
||||
p := newPrinter()
|
||||
p.wrapErrs = true
|
||||
p.doPrintf(format, a)
|
||||
s := string(p.buf)
|
||||
var err error
|
||||
switch len(p.wrappedErrs) {
|
||||
case 0:
|
||||
err = errors.New(s)
|
||||
case 1:
|
||||
w := &wrapError{msg: s}
|
||||
w.err, _ = a[p.wrappedErrs[0]].(error)
|
||||
err = w
|
||||
default:
|
||||
if p.reordered {
|
||||
sort.Ints(p.wrappedErrs)
|
||||
}
|
||||
var errs []error
|
||||
for i, argNum := range p.wrappedErrs {
|
||||
if i > 0 && p.wrappedErrs[i-1] == argNum {
|
||||
continue
|
||||
}
|
||||
if e, ok := a[argNum].(error); ok {
|
||||
errs = append(errs, e)
|
||||
}
|
||||
}
|
||||
err = &wrapErrors{s, errs}
|
||||
}
|
||||
p.free()
|
||||
return err
|
||||
}
|
||||
|
||||
type wrapError struct {
|
||||
msg string
|
||||
err error
|
||||
}
|
||||
|
||||
func (e *wrapError) Error() string {
|
||||
return e.msg
|
||||
}
|
||||
|
||||
func (e *wrapError) Unwrap() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
type wrapErrors struct {
|
||||
msg string
|
||||
errs []error
|
||||
}
|
||||
|
||||
func (e *wrapErrors) Error() string {
|
||||
return e.msg
|
||||
}
|
||||
|
||||
func (e *wrapErrors) Unwrap() []error {
|
||||
return e.errs
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package fmt
|
||||
|
||||
// llgo:skipall
|
||||
import (
|
||||
_ "unsafe"
|
||||
)
|
||||
@@ -1,594 +0,0 @@
|
||||
// Copyright 2009 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 fmt
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const (
|
||||
ldigits = "0123456789abcdefx"
|
||||
udigits = "0123456789ABCDEFX"
|
||||
)
|
||||
|
||||
const (
|
||||
signed = true
|
||||
unsigned = false
|
||||
)
|
||||
|
||||
// flags placed in a separate struct for easy clearing.
|
||||
type fmtFlags struct {
|
||||
widPresent bool
|
||||
precPresent bool
|
||||
minus bool
|
||||
plus bool
|
||||
sharp bool
|
||||
space bool
|
||||
zero bool
|
||||
|
||||
// For the formats %+v %#v, we set the plusV/sharpV flags
|
||||
// and clear the plus/sharp flags since %+v and %#v are in effect
|
||||
// different, flagless formats set at the top level.
|
||||
plusV bool
|
||||
sharpV bool
|
||||
}
|
||||
|
||||
// A fmt is the raw formatter used by Printf etc.
|
||||
// It prints into a buffer that must be set up separately.
|
||||
type fmt struct {
|
||||
buf *buffer
|
||||
|
||||
fmtFlags
|
||||
|
||||
wid int // width
|
||||
prec int // precision
|
||||
|
||||
// intbuf is large enough to store %b of an int64 with a sign and
|
||||
// avoids padding at the end of the struct on 32 bit architectures.
|
||||
intbuf [68]byte
|
||||
}
|
||||
|
||||
func (f *fmt) clearflags() {
|
||||
f.fmtFlags = fmtFlags{}
|
||||
}
|
||||
|
||||
func (f *fmt) init(buf *buffer) {
|
||||
f.buf = buf
|
||||
f.clearflags()
|
||||
}
|
||||
|
||||
// writePadding generates n bytes of padding.
|
||||
func (f *fmt) writePadding(n int) {
|
||||
if n <= 0 { // No padding bytes needed.
|
||||
return
|
||||
}
|
||||
buf := *f.buf
|
||||
oldLen := len(buf)
|
||||
newLen := oldLen + n
|
||||
// Make enough room for padding.
|
||||
if newLen > cap(buf) {
|
||||
buf = make(buffer, cap(buf)*2+n)
|
||||
copy(buf, *f.buf)
|
||||
}
|
||||
// Decide which byte the padding should be filled with.
|
||||
padByte := byte(' ')
|
||||
if f.zero {
|
||||
padByte = byte('0')
|
||||
}
|
||||
// Fill padding with padByte.
|
||||
padding := buf[oldLen:newLen]
|
||||
for i := range padding {
|
||||
padding[i] = padByte
|
||||
}
|
||||
*f.buf = buf[:newLen]
|
||||
}
|
||||
|
||||
// pad appends b to f.buf, padded on left (!f.minus) or right (f.minus).
|
||||
func (f *fmt) pad(b []byte) {
|
||||
if !f.widPresent || f.wid == 0 {
|
||||
f.buf.write(b)
|
||||
return
|
||||
}
|
||||
width := f.wid - utf8.RuneCount(b)
|
||||
if !f.minus {
|
||||
// left padding
|
||||
f.writePadding(width)
|
||||
f.buf.write(b)
|
||||
} else {
|
||||
// right padding
|
||||
f.buf.write(b)
|
||||
f.writePadding(width)
|
||||
}
|
||||
}
|
||||
|
||||
// padString appends s to f.buf, padded on left (!f.minus) or right (f.minus).
|
||||
func (f *fmt) padString(s string) {
|
||||
if !f.widPresent || f.wid == 0 {
|
||||
f.buf.writeString(s)
|
||||
return
|
||||
}
|
||||
width := f.wid - utf8.RuneCountInString(s)
|
||||
if !f.minus {
|
||||
// left padding
|
||||
f.writePadding(width)
|
||||
f.buf.writeString(s)
|
||||
} else {
|
||||
// right padding
|
||||
f.buf.writeString(s)
|
||||
f.writePadding(width)
|
||||
}
|
||||
}
|
||||
|
||||
// fmtBoolean formats a boolean.
|
||||
func (f *fmt) fmtBoolean(v bool) {
|
||||
if v {
|
||||
f.padString("true")
|
||||
} else {
|
||||
f.padString("false")
|
||||
}
|
||||
}
|
||||
|
||||
// fmtUnicode formats a uint64 as "U+0078" or with f.sharp set as "U+0078 'x'".
|
||||
func (f *fmt) fmtUnicode(u uint64) {
|
||||
buf := f.intbuf[0:]
|
||||
|
||||
// With default precision set the maximum needed buf length is 18
|
||||
// for formatting -1 with %#U ("U+FFFFFFFFFFFFFFFF") which fits
|
||||
// into the already allocated intbuf with a capacity of 68 bytes.
|
||||
prec := 4
|
||||
if f.precPresent && f.prec > 4 {
|
||||
prec = f.prec
|
||||
// Compute space needed for "U+" , number, " '", character, "'".
|
||||
width := 2 + prec + 2 + utf8.UTFMax + 1
|
||||
if width > len(buf) {
|
||||
buf = make([]byte, width)
|
||||
}
|
||||
}
|
||||
|
||||
// Format into buf, ending at buf[i]. Formatting numbers is easier right-to-left.
|
||||
i := len(buf)
|
||||
|
||||
// For %#U we want to add a space and a quoted character at the end of the buffer.
|
||||
if f.sharp && u <= utf8.MaxRune && strconv.IsPrint(rune(u)) {
|
||||
i--
|
||||
buf[i] = '\''
|
||||
i -= utf8.RuneLen(rune(u))
|
||||
utf8.EncodeRune(buf[i:], rune(u))
|
||||
i--
|
||||
buf[i] = '\''
|
||||
i--
|
||||
buf[i] = ' '
|
||||
}
|
||||
// Format the Unicode code point u as a hexadecimal number.
|
||||
for u >= 16 {
|
||||
i--
|
||||
buf[i] = udigits[u&0xF]
|
||||
prec--
|
||||
u >>= 4
|
||||
}
|
||||
i--
|
||||
buf[i] = udigits[u]
|
||||
prec--
|
||||
// Add zeros in front of the number until requested precision is reached.
|
||||
for prec > 0 {
|
||||
i--
|
||||
buf[i] = '0'
|
||||
prec--
|
||||
}
|
||||
// Add a leading "U+".
|
||||
i--
|
||||
buf[i] = '+'
|
||||
i--
|
||||
buf[i] = 'U'
|
||||
|
||||
oldZero := f.zero
|
||||
f.zero = false
|
||||
f.pad(buf[i:])
|
||||
f.zero = oldZero
|
||||
}
|
||||
|
||||
// fmtInteger formats signed and unsigned integers.
|
||||
func (f *fmt) fmtInteger(u uint64, base int, isSigned bool, verb rune, digits string) {
|
||||
negative := isSigned && int64(u) < 0
|
||||
if negative {
|
||||
u = -u
|
||||
}
|
||||
|
||||
buf := f.intbuf[0:]
|
||||
// The already allocated f.intbuf with a capacity of 68 bytes
|
||||
// is large enough for integer formatting when no precision or width is set.
|
||||
if f.widPresent || f.precPresent {
|
||||
// Account 3 extra bytes for possible addition of a sign and "0x".
|
||||
width := 3 + f.wid + f.prec // wid and prec are always positive.
|
||||
if width > len(buf) {
|
||||
// We're going to need a bigger boat.
|
||||
buf = make([]byte, width)
|
||||
}
|
||||
}
|
||||
|
||||
// Two ways to ask for extra leading zero digits: %.3d or %03d.
|
||||
// If both are specified the f.zero flag is ignored and
|
||||
// padding with spaces is used instead.
|
||||
prec := 0
|
||||
if f.precPresent {
|
||||
prec = f.prec
|
||||
// Precision of 0 and value of 0 means "print nothing" but padding.
|
||||
if prec == 0 && u == 0 {
|
||||
oldZero := f.zero
|
||||
f.zero = false
|
||||
f.writePadding(f.wid)
|
||||
f.zero = oldZero
|
||||
return
|
||||
}
|
||||
} else if f.zero && f.widPresent {
|
||||
prec = f.wid
|
||||
if negative || f.plus || f.space {
|
||||
prec-- // leave room for sign
|
||||
}
|
||||
}
|
||||
|
||||
// Because printing is easier right-to-left: format u into buf, ending at buf[i].
|
||||
// We could make things marginally faster by splitting the 32-bit case out
|
||||
// into a separate block but it's not worth the duplication, so u has 64 bits.
|
||||
i := len(buf)
|
||||
// Use constants for the division and modulo for more efficient code.
|
||||
// Switch cases ordered by popularity.
|
||||
switch base {
|
||||
case 10:
|
||||
for u >= 10 {
|
||||
i--
|
||||
next := u / 10
|
||||
buf[i] = byte('0' + u - next*10)
|
||||
u = next
|
||||
}
|
||||
case 16:
|
||||
for u >= 16 {
|
||||
i--
|
||||
buf[i] = digits[u&0xF]
|
||||
u >>= 4
|
||||
}
|
||||
case 8:
|
||||
for u >= 8 {
|
||||
i--
|
||||
buf[i] = byte('0' + u&7)
|
||||
u >>= 3
|
||||
}
|
||||
case 2:
|
||||
for u >= 2 {
|
||||
i--
|
||||
buf[i] = byte('0' + u&1)
|
||||
u >>= 1
|
||||
}
|
||||
default:
|
||||
panic("fmt: unknown base; can't happen")
|
||||
}
|
||||
i--
|
||||
buf[i] = digits[u]
|
||||
for i > 0 && prec > len(buf)-i {
|
||||
i--
|
||||
buf[i] = '0'
|
||||
}
|
||||
|
||||
// Various prefixes: 0x, -, etc.
|
||||
if f.sharp {
|
||||
switch base {
|
||||
case 2:
|
||||
// Add a leading 0b.
|
||||
i--
|
||||
buf[i] = 'b'
|
||||
i--
|
||||
buf[i] = '0'
|
||||
case 8:
|
||||
if buf[i] != '0' {
|
||||
i--
|
||||
buf[i] = '0'
|
||||
}
|
||||
case 16:
|
||||
// Add a leading 0x or 0X.
|
||||
i--
|
||||
buf[i] = digits[16]
|
||||
i--
|
||||
buf[i] = '0'
|
||||
}
|
||||
}
|
||||
if verb == 'O' {
|
||||
i--
|
||||
buf[i] = 'o'
|
||||
i--
|
||||
buf[i] = '0'
|
||||
}
|
||||
|
||||
if negative {
|
||||
i--
|
||||
buf[i] = '-'
|
||||
} else if f.plus {
|
||||
i--
|
||||
buf[i] = '+'
|
||||
} else if f.space {
|
||||
i--
|
||||
buf[i] = ' '
|
||||
}
|
||||
|
||||
// Left padding with zeros has already been handled like precision earlier
|
||||
// or the f.zero flag is ignored due to an explicitly set precision.
|
||||
oldZero := f.zero
|
||||
f.zero = false
|
||||
f.pad(buf[i:])
|
||||
f.zero = oldZero
|
||||
}
|
||||
|
||||
// truncateString truncates the string s to the specified precision, if present.
|
||||
func (f *fmt) truncateString(s string) string {
|
||||
if f.precPresent {
|
||||
n := f.prec
|
||||
for i := range s {
|
||||
n--
|
||||
if n < 0 {
|
||||
return s[:i]
|
||||
}
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// truncate truncates the byte slice b as a string of the specified precision, if present.
|
||||
func (f *fmt) truncate(b []byte) []byte {
|
||||
if f.precPresent {
|
||||
n := f.prec
|
||||
for i := 0; i < len(b); {
|
||||
n--
|
||||
if n < 0 {
|
||||
return b[:i]
|
||||
}
|
||||
wid := 1
|
||||
if b[i] >= utf8.RuneSelf {
|
||||
_, wid = utf8.DecodeRune(b[i:])
|
||||
}
|
||||
i += wid
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// fmtS formats a string.
|
||||
func (f *fmt) fmtS(s string) {
|
||||
s = f.truncateString(s)
|
||||
f.padString(s)
|
||||
}
|
||||
|
||||
// fmtBs formats the byte slice b as if it was formatted as string with fmtS.
|
||||
func (f *fmt) fmtBs(b []byte) {
|
||||
b = f.truncate(b)
|
||||
f.pad(b)
|
||||
}
|
||||
|
||||
// fmtSbx formats a string or byte slice as a hexadecimal encoding of its bytes.
|
||||
func (f *fmt) fmtSbx(s string, b []byte, digits string) {
|
||||
length := len(b)
|
||||
if b == nil {
|
||||
// No byte slice present. Assume string s should be encoded.
|
||||
length = len(s)
|
||||
}
|
||||
// Set length to not process more bytes than the precision demands.
|
||||
if f.precPresent && f.prec < length {
|
||||
length = f.prec
|
||||
}
|
||||
// Compute width of the encoding taking into account the f.sharp and f.space flag.
|
||||
width := 2 * length
|
||||
if width > 0 {
|
||||
if f.space {
|
||||
// Each element encoded by two hexadecimals will get a leading 0x or 0X.
|
||||
if f.sharp {
|
||||
width *= 2
|
||||
}
|
||||
// Elements will be separated by a space.
|
||||
width += length - 1
|
||||
} else if f.sharp {
|
||||
// Only a leading 0x or 0X will be added for the whole string.
|
||||
width += 2
|
||||
}
|
||||
} else { // The byte slice or string that should be encoded is empty.
|
||||
if f.widPresent {
|
||||
f.writePadding(f.wid)
|
||||
}
|
||||
return
|
||||
}
|
||||
// Handle padding to the left.
|
||||
if f.widPresent && f.wid > width && !f.minus {
|
||||
f.writePadding(f.wid - width)
|
||||
}
|
||||
// Write the encoding directly into the output buffer.
|
||||
buf := *f.buf
|
||||
if f.sharp {
|
||||
// Add leading 0x or 0X.
|
||||
buf = append(buf, '0', digits[16])
|
||||
}
|
||||
var c byte
|
||||
for i := 0; i < length; i++ {
|
||||
if f.space && i > 0 {
|
||||
// Separate elements with a space.
|
||||
buf = append(buf, ' ')
|
||||
if f.sharp {
|
||||
// Add leading 0x or 0X for each element.
|
||||
buf = append(buf, '0', digits[16])
|
||||
}
|
||||
}
|
||||
if b != nil {
|
||||
c = b[i] // Take a byte from the input byte slice.
|
||||
} else {
|
||||
c = s[i] // Take a byte from the input string.
|
||||
}
|
||||
// Encode each byte as two hexadecimal digits.
|
||||
buf = append(buf, digits[c>>4], digits[c&0xF])
|
||||
}
|
||||
*f.buf = buf
|
||||
// Handle padding to the right.
|
||||
if f.widPresent && f.wid > width && f.minus {
|
||||
f.writePadding(f.wid - width)
|
||||
}
|
||||
}
|
||||
|
||||
// fmtSx formats a string as a hexadecimal encoding of its bytes.
|
||||
func (f *fmt) fmtSx(s, digits string) {
|
||||
f.fmtSbx(s, nil, digits)
|
||||
}
|
||||
|
||||
// fmtBx formats a byte slice as a hexadecimal encoding of its bytes.
|
||||
func (f *fmt) fmtBx(b []byte, digits string) {
|
||||
f.fmtSbx("", b, digits)
|
||||
}
|
||||
|
||||
// fmtQ formats a string as a double-quoted, escaped Go string constant.
|
||||
// If f.sharp is set a raw (backquoted) string may be returned instead
|
||||
// if the string does not contain any control characters other than tab.
|
||||
func (f *fmt) fmtQ(s string) {
|
||||
s = f.truncateString(s)
|
||||
if f.sharp && strconv.CanBackquote(s) {
|
||||
f.padString("`" + s + "`")
|
||||
return
|
||||
}
|
||||
buf := f.intbuf[:0]
|
||||
if f.plus {
|
||||
f.pad(strconv.AppendQuoteToASCII(buf, s))
|
||||
} else {
|
||||
f.pad(strconv.AppendQuote(buf, s))
|
||||
}
|
||||
}
|
||||
|
||||
// fmtC formats an integer as a Unicode character.
|
||||
// If the character is not valid Unicode, it will print '\ufffd'.
|
||||
func (f *fmt) fmtC(c uint64) {
|
||||
// Explicitly check whether c exceeds utf8.MaxRune since the conversion
|
||||
// of a uint64 to a rune may lose precision that indicates an overflow.
|
||||
r := rune(c)
|
||||
if c > utf8.MaxRune {
|
||||
r = utf8.RuneError
|
||||
}
|
||||
buf := f.intbuf[:0]
|
||||
f.pad(utf8.AppendRune(buf, r))
|
||||
}
|
||||
|
||||
// fmtQc formats an integer as a single-quoted, escaped Go character constant.
|
||||
// If the character is not valid Unicode, it will print '\ufffd'.
|
||||
func (f *fmt) fmtQc(c uint64) {
|
||||
r := rune(c)
|
||||
if c > utf8.MaxRune {
|
||||
r = utf8.RuneError
|
||||
}
|
||||
buf := f.intbuf[:0]
|
||||
if f.plus {
|
||||
f.pad(strconv.AppendQuoteRuneToASCII(buf, r))
|
||||
} else {
|
||||
f.pad(strconv.AppendQuoteRune(buf, r))
|
||||
}
|
||||
}
|
||||
|
||||
// fmtFloat formats a float64. It assumes that verb is a valid format specifier
|
||||
// for strconv.AppendFloat and therefore fits into a byte.
|
||||
func (f *fmt) fmtFloat(v float64, size int, verb rune, prec int) {
|
||||
// Explicit precision in format specifier overrules default precision.
|
||||
if f.precPresent {
|
||||
prec = f.prec
|
||||
}
|
||||
// Format number, reserving space for leading + sign if needed.
|
||||
num := strconv.AppendFloat(f.intbuf[:1], v, byte(verb), prec, size)
|
||||
if num[1] == '-' || num[1] == '+' {
|
||||
num = num[1:]
|
||||
} else {
|
||||
num[0] = '+'
|
||||
}
|
||||
// f.space means to add a leading space instead of a "+" sign unless
|
||||
// the sign is explicitly asked for by f.plus.
|
||||
if f.space && num[0] == '+' && !f.plus {
|
||||
num[0] = ' '
|
||||
}
|
||||
// Special handling for infinities and NaN,
|
||||
// which don't look like a number so shouldn't be padded with zeros.
|
||||
if num[1] == 'I' || num[1] == 'N' {
|
||||
oldZero := f.zero
|
||||
f.zero = false
|
||||
// Remove sign before NaN if not asked for.
|
||||
if num[1] == 'N' && !f.space && !f.plus {
|
||||
num = num[1:]
|
||||
}
|
||||
f.pad(num)
|
||||
f.zero = oldZero
|
||||
return
|
||||
}
|
||||
// The sharp flag forces printing a decimal point for non-binary formats
|
||||
// and retains trailing zeros, which we may need to restore.
|
||||
if f.sharp && verb != 'b' {
|
||||
digits := 0
|
||||
switch verb {
|
||||
case 'v', 'g', 'G', 'x':
|
||||
digits = prec
|
||||
// If no precision is set explicitly use a precision of 6.
|
||||
if digits == -1 {
|
||||
digits = 6
|
||||
}
|
||||
}
|
||||
|
||||
// Buffer pre-allocated with enough room for
|
||||
// exponent notations of the form "e+123" or "p-1023".
|
||||
var tailBuf [6]byte
|
||||
tail := tailBuf[:0]
|
||||
|
||||
hasDecimalPoint := false
|
||||
sawNonzeroDigit := false
|
||||
// Starting from i = 1 to skip sign at num[0].
|
||||
for i := 1; i < len(num); i++ {
|
||||
switch num[i] {
|
||||
case '.':
|
||||
hasDecimalPoint = true
|
||||
case 'p', 'P':
|
||||
tail = append(tail, num[i:]...)
|
||||
num = num[:i]
|
||||
case 'e', 'E':
|
||||
if verb != 'x' && verb != 'X' {
|
||||
tail = append(tail, num[i:]...)
|
||||
num = num[:i]
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
if num[i] != '0' {
|
||||
sawNonzeroDigit = true
|
||||
}
|
||||
// Count significant digits after the first non-zero digit.
|
||||
if sawNonzeroDigit {
|
||||
digits--
|
||||
}
|
||||
}
|
||||
}
|
||||
if !hasDecimalPoint {
|
||||
// Leading digit 0 should contribute once to digits.
|
||||
if len(num) == 2 && num[1] == '0' {
|
||||
digits--
|
||||
}
|
||||
num = append(num, '.')
|
||||
}
|
||||
for digits > 0 {
|
||||
num = append(num, '0')
|
||||
digits--
|
||||
}
|
||||
num = append(num, tail...)
|
||||
}
|
||||
// We want a sign if asked for and if the sign is not positive.
|
||||
if f.plus || num[0] != '+' {
|
||||
// If we're zero padding to the left we want the sign before the leading zeros.
|
||||
// Achieve this by writing the sign out and then padding the unsigned number.
|
||||
if f.zero && f.widPresent && f.wid > len(num) {
|
||||
f.buf.writeByte(num[0])
|
||||
f.writePadding(f.wid - len(num))
|
||||
f.buf.write(num[1:])
|
||||
return
|
||||
}
|
||||
f.pad(num)
|
||||
return
|
||||
}
|
||||
// No sign to show and the number is positive; just print the unsigned number.
|
||||
f.pad(num[1:])
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package crc32
|
||||
|
||||
// llgo:skipall
|
||||
import (
|
||||
"hash"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/zlib"
|
||||
)
|
||||
|
||||
// The size of a CRC-32 checksum in bytes.
|
||||
const Size = 4
|
||||
|
||||
// Predefined polynomials.
|
||||
const (
|
||||
// IEEE is by far and away the most common CRC-32 polynomial.
|
||||
// Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, ...
|
||||
IEEE = 0xedb88320
|
||||
|
||||
// Castagnoli's polynomial, used in iSCSI.
|
||||
// Has better error detection characteristics than IEEE.
|
||||
// https://dx.doi.org/10.1109/26.231911
|
||||
Castagnoli = 0x82f63b78
|
||||
|
||||
// Koopman's polynomial.
|
||||
// Also has better error detection characteristics than IEEE.
|
||||
// https://dx.doi.org/10.1109/DSN.2002.1028931
|
||||
Koopman = 0xeb31d82e
|
||||
)
|
||||
|
||||
// Table is a 256-word table representing the polynomial for efficient processing.
|
||||
type Table [256]uint32
|
||||
|
||||
// IEEETable is the table for the IEEE polynomial.
|
||||
var IEEETable *Table = new(Table)
|
||||
|
||||
// MakeTable returns a Table constructed from the specified polynomial.
|
||||
// The contents of this Table must not be modified.
|
||||
func MakeTable(poly uint32) *Table {
|
||||
if poly == IEEE {
|
||||
return IEEETable
|
||||
}
|
||||
panic("todo: hash/crc32.MakeTable")
|
||||
}
|
||||
|
||||
type digest uint32
|
||||
|
||||
func (d *digest) Size() int { return Size }
|
||||
|
||||
func (d *digest) BlockSize() int { return 1 }
|
||||
|
||||
func (d *digest) Reset() { *d = 0 }
|
||||
|
||||
func (d *digest) Write(p []byte) (n int, err error) {
|
||||
*d = digest(zlib.Crc32ZBytes(c.Ulong(*d), p))
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (d *digest) Sum32() uint32 { return uint32(*d) }
|
||||
|
||||
func (d *digest) Sum(in []byte) []byte {
|
||||
s := d.Sum32()
|
||||
return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s))
|
||||
}
|
||||
|
||||
func New(tab *Table) hash.Hash32 {
|
||||
if tab == IEEETable {
|
||||
return new(digest)
|
||||
}
|
||||
panic("todo: hash/crc32.New")
|
||||
}
|
||||
|
||||
// NewIEEE creates a new hash.Hash32 computing the CRC-32 checksum using
|
||||
// the IEEE polynomial. Its Sum method will lay the value out in
|
||||
// big-endian byte order. The returned Hash32 also implements
|
||||
// encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to marshal
|
||||
// and unmarshal the internal state of the hash.
|
||||
func NewIEEE() hash.Hash32 { return New(IEEETable) }
|
||||
|
||||
// Update returns the result of adding the bytes in p to the crc.
|
||||
func Update(crc uint32, tab *Table, p []byte) uint32 {
|
||||
if tab == IEEETable {
|
||||
return uint32(zlib.Crc32ZBytes(c.Ulong(crc), p))
|
||||
}
|
||||
panic("todo: hash/crc32.Update")
|
||||
}
|
||||
|
||||
// Checksum returns the CRC-32 checksum of data
|
||||
// using the polynomial represented by the Table.
|
||||
func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) }
|
||||
|
||||
// ChecksumIEEE returns the CRC-32 checksum of data
|
||||
// using the IEEE polynomial.
|
||||
func ChecksumIEEE(data []byte) uint32 {
|
||||
return uint32(zlib.Crc32ZBytes(0, data))
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package abi
|
||||
|
||||
// llgo:skipall
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/compiler/internal/abi"
|
||||
)
|
||||
|
||||
type InterfaceType = abi.InterfaceType
|
||||
|
||||
func NoEscape(p unsafe.Pointer) unsafe.Pointer {
|
||||
x := uintptr(p)
|
||||
return unsafe.Pointer(x ^ 0)
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package bytealg
|
||||
|
||||
// llgo:skip init CompareString
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/compiler/internal/runtime"
|
||||
)
|
||||
|
||||
func IndexByte(b []byte, ch byte) int {
|
||||
ptr := unsafe.Pointer(unsafe.SliceData(b))
|
||||
ret := c.Memchr(ptr, c.Int(ch), uintptr(len(b)))
|
||||
if ret != nil {
|
||||
return int(uintptr(ret) - uintptr(ptr))
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func IndexByteString(s string, ch byte) int {
|
||||
ptr := unsafe.Pointer(unsafe.StringData(s))
|
||||
ret := c.Memchr(ptr, c.Int(ch), uintptr(len(s)))
|
||||
if ret != nil {
|
||||
return int(uintptr(ret) - uintptr(ptr))
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func Count(b []byte, c byte) (n int) {
|
||||
for _, x := range b {
|
||||
if x == c {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CountString(s string, c byte) (n int) {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == c {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Index returns the index of the first instance of b in a, or -1 if b is not present in a.
|
||||
// Requires 2 <= len(b) <= MaxLen.
|
||||
func Index(a, b []byte) int {
|
||||
for i := 0; i <= len(a)-len(b); i++ {
|
||||
if equal(a[i:i+len(b)], b) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func equal(a, b []byte) bool {
|
||||
if n := len(a); n == len(b) {
|
||||
return c.Memcmp(unsafe.Pointer(unsafe.SliceData(a)), unsafe.Pointer(unsafe.SliceData(b)), uintptr(n)) == 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IndexString returns the index of the first instance of b in a, or -1 if b is not present in a.
|
||||
// Requires 2 <= len(b) <= MaxLen.
|
||||
func IndexString(a, b string) int {
|
||||
for i := 0; i <= len(a)-len(b); i++ {
|
||||
if a[i:i+len(b)] == b {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// MakeNoZero makes a slice of length and capacity n without zeroing the bytes.
|
||||
// It is the caller's responsibility to ensure uninitialized bytes
|
||||
// do not leak to the end user.
|
||||
func MakeNoZero(n int) (r []byte) {
|
||||
s := (*sliceHead)(unsafe.Pointer(&r))
|
||||
s.data = runtime.AllocU(uintptr(n))
|
||||
s.len = n
|
||||
s.cap = n
|
||||
return
|
||||
}
|
||||
|
||||
type sliceHead struct {
|
||||
data unsafe.Pointer
|
||||
len int
|
||||
cap int
|
||||
}
|
||||
|
||||
func LastIndexByte(s []byte, c byte) int {
|
||||
for i := len(s) - 1; i >= 0; i-- {
|
||||
if s[i] == c {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func LastIndexByteString(s string, c byte) int {
|
||||
for i := len(s) - 1; i >= 0; i-- {
|
||||
if s[i] == c {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func CompareString(a, b string) int {
|
||||
l := len(a)
|
||||
if len(b) < l {
|
||||
l = len(b)
|
||||
}
|
||||
for i := 0; i < l; i++ {
|
||||
c1, c2 := a[i], b[i]
|
||||
if c1 < c2 {
|
||||
return -1
|
||||
}
|
||||
if c1 > c2 {
|
||||
return +1
|
||||
}
|
||||
}
|
||||
if len(a) < len(b) {
|
||||
return -1
|
||||
}
|
||||
if len(a) > len(b) {
|
||||
return +1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package filepathlite
|
||||
@@ -1,220 +0,0 @@
|
||||
// Copyright 2018 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 fmtsort provides a general stable ordering mechanism
|
||||
// for maps, on behalf of the fmt and text/template packages.
|
||||
// It is not guaranteed to be efficient and works only for types
|
||||
// that are valid map keys.
|
||||
package fmtsort
|
||||
|
||||
// llgo:skipall
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Note: Throughout this package we avoid calling reflect.Value.Interface as
|
||||
// it is not always legal to do so and it's easier to avoid the issue than to face it.
|
||||
|
||||
// SortedMap represents a map's keys and values. The keys and values are
|
||||
// aligned in index order: Value[i] is the value in the map corresponding to Key[i].
|
||||
type SortedMap struct {
|
||||
Key []reflect.Value
|
||||
Value []reflect.Value
|
||||
}
|
||||
|
||||
func (o *SortedMap) Len() int { return len(o.Key) }
|
||||
func (o *SortedMap) Less(i, j int) bool { return compare(o.Key[i], o.Key[j]) < 0 }
|
||||
func (o *SortedMap) Swap(i, j int) {
|
||||
o.Key[i], o.Key[j] = o.Key[j], o.Key[i]
|
||||
o.Value[i], o.Value[j] = o.Value[j], o.Value[i]
|
||||
}
|
||||
|
||||
// Sort accepts a map and returns a SortedMap that has the same keys and
|
||||
// values but in a stable sorted order according to the keys, modulo issues
|
||||
// raised by unorderable key values such as NaNs.
|
||||
//
|
||||
// The ordering rules are more general than with Go's < operator:
|
||||
//
|
||||
// - when applicable, nil compares low
|
||||
// - ints, floats, and strings order by <
|
||||
// - NaN compares less than non-NaN floats
|
||||
// - bool compares false before true
|
||||
// - complex compares real, then imag
|
||||
// - pointers compare by machine address
|
||||
// - channel values compare by machine address
|
||||
// - structs compare each field in turn
|
||||
// - arrays compare each element in turn.
|
||||
// Otherwise identical arrays compare by length.
|
||||
// - interface values compare first by reflect.Type describing the concrete type
|
||||
// and then by concrete value as described in the previous rules.
|
||||
func Sort(mapValue reflect.Value) *SortedMap {
|
||||
if mapValue.Type().Kind() != reflect.Map {
|
||||
return nil
|
||||
}
|
||||
// Note: this code is arranged to not panic even in the presence
|
||||
// of a concurrent map update. The runtime is responsible for
|
||||
// yelling loudly if that happens. See issue 33275.
|
||||
n := mapValue.Len()
|
||||
key := make([]reflect.Value, 0, n)
|
||||
value := make([]reflect.Value, 0, n)
|
||||
iter := mapValue.MapRange()
|
||||
for iter.Next() {
|
||||
key = append(key, iter.Key())
|
||||
value = append(value, iter.Value())
|
||||
}
|
||||
sorted := &SortedMap{
|
||||
Key: key,
|
||||
Value: value,
|
||||
}
|
||||
sort.Stable(sorted)
|
||||
return sorted
|
||||
}
|
||||
|
||||
// compare compares two values of the same type. It returns -1, 0, 1
|
||||
// according to whether a > b (1), a == b (0), or a < b (-1).
|
||||
// If the types differ, it returns -1.
|
||||
// See the comment on Sort for the comparison rules.
|
||||
func compare(aVal, bVal reflect.Value) int {
|
||||
aType, bType := aVal.Type(), bVal.Type()
|
||||
if aType != bType {
|
||||
return -1 // No good answer possible, but don't return 0: they're not equal.
|
||||
}
|
||||
switch aVal.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
a, b := aVal.Int(), bVal.Int()
|
||||
switch {
|
||||
case a < b:
|
||||
return -1
|
||||
case a > b:
|
||||
return 1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
a, b := aVal.Uint(), bVal.Uint()
|
||||
switch {
|
||||
case a < b:
|
||||
return -1
|
||||
case a > b:
|
||||
return 1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
case reflect.String:
|
||||
a, b := aVal.String(), bVal.String()
|
||||
switch {
|
||||
case a < b:
|
||||
return -1
|
||||
case a > b:
|
||||
return 1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return floatCompare(aVal.Float(), bVal.Float())
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
a, b := aVal.Complex(), bVal.Complex()
|
||||
if c := floatCompare(real(a), real(b)); c != 0 {
|
||||
return c
|
||||
}
|
||||
return floatCompare(imag(a), imag(b))
|
||||
case reflect.Bool:
|
||||
a, b := aVal.Bool(), bVal.Bool()
|
||||
switch {
|
||||
case a == b:
|
||||
return 0
|
||||
case a:
|
||||
return 1
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
case reflect.Pointer, reflect.UnsafePointer:
|
||||
a, b := aVal.Pointer(), bVal.Pointer()
|
||||
switch {
|
||||
case a < b:
|
||||
return -1
|
||||
case a > b:
|
||||
return 1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
case reflect.Chan:
|
||||
if c, ok := nilCompare(aVal, bVal); ok {
|
||||
return c
|
||||
}
|
||||
ap, bp := aVal.Pointer(), bVal.Pointer()
|
||||
switch {
|
||||
case ap < bp:
|
||||
return -1
|
||||
case ap > bp:
|
||||
return 1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
case reflect.Struct:
|
||||
for i := 0; i < aVal.NumField(); i++ {
|
||||
if c := compare(aVal.Field(i), bVal.Field(i)); c != 0 {
|
||||
return c
|
||||
}
|
||||
}
|
||||
return 0
|
||||
case reflect.Array:
|
||||
for i := 0; i < aVal.Len(); i++ {
|
||||
if c := compare(aVal.Index(i), bVal.Index(i)); c != 0 {
|
||||
return c
|
||||
}
|
||||
}
|
||||
return 0
|
||||
case reflect.Interface:
|
||||
if c, ok := nilCompare(aVal, bVal); ok {
|
||||
return c
|
||||
}
|
||||
c := compare(reflect.ValueOf(aVal.Elem().Type()), reflect.ValueOf(bVal.Elem().Type()))
|
||||
if c != 0 {
|
||||
return c
|
||||
}
|
||||
return compare(aVal.Elem(), bVal.Elem())
|
||||
default:
|
||||
// Certain types cannot appear as keys (maps, funcs, slices), but be explicit.
|
||||
panic("bad type in compare: " + aType.String())
|
||||
}
|
||||
}
|
||||
|
||||
// nilCompare checks whether either value is nil. If not, the boolean is false.
|
||||
// If either value is nil, the boolean is true and the integer is the comparison
|
||||
// value. The comparison is defined to be 0 if both are nil, otherwise the one
|
||||
// nil value compares low. Both arguments must represent a chan, func,
|
||||
// interface, map, pointer, or slice.
|
||||
func nilCompare(aVal, bVal reflect.Value) (int, bool) {
|
||||
if aVal.IsNil() {
|
||||
if bVal.IsNil() {
|
||||
return 0, true
|
||||
}
|
||||
return -1, true
|
||||
}
|
||||
if bVal.IsNil() {
|
||||
return 1, true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// floatCompare compares two floating-point values. NaNs compare low.
|
||||
func floatCompare(a, b float64) int {
|
||||
switch {
|
||||
case isNaN(a):
|
||||
return -1 // No good answer if b is a NaN so don't bother checking.
|
||||
case isNaN(b):
|
||||
return 1
|
||||
case a < b:
|
||||
return -1
|
||||
case a > b:
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func isNaN(a float64) bool {
|
||||
return a != a
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright 2021 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.
|
||||
|
||||
// Simple conversions to avoid depending on strconv.
|
||||
|
||||
// llgo:skipall
|
||||
package itoa
|
||||
|
||||
// Itoa converts val to a decimal string.
|
||||
func Itoa(val int) string {
|
||||
if val < 0 {
|
||||
return "-" + Uitoa(uint(-val))
|
||||
}
|
||||
return Uitoa(uint(val))
|
||||
}
|
||||
|
||||
// Uitoa converts val to a decimal string.
|
||||
func Uitoa(val uint) string {
|
||||
if val == 0 { // avoid string allocation
|
||||
return "0"
|
||||
}
|
||||
var buf [20]byte // big enough for 64bit value base 10
|
||||
i := len(buf) - 1
|
||||
for val >= 10 {
|
||||
q := val / 10
|
||||
buf[i] = byte('0' + val - q*10)
|
||||
i--
|
||||
val = q
|
||||
}
|
||||
// val < 10
|
||||
buf[i] = byte('0' + val)
|
||||
return string(buf[i:])
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright 2019 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 oserror defines errors values used in the os package.
|
||||
//
|
||||
// These types are defined here to permit the syscall package to reference them.
|
||||
package oserror
|
||||
|
||||
// llgo:skipall
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrInvalid = errors.New("invalid argument")
|
||||
ErrPermission = errors.New("permission denied")
|
||||
ErrExist = errors.New("file already exists")
|
||||
ErrNotExist = errors.New("file does not exist")
|
||||
ErrClosed = errors.New("file already closed")
|
||||
)
|
||||
@@ -1 +0,0 @@
|
||||
package race
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package reflectlite
|
||||
|
||||
// llgo:skipall
|
||||
import (
|
||||
_ "unsafe"
|
||||
)
|
||||
@@ -1,80 +0,0 @@
|
||||
// Copyright 2016 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 reflectlite
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
goarchPtrSize = unsafe.Sizeof(uintptr(0))
|
||||
)
|
||||
|
||||
// Swapper returns a function that swaps the elements in the provided
|
||||
// slice.
|
||||
//
|
||||
// Swapper panics if the provided interface is not a slice.
|
||||
func Swapper(slice any) func(i, j int) {
|
||||
v := ValueOf(slice)
|
||||
if v.Kind() != Slice {
|
||||
panic(&ValueError{Method: "Swapper", Kind: v.Kind()})
|
||||
}
|
||||
// Fast path for slices of size 0 and 1. Nothing to swap.
|
||||
switch v.Len() {
|
||||
case 0:
|
||||
return func(i, j int) { panic("reflect: slice index out of range") }
|
||||
case 1:
|
||||
return func(i, j int) {
|
||||
if i != 0 || j != 0 {
|
||||
panic("reflect: slice index out of range")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typ := v.Type().Elem().common()
|
||||
size := typ.Size()
|
||||
hasPtr := typ.PtrBytes != 0
|
||||
|
||||
// Some common & small cases, without using memmove:
|
||||
if hasPtr {
|
||||
if size == goarchPtrSize {
|
||||
ps := *(*[]unsafe.Pointer)(v.ptr)
|
||||
return func(i, j int) { ps[i], ps[j] = ps[j], ps[i] }
|
||||
}
|
||||
if typ.Kind() == String {
|
||||
ss := *(*[]string)(v.ptr)
|
||||
return func(i, j int) { ss[i], ss[j] = ss[j], ss[i] }
|
||||
}
|
||||
} else {
|
||||
switch size {
|
||||
case 8:
|
||||
is := *(*[]int64)(v.ptr)
|
||||
return func(i, j int) { is[i], is[j] = is[j], is[i] }
|
||||
case 4:
|
||||
is := *(*[]int32)(v.ptr)
|
||||
return func(i, j int) { is[i], is[j] = is[j], is[i] }
|
||||
case 2:
|
||||
is := *(*[]int16)(v.ptr)
|
||||
return func(i, j int) { is[i], is[j] = is[j], is[i] }
|
||||
case 1:
|
||||
is := *(*[]int8)(v.ptr)
|
||||
return func(i, j int) { is[i], is[j] = is[j], is[i] }
|
||||
}
|
||||
}
|
||||
|
||||
s := (*unsafeheaderSlice)(v.ptr)
|
||||
tmp := unsafe_New(typ) // swap scratch space
|
||||
|
||||
return func(i, j int) {
|
||||
if uint(i) >= uint(s.Len) || uint(j) >= uint(s.Len) {
|
||||
panic("reflect: slice index out of range")
|
||||
}
|
||||
val1 := arrayAt(s.Data, i, size, "i < s.Len")
|
||||
val2 := arrayAt(s.Data, j, size, "j < s.Len")
|
||||
typedmemmove(typ, tmp, val1)
|
||||
typedmemmove(typ, val1, val2)
|
||||
typedmemmove(typ, val2, tmp)
|
||||
}
|
||||
}
|
||||
@@ -1,565 +0,0 @@
|
||||
// Copyright 2009 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 reflectlite implements lightweight version of reflect, not using
|
||||
// any package except for "runtime", "unsafe", and "internal/abi"
|
||||
package reflectlite
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/compiler/internal/abi"
|
||||
)
|
||||
|
||||
// Type is the representation of a Go type.
|
||||
//
|
||||
// Not all methods apply to all kinds of types. Restrictions,
|
||||
// if any, are noted in the documentation for each method.
|
||||
// Use the Kind method to find out the kind of type before
|
||||
// calling kind-specific methods. Calling a method
|
||||
// inappropriate to the kind of type causes a run-time panic.
|
||||
//
|
||||
// Type values are comparable, such as with the == operator,
|
||||
// so they can be used as map keys.
|
||||
// Two Type values are equal if they represent identical types.
|
||||
type Type interface {
|
||||
// Methods applicable to all types.
|
||||
|
||||
// Name returns the type's name within its package for a defined type.
|
||||
// For other (non-defined) types it returns the empty string.
|
||||
Name() string
|
||||
|
||||
// PkgPath returns a defined type's package path, that is, the import path
|
||||
// that uniquely identifies the package, such as "encoding/base64".
|
||||
// If the type was predeclared (string, error) or not defined (*T, struct{},
|
||||
// []int, or A where A is an alias for a non-defined type), the package path
|
||||
// will be the empty string.
|
||||
PkgPath() string
|
||||
|
||||
// Size returns the number of bytes needed to store
|
||||
// a value of the given type; it is analogous to unsafe.Sizeof.
|
||||
Size() uintptr
|
||||
|
||||
// Kind returns the specific kind of this type.
|
||||
Kind() Kind
|
||||
|
||||
// Implements reports whether the type implements the interface type u.
|
||||
Implements(u Type) bool
|
||||
|
||||
// AssignableTo reports whether a value of the type is assignable to type u.
|
||||
AssignableTo(u Type) bool
|
||||
|
||||
// Comparable reports whether values of this type are comparable.
|
||||
Comparable() bool
|
||||
|
||||
// String returns a string representation of the type.
|
||||
// The string representation may use shortened package names
|
||||
// (e.g., base64 instead of "encoding/base64") and is not
|
||||
// guaranteed to be unique among types. To test for type identity,
|
||||
// compare the Types directly.
|
||||
String() string
|
||||
|
||||
// Elem returns a type's element type.
|
||||
// It panics if the type's Kind is not Ptr.
|
||||
Elem() Type
|
||||
|
||||
common() *abi.Type
|
||||
uncommon() *uncommonType
|
||||
}
|
||||
|
||||
/*
|
||||
* These data structures are known to the compiler (../../cmd/internal/reflectdata/reflect.go).
|
||||
* A few are known to ../runtime/type.go to convey to debuggers.
|
||||
* They are also known to ../runtime/type.go.
|
||||
*/
|
||||
|
||||
// A Kind represents the specific kind of type that a Type represents.
|
||||
// The zero Kind is not a valid kind.
|
||||
type Kind = abi.Kind
|
||||
|
||||
const Ptr = abi.Pointer
|
||||
|
||||
const (
|
||||
// Import-and-export these constants as necessary
|
||||
Interface = abi.Interface
|
||||
Slice = abi.Slice
|
||||
String = abi.String
|
||||
Struct = abi.Struct
|
||||
)
|
||||
|
||||
type rtype struct {
|
||||
*abi.Type
|
||||
}
|
||||
|
||||
// uncommonType is present only for defined types or types with methods
|
||||
// (if T is a defined type, the uncommonTypes for T and *T have methods).
|
||||
// Using a pointer to this struct reduces the overall size required
|
||||
// to describe a non-defined type with no methods.
|
||||
type uncommonType = abi.UncommonType
|
||||
|
||||
// arrayType represents a fixed array type.
|
||||
type arrayType = abi.ArrayType
|
||||
|
||||
// chanType represents a channel type.
|
||||
type chanType = abi.ChanType
|
||||
|
||||
type funcType = abi.FuncType
|
||||
|
||||
type interfaceType = abi.InterfaceType
|
||||
|
||||
// mapType represents a map type.
|
||||
type mapType struct {
|
||||
rtype
|
||||
Key *abi.Type // map key type
|
||||
Elem *abi.Type // map element (value) type
|
||||
Bucket *abi.Type // internal bucket structure
|
||||
// function for hashing keys (ptr to key, seed) -> hash
|
||||
Hasher func(unsafe.Pointer, uintptr) uintptr
|
||||
KeySize uint8 // size of key slot
|
||||
ValueSize uint8 // size of value slot
|
||||
BucketSize uint16 // size of bucket
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
// ptrType represents a pointer type.
|
||||
type ptrType = abi.PtrType
|
||||
|
||||
// sliceType represents a slice type.
|
||||
type sliceType = abi.SliceType
|
||||
|
||||
// structType represents a struct type.
|
||||
type structType = abi.StructType
|
||||
|
||||
func (t rtype) uncommon() *uncommonType {
|
||||
return t.Uncommon()
|
||||
}
|
||||
|
||||
func (t rtype) String() string {
|
||||
return t.Type.String()
|
||||
}
|
||||
|
||||
func (t rtype) common() *abi.Type { return t.Type }
|
||||
|
||||
func (t rtype) exportedMethods() []abi.Method {
|
||||
ut := t.uncommon()
|
||||
if ut == nil {
|
||||
return nil
|
||||
}
|
||||
return ut.ExportedMethods()
|
||||
}
|
||||
|
||||
func (t rtype) NumMethod() int {
|
||||
/*
|
||||
tt := t.Type.InterfaceType()
|
||||
if tt != nil {
|
||||
return tt.NumMethod()
|
||||
}
|
||||
return len(t.exportedMethods())
|
||||
*/
|
||||
panic("todo: reflectlite.rtype.NumMethod")
|
||||
}
|
||||
|
||||
func (t rtype) PkgPath() string {
|
||||
/*
|
||||
if t.TFlag&abi.TFlagNamed == 0 {
|
||||
return ""
|
||||
}
|
||||
ut := t.uncommon()
|
||||
if ut == nil {
|
||||
return ""
|
||||
}
|
||||
return t.nameOff(ut.PkgPath).Name()
|
||||
*/
|
||||
panic("todo: reflectlite.rtype.PkgPath")
|
||||
}
|
||||
|
||||
func (t rtype) Name() string {
|
||||
/*
|
||||
if !t.HasName() {
|
||||
return ""
|
||||
}
|
||||
s := t.String()
|
||||
i := len(s) - 1
|
||||
sqBrackets := 0
|
||||
for i >= 0 && (s[i] != '.' || sqBrackets != 0) {
|
||||
switch s[i] {
|
||||
case ']':
|
||||
sqBrackets++
|
||||
case '[':
|
||||
sqBrackets--
|
||||
}
|
||||
i--
|
||||
}
|
||||
return s[i+1:]
|
||||
*/
|
||||
panic("todo: reflectlite.rtype.Name")
|
||||
}
|
||||
|
||||
func toRType(t *abi.Type) rtype {
|
||||
return rtype{t}
|
||||
}
|
||||
|
||||
func elem(t *abi.Type) *abi.Type {
|
||||
et := t.Elem()
|
||||
if et != nil {
|
||||
return et
|
||||
}
|
||||
panic("reflect: Elem of invalid type " + toRType(t).String())
|
||||
}
|
||||
|
||||
func (t rtype) Elem() Type {
|
||||
return toType(elem(t.common()))
|
||||
}
|
||||
|
||||
func (t rtype) In(i int) Type {
|
||||
/*
|
||||
tt := t.Type.FuncType()
|
||||
if tt == nil {
|
||||
panic("reflect: In of non-func type")
|
||||
}
|
||||
return toType(tt.InSlice()[i])
|
||||
*/
|
||||
panic("todo: reflectlite.rtype.In")
|
||||
}
|
||||
|
||||
func (t rtype) Key() Type {
|
||||
tt := t.Type.MapType()
|
||||
if tt == nil {
|
||||
panic("reflect: Key of non-map type")
|
||||
}
|
||||
return toType(tt.Key)
|
||||
}
|
||||
|
||||
func (t rtype) Len() int {
|
||||
tt := t.Type.ArrayType()
|
||||
if tt == nil {
|
||||
panic("reflect: Len of non-array type")
|
||||
}
|
||||
return int(tt.Len)
|
||||
}
|
||||
|
||||
func (t rtype) NumField() int {
|
||||
tt := t.Type.StructType()
|
||||
if tt == nil {
|
||||
panic("reflect: NumField of non-struct type")
|
||||
}
|
||||
return len(tt.Fields)
|
||||
}
|
||||
|
||||
func (t rtype) NumIn() int {
|
||||
/*
|
||||
tt := t.Type.FuncType()
|
||||
if tt == nil {
|
||||
panic("reflect: NumIn of non-func type")
|
||||
}
|
||||
return int(tt.InCount)
|
||||
*/
|
||||
panic("todo: reflectlite.rtype.NumIn")
|
||||
}
|
||||
|
||||
func (t rtype) NumOut() int {
|
||||
/*
|
||||
tt := t.Type.FuncType()
|
||||
if tt == nil {
|
||||
panic("reflect: NumOut of non-func type")
|
||||
}
|
||||
return tt.NumOut()
|
||||
*/
|
||||
panic("todo: reflectlite.rtype.NumOut")
|
||||
}
|
||||
|
||||
func (t rtype) Out(i int) Type {
|
||||
/*
|
||||
tt := t.Type.FuncType()
|
||||
if tt == nil {
|
||||
panic("reflect: Out of non-func type")
|
||||
}
|
||||
return toType(tt.OutSlice()[i])
|
||||
*/
|
||||
panic("todo: reflectlite.rtype.Out")
|
||||
}
|
||||
|
||||
// add returns p+x.
|
||||
//
|
||||
// The whySafe string is ignored, so that the function still inlines
|
||||
// as efficiently as p+x, but all call sites should use the string to
|
||||
// record why the addition is safe, which is to say why the addition
|
||||
// does not cause x to advance to the very end of p's allocation
|
||||
// and therefore point incorrectly at the next block in memory.
|
||||
func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer {
|
||||
return unsafe.Pointer(uintptr(p) + x)
|
||||
}
|
||||
|
||||
// TypeOf returns the reflection Type that represents the dynamic type of i.
|
||||
// If i is a nil interface value, TypeOf returns nil.
|
||||
func TypeOf(i any) Type {
|
||||
eface := *(*emptyInterface)(unsafe.Pointer(&i))
|
||||
return toType(eface.typ)
|
||||
}
|
||||
|
||||
func (t rtype) Implements(u Type) bool {
|
||||
if u == nil {
|
||||
panic("reflect: nil type passed to Type.Implements")
|
||||
}
|
||||
if u.Kind() != Interface {
|
||||
panic("reflect: non-interface type passed to Type.Implements")
|
||||
}
|
||||
return implements(u.common(), t.common())
|
||||
}
|
||||
|
||||
func (t rtype) AssignableTo(u Type) bool {
|
||||
if u == nil {
|
||||
panic("reflect: nil type passed to Type.AssignableTo")
|
||||
}
|
||||
uu := u.common()
|
||||
tt := t.common()
|
||||
return directlyAssignable(uu, tt) || implements(uu, tt)
|
||||
}
|
||||
|
||||
func (t rtype) Comparable() bool {
|
||||
return t.Equal != nil
|
||||
}
|
||||
|
||||
// implements reports whether the type V implements the interface type T.
|
||||
func implements(T, V *abi.Type) bool {
|
||||
/*
|
||||
t := T.InterfaceType()
|
||||
if t == nil {
|
||||
return false
|
||||
}
|
||||
if len(t.Methods) == 0 {
|
||||
return true
|
||||
}
|
||||
rT := toRType(T)
|
||||
rV := toRType(V)
|
||||
|
||||
// The same algorithm applies in both cases, but the
|
||||
// method tables for an interface type and a concrete type
|
||||
// are different, so the code is duplicated.
|
||||
// In both cases the algorithm is a linear scan over the two
|
||||
// lists - T's methods and V's methods - simultaneously.
|
||||
// Since method tables are stored in a unique sorted order
|
||||
// (alphabetical, with no duplicate method names), the scan
|
||||
// through V's methods must hit a match for each of T's
|
||||
// methods along the way, or else V does not implement T.
|
||||
// This lets us run the scan in overall linear time instead of
|
||||
// the quadratic time a naive search would require.
|
||||
// See also ../runtime/iface.go.
|
||||
if V.Kind() == Interface {
|
||||
v := (*interfaceType)(unsafe.Pointer(V))
|
||||
i := 0
|
||||
for j := 0; j < len(v.Methods); j++ {
|
||||
tm := &t.Methods[i]
|
||||
tmName := rT.nameOff(tm.Name)
|
||||
vm := &v.Methods[j]
|
||||
vmName := rV.nameOff(vm.Name)
|
||||
if vmName.Name() == tmName.Name() && rV.typeOff(vm.Typ) == rT.typeOff(tm.Typ) {
|
||||
if !tmName.IsExported() {
|
||||
tmPkgPath := pkgPath(tmName)
|
||||
if tmPkgPath == "" {
|
||||
tmPkgPath = t.PkgPath.Name()
|
||||
}
|
||||
vmPkgPath := pkgPath(vmName)
|
||||
if vmPkgPath == "" {
|
||||
vmPkgPath = v.PkgPath.Name()
|
||||
}
|
||||
if tmPkgPath != vmPkgPath {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if i++; i >= len(t.Methods) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
v := V.Uncommon()
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
i := 0
|
||||
vmethods := v.Methods()
|
||||
for j := 0; j < int(v.Mcount); j++ {
|
||||
tm := &t.Methods[i]
|
||||
tmName := rT.nameOff(tm.Name)
|
||||
vm := vmethods[j]
|
||||
vmName := rV.nameOff(vm.Name)
|
||||
if vmName.Name() == tmName.Name() && rV.typeOff(vm.Mtyp) == rT.typeOff(tm.Typ) {
|
||||
if !tmName.IsExported() {
|
||||
tmPkgPath := pkgPath(tmName)
|
||||
if tmPkgPath == "" {
|
||||
tmPkgPath = t.PkgPath.Name()
|
||||
}
|
||||
vmPkgPath := pkgPath(vmName)
|
||||
if vmPkgPath == "" {
|
||||
vmPkgPath = rV.nameOff(v.PkgPath).Name()
|
||||
}
|
||||
if tmPkgPath != vmPkgPath {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if i++; i >= len(t.Methods) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
*/
|
||||
panic("todo: reflectlite.implements")
|
||||
}
|
||||
|
||||
// directlyAssignable reports whether a value x of type V can be directly
|
||||
// assigned (using memmove) to a value of type T.
|
||||
// https://golang.org/doc/go_spec.html#Assignability
|
||||
// Ignoring the interface rules (implemented elsewhere)
|
||||
// and the ideal constant rules (no ideal constants at run time).
|
||||
func directlyAssignable(T, V *abi.Type) bool {
|
||||
// x's type V is identical to T?
|
||||
if T == V {
|
||||
return true
|
||||
}
|
||||
|
||||
// Otherwise at least one of T and V must not be defined
|
||||
// and they must have the same kind.
|
||||
if T.HasName() && V.HasName() || T.Kind() != V.Kind() {
|
||||
return false
|
||||
}
|
||||
|
||||
// x's type T and V must have identical underlying types.
|
||||
return haveIdenticalUnderlyingType(T, V, true)
|
||||
}
|
||||
|
||||
func haveIdenticalType(T, V *abi.Type, cmpTags bool) bool {
|
||||
if cmpTags {
|
||||
return T == V
|
||||
}
|
||||
|
||||
if toRType(T).Name() != toRType(V).Name() || T.Kind() != V.Kind() {
|
||||
return false
|
||||
}
|
||||
|
||||
return haveIdenticalUnderlyingType(T, V, false)
|
||||
}
|
||||
|
||||
func haveIdenticalUnderlyingType(T, V *abi.Type, cmpTags bool) bool {
|
||||
if T == V {
|
||||
return true
|
||||
}
|
||||
|
||||
kind := T.Kind()
|
||||
if kind != V.Kind() {
|
||||
return false
|
||||
}
|
||||
|
||||
// Non-composite types of equal kind have same underlying type
|
||||
// (the predefined instance of the type).
|
||||
if abi.Bool <= kind && kind <= abi.Complex128 || kind == abi.String || kind == abi.UnsafePointer {
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
// Composite types.
|
||||
switch kind {
|
||||
case abi.Array:
|
||||
return T.Len() == V.Len() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
|
||||
|
||||
case abi.Chan:
|
||||
// Special case:
|
||||
// x is a bidirectional channel value, T is a channel type,
|
||||
// and x's type V and T have identical element types.
|
||||
if V.ChanDir() == abi.BothDir && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Otherwise continue test for identical underlying type.
|
||||
return V.ChanDir() == T.ChanDir() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
|
||||
|
||||
case abi.Func:
|
||||
t := (*funcType)(unsafe.Pointer(T))
|
||||
v := (*funcType)(unsafe.Pointer(V))
|
||||
if t.OutCount != v.OutCount || t.InCount != v.InCount {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < t.NumIn(); i++ {
|
||||
if !haveIdenticalType(t.In(i), v.In(i), cmpTags) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i := 0; i < t.NumOut(); i++ {
|
||||
if !haveIdenticalType(t.Out(i), v.Out(i), cmpTags) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
case Interface:
|
||||
t := (*interfaceType)(unsafe.Pointer(T))
|
||||
v := (*interfaceType)(unsafe.Pointer(V))
|
||||
if len(t.Methods) == 0 && len(v.Methods) == 0 {
|
||||
return true
|
||||
}
|
||||
// Might have the same methods but still
|
||||
// need a run time conversion.
|
||||
return false
|
||||
|
||||
case abi.Map:
|
||||
return haveIdenticalType(T.Key(), V.Key(), cmpTags) && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
|
||||
|
||||
case Ptr, abi.Slice:
|
||||
return haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
|
||||
|
||||
case abi.Struct:
|
||||
t := (*structType)(unsafe.Pointer(T))
|
||||
v := (*structType)(unsafe.Pointer(V))
|
||||
if len(t.Fields) != len(v.Fields) {
|
||||
return false
|
||||
}
|
||||
if t.PkgPath.Name() != v.PkgPath.Name() {
|
||||
return false
|
||||
}
|
||||
for i := range t.Fields {
|
||||
tf := &t.Fields[i]
|
||||
vf := &v.Fields[i]
|
||||
if tf.Name.Name() != vf.Name.Name() {
|
||||
return false
|
||||
}
|
||||
if !haveIdenticalType(tf.Typ, vf.Typ, cmpTags) {
|
||||
return false
|
||||
}
|
||||
if cmpTags && tf.Name.Tag() != vf.Name.Tag() {
|
||||
return false
|
||||
}
|
||||
if tf.Offset != vf.Offset {
|
||||
return false
|
||||
}
|
||||
if tf.Embedded() != vf.Embedded() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
*/
|
||||
panic("todo: reflectlite.haveIdenticalUnderlyingType")
|
||||
}
|
||||
|
||||
// toType converts from a *rtype to a Type that can be returned
|
||||
// to the client of package reflect. In gc, the only concern is that
|
||||
// a nil *rtype must be replaced by a nil Type, but in gccgo this
|
||||
// function takes care of ensuring that multiple *rtype for the same
|
||||
// type are coalesced into a single Type.
|
||||
func toType(t *abi.Type) Type {
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
return toRType(t)
|
||||
}
|
||||
|
||||
// ifaceIndir reports whether t is stored indirectly in an interface value.
|
||||
func ifaceIndir(t *abi.Type) bool {
|
||||
return t.Kind_&abi.KindDirectIface == 0
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
// Copyright 2020 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 reflectlite
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// unsafeheaderSlice is the runtime representation of a slice.
|
||||
// It cannot be used safely or portably and its representation may
|
||||
// change in a later release.
|
||||
//
|
||||
// Unlike reflect.SliceHeader, its Data field is sufficient to guarantee the
|
||||
// data it references will not be garbage collected.
|
||||
type unsafeheaderSlice struct {
|
||||
Data unsafe.Pointer
|
||||
Len int
|
||||
Cap int
|
||||
}
|
||||
|
||||
// unsafeheaderString is the runtime representation of a string.
|
||||
// It cannot be used safely or portably and its representation may
|
||||
// change in a later release.
|
||||
//
|
||||
// Unlike reflect.StringHeader, its Data field is sufficient to guarantee the
|
||||
// data it references will not be garbage collected.
|
||||
type unsafeheaderString struct {
|
||||
Data unsafe.Pointer
|
||||
Len int
|
||||
}
|
||||
@@ -1,477 +0,0 @@
|
||||
// Copyright 2009 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 reflectlite
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/compiler/internal/abi"
|
||||
_ "github.com/goplus/llgo/compiler/internal/runtime"
|
||||
)
|
||||
|
||||
// Value is the reflection interface to a Go value.
|
||||
//
|
||||
// Not all methods apply to all kinds of values. Restrictions,
|
||||
// if any, are noted in the documentation for each method.
|
||||
// Use the Kind method to find out the kind of value before
|
||||
// calling kind-specific methods. Calling a method
|
||||
// inappropriate to the kind of type causes a run time panic.
|
||||
//
|
||||
// The zero Value represents no value.
|
||||
// Its IsValid method returns false, its Kind method returns Invalid,
|
||||
// its String method returns "<invalid Value>", and all other methods panic.
|
||||
// Most functions and methods never return an invalid value.
|
||||
// If one does, its documentation states the conditions explicitly.
|
||||
//
|
||||
// A Value can be used concurrently by multiple goroutines provided that
|
||||
// the underlying Go value can be used concurrently for the equivalent
|
||||
// direct operations.
|
||||
//
|
||||
// To compare two Values, compare the results of the Interface method.
|
||||
// Using == on two Values does not compare the underlying values
|
||||
// they represent.
|
||||
type Value struct {
|
||||
// typ holds the type of the value represented by a Value.
|
||||
typ *abi.Type
|
||||
|
||||
// Pointer-valued data or, if flagIndir is set, pointer to data.
|
||||
// Valid when either flagIndir is set or typ.pointers() is true.
|
||||
ptr unsafe.Pointer
|
||||
|
||||
// flag holds metadata about the value.
|
||||
// The lowest bits are flag bits:
|
||||
// - flagStickyRO: obtained via unexported not embedded field, so read-only
|
||||
// - flagEmbedRO: obtained via unexported embedded field, so read-only
|
||||
// - flagIndir: val holds a pointer to the data
|
||||
// - flagAddr: v.CanAddr is true (implies flagIndir)
|
||||
// Value cannot represent method values.
|
||||
// The next five bits give the Kind of the value.
|
||||
// This repeats typ.Kind() except for method values.
|
||||
// The remaining 23+ bits give a method number for method values.
|
||||
// If flag.kind() != Func, code can assume that flagMethod is unset.
|
||||
// If ifaceIndir(typ), code can assume that flagIndir is set.
|
||||
flag
|
||||
|
||||
// A method value represents a curried method invocation
|
||||
// like r.Read for some receiver r. The typ+val+flag bits describe
|
||||
// the receiver r, but the flag's Kind bits say Func (methods are
|
||||
// functions), and the top bits of the flag give the method number
|
||||
// in r's type's method table.
|
||||
}
|
||||
|
||||
type flag uintptr
|
||||
|
||||
const (
|
||||
flagKindWidth = 5 // there are 27 kinds
|
||||
flagKindMask flag = 1<<flagKindWidth - 1
|
||||
flagStickyRO flag = 1 << 5
|
||||
flagEmbedRO flag = 1 << 6
|
||||
flagIndir flag = 1 << 7
|
||||
flagAddr flag = 1 << 8
|
||||
flagMethod flag = 1 << 9
|
||||
flagMethodShift = 10
|
||||
flagRO flag = flagStickyRO | flagEmbedRO
|
||||
)
|
||||
|
||||
func (f flag) kind() Kind {
|
||||
return Kind(f & flagKindMask)
|
||||
}
|
||||
|
||||
func (f flag) ro() flag {
|
||||
if f&flagRO != 0 {
|
||||
return flagStickyRO
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// pointer returns the underlying pointer represented by v.
|
||||
// v.Kind() must be Pointer, Map, Chan, Func, or UnsafePointer
|
||||
func (v Value) pointer() unsafe.Pointer {
|
||||
/*
|
||||
if v.typ.Size() != goarch.PtrSize || !v.typ.Pointers() {
|
||||
panic("can't call pointer on a non-pointer Value")
|
||||
}
|
||||
if v.flag&flagIndir != 0 {
|
||||
return *(*unsafe.Pointer)(v.ptr)
|
||||
}
|
||||
return v.ptr
|
||||
*/
|
||||
panic("todo: reflectlite.Value.pointer")
|
||||
}
|
||||
|
||||
// packEface converts v to the empty interface.
|
||||
func packEface(v Value) any {
|
||||
t := v.typ
|
||||
var i any
|
||||
e := (*emptyInterface)(unsafe.Pointer(&i))
|
||||
// First, fill in the data portion of the interface.
|
||||
switch {
|
||||
case ifaceIndir(t):
|
||||
if v.flag&flagIndir == 0 {
|
||||
panic("bad indir")
|
||||
}
|
||||
// Value is indirect, and so is the interface we're making.
|
||||
ptr := v.ptr
|
||||
if v.flag&flagAddr != 0 {
|
||||
// TODO: pass safe boolean from valueInterface so
|
||||
// we don't need to copy if safe==true?
|
||||
c := unsafe_New(t)
|
||||
typedmemmove(t, c, ptr)
|
||||
ptr = c
|
||||
}
|
||||
e.word = ptr
|
||||
case v.flag&flagIndir != 0:
|
||||
// Value is indirect, but interface is direct. We need
|
||||
// to load the data at v.ptr into the interface data word.
|
||||
e.word = *(*unsafe.Pointer)(v.ptr)
|
||||
default:
|
||||
// Value is direct, and so is the interface.
|
||||
e.word = v.ptr
|
||||
}
|
||||
// Now, fill in the type portion. We're very careful here not
|
||||
// to have any operation between the e.word and e.typ assignments
|
||||
// that would let the garbage collector observe the partially-built
|
||||
// interface value.
|
||||
e.typ = t
|
||||
return i
|
||||
}
|
||||
|
||||
// unpackEface converts the empty interface i to a Value.
|
||||
func unpackEface(i any) Value {
|
||||
e := (*emptyInterface)(unsafe.Pointer(&i))
|
||||
// NOTE: don't read e.word until we know whether it is really a pointer or not.
|
||||
t := e.typ
|
||||
if t == nil {
|
||||
return Value{}
|
||||
}
|
||||
f := flag(t.Kind())
|
||||
if ifaceIndir(t) {
|
||||
f |= flagIndir
|
||||
}
|
||||
return Value{t, e.word, f}
|
||||
}
|
||||
|
||||
// A ValueError occurs when a Value method is invoked on
|
||||
// a Value that does not support it. Such cases are documented
|
||||
// in the description of each method.
|
||||
type ValueError struct {
|
||||
Method string
|
||||
Kind Kind
|
||||
}
|
||||
|
||||
func (e *ValueError) Error() string {
|
||||
if e.Kind == 0 {
|
||||
return "reflect: call of " + e.Method + " on zero Value"
|
||||
}
|
||||
return "reflect: call of " + e.Method + " on " + e.Kind.String() + " Value"
|
||||
}
|
||||
|
||||
// methodName returns the name of the calling method,
|
||||
// assumed to be two stack frames above.
|
||||
func methodName() string {
|
||||
/* TODO(xsw):
|
||||
pc, _, _, _ := runtime.Caller(2)
|
||||
f := runtime.FuncForPC(pc)
|
||||
if f == nil {
|
||||
return "unknown method"
|
||||
}
|
||||
return f.Name()
|
||||
*/
|
||||
return "unknown method"
|
||||
}
|
||||
|
||||
// emptyInterface is the header for an interface{} value.
|
||||
type emptyInterface struct {
|
||||
typ *abi.Type
|
||||
word unsafe.Pointer
|
||||
}
|
||||
|
||||
// mustBeExported panics if f records that the value was obtained using
|
||||
// an unexported field.
|
||||
func (f flag) mustBeExported() {
|
||||
if f == 0 {
|
||||
panic(&ValueError{methodName(), 0})
|
||||
}
|
||||
if f&flagRO != 0 {
|
||||
panic("reflect: " + methodName() + " using value obtained using unexported field")
|
||||
}
|
||||
}
|
||||
|
||||
// mustBeAssignable panics if f records that the value is not assignable,
|
||||
// which is to say that either it was obtained using an unexported field
|
||||
// or it is not addressable.
|
||||
func (f flag) mustBeAssignable() {
|
||||
if f == 0 {
|
||||
panic(&ValueError{methodName(), abi.Invalid})
|
||||
}
|
||||
// Assignable if addressable and not read-only.
|
||||
if f&flagRO != 0 {
|
||||
panic("reflect: " + methodName() + " using value obtained using unexported field")
|
||||
}
|
||||
if f&flagAddr == 0 {
|
||||
panic("reflect: " + methodName() + " using unaddressable value")
|
||||
}
|
||||
}
|
||||
|
||||
// CanSet reports whether the value of v can be changed.
|
||||
// A Value can be changed only if it is addressable and was not
|
||||
// obtained by the use of unexported struct fields.
|
||||
// If CanSet returns false, calling Set or any type-specific
|
||||
// setter (e.g., SetBool, SetInt) will panic.
|
||||
func (v Value) CanSet() bool {
|
||||
return v.flag&(flagAddr|flagRO) == flagAddr
|
||||
}
|
||||
|
||||
// Elem returns the value that the interface v contains
|
||||
// or that the pointer v points to.
|
||||
// It panics if v's Kind is not Interface or Pointer.
|
||||
// It returns the zero Value if v is nil.
|
||||
func (v Value) Elem() Value {
|
||||
/*
|
||||
k := v.kind()
|
||||
switch k {
|
||||
case abi.Interface:
|
||||
var eface any
|
||||
if v.typ.NumMethod() == 0 {
|
||||
eface = *(*any)(v.ptr)
|
||||
} else {
|
||||
eface = (any)(*(*interface {
|
||||
M()
|
||||
})(v.ptr))
|
||||
}
|
||||
x := unpackEface(eface)
|
||||
if x.flag != 0 {
|
||||
x.flag |= v.flag.ro()
|
||||
}
|
||||
return x
|
||||
case abi.Pointer:
|
||||
ptr := v.ptr
|
||||
if v.flag&flagIndir != 0 {
|
||||
ptr = *(*unsafe.Pointer)(ptr)
|
||||
}
|
||||
// The returned value's address is v's value.
|
||||
if ptr == nil {
|
||||
return Value{}
|
||||
}
|
||||
tt := (*ptrType)(unsafe.Pointer(v.typ))
|
||||
typ := tt.Elem
|
||||
fl := v.flag&flagRO | flagIndir | flagAddr
|
||||
fl |= flag(typ.Kind())
|
||||
return Value{typ, ptr, fl}
|
||||
}
|
||||
panic(&ValueError{"reflectlite.Value.Elem", v.kind()})
|
||||
*/
|
||||
panic("todo: reflectlite.Value.Elem")
|
||||
}
|
||||
|
||||
func valueInterface(v Value) any {
|
||||
if v.flag == 0 {
|
||||
panic(&ValueError{"reflectlite.Value.Interface", 0})
|
||||
}
|
||||
|
||||
if v.kind() == abi.Interface {
|
||||
// Special case: return the element inside the interface.
|
||||
// Empty interface has one layout, all interfaces with
|
||||
// methods have a second layout.
|
||||
if v.numMethod() == 0 {
|
||||
return *(*any)(v.ptr)
|
||||
}
|
||||
return *(*interface {
|
||||
M()
|
||||
})(v.ptr)
|
||||
}
|
||||
|
||||
// TODO: pass safe to packEface so we don't need to copy if safe==true?
|
||||
return packEface(v)
|
||||
}
|
||||
|
||||
// IsNil reports whether its argument v is nil. The argument must be
|
||||
// a chan, func, interface, map, pointer, or slice value; if it is
|
||||
// not, IsNil panics. Note that IsNil is not always equivalent to a
|
||||
// regular comparison with nil in Go. For example, if v was created
|
||||
// by calling ValueOf with an uninitialized interface variable i,
|
||||
// i==nil will be true but v.IsNil will panic as v will be the zero
|
||||
// Value.
|
||||
func (v Value) IsNil() bool {
|
||||
k := v.kind()
|
||||
switch k {
|
||||
case abi.Chan, abi.Func, abi.Map, abi.Pointer, abi.UnsafePointer:
|
||||
// if v.flag&flagMethod != 0 {
|
||||
// return false
|
||||
// }
|
||||
ptr := v.ptr
|
||||
if v.flag&flagIndir != 0 {
|
||||
ptr = *(*unsafe.Pointer)(ptr)
|
||||
}
|
||||
return ptr == nil
|
||||
case abi.Interface, abi.Slice:
|
||||
// Both interface and slice are nil if first word is 0.
|
||||
// Both are always bigger than a word; assume flagIndir.
|
||||
return *(*unsafe.Pointer)(v.ptr) == nil
|
||||
}
|
||||
panic(&ValueError{"reflectlite.Value.IsNil", v.kind()})
|
||||
}
|
||||
|
||||
// IsValid reports whether v represents a value.
|
||||
// It returns false if v is the zero Value.
|
||||
// If IsValid returns false, all other methods except String panic.
|
||||
// Most functions and methods never return an invalid Value.
|
||||
// If one does, its documentation states the conditions explicitly.
|
||||
func (v Value) IsValid() bool {
|
||||
return v.flag != 0
|
||||
}
|
||||
|
||||
// Kind returns v's Kind.
|
||||
// If v is the zero Value (IsValid returns false), Kind returns Invalid.
|
||||
func (v Value) Kind() Kind {
|
||||
return v.kind()
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
// implemented in runtime:
|
||||
func chanlen(unsafe.Pointer) int
|
||||
func maplen(unsafe.Pointer) int
|
||||
*/
|
||||
|
||||
// Len returns v's length.
|
||||
// It panics if v's Kind is not Array, Chan, Map, Slice, or String.
|
||||
func (v Value) Len() int {
|
||||
k := v.kind()
|
||||
switch k {
|
||||
case abi.Slice:
|
||||
// Slice is bigger than a word; assume flagIndir.
|
||||
return (*unsafeheaderSlice)(v.ptr).Len
|
||||
case abi.String:
|
||||
// String is bigger than a word; assume flagIndir.
|
||||
return (*unsafeheaderString)(v.ptr).Len
|
||||
case abi.Array:
|
||||
tt := (*arrayType)(unsafe.Pointer(v.typ))
|
||||
return int(tt.Len)
|
||||
/* TODO(xsw):
|
||||
case abi.Chan:
|
||||
return chanlen(v.pointer())
|
||||
case abi.Map:
|
||||
return maplen(v.pointer())
|
||||
*/
|
||||
}
|
||||
panic(&ValueError{"reflect.Value.Len", v.kind()})
|
||||
}
|
||||
|
||||
// NumMethod returns the number of exported methods in the value's method set.
|
||||
func (v Value) numMethod() int {
|
||||
/*
|
||||
if v.typ == nil {
|
||||
panic(&ValueError{"reflectlite.Value.NumMethod", abi.Invalid})
|
||||
}
|
||||
return v.typ.NumMethod()
|
||||
*/
|
||||
panic("todo: reflectlite.Value.numMethod")
|
||||
}
|
||||
|
||||
// Set assigns x to the value v.
|
||||
// It panics if CanSet returns false.
|
||||
// As in Go, x's value must be assignable to v's type.
|
||||
func (v Value) Set(x Value) {
|
||||
v.mustBeAssignable()
|
||||
x.mustBeExported() // do not let unexported x leak
|
||||
var target unsafe.Pointer
|
||||
if v.kind() == abi.Interface {
|
||||
target = v.ptr
|
||||
}
|
||||
x = x.assignTo("reflectlite.Set", v.typ, target)
|
||||
if x.flag&flagIndir != 0 {
|
||||
typedmemmove(v.typ, v.ptr, x.ptr)
|
||||
} else {
|
||||
*(*unsafe.Pointer)(v.ptr) = x.ptr
|
||||
}
|
||||
}
|
||||
|
||||
// Type returns v's type.
|
||||
func (v Value) Type() Type {
|
||||
f := v.flag
|
||||
if f == 0 {
|
||||
panic(&ValueError{"reflectlite.Value.Type", abi.Invalid})
|
||||
}
|
||||
// Method values not supported.
|
||||
return toRType(v.typ)
|
||||
}
|
||||
|
||||
/*
|
||||
* constructors
|
||||
*/
|
||||
|
||||
//go:linkname unsafe_New github.com/goplus/llgo/compiler/internal/runtime.New
|
||||
func unsafe_New(*abi.Type) unsafe.Pointer
|
||||
|
||||
// ValueOf returns a new Value initialized to the concrete value
|
||||
// stored in the interface i. ValueOf(nil) returns the zero Value.
|
||||
func ValueOf(i any) Value {
|
||||
if i == nil {
|
||||
return Value{}
|
||||
}
|
||||
|
||||
return unpackEface(i)
|
||||
}
|
||||
|
||||
// assignTo returns a value v that can be assigned directly to typ.
|
||||
// It panics if v is not assignable to typ.
|
||||
// For a conversion to an interface type, target is a suggested scratch space to use.
|
||||
func (v Value) assignTo(context string, dst *abi.Type, target unsafe.Pointer) Value {
|
||||
// if v.flag&flagMethod != 0 {
|
||||
// v = makeMethodValue(context, v)
|
||||
// }
|
||||
|
||||
switch {
|
||||
case directlyAssignable(dst, v.typ):
|
||||
// Overwrite type so that they match.
|
||||
// Same memory layout, so no harm done.
|
||||
fl := v.flag&(flagAddr|flagIndir) | v.flag.ro()
|
||||
fl |= flag(dst.Kind())
|
||||
return Value{dst, v.ptr, fl}
|
||||
|
||||
case implements(dst, v.typ):
|
||||
if target == nil {
|
||||
target = unsafe_New(dst)
|
||||
}
|
||||
if v.Kind() == abi.Interface && v.IsNil() {
|
||||
// A nil ReadWriter passed to nil Reader is OK,
|
||||
// but using ifaceE2I below will panic.
|
||||
// Avoid the panic by returning a nil dst (e.g., Reader) explicitly.
|
||||
return Value{dst, nil, flag(abi.Interface)}
|
||||
}
|
||||
/* TODO(xsw):
|
||||
x := valueInterface(v)
|
||||
if dst.NumMethod() == 0 {
|
||||
*(*any)(target) = x
|
||||
} else {
|
||||
ifaceE2I(dst, x, target)
|
||||
}
|
||||
return Value{dst, target, flagIndir | flag(abi.Interface)}
|
||||
*/
|
||||
}
|
||||
|
||||
// Failed.
|
||||
// TODO(xsw):
|
||||
// panic(context + ": value of type " + toRType(v.typ).String() + " is not assignable to type " + toRType(dst).String())
|
||||
panic("todo: reflectlite.Value.assignTo")
|
||||
}
|
||||
|
||||
// arrayAt returns the i-th element of p,
|
||||
// an array whose elements are eltSize bytes wide.
|
||||
// The array pointed at by p must have at least i+1 elements:
|
||||
// it is invalid (but impossible to check here) to pass i >= len,
|
||||
// because then the result will point outside the array.
|
||||
// whySafe must explain why i < len. (Passing "i < len" is fine;
|
||||
// the benefit is to surface this assumption at the call site.)
|
||||
func arrayAt(p unsafe.Pointer, i int, eltSize uintptr, whySafe string) unsafe.Pointer {
|
||||
return add(p, uintptr(i)*eltSize, "i < len")
|
||||
}
|
||||
|
||||
// func ifaceE2I(t *abi.Type, src any, dst unsafe.Pointer)
|
||||
|
||||
// typedmemmove copies a value of type t to dst from src.
|
||||
//
|
||||
//go:linkname typedmemmove github.com/goplus/llgo/compiler/internal/runtime.Typedmemmove
|
||||
func typedmemmove(t *abi.Type, dst, src unsafe.Pointer)
|
||||
@@ -1 +0,0 @@
|
||||
package stringslite
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
//go:build !windows
|
||||
|
||||
package execenv
|
||||
|
||||
// llgo:skipall
|
||||
import "syscall"
|
||||
|
||||
// Default will return the default environment
|
||||
// variables based on the process attributes
|
||||
// provided.
|
||||
//
|
||||
// Defaults to syscall.Environ() on all platforms
|
||||
// other than Windows.
|
||||
func Default(sys *syscall.SysProcAttr) ([]string, error) {
|
||||
return syscall.Environ(), nil
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
//go:build windows
|
||||
|
||||
package execenv
|
||||
|
||||
// llgo:skipall
|
||||
import (
|
||||
"internal/syscall/windows"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Default will return the default environment
|
||||
// variables based on the process attributes
|
||||
// provided.
|
||||
//
|
||||
// If the process attributes contain a token, then
|
||||
// the environment variables will be sourced from
|
||||
// the defaults for that user token, otherwise they
|
||||
// will be sourced from syscall.Environ().
|
||||
func Default(sys *syscall.SysProcAttr) (env []string, err error) {
|
||||
if sys == nil || sys.Token == 0 {
|
||||
return syscall.Environ(), nil
|
||||
}
|
||||
var blockp *uint16
|
||||
err = windows.CreateEnvironmentBlock(&blockp, sys.Token, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer windows.DestroyEnvironmentBlock(blockp)
|
||||
|
||||
const size = unsafe.Sizeof(*blockp)
|
||||
for *blockp != 0 { // environment block ends with empty string
|
||||
// find NUL terminator
|
||||
end := unsafe.Add(unsafe.Pointer(blockp), size)
|
||||
for *(*uint16)(end) != 0 {
|
||||
end = unsafe.Add(end, size)
|
||||
}
|
||||
|
||||
entry := unsafe.Slice(blockp, (uintptr(end)-uintptr(unsafe.Pointer(blockp)))/2)
|
||||
env = append(env, syscall.UTF16ToString(entry))
|
||||
blockp = (*uint16)(unsafe.Add(end, size))
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
//go:build js && wasm
|
||||
|
||||
package unix
|
||||
|
||||
func IsNonblock(fd int) (nonblocking bool, err error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func HasNonblockFlag(flag int) bool {
|
||||
return false
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
//go:build unix
|
||||
|
||||
package unix
|
||||
|
||||
import "github.com/goplus/llgo/c/syscall"
|
||||
|
||||
/* TODO(xsw):
|
||||
func IsNonblock(fd int) (nonblocking bool, err error) {
|
||||
flag, e1 := Fcntl(fd, syscall.F_GETFL, 0)
|
||||
if e1 != nil {
|
||||
return false, e1
|
||||
}
|
||||
return flag&syscall.O_NONBLOCK != 0, nil
|
||||
}
|
||||
*/
|
||||
|
||||
func HasNonblockFlag(flag int) bool {
|
||||
return flag&syscall.O_NONBLOCK != 0
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
// 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.
|
||||
|
||||
//go:build wasip1
|
||||
|
||||
package unix
|
||||
|
||||
import "github.com/goplus/llgo/c/syscall"
|
||||
|
||||
/* TODO(xsw):
|
||||
import (
|
||||
"syscall"
|
||||
_ "unsafe" // for go:linkname
|
||||
)
|
||||
|
||||
func IsNonblock(fd int) (nonblocking bool, err error) {
|
||||
flags, e1 := fd_fdstat_get_flags(fd)
|
||||
if e1 != nil {
|
||||
return false, e1
|
||||
}
|
||||
return flags&syscall.FDFLAG_NONBLOCK != 0, nil
|
||||
}
|
||||
*/
|
||||
|
||||
func HasNonblockFlag(flag int) bool {
|
||||
return flag&syscall.FDFLAG_NONBLOCK != 0
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
// This helper is implemented in the syscall package. It means we don't have
|
||||
// to redefine the fd_fdstat_get host import or the fdstat struct it
|
||||
// populates.
|
||||
//
|
||||
//-go:linkname fd_fdstat_get_flags syscall.fd_fdstat_get_flags
|
||||
func fd_fdstat_get_flags(fd int) (uint32, error)
|
||||
*/
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package unix
|
||||
|
||||
// llgo:skipall
|
||||
import (
|
||||
_ "unsafe"
|
||||
)
|
||||
@@ -1,207 +0,0 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// Pipe adapter to connect code expecting an io.Reader
|
||||
// with code expecting an io.Writer.
|
||||
|
||||
package io
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// onceError is an object that will only store an error once.
|
||||
type onceError struct {
|
||||
sync.Mutex // guards following
|
||||
err error
|
||||
}
|
||||
|
||||
func (a *onceError) Store(err error) {
|
||||
a.Lock()
|
||||
defer a.Unlock()
|
||||
if a.err != nil {
|
||||
return
|
||||
}
|
||||
a.err = err
|
||||
}
|
||||
func (a *onceError) Load() error {
|
||||
a.Lock()
|
||||
defer a.Unlock()
|
||||
return a.err
|
||||
}
|
||||
|
||||
// ErrClosedPipe is the error used for read or write operations on a closed pipe.
|
||||
var ErrClosedPipe = errors.New("io: read/write on closed pipe")
|
||||
|
||||
// A pipe is the shared pipe structure underlying PipeReader and PipeWriter.
|
||||
type pipe struct {
|
||||
wrMu sync.Mutex // Serializes Write operations
|
||||
wrCh chan []byte
|
||||
rdCh chan int
|
||||
|
||||
once sync.Once // Protects closing done
|
||||
done chan struct{}
|
||||
rerr onceError
|
||||
werr onceError
|
||||
}
|
||||
|
||||
func (p *pipe) read(b []byte) (n int, err error) {
|
||||
select {
|
||||
case <-p.done:
|
||||
return 0, p.readCloseError()
|
||||
default:
|
||||
}
|
||||
|
||||
select {
|
||||
case bw := <-p.wrCh:
|
||||
nr := copy(b, bw)
|
||||
p.rdCh <- nr
|
||||
return nr, nil
|
||||
case <-p.done:
|
||||
return 0, p.readCloseError()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *pipe) closeRead(err error) error {
|
||||
if err == nil {
|
||||
err = ErrClosedPipe
|
||||
}
|
||||
p.rerr.Store(err)
|
||||
p.once.Do(func() { close(p.done) })
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *pipe) write(b []byte) (n int, err error) {
|
||||
select {
|
||||
case <-p.done:
|
||||
return 0, p.writeCloseError()
|
||||
default:
|
||||
p.wrMu.Lock()
|
||||
defer p.wrMu.Unlock()
|
||||
}
|
||||
|
||||
for once := true; once || len(b) > 0; once = false {
|
||||
select {
|
||||
case p.wrCh <- b:
|
||||
nw := <-p.rdCh
|
||||
b = b[nw:]
|
||||
n += nw
|
||||
case <-p.done:
|
||||
return n, p.writeCloseError()
|
||||
}
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (p *pipe) closeWrite(err error) error {
|
||||
if err == nil {
|
||||
err = io.EOF
|
||||
}
|
||||
p.werr.Store(err)
|
||||
p.once.Do(func() { close(p.done) })
|
||||
return nil
|
||||
}
|
||||
|
||||
// readCloseError is considered internal to the pipe type.
|
||||
func (p *pipe) readCloseError() error {
|
||||
rerr := p.rerr.Load()
|
||||
if werr := p.werr.Load(); rerr == nil && werr != nil {
|
||||
return werr
|
||||
}
|
||||
return ErrClosedPipe
|
||||
}
|
||||
|
||||
// writeCloseError is considered internal to the pipe type.
|
||||
func (p *pipe) writeCloseError() error {
|
||||
werr := p.werr.Load()
|
||||
if rerr := p.rerr.Load(); werr == nil && rerr != nil {
|
||||
return rerr
|
||||
}
|
||||
return ErrClosedPipe
|
||||
}
|
||||
|
||||
// A PipeReader is the read half of a pipe.
|
||||
type PipeReader struct {
|
||||
p *pipe
|
||||
}
|
||||
|
||||
// Read implements the standard Read interface:
|
||||
// it reads data from the pipe, blocking until a writer
|
||||
// arrives or the write end is closed.
|
||||
// If the write end is closed with an error, that error is
|
||||
// returned as err; otherwise err is EOF.
|
||||
func (r *PipeReader) Read(data []byte) (n int, err error) {
|
||||
return r.p.read(data)
|
||||
}
|
||||
|
||||
// Close closes the reader; subsequent writes to the
|
||||
// write half of the pipe will return the error ErrClosedPipe.
|
||||
func (r *PipeReader) Close() error {
|
||||
return r.CloseWithError(nil)
|
||||
}
|
||||
|
||||
// CloseWithError closes the reader; subsequent writes
|
||||
// to the write half of the pipe will return the error err.
|
||||
//
|
||||
// CloseWithError never overwrites the previous error if it exists
|
||||
// and always returns nil.
|
||||
func (r *PipeReader) CloseWithError(err error) error {
|
||||
return r.p.closeRead(err)
|
||||
}
|
||||
|
||||
// A PipeWriter is the write half of a pipe.
|
||||
type PipeWriter struct {
|
||||
p *pipe
|
||||
}
|
||||
|
||||
// Write implements the standard Write interface:
|
||||
// it writes data to the pipe, blocking until one or more readers
|
||||
// have consumed all the data or the read end is closed.
|
||||
// If the read end is closed with an error, that err is
|
||||
// returned as err; otherwise err is ErrClosedPipe.
|
||||
func (w *PipeWriter) Write(data []byte) (n int, err error) {
|
||||
return w.p.write(data)
|
||||
}
|
||||
|
||||
// Close closes the writer; subsequent reads from the
|
||||
// read half of the pipe will return no bytes and EOF.
|
||||
func (w *PipeWriter) Close() error {
|
||||
return w.CloseWithError(nil)
|
||||
}
|
||||
|
||||
// CloseWithError closes the writer; subsequent reads from the
|
||||
// read half of the pipe will return no bytes and the error err,
|
||||
// or EOF if err is nil.
|
||||
//
|
||||
// CloseWithError never overwrites the previous error if it exists
|
||||
// and always returns nil.
|
||||
func (w *PipeWriter) CloseWithError(err error) error {
|
||||
return w.p.closeWrite(err)
|
||||
}
|
||||
|
||||
// Pipe creates a synchronous in-memory pipe.
|
||||
// It can be used to connect code expecting an io.Reader
|
||||
// with code expecting an io.Writer.
|
||||
//
|
||||
// Reads and Writes on the pipe are matched one to one
|
||||
// except when multiple Reads are needed to consume a single Write.
|
||||
// That is, each Write to the PipeWriter blocks until it has satisfied
|
||||
// one or more Reads from the PipeReader that fully consume
|
||||
// the written data.
|
||||
// The data is copied directly from the Write to the corresponding
|
||||
// Read (or Reads); there is no internal buffering.
|
||||
//
|
||||
// It is safe to call Read and Write in parallel with each other or with Close.
|
||||
// Parallel calls to Read and parallel calls to Write are also safe:
|
||||
// the individual calls will be gated sequentially.
|
||||
func Pipe() (*PipeReader, *PipeWriter) {
|
||||
p := &pipe{
|
||||
wrCh: make(chan []byte, 1),
|
||||
rdCh: make(chan int, 1),
|
||||
done: make(chan struct{}, 1),
|
||||
}
|
||||
return &PipeReader{p}, &PipeWriter{p}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package iter
|
||||
@@ -1,456 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package big
|
||||
|
||||
// llgo:skipall
|
||||
import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/openssl"
|
||||
)
|
||||
|
||||
// A Word represents a single digit of a multi-precision unsigned integer.
|
||||
type Word openssl.BN_ULONG
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// TODO(xsw): share ctx
|
||||
func ctxGet() *openssl.BN_CTX {
|
||||
return openssl.BN_CTXNew()
|
||||
}
|
||||
|
||||
func ctxPut(ctx *openssl.BN_CTX) {
|
||||
ctx.Free()
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type Int openssl.BIGNUM
|
||||
|
||||
// Sign returns:
|
||||
//
|
||||
// -1 if x < 0
|
||||
// 0 if x == 0
|
||||
// +1 if x > 0
|
||||
func (x *Int) Sign() int {
|
||||
a := (*openssl.BIGNUM)(x)
|
||||
if a.IsNegative() != 0 {
|
||||
return -1
|
||||
} else if a.IsZero() != 0 {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
// SetInt64 sets z to x and returns z.
|
||||
func (z *Int) SetInt64(x int64) *Int {
|
||||
a := (*openssl.BIGNUM)(z)
|
||||
if x < 0 {
|
||||
a.SetWord(openssl.BN_ULONG(-x))
|
||||
a.SetNegative(1)
|
||||
} else {
|
||||
a.SetWord(openssl.BN_ULONG(x))
|
||||
a.SetNegative(0)
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
// SetUint64 sets z to x and returns z.
|
||||
func (z *Int) SetUint64(x uint64) *Int {
|
||||
a := (*openssl.BIGNUM)(z)
|
||||
a.SetWord(openssl.BN_ULONG(x))
|
||||
a.SetNegative(0)
|
||||
return z
|
||||
}
|
||||
|
||||
// NewInt allocates and returns a new Int set to x.
|
||||
func NewInt(x int64) *Int {
|
||||
z := (*Int)(openssl.BNNew())
|
||||
return z.SetInt64(x)
|
||||
}
|
||||
|
||||
// Set sets z to x and returns z.
|
||||
func (z *Int) Set(x *Int) *Int {
|
||||
if z != x {
|
||||
a := (*openssl.BIGNUM)(z)
|
||||
b := (*openssl.BIGNUM)(x)
|
||||
a.Copy(b)
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
// Abs sets z to |x| (the absolute value of x) and returns z.
|
||||
func (z *Int) Abs(x *Int) *Int {
|
||||
z.Set(x)
|
||||
a := (*openssl.BIGNUM)(z)
|
||||
a.SetNegative(0)
|
||||
return z
|
||||
}
|
||||
|
||||
// Neg sets z to -x and returns z.
|
||||
func (z *Int) Neg(x *Int) *Int {
|
||||
z.Set(x)
|
||||
a := (*openssl.BIGNUM)(z)
|
||||
if a.IsNegative() != 0 {
|
||||
a.SetNegative(0)
|
||||
} else {
|
||||
a.SetNegative(1)
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
// Bits provides raw (unchecked but fast) access to x by returning its
|
||||
// absolute value as a little-endian Word slice. The result and x share
|
||||
// the same underlying array.
|
||||
// Bits is intended to support implementation of missing low-level Int
|
||||
// functionality outside this package; it should be avoided otherwise.
|
||||
func (x *Int) Bits() []Word {
|
||||
panic("todo big.Bits")
|
||||
}
|
||||
|
||||
// SetBits provides raw (unchecked but fast) access to z by setting its
|
||||
// value to abs, interpreted as a little-endian Word slice, and returning
|
||||
// z. The result and abs share the same underlying array.
|
||||
// SetBits is intended to support implementation of missing low-level Int
|
||||
// functionality outside this package; it should be avoided otherwise.
|
||||
func (z *Int) SetBits(abs []Word) *Int {
|
||||
panic("todo big.SetBits")
|
||||
}
|
||||
|
||||
// Add sets z to the sum x+y and returns z.
|
||||
func (z *Int) Add(x, y *Int) *Int {
|
||||
(*openssl.BIGNUM)(z).Add((*openssl.BIGNUM)(x), (*openssl.BIGNUM)(y))
|
||||
return z
|
||||
}
|
||||
|
||||
// Sub sets z to the difference x-y and returns z.
|
||||
func (z *Int) Sub(x, y *Int) *Int {
|
||||
(*openssl.BIGNUM)(z).Sub((*openssl.BIGNUM)(x), (*openssl.BIGNUM)(y))
|
||||
return z
|
||||
}
|
||||
|
||||
// Mul sets z to the product x*y and returns z.
|
||||
func (z *Int) Mul(x, y *Int) *Int {
|
||||
panic("todo big.Mul")
|
||||
}
|
||||
|
||||
// MulRange sets z to the product of all integers
|
||||
// in the range [a, b] inclusively and returns z.
|
||||
// If a > b (empty range), the result is 1.
|
||||
func (z *Int) MulRange(a, b int64) *Int {
|
||||
panic("todo big.MulRange")
|
||||
}
|
||||
|
||||
// Binomial sets z to the binomial coefficient C(n, k) and returns z.
|
||||
func (z *Int) Binomial(n, k int64) *Int {
|
||||
panic("todo big.Binomial")
|
||||
}
|
||||
|
||||
// Quo sets z to the quotient x/y for y != 0 and returns z.
|
||||
// If y == 0, a division-by-zero run-time panic occurs.
|
||||
// Quo implements truncated division (like Go); see QuoRem for more details.
|
||||
func (z *Int) Quo(x, y *Int) *Int {
|
||||
panic("todo big.Quo")
|
||||
}
|
||||
|
||||
// Rem sets z to the remainder x%y for y != 0 and returns z.
|
||||
// If y == 0, a division-by-zero run-time panic occurs.
|
||||
// Rem implements truncated modulus (like Go); see QuoRem for more details.
|
||||
func (z *Int) Rem(x, y *Int) *Int {
|
||||
panic("todo big.Rem")
|
||||
}
|
||||
|
||||
// QuoRem sets z to the quotient x/y and r to the remainder x%y
|
||||
// and returns the pair (z, r) for y != 0.
|
||||
// If y == 0, a division-by-zero run-time panic occurs.
|
||||
//
|
||||
// QuoRem implements T-division and modulus (like Go):
|
||||
//
|
||||
// q = x/y with the result truncated to zero
|
||||
// r = x - y*q
|
||||
//
|
||||
// (See Daan Leijen, “Division and Modulus for Computer Scientists”.)
|
||||
// See DivMod for Euclidean division and modulus (unlike Go).
|
||||
func (z *Int) QuoRem(x, y, r *Int) (*Int, *Int) {
|
||||
panic("todo big.QuoRem")
|
||||
}
|
||||
|
||||
// Div sets z to the quotient x/y for y != 0 and returns z.
|
||||
// If y == 0, a division-by-zero run-time panic occurs.
|
||||
// Div implements Euclidean division (unlike Go); see DivMod for more details.
|
||||
func (z *Int) Div(x, y *Int) *Int {
|
||||
panic("todo big.Div")
|
||||
}
|
||||
|
||||
// Mod sets z to the modulus x%y for y != 0 and returns z.
|
||||
// If y == 0, a division-by-zero run-time panic occurs.
|
||||
// Mod implements Euclidean modulus (unlike Go); see DivMod for more details.
|
||||
func (z *Int) Mod(x, y *Int) *Int {
|
||||
panic("todo big.Mod")
|
||||
}
|
||||
|
||||
// DivMod sets z to the quotient x div y and m to the modulus x mod y
|
||||
// and returns the pair (z, m) for y != 0.
|
||||
// If y == 0, a division-by-zero run-time panic occurs.
|
||||
//
|
||||
// DivMod implements Euclidean division and modulus (unlike Go):
|
||||
//
|
||||
// q = x div y such that
|
||||
// m = x - y*q with 0 <= m < |y|
|
||||
//
|
||||
// (See Raymond T. Boute, “The Euclidean definition of the functions
|
||||
// div and mod”. ACM Transactions on Programming Languages and
|
||||
// Systems (TOPLAS), 14(2):127-144, New York, NY, USA, 4/1992.
|
||||
// ACM press.)
|
||||
// See QuoRem for T-division and modulus (like Go).
|
||||
func (z *Int) DivMod(x, y, m *Int) (*Int, *Int) {
|
||||
panic("big.DivMod")
|
||||
}
|
||||
|
||||
// Cmp compares x and y and returns:
|
||||
//
|
||||
// -1 if x < y
|
||||
// 0 if x == y
|
||||
// +1 if x > y
|
||||
func (x *Int) Cmp(y *Int) (r int) {
|
||||
return int((*openssl.BIGNUM)(x).Cmp((*openssl.BIGNUM)(y)))
|
||||
}
|
||||
|
||||
// CmpAbs compares the absolute values of x and y and returns:
|
||||
//
|
||||
// -1 if |x| < |y|
|
||||
// 0 if |x| == |y|
|
||||
// +1 if |x| > |y|
|
||||
func (x *Int) CmpAbs(y *Int) int {
|
||||
return int((*openssl.BIGNUM)(x).Ucmp((*openssl.BIGNUM)(y)))
|
||||
}
|
||||
|
||||
// Int64 returns the int64 representation of x.
|
||||
// If x cannot be represented in an int64, the result is undefined.
|
||||
func (x *Int) Int64() int64 {
|
||||
panic("todo big.Int64")
|
||||
}
|
||||
|
||||
// Uint64 returns the uint64 representation of x.
|
||||
// If x cannot be represented in a uint64, the result is undefined.
|
||||
func (x *Int) Uint64() uint64 {
|
||||
panic("todo big.Uint64")
|
||||
}
|
||||
|
||||
// IsInt64 reports whether x can be represented as an int64.
|
||||
func (x *Int) IsInt64() bool {
|
||||
panic("todo big.IsInt64")
|
||||
}
|
||||
|
||||
// IsUint64 reports whether x can be represented as a uint64.
|
||||
func (x *Int) IsUint64() bool {
|
||||
panic("todo big.IsUint64")
|
||||
}
|
||||
|
||||
// Float64 returns the float64 value nearest x,
|
||||
// and an indication of any rounding that occurred.
|
||||
// TODO(xsw):
|
||||
/*
|
||||
func (x *Int) Float64() (float64, Accuracy) {
|
||||
panic("todo big.Float64")
|
||||
}*/
|
||||
|
||||
// SetString sets z to the value of s, interpreted in the given base,
|
||||
// and returns z and a boolean indicating success. The entire string
|
||||
// (not just a prefix) must be valid for success. If SetString fails,
|
||||
// the value of z is undefined but the returned value is nil.
|
||||
//
|
||||
// The base argument must be 0 or a value between 2 and MaxBase.
|
||||
// For base 0, the number prefix determines the actual base: A prefix of
|
||||
// “0b” or “0B” selects base 2, “0”, “0o” or “0O” selects base 8,
|
||||
// and “0x” or “0X” selects base 16. Otherwise, the selected base is 10
|
||||
// and no prefix is accepted.
|
||||
//
|
||||
// For bases <= 36, lower and upper case letters are considered the same:
|
||||
// The letters 'a' to 'z' and 'A' to 'Z' represent digit values 10 to 35.
|
||||
// For bases > 36, the upper case letters 'A' to 'Z' represent the digit
|
||||
// values 36 to 61.
|
||||
//
|
||||
// For base 0, an underscore character “_” may appear between a base
|
||||
// prefix and an adjacent digit, and between successive digits; such
|
||||
// underscores do not change the value of the number.
|
||||
// Incorrect placement of underscores is reported as an error if there
|
||||
// are no other errors. If base != 0, underscores are not recognized
|
||||
// and act like any other character that is not a valid digit.
|
||||
func (z *Int) SetString(s string, base int) (*Int, bool) {
|
||||
panic("todo big.SetString")
|
||||
}
|
||||
|
||||
// SetBytes interprets buf as the bytes of a big-endian unsigned
|
||||
// integer, sets z to that value, and returns z.
|
||||
func (z *Int) SetBytes(buf []byte) *Int {
|
||||
panic("todo big.SetBytes")
|
||||
}
|
||||
|
||||
// Bytes returns the absolute value of x as a big-endian byte slice.
|
||||
//
|
||||
// To use a fixed length slice, or a preallocated one, use FillBytes.
|
||||
func (x *Int) Bytes() []byte {
|
||||
panic("todo big.Bytes")
|
||||
}
|
||||
|
||||
// FillBytes sets buf to the absolute value of x, storing it as a zero-extended
|
||||
// big-endian byte slice, and returns buf.
|
||||
//
|
||||
// If the absolute value of x doesn't fit in buf, FillBytes will panic.
|
||||
func (x *Int) FillBytes(buf []byte) []byte {
|
||||
panic("todo big.FillBytes")
|
||||
}
|
||||
|
||||
// BitLen returns the length of the absolute value of x in bits.
|
||||
// The bit length of 0 is 0.
|
||||
func (x *Int) BitLen() int {
|
||||
panic("todo big.BitLen")
|
||||
}
|
||||
|
||||
// TrailingZeroBits returns the number of consecutive least significant zero
|
||||
// bits of |x|.
|
||||
func (x *Int) TrailingZeroBits() uint {
|
||||
panic("todo big.TrailingZeroBits")
|
||||
}
|
||||
|
||||
// Exp sets z = x**y mod |m| (i.e. the sign of m is ignored), and returns z.
|
||||
// If m == nil or m == 0, z = x**y unless y <= 0 then z = 1. If m != 0, y < 0,
|
||||
// and x and m are not relatively prime, z is unchanged and nil is returned.
|
||||
//
|
||||
// Modular exponentiation of inputs of a particular size is not a
|
||||
// cryptographically constant-time operation.
|
||||
func (z *Int) Exp(x, y, m *Int) *Int {
|
||||
ctx := ctxGet()
|
||||
mbn := (*openssl.BIGNUM)(m)
|
||||
if mbn == nil || mbn.IsZero() != 0 {
|
||||
(*openssl.BIGNUM)(z).Exp((*openssl.BIGNUM)(x), (*openssl.BIGNUM)(y), ctx)
|
||||
} else {
|
||||
(*openssl.BIGNUM)(z).ModExp((*openssl.BIGNUM)(x), (*openssl.BIGNUM)(y), mbn, ctx)
|
||||
}
|
||||
ctxPut(ctx)
|
||||
return z
|
||||
}
|
||||
|
||||
// GCD sets z to the greatest common divisor of a and b and returns z.
|
||||
// If x or y are not nil, GCD sets their value such that z = a*x + b*y.
|
||||
//
|
||||
// a and b may be positive, zero or negative. (Before Go 1.14 both had
|
||||
// to be > 0.) Regardless of the signs of a and b, z is always >= 0.
|
||||
//
|
||||
// If a == b == 0, GCD sets z = x = y = 0.
|
||||
//
|
||||
// If a == 0 and b != 0, GCD sets z = |b|, x = 0, y = sign(b) * 1.
|
||||
//
|
||||
// If a != 0 and b == 0, GCD sets z = |a|, x = sign(a) * 1, y = 0.
|
||||
func (z *Int) GCD(x, y, a, b *Int) *Int {
|
||||
panic("todo big.GCD")
|
||||
}
|
||||
|
||||
// Rand sets z to a pseudo-random number in [0, n) and returns z.
|
||||
//
|
||||
// As this uses the math/rand package, it must not be used for
|
||||
// security-sensitive work. Use crypto/rand.Int instead.
|
||||
func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
|
||||
panic("todo big.Rand")
|
||||
}
|
||||
|
||||
// ModInverse sets z to the multiplicative inverse of g in the ring ℤ/nℤ
|
||||
// and returns z. If g and n are not relatively prime, g has no multiplicative
|
||||
// inverse in the ring ℤ/nℤ. In this case, z is unchanged and the return value
|
||||
// is nil. If n == 0, a division-by-zero run-time panic occurs.
|
||||
func (z *Int) ModInverse(g, n *Int) *Int {
|
||||
panic("todo big.ModInverse")
|
||||
}
|
||||
|
||||
// Jacobi returns the Jacobi symbol (x/y), either +1, -1, or 0.
|
||||
// The y argument must be an odd integer.
|
||||
func Jacobi(x, y *Int) int {
|
||||
panic("todo big.Jacobi")
|
||||
}
|
||||
|
||||
// ModSqrt sets z to a square root of x mod p if such a square root exists, and
|
||||
// returns z. The modulus p must be an odd prime. If x is not a square mod p,
|
||||
// ModSqrt leaves z unchanged and returns nil. This function panics if p is
|
||||
// not an odd integer, its behavior is undefined if p is odd but not prime.
|
||||
func (z *Int) ModSqrt(x, p *Int) *Int {
|
||||
panic("todo big.ModSqrt")
|
||||
}
|
||||
|
||||
// Lsh sets z = x << n and returns z.
|
||||
func (z *Int) Lsh(x *Int, n uint) *Int {
|
||||
a := (*openssl.BIGNUM)(z)
|
||||
b := (*openssl.BIGNUM)(x)
|
||||
a.Lshift(b, c.Int(n))
|
||||
return z
|
||||
}
|
||||
|
||||
// Rsh sets z = x >> n and returns z.
|
||||
func (z *Int) Rsh(x *Int, n uint) *Int {
|
||||
a := (*openssl.BIGNUM)(z)
|
||||
b := (*openssl.BIGNUM)(x)
|
||||
a.Rshift(b, c.Int(n))
|
||||
return z
|
||||
}
|
||||
|
||||
// Bit returns the value of the i'th bit of x. That is, it
|
||||
// returns (x>>i)&1. The bit index i must be >= 0.
|
||||
func (x *Int) Bit(i int) uint {
|
||||
panic("todo big.Bit")
|
||||
}
|
||||
|
||||
// SetBit sets z to x, with x's i'th bit set to b (0 or 1).
|
||||
// That is, if b is 1 SetBit sets z = x | (1 << i);
|
||||
// if b is 0 SetBit sets z = x &^ (1 << i). If b is not 0 or 1,
|
||||
// SetBit will panic.
|
||||
func (z *Int) SetBit(x *Int, i int, b uint) *Int {
|
||||
panic("todo big.SetBit")
|
||||
}
|
||||
|
||||
// And sets z = x & y and returns z.
|
||||
func (z *Int) And(x, y *Int) *Int {
|
||||
panic("todo big.And")
|
||||
}
|
||||
|
||||
// AndNot sets z = x &^ y and returns z.
|
||||
func (z *Int) AndNot(x, y *Int) *Int {
|
||||
panic("todo big.AndNot")
|
||||
}
|
||||
|
||||
// Or sets z = x | y and returns z.
|
||||
func (z *Int) Or(x, y *Int) *Int {
|
||||
panic("todo big.Or")
|
||||
}
|
||||
|
||||
// Xor sets z = x ^ y and returns z.
|
||||
func (z *Int) Xor(x, y *Int) *Int {
|
||||
panic("todo big.Xor")
|
||||
}
|
||||
|
||||
// Not sets z = ^x and returns z.
|
||||
func (z *Int) Not(x *Int) *Int {
|
||||
panic("todo big.Not")
|
||||
}
|
||||
|
||||
// Sqrt sets z to ⌊√x⌋, the largest integer such that z² ≤ x, and returns z.
|
||||
// It panics if x is negative.
|
||||
func (z *Int) Sqrt(x *Int) *Int {
|
||||
panic("todo big.Sqrt")
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/openssl"
|
||||
)
|
||||
|
||||
/*
|
||||
// Text returns the string representation of x in the given base.
|
||||
// Base must be between 2 and 62, inclusive. The result uses the
|
||||
// lower-case letters 'a' to 'z' for digit values 10 to 35, and
|
||||
// the upper-case letters 'A' to 'Z' for digit values 36 to 61.
|
||||
// No prefix (such as "0x") is added to the string. If x is a nil
|
||||
// pointer it returns "<nil>".
|
||||
func (x *Int) Text(base int) string {
|
||||
}
|
||||
|
||||
// Append appends the string representation of x, as generated by
|
||||
// x.Text(base), to buf and returns the extended buffer.
|
||||
func (x *Int) Append(buf []byte, base int) []byte {
|
||||
}
|
||||
*/
|
||||
|
||||
// String returns the decimal representation of x as generated by
|
||||
// x.Text(10).
|
||||
func (x *Int) String() string {
|
||||
// TODO(xsw): can optimize it?
|
||||
cstr := (*openssl.BIGNUM)(x).CStr()
|
||||
ret := c.GoString(cstr)
|
||||
openssl.FreeCStr(cstr)
|
||||
return ret
|
||||
}
|
||||
|
||||
/*
|
||||
// Format implements fmt.Formatter. It accepts the formats
|
||||
// 'b' (binary), 'o' (octal with 0 prefix), 'O' (octal with 0o prefix),
|
||||
// 'd' (decimal), 'x' (lowercase hexadecimal), and
|
||||
// 'X' (uppercase hexadecimal).
|
||||
// Also supported are the full suite of package fmt's format
|
||||
// flags for integral types, including '+' and ' ' for sign
|
||||
// control, '#' for leading zero in octal and for hexadecimal,
|
||||
// a leading "0x" or "0X" for "%#x" and "%#X" respectively,
|
||||
// specification of minimum digits precision, output field
|
||||
// width, space or zero padding, and '-' for left or right
|
||||
// justification.
|
||||
func (x *Int) Format(s fmt.State, ch rune) {
|
||||
}
|
||||
|
||||
// Scan is a support routine for fmt.Scanner; it sets z to the value of
|
||||
// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
|
||||
// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
|
||||
func (z *Int) Scan(s fmt.ScanState, ch rune) error {
|
||||
}
|
||||
*/
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cmplx
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = true
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Abs C.cabs
|
||||
func Abs(z complex128) float64
|
||||
|
||||
//go:linkname Acos C.cacos
|
||||
func Acos(z complex128) complex128
|
||||
|
||||
//go:linkname Acosh C.cacosh
|
||||
func Acosh(z complex128) complex128
|
||||
|
||||
//go:linkname Asin C.casin
|
||||
func Asin(z complex128) complex128
|
||||
|
||||
//go:linkname Asinh C.casinh
|
||||
func Asinh(z complex128) complex128
|
||||
|
||||
//go:linkname Atan C.catan
|
||||
func Atan(z complex128) complex128
|
||||
|
||||
//go:linkname Atanh C.catanh
|
||||
func Atanh(z complex128) complex128
|
||||
|
||||
//go:linkname Cos C.ccos
|
||||
func Cos(z complex128) complex128
|
||||
|
||||
//go:linkname Cosh C.ccosh
|
||||
func Cosh(z complex128) complex128
|
||||
|
||||
//go:linkname Exp C.cexp
|
||||
func Exp(z complex128) complex128
|
||||
|
||||
//go:linkname Log C.clog
|
||||
func Log(z complex128) complex128
|
||||
|
||||
//go:linkname Log10 C.clog10
|
||||
func Log10(z complex128) complex128
|
||||
|
||||
//go:linkname Phase C.carg
|
||||
func Phase(z complex128) float64
|
||||
|
||||
//go:linkname Pow C.cpow
|
||||
func Pow(x, y complex128) complex128
|
||||
|
||||
//go:linkname Sin C.csin
|
||||
func Sin(z complex128) complex128
|
||||
|
||||
//go:linkname Sinh C.csinh
|
||||
func Sinh(z complex128) complex128
|
||||
|
||||
//go:linkname Sqrt C.csqrt
|
||||
func Sqrt(z complex128) complex128
|
||||
|
||||
//go:linkname Tan C.ctan
|
||||
func Tan(z complex128) complex128
|
||||
|
||||
//go:linkname Tanh C.ctanh
|
||||
func Tanh(z complex128) complex128
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -1,202 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package math
|
||||
|
||||
// llgo:skip sin cos
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = true
|
||||
)
|
||||
|
||||
//go:linkname Acos C.acos
|
||||
func Acos(x float64) float64
|
||||
|
||||
//go:linkname Acosh C.acosh
|
||||
func Acosh(x float64) float64
|
||||
|
||||
//go:linkname Asin C.asin
|
||||
func Asin(x float64) float64
|
||||
|
||||
//go:linkname Asinh C.asinh
|
||||
func Asinh(x float64) float64
|
||||
|
||||
//go:linkname Atan C.atan
|
||||
func Atan(x float64) float64
|
||||
|
||||
//go:linkname Atan2 C.atan2
|
||||
func Atan2(y, x float64) float64
|
||||
|
||||
//go:linkname Atanh C.atanh
|
||||
func Atanh(x float64) float64
|
||||
|
||||
//go:linkname Cbrt C.cbrt
|
||||
func Cbrt(x float64) float64
|
||||
|
||||
//go:linkname Ceil C.ceil
|
||||
func Ceil(x float64) float64
|
||||
|
||||
//go:linkname Cos C.cos
|
||||
func Cos(x float64) float64
|
||||
|
||||
//go:linkname Cosh C.cosh
|
||||
func Cosh(x float64) float64
|
||||
|
||||
//go:linkname Copysign C.copysign
|
||||
func Copysign(x, y float64) float64
|
||||
|
||||
//go:linkname Erf C.erf
|
||||
func Erf(x float64) float64
|
||||
|
||||
//go:linkname Erfc C.erfc
|
||||
func Erfc(x float64) float64
|
||||
|
||||
//go:linkname Exp C.exp
|
||||
func Exp(x float64) float64
|
||||
|
||||
//go:linkname Exp2 C.exp2
|
||||
func Exp2(x float64) float64
|
||||
|
||||
//go:linkname Expm1 C.expm1
|
||||
func Expm1(x float64) float64
|
||||
|
||||
//go:linkname Dim C.fdim
|
||||
func Dim(x, y float64) float64
|
||||
|
||||
//go:linkname Floor C.floor
|
||||
func Floor(x float64) float64
|
||||
|
||||
//go:linkname FMA C.fma
|
||||
func FMA(x, y, z float64) float64
|
||||
|
||||
//go:linkname Max C.fmax
|
||||
func Max(x, y float64) float64
|
||||
|
||||
//go:linkname Min C.fmin
|
||||
func Min(x, y float64) float64
|
||||
|
||||
//go:linkname Mod C.fmod
|
||||
func Mod(x, y float64) float64
|
||||
|
||||
//go:linkname cFrexp C.frexp
|
||||
func cFrexp(x float64, exp *c.Int) float64
|
||||
|
||||
func Frexp(f float64) (float64, int) {
|
||||
var exp c.Int
|
||||
var ret = cFrexp(f, &exp)
|
||||
return ret, int(exp)
|
||||
}
|
||||
|
||||
//go:linkname Gamma C.gamma
|
||||
func Gamma(x float64) float64
|
||||
|
||||
//go:linkname Hypot C.hypot
|
||||
func Hypot(x, y float64) float64
|
||||
|
||||
//go:linkname cIlogb C.ilogb
|
||||
func cIlogb(x float64) c.Int
|
||||
|
||||
func Ilogb(x float64) int {
|
||||
return int(cIlogb(x))
|
||||
}
|
||||
|
||||
//go:linkname J0 C.j0
|
||||
func J0(x float64) float64
|
||||
|
||||
//go:linkname J1 C.j1
|
||||
func J1(x float64) float64
|
||||
|
||||
//go:linkname cJn C.jn
|
||||
func cJn(n c.Int, x float64) float64
|
||||
|
||||
func Jn(n int, x float64) float64 {
|
||||
return cJn(c.Int(n), x)
|
||||
}
|
||||
|
||||
//go:linkname cLdexp C.ldexp
|
||||
func cLdexp(x float64, exp c.Int) float64
|
||||
|
||||
func Ldexp(x float64, exp int) float64 {
|
||||
return cLdexp(x, c.Int(exp))
|
||||
}
|
||||
|
||||
//-go:linkname cLgamma C.lgamma
|
||||
//func cLgamma(x float64) float64
|
||||
|
||||
//go:linkname Log C.log
|
||||
func Log(x float64) float64
|
||||
|
||||
//go:linkname Log10 C.log10
|
||||
func Log10(x float64) float64
|
||||
|
||||
//go:linkname Log1p C.log1p
|
||||
func Log1p(x float64) float64
|
||||
|
||||
//go:linkname Log2 C.log2
|
||||
func Log2(x float64) float64
|
||||
|
||||
//go:linkname Logb C.logb
|
||||
func Logb(x float64) float64
|
||||
|
||||
//go:linkname cModf C.modf
|
||||
func cModf(x float64, intpart *float64) float64
|
||||
|
||||
func Modf(f float64) (float64, float64) {
|
||||
var intpart float64
|
||||
var ret = cModf(f, &intpart)
|
||||
return intpart, ret
|
||||
}
|
||||
|
||||
//-go:linkname cNan C.nan
|
||||
//func cNan(tag *c.Char) float64
|
||||
|
||||
//go:linkname Nextafter C.nextafter
|
||||
func Nextafter(x, y float64) float64
|
||||
|
||||
//go:linkname Pow C.pow
|
||||
func Pow(x, y float64) float64
|
||||
|
||||
//go:linkname Remainder C.remainder
|
||||
func Remainder(x, y float64) float64
|
||||
|
||||
//go:linkname Round C.round
|
||||
func Round(x float64) float64
|
||||
|
||||
//go:linkname Sin C.sin
|
||||
func Sin(x float64) float64
|
||||
|
||||
//go:linkname Sinh C.sinh
|
||||
func Sinh(x float64) float64
|
||||
|
||||
//go:linkname Sqrt C.sqrt
|
||||
func Sqrt(x float64) float64
|
||||
|
||||
//go:linkname Tan C.tan
|
||||
func Tan(x float64) float64
|
||||
|
||||
//go:linkname Tanh C.tanh
|
||||
func Tanh(x float64) float64
|
||||
|
||||
//-go:linkname Tgamma C.tgamma
|
||||
//func Tgamma(x float64) float64
|
||||
|
||||
//go:linkname Trunc C.trunc
|
||||
func Trunc(x float64) float64
|
||||
@@ -1,221 +0,0 @@
|
||||
// Copyright 2009 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 rand
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
/*
|
||||
* Exponential distribution
|
||||
*
|
||||
* See "The Ziggurat Method for Generating Random Variables"
|
||||
* (Marsaglia & Tsang, 2000)
|
||||
* https://www.jstatsoft.org/v05/i08/paper [pdf]
|
||||
*/
|
||||
|
||||
const (
|
||||
re = 7.69711747013104972
|
||||
)
|
||||
|
||||
// ExpFloat64 returns an exponentially distributed float64 in the range
|
||||
// (0, +math.MaxFloat64] with an exponential distribution whose rate parameter
|
||||
// (lambda) is 1 and whose mean is 1/lambda (1).
|
||||
// To produce a distribution with a different rate parameter,
|
||||
// callers can adjust the output using:
|
||||
//
|
||||
// sample = ExpFloat64() / desiredRateParameter
|
||||
func (r *Rand) ExpFloat64() float64 {
|
||||
for {
|
||||
j := r.Uint32()
|
||||
i := j & 0xFF
|
||||
x := float64(j) * float64(we[i])
|
||||
if j < ke[i] {
|
||||
return x
|
||||
}
|
||||
if i == 0 {
|
||||
return re - math.Log(r.Float64())
|
||||
}
|
||||
if fe[i]+float32(r.Float64())*(fe[i-1]-fe[i]) < float32(math.Exp(-x)) {
|
||||
return x
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var ke = [256]uint32{
|
||||
0xe290a139, 0x0, 0x9beadebc, 0xc377ac71, 0xd4ddb990,
|
||||
0xde893fb8, 0xe4a8e87c, 0xe8dff16a, 0xebf2deab, 0xee49a6e8,
|
||||
0xf0204efd, 0xf19bdb8e, 0xf2d458bb, 0xf3da104b, 0xf4b86d78,
|
||||
0xf577ad8a, 0xf61de83d, 0xf6afb784, 0xf730a573, 0xf7a37651,
|
||||
0xf80a5bb6, 0xf867189d, 0xf8bb1b4f, 0xf9079062, 0xf94d70ca,
|
||||
0xf98d8c7d, 0xf9c8928a, 0xf9ff175b, 0xfa319996, 0xfa6085f8,
|
||||
0xfa8c3a62, 0xfab5084e, 0xfadb36c8, 0xfaff0410, 0xfb20a6ea,
|
||||
0xfb404fb4, 0xfb5e2951, 0xfb7a59e9, 0xfb95038c, 0xfbae44ba,
|
||||
0xfbc638d8, 0xfbdcf892, 0xfbf29a30, 0xfc0731df, 0xfc1ad1ed,
|
||||
0xfc2d8b02, 0xfc3f6c4d, 0xfc5083ac, 0xfc60ddd1, 0xfc708662,
|
||||
0xfc7f8810, 0xfc8decb4, 0xfc9bbd62, 0xfca9027c, 0xfcb5c3c3,
|
||||
0xfcc20864, 0xfccdd70a, 0xfcd935e3, 0xfce42ab0, 0xfceebace,
|
||||
0xfcf8eb3b, 0xfd02c0a0, 0xfd0c3f59, 0xfd156b7b, 0xfd1e48d6,
|
||||
0xfd26daff, 0xfd2f2552, 0xfd372af7, 0xfd3eeee5, 0xfd4673e7,
|
||||
0xfd4dbc9e, 0xfd54cb85, 0xfd5ba2f2, 0xfd62451b, 0xfd68b415,
|
||||
0xfd6ef1da, 0xfd750047, 0xfd7ae120, 0xfd809612, 0xfd8620b4,
|
||||
0xfd8b8285, 0xfd90bcf5, 0xfd95d15e, 0xfd9ac10b, 0xfd9f8d36,
|
||||
0xfda43708, 0xfda8bf9e, 0xfdad2806, 0xfdb17141, 0xfdb59c46,
|
||||
0xfdb9a9fd, 0xfdbd9b46, 0xfdc170f6, 0xfdc52bd8, 0xfdc8ccac,
|
||||
0xfdcc542d, 0xfdcfc30b, 0xfdd319ef, 0xfdd6597a, 0xfdd98245,
|
||||
0xfddc94e5, 0xfddf91e6, 0xfde279ce, 0xfde54d1f, 0xfde80c52,
|
||||
0xfdeab7de, 0xfded5034, 0xfdefd5be, 0xfdf248e3, 0xfdf4aa06,
|
||||
0xfdf6f984, 0xfdf937b6, 0xfdfb64f4, 0xfdfd818d, 0xfdff8dd0,
|
||||
0xfe018a08, 0xfe03767a, 0xfe05536c, 0xfe07211c, 0xfe08dfc9,
|
||||
0xfe0a8fab, 0xfe0c30fb, 0xfe0dc3ec, 0xfe0f48b1, 0xfe10bf76,
|
||||
0xfe122869, 0xfe1383b4, 0xfe14d17c, 0xfe1611e7, 0xfe174516,
|
||||
0xfe186b2a, 0xfe19843e, 0xfe1a9070, 0xfe1b8fd6, 0xfe1c8289,
|
||||
0xfe1d689b, 0xfe1e4220, 0xfe1f0f26, 0xfe1fcfbc, 0xfe2083ed,
|
||||
0xfe212bc3, 0xfe21c745, 0xfe225678, 0xfe22d95f, 0xfe234ffb,
|
||||
0xfe23ba4a, 0xfe241849, 0xfe2469f2, 0xfe24af3c, 0xfe24e81e,
|
||||
0xfe25148b, 0xfe253474, 0xfe2547c7, 0xfe254e70, 0xfe25485a,
|
||||
0xfe25356a, 0xfe251586, 0xfe24e88f, 0xfe24ae64, 0xfe2466e1,
|
||||
0xfe2411df, 0xfe23af34, 0xfe233eb4, 0xfe22c02c, 0xfe22336b,
|
||||
0xfe219838, 0xfe20ee58, 0xfe20358c, 0xfe1f6d92, 0xfe1e9621,
|
||||
0xfe1daef0, 0xfe1cb7ac, 0xfe1bb002, 0xfe1a9798, 0xfe196e0d,
|
||||
0xfe1832fd, 0xfe16e5fe, 0xfe15869d, 0xfe141464, 0xfe128ed3,
|
||||
0xfe10f565, 0xfe0f478c, 0xfe0d84b1, 0xfe0bac36, 0xfe09bd73,
|
||||
0xfe07b7b5, 0xfe059a40, 0xfe03644c, 0xfe011504, 0xfdfeab88,
|
||||
0xfdfc26e9, 0xfdf98629, 0xfdf6c83b, 0xfdf3ec01, 0xfdf0f04a,
|
||||
0xfdedd3d1, 0xfdea953d, 0xfde7331e, 0xfde3abe9, 0xfddffdfb,
|
||||
0xfddc2791, 0xfdd826cd, 0xfdd3f9a8, 0xfdcf9dfc, 0xfdcb1176,
|
||||
0xfdc65198, 0xfdc15bb3, 0xfdbc2ce2, 0xfdb6c206, 0xfdb117be,
|
||||
0xfdab2a63, 0xfda4f5fd, 0xfd9e7640, 0xfd97a67a, 0xfd908192,
|
||||
0xfd8901f2, 0xfd812182, 0xfd78d98e, 0xfd7022bb, 0xfd66f4ed,
|
||||
0xfd5d4732, 0xfd530f9c, 0xfd48432b, 0xfd3cd59a, 0xfd30b936,
|
||||
0xfd23dea4, 0xfd16349e, 0xfd07a7a3, 0xfcf8219b, 0xfce7895b,
|
||||
0xfcd5c220, 0xfcc2aadb, 0xfcae1d5e, 0xfc97ed4e, 0xfc7fe6d4,
|
||||
0xfc65ccf3, 0xfc495762, 0xfc2a2fc8, 0xfc07ee19, 0xfbe213c1,
|
||||
0xfbb8051a, 0xfb890078, 0xfb5411a5, 0xfb180005, 0xfad33482,
|
||||
0xfa839276, 0xfa263b32, 0xf9b72d1c, 0xf930a1a2, 0xf889f023,
|
||||
0xf7b577d2, 0xf69c650c, 0xf51530f0, 0xf2cb0e3c, 0xeeefb15d,
|
||||
0xe6da6ecf,
|
||||
}
|
||||
var we = [256]float32{
|
||||
2.0249555e-09, 1.486674e-11, 2.4409617e-11, 3.1968806e-11,
|
||||
3.844677e-11, 4.4228204e-11, 4.9516443e-11, 5.443359e-11,
|
||||
5.905944e-11, 6.344942e-11, 6.7643814e-11, 7.1672945e-11,
|
||||
7.556032e-11, 7.932458e-11, 8.298079e-11, 8.654132e-11,
|
||||
9.0016515e-11, 9.3415074e-11, 9.674443e-11, 1.0001099e-10,
|
||||
1.03220314e-10, 1.06377254e-10, 1.09486115e-10, 1.1255068e-10,
|
||||
1.1557435e-10, 1.1856015e-10, 1.2151083e-10, 1.2442886e-10,
|
||||
1.2731648e-10, 1.3017575e-10, 1.3300853e-10, 1.3581657e-10,
|
||||
1.3860142e-10, 1.4136457e-10, 1.4410738e-10, 1.4683108e-10,
|
||||
1.4953687e-10, 1.5222583e-10, 1.54899e-10, 1.5755733e-10,
|
||||
1.6020171e-10, 1.6283301e-10, 1.6545203e-10, 1.6805951e-10,
|
||||
1.7065617e-10, 1.732427e-10, 1.7581973e-10, 1.7838787e-10,
|
||||
1.8094774e-10, 1.8349985e-10, 1.8604476e-10, 1.8858298e-10,
|
||||
1.9111498e-10, 1.9364126e-10, 1.9616223e-10, 1.9867835e-10,
|
||||
2.0119004e-10, 2.0369768e-10, 2.0620168e-10, 2.087024e-10,
|
||||
2.1120022e-10, 2.136955e-10, 2.1618855e-10, 2.1867974e-10,
|
||||
2.2116936e-10, 2.2365775e-10, 2.261452e-10, 2.2863202e-10,
|
||||
2.311185e-10, 2.3360494e-10, 2.360916e-10, 2.3857874e-10,
|
||||
2.4106667e-10, 2.4355562e-10, 2.4604588e-10, 2.485377e-10,
|
||||
2.5103128e-10, 2.5352695e-10, 2.560249e-10, 2.585254e-10,
|
||||
2.6102867e-10, 2.6353494e-10, 2.6604446e-10, 2.6855745e-10,
|
||||
2.7107416e-10, 2.7359479e-10, 2.761196e-10, 2.7864877e-10,
|
||||
2.8118255e-10, 2.8372119e-10, 2.8626485e-10, 2.888138e-10,
|
||||
2.9136826e-10, 2.939284e-10, 2.9649452e-10, 2.9906677e-10,
|
||||
3.016454e-10, 3.0423064e-10, 3.0682268e-10, 3.0942177e-10,
|
||||
3.1202813e-10, 3.1464195e-10, 3.1726352e-10, 3.19893e-10,
|
||||
3.2253064e-10, 3.251767e-10, 3.2783135e-10, 3.3049485e-10,
|
||||
3.3316744e-10, 3.3584938e-10, 3.3854083e-10, 3.4124212e-10,
|
||||
3.4395342e-10, 3.46675e-10, 3.4940711e-10, 3.5215003e-10,
|
||||
3.5490397e-10, 3.5766917e-10, 3.6044595e-10, 3.6323455e-10,
|
||||
3.660352e-10, 3.6884823e-10, 3.7167386e-10, 3.745124e-10,
|
||||
3.773641e-10, 3.802293e-10, 3.8310827e-10, 3.860013e-10,
|
||||
3.8890866e-10, 3.918307e-10, 3.9476775e-10, 3.9772008e-10,
|
||||
4.0068804e-10, 4.0367196e-10, 4.0667217e-10, 4.09689e-10,
|
||||
4.1272286e-10, 4.1577405e-10, 4.1884296e-10, 4.2192994e-10,
|
||||
4.250354e-10, 4.281597e-10, 4.313033e-10, 4.3446652e-10,
|
||||
4.3764986e-10, 4.408537e-10, 4.4407847e-10, 4.4732465e-10,
|
||||
4.5059267e-10, 4.5388301e-10, 4.571962e-10, 4.6053267e-10,
|
||||
4.6389292e-10, 4.6727755e-10, 4.70687e-10, 4.741219e-10,
|
||||
4.7758275e-10, 4.810702e-10, 4.845848e-10, 4.8812715e-10,
|
||||
4.9169796e-10, 4.9529775e-10, 4.989273e-10, 5.0258725e-10,
|
||||
5.0627835e-10, 5.100013e-10, 5.1375687e-10, 5.1754584e-10,
|
||||
5.21369e-10, 5.2522725e-10, 5.2912136e-10, 5.330522e-10,
|
||||
5.370208e-10, 5.4102806e-10, 5.45075e-10, 5.491625e-10,
|
||||
5.532918e-10, 5.5746385e-10, 5.616799e-10, 5.6594107e-10,
|
||||
5.7024857e-10, 5.746037e-10, 5.7900773e-10, 5.834621e-10,
|
||||
5.8796823e-10, 5.925276e-10, 5.971417e-10, 6.018122e-10,
|
||||
6.065408e-10, 6.113292e-10, 6.1617933e-10, 6.2109295e-10,
|
||||
6.260722e-10, 6.3111916e-10, 6.3623595e-10, 6.4142497e-10,
|
||||
6.4668854e-10, 6.5202926e-10, 6.5744976e-10, 6.6295286e-10,
|
||||
6.6854156e-10, 6.742188e-10, 6.79988e-10, 6.858526e-10,
|
||||
6.9181616e-10, 6.978826e-10, 7.04056e-10, 7.103407e-10,
|
||||
7.167412e-10, 7.2326256e-10, 7.2990985e-10, 7.366886e-10,
|
||||
7.4360473e-10, 7.5066453e-10, 7.5787476e-10, 7.6524265e-10,
|
||||
7.7277595e-10, 7.80483e-10, 7.883728e-10, 7.9645507e-10,
|
||||
8.047402e-10, 8.1323964e-10, 8.219657e-10, 8.309319e-10,
|
||||
8.401528e-10, 8.496445e-10, 8.594247e-10, 8.6951274e-10,
|
||||
8.799301e-10, 8.9070046e-10, 9.018503e-10, 9.134092e-10,
|
||||
9.254101e-10, 9.378904e-10, 9.508923e-10, 9.644638e-10,
|
||||
9.786603e-10, 9.935448e-10, 1.0091913e-09, 1.025686e-09,
|
||||
1.0431306e-09, 1.0616465e-09, 1.08138e-09, 1.1025096e-09,
|
||||
1.1252564e-09, 1.1498986e-09, 1.1767932e-09, 1.206409e-09,
|
||||
1.2393786e-09, 1.276585e-09, 1.3193139e-09, 1.3695435e-09,
|
||||
1.4305498e-09, 1.508365e-09, 1.6160854e-09, 1.7921248e-09,
|
||||
}
|
||||
var fe = [256]float32{
|
||||
1, 0.9381437, 0.90046996, 0.87170434, 0.8477855, 0.8269933,
|
||||
0.8084217, 0.7915276, 0.77595687, 0.7614634, 0.7478686,
|
||||
0.7350381, 0.72286767, 0.71127474, 0.70019263, 0.6895665,
|
||||
0.67935055, 0.6695063, 0.66000086, 0.65080583, 0.6418967,
|
||||
0.63325197, 0.6248527, 0.6166822, 0.60872537, 0.60096896,
|
||||
0.5934009, 0.58601034, 0.5787874, 0.57172304, 0.5648092,
|
||||
0.5580383, 0.5514034, 0.5448982, 0.5385169, 0.53225386,
|
||||
0.5261042, 0.52006316, 0.5141264, 0.50828975, 0.5025495,
|
||||
0.496902, 0.49134386, 0.485872, 0.48048335, 0.4751752,
|
||||
0.46994483, 0.46478975, 0.45970762, 0.45469615, 0.44975325,
|
||||
0.44487688, 0.44006512, 0.43531612, 0.43062815, 0.42599955,
|
||||
0.42142874, 0.4169142, 0.41245446, 0.40804818, 0.403694,
|
||||
0.3993907, 0.39513698, 0.39093173, 0.38677382, 0.38266218,
|
||||
0.37859577, 0.37457356, 0.37059465, 0.3666581, 0.362763,
|
||||
0.35890847, 0.35509375, 0.351318, 0.3475805, 0.34388044,
|
||||
0.34021714, 0.3365899, 0.33299807, 0.32944095, 0.32591796,
|
||||
0.3224285, 0.3189719, 0.31554767, 0.31215525, 0.30879408,
|
||||
0.3054636, 0.3021634, 0.29889292, 0.2956517, 0.29243928,
|
||||
0.28925523, 0.28609908, 0.28297043, 0.27986884, 0.27679393,
|
||||
0.2737453, 0.2707226, 0.2677254, 0.26475343, 0.26180625,
|
||||
0.25888354, 0.25598502, 0.2531103, 0.25025907, 0.24743107,
|
||||
0.24462597, 0.24184346, 0.23908329, 0.23634516, 0.23362878,
|
||||
0.23093392, 0.2282603, 0.22560766, 0.22297576, 0.22036438,
|
||||
0.21777324, 0.21520215, 0.21265087, 0.21011916, 0.20760682,
|
||||
0.20511365, 0.20263945, 0.20018397, 0.19774707, 0.19532852,
|
||||
0.19292815, 0.19054577, 0.1881812, 0.18583426, 0.18350479,
|
||||
0.1811926, 0.17889754, 0.17661946, 0.17435817, 0.17211354,
|
||||
0.1698854, 0.16767362, 0.16547804, 0.16329853, 0.16113494,
|
||||
0.15898713, 0.15685499, 0.15473837, 0.15263714, 0.15055119,
|
||||
0.14848037, 0.14642459, 0.14438373, 0.14235765, 0.14034624,
|
||||
0.13834943, 0.13636707, 0.13439907, 0.13244532, 0.13050574,
|
||||
0.1285802, 0.12666863, 0.12477092, 0.12288698, 0.12101672,
|
||||
0.119160056, 0.1173169, 0.115487166, 0.11367077, 0.11186763,
|
||||
0.11007768, 0.10830083, 0.10653701, 0.10478614, 0.10304816,
|
||||
0.101323, 0.09961058, 0.09791085, 0.09622374, 0.09454919,
|
||||
0.09288713, 0.091237515, 0.08960028, 0.087975375, 0.08636274,
|
||||
0.08476233, 0.083174095, 0.081597984, 0.08003395, 0.07848195,
|
||||
0.076941945, 0.07541389, 0.07389775, 0.072393484, 0.07090106,
|
||||
0.069420435, 0.06795159, 0.066494495, 0.06504912, 0.063615434,
|
||||
0.062193416, 0.060783047, 0.059384305, 0.057997175,
|
||||
0.05662164, 0.05525769, 0.053905312, 0.052564494, 0.051235236,
|
||||
0.049917534, 0.048611384, 0.047316793, 0.046033762, 0.0447623,
|
||||
0.043502413, 0.042254124, 0.041017443, 0.039792392,
|
||||
0.038578995, 0.037377283, 0.036187284, 0.035009038,
|
||||
0.033842582, 0.032687962, 0.031545233, 0.030414443, 0.02929566,
|
||||
0.02818895, 0.027094385, 0.026012046, 0.024942026, 0.023884421,
|
||||
0.022839336, 0.021806888, 0.020787204, 0.019780423, 0.0187867,
|
||||
0.0178062, 0.016839107, 0.015885621, 0.014945968, 0.014020392,
|
||||
0.013109165, 0.012212592, 0.011331013, 0.01046481, 0.009614414,
|
||||
0.008780315, 0.007963077, 0.0071633533, 0.006381906,
|
||||
0.0056196423, 0.0048776558, 0.004157295, 0.0034602648,
|
||||
0.0027887989, 0.0021459677, 0.0015362998, 0.0009672693,
|
||||
0.00045413437,
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
// Copyright 2009 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 rand
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
/*
|
||||
* Normal distribution
|
||||
*
|
||||
* See "The Ziggurat Method for Generating Random Variables"
|
||||
* (Marsaglia & Tsang, 2000)
|
||||
* http://www.jstatsoft.org/v05/i08/paper [pdf]
|
||||
*/
|
||||
|
||||
const (
|
||||
rn = 3.442619855899
|
||||
)
|
||||
|
||||
func absInt32(i int32) uint32 {
|
||||
if i < 0 {
|
||||
return uint32(-i)
|
||||
}
|
||||
return uint32(i)
|
||||
}
|
||||
|
||||
// NormFloat64 returns a normally distributed float64 in
|
||||
// the range -math.MaxFloat64 through +math.MaxFloat64 inclusive,
|
||||
// with standard normal distribution (mean = 0, stddev = 1).
|
||||
// To produce a different normal distribution, callers can
|
||||
// adjust the output using:
|
||||
//
|
||||
// sample = NormFloat64() * desiredStdDev + desiredMean
|
||||
func (r *Rand) NormFloat64() float64 {
|
||||
for {
|
||||
j := int32(r.Uint32()) // Possibly negative
|
||||
i := j & 0x7F
|
||||
x := float64(j) * float64(wn[i])
|
||||
if absInt32(j) < kn[i] {
|
||||
// This case should be hit better than 99% of the time.
|
||||
return x
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
// This extra work is only required for the base strip.
|
||||
for {
|
||||
x = -math.Log(r.Float64()) * (1.0 / rn)
|
||||
y := -math.Log(r.Float64())
|
||||
if y+y >= x*x {
|
||||
break
|
||||
}
|
||||
}
|
||||
if j > 0 {
|
||||
return rn + x
|
||||
}
|
||||
return -rn - x
|
||||
}
|
||||
if fn[i]+float32(r.Float64())*(fn[i-1]-fn[i]) < float32(math.Exp(-.5*x*x)) {
|
||||
return x
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var kn = [128]uint32{
|
||||
0x76ad2212, 0x0, 0x600f1b53, 0x6ce447a6, 0x725b46a2,
|
||||
0x7560051d, 0x774921eb, 0x789a25bd, 0x799045c3, 0x7a4bce5d,
|
||||
0x7adf629f, 0x7b5682a6, 0x7bb8a8c6, 0x7c0ae722, 0x7c50cce7,
|
||||
0x7c8cec5b, 0x7cc12cd6, 0x7ceefed2, 0x7d177e0b, 0x7d3b8883,
|
||||
0x7d5bce6c, 0x7d78dd64, 0x7d932886, 0x7dab0e57, 0x7dc0dd30,
|
||||
0x7dd4d688, 0x7de73185, 0x7df81cea, 0x7e07c0a3, 0x7e163efa,
|
||||
0x7e23b587, 0x7e303dfd, 0x7e3beec2, 0x7e46db77, 0x7e51155d,
|
||||
0x7e5aabb3, 0x7e63abf7, 0x7e6c222c, 0x7e741906, 0x7e7b9a18,
|
||||
0x7e82adfa, 0x7e895c63, 0x7e8fac4b, 0x7e95a3fb, 0x7e9b4924,
|
||||
0x7ea0a0ef, 0x7ea5b00d, 0x7eaa7ac3, 0x7eaf04f3, 0x7eb3522a,
|
||||
0x7eb765a5, 0x7ebb4259, 0x7ebeeafd, 0x7ec2620a, 0x7ec5a9c4,
|
||||
0x7ec8c441, 0x7ecbb365, 0x7ece78ed, 0x7ed11671, 0x7ed38d62,
|
||||
0x7ed5df12, 0x7ed80cb4, 0x7eda175c, 0x7edc0005, 0x7eddc78e,
|
||||
0x7edf6ebf, 0x7ee0f647, 0x7ee25ebe, 0x7ee3a8a9, 0x7ee4d473,
|
||||
0x7ee5e276, 0x7ee6d2f5, 0x7ee7a620, 0x7ee85c10, 0x7ee8f4cd,
|
||||
0x7ee97047, 0x7ee9ce59, 0x7eea0eca, 0x7eea3147, 0x7eea3568,
|
||||
0x7eea1aab, 0x7ee9e071, 0x7ee98602, 0x7ee90a88, 0x7ee86d08,
|
||||
0x7ee7ac6a, 0x7ee6c769, 0x7ee5bc9c, 0x7ee48a67, 0x7ee32efc,
|
||||
0x7ee1a857, 0x7edff42f, 0x7ede0ffa, 0x7edbf8d9, 0x7ed9ab94,
|
||||
0x7ed7248d, 0x7ed45fae, 0x7ed1585c, 0x7ece095f, 0x7eca6ccb,
|
||||
0x7ec67be2, 0x7ec22eee, 0x7ebd7d1a, 0x7eb85c35, 0x7eb2c075,
|
||||
0x7eac9c20, 0x7ea5df27, 0x7e9e769f, 0x7e964c16, 0x7e8d44ba,
|
||||
0x7e834033, 0x7e781728, 0x7e6b9933, 0x7e5d8a1a, 0x7e4d9ded,
|
||||
0x7e3b737a, 0x7e268c2f, 0x7e0e3ff5, 0x7df1aa5d, 0x7dcf8c72,
|
||||
0x7da61a1e, 0x7d72a0fb, 0x7d30e097, 0x7cd9b4ab, 0x7c600f1a,
|
||||
0x7ba90bdc, 0x7a722176, 0x77d664e5,
|
||||
}
|
||||
var wn = [128]float32{
|
||||
1.7290405e-09, 1.2680929e-10, 1.6897518e-10, 1.9862688e-10,
|
||||
2.2232431e-10, 2.4244937e-10, 2.601613e-10, 2.7611988e-10,
|
||||
2.9073963e-10, 3.042997e-10, 3.1699796e-10, 3.289802e-10,
|
||||
3.4035738e-10, 3.5121603e-10, 3.616251e-10, 3.7164058e-10,
|
||||
3.8130857e-10, 3.9066758e-10, 3.9975012e-10, 4.08584e-10,
|
||||
4.1719309e-10, 4.2559822e-10, 4.338176e-10, 4.418672e-10,
|
||||
4.497613e-10, 4.5751258e-10, 4.651324e-10, 4.7263105e-10,
|
||||
4.8001775e-10, 4.87301e-10, 4.944885e-10, 5.015873e-10,
|
||||
5.0860405e-10, 5.155446e-10, 5.2241467e-10, 5.2921934e-10,
|
||||
5.359635e-10, 5.426517e-10, 5.4928817e-10, 5.5587696e-10,
|
||||
5.624219e-10, 5.6892646e-10, 5.753941e-10, 5.818282e-10,
|
||||
5.882317e-10, 5.946077e-10, 6.00959e-10, 6.072884e-10,
|
||||
6.135985e-10, 6.19892e-10, 6.2617134e-10, 6.3243905e-10,
|
||||
6.386974e-10, 6.449488e-10, 6.511956e-10, 6.5744005e-10,
|
||||
6.6368433e-10, 6.699307e-10, 6.7618144e-10, 6.824387e-10,
|
||||
6.8870465e-10, 6.949815e-10, 7.012715e-10, 7.075768e-10,
|
||||
7.1389966e-10, 7.202424e-10, 7.266073e-10, 7.329966e-10,
|
||||
7.394128e-10, 7.4585826e-10, 7.5233547e-10, 7.58847e-10,
|
||||
7.653954e-10, 7.719835e-10, 7.7861395e-10, 7.852897e-10,
|
||||
7.920138e-10, 7.987892e-10, 8.0561924e-10, 8.125073e-10,
|
||||
8.194569e-10, 8.2647167e-10, 8.3355556e-10, 8.407127e-10,
|
||||
8.479473e-10, 8.55264e-10, 8.6266755e-10, 8.7016316e-10,
|
||||
8.777562e-10, 8.8545243e-10, 8.932582e-10, 9.0117996e-10,
|
||||
9.09225e-10, 9.174008e-10, 9.2571584e-10, 9.341788e-10,
|
||||
9.427997e-10, 9.515889e-10, 9.605579e-10, 9.697193e-10,
|
||||
9.790869e-10, 9.88676e-10, 9.985036e-10, 1.0085882e-09,
|
||||
1.0189509e-09, 1.0296151e-09, 1.0406069e-09, 1.0519566e-09,
|
||||
1.063698e-09, 1.0758702e-09, 1.0885183e-09, 1.1016947e-09,
|
||||
1.1154611e-09, 1.1298902e-09, 1.1450696e-09, 1.1611052e-09,
|
||||
1.1781276e-09, 1.1962995e-09, 1.2158287e-09, 1.2369856e-09,
|
||||
1.2601323e-09, 1.2857697e-09, 1.3146202e-09, 1.347784e-09,
|
||||
1.3870636e-09, 1.4357403e-09, 1.5008659e-09, 1.6030948e-09,
|
||||
}
|
||||
var fn = [128]float32{
|
||||
1, 0.9635997, 0.9362827, 0.9130436, 0.89228165, 0.87324303,
|
||||
0.8555006, 0.8387836, 0.8229072, 0.8077383, 0.793177,
|
||||
0.7791461, 0.7655842, 0.7524416, 0.73967725, 0.7272569,
|
||||
0.7151515, 0.7033361, 0.69178915, 0.68049186, 0.6694277,
|
||||
0.658582, 0.6479418, 0.63749546, 0.6272325, 0.6171434,
|
||||
0.6072195, 0.5974532, 0.58783704, 0.5783647, 0.56903,
|
||||
0.5598274, 0.5507518, 0.54179835, 0.5329627, 0.52424055,
|
||||
0.5156282, 0.50712204, 0.49871865, 0.49041483, 0.48220766,
|
||||
0.4740943, 0.46607214, 0.4581387, 0.45029163, 0.44252872,
|
||||
0.43484783, 0.427247, 0.41972435, 0.41227803, 0.40490642,
|
||||
0.39760786, 0.3903808, 0.3832238, 0.37613547, 0.36911446,
|
||||
0.3621595, 0.35526937, 0.34844297, 0.34167916, 0.33497685,
|
||||
0.3283351, 0.3217529, 0.3152294, 0.30876362, 0.30235484,
|
||||
0.29600215, 0.28970486, 0.2834622, 0.2772735, 0.27113807,
|
||||
0.2650553, 0.25902456, 0.2530453, 0.24711695, 0.241239,
|
||||
0.23541094, 0.22963232, 0.2239027, 0.21822165, 0.21258877,
|
||||
0.20700371, 0.20146611, 0.19597565, 0.19053204, 0.18513499,
|
||||
0.17978427, 0.17447963, 0.1692209, 0.16400786, 0.15884037,
|
||||
0.15371831, 0.14864157, 0.14361008, 0.13862377, 0.13368265,
|
||||
0.12878671, 0.12393598, 0.119130544, 0.11437051, 0.10965602,
|
||||
0.104987256, 0.10036444, 0.095787846, 0.0912578, 0.08677467,
|
||||
0.0823389, 0.077950984, 0.073611505, 0.06932112, 0.06508058,
|
||||
0.06089077, 0.056752663, 0.0526674, 0.048636295, 0.044660863,
|
||||
0.040742867, 0.03688439, 0.033087887, 0.029356318,
|
||||
0.025693292, 0.022103304, 0.018592102, 0.015167298,
|
||||
0.011839478, 0.008624485, 0.005548995, 0.0026696292,
|
||||
}
|
||||
@@ -1,547 +0,0 @@
|
||||
// Copyright 2009 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 rand implements pseudo-random number generators suitable for tasks
|
||||
// such as simulation, but it should not be used for security-sensitive work.
|
||||
//
|
||||
// Random numbers are generated by a [Source], usually wrapped in a [Rand].
|
||||
// Both types should be used by a single goroutine at a time: sharing among
|
||||
// multiple goroutines requires some kind of synchronization.
|
||||
//
|
||||
// Top-level functions, such as [Float64] and [Int],
|
||||
// are safe for concurrent use by multiple goroutines.
|
||||
//
|
||||
// This package's outputs might be easily predictable regardless of how it's
|
||||
// seeded. For random numbers suitable for security-sensitive work, see the
|
||||
// crypto/rand package.
|
||||
package rand
|
||||
|
||||
// llgo:skipall
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
_ "unsafe" // for go:linkname
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/math/rand"
|
||||
"github.com/goplus/llgo/c/time"
|
||||
)
|
||||
|
||||
// A Source represents a source of uniformly-distributed
|
||||
// pseudo-random int64 values in the range [0, 1<<63).
|
||||
//
|
||||
// A Source is not safe for concurrent use by multiple goroutines.
|
||||
type Source interface {
|
||||
Int63() int64
|
||||
Seed(seed int64)
|
||||
}
|
||||
|
||||
// A Source64 is a Source that can also generate
|
||||
// uniformly-distributed pseudo-random uint64 values in
|
||||
// the range [0, 1<<64) directly.
|
||||
// If a Rand r's underlying Source s implements Source64,
|
||||
// then r.Uint64 returns the result of one call to s.Uint64
|
||||
// instead of making two calls to s.Int63.
|
||||
type Source64 interface {
|
||||
Source
|
||||
Uint64() uint64
|
||||
}
|
||||
|
||||
// NewSource returns a new pseudo-random Source seeded with the given value.
|
||||
// Unlike the default Source used by top-level functions, this source is not
|
||||
// safe for concurrent use by multiple goroutines.
|
||||
// The returned Source implements Source64.
|
||||
func NewSource(seed int64) Source {
|
||||
return newSource(seed)
|
||||
}
|
||||
|
||||
func newSource(seed int64) *rngSource {
|
||||
var rng rngSource
|
||||
rng.Seed(seed)
|
||||
return &rng
|
||||
}
|
||||
|
||||
// A Rand is a source of random numbers.
|
||||
type Rand struct {
|
||||
src Source
|
||||
s64 Source64 // non-nil if src is source64
|
||||
|
||||
// readVal contains remainder of 63-bit integer used for bytes
|
||||
// generation during most recent Read call.
|
||||
// It is saved so next Read call can start where the previous
|
||||
// one finished.
|
||||
readVal int64
|
||||
// readPos indicates the number of low-order bytes of readVal
|
||||
// that are still valid.
|
||||
readPos int8
|
||||
}
|
||||
|
||||
// New returns a new Rand that uses random values from src
|
||||
// to generate other random values.
|
||||
func New(src Source) *Rand {
|
||||
s64, _ := src.(Source64)
|
||||
return &Rand{src: src, s64: s64}
|
||||
}
|
||||
|
||||
// Seed uses the provided seed value to initialize the generator to a deterministic state.
|
||||
// Seed should not be called concurrently with any other Rand method.
|
||||
func (r *Rand) Seed(seed int64) {
|
||||
if lk, ok := r.src.(*lockedSource); ok {
|
||||
lk.seedPos(seed, &r.readPos)
|
||||
return
|
||||
}
|
||||
|
||||
r.src.Seed(seed)
|
||||
r.readPos = 0
|
||||
}
|
||||
|
||||
// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
|
||||
func (r *Rand) Int63() int64 { return r.src.Int63() }
|
||||
|
||||
// Uint32 returns a pseudo-random 32-bit value as a uint32.
|
||||
func (r *Rand) Uint32() uint32 { return uint32(r.Int63() >> 31) }
|
||||
|
||||
// Uint64 returns a pseudo-random 64-bit value as a uint64.
|
||||
func (r *Rand) Uint64() uint64 {
|
||||
if r.s64 != nil {
|
||||
return r.s64.Uint64()
|
||||
}
|
||||
return uint64(r.Int63())>>31 | uint64(r.Int63())<<32
|
||||
}
|
||||
|
||||
// Int31 returns a non-negative pseudo-random 31-bit integer as an int32.
|
||||
func (r *Rand) Int31() int32 { return int32(r.Int63() >> 32) }
|
||||
|
||||
// Int returns a non-negative pseudo-random int.
|
||||
func (r *Rand) Int() int {
|
||||
u := uint(r.Int63())
|
||||
return int(u << 1 >> 1) // clear sign bit if int == int32
|
||||
}
|
||||
|
||||
// Int63n returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n).
|
||||
// It panics if n <= 0.
|
||||
func (r *Rand) Int63n(n int64) int64 {
|
||||
if n <= 0 {
|
||||
panic("invalid argument to Int63n")
|
||||
}
|
||||
if n&(n-1) == 0 { // n is power of two, can mask
|
||||
return r.Int63() & (n - 1)
|
||||
}
|
||||
max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
|
||||
v := r.Int63()
|
||||
for v > max {
|
||||
v = r.Int63()
|
||||
}
|
||||
return v % n
|
||||
}
|
||||
|
||||
// Int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n).
|
||||
// It panics if n <= 0.
|
||||
func (r *Rand) Int31n(n int32) int32 {
|
||||
if n <= 0 {
|
||||
panic("invalid argument to Int31n")
|
||||
}
|
||||
if n&(n-1) == 0 { // n is power of two, can mask
|
||||
return r.Int31() & (n - 1)
|
||||
}
|
||||
max := int32((1 << 31) - 1 - (1<<31)%uint32(n))
|
||||
v := r.Int31()
|
||||
for v > max {
|
||||
v = r.Int31()
|
||||
}
|
||||
return v % n
|
||||
}
|
||||
|
||||
// int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n).
|
||||
// n must be > 0, but int31n does not check this; the caller must ensure it.
|
||||
// int31n exists because Int31n is inefficient, but Go 1 compatibility
|
||||
// requires that the stream of values produced by math/rand remain unchanged.
|
||||
// int31n can thus only be used internally, by newly introduced APIs.
|
||||
//
|
||||
// For implementation details, see:
|
||||
// https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction
|
||||
// https://lemire.me/blog/2016/06/30/fast-random-shuffling
|
||||
func (r *Rand) int31n(n int32) int32 {
|
||||
v := r.Uint32()
|
||||
prod := uint64(v) * uint64(n)
|
||||
low := uint32(prod)
|
||||
if low < uint32(n) {
|
||||
thresh := uint32(-n) % uint32(n)
|
||||
for low < thresh {
|
||||
v = r.Uint32()
|
||||
prod = uint64(v) * uint64(n)
|
||||
low = uint32(prod)
|
||||
}
|
||||
}
|
||||
return int32(prod >> 32)
|
||||
}
|
||||
|
||||
// Intn returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n).
|
||||
// It panics if n <= 0.
|
||||
func (r *Rand) Intn(n int) int {
|
||||
if n <= 0 {
|
||||
panic("invalid argument to Intn")
|
||||
}
|
||||
if n <= 1<<31-1 {
|
||||
return int(r.Int31n(int32(n)))
|
||||
}
|
||||
return int(r.Int63n(int64(n)))
|
||||
}
|
||||
|
||||
// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0).
|
||||
func (r *Rand) Float64() float64 {
|
||||
// A clearer, simpler implementation would be:
|
||||
// return float64(r.Int63n(1<<53)) / (1<<53)
|
||||
// However, Go 1 shipped with
|
||||
// return float64(r.Int63()) / (1 << 63)
|
||||
// and we want to preserve that value stream.
|
||||
//
|
||||
// There is one bug in the value stream: r.Int63() may be so close
|
||||
// to 1<<63 that the division rounds up to 1.0, and we've guaranteed
|
||||
// that the result is always less than 1.0.
|
||||
//
|
||||
// We tried to fix this by mapping 1.0 back to 0.0, but since float64
|
||||
// values near 0 are much denser than near 1, mapping 1 to 0 caused
|
||||
// a theoretically significant overshoot in the probability of returning 0.
|
||||
// Instead of that, if we round up to 1, just try again.
|
||||
// Getting 1 only happens 1/2⁵³ of the time, so most clients
|
||||
// will not observe it anyway.
|
||||
again:
|
||||
f := float64(r.Int63()) / (1 << 63)
|
||||
if f == 1 {
|
||||
goto again // resample; this branch is taken O(never)
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0).
|
||||
func (r *Rand) Float32() float32 {
|
||||
// Same rationale as in Float64: we want to preserve the Go 1 value
|
||||
// stream except we want to fix it not to return 1.0
|
||||
// This only happens 1/2²⁴ of the time (plus the 1/2⁵³ of the time in Float64).
|
||||
again:
|
||||
f := float32(r.Float64())
|
||||
if f == 1 {
|
||||
goto again // resample; this branch is taken O(very rarely)
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers
|
||||
// in the half-open interval [0,n).
|
||||
func (r *Rand) Perm(n int) []int {
|
||||
m := make([]int, n)
|
||||
// In the following loop, the iteration when i=0 always swaps m[0] with m[0].
|
||||
// A change to remove this useless iteration is to assign 1 to i in the init
|
||||
// statement. But Perm also effects r. Making this change will affect
|
||||
// the final state of r. So this change can't be made for compatibility
|
||||
// reasons for Go 1.
|
||||
for i := 0; i < n; i++ {
|
||||
j := r.Intn(i + 1)
|
||||
m[i] = m[j]
|
||||
m[j] = i
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// Shuffle pseudo-randomizes the order of elements.
|
||||
// n is the number of elements. Shuffle panics if n < 0.
|
||||
// swap swaps the elements with indexes i and j.
|
||||
func (r *Rand) Shuffle(n int, swap func(i, j int)) {
|
||||
if n < 0 {
|
||||
panic("invalid argument to Shuffle")
|
||||
}
|
||||
|
||||
// Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
|
||||
// Shuffle really ought not be called with n that doesn't fit in 32 bits.
|
||||
// Not only will it take a very long time, but with 2³¹! possible permutations,
|
||||
// there's no way that any PRNG can have a big enough internal state to
|
||||
// generate even a minuscule percentage of the possible permutations.
|
||||
// Nevertheless, the right API signature accepts an int n, so handle it as best we can.
|
||||
i := n - 1
|
||||
for ; i > 1<<31-1-1; i-- {
|
||||
j := int(r.Int63n(int64(i + 1)))
|
||||
swap(i, j)
|
||||
}
|
||||
for ; i > 0; i-- {
|
||||
j := int(r.int31n(int32(i + 1)))
|
||||
swap(i, j)
|
||||
}
|
||||
}
|
||||
|
||||
// Read generates len(p) random bytes and writes them into p. It
|
||||
// always returns len(p) and a nil error.
|
||||
// Read should not be called concurrently with any other Rand method.
|
||||
func (r *Rand) Read(p []byte) (n int, err error) {
|
||||
switch src := r.src.(type) {
|
||||
case *lockedSource:
|
||||
return src.read(p, &r.readVal, &r.readPos)
|
||||
case *fastSource:
|
||||
return src.read(p, &r.readVal, &r.readPos)
|
||||
}
|
||||
return read(p, r.src, &r.readVal, &r.readPos)
|
||||
}
|
||||
|
||||
func read(p []byte, src Source, readVal *int64, readPos *int8) (n int, err error) {
|
||||
pos := *readPos
|
||||
val := *readVal
|
||||
rng, _ := src.(*rngSource)
|
||||
for n = 0; n < len(p); n++ {
|
||||
if pos == 0 {
|
||||
if rng != nil {
|
||||
val = rng.Int63()
|
||||
} else {
|
||||
val = src.Int63()
|
||||
}
|
||||
pos = 7
|
||||
}
|
||||
p[n] = byte(val)
|
||||
val >>= 8
|
||||
pos--
|
||||
}
|
||||
*readPos = pos
|
||||
*readVal = val
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
* Top-level convenience functions
|
||||
*/
|
||||
|
||||
// globalRandGenerator is the source of random numbers for the top-level
|
||||
// convenience functions. When possible it uses the runtime fastrand64
|
||||
// function to avoid locking. This is not possible if the user called Seed,
|
||||
// either explicitly or implicitly via GODEBUG=randautoseed=0.
|
||||
var globalRandGenerator atomic.Pointer[Rand]
|
||||
|
||||
// globalRand returns the generator to use for the top-level convenience
|
||||
// functions.
|
||||
func globalRand() *Rand {
|
||||
if r := globalRandGenerator.Load(); r != nil {
|
||||
return r
|
||||
}
|
||||
|
||||
// This is the first call. Initialize based on GODEBUG.
|
||||
var r = &Rand{
|
||||
src: &fastSource{},
|
||||
s64: &fastSource{},
|
||||
}
|
||||
if !globalRandGenerator.CompareAndSwap(nil, r) {
|
||||
// Two different goroutines called some top-level
|
||||
// function at the same time. While the results in
|
||||
// that case are unpredictable, if we just use r here,
|
||||
// and we are using a seed, we will most likely return
|
||||
// the same value for both calls. That doesn't seem ideal.
|
||||
// Just use the first one to get in.
|
||||
return globalRandGenerator.Load()
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func fastrand64() uint64 {
|
||||
v1 := uint64(rand.Random())
|
||||
v2 := uint64(rand.Random())
|
||||
return v1 ^ (v2 << 32)
|
||||
}
|
||||
|
||||
func init() {
|
||||
rand.Srandom(c.Uint(time.Time(nil)))
|
||||
}
|
||||
|
||||
// fastSource is an implementation of Source64 that uses the runtime
|
||||
// fastrand functions.
|
||||
type fastSource struct {
|
||||
// The mutex is used to avoid race conditions in Read.
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func (*fastSource) Int63() int64 {
|
||||
return int64(fastrand64() & rngMask)
|
||||
}
|
||||
|
||||
func (*fastSource) Seed(int64) {
|
||||
panic("internal error: call to fastSource.Seed")
|
||||
}
|
||||
|
||||
func (*fastSource) Uint64() uint64 {
|
||||
return fastrand64()
|
||||
}
|
||||
|
||||
func (fs *fastSource) read(p []byte, readVal *int64, readPos *int8) (n int, err error) {
|
||||
fs.mu.Lock()
|
||||
n, err = read(p, fs, readVal, readPos)
|
||||
fs.mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// Seed uses the provided seed value to initialize the default Source to a
|
||||
// deterministic state. Seed values that have the same remainder when
|
||||
// divided by 2³¹-1 generate the same pseudo-random sequence.
|
||||
// Seed, unlike the Rand.Seed method, is safe for concurrent use.
|
||||
//
|
||||
// If Seed is not called, the generator is seeded randomly at program startup.
|
||||
//
|
||||
// Prior to Go 1.20, the generator was seeded like Seed(1) at program startup.
|
||||
// To force the old behavior, call Seed(1) at program startup.
|
||||
// Alternately, set GODEBUG=randautoseed=0 in the environment
|
||||
// before making any calls to functions in this package.
|
||||
//
|
||||
// Deprecated: As of Go 1.20 there is no reason to call Seed with
|
||||
// a random value. Programs that call Seed with a known value to get
|
||||
// a specific sequence of results should use New(NewSource(seed)) to
|
||||
// obtain a local random generator.
|
||||
func Seed(seed int64) {
|
||||
orig := globalRandGenerator.Load()
|
||||
|
||||
// If we are already using a lockedSource, we can just re-seed it.
|
||||
if orig != nil {
|
||||
if _, ok := orig.src.(*lockedSource); ok {
|
||||
orig.Seed(seed)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise either
|
||||
// 1) orig == nil, which is the normal case when Seed is the first
|
||||
// top-level function to be called, or
|
||||
// 2) orig is already a fastSource, in which case we need to change
|
||||
// to a lockedSource.
|
||||
// Either way we do the same thing.
|
||||
|
||||
r := New(new(lockedSource))
|
||||
r.Seed(seed)
|
||||
|
||||
if !globalRandGenerator.CompareAndSwap(orig, r) {
|
||||
// Something changed underfoot. Retry to be safe.
|
||||
Seed(seed)
|
||||
}
|
||||
}
|
||||
|
||||
// Int63 returns a non-negative pseudo-random 63-bit integer as an int64
|
||||
// from the default Source.
|
||||
func Int63() int64 { return globalRand().Int63() }
|
||||
|
||||
// Uint32 returns a pseudo-random 32-bit value as a uint32
|
||||
// from the default Source.
|
||||
func Uint32() uint32 { return globalRand().Uint32() }
|
||||
|
||||
// Uint64 returns a pseudo-random 64-bit value as a uint64
|
||||
// from the default Source.
|
||||
func Uint64() uint64 { return globalRand().Uint64() }
|
||||
|
||||
// Int31 returns a non-negative pseudo-random 31-bit integer as an int32
|
||||
// from the default Source.
|
||||
func Int31() int32 { return globalRand().Int31() }
|
||||
|
||||
// Int returns a non-negative pseudo-random int from the default Source.
|
||||
func Int() int { return globalRand().Int() }
|
||||
|
||||
// Int63n returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n)
|
||||
// from the default Source.
|
||||
// It panics if n <= 0.
|
||||
func Int63n(n int64) int64 { return globalRand().Int63n(n) }
|
||||
|
||||
// Int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n)
|
||||
// from the default Source.
|
||||
// It panics if n <= 0.
|
||||
func Int31n(n int32) int32 { return globalRand().Int31n(n) }
|
||||
|
||||
// Intn returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n)
|
||||
// from the default Source.
|
||||
// It panics if n <= 0.
|
||||
func Intn(n int) int { return globalRand().Intn(n) }
|
||||
|
||||
// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0)
|
||||
// from the default Source.
|
||||
func Float64() float64 { return globalRand().Float64() }
|
||||
|
||||
// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0)
|
||||
// from the default Source.
|
||||
func Float32() float32 { return globalRand().Float32() }
|
||||
|
||||
// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers
|
||||
// in the half-open interval [0,n) from the default Source.
|
||||
func Perm(n int) []int { return globalRand().Perm(n) }
|
||||
|
||||
// Shuffle pseudo-randomizes the order of elements using the default Source.
|
||||
// n is the number of elements. Shuffle panics if n < 0.
|
||||
// swap swaps the elements with indexes i and j.
|
||||
func Shuffle(n int, swap func(i, j int)) { globalRand().Shuffle(n, swap) }
|
||||
|
||||
// Read generates len(p) random bytes from the default Source and
|
||||
// writes them into p. It always returns len(p) and a nil error.
|
||||
// Read, unlike the Rand.Read method, is safe for concurrent use.
|
||||
//
|
||||
// Deprecated: For almost all use cases, crypto/rand.Read is more appropriate.
|
||||
func Read(p []byte) (n int, err error) { return globalRand().Read(p) }
|
||||
|
||||
// NormFloat64 returns a normally distributed float64 in the range
|
||||
// [-math.MaxFloat64, +math.MaxFloat64] with
|
||||
// standard normal distribution (mean = 0, stddev = 1)
|
||||
// from the default Source.
|
||||
// To produce a different normal distribution, callers can
|
||||
// adjust the output using:
|
||||
//
|
||||
// sample = NormFloat64() * desiredStdDev + desiredMean
|
||||
func NormFloat64() float64 { return globalRand().NormFloat64() }
|
||||
|
||||
// ExpFloat64 returns an exponentially distributed float64 in the range
|
||||
// (0, +math.MaxFloat64] with an exponential distribution whose rate parameter
|
||||
// (lambda) is 1 and whose mean is 1/lambda (1) from the default Source.
|
||||
// To produce a distribution with a different rate parameter,
|
||||
// callers can adjust the output using:
|
||||
//
|
||||
// sample = ExpFloat64() / desiredRateParameter
|
||||
func ExpFloat64() float64 { return globalRand().ExpFloat64() }
|
||||
|
||||
type lockedSource struct {
|
||||
lk sync.Mutex
|
||||
s *rngSource
|
||||
}
|
||||
|
||||
func (r *lockedSource) Int63() (n int64) {
|
||||
r.lk.Lock()
|
||||
n = r.s.Int63()
|
||||
r.lk.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (r *lockedSource) Uint64() (n uint64) {
|
||||
r.lk.Lock()
|
||||
n = r.s.Uint64()
|
||||
r.lk.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (r *lockedSource) Seed(seed int64) {
|
||||
r.lk.Lock()
|
||||
r.seed(seed)
|
||||
r.lk.Unlock()
|
||||
}
|
||||
|
||||
// seedPos implements Seed for a lockedSource without a race condition.
|
||||
func (r *lockedSource) seedPos(seed int64, readPos *int8) {
|
||||
r.lk.Lock()
|
||||
r.seed(seed)
|
||||
*readPos = 0
|
||||
r.lk.Unlock()
|
||||
}
|
||||
|
||||
// seed seeds the underlying source.
|
||||
// The caller must have locked r.lk.
|
||||
func (r *lockedSource) seed(seed int64) {
|
||||
if r.s == nil {
|
||||
r.s = newSource(seed)
|
||||
} else {
|
||||
r.s.Seed(seed)
|
||||
}
|
||||
}
|
||||
|
||||
// read implements Read for a lockedSource without a race condition.
|
||||
func (r *lockedSource) read(p []byte, readVal *int64, readPos *int8) (n int, err error) {
|
||||
r.lk.Lock()
|
||||
n, err = read(p, r.s, readVal, readPos)
|
||||
r.lk.Unlock()
|
||||
return
|
||||
}
|
||||
@@ -1,252 +0,0 @@
|
||||
// Copyright 2009 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 rand
|
||||
|
||||
/*
|
||||
* Uniform distribution
|
||||
*
|
||||
* algorithm by
|
||||
* DP Mitchell and JA Reeds
|
||||
*/
|
||||
|
||||
const (
|
||||
rngLen = 607
|
||||
rngTap = 273
|
||||
rngMax = 1 << 63
|
||||
rngMask = rngMax - 1
|
||||
int32max = (1 << 31) - 1
|
||||
)
|
||||
|
||||
var (
|
||||
// rngCooked used for seeding. See gen_cooked.go for details.
|
||||
rngCooked [rngLen]int64 = [...]int64{
|
||||
-4181792142133755926, -4576982950128230565, 1395769623340756751, 5333664234075297259,
|
||||
-6347679516498800754, 9033628115061424579, 7143218595135194537, 4812947590706362721,
|
||||
7937252194349799378, 5307299880338848416, 8209348851763925077, -7107630437535961764,
|
||||
4593015457530856296, 8140875735541888011, -5903942795589686782, -603556388664454774,
|
||||
-7496297993371156308, 113108499721038619, 4569519971459345583, -4160538177779461077,
|
||||
-6835753265595711384, -6507240692498089696, 6559392774825876886, 7650093201692370310,
|
||||
7684323884043752161, -8965504200858744418, -2629915517445760644, 271327514973697897,
|
||||
-6433985589514657524, 1065192797246149621, 3344507881999356393, -4763574095074709175,
|
||||
7465081662728599889, 1014950805555097187, -4773931307508785033, -5742262670416273165,
|
||||
2418672789110888383, 5796562887576294778, 4484266064449540171, 3738982361971787048,
|
||||
-4699774852342421385, 10530508058128498, -589538253572429690, -6598062107225984180,
|
||||
8660405965245884302, 10162832508971942, -2682657355892958417, 7031802312784620857,
|
||||
6240911277345944669, 831864355460801054, -1218937899312622917, 2116287251661052151,
|
||||
2202309800992166967, 9161020366945053561, 4069299552407763864, 4936383537992622449,
|
||||
457351505131524928, -8881176990926596454, -6375600354038175299, -7155351920868399290,
|
||||
4368649989588021065, 887231587095185257, -3659780529968199312, -2407146836602825512,
|
||||
5616972787034086048, -751562733459939242, 1686575021641186857, -5177887698780513806,
|
||||
-4979215821652996885, -1375154703071198421, 5632136521049761902, -8390088894796940536,
|
||||
-193645528485698615, -5979788902190688516, -4907000935050298721, -285522056888777828,
|
||||
-2776431630044341707, 1679342092332374735, 6050638460742422078, -2229851317345194226,
|
||||
-1582494184340482199, 5881353426285907985, 812786550756860885, 4541845584483343330,
|
||||
-6497901820577766722, 4980675660146853729, -4012602956251539747, -329088717864244987,
|
||||
-2896929232104691526, 1495812843684243920, -2153620458055647789, 7370257291860230865,
|
||||
-2466442761497833547, 4706794511633873654, -1398851569026877145, 8549875090542453214,
|
||||
-9189721207376179652, -7894453601103453165, 7297902601803624459, 1011190183918857495,
|
||||
-6985347000036920864, 5147159997473910359, -8326859945294252826, 2659470849286379941,
|
||||
6097729358393448602, -7491646050550022124, -5117116194870963097, -896216826133240300,
|
||||
-745860416168701406, 5803876044675762232, -787954255994554146, -3234519180203704564,
|
||||
-4507534739750823898, -1657200065590290694, 505808562678895611, -4153273856159712438,
|
||||
-8381261370078904295, 572156825025677802, 1791881013492340891, 3393267094866038768,
|
||||
-5444650186382539299, 2352769483186201278, -7930912453007408350, -325464993179687389,
|
||||
-3441562999710612272, -6489413242825283295, 5092019688680754699, -227247482082248967,
|
||||
4234737173186232084, 5027558287275472836, 4635198586344772304, -536033143587636457,
|
||||
5907508150730407386, -8438615781380831356, 972392927514829904, -3801314342046600696,
|
||||
-4064951393885491917, -174840358296132583, 2407211146698877100, -1640089820333676239,
|
||||
3940796514530962282, -5882197405809569433, 3095313889586102949, -1818050141166537098,
|
||||
5832080132947175283, 7890064875145919662, 8184139210799583195, -8073512175445549678,
|
||||
-7758774793014564506, -4581724029666783935, 3516491885471466898, -8267083515063118116,
|
||||
6657089965014657519, 5220884358887979358, 1796677326474620641, 5340761970648932916,
|
||||
1147977171614181568, 5066037465548252321, 2574765911837859848, 1085848279845204775,
|
||||
-5873264506986385449, 6116438694366558490, 2107701075971293812, -7420077970933506541,
|
||||
2469478054175558874, -1855128755834809824, -5431463669011098282, -9038325065738319171,
|
||||
-6966276280341336160, 7217693971077460129, -8314322083775271549, 7196649268545224266,
|
||||
-3585711691453906209, -5267827091426810625, 8057528650917418961, -5084103596553648165,
|
||||
-2601445448341207749, -7850010900052094367, 6527366231383600011, 3507654575162700890,
|
||||
9202058512774729859, 1954818376891585542, -2582991129724600103, 8299563319178235687,
|
||||
-5321504681635821435, 7046310742295574065, -2376176645520785576, -7650733936335907755,
|
||||
8850422670118399721, 3631909142291992901, 5158881091950831288, -6340413719511654215,
|
||||
4763258931815816403, 6280052734341785344, -4979582628649810958, 2043464728020827976,
|
||||
-2678071570832690343, 4562580375758598164, 5495451168795427352, -7485059175264624713,
|
||||
553004618757816492, 6895160632757959823, -989748114590090637, 7139506338801360852,
|
||||
-672480814466784139, 5535668688139305547, 2430933853350256242, -3821430778991574732,
|
||||
-1063731997747047009, -3065878205254005442, 7632066283658143750, 6308328381617103346,
|
||||
3681878764086140361, 3289686137190109749, 6587997200611086848, 244714774258135476,
|
||||
-5143583659437639708, 8090302575944624335, 2945117363431356361, -8359047641006034763,
|
||||
3009039260312620700, -793344576772241777, 401084700045993341, -1968749590416080887,
|
||||
4707864159563588614, -3583123505891281857, -3240864324164777915, -5908273794572565703,
|
||||
-3719524458082857382, -5281400669679581926, 8118566580304798074, 3839261274019871296,
|
||||
7062410411742090847, -8481991033874568140, 6027994129690250817, -6725542042704711878,
|
||||
-2971981702428546974, -7854441788951256975, 8809096399316380241, 6492004350391900708,
|
||||
2462145737463489636, -8818543617934476634, -5070345602623085213, -8961586321599299868,
|
||||
-3758656652254704451, -8630661632476012791, 6764129236657751224, -709716318315418359,
|
||||
-3403028373052861600, -8838073512170985897, -3999237033416576341, -2920240395515973663,
|
||||
-2073249475545404416, 368107899140673753, -6108185202296464250, -6307735683270494757,
|
||||
4782583894627718279, 6718292300699989587, 8387085186914375220, 3387513132024756289,
|
||||
4654329375432538231, -292704475491394206, -3848998599978456535, 7623042350483453954,
|
||||
7725442901813263321, 9186225467561587250, -5132344747257272453, -6865740430362196008,
|
||||
2530936820058611833, 1636551876240043639, -3658707362519810009, 1452244145334316253,
|
||||
-7161729655835084979, -7943791770359481772, 9108481583171221009, -3200093350120725999,
|
||||
5007630032676973346, 2153168792952589781, 6720334534964750538, -3181825545719981703,
|
||||
3433922409283786309, 2285479922797300912, 3110614940896576130, -2856812446131932915,
|
||||
-3804580617188639299, 7163298419643543757, 4891138053923696990, 580618510277907015,
|
||||
1684034065251686769, 4429514767357295841, -8893025458299325803, -8103734041042601133,
|
||||
7177515271653460134, 4589042248470800257, -1530083407795771245, 143607045258444228,
|
||||
246994305896273627, -8356954712051676521, 6473547110565816071, 3092379936208876896,
|
||||
2058427839513754051, -4089587328327907870, 8785882556301281247, -3074039370013608197,
|
||||
-637529855400303673, 6137678347805511274, -7152924852417805802, 5708223427705576541,
|
||||
-3223714144396531304, 4358391411789012426, 325123008708389849, 6837621693887290924,
|
||||
4843721905315627004, -3212720814705499393, -3825019837890901156, 4602025990114250980,
|
||||
1044646352569048800, 9106614159853161675, -8394115921626182539, -4304087667751778808,
|
||||
2681532557646850893, 3681559472488511871, -3915372517896561773, -2889241648411946534,
|
||||
-6564663803938238204, -8060058171802589521, 581945337509520675, 3648778920718647903,
|
||||
-4799698790548231394, -7602572252857820065, 220828013409515943, -1072987336855386047,
|
||||
4287360518296753003, -4633371852008891965, 5513660857261085186, -2258542936462001533,
|
||||
-8744380348503999773, 8746140185685648781, 228500091334420247, 1356187007457302238,
|
||||
3019253992034194581, 3152601605678500003, -8793219284148773595, 5559581553696971176,
|
||||
4916432985369275664, -8559797105120221417, -5802598197927043732, 2868348622579915573,
|
||||
-7224052902810357288, -5894682518218493085, 2587672709781371173, -7706116723325376475,
|
||||
3092343956317362483, -5561119517847711700, 972445599196498113, -1558506600978816441,
|
||||
1708913533482282562, -2305554874185907314, -6005743014309462908, -6653329009633068701,
|
||||
-483583197311151195, 2488075924621352812, -4529369641467339140, -4663743555056261452,
|
||||
2997203966153298104, 1282559373026354493, 240113143146674385, 8665713329246516443,
|
||||
628141331766346752, -4651421219668005332, -7750560848702540400, 7596648026010355826,
|
||||
-3132152619100351065, 7834161864828164065, 7103445518877254909, 4390861237357459201,
|
||||
-4780718172614204074, -319889632007444440, 622261699494173647, -3186110786557562560,
|
||||
-8718967088789066690, -1948156510637662747, -8212195255998774408, -7028621931231314745,
|
||||
2623071828615234808, -4066058308780939700, -5484966924888173764, -6683604512778046238,
|
||||
-6756087640505506466, 5256026990536851868, 7841086888628396109, 6640857538655893162,
|
||||
-8021284697816458310, -7109857044414059830, -1689021141511844405, -4298087301956291063,
|
||||
-4077748265377282003, -998231156719803476, 2719520354384050532, 9132346697815513771,
|
||||
4332154495710163773, -2085582442760428892, 6994721091344268833, -2556143461985726874,
|
||||
-8567931991128098309, 59934747298466858, -3098398008776739403, -265597256199410390,
|
||||
2332206071942466437, -7522315324568406181, 3154897383618636503, -7585605855467168281,
|
||||
-6762850759087199275, 197309393502684135, -8579694182469508493, 2543179307861934850,
|
||||
4350769010207485119, -4468719947444108136, -7207776534213261296, -1224312577878317200,
|
||||
4287946071480840813, 8362686366770308971, 6486469209321732151, -5605644191012979782,
|
||||
-1669018511020473564, 4450022655153542367, -7618176296641240059, -3896357471549267421,
|
||||
-4596796223304447488, -6531150016257070659, -8982326463137525940, -4125325062227681798,
|
||||
-1306489741394045544, -8338554946557245229, 5329160409530630596, 7790979528857726136,
|
||||
4955070238059373407, -4304834761432101506, -6215295852904371179, 3007769226071157901,
|
||||
-6753025801236972788, 8928702772696731736, 7856187920214445904, -4748497451462800923,
|
||||
7900176660600710914, -7082800908938549136, -6797926979589575837, -6737316883512927978,
|
||||
4186670094382025798, 1883939007446035042, -414705992779907823, 3734134241178479257,
|
||||
4065968871360089196, 6953124200385847784, -7917685222115876751, -7585632937840318161,
|
||||
-5567246375906782599, -5256612402221608788, 3106378204088556331, -2894472214076325998,
|
||||
4565385105440252958, 1979884289539493806, -6891578849933910383, 3783206694208922581,
|
||||
8464961209802336085, 2843963751609577687, 3030678195484896323, -4429654462759003204,
|
||||
4459239494808162889, 402587895800087237, 8057891408711167515, 4541888170938985079,
|
||||
1042662272908816815, -3666068979732206850, 2647678726283249984, 2144477441549833761,
|
||||
-3417019821499388721, -2105601033380872185, 5916597177708541638, -8760774321402454447,
|
||||
8833658097025758785, 5970273481425315300, 563813119381731307, -6455022486202078793,
|
||||
1598828206250873866, -4016978389451217698, -2988328551145513985, -6071154634840136312,
|
||||
8469693267274066490, 125672920241807416, -3912292412830714870, -2559617104544284221,
|
||||
-486523741806024092, -4735332261862713930, 5923302823487327109, -9082480245771672572,
|
||||
-1808429243461201518, 7990420780896957397, 4317817392807076702, 3625184369705367340,
|
||||
-6482649271566653105, -3480272027152017464, -3225473396345736649, -368878695502291645,
|
||||
-3981164001421868007, -8522033136963788610, 7609280429197514109, 3020985755112334161,
|
||||
-2572049329799262942, 2635195723621160615, 5144520864246028816, -8188285521126945980,
|
||||
1567242097116389047, 8172389260191636581, -2885551685425483535, -7060359469858316883,
|
||||
-6480181133964513127, -7317004403633452381, 6011544915663598137, 5932255307352610768,
|
||||
2241128460406315459, -8327867140638080220, 3094483003111372717, 4583857460292963101,
|
||||
9079887171656594975, -384082854924064405, -3460631649611717935, 4225072055348026230,
|
||||
-7385151438465742745, 3801620336801580414, -399845416774701952, -7446754431269675473,
|
||||
7899055018877642622, 5421679761463003041, 5521102963086275121, -4975092593295409910,
|
||||
8735487530905098534, -7462844945281082830, -2080886987197029914, -1000715163927557685,
|
||||
-4253840471931071485, -5828896094657903328, 6424174453260338141, 359248545074932887,
|
||||
-5949720754023045210, -2426265837057637212, 3030918217665093212, -9077771202237461772,
|
||||
-3186796180789149575, 740416251634527158, -2142944401404840226, 6951781370868335478,
|
||||
399922722363687927, -8928469722407522623, -1378421100515597285, -8343051178220066766,
|
||||
-3030716356046100229, -8811767350470065420, 9026808440365124461, 6440783557497587732,
|
||||
4615674634722404292, 539897290441580544, 2096238225866883852, 8751955639408182687,
|
||||
-7316147128802486205, 7381039757301768559, 6157238513393239656, -1473377804940618233,
|
||||
8629571604380892756, 5280433031239081479, 7101611890139813254, 2479018537985767835,
|
||||
7169176924412769570, -1281305539061572506, -7865612307799218120, 2278447439451174845,
|
||||
3625338785743880657, 6477479539006708521, 8976185375579272206, -3712000482142939688,
|
||||
1326024180520890843, 7537449876596048829, 5464680203499696154, 3189671183162196045,
|
||||
6346751753565857109, -8982212049534145501, -6127578587196093755, -245039190118465649,
|
||||
-6320577374581628592, 7208698530190629697, 7276901792339343736, -7490986807540332668,
|
||||
4133292154170828382, 2918308698224194548, -7703910638917631350, -3929437324238184044,
|
||||
-4300543082831323144, -6344160503358350167, 5896236396443472108, -758328221503023383,
|
||||
-1894351639983151068, -307900319840287220, -6278469401177312761, -2171292963361310674,
|
||||
8382142935188824023, 9103922860780351547, 4152330101494654406,
|
||||
}
|
||||
)
|
||||
|
||||
type rngSource struct {
|
||||
tap int // index into vec
|
||||
feed int // index into vec
|
||||
vec [rngLen]int64 // current feedback register
|
||||
}
|
||||
|
||||
// seed rng x[n+1] = 48271 * x[n] mod (2**31 - 1)
|
||||
func seedrand(x int32) int32 {
|
||||
const (
|
||||
A = 48271
|
||||
Q = 44488
|
||||
R = 3399
|
||||
)
|
||||
|
||||
hi := x / Q
|
||||
lo := x % Q
|
||||
x = A*lo - R*hi
|
||||
if x < 0 {
|
||||
x += int32max
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// Seed uses the provided seed value to initialize the generator to a deterministic state.
|
||||
func (rng *rngSource) Seed(seed int64) {
|
||||
rng.tap = 0
|
||||
rng.feed = rngLen - rngTap
|
||||
|
||||
seed = seed % int32max
|
||||
if seed < 0 {
|
||||
seed += int32max
|
||||
}
|
||||
if seed == 0 {
|
||||
seed = 89482311
|
||||
}
|
||||
|
||||
x := int32(seed)
|
||||
for i := -20; i < rngLen; i++ {
|
||||
x = seedrand(x)
|
||||
if i >= 0 {
|
||||
var u int64
|
||||
u = int64(x) << 40
|
||||
x = seedrand(x)
|
||||
u ^= int64(x) << 20
|
||||
x = seedrand(x)
|
||||
u ^= int64(x)
|
||||
u ^= rngCooked[i]
|
||||
rng.vec[i] = u
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
|
||||
func (rng *rngSource) Int63() int64 {
|
||||
return int64(rng.Uint64() & rngMask)
|
||||
}
|
||||
|
||||
// Uint64 returns a non-negative pseudo-random 64-bit integer as a uint64.
|
||||
func (rng *rngSource) Uint64() uint64 {
|
||||
rng.tap--
|
||||
if rng.tap < 0 {
|
||||
rng.tap += rngLen
|
||||
}
|
||||
|
||||
rng.feed--
|
||||
if rng.feed < 0 {
|
||||
rng.feed += rngLen
|
||||
}
|
||||
|
||||
x := rng.vec[rng.feed] + rng.vec[rng.tap]
|
||||
rng.vec[rng.feed] = x
|
||||
return uint64(x)
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// W.Hormann, G.Derflinger:
|
||||
// "Rejection-Inversion to Generate Variates
|
||||
// from Monotone Discrete Distributions"
|
||||
// http://eeyore.wu-wien.ac.at/papers/96-04-04.wh-der.ps.gz
|
||||
|
||||
package rand
|
||||
|
||||
import "math"
|
||||
|
||||
// A Zipf generates Zipf distributed variates.
|
||||
type Zipf struct {
|
||||
r *Rand
|
||||
imax float64
|
||||
v float64
|
||||
q float64
|
||||
s float64
|
||||
oneminusQ float64
|
||||
oneminusQinv float64
|
||||
hxm float64
|
||||
hx0minusHxm float64
|
||||
}
|
||||
|
||||
func (z *Zipf) h(x float64) float64 {
|
||||
return math.Exp(z.oneminusQ*math.Log(z.v+x)) * z.oneminusQinv
|
||||
}
|
||||
|
||||
func (z *Zipf) hinv(x float64) float64 {
|
||||
return math.Exp(z.oneminusQinv*math.Log(z.oneminusQ*x)) - z.v
|
||||
}
|
||||
|
||||
// NewZipf returns a Zipf variate generator.
|
||||
// The generator generates values k ∈ [0, imax]
|
||||
// such that P(k) is proportional to (v + k) ** (-s).
|
||||
// Requirements: s > 1 and v >= 1.
|
||||
func NewZipf(r *Rand, s float64, v float64, imax uint64) *Zipf {
|
||||
z := new(Zipf)
|
||||
if s <= 1.0 || v < 1 {
|
||||
return nil
|
||||
}
|
||||
z.r = r
|
||||
z.imax = float64(imax)
|
||||
z.v = v
|
||||
z.q = s
|
||||
z.oneminusQ = 1.0 - z.q
|
||||
z.oneminusQinv = 1.0 / z.oneminusQ
|
||||
z.hxm = z.h(z.imax + 0.5)
|
||||
z.hx0minusHxm = z.h(0.5) - math.Exp(math.Log(z.v)*(-z.q)) - z.hxm
|
||||
z.s = 1 - z.hinv(z.h(1.5)-math.Exp(-z.q*math.Log(z.v+1.0)))
|
||||
return z
|
||||
}
|
||||
|
||||
// Uint64 returns a value drawn from the Zipf distribution described
|
||||
// by the Zipf object.
|
||||
func (z *Zipf) Uint64() uint64 {
|
||||
if z == nil {
|
||||
panic("rand: nil Zipf")
|
||||
}
|
||||
k := 0.0
|
||||
|
||||
for {
|
||||
r := z.r.Float64() // r on [0,1]
|
||||
ur := z.hxm + r*z.hx0minusHxm
|
||||
x := z.hinv(ur)
|
||||
k = math.Floor(x + 0.5)
|
||||
if k-x <= z.s {
|
||||
break
|
||||
}
|
||||
if ur >= z.h(k+0.5)-math.Exp(-math.Log(k+z.v)*z.q) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return uint64(k)
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
// Copyright 2010 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.
|
||||
|
||||
// General environment variables.
|
||||
|
||||
package os
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Expand replaces ${var} or $var in the string based on the mapping function.
|
||||
// For example, os.ExpandEnv(s) is equivalent to os.Expand(s, os.Getenv).
|
||||
func Expand(s string, mapping func(string) string) string {
|
||||
var buf []byte
|
||||
// ${} is all ASCII, so bytes are fine for this operation.
|
||||
i := 0
|
||||
for j := 0; j < len(s); j++ {
|
||||
if s[j] == '$' && j+1 < len(s) {
|
||||
if buf == nil {
|
||||
buf = make([]byte, 0, 2*len(s))
|
||||
}
|
||||
buf = append(buf, s[i:j]...)
|
||||
name, w := getShellName(s[j+1:])
|
||||
if name == "" && w > 0 {
|
||||
// Encountered invalid syntax; eat the
|
||||
// characters.
|
||||
} else if name == "" {
|
||||
// Valid syntax, but $ was not followed by a
|
||||
// name. Leave the dollar character untouched.
|
||||
buf = append(buf, s[j])
|
||||
} else {
|
||||
buf = append(buf, mapping(name)...)
|
||||
}
|
||||
j += w
|
||||
i = j + 1
|
||||
}
|
||||
}
|
||||
if buf == nil {
|
||||
return s
|
||||
}
|
||||
return string(buf) + s[i:]
|
||||
}
|
||||
|
||||
// ExpandEnv replaces ${var} or $var in the string according to the values
|
||||
// of the current environment variables. References to undefined
|
||||
// variables are replaced by the empty string.
|
||||
func ExpandEnv(s string) string {
|
||||
return Expand(s, Getenv)
|
||||
}
|
||||
|
||||
// isShellSpecialVar reports whether the character identifies a special
|
||||
// shell variable such as $*.
|
||||
func isShellSpecialVar(c uint8) bool {
|
||||
switch c {
|
||||
case '*', '#', '$', '@', '!', '?', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isAlphaNum reports whether the byte is an ASCII letter, number, or underscore.
|
||||
func isAlphaNum(c uint8) bool {
|
||||
return c == '_' || '0' <= c && c <= '9' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
|
||||
}
|
||||
|
||||
// getShellName returns the name that begins the string and the number of bytes
|
||||
// consumed to extract it. If the name is enclosed in {}, it's part of a ${}
|
||||
// expansion and two more bytes are needed than the length of the name.
|
||||
func getShellName(s string) (string, int) {
|
||||
switch {
|
||||
case s[0] == '{':
|
||||
if len(s) > 2 && isShellSpecialVar(s[1]) && s[2] == '}' {
|
||||
return s[1:2], 3
|
||||
}
|
||||
// Scan to closing brace
|
||||
for i := 1; i < len(s); i++ {
|
||||
if s[i] == '}' {
|
||||
if i == 1 {
|
||||
return "", 2 // Bad syntax; eat "${}"
|
||||
}
|
||||
return s[1:i], i + 1
|
||||
}
|
||||
}
|
||||
return "", 1 // Bad syntax; eat "${"
|
||||
case isShellSpecialVar(s[0]):
|
||||
return s[0:1], 1
|
||||
}
|
||||
// Scan alphanumerics.
|
||||
var i int
|
||||
for i = 0; i < len(s) && isAlphaNum(s[i]); i++ {
|
||||
}
|
||||
return s[:i], i
|
||||
}
|
||||
|
||||
// Getenv retrieves the value of the environment variable named by the key.
|
||||
// It returns the value, which will be empty if the variable is not present.
|
||||
// To distinguish between an empty value and an unset value, use LookupEnv.
|
||||
func Getenv(key string) string {
|
||||
v, _ := syscall.Getenv(key)
|
||||
return v
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
func Getenv(key string) string {
|
||||
return c.GoString(os.Getenv(c.AllocaCStr(key)))
|
||||
}
|
||||
*/
|
||||
|
||||
// LookupEnv retrieves the value of the environment variable named
|
||||
// by the key. If the variable is present in the environment the
|
||||
// value (which may be empty) is returned and the boolean is true.
|
||||
// Otherwise the returned value will be empty and the boolean will
|
||||
// be false.
|
||||
func LookupEnv(key string) (string, bool) {
|
||||
return syscall.Getenv(key)
|
||||
}
|
||||
|
||||
// Setenv sets the value of the environment variable named by the key.
|
||||
// It returns an error, if any.
|
||||
func Setenv(key, value string) error {
|
||||
err := syscall.Setenv(key, value)
|
||||
if err != nil {
|
||||
return NewSyscallError("setenv", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
func Setenv(key, value string) error {
|
||||
ret := os.Setenv(c.AllocaCStr(key), c.AllocaCStr(value), 1)
|
||||
if ret == 0 {
|
||||
return nil
|
||||
}
|
||||
return &SyscallError{"setenv", syscall.Errno(ret)}
|
||||
}
|
||||
*/
|
||||
|
||||
// Unsetenv unsets a single environment variable.
|
||||
func Unsetenv(key string) error {
|
||||
return syscall.Unsetenv(key)
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
func Unsetenv(key string) error {
|
||||
ret := os.Unsetenv(c.AllocaCStr(key))
|
||||
if ret == 0 {
|
||||
return nil
|
||||
}
|
||||
return syscall.Errno(ret)
|
||||
}
|
||||
*/
|
||||
|
||||
// Environ returns a copy of strings representing the environment,
|
||||
// in the form "key=value".
|
||||
func Environ() []string {
|
||||
return syscall.Environ()
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
// Copyright 2009 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 os
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Portable analogs of some common system call errors.
|
||||
//
|
||||
// Errors returned from this package may be tested against these errors
|
||||
// with errors.Is.
|
||||
var (
|
||||
// ErrInvalid indicates an invalid argument.
|
||||
// Methods on File will return this error when the receiver is nil.
|
||||
ErrInvalid = fs.ErrInvalid // "invalid argument"
|
||||
|
||||
ErrPermission = fs.ErrPermission // "permission denied"
|
||||
ErrExist = fs.ErrExist // "file already exists"
|
||||
ErrNotExist = fs.ErrNotExist // "file does not exist"
|
||||
ErrClosed = fs.ErrClosed // "file already closed"
|
||||
|
||||
// TODO(xsw):
|
||||
// ErrNoDeadline = errNoDeadline() // "file type does not support deadline"
|
||||
// ErrDeadlineExceeded = errDeadlineExceeded() // "i/o timeout"
|
||||
)
|
||||
|
||||
// func errNoDeadline() error { return poll.ErrNoDeadline }
|
||||
|
||||
// errDeadlineExceeded returns the value for os.ErrDeadlineExceeded.
|
||||
// This error comes from the internal/poll package, which is also
|
||||
// used by package net. Doing it this way ensures that the net
|
||||
// package will return os.ErrDeadlineExceeded for an exceeded deadline,
|
||||
// as documented by net.Conn.SetDeadline, without requiring any extra
|
||||
// work in the net package and without requiring the internal/poll
|
||||
// package to import os (which it can't, because that would be circular).
|
||||
// func errDeadlineExceeded() error { return poll.ErrDeadlineExceeded }
|
||||
|
||||
type timeout interface {
|
||||
Timeout() bool
|
||||
}
|
||||
|
||||
// PathError records an error and the operation and file path that caused it.
|
||||
type PathError = fs.PathError
|
||||
|
||||
// SyscallError records an error from a specific system call.
|
||||
type SyscallError struct {
|
||||
Syscall string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *SyscallError) Error() string { return e.Syscall + ": " + e.Err.Error() }
|
||||
|
||||
func (e *SyscallError) Unwrap() error { return e.Err }
|
||||
|
||||
// Timeout reports whether this error represents a timeout.
|
||||
func (e *SyscallError) Timeout() bool {
|
||||
t, ok := e.Err.(timeout)
|
||||
return ok && t.Timeout()
|
||||
}
|
||||
|
||||
// NewSyscallError returns, as an error, a new SyscallError
|
||||
// with the given system call name and error details.
|
||||
// As a convenience, if err is nil, NewSyscallError returns nil.
|
||||
func NewSyscallError(syscall string, err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &SyscallError{syscall, err}
|
||||
}
|
||||
|
||||
// IsExist returns a boolean indicating whether the error is known to report
|
||||
// that a file or directory already exists. It is satisfied by ErrExist as
|
||||
// well as some syscall errors.
|
||||
//
|
||||
// This function predates errors.Is. It only supports errors returned by
|
||||
// the os package. New code should use errors.Is(err, fs.ErrExist).
|
||||
func IsExist(err error) bool {
|
||||
return underlyingErrorIs(err, ErrExist)
|
||||
}
|
||||
|
||||
// IsNotExist returns a boolean indicating whether the error is known to
|
||||
// report that a file or directory does not exist. It is satisfied by
|
||||
// ErrNotExist as well as some syscall errors.
|
||||
//
|
||||
// This function predates errors.Is. It only supports errors returned by
|
||||
// the os package. New code should use errors.Is(err, fs.ErrNotExist).
|
||||
func IsNotExist(err error) bool {
|
||||
return underlyingErrorIs(err, ErrNotExist)
|
||||
}
|
||||
|
||||
// IsPermission returns a boolean indicating whether the error is known to
|
||||
// report that permission is denied. It is satisfied by ErrPermission as well
|
||||
// as some syscall errors.
|
||||
//
|
||||
// This function predates errors.Is. It only supports errors returned by
|
||||
// the os package. New code should use errors.Is(err, fs.ErrPermission).
|
||||
func IsPermission(err error) bool {
|
||||
return underlyingErrorIs(err, ErrPermission)
|
||||
}
|
||||
|
||||
// IsTimeout returns a boolean indicating whether the error is known
|
||||
// to report that a timeout occurred.
|
||||
//
|
||||
// This function predates errors.Is, and the notion of whether an
|
||||
// error indicates a timeout can be ambiguous. For example, the Unix
|
||||
// error EWOULDBLOCK sometimes indicates a timeout and sometimes does not.
|
||||
// New code should use errors.Is with a value appropriate to the call
|
||||
// returning the error, such as os.ErrDeadlineExceeded.
|
||||
func IsTimeout(err error) bool {
|
||||
terr, ok := underlyingError(err).(timeout)
|
||||
return ok && terr.Timeout()
|
||||
}
|
||||
|
||||
type syscallErrorType = syscall.Errno
|
||||
|
||||
func underlyingErrorIs(err, target error) bool {
|
||||
// Note that this function is not errors.Is:
|
||||
// underlyingError only unwraps the specific error-wrapping types
|
||||
// that it historically did, not all errors implementing Unwrap().
|
||||
err = underlyingError(err)
|
||||
if err == target {
|
||||
return true
|
||||
}
|
||||
// To preserve prior behavior, only examine syscall errors.
|
||||
e, ok := err.(syscallErrorType)
|
||||
return ok && e.Is(target)
|
||||
}
|
||||
|
||||
// underlyingError returns the underlying error for known os error types.
|
||||
func underlyingError(err error) error {
|
||||
switch err := err.(type) {
|
||||
case *PathError:
|
||||
return err.Err
|
||||
case *LinkError:
|
||||
return err.Err
|
||||
case *SyscallError:
|
||||
return err.Err
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
// Copyright 2009 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 os
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ErrProcessDone indicates a Process has finished.
|
||||
var ErrProcessDone = errors.New("os: process already finished")
|
||||
|
||||
// Process stores the information about a process created by StartProcess.
|
||||
type Process struct {
|
||||
Pid int
|
||||
handle uintptr // handle is accessed atomically on Windows
|
||||
isdone atomic.Bool // process has been successfully waited on
|
||||
sigMu sync.RWMutex // avoid race between wait and signal
|
||||
}
|
||||
|
||||
func newProcess(pid int, handle uintptr) *Process {
|
||||
p := &Process{Pid: pid, handle: handle}
|
||||
runtime.SetFinalizer(p, (*Process).Release)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *Process) setDone() {
|
||||
p.isdone.Store(true)
|
||||
}
|
||||
|
||||
func (p *Process) done() bool {
|
||||
return p.isdone.Load()
|
||||
}
|
||||
|
||||
// ProcAttr holds the attributes that will be applied to a new process
|
||||
// started by StartProcess.
|
||||
type ProcAttr struct {
|
||||
// If Dir is non-empty, the child changes into the directory before
|
||||
// creating the process.
|
||||
Dir string
|
||||
// If Env is non-nil, it gives the environment variables for the
|
||||
// new process in the form returned by Environ.
|
||||
// If it is nil, the result of Environ will be used.
|
||||
Env []string
|
||||
// Files specifies the open files inherited by the new process. The
|
||||
// first three entries correspond to standard input, standard output, and
|
||||
// standard error. An implementation may support additional entries,
|
||||
// depending on the underlying operating system. A nil entry corresponds
|
||||
// to that file being closed when the process starts.
|
||||
// On Unix systems, StartProcess will change these File values
|
||||
// to blocking mode, which means that SetDeadline will stop working
|
||||
// and calling Close will not interrupt a Read or Write.
|
||||
Files []*File
|
||||
|
||||
// Operating system-specific process creation attributes.
|
||||
// Note that setting this field means that your program
|
||||
// may not execute properly or even compile on some
|
||||
// operating systems.
|
||||
Sys *syscall.SysProcAttr
|
||||
}
|
||||
|
||||
// A Signal represents an operating system signal.
|
||||
// The usual underlying implementation is operating system-dependent:
|
||||
// on Unix it is syscall.Signal.
|
||||
type Signal interface {
|
||||
String() string
|
||||
Signal() // to distinguish from other Stringers
|
||||
}
|
||||
|
||||
// FindProcess looks for a running process by its pid.
|
||||
//
|
||||
// The Process it returns can be used to obtain information
|
||||
// about the underlying operating system process.
|
||||
//
|
||||
// On Unix systems, FindProcess always succeeds and returns a Process
|
||||
// for the given pid, regardless of whether the process exists. To test whether
|
||||
// the process actually exists, see whether p.Signal(syscall.Signal(0)) reports
|
||||
// an error.
|
||||
func FindProcess(pid int) (*Process, error) {
|
||||
return findProcess(pid)
|
||||
}
|
||||
|
||||
// StartProcess starts a new process with the program, arguments and attributes
|
||||
// specified by name, argv and attr. The argv slice will become os.Args in the
|
||||
// new process, so it normally starts with the program name.
|
||||
//
|
||||
// If the calling goroutine has locked the operating system thread
|
||||
// with runtime.LockOSThread and modified any inheritable OS-level
|
||||
// thread state (for example, Linux or Plan 9 name spaces), the new
|
||||
// process will inherit the caller's thread state.
|
||||
//
|
||||
// StartProcess is a low-level interface. The os/exec package provides
|
||||
// higher-level interfaces.
|
||||
//
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) {
|
||||
return startProcess(name, argv, attr)
|
||||
}
|
||||
|
||||
// Release releases any resources associated with the Process p,
|
||||
// rendering it unusable in the future.
|
||||
// Release only needs to be called if Wait is not.
|
||||
func (p *Process) Release() error {
|
||||
return p.release()
|
||||
}
|
||||
|
||||
// Kill causes the Process to exit immediately. Kill does not wait until
|
||||
// the Process has actually exited. This only kills the Process itself,
|
||||
// not any other processes it may have started.
|
||||
func (p *Process) Kill() error {
|
||||
return p.kill()
|
||||
}
|
||||
|
||||
// Wait waits for the Process to exit, and then returns a
|
||||
// ProcessState describing its status and an error, if any.
|
||||
// Wait releases any resources associated with the Process.
|
||||
// On most operating systems, the Process must be a child
|
||||
// of the current process or an error will be returned.
|
||||
func (p *Process) Wait() (*ProcessState, error) {
|
||||
return p.wait()
|
||||
}
|
||||
|
||||
// Signal sends a signal to the Process.
|
||||
// Sending Interrupt on Windows is not implemented.
|
||||
func (p *Process) Signal(sig Signal) error {
|
||||
return p.signal(sig)
|
||||
}
|
||||
|
||||
// UserTime returns the user CPU time of the exited process and its children.
|
||||
func (p *ProcessState) UserTime() time.Duration {
|
||||
return p.userTime()
|
||||
}
|
||||
|
||||
// SystemTime returns the system CPU time of the exited process and its children.
|
||||
func (p *ProcessState) SystemTime() time.Duration {
|
||||
return p.systemTime()
|
||||
}
|
||||
|
||||
// Exited reports whether the program has exited.
|
||||
// On Unix systems this reports true if the program exited due to calling exit,
|
||||
// but false if the program terminated due to a signal.
|
||||
func (p *ProcessState) Exited() bool {
|
||||
return p.exited()
|
||||
}
|
||||
|
||||
// Success reports whether the program exited successfully,
|
||||
// such as with exit status 0 on Unix.
|
||||
func (p *ProcessState) Success() bool {
|
||||
return p.success()
|
||||
}
|
||||
|
||||
// Sys returns system-dependent exit information about
|
||||
// the process. Convert it to the appropriate underlying
|
||||
// type, such as syscall.WaitStatus on Unix, to access its contents.
|
||||
func (p *ProcessState) Sys() any {
|
||||
return p.sys()
|
||||
}
|
||||
|
||||
// SysUsage returns system-dependent resource usage information about
|
||||
// the exited process. Convert it to the appropriate underlying
|
||||
// type, such as *syscall.Rusage on Unix, to access its contents.
|
||||
// (On Unix, *syscall.Rusage matches struct rusage as defined in the
|
||||
// getrusage(2) manual page.)
|
||||
func (p *ProcessState) SysUsage() any {
|
||||
return p.sysUsage()
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,19 +0,0 @@
|
||||
// Copyright 2019 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 exec
|
||||
|
||||
import "io/fs"
|
||||
|
||||
// skipStdinCopyError optionally specifies a function which reports
|
||||
// whether the provided stdin copy error should be ignored.
|
||||
func skipStdinCopyError(err error) bool {
|
||||
// Ignore hungup errors copying to stdin if the program
|
||||
// completed successfully otherwise.
|
||||
// See Issue 35753.
|
||||
pe, ok := err.(*fs.PathError)
|
||||
return ok &&
|
||||
pe.Op == "write" && pe.Path == "|1" &&
|
||||
pe.Err.Error() == "i/o on hungup channel"
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
//go:build !plan9 && !windows
|
||||
|
||||
package exec
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// skipStdinCopyError optionally specifies a function which reports
|
||||
// whether the provided stdin copy error should be ignored.
|
||||
func skipStdinCopyError(err error) bool {
|
||||
// Ignore EPIPE errors copying to stdin if the program
|
||||
// completed successfully otherwise.
|
||||
// See Issue 9173.
|
||||
pe, ok := err.(*fs.PathError)
|
||||
return ok &&
|
||||
pe.Op == "write" && pe.Path == "|1" &&
|
||||
pe.Err == syscall.EPIPE
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Copyright 2017 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 exec
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// skipStdinCopyError optionally specifies a function which reports
|
||||
// whether the provided stdin copy error should be ignored.
|
||||
func skipStdinCopyError(err error) bool {
|
||||
// Ignore ERROR_BROKEN_PIPE and ERROR_NO_DATA errors copying
|
||||
// to stdin if the program completed successfully otherwise.
|
||||
// See Issue 20445.
|
||||
const _ERROR_NO_DATA = syscall.Errno(0xe8)
|
||||
pe, ok := err.(*fs.PathError)
|
||||
return ok &&
|
||||
pe.Op == "write" && pe.Path == "|1" &&
|
||||
(pe.Err == syscall.ERROR_BROKEN_PIPE || pe.Err == _ERROR_NO_DATA)
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
// Copyright 2011 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 exec
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ErrNotFound is the error resulting if a path search failed to find an executable file.
|
||||
var ErrNotFound = errors.New("executable file not found in $path")
|
||||
|
||||
func findExecutable(file string) error {
|
||||
d, err := os.Stat(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if m := d.Mode(); !m.IsDir() && m&0111 != 0 {
|
||||
return nil
|
||||
}
|
||||
return fs.ErrPermission
|
||||
}
|
||||
|
||||
// LookPath searches for an executable named file in the
|
||||
// directories named by the path environment variable.
|
||||
// If file begins with "/", "#", "./", or "../", it is tried
|
||||
// directly and the path is not consulted.
|
||||
// On success, the result is an absolute path.
|
||||
//
|
||||
// In older versions of Go, LookPath could return a path relative to the current directory.
|
||||
// As of Go 1.19, LookPath will instead return that path along with an error satisfying
|
||||
// errors.Is(err, ErrDot). See the package documentation for more details.
|
||||
func LookPath(file string) (string, error) {
|
||||
// skip the path lookup for these prefixes
|
||||
skip := []string{"/", "#", "./", "../"}
|
||||
|
||||
for _, p := range skip {
|
||||
if strings.HasPrefix(file, p) {
|
||||
err := findExecutable(file)
|
||||
if err == nil {
|
||||
return file, nil
|
||||
}
|
||||
return "", &Error{file, err}
|
||||
}
|
||||
}
|
||||
|
||||
path := os.Getenv("path")
|
||||
for _, dir := range filepath.SplitList(path) {
|
||||
path := filepath.Join(dir, file)
|
||||
if err := findExecutable(path); err == nil {
|
||||
if !filepath.IsAbs(path) {
|
||||
if execerrdot.Value() != "0" {
|
||||
return path, &Error{file, ErrDot}
|
||||
}
|
||||
execerrdot.IncNonDefault()
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
}
|
||||
return "", &Error{file, ErrNotFound}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
// Copyright 2010 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.
|
||||
|
||||
//go:build unix
|
||||
|
||||
package exec
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// ErrNotFound is the error resulting if a path search failed to find an executable file.
|
||||
var ErrNotFound = errors.New("executable file not found in $PATH")
|
||||
|
||||
func findExecutable(file string) error {
|
||||
d, err := os.Stat(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m := d.Mode()
|
||||
if m.IsDir() {
|
||||
return syscall.EISDIR
|
||||
}
|
||||
err = unixEaccess(file, unix_X_OK)
|
||||
// ENOSYS means Eaccess is not available or not implemented.
|
||||
// EPERM can be returned by Linux containers employing seccomp.
|
||||
// In both cases, fall back to checking the permission bits.
|
||||
if err == nil || (err != syscall.ENOSYS && err != syscall.EPERM) {
|
||||
return err
|
||||
}
|
||||
if m&0111 != 0 {
|
||||
return nil
|
||||
}
|
||||
return fs.ErrPermission
|
||||
}
|
||||
|
||||
// LookPath searches for an executable named file in the
|
||||
// directories named by the PATH environment variable.
|
||||
// If file contains a slash, it is tried directly and the PATH is not consulted.
|
||||
// Otherwise, on success, the result is an absolute path.
|
||||
//
|
||||
// In older versions of Go, LookPath could return a path relative to the current directory.
|
||||
// As of Go 1.19, LookPath will instead return that path along with an error satisfying
|
||||
// errors.Is(err, ErrDot). See the package documentation for more details.
|
||||
func LookPath(file string) (string, error) {
|
||||
// NOTE(rsc): I wish we could use the Plan 9 behavior here
|
||||
// (only bypass the path if file begins with / or ./ or ../)
|
||||
// but that would not match all the Unix shells.
|
||||
|
||||
if strings.Contains(file, "/") {
|
||||
err := findExecutable(file)
|
||||
if err == nil {
|
||||
return file, nil
|
||||
}
|
||||
return "", &Error{file, err}
|
||||
}
|
||||
path := os.Getenv("PATH")
|
||||
for _, dir := range filepath.SplitList(path) {
|
||||
if dir == "" {
|
||||
// Unix shell semantics: path element "" means "."
|
||||
dir = "."
|
||||
}
|
||||
path := filepath.Join(dir, file)
|
||||
if err := findExecutable(path); err == nil {
|
||||
if !filepath.IsAbs(path) {
|
||||
/* TODO(xsw):
|
||||
if execerrdot.Value() != "0" {
|
||||
return path, &Error{file, ErrDot}
|
||||
}
|
||||
execerrdot.IncNonDefault()
|
||||
*/
|
||||
panic("todo: exec.LookPath: !filepath.IsAbs(path)")
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
}
|
||||
return "", &Error{file, ErrNotFound}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
//go:build wasm
|
||||
|
||||
package exec
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// ErrNotFound is the error resulting if a path search failed to find an executable file.
|
||||
var ErrNotFound = errors.New("executable file not found in $PATH")
|
||||
|
||||
// LookPath searches for an executable named file in the
|
||||
// directories named by the PATH environment variable.
|
||||
// If file contains a slash, it is tried directly and the PATH is not consulted.
|
||||
// The result may be an absolute path or a path relative to the current directory.
|
||||
func LookPath(file string) (string, error) {
|
||||
// Wasm can not execute processes, so act as if there are no executables at all.
|
||||
return "", &Error{file, ErrNotFound}
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
// Copyright 2010 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 exec
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// ErrNotFound is the error resulting if a path search failed to find an executable file.
|
||||
var ErrNotFound = errors.New("executable file not found in %PATH%")
|
||||
|
||||
func chkStat(file string) error {
|
||||
d, err := os.Stat(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.IsDir() {
|
||||
return fs.ErrPermission
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func hasExt(file string) bool {
|
||||
i := strings.LastIndex(file, ".")
|
||||
if i < 0 {
|
||||
return false
|
||||
}
|
||||
return strings.LastIndexAny(file, `:\/`) < i
|
||||
}
|
||||
|
||||
func findExecutable(file string, exts []string) (string, error) {
|
||||
if len(exts) == 0 {
|
||||
return file, chkStat(file)
|
||||
}
|
||||
if hasExt(file) {
|
||||
if chkStat(file) == nil {
|
||||
return file, nil
|
||||
}
|
||||
}
|
||||
for _, e := range exts {
|
||||
if f := file + e; chkStat(f) == nil {
|
||||
return f, nil
|
||||
}
|
||||
}
|
||||
return "", fs.ErrNotExist
|
||||
}
|
||||
|
||||
// LookPath searches for an executable named file in the
|
||||
// directories named by the PATH environment variable.
|
||||
// LookPath also uses PATHEXT environment variable to match
|
||||
// a suitable candidate.
|
||||
// If file contains a slash, it is tried directly and the PATH is not consulted.
|
||||
// Otherwise, on success, the result is an absolute path.
|
||||
//
|
||||
// In older versions of Go, LookPath could return a path relative to the current directory.
|
||||
// As of Go 1.19, LookPath will instead return that path along with an error satisfying
|
||||
// errors.Is(err, ErrDot). See the package documentation for more details.
|
||||
func LookPath(file string) (string, error) {
|
||||
var exts []string
|
||||
x := os.Getenv(`PATHEXT`)
|
||||
if x != "" {
|
||||
for _, e := range strings.Split(strings.ToLower(x), `;`) {
|
||||
if e == "" {
|
||||
continue
|
||||
}
|
||||
if e[0] != '.' {
|
||||
e = "." + e
|
||||
}
|
||||
exts = append(exts, e)
|
||||
}
|
||||
} else {
|
||||
exts = []string{".com", ".exe", ".bat", ".cmd"}
|
||||
}
|
||||
|
||||
if strings.ContainsAny(file, `:\/`) {
|
||||
f, err := findExecutable(file, exts)
|
||||
if err == nil {
|
||||
return f, nil
|
||||
}
|
||||
return "", &Error{file, err}
|
||||
}
|
||||
|
||||
// On Windows, creating the NoDefaultCurrentDirectoryInExePath
|
||||
// environment variable (with any value or no value!) signals that
|
||||
// path lookups should skip the current directory.
|
||||
// In theory we are supposed to call NeedCurrentDirectoryForExePathW
|
||||
// "as the registry location of this environment variable can change"
|
||||
// but that seems exceedingly unlikely: it would break all users who
|
||||
// have configured their environment this way!
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-needcurrentdirectoryforexepathw
|
||||
// See also go.dev/issue/43947.
|
||||
var (
|
||||
dotf string
|
||||
dotErr error
|
||||
)
|
||||
if _, found := syscall.Getenv("NoDefaultCurrentDirectoryInExePath"); !found {
|
||||
if f, err := findExecutable(filepath.Join(".", file), exts); err == nil {
|
||||
if execerrdot.Value() == "0" {
|
||||
execerrdot.IncNonDefault()
|
||||
return f, nil
|
||||
}
|
||||
dotf, dotErr = f, &Error{file, ErrDot}
|
||||
}
|
||||
}
|
||||
|
||||
path := os.Getenv("path")
|
||||
for _, dir := range filepath.SplitList(path) {
|
||||
if f, err := findExecutable(filepath.Join(dir, file), exts); err == nil {
|
||||
if dotErr != nil {
|
||||
// https://go.dev/issue/53536: if we resolved a relative path implicitly,
|
||||
// and it is the same executable that would be resolved from the explicit %PATH%,
|
||||
// prefer the explicit name for the executable (and, likely, no error) instead
|
||||
// of the equivalent implicit name with ErrDot.
|
||||
//
|
||||
// Otherwise, return the ErrDot for the implicit path as soon as we find
|
||||
// out that the explicit one doesn't match.
|
||||
dotfi, dotfiErr := os.Lstat(dotf)
|
||||
fi, fiErr := os.Lstat(f)
|
||||
if dotfiErr != nil || fiErr != nil || !os.SameFile(dotfi, fi) {
|
||||
return dotf, dotErr
|
||||
}
|
||||
}
|
||||
|
||||
if !filepath.IsAbs(f) {
|
||||
if execerrdot.Value() != "0" {
|
||||
return f, &Error{file, ErrDot}
|
||||
}
|
||||
execerrdot.IncNonDefault()
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
}
|
||||
|
||||
if dotErr != nil {
|
||||
return dotf, dotErr
|
||||
}
|
||||
return "", &Error{file, ErrNotFound}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
//go:build unix
|
||||
|
||||
package exec
|
||||
|
||||
const (
|
||||
unix_R_OK = 0x4
|
||||
unix_W_OK = 0x2
|
||||
unix_X_OK = 0x1
|
||||
)
|
||||
@@ -1,15 +0,0 @@
|
||||
// Copyright 2022 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 exec
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"github.com/goplus/llgo/c/syscall/unix"
|
||||
)
|
||||
|
||||
func unixEaccess(path string, mode uint32) error {
|
||||
return syscall.Faccessat(unix.AT_FDCWD, path, mode, unix.AT_EACCESS)
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
//go:build unix && !linux
|
||||
|
||||
package exec
|
||||
|
||||
import "syscall"
|
||||
|
||||
func unixEaccess(path string, mode uint32) error {
|
||||
return syscall.ENOSYS
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
// Copyright 2009 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 os
|
||||
|
||||
import (
|
||||
"internal/itoa"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
// The only signal values guaranteed to be present in the os package
|
||||
// on all systems are Interrupt (send the process an interrupt) and
|
||||
// Kill (force the process to exit). Interrupt is not implemented on
|
||||
// Windows; using it with os.Process.Signal will return an error.
|
||||
var (
|
||||
Interrupt Signal = syscall.Note("interrupt")
|
||||
Kill Signal = syscall.Note("kill")
|
||||
)
|
||||
|
||||
func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
|
||||
sysattr := &syscall.ProcAttr{
|
||||
Dir: attr.Dir,
|
||||
Env: attr.Env,
|
||||
Sys: attr.Sys,
|
||||
}
|
||||
|
||||
sysattr.Files = make([]uintptr, 0, len(attr.Files))
|
||||
for _, f := range attr.Files {
|
||||
sysattr.Files = append(sysattr.Files, f.Fd())
|
||||
}
|
||||
|
||||
pid, h, e := syscall.StartProcess(name, argv, sysattr)
|
||||
if e != nil {
|
||||
return nil, &PathError{Op: "fork/exec", Path: name, Err: e}
|
||||
}
|
||||
|
||||
return newProcess(pid, h), nil
|
||||
}
|
||||
|
||||
func (p *Process) writeProcFile(file string, data string) error {
|
||||
f, e := OpenFile("/proc/"+itoa.Itoa(p.Pid)+"/"+file, O_WRONLY, 0)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
defer f.Close()
|
||||
_, e = f.Write([]byte(data))
|
||||
return e
|
||||
}
|
||||
|
||||
func (p *Process) signal(sig Signal) error {
|
||||
if p.done() {
|
||||
return ErrProcessDone
|
||||
}
|
||||
if e := p.writeProcFile("note", sig.String()); e != nil {
|
||||
return NewSyscallError("signal", e)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Process) kill() error {
|
||||
return p.signal(Kill)
|
||||
}
|
||||
|
||||
func (p *Process) wait() (ps *ProcessState, err error) {
|
||||
var waitmsg syscall.Waitmsg
|
||||
|
||||
if p.Pid == -1 {
|
||||
return nil, ErrInvalid
|
||||
}
|
||||
err = syscall.WaitProcess(p.Pid, &waitmsg)
|
||||
if err != nil {
|
||||
return nil, NewSyscallError("wait", err)
|
||||
}
|
||||
|
||||
p.setDone()
|
||||
ps = &ProcessState{
|
||||
pid: waitmsg.Pid,
|
||||
status: &waitmsg,
|
||||
}
|
||||
return ps, nil
|
||||
}
|
||||
|
||||
func (p *Process) release() error {
|
||||
// NOOP for Plan 9.
|
||||
p.Pid = -1
|
||||
// no need for a finalizer anymore
|
||||
runtime.SetFinalizer(p, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func findProcess(pid int) (p *Process, err error) {
|
||||
// NOOP for Plan 9.
|
||||
return newProcess(pid, 0), nil
|
||||
}
|
||||
|
||||
// ProcessState stores information about a process, as reported by Wait.
|
||||
type ProcessState struct {
|
||||
pid int // The process's id.
|
||||
status *syscall.Waitmsg // System-dependent status info.
|
||||
}
|
||||
|
||||
// Pid returns the process id of the exited process.
|
||||
func (p *ProcessState) Pid() int {
|
||||
return p.pid
|
||||
}
|
||||
|
||||
func (p *ProcessState) exited() bool {
|
||||
return p.status.Exited()
|
||||
}
|
||||
|
||||
func (p *ProcessState) success() bool {
|
||||
return p.status.ExitStatus() == 0
|
||||
}
|
||||
|
||||
func (p *ProcessState) sys() any {
|
||||
return p.status
|
||||
}
|
||||
|
||||
func (p *ProcessState) sysUsage() any {
|
||||
return p.status
|
||||
}
|
||||
|
||||
func (p *ProcessState) userTime() time.Duration {
|
||||
return time.Duration(p.status.Time[0]) * time.Millisecond
|
||||
}
|
||||
|
||||
func (p *ProcessState) systemTime() time.Duration {
|
||||
return time.Duration(p.status.Time[1]) * time.Millisecond
|
||||
}
|
||||
|
||||
func (p *ProcessState) String() string {
|
||||
if p == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
return "exit status: " + p.status.Msg
|
||||
}
|
||||
|
||||
// ExitCode returns the exit code of the exited process, or -1
|
||||
// if the process hasn't exited or was terminated by a signal.
|
||||
func (p *ProcessState) ExitCode() int {
|
||||
// return -1 if the process hasn't started.
|
||||
if p == nil {
|
||||
return -1
|
||||
}
|
||||
return p.status.ExitStatus()
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
//go:build unix || (js && wasm) || wasip1 || windows
|
||||
|
||||
package os
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"syscall"
|
||||
|
||||
"github.com/goplus/llgo/compiler/internal/lib/internal/itoa"
|
||||
"github.com/goplus/llgo/compiler/internal/lib/internal/syscall/execenv"
|
||||
)
|
||||
|
||||
// The only signal values guaranteed to be present in the os package on all
|
||||
// systems are os.Interrupt (send the process an interrupt) and os.Kill (force
|
||||
// the process to exit). On Windows, sending os.Interrupt to a process with
|
||||
// os.Process.Signal is not implemented; it will return an error instead of
|
||||
// sending a signal.
|
||||
var (
|
||||
Interrupt Signal = syscall.SIGINT
|
||||
Kill Signal = syscall.SIGKILL
|
||||
)
|
||||
|
||||
func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
|
||||
// If there is no SysProcAttr (ie. no Chroot or changed
|
||||
// UID/GID), double-check existence of the directory we want
|
||||
// to chdir into. We can make the error clearer this way.
|
||||
if attr != nil && attr.Sys == nil && attr.Dir != "" {
|
||||
if _, err := Stat(attr.Dir); err != nil {
|
||||
pe := err.(*PathError)
|
||||
pe.Op = "chdir"
|
||||
return nil, pe
|
||||
}
|
||||
}
|
||||
|
||||
sysattr := &syscall.ProcAttr{
|
||||
Dir: attr.Dir,
|
||||
Env: attr.Env,
|
||||
Sys: attr.Sys,
|
||||
}
|
||||
if sysattr.Env == nil {
|
||||
sysattr.Env, err = execenv.Default(sysattr.Sys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
sysattr.Files = make([]uintptr, 0, len(attr.Files))
|
||||
for _, f := range attr.Files {
|
||||
sysattr.Files = append(sysattr.Files, f.Fd())
|
||||
}
|
||||
|
||||
pid, h, e := syscall.StartProcess(name, argv, sysattr)
|
||||
|
||||
// TODO(xsw):
|
||||
// Make sure we don't run the finalizers of attr.Files.
|
||||
// runtime.KeepAlive(attr)
|
||||
|
||||
if e != nil {
|
||||
return nil, &PathError{Op: "fork/exec", Path: name, Err: e}
|
||||
}
|
||||
|
||||
return newProcess(pid, h), nil
|
||||
}
|
||||
|
||||
func (p *Process) kill() error {
|
||||
return p.Signal(Kill)
|
||||
}
|
||||
|
||||
// ProcessState stores information about a process, as reported by Wait.
|
||||
type ProcessState struct {
|
||||
pid int // The process's id.
|
||||
status syscall.WaitStatus // System-dependent status info.
|
||||
rusage *syscall.Rusage
|
||||
}
|
||||
|
||||
// Pid returns the process id of the exited process.
|
||||
func (p *ProcessState) Pid() int {
|
||||
return p.pid
|
||||
}
|
||||
|
||||
func (p *ProcessState) exited() bool {
|
||||
return p.status.Exited()
|
||||
}
|
||||
|
||||
func (p *ProcessState) success() bool {
|
||||
return p.status.ExitStatus() == 0
|
||||
}
|
||||
|
||||
func (p *ProcessState) sys() any {
|
||||
return p.status
|
||||
}
|
||||
|
||||
func (p *ProcessState) sysUsage() any {
|
||||
return p.rusage
|
||||
}
|
||||
|
||||
func (p *ProcessState) String() string {
|
||||
if p == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
status := p.Sys().(syscall.WaitStatus)
|
||||
res := ""
|
||||
switch {
|
||||
case status.Exited():
|
||||
code := status.ExitStatus()
|
||||
if runtime.GOOS == "windows" && uint(code) >= 1<<16 { // windows uses large hex numbers
|
||||
res = "exit status " + uitox(uint(code))
|
||||
} else { // unix systems use small decimal integers
|
||||
res = "exit status " + itoa.Itoa(code) // unix
|
||||
}
|
||||
case status.Signaled():
|
||||
res = "signal: " + status.Signal().String()
|
||||
case status.Stopped():
|
||||
res = "stop signal: " + status.StopSignal().String()
|
||||
if status.StopSignal() == syscall.SIGTRAP && status.TrapCause() != 0 {
|
||||
res += " (trap " + itoa.Itoa(status.TrapCause()) + ")"
|
||||
}
|
||||
case status.Continued():
|
||||
res = "continued"
|
||||
}
|
||||
if status.CoreDump() {
|
||||
res += " (core dumped)"
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// ExitCode returns the exit code of the exited process, or -1
|
||||
// if the process hasn't exited or was terminated by a signal.
|
||||
func (p *ProcessState) ExitCode() int {
|
||||
// return -1 if the process hasn't started.
|
||||
if p == nil {
|
||||
return -1
|
||||
}
|
||||
return p.status.ExitStatus()
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
//go:build unix || (js && wasm) || wasip1
|
||||
|
||||
package os
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (p *Process) wait() (ps *ProcessState, err error) {
|
||||
if p.Pid == -1 {
|
||||
return nil, syscall.EINVAL
|
||||
}
|
||||
|
||||
// If we can block until Wait4 will succeed immediately, do so.
|
||||
ready, err := p.blockUntilWaitable()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ready {
|
||||
// Mark the process done now, before the call to Wait4,
|
||||
// so that Process.signal will not send a signal.
|
||||
p.setDone()
|
||||
// Acquire a write lock on sigMu to wait for any
|
||||
// active call to the signal method to complete.
|
||||
p.sigMu.Lock()
|
||||
p.sigMu.Unlock()
|
||||
}
|
||||
|
||||
var (
|
||||
status syscall.WaitStatus
|
||||
rusage syscall.Rusage
|
||||
pid1 int
|
||||
e error
|
||||
)
|
||||
for {
|
||||
pid1, e = syscall.Wait4(p.Pid, &status, 0, &rusage)
|
||||
if e != syscall.EINTR {
|
||||
break
|
||||
}
|
||||
}
|
||||
if e != nil {
|
||||
return nil, NewSyscallError("wait", e)
|
||||
}
|
||||
if pid1 != 0 {
|
||||
p.setDone()
|
||||
}
|
||||
ps = &ProcessState{
|
||||
pid: pid1,
|
||||
status: status,
|
||||
rusage: &rusage,
|
||||
}
|
||||
return ps, nil
|
||||
}
|
||||
|
||||
func (p *Process) signal(sig Signal) error {
|
||||
if p.Pid == -1 {
|
||||
return errors.New("os: process already released")
|
||||
}
|
||||
if p.Pid == 0 {
|
||||
return errors.New("os: process not initialized")
|
||||
}
|
||||
p.sigMu.RLock()
|
||||
defer p.sigMu.RUnlock()
|
||||
if p.done() {
|
||||
return ErrProcessDone
|
||||
}
|
||||
s, ok := sig.(syscall.Signal)
|
||||
if !ok {
|
||||
return errors.New("os: unsupported signal type")
|
||||
}
|
||||
if e := syscall.Kill(p.Pid, s); e != nil {
|
||||
if e == syscall.ESRCH {
|
||||
return ErrProcessDone
|
||||
}
|
||||
return e
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Process) release() error {
|
||||
// NOOP for unix.
|
||||
p.Pid = -1
|
||||
// no need for a finalizer anymore
|
||||
runtime.SetFinalizer(p, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func findProcess(pid int) (p *Process, err error) {
|
||||
// NOOP for unix.
|
||||
return newProcess(pid, 0), nil
|
||||
}
|
||||
|
||||
func (p *ProcessState) userTime() time.Duration {
|
||||
return time.Duration(p.rusage.Utime.Nano()) * time.Nanosecond
|
||||
}
|
||||
|
||||
func (p *ProcessState) systemTime() time.Duration {
|
||||
return time.Duration(p.rusage.Stime.Nano()) * time.Nanosecond
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
// Copyright 2009 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 os
|
||||
|
||||
import (
|
||||
"internal/syscall/windows"
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (p *Process) wait() (ps *ProcessState, err error) {
|
||||
/* TODO(xsw):
|
||||
handle := atomic.LoadUintptr(&p.handle)
|
||||
s, e := syscall.WaitForSingleObject(syscall.Handle(handle), syscall.INFINITE)
|
||||
switch s {
|
||||
case syscall.WAIT_OBJECT_0:
|
||||
break
|
||||
case syscall.WAIT_FAILED:
|
||||
return nil, NewSyscallError("WaitForSingleObject", e)
|
||||
default:
|
||||
return nil, errors.New("os: unexpected result from WaitForSingleObject")
|
||||
}
|
||||
var ec uint32
|
||||
e = syscall.GetExitCodeProcess(syscall.Handle(handle), &ec)
|
||||
if e != nil {
|
||||
return nil, NewSyscallError("GetExitCodeProcess", e)
|
||||
}
|
||||
var u syscall.Rusage
|
||||
e = syscall.GetProcessTimes(syscall.Handle(handle), &u.CreationTime, &u.ExitTime, &u.KernelTime, &u.UserTime)
|
||||
if e != nil {
|
||||
return nil, NewSyscallError("GetProcessTimes", e)
|
||||
}
|
||||
p.setDone()
|
||||
// NOTE(brainman): It seems that sometimes process is not dead
|
||||
// when WaitForSingleObject returns. But we do not know any
|
||||
// other way to wait for it. Sleeping for a while seems to do
|
||||
// the trick sometimes.
|
||||
// See https://golang.org/issue/25965 for details.
|
||||
defer time.Sleep(5 * time.Millisecond)
|
||||
defer p.Release()
|
||||
return &ProcessState{p.Pid, syscall.WaitStatus{ExitCode: ec}, &u}, nil
|
||||
*/
|
||||
panic("todo: os.Process.wait")
|
||||
}
|
||||
|
||||
func (p *Process) signal(sig Signal) error {
|
||||
handle := atomic.LoadUintptr(&p.handle)
|
||||
if handle == uintptr(syscall.InvalidHandle) {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
if p.done() {
|
||||
return ErrProcessDone
|
||||
}
|
||||
if sig == Kill {
|
||||
var terminationHandle syscall.Handle
|
||||
e := syscall.DuplicateHandle(^syscall.Handle(0), syscall.Handle(handle), ^syscall.Handle(0), &terminationHandle, syscall.PROCESS_TERMINATE, false, 0)
|
||||
if e != nil {
|
||||
return NewSyscallError("DuplicateHandle", e)
|
||||
}
|
||||
runtime.KeepAlive(p)
|
||||
defer syscall.CloseHandle(terminationHandle)
|
||||
e = syscall.TerminateProcess(syscall.Handle(terminationHandle), 1)
|
||||
return NewSyscallError("TerminateProcess", e)
|
||||
}
|
||||
// TODO(rsc): Handle Interrupt too?
|
||||
return syscall.Errno(syscall.EWINDOWS)
|
||||
}
|
||||
|
||||
func (p *Process) release() error {
|
||||
handle := atomic.SwapUintptr(&p.handle, uintptr(syscall.InvalidHandle))
|
||||
if handle == uintptr(syscall.InvalidHandle) {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
e := syscall.CloseHandle(syscall.Handle(handle))
|
||||
if e != nil {
|
||||
return NewSyscallError("CloseHandle", e)
|
||||
}
|
||||
// no need for a finalizer anymore
|
||||
runtime.SetFinalizer(p, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func findProcess(pid int) (p *Process, err error) {
|
||||
const da = syscall.STANDARD_RIGHTS_READ |
|
||||
syscall.PROCESS_QUERY_INFORMATION | syscall.SYNCHRONIZE
|
||||
h, e := syscall.OpenProcess(da, false, uint32(pid))
|
||||
if e != nil {
|
||||
return nil, NewSyscallError("OpenProcess", e)
|
||||
}
|
||||
return newProcess(pid, uintptr(h)), nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
cmd := windows.UTF16PtrToString(syscall.GetCommandLine())
|
||||
if len(cmd) == 0 {
|
||||
arg0, _ := Executable()
|
||||
Args = []string{arg0}
|
||||
} else {
|
||||
Args = commandLineToArgv(cmd)
|
||||
}
|
||||
}
|
||||
|
||||
// appendBSBytes appends n '\\' bytes to b and returns the resulting slice.
|
||||
func appendBSBytes(b []byte, n int) []byte {
|
||||
for ; n > 0; n-- {
|
||||
b = append(b, '\\')
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// readNextArg splits command line string cmd into next
|
||||
// argument and command line remainder.
|
||||
func readNextArg(cmd string) (arg []byte, rest string) {
|
||||
var b []byte
|
||||
var inquote bool
|
||||
var nslash int
|
||||
for ; len(cmd) > 0; cmd = cmd[1:] {
|
||||
c := cmd[0]
|
||||
switch c {
|
||||
case ' ', '\t':
|
||||
if !inquote {
|
||||
return appendBSBytes(b, nslash), cmd[1:]
|
||||
}
|
||||
case '"':
|
||||
b = appendBSBytes(b, nslash/2)
|
||||
if nslash%2 == 0 {
|
||||
// use "Prior to 2008" rule from
|
||||
// http://daviddeley.com/autohotkey/parameters/parameters.htm
|
||||
// section 5.2 to deal with double double quotes
|
||||
if inquote && len(cmd) > 1 && cmd[1] == '"' {
|
||||
b = append(b, c)
|
||||
cmd = cmd[1:]
|
||||
}
|
||||
inquote = !inquote
|
||||
} else {
|
||||
b = append(b, c)
|
||||
}
|
||||
nslash = 0
|
||||
continue
|
||||
case '\\':
|
||||
nslash++
|
||||
continue
|
||||
}
|
||||
b = appendBSBytes(b, nslash)
|
||||
nslash = 0
|
||||
b = append(b, c)
|
||||
}
|
||||
return appendBSBytes(b, nslash), ""
|
||||
}
|
||||
|
||||
// commandLineToArgv splits a command line into individual argument
|
||||
// strings, following the Windows conventions documented
|
||||
// at http://daviddeley.com/autohotkey/parameters/parameters.htm#WINARGV
|
||||
func commandLineToArgv(cmd string) []string {
|
||||
var args []string
|
||||
for len(cmd) > 0 {
|
||||
if cmd[0] == ' ' || cmd[0] == '\t' {
|
||||
cmd = cmd[1:]
|
||||
continue
|
||||
}
|
||||
var arg []byte
|
||||
arg, cmd = readNextArg(cmd)
|
||||
args = append(args, string(arg))
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
func ftToDuration(ft *syscall.Filetime) time.Duration {
|
||||
n := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime) // in 100-nanosecond intervals
|
||||
return time.Duration(n*100) * time.Nanosecond
|
||||
}
|
||||
|
||||
func (p *ProcessState) userTime() time.Duration {
|
||||
return ftToDuration(&p.rusage.UserTime)
|
||||
}
|
||||
|
||||
func (p *ProcessState) systemTime() time.Duration {
|
||||
return ftToDuration(&p.rusage.KernelTime)
|
||||
}
|
||||
@@ -1,530 +0,0 @@
|
||||
// Copyright 2009 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 os
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Name returns the name of the file as presented to Open.
|
||||
func (f *File) Name() string { return f.name }
|
||||
|
||||
// Stdin, Stdout, and Stderr are open Files pointing to the standard input,
|
||||
// standard output, and standard error file descriptors.
|
||||
//
|
||||
// Note that the Go runtime writes to standard error for panics and crashes;
|
||||
// closing Stderr may cause those messages to go elsewhere, perhaps
|
||||
// to a file opened later.
|
||||
var (
|
||||
Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
|
||||
Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
|
||||
Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
|
||||
)
|
||||
|
||||
// Flags to OpenFile wrapping those of the underlying system. Not all
|
||||
// flags may be implemented on a given system.
|
||||
const (
|
||||
// Exactly one of O_RDONLY, O_WRONLY, or O_RDWR must be specified.
|
||||
O_RDONLY int = syscall.O_RDONLY // open the file read-only.
|
||||
O_WRONLY int = syscall.O_WRONLY // open the file write-only.
|
||||
O_RDWR int = syscall.O_RDWR // open the file read-write.
|
||||
// The remaining values may be or'ed in to control behavior.
|
||||
O_APPEND int = syscall.O_APPEND // append data to the file when writing.
|
||||
O_CREATE int = syscall.O_CREAT // create a new file if none exists.
|
||||
O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist.
|
||||
O_SYNC int = syscall.O_SYNC // open for synchronous I/O.
|
||||
O_TRUNC int = syscall.O_TRUNC // truncate regular writable file when opened.
|
||||
)
|
||||
|
||||
// Seek whence values.
|
||||
//
|
||||
// Deprecated: Use io.SeekStart, io.SeekCurrent, and io.SeekEnd.
|
||||
const (
|
||||
SEEK_SET int = 0 // seek relative to the origin of the file
|
||||
SEEK_CUR int = 1 // seek relative to the current offset
|
||||
SEEK_END int = 2 // seek relative to the end
|
||||
)
|
||||
|
||||
// Read reads up to len(b) bytes from the File and stores them in b.
|
||||
// It returns the number of bytes read and any error encountered.
|
||||
// At end of file, Read returns 0, io.EOF.
|
||||
func (f *File) Read(b []byte) (n int, err error) {
|
||||
if err := f.checkValid("read"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
n, e := f.read(b)
|
||||
return n, f.wrapErr("read", e)
|
||||
}
|
||||
|
||||
// ReadAt reads len(b) bytes from the File starting at byte offset off.
|
||||
// It returns the number of bytes read and the error, if any.
|
||||
// ReadAt always returns a non-nil error when n < len(b).
|
||||
// At end of file, that error is io.EOF.
|
||||
func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
|
||||
/*
|
||||
if err := f.checkValid("read"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if off < 0 {
|
||||
return 0, &PathError{Op: "readat", Path: f.name, Err: errors.New("negative offset")}
|
||||
}
|
||||
|
||||
for len(b) > 0 {
|
||||
m, e := f.pread(b, off)
|
||||
if e != nil {
|
||||
err = f.wrapErr("read", e)
|
||||
break
|
||||
}
|
||||
n += m
|
||||
b = b[m:]
|
||||
off += int64(m)
|
||||
}
|
||||
return
|
||||
*/
|
||||
panic("todo: os.File.ReadAt")
|
||||
}
|
||||
|
||||
// ReadFrom implements io.ReaderFrom.
|
||||
func (f *File) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
/*
|
||||
if err := f.checkValid("write"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
n, handled, e := f.readFrom(r)
|
||||
if !handled {
|
||||
return genericReadFrom(f, r) // without wrapping
|
||||
}
|
||||
return n, f.wrapErr("write", e)
|
||||
*/
|
||||
panic("todo: os.File.ReadFrom")
|
||||
}
|
||||
|
||||
func genericReadFrom(f *File, r io.Reader) (int64, error) {
|
||||
return io.Copy(fileWithoutReadFrom{f}, r)
|
||||
}
|
||||
|
||||
// fileWithoutReadFrom implements all the methods of *File other
|
||||
// than ReadFrom. This is used to permit ReadFrom to call io.Copy
|
||||
// without leading to a recursive call to ReadFrom.
|
||||
type fileWithoutReadFrom struct {
|
||||
*File
|
||||
}
|
||||
|
||||
// This ReadFrom method hides the *File ReadFrom method.
|
||||
func (fileWithoutReadFrom) ReadFrom(fileWithoutReadFrom) {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Write writes len(b) bytes from b to the File.
|
||||
// It returns the number of bytes written and an error, if any.
|
||||
// Write returns a non-nil error when n != len(b).
|
||||
func (f *File) Write(b []byte) (n int, err error) {
|
||||
if err := f.checkValid("write"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
n, e := f.write(b)
|
||||
|
||||
// TODO(xsw):
|
||||
// epipecheck(f, e)
|
||||
|
||||
if e != nil {
|
||||
err = f.wrapErr("write", e)
|
||||
} else if n != len(b) {
|
||||
err = io.ErrShortWrite
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
var errWriteAtInAppendMode = errors.New("os: invalid use of WriteAt on file opened with O_APPEND")
|
||||
|
||||
// WriteAt writes len(b) bytes to the File starting at byte offset off.
|
||||
// It returns the number of bytes written and an error, if any.
|
||||
// WriteAt returns a non-nil error when n != len(b).
|
||||
//
|
||||
// If file was opened with the O_APPEND flag, WriteAt returns an error.
|
||||
func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
|
||||
/*
|
||||
if err := f.checkValid("write"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if f.appendMode {
|
||||
return 0, errWriteAtInAppendMode
|
||||
}
|
||||
|
||||
if off < 0 {
|
||||
return 0, &PathError{Op: "writeat", Path: f.name, Err: errors.New("negative offset")}
|
||||
}
|
||||
|
||||
for len(b) > 0 {
|
||||
m, e := f.pwrite(b, off)
|
||||
if e != nil {
|
||||
err = f.wrapErr("write", e)
|
||||
break
|
||||
}
|
||||
n += m
|
||||
b = b[m:]
|
||||
off += int64(m)
|
||||
}
|
||||
return
|
||||
*/
|
||||
panic("todo: os.(*File).WriteAt")
|
||||
}
|
||||
|
||||
// Seek sets the offset for the next Read or Write on file to offset, interpreted
|
||||
// according to whence: 0 means relative to the origin of the file, 1 means
|
||||
// relative to the current offset, and 2 means relative to the end.
|
||||
// It returns the new offset and an error, if any.
|
||||
// The behavior of Seek on a file opened with O_APPEND is not specified.
|
||||
func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
|
||||
/*
|
||||
if err := f.checkValid("seek"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
r, e := f.seek(offset, whence)
|
||||
if e == nil && f.dirinfo != nil && r != 0 {
|
||||
e = syscall.EISDIR
|
||||
}
|
||||
if e != nil {
|
||||
return 0, f.wrapErr("seek", e)
|
||||
}
|
||||
return r, nil
|
||||
*/
|
||||
panic("todo: os.(*File).Seek")
|
||||
}
|
||||
|
||||
// WriteString is like Write, but writes the contents of string s rather than
|
||||
// a slice of bytes.
|
||||
func (f *File) WriteString(s string) (n int, err error) {
|
||||
/*
|
||||
b := unsafe.Slice(unsafe.StringData(s), len(s))
|
||||
return f.Write(b)
|
||||
*/
|
||||
panic("todo: os.(*File).WriteString")
|
||||
}
|
||||
|
||||
// setStickyBit adds ModeSticky to the permission bits of path, non atomic.
|
||||
func setStickyBit(name string) error {
|
||||
fi, err := Stat(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return Chmod(name, fi.Mode()|ModeSticky)
|
||||
}
|
||||
|
||||
// Open opens the named file for reading. If successful, methods on
|
||||
// the returned file can be used for reading; the associated file
|
||||
// descriptor has mode O_RDONLY.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func Open(name string) (*File, error) {
|
||||
return OpenFile(name, O_RDONLY, 0)
|
||||
}
|
||||
|
||||
// Create creates or truncates the named file. If the file already exists,
|
||||
// it is truncated. If the file does not exist, it is created with mode 0666
|
||||
// (before umask). If successful, methods on the returned File can
|
||||
// be used for I/O; the associated file descriptor has mode O_RDWR.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func Create(name string) (*File, error) {
|
||||
return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
|
||||
}
|
||||
|
||||
// OpenFile is the generalized open call; most users will use Open
|
||||
// or Create instead. It opens the named file with specified flag
|
||||
// (O_RDONLY etc.). If the file does not exist, and the O_CREATE flag
|
||||
// is passed, it is created with mode perm (before umask). If successful,
|
||||
// methods on the returned File can be used for I/O.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func OpenFile(name string, flag int, perm FileMode) (*File, error) {
|
||||
f, err := openFileNolog(name, flag, perm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.appendMode = flag&O_APPEND != 0
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
/*
|
||||
// lstat is overridden in tests.
|
||||
var lstat = Lstat
|
||||
|
||||
// Many functions in package syscall return a count of -1 instead of 0.
|
||||
// Using fixCount(call()) instead of call() corrects the count.
|
||||
func fixCount(n int, err error) (int, error) {
|
||||
if n < 0 {
|
||||
n = 0
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
*/
|
||||
|
||||
// TODO(xsw):
|
||||
// checkWrapErr is the test hook to enable checking unexpected wrapped errors of poll.ErrFileClosing.
|
||||
// It is set to true in the export_test.go for tests (including fuzz tests).
|
||||
// var checkWrapErr = false
|
||||
|
||||
// wrapErr wraps an error that occurred during an operation on an open file.
|
||||
// It passes io.EOF through unchanged, otherwise converts
|
||||
// poll.ErrFileClosing to ErrClosed and wraps the error in a PathError.
|
||||
func (f *File) wrapErr(op string, err error) error {
|
||||
if err == nil || err == io.EOF {
|
||||
return err
|
||||
}
|
||||
/* TODO(xsw):
|
||||
if err == poll.ErrFileClosing {
|
||||
err = ErrClosed
|
||||
} else if checkWrapErr && errors.Is(err, poll.ErrFileClosing) {
|
||||
panic("unexpected error wrapping poll.ErrFileClosing: " + err.Error())
|
||||
}
|
||||
*/
|
||||
return &PathError{Op: op, Path: f.name, Err: err}
|
||||
}
|
||||
|
||||
// TempDir returns the default directory to use for temporary files.
|
||||
//
|
||||
// On Unix systems, it returns $TMPDIR if non-empty, else /tmp.
|
||||
// On Windows, it uses GetTempPath, returning the first non-empty
|
||||
// value from %TMP%, %TEMP%, %USERPROFILE%, or the Windows directory.
|
||||
// On Plan 9, it returns /tmp.
|
||||
//
|
||||
// The directory is neither guaranteed to exist nor have accessible
|
||||
// permissions.
|
||||
func TempDir() string {
|
||||
return tempDir()
|
||||
}
|
||||
|
||||
// Chmod changes the mode of the file to mode.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func (f *File) Chmod(mode FileMode) error { return f.chmod(mode) }
|
||||
|
||||
// SetDeadline sets the read and write deadlines for a File.
|
||||
// It is equivalent to calling both SetReadDeadline and SetWriteDeadline.
|
||||
//
|
||||
// Only some kinds of files support setting a deadline. Calls to SetDeadline
|
||||
// for files that do not support deadlines will return ErrNoDeadline.
|
||||
// On most systems ordinary files do not support deadlines, but pipes do.
|
||||
//
|
||||
// A deadline is an absolute time after which I/O operations fail with an
|
||||
// error instead of blocking. The deadline applies to all future and pending
|
||||
// I/O, not just the immediately following call to Read or Write.
|
||||
// After a deadline has been exceeded, the connection can be refreshed
|
||||
// by setting a deadline in the future.
|
||||
//
|
||||
// If the deadline is exceeded a call to Read or Write or to other I/O
|
||||
// methods will return an error that wraps ErrDeadlineExceeded.
|
||||
// This can be tested using errors.Is(err, os.ErrDeadlineExceeded).
|
||||
// That error implements the Timeout method, and calling the Timeout
|
||||
// method will return true, but there are other possible errors for which
|
||||
// the Timeout will return true even if the deadline has not been exceeded.
|
||||
//
|
||||
// An idle timeout can be implemented by repeatedly extending
|
||||
// the deadline after successful Read or Write calls.
|
||||
//
|
||||
// A zero value for t means I/O operations will not time out.
|
||||
func (f *File) SetDeadline(t time.Time) error {
|
||||
return f.setDeadline(t)
|
||||
}
|
||||
|
||||
// SetReadDeadline sets the deadline for future Read calls and any
|
||||
// currently-blocked Read call.
|
||||
// A zero value for t means Read will not time out.
|
||||
// Not all files support setting deadlines; see SetDeadline.
|
||||
func (f *File) SetReadDeadline(t time.Time) error {
|
||||
return f.setReadDeadline(t)
|
||||
}
|
||||
|
||||
// SetWriteDeadline sets the deadline for any future Write calls and any
|
||||
// currently-blocked Write call.
|
||||
// Even if Write times out, it may return n > 0, indicating that
|
||||
// some of the data was successfully written.
|
||||
// A zero value for t means Write will not time out.
|
||||
// Not all files support setting deadlines; see SetDeadline.
|
||||
func (f *File) SetWriteDeadline(t time.Time) error {
|
||||
return f.setWriteDeadline(t)
|
||||
}
|
||||
|
||||
// SyscallConn returns a raw file.
|
||||
// This implements the syscall.Conn interface.
|
||||
func (f *File) SyscallConn() (syscall.RawConn, error) {
|
||||
/*
|
||||
if err := f.checkValid("SyscallConn"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newRawConn(f)
|
||||
*/
|
||||
panic("todo: os.(*File).SyscallConn")
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
// DirFS returns a file system (an fs.FS) for the tree of files rooted at the directory dir.
|
||||
//
|
||||
// Note that DirFS("/prefix") only guarantees that the Open calls it makes to the
|
||||
// operating system will begin with "/prefix": DirFS("/prefix").Open("file") is the
|
||||
// same as os.Open("/prefix/file"). So if /prefix/file is a symbolic link pointing outside
|
||||
// the /prefix tree, then using DirFS does not stop the access any more than using
|
||||
// os.Open does. Additionally, the root of the fs.FS returned for a relative path,
|
||||
// DirFS("prefix"), will be affected by later calls to Chdir. DirFS is therefore not
|
||||
// a general substitute for a chroot-style security mechanism when the directory tree
|
||||
// contains arbitrary content.
|
||||
//
|
||||
// The directory dir must not be "".
|
||||
//
|
||||
// The result implements [io/fs.StatFS], [io/fs.ReadFileFS] and
|
||||
// [io/fs.ReadDirFS].
|
||||
func DirFS(dir string) fs.FS {
|
||||
return dirFS(dir)
|
||||
}
|
||||
|
||||
// containsAny reports whether any bytes in chars are within s.
|
||||
func containsAny(s, chars string) bool {
|
||||
for i := 0; i < len(s); i++ {
|
||||
for j := 0; j < len(chars); j++ {
|
||||
if s[i] == chars[j] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type dirFS string
|
||||
|
||||
func (dir dirFS) Open(name string) (fs.File, error) {
|
||||
fullname, err := dir.join(name)
|
||||
if err != nil {
|
||||
return nil, &PathError{Op: "stat", Path: name, Err: err}
|
||||
}
|
||||
f, err := Open(fullname)
|
||||
if err != nil {
|
||||
// DirFS takes a string appropriate for GOOS,
|
||||
// while the name argument here is always slash separated.
|
||||
// dir.join will have mixed the two; undo that for
|
||||
// error reporting.
|
||||
err.(*PathError).Path = name
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// The ReadFile method calls the [ReadFile] function for the file
|
||||
// with the given name in the directory. The function provides
|
||||
// robust handling for small files and special file systems.
|
||||
// Through this method, dirFS implements [io/fs.ReadFileFS].
|
||||
func (dir dirFS) ReadFile(name string) ([]byte, error) {
|
||||
fullname, err := dir.join(name)
|
||||
if err != nil {
|
||||
return nil, &PathError{Op: "readfile", Path: name, Err: err}
|
||||
}
|
||||
return ReadFile(fullname)
|
||||
}
|
||||
|
||||
// ReadDir reads the named directory, returning all its directory entries sorted
|
||||
// by filename. Through this method, dirFS implements [io/fs.ReadDirFS].
|
||||
func (dir dirFS) ReadDir(name string) ([]DirEntry, error) {
|
||||
fullname, err := dir.join(name)
|
||||
if err != nil {
|
||||
return nil, &PathError{Op: "readdir", Path: name, Err: err}
|
||||
}
|
||||
return ReadDir(fullname)
|
||||
}
|
||||
|
||||
func (dir dirFS) Stat(name string) (fs.FileInfo, error) {
|
||||
fullname, err := dir.join(name)
|
||||
if err != nil {
|
||||
return nil, &PathError{Op: "stat", Path: name, Err: err}
|
||||
}
|
||||
f, err := Stat(fullname)
|
||||
if err != nil {
|
||||
// See comment in dirFS.Open.
|
||||
err.(*PathError).Path = name
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// join returns the path for name in dir.
|
||||
func (dir dirFS) join(name string) (string, error) {
|
||||
if dir == "" {
|
||||
return "", errors.New("os: DirFS with empty root")
|
||||
}
|
||||
if !fs.ValidPath(name) {
|
||||
return "", ErrInvalid
|
||||
}
|
||||
name, err := safefilepath.FromFS(name)
|
||||
if err != nil {
|
||||
return "", ErrInvalid
|
||||
}
|
||||
if IsPathSeparator(dir[len(dir)-1]) {
|
||||
return string(dir) + name, nil
|
||||
}
|
||||
return string(dir) + string(PathSeparator) + name, nil
|
||||
}
|
||||
*/
|
||||
|
||||
// ReadFile reads the named file and returns the contents.
|
||||
// A successful call returns err == nil, not err == EOF.
|
||||
// Because ReadFile reads the whole file, it does not treat an EOF from Read
|
||||
// as an error to be reported.
|
||||
func ReadFile(name string) ([]byte, error) {
|
||||
f, err := Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var size int
|
||||
if info, err := f.Stat(); err == nil {
|
||||
size64 := info.Size()
|
||||
if int64(int(size64)) == size64 {
|
||||
size = int(size64)
|
||||
}
|
||||
}
|
||||
size++ // one byte for final read at EOF
|
||||
|
||||
// If a file claims a small size, read at least 512 bytes.
|
||||
// In particular, files in Linux's /proc claim size 0 but
|
||||
// then do not work right if read in small pieces,
|
||||
// so an initial read of 1 byte would not work correctly.
|
||||
if size < 512 {
|
||||
size = 512
|
||||
}
|
||||
|
||||
data := make([]byte, 0, size)
|
||||
for {
|
||||
if len(data) >= cap(data) {
|
||||
d := append(data[:cap(data)], 0)
|
||||
data = d[:len(data)]
|
||||
}
|
||||
n, err := f.Read(data[len(data):cap(data)])
|
||||
data = data[:len(data)+n]
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
}
|
||||
return data, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WriteFile writes data to the named file, creating it if necessary.
|
||||
// If the file does not exist, WriteFile creates it with permissions perm (before umask);
|
||||
// otherwise WriteFile truncates it before writing, without changing permissions.
|
||||
// Since WriteFile requires multiple system calls to complete, a failure mid-operation
|
||||
// can leave the file in a partially written state.
|
||||
func WriteFile(name string, data []byte, perm FileMode) error {
|
||||
f, err := OpenFile(name, O_WRONLY|O_CREATE|O_TRUNC, perm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.Write(data)
|
||||
if err1 := f.Close(); err1 != nil && err == nil {
|
||||
err = err1
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
//go:build unix || (js && wasm) || wasip1 || windows
|
||||
|
||||
package os
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Close closes the File, rendering it unusable for I/O.
|
||||
// On files that support SetDeadline, any pending I/O operations will
|
||||
// be canceled and return immediately with an ErrClosed error.
|
||||
// Close will return an error if it has already been called.
|
||||
func (f *File) Close() error {
|
||||
if f == nil {
|
||||
return ErrInvalid
|
||||
}
|
||||
return f.close()
|
||||
}
|
||||
|
||||
// pread reads len(b) bytes from the File starting at byte offset off.
|
||||
// It returns the number of bytes read and the error, if any.
|
||||
// EOF is signaled by a zero count with err set to nil.
|
||||
func (f *File) pread(b []byte, off int64) (n int, err error) {
|
||||
/*
|
||||
n, err = f.pfd.Pread(b, off)
|
||||
runtime.KeepAlive(f)
|
||||
return n, err
|
||||
*/
|
||||
panic("todo: os.(*File).pread")
|
||||
}
|
||||
|
||||
// pwrite writes len(b) bytes to the File starting at byte offset off.
|
||||
// It returns the number of bytes written and an error, if any.
|
||||
func (f *File) pwrite(b []byte, off int64) (n int, err error) {
|
||||
/*
|
||||
n, err = f.pfd.Pwrite(b, off)
|
||||
runtime.KeepAlive(f)
|
||||
return n, err
|
||||
*/
|
||||
panic("todo: os.(*File).pwrite")
|
||||
}
|
||||
|
||||
// syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
|
||||
func syscallMode(i FileMode) (o uint32) {
|
||||
o |= uint32(i.Perm())
|
||||
if i&ModeSetuid != 0 {
|
||||
o |= syscall.S_ISUID
|
||||
}
|
||||
if i&ModeSetgid != 0 {
|
||||
o |= syscall.S_ISGID
|
||||
}
|
||||
if i&ModeSticky != 0 {
|
||||
o |= syscall.S_ISVTX
|
||||
}
|
||||
// No mapping for Go's ModeTemporary (plan9 only).
|
||||
return
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
// See docs in file.go:Chmod.
|
||||
func chmod(name string, mode FileMode) error {
|
||||
longName := fixLongPath(name)
|
||||
e := ignoringEINTR(func() error {
|
||||
return syscall.Chmod(longName, syscallMode(mode))
|
||||
})
|
||||
if e != nil {
|
||||
return &PathError{Op: "chmod", Path: name, Err: e}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
|
||||
// See docs in file.go:(*File).Chmod.
|
||||
func (f *File) chmod(mode FileMode) error {
|
||||
/*
|
||||
if err := f.checkValid("chmod"); err != nil {
|
||||
return err
|
||||
}
|
||||
if e := f.pfd.Fchmod(syscallMode(mode)); e != nil {
|
||||
return f.wrapErr("chmod", e)
|
||||
}
|
||||
return nil
|
||||
*/
|
||||
panic("todo: os.(*File).chmod")
|
||||
}
|
||||
|
||||
// Chown changes the numeric uid and gid of the named file.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
//
|
||||
// On Windows, it always returns the syscall.EWINDOWS error, wrapped
|
||||
// in *PathError.
|
||||
func (f *File) Chown(uid, gid int) error {
|
||||
/*
|
||||
if err := f.checkValid("chown"); err != nil {
|
||||
return err
|
||||
}
|
||||
if e := f.pfd.Fchown(uid, gid); e != nil {
|
||||
return f.wrapErr("chown", e)
|
||||
}
|
||||
return nil
|
||||
*/
|
||||
panic("todo: os.(*File).Chown")
|
||||
}
|
||||
|
||||
// Truncate changes the size of the file.
|
||||
// It does not change the I/O offset.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func (f *File) Truncate(size int64) error {
|
||||
/*
|
||||
if err := f.checkValid("truncate"); err != nil {
|
||||
return err
|
||||
}
|
||||
if e := f.pfd.Ftruncate(size); e != nil {
|
||||
return f.wrapErr("truncate", e)
|
||||
}
|
||||
return nil
|
||||
*/
|
||||
panic("todo: os.(*File).Truncate")
|
||||
}
|
||||
|
||||
// Sync commits the current contents of the file to stable storage.
|
||||
// Typically, this means flushing the file system's in-memory copy
|
||||
// of recently written data to disk.
|
||||
func (f *File) Sync() error {
|
||||
/*
|
||||
if err := f.checkValid("sync"); err != nil {
|
||||
return err
|
||||
}
|
||||
if e := f.pfd.Fsync(); e != nil {
|
||||
return f.wrapErr("sync", e)
|
||||
}
|
||||
return nil
|
||||
*/
|
||||
panic("todo: os.(*File).Sync")
|
||||
}
|
||||
|
||||
/*
|
||||
// Chtimes changes the access and modification times of the named
|
||||
// file, similar to the Unix utime() or utimes() functions.
|
||||
// A zero time.Time value will leave the corresponding file time unchanged.
|
||||
//
|
||||
// The underlying filesystem may truncate or round the values to a
|
||||
// less precise time unit.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func Chtimes(name string, atime time.Time, mtime time.Time) error {
|
||||
var utimes [2]syscall.Timespec
|
||||
set := func(i int, t time.Time) {
|
||||
if t.IsZero() {
|
||||
utimes[i] = syscall.Timespec{Sec: _UTIME_OMIT, Nsec: _UTIME_OMIT}
|
||||
} else {
|
||||
utimes[i] = syscall.NsecToTimespec(t.UnixNano())
|
||||
}
|
||||
}
|
||||
set(0, atime)
|
||||
set(1, mtime)
|
||||
if e := syscall.UtimesNano(fixLongPath(name), utimes[0:]); e != nil {
|
||||
return &PathError{Op: "chtimes", Path: name, Err: e}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
|
||||
// Chdir changes the current working directory to the file,
|
||||
// which must be a directory.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func (f *File) Chdir() error {
|
||||
/*
|
||||
if err := f.checkValid("chdir"); err != nil {
|
||||
return err
|
||||
}
|
||||
if e := f.pfd.Fchdir(); e != nil {
|
||||
return f.wrapErr("chdir", e)
|
||||
}
|
||||
return nil
|
||||
*/
|
||||
panic("todo: os.(*File).Chdir")
|
||||
}
|
||||
|
||||
// setDeadline sets the read and write deadline.
|
||||
func (f *File) setDeadline(t time.Time) error {
|
||||
/*
|
||||
if err := f.checkValid("SetDeadline"); err != nil {
|
||||
return err
|
||||
}
|
||||
return f.pfd.SetDeadline(t)
|
||||
*/
|
||||
panic("todo: os.(*File).setDeadline")
|
||||
}
|
||||
|
||||
// setReadDeadline sets the read deadline.
|
||||
func (f *File) setReadDeadline(t time.Time) error {
|
||||
/*
|
||||
if err := f.checkValid("SetReadDeadline"); err != nil {
|
||||
return err
|
||||
}
|
||||
return f.pfd.SetReadDeadline(t)
|
||||
*/
|
||||
panic("todo: os.(*File).setReadDeadline")
|
||||
}
|
||||
|
||||
// setWriteDeadline sets the write deadline.
|
||||
func (f *File) setWriteDeadline(t time.Time) error {
|
||||
/*
|
||||
if err := f.checkValid("SetWriteDeadline"); err != nil {
|
||||
return err
|
||||
}
|
||||
return f.pfd.SetWriteDeadline(t)
|
||||
*/
|
||||
panic("todo: os.(*File).setWriteDeadline")
|
||||
}
|
||||
|
||||
// checkValid checks whether f is valid for use.
|
||||
// If not, it returns an appropriate error, perhaps incorporating the operation name op.
|
||||
func (f *File) checkValid(op string) error {
|
||||
if f == nil {
|
||||
return ErrInvalid
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ignoringEINTR makes a function call and repeats it if it returns an
|
||||
// EINTR error. This appears to be required even though we install all
|
||||
// signal handlers with SA_RESTART: see #22838, #38033, #38836, #40846.
|
||||
// Also #20400 and #36644 are issues in which a signal handler is
|
||||
// installed without setting SA_RESTART. None of these are the common case,
|
||||
// but there are enough of them that it seems that we can't avoid
|
||||
// an EINTR loop.
|
||||
func ignoringEINTR(fn func() error) error {
|
||||
for {
|
||||
err := fn()
|
||||
if err != syscall.EINTR {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,334 +0,0 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
//go:build unix || (js && wasm) || wasip1
|
||||
|
||||
package os
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"syscall"
|
||||
|
||||
"github.com/goplus/llgo/compiler/internal/lib/internal/syscall/unix"
|
||||
)
|
||||
|
||||
// Fd returns the integer Unix file descriptor referencing the open file.
|
||||
// If f is closed, the file descriptor becomes invalid.
|
||||
// If f is garbage collected, a finalizer may close the file descriptor,
|
||||
// making it invalid; see runtime.SetFinalizer for more information on when
|
||||
// a finalizer might be run. On Unix systems this will cause the SetDeadline
|
||||
// methods to stop working.
|
||||
// Because file descriptors can be reused, the returned file descriptor may
|
||||
// only be closed through the Close method of f, or by its finalizer during
|
||||
// garbage collection. Otherwise, during garbage collection the finalizer
|
||||
// may close an unrelated file descriptor with the same (reused) number.
|
||||
//
|
||||
// As an alternative, see the f.SyscallConn method.
|
||||
func (f *File) Fd() uintptr {
|
||||
if f == nil {
|
||||
return ^(uintptr(0))
|
||||
}
|
||||
|
||||
return f.fd
|
||||
}
|
||||
|
||||
func NewFile(fd uintptr, name string) *File {
|
||||
return &File{fd: fd, name: name}
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
// NewFile returns a new File with the given file descriptor and
|
||||
// name. The returned value will be nil if fd is not a valid file
|
||||
// descriptor. On Unix systems, if the file descriptor is in
|
||||
// non-blocking mode, NewFile will attempt to return a pollable File
|
||||
// (one for which the SetDeadline methods work).
|
||||
//
|
||||
// After passing it to NewFile, fd may become invalid under the same
|
||||
// conditions described in the comments of the Fd method, and the same
|
||||
// constraints apply.
|
||||
func NewFile(fd uintptr, name string) *File {
|
||||
fdi := int(fd)
|
||||
if fdi < 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
kind := kindNewFile
|
||||
appendMode := false
|
||||
if flags, err := unix.Fcntl(fdi, syscall.F_GETFL, 0); err == nil {
|
||||
if unix.HasNonblockFlag(flags) {
|
||||
kind = kindNonBlock
|
||||
}
|
||||
appendMode = flags&syscall.O_APPEND != 0
|
||||
}
|
||||
f := newFile(fdi, name, kind)
|
||||
f.appendMode = appendMode
|
||||
return f
|
||||
}
|
||||
|
||||
// net_newUnixFile is a hidden entry point called by net.conn.File.
|
||||
// This is used so that a nonblocking network connection will become
|
||||
// blocking if code calls the Fd method. We don't want that for direct
|
||||
// calls to NewFile: passing a nonblocking descriptor to NewFile should
|
||||
// remain nonblocking if you get it back using Fd. But for net.conn.File
|
||||
// the call to NewFile is hidden from the user. Historically in that case
|
||||
// the Fd method has returned a blocking descriptor, and we want to
|
||||
// retain that behavior because existing code expects it and depends on it.
|
||||
//
|
||||
//-go:linkname net_newUnixFile net.newUnixFile
|
||||
func net_newUnixFile(fd int, name string) *File {
|
||||
if fd < 0 {
|
||||
panic("invalid FD")
|
||||
}
|
||||
|
||||
f := newFile(fd, name, kindNonBlock)
|
||||
f.nonblock = true // tell Fd to return blocking descriptor
|
||||
return f
|
||||
}
|
||||
*/
|
||||
|
||||
// newFileKind describes the kind of file to newFile.
|
||||
type newFileKind int
|
||||
|
||||
const (
|
||||
// kindNewFile means that the descriptor was passed to us via NewFile.
|
||||
kindNewFile newFileKind = iota
|
||||
// kindOpenFile means that the descriptor was opened using
|
||||
// Open, Create, or OpenFile (without O_NONBLOCK).
|
||||
kindOpenFile
|
||||
// kindPipe means that the descriptor was opened using Pipe.
|
||||
kindPipe
|
||||
// kindNonBlock means that the descriptor is already in
|
||||
// non-blocking mode.
|
||||
kindNonBlock
|
||||
// kindNoPoll means that we should not put the descriptor into
|
||||
// non-blocking mode, because we know it is not a pipe or FIFO.
|
||||
// Used by openFdAt for directories.
|
||||
kindNoPoll
|
||||
)
|
||||
|
||||
// newFile is like NewFile, but if called from OpenFile or Pipe
|
||||
// (as passed in the kind parameter) it tries to add the file to
|
||||
// the runtime poller.
|
||||
func newFile(fd int, name string, kind newFileKind) *File {
|
||||
f := &File{
|
||||
fd: uintptr(fd),
|
||||
name: name,
|
||||
stdoutOrErr: fd == 1 || fd == 2,
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
pollable := kind == kindOpenFile || kind == kindPipe || kind == kindNonBlock
|
||||
|
||||
// If the caller passed a non-blocking filedes (kindNonBlock),
|
||||
// we assume they know what they are doing so we allow it to be
|
||||
// used with kqueue.
|
||||
if kind == kindOpenFile {
|
||||
switch runtime.GOOS {
|
||||
case "darwin", "ios", "dragonfly", "freebsd", "netbsd", "openbsd":
|
||||
var st syscall.Stat_t
|
||||
err := ignoringEINTR(func() error {
|
||||
return syscall.Fstat(fd, &st)
|
||||
})
|
||||
typ := st.Mode & syscall.S_IFMT
|
||||
// Don't try to use kqueue with regular files on *BSDs.
|
||||
// On FreeBSD a regular file is always
|
||||
// reported as ready for writing.
|
||||
// On Dragonfly, NetBSD and OpenBSD the fd is signaled
|
||||
// only once as ready (both read and write).
|
||||
// Issue 19093.
|
||||
// Also don't add directories to the netpoller.
|
||||
if err == nil && (typ == syscall.S_IFREG || typ == syscall.S_IFDIR) {
|
||||
pollable = false
|
||||
}
|
||||
|
||||
// In addition to the behavior described above for regular files,
|
||||
// on Darwin, kqueue does not work properly with fifos:
|
||||
// closing the last writer does not cause a kqueue event
|
||||
// for any readers. See issue #24164.
|
||||
if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && typ == syscall.S_IFIFO {
|
||||
pollable = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clearNonBlock := false
|
||||
if pollable {
|
||||
if kind == kindNonBlock {
|
||||
// The descriptor is already in non-blocking mode.
|
||||
// We only set f.nonblock if we put the file into
|
||||
// non-blocking mode.
|
||||
} else if err := syscall.SetNonblock(fd, true); err == nil {
|
||||
f.nonblock = true
|
||||
clearNonBlock = true
|
||||
} else {
|
||||
pollable = false
|
||||
}
|
||||
}
|
||||
|
||||
// An error here indicates a failure to register
|
||||
// with the netpoll system. That can happen for
|
||||
// a file descriptor that is not supported by
|
||||
// epoll/kqueue; for example, disk files on
|
||||
// Linux systems. We assume that any real error
|
||||
// will show up in later I/O.
|
||||
// We do restore the blocking behavior if it was set by us.
|
||||
if pollErr := f.pfd.Init("file", pollable); pollErr != nil && clearNonBlock {
|
||||
if err := syscall.SetNonblock(fd, false); err == nil {
|
||||
f.nonblock = false
|
||||
}
|
||||
}
|
||||
|
||||
runtime.SetFinalizer(f.file, (*file).close)
|
||||
*/
|
||||
return f
|
||||
}
|
||||
|
||||
// TODO(xsw):
|
||||
// func sigpipe() // implemented in package runtime
|
||||
|
||||
// epipecheck raises SIGPIPE if we get an EPIPE error on standard
|
||||
// output or standard error. See the SIGPIPE docs in os/signal, and
|
||||
// issue 11845.
|
||||
func epipecheck(file *File, e error) {
|
||||
/* TODO(xsw):
|
||||
if e == syscall.EPIPE && file.stdoutOrErr {
|
||||
sigpipe()
|
||||
}
|
||||
*/
|
||||
panic("todo: os.epipecheck")
|
||||
}
|
||||
|
||||
// DevNull is the name of the operating system's “null device.”
|
||||
// On Unix-like systems, it is "/dev/null"; on Windows, "NUL".
|
||||
const DevNull = "/dev/null"
|
||||
|
||||
// openFileNolog is the Unix implementation of OpenFile.
|
||||
// Changes here should be reflected in openFdAt, if relevant.
|
||||
func openFileNolog(name string, flag int, perm FileMode) (*File, error) {
|
||||
setSticky := false
|
||||
if !supportsCreateWithStickyBit && flag&O_CREATE != 0 && perm&ModeSticky != 0 {
|
||||
if _, err := Stat(name); IsNotExist(err) {
|
||||
setSticky = true
|
||||
}
|
||||
}
|
||||
|
||||
var r int
|
||||
for {
|
||||
var e error
|
||||
r, e = syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
|
||||
if e == nil {
|
||||
break
|
||||
}
|
||||
|
||||
// We have to check EINTR here, per issues 11180 and 39237.
|
||||
if e == syscall.EINTR {
|
||||
continue
|
||||
}
|
||||
|
||||
return nil, &PathError{Op: "open", Path: name, Err: e}
|
||||
}
|
||||
|
||||
// open(2) itself won't handle the sticky bit on *BSD and Solaris
|
||||
if setSticky {
|
||||
setStickyBit(name)
|
||||
}
|
||||
|
||||
// There's a race here with fork/exec, which we are
|
||||
// content to live with. See ../syscall/exec_unix.go.
|
||||
if !supportsCloseOnExec {
|
||||
syscall.CloseOnExec(r)
|
||||
}
|
||||
|
||||
kind := kindOpenFile
|
||||
if unix.HasNonblockFlag(flag) {
|
||||
kind = kindNonBlock
|
||||
panic("todo: os.openFileNolog: unix.HasNonblockFlag")
|
||||
}
|
||||
|
||||
f := newFile(r, name, kind)
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (file *File) close() error {
|
||||
return syscall.Close(int(file.fd))
|
||||
/* TODO(xsw):
|
||||
if file.dirinfo != nil {
|
||||
file.dirinfo.close()
|
||||
file.dirinfo = nil
|
||||
}
|
||||
var err error
|
||||
if e := file.pfd.Close(); e != nil {
|
||||
if e == poll.ErrFileClosing {
|
||||
e = ErrClosed
|
||||
}
|
||||
err = &PathError{Op: "close", Path: file.name, Err: e}
|
||||
}
|
||||
|
||||
// no need for a finalizer anymore
|
||||
runtime.SetFinalizer(file, nil)
|
||||
return err
|
||||
*/
|
||||
}
|
||||
|
||||
func tempDir() string {
|
||||
dir := Getenv("TMPDIR")
|
||||
if dir == "" {
|
||||
if runtime.GOOS == "android" {
|
||||
dir = "/data/local/tmp"
|
||||
} else {
|
||||
dir = "/tmp"
|
||||
}
|
||||
}
|
||||
return dir
|
||||
}
|
||||
|
||||
type unixDirent struct {
|
||||
parent string
|
||||
name string
|
||||
typ FileMode
|
||||
info FileInfo
|
||||
}
|
||||
|
||||
func (d *unixDirent) Name() string { return d.name }
|
||||
func (d *unixDirent) IsDir() bool { return d.typ.IsDir() }
|
||||
func (d *unixDirent) Type() FileMode { return d.typ }
|
||||
|
||||
func (d *unixDirent) Info() (FileInfo, error) {
|
||||
/* TODO(xsw):
|
||||
if d.info != nil {
|
||||
return d.info, nil
|
||||
}
|
||||
return lstat(d.parent + "/" + d.name)
|
||||
*/
|
||||
panic("todo: os.unixDirent.Info")
|
||||
}
|
||||
|
||||
func (d *unixDirent) String() string {
|
||||
/* TODO(xsw):
|
||||
return fs.FormatDirEntry(d)
|
||||
*/
|
||||
panic("todo: os.unixDirent.String")
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
func newUnixDirent(parent, name string, typ FileMode) (DirEntry, error) {
|
||||
ude := &unixDirent{
|
||||
parent: parent,
|
||||
name: name,
|
||||
typ: typ,
|
||||
}
|
||||
if typ != ^FileMode(0) && !testingForceReadDirLstat {
|
||||
return ude, nil
|
||||
}
|
||||
|
||||
info, err := lstat(parent + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ude.typ = info.Mode().Type()
|
||||
ude.info = info
|
||||
return ude, nil
|
||||
}
|
||||
*/
|
||||
@@ -1,464 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package os
|
||||
|
||||
// llgo:skipall
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
"syscall"
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/os"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = true
|
||||
)
|
||||
|
||||
// LinkError records an error during a link or symlink or rename
|
||||
// system call and the paths that caused it.
|
||||
type LinkError struct {
|
||||
Op string
|
||||
Old string
|
||||
New string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *LinkError) Error() string {
|
||||
return e.Op + " " + e.Old + " " + e.New + ": " + e.Err.Error()
|
||||
}
|
||||
|
||||
func (e *LinkError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
func toPathErr(op, path string, errno c.Int) error {
|
||||
return &PathError{Op: op, Path: path, Err: syscall.Errno(errno)}
|
||||
}
|
||||
|
||||
func Chdir(dir string) error {
|
||||
ret := os.Chdir(c.AllocaCStr(dir))
|
||||
if ret == 0 {
|
||||
return nil
|
||||
}
|
||||
return toPathErr("chdir", dir, ret)
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
// Chdir changes the current working directory to the named directory.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func Chdir(dir string) error {
|
||||
if e := syscall.Chdir(dir); e != nil {
|
||||
testlog.Open(dir) // observe likely non-existent directory
|
||||
return &PathError{Op: "chdir", Path: dir, Err: e}
|
||||
}
|
||||
if log := testlog.Logger(); log != nil {
|
||||
wd, err := Getwd()
|
||||
if err == nil {
|
||||
log.Chdir(wd)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
|
||||
func Chmod(name string, mode FileMode) error {
|
||||
ret := os.Chmod(c.AllocaCStr(name), os.ModeT(syscallMode(mode)))
|
||||
if ret == 0 {
|
||||
return nil
|
||||
}
|
||||
return toPathErr("chmod", name, ret)
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
// Chmod changes the mode of the named file to mode.
|
||||
// If the file is a symbolic link, it changes the mode of the link's target.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
//
|
||||
// A different subset of the mode bits are used, depending on the
|
||||
// operating system.
|
||||
//
|
||||
// On Unix, the mode's permission bits, ModeSetuid, ModeSetgid, and
|
||||
// ModeSticky are used.
|
||||
//
|
||||
// On Windows, only the 0200 bit (owner writable) of mode is used; it
|
||||
// controls whether the file's read-only attribute is set or cleared.
|
||||
// The other bits are currently unused. For compatibility with Go 1.12
|
||||
// and earlier, use a non-zero mode. Use mode 0400 for a read-only
|
||||
// file and 0600 for a readable+writable file.
|
||||
//
|
||||
// On Plan 9, the mode's permission bits, ModeAppend, ModeExclusive,
|
||||
// and ModeTemporary are used.
|
||||
func Chmod(name string, mode FileMode) error { return chmod(name, mode) }
|
||||
*/
|
||||
|
||||
func Chown(name string, uid, gid int) error {
|
||||
ret := os.Chown(c.AllocaCStr(name), os.UidT(uid), os.GidT(gid))
|
||||
if ret == 0 {
|
||||
return nil
|
||||
}
|
||||
return toPathErr("chown", name, ret)
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
// Chown changes the numeric uid and gid of the named file.
|
||||
// If the file is a symbolic link, it changes the uid and gid of the link's target.
|
||||
// A uid or gid of -1 means to not change that value.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
//
|
||||
// On Windows or Plan 9, Chown always returns the syscall.EWINDOWS or
|
||||
// EPLAN9 error, wrapped in *PathError.
|
||||
func Chown(name string, uid, gid int) error {
|
||||
e := ignoringEINTR(func() error {
|
||||
return syscall.Chown(name, uid, gid)
|
||||
})
|
||||
if e != nil {
|
||||
return &PathError{Op: "chown", Path: name, Err: e}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
|
||||
// TODO(xsw):
|
||||
// func Chtimes(name string, atime time.Time, mtime time.Time) error
|
||||
|
||||
//go:linkname Clearenv C.clearenv
|
||||
func Clearenv()
|
||||
|
||||
// TODO(xsw):
|
||||
// func DirFS(dir string) fs.FS
|
||||
|
||||
// func Executable() (string, error)
|
||||
|
||||
// TODO(xsw):
|
||||
// func Expand(s string, mapping func(string) string) string
|
||||
// func ExpandEnv(s string) string
|
||||
|
||||
func Getegid() int {
|
||||
return int(os.Getegid())
|
||||
}
|
||||
|
||||
func Geteuid() int {
|
||||
return int(os.Geteuid())
|
||||
}
|
||||
|
||||
func Getgid() int {
|
||||
return int(os.Getgid())
|
||||
}
|
||||
|
||||
// TODO(xsw):
|
||||
// func Getgroups() ([]int, error)
|
||||
// func Getpagesize() int
|
||||
|
||||
func Getpid() int {
|
||||
return int(os.Getpid())
|
||||
}
|
||||
|
||||
func Getppid() int {
|
||||
return int(os.Getppid())
|
||||
}
|
||||
|
||||
func Getuid() int {
|
||||
return int(os.Getuid())
|
||||
}
|
||||
|
||||
func Getwd() (dir string, err error) {
|
||||
wd := os.Getcwd(c.Alloca(os.PATH_MAX), os.PATH_MAX)
|
||||
if wd != nil {
|
||||
return c.GoString(wd), nil
|
||||
}
|
||||
return "", syscall.Errno(os.Errno())
|
||||
}
|
||||
|
||||
// TODO(xsw):
|
||||
// func Hostname() (name string, err error)
|
||||
// func IsExist(err error) bool
|
||||
// func IsNotExist(err error) bool
|
||||
// func IsPermission(err error) bool
|
||||
// func IsTimeout(err error) bool
|
||||
|
||||
func Lchown(name string, uid, gid int) error {
|
||||
ret := os.Lchown(c.AllocaCStr(name), os.UidT(uid), os.GidT(gid))
|
||||
if ret == 0 {
|
||||
return nil
|
||||
}
|
||||
return toPathErr("lchown", name, ret)
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
// Lchown changes the numeric uid and gid of the named file.
|
||||
// If the file is a symbolic link, it changes the uid and gid of the link itself.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
//
|
||||
// On Windows, it always returns the syscall.EWINDOWS error, wrapped
|
||||
// in *PathError.
|
||||
func Lchown(name string, uid, gid int) error {
|
||||
e := ignoringEINTR(func() error {
|
||||
return syscall.Lchown(name, uid, gid)
|
||||
})
|
||||
if e != nil {
|
||||
return &PathError{Op: "lchown", Path: name, Err: e}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
|
||||
func Link(oldname, newname string) error {
|
||||
ret := os.Link(c.AllocaCStr(oldname), c.AllocaCStr(newname))
|
||||
if ret == 0 {
|
||||
return nil
|
||||
}
|
||||
return &LinkError{"link", oldname, newname, syscall.Errno(ret)}
|
||||
}
|
||||
|
||||
// TODO(xsw):
|
||||
// func LookupEnv(key string) (string, bool)
|
||||
|
||||
func Mkdir(name string, perm FileMode) error {
|
||||
ret := os.Mkdir(c.AllocaCStr(name), os.ModeT(syscallMode(perm)))
|
||||
if ret == 0 {
|
||||
return nil
|
||||
}
|
||||
return toPathErr("mkdir", name, ret)
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
// Mkdir creates a new directory with the specified name and permission
|
||||
// bits (before umask).
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func Mkdir(name string, perm FileMode) error {
|
||||
longName := fixLongPath(name)
|
||||
e := ignoringEINTR(func() error {
|
||||
return syscall.Mkdir(longName, syscallMode(perm))
|
||||
})
|
||||
|
||||
if e != nil {
|
||||
return &PathError{Op: "mkdir", Path: name, Err: e}
|
||||
}
|
||||
|
||||
// mkdir(2) itself won't handle the sticky bit on *BSD and Solaris
|
||||
if !supportsCreateWithStickyBit && perm&ModeSticky != 0 {
|
||||
e = setStickyBit(name)
|
||||
|
||||
if e != nil {
|
||||
Remove(name)
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
|
||||
// TODO(xsw):
|
||||
// func NewSyscallError(syscall string, err error) error
|
||||
|
||||
// func ReadFile(name string) ([]byte, error)
|
||||
|
||||
func Readlink(name string) (string, error) {
|
||||
ptr := c.Alloca(os.PATH_MAX)
|
||||
ret := os.Readlink(c.AllocaCStr(name), ptr, os.PATH_MAX)
|
||||
if ret < os.PATH_MAX {
|
||||
return c.GoString((*c.Char)(ptr), ret), nil
|
||||
}
|
||||
panic("todo: buffer too small")
|
||||
}
|
||||
|
||||
func Remove(name string) error {
|
||||
ret := os.Remove(c.AllocaCStr(name))
|
||||
if ret == 0 {
|
||||
return nil
|
||||
}
|
||||
return toPathErr("remove", name, ret)
|
||||
}
|
||||
|
||||
// TODO(xsw):
|
||||
// func RemoveAll(path string) error
|
||||
|
||||
func Rename(oldpath, newpath string) error {
|
||||
ret := os.Rename(c.AllocaCStr(oldpath), c.AllocaCStr(newpath))
|
||||
if ret == 0 {
|
||||
return nil
|
||||
}
|
||||
return &LinkError{"rename", oldpath, newpath, syscall.Errno(ret)}
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
// Rename renames (moves) oldpath to newpath.
|
||||
// If newpath already exists and is not a directory, Rename replaces it.
|
||||
// OS-specific restrictions may apply when oldpath and newpath are in different directories.
|
||||
// Even within the same directory, on non-Unix platforms Rename is not an atomic operation.
|
||||
// If there is an error, it will be of type *LinkError.
|
||||
func Rename(oldpath, newpath string) error {
|
||||
return rename(oldpath, newpath)
|
||||
}
|
||||
*/
|
||||
|
||||
// TODO(xsw):
|
||||
// func SameFile(fi1, fi2 FileInfo) bool
|
||||
|
||||
func Symlink(oldname, newname string) error {
|
||||
ret := os.Symlink(c.AllocaCStr(oldname), c.AllocaCStr(newname))
|
||||
if ret == 0 {
|
||||
return nil
|
||||
}
|
||||
return &LinkError{"symlink", oldname, newname, syscall.Errno(ret)}
|
||||
}
|
||||
|
||||
func Truncate(name string, size int64) error {
|
||||
ret := os.Truncate(c.AllocaCStr(name), os.OffT(size))
|
||||
if ret == 0 {
|
||||
return nil
|
||||
}
|
||||
return toPathErr("truncate", name, ret)
|
||||
}
|
||||
|
||||
// UserCacheDir returns the default root directory to use for user-specific
|
||||
// cached data. Users should create their own application-specific subdirectory
|
||||
// within this one and use that.
|
||||
//
|
||||
// On Unix systems, it returns $XDG_CACHE_HOME as specified by
|
||||
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html if
|
||||
// non-empty, else $HOME/.cache.
|
||||
// On Darwin, it returns $HOME/Library/Caches.
|
||||
// On Windows, it returns %LocalAppData%.
|
||||
// On Plan 9, it returns $home/lib/cache.
|
||||
//
|
||||
// If the location cannot be determined (for example, $HOME is not defined),
|
||||
// then it will return an error.
|
||||
func UserCacheDir() (string, error) {
|
||||
var dir string
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
dir = Getenv("LocalAppData")
|
||||
if dir == "" {
|
||||
return "", errors.New("%LocalAppData% is not defined")
|
||||
}
|
||||
|
||||
case "darwin", "ios":
|
||||
dir = Getenv("HOME")
|
||||
if dir == "" {
|
||||
return "", errors.New("$HOME is not defined")
|
||||
}
|
||||
dir += "/Library/Caches"
|
||||
|
||||
case "plan9":
|
||||
dir = Getenv("home")
|
||||
if dir == "" {
|
||||
return "", errors.New("$home is not defined")
|
||||
}
|
||||
dir += "/lib/cache"
|
||||
|
||||
default: // Unix
|
||||
dir = Getenv("XDG_CACHE_HOME")
|
||||
if dir == "" {
|
||||
dir = Getenv("HOME")
|
||||
if dir == "" {
|
||||
return "", errors.New("neither $XDG_CACHE_HOME nor $HOME are defined")
|
||||
}
|
||||
dir += "/.cache"
|
||||
}
|
||||
}
|
||||
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
// UserConfigDir returns the default root directory to use for user-specific
|
||||
// configuration data. Users should create their own application-specific
|
||||
// subdirectory within this one and use that.
|
||||
//
|
||||
// On Unix systems, it returns $XDG_CONFIG_HOME as specified by
|
||||
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html if
|
||||
// non-empty, else $HOME/.config.
|
||||
// On Darwin, it returns $HOME/Library/Application Support.
|
||||
// On Windows, it returns %AppData%.
|
||||
// On Plan 9, it returns $home/lib.
|
||||
//
|
||||
// If the location cannot be determined (for example, $HOME is not defined),
|
||||
// then it will return an error.
|
||||
func UserConfigDir() (string, error) {
|
||||
var dir string
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
dir = Getenv("AppData")
|
||||
if dir == "" {
|
||||
return "", errors.New("%AppData% is not defined")
|
||||
}
|
||||
|
||||
case "darwin", "ios":
|
||||
dir = Getenv("HOME")
|
||||
if dir == "" {
|
||||
return "", errors.New("$HOME is not defined")
|
||||
}
|
||||
dir += "/Library/Application Support"
|
||||
|
||||
case "plan9":
|
||||
dir = Getenv("home")
|
||||
if dir == "" {
|
||||
return "", errors.New("$home is not defined")
|
||||
}
|
||||
dir += "/lib"
|
||||
|
||||
default: // Unix
|
||||
dir = Getenv("XDG_CONFIG_HOME")
|
||||
if dir == "" {
|
||||
dir = Getenv("HOME")
|
||||
if dir == "" {
|
||||
return "", errors.New("neither $XDG_CONFIG_HOME nor $HOME are defined")
|
||||
}
|
||||
dir += "/.config"
|
||||
}
|
||||
}
|
||||
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
// UserHomeDir returns the current user's home directory.
|
||||
//
|
||||
// On Unix, including macOS, it returns the $HOME environment variable.
|
||||
// On Windows, it returns %USERPROFILE%.
|
||||
// On Plan 9, it returns the $home environment variable.
|
||||
//
|
||||
// If the expected variable is not set in the environment, UserHomeDir
|
||||
// returns either a platform-specific default value or a non-nil error.
|
||||
func UserHomeDir() (string, error) {
|
||||
env, enverr := "HOME", "$HOME"
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
env, enverr = "USERPROFILE", "%userprofile%"
|
||||
case "plan9":
|
||||
env, enverr = "home", "$home"
|
||||
}
|
||||
if v := Getenv(env); v != "" {
|
||||
return v, nil
|
||||
}
|
||||
// On some geese the home directory is not always defined.
|
||||
switch runtime.GOOS {
|
||||
case "android":
|
||||
return "/sdcard", nil
|
||||
case "ios":
|
||||
return "/", nil
|
||||
}
|
||||
return "", errors.New(enverr + " is not defined")
|
||||
}
|
||||
|
||||
// TODO(xsw):
|
||||
// func WriteFile(name string, data []byte, perm FileMode) error
|
||||
@@ -1,55 +0,0 @@
|
||||
package os
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// MkdirAll creates a directory named path,
|
||||
// along with any necessary parents, and returns nil,
|
||||
// or else returns an error.
|
||||
// The permission bits perm (before umask) are used for all
|
||||
// directories that MkdirAll creates.
|
||||
// If path is already a directory, MkdirAll does nothing
|
||||
// and returns nil.
|
||||
func MkdirAll(path string, perm FileMode) error {
|
||||
// Fast path: if we can tell whether path is a directory or file, stop with success or error.
|
||||
dir, err := Stat(path)
|
||||
if err == nil {
|
||||
if dir.IsDir() {
|
||||
return nil
|
||||
}
|
||||
return &PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR}
|
||||
}
|
||||
|
||||
// Slow path: make sure parent exists and then call Mkdir for path.
|
||||
i := len(path)
|
||||
for i > 0 && IsPathSeparator(path[i-1]) { // Skip trailing path separator.
|
||||
i--
|
||||
}
|
||||
|
||||
j := i
|
||||
for j > 0 && !IsPathSeparator(path[j-1]) { // Scan backward over element.
|
||||
j--
|
||||
}
|
||||
|
||||
if j > 1 {
|
||||
// Create parent.
|
||||
err = MkdirAll(fixRootDirectory(path[:j-1]), perm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Parent now exists; invoke Mkdir and use its result.
|
||||
err = Mkdir(path, perm)
|
||||
if err != nil {
|
||||
// Handle arguments like "foo/." by
|
||||
// double-checking that directory doesn't exist.
|
||||
dir, err1 := Lstat(path)
|
||||
if err1 == nil && dir.IsDir() {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright 2011 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 os
|
||||
|
||||
const (
|
||||
PathSeparator = '/' // OS-specific path separator
|
||||
PathListSeparator = '\000' // OS-specific path list separator
|
||||
)
|
||||
|
||||
// IsPathSeparator reports whether c is a directory separator character.
|
||||
func IsPathSeparator(c uint8) bool {
|
||||
return PathSeparator == c
|
||||
}
|
||||
|
||||
func fixRootDirectory(p string) string {
|
||||
return p
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
//go:build unix || (js && wasm) || wasip1
|
||||
|
||||
package os
|
||||
|
||||
const (
|
||||
PathSeparator = '/' // OS-specific path separator
|
||||
PathListSeparator = ':' // OS-specific path list separator
|
||||
)
|
||||
|
||||
// IsPathSeparator reports whether c is a directory separator character.
|
||||
func IsPathSeparator(c uint8) bool {
|
||||
return PathSeparator == c
|
||||
}
|
||||
|
||||
// basename removes trailing slashes and the leading directory name from path name.
|
||||
func basename(name string) string {
|
||||
i := len(name) - 1
|
||||
// Remove trailing slashes
|
||||
for ; i > 0 && name[i] == '/'; i-- {
|
||||
name = name[:i]
|
||||
}
|
||||
// Remove leading directory name
|
||||
for i--; i >= 0; i-- {
|
||||
if name[i] == '/' {
|
||||
name = name[i+1:]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
// splitPath returns the base name and parent directory.
|
||||
func splitPath(path string) (string, string) {
|
||||
// if no better parent is found, the path is relative from "here"
|
||||
dirname := "."
|
||||
|
||||
// Remove all but one leading slash.
|
||||
for len(path) > 1 && path[0] == '/' && path[1] == '/' {
|
||||
path = path[1:]
|
||||
}
|
||||
|
||||
i := len(path) - 1
|
||||
|
||||
// Remove trailing slashes.
|
||||
for ; i > 0 && path[i] == '/'; i-- {
|
||||
path = path[:i]
|
||||
}
|
||||
|
||||
// if no slashes in path, base is path
|
||||
basename := path
|
||||
|
||||
// Remove leading directory path
|
||||
for i--; i >= 0; i-- {
|
||||
if path[i] == '/' {
|
||||
if i == 0 {
|
||||
dirname = path[:1]
|
||||
} else {
|
||||
dirname = path[:i]
|
||||
}
|
||||
basename = path[i+1:]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return dirname, basename
|
||||
}
|
||||
|
||||
func fixRootDirectory(p string) string {
|
||||
return p
|
||||
}
|
||||
@@ -1,227 +0,0 @@
|
||||
// Copyright 2011 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 os
|
||||
|
||||
const (
|
||||
PathSeparator = '\\' // OS-specific path separator
|
||||
PathListSeparator = ';' // OS-specific path list separator
|
||||
)
|
||||
|
||||
// IsPathSeparator reports whether c is a directory separator character.
|
||||
func IsPathSeparator(c uint8) bool {
|
||||
// NOTE: Windows accepts / as path separator.
|
||||
return c == '\\' || c == '/'
|
||||
}
|
||||
|
||||
// basename removes trailing slashes and the leading
|
||||
// directory name and drive letter from path name.
|
||||
func basename(name string) string {
|
||||
// Remove drive letter
|
||||
if len(name) == 2 && name[1] == ':' {
|
||||
name = "."
|
||||
} else if len(name) > 2 && name[1] == ':' {
|
||||
name = name[2:]
|
||||
}
|
||||
i := len(name) - 1
|
||||
// Remove trailing slashes
|
||||
for ; i > 0 && (name[i] == '/' || name[i] == '\\'); i-- {
|
||||
name = name[:i]
|
||||
}
|
||||
// Remove leading directory name
|
||||
for i--; i >= 0; i-- {
|
||||
if name[i] == '/' || name[i] == '\\' {
|
||||
name = name[i+1:]
|
||||
break
|
||||
}
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func isAbs(path string) (b bool) {
|
||||
v := volumeName(path)
|
||||
if v == "" {
|
||||
return false
|
||||
}
|
||||
path = path[len(v):]
|
||||
if path == "" {
|
||||
return false
|
||||
}
|
||||
return IsPathSeparator(path[0])
|
||||
}
|
||||
|
||||
func volumeName(path string) (v string) {
|
||||
if len(path) < 2 {
|
||||
return ""
|
||||
}
|
||||
// with drive letter
|
||||
c := path[0]
|
||||
if path[1] == ':' &&
|
||||
('0' <= c && c <= '9' || 'a' <= c && c <= 'z' ||
|
||||
'A' <= c && c <= 'Z') {
|
||||
return path[:2]
|
||||
}
|
||||
// is it UNC
|
||||
if l := len(path); l >= 5 && IsPathSeparator(path[0]) && IsPathSeparator(path[1]) &&
|
||||
!IsPathSeparator(path[2]) && path[2] != '.' {
|
||||
// first, leading `\\` and next shouldn't be `\`. its server name.
|
||||
for n := 3; n < l-1; n++ {
|
||||
// second, next '\' shouldn't be repeated.
|
||||
if IsPathSeparator(path[n]) {
|
||||
n++
|
||||
// third, following something characters. its share name.
|
||||
if !IsPathSeparator(path[n]) {
|
||||
if path[n] == '.' {
|
||||
break
|
||||
}
|
||||
for ; n < l; n++ {
|
||||
if IsPathSeparator(path[n]) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return path[:n]
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func fromSlash(path string) string {
|
||||
// Replace each '/' with '\\' if present
|
||||
var pathbuf []byte
|
||||
var lastSlash int
|
||||
for i, b := range path {
|
||||
if b == '/' {
|
||||
if pathbuf == nil {
|
||||
pathbuf = make([]byte, len(path))
|
||||
}
|
||||
copy(pathbuf[lastSlash:], path[lastSlash:i])
|
||||
pathbuf[i] = '\\'
|
||||
lastSlash = i + 1
|
||||
}
|
||||
}
|
||||
if pathbuf == nil {
|
||||
return path
|
||||
}
|
||||
|
||||
copy(pathbuf[lastSlash:], path[lastSlash:])
|
||||
return string(pathbuf)
|
||||
}
|
||||
|
||||
func dirname(path string) string {
|
||||
vol := volumeName(path)
|
||||
i := len(path) - 1
|
||||
for i >= len(vol) && !IsPathSeparator(path[i]) {
|
||||
i--
|
||||
}
|
||||
dir := path[len(vol) : i+1]
|
||||
last := len(dir) - 1
|
||||
if last > 0 && IsPathSeparator(dir[last]) {
|
||||
dir = dir[:last]
|
||||
}
|
||||
if dir == "" {
|
||||
dir = "."
|
||||
}
|
||||
return vol + dir
|
||||
}
|
||||
|
||||
// This is set via go:linkname on runtime.canUseLongPaths, and is true when the OS
|
||||
// supports opting into proper long path handling without the need for fixups.
|
||||
var canUseLongPaths bool
|
||||
|
||||
// fixLongPath returns the extended-length (\\?\-prefixed) form of
|
||||
// path when needed, in order to avoid the default 260 character file
|
||||
// path limit imposed by Windows. If path is not easily converted to
|
||||
// the extended-length form (for example, if path is a relative path
|
||||
// or contains .. elements), or is short enough, fixLongPath returns
|
||||
// path unmodified.
|
||||
//
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath
|
||||
func fixLongPath(path string) string {
|
||||
if canUseLongPaths {
|
||||
return path
|
||||
}
|
||||
// Do nothing (and don't allocate) if the path is "short".
|
||||
// Empirically (at least on the Windows Server 2013 builder),
|
||||
// the kernel is arbitrarily okay with < 248 bytes. That
|
||||
// matches what the docs above say:
|
||||
// "When using an API to create a directory, the specified
|
||||
// path cannot be so long that you cannot append an 8.3 file
|
||||
// name (that is, the directory name cannot exceed MAX_PATH
|
||||
// minus 12)." Since MAX_PATH is 260, 260 - 12 = 248.
|
||||
//
|
||||
// The MSDN docs appear to say that a normal path that is 248 bytes long
|
||||
// will work; empirically the path must be less then 248 bytes long.
|
||||
if len(path) < 248 {
|
||||
// Don't fix. (This is how Go 1.7 and earlier worked,
|
||||
// not automatically generating the \\?\ form)
|
||||
return path
|
||||
}
|
||||
|
||||
// The extended form begins with \\?\, as in
|
||||
// \\?\c:\windows\foo.txt or \\?\UNC\server\share\foo.txt.
|
||||
// The extended form disables evaluation of . and .. path
|
||||
// elements and disables the interpretation of / as equivalent
|
||||
// to \. The conversion here rewrites / to \ and elides
|
||||
// . elements as well as trailing or duplicate separators. For
|
||||
// simplicity it avoids the conversion entirely for relative
|
||||
// paths or paths containing .. elements. For now,
|
||||
// \\server\share paths are not converted to
|
||||
// \\?\UNC\server\share paths because the rules for doing so
|
||||
// are less well-specified.
|
||||
if len(path) >= 2 && path[:2] == `\\` {
|
||||
// Don't canonicalize UNC paths.
|
||||
return path
|
||||
}
|
||||
if !isAbs(path) {
|
||||
// Relative path
|
||||
return path
|
||||
}
|
||||
|
||||
const prefix = `\\?`
|
||||
|
||||
pathbuf := make([]byte, len(prefix)+len(path)+len(`\`))
|
||||
copy(pathbuf, prefix)
|
||||
n := len(path)
|
||||
r, w := 0, len(prefix)
|
||||
for r < n {
|
||||
switch {
|
||||
case IsPathSeparator(path[r]):
|
||||
// empty block
|
||||
r++
|
||||
case path[r] == '.' && (r+1 == n || IsPathSeparator(path[r+1])):
|
||||
// /./
|
||||
r++
|
||||
case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || IsPathSeparator(path[r+2])):
|
||||
// /../ is currently unhandled
|
||||
return path
|
||||
default:
|
||||
pathbuf[w] = '\\'
|
||||
w++
|
||||
for ; r < n && !IsPathSeparator(path[r]); r++ {
|
||||
pathbuf[w] = path[r]
|
||||
w++
|
||||
}
|
||||
}
|
||||
}
|
||||
// A drive's root directory needs a trailing \
|
||||
if w == len(`\\?\c:`) {
|
||||
pathbuf[w] = '\\'
|
||||
w++
|
||||
}
|
||||
return string(pathbuf[:w])
|
||||
}
|
||||
|
||||
// fixRootDirectory fixes a reference to a drive's root directory to
|
||||
// have the required trailing slash.
|
||||
func fixRootDirectory(p string) string {
|
||||
if len(p) == len(`\\?\c:`) {
|
||||
if IsPathSeparator(p[0]) && IsPathSeparator(p[1]) && p[2] == '?' && IsPathSeparator(p[3]) && p[5] == ':' {
|
||||
return p + `\`
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
//go:build dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
||||
|
||||
package os
|
||||
|
||||
import "syscall"
|
||||
|
||||
// Pipe returns a connected pair of Files; reads from r return bytes written to w.
|
||||
// It returns the files and an error, if any.
|
||||
func Pipe() (r *File, w *File, err error) {
|
||||
var p [2]int
|
||||
|
||||
e := syscall.Pipe2(p[0:], syscall.O_CLOEXEC)
|
||||
if e != nil {
|
||||
return nil, nil, NewSyscallError("pipe2", e)
|
||||
}
|
||||
|
||||
return newFile(p[0], "|0", kindPipe), newFile(p[1], "|1", kindPipe), nil
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
//go:build aix || darwin
|
||||
|
||||
package os
|
||||
|
||||
import "syscall"
|
||||
|
||||
// Pipe returns a connected pair of Files; reads from r return bytes written to w.
|
||||
// It returns the files and an error, if any.
|
||||
func Pipe() (r *File, w *File, err error) {
|
||||
var p [2]int
|
||||
|
||||
// See ../syscall/exec.go for description of lock.
|
||||
syscall.ForkLock.RLock()
|
||||
e := syscall.Pipe(p[0:])
|
||||
if e != nil {
|
||||
syscall.ForkLock.RUnlock()
|
||||
return nil, nil, NewSyscallError("pipe", e)
|
||||
}
|
||||
syscall.CloseOnExec(p[0])
|
||||
syscall.CloseOnExec(p[1])
|
||||
syscall.ForkLock.RUnlock()
|
||||
|
||||
return newFile(p[0], "|0", kindPipe), newFile(p[1], "|1", kindPipe), nil
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// 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.
|
||||
|
||||
//go:build wasm
|
||||
|
||||
package os
|
||||
|
||||
import "syscall"
|
||||
|
||||
// Pipe returns a connected pair of Files; reads from r return bytes written to w.
|
||||
// It returns the files and an error, if any.
|
||||
func Pipe() (r *File, w *File, err error) {
|
||||
// Neither GOOS=js nor GOOS=wasip1 have pipes.
|
||||
return nil, nil, NewSyscallError("pipe", syscall.ENOSYS)
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// Process etc.
|
||||
|
||||
package os
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/os"
|
||||
)
|
||||
|
||||
// Args hold the command-line arguments, starting with the program name.
|
||||
var Args []string
|
||||
|
||||
func init() {
|
||||
if runtime.GOOS == "windows" {
|
||||
// TODO(xsw): check windows implementation
|
||||
// Initialized in exec_windows.go.
|
||||
return
|
||||
}
|
||||
Args = runtimeArgs(int(c.Argc), c.Argv)
|
||||
}
|
||||
|
||||
func runtimeArgs(argc int, argv **c.Char) []string {
|
||||
args := make([]string, argc)
|
||||
for i := 0; i < argc; i++ {
|
||||
arg := *c.Advance(argv, i)
|
||||
args[i] = unsafe.String((*byte)(unsafe.Pointer(arg)), c.Strlen(arg))
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
// Getgroups returns a list of the numeric ids of groups that the caller belongs to.
|
||||
//
|
||||
// On Windows, it returns syscall.EWINDOWS. See the os/user package
|
||||
// for a possible alternative.
|
||||
func Getgroups() ([]int, error) {
|
||||
/* TODO(xsw):
|
||||
gids, e := syscall.Getgroups()
|
||||
return gids, NewSyscallError("getgroups", e)
|
||||
*/
|
||||
panic("todo: os.Getgroups")
|
||||
}
|
||||
|
||||
// Exit causes the current program to exit with the given status code.
|
||||
// Conventionally, code zero indicates success, non-zero an error.
|
||||
// The program terminates immediately; deferred functions are not run.
|
||||
//
|
||||
// For portability, the status code should be in the range [0, 125].
|
||||
func Exit(code int) {
|
||||
// Inform the runtime that os.Exit is being called. If -race is
|
||||
// enabled, this will give race detector a chance to fail the
|
||||
// program (racy programs do not have the right to finish
|
||||
// successfully). If coverage is enabled, then this call will
|
||||
// enable us to write out a coverage data file.
|
||||
// TODO(xsw):
|
||||
// runtime_beforeExit(code)
|
||||
|
||||
os.Exit(c.Int(code))
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright 2017 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 os
|
||||
|
||||
// Stat returns a FileInfo describing the named file.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func Stat(name string) (FileInfo, error) {
|
||||
return statNolog(name)
|
||||
}
|
||||
|
||||
// Lstat returns a FileInfo describing the named file.
|
||||
// If the file is a symbolic link, the returned FileInfo
|
||||
// describes the symbolic link. Lstat makes no attempt to follow the link.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func Lstat(name string) (FileInfo, error) {
|
||||
return lstatNolog(name)
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
// Copyright 2009 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 os
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/goplus/llgo/c/syscall"
|
||||
)
|
||||
|
||||
func fillFileStatFromSys(fs *fileStat, name string) {
|
||||
fs.name = basename(name)
|
||||
fs.size = fs.sys.Size
|
||||
fs.modTime = time.Unix(fs.sys.Mtimespec.Unix())
|
||||
fs.mode = FileMode(fs.sys.Mode & 0777)
|
||||
switch fs.sys.Mode & syscall.S_IFMT {
|
||||
case syscall.S_IFBLK, syscall.S_IFWHT:
|
||||
fs.mode |= ModeDevice
|
||||
case syscall.S_IFCHR:
|
||||
fs.mode |= ModeDevice | ModeCharDevice
|
||||
case syscall.S_IFDIR:
|
||||
fs.mode |= ModeDir
|
||||
case syscall.S_IFIFO:
|
||||
fs.mode |= ModeNamedPipe
|
||||
case syscall.S_IFLNK:
|
||||
fs.mode |= ModeSymlink
|
||||
case syscall.S_IFREG:
|
||||
// nothing to do
|
||||
case syscall.S_IFSOCK:
|
||||
fs.mode |= ModeSocket
|
||||
}
|
||||
if fs.sys.Mode&syscall.S_ISGID != 0 {
|
||||
fs.mode |= ModeSetgid
|
||||
}
|
||||
if fs.sys.Mode&syscall.S_ISUID != 0 {
|
||||
fs.mode |= ModeSetuid
|
||||
}
|
||||
if fs.sys.Mode&syscall.S_ISVTX != 0 {
|
||||
fs.mode |= ModeSticky
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright 2009 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 os
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func fillFileStatFromSys(fs *fileStat, name string) {
|
||||
fs.name = basename(name)
|
||||
fs.size = fs.sys.Size
|
||||
fs.modTime = time.Unix(fs.sys.Mtim.Unix())
|
||||
fs.mode = FileMode(fs.sys.Mode & 0777)
|
||||
switch fs.sys.Mode & syscall.S_IFMT {
|
||||
case syscall.S_IFBLK:
|
||||
fs.mode |= ModeDevice
|
||||
case syscall.S_IFCHR:
|
||||
fs.mode |= ModeDevice | ModeCharDevice
|
||||
case syscall.S_IFDIR:
|
||||
fs.mode |= ModeDir
|
||||
case syscall.S_IFIFO:
|
||||
fs.mode |= ModeNamedPipe
|
||||
case syscall.S_IFLNK:
|
||||
fs.mode |= ModeSymlink
|
||||
case syscall.S_IFREG:
|
||||
// nothing to do
|
||||
case syscall.S_IFSOCK:
|
||||
fs.mode |= ModeSocket
|
||||
}
|
||||
if fs.sys.Mode&syscall.S_ISGID != 0 {
|
||||
fs.mode |= ModeSetgid
|
||||
}
|
||||
if fs.sys.Mode&syscall.S_ISUID != 0 {
|
||||
fs.mode |= ModeSetuid
|
||||
}
|
||||
if fs.sys.Mode&syscall.S_ISVTX != 0 {
|
||||
fs.mode |= ModeSticky
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
//go:build unix || (js && wasm) || wasip1
|
||||
|
||||
package os
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/os"
|
||||
"github.com/goplus/llgo/compiler/internal/lib/syscall"
|
||||
)
|
||||
|
||||
// Stat returns the FileInfo structure describing file.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func (f *File) Stat() (FileInfo, error) {
|
||||
if f == nil {
|
||||
return nil, ErrInvalid
|
||||
}
|
||||
var fs fileStat
|
||||
err := os.Fstat(c.Int(f.fd), &fs.sys)
|
||||
if err != 0 {
|
||||
return nil, &PathError{Op: "stat", Path: f.name, Err: syscall.Errno(err)}
|
||||
}
|
||||
fillFileStatFromSys(&fs, f.name)
|
||||
return &fs, nil
|
||||
}
|
||||
|
||||
// statNolog stats a file with no test logging.
|
||||
func statNolog(name string) (FileInfo, error) {
|
||||
var fs fileStat
|
||||
err := ignoringEINTR(func() error {
|
||||
return syscall.Stat(name, &fs.sys)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, &PathError{Op: "stat", Path: name, Err: err}
|
||||
}
|
||||
fillFileStatFromSys(&fs, name)
|
||||
return &fs, nil
|
||||
}
|
||||
|
||||
// lstatNolog lstats a file with no test logging.
|
||||
func lstatNolog(name string) (FileInfo, error) {
|
||||
var fs fileStat
|
||||
err := ignoringEINTR(func() error {
|
||||
return syscall.Lstat(name, &fs.sys)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, &PathError{Op: "lstat", Path: name, Err: err}
|
||||
}
|
||||
fillFileStatFromSys(&fs, name)
|
||||
return &fs, nil
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || netbsd || openbsd || solaris || wasip1
|
||||
|
||||
package os
|
||||
|
||||
// According to sticky(8), neither open(2) nor mkdir(2) will create
|
||||
// a file with the sticky bit set.
|
||||
const supportsCreateWithStickyBit = false
|
||||
@@ -1,9 +0,0 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
//go:build !aix && !darwin && !dragonfly && !freebsd && !js && !netbsd && !openbsd && !solaris && !wasip1
|
||||
|
||||
package os
|
||||
|
||||
const supportsCreateWithStickyBit = true
|
||||
@@ -1,39 +0,0 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// Simple conversions to avoid depending on strconv.
|
||||
|
||||
package os
|
||||
|
||||
// itox converts val (an int) to a hexadecimal string.
|
||||
func itox(val int) string {
|
||||
if val < 0 {
|
||||
return "-" + uitox(uint(-val))
|
||||
}
|
||||
return uitox(uint(val))
|
||||
}
|
||||
|
||||
const hex = "0123456789abcdef"
|
||||
|
||||
// uitox converts val (a uint) to a hexadecimal string.
|
||||
func uitox(val uint) string {
|
||||
if val == 0 { // avoid string allocation
|
||||
return "0x0"
|
||||
}
|
||||
var buf [20]byte // big enough for 64bit value base 16 + 0x
|
||||
i := len(buf) - 1
|
||||
for val >= 16 {
|
||||
q := val / 16
|
||||
buf[i] = hex[val%16]
|
||||
i--
|
||||
val = q
|
||||
}
|
||||
// val < 16
|
||||
buf[i] = hex[val%16]
|
||||
i--
|
||||
buf[i] = 'x'
|
||||
i--
|
||||
buf[i] = '0'
|
||||
return string(buf[i:])
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
//go:build js && wasm
|
||||
|
||||
package os
|
||||
|
||||
// supportsCloseOnExec reports whether the platform supports the
|
||||
// O_CLOEXEC flag.
|
||||
const supportsCloseOnExec = false
|
||||
@@ -1,14 +0,0 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
//go:build unix
|
||||
|
||||
package os
|
||||
|
||||
// supportsCloseOnExec reports whether the platform supports the
|
||||
// O_CLOEXEC flag.
|
||||
// On Darwin, the O_CLOEXEC flag was introduced in OS X 10.7 (Darwin 11.0.0).
|
||||
// See https://support.apple.com/kb/HT1633.
|
||||
// On FreeBSD, the O_CLOEXEC flag was introduced in version 8.3.
|
||||
const supportsCloseOnExec = true
|
||||
@@ -1,11 +0,0 @@
|
||||
// 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.
|
||||
|
||||
//go:build wasip1
|
||||
|
||||
package os
|
||||
|
||||
// supportsCloseOnExec reports whether the platform supports the
|
||||
// O_CLOEXEC flag.
|
||||
const supportsCloseOnExec = false
|
||||
@@ -1,115 +0,0 @@
|
||||
// Copyright 2009 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 os
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/compiler/internal/lib/internal/bytealg"
|
||||
"github.com/goplus/llgo/compiler/internal/lib/internal/itoa"
|
||||
)
|
||||
|
||||
func nextRandom() string {
|
||||
return itoa.Uitoa(uint(uint32(c.Rand())))
|
||||
}
|
||||
|
||||
// CreateTemp creates a new temporary file in the directory dir,
|
||||
// opens the file for reading and writing, and returns the resulting file.
|
||||
// The filename is generated by taking pattern and adding a random string to the end.
|
||||
// If pattern includes a "*", the random string replaces the last "*".
|
||||
// If dir is the empty string, CreateTemp uses the default directory for temporary files, as returned by TempDir.
|
||||
// Multiple programs or goroutines calling CreateTemp simultaneously will not choose the same file.
|
||||
// The caller can use the file's Name method to find the pathname of the file.
|
||||
// It is the caller's responsibility to remove the file when it is no longer needed.
|
||||
func CreateTemp(dir, pattern string) (*File, error) {
|
||||
if dir == "" {
|
||||
dir = TempDir()
|
||||
}
|
||||
|
||||
prefix, suffix, err := prefixAndSuffix(pattern)
|
||||
if err != nil {
|
||||
return nil, &PathError{Op: "createtemp", Path: pattern, Err: err}
|
||||
}
|
||||
prefix = joinPath(dir, prefix)
|
||||
|
||||
try := 0
|
||||
for {
|
||||
name := prefix + nextRandom() + suffix
|
||||
f, err := OpenFile(name, O_RDWR|O_CREATE|O_EXCL, 0600)
|
||||
if IsExist(err) {
|
||||
if try++; try < 10000 {
|
||||
continue
|
||||
}
|
||||
return nil, &PathError{Op: "createtemp", Path: prefix + "*" + suffix, Err: ErrExist}
|
||||
}
|
||||
return f, err
|
||||
}
|
||||
}
|
||||
|
||||
var errPatternHasSeparator = errors.New("pattern contains path separator")
|
||||
|
||||
// prefixAndSuffix splits pattern by the last wildcard "*", if applicable,
|
||||
// returning prefix as the part before "*" and suffix as the part after "*".
|
||||
func prefixAndSuffix(pattern string) (prefix, suffix string, err error) {
|
||||
for i := 0; i < len(pattern); i++ {
|
||||
if IsPathSeparator(pattern[i]) {
|
||||
return "", "", errPatternHasSeparator
|
||||
}
|
||||
}
|
||||
if pos := bytealg.LastIndexByteString(pattern, '*'); pos != -1 {
|
||||
prefix, suffix = pattern[:pos], pattern[pos+1:]
|
||||
} else {
|
||||
prefix = pattern
|
||||
}
|
||||
return prefix, suffix, nil
|
||||
}
|
||||
|
||||
// MkdirTemp creates a new temporary directory in the directory dir
|
||||
// and returns the pathname of the new directory.
|
||||
// The new directory's name is generated by adding a random string to the end of pattern.
|
||||
// If pattern includes a "*", the random string replaces the last "*" instead.
|
||||
// If dir is the empty string, MkdirTemp uses the default directory for temporary files, as returned by TempDir.
|
||||
// Multiple programs or goroutines calling MkdirTemp simultaneously will not choose the same directory.
|
||||
// It is the caller's responsibility to remove the directory when it is no longer needed.
|
||||
func MkdirTemp(dir, pattern string) (string, error) {
|
||||
if dir == "" {
|
||||
dir = TempDir()
|
||||
}
|
||||
|
||||
prefix, suffix, err := prefixAndSuffix(pattern)
|
||||
if err != nil {
|
||||
return "", &PathError{Op: "mkdirtemp", Path: pattern, Err: err}
|
||||
}
|
||||
prefix = joinPath(dir, prefix)
|
||||
|
||||
try := 0
|
||||
for {
|
||||
name := prefix + nextRandom() + suffix
|
||||
err := Mkdir(name, 0700)
|
||||
if err == nil {
|
||||
return name, nil
|
||||
}
|
||||
if IsExist(err) {
|
||||
if try++; try < 10000 {
|
||||
continue
|
||||
}
|
||||
return "", &PathError{Op: "mkdirtemp", Path: dir + string(PathSeparator) + prefix + "*" + suffix, Err: ErrExist}
|
||||
}
|
||||
if IsNotExist(err) {
|
||||
if _, err := Stat(dir); IsNotExist(err) {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
func joinPath(dir, name string) string {
|
||||
if len(dir) > 0 && IsPathSeparator(dir[len(dir)-1]) {
|
||||
return dir + name
|
||||
}
|
||||
return dir + string(PathSeparator) + name
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
// Copyright 2009 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 os
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/os"
|
||||
)
|
||||
|
||||
// Getpagesize returns the underlying system's memory page size.
|
||||
func Getpagesize() int { return syscall.Getpagesize() }
|
||||
|
||||
// File represents an open file descriptor.
|
||||
type File struct {
|
||||
fd uintptr
|
||||
name string
|
||||
appendMode bool
|
||||
nonblock bool
|
||||
stdoutOrErr bool
|
||||
}
|
||||
|
||||
// write writes len(b) bytes to the File.
|
||||
// It returns the number of bytes written and an error, if any.
|
||||
func (f *File) write(b []byte) (int, error) {
|
||||
ret := os.Write(c.Int(f.fd), unsafe.Pointer(unsafe.SliceData(b)), uintptr(len(b)))
|
||||
if ret >= 0 {
|
||||
return int(ret), nil
|
||||
}
|
||||
return 0, syscall.Errno(os.Errno())
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
// write writes len(b) bytes to the File.
|
||||
// It returns the number of bytes written and an error, if any.
|
||||
func (f *File) write(b []byte) (n int, err error) {
|
||||
n, err = f.pfd.Write(b)
|
||||
runtime.KeepAlive(f)
|
||||
return n, err
|
||||
}
|
||||
*/
|
||||
|
||||
// read reads up to len(b) bytes from the File.
|
||||
// It returns the number of bytes read and an error, if any.
|
||||
func (f *File) read(b []byte) (int, error) {
|
||||
ret := os.Read(c.Int(f.fd), unsafe.Pointer(unsafe.SliceData(b)), uintptr(len(b)))
|
||||
if ret > 0 {
|
||||
return int(ret), nil
|
||||
}
|
||||
if ret == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return 0, syscall.Errno(os.Errno())
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
// read reads up to len(b) bytes from the File.
|
||||
// It returns the number of bytes read and an error, if any.
|
||||
func (f *File) read(b []byte) (n int, err error) {
|
||||
n, err = f.pfd.Read(b)
|
||||
runtime.KeepAlive(f)
|
||||
return n, err
|
||||
}
|
||||
*/
|
||||
|
||||
// A FileInfo describes a file and is returned by Stat and Lstat.
|
||||
type FileInfo = fs.FileInfo
|
||||
|
||||
// A FileMode represents a file's mode and permission bits.
|
||||
// The bits have the same definition on all systems, so that
|
||||
// information about files can be moved from one system
|
||||
// to another portably. Not all bits apply to all systems.
|
||||
// The only required bit is ModeDir for directories.
|
||||
type FileMode = fs.FileMode
|
||||
|
||||
// The defined file mode bits are the most significant bits of the FileMode.
|
||||
// The nine least-significant bits are the standard Unix rwxrwxrwx permissions.
|
||||
// The values of these bits should be considered part of the public API and
|
||||
// may be used in wire protocols or disk representations: they must not be
|
||||
// changed, although new bits might be added.
|
||||
const (
|
||||
// The single letters are the abbreviations
|
||||
// used by the String method's formatting.
|
||||
ModeDir = fs.ModeDir // d: is a directory
|
||||
ModeAppend = fs.ModeAppend // a: append-only
|
||||
ModeExclusive = fs.ModeExclusive // l: exclusive use
|
||||
ModeTemporary = fs.ModeTemporary // T: temporary file; Plan 9 only
|
||||
ModeSymlink = fs.ModeSymlink // L: symbolic link
|
||||
ModeDevice = fs.ModeDevice // D: device file
|
||||
ModeNamedPipe = fs.ModeNamedPipe // p: named pipe (FIFO)
|
||||
ModeSocket = fs.ModeSocket // S: Unix domain socket
|
||||
ModeSetuid = fs.ModeSetuid // u: setuid
|
||||
ModeSetgid = fs.ModeSetgid // g: setgid
|
||||
ModeCharDevice = fs.ModeCharDevice // c: Unix character device, when ModeDevice is set
|
||||
ModeSticky = fs.ModeSticky // t: sticky
|
||||
ModeIrregular = fs.ModeIrregular // ?: non-regular file; nothing else is known about this file
|
||||
|
||||
// Mask for the type bits. For regular files, none will be set.
|
||||
ModeType = fs.ModeType
|
||||
|
||||
ModePerm = fs.ModePerm // Unix permission bits, 0o777
|
||||
)
|
||||
|
||||
func (fs *fileStat) Name() string { return fs.name }
|
||||
func (fs *fileStat) IsDir() bool { return fs.Mode().IsDir() }
|
||||
|
||||
// SameFile reports whether fi1 and fi2 describe the same file.
|
||||
// For example, on Unix this means that the device and inode fields
|
||||
// of the two underlying structures are identical; on other systems
|
||||
// the decision may be based on the path names.
|
||||
// SameFile only applies to results returned by this package's Stat.
|
||||
// It returns false in other cases.
|
||||
func SameFile(fi1, fi2 FileInfo) bool {
|
||||
fs1, ok1 := fi1.(*fileStat)
|
||||
fs2, ok2 := fi2.(*fileStat)
|
||||
if !ok1 || !ok2 {
|
||||
return false
|
||||
}
|
||||
return sameFile(fs1, fs2)
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright 2009 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 os
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
// A fileStat is the implementation of FileInfo returned by Stat and Lstat.
|
||||
type fileStat struct {
|
||||
name string
|
||||
size int64
|
||||
mode FileMode
|
||||
modTime time.Time
|
||||
sys any
|
||||
}
|
||||
|
||||
func (fs *fileStat) Size() int64 { return fs.size }
|
||||
func (fs *fileStat) Mode() FileMode { return fs.mode }
|
||||
func (fs *fileStat) ModTime() time.Time { return fs.modTime }
|
||||
func (fs *fileStat) Sys() any { return fs.sys }
|
||||
|
||||
func sameFile(fs1, fs2 *fileStat) bool {
|
||||
a := fs1.sys.(*syscall.Dir)
|
||||
b := fs2.sys.(*syscall.Dir)
|
||||
return a.Qid.Path == b.Qid.Path && a.Type == b.Type && a.Dev == b.Dev
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user