[Assorted-commits] SF.net SVN: assorted: [758] zdb/trunk/src/zdb
Brought to you by:
yangzhang
From: <yan...@us...> - 2008-05-08 20:22:35
|
Revision: 758 http://assorted.svn.sourceforge.net/assorted/?rev=758&view=rev Author: yangzhang Date: 2008-05-08 13:22:22 -0700 (Thu, 08 May 2008) Log Message: ----------- blah...some sort of checkpoint Modified Paths: -------------- zdb/trunk/src/zdb/AltUi.scala zdb/trunk/src/zdb/Core.scala Modified: zdb/trunk/src/zdb/AltUi.scala =================================================================== --- zdb/trunk/src/zdb/AltUi.scala 2008-05-08 20:20:00 UTC (rev 757) +++ zdb/trunk/src/zdb/AltUi.scala 2008-05-08 20:22:22 UTC (rev 758) @@ -13,6 +13,23 @@ // import scala.collection.jcl._ import scala.io._ +//object Slick { +// implicit def str2xobj(s: String) = XObj(deref(getObj(s))) +// implicit def xobj2str(o: XObj) = o.obj.id +// implicit def objref2xobj(o: ObjRef) = XObj(deref(o)) +// implicit def xobj2objref(o: XObj) = o.obj.id +// implicit def obj2xobj(o: Obj) = XObj(o) +// implicit def xobj2obj(o: XObj) = o.obj +// case class XObj(obj: Obj) { +// def vals = ValsAdapter +// } +// def example { +// val word = XObj("Word") +// word("media about this") += "review of Word" +// word("media about this") += getObj("review of Word") +// } +//} + /** Command-line interface. */ object FileIo { @@ -39,7 +56,7 @@ def readStruct = { val lines = readBlock val pairs = for (line <- lines) yield { - val Seq(key, valstr) = line split (": ", 2) + val Seq(key, valstr) = line split (":", 2) map (_ trim) val vals = valstr split ";" map (_ trim) (key, vals) } @@ -47,66 +64,213 @@ if (map.size != pairs.length) throw new Exception("duplicate key") map } - /** Update by struct, either adding or updating an object. */ + /** + * Important notes: + * + * - 'parents' is ignored (only used when adding object) + * - everything is replaced; no diffs are computed + */ + def modifyStruct = { + val map = readStruct + val obj = getObj(map("names")(0)) + for ((key, vals) <- map; if key != "parents") { + vals match { + case Seq("_") => + try { unset(map("names")(0),key) } + catch { case e: BadPropException => () } + case _ => infoprop(obj,key).typ match { + case _: ObjSetT => setobj(map("names")(0),key)(vals:_*) + case _: StrSetT => set(map("names")(0),key)(vals:_*) + } + } + } + validateAll + } + + /** Read a block and parse it as a struct. */ + def readSuperStruct = { + val lines = readBlock + val Seq(vallines, proplines) = splitBy(lines)(_ == "new properties:") + + // Values + + val valtuples = for (line <- vallines) yield { + val Seq(key, valstr) = line split (":", 2) map (_ trim) + val vals = valstr split ";" map (_ trim) + (key, vals) + } + val vals = Map(valtuples: _*) + if (vals.size != valtuples.length) throw new Exception("duplicate val key") + + // Properties + + val proptuples = + for ((hdr,bdy) <- separateHeads(groupByHeaders(proplines)(!_.startsWith(" ")))) + yield { + val key = hdr.trim.toList.init.mkString + //val bdymap = Map(bdy map (x => x split ":" map (y => y trim)): _*) + val bdymap = Map(bdy map (_ split (":",2) map (_ trim)) map {case Seq(a,b) => (a,b)}: _*) + val typ = readType(bdymap("type")) + val defStr = bdymap("default") split ";" map (_ trim) + val default = typ match { + case _: StrSetT => mkStrSetV(defStr) + case _: ObjSetT => mkObjSetV(defStr map getObj) + } + (key, Prop(typ, default, false)) + } + val props = Map(proptuples: _*) + if (props.size != proptuples.length) throw new Exception("duplicate prop key") + + (vals, props) + } + /** + * Update by struct, either adding or updating an object. If the object + * exists, compute the diff and apply only those changes. + */ def updateStruct(shouldExist: Boolean) = { - val map = readStruct + val (vals,props) = readSuperStruct + val objname = vals("names")(0) val obj = if (shouldExist) { - deref(getObj(map("names")(0))) + getObj(objname) } else { try { - getObj(map("names")(0)) + getObj(objname) throw new Exception("object of that name already exists") } catch { - case e: Exception => mkObj(map("parents") map getObj) + case e: Exception => mk(vals("names"):_*)(vals("parents"):_*) } } - for ((key, vals) <- map; if key != "parents") { - obj.infoProp(key).typ match { - case _: ObjSetT => obj.setProp(key, mkObjSetV(vals map getObj)) - case _: StrSetT => obj.setProp(key, mkStrSetV(vals)) - } + + // TODO add a way to update parents; this probably requires a new + // ZdbUtil function + + // Next, update properties + + val oldPropsSeq = + for ((_, propname, prop, _) <- getProps(deref(obj))) + yield (propname, prop) + val oldProps: Set[(String,Prop)] = Set(oldPropsSeq.toStream: _*) + val newProps: Set[(String,Prop)] = Set(props.toStream:_*) + val addedProps = newProps -- oldProps + val removedProps = oldProps -- newProps + + for ((propname, p) <- addedProps) { + println("adding property: " + propname) + if (p.typ.isInstanceOf[StrSetT]) + prop(objname, propname, showType(p.typ), Some(p.default.asInstanceOf[StrSetV].s.toList(0)), p.opt) } + for ((propname, prop) <- removedProps) { + println("removing property: " + propname) + rmprop(objname, propname) + } + + // Next, update values + +// val oldValues = asdf +// +// for ((key, vals) <- map; if key != "parents") { +// infoprop(obj,key).typ match { +// case _: ObjSetT => setobj(map("names")(0),key)(vals:_*) +// case _: StrSetT => set(map("names")(0),key)(vals:_*) +// } +// } validateAll } + + def showVal(valOpt: Option[Val]) = { + valOpt match { + case Some(StrSetV(s)) => s mkString "; " + case Some(ObjSetV(s)) => s map deref map nameAndId mkString "; " + case Some(NilV()) => "(nil)" + case None => "_" + } + } + /** Show an object in struct format. */ def show(o: Obj) = { - val lines = for ((key, vals) <- o.vals) yield { - val valstr = vals match { - case StrSetV(s) => s mkString "; " - case ObjSetV(s) => s map deref map nameAndId mkString "; " - } - key + ": " + valstr + val vallines = for ((owner, name, prop, valsOpt) <- getProps(o)) yield { + name + ": " + showVal(valsOpt) } - lines mkString "\n" + + val full = false + val props = + if (!full) + o.props + else + for ((owner, name, prop, valsOpt) <- getProps(o)) + yield (name, prop) + + val proplines = for ((name, prop) <- props) yield { + val top = " " + name + ":" + val defaultstr = " default: " + showVal(Some(prop.default)) + val typestr = " type: " + ( + prop.typ match { + case StrSetT() => "string set" + case ObjSetT(rels) => "object set: " + ( + rels map { case (ref, revkey) => + nameAndId(deref(ref)) + " [" + revkey + "]" + } mkString "; " + ) + } + ) + List(top, defaultstr, typestr) mkString "\n" + } + + (vallines ++ List("new properties:") ++ proplines) mkString "\n" } + def showDescendants(s: String) { + for (d <- descendants(deref(getObj(s)))) { + println(show(d)) + println + } + } + + def showChildren(s: String) { + for (c <- deref(getObj(s)).children map deref) { + println(show(c)) + println + } + } + def main(argv: Array[String]) { while (true) { Console print ">>> " val line = Console.readLine if (line == null) return - val ws = words(line.trim) - val args = ws drop 1 - ws(0) match { - case "load-full" => loadFilePickle("data/data") - case "load" => load - case "validate" => validateAll - case "save-full" => { validateAll; saveFilePickle(ws(1)) } - case "save" => { validateAll; save } - case "find" => println(find(args mkString " ")) - case "get-full" => args match { - case Seq(name) => println(print(deref(getObj(name)))) - case Seq(name, refine) => println(print(deref(getObj(name, refine)))) + try { + val ws = words(line.trim) + val args = ws drop 1 + ws(0) match { + case "load-full" => loadFilePickle("data/data") + case "load" => load + case "validate" => validateAll + case "save-full" => { validateAll; saveFilePickle(ws(1)) } + case "save" => { validateAll; save } + case "find" => println(find(args mkString " ")) + case "get-full" => args match { + case Seq(name) => println(print(deref(getObj(name)))) + case Seq(name, refine) => println(print(deref(getObj(name, refine)))) + } + case "get" => args match { + case Seq(name) => + try { println(show(deref(name.toInt))) } + catch { case e: NumberFormatException => println(show(deref(getObj(name)))) } + case Seq(name, refine) => println(show(deref(getObj(name, refine)))) + } + case "add" => updateStruct(false) + case "update" => updateStruct(true) + case "modify" => modifyStruct + case "quit" => return + case "exit" => return + case "get-children" => showChildren(args(0)) + case "get-desc" => showDescendants(args(0)) + case "" => () + case x => println("unknown command: " + x) } - case "get" => args match { - case Seq(name) => println(show(deref(getObj(name)))) - case Seq(name, refine) => println(show(deref(getObj(name, refine)))) - } - case "add" => updateStruct(false) - case "update" => updateStruct(true) - case "" => () - case x => println("unknown command: " + x) + } catch { + case e: Exception => e.printStackTrace } } } Modified: zdb/trunk/src/zdb/Core.scala =================================================================== --- zdb/trunk/src/zdb/Core.scala 2008-05-08 20:20:00 UTC (rev 757) +++ zdb/trunk/src/zdb/Core.scala 2008-05-08 20:22:22 UTC (rev 758) @@ -10,6 +10,7 @@ package zdb import scala.collection.mutable._ +import scala.collection.{mutable => mut, immutable => immut} import scala.io.BytePickle._ import commons.Collections._ import commons.Control._ @@ -24,6 +25,11 @@ // object ZdbUtil { + def mkHashSet[a](xs: Seq[a]) = { + val set = new HashSet[a] + set ++= xs + set + } var universe = new Universe implicit def obj2xobj(o:Obj) = XObj(o) implicit def xobj2obj(o:XObj) = o.o @@ -58,9 +64,11 @@ case other => printSumm(other) } def printSummObj(o: Obj) = { - val names = o.getProp("names").asInstanceOf[StrSetV].s.toList - val name = if (names.length > 0) names(0) else "" - name + val names = getProp(o,"names") match { + case v: StrSetV => v.s.toList + case _ => List[String]() + } + if (names.length > 0) names(0) else "" } def printSumm(o: Obj): String = printSummObj(o) def printSumm(v: Val): String = v match { @@ -73,6 +81,9 @@ case Prop(typ, default, opt) => "Prop(typ: " + typ + ", default: " + printSumm(default) + ", opt: " + opt + ")" } type ObjRef = Int + /** + * Add a rel prop to both sides. + */ def addRelProp(lref: ObjRef, lname: String, rref: ObjRef, rname: String) = { val left = deref(lref) @@ -93,6 +104,14 @@ doit(left, rname, rref, lname) doit(right, lname, lref, rname) } + /** + * safe + * + * Add a rel prop to one side then the other. Similar to connect(), except + * this uses the raw props map rather than getProp. connect() is less safe + * to use than this as a result, since it may potentially mutate a + * grandparent. + */ def addRel(lname: String, left: ObjRef, rname: String, right: ObjRef) = { def addOneSide(o: Obj, name: String, other: Obj) = { def getDef(o: Obj): Option[Val] = o.props get name match { @@ -147,13 +166,26 @@ } } def getObjs(name: String) = { - val pred: Obj => Boolean = _.getProp("names").asInstanceOf[StrSetV].s.contains(name) - scala.collection.immutable.Set.empty[Obj] ++ (objs filter pred) + val pat = "^(.+) +\\(([0-9]+)\\)$" + val realname = name replaceAll (pat, "$1") + lazy val ref = name replaceAll (pat, "$2") toInt + def pred(o: Obj) = getProp(o,"names") match { + case v: StrSetV => v.s.contains(name) + case _ => false + } + if (realname == name) { + scala.collection.immutable.Set.empty[Obj] ++ (objs filter pred) + } else { + val o = deref(ref) + if (realname != "" && !(getProp(o,"names").asInstanceOf[StrSetV].s contains realname)) + throw new Exception + scala.collection.immutable.Set(o) + } } def getObj(name: String) = { val objs = getObjs(name) objs.size match { - case 0 => throw new NoResultException + case 0 => { Console.err println name; throw new NoResultException } case 1 => (objs toList 0).id case _ => throw new MultiResultException(objs.size, name, objs) } @@ -167,19 +199,46 @@ case _ => throw new MultiResultException(objs.size, name, objs) } } - def ancestors(x: Obj): Set[Obj] = { - Set(x) ++ strictAncestors(x) + + def descendants(x: Obj): Set[Obj] = Set(x) ++ strictDescendants(x) + def strictDescendants(x: Obj): Set[Obj] = { + val ds = for (c <- x.children map deref; d <- descendants(c)) yield d + Set(ds toList: _*) } + + def ancestors(x: Obj): Set[Obj] = Set(x) ++ strictAncestors(x) def strictAncestors(x: Obj): Set[Obj] = { - val as = for (p <- x.parents map deref; - a <- ancestors(p)) yield p + val as = for (p <- x.parents map deref; a <- ancestors(p)) yield a Set(as toList: _*) } - // given an object, returns a list of all the properties associated with the object, including those from its parents + + def union(typ: Type, vs: Seq[Val]) = { + def extract[a](vs: Seq[Val], subextract: Val => HashSet[a]) = { + val es = for (v <- vs; if !v.isInstanceOf[NilV]; e <- subextract(v)) yield e + mkHashSet(es) + } + typ match { + case _: StrSetT => StrSetV(extract[String](vs, _.asInstanceOf[StrSetV].s)) + case _: ObjSetT => ObjSetV(extract[ObjRef](vs, _.asInstanceOf[ObjSetV].s)) + } + } + + /** this will return a newly constructed value that is the union of all the + * ancestral defaults and the given object's instance value */ + def getProp(x: Obj, k: String) = { + // actual vals cannot be NilV, only default vals (and only str vals at that, it seems?? TODO) + val s = if (x.vals.contains(k)) List(x.vals(k)) else List[Val]() + val r = for (a <- ancestors(x); if a.props contains k) yield a.props(k).default + val allNil = s.isEmpty && (ancestors(x) forall { a => + !a.props.contains(k) || a.props(k).default.isInstanceOf[NilV] + }) + if (allNil) NilV() else union(x.infoProp(k).typ, s ++ r) + } + /** given an object, returns a list of all the properties associated with the + * object, including those from its parents */ def getProps(x: Obj) = { - for (a <- ancestors(x); - (propname, prop) <- a.props.elements.toList) - yield (a, propname, prop, optionize(x getProp propname)) + for (a <- ancestors(x); (propname, prop) <- a.props.elements.toList) + yield (a, propname, prop, optionize(getProp(x,propname))) } def pickleStrSetT: SPU[Type] = wrap( @@ -329,6 +388,10 @@ case class StrSetT extends Type case class ObjSetT(rels: HashSet[Rel]) extends Type +/** + * opt is actually ignored and always set to false (even though properties are + * almost always optional, except for e.g. name + */ case class Prop(typ: Type, default: Val, opt: Boolean) abstract class Val @@ -508,6 +571,7 @@ def addProp(name: String, typ: Type, default: Val, opt: Boolean): Unit = props.update(name, Prop(typ, default, opt)) //@ modifies: vals + /** safe: use this to reset the value of a property */ def setProp(name: String, value: Val): Unit = vals.update(name, value) private def getRecur[A](name: String, acc: Obj => Map[String,A]): Option[A] = @@ -624,7 +688,9 @@ override def toString = "InconsistentObjException(" + msg + "," + print(obj) + "\n)" } class BadValueException extends Exception +class BadTypeStrException(val s: String) extends Exception class NameConflictException extends Exception +class NotImplementedException extends Exception object ObjUser { def mkInst(newNames: String*)(srcNames: String*) = { @@ -639,6 +705,34 @@ obj.isInst = false obj.id } + def rmprop(objName: String, propName: String) { + val obj = deref(getObj(objName)) + if (obj.props removeKey propName isEmpty) throw new BadPropException(obj,propName); + // XXX make sure everyone else's ref to it is cut off + throw new NotImplementedException + } + /** safe: show a type-string */ + def showType(typ: Type) = typ match { + case _: StrSetT => "string set" + case _: ObjSetT => "object set" + case _ => throw new BadTypeException() + } + /** safe: parse a type-string */ + def readType(str: String) = { + val Seq(typ, params) = str.split(":",2) map (_ trim) + typ match { + case "string set" => StrSetT() + case "object set" => ObjSetT(mkHashSet( + for (param <- params split ";") yield { + val p = truncateWhile(param.trim.toCharArray)(_ == ']').mkString + val Seq(domain, revkey) = p split "\\[" map (_ trim) + (getObj(domain), revkey) + } + )) + case _ => throw new BadTypeStrException(str) + } + } + /** safe: add prop */ def prop(objName: String, propName: String, propType: String): Unit = prop(objName, propName, propType, None, false) def prop(objName: String, propName: String, propType: String, default: Option[String], opt: Boolean) = { @@ -647,10 +741,7 @@ case Some(s) => mkStrSetV(s) case None => NilV() } - propType match { - case "string set" => obj.addProp(propName, StrSetT(), dflt, opt) - case _ => throw new BadTypeException() - } + obj.addProp(propName, readType(propType), dflt, opt) } def set(objName: String, propName: String)(values: String*): Unit = set(getObj(objName), propName)(values: _*) @@ -662,6 +753,12 @@ } obj.setProp(propName, v) } + /** safe: wipe out the prop */ + def unset(objName: String, propName: String) = { + val obj = deref(getObj(objName)) + if (obj.vals removeKey propName isEmpty) + throw new BadPropException(obj, propName) + } def setobj(objName: String, propName: String)(values: String*): Unit = setobj(getObj(objName), propName)(values map getObj: _*) def setobj(objRef: ObjRef, propName: String)(values: ObjRef*) = { @@ -692,6 +789,7 @@ return inv throw new Exception } + /** unsafe: use of getProp may result in mutating an ancestor */ def connect(aref: ObjRef, asProp: String, bref: ObjRef) = { val a = deref(aref) val b = deref(bref) @@ -701,19 +799,23 @@ try { b.getProp(bsProp).asInstanceOf[ObjSetV].s += aref } catch { case _: BadPropException => setobj(bref, bsProp)(aref) } } + /** safe: read the value of a property */ def getprop(objName: String, propName: String): Val = getprop(getObj(objName), propName) def getprop(objRef: ObjRef, propName: String) = - deref(objRef).getProp(propName) + getProp(deref(objRef),propName) + /** safe: read the metadata of a property */ def infoprop(objName: String, propName: String): Prop = infoprop(getObj(objName), propName) def infoprop(objRef: ObjRef, propName: String) = deref(objRef).infoProp(propName) + /** safe: add a symmetric relation prop between two objects */ def mirror(objName: String, relName: String) = { val obj = getObj(objName) addRelProp(obj, relName, obj, relName) } + /** safe: add an asymmetric relation prop between two objects */ def rel(lobjName: String, lname: String, robjName: String, rname: String) = { val lobj = getObj(lobjName) @@ -727,6 +829,8 @@ def get(objName: String) = deref(getObj(objName)) def get(objName: String, propName: String) = deref(getObj(objName)).getProp(propName) + /** safe: delete an object from the system and unwire references to it from + * other objects */ def rmobj(objRef: ObjRef, propName: String, value: ObjRef) = { deref(objRef).vals(propName).asInstanceOf[ObjSetV].s -= value val inv = findInv(objRef, propName, value) @@ -1124,7 +1228,7 @@ val names = new HashSet[String] val cnames = new HashSet[String] universe.objs foreach { obj => { - val onames = obj.getProp("names").asInstanceOf[StrSetV].s + val onames = getProp(obj,"names").asInstanceOf[StrSetV].s onames foreach { oname => { if (!( names contains oname )) { names += oname This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |