<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2014.  All rights reserved
 */
#ifndef _Stroika_Foundation_Traversal_DisjointRange_inl_
#define _Stroika_Foundation_Traversal_DisjointRange_inl_

namespace   Stroika {
    namespace   Foundation {
        namespace   Traversal {

            /*
            ********************************************************************************
            ************************* DisjointRange<RANGE_TYPE> ****************************
            ********************************************************************************
            */
            template    <typename RANGE_TYPE>
            DisjointRange<RANGE_TYPE>::DisjointRange (const RangeType& from)
                : fSubRanges_ {} {
                MergeIn_ (from);
            }
            template    <typename RANGE_TYPE>
            inline  DisjointRange<RANGE_TYPE>::DisjointRange (const initializer_list<RangeType>& from)
                : DisjointRange { begin (from), end (from) } {
            }
            template    <typename RANGE_TYPE>
            template    <typename CONTAINER_OF_RANGE_OF_T>
            inline  DisjointRange<RANGE_TYPE>::DisjointRange (const CONTAINER_OF_RANGE_OF_T& from)
                : DisjointRange { begin (from), end (from) } {
            }
            template    <typename RANGE_TYPE>
            template    <typename COPY_FROM_ITERATOR_OF_RANGE_OF_T>
            DisjointRange<RANGE_TYPE>::DisjointRange (COPY_FROM_ITERATOR_OF_RANGE_OF_T start, COPY_FROM_ITERATOR_OF_RANGE_OF_T end)
                : fSubRanges_ {} {
                for (auto i = start; i != end; ++i)
                {
                    MergeIn_ (*i);
                }
            }
            template    <typename RANGE_TYPE>
            inline  auto    DisjointRange<RANGE_TYPE>::GetSubRanges () const -> Containers::Sequence<RangeType> {
                return fSubRanges_;
            }
            template    <typename RANGE_TYPE>
            DisjointRange<RANGE_TYPE> DisjointRange<RANGE_TYPE>::FullRange ()
            {
                return DisjointRange<RangeType> { RangeType::FullRange () };
            }
            template    <typename RANGE_TYPE>
            inline  bool    DisjointRange<RANGE_TYPE>::empty () const
            {
                return fSubRanges_.empty ();
            }
            template    <typename RANGE_TYPE>
            bool    DisjointRange<RANGE_TYPE>::Contains (ElementType elt) const
            {
                return fSubRanges_.FindFirstThat ([elt] (RangeType r) { return r.Contains (elt); });
            }
            template    <typename RANGE_TYPE>
            RANGE_TYPE   DisjointRange<RANGE_TYPE>::GetBounds () const
            {
                size_t  n   =   fSubRanges_.size ();
                switch (n) {
                    case 0:
                        return RangeType {};
                    case 1:
                        return fSubRanges_[0];
                    default:
                        return RangeType (fSubRanges_[0].GetLowerBound (), fSubRanges_.GetLast ().GetUpperBound ());
                }
            }
            template    <typename RANGE_TYPE>
            template    <typename RANGE_TYPE2>
            bool    DisjointRange<RANGE_TYPE>::Equals (const DisjointRange<RANGE_TYPE2>& rhs) const
            {
                Containers::Sequence<RangeType>                                         lhsR = GetSubRanges ();
                Containers::Sequence<typename DisjointRange<RANGE_TYPE2>::RangeType>    rhsR = rhs.GetSubRanges ();
                if (lhs.size () != rhs.size ()) {
                    return false;
                }
                auto i = lhsR.begin ();
                auto ri = rhsR.begin ();
                while (i != lhsR.end ()) {
                    if (*i != *ri) {
                        return false;
                    }
                    ++i;
                    ++ri;
                }
                return true;
            }
            template    <typename RANGE_TYPE>
            void    DisjointRange<RANGE_TYPE>::MergeIn_ (const RangeType& r)
            {
                AssertInternalRepValid_ ();
                if (not r.empty ()) {
                    ElementType         rStart  { r.GetLowerBound () };
                    ElementType         rEnd    { r.GetUpperBound () };
                    if (fSubRanges_.size () == 0) {
                        fSubRanges_.Append (r);
                    }
                    else {
                        /*
                         *         [XXXXXX]      [XXX]             [XXXXXXXXXXXX]
                         *  EX 1 ^                                    ^
                         *  BECOMES:
                         *       [XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX]
                         *
                         *         [XXXXXX]      [XXX]             [XXXXXXXXXXXX]
                         *  EX 2               ^                          ^
                         *  BECOMES:
                         *         [XXXXXX]    [XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX]
                         *
                         *  Find first range to the right of LEFT-ANCHOR, and adjusting it to the LEFT based on rStart,
                         *  and stretch it to the left (if needed).
                         *
                         *  Then grab the last block on the right (starting before rEnd) of the defined range,
                         *  and stetch its right side to the right. Then delete all those in between.
                         */
                        Assert (fSubRanges_.size () >= 1);

                        // tmphack - need random-access iterators !!! for sequence at least!
                        auto prevOfIterator = [this] (const Iterator<RangeType>& pOfI) -> Iterator<RangeType> {
                            Iterator<RangeType> result = Iterator<RangeType>::GetEmptyIterator ();
                            for (Iterator<RangeType> i = fSubRanges_.begin (); i != fSubRanges_.end (); ++i)
                            {
                                if (i == pOfI) {
                                    return result;
                                }
                                result = i;
                            }
                            return result;
                        };

                        Iterator<RangeType> startI   =   fSubRanges_.FindFirstThat ([rStart] (const RangeType & r) -> bool {return r.GetLowerBound () >= rStart or r.Contains (rStart); });
                        if (startI == fSubRanges_.end ()) {
                            DbgTrace ("Appending subrange cuz this is past the rest: %f/%f",
                                      static_cast<double> (r.GetLowerBound ()), static_cast<double> (r.GetUpperBound ())
                                     );
                            // cuz this means no ranges to the right containing rStart
                            //
                            // when appending, we can sometimes extend the last item
                            ElementType prevVal = RangeType::TraitsType::GetPrevious (rStart);
                            Iterator<RangeType> i = fSubRanges_.FindFirstThat ([prevVal] (const RangeType & r) -> bool {return r.GetUpperBound () == prevVal; });
                            if (i) {
                                Assert (i->GetUpperBound () == prevVal);
                                RangeType newValue { i->GetLowerBound (), rStart };
                                fSubRanges_.Update (i, newValue);
                            }
                            else {
                                fSubRanges_.Append (r);
                            }
                        }
                        else if (r.Intersects (*startI)) {
                            RangeType newValue { min (rStart, startI->GetLowerBound ()), startI->GetUpperBound () };
                            DbgTrace ("Updating subrange element %d from %f/%f to %f/%f",
                                      fSubRanges_.IndexOf (startI),
                                      static_cast<double> (startI->GetLowerBound ()), static_cast<double> (startI->GetUpperBound ()),
                                      static_cast<double> (newValue.GetLowerBound ()), static_cast<double> (newValue.GetUpperBound ())
                                     );
                            if (*startI != newValue) {
                                fSubRanges_.Update (startI, newValue);
                            }
                        }
                        else {
                            DbgTrace ("Inserting subrange element %d from %f/%f to %f/%f",
                                      fSubRanges_.IndexOf (startI),
                                      static_cast<double> (startI->GetLowerBound ()), static_cast<double> (startI->GetUpperBound ()),
                                      static_cast<double> (r.GetLowerBound ()), static_cast<double> (r.GetUpperBound ())
                                     );
                            fSubRanges_.Insert (startI, r);
                        }

                        /*
                         *  Next adjust RHS of rhs-most element.
                         */
                        Iterator<RangeType> endI = prevOfIterator (fSubRanges_.FindFirstThat (startI, [rEnd] (const RangeType & r) -> bool {return rEnd < r.GetLowerBound ();}));
                        if (endI == fSubRanges_.end ()) {
                            endI = prevOfIterator (fSubRanges_.end ());
                        }
                        Assert (endI != fSubRanges_.end ());
                        if (endI->GetLowerBound () <= rEnd) {
                            RangeType newValue { endI->GetLowerBound (), max (rEnd, endI->GetUpperBound ()) };
                            DbgTrace ("Updating RHS of subrange element %d from %f/%f to %f/%f",
                                      fSubRanges_.IndexOf (endI),
                                      static_cast<double> (endI->GetLowerBound ()), static_cast<double> (endI->GetUpperBound ()),
                                      static_cast<double> (newValue.GetLowerBound ()), static_cast<double> (newValue.GetUpperBound ())
                                     );
                            fSubRanges_.Update (endI, newValue);
                        }
                        else {
                            DbgTrace ("Appending RHS subrange element %f/%f",
                                      static_cast<double> (r.GetLowerBound ()), static_cast<double> (r.GetUpperBound ())
                                     );
                            fSubRanges_.Append (r);
                        }

                        // then merge out uneeded items in between
                        // @todo/CLEANUP/REVIEW - not sure we always have startI <= endI...
                        if (startI != fSubRanges_.end ()) {
                            for (auto i = startI; i != endI and i != fSubRanges_.end (); ++i) {
                                if (i != startI and i != endI) {
                                    DbgTrace ("Removing redundant subrange element %d from %f/%f to %f/%f",
                                              fSubRanges_.IndexOf (i),
                                              static_cast<double> (i->GetLowerBound ()), static_cast<double> (i->GetUpperBound ())
                                             );
                                    fSubRanges_.Remove (i);
                                }
                            }
                        }
                    }
                }
                AssertInternalRepValid_ ();
                //Ensure (Contains (r); NYI so do below tmphack alternative
                Ensure (r.GetLowerBoundOpenness () == Openness::eOpen or Contains (r.GetLowerBound ()));
                Ensure (r.GetUpperBoundOpenness () == Openness::eOpen or Contains (r.GetUpperBound ()));
                Ensure (GetBounds ().Contains (r));
            }
            template    <typename RANGE_TYPE>
            inline  void    DisjointRange<RANGE_TYPE>::AssertInternalRepValid_ ()
            {
#if     qDebug
                Memory::Optional<RangeType> lastRangeSeenSoFar;
                for (RangeType r : fSubRanges_) {
                    Assert (not r.empty ());
                    if (lastRangeSeenSoFar) {
                        Assert (lastRangeSeenSoFar->GetUpperBound () <= r.GetLowerBound ());    // equal maybe bad but check that case with itersects which pays attention to openness
                        Assert (not lastRangeSeenSoFar->Intersects (r));
                        // and make sure we merge together adjacent points
                        ElementType nextVal = RangeType::TraitsType::GetNext (lastRangeSeenSoFar->GetUpperBound ());
                        Assert (nextVal < r.GetLowerBound ());  // if nextval of previous item == lowerBound of successive one, we could have merged them into a contiguous run
                    }
                    lastRangeSeenSoFar = r;
                }
#endif
            }

            /*
             ********************************************************************************
             *********************************** operator+ **********************************
             ********************************************************************************
             */
            template    <typename RANGE_TYPE>
            inline  DisjointRange<RANGE_TYPE>   operator+ (const DisjointRange<RANGE_TYPE>& lhs, const DisjointRange<RANGE_TYPE>& rhs)
            {
                return lhs.Union (rhs);
            }

