<commit_before>/* Copyright 2017 The TensorFlow 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.
==============================================================================*/

#define EIGEN_USE_THREADS

#include <algorithm>
#include <numeric>
#include <unordered_map>
#include <utility>
#include <vector>

#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/framework/tensor_util.h"
#include "tensorflow/core/framework/types.h"
#include "tensorflow/core/lib/gtl/inlined_vector.h"
#include "tensorflow/core/util/sparse/sparse_tensor.h"

namespace tensorflow {

using CPUDevice = Eigen::ThreadPoolDevice;

template <typename T>
class SparseFillEmptyRowsOp : public OpKernel {
 public:
  explicit SparseFillEmptyRowsOp(OpKernelConstruction* context)
      : OpKernel(context) {}

  void Compute(OpKernelContext* context) override {
    const Tensor* indices_t;
    const Tensor* values_t;
    const Tensor* dense_shape_t;
    const Tensor* default_value_t;
    OP_REQUIRES_OK(context, context->input("indices", &indices_t));
    OP_REQUIRES_OK(context, context->input("values", &values_t));
    OP_REQUIRES_OK(context, context->input("dense_shape", &dense_shape_t));
    OP_REQUIRES_OK(context, context->input("default_value", &default_value_t));

    const CPUDevice& d = context->eigen_device<CPUDevice>();

    OP_REQUIRES(context, TensorShapeUtils::IsVector(dense_shape_t->shape()),
                errors::InvalidArgument("dense_shape must be a vector, saw: ",
                                        dense_shape_t->shape().DebugString()));
    OP_REQUIRES(context, TensorShapeUtils::IsMatrix(indices_t->shape()),
                errors::InvalidArgument("indices must be a matrix, saw: ",
                                        indices_t->shape().DebugString()));
    OP_REQUIRES(context, TensorShapeUtils::IsVector(values_t->shape()),
                errors::InvalidArgument("values must be a vector, saw: ",
                                        values_t->shape().DebugString()));
    OP_REQUIRES(
        context, TensorShapeUtils::IsScalar(default_value_t->shape()),
        errors::InvalidArgument("default_value must be a scalar, saw: ",
                                default_value_t->shape().DebugString()));
    // TODO(ebrevdo): add shape checks between values, indices,
    // dense_shape.  Also add check that dense rank > 0.

    const T& default_value = default_value_t->scalar<T>()();
    const auto indices = indices_t->matrix<int64>();
    const auto values = values_t->vec<T>();
    const auto dense_shape = dense_shape_t->vec<int64>();

    const int64 N = indices_t->shape().dim_size(0);
    const int64 dense_rows = dense_shape(0);

    Tensor* empty_row_indicator_t;
    OP_REQUIRES_OK(context, context->allocate_output("empty_row_indicator",
                                                     TensorShape({dense_rows}),
                                                     &empty_row_indicator_t));
    auto empty_row_indicator = empty_row_indicator_t->vec<bool>();
    Tensor* reverse_index_map_t;
    OP_REQUIRES_OK(
        context, context->allocate_output("reverse_index_map", TensorShape({N}),
                                          &reverse_index_map_t));
    auto reverse_index_map = reverse_index_map_t->vec<int64>();

    int rank = indices_t->shape().dim_size(1);

    if (dense_rows == 0) {
      OP_REQUIRES(
          context, N == 0,
          errors::InvalidArgument("Received SparseTensor with dense_shape[0] = "
                                  "0 but indices.shape[0] = ",
                                  N));
      Tensor* output_indices_t;
      TensorShape output_indices_shape({0, rank});
      OP_REQUIRES_OK(context, context->allocate_output("output_indices",
                                                       output_indices_shape,
                                                       &output_indices_t));
      Tensor* output_values_t;
      OP_REQUIRES_OK(context,
                     context->allocate_output("output_values", TensorShape({0}),
                                              &output_values_t));

      // Exit early, nothing more to do.
      return;
    }

    Tensor scratch_t;
    OP_REQUIRES_OK(context,
                   context->allocate_temp(DT_INT64, TensorShape({dense_rows}),
                                          &scratch_t));
    auto scratch = scratch_t.vec<int64>();
    scratch.device(d) = scratch.constant(0);
    for (int i = 0; i < N; ++i) {
      const int64 row = indices(i, 0);
      OP_REQUIRES(context, row >= 0 && row < dense_rows,
                  errors::InvalidArgument("indices(", i, ", 0) is invalid: ",
                                          row, " >= ", dense_rows));
      ++scratch(indices(i, 0));
    }
    for (int row = 0; row < dense_rows; ++row) {
      // Scratch here describes the number of elements in this dense row
      empty_row_indicator(row) = (scratch(row) == 0);
      // In filled version, each row has at least one element.
      scratch(row) = std::max(scratch(row), int64{1});
      // Update scratch to represent the number of elements up to and
      // including dense_row + 1:
      //  scratch(0) == #{elements of row 0}
      //  scratch(1) == #{elements of row 1} + #{elements of row 0}
      //  ..
      //  scratch(i) == starting index for elements in row i + 1.
      if (row > 0) {
        scratch(row) += scratch(row - 1);
      }
    }
    Tensor* output_indices_t;
    const int64 N_full = scratch(dense_rows - 1);
    TensorShape output_indices_shape({N_full, rank});
    OP_REQUIRES_OK(context, context->allocate_output("output_indices",
                                                     output_indices_shape,
                                                     &output_indices_t));
    auto output_indices = output_indices_t->matrix<int64>();
    output_indices.device(d) = output_indices.constant(0);

    Tensor* output_values_t;
    OP_REQUIRES_OK(
        context, context->allocate_output(
                     "output_values", TensorShape({N_full}), &output_values_t));
    auto output_values = output_values_t->vec<T>();
    output_values.device(d) = output_values.constant(default_value);

    Tensor filled_count_t;
    OP_REQUIRES_OK(context,
                   context->allocate_temp(DT_INT64, TensorShape({dense_rows}),
                                          &filled_count_t));
    auto filled_count = filled_count_t.vec<int64>();
    filled_count.device(d) = filled_count.constant(0);

    // Fill in values for rows that are not missing
    for (int64 i = 0; i < N; ++i) {
      const int64 row = indices(i, 0);
      int64& offset = filled_count(row);
      const int64 output_i = ((row == 0) ? 0 : scratch(row - 1)) + offset;
      offset++;  // Increment the filled count for this row.
      std::copy_n(&indices(i, 0), rank, &output_indices(output_i, 0));
      output_values(output_i) = values(i);
      // We'll need this reverse index map to backprop correctly.
      reverse_index_map(i) = output_i;
    }

    // Fill in values for rows that are missing
    for (int64 row = 0; row < dense_rows; ++row) {
      const int64 row_count = filled_count(row);
      if (row_count == 0) {  // We haven't filled this row
        const int64 starting_index = (row == 0) ? 0 : scratch(row - 1);
        // Remaining index values were set to zero already.
        // The value at this index was set to default_value already.
        // Just need to set the row index in the right location.
        output_indices(starting_index, 0) = row;
      }
    }
  }
};

#define REGISTER_KERNELS(type)                            \
  REGISTER_KERNEL_BUILDER(Name("SparseFillEmptyRows")     \
                              .Device(DEVICE_CPU)         \
                              .TypeConstraint<type>("T"), \
                          SparseFillEmptyRowsOp<type>)

TF_CALL_ALL_TYPES(REGISTER_KERNELS);
#undef REGISTER_KERNELS

template <typename T>
class SparseFillEmptyRowsGradOp : public OpKernel {
 public:
  explicit SparseFillEmptyRowsGradOp(OpKernelConstruction* context)
      : OpKernel(context) {}

  void Compute(OpKernelContext* context) override {
    const Tensor* reverse_index_map_t;
    const Tensor* grad_values_t;
    OP_REQUIRES_OK(context,
                   context->input("reverse_index_map", &reverse_index_map_t));
    OP_REQUIRES_OK(context, context->input("grad_values", &grad_values_t));

    const CPUDevice& d = context->eigen_device<CPUDevice>();

    OP_REQUIRES(
        context, TensorShapeUtils::IsVector(reverse_index_map_t->shape()),
        errors::InvalidArgument("reverse_index_map must be a vector, saw: ",
                                reverse_index_map_t->shape().DebugString()));

    const auto reverse_index_map = reverse_index_map_t->vec<int64>();
    const auto grad_values = grad_values_t->vec<T>();

    const int64 N = reverse_index_map_t->shape().dim_size(0);
    const int64 N_full = grad_values_t->shape().dim_size(0);

    Tensor* d_values_t;
    OP_REQUIRES_OK(context, context->allocate_output(
                                "d_values", TensorShape({N}), &d_values_t));
    auto d_values = d_values_t->vec<T>();
    Tensor* d_default_value_t;
    OP_REQUIRES_OK(context,
                   context->allocate_output("d_default_value", TensorShape({}),
                                            &d_default_value_t));
    T& d_default_value = d_default_value_t->scalar<T>()();
    d_default_value = T();

    Tensor visited_t;
    OP_REQUIRES_OK(context, context->allocate_temp(
                                DT_BOOL, TensorShape({N_full}), &visited_t));
    auto visited = visited_t.vec<bool>();
    visited.device(d) = visited.constant(false);

    for (int i = 0; i < N; ++i) {
      // Locate the index of the output of the forward prop associated
      // with this location in the input of the forward prop.  Copy
      // the gradient into it.  Mark it as visited.
      d_values(i) = grad_values(reverse_index_map(i));
      visited(reverse_index_map(i)) = true;
    }
    for (int j = 0; j < N_full; ++j) {
      // The default value gradient gets the accumulated remainder of
      // the backprop values (since the default value was used to fill
      // in these slots in the forward calculation).
      if (!visited(j)) {
        d_default_value += grad_values(j);
      }
    }
  }
};

#define REGISTER_KERNELS(type)                            \
  REGISTER_KERNEL_BUILDER(Name("SparseFillEmptyRowsGrad") \
                              .Device(DEVICE_CPU)         \
                              .TypeConstraint<type>("T"), \
                          SparseFillEmptyRowsGradOp<type>)

TF_CALL_NUMBER_TYPES(REGISTER_KERNELS);
#undef REGISTER_KERNELS
}  // namespace tensorflow
<commit_msg>[SparseFillEmptyRowsOp] Use integer input/output indices instead of string names.<commit_after>/* Copyright 2017 The TensorFlow 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.
==============================================================================*/

#define EIGEN_USE_THREADS

#include <algorithm>
#include <numeric>
#include <unordered_map>
#include <utility>
#include <vector>

#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/framework/tensor_util.h"
#include "tensorflow/core/framework/types.h"
#include "tensorflow/core/lib/gtl/inlined_vector.h"
#include "tensorflow/core/util/sparse/sparse_tensor.h"

namespace tensorflow {

using CPUDevice = Eigen::ThreadPoolDevice;

template <typename T>
class SparseFillEmptyRowsOp : public OpKernel {
 public:
  explicit SparseFillEmptyRowsOp(OpKernelConstruction* context)
      : OpKernel(context) {}

