mirror of
https://github.com/azahar-emu/sirit.git
synced 2026-03-20 19:21:03 +01:00
While looping here does work fine, it's mildly inefficient, particularly if the number of members being added is large, because it can result in multiple allocations over the period of the insertion, depending on how much extra memory push_back may allocate for successive elements. Instead, we can just tell the std::vector that we want to slap the whole contained sequence at the back of it with insert, which lets it allocate the whole memory block in one attempt.
136 lines
3.2 KiB
C++
136 lines
3.2 KiB
C++
/* This file is part of the sirit project.
|
|
* Copyright (c) 2018 ReinUsesLisp
|
|
* This software may be used and distributed according to the terms of the GNU
|
|
* Lesser General Public License version 3 or any later version.
|
|
*/
|
|
|
|
#include <cassert>
|
|
|
|
#include "common_types.h"
|
|
#include "literal_number.h"
|
|
#include "literal_string.h"
|
|
#include "op.h"
|
|
#include "operand.h"
|
|
|
|
namespace Sirit {
|
|
|
|
Op::Op(spv::Op opcode, std::optional<u32> id, Id result_type)
|
|
: opcode(opcode), result_type(result_type), id(id) {
|
|
operand_type = OperandType::Op;
|
|
}
|
|
|
|
Op::~Op() = default;
|
|
|
|
void Op::Fetch(Stream& stream) const {
|
|
assert(id.has_value());
|
|
stream.Write(id.value());
|
|
}
|
|
|
|
u16 Op::GetWordCount() const {
|
|
return 1;
|
|
}
|
|
|
|
bool Op::operator==(const Operand& other) const {
|
|
if (operand_type != other.GetType()) {
|
|
return false;
|
|
}
|
|
const Op& op = dynamic_cast<const Op&>(other);
|
|
if (op.opcode == opcode && result_type == op.result_type &&
|
|
operands.size() == op.operands.size()) {
|
|
for (std::size_t i = 0; i < operands.size(); i++) {
|
|
if (*operands[i] != *op.operands[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Op::Write(Stream& stream) const {
|
|
stream.Write(static_cast<u16>(opcode));
|
|
stream.Write(WordCount());
|
|
|
|
if (result_type) {
|
|
result_type->Fetch(stream);
|
|
}
|
|
if (id.has_value()) {
|
|
stream.Write(id.value());
|
|
}
|
|
for (const auto* operand : operands) {
|
|
operand->Fetch(stream);
|
|
}
|
|
}
|
|
|
|
void Op::Sink(Operand* operand) {
|
|
Add(static_cast<const Operand*>(operand));
|
|
operand_store.push_back(std::unique_ptr<Operand>(operand));
|
|
}
|
|
|
|
void Op::Sink(const std::vector<Operand*>& operands) {
|
|
for (auto* operand : operands) {
|
|
Sink(operand);
|
|
}
|
|
}
|
|
|
|
void Op::Add(const Literal& literal) {
|
|
Operand* operand = [&]() {
|
|
switch (literal.index()) {
|
|
case 0:
|
|
return LiteralNumber::Create(std::get<0>(literal));
|
|
case 1:
|
|
return LiteralNumber::Create(std::get<1>(literal));
|
|
case 2:
|
|
return LiteralNumber::Create(std::get<2>(literal));
|
|
case 3:
|
|
return LiteralNumber::Create(std::get<3>(literal));
|
|
case 4:
|
|
return LiteralNumber::Create(std::get<4>(literal));
|
|
case 5:
|
|
return LiteralNumber::Create(std::get<5>(literal));
|
|
default:
|
|
assert(!"Invalid literal type");
|
|
abort();
|
|
}
|
|
}();
|
|
Sink(operand);
|
|
}
|
|
|
|
void Op::Add(const std::vector<Literal>& literals) {
|
|
for (const auto& literal : literals) {
|
|
Add(literal);
|
|
}
|
|
}
|
|
|
|
void Op::Add(const Operand* operand) {
|
|
operands.push_back(operand);
|
|
}
|
|
|
|
void Op::Add(u32 integer) {
|
|
Sink(LiteralNumber::Create<u32>(integer));
|
|
}
|
|
|
|
void Op::Add(std::string string) {
|
|
Sink(new LiteralString(std::move(string)));
|
|
}
|
|
|
|
void Op::Add(const std::vector<Id>& ids) {
|
|
operands.insert(operands.end(), ids.begin(), ids.end());
|
|
}
|
|
|
|
u16 Op::WordCount() const {
|
|
u16 count = 1;
|
|
if (result_type) {
|
|
count++;
|
|
}
|
|
if (id.has_value()) {
|
|
count++;
|
|
}
|
|
for (const Operand* operand : operands) {
|
|
count += operand->GetWordCount();
|
|
}
|
|
return count;
|
|
}
|
|
|
|
} // namespace Sirit
|