            /*
             ********************************************************************************
             *********************************** operator^ **********************************
             ********************************************************************************
             */
            template    <typename RANGE_TYPE>
            inline  DisjointRange<RANGE_TYPE>   operator^ (const DisjointRange<RANGE_TYPE>& lhs, const DisjointRange<RANGE_TYPE>& rhs)
            {
                return lhs.Intersection (rhs);
            }

            /*
             ********************************************************************************
             ********************************** operator== **********************************
             ********************************************************************************
             */
            template    <typename RANGE_TYPE>
            inline  DisjointRange<RANGE_TYPE>   operator== (const DisjointRange<RANGE_TYPE>& lhs, const DisjointRange<RANGE_TYPE>& rhs)
            {
                return lhs.Equals (rhs);
            }

            /*
             ********************************************************************************
             ********************************** operator!= **********************************
             ********************************************************************************
             */
            template    <typename RANGE_TYPE>
            inline  DisjointRange<RANGE_TYPE>   operator!= (const DisjointRange<RANGE_TYPE>& lhs, const DisjointRange<RANGE_TYPE>& rhs)
            {
                return not lhs.Equals (rhs);
            }

        }
    }
}
#endif /* _Stroika_Foundation_Traversal_DisjointRange_inl_ */
<commit_msg>more regtests on DisjointRange, and more operators and implmentation of peices<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2014.  All rights reserved
 */
#ifndef _Stroika_Foundation_Traversal_DisjointRange_inl_
#define _Stroika_Foundation_Traversal_DisjointRange_inl_

namespace   Stroika {
    namespace   Foundation {
        namespace   Traversal {

            /*
            ********************************************************************************
            ************************* DisjointRange<RANGE_TYPE> ****************************
            ********************************************************************************
            */
            template    <typename RANGE_TYPE>
            DisjointRange<RANGE_TYPE>::DisjointRange (const RangeType& from)
                : fSubRanges_ {} {
                MergeIn_ (from);
            }
            template    <typename RANGE_TYPE>
            inline  DisjointRange<RANGE_TYPE>::DisjointRange (const initializer_list<RangeType>& from)
                : DisjointRange { begin (from), end (from) } {
            }
            template    <typename RANGE_TYPE>
            template    <typename CONTAINER_OF_RANGE_OF_T>
            inline  DisjointRange<RANGE_TYPE>::DisjointRange (const CONTAINER_OF_RANGE_OF_T& from)
                : DisjointRange { begin (from), end (from) } {
            }
            template    <typename RANGE_TYPE>
            template    <typename COPY_FROM_ITERATOR_OF_RANGE_OF_T>
            DisjointRange<RANGE_TYPE>::DisjointRange (COPY_FROM_ITERATOR_OF_RANGE_OF_T start, COPY_FROM_ITERATOR_OF_RANGE_OF_T end)
                : fSubRanges_ {} {
                for (auto i = start; i != end; ++i)
                {
                    MergeIn_ (*i);
                }
            }
            template    <typename RANGE_TYPE>
            inline  auto    DisjointRange<RANGE_TYPE>::GetSubRanges () const -> Containers::Sequence<RangeType> {
                return fSubRanges_;
            }
            template    <typename RANGE_TYPE>
            DisjointRange<RANGE_TYPE> DisjointRange<RANGE_TYPE>::FullRange ()
            {
                return DisjointRange<RangeType> { RangeType::FullRange () };
            }
            template    <typename RANGE_TYPE>
            inline  bool    DisjointRange<RANGE_TYPE>::empty () const
            {
                return fSubRanges_.empty ();
            }
            template    <typename RANGE_TYPE>
            bool    DisjointRange<RANGE_TYPE>::Contains (ElementType elt) const
            {
                return fSubRanges_.FindFirstThat ([elt] (RangeType r) { return r.Contains (elt); });
            }
            template    <typename RANGE_TYPE>
            RANGE_TYPE   DisjointRange<RANGE_TYPE>::GetBounds () const
            {
                size_t  n   =   fSubRanges_.size ();
                switch (n) {
                    case 0:
                        return RangeType {};
                    case 1:
                        return fSubRanges_[0];
                    default:
                        return RangeType (fSubRanges_[0].GetLowerBound (), fSubRanges_.GetLast ().GetUpperBound ());
                }
            }
            template    <typename RANGE_TYPE>
            template    <typename RANGE_TYPE2>
            bool    DisjointRange<RANGE_TYPE>::Equals (const DisjointRange<RANGE_TYPE2>& rhs) const
            {
                Containers::Sequence<RangeType>                                         lhsR = GetSubRanges ();
                Containers::Sequence<typename DisjointRange<RANGE_TYPE2>::RangeType>    rhsR = rhs.GetSubRanges ();
                if (lhsR.size () != rhsR.size ()) {
                    return false;
                }
                auto i = lhsR.begin ();
                auto ri = rhsR.begin ();
                while (i != lhsR.end ()) {
                    if (*i != *ri) {
                        return false;
                    }
                    ++i;
                    ++ri;
                }
                return true;
            }
            template    <typename RANGE_TYPE>
            void    DisjointRange<RANGE_TYPE>::MergeIn_ (const RangeType& r)
            {
                AssertInternalRepValid_ ();
                if (not r.empty ()) {
                    ElementType         rStart  { r.GetLowerBound () };
                    ElementType         rEnd    { r.GetUpperBound () };
                    if (fSubRanges_.size () == 0) {
                        fSubRanges_.Append (r);
                    }
                    else {
                        /*
                         *         [XXXXXX]      [XXX]             [XXXXXXXXXXXX]
                         *  EX 1 ^                                    ^
                         *  BECOMES:
                         *       [XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX]
                         *
                         *         [XXXXXX]      [XXX]             [XXXXXXXXXXXX]
                         *  EX 2               ^                          ^
                         *  BECOMES:
                         *         [XXXXXX]    [XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX]
                         *
                         *  Find first range to the right of LEFT-ANCHOR, and adjusting it to the LEFT based on rStart,
                         *  and stretch it to the left (if needed).
                         *
                         *  Then grab the last block on the right (starting before rEnd) of the defined range,
                         *  and stetch its right side to the right. Then delete all those in between.
                         */
                        Assert (fSubRanges_.size () >= 1);

                        // tmphack - need random-access iterators !!! for sequence at least!
                        auto prevOfIterator = [this] (const Iterator<RangeType>& pOfI) -> Iterator<RangeType> {
                            Iterator<RangeType> result = Iterator<RangeType>::GetEmptyIterator ();
                            for (Iterator<RangeType> i = fSubRanges_.begin (); i != fSubRanges_.end (); ++i)
                            {
                                if (i == pOfI) {
                                    return result;
                                }
                                result = i;
                            }
                            return result;
                        };

                        Iterator<RangeType> startI   =   fSubRanges_.FindFirstThat ([rStart] (const RangeType & r) -> bool {return r.GetLowerBound () >= rStart or r.Contains (rStart); });
                        if (startI == fSubRanges_.end ()) {
                            DbgTrace ("Appending subrange cuz this is past the rest: %f/%f",
                                      static_cast<double> (r.GetLowerBound ()), static_cast<double> (r.GetUpperBound ())
                                     );
                            // cuz this means no ranges to the right containing rStart
                            //
                            // when appending, we can sometimes extend the last item
                            ElementType prevVal = RangeType::TraitsType::GetPrevious (rStart);
                            Iterator<RangeType> i = fSubRanges_.FindFirstThat ([prevVal] (const RangeType & r) -> bool {return r.GetUpperBound () == prevVal; });
                            if (i) {
                                Assert (i->GetUpperBound () == prevVal);
                                RangeType newValue { i->GetLowerBound (), rStart };
                                fSubRanges_.Update (i, newValue);
                            }
                            else {
                                fSubRanges_.Append (r);
                            }
                        }
                        else if (r.Intersects (*startI)) {
                            RangeType newValue { min (rStart, startI->GetLowerBound ()), startI->GetUpperBound () };
                            DbgTrace ("Updating subrange element %d from %f/%f to %f/%f",
                                      fSubRanges_.IndexOf (startI),
                                      static_cast<double> (startI->GetLowerBound ()), static_cast<double> (startI->GetUpperBound ()),
                                      static_cast<double> (newValue.GetLowerBound ()), static_cast<double> (newValue.GetUpperBound ())
                                     );
                            if (*startI != newValue) {
                                fSubRanges_.Update (startI, newValue);
                            }
                        }
                        else {
                            DbgTrace ("Inserting subrange element %d from %f/%f to %f/%f",
                                      fSubRanges_.IndexOf (startI),
                                      static_cast<double> (startI->GetLowerBound ()), static_cast<double> (startI->GetUpperBound ()),
                                      static_cast<double> (r.GetLowerBound ()), static_cast<double> (r.GetUpperBound ())
                                     );
                            fSubRanges_.Insert (startI, r);
                        }

                        /*
                         *  Next adjust RHS of rhs-most element.
                         */
                        Iterator<RangeType> endI = prevOfIterator (fSubRanges_.FindFirstThat (startI, [rEnd] (const RangeType & r) -> bool {return rEnd < r.GetLowerBound ();}));
                        if (endI == fSubRanges_.end ()) {
                            endI = prevOfIterator (fSubRanges_.end ());
                        }
                        Assert (endI != fSubRanges_.end ());
                        if (endI->GetLowerBound () <= rEnd) {
                            RangeType newValue { endI->GetLowerBound (), max (rEnd, endI->GetUpperBound ()) };
                            DbgTrace ("Updating RHS of subrange element %d from %f/%f to %f/%f",
                                      fSubRanges_.IndexOf (endI),
                                      static_cast<double> (endI->GetLowerBound ()), static_cast<double> (endI->GetUpperBound ()),
                                      static_cast<double> (newValue.GetLowerBound ()), static_cast<double> (newValue.GetUpperBound ())
                                     );
                            fSubRanges_.Update (endI, newValue);
                        }
                        else {
                            DbgTrace ("Appending RHS subrange element %f/%f",
                                      static_cast<double> (r.GetLowerBound ()), static_cast<double> (r.GetUpperBound ())
                                     );
                            fSubRanges_.Append (r);
                        }

                        // then merge out uneeded items in between
                        // @todo/CLEANUP/REVIEW - not sure we always have startI <= endI...
                        if (startI != fSubRanges_.end ()) {
                            for (auto i = startI; i != endI and i != fSubRanges_.end (); ++i) {
                                if (i != startI and i != endI) {
                                    DbgTrace ("Removing redundant subrange element %d from %f/%f to %f/%f",
                                              fSubRanges_.IndexOf (i),
                                              static_cast<double> (i->GetLowerBound ()), static_cast<double> (i->GetUpperBound ())
                                             );
                                    fSubRanges_.Remove (i);
                                }
                            }
                        }
                    }
                }
                AssertInternalRepValid_ ();
                //Ensure (Contains (r); NYI so do below tmphack alternative
                Ensure (r.GetLowerBoundOpenness () == Openness::eOpen or Contains (r.GetLowerBound ()));
                Ensure (r.GetUpperBoundOpenness () == Openness::eOpen or Contains (r.GetUpperBound ()));
                Ensure (GetBounds ().Contains (r));
            }
            template    <typename RANGE_TYPE>
            inline  void    DisjointRange<RANGE_TYPE>::AssertInternalRepValid_ ()
            {
#if     qDebug
                Memory::Optional<RangeType> lastRangeSeenSoFar;
                for (RangeType r : fSubRanges_) {
                    Assert (not r.empty ());
                    if (lastRangeSeenSoFar) {
                        Assert (lastRangeSeenSoFar->GetUpperBound () <= r.GetLowerBound ());    // equal maybe bad but check that case with itersects which pays attention to openness
                        Assert (not lastRangeSeenSoFar->Intersects (r));
                        // and make sure we merge together adjacent points
                        ElementType nextVal = RangeType::TraitsType::GetNext (lastRangeSeenSoFar->GetUpperBound ());
                        Assert (nextVal < r.GetLowerBound ());  // if nextval of previous item == lowerBound of successive one, we could have merged them into a contiguous run
                    }
                    lastRangeSeenSoFar = r;
                }
#endif
            }

