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

#include "src/vulkan/vertex_buffer.h"

#include <cassert>
#include <cstring>

#include "src/make_unique.h"
#include "src/vulkan/device.h"
#include "src/vulkan/format_data.h"

namespace amber {
namespace vulkan {
namespace {

// Return sign value of 32 bits float.
uint16_t FloatSign(const uint32_t hex_float) {
  return static_cast<uint16_t>(hex_float >> 31U);
}

// Return exponent value of 32 bits float.
uint16_t FloatExponent(const uint32_t hex_float) {
  uint32_t exponent = ((hex_float >> 23U) & ((1U << 8U) - 1U)) - 112U;
  const uint32_t half_exponent_mask = (1U << 5U) - 1U;
  assert(((exponent & ~half_exponent_mask) == 0U) && "Float exponent overflow");
  return static_cast<uint16_t>(exponent & half_exponent_mask);
}

// Return mantissa value of 32 bits float. Note that mantissa for 32
// bits float is 23 bits and this method must return uint32_t.
uint32_t FloatMantissa(const uint32_t hex_float) {
  return static_cast<uint32_t>(hex_float & ((1U << 23U) - 1U));
}

// Convert 32 bits float |value| to 16 bits float based on IEEE-754.
uint16_t FloatToHexFloat16(const float value) {
  const uint32_t* hex = reinterpret_cast<const uint32_t*>(&value);
  return static_cast<uint16_t>(FloatSign(*hex) << 15U) |
         static_cast<uint16_t>(FloatExponent(*hex) << 10U) |
         static_cast<uint16_t>(FloatMantissa(*hex) >> 13U);
}

// Convert 32 bits float |value| to 11 bits float based on IEEE-754.
uint16_t FloatToHexFloat11(const float value) {
  const uint32_t* hex = reinterpret_cast<const uint32_t*>(&value);
  assert(FloatSign(*hex) == 0);
  return static_cast<uint16_t>(FloatExponent(*hex) << 6U) |
         static_cast<uint16_t>(FloatMantissa(*hex) >> 17U);
}

// Convert 32 bits float |value| to 10 bits float based on IEEE-754.
uint16_t FloatToHexFloat10(const float value) {
  const uint32_t* hex = reinterpret_cast<const uint32_t*>(&value);
  assert(FloatSign(*hex) == 0);
  return static_cast<uint16_t>(FloatExponent(*hex) << 5U) |
         static_cast<uint16_t>(FloatMantissa(*hex) >> 18U);
}

// Convert float to small float format.
// See https://www.khronos.org/opengl/wiki/Small_Float_Formats
// and https://en.wikipedia.org/wiki/IEEE_754.
//
//    Sign Exponent Mantissa Exponent-Bias
// 16    1        5       10            15
// 11    0        5        6            15
// 10    0        5        5            15
// 32    1        8       23           127
// 64    1       11       52          1023
//
// 11 and 10 bits floats are always positive.
// 14 bits float is used only RGB9_E5 format in OpenGL but it does not exist
// in Vulkan.
//
// For example, 1234 in 32 bits float = 1.0011010010 * 2^10 with base 2.
//
// 1.0011010010 * 2^10 --> 0 (sign) / 10 + 127 (exp) / 0011010010 (Mantissa)
//                     --> 0x449a4000
uint16_t FloatToHexFloat(float value, uint8_t bits) {
  switch (bits) {
    case 10:
      return FloatToHexFloat10(value);
    case 11:
      return FloatToHexFloat11(value);
    case 16:
      return FloatToHexFloat16(value);
  }

  assert(false && "Invalid bits");
  return 0;
}

// Copy [0, bits) bits of |src| to
// [dst_bit_offset, dst_bit_offset + bits) of |dst|. If |bits| is
// less than 32 and the type is float, this method uses
// FloatToHexFloat() to convert it into small bits float.
Result CopyBitsOfValueToBuffer(uint8_t* dst,
                               const Value& src,
                               uint8_t dst_bit_offset,
                               uint8_t bits) {
  uint64_t data = 0;
  if (src.IsInteger()) {
    switch (bits) {
      case 8: {
        uint8_t* ptr = reinterpret_cast<uint8_t*>(&data);
        *ptr = src.AsUint8();
        break;
      }
      case 16: {
        uint16_t* ptr = reinterpret_cast<uint16_t*>(&data);
        *ptr = src.AsUint16();
        break;
      }
      case 32: {
        uint32_t* ptr = reinterpret_cast<uint32_t*>(&data);
        *ptr = src.AsUint32();
        break;
      }
      case 64: {
        uint64_t* ptr = reinterpret_cast<uint64_t*>(&data);
        *ptr = src.AsUint64();
        break;
      }
      default: {
        return Result("Vulkan: Invalid int bits for CopyBitsOfValueToBuffer");
      }
    }
  } else {
    if (bits == 64) {
      double* ptr = reinterpret_cast<double*>(&data);
      *ptr = src.AsDouble();
    } else {
      switch (bits) {
        case 32: {
          float* float_ptr = nullptr;
          float_ptr = reinterpret_cast<float*>(&data);
          *float_ptr = src.AsFloat();
          break;
        }
        case 16:
        case 11:
        case 10: {
          uint16_t* uint16_ptr = nullptr;
          uint16_ptr = reinterpret_cast<uint16_t*>(&data);
          *uint16_ptr = FloatToHexFloat(src.AsFloat(), bits);
          break;
        }
        default: {
          return Result(
              "Vulkan: Invalid float bits for CopyBitsOfValueToBuffer");
        }
      }
    }
  }

  while (dst_bit_offset > 7) {
    ++dst;
    dst_bit_offset = static_cast<uint8_t>(dst_bit_offset - 8);
  }

  // No overflow will happen. |dst_bit_offset| is based on VkFormat
  // and if |bits| is 64, |dst_bit_offset| must be 0. No component
  // has |bits| bigger than 64.
  data <<= dst_bit_offset;

  uint64_t* dst64 = reinterpret_cast<uint64_t*>(dst);
  uint64_t dst_lower_bits = *dst64 & ((1UL << dst_bit_offset) - 1UL);
  uint64_t dst_upper_bits =
      *dst64 & ~(((1ULL << (dst_bit_offset + bits)) - 1ULL));

  *dst64 = dst_lower_bits | data | dst_upper_bits;
  return {};
}

}  // namespace

VertexBuffer::VertexBuffer(Device* device) : device_(device) {}

VertexBuffer::~VertexBuffer() = default;

void VertexBuffer::Shutdown() {
  if (buffer_)
    buffer_->Shutdown();
}

void VertexBuffer::SetData(uint8_t location,
                           const Format& format,
                           const std::vector<Value>& values) {
  vertex_attr_desc_.emplace_back();
  // TODO(jaebaek): Support multiple binding
  vertex_attr_desc_.back().binding = 0;
  vertex_attr_desc_.back().location = location;
  vertex_attr_desc_.back().format = ToVkFormat(format.GetFormatType());
  vertex_attr_desc_.back().offset = stride_in_bytes_;

  stride_in_bytes_ += format.GetByteSize();

  formats_.push_back(format);
  data_.push_back(values);
}

Result VertexBuffer::FillVertexBufferWithData(VkCommandBuffer command) {
  // Send vertex data from host to device.
  uint8_t* ptr_in_stride_begin =
      static_cast<uint8_t*>(buffer_->HostAccessibleMemoryPtr());
  for (uint32_t i = 0; i < GetVertexCount(); ++i) {
    uint8_t* ptr = ptr_in_stride_begin;
    for (uint32_t j = 0; j < formats_.size(); ++j) {
      const auto pack_size = formats_[j].GetPackSize();
      if (pack_size) {
        Result r = CopyBitsOfValueToBuffer(ptr, data_[j][i], 0, pack_size);
        if (!r.IsSuccess())
          return r;

        ptr += pack_size / 8;
        continue;
      }

      const auto& components = formats_[j].GetComponents();
      uint8_t bit_offset = 0;

      for (uint32_t k = 0; k < components.size(); ++k) {
        uint8_t bits = components[k].num_bits;
        Result r = CopyBitsOfValueToBuffer(
            ptr, data_[j][i * components.size() + k], bit_offset, bits);
        if (!r.IsSuccess())
          return r;

        if ((k != components.size() - 1) &&
            (static_cast<uint32_t>(bit_offset) + static_cast<uint32_t>(bits) >=
             256)) {
          return Result(
              "Vulkan: VertexBuffer::FillVertexBufferWithData bit_offset "
              "overflow");
        }
        bit_offset = static_cast<uint8_t>(bit_offset + bits);
      }

      ptr += formats_[j].GetByteSize();
    }
    ptr_in_stride_begin += Get4BytesAlignedStride();
  }

  return buffer_->CopyToDevice(command);
}

void VertexBuffer::BindToCommandBuffer(VkCommandBuffer command) {
  const VkDeviceSize offset = 0;
  const VkBuffer buffer = buffer_->GetVkBuffer();
  // TODO(jaebaek): Support multiple binding
  device_->GetPtrs()->vkCmdBindVertexBuffers(command, 0, 1, &buffer, &offset);
}

Result VertexBuffer::SendVertexData(
    VkCommandBuffer command,
    const VkPhysicalDeviceMemoryProperties& properties) {
  if (!is_vertex_data_pending_)
    return Result("Vulkan::Vertices data was already sent");

  const size_t n_vertices = GetVertexCount();
  if (n_vertices == 0)
    return Result("Vulkan::Data for VertexBuffer is empty");

  size_t bytes = static_cast<size_t>(Get4BytesAlignedStride()) * n_vertices;

  if (!buffer_) {
    buffer_ = MakeUnique<Buffer>(device_, bytes, properties);
    Result r = buffer_->Initialize(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
                                   VK_BUFFER_USAGE_TRANSFER_DST_BIT);
    if (!r.IsSuccess())
      return r;
  }

  if (formats_.empty() || formats_[0].GetComponents().empty())
    return Result("Vulkan::Formats for VertexBuffer is empty");

  FillVertexBufferWithData(command);

  is_vertex_data_pending_ = false;
  return {};
}

}  // namespace vulkan
}  // namespace amber
<commit_msg>More casts to make CTS happy. (#291)<commit_after>// Copyright 2018 The Amber Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "src/vulkan/vertex_buffer.h"

#include <cassert>
#include <cstring>

#include "src/make_unique.h"
#include "src/vulkan/device.h"
#include "src/vulkan/format_data.h"

namespace amber {
namespace vulkan {
namespace {

// Return sign value of 32 bits float.
uint16_t FloatSign(const uint32_t hex_float) {
  return static_cast<uint16_t>(hex_float >> 31U);
}

// Return exponent value of 32 bits float.
uint16_t FloatExponent(const uint32_t hex_float) {
  uint32_t exponent = ((hex_float >> 23U) & ((1U << 8U) - 1U)) - 112U;
  const uint32_t half_exponent_mask = (1U << 5U) - 1U;
  assert(((exponent & ~half_exponent_mask) == 0U) && "Float exponent overflow");
  return static_cast<uint16_t>(exponent & half_exponent_mask);
}

// Return mantissa value of 32 bits float. Note that mantissa for 32
// bits float is 23 bits and this method must return uint32_t.
uint32_t FloatMantissa(const uint32_t hex_float) {
  return static_cast<uint32_t>(hex_float & ((1U << 23U) - 1U));
}

// Convert 32 bits float |value| to 16 bits float based on IEEE-754.
uint16_t FloatToHexFloat16(const float value) {
  const uint32_t* hex = reinterpret_cast<const uint32_t*>(&value);
  return static_cast<uint16_t>(
      static_cast<uint16_t>(FloatSign(*hex) << 15U) |
      static_cast<uint16_t>(FloatExponent(*hex) << 10U) |
      static_cast<uint16_t>(FloatMantissa(*hex) >> 13U));
}

// Convert 32 bits float |value| to 11 bits float based on IEEE-754.
uint16_t FloatToHexFloat11(const float value) {
  const uint32_t* hex = reinterpret_cast<const uint32_t*>(&value);
  assert(FloatSign(*hex) == 0);
  return static_cast<uint16_t>(
      static_cast<uint16_t>(FloatExponent(*hex) << 6U) |
      static_cast<uint16_t>(FloatMantissa(*hex) >> 17U));
}

// Convert 32 bits float |value| to 10 bits float based on IEEE-754.
uint16_t FloatToHexFloat10(const float value) {
  const uint32_t* hex = reinterpret_cast<const uint32_t*>(&value);
  assert(FloatSign(*hex) == 0);
  return static_cast<uint16_t>(
      static_cast<uint16_t>(FloatExponent(*hex) << 5U) |
      static_cast<uint16_t>(FloatMantissa(*hex) >> 18U));
}

// Convert float to small float format.
// See https://www.khronos.org/opengl/wiki/Small_Float_Formats
// and https://en.wikipedia.org/wiki/IEEE_754.
//
//    Sign Exponent Mantissa Exponent-Bias
// 16    1        5       10            15
// 11    0        5        6            15
// 10    0        5        5            15
// 32    1        8       23           127
// 64    1       11       52          1023
//
// 11 and 10 bits floats are always positive.
// 14 bits float is used only RGB9_E5 format in OpenGL but it does not exist
// in Vulkan.
//
// For example, 1234 in 32 bits float = 1.0011010010 * 2^10 with base 2.
//
// 1.0011010010 * 2^10 --> 0 (sign) / 10 + 127 (exp) / 0011010010 (Mantissa)
//                     --> 0x449a4000
uint16_t FloatToHexFloat(float value, uint8_t bits) {
  switch (bits) {
    case 10:
      return FloatToHexFloat10(value);
    case 11:
      return FloatToHexFloat11(value);
    case 16:
      return FloatToHexFloat16(value);
  }

  assert(false && "Invalid bits");
  return 0;
}

// Copy [0, bits) bits of |src| to
// [dst_bit_offset, dst_bit_offset + bits) of |dst|. If |bits| is
// less than 32 and the type is float, this method uses
// FloatToHexFloat() to convert it into small bits float.
Result CopyBitsOfValueToBuffer(uint8_t* dst,
                               const Value& src,
                               uint8_t dst_bit_offset,
                               uint8_t bits) {
  uint64_t data = 0;
  if (src.IsInteger()) {
    switch (bits) {
      case 8: {
        uint8_t* ptr = reinterpret_cast<uint8_t*>(&data);
        *ptr = src.AsUint8();
        break;
      }
      case 16: {
        uint16_t* ptr = reinterpret_cast<uint16_t*>(&data);
        *ptr = src.AsUint16();
        break;
      }
      case 32: {
        uint32_t* ptr = reinterpret_cast<uint32_t*>(&data);
        *ptr = src.AsUint32();
        break;
      }
      case 64: {
        uint64_t* ptr = reinterpret_cast<uint64_t*>(&data);
        *ptr = src.AsUint64();
        break;
      }
      default: {
        return Result("Vulkan: Invalid int bits for CopyBitsOfValueToBuffer");
      }
    }
  } else {
    if (bits == 64) {
      double* ptr = reinterpret_cast<double*>(&data);
      *ptr = src.AsDouble();
    } else {
      switch (bits) {
        case 32: {
          float* float_ptr = nullptr;
          float_ptr = reinterpret_cast<float*>(&data);
          *float_ptr = src.AsFloat();
          break;
        }
        case 16:
        case 11:
        case 10: {
          uint16_t* uint16_ptr = nullptr;
          uint16_ptr = reinterpret_cast<uint16_t*>(&data);
          *uint16_ptr = FloatToHexFloat(src.AsFloat(), bits);
          break;
        }
        default: {
          return Result(
              "Vulkan: Invalid float bits for CopyBitsOfValueToBuffer");
        }
      }
    }
  }

  while (dst_bit_offset > 7) {
    ++dst;
    dst_bit_offset = static_cast<uint8_t>(dst_bit_offset - 8);
  }

  // No overflow will happen. |dst_bit_offset| is based on VkFormat
  // and if |bits| is 64, |dst_bit_offset| must be 0. No component
  // has |bits| bigger than 64.
  data <<= dst_bit_offset;

  uint64_t* dst64 = reinterpret_cast<uint64_t*>(dst);
  uint64_t dst_lower_bits = *dst64 & ((1UL << dst_bit_offset) - 1UL);
  uint64_t dst_upper_bits =
      *dst64 & ~(((1ULL << (dst_bit_offset + bits)) - 1ULL));

  *dst64 = dst_lower_bits | data | dst_upper_bits;
  return {};
}

}  // namespace

VertexBuffer::VertexBuffer(Device* device) : device_(device) {}

VertexBuffer::~VertexBuffer() = default;

void VertexBuffer::Shutdown() {
  if (buffer_)
    buffer_->Shutdown();
}

void VertexBuffer::SetData(uint8_t location,
                           const Format& format,
                           const std::vector<Value>& values) {
  vertex_attr_desc_.emplace_back();
  // TODO(jaebaek): Support multiple binding
  vertex_attr_desc_.back().binding = 0;
  vertex_attr_desc_.back().location = location;
  vertex_attr_desc_.back().format = ToVkFormat(format.GetFormatType());
  vertex_attr_desc_.back().offset = stride_in_bytes_;

  stride_in_bytes_ += format.GetByteSize();

  formats_.push_back(format);
  data_.push_back(values);
}

Result VertexBuffer::FillVertexBufferWithData(VkCommandBuffer command) {
  // Send vertex data from host to device.
  uint8_t* ptr_in_stride_begin =
      static_cast<uint8_t*>(buffer_->HostAccessibleMemoryPtr());
  for (uint32_t i = 0; i < GetVertexCount(); ++i) {
    uint8_t* ptr = ptr_in_stride_begin;
    for (uint32_t j = 0; j < formats_.size(); ++j) {
      const auto pack_size = formats_[j].GetPackSize();
      if (pack_size) {
        Result r = CopyBitsOfValueToBuffer(ptr, data_[j][i], 0, pack_size);
        if (!r.IsSuccess())
          return r;

        ptr += pack_size / 8;
        continue;
      }

      const auto& components = formats_[j].GetComponents();
      uint8_t bit_offset = 0;

      for (uint32_t k = 0; k < components.size(); ++k) {
        uint8_t bits = components[k].num_bits;
        Result r = CopyBitsOfValueToBuffer(
            ptr, data_[j][i * components.size() + k], bit_offset, bits);
        if (!r.IsSuccess())
          return r;

        if ((k != components.size() - 1) &&
            (static_cast<uint32_t>(bit_offset) + static_cast<uint32_t>(bits) >=
             256)) {
          return Result(
              "Vulkan: VertexBuffer::FillVertexBufferWithData bit_offset "
              "overflow");
        }
        bit_offset = static_cast<uint8_t>(bit_offset + bits);
      }

      ptr += formats_[j].GetByteSize();
    }
    ptr_in_stride_begin += Get4BytesAlignedStride();
  }

  return buffer_->CopyToDevice(command);
}

void VertexBuffer::BindToCommandBuffer(VkCommandBuffer command) {
  const VkDeviceSize offset = 0;
  const VkBuffer buffer = buffer_->GetVkBuffer();
  // TODO(jaebaek): Support multiple binding
  device_->GetPtrs()->vkCmdBindVertexBuffers(command, 0, 1, &buffer, &offset);
}

Result VertexBuffer::SendVertexData(
    VkCommandBuffer command,
    const VkPhysicalDeviceMemoryProperties& properties) {
  if (!is_vertex_data_pending_)
    return Result("Vulkan::Vertices data was already sent");

  const size_t n_vertices = GetVertexCount();
  if (n_vertices == 0)
    return Result("Vulkan::Data for VertexBuffer is empty");

  size_t bytes = static_cast<size_t>(Get4BytesAlignedStride()) * n_vertices;

  if (!buffer_) {
    buffer_ = MakeUnique<Buffer>(device_, bytes, properties);
    Result r = buffer_->Initialize(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
                                   VK_BUFFER_USAGE_TRANSFER_DST_BIT);
    if (!r.IsSuccess())
      return r;
  }

  if (formats_.empty() || formats_[0].GetComponents().empty())
    return Result("Vulkan::Formats for VertexBuffer is empty");

  FillVertexBufferWithData(command);

  is_vertex_data_pending_ = false;
  return {};
}

}  // namespace vulkan
}  // namespace amber
<|endoftext|>


<commit_before>#include <eeros/hal/Mouse.hpp>
#include <eeros/hal/HAL.hpp>
#include <eeros/hal/MouseDigIn.hpp>
#include <eeros/core/Fault.hpp>

#include <cstdio>
#include <fcntl.h>
#include <unistd.h>

using namespace eeros::hal;

Mouse::Mouse(std::string dev) {
	open(dev.c_str());
	left = new MouseDigIn("leftMouseButton", this);
	middle = new MouseDigIn("middleMouseButton", this);
	right = new MouseDigIn("rightMouseButton", this);
	HAL& hal = HAL::instance();
	hal.addInput(left);
	hal.addInput(middle);
	hal.addInput(right);

	current.button.left = 0;
	current.button.middle = 0;
        current.button.right = 0;

        current.axis.x = 0;
        current.axis.y = 0;
        current.axis.z = 0;
        current.axis.r = 0;

        last = current;
}

Mouse::~Mouse() {
	running = false;
	join();
	close();
}

bool Mouse::open(const char* device) {
	fd = ::open(device, O_RDONLY);
	if (fd < 0) log.error() << "Mouse: could not open input device on " + std::string(device);
	return fd;
}

void Mouse::close() {
        ::close(fd);
}

std::string Mouse::name() {
	if (!fd) return "";
	char name[128];
	if (ioctl(fd, EVIOCGNAME (sizeof(name)), name)) {
		name[127] = 0;
		return name;
	} else return "";
}

void Mouse::on_event(std::function<void(struct input_event)> action) {
        event_action = action;
}

void Mouse::on_button(std::function<void(int, bool)> action) {
        button_action = action;
}

void Mouse::on_axis(std::function<void(int, signed)> action) {
        axis_action = action;
}

void Mouse::run() {
	running = true;
	if (fd < 0) return;
	struct input_event e;
	while (running) {
		ssize_t n = read(fd, &e, sizeof(struct input_event));

		if (e.type == EV_KEY) {
			switch (e.code) {
				case BTN_LEFT: current.button.left = e.value; break;
				case BTN_MIDDLE: current.button.middle = e.value; break;
				case BTN_RIGHT: current.button.right = e.value; break;
				default: break;
			}

			if (button_action != nullptr) button_action(e.code, e.value);
		} else if (e.type == EV_REL) {
			switch (e.code) {
				case REL_X: current.axis.x += e.value; break;
				case REL_Y: current.axis.y += e.value; break;
				case REL_WHEEL: current.axis.z += e.value; break;
				case REL_HWHEEL: current.axis.r += e.value; break;
				default: break;
			}

			if (axis_action != nullptr) axis_action(e.code, e.value);
		}

		if (event_action != nullptr) event_action(e);

		last = current;
	}
}
<commit_msg>Change to unblocking read<commit_after>#include <eeros/hal/Mouse.hpp>
#include <eeros/hal/HAL.hpp>
#include <eeros/hal/MouseDigIn.hpp>
#include <eeros/core/Fault.hpp>

#include <cstdio>
#include <fcntl.h>
#include <unistd.h>

using namespace eeros::hal;

Mouse::Mouse(std::string dev) {
	open(dev.c_str());
	left = new MouseDigIn("leftMouseButton", this);
	middle = new MouseDigIn("middleMouseButton", this);
	right = new MouseDigIn("rightMouseButton", this);
	HAL& hal = HAL::instance();
	hal.addInput(left);
	hal.addInput(middle);
	hal.addInput(right);

	current.button.left = 0;
	current.button.middle = 0;
        current.button.right = 0;

        current.axis.x = 0;
        current.axis.y = 0;
        current.axis.z = 0;
        current.axis.r = 0;

        last = current;
}

Mouse::~Mouse() {
	running = false;
	join();
	close();
}

bool Mouse::open(const char* device) {
	fd = ::open(device, O_RDONLY | O_NONBLOCK);
	if (fd < 0) log.error() << "Mouse: could not open input device on " + std::string(device);
	return fd;
}

void Mouse::close() {
        ::close(fd);
}

std::string Mouse::name() {
	if (!fd) return "";
	char name[128];
	if (ioctl(fd, EVIOCGNAME (sizeof(name)), name)) {
		name[127] = 0;
		return name;
	} else return "";
}

void Mouse::on_event(std::function<void(struct input_event)> action) {
        event_action = action;
}

void Mouse::on_button(std::function<void(int, bool)> action) {
        button_action = action;
}

void Mouse::on_axis(std::function<void(int, signed)> action) {
        axis_action = action;
}

void Mouse::run() {
	running = true;
	if (fd < 0) return;
	struct input_event e;
	while (running) {
		ssize_t n = read(fd, &e, sizeof(struct input_event));
		if (n > 0) {
			if (e.type == EV_KEY) {
				switch (e.code) {
					case BTN_LEFT: current.button.left = e.value; break;
					case BTN_MIDDLE: current.button.middle = e.value; break;
					case BTN_RIGHT: current.button.right = e.value; break;
					default: break;
				}

				if (button_action != nullptr) button_action(e.code, e.value);
			} else if (e.type == EV_REL) {
				switch (e.code) {
					case REL_X: current.axis.x += e.value; break;
					case REL_Y: current.axis.y += e.value; break;
					case REL_WHEEL: current.axis.z += e.value; break;
					case REL_HWHEEL: current.axis.r += e.value; break;
					default: break;
				}

				if (axis_action != nullptr) axis_action(e.code, e.value);
			}

			if (event_action != nullptr) event_action(e);

			last = current;
		} else usleep(1000);
	}
}
<|endoftext|>


<commit_before>#include "httpclient.h"

#include <assert.h>
#include <sys/stat.h>

#include "logger.h"

/*****************************************************************************/
/**
 * \par Description:
 *    A writeback handler for the curl library. I handles writing response
 *    data from curl into a string.
 *    https://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html
 *
 */
static size_t writeString(void* contents, size_t size, size_t nmemb, void* userp) {
  assert(userp);
  // append the writeback data to the provided string
  (static_cast<std::string*>(userp))->append((char*)contents, size * nmemb);

  // return size of written data
  return size * nmemb;
}

static size_t writeFile(void* contents, size_t size, size_t nmemb, FILE* fp) {
  size_t written = fwrite(contents, size, nmemb, fp);
  return written;
}

// Discard the http body
static size_t writeDiscard(void*, size_t size, size_t nmemb) { return size * nmemb; }

HttpClient::HttpClient() : authenticated(false) {
  curl_global_init(CURL_GLOBAL_ALL);
  curl = curl_easy_init();
  headers = NULL;
  http_code = 0;

  curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
  curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60L);
  curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 60L);

  // let curl use our write function
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeString);
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL);

  if (loggerGetSeverity() == LVL_trace) {
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
  }

  headers = curl_slist_append(headers, "Content-Type: application/json");
  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
}

