<commit_before>// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
//
// 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 <algorithm>
#include <map>
#include <numeric>
#include <vector>
#include "paddle/fluid/inference/capi/c_api.h"
#include "paddle/fluid/inference/capi/c_api_internal.h"

using paddle::ConvertToPaddleDType;
using paddle::ConvertToPDDataType;
using paddle::ConvertToACPrecision;

extern "C" {

bool PD_PredictorRun(const PD_AnalysisConfig* config, PD_Tensor* inputs,
                     int in_size, PD_Tensor* output_data, int** out_size,
                     int batch_size) {
  PADDLE_ENFORCE_NOT_NULL(config);
  auto predictor = paddle::CreatePaddlePredictor(config->config);
  std::vector<paddle::PaddleTensor> in;
  for (int i = 0; i < in_size; ++i) {
    in.emplace_back(inputs->tensor);
  }
  std::vector<paddle::PaddleTensor> out;
  if (predictor->Run(in, &out, batch_size)) {
    int osize = out.size();
    for (int i = 0; i < osize; ++i) {
      output_data[i].tensor = out[i];
    }
    *out_size = &osize;
    return true;
  }
  return false;
}

bool PD_PredictorZeroCopyRun(const PD_AnalysisConfig* config,
                             PD_ZeroCopyData* inputs, int in_size,
                             PD_ZeroCopyData** output, int** out_size) {
  PADDLE_ENFORCE_NOT_NULL(config);
  auto predictor = paddle::CreatePaddlePredictor(config->config);
  auto input_names = predictor->GetInputNames();
  VLOG(3) << "The inputs' size is " << input_names.size();
  PADDLE_ENFORCE_EQ(
      input_names.size(), in_size,
      "The number of input and the number of model's input must match. ");
  for (int i = 0; i < in_size; ++i) {
    auto input_t = predictor->GetInputTensor(inputs[i].name);
    std::vector<int> tensor_shape;
    tensor_shape.assign(inputs[i].shape,
                        inputs[i].shape + inputs[i].shape_size);
    input_t->Reshape(tensor_shape);
    switch (inputs[i].dtype) {
      case PD_FLOAT32:
        input_t->copy_from_cpu(static_cast<float*>(inputs[i].data));
        break;
      case PD_INT32:
        input_t->copy_from_cpu(static_cast<int32_t*>(inputs[i].data));
        break;
      case PD_INT64:
        input_t->copy_from_cpu(static_cast<int64_t*>(inputs[i].data));
        break;
      case PD_UINT8:
        input_t->copy_from_cpu(static_cast<uint8_t*>(inputs[i].data));
        break;
      default:
        CHECK(false) << "Unsupport data type.";
        break;
    }
  }
  CHECK(predictor->ZeroCopyRun());
  auto output_names = predictor->GetOutputNames();
  int osize = output_names.size();
  *out_size = &osize;
  *output = new PD_ZeroCopyData[osize];
  VLOG(3) << "The output size is " << osize;
  for (int i = 0; i < osize; ++i) {
    auto& output_i = (*output)[i];
    output_i.name = new char[output_names[i].length() + 1];
    snprintf(output_i.name, output_names[i].length() + 1, "%s",
             output_names[i].c_str());
    auto output_t = predictor->GetOutputTensor(output_names[i]);
    output_i.dtype = ConvertToPDDataType(output_t->type());
    std::vector<int> output_shape = output_t->shape();
    output_i.shape = new int[output_shape.size()];
    output_i.shape = output_shape.data();
    output_i.shape_size = output_shape.size();
    switch (output_i.dtype) {
      case PD_FLOAT32: {
        std::vector<float> out_data;
        int out_num = std::accumulate(output_shape.begin(), output_shape.end(),
                                      1, std::multiplies<int>());
        out_data.resize(out_num);
        output_t->copy_to_cpu(out_data.data());
        output_i.data = static_cast<void*>(out_data.data());
      } break;
      case PD_INT32: {
        std::vector<int32_t> out_data;
        int out_num = std::accumulate(output_shape.begin(), output_shape.end(),
                                      1, std::multiplies<int>());
        out_data.resize(out_num);
        output_t->copy_to_cpu(out_data.data());
        output_i.data = static_cast<void*>(out_data.data());
      } break;
      case PD_INT64: {
        std::vector<int64_t> out_data;
        int out_num = std::accumulate(output_shape.begin(), output_shape.end(),
                                      1, std::multiplies<int>());
        out_data.resize(out_num);
        output_t->copy_to_cpu(out_data.data());
        output_i.data = static_cast<void*>(out_data.data());
      } break;
      case PD_UINT8: {
        std::vector<uint8_t> out_data;
        int out_num = std::accumulate(output_shape.begin(), output_shape.end(),
                                      1, std::multiplies<int>());
        out_data.resize(out_num);
        output_t->copy_to_cpu(out_data.data());
        output_i.data = static_cast<void*>(out_data.data());
      } break;
      default:
        CHECK(false) << "Unsupport data type.";
        break;
    }
  }
  return true;
}
}  // extern "C"
<commit_msg>improve the performance of capi in PD_PredictorRun (#20665)<commit_after>// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
//
// 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 <algorithm>
#include <map>
#include <numeric>
#include <vector>
#include "paddle/fluid/inference/capi/c_api.h"
#include "paddle/fluid/inference/capi/c_api_internal.h"

using paddle::ConvertToPaddleDType;
using paddle::ConvertToPDDataType;
using paddle::ConvertToACPrecision;

extern "C" {

bool PD_PredictorRun(const PD_AnalysisConfig* config, PD_Tensor* inputs,
                     int in_size, PD_Tensor* output_data, int** out_size,
                     int batch_size) {
  PADDLE_ENFORCE_NOT_NULL(config);
  static std::map<std::string, std::unique_ptr<paddle::PaddlePredictor>>
      predictors;
  if (!predictors.count(config->config.model_dir())) {
    predictors[config->config.model_dir()] =
        paddle::CreatePaddlePredictor(config->config);
  }
  auto& predictor = predictors[config->config.model_dir()];
  std::vector<paddle::PaddleTensor> in;
  for (int i = 0; i < in_size; ++i) {
    in.emplace_back(inputs->tensor);
  }
  std::vector<paddle::PaddleTensor> out;
  if (predictor->Run(in, &out, batch_size)) {
    int osize = out.size();
    for (int i = 0; i < osize; ++i) {
      output_data[i].tensor = out[i];
    }
    *out_size = &osize;
    return true;
  }
  return false;
}

bool PD_PredictorZeroCopyRun(const PD_AnalysisConfig* config,
                             PD_ZeroCopyData* inputs, int in_size,
                             PD_ZeroCopyData** output, int** out_size) {
  PADDLE_ENFORCE_NOT_NULL(config);
  auto predictor = paddle::CreatePaddlePredictor(config->config);
  auto input_names = predictor->GetInputNames();
  VLOG(3) << "The inputs' size is " << input_names.size();
  PADDLE_ENFORCE_EQ(
      input_names.size(), in_size,
      "The number of input and the number of model's input must match. ");
  for (int i = 0; i < in_size; ++i) {
    auto input_t = predictor->GetInputTensor(inputs[i].name);
    std::vector<int> tensor_shape;
    tensor_shape.assign(inputs[i].shape,
                        inputs[i].shape + inputs[i].shape_size);
    input_t->Reshape(tensor_shape);
    switch (inputs[i].dtype) {
      case PD_FLOAT32:
        input_t->copy_from_cpu(static_cast<float*>(inputs[i].data));
        break;
      case PD_INT32:
        input_t->copy_from_cpu(static_cast<int32_t*>(inputs[i].data));
        break;
      case PD_INT64:
        input_t->copy_from_cpu(static_cast<int64_t*>(inputs[i].data));
        break;
      case PD_UINT8:
        input_t->copy_from_cpu(static_cast<uint8_t*>(inputs[i].data));
        break;
      default:
        CHECK(false) << "Unsupport data type.";
        break;
    }
  }
  CHECK(predictor->ZeroCopyRun());
  auto output_names = predictor->GetOutputNames();
  int osize = output_names.size();
  *out_size = &osize;
  *output = new PD_ZeroCopyData[osize];
  VLOG(3) << "The output size is " << osize;
  for (int i = 0; i < osize; ++i) {
    auto& output_i = (*output)[i];
    output_i.name = new char[output_names[i].length() + 1];
    snprintf(output_i.name, output_names[i].length() + 1, "%s",
             output_names[i].c_str());
    auto output_t = predictor->GetOutputTensor(output_names[i]);
    output_i.dtype = ConvertToPDDataType(output_t->type());
    std::vector<int> output_shape = output_t->shape();
    output_i.shape = new int[output_shape.size()];
    output_i.shape = output_shape.data();
    output_i.shape_size = output_shape.size();
    switch (output_i.dtype) {
      case PD_FLOAT32: {
        std::vector<float> out_data;
        int out_num = std::accumulate(output_shape.begin(), output_shape.end(),
                                      1, std::multiplies<int>());
        out_data.resize(out_num);
        output_t->copy_to_cpu(out_data.data());
        output_i.data = static_cast<void*>(out_data.data());
      } break;
      case PD_INT32: {
        std::vector<int32_t> out_data;
        int out_num = std::accumulate(output_shape.begin(), output_shape.end(),
                                      1, std::multiplies<int>());
        out_data.resize(out_num);
        output_t->copy_to_cpu(out_data.data());
        output_i.data = static_cast<void*>(out_data.data());
      } break;
      case PD_INT64: {
        std::vector<int64_t> out_data;
        int out_num = std::accumulate(output_shape.begin(), output_shape.end(),
                                      1, std::multiplies<int>());
        out_data.resize(out_num);
        output_t->copy_to_cpu(out_data.data());
        output_i.data = static_cast<void*>(out_data.data());
      } break;
      case PD_UINT8: {
        std::vector<uint8_t> out_data;
        int out_num = std::accumulate(output_shape.begin(), output_shape.end(),
                                      1, std::multiplies<int>());
        out_data.resize(out_num);
        output_t->copy_to_cpu(out_data.data());
        output_i.data = static_cast<void*>(out_data.data());
      } break;
      default:
        CHECK(false) << "Unsupport data type.";
        break;
    }
  }
  return true;
}
}  // extern "C"
<|endoftext|>


<commit_before>/* Copyright (c) 2017 PaddlePaddle Authors. All Rights Reserve.

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 "MKLDNNConcatLayer.h"

using namespace mkldnn;  // NOLINT
typedef memory::format format;

namespace paddle {

REGISTER_LAYER(mkldnn_concat, MKLDNNConcatLayer);

bool MKLDNNConcatLayer::init(const LayerMap& layerMap,
                             const ParameterMap& parameterMap) {
  if (!MKLDNNLayer::init(layerMap, parameterMap)) {
    return false;
  }
  CHECK_GT(inputLayers_.size(), 1UL);
  CHECK(!biasParameter_);
  return true;
}

void MKLDNNConcatLayer::reshape(
    int& bs, int& ic, int& ih, int& iw, int& oc, int& oh, int& ow) {
  reshapeInput(bs, ih, iw);
  ic = inputLayers_[0]->getSize() / ih / iw;
  CHECK_EQ((size_t)ic * ih * iw, inputLayers_[0]->getSize());
  CHECK_EQ(inputLayers_[0]->getOutputValue()->getElementCnt(),
           (size_t)bs * ic * ih * iw);
  CHECK_GT(inputLayers_.size(), 1UL);
  channels_.resize(inputLayers_.size());
  channels_[0] = ic;
  oc = ic;
  for (size_t i = 1; i < inputLayers_.size(); i++) {
    int batchsize, height, witdh;
    reshapeInput(batchsize, height, witdh, i);
    CHECK_EQ(bs, batchsize);
    CHECK_EQ(ih, height);
    CHECK_EQ(iw, witdh);

    channels_[i] = inputLayers_[i]->getSize() / height / witdh;
    CHECK_EQ((size_t)channels_[i] * height * witdh, inputLayers_[i]->getSize());
    oc += channels_[i];
  }
  oh = ih;
  ow = iw;
  reshapeOutput(oh, ow);
  resizeOutput(bs, oc * oh * ow);
}

void MKLDNNConcatLayer::resetFwd(std::vector<primitive>& pipeline,
                                 std::vector<MKLDNNMatrixPtr>& inputs,
                                 MKLDNNMatrixPtr& out) {
  resetFwdBuffers(inputs, out);

  std::shared_ptr<concat::primitive_desc> fwdPD;
  resetFwdPD(fwdPD, inputs, out);

  resetFwdPipeline(pipeline, fwdPD, inputs, out);
}

void MKLDNNConcatLayer::resetBwd(std::vector<primitive>& pipeline,
                                 std::vector<MKLDNNMatrixPtr>& inputs,
                                 MKLDNNMatrixPtr& out) {
  resetBwdBuffers(inputs, out);

  resetBwdPipeline(pipeline, bwds_, inputs, out);
}

void MKLDNNConcatLayer::resetFwdBuffers(std::vector<MKLDNNMatrixPtr>& inputs,
                                        MKLDNNMatrixPtr& out) {
  inputs.resize(inputLayers_.size());
  bool has8c = false, has16c = false, hasnc = false;
  for (size_t i = 0; i < inputs.size(); i++) {
    resetInValue(inputs[i], nullptr, i, channels_[i]);
    CHECK(inputs[i]);
    auto dm = inputs[i]->getDims();
    // inputs format can be different, but ndims must equal
    CHECK(i == 0 || dm.size() == inputs[0]->getDims().size());
    CHECK_EQ(bs_, dm[0]);
    CHECK_EQ(channels_[i], dm[1]);
    if (dm.size() > 2) {
      CHECK_EQ(ih_, dm[2]);
      CHECK_EQ(iw_, dm[3]);
    }
    if (inputs[i]->getFormat() == format::nc) {
      hasnc = true;
    }
    if (inputs[i]->getFormat() == format::nChw8c) {
      has8c = true;
    }
    if (inputs[i]->getFormat() == format::nChw16c) {
      has16c = true;
    }
  }

  format outFmt;
  if (has16c && oc_ % 16 == 0) {
    outFmt = format::nChw16c;
  } else if (has8c && oc_ % 8 == 0) {
    outFmt = format::nChw8c;
  } else if (hasnc) {
    CHECK(oh_ == 1 && ow_ == 1);
    outFmt = format::nc;
  } else {
    outFmt = format::nchw;
  }
  memory::dims outDims =
      hasnc ? memory::dims{bs_, oc_} : memory::dims{bs_, oc_, oh_, ow_};
  auto outPD = MKLDNNMatrix::createPrimitiveDesc(outDims, outFmt, engine_);
  resetOutValue(out, outPD);
}

void MKLDNNConcatLayer::resetFwdPD(std::shared_ptr<concat::primitive_desc>& pd,
                                   std::vector<MKLDNNMatrixPtr>& inputs,
                                   MKLDNNMatrixPtr out) {
  std::vector<memory::primitive_desc> srcPDs;
  for (size_t i = 0; i < inputs.size(); i++) {
    srcPDs.push_back(inputs[i]->getPrimitiveDesc());
  }
  CHECK(out);
  pd.reset(new concat::primitive_desc(out->getMemoryDesc(), axis_, srcPDs));
  CHECK_PRIMITIVE_DESC_EQ(out, pd->dst_primitive_desc());
}

void MKLDNNConcatLayer::resetFwdPipeline(
    std::vector<primitive>& pipeline,
    std::shared_ptr<concat::primitive_desc>& pd,
    std::vector<MKLDNNMatrixPtr>& inputs,
    MKLDNNMatrixPtr& out) {
  std::vector<primitive::at> srcs;
  for (size_t i = 0; i < inputs.size(); i++) {
    srcs.push_back(*(inputs[i]));
  }
  fwd_.reset(new concat(*pd, srcs, *out));
  pipeline.push_back(*fwd_);
}

void MKLDNNConcatLayer::resetBwdBuffers(std::vector<MKLDNNMatrixPtr>& inputs,
                                        MKLDNNMatrixPtr& out) {
  CHECK(outVal_);
  resetOutGrad(out, outVal_->getPrimitiveDesc());
  CHECK(out);

  inputs.resize(inputLayers_.size());
  for (size_t i = 0; i < inputs.size(); i++) {
    CHECK(inVals_[i]);
    resetInGrad(inputs[i], inVals_[i]->getPrimitiveDesc(), i);
    CHECK_PRIMITIVE_DESC_EQ(inputs[i], inVals_[i]->getPrimitiveDesc());
  }
}

void MKLDNNConcatLayer::resetBwdPipeline(
    std::vector<mkldnn::primitive>& pipeline,
    std::vector<std::shared_ptr<mkldnn::primitive>>& prims,
    std::vector<MKLDNNMatrixPtr>& inputs,
    MKLDNNMatrixPtr& out) {
  // reset the backward primitives
  memory::dims offsets = {0, 0, 0, 0};
  prims.resize(inputs.size());
  CHECK_EQ(inputs.size(), channels_.size());
  for (size_t i = 0; i < inputs.size(); i++) {
    auto viewPD = view::primitive_desc(
        out->getPrimitiveDesc(), inputs[i]->getDims(), offsets);
    auto bwdPD = reorder::primitive_desc(viewPD.dst_primitive_desc(),
                                         inputs[i]->getPrimitiveDesc());
    prims[i].reset(new reorder(bwdPD, *out, *(inputs[i])));
    offsets[axis_] += channels_[i];
    // push to pipeline
    pipeline.push_back(*prims[i]);
  }
}

}  // namespace paddle
<commit_msg>fix mkldnn concat dimension issue for rnn<commit_after>/* Copyright (c) 2017 PaddlePaddle Authors. All Rights Reserve.

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 "MKLDNNConcatLayer.h"

using namespace mkldnn;  // NOLINT
typedef memory::format format;

namespace paddle {

REGISTER_LAYER(mkldnn_concat, MKLDNNConcatLayer);

bool MKLDNNConcatLayer::init(const LayerMap& layerMap,
                             const ParameterMap& parameterMap) {
  if (!MKLDNNLayer::init(layerMap, parameterMap)) {
    return false;
  }
  CHECK_GT(inputLayers_.size(), 1UL);
  CHECK(!biasParameter_);
  return true;
}

void MKLDNNConcatLayer::reshape(
    int& bs, int& ic, int& ih, int& iw, int& oc, int& oh, int& ow) {
  reshapeInput(bs, ih, iw);
  ic = inputLayers_[0]->getSize() / ih / iw;
  CHECK_EQ((size_t)ic * ih * iw, inputLayers_[0]->getSize());
  CHECK_EQ(inputLayers_[0]->getOutputValue()->getElementCnt(),
           (size_t)bs * ic * ih * iw);
  CHECK_GT(inputLayers_.size(), 1UL);
  channels_.resize(inputLayers_.size());
  channels_[0] = ic;
  oc = ic;
  for (size_t i = 1; i < inputLayers_.size(); i++) {
    int batchsize = 0, height = 0, witdh = 0;
    reshapeInput(batchsize, height, witdh, i);
    CHECK_EQ(bs, batchsize);
    CHECK_EQ(ih, height);
    CHECK_EQ(iw, witdh);

    channels_[i] = inputLayers_[i]->getSize() / height / witdh;
    CHECK_EQ((size_t)channels_[i] * height * witdh, inputLayers_[i]->getSize());
    oc += channels_[i];
  }
  oh = ih;
  ow = iw;
  reshapeOutput(oh, ow);
  resizeOutput(bs, oc * oh * ow);
}

void MKLDNNConcatLayer::resetFwd(std::vector<primitive>& pipeline,
                                 std::vector<MKLDNNMatrixPtr>& inputs,
                                 MKLDNNMatrixPtr& out) {
  resetFwdBuffers(inputs, out);

  std::shared_ptr<concat::primitive_desc> fwdPD;
  resetFwdPD(fwdPD, inputs, out);

  resetFwdPipeline(pipeline, fwdPD, inputs, out);
}

void MKLDNNConcatLayer::resetBwd(std::vector<primitive>& pipeline,
                                 std::vector<MKLDNNMatrixPtr>& inputs,
                                 MKLDNNMatrixPtr& out) {
  resetBwdBuffers(inputs, out);

  resetBwdPipeline(pipeline, bwds_, inputs, out);
}

void MKLDNNConcatLayer::resetFwdBuffers(std::vector<MKLDNNMatrixPtr>& inputs,
                                        MKLDNNMatrixPtr& out) {
  inputs.resize(inputLayers_.size());
  bool has8c = false, has16c = false, hasnc = false;
  for (size_t i = 0; i < inputs.size(); i++) {
    resetInValue(inputs[i], nullptr, i, channels_[i]);
    inputs[i]->downSpatial();
    CHECK(inputs[i]);
    auto dm = inputs[i]->getDims();
    // inputs format can be different, but ndims must equal
    CHECK(i == 0 || dm.size() == inputs[0]->getDims().size());
    CHECK_EQ(bs_, dm[0]);
    CHECK_EQ(channels_[i], dm[1]);
    if (dm.size() > 2) {
      CHECK_EQ(ih_, dm[2]);
      CHECK_EQ(iw_, dm[3]);
    }
    if (inputs[i]->getFormat() == format::nc) {
      hasnc = true;
    }
    if (inputs[i]->getFormat() == format::nChw8c) {
      has8c = true;
    }
    if (inputs[i]->getFormat() == format::nChw16c) {
      has16c = true;
    }
  }

  format outFmt;
  if (has16c && oc_ % 16 == 0) {
    outFmt = format::nChw16c;
  } else if (has8c && oc_ % 8 == 0) {
    outFmt = format::nChw8c;
  } else if (hasnc) {
    CHECK(oh_ == 1 && ow_ == 1);
    outFmt = format::nc;
  } else {
    outFmt = format::nchw;
  }
  memory::dims outDims =
      hasnc ? memory::dims{bs_, oc_} : memory::dims{bs_, oc_, oh_, ow_};
  auto outPD = MKLDNNMatrix::createPrimitiveDesc(outDims, outFmt, engine_);
  resetOutValue(out, outPD);
}

void MKLDNNConcatLayer::resetFwdPD(std::shared_ptr<concat::primitive_desc>& pd,
                                   std::vector<MKLDNNMatrixPtr>& inputs,
                                   MKLDNNMatrixPtr out) {
  std::vector<memory::primitive_desc> srcPDs;
  for (size_t i = 0; i < inputs.size(); i++) {
    srcPDs.push_back(inputs[i]->getPrimitiveDesc());
  }
  CHECK(out);
  pd.reset(new concat::primitive_desc(out->getMemoryDesc(), axis_, srcPDs));
  CHECK_PRIMITIVE_DESC_EQ(out, pd->dst_primitive_desc());
}

void MKLDNNConcatLayer::resetFwdPipeline(
    std::vector<primitive>& pipeline,
    std::shared_ptr<concat::primitive_desc>& pd,
    std::vector<MKLDNNMatrixPtr>& inputs,
    MKLDNNMatrixPtr& out) {
  std::vector<primitive::at> srcs;
  for (size_t i = 0; i < inputs.size(); i++) {
    srcs.push_back(*(inputs[i]));
  }
  fwd_.reset(new concat(*pd, srcs, *out));
  pipeline.push_back(*fwd_);
}

void MKLDNNConcatLayer::resetBwdBuffers(std::vector<MKLDNNMatrixPtr>& inputs,
                                        MKLDNNMatrixPtr& out) {
  CHECK(outVal_);
  resetOutGrad(out, outVal_->getPrimitiveDesc());
  CHECK(out);

  inputs.resize(inputLayers_.size());
  for (size_t i = 0; i < inputs.size(); i++) {
    CHECK(inVals_[i]);
    resetInGrad(inputs[i], inVals_[i]->getPrimitiveDesc(), i);
    CHECK_PRIMITIVE_DESC_EQ(inputs[i], inVals_[i]->getPrimitiveDesc());
  }
}

void MKLDNNConcatLayer::resetBwdPipeline(
    std::vector<mkldnn::primitive>& pipeline,
    std::vector<std::shared_ptr<mkldnn::primitive>>& prims,
    std::vector<MKLDNNMatrixPtr>& inputs,
    MKLDNNMatrixPtr& out) {
  // reset the backward primitives
  memory::dims offsets = {0, 0, 0, 0};
  prims.resize(inputs.size());
  CHECK_EQ(inputs.size(), channels_.size());
  for (size_t i = 0; i < inputs.size(); i++) {
    auto viewPD = view::primitive_desc(
        out->getPrimitiveDesc(), inputs[i]->getDims(), offsets);
    auto bwdPD = reorder::primitive_desc(viewPD.dst_primitive_desc(),
                                         inputs[i]->getPrimitiveDesc());
    prims[i].reset(new reorder(bwdPD, *out, *(inputs[i])));
    offsets[axis_] += channels_[i];
    // push to pipeline
    pipeline.push_back(*prims[i]);
  }
}

}  // namespace paddle
<|endoftext|>


<commit_before>#include "Globals.h"

#include "FluidSimulator.h"
#include "../World.h"

cFluidSimulator::cFluidSimulator(cWorld & a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid) :
	super(a_World),
	m_FluidBlock(a_Fluid),
	m_StationaryFluidBlock(a_StationaryFluid)
{
}

bool cFluidSimulator::IsAllowedBlock(BLOCKTYPE a_BlockType)
{
	return ((a_BlockType == m_FluidBlock) || (a_BlockType == m_StationaryFluidBlock));
}

bool cFluidSimulator::CanWashAway(BLOCKTYPE a_BlockType)
{
	switch (a_BlockType)
	{
		case E_BLOCK_ACTIVATOR_RAIL:
		case E_BLOCK_ACTIVE_COMPARATOR:
		case E_BLOCK_BEETROOTS:
		case E_BLOCK_BIG_FLOWER:
		case E_BLOCK_BROWN_MUSHROOM:
		case E_BLOCK_CACTUS:
		case E_BLOCK_CARROTS:
		case E_BLOCK_COBWEB:
		case E_BLOCK_CROPS:
		case E_BLOCK_DEAD_BUSH:
		case E_BLOCK_DETECTOR_RAIL:
		case E_BLOCK_INACTIVE_COMPARATOR:
		case E_BLOCK_LILY_PAD:
		case E_BLOCK_POWERED_RAIL:
		case E_BLOCK_RAIL:
		case E_BLOCK_REDSTONE_REPEATER_OFF:
		case E_BLOCK_REDSTONE_REPEATER_ON:
		case E_BLOCK_REDSTONE_TORCH_OFF:
		case E_BLOCK_REDSTONE_TORCH_ON:
		case E_BLOCK_REDSTONE_WIRE:
		case E_BLOCK_RED_MUSHROOM:
		case E_BLOCK_RED_ROSE:
		case E_BLOCK_SNOW:
		case E_BLOCK_SUGARCANE:
		case E_BLOCK_TALL_GRASS:
		case E_BLOCK_TORCH:
		case E_BLOCK_TRIPWIRE_HOOK:
		case E_BLOCK_TRIPWIRE:
		case E_BLOCK_YELLOW_FLOWER:
		{
			return true;
		}
		default:
		{
			return false;
		}
	}
}

bool cFluidSimulator::IsSolidBlock(BLOCKTYPE a_BlockType)
{
	return !IsPassableForFluid(a_BlockType);
}

bool cFluidSimulator::IsPassableForFluid(BLOCKTYPE a_BlockType)
{
	return (
		(a_BlockType == E_BLOCK_AIR) ||
		(a_BlockType == E_BLOCK_FIRE) ||
		IsAllowedBlock(a_BlockType) ||
		CanWashAway(a_BlockType)
	);
}

bool cFluidSimulator::IsHigherMeta(NIBBLETYPE a_Meta1, NIBBLETYPE a_Meta2)
{
	if (a_Meta1 == 0)
	{
		// Source block is higher than anything, even itself.
		return true;
	}
	if ((a_Meta1 & 0x08) != 0)
	{
		// Falling fluid is higher than anything, including self
		return true;
	}

	if (a_Meta2 == 0)
	{
		// Second block is a source and first block isn't
		return false;
	}
	if ((a_Meta2 & 0x08) != 0)
	{
		// Second block is falling and the first one is neither a source nor falling
		return false;
	}

	// All special cases have been handled, now it's just a raw comparison:
	return (a_Meta1 < a_Meta2);
}

Vector3f cFluidSimulator::GetFlowingDirection(int a_X, int a_Y, int a_Z)
{
	if (!cChunkDef::IsValidHeight(a_Y))
	{
		return {};
	}

	if (!IsAllowedBlock(m_World.GetBlock(a_X, a_Y, a_Z)))  // No Fluid -> No Flowing direction :D
	{
		return {};
	}

	const auto HeightFromMeta = [](NIBBLETYPE a_BlockMeta) -> NIBBLETYPE
		{
			// Falling water blocks are always full height (0)
			return ((a_BlockMeta & 0x08) != 0) ? 0 : a_BlockMeta;
		};

	auto BlockMeta = m_World.GetBlockMeta(a_X, a_Y, a_Z);
	NIBBLETYPE CentralPoint = HeightFromMeta(BlockMeta);
	NIBBLETYPE LevelPoint[4];

	// blocks around the checking pos
	Vector3i Points[]
	{
		{ a_X + 1, a_Y, a_Z },
		{ a_X, a_Y, a_Z + 1 },
		{ a_X - 1, a_Y, a_Z },
		{ a_X, a_Y, a_Z - 1 }
	};

	for (size_t i = 0; i < ARRAYCOUNT(LevelPoint); i++)
	{
		if (IsAllowedBlock(m_World.GetBlock(Points[i])))
		{
			LevelPoint[i] = HeightFromMeta(m_World.GetBlockMeta(Points[i]));
		}
		else
		{
			LevelPoint[i] = CentralPoint;
		}
	}

	Vector3f Direction;

	// Calculate the flow direction

	Direction.x = (LevelPoint[0] - LevelPoint[2]) / 2.0f;
	Direction.z = (LevelPoint[1] - LevelPoint[3]) / 2.0f;

	if ((BlockMeta & 0x08) != 0)  // Test falling bit
	{
		Direction.y = -1.0f;
	}

	return Direction;
}

<commit_msg>Add potatoes to washed away list also<commit_after>#include "Globals.h"

#include "FluidSimulator.h"
#include "../World.h"

cFluidSimulator::cFluidSimulator(cWorld & a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid) :
	super(a_World),
	m_FluidBlock(a_Fluid),
	m_StationaryFluidBlock(a_StationaryFluid)
{
}

bool cFluidSimulator::IsAllowedBlock(BLOCKTYPE a_BlockType)
{
	return ((a_BlockType == m_FluidBlock) || (a_BlockType == m_StationaryFluidBlock));
}

bool cFluidSimulator::CanWashAway(BLOCKTYPE a_BlockType)
{
	switch (a_BlockType)
	{
		case E_BLOCK_ACTIVATOR_RAIL:
		case E_BLOCK_ACTIVE_COMPARATOR:
		case E_BLOCK_BEETROOTS:
		case E_BLOCK_BIG_FLOWER:
		case E_BLOCK_BROWN_MUSHROOM:
		case E_BLOCK_CACTUS:
		case E_BLOCK_CARROTS:
		case E_BLOCK_COBWEB:
		case E_BLOCK_CROPS:
		case E_BLOCK_DEAD_BUSH:
		case E_BLOCK_DETECTOR_RAIL:
		case E_BLOCK_INACTIVE_COMPARATOR:
		case E_BLOCK_LILY_PAD:
		case E_BLOCK_POTATOES:
		case E_BLOCK_POWERED_RAIL:
		case E_BLOCK_RAIL:
		case E_BLOCK_REDSTONE_REPEATER_OFF:
		case E_BLOCK_REDSTONE_REPEATER_ON:
		case E_BLOCK_REDSTONE_TORCH_OFF:
		case E_BLOCK_REDSTONE_TORCH_ON:
		case E_BLOCK_REDSTONE_WIRE:
		case E_BLOCK_RED_MUSHROOM:
		case E_BLOCK_RED_ROSE:
		case E_BLOCK_SNOW:
		case E_BLOCK_SUGARCANE:
		case E_BLOCK_TALL_GRASS:
		case E_BLOCK_TORCH:
		case E_BLOCK_TRIPWIRE:
		case E_BLOCK_TRIPWIRE_HOOK:
		case E_BLOCK_YELLOW_FLOWER:
		{
			return true;
		}
		default:
		{
			return false;
		}
	}
}

bool cFluidSimulator::IsSolidBlock(BLOCKTYPE a_BlockType)
{
	return !IsPassableForFluid(a_BlockType);
}

bool cFluidSimulator::IsPassableForFluid(BLOCKTYPE a_BlockType)
{
	return (
		(a_BlockType == E_BLOCK_AIR) ||
		(a_BlockType == E_BLOCK_FIRE) ||
		IsAllowedBlock(a_BlockType) ||
		CanWashAway(a_BlockType)
	);
}

bool cFluidSimulator::IsHigherMeta(NIBBLETYPE a_Meta1, NIBBLETYPE a_Meta2)
{
	if (a_Meta1 == 0)
	{
		// Source block is higher than anything, even itself.
		return true;
	}
	if ((a_Meta1 & 0x08) != 0)
	{
		// Falling fluid is higher than anything, including self
		return true;
	}

	if (a_Meta2 == 0)
	{
		// Second block is a source and first block isn't
		return false;
	}
	if ((a_Meta2 & 0x08) != 0)
	{
		// Second block is falling and the first one is neither a source nor falling
		return false;
	}

	// All special cases have been handled, now it's just a raw comparison:
	return (a_Meta1 < a_Meta2);
}

Vector3f cFluidSimulator::GetFlowingDirection(int a_X, int a_Y, int a_Z)
{
	if (!cChunkDef::IsValidHeight(a_Y))
	{
		return {};
	}

	if (!IsAllowedBlock(m_World.GetBlock(a_X, a_Y, a_Z)))  // No Fluid -> No Flowing direction :D
	{
		return {};
	}

	const auto HeightFromMeta = [](NIBBLETYPE a_BlockMeta) -> NIBBLETYPE
		{
			// Falling water blocks are always full height (0)
			return ((a_BlockMeta & 0x08) != 0) ? 0 : a_BlockMeta;
		};

	auto BlockMeta = m_World.GetBlockMeta(a_X, a_Y, a_Z);
	NIBBLETYPE CentralPoint = HeightFromMeta(BlockMeta);
	NIBBLETYPE LevelPoint[4];

	// blocks around the checking pos
	Vector3i Points[]
	{
		{ a_X + 1, a_Y, a_Z },
		{ a_X, a_Y, a_Z + 1 },
		{ a_X - 1, a_Y, a_Z },
		{ a_X, a_Y, a_Z - 1 }
	};

	for (size_t i = 0; i < ARRAYCOUNT(LevelPoint); i++)
	{
		if (IsAllowedBlock(m_World.GetBlock(Points[i])))
		{
			LevelPoint[i] = HeightFromMeta(m_World.GetBlockMeta(Points[i]));
		}
		else
		{
			LevelPoint[i] = CentralPoint;
		}
	}

	Vector3f Direction;

	// Calculate the flow direction

	Direction.x = (LevelPoint[0] - LevelPoint[2]) / 2.0f;
	Direction.z = (LevelPoint[1] - LevelPoint[3]) / 2.0f;

	if ((BlockMeta & 0x08) != 0)  // Test falling bit
	{
		Direction.y = -1.0f;
	}

	return Direction;
}

<|endoftext|>


<commit_before>/**
@file Object/Defs.hpp
@brief Object definitions.

@author Timothy Howard
@copyright 2013-2014 Timothy Howard under the MIT license;
see @ref index or the accompanying LICENSE file for full text.
*/

#ifndef HORD_OBJECT_DEFS_HPP_
#define HORD_OBJECT_DEFS_HPP_

#include <Hord/config.hpp>
#include <Hord/IO/PropStateStore.hpp>

#include <duct/cc_unique_ptr.hpp>

namespace Hord {
namespace Object {

// Forward declarations
enum class Type : unsigned;
struct type_info;
class Unit; // external

/**
	@addtogroup object
	@{
*/

/**
	Generic object ID.

	@sa Hive::ID,
		Rule::ID,
		Node::ID
*/
using ID = std::uint32_t;

/**
	Object::ID constants.
*/
enum : Object::ID {
	/**
		Null object.
	*/
	NULL_ID = static_cast<Object::ID>(0u)
};

/**
	%Object type.
*/
enum class Type : unsigned {
	/** @ref hive. */
	Hive = 0u,

	/** @ref rule. */
	Rule,

	/** @ref node. */
	Node,

/** @cond INTERNAL */
	LAST
/** @endcond */
};

/**
	Get the name of an object type.

	@returns C-string containing the name of @a object_type or
	"INVALID" if somehow @a object_type is not actually
	an @c Object::Type.
	@param object_type Object type.
*/
char const*
get_type_name(
	Object::Type const object_type
) noexcept;

/**
	Object type info.
*/
struct type_info final {
	/**
		Object type.

		@sa Object::Type
	*/
	Object::Type const type;

	/**
		Prop availability.
	*/
	IO::PropStateStore const props;
};

/**
	Owning pointer to object unit.
*/
using UPtr = duct::cc_unique_ptr<Object::Unit>;

/** @} */ // end of doc-group object

} // namespace Object
} // namespace Hord

#endif // HORD_OBJECT_DEFS_HPP_
<commit_msg>Object/Defs: added Object::Type serialize().<commit_after>/**
@file Object/Defs.hpp
@brief Object definitions.

@author Timothy Howard
@copyright 2013-2014 Timothy Howard under the MIT license;
see @ref index or the accompanying LICENSE file for full text.
*/

#ifndef HORD_OBJECT_DEFS_HPP_
#define HORD_OBJECT_DEFS_HPP_

#include <Hord/config.hpp>
#include <Hord/serialization.hpp>
#include <Hord/IO/PropStateStore.hpp>

#include <duct/cc_unique_ptr.hpp>

namespace Hord {
namespace Object {

// Forward declarations
enum class Type : unsigned;
struct type_info;
class Unit; // external

/**
	@addtogroup object
	@{
*/

/**
	Generic object ID.

	@sa Hive::ID,
		Rule::ID,
		Node::ID
*/
using ID = std::uint32_t;

/**
	Object::ID constants.
*/
enum : Object::ID {
	/**
		Null object.
	*/
	NULL_ID = static_cast<Object::ID>(0u)
};

/**
	%Object type.
*/
enum class Type : unsigned {
	/** @ref hive. */
	Hive = 0u,

	/** @ref rule. */
	Rule,

	/** @ref node. */
	Node,

/** @cond INTERNAL */
	LAST
/** @endcond */
};

/**
	Get the name of an object type.

	@returns C-string containing the name of @a object_type or
	"INVALID" if somehow @a object_type is not actually
	an @c Object::Type.
	@param object_type Object type.
*/
char const*
get_type_name(
	Object::Type const object_type
) noexcept;

/**
	Object type info.
*/
struct type_info final {
	/**
		Object type.

		@sa Object::Type
	*/
	Object::Type const type;

	/**
		Prop availability.
	*/
	IO::PropStateStore const props;
};

/**
	Owning pointer to object unit.
*/
using UPtr = duct::cc_unique_ptr<Object::Unit>;

/**
	Serialize object type.
*/
template<class Ser>
inline ser_result_type
serialize(
	ser_tag_serialize,
	Ser& ser,
	Object::Type& value
) {
	ser(Cacophony::make_enum_cfg<std::uint8_t>(const_safe<Ser>(value)));
}

/** @} */ // end of doc-group object

} // namespace Object
} // namespace Hord

#endif // HORD_OBJECT_DEFS_HPP_
<|endoftext|>


<commit_before>//
// permission.hpp
// **************
//
// Copyright (c) 2019 Sharon W (sharon at aegis dot gg)
//
// Distributed under the MIT License. (See accompanying file LICENSE)
//

#pragma once

#include "aegis/config.hpp"
#include "aegis/fwd.hpp"
#include <stdint.h>

namespace aegis
{

/// Utility class for permission checks
class permission
{
public:
    permission() = default;
    permission(int64_t allow) : _allow_permissions(allow) {}
    //permission(const permission&) = delete;

    operator int64_t() const noexcept
    {
        return _allow_permissions;
    }

    int64_t get_allow_perms() const noexcept { return _allow_permissions; }
    bool can_invite() const noexcept { return (_allow_permissions & 0x1) > 0; }
    bool can_kick() const noexcept { return (_allow_permissions & 0x2) > 0; }
    bool can_ban() const noexcept { return (_allow_permissions & 0x4) > 0; }
    bool is_admin() const noexcept { return (_allow_permissions & 0x8) > 0; }
    bool can_manage_channels() const noexcept { return (_allow_permissions & 0x10) > 0; }
    bool can_manage_guild() const noexcept { return (_allow_permissions & 0x20) > 0; }
    bool can_add_reactions() const noexcept { return (_allow_permissions & 0x40) > 0; }
    bool can_view_audit_logs() const noexcept { return (_allow_permissions & 0x80) > 0; }
    bool can_read_messages() const noexcept { return (_allow_permissions & 0x400) > 0; }
    bool can_send_messages() const noexcept { return (_allow_permissions & 0x800) > 0; }
    bool can_tts() const noexcept { return (_allow_permissions & 0x1000) > 0; }
    bool can_manage_messages() const noexcept { return (_allow_permissions & 0x2000) > 0; }
    bool can_embed() const noexcept { return (_allow_permissions & 0x4000) > 0; }
    bool can_attach_files() const noexcept { return (_allow_permissions & 0x8000) > 0; }
    bool can_read_history() const noexcept { return (_allow_permissions & 0x10000) > 0; }
    bool can_mention_everyone() const noexcept { return (_allow_permissions & 0x20000) > 0; }
    bool can_external_emoiji() const noexcept { return (_allow_permissions & 0x40000) > 0; }
    bool can_change_name() const noexcept { return (_allow_permissions & 0x4000000) > 0; }
    bool can_manage_names() const noexcept { return (_allow_permissions & 0x8000000) > 0; }
    bool can_manage_roles() const noexcept { return (_allow_permissions & 0x10000000) > 0; }
    bool can_manage_webhooks() const noexcept { return (_allow_permissions & 0x20000000) > 0; }
    bool can_manage_emojis() const noexcept { return (_allow_permissions & 0x40000000) > 0; }

    bool can_voice_connect() const noexcept { return (_allow_permissions & 0x100000) > 0; }
    bool can_voice_mute() const noexcept { return (_allow_permissions & 0x400000) > 0; }
    bool can_voice_speak() const noexcept { return (_allow_permissions & 0x200000) > 0; }
    bool can_voice_deafen() const noexcept { return (_allow_permissions & 0x800000) > 0; }
    bool can_voice_move() const noexcept { return (_allow_permissions & 0x1000000) > 0; }
    bool can_voice_activity() const noexcept { return (_allow_permissions & 0x2000000) > 0; }

    void set_invite() noexcept { _allow_permissions = (_allow_permissions & 0x1); }
    void set_kick() noexcept { _allow_permissions = (_allow_permissions & 0x2); }
    void set_ban() noexcept { _allow_permissions = (_allow_permissions & 0x4); }
    void set_admin() noexcept { _allow_permissions = (_allow_permissions & 0x8); }
    void set_manage_channels() noexcept { _allow_permissions = (_allow_permissions & 0x10); }
    void set_manage_guild() noexcept { _allow_permissions = (_allow_permissions & 0x20); }
    void set_add_reactions() noexcept { _allow_permissions = (_allow_permissions & 0x40); }
    void set_view_audit_logs() noexcept { _allow_permissions = (_allow_permissions & 0x80); }
    void set_read_messages() noexcept { _allow_permissions = (_allow_permissions & 0x400); }
    void set_send_messages() noexcept { _allow_permissions = (_allow_permissions & 0x800); }
    void set_tts() noexcept { _allow_permissions = (_allow_permissions & 0x1000); }
    void set_manage_messages() noexcept { _allow_permissions = (_allow_permissions & 0x2000); }
    void set_embed() noexcept { _allow_permissions = (_allow_permissions & 0x4000); }
    void set_attach_files() noexcept { _allow_permissions = (_allow_permissions & 0x8000); }
    void set_read_history() noexcept { _allow_permissions = (_allow_permissions & 0x10000); }
    void set_mention_everyone() noexcept { _allow_permissions = (_allow_permissions & 0x20000); }
    void set_external_emoiji() noexcept { _allow_permissions = (_allow_permissions & 0x40000); }
    void set_change_name() noexcept { _allow_permissions = (_allow_permissions & 0x4000000); }
    void set_manage_names() noexcept { _allow_permissions = (_allow_permissions & 0x8000000); }
    void set_manage_roles() noexcept { _allow_permissions = (_allow_permissions & 0x10000000); }
    void set_manage_webhooks() noexcept { _allow_permissions = (_allow_permissions & 0x20000000); }
    void set_manage_emojis() noexcept { _allow_permissions = (_allow_permissions & 0x40000000); }

    void set_voice_connect() noexcept { _allow_permissions = (_allow_permissions & 0x100000); }
    void set_voice_mute() noexcept { _allow_permissions = (_allow_permissions & 0x400000); }
    void set_voice_speak() noexcept { _allow_permissions = (_allow_permissions & 0x200000); }
    void set_voice_deafen() noexcept { _allow_permissions = (_allow_permissions & 0x800000); }
    void set_voice_move() noexcept { _allow_permissions = (_allow_permissions & 0x1000000); }
    void set_voice_activity() noexcept { _allow_permissions = (_allow_permissions & 0x2000000); }

private:
    int64_t _allow_permissions = 0;
};

/// \cond TEMPLATES
AEGIS_DECL void from_json(const nlohmann::json& j, permission& s);

AEGIS_DECL void to_json(nlohmann::json& j, const permission& s);
/// \endcond

}

#if defined(AEGIS_HEADER_ONLY)
#include "aegis/impl/permission.cpp"
#endif
<commit_msg>Added has_priority_speaker support to permissions<commit_after>//
// permission.hpp
// **************
//
// Copyright (c) 2019 Sharon W (sharon at aegis dot gg)
//
// Distributed under the MIT License. (See accompanying file LICENSE)
//

#pragma once

#include "aegis/config.hpp"
#include "aegis/fwd.hpp"
#include <stdint.h>

namespace aegis
{

/// Utility class for permission checks
class permission
{
public:
    permission() = default;
    permission(int64_t allow) : _allow_permissions(allow) {}
    //permission(const permission&) = delete;

    operator int64_t() const noexcept
    {
        return _allow_permissions;
    }

    int64_t get_allow_perms() const noexcept { return _allow_permissions; }
    bool can_invite() const noexcept { return (_allow_permissions & 0x1) > 0; }
    bool can_kick() const noexcept { return (_allow_permissions & 0x2) > 0; }
    bool can_ban() const noexcept { return (_allow_permissions & 0x4) > 0; }
    bool is_admin() const noexcept { return (_allow_permissions & 0x8) > 0; }
    bool can_manage_channels() const noexcept { return (_allow_permissions & 0x10) > 0; }
    bool can_manage_guild() const noexcept { return (_allow_permissions & 0x20) > 0; }
    bool can_add_reactions() const noexcept { return (_allow_permissions & 0x40) > 0; }
    bool can_view_audit_logs() const noexcept { return (_allow_permissions & 0x80) > 0; }
    bool can_read_messages() const noexcept { return (_allow_permissions & 0x400) > 0; }
    bool can_send_messages() const noexcept { return (_allow_permissions & 0x800) > 0; }
    bool can_tts() const noexcept { return (_allow_permissions & 0x1000) > 0; }
    bool can_manage_messages() const noexcept { return (_allow_permissions & 0x2000) > 0; }
    bool can_embed() const noexcept { return (_allow_permissions & 0x4000) > 0; }
    bool can_attach_files() const noexcept { return (_allow_permissions & 0x8000) > 0; }
    bool can_read_history() const noexcept { return (_allow_permissions & 0x10000) > 0; }
    bool can_mention_everyone() const noexcept { return (_allow_permissions & 0x20000) > 0; }
    bool can_external_emoiji() const noexcept { return (_allow_permissions & 0x40000) > 0; }
    bool can_change_name() const noexcept { return (_allow_permissions & 0x4000000) > 0; }
    bool can_manage_names() const noexcept { return (_allow_permissions & 0x8000000) > 0; }
    bool can_manage_roles() const noexcept { return (_allow_permissions & 0x10000000) > 0; }
    bool can_manage_webhooks() const noexcept { return (_allow_permissions & 0x20000000) > 0; }
    bool can_manage_emojis() const noexcept { return (_allow_permissions & 0x40000000) > 0; }

    bool can_voice_connect() const noexcept { return (_allow_permissions & 0x100000) > 0; }
    bool can_voice_mute() const noexcept { return (_allow_permissions & 0x400000) > 0; }
    bool can_voice_speak() const noexcept { return (_allow_permissions & 0x200000) > 0; }
    bool can_voice_deafen() const noexcept { return (_allow_permissions & 0x800000) > 0; }
    bool can_voice_move() const noexcept { return (_allow_permissions & 0x1000000) > 0; }
    bool can_voice_activity() const noexcept { return (_allow_permissions & 0x2000000) > 0; }
    bool has_priority_speaker() const noexcept { return (_allow_permissions & 0x100) > 0; }

    void set_invite() noexcept { _allow_permissions = (_allow_permissions & 0x1); }
    void set_kick() noexcept { _allow_permissions = (_allow_permissions & 0x2); }
    void set_ban() noexcept { _allow_permissions = (_allow_permissions & 0x4); }
    void set_admin() noexcept { _allow_permissions = (_allow_permissions & 0x8); }
    void set_manage_channels() noexcept { _allow_permissions = (_allow_permissions & 0x10); }
    void set_manage_guild() noexcept { _allow_permissions = (_allow_permissions & 0x20); }
    void set_add_reactions() noexcept { _allow_permissions = (_allow_permissions & 0x40); }
    void set_view_audit_logs() noexcept { _allow_permissions = (_allow_permissions & 0x80); }
    void set_read_messages() noexcept { _allow_permissions = (_allow_permissions & 0x400); }
    void set_send_messages() noexcept { _allow_permissions = (_allow_permissions & 0x800); }
    void set_tts() noexcept { _allow_permissions = (_allow_permissions & 0x1000); }
    void set_manage_messages() noexcept { _allow_permissions = (_allow_permissions & 0x2000); }
    void set_embed() noexcept { _allow_permissions = (_allow_permissions & 0x4000); }
    void set_attach_files() noexcept { _allow_permissions = (_allow_permissions & 0x8000); }
    void set_read_history() noexcept { _allow_permissions = (_allow_permissions & 0x10000); }
    void set_mention_everyone() noexcept { _allow_permissions = (_allow_permissions & 0x20000); }
    void set_external_emoiji() noexcept { _allow_permissions = (_allow_permissions & 0x40000); }
    void set_change_name() noexcept { _allow_permissions = (_allow_permissions & 0x4000000); }
    void set_manage_names() noexcept { _allow_permissions = (_allow_permissions & 0x8000000); }
    void set_manage_roles() noexcept { _allow_permissions = (_allow_permissions & 0x10000000); }
    void set_manage_webhooks() noexcept { _allow_permissions = (_allow_permissions & 0x20000000); }
    void set_manage_emojis() noexcept { _allow_permissions = (_allow_permissions & 0x40000000); }

    void set_voice_connect() noexcept { _allow_permissions = (_allow_permissions & 0x100000); }
    void set_voice_mute() noexcept { _allow_permissions = (_allow_permissions & 0x400000); }
    void set_voice_speak() noexcept { _allow_permissions = (_allow_permissions & 0x200000); }
    void set_voice_deafen() noexcept { _allow_permissions = (_allow_permissions & 0x800000); }
    void set_voice_move() noexcept { _allow_permissions = (_allow_permissions & 0x1000000); }
    void set_voice_activity() noexcept { _allow_permissions = (_allow_permissions & 0x2000000); }

private:
    int64_t _allow_permissions = 0;
};

/// \cond TEMPLATES
AEGIS_DECL void from_json(const nlohmann::json& j, permission& s);

AEGIS_DECL void to_json(nlohmann::json& j, const permission& s);
/// \endcond

}

#if defined(AEGIS_HEADER_ONLY)
#include "aegis/impl/permission.cpp"
#endif
<|endoftext|>


<commit_before>#pragma once
/**
	@file
	@brief bit vector
	@author MITSUNARI Shigeo(@herumi)
	@license modified new BSD license
	http://opensource.org/licenses/BSD-3-Clause
*/
#include <cybozu/exception.hpp>
#include <vector>

namespace cybozu {

class BitVector {
	size_t bitSize_;
	std::vector<uint64_t> v_;
public:
	BitVector()
		: bitSize_(0)
	{
	}
	void init(const uint64_t *block, size_t bitSize)
	{
		resize(bitSize);
		for (size_t i = 0, n = v_.size(); i < n; i++) {
			v_[i] = block[i];
		}
	}
	void resize(size_t bitSize)
	{
		bitSize_ = bitSize;
		v_.resize((bitSize + 63) / 64);
	}
	bool get(size_t idx) const
	{
		size_t q = idx / 64;
		size_t r = idx % 64;
		return (v_[q] & (uint64_t(1) << r)) != 0;
	}
	void clear()
	{
		bitSize_ = 0;
		v_.clear();
	}
	void set(size_t idx, bool b)
	{
		if (b) {
			set(idx);
		} else {
			reset(idx);
		}
	}
	// set(idx, true);
	void set(size_t idx)
	{
		size_t q = idx / 64;
		size_t r = idx % 64;
		if (q >= v_.size()) throw cybozu::Exception("BitVector:set bad idx") << idx;
		v_[q] |= uint64_t(1) << r;
	}
	// set(idx, false);
	void reset(size_t idx)
	{
		size_t q = idx / 64;
		size_t r = idx % 64;
		if (q >= v_.size()) throw cybozu::Exception("BitVector:reset bad idx") << idx;
		v_[q] &= ~(uint64_t(1) << r);
	}
	size_t size() const { return bitSize_; }
	const uint64_t *getBlock() const { return &v_[0]; }
	uint64_t *getBlock() { return &v_[0]; }
	size_t getBlockSize() const { return v_.size(); }
};

} // cybozu
<commit_msg>check idx of get of BitVector<commit_after>#pragma once
/**
	@file
	@brief bit vector
	@author MITSUNARI Shigeo(@herumi)
	@license modified new BSD license
	http://opensource.org/licenses/BSD-3-Clause
*/
#include <cybozu/exception.hpp>
#include <vector>

namespace cybozu {

class BitVector {
	size_t bitSize_;
	std::vector<uint64_t> v_;
public:
	BitVector()
		: bitSize_(0)
	{
	}
	void init(const uint64_t *block, size_t bitSize)
	{
		resize(bitSize);
		for (size_t i = 0, n = v_.size(); i < n; i++) {
			v_[i] = block[i];
		}
	}
	void resize(size_t bitSize)
	{
		bitSize_ = bitSize;
		v_.resize((bitSize + 63) / 64);
	}
	bool get(size_t idx) const
	{
		size_t q = idx / 64;
		size_t r = idx % 64;
		if (q >= v_.size()) throw cybozu::Exception("BitVector:get bad idx") << idx;
		return (v_[q] & (uint64_t(1) << r)) != 0;
	}
	void clear()
	{
		bitSize_ = 0;
		v_.clear();
	}
	void set(size_t idx, bool b)
	{
		if (b) {
			set(idx);
		} else {
			reset(idx);
		}
	}
	// set(idx, true);
	void set(size_t idx)
	{
		size_t q = idx / 64;
		size_t r = idx % 64;
		if (q >= v_.size()) throw cybozu::Exception("BitVector:set bad idx") << idx;
		v_[q] |= uint64_t(1) << r;
	}
	// set(idx, false);
	void reset(size_t idx)
	{
		size_t q = idx / 64;
		size_t r = idx % 64;
		if (q >= v_.size()) throw cybozu::Exception("BitVector:reset bad idx") << idx;
		v_[q] &= ~(uint64_t(1) << r);
	}
	size_t size() const { return bitSize_; }
	const uint64_t *getBlock() const { return &v_[0]; }
	uint64_t *getBlock() { return &v_[0]; }
	size_t getBlockSize() const { return v_.size(); }
};

} // cybozu
<|endoftext|>


<commit_before>#ifndef COFFEE_MILL_VECTOR
#define COFFEE_MILL_VECTOR
#include "Matrix.hpp"
#include "detail/scalar_type_extractor.hpp"

namespace mill
{

template<typename realT, std::size_t N>
using Vector = Matrix<realT, 1, N>;

// for vector 3d
template<typename coordT>
inline typename scalar_type_extractor<coordT>::type
dot_product(const coordT& lhs, const coordT& rhs)
{
    return lhs[0] * rhs[0] + lhs[1] * rhs[1] + lhs[2] * rhs[2];
}

template<typename coordT>
inline coordT
cross_product(const coordT& lhs, const coordT& rhs)
{
    return coordT(lhs[1] * rhs[2] - lhs[2] * rhs[1],
                  lhs[2] * rhs[0] - lhs[0] * rhs[2],
                  lhs[0] * rhs[1] - lhs[1] * rhs[0]);
}

template<typename coordT>
inline typename scalar_type_extractor<coordT>::type
scalar_triple_product(const coordT& lhs, const coordT& mid, const coordT& rhs)
{
    return (lhs[1] * mid[2] - lhs[2] * mid[1]) * rhs[0] +
           (lhs[2] * mid[0] - lhs[0] * mid[2]) * rhs[1] +
           (lhs[0] * mid[1] - lhs[1] * mid[0]) * rhs[2];
}

template<typename coordT>
inline typename scalar_type_extractor<coordT>::type
length_sq(const coordT& lhs)
{
    return lhs[0] * lhs[0] + lhs[1] * lhs[1] + lhs[2] * lhs[2];
}

template<typename coordT>
inline typename scalar_type_extractor<coordT>::type
length(const coordT& lhs)
{
    return std::sqrt(length_sq(lhs));
}

template<typename coordT>
coordT
rotate(const typename scalar_type_extractor<coordT>::type angle,
       const coordT& axis, const coordT& target)
{
    using namespace boost::math;
    using quat = quaternion<typename scalar_type_extractor<coordT>::type>;

    const typename scalar_type_extractor<coordT>::type sin_normalize =
        sin(angle * 0.5) / length(axis);

    const quat Q(cos(angle * 0.5), axis[0] * sin_normalize,
                                   axis[1] * sin_normalize,
                                   axis[2] * sin_normalize);
    const quat P(0e0, target[0], target[1], target[2]);
    const quat S(Q * P * conj(Q));

    return coordT(S.R_component_2(), S.R_component_3(), S.R_component_4());
}

} // mill

#endif /* COFFEE_MILL_VECTOR */
<commit_msg>add include files to Vector<commit_after>#ifndef COFFEE_MILL_VECTOR
#define COFFEE_MILL_VECTOR
#include "Matrix.hpp"
#include "detail/scalar_type_extractor.hpp"
#include <boost/math/quaternion.hpp>
#include <cmath>

namespace mill
{

template<typename realT, std::size_t N>
using Vector = Matrix<realT, 1, N>;

// for vector 3d
template<typename coordT>
inline typename scalar_type_extractor<coordT>::type
dot_product(const coordT& lhs, const coordT& rhs)
{
    return lhs[0] * rhs[0] + lhs[1] * rhs[1] + lhs[2] * rhs[2];
}

template<typename coordT>
inline coordT
cross_product(const coordT& lhs, const coordT& rhs)
{
    return coordT(lhs[1] * rhs[2] - lhs[2] * rhs[1],
                  lhs[2] * rhs[0] - lhs[0] * rhs[2],
                  lhs[0] * rhs[1] - lhs[1] * rhs[0]);
}

template<typename coordT>
inline typename scalar_type_extractor<coordT>::type
scalar_triple_product(const coordT& lhs, const coordT& mid, const coordT& rhs)
{
    return (lhs[1] * mid[2] - lhs[2] * mid[1]) * rhs[0] +
           (lhs[2] * mid[0] - lhs[0] * mid[2]) * rhs[1] +
           (lhs[0] * mid[1] - lhs[1] * mid[0]) * rhs[2];
}

template<typename coordT>
inline typename scalar_type_extractor<coordT>::type
length_sq(const coordT& lhs)
{
    return lhs[0] * lhs[0] + lhs[1] * lhs[1] + lhs[2] * lhs[2];
}

template<typename coordT>
inline typename scalar_type_extractor<coordT>::type
length(const coordT& lhs)
{
    return std::sqrt(length_sq(lhs));
}

template<typename coordT>
coordT
rotate(const typename scalar_type_extractor<coordT>::type angle,
       const coordT& axis, const coordT& target)
{
    using namespace boost::math;
    using quat = quaternion<typename scalar_type_extractor<coordT>::type>;

    const typename scalar_type_extractor<coordT>::type sin_normalize =
        sin(angle * 0.5) / length(axis);

    const quat Q(cos(angle * 0.5), axis[0] * sin_normalize,
                                   axis[1] * sin_normalize,
                                   axis[2] * sin_normalize);
    const quat P(0e0, target[0], target[1], target[2]);
    const quat S(Q * P * conj(Q));

    return coordT(S.R_component_2(), S.R_component_3(), S.R_component_4());
}

} // mill

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


<commit_before>//
// Copyright(c) 2018 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//

//
// latency.cpp : spdlog latency benchmarks
//

#include "benchmark/benchmark.h"

#include "spdlog/spdlog.h"
#include "spdlog/async.h"
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/sinks/null_sink.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include <chrono>

#include "utils.h"
#include <atomic>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <string>
#include <thread>

using namespace std;
using namespace std::chrono;
using namespace spdlog;
using namespace spdlog::sinks;
using namespace utils;

void prepare_logdir()
{
    spdlog::info("Preparing logs_bench directory..");
#ifdef _WIN32
    system("if not exist logs mkdir logs_bench");
    system("del /F /Q logs\\*");
#else
    auto rv = system("mkdir -p logs_bench");
    if (rv != 0)
    {
        throw std::runtime_error("Failed to mkdir -p logs_bench");
    }
    rv = system("rm -f logs_bench/*");
    if (rv != 0)
    {
        throw std::runtime_error("Failed to rm -f logs_bench/*");
    }
#endif
}

void add_rate(benchmark::State &state)
{
    state.counters["Rate"] = benchmark::Counter(1, benchmark::Counter::kIsIterationInvariantRate);
}

void bench_c_string(benchmark::State& state, std::shared_ptr<spdlog::logger> logger)
{
    const char *msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pharetra metus cursus "
                      "lacus placerat congue. Nulla egestas, mauris a tincidunt tempus, enim lectus volutpat mi, eu consequat sem "
                      "libero nec massa. In dapibus ipsum a diam rhoncus gravida. Etiam non dapibus eros. Donec fringilla dui sed "
                      "augue pretium, nec scelerisque est maximus. Nullam convallis, sem nec blandit maximus, nisi turpis ornare "
                      "nisl, sit amet volutpat neque massa eu odio. Maecenas malesuada quam ex, posuere congue nibh turpis duis.";

    for (auto _ : state)
    {
        logger->info(msg);
    }
    add_rate(state);
}

void bench_logger(benchmark::State& state, std::shared_ptr<spdlog::logger> logger)
{
    int i = 0;
    for (auto _ : state)
    {
        logger->info("Hello logger: msg number {}...............", ++i);

    }
    add_rate(state);

}

int main(int argc, char *argv[])
{

    using spdlog::sinks::null_sink_st ;
    using spdlog::sinks::null_sink_mt ;
    using spdlog::sinks::basic_file_sink_st;
    using spdlog::sinks::basic_file_sink_mt;

    size_t file_size = 30 * 1024 * 1024;
    size_t rotating_files = 5;
    int n_threads = 10;

    prepare_logdir();

    //
    // Single threaded bench
    //
    auto null_logger = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_st>());

    benchmark::RegisterBenchmark("null_sink_st-500_bytes_cstr", bench_c_string, null_logger);
    benchmark::RegisterBenchmark("null_sink_st", bench_logger, null_logger);
    benchmark::RegisterBenchmark("null_sink_st", bench_logger, null_logger)->UseRealTime();

    // basic_st
    auto basic_st = spdlog::basic_logger_st("basic_st", "logs_bench/basic_st.log", true);
    benchmark::RegisterBenchmark("basic_st", bench_logger, std::move(basic_st));
    benchmark::RegisterBenchmark("basic_st", bench_logger, std::move(basic_st))->UseRealTime();
    spdlog::drop("basic_st");

    // rotating st
    auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs_bench/rotating_st.log", file_size, rotating_files);
    benchmark::RegisterBenchmark("rotating_st", bench_logger, std::move(rotating_st));
    benchmark::RegisterBenchmark("rotating_st", bench_logger, std::move(rotating_st))->UseRealTime();
    spdlog::drop("rotating_st");

    // daily st
    auto daily_st = spdlog::daily_logger_mt("daily_st", "logs_bench/daily_st.log");
    benchmark::RegisterBenchmark("daily_st", bench_logger, std::move(daily_st));
    benchmark::RegisterBenchmark("daily_st", bench_logger, std::move(daily_st))->UseRealTime();
    spdlog::drop("daily_st");

    //
    // Multi threaded bench, 10 using same logger concurrently
    //
    auto null_logger_mt = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>());
    benchmark::RegisterBenchmark("null_sink_mt", bench_logger, null_logger_mt)->Threads(n_threads);
    benchmark::RegisterBenchmark("null_sink_mt", bench_logger, null_logger_mt)->Threads(n_threads)->UseRealTime();

    // basic_mt
    auto basic_mt = spdlog::basic_logger_mt("basic_mt", "logs_bench/basic_mt.log", true);
    benchmark::RegisterBenchmark("basic_mt", bench_logger, std::move(basic_mt))->Threads(n_threads);
    benchmark::RegisterBenchmark("basic_mt", bench_logger, std::move(basic_mt))->Threads(n_threads)->UseRealTime();
    spdlog::drop("basic_mt");

    // rotating mt
    auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs_bench/rotating_mt.log", file_size, rotating_files);
    benchmark::RegisterBenchmark("rotating_mt", bench_logger, std::move(rotating_mt))->Threads(n_threads);
    benchmark::RegisterBenchmark("rotating_mt", bench_logger, std::move(rotating_mt))->Threads(n_threads)->UseRealTime();
    spdlog::drop("rotating_mt");

    // daily mt
    auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs_bench/daily_mt.log");
    benchmark::RegisterBenchmark("daily_mt", bench_logger, std::move(daily_mt))->Threads(n_threads);
    benchmark::RegisterBenchmark("daily_mt", bench_logger, std::move(daily_mt))->Threads(n_threads)->UseRealTime();
    spdlog::drop("daily_mt");

    benchmark::Initialize(&argc, argv);
    benchmark::RunSpecifiedBenchmarks();

}
<commit_msg>latency test update<commit_after>//
// Copyright(c) 2018 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//

