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

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */

#include "../Debug/Trace.h"

namespace Stroika {
    namespace Foundation {
        namespace Memory {

            /*
            ********************************************************************************
            ************** SharedByValue_CopyByFunction<T,SHARED_IMLP> *********************
            ********************************************************************************
            */
            template <typename T, typename SHARED_IMLP>
            inline SharedByValue_CopyByFunction<T, SHARED_IMLP>::SharedByValue_CopyByFunction (SHARED_IMLP (*copier) (const T&)) noexcept
                : fCopier (copier)
            {
                RequireNotNull (copier);
            }
            template <typename T, typename SHARED_IMLP>
            inline SHARED_IMLP SharedByValue_CopyByFunction<T, SHARED_IMLP>::Copy (const T& t) const
            {
                AssertNotNull (fCopier);
                return (*fCopier) (t);
            }

            /*
            ********************************************************************************
            *************** SharedByValue_CopyByDefault<T,SHARED_IMLP> *********************
            ********************************************************************************
            */
            template <typename T, typename SHARED_IMLP>
            inline SHARED_IMLP SharedByValue_CopyByDefault<T, SHARED_IMLP>::Copy (const T& t)
            {
                return SHARED_IMLP (new T (t));
            }

            /*
            ********************************************************************************
            ****** SharedByValue_CopySharedPtrExternallySynchronized<T,SHARED_IMLP> ********
            ********************************************************************************
            */
            template <typename T, typename SHARED_IMLP>
            inline SHARED_IMLP SharedByValue_CopySharedPtrExternallySynchronized<T, SHARED_IMLP>::Load (const SHARED_IMLP& copyFrom)
            {
                return copyFrom;
            }
            template <typename T, typename SHARED_IMLP>
            inline void SharedByValue_CopySharedPtrExternallySynchronized<T, SHARED_IMLP>::Store (SHARED_IMLP* storeTo, const SHARED_IMLP& o)
            {
                RequireNotNull (storeTo);
                *storeTo = o;
            }

            /*
            ********************************************************************************
            ********* SharedByValue_CopySharedPtrAtomicSynchronized<T,SHARED_IMLP> *********
            ********************************************************************************
            */
            template <typename T, typename SHARED_IMLP>
            inline SHARED_IMLP SharedByValue_CopySharedPtrAtomicSynchronized<T, SHARED_IMLP>::Load (const SHARED_IMLP& copyFrom)
            {
                return atomic_load (&copyFrom);
            }
            template <typename T, typename SHARED_IMLP>
            inline void SharedByValue_CopySharedPtrAtomicSynchronized<T, SHARED_IMLP>::Store (SHARED_IMLP* storeTo, const SHARED_IMLP& o)
            {
                RequireNotNull (storeTo);
                atomic_store (storeTo, o);
            }

            /*
            ********************************************************************************
            ****************************** SharedByValue<TRAITS> ***************************
            ********************************************************************************
            */
            template <typename TRAITS>
            inline SharedByValue<TRAITS>::SharedByValue () noexcept
                : fCopier_ (element_copier_type ())
                , fSharedImpl_ ()
            {
            }
            template <typename TRAITS>
            inline SharedByValue<TRAITS>::SharedByValue (nullptr_t n) noexcept
                : fCopier_ (element_copier_type ())
                , fSharedImpl_ ()
            {
            }
            template <typename TRAITS>
            inline SharedByValue<TRAITS>::SharedByValue (const SharedByValue<TRAITS>& from) noexcept
                : fCopier_ (from.fCopier_)
                , fSharedImpl_ (shared_impl_copier_type::Load (from.fSharedImpl_))
            {
            }
            template <typename TRAITS>
            inline SharedByValue<TRAITS>::SharedByValue (SharedByValue<TRAITS>&& from) noexcept
                : fCopier_ (from.fCopier_)
                , fSharedImpl_ (std::move (from.fSharedImpl_))
            {
            }
            template <typename TRAITS>
            inline SharedByValue<TRAITS>::SharedByValue (const shared_ptr_type& from, const element_copier_type& copier) noexcept
                : fCopier_ (copier)
                , fSharedImpl_ (shared_impl_copier_type::Load (from))
            {
            }
            template <typename TRAITS>
            inline SharedByValue<TRAITS>::SharedByValue (shared_ptr_type&& from, const element_copier_type&& copier) noexcept
                : fCopier_ (move (copier))
                , fSharedImpl_ (move (from))
            {
            }
            template <typename TRAITS>
            inline SharedByValue<TRAITS>::SharedByValue (element_type* from, const element_copier_type& copier)
                : fCopier_ (copier)
                , fSharedImpl_ (from)
            {
            }
            template <typename TRAITS>
            inline SharedByValue<TRAITS>& SharedByValue<TRAITS>::operator= (const SharedByValue<TRAITS>& rhs)
            {
                // If the pointers are the same, there is no need to copy, as the reference counts must also be the same,
                // and we can avoid the (common) and costly memory barrier
                if (fSharedImpl_.get () != rhs.fSharedImpl_.get ()) {
                    fCopier_ = rhs.fCopier_;
                    shared_impl_copier_type::Store (&fSharedImpl_, shared_impl_copier_type::Load (rhs.fSharedImpl_));
                }
                return *this;
            }
            template <typename TRAITS>
            inline SharedByValue<TRAITS>& SharedByValue<TRAITS>::operator= (SharedByValue<TRAITS>&& rhs)
            {
                // If the pointers are the same, there is no need to copy, as the reference counts must also be the same,
                // and we can avoid the (common) and costly memory barrier
                if (fSharedImpl_.get () != rhs.fSharedImpl_.get ()) {
                    fCopier_ = rhs.fCopier_;
                    // ASSUME if doing a move() then this doesn't need to be a multithread safe copy (from the source), since
                    // if its a temporary, you cannot have mulitple peopel referring to me
                    shared_impl_copier_type::Store (&fSharedImpl_, rhs.fSharedImpl_);
                }
                return *this;
            }
            template <typename TRAITS>
            inline SharedByValue<TRAITS>& SharedByValue<TRAITS>::operator= (const shared_ptr_type& from)
            {
                // If the pointers are the same, there is no need to copy, as the reference counts must also be the same,
                // and we can avoid the (common) and costly memory barrier
                if (fSharedImpl_.get () != from.get ()) {
                    shared_impl_copier_type::Store (&fSharedImpl_, shared_impl_copier_type::Load (from));
                }
                return *this;
            }
            template <typename TRAITS>
            inline SharedByValue<TRAITS>& SharedByValue<TRAITS>::operator= (shared_ptr_type&& from)
            {
                // If the pointers are the same, there is no need to copy, as the reference counts must also be the same,
                // and we can avoid the (common) and costly memory barrier
                if (fSharedImpl_.get () != from.get ()) {
                    // ASSUME if doing a move() then this doesn't need to be a multithread safe copy (from the source), since
                    // if its a temporary, you cannot have mulitple peopel referring to me
                    shared_impl_copier_type::Store (&fSharedImpl_, from);
                }
                return *this;
            }
            template <typename TRAITS>
            inline const typename SharedByValue<TRAITS>::element_type* SharedByValue<TRAITS>::get () const noexcept
            {
                return fSharedImpl_.get ();
            }
            template <typename TRAITS>
            template <typename... COPY_ARGS>
            inline typename SharedByValue<TRAITS>::element_type* SharedByValue<TRAITS>::get (COPY_ARGS&&... copyArgs)
            {
                element_type* ptr = fSharedImpl_.get ();
                /*
                 * For non-const pointing, we must clone ourselves (if there are
                 * extra referneces). If we are a nullptr pointer, nobody could actually
                 * rereference it anyhow, so don't bother with the Assure1Reference()
                 * in that case.
                 */
                if (ptr != nullptr) {
                    Assure1Reference (forward<COPY_ARGS> (copyArgs)...);
                    ptr = fSharedImpl_.get ();
                    EnsureNotNull (ptr);
                }
                return ptr;
            }
            template <typename TRAITS>
            inline const typename SharedByValue<TRAITS>::element_type* SharedByValue<TRAITS>::cget () const noexcept
            {
                return get ();
            }
            template <typename TRAITS>
            inline const typename SharedByValue<TRAITS>::element_type* SharedByValue<TRAITS>::operator-> () const
            {
                return fSharedImpl_.get ();
            }
            template <typename TRAITS>
            inline typename SharedByValue<TRAITS>::element_type* SharedByValue<TRAITS>::operator-> ()
            {
                return get ();
            }
            template <typename TRAITS>
            inline const typename SharedByValue<TRAITS>::element_type& SharedByValue<TRAITS>::operator* () const
            {
                const element_type* ptr = get ();
                EnsureNotNull (ptr);
                return *ptr;
            }
            template <typename TRAITS>
            inline typename SharedByValue<TRAITS>::element_type& SharedByValue<TRAITS>::operator* ()
            {
                /*
                 * For non-const dereferencing, we must clone ourselves (if there are
                 * extra referneces).
                 */
                Assure1Reference ();
                element_type* ptr = get ();
                EnsureNotNull (ptr);
                return *ptr;
            }
            template <typename TRAITS>
            inline bool SharedByValue<TRAITS>::operator== (const SharedByValue<TRAITS>& rhs) const
            {
                return fSharedImpl_ == rhs.fSharedImpl_;
            }
            template <typename TRAITS>
            inline bool SharedByValue<TRAITS>::operator!= (const SharedByValue<TRAITS>& rhs) const
            {
                return fSharedImpl_ != rhs.fSharedImpl_;
            }
            template <typename TRAITS>
            inline typename SharedByValue<TRAITS>::element_copier_type SharedByValue<TRAITS>::GetCopier () const
            {
                return fCopier_;
            }
            template <typename TRAITS>
            inline SharedByValue_State SharedByValue<TRAITS>::GetSharingState () const
            {
                switch (fSharedImpl_.use_count ()) {
                    case 0:
                        Assert (fSharedImpl_.get () == nullptr);
                        return SharedByValue_State::eNull;
                    case 1:
                        Assert (fSharedImpl_.get () != nullptr);
                        Assert (fSharedImpl_.unique ());
                        return SharedByValue_State::eSolo;
                    default:
                        Assert (fSharedImpl_.get () != nullptr);
                        //NOT NECESSARILY - cuz there is no lock
                        // between the use_count and this unique call, so another object could decrement its count
                        // and this could be that it was shared, but is no solo.
                        // Assert (not fSharedImpl_.unique ());
                        // -- LGP 2015-01-10
                        return SharedByValue_State::eShared;
                }
            }
            template <typename TRAITS>
            inline bool SharedByValue<TRAITS>::unique () const
            {
                return fSharedImpl_.unique ();
            }
            template <typename TRAITS>
            inline unsigned int SharedByValue<TRAITS>::use_count () const
            {
                return fSharedImpl_.use_count ();
            }
            template <typename TRAITS>
            template <typename... COPY_ARGS>
            inline void SharedByValue<TRAITS>::Assure1Reference (COPY_ARGS&&... copyArgs)
            {
                if (not fSharedImpl_.unique ()) {
                    BreakReferences_ (forward<COPY_ARGS> (copyArgs)...);
                }
            }
            template <typename TRAITS>
            template <typename... COPY_ARGS>
            void SharedByValue<TRAITS>::BreakReferences_ (COPY_ARGS&&... copyArgs)
            {
                shared_ptr_type ptr2Clone{shared_impl_copier_type::Load (fSharedImpl_)}; // other thread could change this (if other thread accesses same envelope)
                // but this copy prevents the bare ptr from possibly becoming invalidated
                element_type* ptr = ptr2Clone.get ();
                RequireNotNull (ptr);
                /*
                 *      For a valid pointer that is reference counted and multiply shared,
                 *  make a copy of that pointer via our fCloner function, and assign
                 *  that cloned reference to this.
                 *
                 *      Note that by doing so, we remove any references to the current
                 *  item, and end up with our having the sole reference to the new copy of fPtr.
                 *
                 *      Since we will be cloning the given pointer, we assume(assert) that
                 *  it is non-nullptr.
                 */
                //Require (!SHARED_IMLP::unique ());    This is not NECESSARILY so. Another thread could have just released this pointer, in which case
                // the creation of a new object was pointless, but harmless, as the assignemnt should decrement to zero the old
                // value and it should go away.
                *this = SharedByValue<TRAITS> (fCopier_.Copy (*ptr, forward<COPY_ARGS> (copyArgs)...), fCopier_);

#if qDebug
                //Ensure (fSharedImpl_.unique ());
                // technically not 100% guarantied if two threads did this at the same time, but so rare interesting if ever triggered.
                // may need to lose this assert - maybe replace with #if qDebug DbgTrace
                if (not fSharedImpl_.unique ()) {
                    DbgTrace ("probably a bug, but not necessarily...");
                }
#endif
            }
        }
    }
}
#endif /*_Stroika_Foundation_Memory_SharedByValue_inl_*/
<commit_msg>shared_ptr<>::unique () now deprecated, so use use_count () == 1 instead<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2017.  All rights reserved
 */