            /*
             ********************************************************************************
             *********************************** operator+ **********************************
             ********************************************************************************
             */
            template    <typename RANGE_TYPE>
            inline  DisjointRange<RANGE_TYPE>   operator+ (const DisjointRange<RANGE_TYPE>& lhs, const DisjointRange<RANGE_TYPE>& rhs)
            {
                return lhs.Union (rhs);
            }

            /*
             ********************************************************************************
             *********************************** operator^ **********************************
             ********************************************************************************
             */
            template    <typename RANGE_TYPE>
            inline  DisjointRange<RANGE_TYPE>   operator^ (const DisjointRange<RANGE_TYPE>& lhs, const DisjointRange<RANGE_TYPE>& rhs)
            {
                return lhs.Intersection (rhs);
            }

            /*
             ********************************************************************************
             ********************************** operator== **********************************
             ********************************************************************************
             */
            template    <typename RANGE_TYPE>
            inline  DisjointRange<RANGE_TYPE>   operator== (const DisjointRange<RANGE_TYPE>& lhs, const DisjointRange<RANGE_TYPE>& rhs)
            {
                return lhs.Equals (rhs);
            }

            /*
             ********************************************************************************
             ********************************** operator!= **********************************
             ********************************************************************************
             */
            template    <typename RANGE_TYPE>
            inline  DisjointRange<RANGE_TYPE>   operator!= (const DisjointRange<RANGE_TYPE>& lhs, const DisjointRange<RANGE_TYPE>& rhs)
            {
                return not lhs.Equals (rhs);
            }

        }
    }
}
#endif /* _Stroika_Foundation_Traversal_DisjointRange_inl_ */
<|endoftext|>


<commit_before>/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */

#include "ts/ink_platform.h"
#include "ts/ink_thread.h"
#include "ts/ink_memory.h"
#include "ts/Regex.h"

#ifdef PCRE_CONFIG_JIT
struct RegexThreadKey {
  RegexThreadKey() { ink_thread_key_create(&this->key, (void (*)(void *)) & pcre_jit_stack_free); }
  ink_thread_key key;
};

static RegexThreadKey k;

static pcre_jit_stack *
get_jit_stack(void *data ATS_UNUSED)
{
  pcre_jit_stack *jit_stack;

  if ((jit_stack = (pcre_jit_stack *)ink_thread_getspecific(k.key)) == nullptr) {
    jit_stack = pcre_jit_stack_alloc(ats_pagesize(), 1024 * 1024); // 1 page min and 1MB max
    ink_thread_setspecific(k.key, (void *)jit_stack);
  }

  return jit_stack;
}
#endif

bool
Regex::compile(const char *pattern, const unsigned flags)
{
  const char *error;
  int erroffset;
  int options    = 0;
  int study_opts = 0;

  if (regex) {
    return false;
  }

  if (flags & RE_CASE_INSENSITIVE) {
    options |= PCRE_CASELESS;
  }

  if (flags & RE_ANCHORED) {
    options |= PCRE_ANCHORED;
  }

  regex = pcre_compile(pattern, options, &error, &erroffset, nullptr);
  if (error) {
    regex = nullptr;
    return false;
  }

#ifdef PCRE_CONFIG_JIT
  study_opts |= PCRE_STUDY_JIT_COMPILE;
#endif

  regex_extra = pcre_study(regex, study_opts, &error);

#ifdef PCRE_CONFIG_JIT
  if (regex_extra) {
    pcre_assign_jit_stack(regex_extra, &get_jit_stack, nullptr);
  }
#endif

  return true;
}

int
Regex::get_capture_count()
{
  int captures = -1;
  if (pcre_fullinfo(regex, regex_extra, PCRE_INFO_CAPTURECOUNT, &captures) != 0) {
    return -1;
  }

  return captures;
}

bool
Regex::exec(const char *str)
{
  return exec(str, strlen(str));
}

bool
Regex::exec(const char *str, int length)
{
  int ovector[30];
  return exec(str, length, ovector, countof(ovector));
}

bool
Regex::exec(const char *str, int length, int *ovector, int ovecsize)
{
  int rv;

  rv = pcre_exec(regex, regex_extra, str, length, 0, 0, ovector, ovecsize);
  return rv > 0 ? true : false;
}

Regex::~Regex()
{
  if (regex_extra) {
#ifdef PCRE_CONFIG_JIT
    pcre_free_study(regex_extra);
  }
#else
    pcre_free(regex_extra);
#endif
  if (regex) {
    pcre_free(regex);
  }
}

DFA::~DFA()
{
  dfa_pattern *p = _my_patterns;
  dfa_pattern *t;

  while (p) {
    if (p->_re) {
      delete p->_re;
    }
    if (p->_p) {
      ats_free(p->_p);
    }
    t = p->_next;
    ats_free(p);
    p = t;
  }
}

dfa_pattern *
DFA::build(const char *pattern, unsigned flags)
{
  dfa_pattern *ret;
  int rv;

  if (!(flags & RE_UNANCHORED)) {
    flags |= RE_ANCHORED;
  }

  ret     = (dfa_pattern *)ats_malloc(sizeof(dfa_pattern));
  ret->_p = nullptr;

  ret->_re = new Regex();
  rv       = ret->_re->compile(pattern, flags);
  if (rv == -1) {
    delete ret->_re;
    ats_free(ret);
    return nullptr;
  }

  ret->_idx  = 0;
  ret->_p    = ats_strndup(pattern, strlen(pattern));
  ret->_next = nullptr;
  return ret;
}

int
DFA::compile(const char *pattern, unsigned flags)
{
  ink_assert(_my_patterns == nullptr);
  _my_patterns = build(pattern, flags);
  if (_my_patterns) {
    return 0;
  } else {
    return -1;
  }
}

int
DFA::compile(const char **patterns, int npatterns, unsigned flags)
{
  const char *pattern;
  dfa_pattern *ret = nullptr;
  dfa_pattern *end = nullptr;
  int i;

  for (i = 0; i < npatterns; i++) {
    pattern = patterns[i];
    ret     = build(pattern, flags);
    if (!ret) {
      continue;
    }

    if (!_my_patterns) {
      _my_patterns        = ret;
      _my_patterns->_next = nullptr;
      _my_patterns->_idx  = i;
    } else {
      end = _my_patterns;
      while (end->_next) {
        end = end->_next;
      }
      end->_next = ret; // add to end
      ret->_idx  = i;
    }
  }

  return 0;
}

int
DFA::match(const char *str) const
{
  return match(str, strlen(str));
}

int
DFA::match(const char *str, int length) const
{
  int rc;
  dfa_pattern *p = _my_patterns;

  while (p) {
    rc = p->_re->exec(str, length);
    if (rc > 0) {
      return p->_idx;
    }
    p = p->_next;
  }

  return -1;
}
<commit_msg>Clang-Tidy cleanup: Bad brace placement in ifdef'd code.<commit_after>/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */

#include "ts/ink_platform.h"
#include "ts/ink_thread.h"
#include "ts/ink_memory.h"
#include "ts/Regex.h"

#ifdef PCRE_CONFIG_JIT
struct RegexThreadKey {
  RegexThreadKey() { ink_thread_key_create(&this->key, (void (*)(void *)) & pcre_jit_stack_free); }
  ink_thread_key key;
};

static RegexThreadKey k;

static pcre_jit_stack *
get_jit_stack(void *data ATS_UNUSED)
{
  pcre_jit_stack *jit_stack;

  if ((jit_stack = (pcre_jit_stack *)ink_thread_getspecific(k.key)) == nullptr) {
    jit_stack = pcre_jit_stack_alloc(ats_pagesize(), 1024 * 1024); // 1 page min and 1MB max
    ink_thread_setspecific(k.key, (void *)jit_stack);
  }

  return jit_stack;
}
#endif

bool
Regex::compile(const char *pattern, const unsigned flags)
{
  const char *error;
  int erroffset;
  int options    = 0;
  int study_opts = 0;

  if (regex) {
    return false;
  }

  if (flags & RE_CASE_INSENSITIVE) {
    options |= PCRE_CASELESS;
  }

  if (flags & RE_ANCHORED) {
    options |= PCRE_ANCHORED;
  }

  regex = pcre_compile(pattern, options, &error, &erroffset, nullptr);
  if (error) {
    regex = nullptr;
    return false;
  }

#ifdef PCRE_CONFIG_JIT
  study_opts |= PCRE_STUDY_JIT_COMPILE;
#endif

  regex_extra = pcre_study(regex, study_opts, &error);

#ifdef PCRE_CONFIG_JIT
  if (regex_extra) {
    pcre_assign_jit_stack(regex_extra, &get_jit_stack, nullptr);
  }
#endif

  return true;
}

int
Regex::get_capture_count()
{
  int captures = -1;
  if (pcre_fullinfo(regex, regex_extra, PCRE_INFO_CAPTURECOUNT, &captures) != 0) {
    return -1;
  }

  return captures;
}

bool
Regex::exec(const char *str)
{
  return exec(str, strlen(str));
}

bool
Regex::exec(const char *str, int length)
{
  int ovector[30];
  return exec(str, length, ovector, countof(ovector));
}

bool
Regex::exec(const char *str, int length, int *ovector, int ovecsize)
{
  int rv;

  rv = pcre_exec(regex, regex_extra, str, length, 0, 0, ovector, ovecsize);
  return rv > 0 ? true : false;
}

Regex::~Regex()
{
  if (regex_extra) {
#ifdef PCRE_CONFIG_JIT
    pcre_free_study(regex_extra);
#else
    pcre_free(regex_extra);
#endif
  }
  if (regex) {
    pcre_free(regex);
  }
}

DFA::~DFA()
{
  dfa_pattern *p = _my_patterns;
  dfa_pattern *t;

  while (p) {
    if (p->_re) {
      delete p->_re;
    }
    if (p->_p) {
      ats_free(p->_p);
    }
    t = p->_next;
    ats_free(p);
    p = t;
  }
}

dfa_pattern *
DFA::build(const char *pattern, unsigned flags)
{
  dfa_pattern *ret;
  int rv;

  if (!(flags & RE_UNANCHORED)) {
    flags |= RE_ANCHORED;
  }

  ret     = (dfa_pattern *)ats_malloc(sizeof(dfa_pattern));
  ret->_p = nullptr;

  ret->_re = new Regex();
  rv       = ret->_re->compile(pattern, flags);
  if (rv == -1) {
    delete ret->_re;
    ats_free(ret);
    return nullptr;
  }

  ret->_idx  = 0;
  ret->_p    = ats_strndup(pattern, strlen(pattern));
  ret->_next = nullptr;
  return ret;
}

