<commit_before>// conversion.cpp: step-by-step example of conversion of values to posits
//
// Copyright (C) 2017-2018 Stillwater Supercomputing, Inc.
//
// This file is part of the universal numbers project, which is released under an MIT Open Source license.

#include "common.hpp"
#include <posit>

// convert a floating point value to a specific posit configuration. Semantically, p = v, return reference to p
template<size_t nbits, size_t es, typename Ty>
sw::unum::posit<nbits, es> convert_to_posit(Ty rhs) {
	constexpr size_t fbits = std::numeric_limits<Ty>::digits - 1;

	using namespace std;
	using namespace sw::unum;

	value<fbits> v((Ty)rhs);
	posit<nbits, es> p;

	streamsize prec = cout.precision();
	cout << setprecision(numeric_limits<Ty>::digits10) << v << "   input value\n";
	cout << components(v);
	if (v.iszero()) {
		p.setzero();
		cout << " input value is zero\n";
		cout << info_print(p);
		return p;
	}
	else {
		cout << " input value is NOT zero\n";
	}
	cout << components(v);
	if (v.isnan() || v.isinf()) {
		p.setnar();
		cout << " input value is NaR\n";
		cout << info_print(p);
		return p;
	}
	else {
		cout << " input value is NOT NaR\n";
	}

	bool _sign = v.sign();
	int _scale = v.scale();
	sw::unum::bitblock<fbits> fraction_in = v.fraction();

	p.clear();
	cout << " construct the posit\n";
	// interpolation rule checks
	if (check_inward_projection_range<nbits, es>(_scale)) {    // regime dominated
		// we are projecting to minpos/maxpos
		int k = calculate_unconstrained_k<nbits, es>(_scale);
		k < 0 ? p.set(minpos_pattern<nbits, es>(_sign)) : p.set(maxpos_pattern<nbits, es>(_sign));
		// we are done
		std::cout << "projection  rounding ";
	}
	else {
		constexpr size_t pt_len = nbits + 3 + es;
		bitblock<pt_len> pt_bits;
		bitblock<pt_len> regime;
		bitblock<pt_len> exponent;
		bitblock<pt_len> fraction;
		bitblock<pt_len> sticky_bit;
		bool s = _sign;
		int e = _scale;
		bool r = (e >= 0);

		unsigned run = (r ? 1 + (e >> es) : -(e >> es));
		regime.set(0, 1 ^ r);
		for (unsigned i = 1; i <= run; i++) regime.set(i, r);

		unsigned esval = e % (uint32_t(1) << es);
		exponent = convert_to_bitblock<pt_len>(esval);
		unsigned nf = (unsigned)std::max<int>(0, (nbits + 1) - (2 + run + es));
		// TODO: what needs to be done if nf > fbits?
		//assert(nf <= input_fbits);
		// copy the most significant nf fraction bits into fraction
		unsigned lsb = nf <= fbits ? 0 : nf - fbits;
		for (unsigned i = lsb; i < nf; i++) fraction[i] = fraction_in[fbits - nf + i];
		cout << fraction_in << "  full fraction bits\n";

		bool sb = anyAfter(fraction_in, fbits - 1 - nf);
		bitblock<fbits> sb_mask;
		for (int i = 0; i < fbits - 1 - nf; i++) sb_mask.set(i);
		cout << sb_mask << "  mask of remainder bits\n";

		// construct the untruncated posit
		cout << pt_bits << "  unconstrained posit starting bits.   length = " << pt_len << "\n";
		// pt    = BitOr[BitShiftLeft[reg, es + nf + 1], BitShiftLeft[esval, nf + 1], BitShiftLeft[fv, 1], sb];
		regime <<= es + nf + 1;
		cout << regime << "  runlength = " << run << endl;
		exponent <<= nf + 1;
		cout << exponent << "  es value = " << esval << endl;
		fraction <<= 1;
		cout << fraction << "  most significant " << nf << " fraction bits\n";
		sticky_bit.set(0, sb);
		cout << sticky_bit << "  sticky bit representing the truncated fraction bits\n";

		pt_bits |= regime;
		pt_bits |= exponent;
		pt_bits |= fraction;
		pt_bits |= sticky_bit;
		cout << pt_bits << "  unconstrained posit bits ";

		unsigned len = 1 + std::max<unsigned>((nbits + 1), (2 + run + es));
		cout << " length = " << len << endl;
		bool blast = pt_bits.test(len - nbits);
		bitblock<pt_len> blast_bb;
		blast_bb.set(len - nbits);
		cout << blast_bb << "  last bit mask\n";
		bool bafter = pt_bits.test(len - nbits - 1);
		bitblock<pt_len> bafter_bb;
		bafter_bb.set(len - nbits - 1);
		cout << bafter_bb << "  bit after last bit mask\n";
		bool bsticky = anyAfter(pt_bits, len - nbits - 1 - 1);
		bitblock<pt_len> bsticky_bb;
		for (int i = len - nbits - 2; i >= 0; --i) bsticky_bb.set(i);
		cout << bsticky_bb << "  sticky bit mask\n";

		bool rb = (blast & bafter) | (bafter & bsticky);
		cout << "rounding decision: " << (rb ? "up" : "down") << endl;

		bitblock<nbits> ptt;
		pt_bits <<= pt_len - len;
		cout << pt_bits << "  shifted posit\n";
		truncate(pt_bits, ptt);
		cout << ptt << "  truncated posit\n";
		if (rb) increment_bitset(ptt);
		cout << ptt << "  rounded posit\n";
		if (s) ptt = twos_complement(ptt);
		cout << ptt << "  final posit\n";
		p.set(ptt);
	}
	return p;
}

int main(int argc, char** argv)
try {
	using namespace std;
	using namespace sw::unum;
	constexpr size_t nbits = 16;
	constexpr size_t es = 1;

	int nrOfFailedTestCases = 0;

	float f = 0.3;
	posit<nbits, es> p;

	p = convert_to_posit<nbits,es,float>(f);

	return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}
catch (char const* msg) {
	std::cerr << msg << std::endl;
	return EXIT_FAILURE;
}
catch (...) {
	std::cerr << "Caught unknown exception" << std::endl;
	return EXIT_FAILURE;
}
<commit_msg>Examples examples of conversion<commit_after>// conversion.cpp: step-by-step example of conversion of values to posits
//
// Copyright (C) 2017-2018 Stillwater Supercomputing, Inc.
//
// This file is part of the universal numbers project, which is released under an MIT Open Source license.

#include "common.hpp"
#include <posit>

// convert a floating point value to a specific posit configuration. Semantically, p = v, return reference to p
template<size_t nbits, size_t es, typename Ty>
sw::unum::posit<nbits, es> convert_to_posit(Ty rhs) {
	constexpr size_t fbits = std::numeric_limits<Ty>::digits - 1;

	using namespace std;
	using namespace sw::unum;

	value<fbits> v((Ty)rhs);
	posit<nbits, es> p;

	streamsize prec = cout.precision();
	cout << setprecision(numeric_limits<Ty>::digits10) << v << "   input value\n";
	cout << components(v);
	if (v.iszero()) {
		p.setzero();
		cout << " input value is zero\n";
		cout << info_print(p);
		return p;
	}
	else {
		cout << " input value is NOT zero\n";
	}
	cout << components(v);
	if (v.isnan() || v.isinf()) {
		p.setnar();
		cout << " input value is NaR\n";
		cout << info_print(p);
		return p;
	}
	else {
		cout << " input value is NOT NaR\n";
	}

	bool _sign = v.sign();
	int _scale = v.scale();
	sw::unum::bitblock<fbits> fraction_in = v.fraction();

	p.clear();
	cout << " construct the posit\n";
	// interpolation rule checks
	if (check_inward_projection_range<nbits, es>(_scale)) {    // regime dominated
		// we are projecting to minpos/maxpos
		int k = calculate_unconstrained_k<nbits, es>(_scale);
		k < 0 ? p.set(minpos_pattern<nbits, es>(_sign)) : p.set(maxpos_pattern<nbits, es>(_sign));
		// we are done
		std::cout << "projection  rounding ";
	}
	else {
		constexpr size_t pt_len = nbits + 3 + es;
		bitblock<pt_len> pt_bits;
		bitblock<pt_len> regime;
		bitblock<pt_len> exponent;
		bitblock<pt_len> fraction;
		bitblock<pt_len> sticky_bit;
		bool s = _sign;
		int e = _scale;
		bool r = (e >= 0);

		unsigned run = (r ? 1 + (e >> es) : -(e >> es));
		regime.set(0, 1 ^ r);
		for (unsigned i = 1; i <= run; i++) regime.set(i, r);

		unsigned esval = e % (uint32_t(1) << es);
		exponent = convert_to_bitblock<pt_len>(esval);
		unsigned nf = (unsigned)std::max<int>(0, (nbits + 1) - (2 + run + es));
		// TODO: what needs to be done if nf > fbits?
		//assert(nf <= input_fbits);
		// copy the most significant nf fraction bits into fraction
		unsigned lsb = nf <= fbits ? 0 : nf - fbits;
		for (unsigned i = lsb; i < nf; i++) fraction[i] = fraction_in[fbits - nf + i];
		cout << fraction_in << "  full fraction bits\n";

		bool sb = anyAfter(fraction_in, fbits - 1 - nf);
		bitblock<fbits> sb_mask;
		for (int i = 0; i < fbits - 1 - nf; i++) sb_mask.set(i);
		cout << sb_mask << "  mask of remainder bits\n";

		// construct the untruncated posit
		cout << pt_bits << "  unconstrained posit: length = nbits(" << nbits << ") + es(" << es << ") + 3 guard bits: " << pt_len << "\n";
		// pt    = BitOr[BitShiftLeft[reg, es + nf + 1], BitShiftLeft[esval, nf + 1], BitShiftLeft[fv, 1], sb];
		regime <<= es + nf + 1;
		cout << regime << "  runlength = " << run << endl;
		exponent <<= nf + 1;
		cout << exponent << "  exponent value = " << hex << esval << dec << endl;
		fraction <<= 1;
		cout << fraction << "  most significant " << nf << " fraction bits\n";
		sticky_bit.set(0, sb);
		cout << sticky_bit << "  sticky bit representing the truncated fraction bits\n";

		pt_bits |= regime;
		pt_bits |= exponent;
		pt_bits |= fraction;
		pt_bits |= sticky_bit;
		cout << pt_bits << "  unconstrained posit bits ";

		unsigned len = 1 + std::max<unsigned>((nbits + 1), (2 + run + es));
		cout << " length = " << len << endl;
		bool blast = pt_bits.test(len - nbits);
		bitblock<pt_len> blast_bb;
		blast_bb.set(len - nbits);
		cout << blast_bb << "  last bit mask\n";
		bool bafter = pt_bits.test(len - nbits - 1);
		bitblock<pt_len> bafter_bb;
		bafter_bb.set(len - nbits - 1);
		cout << bafter_bb << "  bit after last bit mask\n";
		bool bsticky = anyAfter(pt_bits, len - nbits - 1 - 1);
		bitblock<pt_len> bsticky_bb;
		for (int i = len - nbits - 2; i >= 0; --i) bsticky_bb.set(i);
		cout << bsticky_bb << "  sticky bit mask\n";

		bool rb = (blast & bafter) | (bafter & bsticky);
		cout << "rounding decision: " << (rb ? "up" : "down") << endl;

		bitblock<nbits> ptt;
		pt_bits <<= pt_len - len;
		cout << pt_bits << "  shifted posit\n";
		truncate(pt_bits, ptt);
		cout << ptt << "  truncated posit\n";
		if (rb) increment_bitset(ptt);
		cout << ptt << "  rounded posit\n";
		if (s) ptt = twos_complement(ptt);
		cout << ptt << "  final posit\n";
		p.set(ptt);
	}
	return p;
}

int main(int argc, char** argv)
try {
	using namespace std;
	using namespace sw::unum;
	constexpr size_t nbits = 16;
	constexpr size_t es = 1;

	int nrOfFailedTestCases = 0;

	float samples[20];

	posit<nbits, es> p_one_minus_eps, p_one, p_one_plus_eps;
	p_one = 1.0;
	p_one_minus_eps = 1.0; --p_one_minus_eps;
	p_one_plus_eps = 1.0; ++p_one_plus_eps;

	posit<nbits, es> p_minpos, p_maxpos(NAR);
	++p_minpos;
	--p_maxpos;

	samples[0] = 0.0f;
	samples[1] = float(p_minpos) / 2.0f;
	samples[2] = float(p_minpos);
	samples[3] = float(++p_minpos);
	samples[4] = float(p_one_minus_eps);
	samples[5] = float(p_one);
	samples[6] = float(p_one_plus_eps);
	samples[7] = float(--p_maxpos);
	samples[8] = float(p_maxpos);
	samples[9] = float(p_maxpos) * 2.0f;
	samples[10] = INFINITY;
	samples[11] = -samples[9];
	samples[12] = -samples[8];
	samples[13] = -samples[7];
	samples[14] = -samples[6];
	samples[15] = -1.0f;
	samples[16] = -samples[4];
	samples[17] = -samples[3];
	samples[18] = -samples[2];
	samples[19] = -samples[1];

	posit<nbits, es> p;

	int i = 0;
	for (auto sample : samples) {
		cout << "Sample[" << i++ << "] = " << sample << endl;
		p = convert_to_posit<nbits,es,float>(sample);
		cout << "********************************************************************\n";
	}

	return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}
catch (char const* msg) {
	std::cerr << msg << std::endl;
	return EXIT_FAILURE;
}
catch (...) {
	std::cerr << "Caught unknown exception" << std::endl;
	return EXIT_FAILURE;
}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2016, 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 John Haddon 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 "GafferArnold/Private/IECoreArnoldPreview/ShaderNetworkAlgo.h"

#include "GafferOSL/OSLShader.h"

#include "IECoreArnold/ParameterAlgo.h"

#include "IECoreScene/Shader.h"
#include "IECoreScene/ShaderNetworkAlgo.h"

#include "IECore/MessageHandler.h"
#include "IECore/SimpleTypedData.h"
#include "IECore/SplineData.h"
#include "IECore/VectorTypedData.h"

#include "boost/algorithm/string/predicate.hpp"
#include "boost/lexical_cast.hpp"
#include "boost/unordered_map.hpp"

using namespace std;
using namespace IECore;
using namespace IECoreScene;
using namespace IECoreArnold;

namespace
{

const AtString g_catmullRomArnoldString( "catmull-rom" );
const AtString g_bezierArnoldString( "bezier" );
const AtString g_bsplineArnoldString( "bspline" );
const AtString g_linearArnoldString( "linear" );
const AtString g_outputArnoldString( "output" );
const AtString g_shaderNameArnoldString( "shadername" );
const AtString g_oslArnoldString( "osl" );
const AtString g_nameArnoldString( "name" );

template<typename Spline>
void setSplineParameter( AtNode *node, const std::string &name, const Spline &spline )
{
	typedef vector<typename Spline::XType> PositionsVector;
	typedef vector<typename Spline::YType> ValuesVector;
	typedef TypedData<PositionsVector> PositionsData;
	typedef TypedData<ValuesVector> ValuesData;

	typename PositionsData::Ptr positionsData = new PositionsData;
	typename ValuesData::Ptr valuesData = new ValuesData;

	PositionsVector &positions = positionsData->writable();
	ValuesVector &values = valuesData->writable();
	positions.reserve( spline.points.size() );
	values.reserve( spline.points.size() );

	for( typename Spline::PointContainer::const_iterator it = spline.points.begin(), eIt = spline.points.end(); it != eIt; ++it )
	{
		positions.push_back( it->first );
		values.push_back( it->second );
	}

	AtString basis( g_catmullRomArnoldString );
	if( spline.basis == Spline::Basis::bezier() )
	{
		basis = g_bezierArnoldString;
	}
	else if( spline.basis == Spline::Basis::bSpline() )
	{
		basis = g_bsplineArnoldString;
	}
	else if( spline.basis == Spline::Basis::linear() )
	{
		basis = g_linearArnoldString;
	}

	GafferOSL::OSLShader::prepareSplineCVsForOSL( positions, values, basis );
	ParameterAlgo::setParameter( node, ( name + "Positions" ).c_str(), positionsData.get() );
	ParameterAlgo::setParameter( node, ( name + "Values" ).c_str(), valuesData.get() );
	AiNodeSetStr( node, AtString( ( name + "Basis" ).c_str() ), basis );
}

typedef boost::unordered_map<ShaderNetwork::Parameter, AtNode *> ShaderMap;

// Equivalent to Python's `s.partition( c )[0]`.
InternedString partitionStart( const InternedString &s, char c )
{
	const size_t index = s.string().find_first_of( '.' );
	if( index == string::npos )
	{
		return s;
	}
	else
	{
		return InternedString( s.c_str(), index );
	}
}

// Equivalent to Python's `s.partition( c )[2]`.
InternedString partitionEnd( const InternedString &s, char c )
{
	const size_t index = s.string().find_first_of( '.' );
	if( index == string::npos )
	{
		return InternedString();
	}
	else
	{
		return InternedString( s.c_str() + index + 1 );
	}
}

template<typename NodeCreator>
AtNode *convertWalk( const ShaderNetwork::Parameter &outputParameter, const IECoreScene::ShaderNetwork *shaderNetwork, const std::string &name, const NodeCreator &nodeCreator, vector<AtNode *> &nodes, ShaderMap &converted )
{
	// Reuse previously created node if we can. OSL shaders
	// can have multiple outputs, but each Arnold shader node
	// can have only a single output, so we have to emit OSL
	// shaders multiple times, once for each distinct top-level
	// output that is used.

	const IECoreScene::Shader *shader = shaderNetwork->getShader( outputParameter.shader );
	const bool isOSLShader = boost::starts_with( shader->getType(), "osl:" );
	const InternedString oslOutput = isOSLShader ? partitionStart( outputParameter.name, '.' ) : InternedString();

	auto inserted = converted.insert( { { outputParameter.shader, oslOutput }, nullptr } );
	AtNode *&node = inserted.first->second;
	if( !inserted.second )
	{
		return node;
	}

	// Create the AtNode for this shader output

	string nodeName = name;
	if( outputParameter != shaderNetwork->getOutput() )
	{
		nodeName += ":" + outputParameter.shader.string();
	}
	if( oslOutput.string().size() )
	{
		nodeName += ":" + oslOutput.string();
	}

	if( isOSLShader )
	{
		node = nodeCreator( g_oslArnoldString, AtString( nodeName.c_str() ) );
		if( oslOutput.string().size() )
		{
			AiNodeDeclare( node, g_outputArnoldString, "constant STRING" );
			AiNodeSetStr( node, g_outputArnoldString, AtString( oslOutput.c_str() ) );
		}
		AiNodeSetStr( node, g_shaderNameArnoldString, AtString( shader->getName().c_str() ) );
	}
	else
	{
		node = nodeCreator(
			AtString( shader->getName().c_str() ),
			AtString( nodeName.c_str() )
		);
	}

	if( !node )
	{
		msg( Msg::Warning, "IECoreArnold::ShaderNetworkAlgo", boost::format( "Couldn't load shader \"%s\"" ) % shader->getName() );
		return node;
	}

	// Set the shader parameters

	for( const auto &namedParameter : shader->parameters() )
	{
		string parameterName;
		if( isOSLShader )
		{
			parameterName = "param_" + namedParameter.first.string();
		}
		else
		{
			parameterName = namedParameter.first.string();
		}

		if( const SplineffData *splineData = runTimeCast<const SplineffData>( namedParameter.second.get() ) )
		{
			setSplineParameter( node, parameterName, splineData->readable() );
		}
		else if( const SplinefColor3fData *splineData = runTimeCast<const SplinefColor3fData>( namedParameter.second.get() ) )
		{
			setSplineParameter( node, parameterName, splineData->readable() );
			continue;
		}
		else
		{
			ParameterAlgo::setParameter( node, AtString( parameterName.c_str() ), namedParameter.second.get() );
		}
	}

	// Recurse through input connections

	for( const auto &connection : shaderNetwork->inputConnections( outputParameter.shader ) )
	{
		AtNode *sourceNode = convertWalk( connection.source, shaderNetwork, name, nodeCreator, nodes, converted );
		if( !sourceNode )
		{
			continue;
		}

		string parameterName;
		if( isOSLShader )
		{
			parameterName = "param_" + connection.destination.name.string();
		}
		else
		{
			parameterName = connection.destination.name.string();
		}

		InternedString sourceName = connection.source.name;
		const IECoreScene::Shader *sourceShader = shaderNetwork->getShader( connection.source.shader );
		if( boost::starts_with( sourceShader->getType(), "osl:" ) )
		{
			sourceName = partitionEnd( sourceName, '.' );
		}

		AiNodeLinkOutput( sourceNode, sourceName.c_str(), node, parameterName.c_str() );
	}

	nodes.push_back( node );
	return node;
}

AtString g_name( "name" );

const std::vector<AtString> g_protectedLightParameters = {
	AtString( "matrix" ),
	AtString( "filters" ),
	AtString( "mesh" )
};

// Similar to `AiNodeReset()`, but avoids resetting light parameters
// which we know to be unrelated to ShaderNetwork translation.
void resetNode( AtNode *node )
{
	const AtNodeEntry *nodeEntry = AiNodeGetNodeEntry( node );
	const bool isLight = AiNodeEntryGetType( nodeEntry ) == AI_NODE_LIGHT;

	AtParamIterator *it = AiNodeEntryGetParamIterator( nodeEntry );
	while( !AiParamIteratorFinished( it ) )
	{
		const AtParamEntry *param = AiParamIteratorGetNext( it );
		const AtString name = AiParamGetName( param );

		if( name == g_name )
		{
			continue;
		}

		if(
			isLight &&
			std::find(
				g_protectedLightParameters.begin(),
				g_protectedLightParameters.end(),
				name
			) != g_protectedLightParameters.end()
		)
		{
			continue;
		}

		AiNodeResetParameter( node, name );
	}
	AiParamIteratorDestroy( it );
}

} // namespace

namespace IECoreArnoldPreview
{

namespace ShaderNetworkAlgo
{

std::vector<AtNode *> convert( const IECoreScene::ShaderNetwork *shaderNetwork, const std::string &name, const AtNode *parentNode )
{
	ShaderNetworkPtr networkCopy;
	if( true ) // todo : make conditional on OSL < 1.10
	{
		networkCopy = shaderNetwork->copy();
		IECoreScene::ShaderNetworkAlgo::convertOSLComponentConnections( networkCopy.get() );
		shaderNetwork = networkCopy.get();
	}

	ShaderMap converted;
	vector<AtNode *> result;
	const InternedString output = shaderNetwork->getOutput().shader;
	if( output.string().empty() )
	{
		msg( Msg::Warning, "IECoreArnold::ShaderNetworkAlgo", "Shader has no output" );
	}
	else
	{
		auto nodeCreator = [parentNode]( const AtString &nodeType, const AtString &nodeName ) {
			return AiNode( nodeType, nodeName, parentNode );
		};
		convertWalk( shaderNetwork->getOutput(), shaderNetwork, name, nodeCreator, result, converted );
	}
	return result;
}

bool update( std::vector<AtNode *> &nodes, const IECoreScene::ShaderNetwork *shaderNetwork )
{
	assert( nodes.size() );
	AtNode *parentNode = AiNodeGetParent( nodes.back() );
	const std::string &name = AiNodeGetName( nodes.back() );

	boost::unordered_map<AtString, AtNode *, AtStringHash> originalNodes;
	for( const auto &n : nodes )
	{
		originalNodes[AtString(AiNodeGetName(n))] = n;
	}
	std::unordered_set<AtNode *> reusedNodes;
	nodes.clear();

	auto nodeCreator = [parentNode, &originalNodes, &reusedNodes]( const AtString &nodeType, const AtString &nodeName ) {
		auto it = originalNodes.find( nodeName );
		if( it != originalNodes.end() )
		{
			if( AtString( AiNodeEntryGetName( AiNodeGetNodeEntry( it->second ) ) ) == nodeType )
			{
				// Reuse original node
				AtNode *node = it->second;
				originalNodes.erase( it );
				reusedNodes.insert( node );
				resetNode( node );
				return node;
			}
			else
			{
				// Can't reuse original node. Delete it so that we
				// can reuse the name in `AiNode()` below.
				AiNodeDestroy( it->second );
				originalNodes.erase( it );
			}
		}
		return AiNode( nodeType, nodeName, parentNode );
	};

	ShaderMap converted;
	convertWalk( shaderNetwork->getOutput(), shaderNetwork, name, nodeCreator, nodes, converted );

	for( const auto &n : originalNodes )
	{
		AiNodeDestroy( n.second );
	}

	return nodes.size() && reusedNodes.count( nodes.back() );
}

} // namespace ShaderNetworkAlgo

} // namespace IECoreArnoldPreview
<commit_msg>ShaderNetworkAlgo : protect lightFilter transforms<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2016, 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 John Haddon 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 "GafferArnold/Private/IECoreArnoldPreview/ShaderNetworkAlgo.h"

#include "GafferOSL/OSLShader.h"

#include "IECoreArnold/ParameterAlgo.h"

#include "IECoreScene/Shader.h"
#include "IECoreScene/ShaderNetworkAlgo.h"

#include "IECore/MessageHandler.h"
#include "IECore/SimpleTypedData.h"
#include "IECore/SplineData.h"
#include "IECore/VectorTypedData.h"

#include "boost/algorithm/string/predicate.hpp"
#include "boost/lexical_cast.hpp"
#include "boost/unordered_map.hpp"

using namespace std;
using namespace IECore;
using namespace IECoreScene;
using namespace IECoreArnold;

namespace
{

const AtString g_catmullRomArnoldString( "catmull-rom" );
const AtString g_bezierArnoldString( "bezier" );
const AtString g_bsplineArnoldString( "bspline" );
const AtString g_linearArnoldString( "linear" );
const AtString g_outputArnoldString( "output" );
const AtString g_shaderNameArnoldString( "shadername" );
const AtString g_oslArnoldString( "osl" );
const AtString g_nameArnoldString( "name" );

template<typename Spline>
void setSplineParameter( AtNode *node, const std::string &name, const Spline &spline )
{
	typedef vector<typename Spline::XType> PositionsVector;
	typedef vector<typename Spline::YType> ValuesVector;
	typedef TypedData<PositionsVector> PositionsData;
	typedef TypedData<ValuesVector> ValuesData;

	typename PositionsData::Ptr positionsData = new PositionsData;
	typename ValuesData::Ptr valuesData = new ValuesData;

	PositionsVector &positions = positionsData->writable();
	ValuesVector &values = valuesData->writable();
	positions.reserve( spline.points.size() );
	values.reserve( spline.points.size() );

	for( typename Spline::PointContainer::const_iterator it = spline.points.begin(), eIt = spline.points.end(); it != eIt; ++it )
	{
		positions.push_back( it->first );
		values.push_back( it->second );
	}

	AtString basis( g_catmullRomArnoldString );
	if( spline.basis == Spline::Basis::bezier() )
	{
		basis = g_bezierArnoldString;
	}
	else if( spline.basis == Spline::Basis::bSpline() )
	{
		basis = g_bsplineArnoldString;
	}
	else if( spline.basis == Spline::Basis::linear() )
	{
		basis = g_linearArnoldString;
	}

	GafferOSL::OSLShader::prepareSplineCVsForOSL( positions, values, basis );
	ParameterAlgo::setParameter( node, ( name + "Positions" ).c_str(), positionsData.get() );
	ParameterAlgo::setParameter( node, ( name + "Values" ).c_str(), valuesData.get() );
	AiNodeSetStr( node, AtString( ( name + "Basis" ).c_str() ), basis );
}

typedef boost::unordered_map<ShaderNetwork::Parameter, AtNode *> ShaderMap;

// Equivalent to Python's `s.partition( c )[0]`.
InternedString partitionStart( const InternedString &s, char c )
{
	const size_t index = s.string().find_first_of( '.' );
	if( index == string::npos )
	{
		return s;
	}
	else
	{
		return InternedString( s.c_str(), index );
	}
}

// Equivalent to Python's `s.partition( c )[2]`.
InternedString partitionEnd( const InternedString &s, char c )
{
	const size_t index = s.string().find_first_of( '.' );
	if( index == string::npos )
	{
		return InternedString();
	}
	else
	{
		return InternedString( s.c_str() + index + 1 );
	}
}

template<typename NodeCreator>
AtNode *convertWalk( const ShaderNetwork::Parameter &outputParameter, const IECoreScene::ShaderNetwork *shaderNetwork, const std::string &name, const NodeCreator &nodeCreator, vector<AtNode *> &nodes, ShaderMap &converted )
{
	// Reuse previously created node if we can. OSL shaders
	// can have multiple outputs, but each Arnold shader node
	// can have only a single output, so we have to emit OSL
	// shaders multiple times, once for each distinct top-level
	// output that is used.

	const IECoreScene::Shader *shader = shaderNetwork->getShader( outputParameter.shader );
	const bool isOSLShader = boost::starts_with( shader->getType(), "osl:" );
	const InternedString oslOutput = isOSLShader ? partitionStart( outputParameter.name, '.' ) : InternedString();

	auto inserted = converted.insert( { { outputParameter.shader, oslOutput }, nullptr } );
	AtNode *&node = inserted.first->second;
	if( !inserted.second )
	{
		return node;
	}

	// Create the AtNode for this shader output

	string nodeName = name;
	if( outputParameter != shaderNetwork->getOutput() )
	{
		nodeName += ":" + outputParameter.shader.string();
	}
	if( oslOutput.string().size() )
	{
		nodeName += ":" + oslOutput.string();
	}

	if( isOSLShader )
	{
		node = nodeCreator( g_oslArnoldString, AtString( nodeName.c_str() ) );
		if( oslOutput.string().size() )
		{
			AiNodeDeclare( node, g_outputArnoldString, "constant STRING" );
			AiNodeSetStr( node, g_outputArnoldString, AtString( oslOutput.c_str() ) );
		}
		AiNodeSetStr( node, g_shaderNameArnoldString, AtString( shader->getName().c_str() ) );
	}
	else
	{
		node = nodeCreator(
			AtString( shader->getName().c_str() ),
			AtString( nodeName.c_str() )
		);
	}

	if( !node )
	{
		msg( Msg::Warning, "IECoreArnold::ShaderNetworkAlgo", boost::format( "Couldn't load shader \"%s\"" ) % shader->getName() );
		return node;
	}

	// Set the shader parameters

	for( const auto &namedParameter : shader->parameters() )
	{
		string parameterName;
		if( isOSLShader )
		{
			parameterName = "param_" + namedParameter.first.string();
		}
		else
		{
			parameterName = namedParameter.first.string();
		}

		if( const SplineffData *splineData = runTimeCast<const SplineffData>( namedParameter.second.get() ) )
		{
			setSplineParameter( node, parameterName, splineData->readable() );
		}
		else if( const SplinefColor3fData *splineData = runTimeCast<const SplinefColor3fData>( namedParameter.second.get() ) )
		{
			setSplineParameter( node, parameterName, splineData->readable() );
			continue;
		}
		else
		{
			ParameterAlgo::setParameter( node, AtString( parameterName.c_str() ), namedParameter.second.get() );
		}
	}

	// Recurse through input connections

	for( const auto &connection : shaderNetwork->inputConnections( outputParameter.shader ) )
	{
		AtNode *sourceNode = convertWalk( connection.source, shaderNetwork, name, nodeCreator, nodes, converted );
		if( !sourceNode )
		{
			continue;
		}

		string parameterName;
		if( isOSLShader )
		{
			parameterName = "param_" + connection.destination.name.string();
		}
		else
		{
			parameterName = connection.destination.name.string();
		}

		InternedString sourceName = connection.source.name;
		const IECoreScene::Shader *sourceShader = shaderNetwork->getShader( connection.source.shader );
		if( boost::starts_with( sourceShader->getType(), "osl:" ) )
		{
			sourceName = partitionEnd( sourceName, '.' );
		}

		AiNodeLinkOutput( sourceNode, sourceName.c_str(), node, parameterName.c_str() );
	}

	nodes.push_back( node );
	return node;
}

AtString g_name( "name" );
AtString g_lightBlockerNodeEntryName( "light_blocker" );

const std::vector<AtString> g_protectedLightParameters = {
	AtString( "matrix" ),
	AtString( "filters" ),
	AtString( "mesh" )
};

const std::vector<AtString> g_protectedLightFilterParameters = {
	AtString( "geometry_matrix" ),
};

// Similar to `AiNodeReset()`, but avoids resetting light parameters
// which we know to be unrelated to ShaderNetwork translation.
void resetNode( AtNode *node )
{
	const AtNodeEntry *nodeEntry = AiNodeGetNodeEntry( node );
	const bool isLight = AiNodeEntryGetType( nodeEntry ) == AI_NODE_LIGHT;
	const bool isShader = AiNodeEntryGetType( nodeEntry ) == AI_NODE_SHADER;
	const bool isLightFilter = isShader && AtString( AiNodeEntryGetName( nodeEntry ) ) == g_lightBlockerNodeEntryName;

	AtParamIterator *it = AiNodeEntryGetParamIterator( nodeEntry );
	while( !AiParamIteratorFinished( it ) )
	{
		const AtParamEntry *param = AiParamIteratorGetNext( it );
		const AtString name = AiParamGetName( param );

		if( name == g_name )
		{
			continue;
		}

		if(
			isLight &&
			std::find(
				g_protectedLightParameters.begin(),
				g_protectedLightParameters.end(),
				name
			) != g_protectedLightParameters.end()
		)
		{
			continue;
		}

		if(
			isLightFilter &&
			std::find(
				g_protectedLightFilterParameters.begin(),
				g_protectedLightFilterParameters.end(),
				name
			) != g_protectedLightFilterParameters.end()
		)
		{
			continue;
		}

		AiNodeResetParameter( node, name );
	}
	AiParamIteratorDestroy( it );
}

} // namespace

namespace IECoreArnoldPreview
{

namespace ShaderNetworkAlgo
{

std::vector<AtNode *> convert( const IECoreScene::ShaderNetwork *shaderNetwork, const std::string &name, const AtNode *parentNode )
{
	ShaderNetworkPtr networkCopy;
	if( true ) // todo : make conditional on OSL < 1.10
	{
		networkCopy = shaderNetwork->copy();
		IECoreScene::ShaderNetworkAlgo::convertOSLComponentConnections( networkCopy.get() );
		shaderNetwork = networkCopy.get();
	}

	ShaderMap converted;
	vector<AtNode *> result;
	const InternedString output = shaderNetwork->getOutput().shader;
	if( output.string().empty() )
	{
		msg( Msg::Warning, "IECoreArnold::ShaderNetworkAlgo", "Shader has no output" );
	}
	else
	{
		auto nodeCreator = [parentNode]( const AtString &nodeType, const AtString &nodeName ) {
			return AiNode( nodeType, nodeName, parentNode );
		};
		convertWalk( shaderNetwork->getOutput(), shaderNetwork, name, nodeCreator, result, converted );
	}
	return result;
}

bool update( std::vector<AtNode *> &nodes, const IECoreScene::ShaderNetwork *shaderNetwork )
{
	assert( nodes.size() );
	AtNode *parentNode = AiNodeGetParent( nodes.back() );
	const std::string &name = AiNodeGetName( nodes.back() );

	boost::unordered_map<AtString, AtNode *, AtStringHash> originalNodes;
	for( const auto &n : nodes )
	{
		originalNodes[AtString(AiNodeGetName(n))] = n;
	}
	std::unordered_set<AtNode *> reusedNodes;
	nodes.clear();

	auto nodeCreator = [parentNode, &originalNodes, &reusedNodes]( const AtString &nodeType, const AtString &nodeName ) {
		auto it = originalNodes.find( nodeName );
		if( it != originalNodes.end() )
		{
			if( AtString( AiNodeEntryGetName( AiNodeGetNodeEntry( it->second ) ) ) == nodeType )
			{
				// Reuse original node
				AtNode *node = it->second;
				originalNodes.erase( it );
				reusedNodes.insert( node );
				resetNode( node );
				return node;
			}
			else
			{
				// Can't reuse original node. Delete it so that we
				// can reuse the name in `AiNode()` below.
				AiNodeDestroy( it->second );
				originalNodes.erase( it );
			}
		}
		return AiNode( nodeType, nodeName, parentNode );
	};

	ShaderMap converted;
	convertWalk( shaderNetwork->getOutput(), shaderNetwork, name, nodeCreator, nodes, converted );

	for( const auto &n : originalNodes )
	{
		AiNodeDestroy( n.second );
	}

	return nodes.size() && reusedNodes.count( nodes.back() );
}

} // namespace ShaderNetworkAlgo

} // namespace IECoreArnoldPreview
<|endoftext|>


<commit_before>#pragma once

#include <agency/detail/config.hpp>
#include <agency/detail/uninitialized.hpp>
#include <thrust/detail/swap.h>
#include <utility>
#include <type_traits>

namespace agency
{
namespace detail
{

struct nullopt_t {};
constexpr nullopt_t nullopt{};

template<class T>
class optional
{
  public:
    __AGENCY_ANNOTATION
    optional(nullopt_t) : contains_value_{false} {}

    __AGENCY_ANNOTATION
    optional() : optional(nullopt) {}

    __AGENCY_ANNOTATION
    optional(const optional& other)
      : contains_value_(other.contains_value_)
    {
      emplace(other.value_);
    }

    __AGENCY_ANNOTATION
    optional(optional&& other)
      : contains_value_(false)
    {
      emplace(std::move(other.value_));
    }

    __AGENCY_ANNOTATION
    optional(const T& value)
      : contains_value_(false)
    {
      emplace(value);
    }

    __AGENCY_ANNOTATION
    optional(T&& value)
      : contains_value_(false)
    {
      emplace(std::move(value));
    }

    __AGENCY_ANNOTATION
    ~optional()
    {
      clear();
    }

    __AGENCY_ANNOTATION
    optional& operator=(nullopt_t)
    {
      clear();
    }

    template<class U,
             class = typename std::enable_if<
               std::is_same<typename std::decay<U>::type,T>::value
             >::type>
    __AGENCY_ANNOTATION
    optional& operator=(U&& value)
    {
      if(*this)
      {
        value_.get() = std::forward<U>(value);
      }
      else
      {
        emplace(std::forward<U>(value));
      }

      return *this;
    }

    __AGENCY_ANNOTATION
    optional& operator=(const optional& other)
    {
      if(other)
      {
        *this = other.value_;
      }
      else
      {
        *this = nullopt;
      }

      return *this;
    }

    __AGENCY_ANNOTATION
    optional& operator=(optional&& other)
    {
      if(other)
      {
        *this = std::move(other.value_);
      }
      else
      {
        *this = nullopt;
      }

      return *this;
    }

    template<class... Args>
    __AGENCY_ANNOTATION
    void emplace(Args&&... args)
    {
      clear();

      value_.construct(std::forward<Args>(args)...);
      contains_value_ = true;
    }

    __AGENCY_ANNOTATION
    explicit operator bool() const
    {
      return contains_value_;
    }

    __AGENCY_ANNOTATION
    T& value()
    {
      // XXX should check contains_value_ and throw otherwise
      return value_.get();
    }

    __AGENCY_ANNOTATION
    const T& value() const
    {
      // XXX should check contains_value_ and throw otherwise
      return value_.get();
    }

    __AGENCY_ANNOTATION
    void swap(optional& other)
    {
      if(*other)
      {
        if(*this)
        {
          thrust::swap(value_, other.value_);
        }
        else
        {
          emplace(other.value_);
          other = nullopt;
        }
      }
      else
      {
        if(*this)
        {
          other.emplace(value_);
          *this = nullopt;
        }
        else
        {
          // no effect
        }
      }
    }

  private:
    __AGENCY_ANNOTATION
    void clear()
    {
      if(*this)
      {
        value_.destroy();
        contains_value_ = false;
      }
    }

    bool contains_value_;
    uninitialized<T> value_;
};

} // end detail
} // end agency

<commit_msg>Add missing return to the end of optional::operator=<commit_after>#pragma once

#include <agency/detail/config.hpp>
#include <agency/detail/uninitialized.hpp>
#include <thrust/detail/swap.h>
#include <utility>
#include <type_traits>

namespace agency
{
namespace detail
{

struct nullopt_t {};
constexpr nullopt_t nullopt{};

template<class T>
class optional
{
  public:
    __AGENCY_ANNOTATION
    optional(nullopt_t) : contains_value_{false} {}

    __AGENCY_ANNOTATION
    optional() : optional(nullopt) {}

    __AGENCY_ANNOTATION
    optional(const optional& other)
      : contains_value_(other.contains_value_)
    {
      emplace(other.value_);
    }

    __AGENCY_ANNOTATION
    optional(optional&& other)
      : contains_value_(false)
    {
      emplace(std::move(other.value_));
    }

    __AGENCY_ANNOTATION
    optional(const T& value)
      : contains_value_(false)
    {
      emplace(value);
    }

    __AGENCY_ANNOTATION
    optional(T&& value)
      : contains_value_(false)
    {
      emplace(std::move(value));
    }

    __AGENCY_ANNOTATION
    ~optional()
    {
      clear();
    }

    __AGENCY_ANNOTATION
    optional& operator=(nullopt_t)
    {
      clear();
      return *this;
    }

    template<class U,
             class = typename std::enable_if<
               std::is_same<typename std::decay<U>::type,T>::value
             >::type>
    __AGENCY_ANNOTATION
    optional& operator=(U&& value)
    {
      if(*this)
      {
        value_.get() = std::forward<U>(value);
      }
      else
      {
        emplace(std::forward<U>(value));
      }

      return *this;
    }

    __AGENCY_ANNOTATION
    optional& operator=(const optional& other)
    {
      if(other)
      {
        *this = other.value_;
      }
      else
      {
        *this = nullopt;
      }

      return *this;
    }

    __AGENCY_ANNOTATION
    optional& operator=(optional&& other)
    {
      if(other)
      {
        *this = std::move(other.value_);
      }
      else
      {
        *this = nullopt;
      }

      return *this;
    }

    template<class... Args>
    __AGENCY_ANNOTATION
    void emplace(Args&&... args)
    {
      clear();

      value_.construct(std::forward<Args>(args)...);
      contains_value_ = true;
    }

    __AGENCY_ANNOTATION
    explicit operator bool() const
    {
      return contains_value_;
    }

    __AGENCY_ANNOTATION
    T& value()
    {
      // XXX should check contains_value_ and throw otherwise
      return value_.get();
    }

    __AGENCY_ANNOTATION
    const T& value() const
    {
      // XXX should check contains_value_ and throw otherwise
      return value_.get();
    }

    __AGENCY_ANNOTATION
    void swap(optional& other)
    {
      if(*other)
      {
        if(*this)
        {
          thrust::swap(value_, other.value_);
        }
        else
        {
          emplace(other.value_);
          other = nullopt;
        }
      }
      else
      {
        if(*this)
        {
          other.emplace(value_);
          *this = nullopt;
        }
        else
        {
          // no effect
        }
      }
    }

  private:
    __AGENCY_ANNOTATION
    void clear()
    {
      if(*this)
      {
        value_.destroy();
        contains_value_ = false;
      }
    }

    bool contains_value_;
    uninitialized<T> value_;
};

} // end detail
} // end agency

<|endoftext|>


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

#include "src/trace_processor/heap_profile_tracker.h"

#include "src/trace_processor/process_tracker.h"
#include "src/trace_processor/trace_processor_context.h"

#include "perfetto/base/logging.h"

namespace perfetto {
namespace trace_processor {

namespace {
struct MergedCallsite {
  StringId frame_name;
  StringId mapping_name;
  base::Optional<uint32_t> parent_idx;
  bool operator<(const MergedCallsite& o) const {
    return std::tie(frame_name, mapping_name, parent_idx) <
           std::tie(o.frame_name, o.mapping_name, o.parent_idx);
  }
};

std::vector<MergedCallsite> GetMergedCallsites(TraceStorage* storage,
                                               uint32_t callstack_row) {
  const tables::StackProfileCallsiteTable& callsites_tbl =
      storage->stack_profile_callsite_table();
  const tables::StackProfileFrameTable& frames_tbl =
      storage->stack_profile_frame_table();
  const tables::SymbolTable& symbols_tbl = storage->symbol_table();
  const tables::StackProfileMappingTable& mapping_tbl =
      storage->stack_profile_mapping_table();

  // TODO(fmayer): Clean up types and remove the static_cast.
  uint32_t frame_idx = *frames_tbl.id().IndexOf(
      FrameId(static_cast<uint32_t>(callsites_tbl.frame_id()[callstack_row])));

  // TODO(fmayer): Clean up types and remove the static_cast.
  uint32_t mapping_idx = *mapping_tbl.id().IndexOf(
      MappingId(static_cast<uint32_t>(frames_tbl.mapping()[frame_idx])));
  StringId mapping_name = mapping_tbl.name()[mapping_idx];

  base::Optional<uint32_t> symbol_set_id =
      frames_tbl.symbol_set_id()[frame_idx];

  if (!symbol_set_id) {
    StringId frame_name = frames_tbl.name()[frame_idx];
    return {{frame_name, mapping_name, base::nullopt}};
  }

  std::vector<MergedCallsite> result;
  // id == symbol_set_id for the bottommost frame.
  // TODO(lalitm): Encode this optimization in the table and remove this
  // custom optimization.
  uint32_t symbol_set_idx = *symbols_tbl.id().IndexOf(SymbolId(*symbol_set_id));
  for (uint32_t i = symbol_set_idx;
       i < symbols_tbl.row_count() &&
       symbols_tbl.symbol_set_id()[i] == *symbol_set_id;
       ++i) {
    result.emplace_back(
        MergedCallsite{symbols_tbl.name()[i], mapping_name, base::nullopt});
  }
  return result;
}
}  // namespace

std::unique_ptr<tables::ExperimentalFlamegraphNodesTable> BuildNativeFlamegraph(
    TraceStorage* storage,
    UniquePid upid,
    int64_t timestamp) {
  const tables::HeapProfileAllocationTable& allocation_tbl =
      storage->heap_profile_allocation_table();
  const tables::StackProfileCallsiteTable& callsites_tbl =
      storage->stack_profile_callsite_table();

  StringId profile_type = storage->InternString("native");

  std::vector<uint32_t> callsite_to_merged_callsite(callsites_tbl.row_count(),
                                                    0);
  std::map<MergedCallsite, uint32_t> merged_callsites_to_table_idx;

  std::unique_ptr<tables::ExperimentalFlamegraphNodesTable> tbl(
      new tables::ExperimentalFlamegraphNodesTable(
          storage->mutable_string_pool(), nullptr));

  // FORWARD PASS:
  // Aggregate callstacks by frame name / mapping name. Use symbolization data.
  for (uint32_t i = 0; i < callsites_tbl.row_count(); ++i) {
    base::Optional<uint32_t> parent_idx;
    // TODO(fmayer): Clean up types and remove the conditional and static_cast.
    if (callsites_tbl.parent_id()[i] != -1) {
      auto parent_id = static_cast<uint32_t>(callsites_tbl.parent_id()[i]);
      parent_idx = callsites_tbl.id().IndexOf(CallsiteId(parent_id));
      parent_idx = callsite_to_merged_callsite[*parent_idx];
      PERFETTO_CHECK(*parent_idx < i);
    }

    auto callsites = GetMergedCallsites(storage, i);
    for (MergedCallsite& merged_callsite : callsites) {
      merged_callsite.parent_idx = parent_idx;
      auto it = merged_callsites_to_table_idx.find(merged_callsite);
      if (it == merged_callsites_to_table_idx.end()) {
        std::tie(it, std::ignore) = merged_callsites_to_table_idx.emplace(
            merged_callsite, merged_callsites_to_table_idx.size());
        tables::ExperimentalFlamegraphNodesTable::Row row{};
        if (parent_idx) {
          row.depth = tbl->depth()[*parent_idx] + 1;
        } else {
          row.depth = 0;
        }
        row.ts = timestamp;
        row.upid = upid;
        row.profile_type = profile_type;
        row.name = merged_callsite.frame_name;
        row.map_name = merged_callsite.mapping_name;
        if (parent_idx)
          row.parent_id = tbl->id()[*parent_idx].value;

        parent_idx = *tbl->id().IndexOf(tbl->Insert(std::move(row)));
        PERFETTO_CHECK(merged_callsites_to_table_idx.size() ==
                       tbl->row_count());
      }
      parent_idx = it->second;
    }
    PERFETTO_CHECK(parent_idx);
    callsite_to_merged_callsite[i] = *parent_idx;
  }

  // PASS OVER ALLOCATIONS:
  // Aggregate allocations into the newly built tree.
  auto filtered = allocation_tbl.Filter(
      {allocation_tbl.ts().eq(timestamp), allocation_tbl.upid().eq(upid)});

  if (filtered.row_count() == 0) {
    return nullptr;
  }

  for (auto it = filtered.IterateRows(); it; it.Next()) {
    int64_t size =
        it.Get(static_cast<uint32_t>(
                   tables::HeapProfileAllocationTable::ColumnIndex::size))
            .long_value;
    int64_t count =
        it.Get(static_cast<uint32_t>(
                   tables::HeapProfileAllocationTable::ColumnIndex::count))
            .long_value;
    int64_t callsite_id =
        it
            .Get(static_cast<uint32_t>(
                tables::HeapProfileAllocationTable::ColumnIndex::callsite_id))
            .long_value;

    PERFETTO_CHECK((size <= 0 && count <= 0) || (size >= 0 && count >= 0));
    uint32_t merged_idx =
        callsite_to_merged_callsite[*callsites_tbl.id().IndexOf(
            CallsiteId(static_cast<uint32_t>(callsite_id)))];
    if (count > 0) {
      // TODO(fmayer): Clean up types and remove the static_cast.
      tbl->mutable_alloc_size()->Set(merged_idx,
                                     tbl->alloc_size()[merged_idx] + size);
      tbl->mutable_alloc_count()->Set(merged_idx,
                                      tbl->alloc_count()[merged_idx] + count);
    }

    // TODO(fmayer): Clean up types and remove the static_cast.
    tbl->mutable_size()->Set(merged_idx, tbl->size()[merged_idx] + size);
    tbl->mutable_count()->Set(merged_idx, tbl->count()[merged_idx] + count);
  }

  // BACKWARD PASS:
  // Propagate sizes to parents.
  for (int64_t i = tbl->row_count() - 1; i >= 0; --i) {
    uint32_t idx = static_cast<uint32_t>(i);

    tbl->mutable_cumulative_size()->Set(
        idx, tbl->cumulative_size()[idx] + tbl->size()[idx]);
    tbl->mutable_cumulative_count()->Set(
        idx, tbl->cumulative_count()[idx] + tbl->count()[idx]);

    tbl->mutable_cumulative_alloc_size()->Set(
        idx, tbl->cumulative_alloc_size()[idx] + tbl->alloc_size()[idx]);
    tbl->mutable_cumulative_alloc_count()->Set(
        idx, tbl->cumulative_alloc_count()[idx] + tbl->alloc_count()[idx]);

    auto parent = tbl->parent_id()[idx];
    if (parent) {
      uint32_t parent_idx = *tbl->id().IndexOf(
          tables::ExperimentalFlamegraphNodesTable::Id(*parent));
      tbl->mutable_cumulative_size()->Set(
          parent_idx,
          tbl->cumulative_size()[parent_idx] + tbl->cumulative_size()[idx]);
      tbl->mutable_cumulative_count()->Set(
          parent_idx,
          tbl->cumulative_count()[parent_idx] + tbl->cumulative_count()[idx]);

      tbl->mutable_cumulative_alloc_size()->Set(
          parent_idx, tbl->cumulative_alloc_size()[parent_idx] +
                          tbl->cumulative_alloc_size()[idx]);
      tbl->mutable_cumulative_alloc_count()->Set(
          parent_idx, tbl->cumulative_alloc_count()[parent_idx] +
                          tbl->cumulative_alloc_count()[idx]);
    }
  }

  return tbl;
}

HeapProfileTracker::HeapProfileTracker(TraceProcessorContext* context)
    : context_(context), empty_(context_->storage->InternString({"", 0})) {}

HeapProfileTracker::~HeapProfileTracker() = default;

void HeapProfileTracker::SetProfilePacketIndex(uint32_t seq_id,
                                               uint64_t index) {
  SequenceState& sequence_state = sequence_state_[seq_id];
  if (sequence_state.last_profile_packet_index != 0 &&
      sequence_state.last_profile_packet_index + 1 != index) {
    context_->storage->IncrementStats(stats::heapprofd_missing_packet);
  }
  sequence_state.last_profile_packet_index = index;
}

void HeapProfileTracker::AddAllocation(
    uint32_t seq_id,
    StackProfileTracker* stack_profile_tracker,
    const SourceAllocation& alloc,
    const StackProfileTracker::InternLookup* intern_lookup) {
  SequenceState& sequence_state = sequence_state_[seq_id];

  auto maybe_callstack_id = stack_profile_tracker->FindOrInsertCallstack(
      alloc.callstack_id, intern_lookup);
  if (!maybe_callstack_id)
    return;

  CallsiteId callstack_id = *maybe_callstack_id;

  UniquePid upid = context_->process_tracker->GetOrCreateProcess(
      static_cast<uint32_t>(alloc.pid));

  tables::HeapProfileAllocationTable::Row alloc_row{
      alloc.timestamp, upid, callstack_id.value,
      static_cast<int64_t>(alloc.alloc_count),
      static_cast<int64_t>(alloc.self_allocated)};

  tables::HeapProfileAllocationTable::Row free_row{
      alloc.timestamp, upid, callstack_id.value,
      -static_cast<int64_t>(alloc.free_count),
      -static_cast<int64_t>(alloc.self_freed)};

  auto prev_alloc_it = sequence_state.prev_alloc.find({upid, callstack_id});
  if (prev_alloc_it == sequence_state.prev_alloc.end()) {
    std::tie(prev_alloc_it, std::ignore) = sequence_state.prev_alloc.emplace(
        std::make_pair(upid, callstack_id),
        tables::HeapProfileAllocationTable::Row{});
  }

  tables::HeapProfileAllocationTable::Row& prev_alloc = prev_alloc_it->second;

  auto prev_free_it = sequence_state.prev_free.find({upid, callstack_id});
  if (prev_free_it == sequence_state.prev_free.end()) {
    std::tie(prev_free_it, std::ignore) = sequence_state.prev_free.emplace(
        std::make_pair(upid, callstack_id),
        tables::HeapProfileAllocationTable::Row{});
  }

  tables::HeapProfileAllocationTable::Row& prev_free = prev_free_it->second;

  std::set<CallsiteId>& callstacks_for_source_callstack_id =
      sequence_state.seen_callstacks[std::make_pair(upid, alloc.callstack_id)];
  bool new_callstack;
  std::tie(std::ignore, new_callstack) =
      callstacks_for_source_callstack_id.emplace(callstack_id);

  if (new_callstack) {
    sequence_state.alloc_correction[alloc.callstack_id] = prev_alloc;
    sequence_state.free_correction[alloc.callstack_id] = prev_free;
  }

  auto alloc_correction_it =
      sequence_state.alloc_correction.find(alloc.callstack_id);
  if (alloc_correction_it != sequence_state.alloc_correction.end()) {
    const auto& alloc_correction = alloc_correction_it->second;
    alloc_row.count += alloc_correction.count;
    alloc_row.size += alloc_correction.size;
  }

  auto free_correction_it =
      sequence_state.free_correction.find(alloc.callstack_id);
  if (free_correction_it != sequence_state.free_correction.end()) {
    const auto& free_correction = free_correction_it->second;
    free_row.count += free_correction.count;
    free_row.size += free_correction.size;
  }

  tables::HeapProfileAllocationTable::Row alloc_delta = alloc_row;
  tables::HeapProfileAllocationTable::Row free_delta = free_row;

  alloc_delta.count -= prev_alloc.count;
  alloc_delta.size -= prev_alloc.size;
  PERFETTO_DCHECK(alloc_delta.count >= 0);
  PERFETTO_DCHECK(alloc_delta.size >= 0);

  free_delta.count -= prev_free.count;
  free_delta.size -= prev_free.size;
  PERFETTO_DCHECK(free_delta.count <= 0);
  PERFETTO_DCHECK(free_delta.size <= 0);

  if (alloc_delta.count)
    context_->storage->mutable_heap_profile_allocation_table()->Insert(
        alloc_delta);
  if (free_delta.count)
    context_->storage->mutable_heap_profile_allocation_table()->Insert(
        free_delta);

  prev_alloc = alloc_row;
  prev_free = free_row;
}

void HeapProfileTracker::StoreAllocation(uint32_t seq_id,
                                         SourceAllocation alloc) {
  SequenceState& sequence_state = sequence_state_[seq_id];
  sequence_state.pending_allocs.emplace_back(std::move(alloc));
}

void HeapProfileTracker::CommitAllocations(
    uint32_t seq_id,
    StackProfileTracker* stack_profile_tracker,
    const StackProfileTracker::InternLookup* intern_lookup) {
  SequenceState& sequence_state = sequence_state_[seq_id];
  for (const auto& p : sequence_state.pending_allocs)
    AddAllocation(seq_id, stack_profile_tracker, p, intern_lookup);
  sequence_state.pending_allocs.clear();
}

void HeapProfileTracker::FinalizeProfile(
    uint32_t seq_id,
    StackProfileTracker* stack_profile_tracker,
    const StackProfileTracker::InternLookup* intern_lookup) {
  CommitAllocations(seq_id, stack_profile_tracker, intern_lookup);
  stack_profile_tracker->ClearIndices();
}

}  // namespace trace_processor
}  // namespace perfetto
<commit_msg>style: add { } around multi-line statement in if.<commit_after>/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/trace_processor/heap_profile_tracker.h"

#include "src/trace_processor/process_tracker.h"
#include "src/trace_processor/trace_processor_context.h"

#include "perfetto/base/logging.h"

namespace perfetto {
namespace trace_processor {

namespace {
struct MergedCallsite {
  StringId frame_name;
  StringId mapping_name;
  base::Optional<uint32_t> parent_idx;
  bool operator<(const MergedCallsite& o) const {
    return std::tie(frame_name, mapping_name, parent_idx) <
           std::tie(o.frame_name, o.mapping_name, o.parent_idx);
  }
};

std::vector<MergedCallsite> GetMergedCallsites(TraceStorage* storage,
                                               uint32_t callstack_row) {
  const tables::StackProfileCallsiteTable& callsites_tbl =
      storage->stack_profile_callsite_table();
  const tables::StackProfileFrameTable& frames_tbl =
      storage->stack_profile_frame_table();
  const tables::SymbolTable& symbols_tbl = storage->symbol_table();
  const tables::StackProfileMappingTable& mapping_tbl =
      storage->stack_profile_mapping_table();

  // TODO(fmayer): Clean up types and remove the static_cast.
  uint32_t frame_idx = *frames_tbl.id().IndexOf(
      FrameId(static_cast<uint32_t>(callsites_tbl.frame_id()[callstack_row])));

  // TODO(fmayer): Clean up types and remove the static_cast.
  uint32_t mapping_idx = *mapping_tbl.id().IndexOf(
      MappingId(static_cast<uint32_t>(frames_tbl.mapping()[frame_idx])));
  StringId mapping_name = mapping_tbl.name()[mapping_idx];

  base::Optional<uint32_t> symbol_set_id =
      frames_tbl.symbol_set_id()[frame_idx];

  if (!symbol_set_id) {
    StringId frame_name = frames_tbl.name()[frame_idx];
    return {{frame_name, mapping_name, base::nullopt}};
  }

  std::vector<MergedCallsite> result;
  // id == symbol_set_id for the bottommost frame.
  // TODO(lalitm): Encode this optimization in the table and remove this
  // custom optimization.
  uint32_t symbol_set_idx = *symbols_tbl.id().IndexOf(SymbolId(*symbol_set_id));
  for (uint32_t i = symbol_set_idx;
       i < symbols_tbl.row_count() &&
       symbols_tbl.symbol_set_id()[i] == *symbol_set_id;
       ++i) {
    result.emplace_back(
        MergedCallsite{symbols_tbl.name()[i], mapping_name, base::nullopt});
  }
  return result;
}
}  // namespace

std::unique_ptr<tables::ExperimentalFlamegraphNodesTable> BuildNativeFlamegraph(
    TraceStorage* storage,
    UniquePid upid,
    int64_t timestamp) {
  const tables::HeapProfileAllocationTable& allocation_tbl =
      storage->heap_profile_allocation_table();
  const tables::StackProfileCallsiteTable& callsites_tbl =
      storage->stack_profile_callsite_table();

  StringId profile_type = storage->InternString("native");

  std::vector<uint32_t> callsite_to_merged_callsite(callsites_tbl.row_count(),
                                                    0);
  std::map<MergedCallsite, uint32_t> merged_callsites_to_table_idx;

  std::unique_ptr<tables::ExperimentalFlamegraphNodesTable> tbl(
      new tables::ExperimentalFlamegraphNodesTable(
          storage->mutable_string_pool(), nullptr));

  // FORWARD PASS:
  // Aggregate callstacks by frame name / mapping name. Use symbolization data.
  for (uint32_t i = 0; i < callsites_tbl.row_count(); ++i) {
    base::Optional<uint32_t> parent_idx;
    // TODO(fmayer): Clean up types and remove the conditional and static_cast.
    if (callsites_tbl.parent_id()[i] != -1) {
      auto parent_id = static_cast<uint32_t>(callsites_tbl.parent_id()[i]);
      parent_idx = callsites_tbl.id().IndexOf(CallsiteId(parent_id));
      parent_idx = callsite_to_merged_callsite[*parent_idx];
      PERFETTO_CHECK(*parent_idx < i);
    }

    auto callsites = GetMergedCallsites(storage, i);
    for (MergedCallsite& merged_callsite : callsites) {
      merged_callsite.parent_idx = parent_idx;
      auto it = merged_callsites_to_table_idx.find(merged_callsite);
      if (it == merged_callsites_to_table_idx.end()) {
        std::tie(it, std::ignore) = merged_callsites_to_table_idx.emplace(
            merged_callsite, merged_callsites_to_table_idx.size());
        tables::ExperimentalFlamegraphNodesTable::Row row{};
        if (parent_idx) {
          row.depth = tbl->depth()[*parent_idx] + 1;
        } else {
          row.depth = 0;
        }
        row.ts = timestamp;
        row.upid = upid;
        row.profile_type = profile_type;
        row.name = merged_callsite.frame_name;
        row.map_name = merged_callsite.mapping_name;
        if (parent_idx)
          row.parent_id = tbl->id()[*parent_idx].value;

        parent_idx = *tbl->id().IndexOf(tbl->Insert(std::move(row)));
        PERFETTO_CHECK(merged_callsites_to_table_idx.size() ==
                       tbl->row_count());
      }
      parent_idx = it->second;
    }
    PERFETTO_CHECK(parent_idx);
    callsite_to_merged_callsite[i] = *parent_idx;
  }

  // PASS OVER ALLOCATIONS:
  // Aggregate allocations into the newly built tree.
  auto filtered = allocation_tbl.Filter(
      {allocation_tbl.ts().eq(timestamp), allocation_tbl.upid().eq(upid)});

  if (filtered.row_count() == 0) {
    return nullptr;
  }

  for (auto it = filtered.IterateRows(); it; it.Next()) {
    int64_t size =
        it.Get(static_cast<uint32_t>(
                   tables::HeapProfileAllocationTable::ColumnIndex::size))
            .long_value;
    int64_t count =
        it.Get(static_cast<uint32_t>(
                   tables::HeapProfileAllocationTable::ColumnIndex::count))
            .long_value;
    int64_t callsite_id =
        it
            .Get(static_cast<uint32_t>(
                tables::HeapProfileAllocationTable::ColumnIndex::callsite_id))
            .long_value;

    PERFETTO_CHECK((size <= 0 && count <= 0) || (size >= 0 && count >= 0));
    uint32_t merged_idx =
        callsite_to_merged_callsite[*callsites_tbl.id().IndexOf(
            CallsiteId(static_cast<uint32_t>(callsite_id)))];
    if (count > 0) {
      // TODO(fmayer): Clean up types and remove the static_cast.
      tbl->mutable_alloc_size()->Set(merged_idx,
                                     tbl->alloc_size()[merged_idx] + size);
      tbl->mutable_alloc_count()->Set(merged_idx,
                                      tbl->alloc_count()[merged_idx] + count);
    }

    // TODO(fmayer): Clean up types and remove the static_cast.
    tbl->mutable_size()->Set(merged_idx, tbl->size()[merged_idx] + size);
    tbl->mutable_count()->Set(merged_idx, tbl->count()[merged_idx] + count);
  }

  // BACKWARD PASS:
  // Propagate sizes to parents.
  for (int64_t i = tbl->row_count() - 1; i >= 0; --i) {
    uint32_t idx = static_cast<uint32_t>(i);

    tbl->mutable_cumulative_size()->Set(
        idx, tbl->cumulative_size()[idx] + tbl->size()[idx]);
    tbl->mutable_cumulative_count()->Set(
        idx, tbl->cumulative_count()[idx] + tbl->count()[idx]);

    tbl->mutable_cumulative_alloc_size()->Set(
        idx, tbl->cumulative_alloc_size()[idx] + tbl->alloc_size()[idx]);
    tbl->mutable_cumulative_alloc_count()->Set(
        idx, tbl->cumulative_alloc_count()[idx] + tbl->alloc_count()[idx]);

    auto parent = tbl->parent_id()[idx];
    if (parent) {
      uint32_t parent_idx = *tbl->id().IndexOf(
          tables::ExperimentalFlamegraphNodesTable::Id(*parent));
      tbl->mutable_cumulative_size()->Set(
          parent_idx,
          tbl->cumulative_size()[parent_idx] + tbl->cumulative_size()[idx]);
      tbl->mutable_cumulative_count()->Set(
          parent_idx,
          tbl->cumulative_count()[parent_idx] + tbl->cumulative_count()[idx]);

      tbl->mutable_cumulative_alloc_size()->Set(
          parent_idx, tbl->cumulative_alloc_size()[parent_idx] +
                          tbl->cumulative_alloc_size()[idx]);
      tbl->mutable_cumulative_alloc_count()->Set(
          parent_idx, tbl->cumulative_alloc_count()[parent_idx] +
                          tbl->cumulative_alloc_count()[idx]);
    }
  }

  return tbl;
}

HeapProfileTracker::HeapProfileTracker(TraceProcessorContext* context)
    : context_(context), empty_(context_->storage->InternString({"", 0})) {}

HeapProfileTracker::~HeapProfileTracker() = default;

void HeapProfileTracker::SetProfilePacketIndex(uint32_t seq_id,
                                               uint64_t index) {
  SequenceState& sequence_state = sequence_state_[seq_id];
  if (sequence_state.last_profile_packet_index != 0 &&
      sequence_state.last_profile_packet_index + 1 != index) {
    context_->storage->IncrementStats(stats::heapprofd_missing_packet);
  }
  sequence_state.last_profile_packet_index = index;
}

void HeapProfileTracker::AddAllocation(
    uint32_t seq_id,
    StackProfileTracker* stack_profile_tracker,
    const SourceAllocation& alloc,
    const StackProfileTracker::InternLookup* intern_lookup) {
  SequenceState& sequence_state = sequence_state_[seq_id];

  auto maybe_callstack_id = stack_profile_tracker->FindOrInsertCallstack(
      alloc.callstack_id, intern_lookup);
  if (!maybe_callstack_id)
    return;

  CallsiteId callstack_id = *maybe_callstack_id;

  UniquePid upid = context_->process_tracker->GetOrCreateProcess(
      static_cast<uint32_t>(alloc.pid));

  tables::HeapProfileAllocationTable::Row alloc_row{
      alloc.timestamp, upid, callstack_id.value,
      static_cast<int64_t>(alloc.alloc_count),
      static_cast<int64_t>(alloc.self_allocated)};

  tables::HeapProfileAllocationTable::Row free_row{
      alloc.timestamp, upid, callstack_id.value,
      -static_cast<int64_t>(alloc.free_count),
      -static_cast<int64_t>(alloc.self_freed)};

  auto prev_alloc_it = sequence_state.prev_alloc.find({upid, callstack_id});
  if (prev_alloc_it == sequence_state.prev_alloc.end()) {
    std::tie(prev_alloc_it, std::ignore) = sequence_state.prev_alloc.emplace(
        std::make_pair(upid, callstack_id),
        tables::HeapProfileAllocationTable::Row{});
  }

  tables::HeapProfileAllocationTable::Row& prev_alloc = prev_alloc_it->second;

  auto prev_free_it = sequence_state.prev_free.find({upid, callstack_id});
  if (prev_free_it == sequence_state.prev_free.end()) {
    std::tie(prev_free_it, std::ignore) = sequence_state.prev_free.emplace(
        std::make_pair(upid, callstack_id),
        tables::HeapProfileAllocationTable::Row{});
  }

  tables::HeapProfileAllocationTable::Row& prev_free = prev_free_it->second;

  std::set<CallsiteId>& callstacks_for_source_callstack_id =
      sequence_state.seen_callstacks[std::make_pair(upid, alloc.callstack_id)];
  bool new_callstack;
  std::tie(std::ignore, new_callstack) =
      callstacks_for_source_callstack_id.emplace(callstack_id);

  if (new_callstack) {
    sequence_state.alloc_correction[alloc.callstack_id] = prev_alloc;
    sequence_state.free_correction[alloc.callstack_id] = prev_free;
  }

  auto alloc_correction_it =
      sequence_state.alloc_correction.find(alloc.callstack_id);
  if (alloc_correction_it != sequence_state.alloc_correction.end()) {
    const auto& alloc_correction = alloc_correction_it->second;
    alloc_row.count += alloc_correction.count;
    alloc_row.size += alloc_correction.size;
  }

  auto free_correction_it =
      sequence_state.free_correction.find(alloc.callstack_id);
  if (free_correction_it != sequence_state.free_correction.end()) {
    const auto& free_correction = free_correction_it->second;
    free_row.count += free_correction.count;
    free_row.size += free_correction.size;
  }

  tables::HeapProfileAllocationTable::Row alloc_delta = alloc_row;
  tables::HeapProfileAllocationTable::Row free_delta = free_row;

  alloc_delta.count -= prev_alloc.count;
  alloc_delta.size -= prev_alloc.size;
  PERFETTO_DCHECK(alloc_delta.count >= 0);
  PERFETTO_DCHECK(alloc_delta.size >= 0);

  free_delta.count -= prev_free.count;
  free_delta.size -= prev_free.size;
  PERFETTO_DCHECK(free_delta.count <= 0);
  PERFETTO_DCHECK(free_delta.size <= 0);

  if (alloc_delta.count) {
    context_->storage->mutable_heap_profile_allocation_table()->Insert(
        alloc_delta);
  }
  if (free_delta.count) {
    context_->storage->mutable_heap_profile_allocation_table()->Insert(
        free_delta);
  }

  prev_alloc = alloc_row;
  prev_free = free_row;
}

void HeapProfileTracker::StoreAllocation(uint32_t seq_id,
                                         SourceAllocation alloc) {
  SequenceState& sequence_state = sequence_state_[seq_id];
  sequence_state.pending_allocs.emplace_back(std::move(alloc));
}

void HeapProfileTracker::CommitAllocations(
    uint32_t seq_id,
    StackProfileTracker* stack_profile_tracker,
    const StackProfileTracker::InternLookup* intern_lookup) {
  SequenceState& sequence_state = sequence_state_[seq_id];
  for (const auto& p : sequence_state.pending_allocs)
    AddAllocation(seq_id, stack_profile_tracker, p, intern_lookup);
  sequence_state.pending_allocs.clear();
}

void HeapProfileTracker::FinalizeProfile(
    uint32_t seq_id,
    StackProfileTracker* stack_profile_tracker,
    const StackProfileTracker::InternLookup* intern_lookup) {
  CommitAllocations(seq_id, stack_profile_tracker, intern_lookup);
  stack_profile_tracker->ClearIndices();
}

}  // namespace trace_processor
}  // namespace perfetto
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: canvasbitmap.hxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: kz $ $Date: 2005-11-02 12:58:32 $
 *
 *  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
 *
 ************************************************************************/

#ifndef _VCLCANVAS_CANVASBITMAP_HXX
#define _VCLCANVAS_CANVASBITMAP_HXX

#include <cppuhelper/compbase3.hxx>

#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/rendering/XBitmapCanvas.hpp>
#include <com/sun/star/rendering/XIntegerBitmap.hpp>

#include <vcl/virdev.hxx>
#include <vcl/bitmapex.hxx>

#include <canvas/vclwrapper.hxx>

#include <canvas/base/integerbitmapbase.hxx>
#include <canvasbitmaphelper.hxx>

#include "impltools.hxx"
#include "repainttarget.hxx"
#include "spritecanvas.hxx"

/* Definition of CanvasBitmap class */

namespace vclcanvas
{
    typedef ::cppu::WeakComponentImplHelper3< ::com::sun::star::rendering::XBitmapCanvas,
                                               ::com::sun::star::rendering::XIntegerBitmap,
                                                ::com::sun::star::lang::XServiceInfo >      CanvasBitmapBase_Base;
    typedef ::canvas::IntegerBitmapBase< ::canvas::BaseMutexHelper< CanvasBitmapBase_Base >,
                                         CanvasBitmapHelper,
                                         tools::LocalGuard,
                                         ::cppu::OWeakObject >                          CanvasBitmap_Base;

    class CanvasBitmap : public CanvasBitmap_Base,
                         public RepaintTarget
    {
    public:
        /** Must be called with locked Solar mutex

            @param rSize
            Size in pixel of the bitmap to generate

            @param bAlphaBitmap
            When true, bitmap will have an alpha channel

            @param rDevice
            Reference device, with which bitmap should be compatible
         */
        CanvasBitmap( const ::Size&     rSize,
                      bool              bAlphaBitmap,
                      const DeviceRef&  rDevice );

        /// Must be called with locked Solar mutex
        CanvasBitmap( const BitmapEx&   rBitmap,
                      const DeviceRef&  rDevice );

        // overridden because of mpDevice
        virtual void SAL_CALL disposing();

        // XServiceInfo
        virtual ::rtl::OUString SAL_CALL getImplementationName(  ) throw (::com::sun::star::uno::RuntimeException);
        virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (::com::sun::star::uno::RuntimeException);
        virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames(  ) throw (::com::sun::star::uno::RuntimeException);

        // RepaintTarget interface
        virtual bool repaint( const GraphicObjectSharedPtr& rGrf,
                              const ::Point&                rPt,
                              const ::Size&                 rSz,
                              const GraphicAttr&            rAttr ) const;

        /// Not threadsafe! Returned object is shared!
        BitmapEx getBitmap() const;

    private:
        /** MUST hold here, too, since CanvasHelper only contains a
            raw pointer (without refcounting)
        */
        DeviceRef   mpDevice;
    };
}

#endif /* _VCLCANVAS_CANVASBITMAP_HXX */
<commit_msg>INTEGRATION: CWS thbpp9_SRC680 (1.7.114); FILE MERGED 2007/10/17 21:14:36 thb 1.7.114.1: #i82485# Carry clips along, also for XCachedPrimitive repaints<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: canvasbitmap.hxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: hr $ $Date: 2007-11-01 14:40:48 $
 *
 *  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
 *
 ************************************************************************/

#ifndef _VCLCANVAS_CANVASBITMAP_HXX
#define _VCLCANVAS_CANVASBITMAP_HXX

#include <cppuhelper/compbase3.hxx>

#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/rendering/XBitmapCanvas.hpp>
#include <com/sun/star/rendering/XIntegerBitmap.hpp>

#include <vcl/virdev.hxx>
#include <vcl/bitmapex.hxx>

#include <canvas/vclwrapper.hxx>

#include <canvas/base/integerbitmapbase.hxx>
#include <canvasbitmaphelper.hxx>

#include "impltools.hxx"
#include "repainttarget.hxx"
#include "spritecanvas.hxx"

/* Definition of CanvasBitmap class */

namespace vclcanvas
{
    typedef ::cppu::WeakComponentImplHelper3< ::com::sun::star::rendering::XBitmapCanvas,
                                               ::com::sun::star::rendering::XIntegerBitmap,
                                                ::com::sun::star::lang::XServiceInfo >      CanvasBitmapBase_Base;
    typedef ::canvas::IntegerBitmapBase< ::canvas::BaseMutexHelper< CanvasBitmapBase_Base >,
                                         CanvasBitmapHelper,
                                         tools::LocalGuard,
                                         ::cppu::OWeakObject >                          CanvasBitmap_Base;

    class CanvasBitmap : public CanvasBitmap_Base,
                         public RepaintTarget
    {
    public:
        /** Must be called with locked Solar mutex

            @param rSize
            Size in pixel of the bitmap to generate

            @param bAlphaBitmap
            When true, bitmap will have an alpha channel

            @param rDevice
            Reference device, with which bitmap should be compatible
         */
        CanvasBitmap( const ::Size&     rSize,
                      bool              bAlphaBitmap,
                      const DeviceRef&  rDevice );

        /// Must be called with locked Solar mutex
        CanvasBitmap( const BitmapEx&   rBitmap,
                      const DeviceRef&  rDevice );

        // overridden because of mpDevice
        virtual void SAL_CALL disposing();

        // XServiceInfo
        virtual ::rtl::OUString SAL_CALL getImplementationName(  ) throw (::com::sun::star::uno::RuntimeException);
        virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (::com::sun::star::uno::RuntimeException);
        virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames(  ) throw (::com::sun::star::uno::RuntimeException);

        // RepaintTarget interface
        virtual bool repaint( const GraphicObjectSharedPtr&                   rGrf,
                              const ::com::sun::star::rendering::ViewState&   viewState,
                              const ::com::sun::star::rendering::RenderState& renderState,
                              const ::Point&                                  rPt,
                              const ::Size&                                   rSz,
                              const GraphicAttr&                              rAttr ) const;

        /// Not threadsafe! Returned object is shared!
        BitmapEx getBitmap() const;

    private:
        /** MUST hold here, too, since CanvasHelper only contains a
            raw pointer (without refcounting)
        */
        DeviceRef   mpDevice;
    };
}

#endif /* _VCLCANVAS_CANVASBITMAP_HXX */
<|endoftext|>


<commit_before><commit_msg>create directory items in zip file<commit_after><|endoftext|>


<commit_before>#include <QDateTime>
#include <QFileInfo>
#include <QtGlobal>
#include <QSettings>

#include "mooapp.h"
#include "object.h"
#include "objectmanager.h"
#include "connectionmanager.h"
#include "task.h"
#include "connection.h"
#include "lua_moo.h"
#include "lua_object.h"
#include "lua_connection.h"
#include "lua_prop.h"
#include "lua_verb.h"
#include "lua_task.h"
#include <iostream>
#include <algorithm>
#include <QDateTime>
#include <QTimer>

#include "osc.h"

#include "odb_file.h"
#include "odb_sql.h"

mooApp::mooApp( const QString &pDataFileName, QObject *pParent )
	: QObject( pParent ), mTimerId( 0 ), mDataFileName( pDataFileName )
{
	QSettings::setDefaultFormat( QSettings::IniFormat );

	connect( this, SIGNAL(destroyed(QObject*)), this, SLOT(cleanup(QObject*)));

	lua_moo::initialiseAll();

	ObjectManager		&OM = *ObjectManager::instance();

	OSC::deviceInitialise();

	bool LoadFromFile = !QFileInfo( "moo.db" ).exists();

	ODBSQL		*SQL = new ODBSQL();

	if( SQL )
	{
		OM.setODB( SQL );
	}

	if( LoadFromFile )
	{
		ODBFile		ODB( mDataFileName );

		ODB.load();

		SQL->save();
	}
	else
	{
		SQL->load();
	}

	if( OM.maxId() == 0 )
	{
		OM.luaMinimal();
	}

	if( OM.object( 0 ) != 0 )
	{
		QList<Object *>		ObjLst = ObjectManager::instance()->connectedPlayers();

		for( Object *O : ObjLst )
		{
			QString			 CMD = QString( "moo.root:user_disconnected( o( %1 ) )" ).arg( O->id() );
			TaskEntry		 TE( CMD, 0, 0 );
			lua_task		 Com( 0, TE );

			Com.eval();

			O->setConnection( -1 );
		}

		if( true )
		{
			QString			 CMD = QString( "moo.root:server_started()" );
			TaskEntry		 TE( CMD, 0, 0 );
			lua_task		 Com( 0, TE );

			Com.eval();
		}
	}

	qDebug() << "Time to next task:" << OM.timeToNextTask();

	connect( &mTimer, SIGNAL(timeout()), this, SLOT(taskReady()) );

	mTimer.setSingleShot( true );

	connect( &OM, SIGNAL(taskReady()), this, SLOT(taskReady()), Qt::QueuedConnection );

	taskReady();
}

void mooApp::cleanup( QObject *pObject )
{
	Q_UNUSED( pObject )
}

mooApp::~mooApp()
{
	if( mTimerId == 0 )
	{
		killTimer( mTimerId );
	}

	ODB			*OM_ODB = ObjectManager::instance()->odb();

	if( OM_ODB )
	{
		OM_ODB->save();
	}

	ObjectManager::instance()->reset();

	OSC::deviceDeinitialise();
}

void mooApp::doOutput( const QString &pText )
{
	emit textOutput( pText );
}

void mooApp::taskReady()
{
	ObjectManager		&OM = *ObjectManager::instance();

//	mTimer.stop();

	qint64	TimeStamp = QDateTime::currentMSecsSinceEpoch();

	OSC::devicePacketStart( TimeStamp );

	emit frameStart();
	emit frameStart( TimeStamp );

	OM.onFrame( TimeStamp );

	emit frameEnd();
	emit frameEnd( TimeStamp );

	OSC::devicePacketEnd( TimeStamp );

	qint64		TimeToNext = OM.timeToNextTask();

	if( TimeToNext > 0 )
	{
		mTimer.setInterval( qMin( 1000LL, TimeToNext ) );
		mTimer.start();
	}
	else
	{
		mTimer.setInterval( 1000 );
		mTimer.start();
	}
}

void mooApp::streamCallback( const QString &pText, void *pUserData )
{
	((mooApp*)pUserData)->doOutput( pText );
}

void mooApp::timerEvent( QTimerEvent *pEvent )
{
	Q_UNUSED( pEvent )

	qint64	TimeStamp = QDateTime::currentMSecsSinceEpoch();

	OSC::devicePacketStart( TimeStamp );

	emit frameStart();
	emit frameStart( TimeStamp );

	ObjectManager::instance()->onFrame( TimeStamp );

	emit frameEnd();
	emit frameEnd( TimeStamp );

	OSC::devicePacketEnd( TimeStamp );
}