#ifndef _Stroika_Foundation_Memory_SharedByValue_inl_
#define _Stroika_Foundation_Memory_SharedByValue_inl_ 1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */

#include "../Debug/Trace.h"

namespace Stroika {
    namespace Foundation {
        namespace Memory {

            /*
            ********************************************************************************
            ************** SharedByValue_CopyByFunction<T,SHARED_IMLP> *********************
            ********************************************************************************
            */
            template <typename T, typename SHARED_IMLP>
            inline SharedByValue_CopyByFunction<T, SHARED_IMLP>::SharedByValue_CopyByFunction (SHARED_IMLP (*copier) (const T&)) noexcept
                : fCopier (copier)
            {
                RequireNotNull (copier);
            }
            template <typename T, typename SHARED_IMLP>
            inline SHARED_IMLP SharedByValue_CopyByFunction<T, SHARED_IMLP>::Copy (const T& t) const
            {
                AssertNotNull (fCopier);
                return (*fCopier) (t);
            }

            /*
            ********************************************************************************
            *************** SharedByValue_CopyByDefault<T,SHARED_IMLP> *********************
            ********************************************************************************
            */
            template <typename T, typename SHARED_IMLP>
            inline SHARED_IMLP SharedByValue_CopyByDefault<T, SHARED_IMLP>::Copy (const T& t)
            {
                return SHARED_IMLP (new T (t));
            }

            /*
            ********************************************************************************
            ****** SharedByValue_CopySharedPtrExternallySynchronized<T,SHARED_IMLP> ********
            ********************************************************************************
            */
            template <typename T, typename SHARED_IMLP>
            inline SHARED_IMLP SharedByValue_CopySharedPtrExternallySynchronized<T, SHARED_IMLP>::Load (const SHARED_IMLP& copyFrom)
            {
                return copyFrom;
            }
            template <typename T, typename SHARED_IMLP>
            inline void SharedByValue_CopySharedPtrExternallySynchronized<T, SHARED_IMLP>::Store (SHARED_IMLP* storeTo, const SHARED_IMLP& o)
            {
                RequireNotNull (storeTo);
                *storeTo = o;
            }

            /*
            ********************************************************************************
            ********* SharedByValue_CopySharedPtrAtomicSynchronized<T,SHARED_IMLP> *********
            ********************************************************************************
            */
            template <typename T, typename SHARED_IMLP>
            inline SHARED_IMLP SharedByValue_CopySharedPtrAtomicSynchronized<T, SHARED_IMLP>::Load (const SHARED_IMLP& copyFrom)
            {
                return atomic_load (&copyFrom);
            }
            template <typename T, typename SHARED_IMLP>
            inline void SharedByValue_CopySharedPtrAtomicSynchronized<T, SHARED_IMLP>::Store (SHARED_IMLP* storeTo, const SHARED_IMLP& o)
            {
                RequireNotNull (storeTo);
                atomic_store (storeTo, o);
            }

