<commit_before>// Copyright (c) 2009 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 "base/at_exit.h"
#include "base/message_loop.h"
#include "base/scoped_nsautorelease_pool.h"
#include "gpu/command_buffer/common/command_buffer_mock.h"
#include "gpu/command_buffer/service/context_group.h"
#include "gpu/command_buffer/service/gpu_processor.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
#include "gpu/command_buffer/service/mocks.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gmock/include/gmock/gmock.h"

using testing::_;
using testing::DoAll;
using testing::Invoke;
using testing::NiceMock;
using testing::Return;
using testing::SetArgumentPointee;
using testing::StrictMock;

namespace gpu {

const size_t kRingBufferSize = 1024;
const size_t kRingBufferEntries = kRingBufferSize / sizeof(CommandBufferEntry);

class GPUProcessorTest : public testing::Test {
 protected:
  virtual void SetUp() {
    shared_memory_.reset(new ::base::SharedMemory);
    shared_memory_->Create(std::wstring(), false, false, kRingBufferSize);
    shared_memory_->Map(kRingBufferSize);
    buffer_ = static_cast<int32*>(shared_memory_->memory());
    shared_memory_buffer_.ptr = buffer_;
    shared_memory_buffer_.size = kRingBufferSize;
    memset(buffer_, 0, kRingBufferSize);

    command_buffer_.reset(new MockCommandBuffer);
    ON_CALL(*command_buffer_.get(), GetRingBuffer())
      .WillByDefault(Return(shared_memory_buffer_));

    CommandBuffer::State default_state;
    default_state.size = kRingBufferEntries;
    ON_CALL(*command_buffer_.get(), GetState())
      .WillByDefault(Return(default_state));

    async_api_.reset(new StrictMock<AsyncAPIMock>);

    decoder_ = new gles2::MockGLES2Decoder(&group_);

    parser_ = new CommandParser(buffer_,
                                kRingBufferEntries,
                                0,
                                kRingBufferEntries,
                                0,
                                async_api_.get());

    processor_.reset(new GPUProcessor(command_buffer_.get(),
                                      decoder_,
                                      parser_,
                                      2));
  }

  virtual void TearDown() {
    // Ensure that any unexpected tasks posted by the GPU processor are executed
    // in order to fail the test.
    MessageLoop::current()->RunAllPending();
  }

  error::Error GetError() {
    return command_buffer_->GetState().error;
  }

  base::ScopedNSAutoreleasePool autorelease_pool_;
  base::AtExitManager at_exit_manager;
  MessageLoop message_loop;
  scoped_ptr<MockCommandBuffer> command_buffer_;
  scoped_ptr<base::SharedMemory> shared_memory_;
  Buffer shared_memory_buffer_;
  int32* buffer_;
  gles2::ContextGroup group_;
  gles2::MockGLES2Decoder* decoder_;
  CommandParser* parser_;
  scoped_ptr<AsyncAPIMock> async_api_;
  scoped_ptr<GPUProcessor> processor_;
};

TEST_F(GPUProcessorTest, ProcessorDoesNothingIfRingBufferIsEmpty) {
  CommandBuffer::State state;

  state.put_offset = 0;
  EXPECT_CALL(*command_buffer_, GetState())
    .WillOnce(Return(state));
  EXPECT_CALL(*command_buffer_, SetGetOffset(0));

  EXPECT_CALL(*command_buffer_, SetParseError(_))
    .Times(0);

  processor_->ProcessCommands();
}

TEST_F(GPUProcessorTest, ProcessesOneCommand) {
  CommandHeader* header = reinterpret_cast<CommandHeader*>(&buffer_[0]);
  header[0].command = 7;
  header[0].size = 2;
  buffer_[1] = 123;

  CommandBuffer::State state;

  state.put_offset = 2;
  EXPECT_CALL(*command_buffer_, GetState())
    .WillOnce(Return(state));
  EXPECT_CALL(*command_buffer_, SetGetOffset(2));

  EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0]))
    .WillOnce(Return(error::kNoError));

  EXPECT_CALL(*command_buffer_, SetParseError(_))
    .Times(0);

  processor_->ProcessCommands();
}

TEST_F(GPUProcessorTest, ProcessesTwoCommands) {
  CommandHeader* header = reinterpret_cast<CommandHeader*>(&buffer_[0]);
  header[0].command = 7;
  header[0].size = 2;
  buffer_[1] = 123;
  header[2].command = 8;
  header[2].size = 1;

  CommandBuffer::State state;

  state.put_offset = 3;
  EXPECT_CALL(*command_buffer_, GetState())
    .WillOnce(Return(state));
  EXPECT_CALL(*command_buffer_, SetGetOffset(3));

  EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0]))
    .WillOnce(Return(error::kNoError));

  EXPECT_CALL(*async_api_, DoCommand(8, 0, &buffer_[2]))
    .WillOnce(Return(error::kNoError));

  processor_->ProcessCommands();
}

TEST_F(GPUProcessorTest, ProcessorSetsTheGLContext) {
  EXPECT_CALL(*decoder_, MakeCurrent())
    .WillOnce(Return(true));

  CommandBuffer::State state;
  state.put_offset = 0;
  EXPECT_CALL(*command_buffer_, GetState())
    .WillOnce(Return(state));

  EXPECT_CALL(*command_buffer_, SetGetOffset(0));

  processor_->ProcessCommands();
}

TEST_F(GPUProcessorTest, PostsTaskToFinishRemainingCommands) {
  CommandHeader* header = reinterpret_cast<CommandHeader*>(&buffer_[0]);
  header[0].command = 7;
  header[0].size = 2;
  buffer_[1] = 123;
  header[2].command = 8;
  header[2].size = 1;
  header[3].command = 9;
  header[3].size = 1;

  CommandBuffer::State state;

  state.put_offset = 4;
  EXPECT_CALL(*command_buffer_, GetState())
    .WillOnce(Return(state));

  EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0]))
    .WillOnce(Return(error::kNoError));

  EXPECT_CALL(*async_api_, DoCommand(8, 0, &buffer_[2]))
    .WillOnce(Return(error::kNoError));

  EXPECT_CALL(*command_buffer_, SetGetOffset(3));

  processor_->ProcessCommands();

  // ProcessCommands is called a second time when the pending task is run.

  state.put_offset = 4;
  EXPECT_CALL(*command_buffer_, GetState())
    .WillOnce(Return(state));

  EXPECT_CALL(*async_api_, DoCommand(9, 0, &buffer_[3]))
    .WillOnce(Return(error::kNoError));

  EXPECT_CALL(*command_buffer_, SetGetOffset(4));

  MessageLoop::current()->RunAllPending();
}

TEST_F(GPUProcessorTest, SetsErrorCodeOnCommandBuffer) {
  CommandHeader* header = reinterpret_cast<CommandHeader*>(&buffer_[0]);
  header[0].command = 7;
  header[0].size = 1;

  CommandBuffer::State state;

  state.put_offset = 1;
  EXPECT_CALL(*command_buffer_, GetState())
    .WillOnce(Return(state));

  EXPECT_CALL(*async_api_, DoCommand(7, 0, &buffer_[0]))
    .WillOnce(Return(
        error::kUnknownCommand));

  EXPECT_CALL(*command_buffer_,
      SetParseError(error::kUnknownCommand));

  processor_->ProcessCommands();
}

TEST_F(GPUProcessorTest, ProcessCommandsDoesNothingAfterError) {
  CommandBuffer::State state;
  state.error = error::kGenericError;

  EXPECT_CALL(*command_buffer_, GetState())
    .WillOnce(Return(state));

  processor_->ProcessCommands();
}

TEST_F(GPUProcessorTest, CanGetAddressOfSharedMemory) {
  EXPECT_CALL(*command_buffer_.get(), GetTransferBuffer(7))
    .WillOnce(Return(shared_memory_buffer_));

  EXPECT_EQ(&buffer_[0], processor_->GetSharedMemoryBuffer(7).ptr);
}

ACTION_P2(SetPointee, address, value) {
  *address = value;
}

TEST_F(GPUProcessorTest, CanGetSizeOfSharedMemory) {
  EXPECT_CALL(*command_buffer_.get(), GetTransferBuffer(7))
    .WillOnce(Return(shared_memory_buffer_));

  EXPECT_EQ(kRingBufferSize, processor_->GetSharedMemoryBuffer(7).size);
}

TEST_F(GPUProcessorTest, SetTokenForwardsToCommandBuffer) {
  EXPECT_CALL(*command_buffer_, SetToken(7));
  processor_->set_token(7);
}

}  // namespace gpu
<commit_msg>Disable the ProcessorDoesNothingIfRingBufferIsEmpty because it crashes gpu_unittests.<commit_after>// Copyright (c) 2009 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 "base/at_exit.h"
#include "base/message_loop.h"
#include "base/scoped_nsautorelease_pool.h"
#include "gpu/command_buffer/common/command_buffer_mock.h"
#include "gpu/command_buffer/service/context_group.h"
#include "gpu/command_buffer/service/gpu_processor.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
#include "gpu/command_buffer/service/mocks.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gmock/include/gmock/gmock.h"

using testing::_;
using testing::DoAll;
using testing::Invoke;
using testing::NiceMock;
using testing::Return;
using testing::SetArgumentPointee;
using testing::StrictMock;

namespace gpu {

const size_t kRingBufferSize = 1024;
const size_t kRingBufferEntries = kRingBufferSize / sizeof(CommandBufferEntry);

class GPUProcessorTest : public testing::Test {
 protected:
  virtual void SetUp() {
    shared_memory_.reset(new ::base::SharedMemory);
    shared_memory_->Create(std::wstring(), false, false, kRingBufferSize);
    shared_memory_->Map(kRingBufferSize);
    buffer_ = static_cast<int32*>(shared_memory_->memory());
    shared_memory_buffer_.ptr = buffer_;
    shared_memory_buffer_.size = kRingBufferSize;
    memset(buffer_, 0, kRingBufferSize);

    command_buffer_.reset(new MockCommandBuffer);
    ON_CALL(*command_buffer_.get(), GetRingBuffer())
      .WillByDefault(Return(shared_memory_buffer_));

    CommandBuffer::State default_state;
    default_state.size = kRingBufferEntries;
    ON_CALL(*command_buffer_.get(), GetState())
      .WillByDefault(Return(default_state));

    async_api_.reset(new StrictMock<AsyncAPIMock>);

    decoder_ = new gles2::MockGLES2Decoder(&group_);

    parser_ = new CommandParser(buffer_,
                                kRingBufferEntries,
                                0,
                                kRingBufferEntries,
                                0,
                                async_api_.get());

    processor_.reset(new GPUProcessor(command_buffer_.get(),
                                      decoder_,
                                      parser_,
                                      2));
  }

  virtual void TearDown() {
    // Ensure that any unexpected tasks posted by the GPU processor are executed
    // in order to fail the test.
    MessageLoop::current()->RunAllPending();
  }

