2
0

Restored more optimised array type conversions for a few select 1D-slice types.

Results of calls to the reflect lib are now stored as local variables for small performance gains.
This commit is contained in:
Simo Haasanen
2020-08-08 19:51:37 +01:00
parent 449a8a4f8e
commit b90570feb5
25 changed files with 4594 additions and 1273 deletions
+111 -53
View File
@@ -30,56 +30,93 @@ func (dst *<%= pgtype_array_type %>) Set(src interface{}) error {
}
}
value := reflect.ValueOf(src)
if !value.IsValid() || value.IsZero() {
*dst = <%= pgtype_array_type %>{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflect.ValueOf(src), nil, 0)
if !ok {
return errors.Errorf("cannot find dimensions of %v for <%= pgtype_array_type %>", src)
}
if elementsLength == 0 {
*dst = <%= pgtype_array_type %>{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return errors.Errorf("cannot convert %v to <%= pgtype_array_type %>", src)
}
*dst = <%= pgtype_array_type %> {
Elements: make([]<%= pgtype_element_type %>, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflect.ValueOf(src), 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
switch value := src.(type) {
<% go_array_types.split(",").each do |t| %>
<% if t != "[]#{pgtype_element_type}" %>
case <%= t %>:
if value == nil {
*dst = <%= pgtype_array_type %>{Status: Null}
} else if len(value) == 0 {
*dst = <%= pgtype_array_type %>{Status: Present}
} else {
elements := make([]<%= pgtype_element_type %>, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
dst.Elements = make([]<%= pgtype_element_type %>, elementsLength)
elementCount, err = dst.setRecursive(reflect.ValueOf(src), 0, 0)
if err != nil {
*dst = <%= pgtype_array_type %>{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
<% end %>
<% end %>
case []<%= pgtype_element_type %>:
if value == nil {
*dst = <%= pgtype_array_type %>{Status: Null}
} else if len(value) == 0 {
*dst = <%= pgtype_array_type %>{Status: Present}
} else {
*dst = <%= pgtype_array_type %>{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status : Present,
}
}
default:
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = <%= pgtype_array_type %>{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return errors.Errorf("cannot find dimensions of %v for <%= pgtype_array_type %>", src)
}
if elementsLength == 0 {
*dst = <%= pgtype_array_type %>{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return errors.Errorf("cannot convert %v to <%= pgtype_array_type %>", src)
}
*dst = <%= pgtype_array_type %> {
Elements: make([]<%= pgtype_element_type %>, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]<%= pgtype_element_type %>, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return errors.Errorf("cannot convert %v to <%= pgtype_array_type %>, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
if elementCount != len(dst.Elements) {
return errors.Errorf("cannot convert %v to <%= pgtype_array_type %>, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
@@ -94,10 +131,11 @@ func (dst *<%= pgtype_array_type %>) setRecursive(value reflect.Value, index, di
break
}
if int32(value.Len()) != dst.Dimensions[dimension].Length {
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, errors.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < value.Len(); i++ {
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
@@ -132,6 +170,21 @@ func (dst <%= pgtype_array_type %>) Get() interface{} {
func (src *<%= pgtype_array_type %>) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) == 1{
switch v := dst.(type) {
<% go_array_types.split(",").each do |t| %>
case *<%= t %>:
*v = make(<%= t %>, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
<% end %>
}
}
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
@@ -170,10 +223,12 @@ func (src *<%= pgtype_array_type %>) assignToRecursive(value reflect.Value, inde
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
if value.Type().Len() != length {
return 0, errors.Errorf("expected size %d array, but %s has size %d array", length, value.Type(), value.Type().Len())
typ := value.Type()
typLen := typ.Len()
if typLen != length {
return 0, errors.Errorf("expected size %d array, but %s has size %d array", length, typ, typLen)
}
value.Set(reflect.New(value.Type()).Elem())
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
@@ -191,11 +246,14 @@ func (src *<%= pgtype_array_type %>) assignToRecursive(value reflect.Value, inde
if len(src.Dimensions) != dimension {
return 0, errors.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() || !value.Addr().CanInterface() {
if !value.CanAddr(){
return 0, errors.Errorf("cannot assign all values from <%= pgtype_array_type %>")
}
err := src.Elements[index].AssignTo(value.Addr().Interface())
if err != nil {
addr := value.Addr()
if !addr.CanInterface() {
return 0, errors.Errorf("cannot assign all values from <%= pgtype_array_type %>")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++