<commit_before>/*-------------------------------------------------------------------------
  usbdevice.cxx - docker USB classes

             (c) 2006 Pierre Gaufillet <pierre.gaufillet@magic.fr>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-------------------------------------------------------------------------*/

using namespace std;

#include <iostream>
#include <exception>
#include <usb.h>
#include "config.h"
#include "DataBuffer.h"
#include "usbdevice.h"

#define EP_FLASH_OUT 1
#define EP_FLASH_IN  2

USBDevice::USBDevice(struct usb_bus *busses, long vendor, long product)
{
    struct usb_bus *bus;
    int c;

    dh = NULL;
    for (bus = busses; bus; bus = bus->next) {
        struct usb_device *dev;

        for (dev = bus->devices; dev; dev = dev->next) {
            /* Look for Vasco devices */
            if ((dev->descriptor.idVendor == vendor) &&
                (dev->descriptor.idProduct == product))
            {
                // Got one !
//                cout << "device found\n";
                dh = usb_open(dev);
                if(!dh)
                {
                    // raise exception
                    abort();
                }

                c = usb_set_configuration(dh, 2);
                if(c)
                {
                    // raise exception
                    abort();
                }

                c = usb_claim_interface(dh, 0);
                if(c)
                {
                    // raise exception
                    abort();
                }

                break;
            }
        }
        if(dh)
        {
            //cout << "get sections descriptors\n";
            get_section_descriptors();
            break;
        }
    }
}

USBDevice::~USBDevice()
{
    if(dh)
    {
        usb_close(dh);
    }
}

void USBDevice::erase(void)
{
    for(RangeVector::iterator i = device_mmap.begin(); i != device_mmap.end(); i++)
    {
        if((*i)->flags & FLASH_SECTION_WRITE)
        {
            cout << "erasing section [" << hex << (*i)->begin <<", " << (*i)->end << "]" << endl;
            if((*i)->end - (*i)->begin < 64)
            {
                erase_block((*i)->begin);
            }
            else
            {
                for(long addr = (*i)->begin; addr <= (*i)->end - 63; addr += 64)
                {
                    erase_block(addr);
                }
            }
        }
    }
}

void USBDevice::write(DataBuffer& tab)
{
    for(RangeVector::iterator i = device_mmap.begin(); i != device_mmap.end(); i++)
    {
        if((*i)->flags & FLASH_SECTION_WRITE)
        {
            cout << "writing section [" << hex << (*i)->begin <<", " << (*i)->end << "]" << endl;
            if((*i)->end - (*i)->begin < 32)
            {
                write_block((*i)->begin, tab);
            }
            else
            {
                for(long addr = (*i)->begin; addr <= (*i)->end - 31; addr += 32)
                {
                    write_block(addr, tab);
                }
            }
        }
    }
}

void USBDevice::read(DataBuffer& tab)
{
    for(RangeVector::iterator i = device_mmap.begin(); i != device_mmap.end(); i++)
    {
        if((*i)->flags & FLASH_SECTION_READ)
        {
            cout << "reading section [" << hex << (*i)->begin <<", " << (*i)->end << "]" << endl;
            if((*i)->end - (*i)->begin < 64)
            {
                read_block((*i)->begin, tab);
            }
            else
            {
                for(long addr = (*i)->begin; addr <= (*i)->end - 63; addr += 64)
                {
                    read_block(addr, tab);
                }
            }
        }
    }
}

void USBDevice::reset(void)
{
    char cmd = READ_FLASH_CMD;
    int c;

    c = usb_bulk_write(dh, EP_FLASH_OUT, &cmd, sizeof(cmd), 0);
    if(c <= 0)
    {
        // Raise exception
        abort();
    }
}

void USBDevice::validate_application(void)
{
}

void USBDevice::erase_block(long address)
{
    int c;
    char erase_bytes[] = {ERASE_FLASH_CMD,0x00,0x00,0x00};

    erase_bytes[1] = address & 0xff;
    erase_bytes[2] = (address >> 8) & 0xff;
    erase_bytes[3] = (address >> 16) & 0xff;

//    cout << "erase block " << hex << address << endl;
    c = usb_bulk_write(dh, EP_FLASH_OUT, erase_bytes, sizeof(erase_bytes), 0);
    if(c <= 0)
    {
        // Raise exception
        abort();
    }
}

void USBDevice::write_block(long address, DataBuffer& tab)
{
    int c;
    char write_bytes[] = {WRITE_FLASH_CMD,0x00,0x00,0x00,
                          0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 8
                          0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 16
                          0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 24
                          0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff  // 32
                         };

//    cout << "write block " << hex << address << endl;
    bool isBlank = true;

    for(long a = address; a < address + 32; a++)
    {
        if(!tab.isblank(a))
        {
            write_bytes[a - address + 4] = tab[a];
            isBlank = false;
        }
    }

    if(isBlank)
    {
        return;
    }
//    cout << " writing for real..." << endl;
    write_bytes[1] = address & 0xff;
    write_bytes[2] = (address >> 8) & 0xff;
    write_bytes[3] = (address >> 16) & 0xff;

    c = usb_bulk_write(dh, EP_FLASH_OUT, write_bytes, sizeof(write_bytes), 0);
    if(c <= 0)
    {
        // Raise exception
        abort();
    }
}

void USBDevice::read_block(long address, DataBuffer& tab)
{
    int c;
    unsigned char buffer[256];
    char read_bytes[]  = {READ_FLASH_CMD,0x00,0x00,0x00};

    read_bytes[1] = address & 0xff;
    read_bytes[2] = (address >> 8) & 0xff;
    read_bytes[3] = (address >> 16) & 0xff;

    c = usb_bulk_write(dh, EP_FLASH_OUT, read_bytes, sizeof(read_bytes), 0);
    if(c <= 0)
    {
        // Raise exception
        abort();
    }

    c=usb_bulk_read(dh, EP_FLASH_IN, (char*)buffer, sizeof(buffer), 0);
    if(c == 64)
    {
        for(long j = 0; j < 64; j++)
        {
            tab[address + j] = buffer[j];
        }
    }
    else
    {
        // Raise an exception
        abort();
    }

}

void USBDevice::get_section_descriptors(void)
{
    int c;
    unsigned char buffer[256];
    char cmd = SECTION_DESCRIPTOR_CMD;
    long begin, end;
    char flags;

    c = usb_bulk_write(dh, EP_FLASH_OUT, &cmd, sizeof(cmd), 0);
    if(c <= 0)
    {
        // Raise exception
        abort();
    }

    c = usb_bulk_read(dh, EP_FLASH_IN, (char*)buffer, sizeof(buffer), 0);

    for(int i = 0; i < buffer[0]; i++)
    {
        flags = buffer[i * SECTION_DESCRIPTOR_SIZE + 1];
        begin = buffer[i * SECTION_DESCRIPTOR_SIZE + 2] +
                (buffer[i * SECTION_DESCRIPTOR_SIZE + 3] << 8) +
                (buffer[i * SECTION_DESCRIPTOR_SIZE + 4] << 16);
        end   = buffer[i * SECTION_DESCRIPTOR_SIZE + 5] +
                (buffer[i * SECTION_DESCRIPTOR_SIZE + 6] << 8) +
                (buffer[i * SECTION_DESCRIPTOR_SIZE + 7] << 16);

//        cout << "section " << i << " begins at " << hex << begin << " and finish at " << end <<
//                ", flags = " << hex << (int)flags << endl;
        device_mmap.push_back(new Range(flags, begin, end));
    }
}

<commit_msg>as libusb seems to understand 0 as an immediate time out, change it to 5000ms<commit_after>/*-------------------------------------------------------------------------
  usbdevice.cxx - docker USB classes

             (c) 2006 Pierre Gaufillet <pierre.gaufillet@magic.fr>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-------------------------------------------------------------------------*/

using namespace std;

#include <iostream>
#include <exception>
#include <usb.h>
#include "config.h"
#include "DataBuffer.h"
#include "usbdevice.h"

#define EP_FLASH_OUT 1
#define EP_FLASH_IN  2

/* In millisecond. Note that with libusb 0.11 on Linux, a timeout of 0 results
 * in a immediate return... */
#define USB_TIMEOUT 5000

USBDevice::USBDevice(struct usb_bus *busses, long vendor, long product)
{
    struct usb_bus *bus;
    int c;

    dh = NULL;
    for (bus = busses; bus; bus = bus->next) {
        struct usb_device *dev;

        for (dev = bus->devices; dev; dev = dev->next) {
            /* Look for Vasco devices */
            if ((dev->descriptor.idVendor == vendor) &&
                (dev->descriptor.idProduct == product))
            {
                // Got one !
//                cout << "device found\n";
                dh = usb_open(dev);
                if(!dh)
                {
                    // raise exception
                    abort();
                }

                c = usb_set_configuration(dh, 2);
                if(c)
                {
                    // raise exception
                    abort();
                }

                c = usb_claim_interface(dh, 0);
                if(c)
                {
                    // raise exception
                    abort();
                }

                break;
            }
        }
        if(dh)
        {
            //cout << "get sections descriptors\n";
            get_section_descriptors();
            break;
        }
    }
}

USBDevice::~USBDevice()
{
    if(dh)
    {
        usb_close(dh);
    }
}

void USBDevice::erase(void)
{
    for(RangeVector::iterator i = device_mmap.begin(); i != device_mmap.end(); i++)
    {
        if((*i)->flags & FLASH_SECTION_WRITE)
        {
            cout << "erasing section [" << hex << (*i)->begin <<", " << (*i)->end << "]" << endl;
            if((*i)->end - (*i)->begin < 64)
            {
                erase_block((*i)->begin);
            }
            else
            {
                for(long addr = (*i)->begin; addr <= (*i)->end - 63; addr += 64)
                {
                    erase_block(addr);
                }
            }
        }
    }
}

void USBDevice::write(DataBuffer& tab)
{
    for(RangeVector::iterator i = device_mmap.begin(); i != device_mmap.end(); i++)
    {
        if((*i)->flags & FLASH_SECTION_WRITE)
        {
            cout << "writing section [" << hex << (*i)->begin <<", " << (*i)->end << "]" << endl;
            if((*i)->end - (*i)->begin < 32)
            {
                write_block((*i)->begin, tab);
            }
            else
            {
                for(long addr = (*i)->begin; addr <= (*i)->end - 31; addr += 32)
                {
                    write_block(addr, tab);
                }
            }
        }
    }
}

void USBDevice::read(DataBuffer& tab)
{
    for(RangeVector::iterator i = device_mmap.begin(); i != device_mmap.end(); i++)
    {
        if((*i)->flags & FLASH_SECTION_READ)
        {
            cout << "reading section [" << hex << (*i)->begin <<", " << (*i)->end << "]" << endl;
            if((*i)->end - (*i)->begin < 64)
            {
                read_block((*i)->begin, tab);
            }
            else
            {
                for(long addr = (*i)->begin; addr <= (*i)->end - 63; addr += 64)
                {
                    read_block(addr, tab);
                }
            }
        }
    }
}

void USBDevice::reset(void)
{
    char cmd = READ_FLASH_CMD;
    int c;

    c = usb_bulk_write(dh, EP_FLASH_OUT, &cmd, sizeof(cmd), USB_TIMEOUT);
    if(c <= 0)
    {
        // Raise exception
        abort();
    }
}

void USBDevice::validate_application(void)
{
}

void USBDevice::erase_block(long address)
{
    int c;
    char erase_bytes[] = {ERASE_FLASH_CMD,0x00,0x00,0x00};

    erase_bytes[1] = address & 0xff;
    erase_bytes[2] = (address >> 8) & 0xff;
    erase_bytes[3] = (address >> 16) & 0xff;

//    cout << "erase block " << hex << address << endl;
    c = usb_bulk_write(dh, EP_FLASH_OUT, erase_bytes, sizeof(erase_bytes), USB_TIMEOUT);
    if(c <= 0)
    {
        // Raise exception
        abort();
    }
}

void USBDevice::write_block(long address, DataBuffer& tab)
{
    int c;
    char write_bytes[] = {WRITE_FLASH_CMD,0x00,0x00,0x00,
                          0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 8
                          0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 16
                          0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 24
                          0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff  // 32
                         };

//    cout << "write block " << hex << address << endl;
    bool isBlank = true;

    for(long a = address; a < address + 32; a++)
    {
        if(!tab.isblank(a))
        {
            write_bytes[a - address + 4] = tab[a];
            isBlank = false;
        }
    }

    if(isBlank)
    {
        return;
    }
//    cout << " writing for real..." << endl;
    write_bytes[1] = address & 0xff;
    write_bytes[2] = (address >> 8) & 0xff;
    write_bytes[3] = (address >> 16) & 0xff;

    c = usb_bulk_write(dh, EP_FLASH_OUT, write_bytes, sizeof(write_bytes), USB_TIMEOUT);
    if(c <= 0)
    {
        // Raise exception
        abort();
    }
}

