├── project ├── build.properties └── plugins.sbt ├── version.sbt ├── .gitignore ├── .scalafmt.conf ├── src ├── main │ ├── scala │ │ └── dev │ │ │ └── travisbrown │ │ │ └── sized │ │ │ ├── SizedVector.scala │ │ │ ├── SizedArraySeq.scala │ │ │ ├── SizedIndexedSeqOps.scala │ │ │ └── SizedIndexedSeqFactory.scala │ ├── scala-2.13 │ │ └── dev │ │ │ └── travisbrown │ │ │ └── sized │ │ │ ├── Pair.scala │ │ │ ├── PairMacros.scala │ │ │ └── SizedOps.scala │ └── scala-0.24 │ │ └── dev │ │ └── travisbrown │ │ └── sized │ │ └── SizedOps.scala └── test │ ├── scala-2.13 │ └── dev │ │ └── travisbrown │ │ └── sized │ │ └── SizedIndexedSeq213Suite.scala │ └── scala │ └── dev │ └── travisbrown │ └── sized │ └── SizedIndexedSeqSuite.scala ├── .travis.yml ├── README.md └── LICENSE /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.3.13 2 | -------------------------------------------------------------------------------- /version.sbt: -------------------------------------------------------------------------------- 1 | version in ThisBuild := "0.2.1-SNAPSHOT" 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | target/ 3 | .idea/ 4 | .idea_modules/ 5 | .DS_STORE 6 | .cache 7 | .settings 8 | .project 9 | .classpath 10 | tmp/ 11 | _site/ 12 | -------------------------------------------------------------------------------- /.scalafmt.conf: -------------------------------------------------------------------------------- 1 | version = 2.4.2 2 | continuationIndent.defnSite = 2 3 | docstrings = JavaDoc 4 | includeCurlyBraceInSelectChains = false 5 | maxColumn = 120 6 | newlines.alwaysBeforeElseAfterCurlyIf = false 7 | newlines.alwaysBeforeMultilineDef = false 8 | optIn.breakChainOnFirstMethodDot = false 9 | rewrite.rules = [ 10 | AvoidInfix, 11 | RedundantBraces, 12 | RedundantParens, 13 | AsciiSortImports, 14 | PreferCurlyFors 15 | ] 16 | project.excludeFilters = [ 17 | scala-0.24/dev/travisbrown/sized/SizedOps.scala 18 | ] 19 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.4.1") 2 | addSbtPlugin("com.eed3si9n" % "sbt-unidoc" % "0.4.3") 3 | addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.13") 4 | addSbtPlugin("com.jsuereth" % "sbt-pgp" % "2.0.1") 5 | addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.7.0") 6 | addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.0") 7 | addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "1.0.0") 8 | addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.6.1") 9 | addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.3.7") 10 | -------------------------------------------------------------------------------- /src/main/scala/dev/travisbrown/sized/SizedVector.scala: -------------------------------------------------------------------------------- 1 | package dev.travisbrown.sized 2 | 3 | import scala.collection.SeqFactory.Delegate 4 | 5 | final class SizedVector[+A, N <: Int] private (protected val coll: Vector[A]) 6 | extends SizedIndexedSeqOps[A, Vector, N, SizedVector] { 7 | def iterableFactory: SizedIndexedSeqFactory[Vector, SizedVector] = SizedVector 8 | } 9 | 10 | object SizedVector extends Delegate(Vector) with SizedIndexedSeqFactory[Vector, SizedVector] { 11 | private[sized] def unsafeWrap[A, N <: Int](value: Vector[A]): SizedVector[A, N] = new SizedVector[A, N](value) 12 | } 13 | -------------------------------------------------------------------------------- /src/main/scala/dev/travisbrown/sized/SizedArraySeq.scala: -------------------------------------------------------------------------------- 1 | package dev.travisbrown.sized 2 | 3 | import scala.collection.SeqFactory.Delegate 4 | import scala.collection.immutable.ArraySeq 5 | 6 | final class SizedArraySeq[+A, N <: Int] private (protected val coll: ArraySeq[A]) 7 | extends SizedIndexedSeqOps[A, ArraySeq, N, SizedArraySeq] { 8 | def iterableFactory: SizedIndexedSeqFactory[ArraySeq, SizedArraySeq] = SizedArraySeq 9 | } 10 | 11 | object SizedArraySeq extends Delegate(ArraySeq.untagged) with SizedIndexedSeqFactory[ArraySeq, SizedArraySeq] { 12 | private[sized] def unsafeWrap[A, N <: Int](value: ArraySeq[A]): SizedArraySeq[A, N] = new SizedArraySeq[A, N](value) 13 | } 14 | -------------------------------------------------------------------------------- /src/main/scala-2.13/dev/travisbrown/sized/Pair.scala: -------------------------------------------------------------------------------- 1 | package dev.travisbrown.sized 2 | 3 | import scala.language.experimental.macros 4 | 5 | sealed class Pair[A <: Int, B <: Int] { 6 | type Lt <: Boolean 7 | type LtEq <: Boolean 8 | type Diff <: Int 9 | type Sum <: Int 10 | } 11 | 12 | object Pair { 13 | type Lt[A <: Int, B <: Int] = Pair[A, B] { type Lt = true } 14 | type LtEq[A <: Int, B <: Int] = Pair[A, B] { type LtEq = true } 15 | 16 | val singleton: Pair[Nothing, Nothing] = new Pair[Nothing, Nothing] 17 | 18 | implicit def materialize[A <: Int, B <: Int, Lt0 <: Boolean, LtEq0 <: Boolean, Diff0 <: Int, Sum0 <: Int]: Pair[A, B] { 19 | type Lt = Lt0 20 | type LtEq = LtEq0 21 | type Diff = Diff0 22 | type Sum = Sum0 23 | } = macro PairMacros.materialize[A, B] 24 | } 25 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: xenial 2 | language: scala 3 | 4 | scala: 5 | - 2.13.3 6 | - 0.24.0 7 | 8 | jdk: 9 | - openjdk8 10 | 11 | cache: 12 | directories: 13 | - $HOME/.ivy2/cache 14 | - $HOME/.sbt/boot 15 | - $HOME/.coursier 16 | 17 | install: 18 | - pip install --user codecov 19 | 20 | script: 21 | - if [[ "$TRAVIS_SCALA_VERSION" == 0.* ]]; 22 | then 23 | sbt ++$TRAVIS_SCALA_VERSION clean test; 24 | else 25 | sbt ++$TRAVIS_SCALA_VERSION clean coverage test scalafmtCheck test:scalafmtCheck scalafmtSbtCheck && 26 | sbt ++$TRAVIS_SCALA_VERSION coverageAggregate && 27 | codecov; 28 | fi 29 | 30 | # See http://www.scala-sbt.org/0.13/docs/Travis-CI-with-sbt.html 31 | # Tricks to avoid unnecessary cache updates 32 | - find $HOME/.sbt -name "*.lock" | xargs rm 33 | -------------------------------------------------------------------------------- /src/main/scala-2.13/dev/travisbrown/sized/PairMacros.scala: -------------------------------------------------------------------------------- 1 | package dev.travisbrown.sized 2 | 3 | import scala.reflect.macros.whitebox.Context 4 | 5 | class PairMacros(val c: Context) { 6 | import c.universe._ 7 | 8 | final def materialize[A <: Int: WeakTypeTag, B <: Int: WeakTypeTag]: Tree = 9 | (c.weakTypeOf[A].dealias, c.weakTypeOf[B].dealias) match { 10 | case (aType @ ConstantType(Constant(a: Int)), bType @ ConstantType(Constant(b: Int))) => 11 | q""" 12 | _root_.dev.travisbrown.sized.Pair.singleton.asInstanceOf[ 13 | _root_.dev.travisbrown.sized.Pair[$aType, $bType] { 14 | type Lt = ${Constant(a < b)} 15 | type LtEq = ${Constant(a <= b)} 16 | type Diff = ${Constant(b - a)} 17 | type Sum = ${Constant(a + b)} 18 | } 19 | ] 20 | """ 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/scala/dev/travisbrown/sized/SizedIndexedSeqOps.scala: -------------------------------------------------------------------------------- 1 | package dev.travisbrown.sized 2 | 3 | import scala.annotation.unchecked.uncheckedVariance 4 | import scala.collection.immutable.{IndexedSeqOps, StrictOptimizedSeqOps} 5 | import scala.collection.mutable.Builder 6 | 7 | trait SizedIndexedSeqOps[+A, U[+x] <: IndexedSeq[x] with IndexedSeqOps[x, U, U[x]], N <: Int, C[+x, _ <: Int] <: IndexedSeqOps[ 8 | x, 9 | U, 10 | U[x] 11 | ]] extends IndexedSeqOps[A, U, U[A]] 12 | with StrictOptimizedSeqOps[A, U, U[A]] 13 | with SizedOps[A, U, N, C] 14 | with SizedOpsHelpers[U] { 15 | override def iterableFactory: SizedIndexedSeqFactory[U @uncheckedVariance, C] 16 | 17 | final protected def fromSpecific(coll: IterableOnce[A @uncheckedVariance]): U[A] = coll.iterator.to(iterableFactory) 18 | final protected def newSpecificBuilder: Builder[A @uncheckedVariance, U[A]] = iterableFactory.newBuilder[A] 19 | final def toIterable: Iterable[A] = coll.toIterable 20 | final def apply(i: Int): A = coll(i) 21 | final def length: Int = coll.length 22 | 23 | final def unsized: U[A] = coll 24 | 25 | final def sizedMap[B](f: A => B): C[B, N] = unsafeWrap(coll.map(f)) 26 | final def sizedReverse: C[A, N] = unsafeWrap(coll.reverse) 27 | 28 | override def toString: String = s"Sized${coll.toString}" 29 | 30 | final protected[this] def unsafeWrap[A, N <: Int](value: U[A]): C[A, N] = 31 | iterableFactory.unsafeWrap(value.to(iterableFactory)) 32 | } 33 | -------------------------------------------------------------------------------- /src/test/scala-2.13/dev/travisbrown/sized/SizedIndexedSeq213Suite.scala: -------------------------------------------------------------------------------- 1 | package dev.travisbrown.sized 2 | 3 | import org.scalatest.funsuite.AnyFunSuite 4 | import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks 5 | 6 | /** 7 | * Only for tests that won't pass on Dotty because of ScalaTest bugs. 8 | */ 9 | class SizedIndexedSeq213Suite extends AnyFunSuite with ScalaCheckDrivenPropertyChecks { 10 | test("Negative indexing should not compile") { 11 | val xs = SizedVector(1, 2, 3) 12 | assertCompiles("xs[2]") 13 | assertDoesNotCompile("xs[-1]") 14 | } 15 | 16 | test("Out-of-bounds indexing should not compile") { 17 | val xs = SizedVector(1, 2, 3) 18 | assertCompiles("xs[2]") 19 | assertDoesNotCompile("xs[3]") 20 | } 21 | 22 | test("safe head, last, tail, and init on an empty collection should not compile") { 23 | val xs0 = SizedVector.sizedEmpty[String] 24 | val xs1 = SizedVector("a", "b", "c") 25 | assertDoesNotCompile("xs0.safeHead") 26 | assertDoesNotCompile("xs0.safeLast") 27 | assertDoesNotCompile("xs0.sizedTail") 28 | assertDoesNotCompile("xs0.sizedInit") 29 | assertCompiles("xs1.safeHead") 30 | assertCompiles("xs1.safeLast") 31 | assertCompiles("xs1.sizedTail") 32 | assertCompiles("xs1.sizedInit") 33 | } 34 | 35 | test("Out-of-bounds take and drop should not compile") { 36 | val xs0 = SizedVector("a", "b", "c") 37 | val xs1 = SizedVector("a", "b", "c", "d") 38 | assertDoesNotCompile("xs0.sizedTake[4]") 39 | assertDoesNotCompile("xs0.sizedTakeRight[4]") 40 | assertDoesNotCompile("xs0.sizedDrop[4]") 41 | assertDoesNotCompile("xs0.sizedDropRight[4]") 42 | assertCompiles("xs1.sizedTake[4]") 43 | assertCompiles("xs1.sizedTakeRight[4]") 44 | assertCompiles("xs1.sizedDrop[4]") 45 | assertCompiles("xs1.sizedDropRight[4]") 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/scala-2.13/dev/travisbrown/sized/SizedOps.scala: -------------------------------------------------------------------------------- 1 | package dev.travisbrown.sized 2 | 3 | import scala.collection.immutable.IndexedSeqOps 4 | 5 | trait SizedOps[+A, U[+x] <: IndexedSeq[x] with IndexedSeqOps[x, U, U[x]], N <: Int, C[+x, _ <: Int] <: IndexedSeqOps[ 6 | x, 7 | U, 8 | U[x] 9 | ]] { 10 | final def apply[X <: Int](implicit X: ValueOf[X], ev0: Pair.LtEq[0, X], ev1: Pair.Lt[X, N]): A = coll(X.value) 11 | final def safeHead(implicit ev: Pair.LtEq[1, N]): A = coll.head 12 | final def safeLast(implicit ev: Pair.LtEq[1, N]): A = coll.last 13 | final def sizedTail(implicit ev: Pair.LtEq[1, N]): C[A, ev.Diff] = unsafeWrap(coll.tail) 14 | final def sizedInit(implicit ev: Pair.LtEq[1, N]): C[A, ev.Diff] = unsafeWrap(coll.init) 15 | final def sizedAppended[B >: A](value: B)(implicit ev: Pair[1, N]): C[B, ev.Sum] = unsafeWrap(coll.appended(value)) 16 | final def sizedPrepended[B >: A](value: B)(implicit ev: Pair[1, N]): C[B, ev.Sum] = unsafeWrap(coll.prepended(value)) 17 | final def sizedConcat[B >: A, O <: Int](other: C[B, O])(implicit ev: Pair[N, O]): C[B, ev.Sum] = unsafeWrap( 18 | coll ++ other 19 | ) 20 | 21 | final def sizedTake[X <: Int](implicit X: ValueOf[X], ev: Pair.LtEq[X, N]): C[A, X] = unsafeWrap(coll.take(X.value)) 22 | final def sizedTakeRight[X <: Int](implicit X: ValueOf[X], ev: Pair.LtEq[X, N]): C[A, X] = unsafeWrap( 23 | coll.takeRight(X.value) 24 | ) 25 | final def sizedDrop[X <: Int](implicit X: ValueOf[X], ev: Pair.LtEq[X, N]): C[A, ev.Diff] = unsafeWrap( 26 | coll.drop(X.value) 27 | ) 28 | final def sizedDropRight[X <: Int](implicit X: ValueOf[X], ev: Pair.LtEq[X, N]): C[A, ev.Diff] = unsafeWrap( 29 | coll.dropRight(X.value) 30 | ) 31 | 32 | protected def coll: U[A] 33 | protected[this] def unsafeWrap[A, N <: Int](value: U[A]): C[A, N] 34 | } 35 | 36 | private[sized] trait SizedOpsHelpers[U[+x] <: IndexedSeq[x] with IndexedSeqOps[x, U, U[x]]] 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sized collections for Scala 2.13 and Dotty 2 | 3 | [![Build status](https://img.shields.io/travis/travisbrown/sized/master.svg)](https://travis-ci.org/travisbrown/sized) 4 | [![Coverage status](https://img.shields.io/codecov/c/github/travisbrown/sized/master.svg)](https://codecov.io/github/travisbrown/sized) 5 | [![Maven Central](https://img.shields.io/maven-central/v/dev.travisbrown/sized-core_2.13.svg)](https://maven-badges.herokuapp.com/maven-central/dev.travisbrown/sized-core_2.13) 6 | 7 | ## What is it? 8 | 9 | This library provides a statically-sized wrapper for Scala 2.13's `IndexedSeq`: 10 | 11 | ```scala 12 | scala> import dev.travisbrown.sized._ 13 | 14 | scala> val xs = SizedVector(1, 2, 3, 4, 5) 15 | val xs: dev.travisbrown.sized.SizedVector[Int, 5] = SizedVector(1, 2, 3, 4, 5) 16 | 17 | scala> xs.sizedReverse.sizedTail.sizedMap(_.toString) 18 | val res0: dev.travisbrown.sized.SizedVector[String, 4] = SizedVector(4, 3, 2, 1) 19 | 20 | scala> xs[4] 21 | val res1: Int = 5 22 | 23 | scala> xs.sizedConcat(xs.sizedReverse) 24 | val res2: dev.travisbrown.sized.SizedVector[Int, 10] = SizedVector(1, 2, 3, 4, 5, 5, 4, 3, 2, 1) 25 | ``` 26 | 27 | All ordinary collections methods are available and return the underlying unsized type: 28 | 29 | ```scala 30 | scala> xs.toVector 31 | val res3: Vector[Int] = Vector(1, 2, 3, 4, 5) 32 | 33 | scala> xs.take(100) 34 | val res4: Vector[Int] = Vector(1, 2, 3, 4, 5) 35 | 36 | scala> xs.map(_ * 1000) 37 | val res5: Vector[Int] = Vector(1000, 2000, 3000, 4000, 5000) 38 | ``` 39 | 40 | Accessing out-of-bounds elements fails at compile time: 41 | 42 | ```scala 43 | scala> xs[-1] 44 | 1 |xs[-1] 45 | |^^^^^^ 46 | |Can't get element at a negative index 47 | 48 | scala> xs[10] 49 | 1 |xs[10] 50 | |^^^^^^ 51 | |Index out of bounds 52 | 53 | scala> xs.sizedDrop[5].safeHead 54 | 1 |xs.sizedDrop[5].safeHead 55 | |^^^^^^^^^^^^^^^^^^^^^^^^ 56 | |Can't take head of empty collection 57 | ``` 58 | 59 | This is all done without any macros (or custom type classes) on Dotty. Scala 2.13 requires a 60 | (fairly minimal) `Pair` type class with a macro-powered materializer. Neither version has any 61 | non-standard-library dependencies. 62 | 63 | ## Why? 64 | 65 | I've been wanting an excuse to experiment with implementing a collection type with Scala 2.13's 66 | [new collection library][scala-2.13-collections], and also an excuse to spend some time playing with 67 | the [new type-level singleton operations][dotty-singleton-ops] in Dotty. 68 | 69 | ## Other questions 70 | 71 | > What about Scala 2.12? 72 | 73 | Nope. 74 | 75 | > What about Scala.js? 76 | 77 | PRs are open. 78 | 79 | > What about other collection types? 80 | 81 | PRs are open. 82 | 83 | > Why not just use Shapeless's sized collections? 84 | 85 | `Sized` in [Shapeless][shapeless] is great but I want to represent lengths with `Int` singletons, not `Nat`. 86 | 87 | > Why not just use Refined? 88 | 89 | `Size[Equal[N]]` in [Refined][refined] is also great, but not having support for collections in `refineMV` 90 | means it can feel a little awkward to work with. 91 | 92 | ## Participation 93 | 94 | This project supports the [Scala code of conduct][code-of-conduct] and wants 95 | all of its channels (Gitter, GitHub, etc.) to be welcoming environments for everyone. 96 | 97 | ## License 98 | 99 | This project is licensed under the **[Apache License, Version 2.0][apache]** (the 100 | "License"); you may not use this software except in compliance with the License. 101 | 102 | Unless required by applicable law or agreed to in writing, software 103 | distributed under the License is distributed on an "AS IS" BASIS, 104 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 105 | See the License for the specific language governing permissions and 106 | limitations under the License. 107 | 108 | [apache]: http://www.apache.org/licenses/LICENSE-2.0 109 | [code-of-conduct]: https://www.scala-lang.org/conduct/ 110 | [dotty-singleton-ops]: https://github.com/lampepfl/dotty/pull/7628 111 | [refined]: https://github.com/fthomas/refined 112 | [scala-2.13-collections]: https://www.scala-lang.org/blog/2018/06/13/scala-213-collections.html 113 | [shapeless]: https://github.com/milessabin/shapeless -------------------------------------------------------------------------------- /src/main/scala/dev/travisbrown/sized/SizedIndexedSeqFactory.scala: -------------------------------------------------------------------------------- 1 | package dev.travisbrown.sized 2 | 3 | import scala.collection.StrictOptimizedSeqFactory 4 | import scala.collection.immutable.IndexedSeqOps 5 | 6 | trait SizedIndexedSeqFactory[U[+x] <: IndexedSeq[x] with IndexedSeqOps[x, U, U[x]], C[+_, _ <: Int]] 7 | extends StrictOptimizedSeqFactory[U] { 8 | private[sized] def unsafeWrap[A, N <: Int](value: U[A]): C[A, N] 9 | 10 | final def sizedEmpty[A]: C[A, 0] = unsafeWrap(empty) 11 | 12 | final def wrap[N <: Int]: PartiallyAppliedWrap[N] = new PartiallyAppliedWrap[N] 13 | 14 | final class PartiallyAppliedWrap[N <: Int] { 15 | def apply[A](value: U[A])(implicit N: ValueOf[N]): Option[C[A, N]] = 16 | if (value.length == N.value) Some(unsafeWrap(value)) else None 17 | } 18 | 19 | private[this] def unsafeApply[A, N <: Int](values: A*): C[A, N] = unsafeWrap { 20 | val builder = newBuilder[A] 21 | builder ++= values 22 | builder.result() 23 | } 24 | 25 | // format: off 26 | final def apply[A](): C[A, 0] = sizedEmpty 27 | final def apply[A](a0: A): C[A, 1] = unsafeApply(a0) 28 | final def apply[A](a0: A, a1: A): C[A, 2] = unsafeApply(a0, a1) 29 | final def apply[A](a0: A, a1: A, a2: A): C[A, 3] = unsafeApply(a0, a1, a2) 30 | final def apply[A](a0: A, a1: A, a2: A, a3: A): C[A, 4] = unsafeApply(a0, a1, a2, a3) 31 | final def apply[A](a0: A, a1: A, a2: A, a3: A, a4: A): C[A, 5] = unsafeApply(a0, a1, a2, a3, a4) 32 | final def apply[A](a0: A, a1: A, a2: A, a3: A, a4: A, a5: A): C[A, 6] = unsafeApply(a0, a1, a2, a3, a4, a5) 33 | final def apply[A](a0: A, a1: A, a2: A, a3: A, a4: A, a5: A, a6: A): C[A, 7] = unsafeApply(a0, a1, a2, a3, a4, a5, a6) 34 | final def apply[A](a0: A, a1: A, a2: A, a3: A, a4: A, a5: A, a6: A, a7: A): C[A, 8] = unsafeApply(a0, a1, a2, a3, a4, a5, a6, a7) 35 | final def apply[A](a0: A, a1: A, a2: A, a3: A, a4: A, a5: A, a6: A, a7: A, a8: A): C[A, 9] = unsafeApply(a0, a1, a2, a3, a4, a5, a6, a7, a8) 36 | final def apply[A](a0: A, a1: A, a2: A, a3: A, a4: A, a5: A, a6: A, a7: A, a8: A, a9: A): C[A, 10] = unsafeApply(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) 37 | final def apply[A](a0: A, a1: A, a2: A, a3: A, a4: A, a5: A, a6: A, a7: A, a8: A, a9: A, a10: A): C[A, 11] = unsafeApply(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) 38 | final def apply[A](a0: A, a1: A, a2: A, a3: A, a4: A, a5: A, a6: A, a7: A, a8: A, a9: A, a10: A, a11: A): C[A, 12] = unsafeApply(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) 39 | final def apply[A](a0: A, a1: A, a2: A, a3: A, a4: A, a5: A, a6: A, a7: A, a8: A, a9: A, a10: A, a11: A, a12: A): C[A, 13] = unsafeApply(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) 40 | final def apply[A](a0: A, a1: A, a2: A, a3: A, a4: A, a5: A, a6: A, a7: A, a8: A, a9: A, a10: A, a11: A, a12: A, a13: A): C[A, 14] = unsafeApply(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13) 41 | final def apply[A](a0: A, a1: A, a2: A, a3: A, a4: A, a5: A, a6: A, a7: A, a8: A, a9: A, a10: A, a11: A, a12: A, a13: A, a14: A): C[A, 15] = unsafeApply(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14) 42 | final def apply[A]( a0: A, a1: A, a2: A, a3: A, a4: A, a5: A, a6: A, a7: A, a8: A, a9: A, a10: A, a11: A, a12: A, a13: A, a14: A, a15: A): C[A, 16] = unsafeApply(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) 43 | final def apply[A]( a0: A, a1: A, a2: A, a3: A, a4: A, a5: A, a6: A, a7: A, a8: A, a9: A, a10: A, a11: A, a12: A, a13: A, a14: A, a15: A, a16: A): C[A, 17] = unsafeApply(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16) 44 | final def apply[A]( a0: A, a1: A, a2: A, a3: A, a4: A, a5: A, a6: A, a7: A, a8: A, a9: A, a10: A, a11: A, a12: A, a13: A, a14: A, a15: A, a16: A, a17: A): C[A, 18] = unsafeApply(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17) 45 | final def apply[A]( a0: A, a1: A, a2: A, a3: A, a4: A, a5: A, a6: A, a7: A, a8: A, a9: A, a10: A, a11: A, a12: A, a13: A, a14: A, a15: A, a16: A, a17: A, a18: A): C[A, 19] = unsafeApply(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18) 46 | final def apply[A]( a0: A, a1: A, a2: A, a3: A, a4: A, a5: A, a6: A, a7: A, a8: A, a9: A, a10: A, a11: A, a12: A, a13: A, a14: A, a15: A, a16: A, a17: A, a18: A, a19: A): C[A, 20] = unsafeApply(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19) 47 | final def apply[A]( a0: A, a1: A, a2: A, a3: A, a4: A, a5: A, a6: A, a7: A, a8: A, a9: A, a10: A, a11: A, a12: A, a13: A, a14: A, a15: A, a16: A, a17: A, a18: A, a19: A, a20: A): C[A, 21] = unsafeApply(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) 48 | final def apply[A](a0: A, a1: A, a2: A, a3: A, a4: A, a5: A, a6: A, a7: A, a8: A, a9: A, a10: A, a11: A, a12: A, a13: A, a14: A, a15: A, a16: A, a17: A, a18: A, a19: A, a20: A, a21: A): C[A, 22] = unsafeApply(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21) 49 | // format: on 50 | } 51 | -------------------------------------------------------------------------------- /src/main/scala-0.24/dev/travisbrown/sized/SizedOps.scala: -------------------------------------------------------------------------------- 1 | package dev.travisbrown.sized 2 | 3 | import scala.collection.immutable.IndexedSeqOps 4 | import scala.compiletime.{constValue, error} 5 | import scala.compiletime.ops.int._ 6 | 7 | trait SizedOps[+A, U[+x], N <: Int, C[+x, _ <: Int] <: IndexedSeqOps[x, U, U[x]]] { 8 | protected def coll: U[A] 9 | 10 | inline final def apply[X <: Int]: A = inline constValue[X] match { 11 | case x if x < 0 => error("Can't get element at a negative index") 12 | case x => 13 | inline constValue[N] match { 14 | case n if x < n => unsizedApply(coll, x) 15 | case _ => error("Index out of bounds") 16 | } 17 | } 18 | 19 | inline final def safeHead: A = inline constValue[N] match { 20 | case n if n > 0 => unsizedHead(coll) 21 | case _ => error("Can't take head of empty collection") 22 | } 23 | 24 | inline final def safeLast: A = inline constValue[N] match { 25 | case n if n > 0 => unsizedLast(coll) 26 | case _ => error("Can't take head of empty collection") 27 | } 28 | 29 | inline final def sizedTail: C[A, N - 1] = inline constValue[N] match { 30 | case n if n > 0 => unsafeWrap(unsizedTail(coll)) 31 | case _ => error("Can't take tail of empty collection") 32 | } 33 | 34 | inline final def sizedInit: C[A, N - 1] = inline constValue[N] match { 35 | case n if n > 0 => unsafeWrap(unsizedInit(coll)) 36 | case _ => error("Can't take init of empty collection") 37 | } 38 | 39 | final def sizedAppended[B >: A](value: B): C[B, N + 1] = unsafeWrap(unsizedAppended(coll, value)) 40 | final def sizedPrepended[B >: A](value: B): C[B, N + 1] = unsafeWrap(unsizedPrepended(coll, value)) 41 | final def sizedConcat[B >: A, O <: Int](other: C[B, O]): C[B, N + O] = unsafeWrap(unsizedConcat(coll, other)) 42 | 43 | inline final def sizedTake[X <: Int]: C[A, X] = inline constValue[X] match { 44 | case x if x < 0 => error("Can't take a negative number of elements") 45 | case x => 46 | inline constValue[N] match { 47 | case n if x <= n => unsafeWrap(unsizedTake(coll, x)) 48 | case _ => error("Can't take more elements than the size of the collection") 49 | } 50 | } 51 | 52 | inline final def sizedTakeRight[X <: Int]: C[A, X] = inline constValue[X] match { 53 | case x if x < 0 => error("Can't take a negative number of elements") 54 | case x => 55 | inline constValue[N] match { 56 | case n if x <= n => unsafeWrap(unsizedTakeRight(coll, x)) 57 | case _ => error("Can't take more elements than the size of the collection") 58 | } 59 | } 60 | 61 | inline final def sizedDrop[X <: Int]: C[A, N - X] = inline constValue[X] match { 62 | case x if x < 0 => error("Can't drop a negative number of elements") 63 | case x => 64 | inline constValue[N] match { 65 | case n if x <= n => unsafeWrap(unsizedDrop(coll, x)) 66 | case _ => error("Can't drop more elements than the size of the collection") 67 | } 68 | } 69 | 70 | inline final def sizedDropRight[X <: Int]: C[A, N - X] = inline constValue[X] match { 71 | case x if x < 0 => error("Can't drop a negative number of elements") 72 | case x => 73 | inline constValue[N] match { 74 | case n if x <= n => unsafeWrap(unsizedDropRight(coll, x)) 75 | case _ => error("Can't drop more elements than the size of the collection") 76 | } 77 | } 78 | 79 | protected[this] def unsafeWrap[A, N <: Int](value: U[A]): C[A, N] 80 | protected[this] def unsizedApply[A](coll: U[A], n: Int): A 81 | protected[this] def unsizedHead[A](coll: U[A]): A 82 | protected[this] def unsizedLast[A](coll: U[A]): A 83 | protected[this] def unsizedTail[A](coll: U[A]): U[A] 84 | protected[this] def unsizedInit[A](coll: U[A]): U[A] 85 | protected[this] def unsizedAppended[A, B >: A](coll: U[A], value: B): U[B] 86 | protected[this] def unsizedPrepended[A, B >: A](coll: U[A], value: B): U[B] 87 | protected[this] def unsizedConcat[A, B >: A](coll: U[A], other: IndexedSeqOps[B, U, U[B]]): U[B] 88 | protected[this] def unsizedTake[A](coll: U[A], n: Int): U[A] 89 | protected[this] def unsizedTakeRight[A](coll: U[A], n: Int): U[A] 90 | protected[this] def unsizedDrop[A](coll: U[A], n: Int): U[A] 91 | protected[this] def unsizedDropRight[A](coll: U[A], n: Int): U[A] 92 | } 93 | 94 | private[sized] trait SizedOpsHelpers[U[+x] <: IndexedSeq[x] with IndexedSeqOps[x, U, U[x]]] { 95 | // These methods are currently necessary to work around a Dotty bug. 96 | final protected[this] def unsizedApply[A](coll: U[A], n: Int): A = coll(n) 97 | final protected[this] def unsizedHead[A](coll: U[A]): A = coll.head 98 | final protected[this] def unsizedLast[A](coll: U[A]): A = coll.last 99 | final protected[this] def unsizedTail[A](coll: U[A]): U[A] = coll.tail 100 | final protected[this] def unsizedInit[A](coll: U[A]): U[A] = coll.init 101 | final protected[this] def unsizedAppended[A, B >: A](coll: U[A], value: B): U[B] = coll.appended(value) 102 | final protected[this] def unsizedPrepended[A, B >: A](coll: U[A], value: B): U[B] = coll.prepended(value) 103 | final protected[this] def unsizedConcat[A, B >: A](coll: U[A], other: IndexedSeqOps[B, U, U[B]]): U[B] = coll ++ other 104 | final protected[this] def unsizedTake[A](coll: U[A], n: Int): U[A] = coll.take(n) 105 | final protected[this] def unsizedTakeRight[A](coll: U[A], n: Int): U[A] = coll.takeRight(n) 106 | final protected[this] def unsizedDrop[A](coll: U[A], n: Int): U[A] = coll.drop(n) 107 | final protected[this] def unsizedDropRight[A](coll: U[A], n: Int): U[A] = coll.dropRight(n) 108 | } 109 | -------------------------------------------------------------------------------- /src/test/scala/dev/travisbrown/sized/SizedIndexedSeqSuite.scala: -------------------------------------------------------------------------------- 1 | package dev.travisbrown.sized 2 | 3 | import org.scalatest.funsuite.AnyFunSuite 4 | import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks 5 | import scala.collection.immutable.ArraySeq 6 | 7 | class SizedIndexedSeqSuite extends AnyFunSuite with ScalaCheckDrivenPropertyChecks { 8 | test("SizedVector.wrap should only succeed if the input has the right length") { 9 | assert(SizedVector.wrap[4](Vector(1, 2, 3, 4)).map(_.unsized) === Some(Vector(1, 2, 3, 4))) 10 | 11 | forAll { (wrapped: Vector[String]) => 12 | val expected = if (wrapped.length == 1) Some(wrapped) else None 13 | assert(SizedVector.wrap[1](wrapped).map(_.unsized) === expected) 14 | } 15 | } 16 | 17 | test("SizedArraySeq.wrap should only succeed if the input has the right length") { 18 | assert(SizedArraySeq.wrap[4](ArraySeq(1, 2, 3, 4)).map(_.unsized) === Some(ArraySeq(1, 2, 3, 4))) 19 | 20 | forAll { (wrapped: ArraySeq[String]) => 21 | val expected = if (wrapped.length == 1) Some(wrapped) else None 22 | assert(SizedArraySeq.wrap[1](wrapped).map(_.unsized) === expected) 23 | } 24 | } 25 | 26 | test("sizedEmpty should return an empty collection") { 27 | val e0: SizedVector[String, 0] = SizedVector.sizedEmpty[String] 28 | val e1: SizedArraySeq[String, 0] = SizedArraySeq.sizedEmpty[String] 29 | 30 | assert(e0.unsized === Vector.empty[String]) 31 | assert(e1.unsized === ArraySeq.empty[String]) 32 | } 33 | 34 | // Sorry I got lazy. 35 | test("sized methods should work") { 36 | val xs0: SizedVector[String, 0] = SizedVector.sizedEmpty[String] 37 | val xs1: SizedVector[String, 3] = SizedVector("a", "b", "c") 38 | 39 | assert(xs1[2] === xs1(2)) 40 | assert(xs1.safeHead === xs1.head) 41 | assert(xs1.safeLast === xs1.last) 42 | assert(xs1.sizedTail.unsized === xs1.tail) 43 | assert(xs1.sizedInit.unsized === xs1.init) 44 | 45 | val result0: SizedVector[String, 3] = xs0.sizedConcat(xs1) 46 | val result1: SizedVector[String, 6] = xs1.sizedConcat(xs1) 47 | val result2: SizedVector[String, 2] = xs1.sizedTake[2] 48 | val result3: SizedVector[String, 2] = xs1.sizedDrop[1] 49 | val result4: SizedVector[String, 1] = xs1.sizedTakeRight[1] 50 | val result5: SizedVector[String, 1] = xs1.sizedDropRight[2] 51 | val result6: SizedVector[Int, 3] = xs1.sizedMap(_.length) 52 | val result7: SizedVector[String, 4] = xs1.sizedAppended("z") 53 | val result8: SizedVector[String, 4] = xs1.sizedPrepended("z") 54 | val result9: SizedVector[String, 3] = xs1.sizedReverse 55 | 56 | assert(result0.unsized === (xs0 ++ xs1)) 57 | assert(result1.unsized === (xs1 ++ xs1)) 58 | assert(result2.unsized === xs1.take(2)) 59 | assert(result3.unsized === xs1.drop(1)) 60 | assert(result4.unsized === xs1.takeRight(1)) 61 | assert(result5.unsized === xs1.dropRight(2)) 62 | assert(result6.unsized === xs1.map(_.length)) 63 | assert(result7.unsized === (xs1 :+ "z")) 64 | assert(result8.unsized === ("z" +: xs1)) 65 | assert(result9.unsized === xs1.reverse) 66 | } 67 | 68 | test("Sized apply methods should work") { 69 | val xs0: SizedVector[Int, 0] = SizedVector() 70 | val xs1: SizedVector[Int, 1] = SizedVector(1) 71 | val xs2: SizedVector[Int, 2] = SizedVector(1, 1) 72 | val xs3: SizedVector[Int, 3] = SizedVector(1, 1, 1) 73 | val xs4: SizedVector[Int, 4] = SizedVector(1, 1, 1, 1) 74 | val xs5: SizedVector[Int, 5] = SizedVector(1, 1, 1, 1, 1) 75 | val xs6: SizedVector[Int, 6] = SizedVector(1, 1, 1, 1, 1, 1) 76 | val xs7: SizedVector[Int, 7] = SizedVector(1, 1, 1, 1, 1, 1, 1) 77 | val xs8: SizedVector[Int, 8] = SizedVector(1, 1, 1, 1, 1, 1, 1, 1) 78 | val xs9: SizedVector[Int, 9] = SizedVector(1, 1, 1, 1, 1, 1, 1, 1, 1) 79 | val xs10: SizedVector[Int, 10] = SizedVector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1) 80 | val xs11: SizedVector[Int, 11] = SizedVector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) 81 | val xs12: SizedVector[Int, 12] = SizedVector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) 82 | val xs13: SizedVector[Int, 13] = SizedVector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) 83 | val xs14: SizedVector[Int, 14] = SizedVector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) 84 | val xs15: SizedVector[Int, 15] = SizedVector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) 85 | val xs16: SizedVector[Int, 16] = SizedVector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) 86 | val xs17: SizedVector[Int, 17] = SizedVector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) 87 | val xs18: SizedVector[Int, 18] = SizedVector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) 88 | val xs19: SizedVector[Int, 19] = SizedVector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) 89 | val xs20: SizedVector[Int, 20] = SizedVector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) 90 | val xs21: SizedVector[Int, 21] = SizedVector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) 91 | val xs22: SizedVector[Int, 22] = SizedVector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) 92 | 93 | assert(xs0.unsized === Vector.fill(0)(1)) 94 | assert(xs1.unsized === Vector.fill(1)(1)) 95 | assert(xs2.unsized === Vector.fill(2)(1)) 96 | assert(xs3.unsized === Vector.fill(3)(1)) 97 | assert(xs4.unsized === Vector.fill(4)(1)) 98 | assert(xs5.unsized === Vector.fill(5)(1)) 99 | assert(xs6.unsized === Vector.fill(6)(1)) 100 | assert(xs7.unsized === Vector.fill(7)(1)) 101 | assert(xs8.unsized === Vector.fill(8)(1)) 102 | assert(xs9.unsized === Vector.fill(9)(1)) 103 | assert(xs10.unsized === Vector.fill(10)(1)) 104 | assert(xs11.unsized === Vector.fill(11)(1)) 105 | assert(xs12.unsized === Vector.fill(12)(1)) 106 | assert(xs13.unsized === Vector.fill(13)(1)) 107 | assert(xs14.unsized === Vector.fill(14)(1)) 108 | assert(xs15.unsized === Vector.fill(15)(1)) 109 | assert(xs16.unsized === Vector.fill(16)(1)) 110 | assert(xs17.unsized === Vector.fill(17)(1)) 111 | assert(xs18.unsized === Vector.fill(18)(1)) 112 | assert(xs19.unsized === Vector.fill(19)(1)) 113 | assert(xs20.unsized === Vector.fill(20)(1)) 114 | assert(xs21.unsized === Vector.fill(21)(1)) 115 | assert(xs22.unsized === Vector.fill(22)(1)) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | --------------------------------------------------------------------------------