            /*
            ********************************************************************************
            ****************************** SharedByValue<TRAITS> ***************************
            ********************************************************************************
            */
            template <typename TRAITS>
            inline SharedByValue<TRAITS>::SharedByValue () noexcept
                : fCopier_ (element_copier_type ())
                , fSharedImpl_ ()
            {
            }
            template <typename TRAITS>
            inline SharedByValue<TRAITS>::SharedByValue (nullptr_t n) noexcept
                : fCopier_ (element_copier_type ())
                , fSharedImpl_ ()
            {
            }
            template <typename TRAITS>
            inline SharedByValue<TRAITS>::SharedByValue (const SharedByValue<TRAITS>& from) noexcept
                : fCopier_ (from.fCopier_)
                , fSharedImpl_ (shared_impl_copier_type::Load (from.fSharedImpl_))
            {
            }
            template <typename TRAITS>
            inline SharedByValue<TRAITS>::SharedByValue (SharedByValue<TRAITS>&& from) noexcept
                : fCopier_ (from.fCopier_)
                , fSharedImpl_ (std::move (from.fSharedImpl_))
            {
            }
            template <typename TRAITS>
            inline SharedByValue<TRAITS>::SharedByValue (const shared_ptr_type& from, const element_copier_type& copier) noexcept
                : fCopier_ (copier)
                , fSharedImpl_ (shared_impl_copier_type::Load (from))
            {
            }
            template <typename TRAITS>
            inline SharedByValue<TRAITS>::SharedByValue (shared_ptr_type&& from, const element_copier_type&& copier) noexcept
                : fCopier_ (move (copier))
                , fSharedImpl_ (move (from))
            {
            }
            template <typename TRAITS>
            inline SharedByValue<TRAITS>::SharedByValue (element_type* from, const element_copier_type& copier)
                : fCopier_ (copier)
                , fSharedImpl_ (from)
            {
            }
            template <typename TRAITS>
            inline SharedByValue<TRAITS>& SharedByValue<TRAITS>::operator= (const SharedByValue<TRAITS>& rhs)
            {
                // If the pointers are the same, there is no need to copy, as the reference counts must also be the same,
                // and we can avoid the (common) and costly memory barrier
                if (fSharedImpl_.get () != rhs.fSharedImpl_.get ()) {
                    fCopier_ = rhs.fCopier_;
                    shared_impl_copier_type::Store (&fSharedImpl_, shared_impl_copier_type::Load (rhs.fSharedImpl_));
                }
                return *this;
            }
            template <typename TRAITS>
            inline SharedByValue<TRAITS>& SharedByValue<TRAITS>::operator= (SharedByValue<TRAITS>&& rhs)
            {
                // If the pointers are the same, there is no need to copy, as the reference counts must also be the same,
                // and we can avoid the (common) and costly memory barrier
                if (fSharedImpl_.get () != rhs.fSharedImpl_.get ()) {
                    fCopier_ = rhs.fCopier_;
                    // ASSUME if doing a move() then this doesn't need to be a multithread safe copy (from the source), since
                    // if its a temporary, you cannot have mulitple peopel referring to me
                    shared_impl_copier_type::Store (&fSharedImpl_, rhs.fSharedImpl_);
                }
                return *this;
            }
            template <typename TRAITS>
            inline SharedByValue<TRAITS>& SharedByValue<TRAITS>::operator= (const shared_ptr_type& from)
            {
                // If the pointers are the same, there is no need to copy, as the reference counts must also be the same,
                // and we can avoid the (common) and costly memory barrier
                if (fSharedImpl_.get () != from.get ()) {
                    shared_impl_copier_type::Store (&fSharedImpl_, shared_impl_copier_type::Load (from));
                }
                return *this;
            }
            template <typename TRAITS>
            inline SharedByValue<TRAITS>& SharedByValue<TRAITS>::operator= (shared_ptr_type&& from)
            {
                // If the pointers are the same, there is no need to copy, as the reference counts must also be the same,
                // and we can avoid the (common) and costly memory barrier
                if (fSharedImpl_.get () != from.get ()) {
                    // ASSUME if doing a move() then this doesn't need to be a multithread safe copy (from the source), since
                    // if its a temporary, you cannot have mulitple peopel referring to me
                    shared_impl_copier_type::Store (&fSharedImpl_, from);
                }
                return *this;
            }
            template <typename TRAITS>
            inline const typename SharedByValue<TRAITS>::element_type* SharedByValue<TRAITS>::get () const noexcept
            {
                return fSharedImpl_.get ();
            }
            template <typename TRAITS>
            template <typename... COPY_ARGS>
            inline typename SharedByValue<TRAITS>::element_type* SharedByValue<TRAITS>::get (COPY_ARGS&&... copyArgs)
            {
                element_type* ptr = fSharedImpl_.get ();
                /*
                 * For non-const pointing, we must clone ourselves (if there are
                 * extra referneces). If we are a nullptr pointer, nobody could actually
                 * rereference it anyhow, so don't bother with the Assure1Reference()
                 * in that case.
                 */
                if (ptr != nullptr) {
                    Assure1Reference (forward<COPY_ARGS> (copyArgs)...);
                    ptr = fSharedImpl_.get ();
                    EnsureNotNull (ptr);
                }
                return ptr;
            }
            template <typename TRAITS>
            inline const typename SharedByValue<TRAITS>::element_type* SharedByValue<TRAITS>::cget () const noexcept
            {
                return get ();
            }
            template <typename TRAITS>
            inline const typename SharedByValue<TRAITS>::element_type* SharedByValue<TRAITS>::operator-> () const
            {
                return fSharedImpl_.get ();
            }
            template <typename TRAITS>
            inline typename SharedByValue<TRAITS>::element_type* SharedByValue<TRAITS>::operator-> ()
            {
                return get ();
            }
            template <typename TRAITS>
            inline const typename SharedByValue<TRAITS>::element_type& SharedByValue<TRAITS>::operator* () const
            {
                const element_type* ptr = get ();
                EnsureNotNull (ptr);
                return *ptr;
            }
            template <typename TRAITS>
            inline typename SharedByValue<TRAITS>::element_type& SharedByValue<TRAITS>::operator* ()
            {
                /*
                 * For non-const dereferencing, we must clone ourselves (if there are
                 * extra referneces).
                 */
                Assure1Reference ();
                element_type* ptr = get ();
                EnsureNotNull (ptr);
                return *ptr;
            }
            template <typename TRAITS>
            inline bool SharedByValue<TRAITS>::operator== (const SharedByValue<TRAITS>& rhs) const
            {
                return fSharedImpl_ == rhs.fSharedImpl_;
            }
            template <typename TRAITS>
            inline bool SharedByValue<TRAITS>::operator!= (const SharedByValue<TRAITS>& rhs) const
            {
                return fSharedImpl_ != rhs.fSharedImpl_;
            }
            template <typename TRAITS>
            inline typename SharedByValue<TRAITS>::element_copier_type SharedByValue<TRAITS>::GetCopier () const
            {
                return fCopier_;
            }
            template <typename TRAITS>
            inline SharedByValue_State SharedByValue<TRAITS>::GetSharingState () const
            {
                switch (fSharedImpl_.use_count ()) {
                    case 0:
                        Assert (fSharedImpl_.get () == nullptr);
                        return SharedByValue_State::eNull;
                    case 1:
                        Assert (fSharedImpl_.get () != nullptr);
                        return SharedByValue_State::eSolo;
                    default:
                        Assert (fSharedImpl_.get () != nullptr);
                        //NOT NECESSARILY - cuz there is no lock
                        // between the use_count and this unique call, so another object could decrement its count
                        // and this could be that it was shared, but is no solo.
                        // Assert (not fSharedImpl_.unique ());
                        // -- LGP 2015-01-10
                        return SharedByValue_State::eShared;
                }
            }
            template <typename TRAITS>
            inline bool SharedByValue<TRAITS>::unique () const
            {
                return fSharedImpl_.use_count () == 1;
            }
            template <typename TRAITS>
            inline unsigned int SharedByValue<TRAITS>::use_count () const
            {
                return fSharedImpl_.use_count ();
            }
            template <typename TRAITS>
            template <typename... COPY_ARGS>
            inline void SharedByValue<TRAITS>::Assure1Reference (COPY_ARGS&&... copyArgs)
            {
                if (not fSharedImpl_.use_count () == 1) {
                    BreakReferences_ (forward<COPY_ARGS> (copyArgs)...);
                }
            }
            template <typename TRAITS>
            template <typename... COPY_ARGS>
            void SharedByValue<TRAITS>::BreakReferences_ (COPY_ARGS&&... copyArgs)
            {
                shared_ptr_type ptr2Clone{shared_impl_copier_type::Load (fSharedImpl_)}; // other thread could change this (if other thread accesses same envelope)
                // but this copy prevents the bare ptr from possibly becoming invalidated
                element_type* ptr = ptr2Clone.get ();
                RequireNotNull (ptr);
                /*
                 *      For a valid pointer that is reference counted and multiply shared,
                 *  make a copy of that pointer via our fCloner function, and assign
                 *  that cloned reference to this.
                 *
                 *      Note that by doing so, we remove any references to the current
                 *  item, and end up with our having the sole reference to the new copy of fPtr.
                 *
                 *      Since we will be cloning the given pointer, we assume(assert) that
                 *  it is non-nullptr.
                 */
                //Require (!SHARED_IMLP::unique ());    This is not NECESSARILY so. Another thread could have just released this pointer, in which case
                // the creation of a new object was pointless, but harmless, as the assignemnt should decrement to zero the old
                // value and it should go away.
                *this = SharedByValue<TRAITS> (fCopier_.Copy (*ptr, forward<COPY_ARGS> (copyArgs)...), fCopier_);

#if qDebug
                //Ensure (fSharedImpl_.unique ());
                // technically not 100% guarantied if two threads did this at the same time, but so rare interesting if ever triggered.
                // may need to lose this assert - maybe replace with #if qDebug DbgTrace
                if (not unique ()) {
                    DbgTrace ("probably a bug, but not necessarily...");
                }
#endif
            }
        }
    }
}
#endif /*_Stroika_Foundation_Memory_SharedByValue_inl_*/
<|endoftext|>


<commit_before>// -*- coding: us-ascii-unix -*-
// Copyright 2012 Lukas Kemmer
//
// 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
//
// 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 <cassert>
#include "text/utf8.hh"
#include "text/utf8-string.hh"

namespace faint{

static void throw_if_outside(const std::string& data, size_t pos){
  if (utf8::num_characters(data) <= pos){
    throw std::out_of_range("invalid string position");
  }
}

utf8_string::utf8_string(size_t n, const utf8_char& ch){
  for (size_t i = 0; i != n; i++){
    m_data += ch.str();
  }
}
utf8_string::utf8_string(const utf8_char& ch)
  : utf8_string(1, ch)
{}

utf8_string::utf8_string(const char* str)
  : m_data(str)
{}

utf8_string::utf8_string(const std::string& str)
  : m_data(str)
{}

utf8_char utf8_string::at(size_t pos) const{
  throw_if_outside(m_data, pos);
  return operator[](pos);
}

utf8_char utf8_string::back() const{
  assert(!m_data.empty());
  return operator[](size() - 1);
}

utf8_char utf8_string::front() const{
  assert(!m_data.empty());
  return operator[](0);
}

size_t utf8_string::bytes() const{
  return m_data.size();
}

void utf8_string::clear() {
  m_data.clear();
}

utf8_string utf8_string::substr(size_t pos, size_t n) const{
  throw_if_outside(m_data, pos);
  size_t startByte = utf8::char_num_to_byte_num_checked(pos, m_data);
  size_t numBytes = (n == utf8_string::npos) ?
    std::string::npos :
    utf8::char_num_to_byte_num_clamped(pos + n, m_data) - startByte;

  return utf8_string(m_data.substr(startByte, numBytes));
}

const char* utf8_string::c_str() const{
  return m_data.c_str();
}

const std::string& utf8_string::str() const{
  return m_data;
}

size_t utf8_string::size() const{
  return utf8::num_characters(m_data);
}

bool utf8_string::empty() const{
  return m_data.empty();
}

utf8_string& utf8_string::erase(size_t pos, size_t n){
  throw_if_outside(m_data, pos);

  size_t startByte = utf8::char_num_to_byte_num_clamped(pos, m_data);
  size_t numBytes = (n == npos ? npos :
    utf8::char_num_to_byte_num_clamped(pos + n, m_data) - startByte);
  m_data.erase(startByte, numBytes);
  return *this;
}

utf8_string& utf8_string::insert(size_t pos, const utf8_string& inserted){
  if (pos > utf8::num_characters(m_data)){
    throw std::out_of_range("invalid insertion index");
  }

  m_data.insert(utf8::char_num_to_byte_num_checked(pos, m_data), inserted.str());
  return *this;
}

utf8_string& utf8_string::insert(size_t pos, size_t num, const utf8_char& c){
  if (pos > utf8::num_characters(m_data)){
    throw std::out_of_range("invalid insertion index");
  }

  insert(pos, utf8_string(num, c));
  return *this;
}

utf8_char utf8_string::operator[](size_t i) const{
  size_t pos = utf8::char_num_to_byte_num_checked(i, m_data);
  size_t numBytes = faint::utf8::prefix_num_bytes(m_data[pos]);
  return utf8_char(m_data.substr(pos, numBytes));
}

size_t utf8_string::find(const utf8_char& ch, size_t start) const{
  // Since the leading byte has a unique pattern, using regular
  // std::string find should be OK, I think.
  size_t pos = m_data.find(ch.str(), utf8::char_num_to_byte_num_checked(start, m_data));
  if (pos == npos){
    return pos;
  }
  return utf8::byte_num_to_char_num(pos, m_data);
}

size_t utf8_string::rfind(const utf8_char& ch, size_t start) const{
  // Since the leading byte has a unique pattern, using regular
  // std::string rfind should be OK, I think.
  if (m_data.empty()){
    return npos;
  }

  size_t startByte = (start == npos) ? m_data.size() - 1 :
    utf8::char_num_to_byte_num_checked(start, m_data);
  size_t pos = m_data.rfind(ch.str(), startByte);
  if (pos == npos){
    return pos;
  }
  return pos == npos ? npos :
    utf8::byte_num_to_char_num(pos, m_data);
}

utf8_string& utf8_string::operator=(const utf8_string& other){
  if (&other == this){
    return *this;
  }
  m_data = other.m_data;
  return *this;

}
utf8_string& utf8_string::operator+=(const utf8_char& ch){
  m_data += ch.str();
  return *this;
}

utf8_string& utf8_string::operator+=(const utf8_string& str){
  m_data += str.str();
  return *this;
}

utf8_string operator+(const utf8_string& lhs, const utf8_char& rhs){
  return utf8_string(lhs.str() + rhs.str());
}

utf8_string operator+(const utf8_string& lhs, const utf8_string& rhs){
  return utf8_string(lhs.str() + rhs.str());
}

utf8_string operator+(const utf8_char& lhs, const utf8_string& rhs){
  return utf8_string(lhs.str() + rhs.str());
}

const size_t utf8_string::npos(std::string::npos);

bool utf8_string::operator<(const utf8_string& s) const{
  return m_data < s.m_data;
}

bool is_ascii(const utf8_string& s){
  const std::string& bytes = s.str();
  for (char ch : bytes){
    if (utf8::prefix_num_bytes(ch) != 1){
      return false;
    }
  }
  return true;
}

std::ostream& operator<<(std::ostream& o, const utf8_string& s){
  o << s.str();
  return o;
}

bool operator==(const utf8_string& lhs, const utf8_string& rhs){
  return lhs.str() == rhs.str();
}

bool operator!=(const utf8_string& lhs, const utf8_string& rhs){
  return !(lhs == rhs);
}

utf8_string_const_iterator begin(const utf8_string& s){
  return utf8_string_const_iterator(s, 0);
}

utf8_string_const_iterator end(const utf8_string& s){
  return utf8_string_const_iterator(s, s.size());
}

} // namespace
<commit_msg>Formatting.<commit_after>// -*- coding: us-ascii-unix -*-
// Copyright 2012 Lukas Kemmer
//
// 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
//
// 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 <cassert>
#include "text/utf8.hh"
#include "text/utf8-string.hh"

