{"action":"created","comment":{"url":"https://api.github.com/repos/willb/silex/pulls/comments/34075449","id":34075449,"diff_hunk":"@@ -0,0 +1,400 @@\n+/*\n+ * This file is part of the \"silex\" library of helpers for Apache Spark.\n+ *\n+ * Copyright (c) 2015 Red Hat, Inc.\n+ * \n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ * \n+ *      http://www.apache.org/licenses/LICENSE-2.0\n+ * \n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.c\n+ */\n+\n+package com.redhat.et.silex.feature.indexfunction\n+\n+import scala.language.implicitConversions\n+\n+/** An index function is a (partial) function from some subset of collection indices to \n+  * some values, and which can be concatenated with other such functions such that they \n+  * now cover an expanded index range, and the \"right\" side function has had its domain\n+  * shifted.  An index function is defined on an index interval with a particular width,\n+  * and its domain is some subset of that interval.\n+  *\n+  * @tparam V The type of value returned by this function.\n+  */\n+abstract class IndexFunction[V] extends PartialFunction[Int, V] with Serializable { self =>\n+\n+  /** The width of the integer index interval that contains the [[domain]].  All indices this\n+    * function is defined on are on the interval [0, width)\n+    *\n+    * @return The width of the interval [0, width) containing the function [[domain]].\n+    */\n+  def width: Int\n+\n+  /** Obtain a new iterator over the indices that the function is defined on.\n+    *\n+    * @return An iterator over the function domain\n+    */\n+  def domain: Iterator[Int]\n+\n+  /** Obtain a new iterator over the function range values\n+    *\n+    * @return An iterator over values that may be returned by the function\n+    */\n+  def range: Iterator[V]\n+\n+  /** Obtain a Scala Map from values in the [[domain]] to their corresponding [[range]] values.\n+    *\n+    * @return A Scala Map that is equivalent to this function\n+    */\n+  final def toMap: Map[Int, V] = {\n+    val m = scala.collection.mutable.Map.empty[Int, V]\n+    domain.foreach { j =>\n+      m += (j -> this(j))\n+    }\n+    m.toMap\n+  }\n+\n+  /** Concatenate two index functions.\n+    *\n+    * @param that The right-hand function of the concatenation\n+    * @return The concatenation of left and right index functions, defined as:\n+    * {{{\n+    * (f1 ++ f2)(j) = if (j < f1.width) f1(j) else f2(j - f1.width)\n+    * }}}\n+    */\n+  final def ++(that: IndexFunction[V]) = new IndexFunction[V] {\n+    def width = self.width + that.width\n+    def domain = self.domain ++ that.domain.map(_ + self.width)\n+    private lazy val rangeLazy = {\n+      val uniq = scala.collection.mutable.Set.empty[V]\n+      (self.range ++ that.range).foreach { v =>\n+         uniq += v\n+      }\n+      uniq\n+    }\n+    def range = rangeLazy.iterator\n+    def apply(j: Int) = if (j < self.width) self.apply(j) else that.apply(j - self.width)\n+    def isDefinedAt(j: Int) = if (j < self.width) self.isDefinedAt(j) else that.isDefinedAt(j - self.width)\n+  }\n+}\n+\n+/** The inverse of an [[InvertableIndexFunction]].\n+  *\n+  * @tparam V The [[domain]] type of this function.  Also the\n+  * [[InvertableIndexFunction!.range range]] of the parent [[InvertableIndexFunction]].\n+  */\n+abstract class InverseIndexFunction[V] extends PartialFunction[V, Int] with Serializable {\n+\n+  /** The width of index range. Corresponds to the [[InvertableIndexFunction!.width width]]\n+    * of the parent [[InvertableIndexFunction]].\n+    */\n+  def width: Int\n+\n+  /** Obtain a new iterator over the domain of this function.\n+    *\n+    * @return An iterator over the domain values of this function.  Equivalent to the range of the\n+    * parent [[InvertableIndexFunction]].\n+    */\n+  def domain: Iterator[V]\n+\n+  /** Obtain a new iterator over the range values of this function.\n+    *\n+    * @return An iterator over the range values of this function.  Equivalent to the domain of\n+    * the parent [[InvertableIndexFunction]].\n+    */\n+  final def range: Iterator[Int] = domain.map(this)\n+\n+  /** Obtain a Scala Map that is equivalent to this function.\n+    *\n+    * @return A Map that maps domain values into their corresponding index values\n+    */\n+  final def toMap: Map[V, Int] = {\n+    val m = scala.collection.mutable.Map.empty[V, Int]\n+    domain.foreach { v =>\n+      m += (v -> this(v))\n+    }\n+    m.toMap\n+  }\n+}\n+\n+/** An [[IndexFunction]] that is also invertable (and so 1-1).\n+  *\n+  * @tparam V The [[range]] value type of this function.\n+  */\n+abstract class InvertableIndexFunction[V] extends IndexFunction[V] { self =>","path":"src/main/scala/com/redhat/et/silex/feature/indexfunction/indexfunction.scala","position":131,"original_position":131,"commit_id":"288ee81c86862a4f00cb368a6b97ea3dc3be77e1","original_commit_id":"288ee81c86862a4f00cb368a6b97ea3dc3be77e1","user":{"login":"willb","id":1161,"avatar_url":"https://avatars.githubusercontent.com/u/1161?v=3","gravatar_id":"","url":"https://api.github.com/users/willb","html_url":"https://github.com/willb","followers_url":"https://api.github.com/users/willb/followers","following_url":"https://api.github.com/users/willb/following{/other_user}","gists_url":"https://api.github.com/users/willb/gists{/gist_id}","starred_url":"https://api.github.com/users/willb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/willb/subscriptions","organizations_url":"https://api.github.com/users/willb/orgs","repos_url":"https://api.github.com/users/willb/repos","events_url":"https://api.github.com/users/willb/events{/privacy}","received_events_url":"https://api.github.com/users/willb/received_events","type":"User","site_admin":false},"body":"nit:  I think it's \"invertible;\" if so, we should probably change throughout.","created_at":"2015-07-07T18:46:05Z","updated_at":"2015-07-07T18:46:05Z","html_url":"https://github.com/willb/silex/pull/15#discussion_r34075449","pull_request_url":"https://api.github.com/repos/willb/silex/pulls/15","_links":{"self":{"href":"https://api.github.com/repos/willb/silex/pulls/comments/34075449"},"html":{"href":"https://github.com/willb/silex/pull/15#discussion_r34075449"},"pull_request":{"href":"https://api.github.com/repos/willb/silex/pulls/15"}}},"pull_request":{"url":"https://api.github.com/repos/willb/silex/pulls/15","id":33710962,"html_url":"https://github.com/willb/silex/pull/15","diff_url":"https://github.com/willb/silex/pull/15.diff","patch_url":"https://github.com/willb/silex/pull/15.patch","issue_url":"https://api.github.com/repos/willb/silex/issues/15","number":15,"state":"open","locked":false,"title":"Support feature extractor library (#10)","user":{"login":"erikerlandson","id":259898,"avatar_url":"https://avatars.githubusercontent.com/u/259898?v=3","gravatar_id":"","url":"https://api.github.com/users/erikerlandson","html_url":"https://github.com/erikerlandson","followers_url":"https://api.github.com/users/erikerlandson/followers","following_url":"https://api.github.com/users/erikerlandson/following{/other_user}","gists_url":"https://api.github.com/users/erikerlandson/gists{/gist_id}","starred_url":"https://api.github.com/users/erikerlandson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/erikerlandson/subscriptions","organizations_url":"https://api.github.com/users/erikerlandson/orgs","repos_url":"https://api.github.com/users/erikerlandson/repos","events_url":"https://api.github.com/users/erikerlandson/events{/privacy}","received_events_url":"https://api.github.com/users/erikerlandson/received_events","type":"User","site_admin":false},"body":"","created_at":"2015-04-20T22:03:18Z","updated_at":"2015-07-07T18:46:05Z","closed_at":null,"merged_at":null,"merge_commit_sha":"e099e11032e600587bfe2350bf315a6546553475","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/willb/silex/pulls/15/commits","review_comments_url":"https://api.github.com/repos/willb/silex/pulls/15/comments","review_comment_url":"https://api.github.com/repos/willb/silex/pulls/comments{/number}","comments_url":"https://api.github.com/repos/willb/silex/issues/15/comments","statuses_url":"https://api.github.com/repos/willb/silex/statuses/288ee81c86862a4f00cb368a6b97ea3dc3be77e1","head":{"label":"erikerlandson:feature/extractor","ref":"feature/extractor","sha":"288ee81c86862a4f00cb368a6b97ea3dc3be77e1","user":{"login":"erikerlandson","id":259898,"avatar_url":"https://avatars.githubusercontent.com/u/259898?v=3","gravatar_id":"","url":"https://api.github.com/users/erikerlandson","html_url":"https://github.com/erikerlandson","followers_url":"https://api.github.com/users/erikerlandson/followers","following_url":"https://api.github.com/users/erikerlandson/following{/other_user}","gists_url":"https://api.github.com/users/erikerlandson/gists{/gist_id}","starred_url":"https://api.github.com/users/erikerlandson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/erikerlandson/subscriptions","organizations_url":"https://api.github.com/users/erikerlandson/orgs","repos_url":"https://api.github.com/users/erikerlandson/repos","events_url":"https://api.github.com/users/erikerlandson/events{/privacy}","received_events_url":"https://api.github.com/users/erikerlandson/received_events","type":"User","site_admin":false},"repo":{"id":30730149,"name":"silex","full_name":"erikerlandson/silex","owner":{"login":"erikerlandson","id":259898,"avatar_url":"https://avatars.githubusercontent.com/u/259898?v=3","gravatar_id":"","url":"https://api.github.com/users/erikerlandson","html_url":"https://github.com/erikerlandson","followers_url":"https://api.github.com/users/erikerlandson/followers","following_url":"https://api.github.com/users/erikerlandson/following{/other_user}","gists_url":"https://api.github.com/users/erikerlandson/gists{/gist_id}","starred_url":"https://api.github.com/users/erikerlandson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/erikerlandson/subscriptions","organizations_url":"https://api.github.com/users/erikerlandson/orgs","repos_url":"https://api.github.com/users/erikerlandson/repos","events_url":"https://api.github.com/users/erikerlandson/events{/privacy}","received_events_url":"https://api.github.com/users/erikerlandson/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/erikerlandson/silex","description":"something to help you spark","fork":true,"url":"https://api.github.com/repos/erikerlandson/silex","forks_url":"https://api.github.com/repos/erikerlandson/silex/forks","keys_url":"https://api.github.com/repos/erikerlandson/silex/keys{/key_id}","collaborators_url":"https://api.github.com/repos/erikerlandson/silex/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/erikerlandson/silex/teams","hooks_url":"https://api.github.com/repos/erikerlandson/silex/hooks","issue_events_url":"https://api.github.com/repos/erikerlandson/silex/issues/events{/number}","events_url":"https://api.github.com/repos/erikerlandson/silex/events","assignees_url":"https://api.github.com/repos/erikerlandson/silex/assignees{/user}","branches_url":"https://api.github.com/repos/erikerlandson/silex/branches{/branch}","tags_url":"https://api.github.com/repos/erikerlandson/silex/tags","blobs_url":"https://api.github.com/repos/erikerlandson/silex/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/erikerlandson/silex/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/erikerlandson/silex/git/refs{/sha}","trees_url":"https://api.github.com/repos/erikerlandson/silex/git/trees{/sha}","statuses_url":"https://api.github.com/repos/erikerlandson/silex/statuses/{sha}","languages_url":"https://api.github.com/repos/erikerlandson/silex/languages","stargazers_url":"https://api.github.com/repos/erikerlandson/silex/stargazers","contributors_url":"https://api.github.com/repos/erikerlandson/silex/contributors","subscribers_url":"https://api.github.com/repos/erikerlandson/silex/subscribers","subscription_url":"https://api.github.com/repos/erikerlandson/silex/subscription","commits_url":"https://api.github.com/repos/erikerlandson/silex/commits{/sha}","git_commits_url":"https://api.github.com/repos/erikerlandson/silex/git/commits{/sha}","comments_url":"https://api.github.com/repos/erikerlandson/silex/comments{/number}","issue_comment_url":"https://api.github.com/repos/erikerlandson/silex/issues/comments{/number}","contents_url":"https://api.github.com/repos/erikerlandson/silex/contents/{+path}","compare_url":"https://api.github.com/repos/erikerlandson/silex/compare/{base}...{head}","merges_url":"https://api.github.com/repos/erikerlandson/silex/merges","archive_url":"https://api.github.com/repos/erikerlandson/silex/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/erikerlandson/silex/downloads","issues_url":"https://api.github.com/repos/erikerlandson/silex/issues{/number}","pulls_url":"https://api.github.com/repos/erikerlandson/silex/pulls{/number}","milestones_url":"https://api.github.com/repos/erikerlandson/silex/milestones{/number}","notifications_url":"https://api.github.com/repos/erikerlandson/silex/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/erikerlandson/silex/labels{/name}","releases_url":"https://api.github.com/repos/erikerlandson/silex/releases{/id}","created_at":"2015-02-12T23:05:58Z","updated_at":"2015-02-12T23:05:58Z","pushed_at":"2015-06-11T16:02:53Z","git_url":"git://github.com/erikerlandson/silex.git","ssh_url":"git@github.com:erikerlandson/silex.git","clone_url":"https://github.com/erikerlandson/silex.git","svn_url":"https://github.com/erikerlandson/silex","homepage":null,"size":763,"stargazers_count":0,"watchers_count":0,"language":"Scala","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"develop"}},"base":{"label":"willb:develop","ref":"develop","sha":"74ae27dc1107e3c2f6d18030d5ace83ff4c173ae","user":{"login":"willb","id":1161,"avatar_url":"https://avatars.githubusercontent.com/u/1161?v=3","gravatar_id":"","url":"https://api.github.com/users/willb","html_url":"https://github.com/willb","followers_url":"https://api.github.com/users/willb/followers","following_url":"https://api.github.com/users/willb/following{/other_user}","gists_url":"https://api.github.com/users/willb/gists{/gist_id}","starred_url":"https://api.github.com/users/willb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/willb/subscriptions","organizations_url":"https://api.github.com/users/willb/orgs","repos_url":"https://api.github.com/users/willb/repos","events_url":"https://api.github.com/users/willb/events{/privacy}","received_events_url":"https://api.github.com/users/willb/received_events","type":"User","site_admin":false},"repo":{"id":30727293,"name":"silex","full_name":"willb/silex","owner":{"login":"willb","id":1161,"avatar_url":"https://avatars.githubusercontent.com/u/1161?v=3","gravatar_id":"","url":"https://api.github.com/users/willb","html_url":"https://github.com/willb","followers_url":"https://api.github.com/users/willb/followers","following_url":"https://api.github.com/users/willb/following{/other_user}","gists_url":"https://api.github.com/users/willb/gists{/gist_id}","starred_url":"https://api.github.com/users/willb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/willb/subscriptions","organizations_url":"https://api.github.com/users/willb/orgs","repos_url":"https://api.github.com/users/willb/repos","events_url":"https://api.github.com/users/willb/events{/privacy}","received_events_url":"https://api.github.com/users/willb/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/willb/silex","description":"something to help you spark","fork":false,"url":"https://api.github.com/repos/willb/silex","forks_url":"https://api.github.com/repos/willb/silex/forks","keys_url":"https://api.github.com/repos/willb/silex/keys{/key_id}","collaborators_url":"https://api.github.com/repos/willb/silex/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/willb/silex/teams","hooks_url":"https://api.github.com/repos/willb/silex/hooks","issue_events_url":"https://api.github.com/repos/willb/silex/issues/events{/number}","events_url":"https://api.github.com/repos/willb/silex/events","assignees_url":"https://api.github.com/repos/willb/silex/assignees{/user}","branches_url":"https://api.github.com/repos/willb/silex/branches{/branch}","tags_url":"https://api.github.com/repos/willb/silex/tags","blobs_url":"https://api.github.com/repos/willb/silex/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/willb/silex/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/willb/silex/git/refs{/sha}","trees_url":"https://api.github.com/repos/willb/silex/git/trees{/sha}","statuses_url":"https://api.github.com/repos/willb/silex/statuses/{sha}","languages_url":"https://api.github.com/repos/willb/silex/languages","stargazers_url":"https://api.github.com/repos/willb/silex/stargazers","contributors_url":"https://api.github.com/repos/willb/silex/contributors","subscribers_url":"https://api.github.com/repos/willb/silex/subscribers","subscription_url":"https://api.github.com/repos/willb/silex/subscription","commits_url":"https://api.github.com/repos/willb/silex/commits{/sha}","git_commits_url":"https://api.github.com/repos/willb/silex/git/commits{/sha}","comments_url":"https://api.github.com/repos/willb/silex/comments{/number}","issue_comment_url":"https://api.github.com/repos/willb/silex/issues/comments{/number}","contents_url":"https://api.github.com/repos/willb/silex/contents/{+path}","compare_url":"https://api.github.com/repos/willb/silex/compare/{base}...{head}","merges_url":"https://api.github.com/repos/willb/silex/merges","archive_url":"https://api.github.com/repos/willb/silex/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/willb/silex/downloads","issues_url":"https://api.github.com/repos/willb/silex/issues{/number}","pulls_url":"https://api.github.com/repos/willb/silex/pulls{/number}","milestones_url":"https://api.github.com/repos/willb/silex/milestones{/number}","notifications_url":"https://api.github.com/repos/willb/silex/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/willb/silex/labels{/name}","releases_url":"https://api.github.com/repos/willb/silex/releases{/id}","created_at":"2015-02-12T22:24:36Z","updated_at":"2015-07-02T14:10:22Z","pushed_at":"2015-07-02T15:47:39Z","git_url":"git://github.com/willb/silex.git","ssh_url":"git@github.com:willb/silex.git","clone_url":"https://github.com/willb/silex.git","svn_url":"https://github.com/willb/silex","homepage":null,"size":1385,"stargazers_count":6,"watchers_count":6,"language":"Scala","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":4,"mirror_url":null,"open_issues_count":9,"forks":4,"open_issues":9,"watchers":6,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/willb/silex/pulls/15"},"html":{"href":"https://github.com/willb/silex/pull/15"},"issue":{"href":"https://api.github.com/repos/willb/silex/issues/15"},"comments":{"href":"https://api.github.com/repos/willb/silex/issues/15/comments"},"review_comments":{"href":"https://api.github.com/repos/willb/silex/pulls/15/comments"},"review_comment":{"href":"https://api.github.com/repos/willb/silex/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/willb/silex/pulls/15/commits"},"statuses":{"href":"https://api.github.com/repos/willb/silex/statuses/288ee81c86862a4f00cb368a6b97ea3dc3be77e1"}}}}