Bug Summary

File:tools/lldb/source/Commands/CommandObjectType.cpp
Warning:line 67, column 29
Use of memory after it is freed

Annotated Source Code

/build/llvm-toolchain-snapshot-6.0~svn318882/tools/lldb/source/Commands/CommandObjectType.cpp

1//===-- CommandObjectType.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 "CommandObjectType.h"
11
12// C Includes
13// C++ Includes
14#include <algorithm>
15#include <cctype>
16#include <functional>
17
18// Project includes
19#include "lldb/Core/Debugger.h"
20#include "lldb/Core/IOHandler.h"
21#include "lldb/Core/State.h"
22#include "lldb/DataFormatters/DataVisualization.h"
23#include "lldb/Host/OptionParser.h"
24#include "lldb/Interpreter/CommandInterpreter.h"
25#include "lldb/Interpreter/CommandObject.h"
26#include "lldb/Interpreter/CommandReturnObject.h"
27#include "lldb/Interpreter/OptionGroupFormat.h"
28#include "lldb/Interpreter/OptionValueBoolean.h"
29#include "lldb/Interpreter/OptionValueLanguage.h"
30#include "lldb/Interpreter/OptionValueString.h"
31#include "lldb/Interpreter/Options.h"
32#include "lldb/Symbol/Symbol.h"
33#include "lldb/Target/Language.h"
34#include "lldb/Target/Process.h"
35#include "lldb/Target/StackFrame.h"
36#include "lldb/Target/Target.h"
37#include "lldb/Target/Thread.h"
38#include "lldb/Target/ThreadList.h"
39#include "lldb/Utility/ConstString.h"
40#include "lldb/Utility/RegularExpression.h"
41#include "lldb/Utility/StringList.h"
42
43// Other libraries and framework includes
44#include "llvm/ADT/STLExtras.h"
45
46using namespace lldb;
47using namespace lldb_private;
48
49class ScriptAddOptions {
50public:
51 TypeSummaryImpl::Flags m_flags;
52 StringList m_target_types;
53 bool m_regex;
54 ConstString m_name;
55 std::string m_category;
56
57 ScriptAddOptions(const TypeSummaryImpl::Flags &flags, bool regx,
58 const ConstString &name, std::string catg)
59 : m_flags(flags), m_regex(regx), m_name(name), m_category(catg) {}
60
61 typedef std::shared_ptr<ScriptAddOptions> SharedPointer;
62};
63
64class SynthAddOptions {
65public:
66 bool m_skip_pointers;
67 bool m_skip_references;
68 bool m_cascade;
69 bool m_regex;
70 StringList m_target_types;
71 std::string m_category;
72
73 SynthAddOptions(bool sptr, bool sref, bool casc, bool regx, std::string catg)
74 : m_skip_pointers(sptr), m_skip_references(sref), m_cascade(casc),
75 m_regex(regx), m_target_types(), m_category(catg) {}
76
77 typedef std::shared_ptr<SynthAddOptions> SharedPointer;
78};
79
80static bool WarnOnPotentialUnquotedUnsignedType(Args &command,
81 CommandReturnObject &result) {
82 if (command.empty())
83 return false;
84
85 for (auto entry : llvm::enumerate(command.entries().drop_back())) {
86 if (entry.value().ref != "unsigned")
87 continue;
88 auto next = command.entries()[entry.index() + 1].ref;
89 if (next == "int" || next == "short" || next == "char" || next == "long") {
90 result.AppendWarningWithFormat(
91 "unsigned %s being treated as two types. if you meant the combined "
92 "type "
93 "name use quotes, as in \"unsigned %s\"\n",
94 next.str().c_str(), next.str().c_str());
95 return true;
96 }
97 }
98 return false;
99}
100
101static OptionDefinition g_type_summary_add_options[] = {
102 // clang-format off
103 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "category", 'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "Add this to the given category instead of the default one." },
104 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "cascade", 'C', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, cascade through typedef chains." },
105 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "no-value", 'v', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't show the value, just show the summary, for this type." },
106 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "skip-pointers", 'p', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects." },
107 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "skip-references", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use this format for references-to-type objects." },
108 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "regex", 'x', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Type names are actually regular expressions." },
109 { LLDB_OPT_SET_1(1U << 0), true, "inline-children", 'c', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "If true, inline all child values into summary string." },
110 { LLDB_OPT_SET_1(1U << 0), false, "omit-names", 'O', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "If true, omit value names in the summary display." },
111 { LLDB_OPT_SET_2(1U << 1), true, "summary-string", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeSummaryString, "Summary string used to display text and object contents." },
112 { LLDB_OPT_SET_3(1U << 2), false, "python-script", 'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonScript, "Give a one-liner Python script as part of the command." },
113 { LLDB_OPT_SET_3(1U << 2), false, "python-function", 'F', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonFunction, "Give the name of a Python function to use for this type." },
114 { LLDB_OPT_SET_3(1U << 2), false, "input-python", 'P', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Input Python code to use for this type manually." },
115 { LLDB_OPT_SET_2(1U << 1) | LLDB_OPT_SET_3(1U << 2), false, "expand", 'e', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Expand aggregate data types to show children on separate lines." },
116 { LLDB_OPT_SET_2(1U << 1) | LLDB_OPT_SET_3(1U << 2), false, "hide-empty", 'h', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Do not expand aggregate data types with no children." },
117 { LLDB_OPT_SET_2(1U << 1) | LLDB_OPT_SET_3(1U << 2), false, "name", 'n', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "A name for this summary string." }
118 // clang-format on
119};
120
121class CommandObjectTypeSummaryAdd : public CommandObjectParsed,
122 public IOHandlerDelegateMultiline {
123private:
124 class CommandOptions : public Options {
125 public:
126 CommandOptions(CommandInterpreter &interpreter) : Options() {}
127
128 ~CommandOptions() override = default;
129
130 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
131 ExecutionContext *execution_context) override;
132
133 void OptionParsingStarting(ExecutionContext *execution_context) override;
134
135 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
136 return llvm::makeArrayRef(g_type_summary_add_options);
137 }
138
139 // Instance variables to hold the values for command options.
140
141 TypeSummaryImpl::Flags m_flags;
142 bool m_regex;
143 std::string m_format_string;
144 ConstString m_name;
145 std::string m_python_script;
146 std::string m_python_function;
147 bool m_is_add_script;
148 std::string m_category;
149 };
150
151 CommandOptions m_options;
152
153 Options *GetOptions() override { return &m_options; }
154
155 bool Execute_ScriptSummary(Args &command, CommandReturnObject &result);
156
157 bool Execute_StringSummary(Args &command, CommandReturnObject &result);
158
159public:
160 enum SummaryFormatType { eRegularSummary, eRegexSummary, eNamedSummary };
161
162 CommandObjectTypeSummaryAdd(CommandInterpreter &interpreter);
163
164 ~CommandObjectTypeSummaryAdd() override = default;
165
166 void IOHandlerActivated(IOHandler &io_handler) override {
167 static const char *g_summary_addreader_instructions =
168 "Enter your Python command(s). Type 'DONE' to end.\n"
169 "def function (valobj,internal_dict):\n"
170 " \"\"\"valobj: an SBValue which you want to provide a summary "
171 "for\n"
172 " internal_dict: an LLDB support object not to be used\"\"\"\n";
173
174 StreamFileSP output_sp(io_handler.GetOutputStreamFile());
175 if (output_sp) {
176 output_sp->PutCString(g_summary_addreader_instructions);
177 output_sp->Flush();
178 }
179 }
180
181 void IOHandlerInputComplete(IOHandler &io_handler,
182 std::string &data) override {
183 StreamFileSP error_sp = io_handler.GetErrorStreamFile();
184
185#ifndef LLDB_DISABLE_PYTHON
186 ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
187 if (interpreter) {
188 StringList lines;
189 lines.SplitIntoLines(data);
190 if (lines.GetSize() > 0) {
191 ScriptAddOptions *options_ptr =
192 ((ScriptAddOptions *)io_handler.GetUserData());
193 if (options_ptr) {
194 ScriptAddOptions::SharedPointer options(
195 options_ptr); // this will ensure that we get rid of the pointer
196 // when going out of scope
197
198 ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
199 if (interpreter) {
200 std::string funct_name_str;
201 if (interpreter->GenerateTypeScriptFunction(lines,
202 funct_name_str)) {
203 if (funct_name_str.empty()) {
204 error_sp->Printf("unable to obtain a valid function name from "
205 "the script interpreter.\n");
206 error_sp->Flush();
207 } else {
208 // now I have a valid function name, let's add this as script
209 // for every type in the list
210
211 TypeSummaryImplSP script_format;
212 script_format.reset(new ScriptSummaryFormat(
213 options->m_flags, funct_name_str.c_str(),
214 lines.CopyList(" ").c_str()));
215
216 Status error;
217
218 for (size_t i = 0; i < options->m_target_types.GetSize(); i++) {
219 const char *type_name =
220 options->m_target_types.GetStringAtIndex(i);
221 CommandObjectTypeSummaryAdd::AddSummary(
222 ConstString(type_name), script_format,
223 (options->m_regex
224 ? CommandObjectTypeSummaryAdd::eRegexSummary
225 : CommandObjectTypeSummaryAdd::eRegularSummary),
226 options->m_category, &error);
227 if (error.Fail()) {
228 error_sp->Printf("error: %s", error.AsCString());
229 error_sp->Flush();
230 }
231 }
232
233 if (options->m_name) {
234 CommandObjectTypeSummaryAdd::AddSummary(
235 options->m_name, script_format,
236 CommandObjectTypeSummaryAdd::eNamedSummary,
237 options->m_category, &error);
238 if (error.Fail()) {
239 CommandObjectTypeSummaryAdd::AddSummary(
240 options->m_name, script_format,
241 CommandObjectTypeSummaryAdd::eNamedSummary,
242 options->m_category, &error);
243 if (error.Fail()) {
244 error_sp->Printf("error: %s", error.AsCString());
245 error_sp->Flush();
246 }
247 } else {
248 error_sp->Printf("error: %s", error.AsCString());
249 error_sp->Flush();
250 }
251 } else {
252 if (error.AsCString()) {
253 error_sp->Printf("error: %s", error.AsCString());
254 error_sp->Flush();
255 }
256 }
257 }
258 } else {
259 error_sp->Printf("error: unable to generate a function.\n");
260 error_sp->Flush();
261 }
262 } else {
263 error_sp->Printf("error: no script interpreter.\n");
264 error_sp->Flush();
265 }
266 } else {
267 error_sp->Printf("error: internal synchronization information "
268 "missing or invalid.\n");
269 error_sp->Flush();
270 }
271 } else {
272 error_sp->Printf("error: empty function, didn't add python command.\n");
273 error_sp->Flush();
274 }
275 } else {
276 error_sp->Printf(
277 "error: script interpreter missing, didn't add python command.\n");
278 error_sp->Flush();
279 }
280#endif // LLDB_DISABLE_PYTHON
281 io_handler.SetIsDone(true);
282 }
283
284 static bool AddSummary(ConstString type_name, lldb::TypeSummaryImplSP entry,
285 SummaryFormatType type, std::string category,
286 Status *error = nullptr);
287
288protected:
289 bool DoExecute(Args &command, CommandReturnObject &result) override;
290};
291
292static const char *g_synth_addreader_instructions =
293 "Enter your Python command(s). Type 'DONE' to end.\n"
294 "You must define a Python class with these methods:\n"
295 " def __init__(self, valobj, dict):\n"
296 " def num_children(self):\n"
297 " def get_child_at_index(self, index):\n"
298 " def get_child_index(self, name):\n"
299 " def update(self):\n"
300 " '''Optional'''\n"
301 "class synthProvider:\n";
302
303static OptionDefinition g_type_synth_add_options[] = {
304 // clang-format off
305 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "cascade", 'C', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, cascade through typedef chains." },
306 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "skip-pointers", 'p', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects." },
307 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "skip-references", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use this format for references-to-type objects." },
308 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "category", 'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "Add this to the given category instead of the default one." },
309 { LLDB_OPT_SET_2(1U << 1), false, "python-class", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonClass, "Use this Python class to produce synthetic children." },
310 { LLDB_OPT_SET_3(1U << 2), false, "input-python", 'P', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Type Python code to generate a class that provides synthetic children." },
311 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "regex", 'x', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Type names are actually regular expressions." }
312 // clang-format on
313};
314
315class CommandObjectTypeSynthAdd : public CommandObjectParsed,
316 public IOHandlerDelegateMultiline {
317private:
318 class CommandOptions : public Options {
319 public:
320 CommandOptions() : Options() {}
321
322 ~CommandOptions() override = default;
323
324 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
325 ExecutionContext *execution_context) override {
326 Status error;
327 const int short_option = m_getopt_table[option_idx].val;
328 bool success;
329
330 switch (short_option) {
331 case 'C':
332 m_cascade = Args::StringToBoolean(option_arg, true, &success);
333 if (!success)
334 error.SetErrorStringWithFormat("invalid value for cascade: %s",
335 option_arg.str().c_str());
336 break;
337 case 'P':
338 handwrite_python = true;
339 break;
340 case 'l':
341 m_class_name = std::string(option_arg);
342 is_class_based = true;
343 break;
344 case 'p':
345 m_skip_pointers = true;
346 break;
347 case 'r':
348 m_skip_references = true;
349 break;
350 case 'w':
351 m_category = std::string(option_arg);
352 break;
353 case 'x':
354 m_regex = true;
355 break;
356 default:
357 error.SetErrorStringWithFormat("unrecognized option '%c'",
358 short_option);
359 break;
360 }
361
362 return error;
363 }
364
365 void OptionParsingStarting(ExecutionContext *execution_context) override {
366 m_cascade = true;
367 m_class_name = "";
368 m_skip_pointers = false;
369 m_skip_references = false;
370 m_category = "default";
371 is_class_based = false;
372 handwrite_python = false;
373 m_regex = false;
374 }
375
376 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
377 return llvm::makeArrayRef(g_type_synth_add_options);
378 }
379
380 // Instance variables to hold the values for command options.
381
382 bool m_cascade;
383 bool m_skip_references;
384 bool m_skip_pointers;
385 std::string m_class_name;
386 bool m_input_python;
387 std::string m_category;
388 bool is_class_based;
389 bool handwrite_python;
390 bool m_regex;
391 };
392
393 CommandOptions m_options;
394
395 Options *GetOptions() override { return &m_options; }
396
397 bool Execute_HandwritePython(Args &command, CommandReturnObject &result);
398
399 bool Execute_PythonClass(Args &command, CommandReturnObject &result);
400
401protected:
402 bool DoExecute(Args &command, CommandReturnObject &result) override {
403 WarnOnPotentialUnquotedUnsignedType(command, result);
404
405 if (m_options.handwrite_python)
406 return Execute_HandwritePython(command, result);
407 else if (m_options.is_class_based)
408 return Execute_PythonClass(command, result);
409 else {
410 result.AppendError("must either provide a children list, a Python class "
411 "name, or use -P and type a Python class "
412 "line-by-line");
413 result.SetStatus(eReturnStatusFailed);
414 return false;
415 }
416 }
417
418 void IOHandlerActivated(IOHandler &io_handler) override {
419 StreamFileSP output_sp(io_handler.GetOutputStreamFile());
420 if (output_sp) {
421 output_sp->PutCString(g_synth_addreader_instructions);
422 output_sp->Flush();
423 }
424 }
425
426 void IOHandlerInputComplete(IOHandler &io_handler,
427 std::string &data) override {
428 StreamFileSP error_sp = io_handler.GetErrorStreamFile();
429
430#ifndef LLDB_DISABLE_PYTHON
431 ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
432 if (interpreter) {
433 StringList lines;
434 lines.SplitIntoLines(data);
435 if (lines.GetSize() > 0) {
436 SynthAddOptions *options_ptr =
437 ((SynthAddOptions *)io_handler.GetUserData());
438 if (options_ptr) {
439 SynthAddOptions::SharedPointer options(
440 options_ptr); // this will ensure that we get rid of the pointer
441 // when going out of scope
442
443 ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
444 if (interpreter) {
445 std::string class_name_str;
446 if (interpreter->GenerateTypeSynthClass(lines, class_name_str)) {
447 if (class_name_str.empty()) {
448 error_sp->Printf(
449 "error: unable to obtain a proper name for the class.\n");
450 error_sp->Flush();
451 } else {
452 // everything should be fine now, let's add the synth provider
453 // class
454
455 SyntheticChildrenSP synth_provider;
456 synth_provider.reset(new ScriptedSyntheticChildren(
457 SyntheticChildren::Flags()
458 .SetCascades(options->m_cascade)
459 .SetSkipPointers(options->m_skip_pointers)
460 .SetSkipReferences(options->m_skip_references),
461 class_name_str.c_str()));
462
463 lldb::TypeCategoryImplSP category;
464 DataVisualization::Categories::GetCategory(
465 ConstString(options->m_category.c_str()), category);
466
467 Status error;
468
469 for (size_t i = 0; i < options->m_target_types.GetSize(); i++) {
470 const char *type_name =
471 options->m_target_types.GetStringAtIndex(i);
472 ConstString const_type_name(type_name);
473 if (const_type_name) {
474 if (!CommandObjectTypeSynthAdd::AddSynth(
475 const_type_name, synth_provider,
476 options->m_regex
477 ? CommandObjectTypeSynthAdd::eRegexSynth
478 : CommandObjectTypeSynthAdd::eRegularSynth,
479 options->m_category, &error)) {
480 error_sp->Printf("error: %s\n", error.AsCString());
481 error_sp->Flush();
482 break;
483 }
484 } else {
485 error_sp->Printf("error: invalid type name.\n");
486 error_sp->Flush();
487 break;
488 }
489 }
490 }
491 } else {
492 error_sp->Printf("error: unable to generate a class.\n");
493 error_sp->Flush();
494 }
495 } else {
496 error_sp->Printf("error: no script interpreter.\n");
497 error_sp->Flush();
498 }
499 } else {
500 error_sp->Printf("error: internal synchronization data missing.\n");
501 error_sp->Flush();
502 }
503 } else {
504 error_sp->Printf("error: empty function, didn't add python command.\n");
505 error_sp->Flush();
506 }
507 } else {
508 error_sp->Printf(
509 "error: script interpreter missing, didn't add python command.\n");
510 error_sp->Flush();
511 }
512
513#endif // LLDB_DISABLE_PYTHON
514 io_handler.SetIsDone(true);
515 }
516
517public:
518 enum SynthFormatType { eRegularSynth, eRegexSynth };
519
520 CommandObjectTypeSynthAdd(CommandInterpreter &interpreter);
521
522 ~CommandObjectTypeSynthAdd() override = default;
523
524 static bool AddSynth(ConstString type_name, lldb::SyntheticChildrenSP entry,
525 SynthFormatType type, std::string category_name,
526 Status *error);
527};
528
529//-------------------------------------------------------------------------
530// CommandObjectTypeFormatAdd
531//-------------------------------------------------------------------------
532
533static OptionDefinition g_type_format_add_options[] = {
534 // clang-format off
535 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "category", 'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "Add this to the given category instead of the default one." },
536 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "cascade", 'C', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, cascade through typedef chains." },
537 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "skip-pointers", 'p', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects." },
538 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "skip-references", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use this format for references-to-type objects." },
539 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "regex", 'x', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Type names are actually regular expressions." },
540 { LLDB_OPT_SET_2(1U << 1), false, "type", 't', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "Format variables as if they were of this type." }
541 // clang-format on
542};
543
544class CommandObjectTypeFormatAdd : public CommandObjectParsed {
545private:
546 class CommandOptions : public OptionGroup {
547 public:
548 CommandOptions() : OptionGroup() {}
549
550 ~CommandOptions() override = default;
551
552 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
553 return llvm::makeArrayRef(g_type_format_add_options);
554 }
555
556 void OptionParsingStarting(ExecutionContext *execution_context) override {
557 m_cascade = true;
558 m_skip_pointers = false;
559 m_skip_references = false;
560 m_regex = false;
561 m_category.assign("default");
562 m_custom_type_name.clear();
563 }
564
565 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
566 ExecutionContext *execution_context) override {
567 Status error;
568 const int short_option =
569 g_type_format_add_options[option_idx].short_option;
570 bool success;
571
572 switch (short_option) {
573 case 'C':
574 m_cascade = Args::StringToBoolean(option_value, true, &success);
575 if (!success)
576 error.SetErrorStringWithFormat("invalid value for cascade: %s",
577 option_value.str().c_str());
578 break;
579 case 'p':
580 m_skip_pointers = true;
581 break;
582 case 'w':
583 m_category.assign(option_value);
584 break;
585 case 'r':
586 m_skip_references = true;
587 break;
588 case 'x':
589 m_regex = true;
590 break;
591 case 't':
592 m_custom_type_name.assign(option_value);
593 break;
594 default:
595 error.SetErrorStringWithFormat("unrecognized option '%c'",
596 short_option);
597 break;
598 }
599
600 return error;
601 }
602
603 // Instance variables to hold the values for command options.
604
605 bool m_cascade;
606 bool m_skip_references;
607 bool m_skip_pointers;
608 bool m_regex;
609 std::string m_category;
610 std::string m_custom_type_name;
611 };
612
613 OptionGroupOptions m_option_group;
614 OptionGroupFormat m_format_options;
615 CommandOptions m_command_options;
616
617 Options *GetOptions() override { return &m_option_group; }
618
619public:
620 CommandObjectTypeFormatAdd(CommandInterpreter &interpreter)
621 : CommandObjectParsed(interpreter, "type format add",
622 "Add a new formatting style for a type.", nullptr),
623 m_option_group(), m_format_options(eFormatInvalid),
624 m_command_options() {
625 CommandArgumentEntry type_arg;
626 CommandArgumentData type_style_arg;
627
628 type_style_arg.arg_type = eArgTypeName;
629 type_style_arg.arg_repetition = eArgRepeatPlus;
630
631 type_arg.push_back(type_style_arg);
632
633 m_arguments.push_back(type_arg);
634
635 SetHelpLong(
636 R"(
637The following examples of 'type format add' refer to this code snippet for context:
638
639 typedef int Aint;
640 typedef float Afloat;
641 typedef Aint Bint;
642 typedef Afloat Bfloat;
643
644 Aint ix = 5;
645 Bint iy = 5;
646
647 Afloat fx = 3.14;
648 BFloat fy = 3.14;
649
650Adding default formatting:
651
652(lldb) type format add -f hex AInt
653(lldb) frame variable iy
654
655)"
656 " Produces hexadecimal display of iy, because no formatter is available for Bint and \
657the one for Aint is used instead."
658 R"(
659
660To prevent this use the cascade option '-C no' to prevent evaluation of typedef chains:
661
662
663(lldb) type format add -f hex -C no AInt
664
665Similar reasoning applies to this:
666
667(lldb) type format add -f hex -C no float -p
668
669)"
670 " All float values and float references are now formatted as hexadecimal, but not \
671pointers to floats. Nor will it change the default display for Afloat and Bfloat objects.");
672
673 // Add the "--format" to all options groups
674 m_option_group.Append(&m_format_options,
675 OptionGroupFormat::OPTION_GROUP_FORMAT,
676 LLDB_OPT_SET_1(1U << 0));
677 m_option_group.Append(&m_command_options);
678 m_option_group.Finalize();
679 }
680
681 ~CommandObjectTypeFormatAdd() override = default;
682
683protected:
684 bool DoExecute(Args &command, CommandReturnObject &result) override {
685 const size_t argc = command.GetArgumentCount();
686
687 if (argc < 1) {
1
Assuming 'argc' is >= 1
2
Taking false branch
688 result.AppendErrorWithFormat("%s takes one or more args.\n",
689 m_cmd_name.c_str());
690 result.SetStatus(eReturnStatusFailed);
691 return false;
692 }
693
694 const Format format = m_format_options.GetFormat();
695 if (format == eFormatInvalid &&
3
Assuming 'format' is not equal to eFormatInvalid
696 m_command_options.m_custom_type_name.empty()) {
697 result.AppendErrorWithFormat("%s needs a valid format.\n",
698 m_cmd_name.c_str());
699 result.SetStatus(eReturnStatusFailed);
700 return false;
701 }
702
703 TypeFormatImplSP entry;
704
705 if (m_command_options.m_custom_type_name.empty())
4
Assuming the condition is false
5
Taking false branch
706 entry.reset(new TypeFormatImpl_Format(
707 format, TypeFormatImpl::Flags()
708 .SetCascades(m_command_options.m_cascade)
709 .SetSkipPointers(m_command_options.m_skip_pointers)
710 .SetSkipReferences(m_command_options.m_skip_references)));
711 else
712 entry.reset(new TypeFormatImpl_EnumType(
713 ConstString(m_command_options.m_custom_type_name.c_str()),
714 TypeFormatImpl::Flags()
715 .SetCascades(m_command_options.m_cascade)
716 .SetSkipPointers(m_command_options.m_skip_pointers)
717 .SetSkipReferences(m_command_options.m_skip_references)));
718
719 // now I have a valid format, let's add it to every type
720
721 TypeCategoryImplSP category_sp;
722 DataVisualization::Categories::GetCategory(
723 ConstString(m_command_options.m_category), category_sp);
724 if (!category_sp)
6
Taking false branch
725 return false;
726
727 WarnOnPotentialUnquotedUnsignedType(command, result);
728
729 for (auto &arg_entry : command.entries()) {
7
Assuming '__begin' is not equal to '__end'
730 if (arg_entry.ref.empty()) {
8
Assuming the condition is false
9
Taking false branch
12
Assuming the condition is false
13
Taking false branch
15
Assuming the condition is false
16
Taking false branch
46
Assuming the condition is false
47
Taking false branch
731 result.AppendError("empty typenames not allowed");
732 result.SetStatus(eReturnStatusFailed);
733 return false;
734 }
735
736 ConstString typeCS(arg_entry.ref);
737 if (m_command_options.m_regex) {
10
Assuming the condition is false
11
Taking false branch
14
Taking false branch
17
Taking false branch
48
Taking false branch
738 RegularExpressionSP typeRX(new RegularExpression());
739 if (!typeRX->Compile(arg_entry.ref)) {
740 result.AppendError(
741 "regex format error (maybe this is not really a regex?)");
742 result.SetStatus(eReturnStatusFailed);
743 return false;
744 }
745 category_sp->GetRegexTypeSummariesContainer()->Delete(typeCS);
746 category_sp->GetRegexTypeFormatsContainer()->Add(typeRX, entry);
747 } else
748 category_sp->GetTypeFormatsContainer()->Add(typeCS, entry);
18
Calling 'FormattersContainer::Add'
45
Returning; memory was released
49
Calling 'FormattersContainer::Add'
749 }
750
751 result.SetStatus(eReturnStatusSuccessFinishNoResult);
752 return result.Succeeded();
753 }
754};
755
756static OptionDefinition g_type_formatter_delete_options[] = {
757 // clang-format off
758 { LLDB_OPT_SET_1(1U << 0), false, "all", 'a', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Delete from every category." },
759 { LLDB_OPT_SET_2(1U << 1), false, "category", 'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "Delete from given category." },
760 { LLDB_OPT_SET_3(1U << 2), false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Delete from given language's category." }
761 // clang-format on
762};
763
764class CommandObjectTypeFormatterDelete : public CommandObjectParsed {
765protected:
766 class CommandOptions : public Options {
767 public:
768 CommandOptions() : Options() {}
769
770 ~CommandOptions() override = default;
771
772 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
773 ExecutionContext *execution_context) override {
774 Status error;
775 const int short_option = m_getopt_table[option_idx].val;
776
777 switch (short_option) {
778 case 'a':
779 m_delete_all = true;
780 break;
781 case 'w':
782 m_category = std::string(option_arg);
783 break;
784 case 'l':
785 m_language = Language::GetLanguageTypeFromString(option_arg);
786 break;
787 default:
788 error.SetErrorStringWithFormat("unrecognized option '%c'",
789 short_option);
790 break;
791 }
792
793 return error;
794 }
795
796 void OptionParsingStarting(ExecutionContext *execution_context) override {
797 m_delete_all = false;
798 m_category = "default";
799 m_language = lldb::eLanguageTypeUnknown;
800 }
801
802 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
803 return llvm::makeArrayRef(g_type_formatter_delete_options);
804 }
805
806 // Instance variables to hold the values for command options.
807
808 bool m_delete_all;
809 std::string m_category;
810 lldb::LanguageType m_language;
811 };
812
813 CommandOptions m_options;
814 uint32_t m_formatter_kind_mask;
815
816 Options *GetOptions() override { return &m_options; }
817
818public:
819 CommandObjectTypeFormatterDelete(CommandInterpreter &interpreter,
820 uint32_t formatter_kind_mask,
821 const char *name, const char *help)
822 : CommandObjectParsed(interpreter, name, help, nullptr), m_options(),
823 m_formatter_kind_mask(formatter_kind_mask) {
824 CommandArgumentEntry type_arg;
825 CommandArgumentData type_style_arg;
826
827 type_style_arg.arg_type = eArgTypeName;
828 type_style_arg.arg_repetition = eArgRepeatPlain;
829
830 type_arg.push_back(type_style_arg);
831
832 m_arguments.push_back(type_arg);
833 }
834
835 ~CommandObjectTypeFormatterDelete() override = default;
836
837protected:
838 virtual bool FormatterSpecificDeletion(ConstString typeCS) { return false; }
839
840 bool DoExecute(Args &command, CommandReturnObject &result) override {
841 const size_t argc = command.GetArgumentCount();
842
843 if (argc != 1) {
844 result.AppendErrorWithFormat("%s takes 1 arg.\n", m_cmd_name.c_str());
845 result.SetStatus(eReturnStatusFailed);
846 return false;
847 }
848
849 const char *typeA = command.GetArgumentAtIndex(0);
850 ConstString typeCS(typeA);
851
852 if (!typeCS) {
853 result.AppendError("empty typenames not allowed");
854 result.SetStatus(eReturnStatusFailed);
855 return false;
856 }
857
858 if (m_options.m_delete_all) {
859 DataVisualization::Categories::ForEach(
860 [this, typeCS](const lldb::TypeCategoryImplSP &category_sp) -> bool {
861 category_sp->Delete(typeCS, m_formatter_kind_mask);
862 return true;
863 });
864 result.SetStatus(eReturnStatusSuccessFinishNoResult);
865 return result.Succeeded();
866 }
867
868 bool delete_category = false;
869 bool extra_deletion = false;
870
871 if (m_options.m_language != lldb::eLanguageTypeUnknown) {
872 lldb::TypeCategoryImplSP category;
873 DataVisualization::Categories::GetCategory(m_options.m_language,
874 category);
875 if (category)
876 delete_category = category->Delete(typeCS, m_formatter_kind_mask);
877 extra_deletion = FormatterSpecificDeletion(typeCS);
878 } else {
879 lldb::TypeCategoryImplSP category;
880 DataVisualization::Categories::GetCategory(
881 ConstString(m_options.m_category.c_str()), category);
882 if (category)
883 delete_category = category->Delete(typeCS, m_formatter_kind_mask);
884 extra_deletion = FormatterSpecificDeletion(typeCS);
885 }
886
887 if (delete_category || extra_deletion) {
888 result.SetStatus(eReturnStatusSuccessFinishNoResult);
889 return result.Succeeded();
890 } else {
891 result.AppendErrorWithFormat("no custom formatter for %s.\n", typeA);
892 result.SetStatus(eReturnStatusFailed);
893 return false;
894 }
895 }
896};
897
898static OptionDefinition g_type_formatter_clear_options[] = {
899 // clang-format off
900 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "all", 'a', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Clear every category." }
901 // clang-format on
902};
903
904class CommandObjectTypeFormatterClear : public CommandObjectParsed {
905private:
906 class CommandOptions : public Options {
907 public:
908 CommandOptions() : Options() {}
909
910 ~CommandOptions() override = default;
911
912 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
913 ExecutionContext *execution_context) override {
914 Status error;
915 const int short_option = m_getopt_table[option_idx].val;
916
917 switch (short_option) {
918 case 'a':
919 m_delete_all = true;
920 break;
921 default:
922 error.SetErrorStringWithFormat("unrecognized option '%c'",
923 short_option);
924 break;
925 }
926
927 return error;
928 }
929
930 void OptionParsingStarting(ExecutionContext *execution_context) override {
931 m_delete_all = false;
932 }
933
934 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
935 return llvm::makeArrayRef(g_type_formatter_clear_options);
936 }
937
938 // Instance variables to hold the values for command options.
939 bool m_delete_all;
940 };
941
942 CommandOptions m_options;
943 uint32_t m_formatter_kind_mask;
944
945 Options *GetOptions() override { return &m_options; }
946
947public:
948 CommandObjectTypeFormatterClear(CommandInterpreter &interpreter,
949 uint32_t formatter_kind_mask,
950 const char *name, const char *help)
951 : CommandObjectParsed(interpreter, name, help, nullptr), m_options(),
952 m_formatter_kind_mask(formatter_kind_mask) {}
953
954 ~CommandObjectTypeFormatterClear() override = default;
955
956protected:
957 virtual void FormatterSpecificDeletion() {}
958
959 bool DoExecute(Args &command, CommandReturnObject &result) override {
960 if (m_options.m_delete_all) {
961 DataVisualization::Categories::ForEach(
962 [this](const TypeCategoryImplSP &category_sp) -> bool {
963 category_sp->Clear(m_formatter_kind_mask);
964 return true;
965 });
966 } else {
967 lldb::TypeCategoryImplSP category;
968 if (command.GetArgumentCount() > 0) {
969 const char *cat_name = command.GetArgumentAtIndex(0);
970 ConstString cat_nameCS(cat_name);
971 DataVisualization::Categories::GetCategory(cat_nameCS, category);
972 } else {
973 DataVisualization::Categories::GetCategory(ConstString(nullptr),
974 category);
975 }
976 category->Clear(m_formatter_kind_mask);
977 }
978
979 FormatterSpecificDeletion();
980
981 result.SetStatus(eReturnStatusSuccessFinishResult);
982 return result.Succeeded();
983 }
984};
985
986//-------------------------------------------------------------------------
987// CommandObjectTypeFormatDelete
988//-------------------------------------------------------------------------
989
990class CommandObjectTypeFormatDelete : public CommandObjectTypeFormatterDelete {
991public:
992 CommandObjectTypeFormatDelete(CommandInterpreter &interpreter)
993 : CommandObjectTypeFormatterDelete(
994 interpreter,
995 eFormatCategoryItemValue | eFormatCategoryItemRegexValue,
996 "type format delete",
997 "Delete an existing formatting style for a type.") {}
998
999 ~CommandObjectTypeFormatDelete() override = default;
1000};
1001
1002//-------------------------------------------------------------------------
1003// CommandObjectTypeFormatClear
1004//-------------------------------------------------------------------------
1005
1006class CommandObjectTypeFormatClear : public CommandObjectTypeFormatterClear {
1007public:
1008 CommandObjectTypeFormatClear(CommandInterpreter &interpreter)
1009 : CommandObjectTypeFormatterClear(
1010 interpreter,
1011 eFormatCategoryItemValue | eFormatCategoryItemRegexValue,
1012 "type format clear", "Delete all existing format styles.") {}
1013};
1014
1015template <typename FormatterType>
1016class CommandObjectTypeFormatterList : public CommandObjectParsed {
1017 typedef typename FormatterType::SharedPointer FormatterSharedPointer;
1018
1019 class CommandOptions : public Options {
1020 public:
1021 CommandOptions()
1022 : Options(), m_category_regex("", ""),
1023 m_category_language(lldb::eLanguageTypeUnknown,
1024 lldb::eLanguageTypeUnknown) {}
1025
1026 ~CommandOptions() override = default;
1027
1028 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1029 ExecutionContext *execution_context) override {
1030 Status error;
1031 const int short_option = m_getopt_table[option_idx].val;
1032 switch (short_option) {
1033 case 'w':
1034 m_category_regex.SetCurrentValue(option_arg);
1035 m_category_regex.SetOptionWasSet();
1036 break;
1037 case 'l':
1038 error = m_category_language.SetValueFromString(option_arg);
1039 if (error.Success())
1040 m_category_language.SetOptionWasSet();
1041 break;
1042 default:
1043 error.SetErrorStringWithFormat("unrecognized option '%c'",
1044 short_option);
1045 break;
1046 }
1047
1048 return error;
1049 }
1050
1051 void OptionParsingStarting(ExecutionContext *execution_context) override {
1052 m_category_regex.Clear();
1053 m_category_language.Clear();
1054 }
1055
1056 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1057 static OptionDefinition g_option_table[] = {
1058 // clang-format off
1059 {LLDB_OPT_SET_1(1U << 0), false, "category-regex", 'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "Only show categories matching this filter."},
1060 {LLDB_OPT_SET_2(1U << 1), false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Only show the category for a specific language."}
1061 // clang-format on
1062 };
1063 return llvm::ArrayRef<OptionDefinition>(g_option_table);
1064 }
1065
1066 // Instance variables to hold the values for command options.
1067
1068 OptionValueString m_category_regex;
1069 OptionValueLanguage m_category_language;
1070 };
1071
1072 CommandOptions m_options;
1073
1074 Options *GetOptions() override { return &m_options; }
1075
1076public:
1077 CommandObjectTypeFormatterList(CommandInterpreter &interpreter,
1078 const char *name, const char *help)
1079 : CommandObjectParsed(interpreter, name, help, nullptr), m_options() {
1080 CommandArgumentEntry type_arg;
1081 CommandArgumentData type_style_arg;
1082
1083 type_style_arg.arg_type = eArgTypeName;
1084 type_style_arg.arg_repetition = eArgRepeatOptional;
1085
1086 type_arg.push_back(type_style_arg);
1087
1088 m_arguments.push_back(type_arg);
1089 }
1090
1091 ~CommandObjectTypeFormatterList() override = default;
1092
1093protected:
1094 virtual bool FormatterSpecificList(CommandReturnObject &result) {
1095 return false;
1096 }
1097
1098 bool DoExecute(Args &command, CommandReturnObject &result) override {
1099 const size_t argc = command.GetArgumentCount();
1100
1101 std::unique_ptr<RegularExpression> category_regex;
1102 std::unique_ptr<RegularExpression> formatter_regex;
1103
1104 if (m_options.m_category_regex.OptionWasSet()) {
1105 category_regex.reset(new RegularExpression());
1106 if (!category_regex->Compile(
1107 m_options.m_category_regex.GetCurrentValueAsRef())) {
1108 result.AppendErrorWithFormat(
1109 "syntax error in category regular expression '%s'",
1110 m_options.m_category_regex.GetCurrentValueAsRef().str().c_str());
1111 result.SetStatus(eReturnStatusFailed);
1112 return false;
1113 }
1114 }
1115
1116 if (argc == 1) {
1117 const char *arg = command.GetArgumentAtIndex(0);
1118 formatter_regex.reset(new RegularExpression());
1119 if (!formatter_regex->Compile(llvm::StringRef::withNullAsEmpty(arg))) {
1120 result.AppendErrorWithFormat("syntax error in regular expression '%s'",
1121 arg);
1122 result.SetStatus(eReturnStatusFailed);
1123 return false;
1124 }
1125 }
1126
1127 bool any_printed = false;
1128
1129 auto category_closure = [&result, &formatter_regex, &any_printed](
1130 const lldb::TypeCategoryImplSP &category) -> void {
1131 result.GetOutputStream().Printf(
1132 "-----------------------\nCategory: %s%s\n-----------------------\n",
1133 category->GetName(), category->IsEnabled() ? "" : " (disabled)");
1134
1135 TypeCategoryImpl::ForEachCallbacks<FormatterType> foreach;
1136 foreach
1137 .SetExact([&result, &formatter_regex, &any_printed](
1138 ConstString name,
1139 const FormatterSharedPointer &format_sp) -> bool {
1140 if (formatter_regex) {
1141 bool escape = true;
1142 if (name.GetStringRef() == formatter_regex->GetText()) {
1143 escape = false;
1144 } else if (formatter_regex->Execute(name.GetStringRef())) {
1145 escape = false;
1146 }
1147
1148 if (escape)
1149 return true;
1150 }
1151
1152 any_printed = true;
1153 result.GetOutputStream().Printf("%s: %s\n", name.AsCString(),
1154 format_sp->GetDescription().c_str());
1155 return true;
1156 });
1157
1158 foreach
1159 .SetWithRegex([&result, &formatter_regex, &any_printed](
1160 RegularExpressionSP regex_sp,
1161 const FormatterSharedPointer &format_sp) -> bool {
1162 if (formatter_regex) {
1163 bool escape = true;
1164 if (regex_sp->GetText() == formatter_regex->GetText()) {
1165 escape = false;
1166 } else if (formatter_regex->Execute(regex_sp->GetText())) {
1167 escape = false;
1168 }
1169
1170 if (escape)
1171 return true;
1172 }
1173
1174 any_printed = true;
1175 result.GetOutputStream().Printf("%s: %s\n",
1176 regex_sp->GetText().str().c_str(),
1177 format_sp->GetDescription().c_str());
1178 return true;
1179 });
1180
1181 category->ForEach(foreach);
1182 };
1183
1184 if (m_options.m_category_language.OptionWasSet()) {
1185 lldb::TypeCategoryImplSP category_sp;
1186 DataVisualization::Categories::GetCategory(
1187 m_options.m_category_language.GetCurrentValue(), category_sp);
1188 if (category_sp)
1189 category_closure(category_sp);
1190 } else {
1191 DataVisualization::Categories::ForEach(
1192 [&category_regex, &category_closure](
1193 const lldb::TypeCategoryImplSP &category) -> bool {
1194 if (category_regex) {
1195 bool escape = true;
1196 if (category->GetName() == category_regex->GetText()) {
1197 escape = false;
1198 } else if (category_regex->Execute(
1199 llvm::StringRef::withNullAsEmpty(
1200 category->GetName()))) {
1201 escape = false;
1202 }
1203
1204 if (escape)
1205 return true;
1206 }
1207
1208 category_closure(category);
1209
1210 return true;
1211 });
1212
1213 any_printed = FormatterSpecificList(result) | any_printed;
1214 }
1215
1216 if (any_printed)
1217 result.SetStatus(eReturnStatusSuccessFinishResult);
1218 else {
1219 result.GetOutputStream().PutCString("no matching results found.\n");
1220 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1221 }
1222 return result.Succeeded();
1223 }
1224};
1225
1226//-------------------------------------------------------------------------
1227// CommandObjectTypeFormatList
1228//-------------------------------------------------------------------------
1229
1230class CommandObjectTypeFormatList
1231 : public CommandObjectTypeFormatterList<TypeFormatImpl> {
1232public:
1233 CommandObjectTypeFormatList(CommandInterpreter &interpreter)
1234 : CommandObjectTypeFormatterList(interpreter, "type format list",
1235 "Show a list of current formats.") {}
1236};
1237
1238#ifndef LLDB_DISABLE_PYTHON
1239
1240//-------------------------------------------------------------------------
1241// CommandObjectTypeSummaryAdd
1242//-------------------------------------------------------------------------
1243
1244#endif // LLDB_DISABLE_PYTHON
1245
1246Status CommandObjectTypeSummaryAdd::CommandOptions::SetOptionValue(
1247 uint32_t option_idx, llvm::StringRef option_arg,
1248 ExecutionContext *execution_context) {
1249 Status error;
1250 const int short_option = m_getopt_table[option_idx].val;
1251 bool success;
1252
1253 switch (short_option) {
1254 case 'C':
1255 m_flags.SetCascades(Args::StringToBoolean(option_arg, true, &success));
1256 if (!success)
1257 error.SetErrorStringWithFormat("invalid value for cascade: %s",
1258 option_arg.str().c_str());
1259 break;
1260 case 'e':
1261 m_flags.SetDontShowChildren(false);
1262 break;
1263 case 'h':
1264 m_flags.SetHideEmptyAggregates(true);
1265 break;
1266 case 'v':
1267 m_flags.SetDontShowValue(true);
1268 break;
1269 case 'c':
1270 m_flags.SetShowMembersOneLiner(true);
1271 break;
1272 case 's':
1273 m_format_string = std::string(option_arg);
1274 break;
1275 case 'p':
1276 m_flags.SetSkipPointers(true);
1277 break;
1278 case 'r':
1279 m_flags.SetSkipReferences(true);
1280 break;
1281 case 'x':
1282 m_regex = true;
1283 break;
1284 case 'n':
1285 m_name.SetString(option_arg);
1286 break;
1287 case 'o':
1288 m_python_script = option_arg;
1289 m_is_add_script = true;
1290 break;
1291 case 'F':
1292 m_python_function = option_arg;
1293 m_is_add_script = true;
1294 break;
1295 case 'P':
1296 m_is_add_script = true;
1297 break;
1298 case 'w':
1299 m_category = std::string(option_arg);
1300 break;
1301 case 'O':
1302 m_flags.SetHideItemNames(true);
1303 break;
1304 default:
1305 error.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
1306 break;
1307 }
1308
1309 return error;
1310}
1311
1312void CommandObjectTypeSummaryAdd::CommandOptions::OptionParsingStarting(
1313 ExecutionContext *execution_context) {
1314 m_flags.Clear().SetCascades().SetDontShowChildren().SetDontShowValue(false);
1315 m_flags.SetShowMembersOneLiner(false)
1316 .SetSkipPointers(false)
1317 .SetSkipReferences(false)
1318 .SetHideItemNames(false);
1319
1320 m_regex = false;
1321 m_name.Clear();
1322 m_python_script = "";
1323 m_python_function = "";
1324 m_format_string = "";
1325 m_is_add_script = false;
1326 m_category = "default";
1327}
1328
1329#ifndef LLDB_DISABLE_PYTHON
1330
1331bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary(
1332 Args &command, CommandReturnObject &result) {
1333 const size_t argc = command.GetArgumentCount();
1334
1335 if (argc < 1 && !m_options.m_name) {
1336 result.AppendErrorWithFormat("%s takes one or more args.\n",
1337 m_cmd_name.c_str());
1338 result.SetStatus(eReturnStatusFailed);
1339 return false;
1340 }
1341
1342 TypeSummaryImplSP script_format;
1343
1344 if (!m_options.m_python_function
1345 .empty()) // we have a Python function ready to use
1346 {
1347 const char *funct_name = m_options.m_python_function.c_str();
1348 if (!funct_name || !funct_name[0]) {
1349 result.AppendError("function name empty.\n");
1350 result.SetStatus(eReturnStatusFailed);
1351 return false;
1352 }
1353
1354 std::string code =
1355 (" " + m_options.m_python_function + "(valobj,internal_dict)");
1356
1357 script_format.reset(
1358 new ScriptSummaryFormat(m_options.m_flags, funct_name, code.c_str()));
1359
1360 ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
1361
1362 if (interpreter && !interpreter->CheckObjectExists(funct_name))
1363 result.AppendWarningWithFormat(
1364 "The provided function \"%s\" does not exist - "
1365 "please define it before attempting to use this summary.\n",
1366 funct_name);
1367 } else if (!m_options.m_python_script
1368 .empty()) // we have a quick 1-line script, just use it
1369 {
1370 ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
1371 if (!interpreter) {
1372 result.AppendError("script interpreter missing - unable to generate "
1373 "function wrapper.\n");
1374 result.SetStatus(eReturnStatusFailed);
1375 return false;
1376 }
1377 StringList funct_sl;
1378 funct_sl << m_options.m_python_script.c_str();
1379 std::string funct_name_str;
1380 if (!interpreter->GenerateTypeScriptFunction(funct_sl, funct_name_str)) {
1381 result.AppendError("unable to generate function wrapper.\n");
1382 result.SetStatus(eReturnStatusFailed);
1383 return false;
1384 }
1385 if (funct_name_str.empty()) {
1386 result.AppendError(
1387 "script interpreter failed to generate a valid function name.\n");
1388 result.SetStatus(eReturnStatusFailed);
1389 return false;
1390 }
1391
1392 std::string code = " " + m_options.m_python_script;
1393
1394 script_format.reset(new ScriptSummaryFormat(
1395 m_options.m_flags, funct_name_str.c_str(), code.c_str()));
1396 } else {
1397 // Use an IOHandler to grab Python code from the user
1398 ScriptAddOptions *options =
1399 new ScriptAddOptions(m_options.m_flags, m_options.m_regex,
1400 m_options.m_name, m_options.m_category);
1401
1402 for (auto &entry : command.entries()) {
1403 if (entry.ref.empty()) {
1404 result.AppendError("empty typenames not allowed");
1405 result.SetStatus(eReturnStatusFailed);
1406 return false;
1407 }
1408
1409 options->m_target_types << entry.ref;
1410 }
1411
1412 m_interpreter.GetPythonCommandsFromIOHandler(
1413 " ", // Prompt
1414 *this, // IOHandlerDelegate
1415 true, // Run IOHandler in async mode
1416 options); // Baton for the "io_handler" that will be passed back into
1417 // our IOHandlerDelegate functions
1418 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1419
1420 return result.Succeeded();
1421 }
1422
1423 // if I am here, script_format must point to something good, so I can add that
1424 // as a script summary to all interested parties
1425
1426 Status error;
1427
1428 for (auto &entry : command.entries()) {
1429 CommandObjectTypeSummaryAdd::AddSummary(
1430 ConstString(entry.ref), script_format,
1431 (m_options.m_regex ? eRegexSummary : eRegularSummary),
1432 m_options.m_category, &error);
1433 if (error.Fail()) {
1434 result.AppendError(error.AsCString());
1435 result.SetStatus(eReturnStatusFailed);
1436 return false;
1437 }
1438 }
1439
1440 if (m_options.m_name) {
1441 AddSummary(m_options.m_name, script_format, eNamedSummary,
1442 m_options.m_category, &error);
1443 if (error.Fail()) {
1444 result.AppendError(error.AsCString());
1445 result.AppendError("added to types, but not given a name");
1446 result.SetStatus(eReturnStatusFailed);
1447 return false;
1448 }
1449 }
1450
1451 return result.Succeeded();
1452}
1453
1454#endif // LLDB_DISABLE_PYTHON
1455
1456bool CommandObjectTypeSummaryAdd::Execute_StringSummary(
1457 Args &command, CommandReturnObject &result) {
1458 const size_t argc = command.GetArgumentCount();
1459
1460 if (argc < 1 && !m_options.m_name) {
1461 result.AppendErrorWithFormat("%s takes one or more args.\n",
1462 m_cmd_name.c_str());
1463 result.SetStatus(eReturnStatusFailed);
1464 return false;
1465 }
1466
1467 if (!m_options.m_flags.GetShowMembersOneLiner() &&
1468 m_options.m_format_string.empty()) {
1469 result.AppendError("empty summary strings not allowed");
1470 result.SetStatus(eReturnStatusFailed);
1471 return false;
1472 }
1473
1474 const char *format_cstr = (m_options.m_flags.GetShowMembersOneLiner()
1475 ? ""
1476 : m_options.m_format_string.c_str());
1477
1478 // ${var%S} is an endless recursion, prevent it
1479 if (strcmp(format_cstr, "${var%S}") == 0) {
1480 result.AppendError("recursive summary not allowed");
1481 result.SetStatus(eReturnStatusFailed);
1482 return false;
1483 }
1484
1485 std::unique_ptr<StringSummaryFormat> string_format(
1486 new StringSummaryFormat(m_options.m_flags, format_cstr));
1487 if (!string_format) {
1488 result.AppendError("summary creation failed");
1489 result.SetStatus(eReturnStatusFailed);
1490 return false;
1491 }
1492 if (string_format->m_error.Fail()) {
1493 result.AppendErrorWithFormat("syntax error: %s",
1494 string_format->m_error.AsCString("<unknown>"));
1495 result.SetStatus(eReturnStatusFailed);
1496 return false;
1497 }
1498 lldb::TypeSummaryImplSP entry(string_format.release());
1499
1500 // now I have a valid format, let's add it to every type
1501 Status error;
1502 for (auto &arg_entry : command.entries()) {
1503 if (arg_entry.ref.empty()) {
1504 result.AppendError("empty typenames not allowed");
1505 result.SetStatus(eReturnStatusFailed);
1506 return false;
1507 }
1508 ConstString typeCS(arg_entry.ref);
1509
1510 AddSummary(typeCS, entry,
1511 (m_options.m_regex ? eRegexSummary : eRegularSummary),
1512 m_options.m_category, &error);
1513
1514 if (error.Fail()) {
1515 result.AppendError(error.AsCString());
1516 result.SetStatus(eReturnStatusFailed);
1517 return false;
1518 }
1519 }
1520
1521 if (m_options.m_name) {
1522 AddSummary(m_options.m_name, entry, eNamedSummary, m_options.m_category,
1523 &error);
1524 if (error.Fail()) {
1525 result.AppendError(error.AsCString());
1526 result.AppendError("added to types, but not given a name");
1527 result.SetStatus(eReturnStatusFailed);
1528 return false;
1529 }
1530 }
1531
1532 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1533 return result.Succeeded();
1534}
1535
1536CommandObjectTypeSummaryAdd::CommandObjectTypeSummaryAdd(
1537 CommandInterpreter &interpreter)
1538 : CommandObjectParsed(interpreter, "type summary add",
1539 "Add a new summary style for a type.", nullptr),
1540 IOHandlerDelegateMultiline("DONE"), m_options(interpreter) {
1541 CommandArgumentEntry type_arg;
1542 CommandArgumentData type_style_arg;
1543
1544 type_style_arg.arg_type = eArgTypeName;
1545 type_style_arg.arg_repetition = eArgRepeatPlus;
1546
1547 type_arg.push_back(type_style_arg);
1548
1549 m_arguments.push_back(type_arg);
1550
1551 SetHelpLong(
1552 R"(
1553The following examples of 'type summary add' refer to this code snippet for context:
1554
1555 struct JustADemo
1556 {
1557 int* ptr;
1558 float value;
1559 JustADemo(int p = 1, float v = 0.1) : ptr(new int(p)), value(v) {}
1560 };
1561 JustADemo demo_instance(42, 3.14);
1562
1563 typedef JustADemo NewDemo;
1564 NewDemo new_demo_instance(42, 3.14);
1565
1566(lldb) type summary add --summary-string "the answer is ${*var.ptr}" JustADemo
1567
1568 Subsequently displaying demo_instance with 'frame variable' or 'expression' will display "the answer is 42"
1569
1570(lldb) type summary add --summary-string "the answer is ${*var.ptr}, and the question is ${var.value}" JustADemo
1571
1572 Subsequently displaying demo_instance with 'frame variable' or 'expression' will display "the answer is 42 and the question is 3.14"
1573
1574)"
1575 "Alternatively, you could define formatting for all pointers to integers and \
1576rely on that when formatting JustADemo to obtain the same result:"
1577 R"(
1578
1579(lldb) type summary add --summary-string "${var%V} -> ${*var}" "int *"
1580(lldb) type summary add --summary-string "the answer is ${var.ptr}, and the question is ${var.value}" JustADemo
1581
1582)"
1583 "Type summaries are automatically applied to derived typedefs, so the examples \
1584above apply to both JustADemo and NewDemo. The cascade option can be used to \
1585suppress this behavior:"
1586 R"(
1587
1588(lldb) type summary add --summary-string "${var.ptr}, ${var.value},{${var.byte}}" JustADemo -C no
1589
1590 The summary will now be used for values of JustADemo but not NewDemo.
1591
1592)"
1593 "By default summaries are shown for pointers and references to values of the \
1594specified type. To suppress formatting for pointers use the -p option, or apply \
1595the corresponding -r option to suppress formatting for references:"
1596 R"(
1597
1598(lldb) type summary add -p -r --summary-string "${var.ptr}, ${var.value},{${var.byte}}" JustADemo
1599
1600)"
1601 "One-line summaries including all fields in a type can be inferred without supplying an \
1602explicit summary string by passing the -c option:"
1603 R"(
1604
1605(lldb) type summary add -c JustADemo
1606(lldb) frame variable demo_instance
1607(ptr=<address>, value=3.14)
1608
1609)"
1610 "Type summaries normally suppress the nested display of individual fields. To \
1611supply a summary to supplement the default structure add the -e option:"
1612 R"(
1613
1614(lldb) type summary add -e --summary-string "*ptr = ${*var.ptr}" JustADemo
1615
1616)"
1617 "Now when displaying JustADemo values the int* is displayed, followed by the \
1618standard LLDB sequence of children, one per line:"
1619 R"(
1620
1621*ptr = 42 {
1622 ptr = <address>
1623 value = 3.14
1624}
1625
1626)"
1627 "You can also add summaries written in Python. These scripts use lldb public API to \
1628gather information from your variables and produce a meaningful summary. To start a \
1629multi-line script use the -P option. The function declaration will be displayed along with \
1630a comment describing the two arguments. End your script with the word 'DONE' on a line by \
1631itself:"
1632 R"(
1633
1634(lldb) type summary add JustADemo -P
1635def function (valobj,internal_dict):
1636"""valobj: an SBValue which you want to provide a summary for
1637internal_dict: an LLDB support object not to be used"""
1638 value = valobj.GetChildMemberWithName('value');
1639 return 'My value is ' + value.GetValue();
1640 DONE
1641
1642Alternatively, the -o option can be used when providing a simple one-line Python script:
1643
1644(lldb) type summary add JustADemo -o "value = valobj.GetChildMemberWithName('value'); return 'My value is ' + value.GetValue();")");
1645}
1646
1647bool CommandObjectTypeSummaryAdd::DoExecute(Args &command,
1648 CommandReturnObject &result) {
1649 WarnOnPotentialUnquotedUnsignedType(command, result);
1650
1651 if (m_options.m_is_add_script) {
1652#ifndef LLDB_DISABLE_PYTHON
1653 return Execute_ScriptSummary(command, result);
1654#else
1655 result.AppendError("python is disabled");
1656 result.SetStatus(eReturnStatusFailed);
1657 return false;
1658#endif // LLDB_DISABLE_PYTHON
1659 }
1660
1661 return Execute_StringSummary(command, result);
1662}
1663
1664static bool FixArrayTypeNameWithRegex(ConstString &type_name) {
1665 llvm::StringRef type_name_ref(type_name.GetStringRef());
1666
1667 if (type_name_ref.endswith("[]")) {
1668 std::string type_name_str(type_name.GetCString());
1669 type_name_str.resize(type_name_str.length() - 2);
1670 if (type_name_str.back() != ' ')
1671 type_name_str.append(" \\[[0-9]+\\]");
1672 else
1673 type_name_str.append("\\[[0-9]+\\]");
1674 type_name.SetCString(type_name_str.c_str());
1675 return true;
1676 }
1677 return false;
1678}
1679
1680bool CommandObjectTypeSummaryAdd::AddSummary(ConstString type_name,
1681 TypeSummaryImplSP entry,
1682 SummaryFormatType type,
1683 std::string category_name,
1684 Status *error) {
1685 lldb::TypeCategoryImplSP category;
1686 DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()),
1687 category);
1688
1689 if (type == eRegularSummary) {
1690 if (FixArrayTypeNameWithRegex(type_name))
1691 type = eRegexSummary;
1692 }
1693
1694 if (type == eRegexSummary) {
1695 RegularExpressionSP typeRX(new RegularExpression());
1696 if (!typeRX->Compile(type_name.GetStringRef())) {
1697 if (error)
1698 error->SetErrorString(
1699 "regex format error (maybe this is not really a regex?)");
1700 return false;
1701 }
1702
1703 category->GetRegexTypeSummariesContainer()->Delete(type_name);
1704 category->GetRegexTypeSummariesContainer()->Add(typeRX, entry);
1705
1706 return true;
1707 } else if (type == eNamedSummary) {
1708 // system named summaries do not exist (yet?)
1709 DataVisualization::NamedSummaryFormats::Add(type_name, entry);
1710 return true;
1711 } else {
1712 category->GetTypeSummariesContainer()->Add(type_name, entry);
1713 return true;
1714 }
1715}
1716
1717//-------------------------------------------------------------------------
1718// CommandObjectTypeSummaryDelete
1719//-------------------------------------------------------------------------
1720
1721class CommandObjectTypeSummaryDelete : public CommandObjectTypeFormatterDelete {
1722public:
1723 CommandObjectTypeSummaryDelete(CommandInterpreter &interpreter)
1724 : CommandObjectTypeFormatterDelete(
1725 interpreter,
1726 eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary,
1727 "type summary delete", "Delete an existing summary for a type.") {}
1728
1729 ~CommandObjectTypeSummaryDelete() override = default;
1730
1731protected:
1732 bool FormatterSpecificDeletion(ConstString typeCS) override {
1733 if (m_options.m_language != lldb::eLanguageTypeUnknown)
1734 return false;
1735 return DataVisualization::NamedSummaryFormats::Delete(typeCS);
1736 }
1737};
1738
1739class CommandObjectTypeSummaryClear : public CommandObjectTypeFormatterClear {
1740public:
1741 CommandObjectTypeSummaryClear(CommandInterpreter &interpreter)
1742 : CommandObjectTypeFormatterClear(
1743 interpreter,
1744 eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary,
1745 "type summary clear", "Delete all existing summaries.") {}
1746
1747protected:
1748 void FormatterSpecificDeletion() override {
1749 DataVisualization::NamedSummaryFormats::Clear();
1750 }
1751};
1752
1753//-------------------------------------------------------------------------
1754// CommandObjectTypeSummaryList
1755//-------------------------------------------------------------------------
1756
1757class CommandObjectTypeSummaryList
1758 : public CommandObjectTypeFormatterList<TypeSummaryImpl> {
1759public:
1760 CommandObjectTypeSummaryList(CommandInterpreter &interpreter)
1761 : CommandObjectTypeFormatterList(interpreter, "type summary list",
1762 "Show a list of current summaries.") {}
1763
1764protected:
1765 bool FormatterSpecificList(CommandReturnObject &result) override {
1766 if (DataVisualization::NamedSummaryFormats::GetCount() > 0) {
1767 result.GetOutputStream().Printf("Named summaries:\n");
1768 DataVisualization::NamedSummaryFormats::ForEach(
1769 [&result](ConstString name,
1770 const TypeSummaryImplSP &summary_sp) -> bool {
1771 result.GetOutputStream().Printf(
1772 "%s: %s\n", name.AsCString(),
1773 summary_sp->GetDescription().c_str());
1774 return true;
1775 });
1776 return true;
1777 }
1778 return false;
1779 }
1780};
1781
1782//-------------------------------------------------------------------------
1783// CommandObjectTypeCategoryDefine
1784//-------------------------------------------------------------------------
1785
1786static OptionDefinition g_type_category_define_options[] = {
1787 // clang-format off
1788 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "enabled", 'e', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "If specified, this category will be created enabled." },
1789 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Specify the language that this category is supported for." }
1790 // clang-format on
1791};
1792
1793class CommandObjectTypeCategoryDefine : public CommandObjectParsed {
1794 class CommandOptions : public Options {
1795 public:
1796 CommandOptions()
1797 : Options(), m_define_enabled(false, false),
1798 m_cate_language(eLanguageTypeUnknown, eLanguageTypeUnknown) {}
1799
1800 ~CommandOptions() override = default;
1801
1802 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1803 ExecutionContext *execution_context) override {
1804 Status error;
1805 const int short_option = m_getopt_table[option_idx].val;
1806
1807 switch (short_option) {
1808 case 'e':
1809 m_define_enabled.SetValueFromString(llvm::StringRef("true"));
1810 break;
1811 case 'l':
1812 error = m_cate_language.SetValueFromString(option_arg);
1813 break;
1814 default:
1815 error.SetErrorStringWithFormat("unrecognized option '%c'",
1816 short_option);
1817 break;
1818 }
1819
1820 return error;
1821 }
1822
1823 void OptionParsingStarting(ExecutionContext *execution_context) override {
1824 m_define_enabled.Clear();
1825 m_cate_language.Clear();
1826 }
1827
1828 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1829 return llvm::makeArrayRef(g_type_category_define_options);
1830 }
1831
1832 // Instance variables to hold the values for command options.
1833
1834 OptionValueBoolean m_define_enabled;
1835 OptionValueLanguage m_cate_language;
1836 };
1837
1838 CommandOptions m_options;
1839
1840 Options *GetOptions() override { return &m_options; }
1841
1842public:
1843 CommandObjectTypeCategoryDefine(CommandInterpreter &interpreter)
1844 : CommandObjectParsed(interpreter, "type category define",
1845 "Define a new category as a source of formatters.",
1846 nullptr),
1847 m_options() {
1848 CommandArgumentEntry type_arg;
1849 CommandArgumentData type_style_arg;
1850
1851 type_style_arg.arg_type = eArgTypeName;
1852 type_style_arg.arg_repetition = eArgRepeatPlus;
1853
1854 type_arg.push_back(type_style_arg);
1855
1856 m_arguments.push_back(type_arg);
1857 }
1858
1859 ~CommandObjectTypeCategoryDefine() override = default;
1860
1861protected:
1862 bool DoExecute(Args &command, CommandReturnObject &result) override {
1863 const size_t argc = command.GetArgumentCount();
1864
1865 if (argc < 1) {
1866 result.AppendErrorWithFormat("%s takes 1 or more args.\n",
1867 m_cmd_name.c_str());
1868 result.SetStatus(eReturnStatusFailed);
1869 return false;
1870 }
1871
1872 for (auto &entry : command.entries()) {
1873 TypeCategoryImplSP category_sp;
1874 if (DataVisualization::Categories::GetCategory(ConstString(entry.ref),
1875 category_sp) &&
1876 category_sp) {
1877 category_sp->AddLanguage(m_options.m_cate_language.GetCurrentValue());
1878 if (m_options.m_define_enabled.GetCurrentValue())
1879 DataVisualization::Categories::Enable(category_sp,
1880 TypeCategoryMap::Default);
1881 }
1882 }
1883
1884 result.SetStatus(eReturnStatusSuccessFinishResult);
1885 return result.Succeeded();
1886 }
1887};
1888
1889//-------------------------------------------------------------------------
1890// CommandObjectTypeCategoryEnable
1891//-------------------------------------------------------------------------
1892
1893static OptionDefinition g_type_category_enable_options[] = {
1894 // clang-format off
1895 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Enable the category for this language." },
1896 // clang-format on
1897};
1898
1899class CommandObjectTypeCategoryEnable : public CommandObjectParsed {
1900 class CommandOptions : public Options {
1901 public:
1902 CommandOptions() : Options() {}
1903
1904 ~CommandOptions() override = default;
1905
1906 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1907 ExecutionContext *execution_context) override {
1908 Status error;
1909 const int short_option = m_getopt_table[option_idx].val;
1910
1911 switch (short_option) {
1912 case 'l':
1913 if (!option_arg.empty()) {
1914 m_language = Language::GetLanguageTypeFromString(option_arg);
1915 if (m_language == lldb::eLanguageTypeUnknown)
1916 error.SetErrorStringWithFormat("unrecognized language '%s'",
1917 option_arg.str().c_str());
1918 }
1919 break;
1920 default:
1921 error.SetErrorStringWithFormat("unrecognized option '%c'",
1922 short_option);
1923 break;
1924 }
1925
1926 return error;
1927 }
1928
1929 void OptionParsingStarting(ExecutionContext *execution_context) override {
1930 m_language = lldb::eLanguageTypeUnknown;
1931 }
1932
1933 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1934 return llvm::makeArrayRef(g_type_category_enable_options);
1935 }
1936
1937 // Instance variables to hold the values for command options.
1938
1939 lldb::LanguageType m_language;
1940 };
1941
1942 CommandOptions m_options;
1943
1944 Options *GetOptions() override { return &m_options; }
1945
1946public:
1947 CommandObjectTypeCategoryEnable(CommandInterpreter &interpreter)
1948 : CommandObjectParsed(interpreter, "type category enable",
1949 "Enable a category as a source of formatters.",
1950 nullptr),
1951 m_options() {
1952 CommandArgumentEntry type_arg;
1953 CommandArgumentData type_style_arg;
1954
1955 type_style_arg.arg_type = eArgTypeName;
1956 type_style_arg.arg_repetition = eArgRepeatPlus;
1957
1958 type_arg.push_back(type_style_arg);
1959
1960 m_arguments.push_back(type_arg);
1961 }
1962
1963 ~CommandObjectTypeCategoryEnable() override = default;
1964
1965protected:
1966 bool DoExecute(Args &command, CommandReturnObject &result) override {
1967 const size_t argc = command.GetArgumentCount();
1968
1969 if (argc < 1 && m_options.m_language == lldb::eLanguageTypeUnknown) {
1970 result.AppendErrorWithFormat("%s takes arguments and/or a language",
1971 m_cmd_name.c_str());
1972 result.SetStatus(eReturnStatusFailed);
1973 return false;
1974 }
1975
1976 if (argc == 1 && strcmp(command.GetArgumentAtIndex(0), "*") == 0) {
1977 DataVisualization::Categories::EnableStar();
1978 } else if (argc > 0) {
1979 for (int i = argc - 1; i >= 0; i--) {
1980 const char *typeA = command.GetArgumentAtIndex(i);
1981 ConstString typeCS(typeA);
1982
1983 if (!typeCS) {
1984 result.AppendError("empty category name not allowed");
1985 result.SetStatus(eReturnStatusFailed);
1986 return false;
1987 }
1988 DataVisualization::Categories::Enable(typeCS);
1989 lldb::TypeCategoryImplSP cate;
1990 if (DataVisualization::Categories::GetCategory(typeCS, cate) && cate) {
1991 if (cate->GetCount() == 0) {
1992 result.AppendWarning("empty category enabled (typo?)");
1993 }
1994 }
1995 }
1996 }
1997
1998 if (m_options.m_language != lldb::eLanguageTypeUnknown)
1999 DataVisualization::Categories::Enable(m_options.m_language);
2000
2001 result.SetStatus(eReturnStatusSuccessFinishResult);
2002 return result.Succeeded();
2003 }
2004};
2005
2006//-------------------------------------------------------------------------
2007// CommandObjectTypeCategoryDelete
2008//-------------------------------------------------------------------------
2009
2010class CommandObjectTypeCategoryDelete : public CommandObjectParsed {
2011public:
2012 CommandObjectTypeCategoryDelete(CommandInterpreter &interpreter)
2013 : CommandObjectParsed(interpreter, "type category delete",
2014 "Delete a category and all associated formatters.",
2015 nullptr) {
2016 CommandArgumentEntry type_arg;
2017 CommandArgumentData type_style_arg;
2018
2019 type_style_arg.arg_type = eArgTypeName;
2020 type_style_arg.arg_repetition = eArgRepeatPlus;
2021
2022 type_arg.push_back(type_style_arg);
2023
2024 m_arguments.push_back(type_arg);
2025 }
2026
2027 ~CommandObjectTypeCategoryDelete() override = default;
2028
2029protected:
2030 bool DoExecute(Args &command, CommandReturnObject &result) override {
2031 const size_t argc = command.GetArgumentCount();
2032
2033 if (argc < 1) {
2034 result.AppendErrorWithFormat("%s takes 1 or more arg.\n",
2035 m_cmd_name.c_str());
2036 result.SetStatus(eReturnStatusFailed);
2037 return false;
2038 }
2039
2040 bool success = true;
2041
2042 // the order is not relevant here
2043 for (int i = argc - 1; i >= 0; i--) {
2044 const char *typeA = command.GetArgumentAtIndex(i);
2045 ConstString typeCS(typeA);
2046
2047 if (!typeCS) {
2048 result.AppendError("empty category name not allowed");
2049 result.SetStatus(eReturnStatusFailed);
2050 return false;
2051 }
2052 if (!DataVisualization::Categories::Delete(typeCS))
2053 success = false; // keep deleting even if we hit an error
2054 }
2055 if (success) {
2056 result.SetStatus(eReturnStatusSuccessFinishResult);
2057 return result.Succeeded();
2058 } else {
2059 result.AppendError("cannot delete one or more categories\n");
2060 result.SetStatus(eReturnStatusFailed);
2061 return false;
2062 }
2063 }
2064};
2065
2066//-------------------------------------------------------------------------
2067// CommandObjectTypeCategoryDisable
2068//-------------------------------------------------------------------------
2069
2070OptionDefinition g_type_category_disable_options[] = {
2071 // clang-format off
2072 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Enable the category for this language." }
2073 // clang-format on
2074};
2075
2076class CommandObjectTypeCategoryDisable : public CommandObjectParsed {
2077 class CommandOptions : public Options {
2078 public:
2079 CommandOptions() : Options() {}
2080
2081 ~CommandOptions() override = default;
2082
2083 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2084 ExecutionContext *execution_context) override {
2085 Status error;
2086 const int short_option = m_getopt_table[option_idx].val;
2087
2088 switch (short_option) {
2089 case 'l':
2090 if (!option_arg.empty()) {
2091 m_language = Language::GetLanguageTypeFromString(option_arg);
2092 if (m_language == lldb::eLanguageTypeUnknown)
2093 error.SetErrorStringWithFormat("unrecognized language '%s'",
2094 option_arg.str().c_str());
2095 }
2096 break;
2097 default:
2098 error.SetErrorStringWithFormat("unrecognized option '%c'",
2099 short_option);
2100 break;
2101 }
2102
2103 return error;
2104 }
2105
2106 void OptionParsingStarting(ExecutionContext *execution_context) override {
2107 m_language = lldb::eLanguageTypeUnknown;
2108 }
2109
2110 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2111 return llvm::makeArrayRef(g_type_category_disable_options);
2112 }
2113
2114 // Instance variables to hold the values for command options.
2115
2116 lldb::LanguageType m_language;
2117 };
2118
2119 CommandOptions m_options;
2120
2121 Options *GetOptions() override { return &m_options; }
2122
2123public:
2124 CommandObjectTypeCategoryDisable(CommandInterpreter &interpreter)
2125 : CommandObjectParsed(interpreter, "type category disable",
2126 "Disable a category as a source of formatters.",
2127 nullptr),
2128 m_options() {
2129 CommandArgumentEntry type_arg;
2130 CommandArgumentData type_style_arg;
2131
2132 type_style_arg.arg_type = eArgTypeName;
2133 type_style_arg.arg_repetition = eArgRepeatPlus;
2134
2135 type_arg.push_back(type_style_arg);
2136
2137 m_arguments.push_back(type_arg);
2138 }
2139
2140 ~CommandObjectTypeCategoryDisable() override = default;
2141
2142protected:
2143 bool DoExecute(Args &command, CommandReturnObject &result) override {
2144 const size_t argc = command.GetArgumentCount();
2145
2146 if (argc < 1 && m_options.m_language == lldb::eLanguageTypeUnknown) {
2147 result.AppendErrorWithFormat("%s takes arguments and/or a language",
2148 m_cmd_name.c_str());
2149 result.SetStatus(eReturnStatusFailed);
2150 return false;
2151 }
2152
2153 if (argc == 1 && strcmp(command.GetArgumentAtIndex(0), "*") == 0) {
2154 DataVisualization::Categories::DisableStar();
2155 } else if (argc > 0) {
2156 // the order is not relevant here
2157 for (int i = argc - 1; i >= 0; i--) {
2158 const char *typeA = command.GetArgumentAtIndex(i);
2159 ConstString typeCS(typeA);
2160
2161 if (!typeCS) {
2162 result.AppendError("empty category name not allowed");
2163 result.SetStatus(eReturnStatusFailed);
2164 return false;
2165 }
2166 DataVisualization::Categories::Disable(typeCS);
2167 }
2168 }
2169
2170 if (m_options.m_language != lldb::eLanguageTypeUnknown)
2171 DataVisualization::Categories::Disable(m_options.m_language);
2172
2173 result.SetStatus(eReturnStatusSuccessFinishResult);
2174 return result.Succeeded();
2175 }
2176};
2177
2178//-------------------------------------------------------------------------
2179// CommandObjectTypeCategoryList
2180//-------------------------------------------------------------------------
2181
2182class CommandObjectTypeCategoryList : public CommandObjectParsed {
2183public:
2184 CommandObjectTypeCategoryList(CommandInterpreter &interpreter)
2185 : CommandObjectParsed(interpreter, "type category list",
2186 "Provide a list of all existing categories.",
2187 nullptr) {
2188 CommandArgumentEntry type_arg;
2189 CommandArgumentData type_style_arg;
2190
2191 type_style_arg.arg_type = eArgTypeName;
2192 type_style_arg.arg_repetition = eArgRepeatOptional;
2193
2194 type_arg.push_back(type_style_arg);
2195
2196 m_arguments.push_back(type_arg);
2197 }
2198
2199 ~CommandObjectTypeCategoryList() override = default;
2200
2201protected:
2202 bool DoExecute(Args &command, CommandReturnObject &result) override {
2203 const size_t argc = command.GetArgumentCount();
2204
2205 std::unique_ptr<RegularExpression> regex;
2206
2207 if (argc == 1) {
2208 regex.reset(new RegularExpression());
2209 const char *arg = command.GetArgumentAtIndex(0);
2210 if (!regex->Compile(llvm::StringRef::withNullAsEmpty(arg))) {
2211 result.AppendErrorWithFormat(
2212 "syntax error in category regular expression '%s'", arg);
2213 result.SetStatus(eReturnStatusFailed);
2214 return false;
2215 }
2216 } else if (argc != 0) {
2217 result.AppendErrorWithFormat("%s takes 0 or one arg.\n",
2218 m_cmd_name.c_str());
2219 result.SetStatus(eReturnStatusFailed);
2220 return false;
2221 }
2222
2223 DataVisualization::Categories::ForEach(
2224 [&regex, &result](const lldb::TypeCategoryImplSP &category_sp) -> bool {
2225 if (regex) {
2226 bool escape = true;
2227 if (regex->GetText() == category_sp->GetName()) {
2228 escape = false;
2229 } else if (regex->Execute(llvm::StringRef::withNullAsEmpty(
2230 category_sp->GetName()))) {
2231 escape = false;
2232 }
2233
2234 if (escape)
2235 return true;
2236 }
2237
2238 result.GetOutputStream().Printf(
2239 "Category: %s\n", category_sp->GetDescription().c_str());
2240
2241 return true;
2242 });
2243
2244 result.SetStatus(eReturnStatusSuccessFinishResult);
2245 return result.Succeeded();
2246 }
2247};
2248
2249//-------------------------------------------------------------------------
2250// CommandObjectTypeFilterList
2251//-------------------------------------------------------------------------
2252
2253class CommandObjectTypeFilterList
2254 : public CommandObjectTypeFormatterList<TypeFilterImpl> {
2255public:
2256 CommandObjectTypeFilterList(CommandInterpreter &interpreter)
2257 : CommandObjectTypeFormatterList(interpreter, "type filter list",
2258 "Show a list of current filters.") {}
2259};
2260
2261#ifndef LLDB_DISABLE_PYTHON
2262
2263//-------------------------------------------------------------------------
2264// CommandObjectTypeSynthList
2265//-------------------------------------------------------------------------
2266
2267class CommandObjectTypeSynthList
2268 : public CommandObjectTypeFormatterList<SyntheticChildren> {
2269public:
2270 CommandObjectTypeSynthList(CommandInterpreter &interpreter)
2271 : CommandObjectTypeFormatterList(
2272 interpreter, "type synthetic list",
2273 "Show a list of current synthetic providers.") {}
2274};
2275
2276#endif // LLDB_DISABLE_PYTHON
2277
2278//-------------------------------------------------------------------------
2279// CommandObjectTypeFilterDelete
2280//-------------------------------------------------------------------------
2281
2282class CommandObjectTypeFilterDelete : public CommandObjectTypeFormatterDelete {
2283public:
2284 CommandObjectTypeFilterDelete(CommandInterpreter &interpreter)
2285 : CommandObjectTypeFormatterDelete(
2286 interpreter,
2287 eFormatCategoryItemFilter | eFormatCategoryItemRegexFilter,
2288 "type filter delete", "Delete an existing filter for a type.") {}
2289
2290 ~CommandObjectTypeFilterDelete() override = default;
2291};
2292
2293#ifndef LLDB_DISABLE_PYTHON
2294
2295//-------------------------------------------------------------------------
2296// CommandObjectTypeSynthDelete
2297//-------------------------------------------------------------------------
2298
2299class CommandObjectTypeSynthDelete : public CommandObjectTypeFormatterDelete {
2300public:
2301 CommandObjectTypeSynthDelete(CommandInterpreter &interpreter)
2302 : CommandObjectTypeFormatterDelete(
2303 interpreter,
2304 eFormatCategoryItemSynth | eFormatCategoryItemRegexSynth,
2305 "type synthetic delete",
2306 "Delete an existing synthetic provider for a type.") {}
2307
2308 ~CommandObjectTypeSynthDelete() override = default;
2309};
2310
2311#endif // LLDB_DISABLE_PYTHON
2312
2313//-------------------------------------------------------------------------
2314// CommandObjectTypeFilterClear
2315//-------------------------------------------------------------------------
2316
2317class CommandObjectTypeFilterClear : public CommandObjectTypeFormatterClear {
2318public:
2319 CommandObjectTypeFilterClear(CommandInterpreter &interpreter)
2320 : CommandObjectTypeFormatterClear(
2321 interpreter,
2322 eFormatCategoryItemFilter | eFormatCategoryItemRegexFilter,
2323 "type filter clear", "Delete all existing filter.") {}
2324};
2325
2326#ifndef LLDB_DISABLE_PYTHON
2327//-------------------------------------------------------------------------
2328// CommandObjectTypeSynthClear
2329//-------------------------------------------------------------------------
2330
2331class CommandObjectTypeSynthClear : public CommandObjectTypeFormatterClear {
2332public:
2333 CommandObjectTypeSynthClear(CommandInterpreter &interpreter)
2334 : CommandObjectTypeFormatterClear(
2335 interpreter,
2336 eFormatCategoryItemSynth | eFormatCategoryItemRegexSynth,
2337 "type synthetic clear",
2338 "Delete all existing synthetic providers.") {}
2339};
2340
2341bool CommandObjectTypeSynthAdd::Execute_HandwritePython(
2342 Args &command, CommandReturnObject &result) {
2343 SynthAddOptions *options = new SynthAddOptions(
2344 m_options.m_skip_pointers, m_options.m_skip_references,
2345 m_options.m_cascade, m_options.m_regex, m_options.m_category);
2346
2347 for (auto &entry : command.entries()) {
2348 if (entry.ref.empty()) {
2349 result.AppendError("empty typenames not allowed");
2350 result.SetStatus(eReturnStatusFailed);
2351 return false;
2352 }
2353
2354 options->m_target_types << entry.ref;
2355 }
2356
2357 m_interpreter.GetPythonCommandsFromIOHandler(
2358 " ", // Prompt
2359 *this, // IOHandlerDelegate
2360 true, // Run IOHandler in async mode
2361 options); // Baton for the "io_handler" that will be passed back into our
2362 // IOHandlerDelegate functions
2363 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2364 return result.Succeeded();
2365}
2366
2367bool CommandObjectTypeSynthAdd::Execute_PythonClass(
2368 Args &command, CommandReturnObject &result) {
2369 const size_t argc = command.GetArgumentCount();
2370
2371 if (argc < 1) {
2372 result.AppendErrorWithFormat("%s takes one or more args.\n",
2373 m_cmd_name.c_str());
2374 result.SetStatus(eReturnStatusFailed);
2375 return false;
2376 }
2377
2378 if (m_options.m_class_name.empty() && !m_options.m_input_python) {
2379 result.AppendErrorWithFormat("%s needs either a Python class name or -P to "
2380 "directly input Python code.\n",
2381 m_cmd_name.c_str());
2382 result.SetStatus(eReturnStatusFailed);
2383 return false;
2384 }
2385
2386 SyntheticChildrenSP entry;
2387
2388 ScriptedSyntheticChildren *impl = new ScriptedSyntheticChildren(
2389 SyntheticChildren::Flags()
2390 .SetCascades(m_options.m_cascade)
2391 .SetSkipPointers(m_options.m_skip_pointers)
2392 .SetSkipReferences(m_options.m_skip_references),
2393 m_options.m_class_name.c_str());
2394
2395 entry.reset(impl);
2396
2397 ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
2398
2399 if (interpreter &&
2400 !interpreter->CheckObjectExists(impl->GetPythonClassName()))
2401 result.AppendWarning("The provided class does not exist - please define it "
2402 "before attempting to use this synthetic provider");
2403
2404 // now I have a valid provider, let's add it to every type
2405
2406 lldb::TypeCategoryImplSP category;
2407 DataVisualization::Categories::GetCategory(
2408 ConstString(m_options.m_category.c_str()), category);
2409
2410 Status error;
2411
2412 for (auto &arg_entry : command.entries()) {
2413 if (arg_entry.ref.empty()) {
2414 result.AppendError("empty typenames not allowed");
2415 result.SetStatus(eReturnStatusFailed);
2416 return false;
2417 }
2418
2419 ConstString typeCS(arg_entry.ref);
2420 if (!AddSynth(typeCS, entry,
2421 m_options.m_regex ? eRegexSynth : eRegularSynth,
2422 m_options.m_category, &error)) {
2423 result.AppendError(error.AsCString());
2424 result.SetStatus(eReturnStatusFailed);
2425 return false;
2426 }
2427 }
2428
2429 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2430 return result.Succeeded();
2431}
2432
2433CommandObjectTypeSynthAdd::CommandObjectTypeSynthAdd(
2434 CommandInterpreter &interpreter)
2435 : CommandObjectParsed(interpreter, "type synthetic add",
2436 "Add a new synthetic provider for a type.", nullptr),
2437 IOHandlerDelegateMultiline("DONE"), m_options() {
2438 CommandArgumentEntry type_arg;
2439 CommandArgumentData type_style_arg;
2440
2441 type_style_arg.arg_type = eArgTypeName;
2442 type_style_arg.arg_repetition = eArgRepeatPlus;
2443
2444 type_arg.push_back(type_style_arg);
2445
2446 m_arguments.push_back(type_arg);
2447}
2448
2449bool CommandObjectTypeSynthAdd::AddSynth(ConstString type_name,
2450 SyntheticChildrenSP entry,
2451 SynthFormatType type,
2452 std::string category_name,
2453 Status *error) {
2454 lldb::TypeCategoryImplSP category;
2455 DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()),
2456 category);
2457
2458 if (type == eRegularSynth) {
2459 if (FixArrayTypeNameWithRegex(type_name))
2460 type = eRegexSynth;
2461 }
2462
2463 if (category->AnyMatches(type_name, eFormatCategoryItemFilter |
2464 eFormatCategoryItemRegexFilter,
2465 false)) {
2466 if (error)
2467 error->SetErrorStringWithFormat("cannot add synthetic for type %s when "
2468 "filter is defined in same category!",
2469 type_name.AsCString());
2470 return false;
2471 }
2472
2473 if (type == eRegexSynth) {
2474 RegularExpressionSP typeRX(new RegularExpression());
2475 if (!typeRX->Compile(type_name.GetStringRef())) {
2476 if (error)
2477 error->SetErrorString(
2478 "regex format error (maybe this is not really a regex?)");
2479 return false;
2480 }
2481
2482 category->GetRegexTypeSyntheticsContainer()->Delete(type_name);
2483 category->GetRegexTypeSyntheticsContainer()->Add(typeRX, entry);
2484
2485 return true;
2486 } else {
2487 category->GetTypeSyntheticsContainer()->Add(type_name, entry);
2488 return true;
2489 }
2490}
2491
2492#endif // LLDB_DISABLE_PYTHON
2493
2494static OptionDefinition g_type_filter_add_options[] = {
2495 // clang-format off
2496 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "cascade", 'C', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, cascade through typedef chains." },
2497 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "skip-pointers", 'p', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects." },
2498 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "skip-references", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use this format for references-to-type objects." },
2499 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "category", 'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "Add this to the given category instead of the default one." },
2500 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "child", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeExpressionPath, "Include this expression path in the synthetic view." },
2501 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "regex", 'x', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Type names are actually regular expressions." }
2502 // clang-format on
2503};
2504
2505class CommandObjectTypeFilterAdd : public CommandObjectParsed {
2506private:
2507 class CommandOptions : public Options {
2508 typedef std::vector<std::string> option_vector;
2509
2510 public:
2511 CommandOptions() : Options() {}
2512
2513 ~CommandOptions() override = default;
2514
2515 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2516 ExecutionContext *execution_context) override {
2517 Status error;
2518 const int short_option = m_getopt_table[option_idx].val;
2519 bool success;
2520
2521 switch (short_option) {
2522 case 'C':
2523 m_cascade = Args::StringToBoolean(option_arg, true, &success);
2524 if (!success)
2525 error.SetErrorStringWithFormat("invalid value for cascade: %s",
2526 option_arg.str().c_str());
2527 break;
2528 case 'c':
2529 m_expr_paths.push_back(option_arg);
2530 has_child_list = true;
2531 break;
2532 case 'p':
2533 m_skip_pointers = true;
2534 break;
2535 case 'r':
2536 m_skip_references = true;
2537 break;
2538 case 'w':
2539 m_category = std::string(option_arg);
2540 break;
2541 case 'x':
2542 m_regex = true;
2543 break;
2544 default:
2545 error.SetErrorStringWithFormat("unrecognized option '%c'",
2546 short_option);
2547 break;
2548 }
2549
2550 return error;
2551 }
2552
2553 void OptionParsingStarting(ExecutionContext *execution_context) override {
2554 m_cascade = true;
2555 m_skip_pointers = false;
2556 m_skip_references = false;
2557 m_category = "default";
2558 m_expr_paths.clear();
2559 has_child_list = false;
2560 m_regex = false;
2561 }
2562
2563 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2564 return llvm::makeArrayRef(g_type_filter_add_options);
2565 }
2566
2567 // Instance variables to hold the values for command options.
2568
2569 bool m_cascade;
2570 bool m_skip_references;
2571 bool m_skip_pointers;
2572 bool m_input_python;
2573 option_vector m_expr_paths;
2574 std::string m_category;
2575 bool has_child_list;
2576 bool m_regex;
2577
2578 typedef option_vector::iterator ExpressionPathsIterator;
2579 };
2580
2581 CommandOptions m_options;
2582
2583 Options *GetOptions() override { return &m_options; }
2584
2585 enum FilterFormatType { eRegularFilter, eRegexFilter };
2586
2587 bool AddFilter(ConstString type_name, TypeFilterImplSP entry,
2588 FilterFormatType type, std::string category_name,
2589 Status *error) {
2590 lldb::TypeCategoryImplSP category;
2591 DataVisualization::Categories::GetCategory(
2592 ConstString(category_name.c_str()), category);
2593
2594 if (type == eRegularFilter) {
2595 if (FixArrayTypeNameWithRegex(type_name))
2596 type = eRegexFilter;
2597 }
2598
2599 if (category->AnyMatches(type_name, eFormatCategoryItemSynth |
2600 eFormatCategoryItemRegexSynth,
2601 false)) {
2602 if (error)
2603 error->SetErrorStringWithFormat("cannot add filter for type %s when "
2604 "synthetic is defined in same "
2605 "category!",
2606 type_name.AsCString());
2607 return false;
2608 }
2609
2610 if (type == eRegexFilter) {
2611 RegularExpressionSP typeRX(new RegularExpression());
2612 if (!typeRX->Compile(type_name.GetStringRef())) {
2613 if (error)
2614 error->SetErrorString(
2615 "regex format error (maybe this is not really a regex?)");
2616 return false;
2617 }
2618
2619 category->GetRegexTypeFiltersContainer()->Delete(type_name);
2620 category->GetRegexTypeFiltersContainer()->Add(typeRX, entry);
2621
2622 return true;
2623 } else {
2624 category->GetTypeFiltersContainer()->Add(type_name, entry);
2625 return true;
2626 }
2627 }
2628
2629public:
2630 CommandObjectTypeFilterAdd(CommandInterpreter &interpreter)
2631 : CommandObjectParsed(interpreter, "type filter add",
2632 "Add a new filter for a type.", nullptr),
2633 m_options() {
2634 CommandArgumentEntry type_arg;
2635 CommandArgumentData type_style_arg;
2636
2637 type_style_arg.arg_type = eArgTypeName;
2638 type_style_arg.arg_repetition = eArgRepeatPlus;
2639
2640 type_arg.push_back(type_style_arg);
2641
2642 m_arguments.push_back(type_arg);
2643
2644 SetHelpLong(
2645 R"(
2646The following examples of 'type filter add' refer to this code snippet for context:
2647
2648 class Foo {
2649 int a;
2650 int b;
2651 int c;
2652 int d;
2653 int e;
2654 int f;
2655 int g;
2656 int h;
2657 int i;
2658 }
2659 Foo my_foo;
2660
2661Adding a simple filter:
2662
2663(lldb) type filter add --child a --child g Foo
2664(lldb) frame variable my_foo
2665
2666)"
2667 "Produces output where only a and g are displayed. Other children of my_foo \
2668(b, c, d, e, f, h and i) are available by asking for them explicitly:"
2669 R"(
2670
2671(lldb) frame variable my_foo.b my_foo.c my_foo.i
2672
2673)"
2674 "The formatting option --raw on frame variable bypasses the filter, showing \
2675all children of my_foo as if no filter was defined:"
2676 R"(
2677
2678(lldb) frame variable my_foo --raw)");
2679 }
2680
2681 ~CommandObjectTypeFilterAdd() override = default;
2682
2683protected:
2684 bool DoExecute(Args &command, CommandReturnObject &result) override {
2685 const size_t argc = command.GetArgumentCount();
2686
2687 if (argc < 1) {
2688 result.AppendErrorWithFormat("%s takes one or more args.\n",
2689 m_cmd_name.c_str());
2690 result.SetStatus(eReturnStatusFailed);
2691 return false;
2692 }
2693
2694 if (m_options.m_expr_paths.empty()) {
2695 result.AppendErrorWithFormat("%s needs one or more children.\n",
2696 m_cmd_name.c_str());
2697 result.SetStatus(eReturnStatusFailed);
2698 return false;
2699 }
2700
2701 TypeFilterImplSP entry(new TypeFilterImpl(
2702 SyntheticChildren::Flags()
2703 .SetCascades(m_options.m_cascade)
2704 .SetSkipPointers(m_options.m_skip_pointers)
2705 .SetSkipReferences(m_options.m_skip_references)));
2706
2707 // go through the expression paths
2708 CommandOptions::ExpressionPathsIterator begin,
2709 end = m_options.m_expr_paths.end();
2710
2711 for (begin = m_options.m_expr_paths.begin(); begin != end; begin++)
2712 entry->AddExpressionPath(*begin);
2713
2714 // now I have a valid provider, let's add it to every type
2715
2716 lldb::TypeCategoryImplSP category;
2717 DataVisualization::Categories::GetCategory(
2718 ConstString(m_options.m_category.c_str()), category);
2719
2720 Status error;
2721
2722 WarnOnPotentialUnquotedUnsignedType(command, result);
2723
2724 for (auto &arg_entry : command.entries()) {
2725 if (arg_entry.ref.empty()) {
2726 result.AppendError("empty typenames not allowed");
2727 result.SetStatus(eReturnStatusFailed);
2728 return false;
2729 }
2730
2731 ConstString typeCS(arg_entry.ref);
2732 if (!AddFilter(typeCS, entry,
2733 m_options.m_regex ? eRegexFilter : eRegularFilter,
2734 m_options.m_category, &error)) {
2735 result.AppendError(error.AsCString());
2736 result.SetStatus(eReturnStatusFailed);
2737 return false;
2738 }
2739 }
2740
2741 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2742 return result.Succeeded();
2743 }
2744};
2745
2746//----------------------------------------------------------------------
2747// "type lookup"
2748//----------------------------------------------------------------------
2749static OptionDefinition g_type_lookup_options[] = {
2750 // clang-format off
2751 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "show-help", 'h', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Display available help for types" },
2752 { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Which language's types should the search scope be" }
2753 // clang-format on
2754};
2755
2756class CommandObjectTypeLookup : public CommandObjectRaw {
2757protected:
2758 // this function is allowed to do a more aggressive job at guessing languages
2759 // than the expression parser
2760 // is comfortable with - so leave the original call alone and add one that is
2761 // specific to type lookup
2762 lldb::LanguageType GuessLanguage(StackFrame *frame) {
2763 lldb::LanguageType lang_type = lldb::eLanguageTypeUnknown;
2764
2765 if (!frame)
2766 return lang_type;
2767
2768 lang_type = frame->GuessLanguage();
2769 if (lang_type != lldb::eLanguageTypeUnknown)
2770 return lang_type;
2771
2772 Symbol *s = frame->GetSymbolContext(eSymbolContextSymbol).symbol;
2773 if (s)
2774 lang_type = s->GetMangled().GuessLanguage();
2775
2776 return lang_type;
2777 }
2778
2779 class CommandOptions : public OptionGroup {
2780 public:
2781 CommandOptions()
2782 : OptionGroup(), m_show_help(false), m_language(eLanguageTypeUnknown) {}
2783
2784 ~CommandOptions() override = default;
2785
2786 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2787 return llvm::makeArrayRef(g_type_lookup_options);
2788 }
2789
2790 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
2791 ExecutionContext *execution_context) override {
2792 Status error;
2793
2794 const int short_option = g_type_lookup_options[option_idx].short_option;
2795
2796 switch (short_option) {
2797 case 'h':
2798 m_show_help = true;
2799 break;
2800
2801 case 'l':
2802 m_language = Language::GetLanguageTypeFromString(option_value);
2803 break;
2804
2805 default:
2806 error.SetErrorStringWithFormat("invalid short option character '%c'",
2807 short_option);
2808 break;
2809 }
2810
2811 return error;
2812 }
2813
2814 void OptionParsingStarting(ExecutionContext *execution_context) override {
2815 m_show_help = false;
2816 m_language = eLanguageTypeUnknown;
2817 }
2818
2819 // Options table: Required for subclasses of Options.
2820
2821 bool m_show_help;
2822 lldb::LanguageType m_language;
2823 };
2824
2825 OptionGroupOptions m_option_group;
2826 CommandOptions m_command_options;
2827
2828public:
2829 CommandObjectTypeLookup(CommandInterpreter &interpreter)
2830 : CommandObjectRaw(interpreter, "type lookup",
2831 "Lookup types and declarations in the current target, "
2832 "following language-specific naming conventions.",
2833 "type lookup <type-specifier>",
2834 eCommandRequiresTarget),
2835 m_option_group(), m_command_options() {
2836 m_option_group.Append(&m_command_options);
2837 m_option_group.Finalize();
2838 }
2839
2840 ~CommandObjectTypeLookup() override = default;
2841
2842 Options *GetOptions() override { return &m_option_group; }
2843
2844 llvm::StringRef GetHelpLong() override {
2845 if (!m_cmd_help_long.empty())
2846 return m_cmd_help_long;
2847
2848 StreamString stream;
2849 // FIXME: hardcoding languages is not good
2850 lldb::LanguageType languages[] = {eLanguageTypeObjC,
2851 eLanguageTypeC_plus_plus};
2852
2853 for (const auto lang_type : languages) {
2854 if (auto language = Language::FindPlugin(lang_type)) {
2855 if (const char *help = language->GetLanguageSpecificTypeLookupHelp()) {
2856 stream.Printf("%s\n", help);
2857 }
2858 }
2859 }
2860
2861 m_cmd_help_long = stream.GetString();
2862 return m_cmd_help_long;
2863 }
2864
2865 bool DoExecute(const char *raw_command_line,
2866 CommandReturnObject &result) override {
2867 if (!raw_command_line || !raw_command_line[0]) {
2868 result.SetError(
2869 "type lookup cannot be invoked without a type name as argument");
2870 return false;
2871 }
2872
2873 auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
2874 m_option_group.NotifyOptionParsingStarting(&exe_ctx);
2875
2876 const char *name_of_type = nullptr;
2877
2878 if (raw_command_line[0] == '-') {
2879 // We have some options and these options MUST end with --.
2880 const char *end_options = nullptr;
2881 const char *s = raw_command_line;
2882 while (s && s[0]) {
2883 end_options = ::strstr(s, "--");
2884 if (end_options) {
2885 end_options += 2; // Get past the "--"
2886 if (::isspace(end_options[0])) {
2887 name_of_type = end_options;
2888 while (::isspace(*name_of_type))
2889 ++name_of_type;
2890 break;
2891 }
2892 }
2893 s = end_options;
2894 }
2895
2896 if (end_options) {
2897 Args args(
2898 llvm::StringRef(raw_command_line, end_options - raw_command_line));
2899 if (!ParseOptions(args, result))
2900 return false;
2901
2902 Status error(m_option_group.NotifyOptionParsingFinished(&exe_ctx));
2903 if (error.Fail()) {
2904 result.AppendError(error.AsCString());
2905 result.SetStatus(eReturnStatusFailed);
2906 return false;
2907 }
2908 }
2909 }
2910 if (nullptr == name_of_type)
2911 name_of_type = raw_command_line;
2912
2913 // TargetSP
2914 // target_sp(GetCommandInterpreter().GetDebugger().GetSelectedTarget());
2915 // const bool fill_all_in = true;
2916 // ExecutionContext exe_ctx(target_sp.get(), fill_all_in);
2917 ExecutionContextScope *best_scope = exe_ctx.GetBestExecutionContextScope();
2918
2919 bool any_found = false;
2920
2921 std::vector<Language *> languages;
2922
2923 bool is_global_search = false;
2924 LanguageType guessed_language = lldb::eLanguageTypeUnknown;
2925
2926 if ((is_global_search =
2927 (m_command_options.m_language == eLanguageTypeUnknown))) {
2928 // FIXME: hardcoding languages is not good
2929 languages.push_back(Language::FindPlugin(eLanguageTypeObjC));
2930 languages.push_back(Language::FindPlugin(eLanguageTypeC_plus_plus));
2931 } else {
2932 languages.push_back(Language::FindPlugin(m_command_options.m_language));
2933 }
2934
2935 // This is not the most efficient way to do this, but we support very few
2936 // languages
2937 // so the cost of the sort is going to be dwarfed by the actual lookup
2938 // anyway
2939 if (StackFrame *frame = m_exe_ctx.GetFramePtr()) {
2940 guessed_language = GuessLanguage(frame);
2941 if (guessed_language != eLanguageTypeUnknown) {
2942 std::sort(
2943 languages.begin(), languages.end(),
2944 [guessed_language](Language *lang1, Language *lang2) -> bool {
2945 if (!lang1 || !lang2)
2946 return false;
2947 LanguageType lt1 = lang1->GetLanguageType();
2948 LanguageType lt2 = lang2->GetLanguageType();
2949 if (lt1 == guessed_language)
2950 return true; // make the selected frame's language come first
2951 if (lt2 == guessed_language)
2952 return false; // make the selected frame's language come first
2953 return (lt1 < lt2); // normal comparison otherwise
2954 });
2955 }
2956 }
2957
2958 bool is_first_language = true;
2959
2960 for (Language *language : languages) {
2961 if (!language)
2962 continue;
2963
2964 if (auto scavenger = language->GetTypeScavenger()) {
2965 Language::TypeScavenger::ResultSet search_results;
2966 if (scavenger->Find(best_scope, name_of_type, search_results) > 0) {
2967 for (const auto &search_result : search_results) {
2968 if (search_result && search_result->IsValid()) {
2969 any_found = true;
2970 search_result->DumpToStream(result.GetOutputStream(),
2971 this->m_command_options.m_show_help);
2972 }
2973 }
2974 }
2975 }
2976 // this is "type lookup SomeName" and we did find a match, so get out
2977 if (any_found && is_global_search)
2978 break;
2979 else if (is_first_language && is_global_search &&
2980 guessed_language != lldb::eLanguageTypeUnknown) {
2981 is_first_language = false;
2982 result.GetOutputStream().Printf(
2983 "no type was found in the current language %s matching '%s'; "
2984 "performing a global search across all languages\n",
2985 Language::GetNameForLanguageType(guessed_language), name_of_type);
2986 }
2987 }
2988
2989 if (!any_found)
2990 result.AppendMessageWithFormat("no type was found matching '%s'\n",
2991 name_of_type);
2992
2993 result.SetStatus(any_found ? lldb::eReturnStatusSuccessFinishResult
2994 : lldb::eReturnStatusSuccessFinishNoResult);
2995 return true;
2996 }
2997};
2998
2999template <typename FormatterType>
3000class CommandObjectFormatterInfo : public CommandObjectRaw {
3001public:
3002 typedef std::function<typename FormatterType::SharedPointer(ValueObject &)>
3003 DiscoveryFunction;
3004 CommandObjectFormatterInfo(CommandInterpreter &interpreter,
3005 const char *formatter_name,
3006 DiscoveryFunction discovery_func)
3007 : CommandObjectRaw(interpreter, "", "", "",
3008 eCommandRequiresFrame),
3009 m_formatter_name(formatter_name ? formatter_name : ""),
3010 m_discovery_function(discovery_func) {
3011 StreamString name;
3012 name.Printf("type %s info", formatter_name);
3013 SetCommandName(name.GetString());
3014 StreamString help;
3015 help.Printf("This command evaluates the provided expression and shows "
3016 "which %s is applied to the resulting value (if any).",
3017 formatter_name);
3018 SetHelp(help.GetString());
3019 StreamString syntax;
3020 syntax.Printf("type %s info <expr>", formatter_name);
3021 SetSyntax(syntax.GetString());
3022 }
3023
3024 ~CommandObjectFormatterInfo() override = default;
3025
3026protected:
3027 bool DoExecute(const char *command, CommandReturnObject &result) override {
3028 TargetSP target_sp = m_interpreter.GetDebugger().GetSelectedTarget();
3029 Thread *thread = GetDefaultThread();
3030 if (!thread) {
3031 result.AppendError("no default thread");
3032 result.SetStatus(lldb::eReturnStatusFailed);
3033 return false;
3034 }
3035
3036 StackFrameSP frame_sp = thread->GetSelectedFrame();
3037 ValueObjectSP result_valobj_sp;
3038 EvaluateExpressionOptions options;
3039 lldb::ExpressionResults expr_result = target_sp->EvaluateExpression(
3040 command, frame_sp.get(), result_valobj_sp, options);
3041 if (expr_result == eExpressionCompleted && result_valobj_sp) {
3042 result_valobj_sp =
3043 result_valobj_sp->GetQualifiedRepresentationIfAvailable(
3044 target_sp->GetPreferDynamicValue(),
3045 target_sp->GetEnableSyntheticValue());
3046 typename FormatterType::SharedPointer formatter_sp =
3047 m_discovery_function(*result_valobj_sp);
3048 if (formatter_sp) {
3049 std::string description(formatter_sp->GetDescription());
3050 result.AppendMessageWithFormat(
3051 "%s applied to (%s) %s is: %s\n", m_formatter_name.c_str(),
3052 result_valobj_sp->GetDisplayTypeName().AsCString("<unknown>"),
3053 command, description.c_str());
3054 result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
3055 } else {
3056 result.AppendMessageWithFormat(
3057 "no %s applies to (%s) %s\n", m_formatter_name.c_str(),
3058 result_valobj_sp->GetDisplayTypeName().AsCString("<unknown>"),
3059 command);
3060 result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
3061 }
3062 return true;
3063 } else {
3064 result.AppendError("failed to evaluate expression");
3065 result.SetStatus(lldb::eReturnStatusFailed);
3066 return false;
3067 }
3068 }
3069
3070private:
3071 std::string m_formatter_name;
3072 DiscoveryFunction m_discovery_function;
3073};
3074
3075class CommandObjectTypeFormat : public CommandObjectMultiword {
3076public:
3077 CommandObjectTypeFormat(CommandInterpreter &interpreter)
3078 : CommandObjectMultiword(
3079 interpreter, "type format",
3080 "Commands for customizing value display formats.",
3081 "type format [<sub-command-options>] ") {
3082 LoadSubCommand(
3083 "add", CommandObjectSP(new CommandObjectTypeFormatAdd(interpreter)));
3084 LoadSubCommand("clear", CommandObjectSP(
3085 new CommandObjectTypeFormatClear(interpreter)));
3086 LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeFormatDelete(
3087 interpreter)));
3088 LoadSubCommand(
3089 "list", CommandObjectSP(new CommandObjectTypeFormatList(interpreter)));
3090 LoadSubCommand(
3091 "info", CommandObjectSP(new CommandObjectFormatterInfo<TypeFormatImpl>(
3092 interpreter, "format",
3093 [](ValueObject &valobj) -> TypeFormatImpl::SharedPointer {
3094 return valobj.GetValueFormat();
3095 })));
3096 }
3097
3098 ~CommandObjectTypeFormat() override = default;
3099};
3100
3101#ifndef LLDB_DISABLE_PYTHON
3102
3103class CommandObjectTypeSynth : public CommandObjectMultiword {
3104public:
3105 CommandObjectTypeSynth(CommandInterpreter &interpreter)
3106 : CommandObjectMultiword(
3107 interpreter, "type synthetic",
3108 "Commands for operating on synthetic type representations.",
3109 "type synthetic [<sub-command-options>] ") {
3110 LoadSubCommand("add",
3111 CommandObjectSP(new CommandObjectTypeSynthAdd(interpreter)));
3112 LoadSubCommand(
3113 "clear", CommandObjectSP(new CommandObjectTypeSynthClear(interpreter)));
3114 LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeSynthDelete(
3115 interpreter)));
3116 LoadSubCommand(
3117 "list", CommandObjectSP(new CommandObjectTypeSynthList(interpreter)));
3118 LoadSubCommand(
3119 "info",
3120 CommandObjectSP(new CommandObjectFormatterInfo<SyntheticChildren>(
3121 interpreter, "synthetic",
3122 [](ValueObject &valobj) -> SyntheticChildren::SharedPointer {
3123 return valobj.GetSyntheticChildren();
3124 })));
3125 }
3126
3127 ~CommandObjectTypeSynth() override = default;
3128};
3129
3130#endif // LLDB_DISABLE_PYTHON
3131
3132class CommandObjectTypeFilter : public CommandObjectMultiword {
3133public:
3134 CommandObjectTypeFilter(CommandInterpreter &interpreter)
3135 : CommandObjectMultiword(interpreter, "type filter",
3136 "Commands for operating on type filters.",
3137 "type synthetic [<sub-command-options>] ") {
3138 LoadSubCommand(
3139 "add", CommandObjectSP(new CommandObjectTypeFilterAdd(interpreter)));
3140 LoadSubCommand("clear", CommandObjectSP(
3141 new CommandObjectTypeFilterClear(interpreter)));
3142 LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeFilterDelete(
3143 interpreter)));
3144 LoadSubCommand(
3145 "list", CommandObjectSP(new CommandObjectTypeFilterList(interpreter)));
3146 }
3147
3148 ~CommandObjectTypeFilter() override = default;
3149};
3150
3151class CommandObjectTypeCategory : public CommandObjectMultiword {
3152public:
3153 CommandObjectTypeCategory(CommandInterpreter &interpreter)
3154 : CommandObjectMultiword(interpreter, "type category",
3155 "Commands for operating on type categories.",
3156 "type category [<sub-command-options>] ") {
3157 LoadSubCommand(
3158 "define",
3159 CommandObjectSP(new CommandObjectTypeCategoryDefine(interpreter)));
3160 LoadSubCommand(
3161 "enable",
3162 CommandObjectSP(new CommandObjectTypeCategoryEnable(interpreter)));
3163 LoadSubCommand(
3164 "disable",
3165 CommandObjectSP(new CommandObjectTypeCategoryDisable(interpreter)));
3166 LoadSubCommand(
3167 "delete",
3168 CommandObjectSP(new CommandObjectTypeCategoryDelete(interpreter)));
3169 LoadSubCommand("list", CommandObjectSP(
3170 new CommandObjectTypeCategoryList(interpreter)));
3171 }
3172
3173 ~CommandObjectTypeCategory() override = default;
3174};
3175
3176class CommandObjectTypeSummary : public CommandObjectMultiword {
3177public:
3178 CommandObjectTypeSummary(CommandInterpreter &interpreter)
3179 : CommandObjectMultiword(
3180 interpreter, "type summary",
3181 "Commands for editing variable summary display options.",
3182 "type summary [<sub-command-options>] ") {
3183 LoadSubCommand(
3184 "add", CommandObjectSP(new CommandObjectTypeSummaryAdd(interpreter)));
3185 LoadSubCommand("clear", CommandObjectSP(new CommandObjectTypeSummaryClear(
3186 interpreter)));
3187 LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeSummaryDelete(
3188 interpreter)));
3189 LoadSubCommand(
3190 "list", CommandObjectSP(new CommandObjectTypeSummaryList(interpreter)));
3191 LoadSubCommand(
3192 "info", CommandObjectSP(new CommandObjectFormatterInfo<TypeSummaryImpl>(
3193 interpreter, "summary",
3194 [](ValueObject &valobj) -> TypeSummaryImpl::SharedPointer {
3195 return valobj.GetSummaryFormat();
3196 })));
3197 }
3198
3199 ~CommandObjectTypeSummary() override = default;
3200};
3201
3202//-------------------------------------------------------------------------
3203// CommandObjectType
3204//-------------------------------------------------------------------------
3205
3206CommandObjectType::CommandObjectType(CommandInterpreter &interpreter)
3207 : CommandObjectMultiword(interpreter, "type",
3208 "Commands for operating on the type system.",
3209 "type [<sub-command-options>]") {
3210 LoadSubCommand("category",
3211 CommandObjectSP(new CommandObjectTypeCategory(interpreter)));
3212 LoadSubCommand("filter",
3213 CommandObjectSP(new CommandObjectTypeFilter(interpreter)));
3214 LoadSubCommand("format",
3215 CommandObjectSP(new CommandObjectTypeFormat(interpreter)));
3216 LoadSubCommand("summary",
3217 CommandObjectSP(new CommandObjectTypeSummary(interpreter)));
3218#ifndef LLDB_DISABLE_PYTHON
3219 LoadSubCommand("synthetic",
3220 CommandObjectSP(new CommandObjectTypeSynth(interpreter)));
3221#endif // LLDB_DISABLE_PYTHON
3222 LoadSubCommand("lookup",
3223 CommandObjectSP(new CommandObjectTypeLookup(interpreter)));
3224}
3225
3226CommandObjectType::~CommandObjectType() = default;

/build/llvm-toolchain-snapshot-6.0~svn318882/tools/lldb/include/lldb/DataFormatters/FormattersContainer.h

1//===-- FormattersContainer.h -----------------------------------*- 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#ifndef lldb_FormattersContainer_h_
11#define lldb_FormattersContainer_h_
12
13// C Includes
14// C++ Includes
15#include <functional>
16#include <map>
17#include <memory>
18#include <mutex>
19#include <string>
20
21// Other libraries and framework includes
22// Project includes
23#include "lldb/lldb-public.h"
24
25#include "lldb/Core/ValueObject.h"
26#include "lldb/DataFormatters/FormatClasses.h"
27#include "lldb/DataFormatters/TypeFormat.h"
28#include "lldb/DataFormatters/TypeSummary.h"
29#include "lldb/DataFormatters/TypeSynthetic.h"
30#include "lldb/DataFormatters/TypeValidator.h"
31#include "lldb/Symbol/CompilerType.h"
32#include "lldb/Utility/RegularExpression.h"
33#include "lldb/Utility/StringLexer.h"
34
35namespace lldb_private {
36
37class IFormatChangeListener {
38public:
39 virtual ~IFormatChangeListener() = default;
40
41 virtual void Changed() = 0;
42
43 virtual uint32_t GetCurrentRevision() = 0;
44};
45
46// if the user tries to add formatters for, say, "struct Foo"
47// those will not match any type because of the way we strip qualifiers from
48// typenames
49// this method looks for the case where the user is adding a
50// "class","struct","enum" or "union" Foo
51// and strips the unnecessary qualifier
52static inline ConstString GetValidTypeName_Impl(const ConstString &type) {
53 if (type.IsEmpty())
54 return type;
55
56 std::string type_cstr(type.AsCString());
57 lldb_utility::StringLexer type_lexer(type_cstr);
58
59 type_lexer.AdvanceIf("class ");
60 type_lexer.AdvanceIf("enum ");
61 type_lexer.AdvanceIf("struct ");
62 type_lexer.AdvanceIf("union ");
63
64 while (type_lexer.NextIf({' ', '\t', '\v', '\f'}).first)
65 ;
66
67 return ConstString(type_lexer.GetUnlexed());
68}
69
70template <typename KeyType, typename ValueType> class FormattersContainer;
71
72template <typename KeyType, typename ValueType> class FormatMap {
73public:
74 typedef typename ValueType::SharedPointer ValueSP;
75 typedef std::map<KeyType, ValueSP> MapType;
76 typedef typename MapType::iterator MapIterator;
77 typedef std::function<bool(KeyType, const ValueSP &)> ForEachCallback;
78
79 FormatMap(IFormatChangeListener *lst)
80 : m_map(), m_map_mutex(), listener(lst) {}
81
82 void Add(KeyType name, const ValueSP &entry) {
83 if (listener)
21
Assuming the condition is false
22
Taking false branch
52
Assuming the condition is false
53
Taking false branch
84 entry->GetRevision() = listener->GetCurrentRevision();
85 else
86 entry->GetRevision() = 0;
87
88 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
89 m_map[name] = entry;
23
Calling defaulted copy assignment operator for 'shared_ptr'
40
Returning; memory was released
54
Calling defaulted copy assignment operator for 'shared_ptr'
90 if (listener)
41
Assuming the condition is false
42
Taking false branch
91 listener->Changed();
92 }
93
94 bool Delete(KeyType name) {
95 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
96 MapIterator iter = m_map.find(name);
97 if (iter == m_map.end())
98 return false;
99 m_map.erase(name);
100 if (listener)
101 listener->Changed();
102 return true;
103 }
104
105 void Clear() {
106 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
107 m_map.clear();
108 if (listener)
109 listener->Changed();
110 }
111
112 bool Get(KeyType name, ValueSP &entry) {
113 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
114 MapIterator iter = m_map.find(name);
115 if (iter == m_map.end())
116 return false;
117 entry = iter->second;
118 return true;
119 }
120
121 void ForEach(ForEachCallback callback) {
122 if (callback) {
123 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
124 MapIterator pos, end = m_map.end();
125 for (pos = m_map.begin(); pos != end; pos++) {
126 KeyType type = pos->first;
127 if (!callback(type, pos->second))
128 break;
129 }
130 }
131 }
132
133 uint32_t GetCount() { return m_map.size(); }
134
135 ValueSP GetValueAtIndex(size_t index) {
136 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
137 MapIterator iter = m_map.begin();
138 MapIterator end = m_map.end();
139 while (index > 0) {
140 iter++;
141 index--;
142 if (end == iter)
143 return ValueSP();
144 }
145 return iter->second;
146 }
147
148 KeyType GetKeyAtIndex(size_t index) {
149 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
150 MapIterator iter = m_map.begin();
151 MapIterator end = m_map.end();
152 while (index > 0) {
153 iter++;
154 index--;
155 if (end == iter)
156 return KeyType();
157 }
158 return iter->first;
159 }
160
161protected:
162 MapType m_map;
163 std::recursive_mutex m_map_mutex;
164 IFormatChangeListener *listener;
165
166 MapType &map() { return m_map; }
167
168 std::recursive_mutex &mutex() { return m_map_mutex; }
169
170 friend class FormattersContainer<KeyType, ValueType>;
171 friend class FormatManager;
172};
173
174template <typename KeyType, typename ValueType> class FormattersContainer {
175protected:
176 typedef FormatMap<KeyType, ValueType> BackEndType;
177
178public:
179 typedef typename BackEndType::MapType MapType;
180 typedef typename MapType::iterator MapIterator;
181 typedef typename MapType::key_type MapKeyType;
182 typedef typename MapType::mapped_type MapValueType;
183 typedef typename BackEndType::ForEachCallback ForEachCallback;
184 typedef typename std::shared_ptr<FormattersContainer<KeyType, ValueType>>
185 SharedPointer;
186
187 friend class TypeCategoryImpl;
188
189 FormattersContainer(std::string name, IFormatChangeListener *lst)
190 : m_format_map(lst), m_name(name) {}
191
192 void Add(const MapKeyType &type, const MapValueType &entry) {
193 Add_Impl(type, entry, static_cast<KeyType *>(nullptr));
19
Calling 'FormattersContainer::Add_Impl'
44
Returning; memory was released
50
Calling 'FormattersContainer::Add_Impl'
194 }
195
196 bool Delete(ConstString type) {
197 return Delete_Impl(type, static_cast<KeyType *>(nullptr));
198 }
199
200 bool Get(ValueObject &valobj, MapValueType &entry,
201 lldb::DynamicValueType use_dynamic, uint32_t *why = nullptr) {
202 uint32_t value = lldb_private::eFormatterChoiceCriterionDirectChoice;
203 CompilerType ast_type(valobj.GetCompilerType());
204 bool ret = Get(valobj, ast_type, entry, use_dynamic, value);
205 if (ret)
206 entry = MapValueType(entry);
207 else
208 entry = MapValueType();
209 if (why)
210 *why = value;
211 return ret;
212 }
213
214 bool Get(ConstString type, MapValueType &entry) {
215 return Get_Impl(type, entry, static_cast<KeyType *>(nullptr));
216 }
217
218 bool GetExact(ConstString type, MapValueType &entry) {
219 return GetExact_Impl(type, entry, static_cast<KeyType *>(nullptr));
220 }
221
222 MapValueType GetAtIndex(size_t index) {
223 return m_format_map.GetValueAtIndex(index);
224 }
225
226 lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index) {
227 return GetTypeNameSpecifierAtIndex_Impl(index,
228 static_cast<KeyType *>(nullptr));
229 }
230
231 void Clear() { m_format_map.Clear(); }
232
233 void ForEach(ForEachCallback callback) { m_format_map.ForEach(callback); }
234
235 uint32_t GetCount() { return m_format_map.GetCount(); }
236
237protected:
238 BackEndType m_format_map;
239 std::string m_name;
240
241 DISALLOW_COPY_AND_ASSIGN(FormattersContainer)FormattersContainer(const FormattersContainer &) = delete
; const FormattersContainer &operator=(const FormattersContainer
&) = delete
;
242
243 void Add_Impl(const MapKeyType &type, const MapValueType &entry,
244 lldb::RegularExpressionSP *dummy) {
245 m_format_map.Add(type, entry);
246 }
247
248 void Add_Impl(const ConstString &type, const MapValueType &entry,
249 ConstString *dummy) {
250 m_format_map.Add(GetValidTypeName_Impl(type), entry);
20
Calling 'FormatMap::Add'
43
Returning; memory was released
51
Calling 'FormatMap::Add'
251 }
252
253 bool Delete_Impl(ConstString type, ConstString *dummy) {
254 return m_format_map.Delete(type);
255 }
256
257 bool Delete_Impl(ConstString type, lldb::RegularExpressionSP *dummy) {
258 std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex());
259 MapIterator pos, end = m_format_map.map().end();
260 for (pos = m_format_map.map().begin(); pos != end; pos++) {
261 lldb::RegularExpressionSP regex = pos->first;
262 if (type.GetStringRef() == regex->GetText()) {
263 m_format_map.map().erase(pos);
264 if (m_format_map.listener)
265 m_format_map.listener->Changed();
266 return true;
267 }
268 }
269 return false;
270 }
271
272 bool Get_Impl(ConstString type, MapValueType &entry, ConstString *dummy) {
273 return m_format_map.Get(type, entry);
274 }
275
276 bool GetExact_Impl(ConstString type, MapValueType &entry,
277 ConstString *dummy) {
278 return Get_Impl(type, entry, static_cast<KeyType *>(nullptr));
279 }
280
281 lldb::TypeNameSpecifierImplSP
282 GetTypeNameSpecifierAtIndex_Impl(size_t index, ConstString *dummy) {
283 ConstString key = m_format_map.GetKeyAtIndex(index);
284 if (key)
285 return lldb::TypeNameSpecifierImplSP(
286 new TypeNameSpecifierImpl(key.AsCString(), false));
287 else
288 return lldb::TypeNameSpecifierImplSP();
289 }
290
291 lldb::TypeNameSpecifierImplSP
292 GetTypeNameSpecifierAtIndex_Impl(size_t index,
293 lldb::RegularExpressionSP *dummy) {
294 lldb::RegularExpressionSP regex = m_format_map.GetKeyAtIndex(index);
295 if (regex.get() == nullptr)
296 return lldb::TypeNameSpecifierImplSP();
297 return lldb::TypeNameSpecifierImplSP(
298 new TypeNameSpecifierImpl(regex->GetText().str().c_str(), true));
299 }
300
301 bool Get_Impl(ConstString key, MapValueType &value,
302 lldb::RegularExpressionSP *dummy) {
303 llvm::StringRef key_str = key.GetStringRef();
304 std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex());
305 MapIterator pos, end = m_format_map.map().end();
306 for (pos = m_format_map.map().begin(); pos != end; pos++) {
307 lldb::RegularExpressionSP regex = pos->first;
308 if (regex->Execute(key_str)) {
309 value = pos->second;
310 return true;
311 }
312 }
313 return false;
314 }
315
316 bool GetExact_Impl(ConstString key, MapValueType &value,
317 lldb::RegularExpressionSP *dummy) {
318 std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex());
319 MapIterator pos, end = m_format_map.map().end();
320 for (pos = m_format_map.map().begin(); pos != end; pos++) {
321 lldb::RegularExpressionSP regex = pos->first;
322 if (regex->GetText() == key.GetStringRef()) {
323 value = pos->second;
324 return true;
325 }
326 }
327 return false;
328 }
329
330 bool Get(const FormattersMatchVector &candidates, MapValueType &entry,
331 uint32_t *reason) {
332 for (const FormattersMatchCandidate &candidate : candidates) {
333 if (Get(candidate.GetTypeName(), entry)) {
334 if (candidate.IsMatch(entry) == false) {
335 entry.reset();
336 continue;
337 } else {
338 if (reason)
339 *reason = candidate.GetReason();
340 return true;
341 }
342 }
343 }
344 return false;
345 }
346};
347
348} // namespace lldb_private
349
350#endif // lldb_FormattersContainer_h_

