blob: 6105080e27c04d27ab32afa1fb6a047bdbef01bf [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- Value.cpp -----------------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "lldb/Core/Value.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
16#include "lldb/Core/DataExtractor.h"
17#include "lldb/Core/DataBufferHeap.h"
18#include "lldb/Core/Module.h"
19#include "lldb/Core/Stream.h"
Greg Claytone1a916a2010-07-21 22:12:05 +000020#include "lldb/Symbol/ClangASTType.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000021#include "lldb/Symbol/ClangASTContext.h"
22#include "lldb/Symbol/ObjectFile.h"
23#include "lldb/Symbol/SymbolContext.h"
24#include "lldb/Symbol/Type.h"
25#include "lldb/Symbol/Variable.h"
26#include "lldb/Target/ExecutionContext.h"
27#include "lldb/Target/Process.h"
28
29using namespace lldb;
30using namespace lldb_private;
31
32Value::Value() :
33 m_value(),
34 m_value_type(eValueTypeScalar),
35 m_context(NULL),
36 m_context_type(eContextTypeInvalid)
37{
38}
39
40Value::Value(const Scalar& scalar) :
41 m_value(scalar),
42 m_value_type(eValueTypeScalar),
43 m_context(NULL),
44 m_context_type(eContextTypeInvalid)
45{
46}
47
48Value::Value(int v) :
49 m_value(v),
50 m_value_type(eValueTypeScalar),
51 m_context(NULL),
52 m_context_type(eContextTypeInvalid)
53{
54}
55
56Value::Value(unsigned int v) :
57 m_value(v),
58 m_value_type(eValueTypeScalar),
59 m_context(NULL),
60 m_context_type(eContextTypeInvalid)
61{
62}
63
64Value::Value(long v) :
65 m_value(v),
66 m_value_type(eValueTypeScalar),
67 m_context(NULL),
68 m_context_type(eContextTypeInvalid)
69{
70}
71
72Value::Value(unsigned long v) :
73 m_value(v),
74 m_value_type(eValueTypeScalar),
75 m_context(NULL),
76 m_context_type(eContextTypeInvalid)
77{
78}
79
80Value::Value(long long v) :
81 m_value(v),
82 m_value_type(eValueTypeScalar),
83 m_context(NULL),
84 m_context_type(eContextTypeInvalid)
85{
86}
87
88Value::Value(unsigned long long v) :
89 m_value(v),
90 m_value_type(eValueTypeScalar),
91 m_context(NULL),
92 m_context_type(eContextTypeInvalid)
93{
94}
95
96Value::Value(float v) :
97 m_value(v),
98 m_value_type(eValueTypeScalar),
99 m_context(NULL),
100 m_context_type(eContextTypeInvalid)
101{
102}
103
104Value::Value(double v) :
105 m_value(v),
106 m_value_type(eValueTypeScalar),
107 m_context(NULL),
108 m_context_type(eContextTypeInvalid)
109{
110}
111
112Value::Value(long double v) :
113 m_value(v),
114 m_value_type(eValueTypeScalar),
115 m_context(NULL),
116 m_context_type(eContextTypeInvalid)
117{
118}
119
120Value::Value(const uint8_t *bytes, int len) :
121 m_value(),
122 m_value_type(eValueTypeHostAddress),
123 m_context(NULL),
124 m_context_type(eContextTypeInvalid)
125{
126 m_data_buffer.CopyData(bytes, len);
127 m_value = (uintptr_t)m_data_buffer.GetBytes();
128}
129
130Value::Value(const Value &v) :
131 m_value(v.m_value),
132 m_value_type(v.m_value_type),
133 m_context(v.m_context),
134 m_context_type(v.m_context_type)
135{
136 if ((uintptr_t)v.m_value.ULongLong(LLDB_INVALID_ADDRESS) == (uintptr_t)v.m_data_buffer.GetBytes())
137 {
138 m_data_buffer.CopyData(v.m_data_buffer.GetBytes(),
139 v.m_data_buffer.GetByteSize());
140
141 m_value = (uintptr_t)m_data_buffer.GetBytes();
142 }
143}
144
145Value *
146Value::CreateProxy()
147{
148 if (m_context_type == eContextTypeValue)
149 return ((Value*)m_context)->CreateProxy ();
150
151 Value *ret = new Value;
152 ret->SetContext(eContextTypeValue, this);
153 return ret;
154}
155
156Value *
157Value::GetProxyTarget()
158{
159 if (m_context_type == eContextTypeValue)
160 return (Value*)m_context;
161 else
162 return NULL;
163}
164
165//#include "clang/Lex/LiteralSupport.h"
166//#include "clang/AST/ASTContext.h"
167//#include "clang/Frontend/CompilerInstance.h"
168//
169//Value::Value (const char *data, llvm::CompilerInstance *compiler)
170//{
171// clang::NumericLiteralParser parser(data, data + strlen(data), clang::SourceLocation(),
172// compiler->getPreprocessor());
173// if (parser.had_error)
174// {
175// }
176// else if (parser.isBool)
177// {
178// APInt value;
179// parser.GetIntegerValue(value);
180// }
181// else if (parser.isLong)
182// {
183// }
184// else if (parser.isLongLong)
185// {
186// }
187// else if (parser.isFloat)
188// {
189// }
190//
191//}
192//
193void
194Value::Dump (Stream* strm)
195{
196 if (m_context_type == eContextTypeValue)
197 {
198 ((Value*)m_context)->Dump (strm);
199 return;
200 }
201
202 m_value.GetValue (strm, true);
203 strm->Printf(", value_type = %s, context = %p, context_type = %s",
204 Value::GetValueTypeAsCString(m_value_type),
205 m_context,
206 Value::GetContextTypeAsCString(m_context_type));
207}
208
209void *
210Value::GetOpaqueClangQualType()
211{
212 if (m_context_type == eContextTypeValue)
213 return ((Value*)m_context)->GetOpaqueClangQualType ();
214
215 if (m_context_type == eContextTypeOpaqueClangQualType)
216 return m_context;
217
218 return NULL;
219}
220
221Value::ValueType
222Value::GetValueType() const
223{
224 if (m_context_type == eContextTypeValue)
225 return ((Value*)m_context)->GetValueType ();
226
227 return m_value_type;
228}
229
230lldb::AddressType
231Value::GetValueAddressType () const
232{
233 if (m_context_type == eContextTypeValue)
234 return ((Value*)m_context)->GetValueAddressType ();
235
236 switch (m_value_type)
237 {
238 default:
239 case eValueTypeScalar:
240 break;
241 case eValueTypeLoadAddress: return eAddressTypeLoad;
242 case eValueTypeFileAddress: return eAddressTypeFile;
243 case eValueTypeHostAddress: return eAddressTypeHost;
244 }
245 return eAddressTypeInvalid;
246}
247
248
249Value::ContextType
250Value::GetContextType() const
251{
252 if (m_context_type == eContextTypeValue)
253 return ((Value*)m_context)->GetContextType ();
254
255 return m_context_type;
256}
257
258void
259Value::SetValueType (Value::ValueType value_type)
260{
261 if (m_context_type == eContextTypeValue)
262 {
263 ((Value*)m_context)->SetValueType(value_type);
264 return;
265 }
266
267 m_value_type = value_type;
268}
269
270void
271Value::ClearContext ()
272{
273 if (m_context_type == eContextTypeValue)
274 {
275 ((Value*)m_context)->ClearContext();
276 return;
277 }
278
279 m_context = NULL;
280 m_context_type = eContextTypeInvalid;
281}
282
283void
284Value::SetContext (Value::ContextType context_type, void *p)
285{
286 if (m_context_type == eContextTypeValue)
287 {
288 ((Value*)m_context)->SetContext(context_type, p);
289 return;
290 }
291
292 m_context_type = context_type;
293 m_context = p;
294}
295
296RegisterInfo *
297Value::GetRegisterInfo()
298{
299 if (m_context_type == eContextTypeValue)
300 return ((Value*)m_context)->GetRegisterInfo();
301
302 if (m_context_type == eContextTypeDCRegisterInfo)
303 return static_cast<RegisterInfo *> (m_context);
304 return NULL;
305}
306
307Type *
308Value::GetType()
309{
310 if (m_context_type == eContextTypeValue)
311 return ((Value*)m_context)->GetType();
312
313 if (m_context_type == eContextTypeDCType)
314 return static_cast<Type *> (m_context);
315 return NULL;
316}
317
318Scalar &
319Value::GetScalar()
320{
321 if (m_context_type == eContextTypeValue)
322 return ((Value*)m_context)->GetScalar();
323
324 return m_value;
325}
326
327void
328Value::ResizeData(int len)
329{
330 if (m_context_type == eContextTypeValue)
331 {
332 ((Value*)m_context)->ResizeData(len);
333 return;
334 }
335
336 m_value_type = eValueTypeHostAddress;
337 m_data_buffer.SetByteSize(len);
338 m_value = (uintptr_t)m_data_buffer.GetBytes();
339}
340
341bool
342Value::ValueOf(ExecutionContext *exe_ctx, clang::ASTContext *ast_context)
343{
344 if (m_context_type == eContextTypeValue)
345 return ((Value*)m_context)->ValueOf(exe_ctx, ast_context);
346
347 switch (m_context_type)
348 {
349 default:
350 case eContextTypeInvalid:
351 case eContextTypeOpaqueClangQualType: // clang::Type *
352 case eContextTypeDCRegisterInfo: // RegisterInfo *
353 case eContextTypeDCType: // Type *
354 break;
355
356 case eContextTypeDCVariable: // Variable *
357 ResolveValue(exe_ctx, ast_context);
358 return true;
359 }
360 return false;
361}
362
363size_t
364Value::GetValueByteSize (clang::ASTContext *ast_context, Error *error_ptr)
365{
366 if (m_context_type == eContextTypeValue)
367 return ((Value*)m_context)->GetValueByteSize(ast_context, error_ptr);
368
369 size_t byte_size = 0;
370
371 switch (m_context_type)
372 {
373 default:
374 case eContextTypeInvalid:
375 // If we have no context, there is no way to know how much memory to read
376 if (error_ptr)
377 error_ptr->SetErrorString ("Invalid context type, there is no way to know how much memory to read.");
378 break;
379
380 case eContextTypeOpaqueClangQualType:
381 if (ast_context == NULL)
382 {
383 if (error_ptr)
384 error_ptr->SetErrorString ("Can't determine size of opaque clang type with NULL ASTContext *.");
385 }
386 else
387 {
Greg Claytonb0b9fe62010-08-03 00:35:52 +0000388 uint64_t bit_width = ClangASTType::GetClangTypeBitWidth (ast_context, m_context);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000389 byte_size = (bit_width + 7 ) / 8;
390 }
391 break;
392
393 case eContextTypeDCRegisterInfo: // RegisterInfo *
394 if (GetRegisterInfo())
395 byte_size = GetRegisterInfo()->byte_size;
396 else if (error_ptr)
397 error_ptr->SetErrorString ("Can't determine byte size with NULL RegisterInfo *.");
398
399 break;
400
401 case eContextTypeDCType: // Type *
402 if (GetType())
403 byte_size = GetType()->GetByteSize();
404 else if (error_ptr)
405 error_ptr->SetErrorString ("Can't determine byte size with NULL Type *.");
406 break;
407
408 case eContextTypeDCVariable: // Variable *
409 if (GetVariable())
410 byte_size = GetVariable()->GetType()->GetByteSize();
411 else if (error_ptr)
412 error_ptr->SetErrorString ("Can't determine byte size with NULL Variable *.");
413 break;
414 }
415
416 if (error_ptr)
417 {
418 if (byte_size == 0)
419 {
420 if (error_ptr->Success())
421 error_ptr->SetErrorString("Unable to determine byte size.");
422 }
423 else
424 {
425 error_ptr->Clear();
426 }
427 }
428 return byte_size;
429}
430
431void *
432Value::GetValueOpaqueClangQualType ()
433{
434 if (m_context_type == eContextTypeValue)
435 return ((Value*)m_context)->GetValueOpaqueClangQualType();
436
437 switch (m_context_type)
438 {
439 default:
440 case eContextTypeInvalid:
441 break;
442
443 case eContextTypeOpaqueClangQualType:
444 return m_context;
445
446 case eContextTypeDCRegisterInfo:
447 break; // TODO: Eventually convert into a clang type?
448
449 case eContextTypeDCType:
450 if (GetType())
451 return GetType()->GetOpaqueClangQualType();
452 break;
453
454 case eContextTypeDCVariable:
455 if (GetVariable())
456 return GetVariable()->GetType()->GetOpaqueClangQualType();
457 break;
458 }
459
460 return NULL;
461}
462
463lldb::Format
464Value::GetValueDefaultFormat ()
465{
466 if (m_context_type == eContextTypeValue)
467 return ((Value*)m_context)->GetValueDefaultFormat();
468
469 switch (m_context_type)
470 {
471 default:
472 case eContextTypeInvalid:
473 break;
474
475 case eContextTypeOpaqueClangQualType:
Greg Claytone1a916a2010-07-21 22:12:05 +0000476 return ClangASTType::GetFormat (m_context);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000477
478 case eContextTypeDCRegisterInfo:
479 if (GetRegisterInfo())
480 return GetRegisterInfo()->format;
481 break;
482
483 case eContextTypeDCType:
484 if (GetType())
485 return GetType()->GetFormat();
486 break;
487
488 case eContextTypeDCVariable:
489 if (GetVariable())
490 return GetVariable()->GetType()->GetFormat();
491 break;
492
493 }
494
495 // Return a good default in case we can't figure anything out
496 return eFormatHex;
497}
498
499Error
500Value::GetValueAsData (ExecutionContext *exe_ctx, clang::ASTContext *ast_context, DataExtractor &data, uint32_t data_offset)
501{
502 if (m_context_type == eContextTypeValue)
503 return ((Value*)m_context)->GetValueAsData(exe_ctx, ast_context, data, data_offset);
504
505 data.Clear();
506
507 Error error;
508 lldb::addr_t address = LLDB_INVALID_ADDRESS;
509 lldb::AddressType address_type = eAddressTypeFile;
510 switch (m_value_type)
511 {
512 default:
513 error.SetErrorStringWithFormat("Invalid value type %i.\n", m_value_type);
514 break;
515
516 case eValueTypeScalar:
517 data.SetByteOrder (eByteOrderHost);
518 data.SetAddressByteSize(sizeof(void *));
519 if (m_value.GetData (data))
520 return error; // Success;
521 error.SetErrorStringWithFormat("Extracting data from value failed.\n");
522 break;
523
524 case eValueTypeLoadAddress:
525 if (exe_ctx == NULL)
526 {
527 error.SetErrorString ("Can't read memory (no execution context).");
528 }
529 else if (exe_ctx->process == NULL)
530 {
531 error.SetErrorString ("Can't read memory (invalid process).");
532 }
533 else
534 {
535 address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
536 address_type = eAddressTypeLoad;
537 data.SetByteOrder(exe_ctx->process->GetByteOrder());
538 data.SetAddressByteSize(exe_ctx->process->GetAddressByteSize());
539 }
540 break;
541
542 case eValueTypeFileAddress:
543 {
544 // The only thing we can currently lock down to a module so that
545 // we can resolve a file address, is a variable.
546 Variable *variable = GetVariable();
547
548 if (GetVariable())
549 {
550 lldb::addr_t file_addr = m_value.ULongLong(LLDB_INVALID_ADDRESS);
551 if (file_addr != LLDB_INVALID_ADDRESS)
552 {
553 SymbolContext var_sc;
554 variable->CalculateSymbolContext(&var_sc);
555 if (var_sc.module_sp)
556 {
557 ObjectFile *objfile = var_sc.module_sp->GetObjectFile();
558 if (objfile)
559 {
560 Address so_addr(file_addr, objfile->GetSectionList());
Greg Claytonf5e56de2010-09-14 23:36:40 +0000561 address = so_addr.GetLoadAddress (exe_ctx->target);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000562 if (address != LLDB_INVALID_ADDRESS)
Greg Claytonad3843c2010-08-18 18:28:52 +0000563 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000564 address_type = eAddressTypeLoad;
Greg Claytonad3843c2010-08-18 18:28:52 +0000565 data.SetByteOrder(exe_ctx->process->GetByteOrder());
566 data.SetAddressByteSize(exe_ctx->process->GetAddressByteSize());
567 }
568 else
569 {
570 data.SetByteOrder(objfile->GetByteOrder());
571 data.SetAddressByteSize(objfile->GetAddressByteSize());
572 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000573 }
574 if (address_type == eAddressTypeFile)
575 error.SetErrorStringWithFormat ("%s is not loaded.\n", var_sc.module_sp->GetFileSpec().GetFilename().AsCString());
576 }
577 else
578 {
579 error.SetErrorStringWithFormat ("Unable to resolve the module for file address 0x%llx for variable '%s'.\n", file_addr, variable->GetName().AsCString(""));
580 }
581 }
582 else
583 {
584 error.SetErrorString ("Invalid file address.");
585 }
586 }
587 else
588 {
589 // Can't convert a file address to anything valid without more
590 // context (which Module it came from)
591 error.SetErrorString ("Can't read memory from file address without more context.");
592 }
593 }
594 break;
595
596 case eValueTypeHostAddress:
597 address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
598 data.SetByteOrder(eByteOrderHost);
599 data.SetAddressByteSize(sizeof(void *));
600 address_type = eAddressTypeHost;
601 break;
602 }
603
604 // Bail if we encountered any errors
605 if (error.Fail())
606 return error;
607
608 if (address == LLDB_INVALID_ADDRESS)
609 {
610 error.SetErrorStringWithFormat ("Invalid %s address.\n", address_type == eAddressTypeHost ? "host" : "load");
611 return error;
612 }
613
614 // If we got here, we need to read the value from memory
615 uint32_t byte_size = GetValueByteSize (ast_context, &error);
616
617 // Bail if we encountered any errors getting the byte size
618 if (error.Fail())
619 return error;
620
621 // Make sure we have enough room within "data", and if we don't make
622 // something large enough that does
623 if (!data.ValidOffsetForDataOfSize (data_offset, byte_size))
624 {
625 DataBufferSP data_sp(new DataBufferHeap (data_offset + byte_size, '\0'));
626 data.SetData(data_sp);
627 }
628
Greg Claytonc982c762010-07-09 20:39:50 +0000629 uint8_t* dst = const_cast<uint8_t*>(data.PeekData (data_offset, byte_size));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000630 if (dst != NULL)
631 {
632 if (address_type == eAddressTypeHost)
633 {
634 // The address is an address in this process, so just copy it
635 memcpy (dst, (uint8_t*)NULL + address, byte_size);
636 }
637 else if (address_type == eAddressTypeLoad)
638 {
639 if (exe_ctx->process->ReadMemory(address, dst, byte_size, error) != byte_size)
640 {
641 if (error.Success())
642 error.SetErrorStringWithFormat("read %u bytes of memory from 0x%llx failed", (uint64_t)address, byte_size);
643 }
644 }
645 else
646 {
647 error.SetErrorStringWithFormat ("Unsupported lldb::AddressType value (%i).\n", address_type);
648 }
649 }
650 else
651 {
652 error.SetErrorStringWithFormat ("Out of memory.\n");
653 }
654
655 return error;
656}
657
658Scalar &
659Value::ResolveValue(ExecutionContext *exe_ctx, clang::ASTContext *ast_context)
660{
661 Scalar scalar;
662 if (m_context_type == eContextTypeValue)
663 {
664 // Resolve the proxy
665
666 Value * v = (Value*)m_context;
667
668 m_value = v->m_value;
669 m_value_type = v->m_value_type;
670 m_context = v->m_context;
671 m_context_type = v->m_context_type;
672
673 if ((uintptr_t)v->m_value.ULongLong(LLDB_INVALID_ADDRESS) == (uintptr_t)v->m_data_buffer.GetBytes())
674 {
675 m_data_buffer.CopyData(v->m_data_buffer.GetBytes(),
676 v->m_data_buffer.GetByteSize());
677
678 m_value = (uintptr_t)m_data_buffer.GetBytes();
679 }
680 }
681
682 if (m_context_type == eContextTypeOpaqueClangQualType)
683 {
684 void *opaque_clang_qual_type = GetOpaqueClangQualType();
685 switch (m_value_type)
686 {
687 case eValueTypeScalar: // raw scalar value
688 break;
689
Greg Claytonc982c762010-07-09 20:39:50 +0000690 case eContextTypeValue:
691 m_value.Clear(); // TODO: Sean, fill this in
692 break;
693
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000694 default:
695 case eValueTypeFileAddress:
696 m_value.Clear();
697 break;
698
699 case eValueTypeLoadAddress: // load address value
700 case eValueTypeHostAddress: // host address value (for memory in the process that is using liblldb)
701 {
702 lldb::AddressType address_type = m_value_type == eValueTypeLoadAddress ? eAddressTypeLoad : eAddressTypeHost;
703 lldb::addr_t addr = m_value.ULongLong(LLDB_INVALID_ADDRESS);
704 DataExtractor data;
Greg Claytone1a916a2010-07-21 22:12:05 +0000705 if (ClangASTType::ReadFromMemory (ast_context, opaque_clang_qual_type, exe_ctx, addr, address_type, data))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000706 {
Greg Claytone1a916a2010-07-21 22:12:05 +0000707 if (ClangASTType::GetValueAsScalar (ast_context, opaque_clang_qual_type, data, 0, data.GetByteSize(), scalar))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000708 {
709 m_value = scalar;
710 m_value_type = eValueTypeScalar;
711 }
712 else
713 {
714 if ((uintptr_t)addr != (uintptr_t)m_data_buffer.GetBytes())
715 {
716 m_value.Clear();
717 m_value_type = eValueTypeScalar;
718 }
719 }
720 }
721 else
722 {
723 if ((uintptr_t)addr != (uintptr_t)m_data_buffer.GetBytes())
724 {
725 m_value.Clear();
726 m_value_type = eValueTypeScalar;
727 }
728 }
729 }
730 break;
731 }
732
733
734 }
735 return m_value;
736}
737
738Variable *
739Value::GetVariable()
740{
741 if (m_context_type == eContextTypeValue)
742 return ((Value*)m_context)->GetVariable();
743
744 if (m_context_type == eContextTypeDCVariable)
745 return static_cast<Variable *> (m_context);
746 return NULL;
747}
748
749
750
751const char *
752Value::GetValueTypeAsCString (ValueType value_type)
753{
754 switch (value_type)
755 {
756 case eValueTypeScalar: return "scalar";
757 case eValueTypeFileAddress: return "file address";
758 case eValueTypeLoadAddress: return "load address";
759 case eValueTypeHostAddress: return "host address";
760 };
761 return "???";
762}
763
764const char *
765Value::GetContextTypeAsCString (ContextType context_type)
766{
767 switch (context_type)
768 {
769 case eContextTypeInvalid: return "invalid";
770 case eContextTypeOpaqueClangQualType: return "clang::Type *";
771 case eContextTypeDCRegisterInfo: return "RegisterInfo *";
772 case eContextTypeDCType: return "Type *";
773 case eContextTypeDCVariable: return "Variable *";
Greg Claytonc982c762010-07-09 20:39:50 +0000774 case eContextTypeValue: return "Value"; // TODO: Sean, more description here?
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000775 };
776 return "???";
777}
778
779ValueList::ValueList (const ValueList &rhs)
780{
781 m_values = rhs.m_values;
782}
783
784const ValueList &
785ValueList::operator= (const ValueList &rhs)
786{
787 m_values = rhs.m_values;
788 return *this;
789}
790
791void
792ValueList::PushValue (const Value &value)
793{
794 m_values.push_back (value);
795}
796
797size_t
798ValueList::GetSize()
799{
800 return m_values.size();
801}
802
803Value *
804ValueList::GetValueAtIndex (size_t idx)
805{
806 if (idx < GetSize())
807 {
808 return &(m_values[idx]);
809 }
810 else
811 return NULL;
812}
813
814void
815ValueList::Clear ()
816{
817 m_values.clear();
818}