<commit_before>/*************************************************************************
 *
 *  $RCSfile: SlsPageCacheManager.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2005-10-24 07:41:21 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include "cache/SlsPageCacheManager.hxx"

#include "SlsBitmapCache.hxx"
#include "view/SlideSorterView.hxx"
#include "model/SlideSorterModel.hxx"

#include <deque>
#include <map>

namespace {

/** Collection of data that is stored for all active preview caches.
*/
class CacheDescriptor
{
public:
    SdDrawDocument* mpDocument;
    Size maPreviewSize;

    CacheDescriptor(SdDrawDocument* pDocument, const Size& rPreviewSize)
        :mpDocument(pDocument),maPreviewSize(rPreviewSize)
    {}
    /// Test for equality with respect to all members.
    class Equal {public: bool operator() (
        const CacheDescriptor& rDescriptor1, const CacheDescriptor& rDescriptor2) const {
        return rDescriptor1.mpDocument==rDescriptor2.mpDocument
            && rDescriptor1.maPreviewSize==rDescriptor2.maPreviewSize;
    } };
    /// Hash function that takes all members into account.
    class Hash {public: size_t operator() (const CacheDescriptor& rDescriptor) const {
        return (size_t)rDescriptor.mpDocument + rDescriptor.maPreviewSize.Width();
    } };
};

/** Collection of data that is stored for the inactive, recently used
    caches.
*/
class RecentlyUsedCacheDescriptor
{
public:
    SdDrawDocument* mpDocument;
    Size maPreviewSize;
    ::boost::shared_ptr< ::sd::slidesorter::cache::PageCacheManager::Cache> mpCache;

    RecentlyUsedCacheDescriptor(
        SdDrawDocument* pDocument,
        const Size& rPreviewSize,
        const ::boost::shared_ptr< ::sd::slidesorter::cache::PageCacheManager::Cache>& rpCache)
        :mpDocument(pDocument),maPreviewSize(rPreviewSize),mpCache(rpCache)
    {}
};

/** The list of recently used caches is organized as queue.  When elements
    are added the list is shortened to the maximally allowed number of
    elements by removing the least recently used elements.
*/
typedef ::std::deque<RecentlyUsedCacheDescriptor> RecentlyUsedQueue;

/** Compare the caches by preview size.  Those that match the given size
    come first, then, regardless of the given size, the largest ones before
    the smaller ones.
*/
class BestFittingCacheComparer
{
public:
    BestFittingCacheComparer (const Size& rPreferredSize)
        : maPreferredSize(rPreferredSize)
    {}
    bool operator()(const ::sd::slidesorter::cache::PageCacheManager::BestFittingPageCaches::value_type& rElement1,
        const ::sd::slidesorter::cache::PageCacheManager::BestFittingPageCaches::value_type& rElement2)
    {
        if (rElement1.first == maPreferredSize)
            return true;
        else if (rElement2.first == maPreferredSize)
            return false;
        else
            return (rElement1.first.Width()*rElement1.first.Height()
                > rElement2.first.Width()*rElement2.first.Height());
    }

private:
    Size maPreferredSize;
};

} // end of anonymous namespace

namespace sd { namespace slidesorter { namespace cache {

/** Container for the active caches.
*/
class PageCacheManager::PageCacheContainer
    : public ::std::hash_map<CacheDescriptor,
                             ::boost::shared_ptr<PageCacheManager::Cache>,
                             CacheDescriptor::Hash,
                             CacheDescriptor::Equal>
{
public:
    PageCacheContainer (void) {}

    /** Compare entries in the cache container with respect to the cache
        address only.
    */
    class CompareWithCache { public:
        CompareWithCache(const ::boost::shared_ptr<PageCacheManager::Cache>& rpCache)
            : mpCache(rpCache) {}
        bool operator () (const PageCacheContainer::value_type& rValue)
        { return rValue.second == mpCache; }
    private:
        ::boost::shared_ptr<PageCacheManager::Cache> mpCache;
    };
};

/** The recently used caches are stored in one queue for each document.
*/
class PageCacheManager::RecentlyUsedPageCaches
    : public ::std::map<SdDrawDocument*,RecentlyUsedQueue>
{
public:
    RecentlyUsedPageCaches (void) {};
};

//===== PageCacheManager ====================================================

::boost::shared_ptr<PageCacheManager> PageCacheManager::mpInstance;

::boost::shared_ptr<PageCacheManager> PageCacheManager::Instance (void)
{
    if (mpInstance.get() == NULL)
    {
        ::osl::GetGlobalMutex aMutexFunctor;
        ::osl::MutexGuard aGuard (aMutexFunctor());
        if (mpInstance.get() == NULL)
        {
            PageCacheManager* pSingleton = new PageCacheManager();
            OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
            mpInstance.reset(pSingleton);
        }
    }
    else
        OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();

    return mpInstance;
}

PageCacheManager::PageCacheManager (void)
    : mpPageCaches(new PageCacheContainer()),
      mpRecentlyUsedPageCaches(new RecentlyUsedPageCaches()),
      mnMaximalRecentlyCacheCount(2)
{
}

PageCacheManager::~PageCacheManager (void)
{
}

::boost::shared_ptr<PageCacheManager::Cache> PageCacheManager::GetCache (
    SdDrawDocument* pDocument,
    const Size& rPreviewSize)
{
    ::boost::shared_ptr<Cache> pResult;

    // Look for the cache in the list of active caches.
    CacheDescriptor aKey (pDocument, rPreviewSize);
    PageCacheContainer::iterator iCache (mpPageCaches->find(aKey));
    if (iCache != mpPageCaches->end())
        pResult = iCache->second;

    // Look for the cache in the list of recently used caches.
    if (pResult.get() == NULL)
        pResult = GetRecentlyUsedCache(pDocument, rPreviewSize);

    // Create the cache when no suitable one does exist.
    if (pResult.get() == NULL)
        pResult.reset(new Cache());

    // The cache may be newly created and thus empty or is old and may
    // contain previews that are not up-to-date.  Recycle previews from
    // other caches to fill in the holes.
    Recycle(pResult, pDocument,rPreviewSize);

    // Put the new (or old) cache into the container.
    if (pResult.get() != NULL)
        mpPageCaches->insert(PageCacheContainer::value_type(aKey, pResult));

    OSL_TRACE("returning cache %x for document %x and size %d %d",
        pResult.get(), pDocument, rPreviewSize.Width(),rPreviewSize.Height());

    return pResult;
}

void PageCacheManager::Recycle (
    const ::boost::shared_ptr<Cache>& rpCache,
    SdDrawDocument* pDocument,
    const Size& rPreviewSize)
{
    BestFittingPageCaches aCaches;

    // Add bitmap caches from active caches.
    PageCacheContainer::iterator iActiveCache;
    for (iActiveCache=mpPageCaches->begin(); iActiveCache!=mpPageCaches->end(); ++iActiveCache)
    {
        if (iActiveCache->first.mpDocument == pDocument)
            aCaches.push_back(BestFittingPageCaches::value_type(
                iActiveCache->first.maPreviewSize, iActiveCache->second));
    }

    // Add bitmap caches from recently used caches.
    RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument));
    if (iQueue != mpRecentlyUsedPageCaches->end())
    {
        RecentlyUsedQueue::const_iterator iRecentCache;
        for (iRecentCache=iQueue->second.begin();iRecentCache!=iQueue->second.end();++iRecentCache)
            aCaches.push_back(BestFittingPageCaches::value_type(
                iRecentCache->maPreviewSize, iRecentCache->mpCache));
    }

    ::std::sort(aCaches.begin(), aCaches.end(), BestFittingCacheComparer(rPreviewSize));

    BestFittingPageCaches::const_iterator iBestCache;
    for (iBestCache=aCaches.begin(); iBestCache!=aCaches.end(); ++iBestCache)
    {
        rpCache->Recycle(*iBestCache->second);
    }
}

void PageCacheManager::ReleaseCache (const ::boost::shared_ptr<Cache>& rpCache)
{
    OSL_TRACE("releasing cache %x", rpCache.get());
    PageCacheContainer::iterator iCache (::std::find_if(
        mpPageCaches->begin(),
        mpPageCaches->end(),
        PageCacheContainer::CompareWithCache(rpCache)));
    OSL_ASSERT((iCache != mpPageCaches->end()));
    if (iCache != mpPageCaches->end())
    {
        OSL_ASSERT(iCache->second == rpCache);

        PutRecentlyUsedCache(iCache->first.mpDocument,iCache->first.maPreviewSize,rpCache);

        mpPageCaches->erase(iCache);
    }
}

::boost::shared_ptr<PageCacheManager::Cache> PageCacheManager::ChangeSize (
    const ::boost::shared_ptr<Cache>& rpCache,
    const Size& rOldPreviewSize,
    const Size& rNewPreviewSize)
{
    OSL_TRACE("changing size of cache %x from %d %d to %d %d",
        rpCache.get(),
        rOldPreviewSize.Width(),rOldPreviewSize.Height(),
        rNewPreviewSize.Width(),rNewPreviewSize.Height());
    ::boost::shared_ptr<Cache> pResult;

    if (rpCache.get() != NULL)
    {
        // Look up the given cache in the list of active caches.
        PageCacheContainer::iterator iCacheToChange (::std::find_if(
            mpPageCaches->begin(),
            mpPageCaches->end(),
            PageCacheContainer::CompareWithCache(rpCache)));
        OSL_ASSERT(iCacheToChange != mpPageCaches->end());
        if (iCacheToChange != mpPageCaches->end())
        {
            OSL_ASSERT(iCacheToChange->second == rpCache);

            // Now, we can change the preview size of the existing one by
            // removing the cache from the list and re-insert it with the
            // updated size.
            mpPageCaches->erase(iCacheToChange);
            mpPageCaches->insert(PageCacheContainer::value_type(
                CacheDescriptor(iCacheToChange->first.mpDocument,rNewPreviewSize),
                rpCache));

            pResult = rpCache;
        }
    }

    return pResult;
}

void PageCacheManager::InvalidatePreviewBitmap (
    SdDrawDocument* pDocument,
    const SdrPage* pKey)
{
    if (pDocument!=NULL)
    {
        // Iterate over all caches that are currently in use and invalidate
        // the previews in those that belong to the document.
        PageCacheContainer::iterator iCache;
        for (iCache=mpPageCaches->begin(); iCache!=mpPageCaches->end();  ++iCache)
            if (iCache->first.mpDocument == pDocument)
                iCache->second->InvalidateBitmap(pKey);

        // Invalidate the previews in the recently used caches belonging to
        // the given document.
        RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument));
        if (iQueue != mpRecentlyUsedPageCaches->end())
        {
            RecentlyUsedQueue::const_iterator iCache;
            for (iCache=iQueue->second.begin(); iCache!=iQueue->second.end(); ++iCache)
                iCache->mpCache->InvalidateBitmap(pKey);
        }
    }
}

::boost::shared_ptr<PageCacheManager::Cache> PageCacheManager::GetRecentlyUsedCache (
    SdDrawDocument* pDocument,
    const Size& rPreviewSize)
{
    ::boost::shared_ptr<Cache> pCache;

    // Look for the cache in the list of recently used caches.
    RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument));
    if (iQueue != mpRecentlyUsedPageCaches->end())
    {
        RecentlyUsedQueue::iterator iCache;
        for (iCache=iQueue->second.begin(); iCache!= iQueue->second.end(); ++iCache)
            if (iCache->maPreviewSize == rPreviewSize)
            {
                pCache = iCache->mpCache;
                iQueue->second.erase(iCache);
                break;
            }
    }

    return pCache;
}

