<commit_before>/*
Copyright (c) 2015-2021 Alternative Games Ltd / Turo Lamminen

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.
*/

#ifdef RENDERER_NULL

#include "RendererInternal.h"
#include "utils/Utils.h"

namespace renderer {

RendererImpl::RendererImpl(const RendererDesc &desc)
: RendererBase(desc)
{
	SDL_Init(SDL_INIT_EVENTS);

	swapchainFormat = Format::sRGBA8;

	currentRefreshRate = 60;
	maxRefreshRate     = 60;

	recreateRingBuffer(desc.ephemeralRingBufSize);

	frames.resize(desc.swapchain.numFrames);
}

void RendererImpl::recreateRingBuffer(unsigned int newSize) {
	assert(newSize > 0);

	ringBufPtr  = 0;
	ringBufSize = newSize;
	ringBuffer.resize(newSize, 0);
	LOG_TODO("use valgrind to make sure we only write to intended parts of ring buffer");
}

RendererImpl::~RendererImpl() {
	waitForDeviceIdle();

	for (unsigned int i = 0; i < frames.size(); i++) {
		auto &f = frames.at(i);
		assert(!f.outstanding);
		deleteFrameInternal(f);
	}
	frames.clear();

	SDL_Quit();
}

bool Renderer::isRenderTargetFormatSupported(Format /* format */) const {
	LOG_TODO("actually check it...");
	return true;
}

BufferHandle Renderer::createBuffer(BufferType /* type */, uint32_t size, const void *contents) {
	assert(size != 0);
	assert(contents != nullptr);

	Buffer buffer;
	buffer.ringBufferAlloc = false;
	buffer.beginOffs       = 0;
	buffer.size            = size;

	LOG_TODO("store contents into buffer");

	return impl->buffers.add(std::move(buffer));
}

BufferHandle Renderer::createEphemeralBuffer(BufferType /* type */, uint32_t size, const void *contents) {
	assert(size != 0);
	assert(contents != nullptr);

	unsigned int beginPtr = impl->ringBufferAllocate(size, 256);

	LOG_TODO("use valgrind to enforce we only write to intended parts of ring buffer");
	memcpy(&impl->ringBuffer[beginPtr], contents, size);

	auto result    = impl->buffers.add();
	Buffer &buffer = result.first;
	buffer.ringBufferAlloc = true;
	buffer.beginOffs       = beginPtr;
	buffer.size            = size;

	impl->frames.at(impl->currentFrameIdx).ephemeralBuffers.push_back(result.second);

	return result.second;
}

FramebufferHandle Renderer::createFramebuffer(const FramebufferDesc &desc) {
	auto result = impl->framebuffers.add();
	auto &fb = result.first;
	fb.renderPass = desc.renderPass_;

	return result.second;
}

RenderPassHandle Renderer::createRenderPass(const RenderPassDesc &desc) {
	auto result = impl->renderpasses.add();
	auto &rp    = result.first;
	rp.desc     = desc;

	return result.second;
}

PipelineHandle Renderer::createPipeline(const PipelineDesc &desc) {
	auto result = impl->pipelines.add();
	auto &pipeline = result.first;
	pipeline.desc = desc;
	return result.second;
}

RenderTargetHandle Renderer::createRenderTarget(const RenderTargetDesc &desc) {
	assert(desc.width_  > 0);
	assert(desc.height_ > 0);
	assert(desc.format_ != +Format::Invalid);

	auto result = impl->rendertargets.add();
	auto &rendertarget = result.first;
	rendertarget.desc = desc;
	return result.second;
}

SamplerHandle Renderer::createSampler(const SamplerDesc &desc) {
	Sampler sampler;
	LOG_TODO("check desc");
	sampler.desc = desc;

	return impl->samplers.add(std::move(sampler));
}

VertexShaderHandle RendererImpl::createVertexShader(const std::string &name, const ShaderMacros & /* macros */) {
	std::string vertexShaderName   = name + ".vert";

	auto result_ = vertexShaders.add();
	auto &v = result_.first;
	v.name      = vertexShaderName;

	return result_.second;
}

FragmentShaderHandle RendererImpl::createFragmentShader(const std::string &name, const ShaderMacros & /* macros */) {
	std::string fragmentShaderName = name + ".frag";

	auto result_ = fragmentShaders.add();
	auto &f = result_.first;
	f.name      = fragmentShaderName;

	return result_.second;
}

TextureHandle Renderer::createTexture(const TextureDesc &desc) {
	assert(desc.width_   > 0);
	assert(desc.height_  > 0);
	assert(desc.numMips_ > 0);

	LOG_TODO("check data");

	Texture texture;
	LOG_TODO("check desc");
	texture.desc = desc;

	return impl->textures.add(std::move(texture));
}

DSLayoutHandle Renderer::createDescriptorSetLayout(const DescriptorLayout *layout) {
	DescriptorSetLayout dsLayout;

	while (layout->type != +DescriptorType::End) {
		dsLayout.layout.push_back(*layout);
		layout++;
	}
	assert(layout->offset == 0);

	return impl->dsLayouts.add(std::move(dsLayout));
}

TextureHandle Renderer::getRenderTargetView(RenderTargetHandle /* handle */, Format /* f */) {
	TextureHandle handle;

	return handle;
}

void Renderer::deleteBuffer(BufferHandle & /* handle */) {
}

void Renderer::deleteFramebuffer(FramebufferHandle & /*  */) {
}

void Renderer::deletePipeline(PipelineHandle & /* handle */) {
}

void Renderer::deleteRenderPass(RenderPassHandle & /* handle */) {
}

void Renderer::deleteRenderTarget(RenderTargetHandle & /* handle */) {
}

void Renderer::deleteSampler(SamplerHandle & /* handle */) {
}

void Renderer::deleteTexture(TextureHandle & /* handle */) {
}

void Renderer::deleteBuffer(BufferHandle && /* handle */) {
}

void Renderer::deleteFramebuffer(FramebufferHandle && /*  */) {
}

void Renderer::deletePipeline(PipelineHandle && /* handle */) {
}

void Renderer::deleteRenderPass(RenderPassHandle && /* handle */) {
}

void Renderer::deleteRenderTarget(RenderTargetHandle && /* handle */) {
}

void Renderer::deleteSampler(SamplerHandle && /* handle */) {
}

void Renderer::deleteTexture(TextureHandle && /* handle */) {
}

void Renderer::setSwapchainDesc(const SwapchainDesc &desc) {
	impl->swapchainDesc  = desc;
}

glm::uvec2 Renderer::getDrawableSize() const {
	return glm::uvec2(impl->swapchainDesc.width, impl->swapchainDesc.height);
}

MemoryStats Renderer::getMemStats() const {
	MemoryStats stats;
	return stats;
}

void RendererImpl::waitForDeviceIdle() {
	for (unsigned int i = 0; i < frames.size(); i++) {
		auto &f = frames.at(i);
		if (f.outstanding) {
			// try to wait
			waitForFrame(i);
			assert(!f.outstanding);
		}
	}
}

void Renderer::beginFrame() {
	assert(!impl->inFrame);
	impl->inFrame       = true;
	impl->inRenderPass  = false;
	impl->validPipeline = false;
	impl->pipelineDrawn = true;

	impl->currentFrameIdx        = impl->frameNum % impl->frames.size();
	assert(impl->currentFrameIdx < impl->frames.size());
	auto &frame                  = impl->frames.at(impl->currentFrameIdx);

	// frames are a ringbuffer
	// if the frame we want to reuse is still pending on the GPU, wait for it
	if (frame.outstanding) {
		impl->waitForFrame(impl->currentFrameIdx);
	}
	assert(!frame.outstanding);
}

void Renderer::beginRenderPassSwapchain(RenderPassHandle rpHandle) {
	assert(rpHandle);
	assert(!impl->inFrame);
	impl->inFrame       = true;
	impl->inRenderPass  = false;
	impl->validPipeline = false;
	impl->pipelineDrawn = true;

	assert(!impl->renderingToSwapchain);
	impl->renderingToSwapchain = true;

	impl->currentFrameIdx        = impl->frameNum % impl->frames.size();
	assert(impl->currentFrameIdx < impl->frames.size());
	auto &frame                  = impl->frames.at(impl->currentFrameIdx);

	// frames are a ringbuffer
	// if the frame we want to reuse is still pending on the GPU, wait for it
	if (frame.outstanding) {
		impl->waitForFrame(impl->currentFrameIdx);
	}
	assert(!frame.outstanding);
}

void Renderer::presentFrame() {
	assert(impl->inFrame);
	impl->inFrame = false;

	auto &frame = impl->frames.at(impl->currentFrameIdx);

	frame.usedRingBufPtr = impl->ringBufPtr;
	frame.outstanding    = true;
	frame.lastFrameNum   = impl->frameNum;

	impl->frameNum++;
}

void RendererImpl::waitForFrame(unsigned int frameIdx) {
	assert(frameIdx < frames.size());

	Frame &frame = frames.at(frameIdx);
	assert(frame.outstanding);

	for (auto handle : frame.ephemeralBuffers) {
		Buffer &buffer = buffers.get(handle);
		if (buffer.ringBufferAlloc) {
			buffer.ringBufferAlloc = false;
		}

		assert(buffer.size   >  0);
		buffer.size = 0;
		buffer.beginOffs = 0;

		buffers.remove(handle);
	}
	frame.ephemeralBuffers.clear();
	frame.outstanding    = false;
	lastSyncedFrame      = std::max(lastSyncedFrame, frame.lastFrameNum);
	lastSyncedRingBufPtr = std::max(lastSyncedRingBufPtr, frame.usedRingBufPtr);
}

void RendererImpl::deleteFrameInternal(Frame &f) {
	assert(!f.outstanding);
}

void Renderer::beginRenderPass(RenderPassHandle rpHandle, FramebufferHandle fbHandle) {
	assert(impl->inFrame);
	assert(!impl->inRenderPass);
	assert(!impl->renderingToSwapchain);

	impl->inRenderPass  = true;
	impl->validPipeline = false;

	assert(fbHandle);
	const auto &fb = impl->framebuffers.get(fbHandle);

	// make sure renderpass and framebuffer match
	assert(fb.renderPass == rpHandle);
}

void Renderer::endRenderPass() {
	assert(impl->inFrame);
	assert(impl->inRenderPass);
	impl->inRenderPass = false;
	impl->renderingToSwapchain = false;
}

void Renderer::layoutTransition(RenderTargetHandle image, Layout src, Layout dest) {
	assert(image);
	assert(dest != +Layout::Undefined);
	assert(src != dest);
}

void Renderer::bindPipeline(PipelineHandle pipeline) {
	assert(impl->inFrame);
	assert(pipeline);
	assert(impl->inRenderPass);
	assert(impl->pipelineDrawn);
	impl->pipelineDrawn = false;
	impl->validPipeline = true;
	impl->scissorSet    = false;

	impl->currentPipeline = impl->pipelines.get(pipeline).desc;
}

void Renderer::bindIndexBuffer(BufferHandle /* buffer */, bool /* bit16 */ ) {
	assert(impl->inFrame);
	assert(impl->validPipeline);
}

void Renderer::bindVertexBuffer(unsigned int /* binding */, BufferHandle /* buffer */) {
	assert(impl->inFrame);
	assert(impl->validPipeline);
}

void Renderer::bindDescriptorSet(unsigned int /* index */, DSLayoutHandle /* layout */, const void * /* data_ */) {
	assert(impl->validPipeline);
}

void Renderer::setViewport(unsigned int /* x */, unsigned int /* y */, unsigned int /* width */, unsigned int /* height */) {
	assert(impl->inFrame);
}

void Renderer::setScissorRect(unsigned int /* x */, unsigned int /* y */, unsigned int /* width */, unsigned int /* height */) {
	assert(impl->validPipeline);
	assert(impl->currentPipeline.scissorTest_);
	impl->scissorSet = true;
}

void Renderer::blit(RenderTargetHandle source, RenderTargetHandle target) {
	assert(source);
	assert(target);

	assert(!impl->inRenderPass);
}

void Renderer::resolveMSAA(RenderTargetHandle source, RenderTargetHandle target) {
	assert(source);
	assert(target);

	assert(!impl->inRenderPass);
}

void Renderer::resolveMSAAToSwapchain(RenderTargetHandle source, Layout finalLayout) {
	assert(source);
	assert(finalLayout != +Layout::Undefined);

	assert(impl->inFrame);
	assert(!impl->inRenderPass);
	assert(!impl->renderingToSwapchain);
}

void Renderer::draw(unsigned int /* firstVertex */, unsigned int vertexCount) {
	assert(impl->inRenderPass);
	assert(impl->validPipeline);
	assert(vertexCount > 0);
	assert(!impl->currentPipeline.scissorTest_ || impl->scissorSet);
	impl->pipelineDrawn = true;
}

void Renderer::drawIndexedInstanced(unsigned int vertexCount, unsigned int instanceCount) {
	assert(impl->inRenderPass);
	assert(impl->validPipeline);
	assert(vertexCount > 0);
	assert(instanceCount > 0);
	assert(!impl->currentPipeline.scissorTest_ || impl->scissorSet);
	impl->pipelineDrawn = true;
}

void Renderer::drawIndexedOffset(unsigned int vertexCount, unsigned int /* firstIndex */, unsigned int /* minIndex */, unsigned int /* maxIndex */) {
	assert(impl->inRenderPass);
	assert(impl->validPipeline);
	assert(vertexCount > 0);
	assert(!impl->currentPipeline.scissorTest_ || impl->scissorSet);
	impl->pipelineDrawn = true;
}

} // namespace renderer

#endif //  RENDERER_NULL
<commit_msg>Refactor null Renderer::createRenderTarget<commit_after>/*
Copyright (c) 2015-2021 Alternative Games Ltd / Turo Lamminen

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.
*/

#ifdef RENDERER_NULL

#include "RendererInternal.h"
#include "utils/Utils.h"

namespace renderer {

RendererImpl::RendererImpl(const RendererDesc &desc)
: RendererBase(desc)
{
	SDL_Init(SDL_INIT_EVENTS);

	swapchainFormat = Format::sRGBA8;

	currentRefreshRate = 60;
	maxRefreshRate     = 60;

	recreateRingBuffer(desc.ephemeralRingBufSize);

	frames.resize(desc.swapchain.numFrames);
}

void RendererImpl::recreateRingBuffer(unsigned int newSize) {
	assert(newSize > 0);

	ringBufPtr  = 0;
	ringBufSize = newSize;
	ringBuffer.resize(newSize, 0);
	LOG_TODO("use valgrind to make sure we only write to intended parts of ring buffer");
}

RendererImpl::~RendererImpl() {
	waitForDeviceIdle();

	for (unsigned int i = 0; i < frames.size(); i++) {
		auto &f = frames.at(i);
		assert(!f.outstanding);
		deleteFrameInternal(f);
	}
	frames.clear();

	SDL_Quit();
}

bool Renderer::isRenderTargetFormatSupported(Format /* format */) const {
	LOG_TODO("actually check it...");
	return true;
}

BufferHandle Renderer::createBuffer(BufferType /* type */, uint32_t size, const void *contents) {
	assert(size != 0);
	assert(contents != nullptr);

	Buffer buffer;
	buffer.ringBufferAlloc = false;
	buffer.beginOffs       = 0;
	buffer.size            = size;

	LOG_TODO("store contents into buffer");

	return impl->buffers.add(std::move(buffer));
}

BufferHandle Renderer::createEphemeralBuffer(BufferType /* type */, uint32_t size, const void *contents) {
	assert(size != 0);
	assert(contents != nullptr);

	unsigned int beginPtr = impl->ringBufferAllocate(size, 256);

	LOG_TODO("use valgrind to enforce we only write to intended parts of ring buffer");
	memcpy(&impl->ringBuffer[beginPtr], contents, size);

	auto result    = impl->buffers.add();
	Buffer &buffer = result.first;
	buffer.ringBufferAlloc = true;
	buffer.beginOffs       = beginPtr;
	buffer.size            = size;

	impl->frames.at(impl->currentFrameIdx).ephemeralBuffers.push_back(result.second);

	return result.second;
}

FramebufferHandle Renderer::createFramebuffer(const FramebufferDesc &desc) {
	auto result = impl->framebuffers.add();
	auto &fb = result.first;
	fb.renderPass = desc.renderPass_;

	return result.second;
}

RenderPassHandle Renderer::createRenderPass(const RenderPassDesc &desc) {
	auto result = impl->renderpasses.add();
	auto &rp    = result.first;
	rp.desc     = desc;

	return result.second;
}

PipelineHandle Renderer::createPipeline(const PipelineDesc &desc) {
	auto result = impl->pipelines.add();
	auto &pipeline = result.first;
	pipeline.desc = desc;
	return result.second;
}

RenderTargetHandle Renderer::createRenderTarget(const RenderTargetDesc &desc) {
	assert(desc.width_  > 0);
	assert(desc.height_ > 0);
	assert(desc.format_ != +Format::Invalid);

	RenderTarget rendertarget;
	rendertarget.desc = desc;
	return impl->rendertargets.add(std::move(rendertarget));
}

SamplerHandle Renderer::createSampler(const SamplerDesc &desc) {
	Sampler sampler;
	LOG_TODO("check desc");
	sampler.desc = desc;

	return impl->samplers.add(std::move(sampler));
}

VertexShaderHandle RendererImpl::createVertexShader(const std::string &name, const ShaderMacros & /* macros */) {
	std::string vertexShaderName   = name + ".vert";

	auto result_ = vertexShaders.add();
	auto &v = result_.first;
	v.name      = vertexShaderName;

	return result_.second;
}

FragmentShaderHandle RendererImpl::createFragmentShader(const std::string &name, const ShaderMacros & /* macros */) {
	std::string fragmentShaderName = name + ".frag";

	auto result_ = fragmentShaders.add();
	auto &f = result_.first;
	f.name      = fragmentShaderName;

	return result_.second;
}

TextureHandle Renderer::createTexture(const TextureDesc &desc) {
	assert(desc.width_   > 0);
	assert(desc.height_  > 0);
	assert(desc.numMips_ > 0);

	LOG_TODO("check data");

	Texture texture;
	LOG_TODO("check desc");
	texture.desc = desc;

	return impl->textures.add(std::move(texture));
}

DSLayoutHandle Renderer::createDescriptorSetLayout(const DescriptorLayout *layout) {
	DescriptorSetLayout dsLayout;

	while (layout->type != +DescriptorType::End) {
		dsLayout.layout.push_back(*layout);
		layout++;
	}
	assert(layout->offset == 0);

	return impl->dsLayouts.add(std::move(dsLayout));
}

TextureHandle Renderer::getRenderTargetView(RenderTargetHandle /* handle */, Format /* f */) {
	TextureHandle handle;

	return handle;
}

void Renderer::deleteBuffer(BufferHandle & /* handle */) {
}

void Renderer::deleteFramebuffer(FramebufferHandle & /*  */) {
}

void Renderer::deletePipeline(PipelineHandle & /* handle */) {
}

void Renderer::deleteRenderPass(RenderPassHandle & /* handle */) {
}

void Renderer::deleteRenderTarget(RenderTargetHandle & /* handle */) {
}

void Renderer::deleteSampler(SamplerHandle & /* handle */) {
}

void Renderer::deleteTexture(TextureHandle & /* handle */) {
}

void Renderer::deleteBuffer(BufferHandle && /* handle */) {
}

void Renderer::deleteFramebuffer(FramebufferHandle && /*  */) {
}

void Renderer::deletePipeline(PipelineHandle && /* handle */) {
}

void Renderer::deleteRenderPass(RenderPassHandle && /* handle */) {
}

void Renderer::deleteRenderTarget(RenderTargetHandle && /* handle */) {
}

void Renderer::deleteSampler(SamplerHandle && /* handle */) {
}

void Renderer::deleteTexture(TextureHandle && /* handle */) {
}

void Renderer::setSwapchainDesc(const SwapchainDesc &desc) {
	impl->swapchainDesc  = desc;
}

glm::uvec2 Renderer::getDrawableSize() const {
	return glm::uvec2(impl->swapchainDesc.width, impl->swapchainDesc.height);
}

MemoryStats Renderer::getMemStats() const {
	MemoryStats stats;
	return stats;
}

void RendererImpl::waitForDeviceIdle() {
	for (unsigned int i = 0; i < frames.size(); i++) {
		auto &f = frames.at(i);
		if (f.outstanding) {
			// try to wait
			waitForFrame(i);
			assert(!f.outstanding);
		}
	}
}

void Renderer::beginFrame() {
	assert(!impl->inFrame);
	impl->inFrame       = true;
	impl->inRenderPass  = false;
	impl->validPipeline = false;
	impl->pipelineDrawn = true;

	impl->currentFrameIdx        = impl->frameNum % impl->frames.size();
	assert(impl->currentFrameIdx < impl->frames.size());
	auto &frame                  = impl->frames.at(impl->currentFrameIdx);

	// frames are a ringbuffer
	// if the frame we want to reuse is still pending on the GPU, wait for it
	if (frame.outstanding) {
		impl->waitForFrame(impl->currentFrameIdx);
	}
	assert(!frame.outstanding);
}

void Renderer::beginRenderPassSwapchain(RenderPassHandle rpHandle) {
	assert(rpHandle);
	assert(!impl->inFrame);
	impl->inFrame       = true;
	impl->inRenderPass  = false;
	impl->validPipeline = false;
	impl->pipelineDrawn = true;

	assert(!impl->renderingToSwapchain);
	impl->renderingToSwapchain = true;

	impl->currentFrameIdx        = impl->frameNum % impl->frames.size();
	assert(impl->currentFrameIdx < impl->frames.size());
	auto &frame                  = impl->frames.at(impl->currentFrameIdx);

	// frames are a ringbuffer
	// if the frame we want to reuse is still pending on the GPU, wait for it
	if (frame.outstanding) {
		impl->waitForFrame(impl->currentFrameIdx);
	}
	assert(!frame.outstanding);
}

void Renderer::presentFrame() {
	assert(impl->inFrame);
	impl->inFrame = false;

	auto &frame = impl->frames.at(impl->currentFrameIdx);

	frame.usedRingBufPtr = impl->ringBufPtr;
	frame.outstanding    = true;
	frame.lastFrameNum   = impl->frameNum;

	impl->frameNum++;
}

void RendererImpl::waitForFrame(unsigned int frameIdx) {
	assert(frameIdx < frames.size());

	Frame &frame = frames.at(frameIdx);
	assert(frame.outstanding);

	for (auto handle : frame.ephemeralBuffers) {
		Buffer &buffer = buffers.get(handle);
		if (buffer.ringBufferAlloc) {
			buffer.ringBufferAlloc = false;
		}

		assert(buffer.size   >  0);
		buffer.size = 0;
		buffer.beginOffs = 0;

		buffers.remove(handle);
	}
	frame.ephemeralBuffers.clear();
	frame.outstanding    = false;
	lastSyncedFrame      = std::max(lastSyncedFrame, frame.lastFrameNum);
	lastSyncedRingBufPtr = std::max(lastSyncedRingBufPtr, frame.usedRingBufPtr);
}

void RendererImpl::deleteFrameInternal(Frame &f) {
	assert(!f.outstanding);
}

void Renderer::beginRenderPass(RenderPassHandle rpHandle, FramebufferHandle fbHandle) {
	assert(impl->inFrame);
	assert(!impl->inRenderPass);
	assert(!impl->renderingToSwapchain);

	impl->inRenderPass  = true;
	impl->validPipeline = false;

	assert(fbHandle);
	const auto &fb = impl->framebuffers.get(fbHandle);

	// make sure renderpass and framebuffer match
	assert(fb.renderPass == rpHandle);
}

void Renderer::endRenderPass() {
	assert(impl->inFrame);
	assert(impl->inRenderPass);
	impl->inRenderPass = false;
	impl->renderingToSwapchain = false;
}

void Renderer::layoutTransition(RenderTargetHandle image, Layout src, Layout dest) {
	assert(image);
	assert(dest != +Layout::Undefined);
	assert(src != dest);
}

void Renderer::bindPipeline(PipelineHandle pipeline) {
	assert(impl->inFrame);
	assert(pipeline);
	assert(impl->inRenderPass);
	assert(impl->pipelineDrawn);
	impl->pipelineDrawn = false;
	impl->validPipeline = true;
	impl->scissorSet    = false;

	impl->currentPipeline = impl->pipelines.get(pipeline).desc;
}

void Renderer::bindIndexBuffer(BufferHandle /* buffer */, bool /* bit16 */ ) {
	assert(impl->inFrame);
	assert(impl->validPipeline);
}

void Renderer::bindVertexBuffer(unsigned int /* binding */, BufferHandle /* buffer */) {
	assert(impl->inFrame);
	assert(impl->validPipeline);
}

void Renderer::bindDescriptorSet(unsigned int /* index */, DSLayoutHandle /* layout */, const void * /* data_ */) {
	assert(impl->validPipeline);
}

void Renderer::setViewport(unsigned int /* x */, unsigned int /* y */, unsigned int /* width */, unsigned int /* height */) {
	assert(impl->inFrame);
}

void Renderer::setScissorRect(unsigned int /* x */, unsigned int /* y */, unsigned int /* width */, unsigned int /* height */) {
	assert(impl->validPipeline);
	assert(impl->currentPipeline.scissorTest_);
	impl->scissorSet = true;
}

void Renderer::blit(RenderTargetHandle source, RenderTargetHandle target) {
	assert(source);
	assert(target);

	assert(!impl->inRenderPass);
}

void Renderer::resolveMSAA(RenderTargetHandle source, RenderTargetHandle target) {
	assert(source);
	assert(target);

	assert(!impl->inRenderPass);
}

void Renderer::resolveMSAAToSwapchain(RenderTargetHandle source, Layout finalLayout) {
	assert(source);
	assert(finalLayout != +Layout::Undefined);

	assert(impl->inFrame);
	assert(!impl->inRenderPass);
	assert(!impl->renderingToSwapchain);
}

void Renderer::draw(unsigned int /* firstVertex */, unsigned int vertexCount) {
	assert(impl->inRenderPass);
	assert(impl->validPipeline);
	assert(vertexCount > 0);
	assert(!impl->currentPipeline.scissorTest_ || impl->scissorSet);
	impl->pipelineDrawn = true;
}

void Renderer::drawIndexedInstanced(unsigned int vertexCount, unsigned int instanceCount) {
	assert(impl->inRenderPass);
	assert(impl->validPipeline);
	assert(vertexCount > 0);
	assert(instanceCount > 0);
	assert(!impl->currentPipeline.scissorTest_ || impl->scissorSet);
	impl->pipelineDrawn = true;
}

void Renderer::drawIndexedOffset(unsigned int vertexCount, unsigned int /* firstIndex */, unsigned int /* minIndex */, unsigned int /* maxIndex */) {
	assert(impl->inRenderPass);
	assert(impl->validPipeline);
	assert(vertexCount > 0);
	assert(!impl->currentPipeline.scissorTest_ || impl->scissorSet);
	impl->pipelineDrawn = true;
}

} // namespace renderer

