1/* Copyright (c) 2012 Massachusetts Institute of Technology
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 * THE SOFTWARE.
20 */
21
22#include "util/Result.h"
23
24#include <iostream>
25
26#include "libutil/Log.h"
27#include "libutil/Assert.h"
28
29namespace DSENT
30{
31    using std::ostream;
32    using std::endl;
33
34    Result::SubResult::SubResult(const Result* sub_result_, const String& producer_, double num_results_)
35        : m_result_(sub_result_), m_producer_(producer_), m_num_results_(num_results_)
36    {
37        // Check if the result is not a null pointer
38        ASSERT((sub_result_ != NULL), "Internal error: sub_result_ is null");
39
40        // Check if the number of results greater than 0
41        ASSERT((num_results_ >= 0), "Internal error: num_results_ (" + String(num_results_) + ") is less than 0");
42    }
43
44    Result::SubResult::~SubResult()
45    {}
46
47    const Result* Result::SubResult::getResult() const
48    {
49        return m_result_;
50    }
51
52    const String& Result::SubResult::getProducer() const
53    {
54        return m_producer_;
55    }
56
57    double Result::SubResult::getNumResults() const
58    {
59        return m_num_results_;
60    }
61
62    Result::SubResult* Result::SubResult::clone() const
63    {
64        return new SubResult(*this);
65    }
66
67    Result::SubResult::SubResult(const SubResult& sub_result_)
68        : m_result_(sub_result_.m_result_), m_producer_(sub_result_.m_producer_), m_num_results_(sub_result_.m_num_results_)
69    {}
70
71    Result::Result()
72    {}
73
74    Result::Result(const String& result_name_)
75        : m_result_name_(result_name_)
76    {}
77
78    Result::~Result()
79    {
80        // Clear all sub results
81        for(vector<SubResult*>::iterator it = m_sub_results_.begin();
82            it != m_sub_results_.end(); ++it)
83        {
84            SubResult* sub_result = (*it);
85            delete sub_result;
86        }
87    }
88
89    const String& Result::getName() const
90    {
91        return m_result_name_;
92    }
93
94    void Result::setValue(double /* value_ */)
95    {
96        throw LibUtil::Exception("[Error] " + getName() + " -> Cannot set the value of a non-atomic result!");
97        return;
98    }
99
100    void Result::addValue(double /* value_ */)
101    {
102        throw LibUtil::Exception("[Error] " + getName() +
103                " -> Cannot add the value of a non-atomic result");
104        return;
105    }
106
107    double Result::getValue() const
108    {
109        throw LibUtil::Exception("[Error] " + getName() + " -> Cannot get the value of a non-atomic result!");
110        return 0.0;
111    }
112
113    void Result::addSubResult(const Result* sub_result_, const String& result_producer_, double num_results_)
114    {
115        SubResult* new_sub_result = new SubResult(sub_result_, result_producer_, num_results_);
116        m_sub_results_.push_back(new_sub_result);
117        return;
118    }
119
120    void Result::removeAllSubResults()
121    {
122        // Clear all sub results
123        for(vector<SubResult*>::iterator it = m_sub_results_.begin();
124            it != m_sub_results_.end(); ++it)
125        {
126            SubResult* sub_result = (*it);
127            delete sub_result;
128        }
129        m_sub_results_.clear();
130        return;
131    }
132
133    double Result::calculateSum() const
134    {
135        double sum = 0.0;
136
137        // Loop through all sub results and calculate the sum
138        for(vector<SubResult*>::const_iterator it = m_sub_results_.begin();
139            it != m_sub_results_.end(); ++it)
140        {
141            const SubResult* temp_sub_result = (*it);
142            const Result* temp_result = temp_sub_result->getResult();
143            double num_results = temp_sub_result->getNumResults();
144            sum += temp_result->calculateSum()*num_results;
145        }
146        return sum;
147    }
148
149    void Result::print(const String& prepend_str_, int detail_level_, ostream& ost_) const
150    {
151        print(prepend_str_, 1.0, detail_level_, ost_);
152        return;
153    }
154
155    Result* Result::clone() const
156    {
157        return new Result(*this);
158    }
159
160    Result::Result(const Result& result_)
161    {
162        // Copy the result name
163        m_result_name_ = result_.m_result_name_;
164
165        // Clone all sub results
166        for(vector<SubResult*>::const_iterator it = m_sub_results_.begin();
167            it != m_sub_results_.end(); ++it)
168        {
169            const SubResult* temp_sub_result = (*it);
170            SubResult* new_sub_result = temp_sub_result->clone();
171            m_sub_results_.push_back(new_sub_result);
172        }
173    }
174
175    void Result::print(const String& prepend_str_, double num_results_, int detail_level_, ostream& ost_) const
176    {
177        // Go down to lower level if detail_level_ > 0, else print the sthe sthe sthe sum
178        if(detail_level_ > 0)
179        {
180            for(vector<SubResult*>::const_iterator it = m_sub_results_.begin();
181                    it != m_sub_results_.end(); ++it)
182            {
183                const SubResult* temp_sub_result = (*it);
184                const Result* temp_result = temp_sub_result->getResult();
185                const String& temp_producer = temp_sub_result->getProducer();
186                const String& temp_result_name = temp_result->getName();
187                double temp_num_results = temp_sub_result->getNumResults();
188                String temp_prepend_str = prepend_str_ + "->" + temp_producer;
189
190                if(!temp_result_name.empty())
191                {
192                    temp_prepend_str += ":" + temp_result_name;
193                }
194                temp_result->print(temp_prepend_str, num_results_*temp_num_results, detail_level_ - 1, ost_);
195            }
196        }
197        else
198        {
199            ost_ << prepend_str_ << " = " << calculateSum()*num_results_;
200            ost_ << " (" << calculateSum() << " * " << num_results_ << ")" << endl;
201        }
202        return;
203    }
204
205    void Result::printHierarchy(const String& prepend_str_, int detail_level_, ostream& ost_) const
206    {
207        if(detail_level_ > 0)
208        {
209            for(vector<SubResult*>::const_iterator it = m_sub_results_.begin(); it != m_sub_results_.end(); ++it)
210            {
211                const SubResult* temp_sub_result = (*it);
212                const Result* temp_result = temp_sub_result->getResult();
213                const String& temp_producer = temp_sub_result->getProducer();
214                const String& temp_result_name = temp_result->getName();
215                String temp_prepend_str = prepend_str_ + "    ";
216
217                ost_ << prepend_str_ << " |--" << temp_producer << "->" << temp_result_name << endl;
218
219                temp_result->printHierarchy(temp_prepend_str, detail_level_ - 1, ost_);
220            }
221        }
222        return;
223    }
224
225    AtomicResult::AtomicResult(const String& result_name_, double value_)
226        : Result(result_name_), m_value_(value_)
227    {}
228
229    AtomicResult::~AtomicResult()
230    {}
231
232    void AtomicResult::setValue(double value_)
233    {
234        m_value_ = value_;
235        return;
236    }
237
238    void AtomicResult::addValue(double value_)
239    {
240        m_value_ += value_;
241        return;
242    }
243
244    double AtomicResult::getValue() const
245    {
246        return m_value_;
247    }
248
249    double AtomicResult::calculateSum() const
250    {
251        return m_value_;
252    }
253
254    AtomicResult* AtomicResult::clone() const
255    {
256        return new AtomicResult(*this);
257    }
258
259    AtomicResult::AtomicResult(const AtomicResult& atomic_result_)
260        : Result(atomic_result_), m_value_(atomic_result_.m_value_)
261    {}
262
263    void AtomicResult::print(const String& prepend_str_, double num_results_, int /* detail_level_ */, ostream& ost_) const
264    {
265        ost_ << prepend_str_ << " = " << m_value_*num_results_;
266        ost_ << " (" << m_value_ << " * " << num_results_ << ")" << endl;
267        return;
268    }
269} // namespace DSENT
270
271