void PageCacheManager::PutRecentlyUsedCache(
    SdDrawDocument* pDocument,
    const Size& rPreviewSize,
    const ::boost::shared_ptr<Cache>& rpCache)
{
    // Look up the list of recently used caches for the given document.
    RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument));
    if (iQueue == mpRecentlyUsedPageCaches->end())
        iQueue = mpRecentlyUsedPageCaches->insert(
            RecentlyUsedPageCaches::value_type(pDocument, RecentlyUsedQueue())
            ).first;

    if (iQueue != mpRecentlyUsedPageCaches->end())
    {
        iQueue->second.push_front(RecentlyUsedCacheDescriptor(pDocument,rPreviewSize,rpCache));
        // Shorten the list of recently used caches to the allowed maximal length.
        while (iQueue->second.size() > mnMaximalRecentlyCacheCount)
            iQueue->second.pop_back();
    }
}

} } } // end of namespace ::sd::slidesorter::cache
<commit_msg>INTEGRATION: CWS impress74 (1.2.4); FILE MERGED 2005/11/01 15:20:58 af 1.2.4.1: #i57048# Make mpInstance a weak pointer.<commit_after>/*************************************************************************
 *
 *  $RCSfile: SlsPageCacheManager.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-11-08 16:29:59 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include "cache/SlsPageCacheManager.hxx"

#include "SlsBitmapCache.hxx"
#include "view/SlideSorterView.hxx"
#include "model/SlideSorterModel.hxx"

#include <deque>
#include <map>
#include <boost/weak_ptr.hpp>

namespace {

/** Collection of data that is stored for all active preview caches.
*/
class CacheDescriptor
{
public:
    SdDrawDocument* mpDocument;
    Size maPreviewSize;

    CacheDescriptor(SdDrawDocument* pDocument, const Size& rPreviewSize)
        :mpDocument(pDocument),maPreviewSize(rPreviewSize)
    {}
    /// Test for equality with respect to all members.
    class Equal {public: bool operator() (
        const CacheDescriptor& rDescriptor1, const CacheDescriptor& rDescriptor2) const {
        return rDescriptor1.mpDocument==rDescriptor2.mpDocument
            && rDescriptor1.maPreviewSize==rDescriptor2.maPreviewSize;
    } };
    /// Hash function that takes all members into account.
    class Hash {public: size_t operator() (const CacheDescriptor& rDescriptor) const {
        return (size_t)rDescriptor.mpDocument + rDescriptor.maPreviewSize.Width();
    } };
};

/** Collection of data that is stored for the inactive, recently used
    caches.
*/
class RecentlyUsedCacheDescriptor
{
public:
    SdDrawDocument* mpDocument;
    Size maPreviewSize;
    ::boost::shared_ptr< ::sd::slidesorter::cache::PageCacheManager::Cache> mpCache;

    RecentlyUsedCacheDescriptor(
        SdDrawDocument* pDocument,
        const Size& rPreviewSize,
        const ::boost::shared_ptr< ::sd::slidesorter::cache::PageCacheManager::Cache>& rpCache)
        :mpDocument(pDocument),maPreviewSize(rPreviewSize),mpCache(rpCache)
    {}
};

/** The list of recently used caches is organized as queue.  When elements
    are added the list is shortened to the maximally allowed number of
    elements by removing the least recently used elements.
*/
typedef ::std::deque<RecentlyUsedCacheDescriptor> RecentlyUsedQueue;

/** Compare the caches by preview size.  Those that match the given size
    come first, then, regardless of the given size, the largest ones before
    the smaller ones.
*/
class BestFittingCacheComparer
{
public:
    BestFittingCacheComparer (const Size& rPreferredSize)
        : maPreferredSize(rPreferredSize)
    {}
    bool operator()(const ::sd::slidesorter::cache::PageCacheManager::BestFittingPageCaches::value_type& rElement1,
        const ::sd::slidesorter::cache::PageCacheManager::BestFittingPageCaches::value_type& rElement2)
    {
        if (rElement1.first == maPreferredSize)
            return true;
        else if (rElement2.first == maPreferredSize)
            return false;
        else
            return (rElement1.first.Width()*rElement1.first.Height()
                > rElement2.first.Width()*rElement2.first.Height());
    }

private:
    Size maPreferredSize;
};

} // end of anonymous namespace

namespace sd { namespace slidesorter { namespace cache {

/** Container for the active caches.
*/
class PageCacheManager::PageCacheContainer
    : public ::std::hash_map<CacheDescriptor,
                             ::boost::shared_ptr<PageCacheManager::Cache>,
                             CacheDescriptor::Hash,
                             CacheDescriptor::Equal>
{
public:
    PageCacheContainer (void) {}

    /** Compare entries in the cache container with respect to the cache
        address only.
    */
    class CompareWithCache { public:
        CompareWithCache(const ::boost::shared_ptr<PageCacheManager::Cache>& rpCache)
            : mpCache(rpCache) {}
        bool operator () (const PageCacheContainer::value_type& rValue)
        { return rValue.second == mpCache; }
    private:
        ::boost::shared_ptr<PageCacheManager::Cache> mpCache;
    };
};

/** The recently used caches are stored in one queue for each document.
*/
class PageCacheManager::RecentlyUsedPageCaches
    : public ::std::map<SdDrawDocument*,RecentlyUsedQueue>
{
public:
    RecentlyUsedPageCaches (void) {};
};

//===== PageCacheManager ====================================================

::boost::weak_ptr<PageCacheManager> PageCacheManager::mpInstance;

::boost::shared_ptr<PageCacheManager> PageCacheManager::Instance (void)
{
    ::boost::shared_ptr<PageCacheManager> pInstance;

    ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());

    pInstance = mpInstance.lock();
    if (pInstance.get() == NULL)
    {
        pInstance.reset(new PageCacheManager());
        mpInstance = pInstance;
    }

    return pInstance;
}

PageCacheManager::PageCacheManager (void)
    : mpPageCaches(new PageCacheContainer()),
      mpRecentlyUsedPageCaches(new RecentlyUsedPageCaches()),
      mnMaximalRecentlyCacheCount(2)
{
}

PageCacheManager::~PageCacheManager (void)
{
}

::boost::shared_ptr<PageCacheManager::Cache> PageCacheManager::GetCache (
    SdDrawDocument* pDocument,
    const Size& rPreviewSize)
{
    ::boost::shared_ptr<Cache> pResult;

    // Look for the cache in the list of active caches.
    CacheDescriptor aKey (pDocument, rPreviewSize);
    PageCacheContainer::iterator iCache (mpPageCaches->find(aKey));
    if (iCache != mpPageCaches->end())
        pResult = iCache->second;

    // Look for the cache in the list of recently used caches.
    if (pResult.get() == NULL)
        pResult = GetRecentlyUsedCache(pDocument, rPreviewSize);

    // Create the cache when no suitable one does exist.
    if (pResult.get() == NULL)
        pResult.reset(new Cache());

    // The cache may be newly created and thus empty or is old and may
    // contain previews that are not up-to-date.  Recycle previews from
    // other caches to fill in the holes.
    Recycle(pResult, pDocument,rPreviewSize);

    // Put the new (or old) cache into the container.
    if (pResult.get() != NULL)
        mpPageCaches->insert(PageCacheContainer::value_type(aKey, pResult));

    OSL_TRACE("returning cache %x for document %x and size %d %d",
        pResult.get(), pDocument, rPreviewSize.Width(),rPreviewSize.Height());

    return pResult;
}

void PageCacheManager::Recycle (
    const ::boost::shared_ptr<Cache>& rpCache,
    SdDrawDocument* pDocument,
    const Size& rPreviewSize)
{
    BestFittingPageCaches aCaches;

    // Add bitmap caches from active caches.
    PageCacheContainer::iterator iActiveCache;
    for (iActiveCache=mpPageCaches->begin(); iActiveCache!=mpPageCaches->end(); ++iActiveCache)
    {
        if (iActiveCache->first.mpDocument == pDocument)
            aCaches.push_back(BestFittingPageCaches::value_type(
                iActiveCache->first.maPreviewSize, iActiveCache->second));
    }

    // Add bitmap caches from recently used caches.
    RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument));
    if (iQueue != mpRecentlyUsedPageCaches->end())
    {
        RecentlyUsedQueue::const_iterator iRecentCache;
        for (iRecentCache=iQueue->second.begin();iRecentCache!=iQueue->second.end();++iRecentCache)
            aCaches.push_back(BestFittingPageCaches::value_type(
                iRecentCache->maPreviewSize, iRecentCache->mpCache));
    }

    ::std::sort(aCaches.begin(), aCaches.end(), BestFittingCacheComparer(rPreviewSize));

    BestFittingPageCaches::const_iterator iBestCache;
    for (iBestCache=aCaches.begin(); iBestCache!=aCaches.end(); ++iBestCache)
    {
        rpCache->Recycle(*iBestCache->second);
    }
}

void PageCacheManager::ReleaseCache (const ::boost::shared_ptr<Cache>& rpCache)
{
    OSL_TRACE("releasing cache %x", rpCache.get());
    PageCacheContainer::iterator iCache (::std::find_if(
        mpPageCaches->begin(),
        mpPageCaches->end(),
        PageCacheContainer::CompareWithCache(rpCache)));
    OSL_ASSERT((iCache != mpPageCaches->end()));
    if (iCache != mpPageCaches->end())
    {
        OSL_ASSERT(iCache->second == rpCache);

        PutRecentlyUsedCache(iCache->first.mpDocument,iCache->first.maPreviewSize,rpCache);

        mpPageCaches->erase(iCache);
    }
}

::boost::shared_ptr<PageCacheManager::Cache> PageCacheManager::ChangeSize (
    const ::boost::shared_ptr<Cache>& rpCache,
    const Size& rOldPreviewSize,
    const Size& rNewPreviewSize)
{
    OSL_TRACE("changing size of cache %x from %d %d to %d %d",
        rpCache.get(),
        rOldPreviewSize.Width(),rOldPreviewSize.Height(),
        rNewPreviewSize.Width(),rNewPreviewSize.Height());
    ::boost::shared_ptr<Cache> pResult;

    if (rpCache.get() != NULL)
    {
        // Look up the given cache in the list of active caches.
        PageCacheContainer::iterator iCacheToChange (::std::find_if(
            mpPageCaches->begin(),
            mpPageCaches->end(),
            PageCacheContainer::CompareWithCache(rpCache)));
        OSL_ASSERT(iCacheToChange != mpPageCaches->end());
        if (iCacheToChange != mpPageCaches->end())
        {
            OSL_ASSERT(iCacheToChange->second == rpCache);

            // Now, we can change the preview size of the existing one by
            // removing the cache from the list and re-insert it with the
            // updated size.
            mpPageCaches->erase(iCacheToChange);
            mpPageCaches->insert(PageCacheContainer::value_type(
                CacheDescriptor(iCacheToChange->first.mpDocument,rNewPreviewSize),
                rpCache));

            pResult = rpCache;
        }
    }

    return pResult;
}

void PageCacheManager::InvalidatePreviewBitmap (
    SdDrawDocument* pDocument,
    const SdrPage* pKey)
{
    if (pDocument!=NULL)
    {
        // Iterate over all caches that are currently in use and invalidate
        // the previews in those that belong to the document.
        PageCacheContainer::iterator iCache;
        for (iCache=mpPageCaches->begin(); iCache!=mpPageCaches->end();  ++iCache)
            if (iCache->first.mpDocument == pDocument)
                iCache->second->InvalidateBitmap(pKey);

        // Invalidate the previews in the recently used caches belonging to
        // the given document.
        RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument));
        if (iQueue != mpRecentlyUsedPageCaches->end())
        {
            RecentlyUsedQueue::const_iterator iCache;
            for (iCache=iQueue->second.begin(); iCache!=iQueue->second.end(); ++iCache)
                iCache->mpCache->InvalidateBitmap(pKey);
        }
    }
}

::boost::shared_ptr<PageCacheManager::Cache> PageCacheManager::GetRecentlyUsedCache (
    SdDrawDocument* pDocument,
    const Size& rPreviewSize)
{
    ::boost::shared_ptr<Cache> pCache;

    // Look for the cache in the list of recently used caches.
    RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument));
    if (iQueue != mpRecentlyUsedPageCaches->end())
    {
        RecentlyUsedQueue::iterator iCache;
        for (iCache=iQueue->second.begin(); iCache!= iQueue->second.end(); ++iCache)
            if (iCache->maPreviewSize == rPreviewSize)
            {
                pCache = iCache->mpCache;
                iQueue->second.erase(iCache);
                break;
            }
    }

    return pCache;
}

