blob: de6500ef93818632fece98b774b52196fb23cf01 [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
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000209Value::ValueType
210Value::GetValueType() const
211{
212 if (m_context_type == eContextTypeValue)
213 return ((Value*)m_context)->GetValueType ();
214
215 return m_value_type;
216}
217
218lldb::AddressType
219Value::GetValueAddressType () const
220{
221 if (m_context_type == eContextTypeValue)
222 return ((Value*)m_context)->GetValueAddressType ();
223
224 switch (m_value_type)
225 {
226 default:
227 case eValueTypeScalar:
228 break;
229 case eValueTypeLoadAddress: return eAddressTypeLoad;
230 case eValueTypeFileAddress: return eAddressTypeFile;
231 case eValueTypeHostAddress: return eAddressTypeHost;
232 }
233 return eAddressTypeInvalid;
234}
235
236
237Value::ContextType
238Value::GetContextType() const
239{
240 if (m_context_type == eContextTypeValue)
241 return ((Value*)m_context)->GetContextType ();
242
243 return m_context_type;
244}
245
246void
247Value::SetValueType (Value::ValueType value_type)
248{
249 if (m_context_type == eContextTypeValue)
250 {
251 ((Value*)m_context)->SetValueType(value_type);
252 return;
253 }
254
255 m_value_type = value_type;
256}
257
258void
259Value::ClearContext ()
260{
261 if (m_context_type == eContextTypeValue)
262 {
263 ((Value*)m_context)->ClearContext();
264 return;
265 }
266
267 m_context = NULL;
268 m_context_type = eContextTypeInvalid;
269}
270
271void
272Value::SetContext (Value::ContextType context_type, void *p)
273{
274 if (m_context_type == eContextTypeValue)
275 {
276 ((Value*)m_context)->SetContext(context_type, p);
277 return;
278 }
279
280 m_context_type = context_type;
281 m_context = p;
282}
283
284RegisterInfo *
285Value::GetRegisterInfo()
286{
287 if (m_context_type == eContextTypeValue)
288 return ((Value*)m_context)->GetRegisterInfo();
289
290 if (m_context_type == eContextTypeDCRegisterInfo)
291 return static_cast<RegisterInfo *> (m_context);
292 return NULL;
293}
294
295Type *
296Value::GetType()
297{
298 if (m_context_type == eContextTypeValue)
299 return ((Value*)m_context)->GetType();
300
301 if (m_context_type == eContextTypeDCType)
302 return static_cast<Type *> (m_context);
303 return NULL;
304}
305
306Scalar &
307Value::GetScalar()
308{
309 if (m_context_type == eContextTypeValue)
310 return ((Value*)m_context)->GetScalar();
311
312 return m_value;
313}
314
315void
316Value::ResizeData(int len)
317{
318 if (m_context_type == eContextTypeValue)
319 {
320 ((Value*)m_context)->ResizeData(len);
321 return;
322 }
323
324 m_value_type = eValueTypeHostAddress;
325 m_data_buffer.SetByteSize(len);
326 m_value = (uintptr_t)m_data_buffer.GetBytes();
327}
328
329bool
330Value::ValueOf(ExecutionContext *exe_ctx, clang::ASTContext *ast_context)
331{
332 if (m_context_type == eContextTypeValue)
333 return ((Value*)m_context)->ValueOf(exe_ctx, ast_context);
334
335 switch (m_context_type)
336 {
337 default:
338 case eContextTypeInvalid:
339 case eContextTypeOpaqueClangQualType: // clang::Type *
340 case eContextTypeDCRegisterInfo: // RegisterInfo *
341 case eContextTypeDCType: // Type *
342 break;
343
344 case eContextTypeDCVariable: // Variable *
345 ResolveValue(exe_ctx, ast_context);
346 return true;
347 }
348 return false;
349}
350
351size_t
352Value::GetValueByteSize (clang::ASTContext *ast_context, Error *error_ptr)
353{
354 if (m_context_type == eContextTypeValue)
355 return ((Value*)m_context)->GetValueByteSize(ast_context, error_ptr);
356
357 size_t byte_size = 0;
358
359 switch (m_context_type)
360 {
361 default:
362 case eContextTypeInvalid:
363 // If we have no context, there is no way to know how much memory to read
364 if (error_ptr)
365 error_ptr->SetErrorString ("Invalid context type, there is no way to know how much memory to read.");
366 break;
367
368 case eContextTypeOpaqueClangQualType:
369 if (ast_context == NULL)
370 {
371 if (error_ptr)
372 error_ptr->SetErrorString ("Can't determine size of opaque clang type with NULL ASTContext *.");
373 }
374 else
375 {
Greg Claytonb0b9fe62010-08-03 00:35:52 +0000376 uint64_t bit_width = ClangASTType::GetClangTypeBitWidth (ast_context, m_context);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000377 byte_size = (bit_width + 7 ) / 8;
378 }
379 break;
380
381 case eContextTypeDCRegisterInfo: // RegisterInfo *
382 if (GetRegisterInfo())
383 byte_size = GetRegisterInfo()->byte_size;
384 else if (error_ptr)
385 error_ptr->SetErrorString ("Can't determine byte size with NULL RegisterInfo *.");
386
387 break;
388
389 case eContextTypeDCType: // Type *
390 if (GetType())
391 byte_size = GetType()->GetByteSize();
392 else if (error_ptr)
393 error_ptr->SetErrorString ("Can't determine byte size with NULL Type *.");
394 break;
395
396 case eContextTypeDCVariable: // Variable *
397 if (GetVariable())
398 byte_size = GetVariable()->GetType()->GetByteSize();
399 else if (error_ptr)
400 error_ptr->SetErrorString ("Can't determine byte size with NULL Variable *.");
401 break;
402 }
403
404 if (error_ptr)
405 {
406 if (byte_size == 0)
407 {
408 if (error_ptr->Success())
409 error_ptr->SetErrorString("Unable to determine byte size.");
410 }
411 else
412 {
413 error_ptr->Clear();
414 }
415 }
416 return byte_size;
417}
418
419void *
Greg Clayton1be10fc2010-09-29 01:12:09 +0000420Value::GetClangType ()
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000421{
422 if (m_context_type == eContextTypeValue)
Greg Clayton1be10fc2010-09-29 01:12:09 +0000423 return ((Value*)m_context)->GetClangType();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000424
425 switch (m_context_type)
426 {
427 default:
428 case eContextTypeInvalid:
429 break;
430
431 case eContextTypeOpaqueClangQualType:
432 return m_context;
433
434 case eContextTypeDCRegisterInfo:
435 break; // TODO: Eventually convert into a clang type?
436
437 case eContextTypeDCType:
438 if (GetType())
Greg Clayton1be10fc2010-09-29 01:12:09 +0000439 return GetType()->GetClangType();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000440 break;
441
442 case eContextTypeDCVariable:
443 if (GetVariable())
Greg Clayton1be10fc2010-09-29 01:12:09 +0000444 return GetVariable()->GetType()->GetClangType();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000445 break;
446 }
447
448 return NULL;
449}
450
451lldb::Format
452Value::GetValueDefaultFormat ()
453{
454 if (m_context_type == eContextTypeValue)
455 return ((Value*)m_context)->GetValueDefaultFormat();
456
457 switch (m_context_type)
458 {
459 default:
460 case eContextTypeInvalid:
461 break;
462
463 case eContextTypeOpaqueClangQualType:
Greg Claytone1a916a2010-07-21 22:12:05 +0000464 return ClangASTType::GetFormat (m_context);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000465
466 case eContextTypeDCRegisterInfo:
467 if (GetRegisterInfo())
468 return GetRegisterInfo()->format;
469 break;
470
471 case eContextTypeDCType:
472 if (GetType())
473 return GetType()->GetFormat();
474 break;
475
476 case eContextTypeDCVariable:
477 if (GetVariable())
478 return GetVariable()->GetType()->GetFormat();
479 break;
480
481 }
482
483 // Return a good default in case we can't figure anything out
484 return eFormatHex;
485}
486
487Error
488Value::GetValueAsData (ExecutionContext *exe_ctx, clang::ASTContext *ast_context, DataExtractor &data, uint32_t data_offset)
489{
490 if (m_context_type == eContextTypeValue)
491 return ((Value*)m_context)->GetValueAsData(exe_ctx, ast_context, data, data_offset);
492
493 data.Clear();
494
495 Error error;
496 lldb::addr_t address = LLDB_INVALID_ADDRESS;
497 lldb::AddressType address_type = eAddressTypeFile;
498 switch (m_value_type)
499 {
500 default:
501 error.SetErrorStringWithFormat("Invalid value type %i.\n", m_value_type);
502 break;
503
504 case eValueTypeScalar:
505 data.SetByteOrder (eByteOrderHost);
506 data.SetAddressByteSize(sizeof(void *));
507 if (m_value.GetData (data))
508 return error; // Success;
509 error.SetErrorStringWithFormat("Extracting data from value failed.\n");
510 break;
511
512 case eValueTypeLoadAddress:
513 if (exe_ctx == NULL)
514 {
515 error.SetErrorString ("Can't read memory (no execution context).");
516 }
517 else if (exe_ctx->process == NULL)
518 {
519 error.SetErrorString ("Can't read memory (invalid process).");
520 }
521 else
522 {
523 address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
524 address_type = eAddressTypeLoad;
525 data.SetByteOrder(exe_ctx->process->GetByteOrder());
526 data.SetAddressByteSize(exe_ctx->process->GetAddressByteSize());
527 }
528 break;
529
530 case eValueTypeFileAddress:
531 {
532 // The only thing we can currently lock down to a module so that
533 // we can resolve a file address, is a variable.
534 Variable *variable = GetVariable();
535
536 if (GetVariable())
537 {
538 lldb::addr_t file_addr = m_value.ULongLong(LLDB_INVALID_ADDRESS);
539 if (file_addr != LLDB_INVALID_ADDRESS)
540 {
541 SymbolContext var_sc;
542 variable->CalculateSymbolContext(&var_sc);
543 if (var_sc.module_sp)
544 {
545 ObjectFile *objfile = var_sc.module_sp->GetObjectFile();
546 if (objfile)
547 {
548 Address so_addr(file_addr, objfile->GetSectionList());
Greg Claytonf5e56de2010-09-14 23:36:40 +0000549 address = so_addr.GetLoadAddress (exe_ctx->target);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000550 if (address != LLDB_INVALID_ADDRESS)
Greg Claytonad3843c2010-08-18 18:28:52 +0000551 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000552 address_type = eAddressTypeLoad;
Greg Claytonad3843c2010-08-18 18:28:52 +0000553 data.SetByteOrder(exe_ctx->process->GetByteOrder());
554 data.SetAddressByteSize(exe_ctx->process->GetAddressByteSize());
555 }
556 else
557 {
558 data.SetByteOrder(objfile->GetByteOrder());
559 data.SetAddressByteSize(objfile->GetAddressByteSize());
560 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000561 }
562 if (address_type == eAddressTypeFile)
563 error.SetErrorStringWithFormat ("%s is not loaded.\n", var_sc.module_sp->GetFileSpec().GetFilename().AsCString());
564 }
565 else
566 {
567 error.SetErrorStringWithFormat ("Unable to resolve the module for file address 0x%llx for variable '%s'.\n", file_addr, variable->GetName().AsCString(""));
568 }
569 }
570 else
571 {
572 error.SetErrorString ("Invalid file address.");
573 }
574 }
575 else
576 {
577 // Can't convert a file address to anything valid without more
578 // context (which Module it came from)
579 error.SetErrorString ("Can't read memory from file address without more context.");
580 }
581 }
582 break;
583
584 case eValueTypeHostAddress:
585 address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
586 data.SetByteOrder(eByteOrderHost);
587 data.SetAddressByteSize(sizeof(void *));
588 address_type = eAddressTypeHost;
589 break;
590 }
591
592 // Bail if we encountered any errors
593 if (error.Fail())
594 return error;
595
596 if (address == LLDB_INVALID_ADDRESS)
597 {
598 error.SetErrorStringWithFormat ("Invalid %s address.\n", address_type == eAddressTypeHost ? "host" : "load");
599 return error;
600 }
601
602 // If we got here, we need to read the value from memory
603 uint32_t byte_size = GetValueByteSize (ast_context, &error);
604
605 // Bail if we encountered any errors getting the byte size
606 if (error.Fail())
607 return error;
608
609 // Make sure we have enough room within "data", and if we don't make
610 // something large enough that does
611 if (!data.ValidOffsetForDataOfSize (data_offset, byte_size))
612 {
613 DataBufferSP data_sp(new DataBufferHeap (data_offset + byte_size, '\0'));
614 data.SetData(data_sp);
615 }
616
Greg Claytonc982c762010-07-09 20:39:50 +0000617 uint8_t* dst = const_cast<uint8_t*>(data.PeekData (data_offset, byte_size));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000618 if (dst != NULL)
619 {
620 if (address_type == eAddressTypeHost)
621 {
622 // The address is an address in this process, so just copy it
623 memcpy (dst, (uint8_t*)NULL + address, byte_size);
624 }
625 else if (address_type == eAddressTypeLoad)
626 {
627 if (exe_ctx->process->ReadMemory(address, dst, byte_size, error) != byte_size)
628 {
629 if (error.Success())
630 error.SetErrorStringWithFormat("read %u bytes of memory from 0x%llx failed", (uint64_t)address, byte_size);
631 }
632 }
633 else
634 {
635 error.SetErrorStringWithFormat ("Unsupported lldb::AddressType value (%i).\n", address_type);
636 }
637 }
638 else
639 {
640 error.SetErrorStringWithFormat ("Out of memory.\n");
641 }
642
643 return error;
644}
645
646Scalar &
647Value::ResolveValue(ExecutionContext *exe_ctx, clang::ASTContext *ast_context)
648{
649 Scalar scalar;
650 if (m_context_type == eContextTypeValue)
651 {
652 // Resolve the proxy
653
654 Value * v = (Value*)m_context;
655
656 m_value = v->m_value;
657 m_value_type = v->m_value_type;
658 m_context = v->m_context;
659 m_context_type = v->m_context_type;
660
661 if ((uintptr_t)v->m_value.ULongLong(LLDB_INVALID_ADDRESS) == (uintptr_t)v->m_data_buffer.GetBytes())
662 {
663 m_data_buffer.CopyData(v->m_data_buffer.GetBytes(),
664 v->m_data_buffer.GetByteSize());
665
666 m_value = (uintptr_t)m_data_buffer.GetBytes();
667 }
668 }
669
670 if (m_context_type == eContextTypeOpaqueClangQualType)
671 {
Greg Clayton1be10fc2010-09-29 01:12:09 +0000672 void *opaque_clang_qual_type = GetClangType();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000673 switch (m_value_type)
674 {
675 case eValueTypeScalar: // raw scalar value
676 break;
677
Greg Claytonc982c762010-07-09 20:39:50 +0000678 case eContextTypeValue:
679 m_value.Clear(); // TODO: Sean, fill this in
680 break;
681
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000682 default:
683 case eValueTypeFileAddress:
684 m_value.Clear();
685 break;
686
687 case eValueTypeLoadAddress: // load address value
688 case eValueTypeHostAddress: // host address value (for memory in the process that is using liblldb)
689 {
690 lldb::AddressType address_type = m_value_type == eValueTypeLoadAddress ? eAddressTypeLoad : eAddressTypeHost;
691 lldb::addr_t addr = m_value.ULongLong(LLDB_INVALID_ADDRESS);
692 DataExtractor data;
Greg Claytone1a916a2010-07-21 22:12:05 +0000693 if (ClangASTType::ReadFromMemory (ast_context, opaque_clang_qual_type, exe_ctx, addr, address_type, data))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000694 {
Greg Claytone1a916a2010-07-21 22:12:05 +0000695 if (ClangASTType::GetValueAsScalar (ast_context, opaque_clang_qual_type, data, 0, data.GetByteSize(), scalar))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000696 {
697 m_value = scalar;
698 m_value_type = eValueTypeScalar;
699 }
700 else
701 {
702 if ((uintptr_t)addr != (uintptr_t)m_data_buffer.GetBytes())
703 {
704 m_value.Clear();
705 m_value_type = eValueTypeScalar;
706 }
707 }
708 }
709 else
710 {
711 if ((uintptr_t)addr != (uintptr_t)m_data_buffer.GetBytes())
712 {
713 m_value.Clear();
714 m_value_type = eValueTypeScalar;
715 }
716 }
717 }
718 break;
719 }
720
721
722 }
723 return m_value;
724}
725
726Variable *
727Value::GetVariable()
728{
729 if (m_context_type == eContextTypeValue)
730 return ((Value*)m_context)->GetVariable();
731
732 if (m_context_type == eContextTypeDCVariable)
733 return static_cast<Variable *> (m_context);
734 return NULL;
735}
736
737
738
739const char *
740Value::GetValueTypeAsCString (ValueType value_type)
741{
742 switch (value_type)
743 {
744 case eValueTypeScalar: return "scalar";
745 case eValueTypeFileAddress: return "file address";
746 case eValueTypeLoadAddress: return "load address";
747 case eValueTypeHostAddress: return "host address";
748 };
749 return "???";
750}
751
752const char *
753Value::GetContextTypeAsCString (ContextType context_type)
754{
755 switch (context_type)
756 {
757 case eContextTypeInvalid: return "invalid";
758 case eContextTypeOpaqueClangQualType: return "clang::Type *";
759 case eContextTypeDCRegisterInfo: return "RegisterInfo *";
760 case eContextTypeDCType: return "Type *";
761 case eContextTypeDCVariable: return "Variable *";
Greg Claytonc982c762010-07-09 20:39:50 +0000762 case eContextTypeValue: return "Value"; // TODO: Sean, more description here?
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000763 };
764 return "???";
765}
766
767ValueList::ValueList (const ValueList &rhs)
768{
769 m_values = rhs.m_values;
770}
771
772const ValueList &
773ValueList::operator= (const ValueList &rhs)
774{
775 m_values = rhs.m_values;
776 return *this;
777}
778
779void
780ValueList::PushValue (const Value &value)
781{
782 m_values.push_back (value);
783}
784
785size_t
786ValueList::GetSize()
787{
788 return m_values.size();
789}
790
791Value *
792ValueList::GetValueAtIndex (size_t idx)
793{
794 if (idx < GetSize())
795 {
796 return &(m_values[idx]);
797 }
798 else
799 return NULL;
800}
801
802void
803ValueList::Clear ()
804{
805 m_values.clear();
806}