Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

594
LINES

< > BotCompany Repo | #1004681 // OLD Concepts (include)

JavaX fragment (include)

// A concept should be an object, not just a string.

// Functions that should always be there for child processes:
please include function dbLock.

static interface Derefable {
  Concept get();
}
  
sclass Concept extends DynamicObject {
  long id;
  //double energy;
  //bool defunct;
  long created;
  
  // used only internally (cnew)
  *(S className) {
    super(className);
    _created();
  }
  
  *() {
    className = shortClassName(this);
    if (!DynamicObject_loading) {
      //print("New concept of type " + className);
      _created();
    }
  }
  
  new L<Ref> refs;
  new L<Ref> backRefs;

  void _created() {  
    created = now();
    if (!isTrue(_unlisted.get())) register();
  }
  
  void put(S field, O value) {
    fieldValues.put(field, value);
    change();
  }
  
  O get(S field) {
    ret fieldValues.get(field);
  }
  
  class Ref<A extends Concept> implements Derefable {
    A value;
    
    *() {
      if (!DynamicObject_loading) refs.add(this);
    }
    
    *(A *value) {
      refs.add(this);
      index();
    }
    
    // get owning concept (source)
    Concept concept() { ret Concept.this; }
    
    // get target
    public A get() { ret value; }
    
    bool has() { ret value != null; }
    bool empty() { ret value == null; }
    
    void set(A a) {
      if (a == value) ret;
      unindex();
      value = a;
      index();
    }
    
    void set(Ref<A> ref) { set(ref.get()); }
    
    void clear() { set((A) null); }
    
    void index() { 
      if (value != null)
        value.backRefs.add(this);
      change();
    }
    
    void unindex() {
      if (value != null)
        value.backRefs.remove(this);
    }
    
    public S toString() {
      ret str(get());
    }
  }
  
  class RefL<A extends Concept> extends AbstractList<A> {
    new L<Ref<A>> l;
    
    public A set(int i, A o) {
      A prev = l.get(i).get();
      l.get(i).set(o);
      change();
      ret prev;
    }
    
    public void add(int i, A o) {
      l.add(i, new Ref(o));
      change();
    }
    
    public A get(int i) {
      ret l.get(i).get();
    }
    
    public A remove(int i) {
      A a = l.remove(i).get();
      change();
      ret a;
    }
    
    public int size() {
      ret l.size();
    }
    
    // derefs
    void addAll_(L l) {
      for (O x : l) add_(x);
    }
    
    // derefs
    void add_(O o) {
      add((A) deref(o));
    }
  }
  
  void delete() {
    if (id == 0) ret;
    concepts.remove(id);
    conceptsByClass.get(getClass()).remove(id);
    id = 0;
    //name = "[defunct " + name + "]";
    //defunct = true;
    //energy = 0;
    for (Ref r : refs)
      r.unindex();
    refs.clear();
    change();
  }
  
  // register a previously unlisted concept
  void register() {
    if (id != 0) ret; // already registered
    id = newID();
    concepts.put(id, this);
    _addToClassMap();
    change();
  }
  
  void _addToClassMap() {
    Class c = getClass();
    Map<Long, Concept> map = conceptsByClass.get(c);
    if (map == null) {
      // we're the first object, register this class
      Class superclass = c.getSuperclass();
      if (superclass != Concept)
        subclasses.put(superclass, c);
      conceptsByClass.put(c, map = new TreeMap);
    }
    map.put(id, this);
  }
} // class Concept

// for inter-process communication
// prepared for string ids if we do them later
sclass PassRef {
  S id;
  
  *() {} // make serialisation happy
  *(long id) { this.id = str(id); }
  *(Concept c) { this(c.id); }
  long longID() { ret parseLong(id); }
  
  public S toString() {
    ret id;
  }
}

sclass Event extends Concept {}

// This can be set by client
static bool concepts_quietSave;

static Map<Long, Concept> concepts = synchroTreeMap();
static Map<Class, Map<Long, Concept>> conceptsByClass = synchroHashMap();
static new MultiMap<Class, Class> subclasses;

static long idCounter;
static volatile long changes = 1, changesWritten;
static volatile java.util.Timer autoSaver;
static volatile bool savingConcepts;
static new ThreadLocal<Bool> _unlisted;
static bool concepts_saveOneMore;
static S conceptsLoadedFrom;
static int concepts_internStringsLongerThan = 10;
static int concepts_autoSaveInterval = 1000;

static long newID() {
  do {
    ++idCounter;
  } while (hasConcept(idCounter));
  ret idCounter;
}

ssvoid loadConceptsFrom(S programID) {
  conceptsLoadedFrom = programID;
  clearConcepts();
  DynamicObject_loading = true;
  try {
    structure_internStringsLongerThan = concepts_internStringsLongerThan;
    readLocally(programID, "concepts");
    readLocally(programID, "idCounter");
    assignConceptsToUs();
  } finally {
    DynamicObject_loading = false;
  }
}

svoid assignConceptsToUs() {
  for (Concept c : values(concepts)) {
    c._addToClassMap();
    callOpt(c, "_doneLoading2");
  }
}