  error::Error GetError() {
    return command_buffer_->GetState().error;
  }

  base::ScopedNSAutoreleasePool autorelease_pool_;
  base::AtExitManager at_exit_manager;
  MessageLoop message_loop;
  scoped_ptr<MockCommandBuffer> command_buffer_;
  scoped_ptr<base::SharedMemory> shared_memory_;
  Buffer shared_memory_buffer_;
  int32* buffer_;
  gles2::ContextGroup group_;
  gles2::MockGLES2Decoder* decoder_;
  CommandParser* parser_;
  scoped_ptr<AsyncAPIMock> async_api_;
  scoped_ptr<GPUProcessor> processor_;
};

// TODO(apatrick): This test is broken on linux.
TEST_F(GPUProcessorTest, DISABLED_ProcessorDoesNothingIfRingBufferIsEmpty) {
  CommandBuffer::State state;

  state.put_offset = 0;
  EXPECT_CALL(*command_buffer_, GetState())
    .WillOnce(Return(state));
  EXPECT_CALL(*command_buffer_, SetGetOffset(0));

  EXPECT_CALL(*command_buffer_, SetParseError(_))
    .Times(0);

  processor_->ProcessCommands();
}

TEST_F(GPUProcessorTest, ProcessesOneCommand) {
  CommandHeader* header = reinterpret_cast<CommandHeader*>(&buffer_[0]);
  header[0].command = 7;
  header[0].size = 2;
  buffer_[1] = 123;

  CommandBuffer::State state;

  state.put_offset = 2;
  EXPECT_CALL(*command_buffer_, GetState())
    .WillOnce(Return(state));
  EXPECT_CALL(*command_buffer_, SetGetOffset(2));

  EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0]))
    .WillOnce(Return(error::kNoError));

  EXPECT_CALL(*command_buffer_, SetParseError(_))
    .Times(0);

  processor_->ProcessCommands();
}

TEST_F(GPUProcessorTest, ProcessesTwoCommands) {
  CommandHeader* header = reinterpret_cast<CommandHeader*>(&buffer_[0]);
  header[0].command = 7;
  header[0].size = 2;
  buffer_[1] = 123;
  header[2].command = 8;
  header[2].size = 1;

  CommandBuffer::State state;

  state.put_offset = 3;
  EXPECT_CALL(*command_buffer_, GetState())
    .WillOnce(Return(state));
  EXPECT_CALL(*command_buffer_, SetGetOffset(3));

  EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0]))
    .WillOnce(Return(error::kNoError));

  EXPECT_CALL(*async_api_, DoCommand(8, 0, &buffer_[2]))
    .WillOnce(Return(error::kNoError));

  processor_->ProcessCommands();
}

TEST_F(GPUProcessorTest, ProcessorSetsTheGLContext) {
  EXPECT_CALL(*decoder_, MakeCurrent())
    .WillOnce(Return(true));

  CommandBuffer::State state;
  state.put_offset = 0;
  EXPECT_CALL(*command_buffer_, GetState())
    .WillOnce(Return(state));

  EXPECT_CALL(*command_buffer_, SetGetOffset(0));

  processor_->ProcessCommands();
}

TEST_F(GPUProcessorTest, PostsTaskToFinishRemainingCommands) {
  CommandHeader* header = reinterpret_cast<CommandHeader*>(&buffer_[0]);
  header[0].command = 7;
  header[0].size = 2;
  buffer_[1] = 123;
  header[2].command = 8;
  header[2].size = 1;
  header[3].command = 9;
  header[3].size = 1;

  CommandBuffer::State state;

  state.put_offset = 4;
  EXPECT_CALL(*command_buffer_, GetState())
    .WillOnce(Return(state));

  EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0]))
    .WillOnce(Return(error::kNoError));

  EXPECT_CALL(*async_api_, DoCommand(8, 0, &buffer_[2]))
    .WillOnce(Return(error::kNoError));

  EXPECT_CALL(*command_buffer_, SetGetOffset(3));

  processor_->ProcessCommands();

  // ProcessCommands is called a second time when the pending task is run.

  state.put_offset = 4;
  EXPECT_CALL(*command_buffer_, GetState())
    .WillOnce(Return(state));

  EXPECT_CALL(*async_api_, DoCommand(9, 0, &buffer_[3]))
    .WillOnce(Return(error::kNoError));

  EXPECT_CALL(*command_buffer_, SetGetOffset(4));

  MessageLoop::current()->RunAllPending();
}

TEST_F(GPUProcessorTest, SetsErrorCodeOnCommandBuffer) {
  CommandHeader* header = reinterpret_cast<CommandHeader*>(&buffer_[0]);
  header[0].command = 7;
  header[0].size = 1;

  CommandBuffer::State state;

  state.put_offset = 1;
  EXPECT_CALL(*command_buffer_, GetState())
    .WillOnce(Return(state));

  EXPECT_CALL(*async_api_, DoCommand(7, 0, &buffer_[0]))
    .WillOnce(Return(
        error::kUnknownCommand));

  EXPECT_CALL(*command_buffer_,
      SetParseError(error::kUnknownCommand));

  processor_->ProcessCommands();
}

TEST_F(GPUProcessorTest, ProcessCommandsDoesNothingAfterError) {
  CommandBuffer::State state;
  state.error = error::kGenericError;

  EXPECT_CALL(*command_buffer_, GetState())
    .WillOnce(Return(state));

  processor_->ProcessCommands();
}

TEST_F(GPUProcessorTest, CanGetAddressOfSharedMemory) {
  EXPECT_CALL(*command_buffer_.get(), GetTransferBuffer(7))
    .WillOnce(Return(shared_memory_buffer_));

  EXPECT_EQ(&buffer_[0], processor_->GetSharedMemoryBuffer(7).ptr);
}

ACTION_P2(SetPointee, address, value) {
  *address = value;
}

TEST_F(GPUProcessorTest, CanGetSizeOfSharedMemory) {
  EXPECT_CALL(*command_buffer_.get(), GetTransferBuffer(7))
    .WillOnce(Return(shared_memory_buffer_));

  EXPECT_EQ(kRingBufferSize, processor_->GetSharedMemoryBuffer(7).size);
}

TEST_F(GPUProcessorTest, SetTokenForwardsToCommandBuffer) {
  EXPECT_CALL(*command_buffer_, SetToken(7));
  processor_->set_token(7);
}

}  // namespace gpu
<|endoftext|>


<commit_before><commit_msg>Number representation class templates have a default zero.<commit_after><|endoftext|>


<commit_before>#include <cassert>
#include "AnnLocator.h"

using namespace cigma;

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

AnnLocator::AnnLocator()
{
    nnk = 8;
    epsilon = 0;

    npts = 0;
    ndim2 = 0;

    dataPoints = 0;
    kdtree = 0;

    nnIdx = 0;
    nnDists = 0;

    locatorType = NULL_LOCATOR;
}

AnnLocator::~AnnLocator()
{
    if (kdtree != 0) delete kdtree;

    if (dataPoints != 0)
    {
        annDeallocPts(dataPoints);
        dataPoints = 0;
    }

    if (nnIdx != 0)
    {
        delete [] nnIdx;
        nnIdx = 0;
    }
    if (nnDists != 0)
    {
        delete [] nnDists;
        nnDists = 0;
    }
}

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

void AnnLocator::initialize(MeshPart *meshPart)
{
    assert(nnk > 0);

    npts = meshPart->nel;
    ndim = meshPart->nsd;
    ndim2 = ndim * 2;

    assert(npts > 0);
    assert(ndim > 0);

    dataPoints = annAllocPts(npts, ndim);
    queryPoint = annAllocPt(ndim2);

    nnIdx = new ANNidx[nnk];
    nnDists = new ANNdist[nnk];

    int i,j;
    double minpt[ndim];
    double maxpt[ndim];

    for (i = 0; i < npts; i++)
    {
        ANNpoint pt = dataPoints[i];
        meshPart->select_cell(i);
        meshPart->cell->bbox(minpt, maxpt);
        for (j = 0; j < ndim; j++)
        {
            pt[ndim*0 + j] = minpt[j];
            pt[ndim*1 + j] = maxpt[j];
        }
    }

    kdtree = new ANNkd_tree(dataPoints, npts, ndim2);

    locatorType = CELL_LOCATOR;
}

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

void AnnLocator::initialize(Points *points)
{
    assert(nnk > 0);

    npts = points->n_points();
    ndim = points->n_dim();

    assert(npts > 0);
    assert(ndim > 0);

    // XXX watch out for when you change the ANNpoint type to floaT
    assert(sizeof(ANNcoord) == sizeof(double));

    //dataPoints = (ANNpointArray)(points->data); // questionable cast..

    dataPoints = annAllocPts(npts, ndim);
    queryPoint = annAllocPt(ndim);

    int i,j;
    for (i = 0; i < npts; i++)
    {
        ANNpoint pt = dataPoints[i];
        for (j = 0; j < ndim; j++)
        {
            pt[j] = points->data[ndim*i + j];
        }
    }

    nnIdx = new ANNidx[nnk];
    nnDists = new ANNdist[nnk];

    kdtree = new ANNkd_tree(dataPoints, npts, ndim);

    locatorType = POINT_LOCATOR;
}

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

void AnnLocator::search(double *point)
{
    for (int i = 0; i < ndim; i++)
    {
        queryPoint[ndim*0 + i] = point[i];
        queryPoint[ndim*1 + i] = point[i];
    }

    kdtree->annkSearch(queryPoint, nnk, nnIdx, nnDists, epsilon);
}

// ---------------------------------------------------------------------------
<commit_msg>Ooops..big typo! Fixes broken locator searches.<commit_after>#include <cassert>
#include "AnnLocator.h"

using namespace cigma;

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

AnnLocator::AnnLocator()
{
    nnk = 8;
    epsilon = 0;

    npts = 0;
    ndim2 = 0;

    dataPoints = 0;
    kdtree = 0;

    nnIdx = 0;
    nnDists = 0;

    locatorType = NULL_LOCATOR;
}

AnnLocator::~AnnLocator()
{
    if (kdtree != 0) delete kdtree;

    if (dataPoints != 0)
    {
        annDeallocPts(dataPoints);
        dataPoints = 0;
    }

    if (nnIdx != 0)
    {
        delete [] nnIdx;
        nnIdx = 0;
    }
    if (nnDists != 0)
    {
        delete [] nnDists;
        nnDists = 0;
    }
}

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

void AnnLocator::initialize(MeshPart *meshPart)
{
    assert(nnk > 0);

    npts = meshPart->nel;
    ndim = meshPart->nsd;
    ndim2 = ndim * 2;

    assert(npts > 0);
    assert(ndim > 0);

    dataPoints = annAllocPts(npts, ndim2);
    queryPoint = annAllocPt(ndim2);

    nnIdx = new ANNidx[nnk];
    nnDists = new ANNdist[nnk];

    int i,j;
    double minpt[ndim];
    double maxpt[ndim];

    for (i = 0; i < npts; i++)
    {
        ANNpoint pt = dataPoints[i];
        meshPart->select_cell(i);
        meshPart->cell->bbox(minpt, maxpt);
        for (j = 0; j < ndim; j++)
        {
            pt[ndim*0 + j] = minpt[j];
            pt[ndim*1 + j] = maxpt[j];
        }
    }

    kdtree = new ANNkd_tree(dataPoints, npts, ndim2);

    locatorType = CELL_LOCATOR;
}

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

void AnnLocator::initialize(Points *points)
{
    assert(nnk > 0);

    npts = points->n_points();
    ndim = points->n_dim();

    assert(npts > 0);
    assert(ndim > 0);

    // XXX watch out for when you change the ANNpoint type to floaT
    assert(sizeof(ANNcoord) == sizeof(double));

    //dataPoints = (ANNpointArray)(points->data); // questionable cast..

    dataPoints = annAllocPts(npts, ndim);
    queryPoint = annAllocPt(ndim);

    int i,j;
    for (i = 0; i < npts; i++)
    {
        ANNpoint pt = dataPoints[i];
        for (j = 0; j < ndim; j++)
        {
            pt[j] = points->data[ndim*i + j];
        }
    }

    nnIdx = new ANNidx[nnk];
    nnDists = new ANNdist[nnk];

    kdtree = new ANNkd_tree(dataPoints, npts, ndim);

    locatorType = POINT_LOCATOR;
}

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

void AnnLocator::search(double *point)
{
    for (int i = 0; i < ndim; i++)
    {
        queryPoint[ndim*0 + i] = point[i];
        queryPoint[ndim*1 + i] = point[i];
    }

    kdtree->annkSearch(queryPoint, nnk, nnIdx, nnDists, epsilon);
}

// ---------------------------------------------------------------------------
<|endoftext|>


<commit_before>//=====================================================================//
/*! @file
    @brief  RX24T ファースト・サンプル @n
			・P00(4) ピンに赤色LED（VF:1.9V）を吸い込みで接続する
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "RX24T/system.hpp"
#include "RX600/port.hpp"

namespace {

	void wait_delay_(uint32_t n)
	{
		// とりあえず無駄ループ
		for(uint32_t i = 0; i < n; ++i) {
			asm("nop");
		}
	}

}

int main(int argc, char** argv);

int main(int argc, char** argv)
{
	device::SYSTEM::PRCR = 0xA50B;	// クロック、低消費電力、関係書き込み許可

	device::SYSTEM::MEMWAIT = 0b10; // 80MHz 動作 wait 設定

	while(device::SYSTEM::OPCCR.OPCMTSF() != 0) asm("nop");
	device::SYSTEM::OPCCR = 0;  // 高速モード選択
	while(device::SYSTEM::OPCCR.OPCMTSF() != 0) asm("nop");

	// clock osc 10MHz
	device::SYSTEM::MOSCWTCR = 9;	// 4ms wait
	// メインクロック・ドライブ能力設定、内部発信
	device::SYSTEM::MOFCR = device::SYSTEM::MOFCR.MODRV21.b(1);
	device::SYSTEM::MOSCCR.MOSTP = 0;  // メインクロック発振器動作
	while(device::SYSTEM::OSCOVFSR.MOOVF() == 0) asm("nop");

	device::SYSTEM::PLLCR.STC = 0b001111;		// PLL input: 1, PLL 8 倍(80MHz)
	device::SYSTEM::PLLCR2.PLLEN = 0;			// PLL 動作
	while(device::SYSTEM::OSCOVFSR.PLOVF() == 0) asm("nop");

	device::SYSTEM::SCKCR = device::SYSTEM::SCKCR.FCK.b(2)		// 1/4 (80/4=20)
						  | device::SYSTEM::SCKCR.ICK.b(0)		// 1/1 (80/1=80)
						  | device::SYSTEM::SCKCR.PCKA.b(0)		// 1/1 (80/1=80)
						  | device::SYSTEM::SCKCR.PCKB.b(1)		// 1/2 (80/2=40)
						  | device::SYSTEM::SCKCR.PCKD.b(1);	// 1/2 (120/2=60)
	device::SYSTEM::SCKCR3.CKSEL = 0b100;	///< PLL 選択

	uint32_t wait = 1000000;
	device::PORT0::PDR.B0 = 1; // output
	while(1) {
		wait_delay_(wait);
		device::PORT0::PODR.B0 = 0;
		wait_delay_(wait);
		device::PORT0::PODR.B0 = 1;
	}
}
<commit_msg>remove: project refine<commit_after><|endoftext|>


<commit_before>/* The Next Great Finite Element Library. */
/* Copyright (C) 2003  Benjamin S. Kirk */

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

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

/* You should have received a copy of the GNU Lesser General Public */
/* License along with this library; if not, write to the Free Software */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

 //
Miscellaneous Example 6 - Meshing with LibMesh's TetGen and Triangle Interfaces

 //
 // LibMesh provides interfaces to both Triangle and TetGen for generating
 // Delaunay triangulations and tetrahedralizations in two and three dimensions
 // (respectively).

// Local header files
#include "mesh.h"
#include "mesh_triangle_interface.h"
#include "mesh_generation.h"
#include "elem.h"
#include "mesh_tetgen_interface.h"
#include "node.h"
#include "face_tri3.h"
#include "mesh_triangle_holes.h"

// Bring in everything from the libMesh namespace
using namespace libMesh;

// Major functions called by main
void triangulate_domain();
void tetrahedralize_domain();

// Helper routine for tetrahedralize_domain().  Adds the points and elements
// of a convex hull generated by TetGen to the input mesh
void add_cube_convex_hull_to_mesh(MeshBase& mesh, Point lower_limit, Point upper_limit);

// Begin the main program.
int main (int argc, char** argv)
{
  // Initialize libMesh and any dependent libaries, like in example 2.
  LibMeshInit init (argc, argv);

  libmesh_example_assert(2 <= LIBMESH_DIM, "2D support");

  std::cout << "Triangulating an L-shaped domain with holes" << std::endl;

  // 1.) 2D triangulation of L-shaped domain with three holes of different shape
  triangulate_domain();

  libmesh_example_assert(3 <= LIBMESH_DIM, "3D support");

  std::cout << "Tetrahedralizing a prismatic domain with a hole" << std::endl;

  // 2.) 3D tetrahedralization of rectangular domain with hole.
  tetrahedralize_domain();

  return 0;
}

void triangulate_domain()
{
#ifdef LIBMESH_HAVE_TRIANGLE
  // Use typedefs for slightly less typing.
  typedef TriangleInterface::Hole Hole;
  typedef TriangleInterface::PolygonHole PolygonHole;
  typedef TriangleInterface::ArbitraryHole ArbitraryHole;

  // Libmesh mesh that will eventually be created.
  Mesh mesh(2);

  // The points which make up the L-shape:
  mesh.add_point(Point( 0. ,  0.));
  mesh.add_point(Point( 0. , -1.));
  mesh.add_point(Point(-1. , -1.));
  mesh.add_point(Point(-1. ,  1.));
  mesh.add_point(Point( 1. ,  1.));
  mesh.add_point(Point( 1. ,  0.));

  // Declare the TriangleInterface object.  This is where
  // we can set parameters of the triangulation and where the
  // actual triangulate function lives.
  TriangleInterface t(mesh);

  // Customize the variables for the triangulation
  t.desired_area()       = .01;

  // A Planar Straight Line Graph (PSLG) is essentially a list
  // of segments which have to exist in the final triangulation.
  // For an L-shaped domain, Triangle will compute the convex
  // hull of boundary points if we do not specify the PSLG.
  // The PSLG algorithm is also required for triangulating domains
  // containing holes
  t.triangulation_type() = TriangleInterface::PSLG;

  // Turn on/off Laplacian mesh smoothing after generation.
  // By default this is on.
  t.smooth_after_generating() = true;

  // Define holes...

  // hole_1 is a circle (discretized by 50 points)
  PolygonHole hole_1(Point(-0.5,  0.5), // center
		     0.25,              // radius
		     50);               // n. points

  // hole_2 is itself a triangle
  PolygonHole hole_2(Point(0.5, 0.5),   // center
		     0.1,               // radius
		     3);                // n. points

  // hole_3 is an ellipse of 100 points which we define here
  Point ellipse_center(-0.5,  -0.5);
  const unsigned int n_ellipse_points=100;
  std::vector<Point> ellipse_points(n_ellipse_points);
  const Real
    dtheta = 2*libMesh::pi / static_cast<Real>(n_ellipse_points),
    a = .1,
    b = .2;

  for (unsigned int i=0; i<n_ellipse_points; ++i)
    ellipse_points[i]= Point(ellipse_center(0)+a*cos(i*dtheta),
			     ellipse_center(1)+b*sin(i*dtheta));

  ArbitraryHole hole_3(ellipse_center, ellipse_points);

  // Create the vector of Hole*'s ...
  std::vector<Hole*> holes;
  holes.push_back(&hole_1);
  holes.push_back(&hole_2);
  holes.push_back(&hole_3);

  // ... and attach it to the triangulator object
  t.attach_hole_list(&holes);

  // Triangulate!
  t.triangulate();

  // Write the result to file
  mesh.write("delaunay_l_shaped_hole.e");

#endif // LIBMESH_HAVE_TRIANGLE
}

void tetrahedralize_domain()
{
#ifdef LIBMESH_HAVE_TETGEN
  // The algorithm is broken up into several steps:
  // 1.) A convex hull is constructed for a rectangular hole.
  // 2.) A convex hull is constructed for the domain exterior.
  // 3.) Neighbor information is updated so TetGen knows there is a convex hull
  // 4.) A vector of hole points is created.
  // 5.) The domain is tetrahedralized, the mesh is written out, etc.

  // The mesh we will eventually generate
  Mesh mesh(3);

  // Lower and Upper bounding box limits for a rectangular hole within the unit cube.
  Point hole_lower_limit(0.2, 0.2, 0.4);
  Point hole_upper_limit(0.8, 0.8, 0.6);

  // 1.) Construct a convex hull for the hole
  add_cube_convex_hull_to_mesh(mesh, hole_lower_limit, hole_upper_limit);

  // 2.) Generate elements comprising the outer boundary of the domain.
  add_cube_convex_hull_to_mesh(mesh, Point(0.,0.,0.), Point(1., 1., 1.));

  // 3.) Update neighbor information so that TetGen can verify there is a convex hull.
  mesh.find_neighbors();

  // 4.) Set up vector of hole points
  std::vector<Point> hole(1);
  hole[0] = Point( 0.5*(hole_lower_limit + hole_upper_limit) );

  // 5.) Set parameters and tetrahedralize the domain

  // 0 means "use TetGen default value"
  Real quality_constraint = 2.0;

  // The volume constraint determines the max-allowed tetrahedral
  // volume in the Mesh.  TetGen will split cells which are larger than
  // this size
  Real volume_constraint = 0.001;

  // Construct the Delaunay tetrahedralization
  TetGenMeshInterface t(mesh);
  t.triangulate_conformingDelaunayMesh_carvehole(hole,
						 quality_constraint,
						 volume_constraint);

  // Find neighbors, etc in preparation for writing out the Mesh
  mesh.prepare_for_use();

  // Finally, write out the result
  mesh.write("hole_3D.e");
#endif // LIBMESH_HAVE_TETGEN
}