void mooApp::doTask( TaskEntry &pTask )
{
	ObjectManager::instance()->doTask( pTask );
}

<commit_msg>Cleaned startup<commit_after>#include <QDateTime>
#include <QFileInfo>
#include <QtGlobal>
#include <QSettings>

#include "mooapp.h"
#include "object.h"
#include "objectmanager.h"
#include "connectionmanager.h"
#include "task.h"
#include "connection.h"
#include "lua_moo.h"
#include "lua_object.h"
#include "lua_connection.h"
#include "lua_prop.h"
#include "lua_verb.h"
#include "lua_task.h"
#include <iostream>
#include <algorithm>
#include <QDateTime>
#include <QTimer>

#include "osc.h"

#include "odb_file.h"
#include "odb_sql.h"

mooApp::mooApp( const QString &pDataFileName, QObject *pParent )
	: QObject( pParent ), mTimerId( 0 ), mDataFileName( pDataFileName )
{
	QSettings::setDefaultFormat( QSettings::IniFormat );

	connect( this, SIGNAL(destroyed(QObject*)), this, SLOT(cleanup(QObject*)));

	lua_moo::initialiseAll();

	ObjectManager		&OM = *ObjectManager::instance();

	OSC::deviceInitialise();

	bool LoadFromFile = !QFileInfo( "moo.db" ).exists();

	ODBSQL		*SQL = new ODBSQL();

	if( SQL )
	{
		OM.setODB( SQL );
	}

	if( LoadFromFile )
	{
		ODBFile		ODB( mDataFileName );

		ODB.load();

		SQL->save();
	}
	else
	{
		SQL->load();
	}

	if( OM.maxId() == 0 )
	{
		OM.luaMinimal();
	}

	Object		*Root = OM.object( 0 );

	if( Root )
	{
		QList<Object *>		ObjLst = ObjectManager::instance()->connectedPlayers();

		bool		HasVerb = Root->verb( "user_disconnected" );

		for( Object *O : ObjLst )
		{
			if( HasVerb )
			{
				QString			 CMD = QString( "moo.root:user_disconnected( o( %1 ) )" ).arg( O->id() );
				TaskEntry		 TE( CMD, 0, 0 );
				lua_task		 Com( 0, TE );

				Com.eval();
			}

			O->setConnection( -1 );
		}

		if( Root->verb( "server_started" ) )
		{
			QString			 CMD = QString( "moo.root:server_started()" );
			TaskEntry		 TE( CMD, 0, 0 );
			lua_task		 Com( 0, TE );

			Com.eval();
		}
	}

	qint64		TimeToNextTask = OM.timeToNextTask();

	if( TimeToNextTask >= 0 )
	{
		qDebug() << "Time to next task:" << TimeToNextTask;
	}

	connect( &mTimer, SIGNAL(timeout()), this, SLOT(taskReady()) );

	mTimer.setSingleShot( true );

	connect( &OM, SIGNAL(taskReady()), this, SLOT(taskReady()), Qt::QueuedConnection );

	taskReady();
}

void mooApp::cleanup( QObject *pObject )
{
	Q_UNUSED( pObject )
}

mooApp::~mooApp()
{
	if( mTimerId == 0 )
	{
		killTimer( mTimerId );
	}

	ODB			*OM_ODB = ObjectManager::instance()->odb();

	if( OM_ODB )
	{
		OM_ODB->save();
	}

	ObjectManager::instance()->reset();

	OSC::deviceDeinitialise();
}

void mooApp::doOutput( const QString &pText )
{
	emit textOutput( pText );
}

void mooApp::taskReady()
{
	ObjectManager		&OM = *ObjectManager::instance();

//	mTimer.stop();

	qint64	TimeStamp = QDateTime::currentMSecsSinceEpoch();

	OSC::devicePacketStart( TimeStamp );

	emit frameStart();
	emit frameStart( TimeStamp );

	OM.onFrame( TimeStamp );

	emit frameEnd();
	emit frameEnd( TimeStamp );

	OSC::devicePacketEnd( TimeStamp );

	qint64		TimeToNext = OM.timeToNextTask();

	if( TimeToNext > 0 )
	{
		mTimer.setInterval( qMin( 1000LL, TimeToNext ) );
		mTimer.start();
	}
	else
	{
		mTimer.setInterval( 1000 );
		mTimer.start();
	}
}

void mooApp::streamCallback( const QString &pText, void *pUserData )
{
	((mooApp*)pUserData)->doOutput( pText );
}

void mooApp::timerEvent( QTimerEvent *pEvent )
{
	Q_UNUSED( pEvent )

	qint64	TimeStamp = QDateTime::currentMSecsSinceEpoch();

	OSC::devicePacketStart( TimeStamp );

	emit frameStart();
	emit frameStart( TimeStamp );

	ObjectManager::instance()->onFrame( TimeStamp );

	emit frameEnd();
	emit frameEnd( TimeStamp );

	OSC::devicePacketEnd( TimeStamp );
}

void mooApp::doTask( TaskEntry &pTask )
{
	ObjectManager::instance()->doTask( pTask );
}

<|endoftext|>


<commit_before>/* -*- C++ -*- */
/*************************************************************************
 * Copyright(c) 1995~2005  Masaharu Goto (cint@pcroot.cern.ch)
 *
 * For the licensing terms see the file COPYING
 *
 ************************************************************************/

#include <stdio.h>

#define TEST

class A {
  int i;
 public:
  A(int iin=0) : i(iin) { }
  operator int() const { return i; }
  void disp() const { printf("%d\n",i); }
#ifdef TEST
  friend const A& operator+=(const A& a,const A& b) ;
#endif
  friend A& operator+=(A& a,int b) ;

};

#ifdef TEST
const A& operator+=(const A& a,const A& b) {
  printf("operator+=(const A&,const A&)\n");
  return(a);
}
#endif

A& operator+=(A& a,int b) {
  printf("operator+=(A&,int)\n");
  a.i += b;
  return(a);
}

int main() {
  A a(3);
  const A ac(4),ad(5);
  a.disp();
  a += 4;
  a.disp();
  ac += ad;
  a.disp();

  ac.disp();
  ac += 5;
  ac.disp();
  ac += ad;
  ac.disp();

  return 0;
}

<commit_msg>hide expected failure to find the correct operator overload<commit_after>/* -*- C++ -*- */
/*************************************************************************
 * Copyright(c) 1995~2005  Masaharu Goto (cint@pcroot.cern.ch)
 *
 * For the licensing terms see the file COPYING
 *
 ************************************************************************/

#include <stdio.h>

#define TEST

class A {
  int i;
 public:
  A(int iin=0) : i(iin) { }
  operator int() const { return i; }
  void disp() const { printf("%d\n",i); }
#ifdef TEST
  friend const A& operator+=(const A& a,const A& b) ;
#endif
  friend A& operator+=(A& a,int b) ;

};

#ifdef TEST
const A& operator+=(const A& a,const A& b) {
  printf("operator+=(const A&,const A&)\n");
  return(a);
}
#endif

A& operator+=(A& a,int b) {
  printf("operator+=(A&,int)\n");
  a.i += b;
  return(a);
}

int main() {
  A a(3);
  const A ac(4),ad(5);
  a.disp();
  a += 4;
  a.disp();
  ac += ad;
  a.disp();

#ifndef CINT_HIDE_FAILURE
  ac.disp();
  ac += 5;
  ac.disp();
  ac += ad;
  ac.disp();
#endif

  return 0;
}

<|endoftext|>


<commit_before>/* -*- C++ -*- */
/*************************************************************************
 * Copyright(c) 1995~2005  Masaharu Goto (cint@pcroot.cern.ch)
 *
 * For the licensing terms see the file COPYING
 *
 ************************************************************************/

// Start of tt.C
#include<iostream>
using namespace std;
void prna( char (*p)[4][4]) // It doesn't work in CINT
{
#if 0
  cout<< "prna value of p        :" << (void*) p << endl;
  cout<< "prna loc of p[1][1]    :" << (void*)&(p[1][1])<<endl;
#endif
  cout<< "casted value of p[1][1]:" << (char*)&(p[1][1])<<endl;
  cout<< "value of p[1][1]       :" << p[1][1] <<endl;
  const char *str = p[1][1];
  cout << " I see:" << str << endl;
  cout << endl;
}
void prnc(char p[][4][4]) //Call by reference  It doesn't work in CINT
{
#if 0
  cout<< "prnb value of p        :" << (void*) p << endl;
  cout<< "prnb loc of p[1][1]    :" << (void*)&(p[1][1])<<endl;
#endif
  cout<< "casted value of p[1][1]:" << (char*)&(p[1][1])<<endl;
  cout<< "value of p[1][1]       :" << p[1][1] <<endl;
  const char *str = p[1][1];
  cout << " I see:" << str << endl;
  cout << endl;
}

void prnb( char *p[4][4])
{
#if 0
  cout<< (void*) p << endl;
#endif
  cout<<p[1][1]<<endl;
}

void zsendarray()
{
  char a[3][4][4] = {     {"aaa","bbb","ccc","ddd"}
			  ,{"eee","fff","ggg"}
			  ,{"iii","jjj","kkk","lll"}
  };
  char* b[4][4] = {     {"aaa","bbb","ccc","ddd"}
			,{"eee","fff","ggg"}
			,{"iii","jjj","kkk","lll"}
  };
  cout << &(a[0][0][0]) << endl;
  cout << &(a[0][1][0]) << endl;
  cout << &(a[0][2][0]) << endl;
  cout << &(a[0][3][0]) << endl;
  cout << &(a[1][0][0]) << endl;
  cout << &(a[1][1][0]) << endl;

#if 0
  cout << "start of a: " << (void*)a << endl;
  cout << "loc of a[1][1]: " << (void*)&(a[1][1][0]) << endl;
#endif
  cout << endl;

  prna(a);
  prnc(a);
  prnb(b);
}

void t1157() { zsendarray(); }

int main() {zsendarray(); return(0);}

<commit_msg>Fix usage of string constant.<commit_after>/* -*- C++ -*- */
/*************************************************************************
 * Copyright(c) 1995~2005  Masaharu Goto (cint@pcroot.cern.ch)
 *
 * For the licensing terms see the file COPYING
 *
 ************************************************************************/

#include <iostream>

using namespace std;

void prna(char (*p)[4][4])   // It doesn't work in CINT
{
   cout << "casted value of p[1][1]:" << (char*) &p[1][1] << endl;
   cout << "value of p[1][1]       :" << p[1][1] << endl;
   const char* str = p[1][1];
   cout << " I see:" << str << endl;
   cout << endl;
}

void prnc(char p[][4][4]) // Call by pointer to first element  It doesn't work in CINT
{
   cout << "casted value of p[1][1]:" << (char*) &p[1][1] << endl;
   cout << "value of p[1][1]       :" << p[1][1] << endl;
   const char* str = p[1][1];
   cout << " I see:" << str << endl;
   cout << endl;
}

void prnb(const char* p[4][4])
{
   cout << p[1][1] << endl;
}

void zsendarray()
{
   char a[3][4][4] = {
        {"aaa", "bbb", "ccc", "ddd"}
      , {"eee", "fff", "ggg"}
      , {"iii", "jjj", "kkk", "lll"}
   };
   const char* b[4][4] = {
        {"aaa", "bbb", "ccc", "ddd"}
      , {"eee", "fff", "ggg"}
      , {"iii", "jjj", "kkk", "lll"}
   };
   cout << &a[0][0][0] << endl;
   cout << &a[0][1][0] << endl;
   cout << &a[0][2][0] << endl;
   cout << &a[0][3][0] << endl;
   cout << &a[1][0][0] << endl;
   cout << &a[1][1][0] << endl;
   cout << endl;
   prna(a);
   prnc(a);
   prnb(b);
}

void t1157()
{
   zsendarray();
}

int main()
{
   zsendarray();
   return 0;
}

<|endoftext|>