#endif //  RENDERER_NULL
<|endoftext|>


<commit_before>#include <math.h>
#include <stdio.h>
#include "HalideRuntime.h"
#include "HalideBuffer.h"
#include <assert.h>
#if defined(TEST_OPENCL)
#include "HalideRuntimeOpenCL.h"
#elif defined(TEST_CUDA)
#include "HalideRuntimeCuda.h"
#endif

#include "gpu_only.h"
using namespace Halide::Runtime;

int main(int argc, char **argv) {
#if defined(TEST_OPENCL) || defined(TEST_CUDA)
    const int W = 32, H = 32;
    Buffer<int> input(W, H);
    for (int y = 0; y < input.height(); y++) {
        for (int x = 0; x < input.width(); x++) {
            input(x, y) = x + y;
        }
    }

    // Explicitly copy data to the GPU.
    input.set_host_dirty();
#if defined(TEST_OPENCL)
    input.copy_to_device(halide_opencl_device_interface());
#elif defined(TEST_CUDA)
    input.copy_to_device(halide_cuda_device_interface());
#endif

    Buffer<int> output(W, H);

    // Create buffer_ts without host pointers.
    buffer_t input_no_host = *((buffer_t *)input);
    input_no_host.host = nullptr;

    buffer_t output_no_host = *((buffer_t *)output);
    // We need a fake pointer here to trick Halide into creating the
    // device buffer (and not do bounds inference instead of running
    // the pipeline). Halide will not dereference this pointer.
    output_no_host.host = (uint8_t *)1;

    gpu_only(&input_no_host, &output_no_host);

    // Restore the host pointer and copy to host.
    output_no_host.host = (uint8_t *)output.data();
    halide_copy_to_host(nullptr, &output_no_host);

    // Verify output.
    for (int y = 0; y < H; y++) {
        for (int x = 0; x < W; x++) {
            if (input(x, y) * 2 != output(x, y)) {
                printf("Error at %d, %d: %d != %d\n", x, y, input(x, y), output(x, y));
                return -1;
            }
        }
    }

    printf("Success!\n");
#else
    printf("No GPU target enabled, skipping...\n");
#endif
    return 0;
}
<commit_msg>Fix test<commit_after>#include <math.h>
#include <stdio.h>
#include "HalideRuntime.h"
#include "HalideBuffer.h"
#include <assert.h>
#if defined(TEST_OPENCL)
#include "HalideRuntimeOpenCL.h"
#elif defined(TEST_CUDA)
#include "HalideRuntimeCuda.h"
#endif

#include "gpu_only.h"
using namespace Halide::Runtime;

int main(int argc, char **argv) {
#if defined(TEST_OPENCL) || defined(TEST_CUDA)
    const int W = 32, H = 32;
    Buffer<int> input(W, H);
    for (int y = 0; y < input.height(); y++) {
        for (int x = 0; x < input.width(); x++) {
            input(x, y) = x + y;
        }
    }

    // Explicitly copy data to the GPU.
    input.set_host_dirty();
#if defined(TEST_OPENCL)
    input.copy_to_device(halide_opencl_device_interface());
#elif defined(TEST_CUDA)
    input.copy_to_device(halide_cuda_device_interface());
#endif

    Buffer<int> output(W, H);

    // Create halide_buffer_ts without host pointers.
    halide_buffer_t input_no_host = *((halide_buffer_t *)input);
    input_no_host.host = nullptr;

    halide_buffer_t output_no_host = *((halide_buffer_t *)output);
    // We need a fake pointer here to trick Halide into creating the
    // device buffer (and not do bounds inference instead of running
    // the pipeline). Halide will not dereference this pointer.
    output_no_host.host = (uint8_t *)1;

    gpu_only(&input_no_host, &output_no_host);

    // Restore the host pointer and copy to host.
    output_no_host.host = (uint8_t *)output.data();
    halide_copy_to_host(nullptr, &output_no_host);

    // Verify output.
    for (int y = 0; y < H; y++) {
        for (int x = 0; x < W; x++) {
            if (input(x, y) * 2 != output(x, y)) {
                printf("Error at %d, %d: %d != %d\n", x, y, input(x, y), output(x, y));
                return -1;
            }
        }
    }

    printf("Success!\n");
#else
    printf("No GPU target enabled, skipping...\n");
#endif
    return 0;
}
<|endoftext|>


<commit_before>/**
 * Appcelerator Titanium - licensed under the Apache Public License 2
 * see LICENSE in the root folder for details on the license.
 * Copyright (c) 2009, 2010 Appcelerator, Inc. All Rights Reserved.
 */

#include "../network_status.h"
#include <SystemConfiguration/SCNetworkReachability.h>

namespace ti
{

void NetworkStatus::InitializeLoop()
{
}

void NetworkStatus::CleanupLoop()
{
}

bool NetworkStatus::GetStatus()
{
	static SCNetworkReachabilityRef primaryTarget =
		SCNetworkReachabilityCreateWithName(0, "www.google.com");
	if (!primaryTarget)
		return true;

	SCNetworkConnectionFlags flags;
	SCNetworkReachabilityGetFlags(primaryTarget, &flags);
	if ((flags & kSCNetworkFlagsReachable) &&
		!(flags & kSCNetworkFlagsConnectionRequired))
		return true;

	static SCNetworkReachabilityRef secondaryTarget =
		SCNetworkReachabilityCreateWithName(0, "www.google.com");
	if (!secondaryTarget)
		return true;

	SCNetworkReachabilityGetFlags(secondaryTarget, &flags);
	if ((flags & kSCNetworkFlagsReachable) &&
		!(flags & kSCNetworkFlagsConnectionRequired))
		return true;

	return false;
}

}
<commit_msg>The secondary target should actually be a different host.<commit_after>/**
 * Appcelerator Titanium - licensed under the Apache Public License 2
 * see LICENSE in the root folder for details on the license.
 * Copyright (c) 2009, 2010 Appcelerator, Inc. All Rights Reserved.
 */

#include "../network_status.h"
#include <SystemConfiguration/SCNetworkReachability.h>

namespace ti
{

void NetworkStatus::InitializeLoop()
{
}

void NetworkStatus::CleanupLoop()
{
}

bool NetworkStatus::GetStatus()
{
	static SCNetworkReachabilityRef primaryTarget =
		SCNetworkReachabilityCreateWithName(0, "www.google.com");
	if (!primaryTarget)
		return true;

	SCNetworkConnectionFlags flags;
	SCNetworkReachabilityGetFlags(primaryTarget, &flags);
	if ((flags & kSCNetworkFlagsReachable) &&
		!(flags & kSCNetworkFlagsConnectionRequired))
		return true;

	static SCNetworkReachabilityRef secondaryTarget =
		SCNetworkReachabilityCreateWithName(0, "www.yahoo.com");
	if (!secondaryTarget)
		return true;

	SCNetworkReachabilityGetFlags(secondaryTarget, &flags);
	if ((flags & kSCNetworkFlagsReachable) &&
		!(flags & kSCNetworkFlagsConnectionRequired))
		return true;

	return false;
}

}
<|endoftext|>


<commit_before>#include "helpers/MovementGenerator.hpp"
#include "../src/controller/Controller.hpp"

#include <iostream>

int main(int argc, char** argv) {
	std::cout << "Start profile_control" << std::endl;

	/*
	 * TODO: needs to be initialized
	 * Controller instead of DummyPositionReceiver
	 */
	Controller *receiver = new Controller();

	std::vector<Vector> from;
	std::vector<Vector> to;

	from.push_back(Vector(0, 0, 0));
	to.push_back(Vector(1, 1, 1));
	from.push_back(Vector(0, 0, 1));
	to.push_back(Vector(1, 1, 2));
	from.push_back(Vector(0, 1, 0));
	to.push_back(Vector(1, 2, 1));
	from.push_back(Vector(1, 0, 0));
	to.push_back(Vector(2, 1, 1));
	from.push_back(Vector(1, 1, 1));
	to.push_back(Vector(2, 2, 2));

	// See MovementGenerator.hpp
	MovementGenerator generator(receiver, from, to, 0.05, 0.1, 0.01, 150, 30);
	generator.run();
}<commit_msg>a start - once again<commit_after>#include "helpers/MovementGenerator.hpp"
#include "../src/controller/Controller.hpp"

#include <iostream>

int main(int argc, char** argv) {
	ros::init(argc, argv, "profile_control_node");

	std::cout << "Start profile_control" << std::endl;

	/*
	 * TODO: needs to be initialized
	 * Controller instead of DummyPositionReceiver
	 */
	Controller *receiver = new Controller();

	std::vector<Vector> from;
	std::vector<Vector> to;

	from.push_back(Vector(0, 0, 0));
	to.push_back(Vector(1, 1, 1));
	from.push_back(Vector(0, 0, 1));
	to.push_back(Vector(1, 1, 2));
	from.push_back(Vector(0, 1, 0));
	to.push_back(Vector(1, 2, 1));
	from.push_back(Vector(1, 0, 0));
	to.push_back(Vector(2, 1, 1));
	from.push_back(Vector(1, 1, 1));
	to.push_back(Vector(2, 2, 2));

	ros::spin();

	// See MovementGenerator.hpp
	MovementGenerator generator(receiver, from, to, 0.05, 0.1, 0.01, 150, 30);
	generator.run();
}<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "submitfilemodel.h"
#include "vcsbaseconstants.h"

#include <QtGui/QStandardItem>
#include <QtCore/QDebug>

namespace VCSBase {

// --------------------------------------------------------------------------
// Helpers:
// --------------------------------------------------------------------------

static QList<QStandardItem *> createFileRow(const QString &fileName, const QString &status,
                                            bool checked, const QVariant &v)
{
    QStandardItem *statusItem = new QStandardItem(status);
    statusItem->setCheckable(true);
    statusItem->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
    statusItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled);
    statusItem->setData(v);
    QStandardItem *fileItem = new QStandardItem(fileName);
    fileItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
    QList<QStandardItem *> row;
    row << statusItem << fileItem;
    return row;
}

// --------------------------------------------------------------------------
// SubmitFileModel:
// --------------------------------------------------------------------------

/*!
    \class VCSBase::SubmitFileModel

    \brief A 2-column (checkable, state, file name) model to be used to list the files
    in the submit editor. Provides header items and a convience to add files.
 */

SubmitFileModel::SubmitFileModel(QObject *parent) :
    QStandardItemModel(0, 2, parent)
{
    // setColumnCount(2);
    QStringList headerLabels;
    headerLabels << tr("State") << tr("File");
    setHorizontalHeaderLabels(headerLabels);
}

QList<QStandardItem *> SubmitFileModel::addFile(const QString &fileName, const QString &status, bool checked,
                                                const QVariant &v)
{
    const QList<QStandardItem *> row = createFileRow(fileName, status, checked, v);
    appendRow(row);
    return row;
}

QList<QStandardItem *> SubmitFileModel::rowAt(int row) const
{
    const int colCount = columnCount();
    QList<QStandardItem *> rc;
    for (int c = 0; c < colCount; c++)
        rc.push_back(item(row, c));
    return rc;
}

QString SubmitFileModel::state(int row) const
{
    if (row < 0 || row >= rowCount())
        return QString();
    return item(row)->text();
}

QString SubmitFileModel::file(int row) const
{
    if (row < 0 || row >= rowCount())
        return QString();
    return item(row, 1)->text();
}

bool SubmitFileModel::checked(int row) const
{
    if (row < 0 || row >= rowCount())
        return false;
    return (item(row)->checkState() == Qt::Checked);
}

QVariant SubmitFileModel::data(int row) const
{
    if (row < 0 || row >= rowCount())
        return false;
    return item(row)->data();
}

bool SubmitFileModel::hasCheckedFiles() const
{
    for (int i = 0; i < rowCount(); ++i) {
        if (checked(i))
            return true;
    }
    return false;
}

QList<QStandardItem *> SubmitFileModel::findRow(const QString &text, int column) const
{
    // Single item
    const QList<QStandardItem *> items = findItems(text, Qt::MatchExactly, column);
    if (items.empty())
        return items;
    // Compile row
    return rowAt(items.front()->row());
 }

unsigned SubmitFileModel::filter(const QStringList &filter, int column)
{
    unsigned rc = 0;
    for (int r = rowCount() - 1; r >= 0; r--)
        if (const QStandardItem *i = item(r, column))
            if (!filter.contains(i->text())) {
                qDeleteAll(takeRow(r));
                rc++;
            }
    if (VCSBase::Constants::Internal::debug)
        qDebug() << Q_FUNC_INFO << " deleted " << rc << " items using " << filter << " , remaining " << rowCount();
    return rc;
}
}
<commit_msg>VcsBase: show icons for the files in the submit editor<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "submitfilemodel.h"
#include "vcsbaseconstants.h"

#include <coreplugin/fileiconprovider.h>

#include <QtGui/QStandardItem>
#include <QtCore/QFileInfo>
#include <QtCore/QDebug>

namespace VCSBase {

// --------------------------------------------------------------------------
// Helpers:
// --------------------------------------------------------------------------

static QList<QStandardItem *> createFileRow(const QString &fileName, const QString &status,
                                            bool checked, const QVariant &v)
{
    QStandardItem *statusItem = new QStandardItem(status);
    statusItem->setCheckable(true);
    statusItem->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
    statusItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled);
    statusItem->setData(v);
    QStandardItem *fileItem = new QStandardItem(fileName);
    fileItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
    fileItem->setIcon(Core::FileIconProvider::instance()->icon(QFileInfo(fileName)));
    QList<QStandardItem *> row;
    row << statusItem << fileItem;
    return row;
}

// --------------------------------------------------------------------------
// SubmitFileModel:
// --------------------------------------------------------------------------

/*!
    \class VCSBase::SubmitFileModel

    \brief A 2-column (checkable, state, file name) model to be used to list the files
    in the submit editor. Provides header items and a convience to add files.
 */

SubmitFileModel::SubmitFileModel(QObject *parent) :
    QStandardItemModel(0, 2, parent)
{
    // setColumnCount(2);
    QStringList headerLabels;
    headerLabels << tr("State") << tr("File");
    setHorizontalHeaderLabels(headerLabels);
}

QList<QStandardItem *> SubmitFileModel::addFile(const QString &fileName, const QString &status, bool checked,
                                                const QVariant &v)
{
    const QList<QStandardItem *> row = createFileRow(fileName, status, checked, v);
    appendRow(row);
    return row;
}

QList<QStandardItem *> SubmitFileModel::rowAt(int row) const
{
    const int colCount = columnCount();
    QList<QStandardItem *> rc;
    for (int c = 0; c < colCount; c++)
        rc.push_back(item(row, c));
    return rc;
}

QString SubmitFileModel::state(int row) const
{
    if (row < 0 || row >= rowCount())
        return QString();
    return item(row)->text();
}

QString SubmitFileModel::file(int row) const
{
    if (row < 0 || row >= rowCount())
        return QString();
    return item(row, 1)->text();
}

bool SubmitFileModel::checked(int row) const
{
    if (row < 0 || row >= rowCount())
        return false;
    return (item(row)->checkState() == Qt::Checked);
}

QVariant SubmitFileModel::data(int row) const
{
    if (row < 0 || row >= rowCount())
        return false;
    return item(row)->data();
}

bool SubmitFileModel::hasCheckedFiles() const
{
    for (int i = 0; i < rowCount(); ++i) {
        if (checked(i))
            return true;
    }
    return false;
}

QList<QStandardItem *> SubmitFileModel::findRow(const QString &text, int column) const
{
    // Single item
    const QList<QStandardItem *> items = findItems(text, Qt::MatchExactly, column);
    if (items.empty())
        return items;
    // Compile row
    return rowAt(items.front()->row());
 }

unsigned SubmitFileModel::filter(const QStringList &filter, int column)
{
    unsigned rc = 0;
    for (int r = rowCount() - 1; r >= 0; r--)
        if (const QStandardItem *i = item(r, column))
            if (!filter.contains(i->text())) {
                qDeleteAll(takeRow(r));
                rc++;
            }
    if (VCSBase::Constants::Internal::debug)
        qDebug() << Q_FUNC_INFO << " deleted " << rc << " items using " << filter << " , remaining " << rowCount();
    return rc;
}

}
<|endoftext|>


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

#include "src/profiling/memory/client.h"

#include <signal.h>

#include <thread>
#include <vector>

#include "perfetto/base/thread_utils.h"
#include "perfetto/ext/base/unix_socket.h"
#include "src/profiling/memory/wire_protocol.h"
#include "test/gtest_and_gmock.h"