  void Compute(OpKernelContext* context) override {
    const int kIndicesInput = 0;
    const int kValuesInput = 1;
    const int kDenseShapeInput = 2;
    const int kDefaultValueInput = 3;

    const int kOutputIndicesOutput = 0;
    const int kOutputValuesOutput = 1;
    const int kEmptyRowIndicatorOutput = 2;
    const int kReverseIndexMapOutput = 3;

    const Tensor& indices_t = context->input(kIndicesInput);
    const Tensor& values_t = context->input(kValuesInput);
    const Tensor& dense_shape_t = context->input(kDenseShapeInput);
    const Tensor& default_value_t = context->input(kDefaultValueInput);

    const CPUDevice& d = context->eigen_device<CPUDevice>();

    OP_REQUIRES(context, TensorShapeUtils::IsVector(dense_shape_t.shape()),
                errors::InvalidArgument("dense_shape must be a vector, saw: ",
                                        dense_shape_t.shape().DebugString()));
    OP_REQUIRES(context, TensorShapeUtils::IsMatrix(indices_t.shape()),
                errors::InvalidArgument("indices must be a matrix, saw: ",
                                        indices_t.shape().DebugString()));
    OP_REQUIRES(context, TensorShapeUtils::IsVector(values_t.shape()),
                errors::InvalidArgument("values must be a vector, saw: ",
                                        values_t.shape().DebugString()));
    OP_REQUIRES(context, TensorShapeUtils::IsScalar(default_value_t.shape()),
                errors::InvalidArgument("default_value must be a scalar, saw: ",
                                        default_value_t.shape().DebugString()));
    // TODO(ebrevdo): add shape checks between values, indices,
    // dense_shape.  Also add check that dense rank > 0.

    const T& default_value = default_value_t.scalar<T>()();
    const auto indices = indices_t.matrix<int64>();
    const auto values = values_t.vec<T>();
    const auto dense_shape = dense_shape_t.vec<int64>();

    const int64 N = indices_t.shape().dim_size(0);
    const int64 dense_rows = dense_shape(0);

    Tensor* empty_row_indicator_t;
    OP_REQUIRES_OK(context, context->allocate_output(kEmptyRowIndicatorOutput,
                                                     TensorShape({dense_rows}),
                                                     &empty_row_indicator_t));
    auto empty_row_indicator = empty_row_indicator_t->vec<bool>();
    Tensor* reverse_index_map_t;
    OP_REQUIRES_OK(context, context->allocate_output(kReverseIndexMapOutput,
                                                     TensorShape({N}),
                                                     &reverse_index_map_t));
    auto reverse_index_map = reverse_index_map_t->vec<int64>();

    int rank = indices_t.shape().dim_size(1);

    if (dense_rows == 0) {
      OP_REQUIRES(
          context, N == 0,
          errors::InvalidArgument("Received SparseTensor with dense_shape[0] = "
                                  "0 but indices.shape[0] = ",
                                  N));
      Tensor* output_indices_t;
      TensorShape output_indices_shape({0, rank});
      OP_REQUIRES_OK(context, context->allocate_output(kOutputIndicesOutput,
                                                       output_indices_shape,
                                                       &output_indices_t));
      Tensor* output_values_t;
      OP_REQUIRES_OK(context, context->allocate_output(kOutputValuesOutput,
                                                       TensorShape({0}),
                                                       &output_values_t));

      // Exit early, nothing more to do.
      return;
    }

    Tensor scratch_t;
    OP_REQUIRES_OK(context,
                   context->allocate_temp(DT_INT64, TensorShape({dense_rows}),
                                          &scratch_t));
    auto scratch = scratch_t.vec<int64>();
    scratch.device(d) = scratch.constant(0);
    for (int i = 0; i < N; ++i) {
      const int64 row = indices(i, 0);
      OP_REQUIRES(context, row >= 0 && row < dense_rows,
                  errors::InvalidArgument("indices(", i, ", 0) is invalid: ",
                                          row, " >= ", dense_rows));
      ++scratch(indices(i, 0));
    }
    for (int row = 0; row < dense_rows; ++row) {
      // Scratch here describes the number of elements in this dense row
      empty_row_indicator(row) = (scratch(row) == 0);
      // In filled version, each row has at least one element.
      scratch(row) = std::max(scratch(row), int64{1});
      // Update scratch to represent the number of elements up to and
      // including dense_row + 1:
      //  scratch(0) == #{elements of row 0}
      //  scratch(1) == #{elements of row 1} + #{elements of row 0}
      //  ..
      //  scratch(i) == starting index for elements in row i + 1.
      if (row > 0) {
        scratch(row) += scratch(row - 1);
      }
    }
    Tensor* output_indices_t;
    const int64 N_full = scratch(dense_rows - 1);
    TensorShape output_indices_shape({N_full, rank});
    OP_REQUIRES_OK(context, context->allocate_output(kOutputIndicesOutput,
                                                     output_indices_shape,
                                                     &output_indices_t));
    auto output_indices = output_indices_t->matrix<int64>();
    output_indices.device(d) = output_indices.constant(0);

    Tensor* output_values_t;
    OP_REQUIRES_OK(context, context->allocate_output(kOutputValuesOutput,
                                                     TensorShape({N_full}),
                                                     &output_values_t));
    auto output_values = output_values_t->vec<T>();
    output_values.device(d) = output_values.constant(default_value);

    Tensor filled_count_t;
    OP_REQUIRES_OK(context,
                   context->allocate_temp(DT_INT64, TensorShape({dense_rows}),
                                          &filled_count_t));
    auto filled_count = filled_count_t.vec<int64>();
    filled_count.device(d) = filled_count.constant(0);

    // Fill in values for rows that are not missing
    for (int64 i = 0; i < N; ++i) {
      const int64 row = indices(i, 0);
      int64& offset = filled_count(row);
      const int64 output_i = ((row == 0) ? 0 : scratch(row - 1)) + offset;
      offset++;  // Increment the filled count for this row.
      std::copy_n(&indices(i, 0), rank, &output_indices(output_i, 0));
      output_values(output_i) = values(i);
      // We'll need this reverse index map to backprop correctly.
      reverse_index_map(i) = output_i;
    }

    // Fill in values for rows that are missing
    for (int64 row = 0; row < dense_rows; ++row) {
      const int64 row_count = filled_count(row);
      if (row_count == 0) {  // We haven't filled this row
        const int64 starting_index = (row == 0) ? 0 : scratch(row - 1);
        // Remaining index values were set to zero already.
        // The value at this index was set to default_value already.
        // Just need to set the row index in the right location.
        output_indices(starting_index, 0) = row;
      }
    }
  }
};

#define REGISTER_KERNELS(type)                            \
  REGISTER_KERNEL_BUILDER(Name("SparseFillEmptyRows")     \
                              .Device(DEVICE_CPU)         \
                              .TypeConstraint<type>("T"), \
                          SparseFillEmptyRowsOp<type>)

TF_CALL_ALL_TYPES(REGISTER_KERNELS);
#undef REGISTER_KERNELS

template <typename T>
class SparseFillEmptyRowsGradOp : public OpKernel {
 public:
  explicit SparseFillEmptyRowsGradOp(OpKernelConstruction* context)
      : OpKernel(context) {}

  void Compute(OpKernelContext* context) override {
    const Tensor* reverse_index_map_t;
    const Tensor* grad_values_t;
    OP_REQUIRES_OK(context,
                   context->input("reverse_index_map", &reverse_index_map_t));
    OP_REQUIRES_OK(context, context->input("grad_values", &grad_values_t));

    const CPUDevice& d = context->eigen_device<CPUDevice>();

    OP_REQUIRES(
        context, TensorShapeUtils::IsVector(reverse_index_map_t->shape()),
        errors::InvalidArgument("reverse_index_map must be a vector, saw: ",
                                reverse_index_map_t->shape().DebugString()));

    const auto reverse_index_map = reverse_index_map_t->vec<int64>();
    const auto grad_values = grad_values_t->vec<T>();

    const int64 N = reverse_index_map_t->shape().dim_size(0);
    const int64 N_full = grad_values_t->shape().dim_size(0);

    Tensor* d_values_t;
    OP_REQUIRES_OK(context, context->allocate_output(
                                "d_values", TensorShape({N}), &d_values_t));
    auto d_values = d_values_t->vec<T>();
    Tensor* d_default_value_t;
    OP_REQUIRES_OK(context,
                   context->allocate_output("d_default_value", TensorShape({}),
                                            &d_default_value_t));
    T& d_default_value = d_default_value_t->scalar<T>()();
    d_default_value = T();

    Tensor visited_t;
    OP_REQUIRES_OK(context, context->allocate_temp(
                                DT_BOOL, TensorShape({N_full}), &visited_t));
    auto visited = visited_t.vec<bool>();
    visited.device(d) = visited.constant(false);

    for (int i = 0; i < N; ++i) {
      // Locate the index of the output of the forward prop associated
      // with this location in the input of the forward prop.  Copy
      // the gradient into it.  Mark it as visited.
      d_values(i) = grad_values(reverse_index_map(i));
      visited(reverse_index_map(i)) = true;
    }
    for (int j = 0; j < N_full; ++j) {
      // The default value gradient gets the accumulated remainder of
      // the backprop values (since the default value was used to fill
      // in these slots in the forward calculation).
      if (!visited(j)) {
        d_default_value += grad_values(j);
      }
    }
  }
};

#define REGISTER_KERNELS(type)                            \
  REGISTER_KERNEL_BUILDER(Name("SparseFillEmptyRowsGrad") \
                              .Device(DEVICE_CPU)         \
                              .TypeConstraint<type>("T"), \
                          SparseFillEmptyRowsGradOp<type>)

TF_CALL_NUMBER_TYPES(REGISTER_KERNELS);
#undef REGISTER_KERNELS
}  // namespace tensorflow
<|endoftext|>


<commit_before>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * 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 <thrift/lib/cpp2/util/ScopedServerInterfaceThread.h>

#include <folly/SocketAddress.h>

#include <thrift/lib/cpp2/async/PooledRequestChannel.h>
#include <thrift/lib/cpp2/server/BaseThriftServer.h>
#include <thrift/lib/cpp2/server/ThriftServer.h>

using namespace std;
using namespace folly;
using namespace apache::thrift::concurrency;

namespace apache {
namespace thrift {

ScopedServerInterfaceThread::ScopedServerInterfaceThread(
    shared_ptr<AsyncProcessorFactory> apf,
    SocketAddress const& addr,
    ServerConfigCb configCb) {
  auto tf = make_shared<PosixThreadFactory>(PosixThreadFactory::ATTACHED);
  auto tm = ThreadManager::newSimpleThreadManager(1);
  tm->threadFactory(move(tf));
  tm->start();
  auto ts = make_shared<ThriftServer>();
  ts->setAddress(addr);
  // Allow plaintext on loopback so the plaintext clients created by default by
  // the newClient methods can still connect.
  ts->setAllowPlaintextOnLoopback(true);
  ts->setProcessorFactory(move(apf));
  ts->setNumIOWorkerThreads(1);
  ts->setNumCPUWorkerThreads(1);
  ts->setThreadManager(tm);
  // The default behavior is to keep N recent requests per IO worker in memory.
  // In unit-tests, this defers memory reclamation and potentially masks
  // use-after-free bugs. Because this facility is used mostly in tests, it is
  // better not to keep any recent requests in memory.
  ts->setMaxFinishedDebugPayloadsPerWorker(0);
  if (configCb) {
    configCb(*ts);
  }
  ts_ = ts;
  sst_.start(ts_, [ts]() { ts->getEventBaseManager()->clearEventBase(); });
}

ScopedServerInterfaceThread::ScopedServerInterfaceThread(
    shared_ptr<AsyncProcessorFactory> apf,
    const string& host,
    uint16_t port,
    ServerConfigCb configCb)
    : ScopedServerInterfaceThread(
          move(apf), SocketAddress(host, port), move(configCb)) {}

ScopedServerInterfaceThread::ScopedServerInterfaceThread(
    shared_ptr<AsyncProcessorFactory> apf, ServerConfigCb configCb)
    : ScopedServerInterfaceThread(move(apf), "::1", 0, move(configCb)) {}

ScopedServerInterfaceThread::ScopedServerInterfaceThread(
    shared_ptr<BaseThriftServer> bts) {
  ts_ = bts;
  sst_.start(ts_);
}

BaseThriftServer& ScopedServerInterfaceThread::getThriftServer() const {
  return *ts_;
}

const SocketAddress& ScopedServerInterfaceThread::getAddress() const {
  return *sst_.getAddress();
}

uint16_t ScopedServerInterfaceThread::getPort() const {
  return getAddress().getPort();
}

RequestChannel::Ptr ScopedServerInterfaceThread::newChannel(
    folly::Executor* callbackExecutor,
    MakeChannelFunc makeChannel,
    size_t numThreads) const {
  return PooledRequestChannel::newChannel(
      callbackExecutor,
      [makeChannel = std::move(makeChannel),
       address = getAddress()](folly::EventBase& eb) mutable {
        return makeChannel(folly::AsyncSocket::UniquePtr(
            new folly::AsyncSocket(&eb, address)));
      },
      numThreads);
}

namespace {
struct TestClientRunner {
  ScopedServerInterfaceThread runner;
  RequestChannel::Ptr channel;

  explicit TestClientRunner(std::shared_ptr<AsyncProcessorFactory> apf)
      : runner(std::move(apf)) {}
};
} // namespace

std::shared_ptr<RequestChannel>
ScopedServerInterfaceThread::makeTestClientChannel(
    std::shared_ptr<AsyncProcessorFactory> apf,
    ScopedServerInterfaceThread::FaultInjectionFunc injectFault) {
  auto runner = std::make_shared<TestClientRunner>(std::move(apf));
  auto innerChannel = runner->runner.newChannel(
      folly::getGlobalCPUExecutor().get(), RocketClientChannel::newChannel);
  if (injectFault) {
    runner->channel.reset(new apache::thrift::detail::FaultInjectionChannel(
        std::move(innerChannel), std::move(injectFault)));
  } else {
    runner->channel = std::move(innerChannel);
  }
  auto* channel = runner->channel.get();
  return folly::to_shared_ptr_aliasing(std::move(runner), channel);
}

namespace detail {
void validateServiceName(AsyncProcessorFactory& apf, const char* serviceName) {
  if (auto* service = dynamic_cast<ServerInterface*>(&apf)) {
    std::string actualServiceName{service->getGeneratedName()};
    CHECK_STREQ(actualServiceName.c_str(), serviceName)
        << "Client and handler type mismatch";
  }
}
} // namespace detail
} // namespace thrift
} // namespace apache
<commit_msg>Don't use setThreadManager in ScopedServerInterfaceThread<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * 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 <thrift/lib/cpp2/util/ScopedServerInterfaceThread.h>

#include <folly/SocketAddress.h>

#include <thrift/lib/cpp2/async/PooledRequestChannel.h>
#include <thrift/lib/cpp2/server/BaseThriftServer.h>
#include <thrift/lib/cpp2/server/ThriftServer.h>

using namespace std;
using namespace folly;
using namespace apache::thrift::concurrency;

namespace apache {
namespace thrift {

ScopedServerInterfaceThread::ScopedServerInterfaceThread(
    shared_ptr<AsyncProcessorFactory> apf,
    SocketAddress const& addr,
    ServerConfigCb configCb) {
  auto ts = make_shared<ThriftServer>();
  ts->setAddress(addr);
  // Allow plaintext on loopback so the plaintext clients created by default
  // by the newClient methods can still connect.
  ts->setAllowPlaintextOnLoopback(true);
  ts->setProcessorFactory(move(apf));
  ts->setNumIOWorkerThreads(1);
  ts->setNumCPUWorkerThreads(1);
  auto tf = make_shared<PosixThreadFactory>(PosixThreadFactory::ATTACHED);
  ts->setThreadFactory(std::move(tf));
  ts->setThreadManagerType(
      apache::thrift::BaseThriftServer::ThreadManagerType::SIMPLE);

  // The default behavior is to keep N recent requests per IO worker in
  // memory. In unit-tests, this defers memory reclamation and potentially
  // masks use-after-free bugs. Because this facility is used mostly in tests,
  // it is better not to keep any recent requests in memory.
  ts->setMaxFinishedDebugPayloadsPerWorker(0);
  if (configCb) {
    configCb(*ts);
  }
  ts_ = ts;
  sst_.start(ts_, [ts]() { ts->getEventBaseManager()->clearEventBase(); });
}

ScopedServerInterfaceThread::ScopedServerInterfaceThread(
    shared_ptr<AsyncProcessorFactory> apf,
    const string& host,
    uint16_t port,
    ServerConfigCb configCb)
    : ScopedServerInterfaceThread(
          move(apf), SocketAddress(host, port), move(configCb)) {}

ScopedServerInterfaceThread::ScopedServerInterfaceThread(
    shared_ptr<AsyncProcessorFactory> apf, ServerConfigCb configCb)
    : ScopedServerInterfaceThread(move(apf), "::1", 0, move(configCb)) {}

ScopedServerInterfaceThread::ScopedServerInterfaceThread(
    shared_ptr<BaseThriftServer> bts) {
  ts_ = bts;
  sst_.start(ts_);
}

BaseThriftServer& ScopedServerInterfaceThread::getThriftServer() const {
  return *ts_;
}

const SocketAddress& ScopedServerInterfaceThread::getAddress() const {
  return *sst_.getAddress();
}

uint16_t ScopedServerInterfaceThread::getPort() const {
  return getAddress().getPort();
}

RequestChannel::Ptr ScopedServerInterfaceThread::newChannel(
    folly::Executor* callbackExecutor,
    MakeChannelFunc makeChannel,
    size_t numThreads) const {
  return PooledRequestChannel::newChannel(
      callbackExecutor,
      [makeChannel = std::move(makeChannel),
       address = getAddress()](folly::EventBase& eb) mutable {
        return makeChannel(folly::AsyncSocket::UniquePtr(
            new folly::AsyncSocket(&eb, address)));
      },
      numThreads);
}

namespace {
struct TestClientRunner {
  ScopedServerInterfaceThread runner;
  RequestChannel::Ptr channel;

  explicit TestClientRunner(std::shared_ptr<AsyncProcessorFactory> apf)
      : runner(std::move(apf)) {}
};
} // namespace

std::shared_ptr<RequestChannel>
ScopedServerInterfaceThread::makeTestClientChannel(
    std::shared_ptr<AsyncProcessorFactory> apf,
    ScopedServerInterfaceThread::FaultInjectionFunc injectFault) {
  auto runner = std::make_shared<TestClientRunner>(std::move(apf));
  auto innerChannel = runner->runner.newChannel(
      folly::getGlobalCPUExecutor().get(), RocketClientChannel::newChannel);
  if (injectFault) {
    runner->channel.reset(new apache::thrift::detail::FaultInjectionChannel(
        std::move(innerChannel), std::move(injectFault)));
  } else {
    runner->channel = std::move(innerChannel);
  }
  auto* channel = runner->channel.get();
  return folly::to_shared_ptr_aliasing(std::move(runner), channel);
}

namespace detail {
void validateServiceName(AsyncProcessorFactory& apf, const char* serviceName) {
  if (auto* service = dynamic_cast<ServerInterface*>(&apf)) {
    std::string actualServiceName{service->getGeneratedName()};
    CHECK_STREQ(actualServiceName.c_str(), serviceName)
        << "Client and handler type mismatch";
  }
}
} // namespace detail
} // namespace thrift
} // namespace apache
<|endoftext|>


<commit_before>#include <QtTest/QtTest>
#include <QProcess>

#include "../cutehmi.dirs.hpp"

namespace cutehmi {
namespace daemon {

class test_cutehmi_daemon:
	public QObject
{
		Q_OBJECT

	private slots:
		void initTestCase();

		void helpOption();

		void versionOption();

		void countDaemonExample();

	private:
		QString m_installDir;
		QString m_programPath;
};

void test_cutehmi_daemon::initTestCase()
{
        QString m_installDir = qEnvironmentVariable("CUTEHMI_INSTALL_DIR");
	QVERIFY(!m_installDir.isEmpty());

	QString toolsInstallSubdir = CUTEHMI_DIRS_TOOLS_INSTALL_SUBDIR;
	if (!toolsInstallSubdir.isEmpty())
	    m_installDir += "/" + toolsInstallSubdir;

	m_programPath = m_installDir + "/cutehmi.daemon.3";
#ifndef CUTEHMI_NDEBUG
	m_programPath += ".debug";
#endif
}

void test_cutehmi_daemon::helpOption()
{
	QList<QStringList> argumentsList;
	argumentsList << QStringList({"--help"})
			<< QStringList({"--h"});

	for (auto arguments : argumentsList) {
		QProcess process;
		process.start(m_programPath, arguments);
		process.waitForFinished(1000);
		QCOMPARE(process.error(), QProcess::UnknownError);
		QVERIFY(!process.readAllStandardError().contains("Unknown option"));
		QVERIFY(!process.readAllStandardOutput().isEmpty());
		QCOMPARE(process.exitStatus(), QProcess::NormalExit);
		QCOMPARE(process.exitCode(), EXIT_SUCCESS);
	}
}

void test_cutehmi_daemon::versionOption()
{
	QList<QStringList> argumentsList;
	argumentsList << QStringList({"--version"})
			<< QStringList({"--v"});

	for (auto arguments : argumentsList) {
		QProcess process;
		process.start(m_programPath, arguments);
		process.waitForFinished(1000);
		QCOMPARE(process.error(), QProcess::UnknownError);
		QVERIFY(!process.readAllStandardError().contains("Unknown option"));
		QVERIFY(!process.readAllStandardOutput().isEmpty());
		QCOMPARE(process.exitStatus(), QProcess::NormalExit);
		QCOMPARE(process.exitCode(), EXIT_SUCCESS);
	}
}

void test_cutehmi_daemon::countDaemonExample()
{
	QProcess process;
	QStringList arguments { {"--app"}, {"--extension=CuteHMI.Examples.CountDaemon.2"} };
	process.start(m_programPath, arguments);
	QVERIFY(process.waitForFinished());

	QString stdOut = QString::fromLocal8Bit(process.readAllStandardOutput());
	QString stdErr = QString::fromLocal8Bit(process.readAllStandardError());

	QVERIFY(stdErr.contains("I can count"));

	QCOMPARE(process.error(), QProcess::UnknownError);
	QCOMPARE(process.exitStatus(), QProcess::NormalExit);
	QCOMPARE(process.exitCode(), EXIT_SUCCESS);
}

}
}

QTEST_MAIN(cutehmi::daemon::test_cutehmi_daemon)
#include "test_cutehmi_daemon.moc"

//(c)C: Copyright © 2020, Michał Policht <michal@policht.pl>. All rights reserved.
//(c)C: This file is a part of CuteHMI.
//(c)C: CuteHMI is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
//(c)C: CuteHMI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
//(c)C: You should have received a copy of the GNU Lesser General Public License along with CuteHMI.  If not, see <https://www.gnu.org/licenses/>.
<commit_msg>Fix countDaemonExample() arguments.<commit_after>#include <QtTest/QtTest>
#include <QProcess>