//
// latency.cpp : spdlog latency benchmarks
//

#include "benchmark/benchmark.h"

#include "spdlog/spdlog.h"
#include "spdlog/async.h"
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/sinks/null_sink.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include <chrono>

#include "utils.h"
#include <atomic>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <string>
#include <thread>

using namespace std;
using namespace std::chrono;
using namespace spdlog;
using namespace spdlog::sinks;
using namespace utils;

void prepare_logdir()
{
    spdlog::info("Preparing logs_bench directory..");
#ifdef _WIN32
    system("if not exist logs mkdir logs_bench");
    system("del /F /Q logs\\*");
#else
    auto rv = system("mkdir -p logs_bench");
    if (rv != 0)
    {
        throw std::runtime_error("Failed to mkdir -p logs_bench");
    }
    rv = system("rm -f logs_bench/*");
    if (rv != 0)
    {
        throw std::runtime_error("Failed to rm -f logs_bench/*");
    }
#endif
}

void bench_c_string(benchmark::State& state, std::shared_ptr<spdlog::logger> logger)
{
    const char *msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pharetra metus cursus "
                      "lacus placerat congue. Nulla egestas, mauris a tincidunt tempus, enim lectus volutpat mi, eu consequat sem "
                      "libero nec massa. In dapibus ipsum a diam rhoncus gravida. Etiam non dapibus eros. Donec fringilla dui sed "
                      "augue pretium, nec scelerisque est maximus. Nullam convallis, sem nec blandit maximus, nisi turpis ornare "
                      "nisl, sit amet volutpat neque massa eu odio. Maecenas malesuada quam ex, posuere congue nibh turpis duis.";

    for (auto _ : state)
    {
        logger->info(msg);
    }

}

