<commit_before>#include "TextureCube.hpp"

#include "Error.hpp"
#include "InvalidObject.hpp"
#include "Buffer.hpp"

#include "InlineMethods.hpp"

PyObject * MGLTextureCube_tp_new(PyTypeObject * type, PyObject * args, PyObject * kwargs) {
	MGLTextureCube * self = (MGLTextureCube *)type->tp_alloc(type, 0);

	#ifdef MGL_VERBOSE
	printf("MGLTextureCube_tp_new %p\n", self);
	#endif

	if (self) {
	}

	return (PyObject *)self;
}

void MGLTextureCube_tp_dealloc(MGLTextureCube * self) {

	#ifdef MGL_VERBOSE
	printf("MGLTextureCube_tp_dealloc %p\n", self);
	#endif

	MGLTextureCube_Type.tp_free((PyObject *)self);
}

int MGLTextureCube_tp_init(MGLTextureCube * self, PyObject * args, PyObject * kwargs) {
	MGLError_Set("cannot create mgl.TextureCube manually");
	return -1;
}

PyObject * MGLTextureCube_read(MGLTextureCube * self, PyObject * args) {
	int face;
	int alignment;

	int args_ok = PyArg_ParseTuple(
		args,
		"iI",
		&face,
		&alignment
	);

	if (!args_ok) {
		return 0;
	}

	if (face < 0 || face > 5) {
		MGLError_Set("the face must be 0, 1, 2, 3, 4 or 5");
		return 0;
	}

	if (alignment != 1 && alignment != 2 && alignment != 4 && alignment != 8) {
		MGLError_Set("the alignment must be 1, 2, 4 or 8");
		return 0;
	}

	int expected_size = self->width * self->components * (self->floats ? 4 : 1);
	expected_size = (expected_size + alignment - 1) / alignment * alignment;
	expected_size = expected_size * self->height;

	PyObject * result = PyBytes_FromStringAndSize(0, expected_size);
	char * data = PyBytes_AS_STRING(result);

	const int formats[] = {0, GL_RED, GL_RG, GL_RGB, GL_RGBA};
	const int faces[] = {
		GL_TEXTURE_CUBE_MAP_POSITIVE_X,
		GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
		GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
		GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
		GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
		GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
	};

	int pixel_type = self->floats ? GL_FLOAT : GL_UNSIGNED_BYTE;
	int format = formats[self->components];

	const GLMethods & gl = self->context->gl;

	gl.ActiveTexture(GL_TEXTURE0 + self->context->default_texture_unit);
	gl.BindTexture(GL_TEXTURE_CUBE_MAP, self->texture_obj);

	gl.PixelStorei(GL_PACK_ALIGNMENT, alignment);
	gl.PixelStorei(GL_UNPACK_ALIGNMENT, alignment);
	gl.GetTexImage(faces[face], 0, format, pixel_type, data);

	return result;
}

PyObject * MGLTextureCube_read_into(MGLTextureCube * self, PyObject * args) {
	PyObject * data;
	int face;
	int alignment;
	Py_ssize_t write_offset;

	int args_ok = PyArg_ParseTuple(
		args,
		"OiIn",
		&data,
		&face,
		&alignment,
		&write_offset
	);

	if (!args_ok) {
		return 0;
	}

	if (face < 0 || face > 5) {
		MGLError_Set("the face must be 0, 1, 2, 3, 4 or 5");
		return 0;
	}

	if (alignment != 1 && alignment != 2 && alignment != 4 && alignment != 8) {
		MGLError_Set("the alignment must be 1, 2, 4 or 8");
		return 0;
	}

	int expected_size = self->width * self->components * (self->floats ? 4 : 1);
	expected_size = (expected_size + alignment - 1) / alignment * alignment;
	expected_size = expected_size * self->height;

	const int formats[] = {0, GL_RED, GL_RG, GL_RGB, GL_RGBA};
	const int faces[] = {
		GL_TEXTURE_CUBE_MAP_POSITIVE_X,
		GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
		GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
		GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
		GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
		GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
	};

	int pixel_type = self->floats ? GL_FLOAT : GL_UNSIGNED_BYTE;
	int format = formats[self->components];

	if (Py_TYPE(data) == &MGLBuffer_Type) {

		MGLBuffer * buffer = (MGLBuffer *)data;

		const GLMethods & gl = self->context->gl;

		gl.BindBuffer(GL_PIXEL_PACK_BUFFER, buffer->buffer_obj);
		gl.ActiveTexture(GL_TEXTURE0 + self->context->default_texture_unit);
		gl.BindTexture(GL_TEXTURE_CUBE_MAP, self->texture_obj);
		gl.PixelStorei(GL_PACK_ALIGNMENT, alignment);
		gl.PixelStorei(GL_UNPACK_ALIGNMENT, alignment);
		gl.GetTexImage(faces[face], 0, format, pixel_type, (char *)write_offset);
		gl.BindBuffer(GL_PIXEL_PACK_BUFFER, 0);

	} else {

		Py_buffer buffer_view;

		int get_buffer = PyObject_GetBuffer(data, &buffer_view, PyBUF_WRITABLE);
		if (get_buffer < 0) {
			MGLError_Set("the buffer (%s) does not support buffer interface", Py_TYPE(data)->tp_name);
			return 0;
		}

		if (buffer_view.len < write_offset + expected_size) {
			MGLError_Set("the buffer is too small");
			PyBuffer_Release(&buffer_view);
			return 0;
		}

		char * ptr = (char *)buffer_view.buf + write_offset;

		const GLMethods & gl = self->context->gl;
		gl.ActiveTexture(GL_TEXTURE0 + self->context->default_texture_unit);
		gl.BindTexture(GL_TEXTURE_CUBE_MAP, self->texture_obj);
		gl.PixelStorei(GL_PACK_ALIGNMENT, alignment);
		gl.PixelStorei(GL_UNPACK_ALIGNMENT, alignment);
		gl.GetTexImage(faces[face], 0, format, pixel_type, ptr);

		PyBuffer_Release(&buffer_view);

	}

	Py_RETURN_NONE;
}

PyObject * MGLTextureCube_use(MGLTextureCube * self, PyObject * args) {
	int index;

	int args_ok = PyArg_ParseTuple(
		args,
		"I",
		&index
	);

	if (!args_ok) {
		return 0;
	}

	const GLMethods & gl = self->context->gl;
	gl.ActiveTexture(GL_TEXTURE0 + index);
	gl.BindTexture(GL_TEXTURE_CUBE_MAP, self->texture_obj);

	Py_RETURN_NONE;
}

PyObject * MGLTextureCube_release(MGLTextureCube * self) {
	MGLTextureCube_Invalidate(self);
	Py_RETURN_NONE;
}

PyMethodDef MGLTextureCube_tp_methods[] = {
	{"use", (PyCFunction)MGLTextureCube_use, METH_VARARGS, 0},
	{"release", (PyCFunction)MGLTextureCube_release, METH_NOARGS, 0},
	{0},
};

MGLContext * MGLTextureCube_get_context(MGLTextureCube * self, void * closure) {
	Py_INCREF(self->context);
	return self->context;
}

PyObject * MGLTextureCube_get_glo(MGLTextureCube * self, void * closure) {
	return PyLong_FromLong(self->texture_obj);
}

PyGetSetDef MGLTextureCube_tp_getseters[] = {
	{(char *)"context", (getter)MGLTextureCube_get_context, 0, 0, 0},
	{(char *)"glo", (getter)MGLTextureCube_get_glo, 0, 0, 0},
	{0},
};

PyTypeObject MGLTextureCube_Type = {
	PyVarObject_HEAD_INIT(0, 0)
	"mgl.TextureCube",                                      // tp_name
	sizeof(MGLTextureCube),                                 // tp_basicsize
	0,                                                      // tp_itemsize
	(destructor)MGLTextureCube_tp_dealloc,                  // tp_dealloc
	0,                                                      // tp_print
	0,                                                      // tp_getattr
	0,                                                      // tp_setattr
	0,                                                      // tp_reserved
	0,                                                      // tp_repr
	0,                                                      // tp_as_number
	0,                                                      // tp_as_sequence
	0,                                                      // tp_as_mapping
	0,                                                      // tp_hash
	0,                                                      // tp_call
	0,                                                      // tp_str
	0,                                                      // tp_getattro
	0,                                                      // tp_setattro
	0,                                                      // tp_as_buffer
	Py_TPFLAGS_DEFAULT,                                     // tp_flags
	0,                                                      // tp_doc
	0,                                                      // tp_traverse
	0,                                                      // tp_clear
	0,                                                      // tp_richcompare
	0,                                                      // tp_weaklistoffset
	0,                                                      // tp_iter
	0,                                                      // tp_iternext
	MGLTextureCube_tp_methods,                              // tp_methods
	0,                                                      // tp_members
	MGLTextureCube_tp_getseters,                            // tp_getset
	0,                                                      // tp_base
	0,                                                      // tp_dict
	0,                                                      // tp_descr_get
	0,                                                      // tp_descr_set
	0,                                                      // tp_dictoffset
	(initproc)MGLTextureCube_tp_init,                       // tp_init
	0,                                                      // tp_alloc
	MGLTextureCube_tp_new,                                  // tp_new
};

MGLTextureCube * MGLTextureCube_New() {
	MGLTextureCube * self = (MGLTextureCube *)MGLTextureCube_tp_new(&MGLTextureCube_Type, 0, 0);
	return self;
}

void MGLTextureCube_Invalidate(MGLTextureCube * texture) {
	if (Py_TYPE(texture) == &MGLInvalidObject_Type) {

		#ifdef MGL_VERBOSE
		printf("MGLTextureCube_Invalidate %p already released\n", texture);
		#endif

		return;
	}

	#ifdef MGL_VERBOSE
	printf("MGLTextureCube_Invalidate %p\n", texture);
	#endif

	texture->context->gl.DeleteTextures(1, (GLuint *)&texture->texture_obj);

	Py_DECREF(texture->context);

	Py_TYPE(texture) = &MGLInvalidObject_Type;

	Py_DECREF(texture);
}
<commit_msg>register methods<commit_after>#include "TextureCube.hpp"

#include "Error.hpp"
#include "InvalidObject.hpp"
#include "Buffer.hpp"

#include "InlineMethods.hpp"

PyObject * MGLTextureCube_tp_new(PyTypeObject * type, PyObject * args, PyObject * kwargs) {
	MGLTextureCube * self = (MGLTextureCube *)type->tp_alloc(type, 0);

	#ifdef MGL_VERBOSE
	printf("MGLTextureCube_tp_new %p\n", self);
	#endif

	if (self) {
	}

	return (PyObject *)self;
}

void MGLTextureCube_tp_dealloc(MGLTextureCube * self) {

	#ifdef MGL_VERBOSE
	printf("MGLTextureCube_tp_dealloc %p\n", self);
	#endif

	MGLTextureCube_Type.tp_free((PyObject *)self);
}

int MGLTextureCube_tp_init(MGLTextureCube * self, PyObject * args, PyObject * kwargs) {
	MGLError_Set("cannot create mgl.TextureCube manually");
	return -1;
}

PyObject * MGLTextureCube_read(MGLTextureCube * self, PyObject * args) {
	int face;
	int alignment;

	int args_ok = PyArg_ParseTuple(
		args,
		"iI",
		&face,
		&alignment
	);

	if (!args_ok) {
		return 0;
	}

	if (face < 0 || face > 5) {
		MGLError_Set("the face must be 0, 1, 2, 3, 4 or 5");
		return 0;
	}

	if (alignment != 1 && alignment != 2 && alignment != 4 && alignment != 8) {
		MGLError_Set("the alignment must be 1, 2, 4 or 8");
		return 0;
	}

	int expected_size = self->width * self->components * (self->floats ? 4 : 1);
	expected_size = (expected_size + alignment - 1) / alignment * alignment;
	expected_size = expected_size * self->height;

	PyObject * result = PyBytes_FromStringAndSize(0, expected_size);
	char * data = PyBytes_AS_STRING(result);

	const int formats[] = {0, GL_RED, GL_RG, GL_RGB, GL_RGBA};
	const int faces[] = {
		GL_TEXTURE_CUBE_MAP_POSITIVE_X,
		GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
		GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
		GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
		GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
		GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
	};

	int pixel_type = self->floats ? GL_FLOAT : GL_UNSIGNED_BYTE;
	int format = formats[self->components];

	const GLMethods & gl = self->context->gl;

	gl.ActiveTexture(GL_TEXTURE0 + self->context->default_texture_unit);
	gl.BindTexture(GL_TEXTURE_CUBE_MAP, self->texture_obj);

	gl.PixelStorei(GL_PACK_ALIGNMENT, alignment);
	gl.PixelStorei(GL_UNPACK_ALIGNMENT, alignment);
	gl.GetTexImage(faces[face], 0, format, pixel_type, data);

	return result;
}

