Vuo 2.4.4
Loading...
Searching...
No Matches
VuoCompilerCompatibility.cc
Go to the documentation of this file.
1
11#include "VuoStringUtilities.hh"
12
13const map<string, string> VuoCompilerCompatibility::knownPlatforms = {
14 {"macos", "macOS"}
15};
16
17const map<string, string> VuoCompilerCompatibility::knownArchitectures = {
18 {"x86_64", "an Intel (X86-64) CPU"},
19 {"arm64", "an Apple Silicon (ARM64/M1/M2/M3) CPU"}
20};
21
30{
31 this->json = json;
32
33 if (json)
34 json_object_get(json);
35}
36
41{
42 this->json = other.json;
43
44 if (json)
45 json_object_get(json);
46}
47
52{
53 if (this == &other)
54 return *this;
55
56 this->json = other.json;
57
58 if (json)
59 json_object_get(json);
60
61 return *this;
62}
63
68{
69 if (json)
70 json_object_put(json);
71}
72
77{
78 VuoCompilerCompatibility intersect = intersection(other);
79
80 if (! intersect.json || ! other.json)
81 return ! intersect.json && ! other.json;
82
83 return json_object_equal(intersect.json, other.json);
84}
85
90{
91 if (! json)
92 return other;
93
94 if (! other.json)
95 return *this;
96
97 json_object *intersect = json_object_new_object();
98
99 vector<string> platforms;
100 {
101 json_object_object_foreach(json, platform, val)
102 {
103 platforms.push_back(platform);
104 }
105 }
106 {
107 json_object_object_foreach(other.json, platform, val)
108 {
109 platforms.push_back(platform);
110 }
111 }
112
113 for (string platform : platforms)
114 {
115 // Is this platform compatible with both?
116
117 bool thisPlatformCompatible;
118 json_object *thisPlatformVal = findPlatform(json, platform, thisPlatformCompatible);
119
120 bool otherPlatformCompatible;
121 json_object *otherPlatformVal = findPlatform(other.json, platform, otherPlatformCompatible);
122
123 if (! (thisPlatformCompatible && otherPlatformCompatible))
124 {
125 json_object_object_add(intersect, platform.c_str(), json_object_new_boolean(false));
126 continue; // The platform is not compatible with both.
127 }
128
129 if (! otherPlatformVal)
130 {
131 json_object_object_add(intersect, platform.c_str(), thisPlatformVal);
132 continue; // The platform only has restrictions in `this`.
133 }
134
135 if (! thisPlatformVal)
136 {
137 json_object_object_add(intersect, platform.c_str(), otherPlatformVal);
138 continue; // The platform only has restrictions in `other`.
139 }
140
141 // Which architectures are compatible with both?
142
143 vector<string> thisArchVec = findArchitectures(thisPlatformVal);
144 vector<string> otherArchVec = findArchitectures(otherPlatformVal);
145
146 vector<string> intersectArchVec;
147 if (thisArchVec.empty())
148 intersectArchVec = otherArchVec;
149 else if (otherArchVec.empty())
150 intersectArchVec = thisArchVec;
151 else
152 {
153 set_intersection(thisArchVec.begin(), thisArchVec.end(),
154 otherArchVec.begin(), otherArchVec.end(),
155 std::back_inserter(intersectArchVec));
156
157 if (intersectArchVec.empty())
158 {
159 json_object_object_add(intersect, platform.c_str(), json_object_new_boolean(false));
160 continue; // No architectures are compatible with both.
161 }
162 }
163
164 json_object *intersectArch = nullptr;
165 if (! intersectArchVec.empty())
166 {
167 intersectArch = json_object_new_array_ext(intersectArchVec.size());
168 for (size_t i = 0; i < intersectArchVec.size(); ++i)
169 {
170 json_object *a = json_object_new_string(intersectArchVec[i].c_str());
171 json_object_array_put_idx(intersectArch, i, a);
172 }
173 }
174
175 // Which OS versions are compatible with both?
176
177 string thisMin = findVersion(thisPlatformVal, "min");
178 string thisMax = findVersion(thisPlatformVal, "max");
179 string otherMin = findVersion(otherPlatformVal, "min");
180 string otherMax = findVersion(otherPlatformVal, "max");
181
182 auto compareVersions = [](const string &a, const string &b)
183 {
184 vector<string> as = VuoStringUtilities::split(a, '.');
185 vector<string> bs = VuoStringUtilities::split(b, '.');
186 for (size_t i = 0; i < max(as.size(), bs.size()); ++i)
187 {
188 int ai = (i < as.size() ? atoi(as[i].c_str()) : 0);
189 int bi = (i < bs.size() ? atoi(bs[i].c_str()) : 0);
190 if (ai < bi)
191 return true;
192 if (bi < ai)
193 return false;
194 }
195 return false;
196 };
197
198 string greaterMin;
199 if (! thisMin.empty() || ! otherMin.empty())
200 {
201 if (thisMin.empty())
202 greaterMin = otherMin;
203 else if (otherMin.empty())
204 greaterMin = thisMin;
205 else
206 {
207 vector<string> mins = {thisMin, otherMin};
208 sort(mins.begin(), mins.end(), compareVersions);
209 greaterMin = mins[1];
210 }
211 }
212
213 string lesserMax;
214 if (! thisMax.empty() || ! otherMax.empty())
215 {
216 if (thisMax.empty())
217 lesserMax = otherMax;
218 else if (otherMax.empty())
219 lesserMax = thisMax;
220 else
221 {
222 vector<string> maxes = {thisMax, otherMax};
223 sort(maxes.begin(), maxes.end(), compareVersions);
224 lesserMax = maxes[0];
225 }
226 }
227
228 if (! greaterMin.empty() && ! lesserMax.empty())
229 {
230 vector<string> minMax = {greaterMin, lesserMax};
231 vector<string> sortedMinMax = minMax;
232 sort(sortedMinMax.begin(), sortedMinMax.end(), compareVersions);
233 if (minMax != sortedMinMax)
234 {
235 json_object_object_add(intersect, platform.c_str(), json_object_new_boolean(false));
236 continue; // No OS versions are compatible with both.
237 }
238 }
239
240 json_object *intersectMinVersion = nullptr;
241 if (! greaterMin.empty())
242 intersectMinVersion = json_object_new_string(greaterMin.c_str());
243
244 json_object *intersectMaxVersion = nullptr;
245 if (! lesserMax.empty())
246 intersectMaxVersion = json_object_new_string(lesserMax.c_str());
247
248 // Add the restrictions for this platform.
249
250 if (intersectArch || intersectMinVersion || intersectMaxVersion)
251 {
252 json_object *intersectPlatform = json_object_new_object();
253 if (intersectArch)
254 json_object_object_add(intersectPlatform, "arch", intersectArch);
255 if (intersectMinVersion)
256 json_object_object_add(intersectPlatform, "min", intersectMinVersion);
257 if (intersectMaxVersion)
258 json_object_object_add(intersectPlatform, "max", intersectMaxVersion);
259 json_object_object_add(intersect, platform.c_str(), intersectPlatform);
260 }
261 }
262
263 return VuoCompilerCompatibility(intersect);
264}
265
270{
271 if (! json)
272 return "any system that Vuo supports";
273
274 auto labelForKey = [](const string &key, const map<string, string> &keysAndLabels)
275 {
276 auto iter = keysAndLabels.find(key);
277 if (iter != keysAndLabels.end())
278 return iter->second;
279 else
280 return key;
281 };
282
283 auto macOSDisplayName = [](const string &version) {
284 if (version < "10.16" || version >= "11")
285 return version;
286
287 // Map "10.16" to "11", and "10.17" to "12", …
288 auto parts = VuoStringUtilities::split(version, '.');
289 if (parts.size() < 2)
290 return version;
291
292 return to_string(stoi(parts[1]) - 5);
293 };
294
295 vector<string> platformStrings;
296 json_object_object_foreach(json, platformKey, platformVal)
297 {
298 // Platform
299
300 string p = labelForKey(platformKey, knownPlatforms);
301
302 // OS versions
303
304 string min = findVersion(platformVal, "min");
305 string max = findVersion(platformVal, "max");
306
307 string versions;
308 if (! min.empty() || ! max.empty())
309 {
310 if (! min.empty())
311 min = macOSDisplayName(min);
312 if (! max.empty())
313 max = macOSDisplayName(max);
314
315 if (min == max)
316 versions = min;
317 else if (min.empty())
318 versions = max + " and below";
319 else if (max.empty())
320 versions = min + " and above";
321 else
322 versions = min + " through " + max;
323 }
324
325 // Architectures
326
327 vector<string> archKeys = findArchitectures(platformVal);
328 vector<string> archList;
329 std::transform(archKeys.begin(), archKeys.end(),
330 std::back_inserter(archList),
331 [&](string a) { return labelForKey(a, knownArchitectures); });
332 string architectures = VuoStringUtilities::join(archList, " or ");
333
334 if (! versions.empty())
335 p += " " + versions;
336 if (! architectures.empty())
337 p += " on " + architectures;
338 platformStrings.push_back(p);
339 }
340
341 return VuoStringUtilities::join(platformStrings, ", or ");
342}
343
348{
349 return json_object_to_json_string_ext(json, JSON_C_TO_STRING_PLAIN);
350}
351
356{
357 bool isPlatformCompatible;
358 findPlatform(json, platform.c_str(), isPlatformCompatible);
359 return isPlatformCompatible;
360}
361
366{
367 bool isPlatformCompatible;
368 json_object *platformVal = findPlatform(json, platform.c_str(), isPlatformCompatible);
369 if (platformVal)
370 {
371 json_object *min = nullptr;
372 if (json_object_object_get_ex(platformVal, "min", &min))
373 return json_object_get_string(min);
374 }
375
376 return "";
377}
378
384{
385 vector<string> parts = VuoStringUtilities::split(target, '-');
386
387 string arch = parts.at(0);
388
389 string platform;
390 string version;
391 if (VuoStringUtilities::beginsWith(parts.at(2), "macosx"))
392 {
393 platform = "macos";
394
395 version = parts.at(2).substr(6);
396 version = version.substr(0, version.rfind("."));
397 }
398
399 json_object *json = json_object_new_object();
400
401 json_object *platformVal = json_object_new_object();
402 json_object_object_add(json, platform.c_str(), platformVal);
403
404 json_object *archVal = json_object_new_string(arch.c_str());
405 json_object *archArray = json_object_new_array_ext(1);
406 json_object_array_put_idx(archArray, 0, archVal);
407 json_object_object_add(platformVal, "arch", archArray);
408
409 json_object *minVal = json_object_new_string(version.c_str());
410 json_object *maxVal = json_object_new_string(version.c_str());
411 json_object_object_add(platformVal, "min", minVal);
412 json_object_object_add(platformVal, "max", maxVal);
413
414 return VuoCompilerCompatibility(json);
415}
416
424
429{
430 if (architectures.empty())
431 return VuoCompilerCompatibility(nullptr);
432
433 set<string> knownArchitectureKeys;
434 std::transform(knownArchitectures.begin(), knownArchitectures.end(),
435 std::inserter(knownArchitectureKeys, knownArchitectureKeys.end()),
436 [](const pair<string, string> &p) { return p.first; });
437 if (knownArchitectureKeys == architectures)
438 return VuoCompilerCompatibility(nullptr);
439
440 json_object *archArray = json_object_new_array_ext(architectures.size());
441 int i = 0;
442 for (string arch : architectures)
443 {
444 json_object *archVal = json_object_new_string(arch.c_str());
445 json_object_array_put_idx(archArray, i++, archVal);
446 }
447
448 json_object *json = json_object_new_object();
449
450 for (auto platform : knownPlatforms)
451 {
452 json_object *platformVal = json_object_new_object();
453 json_object_object_add(json, platform.first.c_str(), platformVal);
454
455 json_object_object_add(platformVal, "arch", archArray);
456 json_object_get(archArray);
457 }
458
459 json_object_put(archArray);
460
461 return VuoCompilerCompatibility(json);
462}
463
464json_object * VuoCompilerCompatibility::findPlatform(json_object *json, string platformKey, bool &isPlatformCompatible)
465{
466 isPlatformCompatible = true;
467
468 json_object *platformVal = nullptr;
469 if (json_object_object_get_ex(json, platformKey.c_str(), &platformVal))
470 {
471 if (json_object_is_type(platformVal, json_type_boolean))
472 isPlatformCompatible = false;
473
474 return platformVal;
475 }
476
477 return nullptr;
478}
479
480string VuoCompilerCompatibility::findVersion(json_object *platformVal, const string &minOrMax)
481{
482 json_object *versionVal;
483 if (json_object_object_get_ex(platformVal, minOrMax.c_str(), &versionVal))
484 return json_object_get_string(versionVal);
485
486 return "";
487}
488
489vector<string> VuoCompilerCompatibility::findArchitectures(json_object *platformVal)
490{
491 vector<string> architectures;
492
493 json_object *arch = nullptr;
494 if (json_object_object_get_ex(platformVal, "arch", &arch))
495 {
496 size_t len = json_object_array_length(arch);
497 for (size_t i = 0; i < len; ++i)
498 {
499 json_object *a = json_object_array_get_idx(arch, i);
500 architectures.push_back(json_object_get_string(a));
501 }
502 }
503
504 return architectures;
505}