go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/cv/internal/common/cl.go (about)

     1  // Copyright 2020 The LUCI Authors.
     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  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package common
    16  
    17  import (
    18  	"sort"
    19  )
    20  
    21  // CLID is a unique ID of a CL used internally in CV.
    22  //
    23  // It's just 8 bytes long and is thus much shorter than ExternalID,
    24  // which reduces CPU & RAM & storage costs of CL graphs for multi-CL Runs.
    25  type CLID int64
    26  
    27  // CLIDsAsInt64s returns proto representation of CLIDs.
    28  func CLIDsAsInt64s(ids []CLID) []int64 {
    29  	r := make([]int64, len(ids))
    30  	for i, id := range ids {
    31  		r[i] = int64(id)
    32  	}
    33  	return r
    34  }
    35  
    36  // CLIDs is a convenience type to facilitate handling of a slice of CLID.
    37  type CLIDs []CLID
    38  
    39  // Dedupe removes duplicates in place and sorts the slice.
    40  //
    41  // Note: Does not preserve original order.
    42  func (p *CLIDs) Dedupe() {
    43  	clids := *p
    44  	if len(clids) <= 1 {
    45  		return
    46  	}
    47  	sort.Sort(clids)
    48  	n, prev, skipped := 0, clids[0], false
    49  	for _, id := range clids[1:] {
    50  		if id == prev {
    51  			skipped = true
    52  			continue
    53  		}
    54  		n++
    55  		if skipped {
    56  			clids[n] = id
    57  		}
    58  		prev = id
    59  	}
    60  	*p = clids[:n+1]
    61  }
    62  
    63  // Len is the number of elements in the collection.
    64  func (ids CLIDs) Len() int {
    65  	return len(ids)
    66  }
    67  
    68  // Less reports whether the element with
    69  // index i should sort before the element with index j.
    70  func (ids CLIDs) Less(i int, j int) bool {
    71  	return ids[i] < ids[j]
    72  }
    73  
    74  // Swap swaps the elements with indexes i and j.
    75  func (ids CLIDs) Swap(i int, j int) {
    76  	ids[i], ids[j] = ids[j], ids[i]
    77  }
    78  
    79  // Set returns a new set of CLIDs.
    80  func (ids CLIDs) Set() CLIDsSet {
    81  	if len(ids) == 0 {
    82  		return nil
    83  	}
    84  	ret := make(CLIDsSet, len(ids))
    85  	for _, id := range ids {
    86  		ret.Add(id)
    87  	}
    88  	return ret
    89  }
    90  
    91  // Contains returns true if CLID is inside these CLIDs.
    92  func (ids CLIDs) Contains(id CLID) bool {
    93  	for _, x := range ids {
    94  		if x == id {
    95  			return true
    96  		}
    97  	}
    98  	return false
    99  }
   100  
   101  // MakeCLIDs returns CLIDs from list of clids in int64.
   102  func MakeCLIDs(ids ...int64) CLIDs {
   103  	if ids == nil {
   104  		return nil
   105  	}
   106  	ret := make(CLIDs, len(ids))
   107  	for i, id := range ids {
   108  		ret[i] = CLID(id)
   109  	}
   110  	return ret
   111  }
   112  
   113  // CLIDsSet is convenience type to reduce the boilerplate.
   114  type CLIDsSet map[CLID]struct{}
   115  
   116  // MakeCLIDsSet returns new CLIDsSet from list of clids in int64.
   117  func MakeCLIDsSet(ids ...int64) CLIDsSet {
   118  	if len(ids) == 0 {
   119  		return nil
   120  	}
   121  	ret := make(CLIDsSet, len(ids))
   122  	for _, id := range ids {
   123  		ret.AddI64(id)
   124  	}
   125  	return ret
   126  }
   127  
   128  // Reset resets the set to contain just the given IDs.
   129  func (s CLIDsSet) Reset(ids ...CLID) {
   130  	for id := range s {
   131  		delete(s, CLID(id))
   132  	}
   133  	for _, id := range ids {
   134  		s.Add(id)
   135  	}
   136  }
   137  func (s CLIDsSet) Add(clid CLID) {
   138  	s[clid] = struct{}{}
   139  }
   140  func (s CLIDsSet) Has(clid CLID) bool {
   141  	_, exists := s[clid]
   142  	return exists
   143  }
   144  func (s CLIDsSet) Del(id CLID) {
   145  	delete(s, id)
   146  }
   147  func (s CLIDsSet) DelAll(ids CLIDs) {
   148  	for _, id := range ids {
   149  		s.Del(id)
   150  	}
   151  }
   152  
   153  func (s CLIDsSet) ToCLIDs() CLIDs {
   154  	ret := make(CLIDs, 0, len(s))
   155  	for id := range s {
   156  		ret = append(ret, id)
   157  	}
   158  	return ret
   159  }
   160  
   161  func (s CLIDsSet) AddI64(id int64)      { s.Add(CLID(id)) }
   162  func (s CLIDsSet) HasI64(id int64) bool { return s.Has(CLID(id)) }
   163  func (s CLIDsSet) DelI64(id int64)      { s.Del(CLID(id)) }
   164  func (s CLIDsSet) ResetI64(ids ...int64) {
   165  	for id := range s {
   166  		delete(s, CLID(id))
   167  	}
   168  	for _, id := range ids {
   169  		s.AddI64(id)
   170  	}
   171  }