PyObject * MGLTextureCube_read_into(MGLTextureCube * self, PyObject * args) {
	PyObject * data;
	int face;
	int alignment;
	Py_ssize_t write_offset;

	int args_ok = PyArg_ParseTuple(
		args,
		"OiIn",
		&data,
		&face,
		&alignment,
		&write_offset
	);

	if (!args_ok) {
		return 0;
	}

	if (face < 0 || face > 5) {
		MGLError_Set("the face must be 0, 1, 2, 3, 4 or 5");
		return 0;
	}

	if (alignment != 1 && alignment != 2 && alignment != 4 && alignment != 8) {
		MGLError_Set("the alignment must be 1, 2, 4 or 8");
		return 0;
	}

	int expected_size = self->width * self->components * (self->floats ? 4 : 1);
	expected_size = (expected_size + alignment - 1) / alignment * alignment;
	expected_size = expected_size * self->height;

	const int formats[] = {0, GL_RED, GL_RG, GL_RGB, GL_RGBA};
	const int faces[] = {
		GL_TEXTURE_CUBE_MAP_POSITIVE_X,
		GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
		GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
		GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
		GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
		GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
	};

	int pixel_type = self->floats ? GL_FLOAT : GL_UNSIGNED_BYTE;
	int format = formats[self->components];

	if (Py_TYPE(data) == &MGLBuffer_Type) {

		MGLBuffer * buffer = (MGLBuffer *)data;

		const GLMethods & gl = self->context->gl;

		gl.BindBuffer(GL_PIXEL_PACK_BUFFER, buffer->buffer_obj);
		gl.ActiveTexture(GL_TEXTURE0 + self->context->default_texture_unit);
		gl.BindTexture(GL_TEXTURE_CUBE_MAP, self->texture_obj);
		gl.PixelStorei(GL_PACK_ALIGNMENT, alignment);
		gl.PixelStorei(GL_UNPACK_ALIGNMENT, alignment);
		gl.GetTexImage(faces[face], 0, format, pixel_type, (char *)write_offset);
		gl.BindBuffer(GL_PIXEL_PACK_BUFFER, 0);

	} else {

		Py_buffer buffer_view;

		int get_buffer = PyObject_GetBuffer(data, &buffer_view, PyBUF_WRITABLE);
		if (get_buffer < 0) {
			MGLError_Set("the buffer (%s) does not support buffer interface", Py_TYPE(data)->tp_name);
			return 0;
		}

		if (buffer_view.len < write_offset + expected_size) {
			MGLError_Set("the buffer is too small");
			PyBuffer_Release(&buffer_view);
			return 0;
		}

		char * ptr = (char *)buffer_view.buf + write_offset;

		const GLMethods & gl = self->context->gl;
		gl.ActiveTexture(GL_TEXTURE0 + self->context->default_texture_unit);
		gl.BindTexture(GL_TEXTURE_CUBE_MAP, self->texture_obj);
		gl.PixelStorei(GL_PACK_ALIGNMENT, alignment);
		gl.PixelStorei(GL_UNPACK_ALIGNMENT, alignment);
		gl.GetTexImage(faces[face], 0, format, pixel_type, ptr);

		PyBuffer_Release(&buffer_view);

	}

	Py_RETURN_NONE;
}

PyObject * MGLTextureCube_use(MGLTextureCube * self, PyObject * args) {
	int index;

	int args_ok = PyArg_ParseTuple(
		args,
		"I",
		&index
	);

	if (!args_ok) {
		return 0;
	}

	const GLMethods & gl = self->context->gl;
	gl.ActiveTexture(GL_TEXTURE0 + index);
	gl.BindTexture(GL_TEXTURE_CUBE_MAP, self->texture_obj);

	Py_RETURN_NONE;
}

PyObject * MGLTextureCube_release(MGLTextureCube * self) {
	MGLTextureCube_Invalidate(self);
	Py_RETURN_NONE;
}

PyMethodDef MGLTextureCube_tp_methods[] = {
	{"read", (PyCFunction)MGLTextureCube_read, METH_VARARGS, 0},
	{"read_into", (PyCFunction)MGLTextureCube_read_into, METH_VARARGS, 0},
	{"use", (PyCFunction)MGLTextureCube_use, METH_VARARGS, 0},
	{"release", (PyCFunction)MGLTextureCube_release, METH_NOARGS, 0},
	{0},
};

MGLContext * MGLTextureCube_get_context(MGLTextureCube * self, void * closure) {
	Py_INCREF(self->context);
	return self->context;
}

PyObject * MGLTextureCube_get_glo(MGLTextureCube * self, void * closure) {
	return PyLong_FromLong(self->texture_obj);
}

PyGetSetDef MGLTextureCube_tp_getseters[] = {
	{(char *)"context", (getter)MGLTextureCube_get_context, 0, 0, 0},
	{(char *)"glo", (getter)MGLTextureCube_get_glo, 0, 0, 0},
	{0},
};

PyTypeObject MGLTextureCube_Type = {
	PyVarObject_HEAD_INIT(0, 0)
	"mgl.TextureCube",                                      // tp_name
	sizeof(MGLTextureCube),                                 // tp_basicsize
	0,                                                      // tp_itemsize
	(destructor)MGLTextureCube_tp_dealloc,                  // tp_dealloc
	0,                                                      // tp_print
	0,                                                      // tp_getattr
	0,                                                      // tp_setattr
	0,                                                      // tp_reserved
	0,                                                      // tp_repr
	0,                                                      // tp_as_number
	0,                                                      // tp_as_sequence
	0,                                                      // tp_as_mapping
	0,                                                      // tp_hash
	0,                                                      // tp_call
	0,                                                      // tp_str
	0,                                                      // tp_getattro
	0,                                                      // tp_setattro
	0,                                                      // tp_as_buffer
	Py_TPFLAGS_DEFAULT,                                     // tp_flags
	0,                                                      // tp_doc
	0,                                                      // tp_traverse
	0,                                                      // tp_clear
	0,                                                      // tp_richcompare
	0,                                                      // tp_weaklistoffset
	0,                                                      // tp_iter
	0,                                                      // tp_iternext
	MGLTextureCube_tp_methods,                              // tp_methods
	0,                                                      // tp_members
	MGLTextureCube_tp_getseters,                            // tp_getset
	0,                                                      // tp_base
	0,                                                      // tp_dict
	0,                                                      // tp_descr_get
	0,                                                      // tp_descr_set
	0,                                                      // tp_dictoffset
	(initproc)MGLTextureCube_tp_init,                       // tp_init
	0,                                                      // tp_alloc
	MGLTextureCube_tp_new,                                  // tp_new
};

MGLTextureCube * MGLTextureCube_New() {
	MGLTextureCube * self = (MGLTextureCube *)MGLTextureCube_tp_new(&MGLTextureCube_Type, 0, 0);
	return self;
}