void add_cube_convex_hull_to_mesh(MeshBase& mesh, Point lower_limit, Point upper_limit)
{
#ifdef LIBMESH_HAVE_TETGEN
  Mesh cube_mesh(3);

  unsigned n_elem = 1;

  MeshTools::Generation::build_cube(cube_mesh,
				    n_elem,n_elem,n_elem, // n. elements in each direction
				    lower_limit(0), upper_limit(0),
				    lower_limit(1), upper_limit(1),
				    lower_limit(2), upper_limit(2),
				    HEX8);

  // The pointset_convexhull() algorithm will ignore the Hex8s
  // in the Mesh, and just construct the triangulation
  // of the convex hull.
  TetGenMeshInterface t(cube_mesh);
  t.pointset_convexhull();

  // Now add all nodes from the boundary of the cube_mesh to the input mesh.

  // Map from "node id in cube_mesh" -> "node id in mesh".  Initially inserted
  // with a dummy value, later to be assigned a value by the input mesh.
  std::map<unsigned,unsigned> node_id_map;
  typedef std::map<unsigned,unsigned>::iterator iterator;

  {
    MeshBase::element_iterator it = cube_mesh.elements_begin();
    const MeshBase::element_iterator end = cube_mesh.elements_end();
    for ( ; it != end; ++it)
      {
	Elem* elem = *it;

	for (unsigned s=0; s<elem->n_sides(); ++s)
	  if (elem->neighbor(s) == NULL)
	    {
	      // Add the node IDs of this side to the set
	      AutoPtr<Elem> side = elem->side(s);

	      for (unsigned n=0; n<side->n_nodes(); ++n)
		node_id_map.insert( std::make_pair(side->node(n), /*dummy_value=*/0) );
	    }
      }
  }

  // For each node in the map, insert it into the input mesh and keep
  // track of the ID assigned.
  for (iterator it=node_id_map.begin(); it != node_id_map.end(); ++it)
    {
      // Id of the node in the cube mesh
      unsigned id = (*it).first;

      // Pointer to node in the cube mesh
      Node* old_node = cube_mesh.node_ptr(id);

      // Add geometric point to input mesh
      Node* new_node = mesh.add_point ( *old_node );

      // Track ID value of new_node in map
      (*it).second = new_node->id();
    }

  // With the points added and the map data structure in place, we are
  // ready to add each TRI3 element of the cube_mesh to the input Mesh
  // with proper node assignments
  {
    MeshBase::element_iterator       el     = cube_mesh.elements_begin();
    const MeshBase::element_iterator end_el = cube_mesh.elements_end();

    for (; el != end_el; ++el)
      {
	Elem* old_elem = *el;

	if (old_elem->type() == TRI3)
	  {
	    Elem* new_elem = mesh.add_elem(new Tri3);

	    // Assign nodes in new elements.  Since this is an example,
	    // we'll do it in several steps.
	    for (unsigned i=0; i<old_elem->n_nodes(); ++i)
	      {
		// Locate old node ID in the map
		iterator it = node_id_map.find(old_elem->node(i));

		// Check for not found
		if (it == node_id_map.end())
		  {
		    libMesh::err << "Node id " << old_elem->node(i) << " not found in map!" << std::endl;
		    libmesh_error();
		  }

		// Mapping to node ID in input mesh
		unsigned new_node_id = (*it).second;

		// Node pointer assigned from input mesh
		new_elem->set_node(i) = mesh.node_ptr(new_node_id);
	      }
	  }
      }
  }
#endif // LIBMESH_HAVE_TETGEN
}
<commit_msg>Use SerialMesh with tetgen until I can track down the (not recent!) ParallelMesh regression there<commit_after>/* The Next Great Finite Element Library. */
/* Copyright (C) 2003  Benjamin S. Kirk */

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

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

/* You should have received a copy of the GNU Lesser General Public */
/* License along with this library; if not, write to the Free Software */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

 //
Miscellaneous Example 6 - Meshing with LibMesh's TetGen and Triangle Interfaces

 //
 // LibMesh provides interfaces to both Triangle and TetGen for generating
 // Delaunay triangulations and tetrahedralizations in two and three dimensions
 // (respectively).

// Local header files
#include "elem.h"
#include "face_tri3.h"
#include "mesh.h"
#include "mesh_generation.h"
#include "mesh_tetgen_interface.h"
#include "mesh_triangle_holes.h"
#include "mesh_triangle_interface.h"
#include "node.h"
#include "serial_mesh.h"

// Bring in everything from the libMesh namespace
using namespace libMesh;

// Major functions called by main
void triangulate_domain();
void tetrahedralize_domain();

// Helper routine for tetrahedralize_domain().  Adds the points and elements
// of a convex hull generated by TetGen to the input mesh
void add_cube_convex_hull_to_mesh(MeshBase& mesh, Point lower_limit, Point upper_limit);

// Begin the main program.
int main (int argc, char** argv)
{
  // Initialize libMesh and any dependent libaries, like in example 2.
  LibMeshInit init (argc, argv);

  libmesh_example_assert(2 <= LIBMESH_DIM, "2D support");

  std::cout << "Triangulating an L-shaped domain with holes" << std::endl;

  // 1.) 2D triangulation of L-shaped domain with three holes of different shape
  triangulate_domain();

  libmesh_example_assert(3 <= LIBMESH_DIM, "3D support");

  std::cout << "Tetrahedralizing a prismatic domain with a hole" << std::endl;

  // 2.) 3D tetrahedralization of rectangular domain with hole.
  tetrahedralize_domain();

  return 0;
}

void triangulate_domain()
{
#ifdef LIBMESH_HAVE_TRIANGLE
  // Use typedefs for slightly less typing.
  typedef TriangleInterface::Hole Hole;
  typedef TriangleInterface::PolygonHole PolygonHole;
  typedef TriangleInterface::ArbitraryHole ArbitraryHole;

  // Libmesh mesh that will eventually be created.
  Mesh mesh(2);

  // The points which make up the L-shape:
  mesh.add_point(Point( 0. ,  0.));
  mesh.add_point(Point( 0. , -1.));
  mesh.add_point(Point(-1. , -1.));
  mesh.add_point(Point(-1. ,  1.));
  mesh.add_point(Point( 1. ,  1.));
  mesh.add_point(Point( 1. ,  0.));

  // Declare the TriangleInterface object.  This is where
  // we can set parameters of the triangulation and where the
  // actual triangulate function lives.
  TriangleInterface t(mesh);

  // Customize the variables for the triangulation
  t.desired_area()       = .01;

  // A Planar Straight Line Graph (PSLG) is essentially a list
  // of segments which have to exist in the final triangulation.
  // For an L-shaped domain, Triangle will compute the convex
  // hull of boundary points if we do not specify the PSLG.
  // The PSLG algorithm is also required for triangulating domains
  // containing holes
  t.triangulation_type() = TriangleInterface::PSLG;

  // Turn on/off Laplacian mesh smoothing after generation.
  // By default this is on.
  t.smooth_after_generating() = true;

  // Define holes...

  // hole_1 is a circle (discretized by 50 points)
  PolygonHole hole_1(Point(-0.5,  0.5), // center
		     0.25,              // radius
		     50);               // n. points

  // hole_2 is itself a triangle
  PolygonHole hole_2(Point(0.5, 0.5),   // center
		     0.1,               // radius
		     3);                // n. points

  // hole_3 is an ellipse of 100 points which we define here
  Point ellipse_center(-0.5,  -0.5);
  const unsigned int n_ellipse_points=100;
  std::vector<Point> ellipse_points(n_ellipse_points);
  const Real
    dtheta = 2*libMesh::pi / static_cast<Real>(n_ellipse_points),
    a = .1,
    b = .2;

  for (unsigned int i=0; i<n_ellipse_points; ++i)
    ellipse_points[i]= Point(ellipse_center(0)+a*cos(i*dtheta),
			     ellipse_center(1)+b*sin(i*dtheta));

  ArbitraryHole hole_3(ellipse_center, ellipse_points);

  // Create the vector of Hole*'s ...
  std::vector<Hole*> holes;
  holes.push_back(&hole_1);
  holes.push_back(&hole_2);
  holes.push_back(&hole_3);

  // ... and attach it to the triangulator object
  t.attach_hole_list(&holes);

  // Triangulate!
  t.triangulate();

  // Write the result to file
  mesh.write("delaunay_l_shaped_hole.e");

#endif // LIBMESH_HAVE_TRIANGLE
}

void tetrahedralize_domain()
{
#ifdef LIBMESH_HAVE_TETGEN
  // The algorithm is broken up into several steps:
  // 1.) A convex hull is constructed for a rectangular hole.
  // 2.) A convex hull is constructed for the domain exterior.
  // 3.) Neighbor information is updated so TetGen knows there is a convex hull
  // 4.) A vector of hole points is created.
  // 5.) The domain is tetrahedralized, the mesh is written out, etc.

  // The mesh we will eventually generate
  SerialMesh mesh(3);

  // Lower and Upper bounding box limits for a rectangular hole within the unit cube.
  Point hole_lower_limit(0.2, 0.2, 0.4);
  Point hole_upper_limit(0.8, 0.8, 0.6);

  // 1.) Construct a convex hull for the hole
  add_cube_convex_hull_to_mesh(mesh, hole_lower_limit, hole_upper_limit);

  // 2.) Generate elements comprising the outer boundary of the domain.
  add_cube_convex_hull_to_mesh(mesh, Point(0.,0.,0.), Point(1., 1., 1.));

  // 3.) Update neighbor information so that TetGen can verify there is a convex hull.
  mesh.find_neighbors();

  // 4.) Set up vector of hole points
  std::vector<Point> hole(1);
  hole[0] = Point( 0.5*(hole_lower_limit + hole_upper_limit) );

  // 5.) Set parameters and tetrahedralize the domain

  // 0 means "use TetGen default value"
  Real quality_constraint = 2.0;

  // The volume constraint determines the max-allowed tetrahedral
  // volume in the Mesh.  TetGen will split cells which are larger than
  // this size
  Real volume_constraint = 0.001;

  // Construct the Delaunay tetrahedralization
  TetGenMeshInterface t(mesh);
  t.triangulate_conformingDelaunayMesh_carvehole(hole,
						 quality_constraint,
						 volume_constraint);

  // Find neighbors, etc in preparation for writing out the Mesh
  mesh.prepare_for_use();

  // Finally, write out the result
  mesh.write("hole_3D.e");
#endif // LIBMESH_HAVE_TETGEN
}

