<commit_before> /*
  * jabberfiletransfer.cpp
  *
  * Copyright (c) 2004 by Till Gerken <till@tantalo.net>
  *
  * Kopete    (c) by the Kopete developers  <kopete-devel@kde.org>
  *
  * *************************************************************************
  * *                                                                       *
  * * This program is free software; you can redistribute it and/or modify  *
  * * it under the terms of the GNU General Public License as published by  *
  * * the Free Software Foundation; either version 2 of the License, or     *
  * * (at your option) any later version.                                   *
  * *                                                                       *
  * *************************************************************************
  */

#include <kdebug.h>
#include <im.h>
#include <xmpp.h>
#include "jabberfiletransfer.h"
#include <klocale.h>
#include "kopetemetacontact.h"
#include "kopetecontactlist.h"
#include "kopetetransfermanager.h"
#include "jabberaccount.h"
#include "jabberprotocol.h"
#include "jabbercontactpool.h"
#include "jabberbasecontact.h"
#include "jabbercontact.h"

JabberFileTransfer::JabberFileTransfer ( JabberAccount *account, XMPP::FileTransfer *incomingTransfer )
{
	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "New incoming transfer from " << incomingTransfer->peer().full () << ", filename " << incomingTransfer->fileName () << ", size " << QString::number ( incomingTransfer->fileSize () ) << endl;

	mAccount = account;
	mXMPPTransfer = incomingTransfer;

	// try to locate an exact match in our pool first
	JabberBaseContact *contact = mAccount->contactPool()->findExactMatch ( mXMPPTransfer->peer () );

	if ( !contact )
	{
		// we have no exact match, try a broader search
		contact = mAccount->contactPool()->findRelevantRecipient ( mXMPPTransfer->peer () );
	}

	if ( !contact )
	{
		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "No matching local contact found, creating a new one." << endl;

		KopeteMetaContact *metaContact = new KopeteMetaContact ();

		metaContact->setTemporary (true);

		contact = mAccount->contactPool()->addContact ( mXMPPTransfer->peer (), metaContact, false );

		KopeteContactList::contactList ()->addMetaContact ( metaContact );
	}

	connect ( KopeteTransferManager::transferManager (), SIGNAL ( accepted ( KopeteTransfer *, const QString & ) ),
			  this, SLOT ( slotIncomingTransferAccepted ( KopeteTransfer *, const QString & ) ) );
	connect ( KopeteTransferManager::transferManager (), SIGNAL ( refused ( const KopeteFileTransferInfo & ) ),
			  this, SLOT ( slotTransferRefused ( const KopeteFileTransferInfo & ) ) );

	initializeVariables ();

	mTransferId = KopeteTransferManager::transferManager()->askIncomingTransfer ( contact,
																				  mXMPPTransfer->fileName (),
																				  mXMPPTransfer->fileSize (),
																				  mXMPPTransfer->description () );

}

JabberFileTransfer::JabberFileTransfer ( JabberAccount *account, JabberBaseContact *contact, const QString &file )
{
	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "New outgoing transfer for " << contact->contactId() << ": " << file << endl;

	mAccount = account;
	mLocalFile.setName ( file );
	mLocalFile.open ( IO_ReadOnly );

	mKopeteTransfer = KopeteTransferManager::transferManager()->addTransfer ( contact,
																			  mLocalFile.name (),
																			  mLocalFile.size (),
																			  contact->contactId (),
																			  KopeteFileTransferInfo::Outgoing );

 	connect ( mKopeteTransfer, SIGNAL ( result ( KIO::Job * ) ), this, SLOT ( slotTransferResult () ) );

	mXMPPTransfer = mAccount->client()->fileTransferManager()->createTransfer ();

	initializeVariables ();

	connect ( mXMPPTransfer, SIGNAL ( connected () ), this, SLOT ( slotOutgoingConnected () ) );
	connect ( mXMPPTransfer, SIGNAL ( bytesWritten ( int ) ), this, SLOT ( slotOutgoingBytesWritten ( int ) ) );
	connect ( mXMPPTransfer, SIGNAL ( error ( int ) ), this, SLOT ( slotTransferError ( int ) ) );

	mXMPPTransfer->sendFile ( XMPP::Jid ( contact->fullAddress () ), KURL(file).fileName (), mLocalFile.size (), "" );

}

JabberFileTransfer::~JabberFileTransfer ()
{
	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Destroying Jabber file transfer object." << endl;

	mLocalFile.close ();

	mXMPPTransfer->close ();
	delete mXMPPTransfer;

}

void JabberFileTransfer::initializeVariables ()
{

	mTransferId = -1;
	mBytesTransferred = 0;
	mBytesToTransfer = 0;
	mXMPPTransfer->setProxy ( XMPP::Jid ( mAccount->pluginData ( mAccount->protocol (), "ProxyJID" ) ) );

}

void JabberFileTransfer::slotIncomingTransferAccepted ( KopeteTransfer *transfer, const QString &fileName )
{

	if ( (long)transfer->info().transferId () != mTransferId )
		return;

	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Accepting transfer for " << mXMPPTransfer->peer().full () << endl;

	mKopeteTransfer = transfer;
	mLocalFile.setName ( fileName );

	if ( !mLocalFile.open ( IO_WriteOnly ) )
	{
		transfer->slotError ( KopeteTransfer::Other, i18n("Could not write to the local file.") );

		deleteLater ();
	}
	else
	{
	 	connect ( mKopeteTransfer, SIGNAL ( result ( KIO::Job * ) ), this, SLOT ( slotTransferResult () ) );
		connect ( mXMPPTransfer, SIGNAL ( readyRead ( const QByteArray& ) ), this, SLOT ( slotIncomingDataReady ( const QByteArray & ) ) );
		connect ( mXMPPTransfer, SIGNAL ( error ( int ) ), this, SLOT ( slotTransferError ( int ) ) );
		mXMPPTransfer->accept ();
	}

}

void JabberFileTransfer::slotTransferRefused ( const KopeteFileTransferInfo &transfer )
{

	if ( (long)transfer.transferId () != mTransferId )
		return;

	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Local user refused transfer from " << mXMPPTransfer->peer().full () << endl;

	deleteLater ();

}

void JabberFileTransfer::slotTransferResult ()
{

	if ( mKopeteTransfer->error () == KIO::ERR_USER_CANCELED )
	{
		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Transfer with " << mXMPPTransfer->peer().full () << " has been canceled." << endl;
		mXMPPTransfer->close ();
		deleteLater ();
	}

}

void JabberFileTransfer::slotTransferError ( int errorCode )
{

	switch ( errorCode )
	{
		case XMPP::FileTransfer::ErrReject:
			mKopeteTransfer->slotError ( KIO::ERR_ACCESS_DENIED,
										 // "Access denied to"...
										 i18n("The user %1 rejected the transfer request.").
										 arg(mXMPPTransfer->peer().full ()) );
			break;

		case XMPP::FileTransfer::ErrNeg:
			mKopeteTransfer->slotError ( KIO::ERR_COULD_NOT_LOGIN,
										 i18n("Unable to negotiate a suitable connection for the file transfer with %1.").
										 arg(mXMPPTransfer->peer().full ()) );
			break;

		case XMPP::FileTransfer::ErrConnect:
			mKopeteTransfer->slotError ( KIO::ERR_COULD_NOT_CONNECT,
										 i18n("Could not connect to %1.").
										 arg(mXMPPTransfer->peer().full ()) );
			break;

		case XMPP::FileTransfer::ErrStream:
			mKopeteTransfer->slotError ( KIO::ERR_CONNECTION_BROKEN,
										 i18n("The data stream with %1 was disrupted. (probably cancelled)").
										 arg(mXMPPTransfer->peer().full ()) );
			break;

		default:
			mKopeteTransfer->slotError ( KIO::ERR_UNKNOWN,
										 i18n("Unknown error while transferring a file with %1.").
										 arg(mXMPPTransfer->peer().full ()) );
			break;
	}

	deleteLater ();

}

void JabberFileTransfer::slotIncomingDataReady ( const QByteArray &data )
{

	mBytesTransferred += data.size ();

	mKopeteTransfer->slotProcessed ( mBytesTransferred );

	mLocalFile.writeBlock ( data );

	if ( mBytesTransferred >= mXMPPTransfer->fileSize () )
	{
		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Transfer from " << mXMPPTransfer->peer().full () << " done." << endl;

		mKopeteTransfer->slotComplete ();

		deleteLater ();
	}

}

void JabberFileTransfer::slotOutgoingConnected ()
{

	kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Outgoing data connection is open." << endl;

	mBytesTransferred = mXMPPTransfer->offset ();
	mLocalFile.at ( mXMPPTransfer->offset () );
	mBytesToTransfer = ( mXMPPTransfer->fileSize () > mXMPPTransfer->length () ) ? mXMPPTransfer->length () : mXMPPTransfer->fileSize ();

	slotOutgoingBytesWritten ( 0 );

}

void JabberFileTransfer::slotOutgoingBytesWritten ( int nrWritten )
{

	mBytesTransferred += nrWritten;
	mBytesToTransfer -= nrWritten;

	mKopeteTransfer->slotProcessed ( mBytesTransferred );

	if ( mBytesToTransfer )
	{
		int nrToWrite = mXMPPTransfer->dataSizeNeeded ();

		QByteArray readBuffer ( nrToWrite );

		mLocalFile.readBlock ( readBuffer.data (), nrToWrite );

		mXMPPTransfer->writeFileData ( readBuffer );
	}
	else
	{
		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Transfer to " << mXMPPTransfer->peer().full () << " done." << endl;

		mKopeteTransfer->slotComplete ();

		deleteLater ();
	}

}

