1//===-- TypeCategoryMap.cpp ----------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "lldb/lldb-python.h"
11
12#include "lldb/DataFormatters/TypeCategoryMap.h"
13
14// C Includes
15// C++ Includes
16// Other libraries and framework includes
17// Project includes
18
19using namespace lldb;
20using namespace lldb_private;
21
22TypeCategoryMap::TypeCategoryMap (IFormatChangeListener* lst) :
23m_map_mutex(Mutex::eMutexTypeRecursive),
24listener(lst),
25m_map(),
26m_active_categories()
27{
28    ConstString default_cs("default");
29    lldb::TypeCategoryImplSP default_sp = lldb::TypeCategoryImplSP(new TypeCategoryImpl(listener, default_cs));
30    Add(default_cs,default_sp);
31    Enable(default_cs,First);
32}
33
34void
35TypeCategoryMap::Add (KeyType name, const ValueSP& entry)
36{
37    Mutex::Locker locker(m_map_mutex);
38    m_map[name] = entry;
39    if (listener)
40        listener->Changed();
41}
42
43bool
44TypeCategoryMap::Delete (KeyType name)
45{
46    Mutex::Locker locker(m_map_mutex);
47    MapIterator iter = m_map.find(name);
48    if (iter == m_map.end())
49        return false;
50    m_map.erase(name);
51    Disable(name);
52    if (listener)
53        listener->Changed();
54    return true;
55}
56
57bool
58TypeCategoryMap::Enable (KeyType category_name, Position pos)
59{
60    Mutex::Locker locker(m_map_mutex);
61    ValueSP category;
62    if (!Get(category_name,category))
63        return false;
64    return Enable(category, pos);
65}
66
67bool
68TypeCategoryMap::Disable (KeyType category_name)
69{
70    Mutex::Locker locker(m_map_mutex);
71    ValueSP category;
72    if (!Get(category_name,category))
73        return false;
74    return Disable(category);
75}
76
77bool
78TypeCategoryMap::Enable (ValueSP category, Position pos)
79{
80    Mutex::Locker locker(m_map_mutex);
81    if (category.get())
82    {
83        Position pos_w = pos;
84        if (pos == First || m_active_categories.size() == 0)
85            m_active_categories.push_front(category);
86        else if (pos == Last || pos == m_active_categories.size())
87            m_active_categories.push_back(category);
88        else if (pos < m_active_categories.size())
89        {
90            ActiveCategoriesList::iterator iter = m_active_categories.begin();
91            while (pos_w)
92            {
93                pos_w--,iter++;
94            }
95            m_active_categories.insert(iter,category);
96        }
97        else
98            return false;
99        category->Enable(true,
100                         pos);
101        return true;
102    }
103    return false;
104}
105
106bool
107TypeCategoryMap::Disable (ValueSP category)
108{
109    Mutex::Locker locker(m_map_mutex);
110    if (category.get())
111    {
112        m_active_categories.remove_if(delete_matching_categories(category));
113        category->Disable();
114        return true;
115    }
116    return false;
117}
118
119void
120TypeCategoryMap::Clear ()
121{
122    Mutex::Locker locker(m_map_mutex);
123    m_map.clear();
124    m_active_categories.clear();
125    if (listener)
126        listener->Changed();
127}
128
129bool
130TypeCategoryMap::Get (KeyType name, ValueSP& entry)
131{
132    Mutex::Locker locker(m_map_mutex);
133    MapIterator iter = m_map.find(name);
134    if (iter == m_map.end())
135        return false;
136    entry = iter->second;
137    return true;
138}
139
140bool
141TypeCategoryMap::Get (uint32_t pos, ValueSP& entry)
142{
143    Mutex::Locker locker(m_map_mutex);
144    MapIterator iter = m_map.begin();
145    MapIterator end = m_map.end();
146    while (pos > 0)
147    {
148        iter++;
149        pos--;
150        if (iter == end)
151            return false;
152    }
153    entry = iter->second;
154    return false;
155}
156
157bool
158TypeCategoryMap::AnyMatches (ConstString type_name,
159                             TypeCategoryImpl::FormatCategoryItems items,
160                             bool only_enabled,
161                             const char** matching_category,
162                             TypeCategoryImpl::FormatCategoryItems* matching_type)
163{
164    Mutex::Locker locker(m_map_mutex);
165
166    MapIterator pos, end = m_map.end();
167    for (pos = m_map.begin(); pos != end; pos++)
168    {
169        if (pos->second->AnyMatches(type_name,
170                                    items,
171                                    only_enabled,
172                                    matching_category,
173                                    matching_type))
174            return true;
175    }
176    return false;
177}
178
179lldb::TypeSummaryImplSP
180TypeCategoryMap::GetSummaryFormat (ValueObject& valobj,
181                                   lldb::DynamicValueType use_dynamic)
182{
183    Mutex::Locker locker(m_map_mutex);
184
185    uint32_t reason_why;
186    ActiveCategoriesIterator begin, end = m_active_categories.end();
187
188    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
189
190    for (begin = m_active_categories.begin(); begin != end; begin++)
191    {
192        lldb::TypeCategoryImplSP category_sp = *begin;
193        lldb::TypeSummaryImplSP current_format;
194        if (log)
195            log->Printf("\n[CategoryMap::GetSummaryFormat] Trying to use category %s", category_sp->GetName());
196        if (!category_sp->Get(valobj, current_format, use_dynamic, &reason_why))
197            continue;
198        return current_format;
199    }
200    if (log)
201        log->Printf("[CategoryMap::GetSummaryFormat] nothing found - returning empty SP");
202    return lldb::TypeSummaryImplSP();
203}
204
205#ifndef LLDB_DISABLE_PYTHON
206lldb::SyntheticChildrenSP
207TypeCategoryMap::GetSyntheticChildren (ValueObject& valobj,
208                                       lldb::DynamicValueType use_dynamic)
209{
210    Mutex::Locker locker(m_map_mutex);
211
212    uint32_t reason_why;
213
214    ActiveCategoriesIterator begin, end = m_active_categories.end();
215
216    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
217
218    for (begin = m_active_categories.begin(); begin != end; begin++)
219    {
220        lldb::TypeCategoryImplSP category_sp = *begin;
221        lldb::SyntheticChildrenSP current_format;
222        if (log)
223            log->Printf("\n[CategoryMap::GetSyntheticChildren] Trying to use category %s", category_sp->GetName());
224        if (!category_sp->Get(valobj, current_format, use_dynamic, &reason_why))
225            continue;
226        return current_format;
227    }
228    if (log)
229        log->Printf("[CategoryMap::GetSyntheticChildren] nothing found - returning empty SP");
230    return lldb::SyntheticChildrenSP();
231}
232#endif
233
234void
235TypeCategoryMap::LoopThrough(CallbackType callback, void* param)
236{
237    if (callback)
238    {
239        Mutex::Locker locker(m_map_mutex);
240
241        // loop through enabled categories in respective order
242        {
243            ActiveCategoriesIterator begin, end = m_active_categories.end();
244            for (begin = m_active_categories.begin(); begin != end; begin++)
245            {
246                lldb::TypeCategoryImplSP category = *begin;
247                ConstString type = ConstString(category->GetName());
248                if (!callback(param, category))
249                    break;
250            }
251        }
252
253        // loop through disabled categories in just any order
254        {
255            MapIterator pos, end = m_map.end();
256            for (pos = m_map.begin(); pos != end; pos++)
257            {
258                if (pos->second->IsEnabled())
259                    continue;
260                KeyType type = pos->first;
261                if (!callback(param, pos->second))
262                    break;
263            }
264        }
265    }
266}
267
268TypeCategoryImplSP
269TypeCategoryMap::GetAtIndex (uint32_t index)
270{
271    Mutex::Locker locker(m_map_mutex);
272
273    if (index < m_map.size())
274    {
275        MapIterator pos, end = m_map.end();
276        for (pos = m_map.begin(); pos != end; pos++)
277        {
278            if (index == 0)
279                return pos->second;
280            index--;
281        }
282    }
283
284    return TypeCategoryImplSP();
285}
286