HttpClient::HttpClient(const HttpClient& curl_in) : authenticated(false) {
  curl = curl_easy_duphandle(curl_in.curl);
  token = curl_in.token;

  struct curl_slist* inlist = curl_in.headers;
  headers = NULL;
  struct curl_slist* tmp;

  while (inlist) {
    tmp = curl_slist_append(headers, inlist->data);

    if (!tmp) {
      curl_slist_free_all(headers);
      return;
    }

    headers = tmp;
    inlist = inlist->next;
  }
}

HttpClient::~HttpClient() {
  curl_slist_free_all(headers);
  curl_easy_cleanup(curl);
}

bool HttpClient::authenticate(const std::string& cert, const std::string& ca_file, const std::string& pkey) {
  // TODO return false in case of wrong certificates
  setCerts(ca_file, cert, pkey);
  authenticated = true;
  return true;
}

bool HttpClient::authenticate(const AuthConfig& conf) {
  CURL* curl_auth = curl_easy_duphandle(curl);
  std::string auth_url = conf.server + "/token";
  curl_easy_setopt(curl_auth, CURLOPT_URL, auth_url.c_str());
  // let curl put the username and password using HTTP basic authentication
  curl_easy_setopt(curl_auth, CURLOPT_HTTPAUTH, (long)CURLAUTH_BASIC);
  curl_easy_setopt(curl_auth, CURLOPT_POSTFIELDS, "grant_type=client_credentials");

  // compose username and password
  std::string auth_header = conf.client_id + ":" + conf.client_secret;
  // forward username and password to curl
  curl_easy_setopt(curl_auth, CURLOPT_USERPWD, auth_header.c_str());

  LOGGER_LOG(LVL_debug, "servercon - requesting token from server: " << conf.server);

  std::string response;
  curl_easy_setopt(curl_auth, CURLOPT_WRITEDATA, (void*)&response);

  curl_slist *h = curl_slist_append(NULL, "Content-Type: application/x-www-form-urlencoded");
  h = curl_slist_append(h, "charsets: utf-8");
  curl_easy_setopt(curl_auth, CURLOPT_HTTPHEADER, h);

  CURLcode result = curl_easy_perform(curl_auth);
  LOGGER_LOG(LVL_trace, "response:" << response);

  curl_easy_cleanup(curl_auth);
  if (result != CURLE_OK) {
    LOGGER_LOG(LVL_error, "authentication curl error: " << result << " with server: " << conf.server
                                                        << "and auth header: " << auth_header);
    return false;
  }
  Json::Reader reader;
  Json::Value json;
  reader.parse(response, json);

  token = json["access_token"].asString();

  std::string header = "Authorization: Bearer " + token;
  headers = curl_slist_append(headers, header.c_str());
  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
  authenticated = true;
  return true;
}