#include "jabberfiletransfer.moc"
<commit_msg>Fix a few file transfer issues: - since Kopete's FT API is making use of KIO, we can't display our own errors - allow for files to be resumed - don't attempt to read/write past what is possible, so use either length() or fileSize(), what's smaller is regarded as being valid<commit_after> /*
  * jabberfiletransfer.cpp
  *
  * Copyright (c) 2004 by Till Gerken <till@tantalo.net>
  *
  * Kopete    (c) by the Kopete developers  <kopete-devel@kde.org>
  *
  * *************************************************************************
  * *                                                                       *
  * * This program is free software; you can redistribute it and/or modify  *
  * * it under the terms of the GNU General Public License as published by  *
  * * the Free Software Foundation; either version 2 of the License, or     *
  * * (at your option) any later version.                                   *
  * *                                                                       *
  * *************************************************************************
  */

#include <kdebug.h>
#include <im.h>
#include <xmpp.h>
#include "jabberfiletransfer.h"
#include <klocale.h>
#include <kmessagebox.h>
#include "kopeteuiglobal.h"
#include "kopetemetacontact.h"
#include "kopetecontactlist.h"
#include "kopetetransfermanager.h"
#include "jabberaccount.h"
#include "jabberprotocol.h"
#include "jabbercontactpool.h"
#include "jabberbasecontact.h"
#include "jabbercontact.h"

JabberFileTransfer::JabberFileTransfer ( JabberAccount *account, XMPP::FileTransfer *incomingTransfer )
{
	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "New incoming transfer from " << incomingTransfer->peer().full () << ", filename " << incomingTransfer->fileName () << ", size " << QString::number ( incomingTransfer->fileSize () ) << endl;

	mAccount = account;
	mXMPPTransfer = incomingTransfer;

	// try to locate an exact match in our pool first
	JabberBaseContact *contact = mAccount->contactPool()->findExactMatch ( mXMPPTransfer->peer () );

	if ( !contact )
	{
		// we have no exact match, try a broader search
		contact = mAccount->contactPool()->findRelevantRecipient ( mXMPPTransfer->peer () );
	}

	if ( !contact )
	{
		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "No matching local contact found, creating a new one." << endl;

		KopeteMetaContact *metaContact = new KopeteMetaContact ();

		metaContact->setTemporary (true);

		contact = mAccount->contactPool()->addContact ( mXMPPTransfer->peer (), metaContact, false );

		KopeteContactList::contactList ()->addMetaContact ( metaContact );
	}

	connect ( KopeteTransferManager::transferManager (), SIGNAL ( accepted ( KopeteTransfer *, const QString & ) ),
			  this, SLOT ( slotIncomingTransferAccepted ( KopeteTransfer *, const QString & ) ) );
	connect ( KopeteTransferManager::transferManager (), SIGNAL ( refused ( const KopeteFileTransferInfo & ) ),
			  this, SLOT ( slotTransferRefused ( const KopeteFileTransferInfo & ) ) );

	initializeVariables ();

	mTransferId = KopeteTransferManager::transferManager()->askIncomingTransfer ( contact,
																				  mXMPPTransfer->fileName (),
																				  mXMPPTransfer->fileSize (),
																				  mXMPPTransfer->description () );

}

JabberFileTransfer::JabberFileTransfer ( JabberAccount *account, JabberBaseContact *contact, const QString &file )
{
	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "New outgoing transfer for " << contact->contactId() << ": " << file << endl;

	mAccount = account;
	mLocalFile.setName ( file );
	mLocalFile.open ( IO_ReadOnly );

	mKopeteTransfer = KopeteTransferManager::transferManager()->addTransfer ( contact,
																			  mLocalFile.name (),
																			  mLocalFile.size (),
																			  contact->contactId (),
																			  KopeteFileTransferInfo::Outgoing );

 	connect ( mKopeteTransfer, SIGNAL ( result ( KIO::Job * ) ), this, SLOT ( slotTransferResult () ) );

	mXMPPTransfer = mAccount->client()->fileTransferManager()->createTransfer ();

	initializeVariables ();

	connect ( mXMPPTransfer, SIGNAL ( connected () ), this, SLOT ( slotOutgoingConnected () ) );
	connect ( mXMPPTransfer, SIGNAL ( bytesWritten ( int ) ), this, SLOT ( slotOutgoingBytesWritten ( int ) ) );
	connect ( mXMPPTransfer, SIGNAL ( error ( int ) ), this, SLOT ( slotTransferError ( int ) ) );

	mXMPPTransfer->sendFile ( XMPP::Jid ( contact->fullAddress () ), KURL(file).fileName (), mLocalFile.size (), "" );

}

JabberFileTransfer::~JabberFileTransfer ()
{
	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Destroying Jabber file transfer object." << endl;

	mLocalFile.close ();

	mXMPPTransfer->close ();
	delete mXMPPTransfer;

}

void JabberFileTransfer::initializeVariables ()
{

	mTransferId = -1;
	mBytesTransferred = 0;
	mBytesToTransfer = 0;
	mXMPPTransfer->setProxy ( XMPP::Jid ( mAccount->pluginData ( mAccount->protocol (), "ProxyJID" ) ) );

}

void JabberFileTransfer::slotIncomingTransferAccepted ( KopeteTransfer *transfer, const QString &fileName )
{

	if ( (long)transfer->info().transferId () != mTransferId )
		return;

	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Accepting transfer for " << mXMPPTransfer->peer().full () << endl;

	mKopeteTransfer = transfer;
	mLocalFile.setName ( fileName );

	bool couldOpen = false;
	Q_LLONG offset = 0;
	Q_LLONG length = 0;

	mBytesTransferred = 0;
	mBytesToTransfer = mXMPPTransfer->fileSize ();

	if ( mXMPPTransfer->rangeSupported () && mLocalFile.exists () )
	{
		KGuiItem resumeButton ( i18n ( "&Resume" ) );
		KGuiItem overwriteButton ( i18n ( "Over&write" ) );

		switch ( KMessageBox::questionYesNoCancel ( Kopete::UI::Global::mainWidget (),
													i18n ( "The file %1 already exists, do you want to resume or overwrite it?" ).arg ( fileName ),
													i18n ( "File exists: %1" ).arg ( fileName ),
													resumeButton, overwriteButton ) )
		{
			case KMessageBox::Yes:		// resume
										couldOpen = mLocalFile.open ( IO_ReadWrite );
										if ( couldOpen )
										{
											offset = mLocalFile.size ();
											length = mXMPPTransfer->fileSize () - offset;
											mBytesTransferred = offset;
											mBytesToTransfer = length;
											mLocalFile.at ( mLocalFile.size () );
										}
										break;

			case KMessageBox::No:		// overwrite
										couldOpen = mLocalFile.open ( IO_WriteOnly );
										break;

			default:					// cancel
										deleteLater ();
										return;
		}
	}
	else
	{
		// overwrite by default
		couldOpen = mLocalFile.open ( IO_WriteOnly );
	}

	if ( !couldOpen )
	{
		transfer->slotError ( KIO::ERR_COULD_NOT_WRITE, fileName );

		deleteLater ();
	}
	else
	{
		connect ( mKopeteTransfer, SIGNAL ( result ( KIO::Job * ) ), this, SLOT ( slotTransferResult () ) );
		connect ( mXMPPTransfer, SIGNAL ( readyRead ( const QByteArray& ) ), this, SLOT ( slotIncomingDataReady ( const QByteArray & ) ) );
		connect ( mXMPPTransfer, SIGNAL ( error ( int ) ), this, SLOT ( slotTransferError ( int ) ) );
		mXMPPTransfer->accept ( offset, length );
	}

}

void JabberFileTransfer::slotTransferRefused ( const KopeteFileTransferInfo &transfer )
{

	if ( (long)transfer.transferId () != mTransferId )
		return;

	kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Local user refused transfer from " << mXMPPTransfer->peer().full () << endl;

	deleteLater ();

}

void JabberFileTransfer::slotTransferResult ()
{

	if ( mKopeteTransfer->error () == KIO::ERR_USER_CANCELED )
	{
		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Transfer with " << mXMPPTransfer->peer().full () << " has been canceled." << endl;
		mXMPPTransfer->close ();
		deleteLater ();
	}

}

void JabberFileTransfer::slotTransferError ( int errorCode )
{

	switch ( errorCode )
	{
		case XMPP::FileTransfer::ErrReject:
			// user rejected the transfer request
			mKopeteTransfer->slotError ( KIO::ERR_ACCESS_DENIED,
										 mXMPPTransfer->peer().full () );
			break;

		case XMPP::FileTransfer::ErrNeg:
			// unable to negotiate a suitable connection for the file transfer with the user
			mKopeteTransfer->slotError ( KIO::ERR_COULD_NOT_LOGIN,
										 mXMPPTransfer->peer().full () );
			break;

		case XMPP::FileTransfer::ErrConnect:
			// could not connect to the user
			mKopeteTransfer->slotError ( KIO::ERR_COULD_NOT_CONNECT,
										 mXMPPTransfer->peer().full () );
			break;

		case XMPP::FileTransfer::ErrStream:
			// data stream was disrupted, probably cancelled
			mKopeteTransfer->slotError ( KIO::ERR_CONNECTION_BROKEN,
										 mXMPPTransfer->peer().full () );
			break;

		default:
			// unknown error
			mKopeteTransfer->slotError ( KIO::ERR_UNKNOWN,
										 mXMPPTransfer->peer().full () );
			break;
	}

	deleteLater ();

}

void JabberFileTransfer::slotIncomingDataReady ( const QByteArray &data )
{

	mBytesTransferred += data.size ();
	mBytesToTransfer -= data.size ();

	mKopeteTransfer->slotProcessed ( mBytesTransferred );

	mLocalFile.writeBlock ( data );

	if ( mBytesToTransfer <= 0 )
	{
		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Transfer from " << mXMPPTransfer->peer().full () << " done." << endl;

		mKopeteTransfer->slotComplete ();

		deleteLater ();
	}

}