namespace faint{

static void throw_if_outside(const std::string& data, size_t pos){
  if (utf8::num_characters(data) <= pos){
    throw std::out_of_range("invalid string position");
  }
}

utf8_string::utf8_string(size_t n, const utf8_char& ch){
  for (size_t i = 0; i != n; i++){
    m_data += ch.str();
  }
}

utf8_string::utf8_string(const utf8_char& ch)
  : utf8_string(1, ch)
{}

utf8_string::utf8_string(const char* str)
  : m_data(str)
{}

utf8_string::utf8_string(const std::string& str)
  : m_data(str)
{}

utf8_char utf8_string::at(size_t pos) const{
  throw_if_outside(m_data, pos);
  return operator[](pos);
}

utf8_char utf8_string::back() const{
  assert(!m_data.empty());
  return operator[](size() - 1);
}

utf8_char utf8_string::front() const{
  assert(!m_data.empty());
  return operator[](0);
}

size_t utf8_string::bytes() const{
  return m_data.size();
}

void utf8_string::clear() {
  m_data.clear();
}

utf8_string utf8_string::substr(size_t pos, size_t n) const{
  throw_if_outside(m_data, pos);
  size_t startByte = utf8::char_num_to_byte_num_checked(pos, m_data);
  size_t numBytes = (n == utf8_string::npos) ?
    std::string::npos :
    utf8::char_num_to_byte_num_clamped(pos + n, m_data) - startByte;

  return utf8_string(m_data.substr(startByte, numBytes));
}

const char* utf8_string::c_str() const{
  return m_data.c_str();
}

const std::string& utf8_string::str() const{
  return m_data;
}

size_t utf8_string::size() const{
  return utf8::num_characters(m_data);
}

bool utf8_string::empty() const{
  return m_data.empty();
}

utf8_string& utf8_string::erase(size_t pos, size_t n){
  throw_if_outside(m_data, pos);

  size_t startByte = utf8::char_num_to_byte_num_clamped(pos, m_data);
  size_t numBytes = (n == npos ? npos :
    utf8::char_num_to_byte_num_clamped(pos + n, m_data) - startByte);
  m_data.erase(startByte, numBytes);
  return *this;
}

utf8_string& utf8_string::insert(size_t pos, const utf8_string& inserted){
  if (pos > utf8::num_characters(m_data)){
    throw std::out_of_range("invalid insertion index");
  }

  m_data.insert(utf8::char_num_to_byte_num_checked(pos, m_data), inserted.str());
  return *this;
}

utf8_string& utf8_string::insert(size_t pos, size_t num, const utf8_char& c){
  if (pos > utf8::num_characters(m_data)){
    throw std::out_of_range("invalid insertion index");
  }

  insert(pos, utf8_string(num, c));
  return *this;
}

utf8_char utf8_string::operator[](size_t i) const{
  size_t pos = utf8::char_num_to_byte_num_checked(i, m_data);
  size_t numBytes = faint::utf8::prefix_num_bytes(m_data[pos]);
  return utf8_char(m_data.substr(pos, numBytes));
}

size_t utf8_string::find(const utf8_char& ch, size_t start) const{
  // Since the leading byte has a unique pattern, using regular
  // std::string find should be OK, I think.
  size_t pos = m_data.find(ch.str(),
    utf8::char_num_to_byte_num_checked(start, m_data));
  if (pos == npos){
    return pos;
  }
  return utf8::byte_num_to_char_num(pos, m_data);
}

size_t utf8_string::rfind(const utf8_char& ch, size_t start) const{
  // Since the leading byte has a unique pattern, using regular
  // std::string rfind should be OK, I think.
  if (m_data.empty()){
    return npos;
  }

  size_t startByte = (start == npos) ? m_data.size() - 1 :
    utf8::char_num_to_byte_num_checked(start, m_data);
  size_t pos = m_data.rfind(ch.str(), startByte);
  if (pos == npos){
    return pos;
  }
  return pos == npos ? npos :
    utf8::byte_num_to_char_num(pos, m_data);
}

utf8_string& utf8_string::operator=(const utf8_string& other){
  if (&other == this){
    return *this;
  }
  m_data = other.m_data;
  return *this;
}

utf8_string& utf8_string::operator+=(const utf8_char& ch){
  m_data += ch.str();
  return *this;
}

utf8_string& utf8_string::operator+=(const utf8_string& str){
  m_data += str.str();
  return *this;
}

utf8_string operator+(const utf8_string& lhs, const utf8_char& rhs){
  return utf8_string(lhs.str() + rhs.str());
}

utf8_string operator+(const utf8_string& lhs, const utf8_string& rhs){
  return utf8_string(lhs.str() + rhs.str());
}

utf8_string operator+(const utf8_char& lhs, const utf8_string& rhs){
  return utf8_string(lhs.str() + rhs.str());
}

const size_t utf8_string::npos(std::string::npos);

bool utf8_string::operator<(const utf8_string& s) const{
  return m_data < s.m_data;
}

bool is_ascii(const utf8_string& s){
  const std::string& bytes = s.str();
  for (char ch : bytes){
    if (utf8::prefix_num_bytes(ch) != 1){
      return false;
    }
  }
  return true;
}

std::ostream& operator<<(std::ostream& o, const utf8_string& s){
  o << s.str();
  return o;
}

bool operator==(const utf8_string& lhs, const utf8_string& rhs){
  return lhs.str() == rhs.str();
}

bool operator!=(const utf8_string& lhs, const utf8_string& rhs){
  return !(lhs == rhs);
}

utf8_string_const_iterator begin(const utf8_string& s){
  return utf8_string_const_iterator(s, 0);
}

utf8_string_const_iterator end(const utf8_string& s){
  return utf8_string_const_iterator(s, s.size());
}

} // namespace
<|endoftext|>


<commit_before>#include <gtest/gtest.h>

#include <stdio.h>
#include <atomic>

#include <util/blockstore.h>

using namespace std;

namespace util {

class FakeBlockGuardTest : public ::testing::Test {
protected:
	unique_ptr<BlockGuard> block1 = make_unique<FakeBlockGuard<1>>();
	unique_ptr<BlockGuard> block2 = make_unique<FakeBlockGuard<2>>();
	unique_ptr<BlockGuard> block4 = make_unique<FakeBlockGuard<4>>();
};

TEST_F(FakeBlockGuardTest, BlockSize1) {
	ASSERT_EQ(1, block1->blockSize());
}

TEST_F(FakeBlockGuardTest, BlockSize2) {
	ASSERT_EQ(2, block2->blockSize());
}

TEST_F(FakeBlockGuardTest, BlockSize4) {
	ASSERT_EQ(4, block4->blockSize());
}

TEST_F(FakeBlockGuardTest, InitValue1) {
	uint8_t val;
	block1->load(&val);
	ASSERT_EQ(0, val);
}

TEST_F(FakeBlockGuardTest, InitValue2) {
	uint16_t val;
	block2->load(&val);
	ASSERT_EQ(0, val);
}

TEST_F(FakeBlockGuardTest, InitValue4) {
	uint32_t val;
	block4->load(&val);
	ASSERT_EQ(0, val);
}

TEST_F(FakeBlockGuardTest, Store1) {
	const uint8_t store = 0xbd;
	uint8_t load;
	block1->store(&store);
	block1->load(&load);
	ASSERT_EQ(store, load);
}

TEST_F(FakeBlockGuardTest, Store2) {
	const uint16_t store = 0xa55a;
	uint16_t load;
	block2->store(&store);
	block2->load(&load);
	ASSERT_EQ(store, load);
}

TEST_F(FakeBlockGuardTest, Store4) {
	const uint32_t store = 0xa555aaa5;
	uint32_t load;
	block4->store(&store);
	block4->load(&load);
	ASSERT_EQ(store, load);
}

class AtomicBlockStoreTest : public ::testing::Test {
protected:
	AtomicBlockStore store;
};

TEST_F(AtomicBlockStoreTest, BlockSize) {
	store.blockSize();
}

// platform dependent -- least common denominator between 32 bit ARM and x86_64
TEST_F(AtomicBlockStoreTest, BlockSizeIsAtomic) {
	ASSERT_EQ(8, store.blockSize());
	atomic<double> v1;

	struct Foo {
		int32_t x, y;
	};
	atomic<Foo> v2;

	ASSERT_TRUE(atomic_is_lock_free(&v1));
	ASSERT_TRUE(atomic_is_lock_free(&v2));
}

TEST_F(AtomicBlockStoreTest, Length) {
	ASSERT_EQ(0, store.length());
}

TEST_F(AtomicBlockStoreTest, AllocBlock) {
	store.allocBlock();
}

TEST_F(AtomicBlockStoreTest, AllocationIncreasesLength) {
	store.allocBlock();
	ASSERT_EQ(1, store.length());
	store.allocBlock();
	ASSERT_EQ(2, store.length());
}

class AtomicBlockStoreTest2 : public AtomicBlockStoreTest {
protected:
	size_t key1, key2;

