vulkaninfo: use trivial_optional type instead of pair
authorCharles Giessen <charles@lunarg.com>
Tue, 18 May 2021 19:17:09 +0000 (13:17 -0600)
committerCharles Giessen <46324611+charles-lunarg@users.noreply.github.com>
Wed, 19 May 2021 19:59:25 +0000 (13:59 -0600)
Replace the ad-hoc pair with a bool and a type with a proper class that
makes the interface clear. The `util::trivial_optional<T>`
type requires T to be trivially copyable and constructable, but otherwise
follows the conventions of C++17's <optional>.

Change-Id: I5b3b981be0af2ecd4b05380a5d030b9ecc0be1d0

vulkaninfo/vulkaninfo.cpp
vulkaninfo/vulkaninfo.h

index c366d9c..effdd15 100644 (file)
@@ -275,7 +275,7 @@ void DumpGroups(Printer &p, AppInstance &inst) {
             p.AddNewline();
 
             auto group_capabilities = GetGroupCapabilities(inst, group);
-            if (group_capabilities.first == false) {
+            if (!group_capabilities) {
                 p.PrintKeyString("Present Capabilities",
                                  "Group does not support VK_KHR_device_group, skipping printing present capabilities");
             } else {
@@ -287,13 +287,13 @@ void DumpGroups(Printer &p, AppInstance &inst) {
 
                     for (uint32_t j = 0; j < group.physicalDeviceCount; j++) {
                         uint32_t mask = 1 << j;
-                        if (group_capabilities.second.presentMask[i] & mask) {
+                        if (group_capabilities->presentMask[i] & mask) {
                             p.PrintString(std::string(group_props[j].deviceName) + " (ID: " + p.DecorateAsValue(std::to_string(j)) +
                                           ")");
                         }
                     }
                 }
-                DumpVkDeviceGroupPresentModeFlagsKHR(p, "Present modes", group_capabilities.second.modes);
+                DumpVkDeviceGroupPresentModeFlagsKHR(p, "Present modes", group_capabilities->modes);
             }
             p.AddNewline();
             group_id++;
index 79cf475..29abbc2 100644 (file)
@@ -545,6 +545,43 @@ void freepNextChain(VkStructureHeader *first) {
     }
 }
 
+/* An ptional contains either a value or nothing. The trivial_optional asserts if a value is trying to be gotten but none exist.
+ * The interface is taken from C++17's <optional> with many aspects removed.
+ * This class assumes the template type is 'trivial'
+ */
+namespace util {
+template <typename T>
+struct trivial_optional {
+    using value_type = T;
+
+    bool _contains_value = false;
+    T _value;
+
+    void check_type_properties() {
+        static_assert(std::is_trivially_constructible<T>::value, "Type must be trivially constructable");
+        static_assert(std::is_trivially_copyable<T>::value, "Type must be trivially copyable");
+    }
+
+    trivial_optional() noexcept : _contains_value(false), _value({}) { check_type_properties(); }
+    trivial_optional(T value) noexcept : _contains_value(true), _value(value) { check_type_properties(); }
+
+    explicit operator bool() const noexcept { return _contains_value; }
+    bool has_value() const noexcept { return _contains_value; }
+
+    T value() const noexcept {
+        assert(_contains_value);
+        return _value;
+    }
+    // clang-format off
+    const T* operator->() const { assert(_contains_value); return _value;}
+    T* operator->() { assert(_contains_value); return &_value;}
+    const T& operator*() const& { assert(_contains_value); return _value;}
+    T& operator*() & { assert(_contains_value); return _value;}
+    const T&& operator*() const&& { assert(_contains_value); return _value;}
+    T&& operator*() && { assert(_contains_value); return _value;}
+    // clang-format on
+};  // namespace util
+}  // namespace util
 struct LayerExtensionList {
     VkLayerProperties layer_properties{};
     std::vector<VkExtensionProperties> extension_properties;
@@ -1294,9 +1331,8 @@ std::vector<VkPhysicalDeviceProperties> GetGroupProps(AppInstance &inst, VkPhysi
     return props;
 }
 
-// The bool of the pair returns true if the extension VK_KHR_device_group is present
-std::pair<bool, VkDeviceGroupPresentCapabilitiesKHR> GetGroupCapabilities(AppInstance &inst,
-                                                                          VkPhysicalDeviceGroupProperties group) {
+util::trivial_optional<VkDeviceGroupPresentCapabilitiesKHR> GetGroupCapabilities(AppInstance &inst,
+                                                                                 VkPhysicalDeviceGroupProperties group) {
     // Build create info for logical device made from all physical devices in this group.
     std::vector<std::string> extensions_list = {VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_DEVICE_GROUP_EXTENSION_NAME};
     VkDeviceGroupDeviceCreateInfoKHR dg_ci = {VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR, nullptr,
@@ -1316,9 +1352,8 @@ std::pair<bool, VkDeviceGroupPresentCapabilitiesKHR> GetGroupCapabilities(AppIns
     if (err != VK_SUCCESS && err != VK_ERROR_EXTENSION_NOT_PRESENT) THROW_VK_ERR("vkCreateDevice", err);
 
     if (err == VK_ERROR_EXTENSION_NOT_PRESENT) {
-        VkDeviceGroupPresentCapabilitiesKHR group_capabilities = {VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR, nullptr};
         inst.dll.fp_vkDestroyDevice(logical_device, nullptr);
-        return std::pair<bool, VkDeviceGroupPresentCapabilitiesKHR>(false, group_capabilities);
+        return {};
     }
 
     VkDeviceGroupPresentCapabilitiesKHR group_capabilities = {VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR, nullptr};
@@ -1330,7 +1365,7 @@ std::pair<bool, VkDeviceGroupPresentCapabilitiesKHR> GetGroupCapabilities(AppIns
 
     inst.dll.fp_vkDestroyDevice(logical_device, nullptr);
 
-    return std::pair<bool, VkDeviceGroupPresentCapabilitiesKHR>(true, group_capabilities);
+    return {group_capabilities};
 }
 
 // -------------------- Device Setup ------------------- //