Vuo  2.3.2
VuoCompilerCompatibility.cc
Go to the documentation of this file.
1 
11 #include "VuoStringUtilities.hh"
12 
13 const map<string, string> VuoCompilerCompatibility::knownPlatforms = {
14  {"macos", "macOS"}
15 };
16 
17 const map<string, string> VuoCompilerCompatibility::knownArchitectures = {
18  {"x86_64", "an Intel (X86-64) CPU"},
19  {"arm64", "an Apple Silicon (M1/ARM64) 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 
421 {
422  return VuoCompilerCompatibility(nullptr);
423 }
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 
464 json_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 
480 string 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 
489 vector<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 }