ssvoid loadConcepts() {
  loadConceptsFrom(programID());
}

static Concept getConcept(S id) {
  ret empty(id) ? null : getConcept(parseLong(id));
}

static Concept getConcept(long id) {
  ret (Concept) concepts.get((long) id);
}

static Concept getConcept(PassRef ref) {
  ret ref == null ? null : getConcept(ref.longID());
}

static bool hasConcept(long id) {
  ret concepts.containsKey((long) id);
}

static bool hasConcept(Class c, O... params) {
  ret conceptWhere(c, params) != null;
}

static Concept deleteConcept(long id) {
  Concept c = getConcept(id);
  if (c == null)
    print("Concept " + id + " not found");
  else
    c.delete();
  ret c;
}

// call in only one thread
static void saveConceptsIfDirty() {
  saveConceptsIfDirty(programID());
}

static void saveConceptsIfDirty(S programID) {
  savingConcepts = true;
  try {
    S s;
    synchronized(main.class) {
      bool change = changes != changesWritten;
      if (!change && !concepts_saveOneMore) ret;
      changesWritten = changes;
      concepts_saveOneMore = change;
      save(programID, "idCounter");
      s = structure(cloneMap(concepts));
    }
    if (!concepts_quietSave)
      print("Saving " + l(s) + " chars (" + changesWritten + ")");
    saveTextFile(getProgramFile(programID, "concepts.structure"), s);
    copyFile(getProgramFile(programID, "concepts.structure"), getProgramFile(programID, "concepts.structure.backup" + ymd() + "-" + formatInt(hours(), 2)));
  } finally {
    savingConcepts = false;
  }
}

static void saveConcepts() {
  saveConceptsIfDirty();
}

static void saveConceptsTo(S programID) {
  saveConceptsIfDirty(programID);
}

static void clearConcepts() {
  concepts.clear();
  conceptsByClass.clear();
  subclasses.clear();
  change();
}

static synchronized void change() {
  ++changes;
}

// auto-save every second if dirty
static synchronized void autoSaveConcepts() {
  if (autoSaver == null)
    autoSaver = doEvery(concepts_autoSaveInterval, r { saveConcepts(); });
}

static void cleanMeUp() {
  if (autoSaver != null) {
    autoSaver.cancel();
    autoSaver = null;
  }
  while (savingConcepts) sleep(10);
  saveConceptsIfDirty();
}

static Map<Long, S> getIDsAndNames() {
  new Map<Long, S> map;
  Map<Long, Concept> cloned = cloneMap(concepts);
  for (long id : keys(cloned)) 
    map.put(id, cloned.get(id).className);
  ret map;
}

static <A extends Concept> A findBackRef(Concept c, Class<A> type) {
  ret findBackRefOfType(c, type);
}

static <A extends Concept> A findBackRefOfType(Concept c, Class<A> type) {
  for (Concept.Ref r : c.backRefs)
    if (instanceOf(r.concept(), type))
      ret (A) r.concept();
  null;
}

static <A extends Concept> L<A> findBackRefs(Concept c, Class<A> type) {
  new L<A> l;
  for (Concept.Ref r : c.backRefs)
    if (instanceOf(r.concept(), type))
      l.add((A) r.concept());
  ret l;
}

static <A extends Concept> A conceptOfType(Class<A> type) {
  ret firstOfType(allConcepts(), type);
}

static <A extends Concept> L<A> conceptsOfType(Class<A> type) {
  //ret filterByType(allConcepts(), type);
  new L<A> l;
  _collectInstances(type, l);
  ret l;
}

svoid _collectInstances(Class c, L l) {
  l.addAll(values(conceptsByClass.get(c)));
  for (Class sub : subclasses.get(c))
    _collectInstances(sub, l);
}

static <A extends Concept> L<A> listConcepts(Class<A> type) {
  ret conceptsOfType(type);
}

static L<Concept> list(S type, O... params) {
  ret empty(params) ? conceptsOfType(type)
    : conceptsWhere(type, params);
}

static <A extends Concept> L<A> list(Class<A> type, O... params) {
  ret empty(params) ? conceptsOfType(type)
    : conceptsWhere(type, params);
}

static L<Concept> conceptsOfType(S type) {
  ret filterByDynamicType(allConcepts(), "main$" + type);
}

static bool hasConceptOfType(Class<? extends Concept> type) {
  ret hasType(allConcepts(), type);
}

static void persistConcepts() {
  concepts_quietSave = true;
  loadConcepts();
  autoSaveConcepts();
}

static void loadAndAutoSaveConcepts() {
  persistConcepts();
}

// We love synonyms
static void conceptPersistence() {
  persistConcepts();
}
  
// Runs r if there is no concept of that type
static <A extends Concept> A ensureHas(Class<A> c, Runnable r) {
  A a = conceptOfType(c);
  if (a == null) {
    r.run();
    a = conceptOfType(c);
    if (a == null)
      fail("Concept not made by " + r + ": " + shortClassName(c));
  }
  ret a;
}