	AtomicBlockStoreTest2() {
		key1 = store.allocBlock();
		key2 = store.allocBlock();
	}
};

// assumes blockSize
TEST_F(AtomicBlockStoreTest2, InitValue) {
	const uint64_t init{};
	uint64_t val;

	store.load(key1, &val);
	ASSERT_EQ(init, val);
	store.load(key2, &val);
	ASSERT_EQ(init, val);
}

// assumes blockSize
TEST_F(AtomicBlockStoreTest2, Store) {
	const double test1 = 3.3333, test2 = 42.4242;
	double val;

	store.store(key1, &test1);
	store.store(key2, &test2);

	store.load(key1, &val);
	ASSERT_EQ(test1, val);

	store.load(key2, &val);
	ASSERT_EQ(test2, val);
}

// assumes blockSize
TEST_F(AtomicBlockStoreTest, LoadThrowsAtInvalidKey) {
	uint64_t val;
	ASSERT_THROW(store.load(0, &val), out_of_range);
	ASSERT_THROW(store.load(42, &val), out_of_range);
}

// assumes blockSize
TEST_F(AtomicBlockStoreTest, StoreThrowsAtInvalidKey) {
	uint64_t val;
	ASSERT_THROW(store.store(0, &val), out_of_range);
	ASSERT_THROW(store.store(42, &val), out_of_range);
}

// freeing would require bookkeeping of allocated blocks -- initial implementation can get by without it
// TODO delete this test and comment in following tests after implementing freeBlock()
TEST_F(AtomicBlockStoreTest, FreeBlockThrows) {
	auto key = store.allocBlock();
	ASSERT_THROW(store.freeBlock(key), logic_error);
}

/*
TEST_F(AtomicBlockStoreTest, FreeBlock) {
	auto key = store.allocBlock();
	store.freeBlock(key);
}

TEST_F(AtomicBlockStoreTest, FreeingDecreasesLength) {
	auto key1 = store.allocBlock();
	auto key2 = store.allocBlock();
	store.freeBlock(key1);
	ASSERT_EQ(1, store.length());
	store.freeBlock(key2);
	ASSERT_EQ(0, store.length());
}
*/

TEST_F(AtomicBlockStoreTest, Capacity) {
	store.capacity();
}

TEST_F(AtomicBlockStoreTest, CapacityIsNonZeroAfterAllocation) {
	store.allocBlock();
	ASSERT_LT(0, store.capacity());
}

TEST_F(AtomicBlockStoreTest, SetCapacity) {
	ASSERT_GT(100, store.capacity());
	store.setCapacity(100);
	ASSERT_LE(100, store.capacity());
}

TEST_F(AtomicBlockStoreTest, SettingCapacityBelowLengthThrows) {
	store.allocBlock();
	ASSERT_THROW(store.setCapacity(0), length_error);
}

} // namespace
<commit_msg>Add missing include<commit_after>#include <gtest/gtest.h>

#include <stdio.h>
#include <memory>
#include <atomic>

#include <util/blockstore.h>

using namespace std;

namespace util {

class FakeBlockGuardTest : public ::testing::Test {
protected:
	unique_ptr<BlockGuard> block1 = make_unique<FakeBlockGuard<1>>();
	unique_ptr<BlockGuard> block2 = make_unique<FakeBlockGuard<2>>();
	unique_ptr<BlockGuard> block4 = make_unique<FakeBlockGuard<4>>();
};

TEST_F(FakeBlockGuardTest, BlockSize1) {
	ASSERT_EQ(1, block1->blockSize());
}

TEST_F(FakeBlockGuardTest, BlockSize2) {
	ASSERT_EQ(2, block2->blockSize());
}

TEST_F(FakeBlockGuardTest, BlockSize4) {
	ASSERT_EQ(4, block4->blockSize());
}

TEST_F(FakeBlockGuardTest, InitValue1) {
	uint8_t val;
	block1->load(&val);
	ASSERT_EQ(0, val);
}

TEST_F(FakeBlockGuardTest, InitValue2) {
	uint16_t val;
	block2->load(&val);
	ASSERT_EQ(0, val);
}

TEST_F(FakeBlockGuardTest, InitValue4) {
	uint32_t val;
	block4->load(&val);
	ASSERT_EQ(0, val);
}

TEST_F(FakeBlockGuardTest, Store1) {
	const uint8_t store = 0xbd;
	uint8_t load;
	block1->store(&store);
	block1->load(&load);
	ASSERT_EQ(store, load);
}

TEST_F(FakeBlockGuardTest, Store2) {
	const uint16_t store = 0xa55a;
	uint16_t load;
	block2->store(&store);
	block2->load(&load);
	ASSERT_EQ(store, load);
}

TEST_F(FakeBlockGuardTest, Store4) {
	const uint32_t store = 0xa555aaa5;
	uint32_t load;
	block4->store(&store);
	block4->load(&load);
	ASSERT_EQ(store, load);
}

class AtomicBlockStoreTest : public ::testing::Test {
protected:
	AtomicBlockStore store;
};

TEST_F(AtomicBlockStoreTest, BlockSize) {
	store.blockSize();
}

// platform dependent -- least common denominator between 32 bit ARM and x86_64
TEST_F(AtomicBlockStoreTest, BlockSizeIsAtomic) {
	ASSERT_EQ(8, store.blockSize());
	atomic<double> v1;

	struct Foo {
		int32_t x, y;
	};
	atomic<Foo> v2;

	ASSERT_TRUE(atomic_is_lock_free(&v1));
	ASSERT_TRUE(atomic_is_lock_free(&v2));
}

TEST_F(AtomicBlockStoreTest, Length) {
	ASSERT_EQ(0, store.length());
}

TEST_F(AtomicBlockStoreTest, AllocBlock) {
	store.allocBlock();
}

TEST_F(AtomicBlockStoreTest, AllocationIncreasesLength) {
	store.allocBlock();
	ASSERT_EQ(1, store.length());
	store.allocBlock();
	ASSERT_EQ(2, store.length());
}

class AtomicBlockStoreTest2 : public AtomicBlockStoreTest {
protected:
	size_t key1, key2;

	AtomicBlockStoreTest2() {
		key1 = store.allocBlock();
		key2 = store.allocBlock();
	}
};

// assumes blockSize
TEST_F(AtomicBlockStoreTest2, InitValue) {
	const uint64_t init{};
	uint64_t val;

	store.load(key1, &val);
	ASSERT_EQ(init, val);
	store.load(key2, &val);
	ASSERT_EQ(init, val);
}

// assumes blockSize
TEST_F(AtomicBlockStoreTest2, Store) {
	const double test1 = 3.3333, test2 = 42.4242;
	double val;

	store.store(key1, &test1);
	store.store(key2, &test2);

	store.load(key1, &val);
	ASSERT_EQ(test1, val);

	store.load(key2, &val);
	ASSERT_EQ(test2, val);
}

// assumes blockSize
TEST_F(AtomicBlockStoreTest, LoadThrowsAtInvalidKey) {
	uint64_t val;
	ASSERT_THROW(store.load(0, &val), out_of_range);
	ASSERT_THROW(store.load(42, &val), out_of_range);
}

// assumes blockSize
TEST_F(AtomicBlockStoreTest, StoreThrowsAtInvalidKey) {
	uint64_t val;
	ASSERT_THROW(store.store(0, &val), out_of_range);
	ASSERT_THROW(store.store(42, &val), out_of_range);
}

// freeing would require bookkeeping of allocated blocks -- initial implementation can get by without it
// TODO delete this test and comment in following tests after implementing freeBlock()
TEST_F(AtomicBlockStoreTest, FreeBlockThrows) {
	auto key = store.allocBlock();
	ASSERT_THROW(store.freeBlock(key), logic_error);
}

/*
TEST_F(AtomicBlockStoreTest, FreeBlock) {
	auto key = store.allocBlock();
	store.freeBlock(key);
}

TEST_F(AtomicBlockStoreTest, FreeingDecreasesLength) {
	auto key1 = store.allocBlock();
	auto key2 = store.allocBlock();
	store.freeBlock(key1);
	ASSERT_EQ(1, store.length());
	store.freeBlock(key2);
	ASSERT_EQ(0, store.length());
}
*/

TEST_F(AtomicBlockStoreTest, Capacity) {
	store.capacity();
}

TEST_F(AtomicBlockStoreTest, CapacityIsNonZeroAfterAllocation) {
	store.allocBlock();
	ASSERT_LT(0, store.capacity());
}

TEST_F(AtomicBlockStoreTest, SetCapacity) {
	ASSERT_GT(100, store.capacity());
	store.setCapacity(100);
	ASSERT_LE(100, store.capacity());
}

TEST_F(AtomicBlockStoreTest, SettingCapacityBelowLengthThrows) {
	store.allocBlock();
	ASSERT_THROW(store.setCapacity(0), length_error);
}

} // namespace
<|endoftext|>


<commit_before>#include <routingkit/vector_io.h>
#include <routingkit/permutation.h>
#include <routingkit/inverse_vector.h>
#include <routingkit/contraction_hierarchy.h>
#include <routingkit/min_max.h>
#include <routingkit/timer.h>

#include <iostream>
#include <stdexcept>
#include <vector>

using namespace RoutingKit;
using namespace std;

