<commit_before>#include "ch_frb_io_internals.hpp"

using namespace std;

namespace ch_frb_io {
#if 0
};  // pacify emacs c-mode!
#endif

memory_slab_pool::memory_slab_pool(ssize_t nbytes_per_slab_, ssize_t nslabs_, const vector<int> &allocation_cores, bool noisy) :
    nbytes_per_slab(nbytes_per_slab_),
    nslabs(nslabs_)
{
    double gb = 1.0e-9 * double(nbytes_per_slab) * double(nslabs);

    if (nbytes_per_slab <= 0)
	throw runtime_error("ch_frb_io: memory_slab_pool constructor expects nbytes_per_slab > 0");
    if (nslabs <= 0)
	throw runtime_error("ch_frb_io: memory_slab_pool constructor expects nslabs > 0");
    if (gb > 64.0)
	throw runtime_error("ch_frb_io: memory_slab_pool constructor: attempt to allocate > 64 GB, this is assumed unintentional");

    if (noisy) {
	cout << "ch_frb_io: allocating " << gb << " GB memory pool";
	if (allocation_cores.size() > 0)
	    cout << ", cores=" << vstr(allocation_cores);
	cout << endl;
    }

    std::thread t(std::bind(&memory_slab_pool::allocate, this, allocation_cores));
    t.join();

    if (noisy)
	cout << "ch_frb_io:" << gb << " GB memory pool allocated" << endl;
}

unique_ptr<uint8_t[]> memory_slab_pool::get_slab(bool zero, bool wait)
{
    unique_ptr<uint8_t[]> ret;
    unique_lock<std::mutex> ulock(this->lock);

    for (;;) {
	if (curr_size > 0) {
	    ret.swap(slabs[curr_size-1]);
	    curr_size--;
	    break;
	}

	if (!wait)
	    return ret;

	this->cv.wait(ulock);
    }

    ulock.unlock();

    if (!ret)
	throw runtime_error("ch_frb_io: internal error: unexpected null pointer 'ret' in memory_slab_pool::get_slab()");
    if (zero)
	memset(ret.get(), 0, nbytes_per_slab);

    return ret;
}

void memory_slab_pool::put_slab(unique_ptr<uint8_t[]> &p)
{
    if (!p)
	throw runtime_error("ch_frb_io: internal error: unexpected null pointer 'p' in memory_slab_pool::put_slab()");

    unique_lock<std::mutex> ulock(this->lock);

    if (curr_size >= nslabs)
	throw runtime_error("ch_frb_io: internal error: buffer is full in memory_slab_pool::put_slab()");
    if (slabs[curr_size])
	throw runtime_error("ch_frb_io: internal error: unexpected null pointer 'slabs[curr_size]' in memory_slab_pool::put_slab()");

    slabs[curr_size].swap(p);
    curr_size++;
    cv.notify_all();
}

// Called as separate thread!
void memory_slab_pool::allocate(const vector<int> &allocation_cores)
{
    pin_thread_to_cores(allocation_cores);

    this->slabs.resize(nslabs);

    for (ssize_t i = 0; i < nslabs; i++) {
	uint8_t *p = aligned_alloc<uint8_t> (nbytes_per_slab);
	this->slabs[i] = unique_ptr<uint8_t[]> (p);
    }
}

}  // namespace ch_frb_io
<commit_msg>fix bug in memory_slab_pool<commit_after>#include "ch_frb_io_internals.hpp"

using namespace std;

namespace ch_frb_io {
#if 0
};  // pacify emacs c-mode!
#endif

memory_slab_pool::memory_slab_pool(ssize_t nbytes_per_slab_, ssize_t nslabs_, const vector<int> &allocation_cores, bool noisy) :
    nbytes_per_slab(nbytes_per_slab_),
    nslabs(nslabs_)
{
    double gb = 1.0e-9 * double(nbytes_per_slab) * double(nslabs);

    if (nbytes_per_slab <= 0)
	throw runtime_error("ch_frb_io: memory_slab_pool constructor expects nbytes_per_slab > 0");
    if (nslabs <= 0)
	throw runtime_error("ch_frb_io: memory_slab_pool constructor expects nslabs > 0");
    if (gb > 64.0)
	throw runtime_error("ch_frb_io: memory_slab_pool constructor: attempt to allocate > 64 GB, this is assumed unintentional");

    if (noisy) {
	cout << "ch_frb_io: allocating " << gb << " GB memory pool";
	if (allocation_cores.size() > 0)
	    cout << ", cores=" << vstr(allocation_cores);
	cout << endl;
    }

    std::thread t(std::bind(&memory_slab_pool::allocate, this, allocation_cores));
    t.join();

    if (noisy)
	cout << "ch_frb_io:" << gb << " GB memory pool allocated" << endl;
}

unique_ptr<uint8_t[]> memory_slab_pool::get_slab(bool zero, bool wait)
{
    unique_ptr<uint8_t[]> ret;
    unique_lock<std::mutex> ulock(this->lock);

    for (;;) {
	if (curr_size > 0) {
	    ret.swap(slabs[curr_size-1]);
	    curr_size--;
	    break;
	}

	if (!wait)
	    return ret;

	this->cv.wait(ulock);
    }

    ulock.unlock();

    if (!ret)
	throw runtime_error("ch_frb_io: internal error: unexpected null pointer 'ret' in memory_slab_pool::get_slab()");
    if (zero)
	memset(ret.get(), 0, nbytes_per_slab);

    return ret;
}

void memory_slab_pool::put_slab(unique_ptr<uint8_t[]> &p)
{
    if (!p)
	throw runtime_error("ch_frb_io: internal error: unexpected null pointer 'p' in memory_slab_pool::put_slab()");

    unique_lock<std::mutex> ulock(this->lock);

    if (curr_size >= (int)slabs.size())
	throw runtime_error("ch_frb_io: internal error: buffer is full in memory_slab_pool::put_slab()");
    if (slabs[curr_size])
	throw runtime_error("ch_frb_io: internal error: unexpected null pointer 'slabs[curr_size]' in memory_slab_pool::put_slab()");

    slabs[curr_size].swap(p);
    curr_size++;
    cv.notify_all();
}

// Called as separate thread!
void memory_slab_pool::allocate(const vector<int> &allocation_cores)
{
    pin_thread_to_cores(allocation_cores);

    this->slabs.resize(nslabs);
    this->curr_size = nslabs;

    for (ssize_t i = 0; i < nslabs; i++) {
	uint8_t *p = aligned_alloc<uint8_t> (nbytes_per_slab);
	this->slabs[i] = unique_ptr<uint8_t[]> (p);
    }
}

}  // namespace ch_frb_io
<|endoftext|>


<commit_before>// Copyright(c) Andre Caron, 2009-2010
//
// This document is covered by the Artistic License 2.0 (Open Source Initiative
// approved license). A copy of the license should have been provided alongside
// this software package (see "license.rtf"). If not, the license is available
// online at "http://www.opensource.org/licenses/artistic-license-2.0.php".

#include <w32.net/Socket.hpp>
#include <w32/Error.hpp>

namespace {

    void abandon ( ::SOCKET object ) {}
    void destroy ( ::SOCKET object )
    {
        if ( ::closesocket(object) != 0 )
        {
            const w32::Error error(::WSAGetLastError());
            std::cerr << "[[[ " << error << " ]]]" << std::endl;
        }
    }

}

namespace w32 { namespace net {

    Socket::Handle Socket::claim ( ::SOCKET object )
    {
        return (Handle(object, &::destroy));
    }

    Socket::Handle Socket::proxy ( ::SOCKET object )
    {
        return (Handle(object, &::abandon));
    }

    Socket::Socket ( Handle handle )
        : myHandle(handle)
    {
    }

    Socket::~Socket ()
    {
    }

    const Socket::Handle& Socket::handle () const
    {
        return (myHandle);
    }

    void Socket::blocking ( bool blocking )
    {
        ::u_long value = blocking? 0 : 1;
        const int result = ::ioctlsocket(handle(), FIONBIO, &value);
        if ( result == SOCKET_ERROR )
        {
            const int error = ::WSAGetLastError();
            UNCHECKED_WIN32C_ERROR(ioctlsocket, error);
        }
    }

    ulong Socket::available () const
    {
        ::u_long value = 0;
        const int result = ::ioctlsocket(handle(), FIONREAD, &value);
        if ( result == SOCKET_ERROR )
        {
            const int error = ::WSAGetLastError();
            UNCHECKED_WIN32C_ERROR(ioctlsocket, error);
        }
        return (value);
    }

    void Socket::shutdown ()
    {
        shutdown(Shutdown::output());
    }

    void Socket::shutdown ( const Shutdown& method )
    {
        const int result = ::shutdown(handle(), method.value());
        if ( result != 0 )
        {
            const int error = ::WSAGetLastError();
            UNCHECKED_WIN32C_ERROR(shutdown, error);
        }
    }

    void Socket::select ( mt::ManualResetEvent& event, Event events )
    {
        const int result = ::WSAEventSelect(handle(), event.handle(), events);
        if ( result == SOCKET_ERROR )
        {
            const int error = ::WSAGetLastError();
            UNCHECKED_WIN32C_ERROR(WSAEventSelect, error);
        }
    }

    const Socket::Type Socket::Type::stream ()
    {
        return (SOCK_STREAM);
    }

    const Socket::Type Socket::Type::dgram ()
    {
        return (SOCK_DGRAM);
    }

    const Socket::Type Socket::Type::raw ()
    {
        return (SOCK_RAW);
    }

    const Socket::Type Socket::Type::rdm ()
    {
        return (SOCK_RDM);
    }

    const Socket::Type Socket::Type::seqpacket ()
    {
        return (SOCK_SEQPACKET);
    }

    Socket::Type::Type ( Value value )
        : myValue(value)
    {
    }

    Socket::Type::Value Socket::Type::value () const
    {
        return (myValue);
    }

    const Socket::Shutdown Socket::Shutdown::output ()
    {
        return (SD_SEND);
    }

    const Socket::Shutdown Socket::Shutdown::input ()
    {
        return (SD_RECEIVE);
    }

    const Socket::Shutdown Socket::Shutdown::both ()
    {
        return (SD_BOTH);
    }

    Socket::Shutdown::Shutdown ( Value value )
        : myValue(value)
    {
    }

    Socket::Shutdown::Value Socket::Shutdown::value () const
    {
        return (myValue);
    }

} }
<commit_msg>Avoids triggering error for hopeless connection.<commit_after>// Copyright(c) Andre Caron, 2009-2010
//
// This document is covered by the Artistic License 2.0 (Open Source Initiative
// approved license). A copy of the license should have been provided alongside
// this software package (see "license.rtf"). If not, the license is available
// online at "http://www.opensource.org/licenses/artistic-license-2.0.php".

#include <w32.net/Socket.hpp>
#include <w32/Error.hpp>

namespace {

    void abandon ( ::SOCKET object ) {}
    void destroy ( ::SOCKET object )
    {
        if ( ::closesocket(object) != 0 )
        {
            const w32::Error error(::WSAGetLastError());
            std::cerr << "[[[ " << error << " ]]]" << std::endl;
        }
    }

}

namespace w32 { namespace net {

    Socket::Handle Socket::claim ( ::SOCKET object )
    {
        return (Handle(object, &::destroy));
    }

    Socket::Handle Socket::proxy ( ::SOCKET object )
    {
        return (Handle(object, &::abandon));
    }

    Socket::Socket ( Handle handle )
        : myHandle(handle)
    {
    }

    Socket::~Socket ()
    {
    }

    const Socket::Handle& Socket::handle () const
    {
        return (myHandle);
    }