void MGLTextureCube_Invalidate(MGLTextureCube * texture) {
	if (Py_TYPE(texture) == &MGLInvalidObject_Type) {

		#ifdef MGL_VERBOSE
		printf("MGLTextureCube_Invalidate %p already released\n", texture);
		#endif

		return;
	}

	#ifdef MGL_VERBOSE
	printf("MGLTextureCube_Invalidate %p\n", texture);
	#endif

	texture->context->gl.DeleteTextures(1, (GLuint *)&texture->texture_obj);

	Py_DECREF(texture->context);

	Py_TYPE(texture) = &MGLInvalidObject_Type;

	Py_DECREF(texture);
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2017 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Daniel H. Larkin
////////////////////////////////////////////////////////////////////////////////

#include "RocksDBEngine/RocksDBLogValue.h"
#include "Basics/Common.h"
#include "Basics/Exceptions.h"
#include "RocksDBEngine/RocksDBCommon.h"

using namespace arangodb;
using namespace arangodb::rocksutils;

RocksDBLogValue RocksDBLogValue::DatabaseCreate() {
  return RocksDBLogValue(RocksDBLogType::DatabaseCreate);
}

RocksDBLogValue RocksDBLogValue::DatabaseDrop(TRI_voc_tick_t dbid) {
  return RocksDBLogValue(RocksDBLogType::DatabaseDrop, dbid);
}

RocksDBLogValue RocksDBLogValue::CollectionCreate(TRI_voc_tick_t dbid,
                                                  TRI_voc_cid_t cid) {
  return RocksDBLogValue(RocksDBLogType::CollectionCreate, dbid, cid);
}

RocksDBLogValue RocksDBLogValue::CollectionDrop(TRI_voc_tick_t dbid,
                                                TRI_voc_cid_t cid) {
  return RocksDBLogValue(RocksDBLogType::CollectionDrop, dbid, cid);
}

RocksDBLogValue RocksDBLogValue::CollectionRename(TRI_voc_tick_t dbid,
                                                  TRI_voc_cid_t cid,
                                                  StringRef const& newName) {
  return RocksDBLogValue(RocksDBLogType::CollectionRename, dbid, cid, newName);
}

RocksDBLogValue RocksDBLogValue::CollectionChange(TRI_voc_tick_t dbid,
                                                  TRI_voc_cid_t cid) {
  return RocksDBLogValue(RocksDBLogType::CollectionChange, dbid, cid);
}

RocksDBLogValue RocksDBLogValue::IndexCreate(TRI_voc_tick_t dbid,
                                             TRI_voc_cid_t cid,
                                             VPackSlice const& indexInfo) {
  return RocksDBLogValue(RocksDBLogType::IndexCreate, dbid, cid, indexInfo);
}

RocksDBLogValue RocksDBLogValue::IndexDrop(TRI_voc_tick_t dbid,
                                           TRI_voc_cid_t cid,
                                           TRI_idx_iid_t iid) {
  return RocksDBLogValue(RocksDBLogType::IndexDrop, dbid, cid, iid);
}

RocksDBLogValue RocksDBLogValue::ViewCreate(TRI_voc_cid_t cid,
                                            TRI_idx_iid_t iid) {
  return RocksDBLogValue(RocksDBLogType::ViewCreate, cid, iid);
}

RocksDBLogValue RocksDBLogValue::ViewDrop(TRI_voc_cid_t cid,
                                          TRI_idx_iid_t iid) {
  return RocksDBLogValue(RocksDBLogType::ViewDrop, cid, iid);
}

RocksDBLogValue RocksDBLogValue::BeginTransaction(TRI_voc_tick_t dbid,
                                                  TRI_voc_tid_t tid) {
  return RocksDBLogValue(RocksDBLogType::BeginTransaction, dbid, tid);
}

RocksDBLogValue RocksDBLogValue::DocumentOpsPrologue(TRI_voc_cid_t cid) {
  return RocksDBLogValue(RocksDBLogType::DocumentOperationsPrologue, cid);
}

RocksDBLogValue RocksDBLogValue::DocumentRemove(
    arangodb::StringRef const& key) {
  return RocksDBLogValue(RocksDBLogType::DocumentRemove, key);
}

RocksDBLogValue RocksDBLogValue::SinglePut(TRI_voc_tick_t vocbaseId,
                                           TRI_voc_cid_t cid) {
  return RocksDBLogValue(RocksDBLogType::SinglePut, vocbaseId, cid);
}
RocksDBLogValue RocksDBLogValue::SingleRemove(TRI_voc_tick_t vocbaseId,
                                              TRI_voc_cid_t cid,
                                              arangodb::StringRef const& key) {
  return RocksDBLogValue(RocksDBLogType::SingleRemove, vocbaseId, cid, key);
}

RocksDBLogValue::RocksDBLogValue(RocksDBLogType type) : _buffer() {
  switch (type) {
    case RocksDBLogType::DatabaseCreate:
      _buffer.reserve(sizeof(RocksDBLogType));
      _buffer.push_back(static_cast<char>(type));
      break;
    default:
      THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
  }
}

RocksDBLogValue::RocksDBLogValue(RocksDBLogType type, uint64_t val)
    : _buffer() {
  switch (type) {
    case RocksDBLogType::DatabaseDrop:
    case RocksDBLogType::DocumentOperationsPrologue: {
      _buffer.reserve(sizeof(RocksDBLogType) + sizeof(uint64_t));
      _buffer.push_back(static_cast<char>(type));
      uint64ToPersistent(_buffer, val);  // database or collection ID
      break;
    }

    default:
      THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
  }
}

RocksDBLogValue::RocksDBLogValue(RocksDBLogType type, uint64_t dbId,
                                 uint64_t val2)
    : _buffer() {
  switch (type) {
    case RocksDBLogType::CollectionCreate:
    case RocksDBLogType::CollectionChange:
    case RocksDBLogType::CollectionDrop:
    case RocksDBLogType::BeginTransaction:
    case RocksDBLogType::SinglePut: {
      _buffer.reserve(sizeof(RocksDBLogType) + sizeof(uint64_t) * 2);
      _buffer.push_back(static_cast<char>(type));
      uint64ToPersistent(_buffer, dbId);
      uint64ToPersistent(_buffer, val2);
      break;
    }

    default:
      THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
  }
}

RocksDBLogValue::RocksDBLogValue(RocksDBLogType type, uint64_t dbId,
                                 uint64_t cid, uint64_t iid)
    : _buffer() {
  switch (type) {
    case RocksDBLogType::IndexDrop: {
      _buffer.reserve(sizeof(RocksDBLogType) + sizeof(uint64_t) * 3);
      _buffer.push_back(static_cast<char>(type));
      uint64ToPersistent(_buffer, dbId);
      uint64ToPersistent(_buffer, cid);
      uint64ToPersistent(_buffer, iid);
      break;
    }
    default:
      THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
  }
}

RocksDBLogValue::RocksDBLogValue(RocksDBLogType type, uint64_t dbId,
                                 uint64_t cid, VPackSlice const& indexInfo)
    : _buffer() {
  switch (type) {
    case RocksDBLogType::IndexCreate: {
      _buffer.reserve(sizeof(RocksDBLogType) + (sizeof(uint64_t) * 2) +
                      indexInfo.byteSize());
      _buffer.push_back(static_cast<char>(type));
      uint64ToPersistent(_buffer, dbId);
      uint64ToPersistent(_buffer, cid);
      _buffer.append(reinterpret_cast<char const*>(indexInfo.begin()),
                     indexInfo.byteSize());
      break;
    }
    default:
      THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
  }
}

RocksDBLogValue::RocksDBLogValue(RocksDBLogType type, uint64_t dbId,
                                 uint64_t cid, StringRef const& data)
    : _buffer() {
  switch (type) {
    case RocksDBLogType::CollectionRename: {
      _buffer.reserve(sizeof(RocksDBLogType) + sizeof(uint64_t) * 2 +
                      data.length());
      _buffer.push_back(static_cast<char>(type));
      uint64ToPersistent(_buffer, dbId);
      uint64ToPersistent(_buffer, cid);
      _buffer.append(data.data(), data.length());  // primary key
      break;
    }
    default:
      THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
  }
}

RocksDBLogValue::RocksDBLogValue(RocksDBLogType type, StringRef const& data)
    : _buffer() {
  switch (type) {
    case RocksDBLogType::DocumentRemove: {
      _buffer.reserve(data.length() + sizeof(RocksDBLogType));
      _buffer.push_back(static_cast<char>(type));
      _buffer.append(data.data(), data.length());  // primary key
      break;
    }

    default:
      THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
  }
}

// ================= Instance Methods ===================

RocksDBLogType RocksDBLogValue::type(rocksdb::Slice const& slice) {
  TRI_ASSERT(slice.size() >= sizeof(RocksDBLogType));
  return static_cast<RocksDBLogType>(slice.data()[0]);
}

TRI_voc_tick_t RocksDBLogValue::databaseId(rocksdb::Slice const& slice) {
  TRI_ASSERT(slice.size() >= sizeof(RocksDBLogType) + sizeof(uint64_t));
  RocksDBLogType type = static_cast<RocksDBLogType>(slice.data()[0]);
  TRI_ASSERT(type == RocksDBLogType::DatabaseCreate ||
             type == RocksDBLogType::DatabaseDrop ||
             type == RocksDBLogType::CollectionCreate ||
             type == RocksDBLogType::CollectionDrop ||
             type == RocksDBLogType::CollectionRename ||
             type == RocksDBLogType::CollectionChange ||
             type == RocksDBLogType::IndexCreate ||
             type == RocksDBLogType::IndexDrop ||
             type == RocksDBLogType::BeginTransaction ||
             type == RocksDBLogType::SinglePut ||
             type == RocksDBLogType::SingleRemove);
  return uint64FromPersistent(slice.data() + sizeof(RocksDBLogType));
}

TRI_voc_cid_t RocksDBLogValue::collectionId(rocksdb::Slice const& slice) {
  TRI_ASSERT(slice.size() >= sizeof(RocksDBLogType) + sizeof(uint64_t));
  RocksDBLogType type = static_cast<RocksDBLogType>(slice.data()[0]);
  TRI_ASSERT(type == RocksDBLogType::CollectionCreate ||
             type == RocksDBLogType::CollectionDrop ||
             type == RocksDBLogType::CollectionRename ||
             type == RocksDBLogType::CollectionChange ||
             type == RocksDBLogType::IndexCreate ||
             type == RocksDBLogType::IndexDrop ||
             type == RocksDBLogType::DocumentOperationsPrologue ||
             type == RocksDBLogType::SinglePut ||
             type == RocksDBLogType::SingleRemove);
  if (type == RocksDBLogType::DocumentOperationsPrologue) {  // only exception
    return uint64FromPersistent(slice.data() + sizeof(RocksDBLogType));
  } else {
    TRI_ASSERT(slice.size() >= sizeof(RocksDBLogType) + sizeof(uint64_t) * 2);
    return uint64FromPersistent(slice.data() + sizeof(RocksDBLogType) +
                                sizeof(uint64_t));
  }
}

TRI_voc_tid_t RocksDBLogValue::transactionId(rocksdb::Slice const& slice) {
  TRI_ASSERT(slice.size() >= sizeof(RocksDBLogType) + sizeof(uint64_t));
  RocksDBLogType type = static_cast<RocksDBLogType>(slice.data()[0]);
  TRI_ASSERT(type == RocksDBLogType::BeginTransaction);
  return uint64FromPersistent(slice.data() + sizeof(RocksDBLogType) +
                              sizeof(TRI_voc_tick_t));
}

TRI_idx_iid_t RocksDBLogValue::indexId(rocksdb::Slice const& slice) {
  TRI_ASSERT(slice.size() >= sizeof(RocksDBLogType) + sizeof(uint64_t));
  RocksDBLogType type = static_cast<RocksDBLogType>(slice.data()[0]);
  TRI_ASSERT(type == RocksDBLogType::IndexDrop);
  return uint64FromPersistent(slice.data() + sizeof(RocksDBLogType));
}

VPackSlice RocksDBLogValue::indexSlice(rocksdb::Slice const& slice) {
  TRI_ASSERT(slice.size() >= sizeof(RocksDBLogType) + sizeof(uint64_t) * 2);
  RocksDBLogType type = static_cast<RocksDBLogType>(slice.data()[0]);
  TRI_ASSERT(type == RocksDBLogType::IndexCreate ||
             type == RocksDBLogType::ViewCreate ||
             type == RocksDBLogType::ViewChange);
  return VPackSlice(slice.data() + sizeof(RocksDBLogType) +
                    sizeof(uint64_t) * 2);
}

arangodb::StringRef RocksDBLogValue::newCollectionName(
    rocksdb::Slice const& slice) {
  size_t off = sizeof(RocksDBLogType) + sizeof(uint64_t) * 2;
  TRI_ASSERT(slice.size() >= off);
  RocksDBLogType type = static_cast<RocksDBLogType>(slice.data()[0]);
  TRI_ASSERT(type == RocksDBLogType::CollectionRename);
  return StringRef(slice.data() + off, slice.size() - off);
}

arangodb::StringRef RocksDBLogValue::documentKey(rocksdb::Slice const& slice) {
  RocksDBLogType type = static_cast<RocksDBLogType>(slice.data()[0]);
  TRI_ASSERT(type == RocksDBLogType::SingleRemove ||
             type == RocksDBLogType::DocumentRemove);
  size_t off = sizeof(RocksDBLogType);
  if (type == RocksDBLogType::SingleRemove) {
    off += sizeof(uint64_t) * 2;
  }
  TRI_ASSERT(slice.size() >= off);
  return StringRef(slice.data() + off, slice.size() - off);
}
<commit_msg>Fixed bug with drop index marker.<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2017 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Daniel H. Larkin
////////////////////////////////////////////////////////////////////////////////

#include "RocksDBEngine/RocksDBLogValue.h"
#include "Basics/Common.h"
#include "Basics/Exceptions.h"
#include "RocksDBEngine/RocksDBCommon.h"

using namespace arangodb;
using namespace arangodb::rocksutils;

RocksDBLogValue RocksDBLogValue::DatabaseCreate() {
  return RocksDBLogValue(RocksDBLogType::DatabaseCreate);
}

RocksDBLogValue RocksDBLogValue::DatabaseDrop(TRI_voc_tick_t dbid) {
  return RocksDBLogValue(RocksDBLogType::DatabaseDrop, dbid);
}

RocksDBLogValue RocksDBLogValue::CollectionCreate(TRI_voc_tick_t dbid,
                                                  TRI_voc_cid_t cid) {
  return RocksDBLogValue(RocksDBLogType::CollectionCreate, dbid, cid);
}

RocksDBLogValue RocksDBLogValue::CollectionDrop(TRI_voc_tick_t dbid,
                                                TRI_voc_cid_t cid) {
  return RocksDBLogValue(RocksDBLogType::CollectionDrop, dbid, cid);
}

RocksDBLogValue RocksDBLogValue::CollectionRename(TRI_voc_tick_t dbid,
                                                  TRI_voc_cid_t cid,
                                                  StringRef const& newName) {
  return RocksDBLogValue(RocksDBLogType::CollectionRename, dbid, cid, newName);
}

RocksDBLogValue RocksDBLogValue::CollectionChange(TRI_voc_tick_t dbid,
                                                  TRI_voc_cid_t cid) {
  return RocksDBLogValue(RocksDBLogType::CollectionChange, dbid, cid);
}

RocksDBLogValue RocksDBLogValue::IndexCreate(TRI_voc_tick_t dbid,
                                             TRI_voc_cid_t cid,
                                             VPackSlice const& indexInfo) {
  return RocksDBLogValue(RocksDBLogType::IndexCreate, dbid, cid, indexInfo);
}

RocksDBLogValue RocksDBLogValue::IndexDrop(TRI_voc_tick_t dbid,
                                           TRI_voc_cid_t cid,
                                           TRI_idx_iid_t iid) {
  return RocksDBLogValue(RocksDBLogType::IndexDrop, dbid, cid, iid);
}

RocksDBLogValue RocksDBLogValue::ViewCreate(TRI_voc_cid_t cid,
                                            TRI_idx_iid_t iid) {
  return RocksDBLogValue(RocksDBLogType::ViewCreate, cid, iid);
}

RocksDBLogValue RocksDBLogValue::ViewDrop(TRI_voc_cid_t cid,
                                          TRI_idx_iid_t iid) {
  return RocksDBLogValue(RocksDBLogType::ViewDrop, cid, iid);
}

RocksDBLogValue RocksDBLogValue::BeginTransaction(TRI_voc_tick_t dbid,
                                                  TRI_voc_tid_t tid) {
  return RocksDBLogValue(RocksDBLogType::BeginTransaction, dbid, tid);
}

RocksDBLogValue RocksDBLogValue::DocumentOpsPrologue(TRI_voc_cid_t cid) {
  return RocksDBLogValue(RocksDBLogType::DocumentOperationsPrologue, cid);
}

RocksDBLogValue RocksDBLogValue::DocumentRemove(
    arangodb::StringRef const& key) {
  return RocksDBLogValue(RocksDBLogType::DocumentRemove, key);
}

RocksDBLogValue RocksDBLogValue::SinglePut(TRI_voc_tick_t vocbaseId,
                                           TRI_voc_cid_t cid) {
  return RocksDBLogValue(RocksDBLogType::SinglePut, vocbaseId, cid);
}
RocksDBLogValue RocksDBLogValue::SingleRemove(TRI_voc_tick_t vocbaseId,
                                              TRI_voc_cid_t cid,
                                              arangodb::StringRef const& key) {
  return RocksDBLogValue(RocksDBLogType::SingleRemove, vocbaseId, cid, key);
}

RocksDBLogValue::RocksDBLogValue(RocksDBLogType type) : _buffer() {
  switch (type) {
    case RocksDBLogType::DatabaseCreate:
      _buffer.reserve(sizeof(RocksDBLogType));
      _buffer.push_back(static_cast<char>(type));
      break;
    default:
      THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
  }
}

RocksDBLogValue::RocksDBLogValue(RocksDBLogType type, uint64_t val)
    : _buffer() {
  switch (type) {
    case RocksDBLogType::DatabaseDrop:
    case RocksDBLogType::DocumentOperationsPrologue: {
      _buffer.reserve(sizeof(RocksDBLogType) + sizeof(uint64_t));
      _buffer.push_back(static_cast<char>(type));
      uint64ToPersistent(_buffer, val);  // database or collection ID
      break;
    }

    default:
      THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
  }
}

RocksDBLogValue::RocksDBLogValue(RocksDBLogType type, uint64_t dbId,
                                 uint64_t val2)
    : _buffer() {
  switch (type) {
    case RocksDBLogType::CollectionCreate:
    case RocksDBLogType::CollectionChange:
    case RocksDBLogType::CollectionDrop:
    case RocksDBLogType::BeginTransaction:
    case RocksDBLogType::SinglePut: {
      _buffer.reserve(sizeof(RocksDBLogType) + sizeof(uint64_t) * 2);
      _buffer.push_back(static_cast<char>(type));
      uint64ToPersistent(_buffer, dbId);
      uint64ToPersistent(_buffer, val2);
      break;
    }

    default:
      THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
  }
}

RocksDBLogValue::RocksDBLogValue(RocksDBLogType type, uint64_t dbId,
                                 uint64_t cid, uint64_t iid)
    : _buffer() {
  switch (type) {
    case RocksDBLogType::IndexDrop: {
      _buffer.reserve(sizeof(RocksDBLogType) + sizeof(uint64_t) * 3);
      _buffer.push_back(static_cast<char>(type));
      uint64ToPersistent(_buffer, dbId);
      uint64ToPersistent(_buffer, cid);
      uint64ToPersistent(_buffer, iid);
      break;
    }
    default:
      THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
  }
}

RocksDBLogValue::RocksDBLogValue(RocksDBLogType type, uint64_t dbId,
                                 uint64_t cid, VPackSlice const& indexInfo)
    : _buffer() {
  switch (type) {
    case RocksDBLogType::IndexCreate: {
      _buffer.reserve(sizeof(RocksDBLogType) + (sizeof(uint64_t) * 2) +
                      indexInfo.byteSize());
      _buffer.push_back(static_cast<char>(type));
      uint64ToPersistent(_buffer, dbId);
      uint64ToPersistent(_buffer, cid);
      _buffer.append(reinterpret_cast<char const*>(indexInfo.begin()),
                     indexInfo.byteSize());
      break;
    }
    default:
      THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
  }
}

RocksDBLogValue::RocksDBLogValue(RocksDBLogType type, uint64_t dbId,
                                 uint64_t cid, StringRef const& data)
    : _buffer() {
  switch (type) {
    case RocksDBLogType::CollectionRename: {
      _buffer.reserve(sizeof(RocksDBLogType) + sizeof(uint64_t) * 2 +
                      data.length());
      _buffer.push_back(static_cast<char>(type));
      uint64ToPersistent(_buffer, dbId);
      uint64ToPersistent(_buffer, cid);
      _buffer.append(data.data(), data.length());  // primary key
      break;
    }
    default:
      THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
  }
}

RocksDBLogValue::RocksDBLogValue(RocksDBLogType type, StringRef const& data)
    : _buffer() {
  switch (type) {
    case RocksDBLogType::DocumentRemove: {
      _buffer.reserve(data.length() + sizeof(RocksDBLogType));
      _buffer.push_back(static_cast<char>(type));
      _buffer.append(data.data(), data.length());  // primary key
      break;
    }

    default:
      THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
  }
}

// ================= Instance Methods ===================

RocksDBLogType RocksDBLogValue::type(rocksdb::Slice const& slice) {
  TRI_ASSERT(slice.size() >= sizeof(RocksDBLogType));
  return static_cast<RocksDBLogType>(slice.data()[0]);
}

TRI_voc_tick_t RocksDBLogValue::databaseId(rocksdb::Slice const& slice) {
  TRI_ASSERT(slice.size() >= sizeof(RocksDBLogType) + sizeof(uint64_t));
  RocksDBLogType type = static_cast<RocksDBLogType>(slice.data()[0]);
  TRI_ASSERT(type == RocksDBLogType::DatabaseCreate ||
             type == RocksDBLogType::DatabaseDrop ||
             type == RocksDBLogType::CollectionCreate ||
             type == RocksDBLogType::CollectionDrop ||
             type == RocksDBLogType::CollectionRename ||
             type == RocksDBLogType::CollectionChange ||
             type == RocksDBLogType::IndexCreate ||
             type == RocksDBLogType::IndexDrop ||
             type == RocksDBLogType::BeginTransaction ||
             type == RocksDBLogType::SinglePut ||
             type == RocksDBLogType::SingleRemove);
  return uint64FromPersistent(slice.data() + sizeof(RocksDBLogType));
}

TRI_voc_cid_t RocksDBLogValue::collectionId(rocksdb::Slice const& slice) {
  TRI_ASSERT(slice.size() >= sizeof(RocksDBLogType) + sizeof(uint64_t));
  RocksDBLogType type = static_cast<RocksDBLogType>(slice.data()[0]);
  TRI_ASSERT(type == RocksDBLogType::CollectionCreate ||
             type == RocksDBLogType::CollectionDrop ||
             type == RocksDBLogType::CollectionRename ||
             type == RocksDBLogType::CollectionChange ||
             type == RocksDBLogType::IndexCreate ||
             type == RocksDBLogType::IndexDrop ||
             type == RocksDBLogType::DocumentOperationsPrologue ||
             type == RocksDBLogType::SinglePut ||
             type == RocksDBLogType::SingleRemove);
  if (type == RocksDBLogType::DocumentOperationsPrologue) {  // only exception
    return uint64FromPersistent(slice.data() + sizeof(RocksDBLogType));
  } else {
    TRI_ASSERT(slice.size() >= sizeof(RocksDBLogType) + sizeof(uint64_t) * 2);
    return uint64FromPersistent(slice.data() + sizeof(RocksDBLogType) +
                                sizeof(uint64_t));
  }
}

TRI_voc_tid_t RocksDBLogValue::transactionId(rocksdb::Slice const& slice) {
  TRI_ASSERT(slice.size() >= sizeof(RocksDBLogType) + sizeof(uint64_t));
  RocksDBLogType type = static_cast<RocksDBLogType>(slice.data()[0]);
  TRI_ASSERT(type == RocksDBLogType::BeginTransaction);
  return uint64FromPersistent(slice.data() + sizeof(RocksDBLogType) +
                              sizeof(TRI_voc_tick_t));
}

TRI_idx_iid_t RocksDBLogValue::indexId(rocksdb::Slice const& slice) {
  TRI_ASSERT(slice.size() >= sizeof(RocksDBLogType) + (3 * sizeof(uint64_t)));
  RocksDBLogType type = static_cast<RocksDBLogType>(slice.data()[0]);
  TRI_ASSERT(type == RocksDBLogType::IndexDrop);
  return uint64FromPersistent(slice.data() + sizeof(RocksDBLogType) +
                              (2 * sizeof(uint64_t)));
}

VPackSlice RocksDBLogValue::indexSlice(rocksdb::Slice const& slice) {
  TRI_ASSERT(slice.size() >= sizeof(RocksDBLogType) + sizeof(uint64_t) * 2);
  RocksDBLogType type = static_cast<RocksDBLogType>(slice.data()[0]);
  TRI_ASSERT(type == RocksDBLogType::IndexCreate ||
             type == RocksDBLogType::ViewCreate ||
             type == RocksDBLogType::ViewChange);
  return VPackSlice(slice.data() + sizeof(RocksDBLogType) +
                    sizeof(uint64_t) * 2);
}

arangodb::StringRef RocksDBLogValue::newCollectionName(
    rocksdb::Slice const& slice) {
  size_t off = sizeof(RocksDBLogType) + sizeof(uint64_t) * 2;
  TRI_ASSERT(slice.size() >= off);
  RocksDBLogType type = static_cast<RocksDBLogType>(slice.data()[0]);
  TRI_ASSERT(type == RocksDBLogType::CollectionRename);
  return StringRef(slice.data() + off, slice.size() - off);
}

arangodb::StringRef RocksDBLogValue::documentKey(rocksdb::Slice const& slice) {
  RocksDBLogType type = static_cast<RocksDBLogType>(slice.data()[0]);
  TRI_ASSERT(type == RocksDBLogType::SingleRemove ||
             type == RocksDBLogType::DocumentRemove);
  size_t off = sizeof(RocksDBLogType);
  if (type == RocksDBLogType::SingleRemove) {
    off += sizeof(uint64_t) * 2;
  }
  TRI_ASSERT(slice.size() >= off);
  return StringRef(slice.data() + off, slice.size() - off);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2016, alex at staticlibs.net
 *
 * 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.
 */

/*
 * File:   TinydirFile.cpp
 * Author: alex
 *
 * Created on September 6, 2016, 12:39 PM
 */

#include "staticlib/tinydir/TinydirFile.hpp"

#ifdef STATICLIB_WINDOWS
#define UNICODE
#define _UNICODE
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#else // STATICLIB_WINDOWS
#include <cstdio>
#endif

#include "tinydir.h"

#include "staticlib/config.hpp"
#include "staticlib/utils.hpp"

#include "staticlib/tinydir/operations.hpp"

namespace staticlib {
namespace tinydir {

namespace { // anonymous

namespace su = staticlib::utils;

std::string file_type(const TinydirFile& tf) {
    if (tf.is_directory()) return "directory";
    if (tf.is_regular_file()) return "regular_file";
    if (tf.exists()) return "unexistent";
    return "unknown";
}

std::string detele_file_or_dir(const TinydirFile& tf) {
    std::string error;
#ifdef STATICLIB_WINDOWS
    auto wpath = su::widen(tf.path());
    if (tf.is_regular_file()) {
        auto res = ::DeleteFile(wpath.c_str());
        if (0 == res) {
            error = TRACEMSG(su::errcode_to_string(::GetLastError()));
        }
    } else if (tf.is_directory()) {
        auto res = ::RemoveDirectory(wpath.c_str());
        if (0 == res) {
            error = TRACEMSG(su::errcode_to_string(::GetLastError()));
        }
    } else {
        error = TRACEMSG("Cannot delete file, type: [" + file_type(tf) + "]");
    }
#else // !STATICLIB_WINDOWS
    auto res = std::remove(tf.path().c_str());
    if (0 != res) {
        error = TRACEMSG(::strerror(errno));
    }
#endif // STATICLIB_WINDOWS
    return error;
}

} // namespace

TinydirFile::TinydirFile(const std::string& path) :
fpath(path.data(), path.length()),
fname(su::strip_parent_dir(this->fpath)) {
    if (this->fname.empty()) throw TinydirException(TRACEMSG("Error opening file, path: [" + this->fpath + "]"));
    std::string dirpath = this->fname.length() < this->fpath.length() ? su::strip_filename(this->fpath) : "./";
    // tinydir_file_open is doing the same under the hood, but looks to be broken on windows
    auto vec = list_directory(dirpath);
    this->is_exist = false;
    for (auto& tf : vec) {
        if (tf.name() == this->fname) {
            this->is_dir = tf.is_directory();
            this->is_reg = tf.is_regular_file();
            this->is_exist = true;
            break;
        }
    }
}

TinydirFile::TinydirFile(std::nullptr_t, void* /* tinydir_file* */ pfile) {
    auto file = static_cast<tinydir_file*> (pfile);
#ifdef STATICLIB_WINDOWS
    this->fpath = su::narrow(file->path);
    this->fname = su::narrow(file->name);
#else
    this->fpath = std::string(file->path);
    this->fname = std::string(file->name);
#endif
    this->is_dir = 0 != file->is_dir;
    this->is_reg = 0 != file->is_reg;
    this->is_exist = true;
}

TinydirFile::TinydirFile(const TinydirFile& other) :
fpath(other.fpath.data(), other.fpath.length()),
fname(other.fname.data(), other.fname.length()),
is_dir(other.is_dir),
is_reg(other.is_reg),
is_exist(other.is_exist) { }

TinydirFile& TinydirFile::operator=(const TinydirFile& other) {
    fpath = std::string(other.fpath.data(), other.fpath.length());
    fname = std::string(other.fname.data(), other.fname.length());
    is_dir = other.is_dir;
    is_reg = other.is_reg;
    is_exist = other.is_exist;
    return *this;
}

TinydirFile::TinydirFile(TinydirFile&& other) :
fpath(std::move(other.fpath)),
fname(std::move(other.fname)),
is_dir(other.is_dir),
is_reg(other.is_reg),
is_exist(other.is_exist) {
    other.is_dir = false;
    other.is_reg = false;
    other.is_exist = false;
}

TinydirFile& TinydirFile::operator=(TinydirFile&& other) {
    fpath = std::move(other.fpath);
    fname = std::move(other.fname);
    is_dir = other.is_dir;
    other.is_dir = false;
    is_reg = other.is_reg;
    other.is_reg = false;
    is_exist = other.is_exist;
    other.is_exist = false;
    return *this;
}

const std::string& TinydirFile::path() const {
    return fpath;
}

const std::string& TinydirFile::name() const {
    return fname;
}

bool TinydirFile::exists() const {
    return is_exist;
}

bool TinydirFile::is_directory() const {
    return is_dir;
}

bool TinydirFile::is_regular_file() const {
    return is_reg;
}

su::FileDescriptor TinydirFile::open_read() const {
    if (!(is_exist && is_reg)) throw TinydirException(TRACEMSG(
            "Cannot open descriptor to non-regular file: [" + fpath + "]," +
            " type: [" + file_type(*this) + "]"));
    return su::FileDescriptor(fpath, 'r');
}

su::FileDescriptor TinydirFile::open_write() const {
    if (!(!is_exist || is_reg)) throw TinydirException(TRACEMSG(
            "Cannot open descriptor to non-regular file: [" + fpath + "]," +
            " type: [" + file_type(*this) + "]"));
    return su::FileDescriptor(fpath, 'w');
}

void TinydirFile::remove() const {
    auto err = detele_file_or_dir(*this);
    if (!err.empty()) {
        throw TinydirException(TRACEMSG("Cannot remove file: [" + fpath + "]," +
                " type: [" + file_type(*this) + "], error: [" + err + "]"));
    }
}

bool TinydirFile::remove_quietly() const STATICLIB_NOEXCEPT {
    auto err = detele_file_or_dir(*this);
    return err.empty();
}

} // namespace
}
<commit_msg>fix linux delete behaviour<commit_after>/*
 * Copyright 2016, alex at staticlibs.net
 *
 * 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.
 */

/*
 * File:   TinydirFile.cpp
 * Author: alex
 *
 * Created on September 6, 2016, 12:39 PM
 */

#include "staticlib/tinydir/TinydirFile.hpp"

#ifdef STATICLIB_WINDOWS
#define UNICODE
#define _UNICODE
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#else // STATICLIB_WINDOWS
#include <cstdio>
#endif

#include "tinydir.h"

#include "staticlib/config.hpp"
#include "staticlib/utils.hpp"

#include "staticlib/tinydir/operations.hpp"

namespace staticlib {
namespace tinydir {

namespace { // anonymous

namespace su = staticlib::utils;

std::string file_type(const TinydirFile& tf) {
    if (tf.is_directory()) return "directory";
    if (tf.is_regular_file()) return "regular_file";
    if (tf.exists()) return "unexistent";
    return "unknown";
}

std::string detele_file_or_dir(const TinydirFile& tf) {
    std::string error;
#ifdef STATICLIB_WINDOWS
    auto wpath = su::widen(tf.path());
    if (tf.is_regular_file()) {
        auto res = ::DeleteFile(wpath.c_str());
        if (0 == res) {
            error = TRACEMSG(su::errcode_to_string(::GetLastError()));
        }
    } else if (tf.is_directory()) {
        auto res = ::RemoveDirectory(wpath.c_str());
        if (0 == res) {
            error = TRACEMSG(su::errcode_to_string(::GetLastError()));
        }
    } else {
        error = TRACEMSG("Cannot delete file, type: [" + file_type(tf) + "]");
    }
#else // !STATICLIB_WINDOWS
    if (tf.is_regular_file() || tf.is_directory()) {
    auto res = std::remove(tf.path().c_str());
        if (0 != res) {
            error = TRACEMSG(::strerror(errno));
        }
    } else {
        error = TRACEMSG("Cannot delete file, type: [" + file_type(tf) + "]");
    }
#endif // STATICLIB_WINDOWS
    return error;
}

} // namespace

TinydirFile::TinydirFile(const std::string& path) :
fpath(path.data(), path.length()),
fname(su::strip_parent_dir(this->fpath)) {
    if (this->fname.empty()) throw TinydirException(TRACEMSG("Error opening file, path: [" + this->fpath + "]"));
    std::string dirpath = this->fname.length() < this->fpath.length() ? su::strip_filename(this->fpath) : "./";
    // tinydir_file_open is doing the same under the hood, but looks to be broken on windows
    auto vec = list_directory(dirpath);
    this->is_exist = false;
    for (auto& tf : vec) {
        if (tf.name() == this->fname) {
            this->is_dir = tf.is_directory();
            this->is_reg = tf.is_regular_file();
            this->is_exist = true;
            break;
        }
    }
}

TinydirFile::TinydirFile(std::nullptr_t, void* /* tinydir_file* */ pfile) {
    auto file = static_cast<tinydir_file*> (pfile);
#ifdef STATICLIB_WINDOWS
    this->fpath = su::narrow(file->path);
    this->fname = su::narrow(file->name);
#else
    this->fpath = std::string(file->path);
    this->fname = std::string(file->name);
#endif
    this->is_dir = 0 != file->is_dir;
    this->is_reg = 0 != file->is_reg;
    this->is_exist = true;
}

TinydirFile::TinydirFile(const TinydirFile& other) :
fpath(other.fpath.data(), other.fpath.length()),
fname(other.fname.data(), other.fname.length()),
is_dir(other.is_dir),
is_reg(other.is_reg),
is_exist(other.is_exist) { }

TinydirFile& TinydirFile::operator=(const TinydirFile& other) {
    fpath = std::string(other.fpath.data(), other.fpath.length());
    fname = std::string(other.fname.data(), other.fname.length());
    is_dir = other.is_dir;
    is_reg = other.is_reg;
    is_exist = other.is_exist;
    return *this;
}

TinydirFile::TinydirFile(TinydirFile&& other) :
fpath(std::move(other.fpath)),
fname(std::move(other.fname)),
is_dir(other.is_dir),
is_reg(other.is_reg),
is_exist(other.is_exist) {
    other.is_dir = false;
    other.is_reg = false;
    other.is_exist = false;
}

TinydirFile& TinydirFile::operator=(TinydirFile&& other) {
    fpath = std::move(other.fpath);
    fname = std::move(other.fname);
    is_dir = other.is_dir;
    other.is_dir = false;
    is_reg = other.is_reg;
    other.is_reg = false;
    is_exist = other.is_exist;
    other.is_exist = false;
    return *this;
}

const std::string& TinydirFile::path() const {
    return fpath;
}

const std::string& TinydirFile::name() const {
    return fname;
}

bool TinydirFile::exists() const {
    return is_exist;
}

bool TinydirFile::is_directory() const {
    return is_dir;
}

bool TinydirFile::is_regular_file() const {
    return is_reg;
}

su::FileDescriptor TinydirFile::open_read() const {
    if (!(is_exist && is_reg)) throw TinydirException(TRACEMSG(
            "Cannot open descriptor to non-regular file: [" + fpath + "]," +
            " type: [" + file_type(*this) + "]"));
    return su::FileDescriptor(fpath, 'r');
}

su::FileDescriptor TinydirFile::open_write() const {
    if (!(!is_exist || is_reg)) throw TinydirException(TRACEMSG(
            "Cannot open descriptor to non-regular file: [" + fpath + "]," +
            " type: [" + file_type(*this) + "]"));
    return su::FileDescriptor(fpath, 'w');
}

void TinydirFile::remove() const {
    auto err = detele_file_or_dir(*this);
    if (!err.empty()) {
        throw TinydirException(TRACEMSG("Cannot remove file: [" + fpath + "]," +
                " type: [" + file_type(*this) + "], error: [" + err + "]"));
    }
}

bool TinydirFile::remove_quietly() const STATICLIB_NOEXCEPT {
    auto err = detele_file_or_dir(*this);
    return err.empty();
}

} // namespace
}
<|endoftext|>


<commit_before>#include "TriacDimmer.h"
#include <Arduino.h>
#include <assert.h>
#include <util/atomic.h>

uint16_t TriacDimmer::detail::pulse_length;
uint16_t TriacDimmer::detail::min_trigger;
float TriacDimmer::detail::on_thresh;
float TriacDimmer::detail::off_thresh;

volatile bool TriacDimmer::detail::ch_A_en;
volatile uint16_t TriacDimmer::detail::ch_A_up;
volatile uint16_t TriacDimmer::detail::ch_A_dn;
volatile uint16_t ch_A_dn_buf;

volatile bool TriacDimmer::detail::ch_B_en;
volatile uint16_t TriacDimmer::detail::ch_B_up;
volatile uint16_t TriacDimmer::detail::ch_B_dn;
volatile uint16_t ch_B_dn_buf;

volatile uint16_t TriacDimmer::detail::period = 16667;

void TriacDimmer::begin(uint16_t pulse_length, uint16_t min_trigger, float on_thresh, float off_thresh){
	// Don't need atomic writes since the ISRs haven't started yet.
	TriacDimmer::detail::pulse_length = pulse_length;
	TriacDimmer::detail::min_trigger = min_trigger;
	TriacDimmer::detail::on_thresh = on_thresh;
	TriacDimmer::detail::off_thresh = off_thresh;

	TCCR1A = 0;
	TCCR1B = _BV(ICNC1)  //input capture noise cancel
			| _BV(ICES1) //positive edge
			| _BV(CS11); // /8 prescaler

	pinMode(8, INPUT);

	TIFR1 = _BV(ICF1); //clear IC interrupt flag
	TIMSK1 = _BV(ICIE1); //enable input capture interrupt
}

void TriacDimmer::end(){
	TIMSK1 = 0; //disable the interrupts first!
	TIFR1 = 0xFF; //clear all flags
	TCCR1A = 0; //clear to reset state
	TCCR1B = 0;
}

void TriacDimmer::setBrightness(uint8_t pin, float value){
	assert(pin == 9 || pin == 10);

	if (value > TriacDimmer::detail::on_thresh) {
		digitalWrite(pin, HIGH);
		TriacDimmer::disable(pin);
	} else if (value < TriacDimmer::detail::off_thresh) {
		digitalWrite(pin, LOW);
		TriacDimmer::disable(pin);
	} else {
		if ((pin & 0x01) == 0x01){ // if (pin == 9){
			TriacDimmer::detail::setChannelA(1 - value);
			TriacDimmer::detail::ch_A_en = true;
		} else { // if (pin == 10){
			TriacDimmer::detail::setChannelB(1 - value);
			TriacDimmer::detail::ch_B_en = true;
		}
	}
	pinMode(pin, OUTPUT); // only set to output once configured.
}

void TriacDimmer::disable(uint8_t pin) {
	assert(pin == 9 || pin == 10);

	if ((pin & 0x01) == 0x01){ // if (pin == 9){
		TriacDimmer::detail::disableChannelA();
	} else { // if (pin == 10){
		TriacDimmer::detail::disableChannelB();
	}
}

float TriacDimmer::getCurrentBrightness(uint8_t pin){
	assert(pin == 9 || pin == 10);

	if ((pin & 0x01) == 0x01){ // if (pin == 9){
		return 1 - TriacDimmer::detail::getChannelA();
	} else { // if (pin == 10){
		return 1 - TriacDimmer::detail::getChannelB();
	}
}

void TriacDimmer::detail::setChannelA(float value){
	uint16_t p, u, d;
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		// Don't need atomic read for pulse_length or min_trigger since they're not updated from an ISR.
		p = TriacDimmer::detail::period;
	}
	u = p * value;
	d = constrain(u + TriacDimmer::detail::pulse_length, TriacDimmer::detail::min_trigger, p);
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		TriacDimmer::detail::ch_A_up = u;
		TriacDimmer::detail::ch_A_dn = d;
	}
}

