#include <../../nrnconf.h> #include "bbsconf.h" #include #include #include "bbslsrv.h" #define INT 1 #define DOUBLE 2 #define STRING 3 #define VECTOR 4 #if defined(HAVE_STL) #if defined(HAVE_SSTREAM) // the standard ... #include #include #include #else #include #include #include #include #include #endif // debug is 0 1 or 2 #define debug 0 class WorkItem { public: WorkItem(int id, MessageValue*); virtual ~WorkItem(); WorkItem* parent_; int id_; MessageValue* val_; boolean todo_less_than(const WorkItem*)const; }; struct ltstr { boolean operator() (const char* s1, const char* s2) const { return strcmp(s1, s2) < 0; } }; struct ltint { boolean operator() (int i, int j) const { return i < j; } }; struct ltWorkItem { boolean operator() (const WorkItem* w1, const WorkItem* w2) const { return w1->todo_less_than(w2); } }; static char* newstr(const char* s) { char* s1 = new char[strlen(s) + 1]; strcpy(s1, s); return s1; } WorkItem::WorkItem(int id, MessageValue* m) { #if debug == 2 printf("WorkItem %d\n", id); #endif id_ = id; val_ = m; val_->ref(); parent_ = nil; } WorkItem::~WorkItem() { #if debug printf("~WorkItem %d\n", id_); #endif val_->unref(); } boolean WorkItem::todo_less_than(const WorkItem* w) const { WorkItem* w1 = (WorkItem*)this; WorkItem* w2 = (WorkItem*)w; while (w1->parent_ != w2->parent_) { if (w1->id_ < w2->id_) { w2 = w2->parent_; }else{ w1 = w1->parent_; } } #if debug printf("todo_less_than %d < %d return %d\n", this->id_, w->id_, w1->id_ < w2->id_); #endif return w1->id_ < w2->id_; } class MessageList : public multimap {}; class WorkList : public map {}; class ReadyList : public set{}; class ResultList: public multimap{}; #else class MessageList {}; class WorkList {}; class ReadyList{}; class ResultList{}; extern "C" { extern void hoc_execerror(const char*, const char*);} static void nostl() { hoc_execerror("BBSLocalServer not working", "Compiled without STL"); } #endif MessageItem::MessageItem() { next_ = nil; type_ = 0; } MessageItem::~MessageItem() { switch (type_) { case STRING: delete [] u.s; break; case VECTOR: delete [] u.pd; break; } } MessageValue::MessageValue() { first_ = nil; last_ = nil; unpack_ = nil; } MessageValue::~MessageValue() { MessageItem* mi, *next; for (mi = first_; mi; mi = next) { next = mi->next_; delete mi; } } MessageItem* MessageValue::link() { MessageItem* mi = new MessageItem(); if (last_) { last_->next_ = mi; }else{ first_ = mi; unpack_ = mi; } last_ = mi; return mi; } void MessageValue::init_unpack() { unpack_ = first_; } int MessageValue::pkint(int i) { MessageItem* m = link(); m->type_ = INT; m->u.i = i; return 0; } int MessageValue::pkdouble(double x) { MessageItem* m = link(); m->type_ = DOUBLE; m->u.d = x; return 0; } int MessageValue::pkvec(int n, double* x) { int i; MessageItem* m = link(); m->type_ = VECTOR; m->u.pd = new double[n]; for (i=0; i < n; ++i) { m->u.pd[i] = x[i]; } return 0; } int MessageValue::pkstr(const char* str) { MessageItem* m = link(); m->type_ = STRING; m->u.s = new char[strlen(str)+1]; strcpy(m->u.s, str); return 0; } int MessageValue::upkint(int* i) { if (!unpack_ || unpack_->type_ != INT) { return -1; } *i = unpack_->u.i; unpack_ = unpack_->next_; return 0; } int MessageValue::upkdouble(double* d) { if (!unpack_ || unpack_->type_ != DOUBLE) { return -1; } *d = unpack_->u.d; unpack_ = unpack_->next_; return 0; } int MessageValue::upkvec(int n, double* d) { int i; if (!unpack_ || unpack_->type_ != VECTOR) { return -1; } for (i = 0; i < n; ++i) { d[i] = unpack_->u.pd[i]; } unpack_ = unpack_->next_; return 0; } int MessageValue::upkstr(char* s) { if (!unpack_ || unpack_->type_ != STRING) { return -1; } strcpy(s, unpack_->u.s); unpack_ = unpack_->next_; return 0; } BBSLocalServer::BBSLocalServer(){ #if defined(HAVE_STL) messages_ = new MessageList(); work_ = new WorkList(); todo_ = new ReadyList(); results_ = new ResultList(); next_id_ = 1; #endif } BBSLocalServer::~BBSLocalServer(){ #if defined(HAVE_STL) delete todo_; delete results_; printf("~BBSLocalServer not deleting everything\n"); // need to unref MessageValue in messages_ and delete WorkItem in work_ delete messages_; delete work_; #endif } boolean BBSLocalServer::look_take(const char* key, MessageValue** val) { #if defined(HAVE_STL) MessageList::iterator m = messages_->find(key); if (m != messages_->end()) { *val = (MessageValue*)((*m).second); char* s = (char*)((*m).first); messages_->erase(m); delete [] s; #if debug printf("srvr_look_take |%s|\n", key); #endif return true; } #if debug printf("fail srvr_look_take |%s|\n", key); #endif #else nostl(); #endif return false; } boolean BBSLocalServer::look(const char* key, MessageValue** val) { #if defined(HAVE_STL) MessageList::iterator m = messages_->find(key); if (m != messages_->end()) { *val = (MessageValue*)((*m).second); Resource::ref(*val); #if debug printf("srvr_look true |%s|\n", key); #endif return true; }else{ val = nil; } #if debug printf("srvr_look false |%s|\n", key); #endif #else nostl(); #endif return false; } void BBSLocalServer::post(const char* key, MessageValue* val) { #if defined(HAVE_STL) MessageList::iterator m = messages_->insert( pair(newstr(key),val) ); Resource::ref(val); #if debug printf("srvr_post |%s|\n", key); #endif #else nostl(); #endif } void BBSLocalServer::post_todo(int parentid, MessageValue* val) { #if defined(HAVE_STL) WorkItem* w = new WorkItem(next_id_++, val); WorkList::iterator p = work_->find(parentid); if (p != work_->end()) { w->parent_ = (WorkItem*)((*p).second); } work_->insert(pair(w->id_, w)); todo_->insert(w); #if debug printf("srvr_post_todo id=%d pid=%d\n", w->id_, parentid); #endif #else nostl(); #endif } void BBSLocalServer::post_result(int id, MessageValue* val) { #if defined(HAVE_STL) WorkList::iterator i = work_->find(id); WorkItem* w = (WorkItem*)((*i).second); val->ref(); w->val_->unref(); w->val_ = val; results_->insert(pair(w->parent_ ? w->parent_->id_ : 0, w)); #if debug printf("srvr_post_done id=%d pid=%d\n", id, w->parent_ ? w->parent_->id_ : 0); #endif #endif } int BBSLocalServer::look_take_todo(MessageValue** m) { #if defined(HAVE_STL) ReadyList::iterator i = todo_->begin(); if (i != todo_->end()) { WorkItem* w = (*i); todo_->erase(i); *m = w->val_; #if debug printf("srvr look_take_todo %d\n", w->id_); #endif w->val_->ref(); return w->id_; }else{ #if debug printf("srvr look_take_todo failed\n"); #endif return 0; } #else nostl(); return 0; #endif } int BBSLocalServer::look_take_result(int pid, MessageValue** m) { #if defined(HAVE_STL) ResultList::iterator i = results_->find(pid); if (i != results_->end()) { WorkItem* w = (WorkItem*)((*i).second); results_->erase(i); *m = w->val_; w->val_->ref(); int id = w->id_; WorkList::iterator j = work_->find(id); work_->erase(j); #if debug printf("srvr look_take_result %d for parent %d\n", w->id_, pid); #endif delete w; return id; }else{ #if debug printf("srvr look_take_result failed for parent %d\n", pid); #endif return 0; } #else nostl(); return 0; #endif }