void bench_logger(benchmark::State& state, std::shared_ptr<spdlog::logger> logger)
{
    int i = 0;
    for (auto _ : state)
    {
        logger->info("Hello logger: msg number {}...............", ++i);
    }
}

int main(int argc, char *argv[])
{

    using spdlog::sinks::null_sink_st ;
    using spdlog::sinks::null_sink_mt ;
    using spdlog::sinks::basic_file_sink_st;
    using spdlog::sinks::basic_file_sink_mt;

    size_t file_size = 30 * 1024 * 1024;
    size_t rotating_files = 5;
    int n_threads = 10;
    int iters = 1000000;

    prepare_logdir();

    //
    // Single threaded bench
    //
    auto null_logger = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_st>());

    benchmark::RegisterBenchmark("null_sink_st-500_bytes_cstr", bench_c_string, null_logger)
           ->UseRealTime()
           ->Iterations(iters);
    benchmark::RegisterBenchmark("null_sink_st", bench_logger, null_logger)
            ->UseRealTime()
            ->Iterations(iters);

    // basic_st
    auto basic_st = spdlog::basic_logger_st("basic_st", "logs_bench/basic_st.log", true);
    benchmark::RegisterBenchmark("basic_st", bench_logger, std::move(basic_st))
            ->UseRealTime()
            ->Iterations(iters);
    spdlog::drop("basic_st");

    // rotating st
    auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs_bench/rotating_st.log", file_size, rotating_files);
    benchmark::RegisterBenchmark("rotating_st", bench_logger, std::move(rotating_st))
            ->UseRealTime()
            ->Iterations(iters);
    spdlog::drop("rotating_st");

    // daily st
    auto daily_st = spdlog::daily_logger_mt("daily_st", "logs_bench/daily_st.log");
    benchmark::RegisterBenchmark("daily_st", bench_logger, std::move(daily_st))
            ->UseRealTime()
            ->Iterations(iters);
    spdlog::drop("daily_st");

    //
    // Multi threaded bench, 10 using same logger concurrently
    //
    auto null_logger_mt = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>());
    benchmark::RegisterBenchmark("null_sink_mt", bench_logger, null_logger_mt)
            ->Threads(n_threads)
            ->UseRealTime()
            ->Iterations(iters/n_threads);

    // basic_mt
    auto basic_mt = spdlog::basic_logger_mt("basic_mt", "logs_bench/basic_mt.log", true);
    benchmark::RegisterBenchmark("basic_mt", bench_logger, std::move(basic_mt))
            ->Threads(n_threads)
            ->UseRealTime()
            ->Iterations(iters/n_threads);
    spdlog::drop("basic_mt");

    // rotating mt
    auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs_bench/rotating_mt.log", file_size, rotating_files);
    benchmark::RegisterBenchmark("rotating_mt", bench_logger, std::move(rotating_mt))
            ->Threads(n_threads)
            ->UseRealTime()
            ->Iterations(iters/n_threads);
    spdlog::drop("rotating_mt");

    // daily mt
    auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs_bench/daily_mt.log");
    benchmark::RegisterBenchmark("daily_mt", bench_logger, std::move(daily_mt))
            ->Threads(n_threads)
            ->UseRealTime()
            ->Iterations(iters/n_threads);
    spdlog::drop("daily_mt");

    benchmark::Initialize(&argc, argv);
    benchmark::RunSpecifiedBenchmarks();

}
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_ENTRY_HPP_INCLUDED
#define TORRENT_ENTRY_HPP_INCLUDED