/usr/lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/shared_ptr.h

1// shared_ptr and weak_ptr implementation -*- C++ -*-
2
3// Copyright (C) 2007-2017 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25// GCC Note: Based on files from version 1.32.0 of the Boost library.
26
27// shared_count.hpp
28// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.
29
30// shared_ptr.hpp
31// Copyright (C) 1998, 1999 Greg Colvin and Beman Dawes.
32// Copyright (C) 2001, 2002, 2003 Peter Dimov
33
34// weak_ptr.hpp
35// Copyright (C) 2001, 2002, 2003 Peter Dimov
36
37// enable_shared_from_this.hpp
38// Copyright (C) 2002 Peter Dimov
39
40// Distributed under the Boost Software License, Version 1.0. (See
41// accompanying file LICENSE_1_0.txt or copy at
42// http://www.boost.org/LICENSE_1_0.txt)
43
44/** @file
45 * This is an internal header file, included by other library headers.
46 * Do not attempt to use it directly. @headername{memory}
47 */
48
49#ifndef _SHARED_PTR_H1
50#define _SHARED_PTR_H1 1
51
52#include <bits/shared_ptr_base.h>
53
54namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default")))
55{
56_GLIBCXX_BEGIN_NAMESPACE_VERSION
57
58 /**
59 * @addtogroup pointer_abstractions
60 * @{
61 */
62
63 /// 20.7.2.2.11 shared_ptr I/O
64 template<typename _Ch, typename _Tr, typename _Tp, _Lock_policy _Lp>
65 inline std::basic_ostream<_Ch, _Tr>&
66 operator<<(std::basic_ostream<_Ch, _Tr>& __os,
67 const __shared_ptr<_Tp, _Lp>& __p)
68 {
69 __os << __p.get();
70 return __os;
71 }
72
73 /// 20.7.2.2.10 shared_ptr get_deleter
74 template<typename _Del, typename _Tp, _Lock_policy _Lp>
75 inline _Del*
76 get_deleter(const __shared_ptr<_Tp, _Lp>& __p) noexcept
77 {
78#if __cpp_rtti199711
79 return static_cast<_Del*>(__p._M_get_deleter(typeid(_Del)));
80#else
81 return 0;
82#endif
83 }
84
85
86 /**
87 * @brief A smart pointer with reference-counted copy semantics.
88 *
89 * The object pointed to is deleted when the last shared_ptr pointing to
90 * it is destroyed or reset.
91 */
92 template<typename _Tp>
93 class shared_ptr : public __shared_ptr<_Tp>
94 {
95 template<typename... _Args>
96 using _Constructible = typename enable_if<
97 is_constructible<__shared_ptr<_Tp>, _Args...>::value
98 >::type;
99
100 template<typename _Arg>
101 using _Assignable = typename enable_if<
102 is_assignable<__shared_ptr<_Tp>&, _Arg>::value, shared_ptr&
103 >::type;
104
105 public:
106
107 using element_type = typename __shared_ptr<_Tp>::element_type;
108
109#if __cplusplus201103L > 201402L
110# define __cpp_lib_shared_ptr_weak_type 201606
111 using weak_type = weak_ptr<_Tp>;
112#endif
113 /**
114 * @brief Construct an empty %shared_ptr.
115 * @post use_count()==0 && get()==0
116 */
117 constexpr shared_ptr() noexcept : __shared_ptr<_Tp>() { }
118
119 shared_ptr(const shared_ptr&) noexcept = default;
120
121 /**
122 * @brief Construct a %shared_ptr that owns the pointer @a __p.
123 * @param __p A pointer that is convertible to element_type*.
124 * @post use_count() == 1 && get() == __p
125 * @throw std::bad_alloc, in which case @c delete @a __p is called.
126 */
127 template<typename _Yp, typename = _Constructible<_Yp*>>
128 explicit
129 shared_ptr(_Yp* __p) : __shared_ptr<_Tp>(__p) { }
130
131 /**
132 * @brief Construct a %shared_ptr that owns the pointer @a __p
133 * and the deleter @a __d.
134 * @param __p A pointer.
135 * @param __d A deleter.
136 * @post use_count() == 1 && get() == __p
137 * @throw std::bad_alloc, in which case @a __d(__p) is called.
138 *
139 * Requirements: _Deleter's copy constructor and destructor must
140 * not throw
141 *
142 * __shared_ptr will release __p by calling __d(__p)
143 */
144 template<typename _Yp, typename _Deleter,
145 typename = _Constructible<_Yp*, _Deleter>>
146 shared_ptr(_Yp* __p, _Deleter __d)
147 : __shared_ptr<_Tp>(__p, std::move(__d)) { }
148
149 /**
150 * @brief Construct a %shared_ptr that owns a null pointer
151 * and the deleter @a __d.
152 * @param __p A null pointer constant.
153 * @param __d A deleter.
154 * @post use_count() == 1 && get() == __p
155 * @throw std::bad_alloc, in which case @a __d(__p) is called.
156 *
157 * Requirements: _Deleter's copy constructor and destructor must
158 * not throw
159 *
160 * The last owner will call __d(__p)
161 */
162 template<typename _Deleter>
163 shared_ptr(nullptr_t __p, _Deleter __d)
164 : __shared_ptr<_Tp>(__p, std::move(__d)) { }
165
166 /**
167 * @brief Construct a %shared_ptr that owns the pointer @a __p
168 * and the deleter @a __d.
169 * @param __p A pointer.
170 * @param __d A deleter.
171 * @param __a An allocator.
172 * @post use_count() == 1 && get() == __p
173 * @throw std::bad_alloc, in which case @a __d(__p) is called.
174 *
175 * Requirements: _Deleter's copy constructor and destructor must
176 * not throw _Alloc's copy constructor and destructor must not
177 * throw.
178 *
179 * __shared_ptr will release __p by calling __d(__p)
180 */
181 template<typename _Yp, typename _Deleter, typename _Alloc,
182 typename = _Constructible<_Yp*, _Deleter, _Alloc>>
183 shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a)
184 : __shared_ptr<_Tp>(__p, std::move(__d), std::move(__a)) { }
185
186 /**
187 * @brief Construct a %shared_ptr that owns a null pointer
188 * and the deleter @a __d.
189 * @param __p A null pointer constant.
190 * @param __d A deleter.
191 * @param __a An allocator.
192 * @post use_count() == 1 && get() == __p
193 * @throw std::bad_alloc, in which case @a __d(__p) is called.
194 *
195 * Requirements: _Deleter's copy constructor and destructor must
196 * not throw _Alloc's copy constructor and destructor must not
197 * throw.
198 *
199 * The last owner will call __d(__p)
200 */
201 template<typename _Deleter, typename _Alloc>
202 shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a)
203 : __shared_ptr<_Tp>(__p, std::move(__d), std::move(__a)) { }
204
205 // Aliasing constructor
206
207 /**
208 * @brief Constructs a %shared_ptr instance that stores @a __p
209 * and shares ownership with @a __r.
210 * @param __r A %shared_ptr.
211 * @param __p A pointer that will remain valid while @a *__r is valid.
212 * @post get() == __p && use_count() == __r.use_count()
213 *
214 * This can be used to construct a @c shared_ptr to a sub-object
215 * of an object managed by an existing @c shared_ptr.
216 *
217 * @code
218 * shared_ptr< pair<int,int> > pii(new pair<int,int>());
219 * shared_ptr<int> pi(pii, &pii->first);
220 * assert(pii.use_count() == 2);
221 * @endcode
222 */
223 template<typename _Yp>
224 shared_ptr(const shared_ptr<_Yp>& __r, element_type* __p) noexcept
225 : __shared_ptr<_Tp>(__r, __p) { }
226
227 /**
228 * @brief If @a __r is empty, constructs an empty %shared_ptr;
229 * otherwise construct a %shared_ptr that shares ownership
230 * with @a __r.
231 * @param __r A %shared_ptr.
232 * @post get() == __r.get() && use_count() == __r.use_count()
233 */
234 template<typename _Yp,
235 typename = _Constructible<const shared_ptr<_Yp>&>>
236 shared_ptr(const shared_ptr<_Yp>& __r) noexcept
237 : __shared_ptr<_Tp>(__r) { }
238
239 /**
240 * @brief Move-constructs a %shared_ptr instance from @a __r.
241 * @param __r A %shared_ptr rvalue.
242 * @post *this contains the old value of @a __r, @a __r is empty.
243 */
244 shared_ptr(shared_ptr&& __r) noexcept
245 : __shared_ptr<_Tp>(std::move(__r)) { }
246
247 /**
248 * @brief Move-constructs a %shared_ptr instance from @a __r.
249 * @param __r A %shared_ptr rvalue.
250 * @post *this contains the old value of @a __r, @a __r is empty.
251 */
252 template<typename _Yp, typename = _Constructible<shared_ptr<_Yp>>>
253 shared_ptr(shared_ptr<_Yp>&& __r) noexcept
254 : __shared_ptr<_Tp>(std::move(__r)) { }
255
256 /**
257 * @brief Constructs a %shared_ptr that shares ownership with @a __r
258 * and stores a copy of the pointer stored in @a __r.
259 * @param __r A weak_ptr.
260 * @post use_count() == __r.use_count()
261 * @throw bad_weak_ptr when __r.expired(),
262 * in which case the constructor has no effect.
263 */
264 template<typename _Yp, typename = _Constructible<const weak_ptr<_Yp>&>>
265 explicit shared_ptr(const weak_ptr<_Yp>& __r)
266 : __shared_ptr<_Tp>(__r) { }
267
268#if _GLIBCXX_USE_DEPRECATED1
269 template<typename _Yp, typename = _Constructible<auto_ptr<_Yp>>>
270 shared_ptr(auto_ptr<_Yp>&& __r);
271#endif
272
273 // _GLIBCXX_RESOLVE_LIB_DEFECTS
274 // 2399. shared_ptr's constructor from unique_ptr should be constrained
275 template<typename _Yp, typename _Del,
276 typename = _Constructible<unique_ptr<_Yp, _Del>>>
277 shared_ptr(unique_ptr<_Yp, _Del>&& __r)
278 : __shared_ptr<_Tp>(std::move(__r)) { }
279
280#if __cplusplus201103L <= 201402L && _GLIBCXX_USE_DEPRECATED1
281 // This non-standard constructor exists to support conversions that
282 // were possible in C++11 and C++14 but are ill-formed in C++17.
283 // If an exception is thrown this constructor has no effect.
284 template<typename _Yp, typename _Del,
285 _Constructible<unique_ptr<_Yp, _Del>, __sp_array_delete>* = 0>
286 shared_ptr(unique_ptr<_Yp, _Del>&& __r)
287 : __shared_ptr<_Tp>(std::move(__r), __sp_array_delete()) { }
288#endif
289
290 /**
291 * @brief Construct an empty %shared_ptr.
292 * @post use_count() == 0 && get() == nullptr
293 */
294 constexpr shared_ptr(nullptr_t) noexcept : shared_ptr() { }
295
296 shared_ptr& operator=(const shared_ptr&) noexcept = default;
24
Calling defaulted copy assignment operator for '__shared_ptr'
39
Returning; memory was released
55
Calling defaulted copy assignment operator for '__shared_ptr'
297
298 template<typename _Yp>
299 _Assignable<const shared_ptr<_Yp>&>
300 operator=(const shared_ptr<_Yp>& __r) noexcept
301 {
302 this->__shared_ptr<_Tp>::operator=(__r);
303 return *this;
304 }
305
306#if _GLIBCXX_USE_DEPRECATED1
307 template<typename _Yp>
308 _Assignable<auto_ptr<_Yp>>
309 operator=(auto_ptr<_Yp>&& __r)
310 {
311 this->__shared_ptr<_Tp>::operator=(std::move(__r));
312 return *this;
313 }
314#endif
315
316 shared_ptr&
317 operator=(shared_ptr&& __r) noexcept
318 {
319 this->__shared_ptr<_Tp>::operator=(std::move(__r));
320 return *this;
321 }
322
323 template<class _Yp>
324 _Assignable<shared_ptr<_Yp>>
325 operator=(shared_ptr<_Yp>&& __r) noexcept
326 {
327 this->__shared_ptr<_Tp>::operator=(std::move(__r));
328 return *this;
329 }
330
331 template<typename _Yp, typename _Del>
332 _Assignable<unique_ptr<_Yp, _Del>>
333 operator=(unique_ptr<_Yp, _Del>&& __r)
334 {
335 this->__shared_ptr<_Tp>::operator=(std::move(__r));
336 return *this;
337 }
338
339 private:
340 // This constructor is non-standard, it is used by allocate_shared.
341 template<typename _Alloc, typename... _Args>
342 shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
343 _Args&&... __args)
344 : __shared_ptr<_Tp>(__tag, __a, std::forward<_Args>(__args)...)
345 { }
346
347 template<typename _Yp, typename _Alloc, typename... _Args>
348 friend shared_ptr<_Yp>
349 allocate_shared(const _Alloc& __a, _Args&&... __args);
350
351 // This constructor is non-standard, it is used by weak_ptr::lock().
352 shared_ptr(const weak_ptr<_Tp>& __r, std::nothrow_t)
353 : __shared_ptr<_Tp>(__r, std::nothrow) { }
354
355 friend class weak_ptr<_Tp>;
356 };
357
358#if __cpp_deduction_guides >= 201606
359 template<typename _Tp>
360 shared_ptr(weak_ptr<_Tp>) -> shared_ptr<_Tp>;
361 template<typename _Tp, typename _Del>
362 shared_ptr(unique_ptr<_Tp, _Del>) -> shared_ptr<_Tp>;
363#endif
364
365 // 20.7.2.2.7 shared_ptr comparisons
366 template<typename _Tp, typename _Up>
367 inline bool
368 operator==(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
369 { return __a.get() == __b.get(); }
370
371 template<typename _Tp>
372 inline bool
373 operator==(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
374 { return !__a; }
375
376 template<typename _Tp>
377 inline bool
378 operator==(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
379 { return !__a; }
380
381 template<typename _Tp, typename _Up>
382 inline bool
383 operator!=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
384 { return __a.get() != __b.get(); }
385
386 template<typename _Tp>
387 inline bool
388 operator!=(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
389 { return (bool)__a; }
390
391 template<typename _Tp>
392 inline bool
393 operator!=(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
394 { return (bool)__a; }
395
396 template<typename _Tp, typename _Up>
397 inline bool
398 operator<(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
399 {
400 using _Tp_elt = typename shared_ptr<_Tp>::element_type;
401 using _Up_elt = typename shared_ptr<_Up>::element_type;
402 using _Vp = typename common_type<_Tp_elt*, _Up_elt*>::type;
403 return less<_Vp>()(__a.get(), __b.get());
404 }
405
406 template<typename _Tp>
407 inline bool
408 operator<(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
409 {
410 using _Tp_elt = typename shared_ptr<_Tp>::element_type;
411 return less<_Tp_elt*>()(__a.get(), nullptr);
412 }
413
414 template<typename _Tp>
415 inline bool
416 operator<(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
417 {
418 using _Tp_elt = typename shared_ptr<_Tp>::element_type;
419 return less<_Tp_elt*>()(nullptr, __a.get());
420 }
421
422 template<typename _Tp, typename _Up>
423 inline bool
424 operator<=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
425 { return !(__b < __a); }
426
427 template<typename _Tp>
428 inline bool
429 operator<=(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
430 { return !(nullptr < __a); }
431
432 template<typename _Tp>
433 inline bool
434 operator<=(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
435 { return !(__a < nullptr); }
436
437 template<typename _Tp, typename _Up>
438 inline bool
439 operator>(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
440 { return (__b < __a); }
441
442 template<typename _Tp>
443 inline bool
444 operator>(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
445 { return nullptr < __a; }
446
447 template<typename _Tp>
448 inline bool
449 operator>(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
450 { return __a < nullptr; }
451
452 template<typename _Tp, typename _Up>
453 inline bool
454 operator>=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
455 { return !(__a < __b); }
456
457 template<typename _Tp>
458 inline bool
459 operator>=(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
460 { return !(__a < nullptr); }
461
462 template<typename _Tp>
463 inline bool
464 operator>=(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
465 { return !(nullptr < __a); }
466
467 template<typename _Tp>
468 struct less<shared_ptr<_Tp>> : public _Sp_less<shared_ptr<_Tp>>
469 { };
470
471 // 20.7.2.2.8 shared_ptr specialized algorithms.
472 template<typename _Tp>
473 inline void
474 swap(shared_ptr<_Tp>& __a, shared_ptr<_Tp>& __b) noexcept
475 { __a.swap(__b); }
476
477 // 20.7.2.2.9 shared_ptr casts.
478 template<typename _Tp, typename _Up>
479 inline shared_ptr<_Tp>
480 static_pointer_cast(const shared_ptr<_Up>& __r) noexcept
481 {
482 using _Sp = shared_ptr<_Tp>;
483 return _Sp(__r, static_cast<typename _Sp::element_type*>(__r.get()));
484 }
485
486 template<typename _Tp, typename _Up>
487 inline shared_ptr<_Tp>
488 const_pointer_cast(const shared_ptr<_Up>& __r) noexcept
489 {
490 using _Sp = shared_ptr<_Tp>;
491 return _Sp(__r, const_cast<typename _Sp::element_type*>(__r.get()));
492 }
493
494 template<typename _Tp, typename _Up>
495 inline shared_ptr<_Tp>
496 dynamic_pointer_cast(const shared_ptr<_Up>& __r) noexcept
497 {
498 using _Sp = shared_ptr<_Tp>;
499 if (auto* __p = dynamic_cast<typename _Sp::element_type*>(__r.get()))
500 return _Sp(__r, __p);
501 return _Sp();
502 }
503
504#if __cplusplus201103L > 201402L
505 template<typename _Tp, typename _Up>
506 inline shared_ptr<_Tp>
507 reinterpret_pointer_cast(const shared_ptr<_Up>& __r) noexcept
508 {
509 using _Sp = shared_ptr<_Tp>;
510 return _Sp(__r, reinterpret_cast<typename _Sp::element_type*>(__r.get()));
511 }
512#endif
513
514 /**
515 * @brief A smart pointer with weak semantics.
516 *
517 * With forwarding constructors and assignment operators.
518 */
519 template<typename _Tp>
520 class weak_ptr : public __weak_ptr<_Tp>
521 {
522 template<typename _Arg>
523 using _Constructible = typename enable_if<
524 is_constructible<__weak_ptr<_Tp>, _Arg>::value
525 >::type;
526
527 template<typename _Arg>
528 using _Assignable = typename enable_if<
529 is_assignable<__weak_ptr<_Tp>&, _Arg>::value, weak_ptr&
530 >::type;
531
532 public:
533 constexpr weak_ptr() noexcept = default;
534
535 template<typename _Yp,
536 typename = _Constructible<const shared_ptr<_Yp>&>>
537 weak_ptr(const shared_ptr<_Yp>& __r) noexcept
538 : __weak_ptr<_Tp>(__r) { }
539
540 weak_ptr(const weak_ptr&) noexcept = default;
541
542 template<typename _Yp, typename = _Constructible<const weak_ptr<_Yp>&>>
543 weak_ptr(const weak_ptr<_Yp>& __r) noexcept
544 : __weak_ptr<_Tp>(__r) { }
545
546 weak_ptr(weak_ptr&&) noexcept = default;
547
548 template<typename _Yp, typename = _Constructible<weak_ptr<_Yp>>>
549 weak_ptr(weak_ptr<_Yp>&& __r) noexcept
550 : __weak_ptr<_Tp>(std::move(__r)) { }
551
552 weak_ptr&
553 operator=(const weak_ptr& __r) noexcept = default;
554
555 template<typename _Yp>
556 _Assignable<const weak_ptr<_Yp>&>
557 operator=(const weak_ptr<_Yp>& __r) noexcept
558 {
559 this->__weak_ptr<_Tp>::operator=(__r);
560 return *this;
561 }
562
563 template<typename _Yp>
564 _Assignable<const shared_ptr<_Yp>&>
565 operator=(const shared_ptr<_Yp>& __r) noexcept
566 {
567 this->__weak_ptr<_Tp>::operator=(__r);
568 return *this;
569 }
570
571 weak_ptr&
572 operator=(weak_ptr&& __r) noexcept = default;
573
574 template<typename _Yp>
575 _Assignable<weak_ptr<_Yp>>
576 operator=(weak_ptr<_Yp>&& __r) noexcept
577 {
578 this->__weak_ptr<_Tp>::operator=(std::move(__r));
579 return *this;
580 }
581
582 shared_ptr<_Tp>
583 lock() const noexcept
584 { return shared_ptr<_Tp>(*this, std::nothrow); }
585 };
586
587#if __cpp_deduction_guides >= 201606
588 template<typename _Tp>
589 weak_ptr(shared_ptr<_Tp>) -> weak_ptr<_Tp>;
590#endif
591
592 // 20.7.2.3.6 weak_ptr specialized algorithms.
593 template<typename _Tp>
594 inline void
595 swap(weak_ptr<_Tp>& __a, weak_ptr<_Tp>& __b) noexcept
596 { __a.swap(__b); }
597
598
599 /// Primary template owner_less
600 template<typename _Tp = void>
601 struct owner_less;
602
603 /// Void specialization of owner_less
604 template<>
605 struct owner_less<void> : _Sp_owner_less<void, void>
606 { };
607
608 /// Partial specialization of owner_less for shared_ptr.
609 template<typename _Tp>
610 struct owner_less<shared_ptr<_Tp>>
611 : public _Sp_owner_less<shared_ptr<_Tp>, weak_ptr<_Tp>>
612 { };
613
614 /// Partial specialization of owner_less for weak_ptr.
615 template<typename _Tp>
616 struct owner_less<weak_ptr<_Tp>>
617 : public _Sp_owner_less<weak_ptr<_Tp>, shared_ptr<_Tp>>
618 { };
619
620 /**
621 * @brief Base class allowing use of member function shared_from_this.
622 */
623 template<typename _Tp>
624 class enable_shared_from_this
625 {
626 protected:
627 constexpr enable_shared_from_this() noexcept { }
628
629 enable_shared_from_this(const enable_shared_from_this&) noexcept { }
630
631 enable_shared_from_this&
632 operator=(const enable_shared_from_this&) noexcept
633 { return *this; }
634
635 ~enable_shared_from_this() { }
636
637 public:
638 shared_ptr<_Tp>
639 shared_from_this()
640 { return shared_ptr<_Tp>(this->_M_weak_this); }
641
642 shared_ptr<const _Tp>
643 shared_from_this() const
644 { return shared_ptr<const _Tp>(this->_M_weak_this); }
645
646#if __cplusplus201103L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11
647#define __cpp_lib_enable_shared_from_this 201603
648 weak_ptr<_Tp>
649 weak_from_this() noexcept
650 { return this->_M_weak_this; }
651
652 weak_ptr<const _Tp>
653 weak_from_this() const noexcept
654 { return this->_M_weak_this; }
655#endif
656
657 private:
658 template<typename _Tp1>
659 void
660 _M_weak_assign(_Tp1* __p, const __shared_count<>& __n) const noexcept
661 { _M_weak_this._M_assign(__p, __n); }
662
663 // Found by ADL when this is an associated class.
664 friend const enable_shared_from_this*
665 __enable_shared_from_this_base(const __shared_count<>&,
666 const enable_shared_from_this* __p)
667 { return __p; }
668
669 template<typename, _Lock_policy>
670 friend class __shared_ptr;
671
672 mutable weak_ptr<_Tp> _M_weak_this;
673 };
674
675 /**
676 * @brief Create an object that is owned by a shared_ptr.
677 * @param __a An allocator.
678 * @param __args Arguments for the @a _Tp object's constructor.
679 * @return A shared_ptr that owns the newly created object.
680 * @throw An exception thrown from @a _Alloc::allocate or from the
681 * constructor of @a _Tp.
682 *
683 * A copy of @a __a will be used to allocate memory for the shared_ptr
684 * and the new object.
685 */
686 template<typename _Tp, typename _Alloc, typename... _Args>
687 inline shared_ptr<_Tp>
688 allocate_shared(const _Alloc& __a, _Args&&... __args)
689 {
690 return shared_ptr<_Tp>(_Sp_make_shared_tag(), __a,
691 std::forward<_Args>(__args)...);
692 }
693
694 /**
695 * @brief Create an object that is owned by a shared_ptr.
696 * @param __args Arguments for the @a _Tp object's constructor.
697 * @return A shared_ptr that owns the newly created object.
698 * @throw std::bad_alloc, or an exception thrown from the
699 * constructor of @a _Tp.
700 */
701 template<typename _Tp, typename... _Args>
702 inline shared_ptr<_Tp>
703 make_shared(_Args&&... __args)
704 {
705 typedef typename std::remove_const<_Tp>::type _Tp_nc;
706 return std::allocate_shared<_Tp>(std::allocator<_Tp_nc>(),
707 std::forward<_Args>(__args)...);
708 }
709
710 /// std::hash specialization for shared_ptr.
711 template<typename _Tp>
712 struct hash<shared_ptr<_Tp>>
713 : public __hash_base<size_t, shared_ptr<_Tp>>
714 {
715 size_t
716 operator()(const shared_ptr<_Tp>& __s) const noexcept
717 {
718 return std::hash<typename shared_ptr<_Tp>::element_type*>()(__s.get());
719 }
720 };
721
722 // @} group pointer_abstractions
723
724_GLIBCXX_END_NAMESPACE_VERSION
725} // namespace
726
727#endif // _SHARED_PTR_H

/usr/lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/shared_ptr_base.h

1// shared_ptr and weak_ptr implementation details -*- C++ -*-
2
3// Copyright (C) 2007-2017 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25// GCC Note: Based on files from version 1.32.0 of the Boost library.
26
27// shared_count.hpp
28// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.
29
30// shared_ptr.hpp
31// Copyright (C) 1998, 1999 Greg Colvin and Beman Dawes.
32// Copyright (C) 2001, 2002, 2003 Peter Dimov
33
34// weak_ptr.hpp
35// Copyright (C) 2001, 2002, 2003 Peter Dimov
36
37// enable_shared_from_this.hpp
38// Copyright (C) 2002 Peter Dimov
39
40// Distributed under the Boost Software License, Version 1.0. (See
41// accompanying file LICENSE_1_0.txt or copy at
42// http://www.boost.org/LICENSE_1_0.txt)
43
44/** @file bits/shared_ptr_base.h
45 * This is an internal header file, included by other library headers.
46 * Do not attempt to use it directly. @headername{memory}
47 */
48
49#ifndef _SHARED_PTR_BASE_H1
50#define _SHARED_PTR_BASE_H1 1
51
52#if __cpp_rtti199711
53# include <typeinfo>
54#endif
55#include <bits/allocated_ptr.h>
56#include <bits/refwrap.h>
57#include <bits/stl_function.h>
58#include <ext/aligned_buffer.h>
59
60namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default")))
61{
62_GLIBCXX_BEGIN_NAMESPACE_VERSION
63
64#if _GLIBCXX_USE_DEPRECATED1
65 template<typename> class auto_ptr;
66#endif
67
68 /**
69 * @brief Exception possibly thrown by @c shared_ptr.
70 * @ingroup exceptions
71 */
72 class bad_weak_ptr : public std::exception
73 {
74 public:
75 virtual char const* what() const noexcept;
76
77 virtual ~bad_weak_ptr() noexcept;
78 };
79
80 // Substitute for bad_weak_ptr object in the case of -fno-exceptions.
81 inline void
82 __throw_bad_weak_ptr()
83 { _GLIBCXX_THROW_OR_ABORT(bad_weak_ptr())(__builtin_abort()); }
84
85 using __gnu_cxx::_Lock_policy;
86 using __gnu_cxx::__default_lock_policy;
87 using __gnu_cxx::_S_single;
88 using __gnu_cxx::_S_mutex;
89 using __gnu_cxx::_S_atomic;
90
91 // Empty helper class except when the template argument is _S_mutex.
92 template<_Lock_policy _Lp>
93 class _Mutex_base
94 {
95 protected:
96 // The atomic policy uses fully-fenced builtins, single doesn't care.
97 enum { _S_need_barriers = 0 };
98 };
99
100 template<>
101 class _Mutex_base<_S_mutex>
102 : public __gnu_cxx::__mutex
103 {
104 protected:
105 // This policy is used when atomic builtins are not available.
106 // The replacement atomic operations might not have the necessary
107 // memory barriers.
108 enum { _S_need_barriers = 1 };
109 };
110
111 template<_Lock_policy _Lp = __default_lock_policy>
112 class _Sp_counted_base
113 : public _Mutex_base<_Lp>
114 {
115 public:
116 _Sp_counted_base() noexcept
117 : _M_use_count(1), _M_weak_count(1) { }
118
119 virtual
120 ~_Sp_counted_base() noexcept
121 { }
122
123 // Called when _M_use_count drops to zero, to release the resources
124 // managed by *this.
125 virtual void
126 _M_dispose() noexcept = 0;
127
128 // Called when _M_weak_count drops to zero.
129 virtual void
130 _M_destroy() noexcept
131 { delete this; }
35
Memory is released
132
133 virtual void*
134 _M_get_deleter(const std::type_info&) noexcept = 0;
135
136 void
137 _M_add_ref_copy()
138 { __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1); }
139
140 void
141 _M_add_ref_lock();
142
143 bool
144 _M_add_ref_lock_nothrow();
145
146 void
147 _M_release() noexcept
148 {
149 // Be race-detector-friendly. For more info see bits/c++config.
150 _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_use_count);
151 if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1)
31
Taking true branch
61
Calling '__exchange_and_add_dispatch'
152 {
153 _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_use_count);
154 _M_dispose();
155 // There must be a memory barrier between dispose() and destroy()
156 // to ensure that the effects of dispose() are observed in the
157 // thread that runs destroy().
158 // See http://gcc.gnu.org/ml/libstdc++/2005-11/msg00136.html
159 if (_Mutex_base<_Lp>::_S_need_barriers)
32
Taking false branch
160 {
161 __atomic_thread_fence (__ATOMIC_ACQ_REL4);
162 }
163
164 // Be race-detector-friendly. For more info see bits/c++config.
165 _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
166 if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count,
33
Taking true branch
167 -1) == 1)
168 {
169 _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
170 _M_destroy();
34
Calling '_Sp_counted_base::_M_destroy'
36
Returning; memory was released
171 }
172 }
173 }
174
175 void
176 _M_weak_add_ref() noexcept
177 { __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1); }
178
179 void
180 _M_weak_release() noexcept
181 {
182 // Be race-detector-friendly. For more info see bits/c++config.
183 _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
184 if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1)
185 {
186 _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
187 if (_Mutex_base<_Lp>::_S_need_barriers)
188 {
189 // See _M_release(),
190 // destroy() must observe results of dispose()
191 __atomic_thread_fence (__ATOMIC_ACQ_REL4);
192 }
193 _M_destroy();
194 }
195 }
196
197 long
198 _M_get_use_count() const noexcept
199 {
200 // No memory barrier is used here so there is no synchronization
201 // with other threads.
202 return __atomic_load_n(&_M_use_count, __ATOMIC_RELAXED0);
203 }
204
205 private:
206 _Sp_counted_base(_Sp_counted_base const&) = delete;
207 _Sp_counted_base& operator=(_Sp_counted_base const&) = delete;
208
209 _Atomic_word _M_use_count; // #shared
210 _Atomic_word _M_weak_count; // #weak + (#shared != 0)
211 };
212
213 template<>
214 inline void
215 _Sp_counted_base<_S_single>::
216 _M_add_ref_lock()
217 {
218 if (_M_use_count == 0)
219 __throw_bad_weak_ptr();
220 ++_M_use_count;
221 }
222
223 template<>
224 inline void
225 _Sp_counted_base<_S_mutex>::
226 _M_add_ref_lock()
227 {
228 __gnu_cxx::__scoped_lock sentry(*this);
229 if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0)
230 {
231 _M_use_count = 0;
232 __throw_bad_weak_ptr();
233 }
234 }
235
236 template<>
237 inline void
238 _Sp_counted_base<_S_atomic>::
239 _M_add_ref_lock()
240 {
241 // Perform lock-free add-if-not-zero operation.
242 _Atomic_word __count = _M_get_use_count();
243 do
244 {
245 if (__count == 0)
246 __throw_bad_weak_ptr();
247 // Replace the current counter value with the old value + 1, as
248 // long as it's not changed meanwhile.
249 }
250 while (!__atomic_compare_exchange_n(&_M_use_count, &__count, __count + 1,
251 true, __ATOMIC_ACQ_REL4,
252 __ATOMIC_RELAXED0));
253 }
254
255 template<>
256 inline bool
257 _Sp_counted_base<_S_single>::
258 _M_add_ref_lock_nothrow()
259 {
260 if (_M_use_count == 0)
261 return false;
262 ++_M_use_count;
263 return true;
264 }
265
266 template<>
267 inline bool
268 _Sp_counted_base<_S_mutex>::
269 _M_add_ref_lock_nothrow()
270 {
271 __gnu_cxx::__scoped_lock sentry(*this);
272 if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0)
273 {
274 _M_use_count = 0;
275 return false;
276 }
277 return true;
278 }
279
280 template<>
281 inline bool
282 _Sp_counted_base<_S_atomic>::
283 _M_add_ref_lock_nothrow()
284 {
285 // Perform lock-free add-if-not-zero operation.
286 _Atomic_word __count = _M_get_use_count();
287 do
288 {
289 if (__count == 0)
290 return false;
291 // Replace the current counter value with the old value + 1, as
292 // long as it's not changed meanwhile.
293 }
294 while (!__atomic_compare_exchange_n(&_M_use_count, &__count, __count + 1,
295 true, __ATOMIC_ACQ_REL4,
296 __ATOMIC_RELAXED0));
297 return true;
298 }
299
300 template<>
301 inline void
302 _Sp_counted_base<_S_single>::_M_add_ref_copy()
303 { ++_M_use_count; }
304
305 template<>
306 inline void
307 _Sp_counted_base<_S_single>::_M_release() noexcept
308 {
309 if (--_M_use_count == 0)
310 {
311 _M_dispose();
312 if (--_M_weak_count == 0)
313 _M_destroy();
314 }
315 }
316
317 template<>
318 inline void
319 _Sp_counted_base<_S_single>::_M_weak_add_ref() noexcept
320 { ++_M_weak_count; }
321
322 template<>
323 inline void
324 _Sp_counted_base<_S_single>::_M_weak_release() noexcept
325 {
326 if (--_M_weak_count == 0)
327 _M_destroy();
328 }
329
330 template<>
331 inline long
332 _Sp_counted_base<_S_single>::_M_get_use_count() const noexcept
333 { return _M_use_count; }
334
335
336 // Forward declarations.
337 template<typename _Tp, _Lock_policy _Lp = __default_lock_policy>
338 class __shared_ptr;
339
340 template<typename _Tp, _Lock_policy _Lp = __default_lock_policy>
341 class __weak_ptr;
342
343 template<typename _Tp, _Lock_policy _Lp = __default_lock_policy>
344 class __enable_shared_from_this;
345
346 template<typename _Tp>
347 class shared_ptr;
348
349 template<typename _Tp>
350 class weak_ptr;
351
352 template<typename _Tp>
353 struct owner_less;
354
355 template<typename _Tp>
356 class enable_shared_from_this;
357
358 template<_Lock_policy _Lp = __default_lock_policy>
359 class __weak_count;
360
361 template<_Lock_policy _Lp = __default_lock_policy>
362 class __shared_count;
363
364
365 // Counted ptr with no deleter or allocator support
366 template<typename _Ptr, _Lock_policy _Lp>
367 class _Sp_counted_ptr final : public _Sp_counted_base<_Lp>
368 {
369 public:
370 explicit
371 _Sp_counted_ptr(_Ptr __p) noexcept
372 : _M_ptr(__p) { }
373
374 virtual void
375 _M_dispose() noexcept
376 { delete _M_ptr; }
377
378 virtual void
379 _M_destroy() noexcept
380 { delete this; }
381
382 virtual void*
383 _M_get_deleter(const std::type_info&) noexcept
384 { return nullptr; }
385
386 _Sp_counted_ptr(const _Sp_counted_ptr&) = delete;
387 _Sp_counted_ptr& operator=(const _Sp_counted_ptr&) = delete;
388
389 private:
390 _Ptr _M_ptr;
391 };
392
393 template<>
394 inline void
395 _Sp_counted_ptr<nullptr_t, _S_single>::_M_dispose() noexcept { }
396
397 template<>
398 inline void
399 _Sp_counted_ptr<nullptr_t, _S_mutex>::_M_dispose() noexcept { }
400
401 template<>
402 inline void
403 _Sp_counted_ptr<nullptr_t, _S_atomic>::_M_dispose() noexcept { }
404
405 template<int _Nm, typename _Tp,
406 bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)>
407 struct _Sp_ebo_helper;
408
409 /// Specialization using EBO.
410 template<int _Nm, typename _Tp>
411 struct _Sp_ebo_helper<_Nm, _Tp, true> : private _Tp
412 {
413 explicit _Sp_ebo_helper(const _Tp& __tp) : _Tp(__tp) { }
414 explicit _Sp_ebo_helper(_Tp&& __tp) : _Tp(std::move(__tp)) { }
415
416 static _Tp&
417 _S_get(_Sp_ebo_helper& __eboh) { return static_cast<_Tp&>(__eboh); }
418 };
419
420 /// Specialization not using EBO.
421 template<int _Nm, typename _Tp>
422 struct _Sp_ebo_helper<_Nm, _Tp, false>
423 {
424 explicit _Sp_ebo_helper(const _Tp& __tp) : _M_tp(__tp) { }
425 explicit _Sp_ebo_helper(_Tp&& __tp) : _M_tp(std::move(__tp)) { }
426
427 static _Tp&
428 _S_get(_Sp_ebo_helper& __eboh)
429 { return __eboh._M_tp; }
430
431 private:
432 _Tp _M_tp;
433 };
434
435 // Support for custom deleter and/or allocator
436 template<typename _Ptr, typename _Deleter, typename _Alloc, _Lock_policy _Lp>
437 class _Sp_counted_deleter final : public _Sp_counted_base<_Lp>
438 {
439 class _Impl : _Sp_ebo_helper<0, _Deleter>, _Sp_ebo_helper<1, _Alloc>
440 {
441 typedef _Sp_ebo_helper<0, _Deleter> _Del_base;
442 typedef _Sp_ebo_helper<1, _Alloc> _Alloc_base;
443
444 public:
445 _Impl(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept
446 : _M_ptr(__p), _Del_base(std::move(__d)), _Alloc_base(__a)
447 { }
448
449 _Deleter& _M_del() noexcept { return _Del_base::_S_get(*this); }
450 _Alloc& _M_alloc() noexcept { return _Alloc_base::_S_get(*this); }
451
452 _Ptr _M_ptr;
453 };
454
455 public:
456 using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_deleter>;
457
458 // __d(__p) must not throw.
459 _Sp_counted_deleter(_Ptr __p, _Deleter __d) noexcept
460 : _M_impl(__p, std::move(__d), _Alloc()) { }
461
462 // __d(__p) must not throw.
463 _Sp_counted_deleter(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept
464 : _M_impl(__p, std::move(__d), __a) { }
465
466 ~_Sp_counted_deleter() noexcept { }
467
468 virtual void
469 _M_dispose() noexcept
470 { _M_impl._M_del()(_M_impl._M_ptr); }
471
472 virtual void
473 _M_destroy() noexcept
474 {
475 __allocator_type __a(_M_impl._M_alloc());
476 __allocated_ptr<__allocator_type> __guard_ptr{ __a, this };
477 this->~_Sp_counted_deleter();
478 }
479
480 virtual void*
481 _M_get_deleter(const std::type_info& __ti) noexcept
482 {
483#if __cpp_rtti199711
484 // _GLIBCXX_RESOLVE_LIB_DEFECTS
485 // 2400. shared_ptr's get_deleter() should use addressof()
486 return __ti == typeid(_Deleter)
487 ? std::__addressof(_M_impl._M_del())
488 : nullptr;
489#else
490 return nullptr;
491#endif
492 }
493
494 private:
495 _Impl _M_impl;
496 };
497
498 // helpers for make_shared / allocate_shared
499
500 struct _Sp_make_shared_tag { };
501
502 template<typename _Tp, typename _Alloc, _Lock_policy _Lp>
503 class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp>
504 {
505 class _Impl : _Sp_ebo_helper<0, _Alloc>
506 {
507 typedef _Sp_ebo_helper<0, _Alloc> _A_base;
508
509 public:
510 explicit _Impl(_Alloc __a) noexcept : _A_base(__a) { }
511
512 _Alloc& _M_alloc() noexcept { return _A_base::_S_get(*this); }
513
514 __gnu_cxx::__aligned_buffer<_Tp> _M_storage;
515 };
516
517 public:
518 using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_ptr_inplace>;
519
520 template<typename... _Args>
521 _Sp_counted_ptr_inplace(_Alloc __a, _Args&&... __args)
522 : _M_impl(__a)
523 {
524 // _GLIBCXX_RESOLVE_LIB_DEFECTS
525 // 2070. allocate_shared should use allocator_traits<A>::construct
526 allocator_traits<_Alloc>::construct(__a, _M_ptr(),
527 std::forward<_Args>(__args)...); // might throw
528 }
529
530 ~_Sp_counted_ptr_inplace() noexcept { }
531
532 virtual void
533 _M_dispose() noexcept
534 {
535 allocator_traits<_Alloc>::destroy(_M_impl._M_alloc(), _M_ptr());
536 }
537
538 // Override because the allocator needs to know the dynamic type
539 virtual void
540 _M_destroy() noexcept
541 {
542 __allocator_type __a(_M_impl._M_alloc());
543 __allocated_ptr<__allocator_type> __guard_ptr{ __a, this };
544 this->~_Sp_counted_ptr_inplace();
545 }
546
547 // Sneaky trick so __shared_ptr can get the managed pointer
548 virtual void*
549 _M_get_deleter(const std::type_info& __ti) noexcept
550 {
551#if __cpp_rtti199711
552 if (__ti == typeid(_Sp_make_shared_tag))
553 return const_cast<typename remove_cv<_Tp>::type*>(_M_ptr());
554#endif
555 return nullptr;
556 }
557
558 private:
559 _Tp* _M_ptr() noexcept { return _M_impl._M_storage._M_ptr(); }
560
561 _Impl _M_impl;
562 };
563
564 // The default deleter for shared_ptr<T[]> and shared_ptr<T[N]>.
565 struct __sp_array_delete
566 {
567 template<typename _Yp>
568 void operator()(_Yp* __p) const { delete[] __p; }
569 };
570
571 template<_Lock_policy _Lp>
572 class __shared_count
573 {
574 public:
575 constexpr __shared_count() noexcept : _M_pi(0)
576 { }
577
578 template<typename _Ptr>
579 explicit
580 __shared_count(_Ptr __p) : _M_pi(0)
581 {
582 __tryif (true)
583 {
584 _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);
585 }
586 __catch(...)if (false)
587 {
588 delete __p;
589 __throw_exception_again;
590 }
591 }
592
593 template<typename _Ptr>
594 __shared_count(_Ptr __p, /* is_array = */ false_type)
595 : __shared_count(__p)
596 { }
597
598 template<typename _Ptr>
599 __shared_count(_Ptr __p, /* is_array = */ true_type)
600 : __shared_count(__p, __sp_array_delete{}, allocator<void>())
601 { }
602
603 template<typename _Ptr, typename _Deleter>
604 __shared_count(_Ptr __p, _Deleter __d)
605 : __shared_count(__p, std::move(__d), allocator<void>())
606 { }
607
608 template<typename _Ptr, typename _Deleter, typename _Alloc>
609 __shared_count(_Ptr __p, _Deleter __d, _Alloc __a) : _M_pi(0)
610 {
611 typedef _Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp> _Sp_cd_type;
612 __tryif (true)
613 {
614 typename _Sp_cd_type::__allocator_type __a2(__a);
615 auto __guard = std::__allocate_guarded(__a2);
616 _Sp_cd_type* __mem = __guard.get();
617 ::new (__mem) _Sp_cd_type(__p, std::move(__d), std::move(__a));
618 _M_pi = __mem;
619 __guard = nullptr;
620 }
621 __catch(...)if (false)
622 {
623 __d(__p); // Call _Deleter on __p.
624 __throw_exception_again;
625 }
626 }
627
628 template<typename _Tp, typename _Alloc, typename... _Args>
629 __shared_count(_Sp_make_shared_tag, _Tp*, const _Alloc& __a,
630 _Args&&... __args)
631 : _M_pi(0)
632 {
633 typedef _Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp> _Sp_cp_type;
634 typename _Sp_cp_type::__allocator_type __a2(__a);
635 auto __guard = std::__allocate_guarded(__a2);
636 _Sp_cp_type* __mem = __guard.get();
637 ::new (__mem) _Sp_cp_type(std::move(__a),
638 std::forward<_Args>(__args)...);
639 _M_pi = __mem;
640 __guard = nullptr;
641 }
642
643#if _GLIBCXX_USE_DEPRECATED1
644 // Special case for auto_ptr<_Tp> to provide the strong guarantee.
645 template<typename _Tp>
646 explicit
647 __shared_count(std::auto_ptr<_Tp>&& __r);
648#endif
649
650 // Special case for unique_ptr<_Tp,_Del> to provide the strong guarantee.
651 template<typename _Tp, typename _Del>
652 explicit
653 __shared_count(std::unique_ptr<_Tp, _Del>&& __r) : _M_pi(0)
654 {
655 // _GLIBCXX_RESOLVE_LIB_DEFECTS
656 // 2415. Inconsistency between unique_ptr and shared_ptr
657 if (__r.get() == nullptr)
658 return;
659
660 using _Ptr = typename unique_ptr<_Tp, _Del>::pointer;
661 using _Del2 = typename conditional<is_reference<_Del>::value,
662 reference_wrapper<typename remove_reference<_Del>::type>,
663 _Del>::type;
664 using _Sp_cd_type
665 = _Sp_counted_deleter<_Ptr, _Del2, allocator<void>, _Lp>;
666 using _Alloc = allocator<_Sp_cd_type>;
667 using _Alloc_traits = allocator_traits<_Alloc>;
668 _Alloc __a;
669 _Sp_cd_type* __mem = _Alloc_traits::allocate(__a, 1);
670 _Alloc_traits::construct(__a, __mem, __r.release(),
671 __r.get_deleter()); // non-throwing
672 _M_pi = __mem;
673 }
674
675 // Throw bad_weak_ptr when __r._M_get_use_count() == 0.
676 explicit __shared_count(const __weak_count<_Lp>& __r);
677
678 // Does not throw if __r._M_get_use_count() == 0, caller must check.
679 explicit __shared_count(const __weak_count<_Lp>& __r, std::nothrow_t);
680
681 ~__shared_count() noexcept
682 {
683 if (_M_pi != nullptr)
684 _M_pi->_M_release();
685 }
686
687 __shared_count(const __shared_count& __r) noexcept
688 : _M_pi(__r._M_pi)
689 {
690 if (_M_pi != 0)
691 _M_pi->_M_add_ref_copy();
692 }
693
694 __shared_count&
695 operator=(const __shared_count& __r) noexcept
696 {
697 _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
698 if (__tmp != _M_pi)
26
Taking true branch
57
Taking true branch
699 {
700 if (__tmp != 0)
27
Assuming '__tmp' is equal to null
28
Taking false branch
58
Taking false branch
701 __tmp->_M_add_ref_copy();
702 if (_M_pi != 0)
29
Taking true branch
59
Taking true branch
703 _M_pi->_M_release();
30
Calling '_Sp_counted_base::_M_release'
37
Returning; memory was released
60
Calling '_Sp_counted_base::_M_release'
704 _M_pi = __tmp;
705 }
706 return *this;
707 }
708
709 void
710 _M_swap(__shared_count& __r) noexcept
711 {
712 _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
713 __r._M_pi = _M_pi;
714 _M_pi = __tmp;
715 }
716
717 long
718 _M_get_use_count() const noexcept
719 { return _M_pi != 0 ? _M_pi->_M_get_use_count() : 0; }
720
721 bool
722 _M_unique() const noexcept
723 { return this->_M_get_use_count() == 1; }
724
725 void*
726 _M_get_deleter(const std::type_info& __ti) const noexcept
727 { return _M_pi ? _M_pi->_M_get_deleter(__ti) : nullptr; }
728
729 bool
730 _M_less(const __shared_count& __rhs) const noexcept
731 { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); }
732
733 bool
734 _M_less(const __weak_count<_Lp>& __rhs) const noexcept
735 { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); }
736
737 // Friend function injected into enclosing namespace and found by ADL
738 friend inline bool
739 operator==(const __shared_count& __a, const __shared_count& __b) noexcept
740 { return __a._M_pi == __b._M_pi; }
741
742 private:
743 friend class __weak_count<_Lp>;
744
745 _Sp_counted_base<_Lp>* _M_pi;
746 };
747
748
749 template<_Lock_policy _Lp>
750 class __weak_count
751 {
752 public:
753 constexpr __weak_count() noexcept : _M_pi(nullptr)
754 { }
755
756 __weak_count(const __shared_count<_Lp>& __r) noexcept
757 : _M_pi(__r._M_pi)
758 {
759 if (_M_pi != nullptr)
760 _M_pi->_M_weak_add_ref();
761 }
762
763 __weak_count(const __weak_count& __r) noexcept
764 : _M_pi(__r._M_pi)
765 {
766 if (_M_pi != nullptr)
767 _M_pi->_M_weak_add_ref();
768 }
769
770 __weak_count(__weak_count&& __r) noexcept
771 : _M_pi(__r._M_pi)
772 { __r._M_pi = nullptr; }
773
774 ~__weak_count() noexcept
775 {
776 if (_M_pi != nullptr)
777 _M_pi->_M_weak_release();
778 }
779
780 __weak_count&
781 operator=(const __shared_count<_Lp>& __r) noexcept
782 {
783 _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
784 if (__tmp != nullptr)
785 __tmp->_M_weak_add_ref();
786 if (_M_pi != nullptr)
787 _M_pi->_M_weak_release();
788 _M_pi = __tmp;
789 return *this;
790 }
791
792 __weak_count&
793 operator=(const __weak_count& __r) noexcept
794 {
795 _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
796 if (__tmp != nullptr)
797 __tmp->_M_weak_add_ref();
798 if (_M_pi != nullptr)
799 _M_pi->_M_weak_release();
800 _M_pi = __tmp;
801 return *this;
802 }
803
804 __weak_count&
805 operator=(__weak_count&& __r) noexcept
806 {
807 if (_M_pi != nullptr)
808 _M_pi->_M_weak_release();
809 _M_pi = __r._M_pi;
810 __r._M_pi = nullptr;
811 return *this;
812 }
813
814 void
815 _M_swap(__weak_count& __r) noexcept
816 {
817 _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
818 __r._M_pi = _M_pi;
819 _M_pi = __tmp;
820 }
821
822 long
823 _M_get_use_count() const noexcept
824 { return _M_pi != nullptr ? _M_pi->_M_get_use_count() : 0; }
825
826 bool
827 _M_less(const __weak_count& __rhs) const noexcept
828 { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); }
829
830 bool
831 _M_less(const __shared_count<_Lp>& __rhs) const noexcept
832 { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); }
833
834 // Friend function injected into enclosing namespace and found by ADL
835 friend inline bool
836 operator==(const __weak_count& __a, const __weak_count& __b) noexcept
837 { return __a._M_pi == __b._M_pi; }
838
839 private:
840 friend class __shared_count<_Lp>;
841
842 _Sp_counted_base<_Lp>* _M_pi;
843 };
844
845 // Now that __weak_count is defined we can define this constructor:
846 template<_Lock_policy _Lp>
847 inline
848 __shared_count<_Lp>::__shared_count(const __weak_count<_Lp>& __r)
849 : _M_pi(__r._M_pi)
850 {
851 if (_M_pi != nullptr)
852 _M_pi->_M_add_ref_lock();
853 else
854 __throw_bad_weak_ptr();
855 }
856
857 // Now that __weak_count is defined we can define this constructor:
858 template<_Lock_policy _Lp>
859 inline
860 __shared_count<_Lp>::
861 __shared_count(const __weak_count<_Lp>& __r, std::nothrow_t)
862 : _M_pi(__r._M_pi)
863 {
864 if (_M_pi != nullptr)
865 if (!_M_pi->_M_add_ref_lock_nothrow())
866 _M_pi = nullptr;
867 }
868
869#define __cpp_lib_shared_ptr_arrays201603 201603
870
871 // Helper traits for shared_ptr of array:
872
873 // A pointer type Y* is said to be compatible with a pointer type T* when
874 // either Y* is convertible to T* or Y is U[N] and T is U cv [].
875 template<typename _Yp_ptr, typename _Tp_ptr>
876 struct __sp_compatible_with
877 : false_type
878 { };
879
880 template<typename _Yp, typename _Tp>
881 struct __sp_compatible_with<_Yp*, _Tp*>
882 : is_convertible<_Yp*, _Tp*>::type
883 { };
884
885 template<typename _Up, size_t _Nm>
886 struct __sp_compatible_with<_Up(*)[_Nm], _Up(*)[]>
887 : true_type
888 { };
889
890 template<typename _Up, size_t _Nm>
891 struct __sp_compatible_with<_Up(*)[_Nm], const _Up(*)[]>
892 : true_type
893 { };
894
895 template<typename _Up, size_t _Nm>
896 struct __sp_compatible_with<_Up(*)[_Nm], volatile _Up(*)[]>
897 : true_type
898 { };
899
900 template<typename _Up, size_t _Nm>
901 struct __sp_compatible_with<_Up(*)[_Nm], const volatile _Up(*)[]>
902 : true_type
903 { };
904
905 // Test conversion from Y(*)[N] to U(*)[N] without forming invalid type Y[N].
906 template<typename _Up, size_t _Nm, typename _Yp, typename = void>
907 struct __sp_is_constructible_arrN
908 : false_type
909 { };
910
911 template<typename _Up, size_t _Nm, typename _Yp>
912 struct __sp_is_constructible_arrN<_Up, _Nm, _Yp, __void_t<_Yp[_Nm]>>
913 : is_convertible<_Yp(*)[_Nm], _Up(*)[_Nm]>::type
914 { };
915
916 // Test conversion from Y(*)[] to U(*)[] without forming invalid type Y[].
917 template<typename _Up, typename _Yp, typename = void>
918 struct __sp_is_constructible_arr
919 : false_type
920 { };
921
922 template<typename _Up, typename _Yp>
923 struct __sp_is_constructible_arr<_Up, _Yp, __void_t<_Yp[]>>
924 : is_convertible<_Yp(*)[], _Up(*)[]>::type
925 { };
926
927 // Trait to check if shared_ptr<T> can be constructed from Y*.
928 template<typename _Tp, typename _Yp>
929 struct __sp_is_constructible;
930
931 // When T is U[N], Y(*)[N] shall be convertible to T*;
932 template<typename _Up, size_t _Nm, typename _Yp>
933 struct __sp_is_constructible<_Up[_Nm], _Yp>
934 : __sp_is_constructible_arrN<_Up, _Nm, _Yp>::type
935 { };
936
937 // when T is U[], Y(*)[] shall be convertible to T*;
938 template<typename _Up, typename _Yp>
939 struct __sp_is_constructible<_Up[], _Yp>
940 : __sp_is_constructible_arr<_Up, _Yp>::type
941 { };
942
943 // otherwise, Y* shall be convertible to T*.
944 template<typename _Tp, typename _Yp>
945 struct __sp_is_constructible
946 : is_convertible<_Yp*, _Tp*>::type
947 { };
948
949
950 // Define operator* and operator-> for shared_ptr<T>.
951 template<typename _Tp, _Lock_policy _Lp,
952 bool = is_array<_Tp>::value, bool = is_void<_Tp>::value>
953 class __shared_ptr_access
954 {
955 public:
956 using element_type = _Tp;
957
958 element_type&
959 operator*() const noexcept
960 {
961 __glibcxx_assert(_M_get() != nullptr);
962 return *_M_get();
963 }
964
965 element_type*
966 operator->() const noexcept
967 {
968 _GLIBCXX_DEBUG_PEDASSERT(_M_get() != nullptr);
969 return _M_get();
970 }
971
972 private:
973 element_type*
974 _M_get() const noexcept
975 { return static_cast<const __shared_ptr<_Tp, _Lp>*>(this)->get(); }
976 };
977
978 // Define operator-> for shared_ptr<cv void>.
979 template<typename _Tp, _Lock_policy _Lp>
980 class __shared_ptr_access<_Tp, _Lp, false, true>
981 {
982 public:
983 using element_type = _Tp;
984
985 element_type*
986 operator->() const noexcept
987 {
988 auto __ptr = static_cast<const __shared_ptr<_Tp, _Lp>*>(this)->get();
989 _GLIBCXX_DEBUG_PEDASSERT(__ptr != nullptr);
990 return __ptr;
991 }
992 };
993
994 // Define operator[] for shared_ptr<T[]> and shared_ptr<T[N]>.
995 template<typename _Tp, _Lock_policy _Lp>
996 class __shared_ptr_access<_Tp, _Lp, true, false>
997 {
998 public:
999 using element_type = typename remove_extent<_Tp>::type;
1000
1001#if __cplusplus201103L <= 201402L
1002 [[__deprecated__("shared_ptr<T[]>::operator* is absent from C++17")]]
1003 element_type&
1004 operator*() const noexcept
1005 {
1006 __glibcxx_assert(_M_get() != nullptr);
1007 return *_M_get();
1008 }
1009
1010 [[__deprecated__("shared_ptr<T[]>::operator-> is absent from C++17")]]
1011 element_type*
1012 operator->() const noexcept
1013 {
1014 _GLIBCXX_DEBUG_PEDASSERT(_M_get() != nullptr);
1015 return _M_get();
1016 }
1017#endif
1018
1019 element_type&
1020 operator[](ptrdiff_t __i) const
1021 {
1022 __glibcxx_assert(_M_get() != nullptr);
1023 __glibcxx_assert(!extent<_Tp>::value || __i < extent<_Tp>::value);
1024 return _M_get()[__i];
1025 }
1026
1027 private:
1028 element_type*
1029 _M_get() const noexcept
1030 { return static_cast<const __shared_ptr<_Tp, _Lp>*>(this)->get(); }
1031 };
1032
1033 template<typename _Tp, _Lock_policy _Lp>
1034 class __shared_ptr
1035 : public __shared_ptr_access<_Tp, _Lp>
1036 {
1037 public:
1038 using element_type = typename remove_extent<_Tp>::type;
1039
1040 private:
1041 // Constraint for taking ownership of a pointer of type _Yp*:
1042 template<typename _Yp>
1043 using _SafeConv
1044 = typename enable_if<__sp_is_constructible<_Tp, _Yp>::value>::type;
1045
1046 // Constraint for construction from shared_ptr and weak_ptr:
1047 template<typename _Yp, typename _Res = void>
1048 using _Compatible = typename
1049 enable_if<__sp_compatible_with<_Yp*, _Tp*>::value, _Res>::type;
1050
1051 // Constraint for assignment from shared_ptr and weak_ptr:
1052 template<typename _Yp>
1053 using _Assignable = _Compatible<_Yp, __shared_ptr&>;
1054
1055 // Constraint for construction from unique_ptr:
1056 template<typename _Yp, typename _Del, typename _Res = void,
1057 typename _Ptr = typename unique_ptr<_Yp, _Del>::pointer>
1058 using _UniqCompatible = typename enable_if<__and_<
1059 __sp_compatible_with<_Yp*, _Tp*>, is_convertible<_Ptr, element_type*>
1060 >::value, _Res>::type;
1061
1062 // Constraint for assignment from unique_ptr:
1063 template<typename _Yp, typename _Del>
1064 using _UniqAssignable = _UniqCompatible<_Yp, _Del, __shared_ptr&>;
1065
1066 public:
1067
1068#if __cplusplus201103L > 201402L
1069 using weak_type = __weak_ptr<_Tp, _Lp>;
1070#endif
1071
1072 constexpr __shared_ptr() noexcept
1073 : _M_ptr(0), _M_refcount()
1074 { }
1075
1076 template<typename _Yp, typename = _SafeConv<_Yp>>
1077 explicit
1078 __shared_ptr(_Yp* __p)
1079 : _M_ptr(__p), _M_refcount(__p, typename is_array<_Tp>::type())
1080 {
1081 static_assert( !is_void<_Yp>::value, "incomplete type" );
1082 static_assert( sizeof(_Yp) > 0, "incomplete type" );
1083 _M_enable_shared_from_this_with(__p);
1084 }
1085
1086 template<typename _Yp, typename _Deleter, typename = _SafeConv<_Yp>>
1087 __shared_ptr(_Yp* __p, _Deleter __d)
1088 : _M_ptr(__p), _M_refcount(__p, std::move(__d))
1089 {
1090 static_assert(__is_invocable<_Deleter&, _Yp*&>::value,
1091 "deleter expression d(p) is well-formed");
1092 _M_enable_shared_from_this_with(__p);
1093 }
1094
1095 template<typename _Yp, typename _Deleter, typename _Alloc,
1096 typename = _SafeConv<_Yp>>
1097 __shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a)
1098 : _M_ptr(__p), _M_refcount(__p, std::move(__d), std::move(__a))
1099 {
1100 static_assert(__is_invocable<_Deleter&, _Yp*&>::value,
1101 "deleter expression d(p) is well-formed");
1102 _M_enable_shared_from_this_with(__p);
1103 }
1104
1105 template<typename _Deleter>
1106 __shared_ptr(nullptr_t __p, _Deleter __d)
1107 : _M_ptr(0), _M_refcount(__p, std::move(__d))
1108 { }
1109
1110 template<typename _Deleter, typename _Alloc>
1111 __shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a)
1112 : _M_ptr(0), _M_refcount(__p, std::move(__d), std::move(__a))
1113 { }
1114
1115 template<typename _Yp>
1116 __shared_ptr(const __shared_ptr<_Yp, _Lp>& __r,
1117 element_type* __p) noexcept
1118 : _M_ptr(__p), _M_refcount(__r._M_refcount) // never throws
1119 { }
1120
1121 __shared_ptr(const __shared_ptr&) noexcept = default;
1122 __shared_ptr& operator=(const __shared_ptr&) noexcept = default;
25
Calling copy assignment operator for '__shared_count'
38
Returning; memory was released
56
Calling copy assignment operator for '__shared_count'
1123 ~__shared_ptr() = default;
1124
1125 template<typename _Yp, typename = _Compatible<_Yp>>
1126 __shared_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept
1127 : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount)
1128 { }
1129
1130 __shared_ptr(__shared_ptr&& __r) noexcept
1131 : _M_ptr(__r._M_ptr), _M_refcount()
1132 {
1133 _M_refcount._M_swap(__r._M_refcount);
1134 __r._M_ptr = 0;
1135 }
1136
1137 template<typename _Yp, typename = _Compatible<_Yp>>
1138 __shared_ptr(__shared_ptr<_Yp, _Lp>&& __r) noexcept
1139 : _M_ptr(__r._M_ptr), _M_refcount()
1140 {
1141 _M_refcount._M_swap(__r._M_refcount);
1142 __r._M_ptr = 0;
1143 }
1144
1145 template<typename _Yp, typename = _Compatible<_Yp>>
1146 explicit __shared_ptr(const __weak_ptr<_Yp, _Lp>& __r)
1147 : _M_refcount(__r._M_refcount) // may throw
1148 {
1149 // It is now safe to copy __r._M_ptr, as
1150 // _M_refcount(__r._M_refcount) did not throw.
1151 _M_ptr = __r._M_ptr;
1152 }
1153
1154 // If an exception is thrown this constructor has no effect.
1155 template<typename _Yp, typename _Del,
1156 typename = _UniqCompatible<_Yp, _Del>>
1157 __shared_ptr(unique_ptr<_Yp, _Del>&& __r)
1158 : _M_ptr(__r.get()), _M_refcount()
1159 {
1160 auto __raw = _S_raw_ptr(__r.get());
1161 _M_refcount = __shared_count<_Lp>(std::move(__r));
1162 _M_enable_shared_from_this_with(__raw);
1163 }
1164
1165#if __cplusplus201103L <= 201402L && _GLIBCXX_USE_DEPRECATED1
1166 protected:
1167 // If an exception is thrown this constructor has no effect.
1168 template<typename _Tp1, typename _Del,
1169 typename enable_if<__and_<
1170 __not_<is_array<_Tp>>, is_array<_Tp1>,
1171 is_convertible<typename unique_ptr<_Tp1, _Del>::pointer, _Tp*>
1172 >::value, bool>::type = true>
1173 __shared_ptr(unique_ptr<_Tp1, _Del>&& __r, __sp_array_delete)
1174 : _M_ptr(__r.get()), _M_refcount()
1175 {
1176 auto __raw = _S_raw_ptr(__r.get());
1177 _M_refcount = __shared_count<_Lp>(std::move(__r));
1178 _M_enable_shared_from_this_with(__raw);
1179 }
1180 public:
1181#endif
1182
1183#if _GLIBCXX_USE_DEPRECATED1
1184 // Postcondition: use_count() == 1 and __r.get() == 0
1185 template<typename _Yp, typename = _Compatible<_Yp>>
1186 __shared_ptr(auto_ptr<_Yp>&& __r);
1187#endif
1188
1189 constexpr __shared_ptr(nullptr_t) noexcept : __shared_ptr() { }
1190
1191 template<typename _Yp>
1192 _Assignable<_Yp>
1193 operator=(const __shared_ptr<_Yp, _Lp>& __r) noexcept
1194 {
1195 _M_ptr = __r._M_ptr;
1196 _M_refcount = __r._M_refcount; // __shared_count::op= doesn't throw
1197 return *this;
1198 }
1199
1200#if _GLIBCXX_USE_DEPRECATED1
1201 template<typename _Yp>
1202 _Assignable<_Yp>
1203 operator=(auto_ptr<_Yp>&& __r)
1204 {
1205 __shared_ptr(std::move(__r)).swap(*this);
1206 return *this;
1207 }
1208#endif
1209
1210 __shared_ptr&
1211 operator=(__shared_ptr&& __r) noexcept
1212 {
1213 __shared_ptr(std::move(__r)).swap(*this);
1214 return *this;
1215 }
1216
1217 template<class _Yp>
1218 _Assignable<_Yp>
1219 operator=(__shared_ptr<_Yp, _Lp>&& __r) noexcept
1220 {
1221 __shared_ptr(std::move(__r)).swap(*this);
1222 return *this;
1223 }
1224
1225 template<typename _Yp, typename _Del>
1226 _UniqAssignable<_Yp, _Del>
1227 operator=(unique_ptr<_Yp, _Del>&& __r)
1228 {
1229 __shared_ptr(std::move(__r)).swap(*this);
1230 return *this;
1231 }
1232
1233 void
1234 reset() noexcept
1235 { __shared_ptr().swap(*this); }
1236
1237 template<typename _Yp>
1238 _SafeConv<_Yp>
1239 reset(_Yp* __p) // _Yp must be complete.
1240 {
1241 // Catch self-reset errors.
1242 __glibcxx_assert(__p == 0 || __p != _M_ptr);
1243 __shared_ptr(__p).swap(*this);
1244 }
1245
1246 template<typename _Yp, typename _Deleter>
1247 _SafeConv<_Yp>
1248 reset(_Yp* __p, _Deleter __d)
1249 { __shared_ptr(__p, std::move(__d)).swap(*this); }
1250
1251 template<typename _Yp, typename _Deleter, typename _Alloc>
1252 _SafeConv<_Yp>
1253 reset(_Yp* __p, _Deleter __d, _Alloc __a)
1254 { __shared_ptr(__p, std::move(__d), std::move(__a)).swap(*this); }
1255
1256 element_type*
1257 get() const noexcept
1258 { return _M_ptr; }
1259
1260 explicit operator bool() const // never throws
1261 { return _M_ptr == 0 ? false : true; }
1262
1263 bool
1264 unique() const noexcept
1265 { return _M_refcount._M_unique(); }
1266
1267 long
1268 use_count() const noexcept
1269 { return _M_refcount._M_get_use_count(); }
1270
1271 void
1272 swap(__shared_ptr<_Tp, _Lp>& __other) noexcept
1273 {
1274 std::swap(_M_ptr, __other._M_ptr);
1275 _M_refcount._M_swap(__other._M_refcount);
1276 }
1277
1278 template<typename _Tp1>
1279 bool
1280 owner_before(__shared_ptr<_Tp1, _Lp> const& __rhs) const noexcept
1281 { return _M_refcount._M_less(__rhs._M_refcount); }
1282
1283 template<typename _Tp1>
1284 bool
1285 owner_before(__weak_ptr<_Tp1, _Lp> const& __rhs) const noexcept
1286 { return _M_refcount._M_less(__rhs._M_refcount); }
1287
1288#if __cpp_rtti199711
1289 protected:
1290 // This constructor is non-standard, it is used by allocate_shared.
1291 template<typename _Alloc, typename... _Args>
1292 __shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
1293 _Args&&... __args)
1294 : _M_ptr(), _M_refcount(__tag, (_Tp*)0, __a,
1295 std::forward<_Args>(__args)...)
1296 {
1297 // _M_ptr needs to point to the newly constructed object.
1298 // This relies on _Sp_counted_ptr_inplace::_M_get_deleter.
1299 void* __p = _M_refcount._M_get_deleter(typeid(__tag));
1300 _M_ptr = static_cast<_Tp*>(__p);
1301 _M_enable_shared_from_this_with(_M_ptr);
1302 }
1303#else
1304 template<typename _Alloc>
1305 struct _Deleter
1306 {
1307 void operator()(typename _Alloc::value_type* __ptr)
1308 {
1309 __allocated_ptr<_Alloc> __guard{ _M_alloc, __ptr };
1310 allocator_traits<_Alloc>::destroy(_M_alloc, __guard.get());
1311 }
1312 _Alloc _M_alloc;
1313 };
1314
1315 template<typename _Alloc, typename... _Args>
1316 __shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
1317 _Args&&... __args)
1318 : _M_ptr(), _M_refcount()
1319 {
1320 typedef typename allocator_traits<_Alloc>::template
1321 rebind_traits<typename std::remove_cv<_Tp>::type> __traits;
1322 _Deleter<typename __traits::allocator_type> __del = { __a };
1323 auto __guard = std::__allocate_guarded(__del._M_alloc);
1324 auto __ptr = __guard.get();
1325 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1326 // 2070. allocate_shared should use allocator_traits<A>::construct
1327 __traits::construct(__del._M_alloc, __ptr,
1328 std::forward<_Args>(__args)...);
1329 __guard = nullptr;
1330 __shared_count<_Lp> __count(__ptr, __del, __del._M_alloc);
1331 _M_refcount._M_swap(__count);
1332 _M_ptr = __ptr;
1333 _M_enable_shared_from_this_with(_M_ptr);
1334 }
1335#endif
1336
1337 template<typename _Tp1, _Lock_policy _Lp1, typename _Alloc,
1338 typename... _Args>
1339 friend __shared_ptr<_Tp1, _Lp1>
1340 __allocate_shared(const _Alloc& __a, _Args&&... __args);
1341
1342 // This constructor is used by __weak_ptr::lock() and
1343 // shared_ptr::shared_ptr(const weak_ptr&, std::nothrow_t).
1344 __shared_ptr(const __weak_ptr<_Tp, _Lp>& __r, std::nothrow_t)
1345 : _M_refcount(__r._M_refcount, std::nothrow)
1346 {
1347 _M_ptr = _M_refcount._M_get_use_count() ? __r._M_ptr : nullptr;
1348 }
1349
1350 friend class __weak_ptr<_Tp, _Lp>;
1351
1352 private:
1353
1354 template<typename _Yp>
1355 using __esft_base_t = decltype(__enable_shared_from_this_base(
1356 std::declval<const __shared_count<_Lp>&>(),
1357 std::declval<_Yp*>()));
1358
1359 // Detect an accessible and unambiguous enable_shared_from_this base.
1360 template<typename _Yp, typename = void>
1361 struct __has_esft_base
1362 : false_type { };
1363
1364 template<typename _Yp>
1365 struct __has_esft_base<_Yp, __void_t<__esft_base_t<_Yp>>>
1366 : __not_<is_array<_Tp>> { }; // No enable shared_from_this for arrays
1367
1368 template<typename _Yp, typename _Yp2 = typename remove_cv<_Yp>::type>
1369 typename enable_if<__has_esft_base<_Yp2>::value>::type
1370 _M_enable_shared_from_this_with(_Yp* __p) noexcept
1371 {
1372 if (auto __base = __enable_shared_from_this_base(_M_refcount, __p))
1373 __base->_M_weak_assign(const_cast<_Yp2*>(__p), _M_refcount);
1374 }
1375
1376 template<typename _Yp, typename _Yp2 = typename remove_cv<_Yp>::type>
1377 typename enable_if<!__has_esft_base<_Yp2>::value>::type
1378 _M_enable_shared_from_this_with(_Yp*) noexcept
1379 { }
1380
1381 void*
1382 _M_get_deleter(const std::type_info& __ti) const noexcept
1383 { return _M_refcount._M_get_deleter(__ti); }
1384
1385 template<typename _Tp1>
1386 static _Tp1*
1387 _S_raw_ptr(_Tp1* __ptr)
1388 { return __ptr; }
1389
1390 template<typename _Tp1>
1391 static auto
1392 _S_raw_ptr(_Tp1 __ptr) -> decltype(std::__addressof(*__ptr))
1393 { return std::__addressof(*__ptr); }
1394
1395 template<typename _Tp1, _Lock_policy _Lp1> friend class __shared_ptr;
1396 template<typename _Tp1, _Lock_policy _Lp1> friend class __weak_ptr;
1397
1398 template<typename _Del, typename _Tp1, _Lock_policy _Lp1>
1399 friend _Del* get_deleter(const __shared_ptr<_Tp1, _Lp1>&) noexcept;
1400
1401 element_type* _M_ptr; // Contained pointer.
1402 __shared_count<_Lp> _M_refcount; // Reference counter.
1403 };
1404
1405
1406 // 20.7.2.2.7 shared_ptr comparisons
1407 template<typename _Tp1, typename _Tp2, _Lock_policy _Lp>
1408 inline bool
1409 operator==(const __shared_ptr<_Tp1, _Lp>& __a,
1410 const __shared_ptr<_Tp2, _Lp>& __b) noexcept
1411 { return __a.get() == __b.get(); }
1412
1413 template<typename _Tp, _Lock_policy _Lp>
1414 inline bool
1415 operator==(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
1416 { return !__a; }
1417
1418 template<typename _Tp, _Lock_policy _Lp>
1419 inline bool
1420 operator==(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
1421 { return !__a; }
1422
1423 template<typename _Tp1, typename _Tp2, _Lock_policy _Lp>
1424 inline bool
1425 operator!=(const __shared_ptr<_Tp1, _Lp>& __a,
1426 const __shared_ptr<_Tp2, _Lp>& __b) noexcept
1427 { return __a.get() != __b.get(); }
1428
1429 template<typename _Tp, _Lock_policy _Lp>
1430 inline bool
1431 operator!=(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
1432 { return (bool)__a; }
1433
1434 template<typename _Tp, _Lock_policy _Lp>
1435 inline bool
1436 operator!=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
1437 { return (bool)__a; }
1438
1439 template<typename _Tp, typename _Up, _Lock_policy _Lp>
1440 inline bool
1441 operator<(const __shared_ptr<_Tp, _Lp>& __a,
1442 const __shared_ptr<_Up, _Lp>& __b) noexcept
1443 {
1444 using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type;
1445 using _Up_elt = typename __shared_ptr<_Up, _Lp>::element_type;
1446 using _Vp = typename common_type<_Tp_elt*, _Up_elt*>::type;
1447 return less<_Vp>()(__a.get(), __b.get());
1448 }
1449
1450 template<typename _Tp, _Lock_policy _Lp>
1451 inline bool
1452 operator<(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
1453 {
1454 using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type;
1455 return less<_Tp_elt*>()(__a.get(), nullptr);
1456 }
1457
1458 template<typename _Tp, _Lock_policy _Lp>
1459 inline bool
1460 operator<(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
1461 {
1462 using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type;
1463 return less<_Tp_elt*>()(nullptr, __a.get());
1464 }
1465
1466 template<typename _Tp1, typename _Tp2, _Lock_policy _Lp>
1467 inline bool
1468 operator<=(const __shared_ptr<_Tp1, _Lp>& __a,
1469 const __shared_ptr<_Tp2, _Lp>& __b) noexcept
1470 { return !(__b < __a); }
1471
1472 template<typename _Tp, _Lock_policy _Lp>
1473 inline bool
1474 operator<=(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
1475 { return !(nullptr < __a); }
1476
1477 template<typename _Tp, _Lock_policy _Lp>
1478 inline bool
1479 operator<=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
1480 { return !(__a < nullptr); }
1481
1482 template<typename _Tp1, typename _Tp2, _Lock_policy _Lp>
1483 inline bool
1484 operator>(const __shared_ptr<_Tp1, _Lp>& __a,
1485 const __shared_ptr<_Tp2, _Lp>& __b) noexcept
1486 { return (__b < __a); }
1487
1488 template<typename _Tp, _Lock_policy _Lp>
1489 inline bool
1490 operator>(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
1491 { return nullptr < __a; }
1492
1493 template<typename _Tp, _Lock_policy _Lp>
1494 inline bool
1495 operator>(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
1496 { return __a < nullptr; }
1497
1498 template<typename _Tp1, typename _Tp2, _Lock_policy _Lp>
1499 inline bool
1500 operator>=(const __shared_ptr<_Tp1, _Lp>& __a,
1501 const __shared_ptr<_Tp2, _Lp>& __b) noexcept
1502 { return !(__a < __b); }
1503
1504 template<typename _Tp, _Lock_policy _Lp>
1505 inline bool
1506 operator>=(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
1507 { return !(__a < nullptr); }
1508
1509 template<typename _Tp, _Lock_policy _Lp>
1510 inline bool
1511 operator>=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
1512 { return !(nullptr < __a); }
1513
1514 template<typename _Sp>
1515 struct _Sp_less : public binary_function<_Sp, _Sp, bool>
1516 {
1517 bool
1518 operator()(const _Sp& __lhs, const _Sp& __rhs) const noexcept
1519 {
1520 typedef typename _Sp::element_type element_type;
1521 return std::less<element_type*>()(__lhs.get(), __rhs.get());
1522 }
1523 };
1524
1525 template<typename _Tp, _Lock_policy _Lp>
1526 struct less<__shared_ptr<_Tp, _Lp>>
1527 : public _Sp_less<__shared_ptr<_Tp, _Lp>>
1528 { };
1529
1530 // 20.7.2.2.8 shared_ptr specialized algorithms.
1531 template<typename _Tp, _Lock_policy _Lp>
1532 inline void
1533 swap(__shared_ptr<_Tp, _Lp>& __a, __shared_ptr<_Tp, _Lp>& __b) noexcept
1534 { __a.swap(__b); }
1535
1536 // 20.7.2.2.9 shared_ptr casts
1537
1538 // The seemingly equivalent code:
1539 // shared_ptr<_Tp, _Lp>(static_cast<_Tp*>(__r.get()))
1540 // will eventually result in undefined behaviour, attempting to
1541 // delete the same object twice.
1542 /// static_pointer_cast
1543 template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
1544 inline __shared_ptr<_Tp, _Lp>
1545 static_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
1546 {
1547 using _Sp = __shared_ptr<_Tp, _Lp>;
1548 return _Sp(__r, static_cast<typename _Sp::element_type*>(__r.get()));
1549 }
1550
1551 // The seemingly equivalent code:
1552 // shared_ptr<_Tp, _Lp>(const_cast<_Tp*>(__r.get()))
1553 // will eventually result in undefined behaviour, attempting to
1554 // delete the same object twice.
1555 /// const_pointer_cast
1556 template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
1557 inline __shared_ptr<_Tp, _Lp>
1558 const_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
1559 {
1560 using _Sp = __shared_ptr<_Tp, _Lp>;
1561 return _Sp(__r, const_cast<typename _Sp::element_type*>(__r.get()));
1562 }
1563
1564 // The seemingly equivalent code:
1565 // shared_ptr<_Tp, _Lp>(dynamic_cast<_Tp*>(__r.get()))
1566 // will eventually result in undefined behaviour, attempting to
1567 // delete the same object twice.
1568 /// dynamic_pointer_cast
1569 template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
1570 inline __shared_ptr<_Tp, _Lp>
1571 dynamic_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
1572 {
1573 using _Sp = __shared_ptr<_Tp, _Lp>;
1574 if (auto* __p = dynamic_cast<typename _Sp::element_type*>(__r.get()))
1575 return _Sp(__r, __p);
1576 return _Sp();
1577 }
1578
1579#if __cplusplus201103L > 201402L
1580 template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
1581 inline __shared_ptr<_Tp, _Lp>
1582 reinterpret_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
1583 {
1584 using _Sp = __shared_ptr<_Tp, _Lp>;
1585 return _Sp(__r, reinterpret_cast<typename _Sp::element_type*>(__r.get()));
1586 }
1587#endif
1588
1589 template<typename _Tp, _Lock_policy _Lp>
1590 class __weak_ptr
1591 {
1592 template<typename _Yp, typename _Res = void>
1593 using _Compatible = typename
1594 enable_if<__sp_compatible_with<_Yp*, _Tp*>::value, _Res>::type;
1595
1596 // Constraint for assignment from shared_ptr and weak_ptr:
1597 template<typename _Yp>
1598 using _Assignable = _Compatible<_Yp, __weak_ptr&>;
1599
1600 public:
1601 using element_type = typename remove_extent<_Tp>::type;
1602
1603 constexpr __weak_ptr() noexcept
1604 : _M_ptr(nullptr), _M_refcount()
1605 { }
1606
1607 __weak_ptr(const __weak_ptr&) noexcept = default;
1608
1609 ~__weak_ptr() = default;
1610
1611 // The "obvious" converting constructor implementation:
1612 //
1613 // template<typename _Tp1>
1614 // __weak_ptr(const __weak_ptr<_Tp1, _Lp>& __r)
1615 // : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) // never throws
1616 // { }
1617 //
1618 // has a serious problem.
1619 //
1620 // __r._M_ptr may already have been invalidated. The _M_ptr(__r._M_ptr)
1621 // conversion may require access to *__r._M_ptr (virtual inheritance).
1622 //
1623 // It is not possible to avoid spurious access violations since
1624 // in multithreaded programs __r._M_ptr may be invalidated at any point.
1625 template<typename _Yp, typename = _Compatible<_Yp>>
1626 __weak_ptr(const __weak_ptr<_Yp, _Lp>& __r) noexcept
1627 : _M_refcount(__r._M_refcount)
1628 { _M_ptr = __r.lock().get(); }
1629
1630 template<typename _Yp, typename = _Compatible<_Yp>>
1631 __weak_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept
1632 : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount)
1633 { }
1634
1635 __weak_ptr(__weak_ptr&& __r) noexcept
1636 : _M_ptr(__r._M_ptr), _M_refcount(std::move(__r._M_refcount))
1637 { __r._M_ptr = nullptr; }
1638
1639 template<typename _Yp, typename = _Compatible<_Yp>>
1640 __weak_ptr(__weak_ptr<_Yp, _Lp>&& __r) noexcept
1641 : _M_ptr(__r.lock().get()), _M_refcount(std::move(__r._M_refcount))
1642 { __r._M_ptr = nullptr; }
1643
1644 __weak_ptr&
1645 operator=(const __weak_ptr& __r) noexcept = default;
1646
1647 template<typename _Yp>
1648 _Assignable<_Yp>
1649 operator=(const __weak_ptr<_Yp, _Lp>& __r) noexcept
1650 {
1651 _M_ptr = __r.lock().get();
1652 _M_refcount = __r._M_refcount;
1653 return *this;
1654 }
1655
1656 template<typename _Yp>
1657 _Assignable<_Yp>
1658 operator=(const __shared_ptr<_Yp, _Lp>& __r) noexcept
1659 {
1660 _M_ptr = __r._M_ptr;
1661 _M_refcount = __r._M_refcount;
1662 return *this;
1663 }
1664
1665 __weak_ptr&
1666 operator=(__weak_ptr&& __r) noexcept
1667 {
1668 _M_ptr = __r._M_ptr;
1669 _M_refcount = std::move(__r._M_refcount);
1670 __r._M_ptr = nullptr;
1671 return *this;
1672 }
1673
1674 template<typename _Yp>
1675 _Assignable<_Yp>
1676 operator=(__weak_ptr<_Yp, _Lp>&& __r) noexcept
1677 {
1678 _M_ptr = __r.lock().get();
1679 _M_refcount = std::move(__r._M_refcount);
1680 __r._M_ptr = nullptr;
1681 return *this;
1682 }
1683
1684 __shared_ptr<_Tp, _Lp>
1685 lock() const noexcept
1686 { return __shared_ptr<element_type, _Lp>(*this, std::nothrow); }
1687
1688 long
1689 use_count() const noexcept
1690 { return _M_refcount._M_get_use_count(); }
1691
1692 bool
1693 expired() const noexcept
1694 { return _M_refcount._M_get_use_count() == 0; }
1695
1696 template<typename _Tp1>
1697 bool
1698 owner_before(const __shared_ptr<_Tp1, _Lp>& __rhs) const noexcept
1699 { return _M_refcount._M_less(__rhs._M_refcount); }
1700
1701 template<typename _Tp1>
1702 bool
1703 owner_before(const __weak_ptr<_Tp1, _Lp>& __rhs) const noexcept
1704 { return _M_refcount._M_less(__rhs._M_refcount); }
1705
1706 void
1707 reset() noexcept
1708 { __weak_ptr().swap(*this); }
1709
1710 void
1711 swap(__weak_ptr& __s) noexcept
1712 {
1713 std::swap(_M_ptr, __s._M_ptr);
1714 _M_refcount._M_swap(__s._M_refcount);
1715 }
1716
1717 private:
1718 // Used by __enable_shared_from_this.
1719 void
1720 _M_assign(_Tp* __ptr, const __shared_count<_Lp>& __refcount) noexcept
1721 {
1722 if (use_count() == 0)
1723 {
1724 _M_ptr = __ptr;
1725 _M_refcount = __refcount;
1726 }
1727 }
1728
1729 template<typename _Tp1, _Lock_policy _Lp1> friend class __shared_ptr;
1730 template<typename _Tp1, _Lock_policy _Lp1> friend class __weak_ptr;
1731 friend class __enable_shared_from_this<_Tp, _Lp>;
1732 friend class enable_shared_from_this<_Tp>;
1733
1734 element_type* _M_ptr; // Contained pointer.
1735 __weak_count<_Lp> _M_refcount; // Reference counter.
1736 };
1737
1738 // 20.7.2.3.6 weak_ptr specialized algorithms.
1739 template<typename _Tp, _Lock_policy _Lp>
1740 inline void
1741 swap(__weak_ptr<_Tp, _Lp>& __a, __weak_ptr<_Tp, _Lp>& __b) noexcept
1742 { __a.swap(__b); }
1743
1744 template<typename _Tp, typename _Tp1>
1745 struct _Sp_owner_less : public binary_function<_Tp, _Tp, bool>
1746 {
1747 bool
1748 operator()(const _Tp& __lhs, const _Tp& __rhs) const noexcept
1749 { return __lhs.owner_before(__rhs); }
1750
1751 bool
1752 operator()(const _Tp& __lhs, const _Tp1& __rhs) const noexcept
1753 { return __lhs.owner_before(__rhs); }
1754
1755 bool
1756 operator()(const _Tp1& __lhs, const _Tp& __rhs) const noexcept
1757 { return __lhs.owner_before(__rhs); }
1758 };
1759
1760 template<>
1761 struct _Sp_owner_less<void, void>
1762 {
1763 template<typename _Tp, typename _Up>
1764 auto
1765 operator()(const _Tp& __lhs, const _Up& __rhs) const noexcept
1766 -> decltype(__lhs.owner_before(__rhs))
1767 { return __lhs.owner_before(__rhs); }
1768
1769 using is_transparent = void;
1770 };
1771
1772 template<typename _Tp, _Lock_policy _Lp>
1773 struct owner_less<__shared_ptr<_Tp, _Lp>>
1774 : public _Sp_owner_less<__shared_ptr<_Tp, _Lp>, __weak_ptr<_Tp, _Lp>>
1775 { };
1776
1777 template<typename _Tp, _Lock_policy _Lp>
1778 struct owner_less<__weak_ptr<_Tp, _Lp>>
1779 : public _Sp_owner_less<__weak_ptr<_Tp, _Lp>, __shared_ptr<_Tp, _Lp>>
1780 { };
1781
1782
1783 template<typename _Tp, _Lock_policy _Lp>
1784 class __enable_shared_from_this
1785 {
1786 protected:
1787 constexpr __enable_shared_from_this() noexcept { }
1788
1789 __enable_shared_from_this(const __enable_shared_from_this&) noexcept { }
1790
1791 __enable_shared_from_this&
1792 operator=(const __enable_shared_from_this&) noexcept
1793 { return *this; }
1794
1795 ~__enable_shared_from_this() { }
1796
1797 public:
1798 __shared_ptr<_Tp, _Lp>
1799 shared_from_this()
1800 { return __shared_ptr<_Tp, _Lp>(this->_M_weak_this); }
1801
1802 __shared_ptr<const _Tp, _Lp>
1803 shared_from_this() const
1804 { return __shared_ptr<const _Tp, _Lp>(this->_M_weak_this); }
1805
1806#if __cplusplus201103L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11
1807 __weak_ptr<_Tp, _Lp>
1808 weak_from_this() noexcept
1809 { return this->_M_weak_this; }
1810
1811 __weak_ptr<const _Tp, _Lp>
1812 weak_from_this() const noexcept
1813 { return this->_M_weak_this; }
1814#endif
1815
1816 private:
1817 template<typename _Tp1>
1818 void
1819 _M_weak_assign(_Tp1* __p, const __shared_count<_Lp>& __n) const noexcept
1820 { _M_weak_this._M_assign(__p, __n); }
1821
1822 friend const __enable_shared_from_this*
1823 __enable_shared_from_this_base(const __shared_count<_Lp>&,
1824 const __enable_shared_from_this* __p)
1825 { return __p; }
1826
1827 template<typename, _Lock_policy>
1828 friend class __shared_ptr;
1829
1830 mutable __weak_ptr<_Tp, _Lp> _M_weak_this;
1831 };
1832
1833 template<typename _Tp, _Lock_policy _Lp, typename _Alloc, typename... _Args>
1834 inline __shared_ptr<_Tp, _Lp>
1835 __allocate_shared(const _Alloc& __a, _Args&&... __args)
1836 {
1837 return __shared_ptr<_Tp, _Lp>(_Sp_make_shared_tag(), __a,
1838 std::forward<_Args>(__args)...);
1839 }
1840
1841 template<typename _Tp, _Lock_policy _Lp, typename... _Args>
1842 inline __shared_ptr<_Tp, _Lp>
1843 __make_shared(_Args&&... __args)
1844 {
1845 typedef typename std::remove_const<_Tp>::type _Tp_nc;
1846 return std::__allocate_shared<_Tp, _Lp>(std::allocator<_Tp_nc>(),
1847 std::forward<_Args>(__args)...);
1848 }
1849
1850 /// std::hash specialization for __shared_ptr.
1851 template<typename _Tp, _Lock_policy _Lp>
1852 struct hash<__shared_ptr<_Tp, _Lp>>
1853 : public __hash_base<size_t, __shared_ptr<_Tp, _Lp>>
1854 {
1855 size_t
1856 operator()(const __shared_ptr<_Tp, _Lp>& __s) const noexcept
1857 {
1858 return hash<typename __shared_ptr<_Tp, _Lp>::element_type*>()(
1859 __s.get());
1860 }
1861 };
1862
1863_GLIBCXX_END_NAMESPACE_VERSION
1864} // namespace
1865
1866#endif // _SHARED_PTR_BASE_H

/usr/lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/ext/atomicity.h

1// Support for atomic operations -*- C++ -*-
2
3// Copyright (C) 2004-2017 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file ext/atomicity.h
26 * This file is a GNU extension to the Standard C++ Library.
27 */
28
29#ifndef _GLIBCXX_ATOMICITY_H1
30#define _GLIBCXX_ATOMICITY_H1 1
31
32#pragma GCC system_header
33
34#include <bits/c++config.h>
35#include <bits/gthr.h>
36#include <bits/atomic_word.h>
37
38namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default")))
39{
40_GLIBCXX_BEGIN_NAMESPACE_VERSION
41
42 // Functions for portable atomic access.
43 // To abstract locking primitives across all thread policies, use:
44 // __exchange_and_add_dispatch
45 // __atomic_add_dispatch
46#ifdef _GLIBCXX_ATOMIC_BUILTINS1
47 static inline _Atomic_word
48 __exchange_and_add(volatile _Atomic_word* __mem, int __val)
49 { return __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL4); }
50
51 static inline void
52 __atomic_add(volatile _Atomic_word* __mem, int __val)
53 { __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL4); }
54#else
55 _Atomic_word
56 __attribute__ ((__unused__))
57 __exchange_and_add(volatile _Atomic_word*, int) throw ();
58
59 void
60 __attribute__ ((__unused__))
61 __atomic_add(volatile _Atomic_word*, int) throw ();
62#endif
63
64 static inline _Atomic_word
65 __exchange_and_add_single(_Atomic_word* __mem, int __val)
66 {
67 _Atomic_word __result = *__mem;
65
Use of memory after it is freed
68 *__mem += __val;
69 return __result;
70 }
71
72 static inline void
73 __atomic_add_single(_Atomic_word* __mem, int __val)
74 { *__mem += __val; }
75
76 static inline _Atomic_word
77 __attribute__ ((__unused__))
78 __exchange_and_add_dispatch(_Atomic_word* __mem, int __val)
79 {
80#ifdef __GTHREADS1
81 if (__gthread_active_p())
62
Assuming the condition is false
63
Taking false branch
82 return __exchange_and_add(__mem, __val);
83 else
84 return __exchange_and_add_single(__mem, __val);
64
Calling '__exchange_and_add_single'
85#else
86 return __exchange_and_add_single(__mem, __val);
87#endif
88 }
89
90 static inline void
91 __attribute__ ((__unused__))
92 __atomic_add_dispatch(_Atomic_word* __mem, int __val)
93 {
94#ifdef __GTHREADS1
95 if (__gthread_active_p())
96 __atomic_add(__mem, __val);
97 else
98 __atomic_add_single(__mem, __val);
99#else
100 __atomic_add_single(__mem, __val);
101#endif
102 }
103
104_GLIBCXX_END_NAMESPACE_VERSION
105} // namespace
106
107// Even if the CPU doesn't need a memory barrier, we need to ensure
108// that the compiler doesn't reorder memory accesses across the
109// barriers.
110#ifndef _GLIBCXX_READ_MEM_BARRIER__atomic_thread_fence (2)
111#define _GLIBCXX_READ_MEM_BARRIER__atomic_thread_fence (2) __atomic_thread_fence (__ATOMIC_ACQUIRE2)
112#endif
113#ifndef _GLIBCXX_WRITE_MEM_BARRIER__atomic_thread_fence (3)
114#define _GLIBCXX_WRITE_MEM_BARRIER__atomic_thread_fence (3) __atomic_thread_fence (__ATOMIC_RELEASE3)
115#endif
116
117#endif