#include "../cutehmi.dirs.hpp"

namespace cutehmi {
namespace daemon {

class test_cutehmi_daemon:
	public QObject
{
		Q_OBJECT

	private slots:
		void initTestCase();

		void helpOption();

		void versionOption();

		void countDaemonExample();

	private:
		QString m_installDir;
		QString m_programPath;
};

void test_cutehmi_daemon::initTestCase()
{
        QString m_installDir = qEnvironmentVariable("CUTEHMI_INSTALL_DIR");
	QVERIFY(!m_installDir.isEmpty());

	QString toolsInstallSubdir = CUTEHMI_DIRS_TOOLS_INSTALL_SUBDIR;
	if (!toolsInstallSubdir.isEmpty())
	    m_installDir += "/" + toolsInstallSubdir;

	m_programPath = m_installDir + "/cutehmi.daemon.3";
#ifndef CUTEHMI_NDEBUG
	m_programPath += ".debug";
#endif
}

void test_cutehmi_daemon::helpOption()
{
	QList<QStringList> argumentsList;
	argumentsList << QStringList({"--help"})
			<< QStringList({"--h"});

	for (auto arguments : argumentsList) {
		QProcess process;
		process.start(m_programPath, arguments);
		process.waitForFinished(1000);
		QCOMPARE(process.error(), QProcess::UnknownError);
		QVERIFY(!process.readAllStandardError().contains("Unknown option"));
		QVERIFY(!process.readAllStandardOutput().isEmpty());
		QCOMPARE(process.exitStatus(), QProcess::NormalExit);
		QCOMPARE(process.exitCode(), EXIT_SUCCESS);
	}
}

void test_cutehmi_daemon::versionOption()
{
	QList<QStringList> argumentsList;
	argumentsList << QStringList({"--version"})
			<< QStringList({"--v"});

	for (auto arguments : argumentsList) {
		QProcess process;
		process.start(m_programPath, arguments);
		process.waitForFinished(1000);
		QCOMPARE(process.error(), QProcess::UnknownError);
		QVERIFY(!process.readAllStandardError().contains("Unknown option"));
		QVERIFY(!process.readAllStandardOutput().isEmpty());
		QCOMPARE(process.exitStatus(), QProcess::NormalExit);
		QCOMPARE(process.exitCode(), EXIT_SUCCESS);
	}
}

void test_cutehmi_daemon::countDaemonExample()
{
	QProcess process;
	QStringList arguments { {"--app"}, {"CuteHMI.Examples.CountDaemon.3"} };
	process.start(m_programPath, arguments);
	QVERIFY(process.waitForFinished());

	QString stdOut = QString::fromLocal8Bit(process.readAllStandardOutput());
	QString stdErr = QString::fromLocal8Bit(process.readAllStandardError());

	QVERIFY(stdErr.contains("I can count"));

	QCOMPARE(process.error(), QProcess::UnknownError);
	QCOMPARE(process.exitStatus(), QProcess::NormalExit);
	QCOMPARE(process.exitCode(), EXIT_SUCCESS);
}

}
}

QTEST_MAIN(cutehmi::daemon::test_cutehmi_daemon)
#include "test_cutehmi_daemon.moc"

//(c)C: Copyright © 2020, Michał Policht <michal@policht.pl>. All rights reserved.
//(c)C: This file is a part of CuteHMI.
//(c)C: CuteHMI is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
//(c)C: CuteHMI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
//(c)C: You should have received a copy of the GNU Lesser General Public License along with CuteHMI.  If not, see <https://www.gnu.org/licenses/>.
<|endoftext|>


<commit_before>#include "Piezas.h"
#include <vector>
/** CLASS Piezas
 * Class for representing a Piezas vertical board, which is roughly based
 * on the game "Connect Four" where pieces are placed in a column and
 * fall to the bottom of the column, or on top of other pieces already in
 * that column. For an illustration of the board, see:
 *  https://en.wikipedia.org/wiki/Connect_Four
 *
 * Board coordinates [row,col] should match with:
 * [2,0][2,1][2,2][2,3]
 * [1,0][1,1][1,2][1,3]
 * [0,0][0,1][0,2][0,3]
 * So that a piece dropped in column 2 should take [0,2] and the next one
 * dropped in column 2 should take [1,2].
**/

/**
 * Constructor sets an empty board (default 3 rows, 4 columns) and
 * specifies it is X's turn first
**/
Piezas::Piezas();
{
    reset();
    turn = X;
}

/**
 * Resets each board location to the Blank Piece value, with a board of the
 * same size as previously specified
**/
void Piezas::reset();
{
    for(int i = 0; i < BOARD_ROWS; i++)
    {
        for(int j = 0; j < BOARD_COLS; j++)
        {
            board[i][j] = Blank;
        }
    }
}

/**
 * Places a piece of the current turn on the board, returns what
 * piece is placed, and toggles which Piece's turn it is. dropPiece does
 * NOT allow to place a piece in a location where a column is full.
 * In that case, placePiece returns Piece Blank value
 * Out of bounds coordinates return the Piece Invalid value
 * Trying to drop a piece where it cannot be placed loses the player's turn
**/
Piece Piezas::dropPiece(int column);
{
    //Out of bounds placement means turn switches, return valid
    if(column > 3 || column < 0)
    {
        if(turn == X)
        {
            turn = O;
        }
        else
        {
            turn = X;
        }

        return Invalid;
    }

    //checking from bottom of column to the top, else return nothing
    if(board[2][column] == Blank)
    {
        board[2][column] = turn;

        if(turn == X)
        {
            turn = O;
        }
        else
        {
            turn = X;
        }

        return board[2][column];
    }
    else if(board[1][column] == Blank)
    {
        board[1][column] == turn;

        if(turn == X)
        {
            turn = O;
        }
        else
        {
            turn = X;
        }

        return board[1][column];
    }
    else if(board[0][column] == Blank)
    {
        board[0][column] == turn;

        if(turn == X)
        {
            turn = O;
        }
        else
        {
            turn = X;
        }

        return board[0][column];
    }
    else
    {
        return Blank;
    }
}

/**
 * Returns what piece is at the provided coordinates, or Blank if there
 * are no pieces there, or Invalid if the coordinates are out of bounds
**/
Piece Piezas::pieceAt(int row, int column);
{
    if((row > 2 || row < 0) || (column < 0 || column > 3))
    {
        return Invalid;
    }

    if(board[row][column] != Blank)
    {
        return board[row][column];
    }
    else
    {
        return Blank;
    }
}

/**
 * Returns which Piece has won, if there is a winner, Invalid if the game
 * is not over, or Blank if the board is filled and no one has won ("tie").
 * For a game to be over, all locations on the board must be filled with X's
 * and O's (i.e. no remaining Blank spaces). The winner is which player has
 * the most adjacent pieces in a single line. Lines can go either vertically
 * or horizontally. If both X's and O's have the same max number of pieces in a
 * line, it is a tie.
**/
Piece Piezas::gameState();
{
    int max_x = 0;
    int max_o = 0;
    int x_amount;
    int o_amount;
    bool full_col_x = false;
    bool full_col_o = false;
    bool three_adj_x = false;
    bool three_adj_o = false;
    bool two_adj_x = false;
    bool two_adj_o = false;

    for(int i = 0; i < BOARD_ROWS; i++)
    {
        for(int j = 0; j < BOARD_COLS; j++)
        {
            if(board[i][j] == Blank)
            {
                return Invalid;
            }
        }
    }

    //check horizontal
    for(int i = 0; i < BOARD_ROWS; i++)
    {
        x_amount = 0;
        o_amount = 0;

        for(int j = 0; j < BOARD_COLS; j++)
        {
            if(board[i][j] == X)
            {
                x_amount++;
            }
            else
            {
                o_amount++;
            }
        }

        if(x_amount > max_x)
        {
            max_x = x_amount;
        }
        if(o_amount > max_o)
        {
            max_o = o_amount;
        }
    }

    //check for any max values of 4, that would automatically win or tie
    if(max_x == BOARD_COLS && max_o == BOARD_COLS)
    {
        return Blank;
    }
    else if(max_x == BOARD_COLS)
    {
        return X;
    }
    else if(max_o == BOARD_COLS)
    {
        return O;
    }

    //check verticals
    //check column 0
    if(board[0][0] == X)
    {
        if(board[1][0] == X)
        {
            if(board][2][0] == X)
            {
                x_amount = 3;
                full_col_x = true;
            }
            else
            {
                x_amount = 2;
            }
        }
        else
        {
            x_amount = 1;
        }
    }
    else
    {
        if(board[1][0] == O)
        {
            if(board[2][0] == O)
            {
                o_amount = 3;
                full_col_o = true;
            }
            else
            {
                o_amount = 2;
            }
        }
        else
        {
            o_amount = 1;
        }
    }
    if(x_amount > max_x)
    {
        max_x = x_amount;
    }
    if(o_amount > max_o)
    {
        max_o = o_amount;
    }

    //check column 1
    if(board[0][1] == X)
    {
        if(board[1][1] == X)
        {
            if(board][2][1] == X)
            {
                x_amount = 3;
                full_col_x = true;
            }
            else
            {
                x_amount = 2;
            }
        }
        else
        {
            x_amount = 1;
        }
    }
    else
    {
        if(board[1][1] == O)
        {
            if(board[2][1] == O)
            {
                o_amount = 3;
                full_col_o = true;
            }
            else
            {
                o_amount = 2;
            }
        }
        else
        {
            o_amount = 1;
        }
    }
    if(x_amount > max_x)
    {
        max_x = x_amount;
    }
    if(o_amount > max_o)
    {
        max_o = o_amount;
    }

    //check column 2
    if(board[0][2] == X)
    {
        if(board[1][2] == X)
        {
            if(board][2][2] == X)
            {
                x_amount = 3;
                full_col_x = true;
            }
            else
            {
                x_amount = 2;
            }
        }
        else
        {
            x_amount = 1;
        }
    }
    else
    {
        if(board[1][2] == O)
        {
            if(board[2][2] == O)
            {
                o_amount = 3;
                full_col_o = true;
            }
            else
            {
                o_amount = 2;
            }
        }
        else
        {
            o_amount = 1;
        }
    }
    if(x_amount > max_x)
    {
        max_x = x_amount;
    }
    if(o_amount > max_o)
    {
        max_o = o_amount;
    }

    //check column 3
    if(board[0][3] == X)
    {
        if(board[1][3] == X)
        {
            if(board][2][3] == X)
            {
                x_amount = 3;
                full_col_x = true;
            }
            else
            {
                x_amount = 2;
            }
        }
        else
        {
            x_amount = 1;
        }
    }
    else
    {
        if(board[1][3] == O)
        {
            if(board[2][3] == O)
            {
                o_amount = 3;
                full_col_o = true;
            }
            else
            {
                o_amount = 2;
            }
        }
        else
        {
            o_amount = 1;
        }
    }
    if(x_amount > max_x)
    {
        max_x = x_amount;
    }
    if(o_amount > max_o)
    {
        max_o = o_amount;
    }

    //check for 3 x's in a row
    if(max_x == BOARD_ROWS)
    {
        if(full_col_x == true)
        {
            three_adj_x = true;
        }
        else
        {
            for(int i = 0; i < BOARD_ROWS; i++)
            {
                if(board[i][0] == X)
                {
                    if(board[i][1] == X && board[i][2] == X)
                    {
                        three_adj_x = true;
                    }
                }
                else if(board[i][1] == X)
                {
                    if(board[i][2] == X && board[i][3] == X)
                    {
                        three_adj_x = true;
                    }
                }
            }
        }
    }

    //check for 3 o's in a row
    if(max_o == BOARD_ROWS)
    {
        if(full_col_o == true)
        {
            three_adj_o = true;
        }
        else
        {
            for(int i = 0; i < BOARD_ROWS; i++)
            {
                if(board[i][0] == O)
                {
                    if(board[i][1] == O && board[i][2] == O)
                    {
                        three_adj_o = true;
                    }
                }
                else if(board[i][1] == O)
                {
                    if(board[i][2] == O && board[i][3] == O)
                    {
                        three_adj_o = true;
                    }
                }
            }
        }
    }

    //check for tie of 3 in a row
    if(three_adj_x && three_adj_o)
    {
        return Blank;
    }
    else if(three_adj_x)
    {
        return X;
    }
    else if(three_adj_o)
    {
        return O;
    }

    //if max is 2 for either, check if they are in a row
    if(max_x == 2)
    {
        for(int i = 0; i < BOARD_ROWS; i++)
        {
            if(board[i][0] == X && board[i][1] == X)
            {
                two_adj_x = true;
            }
            else if(board[i][1] == X && board[i][2] == X)
            {
                two_adj_x = true;
            }
            else if(board[i][2] == X && board[i][3] == X)
            {
                two_adj_x = true;
            }
        }
        for(int j = 0; j < BOARD_COLS; j++)
        {
            if(board[0][j] == X && board[1][j] == X)
            {
                two_adj_x = true;
            }
            else if(board[1][j] == X && board[2][j] == X)
            {
                two_adj_x = true;
            }
        }
    }

    if(max_o == 2)
    {
        for(int i = 0; i < BOARD_ROWS; i++)
        {
            if(board[i][0] == O && board[i][1] == O)
            {
                two_adj_o = true;
            }
            else if(board[i][1] == O && board[i][2] == O)
            {
                two_adj_o = true;
            }
            else if(board[i][2] == O && board[i][3] == O)
            {
                two_adj_o = true;
            }
        }
        for(int j = 0; j < BOARD_COLS; j++)
        {
            if(board[0][j] == O && board[1][j] == O)
            {
                two_adj_o = true;
            }
            else if(board[1][j] == O && board[2][j] == O)
            {
                two_adj_o = true;
            }
        }
    }

    //check for tie of 2 in a row
    if(two_adj_x && two_adj_o)
    {
        return Blank;
    }
    else if(two_adj_x)
    {
        return X;
    }
    else if(two_adj_o)
    {
        return O;
    }

    //if all above fails to return, max is 1 for both, results in tie
    return Blank;
}<commit_msg>Add files via upload<commit_after>#include "Piezas.h"
#include <vector>
/** CLASS Piezas
 * Class for representing a Piezas vertical board, which is roughly based
 * on the game "Connect Four" where pieces are placed in a column and
 * fall to the bottom of the column, or on top of other pieces already in
 * that column. For an illustration of the board, see:
 *  https://en.wikipedia.org/wiki/Connect_Four
 *
 * Board coordinates [row,col] should match with:
 * [2,0][2,1][2,2][2,3]
 * [1,0][1,1][1,2][1,3]
 * [0,0][0,1][0,2][0,3]
 * So that a piece dropped in column 2 should take [0,2] and the next one
 * dropped in column 2 should take [1,2].
**/

