summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2018-08-26 21:31:39 +0800
committerLi Haoyi <haoyi.sg@gmail.com>2018-08-26 21:31:39 +0800
commit4fc6204a01b8a283c0362f9f3244e93b6de65630 (patch)
tree9863bd2960f845b7fe496a1ab938ab208f4d19ad
parent84b89ff6ccb1cc1b71d1ae20b914f9a61a0209ab (diff)
downloadcask-4fc6204a01b8a283c0362f9f3244e93b6de65630.tar.gz
cask-4fc6204a01b8a283c0362f9f3244e93b6de65630.tar.bz2
cask-4fc6204a01b8a283c0362f9f3244e93b6de65630.zip
0.1.7: micro-optimizations to remove trivially unnecessary bottlenecks0.1.7
-rw-r--r--build.sc2
-rw-r--r--cask/src/cask/endpoints/WebEndpoints.scala16
-rw-r--r--cask/src/cask/internal/Router.scala26
-rw-r--r--cask/src/cask/internal/Util.scala30
-rw-r--r--cask/src/cask/main/Main.scala25
-rw-r--r--cask/test/src/test/cask/UtilTests.scala22
-rw-r--r--example/compress/build.sc2
-rw-r--r--example/compress2/build.sc2
-rw-r--r--example/compress3/build.sc2
-rw-r--r--example/cookies/build.sc2
-rw-r--r--example/decorated/build.sc2
-rw-r--r--example/decorated2/build.sc2
-rw-r--r--example/endpoints/build.sc2
-rw-r--r--example/formJsonPost/build.sc2
-rw-r--r--example/httpMethods/build.sc2
-rw-r--r--example/minimalApplication/build.sc2
-rw-r--r--example/minimalApplication2/build.sc2
-rw-r--r--example/redirectAbort/build.sc2
-rw-r--r--example/scalatags/build.sc2
-rw-r--r--example/staticFiles/build.sc2
-rw-r--r--example/todo/build.sc2
-rw-r--r--example/todoApi/build.sc2
-rw-r--r--example/todoDb/build.sc2
-rw-r--r--example/twirl/build.sc2
-rw-r--r--example/variableRoutes/build.sc2
-rw-r--r--example/websockets/build.sc2
26 files changed, 116 insertions, 45 deletions
diff --git a/build.sc b/build.sc
index 3d0b375..dfe0380 100644
--- a/build.sc
+++ b/build.sc
@@ -51,7 +51,7 @@ object cask extends ScalaModule with PublishModule {
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
ivy"org.xerial:sqlite-jdbc:3.18.0",
ivy"io.getquill::quill-jdbc:2.5.4"
)
diff --git a/cask/src/cask/endpoints/WebEndpoints.scala b/cask/src/cask/endpoints/WebEndpoints.scala
index 9fe28a0..ab3b480 100644
--- a/cask/src/cask/endpoints/WebEndpoints.scala
+++ b/cask/src/cask/endpoints/WebEndpoints.scala
@@ -13,12 +13,16 @@ trait WebEndpoint extends Endpoint{
type InputParser[T] = QueryParamReader[T]
def wrapFunction(ctx: Request,
delegate: Map[String, Input] => Router.Result[Output]): Router.Result[Response] = {
- delegate(
- ctx.exchange.getQueryParameters
- .asScala
- .map{case (k, vs) => (k, vs.asScala.toArray.toSeq)}
- .toMap
- )
+
+ val b = Map.newBuilder[String, Seq[String]]
+ val queryParams = ctx.exchange.getQueryParameters
+ for(k <- queryParams.keySet().iterator().asScala){
+ val deque = queryParams.get(k)
+ val arr = new Array[String](deque.size)
+ deque.toArray(arr)
+ b += (k -> (arr: Seq[String]))
+ }
+ delegate(b.result())
}
def wrapPathSegment(s: String) = Seq(s)
}
diff --git a/cask/src/cask/internal/Router.scala b/cask/src/cask/internal/Router.scala
index 9fa9b60..64af4cd 100644
--- a/cask/src/cask/internal/Router.scala
+++ b/cask/src/cask/internal/Router.scala
@@ -2,6 +2,7 @@ package cask.internal
import language.experimental.macros
import scala.annotation.StaticAnnotation
+import scala.collection.mutable
import scala.reflect.macros.blackbox.Context
/**
@@ -44,14 +45,25 @@ object Router{
argSignatures: Seq[Seq[ArgSig[_, T, _, C]]],
doc: Option[String],
invoke0: (T, C, Seq[Map[String, Any]], Seq[Seq[ArgSig[Any, _, _, C]]]) => Result[Any]){
+
+ val firstArgs = argSignatures.head
+ .map(x => x.name -> x)
+ .toMap[String, Router.ArgSig[_, T, _, C]]
+
def invoke(target: T,
ctx: C,
paramLists: Seq[Map[String, Any]]): Result[Any] = {
- val unknown = paramLists.head.keySet -- argSignatures.head.map(_.name).toSet
- val missing = argSignatures.head.filter(as =>
- as.reads.arity != 0 && !paramLists.head.contains(as.name) && as.default.isEmpty
- )
+ val missing = mutable.Buffer.empty[Router.ArgSig[_, T, _, C]]
+
+ val unknown = paramLists.head.keys.filter(!firstArgs.contains(_))
+
+ for(k <- firstArgs.keys) {
+ if (!paramLists.head.contains(k)) {
+ val as = firstArgs(k)
+ if (as.reads.arity != 0 && as.default.isEmpty) missing.append(as)
+ }
+ }
if (missing.nonEmpty || unknown.nonEmpty) Result.Error.MismatchedArguments(missing, unknown.toSeq)
else {
@@ -313,9 +325,9 @@ class Router[C <: Context](val c: C) {
${method.name.toString},
${argSigs.toList},
${methodDoc match{
- case None => q"scala.None"
- case Some(s) => q"scala.Some($s)"
- }},
+ case None => q"scala.None"
+ case Some(s) => q"scala.Some($s)"
+ }},
(
$baseArgSym: $curCls,
$ctxSymbol: $ctx,
diff --git a/cask/src/cask/internal/Util.scala b/cask/src/cask/internal/Util.scala
index 7da343e..431944a 100644
--- a/cask/src/cask/internal/Util.scala
+++ b/cask/src/cask/internal/Util.scala
@@ -54,8 +54,34 @@ object Util {
def pluralize(s: String, n: Int) = {
if (n == 1) s else s + "s"
}
- def splitPath(p: String) = {
- p.dropWhile(_ == '/').reverse.dropWhile(_ == '/').reverse.split('/').filter(_.nonEmpty)
+
+ /**
+ * Splits a string into path segments; automatically removes all
+ * leading/trailing slashes, and ignores empty path segments.
+ *
+ * Written imperatively for performance since it's used all over the place.
+ */
+ def splitPath(p: String): IndexedSeq[String] = {
+ val pLength = p.length
+ var i = 0
+ while(i < pLength && p(i) == '/') i += 1
+ var segmentStart = i
+ val out = mutable.ArrayBuffer.empty[String]
+
+ def complete() = {
+ if (i != segmentStart) {
+ val s = p.substring(segmentStart, i)
+ out += s
+ }
+ segmentStart = i + 1
+ }
+
+ while(i < pLength){
+ if (p(i) == '/') complete()
+ i += 1
+ }
+ complete()
+ out
}
def stackTraceString(e: Throwable) = {
diff --git a/cask/src/cask/main/Main.scala b/cask/src/cask/main/Main.scala
index 5c0b120..e12683f 100644
--- a/cask/src/cask/main/Main.scala
+++ b/cask/src/cask/main/Main.scala
@@ -78,26 +78,33 @@ abstract class BaseMain{
writeResponseHandler(r).handleRequest(exchange)
}
)
- } else {
- exchange.getRequestMethod.toString.toLowerCase() -> ((r: Any) => writeResponse(exchange, r.asInstanceOf[Response]))
- }
+ } else (
+ exchange.getRequestMethod.toString.toLowerCase(),
+ (r: Any) => writeResponse(exchange, r.asInstanceOf[Response])
+ )
routeTries(effectiveMethod).lookup(Util.splitPath(exchange.getRequestPath).toList, Map()) match {
- case None =>
- writeResponse(exchange, handleNotFound())
- case Some(((routes, metadata), extBindings, remaining)) =>
+ case None => writeResponse(exchange, handleNotFound())
+ case Some(((routes, metadata), routeBindings, remaining)) =>
val ctx = Request(exchange, remaining)
def rec(remaining: List[Decorator],
bindings: List[Map[String, Any]]): Router.Result[Any] = try {
remaining match {
case head :: rest =>
- head.wrapFunction(ctx, args => rec(rest, args :: bindings).asInstanceOf[Router.Result[head.Output]])
+ head.wrapFunction(
+ ctx,
+ args => rec(rest, args :: bindings).asInstanceOf[Router.Result[head.Output]]
+ )
case Nil =>
- metadata.endpoint.wrapFunction(ctx, epBindings =>
+ metadata.endpoint.wrapFunction(ctx, endpointBindings =>
metadata.entryPoint
.asInstanceOf[EntryPoint[cask.main.Routes, cask.model.Request]]
- .invoke(routes, ctx, (epBindings ++ extBindings.mapValues(metadata.endpoint.wrapPathSegment)) :: bindings.reverse)
+ .invoke(
+ routes, ctx,
+ (endpointBindings ++ routeBindings.mapValues(metadata.endpoint.wrapPathSegment))
+ :: bindings.reverse
+ )
.asInstanceOf[Router.Result[Nothing]]
)
}
diff --git a/cask/test/src/test/cask/UtilTests.scala b/cask/test/src/test/cask/UtilTests.scala
new file mode 100644
index 0000000..7b34434
--- /dev/null
+++ b/cask/test/src/test/cask/UtilTests.scala
@@ -0,0 +1,22 @@
+package test.cask
+
+import utest._
+
+object UtilTests extends TestSuite {
+ val tests = Tests{
+ 'splitPath - {
+ cask.internal.Util.splitPath("") ==> Seq()
+ cask.internal.Util.splitPath("/") ==> Seq()
+ cask.internal.Util.splitPath("////") ==> Seq()
+
+ cask.internal.Util.splitPath("abc") ==> Seq("abc")
+ cask.internal.Util.splitPath("/abc/") ==> Seq("abc")
+ cask.internal.Util.splitPath("//abc") ==> Seq("abc")
+ cask.internal.Util.splitPath("abc//") ==> Seq("abc")
+
+ cask.internal.Util.splitPath("abc//def") ==> Seq("abc", "def")
+ cask.internal.Util.splitPath("//abc//def//") ==> Seq("abc", "def")
+ }
+ }
+}
+
diff --git a/example/compress/build.sc b/example/compress/build.sc
index e5faf4b..03421a3 100644
--- a/example/compress/build.sc
+++ b/example/compress/build.sc
@@ -12,7 +12,7 @@ trait AppModule extends ScalaModule{
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
)
}
} \ No newline at end of file
diff --git a/example/compress2/build.sc b/example/compress2/build.sc
index e5faf4b..03421a3 100644
--- a/example/compress2/build.sc
+++ b/example/compress2/build.sc
@@ -12,7 +12,7 @@ trait AppModule extends ScalaModule{
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
)
}
} \ No newline at end of file
diff --git a/example/compress3/build.sc b/example/compress3/build.sc
index e5faf4b..03421a3 100644
--- a/example/compress3/build.sc
+++ b/example/compress3/build.sc
@@ -12,7 +12,7 @@ trait AppModule extends ScalaModule{
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
)
}
} \ No newline at end of file
diff --git a/example/cookies/build.sc b/example/cookies/build.sc
index e5faf4b..03421a3 100644
--- a/example/cookies/build.sc
+++ b/example/cookies/build.sc
@@ -12,7 +12,7 @@ trait AppModule extends ScalaModule{
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
)
}
} \ No newline at end of file
diff --git a/example/decorated/build.sc b/example/decorated/build.sc
index e5faf4b..03421a3 100644
--- a/example/decorated/build.sc
+++ b/example/decorated/build.sc
@@ -12,7 +12,7 @@ trait AppModule extends ScalaModule{
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
)
}
} \ No newline at end of file
diff --git a/example/decorated2/build.sc b/example/decorated2/build.sc
index e5faf4b..03421a3 100644
--- a/example/decorated2/build.sc
+++ b/example/decorated2/build.sc
@@ -12,7 +12,7 @@ trait AppModule extends ScalaModule{
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
)
}
} \ No newline at end of file
diff --git a/example/endpoints/build.sc b/example/endpoints/build.sc
index e5faf4b..03421a3 100644
--- a/example/endpoints/build.sc
+++ b/example/endpoints/build.sc
@@ -12,7 +12,7 @@ trait AppModule extends ScalaModule{
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
)
}
} \ No newline at end of file
diff --git a/example/formJsonPost/build.sc b/example/formJsonPost/build.sc
index e5faf4b..03421a3 100644
--- a/example/formJsonPost/build.sc
+++ b/example/formJsonPost/build.sc
@@ -12,7 +12,7 @@ trait AppModule extends ScalaModule{
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
)
}
} \ No newline at end of file
diff --git a/example/httpMethods/build.sc b/example/httpMethods/build.sc
index e5faf4b..03421a3 100644
--- a/example/httpMethods/build.sc
+++ b/example/httpMethods/build.sc
@@ -12,7 +12,7 @@ trait AppModule extends ScalaModule{
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
)
}
} \ No newline at end of file
diff --git a/example/minimalApplication/build.sc b/example/minimalApplication/build.sc
index e5faf4b..03421a3 100644
--- a/example/minimalApplication/build.sc
+++ b/example/minimalApplication/build.sc
@@ -12,7 +12,7 @@ trait AppModule extends ScalaModule{
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
)
}
} \ No newline at end of file
diff --git a/example/minimalApplication2/build.sc b/example/minimalApplication2/build.sc
index e5faf4b..03421a3 100644
--- a/example/minimalApplication2/build.sc
+++ b/example/minimalApplication2/build.sc
@@ -12,7 +12,7 @@ trait AppModule extends ScalaModule{
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
)
}
} \ No newline at end of file
diff --git a/example/redirectAbort/build.sc b/example/redirectAbort/build.sc
index e5faf4b..03421a3 100644
--- a/example/redirectAbort/build.sc
+++ b/example/redirectAbort/build.sc
@@ -12,7 +12,7 @@ trait AppModule extends ScalaModule{
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
)
}
} \ No newline at end of file
diff --git a/example/scalatags/build.sc b/example/scalatags/build.sc
index 12e8ff9..cf8b34c 100644
--- a/example/scalatags/build.sc
+++ b/example/scalatags/build.sc
@@ -13,7 +13,7 @@ trait AppModule extends ScalaModule{
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
)
}
} \ No newline at end of file
diff --git a/example/staticFiles/build.sc b/example/staticFiles/build.sc
index 4f4716d..4040676 100644
--- a/example/staticFiles/build.sc
+++ b/example/staticFiles/build.sc
@@ -14,7 +14,7 @@ trait AppModule extends ScalaModule{
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
)
def forkWorkingDir = build.millSourcePath
diff --git a/example/todo/build.sc b/example/todo/build.sc
index 37e5253..a71a287 100644
--- a/example/todo/build.sc
+++ b/example/todo/build.sc
@@ -15,7 +15,7 @@ trait AppModule extends ScalaModule{
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
)
}
} \ No newline at end of file
diff --git a/example/todoApi/build.sc b/example/todoApi/build.sc
index e5faf4b..03421a3 100644
--- a/example/todoApi/build.sc
+++ b/example/todoApi/build.sc
@@ -12,7 +12,7 @@ trait AppModule extends ScalaModule{
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
)
}
} \ No newline at end of file
diff --git a/example/todoDb/build.sc b/example/todoDb/build.sc
index 52ac761..77e580e 100644
--- a/example/todoDb/build.sc
+++ b/example/todoDb/build.sc
@@ -14,7 +14,7 @@ trait AppModule extends ScalaModule{
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
)
}
} \ No newline at end of file
diff --git a/example/twirl/build.sc b/example/twirl/build.sc
index 55ea562..646bea7 100644
--- a/example/twirl/build.sc
+++ b/example/twirl/build.sc
@@ -17,7 +17,7 @@ trait AppModule extends ScalaModule with mill.twirllib.TwirlModule{
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
)
}
} \ No newline at end of file
diff --git a/example/variableRoutes/build.sc b/example/variableRoutes/build.sc
index e5faf4b..03421a3 100644
--- a/example/variableRoutes/build.sc
+++ b/example/variableRoutes/build.sc
@@ -12,7 +12,7 @@ trait AppModule extends ScalaModule{
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
)
}
} \ No newline at end of file
diff --git a/example/websockets/build.sc b/example/websockets/build.sc
index ef595b1..909c6b1 100644
--- a/example/websockets/build.sc
+++ b/example/websockets/build.sc
@@ -12,7 +12,7 @@ trait AppModule extends ScalaModule{
def ivyDeps = Agg(
ivy"com.lihaoyi::utest::0.6.3",
- ivy"com.lihaoyi::requests::0.1.3",
+ ivy"com.lihaoyi::requests::0.1.5",
ivy"org.asynchttpclient:async-http-client:2.5.2"
)
}