mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 08:46:55 +08:00
124 lines
3.5 KiB
Go
124 lines
3.5 KiB
Go
// Copyright 2025-2026 肖其顿 (XIAO QI DUN)
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package ofdgo
|
|
|
|
import (
|
|
"reflect"
|
|
"sync"
|
|
)
|
|
|
|
// editorClonePlans 仅共享类型的可变字段索引,不持有文档对象或资源
|
|
var editorClonePlans sync.Map
|
|
|
|
// cloneEditorData 深复制编辑快照,未导出的排版及原文来源保持不可变共享
|
|
// 入参: value 原值
|
|
// 返回: T 独立副本
|
|
func cloneEditorData[T any](value T) T {
|
|
source := reflect.ValueOf(value)
|
|
if !source.IsValid() {
|
|
return value
|
|
}
|
|
return cloneEditorValue(source).Interface().(T)
|
|
}
|
|
|
|
// cloneEditorValue 复制公开指针、切片及数组,纯值数据不创建额外结构
|
|
// 入参: value 原值
|
|
// 返回: reflect.Value 独立副本
|
|
func cloneEditorValue(value reflect.Value) reflect.Value {
|
|
if !value.IsValid() || !editorCloneMutable(value.Type()) {
|
|
return value
|
|
}
|
|
switch value.Kind() {
|
|
case reflect.Pointer:
|
|
if value.IsNil() {
|
|
return value
|
|
}
|
|
result := reflect.New(value.Type().Elem())
|
|
cloneEditorInto(result.Elem(), value.Elem())
|
|
return result
|
|
case reflect.Slice:
|
|
if value.IsNil() {
|
|
return value
|
|
}
|
|
result := reflect.MakeSlice(value.Type(), value.Len(), value.Len())
|
|
if !editorCloneMutable(value.Type().Elem()) {
|
|
reflect.Copy(result, value)
|
|
} else {
|
|
for i := range value.Len() {
|
|
cloneEditorInto(result.Index(i), value.Index(i))
|
|
}
|
|
}
|
|
return result
|
|
default:
|
|
result := reflect.New(value.Type()).Elem()
|
|
cloneEditorInto(result, value)
|
|
return result
|
|
}
|
|
}
|
|
|
|
// cloneEditorInto 直接填充目标结构,避免指针及切片成员的二次结构分配
|
|
// 入参: target 可写目标, source 原值
|
|
func cloneEditorInto(target, source reflect.Value) {
|
|
switch source.Kind() {
|
|
case reflect.Struct:
|
|
target.Set(source)
|
|
for _, i := range editorCloneFields(source.Type()) {
|
|
cloneEditorInto(target.Field(i), source.Field(i))
|
|
}
|
|
case reflect.Array:
|
|
target.Set(source)
|
|
if editorCloneMutable(source.Type().Elem()) {
|
|
for i := range source.Len() {
|
|
cloneEditorInto(target.Index(i), source.Index(i))
|
|
}
|
|
}
|
|
default:
|
|
target.Set(cloneEditorValue(source))
|
|
}
|
|
}
|
|
|
|
// editorCloneMutable 判断类型是否含有需要隔离的公开可变成员
|
|
// 入参: kind 数据类型
|
|
// 返回: bool 是否需要独立复制
|
|
func editorCloneMutable(kind reflect.Type) bool {
|
|
switch kind.Kind() {
|
|
case reflect.Pointer, reflect.Slice:
|
|
return true
|
|
case reflect.Array:
|
|
return editorCloneMutable(kind.Elem())
|
|
case reflect.Struct:
|
|
return len(editorCloneFields(kind)) != 0
|
|
}
|
|
return false
|
|
}
|
|
|
|
// editorCloneFields 按类型复用公开可变字段,索引发布后保持只读
|
|
// 入参: kind 结构类型
|
|
// 返回: []int 可变字段索引
|
|
func editorCloneFields(kind reflect.Type) []int {
|
|
if cached, ok := editorClonePlans.Load(kind); ok {
|
|
return cached.([]int)
|
|
}
|
|
var fields []int
|
|
for i := range kind.NumField() {
|
|
field := kind.Field(i)
|
|
if field.IsExported() && editorCloneMutable(field.Type) {
|
|
fields = append(fields, i)
|
|
}
|
|
}
|
|
actual, _ := editorClonePlans.LoadOrStore(kind, fields)
|
|
return actual.([]int)
|
|
}
|