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

#include "sunversion.hxx"
#include "osl/thread.h"
#include "osl/process.h"
#include "osl/security.hxx"
#include <string.h>
#include <ctype.h>
#include "diagnostics.h"
using namespace osl;

namespace jfw_plugin  { //stoc_javadetect

#if OSL_DEBUG_LEVEL >= 2
class SelfTest
{
public:
    SelfTest();
} test;
#endif

SunVersion::SunVersion(const OUString &usVer):
    m_nUpdateSpecial(0), m_preRelease(Rel_NONE),
    usVersion(usVer)
{
    memset(m_arVersionParts, 0, sizeof(m_arVersionParts));
    OString sVersion= OUStringToOString(usVer, osl_getThreadTextEncoding());
    m_bValid = init(sVersion.getStr());
}
SunVersion::SunVersion(const char * szVer):
    m_nUpdateSpecial(0), m_preRelease(Rel_NONE)
{
    memset(m_arVersionParts, 0, sizeof(m_arVersionParts));
    m_bValid = init(szVer);
    usVersion= OUString(szVer,strlen(szVer),osl_getThreadTextEncoding());
}

/**Format major.minor.maintenance_update
 */
bool SunVersion::init(const char *szVersion)
{
    if ( ! szVersion || strlen(szVersion) == 0)
        return false;

    //first get the major,minor,maintenance
    const char * pLast = szVersion;
    const char * pCur = szVersion;
    //pEnd point to the position after the last character
    const char * pEnd = szVersion + strlen(szVersion);
    // 0 = major, 1 = minor, 2 = maintenance, 3 = update
    int nPart = 0;
    // position within part beginning with 0
    int nPartPos = 0;
    char buf[128];

    //char must me a number 0 - 999 and no leading
    while (true)
    {
        if (pCur < pEnd && isdigit(*pCur))
        {
            if (pCur < pEnd)
                pCur ++;
            nPartPos ++;
        }
        //if  correct separator then form integer
        else if (
            ! (nPartPos == 0) // prevents: ".4.1", "..1", part must start with digit
            && (
                //separators after maintenance (1.4.1_01, 1.4.1-beta, or 1.4.1)
                ((pCur == pEnd || *pCur == '_' || *pCur == '-') && (nPart == 2 ))
                ||
                //separators between major-minor and minor-maintenance
                (nPart < 2 && *pCur == '.') )
            && (
                //prevent 1.4.0. 1.4.0-
                pCur + 1 == pEnd ? isdigit(*(pCur)) : 1) )
        {
            int len = pCur - pLast;
            if (len >= 127)
                return false;

            strncpy(buf, pLast, len);
            buf[len] = 0;
            pCur ++;
            pLast = pCur;

            m_arVersionParts[nPart] = atoi(buf);
            nPart ++;
            nPartPos = 0;
            if (nPart == 3)
                break;

            //check next character
            if (! ( (pCur < pEnd)
                    && ( (nPart < 3) && isdigit(*pCur))))
                return false;
        }
        else
        {
            return false;
        }
    }
    if (pCur >= pEnd)
        return true;
    //We have now 1.4.1. This can be followed by _01, -beta, etc.
    // _01 (update) According to docu must not be followed by any other
    //characters, but on Solaris 9 we have a 1.4.1_01a!!
    if (* (pCur - 1) == '_')
    {// _01, _02
        // update is the last part _01, _01a, part 0 is the digits parts and 1 the trailing alpha
        while (true)
        {
            if (pCur <= pEnd)
            {
                if ( ! isdigit(*pCur))
                {
                    //1.4.1_01-, 1.4.1_01a, the numerical part may only be 2 chars.
                    int len = pCur - pLast;
                    if (len > 2)
                        return false;
                    //we've got the update: 01, 02 etc
                    strncpy(buf, pLast, len);
                    buf[len] = 0;
                    m_arVersionParts[nPart] = atoi(buf);
                    if (pCur == pEnd)
                    {
                        break;
                    }
                    if (*pCur == 'a' && (pCur + 1) == pEnd)
                    {
                        //check if it s followed by a simple "a" (not specified)
                        m_nUpdateSpecial = *pCur;
                        break;
                    }
                    else if (*pCur == '-' && pCur < pEnd)
                    {
                        //check 1.5.0_01-ea
                        PreRelease pr = getPreRelease(++pCur);
                        if (pr == Rel_NONE)
                            return false;
                        //just ignore -ea because its no official release
                        break;
                    }
                    else
                    {
                        return false;
                    }
                }
                if (pCur < pEnd)
                    pCur ++;
                else
                    break;
            }
        }
    }
    // 1.4.1-ea
    else if (*(pCur - 1) == '-')
    {
        m_preRelease = getPreRelease(pCur);
        if (m_preRelease == Rel_NONE)
            return false;
#if defined(FREEBSD)
      if (m_preRelease == Rel_FreeBSD)
      {
          pCur++; //eliminate 'p'
          if (pCur < pEnd && isdigit(*pCur))
              pCur ++;
          int len = pCur - pLast -1; //eliminate 'p'
          if (len >= 127)
              return false;
          strncpy(buf, (pLast+1), len); //eliminate 'p'
          buf[len] = 0;
          m_nUpdateSpecial = atoi(buf)+100; //hack for FBSD #i56953#
          return true;
      }
#endif
    }
    else
    {
        return false;
    }
    return true;
}

SunVersion::PreRelease SunVersion::getPreRelease(const char *szRelease)
{
    if (szRelease == NULL)
        return Rel_NONE;
    if( ! strcmp(szRelease,"internal"))
        return  Rel_INTERNAL;
    else if( ! strcmp(szRelease,"ea"))
        return  Rel_EA;
    else if( ! strcmp(szRelease,"ea1"))
        return Rel_EA1;
    else if( ! strcmp(szRelease,"ea2"))
        return Rel_EA2;
    else if( ! strcmp(szRelease,"ea3"))
        return Rel_EA3;
    else if ( ! strcmp(szRelease,"beta"))
        return Rel_BETA;
    else if ( ! strcmp(szRelease,"beta1"))
        return Rel_BETA1;
    else if ( ! strcmp(szRelease,"beta2"))
        return Rel_BETA2;
    else if ( ! strcmp(szRelease,"beta3"))
        return Rel_BETA3;
    else if (! strcmp(szRelease, "rc"))
        return Rel_RC;
    else if (! strcmp(szRelease, "rc1"))
        return Rel_RC1;
    else if (! strcmp(szRelease, "rc2"))
        return Rel_RC2;
    else if (! strcmp(szRelease, "rc3"))
        return Rel_RC3;
#if defined (FREEBSD)
    else if (! strncmp(szRelease, "p", 1))
        return Rel_FreeBSD;
#endif
    else
        return Rel_NONE;
}

SunVersion::~SunVersion()
{

}

/* Examples:
   a) 1.0 < 1.1
   b) 1.0 < 1.0.0
   c)  1.0 < 1.0_00

   returns false if both values are equal
*/
bool SunVersion::operator > (const SunVersion& ver) const
{
    if( &ver == this)
        return false;

    //compare major.minor.maintenance
    for( int i= 0; i < 4; i ++)
    {
        // 1.4 > 1.3
        if(m_arVersionParts[i] > ver.m_arVersionParts[i])
        {
            return true;
        }
        else if (m_arVersionParts[i] < ver.m_arVersionParts[i])
        {
            return false;
        }
    }
    //major.minor.maintenance_update are equal. Test for a trailing char
    if (m_nUpdateSpecial > ver.m_nUpdateSpecial)
    {
        return true;
    }

    //Until here the versions are equal
    //compare pre -release values
    if ((m_preRelease == Rel_NONE && ver.m_preRelease == Rel_NONE)
        ||
        (m_preRelease != Rel_NONE && ver.m_preRelease == Rel_NONE))
        return false;
    else if (m_preRelease == Rel_NONE && ver.m_preRelease != Rel_NONE)
        return true;
    else if (m_preRelease > ver.m_preRelease)
        return true;

    return false;
}

bool SunVersion::operator < (const SunVersion& ver) const
{
    return (! operator > (ver)) && (! operator == (ver));
}

bool SunVersion::operator == (const SunVersion& ver) const
{
    bool bRet= true;
    for(int i= 0; i < 4; i++)
    {
        if( m_arVersionParts[i] != ver.m_arVersionParts[i])
        {
            bRet= false;
            break;
        }
    }
    bRet = m_nUpdateSpecial == ver.m_nUpdateSpecial && bRet;
    bRet = m_preRelease == ver.m_preRelease && bRet;
    return bRet;
}

#if OSL_DEBUG_LEVEL >= 2
SelfTest::SelfTest()
{
    bool bRet = true;

    char const * versions[] = {"1.4.0", "1.4.1", "1.0.0", "10.0.0", "10.10.0",
                         "10.2.2", "10.10.0", "10.10.10", "111.0.999",
                         "1.4.1_01", "9.90.99_09", "1.4.1_99",
                         "1.4.1_00a",
                         "1.4.1-ea", "1.4.1-beta", "1.4.1-rc1",
                         "1.5.0_01-ea", "1.5.0_01-rc2"};
    char const * badVersions[] = {".4.0", "..1", "", "10.0", "10.10.0.", "10.10.0-", "10.10.0.",
                            "10.2-2", "10_10.0", "10..10","10.10", "a.0.999",
                            "1.4b.1_01", "9.90.-99_09", "1.4.1_99-",
                            "1.4.1_00a2", "1.4.0_z01z", "1.4.1__99A",
                            "1.4.1-1ea", "1.5.0_010", "1.5.0._01-", "1.5.0_01-eac"};
    char const * orderedVer[] = { "1.3.1-ea", "1.3.1-beta", "1.3.1-rc1",
                            "1.3.1", "1.3.1_00a", "1.3.1_01", "1.3.1_01a",
                            "1.3.2", "1.4.0", "1.5.0_01-ea", "2.0.0"};

    int num = sizeof (versions) / sizeof(char*);
    int numBad = sizeof (badVersions) / sizeof(char*);
    int numOrdered = sizeof (orderedVer) / sizeof(char*);
    //parsing test (positive)
    for (int i = 0; i < num; i++)
    {
        SunVersion ver(versions[i]);
        if ( ! ver)
        {
            bRet = false;
            break;
        }
    }
    OSL_ENSURE(bRet, "SunVersion selftest failed");
    //Parsing test (negative)
    for ( int i = 0; i < numBad; i++)
    {
        SunVersion ver(badVersions[i]);
        if (ver)
        {
            bRet = false;
            break;
        }
    }
    OSL_ENSURE(bRet, "SunVersion selftest failed");

    // Ordering test
    bRet = true;
    int j = 0;
    for (int i = 0; i < numOrdered; i ++)
    {
        SunVersion curVer(orderedVer[i]);
        if ( ! curVer)
        {
            bRet = false;
            break;
        }
        for (j = 0; j < numOrdered; j++)
        {
            SunVersion compVer(orderedVer[j]);
            if (i < j)
            {
                if ( !(curVer < compVer))
                {
                    bRet = false;
                    break;
                }
            }
            else if ( i == j)
            {
                if (! (curVer == compVer
                       && ! (curVer > compVer)
                       && ! (curVer < compVer)))
                {
                    bRet = false;
                    break;
                }
            }
            else if (i > j)
            {
                if ( !(curVer > compVer))
                {
                    bRet = false;
                    break;
                }
            }
        }
        if ( ! bRet)
            break;
    }
    if (bRet)
        JFW_TRACE2("Testing class SunVersion succeeded.");
    else
        OSL_ENSURE(bRet, "[Java framework] sunjavaplugin: SunVersion self test failed.\n");
}
#endif

}

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

#include "sunversion.hxx"
#include "osl/diagnose.h"
#include "osl/thread.h"
#include "osl/process.h"
#include "osl/security.hxx"
#include <string.h>
#include <ctype.h>
#include "diagnostics.h"
using namespace osl;