/**
 * Constructor sets an empty board (default 3 rows, 4 columns) and
 * specifies it is X's turn first
**/
Piezas::Piezas()
{
    reset();
    turn = X;
}

/**
 * Resets each board location to the Blank Piece value, with a board of the
 * same size as previously specified
**/
void Piezas::reset()
{
    for(int i = 0; i < BOARD_ROWS; i++)
    {
        for(int j = 0; j < BOARD_COLS; j++)
        {
            board[i][j] = Blank;
        }
    }
}

/**
 * Places a piece of the current turn on the board, returns what
 * piece is placed, and toggles which Piece's turn it is. dropPiece does
 * NOT allow to place a piece in a location where a column is full.
 * In that case, placePiece returns Piece Blank value
 * Out of bounds coordinates return the Piece Invalid value
 * Trying to drop a piece where it cannot be placed loses the player's turn
**/
Piece Piezas::dropPiece(int column)
{
    //Out of bounds placement means turn switches, return valid
    if(column > 3 || column < 0)
    {
        if(turn == X)
        {
            turn = O;
        }
        else
        {
            turn = X;
        }

        return Invalid;
    }

    //checking from bottom of column to the top, else return nothing
    if(board[2][column] == Blank)
    {
        board[2][column] = turn;

        if(turn == X)
        {
            turn = O;
        }
        else
        {
            turn = X;
        }

        return board[2][column];
    }
    else if(board[1][column] == Blank)
    {
        board[1][column] == turn;

        if(turn == X)
        {
            turn = O;
        }
        else
        {
            turn = X;
        }

        return board[1][column];
    }
    else if(board[0][column] == Blank)
    {
        board[0][column] == turn;

        if(turn == X)
        {
            turn = O;
        }
        else
        {
            turn = X;
        }

        return board[0][column];
    }
    else
    {
        return Blank;
    }
}

/**
 * Returns what piece is at the provided coordinates, or Blank if there
 * are no pieces there, or Invalid if the coordinates are out of bounds
**/
Piece Piezas::pieceAt(int row, int column)
{
    if((row > 2 || row < 0) || (column < 0 || column > 3))
    {
        return Invalid;
    }

    if(board[row][column] != Blank)
    {
        return board[row][column];
    }
    else
    {
        return Blank;
    }
}

/**
 * Returns which Piece has won, if there is a winner, Invalid if the game
 * is not over, or Blank if the board is filled and no one has won ("tie").
 * For a game to be over, all locations on the board must be filled with X's
 * and O's (i.e. no remaining Blank spaces). The winner is which player has
 * the most adjacent pieces in a single line. Lines can go either vertically
 * or horizontally. If both X's and O's have the same max number of pieces in a
 * line, it is a tie.
**/
Piece Piezas::gameState()
{
    int max_x = 0;
    int max_o = 0;
    int x_amount;
    int o_amount;
    bool full_col_x = false;
    bool full_col_o = false;
    bool three_adj_x = false;
    bool three_adj_o = false;
    bool two_adj_x = false;
    bool two_adj_o = false;

    for(int i = 0; i < BOARD_ROWS; i++)
    {
        for(int j = 0; j < BOARD_COLS; j++)
        {
            if(board[i][j] == Blank)
            {
                return Invalid;
            }
        }
    }

    //check horizontal
    for(int i = 0; i < BOARD_ROWS; i++)
    {
        x_amount = 0;
        o_amount = 0;

        for(int j = 0; j < BOARD_COLS; j++)
        {
            if(board[i][j] == X)
            {
                x_amount++;
            }
            else
            {
                o_amount++;
            }
        }

        if(x_amount > max_x)
        {
            max_x = x_amount;
        }
        if(o_amount > max_o)
        {
            max_o = o_amount;
        }
    }

    //check for any max values of 4, that would automatically win or tie
    if(max_x == BOARD_COLS && max_o == BOARD_COLS)
    {
        return Blank;
    }
    else if(max_x == BOARD_COLS)
    {
        return X;
    }
    else if(max_o == BOARD_COLS)
    {
        return O;
    }

    //check verticals
    //check column 0
    if(board[0][0] == X)
    {
        if(board[1][0] == X)
        {
            if(board][2][0] == X)
            {
                x_amount = 3;
                full_col_x = true;
            }
            else
            {
                x_amount = 2;
            }
        }
        else
        {
            x_amount = 1;
        }
    }
    else
    {
        if(board[1][0] == O)
        {
            if(board[2][0] == O)
            {
                o_amount = 3;
                full_col_o = true;
            }
            else
            {
                o_amount = 2;
            }
        }
        else
        {
            o_amount = 1;
        }
    }
    if(x_amount > max_x)
    {
        max_x = x_amount;
    }
    if(o_amount > max_o)
    {
        max_o = o_amount;
    }

    //check column 1
    if(board[0][1] == X)
    {
        if(board[1][1] == X)
        {
            if(board][2][1] == X)
            {
                x_amount = 3;
                full_col_x = true;
            }
            else
            {
                x_amount = 2;
            }
        }
        else
        {
            x_amount = 1;
        }
    }
    else
    {
        if(board[1][1] == O)
        {
            if(board[2][1] == O)
            {
                o_amount = 3;
                full_col_o = true;
            }
            else
            {
                o_amount = 2;
            }
        }
        else
        {
            o_amount = 1;
        }
    }
    if(x_amount > max_x)
    {
        max_x = x_amount;
    }
    if(o_amount > max_o)
    {
        max_o = o_amount;
    }

    //check column 2
    if(board[0][2] == X)
    {
        if(board[1][2] == X)
        {
            if(board][2][2] == X)
            {
                x_amount = 3;
                full_col_x = true;
            }
            else
            {
                x_amount = 2;
            }
        }
        else
        {
            x_amount = 1;
        }
    }
    else
    {
        if(board[1][2] == O)
        {
            if(board[2][2] == O)
            {
                o_amount = 3;
                full_col_o = true;
            }
            else
            {
                o_amount = 2;
            }
        }
        else
        {
            o_amount = 1;
        }
    }
    if(x_amount > max_x)
    {
        max_x = x_amount;
    }
    if(o_amount > max_o)
    {
        max_o = o_amount;
    }

    //check column 3
    if(board[0][3] == X)
    {
        if(board[1][3] == X)
        {
            if(board][2][3] == X)
            {
                x_amount = 3;
                full_col_x = true;
            }
            else
            {
                x_amount = 2;
            }
        }
        else
        {
            x_amount = 1;
        }
    }
    else
    {
        if(board[1][3] == O)
        {
            if(board[2][3] == O)
            {
                o_amount = 3;
                full_col_o = true;
            }
            else
            {
                o_amount = 2;
            }
        }
        else
        {
            o_amount = 1;
        }
    }
    if(x_amount > max_x)
    {
        max_x = x_amount;
    }
    if(o_amount > max_o)
    {
        max_o = o_amount;
    }

    //check for 3 x's in a row
    if(max_x == BOARD_ROWS)
    {
        if(full_col_x == true)
        {
            three_adj_x = true;
        }
        else
        {
            for(int i = 0; i < BOARD_ROWS; i++)
            {
                if(board[i][0] == X)
                {
                    if(board[i][1] == X && board[i][2] == X)
                    {
                        three_adj_x = true;
                    }
                }
                else if(board[i][1] == X)
                {
                    if(board[i][2] == X && board[i][3] == X)
                    {
                        three_adj_x = true;
                    }
                }
            }
        }
    }

    //check for 3 o's in a row
    if(max_o == BOARD_ROWS)
    {
        if(full_col_o == true)
        {
            three_adj_o = true;
        }
        else
        {
            for(int i = 0; i < BOARD_ROWS; i++)
            {
                if(board[i][0] == O)
                {
                    if(board[i][1] == O && board[i][2] == O)
                    {
                        three_adj_o = true;
                    }
                }
                else if(board[i][1] == O)
                {
                    if(board[i][2] == O && board[i][3] == O)
                    {
                        three_adj_o = true;
                    }
                }
            }
        }
    }

    //check for tie of 3 in a row
    if(three_adj_x && three_adj_o)
    {
        return Blank;
    }
    else if(three_adj_x)
    {
        return X;
    }
    else if(three_adj_o)
    {
        return O;
    }

    //if max is 2 for either, check if they are in a row
    if(max_x == 2)
    {
        for(int i = 0; i < BOARD_ROWS; i++)
        {
            if(board[i][0] == X && board[i][1] == X)
            {
                two_adj_x = true;
            }
            else if(board[i][1] == X && board[i][2] == X)
            {
                two_adj_x = true;
            }
            else if(board[i][2] == X && board[i][3] == X)
            {
                two_adj_x = true;
            }
        }
        for(int j = 0; j < BOARD_COLS; j++)
        {
            if(board[0][j] == X && board[1][j] == X)
            {
                two_adj_x = true;
            }
            else if(board[1][j] == X && board[2][j] == X)
            {
                two_adj_x = true;
            }
        }
    }

    if(max_o == 2)
    {
        for(int i = 0; i < BOARD_ROWS; i++)
        {
            if(board[i][0] == O && board[i][1] == O)
            {
                two_adj_o = true;
            }
            else if(board[i][1] == O && board[i][2] == O)
            {
                two_adj_o = true;
            }
            else if(board[i][2] == O && board[i][3] == O)
            {
                two_adj_o = true;
            }
        }
        for(int j = 0; j < BOARD_COLS; j++)
        {
            if(board[0][j] == O && board[1][j] == O)
            {
                two_adj_o = true;
            }
            else if(board[1][j] == O && board[2][j] == O)
            {
                two_adj_o = true;
            }
        }
    }

    //check for tie of 2 in a row
    if(two_adj_x && two_adj_o)
    {
        return Blank;
    }
    else if(two_adj_x)
    {
        return X;
    }
    else if(two_adj_o)
    {
        return O;
    }

    //if all above fails to return, max is 1 for both, results in tie
    return Blank;
}<|endoftext|>


