+ else: return me._list[-1]
+
+class Options (object):
+ def __init__(me):
+ op = OP.OptionParser\
+ (usage = "%prog [-y] [-c STEPS] [-f FILE] [-l LIMIT] [-n STEPS] PROG")
+ for short, long, kw in \
+ [("-c", "--ckpt-steps",
+ dict(type = "int", metavar = "STEPS",
+ dest = "ckpt_steps", default = 5000,
+ help = "number of steps between checkpoints")),
+ ("-f", "--ckpt-file",
+ dict(type = "string", metavar = "FILE",
+ dest = "ckpt_file", default = "soak.ckpt",
+ help = "file to hold checkpoint information")),
+ ("-l", "--limit",
+ dict(type = "int", metavar = "LIMIT",
+ dest = "limit", default = None,
+ help = "exclusive limit value to store in test trees")),
+ ("-n", "--steps",
+ dict(type = "int", metavar = "STEPS",
+ dest = "nsteps", default = None,
+ help = "number of steps to run before stopping")),
+ ("-y", "--sync",
+ dict(action = "store_true", dest = "sync",
+ help = "check and print state after every step"))]:
+ op.add_option(short, long, **kw)
+ opts, args = op.parse_args()
+ me.limit = opts.limit
+ me.ckpt_file = opts.ckpt_file
+ me.sync = opts.sync
+ me.ckpt_steps = opts.ckpt_steps
+ me.nsteps = opts.nsteps
+ if len(args) != 1: op.print_usage(SYS.stderr); SYS.exit(2)
+ me.testprog = args[0]
+
+class Level (object):
+ def __init__(me, kind, base, limit, tree = "_"):
+ me.coll = Collection(map(int, RX.findall(r"\d+", tree)))
+ me.kind, me.base, me.limit, me.tree = kind, int(base), int(limit), tree
+ me.rlim = int(M.sqrt(me.limit - me.base))
+ def write(me, file):
+ file.write("%s %d %d %s\n" % (me.kind, me.base, me.limit, me.tree))
+ @classmethod
+ def read(cls, file):
+ line = file.readline()
+ if line == "": return None
+ kind, base, limit, tree = line.split(maxsplit = 3)
+ return cls(kind, base, limit, tree)
+
+class State (object):
+ def __init__(me, opts):
+ me._ckpt_file = opts.ckpt_file
+ try:
+ with open(me._ckpt_file, "r") as f:
+ me.seed, = f.readline().split()
+ stack = []
+ while True:
+ lv = Level.read(f)
+ if lv is None: break
+ stack.append(lv)
+ assert stack
+ me.cur = stack.pop()
+ me.stack = stack
+ if opts.limit is not None and me.cur.limit != opts.limit:
+ raise ValueError("checkpointed limit %d /= command-line limit %d" %
+ (me.cur.limit, opts.limit))
+ except OSError as err:
+ if err.errno != E.ENOENT: raise
+ me.seed = base64_encode(OS.urandom(SEEDSZ))
+ if opts.limit is not None: me.limit = opts.limit
+ else: me.limit = 4096
+ me.stack = []
+ me.cur = Level('base', 0, me.limit)
+ me.write_ckpt(reseed = False)
+ me.rand = RND.Random(me.seed)
+ n, b = 0, me.cur.limit
+ while True:
+ bb = int(M.sqrt(b)) + 4
+ if bb >= b: break
+ n, b = n + 1, bb
+ me.stklim = n
+ def push(me, lv):
+ me.stack.append(me.cur)
+ me.cur = lv
+ def pop(me):
+ assert me.stack
+ lv = me.cur
+ me.cur = me.stack.pop()
+ return lv
+ def write_ckpt(me, reseed = True):
+ if reseed:
+ me.seed = base64_encode(bytes(me.rand.randrange(256)
+ for _ in range(SEEDSZ)))
+ me.rand.seed(me.seed)
+ new = me._ckpt_file + ".new"
+ with open(new, "w") as f:
+ f.write("%s\n" % me.seed)
+ for lv in me.stack: lv.write(f)
+ me.cur.write(f)
+ OS.rename(new, me._ckpt_file)
+ def clear_ckpt(me):
+ try: OS.unlink(me._ckpt_file)
+ except OSError as err:
+ if err.errno == E.ENOENT: pass
+ else: raise
+
+def choices():
+ ch = [(896, "addrm1"),
+ (56, "addrmn"),
+ (56, "lookup")]
+
+ sp = len(ST.stack)
+ ch += [(ST.stklim - sp, "split"),
+ (ST.stklim - sp, "push")]
+
+ if ST.cur.kind == "join":
+ ch += [(sp, "join0"), (sp, "join1")]
+ elif ST.cur.kind == "setop":
+ ch += [(sp, "unisect"), (sp, "diffsect")]
+ elif ST.cur.kind == "base":
+ pass