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

int spiTransfer(unsigned char* const bytes, unsigned int length, void* const customData) {
  return wiringPiSPIDataRW(0, bytes, length);
}

int main() {
  int res = wiringPiSPISetup(0, 500000);

  if (res == -1) {
    std::cerr << "Error setting up SPI interface\n";
    return -1;
  }

  RFM_MODE m = RFM_MODE_SLEEP;

  res = setMode(&m, spiTransfer);

  if (res == -1) {
    std::cerr << "Error transferring data\n";
    return -1;
  }

  m = (RFM_MODE)0;

  res = getMode(&m, spiTransfer);

  if (res == -1) {
    std::cerr << "Error transferring data\n";
    return -1;
  }

  if (m == RFM_MODE_SLEEP) {
    std::cout << "...sleeping...\n";
  } else {
    std::cout << "...doing other stuff..\n";
  }

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

int spiTransfer(unsigned char* const bytes, unsigned int length, void* const customData) {
  return wiringPiSPIDataRW(0, bytes, length);
}

int main() {
  int res = wiringPiSPISetup(0, 500000);

  if (res == -1) {
    std::cerr << "Error setting up SPI interface\n";
    return -1;
  }

  RFM_MODE m = RFM_MODE_SLEEP;

  res = setMode(&m, spiTransfer);

  if (res == -1) {
    std::cerr << "Error transferring data\n";
    return -1;
  }

  m = (RFM_MODE)0;

  res = getMode(&m, spiTransfer);

  if (res == -1) {
    std::cerr << "Error transferring data\n";
    return -1;
  }

  if (m == RFM_MODE_SLEEP) {
    std::cout << "...sleeping...\n";
  } else {
    std::cout << "...doing other stuff..\n";
  }

  float cf;

  res = getCarrierFrequency(&cf, spiTransfer);

  if (res == -1) {
    std::cerr << "Error setting carrier frequency\n";
    return -1;
  }

  std::cout << "carrier frequency: " << cf << "\n";

  return 0;
}
<|endoftext|>


<commit_before>#include <cstdio>

#include <nwg.h>
#include <nwg_basicprotocolcodec.h>

#define BUFFSIZE 32768
#define MAX_CLIENT 5

class EchoHandler : public Nwg::Handler
{
    void sessionOpened(Nwg::Session &session)
    {
        const int num_client = ++session.getServer().get<int>("num_client");
        const int last_id = ++session.getServer().get<int>("last_id");
        int &client_id = *new int(last_id);

        printf("client #%d connected!\n", client_id);
        printf("num_client: %d\n", num_client);

        session.put<int>("msg_received", std::make_shared<int>(1));
        session.put<int>("client_id", &client_id);

        Nwg::ByteBuffer &out = *new Nwg::ByteBuffer(BUFFSIZE);

        if (num_client > MAX_CLIENT) {
            out.put("Client limit exceeded!\n");
            out.flip();

            session.write(&out);
            return;
        }

        out.put("Just type anything. Send key ^] to exit from telnet.\n");
        out.put("1. << ");
        out.flip();

        session.write(&out);
    }

    void sessionClosed(Nwg::Session &session)
    {
        const int num_client = --session.getServer().get<int>("num_client");
        const int client_id = session.get<int>("client_id");
        const int msg_received = --session.get<int>("msg_received");

        printf("client #%d disconnected! # of message received: %d\n", client_id, msg_received);
        printf("num_client: %d\n", num_client);
    }

    void messageReceived(Nwg::Session &session, Nwg::Object &obj)
    {
        Nwg::ByteBuffer &msg = dynamic_cast<Nwg::ByteBuffer &>(obj);

        const int client_id = session.get<int>("client_id");
        int &msg_received = session.get<int>("msg_received");

        printf("client #%d >> %s\n", client_id, msg.sreadUntil('\n').c_str());
        msg.jump(0);

        Nwg::ByteBuffer &out = *new Nwg::ByteBuffer(BUFFSIZE);
        out.put(std::to_string(msg_received) + ". >> ");
        out.put(msg.read(msg.remaining()));
        out.put("\n" + std::to_string(msg_received + 1) + ". << ");
        out.flip();

        session.write(&out);

        msg_received++;
    }

    void messageSent(Nwg::Session &session, Nwg::Object &obj)
    {
        const int num_client = session.getServer().get<int>("num_client");

        if (num_client > MAX_CLIENT) {
            session.close();
        }
    }
};

void run()
{
    Nwg::Server server(8845);
    server.setBuffSize(BUFFSIZE);

    server.setProtocolCodec(new Nwg::BasicProtocolCodec());
    server.setHandler(new EchoHandler());

    server.put<int>("last_id", std::make_shared<int>(0));
    server.put<int>("num_client", std::make_shared<int>(0));

    printf("Listening on port %d\n", server.getPort());
    server.run();
}

int main()
{
    run();
    return 0;
}
<commit_msg>Update example (echoserver)<commit_after>#include <cstdio>

#include <nwg.h>
#include <nwg_basicprotocolcodec.h>

#define BUFFSIZE 32768
#define MAX_CLIENT 5

static int numClient = 0;
static int lastId = 0;

class EchoHandler : public Nwg::Handler
{
    void sessionOpened(Nwg::Session &session)
    {
        numClient++;
        lastId++;

        int &clientId = *new int(lastId);

        printf("client #%d connected!\n", clientId);
        printf("num_client: %d\n", numClient);

        session.put<int>("msg_received", std::make_shared<int>(1));
        session.put<int>("client_id", &clientId);

        Nwg::ByteBuffer &out = *new Nwg::ByteBuffer(BUFFSIZE);

        if (numClient > MAX_CLIENT) {
            out.put("Client limit exceeded!\n");
            out.flip();

            session.write(&out);
            return;
        }

        out.put("Just type anything. Send key ^] to exit from telnet.\n");
        out.put("1. << ");
        out.flip();

        session.write(&out);
    }

    void sessionClosed(Nwg::Session &session)
    {
        --numClient;

        int clientId = session.get<int>("client_id");
        int msgReceived = --session.get<int>("msg_received");

        printf("client #%d disconnected! # of message received: %d\n", clientId, msgReceived);
        printf("num_client: %d\n", numClient);
    }

    void messageReceived(Nwg::Session &session, Nwg::Object &obj)
    {
        Nwg::ByteBuffer &msg = dynamic_cast<Nwg::ByteBuffer &>(obj);

        int clientId = session.get<int>("client_id");
        int &msgReceived = session.get<int>("msg_received");

        printf("client #%d >> %s\n", clientId, msg.sreadUntil('\n').c_str());
        msg.jump(0);

        Nwg::ByteBuffer &out = *new Nwg::ByteBuffer(BUFFSIZE);
        out.put(std::to_string(msgReceived) + ". >> ");
        out.put(msg.read(msg.remaining()));
        out.put("\n" + std::to_string(msgReceived + 1) + ". << ");
        out.flip();

        session.write(&out);

        msgReceived++;
    }

    void messageSent(Nwg::Session &session, Nwg::Object &obj)
    {
        if (numClient > MAX_CLIENT) {
            session.close();
        }
    }
};

void run()
{
    Nwg::Server server(8845);
    server.setBuffSize(BUFFSIZE);

    server.setProtocolCodec(new Nwg::BasicProtocolCodec());
    server.setHandler(new EchoHandler());

    printf("Listening on port %d\n", server.getPort());
    server.run();
}

int main()
{
    run();
    return 0;
}
<|endoftext|>


<commit_before>/**
 * File    : E.cpp
 * Author  : Kazune Takahashi
 * Created : 12/22/2018, 9:09:29 PM
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <functional>
#include <random> // auto rd = bind(uniform_int_distribution<int>(0, 9), mt19937(19920725));
#include <chrono> // std::chrono::system_clock::time_point start_time, end_time;
// start = std::chrono::system_clock::now();
// double elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end_time-start_time).count();
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int N;
ll A[200010];
ll X[200010];
ll Y[200010];
ll imos_X[200010];
ll imos_Y[200010];
ll imos_imos_X[200010];
ll imos_imos_Y[200010];

ll calc(ll x, ll y)
{
  ll res = 0;
  ll mult = 1;
  while (x > y * mult)
  {
    res += 2;
    mult *= 4;
  }
  return res;
}

int main()
{
  cin >> N;
  for (auto i = 0; i < N; i++)
  {
    cin >> A[i];
  }
  X[0] = 0;
  for (auto i = 1; i < N; i++)
  {
    X[i] = calc(A[i - 1], A[i]);
  }
  imos_X[0] = 0;
  for (auto i = 1; i < N; i++)
  {
    imos_X[i] = X[i] + imos_X[i - 1];
  }
  imos_imos_X[0] = 0;
  for (auto i = 0; i < N; i++)
  {
    imos_imos_X[i] = imos_X[i] + imos_imos_X[i - 1];
  }
  Y[N - 1] = 0;
  for (auto i = N - 2; i >= 0; i--)
  {
    Y[i] = calc(A[i], A[i - 1]);
  }
  imos_Y[N - 1] = 0;
  for (auto i = N - 2; i >= 0; i--)
  {
    imos_Y[i] = Y[i] + imos_Y[i + 1];
  }
  imos_imos_Y[N - 1] = 0;
  for (auto i = N - 2; i >= 0; i--)
  {
    imos_imos_Y[i] = imos_Y[i] + imos_imos_Y[i + 1];
  }
  ll ans = 1000000000000000;
  for (auto i = 0; i < N; i++)
  {
    ll t = i + imos_imos_X[N - 1] - imos_imos_X[i] + imos_imos_Y[0] - imos_imos_Y[i];
    ans = min(t, ans);
  }
  cout << ans << endl;
}<commit_msg>tried E.cpp to 'E'<commit_after>/**
 * File    : E.cpp
 * Author  : Kazune Takahashi
 * Created : 12/22/2018, 9:09:29 PM
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <functional>
#include <random> // auto rd = bind(uniform_int_distribution<int>(0, 9), mt19937(19920725));
#include <chrono> // std::chrono::system_clock::time_point start_time, end_time;
// start = std::chrono::system_clock::now();
// double elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end_time-start_time).count();
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int N;
ll A[200010];
ll X[200010];
ll Y[200010];
ll imos_X[200010];
ll imos_Y[200010];
ll imos_imos_X[200010];
ll imos_imos_Y[200010];

ll calc(ll x, ll y)
{
  ll res = 0;
  ll mult = 1;
  while (x > y * mult)
  {
    res += 2;
    mult *= 4;
  }
  return res;
}

int main()
{
  cin >> N;
  for (auto i = 0; i < N; i++)
  {
    cin >> A[i];
  }
  X[0] = 0;
  for (auto i = 1; i < N; i++)
  {
    X[i] = calc(A[i - 1], A[i]);
  }
  imos_X[0] = 0;
  for (auto i = 1; i < N; i++)
  {
    imos_X[i] = X[i] + imos_X[i - 1];
  }
  imos_imos_X[0] = 0;
  for (auto i = 0; i < N; i++)
  {
    imos_imos_X[i] = imos_X[i] + imos_imos_X[i - 1];
  }
  Y[N - 1] = 0;
  for (auto i = N - 2; i >= 0; i--)
  {
    Y[i] = calc(A[i + 1], A[i]);
  }
  imos_Y[N - 1] = 0;
  for (auto i = N - 2; i >= 0; i--)
  {
    imos_Y[i] = Y[i] + imos_Y[i + 1];
  }
  imos_imos_Y[N - 1] = 0;
  for (auto i = N - 2; i >= 0; i--)
  {
    imos_imos_Y[i] = imos_Y[i] + imos_imos_Y[i + 1];
  }
  ll ans = 1000000000000000;
  for (auto i = 0; i < N; i++)
  {
    ll t = i + imos_imos_X[N - 1] - imos_imos_X[i] + imos_imos_Y[0] - imos_imos_Y[i];
    ans = min(t, ans);
  }
  cout << ans << endl;
}<|endoftext|>


<commit_before>/*!
    \file memory_appender.cpp
    \brief Logging memory appender implementation
    \author Ivan Shynkarenka
    \date 26.07.2016
    \copyright MIT License
*/

#include "logging/appenders/memory_appender.h"

#include <cstdio>

namespace CppLogging {

void MemoryAppender::AppendRecord(Record& record)
{
    // Skip logging records without layout
    if (record.raw.first == nullptr)
        return;

    // Resize the buffer to required size
    _buffer.resize(record.raw.second);

    // Get the buffer start position
    uint8_t* buffer = _buffer.data();

    // Copy logging record content into the allocated memory buffer
    std::memcpy(buffer, record.raw.first, record.raw.second);
}

} // namespace CppLogging
<commit_msg>Bugfixing<commit_after>/*!
    \file memory_appender.cpp
    \brief Logging memory appender implementation
    \author Ivan Shynkarenka
    \date 26.07.2016
    \copyright MIT License
*/

#include "logging/appenders/memory_appender.h"

#include <cstring>

namespace CppLogging {

void MemoryAppender::AppendRecord(Record& record)
{
    // Skip logging records without layout
    if (record.raw.first == nullptr)
        return;

    // Resize the buffer to required size
    _buffer.resize(record.raw.second);

    // Get the buffer start position
    uint8_t* buffer = _buffer.data();

    // Copy logging record content into the allocated memory buffer
    std::memcpy(buffer, record.raw.first, record.raw.second);
}

} // namespace CppLogging
<|endoftext|>


<commit_before>#include "WaveOut.h"

#include <boost/bind.hpp>

WaveOut::WaveOut(void) :
	m_waveHandle(NULL),
	m_pCallback(NULL),
    audioThread(NULL),
	m_dwSamplesOut(0),
	m_LastPlayedBuffer(-1),
	m_NumBuffers(8) //TODO: config
{
	ZeroMemory(&m_waveFormatPCMEx, sizeof(m_waveFormatPCMEx));

	QueryPerformanceFrequency(&m_liCountsPerSecond);

	m_pfAudioBuffer = NULL;
}

WaveOut::~WaveOut(void)
{
	Shutdown();
}

void WaveOut::Destroy()
{
    delete this;
}

//////////////////////////////////////////////////////////////////////////////
//
//	Actual Audio Output Stuff!
//
//

void CALLBACK WaveOut::WaveCallback(HWAVEOUT hWave, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD dw2)
{
    if(uMsg == WOM_DONE)
	{
		WaveOut*	to			= (WaveOut *)dwUser;
		LPWAVEHDR	whr					= (LPWAVEHDR)dw1;

		to->m_dwSamplesOut		+= (whr->dwBufferLength / to->m_waveFormatPCMEx.Format.nBlockAlign);
		to->m_LastPlayedBuffer	= (unsigned long)whr->dwUser;

		QueryPerformanceCounter(&to->m_liLastPerformanceCount);

        to->audioCondition.notify_one();
   }
}

bool WaveOut::Open(void)
{
	int r;
	int currentDevice = this->GetOutputDevice();

    boost::mutex::scoped_lock lock(this->audioMutex);

	if(m_waveHandle==NULL)
	{
		r = waveOutOpen(&m_waveHandle, currentDevice, (WAVEFORMATEX*)&m_waveFormatPCMEx, (DWORD_PTR)WaveCallback, (DWORD_PTR)this, CALLBACK_FUNCTION);
		if(r != MMSYSERR_NOERROR)
		{
			return(false);
		}

		m_Buffers = (WAVEHDR *)VirtualAlloc(NULL, m_NumBuffers * sizeof(WAVEHDR), MEM_COMMIT, PAGE_READWRITE);
//        m_dwBufferSize = m_BlockSize * m_NumBuffers;

        unsigned int bytesPerSample = m_waveFormatPCMEx.Format.nChannels*m_waveFormatPCMEx.Format.wBitsPerSample/16;

        m_dwBufferSize = m_BlockSize*bytesPerSample;

		m_pfAudioBuffer = (float *)VirtualAlloc(NULL, m_dwBufferSize * m_NumBuffers, MEM_COMMIT, PAGE_READWRITE);		// allocate audio memory
		VirtualLock(m_pfAudioBuffer, m_dwBufferSize * m_NumBuffers);													// lock the audio memory into physical memory

		for(unsigned long x=0; x<m_NumBuffers; x++)
		{
//            m_Buffers[x].dwBufferLength		= m_BlockSize * m_NumBuffers;
            m_Buffers[x].dwBufferLength		= m_BlockSize*bytesPerSample;
			m_Buffers[x].lpData				= (LPSTR)&m_pfAudioBuffer[x * m_BlockSize];
 			m_Buffers[x].dwUser				= x;
			m_Buffers[x].dwBytesRecorded	= 0;
			m_Buffers[x].dwFlags			= 0;
			m_Buffers[x].dwLoops			= 0;

			waveOutPrepareHeader(m_waveHandle, &m_Buffers[x], sizeof(WAVEHDR));
            m_Buffers[x].dwFlags			|= WHDR_DONE;
		}

		QueryPerformanceCounter(&m_liLastPerformanceCount);

	}

	return true;
}

bool WaveOut::Close(void)
{
	int r;

    boost::mutex::scoped_lock lock(this->audioMutex);

	if(m_waveHandle)
	{
		m_Playing = false;

again:
		if(waveOutReset(m_waveHandle) == MMSYSERR_NOERROR)
		{
			for(unsigned long x=0; x<m_NumBuffers; x++)
			{
				if(m_Buffers[x].dwFlags & WHDR_PREPARED)
					waveOutUnprepareHeader(m_waveHandle, &m_Buffers[x], sizeof(WAVEHDR));
			}
		}

		while((r = waveOutClose(m_waveHandle)) != MMSYSERR_NOERROR)
		{
			goto again;
		}

		m_waveHandle = NULL;

		VirtualUnlock(m_pfAudioBuffer, m_dwBufferSize * m_NumBuffers);
		VirtualFree(m_pfAudioBuffer, 0, MEM_RELEASE);
		m_pfAudioBuffer = NULL;

		VirtualFree(m_Buffers, 0, MEM_RELEASE);
		m_Buffers = NULL;
	}

	return true;
}

///////////////////////////////////////////////////////////////////////
//
//

unsigned long WaveOut::ThreadProc(void)
{
    bool hasPlayed = false;

	while(m_bThreadRun && !hasPlayed)
	{
		while(m_Playing && this->m_pCallback)
		{
			boost::mutex::scoped_lock lock(this->audioMutex);

            while(this->m_Buffers && m_Playing && ((m_Buffers[m_ActiveBuffer].dwFlags&WHDR_DONE)==0) )
			{
                this->audioCondition.wait(lock);
			}

			if(m_Playing)
			{
				if(m_pCallback->GetBuffer((float*)m_Buffers[m_ActiveBuffer].lpData, m_BlockSize))
				{
					m_Buffers[m_ActiveBuffer].dwUser = m_ActiveBuffer;
                    waveOutWrite(m_waveHandle, &m_Buffers[m_ActiveBuffer], sizeof(WAVEHDR));
                    m_ActiveBuffer++;
					m_ActiveBuffer &= (m_NumBuffers-1);
				}
				else
				{
					m_Playing = false;
                    hasPlayed = true;
                    this->audioCondition.wait(lock);
				}
			}
		}
    }
	return(0);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////
//
//	Initialization and termination
//
//
//

bool WaveOut::Initialize(void)
{
	m_Playing = false;
	m_ActiveBuffer	= 0;
	m_QueuedBuffers	= 0;

    m_bThreadRun = true;

    this->audioThread = new boost::thread(boost::bind(&WaveOut::ThreadProc, this));

	if(!this->audioThread)
		return false;

	return(true);
}

bool WaveOut::Shutdown(void)
{
	Close();

//    boost::mutex::scoped_lock lock(this->audioMutex);

	if(this->audioThread)
	{
		m_bThreadRun = false;

        this->audioCondition.notify_one();
        this->audioThread->join();
        delete this->audioThread;
    }

	return(true);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//		Setup Stuff, can only be called before initialize
//
//

bool WaveOut::SetFormat(unsigned long SampleRate, unsigned long Channels)
{
	if( (SampleRate != m_waveFormatPCMEx.Format.nSamplesPerSec) ||
		(Channels != m_waveFormatPCMEx.Format.nChannels) )
	{
		Shutdown();

		DWORD speakerconfig;

		if(Channels == 1)
		{
			speakerconfig = KSAUDIO_SPEAKER_MONO;
		}
		else if(Channels == 2)
		{
			speakerconfig = KSAUDIO_SPEAKER_STEREO;
		}
		else if(Channels == 4)
		{
			speakerconfig = KSAUDIO_SPEAKER_QUAD;
		}
		else if(Channels == 5)
		{
			speakerconfig = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT  | SPEAKER_BACK_RIGHT);
		}
		else if(Channels == 6)
		{
			speakerconfig = KSAUDIO_SPEAKER_5POINT1;
		}
		else
		{
			speakerconfig = 0;
		}

		m_waveFormatPCMEx.Format.cbSize					= 22;
		m_waveFormatPCMEx.Format.wFormatTag				= WAVE_FORMAT_EXTENSIBLE;
		m_waveFormatPCMEx.Format.nChannels				= (WORD)Channels;
		m_waveFormatPCMEx.Format.nSamplesPerSec			= SampleRate;
		m_waveFormatPCMEx.Format.wBitsPerSample			= 32;
		m_waveFormatPCMEx.Format.nBlockAlign			= (m_waveFormatPCMEx.Format.wBitsPerSample/8) * m_waveFormatPCMEx.Format.nChannels;
		m_waveFormatPCMEx.Format.nAvgBytesPerSec		= ((m_waveFormatPCMEx.Format.wBitsPerSample/8) * m_waveFormatPCMEx.Format.nChannels) * m_waveFormatPCMEx.Format.nSamplesPerSec; //Compute using nBlkAlign * nSamp/Sec

        // clangen: wValidBitsPerSample/wReserved/wSamplesPerBlock are a union,
        // so don't set wReserved or wSamplesPerBlock to 0 after assigning
        // wValidBitsPerSample. (Vista bug)
		m_waveFormatPCMEx.Samples.wValidBitsPerSample	= 32;

		m_waveFormatPCMEx.dwChannelMask					= speakerconfig;
		m_waveFormatPCMEx.SubFormat						= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;

		unsigned long samplesperms = ((unsigned long)((float)m_waveFormatPCMEx.Format.nSamplesPerSec / 1000.0f)) * m_waveFormatPCMEx.Format.nChannels;

        m_Interval			= (this->GetBufferSizeMs() / m_NumBuffers) / 2;
		m_BlockSize			= (this->GetBufferSizeMs() / m_NumBuffers) * samplesperms;	// this should be a 300MS buffer size!
		while(m_BlockSize & m_waveFormatPCMEx.Format.nBlockAlign)
			m_BlockSize++;

		if(!Initialize())
			return false;
	}

	return true;
}

////////////////////////////////////////////////////////////////////////////////////////////
// PLAYBACK CONTROLS
//
//
bool WaveOut::Start(void)
{
	if(!Open())
		return(false);

    boost::mutex::scoped_lock lock(this->audioMutex);

	while(m_QueuedBuffers) // Handles pause/play?
	{
		waveOutWrite(m_waveHandle, &m_Buffers[m_ActiveBuffer], sizeof(WAVEHDR));
		m_ActiveBuffer++;
		m_ActiveBuffer &= (m_NumBuffers-1); // Probably only works if m_Numbuffers is power of 2

		m_QueuedBuffers--;
	}

	m_Playing = true;

    this->audioCondition.notify_one();

	return true;
}

bool WaveOut::Stop(void)
{
    boost::mutex::scoped_lock lock(this->audioMutex);

	m_QueuedBuffers = 0;
	m_Playing = false;

	if(m_waveHandle)
	{
		for(unsigned long buffer=0; buffer<m_NumBuffers; buffer++)
		{
			if(	!(m_Buffers[buffer].dwFlags & WHDR_INQUEUE) )
			{
				m_QueuedBuffers++;
			}
		}
		m_ActiveBuffer-= m_QueuedBuffers;
		m_ActiveBuffer &= (m_NumBuffers-1);
	}

	Close();

	return true;
}

bool WaveOut::Reset(void)
{
//	CAutoLock lock(&m_AudioLock);

	// simmilar to stop, except we dont rewind the stream
	if(m_waveHandle)
	{
		waveOutReset(m_waveHandle);

		m_ActiveBuffer = 0;
		m_dwSamplesOut = 0;

		m_LastPlayedBuffer = 0;

		QueryPerformanceCounter(&m_liLastPerformanceCount);
		return(true);
	}
	return false;
}<commit_msg>Fixed waveOut for multichannel audio (more than 2 channels)<commit_after>#include "WaveOut.h"

#include <boost/bind.hpp>

WaveOut::WaveOut(void) :
	m_waveHandle(NULL),
	m_pCallback(NULL),
    audioThread(NULL),
	m_dwSamplesOut(0),
	m_LastPlayedBuffer(-1),
	m_NumBuffers(8) //TODO: config
{
	ZeroMemory(&m_waveFormatPCMEx, sizeof(m_waveFormatPCMEx));

	QueryPerformanceFrequency(&m_liCountsPerSecond);

	m_pfAudioBuffer = NULL;
}

WaveOut::~WaveOut(void)
{
	Shutdown();
}

void WaveOut::Destroy()
{
    delete this;
}

//////////////////////////////////////////////////////////////////////////////
//
//	Actual Audio Output Stuff!
//
//

void CALLBACK WaveOut::WaveCallback(HWAVEOUT hWave, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD dw2)
{
    if(uMsg == WOM_DONE)
	{
		WaveOut*	to			= (WaveOut *)dwUser;
		LPWAVEHDR	whr					= (LPWAVEHDR)dw1;

		to->m_dwSamplesOut		+= (whr->dwBufferLength / to->m_waveFormatPCMEx.Format.nBlockAlign);
		to->m_LastPlayedBuffer	= (unsigned long)whr->dwUser;

		QueryPerformanceCounter(&to->m_liLastPerformanceCount);

        to->audioCondition.notify_one();
   }
}

bool WaveOut::Open(void)
{
	int r;
	int currentDevice = this->GetOutputDevice();

    boost::mutex::scoped_lock lock(this->audioMutex);

	if(m_waveHandle==NULL)
	{
		r = waveOutOpen(&m_waveHandle, currentDevice, (WAVEFORMATEX*)&m_waveFormatPCMEx, (DWORD_PTR)WaveCallback, (DWORD_PTR)this, CALLBACK_FUNCTION);
		if(r != MMSYSERR_NOERROR)
		{
			return(false);
		}

		m_Buffers = (WAVEHDR *)VirtualAlloc(NULL, m_NumBuffers * sizeof(WAVEHDR), MEM_COMMIT, PAGE_READWRITE);

        unsigned int bytesPerSample = m_waveFormatPCMEx.Format.wBitsPerSample/8;

        m_dwBufferSize = m_BlockSize*bytesPerSample;

		m_pfAudioBuffer = (float *)VirtualAlloc(NULL, m_dwBufferSize * m_NumBuffers, MEM_COMMIT, PAGE_READWRITE);		// allocate audio memory
		VirtualLock(m_pfAudioBuffer, m_dwBufferSize * m_NumBuffers);													// lock the audio memory into physical memory

		for(unsigned long x=0; x<m_NumBuffers; x++)
		{
            m_Buffers[x].dwBufferLength		= m_dwBufferSize;
            m_Buffers[x].lpData				= (LPSTR)&(this->m_pfAudioBuffer[x*m_BlockSize]);
 			m_Buffers[x].dwUser				= x;
			m_Buffers[x].dwBytesRecorded	= 0;
			m_Buffers[x].dwFlags			= 0;
			m_Buffers[x].dwLoops			= 0;

			waveOutPrepareHeader(m_waveHandle, &m_Buffers[x], sizeof(WAVEHDR));
            m_Buffers[x].dwFlags			|= WHDR_DONE;
		}

		QueryPerformanceCounter(&m_liLastPerformanceCount);

	}

	return true;
}

bool WaveOut::Close(void)
{
	int r;

    boost::mutex::scoped_lock lock(this->audioMutex);

	if(m_waveHandle)
	{
		m_Playing = false;

        do{
		    if(waveOutReset(m_waveHandle) == MMSYSERR_NOERROR)
		    {
			    for(unsigned long x=0; x<m_NumBuffers; x++)
			    {
				    if(m_Buffers[x].dwFlags & WHDR_PREPARED)
					    waveOutUnprepareHeader(m_waveHandle, &m_Buffers[x], sizeof(WAVEHDR));
			    }
		    }
        } while((r = waveOutClose(m_waveHandle)) != MMSYSERR_NOERROR);

		m_waveHandle = NULL;

		VirtualUnlock(m_pfAudioBuffer, m_dwBufferSize * m_NumBuffers);
		VirtualFree(m_pfAudioBuffer, 0, MEM_RELEASE);
		m_pfAudioBuffer = NULL;

		VirtualFree(m_Buffers, 0, MEM_RELEASE);
		m_Buffers = NULL;
	}

	return true;
}

///////////////////////////////////////////////////////////////////////
//
//

unsigned long WaveOut::ThreadProc(void)
{
    bool hasPlayed = false;

	while(m_bThreadRun && !hasPlayed)
	{
		while(m_Playing && this->m_pCallback)
		{
			boost::mutex::scoped_lock lock(this->audioMutex);

            while(this->m_Buffers && m_Playing && ((m_Buffers[m_ActiveBuffer].dwFlags&WHDR_DONE)==0) )
			{
                this->audioCondition.wait(lock);
			}

			if(m_Playing)
			{
				if(m_pCallback->GetBuffer((float*)m_Buffers[m_ActiveBuffer].lpData, m_BlockSize))
				{
					m_Buffers[m_ActiveBuffer].dwUser = m_ActiveBuffer;
                    waveOutWrite(m_waveHandle, &m_Buffers[m_ActiveBuffer], sizeof(WAVEHDR));
                    m_ActiveBuffer++;
					m_ActiveBuffer &= (m_NumBuffers-1);
				}
				else
				{
					m_Playing = false;
                    hasPlayed = true;
                    this->audioCondition.wait(lock);
				}
			}
		}
    }
	return(0);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////
//
//	Initialization and termination
//
//
//

bool WaveOut::Initialize(void)
{
	m_Playing = false;
	m_ActiveBuffer	= 0;
	m_QueuedBuffers	= 0;

    m_bThreadRun = true;

    this->audioThread = new boost::thread(boost::bind(&WaveOut::ThreadProc, this));

	if(!this->audioThread)
		return false;

	return(true);
}

bool WaveOut::Shutdown(void)
{
	Close();

//    boost::mutex::scoped_lock lock(this->audioMutex);

	if(this->audioThread)
	{
		m_bThreadRun = false;

        this->audioCondition.notify_one();
        this->audioThread->join();
        delete this->audioThread;
    }

	return(true);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//		Setup Stuff, can only be called before initialize
//
//

bool WaveOut::SetFormat(unsigned long SampleRate, unsigned long Channels)
{
	if( (SampleRate != m_waveFormatPCMEx.Format.nSamplesPerSec) ||
		(Channels != m_waveFormatPCMEx.Format.nChannels) )
	{
		Shutdown();

		DWORD speakerconfig;

		if(Channels == 1)
		{
			speakerconfig = KSAUDIO_SPEAKER_MONO;
		}
		else if(Channels == 2)
		{
			speakerconfig = KSAUDIO_SPEAKER_STEREO;
		}
		else if(Channels == 4)
		{
			speakerconfig = KSAUDIO_SPEAKER_QUAD;
		}
		else if(Channels == 5)
		{
			speakerconfig = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT  | SPEAKER_BACK_RIGHT);
		}
		else if(Channels == 6)
		{
			speakerconfig = KSAUDIO_SPEAKER_5POINT1;
		}
		else
		{
			speakerconfig = 0;
		}

		m_waveFormatPCMEx.Format.cbSize					= 22;
		m_waveFormatPCMEx.Format.wFormatTag				= WAVE_FORMAT_EXTENSIBLE;
		m_waveFormatPCMEx.Format.nChannels				= (WORD)Channels;
		m_waveFormatPCMEx.Format.nSamplesPerSec			= SampleRate;
		m_waveFormatPCMEx.Format.wBitsPerSample			= 32;
		m_waveFormatPCMEx.Format.nBlockAlign			= (m_waveFormatPCMEx.Format.wBitsPerSample/8) * m_waveFormatPCMEx.Format.nChannels;
		m_waveFormatPCMEx.Format.nAvgBytesPerSec		= ((m_waveFormatPCMEx.Format.wBitsPerSample/8) * m_waveFormatPCMEx.Format.nChannels) * m_waveFormatPCMEx.Format.nSamplesPerSec; //Compute using nBlkAlign * nSamp/Sec

        // clangen: wValidBitsPerSample/wReserved/wSamplesPerBlock are a union,
        // so don't set wReserved or wSamplesPerBlock to 0 after assigning
        // wValidBitsPerSample. (Vista bug)
		m_waveFormatPCMEx.Samples.wValidBitsPerSample	= 32;

		m_waveFormatPCMEx.dwChannelMask					= speakerconfig;
		m_waveFormatPCMEx.SubFormat						= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;

		unsigned long samplesperms = ((unsigned long)((float)m_waveFormatPCMEx.Format.nSamplesPerSec / 1000.0f)) * m_waveFormatPCMEx.Format.nChannels;

        m_Interval			= (this->GetBufferSizeMs() / m_NumBuffers) / 2;
		m_BlockSize			= (this->GetBufferSizeMs() / m_NumBuffers) * samplesperms;	// this should be a 300MS buffer size!
		while(m_BlockSize & m_waveFormatPCMEx.Format.nBlockAlign)
			m_BlockSize++;

		if(!Initialize())
			return false;
	}

	return true;
}

////////////////////////////////////////////////////////////////////////////////////////////
// PLAYBACK CONTROLS
//
//
bool WaveOut::Start(void)
{
	if(!Open())
		return(false);

    boost::mutex::scoped_lock lock(this->audioMutex);

	while(m_QueuedBuffers) // Handles pause/play?
	{
		waveOutWrite(m_waveHandle, &m_Buffers[m_ActiveBuffer], sizeof(WAVEHDR));
		m_ActiveBuffer++;
		m_ActiveBuffer &= (m_NumBuffers-1); // Probably only works if m_Numbuffers is power of 2

		m_QueuedBuffers--;
	}

	m_Playing = true;

    this->audioCondition.notify_one();

	return true;
}

bool WaveOut::Stop(void)
{
    boost::mutex::scoped_lock lock(this->audioMutex);

	m_QueuedBuffers = 0;
	m_Playing = false;

	if(m_waveHandle)
	{
		for(unsigned long buffer=0; buffer<m_NumBuffers; buffer++)
		{
			if(	!(m_Buffers[buffer].dwFlags & WHDR_INQUEUE) )
			{
				m_QueuedBuffers++;
			}
		}
		m_ActiveBuffer-= m_QueuedBuffers;
		m_ActiveBuffer &= (m_NumBuffers-1);
	}

	Close();

	return true;
}

bool WaveOut::Reset(void)
{
//	CAutoLock lock(&m_AudioLock);

	// simmilar to stop, except we dont rewind the stream
	if(m_waveHandle)
	{
		waveOutReset(m_waveHandle);

		m_ActiveBuffer = 0;
		m_dwSamplesOut = 0;

		m_LastPlayedBuffer = 0;

		QueryPerformanceCounter(&m_liLastPerformanceCount);
		return(true);
	}
	return false;
}<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/base/android/webaudio_media_codec_bridge.h"

#include <errno.h>
#include <unistd.h>
#include <vector>

#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "jni/WebAudioMediaCodecBridge_jni.h"

using base::android::AttachCurrentThread;

namespace media {

void WebAudioMediaCodecBridge::RunWebAudioMediaCodec(
    base::SharedMemoryHandle encoded_audio_handle,
    base::FileDescriptor pcm_output) {
  WebAudioMediaCodecBridge bridge(encoded_audio_handle, pcm_output);

  bridge.DecodeInMemoryAudioFile();
}

WebAudioMediaCodecBridge::WebAudioMediaCodecBridge(
    base::SharedMemoryHandle encoded_audio_handle,
    base::FileDescriptor pcm_output)
    : encoded_audio_handle_(encoded_audio_handle.fd),
      pcm_output_(pcm_output.fd) {
  DVLOG(1) << "WebAudioMediaCodecBridge start **********************"
           << "input fd = " << encoded_audio_handle_
           << " output fd = " << pcm_output.fd;
}

WebAudioMediaCodecBridge::~WebAudioMediaCodecBridge() {
  if (close(pcm_output_)) {
    DVLOG(1) << "Couldn't close output fd " << pcm_output_
             << ": " << strerror(errno);
  }

  if (close(encoded_audio_handle_)) {
    DVLOG(1) << "Couldn't close shared mem fd " << encoded_audio_handle_
             << ": " << strerror(errno);
  }
}

bool WebAudioMediaCodecBridge::DecodeInMemoryAudioFile() {
  // Process the encoded data from |encoded_data_handle_|.

  JNIEnv* env = AttachCurrentThread();
  CHECK(env);
  jboolean decoded = Java_WebAudioMediaCodecBridge_decodeAudioFile(
      env,
      base::android::GetApplicationContext(),
      reinterpret_cast<intptr_t>(this),
      encoded_audio_handle_);

  DVLOG(1) << "decoded = " << decoded;
  return decoded;
}

void WebAudioMediaCodecBridge::InitializeDestination(
    JNIEnv* env,
    jobject /*java object*/,
    jint channel_count,
    jint sample_rate,
    jlong duration_microsec,
    jboolean is_vorbis) {
  // Send information about this audio file: number of channels,
  // sample rate (Hz), number of frames, a flag indicating whether
  // this file is an audio/vorbis file.  Information is sent as a set of
  // 4 longs. This must be coordinated with DecodeAudioFileData!

  unsigned long info[4] = {channel_count,
                           sample_rate,
                           // The number of frames is the duration of the file
                           // (in microseconds) times the sample rate.
                           0.5 + (duration_microsec * 0.000001 * sample_rate),
                           is_vorbis ? 1 : 0};

  DVLOG(1) << "InitializeDestination:"
           << "  channel count = " << channel_count
           << "  rate = " << sample_rate
           << "  duration = " << duration_microsec << " microsec"
           << "  vorbis = " << (is_vorbis ? "yes" : "no");

  HANDLE_EINTR(write(pcm_output_, info, sizeof(info)));
}

void WebAudioMediaCodecBridge::OnChunkDecoded(
    JNIEnv* env,
    jobject /*java object*/,
    jobject buf,
    jint buf_size) {

  if (buf_size <= 0 || !buf)
    return;

  int8_t* buffer =
      static_cast<int8_t*>(env->GetDirectBufferAddress(buf));

  size_t count = static_cast<size_t>(buf_size);

  // Write out the data to the pipe in small chunks if necessary.
  while (count > 0) {
    int bytes_to_write = (count >= PIPE_BUF) ? PIPE_BUF : count;
    ssize_t bytes_written = HANDLE_EINTR(write(pcm_output_,
                                               buffer,
                                               bytes_to_write));
    if (bytes_written == -1)
      break;
    count -= bytes_written;
    buffer += bytes_written;
  }
}

bool WebAudioMediaCodecBridge::RegisterWebAudioMediaCodecBridge(JNIEnv* env) {
  return RegisterNativesImpl(env);
}

} // namespace
<commit_msg>[Android] Fix downstream WebView build.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/base/android/webaudio_media_codec_bridge.h"

#include <errno.h>
#include <unistd.h>
#include <vector>

#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "jni/WebAudioMediaCodecBridge_jni.h"

using base::android::AttachCurrentThread;

namespace media {

void WebAudioMediaCodecBridge::RunWebAudioMediaCodec(
    base::SharedMemoryHandle encoded_audio_handle,
    base::FileDescriptor pcm_output) {
  WebAudioMediaCodecBridge bridge(encoded_audio_handle, pcm_output);

  bridge.DecodeInMemoryAudioFile();
}

WebAudioMediaCodecBridge::WebAudioMediaCodecBridge(
    base::SharedMemoryHandle encoded_audio_handle,
    base::FileDescriptor pcm_output)
    : encoded_audio_handle_(encoded_audio_handle.fd),
      pcm_output_(pcm_output.fd) {
  DVLOG(1) << "WebAudioMediaCodecBridge start **********************"
           << "input fd = " << encoded_audio_handle_
           << " output fd = " << pcm_output.fd;
}

WebAudioMediaCodecBridge::~WebAudioMediaCodecBridge() {
  if (close(pcm_output_)) {
    DVLOG(1) << "Couldn't close output fd " << pcm_output_
             << ": " << strerror(errno);
  }

  if (close(encoded_audio_handle_)) {
    DVLOG(1) << "Couldn't close shared mem fd " << encoded_audio_handle_
             << ": " << strerror(errno);
  }
}

bool WebAudioMediaCodecBridge::DecodeInMemoryAudioFile() {
  // Process the encoded data from |encoded_data_handle_|.

  JNIEnv* env = AttachCurrentThread();
  CHECK(env);
  jboolean decoded = Java_WebAudioMediaCodecBridge_decodeAudioFile(
      env,
      base::android::GetApplicationContext(),
      reinterpret_cast<intptr_t>(this),
      encoded_audio_handle_);

  DVLOG(1) << "decoded = " << decoded;
  return decoded;
}

void WebAudioMediaCodecBridge::InitializeDestination(
    JNIEnv* env,
    jobject /*java object*/,
    jint channel_count,
    jint sample_rate,
    jlong duration_microsec,
    jboolean is_vorbis) {
  // Send information about this audio file: number of channels,
  // sample rate (Hz), number of frames, a flag indicating whether
  // this file is an audio/vorbis file.  Information is sent as a set of
  // 4 longs. This must be coordinated with DecodeAudioFileData!

  unsigned long info[4] = {static_cast<unsigned long>(channel_count),
                           static_cast<unsigned long>(sample_rate),
                           // The number of frames is the duration of the file
                           // (in microseconds) times the sample rate.
                           static_cast<unsigned long>(
                               0.5 + (duration_microsec * 0.000001 *
                                      sample_rate)),
                           is_vorbis ? 1ul : 0ul};

  DVLOG(1) << "InitializeDestination:"
           << "  channel count = " << channel_count
           << "  rate = " << sample_rate
           << "  duration = " << duration_microsec << " microsec"
           << "  vorbis = " << (is_vorbis ? "yes" : "no");

  HANDLE_EINTR(write(pcm_output_, info, sizeof(info)));
}

void WebAudioMediaCodecBridge::OnChunkDecoded(
    JNIEnv* env,
    jobject /*java object*/,
    jobject buf,
    jint buf_size) {

  if (buf_size <= 0 || !buf)
    return;

  int8_t* buffer =
      static_cast<int8_t*>(env->GetDirectBufferAddress(buf));

  size_t count = static_cast<size_t>(buf_size);

  // Write out the data to the pipe in small chunks if necessary.
  while (count > 0) {
    int bytes_to_write = (count >= PIPE_BUF) ? PIPE_BUF : count;
    ssize_t bytes_written = HANDLE_EINTR(write(pcm_output_,
                                               buffer,
                                               bytes_to_write));
    if (bytes_written == -1)
      break;
    count -= bytes_written;
    buffer += bytes_written;
  }
}

bool WebAudioMediaCodecBridge::RegisterWebAudioMediaCodecBridge(JNIEnv* env) {
  return RegisterNativesImpl(env);
}

} // namespace
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#ifndef DELETER_HH_
#define DELETER_HH_

#include <memory>
#include <cstdlib>
#include <assert.h>
#include <type_traits>

class deleter final {
public:
    struct impl;
    struct raw_object_tag {};
private:
    // if bit 0 set, point to object to be freed directly.
    impl* _impl = nullptr;
public:
    deleter() = default;
    deleter(const deleter&) = delete;
    deleter(deleter&& x) : _impl(x._impl) { x._impl = nullptr; }
    explicit deleter(impl* i) : _impl(i) {}
    deleter(raw_object_tag tag, void* object)
        : _impl(from_raw_object(object)) {}
    ~deleter();
    deleter& operator=(deleter&& x);
    deleter& operator=(deleter&) = delete;
    impl& operator*() const { return *_impl; }
    impl* operator->() const { return _impl; }
    impl* get() const { return _impl; }
    void unshare();
    deleter share();
    explicit operator bool() const { return bool(_impl); }
    void reset(impl* i) {
        this->~deleter();
        new (this) deleter(i);
    }
    void append(deleter d);
private:
    static bool is_raw_object(impl* i) {
        auto x = reinterpret_cast<uintptr_t>(i);
        return x & 1;
    }
    bool is_raw_object() const {
        return is_raw_object(_impl);
    }
    static void* to_raw_object(impl* i) {
        auto x = reinterpret_cast<uintptr_t>(i);
        return reinterpret_cast<void*>(x & ~uintptr_t(1));
    }
    void* to_raw_object() const {
        return to_raw_object(_impl);
    }
    impl* from_raw_object(void* object) {
        auto x = reinterpret_cast<uintptr_t>(object);
        return reinterpret_cast<impl*>(x | 1);
    }
};

struct deleter::impl {
    unsigned refs = 1;
    deleter next;
    impl(deleter next) : next(std::move(next)) {}
    virtual ~impl() {}
};

inline
deleter::~deleter() {
    if (is_raw_object()) {
        std::free(to_raw_object());
        return;
    }
    if (_impl && --_impl->refs == 0) {
        delete _impl;
    }
}

inline
deleter& deleter::operator=(deleter&& x) {
    if (this != &x) {
        this->~deleter();
        new (this) deleter(std::move(x));
    }
    return *this;
}

template <typename Deleter>
struct lambda_deleter_impl final : deleter::impl {
    Deleter del;
    lambda_deleter_impl(deleter next, Deleter&& del)
        : impl(std::move(next)), del(std::move(del)) {}
    virtual ~lambda_deleter_impl() override { del(); }
};

template <typename Object>
struct object_deleter_impl final : deleter::impl {
    Object obj;
    object_deleter_impl(deleter next, Object&& obj)
        : impl(std::move(next)), obj(std::move(obj)) {}
};

template <typename Object>
object_deleter_impl<Object>* make_object_deleter_impl(deleter next, Object obj) {
    return new object_deleter_impl<Object>(std::move(next), std::move(obj));
}

template <typename Deleter>
deleter
make_deleter(deleter next, Deleter d) {
    return deleter(new lambda_deleter_impl<Deleter>(std::move(next), std::move(d)));
}

template <typename Deleter>
deleter
make_deleter(Deleter d) {
    return make_deleter(deleter(), std::move(d));
}

struct free_deleter_impl final : deleter::impl {
    void* obj;
    free_deleter_impl(void* obj) : impl(deleter()), obj(obj) {}
    virtual ~free_deleter_impl() override { std::free(obj); }
};

inline
deleter
deleter::share() {
    if (!_impl) {
        return deleter();
    }
    if (is_raw_object()) {
        _impl = new free_deleter_impl(to_raw_object());
    }
    ++_impl->refs;
    return deleter(_impl);
}

// Appends 'd' to the chain of deleters. Avoids allocation if possible. For
// performance reasons the current chain should be shorter and 'd' should be
// longer.
inline
void deleter::append(deleter d) {
    if (!d._impl) {
        return;
    }
    impl* next_impl = _impl;
    deleter* next_d = this;
    while (next_impl) {
        assert(next_impl != d._impl);
        if (is_raw_object(next_impl)) {
            next_d->_impl = next_impl = new free_deleter_impl(to_raw_object(next_impl));
        }
        if (next_impl->refs != 1) {
            next_d->_impl = next_impl = make_object_deleter_impl(std::move(next_impl->next), deleter(next_impl));
        }
        next_d = &next_impl->next;
        next_impl = next_d->_impl;
    }
    next_d->_impl = d._impl;
    d._impl = nullptr;
}

inline
deleter
make_free_deleter(void* obj) {
    if (!obj) {
        return deleter();
    }
    return deleter(deleter::raw_object_tag(), obj);
}

inline
deleter
make_free_deleter(deleter next, void* obj) {
    return make_deleter(std::move(next), [obj] () mutable { std::free(obj); });
}

#endif /* DELETER_HH_ */
<commit_msg>deleter: remove bad/unused interfaces<commit_after>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#ifndef DELETER_HH_
#define DELETER_HH_

#include <memory>
#include <cstdlib>
#include <assert.h>
#include <type_traits>

class deleter final {
public:
    struct impl;
    struct raw_object_tag {};
private:
    // if bit 0 set, point to object to be freed directly.
    impl* _impl = nullptr;
public:
    deleter() = default;
    deleter(const deleter&) = delete;
    deleter(deleter&& x) : _impl(x._impl) { x._impl = nullptr; }
    explicit deleter(impl* i) : _impl(i) {}
    deleter(raw_object_tag tag, void* object)
        : _impl(from_raw_object(object)) {}
    ~deleter();
    deleter& operator=(deleter&& x);
    deleter& operator=(deleter&) = delete;
    deleter share();
    explicit operator bool() const { return bool(_impl); }
    void reset(impl* i) {
        this->~deleter();
        new (this) deleter(i);
    }
    void append(deleter d);
private:
    static bool is_raw_object(impl* i) {
        auto x = reinterpret_cast<uintptr_t>(i);
        return x & 1;
    }
    bool is_raw_object() const {
        return is_raw_object(_impl);
    }
    static void* to_raw_object(impl* i) {
        auto x = reinterpret_cast<uintptr_t>(i);
        return reinterpret_cast<void*>(x & ~uintptr_t(1));
    }
    void* to_raw_object() const {
        return to_raw_object(_impl);
    }
    impl* from_raw_object(void* object) {
        auto x = reinterpret_cast<uintptr_t>(object);
        return reinterpret_cast<impl*>(x | 1);
    }
};

struct deleter::impl {
    unsigned refs = 1;
    deleter next;
    impl(deleter next) : next(std::move(next)) {}
    virtual ~impl() {}
};

inline
deleter::~deleter() {
    if (is_raw_object()) {
        std::free(to_raw_object());
        return;
    }
    if (_impl && --_impl->refs == 0) {
        delete _impl;
    }
}

inline
deleter& deleter::operator=(deleter&& x) {
    if (this != &x) {
        this->~deleter();
        new (this) deleter(std::move(x));
    }
    return *this;
}

template <typename Deleter>
struct lambda_deleter_impl final : deleter::impl {
    Deleter del;
    lambda_deleter_impl(deleter next, Deleter&& del)
        : impl(std::move(next)), del(std::move(del)) {}
    virtual ~lambda_deleter_impl() override { del(); }
};

template <typename Object>
struct object_deleter_impl final : deleter::impl {
    Object obj;
    object_deleter_impl(deleter next, Object&& obj)
        : impl(std::move(next)), obj(std::move(obj)) {}
};

template <typename Object>
object_deleter_impl<Object>* make_object_deleter_impl(deleter next, Object obj) {
    return new object_deleter_impl<Object>(std::move(next), std::move(obj));
}

template <typename Deleter>
deleter
make_deleter(deleter next, Deleter d) {
    return deleter(new lambda_deleter_impl<Deleter>(std::move(next), std::move(d)));
}

template <typename Deleter>
deleter
make_deleter(Deleter d) {
    return make_deleter(deleter(), std::move(d));
}

struct free_deleter_impl final : deleter::impl {
    void* obj;
    free_deleter_impl(void* obj) : impl(deleter()), obj(obj) {}
    virtual ~free_deleter_impl() override { std::free(obj); }
};

inline
deleter
deleter::share() {
    if (!_impl) {
        return deleter();
    }
    if (is_raw_object()) {
        _impl = new free_deleter_impl(to_raw_object());
    }
    ++_impl->refs;
    return deleter(_impl);
}

// Appends 'd' to the chain of deleters. Avoids allocation if possible. For
// performance reasons the current chain should be shorter and 'd' should be
// longer.
inline
void deleter::append(deleter d) {
    if (!d._impl) {
        return;
    }
    impl* next_impl = _impl;
    deleter* next_d = this;
    while (next_impl) {
        assert(next_impl != d._impl);
        if (is_raw_object(next_impl)) {
            next_d->_impl = next_impl = new free_deleter_impl(to_raw_object(next_impl));
        }
        if (next_impl->refs != 1) {
            next_d->_impl = next_impl = make_object_deleter_impl(std::move(next_impl->next), deleter(next_impl));
        }
        next_d = &next_impl->next;
        next_impl = next_d->_impl;
    }
    next_d->_impl = d._impl;
    d._impl = nullptr;
}

inline
deleter
make_free_deleter(void* obj) {
    if (!obj) {
        return deleter();
    }
    return deleter(deleter::raw_object_tag(), obj);
}

inline
deleter
make_free_deleter(deleter next, void* obj) {
    return make_deleter(std::move(next), [obj] () mutable { std::free(obj); });
}

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


<commit_before>// csastil_includeorder.cpp                                           -*-C++-*-
// ----------------------------------------------------------------------------
// Copyright 2012 Dietmar Kuehl http://www.dietmar-kuehl.de
// Distributed under the Boost Software License, Version 1.0. (See file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).
// ----------------------------------------------------------------------------

#include <csabase_analyser.h>
#include <csabase_location.h>
#include <csabase_ppobserver.h>
#include <csabase_registercheck.h>
#include <csabase_util.h>
#include <cctype>
#include <algorithm>
#include <functional>
#include <utility>
#include <vector>

namespace CB = bde_verify::csabase;

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

static std::string const check_name("include-order");

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

namespace
{
    struct include_order
    {
        typedef std::vector<std::pair<std::string, clang::SourceLocation> > headers_t;
        headers_t d_header;
        headers_t d_source;
        void add_include(bool                         in_header,
                         std::string                  header,
                         clang::SourceLocation const& where)
        {
            std::string::size_type pos(header.find('.'));
            if (pos != header.npos) {
                header = header.substr(0u, pos);
            }

            headers_t& headers(in_header? d_header: d_source);
            if (headers.empty() || headers.back().first != header) {
                headers.push_back(std::make_pair(header, where));
            }
        }
    };
}

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

namespace
{
    struct has_prefix
    {
        typedef std::pair<std::string, clang::SourceLocation> const& argument_type;
        has_prefix(std::string const& prefix)
            : d_prefix(prefix)
        {
        }
        bool operator()(argument_type entry) const
        {
            return entry.first.find(d_prefix) == 0;
        }
        std::string d_prefix;
    };
}

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

static bool
first_is_greater(std::pair<std::string, clang::SourceLocation> const& entry0,
                 std::pair<std::string, clang::SourceLocation> const& entry1)
{
    return entry1.first < entry0.first;
}

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

static bool
is_component(std::pair<std::string, clang::SourceLocation> const& entry)
{
    std::string const&     header(entry.first);
    std::string::size_type start(header.find("a_") == 0 || header.find("e_") == 0? 2: 0);
    std::string::size_type under(header.find('_', 0));
    return under != header.npos && 4 < under - start && under - start < 8;
}

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

static void
check_order(CB::Analyser*                              analyser,
            std::string const&                         message,
            include_order::headers_t::const_iterator it,
            include_order::headers_t::const_iterator end)
{
    for (; end != (it = std::adjacent_find(it, end, &first_is_greater));
         ++it) {
        analyser->report(it[1].second, check_name, "SHO01",
                         "%0 header out of order")
            << message;
    }
}

static void
check_order(CB::Analyser*                              analyser,
            std::string const&                         message,
            include_order::headers_t::const_iterator it,
            include_order::headers_t::const_iterator section_end,
            include_order::headers_t::const_iterator end)
{
    check_order(analyser, message, it, section_end);
    for (it = section_end;
         end != (it = std::find_if(it, end, has_prefix(analyser->package() + "_")));
         ++it) {
        analyser->report(it->second, check_name, "SHO02",
                         "%0 header coming late")
            << message;
    }
}

static clang::SourceLocation const*
check_order(CB::Analyser*                   analyser,
            include_order::headers_t const& headers,
            bool                            header)
{
    clang::SourceLocation const* bdes_ident_location(0);
    if (headers.empty()) {
        analyser->report(clang::SourceLocation(), check_name, "SHO03",
                         header
                         ? "Header without include guard included"
                         : "Source without component include");
        return bdes_ident_location;
    }
    include_order::headers_t::const_iterator it(headers.begin());
    if (it->first != analyser->component() || it++ == headers.end()) {
        analyser->report(headers[0].second, check_name, "SHO04",
                         header
                         ? "Header without or with wrong include guard"
                         : "Source doesn't include component header first");
    }
    std::string ident =
        analyser->group() == "bsl" ? "bsls_ident" : "bdes_ident";
    if (analyser->component() == ident ||
        (analyser->is_test_driver() && !header)) {
        if (it != headers.end()) {
            if (it->first == "bdes_ident") {
                bdes_ident_location = &it->second;
            }
            if (it->first == ident) {
                ++it;
            }
        }
    }
    else if (it == headers.end() || it->first != ident) {
        analyser->report((it == headers.end() ? it - 1: it)->second,
                         check_name, "SHO06",
                         "Missing include for %0.h")
            << ident;
    }
    else {
        if (it->first == "bdes_ident") {
            bdes_ident_location = &it->second;
        }
        ++it;
    }

    std::string version = analyser->group() + "scm_version";
    if (   analyser->component() != version
        && header
        && (it == headers.end()
            || it->first != version
            || it++ == headers.end())) {
        analyser->report((it == headers.end() ? it - 1 : it)->second,
                         check_name, "SHO07",
                         "Missing include for %0.h")
            << version;
    }

    include_order::headers_t::const_iterator end
          = std::find_if(it, headers.end(),
                         std::not1(std::ptr_fun(&is_component)));
    include_order::headers_t::const_iterator package_end
          = std::find_if(it, end, std::not1(has_prefix(analyser->package() + "_")));
    check_order(analyser, "Package", it, package_end, end);
    include_order::headers_t::const_iterator group_end
          = std::find_if(it, end, std::not1(has_prefix(analyser->group())));
    check_order(analyser, "Group", package_end, group_end, end);
    check_order(analyser, "Component", group_end, end);

    return bdes_ident_location;
}

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

static inline bool
is_space(unsigned char c)
{
    return std::isspace(c);
}

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

namespace
{
    std::string const prefix0("included_");
    std::string const prefix1("!defined(included_");
    std::string const prefix2("!definedincluded_");

    struct binder
    {
        binder(bde_verify::csabase::Analyser* analyser)
            : d_analyser(analyser)
        {
        }

        void operator()(clang::SourceLocation,
                        clang::SourceRange range) const // onIf
        {
            if (!d_analyser->is_component(range.getBegin())) {
                return;
            }
            include_order& data(d_analyser->attachment<include_order>());
            char const* begin(d_analyser->manager().getCharacterData(range.getBegin()));
            char const* end(d_analyser->manager().getCharacterData(range.getEnd()));
            std::string value(begin, end);
            value.erase(std::remove_if(value.begin(), value.end(),
                                       &is_space), value.end());
            value = bde_verify::csabase::to_lower(value);
            if (value.find(prefix1) == 0 && value[value.size() - 1] == ')') {
                data.add_include(d_analyser->is_component_header(range.getBegin()),
                                 value.substr(prefix1.size(), value.size() - prefix1.size() - 1),
                                 range.getBegin());
            }
            else if (value.find(prefix2) == 0) {
                data.add_include(d_analyser->is_component_header(range.getBegin()),
                                 value.substr(prefix2.size()),
                                 range.getBegin());
            }
        }
        void operator()(clang::SourceLocation where,
                        clang::Token const& token) const // onIfndef
        {
            if (!d_analyser->is_component(token.getLocation())) {
                return;
            }

            include_order& data(d_analyser->attachment<include_order>());
            if (clang::IdentifierInfo const* id = token.getIdentifierInfo())
            {
                std::string value(id->getNameStart());
                value = bde_verify::csabase::to_lower(value);
                if (value.find(prefix0) == 0) {
                    data.add_include(d_analyser->is_component_header(token.getLocation()),
                                     value.substr(prefix0.size()),
                                     token.getLocation());
                }
            }
        }
        void operator()(clang::SourceLocation where,
                        bool,
                        std::string const& name)
        {
            if (d_analyser->is_component(where)) {
                include_order& data(d_analyser->attachment<include_order>());
                bool in_header(d_analyser->is_component_header(where));
                data.add_include(in_header, name, where);
            }
        }
        void operator()()  // translation unit done
        {
            include_order& data(d_analyser->attachment<include_order>());
            clang::SourceLocation const* header_bdes_ident(
                check_order(d_analyser, data.d_header, true));
            clang::SourceLocation const* source_bdes_ident(
                check_order(d_analyser, data.d_source, false));
            if ((header_bdes_ident == 0) != (source_bdes_ident == 0)) {
                d_analyser->report(*(header_bdes_ident ? header_bdes_ident :
                                                         source_bdes_ident),
                                   check_name, "SHO08",
                                   "bdes_ident.h is used inconsistently with "
                                   "the %0")
                    << (header_bdes_ident ? "source" : "header");
            }
        }

        bde_verify::csabase::Analyser* d_analyser;
    };
}

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

static void
subscribe(bde_verify::csabase::Analyser& analyser, bde_verify::csabase::Visitor&, bde_verify::csabase::PPObserver& observer)
{
    analyser.onTranslationUnitDone += binder(&analyser);
    observer.onInclude             += binder(&analyser);
    observer.onIfndef              += binder(&analyser);
    observer.onIf                  += binder(&analyser);
}

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

static bde_verify::csabase::RegisterCheck register_observer(check_name, &subscribe);
<commit_msg>Treat "bdl" like "bsl".<commit_after>// csastil_includeorder.cpp                                           -*-C++-*-
// ----------------------------------------------------------------------------
// Copyright 2012 Dietmar Kuehl http://www.dietmar-kuehl.de
// Distributed under the Boost Software License, Version 1.0. (See file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).
// ----------------------------------------------------------------------------

#include <csabase_analyser.h>
#include <csabase_location.h>
#include <csabase_ppobserver.h>
#include <csabase_registercheck.h>
#include <csabase_util.h>
#include <cctype>
#include <algorithm>
#include <functional>
#include <utility>
#include <vector>

namespace CB = bde_verify::csabase;

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

static std::string const check_name("include-order");

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

namespace
{
    struct include_order
    {
        typedef std::vector<std::pair<std::string, clang::SourceLocation> > headers_t;
        headers_t d_header;
        headers_t d_source;
        void add_include(bool                         in_header,
                         std::string                  header,
                         clang::SourceLocation const& where)
        {
            std::string::size_type pos(header.find('.'));
            if (pos != header.npos) {
                header = header.substr(0u, pos);
            }

            headers_t& headers(in_header? d_header: d_source);
            if (headers.empty() || headers.back().first != header) {
                headers.push_back(std::make_pair(header, where));
            }
        }
    };
}

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

namespace
{
    struct has_prefix
    {
        typedef std::pair<std::string, clang::SourceLocation> const& argument_type;
        has_prefix(std::string const& prefix)
            : d_prefix(prefix)
        {
        }
        bool operator()(argument_type entry) const
        {
            return entry.first.find(d_prefix) == 0;
        }
        std::string d_prefix;
    };
}

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

static bool
first_is_greater(std::pair<std::string, clang::SourceLocation> const& entry0,
                 std::pair<std::string, clang::SourceLocation> const& entry1)
{
    return entry1.first < entry0.first;
}

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

static bool
is_component(std::pair<std::string, clang::SourceLocation> const& entry)
{
    std::string const&     header(entry.first);
    std::string::size_type start(header.find("a_") == 0 || header.find("e_") == 0? 2: 0);
    std::string::size_type under(header.find('_', 0));
    return under != header.npos && 4 < under - start && under - start < 8;
}

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

static void
check_order(CB::Analyser*                              analyser,
            std::string const&                         message,
            include_order::headers_t::const_iterator it,
            include_order::headers_t::const_iterator end)
{
    for (; end != (it = std::adjacent_find(it, end, &first_is_greater));
         ++it) {
        analyser->report(it[1].second, check_name, "SHO01",
                         "%0 header out of order")
            << message;
    }
}

static void
check_order(CB::Analyser*                              analyser,
            std::string const&                         message,
            include_order::headers_t::const_iterator it,
            include_order::headers_t::const_iterator section_end,
            include_order::headers_t::const_iterator end)
{
    check_order(analyser, message, it, section_end);
    for (it = section_end;
         end != (it = std::find_if(it, end, has_prefix(analyser->package() + "_")));
         ++it) {
        analyser->report(it->second, check_name, "SHO02",
                         "%0 header coming late")
            << message;
    }
}

static clang::SourceLocation const*
check_order(CB::Analyser*                   analyser,
            include_order::headers_t const& headers,
            bool                            header)
{
    clang::SourceLocation const* bdes_ident_location(0);
    if (headers.empty()) {
        analyser->report(clang::SourceLocation(), check_name, "SHO03",
                         header
                         ? "Header without include guard included"
                         : "Source without component include");
        return bdes_ident_location;
    }
    include_order::headers_t::const_iterator it(headers.begin());
    if (it->first != analyser->component() || it++ == headers.end()) {
        analyser->report(headers[0].second, check_name, "SHO04",
                         header
                         ? "Header without or with wrong include guard"
                         : "Source doesn't include component header first");
    }
    std::string ident =
        analyser->group() == "bsl" || analyser->group() == "bdl" ?
            "bsls_ident" : "bdes_ident";
    if (analyser->component() == ident ||
        (analyser->is_test_driver() && !header)) {
        if (it != headers.end()) {
            if (it->first == "bdes_ident") {
                bdes_ident_location = &it->second;
            }
            if (it->first == ident) {
                ++it;
            }
        }
    }
    else if (it == headers.end() || it->first != ident) {
        analyser->report((it == headers.end() ? it - 1: it)->second,
                         check_name, "SHO06",
                         "Missing include for %0.h")
            << ident;
    }
    else {
        if (it->first == "bdes_ident") {
            bdes_ident_location = &it->second;
        }
        ++it;
    }

    std::string version = analyser->group() + "scm_version";
    if (   analyser->component() != version
        && header
        && (it == headers.end()
            || it->first != version
            || it++ == headers.end())) {
        analyser->report((it == headers.end() ? it - 1 : it)->second,
                         check_name, "SHO07",
                         "Missing include for %0.h")
            << version;
    }

    include_order::headers_t::const_iterator end
          = std::find_if(it, headers.end(),
                         std::not1(std::ptr_fun(&is_component)));
    include_order::headers_t::const_iterator package_end
          = std::find_if(it, end, std::not1(has_prefix(analyser->package() + "_")));
    check_order(analyser, "Package", it, package_end, end);
    include_order::headers_t::const_iterator group_end
          = std::find_if(it, end, std::not1(has_prefix(analyser->group())));
    check_order(analyser, "Group", package_end, group_end, end);
    check_order(analyser, "Component", group_end, end);

    return bdes_ident_location;
}

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

static inline bool
is_space(unsigned char c)
{
    return std::isspace(c);
}

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

namespace
{
    std::string const prefix0("included_");
    std::string const prefix1("!defined(included_");
    std::string const prefix2("!definedincluded_");

    struct binder
    {
        binder(bde_verify::csabase::Analyser* analyser)
            : d_analyser(analyser)
        {
        }

        void operator()(clang::SourceLocation,
                        clang::SourceRange range) const // onIf
        {
            if (!d_analyser->is_component(range.getBegin())) {
                return;
            }
            include_order& data(d_analyser->attachment<include_order>());
            char const* begin(d_analyser->manager().getCharacterData(range.getBegin()));
            char const* end(d_analyser->manager().getCharacterData(range.getEnd()));
            std::string value(begin, end);
            value.erase(std::remove_if(value.begin(), value.end(),
                                       &is_space), value.end());
            value = bde_verify::csabase::to_lower(value);
            if (value.find(prefix1) == 0 && value[value.size() - 1] == ')') {
                data.add_include(d_analyser->is_component_header(range.getBegin()),
                                 value.substr(prefix1.size(), value.size() - prefix1.size() - 1),
                                 range.getBegin());
            }
            else if (value.find(prefix2) == 0) {
                data.add_include(d_analyser->is_component_header(range.getBegin()),
                                 value.substr(prefix2.size()),
                                 range.getBegin());
            }
        }
        void operator()(clang::SourceLocation where,
                        clang::Token const& token) const // onIfndef
        {
            if (!d_analyser->is_component(token.getLocation())) {
                return;
            }

            include_order& data(d_analyser->attachment<include_order>());
            if (clang::IdentifierInfo const* id = token.getIdentifierInfo())
            {
                std::string value(id->getNameStart());
                value = bde_verify::csabase::to_lower(value);
                if (value.find(prefix0) == 0) {
                    data.add_include(d_analyser->is_component_header(token.getLocation()),
                                     value.substr(prefix0.size()),
                                     token.getLocation());
                }
            }
        }
        void operator()(clang::SourceLocation where,
                        bool,
                        std::string const& name)
        {
            if (d_analyser->is_component(where)) {
                include_order& data(d_analyser->attachment<include_order>());
                bool in_header(d_analyser->is_component_header(where));
                data.add_include(in_header, name, where);
            }
        }
        void operator()()  // translation unit done
        {
            include_order& data(d_analyser->attachment<include_order>());
            clang::SourceLocation const* header_bdes_ident(
                check_order(d_analyser, data.d_header, true));
            clang::SourceLocation const* source_bdes_ident(
                check_order(d_analyser, data.d_source, false));
            if ((header_bdes_ident == 0) != (source_bdes_ident == 0)) {
                d_analyser->report(*(header_bdes_ident ? header_bdes_ident :
                                                         source_bdes_ident),
                                   check_name, "SHO08",
                                   "bdes_ident.h is used inconsistently with "
                                   "the %0")
                    << (header_bdes_ident ? "source" : "header");
            }
        }

        bde_verify::csabase::Analyser* d_analyser;
    };
}

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

static void
subscribe(bde_verify::csabase::Analyser& analyser, bde_verify::csabase::Visitor&, bde_verify::csabase::PPObserver& observer)
{
    analyser.onTranslationUnitDone += binder(&analyser);
    observer.onInclude             += binder(&analyser);
    observer.onIfndef              += binder(&analyser);
    observer.onIf                  += binder(&analyser);
}

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

static bde_verify::csabase::RegisterCheck register_observer(check_name, &subscribe);
<|endoftext|>


<commit_before>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2006 Refractions Research Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 *
 * Last port: operation/linemerge/LineSequencer.java rev. 1.5 (JTS-1.7)
 *
 **********************************************************************/

#include <geos/operation/linemerge/LineSequencer.h>
#include <geos/operation/linemerge/LineMergeEdge.h>
#include <geos/geom/Geometry.h>
#include <geos/geom/GeometryFactory.h>
#include <geos/geom/MultiLineString.h>
#include <geos/geom/Coordinate.h>
#include <geos/geom/CoordinateSequence.h>
#include <geos/geom/LineString.h>
#include <geos/planargraph/Node.h>
#include <geos/planargraph/DirectedEdge.h>
#include <geos/planargraph/Subgraph.h>
#include <geos/planargraph/algorithm/ConnectedSubgraphFinder.h>

#include <cassert>
#include <limits>
#include <vector>

using namespace std;
//using namespace geos::planargraph;
using namespace geos::geom;
//using namespace geos::planargraph::algorithm;

namespace geos {
namespace operation { // geos.operation
namespace linemerge { // geos.operation.linemerge

/* static */
bool
LineSequencer::isSequenced(const Geometry* geom)
{
	const MultiLineString *mls;

	if ( ! (mls=dynamic_cast<const MultiLineString *>(geom)) )
	{
		return true;
	}

	// the nodes in all subgraphs which have been completely scanned
	Coordinate::ConstSet prevSubgraphNodes;
	Coordinate::ConstVect currNodes;

	const Coordinate* lastNode = NULL;

	for (unsigned int i=0, n=mls->getNumGeometries(); i<n; ++i)
	{
		assert(dynamic_cast<const LineString*>(mls->getGeometryN(i)));

		const LineString& line = \
			static_cast<const LineString&>(*(mls->getGeometryN(i)));

		const Coordinate* startNode = &(line.getCoordinateN(0));
		const Coordinate* endNode = &(line.getCoordinateN(line.getNumPoints() - 1));

		/**
		 * If this linestring is connected to a previous subgraph,
		 * geom is not sequenced
		 */
		if (prevSubgraphNodes.find(startNode) != prevSubgraphNodes.end())
		{
			return false;
		}
		if (prevSubgraphNodes.find(endNode) != prevSubgraphNodes.end())
		{
			return false;
		}

		if (lastNode != NULL)
		{
			if (! startNode->equals2D(*lastNode))
			{
				// start new connected sequence
				prevSubgraphNodes.insert(currNodes.begin(),
						currNodes.end());
				currNodes.clear();
			}
		}
		currNodes.push_back(startNode);
		currNodes.push_back(endNode);
		lastNode = endNode;
	}
	return true;
}

/* private */
bool
LineSequencer::hasSequence(planargraph::Subgraph& graph)
{
	int oddDegreeCount = 0;
	for (planargraph::NodeMap::container::const_iterator
		it=graph.nodeBegin(), endIt=graph.nodeEnd();
		it!=endIt;
		++it)
	{
		planargraph::Node* node = it->second;
		if (node->getDegree() % 2 == 1)
		oddDegreeCount++;
	}
	return oddDegreeCount <= 2;
}

/*private*/
LineSequencer::Sequences*
LineSequencer::findSequences()
{
	Sequences *sequences = new Sequences();
	planargraph::algorithm::ConnectedSubgraphFinder csFinder(graph);
	vector<planargraph::Subgraph*>subgraphs;
	csFinder.getConnectedSubgraphs(subgraphs);
	for (vector<planargraph::Subgraph*>::const_iterator
		it=subgraphs.begin(), endIt=subgraphs.end();
		it!=endIt;
		++it )
	{
		planargraph::Subgraph* subgraph = *it;
		if (hasSequence(*subgraph)) {
			planargraph::DirectedEdge::NonConstList* seq=findSequence(*subgraph);
			sequences->push_back(seq);
		}
		else {
			// if any subgraph cannot be sequenced, abort
			return NULL;
		}
	}
	return sequences;
}

/*private*/
void
LineSequencer::addLine(const LineString *lineString)
{
	if (factory == NULL) {
		factory = lineString->getFactory();
	}
	graph.addEdge(lineString);
	++lineCount;
}

/* private */
void
LineSequencer::computeSequence()
{
	if (isRun) return;
	isRun = true;

	Sequences* sequences(findSequences());
	if (sequences == NULL) return;

	sequencedGeometry = auto_ptr<Geometry>(buildSequencedGeometry(*sequences));
	isSequenceableVar = true;

	// Lines were missing from result
	assert(lineCount == sequencedGeometry->getNumGeometries());

	// Result is not linear
	assert(dynamic_cast<LineString *>(sequencedGeometry.get())
		|| dynamic_cast<MultiLineString *>(sequencedGeometry.get()));
}

/*private*/
Geometry*
LineSequencer::buildSequencedGeometry(const Sequences& sequences)
{
	auto_ptr<Geometry::NonConstVect> lines(new Geometry::NonConstVect);

	for (Sequences::const_iterator
		i1=sequences.begin(), i1End=sequences.end();
		i1 != i1End;
		++i1)
	{
		planargraph::DirectedEdge::NonConstList& seq = *(*i1);
		for(planargraph::DirectedEdge::NonConstList::iterator i2=seq.begin(),
			i2End=seq.end(); i2 != i2End; ++i2)
		{
			const planargraph::DirectedEdge* de = *i2;
			assert(dynamic_cast<LineMergeEdge* >(de->getEdge()));
			LineMergeEdge* e = static_cast<LineMergeEdge* >(de->getEdge());
			const LineString* line = e->getLine();

			// lineToAdd will be a *copy* of input things
			LineString* lineToAdd;

			if ( ! de->getEdgeDirection() && ! line->isClosed() ) {
				lineToAdd = reverse(line);
			} else {
				Geometry* lineClone = line->clone();
				assert(dynamic_cast<LineString *>(lineClone));
				lineToAdd = static_cast<LineString *>(lineClone);
			}

			lines->push_back(lineToAdd);
		}
	}

	if ( lines->size() == 0 ) {
		return NULL;
	} else {
		Geometry::NonConstVect *l=lines.get();
		lines.release();
		return factory->buildGeometry(l);
	}
}

/*static private*/
LineString *
LineSequencer::reverse(const LineString *line)
{
	CoordinateSequence* cs=line->getCoordinates();
	CoordinateSequence::reverse(cs);
	return line->getFactory()->createLineString(cs);
}

/*private static*/
const planargraph::Node*
LineSequencer::findLowestDegreeNode(const planargraph::Subgraph& graph)
{
	int minDegree = numeric_limits<int>::max();
	const planargraph::Node* minDegreeNode = NULL;
	for (planargraph::NodeMap::container::const_iterator
		it = graph.nodeBegin(), itEnd = graph.nodeEnd();
		it != itEnd;
		++it )
	{
		const planargraph::Node* node = (*it).second;
		if (minDegreeNode == NULL || node->getDegree() < minDegree)
		{
			minDegree = node->getDegree();
			minDegreeNode = node;
		}
	}
	return minDegreeNode;
}

/*private static*/
const planargraph::DirectedEdge*
LineSequencer::findUnvisitedBestOrientedDE(const planargraph::Node* node)
{
	using planargraph::DirectedEdge;
	using planargraph::DirectedEdgeStar;

	const DirectedEdge* wellOrientedDE = NULL;
	const DirectedEdge* unvisitedDE = NULL;
	const DirectedEdgeStar* des=node->getOutEdges();
	for (DirectedEdge::NonConstVect::const_iterator i=des->begin(),
		e=des->end();
		i!=e;
		++i)
	{
		planargraph::DirectedEdge* de = *i;
		if (! de->getEdge()->isVisited()) {
			unvisitedDE = de;
			if (de->getEdgeDirection()) wellOrientedDE = de;
		}
	}
	if (wellOrientedDE != NULL)
		return wellOrientedDE;
	return unvisitedDE;
}

/*private*/
void
LineSequencer::addReverseSubpath(const planargraph::DirectedEdge *de,
		planargraph::DirectedEdge::NonConstList& deList,
		planargraph::DirectedEdge::NonConstList::iterator lit,
		bool expectedClosed)
{
	using planargraph::Node;
	using planargraph::DirectedEdge;

	// trace an unvisited path *backwards* from this de
	Node* endNode = de->getToNode();

	Node* fromNode = NULL;
	while (true) {
		deList.insert(lit, de->getSym());
		de->getEdge()->setVisited(true);
		fromNode = de->getFromNode();
		const DirectedEdge* unvisitedOutDE = findUnvisitedBestOrientedDE(fromNode);

		// this must terminate, since we are continually marking edges as visited
		if (unvisitedOutDE == NULL) break;
		de = unvisitedOutDE->getSym();
	}
	if ( expectedClosed ) {
		// the path should end at the toNode of this de,
		// otherwise we have an error
		assert(fromNode == endNode);
	}

}

/*private*/
planargraph::DirectedEdge::NonConstList*
LineSequencer::findSequence(planargraph::Subgraph& graph)
{
	using planargraph::DirectedEdge;
	using planargraph::Node;
	using planargraph::GraphComponent;

	GraphComponent::setVisited(graph.edgeBegin(),
			graph.edgeEnd(), false);

	const Node* startNode = findLowestDegreeNode(graph);

	const DirectedEdge *startDE = *(startNode->getOutEdges()->begin());
	const DirectedEdge *startDESym = startDE->getSym();

	DirectedEdge::NonConstList *seq = new DirectedEdge::NonConstList();

	DirectedEdge::NonConstList::iterator lit=seq->begin();
	addReverseSubpath(startDESym, *seq, lit, false);

	lit=seq->end();
	while (lit != seq->begin()) {
		const DirectedEdge* prev = *(--lit);
		const DirectedEdge* unvisitedOutDE = findUnvisitedBestOrientedDE(prev->getFromNode());
		if (unvisitedOutDE != NULL)
			addReverseSubpath(unvisitedOutDE->getSym(), *seq, lit, true);
	}

	// At this point, we have a valid sequence of graph DirectedEdges,
	// but it is not necessarily appropriately oriented relative to
	// the underlying geometry.
	DirectedEdge::NonConstList* orientedSeq = orient(seq);

	if (orientedSeq != seq) delete seq;

	return orientedSeq;
}

/* private */
planargraph::DirectedEdge::NonConstList*
LineSequencer::orient(planargraph::DirectedEdge::NonConstList* seq)
{
	using namespace geos::planargraph;

	const DirectedEdge* startEdge = seq->front();
	const DirectedEdge* endEdge = seq->back();
	Node* startNode = startEdge->getFromNode();
	Node* endNode = endEdge->getToNode();

	bool flipSeq = false;
	bool hasDegree1Node = \
		startNode->getDegree() == 1 || endNode->getDegree() == 1;

	if (hasDegree1Node)
	{
		bool hasObviousStartNode = false;

		// test end edge before start edge, to make result stable
		// (ie. if both are good starts, pick the actual start
		if (endEdge->getToNode()->getDegree() == 1 &&
				endEdge->getEdgeDirection() == false)
		{
			hasObviousStartNode = true;
			flipSeq = true;
		}
		if (startEdge->getFromNode()->getDegree() == 1 &&
				startEdge->getEdgeDirection() == true)
		{
			hasObviousStartNode = true;
			flipSeq = false;
		}

		// since there is no obvious start node,
		// use any node of degree 1
		if (! hasObviousStartNode)
		{
			// check if the start node should actually
			// be the end node
			if (startEdge->getFromNode()->getDegree() == 1)
				flipSeq = true;
			// if the end node is of degree 1, it is
			// properly the end node
		}

	}

	// if there is no degree 1 node, just use the sequence as is
	// (Could insert heuristic of taking direction of majority of
	// lines as overall direction)

	if (flipSeq)
	{
		return reverse(*seq);
	}
	return seq;
}

/* private */
planargraph::DirectedEdge::NonConstList*
LineSequencer::reverse(planargraph::DirectedEdge::NonConstList& seq)
{
	using namespace geos::planargraph;

	DirectedEdge::NonConstList* newSeq = new DirectedEdge::NonConstList();
	DirectedEdge::NonConstList::iterator it=seq.begin(), itEnd=seq.end();
	for (; it!=itEnd; ++it) {
		const DirectedEdge *de = *it;
		newSeq->push_front(de->getSym());
	}
	return newSeq;
}

} // namespace geos.operation.linemerge
} // namespace geos.operation
} // namespace geos

/**********************************************************************
 * $Log$
 * Revision 1.8  2006/03/24 10:44:07  strk
 * Fixed to build with -DNDEBUG
 *
 * Revision 1.7  2006/03/22 10:13:54  strk
 * opLinemerge.h split
 *
 * Revision 1.6  2006/03/21 21:42:54  strk
 * planargraph.h header split, planargraph:: classes renamed to match JTS symbols
 *
 **********************************************************************/
<commit_msg>Changed assert() with Assert::isTrue in addReverseSubpath<commit_after>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2006 Refractions Research Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 *
 * Last port: operation/linemerge/LineSequencer.java rev. 1.5 (JTS-1.7)
 *
 **********************************************************************/

#include <geos/operation/linemerge/LineSequencer.h>
#include <geos/operation/linemerge/LineMergeEdge.h>
#include <geos/geom/Geometry.h>
#include <geos/geom/GeometryFactory.h>
#include <geos/geom/MultiLineString.h>
#include <geos/geom/Coordinate.h>
#include <geos/geom/CoordinateSequence.h>
#include <geos/geom/LineString.h>
#include <geos/planargraph/Node.h>
#include <geos/planargraph/DirectedEdge.h>
#include <geos/planargraph/Subgraph.h>
#include <geos/planargraph/algorithm/ConnectedSubgraphFinder.h>
#include <geos/util/Assert.h>

#include <cassert>
#include <limits>
#include <vector>

using namespace std;
//using namespace geos::planargraph;
using namespace geos::geom;
//using namespace geos::planargraph::algorithm;

namespace geos {
namespace operation { // geos.operation
namespace linemerge { // geos.operation.linemerge

/* static */
bool
LineSequencer::isSequenced(const Geometry* geom)
{
	const MultiLineString *mls;

	if ( ! (mls=dynamic_cast<const MultiLineString *>(geom)) )
	{
		return true;
	}

	// the nodes in all subgraphs which have been completely scanned
	Coordinate::ConstSet prevSubgraphNodes;
	Coordinate::ConstVect currNodes;

	const Coordinate* lastNode = NULL;

	for (unsigned int i=0, n=mls->getNumGeometries(); i<n; ++i)
	{
		assert(dynamic_cast<const LineString*>(mls->getGeometryN(i)));

		const LineString& line = \
			static_cast<const LineString&>(*(mls->getGeometryN(i)));

		const Coordinate* startNode = &(line.getCoordinateN(0));
		const Coordinate* endNode = &(line.getCoordinateN(line.getNumPoints() - 1));

		/**
		 * If this linestring is connected to a previous subgraph,
		 * geom is not sequenced
		 */
		if (prevSubgraphNodes.find(startNode) != prevSubgraphNodes.end())
		{
			return false;
		}
		if (prevSubgraphNodes.find(endNode) != prevSubgraphNodes.end())
		{
			return false;
		}

		if (lastNode != NULL)
		{
			if (! startNode->equals2D(*lastNode))
			{
				// start new connected sequence
				prevSubgraphNodes.insert(currNodes.begin(),
						currNodes.end());
				currNodes.clear();
			}
		}
		currNodes.push_back(startNode);
		currNodes.push_back(endNode);
		lastNode = endNode;
	}
	return true;
}

/* private */
bool
LineSequencer::hasSequence(planargraph::Subgraph& graph)
{
	int oddDegreeCount = 0;
	for (planargraph::NodeMap::container::const_iterator
		it=graph.nodeBegin(), endIt=graph.nodeEnd();
		it!=endIt;
		++it)
	{
		planargraph::Node* node = it->second;
		if (node->getDegree() % 2 == 1)
		oddDegreeCount++;
	}
	return oddDegreeCount <= 2;
}

/*private*/
LineSequencer::Sequences*
LineSequencer::findSequences()
{
	Sequences *sequences = new Sequences();
	planargraph::algorithm::ConnectedSubgraphFinder csFinder(graph);
	vector<planargraph::Subgraph*>subgraphs;
	csFinder.getConnectedSubgraphs(subgraphs);
	for (vector<planargraph::Subgraph*>::const_iterator
		it=subgraphs.begin(), endIt=subgraphs.end();
		it!=endIt;
		++it )
	{
		planargraph::Subgraph* subgraph = *it;
		if (hasSequence(*subgraph)) {
			planargraph::DirectedEdge::NonConstList* seq=findSequence(*subgraph);
			sequences->push_back(seq);
		}
		else {
			// if any subgraph cannot be sequenced, abort
			return NULL;
		}
	}
	return sequences;
}

/*private*/
void
LineSequencer::addLine(const LineString *lineString)
{
	if (factory == NULL) {
		factory = lineString->getFactory();
	}
	graph.addEdge(lineString);
	++lineCount;
}

/* private */
void
LineSequencer::computeSequence()
{
	if (isRun) return;
	isRun = true;

	Sequences* sequences(findSequences());
	if (sequences == NULL) return;

	sequencedGeometry = auto_ptr<Geometry>(buildSequencedGeometry(*sequences));
	isSequenceableVar = true;

	// Lines were missing from result
	assert(lineCount == sequencedGeometry->getNumGeometries());

	// Result is not linear
	assert(dynamic_cast<LineString *>(sequencedGeometry.get())
		|| dynamic_cast<MultiLineString *>(sequencedGeometry.get()));
}

/*private*/
Geometry*
LineSequencer::buildSequencedGeometry(const Sequences& sequences)
{
	auto_ptr<Geometry::NonConstVect> lines(new Geometry::NonConstVect);

	for (Sequences::const_iterator
		i1=sequences.begin(), i1End=sequences.end();
		i1 != i1End;
		++i1)
	{
		planargraph::DirectedEdge::NonConstList& seq = *(*i1);
		for(planargraph::DirectedEdge::NonConstList::iterator i2=seq.begin(),
			i2End=seq.end(); i2 != i2End; ++i2)
		{
			const planargraph::DirectedEdge* de = *i2;
			assert(dynamic_cast<LineMergeEdge* >(de->getEdge()));
			LineMergeEdge* e = static_cast<LineMergeEdge* >(de->getEdge());
			const LineString* line = e->getLine();

			// lineToAdd will be a *copy* of input things
			LineString* lineToAdd;

			if ( ! de->getEdgeDirection() && ! line->isClosed() ) {
				lineToAdd = reverse(line);
			} else {
				Geometry* lineClone = line->clone();
				assert(dynamic_cast<LineString *>(lineClone));
				lineToAdd = static_cast<LineString *>(lineClone);
			}

			lines->push_back(lineToAdd);
		}
	}

	if ( lines->size() == 0 ) {
		return NULL;
	} else {
		Geometry::NonConstVect *l=lines.get();
		lines.release();
		return factory->buildGeometry(l);
	}
}

/*static private*/
LineString *
LineSequencer::reverse(const LineString *line)
{
	CoordinateSequence* cs=line->getCoordinates();
	CoordinateSequence::reverse(cs);
	return line->getFactory()->createLineString(cs);
}

/*private static*/
const planargraph::Node*
LineSequencer::findLowestDegreeNode(const planargraph::Subgraph& graph)
{
	int minDegree = numeric_limits<int>::max();
	const planargraph::Node* minDegreeNode = NULL;
	for (planargraph::NodeMap::container::const_iterator
		it = graph.nodeBegin(), itEnd = graph.nodeEnd();
		it != itEnd;
		++it )
	{
		const planargraph::Node* node = (*it).second;
		if (minDegreeNode == NULL || node->getDegree() < minDegree)
		{
			minDegree = node->getDegree();
			minDegreeNode = node;
		}
	}
	return minDegreeNode;
}

/*private static*/
const planargraph::DirectedEdge*
LineSequencer::findUnvisitedBestOrientedDE(const planargraph::Node* node)
{
	using planargraph::DirectedEdge;
	using planargraph::DirectedEdgeStar;

	const DirectedEdge* wellOrientedDE = NULL;
	const DirectedEdge* unvisitedDE = NULL;
	const DirectedEdgeStar* des=node->getOutEdges();
	for (DirectedEdge::NonConstVect::const_iterator i=des->begin(),
		e=des->end();
		i!=e;
		++i)
	{
		planargraph::DirectedEdge* de = *i;
		if (! de->getEdge()->isVisited()) {
			unvisitedDE = de;
			if (de->getEdgeDirection()) wellOrientedDE = de;
		}
	}
	if (wellOrientedDE != NULL)
		return wellOrientedDE;
	return unvisitedDE;
}

/*private*/
void
LineSequencer::addReverseSubpath(const planargraph::DirectedEdge *de,
		planargraph::DirectedEdge::NonConstList& deList,
		planargraph::DirectedEdge::NonConstList::iterator lit,
		bool expectedClosed)
{
	using planargraph::Node;
	using planargraph::DirectedEdge;

	// trace an unvisited path *backwards* from this de
	Node* endNode = de->getToNode();

	Node* fromNode = NULL;
	while (true) {
		deList.insert(lit, de->getSym());
		de->getEdge()->setVisited(true);
		fromNode = de->getFromNode();
		const DirectedEdge* unvisitedOutDE = findUnvisitedBestOrientedDE(fromNode);

		// this must terminate, since we are continually marking edges as visited
		if (unvisitedOutDE == NULL) break;
		de = unvisitedOutDE->getSym();
	}
	if ( expectedClosed ) {
		// the path should end at the toNode of this de,
		// otherwise we have an error
		util::Assert::isTrue(fromNode == endNode, "path not contiguos");
		//assert(fromNode == endNode);
	}

}

/*private*/
planargraph::DirectedEdge::NonConstList*
LineSequencer::findSequence(planargraph::Subgraph& graph)
{
	using planargraph::DirectedEdge;
	using planargraph::Node;
	using planargraph::GraphComponent;

	GraphComponent::setVisited(graph.edgeBegin(),
			graph.edgeEnd(), false);

	const Node* startNode = findLowestDegreeNode(graph);

	const DirectedEdge *startDE = *(startNode->getOutEdges()->begin());
	const DirectedEdge *startDESym = startDE->getSym();

	DirectedEdge::NonConstList *seq = new DirectedEdge::NonConstList();

	DirectedEdge::NonConstList::iterator lit=seq->begin();
	addReverseSubpath(startDESym, *seq, lit, false);

	lit=seq->end();
	while (lit != seq->begin()) {
		const DirectedEdge* prev = *(--lit);
		const DirectedEdge* unvisitedOutDE = findUnvisitedBestOrientedDE(prev->getFromNode());
		if (unvisitedOutDE != NULL)
			addReverseSubpath(unvisitedOutDE->getSym(), *seq, lit, true);
	}

	// At this point, we have a valid sequence of graph DirectedEdges,
	// but it is not necessarily appropriately oriented relative to
	// the underlying geometry.
	DirectedEdge::NonConstList* orientedSeq = orient(seq);

	if (orientedSeq != seq) delete seq;

	return orientedSeq;
}

/* private */
planargraph::DirectedEdge::NonConstList*
LineSequencer::orient(planargraph::DirectedEdge::NonConstList* seq)
{
	using namespace geos::planargraph;

	const DirectedEdge* startEdge = seq->front();
	const DirectedEdge* endEdge = seq->back();
	Node* startNode = startEdge->getFromNode();
	Node* endNode = endEdge->getToNode();

	bool flipSeq = false;
	bool hasDegree1Node = \
		startNode->getDegree() == 1 || endNode->getDegree() == 1;

	if (hasDegree1Node)
	{
		bool hasObviousStartNode = false;

		// test end edge before start edge, to make result stable
		// (ie. if both are good starts, pick the actual start
		if (endEdge->getToNode()->getDegree() == 1 &&
				endEdge->getEdgeDirection() == false)
		{
			hasObviousStartNode = true;
			flipSeq = true;
		}
		if (startEdge->getFromNode()->getDegree() == 1 &&
				startEdge->getEdgeDirection() == true)
		{
			hasObviousStartNode = true;
			flipSeq = false;
		}

		// since there is no obvious start node,
		// use any node of degree 1
		if (! hasObviousStartNode)
		{
			// check if the start node should actually
			// be the end node
			if (startEdge->getFromNode()->getDegree() == 1)
				flipSeq = true;
			// if the end node is of degree 1, it is
			// properly the end node
		}

	}

	// if there is no degree 1 node, just use the sequence as is
	// (Could insert heuristic of taking direction of majority of
	// lines as overall direction)

	if (flipSeq)
	{
		return reverse(*seq);
	}
	return seq;
}

/* private */
planargraph::DirectedEdge::NonConstList*
LineSequencer::reverse(planargraph::DirectedEdge::NonConstList& seq)
{
	using namespace geos::planargraph;

	DirectedEdge::NonConstList* newSeq = new DirectedEdge::NonConstList();
	DirectedEdge::NonConstList::iterator it=seq.begin(), itEnd=seq.end();
	for (; it!=itEnd; ++it) {
		const DirectedEdge *de = *it;
		newSeq->push_front(de->getSym());
	}
	return newSeq;
}

} // namespace geos.operation.linemerge
} // namespace geos.operation
} // namespace geos

/**********************************************************************
 * $Log$
 * Revision 1.9  2006/03/24 11:04:44  strk
 * Changed assert() with Assert::isTrue in addReverseSubpath
 *
 * Revision 1.8  2006/03/24 10:44:07  strk
 * Fixed to build with -DNDEBUG
 *
 * Revision 1.7  2006/03/22 10:13:54  strk
 * opLinemerge.h split
 *
 * Revision 1.6  2006/03/21 21:42:54  strk
 * planargraph.h header split, planargraph:: classes renamed to match JTS symbols
 *
 **********************************************************************/
<|endoftext|>