<commit_before>#include <set.hpp>

#include <kdb>

#include <iostream>

using namespace std;
using namespace kdb;

SetCommand::SetCommand()
{}

int SetCommand::execute(int argc, char**argv)
{
	if (argc != 3 && argc != 4)
	{
		cerr << "Please provide a name and a value to set" << endl;
		cerr << "Usage: set <name> [<value>]" << endl;
		cerr << "If no value is given, it will be set to a null-value" << endl;
		cerr << "To get an empty value you need to quote like \"\" (depending on shell)" << endl;
		return 1;
	}

	std::string name = argv[2];

	bool nullValue = false;
	if (argc == 3) nullValue = true;

	std::string value;

	if (!nullValue) value = argv[3];

	KeySet conf;
	Key k(name, KEY_END);
	try {
		kdb.get(conf, k);
		printWarnings(k);
	} catch (...)
	{
		printError(k);
		cerr << "kdb get failed, but still resume" << endl;
	}
	Key key = conf.lookup(name);

	if (!key)
	{
		cout << "create a new key with " << name << " and " << value << endl;
		key = Key(name, KEY_END);
		if (!nullValue) key.setString(value);
		if (!key.isValid())
		{
			cerr << "no valid name supplied" << endl;
			return 1;
		}
		conf.append(key);
	} else {
		cout << "Set string to " << value << endl;
		if (!nullValue) key.setString(value);
	}
	Key n;
	kdb.set(conf, n);
	printWarnings(n);

	return 0;
}

SetCommand::~SetCommand()
{}
<commit_msg>dont commit when get failed<commit_after>#include <set.hpp>

#include <kdb>

#include <iostream>

using namespace std;
using namespace kdb;

SetCommand::SetCommand()
{}

int SetCommand::execute(int argc, char**argv)
{
	if (argc != 3 && argc != 4)
	{
		cerr << "Please provide a name and a value to set" << endl;
		cerr << "Usage: set <name> [<value>]" << endl;
		cerr << "If no value is given, it will be set to a null-value" << endl;
		cerr << "To get an empty value you need to quote like \"\" (depending on shell)" << endl;
		return 1;
	}

	std::string name = argv[2];

	bool nullValue = false;
	if (argc == 3) nullValue = true;

	std::string value;

	if (!nullValue) value = argv[3];

	KeySet conf;
	Key k(name, KEY_END);

	// do not resume on any get errors
	// otherwise the user might break
	// the config
	kdb.get(conf, k);
	printWarnings(k);

	Key key = conf.lookup(name);

	if (!key)
	{
		cout << "create a new key with " << name << " and " << value << endl;
		key = Key(name, KEY_END);
		if (!nullValue) key.setString(value);
		if (!key.isValid())
		{
			cerr << "no valid name supplied" << endl;
			return 1;
		}
		conf.append(key);
	} else {
		cout << "Set string to " << value << endl;
		if (!nullValue) key.setString(value);
	}
	Key n;
	kdb.set(conf, n);
	printWarnings(n);

	return 0;
}

SetCommand::~SetCommand()
{}
<|endoftext|>


<commit_before>#include "log.h"

// boost includes are not always warning-clean. Disable warnings that
// cause problems before including the headers, then re-enable the warnings.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wextra"

#include <boost/log/support/date_time.hpp>
#include <boost/log/expressions/attr.hpp>
#include <boost/log/expressions/formatters/date_time.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>

#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/attributes/scoped_attribute.hpp>
#include <boost/log/attributes/current_thread_id.hpp>

#include <vector>
#include <unistd.h>

#pragma GCC diagnostic pop

namespace Cthun {

bool Log::is_log_enabled(const std::string &logger, Log::log_level level) {
    // If the severity_logger returns a record for the specified
    // level, logging is enabled. Otherwise it isn't.
    // This is the guard call used in BOOST_LOG_SEV; see
    // www.boost.org/doc/libs/1_54_0/libs/log/doc/html/log/detailed/sources.html
    boost::log::sources::severity_logger<Log::log_level> slg;
    return (slg.open_record(boost::log::keywords::severity = level) ? true : false);
}

void Log::configure_logging(Log::log_level level, std::ostream &dst) {
    // Set filtering based on log_level (info, warning, debug, etc).
    auto sink = boost::log::add_console_log(dst);

    sink->set_formatter(boost::log::expressions::stream
        << boost::log::expressions::format_date_time<boost::posix_time::ptime>(
            "TimeStamp", "%Y-%m-%d %H:%M:%S.%f")
        << " " << boost::log::expressions::attr<
            boost::log::attributes::current_thread_id::value_type>("ThreadID")
        << " " << std::left << std::setfill(' ') << std::setw(5)
        << Log::log_level_attr << " "
        << Log::namespace_attr << " "
        << boost::log::expressions::smessage);

    sink->set_filter(log_level_attr >= level);
    boost::log::add_common_attributes();
}

std::ostream& Log::operator<<(std::ostream& strm, Log::log_level level) {
    std::vector<std::string> levels {
        "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" };
    if (static_cast<size_t>(level) < levels.size()) {
        strm << levels[static_cast<size_t>(level)];
    } else {
        strm << static_cast<int>(level);
    }
    return strm;
}

void Log::log(const std::string &logger, Log::log_level level, int line_num,
              boost::format& message) {
    log(logger, level, line_num, message.str());
}

//
// POSIX implementation of log()
//

// HERE(ale): we don't have the Win32 implementation; see cfacter

static std::string cyan(std::string const& message) {
    return "\33[0;36m" + message + "\33[0m";
}

static std::string green(std::string const& message) {
    return "\33[0;32m" + message + "\33[0m";
}

static std::string yellow(std::string const& message) {
    return "\33[0;33m" + message + "\33[0m";
}

static std::string red(std::string const& message) {
    return "\33[0;31m" + message + "\33[0m";
}

void Log::log(const std::string &logger, Log::log_level level, int line_num,
              std::string const& message) {
    boost::log::sources::severity_logger<Log::log_level> slg;
    slg.add_attribute("Namespace",
                      boost::log::attributes::constant<std::string>(logger));

    static bool color = isatty(fileno(stderr));
    if (!color) {
        BOOST_LOG_SEV(slg, level) << message;
        return;
    }

    switch (level) {
        case Log::log_level::trace:
            BOOST_LOG_SEV(slg, level) << line_num << " - " << cyan(message);
            break;
        case Log::log_level::debug:
            BOOST_LOG_SEV(slg, level) << line_num << " - " << cyan(message);
            break;
        case Log::log_level::info:
            BOOST_LOG_SEV(slg, level) << line_num << " - " << green(message);
            break;
        case Log::log_level::warning:
            BOOST_LOG_SEV(slg, level) << line_num << " - " << yellow(message);
            break;
        case Log::log_level::error:
            BOOST_LOG_SEV(slg, level) << line_num << " - " << red(message);
            break;
        case Log::log_level::fatal:
            BOOST_LOG_SEV(slg, level) << line_num << " - " << red(message);
            break;
        default:
            BOOST_LOG_SEV(slg, level) << line_num << " - "
                                      << "Invalid logging level used.";
            break;
    }
}

}  // namespace Cthun
<commit_msg>(maint) - updating log format<commit_after>#include "log.h"

// boost includes are not always warning-clean. Disable warnings that
// cause problems before including the headers, then re-enable the warnings.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wextra"

#include <boost/log/support/date_time.hpp>
#include <boost/log/expressions/attr.hpp>
#include <boost/log/expressions/formatters/date_time.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>

#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/attributes/scoped_attribute.hpp>
#include <boost/log/attributes/current_thread_id.hpp>

#include <vector>
#include <unistd.h>

#pragma GCC diagnostic pop

namespace Cthun {

bool Log::is_log_enabled(const std::string &logger, Log::log_level level) {
    // If the severity_logger returns a record for the specified
    // level, logging is enabled. Otherwise it isn't.
    // This is the guard call used in BOOST_LOG_SEV; see
    // www.boost.org/doc/libs/1_54_0/libs/log/doc/html/log/detailed/sources.html
    boost::log::sources::severity_logger<Log::log_level> slg;
    return (slg.open_record(boost::log::keywords::severity = level) ? true : false);
}

void Log::configure_logging(Log::log_level level, std::ostream &dst) {
    // Set filtering based on log_level (info, warning, debug, etc).
    auto sink = boost::log::add_console_log(dst);

    sink->set_formatter(boost::log::expressions::stream
        << boost::log::expressions::format_date_time<boost::posix_time::ptime>(
            "TimeStamp", "%Y-%m-%d %H:%M:%S.%f")
        << " " << boost::log::expressions::attr<
            boost::log::attributes::current_thread_id::value_type>("ThreadID")
        << " " << std::left << std::setfill(' ') << std::setw(5)
        << Log::log_level_attr << " ["
        << Log::namespace_attr << ":"
        << boost::log::expressions::smessage);

    sink->set_filter(log_level_attr >= level);
    boost::log::add_common_attributes();
}

std::ostream& Log::operator<<(std::ostream& strm, Log::log_level level) {
    std::vector<std::string> levels {
        "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" };
    if (static_cast<size_t>(level) < levels.size()) {
        strm << levels[static_cast<size_t>(level)];
    } else {
        strm << static_cast<int>(level);
    }
    return strm;
}

void Log::log(const std::string &logger, Log::log_level level, int line_num,
              boost::format& message) {
    log(logger, level, line_num, message.str());
}

//
// POSIX implementation of log()
//

// HERE(ale): we don't have the Win32 implementation; see cfacter

static std::string cyan(std::string const& message) {
    return "\33[0;36m" + message + "\33[0m";
}

static std::string green(std::string const& message) {
    return "\33[0;32m" + message + "\33[0m";
}

static std::string yellow(std::string const& message) {
    return "\33[0;33m" + message + "\33[0m";
}

static std::string red(std::string const& message) {
    return "\33[0;31m" + message + "\33[0m";
}

void Log::log(const std::string &logger, Log::log_level level, int line_num,
              std::string const& message) {
    boost::log::sources::severity_logger<Log::log_level> slg;
    slg.add_attribute("Namespace",
                      boost::log::attributes::constant<std::string>(logger));

    static bool color = isatty(fileno(stderr));
    if (!color) {
        BOOST_LOG_SEV(slg, level) << message;
        return;
    }

    switch (level) {
        case Log::log_level::trace:
            BOOST_LOG_SEV(slg, level) << line_num << "] - " << cyan(message);
            break;
        case Log::log_level::debug:
            BOOST_LOG_SEV(slg, level) << line_num << "] - " << cyan(message);
            break;
        case Log::log_level::info:
            BOOST_LOG_SEV(slg, level) << line_num << "] - " << green(message);
            break;
        case Log::log_level::warning:
            BOOST_LOG_SEV(slg, level) << line_num << "] - " << yellow(message);
            break;
        case Log::log_level::error:
            BOOST_LOG_SEV(slg, level) << line_num << "] - " << red(message);
            break;
        case Log::log_level::fatal:
            BOOST_LOG_SEV(slg, level) << line_num << "] - " << red(message);
            break;
        default:
            BOOST_LOG_SEV(slg, level) << line_num << "] - "
                                      << "Invalid logging level used.";
            break;
    }
}

}  // namespace Cthun
<|endoftext|>