void USBDevice::read_block(long address, DataBuffer& tab)
{
    int c;
    unsigned char buffer[256];
    char read_bytes[]  = {READ_FLASH_CMD,0x00,0x00,0x00};

    read_bytes[1] = address & 0xff;
    read_bytes[2] = (address >> 8) & 0xff;
    read_bytes[3] = (address >> 16) & 0xff;

    c = usb_bulk_write(dh, EP_FLASH_OUT, read_bytes, sizeof(read_bytes), USB_TIMEOUT);
    if(c <= 0)
    {
        // Raise exception
        abort();
    }

    c=usb_bulk_read(dh, EP_FLASH_IN, (char*)buffer, sizeof(buffer), USB_TIMEOUT);
    if(c == 64)
    {
        for(long j = 0; j < 64; j++)
        {
            tab[address + j] = buffer[j];
        }
    }
    else
    {
        // Raise an exception
        abort();
    }

}

void USBDevice::get_section_descriptors(void)
{
    int c;
    unsigned char buffer[256];
    char cmd = SECTION_DESCRIPTOR_CMD;
    long begin, end;
    char flags;

    c = usb_bulk_write(dh, EP_FLASH_OUT, &cmd, sizeof(cmd), USB_TIMEOUT);
    if(c <= 0)
    {
        // Raise exception
        abort();
    }

    c = usb_bulk_read(dh, EP_FLASH_IN, (char*)buffer, sizeof(buffer), USB_TIMEOUT);

    for(int i = 0; i < buffer[0]; i++)
    {
        flags = buffer[i * SECTION_DESCRIPTOR_SIZE + 1];
        begin = buffer[i * SECTION_DESCRIPTOR_SIZE + 2] +
                (buffer[i * SECTION_DESCRIPTOR_SIZE + 3] << 8) +
                (buffer[i * SECTION_DESCRIPTOR_SIZE + 4] << 16);
        end   = buffer[i * SECTION_DESCRIPTOR_SIZE + 5] +
                (buffer[i * SECTION_DESCRIPTOR_SIZE + 6] << 8) +
                (buffer[i * SECTION_DESCRIPTOR_SIZE + 7] << 16);

//        cout << "section " << i << " begins at " << hex << begin << " and finish at " << end <<
//                ", flags = " << hex << (int)flags << endl;
        device_mmap.push_back(new Range(flags, begin, end));
    }
}

<|endoftext|>


<commit_before>/*
	GWEN
	Copyright (c) 2010 Facepunch Studios
	See license in Gwen.h
*/

#include "Gwen/Gwen.h"
#include "Gwen/Controls/RichLabel.h"
#include "Gwen/Controls/Label.h"
#include "Gwen/Utility.h"

using namespace Gwen;
using namespace Gwen::Controls;

const unsigned char Type_Text = 0;
const unsigned char Type_Newline = 1;

GWEN_CONTROL_CONSTRUCTOR( RichLabel )
{
	m_bNeedsRebuild = false;
}

void RichLabel::AddLineBreak()
{
	DividedText t;
	t.type = Type_Newline;
	m_TextBlocks.push_back( t );
}

void RichLabel::AddText( const Gwen::TextObject & text, Gwen::Color color, Gwen::Font* font )
{
	if ( text.length() == 0 ) { return; }

	Gwen::Utility::Strings::UnicodeList lst;
	Gwen::Utility::Strings::Split( text.GetUnicode(), L"\n", lst, false );

	for ( size_t i = 0; i < lst.size(); i++ )
	{
		if ( i > 0 ) { AddLineBreak(); }

		DividedText t;
		t.type = Type_Text;
		t.text = lst[i];
		t.color = color;
		t.font = font;
		m_TextBlocks.push_back( t );
		m_bNeedsRebuild = true;
		Invalidate();
	}
}

bool RichLabel::SizeToChildren( bool w, bool h )
{
	Rebuild();
	return BaseClass::SizeToChildren( w, h );
}

void RichLabel::SplitLabel( const Gwen::UnicodeString & text, Gwen::Font* pFont, const DividedText & txt, int & x, int & y, int & lineheight )
{
	Gwen::Utility::Strings::UnicodeList lst;
	Gwen::Utility::Strings::Split( text, L" ", lst, true );

	if ( lst.size() == 0 ) { return; }

	int iSpaceLeft = Width() - x;
	// Does the whole word fit in?
	{
		Gwen::Point StringSize = GetSkin()->GetRender()->MeasureText( pFont, text );

		if ( iSpaceLeft > StringSize.x )
		{
			return CreateLabel( text, txt, x, y, lineheight, true );
		}
	}
	// If the first word is bigger than the line, just give up.
	{
		Gwen::Point WordSize = GetSkin()->GetRender()->MeasureText( pFont, lst[0] );

		if ( WordSize.x >= iSpaceLeft )
		{
			CreateLabel( lst[0], txt, x, y, lineheight, true );

			if ( lst[0].size() >= text.size() ) { return; }

			Gwen::UnicodeString LeftOver = text.substr( lst[0].size() + 1 );
			return SplitLabel( LeftOver, pFont, txt, x, y, lineheight );
		}
	}
	Gwen::UnicodeString strNewString = L"";

	for ( size_t i = 0; i < lst.size(); i++ )
	{
		Gwen::Point WordSize = GetSkin()->GetRender()->MeasureText( pFont, strNewString + lst[i] );

		if ( WordSize.x > iSpaceLeft )
		{
			CreateLabel( strNewString, txt, x, y, lineheight, true );
			x = 0;
			y += lineheight;
			break;;
		}

		strNewString += lst[i];
	}

	Gwen::UnicodeString LeftOver = text.substr( strNewString.size() + 1 );
	return SplitLabel( LeftOver, pFont, txt, x, y, lineheight );
}

void RichLabel::CreateLabel( const Gwen::UnicodeString & text, const DividedText & txt, int & x, int & y, int & lineheight, bool NoSplit )
{
	//
	// Use default font or is one set?
	//
	Gwen::Font* pFont = GetSkin()->GetDefaultFont();

	if ( txt.font ) { pFont = txt.font; }

	//
	// This string is too long for us, split it up.
	//
	Gwen::Point p = GetSkin()->GetRender()->MeasureText( pFont, text );

	if ( lineheight == -1 )
	{
		lineheight = p.y;
	}

	if ( !NoSplit )
	{
		if ( x + p.x > Width() )
		{
			return SplitLabel( text, pFont, txt, x, y, lineheight );
		}
	}

	//
	// Wrap
	//
	if ( x + p.x >= Width() )
	{
		CreateNewline( x, y, lineheight );
	}

	Gwen::Controls::Label*	pLabel = new Gwen::Controls::Label( this );
	pLabel->SetText( x == 0 ? Gwen::Utility::Strings::TrimLeft<Gwen::UnicodeString> ( text, L" " ) : text );
	pLabel->SetTextColor( txt.color );
	pLabel->SetFont( pFont );
	pLabel->SizeToContents();
	pLabel->SetPos( x, y );
	//lineheight = (lineheight + pLabel->Height()) / 2;
	x += pLabel->Width();

	if ( x >= Width() )
	{
		CreateNewline( x, y, lineheight );
	}
}

void RichLabel::CreateNewline( int & x, int & y, int & lineheight )
{
	x = 0;
	y += lineheight;
}

void RichLabel::Rebuild()
{
	RemoveAllChildren();
	int x = 0;
	int y = 0;
	int lineheight = -1;

	for ( DividedText::List::iterator it = m_TextBlocks.begin(); it != m_TextBlocks.end(); ++it )
	{
		if ( it->type == Type_Newline )
		{
			CreateNewline( x, y, lineheight );
			continue;
		}

		if ( it->type == Type_Text )
		{
			CreateLabel( ( *it ).text, *it, x, y, lineheight, false );
			continue;
		}
	}

	m_bNeedsRebuild = false;
}

void RichLabel::OnBoundsChanged( Gwen::Rect oldBounds )
{
	BaseClass::OnBoundsChanged( oldBounds );
	Rebuild();
}

void RichLabel::Layout( Gwen::Skin::Base* skin )
{
	BaseClass::Layout( skin );

	if ( m_bNeedsRebuild )
	{
		Rebuild();
	}
}<commit_msg>Fix: throw of an uncontrolled std::out_of_range exception<commit_after>/*
	GWEN
	Copyright (c) 2010 Facepunch Studios
	See license in Gwen.h
*/

#include "Gwen/Gwen.h"
#include "Gwen/Controls/RichLabel.h"
#include "Gwen/Controls/Label.h"
#include "Gwen/Utility.h"

using namespace Gwen;
using namespace Gwen::Controls;

const unsigned char Type_Text = 0;
const unsigned char Type_Newline = 1;

GWEN_CONTROL_CONSTRUCTOR( RichLabel )
{
	m_bNeedsRebuild = false;
}

void RichLabel::AddLineBreak()
{
	DividedText t;
	t.type = Type_Newline;
	m_TextBlocks.push_back( t );
}

void RichLabel::AddText( const Gwen::TextObject & text, Gwen::Color color, Gwen::Font* font )
{
	if ( text.length() == 0 ) { return; }

	Gwen::Utility::Strings::UnicodeList lst;
	Gwen::Utility::Strings::Split( text.GetUnicode(), L"\n", lst, false );

	for ( size_t i = 0; i < lst.size(); i++ )
	{
		if ( i > 0 ) { AddLineBreak(); }

		DividedText t;
		t.type = Type_Text;
		t.text = lst[i];
		t.color = color;
		t.font = font;
		m_TextBlocks.push_back( t );
		m_bNeedsRebuild = true;
		Invalidate();
	}
}

bool RichLabel::SizeToChildren( bool w, bool h )
{
	Rebuild();
	return BaseClass::SizeToChildren( w, h );
}

void RichLabel::SplitLabel( const Gwen::UnicodeString & text, Gwen::Font* pFont, const DividedText & txt, int & x, int & y, int & lineheight )
{
	Gwen::Utility::Strings::UnicodeList lst;
	Gwen::Utility::Strings::Split( text, L" ", lst, true );

	if ( lst.size() == 0 ) { return; }

	int iSpaceLeft = Width() - x;
	// Does the whole word fit in?
	{
		Gwen::Point StringSize = GetSkin()->GetRender()->MeasureText( pFont, text );

		if ( iSpaceLeft > StringSize.x )
		{
			return CreateLabel( text, txt, x, y, lineheight, true );
		}
	}
	// If the first word is bigger than the line, just give up.
	{
		Gwen::Point WordSize = GetSkin()->GetRender()->MeasureText( pFont, lst[0] );

		if ( WordSize.x >= iSpaceLeft )
		{
			CreateLabel( lst[0], txt, x, y, lineheight, true );

			if ( lst[0].size() >= text.size() ) { return; }

			Gwen::UnicodeString LeftOver = text.substr( lst[0].size() + 1 );
			return SplitLabel( LeftOver, pFont, txt, x, y, lineheight );
		}
	}
	Gwen::UnicodeString strNewString = L"";

	for ( size_t i = 0; i < lst.size(); i++ )
	{
		Gwen::Point WordSize = GetSkin()->GetRender()->MeasureText( pFont, strNewString + lst[i] );

		if ( WordSize.x > iSpaceLeft )
		{
			CreateLabel( strNewString, txt, x, y, lineheight, true );
			x = 0;
			y += lineheight;
			break;;
		}

		strNewString += lst[i];
	}

	if ( strNewString.size() >= text.size() ) return;
	Gwen::UnicodeString LeftOver = text.substr( strNewString.size() + 1 );
	return SplitLabel( LeftOver, pFont, txt, x, y, lineheight );
}

