diff --git a/GeoModelCore/GeoModelKernel/GeoModelKernel/Query.h b/GeoModelCore/GeoModelKernel/GeoModelKernel/Query.h index f3cde970c7cb54bec945d5a7bb6abd64deea6713..60dfaf7f39223a3b6b9b11caa5c33caffa963f26 100644 --- a/GeoModelCore/GeoModelKernel/GeoModelKernel/Query.h +++ b/GeoModelCore/GeoModelKernel/GeoModelKernel/Query.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration + Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration */ #ifndef GEOMODELKERNEL_QUERY_H @@ -18,54 +18,31 @@ * based on Barton & Nackman's "Scientific and Engineering C++" */ -#include <stdexcept> -template < class T > class Query +#include <GeoModelKernel/throwExcept.h> +#include <optional> +template < class T > class Query: public std::optional<T> { public: - - // Constructor: - inline Query (const T &); - - // Default constructor: - inline Query (); + /// Use all constructors from the std::optional + using std::optional<T>::optional; // Convert to "T" - inline operator T () const; + inline operator T () const; // Test Validity inline bool isValid () const; -private: - - bool m_failed; - T m_instance; - }; - -template < class T > inline Query < T >::Query (const T & t): -m_failed (false), -m_instance (t) -{ -} - -template < class T > inline Query < T >::Query (): -m_failed (true), -m_instance (T()) -{ +template < class T > inline Query < T >::operator T () const { + if (!this->isValid()){ + THROW_EXCEPTION("Nothing has been saved in query of type "<<typeid(T).name()); + } + return this->value_or(T{}); } - -template < class T > inline Query < T >::operator T () const -{ - if (m_failed) - throw std::range_error ("Failed query"); - return m_instance; -} - -template < class T > inline bool Query < T >::isValid () const -{ - return !m_failed; +template < class T > inline bool Query < T >::isValid () const { + return this->has_value(); } diff --git a/GeoModelCore/GeoModelKernel/tests/testQuery.cxx b/GeoModelCore/GeoModelKernel/tests/testQuery.cxx new file mode 100644 index 0000000000000000000000000000000000000000..61cc302d89ef63f6d71af684f78141c09f4c1c12 --- /dev/null +++ b/GeoModelCore/GeoModelKernel/tests/testQuery.cxx @@ -0,0 +1,78 @@ +/* + Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration + */ +#include "GeoModelKernel/Query.h" +#include "GeoModelKernel/throwExcept.h" + +#include <stdlib.h> +#include <iostream> + + +#define RETURN_FAILURE(MSG) { \ + std::cerr<<__FILE__<<":"<<__LINE__<<" -- "<<MSG<<std::endl; \ + return EXIT_FAILURE; \ +} +int main() { + + { + /// Test that the default constructor generates an invalid query + Query<int> emptyQuery{}; + if (emptyQuery.isValid()){ + RETURN_FAILURE("Empty query is not supposed to be valid." ); + } + } + { + /// Test that the nullopt constructor does what it's supposed to do + Query<int>emptyQuery{std::nullopt}; + if (emptyQuery.isValid()){ + RETURN_FAILURE("std::nullopt query is not supposed to be valid." ); + } + } + + Query<int> initQuery{5}; + if (!initQuery.isValid()){ + RETURN_FAILURE("Query is supposed to be valid... And have value of 5." ); + } + if (initQuery != 5) { + RETURN_FAILURE("Query is valid but has not 5 but instead "<<initQuery); + } + if (initQuery != 5) { + RETURN_FAILURE("Query is valid but has not 5 but instead "<<initQuery); + } + Query<int> copyQuery{initQuery}; + if (!copyQuery.isValid()){ + RETURN_FAILURE("The copy query is constructed from another valid one but is invalid..."); + } + if (copyQuery.value_or(-9999) != initQuery.value_or(9999)){ + RETURN_FAILURE("The copy query stores "<<copyQuery<<" while the other one has "<<initQuery); + } + copyQuery = std::nullopt; + if (copyQuery.isValid()){ + RETURN_FAILURE("After setting back to nullopt it's supposed to be invalid." ); + } + copyQuery = 7; + if (!copyQuery.isValid()){ + RETURN_FAILURE("Expect the query to be valid." ); + } + if (copyQuery != 7) { + RETURN_FAILURE("Expect the query to be 7 and not "<<copyQuery); + } + copyQuery = std::move(initQuery); + if (copyQuery != 5) { + RETURN_FAILURE("Expect the query to be 5 and not "<<copyQuery); + } + /// Apparently, the move on an optional does not invalidate the optional (https://stackoverflow.com/questions/51805059/why-does-moving-stdoptional-not-reset-state) + ///if (initQuery.isValid()) { + /// RETURN_FAILURE("Initial query needs to be invalid and not "<<initQuery); + ///} + initQuery = copyQuery; + if (!initQuery.isValid()) { + RETURN_FAILURE("Initial query needs to be valid again"); + } + if (copyQuery.value_or(-9999) != initQuery.value_or(9999)){ + RETURN_FAILURE("The copy query stores "<<copyQuery<<" while the other one has "<<initQuery); + } + std::cout<<__FILE__<<": - Test is passed. "<<std::endl; + return EXIT_SUCCESS; +} +