void PageCacheManager::PutRecentlyUsedCache(
    SdDrawDocument* pDocument,
    const Size& rPreviewSize,
    const ::boost::shared_ptr<Cache>& rpCache)
{
    // Look up the list of recently used caches for the given document.
    RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument));
    if (iQueue == mpRecentlyUsedPageCaches->end())
        iQueue = mpRecentlyUsedPageCaches->insert(
            RecentlyUsedPageCaches::value_type(pDocument, RecentlyUsedQueue())
            ).first;

    if (iQueue != mpRecentlyUsedPageCaches->end())
    {
        iQueue->second.push_front(RecentlyUsedCacheDescriptor(pDocument,rPreviewSize,rpCache));
        // Shorten the list of recently used caches to the allowed maximal length.
        while (iQueue->second.size() > mnMaximalRecentlyCacheCount)
            iQueue->second.pop_back();
    }
}

} } } // end of namespace ::sd::slidesorter::cache
<|endoftext|>


<commit_before>// Copyright (c) 2012 Plenluno All rights reserved.

#include <libj/console.h>
#include <libj/string.h>
#include <libnode/node.h>
#include <libnode/timer.h>

namespace libj {
namespace node {

class OnInterval : LIBJ_JS_FUNCTION(OnInterval)
 private:
    Value id_;
    Int count_;

 public:
    OnInterval() : count_(100) {}

    void setId(Value id) {
        id_ = id;
    }

    void setCount(Int cnt) {
        count_ = cnt;
    }

    Value operator()(JsArray::Ptr args) {
        if (count_) {
            console::log(String::valueOf(count_--));
        } else {
            clearInterval(id_);
        }
        return 0;
    }
};

}  // namespace node
}  // namespace libj

int main() {
    namespace node = libj::node;

    node::OnInterval::Ptr onInterval(new node::OnInterval);;
    libj::Value id = node::setInterval(
        onInterval, 200, libj::JsArray::null());
    onInterval->setId(id);
    onInterval->setCount(75);

    node::OnInterval::Ptr onInterval2(new node::OnInterval);
    libj::Value id2 = node::setInterval(
        onInterval2, 150, libj::JsArray::null());
    onInterval2->setId(id2);
    onInterval2->setCount(100);

    node::run();
    return 0;
}
<commit_msg>delete redundant ';'<commit_after>// Copyright (c) 2012 Plenluno All rights reserved.

#include <libj/console.h>
#include <libj/string.h>
#include <libnode/node.h>
#include <libnode/timer.h>

namespace libj {
namespace node {

class OnInterval : LIBJ_JS_FUNCTION(OnInterval)
 private:
    Value id_;
    Int count_;

 public:
    OnInterval() : count_(100) {}

    void setId(Value id) {
        id_ = id;
    }

    void setCount(Int cnt) {
        count_ = cnt;
    }

    Value operator()(JsArray::Ptr args) {
        if (count_) {
            console::log(String::valueOf(count_--));
        } else {
            clearInterval(id_);
        }
        return 0;
    }
};

}  // namespace node
}  // namespace libj

int main() {
    namespace node = libj::node;

    node::OnInterval::Ptr onInterval(new node::OnInterval);
    libj::Value id = node::setInterval(
        onInterval, 200, libj::JsArray::null());
    onInterval->setId(id);
    onInterval->setCount(75);

    node::OnInterval::Ptr onInterval2(new node::OnInterval);
    libj::Value id2 = node::setInterval(
        onInterval2, 150, libj::JsArray::null());
    onInterval2->setId(id2);
    onInterval2->setCount(100);

    node::run();
    return 0;
}
<|endoftext|>


<commit_before>#include "Rendering/Quad.h"
#include "Math/Vector4.h"
#include "Math/Vertex.h"

namespace Mile
{
   bool Quad::Init(float minX, float minY,
      float maxX, float maxY)
   {
      std::vector<VertexPosTex> vertices = {
      { Vector4(minX, maxY, 0.0f, 1.0f), Vector2(0.0f, 0.0f) },
      { Vector4(maxX, maxY, 0.0f, 1.0f), Vector2(1.0f, 0.0f) },
      { Vector4(minX, minY, 0.0f, 1.0f), Vector2(0.0f, 1.0f) },
      { Vector4(maxX, minY, 0.0f, 1.0f), Vector2(1.0f, 1.0f) } };

      std::vector<unsigned int> indices = {
         0, 1, 2,
         2, 1, 3
      };

      return Mesh::Init<VertexPosTex>(vertices, indices);
   }
}<commit_msg>Add normal for Quad<commit_after>#include "Rendering/Quad.h"
#include "Math/Vector4.h"
#include "Math/Vertex.h"

namespace Mile
{
   bool Quad::Init(float minX, float minY,
      float maxX, float maxY)
   {
      std::vector<VertexPTN> vertices = {
      { Vector4(minX, maxY, 0.0f, 1.0f), Vector2(0.0f, 0.0f), Vector3(0.0f, 0.0f, -1.0f) },
      { Vector4(maxX, maxY, 0.0f, 1.0f), Vector2(1.0f, 0.0f), Vector3(0.0f, 0.0f, -1.0f) },
      { Vector4(minX, minY, 0.0f, 1.0f), Vector2(0.0f, 1.0f), Vector3(0.0f, 0.0f, -1.0f) },
      { Vector4(maxX, minY, 0.0f, 1.0f), Vector2(1.0f, 1.0f), Vector3(0.0f, 0.0f, -1.0f) } };

      std::vector<unsigned int> indices = {
         0, 1, 2,
         2, 1, 3
      };

      return Mesh::Init<VertexPTN>(vertices, indices);
   }
}<|endoftext|>


<commit_before>#include <chord.h>
#include <modlogger.h>
#include <id_utils.h>
#include "merkle.h"
#include "merkle_tree_disk.h"
#include <location.h>
#include <transport_prot.h>
#include <comm.h>

// {{{ Globals
static const bool usedisk = false;

static struct {
  ptr<merkle_tree> tree;
  ptr<merkle_server> server;
  ptr<asrv> srv;
} SERVER;

static struct {
  ptr<merkle_tree> tree;
  ptr<merkle_syncer> syncer;
  ptr<aclnt> clnt;
} SYNCER;

u_int32_t nkeyspushed = 0;
u_int32_t nkeyspulled = 0;
vec<chordID> keys_for_server;
vec<chordID> keys_for_syncer;

str server_index = "/tmp/server.index.mrk";
str server_internal = "/tmp/server.internal.mrk";
str server_leaf = "/tmp/server.leaf.mrk";
str syncer_index = "/tmp/syncer.index.mrk";
str syncer_internal = "/tmp/syncer.internal.mrk";
str syncer_leaf = "/tmp/syncer.leaf.mrk";

str server_index_ro = "/tmp/server.index.mrk.ro";
str server_internal_ro = "/tmp/server.internal.mrk.ro";
str server_leaf_ro = "/tmp/server.leaf.mrk.ro";
str syncer_index_ro = "/tmp/syncer.index.mrk.ro";
str syncer_internal_ro = "/tmp/syncer.internal.mrk.ro";
str syncer_leaf_ro = "/tmp/syncer.leaf.mrk.ro";
// }}}

// {{{ RPC Magic
static void
doRPCcb (xdrproc_t proc, dorpc_res *res, aclnt_cb cb, void *out, clnt_stat err)
{
  xdrmem x ((char *)res->resok->results.base (),
	    res->resok->results.size (), XDR_DECODE);

  if (err) {
    warnx << "doRPC: err = " << err << "\n";
    assert (!err);
  } else if (!proc (x.xdrp (), out)) {
    warnx << "failed to unmarshall result\n";
    cb (RPC_CANTSEND);
    return;
  }
  cb (err);
  delete res;
}

// called by syncer to perform merkle RPC to server
static void
doRPC (RPC_delay_args *a)
{
  //form the transport RPC
  ptr<dorpc_arg> arg = New refcounted<dorpc_arg> ();
  // Other fields don't matter.
  arg->progno = a->prog.progno;
  arg->procno = a->procno;

  xdrproc_t inproc = a->prog.tbl[a->procno].xdr_arg;
  xdrproc_t outproc = a->prog.tbl[a->procno].xdr_res;
  assert (outproc);
  xdrsuio x (XDR_ENCODE);
  if ((!inproc) || (!inproc (x.xdrp (), (void *)a->in))) {
    fatal << "failed to marshall args\n";
  }
  int args_len = x.uio ()->resid ();
  arg->args.setsize (args_len);
  void *marshalled_args = suio_flatten (x.uio ());
  memcpy (arg->args.base (), marshalled_args, args_len);
  free (marshalled_args);

  dorpc_res *res = New dorpc_res (DORPC_OK);
  SYNCER.clnt->call (TRANSPORTPROC_DORPC, arg, res,
                     wrap (&doRPCcb, outproc, res, a->cb, a->out));
}

vec<const rpc_program *> handledProgs;
vec<cbdispatch_t> handlers;

static void
transport_dispatch (svccb *sbp)
{
  if (!sbp) {
    warnx << "transport server eof\n";
    return;
  }

  dorpc_arg *arg = sbp->Xtmpl getarg<dorpc_arg> ();

  chord_node_wire nw;
  bzero (&nw, sizeof (chord_node_wire));

  const rpc_program *prog (NULL);
  unsigned int i (0);
  for (unsigned int i = 0; i < handledProgs.size (); i++)
    if (arg->progno == (int)handledProgs[i]->progno) {
      prog = handledProgs[i];
      break;
    }
  char *arg_base = (char *)(arg->args.base ());
  int arg_len = arg->args.size ();

  xdrmem x (arg_base, arg_len, XDR_DECODE);
  xdrproc_t proc = prog->tbl[arg->procno].xdr_arg;
  assert (proc);

  void *unmarshalled_args = prog->tbl[arg->procno].alloc_arg ();
  if (!proc (x.xdrp (), unmarshalled_args)) {
    warn << "dispatch: error unmarshalling arguments: "
	 << arg->progno << "." << arg->procno << "\n";
    xdr_delete (prog->tbl[arg->procno].xdr_arg, unmarshalled_args);
    sbp->replyref (rpcstat (DORPC_MARSHALLERR));
    return;
  }
  user_args *ua = New user_args (sbp, unmarshalled_args,
				 prog, arg->procno, 0);
  ua->me_ = New refcounted<location> (make_chord_node (nw));
  handlers[i] (ua);
}

// called by server to register handler fielding merkle RPCs
static void
addHandler (const rpc_program &prog, cbdispatch_t cb)
{
  handledProgs.push_back (&prog);
  handlers.push_back (cb);
}
// }}}
// {{{ Testing framework - setup/finish/addrand/dump_stats
static void
sendblock (bigint blockID, bool missingLocal)
{
  if (missingLocal)
    keys_for_syncer.push_back (blockID);
  else
    keys_for_server.push_back (blockID);
}

void
dump_stats ()
{
  warn  << "+++++++++++++++++++++++++SERVER.tree++++++++++++++++++++++++++++++\n";
  SERVER.tree->compute_stats ();
  // SERVER.tree->dump ();
  warn  << "+++++++++++++++++++++++++SYNCER.tree++++++++++++++++++++++++++++++\n";
  SYNCER.tree->compute_stats ();
  // SYNCER.tree->dump ();
}

void
setup ()
{
  warn << "===> setup() +++++++++++++++++++++++++++\n";
  if (usedisk) {
    SERVER.tree = New refcounted<merkle_tree_disk> (server_index,
						    server_internal, server_leaf,
						    true);
    SYNCER.tree = New refcounted<merkle_tree_disk> (syncer_index,
						    syncer_internal, syncer_leaf,
						    true);
  } else {
    SERVER.tree = New refcounted<merkle_tree> ();
    SYNCER.tree = New refcounted<merkle_tree> ();
  }

  // these are closed by axprt_stream's dtor, right?
  int fds[2];
  assert (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) == 0);
  warn << "  sockets: " << fds[0] << ":" << fds[1] << "\n";
  SERVER.srv = asrv::alloc (axprt_stream::alloc (fds[0]), transport_program_1);
  SYNCER.clnt = aclnt::alloc (axprt_stream::alloc (fds[1]), transport_program_1);
  assert (SERVER.srv && SYNCER.clnt);
  SERVER.srv->setcb (wrap (&transport_dispatch));

  SYNCER.syncer = New refcounted<merkle_syncer> (0, DHASH_CONTENTHASH,
						 SYNCER.tree,
						 wrap (doRPC),
						 wrap (sendblock));
  SERVER.server = New refcounted<merkle_server> (SERVER.tree);
  addHandler (merklesync_program_1,
      wrap (SERVER.server, &merkle_server::dispatch));
  err_flush ();
}