int
DFA::compile(const char *pattern, unsigned flags)
{
  ink_assert(_my_patterns == nullptr);
  _my_patterns = build(pattern, flags);
  if (_my_patterns) {
    return 0;
  } else {
    return -1;
  }
}

int
DFA::compile(const char **patterns, int npatterns, unsigned flags)
{
  const char *pattern;
  dfa_pattern *ret = nullptr;
  dfa_pattern *end = nullptr;
  int i;

  for (i = 0; i < npatterns; i++) {
    pattern = patterns[i];
    ret     = build(pattern, flags);
    if (!ret) {
      continue;
    }

    if (!_my_patterns) {
      _my_patterns        = ret;
      _my_patterns->_next = nullptr;
      _my_patterns->_idx  = i;
    } else {
      end = _my_patterns;
      while (end->_next) {
        end = end->_next;
      }
      end->_next = ret; // add to end
      ret->_idx  = i;
    }
  }

  return 0;
}

int
DFA::match(const char *str) const
{
  return match(str, strlen(str));
}

int
DFA::match(const char *str, int length) const
{
  int rc;
  dfa_pattern *p = _my_patterns;

  while (p) {
    rc = p->_re->exec(str, length);
    if (rc > 0) {
      return p->_idx;
    }
    p = p->_next;
  }

  return -1;
}
<|endoftext|>


<commit_before><commit_msg>Revert r59190 for regressing startup tests.<commit_after><|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 2006 by FThauer FHammer   *
 *   f.thauer@web.de   *
 *                                                                         *
 *   This program 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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program 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 this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "session.h"
#include "game.h"
#include "guiinterface.h"
#include "configfile.h"
#include <localenginefactory.h>
#include <clientenginefactory.h>
#include <net/clientthread.h>
#include <net/serverthread.h>

#include <sstream>

#define NET_CLIENT_TERMINATE_TIMEOUT_MSEC	1000
#define NET_SERVER_TERMINATE_TIMEOUT_MSEC	1000

using namespace std;

Session::Session(GuiInterface *g, ConfigFile *c)
: currentGameID(0), myNetClient(0), myNetServer(0), myGui(g), myConfig(c)
{

}

Session::~Session()
{
	terminateNetworkClient();
	terminateNetworkServer();
	delete myConfig;
	myConfig = 0;
}

void Session::startLocalGame(const GameData &gameData, const StartData &startData) {

	currentGame.reset();
	currentGameID++;

	myGui->initGui(gameData.guiSpeed);

	PlayerDataList playerDataList;
	for(int i=0; i<gameData.numberOfPlayers; i++) {

		//Namen und Avatarpfad abfragen
		ostringstream myName;
		if (i==0) { myName << "MyName";	}
		else { myName << "Opponent" << i << "Name"; }
		ostringstream myAvatar;
		if (i==0) { myAvatar << "MyAvatar";	}
		else { myAvatar << "Opponent" << i << "Avatar"; }

		//PlayerData erzeugen
		// UniqueId = PlayerNumber for local games.
		boost::shared_ptr<PlayerData> playerData(new PlayerData(i, i, i == 0 ? PLAYER_TYPE_HUMAN : PLAYER_TYPE_COMPUTER));
		playerData->SetName(myConfig->readConfigString(myName.str()));
		playerData->SetAvatarFile(myConfig->readConfigString(myAvatar.str()));

		playerDataList.push_back(playerData);
	}
	// EngineFactory erstellen
	boost::shared_ptr<EngineFactory> factory(new LocalEngineFactory(myConfig)); // LocalEngine erstellen

	currentGame.reset(new Game(myGui, factory, playerDataList, gameData, startData, currentGameID));

	//// SPIEL-SCHLEIFE
	currentGame->initHand();
	currentGame->startHand();
	// SPIEL-SCHLEIFE
}

void Session::startClientGame(boost::shared_ptr<Game> game)
{
	currentGameID++;

	currentGame = game;
}

Game *Session::getCurrentGame()
{
	return currentGame.get();
}

GuiInterface *Session::getGui()
{
	return myGui;
}

void Session::startNetworkClient(const string &serverAddress, unsigned serverPort, bool ipv6, bool sctp, const string &pwd)
{
	if (myNetClient || !myGui)
	{
		assert(false);
		return;
	}
	myNetClient = new ClientThread(*myGui);
	myNetClient->Init(
		serverAddress,
		serverPort,
		ipv6,
		sctp,
		pwd,
		myConfig->readConfigString("MyName"));
	myNetClient->Run();
}

void Session::startNetworkClientForLocalServer()
{
	if (myNetClient || !myGui)
	{
		assert(false);
		return;
	}
	myNetClient = new ClientThread(*myGui);
	bool useIpv6 = myConfig->readConfigInt("ServerUseIpv6") == 1;
	const char *loopbackAddr = useIpv6 ? "::1" : "127.0.0.1";
	myNetClient->Init(
		loopbackAddr,
		myConfig->readConfigInt("ServerPort"),
		useIpv6,
		myConfig->readConfigInt("ServerUseSctp") == 1,
		myConfig->readConfigString("ServerPassword"),
		myConfig->readConfigString("MyName"));
	myNetClient->Run();
}

void Session::terminateNetworkClient()
{
	if (!myNetClient)
		return; // already terminated
	myNetClient->SignalTermination();
	// Give the thread some time to terminate.
	if (myNetClient->Join(NET_CLIENT_TERMINATE_TIMEOUT_MSEC))
	{
		delete myNetClient;
	}
	// If termination fails, leave a memory leak to prevent a crash.
	myNetClient = 0;
}

void Session::startNetworkServer(const GameData &gameData)
{
	if (myNetServer)
	{
		assert(false);
		return;
	}
	myNetServer = new ServerThread(*myGui, myConfig);
	myNetServer->Init(
		myConfig->readConfigInt("ServerPort"),
		myConfig->readConfigInt("ServerUseIpv6") == 1,
		myConfig->readConfigInt("ServerUseSCTP") == 1,
		myConfig->readConfigString("ServerPassword"),
		gameData);
	myNetServer->Run();
}

void Session::initiateNetworkServerGame()
{
	if (!myNetServer)
	{
		assert(false);
		return;
	}
	myNetServer->StartGame();
}

void Session::terminateNetworkServer()
{
	if (!myNetServer)
		return; // already terminated
	myNetServer->SignalTermination();
	// Give the thread some time to terminate.
	if (myNetServer->Join(NET_SERVER_TERMINATE_TIMEOUT_MSEC))
	{
		delete myNetServer;
	}
	// If termination fails, leave a memory leak to prevent a crash.
	myNetServer = 0;
}

void Session::sendClientPlayerAction()
{
	if (!myNetClient)
		return; // only act if client is running.
	myNetClient->SendPlayerAction();
}

void Session::sendChatMessage(const std::string &message) {
	if (!myNetClient)
		return; // only act if client is running.
	myNetClient->SendChatMessage(message);
}

bool Session::isNetworkClientRunning() const
{
	// This, and every place which calls this, is a HACK.
	// TODO
	return myNetClient != NULL;
}

<commit_msg>Fixed typeo. *sigh*<commit_after>/***************************************************************************
 *   Copyright (C) 2006 by FThauer FHammer   *
 *   f.thauer@web.de   *
 *                                                                         *
 *   This program 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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program 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 this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "session.h"
#include "game.h"
#include "guiinterface.h"
#include "configfile.h"
#include <localenginefactory.h>
#include <clientenginefactory.h>
#include <net/clientthread.h>
#include <net/serverthread.h>

#include <sstream>

#define NET_CLIENT_TERMINATE_TIMEOUT_MSEC	1000
#define NET_SERVER_TERMINATE_TIMEOUT_MSEC	1000

using namespace std;

Session::Session(GuiInterface *g, ConfigFile *c)
: currentGameID(0), myNetClient(0), myNetServer(0), myGui(g), myConfig(c)
{

}

Session::~Session()
{
	terminateNetworkClient();
	terminateNetworkServer();
	delete myConfig;
	myConfig = 0;
}

void Session::startLocalGame(const GameData &gameData, const StartData &startData) {

	currentGame.reset();
	currentGameID++;

	myGui->initGui(gameData.guiSpeed);

	PlayerDataList playerDataList;
	for(int i=0; i<gameData.numberOfPlayers; i++) {

		//Namen und Avatarpfad abfragen
		ostringstream myName;
		if (i==0) { myName << "MyName";	}
		else { myName << "Opponent" << i << "Name"; }
		ostringstream myAvatar;
		if (i==0) { myAvatar << "MyAvatar";	}
		else { myAvatar << "Opponent" << i << "Avatar"; }

		//PlayerData erzeugen
		// UniqueId = PlayerNumber for local games.
		boost::shared_ptr<PlayerData> playerData(new PlayerData(i, i, i == 0 ? PLAYER_TYPE_HUMAN : PLAYER_TYPE_COMPUTER));
		playerData->SetName(myConfig->readConfigString(myName.str()));
		playerData->SetAvatarFile(myConfig->readConfigString(myAvatar.str()));

		playerDataList.push_back(playerData);
	}
	// EngineFactory erstellen
	boost::shared_ptr<EngineFactory> factory(new LocalEngineFactory(myConfig)); // LocalEngine erstellen

	currentGame.reset(new Game(myGui, factory, playerDataList, gameData, startData, currentGameID));

	//// SPIEL-SCHLEIFE
	currentGame->initHand();
	currentGame->startHand();
	// SPIEL-SCHLEIFE
}

void Session::startClientGame(boost::shared_ptr<Game> game)
{
	currentGameID++;

	currentGame = game;
}

Game *Session::getCurrentGame()
{
	return currentGame.get();
}

GuiInterface *Session::getGui()
{
	return myGui;
}

void Session::startNetworkClient(const string &serverAddress, unsigned serverPort, bool ipv6, bool sctp, const string &pwd)
{
	if (myNetClient || !myGui)
	{
		assert(false);
		return;
	}
	myNetClient = new ClientThread(*myGui);
	myNetClient->Init(
		serverAddress,
		serverPort,
		ipv6,
		sctp,
		pwd,
		myConfig->readConfigString("MyName"));
	myNetClient->Run();
}

void Session::startNetworkClientForLocalServer()
{
	if (myNetClient || !myGui)
	{
		assert(false);
		return;
	}
	myNetClient = new ClientThread(*myGui);
	bool useIpv6 = myConfig->readConfigInt("ServerUseIpv6") == 1;
	const char *loopbackAddr = useIpv6 ? "::1" : "127.0.0.1";
	myNetClient->Init(
		loopbackAddr,
		myConfig->readConfigInt("ServerPort"),
		useIpv6,
		myConfig->readConfigInt("ServerUseSctp") == 1,
		myConfig->readConfigString("ServerPassword"),
		myConfig->readConfigString("MyName"));
	myNetClient->Run();
}

void Session::terminateNetworkClient()
{
	if (!myNetClient)
		return; // already terminated
	myNetClient->SignalTermination();
	// Give the thread some time to terminate.
	if (myNetClient->Join(NET_CLIENT_TERMINATE_TIMEOUT_MSEC))
	{
		delete myNetClient;
	}
	// If termination fails, leave a memory leak to prevent a crash.
	myNetClient = 0;
}

void Session::startNetworkServer(const GameData &gameData)
{
	if (myNetServer)
	{
		assert(false);
		return;
	}
	myNetServer = new ServerThread(*myGui, myConfig);
	myNetServer->Init(
		myConfig->readConfigInt("ServerPort"),
		myConfig->readConfigInt("ServerUseIpv6") == 1,
		myConfig->readConfigInt("ServerUseSctp") == 1,
		myConfig->readConfigString("ServerPassword"),
		gameData);
	myNetServer->Run();
}

void Session::initiateNetworkServerGame()
{
	if (!myNetServer)
	{
		assert(false);
		return;
	}
	myNetServer->StartGame();
}

void Session::terminateNetworkServer()
{
	if (!myNetServer)
		return; // already terminated
	myNetServer->SignalTermination();
	// Give the thread some time to terminate.
	if (myNetServer->Join(NET_SERVER_TERMINATE_TIMEOUT_MSEC))
	{
		delete myNetServer;
	}
	// If termination fails, leave a memory leak to prevent a crash.
	myNetServer = 0;
}

void Session::sendClientPlayerAction()
{
	if (!myNetClient)
		return; // only act if client is running.
	myNetClient->SendPlayerAction();
}

void Session::sendChatMessage(const std::string &message) {
	if (!myNetClient)
		return; // only act if client is running.
	myNetClient->SendChatMessage(message);
}

bool Session::isNetworkClientRunning() const
{
	// This, and every place which calls this, is a HACK.
	// TODO
	return myNetClient != NULL;
}

<|endoftext|>


<commit_before>/*
				Copyright <SWGEmu>
		See file COPYING for copying conditions.*/

