<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2008, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include <string.h>

#include "IECore/RadixSort.h"

using namespace IECore;

RadixSort::RadixSort() : m_currentSize( 0 ), m_ranks( 0 ), m_ranks2( 0 )
{
	m_currentSize |= 0x80000000;
}

RadixSort::~RadixSort()
{
}

void RadixSort::resize( unsigned int s )
{
	m_ranks = new UIntVectorData();
	m_ranks->writable().resize( s );

	m_ranks2 = new UIntVectorData();
	m_ranks2->writable().resize( s );
}

template<typename T>
bool RadixSort::checkPassValidity( const std::vector<T> &input, unsigned int pass, unsigned int* &curCount, unsigned char &uniqueVal )
{
	curCount = &m_histogram[ pass << 8 ];

	uniqueVal = *((( unsigned char* )( &input[0] ) ) + pass );

	if ( curCount[ uniqueVal ] == input.size() )
	{
		return false;
	}

	return true;
}

void RadixSort::checkResize( unsigned int s )
{
	unsigned int curSize = ( m_currentSize & 0x7fffffff );

	if ( s != curSize )
	{
		resize( s );

		m_currentSize = s;
		m_currentSize |= 0x80000000;
	}
}

const std::vector<unsigned int> &RadixSort::operator()( const std::vector<float> &input2 )
{
	const unsigned int nb = input2.size();
	checkResize( nb );

	if ( !nb )
	{
		return m_ranks->readable();
	}

	const unsigned int *input = ( const unsigned int * ) &input2[0];

	bool alreadySorted = createHistograms< float >( input2 );
	if ( alreadySorted )
	{
		return m_ranks->readable();
	}

	unsigned int numNegativeValues = 0;

	const unsigned int *h3 = &m_histogram[ 768 ];
	for ( unsigned int i = 128; i < 256; i ++ )
	{
		numNegativeValues += h3[i];
	}

	for ( unsigned int j = 0; j < 4; j ++ )
	{
		if ( j != 3 )
		{
			unsigned char uniqueVal = 0;
			unsigned int *curCount = 0;
			bool performPass = checkPassValidity( input2, j, curCount, uniqueVal );

			if ( performPass )
			{
				m_link[0] = &m_ranks2->writable()[0];

				for ( unsigned int i = 1; i < 256; i++ )
				{
					m_link[i] = m_link[ i - 1 ] + curCount[ i - 1 ];
				}

				const unsigned char *inputBytes = ( const unsigned char * ) input;
				inputBytes += j;

				if ( m_currentSize & 0x80000000 )
				{
					for ( unsigned int i = 0; i < nb; i++ )
					{
						*m_link[ inputBytes[i<<2] ]++ = i;
					}
					m_currentSize&=0x7fffffff;
				}
				else
				{
					for ( UIntVectorData::ValueType::const_iterator it = m_ranks->readable().begin(); it != m_ranks->readable().end(); ++it )
					{
						unsigned int id = *it;
						*m_link[ inputBytes[ id << 2 ] ]++ = id;
					}
				}

				std::swap( m_ranks, m_ranks2 );
			}
		}
		else
		{
			unsigned char uniqueVal = 0;
			unsigned int *curCount = 0;
			bool performPass = checkPassValidity( input2, j, curCount, uniqueVal );

			if ( performPass )
			{
				m_link[0] = &m_ranks2->writable()[numNegativeValues];
				for ( unsigned int i = 1; i < 128; i++ )
				{
					m_link[i] = m_link[ i - 1 ] + curCount[ i - 1 ];
				}

				m_link[255] = &m_ranks2->writable()[0];
				for ( unsigned int i = 0; i < 127; i ++ )
				{
					m_link[254 - i ] = m_link[255-i] + curCount[255 - i ];
				}

				for ( unsigned int i = 128; i < 256; i ++ )
				{
					m_link[i] += curCount[i];
				}

				if ( m_currentSize & 0x80000000 )
				{
					for ( unsigned int i = 0; i < nb; i++ )
					{
						unsigned int radix = input[i] >> 24;

						if ( radix < 128 )
						{
							*m_link[ radix ]++ = i;
						}
						else
						{
							*( --m_link[ radix] ) = i;
						}
					}
					m_currentSize&=0x7fffffff;
				}
				else
				{
					for ( unsigned int i = 0; i < nb; i ++ )
					{
						unsigned int radix = input[ m_ranks->readable()[i] ] >> 24;

						if ( radix < 128 )
						{
							*m_link[ radix ] ++ = m_ranks->readable()[i];
						}
						else
						{
							*( --m_link[ radix ] ) = m_ranks->readable()[i];
						}
					}
				}

				std::swap( m_ranks, m_ranks2 );
			}
			else
			{
				if ( uniqueVal >= 128 )
				{
					if ( m_currentSize & 0x80000000 )
					{
						for ( unsigned int i = 0; i < nb; i++ )
						{
							m_ranks2->writable()[i] = nb - i - 1;
						}
						m_currentSize&=0x7fffffff;
					}
					else
					{
						for ( unsigned int i = 0; i < nb; i++ )
						{
							m_ranks2->writable()[i] = m_ranks->readable()[ nb - i - 1 ];
						}
					}

					std::swap( m_ranks, m_ranks2 );
				}
			}
		}
	}

	return m_ranks->readable();
}

const std::vector<unsigned int> &RadixSort::operator()( const std::vector<unsigned int> &input2 )
{
	const unsigned int nb = input2.size();
	checkResize( nb );

	if ( !nb )
	{
		return m_ranks->readable();
	}
	const unsigned int *input = &input2[0];

	bool alreadySorted = createHistograms< unsigned int >( input2 );
	if ( alreadySorted )
	{
		return m_ranks->readable();
	}

	for ( unsigned int j = 0; j < 4; j ++ )
	{
		unsigned char uniqueVal = 0;
		unsigned int *curCount = 0;
		bool performPass = checkPassValidity( input2, j, curCount, uniqueVal );

		if ( performPass )
		{
			m_link[0] = &m_ranks2->writable()[0];

			for( unsigned int i = 1; i < 256; i++ )
			{
				m_link[i] = m_link[i - 1] + curCount[ i - 1 ];
			}

			const unsigned char *inputBytes = ( const unsigned char * )( input );
			inputBytes += j;

			if (m_currentSize & 0x80000000)
			{
				for ( unsigned int i = 0; i < nb; i++ )
				{
					*m_link[ inputBytes[ i<<2 ] ]++ = i;
				}
				m_currentSize &= 0x7fffffff;
			}
			else
			{
				for ( UIntVectorData::ValueType::const_iterator it = m_ranks->readable().begin(); it != m_ranks->readable().end(); ++it )
				{
					unsigned int id = *it;
					*m_link[ inputBytes[ id << 2 ] ]++ = id;
				}
			}

			std::swap( m_ranks, m_ranks2 );
		}
	}

	return m_ranks->readable();
}

const std::vector<unsigned int> &RadixSort::operator()( const std::vector<int> &input2 )
{
	const unsigned int nb = input2.size();
	checkResize( nb );

	if ( !nb )
	{
		return m_ranks->readable();
	}
	const unsigned int *input = ( const unsigned int * ) &input2[0];

	bool alreadySorted = createHistograms< int >( input2 );
	if ( alreadySorted )
	{
		return m_ranks->readable();
	}

	unsigned int numNegativeValues = 0;
	unsigned int* h3= &m_histogram[768];
	for ( unsigned int i = 128; i < 256; i++ )
	{
		numNegativeValues += h3[i];
	}

	for ( unsigned int j = 0; j < 4; j ++ )
	{
		unsigned char uniqueVal = 0;
		unsigned int *curCount = 0;
		bool performPass = checkPassValidity( input2, j, curCount, uniqueVal );

		if ( performPass )
		{
			if ( j != 3 )
			{
				m_link[0] = &m_ranks2->writable()[0];

				for( unsigned int i = 1; i < 256; i++ )
				{
					m_link[i] = m_link[i - 1] + curCount[ i - 1 ];
				}
			}
			else
			{
				m_link[0] = &m_ranks2->writable()[numNegativeValues];
				for( unsigned int i = 1; i < 128; i++ )
				{
					m_link[i] = m_link[i - 1] + curCount[ i - 1 ];
				}
				m_link[128] = &m_ranks2->writable()[0];
				for( unsigned int i = 129; i < 256; i++ )
				{
					m_link[i] = m_link[i - 1] + curCount[ i - 1 ];
				}
			}

			const unsigned char *inputBytes = ( const unsigned char * )( input );
			inputBytes += j;

			if (m_currentSize & 0x80000000)
			{
				for ( unsigned int i = 0; i < nb; i++ )
				{
					*m_link[ inputBytes[ i<<2 ] ]++ = i;
				}
				m_currentSize &= 0x7fffffff;
			}
			else
			{
				for ( UIntVectorData::ValueType::const_iterator it = m_ranks->readable().begin(); it != m_ranks->readable().end(); ++it )
				{
					unsigned int id = *it;
					*m_link[ inputBytes[ id << 2 ] ]++ = id;
				}
			}

			std::swap( m_ranks, m_ranks2 );
		}
	}

	return m_ranks->readable();
}

template<typename T>
bool RadixSort::createHistograms( const std::vector<T> &input )
{
	BOOST_STATIC_ASSERT( sizeof(T) == 4 );

	memset( &m_histogram[0], 0, 256 * 4 * sizeof( unsigned int ) );

	const unsigned char *p = reinterpret_cast< const unsigned char * > ( &input[0] );
	const unsigned char *pEnd = &p[ input.size() * 4 ] ;

	unsigned int *h0 = &m_histogram[0];
	unsigned int *h1 = &m_histogram[256];
	unsigned int *h2 = &m_histogram[512];
	unsigned int *h3 = &m_histogram[768];

	bool alreadySorted = true;

	if ( m_currentSize & 0x80000000 )
	{
		const T *running = &input[0];
		T prevVal = *running;

		while ( p != pEnd )
		{
			T val = *running++;

			if ( val < prevVal )
			{
				alreadySorted = false;
				break;
			}

			prevVal = val;

			h0[ *p++ ] ++;
			h1[ *p++ ] ++;
			h2[ *p++ ] ++;
			h3[ *p++ ] ++;
		}

		if ( alreadySorted )
		{
			for ( unsigned int i = 0; i < input.size(); i ++ )
			{
				m_ranks->writable()[i] = i;
			}
			return true;
		}
	}
	else
	{
		const unsigned int* indices = &m_ranks->readable()[0];
		T prevVal = input[ *indices ];

		while ( p != pEnd )
		{
			T val = input[ *indices++ ];
			if ( val < prevVal )
			{
				alreadySorted = false;
				break;
			}

			prevVal = val;

			h0[ *p++ ] ++;
			h1[ *p++ ] ++;
			h2[ *p++ ] ++;
			h3[ *p++ ] ++;
		}

		if ( alreadySorted )
		{
			return true;
		}

	}

	while ( p != pEnd )
	{
		h0[ *p++ ] ++;
		h1[ *p++ ] ++;
		h2[ *p++ ] ++;
		h3[ *p++ ] ++;
	}

	return false;
}

<commit_msg>Changed memory allocation so that sorting an empty list works<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2008, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include <string.h>

#include "IECore/RadixSort.h"

using namespace IECore;

RadixSort::RadixSort() : m_currentSize( 0 ), m_ranks( 0 ), m_ranks2( 0 )
{
	m_ranks = new UIntVectorData();
	m_ranks2 = new UIntVectorData();

	m_currentSize |= 0x80000000;
}

RadixSort::~RadixSort()
{
}

void RadixSort::resize( unsigned int s )
{
	m_ranks->writable().resize( s );
	m_ranks2->writable().resize( s );
}

template<typename T>
bool RadixSort::checkPassValidity( const std::vector<T> &input, unsigned int pass, unsigned int* &curCount, unsigned char &uniqueVal )
{
	curCount = &m_histogram[ pass << 8 ];

	uniqueVal = *((( unsigned char* )( &input[0] ) ) + pass );

	if ( curCount[ uniqueVal ] == input.size() )
	{
		return false;
	}

	return true;
}