<commit_before>/*
 * Copyright 2014 The Imaging Source Europe GmbH
 *
 * 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 "logging.h"
#include "version.h"

#include <stdio.h>              /* printf, fopen */
#include <stdarg.h>             /* va_args */
#include <string.h>             /* memcpy */
#include <time.h>               /* time_t */

static const char* loglevel2string (const enum TCAM_LOG_LEVEL level)
{
    switch (level)
    {
        case TCAM_LOG_OFF:
            return "OFF";
        case TCAM_LOG_TRACE:
            return "TRACE";
        case TCAM_LOG_DEBUG:
            return "DEBUG";
        case TCAM_LOG_INFO:
            return "INFO";
        case TCAM_LOG_WARNING:
            return "WARNING";
        case TCAM_LOG_ERROR:
            return "ERROR";
        default:
            return NULL;
    }
}

static enum TCAM_LOG_LEVEL string2loglevel (const char* level)
{

    if (strcmp("OFF", level) == 0)
    {
        return TCAM_LOG_OFF;
    }
    else if (strcmp("TRACE", level) == 0)
    {
        return TCAM_LOG_TRACE;
    }
    else if (strcmp("DEBUG", level) == 0)
    {
        return TCAM_LOG_DEBUG;
    }
    else if (strcmp("INFO", level) == 0)
    {
        return TCAM_LOG_INFO;
    }
    else if (strcmp("WARNING", level) == 0)
    {
        return TCAM_LOG_WARNING;
    }
    else if (strcmp("ERROR", level) == 0)
    {
        return TCAM_LOG_ERROR;
    }
    else
        return TCAM_LOG_ERROR;
}

Logger::Logger ():
    callback(nullptr),
    logfile(nullptr)
{

#ifndef TCAM_LOG_ENV_NAME
#define TCAM_LOG_ENV_NAME "TCAM_LOG"
#endif

    static const char* env_name = TCAM_LOG_ENV_NAME;

    load_default_settings();
    char* log_def = getenv(env_name);
    if (log_def != nullptr)
    {
        level = string2loglevel(log_def);
    }

    if (level >= TCAM_LOG_DEBUG)
    {
        char b[1024];
        sprintf(b,
                "\nThe following library versions are used:\n\tTcam:\t%s\n\tAravis:\t%s",
                get_version(),
                get_aravis_version());

        va_list args;
        log("", TCAM_LOG_DEBUG, "Logger", __LINE__, b, args);
    }
}

void Logger::load_default_settings ()
{
    level = TCAM_LOG_OFF;
    target = STDIO;
    log_file = "/tmp/tis.log";
}

void Logger::log (const char* module __attribute__((unused)),
                  enum TCAM_LOG_LEVEL _level,
                  const char* function,
                  int line,
                  const char* message,
                  va_list args)
{
    if (_level < level)
    {
        return;
    }

    // local copy of va_list
    // required because vsnprintf calls va_arg()
    // thus making reusage in the 2. vsnprintf call impossible
    va_list tmp_args;
    va_copy(tmp_args, args);

    size_t size = vsnprintf(NULL, 0, message, tmp_args) + 1;
    char *msg = new char[size];

    va_end(tmp_args);

    vsnprintf(msg, size, message, args);
    // use clock_t and not time_t
    // we want the time the program uses based on the
    // cpu and not on a human readable clock.
    clock_t t;
    t = clock();

#pragma GCC diagnostic ignored "-Wformat-truncation"

    size_t buffer_size = snprintf(nullptr,
                                  0,
                                  "%-10ld <%s> %s:%d: %s\n",
                                  /* ctime(&timer), */
                                  t,
                                  loglevel2string(_level),
                                  function,
                                  line,
                                  msg) + 1;

#pragma GCC diagnostic pop

    /* write complete message */
    char *buffer = new char[buffer_size];

    sprintf(buffer,
            "%-10ld <%s> %s:%d: %s\n",
            /* ctime(&timer), */
            t,
            loglevel2string(_level),
            function,
            line,
            msg);

    switch (target)
    {
        case STDIO:
        {
            log_to_stdout(buffer);
            if (callback)
            {
                callback(cb_user_data, _level, function, line, message, args);
            }
            break;
        }
        case LOGFILE:
        {
            log_to_file(buffer);
            break;
        }
        case USER_DEFINED:
        {
            //logger.callback(_level, file, line, message, args);
            break;
        }
        default:
            break;
    }
    delete [] buffer;
    delete [] msg;
}

void Logger::log_to_stdout (const char* message)
{
    fprintf(stdout, "%s", message);
    fflush(stdout);
}

void Logger::log_to_file (const char* message __attribute__((unused)))
{}

void Logger::set_log_level (enum TCAM_LOG_LEVEL l)
{
    level = l;
}

enum TCAM_LOG_LEVEL Logger::get_log_level () const
{
    return level;
}

void Logger::set_target (enum TCAM_LOG_TARGET t)
{
    target = t;
}

enum TCAM_LOG_TARGET Logger::get_target () const
{
    return target;
}

void Logger::set_log_file (const std::string& filename)
{
    log_file = filename;
}

std::string Logger::get_log_file () const
{
    return log_file;
}

void Logger::set_external_callback (logging_callback c,
                                    void* user_data)
{
    callback = c;
    cb_user_data = user_data;
}

void Logger::delete_external_callback ()
{
    callback = nullptr;
}

void Logger::open_logfile ()
{
    if (!log_file.empty())
        logfile = fopen(log_file.c_str(), "a+");
}

void Logger::close_logfile ()
{
    if (logfile != NULL)
    {
        fclose(logfile);
        logfile = NULL;
    }
}

Logger& Logger::getInstance ()
{
    static Logger instance;

    return instance;
}

void tcam_set_logging_level (enum TCAM_LOG_LEVEL level)
{
    Logger::getInstance().set_log_level(level);
}

enum TCAM_LOG_LEVEL tcam_get_logging_level ()
{
    return Logger::getInstance().get_log_level();
}

void tcam_logging_init(enum TCAM_LOG_TARGET target, enum TCAM_LOG_LEVEL level)
{
    tcam_set_logging_target(target);
    tcam_set_logging_level(level);
}

void tcam_set_logging_target (enum TCAM_LOG_TARGET target)
{
    Logger::getInstance().set_target(target);
}

void tcam_set_logging_file (const char* logfile_name)
{
    Logger::getInstance().set_log_file(logfile_name);
}

const char* tcam_get_logging_file ()
{
    return Logger::getInstance().get_log_file().c_str();
}

void tcam_logging (enum TCAM_LOG_LEVEL level, const char* file, int line, const char* message, ...)
{
    if (Logger::getInstance().get_log_level() > level ||
        Logger::getInstance().get_log_level() == TCAM_LOG_OFF)
    {
        return;
    }

    va_list args;
    va_start(args, message);

    Logger::getInstance().log("", level, file, line, message, args);

    va_end(args);
}

void tcam_logging (const char* module, enum TCAM_LOG_LEVEL level, const char* function, int line, const char* message, ...)
{
    if (Logger::getInstance().get_log_level() > level ||
        Logger::getInstance().get_log_level() == TCAM_LOG_OFF)
    {
        return;
    }

    va_list args;
    va_start(args, message);

    Logger::getInstance().log(module, level, function, line, message, args);

    va_end(args);
}
<commit_msg>logging: Make timestamps human readable<commit_after>/*
 * Copyright 2014 The Imaging Source Europe GmbH
 *
 * 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 "logging.h"
#include "version.h"

#include <stdio.h>              /* printf, fopen */
#include <stdarg.h>             /* va_args */
#include <string.h>             /* memcpy */
#include <time.h>               /* time_t */
#include <vector>
#include <chrono>

static const char* loglevel2string (const enum TCAM_LOG_LEVEL level)
{
    switch (level)
    {
        case TCAM_LOG_OFF:
            return "OFF";
        case TCAM_LOG_TRACE:
            return "TRACE";
        case TCAM_LOG_DEBUG:
            return "DEBUG";
        case TCAM_LOG_INFO:
            return "INFO";
        case TCAM_LOG_WARNING:
            return "WARNING";
        case TCAM_LOG_ERROR:
            return "ERROR";
        default:
            return NULL;
    }
}

static enum TCAM_LOG_LEVEL string2loglevel (const char* level)
{

    if (strcmp("OFF", level) == 0)
    {
        return TCAM_LOG_OFF;
    }
    else if (strcmp("TRACE", level) == 0)
    {
        return TCAM_LOG_TRACE;
    }
    else if (strcmp("DEBUG", level) == 0)
    {
        return TCAM_LOG_DEBUG;
    }
    else if (strcmp("INFO", level) == 0)
    {
        return TCAM_LOG_INFO;
    }
    else if (strcmp("WARNING", level) == 0)
    {
        return TCAM_LOG_WARNING;
    }
    else if (strcmp("ERROR", level) == 0)
    {
        return TCAM_LOG_ERROR;
    }
    else
        return TCAM_LOG_ERROR;
}

Logger::Logger ():
    callback(nullptr),
    logfile(nullptr)
{

#ifndef TCAM_LOG_ENV_NAME
#define TCAM_LOG_ENV_NAME "TCAM_LOG"
#endif

    static const char* env_name = TCAM_LOG_ENV_NAME;

    load_default_settings();
    char* log_def = getenv(env_name);
    if (log_def != nullptr)
    {
        level = string2loglevel(log_def);
    }

    if (level >= TCAM_LOG_DEBUG)
    {
        char b[1024];
        sprintf(b,
                "\nThe following library versions are used:\n\tTcam:\t%s\n\tAravis:\t%s",
                get_version(),
                get_aravis_version());

        va_list args;
        log("", TCAM_LOG_DEBUG, "Logger", __LINE__, b, args);
    }
}