namespace jfw_plugin  { //stoc_javadetect

#if OSL_DEBUG_LEVEL >= 2
class SelfTest
{
public:
    SelfTest();
} test;
#endif

SunVersion::SunVersion(const OUString &usVer):
    m_nUpdateSpecial(0), m_preRelease(Rel_NONE),
    usVersion(usVer)
{
    memset(m_arVersionParts, 0, sizeof(m_arVersionParts));
    OString sVersion= OUStringToOString(usVer, osl_getThreadTextEncoding());
    m_bValid = init(sVersion.getStr());
}
SunVersion::SunVersion(const char * szVer):
    m_nUpdateSpecial(0), m_preRelease(Rel_NONE)
{
    memset(m_arVersionParts, 0, sizeof(m_arVersionParts));
    m_bValid = init(szVer);
    usVersion= OUString(szVer,strlen(szVer),osl_getThreadTextEncoding());
}

/**Format major.minor.maintenance_update
 */
bool SunVersion::init(const char *szVersion)
{
    if ( ! szVersion || strlen(szVersion) == 0)
        return false;

    //first get the major,minor,maintenance
    const char * pLast = szVersion;
    const char * pCur = szVersion;
    //pEnd point to the position after the last character
    const char * pEnd = szVersion + strlen(szVersion);
    // 0 = major, 1 = minor, 2 = maintenance, 3 = update
    int nPart = 0;
    // position within part beginning with 0
    int nPartPos = 0;
    char buf[128];

    //char must me a number 0 - 999 and no leading
    while (true)
    {
        if (pCur < pEnd && isdigit(*pCur))
        {
            if (pCur < pEnd)
                pCur ++;
            nPartPos ++;
        }
        //if  correct separator then form integer
        else if (
            ! (nPartPos == 0) // prevents: ".4.1", "..1", part must start with digit
            && (
                //separators after maintenance (1.4.1_01, 1.4.1-beta, or 1.4.1)
                ((pCur == pEnd || *pCur == '_' || *pCur == '-') && (nPart == 2 ))
                ||
                //separators between major-minor and minor-maintenance
                (nPart < 2 && *pCur == '.') )
            && (
                //prevent 1.4.0. 1.4.0-
                pCur + 1 == pEnd ? isdigit(*(pCur)) : 1) )
        {
            int len = pCur - pLast;
            if (len >= 127)
                return false;

            strncpy(buf, pLast, len);
            buf[len] = 0;
            pCur ++;
            pLast = pCur;

            m_arVersionParts[nPart] = atoi(buf);
            nPart ++;
            nPartPos = 0;
            if (nPart == 3)
                break;

            //check next character
            if (! ( (pCur < pEnd)
                    && ( (nPart < 3) && isdigit(*pCur))))
                return false;
        }
        else
        {
            return false;
        }
    }
    if (pCur >= pEnd)
        return true;
    //We have now 1.4.1. This can be followed by _01, -beta, etc.
    // _01 (update) According to docu must not be followed by any other
    //characters, but on Solaris 9 we have a 1.4.1_01a!!
    if (* (pCur - 1) == '_')
    {// _01, _02
        // update is the last part _01, _01a, part 0 is the digits parts and 1 the trailing alpha
        while (true)
        {
            if (pCur <= pEnd)
            {
                if ( ! isdigit(*pCur))
                {
                    //1.4.1_01-, 1.4.1_01a, the numerical part may only be 2 chars.
                    int len = pCur - pLast;
                    if (len > 2)
                        return false;
                    //we've got the update: 01, 02 etc
                    strncpy(buf, pLast, len);
                    buf[len] = 0;
                    m_arVersionParts[nPart] = atoi(buf);
                    if (pCur == pEnd)
                    {
                        break;
                    }
                    if (*pCur == 'a' && (pCur + 1) == pEnd)
                    {
                        //check if it s followed by a simple "a" (not specified)
                        m_nUpdateSpecial = *pCur;
                        break;
                    }
                    else if (*pCur == '-' && pCur < pEnd)
                    {
                        //check 1.5.0_01-ea
                        PreRelease pr = getPreRelease(++pCur);
                        if (pr == Rel_NONE)
                            return false;
                        //just ignore -ea because its no official release
                        break;
                    }
                    else
                    {
                        return false;
                    }
                }
                if (pCur < pEnd)
                    pCur ++;
                else
                    break;
            }
        }
    }
    // 1.4.1-ea
    else if (*(pCur - 1) == '-')
    {
        m_preRelease = getPreRelease(pCur);
        if (m_preRelease == Rel_NONE)
            return false;
#if defined(FREEBSD)
      if (m_preRelease == Rel_FreeBSD)
      {
          pCur++; //eliminate 'p'
          if (pCur < pEnd && isdigit(*pCur))
              pCur ++;
          int len = pCur - pLast -1; //eliminate 'p'
          if (len >= 127)
              return false;
          strncpy(buf, (pLast+1), len); //eliminate 'p'
          buf[len] = 0;
          m_nUpdateSpecial = atoi(buf)+100; //hack for FBSD #i56953#
          return true;
      }
#endif
    }
    else
    {
        return false;
    }
    return true;
}

SunVersion::PreRelease SunVersion::getPreRelease(const char *szRelease)
{
    if (szRelease == NULL)
        return Rel_NONE;
    if( ! strcmp(szRelease,"internal"))
        return  Rel_INTERNAL;
    else if( ! strcmp(szRelease,"ea"))
        return  Rel_EA;
    else if( ! strcmp(szRelease,"ea1"))
        return Rel_EA1;
    else if( ! strcmp(szRelease,"ea2"))
        return Rel_EA2;
    else if( ! strcmp(szRelease,"ea3"))
        return Rel_EA3;
    else if ( ! strcmp(szRelease,"beta"))
        return Rel_BETA;
    else if ( ! strcmp(szRelease,"beta1"))
        return Rel_BETA1;
    else if ( ! strcmp(szRelease,"beta2"))
        return Rel_BETA2;
    else if ( ! strcmp(szRelease,"beta3"))
        return Rel_BETA3;
    else if (! strcmp(szRelease, "rc"))
        return Rel_RC;
    else if (! strcmp(szRelease, "rc1"))
        return Rel_RC1;
    else if (! strcmp(szRelease, "rc2"))
        return Rel_RC2;
    else if (! strcmp(szRelease, "rc3"))
        return Rel_RC3;
#if defined (FREEBSD)
    else if (! strncmp(szRelease, "p", 1))
        return Rel_FreeBSD;
#endif
    else
        return Rel_NONE;
}

SunVersion::~SunVersion()
{

}

/* Examples:
   a) 1.0 < 1.1
   b) 1.0 < 1.0.0
   c)  1.0 < 1.0_00

   returns false if both values are equal
*/
bool SunVersion::operator > (const SunVersion& ver) const
{
    if( &ver == this)
        return false;

    //compare major.minor.maintenance
    for( int i= 0; i < 4; i ++)
    {
        // 1.4 > 1.3
        if(m_arVersionParts[i] > ver.m_arVersionParts[i])
        {
            return true;
        }
        else if (m_arVersionParts[i] < ver.m_arVersionParts[i])
        {
            return false;
        }
    }
    //major.minor.maintenance_update are equal. Test for a trailing char
    if (m_nUpdateSpecial > ver.m_nUpdateSpecial)
    {
        return true;
    }

    //Until here the versions are equal
    //compare pre -release values
    if ((m_preRelease == Rel_NONE && ver.m_preRelease == Rel_NONE)
        ||
        (m_preRelease != Rel_NONE && ver.m_preRelease == Rel_NONE))
        return false;
    else if (m_preRelease == Rel_NONE && ver.m_preRelease != Rel_NONE)
        return true;
    else if (m_preRelease > ver.m_preRelease)
        return true;

    return false;
}

bool SunVersion::operator < (const SunVersion& ver) const
{
    return (! operator > (ver)) && (! operator == (ver));
}

bool SunVersion::operator == (const SunVersion& ver) const
{
    bool bRet= true;
    for(int i= 0; i < 4; i++)
    {
        if( m_arVersionParts[i] != ver.m_arVersionParts[i])
        {
            bRet= false;
            break;
        }
    }
    bRet = m_nUpdateSpecial == ver.m_nUpdateSpecial && bRet;
    bRet = m_preRelease == ver.m_preRelease && bRet;
    return bRet;
}

#if OSL_DEBUG_LEVEL >= 2
SelfTest::SelfTest()
{
    bool bRet = true;

    char const * versions[] = {"1.4.0", "1.4.1", "1.0.0", "10.0.0", "10.10.0",
                         "10.2.2", "10.10.0", "10.10.10", "111.0.999",
                         "1.4.1_01", "9.90.99_09", "1.4.1_99",
                         "1.4.1_00a",
                         "1.4.1-ea", "1.4.1-beta", "1.4.1-rc1",
                         "1.5.0_01-ea", "1.5.0_01-rc2"};
    char const * badVersions[] = {".4.0", "..1", "", "10.0", "10.10.0.", "10.10.0-", "10.10.0.",
                            "10.2-2", "10_10.0", "10..10","10.10", "a.0.999",
                            "1.4b.1_01", "9.90.-99_09", "1.4.1_99-",
                            "1.4.1_00a2", "1.4.0_z01z", "1.4.1__99A",
                            "1.4.1-1ea", "1.5.0_010", "1.5.0._01-", "1.5.0_01-eac"};
    char const * orderedVer[] = { "1.3.1-ea", "1.3.1-beta", "1.3.1-rc1",
                            "1.3.1", "1.3.1_00a", "1.3.1_01", "1.3.1_01a",
                            "1.3.2", "1.4.0", "1.5.0_01-ea", "2.0.0"};

    int num = sizeof (versions) / sizeof(char*);
    int numBad = sizeof (badVersions) / sizeof(char*);
    int numOrdered = sizeof (orderedVer) / sizeof(char*);
    //parsing test (positive)
    for (int i = 0; i < num; i++)
    {
        SunVersion ver(versions[i]);
        if ( ! ver)
        {
            bRet = false;
            break;
        }
    }
    OSL_ENSURE(bRet, "SunVersion selftest failed");
    //Parsing test (negative)
    for ( int i = 0; i < numBad; i++)
    {
        SunVersion ver(badVersions[i]);
        if (ver)
        {
            bRet = false;
            break;
        }
    }
    OSL_ENSURE(bRet, "SunVersion selftest failed");

    // Ordering test
    bRet = true;
    int j = 0;
    for (int i = 0; i < numOrdered; i ++)
    {
        SunVersion curVer(orderedVer[i]);
        if ( ! curVer)
        {
            bRet = false;
            break;
        }
        for (j = 0; j < numOrdered; j++)
        {
            SunVersion compVer(orderedVer[j]);
            if (i < j)
            {
                if ( !(curVer < compVer))
                {
                    bRet = false;
                    break;
                }
            }
            else if ( i == j)
            {
                if (! (curVer == compVer
                       && ! (curVer > compVer)
                       && ! (curVer < compVer)))
                {
                    bRet = false;
                    break;
                }
            }
            else if (i > j)
            {
                if ( !(curVer > compVer))
                {
                    bRet = false;
                    break;
                }
            }
        }
        if ( ! bRet)
            break;
    }
    if (bRet)
        JFW_TRACE2("Testing class SunVersion succeeded.");
    else
        OSL_ENSURE(bRet, "[Java framework] sunjavaplugin: SunVersion self test failed.\n");
}
#endif

}

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


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

#include <cstdio>
#include <iostream>
#include <memory>
#include <vector>

#include "absl/strings/string_view.h"
#include "absl/strings/str_cat.h"
#include "zetasql/parser/parse_tree_visitor.h"
#include "zetasql/parser/parser.h"
#include "zetasql/public/parse_helpers.h"