void RichLabel::CreateLabel( const Gwen::UnicodeString & text, const DividedText & txt, int & x, int & y, int & lineheight, bool NoSplit )
{
	//
	// Use default font or is one set?
	//
	Gwen::Font* pFont = GetSkin()->GetDefaultFont();

	if ( txt.font ) { pFont = txt.font; }

	//
	// This string is too long for us, split it up.
	//
	Gwen::Point p = GetSkin()->GetRender()->MeasureText( pFont, text );

	if ( lineheight == -1 )
	{
		lineheight = p.y;
	}

	if ( !NoSplit )
	{
		if ( x + p.x > Width() )
		{
			return SplitLabel( text, pFont, txt, x, y, lineheight );
		}
	}

	//
	// Wrap
	//
	if ( x + p.x >= Width() )
	{
		CreateNewline( x, y, lineheight );
	}

	Gwen::Controls::Label*	pLabel = new Gwen::Controls::Label( this );
	pLabel->SetText( x == 0 ? Gwen::Utility::Strings::TrimLeft<Gwen::UnicodeString> ( text, L" " ) : text );
	pLabel->SetTextColor( txt.color );
	pLabel->SetFont( pFont );
	pLabel->SizeToContents();
	pLabel->SetPos( x, y );
	//lineheight = (lineheight + pLabel->Height()) / 2;
	x += pLabel->Width();

	if ( x >= Width() )
	{
		CreateNewline( x, y, lineheight );
	}
}

void RichLabel::CreateNewline( int & x, int & y, int & lineheight )
{
	x = 0;
	y += lineheight;
}

void RichLabel::Rebuild()
{
	RemoveAllChildren();
	int x = 0;
	int y = 0;
	int lineheight = -1;

	for ( DividedText::List::iterator it = m_TextBlocks.begin(); it != m_TextBlocks.end(); ++it )
	{
		if ( it->type == Type_Newline )
		{
			CreateNewline( x, y, lineheight );
			continue;
		}

		if ( it->type == Type_Text )
		{
			CreateLabel( ( *it ).text, *it, x, y, lineheight, false );
			continue;
		}
	}

	m_bNeedsRebuild = false;
}

void RichLabel::OnBoundsChanged( Gwen::Rect oldBounds )
{
	BaseClass::OnBoundsChanged( oldBounds );
	Rebuild();
}

void RichLabel::Layout( Gwen::Skin::Base* skin )
{
	BaseClass::Layout( skin );

	if ( m_bNeedsRebuild )
	{
		Rebuild();
	}
}<|endoftext|>


<commit_before>#include "c_util_img.h"

#include <fstream>
#include <iostream>
#include <stdint.h>
#include <stdlib.h>
#include <math.h>

/* GRAYSCALE */
#define RGB2GRAY_IN_INT

#ifdef RGB2GRAY_IN_INT
// #define RATE_SHIFT 24
// #define R_RATE (uint32_t)(0.298912F * (float)(1<<RATE_SHIFT))
// #define G_RATE (uint32_t)(0.586611F * (float)(1<<RATE_SHIFT))
// #define B_RATE (uint32_t)(0.114478F * (float)(1<<RATE_SHIFT))
// the following are OpenCV's numbers
#define RATE_SHIFT 14
#define R_RATE (uint32_t)4899
#define G_RATE (uint32_t)9617
#define B_RATE (uint32_t)1868
#else
#define R_RATE 0.298912f
#define G_RATE 0.586611f
#define B_RATE 0.114478f
#endif

using namespace std;

/*************************************/
/* @namespace Comment                */
/* @brief Comment crusher            */
/*************************************/
namespace Comment {
    static class _comment {
    } cmnt;
    inline std::istream& operator>>(std::istream& is, _comment & manip) {
        char c;
        char b[1024];
        is >> c;
        if (c != '#')
            return is.putback(c);
        is.getline(b, 1024);
        return is;
    }
}

/**
 * BEMAP Utility for finding an input file
 * Finding process iterates on the given folder:

 "./",
 "common/data/",
 "../common/data/",
 "../../common/data/",
 "../../../common/data/",
 "../../../../common/data/"

 *
 * @param filename
 *
 * @return bool Return TRUE if file found, FALSE if not found
 */

bool find_file(std::string & filename)
{
    /* try to open the given file first */
    std::fstream tryin(filename.c_str(), std::ios_base::in | std::ios_base::binary);
    if (tryin.good()) {
        return true;
    }

    const char* search_path[] = {
        "./",
        "common/data/",
        "../common/data/",
        "../../common/data/",
        "../../../common/data/",
        "../../../../common/data/"
    };

    /* extract file name first */
    std::string prefix = "";
    std::string realname = "";

    realname = extract_filename(filename, prefix);
    realname += prefix;

    std::cerr << "File not found: " << realname << std::endl;
    std::cerr << "find_file is trying to search " << realname << " in another path..\n";

    if (filename != "") {
        for (int i = 0; i < sizeof(search_path)/sizeof(char *); i++) {
            std::string path(search_path[i]);
            path.append(realname);

            std::fstream trying(path.c_str(), std::ios_base::in | std::ios_base::binary);
            if (trying.good()) {
                /* file found, return this */
                std::cerr << path << " found. Proceed to execute with this.\n";
                filename = path;
                return true;
            }
        }
    }

    return false;
}

/**
 * @brief Take an image input, PGM or PPM format, and then
 *        save it into the imgStream buffer
 *
 * @param filename
 * @param buffer
 * @param isPGM
 */

void read_pgpm(std::string & filename, imgStream & buffer, int &isPGM)
{
    if (!find_file(filename)) {
        std::cerr << "ERROR: " << "Cannot open file: " << filename << std::endl;
        exit(1);
    }

    std::fstream in(filename.c_str(),
                    std::ios_base::in | std::ios_base::binary);

    pixel_uc *ptr_r = NULL;
    pixel_uc *ptr_g = NULL;
    pixel_uc *ptr_b = NULL;
    int width, height, maxval;
    char c;
    bool isAscii = false;

    in >> c;
    if (c != 'P') {
        std::cerr << "ERROR: " << "The file is not PGM/PPM format" << std::endl;
        exit(1);
    }

    in >> c;
    switch (c) {
    case '2':
        isAscii = true;
    case '5':
        isPGM = true;
        break;
    case '6':
        isPGM = false;
        break;
    default:
        std::cerr << "ERROR: " << "The file is not PGM/PPM format" << std::endl;
        exit(1);
    }

    in >> Comment::cmnt
       >> width >> Comment::cmnt >> height >> Comment::cmnt >> maxval;

    /* get trash */
    {
        char trash;
        in.get(trash);
    }

    if (maxval > 255) {
        std::cerr << "ERROR: " << "Only 8bit color channel is supported" << std::endl;
        exit(1);
    }
    if (!in.good()) {
        std::cerr << "ERROR: " << "PGM header parsing error" << std::endl;
        exit(1);
    }

    if (isPGM && isAscii) {     // PGM P2 image
        ptr_r = new pixel_uc[width * height];
        pixel_uc *start = ptr_r;
        pixel_uc *end;
        end = start + width * height;

        while (start != end) {
            int i;
            in >> i;
            if (!in.good() || i > maxval) {
                std::cerr << "ERROR: " << "PGM parsing error: " << filename << std::endl
                          << "at pixel: " << start - ptr_r << std::endl;
                exit(1);
            }
            *start++ = pixel_uc(i);
        }
    }

    else if (isPGM && !isAscii) {       // PGM P5 image
        ptr_r = new pixel_uc[width * height];
        pixel_uc *start = ptr_r;
        pixel_uc *end = start + width * height;

        std::streampos beg = in.tellg();
        char *buffer = new char[width * height];
        in.read(buffer, width * height);
        if (!in.good()) {
            std::cerr << "ERROR:"  << "PGM parsing error: " << filename << std::endl
                      << "at pixel: " << start - ptr_r << std::endl;
            exit(1);
        }

        while (start != end)
            *start++ = (pixel_uc) (*buffer++);
    } else if (!isPGM && !isAscii) {    // PPM P6 image
        ptr_r = new pixel_uc[width * height];
        ptr_g = new pixel_uc[width * height];
        ptr_b = new pixel_uc[width * height];
        pixel_uc *start_r = ptr_r;
        pixel_uc *start_g = ptr_g;
        pixel_uc *start_b = ptr_b;
        pixel_uc *end = start_r + width * height;

        std::streampos beg = in.tellg();
        char *buffer = new char[width * height * 3];
        in.read(buffer, width * height * 3);
        if (!in.good()) {
            std::cerr << "ERROR:" << "PGM parsing error: " << filename << std::endl
                      << "at pixel: " << start_r - ptr_r << std::endl;
            exit(1);
        }

        pixel_uc *src = reinterpret_cast < pixel_uc * >(buffer);
        while (start_r != end) {
            *start_r++ = *src++;
            *start_g++ = *src++;
            *start_b++ = *src++;
        }
    } else {
        std::cerr << "ERROR: Unknown parsing mode\n" << std::endl;
        exit(1);
    }

    buffer.width = width;
    buffer.height = height;
    buffer.data_r = ptr_r;
    buffer.data_g = (!isPGM) ? ptr_g : NULL;
    buffer.data_b = (!isPGM) ? ptr_b : NULL;
}

