github.com/anakojm/hugo-katex@v0.0.0-20231023141351-42d6f5de9c0b/common/collections/slice.go (about)

     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 collections
    15  
    16  import (
    17  	"reflect"
    18  	"sort"
    19  )
    20  
    21  // Slicer defines a very generic way to create a typed slice. This is used
    22  // in collections.Slice template func to get types such as Pages, PageGroups etc.
    23  // instead of the less useful []interface{}.
    24  type Slicer interface {
    25  	Slice(items any) (any, error)
    26  }
    27  
    28  // Slice returns a slice of all passed arguments.
    29  func Slice(args ...any) any {
    30  	if len(args) == 0 {
    31  		return args
    32  	}
    33  
    34  	first := args[0]
    35  	firstType := reflect.TypeOf(first)
    36  
    37  	if firstType == nil {
    38  		return args
    39  	}
    40  
    41  	if g, ok := first.(Slicer); ok {
    42  		v, err := g.Slice(args)
    43  		if err == nil {
    44  			return v
    45  		}
    46  
    47  		// If Slice fails, the items are not of the same type and
    48  		// []interface{} is the best we can do.
    49  		return args
    50  	}
    51  
    52  	if len(args) > 1 {
    53  		// This can be a mix of types.
    54  		for i := 1; i < len(args); i++ {
    55  			if firstType != reflect.TypeOf(args[i]) {
    56  				// []interface{} is the best we can do
    57  				return args
    58  			}
    59  		}
    60  	}
    61  
    62  	slice := reflect.MakeSlice(reflect.SliceOf(firstType), len(args), len(args))
    63  	for i, arg := range args {
    64  		slice.Index(i).Set(reflect.ValueOf(arg))
    65  	}
    66  	return slice.Interface()
    67  }
    68  
    69  // StringSliceToInterfaceSlice converts ss to []interface{}.
    70  func StringSliceToInterfaceSlice(ss []string) []any {
    71  	result := make([]any, len(ss))
    72  	for i, s := range ss {
    73  		result[i] = s
    74  	}
    75  	return result
    76  
    77  }
    78  
    79  type SortedStringSlice []string
    80  
    81  // Contains returns true if s is in ss.
    82  func (ss SortedStringSlice) Contains(s string) bool {
    83  	i := sort.SearchStrings(ss, s)
    84  	return i < len(ss) && ss[i] == s
    85  }
    86  
    87  // Count returns the number of times s is in ss.
    88  func (ss SortedStringSlice) Count(s string) int {
    89  	var count int
    90  	i := sort.SearchStrings(ss, s)
    91  	for i < len(ss) && ss[i] == s {
    92  		count++
    93  		i++
    94  	}
    95  	return count
    96  }