// Ensures that every concept of type c1 is ref'd by a concept of
// type c2.
// Type of func: voidfunc(concept)
static void ensureHas(Class<? extends Concept> c1, Class<? extends Concept> c2, O func) {
  for (Concept a : conceptsOfType(c1)) {
    Concept b = findBackRef(a, c2);
    if (b == null) {
      callF(func, a);
      b = findBackRef(a, c2);
      if (b == null)
        fail("Concept not made by " + func + ": " + shortClassName(c2));
    }
  }
}

// Type of func: voidfunc(concept)
static void forEvery(Class<? extends Concept> type, O func) {
  for (Concept c : conceptsOfType(type))
    callF(func, c);
}

static int deleteAll(Class<? extends Concept> type) {
  L<Concept> l = (L) conceptsOfType(type);
  for (Concept c : l) c.delete();
  ret l(l);
}

static Collection<Concept> allConcepts() {
  synchronized(concepts) {
    ret new L(values(concepts));
  }
}

static Concept cnew(S name, O... values) {
  Class<? extends Concept> cc = findClass(name);
  Concept c = cc != null ? nuObject(cc) : new Concept(name);
  csetAll(c, values);
  ret c;
}

static <A extends Concept> A cnew(Class<A> cc, O... values) {
  A c = nuObject(cc);
  csetAll(c, values);
  ret c;
}

static void csetAll(Concept c, O... values) {
  cset(c, values);
}

static void cset(Concept c, O... values) ctex {
  values = expandParams(c.getClass(), values);
  warnIfOddCount(values);
  for (int i = 0; i+1 < l(values); i += 2) {
    S field = (S) values[i];
    O value = values[i+1];
    Field f = setOpt_findField(c.getClass(), field);
    //print("cset: " + c.id + " " + field + " " + struct(value) + " " + f);
    if (value instanceof PassRef) value = getConcept((PassRef) value);
    value = deref(value);
    
    if (value instanceof S && l((S) value) >= concepts_internStringsLongerThan) value = ((S) value).intern();
    
    if (f == null)
      c.fieldValues.put(field, value instanceof Concept ? c.new Ref((Concept) value) : value);
    else if (isSubtypeOf(f.getType(), Concept.Ref.class))
      ((Concept.Ref) f.get(c)).set((Concept) value);
    else
      f.set(c, value);
  }
  change();
}

static O cget(Concept c, S field) {
  O o = getOptDyn(c, field);
  if (o instanceof Concept.Ref) ret ((Concept.Ref) o).get();
  ret o;
}

static PassRef toPassRef(Concept c) {
  ret new PassRef(c);
}

// inter-process methods

static PassRef xnew(S name, O... values) {
  ret new PassRef(cnew(name, values));
}

static void xset(long id, S field, O value) {
  xset(new PassRef(id), field, value);
}

static void xset(PassRef c, S field, O value) {
  if (value instanceof PassRef)
    value = getConcept((PassRef) value);
  cset(getConcept(c), field, value);
}

// get class name of concept
static O xclass(PassRef id) {
  Concept c = getConcept(id);
  ret c == null ? null : c.className;
}

static O xget(long id, S field) {
  ret xget(new PassRef(id), field);
}

static O xget(PassRef c, S field) {
  ret export(cget(getConcept(c), field));
}

static void xdelete(long id) {
  xdelete(new PassRef(id));
}

static void xdelete(PassRef c) {
  getConcept(c).delete();
}

static L<PassRef> xlist() {
  ret map("toPassRef", allConcepts());
}

static L<PassRef> xlist(S className) {
  ret map("toPassRef", conceptsOfType(className));
}

// end of IPC methods

// make concept instance that is not connected to DB
static <A extends Concept> A unlisted(Class<A> c) {
  _unlisted.set(true);
  try {
    ret nuObject(c);
  } finally {
    _unlisted.set(null);
  }
}

static <A extends Concept> A unary(Class<A> c) {
  A a = conceptOfType(c);
  if (a == null)
    a = nuObject(c);
  ret a;
}

static Android3 makeDBBot(S name) {
  ret makeBot(name, makeDBResponder());
}

static L<S> exposedDBMethods = ll("xlist", "xnew", "xset", "xdelete", "xget", "xclass");

static O makeDBResponder() {
  ret new O {
    S answer(S s) {
      ret exposeMethods(s, exposedDBMethods);
    }
  };
}

static O export(O o) {
  if (o instanceof Concept)
    ret new PassRef(((Concept) o).id);
  ret o;
}

ssvoid saveConceptsBack() {
  saveConceptsTo(assertNotNull(conceptsLoadedFrom));
}

static bool eq(O a, O b) {
  ret _eq(deref(a), deref(b));
}

download  show line numbers  debug dex  old transpilations   

Travelled to 15 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, ddnzoavkxhuk, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1004681
Snippet name: OLD Concepts (include)
Eternal ID of this version: #1004681/3
Text MD5: 6d12e262917c4a94929783915cae1ab2
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2017-08-16 19:38:25
Source code size: 13914 bytes / 594 lines
Pitched / IR pitched: No / No
Views / Downloads: 1005 / 4402
Version history: 2 change(s)
Referenced in: [show references]