#include "BuffList.h"
#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/managers/object/ObjectManager.h"

BuffList::BuffList() {
	spiceActive = false;

	buffList.setNullValue(NULL);
	buffList.setAllowDuplicateInsertPlan();

	addSerializableVariable("spiceActive", &spiceActive);
	addSerializableVariable("buffList", &buffList);
}

BuffList::BuffList(const BuffList& bf) : Object(), Serializable(), mutex() {
	spiceActive = bf.spiceActive;
	buffList = bf.buffList;

	addSerializableVariable("spiceActive", &spiceActive);
	addSerializableVariable("buffList", &buffList);
}

void BuffList::updateBuffsToDatabase() {
	Locker guard(&mutex);

	for (int i = 0; i < getBuffListSize(); ++i) {
		ManagedReference<Buff*> buff = getBuffByIndex(i);

		if (!buff->isPersistent())
			ObjectManager::instance()->persistObject(buff, 1, "buffs");
		else
			buff->updateToDatabase();
	}
}

void BuffList::sendTo(CreatureObject* player) {
	Locker guard(&mutex);

	for (int i = 0; i < buffList.size(); ++i) {
		Buff* buff = buffList.get(i);

		buff->sendTo(player);
	}
}

void BuffList::sendDestroyTo(CreatureObject* player) {
	Locker guard(&mutex);

	for (int i = 0; i < buffList.size(); ++i) {
		Buff* buff = buffList.get(i);

		buff->sendDestroyTo(player);
	}
}

void BuffList::addBuff(Buff* buff) {
	if (buff == NULL)
		return;

	Locker guard(&mutex);

	ManagedReference<Buff*> ref = buff;

	uint32 buffcrc = buff->getBuffCRC();

	//Remove the old buff if it exists. (Exists checked in removeBuff)
	if ((buff->getBuffType() == BuffType::FOOD && !buff->isAttributeBuff())
			|| (buff->getBuffType() != BuffType::FOOD))
		removeBuff(buffcrc);

	if (!buff->isPersistent())
		ObjectManager::instance()->persistObject(buff, 1, "buffs");

	buffList.put(buffcrc, buff);

	guard.release();

	if (buff->isSpiceBuff())
		spiceActive = true;

	if (!buff->isActive())
		buff->activate();
}

bool BuffList::removeBuff(uint32 buffcrc) {
	Locker guard(&mutex);

	bool ret = false;

	while (buffList.contains(buffcrc)) {
		ret = true;

		ManagedReference<Buff*> buff = buffList.get(buffcrc);

		Locker locker(buff);

		removeBuff(buff);
	}

	return ret;
}

void BuffList::removeBuff(Buff* buff) {
	if (buff == NULL)
		return;

	Locker guard(&mutex);

	ManagedReference<Buff*> ref = buff;

	uint32 buffcrc = buff->getBuffCRC();

	int index = findBuff(buff);

	if (index != -1) {
		if (buff->isSpiceBuff())
			spiceActive = false;

		buff->clearBuffEvent();

		buffList.remove(index);

		mutex.unlock();

		try {
			buff->deactivate();
		} catch (...) {

		}

		if (buff->isPersistent())
			ObjectManager::instance()->destroyObjectFromDatabase(buff->_getObjectID());

		mutex.lock();
	}
}

int BuffList::findBuff(Buff* buff) {
	Locker guard(&mutex);

	uint32 buffCRC = buff->getBuffCRC();

	VectorMapEntry<uint32, ManagedReference<Buff*> > entry(buffCRC);

	int index = buffList.lowerBound(entry);

	if (index < 0)
		return index;

	for (int i = index; i < buffList.size(); ++i) {
		Buff* buffObject = buffList.get(i);

		if (buffObject == buff)
			return i;

		/*uint32 buffObjectCRC = buffObject->getBuffCRC();

		assert(buffObjectCRC == buffCRC);//either we found the buff or its a different buff with the same crc*/
	}

	return -1;
}

void BuffList::clearBuffs(bool updateclient) {
	Locker guard(&mutex);

	while (buffList.size() > 0) {
		ManagedReference<Buff*> buff = buffList.get(0);

		Locker locker(buff);

		if (buff->isActive())
			buff->clearBuffEvent();

		buff->clearBuffEvent();

		buffList.remove(0);

		//Already null checked the buff.
		if (buff->isSpiceBuff())
			buff->deactivate(false); // this wont create the downer
		else
			buff->deactivate();

		if (buff->isPersistent())
			ObjectManager::instance()->destroyObjectFromDatabase(buff->_getObjectID());
	}

	spiceActive = false;
}
<commit_msg>[fixed] stability issue<commit_after>/*
				Copyright <SWGEmu>
		See file COPYING for copying conditions.*/

#include "BuffList.h"
#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/managers/object/ObjectManager.h"

BuffList::BuffList() {
	spiceActive = false;

	buffList.setNullValue(NULL);
	buffList.setAllowDuplicateInsertPlan();

	addSerializableVariable("spiceActive", &spiceActive);
	addSerializableVariable("buffList", &buffList);
}

BuffList::BuffList(const BuffList& bf) : Object(), Serializable(), mutex() {
	spiceActive = bf.spiceActive;
	buffList = bf.buffList;

	addSerializableVariable("spiceActive", &spiceActive);
	addSerializableVariable("buffList", &buffList);
}

void BuffList::updateBuffsToDatabase() {
	Locker guard(&mutex);

	for (int i = 0; i < getBuffListSize(); ++i) {
		ManagedReference<Buff*> buff = getBuffByIndex(i);

		if (!buff->isPersistent())
			ObjectManager::instance()->persistObject(buff, 1, "buffs");
		else
			buff->updateToDatabase();
	}
}

void BuffList::sendTo(CreatureObject* player) {
	Locker guard(&mutex);

	for (int i = 0; i < buffList.size(); ++i) {
		Buff* buff = buffList.get(i);

		buff->sendTo(player);
	}
}

void BuffList::sendDestroyTo(CreatureObject* player) {
	Locker guard(&mutex);

	for (int i = 0; i < buffList.size(); ++i) {
		Buff* buff = buffList.get(i);

		buff->sendDestroyTo(player);
	}
}

void BuffList::addBuff(Buff* buff) {
	if (buff == NULL)
		return;

	Locker guard(&mutex);

	ManagedReference<Buff*> ref = buff;

	uint32 buffcrc = buff->getBuffCRC();

	//Remove the old buff if it exists. (Exists checked in removeBuff)
	if ((buff->getBuffType() == BuffType::FOOD && !buff->isAttributeBuff())
			|| (buff->getBuffType() != BuffType::FOOD))
		removeBuff(buffcrc);

	if (!buff->isPersistent())
		ObjectManager::instance()->persistObject(buff, 1, "buffs");

	buffList.put(buffcrc, buff);

	guard.release();

	if (buff->isSpiceBuff())
		spiceActive = true;

	if (!buff->isActive())
		buff->activate();
}

bool BuffList::removeBuff(uint32 buffcrc) {
	Locker guard(&mutex);

	bool ret = false;

	while (buffList.contains(buffcrc)) {
		ret = true;

		ManagedReference<Buff*> buff = buffList.get(buffcrc);

		Locker locker(buff);

		removeBuff(buff);
	}

	return ret;
}

void BuffList::removeBuff(Buff* buff) {
	if (buff == NULL)
		return;

	Locker guard(&mutex);

	ManagedReference<Buff*> ref = buff;

	uint32 buffcrc = buff->getBuffCRC();

	int index = findBuff(buff);

	if (index != -1) {
		if (buff->isSpiceBuff())
			spiceActive = false;

		buff->clearBuffEvent();

		buffList.remove(index);

		mutex.unlock();

		try {
			buff->deactivate();
		} catch (...) {

		}

		if (buff->isPersistent())
			ObjectManager::instance()->destroyObjectFromDatabase(buff->_getObjectID());

		mutex.lock();
	}
}

int BuffList::findBuff(Buff* buff) {
	Locker guard(&mutex);

	uint32 buffCRC = buff->getBuffCRC();

	VectorMapEntry<uint32, ManagedReference<Buff*> > entry(buffCRC);

	int index = buffList.lowerBound(entry);

	if (index < 0)
		return index;

	for (int i = index; i < buffList.size(); ++i) {
		Buff* buffObject = buffList.get(i);

		if (buffObject == buff)
			return i;

		/*uint32 buffObjectCRC = buffObject->getBuffCRC();

		assert(buffObjectCRC == buffCRC);//either we found the buff or its a different buff with the same crc*/
	}

	return -1;
}

void BuffList::clearBuffs(bool updateclient) {
	Locker guard(&mutex);

	while (buffList.size() > 0) {
		ManagedReference<Buff*> buff = buffList.get(0);

		Locker locker(buff);

		if (buff->isActive())
			buff->clearBuffEvent();

		buff->clearBuffEvent();

		buffList.remove(0);

		mutex.unlock();

		try {
			//Already null checked the buff.
			if (buff->isSpiceBuff())
				buff->deactivate(false); // this wont create the downer
			else
				buff->deactivate();

			if (buff->isPersistent())
				ObjectManager::instance()->destroyObjectFromDatabase(buff->_getObjectID());
		} catch (...) {

		}

		mutex.lock();
	}

	spiceActive = false;
}
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright Leiden University Medical Center, Erasmus University Medical
 *  Center and contributors
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include "selxSSDMetric3rdPartyComponent.h"
#include "selxGDOptimizer3rdPartyComponent.h"
#include "selxSSDMetric4thPartyComponent.h"
#include "selxGDOptimizer4thPartyComponent.h"

#include "gtest/gtest.h"

namespace selx
{
class InterfaceTest : public ::testing::Test
{
public:

