github.com/2matz/terraform@v0.6.1-0.20150714181608-a03cbdb5d5bd/helper/schema/set.go (about)

     1  package schema
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"sort"
     7  	"sync"
     8  
     9  	"github.com/hashicorp/terraform/helper/hashcode"
    10  )
    11  
    12  // HashString hashes strings. If you want a Set of strings, this is the
    13  // SchemaSetFunc you want.
    14  func HashString(v interface{}) int {
    15  	return hashcode.String(v.(string))
    16  }
    17  
    18  // Set is a set data structure that is returned for elements of type
    19  // TypeSet.
    20  type Set struct {
    21  	F SchemaSetFunc
    22  
    23  	m    map[int]interface{}
    24  	once sync.Once
    25  }
    26  
    27  // NewSet is a convenience method for creating a new set with the given
    28  // items.
    29  func NewSet(f SchemaSetFunc, items []interface{}) *Set {
    30  	s := &Set{F: f}
    31  	for _, i := range items {
    32  		s.Add(i)
    33  	}
    34  
    35  	return s
    36  }
    37  
    38  // CopySet returns a copy of another set.
    39  func CopySet(otherSet *Set) *Set {
    40  	return NewSet(otherSet.F, otherSet.List())
    41  }
    42  
    43  // Add adds an item to the set if it isn't already in the set.
    44  func (s *Set) Add(item interface{}) {
    45  	s.add(item)
    46  }
    47  
    48  // Remove removes an item if it's already in the set. Idempotent.
    49  func (s *Set) Remove(item interface{}) {
    50  	s.remove(item)
    51  }
    52  
    53  // Contains checks if the set has the given item.
    54  func (s *Set) Contains(item interface{}) bool {
    55  	_, ok := s.m[s.hash(item)]
    56  	return ok
    57  }
    58  
    59  // Len returns the amount of items in the set.
    60  func (s *Set) Len() int {
    61  	return len(s.m)
    62  }
    63  
    64  // List returns the elements of this set in slice format.
    65  //
    66  // The order of the returned elements is deterministic. Given the same
    67  // set, the order of this will always be the same.
    68  func (s *Set) List() []interface{} {
    69  	result := make([]interface{}, len(s.m))
    70  	for i, k := range s.listCode() {
    71  		result[i] = s.m[k]
    72  	}
    73  
    74  	return result
    75  }
    76  
    77  // Difference performs a set difference of the two sets, returning
    78  // a new third set that has only the elements unique to this set.
    79  func (s *Set) Difference(other *Set) *Set {
    80  	result := &Set{F: s.F}
    81  	result.once.Do(result.init)
    82  
    83  	for k, v := range s.m {
    84  		if _, ok := other.m[k]; !ok {
    85  			result.m[k] = v
    86  		}
    87  	}
    88  
    89  	return result
    90  }
    91  
    92  // Intersection performs the set intersection of the two sets
    93  // and returns a new third set.
    94  func (s *Set) Intersection(other *Set) *Set {
    95  	result := &Set{F: s.F}
    96  	result.once.Do(result.init)
    97  
    98  	for k, v := range s.m {
    99  		if _, ok := other.m[k]; ok {
   100  			result.m[k] = v
   101  		}
   102  	}
   103  
   104  	return result
   105  }
   106  
   107  // Union performs the set union of the two sets and returns a new third
   108  // set.
   109  func (s *Set) Union(other *Set) *Set {
   110  	result := &Set{F: s.F}
   111  	result.once.Do(result.init)
   112  
   113  	for k, v := range s.m {
   114  		result.m[k] = v
   115  	}
   116  	for k, v := range other.m {
   117  		result.m[k] = v
   118  	}
   119  
   120  	return result
   121  }
   122  
   123  func (s *Set) Equal(raw interface{}) bool {
   124  	other, ok := raw.(*Set)
   125  	if !ok {
   126  		return false
   127  	}
   128  
   129  	return reflect.DeepEqual(s.m, other.m)
   130  }
   131  
   132  func (s *Set) GoString() string {
   133  	return fmt.Sprintf("*Set(%#v)", s.m)
   134  }
   135  
   136  func (s *Set) init() {
   137  	s.m = make(map[int]interface{})
   138  }
   139  
   140  func (s *Set) add(item interface{}) int {
   141  	s.once.Do(s.init)
   142  
   143  	code := s.hash(item)
   144  	if _, ok := s.m[code]; !ok {
   145  		s.m[code] = item
   146  	}
   147  
   148  	return code
   149  }
   150  
   151  func (s *Set) hash(item interface{}) int {
   152  	code := s.F(item)
   153  	// Always return a nonnegative hashcode.
   154  	if code < 0 {
   155  		return -code
   156  	}
   157  	return code
   158  }
   159  
   160  func (s *Set) remove(item interface{}) int {
   161  	s.once.Do(s.init)
   162  
   163  	code := s.F(item)
   164  	delete(s.m, code)
   165  
   166  	return code
   167  }
   168  
   169  func (s *Set) index(item interface{}) int {
   170  	return sort.SearchInts(s.listCode(), s.hash(item))
   171  }
   172  
   173  func (s *Set) listCode() []int {
   174  	// Sort the hash codes so the order of the list is deterministic
   175  	keys := make([]int, 0, len(s.m))
   176  	for k, _ := range s.m {
   177  		keys = append(keys, k)
   178  	}
   179  	sort.Sort(sort.IntSlice(keys))
   180  	return keys
   181  }