void JabberFileTransfer::slotOutgoingConnected ()
{

	kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Outgoing data connection is open." << endl;

	mBytesTransferred = mXMPPTransfer->offset ();
	mLocalFile.at ( mXMPPTransfer->offset () );
	mBytesToTransfer = ( mXMPPTransfer->fileSize () > mXMPPTransfer->length () ) ? mXMPPTransfer->length () : mXMPPTransfer->fileSize ();

	slotOutgoingBytesWritten ( 0 );

}

void JabberFileTransfer::slotOutgoingBytesWritten ( int nrWritten )
{

	mBytesTransferred += nrWritten;
	mBytesToTransfer -= nrWritten;

	mKopeteTransfer->slotProcessed ( mBytesTransferred );

	if ( mBytesToTransfer )
	{
		int nrToWrite = mXMPPTransfer->dataSizeNeeded ();

		QByteArray readBuffer ( nrToWrite );

		mLocalFile.readBlock ( readBuffer.data (), nrToWrite );

		mXMPPTransfer->writeFileData ( readBuffer );
	}
	else
	{
		kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Transfer to " << mXMPPTransfer->peer().full () << " done." << endl;

		mKopeteTransfer->slotComplete ();

		deleteLater ();
	}

}

#include "jabberfiletransfer.moc"
<|endoftext|>


<commit_before>/*
 *  Copyright 2008-2013 NVIDIA Corporation
 *
 *  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 <thrust/detail/config.h>

// don't attempt to #include this file without omp support
#if (THRUST_DEVICE_COMPILER_IS_OMP_CAPABLE == THRUST_TRUE)
#include <omp.h>
#endif // omp support

#include <thrust/iterator/iterator_traits.h>
#include <thrust/system/detail/generic/select_system.h>
#include <thrust/sort.h>
#include <thrust/merge.h>
#include <thrust/detail/seq.h>
#include <thrust/detail/temporary_array.h>

namespace thrust
{
namespace system
{
namespace omp
{
namespace detail
{
namespace sort_detail
{

template<typename DerivedPolicy,
         typename RandomAccessIterator,
         typename StrictWeakOrdering>
void inplace_merge(execution_policy<DerivedPolicy> &exec,
                   RandomAccessIterator first,
                   RandomAccessIterator middle,
                   RandomAccessIterator last,
                   StrictWeakOrdering comp)
{
  typedef typename thrust::iterator_value<RandomAccessIterator>::type value_type;

  thrust::detail::temporary_array<value_type,DerivedPolicy> a(exec, first, middle);
  thrust::detail::temporary_array<value_type,DerivedPolicy> b(exec, middle, last);

  thrust::merge(thrust::seq, a.begin(), a.end(), b.begin(), b.end(), first, comp);
}

template<typename DerivedPolicy,
         typename RandomAccessIterator1,
         typename RandomAccessIterator2,
         typename StrictWeakOrdering>
void inplace_merge_by_key(execution_policy<DerivedPolicy> &exec,
                          RandomAccessIterator1 first1,
                          RandomAccessIterator1 middle1,
                          RandomAccessIterator1 last1,
                          RandomAccessIterator2 first2,
                          StrictWeakOrdering comp)
{
  typedef typename thrust::iterator_value<RandomAccessIterator1>::type value_type1;
  typedef typename thrust::iterator_value<RandomAccessIterator2>::type value_type2;

  RandomAccessIterator2 middle2 = first2 + (middle1 - first1);
  RandomAccessIterator2 last2   = first2 + (last1   - first1);

  thrust::detail::temporary_array<value_type1,DerivedPolicy> lhs1(exec, first1, middle1);
  thrust::detail::temporary_array<value_type1,DerivedPolicy> rhs1(exec, middle1, last1);
  thrust::detail::temporary_array<value_type2,DerivedPolicy> lhs2(exec, first2, middle2);
  thrust::detail::temporary_array<value_type2,DerivedPolicy> rhs2(exec, middle2, last2);

  thrust::merge_by_key(thrust::seq,
                       lhs1.begin(), lhs1.end(),
                       rhs1.begin(), rhs1.end(),
                       lhs2.begin(), rhs2.begin(),
                       first1, first2,
                       comp);
}

} // end sort_detail

template<typename DerivedPolicy,
         typename RandomAccessIterator,
         typename StrictWeakOrdering>
void stable_sort(execution_policy<DerivedPolicy> &exec,
                 RandomAccessIterator first,
                 RandomAccessIterator last,
                 StrictWeakOrdering comp)
{
  // we're attempting to launch an omp kernel, assert we're compiling with omp support
  // ========================================================================
  // X Note to the user: If you've found this line due to a compiler error, X
  // X you need to enable OpenMP support in your compiler.                  X
  // ========================================================================
  THRUST_STATIC_ASSERT( (thrust::detail::depend_on_instantiation<RandomAccessIterator,
                        (THRUST_DEVICE_COMPILER_IS_OMP_CAPABLE == THRUST_TRUE)>::value) );

#if (THRUST_DEVICE_COMPILER_IS_OMP_CAPABLE == THRUST_TRUE)
  typedef typename thrust::iterator_difference<RandomAccessIterator>::type IndexType;

  if(first == last)
    return;

  #pragma omp parallel
  {
    thrust::system::detail::internal::uniform_decomposition<IndexType> decomp(last - first, 1, omp_get_num_threads());

    // process id
    IndexType p_i = omp_get_thread_num();

    // every thread sorts its own tile
    if(p_i < decomp.size())
    {
      thrust::stable_sort(thrust::seq,
                          first + decomp[p_i].begin(),
                          first + decomp[p_i].end(),
                          comp);
    }

    #pragma omp barrier

    IndexType nseg = decomp.size();
    IndexType h = 2;

    // keep track of which sub-range we're processing
    IndexType a=p_i, b=p_i, c=p_i+1;

    while(nseg>1)
    {
      if(c >= decomp.size())
        c = decomp.size() - 1;

      if((p_i % h) == 0 && c > b)
      {
        sort_detail::inplace_merge(exec,
                                   first + decomp[a].begin(),
                                   first + decomp[b].end(),
                                   first + decomp[c].end(),
                                   comp);

        b = c;
        c += h;
      }

      nseg = (nseg + 1) / 2;
      h *= 2;

      #pragma omp barrier
    }
  }
#endif // THRUST_DEVICE_COMPILER_IS_OMP_CAPABLE
}

template<typename DerivedPolicy,
         typename RandomAccessIterator1,
         typename RandomAccessIterator2,
         typename StrictWeakOrdering>
void stable_sort_by_key(execution_policy<DerivedPolicy> &exec,
                        RandomAccessIterator1 keys_first,
                        RandomAccessIterator1 keys_last,
                        RandomAccessIterator2 values_first,
                        StrictWeakOrdering comp)
{
  // we're attempting to launch an omp kernel, assert we're compiling with omp support
  // ========================================================================
  // X Note to the user: If you've found this line due to a compiler error, X
  // X you need to enable OpenMP support in your compiler.                  X
  // ========================================================================
  THRUST_STATIC_ASSERT( (thrust::detail::depend_on_instantiation<RandomAccessIterator1,
                        (THRUST_DEVICE_COMPILER_IS_OMP_CAPABLE == THRUST_TRUE)>::value) );

#if (THRUST_DEVICE_COMPILER_IS_OMP_CAPABLE == THRUST_TRUE)
  typedef typename thrust::iterator_difference<RandomAccessIterator1>::type IndexType;

  if(keys_first == keys_last)
    return;

  #pragma omp parallel
  {
    thrust::system::detail::internal::uniform_decomposition<IndexType> decomp(keys_last - keys_first, 1, omp_get_num_threads());

    // process id
    IndexType p_i = omp_get_thread_num();

    // every thread sorts its own tile
    if(p_i < decomp.size())
    {
      thrust::stable_sort_by_key(thrust::seq,
                                 keys_first + decomp[p_i].begin(),
                                 keys_first + decomp[p_i].end(),
                                 values_first + decomp[p_i].begin(),
                                 comp);
    }

    #pragma omp barrier

    IndexType nseg = decomp.size();
    IndexType h = 2;

    // keep track of which sub-range we're processing
    IndexType a=p_i, b=p_i, c=p_i+1;

    while(nseg>1)
    {
      if(c >= decomp.size())
        c = decomp.size() - 1;

      if((p_i % h) == 0 && c > b)
      {
        sort_detail::inplace_merge_by_key(exec,
                                          keys_first + decomp[a].begin(),
                                          keys_first + decomp[b].end(),
                                          keys_first + decomp[c].end(),
                                          values_first + decomp[a].begin(),
                                          comp);

        b = c;
        c += h;
      }

      nseg = (nseg + 1) / 2;
      h *= 2;

      #pragma omp barrier
    }
  }
#endif // THRUST_DEVICE_COMPILER_IS_OMP_CAPABLE
}

} // end namespace detail
} // end namespace omp
} // end namespace system
} // end namespace thrust

<commit_msg> Integrate CL 20980608 from r8.0/thrust<commit_after>/*
 *  Copyright 2008-2013 NVIDIA Corporation
 *
 *  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 <thrust/detail/config.h>

// don't attempt to #include this file without omp support
#if (THRUST_DEVICE_COMPILER_IS_OMP_CAPABLE == THRUST_TRUE)
#include <omp.h>
#endif // omp support

#include <thrust/iterator/iterator_traits.h>
#include <thrust/system/detail/generic/select_system.h>
#include <thrust/sort.h>
#include <thrust/merge.h>
#include <thrust/detail/seq.h>
#include <thrust/detail/temporary_array.h>

namespace thrust
{
namespace system
{
namespace omp
{
namespace detail
{
namespace sort_detail
{

template<typename DerivedPolicy,
         typename RandomAccessIterator,
         typename StrictWeakOrdering>
void inplace_merge(execution_policy<DerivedPolicy> &exec,
                   RandomAccessIterator first,
                   RandomAccessIterator middle,
                   RandomAccessIterator last,
                   StrictWeakOrdering comp)
{
  typedef typename thrust::iterator_value<RandomAccessIterator>::type value_type;

  thrust::detail::temporary_array<value_type,DerivedPolicy> a(exec, first, middle);
  thrust::detail::temporary_array<value_type,DerivedPolicy> b(exec, middle, last);

  thrust::merge(thrust::seq, a.begin(), a.end(), b.begin(), b.end(), first, comp);
}

template<typename DerivedPolicy,
         typename RandomAccessIterator1,
         typename RandomAccessIterator2,
         typename StrictWeakOrdering>
void inplace_merge_by_key(execution_policy<DerivedPolicy> &exec,
                          RandomAccessIterator1 first1,
                          RandomAccessIterator1 middle1,
                          RandomAccessIterator1 last1,
                          RandomAccessIterator2 first2,
                          StrictWeakOrdering comp)
{
  typedef typename thrust::iterator_value<RandomAccessIterator1>::type value_type1;
  typedef typename thrust::iterator_value<RandomAccessIterator2>::type value_type2;

  RandomAccessIterator2 middle2 = first2 + (middle1 - first1);
  RandomAccessIterator2 last2   = first2 + (last1   - first1);

  thrust::detail::temporary_array<value_type1,DerivedPolicy> lhs1(exec, first1, middle1);
  thrust::detail::temporary_array<value_type1,DerivedPolicy> rhs1(exec, middle1, last1);
  thrust::detail::temporary_array<value_type2,DerivedPolicy> lhs2(exec, first2, middle2);
  thrust::detail::temporary_array<value_type2,DerivedPolicy> rhs2(exec, middle2, last2);

  thrust::merge_by_key(thrust::seq,
                       lhs1.begin(), lhs1.end(),
                       rhs1.begin(), rhs1.end(),
                       lhs2.begin(), rhs2.begin(),
                       first1, first2,
                       comp);
}

} // end sort_detail

template<typename DerivedPolicy,
         typename RandomAccessIterator,
         typename StrictWeakOrdering>
void stable_sort(execution_policy<DerivedPolicy> &exec,
                 RandomAccessIterator first,
                 RandomAccessIterator last,
                 StrictWeakOrdering comp)
{
  // we're attempting to launch an omp kernel, assert we're compiling with omp support
  // ========================================================================
  // X Note to the user: If you've found this line due to a compiler error, X
  // X you need to enable OpenMP support in your compiler.                  X
  // ========================================================================
  THRUST_STATIC_ASSERT( (thrust::detail::depend_on_instantiation<RandomAccessIterator,
                        (THRUST_DEVICE_COMPILER_IS_OMP_CAPABLE == THRUST_TRUE)>::value) );

#if (THRUST_DEVICE_COMPILER_IS_OMP_CAPABLE == THRUST_TRUE)
  typedef typename thrust::iterator_difference<RandomAccessIterator>::type IndexType;

  if(first == last)
    return;

  #pragma omp parallel
  {
    thrust::system::detail::internal::uniform_decomposition<IndexType> decomp(last - first, 1, omp_get_num_threads());

    // process id
    IndexType p_i = omp_get_thread_num();

    // every thread sorts its own tile
    if(p_i < decomp.size())
    {
      thrust::stable_sort(thrust::seq,
                          first + decomp[p_i].begin(),
                          first + decomp[p_i].end(),
                          comp);
    }

    #pragma omp barrier

    // XXX For some reason, MSVC 2015 yields an error unless we include this meaningless semicolon here
    ;

    IndexType nseg = decomp.size();
    IndexType h = 2;

    // keep track of which sub-range we're processing
    IndexType a=p_i, b=p_i, c=p_i+1;

    while(nseg>1)
    {
      if(c >= decomp.size())
        c = decomp.size() - 1;

      if((p_i % h) == 0 && c > b)
      {
        sort_detail::inplace_merge(exec,
                                   first + decomp[a].begin(),
                                   first + decomp[b].end(),
                                   first + decomp[c].end(),
                                   comp);

        b = c;
        c += h;
      }

      nseg = (nseg + 1) / 2;
      h *= 2;

      #pragma omp barrier
    }
  }
#endif // THRUST_DEVICE_COMPILER_IS_OMP_CAPABLE
}

template<typename DerivedPolicy,
         typename RandomAccessIterator1,
         typename RandomAccessIterator2,
         typename StrictWeakOrdering>
void stable_sort_by_key(execution_policy<DerivedPolicy> &exec,
                        RandomAccessIterator1 keys_first,
                        RandomAccessIterator1 keys_last,
                        RandomAccessIterator2 values_first,
                        StrictWeakOrdering comp)
{
  // we're attempting to launch an omp kernel, assert we're compiling with omp support
  // ========================================================================
  // X Note to the user: If you've found this line due to a compiler error, X
  // X you need to enable OpenMP support in your compiler.                  X
  // ========================================================================
  THRUST_STATIC_ASSERT( (thrust::detail::depend_on_instantiation<RandomAccessIterator1,
                        (THRUST_DEVICE_COMPILER_IS_OMP_CAPABLE == THRUST_TRUE)>::value) );

#if (THRUST_DEVICE_COMPILER_IS_OMP_CAPABLE == THRUST_TRUE)
  typedef typename thrust::iterator_difference<RandomAccessIterator1>::type IndexType;

  if(keys_first == keys_last)
    return;

  #pragma omp parallel
  {
    thrust::system::detail::internal::uniform_decomposition<IndexType> decomp(keys_last - keys_first, 1, omp_get_num_threads());

    // process id
    IndexType p_i = omp_get_thread_num();

    // every thread sorts its own tile
    if(p_i < decomp.size())
    {
      thrust::stable_sort_by_key(thrust::seq,
                                 keys_first + decomp[p_i].begin(),
                                 keys_first + decomp[p_i].end(),
                                 values_first + decomp[p_i].begin(),
                                 comp);
    }

    #pragma omp barrier

    // XXX For some reason, MSVC 2015 yields an error unless we include this meaningless semicolon here
    ;

    IndexType nseg = decomp.size();
    IndexType h = 2;

    // keep track of which sub-range we're processing
    IndexType a=p_i, b=p_i, c=p_i+1;

    while(nseg>1)
    {
      if(c >= decomp.size())
        c = decomp.size() - 1;

      if((p_i % h) == 0 && c > b)
      {
        sort_detail::inplace_merge_by_key(exec,
                                          keys_first + decomp[a].begin(),
                                          keys_first + decomp[b].end(),
                                          keys_first + decomp[c].end(),
                                          values_first + decomp[a].begin(),
                                          comp);

        b = c;
        c += h;
      }

      nseg = (nseg + 1) / 2;
      h *= 2;

      #pragma omp barrier
    }
  }
#endif // THRUST_DEVICE_COMPILER_IS_OMP_CAPABLE
}

} // end namespace detail
} // end namespace omp
} // end namespace system
} // end namespace thrust

<|endoftext|>


<commit_before>// Copyright (c) 2020 ASMlover. 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 ofconditions 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 materialsprovided with the
//    distribution.
//
// 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 HOLDER 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.
#pragma once

#include <vector>
#include "common.hh"

namespace wrencc {

class WrenVM;

enum class ValueType : u8_t {
  UNDEFINED,

  NIL,
  TRUE,
  FALSE,
  NUMERIC,
  OBJECT,
};

enum class ObjType : u8_t {
  STRING,
  LIST,
  RANGE,
  MAP,
  MODULE,
  FUNCTION,
  FOREIGN,
  UPVALUE,
  CLOSURE,
  FIBER,
  CLASS,
  INSTANCE,
};

class StringObject;
class ListObject;
class RangeObject;
class MapObject;
class ModuleObject;
class FunctionObject;
class ForeignObject;
class UpvalueObject;
class ClosureObject;
class FiberObject;
class ClassObject;
class InstanceObject;

struct BaseObject : private UnCopyable {
  ObjType type_;
  bool is_darken_{};
  ClassObject* cls_{};
public:
  BaseObject(ObjType type, ClassObject* cls = nullptr) noexcept
    : type_(type), cls_(cls) {
  }
  virtual ~BaseObject() noexcept {}

  inline ObjType type() const noexcept { return type_; }
  inline bool is_darken() const noexcept { return is_darken_; }
  inline void set_darken(bool darken = true) noexcept { is_darken_ = darken; }
  inline ClassObject* cls() const noexcept { return cls_; }
  inline void set_cls(ClassObject* cls) noexcept { cls_ = cls; }

  StringObject* as_string() noexcept;
  const char* as_cstring() noexcept;
  ListObject* as_list() noexcept;
  RangeObject* as_range() noexcept;
  MapObject* as_map() noexcept;
  ModuleObject* as_module() noexcept;
  FunctionObject* as_function() noexcept;
  ForeignObject* as_foreign() noexcept;
  UpvalueObject* as_upvalue() noexcept;
  ClosureObject* as_closure() noexcept;
  FiberObject* as_fiber() noexcept;
  ClassObject* as_class() noexcept;
  InstanceObject* as_instance() noexcept;

  virtual bool is_equal(BaseObject* r) const { return false; }
  virtual str_t stringify() const { return "<object>"; }
  virtual void gc_blacken(WrenVM& vm) {}
  virtual void initialize(WrenVM& vm) {}
  virtual void finalize(WrenVM& vm) {}

  virtual u32_t hasher() const {
    ASSERT(false, "only immutable objects can be hashed");
    return 0;
  }
};

class ObjValue final : public Copyable {
  ValueType type_{ValueType::UNDEFINED};

  union {
    double num{};
    BaseObject* obj;
  } as_;

  inline bool is(ObjType type) const noexcept {
    return is_object() && objtype() == type;
  }

  inline bool is_true() const noexcept { return type_ == ValueType::TRUE; }
  inline bool is_false() const noexcept { return type_ == ValueType::FALSE; }

  template <typename T>
  inline void set_decimal(T x) { as_.num = Xt::to_decimal(x); }
public:
  ObjValue() noexcept {}
  ObjValue(nil_t) noexcept : type_(ValueType::NIL) {}
  ObjValue(bool b) noexcept : type_(b ? ValueType::TRUE : ValueType::FALSE) {}
  ObjValue(i8_t n) noexcept : type_(ValueType::NUMERIC) { set_decimal(n); }
  ObjValue(u8_t n) noexcept : type_(ValueType::NUMERIC) { set_decimal(n); }
  ObjValue(i16_t n) noexcept : type_(ValueType::NUMERIC) { set_decimal(n); }
  ObjValue(u16_t n) noexcept : type_(ValueType::NUMERIC) { set_decimal(n); }
  ObjValue(i32_t n) noexcept : type_(ValueType::NUMERIC) { set_decimal(n); }
  ObjValue(u32_t n) noexcept : type_(ValueType::NUMERIC) { set_decimal(n); }
  ObjValue(i64_t n) noexcept : type_(ValueType::NUMERIC) { set_decimal(n); }
  ObjValue(u64_t n) noexcept : type_(ValueType::NUMERIC) { set_decimal(n); }
  ObjValue(float n) noexcept : type_(ValueType::NUMERIC) { set_decimal(n); }
  ObjValue(double d) noexcept : type_(ValueType::NUMERIC) { as_.num = d; }
  ObjValue(BaseObject* o) noexcept : type_(ValueType::OBJECT) { as_.obj = o; }

  inline ValueType type() const noexcept { return type_; }
  inline ObjType objtype() const noexcept { return as_.obj->type(); }

  inline bool is_undefined() const noexcept { return type_ == ValueType::UNDEFINED; }
  inline bool is_nil() const noexcept { return type_ == ValueType::NIL; }
  inline bool is_boolean() const noexcept { return is_true() || is_false(); }
  inline bool is_numeric() const noexcept { return type_ == ValueType::NUMERIC; }
  inline bool is_object() const noexcept { return type_ == ValueType::OBJECT; }
  inline bool is_string() const noexcept { return is(ObjType::STRING); }
  inline bool is_list() const noexcept { return is(ObjType::LIST); }
  inline bool is_range() const noexcept { return is(ObjType::RANGE); }
  inline bool is_map() const noexcept { return is(ObjType::MAP); }
  inline bool is_module() const noexcept { return is(ObjType::MODULE); }
  inline bool is_function() const noexcept { return is(ObjType::FUNCTION); }
  inline bool is_foreign() const noexcept { return is(ObjType::FOREIGN); }
  inline bool is_upvalue() const noexcept { return is(ObjType::UPVALUE); }
  inline bool is_closure() const noexcept { return is(ObjType::CLOSURE); }
  inline bool is_fiber() const noexcept { return is(ObjType::FIBER); }
  inline bool is_class() const noexcept { return is(ObjType::CLASS); }
  inline bool is_instance() const noexcept { return is(ObjType::INSTANCE); }

  inline bool is_falsely() const noexcept { return is_nil() || is_false(); }
  inline bool operator==(const ObjValue& r) const noexcept { return is_equal(r); }
  inline bool operator!=(const ObjValue& r) const noexcept { return !is_equal(r); }

  inline bool as_boolean() const noexcept { return is_true(); }
  template <typename Int = int>
  inline Int as_integer() const noexcept { return Xt::as_type<Int>(as_.num); }
  inline double as_numeric() const noexcept { return as_.num; }
  inline BaseObject* as_object() const noexcept { return as_.obj; }

  StringObject* as_string() const noexcept { return as_.obj->as_string(); }
  const char* as_cstring() const noexcept { return as_.obj->as_cstring(); }
  ListObject* as_list() const noexcept { return as_.obj->as_list(); }
  RangeObject* as_range() const noexcept { return as_.obj->as_range(); }
  MapObject* as_map() const noexcept { return as_.obj->as_map(); }
  ModuleObject* as_module() const noexcept { return as_.obj->as_module(); }
  FunctionObject* as_function() const noexcept { return as_.obj->as_function(); }
  ForeignObject* as_foreign() const noexcept { return as_.obj->as_foreign(); }
  UpvalueObject* as_upvalue() const noexcept { return as_.obj->as_upvalue(); }
  ClosureObject* as_closure() const noexcept { return as_.obj->as_closure(); }
  FiberObject* as_fiber() const noexcept { return as_.obj->as_fiber(); }
  ClassObject* as_class() const noexcept { return as_.obj->as_class(); }
  InstanceObject* as_instance() const noexcept { return as_.obj->as_instance(); }

  bool is_same(const ObjValue& r) const noexcept;
  bool is_equal(const ObjValue& r) const noexcept;
  u32_t hasher() const noexcept;
  str_t stringify() const noexcept;
};

using Value = ObjValue;

inline std::ostream& operator<<(std::ostream& out, const Value& val) noexcept {
  return out << val.stringify();
}

}
<commit_msg>:construction: chore(string): definition string object<commit_after>// Copyright (c) 2020 ASMlover. 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 ofconditions 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 materialsprovided with the
//    distribution.
//
// 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 HOLDER 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.
#pragma once

#include <vector>
#include "common.hh"

namespace wrencc {

class WrenVM;

enum class ValueType : u8_t {
  UNDEFINED,

  NIL,
  TRUE,
  FALSE,
  NUMERIC,
  OBJECT,
};

enum class ObjType : u8_t {
  STRING,
  LIST,
  RANGE,
  MAP,
  MODULE,
  FUNCTION,
  FOREIGN,
  UPVALUE,
  CLOSURE,
  FIBER,
  CLASS,
  INSTANCE,
};

class StringObject;
class ListObject;
class RangeObject;
class MapObject;
class ModuleObject;
class FunctionObject;
class ForeignObject;
class UpvalueObject;
class ClosureObject;
class FiberObject;
class ClassObject;
class InstanceObject;

struct BaseObject : private UnCopyable {
  ObjType type_;
  bool is_darken_{};
  ClassObject* cls_{};
public:
  BaseObject(ObjType type, ClassObject* cls = nullptr) noexcept
    : type_(type), cls_(cls) {
  }
  virtual ~BaseObject() noexcept {}

  inline ObjType type() const noexcept { return type_; }
  inline bool is_darken() const noexcept { return is_darken_; }
  inline void set_darken(bool darken = true) noexcept { is_darken_ = darken; }
  inline ClassObject* cls() const noexcept { return cls_; }
  inline void set_cls(ClassObject* cls) noexcept { cls_ = cls; }

  StringObject* as_string() noexcept;
  const char* as_cstring() noexcept;
  ListObject* as_list() noexcept;
  RangeObject* as_range() noexcept;
  MapObject* as_map() noexcept;
  ModuleObject* as_module() noexcept;
  FunctionObject* as_function() noexcept;
  ForeignObject* as_foreign() noexcept;
  UpvalueObject* as_upvalue() noexcept;
  ClosureObject* as_closure() noexcept;
  FiberObject* as_fiber() noexcept;
  ClassObject* as_class() noexcept;
  InstanceObject* as_instance() noexcept;

  virtual bool is_equal(BaseObject* r) const { return false; }
  virtual str_t stringify() const { return "<object>"; }
  virtual void gc_blacken(WrenVM& vm) {}
  virtual void initialize(WrenVM& vm) {}
  virtual void finalize(WrenVM& vm) {}

  virtual u32_t hasher() const {
    ASSERT(false, "only immutable objects can be hashed");
    return 0;
  }
};

class ObjValue final : public Copyable {
  ValueType type_{ValueType::UNDEFINED};

  union {
    double num{};
    BaseObject* obj;
  } as_;

  inline bool is(ObjType type) const noexcept {
    return is_object() && objtype() == type;
  }

  inline bool is_true() const noexcept { return type_ == ValueType::TRUE; }
  inline bool is_false() const noexcept { return type_ == ValueType::FALSE; }

  template <typename T>
  inline void set_decimal(T x) { as_.num = Xt::to_decimal(x); }
public:
  ObjValue() noexcept {}
  ObjValue(nil_t) noexcept : type_(ValueType::NIL) {}
  ObjValue(bool b) noexcept : type_(b ? ValueType::TRUE : ValueType::FALSE) {}
  ObjValue(i8_t n) noexcept : type_(ValueType::NUMERIC) { set_decimal(n); }
  ObjValue(u8_t n) noexcept : type_(ValueType::NUMERIC) { set_decimal(n); }
  ObjValue(i16_t n) noexcept : type_(ValueType::NUMERIC) { set_decimal(n); }
  ObjValue(u16_t n) noexcept : type_(ValueType::NUMERIC) { set_decimal(n); }
  ObjValue(i32_t n) noexcept : type_(ValueType::NUMERIC) { set_decimal(n); }
  ObjValue(u32_t n) noexcept : type_(ValueType::NUMERIC) { set_decimal(n); }
  ObjValue(i64_t n) noexcept : type_(ValueType::NUMERIC) { set_decimal(n); }
  ObjValue(u64_t n) noexcept : type_(ValueType::NUMERIC) { set_decimal(n); }
  ObjValue(float n) noexcept : type_(ValueType::NUMERIC) { set_decimal(n); }
  ObjValue(double d) noexcept : type_(ValueType::NUMERIC) { as_.num = d; }
  ObjValue(BaseObject* o) noexcept : type_(ValueType::OBJECT) { as_.obj = o; }

  inline ValueType type() const noexcept { return type_; }
  inline ObjType objtype() const noexcept { return as_.obj->type(); }

  inline bool is_undefined() const noexcept { return type_ == ValueType::UNDEFINED; }
  inline bool is_nil() const noexcept { return type_ == ValueType::NIL; }
  inline bool is_boolean() const noexcept { return is_true() || is_false(); }
  inline bool is_numeric() const noexcept { return type_ == ValueType::NUMERIC; }
  inline bool is_object() const noexcept { return type_ == ValueType::OBJECT; }
  inline bool is_string() const noexcept { return is(ObjType::STRING); }
  inline bool is_list() const noexcept { return is(ObjType::LIST); }
  inline bool is_range() const noexcept { return is(ObjType::RANGE); }
  inline bool is_map() const noexcept { return is(ObjType::MAP); }
  inline bool is_module() const noexcept { return is(ObjType::MODULE); }
  inline bool is_function() const noexcept { return is(ObjType::FUNCTION); }
  inline bool is_foreign() const noexcept { return is(ObjType::FOREIGN); }
  inline bool is_upvalue() const noexcept { return is(ObjType::UPVALUE); }
  inline bool is_closure() const noexcept { return is(ObjType::CLOSURE); }
  inline bool is_fiber() const noexcept { return is(ObjType::FIBER); }
  inline bool is_class() const noexcept { return is(ObjType::CLASS); }
  inline bool is_instance() const noexcept { return is(ObjType::INSTANCE); }

  inline bool is_falsely() const noexcept { return is_nil() || is_false(); }
  inline bool operator==(const ObjValue& r) const noexcept { return is_equal(r); }
  inline bool operator!=(const ObjValue& r) const noexcept { return !is_equal(r); }

  inline bool as_boolean() const noexcept { return is_true(); }
  template <typename Int = int>
  inline Int as_integer() const noexcept { return Xt::as_type<Int>(as_.num); }
  inline double as_numeric() const noexcept { return as_.num; }
  inline BaseObject* as_object() const noexcept { return as_.obj; }

  StringObject* as_string() const noexcept { return as_.obj->as_string(); }
  const char* as_cstring() const noexcept { return as_.obj->as_cstring(); }
  ListObject* as_list() const noexcept { return as_.obj->as_list(); }
  RangeObject* as_range() const noexcept { return as_.obj->as_range(); }
  MapObject* as_map() const noexcept { return as_.obj->as_map(); }
  ModuleObject* as_module() const noexcept { return as_.obj->as_module(); }
  FunctionObject* as_function() const noexcept { return as_.obj->as_function(); }
  ForeignObject* as_foreign() const noexcept { return as_.obj->as_foreign(); }
  UpvalueObject* as_upvalue() const noexcept { return as_.obj->as_upvalue(); }
  ClosureObject* as_closure() const noexcept { return as_.obj->as_closure(); }
  FiberObject* as_fiber() const noexcept { return as_.obj->as_fiber(); }
  ClassObject* as_class() const noexcept { return as_.obj->as_class(); }
  InstanceObject* as_instance() const noexcept { return as_.obj->as_instance(); }

  bool is_same(const ObjValue& r) const noexcept;
  bool is_equal(const ObjValue& r) const noexcept;
  u32_t hasher() const noexcept;
  str_t stringify() const noexcept;
};

using Value = ObjValue;

inline std::ostream& operator<<(std::ostream& out, const Value& val) noexcept {
  return out << val.stringify();
}

// a heap-allocated string object
class StringObject final : public BaseObject {
  // number of bytes in the string, not including the null terminator
  sz_t size_{};

  // the hash value of the string's contents
  u32_t hash_{};

  // string's bytes followed by a null terminator
  char* data_{};
public:
  inline sz_t size() const noexcept { return size_; }
  inline bool empty() const noexcept { return size_ == 0; }
  inline const char* cstr() const noexcept { return data_; }
  inline char* data() noexcept { return data_; }
  inline const char* data() const noexcept { return data_; }
  inline char& operator[](sz_t i) { return data_[i]; }
  inline const char& operator[](sz_t i) const { return data_[i]; }
  inline char& at(sz_t i) { return data_[i]; }
  inline const char& at(sz_t i) const { return data_[i]; }

  inline bool compare(StringObject* s) const {
    return this == s || (hash_ == s->hash_ && size_ == s->size_
        && std::memcmp(data_, s->data_, size_) == 0);
  }

  inline bool compare(const str_t& s) const {
    return size_ == s.size() && std::memcmp(data_, s.data(), size_) == 0;
  }

  inline bool compare(const char* s, sz_t n) const {
    return size_ == n && std::memcmp(data_, s, size_) == 0;
  }

  int find(StringObject* sub, sz_t off = 0) const;

  virtual bool is_equal(BaseObject* r) const override;
  virtual str_t stringify() const override;
  virtual u32_t hasher() const override;

  static StringObject* create(WrenVM& vm, char c);
  static StringObject* create(WrenVM& vm, const char* s, sz_t n);
  static StringObject* create(WrenVM& vm, const str_t& s);
  static StringObject* concat(WrenVM& vm, StringObject* s1, StringObject* s2);
  static StringObject* concat(WrenVM& vm, const char* s1, const char* s2);
  static StringObject* concat(WrenVM& vm, const str_t& s1, const str_t& s2);
};

}
<|endoftext|>


<commit_before>/**
  * @purpose A simple object pool example
  *
  * @author  Ashish
  * @license MIT license
  * @version 1.0, Doxygen compatible comments
  */

#include<iostream>
#include<string>
#include<list>
using namespace std;

class Car {
 private:
 	bool in_use_;
 	string rentee_;
 	string last_rentee_;

 public:
 	 Car()
	 : in_use_(false),
	 last_rentee_("NONE"),
	 rentee_("NONE") {
	 }

	 void set_in_use(bool status) {
	 	in_use_ = true;
	 }

	 bool in_use(void) {
	 	return in_use_;
	 }

	 void set_rentee(const string& given_rentee) {
	 	rentee_ = given_rentee;
	 }

	 string rentee(void) {
	 	return rentee_;
	 }

	 void set_last_rentee(const string& given_rentee) {
	 	last_rentee_ = given_rentee;
	 }

	 string last_rentee(void) {
	 	return last_rentee_;
	 }
};

class CarPool : public Car {
 private:
 	list <Car*> car_list; /// list STL to store object pointers

 public:
	static CarPool& get_instance() { /// singleton objectpool instance
		static CarPool instance;
		return instance;
	}

 	Car* get_car() {
 		Car* car = NULL;

		if (car_list.empty()) { /// case 1: Henry gets a brand new car for the first customer
			car = new Car;
		} else {
			car = car_list.front(); /// case 2: Henry allots an already existing car to the customer
			car_list.pop_front();
		}

		car->set_in_use(true);
		return car;
	 }

	 Car* return_car(Car *given_car) {
		if (given_car != NULL) {
			given_car->set_in_use(false);
			given_car->set_last_rentee(given_car->rentee()); /// Henry notes the previous customer name
			given_car->set_rentee("NONE");

			car_list.push_back(given_car); /// The car has been returned to Henry's car lot
			return NULL;
		}
	 }

 protected:
 	CarPool() {
	 }
};

int main()
{
	CarPool henrys_car_rental = CarPool::get_instance(); /// henry starts a car rental service

	/// usecase 1 - alice is the first customer, she gets a brand new car
	Car* alices = henrys_car_rental.get_car(); /// alice gets a car from henry's rental service
	cout << "Alice's car was last rented to = " << alices->last_rentee() << endl;
	alices->set_rentee("ALICE"); /// alice is now registered as the rentee and can drive the car
	cout << "Alice's car is now rented to = " << alices->rentee() << endl;

	/// usecase 2 - bob is the next customer, he also gets a new car
	Car* bobs = henrys_car_rental.get_car(); /// bob also gets a car from henry's rental service
	cout << "Bob's car was last rented to = " << bobs->last_rentee() << endl;
	bobs->set_rentee("BOB"); /// the car is now resitered to BOB as rentee
	cout << "Bob's car is now rented to = " << alices->rentee() << endl;
	bobs = henrys_car_rental.return_car(bobs); /// bob returns the car to henry's rental service

	/// usecase 3 - fred is a customer, who gets the car bob has returned
	Car* freds = henrys_car_rental.get_car(); /// fred gets bob's returned car from henry's rental service
	cout << "Fred's car was last rented to = " << freds->last_rentee() << endl;
	freds->set_rentee("FRED"); /// the car is now resitered to FRED as rentee
	cout << "Fred's car is now rented to = " << freds->rentee() << endl;
	freds = henrys_car_rental.return_car(freds); /// fred returns the car to henry's rental service

 	return 0;
}

<commit_msg>improved indentation<commit_after>/**
  * @purpose A simple object pool example
  *
  * @author  Ashish
  * @license MIT license
  * @version 1.0, Doxygen compatible comments
  */

#include<iostream>
#include<string>
#include<list>
using namespace std;

class Car {
 private:
    bool in_use_;
    string rentee_;
    string last_rentee_;

 public:
    Car()
    : in_use_(false),
    last_rentee_("NONE"),
    rentee_("NONE") {
    }

    void set_in_use(bool status) {
        in_use_ = true;
    }

    bool in_use(void) {
        return in_use_;
    }

    void set_rentee(const string& given_rentee) {
        rentee_ = given_rentee;
    }

    string rentee(void) {
        return rentee_;
    }

    void set_last_rentee(const string& given_rentee) {
        last_rentee_ = given_rentee;
    }

    string last_rentee(void) {
        return last_rentee_;
    }
};

class CarPool : public Car {
 private:
    list <Car*> car_list;  /// list STL to store object pointers

 public:
    static CarPool& get_instance() {  /// singleton objectpool instance
        static CarPool instance;
        return instance;
    }

    Car* get_car() {
        Car* car = NULL;

        if (car_list.empty()) {  /// case 1: Henry gets a brand new car for the first customer
            car = new Car;
        } else {
            car = car_list.front();  /// case 2: Henry allots an already existing car to the customer
            car_list.pop_front();
        }

        car->set_in_use(true);
        return car;
    }

    Car* return_car(Car *given_car) {
        if (given_car != NULL) {
            given_car->set_in_use(false);
            given_car->set_last_rentee(given_car->rentee());  /// Henry notes the previous customer name
            given_car->set_rentee("NONE");

            car_list.push_back(given_car);  /// The car has been returned to Henry's car lot
            return NULL;
        }
    }

 protected:
    CarPool() {
    }
};

