podman

Форк
0
214 строк · 4.6 Кб
1
/*
2
 * Copyright 2021 ByteDance Inc.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package resolver
18

19
import (
20
    `fmt`
21
    `reflect`
22
    `strings`
23
    `sync`
24
)
25

26
type FieldOpts int
27
type OffsetType int
28

29
const (
30
    F_omitempty FieldOpts = 1 << iota
31
    F_stringize
32
)
33

34
const (
35
    F_offset OffsetType = iota
36
    F_deref
37
)
38

39
type Offset struct {
40
    Size uintptr
41
    Kind OffsetType
42
    Type reflect.Type
43
}
44

45
type FieldMeta struct {
46
    Name string
47
    Path []Offset
48
    Opts FieldOpts
49
    Type reflect.Type
50
}
51

52
func (self *FieldMeta) String() string {
53
    var path []string
54
    var opts []string
55

56
    /* dump the field path */
57
    for _, off := range self.Path {
58
        if off.Kind == F_offset {
59
            path = append(path, fmt.Sprintf("%d", off.Size))
60
        } else {
61
            path = append(path, fmt.Sprintf("%d.(*%s)", off.Size, off.Type))
62
        }
63
    }
64

65
    /* check for "string" */
66
    if (self.Opts & F_stringize) != 0 {
67
        opts = append(opts, "string")
68
    }
69

70
    /* check for "omitempty" */
71
    if (self.Opts & F_omitempty) != 0 {
72
        opts = append(opts, "omitempty")
73
    }
74

75
    /* format the field */
76
    return fmt.Sprintf(
77
        "{Field \"%s\" @ %s, opts=%s, type=%s}",
78
        self.Name,
79
        strings.Join(path, "."),
80
        strings.Join(opts, ","),
81
        self.Type,
82
    )
83
}
84

85
func (self *FieldMeta) optimize() {
86
    var n int
87
    var v uintptr
88

89
    /* merge adjacent offsets */
90
    for _, o := range self.Path {
91
        if v += o.Size; o.Kind == F_deref {
92
            self.Path[n].Size    = v
93
            self.Path[n].Type, v = o.Type, 0
94
            self.Path[n].Kind, n = F_deref, n + 1
95
        }
96
    }
97

98
    /* last offset value */
99
    if v != 0 {
100
        self.Path[n].Size = v
101
        self.Path[n].Type = nil
102
        self.Path[n].Kind = F_offset
103
        n++
104
    }
105

106
    /* must be at least 1 offset */
107
    if n != 0 {
108
        self.Path = self.Path[:n]
109
    } else {
110
        self.Path = []Offset{{Kind: F_offset}}
111
    }
112
}
113

114
func resolveFields(vt reflect.Type) []FieldMeta {
115
    tfv := typeFields(vt)
116
    ret := []FieldMeta(nil)
117

118
    /* convert each field */
119
    for _, fv := range tfv.list {
120
        item := vt
121
        path := []Offset(nil)
122
        opts := FieldOpts(0)
123

124
        /* check for "string" */
125
        if fv.quoted {
126
            opts |= F_stringize
127
        }
128

129
        /* check for "omitempty" */
130
        if fv.omitEmpty {
131
            opts |= F_omitempty
132
        }
133

134
        /* dump the field path */
135
        for _, i := range fv.index {
136
            kind := F_offset
137
            fval := item.Field(i)
138
            item  = fval.Type
139

140
            /* deref the pointer if needed */
141
            if item.Kind() == reflect.Ptr {
142
                kind = F_deref
143
                item = item.Elem()
144
            }
145

146
            /* add to path */
147
            path = append(path, Offset {
148
                Kind: kind,
149
                Type: item,
150
                Size: fval.Offset,
151
            })
152
        }
153

154
        /* get the index to the last offset */
155
        idx := len(path) - 1
156
        fvt := path[idx].Type
157

158
        /* do not dereference into fields */
159
        if path[idx].Kind == F_deref {
160
            fvt = reflect.PtrTo(fvt)
161
            path[idx].Kind = F_offset
162
        }
163

164
        /* add to result */
165
        ret = append(ret, FieldMeta {
166
            Type: fvt,
167
            Opts: opts,
168
            Path: path,
169
            Name: fv.name,
170
        })
171
    }
172

173
    /* optimize the offsets */
174
    for i := range ret {
175
        ret[i].optimize()
176
    }
177

178
    /* all done */
179
    return ret
180
}
181

182
var (
183
    fieldLock  = sync.RWMutex{}
184
    fieldCache = map[reflect.Type][]FieldMeta{}
185
)
186

187
func ResolveStruct(vt reflect.Type) []FieldMeta {
188
    var ok bool
189
    var fm []FieldMeta
190

191
    /* attempt to read from cache */
192
    fieldLock.RLock()
193
    fm, ok = fieldCache[vt]
194
    fieldLock.RUnlock()
195

196
    /* check if it was cached */
197
    if ok {
198
        return fm
199
    }
200

201
    /* otherwise use write-lock */
202
    fieldLock.Lock()
203
    defer fieldLock.Unlock()
204

205
    /* double check */
206
    if fm, ok = fieldCache[vt]; ok {
207
        return fm
208
    }
209

210
    /* resolve the field */
211
    fm = resolveFields(vt)
212
    fieldCache[vt] = fm
213
    return fm
214
}
215

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.