  virtual void SetUp()
  {
    Logger * logger = new Logger();
    metric3p    = std::make_shared< SSDMetric3rdPartyComponent >( "nameless", *logger );
    optimizer3p = std::make_shared< GDOptimizer3rdPartyComponent >( "nameless", *logger );

    metric4p    = std::make_shared< SSDMetric4thPartyComponent >( "nameless", *logger );
    optimizer4p = std::make_shared< GDOptimizer4thPartyComponent >( "nameless", *logger );
  }

  virtual void TearDown()
  {
    //delete metric3p;
    //delete optimizer3p;
    //delete metric4p;
    //delete optimizer4p;
  }

  // types as if returned by our component factory
  ComponentBase::Pointer metric3p;
  ComponentBase::Pointer optimizer3p;
  ComponentBase::Pointer metric4p;
  ComponentBase::Pointer optimizer4p;
};

TEST_F( InterfaceTest, InterfaceNameTraits )
{
  EXPECT_STREQ( Properties< MetricValueInterface >::Get().at( "NameOfInterface" ).c_str(), "MetricValueInterface" );
  EXPECT_STREQ( Properties< InterfaceAcceptor< MetricValueInterface >>::Get().at( "NameOfInterface" ).c_str(), "MetricValueInterface" );
}

TEST_F( InterfaceTest, DynamicCast )
{
  int returnval;
  //metric3p should have a MetricValueInterface
  MetricValueInterface::Pointer valueIF = std::dynamic_pointer_cast< MetricValueInterface >( metric3p );
  ASSERT_NE( valueIF, nullptr );
  EXPECT_NO_THROW( returnval = valueIF->GetValue() );

  //metric3p should have a MetricDerivativeInterface
  MetricDerivativeInterface::Pointer derivativeIF = std::dynamic_pointer_cast< MetricDerivativeInterface >( metric3p );
  ASSERT_NE( derivativeIF, nullptr );
  EXPECT_NO_THROW( returnval = derivativeIF->GetDerivative() );

  //optimizer3p should have a OptimizerUpdateInterface
  OptimizerUpdateInterface::Pointer updateIF = std::dynamic_pointer_cast< OptimizerUpdateInterface >( optimizer3p );
  ASSERT_NE( updateIF, nullptr );
  //EXPECT_NO_THROW(returnval = updateIF->Update()); // Update can only be called if metric and optimizer are connected

  //optimizer3p should have a InterfaceAcceptor<MetricValueInterface>
  InterfaceAcceptor< MetricValueInterface >::Pointer valueAcceptorIF = std::dynamic_pointer_cast< InterfaceAcceptor< MetricValueInterface >>(
    optimizer3p );
  ASSERT_NE( valueAcceptorIF, nullptr );

  //optimizer3p should have a InterfaceAcceptor<MetricDerivativeInterface>
  InterfaceAcceptor< MetricDerivativeInterface >::Pointer derivativeAcceptorIF
    = std::dynamic_pointer_cast< InterfaceAcceptor< MetricDerivativeInterface >>( optimizer3p );
  ASSERT_NE( derivativeAcceptorIF, nullptr );
}

TEST_F( InterfaceTest, ConnectByName )
{
  InterfaceStatus IFstatus;
  EXPECT_NO_THROW( IFstatus = optimizer3p->CanAcceptConnectionFrom( metric3p, { { "NameOfInterface", "MetricValueInterface" } } ) );
  EXPECT_EQ( IFstatus, InterfaceStatus::success );

  EXPECT_NO_THROW( IFstatus = optimizer3p->CanAcceptConnectionFrom( metric4p, { { "NameOfInterface", "MetricValueInterface" } } ) );
  EXPECT_EQ( IFstatus, InterfaceStatus::success );

  EXPECT_NO_THROW( IFstatus = optimizer4p->CanAcceptConnectionFrom( metric3p, { { "NameOfInterface", "MetricValueInterface" } } ) );
  EXPECT_EQ( IFstatus, InterfaceStatus::success );

  EXPECT_NO_THROW( IFstatus = optimizer4p->CanAcceptConnectionFrom( metric4p, { { "NameOfInterface", "MetricValueInterface" } } ) );
  EXPECT_EQ( IFstatus, InterfaceStatus::success );

  EXPECT_NO_THROW( IFstatus = optimizer3p->CanAcceptConnectionFrom( metric3p, { { "NameOfInterface", "MetricDerivativeInterface" } } ) );
  EXPECT_EQ( IFstatus, InterfaceStatus::success );

  EXPECT_NO_THROW( IFstatus = optimizer3p->CanAcceptConnectionFrom( metric4p, { { "NameOfInterface", "MetricDerivativeInterface" } } ) );
  EXPECT_EQ( IFstatus, InterfaceStatus::noprovider );

  EXPECT_NO_THROW( IFstatus = optimizer4p->CanAcceptConnectionFrom( metric3p, { { "NameOfInterface", "MetricDerivativeInterface" } } ) );
  EXPECT_EQ( IFstatus, InterfaceStatus::noaccepter );

  EXPECT_NO_THROW( IFstatus = optimizer3p->CanAcceptConnectionFrom( metric3p, {} ) );
  EXPECT_EQ( IFstatus, InterfaceStatus::multiple );
}

TEST_F( InterfaceTest, ConnectAll )
{
  int                               connectionCount = 0;
  int                               returnval;
  OptimizerUpdateInterface::Pointer updateIF;
  EXPECT_NO_THROW( connectionCount = optimizer3p->AcceptConnectionFrom( metric3p ) );
  EXPECT_EQ( connectionCount, 2 ); // both MetricValueInterface and MetricDerivativeInterface are connected

  //optimizer3p should have a OptimizerUpdateInterface
  updateIF = std::dynamic_pointer_cast< OptimizerUpdateInterface >( optimizer3p );
  ASSERT_NE( updateIF, nullptr );
  EXPECT_NO_THROW( returnval = updateIF->Update() ); // Update can only be called if metric and optimizer are connected

  EXPECT_NO_THROW( connectionCount = optimizer3p->AcceptConnectionFrom( metric4p ) );
  EXPECT_EQ( connectionCount, 1 ); // only MetricValueInterface is connected

  //metric4p does not have MetricDerivativeInterface, so optimizer3p cannot run

  EXPECT_NO_THROW( connectionCount = optimizer4p->AcceptConnectionFrom( metric3p ) );
  EXPECT_EQ( connectionCount, 1 ); // only MetricValueInterface is connected

  updateIF = std::dynamic_pointer_cast< OptimizerUpdateInterface >( optimizer4p );
  ASSERT_NE( updateIF, nullptr );
  EXPECT_NO_THROW( returnval = updateIF->Update() );

  EXPECT_NO_THROW( connectionCount = optimizer4p->AcceptConnectionFrom( metric4p ) );
  EXPECT_EQ( connectionCount, 1 ); // only MetricValueInterface is connected

  updateIF = std::dynamic_pointer_cast< OptimizerUpdateInterface >( optimizer4p );
  ASSERT_NE( updateIF, nullptr );
  EXPECT_NO_THROW( returnval = updateIF->Update() );

  EXPECT_NO_THROW( connectionCount = metric4p->AcceptConnectionFrom( optimizer4p ) );
  EXPECT_EQ( connectionCount, 0 ); // cannot connect in this direction

  ConflictinUpdateInterface::Pointer update2IF = std::dynamic_pointer_cast< ConflictinUpdateInterface >( optimizer4p );
  ASSERT_NE( update2IF, nullptr );
  EXPECT_NO_THROW( returnval = update2IF->Update( update2IF ) );
}
} // namespace selx
<commit_msg>COMP BUG: #55 Link error selxComponentInterfaceTest.<commit_after>/*=========================================================================
 *
 *  Copyright Leiden University Medical Center, Erasmus University Medical
 *  Center and contributors
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include "selxSSDMetric3rdPartyComponent.h"
#include "selxGDOptimizer3rdPartyComponent.h"
#include "selxSSDMetric4thPartyComponent.h"
#include "selxGDOptimizer4thPartyComponent.h"

#include "gtest/gtest.h"

namespace selx
{
    namespace hack // see issue SELX-55 Link error selxComponentInterfaceTest #55
    {
        Logger logger;
        typedef SuperElastixComponent< Accepting< >, Providing<  > > DummyBase;
        struct MyComp: DummyBase
        {
            MyComp(): DummyBase("nameless", logger) {}
            virtual bool MeetsCriterion( const CriterionType & criterion ) override { throw 42; };

        } dummy;
    }

class InterfaceTest : public ::testing::Test
{
public:

  virtual void SetUp()
  {
    Logger * logger = new Logger();
    metric3p    = std::make_shared< SSDMetric3rdPartyComponent >( "nameless", *logger );
    optimizer3p = std::make_shared< GDOptimizer3rdPartyComponent >( "nameless", *logger );

    metric4p    = std::make_shared< SSDMetric4thPartyComponent >( "nameless", *logger );
    optimizer4p = std::make_shared< GDOptimizer4thPartyComponent >( "nameless", *logger );
  }

  virtual void TearDown()
  {
    //delete metric3p;
    //delete optimizer3p;
    //delete metric4p;
    //delete optimizer4p;
  }