/*
 *
 * This file declares the entry class. It is a
 * variant-type that can be an integer, list,
 * dictionary (map) or a string. This type is
 * used to hold bdecoded data (which is the
 * encoding BitTorrent messages uses).
 *
 * it has 4 accessors to access the actual
 * type of the object. They are:
 * integer()
 * string()
 * list()
 * dict()
 * The actual type has to match the type you
 * are asking for, otherwise you will get an
 * assertion failure.
 * When you default construct an entry, it is
 * uninitialized. You can initialize it through the
 * assignment operator, copy-constructor or
 * the constructor that takes a data_type enum.
 *
 *
 */

#include <map>
#include <list>
#include <string>
#include <stdexcept>

#include "libtorrent/size_type.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/error_code.hpp"

#if TORRENT_USE_IOSTREAM
#include <iosfwd>
#endif

namespace libtorrent
{

	struct TORRENT_EXPORT type_error: std::runtime_error
	{
		type_error(const char* error): std::runtime_error(error) {}
	};

	namespace detail
	{
		template<int v1, int v2>
		struct max2 { enum { value = v1>v2?v1:v2 }; };

		template<int v1, int v2, int v3>
		struct max3
		{
			enum
			{
				temp = max2<v1,v2>::value,
				value = temp>v3?temp:v3
			};
		};