void TriacDimmer::detail::setChannelB(float value){
	uint16_t p, u, d;
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		// Don't need atomic read for pulse_length or min_trigger since they're not updated from an ISR.
		p = TriacDimmer::detail::period;
	}
	u = p * value;
	d = constrain(u + TriacDimmer::detail::pulse_length, TriacDimmer::detail::min_trigger, p);
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		TriacDimmer::detail::ch_B_up = u;
		TriacDimmer::detail::ch_B_dn = d;
	}
}

float TriacDimmer::detail::getChannelA(){
	uint16_t p, u;
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		p = TriacDimmer::detail::period;
		u = TriacDimmer::detail::ch_A_up;
	}
	return (float)p / u;
}

float TriacDimmer::detail::getChannelB(){
	uint16_t p, u;
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		p = TriacDimmer::detail::period;
		u = TriacDimmer::detail::ch_B_up;
	}
	return (float)p / u;
}

void TriacDimmer::detail::disableChannelA(){
	TriacDimmer::detail::ch_A_en = false;
	TCCR1A &=~ _BV(COM1A0) | _BV(COM1A1);
}

void TriacDimmer::detail::disableChannelB(){
	TriacDimmer::detail::ch_B_en = false;
	TCCR1A &=~ _BV(COM1B0) | _BV(COM1B1);
}

