Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/output/src/libraries/util/output/OutputManager.cc @ 8833

Last change on this file since 8833 was 8833, checked in by landauf, 13 years ago

A context is now defined by a struct instead of only a mask.

Introduced sub-contexts. Sub-contexts of the same main-context share the same mask, but have a different ID.
Main-contexts are filtered using a bitmask which happens for every line of output and is very fast.
Sub-contexts are filtered using a set which is slow but happens only if a specific sub-context is enabled in the config file which is usually not the case.

The concept of filtering normal output + additional contexts was moved from BaseWriter directly to OutputListener and OutputManager which makes the whole system faster.
BaseWriter now calls registerContext() for each configured output context, which basically allows the usage of more than 64 contexts as long as these contexts are not used before loading the config file. Though by design it's not recommended.

  • Property svn:eol-style set to native
File size: 7.5 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "OutputManager.h"
30
31#include "MemoryWriter.h"
32#include "ConsoleWriter.h"
33#include "LogWriter.h"
34#include "util/Output.h"
35#include "util/StringUtils.h"
36
37namespace orxonox
38{
39    OutputManager::OutputManager()
40    {
41        this->combinedLevelMask_ = level::none;
42        this->combinedAdditionalContextsLevelMask_ = level::none;
43        this->combinedAdditionalContextsMask_ = context::none;
44
45        this->subcontextCounter_ = 0;
46    }
47
48    OutputManager::~OutputManager()
49    {
50    }
51
52    /*static*/ OutputManager& OutputManager::getInstance()
53    {
54        static OutputManager instance;
55        return instance;
56    }
57
58    /*static*/ OutputManager& OutputManager::getInstanceAndCreateListeners()
59    {
60        static OutputManager& instance = OutputManager::getInstance();
61
62        static MemoryWriter& memoryWriterInstance = MemoryWriter::getInstance(); (void)memoryWriterInstance;
63        static ConsoleWriter& consoleWriterInstance = ConsoleWriter::getInstance(); (void)consoleWriterInstance;
64        static LogWriter& logWriterInstance = LogWriter::getInstance(); (void)logWriterInstance;
65
66        return instance;
67    }
68
69    void OutputManager::pushMessage(OutputLevel level, const OutputContextContainer& context, const std::string& message)
70    {
71        std::vector<std::string> lines;
72        vectorize(message, '\n', &lines);
73
74        for (size_t i = 0; i < this->listeners_.size(); ++i)
75            this->listeners_[i]->unfilteredOutput(level, context, lines);
76    }
77
78    void OutputManager::registerListener(OutputListener* listener)
79    {
80        this->listeners_.push_back(listener);
81        this->updateMasks();
82    }
83
84    void OutputManager::unregisterListener(OutputListener* listener)
85    {
86        for (std::vector<OutputListener*>::iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it)
87        {
88            if (*it == listener)
89            {
90                this->listeners_.erase(it);
91                break;
92            }
93        }
94        this->updateMasks();
95    }
96
97    void OutputManager::updateMasks()
98    {
99        this->updateCombinedLevelMask();
100        this->updateCombinedAdditionalContextsLevelMask();
101        this->updateCombinedAdditionalContextsMask();
102    }
103
104    void OutputManager::updateCombinedLevelMask()
105    {
106        int mask = 0;
107        for (size_t i = 0; i < this->listeners_.size(); ++i)
108            mask |= this->listeners_[i]->getLevelMask();
109        this->combinedLevelMask_ = static_cast<OutputLevel>(mask);
110    }
111
112    void OutputManager::updateCombinedAdditionalContextsLevelMask()
113    {
114        int mask = 0;
115        for (size_t i = 0; i < this->listeners_.size(); ++i)
116            mask |= this->listeners_[i]->getAdditionalContextsLevelMask();
117        this->combinedAdditionalContextsLevelMask_ = static_cast<OutputLevel>(mask);
118    }
119
120    void OutputManager::updateCombinedAdditionalContextsMask()
121    {
122        this->combinedAdditionalContextsMask_ = 0;
123        for (size_t i = 0; i < this->listeners_.size(); ++i)
124            this->combinedAdditionalContextsMask_ |= this->listeners_[i]->getAdditionalContextsMask();
125    }
126
127    const OutputContextContainer& OutputManager::registerContext(const std::string& name, const std::string& subname)
128    {
129        std::string full_name = name;
130        if (subname != "")
131            full_name += "::" + subname;
132
133        std::map<std::string, OutputContextContainer>::iterator it_container = this->contextContainers_.find(full_name);
134        if (it_container != this->contextContainers_.end())
135            return it_container->second;
136
137        OutputContextContainer container;
138        container.name = full_name;
139
140        std::map<std::string, OutputContextMask>::iterator it_mask = this->contextMasks_.find(name);
141        if (it_mask != this->contextMasks_.end())
142        {
143            container.mask = it_mask->second;
144        }
145        else
146        {
147            container.mask = static_cast<OutputContextMask>(0x1) << this->contextMasks_.size();
148            this->contextMasks_[name] = container.mask;
149
150            if (container.mask == 0)
151                orxout(internal_warning) << "More than " << sizeof(OutputContextMask) * 8 << " output contexts defined. Context '" << name << "' might not get filtered correctly" << endl;
152        }
153
154        if (subname == "")
155            container.sub_id = context::no_subcontext;
156        else
157            container.sub_id = ++this->subcontextCounter_; // start with 1
158
159        return (this->contextContainers_[full_name] = container);
160    }
161
162    const OutputContextContainer& registerContext(const std::string& name, const std::string& subname)
163    {
164        return OutputManager::getInstance().registerContext(name, subname);
165    }
166
167    const std::string& OutputManager::getLevelName(OutputLevel level) const
168    {
169        switch (level)
170        {
171            case level::none:               { static std::string name = "None"; return name; }
172            case level::message:            { static std::string name = "Message"; return name; }
173            case level::debug_output:       { static std::string name = "Debug"; return name; }
174            case level::user_error:         { static std::string name = "Error"; return name; }
175            case level::user_warning:       { static std::string name = "Warning"; return name; }
176            case level::user_status:        { static std::string name = "Status"; return name; }
177            case level::user_info:          { static std::string name = "Info"; return name; }
178            case level::internal_error:     { static std::string name = "Error (internal)"; return name; }
179            case level::internal_warning:   { static std::string name = "Warning (internal)"; return name; }
180            case level::internal_status:    { static std::string name = "Status (internal)"; return name; }
181            case level::internal_info:      { static std::string name = "Info (internal)"; return name; }
182            case level::verbose:            { static std::string name = "Verbose"; return name; }
183            case level::verbose_more:       { static std::string name = "Verbose (more)"; return name; }
184            case level::verbose_ultra:      { static std::string name = "Verbose (ultra)"; return name; }
185            default:                        { static std::string name = ""; return name; }
186        }
187    }
188
189    std::string OutputManager::getDefaultPrefix(OutputLevel level, const OutputContextContainer& context) const
190    {
191        static OutputContextMask undefined_mask = context::undefined().mask;
192
193        std::string prefix = this->getLevelName(level) + ": ";
194        if (context.mask != undefined_mask)
195            prefix += "[" + context.name + "] ";
196
197        return prefix;
198    }
199}
Note: See TracBrowser for help on using the repository browser.