		template<int v1, int v2, int v3, int v4>
		struct max4
		{
			enum
			{
				temp = max3<v1,v2, v3>::value,
				value = temp>v4?temp:v4
			};
		};
	}

	class entry;

	class TORRENT_EXPORT entry
	{
	public:

		// the key is always a string. If a generic entry would be allowed
		// as a key, sorting would become a problem (e.g. to compare a string
		// to a list). The definition doesn't mention such a limit though.
		typedef std::map<std::string, entry> dictionary_type;
		typedef std::string string_type;
		typedef std::list<entry> list_type;
		typedef size_type integer_type;

		enum data_type
		{
			int_t,
			string_t,
			list_t,
			dictionary_t,
			undefined_t
		};

		data_type type() const;

		entry(dictionary_type const&);
		entry(string_type const&);
		entry(list_type const&);
		entry(integer_type const&);

		entry();
		entry(data_type t);
		entry(entry const& e);
		~entry();

		bool operator==(entry const& e) const;

		void operator=(entry const&);
		void operator=(dictionary_type const&);
		void operator=(string_type const&);
		void operator=(list_type const&);
		void operator=(integer_type const&);

		integer_type& integer();
		const integer_type& integer() const;
		string_type& string();
		const string_type& string() const;
		list_type& list();
		const list_type& list() const;
		dictionary_type& dict();
		const dictionary_type& dict() const;