int main() {
    CarPool henrys_car_rental = CarPool::get_instance();  /// henry starts a car rental service

    /// usecase 1 - alice is the first customer, she gets a brand new car
    Car* alices = henrys_car_rental.get_car();  /// alice gets a car from henry's rental service
    cout << "Alice's car was last rented to = " << alices->last_rentee() << endl;
    alices->set_rentee("ALICE");  /// alice is now registered as the rentee and can drive the car
    cout << "Alice's car is now rented to = " << alices->rentee() << endl;

    /// usecase 2 - bob is the next customer, he also gets a new car
    Car* bobs = henrys_car_rental.get_car();  /// bob also gets a car from henry's rental service
    cout << "Bob's car was last rented to = " << bobs->last_rentee() << endl;
    bobs->set_rentee("BOB");  /// the car is now resitered to BOB as rentee
    cout << "Bob's car is now rented to = " << alices->rentee() << endl;
    bobs = henrys_car_rental.return_car(bobs);  /// bob returns the car to henry's rental service

    /// usecase 3 - fred is a customer, who gets the car bob has returned
    Car* freds = henrys_car_rental.get_car();  /// fred gets bob's returned car from henry's rental service
    cout << "Fred's car was last rented to = " << freds->last_rentee() << endl;
    freds->set_rentee("FRED");  /// the car is now resitered to FRED as rentee
    cout << "Fred's car is now rented to = " << freds->rentee() << endl;
    freds = henrys_car_rental.return_car(freds);  /// fred returns the car to henry's rental service

    return 0;
}

<|endoftext|>


<commit_before>#include "core/narukami.h"
#include "core/geometry.h"
#include "core/mesh.h"
#include "core/imageio.h"
#include "core/film.h"
#include "core/spectrum.h"
#include "core/sampler.h"
#include "core/transform.h"
#include "cameras/orthographic.h"
#include "core/meshloader.h"
using namespace narukami;
int main(){
    Sampler sampler(16);
    Film film(Point2i(128,128),Bounds2f(Point2f(0,0),Point2f(1,1)));
    OrthographicCamera camera(Transform(),{{0,0},{1,1}},&film);

    auto transform = translate(Vector3f(0.5, 0, 2))*scale(4,4,4);
    auto inv_transform = translate(Vector3f(-0.5, 0, -2))*scale(-0.25,-0.25,-0.25);
    auto triangles=load_mesh_triangles_from_obj(&transform,&inv_transform,"bunny.obj",".");
    auto soa_triangles = cast2SoA(triangles[0], 0, triangles[0].size());

    for(int y=0;y<128;++y){
         for(int x=0;x<128;++x){
             sampler.start_pixel(Point2i(x,y));
             do{
                auto cameraSample = sampler.get_camera_sample(Point2i(x,y));
                //std::cout<<cameraSample.pFilm<<std::endl;
                Ray ray;
                camera.generate_normalized_ray(cameraSample,&ray);
                SoARay soa_ray(ray);
                //std::cout<<ray<<std::endl;;
                Point2f uv;
                float t=0;
                int index;
                int triangles_index=-1;
                bool is_hit = false;

                for(size_t i=0;i<soa_triangles.size();++i){

                    is_hit = intersect(soa_ray, soa_triangles[i], &t, &uv, &index);
                    if(is_hit){
                        soa_ray.t_max=float4(t);
                        triangles_index=i*4+index;

                    }
                }

                if (triangles_index!=-1)
                {
                    film.add_sample(cameraSample.pFilm,Spectrum(min(t,1.0f),min(t,1.0f),min(t,1.0f)),1);
                }
             }while(sampler.start_next_sample());

         }
    }
    film.write_to_file("mesh_16ssp.png");

}

// #include "core/narukami.h"
// #include "core/geometry.h"
// #include "core/transform.h"
// #include "core/mesh.h"
// #include "core/imageio.h"
// #include "core/sampler.h"
// #include "core/meshloader.h"
// using namespace narukami;
// int main()
// {

//     Sampler sampler(16);

//     auto transform = scale(4,4,4)*translate(Vector3f(0.5, 0, 1));
//     auto inv_transform = scale(-0.25f,-0.25f,-0.25f)*translate(Vector3f(-0.5, 0, 1));
//     auto triangles=load_mesh_triangles_from_obj(&transform,&inv_transform,"bunny.obj",".");
//     auto soa_triangles = cast2SoA(triangles[0], 0, triangles[0].size());

//     std::vector<uint8_t> image;
//     float data[128 * 128 * 3];
//     for (int y = 0; y < 128; ++y)
//     {
//         for (int x = 0; x < 128; ++x)
//         {
//             data[(y*128+x)* 3] = 0;
//             data[(y*128+x)* 3 + 1] = 0;
//             sampler.start_pixel(Point2i(x, y));
//             do
//             {
//                 auto sample = sampler.get_2D();
//                 SoARay ray(Point3f((x+sample.x)/128.0f, (y+sample.y)/128.0f, 0), Vector3f(0, 0, 1));
//                 Point2f uv;
//                 float t=0;
//                 int index;
//                 int triangles_index=-1;
//                 bool b = false;

//                 for(size_t i=0;i<soa_triangles.size();++i){

//                     b = intersect(ray, soa_triangles[i], &t, &uv, &index);

//                     if(b){
//                         ray.t_max=float4(t);
//                         triangles_index=i*4+index;
//                         //std::cout<<t<<std::endl;
//                     }
//                 }

//                 if (triangles_index!=-1)
//                 {
//                     uv = triangles2[0][triangles_index]->sample_uv(uv);
//                     data[(y*128+x)* 3] += uv[0];
//                     data[(y*128+x)* 3 + 1] += uv[1];
//                     data[(y*128+x)* 3] += min(t,1.0f);
//                     data[(y*128+x)* 3 + 1] += min(t,1.0f);

//                 }
//                 // else
//                 // {
//                 //     std::cout << "miss " << ray.o << std::endl;
//                 // }

//             } while (sampler.start_next_sample());
//             data[(y*128+x)* 3] /= sampler.get_spp();
//             data[(y*128+x)* 3 + 1] /= sampler.get_spp();
//             data[(y*128+x)* 3 + 2] = 0;
//         }
//     }

//     narukami::write_image_to_file("mesh.png", data, 128, 128);
//     // //unsigned error = lodepng::encode(, image, 128, 128);
// }<commit_msg>refactor render_a_mesh<commit_after>#include "core/narukami.h"
#include "core/geometry.h"
#include "core/mesh.h"
#include "core/imageio.h"
#include "core/film.h"
#include "core/spectrum.h"
#include "core/sampler.h"
#include "core/transform.h"
#include "cameras/orthographic.h"
#include "core/meshloader.h"
using namespace narukami;
int main(){
    Sampler sampler(32);
    Film film(Point2i(128,128),Bounds2f(Point2f(0,0),Point2f(1,1)));
    OrthographicCamera camera(Transform(),{{0,0},{1,1}},&film);

    auto transform = translate(Vector3f(0.5, 0, 1))*scale(4,4,4);
    auto inv_transform = translate(Vector3f(-0.5, 0, -1))*scale(-0.25,-0.25,-0.25);
    auto triangles=load_mesh_triangles_from_obj(&transform,&inv_transform,"bunny.obj",".");
    auto soa_triangles = cast2SoA(triangles[0], 0, triangles[0].size());

    for(int y=0;y<128;++y){
         for(int x=0;x<128;++x){
             sampler.start_pixel(Point2i(x,y));
             do{
                auto cameraSample = sampler.get_camera_sample(Point2i(x,y));
                //std::cout<<cameraSample.pFilm<<std::endl;
                Ray ray;
                camera.generate_normalized_ray(cameraSample,&ray);
                SoARay soa_ray(ray);
                //std::cout<<ray<<std::endl;;
                Point2f uv;
                float t=0;
                int index;
                int triangles_index=-1;
                bool is_hit = false;

                for(size_t i=0;i<soa_triangles.size();++i){

                    is_hit = intersect(soa_ray, soa_triangles[i], &t, &uv, &index);
                    if(is_hit){
                        soa_ray.t_max=float4(t);
                        triangles_index=i*4+index;

                    }
                }

                if (triangles_index!=-1)
                {
                    film.add_sample(cameraSample.pFilm,Spectrum(min(t,1.0f),min(t,1.0f),min(t,1.0f)),1);
                }
             }while(sampler.start_next_sample());

         }
    }
    film.write_to_file("mesh_32ssp.png");

}

// #include "core/narukami.h"
// #include "core/geometry.h"
// #include "core/transform.h"
// #include "core/mesh.h"
// #include "core/imageio.h"
// #include "core/sampler.h"
// #include "core/meshloader.h"
// using namespace narukami;
// int main()
// {

//     Sampler sampler(16);

//     auto transform = scale(4,4,4)*translate(Vector3f(0.5, 0, 1));
//     auto inv_transform = scale(-0.25f,-0.25f,-0.25f)*translate(Vector3f(-0.5, 0, 1));
//     auto triangles=load_mesh_triangles_from_obj(&transform,&inv_transform,"bunny.obj",".");
//     auto soa_triangles = cast2SoA(triangles[0], 0, triangles[0].size());

//     std::vector<uint8_t> image;
//     float data[128 * 128 * 3];
//     for (int y = 0; y < 128; ++y)
//     {
//         for (int x = 0; x < 128; ++x)
//         {
//             data[(y*128+x)* 3] = 0;
//             data[(y*128+x)* 3 + 1] = 0;
//             sampler.start_pixel(Point2i(x, y));
//             do
//             {
//                 auto sample = sampler.get_2D();
//                 SoARay ray(Point3f((x+sample.x)/128.0f, (y+sample.y)/128.0f, 0), Vector3f(0, 0, 1));
//                 Point2f uv;
//                 float t=0;
//                 int index;
//                 int triangles_index=-1;
//                 bool b = false;

//                 for(size_t i=0;i<soa_triangles.size();++i){

//                     b = intersect(ray, soa_triangles[i], &t, &uv, &index);