std::string HttpClient::get(const std::string& url) {
  curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
  curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
  LOGGER_LOG(LVL_debug, "GET " << url);
  return perform(curl);
}

Json::Value HttpClient::getJson(const std::string& url) {
  Json::Value json;
  Json::Reader reader;

  std::string response = get(url);
  reader.parse(response, json);
  return json;
}

Json::Value HttpClient::post(const std::string& url, const Json::Value& data) {
  Json::Value json;
  Json::Reader reader;

  std::string response = post(url, Json::FastWriter().write(data));
  reader.parse(response, json);
  return json;
}

void HttpClient::setCerts(const std::string& ca, const std::string& cert, const std::string& pkey) {
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
  curl_easy_setopt(curl, CURLOPT_CAINFO, ca.c_str());
  curl_easy_setopt(curl, CURLOPT_SSLCERT, cert.c_str());
  curl_easy_setopt(curl, CURLOPT_SSLKEY, pkey.c_str());
}

std::string HttpClient::post(const std::string& url, const std::string& data) {
  curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
  curl_easy_setopt(curl, CURLOPT_POST, 1);
  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
  LOGGER_LOG(LVL_trace, "post request body:" << data);
  std::string result = perform(curl);
  return result;
}

std::string HttpClient::put(const std::string& url, const std::string& data) {
  curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
  LOGGER_LOG(LVL_trace, "put request body:" << data);
  std::string result = perform(curl);
  return result;
}

std::string HttpClient::perform(CURL* curl_handler) {
  std::string response;
  curl_easy_setopt(curl_handler, CURLOPT_WRITEDATA, (void*)&response);
  CURLcode result = curl_easy_perform(curl_handler);
  if (result != CURLE_OK) {
    std::ostringstream error_message;
    error_message << "curl error:" << curl_easy_strerror(result);
    LOGGER_LOG(LVL_error, error_message.str());
    throw std::runtime_error(error_message.str());
  }
  curl_easy_getinfo(curl_handler, CURLINFO_RESPONSE_CODE, &http_code);
  LOGGER_LOG(LVL_trace, "response:" << response);
  return response;
}

bool HttpClient::download(const std::string& url, const std::string& filename) {
  // Download an update from SOTA Server. This requires two requests: the first
  // is to the sota server, and needs an Authentication: header to be present.
  // This request will return a 30x redirect to S3, which we must not send our
  // secret to (s3 also throws an error in this case :)

  CURL* curl_redir = curl_easy_duphandle(curl);
  curl_easy_setopt(curl_redir, CURLOPT_URL, url.c_str());
  curl_easy_setopt(curl_redir, CURLOPT_FOLLOWLOCATION, 0L);
  curl_easy_setopt(curl_redir, CURLOPT_WRITEFUNCTION, writeDiscard);

  CURLcode result = curl_easy_perform(curl_redir);
  if (result != CURLE_OK) {
    LOGGER_LOG(LVL_error, "curl download error: " << result);
    curl_easy_cleanup(curl_redir);
    return false;
  }

  char* newurl;
  curl_easy_getinfo(curl_redir, CURLINFO_REDIRECT_URL, &newurl);
  LOGGER_LOG(LVL_debug, "AWS Redirect URL:" << newurl);

  // Now perform the actual download
  CURL* curl_download = curl_easy_init();
  curl_easy_setopt(curl_download, CURLOPT_URL, newurl);
  // Let AWS Redirect us
  curl_easy_setopt(curl_download, CURLOPT_FOLLOWLOCATION, 1L);
  curl_easy_setopt(curl_download, CURLOPT_WRITEFUNCTION, writeFile);

  struct stat st;
  std::string mode = "w";
  if (!stat(filename.c_str(), &st)) {
    curl_easy_setopt(curl_download, CURLOPT_RESUME_FROM, st.st_size);
    mode = "a";
  }

  FILE* fp = fopen(filename.c_str(), mode.c_str());
  curl_easy_setopt(curl_download, CURLOPT_WRITEDATA, fp);
  result = curl_easy_perform(curl_download);

  if (result == CURLE_RANGE_ERROR) {
    fseek(fp, 0, SEEK_SET);
    curl_easy_setopt(curl_download, CURLOPT_RESUME_FROM, 0);
    result = curl_easy_perform(curl_download);
  }
  curl_easy_cleanup(curl_download);
  curl_easy_cleanup(curl_redir);  // Keep newurl alive
  fclose(fp);

  if (result != CURLE_OK) {
    LOGGER_LOG(LVL_error, "curl download error: " << result);
    return false;
  }
  return true;
}
// vim: set tabstop=2 shiftwidth=2 expandtab:
<commit_msg>Reformat<commit_after>#include "httpclient.h"

#include <assert.h>
#include <sys/stat.h>

#include "logger.h"

/*****************************************************************************/
/**
 * \par Description:
 *    A writeback handler for the curl library. I handles writing response
 *    data from curl into a string.
 *    https://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html
 *
 */
static size_t writeString(void* contents, size_t size, size_t nmemb, void* userp) {
  assert(userp);
  // append the writeback data to the provided string
  (static_cast<std::string*>(userp))->append((char*)contents, size * nmemb);

  // return size of written data
  return size * nmemb;
}

static size_t writeFile(void* contents, size_t size, size_t nmemb, FILE* fp) {
  size_t written = fwrite(contents, size, nmemb, fp);
  return written;
}

// Discard the http body
static size_t writeDiscard(void*, size_t size, size_t nmemb) { return size * nmemb; }

HttpClient::HttpClient() : authenticated(false) {
  curl_global_init(CURL_GLOBAL_ALL);
  curl = curl_easy_init();
  headers = NULL;
  http_code = 0;

  curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
  curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60L);
  curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 60L);

  // let curl use our write function
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeString);
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL);

  if (loggerGetSeverity() == LVL_trace) {
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
  }

  headers = curl_slist_append(headers, "Content-Type: application/json");
  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
}

HttpClient::HttpClient(const HttpClient& curl_in) : authenticated(false) {
  curl = curl_easy_duphandle(curl_in.curl);
  token = curl_in.token;

  struct curl_slist* inlist = curl_in.headers;
  headers = NULL;
  struct curl_slist* tmp;

  while (inlist) {
    tmp = curl_slist_append(headers, inlist->data);

    if (!tmp) {
      curl_slist_free_all(headers);
      return;
    }

    headers = tmp;
    inlist = inlist->next;
  }
}

HttpClient::~HttpClient() {
  curl_slist_free_all(headers);
  curl_easy_cleanup(curl);
}

bool HttpClient::authenticate(const std::string& cert, const std::string& ca_file, const std::string& pkey) {
  // TODO return false in case of wrong certificates
  setCerts(ca_file, cert, pkey);
  authenticated = true;
  return true;
}

bool HttpClient::authenticate(const AuthConfig& conf) {
  CURL* curl_auth = curl_easy_duphandle(curl);
  std::string auth_url = conf.server + "/token";
  curl_easy_setopt(curl_auth, CURLOPT_URL, auth_url.c_str());
  // let curl put the username and password using HTTP basic authentication
  curl_easy_setopt(curl_auth, CURLOPT_HTTPAUTH, (long)CURLAUTH_BASIC);
  curl_easy_setopt(curl_auth, CURLOPT_POSTFIELDS, "grant_type=client_credentials");

  // compose username and password
  std::string auth_header = conf.client_id + ":" + conf.client_secret;
  // forward username and password to curl
  curl_easy_setopt(curl_auth, CURLOPT_USERPWD, auth_header.c_str());

  LOGGER_LOG(LVL_debug, "servercon - requesting token from server: " << conf.server);

  std::string response;
  curl_easy_setopt(curl_auth, CURLOPT_WRITEDATA, (void*)&response);

  curl_slist* h = curl_slist_append(NULL, "Content-Type: application/x-www-form-urlencoded");
  h = curl_slist_append(h, "charsets: utf-8");
  curl_easy_setopt(curl_auth, CURLOPT_HTTPHEADER, h);

  CURLcode result = curl_easy_perform(curl_auth);
  LOGGER_LOG(LVL_trace, "response:" << response);

  curl_easy_cleanup(curl_auth);
  if (result != CURLE_OK) {
    LOGGER_LOG(LVL_error, "authentication curl error: " << result << " with server: " << conf.server
                                                        << "and auth header: " << auth_header);
    return false;
  }
  Json::Reader reader;
  Json::Value json;
  reader.parse(response, json);

  token = json["access_token"].asString();

  std::string header = "Authorization: Bearer " + token;
  headers = curl_slist_append(headers, header.c_str());
  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
  authenticated = true;
  return true;
}

std::string HttpClient::get(const std::string& url) {
  curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
  curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
  LOGGER_LOG(LVL_debug, "GET " << url);
  return perform(curl);
}

Json::Value HttpClient::getJson(const std::string& url) {
  Json::Value json;
  Json::Reader reader;

  std::string response = get(url);
  reader.parse(response, json);
  return json;
}

Json::Value HttpClient::post(const std::string& url, const Json::Value& data) {
  Json::Value json;
  Json::Reader reader;

  std::string response = post(url, Json::FastWriter().write(data));
  reader.parse(response, json);
  return json;
}

void HttpClient::setCerts(const std::string& ca, const std::string& cert, const std::string& pkey) {
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
  curl_easy_setopt(curl, CURLOPT_CAINFO, ca.c_str());
  curl_easy_setopt(curl, CURLOPT_SSLCERT, cert.c_str());
  curl_easy_setopt(curl, CURLOPT_SSLKEY, pkey.c_str());
}

std::string HttpClient::post(const std::string& url, const std::string& data) {
  curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
  curl_easy_setopt(curl, CURLOPT_POST, 1);
  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
  LOGGER_LOG(LVL_trace, "post request body:" << data);
  std::string result = perform(curl);
  return result;
}

std::string HttpClient::put(const std::string& url, const std::string& data) {
  curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
  LOGGER_LOG(LVL_trace, "put request body:" << data);
  std::string result = perform(curl);
  return result;
}

std::string HttpClient::perform(CURL* curl_handler) {
  std::string response;
  curl_easy_setopt(curl_handler, CURLOPT_WRITEDATA, (void*)&response);
  CURLcode result = curl_easy_perform(curl_handler);
  if (result != CURLE_OK) {
    std::ostringstream error_message;
    error_message << "curl error:" << curl_easy_strerror(result);
    LOGGER_LOG(LVL_error, error_message.str());
    throw std::runtime_error(error_message.str());
  }
  curl_easy_getinfo(curl_handler, CURLINFO_RESPONSE_CODE, &http_code);
  LOGGER_LOG(LVL_trace, "response:" << response);
  return response;
}

bool HttpClient::download(const std::string& url, const std::string& filename) {
  // Download an update from SOTA Server. This requires two requests: the first
  // is to the sota server, and needs an Authentication: header to be present.
  // This request will return a 30x redirect to S3, which we must not send our
  // secret to (s3 also throws an error in this case :)

  CURL* curl_redir = curl_easy_duphandle(curl);
  curl_easy_setopt(curl_redir, CURLOPT_URL, url.c_str());
  curl_easy_setopt(curl_redir, CURLOPT_FOLLOWLOCATION, 0L);
  curl_easy_setopt(curl_redir, CURLOPT_WRITEFUNCTION, writeDiscard);

  CURLcode result = curl_easy_perform(curl_redir);
  if (result != CURLE_OK) {
    LOGGER_LOG(LVL_error, "curl download error: " << result);
    curl_easy_cleanup(curl_redir);
    return false;
  }

  char* newurl;
  curl_easy_getinfo(curl_redir, CURLINFO_REDIRECT_URL, &newurl);
  LOGGER_LOG(LVL_debug, "AWS Redirect URL:" << newurl);

  // Now perform the actual download
  CURL* curl_download = curl_easy_init();
  curl_easy_setopt(curl_download, CURLOPT_URL, newurl);
  // Let AWS Redirect us
  curl_easy_setopt(curl_download, CURLOPT_FOLLOWLOCATION, 1L);
  curl_easy_setopt(curl_download, CURLOPT_WRITEFUNCTION, writeFile);

  struct stat st;
  std::string mode = "w";
  if (!stat(filename.c_str(), &st)) {
    curl_easy_setopt(curl_download, CURLOPT_RESUME_FROM, st.st_size);
    mode = "a";
  }

  FILE* fp = fopen(filename.c_str(), mode.c_str());
  curl_easy_setopt(curl_download, CURLOPT_WRITEDATA, fp);
  result = curl_easy_perform(curl_download);

  if (result == CURLE_RANGE_ERROR) {
    fseek(fp, 0, SEEK_SET);
    curl_easy_setopt(curl_download, CURLOPT_RESUME_FROM, 0);
    result = curl_easy_perform(curl_download);
  }
  curl_easy_cleanup(curl_download);
  curl_easy_cleanup(curl_redir);  // Keep newurl alive
  fclose(fp);

  if (result != CURLE_OK) {
    LOGGER_LOG(LVL_error, "curl download error: " << result);
    return false;
  }
  return true;
}
// vim: set tabstop=2 shiftwidth=2 expandtab:
<|endoftext|>


<commit_before>/* ---------------------------------------------------------------------
 *
 * Copyright (C) 2009 - 2014 by the deal.II authors
 *
 * This file is part of the deal.II library.
 *
 * The deal.II library is free software; you can use it, redistribute
 * it, and/or modify it under the terms of the GNU Lesser General
 * Public License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * The full text of the license can be found in the file LICENSE at
 * the top level of the deal.II distribution.
 *
 * ---------------------------------------------------------------------

 *
 * Author: Wolfgang Bangerth, Texas A&M University, 2009, 2010
 *         Timo Heister, University of Goettingen, 2009, 2010
 */

#include <deal.II/base/config.h>
#include <deal.II/base/quadrature_lib.h>
#include <deal.II/base/function.h>
#include <deal.II/base/timer.h>

#ifdef DEAL_II_WITH_MPI

#include <deal.II/lac/generic_linear_algebra.h>

#define USE_PETSC_LA

namespace LA
{
#ifdef USE_PETSC_LA
  using namespace dealii::LinearAlgebraPETSc;
#else
  using namespace dealii::LinearAlgebraTrilinos;
#endif
}

#include <deal.II/lac/vector.h>
#include <deal.II/lac/full_matrix.h>
#include <deal.II/lac/solver_cg.h>
#include <deal.II/lac/constraint_matrix.h>
#include <deal.II/lac/compressed_simple_sparsity_pattern.h>

#include <deal.II/lac/petsc_parallel_sparse_matrix.h>
#include <deal.II/lac/petsc_parallel_vector.h>
#include <deal.II/lac/petsc_solver.h>
#include <deal.II/lac/petsc_precondition.h>

#include <deal.II/grid/grid_generator.h>
#include <deal.II/grid/tria_accessor.h>
#include <deal.II/grid/tria_iterator.h>
#include <deal.II/dofs/dof_handler.h>
#include <deal.II/dofs/dof_accessor.h>
#include <deal.II/dofs/dof_tools.h>
#include <deal.II/fe/fe_values.h>
#include <deal.II/fe/fe_q.h>
#include <deal.II/numerics/vector_tools.h>
#include <deal.II/numerics/data_out.h>
#include <deal.II/numerics/error_estimator.h>

#include <deal.II/base/utilities.h>
#include <deal.II/base/conditional_ostream.h>
#include <deal.II/base/index_set.h>
#include <deal.II/lac/sparsity_tools.h>
#include <deal.II/distributed/tria.h>
#include <deal.II/distributed/grid_refinement.h>

#include <fstream>
#include <iostream>

#include "parsed_grid_generator.h"
#include "parsed_finite_element.h"
#include "utilities.h"

namespace ParallelLaplace
{
  using namespace dealii;

  template <int dim>
  class LaplaceProblem
  {
  public:
    LaplaceProblem ();
    ~LaplaceProblem ();

    void run ();

  private:
    void setup_system ();
    void assemble_system ();
    void solve ();
    void refine_grid ();
    void output_results (const unsigned int cycle) const;
    void make_grid_fe();

    MPI_Comm                                  mpi_communicator;

    SmartPointer<parallel::distributed::Triangulation<dim> > triangulation;

    SmartPointer<DoFHandler<dim> >                           dof_handler;
    SmartPointer<FiniteElement<dim,dim> >                               fe;

    IndexSet                                  locally_owned_dofs;
    IndexSet                                  locally_relevant_dofs;

    ConstraintMatrix                          constraints;

    LA::MPI::SparseMatrix system_matrix;
    LA::MPI::Vector locally_relevant_solution;
    LA::MPI::Vector system_rhs;

    ConditionalOStream                        pcout;
    TimerOutput                               computing_timer;
  };