  // types as if returned by our component factory
  ComponentBase::Pointer metric3p;
  ComponentBase::Pointer optimizer3p;
  ComponentBase::Pointer metric4p;
  ComponentBase::Pointer optimizer4p;
};

TEST_F( InterfaceTest, InterfaceNameTraits )
{
  EXPECT_STREQ( Properties< MetricValueInterface >::Get().at( "NameOfInterface" ).c_str(), "MetricValueInterface" );
  EXPECT_STREQ( Properties< InterfaceAcceptor< MetricValueInterface >>::Get().at( "NameOfInterface" ).c_str(), "MetricValueInterface" );
}

TEST_F( InterfaceTest, DynamicCast )
{
  int returnval;
  //metric3p should have a MetricValueInterface
  MetricValueInterface::Pointer valueIF = std::dynamic_pointer_cast< MetricValueInterface >( metric3p );
  ASSERT_NE( valueIF, nullptr );
  EXPECT_NO_THROW( returnval = valueIF->GetValue() );

  //metric3p should have a MetricDerivativeInterface
  MetricDerivativeInterface::Pointer derivativeIF = std::dynamic_pointer_cast< MetricDerivativeInterface >( metric3p );
  ASSERT_NE( derivativeIF, nullptr );
  EXPECT_NO_THROW( returnval = derivativeIF->GetDerivative() );

  //optimizer3p should have a OptimizerUpdateInterface
  OptimizerUpdateInterface::Pointer updateIF = std::dynamic_pointer_cast< OptimizerUpdateInterface >( optimizer3p );
  ASSERT_NE( updateIF, nullptr );
  //EXPECT_NO_THROW(returnval = updateIF->Update()); // Update can only be called if metric and optimizer are connected

  //optimizer3p should have a InterfaceAcceptor<MetricValueInterface>
  InterfaceAcceptor< MetricValueInterface >::Pointer valueAcceptorIF = std::dynamic_pointer_cast< InterfaceAcceptor< MetricValueInterface >>(
    optimizer3p );
  ASSERT_NE( valueAcceptorIF, nullptr );

  //optimizer3p should have a InterfaceAcceptor<MetricDerivativeInterface>
  InterfaceAcceptor< MetricDerivativeInterface >::Pointer derivativeAcceptorIF
    = std::dynamic_pointer_cast< InterfaceAcceptor< MetricDerivativeInterface >>( optimizer3p );
  ASSERT_NE( derivativeAcceptorIF, nullptr );
}

TEST_F( InterfaceTest, ConnectByName )
{
  InterfaceStatus IFstatus;
  EXPECT_NO_THROW( IFstatus = optimizer3p->CanAcceptConnectionFrom( metric3p, { { "NameOfInterface", "MetricValueInterface" } } ) );
  EXPECT_EQ( IFstatus, InterfaceStatus::success );

  EXPECT_NO_THROW( IFstatus = optimizer3p->CanAcceptConnectionFrom( metric4p, { { "NameOfInterface", "MetricValueInterface" } } ) );
  EXPECT_EQ( IFstatus, InterfaceStatus::success );

  EXPECT_NO_THROW( IFstatus = optimizer4p->CanAcceptConnectionFrom( metric3p, { { "NameOfInterface", "MetricValueInterface" } } ) );
  EXPECT_EQ( IFstatus, InterfaceStatus::success );

  EXPECT_NO_THROW( IFstatus = optimizer4p->CanAcceptConnectionFrom( metric4p, { { "NameOfInterface", "MetricValueInterface" } } ) );
  EXPECT_EQ( IFstatus, InterfaceStatus::success );

  EXPECT_NO_THROW( IFstatus = optimizer3p->CanAcceptConnectionFrom( metric3p, { { "NameOfInterface", "MetricDerivativeInterface" } } ) );
  EXPECT_EQ( IFstatus, InterfaceStatus::success );

  EXPECT_NO_THROW( IFstatus = optimizer3p->CanAcceptConnectionFrom( metric4p, { { "NameOfInterface", "MetricDerivativeInterface" } } ) );
  EXPECT_EQ( IFstatus, InterfaceStatus::noprovider );

  EXPECT_NO_THROW( IFstatus = optimizer4p->CanAcceptConnectionFrom( metric3p, { { "NameOfInterface", "MetricDerivativeInterface" } } ) );
  EXPECT_EQ( IFstatus, InterfaceStatus::noaccepter );

  EXPECT_NO_THROW( IFstatus = optimizer3p->CanAcceptConnectionFrom( metric3p, {} ) );
  EXPECT_EQ( IFstatus, InterfaceStatus::multiple );
}

TEST_F( InterfaceTest, ConnectAll )
{
  int                               connectionCount = 0;
  int                               returnval;
  OptimizerUpdateInterface::Pointer updateIF;
  EXPECT_NO_THROW( connectionCount = optimizer3p->AcceptConnectionFrom( metric3p ) );
  EXPECT_EQ( connectionCount, 2 ); // both MetricValueInterface and MetricDerivativeInterface are connected

  //optimizer3p should have a OptimizerUpdateInterface
  updateIF = std::dynamic_pointer_cast< OptimizerUpdateInterface >( optimizer3p );
  ASSERT_NE( updateIF, nullptr );
  EXPECT_NO_THROW( returnval = updateIF->Update() ); // Update can only be called if metric and optimizer are connected

  EXPECT_NO_THROW( connectionCount = optimizer3p->AcceptConnectionFrom( metric4p ) );
  EXPECT_EQ( connectionCount, 1 ); // only MetricValueInterface is connected

  //metric4p does not have MetricDerivativeInterface, so optimizer3p cannot run

  EXPECT_NO_THROW( connectionCount = optimizer4p->AcceptConnectionFrom( metric3p ) );
  EXPECT_EQ( connectionCount, 1 ); // only MetricValueInterface is connected

  updateIF = std::dynamic_pointer_cast< OptimizerUpdateInterface >( optimizer4p );
  ASSERT_NE( updateIF, nullptr );
  EXPECT_NO_THROW( returnval = updateIF->Update() );

  EXPECT_NO_THROW( connectionCount = optimizer4p->AcceptConnectionFrom( metric4p ) );
  EXPECT_EQ( connectionCount, 1 ); // only MetricValueInterface is connected

  updateIF = std::dynamic_pointer_cast< OptimizerUpdateInterface >( optimizer4p );
  ASSERT_NE( updateIF, nullptr );
  EXPECT_NO_THROW( returnval = updateIF->Update() );

  EXPECT_NO_THROW( connectionCount = metric4p->AcceptConnectionFrom( optimizer4p ) );
  EXPECT_EQ( connectionCount, 0 ); // cannot connect in this direction

  ConflictinUpdateInterface::Pointer update2IF = std::dynamic_pointer_cast< ConflictinUpdateInterface >( optimizer4p );
  ASSERT_NE( update2IF, nullptr );
  EXPECT_NO_THROW( returnval = update2IF->Update( update2IF ) );
}
} // namespace selx
<|endoftext|>


<commit_before>#include <sstream>
#define _USE_MATH_DEFINES
#include <cmath>
#include <math.h>

#include "entity.h"
#include "board.h"

using namespace std;

Entity::Entity(std::string name, ABoard& board, Player& owner, r2 position, r2 size, double speed, int sight_radius, bool solid, int capacity) :
	position(position),
	speed(speed),
	deletable(false),
	orientation(0),
	size(size),
	name(name),
	owner(owner),
	board(board),
	sight_radius(sight_radius),
	solid(solid),
	capacity(capacity)
{
	static size_t idCount = 0;
	id = idCount++;
	adjustPosition();
	stringstream message;
	message << "Created Entity " << this
		<< " with ID " << id
		<< " of kind " << name
		<< " owned by board " << &board
		<< " at " << position.x << "," << position.y;
	Logger::getInstance()->writeInformation(message.str());
}

Entity::~Entity() {
	stringstream message;
	message << "Killing Entity " << this << " of kind " << name;
	Logger::getInstance()->writeInformation(message.str());
}

bool Entity::adjustPosition() {
	double topX = board.sizeX - size.x;
	double topY = board.sizeY - size.y;
	r2 oldpos = position;
	position = {clip(position.x, 0, topX),clip(position.y, 0, topY)};
	bool adjusted = oldpos != position;
	if (adjusted) {
		setFrame();
	}
	return adjusted;
}

///////////////////////////////////////////////////////////////////////////////
// HIC SVNT DRACONES
///////////////////////////////////////////////////////////////////////////////

#include <queue>
#include <set>

struct TSNode {
	r2 position;
	double g, f;
	shared_ptr<TSNode> previous;
	TSNode(r2 position, double g, double f, shared_ptr<TSNode> previous) :
		position(position), g(g), f(f), previous(previous) {};
};

class compare {
	public:
		bool operator()(const shared_ptr<TSNode> a, const shared_ptr<TSNode> b) {
			return a->f > b->f;
		}
};

void Entity::addTarget(r2 newTarget) {
	auto round = [](r2 a) {return r2(floor(a.x)+.5, floor(a.y)+.5);};
	r2
		end = round(targeted() ? waypoints.back() : position),
		start = round(newTarget);
	if(start.x < 0 || start.x > board.sizeX ||
			start.y < 0 || start.y > board.sizeY) {
		return;
	}

	priority_queue<TSNode, vector<shared_ptr<TSNode>>, compare> open;
	auto h = [&end](r2& p) {return (p - end).length();};
	auto f = [&h](TSNode n) {return h(n.position) + n.g;};
	auto straightenOnce = [this](shared_ptr<TSNode> n) {
		if(n->previous) {
			if(n->previous->previous) {
				if(canEnter(rectangle::box(n->position, n->previous->previous->position, this->size))) {
					n->previous = n->previous->previous;
					return true;
				}
			}
		}
		return false;
	};
	auto straighten = [straightenOnce](shared_ptr<TSNode> n) {
		while(straightenOnce(n));
	};
	bool closed[board.sizeX][board.sizeY];
	for(size_t i = 0; i < board.sizeX; i++) {
		for(size_t j = 0; j < board.sizeY; j++) {
			closed[i][j] = false;
		}
	}

	open.emplace(make_shared<TSNode>(start, 0, h(start), nullptr));
	// i is a runtime cap
	for (size_t i = 4096; (open.size() > 0) && (i > 0); i--) {
		auto c = open.top();
		open.pop();
		auto cpos = c->position;
		if(closed[(int)floor(cpos.x)][(int)floor(cpos.y)]) {
			continue;
		}
		closed[(int)floor(cpos.x)][(int)floor(cpos.y)] = true;
		if ((cpos - end).sqLength() <= 1) {
			for (auto p = c; p; p = p->previous) {
				waypoints.push_back(p->position);
			}
			return;
		}
		for(auto y = cpos.y - 1; y <= cpos.y + 1; y++) {
			for(auto x = cpos.x - 1; x <= cpos.x + 1; x++) {
				auto p = r2(x, y);
				if (p == cpos) {
					continue;
				}
				if ((owner.getVisibility(p) != INVISIBLE) && !(canEnter(rectangle::box(p - size/2, cpos - size/2, size)))) {
					continue;
				}
				auto n = make_shared<TSNode>(p, (cpos - p).length() + c->g, .0, c);
				n->f = f(*n);
				if (closed[(int)floor(p.x)][(int)floor(p.y)]) {
					continue;
				}
				straighten(n);
				open.emplace(n);
			}
		}
	}
}

void Entity::unsetTarget() {
	waypoints.clear();
}

r2 Entity::target() {
	return waypoints.size() > 0?
		waypoints.front():
		r2(0, 0);
}

bool Entity::targeted() {
	return waypoints.size() > 0;
}

void Entity::collide(Entity* other) {
	if(other) {
		if(!deletable &&
				!other->deletable) {
			other->collide(*this);
		}
	}
}

void Entity::collide(Entity& other) {}

void Entity::collide(ResourceEntity& other) {}

bool Entity::canEnter(rectangle r) {
	auto& p = r.position;
	auto& s = r.size;
	for (int dx = 0; dx < s.x + 1; dx++) {
		for (int dy = 0; dy < s.y + 1; dy++) {
			auto t = board.getTerrain(floor(p.x + dx), floor(p.y + dy));
			if (t) {
				if(t->solid) {
					return false;
				}
			}
		}
	}
	auto colliders = board.selectEntities([this, r](shared_ptr<Entity> e) {
			return (*e != *this) &&
			e->solid &&
			!e->deletable &&
			(rectangle(e->position, e->size).intersects(r));
			});
	return colliders.size() == 0;
}

bool Entity::canEnter(r2 newPosition) {
	auto newCenter = newPosition + size / 2;
	if (newCenter.x < 0 ||
			newCenter.y < 0 ||
			newCenter.x >= board.sizeX ||
			newCenter.y >= board.sizeY) {
		return false;
	}
	return canEnter(rectangle(newPosition, size));
}

void Entity::update() {
	if (targeted()) {
		auto traj = trajectory();
		orientation = atan2(traj.y, traj.x);
		auto dr = speed*board.dt/1000;
		if (pow(dr, 2) < sqDistance()) {
			auto newPos = position + r2::fromPolar(orientation, dr);
			rectangle shapeCandidate(newPos, size);
			auto colliders = board.selectEntities([this, shapeCandidate](shared_ptr<Entity> e) {
					return (*e != *this) &&
					(rectangle(e->position, e->size).intersects(shapeCandidate));
					});
			for(auto c : colliders) {
				collide(c.get());
			}
			if (!canEnter(newPos)) {
				auto destiny = waypoints.back();
				unsetTarget();
				addTarget(destiny);
				return;
			}
			position = newPos;
		} else {
			position = target() - size/2;
			waypoints.pop_front();
		}
		if (adjustPosition()) {
			unsetTarget();
		}
		setFrame();
	}
}