void RadixSort::checkResize( unsigned int s )
{
	unsigned int curSize = ( m_currentSize & 0x7fffffff );

	if ( s != curSize )
	{
		resize( s );

		m_currentSize = s;
		m_currentSize |= 0x80000000;
	}
}

const std::vector<unsigned int> &RadixSort::operator()( const std::vector<float> &input2 )
{
	const unsigned int nb = input2.size();
	checkResize( nb );

	if ( !nb )
	{
		assert( m_ranks );
		return m_ranks->readable();
	}

	const unsigned int *input = ( const unsigned int * ) &input2[0];

	bool alreadySorted = createHistograms< float >( input2 );
	if ( alreadySorted )
	{
		return m_ranks->readable();
	}

	unsigned int numNegativeValues = 0;

	const unsigned int *h3 = &m_histogram[ 768 ];
	for ( unsigned int i = 128; i < 256; i ++ )
	{
		numNegativeValues += h3[i];
	}

	for ( unsigned int j = 0; j < 4; j ++ )
	{
		if ( j != 3 )
		{
			unsigned char uniqueVal = 0;
			unsigned int *curCount = 0;

			bool performPass = checkPassValidity( input2, j, curCount, uniqueVal );

			if ( performPass )
			{
				m_link[0] = &m_ranks2->writable()[0];

				for ( unsigned int i = 1; i < 256; i++ )
				{
					m_link[i] = m_link[ i - 1 ] + curCount[ i - 1 ];
				}

				const unsigned char *inputBytes = ( const unsigned char * ) input;
				inputBytes += j;

				if ( m_currentSize & 0x80000000 )
				{
					for ( unsigned int i = 0; i < nb; i++ )
					{
						*m_link[ inputBytes[i<<2] ]++ = i;
					}
					m_currentSize&=0x7fffffff;
				}
				else
				{
					for ( UIntVectorData::ValueType::const_iterator it = m_ranks->readable().begin(); it != m_ranks->readable().end(); ++it )
					{
						unsigned int id = *it;
						*m_link[ inputBytes[ id << 2 ] ]++ = id;
					}
				}

				std::swap( m_ranks, m_ranks2 );
			}
		}
		else
		{
			unsigned char uniqueVal = 0;
			unsigned int *curCount = 0;
			bool performPass = checkPassValidity( input2, j, curCount, uniqueVal );

			if ( performPass )
			{
				m_link[0] = &m_ranks2->writable()[numNegativeValues];
				for ( unsigned int i = 1; i < 128; i++ )
				{
					m_link[i] = m_link[ i - 1 ] + curCount[ i - 1 ];
				}

				m_link[255] = &m_ranks2->writable()[0];
				for ( unsigned int i = 0; i < 127; i ++ )
				{
					m_link[254 - i ] = m_link[255-i] + curCount[255 - i ];
				}

				for ( unsigned int i = 128; i < 256; i ++ )
				{
					m_link[i] += curCount[i];
				}

				if ( m_currentSize & 0x80000000 )
				{
					for ( unsigned int i = 0; i < nb; i++ )
					{
						unsigned int radix = input[i] >> 24;

						if ( radix < 128 )
						{
							*m_link[ radix ]++ = i;
						}
						else
						{
							*( --m_link[ radix] ) = i;
						}
					}
					m_currentSize&=0x7fffffff;
				}
				else
				{
					for ( unsigned int i = 0; i < nb; i ++ )
					{
						unsigned int radix = input[ m_ranks->readable()[i] ] >> 24;

						if ( radix < 128 )
						{
							*m_link[ radix ] ++ = m_ranks->readable()[i];
						}
						else
						{
							*( --m_link[ radix ] ) = m_ranks->readable()[i];
						}
					}
				}

				std::swap( m_ranks, m_ranks2 );
			}
			else
			{
				if ( uniqueVal >= 128 )
				{
					if ( m_currentSize & 0x80000000 )
					{
						for ( unsigned int i = 0; i < nb; i++ )
						{
							m_ranks2->writable()[i] = nb - i - 1;
						}
						m_currentSize&=0x7fffffff;
					}
					else
					{
						for ( unsigned int i = 0; i < nb; i++ )
						{
							m_ranks2->writable()[i] = m_ranks->readable()[ nb - i - 1 ];
						}
					}

					std::swap( m_ranks, m_ranks2 );
				}
			}
		}
	}

	return m_ranks->readable();
}

const std::vector<unsigned int> &RadixSort::operator()( const std::vector<unsigned int> &input2 )
{
	const unsigned int nb = input2.size();
	checkResize( nb );

	if ( !nb )
	{
		return m_ranks->readable();
	}
	const unsigned int *input = &input2[0];

	bool alreadySorted = createHistograms< unsigned int >( input2 );
	if ( alreadySorted )
	{
		return m_ranks->readable();
	}

	for ( unsigned int j = 0; j < 4; j ++ )
	{
		unsigned char uniqueVal = 0;
		unsigned int *curCount = 0;
		bool performPass = checkPassValidity( input2, j, curCount, uniqueVal );

		if ( performPass )
		{
			m_link[0] = &m_ranks2->writable()[0];

			for( unsigned int i = 1; i < 256; i++ )
			{
				m_link[i] = m_link[i - 1] + curCount[ i - 1 ];
			}

			const unsigned char *inputBytes = ( const unsigned char * )( input );
			inputBytes += j;

			if (m_currentSize & 0x80000000)
			{
				for ( unsigned int i = 0; i < nb; i++ )
				{
					*m_link[ inputBytes[ i<<2 ] ]++ = i;
				}
				m_currentSize &= 0x7fffffff;
			}
			else
			{
				for ( UIntVectorData::ValueType::const_iterator it = m_ranks->readable().begin(); it != m_ranks->readable().end(); ++it )
				{
					unsigned int id = *it;
					*m_link[ inputBytes[ id << 2 ] ]++ = id;
				}
			}

			std::swap( m_ranks, m_ranks2 );
		}
	}

	return m_ranks->readable();
}

const std::vector<unsigned int> &RadixSort::operator()( const std::vector<int> &input2 )
{
	const unsigned int nb = input2.size();
	checkResize( nb );

	if ( !nb )
	{
		return m_ranks->readable();
	}
	const unsigned int *input = ( const unsigned int * ) &input2[0];

	bool alreadySorted = createHistograms< int >( input2 );
	if ( alreadySorted )
	{
		return m_ranks->readable();
	}

	unsigned int numNegativeValues = 0;
	unsigned int* h3= &m_histogram[768];
	for ( unsigned int i = 128; i < 256; i++ )
	{
		numNegativeValues += h3[i];
	}

	for ( unsigned int j = 0; j < 4; j ++ )
	{
		unsigned char uniqueVal = 0;
		unsigned int *curCount = 0;
		bool performPass = checkPassValidity( input2, j, curCount, uniqueVal );

		if ( performPass )
		{
			if ( j != 3 )
			{
				m_link[0] = &m_ranks2->writable()[0];

				for( unsigned int i = 1; i < 256; i++ )
				{
					m_link[i] = m_link[i - 1] + curCount[ i - 1 ];
				}
			}
			else
			{
				m_link[0] = &m_ranks2->writable()[numNegativeValues];
				for( unsigned int i = 1; i < 128; i++ )
				{
					m_link[i] = m_link[i - 1] + curCount[ i - 1 ];
				}
				m_link[128] = &m_ranks2->writable()[0];
				for( unsigned int i = 129; i < 256; i++ )
				{
					m_link[i] = m_link[i - 1] + curCount[ i - 1 ];
				}
			}

			const unsigned char *inputBytes = ( const unsigned char * )( input );
			inputBytes += j;

			if (m_currentSize & 0x80000000)
			{
				for ( unsigned int i = 0; i < nb; i++ )
				{
					*m_link[ inputBytes[ i<<2 ] ]++ = i;
				}
				m_currentSize &= 0x7fffffff;
			}
			else
			{
				for ( UIntVectorData::ValueType::const_iterator it = m_ranks->readable().begin(); it != m_ranks->readable().end(); ++it )
				{
					unsigned int id = *it;
					*m_link[ inputBytes[ id << 2 ] ]++ = id;
				}
			}

			std::swap( m_ranks, m_ranks2 );
		}
	}

	return m_ranks->readable();
}

template<typename T>
bool RadixSort::createHistograms( const std::vector<T> &input )
{
	BOOST_STATIC_ASSERT( sizeof(T) == 4 );

	memset( &m_histogram[0], 0, 256 * 4 * sizeof( unsigned int ) );

	const unsigned char *p = reinterpret_cast< const unsigned char * > ( &input[0] );
	const unsigned char *pEnd = &p[ input.size() * 4 ] ;

	unsigned int *h0 = &m_histogram[0];
	unsigned int *h1 = &m_histogram[256];
	unsigned int *h2 = &m_histogram[512];
	unsigned int *h3 = &m_histogram[768];

	bool alreadySorted = true;

	if ( m_currentSize & 0x80000000 )
	{
		const T *running = &input[0];
		T prevVal = *running;

		while ( p != pEnd )
		{
			T val = *running++;

			if ( val < prevVal )
			{
				alreadySorted = false;
				break;
			}

			prevVal = val;

			h0[ *p++ ] ++;
			h1[ *p++ ] ++;
			h2[ *p++ ] ++;
			h3[ *p++ ] ++;
		}

		if ( alreadySorted )
		{
			for ( unsigned int i = 0; i < input.size(); i ++ )
			{
				m_ranks->writable()[i] = i;
			}
			return true;
		}
	}
	else
	{
		const unsigned int* indices = &m_ranks->readable()[0];
		T prevVal = input[ *indices ];

		while ( p != pEnd )
		{
			T val = input[ *indices++ ];
			if ( val < prevVal )
			{
				alreadySorted = false;
				break;
			}

			prevVal = val;

			h0[ *p++ ] ++;
			h1[ *p++ ] ++;
			h2[ *p++ ] ++;
			h3[ *p++ ] ++;
		}

		if ( alreadySorted )
		{
			return true;
		}

	}

	while ( p != pEnd )
	{
		h0[ *p++ ] ++;
		h1[ *p++ ] ++;
		h2[ *p++ ] ++;
		h3[ *p++ ] ++;
	}

	return false;
}

<|endoftext|>


<commit_before>#include "KittlerThreshold.h"

KittlerThreshold::KittlerThreshold(std::string fileName)
    : BaseImage(fileName, 0, 0)
    , m_lPointerOffsetForResult(0)
    , m_usUserThreshold(0)
    , m_ppResult(NULL)
{
    CreateHisto(m_ppImageMatrix, m_iColumns, m_iRows, UCHAR_MAX+1);
}

KittlerThreshold::~KittlerThreshold()
{
}

void KittlerThreshold::Filter()
{
    Filter(m_ppImageMatrix);
}

void KittlerThreshold::Filter(unsigned char** input)
{
    Filter(input, m_iColumns, m_iRows);
}