void
finish ()
{
  // Force all destructors to be called, hopefully.
  handledProgs.clear ();
  handlers.clear ();

  SYNCER.syncer = NULL;
  SERVER.server = NULL;
  SYNCER.clnt = NULL;
  SERVER.srv  = NULL;
  SYNCER.tree = NULL;
  SERVER.tree = NULL;

  if (usedisk) {
    unlink (server_index);
    unlink (server_internal);
    unlink (server_leaf);
    unlink (server_index_ro);
    unlink (server_internal_ro);
    unlink (server_leaf_ro);

    unlink (syncer_index);
    unlink (syncer_internal);
    unlink (syncer_leaf);
    unlink (syncer_index_ro);
    unlink (syncer_internal_ro);
    unlink (syncer_leaf_ro);
  }
}

void
addrand (ptr<merkle_tree> tr, int count)
{
  for (int i = 0; i < count; i++) {
    merkle_hash key;
    key.randomize ();
    tr->insert (key);
    if ((i % 1000) == 0) {
      warn << "inserted " << i << " blocks..of " << count << "\n";
      err_flush ();
    }
  }
}

void
check_invariants ()
{
  warn << "Checking server invariants... ";
  SERVER.tree->check_invariants ();
  warn << "OK\n";
  warn << "Checking syncer invariants... ";
  SYNCER.tree->check_invariants ();
  warn << "OK\n";
}

void check_equal_roots ()
{
  warn << "Checking that roots are equal... ";
  merkle_node *serv_root = SERVER.tree->get_root ();
  merkle_node *sync_root = SYNCER.tree->get_root ();
  if (serv_root->hash != sync_root->hash) {
    warn << "SERVER.tree->root " << serv_root->hash << " cnt " << serv_root->count << "\n";
    warn << "SYNCER.tree->root " << sync_root->hash << " cnt " << sync_root->count << "\n";
    fatal << "NOT OK!\n";
  }
  SERVER.tree->lookup_release (serv_root);
  SYNCER.tree->lookup_release (sync_root);
  warn << "OK\n";
}
// }}}

void
runsync (chordID rngmin, chordID rngmax)
{
  nkeyspushed = 0;
  nkeyspulled = 0;
  SYNCER.syncer->sync (rngmin, rngmax);
  while (!SYNCER.syncer->done ()) {
    acheck ();

    while (keys_for_server.size ()) {
      chordID k = keys_for_server.pop_front ();
      merkle_hash key = to_merkle_hash (k);
      SERVER.tree->insert (key);
      nkeyspushed++;
    }
    while (keys_for_syncer.size ()) {
      chordID k = keys_for_syncer.pop_front ();
      merkle_hash key = to_merkle_hash (k);
      SYNCER.tree->insert (key);
      nkeyspulled++;
    }
  }
}

int
main (int argc, char *argv[])
{
  if (argc > 1)
    modlogger::setmaxprio (modlogger::TRACE);

  // Make sure no old state remains on disk.
  finish ();

  bigint idzero = 0;
  bigint idmax  = (bigint (1) << 160)  - 1;

  // Empty A, Empty B, Complete range
  // ==> A should equal B.
  // ==> Resync should move no keys.
  setup ();
  runsync (idzero, idmax);
  check_invariants ();
  assert (nkeyspushed == 0);
  assert (nkeyspulled == 0);
  check_equal_roots ();
  runsync (idzero, idmax);
  check_invariants ();
  assert (nkeyspushed == 0);
  assert (nkeyspulled == 0);
  dump_stats ();
  finish ();

  // Empty A, Non-empty B, Complete range
  // ==> A should equal B.
  // ==> Resync should move no keys.
  setup ();
  addrand (SERVER.tree, 256);
  runsync (idzero, idmax);
  check_invariants ();
  check_equal_roots ();
  runsync (idzero, idmax);
  check_invariants ();
  assert (nkeyspushed == 0);
  assert (nkeyspulled == 0);
  dump_stats ();
  finish ();

  // Non-empty A, Empty B, Complete range
  // ==> A should equal B.
  // ==> Resync should move no keys.
  setup ();
  addrand (SYNCER.tree, 1024);
  runsync (idzero, idmax);
  check_invariants ();
  check_equal_roots ();
  runsync (idzero, idmax);
  check_invariants ();
  assert (nkeyspushed == 0);
  assert (nkeyspulled == 0);
  dump_stats ();
  finish ();

  // Non-empty A, Non-empty B, Complete range
  // ==> A should equal B.
  // ==> Resync should move no keys.
  setup ();
  addrand (SYNCER.tree, 4097);
  addrand (SERVER.tree, 4097);
  runsync (idzero, idmax);
  check_invariants ();
  check_equal_roots ();
  runsync (idzero, idmax);
  check_invariants ();
  assert (nkeyspushed == 0);
  assert (nkeyspulled == 0);

  // Now test resynchronization after writes.
  addrand (SERVER.tree, 257);
  runsync (idzero, idmax);
  check_equal_roots ();
  assert (nkeyspulled == 257);
  assert (nkeyspushed == 0);
  addrand (SYNCER.tree, 257);
  runsync (idzero, idmax);
  check_equal_roots ();
  assert (nkeyspulled == 0);
  assert (nkeyspushed == 257);

  addrand (SERVER.tree, 3);
  addrand (SYNCER.tree, 5);
  runsync (idzero, idmax);
  check_equal_roots ();
  assert (nkeyspulled == 3);
  assert (nkeyspushed == 5);

  dump_stats ();
  finish ();

  // XXX Should we test various degrees of commonality in A/B?
  //
  // Same as above, but for a partial range.
  // The results are that A will not equal B, but resync won't
  // exchange any keys.
}

/* vim:set foldmethod=marker: */
<commit_msg>Add test that perturbs client/server merkle_trees during sync.<commit_after>#include <chord.h>
#include <modlogger.h>
#include <id_utils.h>
#include "merkle.h"
#include "merkle_tree_disk.h"
#include <location.h>
#include <transport_prot.h>
#include <comm.h>

// {{{ Globals
static const bool usedisk = false;

static struct {
  ptr<merkle_tree> tree;
  ptr<merkle_server> server;
  ptr<asrv> srv;
} SERVER;

static struct {
  ptr<merkle_tree> tree;
  ptr<merkle_syncer> syncer;
  ptr<aclnt> clnt;
} SYNCER;

u_int32_t nkeyspushed = 0;
u_int32_t nkeyspulled = 0;
vec<chordID> keys_for_server;
vec<chordID> keys_for_syncer;

str server_index = "/tmp/server.index.mrk";
str server_internal = "/tmp/server.internal.mrk";
str server_leaf = "/tmp/server.leaf.mrk";
str syncer_index = "/tmp/syncer.index.mrk";
str syncer_internal = "/tmp/syncer.internal.mrk";
str syncer_leaf = "/tmp/syncer.leaf.mrk";

str server_index_ro = "/tmp/server.index.mrk.ro";
str server_internal_ro = "/tmp/server.internal.mrk.ro";
str server_leaf_ro = "/tmp/server.leaf.mrk.ro";
str syncer_index_ro = "/tmp/syncer.index.mrk.ro";
str syncer_internal_ro = "/tmp/syncer.internal.mrk.ro";
str syncer_leaf_ro = "/tmp/syncer.leaf.mrk.ro";
// }}}

// {{{ RPC Magic
static void
doRPCcb (xdrproc_t proc, dorpc_res *res, aclnt_cb cb, void *out, clnt_stat err)
{
  xdrmem x ((char *)res->resok->results.base (),
	    res->resok->results.size (), XDR_DECODE);

  if (err) {
    warnx << "doRPC: err = " << err << "\n";
    assert (!err);
  } else if (!proc (x.xdrp (), out)) {
    warnx << "failed to unmarshall result\n";
    cb (RPC_CANTSEND);
    return;
  }
  cb (err);
  delete res;
}

// called by syncer to perform merkle RPC to server
static void
doRPC (RPC_delay_args *a)
{
  //form the transport RPC
  ptr<dorpc_arg> arg = New refcounted<dorpc_arg> ();
  // Other fields don't matter.
  arg->progno = a->prog.progno;
  arg->procno = a->procno;

  xdrproc_t inproc = a->prog.tbl[a->procno].xdr_arg;
  xdrproc_t outproc = a->prog.tbl[a->procno].xdr_res;
  assert (outproc);
  xdrsuio x (XDR_ENCODE);
  if ((!inproc) || (!inproc (x.xdrp (), (void *)a->in))) {
    fatal << "failed to marshall args\n";
  }
  int args_len = x.uio ()->resid ();
  arg->args.setsize (args_len);
  void *marshalled_args = suio_flatten (x.uio ());
  memcpy (arg->args.base (), marshalled_args, args_len);
  free (marshalled_args);

  dorpc_res *res = New dorpc_res (DORPC_OK);
  SYNCER.clnt->call (TRANSPORTPROC_DORPC, arg, res,
                     wrap (&doRPCcb, outproc, res, a->cb, a->out));
}

vec<const rpc_program *> handledProgs;
vec<cbdispatch_t> handlers;

static void
transport_dispatch (svccb *sbp)
{
  if (!sbp) {
    warnx << "transport server eof\n";
    return;
  }

  dorpc_arg *arg = sbp->Xtmpl getarg<dorpc_arg> ();

  chord_node_wire nw;
  bzero (&nw, sizeof (chord_node_wire));

  const rpc_program *prog (NULL);
  unsigned int i (0);
  for (unsigned int i = 0; i < handledProgs.size (); i++)
    if (arg->progno == (int)handledProgs[i]->progno) {
      prog = handledProgs[i];
      break;
    }
  char *arg_base = (char *)(arg->args.base ());
  int arg_len = arg->args.size ();

  xdrmem x (arg_base, arg_len, XDR_DECODE);
  xdrproc_t proc = prog->tbl[arg->procno].xdr_arg;
  assert (proc);

  void *unmarshalled_args = prog->tbl[arg->procno].alloc_arg ();
  if (!proc (x.xdrp (), unmarshalled_args)) {
    warn << "dispatch: error unmarshalling arguments: "
	 << arg->progno << "." << arg->procno << "\n";
    xdr_delete (prog->tbl[arg->procno].xdr_arg, unmarshalled_args);
    sbp->replyref (rpcstat (DORPC_MARSHALLERR));
    return;
  }
  user_args *ua = New user_args (sbp, unmarshalled_args,
				 prog, arg->procno, 0);
  ua->me_ = New refcounted<location> (make_chord_node (nw));
  handlers[i] (ua);
}

// called by server to register handler fielding merkle RPCs
static void
addHandler (const rpc_program &prog, cbdispatch_t cb)
{
  handledProgs.push_back (&prog);
  handlers.push_back (cb);
}
// }}}
// {{{ Testing framework - setup/finish/addrand/dump_stats
static void
sendblock (bigint blockID, bool missingLocal)
{
  if (missingLocal)
    keys_for_syncer.push_back (blockID);
  else
    keys_for_server.push_back (blockID);
}

void
dump_stats ()
{
  warn  << "+++++++++++++++++++++++++SERVER.tree++++++++++++++++++++++++++++++\n";
  SERVER.tree->compute_stats ();
  // SERVER.tree->dump ();
  warn  << "+++++++++++++++++++++++++SYNCER.tree++++++++++++++++++++++++++++++\n";
  SYNCER.tree->compute_stats ();
  // SYNCER.tree->dump ();
}

