summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Iry <jamesiry@gmail.com>2013-02-07 21:42:18 -0800
committerJames Iry <jamesiry@gmail.com>2013-02-07 21:42:18 -0800
commit62b9e494115cb7a0c4461dbef348c58dd69d7c2b (patch)
treed5f57c54a3d1e74819d5e3ae72a158b6f99a05e3
parent40056d1cf028a967ae24f392a8d825ac7827b913 (diff)
parentfa3b8040ebfedc721a538476be28a6217f1dec56 (diff)
downloadscala-62b9e494115cb7a0c4461dbef348c58dd69d7c2b.tar.gz
scala-62b9e494115cb7a0c4461dbef348c58dd69d7c2b.tar.bz2
scala-62b9e494115cb7a0c4461dbef348c58dd69d7c2b.zip
Merge pull request #2093 from adriaanm/ticket-6961
SI-6961 no structural sharing in list serialization
-rw-r--r--src/library/scala/collection/immutable/List.scala33
-rw-r--r--test/files/run/t5374.check6
-rw-r--r--test/files/run/t5374.scala76
3 files changed, 9 insertions, 106 deletions
diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala
index 55ac3995e9..9765e7c52f 100644
--- a/src/library/scala/collection/immutable/List.scala
+++ b/src/library/scala/collection/immutable/List.scala
@@ -55,6 +55,12 @@ import java.io._
* val shorter = mainList.tail // costs nothing as it uses the same 2::1::Nil instances as mainList
* }}}
*
+ * @note The functional list is characterized by persistence and structural sharing, thus offering considerable
+ * performance and space consumption benefits in some scenarios if used correctly.
+ * However, note that objects having multiple references into the same functional list (that is,
+ * objects that rely on structural sharing), will be serialized and deserialized with multiple lists, one for
+ * each reference to it. I.e. structural sharing is lost after serialization/deserialization.
+ *
* @author Martin Odersky and others
* @version 2.8
* @since 1.0
@@ -352,25 +358,8 @@ final case class ::[B](private var hd: B, private[scala] var tl: List[B]) extend
override def tail : List[B] = tl
override def isEmpty: Boolean = false
- private def writeObject(out: ObjectOutputStream) {
- out.writeObject(ListSerializeStart) // needed to differentiate with the legacy `::` serialization
- out.writeObject(this.hd)
- out.writeObject(this.tl)
- }
-
private def readObject(in: ObjectInputStream) {
- val obj = in.readObject()
- if (obj == ListSerializeStart) {
- this.hd = in.readObject().asInstanceOf[B]
- this.tl = in.readObject().asInstanceOf[List[B]]
- } else oldReadObject(in, obj)
- }
-
- /* The oldReadObject method exists here for compatibility reasons.
- * :: objects used to be serialized by serializing all the elements to
- * the output stream directly, but this was broken (see SI-5374).
- */
- private def oldReadObject(in: ObjectInputStream, firstObject: AnyRef) {
+ val firstObject = in.readObject()
hd = firstObject.asInstanceOf[B]
assert(hd != ListSerializeEnd)
var current: ::[B] = this
@@ -378,14 +367,14 @@ final case class ::[B](private var hd: B, private[scala] var tl: List[B]) extend
case ListSerializeEnd =>
current.tl = Nil
return
- case a : Any =>
+ case a =>
val list : ::[B] = new ::(a.asInstanceOf[B], Nil)
current.tl = list
current = list
}
}
- private def oldWriteObject(out: ObjectOutputStream) {
+ private def writeObject(out: ObjectOutputStream) {
var xs: List[B] = this
while (!xs.isEmpty) { out.writeObject(xs.head); xs = xs.tail }
out.writeObject(ListSerializeEnd)
@@ -654,10 +643,6 @@ object List extends SeqFactory[List] {
}
/** Only used for list serialization */
-@SerialVersionUID(0L - 8287891243975527522L)
-private[scala] case object ListSerializeStart
-
-/** Only used for list serialization */
@SerialVersionUID(0L - 8476791151975527571L)
private[scala] case object ListSerializeEnd
diff --git a/test/files/run/t5374.check b/test/files/run/t5374.check
deleted file mode 100644
index 6be88d77ec..0000000000
--- a/test/files/run/t5374.check
+++ /dev/null
@@ -1,6 +0,0 @@
-ListBuffer(1, 2, 3, 1)
-ListBuffer(1, 2, 3, 1)
-ListBuffer()
-List(1, 2, 3, 4, 5)
-List(1, 2, 3)
-ok \ No newline at end of file
diff --git a/test/files/run/t5374.scala b/test/files/run/t5374.scala
deleted file mode 100644
index 9b1671e795..0000000000
--- a/test/files/run/t5374.scala
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
-
-import collection.mutable.ListBuffer
-import java.io._
-
-
-
-object Test {
-
- def main(args: Array[String]) {
- ticketExample()
- emptyListBuffer()
- list()
- legacyList()
- objectWithMultipleLists()
- }
-
- def inAndOut[T <: AnyRef](obj: T): T = {
- val baos = new ByteArrayOutputStream
- val oos = new ObjectOutputStream(baos)
- oos.writeObject( obj )
- val bais = new ByteArrayInputStream( baos.toByteArray )
- val ois = new ObjectInputStream(bais)
- ois.readObject.asInstanceOf[T]
- }
-
- def ticketExample() {
- val lb = inAndOut(ListBuffer(1, 2, 3))
- val lb2 = ListBuffer[Int]() ++= lb
-
- lb2 ++= List(1)
- lb ++= List(1)
- println(lb)
- println(lb2)
- }
-
- def emptyListBuffer() {
- val lb = inAndOut(ListBuffer[Int]())
-
- println(lb)
- }
-
- def list() {
- val l = inAndOut(List(1, 2, 3, 4, 5))
-
- println(l)
- }
-
- // this byte array corresponds to what List(1, 2, 3) used to be serialized to prior to this fix
- val listBytes = Array[Byte](-84, -19, 0, 5, 115, 114, 0, 39, 115, 99, 97, 108, 97, 46, 99, 111, 108, 108, 101, 99, 116, 105, 111, 110, 46, 105, 109, 109, 117, 116, 97, 98, 108, 101, 46, 36, 99, 111, 108, 111, 110, 36, 99, 111, 108, 111, 110, -118, 92, 99, 91, -10, -40, -7, 109, 3, 0, 2, 76, 0, 43, 115, 99, 97, 108, 97, 36, 99, 111, 108, 108, 101, 99, 116, 105, 111, 110, 36, 105, 109, 109, 117, 116, 97, 98, 108, 101, 36, 36, 99, 111, 108, 111, 110, 36, 99, 111, 108, 111, 110, 36, 36, 104, 100, 116, 0, 18, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 59, 76, 0, 2, 116, 108, 116, 0, 33, 76, 115, 99, 97, 108, 97, 47, 99, 111, 108, 108, 101, 99, 116, 105, 111, 110, 47, 105, 109, 109, 117, 116, 97, 98, 108, 101, 47, 76, 105, 115, 116, 59, 120, 112, 115, 114, 0, 17, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 73, 110, 116, 101, 103, 101, 114, 18, -30, -96, -92, -9, -127, -121, 56, 2, 0, 1, 73, 0, 5, 118, 97, 108, 117, 101, 120, 114, 0, 16, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 78, 117, 109, 98, 101, 114, -122, -84, -107, 29, 11, -108, -32, -117, 2, 0, 0, 120, 112, 0, 0, 0, 1, 115, 113, 0, 126, 0, 4, 0, 0, 0, 2, 115, 113, 0, 126, 0, 4, 0, 0, 0, 3, 115, 114, 0, 44, 115, 99, 97, 108, 97, 46, 99, 111, 108, 108, 101, 99, 116, 105, 111, 110, 46, 105, 109, 109, 117, 116, 97, 98, 108, 101, 46, 76, 105, 115, 116, 83, 101, 114, 105, 97, 108, 105, 122, 101, 69, 110, 100, 36, -118, 92, 99, 91, -9, 83, 11, 109, 2, 0, 0, 120, 112, 120)
-
- def legacyList() {
- val bais = new ByteArrayInputStream(listBytes)
- val ois = new ObjectInputStream(bais)
- val l = ois.readObject()
-
- println(l)
- }
-
- class Foo extends Serializable {
- val head = List(1, 2, 3)
- val last = head.tail.tail
- def structuralSharing: Boolean = head.tail.tail eq last
-
- assert(structuralSharing)
- }
-
- def objectWithMultipleLists() {
- val foo = inAndOut(new Foo)
-
- if (foo.structuralSharing) println("ok")
- else println("no structural sharing")
- }
-
-}