void KittlerThreshold::Filter(unsigned char** input, int col, int row)
{
    int i = 0, j = 0;
    int first = 255, last = 0;
    double mu1Prev = 0.0, mu1 = 0.0, mu2Prev = 0.0, mu2 = 0.0,
           var1Prev = 0.0, var1 = 0.0, var2Prev = 0, var2 = 0.0,
           q1 = 0, q2 = 0, q1Prev = 0, q2Prev = 0, mu = 0.0, H = 0.0;
    double threshold = 255;
    int threshold_i = 255;

    m_ppResult = (unsigned char**)BaseImage::CreateMatrix(m_iColumns, m_iRows, 0, 0, sizeof(unsigned char), &m_lPointerOffsetForResult);

    for(i=1;i<UCHAR_MAX;i++)
    {
        if(m_dP[i] != 0 && m_dP[i+1] != 0 && first > i)
        {
            first = i;
        }

        if(m_dP[i] != 0 && m_dP[i+1] != 0)
        {
            last = i;
        }
    }

    q1Prev = m_dP[first];
    q2Prev = 1-q1Prev;
    q1 = q1Prev;
    q2 = q2Prev;

    for(i=0;i<=UCHAR_MAX;i++)
    {
        mu += m_dP[i]*i;
    }

    mu1Prev = first;
    mu1 = mu1Prev;
    mu2Prev = Mean(first+1, UCHAR_MAX+1);
    //mu2Prev = (mu-mu1*q1)/q2;
    mu2 = mu2Prev;

    //var1Prev = 0.0;
    var1Prev = (first-mu1)*(first-mu1)*m_dP[first]/q1;
    var1 = var1Prev;
    /*for(i=first+1;i<last;i++)
    {
        var2Prev += m_dP[i]*i*i;
    }
    var2Prev -= mu2*mu2;*/
    for(i=first;i<last;i++)
    {
        var2Prev += (i-mu2)*(i-mu2)*m_dP[i]/q2;
    }
    var2 = var2Prev;

    for(i=first+1;i<last;i++)
    {
        q1 = q1Prev+m_dP[i];
        q2 = 1-q1;
        /*if(q1 == 0 || q2 == 0)
        {
            q1Prev = q1;
            q2Prev = q2;
            mu1Prev = mu1;
            mu2Prev = mu2;
            var1Prev = var1;
            var2Prev = var2;
            continue;
        }*/

        mu1 = (q1Prev*mu1Prev+i*m_dP[i])/q1;
        var1 = (q1Prev*(var1Prev+(mu1Prev-mu1)*(mu1Prev-mu1))+
                m_dP[i]*(i-mu1)*(i-mu1))/q1;

        mu2 = (mu-q1*mu1)/q2;
        var2 = (q2Prev*(var2Prev+(mu2Prev-mu2)*(mu2Prev-mu2))-
                m_dP[i]*(i-mu2)*(i-mu2))/q2;

        /*if(var1 <= 0 || var2 <= 0)
        {
            q1Prev = q1;
            q2Prev = q2;
            mu1Prev = mu1;
            mu2Prev = mu2;
            var1Prev = var1;
            var2Prev = var2;
            continue;
        }*/

        H = (q1*log(var1)+q2*log(var2))/2-q1*log(q1)-q2*log(q2);
        if(H<threshold)
        {
            threshold = H;
            threshold_i = i;
        }
#ifdef _DEBUG
        std::cout<</*i<<": "<<*/H<<std::endl;
#endif
        q1Prev = q1;
        q2Prev = q2;
        mu1Prev = mu1;
        mu2Prev = mu2;
        var1Prev = var1;
        var2Prev = var2;
    }

    if(m_usUserThreshold>0)
    {
        threshold_i = m_usUserThreshold;
    }

    for(i=0;i<row;i++)
    {
        for(j=0;j<col;j++)
        {
            if(m_ppImageMatrix[i][j]>=threshold_i)
            {
                m_ppResult[i][j] = 255;
            }
            else
            {
                m_ppResult[i][j] = 0; // Black foreground
            }
        }
    }
}

void KittlerThreshold::SaveResult(std::string filename)
{
    SaveResult(filename, m_iColumns, m_iRows);
}

void KittlerThreshold::SaveResult(std::string filename, int col, int row)
{
    WriteToFile(filename, m_ppResult, 0, 0, col, row);
}

void KittlerThreshold::SetColumns(int col)
{
    m_iColumns = col;
}

void KittlerThreshold::SetRows(int row)
{
    m_iRows = row;
}

void KittlerThreshold::SetUserThreshold(unsigned short t)
{
    m_usUserThreshold = t;
}
<commit_msg>Memory management fix<commit_after>#include "KittlerThreshold.h"

KittlerThreshold::KittlerThreshold(std::string fileName)
    : BaseImage(fileName, 0, 0)
    , m_lPointerOffsetForResult(0)
    , m_usUserThreshold(0)
    , m_ppResult(NULL)
{
    CreateHisto(m_ppImageMatrix, m_iColumns, m_iRows, UCHAR_MAX+1);
}

KittlerThreshold::~KittlerThreshold()
{
    if(m_ppResult != NULL)
    {
        m_ppResult + m_lPointerOffsetForResult;
        free(m_ppResult);
        m_ppResult = NULL;
    }
}

void KittlerThreshold::Filter()
{
    Filter(m_ppImageMatrix);
}

void KittlerThreshold::Filter(unsigned char** input)
{
    Filter(input, m_iColumns, m_iRows);
}

void KittlerThreshold::Filter(unsigned char** input, int col, int row)
{
    int i = 0, j = 0;
    int first = 255, last = 0;
    double mu1Prev = 0.0, mu1 = 0.0, mu2Prev = 0.0, mu2 = 0.0,
           var1Prev = 0.0, var1 = 0.0, var2Prev = 0, var2 = 0.0,
           q1 = 0, q2 = 0, q1Prev = 0, q2Prev = 0, mu = 0.0, H = 0.0;
    double threshold = 255;
    int threshold_i = 255;

    m_ppResult = (unsigned char**)BaseImage::CreateMatrix(m_iColumns, m_iRows, 0, 0, sizeof(unsigned char), &m_lPointerOffsetForResult);

    for(i=1;i<UCHAR_MAX;i++)
    {
        if(m_dP[i] != 0 && m_dP[i+1] != 0 && first > i)
        {
            first = i;
        }

        if(m_dP[i] != 0 && m_dP[i+1] != 0)
        {
            last = i;
        }
    }

    q1Prev = m_dP[first];
    q2Prev = 1-q1Prev;
    q1 = q1Prev;
    q2 = q2Prev;

    for(i=0;i<=UCHAR_MAX;i++)
    {
        mu += m_dP[i]*i;
    }

    mu1Prev = first;
    mu1 = mu1Prev;
    mu2Prev = Mean(first+1, UCHAR_MAX+1);
    //mu2Prev = (mu-mu1*q1)/q2;
    mu2 = mu2Prev;

    //var1Prev = 0.0;
    var1Prev = (first-mu1)*(first-mu1)*m_dP[first]/q1;
    var1 = var1Prev;
    /*for(i=first+1;i<last;i++)
    {
        var2Prev += m_dP[i]*i*i;
    }
    var2Prev -= mu2*mu2;*/
    for(i=first;i<last;i++)
    {
        var2Prev += (i-mu2)*(i-mu2)*m_dP[i]/q2;
    }
    var2 = var2Prev;

    for(i=first+1;i<last;i++)
    {
        q1 = q1Prev+m_dP[i];
        q2 = 1-q1;
        /*if(q1 == 0 || q2 == 0)
        {
            q1Prev = q1;
            q2Prev = q2;
            mu1Prev = mu1;
            mu2Prev = mu2;
            var1Prev = var1;
            var2Prev = var2;
            continue;
        }*/

        mu1 = (q1Prev*mu1Prev+i*m_dP[i])/q1;
        var1 = (q1Prev*(var1Prev+(mu1Prev-mu1)*(mu1Prev-mu1))+
                m_dP[i]*(i-mu1)*(i-mu1))/q1;

        mu2 = (mu-q1*mu1)/q2;
        var2 = (q2Prev*(var2Prev+(mu2Prev-mu2)*(mu2Prev-mu2))-
                m_dP[i]*(i-mu2)*(i-mu2))/q2;

        /*if(var1 <= 0 || var2 <= 0)
        {
            q1Prev = q1;
            q2Prev = q2;
            mu1Prev = mu1;
            mu2Prev = mu2;
            var1Prev = var1;
            var2Prev = var2;
            continue;
        }*/

        H = (q1*log(var1)+q2*log(var2))/2-q1*log(q1)-q2*log(q2);
        if(H<threshold)
        {
            threshold = H;
            threshold_i = i;
        }
#ifdef _DEBUG
        std::cout<</*i<<": "<<*/H<<std::endl;
#endif
        q1Prev = q1;
        q2Prev = q2;
        mu1Prev = mu1;
        mu2Prev = mu2;
        var1Prev = var1;
        var2Prev = var2;
    }

    if(m_usUserThreshold>0)
    {
        threshold_i = m_usUserThreshold;
    }

    for(i=0;i<row;i++)
    {
        for(j=0;j<col;j++)
        {
            if(m_ppImageMatrix[i][j]>=threshold_i)
            {
                m_ppResult[i][j] = 255;
            }
            else
            {
                m_ppResult[i][j] = 0; // Black foreground
            }
        }
    }
}

void KittlerThreshold::SaveResult(std::string filename)
{
    SaveResult(filename, m_iColumns, m_iRows);
}

void KittlerThreshold::SaveResult(std::string filename, int col, int row)
{
    WriteToFile(filename, m_ppResult, 0, 0, col, row);
}

void KittlerThreshold::SetColumns(int col)
{
    m_iColumns = col;
}

void KittlerThreshold::SetRows(int row)
{
    m_iRows = row;
}