int main(int argc, char*argv[]){

	try{
		string first_out_file;
		string head_file;
		string weight_file;
		string ch_file;
		string source_file;
		string target_file;
		string distance_file;

		if(argc != 8){
			cerr << argv[0] << " first_out head weight_file ch_file source_file target_file distance_file" << endl;
			return 1;
		}else{
			first_out_file = argv[1];
			head_file = argv[2];
			weight_file = argv[3];
			ch_file = argv[4];
			source_file = argv[5];
			target_file = argv[6];
			distance_file = argv[7];
		}

		cout << "Loading Graph ... " << flush;

		auto first_out = load_vector<unsigned>(first_out_file);
		auto tail = invert_inverse_vector(first_out);
		auto head = load_vector<unsigned>(head_file);
		auto weight = load_vector<unsigned>(weight_file);

		cout << "done" << endl;

		cout << "Loading Contraction Hierarchy ... " << flush;

		ContractionHierarchy ch = ContractionHierarchy::load_file(ch_file);

		cout << "done" << endl;

		cout << "Loading test queries ... " << flush;

		auto source = load_vector<unsigned>(source_file);
		auto target = load_vector<unsigned>(target_file);
		auto ref_distance = load_vector<unsigned>(distance_file);

		cout << "done" << endl;

		const unsigned query_count = source.size();

		cout << "Loaded " << query_count << " test queries" << endl;

		vector<unsigned>distance(query_count);
		ContractionHierarchyQuery ch_query(ch);

		cout << "Running test queries ... " << flush;

		long long dist_time_max = 0;
		long long dist_time_sum = 0;

		long long arc_path_time_max = 0;
		long long arc_path_time_sum = 0;

		long long node_path_time_max = 0;
		long long node_path_time_sum = 0;

		for(unsigned i=0; i<query_count; ++i){

			try{
				long long time = -get_micro_time();
				ch_query.reset().add_source(source[i]).add_target(target[i]).run();
				time += get_micro_time();

				dist_time_max = std::max(dist_time_max, time);
				dist_time_sum += time;

				if(ch_query.get_distance() != ref_distance[i])
					throw runtime_error("Distance query is wrong");

				time = -get_micro_time();
				auto arc_path = ch_query.get_arc_path();
				time += get_micro_time();

				arc_path_time_max = std::max(arc_path_time_max, time);
				arc_path_time_sum += time;

				time = -get_micro_time();
				auto node_path = ch_query.get_node_path();
				time += get_micro_time();

				node_path_time_max = std::max(node_path_time_max, time);
				node_path_time_sum += time;

				if(source[i] == target[i]){
					if(!arc_path.empty())
						throw runtime_error("if s == t then the path should be empty");
				}else{
					if(arc_path.empty()){
						if(ref_distance[i] != inf_weight)
							throw runtime_error("no path found even though one exists");
					}else{
						if(ch_query.get_used_source() != source[i])
							throw runtime_error("get_used_source returns wrong value");
						if(ch_query.get_used_target() != target[i])
							throw runtime_error("get_used_target returns wrong value");

						if(tail[arc_path.front()] != source[i])
							throw runtime_error("path does not start at the source");
						if(head[arc_path.back()] != target[i])
							throw runtime_error("path does not end at the target");
						for(unsigned j=0; j<arc_path.size()-1; ++j)
							if(head[arc_path[j]] != tail[arc_path[j+1]])
								throw runtime_error("path is not continous");
						unsigned distance = 0;
						for(auto a:arc_path)
							distance += weight[a];
						if(distance != ref_distance[i])
							throw runtime_error("path has the wrong length");

						if(arc_path.size()+1 != node_path.size())
							throw runtime_error("get_node_path path has wrong number of nodes");
						if(node_path.front() != source[i])
							throw runtime_error("get_node_path path does not start at source");
						for(unsigned j=0; j<arc_path.size(); ++j)
							if(head[arc_path[j]] != node_path[j+1])
								throw runtime_error("get_node_path path has a different node than induced by the arc path.");
					}
				}
			}catch(std::runtime_error&err){
				throw std::runtime_error("during query "+std::to_string(i)+" : "+err.what());
			}
		}

		cout << "done" << endl;

		cout << "max dist running time : " << dist_time_max << "musec" << endl;
		cout << "avg dist running time : " << dist_time_sum/query_count << "musec" << endl;

		cout << "max node path running time : " << node_path_time_max << "musec" << endl;
		cout << "avg node path running time : " << node_path_time_sum/query_count << "musec" << endl;

		cout << "max arc path running time : " << arc_path_time_max << "musec" << endl;
		cout << "avg arc path running time : " << arc_path_time_sum/query_count << "musec" << endl;

	}catch(exception&err){
		cerr << "Stopped on exception : " << err.what() << endl;
		return 1;
	}
	return 0;
}

<commit_msg>added better error reporting to test_contraction_hierarchy_path_query<commit_after>#include <routingkit/vector_io.h>
#include <routingkit/permutation.h>
#include <routingkit/inverse_vector.h>
#include <routingkit/contraction_hierarchy.h>
#include <routingkit/min_max.h>
#include <routingkit/timer.h>

#include <iostream>
#include <stdexcept>
#include <vector>

using namespace RoutingKit;
using namespace std;

int main(int argc, char*argv[]){

	try{
		string first_out_file;
		string head_file;
		string weight_file;
		string ch_file;
		string source_file;
		string target_file;
		string distance_file;

		if(argc != 8){
			cerr << argv[0] << " first_out head weight_file ch_file source_file target_file distance_file" << endl;
			return 1;
		}else{
			first_out_file = argv[1];
			head_file = argv[2];
			weight_file = argv[3];
			ch_file = argv[4];
			source_file = argv[5];
			target_file = argv[6];
			distance_file = argv[7];
		}

		cout << "Loading Graph ... " << flush;

		auto first_out = load_vector<unsigned>(first_out_file);
		auto tail = invert_inverse_vector(first_out);
		auto head = load_vector<unsigned>(head_file);
		auto weight = load_vector<unsigned>(weight_file);

		cout << "done" << endl;

		cout << "Loading Contraction Hierarchy ... " << flush;

		ContractionHierarchy ch = ContractionHierarchy::load_file(ch_file);

		cout << "done" << endl;

		cout << "Loading test queries ... " << flush;

		auto source = load_vector<unsigned>(source_file);
		auto target = load_vector<unsigned>(target_file);
		auto ref_distance = load_vector<unsigned>(distance_file);

		cout << "done" << endl;

		const unsigned query_count = source.size();

		cout << "Loaded " << query_count << " test queries" << endl;

		vector<unsigned>distance(query_count);
		ContractionHierarchyQuery ch_query(ch);

		cout << "Running test queries ... " << flush;

		long long dist_time_max = 0;
		long long dist_time_sum = 0;

		long long arc_path_time_max = 0;
		long long arc_path_time_sum = 0;

		long long node_path_time_max = 0;
		long long node_path_time_sum = 0;

		for(unsigned i=0; i<query_count; ++i){

			try{
				long long time = -get_micro_time();
				ch_query.reset().add_source(source[i]).add_target(target[i]).run();
				time += get_micro_time();

				dist_time_max = std::max(dist_time_max, time);
				dist_time_sum += time;

				if(ch_query.get_distance() != ref_distance[i])
					throw runtime_error("Distance query "+std::to_string(i)+" is wrong; reference = "+std::to_string(ref_distance[i])+" computed = "+std::to_string(ch_query.get_distance()));

				time = -get_micro_time();
				auto arc_path = ch_query.get_arc_path();
				time += get_micro_time();

				arc_path_time_max = std::max(arc_path_time_max, time);
				arc_path_time_sum += time;

				time = -get_micro_time();
				auto node_path = ch_query.get_node_path();
				time += get_micro_time();

				node_path_time_max = std::max(node_path_time_max, time);
				node_path_time_sum += time;

				if(source[i] == target[i]){
					if(!arc_path.empty())
						throw runtime_error("if s == t then the path should be empty");
				}else{
					if(arc_path.empty()){
						if(ref_distance[i] != inf_weight)
							throw runtime_error("no path found even though one exists");
					}else{
						if(ch_query.get_used_source() != source[i])
							throw runtime_error("get_used_source returns wrong value");
						if(ch_query.get_used_target() != target[i])
							throw runtime_error("get_used_target returns wrong value");

						if(tail[arc_path.front()] != source[i])
							throw runtime_error("path does not start at the source");
						if(head[arc_path.back()] != target[i])
							throw runtime_error("path does not end at the target");
						for(unsigned j=0; j<arc_path.size()-1; ++j)
							if(head[arc_path[j]] != tail[arc_path[j+1]])
								throw runtime_error("path is not continous");
						unsigned distance = 0;
						for(auto a:arc_path)
							distance += weight[a];
						if(distance != ref_distance[i])
							throw runtime_error("path has wrong length; reference = "+std::to_string(ref_distance[i])+" computed = "+std::to_string(distance));

						if(arc_path.size()+1 != node_path.size())
							throw runtime_error("get_node_path path has wrong number of nodes");
						if(node_path.front() != source[i])
							throw runtime_error("get_node_path path does not start at source");
						for(unsigned j=0; j<arc_path.size(); ++j)
							if(head[arc_path[j]] != node_path[j+1])
								throw runtime_error("get_node_path path has a different node than induced by the arc path.");
					}
				}
			}catch(std::runtime_error&err){
				throw std::runtime_error("during query "+std::to_string(i)+" : "+err.what());
			}
		}

		cout << "done" << endl;

		cout << "max dist running time : " << dist_time_max << "musec" << endl;
		cout << "avg dist running time : " << dist_time_sum/query_count << "musec" << endl;

		cout << "max node path running time : " << node_path_time_max << "musec" << endl;
		cout << "avg node path running time : " << node_path_time_sum/query_count << "musec" << endl;

		cout << "max arc path running time : " << arc_path_time_max << "musec" << endl;
		cout << "avg arc path running time : " << arc_path_time_sum/query_count << "musec" << endl;

	}catch(exception&err){
		cerr << "Stopped on exception : " << err.what() << endl;
		return 1;
	}
	return 0;
}

<|endoftext|>


<commit_before>/*
  MusicXML Library
  Copyright (C) Grame 2006-2013

  This Source Code Form is subject to the terms of the Mozilla Public
  License, v. 2.0. If a copy of the MPL was not distributed with this
  file, You can obtain one at http://mozilla.org/MPL/2.0/.

  Grame Research Laboratory, 11, cours de Verdun Gensoul 69002 Lyon - France
  research@grame.fr
*/

#include <iostream>
#include "notevisitor.h"

//#define PRINTNOTE

using namespace std;