namespace zetasql {

namespace linter {

absl::Status printASTTree(absl::string_view sql) {
    absl::Status return_status;
    std::unique_ptr<zetasql::ParserOutput> output;

    return_status = zetasql::ParseStatement(sql,
        zetasql::ParserOptions(), &output);

    std::cout << "Status for sql \" " << sql << "\" = "
        << return_status.ToString() << std::endl;

    if ( return_status.ok() ) {
        std::cout << output -> statement() -> DebugString() << std::endl;
    }

    return return_status;
}

absl::Status checkStatement(absl::string_view sql) {
    std::unique_ptr<zetasql::ParserOutput> output;
    return zetasql::ParseStatement(sql,
        zetasql::ParserOptions(), &output);
}

absl::Status checkLineLength(absl::string_view sql, int lineLimit,
    const char delimeter) {
    int lineSize = 0;
    int lineNumber = 1;
    for (int i=0; i<static_cast<int>(sql.size()); i++) {
        if ( sql[i] == delimeter ) {
            lineSize = 0;
            lineNumber++;
        } else {
            lineSize++;
        }
        if ( lineSize > lineLimit ) {
            return absl::Status(
                absl::StatusCode::kFailedPrecondition,
                absl::StrCat("Lines should be <= ", std::to_string(lineLimit),
                " characters long [", std::to_string(lineNumber), ",1]") );
        }
    }
    return absl::OkStatus();
}

void KeywordExtractor::extract() {
    // TODO(orhan_uysal): Implement a keyword extractor
    // that pushes all keyword nodes to vector "keywords"
}

bool allUpperCase(const zetasql::ASTNode* x) {
    // TODO(orhan_uysal): Implement a function checking
    // if all characters in ASTNode(keyword node) is uppercase
    return true;
}

absl::Status checkUppercaseKeywords(absl::string_view sql) {
    std::vector<const zetasql::ASTNode *> *keywords;
    *keywords = std::vector<const zetasql::ASTNode *>();

    std::unique_ptr<zetasql::ParserOutput> output;

    absl::Status parser_status = zetasql::ParseStatement(sql,
            zetasql::ParserOptions(), &output);

    if ( !parser_status.ok() )
        return parser_status;

    // KeywordExtractor(output->statement(), keywords).extract();

    for (const zetasql::ASTNode *keyword : *keywords) {
        if ( !allUpperCase(keyword) ) {
            return absl::Status(
                absl::StatusCode::kFailedPrecondition, "");
        }
    }

    return absl::OkStatus();
}

}  // namespace linter
}  // namespace zetasql
<commit_msg>Update keywords to be a vector instear of a pointer to vector. This will fix build error: keyword is uninitialized when used here...<commit_after>//
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "src/linter.h"

#include <cstdio>
#include <iostream>
#include <memory>
#include <vector>

#include "absl/strings/string_view.h"
#include "absl/strings/str_cat.h"
#include "zetasql/parser/parse_tree_visitor.h"
#include "zetasql/parser/parser.h"
#include "zetasql/public/parse_helpers.h"

namespace zetasql {

namespace linter {

absl::Status printASTTree(absl::string_view sql) {
    absl::Status return_status;
    std::unique_ptr<zetasql::ParserOutput> output;

    return_status = zetasql::ParseStatement(sql,
        zetasql::ParserOptions(), &output);

    std::cout << "Status for sql \" " << sql << "\" = "
        << return_status.ToString() << std::endl;

    if ( return_status.ok() ) {
        std::cout << output -> statement() -> DebugString() << std::endl;
    }

    return return_status;
}

absl::Status checkStatement(absl::string_view sql) {
    std::unique_ptr<zetasql::ParserOutput> output;
    return zetasql::ParseStatement(sql,
        zetasql::ParserOptions(), &output);
}

absl::Status checkLineLength(absl::string_view sql, int lineLimit,
    const char delimeter) {
    int lineSize = 0;
    int lineNumber = 1;
    for (int i=0; i<static_cast<int>(sql.size()); i++) {
        if ( sql[i] == delimeter ) {
            lineSize = 0;
            lineNumber++;
        } else {
            lineSize++;
        }
        if ( lineSize > lineLimit ) {
            return absl::Status(
                absl::StatusCode::kFailedPrecondition,
                absl::StrCat("Lines should be <= ", std::to_string(lineLimit),
                " characters long [", std::to_string(lineNumber), ",1]") );
        }
    }
    return absl::OkStatus();
}

void KeywordExtractor::extract() {
    // TODO(orhan_uysal): Implement a keyword extractor
    // that pushes all keyword nodes to vector "keywords"
}

bool allUpperCase(const zetasql::ASTNode* x) {
    // TODO(orhan_uysal): Implement a function checking
    // if all characters in ASTNode(keyword node) is uppercase
    return true;
}

absl::Status checkUppercaseKeywords(absl::string_view sql) {
    std::vector<const zetasql::ASTNode *> keywords{};

    std::unique_ptr<zetasql::ParserOutput> output;

    absl::Status parser_status = zetasql::ParseStatement(sql,
            zetasql::ParserOptions(), &output);

    if ( !parser_status.ok() )
        return parser_status;
    // TODO(orhan_uysal): Implement KeywordExtractor.

    for (const zetasql::ASTNode *keyword : keywords) {
        if ( !allUpperCase(keyword) ) {
            return absl::Status(
                absl::StatusCode::kFailedPrecondition, "");
        }
    }

    return absl::OkStatus();
}

}  // namespace linter
}  // namespace zetasql
<|endoftext|>


<commit_before>//
// Copyright (C) Zbigniew Zagorski <z.zagorski@gmail.com>,
// licensed to the public under the terms of the GNU GPL (>= 2)
// see the file COPYING for details
// I.e., do what you like, but keep copyright and there's NO WARRANTY.
//

#include "tinfra/symbol.h"

#include <unittest++/UnitTest++.h>

#include "tinfra/mo.h"

namespace tinfra_mo_test {
    TINFRA_SYMBOL_IMPL(x);
    TINFRA_SYMBOL_IMPL(y);
    TINFRA_SYMBOL_IMPL(top_left);
    TINFRA_SYMBOL_IMPL(bottom_right);
    struct point {
        int x;
        int y;
        TINFRA_MO_MANIFEST(point) {
            TINFRA_MO_FIELD(x);
            TINFRA_MO_FIELD(y);
        }
    };

    struct rect {
        point top_left;
        point bottom_right;

        TINFRA_MO_MANIFEST(rect) {
            TINFRA_MO_FIELD(top_left);
            TINFRA_MO_FIELD(bottom_right);
        }
    };

    class point_bean {
        int x;
        int y;

    public:
        int getX() const { return x; }
        int getY() const { return y; }

        void setX(int v) { x = v; }
        void setY(int v) { y = v; }

        template <typename F>
        void apply(F& f) const
        {
            f(S::x, &point_bean::getX, &point_bean::setX);
            f(S::y, &point_bean::getY, &point_bean::setY);
        }
    };
}

namespace tinfra {
    template<>
    struct mo_traits<tinfra_mo_test::point>: public tinfra::struct_mo_traits<tinfra_mo_test::point> {};

    template<>
    struct mo_traits<tinfra_mo_test::rect>: public tinfra::struct_mo_traits<tinfra_mo_test::rect> {};

    template <typename MO, typename F>
    struct mo_bean_processor_adapter {
        MO const& mo;
        F&  f;
        template <typename T, typename X>
        void operator()(tinfra::symbol const& sym, T (MO::*getter)() const, X)
        {
            f(sym, (mo.*getter)());
        }
    };

    template <typename MO, typename F>
    struct mo_bean_mutator_adapter {
        MO& mo;
        F&  f;
        template <typename T>
        void operator()(tinfra::symbol const& sym, T (MO::*getter)() const, void (MO::*setter)(T const& v))
        {
            T orig = (mo.*getter)();
            T victim(orig);
            f(sym, victim);
            if( !(victim == orig) ) {
                mo.*setter(victim);
            }
        }

        template <typename T>
        void operator()(tinfra::symbol const& sym, T (MO::*getter)() const, void (MO::*setter)(T v))
        {
            T orig = (mo.*getter)();
            T victim(orig);
            f(sym, victim);
            if( !(victim == orig) ) {
                (mo.*setter)(victim);
            }
        }
    };

    template <typename F>
    void mo_process(tinfra_mo_test::point_bean const& v, F& f)
    {
        mo_bean_processor_adapter<tinfra_mo_test::point_bean,F> adapter = {v, f};
        v.apply(adapter);
    }

    template <typename F>
    void mo_mutate(tinfra_mo_test::point_bean& v, F& f)
    {
        mo_bean_mutator_adapter<tinfra_mo_test::point_bean,F> adapter = { v, f };
        v.apply(adapter);
    }
}

SUITE(tinfra)
{
    using tinfra_mo_test::point;
    using tinfra_mo_test::rect;
    using tinfra_mo_test::point_bean;
    using tinfra::symbol;

    struct dummy_functor {
        int sum;
        int count;
        void operator()(symbol const&, int const& v) {
            sum+=v;
            count++;
        }
        template <typename T>
        void mstruct(symbol const&, T const& v) {
            tinfra::mo_process(v, *this);
        }
    };

    TEST(mo_process_api)
    {
        dummy_functor f = {0,0};
        const point a = { 3,-2};
        tinfra::mo_process(a, f);
        CHECK_EQUAL(1, f.sum);
        CHECK_EQUAL(2, f.count);
    }

    TEST(mo_process_complex)
    {
        dummy_functor f = {0};
        const rect r = { { 3,-2} , {4, -3} };
        tinfra::mo_process(r, f);
        CHECK_EQUAL(2, f.sum);
        CHECK_EQUAL(4, f.count);
    }

    TEST(mo_process_bean_api)
    {
        dummy_functor f = {0};
        point_bean a;
        a.setX(1);
        a.setY(2);
        tinfra::mo_process(a, f);
        CHECK_EQUAL(3, f.sum);
    }

    struct foo_modifier {
        int count;
        void operator()(symbol const&, int& v ) {
            v = 1;
            count++;
        }

        template <typename T>
        void mstruct(symbol const&, T& v) {
            tinfra::mo_mutate(v, *this);
        }
    };

    TEST(mo_mutate_api)
    {
        foo_modifier f = {0};
        point a = { 0, 0 };
        tinfra::mo_mutate(a, f);

        CHECK_EQUAL(1, a.x);
        CHECK_EQUAL(1, a.y);
        CHECK_EQUAL(2, f.count);
    }

    TEST(mo_mutate_complex)
    {
        foo_modifier f = {0};
        rect r = { {0, 0}, {2,2} };
        tinfra::mo_mutate(r, f);

        CHECK_EQUAL(1, r.top_left.x);
        CHECK_EQUAL(1, r.top_left.y);
        CHECK_EQUAL(1, r.bottom_right.x);
        CHECK_EQUAL(1, r.bottom_right.y);
        CHECK_EQUAL(4, f.count);
    }

    TEST(mo_mutate_bean_api)
    {
        foo_modifier f;
        point_bean a;
        a.setX(0);
        a.setY(2);

        tinfra::mo_mutate(a, f);

        CHECK_EQUAL(1, a.getX());
        CHECK_EQUAL(1, a.getY());
    }
}

// jedit: :tabSize=8:indentSize=4:noTabs=true:mode=c++:
<commit_msg>test_mo: added proof of concept for SFINAE based matching of MO objects in functor (works on gcc 3.4.5)<commit_after>//
// Copyright (C) Zbigniew Zagorski <z.zagorski@gmail.com>,
// licensed to the public under the terms of the GNU GPL (>= 2)
// see the file COPYING for details
// I.e., do what you like, but keep copyright and there's NO WARRANTY.
//

#include "tinfra/symbol.h"

#include <unittest++/UnitTest++.h>

#include "tinfra/mo.h"

struct true_type { enum { value = 1 } ; };

struct false_type { enum { value = 1 } ; };

namespace tinfra_mo_test {
    TINFRA_SYMBOL_IMPL(x);
    TINFRA_SYMBOL_IMPL(y);
    TINFRA_SYMBOL_IMPL(z);
    TINFRA_SYMBOL_IMPL(top_left);
    TINFRA_SYMBOL_IMPL(bottom_right);

    struct point {
        int x;
        int y;
        TINFRA_MO_MANIFEST(point) {
            TINFRA_MO_FIELD(x);
            TINFRA_MO_FIELD(y);
        }
    };

