mirror of https://github.com/gogits/gogs.git
Unknwon
7 years ago
45 changed files with 2473 additions and 0 deletions
@ -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 |
||||
|
||||
[![Sourcegraph](https://sourcegraph.com/github.com/modern-go/concurrent/-/badge.svg)](https://sourcegraph.com/github.com/modern-go/concurrent?badge) |
||||
[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/modern-go/concurrent) |
||||
[![Build Status](https://travis-ci.org/modern-go/concurrent.svg?branch=master)](https://travis-ci.org/modern-go/concurrent) |
||||
[![codecov](https://codecov.io/gh/modern-go/concurrent/branch/master/graph/badge.svg)](https://codecov.io/gh/modern-go/concurrent) |
||||
[![rcard](https://goreportcard.com/badge/github.com/modern-go/concurrent)](https://goreportcard.com/report/github.com/modern-go/concurrent) |
||||
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](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 |
||||
|
||||
[![Sourcegraph](https://sourcegraph.com/github.com/modern-go/reflect2/-/badge.svg)](https://sourcegraph.com/github.com/modern-go/reflect2?badge) |
||||
[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/modern-go/reflect2) |
||||
[![Build Status](https://travis-ci.org/modern-go/reflect2.svg?branch=master)](https://travis-ci.org/modern-go/reflect2) |
||||
[![codecov](https://codecov.io/gh/modern-go/reflect2/branch/master/graph/badge.svg)](https://codecov.io/gh/modern-go/reflect2) |
||||
[![rcard](https://goreportcard.com/badge/github.com/modern-go/reflect2)](https://goreportcard.com/report/github.com/modern-go/reflect2) |
||||
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](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()) |
||||
} |
||||
} |
Loading…
Reference in new issue