# HG changeset patch # User Jaroslav Tulach # Date 1346437017 -7200 # Node ID e25dbfce40e98170ec77a049f2f68badef813bc5 # Parent a9097bdcf30720e9a4f4c4e7f8a32f7033071b74 Example demostrating how to use trait to provide effective implementation of linked list while keeping encapsulation diff -r a9097bdcf307 -r e25dbfce40e9 samples/effectivelist/build.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/effectivelist/build.xml Fri Aug 31 20:16:57 2012 +0200 @@ -0,0 +1,74 @@ + + + + + + Builds, tests, and runs the project Effective List. + + + + + + + + + diff -r a9097bdcf307 -r e25dbfce40e9 samples/effectivelist/nbproject/build-impl.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/effectivelist/nbproject/build-impl.xml Fri Aug 31 20:16:57 2012 +0200 @@ -0,0 +1,710 @@ + + + + + + + + + + + + + + + + + + + You must set SCALA_HOME or environment property and append "-J-Dscala.home=scalahomepath" + property to the end of "netbeans_default_options" in NetBeansInstallationPath/etc/netbeans.conf to point to + Scala installation directory. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set test.src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + + + + + + java -cp "${run.classpath.with.dist.jar}" ${main.class} + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + diff -r a9097bdcf307 -r e25dbfce40e9 samples/effectivelist/nbproject/genfiles.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/effectivelist/nbproject/genfiles.properties Fri Aug 31 20:16:57 2012 +0200 @@ -0,0 +1,8 @@ +build.xml.data.CRC32=f1350d5d +build.xml.script.CRC32=037abbe8 +build.xml.stylesheet.CRC32=ca9d572e@1.5 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=f1350d5d +nbproject/build-impl.xml.script.CRC32=ff0a633f +nbproject/build-impl.xml.stylesheet.CRC32=5220179f@1.5 diff -r a9097bdcf307 -r e25dbfce40e9 samples/effectivelist/nbproject/project.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/effectivelist/nbproject/project.properties Fri Aug 31 20:16:57 2012 +0200 @@ -0,0 +1,62 @@ +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form,**/*.scala +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/Effective_List.jar +dist.javadoc.dir=${dist.dir}/scaladoc +excludes= +includes=** +jar.compress=false +java.platform.active=java_default_platform +javac.classpath= +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.source=1.5 +javac.target=1.5 +libs.junit_4.classpath=../libs/dist/junit-4.4.jar +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir}:\ + ${libs.junit_4.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +meta.inf.dir=${src.dir}/META-INF +platform.active=default_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value +# or test-sys-prop.name=value to set system properties for unit tests): +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +# Space-separated list of extra scalac options +scalac.compilerargs= +scalac.deprecation=no +scalac.unchecked=no +source.encoding=UTF-8 +src.dir=src +test.src.dir=test diff -r a9097bdcf307 -r e25dbfce40e9 samples/effectivelist/nbproject/project.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/effectivelist/nbproject/project.xml Fri Aug 31 20:16:57 2012 +0200 @@ -0,0 +1,16 @@ + + + org.netbeans.modules.scala.project + + + Effective List + 1.6.5 + + + + + + + + + diff -r a9097bdcf307 -r e25dbfce40e9 samples/effectivelist/src/org/apidesign/effectivelist/List.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/effectivelist/src/org/apidesign/effectivelist/List.scala Fri Aug 31 20:16:57 2012 +0200 @@ -0,0 +1,74 @@ +package org.apidesign.effectivelist + +/** + * Implementation of add and remove efficient list. It has just one + * restriction - its items need to carry additional information to help + * the list to be effective. All items must extend trait {@link Listable}: + *
+ * case class Person(name : String) extends Listable[Person]
+ * 
+ */ +final class List[T <: Listable[T]] { + private var item : T = _ + private final var EMPTY : T = _ + + final def get(index : Int) : T = { + var pos : T = item; + for (i <- 1 to index) { + pos = pos.next; + if (pos == item) { + throw new IndexOutOfBoundsException() + } + } + return pos + } + + final def size() : Int = { + if (item == EMPTY) { + return 0 + } + var size = 0 + var pos : T = item + do { + size = size + 1 + pos = pos.next + } while (pos != item) + return size + } + + final def add(toAdd : T) : Boolean = { + if (toAdd.prev != EMPTY) { + return false + } + + if (item == null) { + item = toAdd + toAdd.next = toAdd + toAdd.prev = toAdd + return true + } else { + toAdd.prev = item.prev + item.prev.next = toAdd + item.prev = toAdd + toAdd.next = item + return true + } + } + final def remove(toRemove : T) : Boolean = { + if (toRemove.prev == EMPTY) { + return false + } else { + toRemove.prev.next = toRemove.next + toRemove.next.prev = toRemove.prev; + if (item.next == item) { + item = EMPTY + } + if (item == toRemove) { + item = toRemove.next + } + toRemove.next = EMPTY + toRemove.prev = EMPTY + return true + } + } +} diff -r a9097bdcf307 -r e25dbfce40e9 samples/effectivelist/src/org/apidesign/effectivelist/Listable.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/effectivelist/src/org/apidesign/effectivelist/Listable.scala Fri Aug 31 20:16:57 2012 +0200 @@ -0,0 +1,9 @@ +package org.apidesign.effectivelist + +/** A member of a {@link List} that makes keeping references + * to previous and next items in the list effective. + */ +trait Listable[T <: Listable[T]] { + private[effectivelist] var prev : T = _ + private[effectivelist] var next : T = _ +} diff -r a9097bdcf307 -r e25dbfce40e9 samples/effectivelist/test/org/apidesign/effectivelist/ListTest.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/effectivelist/test/org/apidesign/effectivelist/ListTest.scala Fri Aug 31 20:16:57 2012 +0200 @@ -0,0 +1,85 @@ +package org.apidesign.effectivelist + +import org.junit._ +import Assert._ + +class ListTest { + case class Person(name : String, age : Int) extends Listable[Person] + + var list : List[Person] = _ + var p1, p2, p3, p4 : Person = _ + + @Before def initializeListAndValues: Unit = { + list = new List[Person] + p1 = new Person("Jarda", 39) + p2 = new Person("Sona", 37) + p3 = new Person("Anna", 7) + p4 = new Person("Ondra", 6) + } + + @Test def tryFewAdditions = { + assertTrue(list.add(p1)) + assertTrue(list.add(p2)) + assertTrue(list.add(p3)) + assertTrue(list.add(p4)) + + assertEquals("Jarda was inserted first", "Jarda", list.get(0).name) + assertEquals("Sona was inserted 2nd", 37, list.get(1).age) + assertEquals("Anna was inserted 3rd", "Anna", list.get(2).name) + assertEquals("Anna was inserted 4th", 6, list.get(3).age) + } + + @Test def addFewAndThenTryToRemoveHead() = { + assertTrue(list.add(p1)) + assertTrue(list.add(p2)) + assertTrue(list.add(p3)) + + assertEquals("Size it three", 3, list.size()) + assertEquals("Jarda was inserted first", "Jarda", list.get(0).name) + + assertFalse("Can't remove not added element", list.remove(p4)) + assertTrue("OK to remove head", list.remove(p1)) + + assertEquals("Sona is now first", "Sona", list.get(0).name) + assertEquals("Anna is now 2nd", "Anna", list.get(1).name) + + try { + list.get(2) + fail("Previous call should throw exception") + } catch { + case e : IndexOutOfBoundsException => ; // OK + } + } + + @Test def addFewAndThenTryToRemoveSecond() = { + assertEquals(0, list.size()) + assertTrue(list.add(p1)) + assertEquals(1, list.size()) + assertTrue(list.add(p2)) + assertEquals(2, list.size()) + assertTrue(list.add(p3)) + assertEquals(3, list.size()) + + assertEquals("Size it three", 3, list.size()) + assertEquals("Jarda was inserted first", "Jarda", list.get(0).name) + + assertFalse("Can't remove not added element", list.remove(p4)) + assertTrue("OK to remove head", list.remove(p2)) + + assertEquals("Jarda is still first", "Jarda", list.get(0).name) + assertEquals("Anna is now 2nd", "Anna", list.get(1).name) + + try { + list.get(2); + fail("Previous call should throw exception") + } catch { + case e : IndexOutOfBoundsException => ; // OK + } + assertEquals(2, list.size()); + + list.remove(p1) + list.remove(p3) + + assertEquals("Not it is empty", 0, list.size()) + } +} diff -r a9097bdcf307 -r e25dbfce40e9 samples/libs/build.xml --- a/samples/libs/build.xml Mon Aug 13 10:52:45 2012 +0200 +++ b/samples/libs/build.xml Fri Aug 31 20:16:57 2012 +0200 @@ -1,6 +1,6 @@ - - + + @@ -42,6 +42,23 @@ + + + + + + + + + + + + + + + + +