namespace MusicXML2 {

//________________________________________________________________________
ostream& operator<< (ostream& os, const notevisitor& elt)
{
    elt.print(os);
    return os;
}

//________________________________________________________________________
notevisitor::notevisitor()
	: fInNote(false)
{
	reset();
}

//________________________________________________________________________
void notevisitor::reset ()
{
	fGrace = fCue = fChord = fFermata = false;
	fType		= kUndefinedType;
	fTie		= StartStop::undefined;
	fDuration	= 0;
	fDots		= 0;
	fDynamics	= kUndefinedDynamics;
	fStaff		= kUndefinedStaff;
	fVoice		= kUndefinedVoice;
	fAlter = 0.f;
	fOctave = 0;
	fStem = 0;
	fAccent = 0;
	fStrongAccent = 0;
	fStaccato = 0;
    fTenuto = 0;
	fTrill = 0;
    fMordent = 0;
    fInvertedMordent = 0;
	fBreathMark = 0;
	fTimeModification.set(1,1);
#ifdef VC6
	fStep = "";
	fInstrument = "";
#else
	fStep.clear();
	fInstrument.clear();
#endif
	fTied.clear();
	fSlur.clear();
	fBeam.clear();
    fTuplet.clear();

    fLyric.clear();
    fSyllabic = "";
    fLyricText="";
}

//________________________________________________________________________
string notevisitor::i2step(int i)
{
	switch (i) {
		case notevisitor::A:	return "A";
		case notevisitor::B:	return "B";
		case notevisitor::C:	return "C";
		case notevisitor::D:	return "D";
		case notevisitor::E:	return "E";
		case notevisitor::F:	return "F";
		case notevisitor::G:	return "G";
	}
	return "";
}

//________________________________________________________________________
int notevisitor::step2i(const std::string& step)
{
	if (step.size() != 1) return -1;
	switch (step[0]) {
		case 'A':	return notevisitor::A;
		case 'B':	return notevisitor::B;
		case 'C':	return notevisitor::C;
		case 'D':	return notevisitor::D;
		case 'E':	return notevisitor::E;
		case 'F':	return notevisitor::F;
		case 'G':	return notevisitor::G;
	}
	return -1;
}

//________________________________________________________________________
float notevisitor::getMidiPitch() const
{
    if (fType == kPitched) {
		int step = step2i(getStep());
		if (step >= 0) {
			short step2pitch [] = { 0, 2, 4, 5, 7, 9, 11 };
			float pitch = (getOctave() * 12.f) + step2pitch[step];
			return pitch + getAlter();
		}
	}
    return -1;
}

//________________________________________________________________________
void notevisitor::visitStart ( S_time_modification& elt )
{
	fTimeModification.set ( elt->getIntValue(k_normal_notes,1), elt->getIntValue(k_actual_notes,1));
}

//________________________________________________________________________
void notevisitor::visitStart ( S_tie& elt )
{
	const string& value = elt->getAttributeValue("type");
	fTie = StartStop::type(fTie | StartStop::xml(value));
/*
	if (value == "start") fTie |= kTieStart;
	else if (value == "stop") fTie |= kTieStop;
*/
}

//________________________________________________________________________
void notevisitor::print (ostream& out) const
{
		if (isGrace()) out << "grace ";
		if (isCue())   out << "cue ";
		int type = getType();
		if (type == kUndefinedType)
			out << "type undefined";
		else if (type == kUnpitched) {
			out << "unpitched note - duration " << getDuration() << " ";
		}
		else if (type == kRest) {
			out << "rest - duration " << getDuration() << " ";
		}
		else if (type == kPitched) {
			out << "note " << getStep();
			int alter = int(getAlter());
			float diff = getAlter() - alter;
			if (diff >= 0.5) alter++;
			else if (diff <= -0.5) alter--;
			while (alter < 0) { out << 'b'; alter++; }
			while (alter > 0) { out << '#'; alter--; }
			out << getOctave() << " (" << getMidiPitch() << ")";
			out << " - duration " << getDuration() << " ";
		}
		else out << "unknown type " <<  type << " ";
		if (inChord())	out << "in chord ";
		if (getTie() & StartStop::start)	out << "- tie start ";
		if (getTie() & StartStop::stop)	out << "- tie stop ";
		string instr = getInstrument();
		if (!instr.empty()) out << "instrument " << instr << " ";
		if (getDynamics() >= 0) out << "dynamics " << getDynamics();
}

    //________________________________________________________________________
    void notevisitor::visitStart ( S_lyric& elt )
    {
        fLyric.push_back (elt);
        // get attributes
        float posy = elt->getAttributeFloatValue("default-y", 0) + elt->getAttributeFloatValue("relative-y", 0);
        fLyricsDy = (posy / 10) * 2;   // convert to half spaces
        fLyricsDy += 8;		  // anchor point convertion (defaults to upper line in xml)

        /// Get content information:
        fSyllabic = elt->getValue(k_syllabic);
        fLyricText = elt->getValue(k_text);
    }

//________________________________________________________________________
void notevisitor::visitStart ( S_note& elt )
{
	fInNote = true;
	reset();
	fDynamics = elt->getAttributeLongValue("dynamics", kUndefinedDynamics);
}

//________________________________________________________________________
void notevisitor::visitEnd ( S_note& elt )
{
#ifdef PRINTNOTE
	cout << *this << endl;
#endif
}