    struct point3d {
        typedef true_type tinfra_is_mo;
        int x;
        int y;
        int z;
        TINFRA_MO_MANIFEST(point) {
            TINFRA_MO_FIELD(x);
            TINFRA_MO_FIELD(y);
            TINFRA_MO_FIELD(z);
        }
    };

    struct rect {
        point top_left;
        point bottom_right;

        TINFRA_MO_MANIFEST(rect) {
            TINFRA_MO_FIELD(top_left);
            TINFRA_MO_FIELD(bottom_right);
        }
    };

    class point_bean {
        int x;
        int y;

    public:
        int getX() const { return x; }
        int getY() const { return y; }

        void setX(int v) { x = v; }
        void setY(int v) { y = v; }

        template <typename F>
        void apply(F& f) const
        {
            f(S::x, &point_bean::getX, &point_bean::setX);
            f(S::y, &point_bean::getY, &point_bean::setY);
        }
    };
}

namespace tinfra {
    template<>
    struct mo_traits<tinfra_mo_test::point>: public tinfra::struct_mo_traits<tinfra_mo_test::point> {};

    template<>
    struct mo_traits<tinfra_mo_test::rect>: public tinfra::struct_mo_traits<tinfra_mo_test::rect> {};

    template <typename MO, typename F>
    struct mo_bean_processor_adapter {
        MO const& mo;
        F&  f;
        template <typename T, typename X>
        void operator()(tinfra::symbol const& sym, T (MO::*getter)() const, X)
        {
            f(sym, (mo.*getter)());
        }
    };

    template <typename MO, typename F>
    struct mo_bean_mutator_adapter {
        MO& mo;
        F&  f;
        template <typename T>
        void operator()(tinfra::symbol const& sym, T (MO::*getter)() const, void (MO::*setter)(T const& v))
        {
            T orig = (mo.*getter)();
            T victim(orig);
            f(sym, victim);
            if( !(victim == orig) ) {
                mo.*setter(victim);
            }
        }

        template <typename T>
        void operator()(tinfra::symbol const& sym, T (MO::*getter)() const, void (MO::*setter)(T v))
        {
            T orig = (mo.*getter)();
            T victim(orig);
            f(sym, victim);
            if( !(victim == orig) ) {
                (mo.*setter)(victim);
            }
        }
    };

    template <typename F>
    void mo_process(tinfra_mo_test::point_bean const& v, F& f)
    {
        mo_bean_processor_adapter<tinfra_mo_test::point_bean,F> adapter = {v, f};
        v.apply(adapter);
    }

    template <typename F>
    void mo_mutate(tinfra_mo_test::point_bean& v, F& f)
    {
        mo_bean_mutator_adapter<tinfra_mo_test::point_bean,F> adapter = { v, f };
        v.apply(adapter);
    }
}

SUITE(tinfra)
{
    using tinfra_mo_test::point;
    using tinfra_mo_test::rect;
    using tinfra_mo_test::point_bean;
    using tinfra::symbol;

    struct dummy_functor {
        int sum;
        int count;
        void operator()(symbol const&, int const& v) {
            sum+=v;
            count++;
        }
        template <typename T>
        void mstruct(symbol const&, T const& v) {
            tinfra::mo_process(v, *this);
        }
    };

    TEST(mo_process_api)
    {
        dummy_functor f = {0,0};
        const point a = { 3,-2};
        tinfra::mo_process(a, f);
        CHECK_EQUAL(1, f.sum);
        CHECK_EQUAL(2, f.count);
    }

    TEST(mo_process_complex)
    {
        dummy_functor f = {0};
        const rect r = { { 3,-2} , {4, -3} };
        tinfra::mo_process(r, f);
        CHECK_EQUAL(2, f.sum);
        CHECK_EQUAL(4, f.count);
    }

    TEST(mo_process_bean_api)
    {
        dummy_functor f = {0};
        point_bean a;
        a.setX(1);
        a.setY(2);
        tinfra::mo_process(a, f);
        CHECK_EQUAL(3, f.sum);
    }

    struct foo_modifier {
        int count;
        void operator()(symbol const&, int& v ) {
            v = 1;
            count++;
        }

        template <typename T>
        void mstruct(symbol const&, T& v) {
            tinfra::mo_mutate(v, *this);
        }
    };

    TEST(mo_mutate_api)
    {
        foo_modifier f = {0};
        point a = { 0, 0 };
        tinfra::mo_mutate(a, f);

        CHECK_EQUAL(1, a.x);
        CHECK_EQUAL(1, a.y);
        CHECK_EQUAL(2, f.count);
    }

    TEST(mo_mutate_complex)
    {
        foo_modifier f = {0};
        rect r = { {0, 0}, {2,2} };
        tinfra::mo_mutate(r, f);

        CHECK_EQUAL(1, r.top_left.x);
        CHECK_EQUAL(1, r.top_left.y);
        CHECK_EQUAL(1, r.bottom_right.x);
        CHECK_EQUAL(1, r.bottom_right.y);
        CHECK_EQUAL(4, f.count);
    }

    TEST(mo_mutate_bean_api)
    {
        foo_modifier f;
        point_bean a;
        a.setX(0);
        a.setY(2);

        tinfra::mo_mutate(a, f);

        CHECK_EQUAL(1, a.getX());
        CHECK_EQUAL(1, a.getY());
    }

    struct sfinae_functor {
        int sum;
        void operator()(symbol const&, int const& v ) {
            sum += v;
        }

        bool sfinae_matched;
        template <typename T>
        void operator()(symbol const&, T const& v, typename T::tinfra_is_mo = true_type()) {
            sfinae_matched = true;
            tinfra::mo_process(v, *this);
        }
    };

    TEST(mo_sfinae_processor)
    {
        sfinae_functor functor = {0, false};
        const tinfra_mo_test::point3d foo = { 1,2,3 };

        tinfra::process(tinfra::symbol("a"), foo, functor);

        CHECK( functor.sfinae_matched);

        CHECK_EQUAL(6, functor.sum);
    }

    struct sfinae_mutator {
        void operator()(symbol const&, int& v ) {
            v = 0;
        }

        bool sfinae_matched;
        template <typename T>
        void operator()(symbol const&, T& v, typename T::tinfra_is_mo = true_type()) {
            sfinae_matched = true;
            //v.foo =2; uncomment to see how unreadable error is
            tinfra::mo_mutate(v, *this);
        }
    };

    TEST(mo_sfinae_mutator)
    {
        sfinae_mutator functor = {false};
        tinfra_mo_test::point3d foo = { 1,2,3 };

        tinfra::mutate(tinfra::symbol("a"), foo, functor);

        CHECK( functor.sfinae_matched);

        CHECK_EQUAL(0, foo.x);
        CHECK_EQUAL(0, foo.y);
        CHECK_EQUAL(0, foo.z);
    }
}

// jedit: :tabSize=8:indentSize=4:noTabs=true:mode=c++:
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "io.h"
#include "debug.h"
#include "miniposix.h"
#include <algorithm>
#include <errno.h>

#if !_WIN32
#include <sys/uio.h>
#endif

