├── project ├── build.properties └── plugins.sbt ├── .coveralls.yml ├── .gitignore ├── .travis.yml └── src ├── main └── scala │ └── org │ └── feijoas │ └── mango │ └── common │ ├── base │ ├── package.scala │ ├── Optional.scala │ ├── Ticker.scala │ ├── Equivalence.scala │ └── Functions.scala │ ├── collect │ ├── package.scala │ ├── immutable │ │ ├── RangeSetLike.scala │ │ ├── RangeMapLike.scala │ │ ├── RangeMap.scala │ │ ├── RangeSet.scala │ │ ├── ImmutableRangeMapWrapper.scala │ │ └── ImmutableRangeSetWrapper.scala │ ├── RangeMap.scala │ ├── mutable │ │ ├── RangeSet.scala │ │ ├── RangeMap.scala │ │ ├── RangeSetWrapperLike.scala │ │ ├── RangeMapWrapperLike.scala │ │ ├── TreeRangeSetWrapper.scala │ │ ├── TreeRangeMapWrapper.scala │ │ ├── RangeMapLike.scala │ │ └── RangeSetLike.scala │ ├── AsOrdered.scala │ ├── RangeSet.scala │ ├── RangeMapFactory.scala │ ├── RangeSetFactory.scala │ ├── RangeMapWrapperLike.scala │ ├── Bound.scala │ ├── RangeSetWrapperLike.scala │ ├── BoundType.scala │ ├── RangeMapLike.scala │ ├── BinaryTreeTraverser.scala │ └── RangeSetLike.scala │ ├── convert │ ├── package.scala │ └── Decorators.scala │ ├── cache │ ├── package.scala │ ├── Weigher.scala │ ├── CacheLoaderWrapper.scala │ ├── LoadingCacheWrapper.scala │ ├── RemovalListener.scala │ ├── RemovalNotification.scala │ ├── CacheWrapper.scala │ └── RemovalCause.scala │ └── annotations │ └── Beta.scala └── test └── scala └── org └── feijoas └── mango ├── common ├── cache │ ├── WeigherTest.scala │ ├── RemovalCauseTest.scala │ ├── RemovalNotificationTest.scala │ ├── LoadingCacheTest.scala │ ├── CacheStatsMatcher.scala │ ├── CacheTest.scala │ ├── RemovalListenerTest.scala │ ├── CacheStatsTest.scala │ ├── CacheWrapperTest.scala │ └── CacheWrapperBehaviour.scala ├── collect │ ├── immutable │ │ ├── RangeSetFactoryTest.scala │ │ ├── ImmutableRangeMapWrapperTest.scala │ │ └── ImmutableRangeSetWrapperTest.scala │ ├── mutable │ │ ├── TreeRangeSetWrapperTest.scala │ │ └── TreeRangeMapWrapperTest.scala │ ├── BoundTypeTest.scala │ ├── DiscreteDomainTest.scala │ ├── RangeSetFactoryTest.scala │ ├── RangeSetTraitTest.scala │ ├── TreeTraverserTest.scala │ ├── RangeMapWrapperBehaviours.scala │ └── RangeSetWrapperBehaviours.scala ├── base │ ├── EquivalenceTest.scala │ ├── OptionalTest.scala │ └── FunctionsTest.scala └── hash │ ├── FunnelTest.scala │ └── BloomFilterTest.scala └── test └── collect └── Ranges.scala /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.13 -------------------------------------------------------------------------------- /.coveralls.yml: -------------------------------------------------------------------------------- 1 | repo_token: JTc6MH4c3gfqHaZchF7HjXNMeCmIDAwEo -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | project/boot/ 3 | *.jar 4 | .classpath 5 | .project 6 | .cache 7 | .worksheet 8 | .settings 9 | .history 10 | .metadata 11 | .cache-main 12 | .cache-tests 13 | /bin/ 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: scala 2 | scala: 3 | - "2.12.1" 4 | jdk: 5 | - oraclejdk8 6 | 7 | script: 8 | - sbt clean coverage test coverageReport && 9 | sbt coverageAggregate 10 | after_success: 11 | - sbt coveralls -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/" 2 | resolvers += "sonatype-releases" at "https://oss.sonatype.org/content/repositories/releases/" 3 | resolvers += "Sonatype OSS Releases" at "https://oss.sonatype.org/service/local/staging/deploy/maven2" 4 | 5 | addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "5.0.1") 6 | addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") 7 | addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "0.8.0") 8 | addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.5.0") 9 | addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.1.0") 10 | -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/base/package.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common 24 | 25 | /** Basic utility libraries and interfaces. 26 | * 27 | * @author Markus Schneider 28 | * @since 0.7 29 | */ 30 | package object base -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/package.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common 24 | 25 | /** This package contains generic collection traits and implementations 26 | * for working with Guava collections. 27 | * 28 | * @author Markus Schneider 29 | * @since 0.8 30 | */ 31 | package object collect { 32 | 33 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/convert/package.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common 24 | 25 | /** This package contains utility methods to convert between Mango and Guava classes 26 | * 27 | * @author Markus Schneider 28 | * @since 0.7 29 | */ 30 | package object convert { 31 | type AsJava[A] = Decorators.AsJava[A] 32 | type AsScala[A] = Decorators.AsScala[A] 33 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/immutable/RangeSetLike.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect.immutable 24 | 25 | import org.feijoas.mango.common.annotations.Beta 26 | import org.feijoas.mango.common.collect 27 | 28 | /** Implementation trait for immutable [[RangeSet]] 29 | * 30 | * $rangeSetNote 31 | * @author Markus Schneider 32 | * @since 0.8 33 | */ 34 | @Beta 35 | trait RangeSetLike[C, O <: Ordering[C], +Repr <: RangeSetLike[C, O, Repr] with RangeSet[C, O]] 36 | extends collect.RangeSetLike[C, O, Repr] { 37 | } 38 | 39 | -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/immutable/RangeMapLike.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect.immutable 24 | 25 | import org.feijoas.mango.common.annotations.Beta 26 | import org.feijoas.mango.common.collect 27 | 28 | /** Implementation trait for immutable [[RangeMap]] 29 | * 30 | * $rangeMapNote 31 | * @author Markus Schneider 32 | * @since 0.9 33 | */ 34 | @Beta 35 | trait RangeMapLike[K, V, O <: Ordering[K], +Repr <: RangeMapLike[K, V, O, Repr] with RangeMap[K, V, O]] 36 | extends collect.RangeMapLike[K, V, O, Repr] { 37 | } 38 | -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/cache/package.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common 24 | 25 | /** This package contains caching utilities. 26 | * 27 | *

The core interface used to represent caches is [[Cache]]. 28 | * In-memory caches can be configured and created using 29 | * [[CacheBuilder]], with cache entries being loaded by 30 | * [[CacheLoader]]. Statistics about cache performance are exposed using 31 | * [[CacheStats]]. 32 | * 33 | *

