stanch / reftree

Automatically generated diagrams and animations for Scala data structures
http://stanch.github.io/reftree/
GNU General Public License v3.0
587 stars 36 forks source link

How to add pointers to indices into array #20

Open pathikrit opened 6 years ago

pathikrit commented 6 years ago

I have the following image generated: arraydeque

This is the code I am using:

implicit def `ArrayDeque RefTree`: ToRefTree[mutable.ArrayDeque[Char]] = ToRefTree {ds =>
    val array = ds.privateField[Array[AnyRef]]("array").map(c => Option(c).getOrElse('␀').asInstanceOf[Char])
    val start = ds.privateField[Int]("start")
    val end = ds.privateField[Int]("end")

    val arrayRef = {
      val arrayFields = array.zipWithIndex map { case (a, i) =>
        val name = i match {
          case `start` if start == end => s"start=end=$i"
          case `start` => s"start=$i"
          case `end` => s"end=$i"
          case _ => i.toString
        }
        a.refTree.withHighlight(i == start || i == end).toField.withName(name)
      }
      RefTree.Ref(array, arrayFields).rename(s"char[${array.length}]")
    }

    RefTree.Ref(ds, Seq(
      start.refTree.withHighlight(true).toField.withName("start"),
      end.refTree.withHighlight(true).toField.withName("end"),
      arrayRef.toField.withName("array")
    ) ++ ds.toArray.zipWithIndex.map({case (a, i) => a.refTree.toField.withName(i.toString)}))
  }

But, it would be nice to have start and end have arrows into the array. Is it possible?

stanch commented 6 years ago

Nice animation! In theory, GraphViz supports pointing from fields to other fields, but reftree doesn’t expose that. I’m not sure what would be the best way to do it without making the existing functionality more complicated... But I am open to suggestions! :) In the meantime, some improvements could be using ↳3, 6↲ or ↳5↲ (instead of start=3, end=6, start=end=5 respectively); and highlighting the entire portion of the array that is active, instead of just the end markers.

pathikrit commented 6 years ago

Thank you for the nice library and the fast response.

I have a simple suggestion in mind without complicating the API. After we create the diagram instance, maybe you can draw line between 2 cells by their ids? For example:

val diagram = Diagram.sourceCodeCaption(queue += 'a')
diagram.drawArrow(from = "id-of-field1", to = "id-of-field2", label = "foo")

This would solve most of custom use-cases regarding drawing arbitrary arrows.

This would look nice in a fluent style:

Diagram
  .sourceCodeCaption(queue += 'a')
  .drawArrow(from = "id-of-field1", to = "id-of-field2", label = "foo")
  .drawLine(from ="blah1", to = "blah")
  .putLabel()
stanch commented 6 years ago

How would you specify the ids of fields? In terms of public API, currently only RefTree.Ref has an id, and its fields have indices, although even this information is kind of hidden from the user. At the lower level (dot AST) everything has ids, of course. Would you suggest using those low-level ids and leaving it to the user to figure them out?

pathikrit commented 6 years ago

Can we add a id param to each field? Then we can refer to it likewise?

If not RefTree.Red.id + index would be a hack but can work for now?

stanch commented 6 years ago

One concern I forgot to mention is that right now the arrows mean object references. Adding arrows to fields of a primitive array might be misleading because it might suggest some kind of pointer arithmetic...

pathikrit commented 6 years ago

Hmm, maybe a dashed arrow then? Btw, I will present at Scala Days. I am going to mention this repo (see slide 14 here: https://slides.com/pathikrit/arraydeque#/) for making the visualization possible (actual viz is in here: https://github.com/pathikrit/arraydeque-talk/)