Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ This project adheres to [Semantic Versioning], with the exception that minor rel

## [Unreleased]

### Changed

- ♻️ Extract singleton pattern into reusable template base class for QDMI devices and driver ([#1444]) ([**@ystade**], [**@burgholzer**])
- 🚚 Reorganize QDMI code structure by moving devices into dedicated subdirectories and separating driver and common utilities ([#1444]) ([**@ystade**])

## [3.4.0] - 2026-01-08

### Added
Expand Down Expand Up @@ -295,6 +300,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool

<!-- PR links -->

[#1444]: https://github.com/munich-quantum-toolkit/core/pull/1444
[#1415]: https://github.com/munich-quantum-toolkit/core/pull/1415
[#1414]: https://github.com/munich-quantum-toolkit/core/pull/1414
[#1413]: https://github.com/munich-quantum-toolkit/core/pull/1413
Expand Down
2 changes: 1 addition & 1 deletion bindings/fomac/fomac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

#include "fomac/FoMaC.hpp"

#include "qdmi/Driver.hpp"
#include "qdmi/driver/Driver.hpp"

#include <nanobind/nanobind.h>
#include <nanobind/operators.h>
Expand Down
2 changes: 1 addition & 1 deletion bindings/na/register_fomac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

#include "fomac/FoMaC.hpp"
#include "na/fomac/Device.hpp"
#include "qdmi/na/Generator.hpp"
#include "qdmi/devices/na/Generator.hpp"

#include <nanobind/nanobind.h>
#include <nanobind/operators.h>
Expand Down
2 changes: 1 addition & 1 deletion include/mqt-core/fomac/FoMaC.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

#pragma once

#include "qdmi/Common.hpp"
#include "qdmi/common/Common.hpp"

#include <algorithm>
#include <complex>
Expand Down
2 changes: 1 addition & 1 deletion include/mqt-core/na/fomac/Device.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#pragma once

#include "fomac/FoMaC.hpp"
#include "qdmi/na/Generator.hpp"
#include "qdmi/devices/na/Generator.hpp"

// NOLINTNEXTLINE(misc-include-cleaner)
#include <nlohmann/json.hpp>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,40 @@
#include <string>

namespace qdmi {
template <class Concrete> class Singleton {
protected:
/// @brief Protected constructor to enforce the singleton pattern.
Singleton() = default;

public:
// Delete move constructor and move assignment operator because of the
// following reason:
//
// - Users access the singleton via get() which returns a reference
// - Moving would invalidate the singleton's state
// - Users never own the singleton instance
Singleton(Singleton&&) = delete;
Singleton& operator=(Singleton&&) = delete;
// Delete copy constructor and assignment operator to enforce singleton.
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;

/// @brief Virtual destructor for the Singleton base class.
virtual ~Singleton() = default;

/// @returns the singleton instance of the derived class.
[[nodiscard]] static auto get() -> Concrete& {
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
static auto* instance = new Concrete();
// The instance is intentionally leaked to avoid static deinitialization
// issues (cf. static (de)initialization order fiasco)
return *instance;
}
};

/**
* @brief Function used to mark unreachable code
* @details Uses compiler specific extensions if possible. Even if no extension
* @details Uses compiler-specific extensions if possible. Even if no extension
* is used, undefined behavior is still raised by an empty function body and the
* noreturn attribute.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "dd/DDDefinitions.hpp"
#include "dd/Package.hpp"
#include "mqt_ddsim_qdmi/device.h"
#include "qdmi/common/Common.hpp"

#include <atomic>
#include <cstddef>
Expand All @@ -31,7 +32,9 @@
#include <unordered_map>

namespace qdmi::dd {
class Device final {
class Device final : public Singleton<Device> {
friend class Singleton;

/// Provides access to the device name.
std::string name_;

Expand Down Expand Up @@ -64,19 +67,6 @@ class Device final {
Device();

public:
// Default move constructor and move assignment operator.
Device(Device&&) = delete;
Device& operator=(Device&&) = delete;
// Delete copy constructor and assignment operator to enforce singleton.
Device(const Device&) = delete;
Device& operator=(const Device&) = delete;

/// @brief Destructor for the Device class.
~Device() = default;

/// @returns the singleton instance of the Device class.
[[nodiscard]] static auto get() -> Device&;

/**
* @brief Allocates a new device session.
* @see MQT_DDSIM_QDMI_device_session_alloc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

#include "mqt_na_qdmi/device.h"
#include "qdmi/common/Common.hpp"

#include <cstddef>
#include <cstdint>
Expand All @@ -27,7 +28,9 @@
#include <vector>

namespace qdmi::na {
class Device final {
class Device final : public Singleton<Device> {
friend class Singleton;

/// @brief Provides access to the device name.
std::string name_;

Expand Down Expand Up @@ -69,19 +72,6 @@ class Device final {
Device();

public:
// Default move constructor and move assignment operator.
Device(Device&&) = default;
Device& operator=(Device&&) = default;
// Delete copy constructor and assignment operator to enforce singleton.
Device(const Device&) = delete;
Device& operator=(const Device&) = delete;

/// @brief Destructor for the Device class.
~Device() = default;

/// @returns the singleton instance of the Device class.
[[nodiscard]] static auto get() -> Device&;

/**
* @brief Allocates a new device session.
* @see MQT_NA_QDMI_device_session_alloc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

#include "mqt_sc_qdmi/device.h"
#include "qdmi/common/Common.hpp"

#include <cstddef>
#include <cstdint>
Expand All @@ -26,7 +27,9 @@
#include <vector>

namespace qdmi::sc {
class Device final {
class Device final : public Singleton<Device> {
friend class Singleton;

/// @brief Provides access to the device name.
std::string name_;

Expand All @@ -51,19 +54,6 @@ class Device final {
Device();

public:
// Delete move constructor and move assignment operator.
Device(Device&&) = delete;
Device& operator=(Device&&) = delete;
// Delete copy constructor and assignment operator to enforce singleton.
Device(const Device&) = delete;
Device& operator=(const Device&) = delete;

/// @brief Destructor for the Device class.
~Device();

/// @returns the singleton instance of the Device class.
[[nodiscard]] static auto get() -> Device&;

/**
* @brief Allocates a new device session.
* @see MQT_SC_QDMI_device_session_alloc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

#pragma once

#include "qdmi/common/Common.hpp"

#include <cstddef>
#include <cstdint>
#include <memory>
Expand All @@ -18,7 +20,6 @@
#include <qdmi/device.h>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

namespace qdmi {
Expand Down Expand Up @@ -393,7 +394,9 @@ namespace qdmi {
* sessions. It is responsible for loading the libraries, allocating sessions,
* and providing access to the devices.
*/
class Driver final {
class Driver final : public Singleton<Driver> {
friend class Singleton;

/// @brief Private constructor to enforce the singleton pattern.
Driver();

Expand All @@ -410,21 +413,6 @@ class Driver final {
sessions_;

public:
// Delete copy constructors and assignment operators to prevent copying the
// singleton instance.
Driver(const Driver&) = delete;
Driver& operator=(const Driver&) = delete;
Driver(Driver&&) = default;
Driver& operator=(Driver&&) = default;

/// @brief Returns the singleton instance.
static auto get() -> Driver& {
static Driver instance;
return instance;
}

/// @brief Destructor for the Driver class.
~Driver();
/**
* @brief Loads a dynamic device library and adds it to the driver.
*
Expand Down
2 changes: 1 addition & 1 deletion src/fomac/FoMaC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

#include "fomac/FoMaC.hpp"

#include "qdmi/Common.hpp"
#include "qdmi/common/Common.hpp"

#include <algorithm>
#include <complex>
Expand Down
2 changes: 1 addition & 1 deletion src/na/fomac/Device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

#include "fomac/FoMaC.hpp"
#include "ir/Definitions.hpp"
#include "qdmi/na/Generator.hpp"
#include "qdmi/devices/na/Generator.hpp"

#include <algorithm>
#include <array>
Expand Down
53 changes: 3 additions & 50 deletions src/qdmi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,56 +6,9 @@
#
# Licensed under the MIT License

set(TARGET_NAME ${MQT_CORE_TARGET_NAME}-qdmi-common)

if(NOT TARGET ${TARGET_NAME})
# Add common library
add_mqt_core_library(${TARGET_NAME} ALIAS_NAME QDMICommon)

# Add sources to target
target_sources(${TARGET_NAME} PRIVATE Common.cpp)

# Add headers using file sets
target_sources(${TARGET_NAME} PUBLIC FILE_SET HEADERS BASE_DIRS ${MQT_CORE_INCLUDE_BUILD_DIR}
FILES ${MQT_CORE_INCLUDE_BUILD_DIR}/qdmi/Common.hpp)

# Add link libraries
target_link_libraries(
${TARGET_NAME}
PUBLIC qdmi::qdmi
PRIVATE qdmi::qdmi_project_warnings)

# add to list of MQT core targets
list(APPEND MQT_CORE_TARGETS ${TARGET_NAME})
endif()

add_subdirectory(dd)
add_subdirectory(sc)
add_subdirectory(na)

set(TARGET_NAME ${MQT_CORE_TARGET_NAME}-qdmi-driver)

if(NOT TARGET ${TARGET_NAME})
# Add driver library
add_mqt_core_library(${TARGET_NAME} ALIAS_NAME QDMIDriver)

# Add sources to target
target_sources(${TARGET_NAME} PRIVATE Driver.cpp)

# Add headers using file sets
target_sources(${TARGET_NAME} PUBLIC FILE_SET HEADERS BASE_DIRS ${MQT_CORE_INCLUDE_BUILD_DIR}
FILES ${MQT_CORE_INCLUDE_BUILD_DIR}/qdmi/Driver.hpp)

# Add link libraries
target_link_libraries(
${TARGET_NAME}
PUBLIC qdmi::qdmi MQT::CoreQDMICommon
PRIVATE MQT::CoreQDMINaDevice MQT::CoreQDMIScDevice MQT::CoreQDMI_DDSIM_Device
qdmi::qdmi_project_warnings spdlog::spdlog ${CMAKE_DL_LIBS})

# add to list of MQT core targets
list(APPEND MQT_CORE_TARGETS ${TARGET_NAME})
endif()
add_subdirectory(common)
add_subdirectory(devices)
add_subdirectory(driver)

set(MQT_CORE_TARGETS
${MQT_CORE_TARGETS}
Expand Down
34 changes: 34 additions & 0 deletions src/qdmi/common/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
# Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH
# All rights reserved.
#
# SPDX-License-Identifier: MIT
#
# Licensed under the MIT License

set(TARGET_NAME ${MQT_CORE_TARGET_NAME}-qdmi-common)

if(NOT TARGET ${TARGET_NAME})
# Add common library
add_mqt_core_library(${TARGET_NAME} ALIAS_NAME QDMICommon)

# Add sources to target
target_sources(${TARGET_NAME} PRIVATE Common.cpp)

# Add headers using file sets
target_sources(${TARGET_NAME} PUBLIC FILE_SET HEADERS BASE_DIRS ${MQT_CORE_INCLUDE_BUILD_DIR}
FILES ${MQT_CORE_INCLUDE_BUILD_DIR}/qdmi/common/Common.hpp)

# Add link libraries
target_link_libraries(
${TARGET_NAME}
PUBLIC qdmi::qdmi
PRIVATE qdmi::qdmi_project_warnings)

# add to list of MQT core targets
list(APPEND MQT_CORE_TARGETS ${TARGET_NAME})
endif()

set(MQT_CORE_TARGETS
${MQT_CORE_TARGETS}
PARENT_SCOPE)
2 changes: 1 addition & 1 deletion src/qdmi/Common.cpp → src/qdmi/common/Common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
/// @brief Common definitions and utilities for working with QDMI in C++.
/// @note This file will be upstreamed to the QDMI core library in the future.

#include "qdmi/Common.hpp"
#include "qdmi/common/Common.hpp"

#include <iostream>
#include <qdmi/constants.h>
Expand Down
Loading
Loading