void buzzdict_set(buzzdict_t dt, const void* key, const void* data) { /* Hash the key */ uint32_t h = dt->hashf(key) % dt->num_buckets; /* Is the bucket empty? */ if(!dt->buckets[h]) { /* Create new entry list */ dt->buckets[h] = buzzdarray_new(1, sizeof(struct buzzdict_entry_s), NULL); /* Add entry */ buzzdict_entry_new(dt, e, key, data); buzzdarray_push(dt->buckets[h], &e); /* Increase size */ ++(dt->size); } else { /* Bucket not empty - is the entry present? */ uint32_t i; for(i = 0; i < buzzdarray_size(dt->buckets[h]); ++i) { const struct buzzdict_entry_s* e = &buzzdarray_get(dt->buckets[h], i, struct buzzdict_entry_s); if(dt->keycmpf(key, e->key) == 0) { /* Yes, destroy the entry */ dt->dstryf(e->key, e->data, dt); buzzdarray_remove(dt->buckets[h], i); --(dt->size); break; } } /* Add new entry */ buzzdict_entry_new(dt, e, key, data); buzzdarray_push(dt->buckets[h], &e); /* Increase size */ ++(dt->size); } }
buzzlex_t buzzlex_new(const char* fname) { /* The lexer corresponds to a stack of file information */ buzzlex_t x = buzzdarray_new(10, sizeof(struct buzzlex_file_s*), buzzlex_file_destroy); /* Read file */ buzzlex_file_t f = buzzlex_file_new(fname); if(!f) return NULL; buzzdarray_push(x, &f); /* Return the lexer state */ return x; }
buzzvm_state buzzvm_call(buzzvm_t vm, int isswrm) { /* Get argument number and pop it */ buzzvm_stack_assert(vm, 1); buzzvm_type_assert(vm, 1, BUZZTYPE_INT); int32_t argn = buzzvm_stack_at(vm, 1)->i.value; buzzvm_pop(vm); /* Make sure the stack has enough elements */ buzzvm_stack_assert(vm, argn+1); /* Make sure the closure is where expected */ buzzvm_type_assert(vm, argn+1, BUZZTYPE_CLOSURE); buzzobj_t c = buzzvm_stack_at(vm, argn+1); /* Make sure that that data about C closures is correct */ if((!c->c.value.isnative) && ((c->c.value.ref) >= buzzdarray_size(vm->flist))) { buzzvm_seterror(vm, BUZZVM_ERROR_FLIST, NULL); return vm->state; } /* Create a new local symbol list copying the parent's */ vm->lsyms = buzzvm_lsyms_new(isswrm, buzzdarray_clone(c->c.value.actrec)); buzzdarray_push(vm->lsymts, &(vm->lsyms)); /* Add function arguments to the local symbols */ int32_t i; for(i = argn; i > 0; --i) buzzdarray_push(vm->lsyms->syms, &buzzdarray_get(vm->stack, buzzdarray_size(vm->stack) - i, buzzobj_t)); /* Get rid of the function arguments */ for(i = argn+1; i > 0; --i) buzzdarray_pop(vm->stack); /* Pop unused self table */ buzzdarray_pop(vm->stack); /* Push return address */ buzzvm_pushi((vm), vm->pc); /* Make a new stack for the function */ vm->stack = buzzdarray_new(1, sizeof(buzzobj_t), NULL); buzzdarray_push(vm->stacks, &(vm->stack)); /* Jump to/execute the function */ if(c->c.value.isnative) { vm->oldpc = vm->pc; vm->pc = c->c.value.ref; } else buzzdarray_get(vm->flist, c->c.value.ref, buzzvm_funp)(vm); return vm->state; }
buzzswarm_elem_t buzzswarm_elem_new() { buzzswarm_elem_t e = (buzzswarm_elem_t)malloc(sizeof(struct buzzswarm_elem_s)); e->swarms = buzzdarray_new(1, sizeof(uint16_t), NULL); e->age = 0; return e; }
buzzvm_t buzzvm_new(uint16_t robot) { /* Create VM state. calloc() takes care of zeroing everything */ buzzvm_t vm = (buzzvm_t)calloc(1, sizeof(struct buzzvm_s)); /* Create stacks */ vm->stacks = buzzdarray_new(BUZZVM_STACKS_INIT_CAPACITY, sizeof(buzzdarray_t), buzzvm_darray_destroy); vm->stack = buzzdarray_new(BUZZVM_STACK_INIT_CAPACITY, sizeof(buzzobj_t), NULL); buzzdarray_push(vm->stacks, &(vm->stack)); /* Create local variable tables */ vm->lsymts = buzzdarray_new(BUZZVM_LSYMTS_INIT_CAPACITY, sizeof(buzzvm_lsyms_t), buzzvm_lsyms_destroy); vm->lsyms = NULL; /* Create global variable tables */ vm->gsyms = buzzdict_new(BUZZVM_SYMS_INIT_CAPACITY, sizeof(int32_t), sizeof(buzzobj_t), buzzdict_int32keyhash, buzzdict_int32keycmp, NULL); /* Create string list */ vm->strings = buzzstrman_new(); /* Create heap */ vm->heap = buzzheap_new(); /* Create function list */ vm->flist = buzzdarray_new(20, sizeof(buzzvm_funp), NULL); /* Create swarm list */ vm->swarms = buzzdict_new(10, sizeof(uint16_t), sizeof(uint8_t), buzzdict_uint16keyhash, buzzdict_uint16keycmp, NULL); /* Create swarm stack */ vm->swarmstack = buzzdarray_new(10, sizeof(uint16_t), NULL); /* Create swarm member structure */ vm->swarmmembers = buzzswarm_members_new(); vm->swarmbroadcast = SWARM_BROADCAST_PERIOD; /* Create message queues */ vm->inmsgs = buzzinmsg_queue_new(); vm->outmsgs = buzzoutmsg_queue_new(robot); /* Create virtual stigmergy */ vm->vstigs = buzzdict_new(10, sizeof(uint16_t), sizeof(buzzvstig_t), buzzdict_uint16keyhash, buzzdict_uint16keycmp, buzzvm_vstig_destroy); /* Create virtual stigmergy */ vm->listeners = buzzdict_new(10, sizeof(uint16_t), sizeof(buzzobj_t), buzzdict_uint16keyhash, buzzdict_uint16keycmp, NULL); /* Take care of the robot id */ vm->robot = robot; /* Initialize empty random number generator (buzzvm_math takes care of creating it) */ vm->rngstate = NULL; vm->rngidx = 0; /* Return new vm */ return vm; }
void buzzvm_process_inmsgs(buzzvm_t vm) { /* Go through the messages */ while(!buzzinmsg_queue_isempty(vm->inmsgs)) { /* Make sure the VM is in the right state */ if(vm->state != BUZZVM_STATE_READY) return; /* Extract the message data */ uint16_t rid; buzzmsg_payload_t msg; buzzinmsg_queue_extract(vm, &rid, &msg); /* Dispatch the message wrt its type in msg->payload[0] */ switch(buzzmsg_payload_get(msg, 0)) { case BUZZMSG_BROADCAST: { /* Deserialize the topic */ buzzobj_t topic; int64_t pos = buzzobj_deserialize(&topic, msg, 1, vm); /* Make sure there's a listener to call */ const buzzobj_t* l = buzzdict_get(vm->listeners, &topic->s.value.sid, buzzobj_t); if(!l) { /* No listener, ignore message */ break; } /* Deserialize value */ buzzobj_t value; pos = buzzobj_deserialize(&value, msg, pos, vm); /* Make an object for the robot id */ buzzobj_t rido = buzzheap_newobj(vm, BUZZTYPE_INT); rido->i.value = rid; /* Call listener */ buzzvm_push(vm, *l); buzzvm_push(vm, topic); buzzvm_push(vm, value); buzzvm_push(vm, rido); buzzvm_closure_call(vm, 3); break; } case BUZZMSG_VSTIG_PUT: { /* Deserialize the vstig id */ uint16_t id; int64_t pos = buzzmsg_deserialize_u16(&id, msg, 1); if(pos < 0) { fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_VSTIG_PUT message received\n", vm->robot); break; } /* Look for virtual stigmergy */ const buzzvstig_t* vs = buzzdict_get(vm->vstigs, &id, buzzvstig_t); if(!vs) break; /* Virtual stigmergy found */ /* Deserialize key and value from msg */ buzzobj_t k; // key buzzvstig_elem_t v = // value (buzzvstig_elem_t)malloc(sizeof(struct buzzvstig_elem_s)); if(buzzvstig_elem_deserialize(&k, &v, msg, pos, vm) < 0) { fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_VSTIG_PUT message received\n", vm->robot); free(v); break; } /* Deserialization successful */ /* Fetch local vstig element */ const buzzvstig_elem_t* l = buzzvstig_fetch(*vs, &k); if((!l) || /* Element not found */ ((*l)->timestamp < v->timestamp)) { /* Local element is older */ /* Local element must be updated */ /* Store element */ buzzvstig_store(*vs, &k, &v); buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, v); } else if(((*l)->timestamp == v->timestamp) && /* Same timestamp */ ((*l)->robot != v->robot)) { /* Different robot */ /* Conflict! */ /* Call conflict manager */ buzzvstig_elem_t c = buzzvstig_onconflict_call(vm, *vs, k, *l, v); if(!c) { fprintf(stderr, "[WARNING] [ROBOT %u] Error resolving PUT conflict\n", vm->robot); break; } /* Get rid of useless vstig element */ free(v); /* Did this robot lose the conflict? */ if((c->robot != vm->robot) && ((*l)->robot == vm->robot)) { /* Yes */ /* Save current local entry */ buzzvstig_elem_t ol = buzzvstig_elem_clone(vm, *l); /* Store winning value */ buzzvstig_store(*vs, &k, &c); /* Call conflict lost manager */ buzzvstig_onconflictlost_call(vm, *vs, k, ol); } else { /* This robot did not lose the conflict */ /* Just propagate the PUT message */ buzzvstig_store(*vs, &k, &c); } buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, c); } else { /* Remote element is older, ignore it */ /* Get rid of useless vstig element */ free(v); } break; } case BUZZMSG_VSTIG_QUERY: { /* Deserialize the vstig id */ uint16_t id; int64_t pos = buzzmsg_deserialize_u16(&id, msg, 1); if(pos < 0) { fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_VSTIG_QUERY message received (1)\n", vm->robot); break; } /* Deserialize key and value from msg */ buzzobj_t k; // key buzzvstig_elem_t v = // value (buzzvstig_elem_t)malloc(sizeof(struct buzzvstig_elem_s)); if(buzzvstig_elem_deserialize(&k, &v, msg, pos, vm) < 0) { fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_VSTIG_QUERY message received (2)\n", vm->robot); free(v); break; } /* Look for virtual stigmergy */ const buzzvstig_t* vs = buzzdict_get(vm->vstigs, &id, buzzvstig_t); if(!vs) { /* Virtual stigmergy not found, simply propagate the message */ buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_QUERY, id, k, v); free(v); break; } /* Virtual stigmergy found */ /* Fetch local vstig element */ const buzzvstig_elem_t* l = buzzvstig_fetch(*vs, &k); if(!l) { /* Element not found */ if(v->data->o.type == BUZZTYPE_NIL) { /* This robot knows nothing about the query, just propagate it */ buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_QUERY, id, k, v); free(v); } else { /* Store element and propagate PUT message */ buzzvstig_store(*vs, &k, &v); buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, v); } break; } /* Element found */ if((*l)->timestamp < v->timestamp) { /* Local element is older */ /* Store element */ buzzvstig_store(*vs, &k, &v); buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, v); } else if((*l)->timestamp > v->timestamp) { /* Local element is newer */ /* Append a PUT message to the out message queue */ buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, *l); free(v); } else if(((*l)->timestamp == v->timestamp) && /* Same timestamp */ ((*l)->robot != v->robot)) { /* Different robot */ /* Conflict! */ /* Call conflict manager */ buzzvstig_elem_t c = buzzvstig_onconflict_call(vm, *vs, k, *l, v); free(v); /* Make sure conflict manager returned with an element to process */ if(!c) break; /* Did this robot lose the conflict? */ if((c->robot != vm->robot) && ((*l)->robot == vm->robot)) { /* Yes */ /* Save current local entry */ buzzvstig_elem_t ol = buzzvstig_elem_clone(vm, *l); /* Store winning value */ buzzvstig_store(*vs, &k, &c); /* Call conflict lost manager */ buzzvstig_onconflictlost_call(vm, *vs, k, ol); } else { /* This robot did not lose the conflict */ /* Just propagate the PUT message */ buzzvstig_store(*vs, &k, &c); } buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, c); } else { /* Remote element is same as local, ignore it */ /* Get rid of useless vstig element */ free(v); } break; } case BUZZMSG_SWARM_LIST: { /* Deserialize number of swarm ids */ uint16_t nsids; int64_t pos = buzzmsg_deserialize_u16(&nsids, msg, 1); if(pos < 0) { fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_SWARM_LIST message received\n", vm->robot); break; } if(nsids < 1) break; /* Deserialize swarm ids */ buzzdarray_t sids = buzzdarray_new(nsids, sizeof(uint16_t), NULL); uint16_t i; for(i = 0; i < nsids; ++i) { pos = buzzmsg_deserialize_u16(buzzdarray_makeslot(sids, i), msg, pos); if(pos < 0) { fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_SWARM_LIST message received\n", vm->robot); break; } } /* Update the information */ buzzswarm_members_refresh(vm->swarmmembers, rid, sids); break; } case BUZZMSG_SWARM_JOIN: { /* Deserialize swarm id */ uint16_t sid; int64_t pos = buzzmsg_deserialize_u16(&sid, msg, 1); if(pos < 0) { fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_SWARM_JOIN message received\n", vm->robot); break; } /* Update the information */ buzzswarm_members_join(vm->swarmmembers, rid, sid); break; } case BUZZMSG_SWARM_LEAVE: { /* Deserialize swarm id */ uint16_t sid; int64_t pos = buzzmsg_deserialize_u16(&sid, msg, 1); if(pos < 0) { fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_SWARM_LEAVE message received\n", vm->robot); break; } /* Update the information */ buzzswarm_members_leave(vm->swarmmembers, rid, sid); break; } } /* Get rid of the message */ buzzmsg_payload_destroy(&msg); } /* Update swarm membership */ buzzswarm_members_update(vm->swarmmembers); }