github.com/viant/toolbox@v0.34.5/collections_async.go (about)

     1  package toolbox
     2  
     3  import (
     4  	"reflect"
     5  	"sync"
     6  )
     7  
     8  //TrueValueProvider is a function that returns true, it takes one parameters which ignores,
     9  //This provider can be used to make map from slice like map[some type]bool
    10  
    11  //ProcessSliceAsync iterates over any slice, it calls handler with each element asynchronously
    12  func ProcessSliceAsync(slice interface{}, handler func(item interface{}) bool) {
    13  	//The common cases with reflection for speed
    14  	var wg sync.WaitGroup
    15  	if aSlice, ok := slice.([]interface{}); ok {
    16  		wg.Add(len(aSlice))
    17  		for _, item := range aSlice {
    18  			go func(item interface{}) {
    19  				defer wg.Done()
    20  				handler(item)
    21  			}(item)
    22  
    23  		}
    24  		wg.Wait()
    25  		return
    26  	}
    27  	if aSlice, ok := slice.([]map[string]interface{}); ok {
    28  		wg.Add(len(aSlice))
    29  		for _, item := range aSlice {
    30  			go func(item interface{}) {
    31  				defer wg.Done()
    32  				handler(item)
    33  			}(item)
    34  
    35  		}
    36  		wg.Wait()
    37  		return
    38  	}
    39  	//The common cases with reflection for speed
    40  	if aSlice, ok := slice.([]string); ok {
    41  		wg.Add(len(aSlice))
    42  		for _, item := range aSlice {
    43  			go func(item interface{}) {
    44  				defer wg.Done()
    45  				handler(item)
    46  			}(item)
    47  
    48  		}
    49  		wg.Wait()
    50  		return
    51  	}
    52  
    53  	//The common cases with reflection for speed
    54  	if aSlice, ok := slice.([]int); ok {
    55  		wg.Add(len(aSlice))
    56  		for _, item := range aSlice {
    57  			go func(item interface{}) {
    58  				defer wg.Done()
    59  				handler(item)
    60  			}(item)
    61  		}
    62  		wg.Wait()
    63  		return
    64  	}
    65  
    66  	sliceValue := DiscoverValueByKind(reflect.ValueOf(slice), reflect.Slice)
    67  	wg.Add(sliceValue.Len())
    68  	for i := 0; i < sliceValue.Len(); i++ {
    69  		go func(item interface{}) {
    70  			defer wg.Done()
    71  			handler(item)
    72  		}(sliceValue.Index(i).Interface())
    73  
    74  	}
    75  	wg.Wait()
    76  }
    77  
    78  //IndexSlice reads passed in slice and applies function that takes a slice item as argument to return a key value.
    79  //passed in resulting map needs to match key type return by a key function, and accept slice item type as argument.
    80  func IndexSliceAsync(slice, resultingMap, keyFunction interface{}) {
    81  	var lock = sync.RWMutex{}
    82  	mapValue := DiscoverValueByKind(resultingMap, reflect.Map)
    83  	ProcessSliceAsync(slice, func(item interface{}) bool {
    84  		result := CallFunction(keyFunction, item)
    85  		lock.Lock() //otherwise, fatal error: concurrent map writes
    86  		defer lock.Unlock()
    87  		mapValue.SetMapIndex(reflect.ValueOf(result[0]), reflect.ValueOf(item))
    88  		return true
    89  	})
    90  }
    91  
    92  //SliceToMap reads passed in slice to to apply the key and value function for each item. Result of these calls is placed in the resulting map.
    93  func SliceToMapAsync(sourceSlice, targetMap, keyFunction, valueFunction interface{}) {
    94  	//optimized case
    95  	var wg sync.WaitGroup
    96  	var lock = sync.RWMutex{}
    97  	if stringBoolMap, ok := targetMap.(map[string]bool); ok {
    98  		if stringSlice, ok := sourceSlice.([]string); ok {
    99  			if valueFunction, ok := keyFunction.(func(string) bool); ok {
   100  				if keyFunction, ok := keyFunction.(func(string) string); ok {
   101  					wg.Add(len(stringSlice))
   102  					for _, item := range stringSlice {
   103  						go func(item string) {
   104  							defer wg.Done()
   105  							key := keyFunction(item)
   106  							value := valueFunction(item)
   107  							lock.Lock()
   108  							defer lock.Unlock()
   109  							stringBoolMap[key] = value
   110  						}(item)
   111  					}
   112  					wg.Wait()
   113  					return
   114  				}
   115  			}
   116  		}
   117  	}
   118  
   119  	mapValue := DiscoverValueByKind(targetMap, reflect.Map)
   120  	ProcessSliceAsync(sourceSlice, func(item interface{}) bool {
   121  		key := CallFunction(keyFunction, item)
   122  		value := CallFunction(valueFunction, item)
   123  		lock.Lock()
   124  		defer lock.Unlock()
   125  		mapValue.SetMapIndex(reflect.ValueOf(key[0]), reflect.ValueOf(value[0]))
   126  		return true
   127  	})
   128  }
   129  
   130  func ProcessSliceWithIndexAsync(slice interface{}, handler func(index int, item interface{}) bool) {
   131  	var wg sync.WaitGroup
   132  	if aSlice, ok := slice.([]interface{}); ok {
   133  		wg.Add(len(aSlice))
   134  		for i, item := range aSlice {
   135  			go func(i int, item interface{}) {
   136  				defer wg.Done()
   137  				handler(i, item)
   138  			}(i, item)
   139  		}
   140  		wg.Wait()
   141  		return
   142  	}
   143  	if aSlice, ok := slice.([]string); ok {
   144  		wg.Add(len(aSlice))
   145  		for i, item := range aSlice {
   146  			go func(i int, item interface{}) {
   147  				defer wg.Done()
   148  				handler(i, item)
   149  			}(i, item)
   150  		}
   151  		wg.Wait()
   152  		return
   153  	}
   154  	if aSlice, ok := slice.([]int); ok {
   155  		wg.Add(len(aSlice))
   156  		for i, item := range aSlice {
   157  			go func(i int, item interface{}) {
   158  				defer wg.Done()
   159  				handler(i, item)
   160  			}(i, item)
   161  		}
   162  		wg.Wait()
   163  		return
   164  	}
   165  
   166  	sliceValue := DiscoverValueByKind(reflect.ValueOf(slice), reflect.Slice)
   167  	wg.Add(sliceValue.Len())
   168  	for i := 0; i < sliceValue.Len(); i++ {
   169  		go func(i int, item interface{}) {
   170  			defer wg.Done()
   171  			handler(i, item)
   172  		}(i, sliceValue.Index(i).Interface())
   173  	}
   174  	wg.Wait()
   175  }