hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

math.go (3801B)

    1 // Copyright 2018 The Hugo Authors. All rights reserved.
    2 //
    3 // Licensed under the Apache License, Version 2.0 (the "License");
    4 // you may not use this file except in compliance with the License.
    5 // You may obtain a copy of the License at
    6 // http://www.apache.org/licenses/LICENSE-2.0
    7 //
    8 // Unless required by applicable law or agreed to in writing, software
    9 // distributed under the License is distributed on an "AS IS" BASIS,
   10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   11 // See the License for the specific language governing permissions and
   12 // limitations under the License.
   13 
   14 package math
   15 
   16 import (
   17 	"errors"
   18 	"reflect"
   19 )
   20 
   21 // DoArithmetic performs arithmetic operations (+,-,*,/) using reflection to
   22 // determine the type of the two terms.
   23 func DoArithmetic(a, b any, op rune) (any, error) {
   24 	av := reflect.ValueOf(a)
   25 	bv := reflect.ValueOf(b)
   26 	var ai, bi int64
   27 	var af, bf float64
   28 	var au, bu uint64
   29 	switch av.Kind() {
   30 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   31 		ai = av.Int()
   32 		switch bv.Kind() {
   33 		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   34 			bi = bv.Int()
   35 		case reflect.Float32, reflect.Float64:
   36 			af = float64(ai) // may overflow
   37 			ai = 0
   38 			bf = bv.Float()
   39 		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   40 			bu = bv.Uint()
   41 			if ai >= 0 {
   42 				au = uint64(ai)
   43 				ai = 0
   44 			} else {
   45 				bi = int64(bu) // may overflow
   46 				bu = 0
   47 			}
   48 		default:
   49 			return nil, errors.New("can't apply the operator to the values")
   50 		}
   51 	case reflect.Float32, reflect.Float64:
   52 		af = av.Float()
   53 		switch bv.Kind() {
   54 		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   55 			bf = float64(bv.Int()) // may overflow
   56 		case reflect.Float32, reflect.Float64:
   57 			bf = bv.Float()
   58 		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   59 			bf = float64(bv.Uint()) // may overflow
   60 		default:
   61 			return nil, errors.New("can't apply the operator to the values")
   62 		}
   63 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   64 		au = av.Uint()
   65 		switch bv.Kind() {
   66 		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   67 			bi = bv.Int()
   68 			if bi >= 0 {
   69 				bu = uint64(bi)
   70 				bi = 0
   71 			} else {
   72 				ai = int64(au) // may overflow
   73 				au = 0
   74 			}
   75 		case reflect.Float32, reflect.Float64:
   76 			af = float64(au) // may overflow
   77 			au = 0
   78 			bf = bv.Float()
   79 		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   80 			bu = bv.Uint()
   81 		default:
   82 			return nil, errors.New("can't apply the operator to the values")
   83 		}
   84 	case reflect.String:
   85 		as := av.String()
   86 		if bv.Kind() == reflect.String && op == '+' {
   87 			bs := bv.String()
   88 			return as + bs, nil
   89 		}
   90 		return nil, errors.New("can't apply the operator to the values")
   91 	default:
   92 		return nil, errors.New("can't apply the operator to the values")
   93 	}
   94 
   95 	switch op {
   96 	case '+':
   97 		if ai != 0 || bi != 0 {
   98 			return ai + bi, nil
   99 		} else if af != 0 || bf != 0 {
  100 			return af + bf, nil
  101 		} else if au != 0 || bu != 0 {
  102 			return au + bu, nil
  103 		}
  104 		return 0, nil
  105 	case '-':
  106 		if ai != 0 || bi != 0 {
  107 			return ai - bi, nil
  108 		} else if af != 0 || bf != 0 {
  109 			return af - bf, nil
  110 		} else if au != 0 || bu != 0 {
  111 			return au - bu, nil
  112 		}
  113 		return 0, nil
  114 	case '*':
  115 		if ai != 0 || bi != 0 {
  116 			return ai * bi, nil
  117 		} else if af != 0 || bf != 0 {
  118 			return af * bf, nil
  119 		} else if au != 0 || bu != 0 {
  120 			return au * bu, nil
  121 		}
  122 		return 0, nil
  123 	case '/':
  124 		if bi != 0 {
  125 			return ai / bi, nil
  126 		} else if bf != 0 {
  127 			return af / bf, nil
  128 		} else if bu != 0 {
  129 			return au / bu, nil
  130 		}
  131 		return nil, errors.New("can't divide the value by 0")
  132 	default:
  133 		return nil, errors.New("there is no such an operation")
  134 	}
  135 }