See [[http://code.google.com/p/guava-libraries/wiki/CachesExplained the Guava User Guide article on caches]]. 34 | * 35 | * 36 | * @author Markus Schneider 37 | * @since 0.7 (copied from Guava-libraries) 38 | */ 39 | 40 | package object cache -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/RangeMap.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect 24 | 25 | import scala.collection.mutable.Builder 26 | 27 | import org.feijoas.mango.common.annotations.Beta 28 | 29 | /** A base trait for all `RangeMap`, mutable as well as immutable 30 | * 31 | * $rangeMapNote 32 | * @author Markus Schneider 33 | * @since 0.9 34 | */ 35 | @Beta 36 | trait RangeMap[K, V, O <: Ordering[K]] extends RangeMapLike[K, V, O, RangeMap[K, V, O]] { 37 | 38 | } 39 | 40 | /** Factory for immutable [[RangeMap]] 41 | */ 42 | final object RangeMap extends RangeMapFactory[RangeMap] { 43 | override def newBuilder[K, V, O <: Ordering[K]](implicit ord: O) = immutable.RangeMap.newBuilder 44 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/convert/Decorators.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.convert 24 | 25 | /** Utility classes for the conversion between Mango and guava classes 26 | * 27 | * @author Markus Schneider 28 | * @since 0.7 29 | */ 30 | private[convert] trait Decorators { 31 | 32 | /** Generic class containing the `asJava` converter method */ 33 | class AsJava[A](op: => A) { 34 | /** Converts a Scala collection to the corresponding Java collection */ 35 | def asJava: A = op 36 | } 37 | 38 | /** Generic class containing the `asScala` converter method */ 39 | class AsScala[A](op: => A) { 40 | /** Converts a Java collection to the corresponding Scala collection */ 41 | def asScala: A = op 42 | } 43 | } 44 | 45 | private[convert] object Decorators extends Decorators -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/annotations/Beta.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.annotations 24 | 25 | import scala.annotation.meta.{beanGetter, beanSetter, field, getter, setter} 26 | 27 | /** Signifies that a public API (public class, method or field) is subject to 28 | * incompatible changes, or even removal, in a future release. An API bearing 29 | * this annotation is exempt from any compatibility guarantees made by its 30 | * containing library. Note that the presence of this annotation implies nothing 31 | * about the quality or performance of the API in question, only the fact that 32 | * it is not "API-frozen." 33 | * 34 | * @author Markus Schneider 35 | * @since 0.7 (copied from guava-libraries) 36 | */ 37 | @field @getter @setter @beanGetter @beanSetter 38 | class Beta extends scala.annotation.StaticAnnotation -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/cache/WeigherTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.cache 24 | 25 | import org.scalatest.FlatSpec 26 | import org.scalatest.matchers._ 27 | import org.feijoas.mango.common.cache.Weigher._ 28 | import com.google.common.cache.{ Weigher => GuavaWeigher } 29 | import org.scalatest.Matchers._ 30 | 31 | /** 32 | * Tests for [[Weigher]] 33 | * 34 | * @author Markus Schneider 35 | * @since 0.7 (copied from guava-libraries) 36 | */ 37 | class WeigherTest extends FlatSpec { 38 | 39 | behavior of "Weigher" 40 | 41 | it should "convert a function to a Guava Weigher" in { 42 | val cw = (fst: String, snd: String) => { fst.length + snd.length } 43 | 44 | // implicit conversion 45 | val gw: GuavaWeigher[String, String] = cw.asJava 46 | 47 | gw.weigh("a", "bb") should be(3) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/mutable/RangeSet.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect.mutable 24 | 25 | import scala.collection.mutable.Builder 26 | 27 | import org.feijoas.mango.common.annotations.Beta 28 | import org.feijoas.mango.common.collect 29 | import org.feijoas.mango.common.collect.Range 30 | import org.feijoas.mango.common.collect.RangeSetFactory 31 | 32 | /** $rangeSetNote 33 | * @author Markus Schneider 34 | * @since 0.8 35 | */ 36 | @Beta 37 | trait RangeSet[C, O <: Ordering[C]] extends collect.RangeSet[C, O] with RangeSetLike[C, O, RangeSet[C, O]] { 38 | 39 | } 40 | 41 | /** Factory for mutable [[RangeSet]] 42 | */ 43 | final object RangeSet extends RangeSetFactory[RangeSet] { 44 | 45 | override def newBuilder[C, O <: Ordering[C]](implicit ord: O): Builder[Range[C, O], RangeSet[C, O]] = TreeRangeSetWrapper.newBuilder 46 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/mutable/RangeMap.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect.mutable 24 | 25 | import scala.collection.mutable.Builder 26 | 27 | import org.feijoas.mango.common.annotations.Beta 28 | import org.feijoas.mango.common.collect 29 | import org.feijoas.mango.common.collect.Range 30 | import org.feijoas.mango.common.collect.RangeMapFactory 31 | 32 | /** $rangeMapNote 33 | * @author Markus Schneider 34 | * @since 0.9 35 | */ 36 | @Beta 37 | trait RangeMap[K, V, O <: Ordering[K]] extends collect.RangeMap[K, V, O] with RangeMapLike[K, V, O, RangeMap[K, V, O]] { 38 | 39 | } 40 | 41 | /** Factory for immutable [[RangeMap]] 42 | */ 43 | final object RangeMap extends RangeMapFactory[RangeMap] { 44 | override def newBuilder[K, V, O <: Ordering[K]](implicit ord: O): Builder[(Range[K, O], V), RangeMap[K, V, O]] = TreeRangeMapWrapper.newBuilder 45 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/immutable/RangeMap.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect.immutable 24 | 25 | import scala.collection.mutable.Builder 26 | 27 | import org.feijoas.mango.common.annotations.Beta 28 | import org.feijoas.mango.common.collect 29 | import org.feijoas.mango.common.collect.Range 30 | import org.feijoas.mango.common.collect.RangeMapFactory 31 | 32 | /** $rangeMapNote 33 | * @author Markus Schneider 34 | * @since 0.9 35 | */ 36 | @Beta 37 | trait RangeMap[K, V, O <: Ordering[K]] extends collect.RangeMap[K, V, O] with RangeMapLike[K, V, O, RangeMap[K, V, O]] { 38 | 39 | } 40 | 41 | /** Factory for immutable [[RangeMap]] 42 | */ 43 | final object RangeMap extends RangeMapFactory[RangeMap] { 44 | override def newBuilder[K, V, O <: Ordering[K]](implicit ord: O): Builder[(Range[K, O], V), RangeMap[K, V, O]] = ImmutableRangeMapWrapper.newBuilder 45 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/AsOrdered.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect 24 | 25 | import org.feijoas.mango.common.base.Preconditions._ 26 | 27 | /** Guavas `Range` requires the parameter `T` to implement `Ordered[_]` (`Comparable[_]` in Java). 28 | * This class converts a value `T` to a class `AsOrdered[T]` which implements `Ordered[AsOrdered[T]]`. 29 | * Internally we end up with a Guava `Range[AsOrdered[T]]`. 30 | */ 31 | private[mango] case class AsOrdered[T](val value: T)(implicit ord: Ordering[T]) extends Ordered[AsOrdered[T]] { 32 | override def compare(that: AsOrdered[T]) = ord.compare(value, that.value) 33 | override def toString = value.toString 34 | } 35 | 36 | /** Factory for AsOrdered 37 | */ 38 | private[mango] final object AsOrdered { 39 | 40 | /** Implicit conversion from `Ordering[T]` to `AsOrdered[T]` 41 | */ 42 | implicit def asOrdered[T](value: T)(implicit ord: Ordering[T]): AsOrdered[T] = AsOrdered(checkNotNull(value)) 43 | } -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/collect/immutable/RangeSetFactoryTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect.immutable 24 | 25 | import scala.annotation.meta.beanGetter 26 | import scala.annotation.meta.beanSetter 27 | import scala.annotation.meta.field 28 | import scala.annotation.meta.getter 29 | import scala.annotation.meta.setter 30 | import scala.math.Ordering.Int 31 | 32 | import org.feijoas.mango.common.annotations.Beta 33 | import org.feijoas.mango.common.collect.Range 34 | import org.feijoas.mango.common.collect.RangeSetBehaviors 35 | import org.scalatest.FreeSpec 36 | import org.scalatest.Matchers.be 37 | import org.scalatest.Matchers.convertToAnyShouldWrapper 38 | 39 | /** Tests for [[RangeSetFactoryTest]] 40 | * 41 | * @author Markus Schneider 42 | * @since 0.8 43 | */ 44 | class RangeSetFactoryTest extends FreeSpec with RangeSetBehaviors { 45 | 46 | "A (immutable) RangeSetFactory" - { 47 | "it should not create a copy if RangeSet(same type of immutable range set) is called" in { 48 | val fst = RangeSet(Range.open(3, 4)) 49 | val snd = RangeSet(fst) 50 | fst should be theSameInstanceAs (snd) 51 | } 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/collect/mutable/TreeRangeSetWrapperTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect.mutable 24 | 25 | import scala.math.Ordering.Int 26 | 27 | import org.feijoas.mango.common.annotations.Beta 28 | import org.feijoas.mango.common.collect.AsOrdered 29 | import org.feijoas.mango.common.collect.RangeSetBehaviors 30 | import org.feijoas.mango.common.collect.RangeSetWrapperBehaviours 31 | import org.scalatest.FreeSpec 32 | 33 | import com.google.common.collect.{RangeSet => GuavaRangeSet} 34 | 35 | /** Tests for [[ImmutableRangeSetWrapperTest]] 36 | * 37 | * @author Markus Schneider 38 | * @since 0.8 39 | */ 40 | class TreeRangeSetWrapperTest extends FreeSpec with RangeSetBehaviors with RangeSetWrapperBehaviours { 41 | 42 | "A TreeRangeSetWrapper" - { 43 | behave like rangeSet(TreeRangeSetWrapper.newBuilder[Int, Int.type]) 44 | behave like mutableRangeSet(TreeRangeSetWrapper.newBuilder[Int, Int.type]) 45 | behave like rangeSetWithBuilder(TreeRangeSetWrapper.newBuilder[Int, Int.type]) 46 | behave like mutableWrapper((guava: GuavaRangeSet[AsOrdered[Int]]) => TreeRangeSetWrapper[Int, Int.type](guava)) 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/cache/Weigher.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.cache 24 | 25 | import com.google.common.cache.{ Weigher => GuavaWeigher } 26 | import org.feijoas.mango.common.convert.AsJava 27 | 28 | /** Calculates the weights of cache entries. 29 | * 30 | * @author Markus Schneider 31 | * @since 0.7 32 | */ 33 | final object Weigher { 34 | 35 | /** Adds an `asJava` method that wraps a function `(K, V) => Int` in a 36 | * Guava `Weigher[K, V]`. 37 | * 38 | * The returned Guava `Weigher[K, V]` forwards all method calls to the provided 39 | * function `(K, V) => Int`. 40 | * 41 | * @param weigher the function `(K, V) => Int` to wrap in a Guava `GuavaWeigher[K, V]` 42 | * @return An object with an `asJava` method that returns a Guava `GuavaWeigher[K, V]` 43 | * view of the argument 44 | */ 45 | implicit def asGuavaWeigherConverter[K, V](weigher: (K, V) => Int): AsJava[GuavaWeigher[K, V]] = { 46 | new AsJava(asGuavaWeigher(weigher)) 47 | } 48 | 49 | private def asGuavaWeigher[K, V](weigher: (K, V) => Int): GuavaWeigher[K, V] = new GuavaWeigher[K, V] { 50 | override final def weigh(key: K, value: V): Int = weigher(key, value) 51 | } 52 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/RangeSet.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect 24 | 25 | import org.feijoas.mango.common.annotations.Beta 26 | import scala.collection.mutable.Builder 27 | import com.google.common.collect.ImmutableRangeSet 28 | import org.feijoas.mango.common.collect.immutable.ImmutableRangeSetWrapper 29 | 30 | /** A base trait for all `RangeSet`, mutable as well as immutable 31 | * 32 | * $rangeSetNote 33 | * @author Markus Schneider 34 | * @since 0.8 35 | */ 36 | @Beta 37 | trait RangeSet[C, O <: Ordering[C]] extends RangeSetLike[C, O, RangeSet[C, O]] { 38 | 39 | } 40 | 41 | /** Factory for immutable [[RangeSet]] 42 | */ 43 | final object RangeSet extends RangeSetFactory[RangeSet] { 44 | 45 | override def all[C, O <: Ordering[C]](implicit ord: O) = immutable.RangeSet.all[C, O] 46 | override def empty[C, O <: Ordering[C]](implicit ord: O) = immutable.RangeSet.empty[C, O] 47 | override def apply[C, O <: Ordering[C]](ranges: Range[C, O]*)(implicit ord: O) = immutable.RangeSet.apply(ranges: _*) 48 | override def apply[C, O <: Ordering[C]](rangeSet: RangeSet[C, O])(implicit ord: O) = immutable.RangeSet.apply(rangeSet) 49 | override def newBuilder[C, O <: Ordering[C]](implicit ord: O): Builder[Range[C, O], RangeSet[C, O]] = immutable.RangeSet.newBuilder 50 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/immutable/RangeSet.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect.immutable 24 | 25 | import scala.collection.mutable.Builder 26 | import org.feijoas.mango.common.annotations.Beta 27 | import org.feijoas.mango.common.collect 28 | import org.feijoas.mango.common.collect.Range 29 | import org.feijoas.mango.common.collect.RangeSetFactory 30 | 31 | /** $rangeSetNote 32 | * @author Markus Schneider 33 | * @since 0.8 34 | */ 35 | @Beta 36 | trait RangeSet[C, O <: Ordering[C]] extends collect.RangeSet[C, O] with RangeSetLike[C, O, RangeSet[C, O]] { 37 | 38 | } 39 | 40 | /** Factory for immutable [[RangeSet]] 41 | */ 42 | final object RangeSet extends RangeSetFactory[RangeSet] { 43 | 44 | override def all[C, O <: Ordering[C]](implicit ord: O) = ImmutableRangeSetWrapper.all[C, O] 45 | override def empty[C, O <: Ordering[C]](implicit ord: O) = ImmutableRangeSetWrapper.empty[C, O] 46 | override def apply[C, O <: Ordering[C]](ranges: Range[C, O]*)(implicit ord: O) = ImmutableRangeSetWrapper.apply(ranges: _*) 47 | override def apply[C, O <: Ordering[C]](rangeSet: collect.RangeSet[C, O])(implicit ord: O) = ImmutableRangeSetWrapper.apply(rangeSet) 48 | override def newBuilder[C, O <: Ordering[C]](implicit ord: O): Builder[Range[C, O], RangeSet[C, O]] = ImmutableRangeSetWrapper.newBuilder 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/base/EquivalenceTest.scala: -------------------------------------------------------------------------------- 1 | package org.feijoas.mango.common.base 2 | 3 | import org.feijoas.mango.common.base.Equivalence.asGuavaEquiv 4 | import org.feijoas.mango.common.base.Equivalence.asMangoEquiv 5 | import org.scalatest.FreeSpec 6 | import org.scalatest.Matchers.be 7 | import org.scalatest.Matchers.convertToAnyShouldWrapper 8 | import org.scalatest.prop.PropertyChecks 9 | 10 | import com.google.common.{base => gcm} 11 | 12 | /** Tests for [[Equiv]] 13 | * 14 | * @author Markus Schneider 15 | * @since 0.10 16 | */ 17 | class EquivalenceTest extends FreeSpec with PropertyChecks { 18 | 19 | "AsMangoEquiv" - { 20 | "should forward equiv to Guava" in { 21 | val mango: Equiv[Int] = SignumEquiv 22 | val guava: gcm.Equivalence[Int] = mango.asJava 23 | forAll{ (x: Int, y: Int) => 24 | guava.equivalent(x, y) should be (mango.equiv(x, y)) 25 | guava.equivalent(x, x) should be (mango.equiv(x, x)) 26 | } 27 | } 28 | "it should not wrap an Equiv twice" in { 29 | val mango: Equiv[Int] = SignumEquiv 30 | val guava: gcm.Equivalence[Int] = mango.asJava 31 | val wrappedAgain: Equiv[Int] = guava.asScala 32 | 33 | mango should be (wrappedAgain) 34 | } 35 | } 36 | 37 | "AsGuavaEquiv" - { 38 | "should forward equiv to Mango" in { 39 | val guava: gcm.Equivalence[Int] = SignumEquivalence 40 | val mango: Equiv[Int] = guava.asScala 41 | forAll{ (x: Int, y: Int) => 42 | mango.equiv(x, y) should be (guava.equivalent(x, y)) 43 | mango.equiv(x, x) should be (guava.equivalent(x, x)) 44 | } 45 | } 46 | "it should not wrap an Equiv twice" in { 47 | val guava: gcm.Equivalence[Int] = SignumEquivalence 48 | val mango: Equiv[Int] = guava.asScala 49 | val wrappedAgain: gcm.Equivalence[Int] = mango.asJava 50 | 51 | guava should be (wrappedAgain) 52 | } 53 | } 54 | } 55 | 56 | private[mango] object SignumEquiv extends Equiv[Int] { 57 | def equiv(x: Int, y: Int) = x.signum == y.signum 58 | } 59 | 60 | private[mango] object SignumEquivalence extends gcm.Equivalence[Int] { 61 | def doEquivalent(x: Int, y: Int) = x.signum == y.signum 62 | def doHash(x: Int) = 2 * x 63 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/mutable/RangeSetWrapperLike.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect.mutable 24 | 25 | import org.feijoas.mango.common.annotations.Beta 26 | import org.feijoas.mango.common.collect 27 | import org.feijoas.mango.common.collect.Range 28 | import org.feijoas.mango.common.collect.Range.asGuavaRangeConverter 29 | 30 | /** Implementation trait for mutable [[RangeSet]] that delegates to Guava 31 | * 32 | * @author Markus Schneider 33 | * @since 0.8 34 | */ 35 | @Beta 36 | private[mango] trait RangeSetWrapperLike[C, O <: Ordering[C], +Repr <: RangeSetWrapperLike[C, O, Repr] with RangeSet[C, O]] 37 | extends collect.RangeSetWrapperLike[C, O, Repr] with RangeSet[C, O] { 38 | self => 39 | 40 | override def add(range: Range[C, O]) = delegate.add(range.asJava) 41 | override def remove(range: Range[C, O]) = delegate.remove(range.asJava) 42 | override def clear() = delegate.clear() 43 | 44 | override def addAll(other: RangeSet[C, O]) = other match { 45 | case that: RangeSetWrapperLike[C, O, _] => delegate.addAll(that.delegate) 46 | case _ => super.addAll(other) 47 | } 48 | 49 | override def removeAll(other: RangeSet[C, O]) = other match { 50 | case that: RangeSetWrapperLike[C, O, _] => delegate.removeAll(that.delegate) 51 | case _ => super.removeAll(other) 52 | } 53 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/mutable/RangeMapWrapperLike.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect.mutable 24 | 25 | import scala.collection.convert.decorateAll.mapAsScalaMapConverter 26 | import org.feijoas.mango.common.annotations.Beta 27 | import org.feijoas.mango.common.collect.AsOrdered.asOrdered 28 | import org.feijoas.mango.common.collect.Range.asGuavaRangeConverter 29 | import com.google.common.{ collect => gcc } 30 | import org.feijoas.mango.common.collect.AsOrdered 31 | import org.feijoas.mango.common.collect 32 | import org.feijoas.mango.common.collect.Range 33 | 34 | /** Implementation trait for mutable [[RangeMap]] that delegates to Guava 35 | * 36 | * @author Markus Schneider 37 | * @since 0.9 38 | */ 39 | @Beta 40 | private[mango] trait RangeMapWrapperLike[K, V, O <: Ordering[K], +Repr <: RangeMapWrapperLike[K, V, O, Repr] with RangeMap[K, V, O]] 41 | extends collect.RangeMapWrapperLike[K, V, O, Repr] with RangeMap[K, V, O] { 42 | self => 43 | 44 | override def clear() = delegate.clear() 45 | override def remove(range: Range[K, O]) = delegate.remove(range.asJava) 46 | override def put(range: Range[K, O], value: V) = delegate.put(range.asJava, value) 47 | 48 | override def putAll(rangeMap: collect.RangeMap[K, V, O]) = rangeMap match { 49 | case that: RangeMapWrapperLike[K, V, O, _] => delegate.putAll(that.delegate) 50 | case _ => super.putAll(rangeMap) 51 | } 52 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/RangeMapFactory.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect 24 | 25 | import scala.collection.mutable.Builder 26 | 27 | import org.feijoas.mango.common.annotations.Beta 28 | import org.feijoas.mango.common.base.Preconditions.checkNotNull 29 | 30 | /** Factory for RangeMap implementations 31 | * 32 | * @author Markus Schneider 33 | * @since 0.9 34 | */ 35 | @Beta 36 | trait RangeMapFactory[Repr[K, V, O <: Ordering[K]] <: RangeMap[K, V, O] with RangeMapLike[K, V, O, Repr[K, V, O]]] { 37 | 38 | /** Returns an empty [[RangeMap]]. 39 | */ 40 | def empty[K, V, O <: Ordering[K]](implicit ord: O): Repr[K, V, O] = newBuilder[K, V, O](ord).result 41 | 42 | /** Returns a [[RangeMap]] that contains the provided ranges 43 | */ 44 | def apply[K, V, O <: Ordering[K]](entries: (Range[K, O], V)*)(implicit ord: O): Repr[K, V, O] = { 45 | val builder = newBuilder[K, V, O](ord) 46 | entries.foreach { builder += checkNotNull(_) } 47 | builder.result 48 | } 49 | 50 | /** Returns a [[RangeMap]] initialized with the ranges in the specified range map. 51 | */ 52 | def apply[K, V, O <: Ordering[K]](rangeMap: RangeMap[K, V, O])(implicit ord: O): Repr[K, V, O] = { 53 | val builder = newBuilder[K, V, O](ord) 54 | rangeMap.asMapOfRanges.foreach { builder += checkNotNull(_) } 55 | builder.result 56 | } 57 | 58 | /** Returns a new builder for [[RangeMap]]. 59 | */ 60 | def newBuilder[K, V, O <: Ordering[K]](implicit ord: O): Builder[(Range[K, O], V), Repr[K, V, O]] 61 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/cache/CacheLoaderWrapper.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.cache 24 | 25 | import java.util.{ Map => JMap } 26 | import java.lang.{ Iterable => JIterable } 27 | 28 | import scala.collection.convert.decorateAll.{ iterableAsScalaIterableConverter, mapAsJavaMapConverter } 29 | 30 | import org.feijoas.mango.common.base.Preconditions.checkNotNull 31 | import org.feijoas.mango.common.util.concurrent.Futures._ 32 | 33 | import com.google.common.cache.{ CacheLoader => GuavaCacheLoader } 34 | import com.google.common.util.concurrent.ListenableFuture 35 | 36 | /** An adapter that wraps a Mango-[[CacheLoader]] in a Guava-`CacheLoader` and forwards all 37 | * method calls to the underlying Mango-CacheLoader. 38 | * 39 | * @author Markus Schneider 40 | * @since 0.7 41 | */ 42 | private[mango] case class CacheLoaderWrapper[K, V](private val delegate: CacheLoader[K, V]) 43 | extends GuavaCacheLoader[K, V] { 44 | 45 | @throws(classOf[Exception]) 46 | override def load(key: K): V = delegate.load(checkNotNull(key)) 47 | 48 | @throws(classOf[Exception]) 49 | override def reload(key: K, oldValue: V): ListenableFuture[V] = { 50 | delegate.reload(checkNotNull(key), checkNotNull(oldValue)) match { 51 | case null => null 52 | case _@ result => result.asJava 53 | } 54 | } 55 | 56 | override def loadAll(keys: JIterable[_ <: K]): JMap[K, V] = 57 | delegate.loadAll(checkNotNull(keys.asScala)) match { 58 | case null => null 59 | case _@ result => result.asJava 60 | } 61 | } -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/cache/RemovalCauseTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.cache 24 | 25 | import org.feijoas.mango.common.cache.RemovalCause.asGuavaRemovalCauseConverter 26 | import org.feijoas.mango.common.cache.RemovalCause.asMangoRemovalCauseConverter 27 | import org.scalatest.FlatSpec 28 | import org.scalatest.Matchers.be 29 | import org.scalatest.Matchers.convertToAnyShouldWrapper 30 | 31 | import com.google.common.cache.{RemovalCause => GuavaRemovalCause} 32 | 33 | /** Tests for [[RemovalCause]] 34 | * 35 | * @author Markus Schneider 36 | * @since 0.7 (copied from guava-libraries) 37 | */ 38 | class RemovalCauseTest extends FlatSpec { 39 | 40 | behavior of "RemovalCause" 41 | 42 | it should "convert Guava RemovalCause to Mango RemovalCause" in { 43 | GuavaRemovalCause.COLLECTED.asScala should be(RemovalCause.Collected) 44 | GuavaRemovalCause.EXPIRED.asScala should be(RemovalCause.Expired) 45 | GuavaRemovalCause.EXPLICIT.asScala should be(RemovalCause.Explicit) 46 | GuavaRemovalCause.REPLACED.asScala should be(RemovalCause.Replaced) 47 | GuavaRemovalCause.SIZE.asScala should be(RemovalCause.Size) 48 | } 49 | 50 | it should "convert Mango RemovalCause to Guava RemovalCause" in { 51 | RemovalCause.Collected.asJava should be(GuavaRemovalCause.COLLECTED) 52 | RemovalCause.Expired.asJava should be(GuavaRemovalCause.EXPIRED) 53 | RemovalCause.Explicit.asJava should be(GuavaRemovalCause.EXPLICIT) 54 | RemovalCause.Replaced.asJava should be(GuavaRemovalCause.REPLACED) 55 | RemovalCause.Size.asJava should be(GuavaRemovalCause.SIZE) 56 | } 57 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/RangeSetFactory.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect 24 | 25 | import scala.collection.mutable.Builder 26 | import org.feijoas.mango.common.annotations.Beta 27 | import org.feijoas.mango.common.base.Preconditions._ 28 | 29 | /** Factory for RangeSet implementations 30 | * 31 | * @author Markus Schneider 32 | * @since 0.8 33 | */ 34 | @Beta 35 | trait RangeSetFactory[Repr[C, O <: Ordering[C]] <: RangeSet[C, O] with RangeSetLike[C, O, Repr[C, O]]] { 36 | 37 | /** Returns a [[RangeSet]] containing the single range `Range#all` 38 | */ 39 | def all[C, O <: Ordering[C]](implicit ord: O): Repr[C, O] = apply(Range.all[C, O]) 40 | 41 | /** Returns an empty [[RangeSet]]. 42 | */ 43 | def empty[C, O <: Ordering[C]](implicit ord: O): Repr[C, O] = newBuilder[C, O](ord).result 44 | 45 | /** Returns a [[RangeSet]] that contains the provided ranges 46 | */ 47 | def apply[C, O <: Ordering[C]](ranges: Range[C, O]*)(implicit ord: O): Repr[C, O] = { 48 | val builder = newBuilder[C, O](ord) 49 | ranges.foreach { builder += checkNotNull(_) } 50 | builder.result 51 | } 52 | 53 | /** Returns a [[RangeSet]] initialized with the ranges in the specified range set. 54 | */ 55 | def apply[C, O <: Ordering[C]](rangeSet: RangeSet[C, O])(implicit ord: O): Repr[C, O] = { 56 | val builder = newBuilder[C, O](ord) 57 | rangeSet.asRanges.foreach { builder += checkNotNull(_) } 58 | builder.result 59 | } 60 | 61 | /** Returns a new builder for a range set. 62 | */ 63 | def newBuilder[C, O <: Ordering[C]](implicit ord: O): Builder[Range[C, O], Repr[C, O]] 64 | } -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/collect/immutable/ImmutableRangeMapWrapperTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect.immutable 24 | 25 | import scala.annotation.meta.beanGetter 26 | import scala.annotation.meta.beanSetter 27 | import scala.annotation.meta.field 28 | import scala.annotation.meta.getter 29 | import scala.annotation.meta.setter 30 | import scala.math.Ordering.Int 31 | 32 | import org.feijoas.mango.common.annotations.Beta 33 | import org.feijoas.mango.common.collect.AsOrdered 34 | import org.feijoas.mango.common.collect.Range 35 | import org.feijoas.mango.common.collect.RangeMapBehaviors 36 | import org.feijoas.mango.common.collect.RangeMapWrapperBehaviours 37 | import org.scalatest.FreeSpec 38 | import org.scalatest.Matchers.be 39 | import org.scalatest.Matchers.convertToAnyShouldWrapper 40 | 41 | import com.google.common.{collect => gcc} 42 | 43 | /** Tests for [[ImmutableRangeMapWrapperTest]] 44 | * 45 | * @author Markus Schneider 46 | * @since 0.9 47 | */ 48 | class ImmutableRangeMapWrapperTest extends FreeSpec with RangeMapBehaviors with RangeMapWrapperBehaviours { 49 | 50 | "A ImmutableRangeMapWrapper" - { 51 | behave like aRangeMapLike(ImmutableRangeMapWrapper.newBuilder[Int, String, Int.type]) 52 | "it should not create a copy if RangeMap(same type of immutable range map) is called" in { 53 | val fst = ImmutableRangeMapWrapper(Range.open(3, 4) -> "a") 54 | val snd = ImmutableRangeMapWrapper(fst) 55 | fst should be theSameInstanceAs (snd) 56 | } 57 | behave like immutableWrapper((guava: gcc.RangeMap[AsOrdered[Int], String]) => ImmutableRangeMapWrapper[Int, String, Int.type](guava)) 58 | } 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/collect/mutable/TreeRangeMapWrapperTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect.mutable 24 | 25 | import scala.annotation.meta.beanGetter 26 | import scala.annotation.meta.beanSetter 27 | import scala.annotation.meta.field 28 | import scala.annotation.meta.getter 29 | import scala.annotation.meta.setter 30 | import scala.math.Ordering.Int 31 | 32 | import org.feijoas.mango.common.annotations.Beta 33 | import org.feijoas.mango.common.collect.AsOrdered 34 | import org.feijoas.mango.common.collect.Range 35 | import org.feijoas.mango.common.collect.RangeMapBehaviors 36 | import org.feijoas.mango.common.collect.RangeMapWrapperBehaviours 37 | import org.scalatest.FreeSpec 38 | import org.scalatest.Matchers.convertToAnyShouldWrapper 39 | import org.scalatest.Matchers.not 40 | import org.scalatest.Matchers.theSameInstanceAs 41 | 42 | import com.google.common.{collect => gcc} 43 | 44 | /** Tests for [[TreeRangeMapWrapperTest]] 45 | * 46 | * @author Markus Schneider 47 | * @since 0.9 48 | */ 49 | class TreeRangeMapWrapperTest extends FreeSpec with RangeMapBehaviors with RangeMapWrapperBehaviours { 50 | 51 | "A ImmutableRangeMapWrapper" - { 52 | behave like aMutableRangeMapLike(TreeRangeMapWrapper.newBuilder[Int, String, Int.type]) 53 | behave like mutableWrapper((guava: gcc.RangeMap[AsOrdered[Int], String]) => TreeRangeMapWrapper[Int, String, Int.type](guava)) 54 | "it should create a copy if RangeMap(same type of immutable range map) is called" in { 55 | val fst = TreeRangeMapWrapper(Range.open(3, 4) -> "a") 56 | val snd = TreeRangeMapWrapper(fst) 57 | fst should not be theSameInstanceAs(snd) 58 | } 59 | } 60 | } 61 | 62 | -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/cache/RemovalNotificationTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.cache 24 | 25 | import org.scalatest.FlatSpec 26 | import org.scalatest.matchers._ 27 | 28 | import org.feijoas.mango.common.cache.RemovalNotification._ 29 | import org.feijoas.mango.common.cache.RemovalCause._ 30 | import com.google.common.cache.{ RemovalNotification => GuavaRemovalNotification } 31 | import org.scalatest.Matchers._ 32 | 33 | /** 34 | * Tests for [[RemovalNotification]] 35 | * 36 | * @author Markus Schneider 37 | * @since 0.7 (copied from guava-libraries) 38 | */ 39 | class RemovalNotificationTest extends FlatSpec { 40 | behavior of "RemovalNotification" 41 | 42 | it should "convert Guava RemovalNotification to Mango RemovalNotification" in { 43 | // check for all causes, keys, values 44 | val causes = List(Collected, Expired, Explicit, Replaced, Size) 45 | val keys = List(null, "key") 46 | val values = List(null, "values") 47 | 48 | for { 49 | key <- keys 50 | value <- values 51 | cause <- causes 52 | } { 53 | val gn = guavaNotification(key, value, cause) 54 | val cn: RemovalNotification[String, String] = gn.asScala 55 | 56 | Option(key) should be(cn.key) 57 | Option(value) should be(cn.value) 58 | cause should be(cn.cause) 59 | } 60 | } 61 | 62 | /** 63 | * create a guava GuavaRemovalNotification via reflection 64 | */ 65 | def guavaNotification[K, V](key: K, value: V, cause: RemovalCause) = { 66 | val ctors = classOf[GuavaRemovalNotification[K, V]].getDeclaredConstructors() 67 | ctors.length should be(1) 68 | val ctor = ctors(0) 69 | ctor.setAccessible(true) 70 | 71 | val gkey = key.asInstanceOf[Object] 72 | val gvalue = value.asInstanceOf[Object] 73 | val gcause = cause.asJava 74 | ctor.newInstance(gkey, gvalue, gcause).asInstanceOf[GuavaRemovalNotification[K, V]] 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/cache/LoadingCacheWrapper.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.cache 24 | 25 | import scala.annotation.meta.{ beanGetter, beanSetter, field, getter, setter } 26 | import scala.collection.convert.decorateAll.{ asJavaIterableConverter, mapAsScalaMapConverter } 27 | import scala.collection.immutable 28 | import scala.util.Try 29 | 30 | import org.feijoas.mango.common.annotations.Beta 31 | 32 | import com.google.common.cache.{ LoadingCache => GuavaLoadingCache } 33 | 34 | /** An adapter that wraps a Guava-`LoadingCache` in a [[LoadingCache]] and forwards all 35 | * method calls to the underlying Guava-`LoadingCache`. 36 | * 37 | * @author Markus Schneider 38 | * @since 0.7 39 | */ 40 | protected[mango] trait LoadingCacheWrapper[K, V] extends CacheWrapper[K, V] with LoadingCache[K, V] { 41 | 42 | /** Returns the backing Guava `LoadingCache` delegate instance that methods are forwarded to. 43 | * Concrete subclasses override this method to supply the instance being decorated. 44 | */ 45 | protected def cache: GuavaLoadingCache[K, V] 46 | 47 | override def get(key: K): Try[V] = Try(cache.get(key)) 48 | override def getUnchecked(key: K): V = cache.getUnchecked(key) 49 | override def refresh(key: K): Unit = cache.refresh(key) 50 | override def getAll(keys: Traversable[K]): Try[immutable.Map[K, V]] = Try { 51 | val map = cache.getAll(keys.toIterable.asJava).asScala 52 | // TODO: Change this as soon as we have wrappers for Guavas ImmutableMap 53 | immutable.Map.empty ++ map 54 | } 55 | override def getIfPresent(key: K) = Option(cache.getIfPresent(key)) 56 | } 57 | 58 | private[mango] final object LoadingCacheWrapper { 59 | 60 | /** Factory method to create a `LoadingCache[K, V]` from a Guava `LoadingCache[K, V]` 61 | */ 62 | def apply[K, V](guavaCache: GuavaLoadingCache[K, V]): LoadingCache[K, V] = new LoadingCacheWrapper[K, V] { 63 | override def cache = guavaCache 64 | } 65 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/cache/RemovalListener.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.cache 24 | 25 | import org.feijoas.mango.common.annotations.Beta 26 | import org.feijoas.mango.common.cache.RemovalNotification._ 27 | import org.feijoas.mango.common.convert.AsJava 28 | 29 | import com.google.common.cache.{ RemovalListener => GuavaRemovalListener, RemovalNotification => GuavaRemovalNotification } 30 | 31 | /** A function `RemovalNotification[K, V] => Unit` that can receive a notification when an entry is 32 | * removed from a cache. The removal resulting in notification could have occured to an entry being 33 | * manually removed or replaced, or due to eviction resulting from timed expiration, exceeding a 34 | * maximum size, or garbage collection. 35 | * 36 | *

An instance may be called concurrently by multiple threads to process different entries. 37 | * Implementations of `RemovalListener` should avoid performing blocking calls or synchronizing on 38 | * shared resources. 39 | * 40 | * @author Markus Schneider 41 | * @since 0.7 42 | */ 43 | final object RemovalListener { 44 | 45 | /** Adds an `asJava` method that wraps a Mango `RemovalNotification[K, V] => Unit` in a 46 | * Guava `RemovalListener[K, V]`. 47 | * 48 | * The returned Guava `RemovalCause` forwards all method calls to the provided 49 | * Mango `RemovalNotification[K, V] => Unit`. 50 | * 51 | * @param listener the Mango `RemovalNotification[K, V] => Unit` to wrap in a Guava `RemovalListener` 52 | * @return An object with an `asJava` method that returns a Guava `RemovalListener` 53 | * view of the argument 54 | */ 55 | implicit def asGuavaRemovalListenerConverter[K, V](listener: RemovalNotification[K, V] => Unit): AsJava[GuavaRemovalListener[K, V]] = 56 | new AsJava(new GuavaRemovalListener[K, V] { 57 | override def onRemoval(notification: GuavaRemovalNotification[K, V]): Unit = listener(notification.asScala) 58 | }) 59 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/mutable/TreeRangeSetWrapper.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect.mutable 24 | 25 | import scala.collection.mutable.Builder 26 | 27 | import org.feijoas.mango.common.annotations.Beta 28 | import org.feijoas.mango.common.collect.AsOrdered 29 | import org.feijoas.mango.common.collect.Range 30 | import org.feijoas.mango.common.collect.Range.asGuavaRangeConverter 31 | import org.feijoas.mango.common.collect.RangeSetFactory 32 | 33 | import com.google.common.collect.{ RangeSet => GuavaRangeSet } 34 | import com.google.common.collect.TreeRangeSet 35 | 36 | /** An mutable implementation of RangeSet that delegates to Guava TreeRangeSet 37 | * 38 | * @author Markus Schneider 39 | * @since 0.8 40 | */ 41 | @Beta 42 | private[mango] class TreeRangeSetWrapper[C, O <: Ordering[C]] private (guava: GuavaRangeSet[AsOrdered[C]])(override implicit val ordering: O) 43 | extends RangeSet[C, O] with RangeSetWrapperLike[C, O, TreeRangeSetWrapper[C, O]] { 44 | 45 | override def delegate = guava 46 | override def factory = TreeRangeSetWrapper(_)(ordering) 47 | override def newBuilder = TreeRangeSetWrapper.newBuilder[C, O](ordering) 48 | } 49 | 50 | private[mango] final object TreeRangeSetWrapper extends RangeSetFactory[TreeRangeSetWrapper] { 51 | 52 | /** Factory method */ 53 | private[mango] def apply[C, O <: Ordering[C]](guava: GuavaRangeSet[AsOrdered[C]])(implicit ord: O) = new TreeRangeSetWrapper(guava)(ord) 54 | 55 | /** Returns a new builder for a range set. 56 | */ 57 | def newBuilder[C, O <: Ordering[C]](implicit ord: O) = new Builder[Range[C, O], TreeRangeSetWrapper[C, O]]() { 58 | var builder = TreeRangeSet.create[AsOrdered[C]]() 59 | override def +=(range: Range[C, O]): this.type = { 60 | builder.add(range.asJava) 61 | this 62 | } 63 | override def clear() = builder = TreeRangeSet.create[AsOrdered[C]]() 64 | override def result() = new TreeRangeSetWrapper(builder) 65 | } 66 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/mutable/TreeRangeMapWrapper.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect.mutable 24 | 25 | import scala.collection.mutable.Builder 26 | 27 | import org.feijoas.mango.common.annotations.Beta 28 | import org.feijoas.mango.common.collect 29 | import org.feijoas.mango.common.collect.AsOrdered 30 | import org.feijoas.mango.common.collect.Range 31 | import org.feijoas.mango.common.collect.Range.asGuavaRangeConverter 32 | import org.feijoas.mango.common.collect.RangeMapFactory 33 | 34 | import com.google.common.{ collect => gcc } 35 | 36 | /** An mutable implementation of RangeMap that delegates to Guava TreeRangeMap 37 | * 38 | * @author Markus Schneider 39 | * @since 0.9 40 | */ 41 | @Beta 42 | private[mango] class TreeRangeMapWrapper[K, V, O <: Ordering[K]] private (guava: gcc.RangeMap[AsOrdered[K], V])(override implicit val ordering: O) 43 | extends RangeMap[K, V, O] with RangeMapWrapperLike[K, V, O, TreeRangeMapWrapper[K, V, O]] { 44 | 45 | override def delegate = guava 46 | override def factory = TreeRangeMapWrapper(_)(ordering) 47 | override def newBuilder = TreeRangeMapWrapper.newBuilder(ordering) 48 | } 49 | 50 | /** Factory for TreeRangeMapWrapper 51 | */ 52 | private[mango] final object TreeRangeMapWrapper extends RangeMapFactory[TreeRangeMapWrapper] { 53 | 54 | /** Factory method */ 55 | private[mango] def apply[K, V, O <: Ordering[K]](guava: gcc.RangeMap[AsOrdered[K], V])(implicit ord: O) = new TreeRangeMapWrapper(guava)(ord) 56 | 57 | /** Returns a new builder for [[RangeMap]]. 58 | */ 59 | def newBuilder[K, V, O <: Ordering[K]](implicit ord: O) = new Builder[(Range[K, O], V), TreeRangeMapWrapper[K, V, O]]() { 60 | val builder = gcc.TreeRangeMap.create[AsOrdered[K], V]() 61 | override def +=(entry: (Range[K, O], V)): this.type = { 62 | builder.put(entry._1.asJava, entry._2) 63 | this 64 | } 65 | override def clear() = builder.clear() 66 | override def result() = new TreeRangeMapWrapper(builder) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/RangeMapWrapperLike.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect 24 | 25 | import scala.collection.convert.decorateAll.mapAsScalaMapConverter 26 | 27 | import org.feijoas.mango.common.annotations.Beta 28 | import org.feijoas.mango.common.collect.AsOrdered.asOrdered 29 | import org.feijoas.mango.common.collect.Range.asGuavaRangeConverter 30 | 31 | import com.google.common.{ collect => gcc } 32 | 33 | /** Implementation trait for [[RangeMap]] that delegates to Guava 34 | * 35 | * @author Markus Schneider 36 | * @since 0.8 37 | */ 38 | @Beta 39 | private[mango] trait RangeMapWrapperLike[K, V, O <: Ordering[K], +Repr <: RangeMapWrapperLike[K, V, O, Repr] with RangeMap[K, V, O]] 40 | extends RangeMapLike[K, V, O, Repr] { 41 | self => 42 | 43 | /** The Guava RangeMap to use internally */ 44 | protected def delegate: gcc.RangeMap[AsOrdered[K], V] 45 | 46 | /** The `Ordering[K]` used for Ranges is needed */ 47 | protected[this] implicit def ordering: O 48 | 49 | /** Creates a new Repr from a Guava RangeMap */ 50 | protected[this] def factory: gcc.RangeMap[AsOrdered[K], V] => Repr 51 | 52 | override def get(key: K) = Option(delegate.get(key)) 53 | override def isEmpty = delegate.asMapOfRanges().isEmpty 54 | override def subRangeMap(range: Range[K, O]) = factory(delegate.subRangeMap(range.asJava)) 55 | 56 | override def getEntry(key: K) = { 57 | val entry = delegate.getEntry(key) 58 | if (entry == null) 59 | None 60 | else 61 | Some((Range(entry.getKey()), entry.getValue())) 62 | } 63 | 64 | override def span() = { 65 | if (isEmpty) 66 | None 67 | else 68 | Some(Range(delegate.span())) 69 | } 70 | 71 | override def asMapOfRanges() = { 72 | // TODO: Change this as soon as we have wrappers for immutable collectios 73 | val gmap = delegate.asMapOfRanges.asScala 74 | val builder = Map.newBuilder[Range[K, O], V] 75 | gmap.foreach(kv => builder += ((Range[K, O](kv._1), kv._2))) 76 | builder.result 77 | } 78 | } -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/collect/BoundTypeTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect 24 | 25 | import org.feijoas.mango.common.collect.BoundType.Closed 26 | import org.feijoas.mango.common.collect.BoundType.Open 27 | import org.feijoas.mango.common.collect.BoundType.asGuavaBoundType 28 | import org.feijoas.mango.common.collect.BoundType.asMangoBoundType 29 | import org.scalatest.FunSuite 30 | import org.scalatest.Matchers.be 31 | import org.scalatest.Matchers.convertToAnyShouldWrapper 32 | 33 | import com.google.common.collect.{BoundType => GuavaBoundType} 34 | import com.google.common.testing.SerializableTester 35 | 36 | /** Tests for [[BoundType]] 37 | * 38 | * @author Markus Schneider 39 | * @since 0.8 40 | */ 41 | class BoundTypeTest extends FunSuite { 42 | 43 | test("convert from Guava to Mango") { 44 | val gOpen: GuavaBoundType = GuavaBoundType.OPEN 45 | val mOpen: BoundType = gOpen.asScala 46 | 47 | val gClosed: GuavaBoundType = GuavaBoundType.CLOSED 48 | val mClosed: BoundType = gClosed.asScala 49 | 50 | mOpen should be theSameInstanceAs (Open) 51 | mClosed should be theSameInstanceAs (Closed) 52 | } 53 | 54 | test("convert from Mango to Guava") { 55 | val mOpen: BoundType = Open 56 | val gOpen: GuavaBoundType = mOpen.asJava 57 | 58 | val mClosed: BoundType = Closed 59 | val gClosed: GuavaBoundType = mClosed.asJava 60 | 61 | gOpen should be theSameInstanceAs (GuavaBoundType.OPEN) 62 | gClosed should be theSameInstanceAs (GuavaBoundType.CLOSED) 63 | } 64 | 65 | test("throws exeption if attemp to convert null") { 66 | intercept[NullPointerException] { 67 | val mBT: BoundType = null 68 | val gBT: GuavaBoundType = mBT.asJava 69 | } 70 | 71 | intercept[NullPointerException] { 72 | val gBT: GuavaBoundType = null 73 | val mBT: BoundType = gBT.asScala 74 | } 75 | } 76 | 77 | test("serializeable") { 78 | SerializableTester.reserializeAndAssert(Open) 79 | SerializableTester.reserializeAndAssert(Closed) 80 | } 81 | } -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/collect/immutable/ImmutableRangeSetWrapperTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect.immutable 24 | 25 | import scala.annotation.meta.beanGetter 26 | import scala.annotation.meta.beanSetter 27 | import scala.annotation.meta.field 28 | import scala.annotation.meta.getter 29 | import scala.annotation.meta.setter 30 | import scala.math.Ordering.Int 31 | 32 | import org.feijoas.mango.common.annotations.Beta 33 | import org.feijoas.mango.common.collect.AsOrdered 34 | import org.feijoas.mango.common.collect.Range 35 | import org.feijoas.mango.common.collect.RangeSetBehaviors 36 | import org.feijoas.mango.common.collect.RangeSetWrapperBehaviours 37 | import org.scalatest.FreeSpec 38 | import org.scalatest.Matchers.be 39 | import org.scalatest.Matchers.convertToAnyShouldWrapper 40 | 41 | import com.google.common.collect.{RangeSet => GuavaRangeSet} 42 | import com.google.common.testing.SerializableTester.reserializeAndAssert 43 | 44 | /** Tests for [[ImmutableRangeSetWrapperTest]] 45 | * 46 | * @author Markus Schneider 47 | * @since 0.8 48 | */ 49 | class ImmutableRangeSetWrapperTest extends FreeSpec with RangeSetBehaviors with RangeSetWrapperBehaviours { 50 | 51 | "A ImmutableRangeSetWrapper" - { 52 | behave like rangeSet(ImmutableRangeSetWrapper.newBuilder[Int, Int.type]) 53 | behave like rangeSetWithBuilder(ImmutableRangeSetWrapper.newBuilder[Int, Int.type]) 54 | "it should be serializeable" - { 55 | "given the RangeSet contains the Ranges {[5,8],[1,3)}" in { 56 | val rset = (ImmutableRangeSetWrapper.newBuilder[Int, Int.type] ++= Set(Range.closed(5, 8), Range.closedOpen(1, 3))).result 57 | reserializeAndAssert(rset) 58 | } 59 | } 60 | "it should not create a copy if RangeSet(same type of immutable range set) is called" in { 61 | val fst = ImmutableRangeSetWrapper(Range.open(3, 4)) 62 | val snd = ImmutableRangeSetWrapper(fst) 63 | fst should be theSameInstanceAs (snd) 64 | } 65 | behave like immutableWrapper((guava: GuavaRangeSet[AsOrdered[Int]]) => ImmutableRangeSetWrapper[Int, Int.type](guava)) 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/cache/LoadingCacheTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License") 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.cache 24 | 25 | import scala.annotation.meta.{ beanGetter, beanSetter, field, getter, setter } 26 | import scala.util.{ Failure, Success, Try } 27 | 28 | import org.feijoas.mango.common.annotations.Beta 29 | import org.mockito.Mockito.{ spy, times, verify } 30 | import org.scalatest.{ FlatSpec, MustMatchers } 31 | import org.scalatest.mockito.MockitoSugar 32 | 33 | /** 34 | * Tests for [[LoadingCache]] 35 | * 36 | * @author Markus Schneider 37 | * @since 0.7 (copied from guava-libraries) 38 | */ 39 | class LoadingCacheTest extends FlatSpec with MustMatchers with MockitoSugar { 40 | 41 | def fixture = { 42 | val loader = (key: String) => 100 / key.length 43 | val cache = new MapLoadingCache(loader) 44 | (loader, cache) 45 | } 46 | 47 | behavior of "the default implementations of Cache" 48 | 49 | "getUnchecked" must "return a value or throw an exception" in { 50 | val (loader, cache) = fixture 51 | cache.getUnchecked("a") must be(100) 52 | intercept[com.google.common.util.concurrent.UncheckedExecutionException] { 53 | cache.getUnchecked("") 54 | } 55 | } 56 | 57 | "getAll" must "return Success with a map of all key/values or Failure" in { 58 | val (loader, cache) = fixture 59 | cache.getAll(List("a", "bb", "cc")) must be(Success(Map("a" -> 100, "bb" -> 50, "cc" -> 50))) 60 | cache.getAll(List("a", "", "cc")) match { 61 | case Failure(_) => // expected 62 | case other @ _ => fail("Expected Failure(_) but was " + other) 63 | } 64 | } 65 | 66 | "getAll" must "call get only once per key" in { 67 | val (loader, unspyedcache) = fixture 68 | val cache = spy(unspyedcache) 69 | cache.getAll(List("a", "bb", "a")) must be(Success(Map("a" -> 100, "bb" -> 50))) 70 | verify(cache, times(1)).get("a") 71 | } 72 | } 73 | 74 | /** 75 | * A cache implemented with a map 76 | */ 77 | protected[mango] class MapLoadingCache[K, V](loader: K => V) extends MapCache[K, V]() with LoadingCache[K, V] { 78 | def get(key: K): Try[V] = Try(loader(key)) 79 | def refresh(key: K): Unit = loader(key) 80 | } 81 | -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/base/OptionalTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.base 24 | 25 | import org.feijoas.mango.common.base.Optional._ 26 | import org.scalatest._ 27 | import org.scalatest.prop.PropertyChecks 28 | 29 | import com.google.common.base.{ Optional => GuavaOptional } 30 | import com.google.common.testing.SerializableTester 31 | 32 | /** 33 | * Tests for [[Optionals]] 34 | * 35 | * @author Markus Schneider 36 | * @since 0.7 37 | */ 38 | class OptionalTest extends FlatSpec with Matchers with PropertyChecks { 39 | 40 | behavior of "implicits" 41 | 42 | it should "map a Guava Present to a Scala Some" in { 43 | val optional: GuavaOptional[String] = GuavaOptional.of("some") 44 | val option: Option[String] = optional.asScala 45 | 46 | option should be(Some("some")) 47 | } 48 | 49 | it should "map a Guava Absent to a Scala None" in { 50 | val optional: GuavaOptional[Any] = GuavaOptional.absent() 51 | val option: Option[Any] = optional.asScala 52 | 53 | option should be(None) 54 | } 55 | 56 | it should "map a Scala Some to a Guava Present" in { 57 | val option: Option[String] = Some("some") 58 | val optional: GuavaOptional[String] = option.asJava 59 | 60 | optional should be(GuavaOptional.of("some")) 61 | } 62 | 63 | it should "map a Scala None to a Guava Absent" in { 64 | val option: Option[Any] = None 65 | val optional: GuavaOptional[Any] = option.asJava 66 | 67 | optional should be(GuavaOptional.absent()) 68 | } 69 | 70 | it should "be nullsafe" in { 71 | intercept[NullPointerException] { 72 | val option: Option[Any] = null 73 | val optional: GuavaOptional[Any] = option.asJava 74 | } 75 | 76 | intercept[NullPointerException] { 77 | val optional: GuavaOptional[Any] = null 78 | val option: Option[Any] = optional.asScala 79 | } 80 | } 81 | 82 | it should "be serializeable" in { 83 | SerializableTester.reserialize(GuavaOptional.of("some").asScala) 84 | SerializableTester.reserialize(GuavaOptional.absent().asScala) 85 | SerializableTester.reserialize(Some("some").asJava) 86 | SerializableTester.reserialize(None.asJava) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/cache/CacheStatsMatcher.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.cache 24 | 25 | import org.scalatest.matchers._ 26 | 27 | /** CacheStatsMatcher 28 | * 29 | * @author Markus Schneider 30 | * @since 0.7 (copied from Guava-libraries) 31 | */ 32 | trait CacheStatsMatcher { 33 | 34 | def hitCount(expectedValue: Long) = 35 | new HavePropertyMatcher[CacheStats, Long] { 36 | def apply(stats: CacheStats) = HavePropertyMatchResult( 37 | stats.hitCount == expectedValue, 38 | "hitCount", 39 | expectedValue, 40 | stats.hitCount) 41 | } 42 | 43 | def missCount(expectedValue: Long) = 44 | new HavePropertyMatcher[CacheStats, Long] { 45 | def apply(stats: CacheStats) = HavePropertyMatchResult( 46 | stats.missCount == expectedValue, 47 | "missCount", 48 | expectedValue, 49 | stats.missCount) 50 | } 51 | 52 | def loadSuccessCount(expectedValue: Long) = 53 | new HavePropertyMatcher[CacheStats, Long] { 54 | def apply(stats: CacheStats) = HavePropertyMatchResult( 55 | stats.loadSuccessCount == expectedValue, 56 | "loadSuccessCount", 57 | expectedValue, 58 | stats.loadSuccessCount) 59 | } 60 | 61 | def loadExceptionCount(expectedValue: Long) = 62 | new HavePropertyMatcher[CacheStats, Long] { 63 | def apply(stats: CacheStats) = HavePropertyMatchResult( 64 | stats.loadExceptionCount == expectedValue, 65 | "loadExceptionCount", 66 | expectedValue, 67 | stats.loadExceptionCount) 68 | } 69 | 70 | def totalLoadTime(expectedValue: Long) = 71 | new HavePropertyMatcher[CacheStats, Long] { 72 | def apply(stats: CacheStats) = HavePropertyMatchResult( 73 | stats.totalLoadTime == expectedValue, 74 | "totalLoadTime", 75 | expectedValue, 76 | stats.totalLoadTime) 77 | } 78 | 79 | def evictionCount(expectedValue: Long) = 80 | new HavePropertyMatcher[CacheStats, Long] { 81 | def apply(stats: CacheStats) = HavePropertyMatchResult( 82 | stats.evictionCount == expectedValue, 83 | "evictionCount", 84 | expectedValue, 85 | stats.evictionCount) 86 | } 87 | } -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/cache/CacheTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.cache 24 | 25 | import scala.annotation.meta.{ beanGetter, beanSetter, field, getter, setter } 26 | import scala.collection.concurrent 27 | import scala.collection.concurrent.TrieMap 28 | 29 | import org.feijoas.mango.common.annotations.Beta 30 | import org.scalatest.{ FlatSpec, GivenWhenThen, MustMatchers } 31 | import org.scalatest.mockito.MockitoSugar 32 | 33 | /** 34 | * Tests for [[Cache]] 35 | * 36 | * @author Markus Schneider 37 | * @since 0.7 38 | */ 39 | class CacheTest extends FlatSpec with MustMatchers with GivenWhenThen with MockitoSugar { 40 | 41 | def fixture = { 42 | val cache = new MapCache[String, Int]() 43 | (cache.asMap, cache) 44 | } 45 | 46 | behavior of "the default implementations of Cache" 47 | 48 | "getAllPresent(keys)" must "return all (key,value)-pairs in the cache" in { 49 | val (map, cache) = fixture 50 | map.put("a", 1) 51 | map.put("c", 3) 52 | cache.getAllPresent(List("a", "b", "c")) must be(Map("a" -> 1, "c" -> 3)) 53 | } 54 | 55 | "putAll(keys)" must "put all key in the map" in { 56 | val (map, cache) = fixture 57 | cache.putAll(Map("a" -> 1, "c" -> 3)) 58 | map must be(Map("a" -> 1, "c" -> 3)) 59 | } 60 | 61 | "invalidateAll(keys)" must "call invalidate for each key" in { 62 | val (map, cache) = fixture 63 | map.put("a", 1) 64 | map.put("b", 2) 65 | map.put("c", 3) 66 | map must be(Map("a" -> 1, "b" -> 2, "c" -> 3)) 67 | cache.invalidateAll(List("a", "b", "d")) 68 | map must be(Map("c" -> 3)) 69 | } 70 | } 71 | 72 | /** 73 | * A cache implemented with a map 74 | */ 75 | protected[mango] class MapCache[K, V]() extends Cache[K, V] { 76 | val map = TrieMap[K, V]() 77 | def getIfPresent(key: K): Option[V] = map.get(key) 78 | def getOrElseUpdate(key: K, loader: () => V): V = map.getOrElseUpdate(key, loader()) 79 | def put(key: K, value: V): Unit = map.put(key, value) 80 | def invalidate(key: K): Unit = map.remove(key) 81 | def invalidateAll(): Unit = map.clear 82 | def size(): Long = map.size 83 | def stats(): CacheStats = throw new NotImplementedError() 84 | def asMap(): concurrent.Map[K, V] = map 85 | } 86 | -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/Bound.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect 24 | 25 | import org.feijoas.mango.common.base.Preconditions.checkNotNull 26 | import org.feijoas.mango.common.collect.BoundType.{Closed, Open} 27 | 28 | /** A `Bound` describes the to bounds of a [[Range]]. For example the range 29 | * `(4,7]` has the two (finite) bounds "open" 4 and 7 "closed". A bound is 30 | * either a `FiniteBound[T]` with a value of type `T` and a [[BoundType]] or 31 | * an `InifinteBound`. An `InifinteBound` is used to describe unbounded ranges 32 | * as for example `[a..+∞)` 33 | * 34 | * @author Markus Schneider 35 | * @since 0.8 36 | */ 37 | sealed trait Bound[+T] extends Serializable { 38 | private[mango] def describeAsLowerBound(sb: StringBuilder) 39 | private[mango] def describeAsUpperBound(sb: StringBuilder) 40 | } 41 | 42 | /** A `Bound` describes the to bounds of a [[Range]]. For example the range 43 | * `(4,7]` has the two (finite) bounds "open" 4 and 7 "closed". A bound is 44 | * either a `FiniteBound[T]` with a value of type `T` and a [[BoundType]] or 45 | * an `InifinteBound`. An `InifinteBound` is used to describe unbounded ranges 46 | * as for example `[a..+∞)` 47 | * 48 | * @author Markus Schneider 49 | * @since 0.8 50 | */ 51 | final object Bound { 52 | /** A `FiniteBound[T]` is a bound with a value of type `T` and a [[BoundType]]. 53 | */ 54 | case class FiniteBound[T](value: T, bt: BoundType) extends Bound[T] { 55 | checkNotNull(value) 56 | checkNotNull(bt) 57 | 58 | override def describeAsLowerBound(sb: StringBuilder) = bt match { 59 | case Closed => sb.append('[').append(value) 60 | case Open => sb.append('(').append(value) 61 | } 62 | override def describeAsUpperBound(sb: StringBuilder) = bt match { 63 | case Closed => sb.append(value).append(']') 64 | case Open => sb.append(value).append(')') 65 | } 66 | } 67 | 68 | /** An `InifinteBound` is used to describe unbounded ranges 69 | * as for example `[a..+∞)` 70 | */ 71 | final object InfiniteBound extends Bound[Nothing] { 72 | override def describeAsLowerBound(sb: StringBuilder) = sb.append("(-\u221e") 73 | override def describeAsUpperBound(sb: StringBuilder) = sb.append("+\u221e)") 74 | } 75 | } -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/collect/DiscreteDomainTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect 24 | 25 | import org.feijoas.mango.common.annotations.Beta 26 | import org.feijoas.mango.common.collect.DiscreteDomain.{ IntDomain, LongDomain } 27 | import org.scalacheck.{ Arbitrary, Shrink } 28 | import org.scalatest._ 29 | import org.scalatest.prop.PropertyChecks 30 | 31 | import com.google.common.collect.{ DiscreteDomain => GuavaDiscreteDomain } 32 | import com.google.common.testing.SerializableTester.reserializeAndAssert 33 | 34 | /** 35 | * Tests for [[Range]] 36 | * 37 | * @author Markus Schneider 38 | * @since 0.8 39 | */ 40 | class DiscreteDomainTestextends extends FlatSpec with Matchers with PropertyChecks with DiscreteDomainBehaviors { 41 | 42 | "IntDomain" should behave like guavaDomain(IntDomain, GuavaDiscreteDomain.integers()) 43 | "LongDomain" should behave like guavaDomain(LongDomain, GuavaDiscreteDomain.longs()) 44 | 45 | } 46 | 47 | private[mango] trait DiscreteDomainBehaviors extends PropertyChecks with Matchers { 48 | this: FlatSpec => 49 | 50 | def guavaDomain[C <: Comparable[_], T: Arbitrary: Shrink](domain: DiscreteDomain[T], guava: GuavaDiscreteDomain[C])(implicit view: T => C) = { 51 | 52 | it should "implement distance" in { 53 | forAll { (start: T, end: T) => 54 | domain.distance(start, end) should be(guava.distance(start, end)) 55 | } 56 | } 57 | 58 | it should "implement next" in { 59 | forAll { value: T => 60 | val gn = guava.next(value) 61 | if (gn == null) 62 | domain.next(value) should be(None) 63 | else 64 | domain.next(value) should be(Some(gn)) 65 | } 66 | } 67 | 68 | it should "implement previous" in { 69 | forAll { value: T => 70 | val gn = guava.previous(value) 71 | if (gn == null) 72 | domain.previous(value) should be(None) 73 | else 74 | domain.previous(value) should be(Some(gn)) 75 | } 76 | } 77 | 78 | it should "implement minValue and maxValue" in { 79 | domain.maxValue should be(Option(guava.maxValue())) 80 | domain.minValue should be(Option(guava.minValue())) 81 | } 82 | 83 | it should "be serializeable" in { 84 | reserializeAndAssert(domain) 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/RangeSetWrapperLike.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect 24 | 25 | import scala.collection.convert.decorateAll.asScalaSetConverter 26 | 27 | import org.feijoas.mango.common.annotations.Beta 28 | import org.feijoas.mango.common.collect.AsOrdered.asOrdered 29 | import org.feijoas.mango.common.collect.Range.asGuavaRangeConverter 30 | 31 | import com.google.common.collect.{ RangeSet => GuavaRangeSet } 32 | 33 | /** Implementation trait for [[RangeSet]] that delegates to Guava 34 | * 35 | * @author Markus Schneider 36 | * @since 0.8 37 | */ 38 | @Beta 39 | private[mango] trait RangeSetWrapperLike[C, O <: Ordering[C], +Repr <: RangeSetWrapperLike[C, O, Repr] with RangeSet[C, O]] 40 | extends RangeSetLike[C, O, Repr] { 41 | self => 42 | 43 | /** The Guava RangeSet to use internally */ 44 | protected def delegate: GuavaRangeSet[AsOrdered[C]] 45 | 46 | /** The Ordering[C] used for Ranges is needed */ 47 | protected implicit def ordering: O 48 | 49 | /** Creates a new Repr from a Guava RangeSet */ 50 | protected[this] def factory: (GuavaRangeSet[AsOrdered[C]]) => Repr 51 | 52 | override def contains(value: C): Boolean = delegate.contains(value) 53 | override def encloses(otherRange: Range[C, O]): Boolean = delegate.encloses(otherRange.asJava) 54 | override def isEmpty: Boolean = delegate.isEmpty 55 | override def complement(): Repr = factory(delegate.complement) 56 | override def subRangeSet(view: Range[C, O]): Repr = factory(delegate.subRangeSet(view.asJava)) 57 | 58 | override def rangeContaining(value: C): Option[Range[C, O]] = delegate.rangeContaining(value) match { 59 | case null => None 60 | case some => Some(Range(some)) 61 | } 62 | 63 | override def enclosesAll(other: org.feijoas.mango.common.collect.RangeSet[C, O]): Boolean = other match { 64 | case wrapper: RangeSetWrapperLike[C, O, _] => delegate.enclosesAll(wrapper.delegate) 65 | case _ => super.enclosesAll(other) 66 | } 67 | 68 | override def span(): Option[Range[C, O]] = delegate.isEmpty match { 69 | case true => None 70 | case false => Some(Range(delegate.span())) 71 | } 72 | 73 | override def asRanges(): Set[Range[C, O]] = { 74 | val set = delegate.asRanges().asScala.view.map(Range[C, O](_)) 75 | // TODO: Change this as soon as we have wrappers for Guavas ImmutableSet 76 | Set.empty ++ set 77 | } 78 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/BoundType.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect 24 | 25 | import org.feijoas.mango.common.base.Preconditions.checkNotNull 26 | import org.feijoas.mango.common.convert.{ AsJava, AsScala } 27 | 28 | import com.google.common.collect.{ BoundType => GuavaBoundType } 29 | 30 | /** Indicates whether an endpoint of some range is contained in the range itself ("closed") or not 31 | * ("open"). If a range is unbounded on a side, it is neither open nor closed on that side; the 32 | * bound simply does not exist. 33 | * 34 | * @author Markus Schneider 35 | * @since 0.8 (copied from Guava-libraries) 36 | */ 37 | sealed trait BoundType extends Serializable 38 | 39 | /** Indicates whether an endpoint of some range is contained in the range itself ("closed") or not 40 | * ("open"). If a range is unbounded on a side, it is neither open nor closed on that side; the 41 | * bound simply does not exist. 42 | * 43 | * @author Markus Schneider 44 | * @since 0.8 (copied from Guava-libraries) 45 | */ 46 | final object BoundType { 47 | 48 | /** The endpoint value is not considered part of the set ("exclusive"). 49 | */ 50 | final object Open extends BoundType 51 | 52 | /** The endpoint value is considered part of the set ("inclusive"). 53 | */ 54 | final object Closed extends BoundType 55 | 56 | /** Adds an `asScala` method that converts a Guava `BoundType` to a Mango `BoundType` 57 | * 58 | * @param bt the Guava `BoundType` to convert to a Mango `BoundType` 59 | * @return An object with an `asScala` method that converts a Guava `BoundType` 60 | * to a Mango `BoundType` 61 | */ 62 | implicit final def asMangoBoundType(bt: GuavaBoundType): AsScala[BoundType] = { 63 | new AsScala(checkNotNull(bt) match { 64 | case GuavaBoundType.OPEN => Open 65 | case GuavaBoundType.CLOSED => Closed 66 | }) 67 | } 68 | 69 | /** Adds an `asJava` method that converts a Mango `BoundType` to a Guava `BoundType` 70 | * 71 | * @param bt the Mango `BoundType` to convert to a Guava `BoundType` 72 | * @return An object with an `asJava` method that converts a Mango `BoundType` 73 | * to a Guava `BoundType` 74 | */ 75 | implicit final def asGuavaBoundType(bt: BoundType): AsJava[GuavaBoundType] = { 76 | new AsJava(checkNotNull(bt) match { 77 | case Open => GuavaBoundType.OPEN 78 | case Closed => GuavaBoundType.CLOSED 79 | }) 80 | } 81 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/base/Optional.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.base 24 | 25 | import org.feijoas.mango.common.base.Preconditions.checkNotNull 26 | import org.feijoas.mango.common.convert.{ AsJava, AsScala } 27 | 28 | import com.google.common.base.{ Optional => GuavaOptional } 29 | 30 | /** Utility functions for the work with `Option[T]` and `Optional[T]` 31 | * 32 | * Usage example for conversion between Guava and Mango: 33 | * {{{ 34 | * // convert a Guava Optional[T] to a Scala Option[T] 35 | * Optional.of("some").asScala 36 | * Optional.absent().asScala 37 | * 38 | * // convert a Scala Option[T] to a Guava Optional[T] 39 | * Some("some").asJava 40 | * None.asJava 41 | * }}} 42 | * 43 | * @author Markus Schneider 44 | * @since 0.7 45 | */ 46 | final object Optional { 47 | 48 | /** Adds an `asJava` method that converts a Scala `Option[T]` to 49 | * a Guava `Optional[T]`. 50 | * 51 | * The returned Guava `Optional[T]` contains the same reference as in the 52 | * Scala `Option[T]` or `GuavaOptional.absent()` if the `Option[T]` is None. 53 | * 54 | * @param option the Scala `Option[T]` to convert to a Guava `Optional[T]` 55 | * @return An object with an `asJava` method that returns a Guava `Optional[T]` 56 | * view of the argument 57 | */ 58 | implicit def asGuavaOptionalConverter[T](option: Option[T]): AsJava[GuavaOptional[T]] = { 59 | def convert(option: Option[T]): GuavaOptional[T] = checkNotNull(option) match { 60 | case Some(value) => GuavaOptional.of(value) 61 | case None => GuavaOptional.absent() 62 | } 63 | new AsJava(convert(option)) 64 | } 65 | 66 | /** Adds an `asScala` method that converts a Guava `Optional[T]` to 67 | * a Scala `Option[T]`. 68 | * 69 | * The returned Scala `Option[T]` contains the same reference as in the 70 | * Guava `Optional[T]` or `None` if the `Optional[T]` is absent. 71 | * 72 | * @param option the Guava `Optional[T]` to convert to a Scala `Option[T]` 73 | * @return An object with an `asScala` method that returns a Scala `Option[T]` 74 | * view of the argument 75 | */ 76 | implicit def asMangoOptionConverter[T](option: GuavaOptional[T]): AsScala[Option[T]] = { 77 | def convert(option: GuavaOptional[T]) = option.isPresent() match { 78 | case true => Some(option.get()) 79 | case false => None 80 | } 81 | new AsScala(convert(option)) 82 | } 83 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/cache/RemovalNotification.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.cache 24 | 25 | import scala.annotation.meta.{ beanGetter, beanSetter, field, getter, setter } 26 | import org.feijoas.mango.common.convert.AsScala 27 | import org.feijoas.mango.common.annotations.Beta 28 | import org.feijoas.mango.common.cache.RemovalCause._ 29 | 30 | import com.google.common.cache.{ RemovalNotification => GuavaRemovalNotification } 31 | import com.google.common.cache.{ RemovalCause => GuavaRemovalCause } 32 | import org.feijoas.mango.common.cache.RemovalCause._ 33 | 34 | /** A notification of the removal of a single entry. The key and/or value may be 35 | * `None` if the corresponding key/value was already garbage collected. 36 | * 37 | *

A key/value pair associated with [[CacheBuilder]], this class holds 38 | * strong references to the key and value, regardless of the type of references the cache may be 39 | * using. 40 | * 41 | * @constructor create a new RemovalNotification with key,value and cause of removal 42 | * @param key the key of the cache entry 43 | * @param value the value of the cache entry 44 | * @param cause the cause for which the entry was removed 45 | * 46 | * @author Markus Schneider 47 | * @since 0.7 (copied from Guava-libraries) 48 | */ 49 | @Beta 50 | case class RemovalNotification[+K, +V]( 51 | val key: Option[K], 52 | val value: Option[V], 53 | val cause: RemovalCause) { 54 | } 55 | 56 | final object RemovalNotification { 57 | 58 | /** Adds an `asScala` method that converts a Guava `RemovalNotification[K, V]` 59 | * to a Mango `RemovalNotification[K, V]`. 60 | * 61 | * The returned Mango `RemovalNotification[K, V]` contains a reference of the 62 | * `key` and `value` from the Guava `RemovalNotification[K, V]` wrapped in 63 | * a `Some[K]` or `None` if `key` or `value` is `null`. 64 | * 65 | * @param notification the Guava `RemovalNotification[K, V]` to convert to a Mango `RemovalNotification[K, V]` 66 | * @return An object with an `asScala` method that returns a Mango `RemovalNotification[K, V]` 67 | * view of the argument 68 | */ 69 | implicit final def asMangoRemovalNotificationConverter[K, V](notification: GuavaRemovalNotification[K, V]): AsScala[RemovalNotification[K, V]] = { 70 | val (key, value, cause) = (notification.getKey(), notification.getValue(), notification.getCause()) 71 | new AsScala(RemovalNotification(Option(key), Option(value), cause.asScala)) 72 | } 73 | } -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/cache/RemovalListenerTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.cache 24 | 25 | import org.feijoas.mango.common.cache.RemovalListener._ 26 | import org.scalatest.FlatSpec 27 | import org.scalatest.matchers._ 28 | import com.google.common.cache.{ RemovalListener => GuavaRemovalListener } 29 | import com.google.common.cache.{ RemovalNotification => GuavaRemovalNotification } 30 | import com.google.common.cache.{ RemovalCause => GuavaRemovalCause } 31 | import org.feijoas.mango.common.cache.RemovalCause._ 32 | import org.scalatest.Matchers._ 33 | 34 | /** 35 | * Tests for [[RemovalListener]] 36 | * 37 | * @author Markus Schneider 38 | * @since 0.7 39 | */ 40 | class RemovalListenerTest extends FlatSpec { 41 | 42 | behavior of "RemovalListener" 43 | 44 | it should "convert a function to a Guava RemovalListener" in { 45 | // check for all causes, keys, values 46 | val causes = List(Collected, Expired, Explicit, Replaced, Size) 47 | val keys = List(null, "key") 48 | val values = List(null, "values") 49 | 50 | for { 51 | key <- keys 52 | value <- values 53 | cause <- causes 54 | } check(key, value, cause) 55 | } 56 | 57 | def check(key: String, value: String, cause: RemovalCause) = { 58 | // assert that the call to the gauva listener was forwarded to listener 59 | var called = false 60 | 61 | // create a which checks that the notification is the one we give 62 | // to the Guava listener 63 | val listener = (n: RemovalNotification[String, String]) => { 64 | n should be(RemovalNotification(Option(key), Option(value), cause)) 65 | called should be(false) 66 | called = true 67 | } 68 | 69 | // implicit conversion 70 | val guavaListener: GuavaRemovalListener[String, String] = listener.asJava 71 | val notification = guavaNotification(key, value, cause.asJava) 72 | 73 | // the call forwards to listener 74 | guavaListener.onRemoval(notification) 75 | called should be(true) 76 | } 77 | 78 | /** 79 | * create a guava GuavaRemovalNotification via reflection 80 | */ 81 | def guavaNotification[K, V](key: K, value: V, cause: GuavaRemovalCause) = { 82 | val ctors = classOf[GuavaRemovalNotification[K, V]].getDeclaredConstructors() 83 | ctors.length should be(1) 84 | val ctor = ctors(0) 85 | ctor.setAccessible(true) 86 | ctor.newInstance(key.asInstanceOf[Object], value.asInstanceOf[Object], cause).asInstanceOf[GuavaRemovalNotification[K, V]] 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/base/Ticker.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.base 24 | 25 | import org.feijoas.mango.common.annotations.Beta 26 | import com.google.common.base.{ Ticker => GuavaTicker } 27 | import org.feijoas.mango.common.convert.{ AsJava, AsScala } 28 | 29 | /** A time source; returns a time value representing the number of nanoseconds elapsed since some 30 | * fixed but arbitrary point in time. Note that most users should use `Stopwatch` instead of 31 | * interacting with this class directly. 32 | * 33 | *

Warning: this interface can only be used to measure elapsed time, not wall time. 34 | * 35 | * @author Markus Schneider 36 | * @since 0.7 (copied from guava-libraries) 37 | */ 38 | @Beta 39 | trait Ticker { 40 | 41 | /** Returns the number of nanoseconds elapsed since this ticker's fixed 42 | * point of reference. 43 | */ 44 | def read(): Long 45 | } 46 | 47 | /** Factory for [[Ticker]] instances. */ 48 | object Ticker { 49 | 50 | /** A ticker that reads the current time using `System#nanoTime`. 51 | */ 52 | def systemTicker() = GuavaTicker.systemTicker().asScala 53 | 54 | /** Adds an `asJava` method that wraps a Mango `Ticker` in 55 | * a Guava `Ticker`. 56 | * 57 | * The returned Guava `Ticker` forwards all calls of the `read` method 58 | * to the given Scala `ticker`. 59 | * 60 | * @param ticker the Mango `Ticker` to wrap in a Guava `Ticker` 61 | * @return An object with an `asJava` method that returns a Guava `Ticker` 62 | * view of the argument 63 | */ 64 | implicit final def asGuavaTickerConverter[T](ticker: Ticker): AsJava[GuavaTicker] = { 65 | def convert(ticker: Ticker): GuavaTicker = new GuavaTicker { 66 | override def read() = ticker.read() 67 | } 68 | new AsJava(convert(ticker)) 69 | } 70 | 71 | /** Adds an `asScala` method that wraps a Guava `Ticker` in 72 | * a Mango `Ticker`. 73 | * 74 | * The returned Mango `Ticker` forwards all calls of the `read` method 75 | * to the given Guava `ticker`. 76 | * 77 | * @param ticker the Guava `Ticker` to wrap in a Mango `Ticker` 78 | * @return An object with an `asScala` method that returns a Mango `Ticker` 79 | * view of the argument 80 | */ 81 | implicit final def asMangoTickerConverter[T](ticker: GuavaTicker): AsScala[Ticker] = { 82 | def convert(ticker: GuavaTicker): Ticker = new Ticker { 83 | override def read() = ticker.read() 84 | } 85 | new AsScala(convert(ticker)) 86 | } 87 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/immutable/ImmutableRangeMapWrapper.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect.immutable 24 | 25 | import scala.collection.mutable.Builder 26 | 27 | import org.feijoas.mango.common.annotations.Beta 28 | import org.feijoas.mango.common.collect 29 | import org.feijoas.mango.common.collect.AsOrdered 30 | import org.feijoas.mango.common.collect.Range 31 | import org.feijoas.mango.common.collect.Range.asGuavaRangeConverter 32 | import org.feijoas.mango.common.collect.RangeMapFactory 33 | import org.feijoas.mango.common.collect.RangeMapWrapperLike 34 | 35 | import com.google.common.{ collect => gcc } 36 | 37 | /** An immutable implementation of RangeMap that delegates to Guava ImmutableRangeMap 38 | * 39 | * @author Markus Schneider 40 | * @since 0.9 41 | */ 42 | @Beta 43 | private[mango] class ImmutableRangeMapWrapper[K, V, O <: Ordering[K]] private (guava: gcc.RangeMap[AsOrdered[K], V])(override implicit val ordering: O) 44 | extends RangeMap[K, V, O] with RangeMapWrapperLike[K, V, O, ImmutableRangeMapWrapper[K, V, O]] { 45 | 46 | override def delegate = guava 47 | override def factory = ImmutableRangeMapWrapper(_)(ordering) 48 | override def newBuilder = ImmutableRangeMapWrapper.newBuilder(ordering) 49 | } 50 | 51 | /** Factory for ImmutableRangeMapWrapper 52 | */ 53 | private[mango] final object ImmutableRangeMapWrapper extends RangeMapFactory[ImmutableRangeMapWrapper] { 54 | 55 | /** Factory method */ 56 | private[mango] def apply[K, V, O <: Ordering[K]](guava: gcc.RangeMap[AsOrdered[K], V])(implicit ord: O) = new ImmutableRangeMapWrapper(guava)(ord) 57 | 58 | /** Returns a [[RangeMap]] initialized with the ranges in the specified range set. 59 | */ 60 | override def apply[K, V, O <: Ordering[K]](rangeMap: collect.RangeMap[K, V, O])(implicit ord: O) = rangeMap match { 61 | case same: ImmutableRangeMapWrapper[K, V, O] => same 62 | case _ => super.apply(rangeMap) 63 | } 64 | 65 | /** Returns a new builder for [[RangeMap]]. 66 | */ 67 | def newBuilder[K, V, O <: Ordering[K]](implicit ord: O) = new Builder[(Range[K, O], V), ImmutableRangeMapWrapper[K, V, O]]() { 68 | var builder = gcc.ImmutableRangeMap.builder[AsOrdered[K], V]() 69 | override def +=(entry: (Range[K, O], V)): this.type = { 70 | builder.put(entry._1.asJava, entry._2) 71 | this 72 | } 73 | override def clear() = builder = gcc.ImmutableRangeMap.builder[AsOrdered[K], V]() 74 | override def result() = new ImmutableRangeMapWrapper(builder.build) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/immutable/ImmutableRangeSetWrapper.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect.immutable 24 | 25 | import scala.collection.mutable.Builder 26 | 27 | import org.feijoas.mango.common.annotations.Beta 28 | import org.feijoas.mango.common.collect 29 | import org.feijoas.mango.common.collect.AsOrdered 30 | import org.feijoas.mango.common.collect.Range 31 | import org.feijoas.mango.common.collect.Range.asGuavaRangeConverter 32 | import org.feijoas.mango.common.collect.RangeSetFactory 33 | import org.feijoas.mango.common.collect.RangeSetWrapperLike 34 | 35 | import com.google.common.collect.ImmutableRangeSet 36 | import com.google.common.collect.{ RangeSet => GuavaRangeSet } 37 | 38 | /** An immutable implementation of RangeSet that delegates to Guava ImmutableRangeSet 39 | * 40 | * @author Markus Schneider 41 | * @since 0.8 42 | */ 43 | @Beta 44 | @SerialVersionUID(1L) 45 | private[mango] class ImmutableRangeSetWrapper[C, O <: Ordering[C]] private (guava: GuavaRangeSet[AsOrdered[C]])(override implicit val ordering: O) 46 | extends RangeSet[C, O] with RangeSetWrapperLike[C, O, ImmutableRangeSetWrapper[C, O]] with Serializable { 47 | 48 | override def delegate = guava 49 | override def factory: GuavaRangeSet[AsOrdered[C]] => ImmutableRangeSetWrapper[C, O] = new ImmutableRangeSetWrapper(_)(ordering) 50 | override def newBuilder = ImmutableRangeSetWrapper.newBuilder[C, O](ordering) 51 | } 52 | 53 | /** Factory for ImmutableRangeSetWrapper 54 | */ 55 | private[mango] final object ImmutableRangeSetWrapper extends RangeSetFactory[ImmutableRangeSetWrapper] { 56 | 57 | /** Factory method */ 58 | private[mango] def apply[C, O <: Ordering[C]](guava: GuavaRangeSet[AsOrdered[C]])(implicit ord: O) = new ImmutableRangeSetWrapper(guava)(ord) 59 | 60 | /** Returns a [[RangeSet]] initialized with the ranges in the specified range set. 61 | */ 62 | override def apply[C, O <: Ordering[C]](rangeSet: collect.RangeSet[C, O])(implicit ord: O) = rangeSet match { 63 | case same: ImmutableRangeSetWrapper[C, O] => same 64 | case _ => super.apply(rangeSet) 65 | } 66 | 67 | /** Returns a new builder for a range set. 68 | */ 69 | def newBuilder[C, O <: Ordering[C]](implicit ord: O) = new Builder[Range[C, O], ImmutableRangeSetWrapper[C, O]]() { 70 | var builder = ImmutableRangeSet.builder[AsOrdered[C]]() 71 | override def +=(range: Range[C, O]): this.type = { 72 | builder.add(range.asJava) 73 | this 74 | } 75 | override def clear() = builder = ImmutableRangeSet.builder[AsOrdered[C]]() 76 | override def result() = new ImmutableRangeSetWrapper(builder.build) 77 | } 78 | } -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/collect/RangeSetFactoryTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect 24 | 25 | import scala.annotation.meta.beanGetter 26 | import scala.annotation.meta.beanSetter 27 | import scala.annotation.meta.field 28 | import scala.annotation.meta.getter 29 | import scala.annotation.meta.setter 30 | import scala.collection.mutable.Builder 31 | import scala.math.Ordering.Int 32 | 33 | import org.feijoas.mango.common.annotations.Beta 34 | import org.feijoas.mango.common.collect.immutable.ImmutableRangeSetWrapper 35 | import org.scalatest.FreeSpec 36 | import org.scalatest.Matchers.be 37 | import org.scalatest.Matchers.convertToAnyShouldWrapper 38 | 39 | /** Tests for [[RangeSetFactory]] 40 | * 41 | * @author Markus Schneider 42 | * @since 0.8 43 | */ 44 | class RangeSetFactoryTest extends FreeSpec { 45 | "RangeSetFactory" - { 46 | "should implement #empty" in { 47 | val rangeSet = DummyRangeSetFactory.empty[Int, Int.type] 48 | rangeSet.isEmpty should be(true) 49 | rangeSet.asRanges should be(Set()) 50 | } 51 | 52 | "should implement #apply(range1, ...)" - { 53 | "given (5,6) it should return a range set with {(5,6)}" in { 54 | val rangeSet = DummyRangeSetFactory(Range.open(5, 6)) 55 | rangeSet.asRanges should be(Set(Range.open(5, 6))) 56 | } 57 | "given (5,6) and [1,2] it should return a range set with {[1,2], (5,6)}" in { 58 | val rangeSet = DummyRangeSetFactory(Range.open(5, 6), Range.closed(1, 2)) 59 | rangeSet.asRanges should be(Set(Range.open(5, 6), Range.closed(1, 2))) 60 | } 61 | } 62 | "should implement #apply(otherRangeSet)" - { 63 | "given the range set contains (5,6) and [1,2]" - { 64 | val rangeSet = DummyRangeSetFactory(Range.open(5, 6), Range.closed(1, 2)) 65 | "#apply(otherRangeSet) should return a RangeSet with {[1,2], (5,6)}" in { 66 | val copy = DummyRangeSetFactory(rangeSet) 67 | copy should be(rangeSet) 68 | copy.asRanges should be(rangeSet.asRanges) 69 | } 70 | } 71 | "given the range set is empty" - { 72 | val rangeSet = DummyRangeSetFactory.empty[Int, Int.type] 73 | "#apply(otherRangeSet) should return an empty range set" in { 74 | val copy = DummyRangeSetFactory(rangeSet) 75 | copy should be(rangeSet) 76 | copy.asRanges should be(rangeSet.asRanges) 77 | copy.isEmpty should be(true) 78 | } 79 | } 80 | } 81 | } 82 | } 83 | 84 | private[mango] object DummyRangeSetFactory extends RangeSetFactory[RangeSet] { 85 | def newBuilder[C, O <: Ordering[C]](implicit ord: O): Builder[Range[C, O], RangeSet[C, O]] = ImmutableRangeSetWrapper.newBuilder[C, O] 86 | } -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/hash/FunnelTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.hash 24 | 25 | import org.feijoas.mango.common.annotations.Beta 26 | import org.feijoas.mango.common.hash.Funnel.{ asGuavaFunnel, asScalaFunnel, byteArrayFunnel, intFunnel, longFunnel, stringFunnel } 27 | import org.mockito.Mockito.verify 28 | import org.scalatest.{ FlatSpec, PrivateMethodTester } 29 | import org.scalatest.matchers._ 30 | import org.scalatest.mockito.MockitoSugar 31 | import org.scalatest.prop.GeneratorDrivenPropertyChecks 32 | import org.scalatest.Matchers._ 33 | 34 | import com.google.common.hash.{ Funnel => GuavaFunnel, Funnels => GuavaFunnels, PrimitiveSink } 35 | 36 | /** 37 | * Tests for [[Funnel]] 38 | * 39 | * @author Markus Schneider 40 | * @since 0.6 (copied from guava-libraries) 41 | */ 42 | class FunnelTest extends FlatSpec with PrivateMethodTester with MockitoSugar { 43 | 44 | it should "convert from Guava to Mango" in { 45 | val guava: GuavaFunnel[Integer] = GuavaFunnels.integerFunnel 46 | val mango: Funnel[Integer] = guava.asScala 47 | // enough if the compiler does not complain 48 | } 49 | 50 | it should "convert from Mango to Guava" in { 51 | val mango: Funnel[Int] = implicitly[Funnel[Int]] 52 | val guava: GuavaFunnel[Int] = mango.asJava 53 | // enough if the compiler does not complain 54 | } 55 | 56 | it should "not wrap a Guava Funnel twice" in { 57 | val guava: GuavaFunnel[Integer] = GuavaFunnels.integerFunnel 58 | val mango: Funnel[Integer] = guava.asScala 59 | mango.asJava should be theSameInstanceAs (guava) 60 | } 61 | 62 | it should "not wrap a Mango Funnel twice" in { 63 | val mango: Funnel[Int] = implicitly[Funnel[Int]] 64 | val guava: GuavaFunnel[Int] = mango.asJava 65 | guava.asScala should be theSameInstanceAs (mango) 66 | } 67 | 68 | it should "implement Funnel[Array[Byte]]" in { 69 | val primitiveSink = mock[PrimitiveSink] 70 | val funnel = implicitly[Funnel[Array[Byte]]] 71 | funnel.funnel(Array[Byte](4, 3, 2, 1), primitiveSink) 72 | verify(primitiveSink).putBytes(Array[Byte](4, 3, 2, 1)) 73 | } 74 | 75 | it should "implement Funnel[CharSequence]" in { 76 | val primitiveSink = mock[PrimitiveSink] 77 | val funnel = implicitly[Funnel[CharSequence]] 78 | funnel.funnel("test", primitiveSink) 79 | verify(primitiveSink).putUnencodedChars("test") 80 | } 81 | 82 | it should "implement Funnel[Int]" in { 83 | val primitiveSink = mock[PrimitiveSink] 84 | val funnel = implicitly[Funnel[Int]] 85 | funnel.funnel(1234, primitiveSink) 86 | verify(primitiveSink).putInt(1234) 87 | } 88 | 89 | it should "implement Funnel[Long]" in { 90 | val primitiveSink = mock[PrimitiveSink] 91 | val funnel = implicitly[Funnel[Long]] 92 | funnel.funnel(1234, primitiveSink) 93 | verify(primitiveSink).putLong(1234) 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/mutable/RangeMapLike.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect.mutable 24 | 25 | import org.feijoas.mango.common.annotations.Beta 26 | import org.feijoas.mango.common.collect 27 | import org.feijoas.mango.common.collect.Range 28 | import scala.collection.generic.Growable 29 | import scala.collection.generic.Shrinkable 30 | 31 | /** Implementation trait for mutable [[RangeMap]] 32 | * 33 | * $rangeMapNote 34 | * @author Markus Schneider 35 | * @since 0.9 36 | */ 37 | @Beta 38 | trait RangeMapLike[K, V, O <: Ordering[K], +Repr <: RangeMapLike[K, V, O, Repr] with RangeMap[K, V, O]] 39 | extends collect.RangeMapLike[K, V, O, Repr] 40 | with Growable[(Range[K, O], V)] 41 | with Shrinkable[Range[K, O]] { 42 | 43 | /** Maps a range to a specified value. 44 | * 45 | *

Specifically, after a call to `put(range, value)`, if 46 | * `range.contains(k)`, then `get(k)` 47 | * will return `value`. 48 | * 49 | *

If `range` is empty, then this is a no-op. 50 | */ 51 | def put(range: Range[K, O], value: V) 52 | 53 | /** Puts all the associations from `rangeMap` into this range map. 54 | */ 55 | def putAll(rangeMap: collect.RangeMap[K, V, O]) = rangeMap.asMapOfRanges foreach { case (range, value) => put(range, value) } 56 | 57 | /** Removes all associations from this range map. 58 | */ 59 | def clear() 60 | 61 | /** Removes all associations from this range map in the specified range. 62 | * 63 | *

If {@code !range.contains(k)}, `get(k)` will return the same result 64 | * before and after a call to {@code remove(range)}. If {@code range.contains(k)}, then 65 | * after a call to {@code remove(range)}, {@code get(k)} will return {@code None}. 66 | */ 67 | def remove(range: Range[K, O]) 68 | 69 | /** Returns a view of the part of this range map that intersects with `range`. 70 | * 71 | *

For example, if `rangeMap` had the entries 72 | * {@code [1, 5] => "foo", (6, 8) => "bar", (10, \u2025) => "baz"} 73 | * then `rangeMap.subRangeMap(Range.open(3, 12))` would return a range map 74 | * with the entries {@code (3, 5) => "foo", (6, 8) => "bar", (10, 12) => "baz"}. 75 | * 76 | *

The returned range map supports all optional operations that this range map supports. 77 | * 78 | *

The returned range map will throw an `IllegalArgumentException` on an attempt to 79 | * insert a range not enclosed by {@code range}. 80 | */ 81 | @throws(classOf[IllegalArgumentException]) 82 | override def subRangeMap(range: Range[K, O]): Repr 83 | 84 | /** Alias for `#put(range, value)` */ 85 | final override def +=(kv: (Range[K, O], V)): this.type = { 86 | put(kv._1, kv._2) 87 | this 88 | } 89 | 90 | /** Alias for `#remove(range)` */ 91 | final override def -=(range: Range[K, O]): this.type = { 92 | remove(range) 93 | this 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/cache/CacheWrapper.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.cache 24 | 25 | import scala.annotation.meta.{ beanGetter, beanSetter, field, getter, setter } 26 | import scala.collection.{ immutable, mutable } 27 | import scala.collection.concurrent 28 | import scala.collection.convert.WrapAsScala.mapAsScalaMap 29 | import scala.collection.convert.decorateAll.{ asJavaIterableConverter, mapAsScalaConcurrentMapConverter, mutableMapAsJavaMapConverter } 30 | 31 | import org.feijoas.mango.common.annotations.Beta 32 | import org.feijoas.mango.common.base.Functions.asCallableConverter 33 | import org.feijoas.mango.common.cache.CacheStats.asMangoCacheStatsConverter 34 | 35 | import com.google.common.cache.{ Cache => GuavaCache } 36 | 37 | /** An adapter that wraps a Guava-Cache in a Mango-Cache and forwards all 38 | * method calls to the underlying Guava-Cache. 39 | * 40 | * @author Markus Schneider 41 | * @since 0.7 42 | */ 43 | protected[mango] trait CacheWrapper[K, V] extends Cache[K, V] { 44 | 45 | /** Returns the backing Guava `Cache` delegate instance that methods are forwarded to. 46 | * Concrete subclasses override this method to supply the instance being decorated. 47 | */ 48 | protected def cache: GuavaCache[K, V] 49 | 50 | // forward all other methods to the Guava cache 51 | 52 | override def getIfPresent(key: K): Option[V] = Option(cache.getIfPresent(key)) 53 | override def getOrElseUpdate(key: K, loader: () => V): V = cache.get(key, loader.asJava) 54 | override def getAllPresent(keys: Traversable[K]): immutable.Map[K, V] = { 55 | val guavaMap = cache.getAllPresent(keys.toIterable.asJava) 56 | 57 | // TODO: The whole Guava map is copied to a new map. Since both maps are 58 | // immutable this can be replaced as soon as we have light-weight wrappers 59 | // around Guavas immutable collections 60 | import scala.collection.convert.WrapAsScala._ 61 | immutable.Map.empty ++ mapAsScalaMap(guavaMap) 62 | } 63 | 64 | override def put(key: K, value: V): Unit = cache.put(key, value) 65 | override def putAll(kvs: Traversable[(K, V)]): Unit = { 66 | val map = mutable.Map.empty ++= kvs 67 | cache.putAll(map.asJava) 68 | } 69 | override def invalidate(key: K): Unit = cache.invalidate(key) 70 | override def invalidateAll(keys: Traversable[K]): Unit = { 71 | cache.invalidateAll(keys.toIterable.asJava) 72 | } 73 | override def invalidateAll(): Unit = cache.invalidateAll() 74 | override def size(): Long = cache.size() 75 | override def stats(): CacheStats = cache.stats().asScala 76 | override def cleanUp(): Unit = cache.cleanUp() 77 | override def asMap(): concurrent.Map[K, V] = cache.asMap().asScala 78 | } 79 | 80 | private[mango] final object CacheWrapper { 81 | 82 | /** Factory method to create a `CacheWrapper[K, V]` from a Guava `Cache[K, V]` 83 | */ 84 | def apply[K, V](guavaCache: GuavaCache[K, V]) = new CacheWrapper[K, V] { 85 | override def cache = guavaCache 86 | } 87 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/base/Equivalence.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.base 24 | 25 | import org.feijoas.mango.common.base.Preconditions.checkNotNull 26 | import org.feijoas.mango.common.convert.AsJava 27 | import org.feijoas.mango.common.convert.AsScala 28 | 29 | import com.google.common.{ base => gcm } 30 | 31 | /** Utility functions to convert from Scala `Equiv[T]` to Guava `Equivalence[T]` and vice versa. 32 | * 33 | * Usage example for conversion between Guava and Mango: 34 | * {{{ 35 | * import org.feijoas.mango.common.base.Equivalence._ 36 | * 37 | * // convert a Guava Equivalence[T] to a Scala Equiv[T] 38 | * val guava: gcm.Equivalence[T] = ... 39 | * val mango: Equiv[T] = guava.asScala 40 | * 41 | * // convert a Scala Equiv[T] to a Guava Equivalence[T] 42 | * val mango: Equiv[T] = ... 43 | * val guava: gcm.Equivalence[T] = mango.asJava 44 | * }}} 45 | * 46 | * @author Markus Schneider 47 | * @since 0.10 48 | */ 49 | final object Equivalence { 50 | 51 | /** Adds an `asScala` method that wraps a Guava `Equivalence[T]` in 52 | * a Scala `Equiv[T]`. 53 | * 54 | * The returned Scala `Equiv[T]` forwards all calls 55 | * to the given Guava `Equivalence[T]`. 56 | * 57 | * @param equiv the Guava `Equivalence[T]` to wrap in a Scala `Equiv[T]` 58 | * @return An object with an `asScala` method that returns a Scala `Equiv[T]` 59 | * view of the argument 60 | */ 61 | implicit def asMangoEquiv[T](equiv: gcm.Equivalence[T]): AsScala[Equiv[T]] = new AsScala( 62 | equiv match { 63 | case AsGuavaEquiv(delegate) => delegate 64 | case _ => AsMangoEquiv(equiv) 65 | }) 66 | 67 | /** Adds an `asJava` method that wraps a Scala `Equiv[T]` in 68 | * a Guava `Equivalence[T]`. 69 | * 70 | * The returned Guava `Equivalence[T]` forwards all calls 71 | * to the given Scala `Equiv[T]`. 72 | * 73 | * @param equiv the Scala `Equiv[T]` to wrap in a Guava `Equivalence[T]` 74 | * @return An object with an `asJava` method that returns a Guava `Equivalence[T]` 75 | * view of the argument 76 | */ 77 | implicit def asGuavaEquiv[T](equiv: Equiv[T]): AsJava[gcm.Equivalence[T]] = new AsJava( 78 | equiv match { 79 | case AsMangoEquiv(delegate) => delegate 80 | case _ => AsGuavaEquiv(equiv) 81 | }) 82 | } 83 | 84 | /** Wraps a Guava `Equivalence` in a Scala `Equiv` 85 | */ 86 | @SerialVersionUID(1L) 87 | private[mango] case class AsMangoEquiv[T](equiv: gcm.Equivalence[T]) extends Equiv[T] with Serializable { 88 | checkNotNull(equiv) 89 | override def equiv(x: T, y: T): Boolean = equiv.equivalent(x, y) 90 | } 91 | 92 | /** Wraps a Scala `Equiv` in a Guava `Equivalence` 93 | */ 94 | @SerialVersionUID(1L) 95 | private[mango] case class AsGuavaEquiv[T](equiv: Equiv[T]) extends gcm.Equivalence[T] with Serializable { 96 | checkNotNull(equiv) 97 | override def doEquivalent(x: T, y: T): Boolean = equiv.equiv(x, y) 98 | override def doHash(t: T): Int = t.hashCode 99 | } -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/collect/RangeSetTraitTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect 24 | 25 | import scala.annotation.meta.beanGetter 26 | import scala.annotation.meta.beanSetter 27 | import scala.annotation.meta.field 28 | import scala.annotation.meta.getter 29 | import scala.annotation.meta.setter 30 | import scala.collection.convert.decorateAll.asScalaSetConverter 31 | import scala.collection.mutable.Builder 32 | import scala.math.Ordering.Int 33 | 34 | import org.feijoas.mango.common.annotations.Beta 35 | import org.feijoas.mango.common.collect.Range.asGuavaRangeConverter 36 | import org.scalatest.FreeSpec 37 | import org.scalatest.Matchers.be 38 | import org.scalatest.Matchers.convertToAnyShouldWrapper 39 | 40 | import com.google.common.collect.ImmutableRangeSet 41 | 42 | /** Tests for all default implementations in [[RangeSet]] 43 | * 44 | * @author Markus Schneider 45 | * @since 0.8 46 | */ 47 | class RangeSetTraitTest extends FreeSpec with RangeSetBehaviors { 48 | 49 | /** Returns a new builder for a range set. 50 | */ 51 | def newBuilder[C, O <: Ordering[C]](implicit ord: O) = new Builder[Range[C, O], DummyRangeSet[C, O]]() { 52 | var guavaBuilder = ImmutableRangeSet.builder[AsOrdered[C]]() 53 | override def +=(range: Range[C, O]): this.type = { 54 | guavaBuilder.add(range.asJava) 55 | this 56 | } 57 | override def clear() = guavaBuilder = ImmutableRangeSet.builder[AsOrdered[C]]() 58 | override def result() = new DummyRangeSet(guavaBuilder.build()) 59 | } 60 | 61 | "trait RangeSet" - { 62 | behave like rangeSet(newBuilder[Int, Int.type]) 63 | } 64 | 65 | "object RangeSet" - { 66 | "should return an empty RangeSet if #empty is called" in { 67 | val emptySet = RangeSet.empty[Int, Int.type] 68 | emptySet.isEmpty should be(true) 69 | } 70 | "should return a new RangeSet with all ranges supplied with #apply(Iterable)" in { 71 | val set = RangeSet.apply(Range.closed(4, 5)) 72 | set.isEmpty should be(false) 73 | set.asRanges should be(Set(Range.closed(4, 5))) 74 | } 75 | "should return a new builder if #newBuild is called" in { 76 | // just check if the compiler complains 77 | val builder: Builder[Range[Int, Int.type], RangeSet[Int, Int.type]] = RangeSet.newBuilder[Int, Int.type] 78 | } 79 | } 80 | } 81 | 82 | private[mango] class DummyRangeSet[C, O <: Ordering[C]] private[mango] (private val rset: ImmutableRangeSet[AsOrdered[C]])(implicit protected val ord: O) extends RangeSet[C, O] { 83 | 84 | override def span(): Option[Range[C, O]] = rset.isEmpty match { 85 | case true => None 86 | case false => Some(Range(rset.span)) 87 | } 88 | 89 | override def asRanges(): Set[Range[C, O]] = { 90 | Set.empty ++ rset.asRanges().asScala.view.map(Range[C, O](_)) 91 | } 92 | 93 | override def complement(): RangeSet[C, O] = new DummyRangeSet[C, O](rset.complement()) 94 | override def subRangeSet(view: Range[C, O]) = new DummyRangeSet[C, O](rset.subRangeSet(view.asJava)) 95 | override def newBuilder = throw new NotImplementedError 96 | } 97 | 98 | -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/base/FunctionsTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.base 24 | 25 | import java.util.concurrent.Callable 26 | 27 | import org.feijoas.mango.common.base.Functions._ 28 | import org.scalatest._ 29 | import org.scalatest.prop.PropertyChecks 30 | 31 | import com.google.common.base.{ Function => GuavaFunction } 32 | import com.google.common.testing.SerializableTester 33 | 34 | /** 35 | * Tests for [[Functions]] 36 | * 37 | * @author Markus Schneider 38 | * @since 0.7 39 | */ 40 | class FunctionsTest extends FlatSpec with Matchers with PropertyChecks { 41 | 42 | behavior of "implicits" 43 | 44 | it should "be variant" in { 45 | val cf: (C => A) = new GuavaFunction[B, B]() { 46 | override def apply(i: B) = null 47 | }.asScala 48 | } 49 | 50 | it should "map a Guava Function to a Scala Function" in { 51 | val cf: (Int => String) = SomeFunction.asScala 52 | forAll { (n: Int) => cf(n) should be(n.toString) } 53 | } 54 | 55 | it should "map a Scala Function to a Guava Function" in { 56 | val gf: GuavaFunction[Int, String] = { (i: Int) => i.toString }.asJava 57 | forAll { (n: Int) => gf(n) should be(n.toString) } 58 | } 59 | 60 | it should "not wrap Scala function twice" in { 61 | val cf = (i: Int) => i.toString 62 | val gf: GuavaFunction[Int, String] = cf.asJava 63 | 64 | val wrappedTwice: Int => String = gf.asScala 65 | wrappedTwice should be theSameInstanceAs cf 66 | } 67 | 68 | it should "not wrap Guava function twice" in { 69 | val gf = SomeFunction 70 | val cf: Int => String = gf.asScala 71 | 72 | val wrappedTwice: GuavaFunction[Int, String] = cf.asJava 73 | wrappedTwice should be theSameInstanceAs gf 74 | } 75 | 76 | it should "be serializeable" in { 77 | val gf1 = SomeFunction 78 | val cf1: Int => String = gf1.asScala 79 | SerializableTester.reserialize(cf1) 80 | 81 | val cf2 = (i: Int) => i.toString 82 | val gf2: GuavaFunction[Int, String] = cf2.asJava 83 | SerializableTester.reserialize(gf2) 84 | } 85 | 86 | behavior of "Callable[T] conversion" 87 | 88 | it should "wrap a function in a Callable[T]" in { 89 | import java.util.concurrent.Callable 90 | import org.feijoas.mango.common.base.Functions._ 91 | 92 | forAll { (n: Int) => 93 | val callable: Callable[Int] = { () => n }.asJava 94 | callable.call() should be(n) 95 | } 96 | } 97 | 98 | behavior of "Runnable conversion" 99 | 100 | it should "wrap a function in a Runnable" in { 101 | import org.feijoas.mango.common.base.Functions._ 102 | 103 | forAll { (n: Int) => 104 | var result = 0 // the runnable will write this variable 105 | 106 | val runnable: Runnable = { () => { result = n; } }.asJava 107 | 108 | // run and check result 109 | runnable.run() 110 | result should be(n) 111 | } 112 | } 113 | 114 | } 115 | 116 | private case object SomeFunction extends GuavaFunction[Int, String] { 117 | override def apply(i: Int) = i.toString 118 | } 119 | 120 | private trait A 121 | private trait B extends A 122 | private trait C extends B 123 | -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/test/collect/Ranges.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.test.collect 24 | 25 | import scala.math.Ordering.Int 26 | 27 | import org.feijoas.mango.common.collect.BoundType.Closed 28 | import org.feijoas.mango.common.collect.BoundType.Open 29 | import org.feijoas.mango.common.collect.Range 30 | import org.scalacheck.Arbitrary 31 | import org.scalacheck.Arbitrary.arbitrary 32 | import org.scalacheck.Gen.oneOf 33 | 34 | /** Scalacheck generators and utilities 35 | * 36 | * @author Markus Schneider 37 | * @since 0.9 38 | */ 39 | object Ranges { 40 | 41 | val minBound = 0 42 | val maxBound = 10 43 | 44 | /** A list of various ranges 45 | */ 46 | private lazy val ranges = { 47 | val builder = List.newBuilder[Range[Int, Int.type]] 48 | // Add one-ended ranges 49 | for ( 50 | i <- minBound to maxBound; 51 | boundType <- List(Open, Closed) 52 | ) { 53 | builder += Range.upTo(i, boundType) 54 | builder += Range.downTo(i, boundType) 55 | } 56 | 57 | // Add two-ended ranges 58 | for ( 59 | i <- minBound to maxBound; 60 | j <- (i + 1) to maxBound; 61 | lowerType <- List(Open, Closed); 62 | upperType <- List(Open, Closed) if (!(i == j & lowerType == Open & upperType == Open)) 63 | ) { 64 | builder += Range.range(i, lowerType, j, upperType) 65 | } 66 | builder.result 67 | } 68 | 69 | /** A list of pairs of ranges that are not overlaping 70 | */ 71 | private lazy val rangeTuples = for ( 72 | range1 <- ranges; 73 | range2 <- ranges if (!range1.isConnected(range2) || range1.intersection(range2).isEmpty()) 74 | ) yield (range1, range2) 75 | 76 | implicit lazy val arbRange: Arbitrary[Range[Int, Int.type]] = Arbitrary { 77 | oneOf(ranges) 78 | } 79 | 80 | implicit lazy val arbNonOverlappingRangeParis: Arbitrary[(Range[Int, Int.type], Range[Int, Int.type])] = Arbitrary { 81 | oneOf(rangeTuples) 82 | } 83 | 84 | implicit lazy val genOpenRange = for { 85 | lower <- arbitrary[Int] 86 | upper <- arbitrary[Int] 87 | if (lower < upper) 88 | } yield Range.open(lower, upper) 89 | 90 | implicit lazy val genClosedRange = for { 91 | lower <- arbitrary[Int] 92 | upper <- arbitrary[Int] 93 | if (lower <= upper) 94 | } yield Range.closed(lower, upper) 95 | 96 | implicit lazy val genOpenClosedRange = for { 97 | lower <- arbitrary[Int] 98 | upper <- arbitrary[Int] 99 | if (lower < upper) 100 | } yield Range.openClosed(lower, upper) 101 | 102 | implicit lazy val genClosedOpenRange = for { 103 | lower <- arbitrary[Int] 104 | upper <- arbitrary[Int] 105 | if (lower < upper) 106 | } yield Range.closedOpen(lower, upper) 107 | 108 | implicit lazy val genAtLeastRange = for { 109 | endpoint <- arbitrary[Int] 110 | } yield Range.atLeast(endpoint) 111 | 112 | implicit lazy val genAtMostRange = for { 113 | endpoint <- arbitrary[Int] 114 | } yield Range.atMost(endpoint) 115 | 116 | implicit lazy val genLessThanRange = for { 117 | endpoint <- arbitrary[Int] 118 | } yield Range.lessThan(endpoint) 119 | 120 | implicit lazy val genGreaterThanRange = for { 121 | endpoint <- arbitrary[Int] 122 | } yield Range.greaterThan(endpoint) 123 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/mutable/RangeSetLike.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect.mutable 24 | 25 | import scala.collection.generic.Growable 26 | import scala.collection.generic.Shrinkable 27 | 28 | import org.feijoas.mango.common.annotations.Beta 29 | import org.feijoas.mango.common.collect.Range 30 | import org.feijoas.mango.common.collect 31 | 32 | /** Implementation trait for mutable [[RangeSet]] 33 | * 34 | * $rangeSetNote 35 | * @author Markus Schneider 36 | * @since 0.8 37 | */ 38 | @Beta 39 | trait RangeSetLike[C, O <: Ordering[C], +Repr <: RangeSetLike[C, O, Repr] with RangeSet[C, O]] 40 | extends collect.RangeSetLike[C, O, Repr] 41 | with Growable[Range[C, O]] 42 | with Shrinkable[Range[C, O]] { 43 | 44 | /** Adds the specified range to this {@code RangeSet} (optional operation). That is, for equal 45 | * range sets a and b, the result of {@code a.add(range)} is that {@code a} will be the minimal 46 | * range set for which both {@code a.enclosesAll(b)} and {@code a.encloses(range)}. 47 | * 48 | *

Note that {@code range} will be {@linkplain Range#span(Range) coalesced} with any ranges in 49 | * the range set that are {@linkplain Range#isConnected(Range) connected} with it. Moreover, 50 | * if {@code range} is empty, this is a no-op. 51 | */ 52 | def add(range: Range[C, O]) 53 | 54 | /** Alias for `#add(range)` */ 55 | final override def +=(range: Range[C, O]): this.type = { 56 | add(range) 57 | this 58 | } 59 | 60 | /** Removes the specified range from this {@code RangeSet} (optional operation). After this 61 | * operation, if {@code range.contains(c)}, {@code this.contains(c)} will return {@code false}. 62 | * 63 | *

If {@code range} is empty, this is a no-op. 64 | */ 65 | def remove(range: Range[C, O]) 66 | 67 | /** Alias for `#remove(range)` */ 68 | final override def -=(range: Range[C, O]): this.type = { 69 | remove(range) 70 | this 71 | } 72 | 73 | /** Removes all ranges from this {@code RangeSet} (optional operation). After this operation, 74 | * {@code this.contains(c)} will return false for all {@code c}. 75 | * 76 | *

This is equivalent to {@code remove(Range.all())}. 77 | */ 78 | def clear() 79 | 80 | /** Adds all of the ranges from the specified range set to this range set (optional operation). 81 | * After this operation, this range set is the minimal range set that 82 | * {@linkplain #enclosesAll(RangeSet) encloses} both the original range set and {@code other}. 83 | * 84 | *

This is equivalent to calling {@link #add} on each of the ranges in {@code other} in turn. 85 | * 86 | * @throws UnsupportedOperationException if this range set does not support the {@code addAll} 87 | * operation 88 | */ 89 | def addAll(other: RangeSet[C, O]) = other.asRanges() foreach { range => add(range) } 90 | 91 | /** Removes all of the ranges from the specified range set from this range set (optional 92 | * operation). After this operation, if {@code other.contains(c)}, {@code this.contains(c)} will 93 | * return {@code false}. 94 | * 95 | *

This is equivalent to calling {@link #remove} on each of the ranges in {@code other} in 96 | * turn. 97 | */ 98 | def removeAll(other: RangeSet[C, O]) = other.asRanges() foreach { range => remove(range) } 99 | } 100 | -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/collect/TreeTraverserTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect 24 | 25 | import scala.math.Ordering.Int 26 | import org.feijoas.mango.common.annotations.Beta 27 | import org.feijoas.mango.common.collect.Bound.FiniteBound 28 | import org.feijoas.mango.common.collect.Bound.InfiniteBound 29 | import org.feijoas.mango.common.collect.DiscreteDomain.IntDomain 30 | import org.scalatest.FlatSpec 31 | import org.scalatest.Matchers.be 32 | import org.scalatest.Matchers.convertToAnyShouldWrapper 33 | import org.scalatest.prop.PropertyChecks 34 | import com.google.common.testing.SerializableTester.reserializeAndAssert 35 | import org.scalatest._ 36 | import org.scalatest.FunSpec 37 | 38 | /** 39 | * Tests for [[TreeTraverser]] 40 | * 41 | * @author Markus Schneider 42 | * @since 0.11 (copied from guava-libraries) 43 | */ 44 | class TreeTraverserTest extends FunSpec with Matchers { 45 | case class Tree(value: Char, children: Tree*) 46 | case class BinaryTree(value: Char, left: BinaryTree, right: BinaryTree) 47 | 48 | val traverser = TreeTraverser((node: Tree) => node.children) 49 | val binTraverser = BinaryTreeTraverser((node: BinaryTree) => (Option(node.left), Option(node.right))) 50 | 51 | // h 52 | // / | \ 53 | // / e \ 54 | // d g 55 | // /|\ | 56 | // / | \ f 57 | // a b c 58 | val a_ = Tree('a') 59 | val b_ = Tree('b') 60 | val c_ = Tree('c') 61 | val d_ = Tree('d', a_, b_, c_) 62 | val e_ = Tree('e') 63 | val f_ = Tree('f') 64 | val g_ = Tree('g', f_) 65 | val h_ = Tree('h', d_, e_, g_) 66 | 67 | // d 68 | // / \ 69 | // b e 70 | // / \ \ 71 | // a c f 72 | // / 73 | // g 74 | val ba_ = BinaryTree('a', null, null) 75 | val bc_ = BinaryTree('c', null, null) 76 | val bb_ = BinaryTree('b', ba_, bc_) 77 | val bg_ = BinaryTree('g', null, null) 78 | val bf_ = BinaryTree('f', bg_, null) 79 | val be_ = BinaryTree('e', null, bf_) 80 | val bd_ = BinaryTree('d', bb_, be_) 81 | 82 | def treeAsString(tree: Iterable[Tree]): String = tree.foldLeft(""){ case (str, tree) => str + tree.value } 83 | def bTreeAsString(tree: Iterable[BinaryTree]): String = tree.foldLeft(""){ case (str, tree) => str + tree.value } 84 | 85 | describe("A TreeTraverser") { 86 | it("should be able traverse the tree in preOrder") { 87 | treeAsString(traverser.preOrderTraversal(h_)) should be("hdabcegf") 88 | } 89 | it("should be able traverse the tree in postOrder") { 90 | treeAsString(traverser.postOrderTraversal(h_)) should be("abcdefgh") 91 | } 92 | it("should be able traverse the tree in breadthFirstOrder") { 93 | treeAsString(traverser.breadthFirstTraversal(h_)) should be("hdegabcf") 94 | } 95 | } 96 | 97 | describe("A BinaryTreeTraverser") { 98 | it("should be able traverse the tree in preOrder") { 99 | bTreeAsString(binTraverser.preOrderTraversal(bd_)) should be("dbacefg") 100 | } 101 | it("should be able traverse the tree in postOrder") { 102 | bTreeAsString(binTraverser.postOrderTraversal(bd_)) should be("acbgfed") 103 | } 104 | it("should be able traverse the tree in breadthFirstOrder") { 105 | bTreeAsString(binTraverser.breadthFirstTraversal(bd_)) should be("dbeacfg") 106 | } 107 | it("should be able traverse the tree in order") { 108 | bTreeAsString(binTraverser.inOrderTraversal(bd_)) should be("abcdegf") 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/cache/CacheStatsTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.cache 24 | 25 | import org.feijoas.mango.common.cache.CacheStats._ 26 | import org.scalacheck.Gen 27 | import org.scalatest._ 28 | import org.scalatest.prop.GeneratorDrivenPropertyChecks 29 | 30 | import com.google.common.cache.{ CacheStats => GuavaCacheStats } 31 | 32 | /** 33 | * Tests for [[CacheStats]] 34 | * 35 | * @author Markus Schneider 36 | * @since 0.7 37 | */ 38 | class CacheStatsTest extends FlatSpec with GeneratorDrivenPropertyChecks with Matchers { 39 | 40 | behavior of "CacheStats" 41 | 42 | // a non-negative generator 43 | val nonNegGen: Gen[Long] = Gen.frequency( 44 | 1 -> 0, 45 | 2 -> Gen.choose(0, Long.MaxValue / 2)) 46 | 47 | // a CacheStats generator 48 | val cacheStatsGen: Gen[GuavaCacheStats] = for { 49 | a <- nonNegGen 50 | b <- nonNegGen 51 | c <- nonNegGen 52 | d <- nonNegGen 53 | e <- nonNegGen 54 | f <- nonNegGen 55 | } yield new GuavaCacheStats(a, b, c, d, e, f) 56 | 57 | it should "have the same members and function values as Guava-CacheStats" in { 58 | 59 | forAll(cacheStatsGen) { (guava: GuavaCacheStats) => 60 | val mango: CacheStats = guava.asScala 61 | 62 | // check members 63 | mango.hitCount should be(guava.hitCount()) 64 | mango.loadCount should be(guava.loadCount()) 65 | mango.missCount should be(guava.missCount()) 66 | mango.loadExceptionCount should be(guava.loadExceptionCount()) 67 | mango.loadSuccessCount should be(guava.loadSuccessCount()) 68 | mango.evictionCount should be(guava.evictionCount()) 69 | 70 | // check methods 71 | mango.hitRate should be(guava.hitRate()) 72 | mango.loadExceptionRate should be(guava.loadExceptionRate()) 73 | mango.missRate should be(guava.missRate()) 74 | mango.totalLoadTime should be(guava.totalLoadTime()) 75 | mango.requestCount should be(guava.requestCount()) 76 | mango.averageLoadPenalty should be(guava.averageLoadPenalty()) 77 | } 78 | } 79 | 80 | it should "be able to add values" in { 81 | forAll(cacheStatsGen, cacheStatsGen) { 82 | (guavaA: GuavaCacheStats, guavaB: GuavaCacheStats) => 83 | val mangoA: CacheStats = guavaA.asScala 84 | val mangoB: CacheStats = guavaB.asScala 85 | 86 | // if the first test passes we can safely convert a Guava-CacheStats 87 | // to a mango implementation 88 | (mangoA + mangoB) should be(guavaA.plus(guavaB).asScala) 89 | } 90 | } 91 | 92 | it should "be able to subtract values" in { 93 | forAll(cacheStatsGen, cacheStatsGen) { 94 | (guavaA: GuavaCacheStats, guavaB: GuavaCacheStats) => 95 | val mangoA: CacheStats = guavaA.asScala 96 | val mangoB: CacheStats = guavaB.asScala 97 | 98 | // if the first test passes we can safely convert a Guava-CacheStats 99 | // to a mango implementation 100 | (mangoA - mangoB) should be(guavaA.minus(guavaB).asScala) 101 | } 102 | } 103 | 104 | it should "throw an exception if negative values are passed in constructor" in { 105 | // 0 is allowed 106 | CacheStats(0, 0, 0, 0, 0, 0) 107 | 108 | // neg. values not 109 | intercept[IllegalArgumentException] { CacheStats(-1, 0, 0, 0, 0, 0) } 110 | intercept[IllegalArgumentException] { CacheStats(0, -1, 0, 0, 0, 0) } 111 | intercept[IllegalArgumentException] { CacheStats(0, 0, -1, 0, 0, 0) } 112 | intercept[IllegalArgumentException] { CacheStats(0, 0, 0, -1, 0, 0) } 113 | intercept[IllegalArgumentException] { CacheStats(0, 0, 0, 0, -1, 0) } 114 | intercept[IllegalArgumentException] { CacheStats(0, 0, 0, 0, 0, -1) } 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/cache/CacheWrapperTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.cache 24 | 25 | import org.feijoas.mango.common.annotations.Beta 26 | import org.feijoas.mango.common.cache.Cache._ 27 | import org.scalatest._ 28 | import org.scalatest.mockito.MockitoSugar 29 | import org.junit.Assert._ 30 | import com.google.common.cache.{ Cache => GuavaCache } 31 | 32 | /** 33 | * Tests for [[CacheWrapper]] 34 | * 35 | * @author Markus Schneider 36 | * @since 0.7 37 | */ 38 | class CacheWrapperTest extends FlatSpec with CacheWrapperBehaviour with Matchers with MockitoSugar with CacheStatsMatcher { 39 | 40 | def wrappedCacheFixture = { 41 | val wrapped = mock[GuavaCache[String, Int]] 42 | val cache: Cache[String, Int] = wrapped.asScala 43 | (wrapped, cache) 44 | } 45 | 46 | behavior of "CacheWrapper" 47 | 48 | "LoadingCacheWrapper" should behave like forwardingWrapper(wrappedCacheFixture) 49 | 50 | it should "implement getIfPresent" in { 51 | 52 | val cache = CacheBuilder().recordStats.build[Any, Any] 53 | cache.stats should be(CacheStats(0, 0, 0, 0, 0, 0)) 54 | 55 | val one = new Object() 56 | val two = new Object() 57 | 58 | cache getIfPresent (one) should be(None) 59 | cache.stats should have(missCount(1), loadSuccessCount(0), loadExceptionCount(0), hitCount(0)) 60 | cache.asMap.get(one) should be(None) 61 | cache.asMap.contains(one) should be(false) 62 | cache.asMap.values.toSet.contains(two) should be(false) 63 | 64 | cache getIfPresent (two) should be(None) 65 | cache.stats should have(missCount(2), loadSuccessCount(0), loadExceptionCount(0), hitCount(0)) 66 | cache.asMap.get(one) should be(None) 67 | cache.asMap.contains(one) should be(false) 68 | cache.asMap.values.toSet.contains(two) should be(false) 69 | 70 | cache.put(one, two) 71 | assertSame(cache.getIfPresent(one).get, two) 72 | cache.stats should have(missCount(2), loadSuccessCount(0), loadExceptionCount(0), hitCount(1)) 73 | assertSame(cache.asMap.get(one).get, two) 74 | cache.asMap.contains(one) should be(true) 75 | cache.asMap.values.toSet.contains(two) should be(true) 76 | 77 | cache getIfPresent (two) should be(None) 78 | cache.stats should have(missCount(3), loadSuccessCount(0), loadExceptionCount(0), hitCount(1)) 79 | cache.asMap.get(two) should be(None) 80 | cache.asMap.contains(two) should be(false) 81 | cache.asMap.values.toSet.contains(one) should be(false) 82 | 83 | cache.put(two, one) 84 | assertSame(cache.getIfPresent(two).get, one) 85 | cache.stats should have(missCount(3), loadSuccessCount(0), loadExceptionCount(0), hitCount(2)) 86 | assertSame(cache.asMap.get(two).get, one) 87 | cache.asMap.contains(two) should be(true) 88 | cache.asMap.values.toSet.contains(one) should be(true) 89 | } 90 | 91 | it should "implement getAllPresent" in { 92 | val cache = CacheBuilder().recordStats.build[Any, Any] 93 | cache.stats should be(CacheStats(0, 0, 0, 0, 0, 0)) 94 | 95 | cache.getAllPresent(List()) should be(Map()) 96 | cache.stats should be(CacheStats(0, 0, 0, 0, 0, 0)) 97 | 98 | cache.getAllPresent(List(1, 2, 3)) should be(Map()) 99 | cache.stats should have(missCount(3), loadSuccessCount(0), loadExceptionCount(0), hitCount(0)) 100 | 101 | cache.put(2, 22) 102 | cache.getAllPresent(List(1, 2, 3)) should be(Map(2 -> 22)) 103 | cache.stats should have(missCount(5), loadSuccessCount(0), loadExceptionCount(0), hitCount(1)) 104 | 105 | cache.put(3, 33) 106 | cache.getAllPresent(List(1, 2, 3)) should be(Map(2 -> 22, 3 -> 33)) 107 | cache.stats should have(missCount(6), loadSuccessCount(0), loadExceptionCount(0), hitCount(3)) 108 | 109 | cache.put(1, 11) 110 | cache.getAllPresent(List(1, 2, 3)) should be(Map(1 -> 11, 2 -> 22, 3 -> 33)) 111 | cache.stats should have(missCount(6), loadSuccessCount(0), loadExceptionCount(0), hitCount(6)) 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/cache/RemovalCause.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.cache 24 | 25 | import org.feijoas.mango.common.annotations.Beta 26 | import org.feijoas.mango.common.convert.{ AsJava, AsScala } 27 | 28 | import com.google.common.cache.{ RemovalCause => GuavaRemovalCause } 29 | 30 | /** The reason why a cached entry was removed. See the companion object for 31 | * the individual RemovalCause cases. 32 | * 33 | * @author Markus Schneider 34 | * @since 0.7 (copied from guava-libraries) 35 | */ 36 | @Beta 37 | sealed trait RemovalCause extends Serializable { 38 | /** Returns {@code true} if there was an automatic removal due to eviction 39 | * (the cause is neither [[RemovalCause.Explicit]] nor [[RemovalCause.Replaced]] ). 40 | */ 41 | def wasEvicted: Boolean 42 | } 43 | 44 | /** Available RemovalCauses 45 | */ 46 | final object RemovalCause { 47 | 48 | /** The entry was manually removed by the user. This can result from the user invoking 49 | * `Cache#invalidate, `Cache#invalidateAll(Traversable)` or `Cache#invalidateAll()` 50 | */ 51 | case object Explicit extends RemovalCause { 52 | def wasEvicted = false 53 | } 54 | 55 | /** The entry itself was not actually removed, but its value was replaced by the user. This can 56 | * result from the user invoking `Cache#put` or `LoadingCache#refresh` 57 | */ 58 | case object Replaced extends RemovalCause { 59 | def wasEvicted = false 60 | } 61 | 62 | /** The entry was removed automatically because its key or value was garbage-collected. This 63 | * can occur when using `CacheBuilder#weakKeys`, `CacheBuilder#weakValues`, or 64 | * `CacheBuilder#softValues`. 65 | */ 66 | case object Collected extends RemovalCause { 67 | def wasEvicted = false 68 | } 69 | 70 | /** The entry's expiration timestamp has passed. This can occur when using 71 | * `CacheBuilder#expireAfterWrite` or `CacheBuilder#expireAfterAccess`. 72 | */ 73 | case object Expired extends RemovalCause { 74 | def wasEvicted = false 75 | } 76 | 77 | /** The entry was evicted due to size constraints. This can occur when using 78 | * `CacheBuilder#maximumSize` or `CacheBuilder#maximumWeight`. 79 | */ 80 | case object Size extends RemovalCause { 81 | def wasEvicted = false 82 | } 83 | 84 | /** Adds an `asJava` method that converts a Mango `RemovalCause` to a 85 | * Guava `RemovalCause`. 86 | * 87 | * The returned Guava `RemovalCause` contains a copy of all values in the 88 | * Mango `RemovalCause`. 89 | * 90 | * @param cause the Mango `RemovalCause` to convert to a Guava `RemovalCause` 91 | * @return An object with an `asJava` method that returns a Guava `RemovalCause` 92 | * view of the argument 93 | */ 94 | implicit final def asGuavaRemovalCauseConverter(cause: RemovalCause): AsJava[GuavaRemovalCause] = new AsJava( 95 | cause match { 96 | case RemovalCause.Explicit => GuavaRemovalCause.EXPLICIT 97 | case RemovalCause.Replaced => GuavaRemovalCause.REPLACED 98 | case RemovalCause.Collected => GuavaRemovalCause.COLLECTED 99 | case RemovalCause.Expired => GuavaRemovalCause.EXPIRED 100 | case RemovalCause.Size => GuavaRemovalCause.SIZE 101 | }) 102 | 103 | /** Adds an `asScala` method that converts a Guava `RemovalCause` to a 104 | * Mango `RemovalCause`. 105 | * 106 | * The returned Mango `RemovalCause` contains a copy of all values in the 107 | * Guava `RemovalCause`. 108 | * 109 | * @param cause the Guava `RemovalCause` to convert to a Mango `RemovalCause` 110 | * @return An object with an `asScala` method that returns a Mango `RemovalCause` 111 | * view of the argument 112 | */ 113 | implicit final def asMangoRemovalCauseConverter(cause: GuavaRemovalCause): AsScala[RemovalCause] = new AsScala( 114 | cause match { 115 | case GuavaRemovalCause.EXPLICIT => Explicit 116 | case GuavaRemovalCause.REPLACED => Replaced 117 | case GuavaRemovalCause.COLLECTED => Collected 118 | case GuavaRemovalCause.EXPIRED => Expired 119 | case GuavaRemovalCause.SIZE => Size 120 | }) 121 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/base/Functions.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.base 24 | 25 | import java.util.concurrent.Callable 26 | 27 | import org.feijoas.mango.common.base.Preconditions.checkNotNull 28 | import org.feijoas.mango.common.convert.{ AsJava, AsScala } 29 | 30 | import com.google.common.base.{ Function => GuavaFunction } 31 | 32 | /** Utility functions for the work with Guava `Function[T, R]` 33 | * 34 | * Usage example for conversion between Guava and Mango: 35 | * {{{ 36 | * // convert a Guava function to a Scala function 37 | * val fnc: Function[T, R] = { (arg: T) => ... }.asJava 38 | * 39 | * // convert a Scala function to a Guava function 40 | * val fnc: (T => R) = SomeGuavaFunction.asScala 41 | * 42 | * // convert a Scala function to a Callable 43 | * val callable: Callable[R] = { () => n }.asJava 44 | * 45 | * // convert a Scala functio to a Runnable 46 | * val runnable: Runnable = { () => ... }.asJava 47 | * }}} 48 | * 49 | * @author Markus Schneider 50 | * @since 0.7 51 | */ 52 | final object Functions { 53 | 54 | /** Adds an `asScala` method that wraps a Guava `Function[T, R]` in 55 | * a Scala function `T => R`. 56 | * 57 | * All calls to the Scala function are forwarded to the provided Guava function. 58 | * @param fnc the Guava `Function[T, R]` to wrap in a Scala funcion `T => R` 59 | * @return An object with an `asScala` method that returns a Scala 60 | * `T => R` view of the argument. 61 | */ 62 | implicit def asMangoFunctionConverter[T, R](fnc: GuavaFunction[T, R]): AsScala[T => R] = { 63 | def convert(fnc: GuavaFunction[T, R]): (T => R) = fnc match { 64 | case gf: AsGuavaFunction[T, R] => gf.delegate 65 | case _ => AsMangoFunction(fnc) 66 | } 67 | new AsScala(convert(fnc)) 68 | } 69 | 70 | /** Adds an `asJava` method that wraps a Scala function `T => R` in 71 | * a Guava `Function[T, R]`. 72 | * 73 | * All calls to the Guava function are forwarded to the provided Scala function. 74 | * @param fnc the Scala function `T => R` to wrap in a Guava `Function[T, R]` 75 | * @return An object with an `asJava` method that returns a Guava `Function[T, R]` 76 | * view of the argument. 77 | */ 78 | implicit def asGuavaFunctionConverter[T, R](fnc: T => R): AsJava[GuavaFunction[T, R]] = { 79 | def convert(fnc: T => R) = fnc match { 80 | case cf: AsMangoFunction[T, R] => cf.delegate 81 | case _ => AsGuavaFunction(fnc) 82 | } 83 | new AsJava(convert(fnc)) 84 | } 85 | 86 | /** Adds an `asJava` method that wraps a Scala function `() => Unit` in 87 | * a Java `Runnable`. 88 | * 89 | * All calls to the `Runnable` are forwarded to the provided Scala function. 90 | * @param fnc the Scala function `() => Unit` to wrap in a Java `Runnable` 91 | * @return An object with an `asJava` method that returns a Java `Runnable` 92 | * view of the argument. 93 | */ 94 | implicit def asRunnableConverter(fnc: () => Unit): AsJava[Runnable] = new AsJava( 95 | new Runnable() { 96 | override def run() = fnc() 97 | }) 98 | 99 | /** Adds an `asJava` method that wraps a Scala function `() => R` in 100 | * a Java `Callable`. 101 | * 102 | * All calls to the `Callable` are forwarded to the provided Scala function. 103 | * @param fnc the Scala function `() => R` to wrap in a Java `Callable` 104 | * @return An object with an `asJava` method that returns a Java `Callable` 105 | * view of the argument. 106 | */ 107 | implicit def asCallableConverter[R](fnc: () => R): AsJava[Callable[R]] = new AsJava( 108 | new Callable[R]() { 109 | def call() = fnc() 110 | }) 111 | } 112 | 113 | /** Wraps a Guava `Function` in a Scala function */ 114 | @SerialVersionUID(1L) 115 | private[mango] case class AsMangoFunction[R, T](delegate: GuavaFunction[R, T]) extends Function1[R, T] with Serializable { 116 | checkNotNull(delegate) 117 | override def apply(input: R) = delegate.apply(input) 118 | } 119 | 120 | /** Wraps a Scala function in a Guava `Function` */ 121 | @SerialVersionUID(1L) 122 | private[mango] case class AsGuavaFunction[T, R](delegate: R => T) extends GuavaFunction[R, T] with Serializable { 123 | checkNotNull(delegate) 124 | override def apply(input: R) = delegate(input) 125 | } -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/RangeMapLike.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect 24 | 25 | import scala.collection.generic.HasNewBuilder 26 | 27 | import org.feijoas.mango.common.annotations.Beta 28 | 29 | /** Implementation trait for [[RangeMap]] 30 | * 31 | * $rangeMapNote 32 | * @author Markus Schneider 33 | * @since 0.9 34 | * 35 | * @define rangeMapNote 36 | * 37 | * A mapping from disjoint nonempty ranges to non-null values. Queries look up the value 38 | * associated with the range (if any) that contains a specified key. 39 | * 40 | *

In contrast to [[RangeSet]], no "coalescing" is done of connected ranges, even 41 | * if they are mapped to the same value. 42 | * 43 | * Usage example: 44 | * 45 | * {{{ 46 | * import org.feijoas.mango.common.collect.mutable 47 | * import org.feijoas.mango.common.collect.Range 48 | * import math.Ordering.Int 49 | * 50 | * // mutable range map 51 | * val rangeMap = mutable.RangeMap(Range.open(3, 7) -> "1") //Map((3..7) -> 1) 52 | * rangeMap += Range.closed(9, 10) -> "2" // Map((3..7) -> 1, [9..10] -> 2) 53 | * rangeMap += Range.closed(12, 16) -> "3" // Map((3..7) -> 1, [9..10] -> 2, [12..16] -> 3) 54 | * 55 | * val sub = rangeMap.subRangeMap(Range.closed(5, 11)) // Map([5..7) -> 1, [9..10] -> 2) 56 | * sub.put(Range.closed(7, 9), "4") // sub = Map([5..7) -> 1, [7..9] -> 4, (9..10] -> 2) 57 | * 58 | * // rangeMap = Map((3..7) -> 1, [7..9] -> 4, (9..10] -> 2, [12..16] -> 3) 59 | * }}} 60 | * 61 | * @tparam K the type of the keys of the map 62 | * @tparam V the type of the elements of the map 63 | * @tparam O the type of Ordering used to order the elements 64 | * @tparam Repr the type of the map itself. 65 | */ 66 | @Beta 67 | trait RangeMapLike[K, V, O <: Ordering[K], +Repr <: RangeMapLike[K, V, O, Repr] with RangeMap[K, V, O]] 68 | extends HasNewBuilder[(Range[K, O], V), Repr] { 69 | self => 70 | 71 | /** Returns the value associated with the specified key in a `Some`, or `None` if there is no 72 | * such value. 73 | * 74 | *

Specifically, if any range in this range map contains the specified key, the value 75 | * associated with that range is returned. 76 | */ 77 | def get(key: K): Option[V] 78 | 79 | /** Returns the range containing this key and its associated value in a `Some`, if such a range is present 80 | * in the range map, or `None` otherwise. 81 | */ 82 | def getEntry(key: K): Option[(Range[K, O], V)] 83 | 84 | /** Returns the minimal range enclosing the ranges in this `RangeMap` in a `Some` 85 | * or `None` if this range map is empty 86 | */ 87 | def span(): Option[Range[K, O]] 88 | 89 | /** Returns this RangeMap as a map of ranges. 90 | * 91 | * Warning: This differs from Guava which returns an unmodifiable view 92 | * of this RangeMap which modifications to its range map are guaranteed 93 | * to read through to the returned map. 94 | * 95 | *

It is guaranteed that no empty ranges will be in the returned `Map`. 96 | */ 97 | def asMapOfRanges(): Map[Range[K, O], V] 98 | 99 | /** Returns a view of the part of this range map that intersects with `range`. 100 | * 101 | *

For example, if `rangeMap` had the entries 102 | * {@code [1, 5] => "foo", (6, 8) => "bar", (10, \u2025) => "baz"} 103 | * then `rangeMap.subRangeMap(Range.open(3, 12))` would return a range map 104 | * with the entries {@code (3, 5) => "foo", (6, 8) => "bar", (10, 12) => "baz"}. 105 | * 106 | *

The returned range map supports all optional operations that this range map supports. 107 | */ 108 | def subRangeMap(range: Range[K, O]): Repr 109 | 110 | /** Returns `true` if this range map contains no ranges. 111 | */ 112 | def isEmpty: Boolean = asMapOfRanges.isEmpty 113 | 114 | /** Returns `true` if `obj` is another [[RangeMap]] that has an equivalent 115 | * `#asMapOfRanges()`. 116 | */ 117 | override def equals(obj: Any): Boolean = obj match { 118 | case other: RangeMap[_, _, _] => asMapOfRanges == other.asMapOfRanges 119 | case _ => false 120 | } 121 | 122 | /** Returns `asMapOfRanges().hashCode()`. 123 | */ 124 | override def hashCode(): Int = asMapOfRanges().hashCode 125 | 126 | /** Returns a readable string representation of this range map. 127 | */ 128 | override def toString(): String = asMapOfRanges().toString 129 | } -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/collect/RangeMapWrapperBehaviours.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect 24 | 25 | import scala.annotation.meta.beanGetter 26 | import scala.annotation.meta.beanSetter 27 | import scala.annotation.meta.field 28 | import scala.annotation.meta.getter 29 | import scala.annotation.meta.setter 30 | import scala.math.Ordering.Int 31 | 32 | import org.feijoas.mango.common.annotations.Beta 33 | import org.feijoas.mango.common.collect.AsOrdered.asOrdered 34 | import org.feijoas.mango.common.collect.Range.asGuavaRangeConverter 35 | import org.mockito.Mockito.times 36 | import org.mockito.Mockito.verify 37 | import org.mockito.Mockito.when 38 | import org.scalatest.FreeSpec 39 | import org.scalatest.mockito.MockitoSugar 40 | import org.scalatest.prop.PropertyChecks 41 | 42 | import com.google.common.{ collect => gcc } 43 | 44 | /** 45 | * Behavior which all [[RangeMapWrappers]] have in common 46 | */ 47 | private[mango] trait RangeMapWrapperBehaviours extends FreeSpec with PropertyChecks with MockitoSugar { 48 | this: FreeSpec => 49 | 50 | def immutableWrapper[Repr <: RangeMapWrapperLike[Int, String, Int.type, Repr] with RangeMap[Int, String, Int.type]](constructor: (gcc.RangeMap[AsOrdered[Int], String]) => Repr) = { 51 | val mocked = mock[gcc.RangeMap[AsOrdered[Int], String]] 52 | val withMock = constructor(mocked) 53 | "it should forward all immutable methods to guava " - { 54 | "should forward #asMapOfRanges" in { 55 | withMock.asMapOfRanges 56 | verify(mocked).asMapOfRanges() 57 | } 58 | "should forward #get" in { 59 | withMock.get(5) 60 | verify(mocked).get(5) 61 | } 62 | "should forward #getEntry" in { 63 | withMock.getEntry(5) 64 | verify(mocked).getEntry(5) 65 | } 66 | "should forward #span" in { 67 | val nonEmpty = gcc.Maps.newHashMap[gcc.Range[AsOrdered[Int]], String] 68 | nonEmpty.put(Range.open(3, 4).asJava, "a") 69 | when(mocked.asMapOfRanges).thenReturn(nonEmpty) 70 | withMock.span 71 | verify(mocked, times(1)).span() 72 | } 73 | "should forward #subRangeMap" in { 74 | withMock.subRangeMap(Range.open(5, 6)) 75 | verify(mocked).subRangeMap(Range.open(5, 6).asJava) 76 | } 77 | } 78 | } 79 | 80 | def mutableWrapper[Repr <: mutable.RangeMapWrapperLike[Int, String, Int.type, Repr] with mutable.RangeMap[Int, String, Int.type]](constructor: (gcc.RangeMap[AsOrdered[Int], String]) => Repr) = { 81 | // forward all methods like immutable RangeMapWrapperLike 82 | immutableWrapper(constructor) 83 | 84 | def fixture = { 85 | val mocked = mock[gcc.RangeMap[AsOrdered[Int], String]] 86 | val withMock = constructor(mocked) 87 | (mocked, withMock) 88 | } 89 | 90 | // additional mutators 91 | val range = Range.open(5, 6) 92 | val rangeColl = Map(Range.closed(1, 2) -> "1", Range.open(5, 6) -> "2") 93 | 94 | "it should forward all mutable methods to guava " - { 95 | "should forward #put" in { 96 | val (mocked, withMock) = fixture 97 | withMock.put(range, "1") 98 | verify(mocked).put(range.asJava, "1") 99 | } 100 | "should forward #+=" in { 101 | val (mocked, withMock) = fixture 102 | withMock += range -> "1" 103 | verify(mocked).put(range.asJava, "1") 104 | } 105 | "should forward #++=" in { 106 | val (mocked, withMock) = fixture 107 | withMock ++= rangeColl 108 | verify(mocked).put(Range.closed(1, 2).asJava, "1") 109 | verify(mocked).put(Range.open(5, 6).asJava, "2") 110 | } 111 | "should forward #putAll" in { 112 | val (mocked, withMock) = fixture 113 | withMock.putAll(withMock) 114 | verify(mocked).putAll(mocked) 115 | } 116 | "should forward #remove" in { 117 | val (mocked, withMock) = fixture 118 | withMock.remove(range) 119 | verify(mocked).remove(range.asJava) 120 | } 121 | "should forward #-=" in { 122 | val (mocked, withMock) = fixture 123 | withMock -= range 124 | verify(mocked).remove(range.asJava) 125 | } 126 | "should forward #--=" in { 127 | val (mocked, withMock) = fixture 128 | withMock --= rangeColl.keySet 129 | verify(mocked).remove(Range.closed(1, 2).asJava) 130 | verify(mocked).remove(Range.open(5, 6).asJava) 131 | } 132 | "should forward #clear" in { 133 | val (mocked, withMock) = fixture 134 | withMock.clear 135 | verify(mocked).clear 136 | } 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/collect/RangeSetWrapperBehaviours.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect 24 | 25 | import scala.annotation.meta.beanGetter 26 | import scala.annotation.meta.beanSetter 27 | import scala.annotation.meta.field 28 | import scala.annotation.meta.getter 29 | import scala.annotation.meta.setter 30 | import scala.math.Ordering.Int 31 | 32 | import org.feijoas.mango.common.annotations.Beta 33 | import org.feijoas.mango.common.collect.AsOrdered.asOrdered 34 | import org.feijoas.mango.common.collect.Range.asGuavaRangeConverter 35 | import org.mockito.Mockito.verify 36 | import org.scalatest.FreeSpec 37 | import org.scalatest.mockito.MockitoSugar 38 | import org.scalatest.prop.PropertyChecks 39 | 40 | import com.google.common.collect.{ RangeSet => GuavaRangeSet } 41 | 42 | /** 43 | * Behavior which all [[RangeSetWrappers]] have in common 44 | */ 45 | private[mango] trait RangeSetWrapperBehaviours extends FreeSpec with PropertyChecks with MockitoSugar { 46 | this: FreeSpec => 47 | 48 | def immutableWrapper[Repr <: RangeSetWrapperLike[Int, Int.type, Repr] with RangeSet[Int, Int.type]](constructor: (GuavaRangeSet[AsOrdered[Int]]) => Repr) = { 49 | val mocked = mock[GuavaRangeSet[AsOrdered[Int]]] 50 | val withMock = constructor(mocked) 51 | "it should forward all immutable methods to guava " - { 52 | "should forward #asRanges" in { 53 | withMock.asRanges 54 | verify(mocked).asRanges() 55 | } 56 | "should forward #complement" in { 57 | withMock.complement 58 | verify(mocked).complement() 59 | } 60 | "should forward #contains" in { 61 | withMock.contains(5) 62 | verify(mocked).contains(5) 63 | } 64 | "should forward #encloses" in { 65 | withMock.encloses(Range.open(5, 6)) 66 | verify(mocked).encloses(Range.open(5, 6).asJava) 67 | } 68 | "should forward #enclosesAll" in { 69 | withMock.enclosesAll(withMock) 70 | verify(mocked).enclosesAll(mocked) 71 | } 72 | "should forward #isEmpt" in { 73 | withMock.isEmpty 74 | verify(mocked).isEmpty() 75 | } 76 | "should forward #rangeContaining" in { 77 | withMock.rangeContaining(5) 78 | verify(mocked).rangeContaining(5) 79 | } 80 | "should forward #span" in { 81 | withMock.span 82 | verify(mocked).span() 83 | } 84 | "should forward #subRangeSet" in { 85 | withMock.subRangeSet(Range.open(5, 6)) 86 | verify(mocked).subRangeSet(Range.open(5, 6).asJava) 87 | } 88 | } 89 | } 90 | 91 | def mutableWrapper[Repr <: mutable.RangeSetWrapperLike[Int, Int.type, Repr] with mutable.RangeSet[Int, Int.type]](constructor: (GuavaRangeSet[AsOrdered[Int]]) => Repr) = { 92 | // forward all methods like immutable RangeSetWrapperLike 93 | immutableWrapper(constructor) 94 | 95 | def fixture = { 96 | val mocked = mock[GuavaRangeSet[AsOrdered[Int]]] 97 | val withMock = constructor(mocked) 98 | (mocked, withMock) 99 | } 100 | 101 | // additional mutators 102 | val range = Range.open(5, 6) 103 | val rangeColl = List(Range.closed(1, 2), Range.open(5, 6)) 104 | 105 | "it should forward all mutable methods to guava " - { 106 | "should forward #add" in { 107 | val (mocked, withMock) = fixture 108 | withMock.add(range) 109 | verify(mocked).add(range.asJava) 110 | } 111 | "should forward #+=" in { 112 | val (mocked, withMock) = fixture 113 | withMock += range 114 | verify(mocked).add(range.asJava) 115 | } 116 | "should forward #++=" in { 117 | val (mocked, withMock) = fixture 118 | withMock ++= rangeColl 119 | verify(mocked).add(rangeColl(0).asJava) 120 | verify(mocked).add(rangeColl(1).asJava) 121 | } 122 | "should forward #addAll" in { 123 | val (mocked, withMock) = fixture 124 | withMock.addAll(withMock) 125 | verify(mocked).addAll(mocked) 126 | } 127 | "should forward #remove" in { 128 | val (mocked, withMock) = fixture 129 | withMock.remove(range) 130 | verify(mocked).remove(range.asJava) 131 | } 132 | "should forward #-=" in { 133 | val (mocked, withMock) = fixture 134 | withMock -= range 135 | verify(mocked).remove(range.asJava) 136 | } 137 | "should forward #--=" in { 138 | val (mocked, withMock) = fixture 139 | withMock --= rangeColl 140 | verify(mocked).remove(rangeColl(0).asJava) 141 | verify(mocked).remove(rangeColl(1).asJava) 142 | } 143 | "should forward #removeAll" in { 144 | val (mocked, withMock) = fixture 145 | withMock.removeAll(withMock) 146 | verify(mocked).removeAll(mocked) 147 | } 148 | "should forward #clear" in { 149 | val (mocked, withMock) = fixture 150 | withMock.clear 151 | verify(mocked).clear 152 | } 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/BinaryTreeTraverser.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect 24 | 25 | import scala.collection.convert.decorateAsScala.iterableAsScalaIterableConverter 26 | 27 | import org.feijoas.mango.common.annotations.Beta 28 | import org.feijoas.mango.common.base.Optional.asGuavaOptionalConverter 29 | import org.feijoas.mango.common.base.Optional.asMangoOptionConverter 30 | import org.feijoas.mango.common.base.Preconditions.checkNotNull 31 | import org.feijoas.mango.common.convert.AsJava 32 | import org.feijoas.mango.common.convert.AsScala 33 | 34 | import com.google.common.{ collect => cgcc } 35 | 36 | /** 37 | * A variant of {@link TreeTraverser} for binary trees, providing additional traversals specific to 38 | * binary trees. 39 | * 40 | * @author Markus Schneider 41 | * @since 0.11 (copied from guava-libraries) 42 | */ 43 | @Beta 44 | trait BinaryTreeTraverser[T] extends TreeTraverser[T] { 45 | 46 | /** 47 | * Returns the left child of the specified node, or `Option#isEmpty` if the specified 48 | * node has no left child. 49 | */ 50 | def leftChild: T => Option[T] 51 | 52 | /** 53 | * Returns the right child of the specified node, or `Option#isEmpty` if the specified 54 | * node has no right child. 55 | */ 56 | def rightChild: T => Option[T] 57 | 58 | /** 59 | * Returns the children of this node, in left-to-right order. 60 | */ 61 | final override def children: T => Iterable[T] = (root: T) => this.asJava.children(root).asScala 62 | 63 | /** 64 | * Returns an unmodifiable iterable over the nodes in a tree structure, using in-order 65 | * traversal. 66 | */ 67 | final def inOrderTraversal(root: T): Iterable[T] = this.asJava.inOrderTraversal(root).asScala 68 | } 69 | 70 | /** Factory for [[BinaryTreeTraverser]] instances. */ 71 | object BinaryTreeTraverser { 72 | 73 | /** 74 | * Creates a new `BinaryTreeTraverser` using a function that returns the left child and one that returns the right child 75 | */ 76 | final def apply[T](left: T => Option[T], right: T => Option[T]): BinaryTreeTraverser[T] = new BinaryTreeTraverser[T] { 77 | final override def leftChild = (root: T) => left(root) 78 | final override def rightChild = (root: T) => right(root) 79 | } 80 | 81 | /** 82 | * Creates a new `BinaryTreeTraverser` using a function that returns the left child and the right child as a Tuple 83 | */ 84 | final def apply[T](childs: T => (Option[T],Option[T])): BinaryTreeTraverser[T] = new BinaryTreeTraverser[T] { 85 | final override def leftChild = (root: T) => childs(root)._1 86 | final override def rightChild = (root: T) => childs(root)._2 87 | } 88 | 89 | /** 90 | * Adds an `asJava` method that wraps a Scala `BinaryTreeTraverser` in 91 | * a Guava `BinaryTreeTraverser`. 92 | * 93 | * The returned Guava `BinaryTreeTraverser` forwards all calls 94 | * to the given Scala `BinaryTreeTraverser`. 95 | * 96 | * @param fnc the Scala `BinaryTreeTraverser` to wrap in a Guava `BinaryTreeTraverser` 97 | * @return An object with an `asJava` method that returns a Guava `BinaryTreeTraverser` 98 | * view of the argument 99 | */ 100 | implicit final def asGuavaBinaryTreeTraverserConverter[T](traverser: BinaryTreeTraverser[T]): AsJava[cgcc.BinaryTreeTraverser[T]] = { 101 | def convert(traverser: BinaryTreeTraverser[T]): cgcc.BinaryTreeTraverser[T] = traverser match { 102 | case t: AsMangoBinaryTreeTraverser[T] => t.delegate 103 | case _ => AsGuavaBinaryTreeTraverser(traverser) 104 | } 105 | new AsJava(convert(traverser)) 106 | } 107 | 108 | /** 109 | * Adds an `asScala` method that wraps a Guava `BinaryTreeTraverser` in 110 | * a Scala `BinaryTreeTraverser`. 111 | * 112 | * The returned Scala `BinaryTreeTraverser` forwards all calls 113 | * to the given Guava `BinaryTreeTraverser``. 114 | * 115 | * @param pred the Guava `BinaryTreeTraverser` to wrap in a Scala `BinaryTreeTraverser` 116 | * @return An object with an `asScala` method that returns a Scala `BinaryTreeTraverser` 117 | * view of the argument 118 | */ 119 | implicit final def asMangoBinaryTreeTraverserConverter[T](traverser: cgcc.BinaryTreeTraverser[T]): AsScala[BinaryTreeTraverser[T]] = { 120 | def convert(traverser: cgcc.BinaryTreeTraverser[T]) = traverser match { 121 | case AsGuavaBinaryTreeTraverser(delegate) => delegate 122 | case _ => AsMangoBinaryTreeTraverser(traverser) 123 | } 124 | new AsScala(convert(traverser)) 125 | } 126 | 127 | } 128 | 129 | /** 130 | * Wraps a Scala `BinaryTreeTraverser` in a Guava `BinaryTreeTraverser` 131 | */ 132 | @SerialVersionUID(1L) 133 | private[mango] case class AsGuavaBinaryTreeTraverser[T](delegate: BinaryTreeTraverser[T]) extends cgcc.BinaryTreeTraverser[T] with Serializable { 134 | checkNotNull(delegate) 135 | final override def leftChild(root: T) = delegate.leftChild(root).asJava 136 | final override def rightChild(root: T) = delegate.rightChild(root).asJava 137 | } 138 | 139 | /** 140 | * Wraps a Guava `BinaryTreeTraverser` in a Scala `BinaryTreeTraverser` 141 | */ 142 | @SerialVersionUID(1L) 143 | private[mango] case class AsMangoBinaryTreeTraverser[T](delegate: cgcc.BinaryTreeTraverser[T]) extends BinaryTreeTraverser[T] with Serializable { 144 | checkNotNull(delegate) 145 | final override def leftChild = (root: T) => delegate.leftChild(root).asScala 146 | final override def rightChild = (root: T) => delegate.rightChild(root).asScala 147 | } -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/cache/CacheWrapperBehaviour.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.cache 24 | 25 | import java.util.concurrent.{ Callable => Callable, ConcurrentHashMap, ConcurrentMap, ExecutionException } 26 | 27 | import scala.annotation.meta.{ beanGetter, beanSetter, field, getter, setter } 28 | import scala.collection.convert.WrapAsJava.mapAsJavaMap 29 | import scala.collection.convert.WrapAsScala.asScalaIterator 30 | 31 | import org.feijoas.mango.common.annotations.Beta 32 | import org.junit.Assert.assertSame 33 | import org.mockito.Matchers._ 34 | import org.mockito.ArgumentMatchers._ 35 | import org.mockito.ArgumentMatchers 36 | import org.mockito.ArgumentMatcher 37 | import org.mockito.Mockito._ 38 | import org.scalatest._ 39 | 40 | import com.google.common.cache.{ Cache => GuavaCache, CacheStats => GuavaCacheStats } 41 | import com.google.common.collect.ImmutableMap 42 | 43 | /** 44 | * Shared tests for all CacheWrapper 45 | * 46 | * @author Markus Schneider 47 | * @since 0.7 48 | */ 49 | trait CacheWrapperBehaviour extends Matchers { this: FlatSpec => 50 | 51 | def forwardingWrapper(mockedFixture: => (GuavaCache[String, Int], Cache[String, Int])) = { 52 | 53 | behavior of "CacheWrapper" 54 | 55 | it should "forward #get to the underlying LoadingCache" in { 56 | val (wrapped, cache) = mockedFixture 57 | when(wrapped.getIfPresent("foo")).thenReturn(3) 58 | cache.getIfPresent("foo") should be(Some(3)) 59 | verify(wrapped).getIfPresent("foo") 60 | } 61 | 62 | it should "forward #getOrElseUpdate to the underlying LoadingCache" in { 63 | val (wrapped, cache) = mockedFixture 64 | when(wrapped.get(ArgumentMatchers.eq("foo"), isA(classOf[Callable[Int]]))).thenReturn(4) 65 | cache.getOrElseUpdate("foo", () => 4) should be(4) 66 | verify(wrapped).get(ArgumentMatchers.eq("foo"), isA(classOf[Callable[Int]])) 67 | } 68 | 69 | it should "forward #getAllPresent to the underlying LoadingCache" in { 70 | val (wrapped, cache) = mockedFixture 71 | when(wrapped.getAllPresent(isA(classOf[java.lang.Iterable[String]]))).thenReturn(jImmutableMap("a" -> 1, "b" -> 2)) 72 | cache.getAllPresent(List("a", "b")) should be(Map("a" -> 1, "b" -> 2)) 73 | verify(wrapped).getAllPresent(anyIterableWith("a", "b")) 74 | } 75 | 76 | it should "forward #put to the underlying LoadingCache" in { 77 | val (wrapped, cache) = mockedFixture 78 | cache.put("foo", 3) 79 | verify(wrapped).put("foo", 3) 80 | } 81 | 82 | it should "forward #putAll to the underlying LoadingCache" in { 83 | val (wrapped, cache) = mockedFixture 84 | cache.putAll(Map("e" -> 11, "f" -> 13)) 85 | verify(wrapped).putAll(ImmutableMap.of("e", 11, "f", 13)) 86 | } 87 | 88 | it should "forward #invalidate to the underlying LoadingCache" in { 89 | val (wrapped, cache) = mockedFixture 90 | cache.invalidate("g") 91 | verify(wrapped).invalidate("g") 92 | } 93 | 94 | it should "forward #invalidateAll(keys) to the underlying LoadingCache" in { 95 | val (wrapped, cache) = mockedFixture 96 | cache.invalidateAll(List("h", "i")) 97 | verify(wrapped).invalidateAll(anyIterableWith("h", "i")) 98 | } 99 | 100 | it should "forward #invalidateAll to the underlying LoadingCache" in { 101 | val (wrapped, cache) = mockedFixture 102 | cache.invalidateAll 103 | verify(wrapped).invalidateAll() 104 | } 105 | 106 | it should "forward #size to the underlying LoadingCache" in { 107 | val (wrapped, cache) = mockedFixture 108 | when(wrapped.size()).thenReturn(7) 109 | cache.size should be(7) 110 | verify(wrapped).size() 111 | } 112 | 113 | it should "forward #stats to the underlying LoadingCache" in { 114 | val (wrapped, cache) = mockedFixture 115 | when(wrapped.stats()).thenReturn(new GuavaCacheStats(1, 2, 4, 6, 8, 16)) 116 | cache.stats should be(CacheStats(1, 2, 4, 6, 8, 16)) 117 | verify(wrapped).stats() 118 | } 119 | 120 | it should "forward #asMap to the underlying LoadingCache" in { 121 | val (wrapped, cache) = mockedFixture 122 | when(wrapped.asMap()).thenReturn(jConcurrentMap("c" -> 3, "d" -> 7)) 123 | cache.asMap should be(Map("c" -> 3, "d" -> 7)) 124 | verify(wrapped).asMap() 125 | } 126 | 127 | it should "forward #cleanUp to the underlying LoadingCache" in { 128 | val (wrapped, cache) = mockedFixture 129 | cache.cleanUp 130 | verify(wrapped).cleanUp() 131 | } 132 | } 133 | 134 | /** 135 | * creates a Mockito `ArgumentMatcher` which checks that the `Iterable` to match 136 | * has the provided elements 137 | */ 138 | def anyIterableWith[T](elements: Any*) = argThat(new ArgumentMatcher[java.lang.Iterable[T]] { 139 | val expected = List(elements.seq: _*) 140 | override def matches(arg: java.lang.Iterable[T]) = arg match { 141 | case it: java.lang.Iterable[_] => expected sameElements it.iterator().toList 142 | case _ => false 143 | } 144 | }) 145 | 146 | /** creates a Guava ImmutableMap with elems */ 147 | def jImmutableMap[K, V](elems: (K, V)*): ImmutableMap[K, V] = { 148 | val map: java.util.Map[K, V] = Map(elems: _*) 149 | ImmutableMap.copyOf(map) 150 | } 151 | 152 | /** creates a Java ConcurrentMap with elems */ 153 | def jConcurrentMap[K, V](elems: (K, V)*): ConcurrentMap[K, V] = { 154 | val map = new ConcurrentHashMap[K, V]() 155 | map.putAll(jImmutableMap(elems: _*)) 156 | map 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/main/scala/org/feijoas/mango/common/collect/RangeSetLike.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.collect 24 | 25 | import scala.collection.generic.HasNewBuilder 26 | 27 | import org.feijoas.mango.common.annotations.Beta 28 | import org.feijoas.mango.common.base.Preconditions.checkNotNull 29 | 30 | /** 31 | * Implementation trait for [[RangeSet]] 32 | * 33 | * $rangeSetNote 34 | * @author Markus Schneider 35 | * @since 0.8 36 | * 37 | * @define rangeSetNote 38 | * 39 | * A range set is a set comprising zero or more nonempty, disconnected ranges of type `C` 40 | * for which an `Ordering[C]` is defined. 41 | * 42 | *

Note that the behavior of `Range#isEmpty()` and `Range#isConnected(Range)` may 43 | * not be as expected on discrete ranges. See the Scaladoc of those methods for details. 44 | * 45 | *

For a `Set` whose contents are specified by a [[Range]], see [[ContiguousSet]]. 46 | * 47 | * Usage example: 48 | * 49 | * {{{ 50 | * import org.feijoas.mango.common.collect.Bound._ 51 | * import org.feijoas.mango.common.collect._ 52 | * import math.Ordering.Int 53 | * 54 | * // immutable range set: 55 | * val rangeSet = RangeSet(Range.open(1, 3), Range.closed(4, 9)) // {(1,3), [4,9]} 56 | * val subSet = rangeSet.subRangeSet(Range.closed(2, 6)) // union view {[2,3), [4,6]} 57 | * 58 | * // mutable range set: 59 | * val mutableRangeSet = mutable.RangeSet(Range.closed(1, 10)) // {[1, 10]} 60 | * mutableRangeSet += Range.closedOpen(11, 15) // disconnected range: {[1, 10], [11, 15)} 61 | * mutableRangeSet += Range.closedOpen(15, 20) // connected range; {[1, 10], [11, 20)} 62 | * mutableRangeSet += Range.openClosed(0, 0) // empty range; {[1, 10], [11, 20)} 63 | * mutableRangeSet -= Range.open(5, 10) // splits [1, 10]; {[1, 5], [10, 10], [11, 20)} 64 | * }}} 65 | * 66 | * @tparam C the type of the elements of the set 67 | * @tparam O the type of Ordering used to order the elements 68 | * @tparam Repr the type of the set itself. 69 | */ 70 | @Beta 71 | trait RangeSetLike[C, O <: Ordering[C], +Repr <: RangeSetLike[C, O, Repr] with RangeSet[C, O]] 72 | extends HasNewBuilder[Range[C, O], Repr] { 73 | self => 74 | 75 | /** 76 | * Determines whether any of this range set's member ranges contains `value`. 77 | */ 78 | def contains(value: C): Boolean = rangeContaining(value) != None 79 | 80 | /** 81 | * Returns the unique range from this range set that contains 82 | * `value` as `Some(value)`, or `None` if this range set does not contain `value`. 83 | */ 84 | def rangeContaining(value: C): Option[Range[C, O]] = { 85 | checkNotNull(value) 86 | asRanges.find { _.contains(value) } 87 | } 88 | 89 | /** 90 | * Returns `true` if there exists a member range in this range set which 91 | * encloses the specified range. 92 | */ 93 | def encloses(otherRange: Range[C, O]): Boolean = { 94 | checkNotNull(otherRange) 95 | asRanges.find { _.encloses(otherRange) }.isDefined 96 | } 97 | 98 | /** 99 | * Returns `true` if for each member range in `other` there exists a member range in 100 | * this range set which encloses it. It follows that `this.contains(value)` whenever `other.contains(value)`. 101 | * Returns `true` if `other` is empty. 102 | * 103 | *

This is equivalent to checking if this range set `#encloses` each of the ranges in 104 | * `other`. 105 | */ 106 | def enclosesAll(other: RangeSet[C, O]): Boolean = { 107 | checkNotNull(other) 108 | other.asRanges.find { !this.encloses(_) }.isEmpty 109 | } 110 | 111 | /** 112 | * Returns `true` if this range set contains no ranges. 113 | */ 114 | def isEmpty: Boolean = asRanges().isEmpty 115 | 116 | /** 117 | * Returns a `Some` with the minimal range which encloses all ranges in this range set 118 | * or `None` if this range set is empty 119 | */ 120 | def span(): Option[Range[C, O]] 121 | 122 | /** 123 | * Returns a view of the disconnected ranges that make up this 124 | * range set. The returned set may be empty. The iterators returned by its 125 | * `Iterable#iterator` method return the ranges in increasing order of lower bound 126 | * (equivalently, of upper bound). 127 | */ 128 | def asRanges(): Set[Range[C, O]] 129 | 130 | /** 131 | * Returns a view of the complement of this `RangeSet`. 132 | */ 133 | def complement(): Repr 134 | 135 | /** 136 | * Returns a view of the intersection of this `RangeSet` with the specified range. 137 | */ 138 | def subRangeSet(view: Range[C, O]): Repr 139 | 140 | /** 141 | * Returns `true` if `obj` is another `RangeSet` that contains the same ranges 142 | * according to `Range#equals(Any)`. 143 | */ 144 | override def equals(obj: Any): Boolean = obj match { 145 | case other: RangeSet[_, _] => asRanges == other.asRanges 146 | case _ => false 147 | } 148 | 149 | /** 150 | * Returns `asRanges().hashCode()`. 151 | */ 152 | override def hashCode(): Int = asRanges.hashCode 153 | 154 | /** 155 | * Returns a readable string representation of this range set. For example, if this 156 | * `RangeSet` consisted of `Ranges.closed(1, 3)` and `Ranges.greaterThan(4)`, 157 | * this might return `"{[1‥3](4‥+∞)}"`. 158 | */ 159 | override def toString(): String = { 160 | val builder = new StringBuilder() 161 | builder.append('{') 162 | asRanges foreach { builder.append(_) } 163 | builder.append('}') 164 | builder.toString() 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/test/scala/org/feijoas/mango/common/hash/BloomFilterTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Mango Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * The code of this project is a port of (or wrapper around) the Guava-libraries. 19 | * See http://code.google.com/p/guava-libraries/ 20 | * 21 | * @author Markus Schneider 22 | */ 23 | package org.feijoas.mango.common.hash 24 | 25 | import scala.annotation.implicitNotFound 26 | import scala.annotation.meta.beanGetter 27 | import scala.annotation.meta.beanSetter 28 | import scala.annotation.meta.field 29 | import scala.annotation.meta.getter 30 | import scala.annotation.meta.setter 31 | 32 | import org.feijoas.mango.common.annotations.Beta 33 | import org.feijoas.mango.common.hash.Funnel.byteArrayFunnel 34 | import org.feijoas.mango.common.hash.Funnel.intFunnel 35 | import org.feijoas.mango.common.hash.Funnel.longFunnel 36 | import org.feijoas.mango.common.hash.Funnel.stringFunnel 37 | import org.junit.Assert.assertEquals 38 | import org.junit.Assert.assertNotSame 39 | import org.scalatest.FlatSpec 40 | import org.scalatest.Matchers.be 41 | import org.scalatest.Matchers.convertToAnyShouldWrapper 42 | import org.scalatest.Matchers.not 43 | import org.scalatest.mockito.MockitoSugar 44 | 45 | import com.google.common.hash.PrimitiveSink 46 | import com.google.common.primitives.Ints 47 | import com.google.common.testing.SerializableTester 48 | 49 | /** 50 | * Tests for [[BloomFilter]] 51 | * 52 | * @author Markus Schneider 53 | * @since 0.6 (copied from guava-libraries) 54 | */ 55 | class BloomFilterTest extends FlatSpec with MockitoSugar { 56 | 57 | it should "throw an exception if the arguments are out of range" in { 58 | intercept[IllegalArgumentException] { 59 | BloomFilter.create[CharSequence](-1) 60 | } 61 | intercept[IllegalArgumentException] { 62 | BloomFilter.create[CharSequence](-1, 0.03) 63 | } 64 | intercept[IllegalArgumentException] { 65 | BloomFilter.create[CharSequence](1, 0.0) 66 | } 67 | intercept[IllegalArgumentException] { 68 | BloomFilter.create[CharSequence](1, 1.0) 69 | } 70 | intercept[NullPointerException] { 71 | BloomFilter.create[CharSequence](1)(null) 72 | } 73 | } 74 | 75 | it should "fail when more than 255 HashFunctions are needed" in { 76 | val n = 1000 77 | val p = 0.00000000000000000000000000000000000000000000000000000000000000000000000000000001 78 | intercept[IllegalArgumentException] { 79 | BloomFilter.create[CharSequence](n, p) 80 | } 81 | } 82 | 83 | it should "be able to create a copy" in { 84 | val original = BloomFilter.create[CharSequence](100) 85 | val copy = original.copy 86 | assertNotSame(original, copy) 87 | assertEquals(original, copy) 88 | } 89 | 90 | it should "be equal to another instance with the same elements" in { 91 | 92 | val bf1 = BloomFilter.create[CharSequence](100) 93 | bf1.put("1") 94 | bf1.put("2") 95 | 96 | val bf2 = BloomFilter.create[CharSequence](100) 97 | bf2.put("1") 98 | bf2.put("2") 99 | 100 | bf1 should be(bf2) 101 | bf2.put("3") 102 | bf1 should not be (bf2) 103 | } 104 | 105 | it should "be equal to another instance even if the Funnels are different instances" in { 106 | case class CustomFunnel() extends Funnel[Any] { 107 | override def funnel(any: Any, bytePrimitiveSink: PrimitiveSink) { 108 | bytePrimitiveSink.putInt(any.hashCode()) 109 | } 110 | } 111 | BloomFilter.create(100)(new CustomFunnel) should be(BloomFilter.create(100)(new CustomFunnel)) 112 | } 113 | 114 | it should "be serializeable" in { 115 | SerializableTester.reserializeAndAssert(BloomFilter.create[CharSequence](100)) 116 | SerializableTester.reserializeAndAssert(BloomFilter.create[Int](100)) 117 | SerializableTester.reserializeAndAssert(BloomFilter.create[Long](100)) 118 | SerializableTester.reserializeAndAssert(BloomFilter.create[Array[Byte]](100)) 119 | SerializableTester.reserializeAndAssert(BloomFilter.create[CharSequence](100)) 120 | } 121 | 122 | it should "perform basic operations" in { 123 | object BAD_FUNNEL extends Funnel[Any] { 124 | override def funnel(any: Any, bytePrimitiveSink: PrimitiveSink) { 125 | bytePrimitiveSink.putInt(any.hashCode()) 126 | } 127 | } 128 | 129 | var fpr = 0.0000001 130 | while (fpr < 0.1) { 131 | var expectedInsertions = 1 132 | while (expectedInsertions <= 10000) { 133 | checkSanity(BloomFilter.create(expectedInsertions, fpr)(BAD_FUNNEL)) 134 | expectedInsertions = expectedInsertions * 10 135 | 136 | } 137 | fpr = fpr * 10 138 | } 139 | } 140 | 141 | it should "true if the bloom filter's bits changed" in { 142 | for (i <- 0 until 10) { 143 | val bf = BloomFilter.create[CharSequence](100) 144 | for (j <- 0 until 10) { 145 | val value = new Object().toString() 146 | val mightContain = bf.mightContain(value) 147 | val put = bf.put(value) 148 | put should be(!mightContain) 149 | } 150 | } 151 | } 152 | 153 | it should "testJavaSerialization()" in { 154 | val bf = BloomFilter.create[Array[Byte]](100) 155 | for (i <- 0 until 10) { 156 | bf.put(Ints.toByteArray(i)) 157 | } 158 | 159 | val copy = SerializableTester.reserialize(bf) 160 | for (i <- 0 until 10) { 161 | copy.mightContain(Ints.toByteArray(i)) should be(true) 162 | } 163 | bf.expectedFpp() should be(copy.expectedFpp()) 164 | 165 | SerializableTester.reserializeAndAssert(bf) 166 | } 167 | 168 | private def checkSanity(bf: BloomFilter[Any]) = { 169 | bf.mightContain(new Object()) should be(false) 170 | bf.apply(new Object()) should be(false) 171 | for (i <- 0 until 100) { 172 | val o = new Object 173 | bf.put(o) 174 | bf.mightContain(o) should be(true) 175 | bf.apply(o) should be(true) 176 | } 177 | } 178 | } 179 | --------------------------------------------------------------------------------