r2 Entity::center() {
	return position + (size/2);
}

r2 Entity::getPosition() {
	return position;
}

void Entity::setPosition(r2 newPos) {
	position = newPos;
}

r2 Entity::trajectory() {
	return target() - center();
}

double Entity::sqDistance() {
	return trajectory().sqLength();
}

double Entity::distance() {
	return trajectory().length();
}

double Entity::getOrientation() {
	return orientation;
}

void Entity::setOrientation(double newOrientation) {
	orientation = newOrientation;
}

Directions Entity::getDirection(){
	return static_cast<Directions>((unsigned)floor(4*orientation/M_PI+.5)%8);
}

void Entity::setDeletable() {
	deletable = true;
	setFrame();
}

bool Entity::getDeletable() {
	return deletable;
}

size_t Entity::getId() {
	return id;
}

void Entity::setId(size_t newId) {
	id = newId;
}

void Entity::setFrame() {
	setFrame(board.getFrame());
}

size_t Entity::getFrame() {
	return frame;
}
void Entity::setFrame(size_t newFrame) {
	frame = newFrame;
}

bool Entity::operator==(Entity& other) {
	return this == &other;
}

bool Entity::operator!=(Entity& other) {
	return !operator==(other);
}

ResourceEntity::ResourceEntity(std::string name, ABoard& board, Player& owner, r2 position, r2 size, double speed, int sight_radius, bool solid, int capacity):Entity(name, board, owner, position, size, speed, sight_radius, solid, capacity)
{}

void ResourceEntity::collide(Entity& other) {
	if(!getDeletable() &&
			!other.getDeletable()) {
		stringstream message;
		message << "Un " << other.name << " de " << other.owner.name << " encontró" << name;
		if(other.owner.grantResources(name, capacity)) {
			setDeletable();
			message << "; ahora " << other.owner.name
				<< " tiene " << other.owner.getResources()[name]
				<< " " << name;
		} else {
			message << "; pero no puede tomarlos";
		}
		Logger::getInstance()->writeInformation(message.str());
	}
}

void ResourceEntity::collide(ResourceEntity& other) {}

<commit_msg>Short-circuiting visibility naïvety<commit_after>#include <sstream>
#define _USE_MATH_DEFINES
#include <cmath>
#include <math.h>

#include "entity.h"
#include "board.h"

using namespace std;

Entity::Entity(std::string name, ABoard& board, Player& owner, r2 position, r2 size, double speed, int sight_radius, bool solid, int capacity) :
	position(position),
	speed(speed),
	deletable(false),
	orientation(0),
	size(size),
	name(name),
	owner(owner),
	board(board),
	sight_radius(sight_radius),
	solid(solid),
	capacity(capacity)
{
	static size_t idCount = 0;
	id = idCount++;
	adjustPosition();
	stringstream message;
	message << "Created Entity " << this
		<< " with ID " << id
		<< " of kind " << name
		<< " owned by board " << &board
		<< " at " << position.x << "," << position.y;
	Logger::getInstance()->writeInformation(message.str());
}

Entity::~Entity() {
	stringstream message;
	message << "Killing Entity " << this << " of kind " << name;
	Logger::getInstance()->writeInformation(message.str());
}

bool Entity::adjustPosition() {
	double topX = board.sizeX - size.x;
	double topY = board.sizeY - size.y;
	r2 oldpos = position;
	position = {clip(position.x, 0, topX),clip(position.y, 0, topY)};
	bool adjusted = oldpos != position;
	if (adjusted) {
		setFrame();
	}
	return adjusted;
}

///////////////////////////////////////////////////////////////////////////////
// HIC SVNT DRACONES
///////////////////////////////////////////////////////////////////////////////

#include <queue>
#include <set>

struct TSNode {
	r2 position;
	double g, f;
	shared_ptr<TSNode> previous;
	TSNode(r2 position, double g, double f, shared_ptr<TSNode> previous) :
		position(position), g(g), f(f), previous(previous) {};
};

class compare {
	public:
		bool operator()(const shared_ptr<TSNode> a, const shared_ptr<TSNode> b) {
			return a->f > b->f;
		}
};

void Entity::addTarget(r2 newTarget) {
	auto round = [](r2 a) {return r2(floor(a.x)+.5, floor(a.y)+.5);};
	r2
		end = round(targeted() ? waypoints.back() : position),
		start = round(newTarget);
	if(start.x < 0 || start.x > board.sizeX ||
			start.y < 0 || start.y > board.sizeY) {
		return;
	}

	priority_queue<TSNode, vector<shared_ptr<TSNode>>, compare> open;
	auto h = [&end](r2& p) {return (p - end).length();};
	auto f = [&h](TSNode n) {return h(n.position) + n.g;};
	auto straightenOnce = [this](shared_ptr<TSNode> n) {
		if(n->previous) {
			if(n->previous->previous) {
				if(canEnter(rectangle::box(n->position, n->previous->previous->position, this->size))) {
					n->previous = n->previous->previous;
					return true;
				}
			}
		}
		return false;
	};
	auto straighten = [straightenOnce](shared_ptr<TSNode> n) {
		while(straightenOnce(n));
	};
	bool closed[board.sizeX][board.sizeY];
	for(size_t i = 0; i < board.sizeX; i++) {
		for(size_t j = 0; j < board.sizeY; j++) {
			closed[i][j] = false;
		}
	}

	open.emplace(make_shared<TSNode>(start, 0, h(start), nullptr));
	// i is a runtime cap
	for (size_t i = 4096; (open.size() > 0) && (i > 0); i--) {
		auto c = open.top();
		open.pop();
		auto cpos = c->position;
		if(closed[(int)floor(cpos.x)][(int)floor(cpos.y)]) {
			continue;
		}
		closed[(int)floor(cpos.x)][(int)floor(cpos.y)] = true;
		if ((cpos - end).sqLength() <= 1) {
			for (auto p = c; p; p = p->previous) {
				waypoints.push_back(p->position);
			}
			return;
		}
		for(auto y = cpos.y - 1; y <= cpos.y + 1; y++) {
			for(auto x = cpos.x - 1; x <= cpos.x + 1; x++) {
				auto p = r2(x, y);
				if (p == cpos) {
					continue;
				}
				if ((owner.getVisibility(p) != INVISIBLE)) {
					if (!(canEnter(rectangle::box(p - size/2, cpos - size/2, size)))) {
						continue;
					}
				}
				auto n = make_shared<TSNode>(p, (cpos - p).length() + c->g, .0, c);
				n->f = f(*n);
				if (closed[(int)floor(p.x)][(int)floor(p.y)]) {
					continue;
				}
				straighten(n);
				open.emplace(n);
			}
		}
	}
}

void Entity::unsetTarget() {
	waypoints.clear();
}

r2 Entity::target() {
	return waypoints.size() > 0?
		waypoints.front():
		r2(0, 0);
}

bool Entity::targeted() {
	return waypoints.size() > 0;
}

void Entity::collide(Entity* other) {
	if(other) {
		if(!deletable &&
				!other->deletable) {
			other->collide(*this);
		}
	}
}

void Entity::collide(Entity& other) {}

void Entity::collide(ResourceEntity& other) {}

bool Entity::canEnter(rectangle r) {
	auto& p = r.position;
	auto& s = r.size;
	for (int dx = 0; dx < s.x + 1; dx++) {
		for (int dy = 0; dy < s.y + 1; dy++) {
			auto t = board.getTerrain(floor(p.x + dx), floor(p.y + dy));
			if (t) {
				if(t->solid) {
					return false;
				}
			}
		}
	}
	auto colliders = board.selectEntities([this, r](shared_ptr<Entity> e) {
			return (*e != *this) &&
			e->solid &&
			!e->deletable &&
			(rectangle(e->position, e->size).intersects(r));
			});
	return colliders.size() == 0;
}

bool Entity::canEnter(r2 newPosition) {
	auto newCenter = newPosition + size / 2;
	if (newCenter.x < 0 ||
			newCenter.y < 0 ||
			newCenter.x >= board.sizeX ||
			newCenter.y >= board.sizeY) {
		return false;
	}
	return canEnter(rectangle(newPosition, size));
}

void Entity::update() {
	if (targeted()) {
		auto traj = trajectory();
		orientation = atan2(traj.y, traj.x);
		auto dr = speed*board.dt/1000;
		if (pow(dr, 2) < sqDistance()) {
			auto newPos = position + r2::fromPolar(orientation, dr);
			rectangle shapeCandidate(newPos, size);
			auto colliders = board.selectEntities([this, shapeCandidate](shared_ptr<Entity> e) {
					return (*e != *this) &&
					(rectangle(e->position, e->size).intersects(shapeCandidate));
					});
			for(auto c : colliders) {
				collide(c.get());
			}
			if (!canEnter(newPos)) {
				auto destiny = waypoints.back();
				unsetTarget();
				addTarget(destiny);
				return;
			}
			position = newPos;
		} else {
			position = target() - size/2;
			waypoints.pop_front();
		}
		if (adjustPosition()) {
			unsetTarget();
		}
		setFrame();
	}
}

r2 Entity::center() {
	return position + (size/2);
}

r2 Entity::getPosition() {
	return position;
}

void Entity::setPosition(r2 newPos) {
	position = newPos;
}

r2 Entity::trajectory() {
	return target() - center();
}

double Entity::sqDistance() {
	return trajectory().sqLength();
}

double Entity::distance() {
	return trajectory().length();
}

double Entity::getOrientation() {
	return orientation;
}

void Entity::setOrientation(double newOrientation) {
	orientation = newOrientation;
}

Directions Entity::getDirection(){
	return static_cast<Directions>((unsigned)floor(4*orientation/M_PI+.5)%8);
}

void Entity::setDeletable() {
	deletable = true;
	setFrame();
}

bool Entity::getDeletable() {
	return deletable;
}

size_t Entity::getId() {
	return id;
}

void Entity::setId(size_t newId) {
	id = newId;
}

void Entity::setFrame() {
	setFrame(board.getFrame());
}

size_t Entity::getFrame() {
	return frame;
}
void Entity::setFrame(size_t newFrame) {
	frame = newFrame;
}

bool Entity::operator==(Entity& other) {
	return this == &other;
}

bool Entity::operator!=(Entity& other) {
	return !operator==(other);
}

ResourceEntity::ResourceEntity(std::string name, ABoard& board, Player& owner, r2 position, r2 size, double speed, int sight_radius, bool solid, int capacity):Entity(name, board, owner, position, size, speed, sight_radius, solid, capacity)
{}

void ResourceEntity::collide(Entity& other) {
	if(!getDeletable() &&
			!other.getDeletable()) {
		stringstream message;
		message << "Un " << other.name << " de " << other.owner.name << " encontró" << name;
		if(other.owner.grantResources(name, capacity)) {
			setDeletable();
			message << "; ahora " << other.owner.name
				<< " tiene " << other.owner.getResources()[name]
				<< " " << name;
		} else {
			message << "; pero no puede tomarlos";
		}
		Logger::getInstance()->writeInformation(message.str());
	}
}

void ResourceEntity::collide(ResourceEntity& other) {}

<|endoftext|>