ISR(TIMER1_CAPT_vect){
	TIMSK1 &=~ (_BV(OCIE1A) | _BV(OCIE1B)); //clear interrupts, in case they haven't run yet
	TCCR1A &=~ (_BV(COM1A0) | _BV(COM1B0));
	TCCR1C = _BV(FOC1A) | _BV(FOC1B); //ensure outputs are properly cleared

	OCR1A = ICR1 + TriacDimmer::detail::ch_A_up;
	OCR1B = ICR1 + TriacDimmer::detail::ch_B_up;
	ch_A_dn_buf = TriacDimmer::detail::ch_A_dn;
	ch_B_dn_buf = TriacDimmer::detail::ch_B_dn;

	TCCR1A |=
		( TriacDimmer::detail::ch_A_en ? _BV(COM1A0) | _BV(COM1A1) : 0 ) |
		( TriacDimmer::detail::ch_B_en ? _BV(COM1B0) | _BV(COM1B1) : 0 ); //set OC1x on compare match, only if enabled
	TIFR1 = _BV(OCF1A) | _BV(OCF1B); //clear compare match flags
	TIMSK1 |= _BV(OCIE1A) | _BV(OCIE1B); //enable input capture and compare match interrupts

	static uint16_t last_icr = 0;
	TriacDimmer::detail::period = ICR1 - last_icr;
	last_icr = ICR1;

	if((signed)(TCNT1 - OCR1A) >= 0){
		TCCR1C = _BV(FOC1A); //interrupt ran late, trigger match manually
	}
	if((signed)(TCNT1 - OCR1B) >= 0){
		TCCR1C = _BV(FOC1B); //interrupt ran late, trigger match manually
	}
}