void Logger::load_default_settings ()
{
    level = TCAM_LOG_OFF;
    target = STDIO;
    log_file = "/tmp/tis.log";
}

void Logger::log (const char* module __attribute__((unused)),
                  enum TCAM_LOG_LEVEL _level,
                  const char* function,
                  int line,
                  const char* message,
                  va_list args)
{
    if (_level < level)
    {
        return;
    }

    // local copy of va_list
    // required because vsnprintf calls va_arg()
    // thus making reusage in the 2. vsnprintf call impossible
    va_list tmp_args;
    va_copy(tmp_args, args);

    size_t size = vsnprintf(NULL, 0, message, tmp_args) + 1;
    char *msg = new char[size];

    va_end(tmp_args);

    vsnprintf(msg, size, message, args);

    // get current time
    auto now = std::chrono::system_clock::now();

    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;

    std::time_t now_c = std::chrono::system_clock::to_time_t(now);
    std::tm now_tm = *std::localtime(&now_c);

    const size_t t_size = 80;
    std::vector<char> t0(t_size);
    std::vector<char> t(t_size);

    strftime(t0.data(), t_size -1, "%Y.%m.%dT%H:%M:%S:%%03u", &now_tm);
    snprintf(t.data(), t_size -1, t0.data(),  ms);

#pragma GCC diagnostic ignored "-Wformat-truncation"

    size_t buffer_size = snprintf(nullptr,
                                  0,
                                  "%-30s <%s> %s:%d: %s\n",
                                  /* ctime(&timer), */
                                  t.data(),
                                  loglevel2string(_level),
                                  function,
                                  line,
                                  msg) + 1;

#pragma GCC diagnostic pop

    /* write complete message */
    char *buffer = new char[buffer_size];

    sprintf(buffer,
            "%-30s <%s> %s:%d: %s\n",
            /* ctime(&timer), */
            t.data(),
            loglevel2string(_level),
            function,
            line,
            msg);

    switch (target)
    {
        case STDIO:
        {
            log_to_stdout(buffer);
            if (callback)
            {
                callback(cb_user_data, _level, function, line, message, args);
            }
            break;
        }
        case LOGFILE:
        {
            log_to_file(buffer);
            break;
        }
        case USER_DEFINED:
        {
            //logger.callback(_level, file, line, message, args);
            break;
        }
        default:
            break;
    }
    delete [] buffer;
    delete [] msg;
}

void Logger::log_to_stdout (const char* message)
{
    fprintf(stdout, "%s", message);
    fflush(stdout);
}

void Logger::log_to_file (const char* message __attribute__((unused)))
{}

void Logger::set_log_level (enum TCAM_LOG_LEVEL l)
{
    level = l;
}

enum TCAM_LOG_LEVEL Logger::get_log_level () const
{
    return level;
}

void Logger::set_target (enum TCAM_LOG_TARGET t)
{
    target = t;
}

enum TCAM_LOG_TARGET Logger::get_target () const
{
    return target;
}

void Logger::set_log_file (const std::string& filename)
{
    log_file = filename;
}

std::string Logger::get_log_file () const
{
    return log_file;
}

void Logger::set_external_callback (logging_callback c,
                                    void* user_data)
{
    callback = c;
    cb_user_data = user_data;
}

void Logger::delete_external_callback ()
{
    callback = nullptr;
}

void Logger::open_logfile ()
{
    if (!log_file.empty())
        logfile = fopen(log_file.c_str(), "a+");
}

void Logger::close_logfile ()
{
    if (logfile != NULL)
    {
        fclose(logfile);
        logfile = NULL;
    }
}

Logger& Logger::getInstance ()
{
    static Logger instance;

    return instance;
}

void tcam_set_logging_level (enum TCAM_LOG_LEVEL level)
{
    Logger::getInstance().set_log_level(level);
}

enum TCAM_LOG_LEVEL tcam_get_logging_level ()
{
    return Logger::getInstance().get_log_level();
}

void tcam_logging_init(enum TCAM_LOG_TARGET target, enum TCAM_LOG_LEVEL level)
{
    tcam_set_logging_target(target);
    tcam_set_logging_level(level);
}

void tcam_set_logging_target (enum TCAM_LOG_TARGET target)
{
    Logger::getInstance().set_target(target);
}

void tcam_set_logging_file (const char* logfile_name)
{
    Logger::getInstance().set_log_file(logfile_name);
}

const char* tcam_get_logging_file ()
{
    return Logger::getInstance().get_log_file().c_str();
}

void tcam_logging (enum TCAM_LOG_LEVEL level, const char* file, int line, const char* message, ...)
{
    if (Logger::getInstance().get_log_level() > level ||
        Logger::getInstance().get_log_level() == TCAM_LOG_OFF)
    {
        return;
    }

    va_list args;
    va_start(args, message);

    Logger::getInstance().log("", level, file, line, message, args);

    va_end(args);
}

void tcam_logging (const char* module, enum TCAM_LOG_LEVEL level, const char* function, int line, const char* message, ...)
{
    if (Logger::getInstance().get_log_level() > level ||
        Logger::getInstance().get_log_level() == TCAM_LOG_OFF)
    {
        return;
    }

    va_list args;
    va_start(args, message);

    Logger::getInstance().log(module, level, function, line, message, args);

    va_end(args);
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
// The Loki Library
// Copyright (c) 2005 by Curtis Krauskopf
// Copyright (c) 2005 by Peter Kuemmel
//
// Code covered by the MIT License
// The authors make no representations about the suitability of this software
// for any purpose. It is provided "as is" without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////

// This is an example of using the SetLongevity function for both
// singletons and globally and locally defined dynamically allocated
// objects.
//
// The program defines three classes:  Example, Keyboard and LogClass.
//
// The purpose of the Example class is to send a message to cout
// when an Example object is being destroyed.
//
// The Keyboard class is a singleton.
//
// The LogClass class is also a singleton.
//
// The pGlobal object is deleted using an adapter functor to
// customize Example's destruction (see destGlobal()).
// The glue that binds the adapter functor (above) with Loki's
// SetLongevity function is:
//
// Loki::Private::Adapter<Example>exampleAdapter = {&destGlobal};
// SetLongevity(pGlobal, globalPriority, exampleAdapter);
//
// An alternative Loki-compatible way of destroying pGlobal (without
// defining a global static functor) is to use the default parameter
// on SetLongevity:
//
// Example *pLocal = new Example("Destroying local Example");
// SetLongevity(pLocal, localPriority);
//
// The parameters passed by the user on main define the longevity values
// for (respectively):
//  1)  The global object
//  2)  The local object
//  3)  The Keyboard singleton
//  4)  The LogClass singleton
//
// Examples:
//    longevity 1 2 3 4
//    longevity 40 30 20 10
//

#include <iostream>
#include <loki/Singleton.h>   // for Loki::SingletonHolder

using namespace std;   // okay for small programs
using namespace Loki;  // okay for small programs

// These globals allow the priority for each object to be
// set in main() but used anywhere in the program.
int  globalPriority;
int  localPriority;
int  keyboardPriority;
int  logPriority;

// A generic example class that stores and echoes a const char.
//
class Example
{
public:
    Example(const char * s)
    {
        msg = s;
    };
    virtual ~Example()
    {
        echo(msg);
    }
    void echo(const char *s)
    {
        cout << s << endl;
    }
protected:
    const char *msg;
};

// A singleton Keyboard object derived from the Example class.
// Its longevity is set by the user on the command line.
//
class Keyboard : public Example
{
public:
    Keyboard() : Example("Destroying Keyboard")
    {  }
}
;

inline unsigned int GetLongevity(Keyboard *)
{
    return keyboardPriority;
}

typedef SingletonHolder<Keyboard, CreateUsingNew, SingletonWithLongevity> keyboard;

// A singleton LogClass object derived from the Example class.
// Its longevity is set by the user on the command line.
//
class LogClass : public Example
{
public:
    LogClass() : Example("Destroying LogClass")
    {  }
}
;

inline unsigned int GetLongevity(LogClass *)
{
    return logPriority;
}

typedef SingletonHolder<LogClass, CreateUsingNew, SingletonWithLongevity> LogBook;

// Instantiate a global Example object.  It's not a singleton
// but because it's instantiated with new (and therefore it isn't
// automatically destroyed) it can use the SetLongevity template function.
// Its longevity is determined by the user on the command line.
//
Example* pGlobal( new Example("Destroying global Example") );

// destGlobal() is called when the pGlobal object needs to be destroyed.
static void destGlobal()
{
    cout << "Going to delete pGlobal\n";
    delete pGlobal;
}

void help(const char *s)
{
    cout << "To use:\n";
    cout << s << " par1 par2 par3 par4\n";
    cout << "  where each par is a number that represents the object's ";
    cout << " longevity:\n";
    cout << "    par1: global object\n";
    cout << "    par2: local object\n";
    cout << "    par3: keyboard singleton\n";
    cout << "    par4: LogBook singleton\n";
    cout << "Example:  " << s << " 1 2 3 4" << endl;
}

int main(int argc, char *argv[])
{
    if (argc != 5)
    {
        help(argv[0]);
        return 0;
    }

    globalPriority = atoi(argv[1]);
    localPriority = atoi(argv[2]);
    keyboardPriority = atoi(argv[3]);
    logPriority = atoi(argv[4]);

    // Use an adapter functor to tie the destGlobal function to the
    // destruction priority for pGlobal.
    Loki::Private::Adapter<Example> exampleAdapter = { &destGlobal };
    SetLongevity(pGlobal, globalPriority, exampleAdapter);

    // Use Loki's private Deleter template function to destroy the
    // pLocal object for a user-defined priority.
    Example *pLocal = new Example("Destroying local Example");
    SetLongevity<Example, void (*)(Example*)>(pLocal, localPriority, &Loki::Private::Deleter<Example>::Delete);

    // Make the global and local objects announce their presense.
    pGlobal->echo("pGlobal created during program initialization.");
    pLocal->echo("pLocal created after main() started.");

    // Instantiate both singletons by calling them...
    LogBook::Instance().echo("LogClass singleton instantiated");
    keyboard::Instance().echo("Keyboard singleton instantiated");

    return 0;
}

<commit_msg>swap names<commit_after>////////////////////////////////////////////////////////////////////////////////
// The Loki Library
// Copyright (c) 2005 by Peter Kuemmel
//
// Code covered by the MIT License
// The author make no representations about the suitability of this software
// for any purpose. It is provided "as is" without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////

#include <iostream>

#include <loki/Singleton.h>

struct L1
{
    L1(){std::cout << "create L1: " << this << "\n";}
    ~L1(){std::cout << "delete L1: " << this <<" \n";}
};

struct L2
{
    L2(){std::cout << "create L2 \n";}
    ~L2(){std::cout << "delete L2 \n";}
};

struct L3
{
    L3(){std::cout << "create L3 \n";}
    ~L3(){std::cout << "delete L3 \n";}
};

int main()
{
    Loki::SetLongevity
                (new L1, 1);
    Loki::SetLongevity<L1,    void (*)(L1*)>
                (new L1, 1, Loki::Private::Deleter<L1>::Delete);
    Loki::SetLongevity<L1,    Loki::Private::Deleter<L1>::Type>
                (new L1, 1, Loki::Private::Deleter<L1>::Delete);
    Loki::SetLongevity(new L2, 2);
    Loki::SetLongevity(new L1, 1);
    Loki::SetLongevity(new L3, 3);
    Loki::SetLongevity(new L1, 1);

    std::cout << "\n";
}

<|endoftext|>