namespace kj {

InputStream::~InputStream() noexcept(false) {}
OutputStream::~OutputStream() noexcept(false) {}
BufferedInputStream::~BufferedInputStream() noexcept(false) {}
BufferedOutputStream::~BufferedOutputStream() noexcept(false) {}

size_t InputStream::read(void* buffer, size_t minBytes, size_t maxBytes) {
  size_t n = tryRead(buffer, minBytes, maxBytes);
  KJ_REQUIRE(n >= minBytes, "Premature EOF") {
    // Pretend we read zeros from the input.
    memset(reinterpret_cast<byte*>(buffer) + n, 0, minBytes - n);
    return minBytes;
  }
  return n;
}

void InputStream::skip(size_t bytes) {
  char scratch[8192];
  while (bytes > 0) {
    size_t amount = std::min(bytes, sizeof(scratch));
    read(scratch, amount);
    bytes -= amount;
  }
}

void OutputStream::write(ArrayPtr<const ArrayPtr<const byte>> pieces) {
  for (auto piece: pieces) {
    write(piece.begin(), piece.size());
  }
}

ArrayPtr<const byte> BufferedInputStream::getReadBuffer() {
  auto result = tryGetReadBuffer();
  KJ_REQUIRE(result.size() > 0, "Premature EOF");
  return result;
}

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

BufferedInputStreamWrapper::BufferedInputStreamWrapper(InputStream& inner, ArrayPtr<byte> buffer)
    : inner(inner), ownedBuffer(buffer == nullptr ? heapArray<byte>(8192) : nullptr),
      buffer(buffer == nullptr ? ownedBuffer : buffer) {}

BufferedInputStreamWrapper::~BufferedInputStreamWrapper() noexcept(false) {}

ArrayPtr<const byte> BufferedInputStreamWrapper::tryGetReadBuffer() {
  if (bufferAvailable.size() == 0) {
    size_t n = inner.tryRead(buffer.begin(), 1, buffer.size());
    bufferAvailable = buffer.slice(0, n);
  }

  return bufferAvailable;
}

size_t BufferedInputStreamWrapper::tryRead(void* dst, size_t minBytes, size_t maxBytes) {
  if (minBytes <= bufferAvailable.size()) {
    // Serve from current buffer.
    size_t n = std::min(bufferAvailable.size(), maxBytes);
    memcpy(dst, bufferAvailable.begin(), n);
    bufferAvailable = bufferAvailable.slice(n, bufferAvailable.size());
    return n;
  } else {
    // Copy current available into destination.
    memcpy(dst, bufferAvailable.begin(), bufferAvailable.size());
    size_t fromFirstBuffer = bufferAvailable.size();

    dst = reinterpret_cast<byte*>(dst) + fromFirstBuffer;
    minBytes -= fromFirstBuffer;
    maxBytes -= fromFirstBuffer;

    if (maxBytes <= buffer.size()) {
      // Read the next buffer-full.
      size_t n = inner.read(buffer.begin(), minBytes, buffer.size());
      size_t fromSecondBuffer = std::min(n, maxBytes);
      memcpy(dst, buffer.begin(), fromSecondBuffer);
      bufferAvailable = buffer.slice(fromSecondBuffer, n);
      return fromFirstBuffer + fromSecondBuffer;
    } else {
      // Forward large read to the underlying stream.
      bufferAvailable = nullptr;
      return fromFirstBuffer + inner.read(dst, minBytes, maxBytes);
    }
  }
}

void BufferedInputStreamWrapper::skip(size_t bytes) {
  if (bytes <= bufferAvailable.size()) {
    bufferAvailable = bufferAvailable.slice(bytes, bufferAvailable.size());
  } else {
    bytes -= bufferAvailable.size();
    if (bytes <= buffer.size()) {
      // Read the next buffer-full.
      size_t n = inner.read(buffer.begin(), bytes, buffer.size());
      bufferAvailable = buffer.slice(bytes, n);
    } else {
      // Forward large skip to the underlying stream.
      bufferAvailable = nullptr;
      inner.skip(bytes);
    }
  }
}

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

BufferedOutputStreamWrapper::BufferedOutputStreamWrapper(OutputStream& inner, ArrayPtr<byte> buffer)
    : inner(inner),
      ownedBuffer(buffer == nullptr ? heapArray<byte>(8192) : nullptr),
      buffer(buffer == nullptr ? ownedBuffer : buffer),
      bufferPos(this->buffer.begin()) {}

BufferedOutputStreamWrapper::~BufferedOutputStreamWrapper() noexcept(false) {
  unwindDetector.catchExceptionsIfUnwinding([&]() {
    flush();
  });
}

void BufferedOutputStreamWrapper::flush() {
  if (bufferPos > buffer.begin()) {
    inner.write(buffer.begin(), bufferPos - buffer.begin());
    bufferPos = buffer.begin();
  }
}

ArrayPtr<byte> BufferedOutputStreamWrapper::getWriteBuffer() {
  return arrayPtr(bufferPos, buffer.end());
}

void BufferedOutputStreamWrapper::write(const void* src, size_t size) {
  if (src == bufferPos) {
    // Oh goody, the caller wrote directly into our buffer.
    bufferPos += size;
  } else {
    size_t available = buffer.end() - bufferPos;

    if (size <= available) {
      memcpy(bufferPos, src, size);
      bufferPos += size;
    } else if (size <= buffer.size()) {
      // Too much for this buffer, but not a full buffer's worth, so we'll go ahead and copy.
      memcpy(bufferPos, src, available);
      inner.write(buffer.begin(), buffer.size());

      size -= available;
      src = reinterpret_cast<const byte*>(src) + available;

      memcpy(buffer.begin(), src, size);
      bufferPos = buffer.begin() + size;
    } else {
      // Writing so much data that we might as well write directly to avoid a copy.
      inner.write(buffer.begin(), bufferPos - buffer.begin());
      bufferPos = buffer.begin();
      inner.write(src, size);
    }
  }
}

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

ArrayInputStream::ArrayInputStream(ArrayPtr<const byte> array): array(array) {}
ArrayInputStream::~ArrayInputStream() noexcept(false) {}

ArrayPtr<const byte> ArrayInputStream::tryGetReadBuffer() {
  return array;
}

size_t ArrayInputStream::tryRead(void* dst, size_t minBytes, size_t maxBytes) {
  size_t n = std::min(maxBytes, array.size());
  memcpy(dst, array.begin(), n);
  array = array.slice(n, array.size());
  return n;
}

void ArrayInputStream::skip(size_t bytes) {
  KJ_REQUIRE(array.size() >= bytes, "ArrayInputStream ended prematurely.") {
    bytes = array.size();
    break;
  }
  array = array.slice(bytes, array.size());
}

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

ArrayOutputStream::ArrayOutputStream(ArrayPtr<byte> array): array(array), fillPos(array.begin()) {}
ArrayOutputStream::~ArrayOutputStream() noexcept(false) {}

ArrayPtr<byte> ArrayOutputStream::getWriteBuffer() {
  return arrayPtr(fillPos, array.end());
}

void ArrayOutputStream::write(const void* src, size_t size) {
  if (src == fillPos) {
    // Oh goody, the caller wrote directly into our buffer.
    KJ_REQUIRE(size <= array.end() - fillPos);
    fillPos += size;
  } else {
    KJ_REQUIRE(size <= (size_t)(array.end() - fillPos),
            "ArrayOutputStream's backing array was not large enough for the data written.");
    memcpy(fillPos, src, size);
    fillPos += size;
  }
}

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

VectorOutputStream::VectorOutputStream(size_t initialCapacity)
    : vector(heapArray<byte>(initialCapacity)), fillPos(vector.begin()) {}
VectorOutputStream::~VectorOutputStream() noexcept(false) {}

ArrayPtr<byte> VectorOutputStream::getWriteBuffer() {
  // Grow if needed.
  if (fillPos == vector.end()) {
    grow(vector.size() + 1);
  }

  return arrayPtr(fillPos, vector.end());
}

void VectorOutputStream::write(const void* src, size_t size) {
  if (src == fillPos) {
    // Oh goody, the caller wrote directly into our buffer.
    KJ_REQUIRE(size <= vector.end() - fillPos);
    fillPos += size;
  } else {
    if (vector.end() - fillPos < size) {
      grow(fillPos - vector.begin() + size);
    }

    memcpy(fillPos, src, size);
    fillPos += size;
  }
}

void VectorOutputStream::grow(size_t minSize) {
  size_t newSize = vector.size() * 2;
  while (newSize < minSize) newSize *= 2;
  auto newVector = heapArray<byte>(newSize);
  memcpy(newVector.begin(), vector.begin(), fillPos - vector.begin());
  fillPos = fillPos - vector.begin() + newVector.begin();
  vector = kj::mv(newVector);
}

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

AutoCloseFd::~AutoCloseFd() noexcept(false) {
  if (fd >= 0) {
    unwindDetector.catchExceptionsIfUnwinding([&]() {
      // Don't use SYSCALL() here because close() should not be repeated on EINTR.
      if (miniposix::close(fd) < 0) {
        KJ_FAIL_SYSCALL("close", errno, fd) {
          break;
        }
      }
    });
  }
}

FdInputStream::~FdInputStream() noexcept(false) {}

size_t FdInputStream::tryRead(void* buffer, size_t minBytes, size_t maxBytes) {
  byte* pos = reinterpret_cast<byte*>(buffer);
  byte* min = pos + minBytes;
  byte* max = pos + maxBytes;

  while (pos < min) {
    miniposix::ssize_t n;
    KJ_SYSCALL(n = miniposix::read(fd, pos, max - pos), fd);
    if (n == 0) {
      break;
    }
    pos += n;
  }

  return pos - reinterpret_cast<byte*>(buffer);
}

FdOutputStream::~FdOutputStream() noexcept(false) {}

void FdOutputStream::write(const void* buffer, size_t size) {
  const char* pos = reinterpret_cast<const char*>(buffer);

  while (size > 0) {
    miniposix::ssize_t n;
    KJ_SYSCALL(n = miniposix::write(fd, pos, size), fd);
    KJ_ASSERT(n > 0, "write() returned zero.");
    pos += n;
    size -= n;
  }
}

void FdOutputStream::write(ArrayPtr<const ArrayPtr<const byte>> pieces) {
#if _WIN32
  // Windows has no reasonable writev(). It has WriteFileGather, but this call has the unreasonable
  // restriction that each segment must be page-aligned. So, fall back to write().

  for (auto piece: pieces) {
    write(piece.begin(), piece.size());
  }

#else
  const size_t iovmax = miniposix::iovMax(pieces.size());
  while (pieces.size() > iovmax) {
    write(pieces.slice(0, iovmax));
    pieces = pieces.slice(iovmax, pieces.size());
  }

  KJ_STACK_ARRAY(struct iovec, iov, pieces.size(), 16, 128);

  for (uint i = 0; i < pieces.size(); i++) {
    // writev() interface is not const-correct.  :(
    iov[i].iov_base = const_cast<byte*>(pieces[i].begin());
    iov[i].iov_len = pieces[i].size();
  }

  struct iovec* current = iov.begin();

  // Advance past any leading empty buffers so that a write full of only empty buffers does not
  // cause a syscall at all.
  while (current < iov.end() && current->iov_len == 0) {
    ++current;
  }

  while (current < iov.end()) {
    // Issue the write.
    ssize_t n = 0;
    KJ_SYSCALL(n = ::writev(fd, current, iov.end() - current), fd);
    KJ_ASSERT(n > 0, "writev() returned zero.");

    // Advance past all buffers that were fully-written.
    while (current < iov.end() && static_cast<size_t>(n) >= current->iov_len) {
      n -= current->iov_len;
      ++current;
    }

    // If we only partially-wrote one of the buffers, adjust the pointer and size to include only
    // the unwritten part.
    if (n > 0) {
      current->iov_base = reinterpret_cast<byte*>(current->iov_base) + n;
      current->iov_len -= n;
    }
  }
#endif
}

}  // namespace kj
<commit_msg>kj/io: Make FdOutputStream::write fallback to OutputStream::write.<commit_after>// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "io.h"
#include "debug.h"
#include "miniposix.h"
#include <algorithm>
#include <errno.h>

#if !_WIN32
#include <sys/uio.h>
#endif