ISR(TIMER1_COMPA_vect){
	TIMSK1 &=~ _BV(OCIE1A); //disable match interrupt
	TCCR1A &=~ _BV(COM1A0); //clear OC1x on compare match

	OCR1A = ICR1 + ch_A_dn_buf;

	if((signed)(TCNT1 - OCR1A) >= 0){
		TCCR1C = _BV(FOC1A); //interrupt ran late, trigger match manually
	}
}

ISR(TIMER1_COMPB_vect){
	TIMSK1 &=~ _BV(OCIE1B); //disable match interrupt
	TCCR1A &=~ _BV(COM1B0); //clear OC1x on compare match

	OCR1B = ICR1 + ch_B_dn_buf;

	if((signed)(TCNT1 - OCR1B) >= 0){
		TCCR1C = _BV(FOC1B); //interrupt ran late, trigger match manually
	}
}

<commit_msg>base falling edges on last_icr in case of overlap<commit_after>#include "TriacDimmer.h"
#include <Arduino.h>
#include <assert.h>
#include <util/atomic.h>

uint16_t TriacDimmer::detail::pulse_length;
uint16_t TriacDimmer::detail::min_trigger;
float TriacDimmer::detail::on_thresh;
float TriacDimmer::detail::off_thresh;

volatile bool TriacDimmer::detail::ch_A_en;
volatile uint16_t TriacDimmer::detail::ch_A_up;
volatile uint16_t TriacDimmer::detail::ch_A_dn;
volatile uint16_t ch_A_dn_buf;

volatile bool TriacDimmer::detail::ch_B_en;
volatile uint16_t TriacDimmer::detail::ch_B_up;
volatile uint16_t TriacDimmer::detail::ch_B_dn;
volatile uint16_t ch_B_dn_buf;

uint16_t last_icr = 0;
volatile uint16_t TriacDimmer::detail::period = 16667;

void TriacDimmer::begin(uint16_t pulse_length, uint16_t min_trigger, float on_thresh, float off_thresh){
	// Don't need atomic writes since the ISRs haven't started yet.
	TriacDimmer::detail::pulse_length = pulse_length;
	TriacDimmer::detail::min_trigger = min_trigger;
	TriacDimmer::detail::on_thresh = on_thresh;
	TriacDimmer::detail::off_thresh = off_thresh;

	TCCR1A = 0;
	TCCR1B = _BV(ICNC1)  //input capture noise cancel
			| _BV(ICES1) //positive edge
			| _BV(CS11); // /8 prescaler

	pinMode(8, INPUT);

	TIFR1 = _BV(ICF1); //clear IC interrupt flag
	TIMSK1 = _BV(ICIE1); //enable input capture interrupt
}

void TriacDimmer::end(){
	TIMSK1 = 0; //disable the interrupts first!
	TIFR1 = 0xFF; //clear all flags
	TCCR1A = 0; //clear to reset state
	TCCR1B = 0;
}

void TriacDimmer::setBrightness(uint8_t pin, float value){
	assert(pin == 9 || pin == 10);

	if (value > TriacDimmer::detail::on_thresh) {
		digitalWrite(pin, HIGH);
		TriacDimmer::disable(pin);
	} else if (value < TriacDimmer::detail::off_thresh) {
		digitalWrite(pin, LOW);
		TriacDimmer::disable(pin);
	} else {
		if ((pin & 0x01) == 0x01){ // if (pin == 9){
			TriacDimmer::detail::setChannelA(1 - value);
			TriacDimmer::detail::ch_A_en = true;
		} else { // if (pin == 10){
			TriacDimmer::detail::setChannelB(1 - value);
			TriacDimmer::detail::ch_B_en = true;
		}
	}
	pinMode(pin, OUTPUT); // only set to output once configured.
}

void TriacDimmer::disable(uint8_t pin) {
	assert(pin == 9 || pin == 10);

	if ((pin & 0x01) == 0x01){ // if (pin == 9){
		TriacDimmer::detail::disableChannelA();
	} else { // if (pin == 10){
		TriacDimmer::detail::disableChannelB();
	}
}

float TriacDimmer::getCurrentBrightness(uint8_t pin){
	assert(pin == 9 || pin == 10);

	if ((pin & 0x01) == 0x01){ // if (pin == 9){
		return 1 - TriacDimmer::detail::getChannelA();
	} else { // if (pin == 10){
		return 1 - TriacDimmer::detail::getChannelB();
	}
}

void TriacDimmer::detail::setChannelA(float value){
	uint16_t p, u, d;
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		// Don't need atomic read for pulse_length or min_trigger since they're not updated from an ISR.
		p = TriacDimmer::detail::period;
	}
	u = p * value;
	d = constrain(u + TriacDimmer::detail::pulse_length, TriacDimmer::detail::min_trigger, p);
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		TriacDimmer::detail::ch_A_up = u;
		TriacDimmer::detail::ch_A_dn = d;
	}
}

void TriacDimmer::detail::setChannelB(float value){
	uint16_t p, u, d;
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		// Don't need atomic read for pulse_length or min_trigger since they're not updated from an ISR.
		p = TriacDimmer::detail::period;
	}
	u = p * value;
	d = constrain(u + TriacDimmer::detail::pulse_length, TriacDimmer::detail::min_trigger, p);
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		TriacDimmer::detail::ch_B_up = u;
		TriacDimmer::detail::ch_B_dn = d;
	}
}

float TriacDimmer::detail::getChannelA(){
	uint16_t p, u;
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		p = TriacDimmer::detail::period;
		u = TriacDimmer::detail::ch_A_up;
	}
	return (float)p / u;
}

float TriacDimmer::detail::getChannelB(){
	uint16_t p, u;
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		p = TriacDimmer::detail::period;
		u = TriacDimmer::detail::ch_B_up;
	}
	return (float)p / u;
}

void TriacDimmer::detail::disableChannelA(){
	TriacDimmer::detail::ch_A_en = false;
	TCCR1A &=~ _BV(COM1A0) | _BV(COM1A1);
}

void TriacDimmer::detail::disableChannelB(){
	TriacDimmer::detail::ch_B_en = false;
	TCCR1A &=~ _BV(COM1B0) | _BV(COM1B1);
}

ISR(TIMER1_CAPT_vect){
	TIMSK1 &=~ (_BV(OCIE1A) | _BV(OCIE1B)); //clear interrupts, in case they haven't run yet
	TCCR1A &=~ (_BV(COM1A0) | _BV(COM1B0));
	TCCR1C = _BV(FOC1A) | _BV(FOC1B); //ensure outputs are properly cleared

	OCR1A = ICR1 + TriacDimmer::detail::ch_A_up;
	OCR1B = ICR1 + TriacDimmer::detail::ch_B_up;
	ch_A_dn_buf = TriacDimmer::detail::ch_A_dn;
	ch_B_dn_buf = TriacDimmer::detail::ch_B_dn;

	TCCR1A |=
		( TriacDimmer::detail::ch_A_en ? _BV(COM1A0) | _BV(COM1A1) : 0 ) |
		( TriacDimmer::detail::ch_B_en ? _BV(COM1B0) | _BV(COM1B1) : 0 ); //set OC1x on compare match, only if enabled
	TIFR1 = _BV(OCF1A) | _BV(OCF1B); //clear compare match flags
	TIMSK1 |= _BV(OCIE1A) | _BV(OCIE1B); //enable input capture and compare match interrupts

	TriacDimmer::detail::period = ICR1 - last_icr;
	last_icr = ICR1;

	if((signed)(TCNT1 - OCR1A) >= 0){
		TCCR1C = _BV(FOC1A); //interrupt ran late, trigger match manually
	}
	if((signed)(TCNT1 - OCR1B) >= 0){
		TCCR1C = _BV(FOC1B); //interrupt ran late, trigger match manually
	}
}

ISR(TIMER1_COMPA_vect){
	TIMSK1 &=~ _BV(OCIE1A); //disable match interrupt
	TCCR1A &=~ _BV(COM1A0); //clear OC1x on compare match

	OCR1A = last_icr + ch_A_dn_buf;

	if((signed)(TCNT1 - OCR1A) >= 0){
		TCCR1C = _BV(FOC1A); //interrupt ran late, trigger match manually
	}
}

ISR(TIMER1_COMPB_vect){
	TIMSK1 &=~ _BV(OCIE1B); //disable match interrupt
	TCCR1A &=~ _BV(COM1B0); //clear OC1x on compare match

	OCR1B = last_icr + ch_B_dn_buf;

	if((signed)(TCNT1 - OCR1B) >= 0){
		TCCR1C = _BV(FOC1B); //interrupt ran late, trigger match manually
	}
}

<|endoftext|>