    void Socket::blocking ( bool blocking )
    {
        ::u_long value = blocking? 0 : 1;
        const int result = ::ioctlsocket(handle(), FIONBIO, &value);
        if ( result == SOCKET_ERROR )
        {
            const int error = ::WSAGetLastError();
            UNCHECKED_WIN32C_ERROR(ioctlsocket, error);
        }
    }

    ulong Socket::available () const
    {
        ::u_long value = 0;
        const int result = ::ioctlsocket(handle(), FIONREAD, &value);
        if ( result == SOCKET_ERROR )
        {
            const int error = ::WSAGetLastError();
            UNCHECKED_WIN32C_ERROR(ioctlsocket, error);
        }
        return (value);
    }

    void Socket::shutdown ()
    {
        shutdown(Shutdown::output());
    }

    void Socket::shutdown ( const Shutdown& method )
    {
        const int result = ::shutdown(handle(), method.value());
        if ( result != 0 )
        {
            const int error = ::WSAGetLastError();
            if (error == WSAECONNABORTED) {
                return;
            }
            if (error == WSAECONNRESET) {
                return;
            }
            UNCHECKED_WIN32C_ERROR(shutdown, error);
        }
    }

    void Socket::select ( mt::ManualResetEvent& event, Event events )
    {
        const int result = ::WSAEventSelect(handle(), event.handle(), events);
        if ( result == SOCKET_ERROR )
        {
            const int error = ::WSAGetLastError();
            UNCHECKED_WIN32C_ERROR(WSAEventSelect, error);
        }
    }

    const Socket::Type Socket::Type::stream ()
    {
        return (SOCK_STREAM);
    }

    const Socket::Type Socket::Type::dgram ()
    {
        return (SOCK_DGRAM);
    }

    const Socket::Type Socket::Type::raw ()
    {
        return (SOCK_RAW);
    }

    const Socket::Type Socket::Type::rdm ()
    {
        return (SOCK_RDM);
    }

    const Socket::Type Socket::Type::seqpacket ()
    {
        return (SOCK_SEQPACKET);
    }

    Socket::Type::Type ( Value value )
        : myValue(value)
    {
    }

    Socket::Type::Value Socket::Type::value () const
    {
        return (myValue);
    }

    const Socket::Shutdown Socket::Shutdown::output ()
    {
        return (SD_SEND);
    }

    const Socket::Shutdown Socket::Shutdown::input ()
    {
        return (SD_RECEIVE);
    }

    const Socket::Shutdown Socket::Shutdown::both ()
    {
        return (SD_BOTH);
    }

    Socket::Shutdown::Shutdown ( Value value )
        : myValue(value)
    {
    }

    Socket::Shutdown::Value Socket::Shutdown::value () const
    {
        return (myValue);
    }

} }
<|endoftext|>


<commit_before>#include "ex14_26_String.h"
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <string>

void foo(String x)
{
	std::cout << x << std::endl;
}

void bar(const String& x)
{
	std::cout << x.c_str() << std::endl;
}

String baz()
{
	String ret("world");
	return ret;
}

int main()
{
	char text[] = "world";

	String s0;
	String s1("hello");
	String s2(std::move(s0));
	String s3 = s1;
	String s4(text);
	s2 = s1;

	if (s2 == s1)
		std::cout << "s2 == s1" << std::endl;

	foo(s1);
	bar(s1);
	foo("temporary");
	bar("temporary");
	String s5 = baz();

	std::vector<String> svec;
	//svec.push_back(s0);
	svec.push_back(s1);
	svec.push_back(s2);
	svec.push_back(s3);
	svec.push_back(s4);
	svec.push_back(baz());
	svec.push_back("good job");

	for (const auto &s : svec) {
		std::cout << s << std::endl;
	}

	std::cout << "Input a string: ";
	String s6;
	std::cin >> s6;
	std::cout << s6 << std::endl;

	if (s6 > s1)
		std::cout << "s6 > s1" << std::endl;

    std::cout << s5[2] << std::endl;
}
<commit_msg>Update ex14_26_StringMain.cpp<commit_after>#include "ex14_26_String.h"
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <string>

void foo(String x)
{
    std::cout << x << std::endl;
}

void bar(const String& x)
{
    std::cout << x.c_str() << std::endl;
}

String baz()
{
    String ret("world");
    return ret;
}

