diff options
author | Li Haoyi <haoyi.sg@gmail.com> | 2018-08-26 21:31:39 +0800 |
---|---|---|
committer | Li Haoyi <haoyi.sg@gmail.com> | 2018-08-26 21:31:39 +0800 |
commit | 4fc6204a01b8a283c0362f9f3244e93b6de65630 (patch) | |
tree | 9863bd2960f845b7fe496a1ab938ab208f4d19ad /cask/src | |
parent | 84b89ff6ccb1cc1b71d1ae20b914f9a61a0209ab (diff) | |
download | cask-4fc6204a01b8a283c0362f9f3244e93b6de65630.tar.gz cask-4fc6204a01b8a283c0362f9f3244e93b6de65630.tar.bz2 cask-4fc6204a01b8a283c0362f9f3244e93b6de65630.zip |
0.1.7: micro-optimizations to remove trivially unnecessary bottlenecks0.1.7
Diffstat (limited to 'cask/src')
-rw-r--r-- | cask/src/cask/endpoints/WebEndpoints.scala | 16 | ||||
-rw-r--r-- | cask/src/cask/internal/Router.scala | 26 | ||||
-rw-r--r-- | cask/src/cask/internal/Util.scala | 30 | ||||
-rw-r--r-- | cask/src/cask/main/Main.scala | 25 |
4 files changed, 73 insertions, 24 deletions
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]] ) } |