  template <int dim>
  LaplaceProblem<dim>::LaplaceProblem ()
    :
    mpi_communicator (MPI_COMM_WORLD),
    pcout (std::cout,
           (Utilities::MPI::this_mpi_process(mpi_communicator)
            == 0)),
    computing_timer (mpi_communicator,
                     pcout,
                     TimerOutput::summary,
                     TimerOutput::wall_times)
  {}

  template <int dim>
  LaplaceProblem<dim>::~LaplaceProblem ()
  {
    dof_handler->clear ();
    smart_delete(dof_handler);
    smart_delete(fe);
    smart_delete(triangulation);
  }

  template <int dim>
  void LaplaceProblem<dim>::setup_system ()
  {
    TimerOutput::Scope t(computing_timer, "setup");

    dof_handler->distribute_dofs (*fe);

    locally_owned_dofs = dof_handler->locally_owned_dofs ();
    DoFTools::extract_locally_relevant_dofs (*dof_handler,
                                             locally_relevant_dofs);

    locally_relevant_solution.reinit (locally_owned_dofs,
                                      locally_relevant_dofs, mpi_communicator);
    system_rhs.reinit (locally_owned_dofs, mpi_communicator);

    constraints.clear ();
    constraints.reinit (locally_relevant_dofs);
    DoFTools::make_hanging_node_constraints (*dof_handler, constraints);
    VectorTools::interpolate_boundary_values (*dof_handler,
                                              0,
                                              ZeroFunction<dim>(),
                                              constraints);
    constraints.close ();

    DynamicSparsityPattern csp (locally_relevant_dofs);

    DoFTools::make_sparsity_pattern (*dof_handler, csp,
                                     constraints, false);
    SparsityTools::distribute_sparsity_pattern (csp,
                                                dof_handler->n_locally_owned_dofs_per_processor(),
                                                mpi_communicator,
                                                locally_relevant_dofs);

    system_matrix.reinit (locally_owned_dofs,
                          locally_owned_dofs,
                          csp,
                          mpi_communicator);
  }

  template <int dim>
  void LaplaceProblem<dim>::assemble_system ()
  {
    TimerOutput::Scope t(computing_timer, "assembly");

    const QGauss<dim>  quadrature_formula(3);

    FEValues<dim> fe_values (*fe, quadrature_formula,
                             update_values    |  update_gradients |
                             update_quadrature_points |
                             update_JxW_values);

    const unsigned int   dofs_per_cell = fe->dofs_per_cell;
    const unsigned int   n_q_points    = quadrature_formula.size();

    FullMatrix<double>   cell_matrix (dofs_per_cell, dofs_per_cell);
    Vector<double>       cell_rhs (dofs_per_cell);

    std::vector<types::global_dof_index> local_dof_indices (dofs_per_cell);

    typename DoFHandler<dim>::active_cell_iterator
    cell = dof_handler->begin_active(),
    endc = dof_handler->end();
    for (; cell!=endc; ++cell)
      if (cell->is_locally_owned())
        {
          cell_matrix = 0;
          cell_rhs = 0;

          fe_values.reinit (cell);

          for (unsigned int q_point=0; q_point<n_q_points; ++q_point)
            {
              const double
              rhs_value
                = (fe_values.quadrature_point(q_point)[1]
                   >
                   0.5+0.25*std::sin(4.0 * numbers::PI *
                                     fe_values.quadrature_point(q_point)[0])
                   ? 1 : -1);

              for (unsigned int i=0; i<dofs_per_cell; ++i)
                {
                  for (unsigned int j=0; j<dofs_per_cell; ++j)
                    cell_matrix(i,j) += (fe_values.shape_grad(i,q_point) *
                                         fe_values.shape_grad(j,q_point) *
                                         fe_values.JxW(q_point));

                  cell_rhs(i) += (rhs_value *
                                  fe_values.shape_value(i,q_point) *
                                  fe_values.JxW(q_point));
                }
            }

          cell->get_dof_indices (local_dof_indices);
          constraints.distribute_local_to_global (cell_matrix,
                                                  cell_rhs,
                                                  local_dof_indices,
                                                  system_matrix,
                                                  system_rhs);
        }

    system_matrix.compress (VectorOperation::add);
    system_rhs.compress (VectorOperation::add);
  }

  template <int dim>
  void LaplaceProblem<dim>::solve ()
  {
    TimerOutput::Scope t(computing_timer, "solve");
    LA::MPI::Vector
    completely_distributed_solution (locally_owned_dofs, mpi_communicator);

    SolverControl solver_control (dof_handler->n_dofs(), 1e-12);

    LA::SolverCG solver(solver_control, mpi_communicator);
    LA::MPI::PreconditionAMG preconditioner;

    LA::MPI::PreconditionAMG::AdditionalData data;

#ifdef USE_PETSC_LA
    data.symmetric_operator = true;
#else
    /* Trilinos defaults are good */
#endif
    preconditioner.initialize(system_matrix, data);

    solver.solve (system_matrix, completely_distributed_solution, system_rhs,
                  preconditioner);

    pcout << "   Solved in " << solver_control.last_step()
          << " iterations." << std::endl;

    constraints.distribute (completely_distributed_solution);

    locally_relevant_solution = completely_distributed_solution;
  }

  template <int dim>
  void LaplaceProblem<dim>::refine_grid ()
  {
    TimerOutput::Scope t(computing_timer, "refine");

    Vector<float> estimated_error_per_cell (triangulation->n_active_cells());
    KellyErrorEstimator<dim>::estimate (*dof_handler,
                                        QGauss<dim-1>(3),
                                        typename FunctionMap<dim>::type(),
                                        locally_relevant_solution,
                                        estimated_error_per_cell);
    parallel::distributed::GridRefinement::
    refine_and_coarsen_fixed_number (*triangulation,
                                     estimated_error_per_cell,
                                     0.3, 0.03);
    triangulation->execute_coarsening_and_refinement ();
  }

  template <int dim>
  void LaplaceProblem<dim>::output_results (const unsigned int cycle) const
  {
    DataOut<dim> data_out;
    data_out.attach_dof_handler (*dof_handler);
    data_out.add_data_vector (locally_relevant_solution, "u");

    Vector<float> subdomain (triangulation->n_active_cells());
    for (unsigned int i=0; i<subdomain.size(); ++i)
      subdomain(i) = triangulation->locally_owned_subdomain();
    data_out.add_data_vector (subdomain, "subdomain");

    data_out.build_patches ();

    const std::string filename = ("solution-" +
                                  Utilities::int_to_string (cycle, 2) +
                                  "." +
                                  Utilities::int_to_string
                                  (triangulation->locally_owned_subdomain(), 4));
    std::ofstream output ((filename + ".vtu").c_str());
    data_out.write_vtu (output);

    if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0)
      {
        std::vector<std::string> filenames;
        for (unsigned int i=0;
             i<Utilities::MPI::n_mpi_processes(mpi_communicator);
             ++i)
          filenames.push_back ("solution-" +
                               Utilities::int_to_string (cycle, 2) +
                               "." +
                               Utilities::int_to_string (i, 4) +
                               ".vtu");

        std::ofstream master_output ((filename + ".pvtu").c_str());
        data_out.write_pvtu_record (master_output, filenames);
      }
  }

  template<int dim>
  void LaplaceProblem<dim>::make_grid_fe ()
  {
    // triangulation =*triangulation (mpi_communicator,
    //                typename Triangulation<dim>::MeshSmoothing
    //                (Triangulation<dim>::smoothing_on_refinement |
    //                 Triangulation<dim>::smoothing_on_coarsening)),

    ParsedGridGenerator<dim,dim> pgg("Cube");

    ParsedFiniteElement<dim,dim> fe_builder("FE_Q");

    ParameterAcceptor::initialize("params.prm");

    triangulation = pgg.distributed(mpi_communicator);

    dof_handler = new DoFHandler<dim>(*triangulation);
    //GridGenerator::hyper_cube (triangulation, -1, 1);

    std::cout << "Number of active cells: "
              << triangulation->n_active_cells()
              << std::endl;

    fe=fe_builder();

  }

  template <int dim>
  void LaplaceProblem<dim>::run ()
  {
    const unsigned int n_cycles = 8;
    make_grid_fe();
    for (unsigned int cycle=0; cycle<n_cycles; ++cycle)
      {
        pcout << "Cycle " << cycle << ':' << std::endl;

        if (cycle != 0)
          refine_grid ();

        setup_system ();

        pcout << "   Number of active cells:       "
              << triangulation->n_global_active_cells()
              << std::endl
              << "   Number of degrees of freedom: "
              << dof_handler->n_dofs()
              << std::endl;

        assemble_system ();
        solve ();

        if (Utilities::MPI::n_mpi_processes(mpi_communicator) <= 32)
          {
            TimerOutput::Scope t(computing_timer, "output");
            output_results (cycle);
          }

        computing_timer.print_summary ();
        computing_timer.reset ();

        pcout << std::endl;
      }
  }
}

int main(int argc, char *argv[])
{
  try
    {
      using namespace dealii;
      using namespace ParallelLaplace;

      Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1);
      deallog.depth_console (0);

      {
        LaplaceProblem<2> laplace_problem_2d;
        laplace_problem_2d.run ();
      }
    }
  catch (std::exception &exc)
    {
      std::cerr << std::endl << std::endl
                << "----------------------------------------------------"
                << std::endl;
      std::cerr << "Exception on processing: " << std::endl
                << exc.what() << std::endl
                << "Aborting!" << std::endl
                << "----------------------------------------------------"
                << std::endl;

      return 1;
    }
  catch (...)
    {
      std::cerr << std::endl << std::endl
                << "----------------------------------------------------"
                << std::endl;
      std::cerr << "Unknown exception!" << std::endl
                << "Aborting!" << std::endl
                << "----------------------------------------------------"
                << std::endl;
      return 1;
    }

  return 0;
}

#else
int main() {
  return 0;
}
#endif
<commit_msg>fixed indentation.<commit_after>/* ---------------------------------------------------------------------
 *
 * Copyright (C) 2009 - 2014 by the deal.II authors
 *
 * This file is part of the deal.II library.
 *
 * The deal.II library is free software; you can use it, redistribute
 * it, and/or modify it under the terms of the GNU Lesser General
 * Public License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * The full text of the license can be found in the file LICENSE at
 * the top level of the deal.II distribution.
 *
 * ---------------------------------------------------------------------

 *
 * Author: Wolfgang Bangerth, Texas A&M University, 2009, 2010
 *         Timo Heister, University of Goettingen, 2009, 2010
 */

#include <deal.II/base/config.h>
#include <deal.II/base/quadrature_lib.h>
#include <deal.II/base/function.h>
#include <deal.II/base/timer.h>

#ifdef DEAL_II_WITH_MPI

#include <deal.II/lac/generic_linear_algebra.h>

#define USE_PETSC_LA

namespace LA
{
#ifdef USE_PETSC_LA
  using namespace dealii::LinearAlgebraPETSc;
#else
  using namespace dealii::LinearAlgebraTrilinos;
#endif
}

#include <deal.II/lac/vector.h>
#include <deal.II/lac/full_matrix.h>
#include <deal.II/lac/solver_cg.h>
#include <deal.II/lac/constraint_matrix.h>
#include <deal.II/lac/compressed_simple_sparsity_pattern.h>

#include <deal.II/lac/petsc_parallel_sparse_matrix.h>
#include <deal.II/lac/petsc_parallel_vector.h>
#include <deal.II/lac/petsc_solver.h>
#include <deal.II/lac/petsc_precondition.h>

#include <deal.II/grid/grid_generator.h>
#include <deal.II/grid/tria_accessor.h>
#include <deal.II/grid/tria_iterator.h>
#include <deal.II/dofs/dof_handler.h>
#include <deal.II/dofs/dof_accessor.h>
#include <deal.II/dofs/dof_tools.h>
#include <deal.II/fe/fe_values.h>
#include <deal.II/fe/fe_q.h>
#include <deal.II/numerics/vector_tools.h>
#include <deal.II/numerics/data_out.h>
#include <deal.II/numerics/error_estimator.h>