void KittlerThreshold::SetUserThreshold(unsigned short t)
{
    m_usUserThreshold = t;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: gendict.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: kz $ $Date: 2005-11-01 14:52:06 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sal/main.h>
#include <sal/types.h>
#include <rtl/strbuf.hxx>
#include <rtl/ustring.hxx>

using namespace ::rtl;

/* Main Procedure */

SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv)
{
    FILE *sfp, *cfp;

    if (argc < 3) exit(-1);

    sfp = fopen(argv[1], "rb"); // open the source file for read;
    if (sfp == NULL)
        printf("Open the dictionary source file failed.");

    // create the C source file to write
    cfp = fopen(argv[2], "wb");
    if (cfp == NULL) {
        fclose(sfp);
        printf("Can't create the C source file.");
    }

    fprintf(cfp, "/*\n");
    fprintf(cfp, " * Copyright(c) 1999 - 2000, Sun Microsystems, Inc.\n");
    fprintf(cfp, " * All Rights Reserved.\n");
    fprintf(cfp, " */\n\n");
    fprintf(cfp, "/* !!!The file is generated automatically. DONOT edit the file manually!!! */\n\n");
    fprintf(cfp, "#include <sal/types.h>\n\n");
    fprintf(cfp, "extern \"C\" {\n");

    sal_Int32 count, i, j;
    sal_Int32 lenArrayCurr = 0, lenArrayCount = 0, lenArrayLen = 0, *lenArray = NULL, charArray[0x10000];
    sal_Bool exist[0x10000];
    for (i = 0; i < 0x10000; i++) {
        exist[i] = sal_False;
        charArray[i] = 0;
    }

    // generate main dict. data array
    fprintf(cfp, "static const sal_Unicode dataArea[] = {");
    sal_Char str[1024];
    sal_Unicode current = 0;
    count = 0;
    while (fgets(str, 1024, sfp)) {
        // input file is in UTF-8 encoding
        // don't convert last new line character to Ostr.
        OUString Ostr((const sal_Char *)str, strlen(str) - 1, RTL_TEXTENCODING_UTF8);
        const sal_Unicode *u = Ostr.getStr();

        sal_Int32 len = Ostr.getLength();

        if (len == 1) continue; // skip one character word

        if (*u != current) {
        if (*u < current)
        printf("u %x, current %x, count %d, lenArrayCount %d\n", *u, current, count, lenArrayCount);
        current = *u;
        charArray[current] = lenArrayCount;
        }

        if (lenArrayLen <= lenArrayCount+1)
        lenArray = (sal_Int32*) realloc(lenArray, (lenArrayLen += 1000) * sizeof(sal_Int32));
        lenArray[lenArrayCount++] = lenArrayCurr;

        exist[u[0]] = sal_True;
        for (i = 1; i < len; i++) {     // start from second character,
        exist[u[i]] = sal_True;     // since the first character is captured in charArray.
        lenArrayCurr++;
        if ((count++) % 0x10 == 0)
            fprintf(cfp, "\n\t");
        fprintf(cfp, "0x%04x, ", u[i]);
        }
    }
    lenArray[lenArrayCount++] = lenArrayCurr; // store last ending pointer
    charArray[current+1] = lenArrayCount;
    fprintf(cfp, "\n};\n");

    // generate lenArray
    fprintf(cfp, "static const sal_Int32 lenArray[] = {\n\t");
    count = 1;
    fprintf(cfp, "0x%x, ", 0); // insert one slat for skipping 0 in index2 array.
    for (i = 0; i < lenArrayCount; i++) {
        fprintf(cfp, "0x%lx, ", lenArray[i]);
        if (count == 0xf) {
        count = 0;
        fprintf(cfp, "\n\t");
        } else count++;
    }
    fprintf(cfp, "\n};\n");

    free(lenArray);

    // generate index1 array
    fprintf (cfp, "static const sal_Int16 index1[] = {\n\t");
    sal_Int16 set[0x100];
    count = 0;
    for (i = 0; i < 0x100; i++) {
        for (j = 0; j < 0x100; j++)
        if (charArray[(i*0x100) + j] != 0)
            break;

        fprintf(cfp, "0x%02x, ", set[i] = (j < 0x100 ? count++ : 0xff));
        if ((i+1) % 0x10 == 0)
        fprintf (cfp, "\n\t");
    }
    fprintf (cfp, "};\n");

    // generate index2 array
    fprintf (cfp, "static const sal_Int32 index2[] = {\n\t");
    sal_Int32 prev = 0, curr = 0;;
    for (i = 0; i < 0x100; i++) {
        if (set[i] != 0xff) {
        for (j = 0; j < 0x100; j++) {
            sal_Int32 k = (i*0x100) + j;
            if (prev != 0 && charArray[k] == 0) {
            for (k++; k < 0x10000; k++)
                if (charArray[k] != 0)
                break;
            }
            prev = charArray[(i*0x100) + j];
            fprintf(cfp, "0x%x, ", k < 0x10000 ? charArray[k] + 1 : 0);
            if ((j+1) % 0x10 == 0)
            fprintf (cfp, "\n\t");
        }
        fprintf (cfp, "\n\t");
        }
    }
    fprintf (cfp, "\n};\n");

    // generate existMark array
    count = 0;
    fprintf (cfp, "static const sal_uInt8 existMark[] = {\n\t");
    for (i = 0; i < 0x1FFF; i++) {
        sal_uInt8 bit = 0;
        for (j = 0; j < 8; j++)
        if (exist[i * 8 + j])
            bit |= 1 << j;
        fprintf(cfp, "0x%02x, ", bit);
        if (count == 0xf) {
        count = 0;
        fprintf(cfp, "\n\t");
        } else count++;
    }
    fprintf (cfp, "\n};\n");

    // create function to return arrays
    fprintf (cfp, "\tconst sal_uInt8* getExistMark() { return existMark; }\n");
    fprintf (cfp, "\tconst sal_Int16* getIndex1() { return index1; }\n");
    fprintf (cfp, "\tconst sal_Int32* getIndex2() { return index2; }\n");
    fprintf (cfp, "\tconst sal_Int32* getLenArray() { return lenArray; }\n");
    fprintf (cfp, "\tconst sal_Unicode* getDataArea() { return dataArea; }\n");
    fprintf (cfp, "}\n");

    fclose(sfp);
    fclose(cfp);

    return 0;
}   // End of main
<commit_msg>INTEGRATION: CWS warnings01 (1.4.14); FILE MERGED 2006/03/08 13:19:08 nn 1.4.14.3: #i53898# warning-free code 2005/11/07 19:46:39 pl 1.4.14.2: RESYNC: (1.4-1.5); FILE MERGED 2005/10/24 14:55:13 nn 1.4.14.1: #i53898# warning-free code<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: gendict.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-20 04:42:18 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sal/main.h>
#include <sal/types.h>
#include <rtl/strbuf.hxx>
#include <rtl/ustring.hxx>

using namespace ::rtl;

/* Main Procedure */

SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv)
{
    FILE *sfp, *cfp;

    if (argc < 3) exit(-1);

    sfp = fopen(argv[1], "rb"); // open the source file for read;
    if (sfp == NULL)
        printf("Open the dictionary source file failed.");

    // create the C source file to write
    cfp = fopen(argv[2], "wb");
    if (cfp == NULL) {
        fclose(sfp);
        printf("Can't create the C source file.");
    }

    fprintf(cfp, "/*\n");
    fprintf(cfp, " * Copyright(c) 1999 - 2000, Sun Microsystems, Inc.\n");
    fprintf(cfp, " * All Rights Reserved.\n");
    fprintf(cfp, " */\n\n");
    fprintf(cfp, "/* !!!The file is generated automatically. DONOT edit the file manually!!! */\n\n");
    fprintf(cfp, "#include <sal/types.h>\n\n");
    fprintf(cfp, "extern \"C\" {\n");

    sal_Int32 count, i, j;
    sal_Int32 lenArrayCurr = 0, lenArrayCount = 0, lenArrayLen = 0, *lenArray = NULL, charArray[0x10000];
    sal_Bool exist[0x10000];
    for (i = 0; i < 0x10000; i++) {
        exist[i] = sal_False;
        charArray[i] = 0;
    }

    // generate main dict. data array
    fprintf(cfp, "static const sal_Unicode dataArea[] = {");
    sal_Char str[1024];
    sal_Unicode current = 0;
    count = 0;
    while (fgets(str, 1024, sfp)) {
        // input file is in UTF-8 encoding
        // don't convert last new line character to Ostr.
        OUString Ostr((const sal_Char *)str, strlen(str) - 1, RTL_TEXTENCODING_UTF8);
        const sal_Unicode *u = Ostr.getStr();

        sal_Int32 len = Ostr.getLength();

        if (len == 1) continue; // skip one character word

        if (*u != current) {
        if (*u < current)
        printf("u %x, current %x, count %d, lenArrayCount %d\n", *u, current,
                    sal::static_int_cast<int>(count), sal::static_int_cast<int>(lenArrayCount));
        current = *u;
        charArray[current] = lenArrayCount;
        }

        if (lenArrayLen <= lenArrayCount+1)
        lenArray = (sal_Int32*) realloc(lenArray, (lenArrayLen += 1000) * sizeof(sal_Int32));
        lenArray[lenArrayCount++] = lenArrayCurr;

        exist[u[0]] = sal_True;
        for (i = 1; i < len; i++) {     // start from second character,
        exist[u[i]] = sal_True;     // since the first character is captured in charArray.
        lenArrayCurr++;
        if ((count++) % 0x10 == 0)
            fprintf(cfp, "\n\t");
        fprintf(cfp, "0x%04x, ", u[i]);
        }
    }
    lenArray[lenArrayCount++] = lenArrayCurr; // store last ending pointer
    charArray[current+1] = lenArrayCount;
    fprintf(cfp, "\n};\n");

    // generate lenArray
    fprintf(cfp, "static const sal_Int32 lenArray[] = {\n\t");
    count = 1;
    fprintf(cfp, "0x%x, ", 0); // insert one slat for skipping 0 in index2 array.
    for (i = 0; i < lenArrayCount; i++) {
        fprintf(cfp, "0x%lx, ", lenArray[i]);
        if (count == 0xf) {
        count = 0;
        fprintf(cfp, "\n\t");
        } else count++;
    }
    fprintf(cfp, "\n};\n");

    free(lenArray);

    // generate index1 array
    fprintf (cfp, "static const sal_Int16 index1[] = {\n\t");
    sal_Int16 set[0x100];
    count = 0;
    for (i = 0; i < 0x100; i++) {
        for (j = 0; j < 0x100; j++)
        if (charArray[(i*0x100) + j] != 0)
            break;

        fprintf(cfp, "0x%02x, ", set[i] = (j < 0x100 ? sal::static_int_cast<sal_Int16>(count++) : 0xff));
        if ((i+1) % 0x10 == 0)
        fprintf (cfp, "\n\t");
    }
    fprintf (cfp, "};\n");

    // generate index2 array
    fprintf (cfp, "static const sal_Int32 index2[] = {\n\t");
    sal_Int32 prev = 0;
    for (i = 0; i < 0x100; i++) {
        if (set[i] != 0xff) {
        for (j = 0; j < 0x100; j++) {
            sal_Int32 k = (i*0x100) + j;
            if (prev != 0 && charArray[k] == 0) {
            for (k++; k < 0x10000; k++)
                if (charArray[k] != 0)
                break;
            }
            prev = charArray[(i*0x100) + j];
            fprintf(cfp, "0x%x, ", k < 0x10000 ? charArray[k] + 1 : 0);
            if ((j+1) % 0x10 == 0)
            fprintf (cfp, "\n\t");
        }
        fprintf (cfp, "\n\t");
        }
    }
    fprintf (cfp, "\n};\n");

    // generate existMark array
    count = 0;
    fprintf (cfp, "static const sal_uInt8 existMark[] = {\n\t");
    for (i = 0; i < 0x1FFF; i++) {
        sal_uInt8 bit = 0;
        for (j = 0; j < 8; j++)
        if (exist[i * 8 + j])
            bit |= 1 << j;
        fprintf(cfp, "0x%02x, ", bit);
        if (count == 0xf) {
        count = 0;
        fprintf(cfp, "\n\t");
        } else count++;
    }
    fprintf (cfp, "\n};\n");

    // create function to return arrays
    fprintf (cfp, "\tconst sal_uInt8* getExistMark() { return existMark; }\n");
    fprintf (cfp, "\tconst sal_Int16* getIndex1() { return index1; }\n");
    fprintf (cfp, "\tconst sal_Int32* getIndex2() { return index2; }\n");
    fprintf (cfp, "\tconst sal_Int32* getLenArray() { return lenArray; }\n");
    fprintf (cfp, "\tconst sal_Unicode* getDataArea() { return dataArea; }\n");
    fprintf (cfp, "}\n");

    fclose(sfp);
    fclose(cfp);

    return 0;
}   // End of main
<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2009 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

#include "OgreGLSLESLinkProgram.h"
#include "OgreGLSLESExtSupport.h"
#include "OgreGLSLESGpuProgram.h"
#include "OgreGLSLESProgram.h"
#include "OgreGLSLESLinkProgramManager.h"
#include "OgreStringVector.h"
#include "OgreLogManager.h"
#include "OgreGpuProgramManager.h"
#include "OgreStringConverter.h"

namespace Ogre {

	//-----------------------------------------------------------------------
	GLSLESLinkProgram::GLSLESLinkProgram(GLSLESGpuProgram* vertexProgram, GLSLESGpuProgram* fragmentProgram)
        : mVertexProgram(vertexProgram)
		, mFragmentProgram(fragmentProgram)
		, mUniformRefsBuilt(false)
        , mLinked(false)
		, mTriedToLinkAndFailed(false)
	{
		// init CustomAttributesIndexs
		for(size_t i = 0 ; i < VES_COUNT; i++)
			for(size_t j = 0 ; j < OGRE_MAX_TEXTURE_COORD_SETS; j++)
		{
			mCustomAttributesIndexes[i][j] = NULL_CUSTOM_ATTRIBUTES_INDEX;
		}

        if (!mVertexProgram && !mFragmentProgram)
        {
            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
                        "Attempted to create a shader program without both a vertex and fragment program.",
                        "GLSLESLinkProgram::GLSLESLinkProgram");
        }
	}

	//-----------------------------------------------------------------------
	GLSLESLinkProgram::~GLSLESLinkProgram(void)
	{
		glDeleteProgram(mGLHandle);
        GL_CHECK_ERROR;
	}

	//-----------------------------------------------------------------------
	Ogre::String GLSLESLinkProgram::getCombinedName()
	{
		String name;
		if (mVertexProgram)
		{
			name += "Vertex Program:" ;
			name += mVertexProgram->getName();
		}
		if (mFragmentProgram)
		{
			name += " Fragment Program:" ;
			name += mFragmentProgram->getName();
		}
		return name;
	}
	//-----------------------------------------------------------------------
	void GLSLESLinkProgram::activate(void)
	{
		if (!mLinked && !mTriedToLinkAndFailed)
		{
			glGetError(); // Clean up the error. Otherwise will flood log.
			mGLHandle = glCreateProgram();
			GL_CHECK_ERROR

			if ( GpuProgramManager::getSingleton().canGetCompiledShaderBuffer() &&
				GpuProgramManager::getSingleton().isMicrocodeAvailableInCache(getCombinedName()) )
			{
				getMicrocodeFromCache();
			}
			else
			{
				compileAndLink();
			}

			buildGLUniformReferences();
		}

		if (mLinked)
		{
            GL_CHECK_ERROR
            glUseProgram( mGLHandle );
            GL_CHECK_ERROR
		}
	}
	//-----------------------------------------------------------------------
	void GLSLESLinkProgram::getMicrocodeFromCache(void)
	{
		GpuProgramManager::Microcode cacheMicrocode =
			GpuProgramManager::getSingleton().getMicrocodeFromCache(getCombinedName());

		// add to the microcode to the cache
		String name;
		name = getCombinedName();

		// turns out we need this param when loading
		GLenum binaryFormat = 0;

		cacheMicrocode->seek(0);

		// get size of binary
		cacheMicrocode->read(&binaryFormat, sizeof(GLenum));

#if GL_OES_get_program_binary
		// load binary
		glProgramBinaryOES( mGLHandle,
							binaryFormat,
							cacheMicrocode->getPtr(),
							binaryLength
			);
#endif
		GLint   success = 0;
		glGetProgramiv(mGLHandle, GL_LINK_STATUS, &success);
		if (!success)
		{
			//
			// Something must have changed since the program binaries
			// were cached away.  Fallback to source shader loading path,
			// and then retrieve and cache new program binaries once again.
			//
			compileAndLink();
		}

	}

	//-----------------------------------------------------------------------
	void GLSLESLinkProgram::compileAndLink()
	{
		// compile and attach Vertex Program
		if (!mVertexProgram->getGLSLProgram()->compile(true))
		{
			// todo error
			return;
		}
        mVertexProgram->getGLSLProgram()->attachToProgramObject(mGLHandle);
        setSkeletalAnimationIncluded(mVertexProgram->isSkeletalAnimationIncluded());

		// compile and attach Fragment Program
		if (!mFragmentProgram->getGLSLProgram()->compile(true))
		{
			// todo error
			return;
		}
        mFragmentProgram->getGLSLProgram()->attachToProgramObject(mGLHandle);

		// the link
		glLinkProgram( mGLHandle );
		GL_CHECK_ERROR
			glGetProgramiv( mGLHandle, GL_LINK_STATUS, &mLinked );
		GL_CHECK_ERROR

		mTriedToLinkAndFailed = !mLinked;

		logObjectInfo( getCombinedName() + String("GLSL link result : "), mGLHandle );
		if(mLinked)
		{
			if ( GpuProgramManager::getSingleton().getSaveMicrocodesToCache() )
			{
				// add to the microcode to the cache
				String name;
				name = getCombinedName();

				// get buffer size
				GLint binaryLength = 0;
#if GL_OES_get_program_binary
				glGetProgramiv(mGLHandle, GL_PROGRAM_BINARY_LENGTH_OES, &binaryLength);
#endif

                // create microcode
                GpuProgramManager::Microcode newMicrocode =
                    GpuProgramManager::getSingleton().createMicrocode(binaryLength + sizeof(GLenum));

#if GL_OES_get_program_binary
				// get binary
				glGetProgramBinaryOES(mGLHandle, binaryLength, NULL, (GLenum *)newMicrocode->getPtr(), newMicrocode->getPtr() + sizeof(GLenum));
#endif

        		// add to the microcode to the cache
				GpuProgramManager::getSingleton().addMicrocodeToCache(name, newMicrocode);
			}
		}
	}
	//-----------------------------------------------------------------------
	const char * getAttributeSemanticString(VertexElementSemantic semantic)
	{
		switch(semantic)
		{
			case VES_POSITION:
				return "vertex";
			case VES_BLEND_WEIGHTS:
				return "blendWeights";
			case VES_NORMAL:
				return "normal";
			case VES_DIFFUSE:
				return "colour";
			case VES_SPECULAR:
				return "secondary_colour";
			case VES_BLEND_INDICES:
				return "blendIndices";
			case VES_TANGENT:
				return "tangent";
			case VES_BINORMAL:
				return "binormal";
			case VES_TEXTURE_COORDINATES:
				return "uv";
			default:
				assert(false && "Missing attribute!");
				return 0;
		};

	}
	//-----------------------------------------------------------------------
	GLuint GLSLESLinkProgram::getAttributeIndex(VertexElementSemantic semantic, uint index)
	{
		GLint res = mCustomAttributesIndexes[semantic-1][index];
		if (res == NULL_CUSTOM_ATTRIBUTES_INDEX)
		{
			const char * attString = getAttributeSemanticString(semantic);
			GLint attrib = glGetAttribLocation(mGLHandle, attString);

			// sadly position is a special case
			if (attrib == NOT_FOUND_CUSTOM_ATTRIBUTES_INDEX && semantic == VES_POSITION)
			{
				attrib = glGetAttribLocation(mGLHandle, "position");
			}

			// for uv and other case the index is a part of the name
			if (attrib == NOT_FOUND_CUSTOM_ATTRIBUTES_INDEX)
			{
				String attStringWithSemantic = String(attString) + StringConverter::toString(index);
				attrib = glGetAttribLocation(mGLHandle, attStringWithSemantic.c_str());
			}

			// update mCustomAttributesIndexes with the index we found (or didn't find)
			mCustomAttributesIndexes[semantic-1][index] = attrib;
			res = attrib;
		}
		return (GLuint)res;
	}
	//-----------------------------------------------------------------------
	bool GLSLESLinkProgram::isAttributeValid(VertexElementSemantic semantic, uint index)
	{
		return (GLint)(getAttributeIndex(semantic, index)) != NOT_FOUND_CUSTOM_ATTRIBUTES_INDEX;
	}
	//-----------------------------------------------------------------------
	void GLSLESLinkProgram::buildGLUniformReferences(void)
	{
		if (!mUniformRefsBuilt)
		{
			const GpuConstantDefinitionMap* vertParams = 0;
			const GpuConstantDefinitionMap* fragParams = 0;
			if (mVertexProgram)
			{
				vertParams = &(mVertexProgram->getGLSLProgram()->getConstantDefinitions().map);
			}
			if (mFragmentProgram)
			{
				fragParams = &(mFragmentProgram->getGLSLProgram()->getConstantDefinitions().map);
			}

			GLSLESLinkProgramManager::getSingleton().extractUniforms(
				mGLHandle, vertParams, fragParams, mGLUniformReferences);

			mUniformRefsBuilt = true;
		}
	}

	//-----------------------------------------------------------------------
	void GLSLESLinkProgram::updateUniforms(GpuProgramParametersSharedPtr params,
		uint16 mask, GpuProgramType fromProgType)
	{
		// Iterate through uniform reference list and update uniform values
		GLUniformReferenceIterator currentUniform = mGLUniformReferences.begin();
		GLUniformReferenceIterator endUniform = mGLUniformReferences.end();

		for (;currentUniform != endUniform; ++currentUniform)
		{
			// Only pull values from buffer it's supposed to be in (vertex or fragment)
			// This method will be called twice, once for vertex program params,
			// and once for fragment program params.
			if (fromProgType == currentUniform->mSourceProgType)
			{
				const GpuConstantDefinition* def = currentUniform->mConstantDef;
				if (def->variability & mask)
				{
					GLsizei glArraySize = (GLsizei)def->arraySize;

					// Get the index in the parameter real list
					switch (def->constType)
					{
					case GCT_FLOAT1:
						glUniform1fv(currentUniform->mLocation, glArraySize,
							params->getFloatPointer(def->physicalIndex));
						break;
					case GCT_FLOAT2:
						glUniform2fv(currentUniform->mLocation, glArraySize,
							params->getFloatPointer(def->physicalIndex));
						break;
					case GCT_FLOAT3:
						glUniform3fv(currentUniform->mLocation, glArraySize,
							params->getFloatPointer(def->physicalIndex));
						break;
					case GCT_FLOAT4:
						glUniform4fv(currentUniform->mLocation, glArraySize,
							params->getFloatPointer(def->physicalIndex));
						break;
					case GCT_MATRIX_2X2:
						glUniformMatrix2fv(currentUniform->mLocation, glArraySize,
							GL_FALSE, params->getFloatPointer(def->physicalIndex));
						break;
					case GCT_MATRIX_3X3:
						glUniformMatrix3fv(currentUniform->mLocation, glArraySize,
							GL_FALSE, params->getFloatPointer(def->physicalIndex));
						break;
					case GCT_MATRIX_4X4:
						glUniformMatrix4fv(currentUniform->mLocation, glArraySize,
							GL_FALSE, params->getFloatPointer(def->physicalIndex));
						break;
					case GCT_INT1:
						glUniform1iv(currentUniform->mLocation, glArraySize,
							(GLint*)params->getIntPointer(def->physicalIndex));
						break;
					case GCT_INT2:
						glUniform2iv(currentUniform->mLocation, glArraySize,
							(GLint*)params->getIntPointer(def->physicalIndex));
						break;
					case GCT_INT3:
						glUniform3iv(currentUniform->mLocation, glArraySize,
							(GLint*)params->getIntPointer(def->physicalIndex));
						break;
					case GCT_INT4:
						glUniform4iv(currentUniform->mLocation, glArraySize,
							(GLint*)params->getIntPointer(def->physicalIndex));
						break;
					case GCT_SAMPLER1D:
					case GCT_SAMPLER1DSHADOW:
					case GCT_SAMPLER2D:
					case GCT_SAMPLER2DSHADOW:
					case GCT_SAMPLER3D:
					case GCT_SAMPLERCUBE:
						// Samplers handled like 1-element ints
						glUniform1iv(currentUniform->mLocation, 1,
							(GLint*)params->getIntPointer(def->physicalIndex));
						break;
					case GCT_MATRIX_2X3:
					case GCT_MATRIX_2X4:
					case GCT_MATRIX_3X2:
					case GCT_MATRIX_3X4:
					case GCT_MATRIX_4X2:
					case GCT_MATRIX_4X3:
                    case GCT_UNKNOWN:
                        break;

					} // End switch
                    GL_CHECK_ERROR;
				} // Variability & mask
			} // fromProgType == currentUniform->mSourceProgType

  		} // End for
	}
	//-----------------------------------------------------------------------
	void GLSLESLinkProgram::updatePassIterationUniforms(GpuProgramParametersSharedPtr params)
	{
		if (params->hasPassIterationNumber())
		{
			size_t index = params->getPassIterationNumberIndex();

			GLUniformReferenceIterator currentUniform = mGLUniformReferences.begin();
			GLUniformReferenceIterator endUniform = mGLUniformReferences.end();

			// Need to find the uniform that matches the multi pass entry
			for (;currentUniform != endUniform; ++currentUniform)
			{
				// Get the index in the parameter real list
				if (index == currentUniform->mConstantDef->physicalIndex)
				{
					glUniform1fv(currentUniform->mLocation, 1, params->getFloatPointer(index));
                    GL_CHECK_ERROR;
					// There will only be one multipass entry
					return;
				}
			}
		}
    }
} // namespace Ogre
<commit_msg>GLES2 render system: Added a var init that was missing (binaryLength in GLSLESLinkProgram::getMicrocodeFromCache).<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2009 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

#include "OgreGLSLESLinkProgram.h"
#include "OgreGLSLESExtSupport.h"
#include "OgreGLSLESGpuProgram.h"
#include "OgreGLSLESProgram.h"
#include "OgreGLSLESLinkProgramManager.h"
#include "OgreStringVector.h"
#include "OgreLogManager.h"
#include "OgreGpuProgramManager.h"
#include "OgreStringConverter.h"

namespace Ogre {

	//-----------------------------------------------------------------------
	GLSLESLinkProgram::GLSLESLinkProgram(GLSLESGpuProgram* vertexProgram, GLSLESGpuProgram* fragmentProgram)
        : mVertexProgram(vertexProgram)
		, mFragmentProgram(fragmentProgram)
		, mUniformRefsBuilt(false)
        , mLinked(false)
		, mTriedToLinkAndFailed(false)
	{
		// init CustomAttributesIndexs
		for(size_t i = 0 ; i < VES_COUNT; i++)
			for(size_t j = 0 ; j < OGRE_MAX_TEXTURE_COORD_SETS; j++)
		{
			mCustomAttributesIndexes[i][j] = NULL_CUSTOM_ATTRIBUTES_INDEX;
		}

        if (!mVertexProgram && !mFragmentProgram)
        {
            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
                        "Attempted to create a shader program without both a vertex and fragment program.",
                        "GLSLESLinkProgram::GLSLESLinkProgram");
        }
	}

	//-----------------------------------------------------------------------
	GLSLESLinkProgram::~GLSLESLinkProgram(void)
	{
		glDeleteProgram(mGLHandle);
        GL_CHECK_ERROR;
	}

	//-----------------------------------------------------------------------
	Ogre::String GLSLESLinkProgram::getCombinedName()
	{
		String name;
		if (mVertexProgram)
		{
			name += "Vertex Program:" ;
			name += mVertexProgram->getName();
		}
		if (mFragmentProgram)
		{
			name += " Fragment Program:" ;
			name += mFragmentProgram->getName();
		}
		return name;
	}
	//-----------------------------------------------------------------------
	void GLSLESLinkProgram::activate(void)
	{
		if (!mLinked && !mTriedToLinkAndFailed)
		{
			glGetError(); // Clean up the error. Otherwise will flood log.
			mGLHandle = glCreateProgram();
			GL_CHECK_ERROR

			if ( GpuProgramManager::getSingleton().canGetCompiledShaderBuffer() &&
				GpuProgramManager::getSingleton().isMicrocodeAvailableInCache(getCombinedName()) )
			{
				getMicrocodeFromCache();
			}
			else
			{
				compileAndLink();
			}

			buildGLUniformReferences();
		}

		if (mLinked)
		{
            GL_CHECK_ERROR
            glUseProgram( mGLHandle );
            GL_CHECK_ERROR
		}
	}
	//-----------------------------------------------------------------------
	void GLSLESLinkProgram::getMicrocodeFromCache(void)
	{
		GpuProgramManager::Microcode cacheMicrocode =
			GpuProgramManager::getSingleton().getMicrocodeFromCache(getCombinedName());

		// add to the microcode to the cache
		String name;
		name = getCombinedName();

		// turns out we need this param when loading
		GLenum binaryFormat = 0;

		cacheMicrocode->seek(0);

		// get size of binary
		cacheMicrocode->read(&binaryFormat, sizeof(GLenum));

        GLint binaryLength = cacheMicrocode->size() - sizeof(GLenum);

#if GL_OES_get_program_binary
		// load binary
		glProgramBinaryOES( mGLHandle,
							binaryFormat,
							cacheMicrocode->getPtr(),
							binaryLength
			);
#endif
		GLint   success = 0;
		glGetProgramiv(mGLHandle, GL_LINK_STATUS, &success);
		if (!success)
		{
			//
			// Something must have changed since the program binaries
			// were cached away.  Fallback to source shader loading path,
			// and then retrieve and cache new program binaries once again.
			//
			compileAndLink();
		}

	}

	//-----------------------------------------------------------------------
	void GLSLESLinkProgram::compileAndLink()
	{
		// compile and attach Vertex Program
		if (!mVertexProgram->getGLSLProgram()->compile(true))
		{
			// todo error
			return;
		}
        mVertexProgram->getGLSLProgram()->attachToProgramObject(mGLHandle);
        setSkeletalAnimationIncluded(mVertexProgram->isSkeletalAnimationIncluded());

		// compile and attach Fragment Program
		if (!mFragmentProgram->getGLSLProgram()->compile(true))
		{
			// todo error
			return;
		}
        mFragmentProgram->getGLSLProgram()->attachToProgramObject(mGLHandle);

		// the link
		glLinkProgram( mGLHandle );
		GL_CHECK_ERROR
			glGetProgramiv( mGLHandle, GL_LINK_STATUS, &mLinked );
		GL_CHECK_ERROR

		mTriedToLinkAndFailed = !mLinked;

		logObjectInfo( getCombinedName() + String("GLSL link result : "), mGLHandle );
		if(mLinked)
		{
			if ( GpuProgramManager::getSingleton().getSaveMicrocodesToCache() )
			{
				// add to the microcode to the cache
				String name;
				name = getCombinedName();

				// get buffer size
				GLint binaryLength = 0;
#if GL_OES_get_program_binary
				glGetProgramiv(mGLHandle, GL_PROGRAM_BINARY_LENGTH_OES, &binaryLength);
#endif

                // create microcode
                GpuProgramManager::Microcode newMicrocode =
                    GpuProgramManager::getSingleton().createMicrocode(binaryLength + sizeof(GLenum));

#if GL_OES_get_program_binary
				// get binary
				glGetProgramBinaryOES(mGLHandle, binaryLength, NULL, (GLenum *)newMicrocode->getPtr(), newMicrocode->getPtr() + sizeof(GLenum));
#endif

        		// add to the microcode to the cache
				GpuProgramManager::getSingleton().addMicrocodeToCache(name, newMicrocode);
			}
		}
	}
	//-----------------------------------------------------------------------
	const char * getAttributeSemanticString(VertexElementSemantic semantic)
	{
		switch(semantic)
		{
			case VES_POSITION:
				return "vertex";
			case VES_BLEND_WEIGHTS:
				return "blendWeights";
			case VES_NORMAL:
				return "normal";
			case VES_DIFFUSE:
				return "colour";
			case VES_SPECULAR:
				return "secondary_colour";
			case VES_BLEND_INDICES:
				return "blendIndices";
			case VES_TANGENT:
				return "tangent";
			case VES_BINORMAL:
				return "binormal";
			case VES_TEXTURE_COORDINATES:
				return "uv";
			default:
				assert(false && "Missing attribute!");
				return 0;
		};

	}
	//-----------------------------------------------------------------------
	GLuint GLSLESLinkProgram::getAttributeIndex(VertexElementSemantic semantic, uint index)
	{
		GLint res = mCustomAttributesIndexes[semantic-1][index];
		if (res == NULL_CUSTOM_ATTRIBUTES_INDEX)
		{
			const char * attString = getAttributeSemanticString(semantic);
			GLint attrib = glGetAttribLocation(mGLHandle, attString);

			// sadly position is a special case
			if (attrib == NOT_FOUND_CUSTOM_ATTRIBUTES_INDEX && semantic == VES_POSITION)
			{
				attrib = glGetAttribLocation(mGLHandle, "position");
			}

			// for uv and other case the index is a part of the name
			if (attrib == NOT_FOUND_CUSTOM_ATTRIBUTES_INDEX)
			{
				String attStringWithSemantic = String(attString) + StringConverter::toString(index);
				attrib = glGetAttribLocation(mGLHandle, attStringWithSemantic.c_str());
			}

			// update mCustomAttributesIndexes with the index we found (or didn't find)
			mCustomAttributesIndexes[semantic-1][index] = attrib;
			res = attrib;
		}
		return (GLuint)res;
	}
	//-----------------------------------------------------------------------
	bool GLSLESLinkProgram::isAttributeValid(VertexElementSemantic semantic, uint index)
	{
		return (GLint)(getAttributeIndex(semantic, index)) != NOT_FOUND_CUSTOM_ATTRIBUTES_INDEX;
	}
	//-----------------------------------------------------------------------
	void GLSLESLinkProgram::buildGLUniformReferences(void)
	{
		if (!mUniformRefsBuilt)
		{
			const GpuConstantDefinitionMap* vertParams = 0;
			const GpuConstantDefinitionMap* fragParams = 0;
			if (mVertexProgram)
			{
				vertParams = &(mVertexProgram->getGLSLProgram()->getConstantDefinitions().map);
			}
			if (mFragmentProgram)
			{
				fragParams = &(mFragmentProgram->getGLSLProgram()->getConstantDefinitions().map);
			}

			GLSLESLinkProgramManager::getSingleton().extractUniforms(
				mGLHandle, vertParams, fragParams, mGLUniformReferences);

			mUniformRefsBuilt = true;
		}
	}

	//-----------------------------------------------------------------------
	void GLSLESLinkProgram::updateUniforms(GpuProgramParametersSharedPtr params,
		uint16 mask, GpuProgramType fromProgType)
	{
		// Iterate through uniform reference list and update uniform values
		GLUniformReferenceIterator currentUniform = mGLUniformReferences.begin();
		GLUniformReferenceIterator endUniform = mGLUniformReferences.end();

		for (;currentUniform != endUniform; ++currentUniform)
		{
			// Only pull values from buffer it's supposed to be in (vertex or fragment)
			// This method will be called twice, once for vertex program params,
			// and once for fragment program params.
			if (fromProgType == currentUniform->mSourceProgType)
			{
				const GpuConstantDefinition* def = currentUniform->mConstantDef;
				if (def->variability & mask)
				{
					GLsizei glArraySize = (GLsizei)def->arraySize;

					// Get the index in the parameter real list
					switch (def->constType)
					{
					case GCT_FLOAT1:
						glUniform1fv(currentUniform->mLocation, glArraySize,
							params->getFloatPointer(def->physicalIndex));
						break;
					case GCT_FLOAT2:
						glUniform2fv(currentUniform->mLocation, glArraySize,
							params->getFloatPointer(def->physicalIndex));
						break;
					case GCT_FLOAT3:
						glUniform3fv(currentUniform->mLocation, glArraySize,
							params->getFloatPointer(def->physicalIndex));
						break;
					case GCT_FLOAT4:
						glUniform4fv(currentUniform->mLocation, glArraySize,
							params->getFloatPointer(def->physicalIndex));
						break;
					case GCT_MATRIX_2X2:
						glUniformMatrix2fv(currentUniform->mLocation, glArraySize,
							GL_FALSE, params->getFloatPointer(def->physicalIndex));
						break;
					case GCT_MATRIX_3X3:
						glUniformMatrix3fv(currentUniform->mLocation, glArraySize,
							GL_FALSE, params->getFloatPointer(def->physicalIndex));
						break;
					case GCT_MATRIX_4X4:
						glUniformMatrix4fv(currentUniform->mLocation, glArraySize,
							GL_FALSE, params->getFloatPointer(def->physicalIndex));
						break;
					case GCT_INT1:
						glUniform1iv(currentUniform->mLocation, glArraySize,
							(GLint*)params->getIntPointer(def->physicalIndex));
						break;
					case GCT_INT2:
						glUniform2iv(currentUniform->mLocation, glArraySize,
							(GLint*)params->getIntPointer(def->physicalIndex));
						break;
					case GCT_INT3:
						glUniform3iv(currentUniform->mLocation, glArraySize,
							(GLint*)params->getIntPointer(def->physicalIndex));
						break;
					case GCT_INT4:
						glUniform4iv(currentUniform->mLocation, glArraySize,
							(GLint*)params->getIntPointer(def->physicalIndex));
						break;
					case GCT_SAMPLER1D:
					case GCT_SAMPLER1DSHADOW:
					case GCT_SAMPLER2D:
					case GCT_SAMPLER2DSHADOW:
					case GCT_SAMPLER3D:
					case GCT_SAMPLERCUBE:
						// Samplers handled like 1-element ints
						glUniform1iv(currentUniform->mLocation, 1,
							(GLint*)params->getIntPointer(def->physicalIndex));
						break;
					case GCT_MATRIX_2X3:
					case GCT_MATRIX_2X4:
					case GCT_MATRIX_3X2:
					case GCT_MATRIX_3X4:
					case GCT_MATRIX_4X2:
					case GCT_MATRIX_4X3:
                    case GCT_UNKNOWN:
                        break;

					} // End switch
                    GL_CHECK_ERROR;
				} // Variability & mask
			} // fromProgType == currentUniform->mSourceProgType

  		} // End for
	}
	//-----------------------------------------------------------------------
	void GLSLESLinkProgram::updatePassIterationUniforms(GpuProgramParametersSharedPtr params)
	{
		if (params->hasPassIterationNumber())
		{
			size_t index = params->getPassIterationNumberIndex();

			GLUniformReferenceIterator currentUniform = mGLUniformReferences.begin();
			GLUniformReferenceIterator endUniform = mGLUniformReferences.end();

			// Need to find the uniform that matches the multi pass entry
			for (;currentUniform != endUniform; ++currentUniform)
			{
				// Get the index in the parameter real list
				if (index == currentUniform->mConstantDef->physicalIndex)
				{
					glUniform1fv(currentUniform->mLocation, 1, params->getFloatPointer(index));
                    GL_CHECK_ERROR;
					// There will only be one multipass entry
					return;
				}
			}
		}
    }
} // namespace Ogre
<|endoftext|>


<commit_before>#ifndef BULL_CORE_ASSETS_ASSETMANAGER_HPP
#define BULL_CORE_ASSETS_ASSETMANAGER_HPP

#include <map>

#include <Bull/Core/Exception/InvalidParameter.hpp>

namespace Bull
{
    template <typename T>
    class BULL_CORE_API AssetManager
    {
    public:

        /*! \brief Create an Asset and register it the AssetManager
         *
         * \param name The name of the Asset to create
         * \param args Arguments to create the Asset
         *
         * \return A handler to the created Asset
         *
         */
        template <typename... Args>
        T& create(const String& name, Args&&... args)
        {
            typename AssetMap::iterator it = m_assets.find(name);

            if(it == m_assets.end())
            {
                it = m_assets.insert(
                        std::make_pair(name, T(std::forward<Args>(args)...))
                ).first;
            }
            else
            {
                it->second = T(std::forward<Args>(args)...);
            }

            it->second.setName(name);

            return it->second;
        }

        /*! \brief Register an Asset in the AssetManager
         *
         * \param asset The Asset to register
         * \param name  The name of the Asset to register
         *
         * \return A handler to the added Asset
         *
         */
        T& add(T&& asset, const String& name)
        {
            typename AssetMap::iterator it = m_assets.find(name);

            if(it == m_assets.end())
            {
                it = m_assets.insert(
                        std::make_pair(name, std::forward<T>(asset))
                ).first;
            }
            else
            {
                it->second = std::forward<T>(asset);
            }

            it->second.setName(name);

            return it->second;
        }

        /*! \brief Remove an Asset from the AssetManager
         *
         * \param name The name of the Asset to remove
         *
         * \return The removed
         *
         */
        T remove(const String& name)
        {
            typename AssetMap::iterator it = m_assets.find(name);

            Expect(it != m_assets.end(), Throw(InvalidParameter, "AssetManager::find", "The manager does not contains any asset " + name));

            return std::move(m_assets.erase(it)->second);
        }

        /*! \brief Tell whether an Asset exists in the AssetManager
         *
         * \param name The name of the Asset to get
         *
         * \return True if the Asset exists
         *
         */
        bool has(const String& name) const
        {
            return m_assets.find(name) != m_assets.end();
        }

        /*! \brief Find an Asset by its name a new one and return it
         *
         * \param name The name of the Asset to find
         *
         * \return A handler to the Asset
         *
         */
        T& find(const String& name)
        {
            typename AssetMap::iterator it = m_assets.find(name);

            Expect(it != m_assets.end(), Throw(InvalidParameter, "AssetManager::find", "The manager does not contains any asset " + name));

            return it->second;
        }

        /*! \brief Find an Asset by its name or create a new one and return it
         *
         * \param name The name of the Asset to find
         *
         * \return The Asset
         *
         */
        template <typename... Args>
        T& findOrCreate(const String& name, Args&&... args)
        {
            return findOrCreateWithFactory(name, [&args...]() -> T {
                return T(std::forward<Args>(args)...);
            });
        }

        /*! \brief Find or create an Asset by its name or create a new one using a factory and return it
         *
         * \param name    The name of the Asset to create
         * \param factory The factory to use to create the Asset
         *
         * \return The created Asset
         *
         */
        T& findOrCreateWithFactory(const String& name, const std::function<T()>& factory)
        {
            typename AssetMap::iterator it = m_assets.find(name);

            if(it == m_assets.end())
            {
                it = m_assets.insert(std::make_pair(name, factory())).first;

                it->second.setName(name);
            }

            return it->second;
        }

        /*! \brief Delete every Asset
         *
         */
        void clear()
        {
            m_assets.clear();
        }

    private:

        using AssetMap = std::map<String, T>;

        AssetMap m_assets;
    };
}

#endif // BULL_CORE_ASSETS_ASSETMANAGER_HPP
<commit_msg>[Core/AssetManager] Fix missing include<commit_after>#ifndef BULL_CORE_ASSETS_ASSETMANAGER_HPP
#define BULL_CORE_ASSETS_ASSETMANAGER_HPP

#include <functional>
#include <map>

#include <Bull/Core/Exception/InvalidParameter.hpp>

namespace Bull
{
    template <typename T>
    class BULL_CORE_API AssetManager
    {
    public:

        /*! \brief Create an Asset and register it the AssetManager
         *
         * \param name The name of the Asset to create
         * \param args Arguments to create the Asset
         *
         * \return A handler to the created Asset
         *
         */
        template <typename... Args>
        T& create(const String& name, Args&&... args)
        {
            typename AssetMap::iterator it = m_assets.find(name);

            if(it == m_assets.end())
            {
                it = m_assets.insert(
                        std::make_pair(name, T(std::forward<Args>(args)...))
                ).first;
            }
            else
            {
                it->second = T(std::forward<Args>(args)...);
            }

            it->second.setName(name);

            return it->second;
        }

        /*! \brief Register an Asset in the AssetManager
         *
         * \param asset The Asset to register
         * \param name  The name of the Asset to register
         *
         * \return A handler to the added Asset
         *
         */
        T& add(T&& asset, const String& name)
        {
            typename AssetMap::iterator it = m_assets.find(name);

            if(it == m_assets.end())
            {
                it = m_assets.insert(
                        std::make_pair(name, std::forward<T>(asset))
                ).first;
            }
            else
            {
                it->second = std::forward<T>(asset);
            }

            it->second.setName(name);

            return it->second;
        }

        /*! \brief Remove an Asset from the AssetManager
         *
         * \param name The name of the Asset to remove
         *
         * \return The removed
         *
         */
        T remove(const String& name)
        {
            typename AssetMap::iterator it = m_assets.find(name);

            Expect(it != m_assets.end(), Throw(InvalidParameter, "AssetManager::find", "The manager does not contains any asset " + name));

            return std::move(m_assets.erase(it)->second);
        }

        /*! \brief Tell whether an Asset exists in the AssetManager
         *
         * \param name The name of the Asset to get
         *
         * \return True if the Asset exists
         *
         */
        bool has(const String& name) const
        {
            return m_assets.find(name) != m_assets.end();
        }

        /*! \brief Find an Asset by its name a new one and return it
         *
         * \param name The name of the Asset to find
         *
         * \return A handler to the Asset
         *
         */
        T& find(const String& name)
        {
            typename AssetMap::iterator it = m_assets.find(name);

            Expect(it != m_assets.end(), Throw(InvalidParameter, "AssetManager::find", "The manager does not contains any asset " + name));

            return it->second;
        }

        /*! \brief Find an Asset by its name or create a new one and return it
         *
         * \param name The name of the Asset to find
         *
         * \return The Asset
         *
         */
        template <typename... Args>
        T& findOrCreate(const String& name, Args&&... args)
        {
            return findOrCreateWithFactory(name, [&args...]() -> T {
                return T(std::forward<Args>(args)...);
            });
        }

        /*! \brief Find or create an Asset by its name or create a new one using a factory and return it
         *
         * \param name    The name of the Asset to create
         * \param factory The factory to use to create the Asset
         *
         * \return The created Asset
         *
         */
        T& findOrCreateWithFactory(const String& name, const std::function<T()>& factory)
        {
            typename AssetMap::iterator it = m_assets.find(name);

            if(it == m_assets.end())
            {
                it = m_assets.insert(std::make_pair(name, factory())).first;

                it->second.setName(name);
            }

            return it->second;
        }

        /*! \brief Delete every Asset
         *
         */
        void clear()
        {
            m_assets.clear();
        }

    private:

        using AssetMap = std::map<String, T>;

        AssetMap m_assets;
    };
}

#endif // BULL_CORE_ASSETS_ASSETMANAGER_HPP
<|endoftext|>


<commit_before>/**
 * These codes are licensed under the Unlicense.
 * http://unlicense.org
 */

#ifndef FURFURYLIC_GUARD_E8F031F6_10D8_4585_9012_CFADC2F95BA7
#define FURFURYLIC_GUARD_E8F031F6_10D8_4585_9012_CFADC2F95BA7

#include <cassert>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <exception>
#include <limits>
#include <memory>
#include <ostream>
#include <sstream>
#include <streambuf>
#include <string>
#include <type_traits>
#include <utility>

#include "formatted_output.hpp"

namespace furfurylic {
namespace commata {
namespace detail {

template <class T>
struct npos_impl
{
    constexpr static T npos = static_cast<T>(-1);
};

// To define this in a header, npos_impl is a template
template <class T>
constexpr T npos_impl<T>::npos;

} // end namespace detail

class text_error_info;

class text_error :
    public std::exception, public detail::npos_impl<std::size_t>
{
    std::shared_ptr<std::string> what_;
    std::pair<std::size_t, std::size_t> physical_position_;

public:
    template <class T,
        class = std::enable_if_t<std::is_constructible<std::string, T>::value>>
    explicit text_error(T&& what_arg) :
        what_(std::make_shared<std::string>(std::forward<T>(what_arg))),
        physical_position_(npos, npos)
    {}

    // Copy/move ctors and copy/move assignment ops are explicitly defined
    // so that they are noexcept

    text_error(const text_error& other) noexcept :
        std::exception(other),
        what_(other.what_),
        physical_position_(other.physical_position_)
        // According to C++14 20.3.2 (1), pair's copy ctor is noexcept
    {}

    text_error(text_error&& other) noexcept :
        std::exception(std::move(other)),
        what_(std::move(other.what_)),
        physical_position_(other.physical_position_)
        // ditto
    {}

    text_error& operator=(const text_error& other) noexcept
    {
        std::exception::operator=(other);
        what_ = other.what_;
        physical_position_ = other.physical_position_;
        // According to C++14 20.3.2 (1), pair's assignments are noexcept
        return *this;
    }

    text_error& operator=(text_error&& other) noexcept
    {
        std::exception::operator=(std::move(other));
        what_ = std::move(other.what_);
        physical_position_ = other.physical_position_;
        // ditto
        return *this;
    }

    const char* what() const noexcept override
    {
        return what_->c_str(); // std::string::c_str is noexcept
    }

    void set_physical_position(std::size_t line = npos, std::size_t col = npos)
    {
        physical_position_ = std::make_pair(line, col);
    }

    const std::pair<std::size_t, std::size_t>* get_physical_position() const
        noexcept
    {
        // std::make_pair<std::size_t, std::size_t> shall not throw exceptions
        return (physical_position_ != std::make_pair(npos, npos)) ?
            &physical_position_ : nullptr;
    }

    text_error_info info() const noexcept;
};

namespace detail {

// Prints a non-negative integer value in the decimal system
// into a sufficient-length buffer
template <std::size_t N>
std::streamsize print_pos(char (&s)[N], std::size_t pos)
{
    const auto len = (pos != text_error::npos) ?
        std::snprintf(s, N, "%zu", pos + 1) :
        std::snprintf(s, N, "n/a");
    assert((len > 0 ) && (static_cast<std::size_t>(len) < N));
    return static_cast<std::streamsize>(len);
}

template <std::size_t N>
std::streamsize print_pos(wchar_t (&s)[N], std::size_t pos)
{
    const auto len = (pos != text_error::npos) ?
        std::swprintf(s, N, L"%zu", pos + 1) :
        std::swprintf(s, N, L"n/a");
    assert((len > 0 ) && (static_cast<std::size_t>(len) < N));
    return static_cast<std::streamsize>(len);
}

} // end namespace detail

class text_error_info
{
    const text_error* ex_;

public:
    explicit text_error_info(const text_error& ex) noexcept :
        ex_(&ex)
    {}

private:
    template <class Tr>
    friend std::basic_ostream<char, Tr>& operator<<(
        std::basic_ostream<char, Tr>& os, const text_error_info& i);

    template <class Tr>
    friend std::basic_ostream<wchar_t, Tr>& operator<<(
        std::basic_ostream<wchar_t, Tr>& os, const text_error_info& i);
};

template <class Tr>
std::basic_ostream<char, Tr>& operator<<(
    std::basic_ostream<char, Tr>& os, const text_error_info& i)
{
    if (const auto p = i.ex_->get_physical_position()) {
        // line
        char l[std::numeric_limits<std::size_t>::digits10 + 2];
        const auto l_len = detail::print_pos(l, p->first);

        // column
        char c[sizeof(l)];
        const auto c_len = detail::print_pos(c, p->second);

        // what
        const auto w = i.ex_->what();
        const auto w_len = static_cast<std::streamsize>(std::strlen(w));

        const auto n = w_len + l_len + c_len + ((w_len > 0) ? 15 : 27);

        return detail::formatted_output(os, n,
            [w, w_len, l = &l[0], l_len, c = &c[0], c_len]
            (auto* sb) {
                if (w_len > 0) {
                    if ((sb->sputn(w, w_len) != w_len)
                     || (sb->sputn("; line ", 7) != 7)) {
                        return false;
                    }
                } else if (sb->sputn("Text error at line ", 19) != 19) {
                    return false;
                }
                return (sb->sputn(l, l_len) == l_len)
                    && (sb->sputn(" column ", 8) == 8)
                    && (sb->sputn(c, c_len) == c_len);
            });

    } else {
        return os << i.ex_->what();
    }
}

template <class Tr>
std::basic_ostream<wchar_t, Tr>& operator<<(
    std::basic_ostream<wchar_t, Tr>& os, const text_error_info& i)
{
    // Count the wide characters in what, which may be an NTMBS
    auto w_raw = i.ex_->what();
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4996)
#endif
    auto w_len = static_cast<std::streamsize>(std::mbstowcs(0, w_raw, 0));
#ifdef _MSC_VER
#pragma warning(pop)
#endif
    if (w_len == -1) {
        // Conversion failed
        w_raw = "";
        w_len = 0;
    }

    if (const auto p = i.ex_->get_physical_position()) {
        // line
        wchar_t l[std::numeric_limits<std::size_t>::digits10 + 2];
        const auto l_len = detail::print_pos(l, p->first);

        // column
        wchar_t c[sizeof(l)];
        const auto c_len = detail::print_pos(c, p->second);

        const auto n = w_len + l_len + c_len + ((w_len > 0) ? 15 : 27);

        return detail::formatted_output(os, n,
            [w_raw, w_len, l = &l[0], l_len, c = &c[0], c_len]
            (auto* sb) {
                if (w_len > 0) {
                    std::unique_ptr<wchar_t[]> w(
                        new wchar_t[w_len + 1]);                    // throw
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4996)
#endif
                    std::mbstowcs(w.get(), w_raw, w_len);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
                    w[w_len] = L'\0';   // maybe not required
                    if ((sb->sputn(w.get(), w_len) != w_len)
                     || (sb->sputn(L"; line ", 7) != 7)) {
                        return false;
                    }
                } else if (sb->sputn(L"Text error at line ", 19) != 19) {
                    return false;
                }
                return (sb->sputn(l, l_len) == l_len)
                    && (sb->sputn(L" column ", 8) == 8)
                    && (sb->sputn(c, c_len) == c_len);
            });

    } else if (w_len > 0) {
        return detail::formatted_output(os, w_len,
            [w_raw, &w_len]
            (auto* sb) {
                std::unique_ptr<wchar_t[]> w(
                    new wchar_t[w_len + 1]);                        // throw
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4996)
#endif
                std::mbstowcs(w.get(), w_raw, w_len);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
                w[w_len] = L'\0';   // maybe not required
                return sb->sputn(w.get(), w_len) == w_len;
            });

    } else {
        return os;
    }
}

inline text_error_info text_error::info() const noexcept
{
    return text_error_info(*this);
}

inline std::string to_string(const text_error_info& i)
{
    std::ostringstream s;
    s << i;
    return s.str();
}

inline std::wstring to_wstring(const text_error_info& i)
{
    std::wostringstream s;
    s << i;
    return s.str();
}

}}

#endif
<commit_msg>Make text_error_info's exception member accessible<commit_after>/**
 * These codes are licensed under the Unlicense.
 * http://unlicense.org
 */

#ifndef FURFURYLIC_GUARD_E8F031F6_10D8_4585_9012_CFADC2F95BA7
#define FURFURYLIC_GUARD_E8F031F6_10D8_4585_9012_CFADC2F95BA7

#include <cassert>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <exception>
#include <limits>
#include <memory>
#include <ostream>
#include <sstream>
#include <streambuf>
#include <string>
#include <type_traits>
#include <utility>

#include "formatted_output.hpp"

namespace furfurylic {
namespace commata {
namespace detail {

template <class T>
struct npos_impl
{
    constexpr static T npos = static_cast<T>(-1);
};

// To define this in a header, npos_impl is a template
template <class T>
constexpr T npos_impl<T>::npos;

} // end namespace detail

class text_error_info;

class text_error :
    public std::exception, public detail::npos_impl<std::size_t>
{
    std::shared_ptr<std::string> what_;
    std::pair<std::size_t, std::size_t> physical_position_;

public:
    template <class T,
        class = std::enable_if_t<std::is_constructible<std::string, T>::value>>
    explicit text_error(T&& what_arg) :
        what_(std::make_shared<std::string>(std::forward<T>(what_arg))),
        physical_position_(npos, npos)
    {}

    // Copy/move ctors and copy/move assignment ops are explicitly defined
    // so that they are noexcept

    text_error(const text_error& other) noexcept :
        std::exception(other),
        what_(other.what_),
        physical_position_(other.physical_position_)
        // According to C++14 20.3.2 (1), pair's copy ctor is noexcept
    {}

    text_error(text_error&& other) noexcept :
        std::exception(std::move(other)),
        what_(std::move(other.what_)),
        physical_position_(other.physical_position_)
        // ditto
    {}

    text_error& operator=(const text_error& other) noexcept
    {
        std::exception::operator=(other);
        what_ = other.what_;
        physical_position_ = other.physical_position_;
        // According to C++14 20.3.2 (1), pair's assignments are noexcept
        return *this;
    }

    text_error& operator=(text_error&& other) noexcept
    {
        std::exception::operator=(std::move(other));
        what_ = std::move(other.what_);
        physical_position_ = other.physical_position_;
        // ditto
        return *this;
    }

    const char* what() const noexcept override
    {
        return what_->c_str(); // std::string::c_str is noexcept
    }

    void set_physical_position(std::size_t line = npos, std::size_t col = npos)
    {
        physical_position_ = std::make_pair(line, col);
    }

    const std::pair<std::size_t, std::size_t>* get_physical_position() const
        noexcept
    {
        // std::make_pair<std::size_t, std::size_t> shall not throw exceptions
        return (physical_position_ != std::make_pair(npos, npos)) ?
            &physical_position_ : nullptr;
    }

    text_error_info info() const noexcept;
};

namespace detail {

// Prints a non-negative integer value in the decimal system
// into a sufficient-length buffer
template <std::size_t N>
std::streamsize print_pos(char (&s)[N], std::size_t pos)
{
    const auto len = (pos != text_error::npos) ?
        std::snprintf(s, N, "%zu", pos + 1) :
        std::snprintf(s, N, "n/a");
    assert((len > 0 ) && (static_cast<std::size_t>(len) < N));
    return static_cast<std::streamsize>(len);
}

template <std::size_t N>
std::streamsize print_pos(wchar_t (&s)[N], std::size_t pos)
{
    const auto len = (pos != text_error::npos) ?
        std::swprintf(s, N, L"%zu", pos + 1) :
        std::swprintf(s, N, L"n/a");
    assert((len > 0 ) && (static_cast<std::size_t>(len) < N));
    return static_cast<std::streamsize>(len);
}

} // end namespace detail

class text_error_info
{
    const text_error* ex_;

public:
    explicit text_error_info(const text_error& ex) noexcept :
        ex_(&ex)
    {}

    const text_error& error() const noexcept
    {
        return *ex_;
    }
};

template <class Tr>
std::basic_ostream<char, Tr>& operator<<(
    std::basic_ostream<char, Tr>& os, const text_error_info& i)
{
    if (const auto p = i.error().get_physical_position()) {
        // line
        char l[std::numeric_limits<std::size_t>::digits10 + 2];
        const auto l_len = detail::print_pos(l, p->first);

        // column
        char c[sizeof(l)];
        const auto c_len = detail::print_pos(c, p->second);

        // what
        const auto w = i.error().what();
        const auto w_len = static_cast<std::streamsize>(std::strlen(w));

        const auto n = w_len + l_len + c_len + ((w_len > 0) ? 15 : 27);

        return detail::formatted_output(os, n,
            [w, w_len, l = &l[0], l_len, c = &c[0], c_len]
            (auto* sb) {
                if (w_len > 0) {
                    if ((sb->sputn(w, w_len) != w_len)
                     || (sb->sputn("; line ", 7) != 7)) {
                        return false;
                    }
                } else if (sb->sputn("Text error at line ", 19) != 19) {
                    return false;
                }
                return (sb->sputn(l, l_len) == l_len)
                    && (sb->sputn(" column ", 8) == 8)
                    && (sb->sputn(c, c_len) == c_len);
            });

    } else {
        return os << i.error().what();
    }
}

template <class Tr>
std::basic_ostream<wchar_t, Tr>& operator<<(
    std::basic_ostream<wchar_t, Tr>& os, const text_error_info& i)
{
    // Count the wide characters in what, which may be an NTMBS
    auto w_raw = i.error().what();
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4996)
#endif
    auto w_len = static_cast<std::streamsize>(std::mbstowcs(0, w_raw, 0));
#ifdef _MSC_VER
#pragma warning(pop)
#endif
    if (w_len == -1) {
        // Conversion failed
        w_raw = "";
        w_len = 0;
    }

    if (const auto p = i.error().get_physical_position()) {
        // line
        wchar_t l[std::numeric_limits<std::size_t>::digits10 + 2];
        const auto l_len = detail::print_pos(l, p->first);

        // column
        wchar_t c[sizeof(l)];
        const auto c_len = detail::print_pos(c, p->second);

        const auto n = w_len + l_len + c_len + ((w_len > 0) ? 15 : 27);

        return detail::formatted_output(os, n,
            [w_raw, w_len, l = &l[0], l_len, c = &c[0], c_len]
            (auto* sb) {
                if (w_len > 0) {
                    std::unique_ptr<wchar_t[]> w(
                        new wchar_t[w_len + 1]);                    // throw
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4996)
#endif
                    std::mbstowcs(w.get(), w_raw, w_len);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
                    w[w_len] = L'\0';   // maybe not required
                    if ((sb->sputn(w.get(), w_len) != w_len)
                     || (sb->sputn(L"; line ", 7) != 7)) {
                        return false;
                    }
                } else if (sb->sputn(L"Text error at line ", 19) != 19) {
                    return false;
                }
                return (sb->sputn(l, l_len) == l_len)
                    && (sb->sputn(L" column ", 8) == 8)
                    && (sb->sputn(c, c_len) == c_len);
            });

    } else if (w_len > 0) {
        return detail::formatted_output(os, w_len,
            [w_raw, &w_len]
            (auto* sb) {
                std::unique_ptr<wchar_t[]> w(
                    new wchar_t[w_len + 1]);                        // throw
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4996)
#endif
                std::mbstowcs(w.get(), w_raw, w_len);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
                w[w_len] = L'\0';   // maybe not required
                return sb->sputn(w.get(), w_len) == w_len;
            });

    } else {
        return os;
    }
}

inline text_error_info text_error::info() const noexcept
{
    return text_error_info(*this);
}

inline std::string to_string(const text_error_info& i)
{
    std::ostringstream s;
    s << i;
    return s.str();
}

inline std::wstring to_wstring(const text_error_info& i)
{
    std::wostringstream s;
    s << i;
    return s.str();
}

}}

#endif
<|endoftext|>