		void swap(entry& e);

		// these functions requires that the entry
		// is a dictionary, otherwise they will throw
		entry& operator[](char const* key);
		entry& operator[](std::string const& key);
#ifndef BOOST_NO_EXCEPTIONS
		const entry& operator[](char const* key) const;
		const entry& operator[](std::string const& key) const;
#endif
		entry* find_key(char const* key);
		entry const* find_key(char const* key) const;
		entry* find_key(std::string const& key);
		entry const* find_key(std::string const& key) const;

#if defined TORRENT_DEBUG && TORRENT_USE_IOSTREAM
		void print(std::ostream& os, int indent = 0) const;
#endif

	protected:

		void construct(data_type t);
		void copy(const entry& e);
		void destruct();

	private:

		data_type m_type;

#if defined(_MSC_VER) && _MSC_VER < 1310
		// workaround for msvc-bug.
		// assumes sizeof(map<string, char>) == sizeof(map<string, entry>)
		// and sizeof(list<char>) == sizeof(list<entry>)
		union
		{
			char data[
				detail::max4<sizeof(std::list<char>)
				, sizeof(std::map<std::string, char>)
				, sizeof(string_type)
				, sizeof(integer_type)>::value];
			integer_type dummy_aligner;
		};
#else
		union
		{
			char data[detail::max4<sizeof(list_type)
				, sizeof(dictionary_type)
				, sizeof(string_type)
				, sizeof(integer_type)>::value];
			integer_type dummy_aligner;
		};
#endif

#ifdef TORRENT_DEBUG
	public:
		// in debug mode this is set to false by bdecode
		// to indicate that the program has not yet queried
		// the type of this entry, and sould not assume
		// that it has a certain type. This is asserted in
		// the accessor functions. This does not apply if
		// exceptions are used.
		mutable bool m_type_queried;
#endif
	};

#if TORRENT_USE_IOSTREAM
	inline std::ostream& operator<<(std::ostream& os, const entry& e)
	{
		e.print(os, 0);
		return os;
	}
#endif

#ifndef BOOST_NO_EXCEPTIONS
	inline void throw_type_error()
	{
		throw libtorrent_exception(error_code(errors::invalid_entry_type
			, libtorrent_category));
	}
#endif