<commit_before>/*
 * MIT License
 *
 * Copyright (c) 2016 xiongziliang <771730766@qq.com>
 *
 * 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 "logger.h"
#include "onceToken.h"

namespace toolkit {

#define CLEAR_COLOR "\033[0m"
static const char *LOG_CONST_TABLE[][3] = {
        {"\033[44;37m", "\033[34m" , "T"},
        {"\033[42;37m", "\033[32m" , "D"},
        {"\033[46;37m", "\033[36m" , "I"},
        {"\033[43;37m", "\033[33m" , "W"},
        {"\033[41;37m", "\033[31m" , "E"}};

///////////////////Logger///////////////////
INSTANCE_IMP(Logger,exeName());

Logger::Logger(const string &loggerName) {
    _loggerName = loggerName;
}
Logger::~Logger() {
    _writer.reset();
    {
        LogContextCapturer(*this, LInfo, __FILE__, __FUNCTION__, __LINE__);
    }
    _channels.clear();
}

void Logger::add(const std::shared_ptr<LogChannel> &channel) {
    _channels[channel->name()] = channel;
}

void Logger::del(const string &name) {
    _channels.erase(name);
}

std::shared_ptr<LogChannel> Logger::get(const string &name) {
    auto it = _channels.find(name);
    if (it == _channels.end()) {
        return nullptr;
    }
    return it->second;
}

void Logger::setWriter(const std::shared_ptr<LogWriter> &writer) {
    _writer = writer;
}

void Logger::write(const LogContextPtr &logContext) {
    if (_writer) {
        _writer->write(logContext);
    }else{
        writeChannels(logContext);
    }
}

void Logger::setLevel(LogLevel level) {
    for (auto &chn : _channels) {
        chn.second->setLevel(level);
    }
}

void Logger::writeChannels(const LogContextPtr &logContext){
    for (auto &chn : _channels) {
        chn.second->write(*this,logContext);
    }
}

const string &Logger::getName() const{
    return _loggerName;
}
///////////////////LogContext///////////////////
LogContext::LogContext(LogLevel level,
        const char *file,
        const char *function,
        int line) :
        _level(level),
        _line(line),
        _file(file),
        _function(function) {
    gettimeofday(&_tv, NULL);
}

///////////////////AsyncLogWriter///////////////////
LogContextCapturer::LogContextCapturer(
        Logger &logger,
        LogLevel level,
        const char *file,
        const char *function,
        int line) :
        _logContext(new LogContext(level, file, function, line)),_logger(logger) {
}

LogContextCapturer::LogContextCapturer(const LogContextCapturer &that): _logContext(that._logContext),_logger(that._logger) {
    const_cast<LogContextPtr&>(that._logContext).reset();
}

LogContextCapturer::~LogContextCapturer() {
    *this << endl;
}

LogContextCapturer &LogContextCapturer::operator << (ostream &(*f)(ostream &)) {
    if (!_logContext) {
        return *this;
    }
    _logger.write(_logContext);
    _logContext.reset();
    return *this;
}

void LogContextCapturer::clear() {
    _logContext.reset();
}

///////////////////AsyncLogWriter///////////////////
AsyncLogWriter::AsyncLogWriter(Logger &logger) : _exit_flag(false),_logger(logger) {
    _thread = std::make_shared<thread>([this]() { this->run(); });
}

AsyncLogWriter::~AsyncLogWriter() {
    _exit_flag = true;
    _sem.post();
    _thread->join();
    flushAll();
}

void AsyncLogWriter::write(const LogContextPtr &logContext) {
    {
        lock_guard<mutex> lock(_mutex);
        _pending.emplace_back(logContext);
    }
    _sem.post();
}

void AsyncLogWriter::run() {
    while (!_exit_flag) {
        _sem.wait();
        flushAll();
    }
}
void AsyncLogWriter::flushAll(){
    List<LogContextPtr> tmp;
    {
        lock_guard<mutex> lock(_mutex);
        tmp.swap(_pending);
    }

    tmp.for_each([&](const LogContextPtr &ctx){
        _logger.writeChannels(ctx);
    });

}

///////////////////ConsoleChannel///////////////////

#ifdef ANDROID
#include <android/log.h>
#endif //ANDROID

ConsoleChannel::ConsoleChannel(const string &name, LogLevel level) : LogChannel(name, level) {}
ConsoleChannel:: ~ConsoleChannel() {}
void ConsoleChannel::write(const Logger &logger,const LogContextPtr &logContext)  {
    if (_level > logContext->_level) {
        return;
    }

#if defined(_WIN32) || defined(OS_IPHONE)
    format(logger,std::cout, logContext , false);
#elif defined(ANDROID)
    static android_LogPriority LogPriorityArr[10];
    static onceToken s_token([](){
        LogPriorityArr[LTrace] = ANDROID_LOG_VERBOSE;
        LogPriorityArr[LDebug] = ANDROID_LOG_DEBUG;
        LogPriorityArr[LInfo] = ANDROID_LOG_INFO;
        LogPriorityArr[LWarn] = ANDROID_LOG_WARN;
        LogPriorityArr[LError] = ANDROID_LOG_ERROR;
    }, nullptr);
    __android_log_print(LogPriorityArr[logContext->_level],"JNI","%s %s",logContext->_function.c_str(),logContext->str().c_str());
#else
    format(logger,std::cout,logContext, true);
#endif

}

///////////////////LogChannel///////////////////
LogChannel::LogChannel(const string &name, LogLevel level) : _name(name), _level(level) {}
LogChannel::~LogChannel(){}
const string &LogChannel::name() const { return _name; }
void LogChannel::setLevel(LogLevel level) { _level = level; }

std::string LogChannel::printTime(const timeval &tv) {
    time_t sec_tmp = tv.tv_sec;
    struct tm *tm = localtime(&sec_tmp);
    char buf[128];
    snprintf(buf, sizeof(buf), "%d-%02d-%02d %02d:%02d:%02d.%03d",
             1900 + tm->tm_year,
             1 + tm->tm_mon,
             tm->tm_mday,
             tm->tm_hour,
             tm->tm_min,
             tm->tm_sec,
             (int) (tv.tv_usec / 1000));
    return buf;
}

void LogChannel::format(const Logger &logger,ostream &ost,const LogContextPtr & logContext, bool enableColor, bool enableDetail) {
    if (!enableDetail && logContext->str().empty()) {
        //没有任何信息打印
        return;
    }

    if (enableDetail) {
#if defined(_WIN32)
        ost << logger.getName() <<"(" << GetCurrentProcessId() << ") " << logContext->_file << " " << logContext->_line << endl;
#else
        ost << logger.getName() << "(" << getpid() << ") " << logContext->_file << " " << logContext->_line << endl;
#endif
    }

    if (enableColor) {
        ost << LOG_CONST_TABLE[logContext->_level][1];
    }

    ost << printTime(logContext->_tv) << " " << LOG_CONST_TABLE[logContext->_level][2] << " | ";

    if (enableDetail) {
        ost << logContext->_function << " ";
    }

    ost << logContext->str();

    if (enableColor) {
        ost << CLEAR_COLOR;
    }

    ost << endl;
}

///////////////////FileChannel///////////////////
FileChannel::FileChannel(const string &name, const string &path, LogLevel level) :
        LogChannel(name, level), _path(path) {}

FileChannel::~FileChannel() {
    close();
}

void FileChannel::write(const Logger &logger,const std::shared_ptr<LogContext> &logContext) {
    if (_level > logContext->_level) {
        return;
    }
    if (!_fstream.is_open()) {
        open();
    }
    format(logger, _fstream, logContext ,false);
}

void FileChannel::setPath(const string &path) {
    _path = path;
    open();
}

const string &FileChannel::path() const {
    return _path;
}

void FileChannel::open() {
    // Ensure a path was set
    if (_path.empty()) {
        throw runtime_error("Log file path must be set.");
    }
    // Open the file stream
    _fstream.close();
    _fstream.open(_path.c_str(), ios::out | ios::app);
    // Throw on failure
    if (!_fstream.is_open()) {
        throw runtime_error("Failed to open log file: " + _path);
    }
}

void FileChannel::close() {
    _fstream.close();
}

} /* namespace toolkit */

<commit_msg>修复android上的编译bug<commit_after>/*
 * MIT License
 *
 * Copyright (c) 2016 xiongziliang <771730766@qq.com>
 *
 * 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 "logger.h"
#include "onceToken.h"

namespace toolkit {

#define CLEAR_COLOR "\033[0m"
static const char *LOG_CONST_TABLE[][3] = {
        {"\033[44;37m", "\033[34m" , "T"},
        {"\033[42;37m", "\033[32m" , "D"},
        {"\033[46;37m", "\033[36m" , "I"},
        {"\033[43;37m", "\033[33m" , "W"},
        {"\033[41;37m", "\033[31m" , "E"}};

///////////////////Logger///////////////////
INSTANCE_IMP(Logger,exeName());

Logger::Logger(const string &loggerName) {
    _loggerName = loggerName;
}
Logger::~Logger() {
    _writer.reset();
    {
        LogContextCapturer(*this, LInfo, __FILE__, __FUNCTION__, __LINE__);
    }
    _channels.clear();
}

void Logger::add(const std::shared_ptr<LogChannel> &channel) {
    _channels[channel->name()] = channel;
}

void Logger::del(const string &name) {
    _channels.erase(name);
}

std::shared_ptr<LogChannel> Logger::get(const string &name) {
    auto it = _channels.find(name);
    if (it == _channels.end()) {
        return nullptr;
    }
    return it->second;
}

void Logger::setWriter(const std::shared_ptr<LogWriter> &writer) {
    _writer = writer;
}

void Logger::write(const LogContextPtr &logContext) {
    if (_writer) {
        _writer->write(logContext);
    }else{
        writeChannels(logContext);
    }
}

void Logger::setLevel(LogLevel level) {
    for (auto &chn : _channels) {
        chn.second->setLevel(level);
    }
}

void Logger::writeChannels(const LogContextPtr &logContext){
    for (auto &chn : _channels) {
        chn.second->write(*this,logContext);
    }
}

const string &Logger::getName() const{
    return _loggerName;
}
///////////////////LogContext///////////////////
LogContext::LogContext(LogLevel level,
        const char *file,
        const char *function,
        int line) :
        _level(level),
        _line(line),
        _file(file),
        _function(function) {
    gettimeofday(&_tv, NULL);
}

///////////////////AsyncLogWriter///////////////////
LogContextCapturer::LogContextCapturer(
        Logger &logger,
        LogLevel level,
        const char *file,
        const char *function,
        int line) :
        _logContext(new LogContext(level, file, function, line)),_logger(logger) {
}

LogContextCapturer::LogContextCapturer(const LogContextCapturer &that): _logContext(that._logContext),_logger(that._logger) {
    const_cast<LogContextPtr&>(that._logContext).reset();
}

LogContextCapturer::~LogContextCapturer() {
    *this << endl;
}

LogContextCapturer &LogContextCapturer::operator << (ostream &(*f)(ostream &)) {
    if (!_logContext) {
        return *this;
    }
    _logger.write(_logContext);
    _logContext.reset();
    return *this;
}

void LogContextCapturer::clear() {
    _logContext.reset();
}

///////////////////AsyncLogWriter///////////////////
AsyncLogWriter::AsyncLogWriter(Logger &logger) : _exit_flag(false),_logger(logger) {
    _thread = std::make_shared<thread>([this]() { this->run(); });
}

AsyncLogWriter::~AsyncLogWriter() {
    _exit_flag = true;
    _sem.post();
    _thread->join();
    flushAll();
}

void AsyncLogWriter::write(const LogContextPtr &logContext) {
    {
        lock_guard<mutex> lock(_mutex);
        _pending.emplace_back(logContext);
    }
    _sem.post();
}

void AsyncLogWriter::run() {
    while (!_exit_flag) {
        _sem.wait();
        flushAll();
    }
}
void AsyncLogWriter::flushAll(){
    List<LogContextPtr> tmp;
    {
        lock_guard<mutex> lock(_mutex);
        tmp.swap(_pending);
    }

    tmp.for_each([&](const LogContextPtr &ctx){
        _logger.writeChannels(ctx);
    });

}

///////////////////ConsoleChannel///////////////////

#ifdef ANDROID
#include <android/log.h>
#endif //ANDROID

ConsoleChannel::ConsoleChannel(const string &name, LogLevel level) : LogChannel(name, level) {}
ConsoleChannel:: ~ConsoleChannel() {}
void ConsoleChannel::write(const Logger &logger,const LogContextPtr &logContext)  {
    if (_level > logContext->_level) {
        return;
    }

#if defined(_WIN32) || defined(OS_IPHONE)
    format(logger,std::cout, logContext , false);
#elif defined(ANDROID)
    static android_LogPriority LogPriorityArr[10];
    static onceToken s_token([](){
        LogPriorityArr[LTrace] = ANDROID_LOG_VERBOSE;
        LogPriorityArr[LDebug] = ANDROID_LOG_DEBUG;
        LogPriorityArr[LInfo] = ANDROID_LOG_INFO;
        LogPriorityArr[LWarn] = ANDROID_LOG_WARN;
        LogPriorityArr[LError] = ANDROID_LOG_ERROR;
    }, nullptr);
    __android_log_print(LogPriorityArr[logContext->_level],"JNI","%s %s",logContext->_function,logContext->str().c_str());
#else
    format(logger,std::cout,logContext, true);
#endif

}

///////////////////LogChannel///////////////////
LogChannel::LogChannel(const string &name, LogLevel level) : _name(name), _level(level) {}
LogChannel::~LogChannel(){}
const string &LogChannel::name() const { return _name; }
void LogChannel::setLevel(LogLevel level) { _level = level; }

std::string LogChannel::printTime(const timeval &tv) {
    time_t sec_tmp = tv.tv_sec;
    struct tm *tm = localtime(&sec_tmp);
    char buf[128];
    snprintf(buf, sizeof(buf), "%d-%02d-%02d %02d:%02d:%02d.%03d",
             1900 + tm->tm_year,
             1 + tm->tm_mon,
             tm->tm_mday,
             tm->tm_hour,
             tm->tm_min,
             tm->tm_sec,
             (int) (tv.tv_usec / 1000));
    return buf;
}

void LogChannel::format(const Logger &logger,ostream &ost,const LogContextPtr & logContext, bool enableColor, bool enableDetail) {
    if (!enableDetail && logContext->str().empty()) {
        //没有任何信息打印
        return;
    }

    if (enableDetail) {
#if defined(_WIN32)
        ost << logger.getName() <<"(" << GetCurrentProcessId() << ") " << logContext->_file << " " << logContext->_line << endl;
#else
        ost << logger.getName() << "(" << getpid() << ") " << logContext->_file << " " << logContext->_line << endl;
#endif
    }

    if (enableColor) {
        ost << LOG_CONST_TABLE[logContext->_level][1];
    }

    ost << printTime(logContext->_tv) << " " << LOG_CONST_TABLE[logContext->_level][2] << " | ";

    if (enableDetail) {
        ost << logContext->_function << " ";
    }

    ost << logContext->str();

    if (enableColor) {
        ost << CLEAR_COLOR;
    }

    ost << endl;
}

///////////////////FileChannel///////////////////
FileChannel::FileChannel(const string &name, const string &path, LogLevel level) :
        LogChannel(name, level), _path(path) {}

FileChannel::~FileChannel() {
    close();
}

void FileChannel::write(const Logger &logger,const std::shared_ptr<LogContext> &logContext) {
    if (_level > logContext->_level) {
        return;
    }
    if (!_fstream.is_open()) {
        open();
    }
    format(logger, _fstream, logContext ,false);
}

void FileChannel::setPath(const string &path) {
    _path = path;
    open();
}

const string &FileChannel::path() const {
    return _path;
}

void FileChannel::open() {
    // Ensure a path was set
    if (_path.empty()) {
        throw runtime_error("Log file path must be set.");
    }
    // Open the file stream
    _fstream.close();
    _fstream.open(_path.c_str(), ios::out | ios::app);
    // Throw on failure
    if (!_fstream.is_open()) {
        throw runtime_error("Failed to open log file: " + _path);
    }
}

void FileChannel::close() {
    _fstream.close();
}

} /* namespace toolkit */