namespace perfetto {
namespace profiling {
namespace {

TEST(ClientTest, GetThreadStackRangeBase) {
  std::thread th([] {
    StackRange stackrange = GetThreadStackRange();
    ASSERT_NE(stackrange.begin, nullptr);
    ASSERT_NE(stackrange.end, nullptr);
    // The implementation assumes the stack grows from higher addresses to
    // lower. We will need to rework once we encounter architectures where the
    // stack grows the other way.
    EXPECT_LT(stackrange.begin, __builtin_frame_address(0));
    EXPECT_GT(stackrange.end, __builtin_frame_address(0));
  });
  th.join();
}

#if defined(ADDRESS_SANITIZER)
#define MAYBE_GetSigaltStackRange DISABLED_GetSigaltStackRange
#else
#define MAYBE_GetSigaltStackRange GetSigaltStackRange
#endif

TEST(ClientTest, MAYBE_GetSigaltStackRange) {
  std::vector<char> stack(MINSIGSTKSZ);
  stack_t altstack{};
  stack_t old_altstack{};
  altstack.ss_sp = stack.data();
  altstack.ss_size = stack.size();
  ASSERT_NE(sigaltstack(&altstack, &old_altstack), -1) << strerror(errno);

  struct sigaction oldact;
  struct sigaction newact {};

  static StackRange stackrange;
  static const char* stackptr;
  newact.sa_handler = [](int) {
    stackrange = GetSigAltStackRange();
    stackptr = static_cast<char*>(__builtin_frame_address(0));
  };
  newact.sa_flags = SA_ONSTACK;
  int res = sigaction(SIGUSR1, &newact, &oldact);
  ASSERT_NE(res, -1);

  raise(SIGUSR1);

  PERFETTO_CHECK(sigaction(SIGUSR1, &oldact, nullptr) != -1);
  PERFETTO_CHECK(sigaltstack(&old_altstack, nullptr) != -1);

  ASSERT_EQ(stackrange.begin, stack.data());
  ASSERT_EQ(stackrange.end, &stack[MINSIGSTKSZ]);
  ASSERT_LT(stackrange.begin, stackptr);
  ASSERT_GT(stackrange.end, stackptr);
}

TEST(ClientTest, GetMainThreadStackRange) {
  if (getpid() != base::GetThreadId())
    GTEST_SKIP() << "This test has to run on the main thread.";

  StackRange stackrange = GetMainThreadStackRange();
  ASSERT_NE(stackrange.begin, nullptr);
  ASSERT_NE(stackrange.end, nullptr);
  // The implementation assumes the stack grows from higher addresses to
  // lower. We will need to rework once we encounter architectures where the
  // stack grows the other way.
  EXPECT_LT(stackrange.begin, __builtin_frame_address(0));
  EXPECT_GT(stackrange.end, __builtin_frame_address(0));
}

TEST(ClientTest, IsMainThread) {
  // Our code relies on the fact that getpid() == GetThreadId() if this
  // process/thread is the main thread of the process. This test ensures that is
  // true.
  auto pid = getpid();
  auto main_thread_id = base::GetThreadId();
  EXPECT_EQ(pid, main_thread_id);
  std::thread th(
      [main_thread_id] { EXPECT_NE(main_thread_id, base::GetThreadId()); });
  th.join();
}

TEST(ClientTest, GetMaxTriesBlock) {
  ClientConfiguration cfg = {};
  cfg.block_client = true;
  cfg.block_client_timeout_us = 200;
  EXPECT_EQ(GetMaxTries(cfg), 2u);
}

TEST(ClientTest, GetMaxTriesBlockSmall) {
  ClientConfiguration cfg = {};
  cfg.block_client = true;
  cfg.block_client_timeout_us = 99;
  EXPECT_EQ(GetMaxTries(cfg), 1u);
}

TEST(ClientTest, GetMaxTriesBlockVerySmall) {
  ClientConfiguration cfg = {};
  cfg.block_client = true;
  cfg.block_client_timeout_us = 1;
  EXPECT_EQ(GetMaxTries(cfg), 1u);
}

TEST(ClientTest, GetMaxTriesBlockInfinite) {
  ClientConfiguration cfg = {};
  cfg.block_client = true;
  cfg.block_client_timeout_us = 0;
  EXPECT_EQ(GetMaxTries(cfg), kInfiniteTries);
}

TEST(ClientTest, GetMaxTriesNoBlock) {
  ClientConfiguration cfg = {};
  cfg.block_client = false;
  cfg.block_client_timeout_us = 200;
  EXPECT_EQ(GetMaxTries(cfg), 1u);
}

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

#include "src/profiling/memory/client.h"

#include <signal.h>

#include <thread>

#include "perfetto/base/thread_utils.h"
#include "perfetto/ext/base/unix_socket.h"
#include "src/profiling/memory/wire_protocol.h"
#include "test/gtest_and_gmock.h"

namespace perfetto {
namespace profiling {
namespace {

TEST(ClientTest, GetThreadStackRangeBase) {
  std::thread th([] {
    StackRange stackrange = GetThreadStackRange();
    ASSERT_NE(stackrange.begin, nullptr);
    ASSERT_NE(stackrange.end, nullptr);
    // The implementation assumes the stack grows from higher addresses to
    // lower. We will need to rework once we encounter architectures where the
    // stack grows the other way.
    EXPECT_LT(stackrange.begin, __builtin_frame_address(0));
    EXPECT_GT(stackrange.end, __builtin_frame_address(0));
  });
  th.join();
}

#if defined(ADDRESS_SANITIZER)
#define MAYBE_GetSigaltStackRange DISABLED_GetSigaltStackRange
#else
#define MAYBE_GetSigaltStackRange GetSigaltStackRange
#endif

TEST(ClientTest, MAYBE_GetSigaltStackRange) {
  char stack[4096];
  stack_t altstack{};
  stack_t old_altstack{};
  altstack.ss_sp = stack;
  altstack.ss_size = sizeof(stack);
  ASSERT_NE(sigaltstack(&altstack, &old_altstack), -1);

  struct sigaction oldact;
  struct sigaction newact {};

  static StackRange stackrange;
  static const char* stackptr;
  newact.sa_handler = [](int) {
    stackrange = GetSigAltStackRange();
    stackptr = static_cast<char*>(__builtin_frame_address(0));
  };
  newact.sa_flags = SA_ONSTACK;
  int res = sigaction(SIGUSR1, &newact, &oldact);
  ASSERT_NE(res, -1);

  raise(SIGUSR1);

  PERFETTO_CHECK(sigaction(SIGUSR1, &oldact, nullptr) != -1);
  PERFETTO_CHECK(sigaltstack(&old_altstack, nullptr) != -1);

  ASSERT_EQ(stackrange.begin, stack);
  ASSERT_EQ(stackrange.end, &stack[4096]);
  ASSERT_LT(stackrange.begin, stackptr);
  ASSERT_GT(stackrange.end, stackptr);
}

TEST(ClientTest, GetMainThreadStackRange) {
  if (getpid() != base::GetThreadId())
    GTEST_SKIP() << "This test has to run on the main thread.";

  StackRange stackrange = GetMainThreadStackRange();
  ASSERT_NE(stackrange.begin, nullptr);
  ASSERT_NE(stackrange.end, nullptr);
  // The implementation assumes the stack grows from higher addresses to
  // lower. We will need to rework once we encounter architectures where the
  // stack grows the other way.
  EXPECT_LT(stackrange.begin, __builtin_frame_address(0));
  EXPECT_GT(stackrange.end, __builtin_frame_address(0));
}

TEST(ClientTest, IsMainThread) {
  // Our code relies on the fact that getpid() == GetThreadId() if this
  // process/thread is the main thread of the process. This test ensures that is
  // true.
  auto pid = getpid();
  auto main_thread_id = base::GetThreadId();
  EXPECT_EQ(pid, main_thread_id);
  std::thread th(
      [main_thread_id] { EXPECT_NE(main_thread_id, base::GetThreadId()); });
  th.join();
}

TEST(ClientTest, GetMaxTriesBlock) {
  ClientConfiguration cfg = {};
  cfg.block_client = true;
  cfg.block_client_timeout_us = 200;
  EXPECT_EQ(GetMaxTries(cfg), 2u);
}

TEST(ClientTest, GetMaxTriesBlockSmall) {
  ClientConfiguration cfg = {};
  cfg.block_client = true;
  cfg.block_client_timeout_us = 99;
  EXPECT_EQ(GetMaxTries(cfg), 1u);
}

TEST(ClientTest, GetMaxTriesBlockVerySmall) {
  ClientConfiguration cfg = {};
  cfg.block_client = true;
  cfg.block_client_timeout_us = 1;
  EXPECT_EQ(GetMaxTries(cfg), 1u);
}

TEST(ClientTest, GetMaxTriesBlockInfinite) {
  ClientConfiguration cfg = {};
  cfg.block_client = true;
  cfg.block_client_timeout_us = 0;
  EXPECT_EQ(GetMaxTries(cfg), kInfiniteTries);
}

TEST(ClientTest, GetMaxTriesNoBlock) {
  ClientConfiguration cfg = {};
  cfg.block_client = false;
  cfg.block_client_timeout_us = 200;
  EXPECT_EQ(GetMaxTries(cfg), 1u);
}

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


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <canvas/debug.hxx>
#include <canvas/verbosetrace.hxx>
#include <canvas/canvastools.hxx>
#include <tools/diagnose_ex.h>

#include <osl/mutex.hxx>

#include <com/sun/star/registry/XRegistryKey.hpp>
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#include <com/sun/star/uno/XComponentContext.hpp>
#include <com/sun/star/lang/NoSupportException.hpp>

#include <toolkit/helper/vclunohelper.hxx>

#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/point/b2dpoint.hxx>
#include <basegfx/tools/canvastools.hxx>
#include <basegfx/numeric/ftools.hxx>

#include "cairo_spritecanvas.hxx"

using namespace ::cairo;
using namespace ::com::sun::star;

namespace cairocanvas
{
    SpriteCanvas::SpriteCanvas( const uno::Sequence< uno::Any >&                aArguments,
                                const uno::Reference< uno::XComponentContext >& rxContext ) :
        maArguments(aArguments),
        mxComponentContext( rxContext )
    {
    }

    void SpriteCanvas::initialize()
    {
        VERBOSE_TRACE("CairoSpriteCanvas created %p\n", this);

        // #i64742# Only call initialize when not in probe mode
        if( maArguments.getLength() == 0 )
            return;

        /* maArguments:
           0: ptr to creating instance (Window or VirtualDevice)
           1: SystemEnvData as a streamed Any (or empty for VirtualDevice)
           2: current bounds of creating instance
           3: bool, denoting always on top state for Window (always false for VirtualDevice)
           4: XWindow for creating Window (or empty for VirtualDevice)
           5: SystemGraphicsData as a streamed Any
         */
        ENSURE_ARG_OR_THROW( maArguments.getLength() >= 4 &&
                             maArguments[0].getValueTypeClass() == uno::TypeClass_HYPER &&
                             maArguments[4].getValueTypeClass() == uno::TypeClass_INTERFACE,
                             "CairoSpriteCanvas::initialize: wrong number of arguments, or wrong types" );

        awt::Rectangle aRect;
        maArguments[2] >>= aRect;

        bool bIsFullscreen( false );
        maArguments[3] >>= bIsFullscreen;

        uno::Reference< awt::XWindow > xParentWindow;
        maArguments[4] >>= xParentWindow;

        Window* pParentWindow = VCLUnoHelper::GetWindow(xParentWindow);
        if( !pParentWindow )
            throw lang::NoSupportException(
                "Parent window not VCL window, or canvas out-of-process!", NULL);

        bool bHasXRender = IsCairoWorking(pParentWindow);
        ENSURE_ARG_OR_THROW( bHasXRender == true,
                             "CairoSpriteCanvas::SpriteCanvas: No RENDER extension" );

        Size aPixelSize( pParentWindow->GetOutputSizePixel() );
        const ::basegfx::B2ISize aSize( aPixelSize.Width(),
                                        aPixelSize.Height() );

        ENSURE_ARG_OR_THROW( pParentWindow != NULL,
                             "CairoSpriteCanvas::initialize: invalid Window pointer" );

        // setup helper
        maDeviceHelper.init( *pParentWindow,
                             *this,
                             aSize,
                             bIsFullscreen );

        setWindow(uno::Reference<awt::XWindow2>(xParentWindow, uno::UNO_QUERY_THROW));

        maCanvasHelper.init( maRedrawManager,
                             *this,
                             aSize );

        maArguments.realloc(0);
    }

    void SpriteCanvas::disposeThis()
    {
        ::osl::MutexGuard aGuard( m_aMutex );

        mxComponentContext.clear();

        // forward to parent
        SpriteCanvasBaseT::disposeThis();
    }

    sal_Bool SAL_CALL SpriteCanvas::showBuffer( sal_Bool bUpdateAll ) throw (uno::RuntimeException, std::exception)
    {
        return updateScreen( bUpdateAll );
    }

    sal_Bool SAL_CALL SpriteCanvas::switchBuffer( sal_Bool bUpdateAll ) throw (uno::RuntimeException)
    {
        return updateScreen( bUpdateAll );
    }

    sal_Bool SAL_CALL SpriteCanvas::updateScreen( sal_Bool bUpdateAll ) throw (uno::RuntimeException, std::exception)
    {
        ::osl::MutexGuard aGuard( m_aMutex );

        // avoid repaints on hidden window (hidden: not mapped to
        // screen). Return failure, since the screen really has _not_
        // been updated (caller should try again later)
        return !mbIsVisible ? false : maCanvasHelper.updateScreen(
            ::basegfx::unotools::b2IRectangleFromAwtRectangle(maBounds),
            bUpdateAll,
            mbSurfaceDirty);
    }

