1 /*
2 * Copyright (C) 2007-2010 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * Note: See DummyComponent.cc for unit tests of the component framework.
29 */
30
31 #include "assert.h"
32 #include <fstream>
33
34 #include "components/RootComponent.h"
35 #include "Component.h"
36 #include "ComponentFactory.h"
37 #include "EscapedString.h"
38 #include "GXemul.h"
39 #include "StringHelper.h"
40
41
Component(const string & className,const string & visibleClassName)42 Component::Component(const string& className, const string& visibleClassName)
43 : m_parentComponent(NULL)
44 , m_className(className)
45 , m_visibleClassName(visibleClassName)
46 , m_step(0)
47 {
48 AddVariable("name", &m_name);
49 AddVariable("template", &m_template);
50 AddVariable("step", &m_step);
51 }
52
53
GetClassName() const54 string Component::GetClassName() const
55 {
56 return m_className;
57 }
58
59
GetVisibleClassName() const60 string Component::GetVisibleClassName() const
61 {
62 return m_visibleClassName;
63 }
64
65
GetAttribute(const string & attributeName)66 string Component::GetAttribute(const string& attributeName)
67 {
68 // The Component base class always returns an empty string
69 // for all attribute names. It is up to individual Component
70 // implementations to return overrides.
71
72 return "";
73 }
74
75
Clone() const76 refcount_ptr<Component> Component::Clone() const
77 {
78 refcount_ptr<Component> clone;
79
80 if (GetClassName() == "root")
81 clone = new RootComponent;
82 else
83 clone = ComponentFactory::CreateComponent(GetClassName());
84
85 if (clone.IsNULL()) {
86 std::cerr << "INTERNAL ERROR in Component::Clone(): "
87 "could not clone a '" << GetClassName() << "'\n";
88 throw std::exception();
89 }
90
91 // Copy the value of each state variable to the clone:
92 StateVariableMap::const_iterator varIt = m_stateVariables.begin();
93 for ( ; varIt != m_stateVariables.end(); ++varIt) {
94 const string& varName = varIt->first;
95 const StateVariable& variable = varIt->second;
96
97 StateVariableMap::iterator cloneVarIt =
98 clone->m_stateVariables.find(varName);
99
100 if (cloneVarIt == clone->m_stateVariables.end()) {
101 std::cerr << "INTERNAL ERROR in Component::Clone(): "
102 "could not copy variable " << varName << "'s "
103 << " value to the clone: clone is missing"
104 " this variable?\n";
105 assert(false);
106 } else if (!(cloneVarIt->second).CopyValueFrom(variable)) {
107 std::cerr << "INTERNAL ERROR in Component::Clone(): "
108 "could not copy variable " << varName << "'s "
109 << " value to the clone.\n";
110 assert(false);
111 }
112 }
113
114 for (Components::const_iterator it = m_childComponents.begin();
115 it != m_childComponents.end(); ++it) {
116 refcount_ptr<Component> child = (*it)->Clone();
117 if (child.IsNULL()) {
118 std::cerr << "INTERNAL ERROR in Component::Clone(): "
119 "could not clone child of class '" <<
120 (*it)->GetClassName() << "'\n";
121 assert(false);
122 } else {
123 clone->AddChild(child);
124 }
125 }
126
127 return clone;
128 }
129
130
LightCloneInternal() const131 refcount_ptr<Component> Component::LightCloneInternal() const
132 {
133 refcount_ptr<Component> clone;
134
135 if (GetClassName() == "root")
136 clone = new RootComponent;
137 else
138 clone = ComponentFactory::CreateComponent(GetClassName());
139
140 if (clone.IsNULL()) {
141 std::cerr << "INTERNAL ERROR in Component::LightCloneInternal(): "
142 "could not clone a '" << GetClassName() << "'\n";
143 throw std::exception();
144 }
145
146 // Copy the value of each state variable to the clone:
147 StateVariableMap::const_iterator varIt = m_stateVariables.begin();
148 for ( ; varIt != m_stateVariables.end(); ++varIt) {
149 const string& varName = varIt->first;
150 const StateVariable& variable = varIt->second;
151
152 StateVariableMap::iterator cloneVarIt =
153 clone->m_stateVariables.find(varName);
154
155 if (cloneVarIt == clone->m_stateVariables.end()) {
156 std::cerr << "INTERNAL ERROR in Component::LightCloneInternal(): "
157 "could not copy variable " << varName << "'s "
158 << " value to the clone: clone is missing"
159 " this variable?\n";
160 throw std::exception();
161 }
162
163 // Skip custom variables:
164 if (variable.GetType() == StateVariable::Custom)
165 continue;
166
167 if (!(cloneVarIt->second).CopyValueFrom(variable)) {
168 std::cerr << "INTERNAL ERROR in Component::LightCloneInternal(): "
169 "could not copy variable " << varName << "'s "
170 << " value to the clone.\n";
171 throw std::exception();
172 }
173 }
174
175 for (Components::const_iterator it = m_childComponents.begin();
176 it != m_childComponents.end(); ++it) {
177 refcount_ptr<Component> child = (*it)->LightCloneInternal();
178 if (child.IsNULL()) {
179 std::cerr << "INTERNAL ERROR in Component::LightCloneInternal(): "
180 "could not clone child of class '" <<
181 (*it)->GetClassName() << "'\n";
182 throw std::exception();
183 } else {
184 clone->AddChild(child);
185 }
186 }
187
188 return clone;
189 }
190
191
LightClone() const192 const refcount_ptr<Component> Component::LightClone() const
193 {
194 return LightCloneInternal();
195 }
196
197
DetectChanges(const refcount_ptr<Component> & oldClone,ostream & changeMessages) const198 void Component::DetectChanges(const refcount_ptr<Component>& oldClone,
199 ostream& changeMessages) const
200 {
201 // Recursively look for changes in state. Compare the
202 // oldClone component with this component first.
203
204 if (oldClone->GetClassName() != GetClassName()) {
205 changeMessages << oldClone->GenerateShortestPossiblePath() <<
206 " changed class from " << oldClone->GetClassName() <<
207 " to " << GetClassName() << "?\n";
208 return;
209 }
210
211 // Compare all state variables:
212 StateVariableMap::const_iterator varIt = m_stateVariables.begin();
213 for ( ; varIt != m_stateVariables.end(); ++varIt) {
214 const string& varName = varIt->first;
215
216 // Don't output "step" changes, because they happen all
217 // the time for all executable components.
218 if (varName == "step")
219 continue;
220
221 const StateVariable& variable = varIt->second;
222 const StateVariable* oldVariable = oldClone->GetVariable(varName);
223
224 // NOTE: Custom types have a nonsense tostring, which
225 // usually just says "(custom)" or something, so they
226 // are quickly compared.
227
228 // TODO: In the future, maybe RAM components and such (i.e.
229 // custom data types) can be lazily reference counted or
230 // similar, to detect changes in RAM as well.
231
232 string var = variable.ToString();
233 string varOld = oldVariable->ToString();
234
235 if (var != varOld)
236 changeMessages << "=> " << GenerateShortestPossiblePath() << "."
237 << varName << ": " << varOld << " -> " << var << "\n";
238 }
239
240 // Compare all children.
241 const Components& oldChildren = oldClone->GetChildren();
242 for (size_t i = 0; i < m_childComponents.size(); ++ i) {
243 string myName = m_childComponents[i]->GetVariable("name")->ToString();
244
245 // Find the corresponding child component in the oldClone:
246 size_t j;
247 bool found = false;
248 for (j=0; j<oldChildren.size(); ++j)
249 if (oldChildren[j]->GetVariable("name")->ToString() == myName) {
250 m_childComponents[i]->DetectChanges(oldChildren[j], changeMessages);
251 found = true;
252 break;
253 }
254
255 if (!found)
256 changeMessages << m_childComponents[i]->
257 GenerateShortestPossiblePath() << " (appeared)\n";
258 }
259
260 // ... and see if any disappeared (i.e. were in the old clone,
261 // but not in the current tree):
262 for (size_t j=0; j<oldChildren.size(); ++j) {
263 string oldName = oldChildren[j]->GetVariable("name")->ToString();
264
265 bool found = false;
266 for (size_t k=0; k<m_childComponents.size(); ++k) {
267 string newName = m_childComponents[k]->GetVariable("name")->ToString();
268 if (newName == oldName) {
269 found = true;
270 break;
271 }
272 }
273
274 if (!found)
275 changeMessages << oldChildren[j]->
276 GenerateShortestPossiblePath() << " (disappeared)\n";
277 }
278 }
279
280
Reset()281 void Component::Reset()
282 {
283 ResetState();
284
285 // Recurse:
286 for (size_t i = 0; i < m_childComponents.size(); ++ i)
287 m_childComponents[i]->Reset();
288 }
289
290
ResetState()291 void Component::ResetState()
292 {
293 // Base implementation.
294 m_step = 0;
295 }
296
297
PreRunCheck(GXemul * gxemul)298 bool Component::PreRunCheck(GXemul* gxemul)
299 {
300 bool everythingOk = PreRunCheckForComponent(gxemul);
301
302 // Recurse:
303 for (size_t i = 0; i < m_childComponents.size(); ++ i)
304 everythingOk &= m_childComponents[i]->PreRunCheck(gxemul);
305
306 return everythingOk;
307 }
308
309
PreRunCheckForComponent(GXemul * gxemul)310 bool Component::PreRunCheckForComponent(GXemul* gxemul)
311 {
312 // Base implementation: Do nothing. Everything is Ok.
313 return true;
314 }
315
316
FlushCachedState()317 void Component::FlushCachedState()
318 {
319 FlushCachedStateForComponent();
320
321 // Recurse:
322 for (size_t i = 0; i < m_childComponents.size(); ++ i)
323 m_childComponents[i]->FlushCachedState();
324 }
325
326
FlushCachedStateForComponent()327 void Component::FlushCachedStateForComponent()
328 {
329 // Base implementation: Do nothing.
330 }
331
332
Execute(GXemul * gxemul,int nrOfCycles)333 int Component::Execute(GXemul* gxemul, int nrOfCycles)
334 {
335 // Base implementation: Do nothing, but pretend we executed
336 // the instructions. Actual components that inherit from this
337 // class should of course _do_ something here.
338
339 return nrOfCycles;
340 }
341
342
GetCurrentFrequency() const343 double Component::GetCurrentFrequency() const
344 {
345 // The base component does not run at any frequency. Only components
346 // that actually run something "per cycle" should return values
347 // greater than 0.0.
348
349 return 0.0;
350 }
351
352
AsRootComponent()353 RootComponent* Component::AsRootComponent()
354 {
355 // Default implementation (the base Component class) is not a RootComponent.
356 return NULL;
357 }
358
359
AsCPUComponent()360 CPUComponent* Component::AsCPUComponent()
361 {
362 // Default implementation (the base Component class) is not a CPU.
363 return NULL;
364 }
365
366
AsAddressDataBus()367 AddressDataBus* Component::AsAddressDataBus()
368 {
369 // Default implementation (the base Component class) is not an
370 // address data bus.
371 return NULL;
372 }
373
374
SetParent(Component * parentComponent)375 void Component::SetParent(Component* parentComponent)
376 {
377 m_parentComponent = parentComponent;
378 }
379
380
GetParent()381 Component* Component::GetParent()
382 {
383 return m_parentComponent;
384 }
385
386
GetParent() const387 const Component* Component::GetParent() const
388 {
389 return m_parentComponent;
390 }
391
392
GetMethodNames(vector<string> & names) const393 void Component::GetMethodNames(vector<string>& names) const
394 {
395 // The default component has no implemented methods.
396 }
397
398
MethodMayBeReexecutedWithoutArgs(const string & methodName) const399 bool Component::MethodMayBeReexecutedWithoutArgs(const string& methodName) const
400 {
401 // By default, methods are _not_ re-executable without args.
402 return false;
403 }
404
405
ExecuteMethod(GXemul * gxemul,const string & methodName,const vector<string> & arguments)406 void Component::ExecuteMethod(GXemul* gxemul,
407 const string& methodName,
408 const vector<string>& arguments)
409 {
410 std::cerr << "Internal error: someone tried to execute "
411 "method '" << methodName << "' on the Component base"
412 " class. Perhaps you are missing an override?\n";
413 throw std::exception();
414 }
415
416
GenerateDetails() const417 string Component::GenerateDetails() const
418 {
419 stringstream ss;
420
421 // If this component has a "model", then show that.
422 const StateVariable* model = GetVariable("model");
423 if (model != NULL && !model->ToString().empty()) {
424 if (!ss.str().empty())
425 ss << ", ";
426 ss << model->ToString();
427 }
428
429 // If this component has a frequency (i.e. it is runnable), then
430 // show the frequency:
431 double freq = GetCurrentFrequency();
432 if (freq != 0.0) {
433 if (!ss.str().empty())
434 ss << ", ";
435
436 if (freq >= 1e9)
437 ss << freq/1e9 << " GHz";
438 else if (freq >= 1e6)
439 ss << freq/1e6 << " MHz";
440 else if (freq >= 1e3)
441 ss << freq/1e3 << " kHz";
442 else
443 ss << freq << " Hz";
444 }
445
446 const StateVariable* paused = GetVariable("paused");
447 // TODO: ToBool :)
448 if (paused != NULL && paused->ToInteger() > 0) {
449 if (!ss.str().empty())
450 ss << ", ";
451
452 ss << "paused";
453 }
454
455 return ss.str();
456 }
457
458
GenerateTreeDump(const string & branchTemplate,bool htmlLinksForClassNames,string prefixForComponentUrls) const459 string Component::GenerateTreeDump(const string& branchTemplate,
460 bool htmlLinksForClassNames, string prefixForComponentUrls) const
461 {
462 // This generates an ASCII string which looks like:
463 //
464 // root
465 // |-- child1
466 // | |-- child1's child1
467 // | \-- child1's child2
468 // \-- child2
469 // \-- child2's child
470
471 string branch;
472 for (size_t pos=0; pos<branchTemplate.length(); pos++) {
473 stringchar ch = branchTemplate[pos];
474 if (ch == '\\') {
475 if (pos < branchTemplate.length() - 4)
476 branch += ' ';
477 else
478 branch += ch;
479 } else {
480 if (pos == branchTemplate.length() - 3 ||
481 pos == branchTemplate.length() - 2)
482 ch = '-';
483 branch += ch;
484 }
485 }
486
487 // Fallback to showing the component's class name in parentheses...
488 const string className = GetClassName();
489 string name = "(unnamed " + className + ")";
490
491 // ... but prefer the state variable "name" if it is non-empty:
492 const StateVariable* value = GetVariable("name");
493 if (!value->ToString().empty())
494 name = value->ToString();
495
496 string str = branch;
497
498 if (htmlLinksForClassNames) {
499 // See if this class name has its own HTML page.
500 std::ifstream documentationComponentFile((
501 "doc/components/component_"
502 + className + ".html").c_str());
503
504 if (documentationComponentFile.is_open())
505 str += "<a href=\"" + prefixForComponentUrls +
506 "components/component_" +
507 className + ".html\">" + name + "</a>";
508 else
509 str += name;
510 } else {
511 str += name;
512 }
513
514 // If this component was created by a template, then show the template
515 // type in [ ].
516 const StateVariable* templateName;
517 if ((templateName = GetVariable("template")) != NULL &&
518 !templateName->ToString().empty())
519 {
520 string tName = templateName->ToString();
521
522 str += " [";
523
524 if (htmlLinksForClassNames) {
525 // See if this class/template name has its own HTML page.
526 // (Usually machines. TODO: also other components.)
527 std::ifstream documentationMachineFile((
528 "doc/machines/machine_"
529 + tName + ".html").c_str());
530
531 if (documentationMachineFile.is_open())
532 str += "<a href=\"" + prefixForComponentUrls +
533 "machines/machine_" +
534 tName + ".html\">" + tName + "</a>";
535 else
536 str += tName;
537 } else {
538 str += tName;
539 }
540
541 str += "]";
542 }
543
544 // Get any additional details (CPU model, memory mapped address, etc.):
545 string details = GenerateDetails();
546 if (!details.empty())
547 str += " (" + details + ")";
548
549 // Show the branch of the tree...
550 string result = " " + str + "\n";
551
552 // ... and recurse to show children, if there are any:
553 const Components& children = GetChildren();
554 for (size_t i=0, n=children.size(); i<n; ++i) {
555 string subBranch = branchTemplate;
556 if (i == n-1)
557 subBranch += "\\ ";
558 else
559 subBranch += "| ";
560
561 result += children[i]->GenerateTreeDump(subBranch,
562 htmlLinksForClassNames, prefixForComponentUrls);
563 }
564
565 return result;
566 }
567
568
GetRunningGXemulInstance()569 GXemul* Component::GetRunningGXemulInstance()
570 {
571 Component* root = this;
572 while (root->GetParent() != NULL)
573 root = root->GetParent();
574
575 RootComponent* rootComponent = root->AsRootComponent();
576 if (rootComponent == NULL)
577 return NULL;
578
579 return rootComponent->GetOwner();
580 }
581
582
GetUI()583 UI* Component::GetUI()
584 {
585 GXemul* gxemul = GetRunningGXemulInstance();
586 if (gxemul == NULL)
587 return NULL;
588
589 // TODO: Return NULL if the UI has debug messages turned off.
590
591 return gxemul->GetUI();
592 }
593
594
AddChild(refcount_ptr<Component> childComponent,size_t insertPosition)595 void Component::AddChild(refcount_ptr<Component> childComponent,
596 size_t insertPosition)
597 {
598 if (insertPosition == (size_t) -1) {
599 insertPosition = m_childComponents.size();
600 m_childComponents.push_back(childComponent);
601 } else {
602 m_childComponents.insert(
603 m_childComponents.begin() + insertPosition,
604 childComponent);
605 }
606
607 // A component cannot have two parents.
608 assert(childComponent->GetParent() == NULL);
609
610 childComponent->SetParent(this);
611
612 // Make sure that the child's "name" state variable is unique among
613 // all children of this component. (Yes, this is O(n^2) and it may
614 // need to be rewritten to cope with _lots_ of components.)
615 size_t postfix = 0;
616 bool collision = false;
617 do {
618 const StateVariable* name =
619 childComponent->GetVariable("name");
620 if (name->ToString().empty() || collision) {
621 // Set the default name:
622 // visibleclassname + postfix number
623 stringstream ss;
624 ss << childComponent->GetVisibleClassName() << postfix;
625 EscapedString escaped(ss.str());
626 childComponent->SetVariableValue("name",
627 escaped.Generate());
628
629 name = childComponent->GetVariable("name");
630 }
631
632 collision = false;
633 for (size_t i=0; i<m_childComponents.size(); ++i) {
634 if (i == insertPosition)
635 continue;
636
637 // Collision?
638 const StateVariable* otherName =
639 m_childComponents[i]->GetVariable("name");
640 if (otherName != NULL) {
641 if (name->ToString() == otherName->ToString()) {
642 collision = true;
643 ++ postfix;
644 break;
645 }
646 } else {
647 // Hm. All components should have a "name".
648 assert(false);
649 }
650 }
651 } while (collision);
652 }
653
654
RemoveChild(Component * childToRemove)655 size_t Component::RemoveChild(Component* childToRemove)
656 {
657 size_t index = 0;
658 for (Components::iterator it = m_childComponents.begin();
659 it != m_childComponents.end(); ++it, ++index) {
660 if (childToRemove == (*it)) {
661 childToRemove->SetParent(NULL);
662 m_childComponents.erase(it);
663 return index;
664 }
665 }
666
667 // Child not found? Should not happen.
668 assert(false);
669
670 return (size_t) -1;
671 }
672
673
GetChildren()674 Components& Component::GetChildren()
675 {
676 return m_childComponents;
677 }
678
679
GetChildren() const680 const Components& Component::GetChildren() const
681 {
682 return m_childComponents;
683 }
684
685
GeneratePath() const686 string Component::GeneratePath() const
687 {
688 string path = GetVariable("name")->ToString();
689 if (path.empty())
690 path = "(" + GetClassName() + ")";
691
692 if (m_parentComponent != NULL)
693 path = m_parentComponent->GeneratePath() + "." + path;
694
695 return path;
696 }
697
698
SplitPathStringIntoVector(const string & path)699 static vector<string> SplitPathStringIntoVector(const string &path)
700 {
701 // Split the path into a vector. This is slow and hackish, but works.
702 vector<string> pathStrings;
703 string word;
704
705 for (size_t i=0, n=path.length(); i<n; i++) {
706 stringchar ch = path[i];
707 if (ch == '.') {
708 pathStrings.push_back(word);
709 word = "";
710 } else {
711 word += ch;
712 }
713 }
714
715 pathStrings.push_back(word);
716
717 return pathStrings;
718 }
719
720
GenerateShortestPossiblePath() const721 string Component::GenerateShortestPossiblePath() const
722 {
723 string myPath = GeneratePath();
724 vector<string> allComponentPaths;
725
726 const Component* root = this;
727 while (root->GetParent() != NULL)
728 root = root->GetParent();
729
730 root->AddAllComponentPaths(allComponentPaths);
731
732 // Include as few as possible sub-parts of myPath (starting from the
733 // end), to uniqely identify the component.
734 vector<string> myPathParts = SplitPathStringIntoVector(myPath);
735
736 for (size_t n=1; n<=myPathParts.size(); ++n) {
737 string attempt = "";
738 for (size_t i=myPathParts.size()-n; i<myPathParts.size(); i++) {
739 if (attempt.length() > 0)
740 attempt += ".";
741 attempt += myPathParts[i];
742 }
743
744 // std::cerr << "attempt = " << attempt << "\n";
745 // attempt = ram0
746 // attempt = mainbus0.ram0
747 // attempt = machine0.mainbus0.ram0
748 // etc.
749
750 // See if this substring is unique in allComponentPaths.
751 int nHits = 0;
752 string dotAttempt = "." + attempt;
753 size_t dotAttemptLength = dotAttempt.length();
754 for (size_t j=0; j<allComponentPaths.size(); ++j) {
755 const string& s = allComponentPaths[j];
756 if (s.length() < attempt.length())
757 continue;
758
759 if (s == attempt)
760 nHits ++;
761 else if (s.length() > dotAttemptLength &&
762 s.substr(s.length() - dotAttemptLength, dotAttemptLength) == dotAttempt)
763 nHits ++;
764 }
765
766 // Unique? Then we found a good short path.
767 if (nHits == 1)
768 return attempt;
769
770 // Otherwise continue.
771 }
772
773 // Worst case: return full path.
774 return myPath;
775 }
776
777
LookupPath(string path) const778 const refcount_ptr<Component> Component::LookupPath(string path) const
779 {
780 // Trim whitespace
781 while (path.length() > 0 && path[path.length() - 1] == ' ')
782 path = path.substr(0, path.length() - 1);
783
784 refcount_ptr<Component> component = LookupPath(SplitPathStringIntoVector(path), 0);
785
786 if (component.IsNULL()) {
787 // Maybe it was a path starting from somewhere other than the
788 // root. That is, if we find "." + path in the list of all
789 // components' full names exactly 1 time, then we return that.
790 vector<string> allComponentPaths;
791 AddAllComponentPaths(allComponentPaths);
792
793 const Component* root = this;
794 while (root->GetParent() != NULL)
795 root = root->GetParent();
796
797 int nMatches = 0;
798 string strToFind = "." + path;
799 for (size_t i=0, n=allComponentPaths.size(); i<n; i++) {
800 if (allComponentPaths[i].length() > strToFind.length()) {
801 string subs = allComponentPaths[i].substr(
802 allComponentPaths[i].length() - strToFind.length());
803 if (strToFind == subs) {
804 nMatches ++;
805 component = root->LookupPath(allComponentPaths[i]);
806 }
807 }
808 }
809
810 if (nMatches != 1)
811 return NULL;
812 }
813
814 return component;
815 }
816
817
LookupPath(const vector<string> & path,size_t index) const818 const refcount_ptr<Component> Component::LookupPath(const vector<string>& path,
819 size_t index) const
820 {
821 refcount_ptr<Component> component;
822
823 if (index > path.size()) {
824 // Huh? Lookup of empty path? Should not usually happen.
825 assert(false);
826 return component;
827 }
828
829 StateVariableMap::const_iterator it = m_stateVariables.find("name");
830 if (it == m_stateVariables.end()) {
831 // Failure (return NULL) if we don't have a name.
832 return component;
833 }
834
835 string nameOfThisComponent = (it->second).ToString();
836 bool match = (path[index] == nameOfThisComponent);
837
838 // No match? Or was it the last part of the path? Then return.
839 if (!match || index == path.size() - 1) {
840 // (Successfully, if there was a match.)
841 if (match)
842 return const_cast<Component*>(this);
843 return component;
844 }
845
846 // If there are still parts left to check, look among all the children:
847 const string& pathPartToLookup = path[index+1];
848 for (size_t i=0, n=m_childComponents.size(); i<n; i++) {
849 const StateVariable* childName =
850 m_childComponents[i]->GetVariable("name");
851 if (childName != NULL) {
852 if (childName->ToString() == pathPartToLookup) {
853 component = m_childComponents[i]->
854 LookupPath(path, index+1);
855 break;
856 }
857 }
858 }
859
860 return component;
861 }
862
863
AddAllComponentPaths(vector<string> & allComponentPaths) const864 void Component::AddAllComponentPaths(vector<string>& allComponentPaths) const
865 {
866 // Add the component itself first:
867 allComponentPaths.push_back(GeneratePath());
868
869 // Then all children:
870 for (size_t i=0, n=m_childComponents.size(); i<n; i++)
871 m_childComponents[i]->AddAllComponentPaths(allComponentPaths);
872 }
873
874
PartialMatch(const string & partialPath,const string & path)875 static bool PartialMatch(const string& partialPath, const string& path)
876 {
877 if (partialPath.empty())
878 return true;
879
880 const size_t partialPathLength = partialPath.length();
881 const size_t pathLength = path.length();
882 size_t pathPos = 0;
883
884 do {
885 // Partial path too long? Then abort immediately.
886 if (partialPathLength + pathPos > pathLength)
887 break;
888
889 // A substring match? Then we might have found it.
890 if (path.substr(pathPos, partialPathLength) == partialPath) {
891 // If the path has no tail (".subcomponent"), then
892 // we found it:
893 if (path.find('.', pathPos + partialPathLength) ==
894 string::npos)
895 return true;
896 }
897
898 // Find next place in path to test:
899 do {
900 pathPos ++;
901 } while (pathPos < pathLength && path[pathPos] != '.');
902
903 if (pathPos < pathLength)
904 pathPos ++;
905
906 } while (pathPos < pathLength);
907
908 return false;
909 }
910
911
FindPathByPartialMatch(const string & partialPath,bool shortestPossible) const912 vector<string> Component::FindPathByPartialMatch(
913 const string& partialPath, bool shortestPossible) const
914 {
915 vector<string> allComponentPaths;
916 vector<string> matches;
917
918 AddAllComponentPaths(allComponentPaths);
919
920 for (size_t i=0, n=allComponentPaths.size(); i<n; i++)
921 if (PartialMatch(partialPath, allComponentPaths[i])) {
922 string match = allComponentPaths[i];
923
924 if (shortestPossible) {
925 const Component* root = this;
926 while (root->GetParent() != NULL)
927 root = root->GetParent();
928
929 refcount_ptr<Component> component =
930 root->LookupPath(match);
931 match = component->GenerateShortestPossiblePath();
932 }
933
934 matches.push_back(match);
935 }
936
937 return matches;
938 }
939
940
GetVariableNames(vector<string> & names) const941 void Component::GetVariableNames(vector<string>& names) const
942 {
943 for (StateVariableMap::const_iterator it = m_stateVariables.begin();
944 it != m_stateVariables.end(); ++it)
945 names.push_back(it->first);
946 }
947
948
GetVariable(const string & name)949 StateVariable* Component::GetVariable(const string& name)
950 {
951 StateVariableMap::iterator it = m_stateVariables.find(name);
952 if (it == m_stateVariables.end())
953 return NULL;
954 else
955 return &(it->second);
956 }
957
958
GetVariable(const string & name) const959 const StateVariable* Component::GetVariable(const string& name) const
960 {
961 StateVariableMap::const_iterator it = m_stateVariables.find(name);
962 if (it == m_stateVariables.end())
963 return NULL;
964 else
965 return &(it->second);
966 }
967
968
CheckVariableWrite(StateVariable & var,const string & oldValue)969 bool Component::CheckVariableWrite(StateVariable& var, const string& oldValue)
970 {
971 GXemul* gxemul = GetRunningGXemulInstance();
972 UI* ui = GetUI();
973
974 if (gxemul != NULL) {
975 const string& name = var.GetName();
976
977 if (name == "step") {
978 // If we are the root component, then writing to step
979 // has special meaning:
980 if (GetParent() == NULL) {
981 bool error = false;
982 int64_t oldStep = StringHelper::ParseNumber(oldValue.c_str(), error);
983 int64_t newStep = var.ToInteger();
984
985 // 0. Value is the same as before. Simply return.
986 if (newStep == oldStep)
987 return true;
988
989 // 1. The new value is too low (less than 0).
990 if (newStep < 0) {
991 if (ui != NULL)
992 ui->ShowDebugMessage("root.step can"
993 " not be set to lower than zero.\n");
994 return false;
995 }
996
997 // 2. The value is lower; run backwards if possible.
998 if (newStep < oldStep) {
999 if (!gxemul->GetSnapshottingEnabled()) {
1000 if (ui != NULL)
1001 ui->ShowDebugMessage("root.step can"
1002 " not be decreased; snapshotting"
1003 " was not enabled prior to\nstarting"
1004 " the emulation. (-B command line"
1005 " option.)\n");
1006 return false;
1007 }
1008
1009 return gxemul->ModifyStep(oldStep, newStep);
1010 }
1011
1012 // 3. The value is higher; run forwards.
1013 return gxemul->ModifyStep(oldStep, newStep);
1014 } else {
1015 // We are not the root component. Direct (interactive)
1016 // writes to the step variable is not allowed.
1017 if (ui != NULL)
1018 ui->ShowDebugMessage("The step variable of "
1019 "this component cannot be set manually.\n");
1020 }
1021
1022 return false;
1023 }
1024 }
1025
1026 return true;
1027 }
1028
1029
SetVariableValue(const string & name,const string & expression)1030 bool Component::SetVariableValue(const string& name, const string& expression)
1031 {
1032 UI* ui = GetUI();
1033
1034 StateVariableMap::iterator it = m_stateVariables.find(name);
1035 if (it == m_stateVariables.end()) {
1036 if (ui != NULL)
1037 ui->ShowDebugMessage((string) name + ": no such variable\n");
1038 return false;
1039 }
1040
1041 StateVariable& var = it->second;
1042
1043 stringstream oldValue;
1044 var.SerializeValue(oldValue);
1045
1046 bool success = var.SetValue(expression);
1047 if (!success) {
1048 if (ui != NULL)
1049 ui->ShowDebugMessage((string) name + ": expression could"
1050 " not be assigned; type mismatch?\n");
1051 return false;
1052 }
1053
1054 stringstream newValue;
1055 var.SerializeValue(newValue);
1056
1057 if (oldValue.str() != newValue.str()) {
1058 success = CheckVariableWrite(var, oldValue.str());
1059 if (!success) {
1060 // Revert to the previous:
1061 var.SetValue(oldValue.str());
1062 return false;
1063 }
1064 }
1065
1066 return true;
1067 }
1068
1069
Serialize(ostream & ss,SerializationContext & context) const1070 void Component::Serialize(ostream& ss, SerializationContext& context) const
1071 {
1072 SerializationContext subContext = context.Indented();
1073 string tabs = context.Tabs();
1074
1075 ss << tabs << "component " << m_className << "\n" << tabs << "{\n";
1076
1077 for (StateVariableMap::const_iterator it = m_stateVariables.begin();
1078 it != m_stateVariables.end(); ++it)
1079 (it->second).Serialize(ss, subContext);
1080
1081 for (size_t i = 0, n = m_childComponents.size(); i < n; ++ i)
1082 m_childComponents[i]->Serialize(ss, subContext);
1083
1084 ss << tabs << "}\n";
1085 }
1086
1087
GetNextToken(const string & str,size_t & pos,string & token)1088 static bool GetNextToken(const string& str, size_t& pos, string& token)
1089 {
1090 token = "";
1091
1092 size_t len = str.length();
1093
1094 // Skip initial whitespace:
1095 while (pos < len &&
1096 (str[pos] == ' ' || str[pos] == '\t' ||
1097 str[pos] == '\r' || str[pos] == '\n'))
1098 ++ pos;
1099
1100 if (pos >= len)
1101 return false;
1102
1103 // Get the token, until end-of-string or until whitespace is found:
1104 bool quoted = false;
1105 do {
1106 char ch = str[pos];
1107
1108 if (!quoted) {
1109 if (ch == '"')
1110 quoted = true;
1111 if (ch == ' ' || ch == '\t' ||
1112 ch == '\r' || ch == '\n')
1113 break;
1114 token += ch;
1115 } else {
1116 if (ch == '"')
1117 quoted = false;
1118 token += ch;
1119 if (ch == '\\' && pos < len-1)
1120 token += str[++pos];
1121 }
1122
1123 ++ pos;
1124 } while (pos < len);
1125
1126 return true;
1127 }
1128
1129
Deserialize(ostream & messages,const string & str,size_t & pos)1130 refcount_ptr<Component> Component::Deserialize(ostream& messages, const string& str, size_t& pos)
1131 {
1132 refcount_ptr<Component> deserializedTree = NULL;
1133 string token;
1134
1135 if (!GetNextToken(str, pos, token) || token != "component") {
1136 messages << "Expecting \"component\".\n";
1137 return deserializedTree;
1138 }
1139
1140 string className;
1141 if (!GetNextToken(str, pos, className)) {
1142 messages << "Expecting a class name.\n";
1143 return deserializedTree;
1144 }
1145
1146 if (!GetNextToken(str, pos, token) || token != "{") {
1147 messages << "Expecting {.\n";
1148 return deserializedTree;
1149 }
1150
1151 // root is a special case (cannot be created by the factory). All other
1152 // class types should be possible to create using the factory.
1153 if (className == "root") {
1154 deserializedTree = new RootComponent;
1155 } else {
1156 deserializedTree = ComponentFactory::CreateComponent(className);
1157 if (deserializedTree.IsNULL()) {
1158 messages << "Could not create a '" << className << "' component.\n";
1159 return deserializedTree;
1160 }
1161 }
1162
1163 while (pos < str.length()) {
1164 size_t savedPos = pos;
1165
1166 // Either 1) } (end of current component)
1167 // or 2) component name { ...
1168 // or 3) variableType name "value"
1169
1170 if (!GetNextToken(str, pos, token)) {
1171 // Failure.
1172 messages << "Failure. (0)\n";
1173 deserializedTree = NULL;
1174 break;
1175 }
1176
1177 // Case 1:
1178 if (token == "}")
1179 break;
1180
1181 string name;
1182 if (!GetNextToken(str, pos, name)) {
1183 // Failure.
1184 messages << "Failure. (1)\n";
1185 deserializedTree = NULL;
1186 break;
1187 }
1188
1189 if (token == "component") {
1190 // Case 2:
1191 refcount_ptr<Component> child =
1192 Component::Deserialize(messages, str, savedPos);
1193 if (child.IsNULL()) {
1194 // Failure.
1195 messages << "Failure. (2)\n";
1196 deserializedTree = NULL;
1197 break;
1198 }
1199
1200 deserializedTree->AddChild(child);
1201 pos = savedPos;
1202 } else {
1203 // Case 3:
1204 string varType = token;
1205 string varValue;
1206 if (!GetNextToken(str, pos, varValue)) {
1207 // Failure.
1208 messages << "Failure. (3)\n";
1209 deserializedTree = NULL;
1210 break;
1211 }
1212
1213 if (!deserializedTree->SetVariableValue(name,
1214 varValue)) {
1215 messages << "Warning: variable '" << name <<
1216 "' for component class " << className <<
1217 " could not be deserialized; skipping.\n";
1218 }
1219 }
1220 }
1221
1222 return deserializedTree;
1223 }
1224
1225
CheckConsistency() const1226 bool Component::CheckConsistency() const
1227 {
1228 // Serialize
1229 SerializationContext context;
1230 stringstream ss;
1231 Serialize(ss, context);
1232
1233 string result = ss.str();
1234
1235 Checksum checksumOriginal;
1236 AddChecksum(checksumOriginal);
1237
1238 // Deserialize
1239 size_t pos = 0;
1240 stringstream messages;
1241 refcount_ptr<Component> tmpDeserializedTree = Deserialize(messages, result, pos);
1242 if (tmpDeserializedTree.IsNULL())
1243 return false;
1244
1245 Checksum checksumDeserialized;
1246 tmpDeserializedTree->AddChecksum(checksumDeserialized);
1247
1248 // ... and compare the checksums:
1249 return checksumOriginal == checksumDeserialized;
1250 }
1251
1252
AddChecksum(Checksum & checksum) const1253 void Component::AddChecksum(Checksum& checksum) const
1254 {
1255 // Some random stuff is added between normal fields to the checksum.
1256 // This is to make it harder to get the same checksum for two different
1257 // objects, that just have some fields swapped, or such. (Yes, I know,
1258 // that is not a very scientific explanation :) but it will have to do.)
1259
1260 checksum.Add(((uint64_t) 0x12491725 << 32) | 0xabcef011);
1261 checksum.Add(m_className);
1262
1263 SerializationContext dummyContext;
1264
1265 // Add all state variables.
1266 for (StateVariableMap::const_iterator it = m_stateVariables.begin();
1267 it != m_stateVariables.end();
1268 ++ it) {
1269 checksum.Add(((uint64_t) 0x019fb879 << 32) | 0x25addae1);
1270
1271 stringstream ss;
1272 (it->second).Serialize(ss, dummyContext);
1273 checksum.Add(ss.str());
1274 }
1275
1276 // Add all child components.
1277 for (size_t i = 0; i < m_childComponents.size(); ++ i) {
1278 checksum.Add((((uint64_t) 0xf98a7c7c << 32) | 0x109f0000)
1279 + i * 0x98127417);
1280 m_childComponents[i]->AddChecksum(checksum);
1281 }
1282
1283 checksum.Add(((uint64_t) 0x90a10224 << 32) | 0x97defa7a);
1284 }
1285
1286
1287