mirror of https://github.com/gogs/gogs.git
vendor: add new dependencies
parent
fbecc18e2e
commit
5e158b51db
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
|
@ -0,0 +1,49 @@
|
|||
# concurrent
|
||||
|
||||
[](https://sourcegraph.com/github.com/modern-go/concurrent?badge)
|
||||
[](http://godoc.org/github.com/modern-go/concurrent)
|
||||
[](https://travis-ci.org/modern-go/concurrent)
|
||||
[](https://codecov.io/gh/modern-go/concurrent)
|
||||
[](https://goreportcard.com/report/github.com/modern-go/concurrent)
|
||||
[](https://raw.githubusercontent.com/modern-go/concurrent/master/LICENSE)
|
||||
|
||||
* concurrent.Map: backport sync.Map for go below 1.9
|
||||
* concurrent.Executor: goroutine with explicit ownership and cancellable
|
||||
|
||||
# concurrent.Map
|
||||
|
||||
because sync.Map is only available in go 1.9, we can use concurrent.Map to make code portable
|
||||
|
||||
```go
|
||||
m := concurrent.NewMap()
|
||||
m.Store("hello", "world")
|
||||
elem, found := m.Load("hello")
|
||||
// elem will be "world"
|
||||
// found will be true
|
||||
```
|
||||
|
||||
# concurrent.Executor
|
||||
|
||||
```go
|
||||
executor := concurrent.NewUnboundedExecutor()
|
||||
executor.Go(func(ctx context.Context) {
|
||||
everyMillisecond := time.NewTicker(time.Millisecond)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
fmt.Println("goroutine exited")
|
||||
return
|
||||
case <-everyMillisecond.C:
|
||||
// do something
|
||||
}
|
||||
}
|
||||
})
|
||||
time.Sleep(time.Second)
|
||||
executor.StopAndWaitForever()
|
||||
fmt.Println("executor stopped")
|
||||
```
|
||||
|
||||
attach goroutine to executor instance, so that we can
|
||||
|
||||
* cancel it by stop the executor with Stop/StopAndWait/StopAndWaitForever
|
||||
* handle panic by callback: the default behavior will no longer crash your application
|
|
@ -0,0 +1,14 @@
|
|||
package concurrent
|
||||
|
||||
import "context"
|
||||
|
||||
// Executor replace go keyword to start a new goroutine
|
||||
// the goroutine should cancel itself if the context passed in has been cancelled
|
||||
// the goroutine started by the executor, is owned by the executor
|
||||
// we can cancel all executors owned by the executor just by stop the executor itself
|
||||
// however Executor interface does not Stop method, the one starting and owning executor
|
||||
// should use the concrete type of executor, instead of this interface.
|
||||
type Executor interface {
|
||||
// Go starts a new goroutine controlled by the context
|
||||
Go(handler func(ctx context.Context))
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
//+build go1.9
|
||||
|
||||
package concurrent
|
||||
|
||||
import "sync"
|
||||
|
||||
// Map is a wrapper for sync.Map introduced in go1.9
|
||||
type Map struct {
|
||||
sync.Map
|
||||
}
|
||||
|
||||
// NewMap creates a thread safe Map
|
||||
func NewMap() *Map {
|
||||
return &Map{}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
//+build !go1.9
|
||||
|
||||
package concurrent
|
||||
|
||||
import "sync"
|
||||
|
||||
// Map implements a thread safe map for go version below 1.9 using mutex
|
||||
type Map struct {
|
||||
lock sync.RWMutex
|
||||
data map[interface{}]interface{}
|
||||
}
|
||||
|
||||
// NewMap creates a thread safe map
|
||||
func NewMap() *Map {
|
||||
return &Map{
|
||||
data: make(map[interface{}]interface{}, 32),
|
||||
}
|
||||
}
|
||||
|
||||
// Load is same as sync.Map Load
|
||||
func (m *Map) Load(key interface{}) (elem interface{}, found bool) {
|
||||
m.lock.RLock()
|
||||
elem, found = m.data[key]
|
||||
m.lock.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
// Load is same as sync.Map Store
|
||||
func (m *Map) Store(key interface{}, elem interface{}) {
|
||||
m.lock.Lock()
|
||||
m.data[key] = elem
|
||||
m.lock.Unlock()
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package concurrent
|
||||
|
||||
import (
|
||||
"os"
|
||||
"log"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// ErrorLogger is used to print out error, can be set to writer other than stderr
|
||||
var ErrorLogger = log.New(os.Stderr, "", 0)
|
||||
|
||||
// InfoLogger is used to print informational message, default to off
|
||||
var InfoLogger = log.New(ioutil.Discard, "", 0)
|
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
echo "" > coverage.txt
|
||||
|
||||
for d in $(go list ./... | grep -v vendor); do
|
||||
go test -coverprofile=profile.out -coverpkg=github.com/modern-go/concurrent $d
|
||||
if [ -f profile.out ]; then
|
||||
cat profile.out >> coverage.txt
|
||||
rm profile.out
|
||||
fi
|
||||
done
|
|
@ -0,0 +1,119 @@
|
|||
package concurrent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
"time"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// HandlePanic logs goroutine panic by default
|
||||
var HandlePanic = func(recovered interface{}, funcName string) {
|
||||
ErrorLogger.Println(fmt.Sprintf("%s panic: %v", funcName, recovered))
|
||||
ErrorLogger.Println(string(debug.Stack()))
|
||||
}
|
||||
|
||||
// UnboundedExecutor is a executor without limits on counts of alive goroutines
|
||||
// it tracks the goroutine started by it, and can cancel them when shutdown
|
||||
type UnboundedExecutor struct {
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
activeGoroutinesMutex *sync.Mutex
|
||||
activeGoroutines map[string]int
|
||||
HandlePanic func(recovered interface{}, funcName string)
|
||||
}
|
||||
|
||||
// GlobalUnboundedExecutor has the life cycle of the program itself
|
||||
// any goroutine want to be shutdown before main exit can be started from this executor
|
||||
// GlobalUnboundedExecutor expects the main function to call stop
|
||||
// it does not magically knows the main function exits
|
||||
var GlobalUnboundedExecutor = NewUnboundedExecutor()
|
||||
|
||||
// NewUnboundedExecutor creates a new UnboundedExecutor,
|
||||
// UnboundedExecutor can not be created by &UnboundedExecutor{}
|
||||
// HandlePanic can be set with a callback to override global HandlePanic
|
||||
func NewUnboundedExecutor() *UnboundedExecutor {
|
||||
ctx, cancel := context.WithCancel(context.TODO())
|
||||
return &UnboundedExecutor{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
activeGoroutinesMutex: &sync.Mutex{},
|
||||
activeGoroutines: map[string]int{},
|
||||
}
|
||||
}
|
||||
|
||||
// Go starts a new goroutine and tracks its lifecycle.
|
||||
// Panic will be recovered and logged automatically, except for StopSignal
|
||||
func (executor *UnboundedExecutor) Go(handler func(ctx context.Context)) {
|
||||
pc := reflect.ValueOf(handler).Pointer()
|
||||
f := runtime.FuncForPC(pc)
|
||||
funcName := f.Name()
|
||||
file, line := f.FileLine(pc)
|
||||
executor.activeGoroutinesMutex.Lock()
|
||||
defer executor.activeGoroutinesMutex.Unlock()
|
||||
startFrom := fmt.Sprintf("%s:%d", file, line)
|
||||
executor.activeGoroutines[startFrom] += 1
|
||||
go func() {
|
||||
defer func() {
|
||||
recovered := recover()
|
||||
// if you want to quit a goroutine without trigger HandlePanic
|
||||
// use runtime.Goexit() to quit
|
||||
if recovered != nil {
|
||||
if executor.HandlePanic == nil {
|
||||
HandlePanic(recovered, funcName)
|
||||
} else {
|
||||
executor.HandlePanic(recovered, funcName)
|
||||
}
|
||||
}
|
||||
executor.activeGoroutinesMutex.Lock()
|
||||
executor.activeGoroutines[startFrom] -= 1
|
||||
executor.activeGoroutinesMutex.Unlock()
|
||||
}()
|
||||
handler(executor.ctx)
|
||||
}()
|
||||
}
|
||||
|
||||
// Stop cancel all goroutines started by this executor without wait
|
||||
func (executor *UnboundedExecutor) Stop() {
|
||||
executor.cancel()
|
||||
}
|
||||
|
||||
// StopAndWaitForever cancel all goroutines started by this executor and
|
||||
// wait until all goroutines exited
|
||||
func (executor *UnboundedExecutor) StopAndWaitForever() {
|
||||
executor.StopAndWait(context.Background())
|
||||
}
|
||||
|
||||
// StopAndWait cancel all goroutines started by this executor and wait.
|
||||
// Wait can be cancelled by the context passed in.
|
||||
func (executor *UnboundedExecutor) StopAndWait(ctx context.Context) {
|
||||
executor.cancel()
|
||||
for {
|
||||
oneHundredMilliseconds := time.NewTimer(time.Millisecond * 100)
|
||||
select {
|
||||
case <-oneHundredMilliseconds.C:
|
||||
if executor.checkNoActiveGoroutines() {
|
||||
return
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (executor *UnboundedExecutor) checkNoActiveGoroutines() bool {
|
||||
executor.activeGoroutinesMutex.Lock()
|
||||
defer executor.activeGoroutinesMutex.Unlock()
|
||||
for startFrom, count := range executor.activeGoroutines {
|
||||
if count > 0 {
|
||||
InfoLogger.Println("UnboundedExecutor is still waiting goroutines to quit",
|
||||
"startFrom", startFrom,
|
||||
"count", count)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/modern-go/concurrent"
|
||||
packages = ["."]
|
||||
revision = "e0a39a4cb4216ea8db28e22a69f4ec25610d513a"
|
||||
version = "1.0.0"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "daee8a88b3498b61c5640056665b8b9eea062006f5e596bbb6a3ed9119a11ec7"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
|
@ -0,0 +1,35 @@
|
|||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
#
|
||||
# [prune]
|
||||
# non-go = false
|
||||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
ignored = ["github.com/modern-go/test","github.com/modern-go/test/must","github.com/modern-go/test/should"]
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/modern-go/concurrent"
|
||||
version = "1.0.0"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
|
@ -0,0 +1,71 @@
|
|||
# reflect2
|
||||
|
||||
[](https://sourcegraph.com/github.com/modern-go/reflect2?badge)
|
||||
[](http://godoc.org/github.com/modern-go/reflect2)
|
||||
[](https://travis-ci.org/modern-go/reflect2)
|
||||
[](https://codecov.io/gh/modern-go/reflect2)
|
||||
[](https://goreportcard.com/report/github.com/modern-go/reflect2)
|
||||
[](https://raw.githubusercontent.com/modern-go/reflect2/master/LICENSE)
|
||||
|
||||
reflect api that avoids runtime reflect.Value cost
|
||||
|
||||
* reflect get/set interface{}, with type checking
|
||||
* reflect get/set unsafe.Pointer, without type checking
|
||||
* `reflect2.TypeByName` works like `Class.forName` found in java
|
||||
|
||||
[json-iterator](https://github.com/json-iterator/go) use this package to save runtime dispatching cost.
|
||||
This package is designed for low level libraries to optimize reflection performance.
|
||||
General application should still use reflect standard library.
|
||||
|
||||
# reflect2.TypeByName
|
||||
|
||||
```go
|
||||
// given package is github.com/your/awesome-package
|
||||
type MyStruct struct {
|
||||
// ...
|
||||
}
|
||||
|
||||
// will return the type
|
||||
reflect2.TypeByName("awesome-package.MyStruct")
|
||||
// however, if the type has not been used
|
||||
// it will be eliminated by compiler, so we can not get it in runtime
|
||||
```
|
||||
|
||||
# reflect2 get/set interface{}
|
||||
|
||||
```go
|
||||
valType := reflect2.TypeOf(1)
|
||||
i := 1
|
||||
j := 10
|
||||
valType.Set(&i, &j)
|
||||
// i will be 10
|
||||
```
|
||||
|
||||
to get set `type`, always use its pointer `*type`
|
||||
|
||||
# reflect2 get/set unsafe.Pointer
|
||||
|
||||
```go
|
||||
valType := reflect2.TypeOf(1)
|
||||
i := 1
|
||||
j := 10
|
||||
valType.UnsafeSet(unsafe.Pointer(&i), unsafe.Pointer(&j))
|
||||
// i will be 10
|
||||
```
|
||||
|
||||
to get set `type`, always use its pointer `*type`
|
||||
|
||||
# benchmark
|
||||
|
||||
Benchmark is not necessary for this package. It does nothing actually.
|
||||
As it is just a thin wrapper to make go runtime public.
|
||||
Both `reflect2` and `reflect` call same function
|
||||
provided by `runtime` package exposed by go language.
|
||||
|
||||
# unsafe safety
|
||||
|
||||
Instead of casting `[]byte` to `sliceHeader` in your application using unsafe.
|
||||
We can use reflect2 instead. This way, if `sliceHeader` changes in the future,
|
||||
only reflect2 need to be upgraded.
|
||||
|
||||
reflect2 tries its best to keep the implementation same as reflect (by testing).
|
|
@ -0,0 +1,8 @@
|
|||
//+build go1.7
|
||||
|
||||
package reflect2
|
||||
|
||||
import "unsafe"
|
||||
|
||||
//go:linkname resolveTypeOff reflect.resolveTypeOff
|
||||
func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer
|
|
@ -0,0 +1,14 @@
|
|||
//+build go1.9
|
||||
|
||||
package reflect2
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//go:linkname makemap reflect.makemap
|
||||
func makemap(rtype unsafe.Pointer, cap int) (m unsafe.Pointer)
|
||||
|
||||
func makeMapWithSize(rtype unsafe.Pointer, cap int) unsafe.Pointer {
|
||||
return makemap(rtype, cap)
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
//+build !go1.7
|
||||
|
||||
package reflect2
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer {
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
//+build !go1.9
|
||||
|
||||
package reflect2
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//go:linkname makemap reflect.makemap
|
||||
func makemap(rtype unsafe.Pointer) (m unsafe.Pointer)
|
||||
|
||||
func makeMapWithSize(rtype unsafe.Pointer, cap int) unsafe.Pointer {
|
||||
return makemap(rtype)
|
||||
}
|
|
@ -0,0 +1,298 @@
|
|||
package reflect2
|
||||
|
||||
import (
|
||||
"github.com/modern-go/concurrent"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Type interface {
|
||||
Kind() reflect.Kind
|
||||
// New return pointer to data of this type
|
||||
New() interface{}
|
||||
// UnsafeNew return the allocated space pointed by unsafe.Pointer
|
||||
UnsafeNew() unsafe.Pointer
|
||||
// PackEFace cast a unsafe pointer to object represented pointer
|
||||
PackEFace(ptr unsafe.Pointer) interface{}
|
||||
// Indirect dereference object represented pointer to this type
|
||||
Indirect(obj interface{}) interface{}
|
||||
// UnsafeIndirect dereference pointer to this type
|
||||
UnsafeIndirect(ptr unsafe.Pointer) interface{}
|
||||
// Type1 returns reflect.Type
|
||||
Type1() reflect.Type
|
||||
Implements(thatType Type) bool
|
||||
String() string
|
||||
RType() uintptr
|
||||
// interface{} of this type has pointer like behavior
|
||||
LikePtr() bool
|
||||
IsNullable() bool
|
||||
IsNil(obj interface{}) bool
|
||||
UnsafeIsNil(ptr unsafe.Pointer) bool
|
||||
Set(obj interface{}, val interface{})
|
||||
UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer)
|
||||
AssignableTo(anotherType Type) bool
|
||||
}
|
||||
|
||||
type ListType interface {
|
||||
Type
|
||||
Elem() Type
|
||||
SetIndex(obj interface{}, index int, elem interface{})
|
||||
UnsafeSetIndex(obj unsafe.Pointer, index int, elem unsafe.Pointer)
|
||||
GetIndex(obj interface{}, index int) interface{}
|
||||
UnsafeGetIndex(obj unsafe.Pointer, index int) unsafe.Pointer
|
||||
}
|
||||
|
||||
type ArrayType interface {
|
||||
ListType
|
||||
Len() int
|
||||
}
|
||||
|
||||
type SliceType interface {
|
||||
ListType
|
||||
MakeSlice(length int, cap int) interface{}
|
||||
UnsafeMakeSlice(length int, cap int) unsafe.Pointer
|
||||
Grow(obj interface{}, newLength int)
|
||||
UnsafeGrow(ptr unsafe.Pointer, newLength int)
|
||||
Append(obj interface{}, elem interface{})
|
||||
UnsafeAppend(obj unsafe.Pointer, elem unsafe.Pointer)
|
||||
LengthOf(obj interface{}) int
|
||||
UnsafeLengthOf(ptr unsafe.Pointer) int
|
||||
SetNil(obj interface{})
|
||||
UnsafeSetNil(ptr unsafe.Pointer)
|
||||
Cap(obj interface{}) int
|
||||
UnsafeCap(ptr unsafe.Pointer) int
|
||||
}
|
||||
|
||||
type StructType interface {
|
||||
Type
|
||||
NumField() int
|
||||
Field(i int) StructField
|
||||
FieldByName(name string) StructField
|
||||
FieldByIndex(index []int) StructField
|
||||
FieldByNameFunc(match func(string) bool) StructField
|
||||
}
|
||||
|
||||
type StructField interface {
|
||||
Offset() uintptr
|
||||
Name() string
|
||||
PkgPath() string
|
||||
Type() Type
|
||||
Tag() reflect.StructTag
|
||||
Index() []int
|
||||
Anonymous() bool
|
||||
Set(obj interface{}, value interface{})
|
||||
UnsafeSet(obj unsafe.Pointer, value unsafe.Pointer)
|
||||
Get(obj interface{}) interface{}
|
||||
UnsafeGet(obj unsafe.Pointer) unsafe.Pointer
|
||||
}
|
||||
|
||||
type MapType interface {
|
||||
Type
|
||||
Key() Type
|
||||
Elem() Type
|
||||
MakeMap(cap int) interface{}
|
||||
UnsafeMakeMap(cap int) unsafe.Pointer
|
||||
SetIndex(obj interface{}, key interface{}, elem interface{})
|
||||
UnsafeSetIndex(obj unsafe.Pointer, key unsafe.Pointer, elem unsafe.Pointer)
|
||||
TryGetIndex(obj interface{}, key interface{}) (interface{}, bool)
|
||||
GetIndex(obj interface{}, key interface{}) interface{}
|
||||
UnsafeGetIndex(obj unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer
|
||||
Iterate(obj interface{}) MapIterator
|
||||
UnsafeIterate(obj unsafe.Pointer) MapIterator
|
||||
}
|
||||
|
||||
type MapIterator interface {
|
||||
HasNext() bool
|
||||
Next() (key interface{}, elem interface{})
|
||||
UnsafeNext() (key unsafe.Pointer, elem unsafe.Pointer)
|
||||
}
|
||||
|
||||
type PtrType interface {
|
||||
Type
|
||||
Elem() Type
|
||||
}
|
||||
|
||||
type InterfaceType interface {
|
||||
NumMethod() int
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
UseSafeImplementation bool
|
||||
}
|
||||
|
||||
type API interface {
|
||||
TypeOf(obj interface{}) Type
|
||||
Type2(type1 reflect.Type) Type
|
||||
}
|
||||
|
||||
var ConfigUnsafe = Config{UseSafeImplementation: false}.Froze()
|
||||
var ConfigSafe = Config{UseSafeImplementation: true}.Froze()
|
||||
|
||||
type frozenConfig struct {
|
||||
useSafeImplementation bool
|
||||
cache *concurrent.Map
|
||||
}
|
||||
|
||||
func (cfg Config) Froze() *frozenConfig {
|
||||
return &frozenConfig{
|
||||
useSafeImplementation: cfg.UseSafeImplementation,
|
||||
cache: concurrent.NewMap(),
|
||||
}
|
||||
}
|
||||
|
||||
func (cfg *frozenConfig) TypeOf(obj interface{}) Type {
|
||||
cacheKey := uintptr(unpackEFace(obj).rtype)
|
||||
typeObj, found := cfg.cache.Load(cacheKey)
|
||||
if found {
|
||||
return typeObj.(Type)
|
||||
}
|
||||
return cfg.Type2(reflect.TypeOf(obj))
|
||||
}
|
||||
|
||||
func (cfg *frozenConfig) Type2(type1 reflect.Type) Type {
|
||||
if type1 == nil {
|
||||
return nil
|
||||
}
|
||||
cacheKey := uintptr(unpackEFace(type1).data)
|
||||
typeObj, found := cfg.cache.Load(cacheKey)
|
||||
if found {
|
||||
return typeObj.(Type)
|
||||
}
|
||||
type2 := cfg.wrapType(type1)
|
||||
cfg.cache.Store(cacheKey, type2)
|
||||
return type2
|
||||
}
|
||||
|
||||
func (cfg *frozenConfig) wrapType(type1 reflect.Type) Type {
|
||||
safeType := safeType{Type: type1, cfg: cfg}
|
||||
switch type1.Kind() {
|
||||
case reflect.Struct:
|
||||
if cfg.useSafeImplementation {
|
||||
return &safeStructType{safeType}
|
||||
}
|
||||
return newUnsafeStructType(cfg, type1)
|
||||
case reflect.Array:
|
||||
if cfg.useSafeImplementation {
|
||||
return &safeSliceType{safeType}
|
||||
}
|
||||
return newUnsafeArrayType(cfg, type1)
|
||||
case reflect.Slice:
|
||||
if cfg.useSafeImplementation {
|
||||
return &safeSliceType{safeType}
|
||||
}
|
||||
return newUnsafeSliceType(cfg, type1)
|
||||
case reflect.Map:
|
||||
if cfg.useSafeImplementation {
|
||||
return &safeMapType{safeType}
|
||||
}
|
||||
return newUnsafeMapType(cfg, type1)
|
||||
case reflect.Ptr, reflect.Chan, reflect.Func:
|
||||
if cfg.useSafeImplementation {
|
||||
return &safeMapType{safeType}
|
||||
}
|
||||
return newUnsafePtrType(cfg, type1)
|
||||
case reflect.Interface:
|
||||
if cfg.useSafeImplementation {
|
||||
return &safeMapType{safeType}
|
||||
}
|
||||
if type1.NumMethod() == 0 {
|
||||
return newUnsafeEFaceType(cfg, type1)
|
||||
}
|
||||
return newUnsafeIFaceType(cfg, type1)
|
||||
default:
|
||||
if cfg.useSafeImplementation {
|
||||
return &safeType
|
||||
}
|
||||
return newUnsafeType(cfg, type1)
|
||||
}
|
||||
}
|
||||
|
||||
func TypeOf(obj interface{}) Type {
|
||||
return ConfigUnsafe.TypeOf(obj)
|
||||
}
|
||||
|
||||
func TypeOfPtr(obj interface{}) PtrType {
|
||||
return TypeOf(obj).(PtrType)
|
||||
}
|
||||
|
||||
func Type2(type1 reflect.Type) Type {
|
||||
if type1 == nil {
|
||||
return nil
|
||||
}
|
||||
return ConfigUnsafe.Type2(type1)
|
||||
}
|
||||
|
||||
func PtrTo(typ Type) Type {
|
||||
return Type2(reflect.PtrTo(typ.Type1()))
|
||||
}
|
||||
|
||||
func PtrOf(obj interface{}) unsafe.Pointer {
|
||||
return unpackEFace(obj).data
|
||||
}
|
||||
|
||||
func RTypeOf(obj interface{}) uintptr {
|
||||
return uintptr(unpackEFace(obj).rtype)
|
||||
}
|
||||
|
||||
func IsNil(obj interface{}) bool {
|
||||
if obj == nil {
|
||||
return true
|
||||
}
|
||||
return unpackEFace(obj).data == nil
|
||||
}
|
||||
|
||||
func IsNullable(kind reflect.Kind) bool {
|
||||
switch kind {
|
||||
case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Func, reflect.Slice, reflect.Interface:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func likePtrKind(kind reflect.Kind) bool {
|
||||
switch kind {
|
||||
case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Func:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func likePtrType(typ reflect.Type) bool {
|
||||
if likePtrKind(typ.Kind()) {
|
||||
return true
|
||||
}
|
||||
if typ.Kind() == reflect.Struct {
|
||||
if typ.NumField() != 1 {
|
||||
return false
|
||||
}
|
||||
return likePtrType(typ.Field(0).Type)
|
||||
}
|
||||
if typ.Kind() == reflect.Array {
|
||||
if typ.Len() != 1 {
|
||||
return false
|
||||
}
|
||||
return likePtrType(typ.Elem())
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NoEscape hides a pointer from escape analysis. noescape is
|
||||
// the identity function but escape analysis doesn't think the
|
||||
// output depends on the input. noescape is inlined and currently
|
||||
// compiles down to zero instructions.
|
||||
// USE CAREFULLY!
|
||||
//go:nosplit
|
||||
func NoEscape(p unsafe.Pointer) unsafe.Pointer {
|
||||
x := uintptr(p)
|
||||
return unsafe.Pointer(x ^ 0)
|
||||
}
|
||||
|
||||
func UnsafeCastString(str string) []byte {
|
||||
stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&str))
|
||||
sliceHeader := &reflect.SliceHeader{
|
||||
Data: stringHeader.Data,
|
||||
Cap: stringHeader.Len,
|
||||
Len: stringHeader.Len,
|
||||
}
|
||||
return *(*[]byte)(unsafe.Pointer(sliceHeader))
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package reflect2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// DefaultTypeOfKind return the non aliased default type for the kind
|
||||
func DefaultTypeOfKind(kind reflect.Kind) Type {
|
||||
return kindTypes[kind]
|
||||
}
|
||||
|
||||
var kindTypes = map[reflect.Kind]Type{
|
||||
reflect.Bool: TypeOf(true),
|
||||
reflect.Uint8: TypeOf(uint8(0)),
|
||||
reflect.Int8: TypeOf(int8(0)),
|
||||
reflect.Uint16: TypeOf(uint16(0)),
|
||||
reflect.Int16: TypeOf(int16(0)),
|
||||
reflect.Uint32: TypeOf(uint32(0)),
|
||||
reflect.Int32: TypeOf(int32(0)),
|
||||
reflect.Uint64: TypeOf(uint64(0)),
|
||||
reflect.Int64: TypeOf(int64(0)),
|
||||
reflect.Uint: TypeOf(uint(0)),
|
||||
reflect.Int: TypeOf(int(0)),
|
||||
reflect.Float32: TypeOf(float32(0)),
|
||||
reflect.Float64: TypeOf(float64(0)),
|
||||
reflect.Uintptr: TypeOf(uintptr(0)),
|
||||
reflect.String: TypeOf(""),
|
||||
reflect.UnsafePointer: TypeOf(unsafe.Pointer(nil)),
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package reflect2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type safeField struct {
|
||||
reflect.StructField
|
||||
}
|
||||
|
||||
func (field *safeField) Offset() uintptr {
|
||||
return field.StructField.Offset
|
||||
}
|
||||
|
||||
func (field *safeField) Name() string {
|
||||
return field.StructField.Name
|
||||
}
|
||||
|
||||
func (field *safeField) PkgPath() string {
|
||||
return field.StructField.PkgPath
|
||||
}
|
||||
|
||||
func (field *safeField) Type() Type {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (field *safeField) Tag() reflect.StructTag {
|
||||
return field.StructField.Tag
|
||||
}
|
||||
|
||||
func (field *safeField) Index() []int {
|
||||
return field.StructField.Index
|
||||
}
|
||||
|
||||
func (field *safeField) Anonymous() bool {
|
||||
return field.StructField.Anonymous
|
||||
}
|
||||
|
||||
func (field *safeField) Set(obj interface{}, value interface{}) {
|
||||
val := reflect.ValueOf(obj).Elem()
|
||||
val.FieldByIndex(field.Index()).Set(reflect.ValueOf(value).Elem())
|
||||
}
|
||||
|
||||
func (field *safeField) UnsafeSet(obj unsafe.Pointer, value unsafe.Pointer) {
|
||||
panic("unsafe operation is not supported")
|
||||
}
|
||||
|
||||
func (field *safeField) Get(obj interface{}) interface{} {
|
||||
val := reflect.ValueOf(obj).Elem().FieldByIndex(field.Index())
|
||||
ptr := reflect.New(val.Type())
|
||||
ptr.Elem().Set(val)
|
||||
return ptr.Interface()
|
||||
}
|
||||
|
||||
func (field *safeField) UnsafeGet(obj unsafe.Pointer) unsafe.Pointer {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package reflect2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type safeMapType struct {
|
||||
safeType
|
||||
}
|
||||
|
||||
func (type2 *safeMapType) Key() Type {
|
||||
return type2.safeType.cfg.Type2(type2.Type.Key())
|
||||
}
|
||||
|
||||
func (type2 *safeMapType) MakeMap(cap int) interface{} {
|
||||
ptr := reflect.New(type2.Type)
|
||||
ptr.Elem().Set(reflect.MakeMap(type2.Type))
|
||||
return ptr.Interface()
|
||||
}
|
||||
|
||||
func (type2 *safeMapType) UnsafeMakeMap(cap int) unsafe.Pointer {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
||||
|
||||
func (type2 *safeMapType) SetIndex(obj interface{}, key interface{}, elem interface{}) {
|
||||
keyVal := reflect.ValueOf(key)
|
||||
elemVal := reflect.ValueOf(elem)
|
||||
val := reflect.ValueOf(obj)
|
||||
val.Elem().SetMapIndex(keyVal.Elem(), elemVal.Elem())
|
||||
}
|
||||
|
||||
func (type2 *safeMapType) UnsafeSetIndex(obj unsafe.Pointer, key unsafe.Pointer, elem unsafe.Pointer) {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
||||
|
||||
func (type2 *safeMapType) TryGetIndex(obj interface{}, key interface{}) (interface{}, bool) {
|
||||
keyVal := reflect.ValueOf(key)
|
||||
if key == nil {
|
||||
keyVal = reflect.New(type2.Type.Key()).Elem()
|
||||
}
|
||||
val := reflect.ValueOf(obj).MapIndex(keyVal)
|
||||
if !val.IsValid() {
|
||||
return nil, false
|
||||
}
|
||||
return val.Interface(), true
|
||||
}
|
||||
|
||||
func (type2 *safeMapType) GetIndex(obj interface{}, key interface{}) interface{} {
|
||||
val := reflect.ValueOf(obj).Elem()
|
||||
keyVal := reflect.ValueOf(key).Elem()
|
||||
elemVal := val.MapIndex(keyVal)
|
||||
if !elemVal.IsValid() {
|
||||
ptr := reflect.New(reflect.PtrTo(val.Type().Elem()))
|
||||
return ptr.Elem().Interface()
|
||||
}
|
||||
ptr := reflect.New(elemVal.Type())
|
||||
ptr.Elem().Set(elemVal)
|
||||
return ptr.Interface()
|
||||
}
|
||||
|
||||
func (type2 *safeMapType) UnsafeGetIndex(obj unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
||||
|
||||
func (type2 *safeMapType) Iterate(obj interface{}) MapIterator {
|
||||
m := reflect.ValueOf(obj).Elem()
|
||||
return &safeMapIterator{
|
||||
m: m,
|
||||
keys: m.MapKeys(),
|
||||
}
|
||||
}
|
||||
|
||||
func (type2 *safeMapType) UnsafeIterate(obj unsafe.Pointer) MapIterator {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
||||
|
||||
type safeMapIterator struct {
|
||||
i int
|
||||
m reflect.Value
|
||||
keys []reflect.Value
|
||||
}
|
||||
|
||||
func (iter *safeMapIterator) HasNext() bool {
|
||||
return iter.i != len(iter.keys)
|
||||
}
|
||||
|
||||
func (iter *safeMapIterator) Next() (interface{}, interface{}) {
|
||||
key := iter.keys[iter.i]
|
||||
elem := iter.m.MapIndex(key)
|
||||
iter.i += 1
|
||||
keyPtr := reflect.New(key.Type())
|
||||
keyPtr.Elem().Set(key)
|
||||
elemPtr := reflect.New(elem.Type())
|
||||
elemPtr.Elem().Set(elem)
|
||||
return keyPtr.Interface(), elemPtr.Interface()
|
||||
}
|
||||
|
||||
func (iter *safeMapIterator) UnsafeNext() (unsafe.Pointer, unsafe.Pointer) {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package reflect2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type safeSliceType struct {
|
||||
safeType
|
||||
}
|
||||
|
||||
func (type2 *safeSliceType) SetIndex(obj interface{}, index int, value interface{}) {
|
||||
val := reflect.ValueOf(obj).Elem()
|
||||
elem := reflect.ValueOf(value).Elem()
|
||||
val.Index(index).Set(elem)
|
||||
}
|
||||
|
||||
func (type2 *safeSliceType) UnsafeSetIndex(obj unsafe.Pointer, index int, value unsafe.Pointer) {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
||||
|
||||
func (type2 *safeSliceType) GetIndex(obj interface{}, index int) interface{} {
|
||||
val := reflect.ValueOf(obj).Elem()
|
||||
elem := val.Index(index)
|
||||
ptr := reflect.New(elem.Type())
|
||||
ptr.Elem().Set(elem)
|
||||
return ptr.Interface()
|
||||
}
|
||||
|
||||
func (type2 *safeSliceType) UnsafeGetIndex(obj unsafe.Pointer, index int) unsafe.Pointer {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
||||
|
||||
func (type2 *safeSliceType) MakeSlice(length int, cap int) interface{} {
|
||||
val := reflect.MakeSlice(type2.Type, length, cap)
|
||||
ptr := reflect.New(val.Type())
|
||||
ptr.Elem().Set(val)
|
||||
return ptr.Interface()
|
||||
}
|
||||
|
||||
func (type2 *safeSliceType) UnsafeMakeSlice(length int, cap int) unsafe.Pointer {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
||||
|
||||
func (type2 *safeSliceType) Grow(obj interface{}, newLength int) {
|
||||
oldCap := type2.Cap(obj)
|
||||
oldSlice := reflect.ValueOf(obj).Elem()
|
||||
delta := newLength - oldCap
|
||||
deltaVals := make([]reflect.Value, delta)
|
||||
newSlice := reflect.Append(oldSlice, deltaVals...)
|
||||
oldSlice.Set(newSlice)
|
||||
}
|
||||
|
||||
func (type2 *safeSliceType) UnsafeGrow(ptr unsafe.Pointer, newLength int) {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
||||
|
||||
func (type2 *safeSliceType) Append(obj interface{}, elem interface{}) {
|
||||
val := reflect.ValueOf(obj).Elem()
|
||||
elemVal := reflect.ValueOf(elem).Elem()
|
||||
newVal := reflect.Append(val, elemVal)
|
||||
val.Set(newVal)
|
||||
}
|
||||
|
||||
func (type2 *safeSliceType) UnsafeAppend(obj unsafe.Pointer, elem unsafe.Pointer) {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
||||
|
||||
func (type2 *safeSliceType) SetNil(obj interface{}) {
|
||||
val := reflect.ValueOf(obj).Elem()
|
||||
val.Set(reflect.Zero(val.Type()))
|
||||
}
|
||||
|
||||
func (type2 *safeSliceType) UnsafeSetNil(ptr unsafe.Pointer) {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
||||
|
||||
func (type2 *safeSliceType) LengthOf(obj interface{}) int {
|
||||
return reflect.ValueOf(obj).Elem().Len()
|
||||
}
|
||||
|
||||
func (type2 *safeSliceType) UnsafeLengthOf(ptr unsafe.Pointer) int {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
||||
|
||||
func (type2 *safeSliceType) Cap(obj interface{}) int {
|
||||
return reflect.ValueOf(obj).Elem().Cap()
|
||||
}
|
||||
|
||||
func (type2 *safeSliceType) UnsafeCap(ptr unsafe.Pointer) int {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package reflect2
|
||||
|
||||
type safeStructType struct {
|
||||
safeType
|
||||
}
|
||||
|
||||
func (type2 *safeStructType) FieldByName(name string) StructField {
|
||||
field, found := type2.Type.FieldByName(name)
|
||||
if !found {
|
||||
panic("field " + name + " not found")
|
||||
}
|
||||
return &safeField{StructField: field}
|
||||
}
|
||||
|
||||
func (type2 *safeStructType) Field(i int) StructField {
|
||||
return &safeField{StructField: type2.Type.Field(i)}
|
||||
}
|
||||
|
||||
func (type2 *safeStructType) FieldByIndex(index []int) StructField {
|
||||
return &safeField{StructField: type2.Type.FieldByIndex(index)}
|
||||
}
|
||||
|
||||
func (type2 *safeStructType) FieldByNameFunc(match func(string) bool) StructField {
|
||||
field, found := type2.Type.FieldByNameFunc(match)
|
||||
if !found {
|
||||
panic("field match condition not found in " + type2.Type.String())
|
||||
}
|
||||
return &safeField{StructField: field}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package reflect2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type safeType struct {
|
||||
reflect.Type
|
||||
cfg *frozenConfig
|
||||
}
|
||||
|
||||
func (type2 *safeType) New() interface{} {
|
||||
return reflect.New(type2.Type).Interface()
|
||||
}
|
||||
|
||||
func (type2 *safeType) UnsafeNew() unsafe.Pointer {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
||||
|
||||
func (type2 *safeType) Elem() Type {
|
||||
return type2.cfg.Type2(type2.Type.Elem())
|
||||
}
|
||||
|
||||
func (type2 *safeType) Type1() reflect.Type {
|
||||
return type2.Type
|
||||
}
|
||||
|
||||
func (type2 *safeType) PackEFace(ptr unsafe.Pointer) interface{} {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
||||
|
||||
func (type2 *safeType) Implements(thatType Type) bool {
|
||||
return type2.Type.Implements(thatType.Type1())
|
||||
}
|
||||
|
||||
func (type2 *safeType) RType() uintptr {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
||||
|
||||
func (type2 *safeType) Indirect(obj interface{}) interface{} {
|
||||
return reflect.Indirect(reflect.ValueOf(obj)).Interface()
|
||||
}
|
||||
|
||||
func (type2 *safeType) UnsafeIndirect(ptr unsafe.Pointer) interface{} {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
||||
|
||||
func (type2 *safeType) LikePtr() bool {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
||||
|
||||
func (type2 *safeType) IsNullable() bool {
|
||||
return IsNullable(type2.Kind())
|
||||
}
|
||||
|
||||
func (type2 *safeType) IsNil(obj interface{}) bool {
|
||||
if obj == nil {
|
||||
return true
|
||||
}
|
||||
return reflect.ValueOf(obj).Elem().IsNil()
|
||||
}
|
||||
|
||||
func (type2 *safeType) UnsafeIsNil(ptr unsafe.Pointer) bool {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
||||
|
||||
func (type2 *safeType) Set(obj interface{}, val interface{}) {
|
||||
reflect.ValueOf(obj).Elem().Set(reflect.ValueOf(val).Elem())
|
||||
}
|
||||
|
||||
func (type2 *safeType) UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer) {
|
||||
panic("does not support unsafe operation")
|
||||
}
|
||||
|
||||
func (type2 *safeType) AssignableTo(anotherType Type) bool {
|
||||
return type2.Type1().AssignableTo(anotherType.Type1())
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
echo "" > coverage.txt
|
||||
|
||||
for d in $(go list ./... | grep -v vendor); do
|
||||
go test -coverprofile=profile.out -coverpkg=github.com/modern-go/reflect2 $d
|
||||
if [ -f profile.out ]; then
|
||||
cat profile.out >> coverage.txt
|
||||
rm profile.out
|
||||
fi
|
||||
done
|
|
@ -0,0 +1,103 @@
|
|||
package reflect2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// typelinks1 for 1.5 ~ 1.6
|
||||
//go:linkname typelinks1 reflect.typelinks
|
||||
func typelinks1() [][]unsafe.Pointer
|
||||
|
||||
// typelinks2 for 1.7 ~
|
||||
//go:linkname typelinks2 reflect.typelinks
|
||||
func typelinks2() (sections []unsafe.Pointer, offset [][]int32)
|
||||
|
||||
var types = map[string]reflect.Type{}
|
||||
var packages = map[string]map[string]reflect.Type{}
|
||||
|
||||
func init() {
|
||||
ver := runtime.Version()
|
||||
if ver == "go1.5" || strings.HasPrefix(ver, "go1.5.") {
|
||||
loadGo15Types()
|
||||
} else if ver == "go1.6" || strings.HasPrefix(ver, "go1.6.") {
|
||||
loadGo15Types()
|
||||
} else {
|
||||
loadGo17Types()
|
||||
}
|
||||
}
|
||||
|
||||
func loadGo15Types() {
|
||||
var obj interface{} = reflect.TypeOf(0)
|
||||
typePtrss := typelinks1()
|
||||
for _, typePtrs := range typePtrss {
|
||||
for _, typePtr := range typePtrs {
|
||||
(*emptyInterface)(unsafe.Pointer(&obj)).word = typePtr
|
||||
typ := obj.(reflect.Type)
|
||||
if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct {
|
||||
loadedType := typ.Elem()
|
||||
pkgTypes := packages[loadedType.PkgPath()]
|
||||
if pkgTypes == nil {
|
||||
pkgTypes = map[string]reflect.Type{}
|
||||
packages[loadedType.PkgPath()] = pkgTypes
|
||||
}
|
||||
types[loadedType.String()] = loadedType
|
||||
pkgTypes[loadedType.Name()] = loadedType
|
||||
}
|
||||
if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Ptr &&
|
||||
typ.Elem().Elem().Kind() == reflect.Struct {
|
||||
loadedType := typ.Elem().Elem()
|
||||
pkgTypes := packages[loadedType.PkgPath()]
|
||||
if pkgTypes == nil {
|
||||
pkgTypes = map[string]reflect.Type{}
|
||||
packages[loadedType.PkgPath()] = pkgTypes
|
||||
}
|
||||
types[loadedType.String()] = loadedType
|
||||
pkgTypes[loadedType.Name()] = loadedType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func loadGo17Types() {
|
||||
var obj interface{} = reflect.TypeOf(0)
|
||||
sections, offset := typelinks2()
|
||||
for i, offs := range offset {
|
||||
rodata := sections[i]
|
||||
for _, off := range offs {
|
||||
(*emptyInterface)(unsafe.Pointer(&obj)).word = resolveTypeOff(unsafe.Pointer(rodata), off)
|
||||
typ := obj.(reflect.Type)
|
||||
if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct {
|
||||
loadedType := typ.Elem()
|
||||
pkgTypes := packages[loadedType.PkgPath()]
|
||||
if pkgTypes == nil {
|
||||
pkgTypes = map[string]reflect.Type{}
|
||||
packages[loadedType.PkgPath()] = pkgTypes
|
||||
}
|
||||
types[loadedType.String()] = loadedType
|
||||
pkgTypes[loadedType.Name()] = loadedType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type emptyInterface struct {
|
||||
typ unsafe.Pointer
|
||||
word unsafe.Pointer
|
||||
}
|
||||
|
||||
// TypeByName return the type by its name, just like Class.forName in java
|
||||
func TypeByName(typeName string) Type {
|
||||
return Type2(types[typeName])
|
||||
}
|
||||
|
||||
// TypeByPackageName return the type by its package and name
|
||||
func TypeByPackageName(pkgPath string, name string) Type {
|
||||
pkgTypes := packages[pkgPath]
|
||||
if pkgTypes == nil {
|
||||
return nil
|
||||
}
|
||||
return Type2(pkgTypes[name])
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package reflect2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type UnsafeArrayType struct {
|
||||
unsafeType
|
||||
elemRType unsafe.Pointer
|
||||
pElemRType unsafe.Pointer
|
||||
elemSize uintptr
|
||||
likePtr bool
|
||||
}
|
||||
|
||||
func newUnsafeArrayType(cfg *frozenConfig, type1 reflect.Type) *UnsafeArrayType {
|
||||
return &UnsafeArrayType{
|
||||
unsafeType: *newUnsafeType(cfg, type1),
|
||||
elemRType: unpackEFace(type1.Elem()).data,
|
||||
pElemRType: unpackEFace(reflect.PtrTo(type1.Elem())).data,
|
||||
elemSize: type1.Elem().Size(),
|
||||
likePtr: likePtrType(type1),
|
||||
}
|
||||
}
|
||||
|
||||
func (type2 *UnsafeArrayType) LikePtr() bool {
|
||||
return type2.likePtr
|
||||
}
|
||||
|
||||
func (type2 *UnsafeArrayType) Indirect(obj interface{}) interface{} {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype)
|
||||
return type2.UnsafeIndirect(objEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeArrayType) UnsafeIndirect(ptr unsafe.Pointer) interface{} {
|
||||
if type2.likePtr {
|
||||
return packEFace(type2.rtype, *(*unsafe.Pointer)(ptr))
|
||||
}
|
||||
return packEFace(type2.rtype, ptr)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeArrayType) SetIndex(obj interface{}, index int, elem interface{}) {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("ArrayType.SetIndex argument 1", type2.ptrRType, objEFace.rtype)
|
||||
elemEFace := unpackEFace(elem)
|
||||
assertType("ArrayType.SetIndex argument 3", type2.pElemRType, elemEFace.rtype)
|
||||
type2.UnsafeSetIndex(objEFace.data, index, elemEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeArrayType) UnsafeSetIndex(obj unsafe.Pointer, index int, elem unsafe.Pointer) {
|
||||
elemPtr := arrayAt(obj, index, type2.elemSize, "i < s.Len")
|
||||
typedmemmove(type2.elemRType, elemPtr, elem)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeArrayType) GetIndex(obj interface{}, index int) interface{} {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("ArrayType.GetIndex argument 1", type2.ptrRType, objEFace.rtype)
|
||||
elemPtr := type2.UnsafeGetIndex(objEFace.data, index)
|
||||
return packEFace(type2.pElemRType, elemPtr)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeArrayType) UnsafeGetIndex(obj unsafe.Pointer, index int) unsafe.Pointer {
|
||||
return arrayAt(obj, index, type2.elemSize, "i < s.Len")
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package reflect2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type eface struct {
|
||||
rtype unsafe.Pointer
|
||||
data unsafe.Pointer
|
||||
}
|
||||
|
||||
func unpackEFace(obj interface{}) *eface {
|
||||
return (*eface)(unsafe.Pointer(&obj))
|
||||
}
|
||||
|
||||
func packEFace(rtype unsafe.Pointer, data unsafe.Pointer) interface{} {
|
||||
var i interface{}
|
||||
e := (*eface)(unsafe.Pointer(&i))
|
||||
e.rtype = rtype
|
||||
e.data = data
|
||||
return i
|
||||
}
|
||||
|
||||
type UnsafeEFaceType struct {
|
||||
unsafeType
|
||||
}
|
||||
|
||||
func newUnsafeEFaceType(cfg *frozenConfig, type1 reflect.Type) *UnsafeEFaceType {
|
||||
return &UnsafeEFaceType{
|
||||
unsafeType: *newUnsafeType(cfg, type1),
|
||||
}
|
||||
}
|
||||
|
||||
func (type2 *UnsafeEFaceType) IsNil(obj interface{}) bool {
|
||||
if obj == nil {
|
||||
return true
|
||||
}
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype)
|
||||
return type2.UnsafeIsNil(objEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeEFaceType) UnsafeIsNil(ptr unsafe.Pointer) bool {
|
||||
if ptr == nil {
|
||||
return true
|
||||
}
|
||||
return unpackEFace(*(*interface{})(ptr)).data == nil
|
||||
}
|
||||
|
||||
func (type2 *UnsafeEFaceType) Indirect(obj interface{}) interface{} {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype)
|
||||
return type2.UnsafeIndirect(objEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeEFaceType) UnsafeIndirect(ptr unsafe.Pointer) interface{} {
|
||||
return *(*interface{})(ptr)
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package reflect2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type UnsafeStructField struct {
|
||||
reflect.StructField
|
||||
structType *UnsafeStructType
|
||||
rtype unsafe.Pointer
|
||||
ptrRType unsafe.Pointer
|
||||
}
|
||||
|
||||
func newUnsafeStructField(structType *UnsafeStructType, structField reflect.StructField) *UnsafeStructField {
|
||||
return &UnsafeStructField{
|
||||
StructField: structField,
|
||||
rtype: unpackEFace(structField.Type).data,
|
||||
ptrRType: unpackEFace(reflect.PtrTo(structField.Type)).data,
|
||||
structType: structType,
|
||||
}
|
||||
}
|
||||
|
||||
func (field *UnsafeStructField) Offset() uintptr {
|
||||
return field.StructField.Offset
|
||||
}
|
||||
|
||||
func (field *UnsafeStructField) Name() string {
|
||||
return field.StructField.Name
|
||||
}
|
||||
|
||||
func (field *UnsafeStructField) PkgPath() string {
|
||||
return field.StructField.PkgPath
|
||||
}
|
||||
|
||||
func (field *UnsafeStructField) Type() Type {
|
||||
return field.structType.cfg.Type2(field.StructField.Type)
|
||||
}
|
||||
|
||||
func (field *UnsafeStructField) Tag() reflect.StructTag {
|
||||
return field.StructField.Tag
|
||||
}
|
||||
|
||||
func (field *UnsafeStructField) Index() []int {
|
||||
return field.StructField.Index
|
||||
}
|
||||
|
||||
func (field *UnsafeStructField) Anonymous() bool {
|
||||
return field.StructField.Anonymous
|
||||
}
|
||||
|
||||
func (field *UnsafeStructField) Set(obj interface{}, value interface{}) {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("StructField.SetIndex argument 1", field.structType.ptrRType, objEFace.rtype)
|
||||
valueEFace := unpackEFace(value)
|
||||
assertType("StructField.SetIndex argument 2", field.ptrRType, valueEFace.rtype)
|
||||
field.UnsafeSet(objEFace.data, valueEFace.data)
|
||||
}
|
||||
|
||||
func (field *UnsafeStructField) UnsafeSet(obj unsafe.Pointer, value unsafe.Pointer) {
|
||||
fieldPtr := add(obj, field.StructField.Offset, "same as non-reflect &v.field")
|
||||
typedmemmove(field.rtype, fieldPtr, value)
|
||||
}
|
||||
|
||||
func (field *UnsafeStructField) Get(obj interface{}) interface{} {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("StructField.GetIndex argument 1", field.structType.ptrRType, objEFace.rtype)
|
||||
value := field.UnsafeGet(objEFace.data)
|
||||
return packEFace(field.ptrRType, value)
|
||||
}
|
||||
|
||||
func (field *UnsafeStructField) UnsafeGet(obj unsafe.Pointer) unsafe.Pointer {
|
||||
return add(obj, field.StructField.Offset, "same as non-reflect &v.field")
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package reflect2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type iface struct {
|
||||
itab *itab
|
||||
data unsafe.Pointer
|
||||
}
|
||||
|
||||
type itab struct {
|
||||
ignore unsafe.Pointer
|
||||
rtype unsafe.Pointer
|
||||
}
|
||||
|
||||
func IFaceToEFace(ptr unsafe.Pointer) interface{} {
|
||||
iface := (*iface)(ptr)
|
||||
if iface.itab == nil {
|
||||
return nil
|
||||
}
|
||||
return packEFace(iface.itab.rtype, iface.data)
|
||||
}
|
||||
|
||||
type UnsafeIFaceType struct {
|
||||
unsafeType
|
||||
}
|
||||
|
||||
func newUnsafeIFaceType(cfg *frozenConfig, type1 reflect.Type) *UnsafeIFaceType {
|
||||
return &UnsafeIFaceType{
|
||||
unsafeType: *newUnsafeType(cfg, type1),
|
||||
}
|
||||
}
|
||||
|
||||
func (type2 *UnsafeIFaceType) Indirect(obj interface{}) interface{} {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype)
|
||||
return type2.UnsafeIndirect(objEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeIFaceType) UnsafeIndirect(ptr unsafe.Pointer) interface{} {
|
||||
return IFaceToEFace(ptr)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeIFaceType) IsNil(obj interface{}) bool {
|
||||
if obj == nil {
|
||||
return true
|
||||
}
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype)
|
||||
return type2.UnsafeIsNil(objEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeIFaceType) UnsafeIsNil(ptr unsafe.Pointer) bool {
|
||||
if ptr == nil {
|
||||
return true
|
||||
}
|
||||
iface := (*iface)(ptr)
|
||||
if iface.itab == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package reflect2
|
||||
|
||||
import "unsafe"
|
||||
|
||||
//go:linkname unsafe_New reflect.unsafe_New
|
||||
func unsafe_New(rtype unsafe.Pointer) unsafe.Pointer
|
||||
|
||||
//go:linkname typedmemmove reflect.typedmemmove
|
||||
func typedmemmove(rtype unsafe.Pointer, dst, src unsafe.Pointer)
|
||||
|
||||
//go:linkname unsafe_NewArray reflect.unsafe_NewArray
|
||||
func unsafe_NewArray(rtype unsafe.Pointer, length int) unsafe.Pointer
|
||||
|
||||
// typedslicecopy copies a slice of elemType values from src to dst,
|
||||
// returning the number of elements copied.
|
||||
//go:linkname typedslicecopy reflect.typedslicecopy
|
||||
//go:noescape
|
||||
func typedslicecopy(elemType unsafe.Pointer, dst, src sliceHeader) int
|
||||
|
||||
//go:linkname mapassign reflect.mapassign
|
||||
//go:noescape
|
||||
func mapassign(rtype unsafe.Pointer, m unsafe.Pointer, key, val unsafe.Pointer)
|
||||
|
||||
//go:linkname mapaccess reflect.mapaccess
|
||||
//go:noescape
|
||||
func mapaccess(rtype unsafe.Pointer, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer)
|
||||
|
||||
// m escapes into the return value, but the caller of mapiterinit
|
||||
// doesn't let the return value escape.
|
||||
//go:noescape
|
||||
//go:linkname mapiterinit reflect.mapiterinit
|
||||
func mapiterinit(rtype unsafe.Pointer, m unsafe.Pointer) *hiter
|
||||
|
||||
//go:noescape
|
||||
//go:linkname mapiternext reflect.mapiternext
|
||||
func mapiternext(it *hiter)
|
||||
|
||||
//go:linkname ifaceE2I reflect.ifaceE2I
|
||||
func ifaceE2I(rtype unsafe.Pointer, src interface{}, dst unsafe.Pointer)
|
||||
|
||||
// A hash iteration structure.
|
||||
// If you modify hiter, also change cmd/internal/gc/reflect.go to indicate
|
||||
// the layout of this structure.
|
||||
type hiter struct {
|
||||
key unsafe.Pointer // Must be in first position. Write nil to indicate iteration end (see cmd/internal/gc/range.go).
|
||||
value unsafe.Pointer // Must be in second position (see cmd/internal/gc/range.go).
|
||||
// rest fields are ignored
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
package reflect2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type UnsafeMapType struct {
|
||||
unsafeType
|
||||
pKeyRType unsafe.Pointer
|
||||
pElemRType unsafe.Pointer
|
||||
}
|
||||
|
||||
func newUnsafeMapType(cfg *frozenConfig, type1 reflect.Type) MapType {
|
||||
return &UnsafeMapType{
|
||||
unsafeType: *newUnsafeType(cfg, type1),
|
||||
pKeyRType: unpackEFace(reflect.PtrTo(type1.Key())).data,
|
||||
pElemRType: unpackEFace(reflect.PtrTo(type1.Elem())).data,
|
||||
}
|
||||
}
|
||||
|
||||
func (type2 *UnsafeMapType) IsNil(obj interface{}) bool {
|
||||
if obj == nil {
|
||||
return true
|
||||
}
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype)
|
||||
return type2.UnsafeIsNil(objEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeMapType) UnsafeIsNil(ptr unsafe.Pointer) bool {
|
||||
if ptr == nil {
|
||||
return true
|
||||
}
|
||||
return *(*unsafe.Pointer)(ptr) == nil
|
||||
}
|
||||
|
||||
func (type2 *UnsafeMapType) LikePtr() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (type2 *UnsafeMapType) Indirect(obj interface{}) interface{} {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("MapType.Indirect argument 1", type2.ptrRType, objEFace.rtype)
|
||||
return type2.UnsafeIndirect(objEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeMapType) UnsafeIndirect(ptr unsafe.Pointer) interface{} {
|
||||
return packEFace(type2.rtype, *(*unsafe.Pointer)(ptr))
|
||||
}
|
||||
|
||||
func (type2 *UnsafeMapType) Key() Type {
|
||||
return type2.cfg.Type2(type2.Type.Key())
|
||||
}
|
||||
|
||||
func (type2 *UnsafeMapType) MakeMap(cap int) interface{} {
|
||||
return packEFace(type2.ptrRType, type2.UnsafeMakeMap(cap))
|
||||
}
|
||||
|
||||
func (type2 *UnsafeMapType) UnsafeMakeMap(cap int) unsafe.Pointer {
|
||||
m := makeMapWithSize(type2.rtype, cap)
|
||||
return unsafe.Pointer(&m)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeMapType) SetIndex(obj interface{}, key interface{}, elem interface{}) {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("MapType.SetIndex argument 1", type2.ptrRType, objEFace.rtype)
|
||||
keyEFace := unpackEFace(key)
|
||||
assertType("MapType.SetIndex argument 2", type2.pKeyRType, keyEFace.rtype)
|
||||
elemEFace := unpackEFace(elem)
|
||||
assertType("MapType.SetIndex argument 3", type2.pElemRType, elemEFace.rtype)
|
||||
type2.UnsafeSetIndex(objEFace.data, keyEFace.data, elemEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeMapType) UnsafeSetIndex(obj unsafe.Pointer, key unsafe.Pointer, elem unsafe.Pointer) {
|
||||
mapassign(type2.rtype, *(*unsafe.Pointer)(obj), key, elem)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeMapType) TryGetIndex(obj interface{}, key interface{}) (interface{}, bool) {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("MapType.TryGetIndex argument 1", type2.ptrRType, objEFace.rtype)
|
||||
keyEFace := unpackEFace(key)
|
||||
assertType("MapType.TryGetIndex argument 2", type2.pKeyRType, keyEFace.rtype)
|
||||
elemPtr := type2.UnsafeGetIndex(objEFace.data, keyEFace.data)
|
||||
if elemPtr == nil {
|
||||
return nil, false
|
||||
}
|
||||
return packEFace(type2.pElemRType, elemPtr), true
|
||||
}
|
||||
|
||||
func (type2 *UnsafeMapType) GetIndex(obj interface{}, key interface{}) interface{} {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("MapType.GetIndex argument 1", type2.ptrRType, objEFace.rtype)
|
||||
keyEFace := unpackEFace(key)
|
||||
assertType("MapType.GetIndex argument 2", type2.pKeyRType, keyEFace.rtype)
|
||||
elemPtr := type2.UnsafeGetIndex(objEFace.data, keyEFace.data)
|
||||
return packEFace(type2.pElemRType, elemPtr)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeMapType) UnsafeGetIndex(obj unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer {
|
||||
return mapaccess(type2.rtype, *(*unsafe.Pointer)(obj), key)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeMapType) Iterate(obj interface{}) MapIterator {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("MapType.Iterate argument 1", type2.ptrRType, objEFace.rtype)
|
||||
return type2.UnsafeIterate(objEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeMapType) UnsafeIterate(obj unsafe.Pointer) MapIterator {
|
||||
return &UnsafeMapIterator{
|
||||
hiter: mapiterinit(type2.rtype, *(*unsafe.Pointer)(obj)),
|
||||
pKeyRType: type2.pKeyRType,
|
||||
pElemRType: type2.pElemRType,
|
||||
}
|
||||
}
|
||||
|
||||
type UnsafeMapIterator struct {
|
||||
*hiter
|
||||
pKeyRType unsafe.Pointer
|
||||
pElemRType unsafe.Pointer
|
||||
}
|
||||
|
||||
func (iter *UnsafeMapIterator) HasNext() bool {
|
||||
return iter.key != nil
|
||||
}
|
||||
|
||||
func (iter *UnsafeMapIterator) Next() (interface{}, interface{}) {
|
||||
key, elem := iter.UnsafeNext()
|
||||
return packEFace(iter.pKeyRType, key), packEFace(iter.pElemRType, elem)
|
||||
}
|
||||
|
||||
func (iter *UnsafeMapIterator) UnsafeNext() (unsafe.Pointer, unsafe.Pointer) {
|
||||
key := iter.key
|
||||
elem := iter.value
|
||||
mapiternext(iter.hiter)
|
||||
return key, elem
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package reflect2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type UnsafePtrType struct {
|
||||
unsafeType
|
||||
}
|
||||
|
||||
func newUnsafePtrType(cfg *frozenConfig, type1 reflect.Type) *UnsafePtrType {
|
||||
return &UnsafePtrType{
|
||||
unsafeType: *newUnsafeType(cfg, type1),
|
||||
}
|
||||
}
|
||||
|
||||
func (type2 *UnsafePtrType) IsNil(obj interface{}) bool {
|
||||
if obj == nil {
|
||||
return true
|
||||
}
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype)
|
||||
return type2.UnsafeIsNil(objEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafePtrType) UnsafeIsNil(ptr unsafe.Pointer) bool {
|
||||
if ptr == nil {
|
||||
return true
|
||||
}
|
||||
return *(*unsafe.Pointer)(ptr) == nil
|
||||
}
|
||||
|
||||
func (type2 *UnsafePtrType) LikePtr() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (type2 *UnsafePtrType) Indirect(obj interface{}) interface{} {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype)
|
||||
return type2.UnsafeIndirect(objEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafePtrType) UnsafeIndirect(ptr unsafe.Pointer) interface{} {
|
||||
return packEFace(type2.rtype, *(*unsafe.Pointer)(ptr))
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
package reflect2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// sliceHeader is a safe version of SliceHeader used within this package.
|
||||
type sliceHeader struct {
|
||||
Data unsafe.Pointer
|
||||
Len int
|
||||
Cap int
|
||||
}
|
||||
|
||||
type UnsafeSliceType struct {
|
||||
unsafeType
|
||||
elemRType unsafe.Pointer
|
||||
pElemRType unsafe.Pointer
|
||||
elemSize uintptr
|
||||
}
|
||||
|
||||
func newUnsafeSliceType(cfg *frozenConfig, type1 reflect.Type) SliceType {
|
||||
elemType := type1.Elem()
|
||||
return &UnsafeSliceType{
|
||||
unsafeType: *newUnsafeType(cfg, type1),
|
||||
pElemRType: unpackEFace(reflect.PtrTo(elemType)).data,
|
||||
elemRType: unpackEFace(elemType).data,
|
||||
elemSize: elemType.Size(),
|
||||
}
|
||||
}
|
||||
|
||||
func (type2 *UnsafeSliceType) Set(obj interface{}, val interface{}) {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("Type.Set argument 1", type2.ptrRType, objEFace.rtype)
|
||||
valEFace := unpackEFace(val)
|
||||
assertType("Type.Set argument 2", type2.ptrRType, valEFace.rtype)
|
||||
type2.UnsafeSet(objEFace.data, valEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeSliceType) UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer) {
|
||||
*(*sliceHeader)(ptr) = *(*sliceHeader)(val)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeSliceType) IsNil(obj interface{}) bool {
|
||||
if obj == nil {
|
||||
return true
|
||||
}
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype)
|
||||
return type2.UnsafeIsNil(objEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeSliceType) UnsafeIsNil(ptr unsafe.Pointer) bool {
|
||||
if ptr == nil {
|
||||
return true
|
||||
}
|
||||
return (*sliceHeader)(ptr).Data == nil
|
||||
}
|
||||
|
||||
func (type2 *UnsafeSliceType) SetNil(obj interface{}) {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("SliceType.SetNil argument 1", type2.ptrRType, objEFace.rtype)
|
||||
type2.UnsafeSetNil(objEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeSliceType) UnsafeSetNil(ptr unsafe.Pointer) {
|
||||
header := (*sliceHeader)(ptr)
|
||||
header.Len = 0
|
||||
header.Cap = 0
|
||||
header.Data = nil
|
||||
}
|
||||
|
||||
func (type2 *UnsafeSliceType) MakeSlice(length int, cap int) interface{} {
|
||||
return packEFace(type2.ptrRType, type2.UnsafeMakeSlice(length, cap))
|
||||
}
|
||||
|
||||
func (type2 *UnsafeSliceType) UnsafeMakeSlice(length int, cap int) unsafe.Pointer {
|
||||
header := &sliceHeader{unsafe_NewArray(type2.elemRType, cap), length, cap}
|
||||
return unsafe.Pointer(header)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeSliceType) LengthOf(obj interface{}) int {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("SliceType.Len argument 1", type2.ptrRType, objEFace.rtype)
|
||||
return type2.UnsafeLengthOf(objEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeSliceType) UnsafeLengthOf(obj unsafe.Pointer) int {
|
||||
header := (*sliceHeader)(obj)
|
||||
return header.Len
|
||||
}
|
||||
|
||||
func (type2 *UnsafeSliceType) SetIndex(obj interface{}, index int, elem interface{}) {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("SliceType.SetIndex argument 1", type2.ptrRType, objEFace.rtype)
|
||||
elemEFace := unpackEFace(elem)
|
||||
assertType("SliceType.SetIndex argument 3", type2.pElemRType, elemEFace.rtype)
|
||||
type2.UnsafeSetIndex(objEFace.data, index, elemEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeSliceType) UnsafeSetIndex(obj unsafe.Pointer, index int, elem unsafe.Pointer) {
|
||||
header := (*sliceHeader)(obj)
|
||||
elemPtr := arrayAt(header.Data, index, type2.elemSize, "i < s.Len")
|
||||
typedmemmove(type2.elemRType, elemPtr, elem)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeSliceType) GetIndex(obj interface{}, index int) interface{} {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("SliceType.GetIndex argument 1", type2.ptrRType, objEFace.rtype)
|
||||
elemPtr := type2.UnsafeGetIndex(objEFace.data, index)
|
||||
return packEFace(type2.pElemRType, elemPtr)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeSliceType) UnsafeGetIndex(obj unsafe.Pointer, index int) unsafe.Pointer {
|
||||
header := (*sliceHeader)(obj)
|
||||
return arrayAt(header.Data, index, type2.elemSize, "i < s.Len")
|
||||
}
|
||||
|
||||
func (type2 *UnsafeSliceType) Append(obj interface{}, elem interface{}) {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("SliceType.Append argument 1", type2.ptrRType, objEFace.rtype)
|
||||
elemEFace := unpackEFace(elem)
|
||||
assertType("SliceType.Append argument 2", type2.pElemRType, elemEFace.rtype)
|
||||
type2.UnsafeAppend(objEFace.data, elemEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeSliceType) UnsafeAppend(obj unsafe.Pointer, elem unsafe.Pointer) {
|
||||
header := (*sliceHeader)(obj)
|
||||
oldLen := header.Len
|
||||
type2.UnsafeGrow(obj, oldLen+1)
|
||||
type2.UnsafeSetIndex(obj, oldLen, elem)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeSliceType) Cap(obj interface{}) int {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("SliceType.Cap argument 1", type2.ptrRType, objEFace.rtype)
|
||||
return type2.UnsafeCap(objEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeSliceType) UnsafeCap(ptr unsafe.Pointer) int {
|
||||
return (*sliceHeader)(ptr).Cap
|
||||
}
|
||||
|
||||
func (type2 *UnsafeSliceType) Grow(obj interface{}, newLength int) {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("SliceType.Grow argument 1", type2.ptrRType, objEFace.rtype)
|
||||
type2.UnsafeGrow(objEFace.data, newLength)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeSliceType) UnsafeGrow(obj unsafe.Pointer, newLength int) {
|
||||
header := (*sliceHeader)(obj)
|
||||
if newLength <= header.Cap {
|
||||
header.Len = newLength
|
||||
return
|
||||
}
|
||||
newCap := calcNewCap(header.Cap, newLength)
|
||||
newHeader := (*sliceHeader)(type2.UnsafeMakeSlice(header.Len, newCap))
|
||||
typedslicecopy(type2.elemRType, *newHeader, *header)
|
||||
header.Data = newHeader.Data
|
||||
header.Cap = newHeader.Cap
|
||||
header.Len = newLength
|
||||
}
|
||||
|
||||
func calcNewCap(cap int, expectedCap int) int {
|
||||
if cap == 0 {
|
||||
cap = expectedCap
|
||||
} else {
|
||||
for cap < expectedCap {
|
||||
if cap < 1024 {
|
||||
cap += cap
|
||||
} else {
|
||||
cap += cap / 4
|
||||
}
|
||||
}
|
||||
}
|
||||
return cap
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package reflect2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type UnsafeStructType struct {
|
||||
unsafeType
|
||||
likePtr bool
|
||||
}
|
||||
|
||||
func newUnsafeStructType(cfg *frozenConfig, type1 reflect.Type) *UnsafeStructType {
|
||||
return &UnsafeStructType{
|
||||
unsafeType: *newUnsafeType(cfg, type1),
|
||||
likePtr: likePtrType(type1),
|
||||
}
|
||||
}
|
||||
|
||||
func (type2 *UnsafeStructType) LikePtr() bool {
|
||||
return type2.likePtr
|
||||
}
|
||||
|
||||
func (type2 *UnsafeStructType) Indirect(obj interface{}) interface{} {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype)
|
||||
return type2.UnsafeIndirect(objEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeStructType) UnsafeIndirect(ptr unsafe.Pointer) interface{} {
|
||||
if type2.likePtr {
|
||||
return packEFace(type2.rtype, *(*unsafe.Pointer)(ptr))
|
||||
}
|
||||
return packEFace(type2.rtype, ptr)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeStructType) FieldByName(name string) StructField {
|
||||
structField, found := type2.Type.FieldByName(name)
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
return newUnsafeStructField(type2, structField)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeStructType) Field(i int) StructField {
|
||||
return newUnsafeStructField(type2, type2.Type.Field(i))
|
||||
}
|
||||
|
||||
func (type2 *UnsafeStructType) FieldByIndex(index []int) StructField {
|
||||
return newUnsafeStructField(type2, type2.Type.FieldByIndex(index))
|
||||
}
|
||||
|
||||
func (type2 *UnsafeStructType) FieldByNameFunc(match func(string) bool) StructField {
|
||||
structField, found := type2.Type.FieldByNameFunc(match)
|
||||
if !found {
|
||||
panic("field match condition not found in " + type2.Type.String())
|
||||
}
|
||||
return newUnsafeStructField(type2, structField)
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package reflect2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type unsafeType struct {
|
||||
safeType
|
||||
rtype unsafe.Pointer
|
||||
ptrRType unsafe.Pointer
|
||||
}
|
||||
|
||||
func newUnsafeType(cfg *frozenConfig, type1 reflect.Type) *unsafeType {
|
||||
return &unsafeType{
|
||||
safeType: safeType{
|
||||
Type: type1,
|
||||
cfg: cfg,
|
||||
},
|
||||
rtype: unpackEFace(type1).data,
|
||||
ptrRType: unpackEFace(reflect.PtrTo(type1)).data,
|
||||
}
|
||||
}
|
||||
|
||||
func (type2 *unsafeType) Set(obj interface{}, val interface{}) {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("Type.Set argument 1", type2.ptrRType, objEFace.rtype)
|
||||
valEFace := unpackEFace(val)
|
||||
assertType("Type.Set argument 2", type2.ptrRType, valEFace.rtype)
|
||||
type2.UnsafeSet(objEFace.data, valEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *unsafeType) UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer) {
|
||||
typedmemmove(type2.rtype, ptr, val)
|
||||
}
|
||||
|
||||
func (type2 *unsafeType) IsNil(obj interface{}) bool {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype)
|
||||
return type2.UnsafeIsNil(objEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *unsafeType) UnsafeIsNil(ptr unsafe.Pointer) bool {
|
||||
return ptr == nil
|
||||
}
|
||||
|
||||
func (type2 *unsafeType) UnsafeNew() unsafe.Pointer {
|
||||
return unsafe_New(type2.rtype)
|
||||
}
|
||||
|
||||
func (type2 *unsafeType) New() interface{} {
|
||||
return packEFace(type2.ptrRType, type2.UnsafeNew())
|
||||
}
|
||||
|
||||
func (type2 *unsafeType) PackEFace(ptr unsafe.Pointer) interface{} {
|
||||
return packEFace(type2.ptrRType, ptr)
|
||||
}
|
||||
|
||||
func (type2 *unsafeType) RType() uintptr {
|
||||
return uintptr(type2.rtype)
|
||||
}
|
||||
|
||||
func (type2 *unsafeType) Indirect(obj interface{}) interface{} {
|
||||
objEFace := unpackEFace(obj)
|
||||
assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype)
|
||||
return type2.UnsafeIndirect(objEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *unsafeType) UnsafeIndirect(obj unsafe.Pointer) interface{} {
|
||||
return packEFace(type2.rtype, obj)
|
||||
}
|
||||
|
||||
func (type2 *unsafeType) LikePtr() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func assertType(where string, expectRType unsafe.Pointer, actualRType unsafe.Pointer) {
|
||||
if expectRType != actualRType {
|
||||
expectType := reflect.TypeOf(0)
|
||||
(*iface)(unsafe.Pointer(&expectType)).data = expectRType
|
||||
actualType := reflect.TypeOf(0)
|
||||
(*iface)(unsafe.Pointer(&actualType)).data = actualRType
|
||||
panic(where + ": expect " + expectType.String() + ", actual " + actualType.String())
|
||||
}
|
||||
}
|
|
@ -302,6 +302,18 @@
|
|||
"revision": "f77f16ffc87a6a58814e64ae72d55f9c41374e6d",
|
||||
"revisionTime": "2016-10-12T08:37:05Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "ZTcgWKWHsrX0RXYVXn5Xeb8Q0go=",
|
||||
"path": "github.com/modern-go/concurrent",
|
||||
"revision": "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94",
|
||||
"revisionTime": "2018-03-06T01:26:44Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "ntSr6NgBxGzQG1fgkl5IFgdjCLo=",
|
||||
"path": "github.com/modern-go/reflect2",
|
||||
"revision": "58118c1ea9161250907268a484af4dd6ed314280",
|
||||
"revisionTime": "2018-05-11T05:30:14Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "lfOuMiAdiqc/dalUSBTvD5ZMSzA=",
|
||||
"path": "github.com/msteinert/pam",
|
||||
|
|
Loading…
Reference in New Issue