Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  uniquelist.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// Copyright 2024 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package uniquelist

import (
 "hash/maphash"
 "iter"
 "reflect"
 "runtime"
 "slices"
 "sync"
 "time"
 "weak"

 "github.com/google/blueprint/proptools"
 "github.com/google/blueprint/syncmap"
)

// UniqueList is a workaround for Go limitation that slices are not comparable and
// thus can't be used with unique.Make.  It interns slices by manually hashing the
// contents of each element and using the result as the key in a sync.Map.
type UniqueList[T comparable] struct {
 p *[]T
}

// uniqueListMapsByType stores a map from the type of list element to the uniqueListMap
// that stores lists of that type.  The value in the map is always a *uniqueListMap[T]
// when the key is the reflect.TypeOf(T).
var uniqueListMapsByType syncmap.SyncMap[reflect.Type, any]

// uniqueListMap stores a map of hash of the contents of a slice to a weak pointer to
// a canonical slice with that contents.
type uniqueListMap[T comparable] = syncmap.SyncMap[uint64, weak.Pointer[[]T]]

// freeUnusedList stores a list of functions to call periodically to remove entries
// in uniqueListMaps whose weak pointer is no longer valid.
var freeUnusedList []func()

// freeUnusedMutex protects freeUnusedList.
var freeUnusedMutex sync.Mutex

// initFreeUnused creates a goroutine to call the functions in the freeUnusedList.
var initFreeUnused = sync.OnceFunc(func() {
 t := time.Tick(5 * time.Second)
 go func() {
  for {
   <-t
   freeUnusedMutex.Lock()
   c := freeUnusedList
   freeUnusedMutex.Unlock()

   for _, f := range c {
    f()
   }
  }
 }()
})

// Len returns the length of the slice that was originally passed to Make.
func (s UniqueList[T]) Len() int {
 if s.p == nil {
  return 0
 }
 return len(*s.p)
}

// ToSlice returns a slice containing a shallow copy of the list.
func (s UniqueList[T]) ToSlice() []T {
 if s.p == nil {
  return []T(nil)
 }
 return slices.Clone(*s.p)
}

// Iter returns a iter.Seq that iterates the elements of the list.
func (s UniqueList[T]) Iter() iter.Seq[T] {
 if s.p == nil {
  return func(yield func(T) bool) {}
 }
 return slices.Values(*s.p)
}

// AppendTo appends the contents of the list to the given slice and returns
// the results.
func (s UniqueList[T]) AppendTo(slice []T) []T {
 if s.p == nil {
  return slice
 }
 slice = append(slice, *s.p...)
 return slice
}

func (s UniqueList[T]) Hash(hasher *proptools.Hasher, typeName string, hashT func(*proptools.Hasher, T) error) error {
 if s.p == nil {
  hasher.WriteByte(0)
  return nil
 }
 hash := func(hasher *proptools.Hasher) error {
  hasher.WriteString("[]" + typeName)
  items := s.ToSlice()
  hasher.WriteInt(len(items))
  for i := 0; i < len(items); i++ {
   if err := hashT(hasher, items[i]); err != nil {
    return err
   }
  }
  return nil
 }
 return proptools.HashReference(hasher, s, hash)
}

// Make returns a UniqueList for the given slice.  Two calls to UniqueList with the same slice contents
// will return identical UniqueList objects.
func Make[T comparable](slice []T) UniqueList[T] {
 if len(slice) == 0 {
  return UniqueList[T]{}
 }

 uniqueListsForT := getUniqueListMapForType[T]()
 key := hashSliceContents(slice)

 for {
  var s []T
  w, _ := uniqueListsForT.LoadOrCompute(key, func() weak.Pointer[[]T] {
   s = slices.Clone(slice)
   return weak.Make(&s)
  })

  p := w.Value()
  runtime.KeepAlive(s)
  if p != nil {
   return UniqueList[T]{p}
  }

  uniqueListsForT.CompareAndDelete(key, w)
 }
}

var seed = maphash.MakeSeed()

// hashSliceContents uses maphash.Hash to hash each element of a slice.
func hashSliceContents[T comparable](list []T) uint64 {
 var h maphash.Hash
 h.SetSeed(seed)
 for _, e := range list {
  maphash.WriteComparable(&h, e)
 }
 return h.Sum64()
}

// getUniqueListMapForType
func getUniqueListMapForType[T comparable]() *uniqueListMap[T] {
 var zero T
 typ := reflect.TypeOf(zero)

 initFreeUnused()
 uniqueListsForT, ok := uniqueListMapsByType.Load(typ)
 if !ok {
  var loaded bool
  uniqueListsForT = &uniqueListMap[T]{}
  uniqueListsForT, loaded = uniqueListMapsByType.LoadOrStore(typ, uniqueListsForT)
  if !loaded {
   u := uniqueListsForT.(*uniqueListMap[T])
   freeUnusedMutex.Lock()
   freeUnusedList = append(freeUnusedList, func() { freeUnused(u) })
   freeUnusedMutex.Unlock()
  }
 }
 return uniqueListsForT.(*uniqueListMap[T])
}

// freeUnused walks the entries in a uniqueListMap and removes any whose
// value is a weak pointer to an object that has been reclaimed.
func freeUnused[T comparable](u *uniqueListMap[T]) {
 u.Range(func(key uint64, value weak.Pointer[[]T]) bool {
  if value.Value() == nil {
   u.Delete(key)
  }
  return true
 })
}

[Dauer der Verarbeitung: 0.18 Sekunden, vorverarbeitet 2026-06-28]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik