<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <vclhelperbufferdevice.hxx>
#include <basegfx/range/b2drange.hxx>
#include <vcl/bitmapex.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <tools/stream.hxx>
#include <vcl/timer.hxx>
#include <comphelper/broadcasthelper.hxx>
#include <vcl/lazydelete.hxx>
#include <vcl/dibtools.hxx>

// buffered VDev usage

namespace
{
    typedef ::std::vector< VirtualDevice* > aBuffers;

    class VDevBuffer : public Timer, protected comphelper::OBaseMutex
    {
    private:
        // available buffers
        aBuffers            maFreeBuffers;

        // allocated/used buffers (remembered to allow deleteing them in destructor)
        aBuffers            maUsedBuffers;

    public:
        VDevBuffer();
        virtual ~VDevBuffer();

        VirtualDevice* alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, sal_Int32 nBits);
        void free(VirtualDevice& rDevice);

        // Timer virtuals
        virtual void Timeout() SAL_OVERRIDE;
    };

    VDevBuffer::VDevBuffer()
    :   Timer(),
        maFreeBuffers(),
        maUsedBuffers()
    {
        SetTimeout(10L * 1000L); // ten seconds
    }

    VDevBuffer::~VDevBuffer()
    {
        ::osl::MutexGuard aGuard(m_aMutex);
        Stop();

        while(!maFreeBuffers.empty())
        {
            delete *(maFreeBuffers.end() - 1);
            maFreeBuffers.pop_back();
        }

        while(!maUsedBuffers.empty())
        {
            delete *(maUsedBuffers.end() - 1);
            maUsedBuffers.pop_back();
        }
    }

    VirtualDevice* VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, sal_Int32 nBits)
    {
        ::osl::MutexGuard aGuard(m_aMutex);
        VirtualDevice* pRetval = 0;

        if(!maFreeBuffers.empty())
        {
            bool bOkay(false);
            aBuffers::iterator aFound(maFreeBuffers.end());

            for(aBuffers::iterator a(maFreeBuffers.begin()); a != maFreeBuffers.end(); ++a)
            {
                OSL_ENSURE(*a, "Empty pointer in VDevBuffer (!)");

                if(nBits == (*a)->GetBitCount())
                {
                    // candidate is valid due to bit depth
                    if(aFound != maFreeBuffers.end())
                    {
                        // already found
                        if(bOkay)
                        {
                            // found is valid
                            const bool bCandidateOkay((*a)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*a)->GetOutputHeightPixel() >= rSizePixel.getHeight());

                            if(bCandidateOkay)
                            {
                                // found and candidate are valid
                                const sal_uLong aSquare((*aFound)->GetOutputWidthPixel() * (*aFound)->GetOutputHeightPixel());
                                const sal_uLong aCandidateSquare((*a)->GetOutputWidthPixel() * (*a)->GetOutputHeightPixel());

                                if(aCandidateSquare < aSquare)
                                {
                                    // candidate is valid and smaller, use it
                                    aFound = a;
                                }
                            }
                            else
                            {
                                // found is valid, candidate is not. Keep found
                            }
                        }
                        else
                        {
                            // found is invalid, use candidate
                            aFound = a;
                            bOkay = (*aFound)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*aFound)->GetOutputHeightPixel() >= rSizePixel.getHeight();
                        }
                    }
                    else
                    {
                        // none yet, use candidate
                        aFound = a;
                        bOkay = (*aFound)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*aFound)->GetOutputHeightPixel() >= rSizePixel.getHeight();
                    }
                }
            }

            if(aFound != maFreeBuffers.end())
            {
                pRetval = *aFound;
                maFreeBuffers.erase(aFound);

                if(bOkay)
                {
                    if(bClear)
                    {
                        pRetval->Erase(Rectangle(0, 0, rSizePixel.getWidth(), rSizePixel.getHeight()));
                    }
                }
                else
                {
                    pRetval->SetOutputSizePixel(rSizePixel, bClear);
                }
            }
        }

        // no success yet, create new buffer
        if(!pRetval)
        {
            pRetval = new VirtualDevice(rOutDev, nBits);
            pRetval->SetOutputSizePixel(rSizePixel, bClear);
        }
        else
        {
            // reused, reset some values
            pRetval->SetMapMode();
        }

        // remember allocated buffer
        maUsedBuffers.push_back(pRetval);

        return pRetval;
    }

    void VDevBuffer::free(VirtualDevice& rDevice)
    {
        ::osl::MutexGuard aGuard(m_aMutex);
        const aBuffers::iterator aUsedFound(::std::find(maUsedBuffers.begin(), maUsedBuffers.end(), &rDevice));
        OSL_ENSURE(aUsedFound != maUsedBuffers.end(), "OOps, non-registered buffer freed (!)");

        maUsedBuffers.erase(aUsedFound);
        maFreeBuffers.push_back(&rDevice);
        Start();
    }

    void VDevBuffer::Timeout()
    {
        ::osl::MutexGuard aGuard(m_aMutex);

        while(!maFreeBuffers.empty())
        {
            delete *(maFreeBuffers.end() - 1);
            maFreeBuffers.pop_back();
        }
    }
}

// support for rendering Bitmap and BitmapEx contents

namespace drawinglayer
{
    // static global VDev buffer for the VclProcessor2D's (VclMetafileProcessor2D and VclPixelProcessor2D)
    VDevBuffer& getVDevBuffer()
    {
        // secure global instance with Vcl's safe desroyer of external (seen by
        // library base) stuff, the remembered VDevs need to be deleted before
        // Vcl's deinit
        static vcl::DeleteOnDeinit< VDevBuffer > aVDevBuffer(new VDevBuffer());
        return *aVDevBuffer.get();
    }

    impBufferDevice::impBufferDevice(
        OutputDevice& rOutDev,
        const basegfx::B2DRange& rRange,
        bool bAddOffsetToMapping)
    :   mrOutDev(rOutDev),
        mpContent(0),
        mpMask(0),
        mpAlpha(0)
    {
        basegfx::B2DRange aRangePixel(rRange);
        aRangePixel.transform(mrOutDev.GetViewTransformation());
        const Rectangle aRectPixel(
            (sal_Int32)floor(aRangePixel.getMinX()), (sal_Int32)floor(aRangePixel.getMinY()),
            (sal_Int32)ceil(aRangePixel.getMaxX()), (sal_Int32)ceil(aRangePixel.getMaxY()));
        const Point aEmptyPoint;
        maDestPixel = Rectangle(aEmptyPoint, mrOutDev.GetOutputSizePixel());
        maDestPixel.Intersection(aRectPixel);

        if(isVisible())
        {
#ifdef IOS
            // Exact mechanism unknown, but for some reason SmartArt
            // rendering, especially shadows, is broken on iOS unless
            // we pass 'true' here. Are virtual devices always de
            // facto cleared when created on other platforms?
            mpContent = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, 0);
#else
            mpContent = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), false, 0);
#endif

            // #i93485# assert when copying from window to VDev is used
            OSL_ENSURE(mrOutDev.GetOutDevType() != OUTDEV_WINDOW,
                "impBufferDevice render helper: Copying from Window to VDev, this should be avoided (!)");

            const bool bWasEnabledSrc(mrOutDev.IsMapModeEnabled());
            mrOutDev.EnableMapMode(false);
            mpContent->DrawOutDev(aEmptyPoint, maDestPixel.GetSize(), maDestPixel.TopLeft(), maDestPixel.GetSize(), mrOutDev);
            mrOutDev.EnableMapMode(bWasEnabledSrc);

            MapMode aNewMapMode(mrOutDev.GetMapMode());

            if(bAddOffsetToMapping)
            {
                const Point aLogicTopLeft(mrOutDev.PixelToLogic(maDestPixel.TopLeft()));
                aNewMapMode.SetOrigin(Point(-aLogicTopLeft.X(), -aLogicTopLeft.Y()));
            }

            mpContent->SetMapMode(aNewMapMode);

            // copy AA flag for new target
            mpContent->SetAntialiasing(mrOutDev.GetAntialiasing());
        }
    }

    impBufferDevice::~impBufferDevice()
    {
        if(mpContent)
        {
            getVDevBuffer().free(*mpContent);
        }

        if(mpMask)
        {
            getVDevBuffer().free(*mpMask);
        }

        if(mpAlpha)
        {
            getVDevBuffer().free(*mpAlpha);
        }
    }

    void impBufferDevice::paint(double fTrans)
    {
        if(isVisible())
        {
            const Point aEmptyPoint;
            const Size aSizePixel(maDestPixel.GetSize());
            const bool bWasEnabledDst(mrOutDev.IsMapModeEnabled());
            static bool bDoSaveForVisualControl(false);

            mrOutDev.EnableMapMode(false);
            mpContent->EnableMapMode(false);
            Bitmap aContent(mpContent->GetBitmap(aEmptyPoint, aSizePixel));

            if(bDoSaveForVisualControl)
            {
                SvFileStream aNew( "c:\\content.bmp", STREAM_WRITE|STREAM_TRUNC);
                WriteDIB(aContent, aNew, false, true);
            }

            if(mpAlpha)
            {
                mpAlpha->EnableMapMode(false);
                const AlphaMask aAlphaMask(mpAlpha->GetBitmap(aEmptyPoint, aSizePixel));

                if(bDoSaveForVisualControl)
                {
                    SvFileStream aNew( "c:\\transparence.bmp", STREAM_WRITE|STREAM_TRUNC);
                    WriteDIB(aAlphaMask.GetBitmap(), aNew, false, true);
                }

                mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask));
            }
            else if(mpMask)
            {
                mpMask->EnableMapMode(false);
                const Bitmap aMask(mpMask->GetBitmap(aEmptyPoint, aSizePixel));

                if(bDoSaveForVisualControl)
                {
                    SvFileStream aNew( "c:\\mask.bmp", STREAM_WRITE|STREAM_TRUNC);
                    WriteDIB(aMask, aNew, false, true);
                }

                mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aMask));
            }
            else if(0.0 != fTrans)
            {
                sal_uInt8 nMaskValue((sal_uInt8)basegfx::fround(fTrans * 255.0));
                const AlphaMask aAlphaMask(aSizePixel, &nMaskValue);
                mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask));
            }
            else
            {
                mrOutDev.DrawBitmap(maDestPixel.TopLeft(), aContent);
            }

            mrOutDev.EnableMapMode(bWasEnabledDst);
        }
    }

    VirtualDevice& impBufferDevice::getContent()
    {
        OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)");
        return *mpContent;
    }

    VirtualDevice& impBufferDevice::getMask()
    {
        OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)");
        if(!mpMask)
        {
            mpMask = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, 1);
            mpMask->SetMapMode(mpContent->GetMapMode());

            // do NOT copy AA flag for mask!
        }

        return *mpMask;
    }

    VirtualDevice& impBufferDevice::getTransparence()
    {
        OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)");
        if(!mpAlpha)
        {
            mpAlpha = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, 8);
            mpAlpha->SetMapMode(mpContent->GetMapMode());

            // copy AA flag for new target; masking needs to be smooth
            mpAlpha->SetAntialiasing(mpContent->GetAntialiasing());
        }

        return *mpAlpha;
    }
} // end of namespace drawinglayer

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>"Fix" for some SmartArt rendering artefacts on iOS<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <vclhelperbufferdevice.hxx>
#include <basegfx/range/b2drange.hxx>
#include <vcl/bitmapex.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <tools/stream.hxx>
#include <vcl/timer.hxx>
#include <comphelper/broadcasthelper.hxx>
#include <vcl/lazydelete.hxx>
#include <vcl/dibtools.hxx>

// buffered VDev usage

namespace
{
    typedef ::std::vector< VirtualDevice* > aBuffers;

    class VDevBuffer : public Timer, protected comphelper::OBaseMutex
    {
    private:
        // available buffers
        aBuffers            maFreeBuffers;

        // allocated/used buffers (remembered to allow deleteing them in destructor)
        aBuffers            maUsedBuffers;

    public:
        VDevBuffer();
        virtual ~VDevBuffer();

        VirtualDevice* alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, sal_Int32 nBits);
        void free(VirtualDevice& rDevice);

        // Timer virtuals
        virtual void Timeout() SAL_OVERRIDE;
    };

    VDevBuffer::VDevBuffer()
    :   Timer(),
        maFreeBuffers(),
        maUsedBuffers()
    {
        SetTimeout(10L * 1000L); // ten seconds
    }

    VDevBuffer::~VDevBuffer()
    {
        ::osl::MutexGuard aGuard(m_aMutex);
        Stop();

        while(!maFreeBuffers.empty())
        {
            delete *(maFreeBuffers.end() - 1);
            maFreeBuffers.pop_back();
        }

        while(!maUsedBuffers.empty())
        {
            delete *(maUsedBuffers.end() - 1);
            maUsedBuffers.pop_back();
        }
    }

    VirtualDevice* VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, sal_Int32 nBits)
    {
        ::osl::MutexGuard aGuard(m_aMutex);
        VirtualDevice* pRetval = 0;

        if(!maFreeBuffers.empty())
        {
            bool bOkay(false);
            aBuffers::iterator aFound(maFreeBuffers.end());

            for(aBuffers::iterator a(maFreeBuffers.begin()); a != maFreeBuffers.end(); ++a)
            {
                OSL_ENSURE(*a, "Empty pointer in VDevBuffer (!)");

                if(nBits == (*a)->GetBitCount())
                {
                    // candidate is valid due to bit depth
                    if(aFound != maFreeBuffers.end())
                    {
                        // already found
                        if(bOkay)
                        {
                            // found is valid
                            const bool bCandidateOkay((*a)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*a)->GetOutputHeightPixel() >= rSizePixel.getHeight());

                            if(bCandidateOkay)
                            {
                                // found and candidate are valid
                                const sal_uLong aSquare((*aFound)->GetOutputWidthPixel() * (*aFound)->GetOutputHeightPixel());
                                const sal_uLong aCandidateSquare((*a)->GetOutputWidthPixel() * (*a)->GetOutputHeightPixel());

                                if(aCandidateSquare < aSquare)
                                {
                                    // candidate is valid and smaller, use it
                                    aFound = a;
                                }
                            }
                            else
                            {
                                // found is valid, candidate is not. Keep found
                            }
                        }
                        else
                        {
                            // found is invalid, use candidate
                            aFound = a;
                            bOkay = (*aFound)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*aFound)->GetOutputHeightPixel() >= rSizePixel.getHeight();
                        }
                    }
                    else
                    {
                        // none yet, use candidate
                        aFound = a;
                        bOkay = (*aFound)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*aFound)->GetOutputHeightPixel() >= rSizePixel.getHeight();
                    }
                }
            }

            if(aFound != maFreeBuffers.end())
            {
                pRetval = *aFound;
                maFreeBuffers.erase(aFound);

                if(bOkay)
                {
                    if(bClear)
                    {
                        pRetval->Erase(Rectangle(0, 0, rSizePixel.getWidth(), rSizePixel.getHeight()));
                    }
                }
                else
                {
                    pRetval->SetOutputSizePixel(rSizePixel, bClear);
                }
            }
        }

        // no success yet, create new buffer
        if(!pRetval)
        {
            pRetval = new VirtualDevice(rOutDev, nBits);
            pRetval->SetOutputSizePixel(rSizePixel, bClear);
        }
        else
        {
            // reused, reset some values
            pRetval->SetMapMode();
        }

        // remember allocated buffer
        maUsedBuffers.push_back(pRetval);

        return pRetval;
    }

    void VDevBuffer::free(VirtualDevice& rDevice)
    {
        ::osl::MutexGuard aGuard(m_aMutex);
        const aBuffers::iterator aUsedFound(::std::find(maUsedBuffers.begin(), maUsedBuffers.end(), &rDevice));
        OSL_ENSURE(aUsedFound != maUsedBuffers.end(), "OOps, non-registered buffer freed (!)");

        maUsedBuffers.erase(aUsedFound);
        maFreeBuffers.push_back(&rDevice);
        Start();
    }

    void VDevBuffer::Timeout()
    {
        ::osl::MutexGuard aGuard(m_aMutex);

        while(!maFreeBuffers.empty())
        {
            delete *(maFreeBuffers.end() - 1);
            maFreeBuffers.pop_back();
        }
    }
}

// support for rendering Bitmap and BitmapEx contents

namespace drawinglayer
{
    // static global VDev buffer for the VclProcessor2D's (VclMetafileProcessor2D and VclPixelProcessor2D)
    VDevBuffer& getVDevBuffer()
    {
        // secure global instance with Vcl's safe desroyer of external (seen by
        // library base) stuff, the remembered VDevs need to be deleted before
        // Vcl's deinit
        static vcl::DeleteOnDeinit< VDevBuffer > aVDevBuffer(new VDevBuffer());
        return *aVDevBuffer.get();
    }

    impBufferDevice::impBufferDevice(
        OutputDevice& rOutDev,
        const basegfx::B2DRange& rRange,
        bool bAddOffsetToMapping)
    :   mrOutDev(rOutDev),
        mpContent(0),
        mpMask(0),
        mpAlpha(0)
    {
        basegfx::B2DRange aRangePixel(rRange);
        aRangePixel.transform(mrOutDev.GetViewTransformation());
        const Rectangle aRectPixel(
            (sal_Int32)floor(aRangePixel.getMinX()), (sal_Int32)floor(aRangePixel.getMinY()),
            (sal_Int32)ceil(aRangePixel.getMaxX()), (sal_Int32)ceil(aRangePixel.getMaxY()));
        const Point aEmptyPoint;
        maDestPixel = Rectangle(aEmptyPoint, mrOutDev.GetOutputSizePixel());
        maDestPixel.Intersection(aRectPixel);

        if(isVisible())
        {
#ifdef IOS
            // Exact mechanism unknown, but for some reason SmartArt
            // rendering, especially shadows, is broken on iOS unless
            // we pass 'true' here. Are virtual devices always de
            // facto cleared when created on other platforms?
            mpContent = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, 0);
#else
            mpContent = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), false, 0);
#endif

            // #i93485# assert when copying from window to VDev is used
            OSL_ENSURE(mrOutDev.GetOutDevType() != OUTDEV_WINDOW,
                "impBufferDevice render helper: Copying from Window to VDev, this should be avoided (!)");

            const bool bWasEnabledSrc(mrOutDev.IsMapModeEnabled());
            mrOutDev.EnableMapMode(false);
            mpContent->DrawOutDev(aEmptyPoint, maDestPixel.GetSize(), maDestPixel.TopLeft(), maDestPixel.GetSize(), mrOutDev);
            mrOutDev.EnableMapMode(bWasEnabledSrc);

            MapMode aNewMapMode(mrOutDev.GetMapMode());

            if(bAddOffsetToMapping)
            {
                const Point aLogicTopLeft(mrOutDev.PixelToLogic(maDestPixel.TopLeft()));
                aNewMapMode.SetOrigin(Point(-aLogicTopLeft.X(), -aLogicTopLeft.Y()));
            }

            mpContent->SetMapMode(aNewMapMode);

            // copy AA flag for new target
            mpContent->SetAntialiasing(mrOutDev.GetAntialiasing());
        }
    }

    impBufferDevice::~impBufferDevice()
    {
        if(mpContent)
        {
            getVDevBuffer().free(*mpContent);
        }

        if(mpMask)
        {
            getVDevBuffer().free(*mpMask);
        }

        if(mpAlpha)
        {
            getVDevBuffer().free(*mpAlpha);
        }
    }

    void impBufferDevice::paint(double fTrans)
    {
        if(isVisible())
        {
            const Point aEmptyPoint;
            const Size aSizePixel(maDestPixel.GetSize());
            const bool bWasEnabledDst(mrOutDev.IsMapModeEnabled());
            static bool bDoSaveForVisualControl(false);

            mrOutDev.EnableMapMode(false);
            mpContent->EnableMapMode(false);
            Bitmap aContent(mpContent->GetBitmap(aEmptyPoint, aSizePixel));

            if(bDoSaveForVisualControl)
            {
                SvFileStream aNew( "c:\\content.bmp", STREAM_WRITE|STREAM_TRUNC);
                WriteDIB(aContent, aNew, false, true);
            }

            if(mpAlpha)
            {
                mpAlpha->EnableMapMode(false);
                const AlphaMask aAlphaMask(mpAlpha->GetBitmap(aEmptyPoint, aSizePixel));

                if(bDoSaveForVisualControl)
                {
                    SvFileStream aNew( "c:\\transparence.bmp", STREAM_WRITE|STREAM_TRUNC);
                    WriteDIB(aAlphaMask.GetBitmap(), aNew, false, true);
                }

                mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask));
            }
            else if(mpMask)
            {
                mpMask->EnableMapMode(false);
                const Bitmap aMask(mpMask->GetBitmap(aEmptyPoint, aSizePixel));

                if(bDoSaveForVisualControl)
                {
                    SvFileStream aNew( "c:\\mask.bmp", STREAM_WRITE|STREAM_TRUNC);
                    WriteDIB(aMask, aNew, false, true);
                }

                mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aMask));
            }
            else if(0.0 != fTrans)
            {
#ifndef IOS
                // For some reason using this "normal" code path on
                // iOS with tiled rendering causes horrible artefacts:
                // The mask ends up being drawn too, ending up looking
                // as translucent milky rectangles covering the
                // SmartArt (which is what this typically (?) ends up
                // being used for) ... Why this doesn't cause any
                // artefacts on OS X, which uses largely the very same
                // code in vcl/quartz, I don't know.
                sal_uInt8 nMaskValue((sal_uInt8)basegfx::fround(fTrans * 255.0));
                const AlphaMask aAlphaMask(aSizePixel, &nMaskValue);
                mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask));
#else
                // Not sure at all why this works, but it does. The
                // result is not beautiful (jaggies), but better than
                // blocking out rectangles of the image.
                Bitmap aMask(aContent);
                aMask.Convert(BMP_CONVERSION_8BIT_GREYS);
                mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aMask));
#endif
            }
            else
            {
                mrOutDev.DrawBitmap(maDestPixel.TopLeft(), aContent);
            }

            mrOutDev.EnableMapMode(bWasEnabledDst);
        }
    }

    VirtualDevice& impBufferDevice::getContent()
    {
        OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)");
        return *mpContent;
    }

    VirtualDevice& impBufferDevice::getMask()
    {
        OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)");
        if(!mpMask)
        {
            mpMask = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, 1);
            mpMask->SetMapMode(mpContent->GetMapMode());

            // do NOT copy AA flag for mask!
        }

        return *mpMask;
    }

    VirtualDevice& impBufferDevice::getTransparence()
    {
        OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)");
        if(!mpAlpha)
        {
            mpAlpha = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, 8);
            mpAlpha->SetMapMode(mpContent->GetMapMode());

            // copy AA flag for new target; masking needs to be smooth
            mpAlpha->SetAntialiasing(mpContent->GetAntialiasing());
        }

        return *mpAlpha;
    }
} // end of namespace drawinglayer

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>#include <config.h>
#include <assert.h>
#include <boost/concept/usage.hpp>
#include <boost/format.hpp>
#include <dune/common/exceptions.hh>
#include <dune/fem/io/file/dataoutput.hh>
#include <dune/fem/io/parameter.hh>
#include <dune/istl/scalarproducts.hh>
#include <dune/istl/solvers.hh>
#include <dune/multiscale/msfem/localproblems/localoperator.hh>
#include <dune/multiscale/problems/selector.hh>
#include <dune/multiscale/tools/discretefunctionwriter.hh>
#include <dune/multiscale/msfem/localproblems/localsolutionmanager.hh>
#include <dune/multiscale/tools/misc.hh>
#include <dune/stuff/common/logging.hh>
#include <dune/stuff/common/math.hh>
#include <dune/stuff/common/memory.hh>
#include <dune/stuff/common/parameter/configcontainer.hh>
#include <dune/stuff/common/profiler.hh>
#include <dune/stuff/common/ranges.hh>
#include <dune/stuff/fem/localmatrix_proxy.hh>
#include <dune/stuff/functions/norm.hh>
#include <iterator>
#include <memory>
#include <sstream>
#include <string>
#include <tuple>
#include <vector>

#include "dune/multiscale/msfem/localproblems/subgrid-list.hh"
#include "dune/multiscale/tools/misc/outputparameter.hh"
#include "localproblemsolver.hh"

namespace Dune {
namespace Multiscale {
namespace MsFEM {

/** \brief define output parameters for local problems
 *  appends "local_problems" for path
 **/
struct LocalProblemDataOutputParameters : public OutputParameters {
public:
  explicit LocalProblemDataOutputParameters();
};

LocalProblemDataOutputParameters::LocalProblemDataOutputParameters()
  : OutputParameters(DSC_CONFIG_GET("global.datadir", "data") + "/local_problems/") {}

LocalProblemSolver::LocalProblemSolver(const CommonTraits::DiscreteFunctionSpaceType& coarse_space,
                                       LocalGridList& subgrid_list,
                                       const CommonTraits::DiffusionType& diffusion_operator)
  : diffusion_(diffusion_operator)
  , subgrid_list_(subgrid_list)
  , coarse_space_(coarse_space) {}

void LocalProblemSolver::solve_all_on_single_cell(const MsFEMTraits::CoarseEntityType& coarseCell,
                                                  MsFEMTraits::LocalSolutionVectorType& allLocalSolutions) const {
  assert(allLocalSolutions.size() > 0);

  const bool hasBoundary = coarseCell.hasBoundaryIntersections();
  const auto numBoundaryCorrectors = DSG::is_simplex_grid(coarse_space_) ? 1u : 2u;
  const auto numInnerCorrectors = allLocalSolutions.size() - numBoundaryCorrectors;

  // clear return argument
  for (auto& localSol : allLocalSolutions)
    localSol->clear();

  const auto& subDiscreteFunctionSpace = allLocalSolutions[0]->space();

  //! define the discrete (elliptic) local MsFEM problem operator
  // ( effect of the discretized differential operator on a certain discrete function )
  LocalProblemOperator localProblemOperator(coarse_space_, subDiscreteFunctionSpace, diffusion_);

  // right hand side vector of the algebraic local MsFEM problem
  MsFEMTraits::LocalSolutionVectorType allLocalRHS(allLocalSolutions.size());
  for (auto& it : allLocalRHS)
    it = DSC::make_unique<MsFEMTraits::LocalGridDiscreteFunctionType>("rhs of local MsFEM problem",
                                                                      subDiscreteFunctionSpace);

  localProblemOperator.assemble_all_local_rhs(coarseCell, allLocalRHS);

  for (auto i : DSC::valueRange(allLocalSolutions.size())) {
    auto& current_rhs = *allLocalRHS[i];
    auto& current_solution = *allLocalSolutions[i];

    // is the right hand side of the local MsFEM problem equal to zero or almost identical to zero?
    // if yes, the solution of the local MsFEM problem is also identical to zero. The solver is getting a problem with
    // this situation, which is why we do not solve local msfem problems for zero-right-hand-side, since we already know
    // the result.
    if (DS::l2norm(current_rhs) < 1e-30) {
      current_solution.clear();
      DSC_LOG_DEBUG << "Local MsFEM problem with solution zero." << std::endl;
      continue;
    }
    // don't solve local problems for boundary correctors if coarse cell has no boundary intersections
    if (i >= numInnerCorrectors && !hasBoundary) {
      current_solution.clear();
      DSC_LOG_DEBUG << "Zero-Boundary corrector." << std::endl;
      continue;
    }
    localProblemOperator.apply_inverse(current_rhs, current_solution);
  }
}

void LocalProblemSolver::solve_for_all_cells() {
  static const int dimension = CommonTraits::GridType::dimension;

  JacobianRangeType unitVectors[dimension];
  for (int i = 0; i < dimension; ++i)
    for (int j = 0; j < dimension; ++j) {
      if (i == j) {
        unitVectors[i][0][j] = 1.0;
      } else {
        unitVectors[i][0][j] = 0.0;
      }
    }

  // number of coarse grid entities (of codim 0).
  const auto coarseGridSize = coarse_space_.grid().size(0);
  if (Dune::Fem::MPIManager::size() > 0)
    DSC_LOG_DEBUG << "Rank " << Dune::Fem::MPIManager::rank() << " will solve local problems for " << coarseGridSize
                 << " coarse entities!" << std::endl;
  else {
    DSC_LOG_DEBUG << "Will solve local problems for " << coarseGridSize << " coarse entities!" << std::endl;
  }
  DSC_PROFILER.startTiming("msfem.localProblemSolver.solveAndSaveAll");

  // we want to determine minimum, average and maxiumum time for solving a local msfem problem in the current method
  DSC::MinMaxAvg<double> solveTime;
  DSC::MinMaxAvg<double> saveTime;

  const auto& coarseGridLeafIndexSet = coarse_space_.gridPart().grid().leafIndexSet();
  for (const auto& coarseEntity : coarse_space_) {
    const int coarse_index = coarseGridLeafIndexSet.index(coarseEntity);
    DSC_LOG_DEBUG << "-------------------------" << std::endl << "Coarse index " << coarse_index << std::endl;

    // take time
    DSC_PROFILER.startTiming("msfem.localProblemSolver.solve");
    LocalSolutionManager localSolutionManager(coarse_space_, coarseEntity, subgrid_list_);
    // solve the problems
    solve_all_on_single_cell(coarseEntity, localSolutionManager.getLocalSolutions());
    solveTime(DSC_PROFILER.stopTiming("msfem.localProblemSolver.solve") / 1000.f);

    // save the local solutions to disk
    DSC_PROFILER.startTiming("msfem.localProblemSolver.save");
    localSolutionManager.save();
    saveTime(DSC_PROFILER.stopTiming("msfem.localProblemSolver.save") / 1000.f);

    DSC_PROFILER.resetTiming("msfem.localProblemSolver.solve");
    DSC_PROFILER.resetTiming("msfem.localProblemSolver.save");
  } // for

  //! @todo The following debug-output is wrong (number of local problems may be different)
  const auto totalTime = DSC_PROFILER.stopTiming("msfem.localProblemSolver.solveAndSaveAll") / 1000.f;
  DSC_LOG_DEBUG << "Local problems solved for " << coarseGridSize << " coarse grid entities.\n";
  DSC_LOG_DEBUG << "Minimum time for solving a local problem = " << solveTime.min() << "s.\n";
  DSC_LOG_DEBUG << "Maximum time for solving a localproblem = " << solveTime.max() << "s.\n";
  DSC_LOG_DEBUG << "Average time for solving a localproblem = " << solveTime.average() << "s.\n";
  DSC_LOG_DEBUG << "Minimum time for saving a local problem = " << saveTime.min() << "s.\n";
  DSC_LOG_DEBUG << "Maximum time for saving a localproblem = " << saveTime.max() << "s.\n";
  DSC_LOG_DEBUG << "Average time for saving a localproblem = " << saveTime.average() << "s.\n";
  DSC_LOG_DEBUG << "Total time for computing and saving the localproblems = "
                << totalTime << "s on rank" << Dune::Fem::MPIManager::rank() << std::endl;
} // assemble_all

} // namespace MsFEM {
} // namespace Multiscale {
} // namespace Dune {
<commit_msg>Reduce threshold for zero-solution detection<commit_after>#include <config.h>
#include <assert.h>
#include <boost/concept/usage.hpp>
#include <boost/format.hpp>
#include <dune/common/exceptions.hh>
#include <dune/fem/io/file/dataoutput.hh>
#include <dune/fem/io/parameter.hh>
#include <dune/istl/scalarproducts.hh>
#include <dune/istl/solvers.hh>
#include <dune/multiscale/msfem/localproblems/localoperator.hh>
#include <dune/multiscale/problems/selector.hh>
#include <dune/multiscale/tools/discretefunctionwriter.hh>
#include <dune/multiscale/msfem/localproblems/localsolutionmanager.hh>
#include <dune/multiscale/tools/misc.hh>
#include <dune/stuff/common/logging.hh>
#include <dune/stuff/common/math.hh>
#include <dune/stuff/common/memory.hh>
#include <dune/stuff/common/parameter/configcontainer.hh>
#include <dune/stuff/common/profiler.hh>
#include <dune/stuff/common/ranges.hh>
#include <dune/stuff/fem/localmatrix_proxy.hh>
#include <dune/stuff/functions/norm.hh>
#include <iterator>
#include <memory>
#include <sstream>
#include <string>
#include <tuple>
#include <vector>

#include "dune/multiscale/msfem/localproblems/subgrid-list.hh"
#include "dune/multiscale/tools/misc/outputparameter.hh"
#include "localproblemsolver.hh"

namespace Dune {
namespace Multiscale {
namespace MsFEM {

/** \brief define output parameters for local problems
 *  appends "local_problems" for path
 **/
struct LocalProblemDataOutputParameters : public OutputParameters {
public:
  explicit LocalProblemDataOutputParameters();
};

LocalProblemDataOutputParameters::LocalProblemDataOutputParameters()
  : OutputParameters(DSC_CONFIG_GET("global.datadir", "data") + "/local_problems/") {}

LocalProblemSolver::LocalProblemSolver(const CommonTraits::DiscreteFunctionSpaceType& coarse_space,
                                       LocalGridList& subgrid_list,
                                       const CommonTraits::DiffusionType& diffusion_operator)
  : diffusion_(diffusion_operator)
  , subgrid_list_(subgrid_list)
  , coarse_space_(coarse_space) {}

void LocalProblemSolver::solve_all_on_single_cell(const MsFEMTraits::CoarseEntityType& coarseCell,
                                                  MsFEMTraits::LocalSolutionVectorType& allLocalSolutions) const {
  assert(allLocalSolutions.size() > 0);

  const bool hasBoundary = coarseCell.hasBoundaryIntersections();
  const auto numBoundaryCorrectors = DSG::is_simplex_grid(coarse_space_) ? 1u : 2u;
  const auto numInnerCorrectors = allLocalSolutions.size() - numBoundaryCorrectors;

  // clear return argument
  for (auto& localSol : allLocalSolutions)
    localSol->clear();

  const auto& subDiscreteFunctionSpace = allLocalSolutions[0]->space();

  //! define the discrete (elliptic) local MsFEM problem operator
  // ( effect of the discretized differential operator on a certain discrete function )
  LocalProblemOperator localProblemOperator(coarse_space_, subDiscreteFunctionSpace, diffusion_);

  // right hand side vector of the algebraic local MsFEM problem
  MsFEMTraits::LocalSolutionVectorType allLocalRHS(allLocalSolutions.size());
  for (auto& it : allLocalRHS)
    it = DSC::make_unique<MsFEMTraits::LocalGridDiscreteFunctionType>("rhs of local MsFEM problem",
                                                                      subDiscreteFunctionSpace);

  localProblemOperator.assemble_all_local_rhs(coarseCell, allLocalRHS);

  for (auto i : DSC::valueRange(allLocalSolutions.size())) {
    auto& current_rhs = *allLocalRHS[i];
    auto& current_solution = *allLocalSolutions[i];

    // is the right hand side of the local MsFEM problem equal to zero or almost identical to zero?
    // if yes, the solution of the local MsFEM problem is also identical to zero. The solver is getting a problem with
    // this situation, which is why we do not solve local msfem problems for zero-right-hand-side, since we already know
    // the result.
    if (DS::l2norm(current_rhs) < 1e-12) {
      current_solution.clear();
      DSC_LOG_DEBUG << "Local MsFEM problem with solution zero." << std::endl;
      continue;
    }
    // don't solve local problems for boundary correctors if coarse cell has no boundary intersections
    if (i >= numInnerCorrectors && !hasBoundary) {
      current_solution.clear();
      DSC_LOG_DEBUG << "Zero-Boundary corrector." << std::endl;
      continue;
    }
    localProblemOperator.apply_inverse(current_rhs, current_solution);
  }
}

void LocalProblemSolver::solve_for_all_cells() {
  static const int dimension = CommonTraits::GridType::dimension;

  JacobianRangeType unitVectors[dimension];
  for (int i = 0; i < dimension; ++i)
    for (int j = 0; j < dimension; ++j) {
      if (i == j) {
        unitVectors[i][0][j] = 1.0;
      } else {
        unitVectors[i][0][j] = 0.0;
      }
    }

  // number of coarse grid entities (of codim 0).
  const auto coarseGridSize = coarse_space_.grid().size(0);
  if (Dune::Fem::MPIManager::size() > 0)
    DSC_LOG_DEBUG << "Rank " << Dune::Fem::MPIManager::rank() << " will solve local problems for " << coarseGridSize
                 << " coarse entities!" << std::endl;
  else {
    DSC_LOG_DEBUG << "Will solve local problems for " << coarseGridSize << " coarse entities!" << std::endl;
  }
  DSC_PROFILER.startTiming("msfem.localProblemSolver.solveAndSaveAll");

  // we want to determine minimum, average and maxiumum time for solving a local msfem problem in the current method
  DSC::MinMaxAvg<double> solveTime;
  DSC::MinMaxAvg<double> saveTime;

  const auto& coarseGridLeafIndexSet = coarse_space_.gridPart().grid().leafIndexSet();
  for (const auto& coarseEntity : coarse_space_) {
    const int coarse_index = coarseGridLeafIndexSet.index(coarseEntity);
    DSC_LOG_DEBUG << "-------------------------" << std::endl << "Coarse index " << coarse_index << std::endl;

    // take time
    DSC_PROFILER.startTiming("msfem.localProblemSolver.solve");
    LocalSolutionManager localSolutionManager(coarse_space_, coarseEntity, subgrid_list_);
    // solve the problems
    solve_all_on_single_cell(coarseEntity, localSolutionManager.getLocalSolutions());
    solveTime(DSC_PROFILER.stopTiming("msfem.localProblemSolver.solve") / 1000.f);

    // save the local solutions to disk
    DSC_PROFILER.startTiming("msfem.localProblemSolver.save");
    localSolutionManager.save();
    saveTime(DSC_PROFILER.stopTiming("msfem.localProblemSolver.save") / 1000.f);

    DSC_PROFILER.resetTiming("msfem.localProblemSolver.solve");
    DSC_PROFILER.resetTiming("msfem.localProblemSolver.save");
  } // for

  //! @todo The following debug-output is wrong (number of local problems may be different)
  const auto totalTime = DSC_PROFILER.stopTiming("msfem.localProblemSolver.solveAndSaveAll") / 1000.f;
  DSC_LOG_DEBUG << "Local problems solved for " << coarseGridSize << " coarse grid entities.\n";
  DSC_LOG_DEBUG << "Minimum time for solving a local problem = " << solveTime.min() << "s.\n";
  DSC_LOG_DEBUG << "Maximum time for solving a localproblem = " << solveTime.max() << "s.\n";
  DSC_LOG_DEBUG << "Average time for solving a localproblem = " << solveTime.average() << "s.\n";
  DSC_LOG_DEBUG << "Minimum time for saving a local problem = " << saveTime.min() << "s.\n";
  DSC_LOG_DEBUG << "Maximum time for saving a localproblem = " << saveTime.max() << "s.\n";
  DSC_LOG_DEBUG << "Average time for saving a localproblem = " << saveTime.average() << "s.\n";
  DSC_LOG_DEBUG << "Total time for computing and saving the localproblems = "
                << totalTime << "s on rank" << Dune::Fem::MPIManager::rank() << std::endl;
} // assemble_all

} // namespace MsFEM {
} // namespace Multiscale {
} // namespace Dune {
<|endoftext|>


<commit_before>/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

/**
 * @author Yu-Nan He, 2007/01/18
 */
#define LOG_DOMAIN "gc.base"
#include "gc_common.h"
char* large_page_hint = NULL;

#if defined (_WINDOWS_)
Boolean set_privilege(HANDLE process, LPCTSTR priv_name, Boolean is_enable)
{
  HANDLE token;
  TOKEN_PRIVILEGES tp;
  bool res = OpenProcessToken(process, TOKEN_ADJUST_PRIVILEGES, &token);
  if(!res){
    return FALSE;
  }

  tp.PrivilegeCount = 1;
  tp.Privileges[0].Attributes = is_enable ? SE_PRIVILEGE_ENABLED : 0;

  res = LookupPrivilegeValue( NULL, priv_name, &tp.Privileges[0].Luid);
  if(!res){
    CloseHandle(token);
    return FALSE;
  }

  if (AdjustTokenPrivileges( token, FALSE, &tp, 0, NULL, 0) == ERROR_NOT_ALL_ASSIGNED) {
    CloseHandle(token);
    return FALSE;
  }
  return TRUE;
}

Boolean obtain_lock_memory_priv()
{
  HANDLE process = GetCurrentProcess();
  return set_privilege(process, SE_LOCK_MEMORY_NAME, TRUE);
}

Boolean release_lock_memory_priv()
{
  HANDLE process = GetCurrentProcess();
  return set_privilege(process, SE_LOCK_MEMORY_NAME, FALSE);
}

void* alloc_large_pages(size_t size, const char* hint)
{
  void* alloc_addr = NULL;
  bool lock_memory_enable = obtain_lock_memory_priv();

  if(lock_memory_enable){
    alloc_addr = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
    release_lock_memory_priv();
    if(alloc_addr == NULL){
      LWARN(49, "GC large_page: No required number of large pages found. Please reboot.....");
      return NULL;
    }else
      return alloc_addr;
  }else{
    LWARN(50, "GC large_page: Check that you have permissions:\nGC large_page: Control Panel->Administrative Tools->Local Security Settings->->User Rights Assignment->Lock pages in memory.\nGC large_page: Start VM as soon after reboot as possible, because large pages become fragmented and unusable after a while.\nGC large_page: Heap size should be multiple of large page size.");
    return NULL;
  }
}

#elif defined (__linux__)
#include <fcntl.h>
#include <unistd.h>

static size_t proc_huge_page_size   = 4 * MB;
static size_t proc_huge_pages_total = (size_t)-1;
static size_t proc_huge_pages_free  = 0;
static const char* str_HugePages_Total = "HugePages_Total:";
static const char* str_HugePages_Free  = "HugePages_Free:";
static const char* str_Hugepagesize    = "Hugepagesize:";

static const char* parse_value(const char* buf, int len, const char* name, int name_len, size_t* value){
  if (len < name_len) return NULL;
  if (strncmp(buf, name, name_len)) return NULL;
  buf += name_len;
  char* endpos;
  long int res = strtol(buf, &endpos, 10);
  if (endpos == buf) return NULL;
  *value = (size_t) res;
  return endpos;
}

static void parse_proc_meminfo(size_t required_size){
  FILE* f = fopen("/proc/meminfo", "r");
  if (f == NULL){
    LWARN(51, "GC large_page: Can't open /proc/meminfo");
    return;
  }

  size_t size = 128;
  char* buf = (char*) malloc(size);
  while (true){
    ssize_t len = getline(&buf, &size, f);
    if (len == -1) break;
    parse_value(buf, len, str_HugePages_Total, strlen(str_HugePages_Total), &proc_huge_pages_total);
    parse_value(buf, len, str_HugePages_Free, strlen(str_HugePages_Free), &proc_huge_pages_free);
    const char* end =parse_value(buf, len, str_Hugepagesize, strlen(str_Hugepagesize), &proc_huge_page_size);
    if (end && !strncmp(end, " kB", 3)) proc_huge_page_size *= KB;
  }
  if (buf) free(buf);

  if (proc_huge_pages_total == (size_t)-1){
    LWARN(52, "GC large_page: Large pages are not supported by kernel.\nGC large_page: CONFIG_HUGETLB_PAGE and CONFIG_HUGETLBFS needs to be enabled.");
  } else if (proc_huge_pages_total == 0){
    LWARN(53, "GC large_page: No large pages reserved,  Use the following command: echo num> /proc/sys/vm/nr_hugepages.\nGC large_page: Do it just after kernel boot before huge pages become fragmented.");
  } else if (proc_huge_pages_free * proc_huge_page_size < required_size) {
    if (proc_huge_pages_total * proc_huge_page_size >= required_size) {
      LWARN(54, "GC large_page: Not enough free large pages, some of reserved space is already busy.");
    } else {
      LWARN(54, "GC large_page: Not enough free large pages, some of reserved space is already busy.");
    }
    LWARN(55, "GC large_page: Large pages can be only allocated.");
  }
}

void* mmap_large_pages(size_t size, const char* path)
{
  const char* postfix = "/vm_heap";
  char* buf = (char*) malloc(strlen(path) + strlen(postfix) + 1);
  assert(buf);

  strcpy(buf, path);
  strcat(buf, postfix);

  int fd = open(buf, O_CREAT | O_RDWR, 0700);
  if (fd == -1){
    LWARN(56, "GC large_page: Can't open Mount hugetlbfs with: mount none /mnt/huge -t hugetlbfs.\nGC large_page: Check you have appropriate permissions to /mnt/huge.\nGC large_page: Use command line switch -Dgc.lp=/mnt/huge.");
    free(buf);
    return NULL;
  }
  unlink(buf);

  void* addr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  if (addr == MAP_FAILED){
    LWARN(57, "GC large_page: Map failed.");
    close(fd);
    free(buf);
    return NULL;
  }
  close(fd);
  free(buf);
  return addr;
}

void* alloc_large_pages(size_t size, const char* hint){
  parse_proc_meminfo(size);
  void* alloc_addr = mmap_large_pages(size, hint);
  if(alloc_addr == NULL){
    LWARN(58, "GC large_page: Large pages allocation failed.");
    return NULL;
  }
  return alloc_addr;
}
#elif defined(FREEBSD)
void* mmap_large_pages(size_t size, const char* path)
{
  return NULL;
}
void* alloc_large_pages(size_t size, const char* hint)
{
  return NULL;
}
#else
#error Need to define mmap_large_pages and alloc_large_pages
#endif
<commit_msg>HARMONY-5049 : a minor fix to prevent mem size calculation overflow<commit_after>/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

/**
 * @author Yu-Nan He, 2007/01/18
 */
#define LOG_DOMAIN "gc.base"
#include "gc_common.h"
char* large_page_hint = NULL;

#if defined (_WINDOWS_)
Boolean set_privilege(HANDLE process, LPCTSTR priv_name, Boolean is_enable)
{
  HANDLE token;
  TOKEN_PRIVILEGES tp;
  bool res = OpenProcessToken(process, TOKEN_ADJUST_PRIVILEGES, &token);
  if(!res){
    return FALSE;
  }

  tp.PrivilegeCount = 1;
  tp.Privileges[0].Attributes = is_enable ? SE_PRIVILEGE_ENABLED : 0;

  res = LookupPrivilegeValue( NULL, priv_name, &tp.Privileges[0].Luid);
  if(!res){
    CloseHandle(token);
    return FALSE;
  }

  if (AdjustTokenPrivileges( token, FALSE, &tp, 0, NULL, 0) == ERROR_NOT_ALL_ASSIGNED) {
    CloseHandle(token);
    return FALSE;
  }
  return TRUE;
}

Boolean obtain_lock_memory_priv()
{
  HANDLE process = GetCurrentProcess();
  return set_privilege(process, SE_LOCK_MEMORY_NAME, TRUE);
}

Boolean release_lock_memory_priv()
{
  HANDLE process = GetCurrentProcess();
  return set_privilege(process, SE_LOCK_MEMORY_NAME, FALSE);
}

void* alloc_large_pages(size_t size, const char* hint)
{
  void* alloc_addr = NULL;
  bool lock_memory_enable = obtain_lock_memory_priv();

  if(lock_memory_enable){
    alloc_addr = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
    release_lock_memory_priv();
    if(alloc_addr == NULL){
      LWARN(49, "GC large_page: No required number of large pages found. Please reboot.....");
      return NULL;
    }else
      return alloc_addr;
  }else{
    LWARN(50, "GC large_page: Check that you have permissions:\nGC large_page: Control Panel->Administrative Tools->Local Security Settings->->User Rights Assignment->Lock pages in memory.\nGC large_page: Start VM as soon after reboot as possible, because large pages become fragmented and unusable after a while.\nGC large_page: Heap size should be multiple of large page size.");
    return NULL;
  }
}

#elif defined (__linux__)
#include <fcntl.h>
#include <unistd.h>

static size_t proc_huge_page_size   = 4 * MB;
static size_t proc_huge_pages_total = (size_t)-1;
static size_t proc_huge_pages_free  = 0;
static const char* str_HugePages_Total = "HugePages_Total:";
static const char* str_HugePages_Free  = "HugePages_Free:";
static const char* str_Hugepagesize    = "Hugepagesize:";

static const char* parse_value(const char* buf, int len, const char* name, int name_len, size_t* value){
  if (len < name_len) return NULL;
  if (strncmp(buf, name, name_len)) return NULL;
  buf += name_len;
  char* endpos;
  long int res = strtol(buf, &endpos, 10);
  if (endpos == buf) return NULL;
  *value = (size_t) res;
  return endpos;
}

static void parse_proc_meminfo(size_t required_size){
  FILE* f = fopen("/proc/meminfo", "r");
  if (f == NULL){
    LWARN(51, "GC large_page: Can't open /proc/meminfo");
    return;
  }

  size_t size = 128;
  char* buf = (char*) malloc(size);
  while (true){
    ssize_t len = getline(&buf, &size, f);
    if (len == -1) break;
    parse_value(buf, len, str_HugePages_Total, strlen(str_HugePages_Total), &proc_huge_pages_total);
    parse_value(buf, len, str_HugePages_Free, strlen(str_HugePages_Free), &proc_huge_pages_free);
    const char* end =parse_value(buf, len, str_Hugepagesize, strlen(str_Hugepagesize), &proc_huge_page_size);
    if (end && !strncmp(end, " kB", 3)) proc_huge_page_size *= KB;
  }
  if (buf) free(buf);

  if (proc_huge_pages_total == (size_t)-1){
    LWARN(52, "GC large_page: Large pages are not supported by kernel.\nGC large_page: CONFIG_HUGETLB_PAGE and CONFIG_HUGETLBFS needs to be enabled.");
  } else if (proc_huge_pages_total == 0){
    LWARN(53, "GC large_page: No large pages reserved,  Use the following command: echo num> /proc/sys/vm/nr_hugepages.\nGC large_page: Do it just after kernel boot before huge pages become fragmented.");
  } else {
    //compute required huge page number
    size_t required = (required_size+proc_huge_page_size-1)/proc_huge_page_size;
    if (proc_huge_pages_total < required) {
      LWARN(54, "GC large_page: required size exceeds total large page size.");
    } else if (proc_huge_pages_free < required) {
      LWARN(55, "GC large_page: required size exceeds free large page size.");
    }
  }
}

void* mmap_large_pages(size_t size, const char* path)
{
  const char* postfix = "/vm_heap";
  char* buf = (char*) malloc(strlen(path) + strlen(postfix) + 1);
  assert(buf);

  strcpy(buf, path);
  strcat(buf, postfix);

  int fd = open(buf, O_CREAT | O_RDWR, 0700);
  if (fd == -1){
    LWARN(56, "GC large_page: Can't open Mount hugetlbfs with: mount none /mnt/huge -t hugetlbfs.\nGC large_page: Check you have appropriate permissions to /mnt/huge.\nGC large_page: Use command line switch -Dgc.lp=/mnt/huge.");
    free(buf);
    return NULL;
  }
  unlink(buf);

  void* addr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  if (addr == MAP_FAILED){
    LWARN(57, "GC large_page: Map failed.");
    close(fd);
    free(buf);
    return NULL;
  }
  close(fd);
  free(buf);
  return addr;
}

void* alloc_large_pages(size_t size, const char* hint){
  parse_proc_meminfo(size);
  void* alloc_addr = mmap_large_pages(size, hint);
  if(alloc_addr == NULL){
    LWARN(58, "GC large_page: Large pages allocation failed.");
    return NULL;
  }
  return alloc_addr;
}
#elif defined(FREEBSD)
void* mmap_large_pages(size_t size, const char* path)
{
  return NULL;
}
void* alloc_large_pages(size_t size, const char* hint)
{
  return NULL;
}
#else
#error Need to define mmap_large_pages and alloc_large_pages
#endif
<|endoftext|>


<commit_before><commit_msg>translation to C: do not export 'global' temporaries<commit_after><|endoftext|>


<commit_before>#include <shogun/features/LatentLabels.h>
#include <shogun/features/LatentFeatures.h>
#include <shogun/classifier/svm/LatentLinearMachine.h>
#include <shogun/base/init.h>
#include <shogun/lib/common.h>
#include <shogun/io/SGIO.h>

#include <libgen.h>

using namespace shogun;

#define MAX_LINE_LENGTH 4096
#define HOG_SIZE 1488

struct CBoundingBox : public CLatentData
{
  CBoundingBox (int32_t x, int32_t y) : CLatentData(), x_pos (x), y_pos (y) {};

  int32_t x_pos, y_pos;

  /** @return name of SGSerializable */
  virtual const char* get_name() const { return "BoundingBox"; }
};

struct CHOGFeatures : public CLatentData
{
  CHOGFeatures (int32_t w, int32_t h) : CLatentData(), width (w), height (h) {};

  int32_t width, height;
  float64_t ***hog;

  /** @return name of SGSerializable */
  virtual const char* get_name() const { return "HOGFeatures"; }
};

static void psi_hog (CLatentLinearMachine& llm, CLatentData* f, CLatentData* l, float64_t* psi)
{
  CHOGFeatures* hf = (CHOGFeatures*) f;
  CBoundingBox* bb = (CBoundingBox*) l;
 // printf ("%d %d <-> %d %d\n", hf->width, hf->height, bb->x_pos, bb->y_pos);
  for (int i = 0; i < llm.get_psi_size (); ++i)
  {
    psi[i] = hf->hog[bb->x_pos][bb->y_pos][i];
  }
}

static CLatentData* infer_latent_variable (CLatentLinearMachine& llm, CLatentData* f)
{
  int32_t pos_x = 0, pos_y = 0;
  float64_t* w;
  int32_t w_dim;
  float64_t max_score;

  llm.get_w (w, w_dim);
  CHOGFeatures* hf = dynamic_cast<CHOGFeatures*> (f);
  for (int i = 0; i < hf->width; ++i)
  {
    for (int j = 0; j < hf->height; ++j)
    {
      float64_t score = CMath::dot (w, hf->hog[i][j], w_dim);

      if (score > max_score)
      {
        pos_x = i;
        pos_y = j;
        max_score = score;
      }
    }
  }
  printf ("%d %d %f\n", pos_x, pos_y, max_score);
  CBoundingBox* h = new CBoundingBox (pos_x, pos_y);
  SG_REF (h);

  return h;
}

static void read_dataset (char* fname, CLatentFeatures*& feats, CLatentLabels*& labels)
{
  FILE* fd = fopen (fname, "r");
  char line[MAX_LINE_LENGTH];
  char *pchar, *last_pchar;
  int num_examples,label,height,width;

  char* path = dirname (fname);

  if (fd == NULL)
  {
    fprintf (stderr, "Cannot open input file %s!\n", fname);
    exit (1);
  }

  fgets (line, MAX_LINE_LENGTH, fd);
  num_examples = atoi(line);

  labels = new CLatentLabels (num_examples);
  SG_REF (labels);

  feats = new CLatentFeatures (num_examples);
  SG_REF (feats);

  CMath::init_random ();
  for (int i = 0; (!feof(fd)) && (i < num_examples); ++i)
  {
    fgets(line, MAX_LINE_LENGTH, fd);

    pchar = line;
    while ((*pchar)!=' ') pchar++;
    *pchar = '\0';
    pchar++;

    /* label: {-1, 1} */
    last_pchar = pchar;
    while ((*pchar)!=' ') pchar++;
    *pchar = '\0';
    label = (atoi(last_pchar) % 2 == 0) ? 1 : -1;
    pchar++;

    //printf ("%d\n", label);
    labels->set_label (i, label);

    last_pchar = pchar;
    while ((*pchar)!=' ') pchar++;
    *pchar = '\0';
    width = atoi(last_pchar);
    pchar++;

    last_pchar = pchar;
    while ((*pchar)!='\n') pchar++;
    *pchar = '\0';
    height = atoi(last_pchar);

    /* create latent label */
    int x = CMath::random (0, width-1);
    int y = CMath::random (0, height-1);
    CBoundingBox* bb = new CBoundingBox (x,y);
    labels->add_latent_label (bb);

    //SG_SPRINT ("\nLoading HOG features of size %d\n", HOG_SIZE);
    SG_SPROGRESS (i, 0, num_examples);
    CHOGFeatures* hog = new CHOGFeatures (width, height);
    hog->hog = SG_CALLOC (float64_t**, hog->width);
    for (int j = 0; j < width; ++j)
    {
      hog->hog[j] = SG_CALLOC (float64_t*, hog->height);
      for (int k = 0; k < height; ++k)
      {
        char filename[MAX_LINE_LENGTH];
        hog->hog[j][k] = SG_CALLOC (float64_t, HOG_SIZE);

        sprintf (filename,"%s/%s.%03d.%03d.txt",path,line,j,k);
        FILE* f = fopen (filename, "r");
        if (f == NULL)
          SG_SERROR ("Could not open file: %s\n", filename);
        for (int l = 0; l < HOG_SIZE; ++l)
          fscanf (f,"%lf",&hog->hog[j][k][l]);
        fclose (f);
      }
    }
    feats->add_sample (hog);
  }
  fclose (fd);

  SG_SDONE();
}

int main (int argc, char** argv)
{
  init_shogun_with_defaults ();
  sg_io->set_loglevel (MSG_DEBUG);

  /* check whether the train/test args are given */
  if (argc < 3)
  {
    fprintf (stderr, "not enough arguements given\n");
    exit (1);
  }

  CLatentFeatures* train_feats = NULL;
  CLatentLabels* train_labels = NULL;
  /* read train data set */
  read_dataset (argv[1], train_feats, train_labels);

  /* train the classifier */
  float64_t C = 10.0;

  CLatentLinearMachine llm (C, train_feats, train_labels, HOG_SIZE);
  llm.set_psi (psi_hog);
  llm.set_infer (infer_latent_variable);
  llm.train ();

//  CLatentFeatures* test_feats = NULL;
//  CLatentLabels* test_labels = NULL;
//  read_dataset (argv[2], test_feats, test_labels);

  SG_SPRINT ("Testing with the test set\n");
  llm.apply (train_feats);

  exit_shogun ();
  return 0;
}

<commit_msg>Consolidate latent classifier example with the new API<commit_after>#include <shogun/labels/LatentLabels.h>
#include <shogun/features/LatentFeatures.h>
#include <shogun/classifier/svm/LatentLinearMachine.h>
#include <shogun/base/init.h>
#include <shogun/lib/common.h>
#include <shogun/io/SGIO.h>

#include <libgen.h>

using namespace shogun;

#define MAX_LINE_LENGTH 4096
#define HOG_SIZE 1488

struct CBoundingBox : public CLatentData
{
  CBoundingBox (int32_t x, int32_t y) : CLatentData(), x_pos (x), y_pos (y) {};

  int32_t x_pos, y_pos;

  /** @return name of SGSerializable */
  virtual const char* get_name() const { return "BoundingBox"; }
};

struct CHOGFeatures : public CLatentData
{
  CHOGFeatures (int32_t w, int32_t h) : CLatentData(), width (w), height (h) {};

  int32_t width, height;
  float64_t ***hog;

  /** @return name of SGSerializable */
  virtual const char* get_name() const { return "HOGFeatures"; }
};

static void psi_hog (CLatentLinearMachine& llm, CLatentData* f, CLatentData* l, float64_t* psi)
{
  CHOGFeatures* hf = (CHOGFeatures*) f;
  CBoundingBox* bb = (CBoundingBox*) l;
 // printf ("%d %d <-> %d %d\n", hf->width, hf->height, bb->x_pos, bb->y_pos);
  for (int i = 0; i < llm.get_psi_size (); ++i)
  {
    psi[i] = hf->hog[bb->x_pos][bb->y_pos][i];
  }
}

static CLatentData* infer_latent_variable (CLatentLinearMachine& llm, CLatentData* f)
{
  int32_t pos_x = 0, pos_y = 0;
  int32_t w_dim;
  float64_t max_score;

  SGVector<float64_t> w = llm.get_w ();
  CHOGFeatures* hf = dynamic_cast<CHOGFeatures*> (f);
  for (int i = 0; i < hf->width; ++i)
  {
    for (int j = 0; j < hf->height; ++j)
    {
      float64_t score = w.dot (w.vector, hf->hog[i][j], w.vlen);

      if (score > max_score)
      {
        pos_x = i;
        pos_y = j;
        max_score = score;
      }
    }
  }
  SG_SDEBUG ("%d %d %f\n", pos_x, pos_y, max_score);
  CBoundingBox* h = new CBoundingBox (pos_x, pos_y);
  SG_REF (h);

  return h;
}

static void read_dataset (char* fname, CLatentFeatures*& feats, CLatentLabels*& labels)
{
  FILE* fd = fopen (fname, "r");
  char line[MAX_LINE_LENGTH];
  char *pchar, *last_pchar;
  int num_examples,label,height,width;

  char* path = dirname (fname);

  if (fd == NULL)
  {
    fprintf (stderr, "Cannot open input file %s!\n", fname);
    exit (1);
  }

  fgets (line, MAX_LINE_LENGTH, fd);
  num_examples = atoi(line);

  labels = new CLatentLabels (num_examples);
  SG_REF (labels);

  feats = new CLatentFeatures (num_examples);
  SG_REF (feats);

  CMath::init_random ();
  for (int i = 0; (!feof(fd)) && (i < num_examples); ++i)
  {
    fgets(line, MAX_LINE_LENGTH, fd);

    pchar = line;
    while ((*pchar)!=' ') pchar++;
    *pchar = '\0';
    pchar++;

    /* label: {-1, 1} */
    last_pchar = pchar;
    while ((*pchar)!=' ') pchar++;
    *pchar = '\0';
    label = (atoi(last_pchar) % 2 == 0) ? 1 : -1;
    pchar++;

    //printf ("%d\n", label);
    labels->set_label (i, label);

    last_pchar = pchar;
    while ((*pchar)!=' ') pchar++;
    *pchar = '\0';
    width = atoi(last_pchar);
    pchar++;

    last_pchar = pchar;
    while ((*pchar)!='\n') pchar++;
    *pchar = '\0';
    height = atoi(last_pchar);

    /* create latent label */
    int x = CMath::random (0, width-1);
    int y = CMath::random (0, height-1);
    CBoundingBox* bb = new CBoundingBox (x,y);
    labels->add_latent_label (bb);

    //SG_SPRINT ("\nLoading HOG features of size %d\n", HOG_SIZE);
    SG_SPROGRESS (i, 0, num_examples);
    CHOGFeatures* hog = new CHOGFeatures (width, height);
    hog->hog = SG_CALLOC (float64_t**, hog->width);
    for (int j = 0; j < width; ++j)
    {
      hog->hog[j] = SG_CALLOC (float64_t*, hog->height);
      for (int k = 0; k < height; ++k)
      {
        char filename[MAX_LINE_LENGTH];
        hog->hog[j][k] = SG_CALLOC (float64_t, HOG_SIZE);

        sprintf (filename,"%s/%s.%03d.%03d.txt",path,line,j,k);
        FILE* f = fopen (filename, "r");
        if (f == NULL)
          SG_SERROR ("Could not open file: %s\n", filename);
        for (int l = 0; l < HOG_SIZE; ++l)
          fscanf (f,"%lf",&hog->hog[j][k][l]);
        fclose (f);
      }
    }
    feats->add_sample (hog);
  }
  fclose (fd);

  SG_SDONE();
}

int main (int argc, char** argv)
{
  init_shogun_with_defaults ();
  sg_io->set_loglevel (MSG_DEBUG);

  /* check whether the train/test args are given */
  if (argc < 3)
  {
    fprintf (stderr, "not enough arguements given\n");
    exit (1);
  }

  CLatentFeatures* train_feats = NULL;
  CLatentLabels* train_labels = NULL;
  /* read train data set */
  read_dataset (argv[1], train_feats, train_labels);

  /* train the classifier */
  float64_t C = 10.0;

  CLatentLinearMachine llm (C, train_feats, train_labels, HOG_SIZE);
  llm.set_psi (psi_hog);
  llm.set_infer (infer_latent_variable);
  llm.train ();

//  CLatentFeatures* test_feats = NULL;
//  CLatentLabels* test_labels = NULL;
//  read_dataset (argv[2], test_feats, test_labels);

  SG_SPRINT ("Testing with the test set\n");
  llm.apply (train_feats);

  exit_shogun ();
  return 0;
}

<|endoftext|>


<commit_before>// DO NOT MODIFY THIS FILE
// Never try to directly create an instance of this class, or modify its member variables.
// This contains implementation details, written by code, and only useful to code

#include "../tile.hpp"
#include "../../../joueur/src/base_ai.hpp"
#include "../../../joueur/src/any.hpp"
#include "../../../joueur/src/exceptions.hpp"
#include "../../../joueur/src/delta.hpp"
#include "../game_object.hpp"
#include "../player.hpp"
#include "../tile.hpp"
#include "../tower.hpp"
#include "../tower_job.hpp"
#include "../unit.hpp"
#include "../unit_job.hpp"
#include "necrowar.hpp"

#include <type_traits>

namespace cpp_client
{

namespace necrowar
{

bool Tile_::res(int num)
{
    std::string order = R"({"event": "run", "data": {"functionName": "res", "caller": {"id": ")";
    order += this->id + R"("}, "args": {)";

    order += std::string("\"num\":") + std::to_string(num);

    order += "}}}";
    Necrowar::instance()->send(order);
    //Go until not a delta
    std::unique_ptr<Any> info;
    //until a not bool is seen (i.e., the delta has been processed)
    do
    {
        info = Necrowar::instance()->handle_response();
    } while(info->type() == typeid(bool));
    auto doc = info->as<rapidjson::Document*>();
    auto loc = doc->FindMember("data");
    if(loc == doc->MemberEnd())
    {
       return {};
    }
    auto& val = loc->value;
    Any to_return;
    morph_any(to_return, val);
    return to_return.as<bool>();
}

bool Tile_::spawn_unit(const std::string& title)
{
    std::string order = R"({"event": "run", "data": {"functionName": "spawnUnit", "caller": {"id": ")";
    order += this->id + R"("}, "args": {)";

    order += std::string("\"title\":") + std::string("\"") + title + "\"";

    order += "}}}";
    Necrowar::instance()->send(order);
    //Go until not a delta
    std::unique_ptr<Any> info;
    //until a not bool is seen (i.e., the delta has been processed)
    do
    {
        info = Necrowar::instance()->handle_response();
    } while(info->type() == typeid(bool));
    auto doc = info->as<rapidjson::Document*>();
    auto loc = doc->FindMember("data");
    if(loc == doc->MemberEnd())
    {
       return {};
    }
    auto& val = loc->value;
    Any to_return;
    morph_any(to_return, val);
    return to_return.as<bool>();
}

bool Tile_::spawn_worker()
{
    std::string order = R"({"event": "run", "data": {"functionName": "spawnWorker", "caller": {"id": ")";
    order += this->id + R"("}, "args": {)";

    order += "}}}";
    Necrowar::instance()->send(order);
    //Go until not a delta
    std::unique_ptr<Any> info;
    //until a not bool is seen (i.e., the delta has been processed)
    do
    {
        info = Necrowar::instance()->handle_response();
    } while(info->type() == typeid(bool));
    auto doc = info->as<rapidjson::Document*>();
    auto loc = doc->FindMember("data");
    if(loc == doc->MemberEnd())
    {
       return {};
    }
    auto& val = loc->value;
    Any to_return;
    morph_any(to_return, val);
    return to_return.as<bool>();
}

Tile_::Tile_(std::initializer_list<std::pair<std::string, Any&&>> init) :
    Game_object_{
        {"corpses", Any{std::decay<decltype(corpses)>::type{}}},
        {"isCastle", Any{std::decay<decltype(is_castle)>::type{}}},
        {"isGoldMine", Any{std::decay<decltype(is_gold_mine)>::type{}}},
        {"isGrass", Any{std::decay<decltype(is_grass)>::type{}}},
        {"isIslandGoldMine", Any{std::decay<decltype(is_island_gold_mine)>::type{}}},
        {"isPath", Any{std::decay<decltype(is_path)>::type{}}},
        {"isRiver", Any{std::decay<decltype(is_river)>::type{}}},
        {"isTower", Any{std::decay<decltype(is_tower)>::type{}}},
        {"isUnitSpawn", Any{std::decay<decltype(is_unit_spawn)>::type{}}},
        {"isWall", Any{std::decay<decltype(is_wall)>::type{}}},
        {"isWorkerSpawn", Any{std::decay<decltype(is_worker_spawn)>::type{}}},
        {"numGhouls", Any{std::decay<decltype(num_ghouls)>::type{}}},
        {"numHounds", Any{std::decay<decltype(num_hounds)>::type{}}},
        {"numZombies", Any{std::decay<decltype(num_zombies)>::type{}}},
        {"tileEast", Any{std::decay<decltype(tile_east)>::type{}}},
        {"tileNorth", Any{std::decay<decltype(tile_north)>::type{}}},
        {"tileSouth", Any{std::decay<decltype(tile_south)>::type{}}},
        {"tileWest", Any{std::decay<decltype(tile_west)>::type{}}},
        {"tower", Any{std::decay<decltype(tower)>::type{}}},
        {"type", Any{std::decay<decltype(type)>::type{}}},
        {"unit", Any{std::decay<decltype(unit)>::type{}}},
        {"x", Any{std::decay<decltype(x)>::type{}}},
        {"y", Any{std::decay<decltype(y)>::type{}}},
    },
    corpses(variables_["corpses"].as<std::decay<decltype(corpses)>::type>()),
    is_castle(variables_["isCastle"].as<std::decay<decltype(is_castle)>::type>()),
    is_gold_mine(variables_["isGoldMine"].as<std::decay<decltype(is_gold_mine)>::type>()),
    is_grass(variables_["isGrass"].as<std::decay<decltype(is_grass)>::type>()),
    is_island_gold_mine(variables_["isIslandGoldMine"].as<std::decay<decltype(is_island_gold_mine)>::type>()),
    is_path(variables_["isPath"].as<std::decay<decltype(is_path)>::type>()),
    is_river(variables_["isRiver"].as<std::decay<decltype(is_river)>::type>()),
    is_tower(variables_["isTower"].as<std::decay<decltype(is_tower)>::type>()),
    is_unit_spawn(variables_["isUnitSpawn"].as<std::decay<decltype(is_unit_spawn)>::type>()),
    is_wall(variables_["isWall"].as<std::decay<decltype(is_wall)>::type>()),
    is_worker_spawn(variables_["isWorkerSpawn"].as<std::decay<decltype(is_worker_spawn)>::type>()),
    num_ghouls(variables_["numGhouls"].as<std::decay<decltype(num_ghouls)>::type>()),
    num_hounds(variables_["numHounds"].as<std::decay<decltype(num_hounds)>::type>()),
    num_zombies(variables_["numZombies"].as<std::decay<decltype(num_zombies)>::type>()),
    tile_east(variables_["tileEast"].as<std::decay<decltype(tile_east)>::type>()),
    tile_north(variables_["tileNorth"].as<std::decay<decltype(tile_north)>::type>()),
    tile_south(variables_["tileSouth"].as<std::decay<decltype(tile_south)>::type>()),
    tile_west(variables_["tileWest"].as<std::decay<decltype(tile_west)>::type>()),
    tower(variables_["tower"].as<std::decay<decltype(tower)>::type>()),
    type(variables_["type"].as<std::decay<decltype(type)>::type>()),
    unit(variables_["unit"].as<std::decay<decltype(unit)>::type>()),
    x(variables_["x"].as<std::decay<decltype(x)>::type>()),
    y(variables_["y"].as<std::decay<decltype(y)>::type>())
{
    for(auto&& obj : init)
    {
      variables_.emplace(std::make_pair(std::move(obj.first), std::move(obj.second)));
    }
}

Tile_::~Tile_() = default;

void Tile_::resize(const std::string& name, std::size_t size)
{
    try
    {
        Game_object_::resize(name, size);
        return;
    }
    catch(...){}
    throw Bad_manipulation(name + " in Tile treated as a vector, but it is not a vector.");
}

void Tile_::change_vec_values(const std::string& name, std::vector<std::pair<std::size_t, Any>>& values)
{
    try
    {
        Game_object_::change_vec_values(name, values);
        return;
    }
    catch(...){}
    throw Bad_manipulation(name + " in Tile treated as a vector, but it is not a vector.");
}

void Tile_::remove_key(const std::string& name, Any& key)
{
    try
    {
        Game_object_::remove_key(name, key);
        return;
    }
    catch(...){}
    throw Bad_manipulation(name + " in Tile treated as a map, but it is not a map.");
}

std::unique_ptr<Any> Tile_::add_key_value(const std::string& name, Any& key, Any& value)
{
    try
    {
        return Game_object_::add_key_value(name, key, value);
    }
    catch(...){}
    throw Bad_manipulation(name + " in Tile treated as a map, but it is not a map.");
}

bool Tile_::is_map(const std::string& name)
{
    try
    {
        return Game_object_::is_map(name);
    }
    catch(...){}
    return false;
}

