// copies source nodes to be underneath this node // branch is the location where detour is being introduced, so that we can see if slack times should be decreased // returns whether or not copy was successful; if not successful, parent maybe should delete bool TreeSlackNode :: copyNodes(vector<TreeSlackNode *> source, TreeSlackNode *branch, double detour) { bool fail = false; for(int i = 0; i < source.size(); i++) { TreeSlackNode *myCopy = constructCopy(this, source[i], branch, detour, shortestPath); if(myCopy) { children.push_back(myCopy); if(!myCopy->copyNodes(source[i]->children, branch, detour)) { //something's infeasible in our child's subtree, so delete child children.pop_back(); fail = true; } } else { //child is infeasible, so fail fail = true; } } //determine whether or not copy was successful //we check the fail flag because we may not have had to copy any nodes at all if(fail && children.empty()) { return false; } else { return true; } }
//attempt to insert new nodes into the tree //doInsert will always be either size 2 containing a pickup and // then a dropoff node, or size 1 and containing a dropoff //the meaning of depth varies depending on if we're inserting pickup or dropoff // pickup: distance from the root node // dropoff: extra distance from the pickup node bool TreeSlackNode :: insertNodes(vector<TreeSlackNode *> doInsert, double depth) { if(doInsert.size() > 0) { //try to create the first node to be inserted //for pickup nodes, the slack time is initialized to the pickup // constraint, so the detour introduced will be the distance from // the new node to the root node, or: // depth + distance(here, new node) //for dropoff nodes, the slack time is how much extra distance to // the pickup node is tolerable, and the depth is set such that the // formula above will still work TreeSlackNode *insertCopy = constructCopy(this, doInsert[0], this, depth + shortestPath->shortestDistance(this->vert, doInsert[0]->vert), shortestPath); if(insertCopy) { bool fail = false; // first, copy other branches to our inserted copy vector<TreeSlackNode *> copySource; for(int i = 0; i < children.size(); i++) { copySource.clear(); copySource.push_back(children[i]); //the child node will experience a detour between here and the // inserted node, and that detour will be equal to the time it // takes to go to the new node and back to the child minus the // time it takes to go directly from here to the child if(!(insertCopy->copyNodes(copySource, insertCopy, insertCopy->time + shortestPath->shortestDistance(insertCopy->vert, children[i]->vert) - children[i]->time))) { fail = true; break; } } if(!fail && doInsert.size() >= 2) { //if we haven't failed, we need to give to give the new node // the rest of the nodes to be inserted insertCopy->updateChildSlackTime(); // give the insertCopy our doInsert, but with first element that was already copied by it removed vector<TreeSlackNode *> doInsertClone; for(int i = 1; i < doInsert.size(); i++) { doInsertClone.push_back(doInsert[i]); } // restart depth counter since this is the corresponding dropoff node // it's slack time is remaining service time, and so will only be affected by distance to the pickup node // we include the negative number because we only want to include EXTRA time from going directly in the detour if(!insertCopy->insertNodes(doInsertClone, -doInsertClone[0]->time)) { fail = true; } } // give other children our insertCopy in full // note that this must be executed after insertCopy updates because insertCopy copies nodes from these children for(int it = 0; it < children.size(); it++) { TreeSlackNode *child = children[it]; if(!(child->insertNodes(doInsert, depth + child->time))) { // child failed, so delete from children delete child; children.erase(children.begin() + it); it--; } } if(!fail) { // lastly, insert insertCopy into our children (do this last so we don't push insertCopy into itself) children.push_back(insertCopy); } else if(children.empty()) { delete insertCopy; return false; } else { delete insertCopy; } } else { // if our inserted copy is not feasible, no other path will be feasible // since we have to insert the same node to our children.. assuming shortest paths are shortest return false; } } return true; }
static void marshall_basetype(Marshall *m) { switch(m->type().element()) { case Smoke::t_bool: switch(m->action()) { case Marshall::FromQScriptValue: { QScriptValue value = *(m->var()); if (!value.isBool()) { m->item().s_bool = false; } else { m->item().s_bool = value.toBool(); } break; } case Marshall::ToQScriptValue: *(m->var()) = QScriptValue(m->engine(), m->item().s_bool); break; default: m->unsupported(); break; } break; case Smoke::t_char: switch(m->action()) { case Marshall::FromQScriptValue: { QScriptValue value = *(m->var()); if (value.isNull()) { m->item().s_char = 0; } else { m->item().s_char = (char) value.toInt32(); } break; } case Marshall::ToQScriptValue: *(m->var()) = QScriptValue(m->engine(), m->item().s_char); break; default: m->unsupported(); break; } break; case Smoke::t_uchar: switch(m->action()) { case Marshall::FromQScriptValue: { QScriptValue value = *(m->var()); if (value.isNull()) { m->item().s_uchar = 0; } else { m->item().s_uchar = (uchar) value.toUInt32(); } break; } case Marshall::ToQScriptValue: *(m->var()) = QScriptValue(m->engine(), m->item().s_uchar); break; default: m->unsupported(); break; } break; case Smoke::t_short: switch(m->action()) { case Marshall::FromQScriptValue: { QScriptValue value = *(m->var()); if (value.isNull()) { m->item().s_short = 0; } else { m->item().s_short = (short) value.toInt32(); } break; } case Marshall::ToQScriptValue: *(m->var()) = QScriptValue(m->engine(), m->item().s_short); break; default: m->unsupported(); break; } break; case Smoke::t_ushort: switch(m->action()) { case Marshall::FromQScriptValue: { QScriptValue value = *(m->var()); if (value.isNull()) { m->item().s_ushort = 0; } else { m->item().s_ushort = value.toUInt16(); } break; } case Marshall::ToQScriptValue: *(m->var()) = QScriptValue(m->engine(), m->item().s_ushort); break; default: m->unsupported(); break; } break; case Smoke::t_int: switch(m->action()) { case Marshall::FromQScriptValue: { QScriptValue value = *(m->var()); if (value.isNull()) { m->item().s_int = 0; } else { m->item().s_int = value.toInt32(); } break; } case Marshall::ToQScriptValue: *(m->var()) = QScriptValue(m->engine(), m->item().s_int); break; default: m->unsupported(); break; } break; case Smoke::t_uint: switch(m->action()) { case Marshall::FromQScriptValue: { QScriptValue value = *(m->var()); if (value.isNull()) { m->item().s_uint = 0; } else { m->item().s_uint = value.toUInt32(); } break; } case Marshall::ToQScriptValue: *(m->var()) = QScriptValue(m->engine(), m->item().s_uint); break; default: m->unsupported(); break; } break; case Smoke::t_long: switch(m->action()) { case Marshall::FromQScriptValue: { QScriptValue value = *(m->var()); if (value.isNull()) { m->item().s_long = 0; } else { m->item().s_long = (long) value.toInt32(); } break; } case Marshall::ToQScriptValue: *(m->var()) = QScriptValue(m->engine(), (int) m->item().s_long); break; default: m->unsupported(); break; } break; case Smoke::t_ulong: switch(m->action()) { case Marshall::FromQScriptValue: { QScriptValue value = *(m->var()); if (value.isNull()) { m->item().s_ulong = 0; } else { m->item().s_ulong = (ulong) value.toUInt32(); } break; } case Marshall::ToQScriptValue: *(m->var()) = QScriptValue(m->engine(), (uint) m->item().s_ulong); break; default: m->unsupported(); break; } break; case Smoke::t_float: switch(m->action()) { case Marshall::FromQScriptValue: { QScriptValue value = *(m->var()); if (value.isNull()) { m->item().s_float = 0.0; } else { m->item().s_float = (float) value.toNumber(); } break; } case Marshall::ToQScriptValue: *(m->var()) = QScriptValue(m->engine(), m->item().s_float); break; default: m->unsupported(); break; } break; case Smoke::t_double: switch(m->action()) { case Marshall::FromQScriptValue: { QScriptValue value = *(m->var()); if (value.isNull()) { m->item().s_double = 0.0; } else { m->item().s_double = value.toNumber(); } break; } case Marshall::ToQScriptValue: *(m->var()) = QScriptValue(m->engine(), m->item().s_double); break; default: m->unsupported(); break; } break; case Smoke::t_enum: switch(m->action()) { case Marshall::FromQScriptValue: { QScriptValue value = *(m->var()); if (value.isNull()) { m->item().s_enum = 0; } else if (value.instanceOf(JSmoke::Global::QtEnum)) { m->item().s_enum = value.property("value").toUInt32(); } else { m->item().s_enum = value.toUInt32(); } break; } case Marshall::ToQScriptValue: { QScriptValueList args; args << (uint) m->item().s_enum << m->type().name(); *(m->var()) = JSmoke::Global::QtEnum.call(QScriptValue(), args); break; } default: m->unsupported(); break; } break; case Smoke::t_class: switch(m->action()) { case Marshall::FromQScriptValue: { QScriptValue value = *(m->var()); if (value.isNull()) { m->item().s_class = 0; return; } if (value.isDate()) { Smoke::ModuleIndex classId = Smoke::findClass(m->smoke()->classes[m->type().classId()].className); if (classId == JSmoke::Global::QDateClassId) { m->item().s_class = new QDate(value.toDateTime().date()); } else if (classId == JSmoke::Global::QDateTimeClassId) { m->item().s_class = new QDateTime(value.toDateTime()); } else if (classId == JSmoke::Global::QTimeClassId) { m->item().s_class = new QTime(value.toDateTime().time()); } else { m->item().s_class = 0; } return; } else if (value.isRegExp()) { m->item().s_class = new QRegExp(value.toRegExp()); return; } if (!Object::Instance::isSmokeObject(value)) { m->item().s_class = 0; return; } Object::Instance * instance = Object::Instance::get(value); void * ptr = instance->value; if (!m->cleanup() && m->type().isStack()) { ptr = constructCopy(instance); } ptr = instance->classId.smoke->cast( ptr, instance->classId, Smoke::ModuleIndex(m->smoke(), m->type().classId()) ); m->item().s_class = ptr; break; } case Marshall::ToQScriptValue: { if (m->item().s_voidp == 0) { *(m->var()) = m->engine()->nullValue(); return; } void * ptr = m->item().s_voidp; QScriptValue * value = JSmoke::Global::getScriptValue(ptr); if (value != 0) { *(m->var()) = *value; return ; } QByteArray className(m->smoke()->classes[m->type().classId()].className); QScriptValue obj = Global::wrapInstance( m->engine(), Smoke::findClass(className), ptr, QScriptEngine::QtOwnership ); if (m->type().isConst() && m->type().isRef()) { Object::Instance * instance = Object::Instance::get(obj); ptr = constructCopy(instance); if (ptr != 0) { instance->value = ptr; instance->ownership = QScriptEngine::ScriptOwnership; Global::mapPointer(new QScriptValue(obj), instance, instance->classId); } } *(m->var()) = obj; break; } default: m->unsupported(); break; } break; default: m->unsupported(); break; } }