void add_cube_convex_hull_to_mesh(MeshBase& mesh, Point lower_limit, Point upper_limit)
{
#ifdef LIBMESH_HAVE_TETGEN
  Mesh cube_mesh(3);

  unsigned n_elem = 1;

  MeshTools::Generation::build_cube(cube_mesh,
				    n_elem,n_elem,n_elem, // n. elements in each direction
				    lower_limit(0), upper_limit(0),
				    lower_limit(1), upper_limit(1),
				    lower_limit(2), upper_limit(2),
				    HEX8);

  // The pointset_convexhull() algorithm will ignore the Hex8s
  // in the Mesh, and just construct the triangulation
  // of the convex hull.
  TetGenMeshInterface t(cube_mesh);
  t.pointset_convexhull();

  // Now add all nodes from the boundary of the cube_mesh to the input mesh.

  // Map from "node id in cube_mesh" -> "node id in mesh".  Initially inserted
  // with a dummy value, later to be assigned a value by the input mesh.
  std::map<unsigned,unsigned> node_id_map;
  typedef std::map<unsigned,unsigned>::iterator iterator;

  {
    MeshBase::element_iterator it = cube_mesh.elements_begin();
    const MeshBase::element_iterator end = cube_mesh.elements_end();
    for ( ; it != end; ++it)
      {
	Elem* elem = *it;

	for (unsigned s=0; s<elem->n_sides(); ++s)
	  if (elem->neighbor(s) == NULL)
	    {
	      // Add the node IDs of this side to the set
	      AutoPtr<Elem> side = elem->side(s);

	      for (unsigned n=0; n<side->n_nodes(); ++n)
		node_id_map.insert( std::make_pair(side->node(n), /*dummy_value=*/0) );
	    }
      }
  }

  // For each node in the map, insert it into the input mesh and keep
  // track of the ID assigned.
  for (iterator it=node_id_map.begin(); it != node_id_map.end(); ++it)
    {
      // Id of the node in the cube mesh
      unsigned id = (*it).first;

      // Pointer to node in the cube mesh
      Node* old_node = cube_mesh.node_ptr(id);

      // Add geometric point to input mesh
      Node* new_node = mesh.add_point ( *old_node );

      // Track ID value of new_node in map
      (*it).second = new_node->id();
    }

  // With the points added and the map data structure in place, we are
  // ready to add each TRI3 element of the cube_mesh to the input Mesh
  // with proper node assignments
  {
    MeshBase::element_iterator       el     = cube_mesh.elements_begin();
    const MeshBase::element_iterator end_el = cube_mesh.elements_end();

    for (; el != end_el; ++el)
      {
	Elem* old_elem = *el;

	if (old_elem->type() == TRI3)
	  {
	    Elem* new_elem = mesh.add_elem(new Tri3);

	    // Assign nodes in new elements.  Since this is an example,
	    // we'll do it in several steps.
	    for (unsigned i=0; i<old_elem->n_nodes(); ++i)
	      {
		// Locate old node ID in the map
		iterator it = node_id_map.find(old_elem->node(i));

		// Check for not found
		if (it == node_id_map.end())
		  {
		    libMesh::err << "Node id " << old_elem->node(i) << " not found in map!" << std::endl;
		    libmesh_error();
		  }

		// Mapping to node ID in input mesh
		unsigned new_node_id = (*it).second;

		// Node pointer assigned from input mesh
		new_elem->set_node(i) = mesh.node_ptr(new_node_id);
	      }
	  }
      }
  }
#endif // LIBMESH_HAVE_TETGEN
}
<|endoftext|>


<commit_before>//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
// Developed by Minigraph
//
// Author:  James Stanard
//

#include "pch.h"
#include "CommandListManager.h"

CommandQueue::CommandQueue(D3D12_COMMAND_LIST_TYPE Type) :
    m_Type(Type),
    m_CommandQueue(nullptr),
    m_pFence(nullptr),
    m_NextFenceValue((uint64_t)Type << 56 | 1),
    m_LastCompletedFenceValue((uint64_t)Type << 56),
    m_AllocatorPool(Type)
{
}

CommandQueue::~CommandQueue()
{
    Shutdown();
}

void CommandQueue::Shutdown()
{
    if (m_CommandQueue == nullptr)
        return;

    m_AllocatorPool.Shutdown();

    CloseHandle(m_FenceEventHandle);

    m_pFence->Release();
    m_pFence = nullptr;

    m_CommandQueue->Release();
    m_CommandQueue = nullptr;
}

CommandListManager::CommandListManager() :
    m_Device(nullptr),
    m_GraphicsQueue(D3D12_COMMAND_LIST_TYPE_DIRECT),
    m_ComputeQueue(D3D12_COMMAND_LIST_TYPE_COMPUTE),
    m_CopyQueue(D3D12_COMMAND_LIST_TYPE_COPY)
{
}

CommandListManager::~CommandListManager()
{
    Shutdown();
}

void CommandListManager::Shutdown()
{
    m_GraphicsQueue.Shutdown();
    m_ComputeQueue.Shutdown();
    m_CopyQueue.Shutdown();
}

void CommandQueue::Create(ID3D12Device* pDevice)
{
    ASSERT(pDevice != nullptr);
    ASSERT(!IsReady());
    ASSERT(m_AllocatorPool.Size() == 0);

    D3D12_COMMAND_QUEUE_DESC QueueDesc = {};
    QueueDesc.Type = m_Type;
    QueueDesc.NodeMask = 1;
    pDevice->CreateCommandQueue(&QueueDesc, MY_IID_PPV_ARGS(&m_CommandQueue));
    m_CommandQueue->SetName(L"CommandListManager::m_CommandQueue");

    ASSERT_SUCCEEDED(pDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, MY_IID_PPV_ARGS(&m_pFence)));
    m_pFence->SetName(L"CommandListManager::m_pFence");
    m_pFence->Signal((uint64_t)m_Type << 56);

    m_FenceEventHandle = CreateEvent(nullptr, false, false, nullptr);
    ASSERT(m_FenceEventHandle != INVALID_HANDLE_VALUE);

    m_AllocatorPool.Create(pDevice);

    ASSERT(IsReady());
}

void CommandListManager::Create(ID3D12Device* pDevice)
{
    ASSERT(pDevice != nullptr);

    m_Device = pDevice;

    m_GraphicsQueue.Create(pDevice);
    m_ComputeQueue.Create(pDevice);
    m_CopyQueue.Create(pDevice);
}

void CommandListManager::CreateNewCommandList( D3D12_COMMAND_LIST_TYPE Type, ID3D12GraphicsCommandList** List, ID3D12CommandAllocator** Allocator )
{
    ASSERT(Type != D3D12_COMMAND_LIST_TYPE_BUNDLE, "Bundles are not yet supported");
    switch (Type)
    {
    case D3D12_COMMAND_LIST_TYPE_DIRECT: *Allocator = m_GraphicsQueue.RequestAllocator(); break;
    case D3D12_COMMAND_LIST_TYPE_BUNDLE: break;
    case D3D12_COMMAND_LIST_TYPE_COMPUTE: *Allocator = m_ComputeQueue.RequestAllocator(); break;
    case D3D12_COMMAND_LIST_TYPE_COPY: *Allocator = m_CopyQueue.RequestAllocator(); break;
    }

    ASSERT_SUCCEEDED( m_Device->CreateCommandList(1, Type, *Allocator, nullptr, MY_IID_PPV_ARGS(List)) );
    (*List)->SetName(L"CommandList");
}

uint64_t CommandQueue::ExecuteCommandList( ID3D12CommandList* List )
{
    std::lock_guard<std::mutex> LockGuard(m_FenceMutex);

    ASSERT_SUCCEEDED(((ID3D12GraphicsCommandList*)List)->Close());

    // Kickoff the command list
    m_CommandQueue->ExecuteCommandLists(1, &List);

    // Signal the next fence value (with the GPU)
    m_CommandQueue->Signal(m_pFence, m_NextFenceValue);

    // And increment the fence value.
    return m_NextFenceValue++;
}

uint64_t CommandQueue::IncrementFence(void)
{
    std::lock_guard<std::mutex> LockGuard(m_FenceMutex);
    m_CommandQueue->Signal(m_pFence, m_NextFenceValue);
    return m_NextFenceValue++;
}

bool CommandQueue::IsFenceComplete(uint64_t FenceValue)
{
    // Avoid querying the fence value by testing against the last one seen.
    // The max() is to protect against an unlikely race condition that could cause the last
    // completed fence value to regress.
    if (FenceValue > m_LastCompletedFenceValue)
        m_LastCompletedFenceValue = std::max(m_LastCompletedFenceValue, m_pFence->GetCompletedValue());

    return FenceValue <= m_LastCompletedFenceValue;
}

namespace Graphics
{
    extern CommandListManager g_CommandManager;
}

void CommandQueue::StallForFence(uint64_t FenceValue)
{
    CommandQueue& Producer = Graphics::g_CommandManager.GetQueue((D3D12_COMMAND_LIST_TYPE)(FenceValue >> 56));
    m_CommandQueue->Wait(Producer.m_pFence, FenceValue);
}

void CommandQueue::StallForProducer(CommandQueue& Producer)
{
    ASSERT(Producer.m_NextFenceValue > 0);
    m_CommandQueue->Wait(Producer.m_pFence, Producer.m_NextFenceValue - 1);
}

void CommandQueue::WaitForFence(uint64_t FenceValue)
{
    if (IsFenceComplete(FenceValue))
        return;

    // TODO:  Think about how this might affect a multi-threaded situation.  Suppose thread A
    // wants to wait for fence 100, then thread B comes along and wants to wait for 99.  If
    // the fence can only have one event set on completion, then thread B has to wait for
    // 100 before it knows 99 is ready.  Maybe insert sequential events?
    {
        std::lock_guard<std::mutex> LockGuard(m_EventMutex);

        m_pFence->SetEventOnCompletion(FenceValue, m_FenceEventHandle);
        WaitForSingleObject(m_FenceEventHandle, INFINITE);
        m_LastCompletedFenceValue = FenceValue;
    }
}

void CommandListManager::WaitForFence(uint64_t FenceValue)
{
    CommandQueue& Producer = Graphics::g_CommandManager.GetQueue((D3D12_COMMAND_LIST_TYPE)(FenceValue >> 56));
    Producer.WaitForFence(FenceValue);
}

ID3D12CommandAllocator* CommandQueue::RequestAllocator()
{
    uint64_t CompletedFence = m_pFence->GetCompletedValue();

    return m_AllocatorPool.RequestAllocator(CompletedFence);
}

