Skip to content

Commit c75e296

Browse files
authored
remove traversal second attempt (#367)
* this removes "Traversal" as a class. Instead everything runs via scala Iterator, with some DSL-style implicits attached.
1 parent db55594 commit c75e296

36 files changed

+454
-533
lines changed

core/build.sbt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,5 @@ libraryDependencies ++= Seq(
44
"net.sf.trove4j" % "core" % "3.1.0",
55
"org.msgpack" % "msgpack-core" % "0.9.1",
66
"com.h2database" % "h2-mvstore" % "1.4.200",
7-
"org.slf4j" % "slf4j-api" % "2.0.7",
7+
"org.slf4j" % "slf4j-api" % "2.0.7"
88
)
9-
10-
/* it's a java-only build */
11-
autoScalaLibrary := false
12-
crossPaths := false

core/src/main/java/overflowdb/NodeDb.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,20 @@ public final <A extends Node> Iterator<A> createAdjacentNodeIteratorByOffSet(int
601601
}
602602
}
603603

604+
/* Simplify hoisting of string lookups.
605+
* n.b. `final` so that the JIT compiler can inline it */
606+
public final <A extends Node> scala.collection.Iterator<A> createAdjacentNodeScalaIteratorByOffSet(int offsetPos) {
607+
AdjacentNodes adjacentNodesTmp = this.adjacentNodes;
608+
if (offsetPos != -1) {
609+
int start = startIndex(adjacentNodesTmp, offsetPos);
610+
int length = blockLength(adjacentNodesTmp, offsetPos);
611+
int strideSize = layoutInformation().getEdgePropertyCountByOffsetPos(offsetPos) + 1;
612+
return new overflowdb.misc.ArrayIter<A>(adjacentNodesTmp.nodesWithEdgeProperties, start, start + length, strideSize);
613+
} else {
614+
return scala.collection.Iterator.empty();
615+
}
616+
}
617+
604618
private final String[] allowedLabelsByDirection(Direction direction) {
605619
if (direction.equals(Direction.OUT))
606620
return layoutInformation().allowedOutEdgeLabels();
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package overflowdb.misc
2+
3+
class ArrayIter[+T <: AnyRef](items: Array[AnyRef], private var pos: Int, until: Int, stride: Int)
4+
extends scala.collection.Iterator[T] {
5+
override def hasNext: Boolean = {
6+
while (pos < until && items(pos) == null) pos += stride
7+
pos < until
8+
}
9+
10+
override def next(): T =
11+
if (!hasNext) Iterator.empty[T].next() else { val res = items(pos); pos += stride; res.asInstanceOf[T] }
12+
}

formats/src/test/scala/overflowdb/formats/neo4jcsv/Neo4jCsvTests.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import testutils.ProjectRoot
1111

1212
import java.io.FileNotFoundException
1313
import java.nio.file.Paths
14-
import scala.jdk.CollectionConverters.{CollectionHasAsScala, IterableHasAsJava}
14+
import scala.jdk.CollectionConverters.{CollectionHasAsScala, IterableHasAsJava, IteratorHasAsScala}
1515

1616
class Neo4jCsvTests extends AnyWordSpec {
1717
val subprojectRoot = ProjectRoot.relativise("formats")
@@ -216,7 +216,7 @@ class Neo4jCsvTests extends AnyWordSpec {
216216

217217
// TODO change back once we're on Scala 3.2.2
218218
// graphReimported.node(2).out(TestEdge.LABEL).property(TestNode.INT_PROPERTY).l shouldBe Seq(13)
219-
graphReimported.node(2).out(TestEdge.LABEL).to(Traversal).property(TestNode.INT_PROPERTY).l shouldBe Seq(13)
219+
graphReimported.node(2).out(TestEdge.LABEL).asScala.property(TestNode.INT_PROPERTY).l shouldBe Seq(13)
220220
}
221221
}
222222

traversal-tests/src/test/scala/overflowdb/traversal/GenericGraphTraversalTests.scala

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@ import overflowdb.traversal.testdomains.simple.Thing.Properties.Name
99
import overflowdb.traversal.testdomains.simple.{Connection, ExampleGraphSetup, Thing}
1010
import ChainedImplicitsTemp._
1111

12+
import scala.jdk.CollectionConverters.IteratorHasAsScala
13+
1214
/** generic graph traversals, i.e. domain independent */
1315
class GenericGraphTraversalTests extends AnyWordSpec with ExampleGraphSetup {
1416
"V for all nodes" in {
15-
graph.V.count.head shouldBe 9
1617
graph.V.size shouldBe 9
1718
}
1819

1920
"E for all edges" in {
20-
graph.E.count.head shouldBe 8
21-
graph.E.size shouldBe 8
21+
graph.E.asScala.size shouldBe 8
2222
}
2323

2424
"label lookup" in {
@@ -97,12 +97,20 @@ class GenericGraphTraversalTests extends AnyWordSpec with ExampleGraphSetup {
9797

9898
"`where` step taking a traversal" in {
9999
// find all nodes that _do_ have an OUT neighbor, i.e. find the inner nodes
100-
graph.V.where(_.out).property(Name).toSetMutable shouldBe Set("L2", "L1", "Center", "R1", "R2", "R3", "R4")
100+
graph.V.asScala.where(_.out).property(Name).toSetMutable shouldBe Set(
101+
"L2",
102+
"L1",
103+
"Center",
104+
"R1",
105+
"R2",
106+
"R3",
107+
"R4"
108+
)
101109
}
102110

103111
"`not` step taking a traversal" in {
104112
// find all nodes that do _not_ have an OUT neighbor, i.e. find the outermost nodes
105-
graph.V.not(_.out).property(Name).toSetMutable shouldBe Set("L3", "R5")
113+
graph.V.asScala.not(_.out).property(Name).toSetMutable shouldBe Set("L3", "R5")
106114
}
107115
}
108116

traversal-tests/src/test/scala/overflowdb/traversal/GratefulDeadTests.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ class GratefulDeadTests extends AnyWordSpec {
1616
gratefulDead.all.label.toSetMutable shouldBe Set(Artist.Label, Song.Label)
1717

1818
gratefulDead.label(Artist.Label).size shouldBe 224
19-
gratefulDead.id(1).label.head shouldBe Song.Label
20-
gratefulDead.id(2).property(Song.Properties.Name).head shouldBe "IM A MAN"
19+
gratefulDead.id(1).label.next() shouldBe Song.Label
20+
gratefulDead.id(2).property(Song.Properties.Name).next() shouldBe "IM A MAN"
2121
gratefulDead.ids(3, 4).property[String]("name").toSetMutable shouldBe Set("BERTHA", "NOT FADE AWAY")
2222
gratefulDead.all.has(Song.Properties.SongType).size shouldBe 584
2323
gratefulDead.all.has(Song.Properties.Performances, 2).size shouldBe 36
@@ -85,18 +85,18 @@ class GratefulDeadTests extends AnyWordSpec {
8585

8686
"lifting elements into a Traversal".can {
8787
"lift a single element with `Traversal.fromSingle`" in {
88-
val dylan = gratefulDead.artists.nameExact("Bob_Dylan").head
89-
Traversal.fromSingle(dylan).sangSongs.size shouldBe 22
88+
val dylan = gratefulDead.artists.nameExact("Bob_Dylan").next()
89+
Iterator.single(dylan).sangSongs.size shouldBe 22
9090
}
9191

9292
"lift a single element with `.start`" in {
93-
val dylan = gratefulDead.artists.nameExact("Bob_Dylan").head
93+
val dylan = gratefulDead.artists.nameExact("Bob_Dylan").next()
9494
dylan.start.sangSongs.size shouldBe 22
9595
}
9696

9797
"lift multiple elements with `Traversal.from`" in {
9898
val artists = gratefulDead.artists.nameExact("Bob_Dylan", "All").toList
99-
Traversal.from(artists).sangSongs.size shouldBe 31
99+
artists.iterator.sangSongs.size shouldBe 31
100100
}
101101
}
102102

traversal-tests/src/test/scala/overflowdb/traversal/LogicalStepsTests.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import overflowdb.Node
66
import overflowdb.traversal.testdomains.simple.Thing.Properties.Name
77
import overflowdb.traversal.testdomains.simple.{ExampleGraphSetup, Thing, ThingTraversal}
88

9+
import scala.jdk.CollectionConverters.IteratorHasAsScala
10+
911
class LogicalStepsTests extends AnyWordSpec with ExampleGraphSetup {
1012
/* most tests work with this simple graph:
1113
* L3 <- L2 <- L1 <- Center -> R1 -> R2 -> R3 -> R4 -> R5
@@ -46,6 +48,7 @@ class LogicalStepsTests extends AnyWordSpec with ExampleGraphSetup {
4648
"provide if semantics" in {
4749
graph
4850
.nodes(Thing.Label)
51+
.asScala
4952
.choose(_.property(Name)) { case "L1" =>
5053
_.out // -> L2
5154
}
@@ -56,6 +59,7 @@ class LogicalStepsTests extends AnyWordSpec with ExampleGraphSetup {
5659
"provide if/elseif semantics" in {
5760
graph
5861
.nodes(Thing.Label)
62+
.asScala
5963
.choose(_.property(Name)) {
6064
case "L1" => _.out // -> L2
6165
case "R1" => _.repeat(_.out)(_.maxDepth(3)) // -> R4
@@ -67,6 +71,7 @@ class LogicalStepsTests extends AnyWordSpec with ExampleGraphSetup {
6771
"provide if/else semantics" in {
6872
graph
6973
.nodes(Thing.Label)
74+
.asScala
7075
.choose(_.property(Name)) {
7176
case "L1" => _.out // -> L2
7277
case "R1" => _.repeat(_.out)(_.maxDepth(3)) // -> R4
@@ -79,6 +84,7 @@ class LogicalStepsTests extends AnyWordSpec with ExampleGraphSetup {
7984
"handle empty `on` traversal: if semantics" in {
8085
graph
8186
.nodes(Thing.Label)
87+
.asScala
8288
.choose(_.property(Name).filter(_ => false)) { case "L1" =>
8389
_.out
8490
}
@@ -89,6 +95,7 @@ class LogicalStepsTests extends AnyWordSpec with ExampleGraphSetup {
8995
"handle empty `on` traversal: if/else semantics" in {
9096
graph
9197
.nodes(Thing.Label)
98+
.asScala
9299
.choose(_.property(Name).filter(_ => false)) {
93100
case "L1" => _.in
94101
case _ => _.out

traversal-tests/src/test/scala/overflowdb/traversal/PathTraversalTests.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import overflowdb.traversal.testdomains.simple.Thing.Properties.Name
77
import overflowdb.traversal.testdomains.simple.{ExampleGraphSetup, Thing, ThingTraversal}
88

99
import scala.collection.mutable
10+
import scala.jdk.CollectionConverters.IteratorHasAsScala
1011

1112
class PathTraversalTests extends AnyWordSpec with ExampleGraphSetup {
1213

@@ -89,7 +90,7 @@ class PathTraversalTests extends AnyWordSpec with ExampleGraphSetup {
8990
}
9091

9192
"cast" in {
92-
val traversal: Traversal[Node] = center.start.enablePathTracking.out.out
93+
val traversal: Iterator[Node] = center.start.enablePathTracking.out.out
9394
val results: Seq[Thing] = traversal.cast[Thing].l
9495
results shouldBe Seq(l2, r2)
9596
}
@@ -164,6 +165,7 @@ class PathTraversalTests extends AnyWordSpec with ExampleGraphSetup {
164165
"choose" in {
165166
graph
166167
.nodes(Thing.Label)
168+
.asScala
167169
.enablePathTracking
168170
.choose(_.property(Name)) {
169171
case "L1" => _.out // -> L2
@@ -200,7 +202,7 @@ class PathTraversalTests extends AnyWordSpec with ExampleGraphSetup {
200202
Seq(center, r1, r2)
201203
)
202204
// we can hide internal steps from path-tracking
203-
centerTrav.enablePathTracking.union(t => Traversal.from(t.out.out).iterator).path.toSetMutable shouldBe Set(
205+
centerTrav.enablePathTracking.union(t => (t.out.out.l).iterator).path.toSetMutable shouldBe Set(
204206
Seq(center, l2),
205207
Seq(center, r2)
206208
)

traversal-tests/src/test/scala/overflowdb/traversal/RepeatTraversalTests.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -380,8 +380,8 @@ class RepeatTraversalTests extends AnyWordSpec with ExampleGraphSetup {
380380
c --- Connection.Label --> a
381381

382382
val repeatCount = 100000
383-
Traversal.fromSingle(a).repeat(_.out)(_.maxDepth(repeatCount)).property(Name).l shouldBe List("b")
384-
Traversal.fromSingle(a).repeat(_.out)(_.maxDepth(repeatCount).breadthFirstSearch).property(Name).l shouldBe List(
383+
Iterator.single(a).repeat(_.out)(_.maxDepth(repeatCount)).property(Name).l shouldBe List("b")
384+
Iterator.single(a).repeat(_.out)(_.maxDepth(repeatCount).breadthFirstSearch).property(Name).l shouldBe List(
385385
"b"
386386
)
387387

@@ -441,7 +441,7 @@ class RepeatTraversalTests extends AnyWordSpec with ExampleGraphSetup {
441441
.toSetMutable shouldBe Set(Seq(r1, r2, r3, r4))
442442

443443
r1.start.enablePathTracking.repeat(_.out.out)(_.maxDepth(2)).l shouldBe Seq(r5)
444-
r1.start.enablePathTracking.repeat(_.out.out)(_.maxDepth(2)).path.head shouldBe List(r1, r2, r3, r4, r5)
444+
r1.start.enablePathTracking.repeat(_.out.out)(_.maxDepth(2)).path.next() shouldBe List(r1, r2, r3, r4, r5)
445445
}
446446
"should not forget steps preceding the repeat" in {
447447
centerTrav.enablePathTracking.followedBy

0 commit comments

Comments
 (0)