#include <deal.II/base/utilities.h>
#include <deal.II/base/conditional_ostream.h>
#include <deal.II/base/index_set.h>
#include <deal.II/lac/sparsity_tools.h>
#include <deal.II/distributed/tria.h>
#include <deal.II/distributed/grid_refinement.h>

#include <fstream>
#include <iostream>

#include "parsed_grid_generator.h"
#include "parsed_finite_element.h"
#include "utilities.h"

namespace ParallelLaplace
{
  using namespace dealii;

  template <int dim>
  class LaplaceProblem
  {
  public:
    LaplaceProblem ();
    ~LaplaceProblem ();

    void run ();

  private:
    void setup_system ();
    void assemble_system ();
    void solve ();
    void refine_grid ();
    void output_results (const unsigned int cycle) const;
    void make_grid_fe();

    MPI_Comm                                  mpi_communicator;

    SmartPointer<parallel::distributed::Triangulation<dim> > triangulation;

    SmartPointer<DoFHandler<dim> >                           dof_handler;
    SmartPointer<FiniteElement<dim,dim> >                               fe;

    IndexSet                                  locally_owned_dofs;
    IndexSet                                  locally_relevant_dofs;

    ConstraintMatrix                          constraints;

    LA::MPI::SparseMatrix system_matrix;
    LA::MPI::Vector locally_relevant_solution;
    LA::MPI::Vector system_rhs;

    ConditionalOStream                        pcout;
    TimerOutput                               computing_timer;
  };

  template <int dim>
  LaplaceProblem<dim>::LaplaceProblem ()
    :
    mpi_communicator (MPI_COMM_WORLD),
    pcout (std::cout,
           (Utilities::MPI::this_mpi_process(mpi_communicator)
            == 0)),
    computing_timer (mpi_communicator,
                     pcout,
                     TimerOutput::summary,
                     TimerOutput::wall_times)
  {}

  template <int dim>
  LaplaceProblem<dim>::~LaplaceProblem ()
  {
    dof_handler->clear ();
    smart_delete(dof_handler);
    smart_delete(fe);
    smart_delete(triangulation);
  }

  template <int dim>
  void LaplaceProblem<dim>::setup_system ()
  {
    TimerOutput::Scope t(computing_timer, "setup");

    dof_handler->distribute_dofs (*fe);

    locally_owned_dofs = dof_handler->locally_owned_dofs ();
    DoFTools::extract_locally_relevant_dofs (*dof_handler,
                                             locally_relevant_dofs);

    locally_relevant_solution.reinit (locally_owned_dofs,
                                      locally_relevant_dofs, mpi_communicator);
    system_rhs.reinit (locally_owned_dofs, mpi_communicator);

    constraints.clear ();
    constraints.reinit (locally_relevant_dofs);
    DoFTools::make_hanging_node_constraints (*dof_handler, constraints);
    VectorTools::interpolate_boundary_values (*dof_handler,
                                              0,
                                              ZeroFunction<dim>(),
                                              constraints);
    constraints.close ();

    DynamicSparsityPattern csp (locally_relevant_dofs);

    DoFTools::make_sparsity_pattern (*dof_handler, csp,
                                     constraints, false);
    SparsityTools::distribute_sparsity_pattern (csp,
                                                dof_handler->n_locally_owned_dofs_per_processor(),
                                                mpi_communicator,
                                                locally_relevant_dofs);

    system_matrix.reinit (locally_owned_dofs,
                          locally_owned_dofs,
                          csp,
                          mpi_communicator);
  }

  template <int dim>
  void LaplaceProblem<dim>::assemble_system ()
  {
    TimerOutput::Scope t(computing_timer, "assembly");

    const QGauss<dim>  quadrature_formula(3);

    FEValues<dim> fe_values (*fe, quadrature_formula,
                             update_values    |  update_gradients |
                             update_quadrature_points |
                             update_JxW_values);

    const unsigned int   dofs_per_cell = fe->dofs_per_cell;
    const unsigned int   n_q_points    = quadrature_formula.size();

    FullMatrix<double>   cell_matrix (dofs_per_cell, dofs_per_cell);
    Vector<double>       cell_rhs (dofs_per_cell);

    std::vector<types::global_dof_index> local_dof_indices (dofs_per_cell);

    typename DoFHandler<dim>::active_cell_iterator
    cell = dof_handler->begin_active(),
    endc = dof_handler->end();
    for (; cell!=endc; ++cell)
      if (cell->is_locally_owned())
        {
          cell_matrix = 0;
          cell_rhs = 0;

          fe_values.reinit (cell);

          for (unsigned int q_point=0; q_point<n_q_points; ++q_point)
            {
              const double
              rhs_value
                = (fe_values.quadrature_point(q_point)[1]
                   >
                   0.5+0.25*std::sin(4.0 * numbers::PI *
                                     fe_values.quadrature_point(q_point)[0])
                   ? 1 : -1);

              for (unsigned int i=0; i<dofs_per_cell; ++i)
                {
                  for (unsigned int j=0; j<dofs_per_cell; ++j)
                    cell_matrix(i,j) += (fe_values.shape_grad(i,q_point) *
                                         fe_values.shape_grad(j,q_point) *
                                         fe_values.JxW(q_point));

                  cell_rhs(i) += (rhs_value *
                                  fe_values.shape_value(i,q_point) *
                                  fe_values.JxW(q_point));
                }
            }

          cell->get_dof_indices (local_dof_indices);
          constraints.distribute_local_to_global (cell_matrix,
                                                  cell_rhs,
                                                  local_dof_indices,
                                                  system_matrix,
                                                  system_rhs);
        }

    system_matrix.compress (VectorOperation::add);
    system_rhs.compress (VectorOperation::add);
  }

  template <int dim>
  void LaplaceProblem<dim>::solve ()
  {
    TimerOutput::Scope t(computing_timer, "solve");
    LA::MPI::Vector
    completely_distributed_solution (locally_owned_dofs, mpi_communicator);

    SolverControl solver_control (dof_handler->n_dofs(), 1e-12);

    LA::SolverCG solver(solver_control, mpi_communicator);
    LA::MPI::PreconditionAMG preconditioner;

    LA::MPI::PreconditionAMG::AdditionalData data;

#ifdef USE_PETSC_LA
    data.symmetric_operator = true;
#else
    /* Trilinos defaults are good */
#endif
    preconditioner.initialize(system_matrix, data);

    solver.solve (system_matrix, completely_distributed_solution, system_rhs,
                  preconditioner);

    pcout << "   Solved in " << solver_control.last_step()
          << " iterations." << std::endl;

    constraints.distribute (completely_distributed_solution);

    locally_relevant_solution = completely_distributed_solution;
  }

  template <int dim>
  void LaplaceProblem<dim>::refine_grid ()
  {
    TimerOutput::Scope t(computing_timer, "refine");

    Vector<float> estimated_error_per_cell (triangulation->n_active_cells());
    KellyErrorEstimator<dim>::estimate (*dof_handler,
                                        QGauss<dim-1>(3),
                                        typename FunctionMap<dim>::type(),
                                        locally_relevant_solution,
                                        estimated_error_per_cell);
    parallel::distributed::GridRefinement::
    refine_and_coarsen_fixed_number (*triangulation,
                                     estimated_error_per_cell,
                                     0.3, 0.03);
    triangulation->execute_coarsening_and_refinement ();
  }

  template <int dim>
  void LaplaceProblem<dim>::output_results (const unsigned int cycle) const
  {
    DataOut<dim> data_out;
    data_out.attach_dof_handler (*dof_handler);
    data_out.add_data_vector (locally_relevant_solution, "u");

    Vector<float> subdomain (triangulation->n_active_cells());
    for (unsigned int i=0; i<subdomain.size(); ++i)
      subdomain(i) = triangulation->locally_owned_subdomain();
    data_out.add_data_vector (subdomain, "subdomain");

    data_out.build_patches ();

    const std::string filename = ("solution-" +
                                  Utilities::int_to_string (cycle, 2) +
                                  "." +
                                  Utilities::int_to_string
                                  (triangulation->locally_owned_subdomain(), 4));
    std::ofstream output ((filename + ".vtu").c_str());
    data_out.write_vtu (output);

    if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0)
      {
        std::vector<std::string> filenames;
        for (unsigned int i=0;
             i<Utilities::MPI::n_mpi_processes(mpi_communicator);
             ++i)
          filenames.push_back ("solution-" +
                               Utilities::int_to_string (cycle, 2) +
                               "." +
                               Utilities::int_to_string (i, 4) +
                               ".vtu");

        std::ofstream master_output ((filename + ".pvtu").c_str());
        data_out.write_pvtu_record (master_output, filenames);
      }
  }

  template<int dim>
  void LaplaceProblem<dim>::make_grid_fe ()
  {
    // triangulation =*triangulation (mpi_communicator,
    //                typename Triangulation<dim>::MeshSmoothing
    //                (Triangulation<dim>::smoothing_on_refinement |
    //                 Triangulation<dim>::smoothing_on_coarsening)),

    ParsedGridGenerator<dim,dim> pgg("Cube");

    ParsedFiniteElement<dim,dim> fe_builder("FE_Q");

    ParameterAcceptor::initialize("params.prm");

    triangulation = pgg.distributed(mpi_communicator);

    dof_handler = new DoFHandler<dim>(*triangulation);
    //GridGenerator::hyper_cube (triangulation, -1, 1);

    std::cout << "Number of active cells: "
              << triangulation->n_active_cells()
              << std::endl;

    fe=fe_builder();

  }

  template <int dim>
  void LaplaceProblem<dim>::run ()
  {
    const unsigned int n_cycles = 8;
    make_grid_fe();
    for (unsigned int cycle=0; cycle<n_cycles; ++cycle)
      {
        pcout << "Cycle " << cycle << ':' << std::endl;

        if (cycle != 0)
          refine_grid ();

        setup_system ();

        pcout << "   Number of active cells:       "
              << triangulation->n_global_active_cells()
              << std::endl
              << "   Number of degrees of freedom: "
              << dof_handler->n_dofs()
              << std::endl;

        assemble_system ();
        solve ();

        if (Utilities::MPI::n_mpi_processes(mpi_communicator) <= 32)
          {
            TimerOutput::Scope t(computing_timer, "output");
            output_results (cycle);
          }

        computing_timer.print_summary ();
        computing_timer.reset ();

        pcout << std::endl;
      }
  }
}

int main(int argc, char *argv[])
{
  try
    {
      using namespace dealii;
      using namespace ParallelLaplace;

      Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1);
      deallog.depth_console (0);

      {
        LaplaceProblem<2> laplace_problem_2d;
        laplace_problem_2d.run ();
      }
    }
  catch (std::exception &exc)
    {
      std::cerr << std::endl << std::endl
                << "----------------------------------------------------"
                << std::endl;
      std::cerr << "Exception on processing: " << std::endl
                << exc.what() << std::endl
                << "Aborting!" << std::endl
                << "----------------------------------------------------"
                << std::endl;

      return 1;
    }
  catch (...)
    {
      std::cerr << std::endl << std::endl
                << "----------------------------------------------------"
                << std::endl;
      std::cerr << "Unknown exception!" << std::endl
                << "Aborting!" << std::endl
                << "----------------------------------------------------"
                << std::endl;
      return 1;
    }

  return 0;
}

#else
int main()
{
  return 0;
}
#endif
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 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 Kaveh Vahedipour
////////////////////////////////////////////////////////////////////////////////

#include "Store.h"

#include <velocypack/Buffer.h>
#include <velocypack/Iterator.h>
#include <velocypack/velocypack-aliases.h>

