missions and
 * limitations under the License.
 */

#include "src/binary-reader-opcnt.h"

#include <cassert>
#include <cinttypes>
#include <cstdarg>
#include <cstdint>
#include <cstdio>

#include "src/binary-reader-nop.h"
#include "src/common.h"
#include "src/literal.h"
#include "src/stream.h"

namespace wabt {

OpcodeInfo::OpcodeInfo(Opcode opcode, Kind kind)
    : opcode_(opcode), kind_(kind) {}

template <typename T>
OpcodeInfo::OpcodeInfo(Opcode opcode, Kind kind, T* data, size_t count)
    : OpcodeInfo(opcode, kind) {
  if (count > 0) {
    data_.resize(sizeof(T) * count);
    memcpy(data_.data(), data, data_.size());
  }
}

template <typename T>
OpcodeInfo::OpcodeInfo(Opcode opcode, Kind kind, T* data, size_t count, T extra)
    : OpcodeInfo(opcode, kind, data, count) {
  data_.resize(data_.size() + sizeof(T));
  memcpy(data_.data() + data_.size() - sizeof(T), &extra, sizeof(T));
}

template <typename T>
std::pair<const T*, size_t> OpcodeInfo::GetDataArray() const {
  if (data_.empty()) {
    return std::pair<const T*, size_t>(nullptr, 0);
  }

  assert(data_.size() % sizeof(T) == 0);
  return std::make_pair(reinterpret_cast<const T*>(data_.data()),
                        data_.size() / sizeof(T));
}

template <typename T>
const T* OpcodeInfo::GetData(size_t expected_size) const {
  auto pair = GetDataArray<T>();
  assert(pair.second == expected_size);
  return pair.first;
}

template <typename T, typename F>
void OpcodeInfo::WriteArray(Stream& stream, F&& write_func) {
  auto pair = GetDataArray<T>();
  for (size_t i = 0; i < pair.second; ++i) {
    // Write an initial space (to separate from the opcode name) first, then
    // comma-separate.
    stream.Writef("%s", i == 0 ? " " : ", ");
    write_func(pair.first[i]);
  }
}

void OpcodeInfo::Write(Stream& stream) {
  stream.Writef("%s", opcode_.GetName());

  switch (kind_) {
    case Kind::Bare:
      break;

    case Kind::Uint32:
      stream.Writef(" %u (0x%x)", *GetData<uint32_t>(), *GetData<uint32_t>());
      break;

    case Kind::Uint64:
      s