From 251e7e4fd95b4fd8678ccabc09bf167e82f5e095 Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Fri, 15 Nov 2019 12:33:19 +0100 Subject: [PATCH] use optional ref in environment nesting --- alib2cli/src/environment/Environment.h | 11 +- alib2std/src/alib/optional | 1 + .../src/extensions/container/optional.hpp | 1 + .../src/extensions/container/optional_ref.hpp | 278 ++++++++++++++++++ .../extensions/container/OptionalTest.cpp | 19 ++ 5 files changed, 308 insertions(+), 2 deletions(-) create mode 100644 alib2std/src/extensions/container/optional_ref.hpp create mode 100644 alib2std/test-src/extensions/container/OptionalTest.cpp diff --git a/alib2cli/src/environment/Environment.h b/alib2cli/src/environment/Environment.h index b7d7fc72d0..351dbb7e67 100644 --- a/alib2cli/src/environment/Environment.h +++ b/alib2cli/src/environment/Environment.h @@ -5,6 +5,7 @@ #include <alib/map> #include <alib/memory> #include <alib/typeinfo> +#include <alib/optional> #include <abstraction/Value.hpp> #include <exception/CommonException.h> @@ -20,7 +21,7 @@ class Environment { ext::map < std::string, std::shared_ptr < abstraction::Value > > m_variables; std::shared_ptr < abstraction::Value > m_result; - std::unique_ptr < Environment > m_upper; + ext::optional_ref < Environment > m_upper; std::shared_ptr < abstraction::Value > getVariableInt ( const std::string & name ) const { auto res = m_variables.find ( name ); @@ -41,7 +42,7 @@ class Environment { public: Environment ( ) = default; - Environment ( std::unique_ptr < Environment > upper ) : m_upper ( std::move ( upper ) ) { + Environment ( ext::optional_ref < Environment > upper ) : m_upper ( std::move ( upper ) ) { } std::string getBinding ( const std::string & name ) const { @@ -118,6 +119,12 @@ public: cli::CommandResult execute ( std::shared_ptr < cli::LineInterface > lineInterface ); cli::CommandResult execute_line ( cli::CharSequence charSequence ); + + Environment & getGlobalScope ( ) { + if ( ! ( bool ) m_upper ) + return * this; + return getGlobalScope ( ); + } }; } /* namespace cli */ diff --git a/alib2std/src/alib/optional b/alib2std/src/alib/optional index 0d36636307..1f1606cc70 100644 --- a/alib2std/src/alib/optional +++ b/alib2std/src/alib/optional @@ -1 +1,2 @@ #include <extensions/container/optional.hpp> +#include <extensions/container/optional_ref.hpp> diff --git a/alib2std/src/extensions/container/optional.hpp b/alib2std/src/extensions/container/optional.hpp index aafc2beda6..d9b09b69c1 100644 --- a/alib2std/src/extensions/container/optional.hpp +++ b/alib2std/src/extensions/container/optional.hpp @@ -27,6 +27,7 @@ #define __OPTIONAL_HPP_ #include <optional> +#include <sstream> #include <extensions/compare.hpp> diff --git a/alib2std/src/extensions/container/optional_ref.hpp b/alib2std/src/extensions/container/optional_ref.hpp new file mode 100644 index 0000000000..11afe17a68 --- /dev/null +++ b/alib2std/src/extensions/container/optional_ref.hpp @@ -0,0 +1,278 @@ +/* + * optional.hpp + * + * This file is part of Algorithms library toolkit. + * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz) + + * Algorithms library toolkit is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * Algorithms library toolkit is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with Algorithms library toolkit. If not, see <http://www.gnu.org/licenses/>. + * + * Created on: Apr 7, 2016 + * Author: Jan Travnicek + */ + +#ifndef __OPTIONAL_REF_HPP_ +#define __OPTIONAL_REF_HPP_ + +#include <optional> +#include <memory> + +namespace ext { + +template < class T > +class optional_ref { + T * m_value; + +public: + optional_ref ( ) : optional_ref ( std::nullopt ) { } + optional_ref ( std::nullopt_t ) : m_value ( nullptr ) { } + + optional_ref ( T & val ) : m_value ( std::addressof ( val ) ) { + } + + template < class U > + optional_ref ( const optional < U > & other ) : optional_ref ( other.value ( ) ) { + } + + template < class U > + optional_ref ( optional < U > && other ) : optional_ref ( std::move ( other ).value ( ) ) { + } + + optional_ref & operator = ( const optional_ref & ) = delete; + optional_ref & operator = ( optional_ref && ) = delete; + + optional_ref ( const optional_ref & other ) = default; + optional_ref ( optional_ref && other ) noexcept = default; + + ~ optional_ref ( ) noexcept = default; + + const T * operator-> ( ) const { + return m_value; + } + + T * operator-> ( ) { + return m_value; + } + + const T & operator * ( ) const & { + return value ( ); + } + + T & operator * ( ) & { + return value ( ); + } + + const T && operator * ( ) const && { + return std::move ( value ( ) ); + } + + T && operator * ( ) && { + return std::move ( value ( ) ); + } + + explicit operator bool ( ) const noexcept { + return has_value ( ); + } + + bool has_value ( ) const noexcept { + return m_value != nullptr; + } + + T & value ( ) & { + return * m_value; + } + + const T & value ( ) const & { + return * m_value; + } + + T && value ( ) && { + return std::move ( * m_value ); + } + + const T && value ( ) const && { + return std::move ( * m_value ); + } + + const T & value_or ( const T & default_value ) const & { + if ( has_value ( ) ) + return value ( ); + else + return default_value; + } + + T & value_or ( T & default_value ) & { + if ( has_value ( ) ) + return value ( ); + else + return default_value; + } + + T && value_or ( T && default_value ) && { + if ( has_value ( ) ) + return std::move ( value ( ) ); + else + return default_value; + } + + /** + * \brief + * Compares two optional_ref instances for equvalence. + * + * \param lhs the first instance to compare + * \param rhs the second instance to compare + * + * \return true if the two compared instance are equal, false othervise + */ + friend bool operator== ( const optional_ref < T >& lhs, const optional_ref < T >& rhs ) { + return lhs.value ( ) == rhs.value ( ); + } + + /** + * \brief + * Compares two optional_ref instances for non equvalence. + * + * \param lhs the first instance to compare + * \param rhs the second instance to compare + * + * \return true if the two compared instance are not equal, false othervise + */ + friend bool operator!= ( const optional_ref < T >& lhs, const optional_ref < T >& rhs ) { + return lhs.value ( ) != rhs.value ( ); + } + + /** + * \brief + * Compares two optional_ref instances by less relation. + * + * \param lhs the first instance to compare + * \param rhs the second instance to compare + * + * \return true if the first compared instance is less than the other instance, false othervise + */ + friend bool operator< ( const optional_ref < T >& lhs, const optional_ref < T >& rhs ) { + return lhs.value ( ) < rhs.value ( ); + } + + /** + * \brief + * Compares two optional_ref instances by less or equal relation. + * + * \param lhs the first instance to compare + * \param rhs the second instance to compare + * + * \return true if the first compared instance is less than or equal than the other instance, false othervise + */ + friend bool operator<= ( const optional_ref < T >& lhs, const optional_ref < T >& rhs ) { + return lhs.value ( ) <= rhs.value ( ); + } + + /** + * \brief + * Compares two optional_ref instances by greater relation. + * + * \param lhs the first instance to compare + * \param rhs the second instance to compare + * + * \return true if the first compared instance is greater than the other instance, false othervise + */ + friend bool operator> ( const optional_ref < T >& lhs, const optional_ref < T >& rhs ) { + return lhs.value ( ) > rhs.value ( ); + } + + /** + * \brief + * Compares two optional_ref instances by greater or equal relation. + * + * \param lhs the first instance to compare + * \param rhs the second instance to compare + * + * \return true if the first compared instance is greater than or equal than the other instance, false othervise + */ + friend bool operator>= ( const optional_ref < T >& lhs, const optional_ref < T >& rhs ) { + return lhs.value ( ) >= rhs.value ( ); + } + +}; + +/** + * \brief + * Specialisation of the compare structure implementing the three-way comparison. + * + * \tparam T type in the optional + */ +template < typename T > +struct compare < ext::optional_ref < T > > { + + /** + * \brief + * Implementation of the three-way comparison. + * + * \param first the left operand of the comparison + * \param second the right operand of the comparison + * + * \return negative value of left < right, positive value if left > right, zero if left == right + */ + int operator ( ) ( const ext::optional_ref < T > & first, const ext::optional_ref < T > & second ) const { + if ( ! first && ! second ) + return 0; + if ( first && ! second ) + return 1; + if ( ! first && second ) + return -1; + + static ext::compare < T > comp; + return comp ( first.value ( ), second.value ( ) ); + } +}; + +/** + * \brief + * Operator to print the optional to the output stream. + * + * \param out the output stream + * \param optional the optional to print + * + * \tparam T the type of value inside the optional + * + * \return the output stream from the \p out + */ +template< class T > +std::ostream & operator << ( std::ostream & out, const ext::optional_ref < T > & optional ) { + if ( ! optional ) + return out << "void"; + else + return out << optional.value ( ); +} + + +/** + * \brief + * Overload of to_string function. + * + * \param value the optional to be converted to string + * + * \tparam T the type of values inside the optional + * + * \return string representation + */ +template < class T > +std::string to_string ( const ext::optional_ref < T > & value ) { + std::stringstream ss; + ss << value; + return ss.str(); +} + +} /* namespace ext */ + +#endif /* __OPTIONAL_REF_HPP_ */ diff --git a/alib2std/test-src/extensions/container/OptionalTest.cpp b/alib2std/test-src/extensions/container/OptionalTest.cpp new file mode 100644 index 0000000000..0b40754a63 --- /dev/null +++ b/alib2std/test-src/extensions/container/OptionalTest.cpp @@ -0,0 +1,19 @@ +#include <catch2/catch.hpp> +#include <alib/optional> +#include <sstream> + +TEST_CASE ( "Optional", "[unit][std][container]" ) { + SECTION ( "Ref test" ) { + int a = 5; + + ext::optional_ref < int > empty; + ext::optional_ref < int > a_ref ( a ); + CHECK ( a_ref.value ( ) == a ); + a_ref.value ( ) = 10; + CHECK ( a == 10 ); + + ext::optional_ref < int > a_ref2 ( a_ref ); + CHECK ( a_ref2 == a_ref ); + } +} + -- GitLab