void
setup ()
{
  warn << "===> setup() +++++++++++++++++++++++++++\n";
  if (usedisk) {
    SERVER.tree = New refcounted<merkle_tree_disk> (server_index,
						    server_internal, server_leaf,
						    true);
    SYNCER.tree = New refcounted<merkle_tree_disk> (syncer_index,
						    syncer_internal, syncer_leaf,
						    true);
  } else {
    SERVER.tree = New refcounted<merkle_tree> ();
    SYNCER.tree = New refcounted<merkle_tree> ();
  }

  // these are closed by axprt_stream's dtor, right?
  int fds[2];
  assert (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) == 0);
  warn << "  sockets: " << fds[0] << ":" << fds[1] << "\n";
  SERVER.srv = asrv::alloc (axprt_stream::alloc (fds[0]), transport_program_1);
  SYNCER.clnt = aclnt::alloc (axprt_stream::alloc (fds[1]), transport_program_1);
  assert (SERVER.srv && SYNCER.clnt);
  SERVER.srv->setcb (wrap (&transport_dispatch));

  SYNCER.syncer = New refcounted<merkle_syncer> (0, DHASH_CONTENTHASH,
						 SYNCER.tree,
						 wrap (doRPC),
						 wrap (sendblock));
  SERVER.server = New refcounted<merkle_server> (SERVER.tree);
  addHandler (merklesync_program_1,
      wrap (SERVER.server, &merkle_server::dispatch));
  err_flush ();
}

void
finish ()
{
  // Force all destructors to be called, hopefully.
  handledProgs.clear ();
  handlers.clear ();

  SYNCER.syncer = NULL;
  SERVER.server = NULL;
  SYNCER.clnt = NULL;
  SERVER.srv  = NULL;
  SYNCER.tree = NULL;
  SERVER.tree = NULL;

  if (usedisk) {
    unlink (server_index);
    unlink (server_internal);
    unlink (server_leaf);
    unlink (server_index_ro);
    unlink (server_internal_ro);
    unlink (server_leaf_ro);

    unlink (syncer_index);
    unlink (syncer_internal);
    unlink (syncer_leaf);
    unlink (syncer_index_ro);
    unlink (syncer_internal_ro);
    unlink (syncer_leaf_ro);
  }
}

void
addrand (ptr<merkle_tree> tr, int count)
{
  for (int i = 0; i < count; i++) {
    merkle_hash key;
    key.randomize ();
    tr->insert (key);
    if ((i % 1000) == 0) {
      warn << "inserted " << i << " blocks..of " << count << "\n";
      err_flush ();
    }
  }
}

void
removesome (ptr<merkle_tree> tr, int count, bool rand = false)
{
  static bigint idmax = (bigint (1) << 160) - 1;
  int maxtries = 2*count;
  int nremoved = 0;
  while (nremoved < count && maxtries > 0) {
    maxtries--;
    merkle_hash key (0);
    if (rand)
      key.randomize ();
    vec<chordID> keys = tr->get_keyrange (tobigint (key), idmax, count);
    while (keys.size () && (nremoved < count)) {
      nremoved++;
      tr->remove (keys.back ());
      keys.pop_back ();
    }
  }
  warnx << "Removed " << nremoved << " keys\n";
}

void
check_invariants ()
{
  warn << "Checking server invariants... ";
  SERVER.tree->check_invariants ();
  warn << "OK\n";
  warn << "Checking syncer invariants... ";
  SYNCER.tree->check_invariants ();
  warn << "OK\n";
}

void check_equal_roots ()
{
  warn << "Checking that roots are equal... ";
  merkle_node *serv_root = SERVER.tree->get_root ();
  merkle_node *sync_root = SYNCER.tree->get_root ();
  if (serv_root->hash != sync_root->hash) {
    warn << "SERVER.tree->root " << serv_root->hash << " cnt " << serv_root->count << "\n";
    warn << "SYNCER.tree->root " << sync_root->hash << " cnt " << sync_root->count << "\n";
    fatal << "NOT OK!\n";
  }
  SERVER.tree->lookup_release (serv_root);
  SYNCER.tree->lookup_release (sync_root);
  warn << "OK\n";
}
// }}}

void
runsync (chordID rngmin, chordID rngmax, bool perturb = false)
{
  nkeyspushed = 0;
  nkeyspulled = 0;
  SYNCER.syncer->sync (rngmin, rngmax);
  while (!SYNCER.syncer->done ()) {
    if (perturb) {
      long int bits = random ();
      ptr<merkle_tree> t = ((bits>>1)&0x1) ? SYNCER.tree : SERVER.tree;
      if (bits & 0x1)
	addrand (t, 64);
      else
	removesome (t, 64);
    }
    acheck ();

    while (keys_for_server.size ()) {
      chordID k = keys_for_server.pop_front ();
      merkle_hash key = to_merkle_hash (k);
      SERVER.tree->insert (key);
      nkeyspushed++;
    }
    while (keys_for_syncer.size ()) {
      chordID k = keys_for_syncer.pop_front ();
      merkle_hash key = to_merkle_hash (k);
      SYNCER.tree->insert (key);
      nkeyspulled++;
    }
  }
}

int
main (int argc, char *argv[])
{
  if (argc > 1)
    modlogger::setmaxprio (modlogger::TRACE);

  // Make sure no old state remains on disk.
  finish ();

  bigint idzero = 0;
  bigint idmax  = (bigint (1) << 160)  - 1;

  // Empty A, Empty B, Complete range
  // ==> A should equal B.
  // ==> Resync should move no keys.
  setup ();
  runsync (idzero, idmax);
  check_invariants ();
  assert (nkeyspushed == 0);
  assert (nkeyspulled == 0);
  check_equal_roots ();
  runsync (idzero, idmax);
  check_invariants ();
  assert (nkeyspushed == 0);
  assert (nkeyspulled == 0);
  dump_stats ();
  finish ();

  // Empty A, Non-empty B, Complete range
  // ==> A should equal B.
  // ==> Resync should move no keys.
  setup ();
  addrand (SERVER.tree, 256);
  runsync (idzero, idmax);
  check_invariants ();
  check_equal_roots ();
  runsync (idzero, idmax);
  check_invariants ();
  assert (nkeyspushed == 0);
  assert (nkeyspulled == 0);
  dump_stats ();
  finish ();

  // Non-empty A, Empty B, Complete range
  // ==> A should equal B.
  // ==> Resync should move no keys.
  setup ();
  addrand (SYNCER.tree, 1024);
  runsync (idzero, idmax);
  check_invariants ();
  check_equal_roots ();
  runsync (idzero, idmax);
  check_invariants ();
  assert (nkeyspushed == 0);
  assert (nkeyspulled == 0);
  dump_stats ();
  finish ();

  // Non-empty A, Non-empty B, Complete range
  // ==> A should equal B.
  // ==> Resync should move no keys.
  setup ();
  addrand (SYNCER.tree, 4097);
  addrand (SERVER.tree, 4097);
  runsync (idzero, idmax);
  check_invariants ();
  check_equal_roots ();
  runsync (idzero, idmax);
  check_invariants ();
  assert (nkeyspushed == 0);
  assert (nkeyspulled == 0);

  // Now test resynchronization after writes.
  addrand (SERVER.tree, 257);
  runsync (idzero, idmax);
  check_equal_roots ();
  assert (nkeyspulled == 257);
  assert (nkeyspushed == 0);
  addrand (SYNCER.tree, 257);
  runsync (idzero, idmax);
  check_equal_roots ();
  assert (nkeyspulled == 0);
  assert (nkeyspushed == 257);

  addrand (SERVER.tree, 3);
  addrand (SYNCER.tree, 5);
  runsync (idzero, idmax);
  check_equal_roots ();
  assert (nkeyspulled == 3);
  assert (nkeyspushed == 5);

  dump_stats ();
  finish ();

  setup ();
  addrand (SYNCER.tree, 4097);
  addrand (SERVER.tree, 4097);
  runsync (idzero, idmax, true);
  runsync (idzero, idmax, false);
  check_invariants ();
  check_equal_roots ();
  finish ();

  // XXX Should we test various degrees of commonality in A/B?
  //
  // Same as above, but for a partial range.
  // The results are that A will not equal B, but resync won't
  // exchange any keys.
}

/* vim:set foldmethod=marker: */
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include "WARCReader.h"
#include "WARCRecord.h"
#include "WARCException.h"
#include "CSVWriter.h"
#include "tclap/CmdLine.h"
#include "rapidjson/Pointer.h"

void writeCSVHeader(CSV::Writer&);
void processWARC(std::istream&, CSV::Writer&, int);

constexpr int noVerbosity = 0;
constexpr int lowVerbosity = 1;
constexpr int medVerbosity = 2;
constexpr int highVerbosity = 3;

int main(int argc, char** argv) {
    std::istream* input;
    std::ostream* output;

    TCLAP::CmdLine cmd("meta-extractor", ' ', "0.1");
    TCLAP::ValueArg<std::string> inFile("i", "input", "Input file", false, "", "file", cmd);
    TCLAP::ValueArg<std::string> outFile("o", "output", "Output file", false, "", "file", cmd);
    TCLAP::MultiSwitchArg verbosity("v", "verbose", "Verbose Output", cmd, noVerbosity);
    try {
        cmd.parse(argc, argv);
    } catch(TCLAP::ArgException &e) {
        std::cerr << "command line parsing error: " << e.what() << std::endl;
        return 1;
    }

    std::ifstream inFileStream;
    if(inFile.isSet()) {
        inFileStream.open(inFile.getValue(), std::ifstream::binary);
        if(!inFileStream.good()) {
            std::cerr << "input file not found" << std::endl;
            return 2;
        }
        input = &inFileStream;
    } else {
        input = &std::cin;
    }

    std::ofstream outFileStream;
    if(outFile.isSet()) {
        outFileStream.open(outFile.getValue(), std::ifstream::binary);
        if(!outFileStream.good()) {
            std::cerr << "output file not found" << std::endl;
            return 3;
        }
        output = &outFileStream;
    } else {
        output = &std::cout;
    }

    try {
        CSV::Writer csv(*output);

        writeCSVHeader(csv);
        processWARC(*input, csv, verbosity.getValue());
    } catch(const std::exception& e) {
        std::cerr << "Exception occurred: " << e.what() << std::endl;
        return 10;
    }

    return 0;
}

void writeCSVHeader(CSV::Writer& csv) {
    csv
        << "time"               // uint32 : unix timestamp (of crawl)
        << "protocol"           // bool   : http[s]
        << "sl-domain"          // string : amazon.co.uk
        << "tld"                // string : uk
        << "public suffix"      // string : co.uk
        << "path depth"         // uint8  : (number of slashes)
        << "path length"        // uint16 :
        << "server (all)"       // string : Apache (2.4)
        // TODO: server (name) only as enum value?
        << "server (name)"      // string : Apache
        << "caching"            // ?
        << "cookies"            // uint16 : number of cookies used
        << "mime"               // string : mime-type e. g. text/html
        << "encoding"           // string : e. g. UTF-8
        // TODO: add rest of fields
        << "scripts"            // string : string[] - clustering
        << "styles"             // string : string[] - clustering
        << "cdn"                // bool   : uses CDNs or not
        << "links (intern)"     // uint16
        << "links (extern)";    // uint16

    csv.next();
}

void processWARC(std::istream& input, CSV::Writer&, int verbosity) {
    using Pointer = rapidjson::Pointer;

    WARC::Reader reader(input);
    WARC::Record<rapidjson::Document> record;
    uint32_t countProcessed {0}, countIgnored {0};

    const Pointer pContentType("/Envelope/WARC-Header-Metadata/Content-Type");

    while(reader.read(record)) {
        // this is not a json record
        if(!record.valid) {
            record.clear();
            continue;
        }

        std::string contentType;
        if(auto jContentType = pContentType.Get(record.content)) {
            contentType = jContentType->GetString();
        } else {
            throw WARC::Exception("Invalid WAT: missing Content-Type");
        }

        if (contentType == "application/http; msgtype=response") {
            ++countProcessed;
            // TODO: Output data
        } else {
            ++countIgnored;
        }

        if (verbosity >= highVerbosity) {
            std::cerr << record.id << ", " << record.date << ", "
                      << record.length << " bytes, "
                      << contentType << std::endl;
        }

        // clear record because it is reused
        record.clear();
    }

    if(verbosity >= lowVerbosity) {
        std::cerr << countProcessed << " records processed, "
                  << countIgnored << " records ignored because of Content-Type"
                  << std::endl;
    }
}
<commit_msg>Add convenience function for extracting values from the json dom<commit_after>#include <iostream>
#include <fstream>
#include "WARCReader.h"
#include "WARCRecord.h"
#include "WARCException.h"
#include "CSVWriter.h"
#include "tclap/CmdLine.h"
#include "rapidjson/Pointer.h"
#include "rapidjson/StringBuffer.h"

