1/*
2 * LegacyClonk
3 *
4 * Copyright (c) RedWolf Design
5 * Copyright (c) 2017-2022, The LegacyClonk Team and contributors
6 *
7 * Distributed under the terms of the ISC license; see accompanying file
8 * "COPYING" for details.
9 *
10 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11 * See accompanying file "TRADEMARK" for details.
12 *
13 * To redistribute this file separately, substitute the full license texts
14 * for the above references.
15 */
16
17#include <C4Include.h>
18#include <C4ValueList.h>
19#include <stdexcept>
20
21#include <C4Aul.h>
22#include <C4FindObject.h>
23
24#include <format>
25#include <compare>
26#include <ranges>
27
28C4ValueList::C4ValueList(const std::int32_t size)
29{
30 SetSize(size);
31}
32
33C4ValueList::C4ValueList(const C4ValueList &other)
34 : values{other.values}
35{
36}
37
38C4ValueList &C4ValueList::operator=(const C4ValueList &other)
39{
40 values.resize(new_size: other.values.size());
41
42 for (std::size_t i{0}; i < values.size(); ++i)
43 {
44 values[i].Set(other.values[i]);
45 }
46
47 return *this;
48}
49
50C4Value &C4ValueList::GetItem(std::int32_t index)
51{
52 if (index < 0) index = 0;
53
54 if (index >= GetSize() && index < MaxSize)
55 {
56 SetSize(index + 1);
57 }
58
59 if (index >= GetSize())
60 {
61 throw C4AulExecError(nullptr, "out of memory");
62 }
63
64 return values[index];
65}
66
67void C4ValueList::SetSize(const std::int32_t size)
68{
69 const auto cmp = size <=> GetSize();
70
71 if (cmp == std::strong_ordering::equal || (cmp == std::strong_ordering::greater && size > MaxSize))
72 {
73 return;
74 }
75
76 else if (cmp == std::strong_ordering::less)
77 {
78 values.resize(new_size: size);
79 return;
80 }
81
82 std::vector<C4Value> newValues(size);
83
84 for (std::size_t i{0}; i < values.size(); ++i)
85 {
86 values[i].Move(nValue: &newValues[i]);
87 }
88
89 values = std::move(newValues);
90}
91
92void C4ValueList::Reset()
93{
94 values.clear();
95}
96
97void C4ValueList::DenumeratePointers()
98{
99 std::ranges::for_each(values, &C4Value::DenumeratePointer);
100}
101
102void C4ValueList::CompileFunc(class StdCompiler *pComp)
103{
104 // FIXME: this should be one of C4ValueInt or (u)intptr_t (or C4ID), but which one?
105 int32_t size{GetSize()};
106 // Size. Reset if not found.
107 try
108 {
109 pComp->Value(rInt&: size);
110 }
111 catch (const StdCompiler::NotFoundException &)
112 {
113 Reset(); return;
114 }
115 // Separator
116 if (!pComp->Separator(eSep: StdCompiler::SEP_SEP2))
117 {
118 assert(pComp->isCompiler());
119 // No ';'-separator? So it's a really old value list format, or empty
120 pComp->Separator(eSep: StdCompiler::SEP_SEP);
121 this->SetSize(C4MaxVariable);
122 // First variable was misinterpreted as size
123 values[0] = C4Value{C4V_Data{.Int: size}, C4V_Any};
124 // Read remaining data
125 pComp->Value(rStruct: mkArrayAdaptS(array: values.data() + 1, size: C4MaxVariable - 1, default_: C4Value()));
126 }
127 else
128 {
129 if (pComp->isCompiler())
130 {
131 // Allocate
132 this->SetSize(size);
133 // Values
134 pComp->Value(rStruct: mkArrayAdaptS(array: values.data(), size, default_: C4Value()));
135 }
136 else
137 {
138 pComp->Value(rStruct: mkArrayAdaptS(array: values.data(), size));
139 }
140 }
141}
142
143C4ValueArray::C4ValueArray()
144 : C4ValueList() {}
145
146C4ValueArray::C4ValueArray(int32_t inSize)
147 : C4ValueList(inSize) {}
148
149C4ValueArray::C4ValueArray(const C4ValueArray &Array2)
150 : C4ValueList(Array2) {}
151
152C4ValueArray::~C4ValueArray() {}
153
154C4ValueArray *C4ValueArray::SetLength(int32_t size)
155{
156 if (GetRefCount() > 1)
157 {
158 C4ValueArray *pNew = static_cast<C4ValueArray *>((new C4ValueArray(size))->IncRef());
159 for (std::int32_t i = 0; i < (std::min)(a: size, b: GetSize()); i++)
160 pNew->values[i].Set(values[i]);
161 DecRef();
162 return pNew;
163 }
164 else
165 {
166 SetSize(size);
167 return this;
168 }
169}
170
171bool C4ValueArray::hasIndex(const C4Value &index) const
172{
173 C4Value copyIndex = index;
174 if (!copyIndex.ConvertTo(vtToType: C4V_Int)) throw std::runtime_error{std::format(fmt: "array access: can not convert \"{}\" to int", args: GetC4VName(Type: index.GetType()))};
175 return copyIndex._getInt() < GetSize();
176}
177
178C4Value &C4ValueArray::operator[](const C4Value &index)
179{
180 C4Value copyIndex = index;
181 if (!copyIndex.ConvertTo(vtToType: C4V_Int)) throw std::runtime_error{std::format(fmt: "array access: can not convert \"{}\" to int", args: GetC4VName(Type: index.GetType()))};
182 return (*this)[copyIndex._getInt()];
183}
184