//                     if(b){
//                         ray.t_max=float4(t);
//                         triangles_index=i*4+index;
//                         //std::cout<<t<<std::endl;
//                     }
//                 }

//                 if (triangles_index!=-1)
//                 {
//                     uv = triangles2[0][triangles_index]->sample_uv(uv);
//                     data[(y*128+x)* 3] += uv[0];
//                     data[(y*128+x)* 3 + 1] += uv[1];
//                     data[(y*128+x)* 3] += min(t,1.0f);
//                     data[(y*128+x)* 3 + 1] += min(t,1.0f);

//                 }
//                 // else
//                 // {
//                 //     std::cout << "miss " << ray.o << std::endl;
//                 // }

//             } while (sampler.start_next_sample());
//             data[(y*128+x)* 3] /= sampler.get_spp();
//             data[(y*128+x)* 3 + 1] /= sampler.get_spp();
//             data[(y*128+x)* 3 + 2] = 0;
//         }
//     }

//     narukami::write_image_to_file("mesh.png", data, 128, 128);
//     // //unsigned error = lodepng::encode(, image, 128, 128);
// }<|endoftext|>


<commit_before>//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
//
// spdlog usage example
//
//

#include <iostream>

void stdout_example();
void basic_example();
void rotating_example();
void daily_example();
void async_example();
void user_defined_example();
void err_handler_example();
void syslog_example();

#include "spdlog/spdlog.h"

int main(int, char *[])
{
    try
    {
        // console logging example
        stdout_example();

        // various file loggers
        basic_example();
        rotating_example();
        daily_example();

        // async logging using a backing thread pool
        async_example();

        // user defined types logging by implementing operator<<
        user_defined_example();

        // custom  error handler
        err_handler_example();

        // apply some function on all registered loggers
        spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->info("End of example."); });

        // Release and close all loggers
        spdlog::drop_all();
    }
    // Exceptions will only be thrown upon failed logger or sink construction (not during logging)
    catch (const spdlog::spdlog_ex &ex)
    {
        std::cout << "Log init failed: " << ex.what() << std::endl;
        return 1;
    }
}

#include "spdlog/sinks/stdout_color_sinks.h" // or "/sinks/stdout_sinks.h" if no colors needed

void stdout_example()
{
    // create color multi threaded logger
    auto console = spdlog::stdout_logger_mt("console");
    console->info("Welcome to spdlog!");
    console->error("Some error message with arg: {}", 1);

    auto err_logger = spdlog::stderr_logger_mt("error_logger");
    err_logger->error("Some error message");
    // Formatting examples
    console->warn("Easy padding in numbers like {:08d}", 12);
    console->critical("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42);
    console->info("Support for floats {:03.2f}", 1.23456);
    console->info("Positional args are {1} {0}..", "too", "supported");
    console->info("{:<30}", "left aligned");

    spdlog::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)");

    // Runtime log levels
    spdlog::set_level(spdlog::level::info); // Set global log level to info
    console->debug("This message should not be displayed!");
    console->set_level(spdlog::level::trace); // Set specific logger's log level
    console->debug("This message should be displayed..");

    // Customize msg format for all loggers
    spdlog::set_pattern("[%H:%M:%S %z] [%^---%L---%$] [thread %t] %v");
    console->info("This an info message with custom format");

    // Compile time log levels
    // define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON
    SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
    SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);
}

#include "spdlog/sinks/basic_file_sink.h"
void basic_example()
{
    // Create basic file logger (not rotated)
    auto my_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt");
}

#include "spdlog/sinks/rotating_file_sink.h"
void rotating_example()
{
    // Create a file rotating logger with 5mb size max and 3 rotated files
    auto rotating_logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3);
}

#include "spdlog/sinks/daily_file_sink.h"
void daily_example()
{
    // Create a daily logger - a new file is created every day on 2:30am
    auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
}

#include "spdlog/async.h"
void async_example()
{
    // default thread pool settings can be modified *before* creating the async logger:
    // spdlog::init_thread_pool(32768, 1); // queue with max 32k items 1 backing thread.
    auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");
    // alternatively:
    // auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");

    for (int i = 1; i < 101; ++i)
    {
        async_file->info("Async message #{}", i);
    }
}

// user defined types logging by implementing operator<<
#include "spdlog/fmt/ostr.h" // must be included
struct my_type
{
    int i;
    template<typename OStream>
    friend OStream &operator<<(OStream &os, const my_type &c)
    {
        return os << "[my_type i=" << c.i << "]";
    }
};

void user_defined_example()
{
    spdlog::get("console")->info("user defined type: {}", my_type{14});
}

//
// custom error handler
//
void err_handler_example()
{
    // can be set globally or per logger(logger->set_error_handler(..))
    spdlog::set_error_handler([](const std::string &msg) { spdlog::get("console")->error("*** LOGGER ERROR ***: {}", msg); });
    spdlog::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3);
}

// syslog example (linux/osx/freebsd)
#ifndef _WIN32
#include "spdlog/sinks/syslog_sink.h"
void syslog_example()
{
    std::string ident = "spdlog-example";
    auto syslog_logger = spdlog::syslog_logger("syslog", ident, LOG_PID);
    syslog_logger->warn("This is warning that will end up in syslog.");
}
#endif

// Android example
#if defined(__ANDROID__)
#incude "spdlog/sinks/android_sink.h"
void android_example()
{
    std::string tag = "spdlog-android";
    auto android_logger = spdlog::android_logger("android", tag);
    android_logger->critical("Use \"adb shell logcat\" to view this message.");
}

#endif
<commit_msg>Update example.cpp<commit_after>//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
//
// spdlog usage example
//
//

#include <iostream>

void stdout_example();
void basic_example();
void rotating_example();
void daily_example();
void async_example();
void user_defined_example();
void err_handler_example();
void syslog_example();

#include "spdlog/spdlog.h"

int main(int, char *[])
{
    try
    {
        // console logging example
        stdout_example();

        // various file loggers
        basic_example();
        rotating_example();
        daily_example();

        // async logging using a backing thread pool
        async_example();

        // user defined types logging by implementing operator<<
        user_defined_example();

        // custom  error handler
        err_handler_example();

        // apply some function on all registered loggers
        spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->info("End of example."); });

        // Release and close all loggers
        spdlog::drop_all();
    }
    // Exceptions will only be thrown upon failed logger or sink construction (not during logging)
    catch (const spdlog::spdlog_ex &ex)
    {
        std::cout << "Log init failed: " << ex.what() << std::endl;
        return 1;
    }
}

#include "spdlog/sinks/stdout_color_sinks.h" // or "/sinks/stdout_sinks.h" if no colors needed
void stdout_example()
{
    // create color multi threaded logger
    auto console = spdlog::stdout_logger_mt("console");
    console->info("Welcome to spdlog!");
    console->error("Some error message with arg: {}", 1);

    auto err_logger = spdlog::stderr_logger_mt("error_logger");
    err_logger->error("Some error message");
    // Formatting examples
    console->warn("Easy padding in numbers like {:08d}", 12);
    console->critical("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42);
    console->info("Support for floats {:03.2f}", 1.23456);
    console->info("Positional args are {1} {0}..", "too", "supported");
    console->info("{:<30}", "left aligned");

    spdlog::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)");

    // Runtime log levels
    spdlog::set_level(spdlog::level::info); // Set global log level to info
    console->debug("This message should not be displayed!");
    console->set_level(spdlog::level::trace); // Set specific logger's log level
    console->debug("This message should be displayed..");

    // Customize msg format for all loggers
    spdlog::set_pattern("[%H:%M:%S %z] [%^---%L---%$] [thread %t] %v");
    console->info("This an info message with custom format");

    // Compile time log levels
    // define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON
    SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
    SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);
}

#include "spdlog/sinks/basic_file_sink.h"
void basic_example()
{
    // Create basic file logger (not rotated)
    auto my_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt");
}

#include "spdlog/sinks/rotating_file_sink.h"
void rotating_example()
{
    // Create a file rotating logger with 5mb size max and 3 rotated files
    auto rotating_logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3);
}

#include "spdlog/sinks/daily_file_sink.h"
void daily_example()
{
    // Create a daily logger - a new file is created every day on 2:30am
    auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
}

#include "spdlog/async.h"
void async_example()
{
    // default thread pool settings can be modified *before* creating the async logger:
    // spdlog::init_thread_pool(32768, 1); // queue with max 32k items 1 backing thread.
    auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");
    // alternatively:
    // auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");

    for (int i = 1; i < 101; ++i)
    {
        async_file->info("Async message #{}", i);
    }
}

// user defined types logging by implementing operator<<
#include "spdlog/fmt/ostr.h" // must be included
struct my_type
{
    int i;
    template<typename OStream>
    friend OStream &operator<<(OStream &os, const my_type &c)
    {
        return os << "[my_type i=" << c.i << "]";
    }
};

void user_defined_example()
{
    spdlog::get("console")->info("user defined type: {}", my_type{14});
}

//
// custom error handler
//
void err_handler_example()
{
    // can be set globally or per logger(logger->set_error_handler(..))
    spdlog::set_error_handler([](const std::string &msg) { spdlog::get("console")->error("*** LOGGER ERROR ***: {}", msg); });
    spdlog::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3);
}

// syslog example (linux/osx/freebsd)
#ifndef _WIN32
#include "spdlog/sinks/syslog_sink.h"
void syslog_example()
{
    std::string ident = "spdlog-example";
    auto syslog_logger = spdlog::syslog_logger("syslog", ident, LOG_PID);
    syslog_logger->warn("This is warning that will end up in syslog.");
}
#endif

// Android example
#if defined(__ANDROID__)
#incude "spdlog/sinks/android_sink.h"
void android_example()
{
    std::string tag = "spdlog-android";
    auto android_logger = spdlog::android_logger("android", tag);
    android_logger->critical("Use \"adb shell logcat\" to view this message.");
}

#endif
<|endoftext|>