Program Listing for File ScopedState.h

Return to documentation for file (src/ompl/base/ScopedState.h)

/*********************************************************************
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2010, Rice University
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the Rice University nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *********************************************************************/

/* Author: Ioan Sucan */

#ifndef OMPL_BASE_SCOPED_STATE_
#define OMPL_BASE_SCOPED_STATE_

#include "ompl/base/SpaceInformation.h"
#include <boost/concept_check.hpp>
#include <iostream>
#include <utility>

namespace ompl
{
    namespace base
    {
        template <class T = StateSpace>
        class ScopedState
        {
            BOOST_CONCEPT_ASSERT((boost::Convertible<T *, StateSpace *>));

            BOOST_CONCEPT_ASSERT((boost::Convertible<typename T::StateType *, State *>));

        public:
            using StateType = typename T::StateType;

            explicit ScopedState(const SpaceInformationPtr &si) : space_(si->getStateSpace())
            {
                State *s = space_->allocState();

                // ideally, this should be a dynamic_cast and we
                // should throw an exception in case of
                // failure. However, RTTI may not be available across
                // shared library boundaries, so we do not use it
                state_ = static_cast<StateType *>(s);
            }

            explicit ScopedState(StateSpacePtr space) : space_(std::move(space))
            {
                State *s = space_->allocState();

                // ideally, this should be a dynamic_cast and we
                // should throw an exception in case of
                // failure. However, RTTI may not be available across
                // shared library boundaries, so we do not use it
                state_ = static_cast<StateType *>(s);
            }

            ScopedState(const ScopedState<T> &other) : space_(other.getSpace())
            {
                State *s = space_->allocState();
                state_ = static_cast<StateType *>(s);
                space_->copyState(s, static_cast<const State *>(other.get()));
            }

            template <class O>
            ScopedState(const ScopedState<O> &other) : space_(other.getSpace())
            {
                BOOST_CONCEPT_ASSERT((boost::Convertible<O *, StateSpace *>));
                BOOST_CONCEPT_ASSERT((boost::Convertible<typename O::StateType *, State *>));

                // ideally, we should use a dynamic_cast and throw an
                // exception in case other.get() does not cast to
                // const StateType*. However, RTTI may not be
                // available across shared library boundaries, so we
                // do not use it

                State *s = space_->allocState();
                state_ = static_cast<StateType *>(s);
                space_->copyState(s, static_cast<const State *>(other.get()));
            }

            ScopedState(StateSpacePtr space, const State *state) : space_(std::move(space))
            {
                State *s = space_->allocState();
                space_->copyState(s, state);

                // ideally, this should be a dynamic_cast and we
                // should throw an exception in case of
                // failure. However, RTTI may not be available across
                // shared library boundaries, so we do not use it
                state_ = static_cast<StateType *>(s);
            }

            ~ScopedState()
            {
                space_->freeState(state_);
            }

            const StateSpacePtr &getSpace() const
            {
                return space_;
            }

            ScopedState<T> &operator=(const ScopedState<T> &other)
            {
                if (&other != this)
                {
                    space_->freeState(state_);
                    space_ = other.getSpace();

                    State *s = space_->allocState();
                    state_ = static_cast<StateType *>(s);
                    space_->copyState(s, static_cast<const State *>(other.get()));
                }
                return *this;
            }

            ScopedState<T> &operator=(const State *other)
            {
                if (other != static_cast<State *>(state_))
                {
                    // ideally, we should use a dynamic_cast and throw an
                    // exception in case other does not cast to
                    // const StateType*. However, RTTI may not be
                    // available across shared library boundaries, so we
                    // do not use it

                    space_->copyState(static_cast<State *>(state_), other);
                }
                return *this;
            }

            ScopedState<T> &operator=(const State &other)
            {
                if (&other != static_cast<State *>(state_))
                {
                    // ideally, we should use a dynamic_cast and throw an
                    // exception in case &other does not cast to
                    // const StateType*. However, RTTI may not be
                    // available across shared library boundaries, so we
                    // do not use it

                    space_->copyState(static_cast<State *>(state_), &other);
                }
                return *this;
            }

            template <class O>
            ScopedState<T> &operator=(const ScopedState<O> &other)
            {
                BOOST_CONCEPT_ASSERT((boost::Convertible<O *, StateSpace *>));
                BOOST_CONCEPT_ASSERT((boost::Convertible<typename O::StateType *, State *>));

                // ideally, we should use a dynamic_cast and throw an
                // exception in case other.get() does not cast to
                // const StateType*. However, RTTI may not be
                // available across shared library boundaries, so we
                // do not use it

                if (reinterpret_cast<const void *>(&other) != reinterpret_cast<const void *>(this))
                {
                    space_->freeState(state_);
                    space_ = other.getSpace();

                    State *s = space_->allocState();
                    state_ = static_cast<StateType *>(s);
                    space_->copyState(s, static_cast<const State *>(other.get()));
                }
                return *this;
            }