void writeCSVHeader(CSV::Writer&);
void processWARC(std::istream&, CSV::Writer&, int);
const rapidjson::Value& extract(const rapidjson::Document&, const rapidjson::Pointer&);

constexpr int noVerbosity = 0;
constexpr int lowVerbosity = 1;
constexpr int medVerbosity = 2;
constexpr int highVerbosity = 3;

int main(int argc, char** argv) {
    std::istream* input;
    std::ostream* output;

    TCLAP::CmdLine cmd("meta-extractor", ' ', "0.1");
    TCLAP::ValueArg<std::string> inFile("i", "input", "Input file", false, "", "file", cmd);
    TCLAP::ValueArg<std::string> outFile("o", "output", "Output file", false, "", "file", cmd);
    TCLAP::MultiSwitchArg verbosity("v", "verbose", "Verbose Output", cmd, noVerbosity);
    try {
        cmd.parse(argc, argv);
    } catch(TCLAP::ArgException &e) {
        std::cerr << "command line parsing error: " << e.what() << std::endl;
        return 1;
    }

    std::ifstream inFileStream;
    if(inFile.isSet()) {
        inFileStream.open(inFile.getValue(), std::ifstream::binary);
        if(!inFileStream.good()) {
            std::cerr << "input file not found" << std::endl;
            return 2;
        }
        input = &inFileStream;
    } else {
        input = &std::cin;
    }

    std::ofstream outFileStream;
    if(outFile.isSet()) {
        outFileStream.open(outFile.getValue(), std::ifstream::binary);
        if(!outFileStream.good()) {
            std::cerr << "output file not found" << std::endl;
            return 3;
        }
        output = &outFileStream;
    } else {
        output = &std::cout;
    }

    try {
        CSV::Writer csv(*output);

        writeCSVHeader(csv);
        processWARC(*input, csv, verbosity.getValue());
    } catch(const std::exception& e) {
        std::cerr << "Exception occurred: " << e.what() << std::endl;
        return 10;
    }

    return 0;
}

void writeCSVHeader(CSV::Writer& csv) {
    csv
        << "time"               // uint32 : unix timestamp (of crawl)
        << "protocol"           // bool   : http[s]
        << "sl-domain"          // string : amazon.co.uk
        << "tld"                // string : uk
        << "public suffix"      // string : co.uk
        << "path depth"         // uint8  : (number of slashes)
        << "path length"        // uint16 :
        << "server (all)"       // string : Apache (2.4)
        // TODO: server (name) only as enum value?
        << "server (name)"      // string : Apache
        << "caching"            // ?
        << "cookies"            // uint16 : number of cookies used
        << "mime"               // string : mime-type e. g. text/html
        << "encoding"           // string : e. g. UTF-8
        // TODO: add rest of fields
        << "scripts"            // string : string[] - clustering
        << "styles"             // string : string[] - clustering
        << "cdn"                // bool   : uses CDNs or not
        << "links (intern)"     // uint16
        << "links (extern)";    // uint16

    csv.next();
}

void processWARC(std::istream& input, CSV::Writer&, int verbosity) {
    using Pointer = rapidjson::Pointer;

    WARC::Reader reader(input);
    WARC::Record<rapidjson::Document> record;
    uint32_t countProcessed {0}, countIgnored {0};

    const Pointer pContentType("/Envelope/WARC-Header-Metadata/Content-Type");

    while(reader.read(record)) {
        // this is not a json record
        if(!record.valid) {
            record.clear();
            continue;
        }

        std::string contentType;
        if(auto jContentType = pContentType.Get(record.content)) {
            contentType = jContentType->GetString();
        } else {
            throw WARC::Exception("Invalid WAT: missing Content-Type");
        }

        if (contentType == "application/http; msgtype=response") {
            ++countProcessed;
            // TODO: Output data
        } else {
            ++countIgnored;
        }

        if (verbosity >= highVerbosity) {
            std::cerr << record.id << ", " << record.date << ", "
                      << record.length << " bytes, "
                      << contentType << std::endl;
        }

        // clear record because it is reused
        record.clear();
    }

    if(verbosity >= lowVerbosity) {
        std::cerr << countProcessed << " records processed, "
                  << countIgnored << " records ignored because of Content-Type"
                  << std::endl;
    }
}

const rapidjson::Value& extract(const rapidjson::Document& doc, const rapidjson::Pointer& pointer) {
    if(auto value = pointer.Get(doc)) {
        // Returning a reference is ok, because the object is stored in the doc
        return *value;
    } else {
        rapidjson::StringBuffer pointerString;
        pointer.Stringify(pointerString);
        throw WARC::Exception(std::string("Invalid WAT: missing entry ")
                              .append(pointerString.GetString()));
    }
}
<|endoftext|>


<commit_before>#include <unittest.hpp>

int main() {

  UnitTest::print_statistics();
  return 0;
}<commit_msg>return code in tests<commit_after>#include <unittest.hpp>

int main() {
  UnitTest::print_statistics();
  int r = UnitTest::tests - UnitTest::passed;
  return r > 0 ? 1 : 0;
}
<|endoftext|>


<commit_before>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

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 "tensorflow/compiler/xla/service/memory_space_assignment_utils.h"

#include "tensorflow/compiler/xla/service/hlo_casting_utils.h"
#include "tensorflow/compiler/xla/service/hlo_instructions.h"

namespace xla {

bool MemorySpaceAssignmentUtils::IsValueAllowedInAlternateMemory(
    const HloValue* value) {
  // If the buffer is a tuple, don't use this algorithm for now. The buffers
  // that are pointed to by the tuple will still use this algorithm.  Because
  // tuples are cheap to place in the alternate memory (they are just pointers)
  // we don't need to use prefetch/evict logic.
  if (value->shape().IsTuple()) {
    VLOG(4) << "Keeping value " << value->ToShortString()
            << " in default mem because it is a tuple.";
    return false;
  }

  // Don't place scalars in the alternate memory.
  if (ShapeUtil::IsEffectiveScalar(value->shape())) {
    VLOG(4) << "Keeping value " << value->ToShortString()
            << " in default mem because it is a scalar.";
    return false;
  }

  // The semantics of TupleSelect are weird: TupleSelect doesn't define a
  // buffer, but just forwards the buffers in the either left or right side.
  // This means the two different inputs to TupleSelect must not alias, yet they
  // should be allocated in the same memory space, and both buffers must be kept
  // alive for the entire live range of TupleSelect. Instead, just don't
  // allocate TupleSelect in the alternate memory space.
  // TODO(berkin): Not allocating add-dependencies either since they need to be
  // treated specially. We should revisit this later.
  for (const HloPosition& position : value->positions()) {
    if (position.instruction->opcode() == HloOpcode::kTupleSelect ||
        position.instruction->opcode() == HloOpcode::kAddDependency) {
      VLOG(4) << "Keeping value " << value->ToShortString()
              << " in default mem because it has a tuple-select or "
              << "add-dependency position.";
      return false;
    }
  }

  // Send and Recv HLOs return a request identifier. These should not be
  // allocated in the alternate memory.
  for (const HloPosition& position : value->positions()) {
    if ((position.instruction->opcode() == HloOpcode::kSend ||
         position.instruction->opcode() == HloOpcode::kRecv) &&
        DynCast<HloSendRecvInstruction>(position.instruction)
            ->is_host_transfer()) {
      // TODO(berkin): Host transfers using alternate memory space doesn't seem
      // to work at the moment.
      VLOG(4) << "Keeping value " << value->ToShortString()
              << " in default mem because it is a send/recv buffer used for "
                 "host transfer.";
      return false;
    }

    if (auto* custom_call =
            DynCast<HloCustomCallInstruction>(position.instruction)) {
      for (const auto& pair : custom_call->output_to_operand_aliasing()) {
        if (position.index == pair.first) {
          VLOG(4) << "Keeping value " << value->ToShortString()
                  << " in default mem because it is a custom-call output that "
                     "aliases an operand buffer.";
          return false;
        }
      }
    }
  }

  return true;
}

bool MemorySpaceAssignmentUtils::IsIntervalAllowedInAlternateMemory(
    const GlobalDecreasingSizeBestFitHeap<HloValue>::BufferInterval& interval) {
  return IsValueAllowedInAlternateMemory(interval.buffer) &&
         absl::c_all_of(interval.colocations, IsValueAllowedInAlternateMemory);
}

/*static*/ void MemorySpaceAssignmentUtils::HoistConstantOperations(
    HloModule& module) {
  CHECK(module.has_schedule());
  HloSchedule& schedule = module.schedule();
  for (const HloComputation* computation : module.MakeNonfusionComputations()) {
    CHECK(schedule.is_computation_scheduled(computation));
    const HloInstructionSequence& sequence = schedule.sequence(computation);
    HloInstructionSequence new_sequence;

    for (HloInstruction* instruction : sequence.instructions()) {
      if (instruction->opcode() == HloOpcode::kConstant) {
        new_sequence.push_back(instruction);
      }
    }
    for (HloInstruction* instruction : sequence.instructions()) {
      if (instruction->opcode() != HloOpcode::kConstant) {
        new_sequence.push_back(instruction);
      }
    }
    CHECK_EQ(new_sequence.size(), sequence.size());
    schedule.set_sequence(computation, new_sequence);
  }
}

}  // namespace xla
<commit_msg>[XLA] Don't hoist constants if the computation contains any instruction with control predecessor or successor on a constant<commit_after>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

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 "tensorflow/compiler/xla/service/memory_space_assignment_utils.h"

#include "tensorflow/compiler/xla/service/hlo_casting_utils.h"
#include "tensorflow/compiler/xla/service/hlo_instructions.h"

namespace xla {

bool MemorySpaceAssignmentUtils::IsValueAllowedInAlternateMemory(
    const HloValue* value) {
  // If the buffer is a tuple, don't use this algorithm for now. The buffers
  // that are pointed to by the tuple will still use this algorithm.  Because
  // tuples are cheap to place in the alternate memory (they are just pointers)
  // we don't need to use prefetch/evict logic.
  if (value->shape().IsTuple()) {
    VLOG(4) << "Keeping value " << value->ToShortString()
            << " in default mem because it is a tuple.";
    return false;
  }

  // Don't place scalars in the alternate memory.
  if (ShapeUtil::IsEffectiveScalar(value->shape())) {
    VLOG(4) << "Keeping value " << value->ToShortString()
            << " in default mem because it is a scalar.";
    return false;
  }

  // The semantics of TupleSelect are weird: TupleSelect doesn't define a
  // buffer, but just forwards the buffers in the either left or right side.
  // This means the two different inputs to TupleSelect must not alias, yet they
  // should be allocated in the same memory space, and both buffers must be kept
  // alive for the entire live range of TupleSelect. Instead, just don't
  // allocate TupleSelect in the alternate memory space.
  // TODO(berkin): Not allocating add-dependencies either since they need to be
  // treated specially. We should revisit this later.
  for (const HloPosition& position : value->positions()) {
    if (position.instruction->opcode() == HloOpcode::kTupleSelect ||
        position.instruction->opcode() == HloOpcode::kAddDependency) {
      VLOG(4) << "Keeping value " << value->ToShortString()
              << " in default mem because it has a tuple-select or "
              << "add-dependency position.";
      return false;
    }
  }

  // Send and Recv HLOs return a request identifier. These should not be
  // allocated in the alternate memory.
  for (const HloPosition& position : value->positions()) {
    if ((position.instruction->opcode() == HloOpcode::kSend ||
         position.instruction->opcode() == HloOpcode::kRecv) &&
        DynCast<HloSendRecvInstruction>(position.instruction)
            ->is_host_transfer()) {
      // TODO(berkin): Host transfers using alternate memory space doesn't seem
      // to work at the moment.
      VLOG(4) << "Keeping value " << value->ToShortString()
              << " in default mem because it is a send/recv buffer used for "
                 "host transfer.";
      return false;
    }

    if (auto* custom_call =
            DynCast<HloCustomCallInstruction>(position.instruction)) {
      for (const auto& pair : custom_call->output_to_operand_aliasing()) {
        if (position.index == pair.first) {
          VLOG(4) << "Keeping value " << value->ToShortString()
                  << " in default mem because it is a custom-call output that "
                     "aliases an operand buffer.";
          return false;
        }
      }
    }
  }

  return true;
}

bool MemorySpaceAssignmentUtils::IsIntervalAllowedInAlternateMemory(
    const GlobalDecreasingSizeBestFitHeap<HloValue>::BufferInterval& interval) {
  return IsValueAllowedInAlternateMemory(interval.buffer) &&
         absl::c_all_of(interval.colocations, IsValueAllowedInAlternateMemory);
}

/*static*/ void MemorySpaceAssignmentUtils::HoistConstantOperations(
    HloModule& module) {
  CHECK(module.has_schedule());
  HloSchedule& schedule = module.schedule();
  for (const HloComputation* computation : module.MakeNonfusionComputations()) {
    CHECK(schedule.is_computation_scheduled(computation));
    const HloInstructionSequence& sequence = schedule.sequence(computation);
    // Conservatively don't modify the schedule if any instruction has a control
    // successor or predecessor on a constant op. Computations with these
    // dependencies should be very rare anyway.
    bool contains_constant_successor_or_predecessors = false;
    for (HloInstruction* instruction : sequence.instructions()) {
      if (instruction->opcode() == HloOpcode::kConstant) {
        contains_constant_successor_or_predecessors |=
            !instruction->control_predecessors().empty();
        contains_constant_successor_or_predecessors |=
            !instruction->control_successors().empty();
      } else {
        auto is_constant = [](const HloInstruction* inst) {
          return inst->opcode() == HloOpcode::kConstant;
        };
        contains_constant_successor_or_predecessors |=
            absl::c_find_if(instruction->control_predecessors(), is_constant) !=
            instruction->control_predecessors().end();
        contains_constant_successor_or_predecessors |=
            absl::c_find_if(instruction->control_successors(), is_constant) !=
            instruction->control_successors().end();
      }
    }
    if (contains_constant_successor_or_predecessors) {
      continue;
    }
    HloInstructionSequence new_sequence;

    for (HloInstruction* instruction : sequence.instructions()) {
      if (instruction->opcode() == HloOpcode::kConstant) {
        new_sequence.push_back(instruction);
      }
    }
    for (HloInstruction* instruction : sequence.instructions()) {
      if (instruction->opcode() != HloOpcode::kConstant) {
        new_sequence.push_back(instruction);
      }
    }
    CHECK_EQ(new_sequence.size(), sequence.size());
    schedule.set_sequence(computation, new_sequence);
  }
}

}  // namespace xla
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * TIGHTDB CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2012] TightDB Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of TightDB Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to TightDB Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from TightDB Incorporated.
 *
 **************************************************************************/
#ifndef TIGHTDB_COLUMN_STRING_HPP
#define TIGHTDB_COLUMN_STRING_HPP

#include <tightdb/util/unique_ptr.hpp>
#include <tightdb/array_string.hpp>
#include <tightdb/array_string_long.hpp>
#include <tightdb/array_blobs_big.hpp>
#include <tightdb/column.hpp>

namespace tightdb {

// Pre-declarations
class StringIndex;

class AdaptiveStringColumn: public ColumnBase {
public:
    typedef StringData value_type;

    explicit AdaptiveStringColumn(Allocator& = Allocator::get_default());
    explicit AdaptiveStringColumn(ref_type, ArrayParent* = 0, std::size_t ndx_in_parent = 0,
                                  Allocator& = Allocator::get_default());
    ~AdaptiveStringColumn() TIGHTDB_NOEXCEPT TIGHTDB_OVERRIDE;

    void destroy() TIGHTDB_NOEXCEPT TIGHTDB_OVERRIDE;

    std::size_t size() const TIGHTDB_NOEXCEPT;
    bool is_empty() const TIGHTDB_NOEXCEPT { return size() == 0; }

    StringData get(std::size_t ndx) const TIGHTDB_NOEXCEPT;
    void add() TIGHTDB_OVERRIDE { return add(StringData()); }
    void add(StringData);
    void set(std::size_t ndx, StringData);
    void insert(std::size_t ndx) TIGHTDB_OVERRIDE { insert(ndx, StringData()); }
    void insert(std::size_t ndx, StringData);
    void erase(std::size_t ndx, bool is_last) TIGHTDB_OVERRIDE;
    void clear() TIGHTDB_OVERRIDE;
    void move_last_over(std::size_t ndx) TIGHTDB_OVERRIDE;

    std::size_t count(StringData value) const;
    std::size_t find_first(StringData value, std::size_t begin = 0,
                           std::size_t end = npos) const;
    void find_all(Array& result, StringData value, std::size_t begin = 0,
                  std::size_t end = npos) const;

    //@{
    /// Find the lower/upper bound for the specified value assuming
    /// that the elements are already sorted in ascending order
    /// according to StringData::operator<().
    std::size_t lower_bound_string(StringData value) const TIGHTDB_NOEXCEPT;
    std::size_t upper_bound_string(StringData value) const TIGHTDB_NOEXCEPT;
    //@}

    FindRes find_all_indexref(StringData value, std::size_t& dst) const;

    // Index
    bool has_index() const TIGHTDB_NOEXCEPT TIGHTDB_OVERRIDE { return m_index != 0; }
    void set_index_ref(ref_type, ArrayParent*, std::size_t ndx_in_parent) TIGHTDB_OVERRIDE;
    const StringIndex& get_index() const { return *m_index; }
    StringIndex* release_index() TIGHTDB_NOEXCEPT;
    StringIndex& create_index();

    // Optimizing data layout
    bool auto_enumerate(ref_type& keys, ref_type& values) const;

    /// Compare two string columns for equality.
    bool compare_string(const AdaptiveStringColumn&) const;

    enum LeafType {
        leaf_type_Small,  ///< ArrayString
        leaf_type_Medium, ///< ArrayStringLong
        leaf_type_Big     ///< ArrayBigBlobs
    };

    LeafType GetBlock(std::size_t ndx, ArrayParent**, std::size_t& off,
                      bool use_retval = false) const;

    static ref_type create(std::size_t size, Allocator&);

    static std::size_t get_size_from_ref(ref_type root_ref, Allocator&) TIGHTDB_NOEXCEPT;

    // Overrriding method in ColumnBase
    ref_type write(std::size_t, std::size_t, std::size_t,
                   _impl::OutputStream&) const TIGHTDB_OVERRIDE;

    void update_from_parent(std::size_t old_baseline) TIGHTDB_NOEXCEPT TIGHTDB_OVERRIDE;
#ifdef TIGHTDB_DEBUG
    void Verify() const TIGHTDB_OVERRIDE;
    void to_dot(std::ostream&, StringData title) const TIGHTDB_OVERRIDE;
    void dump_node_structure(std::ostream&, int level) const TIGHTDB_OVERRIDE;
    using ColumnBase::dump_node_structure;
#endif

private:
    StringIndex* m_index;

    std::size_t do_get_size() const TIGHTDB_NOEXCEPT TIGHTDB_OVERRIDE { return size(); }

    void do_insert(std::size_t ndx, StringData value);

    // Called by Array::bptree_insert().
    static ref_type leaf_insert(MemRef leaf_mem, ArrayParent&, std::size_t ndx_in_parent,
                                Allocator&, std::size_t insert_ndx,
                                Array::TreeInsert<AdaptiveStringColumn>& state);

    class EraseLeafElem;
    class CreateHandler;
    class SliceHandler;

    /// Root must be a leaf. Upgrades the root leaf as
    /// necessary. Returns the type of the root leaf as it is upon
    /// return.
    LeafType upgrade_root_leaf(std::size_t value_size);

#ifdef TIGHTDB_DEBUG
    void leaf_to_dot(MemRef, ArrayParent*, std::size_t ndx_in_parent,
                     std::ostream&) const TIGHTDB_OVERRIDE;
#endif

    friend class Array;
    friend class ColumnBase;
};

// Implementation:

inline std::size_t AdaptiveStringColumn::size() const TIGHTDB_NOEXCEPT
{
    if (root_is_leaf()) {
        bool long_strings = m_array->has_refs();
        if (!long_strings) {
            // Small strings root leaf
            ArrayString* leaf = static_cast<ArrayString*>(m_array);
            return leaf->size();
        }
        bool is_big = m_array->get_context_flag();
        if (!is_big) {
            // Medium strings root leaf
            ArrayStringLong* leaf = static_cast<ArrayStringLong*>(m_array);
            return leaf->size();
        }
        // Big strings root leaf
        ArrayBigBlobs* leaf = static_cast<ArrayBigBlobs*>(m_array);
        return leaf->size();
    }
    // Non-leaf root
    return m_array->get_bptree_size();
}

inline void AdaptiveStringColumn::add(StringData value)
{
    do_insert(npos, value);
}

inline void AdaptiveStringColumn::insert(size_t ndx, StringData value)
{
    TIGHTDB_ASSERT(ndx <= size());
    if (size() <= ndx)
        ndx = npos;
    do_insert(ndx, value);
}

inline StringIndex* AdaptiveStringColumn::release_index() TIGHTDB_NOEXCEPT
{
    StringIndex* i = m_index;
    m_index = 0;
    return i;
}

inline std::size_t AdaptiveStringColumn::get_size_from_ref(ref_type root_ref,
                                                           Allocator& alloc) TIGHTDB_NOEXCEPT
{
    const char* root_header = alloc.translate(root_ref);
    bool root_is_leaf = !Array::get_is_inner_bptree_node_from_header(root_header);
    if (root_is_leaf) {
        bool long_strings = Array::get_hasrefs_from_header(root_header);
        if (!long_strings) {
            // Small strings leaf
            return ArrayString::get_size_from_header(root_header);
        }
        bool is_big = Array::get_context_flag_from_header(root_header);
        if (!is_big) {
            // Medium strings leaf
            return ArrayStringLong::get_size_from_header(root_header, alloc);
        }
        // Big strings leaf
        return ArrayBigBlobs::get_size_from_header(root_header);
    }
    return Array::get_bptree_size_from_header(root_header);
}

inline void AdaptiveStringColumn::update_from_parent(std::size_t old_baseline) TIGHTDB_NOEXCEPT TIGHTDB_OVERRIDE
{
    if (root_is_leaf()) {
        bool long_strings = m_array->has_refs();
        if (!long_strings) {
            // Small strings root leaf
            ArrayString* leaf = static_cast<ArrayString*>(m_array);
            leaf->update_from_parent(old_baseline);
            return;
        }
        bool is_big = m_array->get_context_flag();
        if (!is_big) {
            // Medium strings root leaf
            ArrayStringLong* leaf = static_cast<ArrayStringLong*>(m_array);
            leaf->update_from_parent(old_baseline);
            return;
        }
        // Big strings root leaf
        ArrayBigBlobs* leaf = static_cast<ArrayBigBlobs*>(m_array);
        leaf->update_from_parent(old_baseline);
        return;
    }
    // Non-leaf root
}

} // namespace tightdb

#endif // TIGHTDB_COLUMN_STRING_HPP
<commit_msg>fix: added non-leaf case<commit_after>/*************************************************************************
 *
 * TIGHTDB CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2012] TightDB Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of TightDB Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to TightDB Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from TightDB Incorporated.
 *
 **************************************************************************/
#ifndef TIGHTDB_COLUMN_STRING_HPP
#define TIGHTDB_COLUMN_STRING_HPP

#include <tightdb/util/unique_ptr.hpp>
#include <tightdb/array_string.hpp>
#include <tightdb/array_string_long.hpp>
#include <tightdb/array_blobs_big.hpp>
#include <tightdb/column.hpp>

namespace tightdb {

// Pre-declarations
class StringIndex;

class AdaptiveStringColumn: public ColumnBase {
public:
    typedef StringData value_type;