void Tile_::rebind_by_name(Any* to_change, const std::string& member, std::shared_ptr<Base_object> ref)
{
   if(member == "tileEast")
   {
      to_change->as<Tile>() = std::static_pointer_cast<Tile_>(ref);
      return;
   }
   if(member == "tileNorth")
   {
      to_change->as<Tile>() = std::static_pointer_cast<Tile_>(ref);
      return;
   }
   if(member == "tileSouth")
   {
      to_change->as<Tile>() = std::static_pointer_cast<Tile_>(ref);
      return;
   }
   if(member == "tileWest")
   {
      to_change->as<Tile>() = std::static_pointer_cast<Tile_>(ref);
      return;
   }
   if(member == "tower")
   {
      to_change->as<Tower>() = std::static_pointer_cast<Tower_>(ref);
      return;
   }
   if(member == "unit")
   {
      to_change->as<Unit>() = std::static_pointer_cast<Unit_>(ref);
      return;
   }
   try
   {
      Game_object_::rebind_by_name(to_change, member, ref);
      return;
   }
   catch(...){}
   throw Bad_manipulation(member + " in Tile treated as a reference, but it is not a reference.");
}

} // necrowar

} // cpp_client
<commit_msg>added owner attribute to tile and made other changes<commit_after>// DO NOT MODIFY THIS FILE
// Never try to directly create an instance of this class, or modify its member variables.
// This contains implementation details, written by code, and only useful to code

#include "../tile.hpp"
#include "../../../joueur/src/base_ai.hpp"
#include "../../../joueur/src/any.hpp"
#include "../../../joueur/src/exceptions.hpp"
#include "../../../joueur/src/delta.hpp"
#include "../game_object.hpp"
#include "../player.hpp"
#include "../tile.hpp"
#include "../tower.hpp"
#include "../tower_job.hpp"
#include "../unit.hpp"
#include "../unit_job.hpp"
#include "necrowar.hpp"

#include <type_traits>

namespace cpp_client
{

namespace necrowar
{

bool Tile_::res(int num)
{
    std::string order = R"({"event": "run", "data": {"functionName": "res", "caller": {"id": ")";
    order += this->id + R"("}, "args": {)";

    order += std::string("\"num\":") + std::to_string(num);

    order += "}}}";
    Necrowar::instance()->send(order);
    //Go until not a delta
    std::unique_ptr<Any> info;
    //until a not bool is seen (i.e., the delta has been processed)
    do
    {
        info = Necrowar::instance()->handle_response();
    } while(info->type() == typeid(bool));
    auto doc = info->as<rapidjson::Document*>();
    auto loc = doc->FindMember("data");
    if(loc == doc->MemberEnd())
    {
       return {};
    }
    auto& val = loc->value;
    Any to_return;
    morph_any(to_return, val);
    return to_return.as<bool>();
}

bool Tile_::spawn_unit(const std::string& title)
{
    std::string order = R"({"event": "run", "data": {"functionName": "spawnUnit", "caller": {"id": ")";
    order += this->id + R"("}, "args": {)";

    order += std::string("\"title\":") + std::string("\"") + title + "\"";

    order += "}}}";
    Necrowar::instance()->send(order);
    //Go until not a delta
    std::unique_ptr<Any> info;
    //until a not bool is seen (i.e., the delta has been processed)
    do
    {
        info = Necrowar::instance()->handle_response();
    } while(info->type() == typeid(bool));
    auto doc = info->as<rapidjson::Document*>();
    auto loc = doc->FindMember("data");
    if(loc == doc->MemberEnd())
    {
       return {};
    }
    auto& val = loc->value;
    Any to_return;
    morph_any(to_return, val);
    return to_return.as<bool>();
}

bool Tile_::spawn_worker()
{
    std::string order = R"({"event": "run", "data": {"functionName": "spawnWorker", "caller": {"id": ")";
    order += this->id + R"("}, "args": {)";

    order += "}}}";
    Necrowar::instance()->send(order);
    //Go until not a delta
    std::unique_ptr<Any> info;
    //until a not bool is seen (i.e., the delta has been processed)
    do
    {
        info = Necrowar::instance()->handle_response();
    } while(info->type() == typeid(bool));
    auto doc = info->as<rapidjson::Document*>();
    auto loc = doc->FindMember("data");
    if(loc == doc->MemberEnd())
    {
       return {};
    }
    auto& val = loc->value;
    Any to_return;
    morph_any(to_return, val);
    return to_return.as<bool>();
}

Tile_::Tile_(std::initializer_list<std::pair<std::string, Any&&>> init) :
    Game_object_{
        {"corpses", Any{std::decay<decltype(corpses)>::type{}}},
        {"isCastle", Any{std::decay<decltype(is_castle)>::type{}}},
        {"isGoldMine", Any{std::decay<decltype(is_gold_mine)>::type{}}},
        {"isGrass", Any{std::decay<decltype(is_grass)>::type{}}},
        {"isIslandGoldMine", Any{std::decay<decltype(is_island_gold_mine)>::type{}}},
        {"isPath", Any{std::decay<decltype(is_path)>::type{}}},
        {"isRiver", Any{std::decay<decltype(is_river)>::type{}}},
        {"isTower", Any{std::decay<decltype(is_tower)>::type{}}},
        {"isUnitSpawn", Any{std::decay<decltype(is_unit_spawn)>::type{}}},
        {"isWall", Any{std::decay<decltype(is_wall)>::type{}}},
        {"isWorkerSpawn", Any{std::decay<decltype(is_worker_spawn)>::type{}}},
        {"numGhouls", Any{std::decay<decltype(num_ghouls)>::type{}}},
        {"numHounds", Any{std::decay<decltype(num_hounds)>::type{}}},
        {"numZombies", Any{std::decay<decltype(num_zombies)>::type{}}},
        {"owner", Any{std::decay<decltype(owner)>::type{}}},
        {"tileEast", Any{std::decay<decltype(tile_east)>::type{}}},
        {"tileNorth", Any{std::decay<decltype(tile_north)>::type{}}},
        {"tileSouth", Any{std::decay<decltype(tile_south)>::type{}}},
        {"tileWest", Any{std::decay<decltype(tile_west)>::type{}}},
        {"tower", Any{std::decay<decltype(tower)>::type{}}},
        {"unit", Any{std::decay<decltype(unit)>::type{}}},
        {"x", Any{std::decay<decltype(x)>::type{}}},
        {"y", Any{std::decay<decltype(y)>::type{}}},
    },
    corpses(variables_["corpses"].as<std::decay<decltype(corpses)>::type>()),
    is_castle(variables_["isCastle"].as<std::decay<decltype(is_castle)>::type>()),
    is_gold_mine(variables_["isGoldMine"].as<std::decay<decltype(is_gold_mine)>::type>()),
    is_grass(variables_["isGrass"].as<std::decay<decltype(is_grass)>::type>()),
    is_island_gold_mine(variables_["isIslandGoldMine"].as<std::decay<decltype(is_island_gold_mine)>::type>()),
    is_path(variables_["isPath"].as<std::decay<decltype(is_path)>::type>()),
    is_river(variables_["isRiver"].as<std::decay<decltype(is_river)>::type>()),
    is_tower(variables_["isTower"].as<std::decay<decltype(is_tower)>::type>()),
    is_unit_spawn(variables_["isUnitSpawn"].as<std::decay<decltype(is_unit_spawn)>::type>()),
    is_wall(variables_["isWall"].as<std::decay<decltype(is_wall)>::type>()),
    is_worker_spawn(variables_["isWorkerSpawn"].as<std::decay<decltype(is_worker_spawn)>::type>()),
    num_ghouls(variables_["numGhouls"].as<std::decay<decltype(num_ghouls)>::type>()),
    num_hounds(variables_["numHounds"].as<std::decay<decltype(num_hounds)>::type>()),
    num_zombies(variables_["numZombies"].as<std::decay<decltype(num_zombies)>::type>()),
    owner(variables_["owner"].as<std::decay<decltype(owner)>::type>()),
    tile_east(variables_["tileEast"].as<std::decay<decltype(tile_east)>::type>()),
    tile_north(variables_["tileNorth"].as<std::decay<decltype(tile_north)>::type>()),
    tile_south(variables_["tileSouth"].as<std::decay<decltype(tile_south)>::type>()),
    tile_west(variables_["tileWest"].as<std::decay<decltype(tile_west)>::type>()),
    tower(variables_["tower"].as<std::decay<decltype(tower)>::type>()),
    unit(variables_["unit"].as<std::decay<decltype(unit)>::type>()),
    x(variables_["x"].as<std::decay<decltype(x)>::type>()),
    y(variables_["y"].as<std::decay<decltype(y)>::type>())
{
    for(auto&& obj : init)
    {
      variables_.emplace(std::make_pair(std::move(obj.first), std::move(obj.second)));
    }
}

Tile_::~Tile_() = default;

void Tile_::resize(const std::string& name, std::size_t size)
{
    try
    {
        Game_object_::resize(name, size);
        return;
    }
    catch(...){}
    throw Bad_manipulation(name + " in Tile treated as a vector, but it is not a vector.");
}

void Tile_::change_vec_values(const std::string& name, std::vector<std::pair<std::size_t, Any>>& values)
{
    try
    {
        Game_object_::change_vec_values(name, values);
        return;
    }
    catch(...){}
    throw Bad_manipulation(name + " in Tile treated as a vector, but it is not a vector.");
}

void Tile_::remove_key(const std::string& name, Any& key)
{
    try
    {
        Game_object_::remove_key(name, key);
        return;
    }
    catch(...){}
    throw Bad_manipulation(name + " in Tile treated as a map, but it is not a map.");
}

std::unique_ptr<Any> Tile_::add_key_value(const std::string& name, Any& key, Any& value)
{
    try
    {
        return Game_object_::add_key_value(name, key, value);
    }
    catch(...){}
    throw Bad_manipulation(name + " in Tile treated as a map, but it is not a map.");
}

bool Tile_::is_map(const std::string& name)
{
    try
    {
        return Game_object_::is_map(name);
    }
    catch(...){}
    return false;
}

void Tile_::rebind_by_name(Any* to_change, const std::string& member, std::shared_ptr<Base_object> ref)
{
   if(member == "owner")
   {
      to_change->as<Player>() = std::static_pointer_cast<Player_>(ref);
      return;
   }
   if(member == "tileEast")
   {
      to_change->as<Tile>() = std::static_pointer_cast<Tile_>(ref);
      return;
   }
   if(member == "tileNorth")
   {
      to_change->as<Tile>() = std::static_pointer_cast<Tile_>(ref);
      return;
   }
   if(member == "tileSouth")
   {
      to_change->as<Tile>() = std::static_pointer_cast<Tile_>(ref);
      return;
   }
   if(member == "tileWest")
   {
      to_change->as<Tile>() = std::static_pointer_cast<Tile_>(ref);
      return;
   }
   if(member == "tower")
   {
      to_change->as<Tower>() = std::static_pointer_cast<Tower_>(ref);
      return;
   }
   if(member == "unit")
   {
      to_change->as<Unit>() = std::static_pointer_cast<Unit_>(ref);
      return;
   }
   try
   {
      Game_object_::rebind_by_name(to_change, member, ref);
      return;
   }
   catch(...){}
   throw Bad_manipulation(member + " in Tile treated as a reference, but it is not a reference.");
}

} // necrowar

} // cpp_client
<|endoftext|>