git ssb

1+

Matt McKegg / mutant



Tree: b9dcc7d4908103b141bd9701cec47b3eebd64d2b

Files: b9dcc7d4908103b141bd9701cec47b3eebd64d2b / set.js

3438 bytesRaw
1var LazyWatcher = require('./lib/lazy-watcher')
2
3module.exports = Set
4
5function Set (defaultValues) {
6 var instance = new ProtoSet(defaultValues)
7 var observable = instance.MutantSet.bind(instance)
8 observable.add = instance.add.bind(instance)
9 observable.clear = instance.clear.bind(instance)
10 observable.delete = instance.delete.bind(instance)
11 observable.has = instance.has.bind(instance)
12 observable.set = instance.set.bind(instance)
13 observable.get = instance.get.bind(instance)
14 observable.getLength = instance.getLength.bind(instance)
15 return observable
16}
17
18// optimise memory usage
19function ProtoSet (defaultValues) {
20 var self = this
21 self.object = []
22 self.sources = []
23 self.releases = []
24 self.binder = LazyWatcher.call(self, self._update, self._listen, self._unlisten)
25 self.binder.value = this.object
26
27 if (defaultValues && defaultValues.length) {
28 defaultValues.forEach(function (valueOrObs) {
29 if (!~self.sources.indexOf(valueOrObs)) {
30 self.sources.push(valueOrObs)
31 }
32 })
33 this.update()
34 }
35}
36
37ProtoSet.prototype.MutantSet = function (listener) {
38 if (!listener) {
39 return this.binder.getValue()
40 }
41 return this.binder.addListener(listener)
42}
43
44ProtoSet.prototype.add = function (valueOrObs) {
45 if (!~this.sources.indexOf(valueOrObs)) {
46 this.sources.push(valueOrObs)
47 if (this.binder.live) {
48 this.releases[this.sources.length - 1] = this._bind(valueOrObs)
49 }
50 this.binder.onUpdate()
51 }
52}
53
54ProtoSet.prototype.clear = function () {
55 this.releases.forEach(tryInvoke)
56 this.sources.length = 0
57 this.releases.length = 0
58 this.binder.onUpdate()
59}
60
61ProtoSet.prototype.delete = function (valueOrObs) {
62 var index = this.sources.indexOf(valueOrObs)
63 if (~index) {
64 this.sources.splice(index, 1)
65 this.releases.splice(index, 1).forEach(tryInvoke)
66 this.binder.onUpdate()
67 }
68}
69
70ProtoSet.prototype.has = function (valueOrObs) {
71 return !!~this.object.indexOf(valueOrObs)
72}
73
74ProtoSet.prototype.set = function (values) {
75 var self = this
76 self.sources.length = 0
77 values.forEach(function (value) {
78 self.sources.push(value)
79 })
80 self.binder.onUpdate()
81}
82
83ProtoSet.prototype.get = function (index) {
84 return this.sources[index]
85}
86
87ProtoSet.prototype.getLength = function () {
88 return this.sources.length
89}
90
91ProtoSet.prototype._bind = function (valueOrObs) {
92 return typeof valueOrObs === 'function' ? valueOrObs(this.binder.onUpdate) : null
93}
94
95ProtoSet.prototype._listen = function () {
96 var self = this
97 self.sources.forEach(function (obs, i) {
98 self.releases[i] = self._bind(obs)
99 })
100}
101
102ProtoSet.prototype._unlisten = function () {
103 this.releases.forEach(tryInvoke)
104 this.releases.length = 0
105}
106
107ProtoSet.prototype._update = function () {
108 var currentValues = this.object.map(get)
109 var newValues = this.sources.map(resolve)
110 currentValues.filter(notIncluded, newValues).forEach(removeFrom, this.object)
111 newValues.filter(notIncluded, currentValues).forEach(addTo, this.object)
112 return true
113}
114
115function get (value) {
116 return value
117}
118
119function resolve (source) {
120 return typeof source === 'function' ? source() : source
121}
122
123function notIncluded (value) {
124 return !~this.indexOf(value)
125}
126
127function removeFrom (item) {
128 var index = this.indexOf(item)
129 if (~index) {
130 this.splice(index, 1)
131 }
132}
133
134function addTo (item) {
135 this.push(item)
136}
137
138function tryInvoke (func) {
139 if (typeof func === 'function') {
140 func()
141 }
142}
143

Built with git-ssb-web