            ScopedState<T> &operator=(const std::vector<double> &reals)
            {
                for (unsigned int i = 0; i < reals.size(); ++i)
                    if (double *va = space_->getValueAddressAtIndex(state_, i))
                        *va = reals[i];
                    else
                        break;
                return *this;
            }

            ScopedState<T> &operator=(const double value)
            {
                unsigned int index = 0;
                while (double *va = space_->getValueAddressAtIndex(state_, index++))
                    *va = value;
                return *this;
            }

            template <class O>
            bool operator==(const ScopedState<O> &other) const
            {
                BOOST_CONCEPT_ASSERT((boost::Convertible<O *, StateSpace *>));
                BOOST_CONCEPT_ASSERT((boost::Convertible<typename O::StateType *, State *>));

                // ideally, we should use a dynamic_cast and throw an
                // exception in case other.get() does not cast to
                // const StateType*. However, RTTI may not be
                // available across shared library boundaries, so we
                // do not use it

                return space_->equalStates(static_cast<const State *>(state_), static_cast<const State *>(other.get()));
            }

            template <class O>
            bool operator!=(const ScopedState<O> &other) const
            {
                return !(*this == other);
            }

            const ScopedState<> operator[](const StateSpacePtr &s) const;

            double &operator[](const unsigned int index)
            {
                double *val = space_->getValueAddressAtIndex(state_, index);
                if (val == nullptr)
                    throw Exception("Index out of bounds");
                return *val;
            }

            double operator[](const unsigned int index) const
            {
                const double *val = space_->getValueAddressAtIndex(state_, index);
                if (val == nullptr)
                    throw Exception("Index out of bounds");
                return *val;
            }

            double &operator[](const std::string &name)
            {
                const std::map<std::string, StateSpace::ValueLocation> &vm = space_->getValueLocationsByName();
                auto it = vm.find(name);
                if (it != vm.end())
                {
                    double *val = space_->getValueAddressAtLocation(state_, it->second);
                    if (val != nullptr)
                        return *val;
                }
                throw Exception("Name '" + name + "' not known");
            }

            double operator[](const std::string &name) const
            {
                const std::map<std::string, StateSpace::ValueLocation> &vm = space_->getValueLocationsByName();
                auto it = vm.find(name);
                if (it != vm.end())
                {
                    const double *val = space_->getValueAddressAtLocation(state_, it->second);
                    if (val != nullptr)
                        return *val;
                }
                throw Exception("Name '" + name + "' not known");
            }

            template <class O>
            double distance(const ScopedState<O> &other) const
            {
                BOOST_CONCEPT_ASSERT((boost::Convertible<O *, StateSpace *>));
                BOOST_CONCEPT_ASSERT((boost::Convertible<typename O::StateType *, State *>));
                return distance(other.get());
            }

            double distance(const State *state) const
            {
                return space_->distance(static_cast<const State *>(state_), state);
            }

            void random()
            {
                if (!sampler_)
                    sampler_ = space_->allocStateSampler();
                sampler_->sampleUniform(state_);
            }

            void enforceBounds()
            {
                space_->enforceBounds(state_);
            }

            bool satisfiesBounds() const
            {
                return space_->satisfiesBounds(state_);
            }

            std::vector<double> reals() const
            {
                std::vector<double> r;
                unsigned int index = 0;
                while (double *va = space_->getValueAddressAtIndex(state_, index++))
                    r.push_back(*va);
                return r;
            }

            void print(std::ostream &out = std::cout) const
            {
                space_->printState(state_, out);
            }

            StateType &operator*()
            {
                return *state_;
            }

            const StateType &operator*() const
            {
                return *state_;
            }

            StateType *operator->()
            {
                return state_;
            }

            const StateType *operator->() const
            {
                return state_;
            }

            StateType *get()
            {
                return state_;
            }

            const StateType *get() const
            {
                return state_;
            }

            StateType *operator()() const
            {
                return state_;
            }

        private:
            StateSpacePtr space_;
            StateSamplerPtr sampler_;
            StateType *state_;
        };

        template <class T>
        inline std::ostream &operator<<(std::ostream &out, const ScopedState<T> &state)
        {
            state.print(out);
            return out;
        }

        template <class T, class Y>
        inline ScopedState<T> &operator<<(ScopedState<T> &to, const ScopedState<Y> &from)
        {
            copyStateData(to.getSpace(), to.get(), from.getSpace(), from.get());
            return to;
        }

        template <class T, class Y>
        inline const ScopedState<T> &operator>>(const ScopedState<T> &from, ScopedState<Y> &to)
        {
            copyStateData(to.getSpace(), to.get(), from.getSpace(), from.get());
            return from;
        }

        template <class T, class Y>
        inline const ScopedState<> operator^(const ScopedState<T> &a, const ScopedState<Y> &b)
        {
            ScopedState<> r(a.getSpace() + b.getSpace());
            return r << a << b;
        }

        template <class T>
        const ScopedState<> ScopedState<T>::operator[](const StateSpacePtr &s) const
        {
            ScopedState<> r(s);
            return r << *this;
        }

        using ScopedStatePtr = std::shared_ptr<ScopedState<>>;
    }  // namespace base
}  // namespace ompl

#endif