text: //===-- Value.h -------------------------------------------------*- C++ -*-===//
  //
  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  // See https://llvm.org/LICENSE.txt for license information.
  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  //
  //===----------------------------------------------------------------------===//
  
  #ifndef liblldb_Value_h_
  #define liblldb_Value_h_
  
  #include "lldb/Symbol/CompilerType.h"
  #include "lldb/Utility/DataBufferHeap.h"
  #include "lldb/Utility/Scalar.h"
  #include "lldb/Utility/Status.h"
  #include "lldb/lldb-enumerations.h"
  #include "lldb/lldb-private-enumerations.h"
  #include "lldb/lldb-private-types.h"
  
  #include "llvm/ADT/APInt.h"
  
  #include <vector>
  
  #include <stdint.h>
  #include <string.h>
  
  namespace lldb_private {
  class DataExtractor;
  class ExecutionContext;
  class Module;
  class Stream;
  class Type;
  class Variable;
  }
  
  namespace lldb_private {
  
  class Value {
  public:
    // Values Less than zero are an error, greater than or equal to zero returns
    // what the Scalar result is.
    enum ValueType {
      // m_value contains...
      // ============================
      eValueTypeScalar,      // raw scalar value
      eValueTypeVector,      // byte array of m_vector.length with endianness of
                             // m_vector.byte_order
      eValueTypeFileAddress, // file address value
      eValueTypeLoadAddress, // load address value
      eValueTypeHostAddress  // host address value (for memory in the process that
                             // is using liblldb)
    };
  
    enum ContextType // Type that describes Value::m_context
    {
      // m_context contains...
      // ====================
      eContextTypeInvalid,      // undefined
      eContextTypeRegisterInfo, // RegisterInfo * (can be a scalar or a vector
                                // register)
      eContextTypeLLDBType,     // lldb_private::Type *
      eContextTypeVariable      // lldb_private::Variable *
    };
  
    const static size_t kMaxByteSize = 32u;
  
    struct Vector {
      // The byte array must be big enough to hold vector registers for any
      // supported target.
      uint8_t bytes[kMaxByteSize];
      size_t length;
      lldb::ByteOrder byte_order;
  
      Vector() : length(0), byte_order(lldb::eByteOrderInvalid) {}
  
      Vector(const Vector &vector) { *this = vector; }
      const Vector &operator=(const Vector &vector) {
        SetBytes(vector.bytes, vector.length, vector.byte_order);
        return *this;
      }
  
      void Clear() { length = 0; }
  
      bool SetBytes(const void *bytes, size_t length,
                    lldb::ByteOrder byte_order) {
        this->length = length;
        this->byte_order = byte_order;
        if (length)
          ::memcpy(this->bytes, bytes,
                   length < kMaxByteSize ? length : kMaxByteSize);
        return IsValid();
      }
  
      bool IsValid() const {
        return (length > 0 && length < kMaxByteSize &&
                byte_order != lldb::eByteOrderInvalid);
      }
      // Casts a vector, if valid, to an unsigned int of matching or largest
      // supported size. Truncates to the beginning of the vector if required.
      // Returns a default constructed Scalar if the Vector data is internally
      // inconsistent.
      llvm::APInt rhs = llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128,
                                    ((type128 *)bytes)->x);
      Scalar GetAsScalar() const {
        Scalar scalar;
        if (IsValid()) {
          if (length == 1)
            scalar = *(const uint8_t *)bytes;
          else if (length == 2)
            scalar = *(const uint16_t *)bytes;
          else if (length == 4)
            scalar = *(const uint32_t *)bytes;
          else if (length == 8)
            scalar = *(const uint64_t *)bytes;
          else if (length >= 16)
            scalar = rhs;
        }
        return scalar;
      }
    };
  
    Value();
    Value(const Scalar &scalar);
    Value(const Vector &vector);
    Value(const void *bytes, int len);
    Value(const Value &rhs);
  
    void SetBytes(const void *bytes, int len);
  
    void AppendBytes(const void *bytes, int len);
  
    Value &operator=(const Value &rhs);
  
    const CompilerType &GetCompilerType();
  
    void SetCompilerType(const CompilerType &compiler_type);
  
    ValueType GetValueType() const;
  
    AddressType GetValueAddressType() const;
  
    ContextType GetContextType() const { return m_context_type; }
  
    void SetValueType(ValueType value_type) { m_value_type = value_type; }
  
    void ClearContext() {
      m_context = nullptr;
      m_context_type = eContextTypeInvalid;
    }
  
    void SetContext(ContextType context_type, void *p) {
      m_context_type = context_type;
      m_context = p;
      if (m_context_type == eContextTypeRegisterInfo) {
        RegisterInfo *reg_info = GetRegisterInfo();
        if (reg_info->encoding == lldb::eEncodingVector &&
            m_vector.byte_order != lldb::eByteOrderInvalid)
          SetValueType(eValueTypeScalar);
      }
    }
  
    RegisterInfo *GetRegisterInfo() const;
  
    Type *GetType();
  
    Scalar &ResolveValue(ExecutionContext *exe_ctx);
  
    const Scalar &GetScalar() const { return m_value; }
  
    const Vector &GetVector() const { return m_vector; }
  
    Scalar &GetScalar() { return m_value; }
  
    Vector &GetVector() { return m_vector; }
  
    bool SetVectorBytes(const Vector &vector) {
      m_vector = vector;
      return m_vector.IsValid();
    }
  
    bool SetVectorBytes(uint8_t *bytes, size_t length,
                        lldb::ByteOrder byte_order) {
      return m_vector.SetBytes(bytes, length, byte_order);
    }
  
    bool SetScalarFromVector() {
      if (m_vector.IsValid()) {
        m_value = m_vector.GetAsScalar();
        return true;
      }
      return false;
    }
  
    size_t ResizeData(size_t len);
  
    size_t AppendDataToHostBuffer(const Value &rhs);
  
    DataBufferHeap &GetBuffer() { return m_data_buffer; }
  
    const DataBufferHeap &GetBuffer() const { return m_data_buffer; }
  
    bool ValueOf(ExecutionContext *exe_ctx);
  
    Variable *GetVariable();
  
    void Dump(Stream *strm);
  
    lldb::Format GetValueDefaultFormat();
  
    uint64_t GetValueByteSize(Status *error_ptr, ExecutionContext *exe_ctx);
  
    Status GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data,
                          uint32_t data_offset,
                          Module *module); // Can be nullptr
  
    static const char *GetValueTypeAsCString(ValueType context_type);
  
    static const char *GetContextTypeAsCString(ContextType context_type);
  
    /// Convert this value's file address to a load address, if possible.
    void ConvertToLoadAddress(Module *module, Target *target);
  
    bool GetData(DataExtractor &data);
  
    void Clear();
  
  protected:
    Scalar m_value;
    Vector m_vector;
    CompilerType m_compiler_type;
    void *m_context;
    ValueType m_value_type;
    ContextType m_context_type;
    DataBufferHeap m_data_buffer;
  };
  
  class ValueList {
  public:
    ValueList() : m_values() {}
  
    ValueList(const ValueList &rhs);
  
    ~ValueList() = default;
  
    const ValueList &operator=(const ValueList &rhs);
  
    // void InsertValue (Value *value, size_t idx);
    void PushValue(const Value &value);
  
    size_t GetSize();
    Value *GetValueAtIndex(size_t idx);
    void Clear();
  
  private:
    typedef std::vector<Value> collection;
  
    collection m_values;
  };
  
  } // namespace lldb_private
  
  #endif // liblldb_Value_h_
  