int main()
{
    char text[] = "world";

    String s0;
    String s1("hello");
    String s2(std::move(s0));
    String s3 = s1;
    String s4(text);
    s2 = s1;

    if (s2 == s1)
        std::cout << "s2 == s1" << std::endl;

    foo(s1);
    bar(s1);
    foo("temporary");
    bar("temporary");
    String s5 = baz();

    std::vector<String> svec;
    //svec.push_back(s0);
    svec.push_back(s1);
    svec.push_back(s2);
    svec.push_back(s3);
    svec.push_back(s4);
    svec.push_back(baz());
    svec.push_back("good job");

    for (const auto &s : svec) {
        std::cout << s << std::endl;
    }

    std::cout << "Input a string: ";
    String s6;
    std::cin >> s6;
    std::cout << s6 << std::endl;

    if (s6 > s1)
        std::cout << "s6 > s1" << std::endl;

    std::cout << s5[2] << std::endl;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: cursor.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2003-04-17 15:19:06 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/

#define _SV_CURSOR_CXX

#ifndef _SV_SVAPP_HXX
#include <svapp.hxx>
#endif
#ifndef _SV_TIMER_HXX
#include <timer.hxx>
#endif
#ifndef _SV_SETTINGS_HXX
#include <settings.hxx>
#endif
#ifndef _SV_WINDOW_HXX
#include <window.hxx>
#endif
#ifndef _SV_WINDOW_H
#include <window.h>
#endif
#ifndef _SV_POLY_HXX
#include <poly.hxx>
#endif
#ifndef _SV_CURSOR_HXX
#include <cursor.hxx>
#endif
#ifdef REMOTE_APPSERVER
#ifndef _SV_WINDATA_HXX
#include <windata.hxx>
#endif
#endif
#pragma hdrstop

// =======================================================================

struct ImplCursorData
{
    AutoTimer       maTimer;            // Timer
    Point           maPixPos;           // Pixel-Position
    Point           maPixRotOff;        // Pixel-Offset-Position
    Size            maPixSize;          // Pixel-Size
    long            mnPixSlant;         // Pixel-Slant
    short           mnOrientation;      // Pixel-Orientation
    unsigned char   mnDirection;        // indicates writing direction
    USHORT          mnStyle;            // Cursor-Style
    BOOL            mbCurVisible;       // Ist Cursor aktuell sichtbar
    Window*         mpWindow;           // Zugeordnetes Windows
};

// =======================================================================

static void ImplCursorInvert( ImplCursorData* pData )
{
    Window* pWindow  = pData->mpWindow;
    BOOL    bMapMode = pWindow->IsMapModeEnabled();
    pWindow->EnableMapMode( FALSE );
    USHORT nInvertStyle;
    if ( pData->mnStyle & CURSOR_SHADOW )
        nInvertStyle = INVERT_50;
    else
        nInvertStyle = 0;

    Rectangle aRect( pData->maPixPos, pData->maPixSize );
    if ( pData->mnDirection || pData->mnOrientation || pData->mnPixSlant )
    {
        Polygon aPoly( aRect );
        if( aPoly.GetSize() == 5 )
        {
            aPoly[1].X() += 1;  // include the right border
            aPoly[2].X() += 1;
            if ( pData->mnPixSlant )
            {
                Point aPoint = aPoly.GetPoint( 0 );
                aPoint.X() += pData->mnPixSlant;
                aPoly.SetPoint( aPoint, 0 );
                aPoly.SetPoint( aPoint, 4 );
                aPoint = aPoly.GetPoint( 1 );
                aPoint.X() += pData->mnPixSlant;
                aPoly.SetPoint( aPoint, 1 );
            }

            // apply direction flag after slant to use the correct shape
            if ( pData->mnDirection )
            {
                Point pAry[7];
                int delta = 3*aRect.getWidth()+1;
                if( pData->mnDirection == CURSOR_DIRECTION_LTR )
                {
                    // left-to-right
                    pAry[0] = aPoly.GetPoint( 0 );
                    pAry[1] = aPoly.GetPoint( 1 );
                    pAry[2] = pAry[1];
                    pAry[2].X() += delta;
                    pAry[3] =  pAry[1];
                    pAry[3].Y() += delta;
                    pAry[4] = aPoly.GetPoint( 2 );
                    pAry[5] = aPoly.GetPoint( 3 );
                    pAry[6] = aPoly.GetPoint( 4 );
                }
                else if( pData->mnDirection == CURSOR_DIRECTION_RTL )
                {
                    // right-to-left
                    pAry[0] = aPoly.GetPoint( 0 );
                    pAry[1] = aPoly.GetPoint( 1 );
                    pAry[2] = aPoly.GetPoint( 2 );
                    pAry[3] = aPoly.GetPoint( 3 );
                    pAry[4] = pAry[0];
                    pAry[4].Y() += delta;
                    pAry[5] =  pAry[0];
                    pAry[5].X() -= delta;
                    pAry[6] = aPoly.GetPoint( 4 );
                }
                aPoly = Polygon( 7, pAry);
            }

            if ( pData->mnOrientation )
                aPoly.Rotate( pData->maPixRotOff, pData->mnOrientation );
            pWindow->Invert( aPoly, nInvertStyle );
        }
    }
    else
        pWindow->Invert( aRect, nInvertStyle );
    pWindow->EnableMapMode( bMapMode );
}

// -----------------------------------------------------------------------

void Cursor::ImplDraw()
{
    if ( mpData && mpData->mpWindow && !mpData->mbCurVisible )
    {
        Window* pWindow         = mpData->mpWindow;
        mpData->maPixPos        = pWindow->LogicToPixel( maPos );
        mpData->maPixSize       = pWindow->LogicToPixel( maSize );
        mpData->mnPixSlant      = pWindow->LogicToPixel( Size( mnSlant, 0 ) ).Width();
        mpData->mnOrientation   = mnOrientation;
        mpData->mnDirection     = mnDirection;
        long nOffsetY           = pWindow->LogicToPixel( Size( 0, mnOffsetY ) ).Height();

        // Position um den Offset korrigieren
        mpData->maPixPos.Y() -= nOffsetY;
        mpData->maPixRotOff = mpData->maPixPos;
        mpData->maPixRotOff.Y() += nOffsetY;

        // Wenn groesse 0 ist, nehmen wir die breite, die in den
        // Settings eingestellt ist
        if ( !mpData->maPixSize.Width() )
            mpData->maPixSize.Width() = pWindow->GetSettings().GetStyleSettings().GetCursorSize();

        // Ausgabeflaeche berechnen und ausgeben
        ImplCursorInvert( mpData );
        mpData->mbCurVisible = TRUE;
#ifdef REMOTE_APPSERVER
        // update remote cursor pos
        ImplUpdateCursorRect( pWindow );
#endif
    }
}

// -----------------------------------------------------------------------

void Cursor::ImplRestore()
{
    if ( mpData && mpData->mbCurVisible )
    {
        ImplCursorInvert( mpData );
        mpData->mbCurVisible = FALSE;
    }
}

// -----------------------------------------------------------------------

void Cursor::ImplShow( BOOL bDrawDirect )
{
    if ( mbVisible )
    {
        Window* pWindow;
        if ( mpWindow )
            pWindow = mpWindow;
        else
        {
            // Gibt es ein aktives Fenster und ist der Cursor in dieses Fenster
            // selektiert, dann zeige den Cursor an
            pWindow = Application::GetFocusWindow();
            if ( !pWindow || (pWindow->mpCursor != this) || pWindow->mbInPaint
                || !pWindow->mpFrameData->mbHasFocus )
                pWindow = NULL;
        }

        if ( pWindow )
        {
            if ( !mpData )
            {
                mpData = new ImplCursorData;
                mpData->mbCurVisible = FALSE;
                mpData->maTimer.SetTimeoutHdl( LINK( this, Cursor, ImplTimerHdl ) );
            }

            mpData->mpWindow    = pWindow;
            mpData->mnStyle     = mnStyle;
            if ( bDrawDirect )
                ImplDraw();

            if ( !mpWindow )
            {
                mpData->maTimer.SetTimeout( pWindow->GetSettings().GetStyleSettings().GetCursorBlinkTime() );
                if ( mpData->maTimer.GetTimeout() != STYLE_CURSOR_NOBLINKTIME )
                    mpData->maTimer.Start();
                else if ( !mpData->mbCurVisible )
                    ImplDraw();
            }
        }
    }
}

// -----------------------------------------------------------------------

void Cursor::ImplHide()
{
    if ( mpData && mpData->mpWindow )
    {
        if ( mpData->mbCurVisible )
            ImplRestore();

        mpData->maTimer.Stop();
        mpData->mpWindow = NULL;
    }
}

// -----------------------------------------------------------------------

void Cursor::ImplNew()
{
    if ( mbVisible && mpData && mpData->mpWindow )
    {
        if ( mpData->mbCurVisible )
            ImplRestore();

        ImplDraw();
        if ( !mpWindow )
        {
            if ( mpData->maTimer.GetTimeout() != STYLE_CURSOR_NOBLINKTIME )
                mpData->maTimer.Start();
        }
    }
}

// -----------------------------------------------------------------------

IMPL_LINK( Cursor, ImplTimerHdl, AutoTimer*, EMPTYARG )
{
    if ( mpData->mbCurVisible )
        ImplRestore();
    else
        ImplDraw();
    return 0;
}

// =======================================================================

Cursor::Cursor()
{
    mpData          = NULL;
    mpWindow        = NULL;
    mnSlant         = 0;
    mnOffsetY       = 0;
    mnOrientation   = 0;
    mnDirection     = 0;
    mnStyle         = 0;
    mbVisible       = FALSE;
}

// -----------------------------------------------------------------------

Cursor::Cursor( const Cursor& rCursor ) :
    maPos( rCursor.maPos ),
    maSize( rCursor.maSize )
{
    mpData          = NULL;
    mpWindow        = NULL;
    mnSlant         = rCursor.mnSlant;
    mnOrientation   = rCursor.mnOrientation;
    mnDirection     = rCursor.mnDirection;
    mnStyle         = 0;
    mbVisible       = rCursor.mbVisible;
}

// -----------------------------------------------------------------------

Cursor::~Cursor()
{
    if ( mpData )
    {
        if ( mpData->mbCurVisible )
            ImplRestore();

        delete mpData;
    }
}

// -----------------------------------------------------------------------

void Cursor::SetStyle( USHORT nStyle )
{
    if ( mnStyle != nStyle )
    {
        mnStyle = nStyle;
        ImplNew();
    }
}

// -----------------------------------------------------------------------

void Cursor::Show()
{
    if ( !mbVisible )
    {
        mbVisible = TRUE;
        ImplShow();
    }
}

// -----------------------------------------------------------------------

void Cursor::Hide()
{
    if ( mbVisible )
    {
        mbVisible = FALSE;
        ImplHide();
    }
}

// -----------------------------------------------------------------------

void Cursor::SetWindow( Window* pWindow )
{
    if ( mpWindow != pWindow )
    {
        mpWindow = pWindow;
        ImplNew();
    }
}

// -----------------------------------------------------------------------

void Cursor::SetPos( const Point& rPoint )
{
    if ( maPos != rPoint )
    {
        maPos = rPoint;
        ImplNew();
    }
}

// -----------------------------------------------------------------------

void Cursor::SetOffsetY( long nNewOffsetY )
{
    if ( mnOffsetY != nNewOffsetY )
    {
        mnOffsetY = nNewOffsetY;
        ImplNew();
    }
}

// -----------------------------------------------------------------------

void Cursor::SetSize( const Size& rSize )
{
    if ( maSize != rSize )
    {
        maSize = rSize;
        ImplNew();
    }
}

// -----------------------------------------------------------------------

void Cursor::SetWidth( long nNewWidth )
{
    if ( maSize.Width() != nNewWidth )
    {
        maSize.Width() = nNewWidth;
        ImplNew();
    }
}

// -----------------------------------------------------------------------

void Cursor::SetHeight( long nNewHeight )
{
    if ( maSize.Height() != nNewHeight )
    {
        maSize.Height() = nNewHeight;
        ImplNew();
    }
}

// -----------------------------------------------------------------------

void Cursor::SetSlant( long nNewSlant )
{
    if ( mnSlant != nNewSlant )
    {
        mnSlant = nNewSlant;
        ImplNew();
    }
}

// -----------------------------------------------------------------------

void Cursor::SetOrientation( short nNewOrientation )
{
    if ( mnOrientation != nNewOrientation )
    {
        mnOrientation = nNewOrientation;
        ImplNew();
    }
}

// -----------------------------------------------------------------------

void Cursor::SetDirection( unsigned char nNewDirection )
{
    if ( mnDirection != nNewDirection )
    {
        mnDirection = nNewDirection;
        ImplNew();
    }
}

// -----------------------------------------------------------------------

Cursor& Cursor::operator=( const Cursor& rCursor )
{
    maPos           = rCursor.maPos;
    maSize          = rCursor.maSize;
    mnSlant         = rCursor.mnSlant;
    mnOrientation   = rCursor.mnOrientation;
    mnDirection     = rCursor.mnDirection;
    mbVisible       = rCursor.mbVisible;
    ImplNew();

    return *this;
}

// -----------------------------------------------------------------------

BOOL Cursor::operator==( const Cursor& rCursor ) const
{
    if ( (maPos         == rCursor.maPos)           &&
         (maSize        == rCursor.maSize)          &&
         (mnSlant       == rCursor.mnSlant)         &&
         (mnOrientation == rCursor.mnOrientation)   &&
         (mnDirection   == rCursor.mnDirection)     &&
         (mbVisible     == rCursor.mbVisible) )
        return TRUE;
    else
        return FALSE;
}
<commit_msg>INTEGRATION: CWS vclcleanup01 (1.5.204); FILE MERGED 2003/11/28 07:32:54 mt 1.5.204.1: #i22952# Removed App Server code<commit_after>/*************************************************************************
 *
 *  $RCSfile: cursor.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: rt $ $Date: 2003-12-01 13:32:38 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/

#define _SV_CURSOR_CXX

#ifndef _SV_SVAPP_HXX
#include <svapp.hxx>
#endif
#ifndef _SV_TIMER_HXX
#include <timer.hxx>
#endif
#ifndef _SV_SETTINGS_HXX
#include <settings.hxx>
#endif
#ifndef _SV_WINDOW_HXX
#include <window.hxx>
#endif
#ifndef _SV_WINDOW_H
#include <window.h>
#endif
#ifndef _SV_POLY_HXX
#include <poly.hxx>
#endif
#ifndef _SV_CURSOR_HXX
#include <cursor.hxx>
#endif

// =======================================================================

struct ImplCursorData
{
    AutoTimer       maTimer;            // Timer
    Point           maPixPos;           // Pixel-Position
    Point           maPixRotOff;        // Pixel-Offset-Position
    Size            maPixSize;          // Pixel-Size
    long            mnPixSlant;         // Pixel-Slant
    short           mnOrientation;      // Pixel-Orientation
    unsigned char   mnDirection;        // indicates writing direction
    USHORT          mnStyle;            // Cursor-Style
    BOOL            mbCurVisible;       // Ist Cursor aktuell sichtbar
    Window*         mpWindow;           // Zugeordnetes Windows
};

// =======================================================================

static void ImplCursorInvert( ImplCursorData* pData )
{
    Window* pWindow  = pData->mpWindow;
    BOOL    bMapMode = pWindow->IsMapModeEnabled();
    pWindow->EnableMapMode( FALSE );
    USHORT nInvertStyle;
    if ( pData->mnStyle & CURSOR_SHADOW )
        nInvertStyle = INVERT_50;
    else
        nInvertStyle = 0;

    Rectangle aRect( pData->maPixPos, pData->maPixSize );
    if ( pData->mnDirection || pData->mnOrientation || pData->mnPixSlant )
    {
        Polygon aPoly( aRect );
        if( aPoly.GetSize() == 5 )
        {
            aPoly[1].X() += 1;  // include the right border
            aPoly[2].X() += 1;
            if ( pData->mnPixSlant )
            {
                Point aPoint = aPoly.GetPoint( 0 );
                aPoint.X() += pData->mnPixSlant;
                aPoly.SetPoint( aPoint, 0 );
                aPoly.SetPoint( aPoint, 4 );
                aPoint = aPoly.GetPoint( 1 );
                aPoint.X() += pData->mnPixSlant;
                aPoly.SetPoint( aPoint, 1 );
            }

            // apply direction flag after slant to use the correct shape
            if ( pData->mnDirection )
            {
                Point pAry[7];
                int delta = 3*aRect.getWidth()+1;
                if( pData->mnDirection == CURSOR_DIRECTION_LTR )
                {
                    // left-to-right
                    pAry[0] = aPoly.GetPoint( 0 );
                    pAry[1] = aPoly.GetPoint( 1 );
                    pAry[2] = pAry[1];
                    pAry[2].X() += delta;
                    pAry[3] =  pAry[1];
                    pAry[3].Y() += delta;
                    pAry[4] = aPoly.GetPoint( 2 );
                    pAry[5] = aPoly.GetPoint( 3 );
                    pAry[6] = aPoly.GetPoint( 4 );
                }
                else if( pData->mnDirection == CURSOR_DIRECTION_RTL )
                {
                    // right-to-left
                    pAry[0] = aPoly.GetPoint( 0 );
                    pAry[1] = aPoly.GetPoint( 1 );
                    pAry[2] = aPoly.GetPoint( 2 );
                    pAry[3] = aPoly.GetPoint( 3 );
                    pAry[4] = pAry[0];
                    pAry[4].Y() += delta;
                    pAry[5] =  pAry[0];
                    pAry[5].X() -= delta;
                    pAry[6] = aPoly.GetPoint( 4 );
                }
                aPoly = Polygon( 7, pAry);
            }

            if ( pData->mnOrientation )
                aPoly.Rotate( pData->maPixRotOff, pData->mnOrientation );
            pWindow->Invert( aPoly, nInvertStyle );
        }
    }
    else
        pWindow->Invert( aRect, nInvertStyle );
    pWindow->EnableMapMode( bMapMode );
}

// -----------------------------------------------------------------------

void Cursor::ImplDraw()
{
    if ( mpData && mpData->mpWindow && !mpData->mbCurVisible )
    {
        Window* pWindow         = mpData->mpWindow;
        mpData->maPixPos        = pWindow->LogicToPixel( maPos );
        mpData->maPixSize       = pWindow->LogicToPixel( maSize );
        mpData->mnPixSlant      = pWindow->LogicToPixel( Size( mnSlant, 0 ) ).Width();
        mpData->mnOrientation   = mnOrientation;
        mpData->mnDirection     = mnDirection;
        long nOffsetY           = pWindow->LogicToPixel( Size( 0, mnOffsetY ) ).Height();

        // Position um den Offset korrigieren
        mpData->maPixPos.Y() -= nOffsetY;
        mpData->maPixRotOff = mpData->maPixPos;
        mpData->maPixRotOff.Y() += nOffsetY;

        // Wenn groesse 0 ist, nehmen wir die breite, die in den
        // Settings eingestellt ist
        if ( !mpData->maPixSize.Width() )
            mpData->maPixSize.Width() = pWindow->GetSettings().GetStyleSettings().GetCursorSize();

        // Ausgabeflaeche berechnen und ausgeben
        ImplCursorInvert( mpData );
        mpData->mbCurVisible = TRUE;
    }
}

// -----------------------------------------------------------------------

void Cursor::ImplRestore()
{
    if ( mpData && mpData->mbCurVisible )
    {
        ImplCursorInvert( mpData );
        mpData->mbCurVisible = FALSE;
    }
}

// -----------------------------------------------------------------------

void Cursor::ImplShow( BOOL bDrawDirect )
{
    if ( mbVisible )
    {
        Window* pWindow;
        if ( mpWindow )
            pWindow = mpWindow;
        else
        {
            // Gibt es ein aktives Fenster und ist der Cursor in dieses Fenster
            // selektiert, dann zeige den Cursor an
            pWindow = Application::GetFocusWindow();
            if ( !pWindow || (pWindow->mpCursor != this) || pWindow->mbInPaint
                || !pWindow->mpFrameData->mbHasFocus )
                pWindow = NULL;
        }

        if ( pWindow )
        {
            if ( !mpData )
            {
                mpData = new ImplCursorData;
                mpData->mbCurVisible = FALSE;
                mpData->maTimer.SetTimeoutHdl( LINK( this, Cursor, ImplTimerHdl ) );
            }

            mpData->mpWindow    = pWindow;
            mpData->mnStyle     = mnStyle;
            if ( bDrawDirect )
                ImplDraw();

            if ( !mpWindow )
            {
                mpData->maTimer.SetTimeout( pWindow->GetSettings().GetStyleSettings().GetCursorBlinkTime() );
                if ( mpData->maTimer.GetTimeout() != STYLE_CURSOR_NOBLINKTIME )
                    mpData->maTimer.Start();
                else if ( !mpData->mbCurVisible )
                    ImplDraw();
            }
        }
    }
}

// -----------------------------------------------------------------------

void Cursor::ImplHide()
{
    if ( mpData && mpData->mpWindow )
    {
        if ( mpData->mbCurVisible )
            ImplRestore();

        mpData->maTimer.Stop();
        mpData->mpWindow = NULL;
    }
}

// -----------------------------------------------------------------------

void Cursor::ImplNew()
{
    if ( mbVisible && mpData && mpData->mpWindow )
    {
        if ( mpData->mbCurVisible )
            ImplRestore();

        ImplDraw();
        if ( !mpWindow )
        {
            if ( mpData->maTimer.GetTimeout() != STYLE_CURSOR_NOBLINKTIME )
                mpData->maTimer.Start();
        }
    }
}

// -----------------------------------------------------------------------

IMPL_LINK( Cursor, ImplTimerHdl, AutoTimer*, EMPTYARG )
{
    if ( mpData->mbCurVisible )
        ImplRestore();
    else
        ImplDraw();
    return 0;
}

// =======================================================================

Cursor::Cursor()
{
    mpData          = NULL;
    mpWindow        = NULL;
    mnSlant         = 0;
    mnOffsetY       = 0;
    mnOrientation   = 0;
    mnDirection     = 0;
    mnStyle         = 0;
    mbVisible       = FALSE;
}

// -----------------------------------------------------------------------

Cursor::Cursor( const Cursor& rCursor ) :
    maPos( rCursor.maPos ),
    maSize( rCursor.maSize )
{
    mpData          = NULL;
    mpWindow        = NULL;
    mnSlant         = rCursor.mnSlant;
    mnOrientation   = rCursor.mnOrientation;
    mnDirection     = rCursor.mnDirection;
    mnStyle         = 0;
    mbVisible       = rCursor.mbVisible;
}

// -----------------------------------------------------------------------

Cursor::~Cursor()
{
    if ( mpData )
    {
        if ( mpData->mbCurVisible )
            ImplRestore();

        delete mpData;
    }
}

// -----------------------------------------------------------------------

void Cursor::SetStyle( USHORT nStyle )
{
    if ( mnStyle != nStyle )
    {
        mnStyle = nStyle;
        ImplNew();
    }
}

// -----------------------------------------------------------------------

void Cursor::Show()
{
    if ( !mbVisible )
    {
        mbVisible = TRUE;
        ImplShow();
    }
}

// -----------------------------------------------------------------------

void Cursor::Hide()
{
    if ( mbVisible )
    {
        mbVisible = FALSE;
        ImplHide();
    }
}

// -----------------------------------------------------------------------

void Cursor::SetWindow( Window* pWindow )
{
    if ( mpWindow != pWindow )
    {
        mpWindow = pWindow;
        ImplNew();
    }
}

// -----------------------------------------------------------------------

void Cursor::SetPos( const Point& rPoint )
{
    if ( maPos != rPoint )
    {
        maPos = rPoint;
        ImplNew();
    }
}

// -----------------------------------------------------------------------

void Cursor::SetOffsetY( long nNewOffsetY )
{
    if ( mnOffsetY != nNewOffsetY )
    {
        mnOffsetY = nNewOffsetY;
        ImplNew();
    }
}

// -----------------------------------------------------------------------

void Cursor::SetSize( const Size& rSize )
{
    if ( maSize != rSize )
    {
        maSize = rSize;
        ImplNew();
    }
}

// -----------------------------------------------------------------------

void Cursor::SetWidth( long nNewWidth )
{
    if ( maSize.Width() != nNewWidth )
    {
        maSize.Width() = nNewWidth;
        ImplNew();
    }
}

// -----------------------------------------------------------------------

void Cursor::SetHeight( long nNewHeight )
{
    if ( maSize.Height() != nNewHeight )
    {
        maSize.Height() = nNewHeight;
        ImplNew();
    }
}

// -----------------------------------------------------------------------

void Cursor::SetSlant( long nNewSlant )
{
    if ( mnSlant != nNewSlant )
    {
        mnSlant = nNewSlant;
        ImplNew();
    }
}

// -----------------------------------------------------------------------

void Cursor::SetOrientation( short nNewOrientation )
{
    if ( mnOrientation != nNewOrientation )
    {
        mnOrientation = nNewOrientation;
        ImplNew();
    }
}

// -----------------------------------------------------------------------

void Cursor::SetDirection( unsigned char nNewDirection )
{
    if ( mnDirection != nNewDirection )
    {
        mnDirection = nNewDirection;
        ImplNew();
    }
}

// -----------------------------------------------------------------------

Cursor& Cursor::operator=( const Cursor& rCursor )
{
    maPos           = rCursor.maPos;
    maSize          = rCursor.maSize;
    mnSlant         = rCursor.mnSlant;
    mnOrientation   = rCursor.mnOrientation;
    mnDirection     = rCursor.mnDirection;
    mbVisible       = rCursor.mbVisible;
    ImplNew();

    return *this;
}

// -----------------------------------------------------------------------

BOOL Cursor::operator==( const Cursor& rCursor ) const
{
    if ( (maPos         == rCursor.maPos)           &&
         (maSize        == rCursor.maSize)          &&
         (mnSlant       == rCursor.mnSlant)         &&
         (mnOrientation == rCursor.mnOrientation)   &&
         (mnDirection   == rCursor.mnDirection)     &&
         (mbVisible     == rCursor.mbVisible) )
        return TRUE;
    else
        return FALSE;
}
<|endoftext|>


<commit_before><commit_msg>vcl: Move constructor and graphics functions to top of window.cxx<commit_after><|endoftext|>


<commit_before>// In this file, we assume the input matrix is in CSR format, in which
// rowPtr and colIdx are 1-based. We convert their values to 0-based
// on the fly so that the underlying library keeps as 0-based.

#include <cstdio>
#include <cassert>
#include <cstring>
#include <climits>
#include <vector>

#include <omp.h>

#include "CSR.hpp"

using namespace std;

void getInversePerm(int *inversePerm, const int *perm, int n)
{
#pragma omp parallel for
#pragma simd
  for (int i = 0; i < n; ++i) {
    inversePerm[perm[i]] = i;
  }
}

#ifdef USE_BOOST
#define BOOST_GRAPH_USE_NEW_CSR_INTERFACE
#include <boost/graph/compressed_sparse_row_graph.hpp>
#include <boost/graph/cuthill_mckee_ordering.hpp>
#include <boost/graph/bandwidth.hpp>

using namespace boost;

typedef compressed_sparse_row_graph<directedS> Graph;

// convert CSR to boost Graph
static Graph *constructBoostTaskGraph(const CSR& A)
{
  vector<pair<int, int> > edges;
  for (int i = 0; i < A.m; ++i) {
    for (int j = A.rowPtr[i] - 1; j < A.rowPtr[i + 1] - 1; ++j) {
      int src = A.colIdx[j] - 1;
      if (src != i) {
        edges.push_back(make_pair(src, i));
      }
    }
  } // for each row i

  return new Graph(edges_are_unsorted_t(), edges.begin(), edges.end(), A.m);
}

void CSR::boostGetRCMPermutation(int *perm, int *inversePerm, int source /*=-1*/) const
{
  Graph *g = constructBoostTaskGraph(*this);

  vector<int> v;
  if (-1 == source) {
    cuthill_mckee_ordering(*g, back_inserter(v));
  }
  else {
    typedef out_degree_property_map<Graph> DegreeMap;
    std::vector<default_color_type> colors(num_vertices(*g));

    cuthill_mckee_ordering(*g, source, back_inserter(v), make_iterator_property_map(&colors[0], get(vertex_index, *g), colors[0]), make_out_degree_map(*g));
  }
  delete g;

  reverse_copy(v.begin(), v.end(), inversePerm);

  getInversePerm(perm, inversePerm, m);
}
#endif // USE_BOOST

void CSR::permuteRowPtr_(CSR* out, const int *inversePerm) const
{
  out->rowPtr[0] = 1;

  int rowPtrSum[omp_get_max_threads() + 1];
  rowPtrSum[0] = 0;

#pragma omp parallel
  {
    int nthreads = omp_get_num_threads();
    int tid = omp_get_thread_num();

    int iPerThread = (m + nthreads - 1) / nthreads;
    int iBegin = min(iPerThread*tid, m);
    int iEnd = min(iBegin + iPerThread, m);

    out->rowPtr[iBegin] = 1;
    int i;
    for (i = iBegin; i < iEnd - 1; ++i) {
      int row = inversePerm ? inversePerm[i] : i;
      int begin = rowPtr[row], end = rowPtr[row + 1];
      out->rowPtr[i + 1] = out->rowPtr[i] + end - begin;
    }
    if (i < iEnd) {
      int row = inversePerm ? inversePerm[i] : i;
      int begin = rowPtr[row], end = rowPtr[row + 1];
      rowPtrSum[tid + 1] = out->rowPtr[i] + end - begin - 1;
    }
    else {
      rowPtrSum[tid + 1] = 0;
    }

#pragma omp barrier
#pragma omp single
    {
      for (int tid = 1; tid < nthreads; ++tid) {
        rowPtrSum[tid + 1] += rowPtrSum[tid];
      }
      out->rowPtr[m] = rowPtrSum[nthreads] + 1;
      assert(out->rowPtr[m] == rowPtr[m]);
    }

    for (i = iBegin; i < iEnd; ++i) {
      out->rowPtr[i] += rowPtrSum[tid];
    }
  } // omp parallel
}

void CSR::permute(CSR *out, const int *columnPerm, const int *rowInversePerm) const
{
  permuteRowPtr_(out, rowInversePerm);

#pragma omp parallel for
  for (int i = 0; i < m; ++i) {
    int row = rowInversePerm ? rowInversePerm[i] : i;
    int begin = rowPtr[row] - 1, end = rowPtr[row + 1] - 1;
    int newBegin = out->rowPtr[i] - 1;

    int k = newBegin;
    for (int j = begin; j < end; ++j, ++k) {
      int c = colIdx[j] - 1;
      int newColIdx = columnPerm[c];

      out->colIdx[k] = newColIdx + 1;
      out->values[k] = values[j];
    }

    memcpy(
      out->values + newBegin + (end - begin),
      values + end, (rowPtr[row + 1] -1 - end)*sizeof(double));
    memcpy(
      out->colIdx + newBegin + (end - begin),
      colIdx + end, (rowPtr[row + 1] -1 - end)*sizeof(int));

    // insertion sort
    for (int j = newBegin + 1; j < newBegin + (end - begin); ++j) {
      int c = out->colIdx[j];
      double v = out->values[j];

      int k = j - 1;
      while (k >= newBegin && out->colIdx[k] > c) {
        out->colIdx[k + 1] = out->colIdx[k];
        out->values[k + 1] = out->values[k];
        --k;
      }

      out->colIdx[k + 1] = c;
      out->values[k + 1] = v;
    }
  } // for each row
}

int CSR::getBandwidth() const
{
  int bw = INT_MIN;
  for (int i = 0; i < m; ++i) {
    for (int j = rowPtr[i] - 1; j < rowPtr[i + 1] - 1; ++j) {
      int c = colIdx[j] - 1;
      int temp = c - i;
      if (temp < 0) temp = -temp;
      bw = max(temp, bw);
    }
  }
  return bw;
}

void CSR::printInDense() const
{
  // Raw format
  printf("RowPtr: ");
  for (int i = 0; i <= m; i++) {
    printf("%d ", rowPtr[i]);
  }
  printf("\nColIdx: ");
  for (int i = 0; i < rowPtr[m] - 1; i++) {
    printf("%d ", colIdx[i]);
  }
  printf("\nValues: ");
  for (int i = 0; i < rowPtr[m] - 1; i++) {
    printf("%f ", values[i]);
  }
  printf("\n\n");

  for (int i = 0; i < m; ++i) {
    int jj = 0;
    printf("%d: ", i);
    for (int j = rowPtr[i] - 1; j < rowPtr[i + 1] - 1; ++j) {
      int c = colIdx[j] - 1;
      for (; jj < c; ++jj) printf("0 ");
      printf("%g ", values[j]);
      ++jj;
    }
    for (; jj < m; ++jj) printf("0 ");
    printf("\n");
  }
}
<commit_msg>add sort parameter to CSR 1 based indexing permutation<commit_after>// In this file, we assume the input matrix is in CSR format, in which
// rowPtr and colIdx are 1-based. We convert their values to 0-based
// on the fly so that the underlying library keeps as 0-based.

#include <cstdio>
#include <cassert>
#include <cstring>
#include <climits>
#include <vector>

#include <omp.h>

#include "CSR.hpp"

using namespace std;

void getInversePerm(int *inversePerm, const int *perm, int n)
{
#pragma omp parallel for
#pragma simd
  for (int i = 0; i < n; ++i) {
    inversePerm[perm[i]] = i;
  }
}

#ifdef USE_BOOST
#define BOOST_GRAPH_USE_NEW_CSR_INTERFACE
#include <boost/graph/compressed_sparse_row_graph.hpp>
#include <boost/graph/cuthill_mckee_ordering.hpp>
#include <boost/graph/bandwidth.hpp>

using namespace boost;

typedef compressed_sparse_row_graph<directedS> Graph;

// convert CSR to boost Graph
static Graph *constructBoostTaskGraph(const CSR& A)
{
  vector<pair<int, int> > edges;
  for (int i = 0; i < A.m; ++i) {
    for (int j = A.rowPtr[i] - 1; j < A.rowPtr[i + 1] - 1; ++j) {
      int src = A.colIdx[j] - 1;
      if (src != i) {
        edges.push_back(make_pair(src, i));
      }
    }
  } // for each row i

  return new Graph(edges_are_unsorted_t(), edges.begin(), edges.end(), A.m);
}

void CSR::boostGetRCMPermutation(int *perm, int *inversePerm, int source /*=-1*/) const
{
  Graph *g = constructBoostTaskGraph(*this);

  vector<int> v;
  if (-1 == source) {
    cuthill_mckee_ordering(*g, back_inserter(v));
  }
  else {
    typedef out_degree_property_map<Graph> DegreeMap;
    std::vector<default_color_type> colors(num_vertices(*g));

    cuthill_mckee_ordering(*g, source, back_inserter(v), make_iterator_property_map(&colors[0], get(vertex_index, *g), colors[0]), make_out_degree_map(*g));
  }
  delete g;

  reverse_copy(v.begin(), v.end(), inversePerm);

  getInversePerm(perm, inversePerm, m);
}
#endif // USE_BOOST

void CSR::permuteRowPtr_(CSR* out, const int *inversePerm) const
{
  out->rowPtr[0] = 1;

  int rowPtrSum[omp_get_max_threads() + 1];
  rowPtrSum[0] = 0;

#pragma omp parallel
  {
    int nthreads = omp_get_num_threads();
    int tid = omp_get_thread_num();

    int iPerThread = (m + nthreads - 1) / nthreads;
    int iBegin = min(iPerThread*tid, m);
    int iEnd = min(iBegin + iPerThread, m);

    out->rowPtr[iBegin] = 1;
    int i;
    for (i = iBegin; i < iEnd - 1; ++i) {
      int row = inversePerm ? inversePerm[i] : i;
      int begin = rowPtr[row], end = rowPtr[row + 1];
      out->rowPtr[i + 1] = out->rowPtr[i] + end - begin;
    }
    if (i < iEnd) {
      int row = inversePerm ? inversePerm[i] : i;
      int begin = rowPtr[row], end = rowPtr[row + 1];
      rowPtrSum[tid + 1] = out->rowPtr[i] + end - begin - 1;
    }
    else {
      rowPtrSum[tid + 1] = 0;
    }

#pragma omp barrier
#pragma omp single
    {
      for (int tid = 1; tid < nthreads; ++tid) {
        rowPtrSum[tid + 1] += rowPtrSum[tid];
      }
      out->rowPtr[m] = rowPtrSum[nthreads] + 1;
      assert(out->rowPtr[m] == rowPtr[m]);
    }

    for (i = iBegin; i < iEnd; ++i) {
      out->rowPtr[i] += rowPtrSum[tid];
    }
  } // omp parallel
}

void CSR::permute(CSR *out, const int *columnPerm, const int *rowInversePerm, bool sort/*=false*/) const
{
  permuteRowPtr_(out, rowInversePerm);

  if (sort) {
#pragma omp parallel for
    for (int i = 0; i < m; ++i) {
      int row = rowInversePerm ? rowInversePerm[i] : i;
      int begin = rowPtr[row] - 1, end = rowPtr[row + 1] - 1;
      int newBegin = out->rowPtr[i] - 1;

      int k = newBegin;
      for (int j = begin; j < end; ++j, ++k) {
        int c = colIdx[j] - 1;
        int newColIdx = columnPerm[c];

        out->colIdx[k] = newColIdx + 1;
        out->values[k] = values[j];
      }

      // insertion sort
      for (int j = newBegin + 1; j < newBegin + (end - begin); ++j) {
        int c = out->colIdx[j];
        double v = out->values[j];

        int k = j - 1;
        while (k >= newBegin && out->colIdx[k] > c) {
          out->colIdx[k + 1] = out->colIdx[k];
          out->values[k + 1] = out->values[k];
          --k;
        }

        out->colIdx[k + 1] = c;
        out->values[k + 1] = v;
      }
    } // for each row
  }
  else {
#pragma omp parallel for
    for (int i = 0; i < m; ++i) {
      int row = rowInversePerm ? rowInversePerm[i] : i;
      int begin = rowPtr[row] - 1, end = rowPtr[row + 1] - 1;
      int newBegin = out->rowPtr[i] - 1;

      int k = newBegin;
      for (int j = begin; j < end; ++j, ++k) {
        int c = colIdx[j] - 1;
        int newColIdx = columnPerm[c];

        out->colIdx[k] = newColIdx + 1;
        out->values[k] = values[j];
      }
    }
  }
}

int CSR::getBandwidth() const
{
  int bw = INT_MIN;
  for (int i = 0; i < m; ++i) {
    for (int j = rowPtr[i] - 1; j < rowPtr[i + 1] - 1; ++j) {
      int c = colIdx[j] - 1;
      int temp = c - i;
      if (temp < 0) temp = -temp;
      bw = max(temp, bw);
    }
  }
  return bw;
}

void CSR::printInDense() const
{
  // Raw format
  printf("RowPtr: ");
  for (int i = 0; i <= m; i++) {
    printf("%d ", rowPtr[i]);
  }
  printf("\nColIdx: ");
  for (int i = 0; i < rowPtr[m] - 1; i++) {
    printf("%d ", colIdx[i]);
  }
  printf("\nValues: ");
  for (int i = 0; i < rowPtr[m] - 1; i++) {
    printf("%f ", values[i]);
  }
  printf("\n\n");

  for (int i = 0; i < m; ++i) {
    int jj = 0;
    printf("%d: ", i);
    for (int j = rowPtr[i] - 1; j < rowPtr[i + 1] - 1; ++j) {
      int c = colIdx[j] - 1;
      for (; jj < c; ++jj) printf("0 ");
      printf("%g ", values[j]);
      ++jj;
    }
    for (; jj < m; ++jj) printf("0 ");
    printf("\n");
  }
}
<|endoftext|>


<commit_before>// System headers
#include <iostream>
#include <algorithm>
#include <fstream>
#include <sstream>
#include <ctime>
// --------------

#include "csv_data_manipulator.hpp"

// --- CONSTANTS --- //
const char *CSVData::VERSION = "v0.2a"; // XXX: Update version here
const char CSVData::CSV_DELIMITER = ',';
const char CSVData::C_STRING_DELIMITER = '"';
const char *CSVData::S_STRING_DELIMITER = "\"";
const char *CSVData::TMP_DELIM_REPLACEMENT = "#|#";
const char CSVData::DECIMAL_DELIMITER = '.';

const int CSVData::ASC = 1;
const int CSVData::DESC = 2;
// ----------------- //

using namespace std;

// ==========================================================================================================|

CSVData::CSVData() : m_is_modified(false), m_is_unified(true), m_rows(0), m_cols(0)
{
}

// ----------------------------------------------------------------------------------------------------------|

CSVData::CSVData(CSVData &rhs) :
    m_is_modified(rhs.is_modified()), m_is_unified(rhs.is_unified()),
    m_rows(rhs.m_rows), m_cols(rhs.m_cols)
{
}

// ----------------------------------------------------------------------------------------------------------|

CSVData::CSVData(const string &filename) :
    m_is_modified(false), m_is_unified(true), m_rows(0), m_cols(0)
{
    read_file(filename);
    m_is_modified = false;
}

// ----------------------------------------------------------------------------------------------------------|

const string CSVData::get_value(int row, int col)
{
     if (row >= m_rows || col >= m_cols || row < 0 || col < 0) return "";
     return const_cast<string&>(m_data.at(row).at(col));
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::set_value(int row, int col, string value)
{
     if (row >= m_rows || col >= m_cols || row < 0 || col < 0) return;

     m_data.at(row).at(col) = value;
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::add_row(vector<string> row_data)
{
     size_t new_row_size = row_data.size();
     if (new_row_size != m_cols && m_is_unified) m_is_unified = false;
     m_data.push_back(row_data);
     m_rows++;
     if (m_cols < new_row_size) m_cols = new_row_size;
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::add_row(vector<string> row_data, int pos)
{
     if (pos < 0 || pos >= m_data.size()) return;

     vector< vector<string> >::iterator it = m_data.begin() + pos;

     size_t new_row_size = row_data.size();
     if (new_row_size != m_cols && m_is_unified) m_is_unified = false;

     m_data.insert(it, row_data);
     m_rows++;
     if (m_cols < new_row_size) m_cols = new_row_size;
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::delete_row(int row)
{
	if (row >= m_rows || row < 0) return;
	m_data.erase(m_data.begin() + row);
	m_rows--;
	m_is_modified = true;
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::delete_row_if(function<bool(int, int, const std::string&)> cbFun)
{
    vector<int> rows_to_delete;

    for (int row = 0; row < m_data.size(); ++row) {
        for (int col = 0; col < m_data.at(row).size(); ++col) {
            if ( cbFun(row, col, m_data.at(row).at(col)) ) {
                rows_to_delete.push_back(row);
                break;
            }
        }
    }

    if (rows_to_delete.size() > 0) {
        sort(rows_to_delete.begin(), rows_to_delete.end(), std::greater<int>());
        for (int row = 0; row < rows_to_delete.size(); ++row) delete_row(rows_to_delete.at(row));
    }
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::delete_col(int col)
{
	if (col >= m_cols || col < 0) return;
	for (int i = 0; i < m_data.size(); ++i) {
		if (col < m_data.at(i).size()) {
			m_data.at(i).erase(m_data.at(i).begin() + col);
			m_is_modified = true;
		}
	}
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::delete_item(int row, int col)
{
	if (row >= m_rows || row < 0) return;
	if (col >= m_data.at(row).size() || col < 0) return;

	m_data.at(row).erase(m_data.at(row).begin() + col);
	m_is_modified = true;
	m_is_unified = false;
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::read_file(const string &filename)
{
    ifstream input_file(filename.c_str());

    if (!input_file.is_open()) {
        cerr << "Unable to open file '" << filename << "'. Check if file exists and if you have the right permissions." << endl;
        return;
    }

    m_data.clear();
    string line;

    int cols = 0;
    while (getline(input_file, line)) {
        int contains_strings = 0;
        if ( (contains_strings = count(line.begin(), line.end(), C_STRING_DELIMITER)) > 0 ) {
            size_t left = line.find(C_STRING_DELIMITER, 0);
            size_t right = line.find(C_STRING_DELIMITER, left + 1);

            while (left != string::npos && right != string::npos) {
                size_t found = left;
                while (true) {
                    found = line.find(C_STRING_DELIMITER, found);
                    if (found == string::npos) break;

                    line.replace(found, 1, TMP_DELIM_REPLACEMENT);
                    found += 3;
                }

                left = line.find(C_STRING_DELIMITER, right);
                right = line.find(C_STRING_DELIMITER, left + 1);
            }
        }

        stringstream ss(line);
        string tok, i_row;
        vector<string> row;

        while (getline(ss, tok, CSV_DELIMITER)) {
            if (tok.find(TMP_DELIM_REPLACEMENT) != string::npos) {
                i_row = tok;

                size_t found = 0;
                while (true) {
                    found = i_row.find(TMP_DELIM_REPLACEMENT, found);
                    if (found == string::npos) break;

                    i_row.replace(found, 3, string(S_STRING_DELIMITER));
                    found++;
                }
            } else {
                i_row = tok;
            }
            row.push_back(i_row);
        }

        if (cols != 0 && cols != row.size()) m_is_unified = false;

        cols = row.size();

        m_data.push_back(row);
    }

    input_file.close();

    m_is_modified = true;
    m_cols = cols;
    m_rows = m_data.size();
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::write_data(const string &filename)
{
    ofstream output_file(filename.c_str(), ofstream::out);

    if (!output_file.is_open()) {
        cerr << "Unable to open file '" << filename << "'. Check if you have the right permissions." << endl;
        return;
    }

    for (int row = 0; row < m_data.size(); ++row) {
        string new_line;

        vector<string> row_data = m_data.at(row);
        for (int i = 0; i < row_data.size(); i++) {
            new_line.append(row_data.at(i));
            new_line.append(string(1, CSV_DELIMITER));
        }

        size_t last_comma = new_line.find_last_of(",");
        new_line.replace(last_comma, 1, "\n");

        output_file << new_line;
    }

    output_file.close();

    m_is_modified = false;
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::convert_date_format(const std::string &old_format, const std::string &new_format, int column)
{
    for (int row = 0; row < m_data.size(); ++row) convert_date_format(old_format, new_format, row, column);
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::convert_date_format(const std::string &old_format, const std::string &new_format, int row, int column)
{
    if (column < 0 || column >= m_cols) {
        cerr << "Invalid column number: " << column << endl;
        return;
    }

    if (row < 0 || row >= m_rows) {
        cerr << "Invalid row number: " << row << endl;
        return;
    }

    vector<string> row_data = m_data.at(row);

    string old_date = row_data.at(column);
    std::tm od;
    strptime(old_date.c_str(), old_format.c_str(), &od);

    char buffer[256];
    strftime(buffer, sizeof(buffer), new_format.c_str(), &od);

    string new_date(buffer);

    m_data.at(row).at(column) = new_date;

    m_is_modified = true;
}

// ==========================================================================================================|

static bool is_digits(const string &str)
{
    return std::all_of(str.begin(), str.end(), ::isdigit);
}

// ==========================================================================================================|

void CSVData::sort_by_col(int col, int order)
{
    auto acs_compare_fun = [&](const vector< string > &row1, const vector< string > &row2) {
        bool ret_val;

        if (is_digits(row1[col]) && is_digits(row2[col])) {
            auto a = (row1[col].find(DECIMAL_DELIMITER) != string::npos) ? stod(row1[col]) : stol(row1[col]);
            auto b = (row2[col].find(DECIMAL_DELIMITER) != string::npos) ? stod(row2[col]) : stol(row2[col]);
            ret_val = a < b;
        } else {
             ret_val = row1[col] < row2[col];
        }

        return ret_val;
    };

    auto desc_compare_fun = [&](const vector< string > &row1, const vector< string > &row2) {
        bool ret_val;

        if (is_digits(row1[col]) && is_digits(row2[col])) {
            auto a = (row1[col].find(DECIMAL_DELIMITER) != string::npos) ? stod(row1[col]) : stol(row1[col]);
            auto b = (row2[col].find(DECIMAL_DELIMITER) != string::npos) ? stod(row2[col]) : stol(row2[col]);
            ret_val = a > b;
        } else {
             ret_val = row1[col] > row2[col];
        }

        return ret_val;
    };

    switch (order) {
        case DESC:
            sort(m_data.begin(), m_data.end(), desc_compare_fun);
            break;
        case ASC:
        default:
            sort(m_data.begin(), m_data.end(), acs_compare_fun);
            break;
    }
}

// ==========================================================================================================|
<commit_msg>set modified after sorting<commit_after>// System headers
#include <iostream>
#include <algorithm>
#include <fstream>
#include <sstream>
#include <ctime>
// --------------

#include "csv_data_manipulator.hpp"

// --- CONSTANTS --- //
const char *CSVData::VERSION = "v0.2a"; // XXX: Update version here
const char CSVData::CSV_DELIMITER = ',';
const char CSVData::C_STRING_DELIMITER = '"';
const char *CSVData::S_STRING_DELIMITER = "\"";
const char *CSVData::TMP_DELIM_REPLACEMENT = "#|#";
const char CSVData::DECIMAL_DELIMITER = '.';

const int CSVData::ASC = 1;
const int CSVData::DESC = 2;
// ----------------- //

using namespace std;

// ==========================================================================================================|

CSVData::CSVData() : m_is_modified(false), m_is_unified(true), m_rows(0), m_cols(0)
{
}

// ----------------------------------------------------------------------------------------------------------|

CSVData::CSVData(CSVData &rhs) :
    m_is_modified(rhs.is_modified()), m_is_unified(rhs.is_unified()),
    m_rows(rhs.m_rows), m_cols(rhs.m_cols)
{
}

// ----------------------------------------------------------------------------------------------------------|

CSVData::CSVData(const string &filename) :
    m_is_modified(false), m_is_unified(true), m_rows(0), m_cols(0)
{
    read_file(filename);
    m_is_modified = false;
}

// ----------------------------------------------------------------------------------------------------------|

const string CSVData::get_value(int row, int col)
{
     if (row >= m_rows || col >= m_cols || row < 0 || col < 0) return "";
     return const_cast<string&>(m_data.at(row).at(col));
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::set_value(int row, int col, string value)
{
     if (row >= m_rows || col >= m_cols || row < 0 || col < 0) return;

     m_data.at(row).at(col) = value;
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::add_row(vector<string> row_data)
{
     size_t new_row_size = row_data.size();
     if (new_row_size != m_cols && m_is_unified) m_is_unified = false;
     m_data.push_back(row_data);
     m_rows++;
     if (m_cols < new_row_size) m_cols = new_row_size;
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::add_row(vector<string> row_data, int pos)
{
     if (pos < 0 || pos >= m_data.size()) return;

     vector< vector<string> >::iterator it = m_data.begin() + pos;

     size_t new_row_size = row_data.size();
     if (new_row_size != m_cols && m_is_unified) m_is_unified = false;

     m_data.insert(it, row_data);
     m_rows++;
     if (m_cols < new_row_size) m_cols = new_row_size;
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::delete_row(int row)
{
	if (row >= m_rows || row < 0) return;
	m_data.erase(m_data.begin() + row);
	m_rows--;
	m_is_modified = true;
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::delete_row_if(function<bool(int, int, const std::string&)> cbFun)
{
    vector<int> rows_to_delete;

    for (int row = 0; row < m_data.size(); ++row) {
        for (int col = 0; col < m_data.at(row).size(); ++col) {
            if ( cbFun(row, col, m_data.at(row).at(col)) ) {
                rows_to_delete.push_back(row);
                break;
            }
        }
    }

    if (rows_to_delete.size() > 0) {
        sort(rows_to_delete.begin(), rows_to_delete.end(), std::greater<int>());
        for (int row = 0; row < rows_to_delete.size(); ++row) delete_row(rows_to_delete.at(row));
    }
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::delete_col(int col)
{
	if (col >= m_cols || col < 0) return;
	for (int i = 0; i < m_data.size(); ++i) {
		if (col < m_data.at(i).size()) {
			m_data.at(i).erase(m_data.at(i).begin() + col);
			m_is_modified = true;
		}
	}
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::delete_item(int row, int col)
{
	if (row >= m_rows || row < 0) return;
	if (col >= m_data.at(row).size() || col < 0) return;

	m_data.at(row).erase(m_data.at(row).begin() + col);
	m_is_modified = true;
	m_is_unified = false;
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::read_file(const string &filename)
{
    ifstream input_file(filename.c_str());

    if (!input_file.is_open()) {
        cerr << "Unable to open file '" << filename << "'. Check if file exists and if you have the right permissions." << endl;
        return;
    }

    m_data.clear();
    string line;

    int cols = 0;
    while (getline(input_file, line)) {
        int contains_strings = 0;
        if ( (contains_strings = count(line.begin(), line.end(), C_STRING_DELIMITER)) > 0 ) {
            size_t left = line.find(C_STRING_DELIMITER, 0);
            size_t right = line.find(C_STRING_DELIMITER, left + 1);

            while (left != string::npos && right != string::npos) {
                size_t found = left;
                while (true) {
                    found = line.find(C_STRING_DELIMITER, found);
                    if (found == string::npos) break;

                    line.replace(found, 1, TMP_DELIM_REPLACEMENT);
                    found += 3;
                }

                left = line.find(C_STRING_DELIMITER, right);
                right = line.find(C_STRING_DELIMITER, left + 1);
            }
        }

        stringstream ss(line);
        string tok, i_row;
        vector<string> row;

        while (getline(ss, tok, CSV_DELIMITER)) {
            if (tok.find(TMP_DELIM_REPLACEMENT) != string::npos) {
                i_row = tok;

                size_t found = 0;
                while (true) {
                    found = i_row.find(TMP_DELIM_REPLACEMENT, found);
                    if (found == string::npos) break;

                    i_row.replace(found, 3, string(S_STRING_DELIMITER));
                    found++;
                }
            } else {
                i_row = tok;
            }
            row.push_back(i_row);
        }

        if (cols != 0 && cols != row.size()) m_is_unified = false;

        cols = row.size();

        m_data.push_back(row);
    }

    input_file.close();

    m_is_modified = true;
    m_cols = cols;
    m_rows = m_data.size();
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::write_data(const string &filename)
{
    ofstream output_file(filename.c_str(), ofstream::out);

    if (!output_file.is_open()) {
        cerr << "Unable to open file '" << filename << "'. Check if you have the right permissions." << endl;
        return;
    }

    for (int row = 0; row < m_data.size(); ++row) {
        string new_line;

        vector<string> row_data = m_data.at(row);
        for (int i = 0; i < row_data.size(); i++) {
            new_line.append(row_data.at(i));
            new_line.append(string(1, CSV_DELIMITER));
        }

        size_t last_comma = new_line.find_last_of(",");
        new_line.replace(last_comma, 1, "\n");

        output_file << new_line;
    }

    output_file.close();

    m_is_modified = false;
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::convert_date_format(const std::string &old_format, const std::string &new_format, int column)
{
    for (int row = 0; row < m_data.size(); ++row) convert_date_format(old_format, new_format, row, column);
}

// ----------------------------------------------------------------------------------------------------------|

void CSVData::convert_date_format(const std::string &old_format, const std::string &new_format, int row, int column)
{
    if (column < 0 || column >= m_cols) {
        cerr << "Invalid column number: " << column << endl;
        return;
    }

    if (row < 0 || row >= m_rows) {
        cerr << "Invalid row number: " << row << endl;
        return;
    }

    vector<string> row_data = m_data.at(row);

    string old_date = row_data.at(column);
    std::tm od;
    strptime(old_date.c_str(), old_format.c_str(), &od);

    char buffer[256];
    strftime(buffer, sizeof(buffer), new_format.c_str(), &od);

    string new_date(buffer);

    m_data.at(row).at(column) = new_date;

    m_is_modified = true;
}

// ==========================================================================================================|

static bool is_digits(const string &str)
{
    return std::all_of(str.begin(), str.end(), ::isdigit);
}

// ==========================================================================================================|

void CSVData::sort_by_col(int col, int order)
{
    auto acs_compare_fun = [&](const vector< string > &row1, const vector< string > &row2) {
        bool ret_val;

        if (is_digits(row1[col]) && is_digits(row2[col])) {
            auto a = (row1[col].find(DECIMAL_DELIMITER) != string::npos) ? stod(row1[col]) : stol(row1[col]);
            auto b = (row2[col].find(DECIMAL_DELIMITER) != string::npos) ? stod(row2[col]) : stol(row2[col]);
            ret_val = a < b;
        } else {
             ret_val = row1[col] < row2[col];
        }

        return ret_val;
    };

    auto desc_compare_fun = [&](const vector< string > &row1, const vector< string > &row2) {
        bool ret_val;

        if (is_digits(row1[col]) && is_digits(row2[col])) {
            auto a = (row1[col].find(DECIMAL_DELIMITER) != string::npos) ? stod(row1[col]) : stol(row1[col]);
            auto b = (row2[col].find(DECIMAL_DELIMITER) != string::npos) ? stod(row2[col]) : stol(row2[col]);
            ret_val = a > b;
        } else {
             ret_val = row1[col] > row2[col];
        }

        return ret_val;
    };

    switch (order) {
        case DESC:
            sort(m_data.begin(), m_data.end(), desc_compare_fun);
            break;
        case ASC:
        default:
            sort(m_data.begin(), m_data.end(), acs_compare_fun);
            break;
    }

    m_is_modified = true;
}

// ==========================================================================================================|
<|endoftext|>


<commit_before>//===-- MachineSink.cpp - Sinking for machine instructions ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass moves instructions into successor blocks, when possible, so that
// they aren't executed on paths where their results aren't needed.
//
// This pass is not intended to be a replacement or a complete alternative
// for an LLVM-IR-level sinking pass. It is only designed to sink simple
// constructs that are not exposed before lowering and instruction selection.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "machine-sink"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

STATISTIC(NumSunk, "Number of machine instructions sunk");

namespace {
  class MachineSinking : public MachineFunctionPass {
    const TargetInstrInfo *TII;
    const TargetRegisterInfo *TRI;
    MachineRegisterInfo  *RegInfo; // Machine register information
    MachineDominatorTree *DT;   // Machine dominator tree
    AliasAnalysis *AA;
    BitVector AllocatableSet;   // Which physregs are allocatable?

  public:
    static char ID; // Pass identification
    MachineSinking() : MachineFunctionPass(&ID) {}

    virtual bool runOnMachineFunction(MachineFunction &MF);

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      MachineFunctionPass::getAnalysisUsage(AU);
      AU.addRequired<AliasAnalysis>();
      AU.addRequired<MachineDominatorTree>();
      AU.addPreserved<MachineDominatorTree>();
    }
  private:
    bool ProcessBlock(MachineBasicBlock &MBB);
    bool SinkInstruction(MachineInstr *MI, bool &SawStore);
    bool AllUsesDominatedByBlock(unsigned Reg, MachineBasicBlock *MBB) const;
  };
} // end anonymous namespace

char MachineSinking::ID = 0;
static RegisterPass<MachineSinking>
X("machine-sink", "Machine code sinking");

FunctionPass *llvm::createMachineSinkingPass() { return new MachineSinking(); }

/// AllUsesDominatedByBlock - Return true if all uses of the specified register
/// occur in blocks dominated by the specified block.
bool MachineSinking::AllUsesDominatedByBlock(unsigned Reg,
                                             MachineBasicBlock *MBB) const {
  assert(TargetRegisterInfo::isVirtualRegister(Reg) &&
         "Only makes sense for vregs");
  for (MachineRegisterInfo::use_iterator I = RegInfo->use_begin(Reg),
       E = RegInfo->use_end(); I != E; ++I) {
    // Determine the block of the use.
    MachineInstr *UseInst = &*I;
    MachineBasicBlock *UseBlock = UseInst->getParent();
    if (UseInst->getOpcode() == TargetInstrInfo::PHI) {
      // PHI nodes use the operand in the predecessor block, not the block with
      // the PHI.
      UseBlock = UseInst->getOperand(I.getOperandNo()+1).getMBB();
    }
    // Check that it dominates.
    if (!DT->dominates(MBB, UseBlock))
      return false;
  }
  return true;
}

bool MachineSinking::runOnMachineFunction(MachineFunction &MF) {
  DEBUG(errs() << "******** Machine Sinking ********\n");

  const TargetMachine &TM = MF.getTarget();
  TII = TM.getInstrInfo();
  TRI = TM.getRegisterInfo();
  RegInfo = &MF.getRegInfo();
  DT = &getAnalysis<MachineDominatorTree>();
  AA = &getAnalysis<AliasAnalysis>();
  AllocatableSet = TRI->getAllocatableSet(MF);

  bool EverMadeChange = false;

  while (1) {
    bool MadeChange = false;

    // Process all basic blocks.
    for (MachineFunction::iterator I = MF.begin(), E = MF.end();
         I != E; ++I)
      MadeChange |= ProcessBlock(*I);

    // If this iteration over the code changed anything, keep iterating.
    if (!MadeChange) break;
    EverMadeChange = true;
  }
  return EverMadeChange;
}

bool MachineSinking::ProcessBlock(MachineBasicBlock &MBB) {
  // Can't sink anything out of a block that has less than two successors.
  if (MBB.succ_size() <= 1 || MBB.empty()) return false;

  bool MadeChange = false;

  // Walk the basic block bottom-up.  Remember if we saw a store.
  MachineBasicBlock::iterator I = MBB.end();
  --I;
  bool ProcessedBegin, SawStore = false;
  do {
    MachineInstr *MI = I;  // The instruction to sink.

    // Predecrement I (if it's not begin) so that it isn't invalidated by
    // sinking.
    ProcessedBegin = I == MBB.begin();
    if (!ProcessedBegin)
      --I;

    if (SinkInstruction(MI, SawStore))
      ++NumSunk, MadeChange = true;

    // If we just processed the first instruction in the block, we're done.
  } while (!ProcessedBegin);

  return MadeChange;
}

/// SinkInstruction - Determine whether it is safe to sink the specified machine
/// instruction out of its current block into a successor.
bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore) {
  // Check if it's safe to move the instruction.
  if (!MI->isSafeToMove(TII, SawStore, AA))
    return false;

  // FIXME: This should include support for sinking instructions within the
  // block they are currently in to shorten the live ranges.  We often get
  // instructions sunk into the top of a large block, but it would be better to
  // also sink them down before their first use in the block.  This xform has to
  // be careful not to *increase* register pressure though, e.g. sinking
  // "x = y + z" down if it kills y and z would increase the live ranges of y
  // and z and only shrink the live range of x.

  // Loop over all the operands of the specified instruction.  If there is
  // anything we can't handle, bail out.
  MachineBasicBlock *ParentBlock = MI->getParent();

  // SuccToSinkTo - This is the successor to sink this instruction to, once we
  // decide.
  MachineBasicBlock *SuccToSinkTo = 0;

  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
    const MachineOperand &MO = MI->getOperand(i);
    if (!MO.isReg()) continue;  // Ignore non-register operands.

    unsigned Reg = MO.getReg();
    if (Reg == 0) continue;

    if (TargetRegisterInfo::isPhysicalRegister(Reg)) {
      if (MO.isUse()) {
        // If the physreg has no defs anywhere, it's just an ambient register
        // and we can freely move its uses. Alternatively, if it's allocatable,
        // it could get allocated to something with a def during allocation.
        if (!RegInfo->def_empty(Reg))
          return false;
        if (AllocatableSet.test(Reg))
          return false;
        // Check for a def among the register's aliases too.
        for (const unsigned *Alias = TRI->getAliasSet(Reg); *Alias; ++Alias) {
          unsigned AliasReg = *Alias;
          if (!RegInfo->def_empty(AliasReg))
            return false;
          if (AllocatableSet.test(AliasReg))
            return false;
        }
      } else if (!MO.isDead()) {
        // A def that isn't dead. We can't move it.
        return false;
      }
    } else {
      // Virtual register uses are always safe to sink.
      if (MO.isUse()) continue;

      // If it's not safe to move defs of the register class, then abort.
      if (!TII->isSafeToMoveRegClassDefs(RegInfo->getRegClass(Reg)))
        return false;

      // FIXME: This picks a successor to sink into based on having one
      // successor that dominates all the uses.  However, there are cases where
      // sinking can happen but where the sink point isn't a successor.  For
      // example:
      //   x = computation
      //   if () {} else {}
      //   use x
      // the instruction could be sunk over the whole diamond for the
      // if/then/else (or loop, etc), allowing it to be sunk into other blocks
      // after that.

      // Virtual register defs can only be sunk if all their uses are in blocks
      // dominated by one of the successors.
      if (SuccToSinkTo) {
        // If a previous operand picked a block to sink to, then this operand
        // must be sinkable to the same block.
        if (!AllUsesDominatedByBlock(Reg, SuccToSinkTo))
          return false;
        continue;
      }

      // Otherwise, we should look at all the successors and decide which one
      // we should sink to.
      for (MachineBasicBlock::succ_iterator SI = ParentBlock->succ_begin(),
           E = ParentBlock->succ_end(); SI != E; ++SI) {
        if (AllUsesDominatedByBlock(Reg, *SI)) {
          SuccToSinkTo = *SI;
          break;
        }
      }

      // If we couldn't find a block to sink to, ignore this instruction.
      if (SuccToSinkTo == 0)
        return false;
    }
  }

  // If there are no outputs, it must have side-effects.
  if (SuccToSinkTo == 0)
    return false;

  // It's not safe to sink instructions to EH landing pad. Control flow into
  // landing pad is implicitly defined.
  if (SuccToSinkTo->isLandingPad())
    return false;

  // It is not possible to sink an instruction into its own block.  This can
  // happen with loops.
  if (MI->getParent() == SuccToSinkTo)
    return false;

  DEBUG(errs() << "Sink instr " << *MI);
  DEBUG(errs() << "to block " << *SuccToSinkTo);

  // If the block has multiple predecessors, this would introduce computation on
  // a path that it doesn't already exist.  We could split the critical edge,
  // but for now we just punt.
  // FIXME: Split critical edges if not backedges.
  if (SuccToSinkTo->pred_size() > 1) {
    DEBUG(errs() << " *** PUNTING: Critical edge found\n");
    return false;
  }

  // Determine where to insert into.  Skip phi nodes.
  MachineBasicBlock::iterator InsertPos = SuccToSinkTo->begin();
  while (InsertPos != SuccToSinkTo->end() &&
         InsertPos->getOpcode() == TargetInstrInfo::PHI)
    ++InsertPos;

  // Move the instruction.
  SuccToSinkTo->splice(InsertPos, ParentBlock, MI,
                       ++MachineBasicBlock::iterator(MI));
  return true;
}
<commit_msg>Change errs() to dbgs().<commit_after>//===-- MachineSink.cpp - Sinking for machine instructions ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass moves instructions into successor blocks, when possible, so that
// they aren't executed on paths where their results aren't needed.
//
// This pass is not intended to be a replacement or a complete alternative
// for an LLVM-IR-level sinking pass. It is only designed to sink simple
// constructs that are not exposed before lowering and instruction selection.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "machine-sink"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

STATISTIC(NumSunk, "Number of machine instructions sunk");

namespace {
  class MachineSinking : public MachineFunctionPass {
    const TargetInstrInfo *TII;
    const TargetRegisterInfo *TRI;
    MachineRegisterInfo  *RegInfo; // Machine register information
    MachineDominatorTree *DT;   // Machine dominator tree
    AliasAnalysis *AA;
    BitVector AllocatableSet;   // Which physregs are allocatable?

  public:
    static char ID; // Pass identification
    MachineSinking() : MachineFunctionPass(&ID) {}

    virtual bool runOnMachineFunction(MachineFunction &MF);

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      MachineFunctionPass::getAnalysisUsage(AU);
      AU.addRequired<AliasAnalysis>();
      AU.addRequired<MachineDominatorTree>();
      AU.addPreserved<MachineDominatorTree>();
    }
  private:
    bool ProcessBlock(MachineBasicBlock &MBB);
    bool SinkInstruction(MachineInstr *MI, bool &SawStore);
    bool AllUsesDominatedByBlock(unsigned Reg, MachineBasicBlock *MBB) const;
  };
} // end anonymous namespace

char MachineSinking::ID = 0;
static RegisterPass<MachineSinking>
X("machine-sink", "Machine code sinking");

FunctionPass *llvm::createMachineSinkingPass() { return new MachineSinking(); }

/// AllUsesDominatedByBlock - Return true if all uses of the specified register
/// occur in blocks dominated by the specified block.
bool MachineSinking::AllUsesDominatedByBlock(unsigned Reg,
                                             MachineBasicBlock *MBB) const {
  assert(TargetRegisterInfo::isVirtualRegister(Reg) &&
         "Only makes sense for vregs");
  for (MachineRegisterInfo::use_iterator I = RegInfo->use_begin(Reg),
       E = RegInfo->use_end(); I != E; ++I) {
    // Determine the block of the use.
    MachineInstr *UseInst = &*I;
    MachineBasicBlock *UseBlock = UseInst->getParent();
    if (UseInst->getOpcode() == TargetInstrInfo::PHI) {
      // PHI nodes use the operand in the predecessor block, not the block with
      // the PHI.
      UseBlock = UseInst->getOperand(I.getOperandNo()+1).getMBB();
    }
    // Check that it dominates.
    if (!DT->dominates(MBB, UseBlock))
      return false;
  }
  return true;
}

bool MachineSinking::runOnMachineFunction(MachineFunction &MF) {
  DEBUG(dbgs() << "******** Machine Sinking ********\n");

  const TargetMachine &TM = MF.getTarget();
  TII = TM.getInstrInfo();
  TRI = TM.getRegisterInfo();
  RegInfo = &MF.getRegInfo();
  DT = &getAnalysis<MachineDominatorTree>();
  AA = &getAnalysis<AliasAnalysis>();
  AllocatableSet = TRI->getAllocatableSet(MF);

  bool EverMadeChange = false;

  while (1) {
    bool MadeChange = false;

    // Process all basic blocks.
    for (MachineFunction::iterator I = MF.begin(), E = MF.end();
         I != E; ++I)
      MadeChange |= ProcessBlock(*I);

    // If this iteration over the code changed anything, keep iterating.
    if (!MadeChange) break;
    EverMadeChange = true;
  }
  return EverMadeChange;
}

bool MachineSinking::ProcessBlock(MachineBasicBlock &MBB) {
  // Can't sink anything out of a block that has less than two successors.
  if (MBB.succ_size() <= 1 || MBB.empty()) return false;

  bool MadeChange = false;

  // Walk the basic block bottom-up.  Remember if we saw a store.
  MachineBasicBlock::iterator I = MBB.end();
  --I;
  bool ProcessedBegin, SawStore = false;
  do {
    MachineInstr *MI = I;  // The instruction to sink.

    // Predecrement I (if it's not begin) so that it isn't invalidated by
    // sinking.
    ProcessedBegin = I == MBB.begin();
    if (!ProcessedBegin)
      --I;

    if (SinkInstruction(MI, SawStore))
      ++NumSunk, MadeChange = true;

    // If we just processed the first instruction in the block, we're done.
  } while (!ProcessedBegin);

  return MadeChange;
}

/// SinkInstruction - Determine whether it is safe to sink the specified machine
/// instruction out of its current block into a successor.
bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore) {
  // Check if it's safe to move the instruction.
  if (!MI->isSafeToMove(TII, SawStore, AA))
    return false;

  // FIXME: This should include support for sinking instructions within the
  // block they are currently in to shorten the live ranges.  We often get
  // instructions sunk into the top of a large block, but it would be better to
  // also sink them down before their first use in the block.  This xform has to
  // be careful not to *increase* register pressure though, e.g. sinking
  // "x = y + z" down if it kills y and z would increase the live ranges of y
  // and z and only shrink the live range of x.

  // Loop over all the operands of the specified instruction.  If there is
  // anything we can't handle, bail out.
  MachineBasicBlock *ParentBlock = MI->getParent();

  // SuccToSinkTo - This is the successor to sink this instruction to, once we
  // decide.
  MachineBasicBlock *SuccToSinkTo = 0;

  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
    const MachineOperand &MO = MI->getOperand(i);
    if (!MO.isReg()) continue;  // Ignore non-register operands.

    unsigned Reg = MO.getReg();
    if (Reg == 0) continue;

    if (TargetRegisterInfo::isPhysicalRegister(Reg)) {
      if (MO.isUse()) {
        // If the physreg has no defs anywhere, it's just an ambient register
        // and we can freely move its uses. Alternatively, if it's allocatable,
        // it could get allocated to something with a def during allocation.
        if (!RegInfo->def_empty(Reg))
          return false;
        if (AllocatableSet.test(Reg))
          return false;
        // Check for a def among the register's aliases too.
        for (const unsigned *Alias = TRI->getAliasSet(Reg); *Alias; ++Alias) {
          unsigned AliasReg = *Alias;
          if (!RegInfo->def_empty(AliasReg))
            return false;
          if (AllocatableSet.test(AliasReg))
            return false;
        }
      } else if (!MO.isDead()) {
        // A def that isn't dead. We can't move it.
        return false;
      }
    } else {
      // Virtual register uses are always safe to sink.
      if (MO.isUse()) continue;

      // If it's not safe to move defs of the register class, then abort.
      if (!TII->isSafeToMoveRegClassDefs(RegInfo->getRegClass(Reg)))
        return false;

      // FIXME: This picks a successor to sink into based on having one
      // successor that dominates all the uses.  However, there are cases where
      // sinking can happen but where the sink point isn't a successor.  For
      // example:
      //   x = computation
      //   if () {} else {}
      //   use x
      // the instruction could be sunk over the whole diamond for the
      // if/then/else (or loop, etc), allowing it to be sunk into other blocks
      // after that.

      // Virtual register defs can only be sunk if all their uses are in blocks
      // dominated by one of the successors.
      if (SuccToSinkTo) {
        // If a previous operand picked a block to sink to, then this operand
        // must be sinkable to the same block.
        if (!AllUsesDominatedByBlock(Reg, SuccToSinkTo))
          return false;
        continue;
      }

      // Otherwise, we should look at all the successors and decide which one
      // we should sink to.
      for (MachineBasicBlock::succ_iterator SI = ParentBlock->succ_begin(),
           E = ParentBlock->succ_end(); SI != E; ++SI) {
        if (AllUsesDominatedByBlock(Reg, *SI)) {
          SuccToSinkTo = *SI;
          break;
        }
      }

      // If we couldn't find a block to sink to, ignore this instruction.
      if (SuccToSinkTo == 0)
        return false;
    }
  }

  // If there are no outputs, it must have side-effects.
  if (SuccToSinkTo == 0)
    return false;

  // It's not safe to sink instructions to EH landing pad. Control flow into
  // landing pad is implicitly defined.
  if (SuccToSinkTo->isLandingPad())
    return false;

  // It is not possible to sink an instruction into its own block.  This can
  // happen with loops.
  if (MI->getParent() == SuccToSinkTo)
    return false;

  DEBUG(dbgs() << "Sink instr " << *MI);
  DEBUG(dbgs() << "to block " << *SuccToSinkTo);

  // If the block has multiple predecessors, this would introduce computation on
  // a path that it doesn't already exist.  We could split the critical edge,
  // but for now we just punt.
  // FIXME: Split critical edges if not backedges.
  if (SuccToSinkTo->pred_size() > 1) {
    DEBUG(dbgs() << " *** PUNTING: Critical edge found\n");
    return false;
  }

  // Determine where to insert into.  Skip phi nodes.
  MachineBasicBlock::iterator InsertPos = SuccToSinkTo->begin();
  while (InsertPos != SuccToSinkTo->end() &&
         InsertPos->getOpcode() == TargetInstrInfo::PHI)
    ++InsertPos;

  // Move the instruction.
  SuccToSinkTo->splice(InsertPos, ParentBlock, MI,
                       ++MachineBasicBlock::iterator(MI));
  return true;
}
<|endoftext|>