	inline entry::data_type entry::type() const
	{
#ifdef TORRENT_DEBUG
		m_type_queried = true;
#endif
		return m_type;
	}

	inline entry::~entry() { destruct(); }

	inline void entry::operator=(const entry& e)
	{
		destruct();
		copy(e);
	}

	inline entry::integer_type& entry::integer()
	{
		if (m_type == undefined_t) construct(int_t);
#ifndef BOOST_NO_EXCEPTIONS
		if (m_type != int_t) throw_type_error();
#elif defined TORRENT_DEBUG
		TORRENT_ASSERT(m_type_queried);
#endif
		TORRENT_ASSERT(m_type == int_t);
		return *reinterpret_cast<integer_type*>(data);
	}

	inline entry::integer_type const& entry::integer() const
	{
#ifndef BOOST_NO_EXCEPTIONS
		if (m_type != int_t) throw_type_error();
#elif defined TORRENT_DEBUG
		TORRENT_ASSERT(m_type_queried);
#endif
		TORRENT_ASSERT(m_type == int_t);
		return *reinterpret_cast<const integer_type*>(data);
	}

	inline entry::string_type& entry::string()
	{
		if (m_type == undefined_t) construct(string_t);
#ifndef BOOST_NO_EXCEPTIONS
		if (m_type != string_t) throw_type_error();
#elif defined TORRENT_DEBUG
		TORRENT_ASSERT(m_type_queried);
#endif
		TORRENT_ASSERT(m_type == string_t);
		return *reinterpret_cast<string_type*>(data);
	}

	inline entry::string_type const& entry::string() const
	{
#ifndef BOOST_NO_EXCEPTIONS
		if (m_type != string_t) throw_type_error();
#elif defined TORRENT_DEBUG
		TORRENT_ASSERT(m_type_queried);
#endif
		TORRENT_ASSERT(m_type == string_t);
		return *reinterpret_cast<const string_type*>(data);
	}

	inline entry::list_type& entry::list()
	{
		if (m_type == undefined_t) construct(list_t);
#ifndef BOOST_NO_EXCEPTIONS
		if (m_type != list_t) throw_type_error();
#elif defined TORRENT_DEBUG
		TORRENT_ASSERT(m_type_queried);
#endif
		TORRENT_ASSERT(m_type == list_t);
		return *reinterpret_cast<list_type*>(data);
	}

	inline entry::list_type const& entry::list() const
	{
#ifndef BOOST_NO_EXCEPTIONS
		if (m_type != list_t) throw_type_error();
#elif defined TORRENT_DEBUG
		TORRENT_ASSERT(m_type_queried);
#endif
		TORRENT_ASSERT(m_type == list_t);
		return *reinterpret_cast<const list_type*>(data);
	}

	inline entry::dictionary_type& entry::dict()
	{
		if (m_type == undefined_t) construct(dictionary_t);
#ifndef BOOST_NO_EXCEPTIONS
		if (m_type != dictionary_t) throw_type_error();
#elif defined TORRENT_DEBUG
		TORRENT_ASSERT(m_type_queried);
#endif
		TORRENT_ASSERT(m_type == dictionary_t);
		return *reinterpret_cast<dictionary_type*>(data);
	}

	inline entry::dictionary_type const& entry::dict() const
	{
#ifndef BOOST_NO_EXCEPTIONS
		if (m_type != dictionary_t) throw_type_error();
#elif defined TORRENT_DEBUG
		TORRENT_ASSERT(m_type_queried);
#endif
		TORRENT_ASSERT(m_type == dictionary_t);
		return *reinterpret_cast<const dictionary_type*>(data);
	}

}

#endif // TORRENT_ENTRY_HPP_INCLUDED

<commit_msg>fixed inconsistent use of preprocessor macro for entry::print<commit_after>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_ENTRY_HPP_INCLUDED
#define TORRENT_ENTRY_HPP_INCLUDED

/*
 *
 * This file declares the entry class. It is a
 * variant-type that can be an integer, list,
 * dictionary (map) or a string. This type is
 * used to hold bdecoded data (which is the
 * encoding BitTorrent messages uses).
 *
 * it has 4 accessors to access the actual
 * type of the object. They are:
 * integer()
 * string()
 * list()
 * dict()
 * The actual type has to match the type you
 * are asking for, otherwise you will get an
 * assertion failure.
 * When you default construct an entry, it is
 * uninitialized. You can initialize it through the
 * assignment operator, copy-constructor or
 * the constructor that takes a data_type enum.
 *
 *
 */

#include <map>
#include <list>
#include <string>
#include <stdexcept>

#include "libtorrent/size_type.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/error_code.hpp"

#if TORRENT_USE_IOSTREAM
#include <iosfwd>
#endif

namespace libtorrent
{

	struct TORRENT_EXPORT type_error: std::runtime_error
	{
		type_error(const char* error): std::runtime_error(error) {}
	};

	namespace detail
	{
		template<int v1, int v2>
		struct max2 { enum { value = v1>v2?v1:v2 }; };

		template<int v1, int v2, int v3>
		struct max3
		{
			enum
			{
				temp = max2<v1,v2>::value,
				value = temp>v3?temp:v3
			};
		};

		template<int v1, int v2, int v3, int v4>
		struct max4
		{
			enum
			{
				temp = max3<v1,v2, v3>::value,
				value = temp>v4?temp:v4
			};
		};
	}

	class entry;

	class TORRENT_EXPORT entry
	{
	public:

		// the key is always a string. If a generic entry would be allowed
		// as a key, sorting would become a problem (e.g. to compare a string
		// to a list). The definition doesn't mention such a limit though.
		typedef std::map<std::string, entry> dictionary_type;
		typedef std::string string_type;
		typedef std::list<entry> list_type;
		typedef size_type integer_type;

		enum data_type
		{
			int_t,
			string_t,
			list_t,
			dictionary_t,
			undefined_t
		};

		data_type type() const;

		entry(dictionary_type const&);
		entry(string_type const&);
		entry(list_type const&);
		entry(integer_type const&);

		entry();
		entry(data_type t);
		entry(entry const& e);
		~entry();

		bool operator==(entry const& e) const;

		void operator=(entry const&);
		void operator=(dictionary_type const&);
		void operator=(string_type const&);
		void operator=(list_type const&);
		void operator=(integer_type const&);

		integer_type& integer();
		const integer_type& integer() const;
		string_type& string();
		const string_type& string() const;
		list_type& list();
		const list_type& list() const;
		dictionary_type& dict();
		const dictionary_type& dict() const;

		void swap(entry& e);

		// these functions requires that the entry
		// is a dictionary, otherwise they will throw
		entry& operator[](char const* key);
		entry& operator[](std::string const& key);
#ifndef BOOST_NO_EXCEPTIONS
		const entry& operator[](char const* key) const;
		const entry& operator[](std::string const& key) const;
#endif
		entry* find_key(char const* key);
		entry const* find_key(char const* key) const;
		entry* find_key(std::string const& key);
		entry const* find_key(std::string const& key) const;

#if defined TORRENT_DEBUG && TORRENT_USE_IOSTREAM
		void print(std::ostream& os, int indent = 0) const;
#endif

	protected:

		void construct(data_type t);
		void copy(const entry& e);
		void destruct();

	private:

		data_type m_type;

#if defined(_MSC_VER) && _MSC_VER < 1310
		// workaround for msvc-bug.
		// assumes sizeof(map<string, char>) == sizeof(map<string, entry>)
		// and sizeof(list<char>) == sizeof(list<entry>)
		union
		{
			char data[
				detail::max4<sizeof(std::list<char>)
				, sizeof(std::map<std::string, char>)
				, sizeof(string_type)
				, sizeof(integer_type)>::value];
			integer_type dummy_aligner;
		};
#else
		union
		{
			char data[detail::max4<sizeof(list_type)
				, sizeof(dictionary_type)
				, sizeof(string_type)
				, sizeof(integer_type)>::value];
			integer_type dummy_aligner;
		};
#endif

#ifdef TORRENT_DEBUG
	public:
		// in debug mode this is set to false by bdecode
		// to indicate that the program has not yet queried
		// the type of this entry, and sould not assume
		// that it has a certain type. This is asserted in
		// the accessor functions. This does not apply if
		// exceptions are used.
		mutable bool m_type_queried;
#endif
	};

#if defined TORRENT_DEBUG && TORRENT_USE_IOSTREAM
	inline std::ostream& operator<<(std::ostream& os, const entry& e)
	{
		e.print(os, 0);
		return os;
	}
#endif

#ifndef BOOST_NO_EXCEPTIONS
	inline void throw_type_error()
	{
		throw libtorrent_exception(error_code(errors::invalid_entry_type
			, libtorrent_category));
	}
#endif

	inline entry::data_type entry::type() const
	{
#ifdef TORRENT_DEBUG
		m_type_queried = true;
#endif
		return m_type;
	}

	inline entry::~entry() { destruct(); }

	inline void entry::operator=(const entry& e)
	{
		destruct();
		copy(e);
	}

	inline entry::integer_type& entry::integer()
	{
		if (m_type == undefined_t) construct(int_t);
#ifndef BOOST_NO_EXCEPTIONS
		if (m_type != int_t) throw_type_error();
#elif defined TORRENT_DEBUG
		TORRENT_ASSERT(m_type_queried);
#endif
		TORRENT_ASSERT(m_type == int_t);
		return *reinterpret_cast<integer_type*>(data);
	}

	inline entry::integer_type const& entry::integer() const
	{
#ifndef BOOST_NO_EXCEPTIONS
		if (m_type != int_t) throw_type_error();
#elif defined TORRENT_DEBUG
		TORRENT_ASSERT(m_type_queried);
#endif
		TORRENT_ASSERT(m_type == int_t);
		return *reinterpret_cast<const integer_type*>(data);
	}

	inline entry::string_type& entry::string()
	{
		if (m_type == undefined_t) construct(string_t);
#ifndef BOOST_NO_EXCEPTIONS
		if (m_type != string_t) throw_type_error();
#elif defined TORRENT_DEBUG
		TORRENT_ASSERT(m_type_queried);
#endif
		TORRENT_ASSERT(m_type == string_t);
		return *reinterpret_cast<string_type*>(data);
	}