    explicit AdaptiveStringColumn(Allocator& = Allocator::get_default());
    explicit AdaptiveStringColumn(ref_type, ArrayParent* = 0, std::size_t ndx_in_parent = 0,
                                  Allocator& = Allocator::get_default());
    ~AdaptiveStringColumn() TIGHTDB_NOEXCEPT TIGHTDB_OVERRIDE;

    void destroy() TIGHTDB_NOEXCEPT TIGHTDB_OVERRIDE;

    std::size_t size() const TIGHTDB_NOEXCEPT;
    bool is_empty() const TIGHTDB_NOEXCEPT { return size() == 0; }

    StringData get(std::size_t ndx) const TIGHTDB_NOEXCEPT;
    void add() TIGHTDB_OVERRIDE { return add(StringData()); }
    void add(StringData);
    void set(std::size_t ndx, StringData);
    void insert(std::size_t ndx) TIGHTDB_OVERRIDE { insert(ndx, StringData()); }
    void insert(std::size_t ndx, StringData);
    void erase(std::size_t ndx, bool is_last) TIGHTDB_OVERRIDE;
    void clear() TIGHTDB_OVERRIDE;
    void move_last_over(std::size_t ndx) TIGHTDB_OVERRIDE;

    std::size_t count(StringData value) const;
    std::size_t find_first(StringData value, std::size_t begin = 0,
                           std::size_t end = npos) const;
    void find_all(Array& result, StringData value, std::size_t begin = 0,
                  std::size_t end = npos) const;

    //@{
    /// Find the lower/upper bound for the specified value assuming
    /// that the elements are already sorted in ascending order
    /// according to StringData::operator<().
    std::size_t lower_bound_string(StringData value) const TIGHTDB_NOEXCEPT;
    std::size_t upper_bound_string(StringData value) const TIGHTDB_NOEXCEPT;
    //@}

    FindRes find_all_indexref(StringData value, std::size_t& dst) const;

    // Index
    bool has_index() const TIGHTDB_NOEXCEPT TIGHTDB_OVERRIDE { return m_index != 0; }
    void set_index_ref(ref_type, ArrayParent*, std::size_t ndx_in_parent) TIGHTDB_OVERRIDE;
    const StringIndex& get_index() const { return *m_index; }
    StringIndex* release_index() TIGHTDB_NOEXCEPT;
    StringIndex& create_index();

    // Optimizing data layout
    bool auto_enumerate(ref_type& keys, ref_type& values) const;

    /// Compare two string columns for equality.
    bool compare_string(const AdaptiveStringColumn&) const;

    enum LeafType {
        leaf_type_Small,  ///< ArrayString
        leaf_type_Medium, ///< ArrayStringLong
        leaf_type_Big     ///< ArrayBigBlobs
    };

    LeafType GetBlock(std::size_t ndx, ArrayParent**, std::size_t& off,
                      bool use_retval = false) const;

    static ref_type create(std::size_t size, Allocator&);

    static std::size_t get_size_from_ref(ref_type root_ref, Allocator&) TIGHTDB_NOEXCEPT;

    // Overrriding method in ColumnBase
    ref_type write(std::size_t, std::size_t, std::size_t,
                   _impl::OutputStream&) const TIGHTDB_OVERRIDE;

    void update_from_parent(std::size_t old_baseline) TIGHTDB_NOEXCEPT TIGHTDB_OVERRIDE;
#ifdef TIGHTDB_DEBUG
    void Verify() const TIGHTDB_OVERRIDE;
    void to_dot(std::ostream&, StringData title) const TIGHTDB_OVERRIDE;
    void dump_node_structure(std::ostream&, int level) const TIGHTDB_OVERRIDE;
    using ColumnBase::dump_node_structure;
#endif

private:
    StringIndex* m_index;

    std::size_t do_get_size() const TIGHTDB_NOEXCEPT TIGHTDB_OVERRIDE { return size(); }

    void do_insert(std::size_t ndx, StringData value);

    // Called by Array::bptree_insert().
    static ref_type leaf_insert(MemRef leaf_mem, ArrayParent&, std::size_t ndx_in_parent,
                                Allocator&, std::size_t insert_ndx,
                                Array::TreeInsert<AdaptiveStringColumn>& state);

    class EraseLeafElem;
    class CreateHandler;
    class SliceHandler;

    /// Root must be a leaf. Upgrades the root leaf as
    /// necessary. Returns the type of the root leaf as it is upon
    /// return.
    LeafType upgrade_root_leaf(std::size_t value_size);

#ifdef TIGHTDB_DEBUG
    void leaf_to_dot(MemRef, ArrayParent*, std::size_t ndx_in_parent,
                     std::ostream&) const TIGHTDB_OVERRIDE;
#endif

    friend class Array;
    friend class ColumnBase;
};

// Implementation:

inline std::size_t AdaptiveStringColumn::size() const TIGHTDB_NOEXCEPT
{
    if (root_is_leaf()) {
        bool long_strings = m_array->has_refs();
        if (!long_strings) {
            // Small strings root leaf
            ArrayString* leaf = static_cast<ArrayString*>(m_array);
            return leaf->size();
        }
        bool is_big = m_array->get_context_flag();
        if (!is_big) {
            // Medium strings root leaf
            ArrayStringLong* leaf = static_cast<ArrayStringLong*>(m_array);
            return leaf->size();
        }
        // Big strings root leaf
        ArrayBigBlobs* leaf = static_cast<ArrayBigBlobs*>(m_array);
        return leaf->size();
    }
    // Non-leaf root
    return m_array->get_bptree_size();
}

inline void AdaptiveStringColumn::add(StringData value)
{
    do_insert(npos, value);
}

inline void AdaptiveStringColumn::insert(size_t ndx, StringData value)
{
    TIGHTDB_ASSERT(ndx <= size());
    if (size() <= ndx)
        ndx = npos;
    do_insert(ndx, value);
}

inline StringIndex* AdaptiveStringColumn::release_index() TIGHTDB_NOEXCEPT
{
    StringIndex* i = m_index;
    m_index = 0;
    return i;
}

inline std::size_t AdaptiveStringColumn::get_size_from_ref(ref_type root_ref,
                                                           Allocator& alloc) TIGHTDB_NOEXCEPT
{
    const char* root_header = alloc.translate(root_ref);
    bool root_is_leaf = !Array::get_is_inner_bptree_node_from_header(root_header);
    if (root_is_leaf) {
        bool long_strings = Array::get_hasrefs_from_header(root_header);
        if (!long_strings) {
            // Small strings leaf
            return ArrayString::get_size_from_header(root_header);
        }
        bool is_big = Array::get_context_flag_from_header(root_header);
        if (!is_big) {
            // Medium strings leaf
            return ArrayStringLong::get_size_from_header(root_header, alloc);
        }
        // Big strings leaf
        return ArrayBigBlobs::get_size_from_header(root_header);
    }
    return Array::get_bptree_size_from_header(root_header);
}

inline void AdaptiveStringColumn::update_from_parent(std::size_t old_baseline) TIGHTDB_NOEXCEPT TIGHTDB_OVERRIDE
{
    if (root_is_leaf()) {
        bool long_strings = m_array->has_refs();
        if (!long_strings) {
            // Small strings root leaf
            ArrayString* leaf = static_cast<ArrayString*>(m_array);
            leaf->update_from_parent(old_baseline);
            return;
        }
        bool is_big = m_array->get_context_flag();
        if (!is_big) {
            // Medium strings root leaf
            ArrayStringLong* leaf = static_cast<ArrayStringLong*>(m_array);
            leaf->update_from_parent(old_baseline);
            return;
        }
        // Big strings root leaf
        ArrayBigBlobs* leaf = static_cast<ArrayBigBlobs*>(m_array);
        leaf->update_from_parent(old_baseline);
        return;
    }
    // Non-leaf root
    m_array->update_from_parent(old_baseline);
}

} // namespace tightdb

#endif // TIGHTDB_COLUMN_STRING_HPP
<|endoftext|>


<commit_before>//=====================================================================//
/*!	@file
	@brief	ソフト・ディレイ・サンプル @n
			P4_3 を 10us（マイクロ秒）毎に反転する。(50KHz)
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2016 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RL78/blob/master/LICENSE
*/
//=====================================================================//
#include <cstdint>
#include "common/port_utils.hpp"
#include "common/delay.hpp"

namespace {

}

int main(int argc, char* argv[])
{
	using namespace device;

	utils::port::pullup_all();  ///< 安全の為、全ての入力をプルアップ

	PM4.B3 = 0;  // output

	while(1) {
		utils::delay::micro_second(10);
		P4.B3 = !P4.B3();
	}
}
<commit_msg>cleanup<commit_after>//=====================================================================//
/*!	@file
	@brief	ソフト・ディレイ・サンプル @n
			P4_3 を 10us（マイクロ秒）毎に反転する。(50KHz)
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2016 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RL78/blob/master/LICENSE
*/
//=====================================================================//
#include <cstdint>
#include "common/port_utils.hpp"
#include "common/delay.hpp"

int main(int argc, char* argv[])
{
	using namespace device;

	utils::port::pullup_all();  ///< 安全の為、全ての入力をプルアップ

	PM4.B3 = 0;  // output

	while(1) {
		utils::delay::micro_second(10);
//		utils::delay::milli_second(500);
		P4.B3 = !P4.B3();
	}
}
<|endoftext|>


<commit_before>/*ckwg +5
 * Copyright 2013 by Kitware, Inc. All Rights Reserved. Please refer to
 * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel,
 * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065.
 */

#include "tool_io.h"

#include <boost/filesystem/fstream.hpp>

namespace
{

static vistk::path_t const iostream_path = vistk::path_t("-");

}

static void std_stream_dtor(void* ptr);

istream_t
open_istream(vistk::path_t const& path)
{
  istream_t istr;

  if (path == iostream_path)
  {
    istr.reset(&std::cin, &std_stream_dtor);
  }
  else
  {
    istr.reset(new boost::filesystem::ifstream(path));

    if (!istr->good())
    {
      std::string const str = path.string<std::string>();
      std::string const reason = "Unable to open input file: " + str;

      throw std::runtime_error(reason);
    }
  }

  return istr;
}

ostream_t
open_ostream(vistk::path_t const& path)
{
  ostream_t ostr;

  if (path == iostream_path)
  {
    ostr.reset(&std::cout, &std_stream_dtor);
  }
  else
  {
    ostr.reset(new boost::filesystem::ofstream(path));

    if (!ostr->good())
    {
      std::string const str = path.string<std::string>();
      std::string const reason = "Unable to open input file: " + str;

      throw std::runtime_error(reason);
    }
  }

  return ostr;
}

void
std_stream_dtor(void* /*ptr*/)
{
  // We don't want to delete std::cin or std::cout.
}
<commit_msg>Include iostream in tool_io source<commit_after>/*ckwg +5
 * Copyright 2013 by Kitware, Inc. All Rights Reserved. Please refer to
 * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel,
 * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065.
 */

#include "tool_io.h"

#include <boost/filesystem/fstream.hpp>

#include <iostream>

namespace
{

static vistk::path_t const iostream_path = vistk::path_t("-");

}

static void std_stream_dtor(void* ptr);

istream_t
open_istream(vistk::path_t const& path)
{
  istream_t istr;

  if (path == iostream_path)
  {
    istr.reset(&std::cin, &std_stream_dtor);
  }
  else
  {
    istr.reset(new boost::filesystem::ifstream(path));

    if (!istr->good())
    {
      std::string const str = path.string<std::string>();
      std::string const reason = "Unable to open input file: " + str;

      throw std::runtime_error(reason);
    }
  }

  return istr;
}

ostream_t
open_ostream(vistk::path_t const& path)
{
  ostream_t ostr;

  if (path == iostream_path)
  {
    ostr.reset(&std::cout, &std_stream_dtor);
  }
  else
  {
    ostr.reset(new boost::filesystem::ofstream(path));

    if (!ostr->good())
    {
      std::string const str = path.string<std::string>();
      std::string const reason = "Unable to open input file: " + str;

      throw std::runtime_error(reason);
    }
  }

  return ostr;
}

void
std_stream_dtor(void* /*ptr*/)
{
  // We don't want to delete std::cin or std::cout.
}
<|endoftext|>