void CommandQueue::DiscardAllocator(uint64_t FenceValue, ID3D12CommandAllocator* Allocator)
{
    m_AllocatorPool.DiscardAllocator(FenceValue, Allocator);
}
<commit_msg>Fixed a bug with CreateEvent() error handling.<commit_after>//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
// Developed by Minigraph
//
// Author:  James Stanard
//

#include "pch.h"
#include "CommandListManager.h"

CommandQueue::CommandQueue(D3D12_COMMAND_LIST_TYPE Type) :
    m_Type(Type),
    m_CommandQueue(nullptr),
    m_pFence(nullptr),
    m_NextFenceValue((uint64_t)Type << 56 | 1),
    m_LastCompletedFenceValue((uint64_t)Type << 56),
    m_AllocatorPool(Type)
{
}

CommandQueue::~CommandQueue()
{
    Shutdown();
}

void CommandQueue::Shutdown()
{
    if (m_CommandQueue == nullptr)
        return;

    m_AllocatorPool.Shutdown();

    CloseHandle(m_FenceEventHandle);

    m_pFence->Release();
    m_pFence = nullptr;

    m_CommandQueue->Release();
    m_CommandQueue = nullptr;
}

CommandListManager::CommandListManager() :
    m_Device(nullptr),
    m_GraphicsQueue(D3D12_COMMAND_LIST_TYPE_DIRECT),
    m_ComputeQueue(D3D12_COMMAND_LIST_TYPE_COMPUTE),
    m_CopyQueue(D3D12_COMMAND_LIST_TYPE_COPY)
{
}

CommandListManager::~CommandListManager()
{
    Shutdown();
}

void CommandListManager::Shutdown()
{
    m_GraphicsQueue.Shutdown();
    m_ComputeQueue.Shutdown();
    m_CopyQueue.Shutdown();
}

void CommandQueue::Create(ID3D12Device* pDevice)
{
    ASSERT(pDevice != nullptr);
    ASSERT(!IsReady());
    ASSERT(m_AllocatorPool.Size() == 0);

    D3D12_COMMAND_QUEUE_DESC QueueDesc = {};
    QueueDesc.Type = m_Type;
    QueueDesc.NodeMask = 1;
    pDevice->CreateCommandQueue(&QueueDesc, MY_IID_PPV_ARGS(&m_CommandQueue));
    m_CommandQueue->SetName(L"CommandListManager::m_CommandQueue");

    ASSERT_SUCCEEDED(pDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, MY_IID_PPV_ARGS(&m_pFence)));
    m_pFence->SetName(L"CommandListManager::m_pFence");
    m_pFence->Signal((uint64_t)m_Type << 56);

    m_FenceEventHandle = CreateEvent(nullptr, false, false, nullptr);
    ASSERT(m_FenceEventHandle != NULL);

    m_AllocatorPool.Create(pDevice);

    ASSERT(IsReady());
}

void CommandListManager::Create(ID3D12Device* pDevice)
{
    ASSERT(pDevice != nullptr);

    m_Device = pDevice;

    m_GraphicsQueue.Create(pDevice);
    m_ComputeQueue.Create(pDevice);
    m_CopyQueue.Create(pDevice);
}

void CommandListManager::CreateNewCommandList( D3D12_COMMAND_LIST_TYPE Type, ID3D12GraphicsCommandList** List, ID3D12CommandAllocator** Allocator )
{
    ASSERT(Type != D3D12_COMMAND_LIST_TYPE_BUNDLE, "Bundles are not yet supported");
    switch (Type)
    {
    case D3D12_COMMAND_LIST_TYPE_DIRECT: *Allocator = m_GraphicsQueue.RequestAllocator(); break;
    case D3D12_COMMAND_LIST_TYPE_BUNDLE: break;
    case D3D12_COMMAND_LIST_TYPE_COMPUTE: *Allocator = m_ComputeQueue.RequestAllocator(); break;
    case D3D12_COMMAND_LIST_TYPE_COPY: *Allocator = m_CopyQueue.RequestAllocator(); break;
    }

    ASSERT_SUCCEEDED( m_Device->CreateCommandList(1, Type, *Allocator, nullptr, MY_IID_PPV_ARGS(List)) );
    (*List)->SetName(L"CommandList");
}

uint64_t CommandQueue::ExecuteCommandList( ID3D12CommandList* List )
{
    std::lock_guard<std::mutex> LockGuard(m_FenceMutex);

    ASSERT_SUCCEEDED(((ID3D12GraphicsCommandList*)List)->Close());

    // Kickoff the command list
    m_CommandQueue->ExecuteCommandLists(1, &List);

    // Signal the next fence value (with the GPU)
    m_CommandQueue->Signal(m_pFence, m_NextFenceValue);

    // And increment the fence value.
    return m_NextFenceValue++;
}

uint64_t CommandQueue::IncrementFence(void)
{
    std::lock_guard<std::mutex> LockGuard(m_FenceMutex);
    m_CommandQueue->Signal(m_pFence, m_NextFenceValue);
    return m_NextFenceValue++;
}

bool CommandQueue::IsFenceComplete(uint64_t FenceValue)
{
    // Avoid querying the fence value by testing against the last one seen.
    // The max() is to protect against an unlikely race condition that could cause the last
    // completed fence value to regress.
    if (FenceValue > m_LastCompletedFenceValue)
        m_LastCompletedFenceValue = std::max(m_LastCompletedFenceValue, m_pFence->GetCompletedValue());

    return FenceValue <= m_LastCompletedFenceValue;
}

namespace Graphics
{
    extern CommandListManager g_CommandManager;
}

void CommandQueue::StallForFence(uint64_t FenceValue)
{
    CommandQueue& Producer = Graphics::g_CommandManager.GetQueue((D3D12_COMMAND_LIST_TYPE)(FenceValue >> 56));
    m_CommandQueue->Wait(Producer.m_pFence, FenceValue);
}

void CommandQueue::StallForProducer(CommandQueue& Producer)
{
    ASSERT(Producer.m_NextFenceValue > 0);
    m_CommandQueue->Wait(Producer.m_pFence, Producer.m_NextFenceValue - 1);
}

void CommandQueue::WaitForFence(uint64_t FenceValue)
{
    if (IsFenceComplete(FenceValue))
        return;

    // TODO:  Think about how this might affect a multi-threaded situation.  Suppose thread A
    // wants to wait for fence 100, then thread B comes along and wants to wait for 99.  If
    // the fence can only have one event set on completion, then thread B has to wait for
    // 100 before it knows 99 is ready.  Maybe insert sequential events?
    {
        std::lock_guard<std::mutex> LockGuard(m_EventMutex);

        m_pFence->SetEventOnCompletion(FenceValue, m_FenceEventHandle);
        WaitForSingleObject(m_FenceEventHandle, INFINITE);
        m_LastCompletedFenceValue = FenceValue;
    }
}

void CommandListManager::WaitForFence(uint64_t FenceValue)
{
    CommandQueue& Producer = Graphics::g_CommandManager.GetQueue((D3D12_COMMAND_LIST_TYPE)(FenceValue >> 56));
    Producer.WaitForFence(FenceValue);
}

ID3D12CommandAllocator* CommandQueue::RequestAllocator()
{
    uint64_t CompletedFence = m_pFence->GetCompletedValue();

    return m_AllocatorPool.RequestAllocator(CompletedFence);
}

void CommandQueue::DiscardAllocator(uint64_t FenceValue, ID3D12CommandAllocator* Allocator)
{
    m_AllocatorPool.DiscardAllocator(FenceValue, Allocator);
}
<|endoftext|>


<commit_before>#include "umundo/core.h"
#include <iostream>
#include <stdio.h>

using namespace umundo;

static int receives = 0;
static Monitor monitor;

class TestDiscoverer : public ResultSet<NodeStub> {
public:
	TestDiscoverer() {
	}
	void added(shared_ptr<NodeStub> node) {
		printf("node added!\n");
		assert(node->getIP().size() >= 7);
		receives++;
		UMUNDO_SIGNAL(monitor);
	}
	void removed(shared_ptr<NodeStub> node) {

	}
	void changed(shared_ptr<NodeStub> node) {

	}
};

class TestDiscoverable : public Node {
public:
	TestDiscoverable(string domain) : Node(domain) {
	}
};

int main(int argc, char** argv, char** envp) {
//	setenv("UMUNDO_LOGLEVEL", "4", 1);

	string hostId = Host::getHostId();
	std::cout << "HostId:" << hostId << std::endl;

	TestDiscoverer* testDiscoverer = new TestDiscoverer();
	shared_ptr<NodeQuery> query = shared_ptr<NodeQuery>(new NodeQuery(hostId + "fooDomain", testDiscoverer));
	Discovery::browse(query);

	TestDiscoverable* testDiscoverable = new TestDiscoverable(hostId + "fooDomain");
	Discovery::add(testDiscoverable);
	while(receives < 1)
		UMUNDO_WAIT(monitor);

	// test node / publisher / subscriber churn
	for (int i = 0; i < 2; i++) {
		Node* node1 = new Node(hostId);
		Node* node2 = new Node(hostId);
		for (int j = 0; j < 2; j++) {
			Subscriber* sub1 = new Subscriber("foo", NULL);
			Subscriber* sub2 = new Subscriber("foo", NULL);
			Subscriber* sub3 = new Subscriber("foo", NULL);
			Publisher* pub = new Publisher("foo");

			int subs = 0;
			(void)subs;
			node1->addPublisher(pub);
			subs = pub->waitForSubscribers(0);
			assert(subs == 0);

			node2->addSubscriber(sub1);
			subs = pub->waitForSubscribers(1);
			assert(subs == 1);

			node2->addSubscriber(sub2);
			subs = pub->waitForSubscribers(2);
			assert(subs == 2);

			node2->addSubscriber(sub3);
			subs = pub->waitForSubscribers(3);
			assert(subs == 3);

			node2->removeSubscriber(sub1);
			Thread::sleepMs(50);
			subs = pub->waitForSubscribers(0);
			assert(subs == 2);

			node2->removeSubscriber(sub2);
			Thread::sleepMs(50);
			subs = pub->waitForSubscribers(0);
			assert(subs == 1);

			node2->removeSubscriber(sub3);
			Thread::sleepMs(50);
			subs = pub->waitForSubscribers(0);
			assert(subs == 0);

			node2->removeSubscriber(sub1);
			node2->removeSubscriber(sub2);
			node2->removeSubscriber(sub3);
			node1->removePublisher(pub);

			delete sub1;
			delete sub2;
			delete sub3;
			delete pub;
		}
		delete node1;
		delete node2;
	}
}
<commit_msg>some more test output<commit_after>#include "umundo/core.h"
#include <iostream>
#include <stdio.h>

using namespace umundo;

static int receives = 0;
static Monitor monitor;