<|endoftext|>


<commit_before><commit_msg>Revert "Test logtesting on Jenkins"<commit_after><|endoftext|>


<commit_before>#pragma once

#include <string>
#include <ctime>
#include <glm/glm.hpp>
#include "linking.hpp"

/// Logging class.
/**
 * Usage:
 * @code{.cpp}
 * Log() << "Testing: " << 5 << "\n";
 * @endcode
 */
class Log {
    public:
        UTILITY_API const enum Channel {
            DEFAULT = 0,        ///< Default channel.
            INFO,               ///< Information.
            WARNING,            ///< Warnings.
            ERR,                ///< Error.
            CONSOLE,            ///< Console.
            NUMBER_OF_CHANNELS  ///< Maximum number of channels, ensure this is the last element of the enum if adding channels.
        };

        /// Constructor.
        UTILITY_API Log(const Channel channel = Channel::DEFAULT);

        /// Destructor.
        UTILITY_API ~Log();

        /// Output some text to stderr.
        /**
         * @param text Text to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(const std::string text);

        /// Output an integer to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(const int value);

        /// Output an unsigned integer to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(const unsigned int value);

        /// Output a float to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(const float value);

        /// Output a double to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(const double value);

        /// Output a time to stderr.
        /**
         * Formatted Y-m-d H:M:S.
         * @param value Value to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(const time_t value);

        /// Output a vec2 to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(const glm::vec2& value);

        /// Output a vec3 to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(const glm::vec3& value);

        /// Output a vec4 to stderr.
        /**
        * @param value Value to output.
        * @return The %Log instance.
        */
        UTILITY_API Log& operator<<(const glm::vec4& value);

        /// Sets channels.
        /**
         * @param channel The channel to set.
         * @param stream The stream that will be mapped to the channel.
         * @return Whether the operation succeeded or not.
         */
        UTILITY_API static bool Log::SetupStream(const Channel channel, std::ostream* stream);

        /// Sets all channels at once.
        /**
         * @param defaultStream The stream for default output.
         * @param info The stream for information.
         * @param warning The stream for warnings.
         * @param error The stream for errors.
         * @param console The stream to the console.
         * @return Whether the operation succeeded or not.
         */
        UTILITY_API static bool Log::SetupStreams(std::ostream* defaultStream, std::ostream* info, std::ostream* warning, std::ostream* error, std::ostream* console);

    private:
        Channel currentChannel;
        static std::ostream* streams[Channel::NUMBER_OF_CHANNELS];
};
<commit_msg>Don't use utility_api on channel enum.<commit_after>#pragma once

#include <string>
#include <ctime>
#include <glm/glm.hpp>
#include "linking.hpp"

/// Logging class.
/**
 * Usage:
 * @code{.cpp}
 * Log() << "Testing: " << 5 << "\n";
 * @endcode
 */
class Log {
    public:
        const enum Channel {
            DEFAULT = 0,        ///< Default channel.
            INFO,               ///< Information.
            WARNING,            ///< Warnings.
            ERR,                ///< Error.
            CONSOLE,            ///< Console.
            NUMBER_OF_CHANNELS  ///< Maximum number of channels, ensure this is the last element of the enum if adding channels.
        };

        /// Constructor.
        UTILITY_API Log(const Channel channel = Channel::DEFAULT);

        /// Destructor.
        UTILITY_API ~Log();

        /// Output some text to stderr.
        /**
         * @param text Text to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(const std::string text);

        /// Output an integer to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(const int value);

        /// Output an unsigned integer to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(const unsigned int value);

        /// Output a float to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(const float value);

        /// Output a double to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(const double value);

        /// Output a time to stderr.
        /**
         * Formatted Y-m-d H:M:S.
         * @param value Value to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(const time_t value);

        /// Output a vec2 to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(const glm::vec2& value);

        /// Output a vec3 to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(const glm::vec3& value);

        /// Output a vec4 to stderr.
        /**
        * @param value Value to output.
        * @return The %Log instance.
        */
        UTILITY_API Log& operator<<(const glm::vec4& value);

        /// Sets channels.
        /**
         * @param channel The channel to set.
         * @param stream The stream that will be mapped to the channel.
         * @return Whether the operation succeeded or not.
         */
        UTILITY_API static bool Log::SetupStream(const Channel channel, std::ostream* stream);

        /// Sets all channels at once.
        /**
         * @param defaultStream The stream for default output.
         * @param info The stream for information.
         * @param warning The stream for warnings.
         * @param error The stream for errors.
         * @param console The stream to the console.
         * @return Whether the operation succeeded or not.
         */
        UTILITY_API static bool Log::SetupStreams(std::ostream* defaultStream, std::ostream* info, std::ostream* warning, std::ostream* error, std::ostream* console);

    private:
        Channel currentChannel;
        static std::ostream* streams[Channel::NUMBER_OF_CHANNELS];
};
<|endoftext|>


<commit_before>#pragma once

#include <string>
#include <ctime>
#include <glm/glm.hpp>
#include "linking.hpp"

/// Logging class.
/**
 * Usage:
 * @code{.cpp}
 * Log() << "Testing: " << 5 << "\n";
 * @endcode
 */
class Log {
    public:
        UTILITY_API const enum Channel {
            DEFAULT = 0,        ///< Default channel.
            INFO,               ///< Information.
            WARNING,            ///< Warnings.
            ERR,                ///< Error.
            CONSOLE,            ///< Console.
            NUMBER_OF_CHANNELS  ///< Maximum number of channels, ensure this is the last element of the enum if adding channels.
        };

        /// Destructor.
        UTILITY_API ~Log();

        /// Output some text to stderr.
        /**
         * @param text Text to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(const std::string text);

        /// Output an integer to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(const int value);

        /// Output an unsigned integer to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(const unsigned int value);

        /// Output a float to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(const float value);

        /// Output a double to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(const double value);

        /// Output a time to stderr.
        /**
         * Formatted Y-m-d H:M:S.
         * @param value Value to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(const time_t value);

        /// Output a vec2 to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(const glm::vec2& value);

        /// Output a vec3 to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(const glm::vec3& value);

        /// Output a vec4 to stderr.
        /**
        * @param value Value to output.
        * @return The %Log instance.
        */
        UTILITY_API Log& operator<<(const glm::vec4& value);

        /// Sets channels.
        /**
         * @param channel The channel to set.
         * @param stream The stream that will be mapped to the channel.
         * @return Whether the operation succeeded or not.
         */
        UTILITY_API static bool Log::SetupStream(const Channel channel, std::ostream* stream);

    private:
        Channel currentChannel;
        static std::ostream* streams[Channel::NUMBER_OF_CHANNELS];
};
<commit_msg>Changed Log() constructor to use new channels.<commit_after>#pragma once

#include <string>
#include <ctime>
#include <glm/glm.hpp>
#include "linking.hpp"

/// Logging class.
/**
 * Usage:
 * @code{.cpp}
 * Log() << "Testing: " << 5 << "\n";
 * @endcode
 */
class Log {
    public:
        UTILITY_API const enum Channel {
            DEFAULT = 0,        ///< Default channel.
            INFO,               ///< Information.
            WARNING,            ///< Warnings.
            ERR,                ///< Error.
            CONSOLE,            ///< Console.
            NUMBER_OF_CHANNELS  ///< Maximum number of channels, ensure this is the last element of the enum if adding channels.
        };

        /// Constructor.
        UTILITY_API Log(const Channel channel = Channel::DEFAULT);

        /// Destructor.
        UTILITY_API ~Log();

        /// Output some text to stderr.
        /**
         * @param text Text to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(const std::string text);

        /// Output an integer to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(const int value);

        /// Output an unsigned integer to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(const unsigned int value);

        /// Output a float to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(const float value);

        /// Output a double to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(const double value);

        /// Output a time to stderr.
        /**
         * Formatted Y-m-d H:M:S.
         * @param value Value to output.
         * @return The %Log instance
         */
        UTILITY_API Log& operator<<(const time_t value);

        /// Output a vec2 to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(const glm::vec2& value);

        /// Output a vec3 to stderr.
        /**
         * @param value Value to output.
         * @return The %Log instance.
         */
        UTILITY_API Log& operator<<(const glm::vec3& value);

        /// Output a vec4 to stderr.
        /**
        * @param value Value to output.
        * @return The %Log instance.
        */
        UTILITY_API Log& operator<<(const glm::vec4& value);

        /// Sets channels.
        /**
         * @param channel The channel to set.
         * @param stream The stream that will be mapped to the channel.
         * @return Whether the operation succeeded or not.
         */
        UTILITY_API static bool Log::SetupStream(const Channel channel, std::ostream* stream);

    private:
        Channel currentChannel;
        static std::ostream* streams[Channel::NUMBER_OF_CHANNELS];
};
<|endoftext|>