void read_gray(std::string & filename, imgStream & buffer)
{
    // cerr << "Entering " << __FUNCTION__ << endl;
    // cerr << "   filename " << filename << endl;

    bool isPGM;

    if (!find_file(filename)) {
        std::cerr << "ERROR: " << "Cannot open file: " << filename << std::endl;
        exit(1);
    }

    std::fstream in(filename.c_str(),
                    std::ios_base::in | std::ios_base::binary);

    pixel_uc *ptr_r = NULL;
    int width, height, maxval;
    char c;
    bool isAscii = false;

    in >> c;
    if (c != 'P') {
        std::cerr << "ERROR: " << "The file is not PGM/PPM format" << std::endl;
        exit(1);
    }

    in >> c;
    switch (c) {
    case '2':
        isAscii = true;
    case '5':
        isPGM = true;
        break;
    case '6':
        // cerr << "    File is in PPM format" << endl;
        isPGM = false;
        break;
    default:
        std::cerr << "ERROR: " << "The file is not PGM/PPM format" << std::endl;
        exit(1);
    }

    in >> Comment::cmnt
       >> width >> Comment::cmnt >> height >> Comment::cmnt >> maxval;

    /* get trash */
    {
        char trash;
        in.get(trash);
    }

    if (maxval > 255) {
        std::cerr << "ERROR: " << "Only 8bit color channel is supported" << std::endl;
        exit(1);
    }
    if (!in.good()) {
        std::cerr << "ERROR: " << "PGM header parsing error" << std::endl;
        exit(1);
    }

    if( isPGM ) {
      if( isAscii ) { // PGM P2 image
        ptr_r = new pixel_uc[width * height];
        pixel_uc *start = ptr_r;
        pixel_uc *end;
        end = start + width * height;

        while (start != end) {
            int i;
            in >> i;
            if (!in.good() || i > maxval) {
                std::cerr << "ERROR: " << "PGM parsing error: " << filename << std::endl
                          << "at pixel: " << start - ptr_r << std::endl;
                exit(1);
            }
            *start++ = pixel_uc(i);
        }
      } else {
        ptr_r = new pixel_uc[width * height];
        pixel_uc *start = ptr_r;
        pixel_uc *end = start + width * height;

        std::streampos beg = in.tellg();
        char *buffer = new char[width * height];
        in.read(buffer, width * height);
        if (!in.good()) {
            std::cerr << "ERROR:"  << "PGM parsing error: " << filename << std::endl
                      << "at pixel: " << start - ptr_r << std::endl;
            exit(1);
        }

        while (start != end)
            *start++ = (pixel_uc) (*buffer++);
      }
    } else {
      // cerr << "    NOT PGM case" << endl;
      if( not isAscii ) {    // PPM P6 image
        ptr_r = new pixel_uc[width * height];

        std::streampos beg = in.tellg();
        char *buffer = new char[width * height * 3];
        in.read(buffer, width * height * 3);
        if (!in.good()) {
            std::cerr << "ERROR:" << "PGM parsing error: " << filename << std::endl;
            exit(1);
        }

        pixel_uc *src = reinterpret_cast < pixel_uc * >(buffer);
        for( int i=0; i<width * height; i++ ) {
#ifdef RGB2GRAY_IN_INT
            uint32_t r = *src; src++;
            uint32_t g = *src; src++;
            uint32_t b = *src; src++;
            uint32_t res = ( ( R_RATE*r+G_RATE*g+B_RATE*b ) >> RATE_SHIFT );
            ptr_r[i] = (unsigned char)res;
#else // RGB2GRAY_IN_INT
            float r =(*src; src++;
            float g = *src; src++;
            float b = *src; src++;
            ptr_r[i] = (unsigned char)( R_RATE*r+G_RATE*g+B_RATE*b );
#endif // RGB2GRAY_IN_INT
    // cerr << "(" << i%width << "," << i/width << ") -> R " << r << " G " << g << " B " << b << " -> " << (int)ptr_r[i] << endl;
// if( i == 19*width+3 ) {
    // cerr << "(3,19) -> R " << r << " G " << g << " B " << b << " -> " << (int)ptr_r[i] << endl;
// }
        }
      } else {
        std::cerr << "ERROR: Unknown parsing mode\n" << std::endl;
        exit(1);
      }
    }

    buffer.width  = width;
    buffer.height = height;
    buffer.data_r = ptr_r;
    buffer.data_g = 0;
    buffer.data_b = 0;

    // cerr << "Leaving " << __FUNCTION__ << endl;
}

/**
 * @brief Output image in PGM or PPM format
 *
 * @param filename
 * @param buffer
 * @param isPGM
 */

void out_pgpm(const std::string & filename, imgStream & buffer, int &isPGM)
{
    int x, y;
    pixel_uc r, g, b;

    int width = buffer.width;
    int height = buffer.height;
    pixel_uc *ptr_r = buffer.data_r;
    pixel_uc *ptr_g = buffer.data_g;
    pixel_uc *ptr_b = buffer.data_b;

    std::fstream out(filename.c_str(),
                     std::ios_base::out | std::ios_base::binary);
    if (!out.good()) {
        std::cerr << "ERROR: " << "Cannot open file: " << filename << std::endl;
        exit(1);
    }

    if (isPGM) {
        out << "P5" << "\n"
            << width << " " << height << "\n" << "255" << "\n";

        for (y = 0; y < height; ++y) {
            for (x = 0; x < width; ++x) {
                r = (pixel_uc) * ptr_r++;
                out << r;
            }
        }
    } else {
        out << "P6" << "\n"
            << width << " " << height << "\n" << "255" << "\n";

        for (y = 0; y < height; ++y) {
            for (x = 0; x < width; ++x) {
                r = (pixel_uc) * ptr_r++;
                g = (pixel_uc) * ptr_g++;
                b = (pixel_uc) * ptr_b++;
                out << r << g << b;
            }
        }
    }
}

<commit_msg>improved comment crusher for reading PGM<commit_after>#include "c_util_img.h"

#include <fstream>
#include <iostream>
#include <stdint.h>
#include <stdlib.h>
#include <math.h>

/* GRAYSCALE */
#define RGB2GRAY_IN_INT

#ifdef RGB2GRAY_IN_INT
// #define RATE_SHIFT 24
// #define R_RATE (uint32_t)(0.298912F * (float)(1<<RATE_SHIFT))
// #define G_RATE (uint32_t)(0.586611F * (float)(1<<RATE_SHIFT))
// #define B_RATE (uint32_t)(0.114478F * (float)(1<<RATE_SHIFT))
// the following are OpenCV's numbers
#define RATE_SHIFT 14
#define R_RATE (uint32_t)4899
#define G_RATE (uint32_t)9617
#define B_RATE (uint32_t)1868
#else
#define R_RATE 0.298912f
#define G_RATE 0.586611f
#define B_RATE 0.114478f
#endif

using namespace std;

/*************************************/
/* @namespace Comment                */
/* @brief Comment crusher            */
/*************************************/
namespace Comment {
    static class _comment {
    } cmnt;
    inline std::istream& operator>>(std::istream& is, _comment & manip) {
        char c;
        char b[1024];
        while( is.good() )
        {
            is >> c;
            if (c != '#')
                return is.putback(c);
            is.getline(b, 1024);
        }
        return is;
    }
}

/**
 * BEMAP Utility for finding an input file
 * Finding process iterates on the given folder:

 "./",
 "common/data/",
 "../common/data/",
 "../../common/data/",
 "../../../common/data/",
 "../../../../common/data/"

 *
 * @param filename
 *
 * @return bool Return TRUE if file found, FALSE if not found
 */

bool find_file(std::string & filename)
{
    /* try to open the given file first */
    std::fstream tryin(filename.c_str(), std::ios_base::in | std::ios_base::binary);
    if (tryin.good()) {
        return true;
    }

    const char* search_path[] = {
        "./",
        "common/data/",
        "../common/data/",
        "../../common/data/",
        "../../../common/data/",
        "../../../../common/data/"
    };

    /* extract file name first */
    std::string prefix = "";
    std::string realname = "";

    realname = extract_filename(filename, prefix);
    realname += prefix;

    std::cerr << "File not found: " << realname << std::endl;
    std::cerr << "find_file is trying to search " << realname << " in another path..\n";

    if (filename != "") {
        for (int i = 0; i < sizeof(search_path)/sizeof(char *); i++) {
            std::string path(search_path[i]);
            path.append(realname);

            std::fstream trying(path.c_str(), std::ios_base::in | std::ios_base::binary);
            if (trying.good()) {
                /* file found, return this */
                std::cerr << path << " found. Proceed to execute with this.\n";
                filename = path;
                return true;
            }
        }
    }

    return false;
}

/**
 * @brief Take an image input, PGM or PPM format, and then
 *        save it into the imgStream buffer
 *
 * @param filename
 * @param buffer
 * @param isPGM
 */

void read_pgpm(std::string & filename, imgStream & buffer, int &isPGM)
{
    if (!find_file(filename)) {
        std::cerr << "ERROR: " << "Cannot open file: " << filename << std::endl;
        exit(1);
    }

    std::fstream in(filename.c_str(),
                    std::ios_base::in | std::ios_base::binary);

    pixel_uc *ptr_r = NULL;
    pixel_uc *ptr_g = NULL;
    pixel_uc *ptr_b = NULL;
    int width, height, maxval;
    char c;
    bool isAscii = false;

    in >> c;
    if (c != 'P') {
        std::cerr << "ERROR: " << "The file is not PGM/PPM format" << std::endl;
        exit(1);
    }

    in >> c;
    switch (c) {
    case '2':
        isAscii = true;
    case '5':
        isPGM = true;
        break;
    case '6':
        isPGM = false;
        break;
    default:
        std::cerr << "ERROR: " << "The file is not PGM/PPM format" << std::endl;
        exit(1);
    }

    in >> Comment::cmnt
       >> width >> Comment::cmnt >> height >> Comment::cmnt >> maxval;

    /* get trash */
    {
        char trash;
        in.get(trash);
    }

    if (maxval > 255) {
        std::cerr << "ERROR: " << "Only 8bit color channel is supported" << std::endl;
        exit(1);
    }
    if (!in.good()) {
        std::cerr << "ERROR: " << "PGM header parsing error" << std::endl;
        exit(1);
    }

    if (isPGM && isAscii) {     // PGM P2 image
        ptr_r = new pixel_uc[width * height];
        pixel_uc *start = ptr_r;
        pixel_uc *end;
        end = start + width * height;

        while (start != end) {
            int i;
            in >> i;
            if (!in.good() || i > maxval) {
                std::cerr << "ERROR: " << "PGM parsing error: " << filename << std::endl
                          << "at pixel: " << start - ptr_r << std::endl;
                exit(1);
            }
            *start++ = pixel_uc(i);
        }
    }

    else if (isPGM && !isAscii) {       // PGM P5 image
        ptr_r = new pixel_uc[width * height];
        pixel_uc *start = ptr_r;
        pixel_uc *end = start + width * height;

        std::streampos beg = in.tellg();
        char *buffer = new char[width * height];
        in.read(buffer, width * height);
        if (!in.good()) {
            std::cerr << "ERROR:"  << "PGM parsing error: " << filename << std::endl
                      << "at pixel: " << start - ptr_r << std::endl;
            exit(1);
        }

        while (start != end)
            *start++ = (pixel_uc) (*buffer++);
    } else if (!isPGM && !isAscii) {    // PPM P6 image
        ptr_r = new pixel_uc[width * height];
        ptr_g = new pixel_uc[width * height];
        ptr_b = new pixel_uc[width * height];
        pixel_uc *start_r = ptr_r;
        pixel_uc *start_g = ptr_g;
        pixel_uc *start_b = ptr_b;
        pixel_uc *end = start_r + width * height;

        std::streampos beg = in.tellg();
        char *buffer = new char[width * height * 3];
        in.read(buffer, width * height * 3);
        if (!in.good()) {
            std::cerr << "ERROR:" << "PGM parsing error: " << filename << std::endl
                      << "at pixel: " << start_r - ptr_r << std::endl;
            exit(1);
        }

        pixel_uc *src = reinterpret_cast < pixel_uc * >(buffer);
        while (start_r != end) {
            *start_r++ = *src++;
            *start_g++ = *src++;
            *start_b++ = *src++;
        }
    } else {
        std::cerr << "ERROR: Unknown parsing mode\n" << std::endl;
        exit(1);
    }

    buffer.width = width;
    buffer.height = height;
    buffer.data_r = ptr_r;
    buffer.data_g = (!isPGM) ? ptr_g : NULL;
    buffer.data_b = (!isPGM) ? ptr_b : NULL;
}

void read_gray(std::string & filename, imgStream & buffer)
{
    // cerr << "Entering " << __FUNCTION__ << endl;
    // cerr << "   filename " << filename << endl;

    bool isPGM;

    if (!find_file(filename)) {
        std::cerr << "ERROR: " << "Cannot open file: " << filename << std::endl;
        exit(1);
    }

    std::fstream in(filename.c_str(),
                    std::ios_base::in | std::ios_base::binary);

    pixel_uc *ptr_r = NULL;
    int width, height, maxval;
    char c;
    bool isAscii = false;

    in >> c;
    if (c != 'P') {
        std::cerr << "ERROR: " << "The file is not PGM/PPM format" << std::endl;
        exit(1);
    }

    in >> c;
    switch (c) {
    case '2':
        isAscii = true;
    case '5':
        isPGM = true;
        break;
    case '6':
        // cerr << "    File is in PPM format" << endl;
        isPGM = false;
        break;
    default:
        std::cerr << "ERROR: " << "The file is not PGM/PPM format" << std::endl;
        exit(1);
    }

    in >> Comment::cmnt
       >> width >> Comment::cmnt >> height >> Comment::cmnt >> maxval;

    /* get trash */
    {
        char trash;
        in.get(trash);
    }

    if (maxval > 255) {
        std::cerr << "ERROR: " << "Only 8bit color channel is supported" << std::endl;
        exit(1);
    }
    if (!in.good()) {
        std::cerr << "ERROR: " << "PGM header parsing error" << std::endl;
        exit(1);
    }

    if( isPGM ) {
      if( isAscii ) { // PGM P2 image
        ptr_r = new pixel_uc[width * height];
        pixel_uc *start = ptr_r;
        pixel_uc *end;
        end = start + width * height;

        while (start != end) {
            int i;
            in >> i;
            if (!in.good() || i > maxval) {
                std::cerr << "ERROR: " << "PGM parsing error: " << filename << std::endl
                          << "at pixel: " << start - ptr_r << std::endl;
                exit(1);
            }
            *start++ = pixel_uc(i);
        }
      } else {
        ptr_r = new pixel_uc[width * height];
        pixel_uc *start = ptr_r;
        pixel_uc *end = start + width * height;

        std::streampos beg = in.tellg();
        char *buffer = new char[width * height];
        in.read(buffer, width * height);
        if (!in.good()) {
            std::cerr << "ERROR:"  << "PGM parsing error: " << filename << std::endl
                      << "at pixel: " << start - ptr_r << std::endl;
            exit(1);
        }

        while (start != end)
            *start++ = (pixel_uc) (*buffer++);
      }
    } else {
      // cerr << "    NOT PGM case" << endl;
      if( not isAscii ) {    // PPM P6 image
        ptr_r = new pixel_uc[width * height];

        std::streampos beg = in.tellg();
        char *buffer = new char[width * height * 3];
        in.read(buffer, width * height * 3);
        if (!in.good()) {
            std::cerr << "ERROR:" << "PGM parsing error: " << filename << std::endl;
            exit(1);
        }

        pixel_uc *src = reinterpret_cast < pixel_uc * >(buffer);
        for( int i=0; i<width * height; i++ ) {
#ifdef RGB2GRAY_IN_INT
            uint32_t r = *src; src++;
            uint32_t g = *src; src++;
            uint32_t b = *src; src++;
            uint32_t res = ( ( R_RATE*r+G_RATE*g+B_RATE*b ) >> RATE_SHIFT );
            ptr_r[i] = (unsigned char)res;
#else // RGB2GRAY_IN_INT
            float r =(*src; src++;
            float g = *src; src++;
            float b = *src; src++;
            ptr_r[i] = (unsigned char)( R_RATE*r+G_RATE*g+B_RATE*b );
#endif // RGB2GRAY_IN_INT
    // cerr << "(" << i%width << "," << i/width << ") -> R " << r << " G " << g << " B " << b << " -> " << (int)ptr_r[i] << endl;
// if( i == 19*width+3 ) {
    // cerr << "(3,19) -> R " << r << " G " << g << " B " << b << " -> " << (int)ptr_r[i] << endl;
// }
        }
      } else {
        std::cerr << "ERROR: Unknown parsing mode\n" << std::endl;
        exit(1);
      }
    }

    buffer.width  = width;
    buffer.height = height;
    buffer.data_r = ptr_r;
    buffer.data_g = 0;
    buffer.data_b = 0;

    // cerr << "Leaving " << __FUNCTION__ << endl;
}

/**
 * @brief Output image in PGM or PPM format
 *
 * @param filename
 * @param buffer
 * @param isPGM
 */

void out_pgpm(const std::string & filename, imgStream & buffer, int &isPGM)
{
    int x, y;
    pixel_uc r, g, b;

    int width = buffer.width;
    int height = buffer.height;
    pixel_uc *ptr_r = buffer.data_r;
    pixel_uc *ptr_g = buffer.data_g;
    pixel_uc *ptr_b = buffer.data_b;

    std::fstream out(filename.c_str(),
                     std::ios_base::out | std::ios_base::binary);
    if (!out.good()) {
        std::cerr << "ERROR: " << "Cannot open file: " << filename << std::endl;
        exit(1);
    }

    if (isPGM) {
        out << "P5" << "\n"
            << width << " " << height << "\n" << "255" << "\n";

        for (y = 0; y < height; ++y) {
            for (x = 0; x < width; ++x) {
                r = (pixel_uc) * ptr_r++;
                out << r;
            }
        }
    } else {
        out << "P6" << "\n"
            << width << " " << height << "\n" << "255" << "\n";

        for (y = 0; y < height; ++y) {
            for (x = 0; x < width; ++x) {
                r = (pixel_uc) * ptr_r++;
                g = (pixel_uc) * ptr_g++;
                b = (pixel_uc) * ptr_b++;
                out << r << g << b;
            }
        }
    }
}

<|endoftext|>


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

#include "common/validation.hpp"

#include <algorithm>
#include <cctype>

#include <stout/foreach.hpp>
#include <stout/unreachable.hpp>

#include <stout/os/constants.hpp>

using std::string;

namespace mesos {
namespace internal {
namespace common {
namespace validation {

Option<Error> validateID(const string& id)
{
  if (id.empty()) {
    return Error("ID must not be empty");
  }

  // The ID cannot be exactly these special path components.
  if (id == "." || id == "..") {
    return Error("'" + id + "' is disallowed");
  }

  // Rules on invalid characters in the ID:
  // - Control charaters are obviously not allowed.
  // - Slashes are disallowed as IDs are likely mapped to directories in Mesos.
  auto invalidCharacter = [](char c) {
    return iscntrl(c) ||
           c == os::POSIX_PATH_SEPARATOR ||
           c == os::WINDOWS_PATH_SEPARATOR;
  };

  if (std::any_of(id.begin(), id.end(), invalidCharacter)) {
    return Error("'" + id + "' contains invalid characters");
  }

  return None();
}

// These IDs are valid as long as they meet the common ID requirements
// enforced by `validateID()` but we define each of them separately to
// be clear which IDs are subject to which rules.
Option<Error> validateTaskID(const TaskID& taskId)
{
  return validateID(taskId.value());
}

Option<Error> validateExecutorID(const ExecutorID& executorId)
{
  return validateID(executorId.value());
}

Option<Error> validateSlaveID(const SlaveID& slaveId)
{
  return validateID(slaveId.value());
}

Option<Error> validateFrameworkID(const FrameworkID& frameworkId)
{
  return validateID(frameworkId.value());
}

Option<Error> validateSecret(const Secret& secret)
{
  switch (secret.type()) {
    case Secret::REFERENCE:
      if (!secret.has_reference()) {
        return Error(
            "Secret of type REFERENCE must have the 'reference' field set");
      }

      if (secret.has_value()) {
        return Error(
            "Secret '" + secret.reference().name() + "' of type REFERENCE "
            "must not have the 'value' field set");
      }
      break;

    case Secret::VALUE:
      if (!secret.has_value()) {
        return Error("Secret of type VALUE must have the 'value' field set");
      }

      if (secret.has_reference()) {
        return Error(
            "Secret of type VALUE must not have the 'reference' field set");
      }
      break;

    case Secret::UNKNOWN:
      break;

    UNREACHABLE();
  }

  return None();
}

Option<Error> validateEnvironment(const Environment& environment)
{
  foreach (const Environment::Variable& variable, environment.variables()) {
    switch (variable.type()) {
      case Environment::Variable::SECRET: {
        if (!variable.has_secret()) {
          return Error(
              "Environment variable '" + variable.name() +
              "' of type 'SECRET' must have a secret set");
        }

        if (variable.has_value()) {
          return Error(
              "Environment variable '" + variable.name() +
              "' of type 'SECRET' must not have a value set");
        }

        Option<Error> error = validateSecret(variable.secret());
        if (error.isSome()) {
          return Error(
              "Environment variable '" + variable.name() + "' specifies an "
              "invalid secret: " + error->message);
        }

        if (variable.secret().value().data().find('\0') != string::npos) {
            return Error(
                "Environment variable '" + variable.name() + "' specifies a "
                "secret containing null bytes, which is not allowed in the "
                "environment");
        }
        break;
      }

      // NOTE: If new variable types are added in the future and an upgraded
      // client/master sends a new type to an older master/agent, the older
      // master/agent will see VALUE instead of the new type, since VALUE is set
      // as the default type in the protobuf definition.
      case Environment::Variable::VALUE:
        if (!variable.has_value()) {
          return Error(
              "Environment variable '" + variable.name() +
              "' of type 'VALUE' must have a value set");
        }

        if (variable.has_secret()) {
          return Error(
              "Environment variable '" + variable.name() +
              "' of type 'VALUE' must not have a secret set");
        }
        break;

      case Environment::Variable::UNKNOWN:
          return Error("Environment variable of type 'UNKNOWN' is not allowed");

      UNREACHABLE();
    }
  }

  return None();
}

// TODO(greggomann): Do more than just validate the `Environment`.
Option<Error> validateCommandInfo(const CommandInfo& command)
{
  return validateEnvironment(command.environment());
}

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

#include "common/validation.hpp"

#include <limits.h>

#include <algorithm>
#include <cctype>

#include <stout/foreach.hpp>
#include <stout/stringify.hpp>
#include <stout/unreachable.hpp>

#include <stout/os/constants.hpp>

using std::string;

namespace mesos {
namespace internal {
namespace common {
namespace validation {

Option<Error> validateID(const string& id)
{
  if (id.empty()) {
    return Error("ID must not be empty");
  }

  if (id.length() > NAME_MAX) {
    return Error(
        "ID must not be greater than " +
        stringify(NAME_MAX) + " characters");
  }

  // The ID cannot be exactly these special path components.
  if (id == "." || id == "..") {
    return Error("'" + id + "' is disallowed");
  }

  // Rules on invalid characters in the ID:
  // - Control characters are obviously not allowed.
  // - Slashes are disallowed as IDs are likely mapped to directories in Mesos.
  auto invalidCharacter = [](char c) {
    return iscntrl(c) ||
           c == os::POSIX_PATH_SEPARATOR ||
           c == os::WINDOWS_PATH_SEPARATOR;
  };

  if (std::any_of(id.begin(), id.end(), invalidCharacter)) {
    return Error("'" + id + "' contains invalid characters");
  }

  return None();
}

// These IDs are valid as long as they meet the common ID requirements
// enforced by `validateID()` but we define each of them separately to
// be clear which IDs are subject to which rules.
Option<Error> validateTaskID(const TaskID& taskId)
{
  return validateID(taskId.value());
}

Option<Error> validateExecutorID(const ExecutorID& executorId)
{
  return validateID(executorId.value());
}

Option<Error> validateSlaveID(const SlaveID& slaveId)
{
  return validateID(slaveId.value());
}

Option<Error> validateFrameworkID(const FrameworkID& frameworkId)
{
  return validateID(frameworkId.value());
}

Option<Error> validateSecret(const Secret& secret)
{
  switch (secret.type()) {
    case Secret::REFERENCE:
      if (!secret.has_reference()) {
        return Error(
            "Secret of type REFERENCE must have the 'reference' field set");
      }

      if (secret.has_value()) {
        return Error(
            "Secret '" + secret.reference().name() + "' of type REFERENCE "
            "must not have the 'value' field set");
      }
      break;

    case Secret::VALUE:
      if (!secret.has_value()) {
        return Error("Secret of type VALUE must have the 'value' field set");
      }

      if (secret.has_reference()) {
        return Error(
            "Secret of type VALUE must not have the 'reference' field set");
      }
      break;

    case Secret::UNKNOWN:
      break;

    UNREACHABLE();
  }

  return None();
}

Option<Error> validateEnvironment(const Environment& environment)
{
  foreach (const Environment::Variable& variable, environment.variables()) {
    switch (variable.type()) {
      case Environment::Variable::SECRET: {
        if (!variable.has_secret()) {
          return Error(
              "Environment variable '" + variable.name() +
              "' of type 'SECRET' must have a secret set");
        }

        if (variable.has_value()) {
          return Error(
              "Environment variable '" + variable.name() +
              "' of type 'SECRET' must not have a value set");
        }

        Option<Error> error = validateSecret(variable.secret());
        if (error.isSome()) {
          return Error(
              "Environment variable '" + variable.name() + "' specifies an "
              "invalid secret: " + error->message);
        }

        if (variable.secret().value().data().find('\0') != string::npos) {
            return Error(
                "Environment variable '" + variable.name() + "' specifies a "
                "secret containing null bytes, which is not allowed in the "
                "environment");
        }
        break;
      }

      // NOTE: If new variable types are added in the future and an upgraded
      // client/master sends a new type to an older master/agent, the older
      // master/agent will see VALUE instead of the new type, since VALUE is set
      // as the default type in the protobuf definition.
      case Environment::Variable::VALUE:
        if (!variable.has_value()) {
          return Error(
              "Environment variable '" + variable.name() +
              "' of type 'VALUE' must have a value set");
        }

        if (variable.has_secret()) {
          return Error(
              "Environment variable '" + variable.name() +
              "' of type 'VALUE' must not have a secret set");
        }
        break;

      case Environment::Variable::UNKNOWN:
          return Error("Environment variable of type 'UNKNOWN' is not allowed");

      UNREACHABLE();
    }
  }

  return None();
}

// TODO(greggomann): Do more than just validate the `Environment`.
Option<Error> validateCommandInfo(const CommandInfo& command)
{
  return validateEnvironment(command.environment());
}

} // namespace validation {
} // namespace common {
} // namespace internal {
} // namespace mesos {
<|endoftext|>


<commit_before>// Copyright (c) 2009-2018 The Regents of the University of Michigan
// This file is part of the HOOMD-blue project, released under the BSD 3-Clause License.

// this include is necessary to get MPI included before anything else to support intel MPI
#include "hoomd/ExecutionConfiguration.h"

#include <iostream>

#include <memory>

#include "hoomd/GlobalArray.h"
#include "hoomd/GPUVector.h"

#ifdef ENABLE_CUDA
#include "test_global_array.cuh"
#endif

using namespace std;

/*! \file gpu_array_test.cc
    \brief Implements unit tests for GlobalArray and GPUVector
    \ingroup unit_tests
*/

#include "upp11_config.h"
HOOMD_UP_MAIN();

//! test case for testing the basic operation of GlobalArray
UP_TEST( GlobalArray_basic_tests )
    {
    std::shared_ptr<ExecutionConfiguration> exec_conf(new ExecutionConfiguration(ExecutionConfiguration::CPU));
    GlobalArray<int> gpu_array(100, exec_conf);

    // basic check: ensure that the number of elements is set correctly
    UP_ASSERT_EQUAL((int)gpu_array.getNumElements(), 100);

    // basic check 2: acquire the data on the host and fill out a pattern
        {
        ArrayHandle<int> h_handle(gpu_array, access_location::host, access_mode::readwrite);
        UP_ASSERT(h_handle.data != NULL);
        for (int i = 0; i < (int)gpu_array.getNumElements(); i++)
            h_handle.data[i] = i;
        }

    // basic check 3: verify the data set in check 2
        {
        ArrayHandle<int> h_handle(gpu_array, access_location::host, access_mode::read);
        UP_ASSERT(h_handle.data != NULL);
        for (int i = 0; i < (int)gpu_array.getNumElements(); i++)
            UP_ASSERT_EQUAL(h_handle.data[i], i);
        }

    // basic check 3.5: test the construction of a 2-D GlobalArray
    GlobalArray<int> gpu_array_2d(63, 120, exec_conf);
    UP_ASSERT_EQUAL((int)gpu_array_2d.getPitch(), 64);
    UP_ASSERT_EQUAL((int)gpu_array_2d.getHeight(), 120);
    UP_ASSERT_EQUAL((int)gpu_array_2d.getNumElements(), 7680);

    // basic check 4: verify the copy constructor
    GlobalArray<int> array_b(gpu_array);
    UP_ASSERT_EQUAL((int)array_b.getNumElements(), 100);
    UP_ASSERT_EQUAL((int)array_b.getPitch(), 100);
    UP_ASSERT_EQUAL((int)array_b.getHeight(), 1);

        {
        ArrayHandle<int> h_handle(array_b, access_location::host, access_mode::read);
        UP_ASSERT(h_handle.data != NULL);
        for (int i = 0; i < (int)array_b.getNumElements(); i++)
            UP_ASSERT_EQUAL(h_handle.data[i], i);
        }

    // basic check 5: verify the = operator
    GlobalArray<int> array_c(1, exec_conf);
    array_c = gpu_array;

    UP_ASSERT_EQUAL((int)array_c.getNumElements(), 100);
    UP_ASSERT_EQUAL((int)array_c.getPitch(), 100);
    UP_ASSERT_EQUAL((int)array_c.getHeight(), 1);

        {
        ArrayHandle<int> h_handle(array_c, access_location::host, access_mode::read);
        UP_ASSERT(h_handle.data != NULL);
        for (int i = 0; i < (int)array_c.getNumElements(); i++)
            UP_ASSERT_EQUAL(h_handle.data[i], i);
        }

    }

#ifdef ENABLE_CUDA
//! test case for testing device to/from host transfers
UP_TEST( GlobalArray_transfer_tests )
    {
    std::shared_ptr<ExecutionConfiguration> exec_conf(new ExecutionConfiguration(ExecutionConfiguration::GPU));
    UP_ASSERT(exec_conf->isCUDAEnabled());

    GlobalArray<int> gpu_array(100, exec_conf);

    // initialize the data on the device
        {
        ArrayHandle<int> d_handle(gpu_array, access_location::device, access_mode::readwrite);
        UP_ASSERT(d_handle.data != NULL);

        gpu_fill_test_pattern(d_handle.data, gpu_array.getNumElements());
        cudaError_t err_sync = cudaGetLastError();
        exec_conf->handleCUDAError(err_sync, __FILE__, __LINE__);
        }

    // copy it to the host and verify
        {
        ArrayHandle<int> h_handle(gpu_array, access_location::host, access_mode::readwrite);
        UP_ASSERT(h_handle.data != NULL);
        for (int i = 0; i < (int)gpu_array.getNumElements(); i++)
            {
            UP_ASSERT_EQUAL(h_handle.data[i], i*i);
            // overwrite the data as we verify
            h_handle.data[i] = 100+i;
            }
        }

    // data has been overwitten on the host. Increment it on the device in overwrite mode
    // because there may be only a single array shared between the host and the device, there is no guarantee
    // that the add_one operates on separate different copy of the data
        {
        ArrayHandle<int> d_handle(gpu_array, access_location::device, access_mode::readwrite);
        UP_ASSERT(d_handle.data != NULL);

        gpu_add_one(d_handle.data, gpu_array.getNumElements());
        cudaError_t err_sync = cudaGetLastError();
        exec_conf->handleCUDAError(err_sync, __FILE__, __LINE__);
        }

    // read back on host
        {
        ArrayHandle<int> h_handle(gpu_array, access_location::host, access_mode::readwrite);
        UP_ASSERT(h_handle.data != NULL);
        for (int i = 0; i < (int)gpu_array.getNumElements(); i++)
            {
            UP_ASSERT_EQUAL(h_handle.data[i], 101+i);
            }
        }

    // finally, test host-> device copies
        {
        ArrayHandle<int> d_handle(gpu_array, access_location::device, access_mode::readwrite);
        UP_ASSERT(d_handle.data != NULL);

        gpu_add_one(d_handle.data, gpu_array.getNumElements());
        cudaError_t err_sync = cudaGetLastError();
        exec_conf->handleCUDAError(err_sync, __FILE__, __LINE__);
        }

    // via the read access mode
        {
        ArrayHandle<int> h_handle(gpu_array, access_location::host, access_mode::read);
        UP_ASSERT(h_handle.data != NULL);
        for (int i = 0; i < (int)gpu_array.getNumElements(); i++)
            {
            UP_ASSERT_EQUAL(h_handle.data[i], 100+i+1);
            }
        }

        {
        ArrayHandle<int> d_handle(gpu_array, access_location::device, access_mode::readwrite);
        UP_ASSERT(d_handle.data != NULL);

        gpu_add_one(d_handle.data, gpu_array.getNumElements());
        cudaError_t err_sync = cudaGetLastError();
        exec_conf->handleCUDAError(err_sync, __FILE__, __LINE__);
        }

    // and via the readwrite access mode
        {
        ArrayHandle<int> h_handle(gpu_array, access_location::host, access_mode::readwrite);
        UP_ASSERT(h_handle.data != NULL);
        for (int i = 0; i < (int)gpu_array.getNumElements(); i++)
            {
            UP_ASSERT_EQUAL(h_handle.data[i], 100+i+1+1);
            }
        }
    }

//! Tests operations on NULL GlobalArrays
UP_TEST( GlobalArray_null_tests )
    {
    // Construct a NULL GlobalArray
    GlobalArray<int> a;

    UP_ASSERT(a.isNull());
    UP_ASSERT_EQUAL(a.getNumElements(), (unsigned)0);

    // check copy construction of a NULL GlobalArray
    GlobalArray<int> b(a);

    UP_ASSERT(b.isNull());
    UP_ASSERT_EQUAL(b.getNumElements(), (unsigned)0);

    // check assignment of a NULL GlobalArray
    std::shared_ptr<ExecutionConfiguration> exec_conf(new ExecutionConfiguration(ExecutionConfiguration::GPU));
    GlobalArray<int> c(1000, exec_conf);
    c = a;

    UP_ASSERT(c.isNull());
    UP_ASSERT_EQUAL(c.getNumElements(), (unsigned)0);

    // check swapping of a NULL GlobalArray
    GlobalArray<int> d(1000, exec_conf);

    d.swap(a);
    UP_ASSERT(d.isNull());
    UP_ASSERT_EQUAL(d.getNumElements(), (unsigned)0);

    UP_ASSERT(!a.isNull());
    UP_ASSERT_EQUAL(a.getNumElements(), (unsigned)1000);
    }

//! Tests resize methods
UP_TEST( GlobalArray_resize_tests )
    {
    std::shared_ptr<ExecutionConfiguration> exec_conf(new ExecutionConfiguration(ExecutionConfiguration::GPU));

    // create a 1D GlobalArray
    GlobalArray<unsigned int> a(5, exec_conf);

        {
        // Fill it with some values
        ArrayHandle<unsigned int> h_handle(a, access_location::host, access_mode::overwrite);

        h_handle.data[0] = 1;
        h_handle.data[1] = 2;
        h_handle.data[2] = 3;
        h_handle.data[3] = 4;
        h_handle.data[4] = 5;
        }

    // resize the array
    a.resize(10);

    // check that it has the right size
    UP_ASSERT_EQUAL(a.getNumElements(),(unsigned int)10);
        {
        // test that it still contains the data
        ArrayHandle<unsigned int> h_handle(a, access_location::host, access_mode::read);

        UP_ASSERT_EQUAL(h_handle.data[0], (unsigned int)1);
        UP_ASSERT_EQUAL(h_handle.data[1], (unsigned int)2);
        UP_ASSERT_EQUAL(h_handle.data[2], (unsigned int)3);
        UP_ASSERT_EQUAL(h_handle.data[3], (unsigned int)4);
        UP_ASSERT_EQUAL(h_handle.data[4], (unsigned int)5);

        // test that the other elements are set to zero
        UP_ASSERT_EQUAL(h_handle.data[5], (unsigned int)0);
        UP_ASSERT_EQUAL(h_handle.data[6], (unsigned int)0);
        UP_ASSERT_EQUAL(h_handle.data[7], (unsigned int)0);
        UP_ASSERT_EQUAL(h_handle.data[8], (unsigned int)0);
        UP_ASSERT_EQUAL(h_handle.data[9], (unsigned int)0);
        }

   // check that it also works for a GlobalArray that is initially empty
   GlobalArray<unsigned int> b;
   b.resize(7);

   UP_ASSERT_EQUAL(b.getNumElements(), (unsigned int)7);

   // allocate a 2D GlobalArray
   unsigned int width=3;
   unsigned int height=2;
   GlobalArray<unsigned int> c(width, height,exec_conf);
   unsigned int pitch = c.getPitch();
       {
       // write some data to it
       ArrayHandle<unsigned int> h_handle(c, access_location::host, access_mode::overwrite);

       h_handle.data[0] = 123;
       h_handle.data[1] = 456;
       h_handle.data[2] = 789;

       h_handle.data[0+pitch] = 1234;
       h_handle.data[1+pitch] = 3456;
       h_handle.data[2+pitch] = 5678;
       }

   // resize it
   width = 17;
   height = 4;
   c.resize(width,height);
   pitch = c.getPitch();

   // check that it has the right size
   UP_ASSERT_EQUAL(c.getNumElements(), pitch*height);

       {
       // test that we can still recover the data
       ArrayHandle<unsigned int> h_handle(c, access_location::host, access_mode::read);

       UP_ASSERT_EQUAL(h_handle.data[0], (unsigned int)123);
       UP_ASSERT_EQUAL(h_handle.data[1], (unsigned int)456);
       UP_ASSERT_EQUAL(h_handle.data[2], (unsigned int)789);

       UP_ASSERT_EQUAL(h_handle.data[0+pitch], (unsigned int)1234);
       UP_ASSERT_EQUAL(h_handle.data[1+pitch], (unsigned int)3456);
       UP_ASSERT_EQUAL(h_handle.data[2+pitch], (unsigned int)5678);
       }
   }

//! Tests GPUVector
UP_TEST( GPUVector_basic_tests )
    {
    std::shared_ptr<ExecutionConfiguration> exec_conf(new ExecutionConfiguration(ExecutionConfiguration::GPU));

    // First create an empty GPUVector
    GPUVector<unsigned int> vec(exec_conf);

    // The size should be zero
    UP_ASSERT_EQUAL(vec.size(),(unsigned int)0);

    // Add some elements
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);

    UP_ASSERT_EQUAL(vec.size(), (unsigned int)3);

    // Test bracket operator
    UP_ASSERT_EQUAL((unsigned int)vec[0],(unsigned int)1);
    UP_ASSERT_EQUAL((unsigned int)vec[1],(unsigned int)2);
    UP_ASSERT_EQUAL((unsigned int)vec[2],(unsigned int)3);

    // Test assignment
    vec[1] = 4;

    UP_ASSERT_EQUAL((unsigned int)vec[0],(unsigned int)1);
    UP_ASSERT_EQUAL((unsigned int)vec[1],(unsigned int)4);
    UP_ASSERT_EQUAL((unsigned int)vec[2],(unsigned int)3);

    // remove an element
    vec.pop_back();

    UP_ASSERT_EQUAL(vec.size(), (unsigned int)2);

    // clear the array
    vec.clear();

    UP_ASSERT_EQUAL(vec.size(), (unsigned int)0);

    // resize it
    vec.resize(10);
    UP_ASSERT_EQUAL(vec.size(), (unsigned int)10 );

    // verify we can still write to it
    vec[0] = 234;
    vec[1] = 123;
    vec[2] = 654;
    vec[3] = 789;
    vec[4] = 321;
    vec[5] = 432;
    vec[6] = 543;
    vec[7] = 678;
    vec[8] = 987;
    vec[9] = 890;

    // read back
    UP_ASSERT_EQUAL((unsigned int)vec[0], (unsigned int)234);
    UP_ASSERT_EQUAL((unsigned int)vec[1], (unsigned int)123);
    UP_ASSERT_EQUAL((unsigned int)vec[2], (unsigned int)654);
    UP_ASSERT_EQUAL((unsigned int)vec[3], (unsigned int)789);
    UP_ASSERT_EQUAL((unsigned int)vec[4], (unsigned int)321);
    UP_ASSERT_EQUAL((unsigned int)vec[5], (unsigned int)432);
    UP_ASSERT_EQUAL((unsigned int)vec[6], (unsigned int)543);
    UP_ASSERT_EQUAL((unsigned int)vec[7], (unsigned int)678);
    UP_ASSERT_EQUAL((unsigned int)vec[8], (unsigned int)987);
    UP_ASSERT_EQUAL((unsigned int)vec[9], (unsigned int)890);
    }
#endif
<commit_msg>try really fixing unit test<commit_after>// Copyright (c) 2009-2018 The Regents of the University of Michigan
// This file is part of the HOOMD-blue project, released under the BSD 3-Clause License.

// this include is necessary to get MPI included before anything else to support intel MPI
#include "hoomd/ExecutionConfiguration.h"

#include <iostream>

#include <memory>

#include "hoomd/GlobalArray.h"
#include "hoomd/GPUVector.h"

#ifdef ENABLE_CUDA
#include "test_global_array.cuh"
#endif

using namespace std;

/*! \file gpu_array_test.cc
    \brief Implements unit tests for GlobalArray and GPUVector
    \ingroup unit_tests
*/

#include "upp11_config.h"
HOOMD_UP_MAIN();

//! test case for testing the basic operation of GlobalArray
UP_TEST( GlobalArray_basic_tests )
    {
    std::shared_ptr<ExecutionConfiguration> exec_conf(new ExecutionConfiguration(ExecutionConfiguration::CPU));
    GlobalArray<int> gpu_array(100, exec_conf);

    // basic check: ensure that the number of elements is set correctly
    UP_ASSERT_EQUAL((int)gpu_array.getNumElements(), 100);

    // basic check 2: acquire the data on the host and fill out a pattern
        {
        ArrayHandle<int> h_handle(gpu_array, access_location::host, access_mode::readwrite);
        UP_ASSERT(h_handle.data != NULL);
        for (int i = 0; i < (int)gpu_array.getNumElements(); i++)
            h_handle.data[i] = i;
        }

    // basic check 3: verify the data set in check 2
        {
        ArrayHandle<int> h_handle(gpu_array, access_location::host, access_mode::read);
        UP_ASSERT(h_handle.data != NULL);
        for (int i = 0; i < (int)gpu_array.getNumElements(); i++)
            UP_ASSERT_EQUAL(h_handle.data[i], i);
        }

    // basic check 3.5: test the construction of a 2-D GlobalArray
    GlobalArray<int> gpu_array_2d(63, 120, exec_conf);
    UP_ASSERT_EQUAL((int)gpu_array_2d.getPitch(), 64);
    UP_ASSERT_EQUAL((int)gpu_array_2d.getHeight(), 120);
    UP_ASSERT_EQUAL((int)gpu_array_2d.getNumElements(), 7680);

    // basic check 4: verify the copy constructor
    GlobalArray<int> array_b(gpu_array);
    UP_ASSERT_EQUAL((int)array_b.getNumElements(), 100);
    UP_ASSERT_EQUAL((int)array_b.getPitch(), 100);
    UP_ASSERT_EQUAL((int)array_b.getHeight(), 1);

        {
        ArrayHandle<int> h_handle(array_b, access_location::host, access_mode::read);
        UP_ASSERT(h_handle.data != NULL);
        for (int i = 0; i < (int)array_b.getNumElements(); i++)
            UP_ASSERT_EQUAL(h_handle.data[i], i);
        }

    // basic check 5: verify the = operator
    GlobalArray<int> array_c(1, exec_conf);
    array_c = gpu_array;

    UP_ASSERT_EQUAL((int)array_c.getNumElements(), 100);
    UP_ASSERT_EQUAL((int)array_c.getPitch(), 100);
    UP_ASSERT_EQUAL((int)array_c.getHeight(), 1);

        {
        ArrayHandle<int> h_handle(array_c, access_location::host, access_mode::read);
        UP_ASSERT(h_handle.data != NULL);
        for (int i = 0; i < (int)array_c.getNumElements(); i++)
            UP_ASSERT_EQUAL(h_handle.data[i], i);
        }

    }

#ifdef ENABLE_CUDA
//! test case for testing device to/from host transfers
UP_TEST( GlobalArray_transfer_tests )
    {
    std::shared_ptr<ExecutionConfiguration> exec_conf(new ExecutionConfiguration(ExecutionConfiguration::GPU));
    UP_ASSERT(exec_conf->isCUDAEnabled());

    GlobalArray<int> gpu_array(100, exec_conf);

    // initialize the data on the device
        {
        ArrayHandle<int> d_handle(gpu_array, access_location::device, access_mode::readwrite);
        UP_ASSERT(d_handle.data != NULL);

        gpu_fill_test_pattern(d_handle.data, gpu_array.getNumElements());
        cudaError_t err_sync = cudaGetLastError();
        exec_conf->handleCUDAError(err_sync, __FILE__, __LINE__);
        }

    // copy it to the host and verify
        {
        ArrayHandle<int> h_handle(gpu_array, access_location::host, access_mode::readwrite);
        UP_ASSERT(h_handle.data != NULL);
        for (int i = 0; i < (int)gpu_array.getNumElements(); i++)
            {
            UP_ASSERT_EQUAL(h_handle.data[i], i*i);
            // overwrite the data as we verify
            h_handle.data[i] = 100+i;
            }
        }

    // test host-> device copies
        {
        ArrayHandle<int> d_handle(gpu_array, access_location::device, access_mode::readwrite);
        UP_ASSERT(d_handle.data != NULL);

        gpu_add_one(d_handle.data, gpu_array.getNumElements());
        cudaError_t err_sync = cudaGetLastError();
        exec_conf->handleCUDAError(err_sync, __FILE__, __LINE__);
        }

    // via the read access mode
        {
        ArrayHandle<int> h_handle(gpu_array, access_location::host, access_mode::read);
        UP_ASSERT(h_handle.data != NULL);
        for (int i = 0; i < (int)gpu_array.getNumElements(); i++)
            {
            UP_ASSERT_EQUAL(h_handle.data[i], 100+i+1);
            }
        }

        {
        ArrayHandle<int> d_handle(gpu_array, access_location::device, access_mode::readwrite);
        UP_ASSERT(d_handle.data != NULL);

        gpu_add_one(d_handle.data, gpu_array.getNumElements());
        cudaError_t err_sync = cudaGetLastError();
        exec_conf->handleCUDAError(err_sync, __FILE__, __LINE__);
        }

    // and via the readwrite access mode
        {
        ArrayHandle<int> h_handle(gpu_array, access_location::host, access_mode::readwrite);
        UP_ASSERT(h_handle.data != NULL);
        for (int i = 0; i < (int)gpu_array.getNumElements(); i++)
            {
            UP_ASSERT_EQUAL(h_handle.data[i], 100+i+1+1);
            }
        }
    }

//! Tests operations on NULL GlobalArrays
UP_TEST( GlobalArray_null_tests )
    {
    // Construct a NULL GlobalArray
    GlobalArray<int> a;

    UP_ASSERT(a.isNull());
    UP_ASSERT_EQUAL(a.getNumElements(), (unsigned)0);

    // check copy construction of a NULL GlobalArray
    GlobalArray<int> b(a);

    UP_ASSERT(b.isNull());
    UP_ASSERT_EQUAL(b.getNumElements(), (unsigned)0);

    // check assignment of a NULL GlobalArray
    std::shared_ptr<ExecutionConfiguration> exec_conf(new ExecutionConfiguration(ExecutionConfiguration::GPU));
    GlobalArray<int> c(1000, exec_conf);
    c = a;

    UP_ASSERT(c.isNull());
    UP_ASSERT_EQUAL(c.getNumElements(), (unsigned)0);

    // check swapping of a NULL GlobalArray
    GlobalArray<int> d(1000, exec_conf);

    d.swap(a);
    UP_ASSERT(d.isNull());
    UP_ASSERT_EQUAL(d.getNumElements(), (unsigned)0);

    UP_ASSERT(!a.isNull());
    UP_ASSERT_EQUAL(a.getNumElements(), (unsigned)1000);
    }

//! Tests resize methods
UP_TEST( GlobalArray_resize_tests )
    {
    std::shared_ptr<ExecutionConfiguration> exec_conf(new ExecutionConfiguration(ExecutionConfiguration::GPU));

    // create a 1D GlobalArray
    GlobalArray<unsigned int> a(5, exec_conf);

        {
        // Fill it with some values
        ArrayHandle<unsigned int> h_handle(a, access_location::host, access_mode::overwrite);

        h_handle.data[0] = 1;
        h_handle.data[1] = 2;
        h_handle.data[2] = 3;
        h_handle.data[3] = 4;
        h_handle.data[4] = 5;
        }

    // resize the array
    a.resize(10);

    // check that it has the right size
    UP_ASSERT_EQUAL(a.getNumElements(),(unsigned int)10);
        {
        // test that it still contains the data
        ArrayHandle<unsigned int> h_handle(a, access_location::host, access_mode::read);

        UP_ASSERT_EQUAL(h_handle.data[0], (unsigned int)1);
        UP_ASSERT_EQUAL(h_handle.data[1], (unsigned int)2);
        UP_ASSERT_EQUAL(h_handle.data[2], (unsigned int)3);
        UP_ASSERT_EQUAL(h_handle.data[3], (unsigned int)4);
        UP_ASSERT_EQUAL(h_handle.data[4], (unsigned int)5);

        // test that the other elements are set to zero
        UP_ASSERT_EQUAL(h_handle.data[5], (unsigned int)0);
        UP_ASSERT_EQUAL(h_handle.data[6], (unsigned int)0);
        UP_ASSERT_EQUAL(h_handle.data[7], (unsigned int)0);
        UP_ASSERT_EQUAL(h_handle.data[8], (unsigned int)0);
        UP_ASSERT_EQUAL(h_handle.data[9], (unsigned int)0);
        }

   // check that it also works for a GlobalArray that is initially empty
   GlobalArray<unsigned int> b;
   b.resize(7);

   UP_ASSERT_EQUAL(b.getNumElements(), (unsigned int)7);

   // allocate a 2D GlobalArray
   unsigned int width=3;
   unsigned int height=2;
   GlobalArray<unsigned int> c(width, height,exec_conf);
   unsigned int pitch = c.getPitch();
       {
       // write some data to it
       ArrayHandle<unsigned int> h_handle(c, access_location::host, access_mode::overwrite);

       h_handle.data[0] = 123;
       h_handle.data[1] = 456;
       h_handle.data[2] = 789;

       h_handle.data[0+pitch] = 1234;
       h_handle.data[1+pitch] = 3456;
       h_handle.data[2+pitch] = 5678;
       }

   // resize it
   width = 17;
   height = 4;
   c.resize(width,height);
   pitch = c.getPitch();

   // check that it has the right size
   UP_ASSERT_EQUAL(c.getNumElements(), pitch*height);

       {
       // test that we can still recover the data
       ArrayHandle<unsigned int> h_handle(c, access_location::host, access_mode::read);

       UP_ASSERT_EQUAL(h_handle.data[0], (unsigned int)123);
       UP_ASSERT_EQUAL(h_handle.data[1], (unsigned int)456);
       UP_ASSERT_EQUAL(h_handle.data[2], (unsigned int)789);

       UP_ASSERT_EQUAL(h_handle.data[0+pitch], (unsigned int)1234);
       UP_ASSERT_EQUAL(h_handle.data[1+pitch], (unsigned int)3456);
       UP_ASSERT_EQUAL(h_handle.data[2+pitch], (unsigned int)5678);
       }
   }

//! Tests GPUVector
UP_TEST( GPUVector_basic_tests )
    {
    std::shared_ptr<ExecutionConfiguration> exec_conf(new ExecutionConfiguration(ExecutionConfiguration::GPU));

    // First create an empty GPUVector
    GPUVector<unsigned int> vec(exec_conf);

    // The size should be zero
    UP_ASSERT_EQUAL(vec.size(),(unsigned int)0);

    // Add some elements
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);

    UP_ASSERT_EQUAL(vec.size(), (unsigned int)3);

    // Test bracket operator
    UP_ASSERT_EQUAL((unsigned int)vec[0],(unsigned int)1);
    UP_ASSERT_EQUAL((unsigned int)vec[1],(unsigned int)2);
    UP_ASSERT_EQUAL((unsigned int)vec[2],(unsigned int)3);

    // Test assignment
    vec[1] = 4;

    UP_ASSERT_EQUAL((unsigned int)vec[0],(unsigned int)1);
    UP_ASSERT_EQUAL((unsigned int)vec[1],(unsigned int)4);
    UP_ASSERT_EQUAL((unsigned int)vec[2],(unsigned int)3);

    // remove an element
    vec.pop_back();

    UP_ASSERT_EQUAL(vec.size(), (unsigned int)2);

    // clear the array
    vec.clear();

    UP_ASSERT_EQUAL(vec.size(), (unsigned int)0);

    // resize it
    vec.resize(10);
    UP_ASSERT_EQUAL(vec.size(), (unsigned int)10 );

    // verify we can still write to it
    vec[0] = 234;
    vec[1] = 123;
    vec[2] = 654;
    vec[3] = 789;
    vec[4] = 321;
    vec[5] = 432;
    vec[6] = 543;
    vec[7] = 678;
    vec[8] = 987;
    vec[9] = 890;

    // read back
    UP_ASSERT_EQUAL((unsigned int)vec[0], (unsigned int)234);
    UP_ASSERT_EQUAL((unsigned int)vec[1], (unsigned int)123);
    UP_ASSERT_EQUAL((unsigned int)vec[2], (unsigned int)654);
    UP_ASSERT_EQUAL((unsigned int)vec[3], (unsigned int)789);
    UP_ASSERT_EQUAL((unsigned int)vec[4], (unsigned int)321);
    UP_ASSERT_EQUAL((unsigned int)vec[5], (unsigned int)432);
    UP_ASSERT_EQUAL((unsigned int)vec[6], (unsigned int)543);
    UP_ASSERT_EQUAL((unsigned int)vec[7], (unsigned int)678);
    UP_ASSERT_EQUAL((unsigned int)vec[8], (unsigned int)987);
    UP_ASSERT_EQUAL((unsigned int)vec[9], (unsigned int)890);
    }
#endif
<|endoftext|>


<commit_before>// $Id$

/**************************************************************************
 * Copyright(c) 1998-2008, ALICE Experiment at CERN, all rights reserved. *
 * See http://aliceinfo.cern.ch/Offline/AliRoot/License.html for          *
 * full copyright notice.                                                 *
 **************************************************************************/

/// \ingroup evemacros
/// \file geom_gentle_muon.C
///
/// \author B. Vulpescu, LPC; M. Tadel, CERN

void DrawDeep(TEveGeoShape *gsre) {

  for (TEveElement::List_i i = gsre->BeginChildren(); i != gsre->EndChildren(); ++i) {
    TEveGeoShape* lvl = (TEveGeoShape*) *i;
    lvl->SetRnrSelf(kFALSE);
    if (!lvl->HasChildren()) {
      lvl->SetRnrSelf(kTRUE);
      lvl->SetMainColor(3);
      lvl->SetMainTransparency(50);
    }
    DrawDeep(lvl);
  }

}

TEveGeoShape* geom_gentle_muon(Bool_t updateScene = kTRUE) {

  TFile f("$ALICE_ROOT/EVE/alice-data/gentle_geo_muon.root");
  TEveGeoShapeExtract* gse = (TEveGeoShapeExtract*) f.Get("Gentle MUON");
  TEveGeoShape* gsre = TEveGeoShape::ImportShapeExtract(gse);
  gEve->AddGlobalElement(gsre);
  f.Close();

  gsre->SetRnrSelf(kFALSE);

  DrawDeep(gsre);

  if ( updateScene ) {
    TGLViewer* v = gEve->GetDefaultGLViewer();
    v->UpdateScene();
  }

  return gsre;

}

<commit_msg><commit_after>// $Id$

/**************************************************************************
 * Copyright(c) 1998-2008, ALICE Experiment at CERN, all rights reserved. *
 * See http://aliceinfo.cern.ch/Offline/AliRoot/License.html for          *
 * full copyright notice.                                                 *
 **************************************************************************/

/// \ingroup evemacros
/// \file geom_gentle_muon.C
///
/// \author B. Vulpescu, LPC; M. Tadel, CERN

void DrawDeep(TEveGeoShape *gsre) {

  for (TEveElement::List_i i = gsre->BeginChildren(); i != gsre->EndChildren(); ++i) {
    TEveGeoShape* lvl = (TEveGeoShape*) *i;
    lvl->SetRnrSelf(kFALSE);
    if (!lvl->HasChildren()) {
      lvl->SetRnrSelf(kTRUE);
      lvl->SetMainColor(3);
      lvl->SetMainTransparency(80);
    }
    DrawDeep(lvl);
  }

}

TEveGeoShape* geom_gentle_muon(Bool_t updateScene = kTRUE) {

  TFile f("$ALICE_ROOT/EVE/alice-data/gentle_geo_muon.root");
  TEveGeoShapeExtract* gse = (TEveGeoShapeExtract*) f.Get("Gentle MUON");
  TEveGeoShape* gsre = TEveGeoShape::ImportShapeExtract(gse);
  gEve->AddGlobalElement(gsre);
  f.Close();

  gsre->SetRnrSelf(kFALSE);

  DrawDeep(gsre);

  if ( updateScene ) {
    TGLViewer* v = gEve->GetDefaultGLViewer();
    v->UpdateScene();
  }

  return gsre;

}

<|endoftext|>


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

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/compiler/xla/service/reduce_precision_insertion.h"

#include "tensorflow/compiler/xla/service/hlo_module.h"
#include "tensorflow/compiler/xla/shape_util.h"
#include "tensorflow/core/platform/logging.h"

namespace xla {

StatusOr<bool> ReducePrecisionInsertion::Run(HloModule* module) {
  bool changed = false;
  VLOG(1) << "Running ReducePrecisionInsertion pass on " << module->name();

  for (auto& computation : module->computations()) {
    if (computation->IsFusionComputation()) {
      continue;
    }
    std::vector<HloInstruction*> instructions_to_suffix;

    for (auto& instruction : computation->instructions()) {
      VLOG(3) << "Visited instruction: " << instruction->ToString();

      // For now, ReducePrecision is only implemented for F32 arrays, so this
      // ignore instructions that produce other data.  In particular, this
      // currently ignores instructions producing tuples, even if those tuples
      // contain F32 arrays inside them.  The assumption is that in most cases
      // equivalent behavior can be obtained by adding ReducePrecision
      // instructions after the instructions that pull the F32 arrays out of
      // the tuples.
      if (instruction->shape().element_type() == PrimitiveType::F32 &&
          !ShapeUtil::IsScalar(instruction->shape()) &&
          should_reduce_output_precision_(instruction->opcode())) {
        instructions_to_suffix.push_back(instruction.get());
      }
    }

    for (auto& instruction : instructions_to_suffix) {
      HloInstruction* reduced =
          computation->AddInstruction(HloInstruction::CreateReducePrecision(
              instruction->shape(), instruction, exponent_bits_,
              mantissa_bits_));
      TF_RETURN_IF_ERROR(
          computation->ReplaceUsesOfInstruction(instruction, reduced));
      VLOG(2) << "Inserted new op after instruction: "
              << instruction->ToString();
      changed = true;
    }
  }
  return changed;
}

ReducePrecisionInsertion::OpcodeFilterFunction
ReducePrecisionInsertion::make_filter_function(
    const HloReducePrecisionOptions& reduce_precision_options) {
  // Implement the filter function with a lookup table.
  std::vector<bool> filter(HloOpcodeCount(), false);
  for (const auto& opcode : reduce_precision_options.opcodes_to_suffix()) {
    filter[opcode] = true;
  }
  return [filter](const HloOpcode opcode) {
    return filter[static_cast<unsigned int>(opcode)];
  };
}

HloReducePrecisionOptions ReducePrecisionInsertion::make_options_proto(
    const HloReducePrecisionOptions::PassTiming pass_timing,
    const int exponent_bits, const int mantissa_bits,
    const OpcodeFilterFunction& should_reduce_output_precision) {
  HloReducePrecisionOptions options;
  options.set_pass_timing(pass_timing);
  options.set_exponent_bits(exponent_bits);
  options.set_mantissa_bits(mantissa_bits);
  for (uint32_t opcode = 0; opcode < HloOpcodeCount(); opcode++) {
    if (should_reduce_output_precision(static_cast<HloOpcode>(opcode))) {
      options.add_opcodes_to_suffix(opcode);
    }
  }
  return options;
}

bool ReducePrecisionInsertion::AddPasses(
    HloPassPipeline* pipeline, const DebugOptions& debug_options,
    const HloReducePrecisionOptions::PassTiming pass_timing) {
  bool passes_added = false;
  for (const auto& pass_options :
       debug_options.hlo_reduce_precision_options()) {
    if (pass_options.pass_timing() == pass_timing) {
      pipeline->AddPass<ReducePrecisionInsertion>(pass_options);
      passes_added = true;
    }
  }
  return passes_added;
}

}  // namespace xla
<commit_msg>[XLA] Add TODO comment explaining why the IsScalar check exists.<commit_after>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/compiler/xla/service/reduce_precision_insertion.h"

#include "tensorflow/compiler/xla/service/hlo_module.h"
#include "tensorflow/compiler/xla/shape_util.h"
#include "tensorflow/core/platform/logging.h"

namespace xla {

StatusOr<bool> ReducePrecisionInsertion::Run(HloModule* module) {
  bool changed = false;
  VLOG(1) << "Running ReducePrecisionInsertion pass on " << module->name();

  for (auto& computation : module->computations()) {
    if (computation->IsFusionComputation()) {
      continue;
    }
    std::vector<HloInstruction*> instructions_to_suffix;

    for (auto& instruction : computation->instructions()) {
      VLOG(3) << "Visited instruction: " << instruction->ToString();

      // For now, ReducePrecision is only implemented for F32 arrays, so this
      // ignore instructions that produce other data.  In particular, this
      // currently ignores instructions producing tuples, even if those tuples
      // contain F32 arrays inside them.  The assumption is that in most cases
      // equivalent behavior can be obtained by adding ReducePrecision
      // instructions after the instructions that pull the F32 arrays out of
      // the tuples.
      //
      // TODO(b/64093391): Remove the IsScalar check once this won't cause
      // failures on the GPU backend if the ReducePrecision instruction ends up
      // inserted between a scalar constant and the init_value argument of a
      // Reduce operation.
      if (instruction->shape().element_type() == PrimitiveType::F32 &&
          !ShapeUtil::IsScalar(instruction->shape()) &&
          should_reduce_output_precision_(instruction->opcode())) {
        instructions_to_suffix.push_back(instruction.get());
      }
    }

    for (auto& instruction : instructions_to_suffix) {
      HloInstruction* reduced =
          computation->AddInstruction(HloInstruction::CreateReducePrecision(
              instruction->shape(), instruction, exponent_bits_,
              mantissa_bits_));
      TF_RETURN_IF_ERROR(
          computation->ReplaceUsesOfInstruction(instruction, reduced));
      VLOG(2) << "Inserted new op after instruction: "
              << instruction->ToString();
      changed = true;
    }
  }
  return changed;
}

ReducePrecisionInsertion::OpcodeFilterFunction
ReducePrecisionInsertion::make_filter_function(
    const HloReducePrecisionOptions& reduce_precision_options) {
  // Implement the filter function with a lookup table.
  std::vector<bool> filter(HloOpcodeCount(), false);
  for (const auto& opcode : reduce_precision_options.opcodes_to_suffix()) {
    filter[opcode] = true;
  }
  return [filter](const HloOpcode opcode) {
    return filter[static_cast<unsigned int>(opcode)];
  };
}

HloReducePrecisionOptions ReducePrecisionInsertion::make_options_proto(
    const HloReducePrecisionOptions::PassTiming pass_timing,
    const int exponent_bits, const int mantissa_bits,
    const OpcodeFilterFunction& should_reduce_output_precision) {
  HloReducePrecisionOptions options;
  options.set_pass_timing(pass_timing);
  options.set_exponent_bits(exponent_bits);
  options.set_mantissa_bits(mantissa_bits);
  for (uint32_t opcode = 0; opcode < HloOpcodeCount(); opcode++) {
    if (should_reduce_output_precision(static_cast<HloOpcode>(opcode))) {
      options.add_opcodes_to_suffix(opcode);
    }
  }
  return options;
}

bool ReducePrecisionInsertion::AddPasses(
    HloPassPipeline* pipeline, const DebugOptions& debug_options,
    const HloReducePrecisionOptions::PassTiming pass_timing) {
  bool passes_added = false;
  for (const auto& pass_options :
       debug_options.hlo_reduce_precision_options()) {
    if (pass_options.pass_timing() == pass_timing) {
      pipeline->AddPass<ReducePrecisionInsertion>(pass_options);
      passes_added = true;
    }
  }
  return passes_added;
}

}  // namespace xla
<|endoftext|>