#include <iostream>

using namespace arangodb::consensus;

struct NotEmpty {
  bool operator()(const std::string& s) { return !s.empty(); }
};
struct Empty {
  bool operator()(const std::string& s) { return s.empty(); }
};

std::vector<std::string> split(const std::string& value, char separator) {
  std::vector<std::string> result;
  std::string::size_type p = (value.find(separator) == 0) ? 1:0;
  std::string::size_type q;
  while ((q = value.find(separator, p)) != std::string::npos) {
    result.emplace_back(value, p, q - p);
    p = q + 1;
  }
  result.emplace_back(value, p);
  result.erase(std::find_if(result.rbegin(), result.rend(),
                            NotEmpty()).base(), result.end());
  return result;
}

Node::Node (std::string const& name) : _parent(nullptr), _name(name) {
  _value.clear();
}
Node::Node (std::string const& name, Node const* parent) :
  _parent(parent), _name(name) {
  _value.clear();
}

Node::~Node() {}

Slice Node::slice() const {
  return (_value.size()==0) ?
    Slice("\x018",&Options::Defaults):Slice(_value.data());
}

std::string const& Node::name() const {return _name;}

Node& Node::operator= (Slice const& slice) { // Assign value (become leaf)
  _children.clear();
  _value.reset();
  _value.append(reinterpret_cast<char const*>(slice.begin()), slice.byteSize());
  return *this;
}

Node& Node::operator= (Node const& node) { // Assign node
  _name = node._name;
  _type = node._type;
  _value = node._value;
  _children = node._children;
  _ttl = node._ttl;
  return *this;
}

bool Node::operator== (arangodb::velocypack::Slice const& rhs) const {
  return rhs.equals(slice());
}

/*Node& Node::parent () {
  return *_parent;
  }

Node const& Node::parent () const {
  return *_parent;
  }*/

bool Node::remove (std::string const& path) {
  std::vector<std::string> pv = split(path, '/');
  std::string key(pv.back());
  pv.pop_back();
  try {
    Node& parent = (*this)(pv);

    return parent.removeChild(key);
  } catch (StoreException const& e) {
    return false;
  }
}

bool Node::removeChild (std::string const& key) {
  auto found = _children.find(key);
  if (found == _children.end())
    return false;
  else
    _children.erase(found);
  return true;
}

NodeType Node::type() const {return _children.size() ? NODE : LEAF;}

Node& Node::operator [](std::string name) {
  return *_children[name];
}

bool Node::append (std::string const name, std::shared_ptr<Node> const node) {
  if (node != nullptr) {
    _children[name] = node;
  } else {
    _children[name] = std::make_shared<Node>(name);
  }
  _children[name]->_parent = this;
  return true;
}

Node& Node::operator ()(std::vector<std::string>& pv) {
  if (pv.size()) {
    std::string const key = pv[0];
    if (_children.find(key) == _children.end()) {
      _children[key] = std::make_shared<Node>(pv[0], this);
    }
    pv.erase(pv.begin());
    return (*_children[key])(pv);
  } else {
    return *this;
  }
}

Node const& Node::operator ()(std::vector<std::string>& pv) const {
  if (pv.size()) {
    std::string const key = pv[0];
    pv.erase(pv.begin());
    if (_children.find(key) == _children.end()) {
      throw StoreException("Not found");
    }
    const Node& child = *_children.at(key);
    return child(pv);
  } else {
    return *this;
  }
}

Node const& Node::operator ()(std::string const& path) const {
  PathType pv = split(path,'/');
  return this->operator()(pv);
}

Node& Node::operator ()(std::string const& path) {
  PathType pv = split(path,'/');
  return this->operator()(pv);
}

Node const& Node::read (std::string const& path) const {
  PathType pv = split(path,'/');
  return this->operator()(pv);
}

Node& Node::write (std::string const& path) {
  PathType pv = split(path,'/');
  return this->operator()(pv);
}

bool Node::apply (arangodb::velocypack::Slice const& slice) {
  if (slice.type() == ValueType::Object) {
    for (auto const& i : VPackObjectIterator(slice)) {
      std::string key = i.key.toString();
      key = key.substr(1,key.length()-2);
      auto found = _children.find(key);
      if (found == _children.end()) {
        _children[key] = std::make_shared<Node>(key, this);
      }
      _children[key]->apply(i.value);
    }
  } else {
    *this = slice;
  }
  return true;
}

void Node::toBuilder (Builder& builder) const {
  try {
    if (type()==NODE) {
      VPackObjectBuilder guard(&builder);
      for (auto const& child : _children) {
        builder.add(VPackValue(child.first));
        child.second->toBuilder(builder);
      }
    } else {
      builder.add(slice());
    }
  } catch (std::exception const& e) {
    std::cout << e.what() << std::endl;
  }
}

Store::Store (std::string const& name) : Node(name) {}
Store::~Store () {}

std::vector<bool> Store::apply (query_t const& query) {
  std::vector<bool> applied;
  std::vector<std::string> path;
  MUTEX_LOCKER(storeLocker, _storeLock);
  for (auto const& i : VPackArrayIterator(query->slice())) {
    switch (i.length()) {
    case 1:
      applied.push_back(this->apply(i[0])); break; // no precond
    case 2:
      if (check(i[1])) {
        applied.push_back(this->apply(i[0]));      // precondition
      } else {
        LOG(WARN) << "Precondition failed!";
        applied.push_back(false);
      }
      break;
    default:                                 // wrong
      LOG(FATAL) << "We can only handle log entry with or without precondition!";
      applied.push_back(false);
      break;
    }
  }
  return applied;
}

bool Store::apply (arangodb::velocypack::Slice const& slice) {
  return Node::apply(slice);
}

Node const& Store::read (std::string const& path) const {
  return Node::read(path);
}

bool Store::check (arangodb::velocypack::Slice const& slice) const {
  if (slice.type() != VPackValueType::Object) {
    LOG(WARN) << "Cannot check precondition: " << slice.toJson();
    return false;
  }
  for (auto const& precond : VPackObjectIterator(slice)) {
    std::string path = precond.key.toString();
    path = path.substr(1,path.size()-2);
    if (precond.value.type() == VPackValueType::Object) { //"old", "oldEmpty", "isArray"
      for (auto const& op : VPackObjectIterator(precond.value)) {
        std::string const& oper = op.key.copyString();
        if (oper == "old") {
          return (*this)(path) == op.value;
        } else if ("oldEmpty") {

        }
      }

    } else {

    }
  }
  //

  return true;
}

query_t Store::read (query_t const& queries) const { // list of list of paths
  MUTEX_LOCKER(storeLocker, _storeLock);
  query_t result = std::make_shared<arangodb::velocypack::Builder>();
  if (queries->slice().type() == VPackValueType::Array) {
    result->add(VPackValue(VPackValueType::Array)); // top node array
    for (auto const& query : VPackArrayIterator(queries->slice())) {
      read (query, *result);
    }
    result->close();
  } else {
    LOG(FATAL) << "Read queries to stores must be arrays";
  }
  return result;
}

bool Store::read (arangodb::velocypack::Slice const& query, Builder& ret) const {

  // Collect all paths
  std::list<std::string> query_strs;
  if (query.type() == VPackValueType::Array) {
    for (auto const& sub_query : VPackArrayIterator(query))
      query_strs.push_back(sub_query.copyString());
  } else if (query.type() == VPackValueType::String) {
    query_strs.push_back(query.copyString());
  } else {
    return false;
  }
  query_strs.sort();     // sort paths

  // Remove double ranges (inclusion / identity)
  for (auto i = query_strs.begin(), j = i; i != query_strs.end(); ++i) {
    if (i!=j && i->compare(0,j->size(),*j)==0) {
      *i="";
    } else {
      j = i;
    }
  }
  auto cut = std::remove_if(query_strs.begin(), query_strs.end(), Empty());
  query_strs.erase (cut,query_strs.end());

  // Create response tree
  Node copy("copy");
  for (auto i = query_strs.begin(); i != query_strs.end(); ++i) {
    try {
      copy(*i) = (*this)(*i);
    } catch (StoreException const&) {}
  }
  // Assemble builder from response tree
  if (query_strs.size() == 1 && copy(*query_strs.begin()).type() == LEAF) {
    ret.add(copy(*query_strs.begin()).slice());
  } else {
    copy.toBuilder(ret);
  }

  return true;
}

<commit_msg>correct const/non const iterations in operator() for Store<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 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 Kaveh Vahedipour
////////////////////////////////////////////////////////////////////////////////

#include "Store.h"

#include <velocypack/Buffer.h>
#include <velocypack/Iterator.h>
#include <velocypack/velocypack-aliases.h>

#include <iostream>

using namespace arangodb::consensus;

struct NotEmpty {
  bool operator()(const std::string& s) { return !s.empty(); }
};
struct Empty {
  bool operator()(const std::string& s) { return s.empty(); }
};

std::vector<std::string> split(const std::string& value, char separator) {
  std::vector<std::string> result;
  std::string::size_type p = (value.find(separator) == 0) ? 1:0;
  std::string::size_type q;
  while ((q = value.find(separator, p)) != std::string::npos) {
    result.emplace_back(value, p, q - p);
    p = q + 1;
  }
  result.emplace_back(value, p);
  result.erase(std::find_if(result.rbegin(), result.rend(),
                            NotEmpty()).base(), result.end());
  return result;
}

Node::Node (std::string const& name) : _parent(nullptr), _name(name) {
  _value.clear();
}
Node::Node (std::string const& name, Node const* parent) :
  _parent(parent), _name(name) {
  _value.clear();
}

Node::~Node() {}

Slice Node::slice() const {
  return (_value.size()==0) ?
    Slice("\x018",&Options::Defaults):Slice(_value.data());
}

std::string const& Node::name() const {return _name;}

Node& Node::operator= (Slice const& slice) { // Assign value (become leaf)
  _children.clear();
  _value.reset();
  _value.append(reinterpret_cast<char const*>(slice.begin()), slice.byteSize());
  return *this;
}

Node& Node::operator= (Node const& node) { // Assign node
  _name = node._name;
  _type = node._type;
  _value = node._value;
  _children = node._children;
  _ttl = node._ttl;
  return *this;
}

bool Node::operator== (arangodb::velocypack::Slice const& rhs) const {
  return rhs.equals(slice());
}

/*Node& Node::parent () {
  return *_parent;
  }

Node const& Node::parent () const {
  return *_parent;
  }*/

bool Node::remove (std::string const& path) {
  std::vector<std::string> pv = split(path, '/');
  std::string key(pv.back());
  pv.pop_back();
  try {
    Node& parent = (*this)(pv);

    return parent.removeChild(key);
  } catch (StoreException const& e) {
    return false;
  }
}

bool Node::removeChild (std::string const& key) {
  auto found = _children.find(key);
  if (found == _children.end())
    return false;
  else
    _children.erase(found);
  return true;
}

NodeType Node::type() const {return _children.size() ? NODE : LEAF;}

Node& Node::operator [](std::string name) {
  return *_children[name];
}

bool Node::append (std::string const name, std::shared_ptr<Node> const node) {
  if (node != nullptr) {
    _children[name] = node;
  } else {
    _children[name] = std::make_shared<Node>(name);
  }
  _children[name]->_parent = this;
  return true;
}

Node& Node::operator ()(std::vector<std::string>& pv) {
  if (pv.size()) {
    std::string const key = pv[0];
    if (_children.find(key) == _children.end()) {
      _children[key] = std::make_shared<Node>(pv[0], this);
    }
    pv.erase(pv.begin());
    return (*_children[key])(pv);
  } else {
    return *this;
  }
}