    //________________________________________________________________________
    float notevisitor::getRestFormatDy ( string fCurClef ) const
    {
        float restFormatDy = 0.0;
        //string display_step = elt->getValue(k_display_step);
        //int display_octave = elt->getIntValue(k_display_octave, 0.0);
        string display_step = fStep;
        int display_octave = fOctave;

        // Now convert to half-space! We'd need the Current Clef info for this!
        if (display_octave)
        {
            // dy 0 is B4, dy=-6 for C4, -4 for E4, -2 for G4 ;
            // D5-> +2, F5 -> +4
            switch (display_step[0]) {
                case 'A':
                    switch (display_octave) {
                        case 4:
                            restFormatDy = -1.0;
                            break;
                        case 5:
                            restFormatDy = 6.0;
                            break;

                        case 3:
                            if (fCurClef == "G")
                                restFormatDy = -8.0;
                            else if (fCurClef == "F")
                                restFormatDy = 4.0;
                            break;

                        // treating F clef directly!
                        case 2:
                            restFormatDy = -3.0;
                            break;
                        case 1:
                            restFormatDy = -10.0;
                            break;

                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;

                case 'B':
                    switch (display_octave) {
                        case 4:
                            restFormatDy = 0.0;
                            break;
                        case 5:
                            restFormatDy = 7.0;
                            break;

                        case 3:
                            if (fCurClef == "G")
                                restFormatDy = -7.0;
                            else if (fCurClef == "F")
                                restFormatDy = 5.0;
                            break;
                        // F clef:
                        case 2:
                            restFormatDy = -2.0;
                            break;
                        case 1:
                            restFormatDy = -9.0;
                            break;

                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;
                case 'C':
                    switch (display_octave) {
                        case 4:
                            if (fCurClef == "G")
                                restFormatDy = -6.0;
                            else if (fCurClef == "F")
                                restFormatDy = 6.0;
                            break;
                        case 5:
                            restFormatDy = 1.0;
                            break;
                        case 6:
                            restFormatDy = 8.0;
                            break;
                        // F clef:
                        case 3:
                            restFormatDy = -1.0;
                            break;
                        case 2:
                            restFormatDy = -8.0;
                            break;
                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;

                case 'D':
                    switch (display_octave) {
                        case 4:
                            if (fCurClef == "G")
                                restFormatDy = -5.0;
                            else if (fCurClef == "F")
                                restFormatDy = 7.0;
                            break;
                        case 5:
                            restFormatDy = 2.0;
                            break;
                        // F clef:
                        case 3:
                            restFormatDy = 0.0;
                            break;
                        case 2:
                            restFormatDy = -7.0;
                            break;

                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;
                case 'E':
                    switch (display_octave) {
                        case 4:
                            if (fCurClef == "G")
                                restFormatDy = -4.0;
                            else if (fCurClef == "F")
                                restFormatDy = 8.0;
                            break;
                        case 5:
                            restFormatDy = 3.0;
                            break;
                        case 6:
                            restFormatDy = 10.0;
                            break;
                        // F clef:
                        case 3:
                            restFormatDy = 1.0;
                            break;
                        case 2:
                            restFormatDy = -6.0;
                            break;
                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;
                case 'F':
                    switch (display_octave) {
                        case 4:
                            if (fCurClef == "G")
                                restFormatDy = -3.0;
                            else if (fCurClef == "F")
                                restFormatDy = 9.0;
                            break;
                        case 5:
                            restFormatDy = 4.0;
                            break;
                        // F clef:
                        case 3:
                            restFormatDy = 2.0;
                            break;
                        case 2:
                            restFormatDy = -5.0;
                            break;

                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;
                case 'G':
                    switch (display_octave) {
                        // G clef:
                        case 4:
                            restFormatDy = -2.0;
                            break;
                        case 5:
                            restFormatDy = 5.0;
                            break;
                        // F clef:
                        case 3:
                            restFormatDy = 3.0;
                            break;
                        case 2:
                            restFormatDy = -4.0;
                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;

                default:
                    break;
            }

        /* F-clef case treated separately
        {
            switch (display_step[0]) {
                case 'A':
                    switch (display_octave) {
                        case 3:
                            restFormatDy = 4.0;
                            break;
                        case 2:
                            restFormatDy = -3.0;
                            break;

                        case 1:
                            restFormatDy = -10.0;
                            break;

                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;

                case 'B':
                    switch (display_octave) {
                        case 3:
                            restFormatDy = 5.0;
                            break;
                        case 2:
                            restFormatDy = -2.0;
                            break;

                        case 1:
                            restFormatDy = -9.0;
                            break;
                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;
                case 'C':
                    switch (display_octave) {
                        case 4:
                            restFormatDy = 6.0;
                            break;
                        case 3:
                            restFormatDy = -1.0;
                            break;
                        case 2:
                            restFormatDy = -8.0;
                            break;
                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;

                case 'D':
                    switch (display_octave) {
                        case 4:
                            restFormatDy = 7.0;
                            break;
                        case 3:
                            restFormatDy = 0.0;
                            break;
                        case 2:
                            restFormatDy = -7.0;
                            break;

                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;
                case 'E':
                    switch (display_octave) {
                        case 4:
                            restFormatDy = 8.0;
                            break;
                        case 3:
                            restFormatDy = 1.0;
                            break;
                        case 2:
                            restFormatDy = -6.0;
                            break;
                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;
                case 'F':
                    switch (display_octave) {
                        case 4:
                            restFormatDy = 9.0;
                            break;
                        case 3:
                            restFormatDy = 2.0;
                            break;
                        case 2:
                            restFormatDy = -5.0;
                            break;

                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;
                case 'G':
                    switch (display_octave) {
                        case 3:
                            restFormatDy = 3.0;
                            break;
                        case 2:
                            restFormatDy = -4.0;
                            break;
                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;

                default:
                    break;
            }
        }
        */

            // Got it reversed for F clef
            if (fCurClef == "G")
                restFormatDy = -1.0 * restFormatDy;
        }

        return restFormatDy;
    }

}

<commit_msg>xml2guido: Corrects restFormat spacing<commit_after>/*
  MusicXML Library
  Copyright (C) Grame 2006-2013

  This Source Code Form is subject to the terms of the Mozilla Public
  License, v. 2.0. If a copy of the MPL was not distributed with this
  file, You can obtain one at http://mozilla.org/MPL/2.0/.

  Grame Research Laboratory, 11, cours de Verdun Gensoul 69002 Lyon - France
  research@grame.fr
*/

#include <iostream>
#include "notevisitor.h"

//#define PRINTNOTE

using namespace std;

namespace MusicXML2 {

//________________________________________________________________________
ostream& operator<< (ostream& os, const notevisitor& elt)
{
    elt.print(os);
    return os;
}

//________________________________________________________________________
notevisitor::notevisitor()
	: fInNote(false)
{
	reset();
}

//________________________________________________________________________
void notevisitor::reset ()
{
	fGrace = fCue = fChord = fFermata = false;
	fType		= kUndefinedType;
	fTie		= StartStop::undefined;
	fDuration	= 0;
	fDots		= 0;
	fDynamics	= kUndefinedDynamics;
	fStaff		= kUndefinedStaff;
	fVoice		= kUndefinedVoice;
	fAlter = 0.f;
	fOctave = 0;
	fStem = 0;
	fAccent = 0;
	fStrongAccent = 0;
	fStaccato = 0;
    fTenuto = 0;
	fTrill = 0;
    fMordent = 0;
    fInvertedMordent = 0;
	fBreathMark = 0;
	fTimeModification.set(1,1);
#ifdef VC6
	fStep = "";
	fInstrument = "";
#else
	fStep.clear();
	fInstrument.clear();
#endif
	fTied.clear();
	fSlur.clear();
	fBeam.clear();
    fTuplet.clear();

    fLyric.clear();
    fSyllabic = "";
    fLyricText="";
}

//________________________________________________________________________
string notevisitor::i2step(int i)
{
	switch (i) {
		case notevisitor::A:	return "A";
		case notevisitor::B:	return "B";
		case notevisitor::C:	return "C";
		case notevisitor::D:	return "D";
		case notevisitor::E:	return "E";
		case notevisitor::F:	return "F";
		case notevisitor::G:	return "G";
	}
	return "";
}

//________________________________________________________________________
int notevisitor::step2i(const std::string& step)
{
	if (step.size() != 1) return -1;
	switch (step[0]) {
		case 'A':	return notevisitor::A;
		case 'B':	return notevisitor::B;
		case 'C':	return notevisitor::C;
		case 'D':	return notevisitor::D;
		case 'E':	return notevisitor::E;
		case 'F':	return notevisitor::F;
		case 'G':	return notevisitor::G;
	}
	return -1;
}

//________________________________________________________________________
float notevisitor::getMidiPitch() const
{
    if (fType == kPitched) {
		int step = step2i(getStep());
		if (step >= 0) {
			short step2pitch [] = { 0, 2, 4, 5, 7, 9, 11 };
			float pitch = (getOctave() * 12.f) + step2pitch[step];
			return pitch + getAlter();
		}
	}
    return -1;
}

//________________________________________________________________________
void notevisitor::visitStart ( S_time_modification& elt )
{
	fTimeModification.set ( elt->getIntValue(k_normal_notes,1), elt->getIntValue(k_actual_notes,1));
}

//________________________________________________________________________
void notevisitor::visitStart ( S_tie& elt )
{
	const string& value = elt->getAttributeValue("type");
	fTie = StartStop::type(fTie | StartStop::xml(value));
/*
	if (value == "start") fTie |= kTieStart;
	else if (value == "stop") fTie |= kTieStop;
*/
}

//________________________________________________________________________
void notevisitor::print (ostream& out) const
{
		if (isGrace()) out << "grace ";
		if (isCue())   out << "cue ";
		int type = getType();
		if (type == kUndefinedType)
			out << "type undefined";
		else if (type == kUnpitched) {
			out << "unpitched note - duration " << getDuration() << " ";
		}
		else if (type == kRest) {
			out << "rest - duration " << getDuration() << " ";
		}
		else if (type == kPitched) {
			out << "note " << getStep();
			int alter = int(getAlter());
			float diff = getAlter() - alter;
			if (diff >= 0.5) alter++;
			else if (diff <= -0.5) alter--;
			while (alter < 0) { out << 'b'; alter++; }
			while (alter > 0) { out << '#'; alter--; }
			out << getOctave() << " (" << getMidiPitch() << ")";
			out << " - duration " << getDuration() << " ";
		}
		else out << "unknown type " <<  type << " ";
		if (inChord())	out << "in chord ";
		if (getTie() & StartStop::start)	out << "- tie start ";
		if (getTie() & StartStop::stop)	out << "- tie stop ";
		string instr = getInstrument();
		if (!instr.empty()) out << "instrument " << instr << " ";
		if (getDynamics() >= 0) out << "dynamics " << getDynamics();
}

    //________________________________________________________________________
    void notevisitor::visitStart ( S_lyric& elt )
    {
        fLyric.push_back (elt);
        // get attributes
        float posy = elt->getAttributeFloatValue("default-y", 0) + elt->getAttributeFloatValue("relative-y", 0);
        fLyricsDy = (posy / 10) * 2;   // convert to half spaces
        fLyricsDy += 8;		  // anchor point convertion (defaults to upper line in xml)

        /// Get content information:
        fSyllabic = elt->getValue(k_syllabic);
        fLyricText = elt->getValue(k_text);
    }

//________________________________________________________________________
void notevisitor::visitStart ( S_note& elt )
{
	fInNote = true;
	reset();
	fDynamics = elt->getAttributeLongValue("dynamics", kUndefinedDynamics);
}

//________________________________________________________________________
void notevisitor::visitEnd ( S_note& elt )
{
#ifdef PRINTNOTE
	cout << *this << endl;
#endif
}

    //________________________________________________________________________
    float notevisitor::getRestFormatDy ( string fCurClef ) const
    {
        float restFormatDy = 0.0;
        //string display_step = elt->getValue(k_display_step);
        //int display_octave = elt->getIntValue(k_display_octave, 0.0);
        string display_step = fStep;
        int display_octave = fOctave;

        // Now convert to half-space! We'd need the Current Clef info for this!
        if (display_octave)
        {
            // dy 0 is B4, dy=-6 for C4, -4 for E4, -2 for G4 ;
            // D5-> +2, F5 -> +4
            switch (display_step[0]) {
                case 'A':
                    switch (display_octave) {
                        case 4:
                            restFormatDy = -1.0;
                            break;
                        case 5:
                            restFormatDy = 6.0;
                            break;

                        case 3:
                            if (fCurClef == "G")
                                restFormatDy = -8.0;
                            else if (fCurClef == "F")
                                restFormatDy = 4.0;
                            break;

                        // treating F clef directly!
                        case 2:
                            restFormatDy = -3.0;
                            break;
                        case 1:
                            restFormatDy = -10.0;
                            break;

                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;

                case 'B':
                    switch (display_octave) {
                        case 4:
                            restFormatDy = 0.0;
                            break;
                        case 5:
                            restFormatDy = 7.0;
                            break;

                        case 3:
                            if (fCurClef == "G")
                                restFormatDy = -7.0;
                            else if (fCurClef == "F")
                                restFormatDy = 5.0;
                            break;
                        // F clef:
                        case 2:
                            restFormatDy = -2.0;
                            break;
                        case 1:
                            restFormatDy = -9.0;
                            break;

                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;
                case 'C':
                    switch (display_octave) {
                        case 4:
                            if (fCurClef == "G")
                                restFormatDy = -6.0;
                            else if (fCurClef == "F")
                                restFormatDy = 6.0;
                            break;
                        case 5:
                            restFormatDy = 1.0;
                            break;
                        case 6:
                            restFormatDy = 8.0;
                            break;
                        // F clef:
                        case 3:
                            restFormatDy = -1.0;
                            break;
                        case 2:
                            restFormatDy = -8.0;
                            break;
                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;

                case 'D':
                    switch (display_octave) {
                        case 4:
                            if (fCurClef == "G")
                                restFormatDy = -5.0;
                            else if (fCurClef == "F")
                                restFormatDy = 7.0;
                            break;
                        case 5:
                            restFormatDy = 2.0;
                            break;
                        // F clef:
                        case 3:
                            restFormatDy = 0.0;
                            break;
                        case 2:
                            restFormatDy = -7.0;
                            break;

                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;
                case 'E':
                    switch (display_octave) {
                        case 4:
                            if (fCurClef == "G")
                                restFormatDy = -4.0;
                            else if (fCurClef == "F")
                                restFormatDy = 8.0;
                            break;
                        case 5:
                            restFormatDy = 3.0;
                            break;
                        case 6:
                            restFormatDy = 10.0;
                            break;
                        // F clef:
                        case 3:
                            restFormatDy = 1.0;
                            break;
                        case 2:
                            restFormatDy = -6.0;
                            break;
                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;
                case 'F':
                    switch (display_octave) {
                        case 4:
                            if (fCurClef == "G")
                                restFormatDy = -3.0;
                            else if (fCurClef == "F")
                                restFormatDy = 9.0;
                            break;
                        case 5:
                            restFormatDy = 4.0;
                            break;
                        // F clef:
                        case 3:
                            restFormatDy = 2.0;
                            break;
                        case 2:
                            restFormatDy = -5.0;
                            break;

                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;
                case 'G':
                    switch (display_octave) {
                        // G clef:
                        case 4:
                            restFormatDy = -2.0;
                            break;
                        case 5:
                            restFormatDy = 5.0;
                            break;
                        // F clef:
                        case 3:
                            restFormatDy = 3.0;
                            break;
                        case 2:
                            restFormatDy = -4.0;
                            break;
                        default:
                            restFormatDy = 0.0;
                            break;
                    }
                    break;

                default:
                    break;
            }

            // Got it reversed for F clef
            restFormatDy = -1.0 * restFormatDy;

            //cout<<"resFormat "<<display_step<<display_octave<<" on clef "<<fCurClef<<" gives "<<restFormatDy<<endl;
        }

        return restFormatDy;
    }

}

<|endoftext|>