-
Notifications
You must be signed in to change notification settings - Fork 86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IterableStore #191
IterableStore #191
Changes from 2 commits
5d897c6
0bd039b
4421685
b8cdbb5
d64bf25
ac6d39b
6e101fe
c024f20
54ab8b3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/* | ||
* Copyright 2013 Twitter Inc. | ||
* | ||
* 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 com.twitter.storehaus | ||
|
||
import com.twitter.util.{ Future, Promise, Return } | ||
import com.twitter.concurrent.Spool | ||
import com.twitter.concurrent.Spool.*:: | ||
|
||
object IterableStore { | ||
/** Factory method to create a IterableStore from a Map. */ | ||
def fromMap[K, V](m: Map[K, V]): IterableStore[K, V] = new MapStore(m) | ||
} | ||
|
||
/** | ||
* Trait for stores with iterator over their key-value pairs. | ||
* | ||
* Depending on the backing store, this may have performance implications. So use with caution. | ||
* In general, this should be okay to use with cache stores. | ||
* For other stores, the iterable should ideally be backed by a stream. | ||
*/ | ||
trait IterableStore[K, V] extends ReadableStore[K, V] { | ||
|
||
protected def iteratorToSpool(it: Iterator[(K, V)]): Future[Spool[(K, V)]] = { | ||
val s = new Promise[Spool[(K, V)]] | ||
fillSpool(it, s) | ||
s | ||
} | ||
|
||
protected def fillSpool(it: Iterator[(K, V)], s: Promise[Spool[(K, V)]]): Unit = { | ||
if (it.isEmpty) { | ||
s() = Return(Spool.empty[(K, V)]) | ||
} else { | ||
val next = new Promise[Spool[(K, V)]] | ||
s() = Return(it.next *:: next) | ||
fillSpool(it, next) | ||
} | ||
} | ||
|
||
def iterator: Future[Spool[(K, V)]] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we call this "items" or "spool"? Iterator seems misleading. |
||
|
||
def withFilter(f: ((K, V)) => Boolean): Future[Spool[(K, V)]] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. seems like you can get a default implementation of this by action on the spool. Isn't there a filter method there? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, spool has a filter method. So seems like we don't need this here. |
||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/* | ||
* Copyright 2013 Twitter Inc. | ||
* | ||
* 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 com.twitter.storehaus | ||
|
||
import com.twitter.util.{ Await, Future } | ||
|
||
import org.scalacheck.{ Arbitrary, Properties } | ||
import org.scalacheck.Gen.choose | ||
import org.scalacheck.Prop._ | ||
|
||
object IterableStoreProperties extends Properties("IterableStore") { | ||
|
||
def iteratorLaw[K: Arbitrary, V: Arbitrary](fn: Map[K, V] => IterableStore[K, V]) = | ||
forAll { m: Map[K,V] => | ||
val store = fn(m) | ||
val m2 = new scala.collection.mutable.HashMap[K, V]() | ||
Await.result(store.iterator).foreach { kv => | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. don't you need to Await on the whole spool? A function that Awaits a |
||
m2.put(kv._1, kv._2) | ||
} | ||
m == m2 | ||
} | ||
|
||
def withFilterLaw[K: Arbitrary, V: Arbitrary](fn: Map[K, V] => IterableStore[K, V], | ||
filter: ((K, V)) => Boolean) = | ||
forAll { m: Map[K,V] => | ||
val store = fn(m) | ||
val m2 = new scala.collection.mutable.HashMap[K, V]() | ||
Await.result(store.withFilter(filter)).foreach { kv => | ||
m2.put(kv._1, kv._2) | ||
} | ||
m.iterator.withFilter(filter).toMap == m2 | ||
} | ||
|
||
def iterableStoreLaws[K: Arbitrary, V: Arbitrary](fn: Map[K, V] => IterableStore[K, V], | ||
filter: ((K, V)) => Boolean) = | ||
iteratorLaw(fn) && withFilterLaw(fn, filter) | ||
|
||
property("MapStore obeys the IterableStore laws") = { | ||
val filter : (((Int, String)) => Boolean) = { case ((k, v)) => k % 2 == 0 } | ||
iterableStoreLaws[Int, String](IterableStore.fromMap(_), filter) | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can these two methods move to the companion object?