    OUString SAL_CALL SpriteCanvas::getServiceName(  ) throw (uno::RuntimeException, std::exception)
    {
        return OUString( SPRITECANVAS_SERVICE_NAME );
    }

    SurfaceSharedPtr SpriteCanvas::getSurface()
    {
        return maDeviceHelper.getBufferSurface();
    }

    SurfaceSharedPtr SpriteCanvas::createSurface( const ::basegfx::B2ISize& rSize, Content aContent )
    {
        return maDeviceHelper.createSurface( rSize, aContent );
    }

    SurfaceSharedPtr SpriteCanvas::createSurface( ::Bitmap& rBitmap )
    {
        BitmapSystemData aData;
        if( rBitmap.GetSystemData( aData ) ) {
            const Size& rSize = rBitmap.GetSizePixel();

            return maDeviceHelper.createSurface( aData, rSize );
        }

        return SurfaceSharedPtr();
    }

    SurfaceSharedPtr SpriteCanvas::changeSurface( bool, bool )
    {
        // non-modifiable surface here
        return SurfaceSharedPtr();
    }

    OutputDevice* SpriteCanvas::getOutputDevice()
    {
        return maDeviceHelper.getOutputDevice();
    }

    SurfaceSharedPtr SpriteCanvas::getBufferSurface()
    {
        return maDeviceHelper.getBufferSurface();
    }

    SurfaceSharedPtr SpriteCanvas::getWindowSurface()
    {
        return maDeviceHelper.getWindowSurface();
    }

    const ::basegfx::B2ISize& SpriteCanvas::getSizePixel()
    {
        return maDeviceHelper.getSizePixel();
    }

    void SpriteCanvas::setSizePixel( const ::basegfx::B2ISize& rSize )
    {
        maCanvasHelper.setSize( rSize );
        // re-set background surface, in case it needed recreation
        maCanvasHelper.setSurface( maDeviceHelper.getBufferSurface(),
                                   false );
    }

    void SpriteCanvas::flush()
    {
        maDeviceHelper.flush();
    }

    bool SpriteCanvas::repaint( const SurfaceSharedPtr&       pSurface,
                                const rendering::ViewState&   viewState,
                                const rendering::RenderState& renderState )
    {
        return maCanvasHelper.repaint( pSurface, viewState, renderState );
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>coverity#735401 Logically dead code<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <canvas/debug.hxx>
#include <canvas/verbosetrace.hxx>
#include <canvas/canvastools.hxx>
#include <tools/diagnose_ex.h>

#include <osl/mutex.hxx>

#include <com/sun/star/registry/XRegistryKey.hpp>
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#include <com/sun/star/uno/XComponentContext.hpp>
#include <com/sun/star/lang/NoSupportException.hpp>

#include <toolkit/helper/vclunohelper.hxx>

#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/point/b2dpoint.hxx>
#include <basegfx/tools/canvastools.hxx>
#include <basegfx/numeric/ftools.hxx>

#include "cairo_spritecanvas.hxx"

using namespace ::cairo;
using namespace ::com::sun::star;

namespace cairocanvas
{
    SpriteCanvas::SpriteCanvas( const uno::Sequence< uno::Any >&                aArguments,
                                const uno::Reference< uno::XComponentContext >& rxContext ) :
        maArguments(aArguments),
        mxComponentContext( rxContext )
    {
    }

    void SpriteCanvas::initialize()
    {
        VERBOSE_TRACE("CairoSpriteCanvas created %p\n", this);

        // #i64742# Only call initialize when not in probe mode
        if( maArguments.getLength() == 0 )
            return;

        /* maArguments:
           0: ptr to creating instance (Window or VirtualDevice)
           1: SystemEnvData as a streamed Any (or empty for VirtualDevice)
           2: current bounds of creating instance
           3: bool, denoting always on top state for Window (always false for VirtualDevice)
           4: XWindow for creating Window (or empty for VirtualDevice)
           5: SystemGraphicsData as a streamed Any
         */
        ENSURE_ARG_OR_THROW( maArguments.getLength() >= 4 &&
                             maArguments[0].getValueTypeClass() == uno::TypeClass_HYPER &&
                             maArguments[4].getValueTypeClass() == uno::TypeClass_INTERFACE,
                             "CairoSpriteCanvas::initialize: wrong number of arguments, or wrong types" );

        awt::Rectangle aRect;
        maArguments[2] >>= aRect;

        bool bIsFullscreen( false );
        maArguments[3] >>= bIsFullscreen;

        uno::Reference< awt::XWindow > xParentWindow;
        maArguments[4] >>= xParentWindow;

        Window* pParentWindow = VCLUnoHelper::GetWindow(xParentWindow);
        if( !pParentWindow )
            throw lang::NoSupportException(
                "Parent window not VCL window, or canvas out-of-process!", NULL);

        bool bHasXRender = IsCairoWorking(pParentWindow);
        ENSURE_ARG_OR_THROW( bHasXRender == true,
                             "CairoSpriteCanvas::SpriteCanvas: No RENDER extension" );

        Size aPixelSize( pParentWindow->GetOutputSizePixel() );
        const ::basegfx::B2ISize aSize( aPixelSize.Width(),
                                        aPixelSize.Height() );

        // setup helper
        maDeviceHelper.init( *pParentWindow,
                             *this,
                             aSize,
                             bIsFullscreen );

        setWindow(uno::Reference<awt::XWindow2>(xParentWindow, uno::UNO_QUERY_THROW));

        maCanvasHelper.init( maRedrawManager,
                             *this,
                             aSize );

        maArguments.realloc(0);
    }

    void SpriteCanvas::disposeThis()
    {
        ::osl::MutexGuard aGuard( m_aMutex );

        mxComponentContext.clear();

        // forward to parent
        SpriteCanvasBaseT::disposeThis();
    }

    sal_Bool SAL_CALL SpriteCanvas::showBuffer( sal_Bool bUpdateAll ) throw (uno::RuntimeException, std::exception)
    {
        return updateScreen( bUpdateAll );
    }

    sal_Bool SAL_CALL SpriteCanvas::switchBuffer( sal_Bool bUpdateAll ) throw (uno::RuntimeException)
    {
        return updateScreen( bUpdateAll );
    }

    sal_Bool SAL_CALL SpriteCanvas::updateScreen( sal_Bool bUpdateAll ) throw (uno::RuntimeException, std::exception)
    {
        ::osl::MutexGuard aGuard( m_aMutex );

        // avoid repaints on hidden window (hidden: not mapped to
        // screen). Return failure, since the screen really has _not_
        // been updated (caller should try again later)
        return !mbIsVisible ? false : maCanvasHelper.updateScreen(
            ::basegfx::unotools::b2IRectangleFromAwtRectangle(maBounds),
            bUpdateAll,
            mbSurfaceDirty);
    }

    OUString SAL_CALL SpriteCanvas::getServiceName(  ) throw (uno::RuntimeException, std::exception)
    {
        return OUString( SPRITECANVAS_SERVICE_NAME );
    }

    SurfaceSharedPtr SpriteCanvas::getSurface()
    {
        return maDeviceHelper.getBufferSurface();
    }

    SurfaceSharedPtr SpriteCanvas::createSurface( const ::basegfx::B2ISize& rSize, Content aContent )
    {
        return maDeviceHelper.createSurface( rSize, aContent );
    }

    SurfaceSharedPtr SpriteCanvas::createSurface( ::Bitmap& rBitmap )
    {
        BitmapSystemData aData;
        if( rBitmap.GetSystemData( aData ) ) {
            const Size& rSize = rBitmap.GetSizePixel();

            return maDeviceHelper.createSurface( aData, rSize );
        }

        return SurfaceSharedPtr();
    }

    SurfaceSharedPtr SpriteCanvas::changeSurface( bool, bool )
    {
        // non-modifiable surface here
        return SurfaceSharedPtr();
    }

    OutputDevice* SpriteCanvas::getOutputDevice()
    {
        return maDeviceHelper.getOutputDevice();
    }

    SurfaceSharedPtr SpriteCanvas::getBufferSurface()
    {
        return maDeviceHelper.getBufferSurface();
    }

    SurfaceSharedPtr SpriteCanvas::getWindowSurface()
    {
        return maDeviceHelper.getWindowSurface();
    }

    const ::basegfx::B2ISize& SpriteCanvas::getSizePixel()
    {
        return maDeviceHelper.getSizePixel();
    }

    void SpriteCanvas::setSizePixel( const ::basegfx::B2ISize& rSize )
    {
        maCanvasHelper.setSize( rSize );
        // re-set background surface, in case it needed recreation
        maCanvasHelper.setSurface( maDeviceHelper.getBufferSurface(),
                                   false );
    }

    void SpriteCanvas::flush()
    {
        maDeviceHelper.flush();
    }

    bool SpriteCanvas::repaint( const SurfaceSharedPtr&       pSurface,
                                const rendering::ViewState&   viewState,
                                const rendering::RenderState& renderState )
    {
        return maCanvasHelper.repaint( pSurface, viewState, renderState );
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/**
 * The MIT License
 *
 * Copyright (C) 2017 Kiyofumi Kondoh
 *
 * 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 "stdafx.h"

#include "cef_scheme_handler.h"

#include "include/cef_scheme.h"
#include "include/wrapper/cef_helpers.h"

namespace {
const char kScheme[] = "local";
const char kDomain[] = "test";
} // namespace {

static
CefRefPtr<CefSchemeHandlerFactory>
createClientSchemeHandlerFactory();

static
CefRefPtr<CefResourceHandler>
createClientSchemeHandler();

void registerSchemeHandlerFactory()
{
    const bool bRet = CefRegisterSchemeHandlerFactory(
        kScheme
        , kDomain
        , createClientSchemeHandlerFactory()
        );

    DCHECK(bRet);
}

void addCustomScheme( CefRawPtr<CefSchemeRegistrar> registrar )
{
    const bool is_standard = true;
    const bool is_local = false;
    const bool is_display_isolated = false;
    const bool is_secure = true;
    const bool is_cors_enabled = false;
    const bool is_csp_bypassing = false;

    const bool bRet = registrar->AddCustomScheme(
        kScheme
        , is_standard
        , is_local
        , is_display_isolated
        , is_secure
        , is_cors_enabled
#if CHROME_VERSION_BUILD > 2987
        , is_csp_bypassing
#endif // CHROME_VERSION_BUILD > 2987
        );
    DCHECK( bRet );
}

class ClientSchemeHandlerFactory
    : public CefSchemeHandlerFactory
{
public:
    ClientSchemeHandlerFactory() {}

    CefRefPtr<CefResourceHandler>
    Create(
        CefRefPtr<CefBrowser> browser
        , CefRefPtr<CefFrame> frame
        , const CefString& scheme_name
        , CefRefPtr<CefRequest> request
        ) OVERRIDE;

private:
    IMPLEMENT_REFCOUNTING(ClientSchemeHandlerFactory);
    DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandlerFactory);
};

CefRefPtr<CefResourceHandler>
ClientSchemeHandlerFactory::Create(
    CefRefPtr<CefBrowser> browser
    , CefRefPtr<CefFrame> frame
    , const CefString& scheme_name
    , CefRefPtr<CefRequest> request
) // OVERRIDE
{
    CEF_REQUIRE_IO_THREAD();

    return createClientSchemeHandler();
}

CefRefPtr<CefSchemeHandlerFactory>
createClientSchemeHandlerFactory()
{
    return new ClientSchemeHandlerFactory();
}

class ClientSchemeHandler
    : public CefResourceHandler
{
public:
    ClientSchemeHandler()
        : is_binary_(false)
        , offset_(0)
    {
    }

    bool
    ProcessRequest(
        CefRefPtr<CefRequest> request
        , CefRefPtr<CefCallback> callback
        ) OVERRIDE;

    void
    GetResponseHeaders(
        CefRefPtr<CefResponse> response
        , int64& response_length
        , CefString& redirectUrl
        ) OVERRIDE;

    bool
    ReadResponse(
        void* data_out
        , int bytes_to_read
        , int& bytes_read
        , CefRefPtr<CefCallback> callback
        ) OVERRIDE;

    void
    Cancel() OVERRIDE;

private:
    std::string                 mime_type_;
    std::vector<uint8_t>        data_;
    bool                        is_binary_;
    size_t                      offset_;

private:
    IMPLEMENT_REFCOUNTING(ClientSchemeHandler);
    DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandler);
};

bool
ClientSchemeHandler::ProcessRequest(
    CefRefPtr<CefRequest> request
    , CefRefPtr<CefCallback> callback
) // OVERRIDE
{
    CEF_REQUIRE_IO_THREAD();

    return false;
}

void
ClientSchemeHandler::GetResponseHeaders(
    CefRefPtr<CefResponse> response
    , int64& response_length
    , CefString& redirectUrl
) // OVERRIDE
{
    CEF_REQUIRE_IO_THREAD();
}

bool
ClientSchemeHandler::ReadResponse(
    void* data_out
    , int bytes_to_read
    , int& bytes_read
    , CefRefPtr<CefCallback> callback
) // OVERRIDE
{
    CEF_REQUIRE_IO_THREAD();

    return true;
}

void
ClientSchemeHandler::Cancel() // OVERRIDE
{
    CEF_REQUIRE_IO_THREAD();
}

CefRefPtr<CefResourceHandler>
createClientSchemeHandler()
{
    return new ClientSchemeHandler();
}
<commit_msg>add parseURL and ends_with, handling my resource<commit_after>/**
 * The MIT License
 *
 * Copyright (C) 2017 Kiyofumi Kondoh
 *
 * 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 "stdafx.h"

#include "cef_scheme_handler.h"

#include "include/cef_scheme.h"
#include "include/wrapper/cef_helpers.h"

namespace {
const char kScheme[] = "local";
const char kDomain[] = "test";
} // namespace {

static
CefRefPtr<CefSchemeHandlerFactory>
createClientSchemeHandlerFactory();

static
CefRefPtr<CefResourceHandler>
createClientSchemeHandler();

void registerSchemeHandlerFactory()
{
    const bool bRet = CefRegisterSchemeHandlerFactory(
        kScheme
        , kDomain
        , createClientSchemeHandlerFactory()
        );

    DCHECK(bRet);
}

void addCustomScheme( CefRawPtr<CefSchemeRegistrar> registrar )
{
    const bool is_standard = true;
    const bool is_local = false;
    const bool is_display_isolated = false;
    const bool is_secure = true;
    const bool is_cors_enabled = false;
    const bool is_csp_bypassing = false;

    const bool bRet = registrar->AddCustomScheme(
        kScheme
        , is_standard
        , is_local
        , is_display_isolated
        , is_secure
        , is_cors_enabled
#if CHROME_VERSION_BUILD > 2987
        , is_csp_bypassing
#endif // CHROME_VERSION_BUILD > 2987
        );
    DCHECK( bRet );
}

class ClientSchemeHandlerFactory
    : public CefSchemeHandlerFactory
{
public:
    ClientSchemeHandlerFactory() {}

    CefRefPtr<CefResourceHandler>
    Create(
        CefRefPtr<CefBrowser> browser
        , CefRefPtr<CefFrame> frame
        , const CefString& scheme_name
        , CefRefPtr<CefRequest> request
        ) OVERRIDE;

private:
    IMPLEMENT_REFCOUNTING(ClientSchemeHandlerFactory);
    DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandlerFactory);
};

CefRefPtr<CefResourceHandler>
ClientSchemeHandlerFactory::Create(
    CefRefPtr<CefBrowser> browser
    , CefRefPtr<CefFrame> frame
    , const CefString& scheme_name
    , CefRefPtr<CefRequest> request
) // OVERRIDE
{
    CEF_REQUIRE_IO_THREAD();

    return createClientSchemeHandler();
}

CefRefPtr<CefSchemeHandlerFactory>
createClientSchemeHandlerFactory()
{
    return new ClientSchemeHandlerFactory();
}

class ClientSchemeHandler
    : public CefResourceHandler
{
public:
    ClientSchemeHandler()
        : is_binary_(false)
        , offset_(0)
    {
    }

    bool
    ProcessRequest(
        CefRefPtr<CefRequest> request
        , CefRefPtr<CefCallback> callback
        ) OVERRIDE;

    void
    GetResponseHeaders(
        CefRefPtr<CefResponse> response
        , int64& response_length
        , CefString& redirectUrl
        ) OVERRIDE;

    bool
    ReadResponse(
        void* data_out
        , int bytes_to_read
        , int& bytes_read
        , CefRefPtr<CefCallback> callback
        ) OVERRIDE;

    void
    Cancel() OVERRIDE;

private:
    std::string                 mime_type_;
    std::vector<uint8_t>        data_;
    bool                        is_binary_;
    size_t                      offset_;

private:
    IMPLEMENT_REFCOUNTING(ClientSchemeHandler);
    DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandler);
};

static
bool
ends_with(const std::string& str, const std::string& suffix)
{
    if ( str.size() < suffix.size() )
    {
        return false;
    }
    return std::equal( std::rbegin(suffix), std::rend(suffix), std::rbegin(str) );
    //return ( 0 == str.compare( str.size() - suffix.size(), suffix.size(), suffix ));
}

static
bool
parseURL(std::string& scheme, std::string& domain, std::string& path, const std::string& url)
{
    const size_t pos_scheme = url.find( "://" );
    if ( std::string::npos == pos_scheme )
    {
        return false;
    }

    scheme = url.substr( 0, pos_scheme );

    if ( url.size() <= (pos_scheme + 3/*strlen("://")*/) )
    {
        return false;
    }

    const size_t pos_domain = url.find( '/', (pos_scheme + 3/*strlen("://")*/) );
    if ( std::string::npos == pos_domain )
    {
        return false;
    }
    domain = url.substr( (pos_scheme + 3/*strlen("://")*/), pos_domain - (pos_scheme + 3/*strlen("://")*/) );

    if ( url.size() <= (pos_domain + 1/*strlen("/")*/) )
    {
        return false;
    }

    path = url.substr( (pos_domain + 1/*strlen("/")*/) );

    return true;
}

//static
//bool
//readResource(

bool
ClientSchemeHandler::ProcessRequest(
    CefRefPtr<CefRequest> request
    , CefRefPtr<CefCallback> callback
) // OVERRIDE
{
    CEF_REQUIRE_IO_THREAD();

    bool handled = false;

    std::string url = request->GetURL();

    std::string scheme;
    std::string domain;
    std::string path;
    {
        const bool bRet = parseURL( scheme, domain, path, url );
    }

    if ( ends_with( url, ".html" ) )
    {
    }

    return handled;
}

void
ClientSchemeHandler::GetResponseHeaders(
    CefRefPtr<CefResponse> response
    , int64& response_length
    , CefString& redirectUrl
) // OVERRIDE
{
    CEF_REQUIRE_IO_THREAD();
}

bool
ClientSchemeHandler::ReadResponse(
    void* data_out
    , int bytes_to_read
    , int& bytes_read
    , CefRefPtr<CefCallback> callback
) // OVERRIDE
{
    CEF_REQUIRE_IO_THREAD();

    return true;
}

void
ClientSchemeHandler::Cancel() // OVERRIDE
{
    CEF_REQUIRE_IO_THREAD();
}

CefRefPtr<CefResourceHandler>
createClientSchemeHandler()
{
    return new ClientSchemeHandler();
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2015] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/

#ifndef REALM_UTIL_INTERPROCESS_CONDVAR
#define REALM_UTIL_INTERPROCESS_CONDVAR

#include <realm/util/features.h>
#include <realm/util/thread.hpp>
#include <realm/util/interprocess_mutex.hpp>
#include <stdint.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>

// Condvar Emulation is required if RobustMutex emulation is enabled
#ifdef REALM_ROBUST_MUTEX_EMULATION
#define REALM_CONDVAR_EMULATION
#endif

namespace realm {
namespace util {

/// Condition variable for use in synchronization monitors.
/// This condition variable uses emulation based on named pipes
/// for the inter-process case, if enabled by REALM_CONDVAR_EMULATION.
///
/// FIXME: This implementation will never release/delete pipes. This is unlikely
/// to be a problem as long as only a modest number of different database names
/// are in use
///
/// A InterprocessCondVar is always process shared.
class InterprocessCondVar {
public:
    InterprocessCondVar();
    ~InterprocessCondVar() noexcept;