class TestDiscoverer : public ResultSet<NodeStub> {
public:
	TestDiscoverer() {
	}
	void added(shared_ptr<NodeStub> node) {
		printf("node added!\n");
		assert(node->getIP().size() >= 7);
		receives++;
		UMUNDO_SIGNAL(monitor);
	}
	void removed(shared_ptr<NodeStub> node) {

	}
	void changed(shared_ptr<NodeStub> node) {

	}
};

class TestDiscoverable : public Node {
public:
	TestDiscoverable(string domain) : Node(domain) {
	}
};

int main(int argc, char** argv, char** envp) {
//	setenv("UMUNDO_LOGLEVEL", "4", 1);

	string hostId = Host::getHostId();
	std::cout << "HostId:" << hostId << std::endl;

	TestDiscoverer* testDiscoverer = new TestDiscoverer();
	shared_ptr<NodeQuery> query = shared_ptr<NodeQuery>(new NodeQuery(hostId + "fooDomain", testDiscoverer));
	Discovery::browse(query);

	TestDiscoverable* testDiscoverable = new TestDiscoverable(hostId + "fooDomain");
	Discovery::add(testDiscoverable);
	while(receives < 1)
		UMUNDO_WAIT(monitor);
	std::cout << "Successfully found node via discovery" << std::endl;

	// test node / publisher / subscriber churn
	for (int i = 0; i < 2; i++) {
		Node* node1 = new Node(hostId);
		Node* node2 = new Node(hostId);
		for (int j = 0; j < 2; j++) {
			Subscriber* sub1 = new Subscriber("foo", NULL);
			Subscriber* sub2 = new Subscriber("foo", NULL);
			Subscriber* sub3 = new Subscriber("foo", NULL);
			Publisher* pub = new Publisher("foo");

			int subs = 0;
			(void)subs;
			node1->addPublisher(pub);
			subs = pub->waitForSubscribers(0);
			assert(subs == 0);

			node2->addSubscriber(sub1);
			std::cout << "Waiting for 1st subscriber" << std::endl;
			subs = pub->waitForSubscribers(1);
			assert(subs == 1);

			node2->addSubscriber(sub2);
			std::cout << "Waiting for 2nd subscriber" << std::endl;
			subs = pub->waitForSubscribers(2);
			assert(subs == 2);

			node2->addSubscriber(sub3);
			std::cout << "Waiting for 3rd subscriber" << std::endl;
			subs = pub->waitForSubscribers(3);
			assert(subs == 3);

			node2->removeSubscriber(sub1);
			Thread::sleepMs(50);
			std::cout << "Removed 1st subscriber" << std::endl;
			subs = pub->waitForSubscribers(0);
			assert(subs == 2);

			node2->removeSubscriber(sub2);
			std::cout << "Removed 2nd subscriber" << std::endl;
			Thread::sleepMs(50);
			subs = pub->waitForSubscribers(0);
			assert(subs == 1);

			node2->removeSubscriber(sub3);
			std::cout << "Removed 3rd subscriber" << std::endl;
			Thread::sleepMs(50);
			subs = pub->waitForSubscribers(0);
			assert(subs == 0);

			std::cout << "Successfully connected subscribers to publishers" << std::endl;

			node2->removeSubscriber(sub1);
			node2->removeSubscriber(sub2);
			node2->removeSubscriber(sub3);
			node1->removePublisher(pub);

			delete sub1;
			delete sub2;
			delete sub3;
			delete pub;
		}
		delete node1;
		delete node2;
	}
}
<|endoftext|>


<commit_before>#include "firestore/src/include/firebase/firestore.h"

#include <cassert>
#include <map>

#include "app/meta/move.h"
#include "app/src/assert.h"
#include "app/src/cleanup_notifier.h"
#include "app/src/include/firebase/version.h"
#include "app/src/log.h"
#include "app/src/util.h"
#include "firestore/src/common/futures.h"

#if defined(__ANDROID__)
#include "firestore/src/android/firestore_android.h"
#elif defined(FIRESTORE_STUB_BUILD)
#include "firestore/src/stub/firestore_stub.h"
#else
#include "firestore/src/ios/firestore_ios.h"
#endif  // defined(__ANDROID__)

namespace firebase {
namespace firestore {

DEFINE_FIREBASE_VERSION_STRING(FirebaseFirestore);

namespace {

Mutex g_firestores_lock;  // NOLINT
std::map<App*, Firestore*>* g_firestores = nullptr;

// Ensures that the cache is initialized.
// Prerequisite: `g_firestores_lock` must be locked before calling this
// function.
std::map<App*, Firestore*>* FirestoreCache() {
  if (!g_firestores) {
    g_firestores = new std::map<App*, Firestore*>();
  }
  return g_firestores;
}

// Prerequisite: `g_firestores_lock` must be locked before calling this
// function.
Firestore* FindFirestoreInCache(App* app, InitResult* init_result_out) {
  auto* cache = FirestoreCache();

  auto found = cache->find(app);
  if (found != cache->end()) {
    if (init_result_out) *init_result_out = kInitResultSuccess;
    return found->second;
  }

  return nullptr;
}

InitResult CheckInitialized(const FirestoreInternal& firestore) {
  if (!firestore.initialized()) {
    return kInitResultFailedMissingDependency;
  }

  return kInitResultSuccess;
}

}  // namespace

Firestore* Firestore::GetInstance(App* app, InitResult* init_result_out) {
  FIREBASE_ASSERT_MESSAGE(app != nullptr,
                          "Provided firebase::App must not be null.");

  MutexLock lock(g_firestores_lock);

  Firestore* from_cache = FindFirestoreInCache(app, init_result_out);
  if (from_cache) {
    return from_cache;
  }

  return AddFirestoreToCache(new Firestore(app), init_result_out);
}

Firestore* Firestore::GetInstance(InitResult* init_result_out) {
  App* app = App::GetInstance();
  FIREBASE_ASSERT_MESSAGE(app, "You must call firebase::App.Create first.");
  return Firestore::GetInstance(app, init_result_out);
}

Firestore* Firestore::CreateFirestore(App* app, FirestoreInternal* internal,
                                      InitResult* init_result_out) {
  FIREBASE_ASSERT_MESSAGE(app != nullptr,
                          "Provided firebase::App must not be null.");
  FIREBASE_ASSERT_MESSAGE(internal != nullptr,
                          "Provided FirestoreInternal must not be null.");

  MutexLock lock(g_firestores_lock);

  Firestore* from_cache = FindFirestoreInCache(app, init_result_out);
  FIREBASE_ASSERT_MESSAGE(from_cache == nullptr,
                          "Firestore must not be created already");

  return AddFirestoreToCache(new Firestore(internal), init_result_out);
}

Firestore* Firestore::AddFirestoreToCache(Firestore* firestore,
                                          InitResult* init_result_out) {
  InitResult init_result = CheckInitialized(*firestore->internal_);
  if (init_result_out) {
    *init_result_out = init_result;
  }
  if (init_result != kInitResultSuccess) {
    delete firestore;
    return nullptr;
  }

  // Once we remove STLPort support, change this back to `emplace`.
  FirestoreCache()->insert(std::make_pair(firestore->app(), firestore));
  return firestore;
}

Firestore::Firestore(::firebase::App* app)
    : Firestore{new FirestoreInternal{app}} {}

Firestore::Firestore(FirestoreInternal* internal)
    // TODO(zxu): use make_unique once it is supported for our build here.
    : internal_(internal) {
  if (internal_->initialized()) {
    CleanupNotifier* app_notifier = CleanupNotifier::FindByOwner(app());
    assert(app_notifier);
    app_notifier->RegisterObject(this, [](void* object) {
      Firestore* firestore = reinterpret_cast<Firestore*>(object);
      LogWarning(
          "Firestore object 0x%08x should be deleted before the App 0x%08x it "
          "depends upon.",
          static_cast<int>(reinterpret_cast<intptr_t>(firestore)),
          static_cast<int>(reinterpret_cast<intptr_t>(firestore->app())));
      firestore->DeleteInternal();
    });
  }
}

Firestore::~Firestore() { DeleteInternal(); }

void Firestore::DeleteInternal() {
  MutexLock lock(g_firestores_lock);

  if (!internal_) return;

  App* my_app = app();

  // Only need to unregister if internal_ is initialized.
  if (internal_->initialized()) {
    CleanupNotifier* app_notifier = CleanupNotifier::FindByOwner(my_app);
    assert(app_notifier);
    app_notifier->UnregisterObject(this);
  }

  // Force cleanup to happen first.
  internal_->cleanup().CleanupAll();
  delete internal_;
  internal_ = nullptr;
  // If a Firestore is explicitly deleted, remove it from our cache.
  FirestoreCache()->erase(my_app);
  // If it's the last one, delete the map.
  if (g_firestores->empty()) {
    delete g_firestores;
    g_firestores = nullptr;
  }
}

const App* Firestore::app() const {
  if (!internal_) return {};
  return internal_->app();
}

App* Firestore::app() {
  if (!internal_) return {};
  return internal_->app();
}

CollectionReference Firestore::Collection(const char* collection_path) const {
  FIREBASE_ASSERT_MESSAGE(collection_path != nullptr,
                          "Provided collection path must not be null");
  if (!internal_) return {};
  return internal_->Collection(collection_path);
}

CollectionReference Firestore::Collection(
    const std::string& collection_path) const {
  return Collection(collection_path.c_str());
}

DocumentReference Firestore::Document(const char* document_path) const {
  if (!internal_) return {};
  return internal_->Document(document_path);
}

DocumentReference Firestore::Document(const std::string& document_path) const {
  return Document(document_path.c_str());
}

Query Firestore::CollectionGroup(const std::string& collection_id) const {
  if (!internal_) return {};
  return internal_->CollectionGroup(collection_id.c_str());
}

Settings Firestore::settings() const {
  if (!internal_) return {};
  return internal_->settings();
}

void Firestore::set_settings(const Settings& settings) {
  if (!internal_) return;
  internal_->set_settings(settings);
}

WriteBatch Firestore::batch() const {
  if (!internal_) return {};
  return internal_->batch();
}

Future<void> Firestore::RunTransaction(TransactionFunction* update) {
  if (!internal_) return FailedFuture<void>();
  return internal_->RunTransaction(update);
}

#if defined(FIREBASE_USE_STD_FUNCTION) || defined(DOXYGEN)
Future<void> Firestore::RunTransaction(
    std::function<Error(Transaction*, std::string*)> update) {
  FIREBASE_ASSERT_MESSAGE(update, "invalid update parameter is passed in.");
  if (!internal_) return FailedFuture<void>();
  return internal_->RunTransaction(firebase::Move(update));
}
#endif  // defined(FIREBASE_USE_STD_FUNCTION) || defined(DOXYGEN)

Future<void> Firestore::RunTransactionLastResult() {
  if (!internal_) return FailedFuture<void>();
  return internal_->RunTransactionLastResult();
}

Future<void> Firestore::DisableNetwork() {
  if (!internal_) return FailedFuture<void>();
  return internal_->DisableNetwork();
}

Future<void> Firestore::DisableNetworkLastResult() {
  if (!internal_) return FailedFuture<void>();
  return internal_->DisableNetworkLastResult();
}

Future<void> Firestore::EnableNetwork() {
  if (!internal_) return FailedFuture<void>();
  return internal_->EnableNetwork();
}

Future<void> Firestore::EnableNetworkLastResult() {
  if (!internal_) return FailedFuture<void>();
  return internal_->EnableNetworkLastResult();
}

Future<void> Firestore::Terminate() {
  if (!internal_) return FailedFuture<void>();
  FirestoreCache()->erase(app());
  return internal_->Terminate();
}

Future<void> Firestore::TerminateLastResult() {
  if (!internal_) return FailedFuture<void>();
  return internal_->TerminateLastResult();
}

Future<void> Firestore::WaitForPendingWrites() {
  if (!internal_) return FailedFuture<void>();
  return internal_->WaitForPendingWrites();
}

Future<void> Firestore::WaitForPendingWritesLastResult() {
  if (!internal_) return FailedFuture<void>();
  return internal_->WaitForPendingWritesLastResult();
}

Future<void> Firestore::ClearPersistence() {
  if (!internal_) return FailedFuture<void>();
  return internal_->ClearPersistence();
}

Future<void> Firestore::ClearPersistenceLastResult() {
  if (!internal_) return FailedFuture<void>();
  return internal_->ClearPersistenceLastResult();
}

}  // namespace firestore
}  // namespace firebase
<commit_msg>Enable iOS/Android integration tests as part of presubmit check_tests.<commit_after>#include "firestore/src/include/firebase/firestore.h"

