github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/helper/schema/set.go (about)

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