    /// To use the InterprocessCondVar, you also must place a structure of type
    /// InterprocessCondVar::SharedPart in memory shared by multiple processes
    /// or in a memory mapped file, and use set_shared_part() to associate
    /// the condition variable with it's shared part. You must initialize
    /// the shared part using InterprocessCondVar::init_shared_part(), but only before
    /// first use and only when you have exclusive access to the shared part.

#ifdef REALM_CONDVAR_EMULATION
    struct SharedPart {
        uint64_t signal_counter;
        uint64_t wait_counter;
    };
#else
    typedef CondVar SharedPart;
#endif

    /// You need to bind the emulation to a SharedPart in shared/mmapped memory.
    /// The SharedPart is assumed to have been initialized (possibly by another process)
    /// earlier through a call to init_shared_part.
    void set_shared_part(SharedPart& shared_part, std::string path, size_t offset_of_condvar);

    /// Initialize the shared part of a process shared condition variable.
    /// A process shared condition variables may be represented by any number of
    /// InterprocessCondVar instances in any number of different processes,
    /// all sharing a common SharedPart instance, which must be in shared memory.
    static void init_shared_part(SharedPart& shared_part);

    /// Wait for someone to call notify() or notify_all() on this condition
    /// variable. The call to wait() may return spuriously, so the caller should
    /// always re-evaluate the condition on which to wait and loop on wait()
    /// if necessary.
    void wait(InterprocessMutex& m, const struct timespec* tp);

    /// If any threads are waiting for this condition, wake up at least one.
    /// (Current implementation may actually wake all :-O ). The caller must
    /// hold the lock associated with the condvar at the time of calling notify()
    void notify() noexcept;

    /// Wake up every thread that is currently waiting on this condition.
    /// The caller must hold the lock associated with the condvar at the time
    /// of calling notify_all().
    void notify_all() noexcept;

    /// Cleanup and release system resources if possible.
    void close() noexcept;

private:
    // non-zero if a shared part has been registered (always 0 on process local instances)
    SharedPart* m_shared_part = nullptr;

    bool uses_emulation = false;
    // pipe used for emulation
    int m_fd_read = -1;
    int m_fd_write = -1;
};

// Implementation:

} // namespace util
} // namespace realm

#endif
<commit_msg>added forgotten include<commit_after>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2015] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/

#ifndef REALM_UTIL_INTERPROCESS_CONDVAR
#define REALM_UTIL_INTERPROCESS_CONDVAR

#include <realm/util/features.h>
#include <realm/util/thread.hpp>
#include <realm/util/interprocess_mutex.hpp>
#include <stdint.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <mutex>

// Condvar Emulation is required if RobustMutex emulation is enabled
#ifdef REALM_ROBUST_MUTEX_EMULATION
#define REALM_CONDVAR_EMULATION
#endif

namespace realm {
namespace util {

/// Condition variable for use in synchronization monitors.
/// This condition variable uses emulation based on named pipes
/// for the inter-process case, if enabled by REALM_CONDVAR_EMULATION.
///
/// FIXME: This implementation will never release/delete pipes. This is unlikely
/// to be a problem as long as only a modest number of different database names
/// are in use
///
/// A InterprocessCondVar is always process shared.
class InterprocessCondVar {
public:
    InterprocessCondVar();
    ~InterprocessCondVar() noexcept;