#include <cassert>
#include <map>

#include "app/meta/move.h"
#include "app/src/assert.h"
#include "app/src/cleanup_notifier.h"
#include "app/src/include/firebase/version.h"
#include "app/src/log.h"
#include "app/src/util.h"
#include "firestore/src/common/futures.h"

#if defined(__ANDROID__)
#include "firestore/src/android/firestore_android.h"
#elif defined(FIRESTORE_STUB_BUILD)
#include "firestore/src/stub/firestore_stub.h"
#else
#include "firestore/src/ios/firestore_ios.h"
#endif  // defined(__ANDROID__)

namespace firebase {
namespace firestore {

DEFINE_FIREBASE_VERSION_STRING(FirebaseFirestore);

namespace {

Mutex g_firestores_lock;  // NOLINT
std::map<App*, Firestore*>* g_firestores = nullptr;

// Ensures that the cache is initialized.
// Prerequisite: `g_firestores_lock` must be locked before calling this
// function.
std::map<App*, Firestore*>* FirestoreCache() {
  if (!g_firestores) {
    g_firestores = new std::map<App*, Firestore*>();
  }
  return g_firestores;
}

// Prerequisite: `g_firestores_lock` must be locked before calling this
// function.
Firestore* FindFirestoreInCache(App* app, InitResult* init_result_out) {
  auto* cache = FirestoreCache();

  auto found = cache->find(app);
  if (found != cache->end()) {
    if (init_result_out) *init_result_out = kInitResultSuccess;
    return found->second;
  }

  return nullptr;
}

InitResult CheckInitialized(const FirestoreInternal& firestore) {
  if (!firestore.initialized()) {
    return kInitResultFailedMissingDependency;
  }

  return kInitResultSuccess;
}

}  // namespace

Firestore* Firestore::GetInstance(App* app, InitResult* init_result_out) {
  FIREBASE_ASSERT_MESSAGE(app != nullptr,
                          "Provided firebase::App must not be null.");

  MutexLock lock(g_firestores_lock);

  Firestore* from_cache = FindFirestoreInCache(app, init_result_out);
  if (from_cache) {
    return from_cache;
  }

  return AddFirestoreToCache(new Firestore(app), init_result_out);
}

Firestore* Firestore::GetInstance(InitResult* init_result_out) {
  App* app = App::GetInstance();
  FIREBASE_ASSERT_MESSAGE(app, "You must call firebase::App.Create first.");
  return Firestore::GetInstance(app, init_result_out);
}

Firestore* Firestore::CreateFirestore(App* app, FirestoreInternal* internal,
                                      InitResult* init_result_out) {
  FIREBASE_ASSERT_MESSAGE(app != nullptr,
                          "Provided firebase::App must not be null.");
  FIREBASE_ASSERT_MESSAGE(internal != nullptr,
                          "Provided FirestoreInternal must not be null.");

  MutexLock lock(g_firestores_lock);

  Firestore* from_cache = FindFirestoreInCache(app, init_result_out);
  FIREBASE_ASSERT_MESSAGE(from_cache == nullptr,
                          "Firestore must not be created already");

  return AddFirestoreToCache(new Firestore(internal), init_result_out);
}

Firestore* Firestore::AddFirestoreToCache(Firestore* firestore,
                                          InitResult* init_result_out) {
  InitResult init_result = CheckInitialized(*firestore->internal_);
  if (init_result_out) {
    *init_result_out = init_result;
  }
  if (init_result != kInitResultSuccess) {
    delete firestore;
    return nullptr;
  }

  // Once we remove STLPort support, change this back to `emplace`.
  FirestoreCache()->insert(std::make_pair(firestore->app(), firestore));
  return firestore;
}

Firestore::Firestore(::firebase::App* app)
    : Firestore{new FirestoreInternal{app}} {}

Firestore::Firestore(FirestoreInternal* internal)
    // TODO(wuandy): use make_unique once it is supported for our build here.
    : internal_(internal) {
  if (internal_->initialized()) {
    CleanupNotifier* app_notifier = CleanupNotifier::FindByOwner(app());
    assert(app_notifier);
    app_notifier->RegisterObject(this, [](void* object) {
      Firestore* firestore = reinterpret_cast<Firestore*>(object);
      LogWarning(
          "Firestore object 0x%08x should be deleted before the App 0x%08x it "
          "depends upon.",
          static_cast<int>(reinterpret_cast<intptr_t>(firestore)),
          static_cast<int>(reinterpret_cast<intptr_t>(firestore->app())));
      firestore->DeleteInternal();
    });
  }
}

Firestore::~Firestore() { DeleteInternal(); }

void Firestore::DeleteInternal() {
  MutexLock lock(g_firestores_lock);

  if (!internal_) return;

  App* my_app = app();

  // Only need to unregister if internal_ is initialized.
  if (internal_->initialized()) {
    CleanupNotifier* app_notifier = CleanupNotifier::FindByOwner(my_app);
    assert(app_notifier);
    app_notifier->UnregisterObject(this);
  }

  // Force cleanup to happen first.
  internal_->cleanup().CleanupAll();
  delete internal_;
  internal_ = nullptr;
  // If a Firestore is explicitly deleted, remove it from our cache.
  FirestoreCache()->erase(my_app);
  // If it's the last one, delete the map.
  if (g_firestores->empty()) {
    delete g_firestores;
    g_firestores = nullptr;
  }
}

const App* Firestore::app() const {
  if (!internal_) return {};
  return internal_->app();
}

App* Firestore::app() {
  if (!internal_) return {};
  return internal_->app();
}

CollectionReference Firestore::Collection(const char* collection_path) const {
  FIREBASE_ASSERT_MESSAGE(collection_path != nullptr,
                          "Provided collection path must not be null");
  if (!internal_) return {};
  return internal_->Collection(collection_path);
}

CollectionReference Firestore::Collection(
    const std::string& collection_path) const {
  return Collection(collection_path.c_str());
}

DocumentReference Firestore::Document(const char* document_path) const {
  if (!internal_) return {};
  return internal_->Document(document_path);
}

DocumentReference Firestore::Document(const std::string& document_path) const {
  return Document(document_path.c_str());
}

Query Firestore::CollectionGroup(const std::string& collection_id) const {
  if (!internal_) return {};
  return internal_->CollectionGroup(collection_id.c_str());
}

Settings Firestore::settings() const {
  if (!internal_) return {};
  return internal_->settings();
}

void Firestore::set_settings(const Settings& settings) {
  if (!internal_) return;
  internal_->set_settings(settings);
}

WriteBatch Firestore::batch() const {
  if (!internal_) return {};
  return internal_->batch();
}

Future<void> Firestore::RunTransaction(TransactionFunction* update) {
  if (!internal_) return FailedFuture<void>();
  return internal_->RunTransaction(update);
}

#if defined(FIREBASE_USE_STD_FUNCTION) || defined(DOXYGEN)
Future<void> Firestore::RunTransaction(
    std::function<Error(Transaction*, std::string*)> update) {
  FIREBASE_ASSERT_MESSAGE(update, "invalid update parameter is passed in.");
  if (!internal_) return FailedFuture<void>();
  return internal_->RunTransaction(firebase::Move(update));
}
#endif  // defined(FIREBASE_USE_STD_FUNCTION) || defined(DOXYGEN)

Future<void> Firestore::RunTransactionLastResult() {
  if (!internal_) return FailedFuture<void>();
  return internal_->RunTransactionLastResult();
}

Future<void> Firestore::DisableNetwork() {
  if (!internal_) return FailedFuture<void>();
  return internal_->DisableNetwork();
}

Future<void> Firestore::DisableNetworkLastResult() {
  if (!internal_) return FailedFuture<void>();
  return internal_->DisableNetworkLastResult();
}

Future<void> Firestore::EnableNetwork() {
  if (!internal_) return FailedFuture<void>();
  return internal_->EnableNetwork();
}

Future<void> Firestore::EnableNetworkLastResult() {
  if (!internal_) return FailedFuture<void>();
  return internal_->EnableNetworkLastResult();
}

Future<void> Firestore::Terminate() {
  if (!internal_) return FailedFuture<void>();
  FirestoreCache()->erase(app());
  return internal_->Terminate();
}

Future<void> Firestore::TerminateLastResult() {
  if (!internal_) return FailedFuture<void>();
  return internal_->TerminateLastResult();
}

Future<void> Firestore::WaitForPendingWrites() {
  if (!internal_) return FailedFuture<void>();
  return internal_->WaitForPendingWrites();
}

Future<void> Firestore::WaitForPendingWritesLastResult() {
  if (!internal_) return FailedFuture<void>();
  return internal_->WaitForPendingWritesLastResult();
}

Future<void> Firestore::ClearPersistence() {
  if (!internal_) return FailedFuture<void>();
  return internal_->ClearPersistence();
}

Future<void> Firestore::ClearPersistenceLastResult() {
  if (!internal_) return FailedFuture<void>();
  return internal_->ClearPersistenceLastResult();
}

}  // namespace firestore
}  // namespace firebase
<|endoftext|>