	inline entry::string_type const& entry::string() const
	{
#ifndef BOOST_NO_EXCEPTIONS
		if (m_type != string_t) throw_type_error();
#elif defined TORRENT_DEBUG
		TORRENT_ASSERT(m_type_queried);
#endif
		TORRENT_ASSERT(m_type == string_t);
		return *reinterpret_cast<const string_type*>(data);
	}

	inline entry::list_type& entry::list()
	{
		if (m_type == undefined_t) construct(list_t);
#ifndef BOOST_NO_EXCEPTIONS
		if (m_type != list_t) throw_type_error();
#elif defined TORRENT_DEBUG
		TORRENT_ASSERT(m_type_queried);
#endif
		TORRENT_ASSERT(m_type == list_t);
		return *reinterpret_cast<list_type*>(data);
	}

	inline entry::list_type const& entry::list() const
	{
#ifndef BOOST_NO_EXCEPTIONS
		if (m_type != list_t) throw_type_error();
#elif defined TORRENT_DEBUG
		TORRENT_ASSERT(m_type_queried);
#endif
		TORRENT_ASSERT(m_type == list_t);
		return *reinterpret_cast<const list_type*>(data);
	}

	inline entry::dictionary_type& entry::dict()
	{
		if (m_type == undefined_t) construct(dictionary_t);
#ifndef BOOST_NO_EXCEPTIONS
		if (m_type != dictionary_t) throw_type_error();
#elif defined TORRENT_DEBUG
		TORRENT_ASSERT(m_type_queried);
#endif
		TORRENT_ASSERT(m_type == dictionary_t);
		return *reinterpret_cast<dictionary_type*>(data);
	}

	inline entry::dictionary_type const& entry::dict() const
	{
#ifndef BOOST_NO_EXCEPTIONS
		if (m_type != dictionary_t) throw_type_error();
#elif defined TORRENT_DEBUG
		TORRENT_ASSERT(m_type_queried);
#endif
		TORRENT_ASSERT(m_type == dictionary_t);
		return *reinterpret_cast<const dictionary_type*>(data);
	}

}

#endif // TORRENT_ENTRY_HPP_INCLUDED

<|endoftext|>


<commit_before>///
/// @file   Wheel.hpp
/// @brief  Wheel factorization is used to skip multiles of
///         small primes in the sieve of Eratosthenes.
///
/// Copyright (C) 2019 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#ifndef WHEEL_HPP
#define WHEEL_HPP

#include "config.hpp"
#include "primesieve_error.hpp"
#include "Bucket.hpp"

#include <stdint.h>
#include <algorithm>
#include <cassert>
#include <string>

namespace primesieve {

/// The WheelInit data structure is used to calculate the
/// first multiple >= start of each sieving prime
///
struct WheelInit
{
  uint8_t nextMultipleFactor;
  uint8_t wheelIndex;
};

extern const WheelInit wheel30Init[30];
extern const WheelInit wheel210Init[210];

/// The WheelElement data structure is used to skip multiples
/// of small primes using wheel factorization
///
struct WheelElement
{
  /// Bitmask used to unset the bit corresponding to the current
  /// multiple of a SievingPrime object
  uint8_t unsetBit;
  /// Factor used to calculate the next multiple of a sieving prime
  /// that is not divisible by any of the wheel factors
  uint8_t nextMultipleFactor;
  /// Overflow needed to correct the next multiple index
  /// (due to sievingPrime = prime / 30)
  uint8_t correct;
  /// Used to calculate the next wheel index:
  /// wheelIndex += next;
  int8_t next;
};

extern const WheelElement wheel30[8*8];
extern const WheelElement wheel210[48*8];

/// The abstract Wheel class is used skip multiples of small
/// primes in the sieve of Eratosthenes. The EratSmall,
/// EratMedium and EratBig classes are derived from Wheel.
///
template <int MODULO, int SIZE, const WheelElement* WHEEL, const WheelInit* INIT>
class Wheel
{
public:
  /// Add a new sieving prime to the sieving algorithm.
  /// Calculate the first multiple > segmentLow of prime and the
  /// position within the sieve array of that multiple
  /// and its wheel index. When done store the sieving prime.
  ///
  void addSievingPrime(uint64_t prime, uint64_t segmentLow)
  {
    assert(segmentLow % 30 == 0);
    segmentLow += 6;
    // calculate the first multiple (of prime) > segmentLow
    uint64_t quotient = (segmentLow / prime) + 1;
    quotient = std::max(prime, quotient);
    uint64_t multiple = prime * quotient;
    // prime not needed for sieving
    if (multiple > stop_ ||
        multiple < segmentLow)
      return;
    // calculate the next multiple of prime that is not
    // divisible by any of the wheel's factors
    uint64_t nextMultipleFactor = INIT[quotient % MODULO].nextMultipleFactor;
    uint64_t nextMultiple = prime * nextMultipleFactor;
    if (nextMultiple > stop_ - multiple)
      return;
    nextMultiple += multiple - segmentLow;
    uint64_t multipleIndex = nextMultiple / 30;
    uint64_t wheelIndex = wheelOffsets_[prime % 30] + INIT[quotient % MODULO].wheelIndex;
    storeSievingPrime(prime, multipleIndex, wheelIndex);
  }

protected:
  void init(uint64_t stop, uint64_t sieveSize)
  {
    stop_ = stop;
    uint64_t maxSieveSize = SievingPrime::MAX_MULTIPLEINDEX + 1;

    if (sieveSize > maxSieveSize)
      throw primesieve_error("Wheel: sieveSize > " + std::to_string(maxSieveSize));
  }

  virtual ~Wheel() = default;
  virtual void storeSievingPrime(uint64_t, uint64_t, uint64_t) = 0;

  static uint64_t getMaxFactor()
  {
    return WHEEL[0].nextMultipleFactor;
  }

  /// Cross-off the current multiple of sievingPrime
  /// and calculate its next multiple
  ///
  static void unsetBit(uint8_t* sieve,
                       uint64_t sievingPrime,
                       uint64_t* multipleIndex,
                       uint64_t* wheelIndex)
  {
    sieve[*multipleIndex] &= WHEEL[*wheelIndex].unsetBit;
    *multipleIndex        += WHEEL[*wheelIndex].nextMultipleFactor * sievingPrime;
    *multipleIndex        += WHEEL[*wheelIndex].correct;
    *wheelIndex           += WHEEL[*wheelIndex].next;
  }

private:
  static const uint64_t wheelOffsets_[30];
  uint64_t stop_ = 0;
};

template <int MODULO, int SIZE, const WheelElement* WHEEL, const WheelInit* INIT>
const uint64_t
Wheel<MODULO, SIZE, WHEEL, INIT>::wheelOffsets_[30] =
{
  0, SIZE * 7, 0, 0, 0, 0,
  0, SIZE * 0, 0, 0, 0, SIZE * 1,
  0, SIZE * 2, 0, 0, 0, SIZE * 3,
  0, SIZE * 4, 0, 0, 0, SIZE * 5,
  0, 0,        0, 0, 0, SIZE * 6
};

/// 3rd wheel, skips multiples of 2, 3 and 5
using Wheel30_t = Wheel<30, 8, wheel30, wheel30Init>;

/// 4th wheel, skips multiples of 2, 3, 5 and 7
using Wheel210_t = Wheel<210, 48, wheel210, wheel210Init>;

} // namespace

#endif
<commit_msg>Update documentation<commit_after>///
/// @file   Wheel.hpp
/// @brief  Wheel factorization is used to skip multiles of
///         small primes in the sieve of Eratosthenes.
///
/// Copyright (C) 2019 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#ifndef WHEEL_HPP
#define WHEEL_HPP

#include "config.hpp"
#include "primesieve_error.hpp"
#include "Bucket.hpp"

#include <stdint.h>
#include <algorithm>
#include <cassert>
#include <string>

namespace primesieve {

/// The WheelInit data structure is used to calculate the
/// first multiple >= start of each sieving prime
///
struct WheelInit
{
  uint8_t nextMultipleFactor;
  uint8_t wheelIndex;
};

extern const WheelInit wheel30Init[30];
extern const WheelInit wheel210Init[210];

/// The WheelElement data structure is used to skip multiples
/// of small primes using wheel factorization
///
struct WheelElement
{
  /// Bitmask used to unset the bit corresponding to the current
  /// multiple of a SievingPrime object
  uint8_t unsetBit;
  /// Factor used to calculate the next multiple of a sieving prime
  /// that is not divisible by any of the wheel factors
  uint8_t nextMultipleFactor;
  /// Overflow needed to correct the next multiple index
  /// (due to sievingPrime = prime / 30)
  uint8_t correct;
  /// Used to calculate the next wheel index:
  /// wheelIndex += next;
  int8_t next;
};

extern const WheelElement wheel30[8*8];
extern const WheelElement wheel210[48*8];

/// The abstract Wheel class is used skip multiples of small
/// primes in the sieve of Eratosthenes. The EratSmall,
/// EratMedium and EratBig classes are derived from Wheel.
///
template <int MODULO, int SIZE, const WheelElement* WHEEL, const WheelInit* INIT>
class Wheel
{
public:
  /// Add a new sieving prime to the sieving algorithm.
  /// Calculate the first multiple > segmentLow of prime and
  /// the position within the sieve array of that multiple
  /// and its wheel index. When done store the sieving prime.
  ///
  void addSievingPrime(uint64_t prime, uint64_t segmentLow)
  {
    assert(segmentLow % 30 == 0);

    // This hack is required because in primesieve the 8
    // bits of each byte (of the sieve array) correspond to
    // the offsets { 7, 11, 13, 17, 19, 23, 29, 31 }.
    // So we are looking for: multiples > segmentLow + 6.
    segmentLow += 6;

    // calculate the first multiple (of prime) > segmentLow
    uint64_t quotient = (segmentLow / prime) + 1;
    quotient = std::max(prime, quotient);
    uint64_t multiple = prime * quotient;
    // prime not needed for sieving
    if (multiple > stop_ ||
        multiple < segmentLow)
      return;

    // calculate the next multiple of prime that is not
    // divisible by any of the wheel's factors
    uint64_t nextMultipleFactor = INIT[quotient % MODULO].nextMultipleFactor;
    uint64_t nextMultiple = prime * nextMultipleFactor;
    if (nextMultiple > stop_ - multiple)
      return;

    nextMultiple += multiple - segmentLow;
    uint64_t multipleIndex = nextMultiple / 30;
    uint64_t wheelIndex = wheelOffsets_[prime % 30] + INIT[quotient % MODULO].wheelIndex;
    storeSievingPrime(prime, multipleIndex, wheelIndex);
  }

protected:
  void init(uint64_t stop, uint64_t sieveSize)
  {
    stop_ = stop;
    uint64_t maxSieveSize = SievingPrime::MAX_MULTIPLEINDEX + 1;

    if (sieveSize > maxSieveSize)
      throw primesieve_error("Wheel: sieveSize > " + std::to_string(maxSieveSize));
  }

  virtual ~Wheel() = default;
  virtual void storeSievingPrime(uint64_t, uint64_t, uint64_t) = 0;

  static uint64_t getMaxFactor()
  {
    return WHEEL[0].nextMultipleFactor;
  }

  /// Cross-off the current multiple of sievingPrime
  /// and calculate its next multiple
  ///
  static void unsetBit(uint8_t* sieve,
                       uint64_t sievingPrime,
                       uint64_t* multipleIndex,
                       uint64_t* wheelIndex)
  {
    sieve[*multipleIndex] &= WHEEL[*wheelIndex].unsetBit;
    *multipleIndex        += WHEEL[*wheelIndex].nextMultipleFactor * sievingPrime;
    *multipleIndex        += WHEEL[*wheelIndex].correct;
    *wheelIndex           += WHEEL[*wheelIndex].next;
  }

private:
  static const uint64_t wheelOffsets_[30];
  uint64_t stop_ = 0;
};

template <int MODULO, int SIZE, const WheelElement* WHEEL, const WheelInit* INIT>
const uint64_t
Wheel<MODULO, SIZE, WHEEL, INIT>::wheelOffsets_[30] =
{
  0, SIZE * 7, 0, 0, 0, 0,
  0, SIZE * 0, 0, 0, 0, SIZE * 1,
  0, SIZE * 2, 0, 0, 0, SIZE * 3,
  0, SIZE * 4, 0, 0, 0, SIZE * 5,
  0, 0,        0, 0, 0, SIZE * 6
};

/// 3rd wheel, skips multiples of 2, 3 and 5
using Wheel30_t = Wheel<30, 8, wheel30, wheel30Init>;

/// 4th wheel, skips multiples of 2, 3, 5 and 7
using Wheel210_t = Wheel<210, 48, wheel210, wheel210Init>;

} // namespace

#endif
<|endoftext|>