    /// To use the InterprocessCondVar, you also must place a structure of type
    /// InterprocessCondVar::SharedPart in memory shared by multiple processes
    /// or in a memory mapped file, and use set_shared_part() to associate
    /// the condition variable with it's shared part. You must initialize
    /// the shared part using InterprocessCondVar::init_shared_part(), but only before
    /// first use and only when you have exclusive access to the shared part.

#ifdef REALM_CONDVAR_EMULATION
    struct SharedPart {
        uint64_t signal_counter;
        uint64_t wait_counter;
    };
#else
    typedef CondVar SharedPart;
#endif

    /// You need to bind the emulation to a SharedPart in shared/mmapped memory.
    /// The SharedPart is assumed to have been initialized (possibly by another process)
    /// earlier through a call to init_shared_part.
    void set_shared_part(SharedPart& shared_part, std::string path, size_t offset_of_condvar);

    /// Initialize the shared part of a process shared condition variable.
    /// A process shared condition variables may be represented by any number of
    /// InterprocessCondVar instances in any number of different processes,
    /// all sharing a common SharedPart instance, which must be in shared memory.
    static void init_shared_part(SharedPart& shared_part);

    /// Wait for someone to call notify() or notify_all() on this condition
    /// variable. The call to wait() may return spuriously, so the caller should
    /// always re-evaluate the condition on which to wait and loop on wait()
    /// if necessary.
    void wait(InterprocessMutex& m, const struct timespec* tp);

    /// If any threads are waiting for this condition, wake up at least one.
    /// (Current implementation may actually wake all :-O ). The caller must
    /// hold the lock associated with the condvar at the time of calling notify()
    void notify() noexcept;

    /// Wake up every thread that is currently waiting on this condition.
    /// The caller must hold the lock associated with the condvar at the time
    /// of calling notify_all().
    void notify_all() noexcept;

    /// Cleanup and release system resources if possible.
    void close() noexcept;

private:
    // non-zero if a shared part has been registered (always 0 on process local instances)
    SharedPart* m_shared_part = nullptr;

    bool uses_emulation = false;
    // pipe used for emulation
    int m_fd_read = -1;
    int m_fd_write = -1;
};

// Implementation:

} // namespace util
} // namespace realm

#endif
<|endoftext|>


<commit_before>/**
 * @file    Heap.hpp
 * @author  niob
 * @date    Oct 21, 2016
 * @brief   Declares and defines the {@link Heap} class.
 */

#ifndef HEAP_HPP_
#define HEAP_HPP_
#pragma once

#include <cstddef>
#include <ostream>
#include <vector>

#include "TaggedPointer.hpp"
#include "TypeDescriptor.hpp"

namespace ssw {

using byte = unsigned char;

class HeapBase
{
	using TypePtr = TaggedPointer;

	class FreeListNode;

	FreeListNode *mFreeList;
	const std::size_t mAlign;
	std::vector<void*> mRoots;

protected:

	/**
	 * Initialize this heap with the specified storage and alignment.
	 *
	 * @param storage Pointer to the storage to use for objects.
	 * @param size Raw size of the storage.
	 * @param align The alignment to use for allocated objects, `storage` must have at least that alignment.
	 */
	HeapBase(byte *storage, std::size_t size, std::size_t align) noexcept;

	/**
	 * Try to allocate a block of memory for the specified type.
	 *
	 * @param type Type descriptor for the memory to allocate.
	 * @return A pointer to the allocated memory block, or `nullptr` if the allocation failed.
	 */
	void* tryAllocate(const TypeDescriptor &type) noexcept;

	/**
	 * Merge free blocks and build a new free list.
	 */
	void mergeBlocks() noexcept;

	/**
	 * Deallocate the specified block by putting it back into the free list. No destructors are called.
	 *
	 * @param block Pointer to the block to deallocate.
	 */
	void deallocate(byte *block) noexcept;

	/**
	 * Align the specified offset to the heap alignment.
	 *
	 * @param offset The offset to align.
	 * @return The offset aligned to the next larger multiple of this heap's alignment.
	 */
	std::size_t align(std::size_t offset) noexcept {
		return (offset + mAlign - 1) & ~(mAlign - 1);
	}

	/**
	 * Get a reference to the type descriptor pointer from an object address. The type descriptor pointer
	 * for that address must already have been created before.
	 *
	 * @param ptr The object address (pointer to a managed object).
	 * @return A reference to the pointer to the type descriptor for the object.
	 */
	static TypePtr& typeDescriptorPtr(byte *ptr) noexcept {
		return *reinterpret_cast<TypePtr*>(ptr - sizeof(TypePtr));
	}

public:

	/**
	 * Allocate a block of memory for the specified type.
	 *
	 * @param type Type descriptor for the memory to allocate.
	 * @param isRoot (optional) Whether to register the allocated object as a heap root.
	 * @return A pointer to the allocated memory block, or `nullptr` if the allocation failed.
	 */
	void* allocate(const TypeDescriptor &type, bool isRoot = false) noexcept;

	/**
	 * Allocate a block of memory for the specified type.
	 *
	 * @param isRoot (optional) Whether to register the allocated object as a heap root.
	 * @return Pointer to the newly allocated and uninitialized object, or `nullptr` if the allocation
	 *         failed.
	 *
	 * @tparam The type to allocate memory for, must have a static member variable `type` that holds the
	 *         type descriptor to use.
	 */
	template <typename T>
	T* allocate(bool isRoot = false) noexcept {
		assert(T::type.size() >= sizeof(T));
		return reinterpret_cast<T*>(allocate(T::type, isRoot));
	}

	/**
	 * Register the specified object as a heap root for garbage collection.
	 *
	 * @param object Pointer to the object to register.
	 */
	void registerRoot(void *object) {
		mRoots.push_back(object);
	}

	/**
	 * Dump the contents of this heap to the specified stream.
	 *
	 * The dump contains a list of live objects, a list of free blocks, and overall statistics.
	 *
	 * @param os The output stream to write to.
	 */
	void dump(std::ostream &os) const;
};

template <std::size_t HeapSize, std::size_t Align = alignof(std::max_align_t)>
class Heap : public HeapBase
{
	// Make storage slightly bigger to allow for type descriptor pointer
	alignas(Align)
	byte mStorage[HeapSize + Align];

public:

	/** The alignment of this heap. */
	static constexpr auto alignment = Align;

	/** The size of this heap. */
	static constexpr auto size = HeapSize;

	Heap() noexcept : HeapBase(mStorage, HeapSize + Align, Align) {
	}
};

} // namespace ssw

#endif /* HEAP_HPP_ */
<commit_msg>Change visibility of several methods in HeapBase.<commit_after>/**
 * @file    Heap.hpp
 * @author  niob
 * @date    Oct 21, 2016
 * @brief   Declares and defines the {@link Heap} class.
 */

#ifndef HEAP_HPP_
#define HEAP_HPP_
#pragma once

#include <cstddef>
#include <ostream>
#include <vector>

#include "TaggedPointer.hpp"
#include "TypeDescriptor.hpp"

namespace ssw {

using byte = unsigned char;

class HeapBase
{
	using TypePtr = TaggedPointer;

	class FreeListNode;

	FreeListNode *mFreeList;
	const std::size_t mAlign;
	std::vector<void*> mRoots;

protected:

	/**
	 * Initialize this heap with the specified storage and alignment.
	 *
	 * @param storage Pointer to the storage to use for objects.
	 * @param size Raw size of the storage.
	 * @param align The alignment to use for allocated objects, `storage` must have at least that alignment.
	 */
	HeapBase(byte *storage, std::size_t size, std::size_t align) noexcept;

public:

	/**
	 * Allocate a block of memory for the specified type.
	 *
	 * @param type Type descriptor for the memory to allocate.
	 * @param isRoot (optional) Whether to register the allocated object as a heap root.
	 * @return A pointer to the allocated memory block, or `nullptr` if the allocation failed.
	 */
	void* allocate(const TypeDescriptor &type, bool isRoot = false) noexcept;

	/**
	 * Allocate a block of memory for the specified type.
	 *
	 * @param isRoot (optional) Whether to register the allocated object as a heap root.
	 * @return Pointer to the newly allocated and uninitialized object, or `nullptr` if the allocation
	 *         failed.
	 *
	 * @tparam The type to allocate memory for, must have a static member variable `type` that holds the
	 *         type descriptor to use.
	 */
	template <typename T>
	T* allocate(bool isRoot = false) noexcept {
		assert(T::type.size() >= sizeof(T));
		return reinterpret_cast<T*>(allocate(T::type, isRoot));
	}

	/**
	 * Deallocate the specified block by putting it back into the free list. No destructors are called.
	 *
	 * This function may be used by `operator delete` of managed objects to free memory immediately instead
	 * of waiting for the next garbage collection. It is not used during garbage collection.
	 *
	 * @param block Pointer to the block to deallocate.
	 */
	void deallocate(byte *block) noexcept;

	/**
	 * Register the specified object as a heap root for garbage collection.
	 *
	 * @param object Pointer to the object to register.
	 */
	void registerRoot(void *object) {
		mRoots.push_back(object);
	}

	/**
	 * Dump the contents of this heap to the specified stream.
	 *
	 * The dump contains a list of live objects, a list of free blocks, and overall statistics.
	 *
	 * @param os The output stream to write to.
	 */
	void dump(std::ostream &os) const;

private:

	/**
	 * Get a reference to the type descriptor pointer from an object address. The type descriptor pointer
	 * for that address must already have been created before.
	 *
	 * @param ptr The object address (pointer to a managed object).
	 * @return A reference to the pointer to the type descriptor for the object.
	 */
	static TypePtr& typeDescriptorPtr(byte *ptr) noexcept {
		return *reinterpret_cast<TypePtr*>(ptr - sizeof(TypePtr));
	}

	/**
	 * Try to allocate a block of memory for the specified type.
	 *
	 * @param type Type descriptor for the memory to allocate.
	 * @return A pointer to the allocated memory block, or `nullptr` if the allocation failed.
	 */
	void* tryAllocate(const TypeDescriptor &type) noexcept;

	/**
	 * Merge free blocks and build a new free list.
	 */
	void mergeBlocks() noexcept;

	/**
	 * Align the specified offset to the heap alignment.
	 *
	 * @param offset The offset to align.
	 * @return The offset aligned to the next larger multiple of this heap's alignment.
	 */
	std::size_t align(std::size_t offset) noexcept {
		return (offset + mAlign - 1) & ~(mAlign - 1);
	}
};

template <std::size_t HeapSize, std::size_t Align = alignof(std::max_align_t)>
class Heap : public HeapBase
{
	// Make storage slightly bigger to allow for type descriptor pointer
	alignas(Align)
	byte mStorage[HeapSize + Align];

public:

	/** The alignment of this heap. */
	static constexpr auto alignment = Align;

	/** The size of this heap. */
	static constexpr auto size = HeapSize;

	Heap() noexcept : HeapBase(mStorage, HeapSize + Align, Align) {
	}
};

} // namespace ssw

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