Node const& Node::operator ()(std::vector<std::string>& pv) const {
  if (pv.size()) {
    std::string const key = pv[0];
    pv.erase(pv.begin());
    if (_children.find(key) == _children.end()) {
      throw StoreException("Not found");
    }
    const Node& child = *_children.at(key);
    return child(pv);
  } else {
    return *this;
  }
}

Node const& Node::operator ()(std::string const& path) const {
  PathType pv = split(path,'/');
  return this->operator()(pv);
}

Node& Node::operator ()(std::string const& path) {
  PathType pv = split(path,'/');
  return this->operator()(pv);
}

Node const& Node::read (std::string const& path) const {
  PathType pv = split(path,'/');
  return this->operator()(pv);
}

Node& Node::write (std::string const& path) {
  PathType pv = split(path,'/');
  return this->operator()(pv);
}

bool Node::apply (arangodb::velocypack::Slice const& slice) {
  if (slice.type() == ValueType::Object) {
    for (auto const& i : VPackObjectIterator(slice)) {
      std::string key = i.key.toString();
      key = key.substr(1,key.length()-2);
      auto found = _children.find(key);
      if (found == _children.end()) {
        _children[key] = std::make_shared<Node>(key, this);
      }
      _children[key]->apply(i.value);
    }
  } else {
    *this = slice;
  }
  return true;
}

void Node::toBuilder (Builder& builder) const {
  try {
    if (type()==NODE) {
      VPackObjectBuilder guard(&builder);
      for (auto const& child : _children) {
        builder.add(VPackValue(child.first));
        child.second->toBuilder(builder);
      }
    } else {
      builder.add(slice());
    }
  } catch (std::exception const& e) {
    std::cout << e.what() << std::endl;
  }
}

Store::Store (std::string const& name) : Node(name) {}
Store::~Store () {}

std::vector<bool> Store::apply (query_t const& query) {
  std::vector<bool> applied;
  std::vector<std::string> path;
  MUTEX_LOCKER(storeLocker, _storeLock);
  for (auto const& i : VPackArrayIterator(query->slice())) {
    switch (i.length()) {
    case 1:
      applied.push_back(this->apply(i[0])); break; // no precond
    case 2:
      if (check(i[1])) {
        applied.push_back(this->apply(i[0]));      // precondition
      } else {
        LOG(WARN) << "Precondition failed!";
        applied.push_back(false);
      }
      break;
    default:                                 // wrong
      LOG(FATAL) << "We can only handle log entry with or without precondition!";
      applied.push_back(false);
      break;
    }
  }
  return applied;
}

bool Store::apply (arangodb::velocypack::Slice const& slice) {
  return Node::apply(slice);
}

Node const& Store::read (std::string const& path) const {
  return Node::read(path);
}

bool Store::check (arangodb::velocypack::Slice const& slice) const {
  if (slice.type() != VPackValueType::Object) {
    LOG(WARN) << "Cannot check precondition: " << slice.toJson();
    return false;
  }
  for (auto const& precond : VPackObjectIterator(slice)) {
    std::string path = precond.key.toString();
    path = path.substr(1,path.size()-2);
    if (precond.value.type() == VPackValueType::Object) { //"old", "oldEmpty", "isArray"
      for (auto const& op : VPackObjectIterator(precond.value)) {
        std::string const& oper = op.key.copyString();
        Node const& node = (*this)(path);
        if (oper == "old") {
          return (node == op.value);
        } else if ("isArray") {
          if (op.value.type()!=VPackValueType::Bool) {
            return false;
          }
          bool isArray =
            (node.type() == LEAF &&
             node.slice().type() == VPackValueType::Array);
          return op.value.getBool() ? isArray : !isArray;
        }
      }

    } else {

    }
  }
  //

  return true;
}

query_t Store::read (query_t const& queries) const { // list of list of paths
  MUTEX_LOCKER(storeLocker, _storeLock);
  query_t result = std::make_shared<arangodb::velocypack::Builder>();
  if (queries->slice().type() == VPackValueType::Array) {
    result->add(VPackValue(VPackValueType::Array)); // top node array
    for (auto const& query : VPackArrayIterator(queries->slice())) {
      read (query, *result);
    }
    result->close();
  } else {
    LOG(FATAL) << "Read queries to stores must be arrays";
  }
  return result;
}

bool Store::read (arangodb::velocypack::Slice const& query, Builder& ret) const {

  // Collect all paths
  std::list<std::string> query_strs;
  if (query.type() == VPackValueType::Array) {
    for (auto const& sub_query : VPackArrayIterator(query))
      query_strs.push_back(sub_query.copyString());
  } else if (query.type() == VPackValueType::String) {
    query_strs.push_back(query.copyString());
  } else {
    return false;
  }
  query_strs.sort();     // sort paths

  // Remove double ranges (inclusion / identity)
  for (auto i = query_strs.begin(), j = i; i != query_strs.end(); ++i) {
    if (i!=j && i->compare(0,j->size(),*j)==0) {
      *i="";
    } else {
      j = i;
    }
  }
  auto cut = std::remove_if(query_strs.begin(), query_strs.end(), Empty());
  query_strs.erase (cut,query_strs.end());

  // Create response tree
  Node copy("copy");
  for (auto i = query_strs.begin(); i != query_strs.end(); ++i) {
    try {
      copy(*i) = (*this)(*i);
    } catch (StoreException const&) {}
  }
  // Assemble builder from response tree
  if (query_strs.size() == 1 && copy(*query_strs.begin()).type() == LEAF) {
    ret.add(copy(*query_strs.begin()).slice());
  } else {
    copy.toBuilder(ret);
  }

  return true;
}

<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <iostream>
#include <typeinfo>
#include <exception>

#include "json.h"

using namespace std;

JsonDict::JsonDict(){}

void JsonDict::add(JsonString key, JsonValue value){
    dict[(string) key] = value;
}

JsonString::JsonString(){}

JsonString::JsonString(string val){
    value = val;
}

JsonString::operator std::string() const{
    return value;
}

JsonString JsonString::operator=(const JsonString &str){
    value = str.value;
    return *this;
}

JsonValue * createList(string message, int &i){
    return new JsonValue();
}

JsonValue * createNumber(string message, int &i){
    return new JsonValue();
}

JsonValue * createValue(string message, int &i){
    i = 0;
    while(i < message.length()){
        switch(message[i]){
            case '{':
                return createDict(message.substr(i + 1, message.length()), i);
                break;
            case '[':
                return createList(message.substr(i + 1, message.length()), i);
                break;
            case '"':
                return createString(message.substr(i + 1, message.length()), i);
                break;
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                return createNumber(message.substr(i, message.length()), i);
                break;
            case '\n':
            case ' ':
                i++;
                break;
            default:
                throw 1;
        }
    }
    throw 1;
}

JsonDict * createDict(string message, int &i){
    JsonDict * r = new JsonDict();
    i = 0;
    while(1){
        JsonString * key;
        JsonValue * value;
        bool colon = false;
        bool coma = false;
        bool gotkey = false;
        while(i < message.length()){
            switch(message[i]){
                case '"':
                    key = createString(message.substr(i + 1, message.length()), i);
                    gotkey = true;
                    break;
                case '\n':
                case ' ':
                    break;
                case '}':
                    i++;
                    return r;
                    break;
                default:
                    throw 1;
            }
            if(gotkey){
                break;
            }
            i++;
        }
        i++;
        while(i < message.length() && !colon){
                switch(message[i]){
                case ':':
                    colon = true;
                    break;
                case '\n':
                case ' ':
                    break;
                default:
                    throw 1;
            }
            i++;
        }
        int bak = i;
        value = createValue(message.substr(i, message.length()), i);
        i += bak + 1;
        r->add(*key, *value);
        while(i < message.length() && !coma){
                switch(message[i]){
                case ',':
                    coma = true;
                    i++;
                    break;
                case '\n':
                case ' ':
                    break;
                case '}':
                    break;
                default:
                    throw 1;
            }
            i++;
        }
        i--;
    }
}

JsonString * createString(string message, int &i){
    int j = i;
    i = 0;
    while(i < message.length()){
        switch(message[i]){
        case '\\':
            i++;
            break;
        case '"':
            i++;
            i += j;
            return new JsonString(message.substr(0, i - 1));
            break;
        }
    i++;
    }
    throw 1;
}

int main(){
    int i = 0;
    JsonValue * val = createValue("{\"Coucou\":\"char\",\"Cocco\":\"chir ?\",\"sqdfqs\":\"qsdf ?\",\"qsd\":\"qdfqsf ?\"}", i);
    JsonDict* strptr = dynamic_cast<JsonDict*>(val);
    cout << strptr->dict.size() << endl;
    return 0;
}<commit_msg>[code/json] corrected end dico parsing (find "}").<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <iostream>
#include <typeinfo>
#include <exception>

#include "json.h"

using namespace std;

JsonDict::JsonDict(){}

void JsonDict::add(JsonString key, JsonValue value){
    dict[(string) key] = value;
}

JsonString::JsonString(){}

JsonString::JsonString(string val){
    value = val;
}

JsonString::operator std::string() const{
    return value;
}

JsonString JsonString::operator=(const JsonString &str){
    value = str.value;
    return *this;
}

JsonValue * createList(string message, int &i){
    return new JsonValue();
}

JsonValue * createNumber(string message, int &i){
    return new JsonValue();
}

JsonValue * createValue(string message, int &i){
    i = 0;
    while(i < message.length()){
        switch(message[i]){
            case '{':
                return createDict(message.substr(i + 1, message.length()), i);
                break;
            case '[':
                return createList(message.substr(i + 1, message.length()), i);
                break;
            case '"':
                return createString(message.substr(i + 1, message.length()), i);
                break;
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                return createNumber(message.substr(i, message.length()), i);
                break;
            case '\n':
            case ' ':
                i++;
                break;
            default:
                throw 1;
        }
    }
    throw 1;
}

JsonDict * createDict(string message, int &i){
    JsonDict * r = new JsonDict();
    i = 0;
    while(1){
        JsonString * key;
        JsonValue * value;
        bool colon = false;
        bool coma = false;
        bool gotkey = false;
        while(i < message.length()){
            switch(message[i]){
                case '"':
                    key = createString(message.substr(i + 1, message.length()), i);
                    gotkey = true;
                    break;
                case '\n':
                case ' ':
                    break;
                case '}':
                    i++;
                    return r;
                    break;
                default:
                    throw 1;
            }
            if(gotkey){
                break;
            }
            i++;
        }
        i++;
        while(i < message.length() && !colon){
                switch(message[i]){
                case ':':
                    colon = true;
                    break;
                case '\n':
                case ' ':
                    break;
                default:
                    throw 1;
            }
            i++;
        }
        int bak = i;
        value = createValue(message.substr(i, message.length()), i);
        i += bak + 1;
        r->add(*key, *value);
        while(i < message.length() && !coma){
                switch(message[i]){
                case ',':
                    coma = true;
                    break;
                case '\n':
                case ' ':
                    break;
                case '}':
                    i++;
                    return r;
                    break;
                default:
                    throw 1;
            }
            i++;
        }
    }
}

JsonString * createString(string message, int &i){
    int j = i;
    i = 0;
    while(i < message.length()){
        switch(message[i]){
        case '\\':
            i++;
            break;
        case '"':
            i++;
            i += j;
            return new JsonString(message.substr(0, i - 1));
            break;
        }
    i++;
    }
    throw 1;
}

int main(){
    int i = 0;
    JsonValue * val = createValue("{\"Coucou\":\"char\",\"Cocco\":\"chir ?\",\"sqdfqs\":\"qsdf ?\",\"qsd\":\"qdfqsf ?\"}", i);
    JsonDict* strptr = dynamic_cast<JsonDict*>(val);
    cout << strptr->dict.size() << endl;
    return 0;
}
<|endoftext|>