namespace kj {

InputStream::~InputStream() noexcept(false) {}
OutputStream::~OutputStream() noexcept(false) {}
BufferedInputStream::~BufferedInputStream() noexcept(false) {}
BufferedOutputStream::~BufferedOutputStream() noexcept(false) {}

size_t InputStream::read(void* buffer, size_t minBytes, size_t maxBytes) {
  size_t n = tryRead(buffer, minBytes, maxBytes);
  KJ_REQUIRE(n >= minBytes, "Premature EOF") {
    // Pretend we read zeros from the input.
    memset(reinterpret_cast<byte*>(buffer) + n, 0, minBytes - n);
    return minBytes;
  }
  return n;
}

void InputStream::skip(size_t bytes) {
  char scratch[8192];
  while (bytes > 0) {
    size_t amount = std::min(bytes, sizeof(scratch));
    read(scratch, amount);
    bytes -= amount;
  }
}

void OutputStream::write(ArrayPtr<const ArrayPtr<const byte>> pieces) {
  for (auto piece: pieces) {
    write(piece.begin(), piece.size());
  }
}

ArrayPtr<const byte> BufferedInputStream::getReadBuffer() {
  auto result = tryGetReadBuffer();
  KJ_REQUIRE(result.size() > 0, "Premature EOF");
  return result;
}

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

BufferedInputStreamWrapper::BufferedInputStreamWrapper(InputStream& inner, ArrayPtr<byte> buffer)
    : inner(inner), ownedBuffer(buffer == nullptr ? heapArray<byte>(8192) : nullptr),
      buffer(buffer == nullptr ? ownedBuffer : buffer) {}

BufferedInputStreamWrapper::~BufferedInputStreamWrapper() noexcept(false) {}

ArrayPtr<const byte> BufferedInputStreamWrapper::tryGetReadBuffer() {
  if (bufferAvailable.size() == 0) {
    size_t n = inner.tryRead(buffer.begin(), 1, buffer.size());
    bufferAvailable = buffer.slice(0, n);
  }

  return bufferAvailable;
}

size_t BufferedInputStreamWrapper::tryRead(void* dst, size_t minBytes, size_t maxBytes) {
  if (minBytes <= bufferAvailable.size()) {
    // Serve from current buffer.
    size_t n = std::min(bufferAvailable.size(), maxBytes);
    memcpy(dst, bufferAvailable.begin(), n);
    bufferAvailable = bufferAvailable.slice(n, bufferAvailable.size());
    return n;
  } else {
    // Copy current available into destination.
    memcpy(dst, bufferAvailable.begin(), bufferAvailable.size());
    size_t fromFirstBuffer = bufferAvailable.size();

    dst = reinterpret_cast<byte*>(dst) + fromFirstBuffer;
    minBytes -= fromFirstBuffer;
    maxBytes -= fromFirstBuffer;

    if (maxBytes <= buffer.size()) {
      // Read the next buffer-full.
      size_t n = inner.read(buffer.begin(), minBytes, buffer.size());
      size_t fromSecondBuffer = std::min(n, maxBytes);
      memcpy(dst, buffer.begin(), fromSecondBuffer);
      bufferAvailable = buffer.slice(fromSecondBuffer, n);
      return fromFirstBuffer + fromSecondBuffer;
    } else {
      // Forward large read to the underlying stream.
      bufferAvailable = nullptr;
      return fromFirstBuffer + inner.read(dst, minBytes, maxBytes);
    }
  }
}

void BufferedInputStreamWrapper::skip(size_t bytes) {
  if (bytes <= bufferAvailable.size()) {
    bufferAvailable = bufferAvailable.slice(bytes, bufferAvailable.size());
  } else {
    bytes -= bufferAvailable.size();
    if (bytes <= buffer.size()) {
      // Read the next buffer-full.
      size_t n = inner.read(buffer.begin(), bytes, buffer.size());
      bufferAvailable = buffer.slice(bytes, n);
    } else {
      // Forward large skip to the underlying stream.
      bufferAvailable = nullptr;
      inner.skip(bytes);
    }
  }
}

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

BufferedOutputStreamWrapper::BufferedOutputStreamWrapper(OutputStream& inner, ArrayPtr<byte> buffer)
    : inner(inner),
      ownedBuffer(buffer == nullptr ? heapArray<byte>(8192) : nullptr),
      buffer(buffer == nullptr ? ownedBuffer : buffer),
      bufferPos(this->buffer.begin()) {}

BufferedOutputStreamWrapper::~BufferedOutputStreamWrapper() noexcept(false) {
  unwindDetector.catchExceptionsIfUnwinding([&]() {
    flush();
  });
}

void BufferedOutputStreamWrapper::flush() {
  if (bufferPos > buffer.begin()) {
    inner.write(buffer.begin(), bufferPos - buffer.begin());
    bufferPos = buffer.begin();
  }
}

ArrayPtr<byte> BufferedOutputStreamWrapper::getWriteBuffer() {
  return arrayPtr(bufferPos, buffer.end());
}

void BufferedOutputStreamWrapper::write(const void* src, size_t size) {
  if (src == bufferPos) {
    // Oh goody, the caller wrote directly into our buffer.
    bufferPos += size;
  } else {
    size_t available = buffer.end() - bufferPos;

    if (size <= available) {
      memcpy(bufferPos, src, size);
      bufferPos += size;
    } else if (size <= buffer.size()) {
      // Too much for this buffer, but not a full buffer's worth, so we'll go ahead and copy.
      memcpy(bufferPos, src, available);
      inner.write(buffer.begin(), buffer.size());

      size -= available;
      src = reinterpret_cast<const byte*>(src) + available;

      memcpy(buffer.begin(), src, size);
      bufferPos = buffer.begin() + size;
    } else {
      // Writing so much data that we might as well write directly to avoid a copy.
      inner.write(buffer.begin(), bufferPos - buffer.begin());
      bufferPos = buffer.begin();
      inner.write(src, size);
    }
  }
}

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

ArrayInputStream::ArrayInputStream(ArrayPtr<const byte> array): array(array) {}
ArrayInputStream::~ArrayInputStream() noexcept(false) {}

ArrayPtr<const byte> ArrayInputStream::tryGetReadBuffer() {
  return array;
}

size_t ArrayInputStream::tryRead(void* dst, size_t minBytes, size_t maxBytes) {
  size_t n = std::min(maxBytes, array.size());
  memcpy(dst, array.begin(), n);
  array = array.slice(n, array.size());
  return n;
}

void ArrayInputStream::skip(size_t bytes) {
  KJ_REQUIRE(array.size() >= bytes, "ArrayInputStream ended prematurely.") {
    bytes = array.size();
    break;
  }
  array = array.slice(bytes, array.size());
}

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

ArrayOutputStream::ArrayOutputStream(ArrayPtr<byte> array): array(array), fillPos(array.begin()) {}
ArrayOutputStream::~ArrayOutputStream() noexcept(false) {}

ArrayPtr<byte> ArrayOutputStream::getWriteBuffer() {
  return arrayPtr(fillPos, array.end());
}

void ArrayOutputStream::write(const void* src, size_t size) {
  if (src == fillPos) {
    // Oh goody, the caller wrote directly into our buffer.
    KJ_REQUIRE(size <= array.end() - fillPos);
    fillPos += size;
  } else {
    KJ_REQUIRE(size <= (size_t)(array.end() - fillPos),
            "ArrayOutputStream's backing array was not large enough for the data written.");
    memcpy(fillPos, src, size);
    fillPos += size;
  }
}

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

VectorOutputStream::VectorOutputStream(size_t initialCapacity)
    : vector(heapArray<byte>(initialCapacity)), fillPos(vector.begin()) {}
VectorOutputStream::~VectorOutputStream() noexcept(false) {}

ArrayPtr<byte> VectorOutputStream::getWriteBuffer() {
  // Grow if needed.
  if (fillPos == vector.end()) {
    grow(vector.size() + 1);
  }

  return arrayPtr(fillPos, vector.end());
}

void VectorOutputStream::write(const void* src, size_t size) {
  if (src == fillPos) {
    // Oh goody, the caller wrote directly into our buffer.
    KJ_REQUIRE(size <= vector.end() - fillPos);
    fillPos += size;
  } else {
    if (vector.end() - fillPos < size) {
      grow(fillPos - vector.begin() + size);
    }

    memcpy(fillPos, src, size);
    fillPos += size;
  }
}

void VectorOutputStream::grow(size_t minSize) {
  size_t newSize = vector.size() * 2;
  while (newSize < minSize) newSize *= 2;
  auto newVector = heapArray<byte>(newSize);
  memcpy(newVector.begin(), vector.begin(), fillPos - vector.begin());
  fillPos = fillPos - vector.begin() + newVector.begin();
  vector = kj::mv(newVector);
}

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

AutoCloseFd::~AutoCloseFd() noexcept(false) {
  if (fd >= 0) {
    unwindDetector.catchExceptionsIfUnwinding([&]() {
      // Don't use SYSCALL() here because close() should not be repeated on EINTR.
      if (miniposix::close(fd) < 0) {
        KJ_FAIL_SYSCALL("close", errno, fd) {
          break;
        }
      }
    });
  }
}

FdInputStream::~FdInputStream() noexcept(false) {}

size_t FdInputStream::tryRead(void* buffer, size_t minBytes, size_t maxBytes) {
  byte* pos = reinterpret_cast<byte*>(buffer);
  byte* min = pos + minBytes;
  byte* max = pos + maxBytes;

  while (pos < min) {
    miniposix::ssize_t n;
    KJ_SYSCALL(n = miniposix::read(fd, pos, max - pos), fd);
    if (n == 0) {
      break;
    }
    pos += n;
  }

  return pos - reinterpret_cast<byte*>(buffer);
}

FdOutputStream::~FdOutputStream() noexcept(false) {}

void FdOutputStream::write(const void* buffer, size_t size) {
  const char* pos = reinterpret_cast<const char*>(buffer);

  while (size > 0) {
    miniposix::ssize_t n;
    KJ_SYSCALL(n = miniposix::write(fd, pos, size), fd);
    KJ_ASSERT(n > 0, "write() returned zero.");
    pos += n;
    size -= n;
  }
}

void FdOutputStream::write(ArrayPtr<const ArrayPtr<const byte>> pieces) {
#if _WIN32
  // Windows has no reasonable writev(). It has WriteFileGather, but this call has the unreasonable
  // restriction that each segment must be page-aligned. So, fall back to the default implementation

  OutputStream::write(pieces);

#else
  const size_t iovmax = miniposix::iovMax(pieces.size());
  while (pieces.size() > iovmax) {
    write(pieces.slice(0, iovmax));
    pieces = pieces.slice(iovmax, pieces.size());
  }

  KJ_STACK_ARRAY(struct iovec, iov, pieces.size(), 16, 128);

  for (uint i = 0; i < pieces.size(); i++) {
    // writev() interface is not const-correct.  :(
    iov[i].iov_base = const_cast<byte*>(pieces[i].begin());
    iov[i].iov_len = pieces[i].size();
  }

  struct iovec* current = iov.begin();

  // Advance past any leading empty buffers so that a write full of only empty buffers does not
  // cause a syscall at all.
  while (current < iov.end() && current->iov_len == 0) {
    ++current;
  }

  while (current < iov.end()) {
    // Issue the write.
    ssize_t n = 0;
    KJ_SYSCALL(n = ::writev(fd, current, iov.end() - current), fd);
    KJ_ASSERT(n > 0, "writev() returned zero.");

    // Advance past all buffers that were fully-written.
    while (current < iov.end() && static_cast<size_t>(n) >= current->iov_len) {
      n -= current->iov_len;
      ++current;
    }

    // If we only partially-wrote one of the buffers, adjust the pointer and size to include only
    // the unwritten part.
    if (n > 0) {
      current->iov_base = reinterpret_cast<byte*>(current->iov_base) + n;
      current->iov_len -= n;
    }
  }
#endif
}

}  // namespace kj
<|endoftext|>


<commit_before>//===-- SelectionDAGPrinter.cpp - Implement SelectionDAG::viewGraph() -----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This implements the SelectionDAG::viewGraph method.
//
//===----------------------------------------------------------------------===//

#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/ScheduleDAGSDNodes.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/PseudoSourceValue.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Config/config.h"
#include <fstream>
using namespace llvm;

namespace llvm {
  template<>
  struct DOTGraphTraits<SelectionDAG*> : public DefaultDOTGraphTraits {
    static bool hasEdgeDestLabels() {
      return true;
    }

    static unsigned numEdgeDestLabels(const void *Node) {
      return ((const SDNode *) Node)->getNumValues();
    }

    static std::string getEdgeDestLabel(const void *Node, unsigned i) {
      return ((const SDNode *) Node)->getValueType(i).getMVTString();
    }

    /// edgeTargetsEdgeSource - This method returns true if this outgoing edge
    /// should actually target another edge source, not a node.  If this method is
    /// implemented, getEdgeTarget should be implemented.
    template<typename EdgeIter>
    static bool edgeTargetsEdgeSource(const void *Node, EdgeIter I) {
      return true;
    }

    /// getEdgeTarget - If edgeTargetsEdgeSource returns true, this method is
    /// called to determine which outgoing edge of Node is the target of this
    /// edge.
    template<typename EdgeIter>
    static EdgeIter getEdgeTarget(const void *Node, EdgeIter I) {
      SDNode *TargetNode = *I;
      SDNodeIterator NI = SDNodeIterator::begin(TargetNode);
      std::advance(NI, I.getNode()->getOperand(I.getOperand()).getResNo());
      return NI;
    }

    static std::string getGraphName(const SelectionDAG *G) {
      return G->getMachineFunction().getFunction()->getName();
    }

    static bool renderGraphFromBottomUp() {
      return true;
    }

    static bool hasNodeAddressLabel(const SDNode *Node,
                                    const SelectionDAG *Graph) {
      return true;
    }

    /// If you want to override the dot attributes printed for a particular
    /// edge, override this method.
    template<typename EdgeIter>
    static std::string getEdgeAttributes(const void *Node, EdgeIter EI) {
      SDValue Op = EI.getNode()->getOperand(EI.getOperand());
      MVT VT = Op.getValueType();
      if (VT == MVT::Flag)
        return "color=red,style=bold";
      else if (VT == MVT::Other)
        return "color=blue,style=dashed";
      return "";
    }

    static std::string getNodeLabel(const SDNode *Node,
                                    const SelectionDAG *Graph);
    static std::string getNodeAttributes(const SDNode *N,
                                         const SelectionDAG *Graph) {
#ifndef NDEBUG
      const std::string &Attrs = Graph->getGraphAttrs(N);
      if (!Attrs.empty()) {
        if (Attrs.find("shape=") == std::string::npos)
          return std::string("shape=Mrecord,") + Attrs;
        else
          return Attrs;
      }
#endif
      return "shape=Mrecord";
    }

    static void addCustomGraphFeatures(SelectionDAG *G,
                                       GraphWriter<SelectionDAG*> &GW) {
      GW.emitSimpleNode(0, "plaintext=circle", "GraphRoot");
      if (G->getRoot().getNode())
        GW.emitEdge(0, -1, G->getRoot().getNode(), G->getRoot().getResNo(),
                    "color=blue,style=dashed");
    }
  };
}

