pax_global_header00006660000000000000000000000064136663251710014524gustar00rootroot0000000000000052 comment=0d0ec82b7271ca0fa8d1c388595fd8f83585db48 golang-github-juju-collections-0.0~git20200605.0d0ec82/000077500000000000000000000000001366632517100221665ustar00rootroot00000000000000golang-github-juju-collections-0.0~git20200605.0d0ec82/LICENSE000066400000000000000000000215011366632517100231720ustar00rootroot00000000000000All files in this repository are licensed as follows. If you contribute to this repository, it is assumed that you license your contribution under the same license unless you state otherwise. All files Copyright (C) 2015 Canonical Ltd. unless otherwise specified in the file. This software is licensed under the LGPLv3, included below. As a special exception to the GNU Lesser General Public License version 3 ("LGPL3"), the copyright holders of this Library give you permission to convey to a third party a Combined Work that links statically or dynamically to this Library without providing any Minimal Corresponding Source or Minimal Application Code as set out in 4d or providing the installation information set out in section 4e, provided that you comply with the other provisions of LGPL3 and provided that you meet, for the Application the terms and conditions of the license(s) which apply to the Application. Except as stated in this special exception, the provisions of LGPL3 will continue to comply in full to this Library. If you modify this Library, you may apply this exception to your version of this Library, but you are not obliged to do so. If you do not wish to do so, delete this exception statement from your version. This exception does not (and cannot) modify any license terms which apply to the Application, with which you must still comply. GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. golang-github-juju-collections-0.0~git20200605.0d0ec82/Makefile000066400000000000000000000011271366632517100236270ustar00rootroot00000000000000PROJECT := github.com/juju/collections .PHONY: check-licence check-go check check: check-licence check-go go test $(PROJECT)/... check-licence: @(fgrep -rl "Licensed under the LGPLv3" .;\ fgrep -rl "MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT" .;\ find . -name "*.go") | sed -e 's,\./,,' | sort | uniq -u | \ xargs -I {} echo FAIL: licence missed: {} check-go: $(eval GOFMT := $(strip $(shell gofmt -l .| sed -e "s/^/ /g"))) @(if [ x$(GOFMT) != x"" ]; then \ echo go fmt is sad: $(GOFMT); \ exit 1; \ fi ) @(go vet -all -composites=false -copylocks=false $(PROJECT)/...) golang-github-juju-collections-0.0~git20200605.0d0ec82/README.md000066400000000000000000000000561366632517100234460ustar00rootroot00000000000000# collections Set and deque implementations. golang-github-juju-collections-0.0~git20200605.0d0ec82/deque/000077500000000000000000000000001366632517100232715ustar00rootroot00000000000000golang-github-juju-collections-0.0~git20200605.0d0ec82/deque/deque.go000066400000000000000000000113621366632517100247260ustar00rootroot00000000000000// Copyright 2015 Canonical Ltd. // Licensed under the LGPLv3, see LICENCE file for details. package deque import "container/list" // Deque implements an efficient double-ended queue. // // Internally it is composed of a doubly-linked list (list.List) of // blocks. Each block is a slice that holds 0 to blockLen items. The // Deque starts with one block. Blocks are added to the front and back // when the edge blocks fill up as items are pushed onto the // deque. Edge blocks are removed when blocks become empty as items // are popped off the Deque. // // Only the front and back blocks may contain less than blockLen items. // The first element in the Deque is d.blocks.Front().Value[d.frontIdx]. // The last element in the Deque is d.blocks.Back().Value[d.backIdx]. // // This approach is more efficient than using a standard doubly-linked // list for a queue because memory allocation is only required every // blockLen items, instead of for each pushed item. Conversely, fewer // memory deallocations are required when popping items. Bookkeeping // overhead per item is also reduced. type Deque struct { maxLen int blocks list.List frontIdx, backIdx int len int } // blockLen can be any value above 1. Raising the blockLen decreases // the average number of memory allocations per item, but increases // the amount of memory "wasted". Raising blockLen also doesn't // necessarily make Deque operations faster. 64 is used by Python's // deque and seems to be a sweet spot on the author's machine too. const blockLen = 64 const blockCenter = (blockLen - 1) / 2 type blockT []interface{} // New returns a new Deque instance. func New() *Deque { return NewWithMaxLen(0) } // New returns a new Deque instance which is limited to a certain // length. Pushes which cause the length to exceed the specified size // will cause an item to be dropped from the opposing side. // // A maxLen of 0 means that there is no maximum length limit in place. func NewWithMaxLen(maxLen int) *Deque { d := Deque{maxLen: maxLen} d.blocks.PushBack(newBlock()) d.recenter() return &d } func newBlock() blockT { return make(blockT, blockLen) } func (d *Deque) recenter() { // The indexes start crossed at the middle of the block so that // the first push on either side has both indexes pointing at the // first item. d.frontIdx = blockCenter + 1 d.backIdx = blockCenter } // Len returns the number of items stored in the queue. func (d *Deque) Len() int { return d.len } // PushBack adds an item to the back of the queue. func (d *Deque) PushBack(item interface{}) { var block blockT if d.backIdx == blockLen-1 { // The current back block is full so add another. block = newBlock() d.blocks.PushBack(block) d.backIdx = -1 } else { block = d.blocks.Back().Value.(blockT) } d.backIdx++ block[d.backIdx] = item d.len++ if d.maxLen > 0 && d.len > d.maxLen { d.PopFront() } } // PushFront adds an item to the front of the queue. func (d *Deque) PushFront(item interface{}) { var block blockT if d.frontIdx == 0 { // The current front block is full so add another. block = newBlock() d.blocks.PushFront(block) d.frontIdx = blockLen } else { block = d.blocks.Front().Value.(blockT) } d.frontIdx-- block[d.frontIdx] = item d.len++ if d.maxLen > 0 && d.len > d.maxLen { d.PopBack() } } // PopBack removes an item from the back of the queue and returns // it. The returned flag is true unless there were no items left in // the queue. func (d *Deque) PopBack() (interface{}, bool) { if d.len < 1 { return nil, false } elem := d.blocks.Back() block := elem.Value.(blockT) item := block[d.backIdx] block[d.backIdx] = nil d.backIdx-- d.len-- if d.backIdx == -1 { // The back block is now empty. if d.len == 0 { d.recenter() // Deque is empty so reset. } else { d.blocks.Remove(elem) d.backIdx = blockLen - 1 } } return item, true } // PopFront removes an item from the front of the queue and returns // it. The returned flag is true unless there were no items left in // the queue. func (d *Deque) PopFront() (interface{}, bool) { if d.len < 1 { return nil, false } elem := d.blocks.Front() block := elem.Value.(blockT) item := block[d.frontIdx] block[d.frontIdx] = nil d.frontIdx++ d.len-- if d.frontIdx == blockLen { // The front block is now empty. if d.len == 0 { d.recenter() // Deque is empty so reset. } else { d.blocks.Remove(elem) d.frontIdx = 0 } } return item, true } // Front looks at the front of the queue but does not remove it. // The returned flag is true unless there were no items in the queue. func (d *Deque) Front() (interface{}, bool) { if d.len < 1 { return nil, false } elem := d.blocks.Front() block := elem.Value.(blockT) item := block[d.frontIdx] return item, true } golang-github-juju-collections-0.0~git20200605.0d0ec82/deque/deque_test.go000066400000000000000000000163161366632517100257710ustar00rootroot00000000000000// Copyright 2015 Canonical Ltd. // Licensed under the LGPLv3, see LICENCE file for details. package deque_test import ( "container/list" "github.com/juju/testing" jc "github.com/juju/testing/checkers" gc "gopkg.in/check.v1" "github.com/juju/collections/deque" ) type suite struct { testing.IsolationSuite deque *deque.Deque } var _ = gc.Suite(&suite{}) const testLen = 1000 func (s *suite) SetUpTest(c *gc.C) { s.deque = deque.New() } func (s *suite) TestInit(c *gc.C) { s.checkEmpty(c) } func (s *suite) TestStackBack(c *gc.C) { // Push many values on to the back. for i := 0; i < testLen; i++ { c.Assert(s.deque.Len(), gc.Equals, i) s.deque.PushBack(i) } // Pop them all off from the back. for i := testLen; i > 0; i-- { c.Assert(s.deque.Len(), gc.Equals, i) v, ok := s.deque.PopBack() c.Assert(ok, jc.IsTrue) c.Assert(v.(int), gc.Equals, i-1) } s.checkEmpty(c) } func (s *suite) TestStackFront(c *gc.C) { // Push many values on to the front. for i := 0; i < testLen; i++ { c.Assert(s.deque.Len(), gc.Equals, i) s.deque.PushFront(i) } // Pop them all off from the front. for i := testLen; i > 0; i-- { c.Assert(s.deque.Len(), gc.Equals, i) v, ok := s.deque.PopFront() c.Assert(ok, jc.IsTrue) c.Assert(v.(int), gc.Equals, i-1) } s.checkEmpty(c) } func (s *suite) TestQueueFromFront(c *gc.C) { // Push many values on to the back. for i := 0; i < testLen; i++ { s.deque.PushBack(i) } // Pop them all off the front. for i := 0; i < testLen; i++ { v, ok := s.deque.PopFront() c.Assert(ok, jc.IsTrue) c.Assert(v.(int), gc.Equals, i) } s.checkEmpty(c) } func (s *suite) TestQueueFromBack(c *gc.C) { // Push many values on to the front. for i := 0; i < testLen; i++ { s.deque.PushFront(i) } // Pop them all off the back. for i := 0; i < testLen; i++ { v, ok := s.deque.PopBack() c.Assert(ok, jc.IsTrue) c.Assert(v.(int), gc.Equals, i) } s.checkEmpty(c) } func (s *suite) TestFrontEmpty(c *gc.C) { v, ok := s.deque.Front() c.Assert(ok, jc.IsFalse) c.Assert(v, gc.IsNil) } func (s *suite) TestFrontValue(c *gc.C) { s.deque.PushFront(42) v, ok := s.deque.Front() c.Assert(ok, jc.IsTrue) c.Assert(v.(int), gc.Equals, 42) // Item is still there. c.Assert(s.deque.Len(), gc.Equals, 1) } func (s *suite) TestFrontBack(c *gc.C) { // Populate from the front and back. for i := 0; i < testLen; i++ { c.Assert(s.deque.Len(), gc.Equals, i*2) s.deque.PushFront(i) s.deque.PushBack(i) } // Remove half the items from the front and back. for i := testLen; i > testLen/2; i-- { c.Assert(s.deque.Len(), gc.Equals, i*2) vb, ok := s.deque.PopBack() c.Assert(ok, jc.IsTrue) c.Assert(vb.(int), gc.Equals, i-1) vf, ok := s.deque.PopFront() c.Assert(ok, jc.IsTrue) c.Assert(vf.(int), gc.Equals, i-1) } // Expand out again. for i := testLen / 2; i < testLen; i++ { c.Assert(s.deque.Len(), gc.Equals, i*2) s.deque.PushFront(i) s.deque.PushBack(i) } // Consume all. for i := testLen; i > 0; i-- { c.Assert(s.deque.Len(), gc.Equals, i*2) vb, ok := s.deque.PopBack() c.Assert(ok, jc.IsTrue) c.Assert(vb.(int), gc.Equals, i-1) vf, ok := s.deque.PopFront() c.Assert(ok, jc.IsTrue) c.Assert(vf.(int), gc.Equals, i-1) } s.checkEmpty(c) } func (s *suite) TestMaxLenFront(c *gc.C) { const max = 5 d := deque.NewWithMaxLen(max) // Exceed the maximum length by 2 for i := 0; i < max+2; i++ { d.PushFront(i) } // Observe the the first 2 items on the back were dropped. v, ok := d.PopBack() c.Assert(ok, jc.IsTrue) c.Assert(v.(int), gc.Equals, 2) } func (s *suite) TestMaxLenBack(c *gc.C) { const max = 5 d := deque.NewWithMaxLen(max) // Exceed the maximum length by 3 for i := 0; i < max+3; i++ { d.PushBack(i) } // Observe the the first 3 items on the front were dropped. v, ok := d.PopFront() c.Assert(ok, jc.IsTrue) c.Assert(v.(int), gc.Equals, 3) } func (s *suite) TestBlockAllocation(c *gc.C) { // This test confirms that the Deque allocates and deallocates // blocks as expected. for i := 0; i < testLen; i++ { s.deque.PushFront(i) s.deque.PushBack(i) } // 2000 items at a blockLen of 64: // 31 full blocks + 1 partial front + 1 partial back = 33 c.Assert(deque.GetDequeBlocks(s.deque), gc.Equals, 33) for i := 0; i < testLen; i++ { s.deque.PopFront() s.deque.PopBack() } // At empty there should be just 1 block. c.Assert(deque.GetDequeBlocks(s.deque), gc.Equals, 1) } func (s *suite) checkEmpty(c *gc.C) { c.Assert(s.deque.Len(), gc.Equals, 0) _, ok := s.deque.PopFront() c.Assert(ok, jc.IsFalse) _, ok = s.deque.PopBack() c.Assert(ok, jc.IsFalse) } func (s *suite) BenchmarkPushBackList(c *gc.C) { l := list.New() for i := 0; i < c.N; i++ { l.PushBack(i) } } func (s *suite) BenchmarkPushBackDeque(c *gc.C) { d := deque.New() for i := 0; i < c.N; i++ { d.PushBack(i) } } func (s *suite) BenchmarkPushFrontList(c *gc.C) { l := list.New() for i := 0; i < c.N; i++ { l.PushFront(i) } } func (s *suite) BenchmarkPushFrontDeque(c *gc.C) { d := deque.New() for i := 0; i < c.N; i++ { d.PushFront(i) } } func (s *suite) BenchmarkPushPopFrontList(c *gc.C) { l := list.New() for i := 0; i < c.N; i++ { l.PushFront(i) } for i := 0; i < c.N; i++ { elem := l.Front() _ = elem.Value l.Remove(elem) } } func (s *suite) BenchmarkPushPopFrontDeque(c *gc.C) { d := deque.New() for i := 0; i < c.N; i++ { d.PushFront(i) } for i := 0; i < c.N; i++ { _, _ = d.PopFront() } } func (s *suite) BenchmarkPushPopBackList(c *gc.C) { l := list.New() for i := 0; i < c.N; i++ { l.PushBack(i) } for i := 0; i < c.N; i++ { elem := l.Back() _ = elem.Value l.Remove(elem) } } func (s *suite) BenchmarkPushPopBackDeque(c *gc.C) { d := deque.New() for i := 0; i < c.N; i++ { d.PushBack(i) } for i := 0; i < c.N; i++ { _, _ = d.PopBack() } } func iterToSlice(iter deque.Iterator) []string { var result []string var value string for iter.Next(&value) { result = append(result, value) } return result } func (s *suite) TestIterEmpty(c *gc.C) { c.Assert(iterToSlice(s.deque.Iterator()), gc.HasLen, 0) } func (s *suite) TestIter(c *gc.C) { s.deque.PushFront("second") s.deque.PushBack("third") s.deque.PushFront("first") c.Assert(iterToSlice(s.deque.Iterator()), jc.DeepEquals, []string{"first", "second", "third"}) } func (s *suite) TestIterOverBlocksBack(c *gc.C) { for i := 0; i < testLen; i++ { s.deque.PushBack(i) } iter := s.deque.Iterator() expect := 0 var obtained int for iter.Next(&obtained) { c.Assert(obtained, gc.Equals, expect) expect++ } c.Assert(expect, gc.Equals, testLen) } func (s *suite) TestIterOverBlocksFront(c *gc.C) { for i := 0; i < testLen; i++ { s.deque.PushFront(i) } iter := s.deque.Iterator() expect := testLen - 1 var obtained int for iter.Next(&obtained) { c.Assert(obtained, gc.Equals, expect) expect-- } c.Assert(expect, gc.Equals, -1) } func (s *suite) TestWrongTypePanics(c *gc.C) { // Use an int in the deque, and try to get strings out using the iterToSlice method. s.deque.PushFront(14) c.Assert(func() { iterToSlice(s.deque.Iterator()) }, gc.PanicMatches, "reflect.Set: value of type int is not assignable to type string") c.Assert(func() { iter := s.deque.Iterator() var i int iter.Next(i) }, gc.PanicMatches, "value is not a pointer") } golang-github-juju-collections-0.0~git20200605.0d0ec82/deque/doc.go000066400000000000000000000013731366632517100243710ustar00rootroot00000000000000// Copyright 2015 Canonical Ltd. // Licensed under the LGPLv3, see LICENCE file for details. // The deque package implements an efficient double-ended queue data // structure called Deque. // // Usage: // // d := deque.New() // d.PushFront("foo") // d.PushBack("bar") // d.PushBack("123") // l := d.Len() // l == 3 // v, ok := d.PopFront() // v.(string) == "foo", ok == true // v, ok = d.PopFront() // v.(string) == "bar", ok == true // v, ok = d.PopBack() // v.(string) == "123", ok == true // v, ok = d.PopBack() // v == nil, ok == false // v, ok = d.PopFront() // v == nil, ok == false // l = d.Len() // l == 0 // // A discussion of the internals can be found at the top of deque.go. // package deque golang-github-juju-collections-0.0~git20200605.0d0ec82/deque/export_test.go000066400000000000000000000003761366632517100262060ustar00rootroot00000000000000// Copyright 2015 Canonical Ltd. // Licensed under the LGPLv3, see LICENCE file for details. package deque // GetDequeBlocks returns the number of internal blocks that the Deque // is using. func GetDequeBlocks(d *Deque) int { return d.blocks.Len() } golang-github-juju-collections-0.0~git20200605.0d0ec82/deque/iterator.go000066400000000000000000000023751366632517100254600ustar00rootroot00000000000000// Copyright 2018 Canonical Ltd. // Licensed under the LGPLv3, see LICENCE file for details. package deque import ( "container/list" "reflect" ) // Iterator allows in order iteration of the deque elements. // The iterator is valid as long as no elements are added or removed from the deque. type Iterator struct { deque *Deque elem *list.Element block blockT index int pos int } // Iterator returns an `Iterator` for in order iteration of the elements. func (d *Deque) Iterator() Iterator { front := d.blocks.Front() return Iterator{ deque: d, elem: front, block: front.Value.(blockT), pos: d.frontIdx - 1, } } // Next returns true if there is a value, and the value is populated with the // next element. Next returns false if it is at the end and the value is // unchanged. The `value` must be a pointer to the type stored in the deque. func (i *Iterator) Next(value interface{}) bool { if i.index >= i.deque.Len() { return false } i.index++ i.pos++ if i.pos == blockLen { i.pos = 0 i.elem = i.elem.Next() i.block = i.elem.Value.(blockT) } v := reflect.ValueOf(value) if v.Kind() != reflect.Ptr { panic("value is not a pointer") } v = v.Elem() // dereference the pointer v.Set(reflect.ValueOf(i.block[i.pos])) return true } golang-github-juju-collections-0.0~git20200605.0d0ec82/deque/package_test.go000066400000000000000000000003251366632517100262520ustar00rootroot00000000000000// Copyright 2015 Canonical Ltd. // Licensed under the LGPLv3, see LICENCE file for details. package deque_test import ( "testing" gc "gopkg.in/check.v1" ) func TestPackage(t *testing.T) { gc.TestingT(t) } golang-github-juju-collections-0.0~git20200605.0d0ec82/go.mod000066400000000000000000000012461366632517100232770ustar00rootroot00000000000000module github.com/juju/collections go 1.14 require ( github.com/juju/errors v0.0.0-20150916125642-1b5e39b83d18 github.com/juju/loggo v0.0.0-20170605014607-8232ab8918d9 github.com/juju/retry v0.0.0-20151029024821-62c620325291 github.com/juju/testing v0.0.0-20180402130637-44801989f0f7 github.com/juju/utils v0.0.0-20180424094159-2000ea4ff043 github.com/juju/version v0.0.0-20161031051906-1f41e27e54f2 golang.org/x/crypto v0.0.0-20180214000028-650f4a345ab4 golang.org/x/net v0.0.0-20180406214816-61147c48b25b gopkg.in/check.v1 v1.0.0-20160105164936-4f90aeace3a2 gopkg.in/mgo.v2 v2.0.0-20160818015218-f2b6f6c918c4 gopkg.in/yaml.v2 v2.0.0-20170712054546-1be3d31502d6 ) golang-github-juju-collections-0.0~git20200605.0d0ec82/go.sum000066400000000000000000000044611366632517100233260ustar00rootroot00000000000000github.com/juju/errors v0.0.0-20150916125642-1b5e39b83d18 h1:Sem5Flzxj8ZdAgY2wfHBUlOYyP4wrpIfM8IZgANNGh8= github.com/juju/errors v0.0.0-20150916125642-1b5e39b83d18/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= github.com/juju/loggo v0.0.0-20170605014607-8232ab8918d9 h1:Y+lzErDTURqeXqlqYi4YBYbDd7ycU74gW1ADt57/bgY= github.com/juju/loggo v0.0.0-20170605014607-8232ab8918d9/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= github.com/juju/retry v0.0.0-20151029024821-62c620325291 h1:Rp0pLxDOsLDDwh2S73oHLI2KTFFyrF6oM/DgP0FhhBk= github.com/juju/retry v0.0.0-20151029024821-62c620325291/go.mod h1:OohPQGsr4pnxwD5YljhQ+TZnuVRYpa5irjugL1Yuif4= github.com/juju/testing v0.0.0-20180402130637-44801989f0f7 h1:IOzyKRl+7X8/fDIqNUDQH73yo8bqDrMEh90y9Il158A= github.com/juju/testing v0.0.0-20180402130637-44801989f0f7/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/juju/utils v0.0.0-20180424094159-2000ea4ff043 h1:kjdsJcIYzmK2k4X2yVCi5Nip6sGoAuc7CLbp+qQnQUM= github.com/juju/utils v0.0.0-20180424094159-2000ea4ff043/go.mod h1:6/KLg8Wz/y2KVGWEpkK9vMNGkOnu4k/cqs8Z1fKjTOk= github.com/juju/version v0.0.0-20161031051906-1f41e27e54f2 h1:loQDi5MyxxNm7Q42mBGuPD6X+F6zw8j5S9yexLgn/BE= github.com/juju/version v0.0.0-20161031051906-1f41e27e54f2/go.mod h1:kE8gK5X0CImdr7qpSKl3xB2PmpySSmfj7zVbkZFs81U= golang.org/x/crypto v0.0.0-20180214000028-650f4a345ab4 h1:OfaUle5HH9Y0obNU74mlOZ/Igdtwi3eGOKcljJsTnbw= golang.org/x/crypto v0.0.0-20180214000028-650f4a345ab4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/net v0.0.0-20180406214816-61147c48b25b h1:7rskAFQwNXGW6AD8E/6y0LDHW5mT9rsLD7ViLVFfh5w= golang.org/x/net v0.0.0-20180406214816-61147c48b25b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= gopkg.in/check.v1 v1.0.0-20160105164936-4f90aeace3a2 h1:+j1SppRob9bAgoYmsdW9NNBdKZfgYuWpqnYHv78Qt8w= gopkg.in/check.v1 v1.0.0-20160105164936-4f90aeace3a2/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/mgo.v2 v2.0.0-20160818015218-f2b6f6c918c4 h1:hILp2hNrRnYjZpmIbx70psAHbBSEcQ1NIzDcUbJ1b6g= gopkg.in/mgo.v2 v2.0.0-20160818015218-f2b6f6c918c4/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/yaml.v2 v2.0.0-20170712054546-1be3d31502d6 h1:CvAnnm1XvMjfib69SZzDwgWfOk+PxYz0hA0HBupilBA= gopkg.in/yaml.v2 v2.0.0-20170712054546-1be3d31502d6/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= golang-github-juju-collections-0.0~git20200605.0d0ec82/set/000077500000000000000000000000001366632517100227615ustar00rootroot00000000000000golang-github-juju-collections-0.0~git20200605.0d0ec82/set/ints.go000066400000000000000000000052741366632517100242750ustar00rootroot00000000000000// Copyright 2014 Canonical Ltd. // Licensed under the LGPLv3, see LICENCE file for details. package set import ( "sort" ) // Ints represents the classic "set" data structure, and contains ints. type Ints map[int]bool // NewInts creates and initializes an Ints and populates it with // initial values as specified in the parameters. func NewInts(initial ...int) Ints { result := make(Ints) for _, value := range initial { result.Add(value) } return result } // Size returns the number of elements in the set. func (is Ints) Size() int { return len(is) } // IsEmpty is true for empty or uninitialized sets. func (is Ints) IsEmpty() bool { return len(is) == 0 } // Add puts a value into the set. func (is Ints) Add(value int) { if is == nil { panic("uninitalised set") } is[value] = true } // Remove takes a value out of the set. If value wasn't in the set to start // with, this method silently succeeds. func (is Ints) Remove(value int) { delete(is, value) } // Contains returns true if the value is in the set, and false otherwise. func (is Ints) Contains(value int) bool { _, exists := is[value] return exists } // Values returns an unordered slice containing all the values in the set. func (is Ints) Values() []int { result := make([]int, len(is)) i := 0 for key := range is { result[i] = key i++ } return result } // SortedValues returns an ordered slice containing all the values in the set. func (is Ints) SortedValues() []int { values := is.Values() sort.Ints(values) return values } // Union returns a new Ints representing a union of the elments in the // method target and the parameter. func (is Ints) Union(other Ints) Ints { result := make(Ints) // Use the internal map rather than going through the friendlier functions // to avoid extra allocation of slices. for value := range is { result[value] = true } for value := range other { result[value] = true } return result } // Intersection returns a new Ints representing a intersection of the elments in the // method target and the parameter. func (is Ints) Intersection(other Ints) Ints { result := make(Ints) // Use the internal map rather than going through the friendlier functions // to avoid extra allocation of slices. for value := range is { if other.Contains(value) { result[value] = true } } return result } // Difference returns a new Ints representing all the values in the // target that are not in the parameter. func (is Ints) Difference(other Ints) Ints { result := make(Ints) // Use the internal map rather than going through the friendlier functions // to avoid extra allocation of slices. for value := range is { if !other.Contains(value) { result[value] = true } } return result } golang-github-juju-collections-0.0~git20200605.0d0ec82/set/ints_test.go000066400000000000000000000055321366632517100253310ustar00rootroot00000000000000// Copyright 2014 Canonical Ltd. // Licensed under the LGPLv3, see LICENCE file for details. package set_test import ( "sort" "github.com/juju/testing" jc "github.com/juju/testing/checkers" gc "gopkg.in/check.v1" "github.com/juju/collections/set" ) type intSetSuite struct { testing.IsolationSuite } var _ = gc.Suite(intSetSuite{}) // Helper methods for the tests. func AssertIntValues(c *gc.C, s set.Ints, expected ...int) { values := s.Values() // Expect an empty slice, not a nil slice for values. if expected == nil { expected = []int{} } sort.Ints(expected) sort.Ints(values) c.Assert(values, gc.DeepEquals, expected) c.Assert(s.Size(), gc.Equals, len(expected)) // Check the sorted values too. sorted := s.SortedValues() c.Assert(sorted, gc.DeepEquals, expected) } // Actual tests start here. func (intSetSuite) TestEmpty(c *gc.C) { s := set.NewInts() AssertIntValues(c, s) } func (intSetSuite) TestInitialValues(c *gc.C) { values := []int{1, 2, 3} s := set.NewInts(values...) AssertIntValues(c, s, values...) } func (intSetSuite) TestSize(c *gc.C) { // Empty sets are empty. s := set.NewInts() c.Assert(s.Size(), gc.Equals, 0) // Size returns number of unique values. s = set.NewInts(1, 1, 2) c.Assert(s.Size(), gc.Equals, 2) } func (intSetSuite) TestIsEmpty(c *gc.C) { // Empty sets are empty. s := set.NewInts() c.Assert(s.IsEmpty(), jc.IsTrue) // Non-empty sets are not empty. s = set.NewInts(1) c.Assert(s.IsEmpty(), jc.IsFalse) // Newly empty sets work too. s.Remove(1) c.Assert(s.IsEmpty(), jc.IsTrue) } func (intSetSuite) TestAdd(c *gc.C) { s := set.NewInts() s.Add(1) s.Add(1) s.Add(2) AssertIntValues(c, s, 1, 2) } func (intSetSuite) TestRemove(c *gc.C) { s := set.NewInts(1, 2) s.Remove(1) AssertIntValues(c, s, 2) } func (intSetSuite) TestContains(c *gc.C) { s := set.NewInts(1, 2) c.Assert(s.Contains(1), jc.IsTrue) c.Assert(s.Contains(2), jc.IsTrue) c.Assert(s.Contains(3), jc.IsFalse) } func (intSetSuite) TestRemoveNonExistent(c *gc.C) { s := set.NewInts() s.Remove(1) AssertIntValues(c, s) } func (intSetSuite) TestUnion(c *gc.C) { s1 := set.NewInts(1, 2) s2 := set.NewInts(1, 3, 4) union1 := s1.Union(s2) union2 := s2.Union(s1) AssertIntValues(c, union1, 1, 2, 3, 4) AssertIntValues(c, union2, 1, 2, 3, 4) } func (intSetSuite) TestIntersection(c *gc.C) { s1 := set.NewInts(1, 2) s2 := set.NewInts(1, 3, 4) int1 := s1.Intersection(s2) int2 := s2.Intersection(s1) AssertIntValues(c, int1, 1) AssertIntValues(c, int2, 1) } func (intSetSuite) TestDifference(c *gc.C) { s1 := set.NewInts(1, 2) s2 := set.NewInts(1, 3, 4) diff1 := s1.Difference(s2) diff2 := s2.Difference(s1) AssertIntValues(c, diff1, 2) AssertIntValues(c, diff2, 3, 4) } func (intSetSuite) TestUninitializedPanics(c *gc.C) { f := func() { var s set.Ints s.Add(1) } c.Assert(f, gc.PanicMatches, "uninitalised set") } golang-github-juju-collections-0.0~git20200605.0d0ec82/set/package_test.go000066400000000000000000000003231366632517100257400ustar00rootroot00000000000000// Copyright 2014 Canonical Ltd. // Licensed under the LGPLv3, see LICENCE file for details. package set_test import ( "testing" gc "gopkg.in/check.v1" ) func TestPackage(t *testing.T) { gc.TestingT(t) } golang-github-juju-collections-0.0~git20200605.0d0ec82/set/strings.go000066400000000000000000000054321366632517100250050ustar00rootroot00000000000000// Copyright 2013 Canonical Ltd. // Licensed under the LGPLv3, see LICENCE file for details. package set import ( "sort" ) // Strings represents the classic "set" data structure, and contains strings. type Strings map[string]bool // NewStrings creates and initializes a Strings and populates it with // initial values as specified in the parameters. func NewStrings(initial ...string) Strings { result := make(Strings) for _, value := range initial { result.Add(value) } return result } // Size returns the number of elements in the set. func (s Strings) Size() int { return len(s) } // IsEmpty is true for empty or uninitialized sets. func (s Strings) IsEmpty() bool { return len(s) == 0 } // Add puts a value into the set. func (s Strings) Add(value string) { if s == nil { panic("uninitalised set") } s[value] = true } // Remove takes a value out of the set. If value wasn't in the set to start // with, this method silently succeeds. func (s Strings) Remove(value string) { delete(s, value) } // Contains returns true if the value is in the set, and false otherwise. func (s Strings) Contains(value string) bool { _, exists := s[value] return exists } // Values returns an unordered slice containing all the values in the set. func (s Strings) Values() []string { result := make([]string, len(s)) i := 0 for key := range s { result[i] = key i++ } return result } // SortedValues returns an ordered slice containing all the values in the set. func (s Strings) SortedValues() []string { values := s.Values() sort.Strings(values) return values } // Union returns a new Strings representing a union of the elments in the // method target and the parameter. func (s Strings) Union(other Strings) Strings { result := make(Strings) // Use the internal map rather than going through the friendlier functions // to avoid extra allocation of slices. for value := range s { result[value] = true } for value := range other { result[value] = true } return result } // Intersection returns a new Strings representing a intersection of the elments in the // method target and the parameter. func (s Strings) Intersection(other Strings) Strings { result := make(Strings) // Use the internal map rather than going through the friendlier functions // to avoid extra allocation of slices. for value := range s { if other.Contains(value) { result[value] = true } } return result } // Difference returns a new Strings representing all the values in the // target that are not in the parameter. func (s Strings) Difference(other Strings) Strings { result := make(Strings) // Use the internal map rather than going through the friendlier functions // to avoid extra allocation of slices. for value := range s { if !other.Contains(value) { result[value] = true } } return result } golang-github-juju-collections-0.0~git20200605.0d0ec82/set/strings_test.go000066400000000000000000000061701366632517100260440ustar00rootroot00000000000000// Copyright 2013 Canonical Ltd. // Licensed under the LGPLv3, see LICENCE file for details. package set_test import ( "sort" "github.com/juju/testing" gc "gopkg.in/check.v1" "github.com/juju/collections/set" ) type stringSetSuite struct { testing.IsolationSuite } var _ = gc.Suite(stringSetSuite{}) // Helper methods for the tests. func AssertValues(c *gc.C, s set.Strings, expected ...string) { values := s.Values() // Expect an empty slice, not a nil slice for values. if expected == nil { expected = []string{} } sort.Strings(expected) sort.Strings(values) c.Assert(values, gc.DeepEquals, expected) c.Assert(s.Size(), gc.Equals, len(expected)) // Check the sorted values too. sorted := s.SortedValues() c.Assert(sorted, gc.DeepEquals, expected) } // Actual tests start here. func (stringSetSuite) TestEmpty(c *gc.C) { s := set.NewStrings() AssertValues(c, s) } func (stringSetSuite) TestInitialValues(c *gc.C) { values := []string{"foo", "bar", "baz"} s := set.NewStrings(values...) AssertValues(c, s, values...) } func (stringSetSuite) TestSize(c *gc.C) { // Empty sets are empty. s := set.NewStrings() c.Assert(s.Size(), gc.Equals, 0) // Size returns number of unique values. s = set.NewStrings("foo", "foo", "bar") c.Assert(s.Size(), gc.Equals, 2) } func (stringSetSuite) TestIsEmpty(c *gc.C) { // Empty sets are empty. s := set.NewStrings() c.Assert(s.IsEmpty(), gc.Equals, true) // Non-empty sets are not empty. s = set.NewStrings("foo") c.Assert(s.IsEmpty(), gc.Equals, false) // Newly empty sets work too. s.Remove("foo") c.Assert(s.IsEmpty(), gc.Equals, true) } func (stringSetSuite) TestAdd(c *gc.C) { s := set.NewStrings() s.Add("foo") s.Add("foo") s.Add("bar") AssertValues(c, s, "foo", "bar") } func (stringSetSuite) TestRemove(c *gc.C) { s := set.NewStrings("foo", "bar") s.Remove("foo") AssertValues(c, s, "bar") } func (stringSetSuite) TestContains(c *gc.C) { s := set.NewStrings("foo", "bar") c.Assert(s.Contains("foo"), gc.Equals, true) c.Assert(s.Contains("bar"), gc.Equals, true) c.Assert(s.Contains("baz"), gc.Equals, false) } func (stringSetSuite) TestRemoveNonExistent(c *gc.C) { s := set.NewStrings() s.Remove("foo") AssertValues(c, s) } func (stringSetSuite) TestUnion(c *gc.C) { s1 := set.NewStrings("foo", "bar") s2 := set.NewStrings("foo", "baz", "bang") union1 := s1.Union(s2) union2 := s2.Union(s1) AssertValues(c, union1, "foo", "bar", "baz", "bang") AssertValues(c, union2, "foo", "bar", "baz", "bang") } func (stringSetSuite) TestIntersection(c *gc.C) { s1 := set.NewStrings("foo", "bar") s2 := set.NewStrings("foo", "baz", "bang") int1 := s1.Intersection(s2) int2 := s2.Intersection(s1) AssertValues(c, int1, "foo") AssertValues(c, int2, "foo") } func (stringSetSuite) TestDifference(c *gc.C) { s1 := set.NewStrings("foo", "bar") s2 := set.NewStrings("foo", "baz", "bang") diff1 := s1.Difference(s2) diff2 := s2.Difference(s1) AssertValues(c, diff1, "bar") AssertValues(c, diff2, "baz", "bang") } func (stringSetSuite) TestUninitializedPanics(c *gc.C) { f := func() { var s set.Strings s.Add("foo") } c.Assert(f, gc.PanicMatches, "uninitalised set") }