Skip to content
This repository was archived by the owner on Nov 4, 2022. It is now read-only.

Commit 18ab1d6

Browse files
initial commit
0 parents  commit 18ab1d6

File tree

11 files changed

+277
-0
lines changed

11 files changed

+277
-0
lines changed

.gitignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
.cache*
2+
.classpath
3+
.project
4+
.worksheet/
5+
.settings
6+
7+
8+
data/
9+
project/project/*
10+
project/target/*
11+
src/main/target
12+
target/
13+
project/eclipse.sbt
14+
15+
.idea
16+
config.json

build.sbt

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// scala.meta macros are at the moment only supported in 2.11.
2+
scalaVersion in ThisBuild := "2.11.8"
3+
4+
lazy val metaMacroSettings: Seq[Def.Setting[_]] = Seq(
5+
// New-style macro annotations are under active development. As a result, in
6+
// this build we'll be referring to snapshot versions of both scala.meta and
7+
// macro paradise.
8+
resolvers += Resolver.url(
9+
"scalameta",
10+
url("http://dl.bintray.com/scalameta/maven"))(Resolver.ivyStylePatterns),
11+
// A dependency on macro paradise 3.x is required to both write and expand
12+
// new-style macros. This is similar to how it works for old-style macro
13+
// annotations and a dependency on macro paradise 2.x.
14+
addCompilerPlugin(
15+
"org.scalameta" % "paradise" % "3.0.0.132" cross CrossVersion.full),
16+
scalacOptions += "-Xplugin-require:macroparadise",
17+
// temporary workaround for https://github.com/scalameta/paradise/issues/10
18+
scalacOptions in (Compile, console) := Seq(), // macroparadise plugin doesn't work in repl yet.
19+
// temporary workaround for https://github.com/scalameta/paradise/issues/55
20+
sources in (Compile, doc) := Nil // macroparadise doesn't work with scaladoc yet.
21+
)
22+
23+
// Define macros in this project.
24+
lazy val macros = (project in file("macros")).settings(
25+
name := "scala-packed-macro",
26+
metaMacroSettings,
27+
// A dependency on scala.meta is required to write new-style macros, but not
28+
// to expand such macros. This is similar to how it works for old-style
29+
// macros and a dependency on scala.reflect.
30+
libraryDependencies += "org.scalameta" %% "scalameta" % "1.4.0.544",
31+
libraryDependencies += "org.scalatest" % "scalatest_2.11" % "3.0.1"
32+
)
33+
34+
// Use macros in this project.
35+
lazy val core = (project in file("core")).settings(
36+
name := "scala-packed-core",
37+
metaMacroSettings
38+
).dependsOn(macros)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package io.findify.scalapacked
2+
3+
import java.nio.ByteBuffer
4+
5+
import io.findify.scalapacked.types.PackedType
6+
7+
/**
8+
* Created by shutty on 11/19/16.
9+
*/
10+
trait PackedProduct {
11+
var buffer: ByteBuffer
12+
var offset: Int
13+
def size: Int
14+
}
15+
16+
object PackedMember {
17+
def memberSize[T](value: T)(implicit packer: PackedType[T]): Int = packer.size(value)
18+
def memberWrite[T](value: T, buffer: ByteBuffer, offset: Int)(implicit packer: PackedType[T]): Unit = packer.write(value, buffer, offset)
19+
def memberRead[T](buffer: ByteBuffer, offset: Int)(implicit packer: PackedType[T]):T = packer.read(buffer, offset)
20+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package io.findify.scalapacked
2+
3+
import java.nio.ByteBuffer
4+
5+
import scala.reflect.ClassTag
6+
7+
/**
8+
* Created by shutty on 11/20/16.
9+
*/
10+
class PackedSeq[T <: PackedProduct : ClassTag](buffer: ByteBuffer, size: Int) {
11+
import scala.reflect._
12+
def map[U <: PackedProduct : ClassTag]( f: T => U ) = {
13+
var offset = 0
14+
var count = 0
15+
val instanceT = classTag[T].runtimeClass.newInstance().asInstanceOf[T]
16+
var instanceU = classTag[U].runtimeClass.newInstance().asInstanceOf[U]
17+
var output = ByteBuffer.allocate(1024)
18+
while (count < size) {
19+
instanceT.buffer = buffer
20+
instanceT.offset = offset
21+
offset += instanceT.size
22+
instanceU = f(instanceT)
23+
count += 1
24+
if (output.remaining() > instanceU.size) {
25+
output.put(instanceU.buffer)
26+
} else {
27+
val largerOutput = ByteBuffer.allocate(output.capacity() * 2)
28+
largerOutput.put(output)
29+
largerOutput.put(instanceU.buffer)
30+
output = largerOutput
31+
}
32+
}
33+
new PackedSeq[U](output, size)
34+
}
35+
36+
def foreach(f: T => Unit) = {
37+
var offset = 0
38+
var count = 0
39+
val instanceT = classTag[T].runtimeClass.newInstance().asInstanceOf[T]
40+
while (count < size) {
41+
instanceT.buffer = buffer
42+
instanceT.offset = offset
43+
offset += instanceT.size
44+
f(instanceT)
45+
count += 1
46+
}
47+
}
48+
}
49+
50+
object PackedSeq {
51+
def apply[T <: PackedProduct : ClassTag](items: Seq[T]) = {
52+
val initial = ByteBuffer.allocate(1024)
53+
val buffer = items.foldLeft(initial)( (buffer, item) => {
54+
if (buffer.remaining() > item.size) {
55+
buffer.put(item.buffer)
56+
buffer
57+
} else {
58+
val largerBuffer = ByteBuffer.allocate(buffer.capacity() * 2)
59+
largerBuffer.put(buffer)
60+
largerBuffer.put(item.buffer)
61+
}
62+
})
63+
new PackedSeq[T](buffer, items.length)
64+
}
65+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package io.findify.scalapacked.types
2+
3+
import java.nio.ByteBuffer
4+
5+
/**
6+
* Created by shutty on 11/20/16.
7+
*/
8+
object DefaultTypes {
9+
10+
implicit object IntPacked extends PackedType[Int] {
11+
override def size(value:Int): Int = 4
12+
override def write(value:Int, buffer: ByteBuffer, offset: Int): Unit = buffer.putInt(offset, value)
13+
override def read(buffer: ByteBuffer, offset: Int): Int = buffer.getInt(offset)
14+
}
15+
16+
implicit object LongPacked extends PackedType[Long] {
17+
override def size(value:Long): Int = 8
18+
override def write(value:Long, buffer: ByteBuffer, offset: Int): Unit = buffer.putLong(offset, value)
19+
override def read(buffer: ByteBuffer, offset: Int): Long = buffer.getLong(offset)
20+
}
21+
22+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.findify.scalapacked.types
2+
3+
import java.nio.ByteBuffer
4+
5+
/**
6+
* Created by shutty on 11/19/16.
7+
*/
8+
trait PackedType[@specialized(Int, Long, Float, Double) T] {
9+
def size(value: T): Int
10+
def write(value: T, buffer: ByteBuffer, offset: Int): Unit
11+
def read(buffer: ByteBuffer, offset: Int): T
12+
}
13+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package io.findify.scalapacked
2+
3+
import org.scalatest.{FlatSpec, Matchers}
4+
5+
/**
6+
* Created by shutty on 11/21/16.
7+
*/
8+
9+
@Packed class Bar(a:Int)
10+
11+
class MacroTest extends FlatSpec with Matchers {
12+
"packed class" should "have size method" in {
13+
val bar = new Bar(1)
14+
bar.size shouldBe 4
15+
}
16+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package io.findify.scalapacked
2+
3+
import java.nio.ByteBuffer
4+
5+
import org.scalatest.{FlatSpec, Matchers}
6+
7+
/**
8+
* Created by shutty on 11/19/16.
9+
*/
10+
11+
12+
class Foo(var buffer: ByteBuffer, var offset: Int) extends PackedProduct {
13+
def this() = this(ByteBuffer.allocate(0), 0)
14+
import io.findify.scalapacked.types.DefaultTypes._
15+
def i1: Int = PackedMember.memberRead[Int](buffer, offset + 0)
16+
def i2: Long = PackedMember.memberRead[Long](buffer, offset + PackedMember.memberSize(i1))
17+
def size = PackedMember.memberSize(i1) + PackedMember.memberSize(i2)
18+
}
19+
20+
object Foo {
21+
def apply(i1: Int, i2: Long) = {
22+
import io.findify.scalapacked.types.DefaultTypes._
23+
val i1size = PackedMember.memberSize(i1)
24+
val i2size = PackedMember.memberSize(i2)
25+
val buffer = ByteBuffer.allocate(i1size + i2size)
26+
val i1offset = 0
27+
PackedMember.memberWrite(i1, buffer, i1offset)
28+
val i2offset = i1offset + i1size
29+
PackedMember.memberWrite(i2, buffer, i2offset)
30+
new Foo(buffer, 0)
31+
}
32+
}
33+
34+
class SimpleTest extends FlatSpec with Matchers {
35+
"case class with int" should "be written to bytebuffer" in {
36+
val in = Foo(17, 24)
37+
val buff = ByteBuffer.allocate(in.size)
38+
buff.put(in.buffer)
39+
val result1 = buff.getInt(0)
40+
result1 shouldBe 17
41+
val result2 = buff.getLong(4)
42+
result2 shouldBe 24
43+
}
44+
45+
it should "not fail on empty instance" in {
46+
val empty = new Foo()
47+
empty.offset shouldBe 0
48+
}
49+
50+
it should "be insertable to PackedSeq" in {
51+
val seq = PackedSeq(Seq(Foo(1, 2), Foo(3, 4)))
52+
var count = 0
53+
seq.foreach { item => {
54+
count += item.i1
55+
count += item.i2.toInt
56+
}}
57+
count shouldBe 10
58+
}
59+
60+
it should "map thru elements" in {
61+
val seq = PackedSeq(Seq(Foo(1, 2), Foo(3, 4))).map(item => Foo(item.i1 * 2, item.i2 * 2))
62+
var count = 0
63+
seq.foreach { item => {
64+
count += item.i1
65+
count += item.i2.toInt
66+
}}
67+
count shouldBe 20
68+
}
69+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package io.findify.scalapacked
2+
3+
/**
4+
* Created by shutty on 11/21/16.
5+
*/
6+
7+
import scala.meta._
8+
9+
class Packed extends scala.annotation.StaticAnnotation {
10+
inline def apply(defn: Any): Any = meta {
11+
defn match {
12+
case q"class $tpname (...$paramss) { ..$stats }" => q"class $tpname (...$paramss) {..$stats; def size: Int = 1}; object $tpname { def hello: Int = 1 }"
13+
case _ => abort("cannot match class")
14+
}
15+
}
16+
}

project/build.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
sbt.version = 0.13.8

project/plugins.sbt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
logLevel := Level.Warn

0 commit comments

Comments
 (0)