std::string DOTGraphTraits<SelectionDAG*>::getNodeLabel(const SDNode *Node,
                                                        const SelectionDAG *G) {
  std::string Op = Node->getOperationName(G);

  if (const ConstantSDNode *CSDN = dyn_cast<ConstantSDNode>(Node)) {
    Op += ": " + utostr(CSDN->getZExtValue());
  } else if (const ConstantFPSDNode *CSDN = dyn_cast<ConstantFPSDNode>(Node)) {
    Op += ": " + ftostr(CSDN->getValueAPF());
  } else if (const GlobalAddressSDNode *GADN =
             dyn_cast<GlobalAddressSDNode>(Node)) {
    Op += ": " + GADN->getGlobal()->getName();
    if (int64_t Offset = GADN->getOffset()) {
      if (Offset > 0)
        Op += "+" + itostr(Offset);
      else
        Op += itostr(Offset);
    }
  } else if (const FrameIndexSDNode *FIDN = dyn_cast<FrameIndexSDNode>(Node)) {
    Op += " " + itostr(FIDN->getIndex());
  } else if (const JumpTableSDNode *JTDN = dyn_cast<JumpTableSDNode>(Node)) {
    Op += " " + itostr(JTDN->getIndex());
  } else if (const ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(Node)){
    if (CP->isMachineConstantPoolEntry()) {
      Op += '<';
      {
        raw_string_ostream OSS(Op);
        OSS << *CP->getMachineCPVal();
      }
      Op += '>';
    } else {
      if (ConstantFP *CFP = dyn_cast<ConstantFP>(CP->getConstVal()))
        Op += "<" + ftostr(CFP->getValueAPF()) + ">";
      else if (ConstantInt *CI = dyn_cast<ConstantInt>(CP->getConstVal()))
        Op += "<" + utostr(CI->getZExtValue()) + ">";
      else {
        Op += '<';
        {
          raw_string_ostream OSS(Op);
          WriteAsOperand(OSS, CP->getConstVal(), false);
        }
        Op += '>';
      }
    }
    Op += " A=" + itostr(1 << CP->getAlignment());
  } else if (const BasicBlockSDNode *BBDN = dyn_cast<BasicBlockSDNode>(Node)) {
    Op = "BB: ";
    const Value *LBB = (const Value*)BBDN->getBasicBlock()->getBasicBlock();
    if (LBB)
      Op += LBB->getName();
    //Op += " " + (const void*)BBDN->getBasicBlock();
  } else if (const RegisterSDNode *R = dyn_cast<RegisterSDNode>(Node)) {
    if (G && R->getReg() != 0 &&
        TargetRegisterInfo::isPhysicalRegister(R->getReg())) {
      Op = Op + " " +
        G->getTarget().getRegisterInfo()->getName(R->getReg());
    } else {
      Op += " #" + utostr(R->getReg());
    }
  } else if (const DbgStopPointSDNode *D = dyn_cast<DbgStopPointSDNode>(Node)) {
    Op += ": " + D->getCompileUnit()->getFileName();
    Op += ":" + utostr(D->getLine());
    if (D->getColumn() != 0)
      Op += ":" + utostr(D->getColumn());
  } else if (const LabelSDNode *L = dyn_cast<LabelSDNode>(Node)) {
    Op += ": LabelID=" + utostr(L->getLabelID());
  } else if (const CallSDNode *C = dyn_cast<CallSDNode>(Node)) {
    Op += ": CallingConv=" + utostr(C->getCallingConv());
    if (C->isVarArg())
      Op += ", isVarArg";
    if (C->isTailCall())
      Op += ", isTailCall";
  } else if (const ExternalSymbolSDNode *ES =
             dyn_cast<ExternalSymbolSDNode>(Node)) {
    Op += "'" + std::string(ES->getSymbol()) + "'";
  } else if (const SrcValueSDNode *M = dyn_cast<SrcValueSDNode>(Node)) {
    if (M->getValue())
      Op += "<" + M->getValue()->getName() + ">";
    else
      Op += "<null>";
  } else if (const MemOperandSDNode *M = dyn_cast<MemOperandSDNode>(Node)) {
    const Value *V = M->MO.getValue();
    Op += '<';
    if (!V) {
      Op += "(unknown)";
    } else if (isa<PseudoSourceValue>(V)) {
      // PseudoSourceValues don't have names, so use their print method.
      {
        raw_string_ostream OSS(Op);
        OSS << *M->MO.getValue();
      }
    } else {
      Op += V->getName();
    }
    Op += '+' + itostr(M->MO.getOffset()) + '>';
  } else if (const ARG_FLAGSSDNode *N = dyn_cast<ARG_FLAGSSDNode>(Node)) {
    Op = Op + " AF=" + N->getArgFlags().getArgFlagsString();
  } else if (const VTSDNode *N = dyn_cast<VTSDNode>(Node)) {
    Op = Op + " VT=" + N->getVT().getMVTString();
  } else if (const LoadSDNode *LD = dyn_cast<LoadSDNode>(Node)) {
    bool doExt = true;
    switch (LD->getExtensionType()) {
    default: doExt = false; break;
    case ISD::EXTLOAD:
      Op = Op + "<anyext ";
      break;
    case ISD::SEXTLOAD:
      Op = Op + " <sext ";
      break;
    case ISD::ZEXTLOAD:
      Op = Op + " <zext ";
      break;
    }
    if (doExt)
      Op += LD->getMemoryVT().getMVTString() + ">";
    if (LD->isVolatile())
      Op += "<V>";
    Op += LD->getIndexedModeName(LD->getAddressingMode());
    if (LD->getAlignment() > 1)
      Op += " A=" + utostr(LD->getAlignment());
  } else if (const StoreSDNode *ST = dyn_cast<StoreSDNode>(Node)) {
    if (ST->isTruncatingStore())
      Op += "<trunc " + ST->getMemoryVT().getMVTString() + ">";
    if (ST->isVolatile())
      Op += "<V>";
    Op += ST->getIndexedModeName(ST->getAddressingMode());
    if (ST->getAlignment() > 1)
      Op += " A=" + utostr(ST->getAlignment());
  }

#if 0
  Op += " Id=" + itostr(Node->getNodeId());
#endif

  return Op;
}

/// viewGraph - Pop up a ghostview window with the reachable parts of the DAG
/// rendered using 'dot'.
///
void SelectionDAG::viewGraph(const std::string &Title) {
// This code is only for debugging!
#ifndef NDEBUG
  ViewGraph(this, "dag." + getMachineFunction().getFunction()->getName(),
            Title);
#else
  cerr << "SelectionDAG::viewGraph is only available in debug builds on "
       << "systems with Graphviz or gv!\n";
#endif  // NDEBUG
}

// This overload is defined out-of-line here instead of just using a
// default parameter because this is easiest for gdb to call.
void SelectionDAG::viewGraph() {
  viewGraph("");
}

/// clearGraphAttrs - Clear all previously defined node graph attributes.
/// Intended to be used from a debugging tool (eg. gdb).
void SelectionDAG::clearGraphAttrs() {
#ifndef NDEBUG
  NodeGraphAttrs.clear();
#else
  cerr << "SelectionDAG::clearGraphAttrs is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

/// setGraphAttrs - Set graph attributes for a node. (eg. "color=red".)
///
void SelectionDAG::setGraphAttrs(const SDNode *N, const char *Attrs) {
#ifndef NDEBUG
  NodeGraphAttrs[N] = Attrs;
#else
  cerr << "SelectionDAG::setGraphAttrs is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

/// getGraphAttrs - Get graph attributes for a node. (eg. "color=red".)
/// Used from getNodeAttributes.
const std::string SelectionDAG::getGraphAttrs(const SDNode *N) const {
#ifndef NDEBUG
  std::map<const SDNode *, std::string>::const_iterator I =
    NodeGraphAttrs.find(N);

  if (I != NodeGraphAttrs.end())
    return I->second;
  else
    return "";
#else
  cerr << "SelectionDAG::getGraphAttrs is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
  return std::string("");
#endif
}

/// setGraphColor - Convenience for setting node color attribute.
///
void SelectionDAG::setGraphColor(const SDNode *N, const char *Color) {
#ifndef NDEBUG
  NodeGraphAttrs[N] = std::string("color=") + Color;
#else
  cerr << "SelectionDAG::setGraphColor is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

/// setSubgraphColorHelper - Implement setSubgraphColor.  Return
/// whether we truncated the search.
///
bool SelectionDAG::setSubgraphColorHelper(SDNode *N, const char *Color, DenseSet<SDNode *> &visited,
                                          int level, bool &printed) {
  bool hit_limit = false;

#ifndef NDEBUG
  if (level >= 20) {
    if (!printed) {
      printed = true;
      DOUT << "setSubgraphColor hit max level\n";
    }
    return true;
  }

  unsigned oldSize = visited.size();
  visited.insert(N);
  if (visited.size() != oldSize) {
    setGraphColor(N, Color);
    for(SDNodeIterator i = SDNodeIterator::begin(N), iend = SDNodeIterator::end(N);
        i != iend;
        ++i) {
      hit_limit = setSubgraphColorHelper(*i, Color, visited, level+1, printed) || hit_limit;
    }
  }
#else
  cerr << "SelectionDAG::setSubgraphColor is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
  return hit_limit;
}

/// setSubgraphColor - Convenience for setting subgraph color attribute.
///
void SelectionDAG::setSubgraphColor(SDNode *N, const char *Color) {
#ifndef NDEBUG
  DenseSet<SDNode *> visited;
  bool printed = false;
  if (setSubgraphColorHelper(N, Color, visited, 0, printed)) {
    // Visually mark that we hit the limit
    if (strcmp(Color, "red") == 0) {
      setSubgraphColorHelper(N, "blue", visited, 0, printed);
    }
    else if (strcmp(Color, "yellow") == 0) {
      setSubgraphColorHelper(N, "green", visited, 0, printed);
    }
  }

#else
  cerr << "SelectionDAG::setSubgraphColor is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

std::string ScheduleDAGSDNodes::getGraphNodeLabel(const SUnit *SU) const {
  std::string s;
  raw_string_ostream O(s);
  O << "SU(" << SU->NodeNum << "): ";
  if (SU->getNode()) {
    SmallVector<SDNode *, 4> FlaggedNodes;
    for (SDNode *N = SU->getNode(); N; N = N->getFlaggedNode())
      FlaggedNodes.push_back(N);
    while (!FlaggedNodes.empty()) {
      O << DOTGraphTraits<SelectionDAG*>::getNodeLabel(FlaggedNodes.back(), DAG);
      FlaggedNodes.pop_back();
      if (!FlaggedNodes.empty())
        O << "\n    ";
    }
  } else {
    O << "CROSS RC COPY";
  }
  return O.str();
}

void ScheduleDAGSDNodes::getCustomGraphFeatures(GraphWriter<ScheduleDAG*> &GW) const {
  if (DAG) {
    // Draw a special "GraphRoot" node to indicate the root of the graph.
    GW.emitSimpleNode(0, "plaintext=circle", "GraphRoot");
    const SDNode *N = DAG->getRoot().getNode();
    if (N && N->getNodeId() != -1)
      GW.emitEdge(0, -1, &SUnits[N->getNodeId()], -1,
                  "color=blue,style=dashed");
  }
}
<commit_msg>Fix printing of PseudoSourceValues in SDNode graphs.<commit_after>//===-- SelectionDAGPrinter.cpp - Implement SelectionDAG::viewGraph() -----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This implements the SelectionDAG::viewGraph method.
//
//===----------------------------------------------------------------------===//

#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/ScheduleDAGSDNodes.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/PseudoSourceValue.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Config/config.h"
#include <fstream>
using namespace llvm;

namespace llvm {
  template<>
  struct DOTGraphTraits<SelectionDAG*> : public DefaultDOTGraphTraits {
    static bool hasEdgeDestLabels() {
      return true;
    }

    static unsigned numEdgeDestLabels(const void *Node) {
      return ((const SDNode *) Node)->getNumValues();
    }

    static std::string getEdgeDestLabel(const void *Node, unsigned i) {
      return ((const SDNode *) Node)->getValueType(i).getMVTString();
    }

    /// edgeTargetsEdgeSource - This method returns true if this outgoing edge
    /// should actually target another edge source, not a node.  If this method is
    /// implemented, getEdgeTarget should be implemented.
    template<typename EdgeIter>
    static bool edgeTargetsEdgeSource(const void *Node, EdgeIter I) {
      return true;
    }

    /// getEdgeTarget - If edgeTargetsEdgeSource returns true, this method is
    /// called to determine which outgoing edge of Node is the target of this
    /// edge.
    template<typename EdgeIter>
    static EdgeIter getEdgeTarget(const void *Node, EdgeIter I) {
      SDNode *TargetNode = *I;
      SDNodeIterator NI = SDNodeIterator::begin(TargetNode);
      std::advance(NI, I.getNode()->getOperand(I.getOperand()).getResNo());
      return NI;
    }

    static std::string getGraphName(const SelectionDAG *G) {
      return G->getMachineFunction().getFunction()->getName();
    }

    static bool renderGraphFromBottomUp() {
      return true;
    }

    static bool hasNodeAddressLabel(const SDNode *Node,
                                    const SelectionDAG *Graph) {
      return true;
    }

    /// If you want to override the dot attributes printed for a particular
    /// edge, override this method.
    template<typename EdgeIter>
    static std::string getEdgeAttributes(const void *Node, EdgeIter EI) {
      SDValue Op = EI.getNode()->getOperand(EI.getOperand());
      MVT VT = Op.getValueType();
      if (VT == MVT::Flag)
        return "color=red,style=bold";
      else if (VT == MVT::Other)
        return "color=blue,style=dashed";
      return "";
    }

    static std::string getNodeLabel(const SDNode *Node,
                                    const SelectionDAG *Graph);
    static std::string getNodeAttributes(const SDNode *N,
                                         const SelectionDAG *Graph) {
#ifndef NDEBUG
      const std::string &Attrs = Graph->getGraphAttrs(N);
      if (!Attrs.empty()) {
        if (Attrs.find("shape=") == std::string::npos)
          return std::string("shape=Mrecord,") + Attrs;
        else
          return Attrs;
      }
#endif
      return "shape=Mrecord";
    }

    static void addCustomGraphFeatures(SelectionDAG *G,
                                       GraphWriter<SelectionDAG*> &GW) {
      GW.emitSimpleNode(0, "plaintext=circle", "GraphRoot");
      if (G->getRoot().getNode())
        GW.emitEdge(0, -1, G->getRoot().getNode(), G->getRoot().getResNo(),
                    "color=blue,style=dashed");
    }
  };
}

std::string DOTGraphTraits<SelectionDAG*>::getNodeLabel(const SDNode *Node,
                                                        const SelectionDAG *G) {
  std::string Op = Node->getOperationName(G);

  if (const ConstantSDNode *CSDN = dyn_cast<ConstantSDNode>(Node)) {
    Op += ": " + utostr(CSDN->getZExtValue());
  } else if (const ConstantFPSDNode *CSDN = dyn_cast<ConstantFPSDNode>(Node)) {
    Op += ": " + ftostr(CSDN->getValueAPF());
  } else if (const GlobalAddressSDNode *GADN =
             dyn_cast<GlobalAddressSDNode>(Node)) {
    Op += ": " + GADN->getGlobal()->getName();
    if (int64_t Offset = GADN->getOffset()) {
      if (Offset > 0)
        Op += "+" + itostr(Offset);
      else
        Op += itostr(Offset);
    }
  } else if (const FrameIndexSDNode *FIDN = dyn_cast<FrameIndexSDNode>(Node)) {
    Op += " " + itostr(FIDN->getIndex());
  } else if (const JumpTableSDNode *JTDN = dyn_cast<JumpTableSDNode>(Node)) {
    Op += " " + itostr(JTDN->getIndex());
  } else if (const ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(Node)){
    if (CP->isMachineConstantPoolEntry()) {
      Op += '<';
      {
        raw_string_ostream OSS(Op);
        OSS << *CP->getMachineCPVal();
      }
      Op += '>';
    } else {
      if (ConstantFP *CFP = dyn_cast<ConstantFP>(CP->getConstVal()))
        Op += "<" + ftostr(CFP->getValueAPF()) + ">";
      else if (ConstantInt *CI = dyn_cast<ConstantInt>(CP->getConstVal()))
        Op += "<" + utostr(CI->getZExtValue()) + ">";
      else {
        Op += '<';
        {
          raw_string_ostream OSS(Op);
          WriteAsOperand(OSS, CP->getConstVal(), false);
        }
        Op += '>';
      }
    }
    Op += " A=" + itostr(1 << CP->getAlignment());
  } else if (const BasicBlockSDNode *BBDN = dyn_cast<BasicBlockSDNode>(Node)) {
    Op = "BB: ";
    const Value *LBB = (const Value*)BBDN->getBasicBlock()->getBasicBlock();
    if (LBB)
      Op += LBB->getName();
    //Op += " " + (const void*)BBDN->getBasicBlock();
  } else if (const RegisterSDNode *R = dyn_cast<RegisterSDNode>(Node)) {
    if (G && R->getReg() != 0 &&
        TargetRegisterInfo::isPhysicalRegister(R->getReg())) {
      Op = Op + " " +
        G->getTarget().getRegisterInfo()->getName(R->getReg());
    } else {
      Op += " #" + utostr(R->getReg());
    }
  } else if (const DbgStopPointSDNode *D = dyn_cast<DbgStopPointSDNode>(Node)) {
    Op += ": " + D->getCompileUnit()->getFileName();
    Op += ":" + utostr(D->getLine());
    if (D->getColumn() != 0)
      Op += ":" + utostr(D->getColumn());
  } else if (const LabelSDNode *L = dyn_cast<LabelSDNode>(Node)) {
    Op += ": LabelID=" + utostr(L->getLabelID());
  } else if (const CallSDNode *C = dyn_cast<CallSDNode>(Node)) {
    Op += ": CallingConv=" + utostr(C->getCallingConv());
    if (C->isVarArg())
      Op += ", isVarArg";
    if (C->isTailCall())
      Op += ", isTailCall";
  } else if (const ExternalSymbolSDNode *ES =
             dyn_cast<ExternalSymbolSDNode>(Node)) {
    Op += "'" + std::string(ES->getSymbol()) + "'";
  } else if (const SrcValueSDNode *M = dyn_cast<SrcValueSDNode>(Node)) {
    if (M->getValue())
      Op += "<" + M->getValue()->getName() + ">";
    else
      Op += "<null>";
  } else if (const MemOperandSDNode *M = dyn_cast<MemOperandSDNode>(Node)) {
    const Value *V = M->MO.getValue();
    Op += '<';
    if (!V) {
      Op += "(unknown)";
    } else if (const PseudoSourceValue *PSV = dyn_cast<PseudoSourceValue>(V)) {
      // PseudoSourceValues don't have names, so use their print method.
      raw_string_ostream OSS(Op);
      PSV->print(OSS);
    } else {
      Op += V->getName();
    }
    Op += '+' + itostr(M->MO.getOffset()) + '>';
  } else if (const ARG_FLAGSSDNode *N = dyn_cast<ARG_FLAGSSDNode>(Node)) {
    Op = Op + " AF=" + N->getArgFlags().getArgFlagsString();
  } else if (const VTSDNode *N = dyn_cast<VTSDNode>(Node)) {
    Op = Op + " VT=" + N->getVT().getMVTString();
  } else if (const LoadSDNode *LD = dyn_cast<LoadSDNode>(Node)) {
    bool doExt = true;
    switch (LD->getExtensionType()) {
    default: doExt = false; break;
    case ISD::EXTLOAD:
      Op = Op + "<anyext ";
      break;
    case ISD::SEXTLOAD:
      Op = Op + " <sext ";
      break;
    case ISD::ZEXTLOAD:
      Op = Op + " <zext ";
      break;
    }
    if (doExt)
      Op += LD->getMemoryVT().getMVTString() + ">";
    if (LD->isVolatile())
      Op += "<V>";
    Op += LD->getIndexedModeName(LD->getAddressingMode());
    if (LD->getAlignment() > 1)
      Op += " A=" + utostr(LD->getAlignment());
  } else if (const StoreSDNode *ST = dyn_cast<StoreSDNode>(Node)) {
    if (ST->isTruncatingStore())
      Op += "<trunc " + ST->getMemoryVT().getMVTString() + ">";
    if (ST->isVolatile())
      Op += "<V>";
    Op += ST->getIndexedModeName(ST->getAddressingMode());
    if (ST->getAlignment() > 1)
      Op += " A=" + utostr(ST->getAlignment());
  }

#if 0
  Op += " Id=" + itostr(Node->getNodeId());
#endif

  return Op;
}

/// viewGraph - Pop up a ghostview window with the reachable parts of the DAG
/// rendered using 'dot'.
///
void SelectionDAG::viewGraph(const std::string &Title) {
// This code is only for debugging!
#ifndef NDEBUG
  ViewGraph(this, "dag." + getMachineFunction().getFunction()->getName(),
            Title);
#else
  cerr << "SelectionDAG::viewGraph is only available in debug builds on "
       << "systems with Graphviz or gv!\n";
#endif  // NDEBUG
}

// This overload is defined out-of-line here instead of just using a
// default parameter because this is easiest for gdb to call.
void SelectionDAG::viewGraph() {
  viewGraph("");
}

/// clearGraphAttrs - Clear all previously defined node graph attributes.
/// Intended to be used from a debugging tool (eg. gdb).
void SelectionDAG::clearGraphAttrs() {
#ifndef NDEBUG
  NodeGraphAttrs.clear();
#else
  cerr << "SelectionDAG::clearGraphAttrs is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

/// setGraphAttrs - Set graph attributes for a node. (eg. "color=red".)
///
void SelectionDAG::setGraphAttrs(const SDNode *N, const char *Attrs) {
#ifndef NDEBUG
  NodeGraphAttrs[N] = Attrs;
#else
  cerr << "SelectionDAG::setGraphAttrs is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

/// getGraphAttrs - Get graph attributes for a node. (eg. "color=red".)
/// Used from getNodeAttributes.
const std::string SelectionDAG::getGraphAttrs(const SDNode *N) const {
#ifndef NDEBUG
  std::map<const SDNode *, std::string>::const_iterator I =
    NodeGraphAttrs.find(N);

  if (I != NodeGraphAttrs.end())
    return I->second;
  else
    return "";
#else
  cerr << "SelectionDAG::getGraphAttrs is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
  return std::string("");
#endif
}

/// setGraphColor - Convenience for setting node color attribute.
///
void SelectionDAG::setGraphColor(const SDNode *N, const char *Color) {
#ifndef NDEBUG
  NodeGraphAttrs[N] = std::string("color=") + Color;
#else
  cerr << "SelectionDAG::setGraphColor is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

/// setSubgraphColorHelper - Implement setSubgraphColor.  Return
/// whether we truncated the search.
///
bool SelectionDAG::setSubgraphColorHelper(SDNode *N, const char *Color, DenseSet<SDNode *> &visited,
                                          int level, bool &printed) {
  bool hit_limit = false;

#ifndef NDEBUG
  if (level >= 20) {
    if (!printed) {
      printed = true;
      DOUT << "setSubgraphColor hit max level\n";
    }
    return true;
  }

  unsigned oldSize = visited.size();
  visited.insert(N);
  if (visited.size() != oldSize) {
    setGraphColor(N, Color);
    for(SDNodeIterator i = SDNodeIterator::begin(N), iend = SDNodeIterator::end(N);
        i != iend;
        ++i) {
      hit_limit = setSubgraphColorHelper(*i, Color, visited, level+1, printed) || hit_limit;
    }
  }
#else
  cerr << "SelectionDAG::setSubgraphColor is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
  return hit_limit;
}

/// setSubgraphColor - Convenience for setting subgraph color attribute.
///
void SelectionDAG::setSubgraphColor(SDNode *N, const char *Color) {
#ifndef NDEBUG
  DenseSet<SDNode *> visited;
  bool printed = false;
  if (setSubgraphColorHelper(N, Color, visited, 0, printed)) {
    // Visually mark that we hit the limit
    if (strcmp(Color, "red") == 0) {
      setSubgraphColorHelper(N, "blue", visited, 0, printed);
    }
    else if (strcmp(Color, "yellow") == 0) {
      setSubgraphColorHelper(N, "green", visited, 0, printed);
    }
  }

#else
  cerr << "SelectionDAG::setSubgraphColor is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

std::string ScheduleDAGSDNodes::getGraphNodeLabel(const SUnit *SU) const {
  std::string s;
  raw_string_ostream O(s);
  O << "SU(" << SU->NodeNum << "): ";
  if (SU->getNode()) {
    SmallVector<SDNode *, 4> FlaggedNodes;
    for (SDNode *N = SU->getNode(); N; N = N->getFlaggedNode())
      FlaggedNodes.push_back(N);
    while (!FlaggedNodes.empty()) {
      O << DOTGraphTraits<SelectionDAG*>::getNodeLabel(FlaggedNodes.back(), DAG);
      FlaggedNodes.pop_back();
      if (!FlaggedNodes.empty())
        O << "\n    ";
    }
  } else {
    O << "CROSS RC COPY";
  }
  return O.str();
}

void ScheduleDAGSDNodes::getCustomGraphFeatures(GraphWriter<ScheduleDAG*> &GW) const {
  if (DAG) {
    // Draw a special "GraphRoot" node to indicate the root of the graph.
    GW.emitSimpleNode(0, "plaintext=circle", "GraphRoot");
    const SDNode *N = DAG->getRoot().getNode();
    if (N && N->getNodeId() != -1)
      GW.emitEdge(0, -1, &SUnits[N->getNodeId()], -1,
                  "color=blue,style=dashed");
  }
}
<|endoftext|>