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

#include "paddle/fluid/operators/temporal_shift_op.h"
#include <memory>
#include <string>
#include <vector>
#include "paddle/fluid/framework/op_registry.h"

namespace paddle {
namespace operators {

using framework::Tensor;

class TemporalShiftOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

 protected:
  void InferShape(framework::InferShapeContext* ctx) const override {
    PADDLE_ENFORCE(ctx->HasInput("X"),
                   "Input(X) of TemporalShiftOp should not be null.");
    PADDLE_ENFORCE(ctx->HasOutput("Out"),
                   "Output(Out) of TemporalShiftOp should not be null.");

    auto dim_x = ctx->GetInputDim("X");
    PADDLE_ENFORCE_EQ(dim_x.size(), 4,
                      "Input(X) rank should be 4 in shape of [N*T, C, H, W].");

    int seg_num = ctx->Attrs().Get<int>("seg_num");
    float shift_ratio = ctx->Attrs().Get<float>("shift_ratio");
    PADDLE_ENFORCE_GT(seg_num, 0, "Attr(seg_num) should be greater than 0.");
    PADDLE_ENFORCE(shift_ratio > 0 || shift_ratio < .5,
                   "Attr(shift_ratio) should be greater than 0 and less "
                   "than 0.5.");

    if (ctx->IsRuntime()) {
      PADDLE_ENFORCE_EQ(
          dim_x[0] % seg_num, 0,
          "Input(X) dims[0] should be divided exactly by Attr(seg_num).");
    }

    ctx->SetOutputDim("Out", dim_x);
    ctx->ShareLoD("X", "Out");
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext& ctx) const override {
    return framework::OpKernelType(ctx.Input<Tensor>("X")->type(),
                                   ctx.GetPlace());
  }
};

class TemporalShiftOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  void Make() override {
    AddInput("X",
             "The input tensor of temporal shift operator. "
             "This is a 4-D tensor with shape of [N*T,  C, H, W]. "
             "While N is the batch size, T is the temporal segment "
             "number, C is the channel number, H is the height of "
             "features and W is the width of features.");
    AddOutput("Out",
              "The output tensor of temporal shift operator. "
              "This is a 4-D tensor in the same shape with Input(X).");

    AddAttr<int>("seg_num",
                 "The temporal segment number, this should be a positive "
                 "integer.");
    AddAttr<float>(
        "shift_ratio",
        "The shift ratio of the channels, the first :attr:`shift_ratio` part "
        "of channels will be shifted by -1 along the temporal dimension, "
        "and the second :attr:`shift_ratio` part of channels will be shifted "
        "by 1 along the temporal dimension. Default 0.25.")
        .SetDefault(0.25);

    AddComment(R"DOC(
          This operator calculates the temporal shifting features for Input(X).

          Input(X) should be in shape of [N*T, C, H, W], while N is the batch
          size, T is the temporal segment number specified by :attr:`seg_num`,
          C is the channel number, H and W is the height and width of features.

          Temporal Shifting is calculated as follows:

          Step 1: Reshape Input(X) to [N, T, C, H, W].

          Step 2: Pad 0 to reshaping result in the 2nd(T) dimension with
          padding width as 1 on each side, padding result will be in shape
          of [N, T+2, C, H, W].

          Step 3: Assume :attr:`shift_ratio` is :math:`1/4`, slice padding
          result as follows:

          $$
          slice1 = x[:, :T, :C/4, :, :]
          $$
          $$
          slice2 = x[:, 2:T+2, C/4:C/2, :, :]
          $$
          $$
          slice3 = x[:, 1:T+1, C/2:, :, :]
          $$

          Step 4: Concatenate three slices along the 3rd(C) dimension and
          reshape result to [N*T, C, H, W].

          For details of temporal shifting, please refer to paper:
          `Temporal Shift Module <http://arxiv.org/abs/1811.08383>`_ .

         )DOC");
  }
};

class TemporalShiftOpGrad : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

 protected:
  void InferShape(framework::InferShapeContext* ctx) const override {
    if (ctx->HasOutput(framework::GradVarName("X"))) {
      ctx->SetOutputDim(framework::GradVarName("X"),
                        ctx->GetInputDim(framework::GradVarName("Out")));
    }
  }

  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext& ctx) const override {
    return framework::OpKernelType(
        ctx.Input<Tensor>(framework::GradVarName("Out"))->type(),
        ctx.GetPlace());
  }
};

class TemporalShiftGradOpDescMaker : public framework::SingleGradOpDescMaker {
 public:
  using framework::SingleGradOpDescMaker::SingleGradOpDescMaker;

 protected:
  std::unique_ptr<framework::OpDesc> Apply() const override {
    std::unique_ptr<framework::OpDesc> op(new framework::OpDesc());
    op->SetType("temporal_shift_grad");
    op->SetInput(framework::GradVarName("Out"), OutputGrad("Out"));
    op->SetOutput(framework::GradVarName("X"), InputGrad("X"));
    op->SetAttrMap(Attrs());
    return op;
  }
};

}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;
REGISTER_OPERATOR(temporal_shift, ops::TemporalShiftOp,
                  ops::TemporalShiftOpMaker, ops::TemporalShiftGradOpDescMaker);
REGISTER_OPERATOR(temporal_shift_grad, ops::TemporalShiftOpGrad);
REGISTER_OP_CPU_KERNEL(temporal_shift, ops::TemporalShiftKernel<float>,
                       ops::TemporalShiftKernel<double>);
REGISTER_OP_CPU_KERNEL(temporal_shift_grad, ops::TemporalShiftGradKernel<float>,
                       ops::TemporalShiftGradKernel<double>);
<commit_msg>fix temporal_shift OP PADDLE_ENFORCE. test=develop (#19161)<commit_after>/* Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserve.
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at
   http://www.apache.org/licenses/LICENSE-2.0
   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

#include "paddle/fluid/operators/temporal_shift_op.h"
#include <memory>
#include <string>
#include <vector>
#include "paddle/fluid/framework/op_registry.h"

namespace paddle {
namespace operators {

using framework::Tensor;

class TemporalShiftOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

 protected:
  void InferShape(framework::InferShapeContext* ctx) const override {
    PADDLE_ENFORCE_EQ(ctx->HasInput("X"), true,
                      "Input(X) of TemporalShiftOp should not be null.");
    PADDLE_ENFORCE_EQ(ctx->HasOutput("Out"), true,
                      "Output(Out) of TemporalShiftOp should not be null.");

    auto dim_x = ctx->GetInputDim("X");
    PADDLE_ENFORCE_EQ(dim_x.size(), 4,
                      "Input(X) rank should be 4 in shape of [N*T, C, H, W].");

    int seg_num = ctx->Attrs().Get<int>("seg_num");
    float shift_ratio = ctx->Attrs().Get<float>("shift_ratio");
    PADDLE_ENFORCE_GT(seg_num, 0, "Attr(seg_num) should be greater than 0.");
    PADDLE_ENFORCE_GT(shift_ratio, 0.,
                      "Attr(shift_ratio) should be greater than 0");
    PADDLE_ENFORCE_LT(shift_ratio, 0.5,
                      "Attr(shift_ratio) should be less than 0.5");

    if (ctx->IsRuntime()) {
      PADDLE_ENFORCE_EQ(
          dim_x[0] % seg_num, 0,
          "Input(X) dims[0] should be divided exactly by Attr(seg_num).");
    }

    ctx->SetOutputDim("Out", dim_x);
    ctx->ShareLoD("X", "Out");
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext& ctx) const override {
    return framework::OpKernelType(ctx.Input<Tensor>("X")->type(),
                                   ctx.GetPlace());
  }
};

class TemporalShiftOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  void Make() override {
    AddInput("X",
             "The input tensor of temporal shift operator. "
             "This is a 4-D tensor with shape of [N*T,  C, H, W]. "
             "While N is the batch size, T is the temporal segment "
             "number, C is the channel number, H is the height of "
             "features and W is the width of features.");
    AddOutput("Out",
              "The output tensor of temporal shift operator. "
              "This is a 4-D tensor in the same shape with Input(X).");

    AddAttr<int>("seg_num",
                 "The temporal segment number, this should be a positive "
                 "integer.");
    AddAttr<float>(
        "shift_ratio",
        "The shift ratio of the channels, the first :attr:`shift_ratio` part "
        "of channels will be shifted by -1 along the temporal dimension, "
        "and the second :attr:`shift_ratio` part of channels will be shifted "
        "by 1 along the temporal dimension. Default 0.25.")
        .SetDefault(0.25);

    AddComment(R"DOC(
          This operator calculates the temporal shifting features for Input(X).

          Input(X) should be in shape of [N*T, C, H, W], while N is the batch
          size, T is the temporal segment number specified by :attr:`seg_num`,
          C is the channel number, H and W is the height and width of features.

          Temporal Shifting is calculated as follows:

          Step 1: Reshape Input(X) to [N, T, C, H, W].

          Step 2: Pad 0 to reshaping result in the 2nd(T) dimension with
          padding width as 1 on each side, padding result will be in shape
          of [N, T+2, C, H, W].

          Step 3: Assume :attr:`shift_ratio` is :math:`1/4`, slice padding
          result as follows:

          $$
          slice1 = x[:, :T, :C/4, :, :]
          $$
          $$
          slice2 = x[:, 2:T+2, C/4:C/2, :, :]
          $$
          $$
          slice3 = x[:, 1:T+1, C/2:, :, :]
          $$

          Step 4: Concatenate three slices along the 3rd(C) dimension and
          reshape result to [N*T, C, H, W].

          For details of temporal shifting, please refer to paper:
          `Temporal Shift Module <http://arxiv.org/abs/1811.08383>`_ .

         )DOC");
  }
};

class TemporalShiftOpGrad : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

 protected:
  void InferShape(framework::InferShapeContext* ctx) const override {
    if (ctx->HasOutput(framework::GradVarName("X"))) {
      ctx->SetOutputDim(framework::GradVarName("X"),
                        ctx->GetInputDim(framework::GradVarName("Out")));
    }
  }

  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext& ctx) const override {
    return framework::OpKernelType(
        ctx.Input<Tensor>(framework::GradVarName("Out"))->type(),
        ctx.GetPlace());
  }
};

class TemporalShiftGradOpDescMaker : public framework::SingleGradOpDescMaker {
 public:
  using framework::SingleGradOpDescMaker::SingleGradOpDescMaker;

 protected:
  std::unique_ptr<framework::OpDesc> Apply() const override {
    std::unique_ptr<framework::OpDesc> op(new framework::OpDesc());
    op->SetType("temporal_shift_grad");
    op->SetInput(framework::GradVarName("Out"), OutputGrad("Out"));
    op->SetOutput(framework::GradVarName("X"), InputGrad("X"));
    op->SetAttrMap(Attrs());
    return op;
  }
};

}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;
REGISTER_OPERATOR(temporal_shift, ops::TemporalShiftOp,
                  ops::TemporalShiftOpMaker, ops::TemporalShiftGradOpDescMaker);
REGISTER_OPERATOR(temporal_shift_grad, ops::TemporalShiftOpGrad);
REGISTER_OP_CPU_KERNEL(temporal_shift, ops::TemporalShiftKernel<float>,
                       ops::TemporalShiftKernel<double>);
REGISTER_OP_CPU_KERNEL(temporal_shift_grad, ops::TemporalShiftGradKernel<float>,
                       ops::TemporalShiftGradKernel<double>);
<|endoftext|>


<commit_before>#include <iostream>

class Number
{

private:
    int number;

    std::vector<int> function getFactors();
    int function getLargestPrimeFactor();
}

<commit_msg>adding some changes<commit_after>#include <iostream>

class Number
{

private:
    int number;

    std::vector<int> function getFactors();
    int function getLargestPrimeFactor();
}

#include <iostream>
#include <vector>
#include <cmath>

// Initializing
Number::Number(int n)
: mNumber(n)
{
}

// Get the factors of a number
std::vector<int> problem3::getFactors()
{
   double squareRootValue = floor(sqrt(mNumber));

   // Cheching if
   if(squareRootValue >= 2)
   {
       for(int i = 2; i <= squareRootValue; i++)
       {
           if(mNumber % i == 0)
               mFactors = push(i);
           else
               getFactors();
       }
   }
}

int problem3::getLargestPrimeFactor()
{

}

int main() {

	return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "was/Client.hxx"
#include "was/Launch.hxx"
#include "was/Lease.hxx"
#include "stopwatch.hxx"
#include "lease.hxx"
#include "HttpResponseHandler.hxx"
#include "direct.hxx"
#include "strmap.hxx"
#include "istream/Handler.hxx"
#include "istream/Pointer.hxx"
#include "istream/UnusedPtr.hxx"
#include "istream/FileIstream.hxx"
#include "fb_pool.hxx"
#include "PInstance.hxx"
#include "spawn/Config.hxx"
#include "spawn/ChildOptions.hxx"
#include "spawn/Registry.hxx"
#include "spawn/Local.hxx"
#include "io/Logger.hxx"
#include "util/ConstBuffer.hxx"
#include "util/Cancellable.hxx"
#include "util/PrintException.hxx"
#include "util/StaticArray.hxx"

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

struct Context final
    : PInstance, WasLease, IstreamHandler, HttpResponseHandler {

    WasProcess process;

    IstreamPointer body;
    bool error;

    CancellablePointer cancel_ptr;

    Context():body(nullptr) {}

    /* virtual methods from class IstreamHandler */

    size_t OnData(const void *data, size_t length) noexcept override;

    void OnEof() noexcept override {
        body.Clear();
    }

    void OnError(std::exception_ptr ep) noexcept override {
        PrintException(ep);

        body.Clear();
        error = true;
    }

    /* virtual methods from class Lease */
    void ReleaseWas(gcc_unused bool reuse) override {
        kill(process.pid, SIGTERM);

        process.Close();
    }

    void ReleaseWasStop(gcc_unused uint64_t input_received) override {
        ReleaseWas(false);
    }

    /* virtual methods from class HttpResponseHandler */
    void OnHttpResponse(http_status_t status, StringMap &&headers,
                        UnusedIstreamPtr body) noexcept override;
    void OnHttpError(std::exception_ptr ep) noexcept override;
};

/*
 * istream handler
 *
 */

size_t
Context::OnData(const void *data, size_t length) noexcept
{
    ssize_t nbytes = write(1, data, length);
    if (nbytes <= 0) {
        error = true;
        body.ClearAndClose();
        return 0;
    }

    return (size_t)nbytes;
}

/*
 * http_response_handler
 *
 */

void
Context::OnHttpResponse(gcc_unused http_status_t status,
                        gcc_unused StringMap &&headers,
                        UnusedIstreamPtr _body) noexcept
{
    if (_body)
        body.Set(std::move(_body), *this);
}

void
Context::OnHttpError(std::exception_ptr ep) noexcept
{
    PrintException(ep);

    error = true;
}

static Istream *
request_body(EventLoop &event_loop, struct pool &pool)
{
    struct stat st;
    return fstat(0, &st) == 0 && S_ISREG(st.st_mode)
        ? istream_file_fd_new(event_loop, pool,
                              "/dev/stdin", UniqueFileDescriptor(STDIN_FILENO),
                              FdType::FD_FILE, -1)
        : nullptr;
}

int
main(int argc, char **argv)
try {
    SetLogLevel(5);

    StaticArray<const char *, 64> params;

    if (argc < 3) {
        fprintf(stderr, "Usage: run_was PATH URI [--parameter a=b ...]\n");
        return EXIT_FAILURE;
    }

    const char *uri = argv[2];

    for (int i = 3; i < argc;) {
        if (strcmp(argv[i], "--parameter") == 0 ||
            strcmp(argv[i], "-p") == 0) {
            ++i;
            if (i >= argc)
                throw std::runtime_error("Parameter value missing");

            if (params.full())
                throw std::runtime_error("Too many parameters");

            params.push_back(argv[i++]);
        } else
            throw std::runtime_error("Unrecognized parameter");
    }

    direct_global_init();

    SpawnConfig spawn_config;

    const ScopeFbPoolInit fb_pool_init;

    ChildOptions child_options;

    Context context;
    ChildProcessRegistry child_process_registry(context.event_loop);
    child_process_registry.SetVolatile();
    LocalSpawnService spawn_service(spawn_config, child_process_registry);

    context.process = was_launch(spawn_service, "was",
                                 argv[1], nullptr,
                                 child_options, {}, nullptr);

    was_client_request(context.root_pool, context.event_loop, nullptr,
                       context.process.control,
                       context.process.input,
                       context.process.output,
                       context,
                       HTTP_METHOD_GET, uri,
                       nullptr,
                       nullptr, nullptr,
                       *strmap_new(context.root_pool),
                       UnusedIstreamPtr(request_body(context.event_loop,
                                                     context.root_pool)),
                       { (const char *const*)params.raw(), params.size() },
                       context, context.cancel_ptr);

    context.event_loop.Dispatch();

    return context.error;
} catch (const std::exception &e) {
    PrintException(e);
    return EXIT_FAILURE;
}
<commit_msg>test/run_was: print the status to stderr<commit_after>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "was/Client.hxx"
#include "was/Launch.hxx"
#include "was/Lease.hxx"
#include "stopwatch.hxx"
#include "lease.hxx"
#include "HttpResponseHandler.hxx"
#include "direct.hxx"
#include "strmap.hxx"
#include "istream/Handler.hxx"
#include "istream/Pointer.hxx"
#include "istream/UnusedPtr.hxx"
#include "istream/FileIstream.hxx"
#include "fb_pool.hxx"
#include "PInstance.hxx"
#include "spawn/Config.hxx"
#include "spawn/ChildOptions.hxx"
#include "spawn/Registry.hxx"
#include "spawn/Local.hxx"
#include "io/Logger.hxx"
#include "util/ConstBuffer.hxx"
#include "util/Cancellable.hxx"
#include "util/PrintException.hxx"
#include "util/StaticArray.hxx"

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

struct Context final
    : PInstance, WasLease, IstreamHandler, HttpResponseHandler {

    WasProcess process;

    IstreamPointer body;
    bool error;

    CancellablePointer cancel_ptr;

    Context():body(nullptr) {}

    /* virtual methods from class IstreamHandler */

    size_t OnData(const void *data, size_t length) noexcept override;

    void OnEof() noexcept override {
        body.Clear();
    }

    void OnError(std::exception_ptr ep) noexcept override {
        PrintException(ep);

        body.Clear();
        error = true;
    }

    /* virtual methods from class Lease */
    void ReleaseWas(gcc_unused bool reuse) override {
        kill(process.pid, SIGTERM);

        process.Close();
    }

    void ReleaseWasStop(gcc_unused uint64_t input_received) override {
        ReleaseWas(false);
    }

    /* virtual methods from class HttpResponseHandler */
    void OnHttpResponse(http_status_t status, StringMap &&headers,
                        UnusedIstreamPtr body) noexcept override;
    void OnHttpError(std::exception_ptr ep) noexcept override;
};

/*
 * istream handler
 *
 */

size_t
Context::OnData(const void *data, size_t length) noexcept
{
    ssize_t nbytes = write(1, data, length);
    if (nbytes <= 0) {
        error = true;
        body.ClearAndClose();
        return 0;
    }

    return (size_t)nbytes;
}

/*
 * http_response_handler
 *
 */

void
Context::OnHttpResponse(http_status_t status,
                        gcc_unused StringMap &&headers,
                        UnusedIstreamPtr _body) noexcept
{
    fprintf(stderr, "status: %s\n", http_status_to_string(status));

    if (_body)
        body.Set(std::move(_body), *this);
}

void
Context::OnHttpError(std::exception_ptr ep) noexcept
{
    PrintException(ep);

    error = true;
}

static Istream *
request_body(EventLoop &event_loop, struct pool &pool)
{
    struct stat st;
    return fstat(0, &st) == 0 && S_ISREG(st.st_mode)
        ? istream_file_fd_new(event_loop, pool,
                              "/dev/stdin", UniqueFileDescriptor(STDIN_FILENO),
                              FdType::FD_FILE, -1)
        : nullptr;
}

int
main(int argc, char **argv)
try {
    SetLogLevel(5);

    StaticArray<const char *, 64> params;

    if (argc < 3) {
        fprintf(stderr, "Usage: run_was PATH URI [--parameter a=b ...]\n");
        return EXIT_FAILURE;
    }

    const char *uri = argv[2];

    for (int i = 3; i < argc;) {
        if (strcmp(argv[i], "--parameter") == 0 ||
            strcmp(argv[i], "-p") == 0) {
            ++i;
            if (i >= argc)
                throw std::runtime_error("Parameter value missing");

            if (params.full())
                throw std::runtime_error("Too many parameters");

            params.push_back(argv[i++]);
        } else
            throw std::runtime_error("Unrecognized parameter");
    }

    direct_global_init();

    SpawnConfig spawn_config;

    const ScopeFbPoolInit fb_pool_init;

    ChildOptions child_options;

    Context context;
    ChildProcessRegistry child_process_registry(context.event_loop);
    child_process_registry.SetVolatile();
    LocalSpawnService spawn_service(spawn_config, child_process_registry);

    context.process = was_launch(spawn_service, "was",
                                 argv[1], nullptr,
                                 child_options, {}, nullptr);

    was_client_request(context.root_pool, context.event_loop, nullptr,
                       context.process.control,
                       context.process.input,
                       context.process.output,
                       context,
                       HTTP_METHOD_GET, uri,
                       nullptr,
                       nullptr, nullptr,
                       *strmap_new(context.root_pool),
                       UnusedIstreamPtr(request_body(context.event_loop,
                                                     context.root_pool)),
                       { (const char *const*)params.raw(), params.size() },
                       context, context.cancel_ptr);

    context.event_loop.Dispatch();

    return context.error;
} catch (const std::exception &e) {
    PrintException(e);
    return EXIT_FAILURE;
}
<|endoftext|>


<commit_before>#include "chainerx/routines/normalization.h"

#include <cstdint>
#include <memory>
#include <utility>

#include "chainerx/array.h"
#include "chainerx/axes.h"
#include "chainerx/backprop_mode.h"
#include "chainerx/backward_builder.h"
#include "chainerx/backward_context.h"
#include "chainerx/device.h"
#include "chainerx/dtype.h"
#include "chainerx/error.h"
#include "chainerx/graph.h"
#include "chainerx/macro.h"
#include "chainerx/routines/math.h"
#include "chainerx/routines/routines_util.h"
#include "chainerx/routines/statistics.h"
#include "chainerx/scalar.h"
#include "chainerx/shape.h"

namespace chainerx {
namespace {

struct PreprocessBatchNormResult {
    // Arrays are reshaped if necessary
    Array gamma;
    Array beta;
    Array mean;
    Array var;
    Axes sorted_axis;
};

// Reshapes the array. If the shape is unchanged, an array with identical array body is returned. Note that chainerx::Reshape() returns
// a view with different array body if the shape is unchanged.
Array ReshapeOrIdentity(const Array& a, const Shape& shape) {
    if (a.shape() == shape) {
        return a;
    }
    return a.Reshape(shape);
}

// Reshapes the input arrays (except x) as needed.
// Sorted axes is also returned.
PreprocessBatchNormResult PreprocessBatchNorm(
        const Array& x, const Array& gamma, const Array& beta, const Array& mean, const Array& var, const OptionalAxes& axis) {
    Dtype dtype = x.dtype();
    CheckEqual(dtype, gamma.dtype());
    CheckEqual(dtype, beta.dtype());
    CheckEqual(dtype, mean.dtype());
    CheckEqual(dtype, var.dtype());

    Axes sorted_axis = axis.has_value() ? internal::GetSortedAxes(*axis, x.ndim()) : Axes{0};

    Shape reduced_shape = internal::ReduceShape(x.shape(), sorted_axis, true);
    int64_t reduced_size = reduced_shape.GetTotalSize();

    if (gamma.GetTotalSize() != reduced_size) {
        throw DimensionError{
                "Gamma must have the same size as the reduced input. Actual: ", gamma.GetTotalSize(), ". Expected: ", reduced_size, "."};
    }
    if (beta.GetTotalSize() != reduced_size) {
        throw DimensionError{
                "Beta must have the same size as the reduced input. Actual: ", beta.GetTotalSize(), ". Expected: ", reduced_size, "."};
    }
    if (mean.GetTotalSize() != reduced_size) {
        throw DimensionError{
                "Mean must have the same size as the reduced input. Actual: ", mean.GetTotalSize(), ". Expected: ", reduced_size, "."};
    }
    if (var.GetTotalSize() != reduced_size) {
        throw DimensionError{
                "Variance must have the same size as the reduced input. Actual: ", var.GetTotalSize(), ". Expected: ", reduced_size, "."};
    }

    Array gamma_reshaped = ReshapeOrIdentity(gamma, reduced_shape);
    Array beta_reshaped = ReshapeOrIdentity(beta, reduced_shape);
    Array mean_reshaped = ReshapeOrIdentity(mean, reduced_shape);
    Array var_reshaped = ReshapeOrIdentity(var, reduced_shape);
    CHAINERX_ASSERT(gamma_reshaped.data() == gamma.data());  // No data copy should occur
    CHAINERX_ASSERT(beta_reshaped.data() == beta.data());
    CHAINERX_ASSERT(mean_reshaped.data() == mean.data());
    CHAINERX_ASSERT(var_reshaped.data() == var.data());

    return {std::move(gamma_reshaped), std::move(beta_reshaped), std::move(mean_reshaped), std::move(var_reshaped), sorted_axis};
}

}  // namespace

Array BatchNorm(
        const Array& x,
        const Array& gamma,
        const Array& beta,
        const Array& running_mean,
        const Array& running_var,
        Scalar eps,
        Scalar decay,
        const OptionalAxes& axis) {
    PreprocessBatchNormResult result = PreprocessBatchNorm(x, gamma, beta, running_mean, running_var, axis);
    std::shared_ptr<BatchNormForwardBackward> fb =
            x.device().GetBatchNormForwardBackward(result.mean, result.var, eps, decay, result.sorted_axis);

    const Array& gamma_reshaped = result.gamma;
    const Array& beta_reshaped = result.beta;

    Array out = fb->Forward(x.AsGradStopped(), gamma_reshaped.AsGradStopped(), beta_reshaped.AsGradStopped());
    internal::MakeViewForForwardBackwardOutput(out);

    BackwardBuilder bb{"batch_norm", {x, gamma_reshaped, beta_reshaped}, {out}};
    if (BackwardBuilder::Target bt = bb.CreateTarget({0, 1, 2})) {
        bt.Define([fb = std::move(fb), x_tok = bb.RetainInput(0), gamma_tok = bb.RetainInput(1), eps, sorted_axis = result.sorted_axis](
                          BackwardContext& bctx) {
            const Array& gout = *bctx.output_grad();

            Array gx{};
            Array ggamma{};
            Array gbeta{};
            {
                std::array<Array, 3> ginputs = fb->Backward(gout.AsGradStopped());
                internal::MakeViewForForwardBackwardOutput(ginputs);

                gx = std::move(ginputs[0]);
                ggamma = std::move(ginputs[1]);
                gbeta = std::move(ginputs[2]);
            }

            CHAINERX_ASSERT(internal::GetArrayBody(gx)->nodes().empty());
            CHAINERX_ASSERT(internal::GetArrayBody(ggamma)->nodes().empty());
            CHAINERX_ASSERT(internal::GetArrayBody(gbeta)->nodes().empty());

            if (bctx.next_required()) {
                const Array& x = bctx.GetRetainedInput(x_tok);
                const Array& gamma_reshaped = bctx.GetRetainedInput(gamma_tok);

                BackwardBuilder bb2{"batch_norm_backward", {x, gamma_reshaped, gout}, {gx, ggamma, gbeta}};
                if (BackwardBuilder::Target bt2 = bb2.CreateTarget({0, 1, 2})) {
                    bt2.Define([x_tok = bb2.RetainInput(0),
                                gamma2_tok = bb2.RetainInput(1),
                                gout_tok = bb2.RetainInput(2),
                                eps,
                                sorted_axis,
                                gx_tok = bb2.RetainOutput(0),
                                ggamma_tok = bb2.RetainOutput(1)](BackwardContext& bctx2) {
                        const Array& x = bctx2.GetRetainedInput(x_tok);
                        const Array& gamma_reshaped = bctx2.GetRetainedInput(gamma2_tok);
                        const Array& gout = bctx2.GetRetainedInput(gout_tok);

                        const Array& ggx = *bctx2.output_grad(0);
                        const Array& gggamma = *bctx2.output_grad(1);
                        const Array& ggbeta = *bctx2.output_grad(2);

                        const Array& x_mean = Mean(x, sorted_axis, true);
                        const Array& x_var = Var(x, sorted_axis, true);
                        const Array& x_inv_std = Reciprocal(Sqrt(x_var + eps));

                        const Array& gx = bctx2.GetRetainedOutput(gx_tok);
                        const Array& ggamma = bctx2.GetRetainedOutput(ggamma_tok);

                        // Auxiliary values
                        int64_t n = x.GetTotalSize() / gamma_reshaped.GetTotalSize();
                        double inv_n = 1.0 / n;
                        Array r = (gx * ggx).Sum(sorted_axis);
                        Array coeff = gamma_reshaped * x_inv_std;
                        Array coeff_m = coeff * inv_n;
                        Array x_hat = (x - x_mean) * x_inv_std;

                        Array gggamma2 = gggamma - coeff_m * (x_hat * ggx).Sum(sorted_axis);
                        Array ggbeta2 = ggbeta - coeff_m * ggx.Sum(sorted_axis);

                        Array gx_hat2 = gggamma2 * gout - coeff_m * ggamma * ggx;
                        Array gstd2 = -x_inv_std * (r + (x_hat * gx_hat2).Sum(sorted_axis));
                        Array gmean2 = -x_inv_std * gx_hat2.Sum(sorted_axis);
                        Array gx2 = x_inv_std * gx_hat2 + inv_n * (gmean2 + x_hat * gstd2);
                        Array ggout2 = gggamma2 * x_hat + ggbeta2 + coeff * ggx;

                        Array ggamma2 = r / gamma_reshaped;

                        bctx2.input_grad(0) = std::move(gx2);
                        bctx2.input_grad(1) = std::move(ggamma2);
                        bctx2.input_grad(2) = std::move(ggout2);
                    });
                }
                bb2.Finalize();
            }

            // TODO(niboshi): Assign at once
            bctx.input_grad(0) = std::move(gx);
            bctx.input_grad(1) = std::move(ggamma);
            bctx.input_grad(2) = std::move(gbeta);
        });
    }
    bb.Finalize();

    return out;
}

Array FixedBatchNorm(
        const Array& x, const Array& gamma, const Array& beta, const Array& mean, const Array& var, Scalar eps, const OptionalAxes& axis) {
    PreprocessBatchNormResult result =
            PreprocessBatchNorm(x, gamma.AsGradStopped(), beta.AsGradStopped(), mean.AsGradStopped(), var.AsGradStopped(), axis);
    {
        NoBackpropModeScope scope{};
        return x.device().FixedBatchNorm(x.AsGradStopped(), result.gamma, result.beta, result.mean, result.var, eps, result.sorted_axis);
    }
}

}  // namespace chainerx
<commit_msg>Fix BatchNorm for nullptr upstream gradients<commit_after>#include "chainerx/routines/normalization.h"

#include <cstdint>
#include <memory>
#include <utility>

#include <nonstd/optional.hpp>

#include "chainerx/array.h"
#include "chainerx/axes.h"
#include "chainerx/backprop_mode.h"
#include "chainerx/backward_builder.h"
#include "chainerx/backward_context.h"
#include "chainerx/device.h"
#include "chainerx/dtype.h"
#include "chainerx/error.h"
#include "chainerx/graph.h"
#include "chainerx/macro.h"
#include "chainerx/routines/creation.h"
#include "chainerx/routines/math.h"
#include "chainerx/routines/routines_util.h"
#include "chainerx/routines/statistics.h"
#include "chainerx/scalar.h"
#include "chainerx/shape.h"

namespace chainerx {
namespace {

struct PreprocessBatchNormResult {
    // Arrays are reshaped if necessary
    Array gamma;
    Array beta;
    Array mean;
    Array var;
    Axes sorted_axis;
};

// Reshapes the array. If the shape is unchanged, an array with identical array body is returned. Note that chainerx::Reshape() returns
// a view with different array body if the shape is unchanged.
Array ReshapeOrIdentity(const Array& a, const Shape& shape) {
    if (a.shape() == shape) {
        return a;
    }
    return a.Reshape(shape);
}

// Reshapes the input arrays (except x) as needed.
// Sorted axes is also returned.
PreprocessBatchNormResult PreprocessBatchNorm(
        const Array& x, const Array& gamma, const Array& beta, const Array& mean, const Array& var, const OptionalAxes& axis) {
    Dtype dtype = x.dtype();
    CheckEqual(dtype, gamma.dtype());
    CheckEqual(dtype, beta.dtype());
    CheckEqual(dtype, mean.dtype());
    CheckEqual(dtype, var.dtype());

    Axes sorted_axis = axis.has_value() ? internal::GetSortedAxes(*axis, x.ndim()) : Axes{0};

    Shape reduced_shape = internal::ReduceShape(x.shape(), sorted_axis, true);
    int64_t reduced_size = reduced_shape.GetTotalSize();

    if (gamma.GetTotalSize() != reduced_size) {
        throw DimensionError{
                "Gamma must have the same size as the reduced input. Actual: ", gamma.GetTotalSize(), ". Expected: ", reduced_size, "."};
    }
    if (beta.GetTotalSize() != reduced_size) {
        throw DimensionError{
                "Beta must have the same size as the reduced input. Actual: ", beta.GetTotalSize(), ". Expected: ", reduced_size, "."};
    }
    if (mean.GetTotalSize() != reduced_size) {
        throw DimensionError{
                "Mean must have the same size as the reduced input. Actual: ", mean.GetTotalSize(), ". Expected: ", reduced_size, "."};
    }
    if (var.GetTotalSize() != reduced_size) {
        throw DimensionError{
                "Variance must have the same size as the reduced input. Actual: ", var.GetTotalSize(), ". Expected: ", reduced_size, "."};
    }

    Array gamma_reshaped = ReshapeOrIdentity(gamma, reduced_shape);
    Array beta_reshaped = ReshapeOrIdentity(beta, reduced_shape);
    Array mean_reshaped = ReshapeOrIdentity(mean, reduced_shape);
    Array var_reshaped = ReshapeOrIdentity(var, reduced_shape);
    CHAINERX_ASSERT(gamma_reshaped.data() == gamma.data());  // No data copy should occur
    CHAINERX_ASSERT(beta_reshaped.data() == beta.data());
    CHAINERX_ASSERT(mean_reshaped.data() == mean.data());
    CHAINERX_ASSERT(var_reshaped.data() == var.data());

    return {std::move(gamma_reshaped), std::move(beta_reshaped), std::move(mean_reshaped), std::move(var_reshaped), sorted_axis};
}

Array ArrayOrZeros(const nonstd::optional<Array>& array, const Array& zeros_template) {
    if (array.has_value()) {
        return *array;
    }
    return ZerosLike(zeros_template, zeros_template.device());
}

}  // namespace

Array BatchNorm(
        const Array& x,
        const Array& gamma,
        const Array& beta,
        const Array& running_mean,
        const Array& running_var,
        Scalar eps,
        Scalar decay,
        const OptionalAxes& axis) {
    PreprocessBatchNormResult result = PreprocessBatchNorm(x, gamma, beta, running_mean, running_var, axis);
    std::shared_ptr<BatchNormForwardBackward> fb =
            x.device().GetBatchNormForwardBackward(result.mean, result.var, eps, decay, result.sorted_axis);

    const Array& gamma_reshaped = result.gamma;
    const Array& beta_reshaped = result.beta;

    Array out = fb->Forward(x.AsGradStopped(), gamma_reshaped.AsGradStopped(), beta_reshaped.AsGradStopped());
    internal::MakeViewForForwardBackwardOutput(out);

    BackwardBuilder bb{"batch_norm", {x, gamma_reshaped, beta_reshaped}, {out}};
    if (BackwardBuilder::Target bt = bb.CreateTarget({0, 1, 2})) {
        bt.Define([fb = std::move(fb), x_tok = bb.RetainInput(0), gamma_tok = bb.RetainInput(1), eps, sorted_axis = result.sorted_axis](
                          BackwardContext& bctx) {
            const Array& gout = *bctx.output_grad();

            Array gx{};
            Array ggamma{};
            Array gbeta{};
            {
                std::array<Array, 3> ginputs = fb->Backward(gout.AsGradStopped());
                internal::MakeViewForForwardBackwardOutput(ginputs);

                gx = std::move(ginputs[0]);
                ggamma = std::move(ginputs[1]);
                gbeta = std::move(ginputs[2]);
            }

            CHAINERX_ASSERT(internal::GetArrayBody(gx)->nodes().empty());
            CHAINERX_ASSERT(internal::GetArrayBody(ggamma)->nodes().empty());
            CHAINERX_ASSERT(internal::GetArrayBody(gbeta)->nodes().empty());

            if (bctx.next_required()) {
                const Array& x = bctx.GetRetainedInput(x_tok);
                const Array& gamma_reshaped = bctx.GetRetainedInput(gamma_tok);

                BackwardBuilder bb2{"batch_norm_backward", {x, gamma_reshaped, gout}, {gx, ggamma, gbeta}};
                if (BackwardBuilder::Target bt2 = bb2.CreateTarget({0, 1, 2})) {
                    bt2.Define([x_tok = bb2.RetainInput(0),
                                gamma2_tok = bb2.RetainInput(1),
                                gout_tok = bb2.RetainInput(2),
                                eps,
                                sorted_axis,
                                gx_tok = bb2.RetainOutput(0),
                                ggamma_tok = bb2.RetainOutput(1)](BackwardContext& bctx2) {
                        const Array& x = bctx2.GetRetainedInput(x_tok);
                        const Array& gamma_reshaped = bctx2.GetRetainedInput(gamma2_tok);
                        const Array& gout = bctx2.GetRetainedInput(gout_tok);

                        Array ggx = ArrayOrZeros(bctx2.output_grad(0), x);
                        Array gggamma = ArrayOrZeros(bctx2.output_grad(1), gamma_reshaped);
                        Array ggbeta = ArrayOrZeros(bctx2.output_grad(2), gamma_reshaped);

                        const Array& x_mean = Mean(x, sorted_axis, true);
                        const Array& x_var = Var(x, sorted_axis, true);
                        const Array& x_inv_std = Reciprocal(Sqrt(x_var + eps));

                        const Array& gx = bctx2.GetRetainedOutput(gx_tok);
                        const Array& ggamma = bctx2.GetRetainedOutput(ggamma_tok);

                        // Auxiliary values
                        int64_t n = x.GetTotalSize() / gamma_reshaped.GetTotalSize();
                        double inv_n = 1.0 / n;
                        Array r = (gx * ggx).Sum(sorted_axis, true);
                        Array coeff = gamma_reshaped * x_inv_std;
                        Array coeff_m = coeff * inv_n;
                        Array x_hat = (x - x_mean) * x_inv_std;

                        Array gggamma2 = gggamma - coeff_m * (x_hat * ggx).Sum(sorted_axis, true);
                        Array ggbeta2 = ggbeta - coeff_m * ggx.Sum(sorted_axis, true);

                        Array gx_hat2 = gggamma2 * gout - coeff_m * ggamma * ggx;
                        Array gstd2 = -x_inv_std * (r + (x_hat * gx_hat2).Sum(sorted_axis, true));
                        Array gmean2 = -x_inv_std * gx_hat2.Sum(sorted_axis, true);
                        Array gx2 = x_inv_std * gx_hat2 + inv_n * (gmean2 + x_hat * gstd2);
                        Array ggout2 = gggamma2 * x_hat + ggbeta2 + coeff * ggx;

                        Array ggamma2 = r / gamma_reshaped;

                        bctx2.input_grad(0) = std::move(gx2);
                        bctx2.input_grad(1) = std::move(ggamma2);
                        bctx2.input_grad(2) = std::move(ggout2);
                    });
                }
                bb2.Finalize();
            }

            // TODO(niboshi): Assign at once
            bctx.input_grad(0) = std::move(gx);
            bctx.input_grad(1) = std::move(ggamma);
            bctx.input_grad(2) = std::move(gbeta);
        });
    }
    bb.Finalize();

    return out;
}

Array FixedBatchNorm(
        const Array& x, const Array& gamma, const Array& beta, const Array& mean, const Array& var, Scalar eps, const OptionalAxes& axis) {
    PreprocessBatchNormResult result =
            PreprocessBatchNorm(x, gamma.AsGradStopped(), beta.AsGradStopped(), mean.AsGradStopped(), var.AsGradStopped(), axis);
    {
        NoBackpropModeScope scope{};
        return x.device().FixedBatchNorm(x.AsGradStopped(), result.gamma, result.beta, result.mean, result.var, eps, result.sorted_axis);
    }
}

}  // namespace chainerx
<|endoftext|>


<commit_before>/*
Copyright (C) 2001-2020 by Serge Lamikhov-Center

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifndef ELFIO_SYMBOLS_HPP
#define ELFIO_SYMBOLS_HPP

namespace ELFIO {

//------------------------------------------------------------------------------
template <class S> class symbol_section_accessor_template
{
  public:
    //------------------------------------------------------------------------------
    symbol_section_accessor_template( const elfio& elf_file_,
                                      S*           symbol_section_ )
        : elf_file( elf_file_ ), symbol_section( symbol_section_ )
    {
        find_hash_section();
    }

    //------------------------------------------------------------------------------
    Elf_Xword get_symbols_num() const
    {
        Elf_Xword nRet = 0;
        if ( 0 != symbol_section->get_entry_size() ) {
            nRet =
                symbol_section->get_size() / symbol_section->get_entry_size();
        }

        return nRet;
    }

    //------------------------------------------------------------------------------
    bool get_symbol( Elf_Xword      index,
                     std::string&   name,
                     Elf64_Addr&    value,
                     Elf_Xword&     size,
                     unsigned char& bind,
                     unsigned char& type,
                     Elf_Half&      section_index,
                     unsigned char& other ) const
    {
        bool ret = false;

        if ( elf_file.get_class() == ELFCLASS32 ) {
            ret = generic_get_symbol<Elf32_Sym>( index, name, value, size, bind,
                                                 type, section_index, other );
        }
        else {
            ret = generic_get_symbol<Elf64_Sym>( index, name, value, size, bind,
                                                 type, section_index, other );
        }

        return ret;
    }

    //------------------------------------------------------------------------------
    bool get_symbol( const std::string& name,
                     Elf64_Addr&        value,
                     Elf_Xword&         size,
                     unsigned char&     bind,
                     unsigned char&     type,
                     Elf_Half&          section_index,
                     unsigned char&     other ) const
    {
        bool ret = false;

        if ( 0 != get_hash_table_index() ) {
            Elf_Word    nbucket = *(const Elf_Word*)hash_section->get_data();
            Elf_Word    nchain  = *(const Elf_Word*)( hash_section->get_data() +
                                                  sizeof( Elf_Word ) );
            Elf_Word    val = elf_hash( (const unsigned char*)name.c_str() );
            Elf_Word    y   = *(const Elf_Word*)( hash_section->get_data() +
                                             ( 2 + val % nbucket ) *
                                                 sizeof( Elf_Word ) );
            std::string str;
            get_symbol( y, str, value, size, bind, type, section_index, other );
            while ( str != name && STN_UNDEF != y && y < nchain ) {
                y = *(const Elf_Word*)( hash_section->get_data() +
                                        ( 2 + nbucket + y ) *
                                            sizeof( Elf_Word ) );
                get_symbol( y, str, value, size, bind, type, section_index,
                            other );
            }
            if ( str == name ) {
                ret = true;
            }
        }
        else {
            for ( Elf_Xword i = 0; i < get_symbols_num() && !ret; i++ ) {
                std::string symbol_name;
                if ( get_symbol( i, symbol_name, value, size, bind, type,
                                 section_index, other ) ) {
                    if ( symbol_name == name ) {
                        ret = true;
                    }
                }
            }
        }

        return ret;
    }

    //------------------------------------------------------------------------------
    bool get_symbol( const Elf64_Addr& value,
                     std::string&      name,
                     Elf_Xword&        size,
                     unsigned char&    bind,
                     unsigned char&    type,
                     Elf_Half&         section_index,
                     unsigned char&    other ) const
    {

        const endianess_convertor& convertor = elf_file.get_convertor();

        Elf_Xword  idx   = 0;
        bool       match = false;
        Elf64_Addr v     = 0;

        if ( elf_file.get_class() == ELFCLASS32 ) {
            match = generic_search_symbols<Elf32_Sym>(
                [&]( const Elf32_Sym* sym ) {
                    return convertor( sym->st_value ) == value;
                },
                idx );
        }
        else {
            match = generic_search_symbols<Elf64_Sym>(
                [&]( const Elf64_Sym* sym ) {
                    return convertor( sym->st_value ) == value;
                },
                idx );
        }

        if ( match ) {
            return get_symbol( idx, name, v, size, bind, type, section_index,
                               other );
        }

        return false;
    }

    //------------------------------------------------------------------------------
    Elf_Word add_symbol( Elf_Word      name,
                         Elf64_Addr    value,
                         Elf_Xword     size,
                         unsigned char info,
                         unsigned char other,
                         Elf_Half      shndx )
    {
        Elf_Word nRet;

        if ( symbol_section->get_size() == 0 ) {
            if ( elf_file.get_class() == ELFCLASS32 ) {
                nRet = generic_add_symbol<Elf32_Sym>( 0, 0, 0, 0, 0, 0 );
            }
            else {
                nRet = generic_add_symbol<Elf64_Sym>( 0, 0, 0, 0, 0, 0 );
            }
        }

        if ( elf_file.get_class() == ELFCLASS32 ) {
            nRet = generic_add_symbol<Elf32_Sym>( name, value, size, info,
                                                  other, shndx );
        }
        else {
            nRet = generic_add_symbol<Elf64_Sym>( name, value, size, info,
                                                  other, shndx );
        }

        return nRet;
    }

    //------------------------------------------------------------------------------
    Elf_Word add_symbol( Elf_Word      name,
                         Elf64_Addr    value,
                         Elf_Xword     size,
                         unsigned char bind,
                         unsigned char type,
                         unsigned char other,
                         Elf_Half      shndx )
    {
        return add_symbol( name, value, size, ELF_ST_INFO( bind, type ), other,
                           shndx );
    }

    //------------------------------------------------------------------------------
    Elf_Word add_symbol( string_section_accessor& pStrWriter,
                         const char*              str,
                         Elf64_Addr               value,
                         Elf_Xword                size,
                         unsigned char            info,
                         unsigned char            other,
                         Elf_Half                 shndx )
    {
        Elf_Word index = pStrWriter.add_string( str );
        return add_symbol( index, value, size, info, other, shndx );
    }

    //------------------------------------------------------------------------------
    Elf_Word add_symbol( string_section_accessor& pStrWriter,
                         const char*              str,
                         Elf64_Addr               value,
                         Elf_Xword                size,
                         unsigned char            bind,
                         unsigned char            type,
                         unsigned char            other,
                         Elf_Half                 shndx )
    {
        return add_symbol( pStrWriter, str, value, size,
                           ELF_ST_INFO( bind, type ), other, shndx );
    }

    //------------------------------------------------------------------------------
    Elf_Xword arrange_local_symbols(
        std::function<void( Elf_Xword first, Elf_Xword second )> func =
            nullptr )
    {
        int nRet = 0;

        if ( elf_file.get_class() == ELFCLASS32 ) {
            nRet = generic_arrange_local_symbols<Elf32_Sym>( func );
        }
        else {
            nRet = generic_arrange_local_symbols<Elf64_Sym>( func );
        }

        return nRet;
    }

    //------------------------------------------------------------------------------
  private:
    //------------------------------------------------------------------------------
    void find_hash_section()
    {
        hash_section       = 0;
        hash_section_index = 0;
        Elf_Half nSecNo    = elf_file.sections.size();
        for ( Elf_Half i = 0; i < nSecNo && 0 == hash_section_index; ++i ) {
            const section* sec = elf_file.sections[i];
            if ( sec->get_link() == symbol_section->get_index() ) {
                hash_section       = sec;
                hash_section_index = i;
            }
        }
    }

    //------------------------------------------------------------------------------
    Elf_Half get_string_table_index() const
    {
        return (Elf_Half)symbol_section->get_link();
    }

    //------------------------------------------------------------------------------
    Elf_Half get_hash_table_index() const { return hash_section_index; }

    //------------------------------------------------------------------------------
    template <class T> const T* generic_get_symbol_ptr( Elf_Xword index ) const
    {
        if ( 0 != symbol_section->get_data() && index < get_symbols_num() ) {
            const T* pSym = reinterpret_cast<const T*>(
                symbol_section->get_data() +
                index * symbol_section->get_entry_size() );

            return pSym;
        }

        return nullptr;
    }

    //------------------------------------------------------------------------------
    template <class T>
    bool generic_search_symbols( std::function<bool( const T* )> match,
                                 Elf_Xword&                      idx ) const
    {
        for ( Elf_Xword i = 0; i < get_symbols_num(); i++ ) {
            const T* symPtr = generic_get_symbol_ptr<T>( i );

            if ( symPtr == nullptr )
                return false;

            if ( match( symPtr ) ) {
                idx = i;
                return true;
            }
        }

        return false;
    }

    //------------------------------------------------------------------------------
    template <class T>
    bool generic_get_symbol( Elf_Xword      index,
                             std::string&   name,
                             Elf64_Addr&    value,
                             Elf_Xword&     size,
                             unsigned char& bind,
                             unsigned char& type,
                             Elf_Half&      section_index,
                             unsigned char& other ) const
    {
        bool ret = false;

        if ( 0 != symbol_section->get_data() && index < get_symbols_num() ) {
            const T* pSym = reinterpret_cast<const T*>(
                symbol_section->get_data() +
                index * symbol_section->get_entry_size() );

            const endianess_convertor& convertor = elf_file.get_convertor();

            section* string_section =
                elf_file.sections[get_string_table_index()];
            string_section_accessor str_reader( string_section );
            const char*             pStr =
                str_reader.get_string( convertor( pSym->st_name ) );
            if ( 0 != pStr ) {
                name = pStr;
            }
            value         = convertor( pSym->st_value );
            size          = convertor( pSym->st_size );
            bind          = ELF_ST_BIND( pSym->st_info );
            type          = ELF_ST_TYPE( pSym->st_info );
            section_index = convertor( pSym->st_shndx );
            other         = pSym->st_other;

            ret = true;
        }

        return ret;
    }

    //------------------------------------------------------------------------------
    template <class T>
    Elf_Word generic_add_symbol( Elf_Word      name,
                                 Elf64_Addr    value,
                                 Elf_Xword     size,
                                 unsigned char info,
                                 unsigned char other,
                                 Elf_Half      shndx )
    {
        const endianess_convertor& convertor = elf_file.get_convertor();

        T entry;
        entry.st_name  = convertor( name );
        entry.st_value = value;
        entry.st_value = convertor( entry.st_value );
        entry.st_size  = size;
        entry.st_size  = convertor( entry.st_size );
        entry.st_info  = convertor( info );
        entry.st_other = convertor( other );
        entry.st_shndx = convertor( shndx );

        symbol_section->append_data( reinterpret_cast<char*>( &entry ),
                                     sizeof( entry ) );

        Elf_Word nRet = symbol_section->get_size() / sizeof( entry ) - 1;

        return nRet;
    }

    //------------------------------------------------------------------------------
    template <class T>
    Elf_Xword generic_arrange_local_symbols(
        std::function<void( Elf_Xword first, Elf_Xword second )> func )
    {
        const endianess_convertor& convertor = elf_file.get_convertor();
        const Elf_Xword            size      = symbol_section->get_entry_size();

        Elf_Xword first_not_local =
            1; // Skip the first entry. It is always NOTYPE
        Elf_Xword current = 0;
        Elf_Xword count   = get_symbols_num();

        while ( true ) {
            T* p1 = nullptr;
            T* p2 = nullptr;

            while ( first_not_local < count ) {
                p1 = const_cast<T*>(
                    generic_get_symbol_ptr<T>( first_not_local ) );
                if ( ELF_ST_BIND( convertor( p1->st_info ) ) != STB_LOCAL )
                    break;
                ++first_not_local;
            }

            current = first_not_local + 1;
            while ( current < count ) {
                p2 = const_cast<T*>( generic_get_symbol_ptr<T>( current ) );
                if ( ELF_ST_BIND( convertor( p2->st_info ) ) == STB_LOCAL )
                    break;
                ++current;
            }

            if ( first_not_local < count && current < count ) {
                if ( func )
                    func( first_not_local, current );

                // Swap the symbols
                T tmp;
                std::copy( p1, p1 + 1, &tmp );
                std::copy( p2, p2 + 1, p1 );
                std::copy( &tmp, &tmp + 1, p2 );
            }
            else {
                // Update 'info' field of the section
                symbol_section->set_info( first_not_local );
                break;
            }
        }

        // Elf_Word nRet = symbol_section->get_size() / sizeof(entry) - 1;

        return first_not_local;
    }

    //------------------------------------------------------------------------------
  private:
    const elfio&   elf_file;
    S*             symbol_section;
    Elf_Half       hash_section_index;
    const section* hash_section;
};

using symbol_section_accessor = symbol_section_accessor_template<section>;
using const_symbol_section_accessor =
    symbol_section_accessor_template<const section>;

} // namespace ELFIO

#endif // ELFIO_SYMBOLS_HPP
<commit_msg>Remove unused var; Use std::swap()<commit_after>/*
Copyright (C) 2001-2020 by Serge Lamikhov-Center

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifndef ELFIO_SYMBOLS_HPP
#define ELFIO_SYMBOLS_HPP

namespace ELFIO {

//------------------------------------------------------------------------------
template <class S> class symbol_section_accessor_template
{
  public:
    //------------------------------------------------------------------------------
    symbol_section_accessor_template( const elfio& elf_file_,
                                      S*           symbol_section_ )
        : elf_file( elf_file_ ), symbol_section( symbol_section_ )
    {
        find_hash_section();
    }

    //------------------------------------------------------------------------------
    Elf_Xword get_symbols_num() const
    {
        Elf_Xword nRet = 0;
        if ( 0 != symbol_section->get_entry_size() ) {
            nRet =
                symbol_section->get_size() / symbol_section->get_entry_size();
        }

        return nRet;
    }

    //------------------------------------------------------------------------------
    bool get_symbol( Elf_Xword      index,
                     std::string&   name,
                     Elf64_Addr&    value,
                     Elf_Xword&     size,
                     unsigned char& bind,
                     unsigned char& type,
                     Elf_Half&      section_index,
                     unsigned char& other ) const
    {
        bool ret = false;

        if ( elf_file.get_class() == ELFCLASS32 ) {
            ret = generic_get_symbol<Elf32_Sym>( index, name, value, size, bind,
                                                 type, section_index, other );
        }
        else {
            ret = generic_get_symbol<Elf64_Sym>( index, name, value, size, bind,
                                                 type, section_index, other );
        }

        return ret;
    }

    //------------------------------------------------------------------------------
    bool get_symbol( const std::string& name,
                     Elf64_Addr&        value,
                     Elf_Xword&         size,
                     unsigned char&     bind,
                     unsigned char&     type,
                     Elf_Half&          section_index,
                     unsigned char&     other ) const
    {
        bool ret = false;

        if ( 0 != get_hash_table_index() ) {
            Elf_Word    nbucket = *(const Elf_Word*)hash_section->get_data();
            Elf_Word    nchain  = *(const Elf_Word*)( hash_section->get_data() +
                                                  sizeof( Elf_Word ) );
            Elf_Word    val = elf_hash( (const unsigned char*)name.c_str() );
            Elf_Word    y   = *(const Elf_Word*)( hash_section->get_data() +
                                             ( 2 + val % nbucket ) *
                                                 sizeof( Elf_Word ) );
            std::string str;
            get_symbol( y, str, value, size, bind, type, section_index, other );
            while ( str != name && STN_UNDEF != y && y < nchain ) {
                y = *(const Elf_Word*)( hash_section->get_data() +
                                        ( 2 + nbucket + y ) *
                                            sizeof( Elf_Word ) );
                get_symbol( y, str, value, size, bind, type, section_index,
                            other );
            }
            if ( str == name ) {
                ret = true;
            }
        }
        else {
            for ( Elf_Xword i = 0; i < get_symbols_num() && !ret; i++ ) {
                std::string symbol_name;
                if ( get_symbol( i, symbol_name, value, size, bind, type,
                                 section_index, other ) ) {
                    if ( symbol_name == name ) {
                        ret = true;
                    }
                }
            }
        }

        return ret;
    }

    //------------------------------------------------------------------------------
    bool get_symbol( const Elf64_Addr& value,
                     std::string&      name,
                     Elf_Xword&        size,
                     unsigned char&    bind,
                     unsigned char&    type,
                     Elf_Half&         section_index,
                     unsigned char&    other ) const
    {

        const endianess_convertor& convertor = elf_file.get_convertor();

        Elf_Xword  idx   = 0;
        bool       match = false;
        Elf64_Addr v     = 0;

        if ( elf_file.get_class() == ELFCLASS32 ) {
            match = generic_search_symbols<Elf32_Sym>(
                [&]( const Elf32_Sym* sym ) {
                    return convertor( sym->st_value ) == value;
                },
                idx );
        }
        else {
            match = generic_search_symbols<Elf64_Sym>(
                [&]( const Elf64_Sym* sym ) {
                    return convertor( sym->st_value ) == value;
                },
                idx );
        }

        if ( match ) {
            return get_symbol( idx, name, v, size, bind, type, section_index,
                               other );
        }

        return false;
    }

    //------------------------------------------------------------------------------
    Elf_Word add_symbol( Elf_Word      name,
                         Elf64_Addr    value,
                         Elf_Xword     size,
                         unsigned char info,
                         unsigned char other,
                         Elf_Half      shndx )
    {
        Elf_Word nRet;

        if ( symbol_section->get_size() == 0 ) {
            if ( elf_file.get_class() == ELFCLASS32 ) {
                nRet = generic_add_symbol<Elf32_Sym>( 0, 0, 0, 0, 0, 0 );
            }
            else {
                nRet = generic_add_symbol<Elf64_Sym>( 0, 0, 0, 0, 0, 0 );
            }
        }

        if ( elf_file.get_class() == ELFCLASS32 ) {
            nRet = generic_add_symbol<Elf32_Sym>( name, value, size, info,
                                                  other, shndx );
        }
        else {
            nRet = generic_add_symbol<Elf64_Sym>( name, value, size, info,
                                                  other, shndx );
        }

        return nRet;
    }

    //------------------------------------------------------------------------------
    Elf_Word add_symbol( Elf_Word      name,
                         Elf64_Addr    value,
                         Elf_Xword     size,
                         unsigned char bind,
                         unsigned char type,
                         unsigned char other,
                         Elf_Half      shndx )
    {
        return add_symbol( name, value, size, ELF_ST_INFO( bind, type ), other,
                           shndx );
    }

    //------------------------------------------------------------------------------
    Elf_Word add_symbol( string_section_accessor& pStrWriter,
                         const char*              str,
                         Elf64_Addr               value,
                         Elf_Xword                size,
                         unsigned char            info,
                         unsigned char            other,
                         Elf_Half                 shndx )
    {
        Elf_Word index = pStrWriter.add_string( str );
        return add_symbol( index, value, size, info, other, shndx );
    }

    //------------------------------------------------------------------------------
    Elf_Word add_symbol( string_section_accessor& pStrWriter,
                         const char*              str,
                         Elf64_Addr               value,
                         Elf_Xword                size,
                         unsigned char            bind,
                         unsigned char            type,
                         unsigned char            other,
                         Elf_Half                 shndx )
    {
        return add_symbol( pStrWriter, str, value, size,
                           ELF_ST_INFO( bind, type ), other, shndx );
    }

    //------------------------------------------------------------------------------
    Elf_Xword arrange_local_symbols(
        std::function<void( Elf_Xword first, Elf_Xword second )> func =
            nullptr )
    {
        int nRet = 0;

        if ( elf_file.get_class() == ELFCLASS32 ) {
            nRet = generic_arrange_local_symbols<Elf32_Sym>( func );
        }
        else {
            nRet = generic_arrange_local_symbols<Elf64_Sym>( func );
        }

        return nRet;
    }

    //------------------------------------------------------------------------------
  private:
    //------------------------------------------------------------------------------
    void find_hash_section()
    {
        hash_section       = 0;
        hash_section_index = 0;
        Elf_Half nSecNo    = elf_file.sections.size();
        for ( Elf_Half i = 0; i < nSecNo && 0 == hash_section_index; ++i ) {
            const section* sec = elf_file.sections[i];
            if ( sec->get_link() == symbol_section->get_index() ) {
                hash_section       = sec;
                hash_section_index = i;
            }
        }
    }

    //------------------------------------------------------------------------------
    Elf_Half get_string_table_index() const
    {
        return (Elf_Half)symbol_section->get_link();
    }

    //------------------------------------------------------------------------------
    Elf_Half get_hash_table_index() const { return hash_section_index; }

    //------------------------------------------------------------------------------
    template <class T> const T* generic_get_symbol_ptr( Elf_Xword index ) const
    {
        if ( 0 != symbol_section->get_data() && index < get_symbols_num() ) {
            const T* pSym = reinterpret_cast<const T*>(
                symbol_section->get_data() +
                index * symbol_section->get_entry_size() );

            return pSym;
        }

        return nullptr;
    }

    //------------------------------------------------------------------------------
    template <class T>
    bool generic_search_symbols( std::function<bool( const T* )> match,
                                 Elf_Xword&                      idx ) const
    {
        for ( Elf_Xword i = 0; i < get_symbols_num(); i++ ) {
            const T* symPtr = generic_get_symbol_ptr<T>( i );

            if ( symPtr == nullptr )
                return false;

            if ( match( symPtr ) ) {
                idx = i;
                return true;
            }
        }

        return false;
    }

    //------------------------------------------------------------------------------
    template <class T>
    bool generic_get_symbol( Elf_Xword      index,
                             std::string&   name,
                             Elf64_Addr&    value,
                             Elf_Xword&     size,
                             unsigned char& bind,
                             unsigned char& type,
                             Elf_Half&      section_index,
                             unsigned char& other ) const
    {
        bool ret = false;

        if ( 0 != symbol_section->get_data() && index < get_symbols_num() ) {
            const T* pSym = reinterpret_cast<const T*>(
                symbol_section->get_data() +
                index * symbol_section->get_entry_size() );

            const endianess_convertor& convertor = elf_file.get_convertor();

            section* string_section =
                elf_file.sections[get_string_table_index()];
            string_section_accessor str_reader( string_section );
            const char*             pStr =
                str_reader.get_string( convertor( pSym->st_name ) );
            if ( 0 != pStr ) {
                name = pStr;
            }
            value         = convertor( pSym->st_value );
            size          = convertor( pSym->st_size );
            bind          = ELF_ST_BIND( pSym->st_info );
            type          = ELF_ST_TYPE( pSym->st_info );
            section_index = convertor( pSym->st_shndx );
            other         = pSym->st_other;

            ret = true;
        }

        return ret;
    }

    //------------------------------------------------------------------------------
    template <class T>
    Elf_Word generic_add_symbol( Elf_Word      name,
                                 Elf64_Addr    value,
                                 Elf_Xword     size,
                                 unsigned char info,
                                 unsigned char other,
                                 Elf_Half      shndx )
    {
        const endianess_convertor& convertor = elf_file.get_convertor();

        T entry;
        entry.st_name  = convertor( name );
        entry.st_value = value;
        entry.st_value = convertor( entry.st_value );
        entry.st_size  = size;
        entry.st_size  = convertor( entry.st_size );
        entry.st_info  = convertor( info );
        entry.st_other = convertor( other );
        entry.st_shndx = convertor( shndx );

        symbol_section->append_data( reinterpret_cast<char*>( &entry ),
                                     sizeof( entry ) );

        Elf_Word nRet = symbol_section->get_size() / sizeof( entry ) - 1;

        return nRet;
    }

    //------------------------------------------------------------------------------
    template <class T>
    Elf_Xword generic_arrange_local_symbols(
        std::function<void( Elf_Xword first, Elf_Xword second )> func )
    {
        const endianess_convertor& convertor = elf_file.get_convertor();

        Elf_Xword first_not_local =
            1; // Skip the first entry. It is always NOTYPE
        Elf_Xword current = 0;
        Elf_Xword count   = get_symbols_num();

        while ( true ) {
            T* p1 = nullptr;
            T* p2 = nullptr;

            while ( first_not_local < count ) {
                p1 = const_cast<T*>(
                    generic_get_symbol_ptr<T>( first_not_local ) );
                if ( ELF_ST_BIND( convertor( p1->st_info ) ) != STB_LOCAL )
                    break;
                ++first_not_local;
            }

            current = first_not_local + 1;
            while ( current < count ) {
                p2 = const_cast<T*>( generic_get_symbol_ptr<T>( current ) );
                if ( ELF_ST_BIND( convertor( p2->st_info ) ) == STB_LOCAL )
                    break;
                ++current;
            }

            if ( first_not_local < count && current < count ) {
                if ( func )
                    func( first_not_local, current );

                std::swap( *p1, *p2 );
            }
            else {
                // Update 'info' field of the section
                symbol_section->set_info( first_not_local );
                break;
            }
        }

        // Elf_Word nRet = symbol_section->get_size() / sizeof(entry) - 1;

        return first_not_local;
    }

    //------------------------------------------------------------------------------
  private:
    const elfio&   elf_file;
    S*             symbol_section;
    Elf_Half       hash_section_index;
    const section* hash_section;
};

using symbol_section_accessor = symbol_section_accessor_template<section>;
using const_symbol_section_accessor =
    symbol_section_accessor_template<const section>;

} // namespace ELFIO

#endif // ELFIO_SYMBOLS_HPP
<|endoftext|>


<commit_before>#include <cassert>
#include <iostream>
#include <list>

#include <pqxx/pqxx>

#include <pqxx/compiler-internal.hxx>

using namespace PGSTD;
using namespace pqxx;

namespace
{
#ifndef PQXX_HAVE_DISTANCE
template<typename ITERATOR> size_t distance(ITERATOR begin, ITERATOR end)
{
  size_t d = 0;
  while (begin != end)
  {
    ++begin;
    ++d;
  }
  return d;
}
#endif // PQXX_HAVE_DISTANCE

void compare_results(string name, result lhs, result rhs)
{
  if (lhs != rhs)
    throw logic_error("Executing " + name + " as prepared statement "
	  "yields different results from direct execution");

  if (lhs.empty())
    throw logic_error("Results being compared are empty.  Not much point!");
}

string stringize(transaction_base &t, const string &arg)
{
  return "'" + t.esc(arg) + "'";
}
string stringize(transaction_base &t, const char arg[])
{
  return arg ? stringize(t,string(arg)) : "null";
}
string stringize(transaction_base &t, char arg[])
{
  return arg ? stringize(t, string(arg)) : "null";
}
template<typename T> string stringize(transaction_base &t, T i)
{
  return stringize(t, to_string(i));
}

// Substitute variables in raw query.  This is not likely to be very robust,
// but it should do for just this test.  The main shortcomings are escaping,
// and not knowing when to quote the variables.
// Note we do the replacement backwards (meaning forward_only iterators won't
// do!) to avoid substituting e.g. "$12" as "$1" first.
template<typename ITER> string subst(transaction_base &t,
	string q,
	ITER patbegin,
	ITER patend)
{
  int i = distance(patbegin, patend);
  for (ITER arg = patend; i > 0; --i)
  {
   --arg;
    const string marker = "$" + to_string(i),
	  var = stringize(t, *arg);
    const string::size_type msz = marker.size();
    while (q.find(marker) != string::npos) q.replace(q.find(marker),msz,var);
  }
  return q;
}

template<typename CNTNR> string subst(transaction_base &t,
	string q,
	const CNTNR &patterns)
{
  return subst(t, q, patterns.begin(), patterns.end());
}

} // namespace

// Test program for libpqxx.  Define and use prepared statements.
//
// Usage: test085
int main()
{
  try
  {
    /* A bit of nastiness in prepared statements: on 7.3.x backends we can't
     * compare pg_tables.tablename to a string.  We work around this by using
     * the LIKE operator.
     *
     * Later backend versions do not suffer from this problem.
     */
    const string QN_readpgtables = "ReadPGTables",
	  Q_readpgtables = "SELECT * FROM pg_tables",
	  QN_seetable = "SeeTable",
	  Q_seetable = Q_readpgtables + " WHERE tablename LIKE $1",
	  QN_seetables = "SeeTables",
	  Q_seetables = Q_seetable + " OR tablename LIKE $2";

    lazyconnection C;

    cout << "Preparing a simple statement..." << endl;
    C.prepare(QN_readpgtables, Q_readpgtables);
    nontransaction T(C, "test85");

    try
    {
      // See if a basic prepared statement works just like a regular query
      cout << "Basic correctness check on prepared statement..." << endl;
      compare_results(QN_readpgtables,
	T.prepared(QN_readpgtables).exec(),
	T.exec(Q_readpgtables));
    }
    catch (const exception &)
    {
      if (!C.supports(connection_base::cap_prepared_statements))
      {
        cout << "Backend version does not support prepared statements.  "
	        "Skipping."
	     << endl;
	return 0;
      }
      throw;
    }

    // Try prepare_now() on an already prepared statement
    C.prepare_now(QN_readpgtables);

    // Pro forma check: same thing but with name passed as C-style string
    compare_results(QN_readpgtables+"_char",
	T.prepared(QN_readpgtables.c_str()).exec(),
	T.exec(Q_readpgtables));

    cout << "Dropping prepared statement..." << endl;
    C.unprepare(QN_readpgtables);

    bool failed = true;
    try
    {
      disable_noticer d(C);
      C.prepare_now(QN_readpgtables);
      failed = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failed)
      throw runtime_error("prepare_now() succeeded on dropped statement");

    // Just to try and confuse things, "unprepare" twice
    cout << "Testing error detection and handling..." << endl;
    try { C.unprepare(QN_readpgtables); }
    catch (const exception &e) { cout << "(Expected) " << e.what() << endl; }

    // Verify that attempt to execute unprepared statement fails
    bool failsOK = true;
    try { T.prepared(QN_readpgtables).exec(); failsOK = false; }
    catch (const exception &e) { cout << "(Expected) " << e.what() << endl; }
    if (!failsOK) throw logic_error("Execute unprepared statement didn't fail");

    // Re-prepare the same statement and test again
    C.prepare(QN_readpgtables, Q_readpgtables);
    C.prepare_now(QN_readpgtables);
    compare_results(QN_readpgtables+"_2",
	T.prepared(QN_readpgtables).exec(),
	T.exec(Q_readpgtables));

    // Double preparation of identical statement should be ignored...
    C.prepare(QN_readpgtables, Q_readpgtables);
    compare_results(QN_readpgtables+"_double",
	T.prepared(QN_readpgtables).exec(),
	T.exec(Q_readpgtables));

    // ...But a modified definition shouldn't
    try
    {
      failsOK = true;
      C.prepare(QN_readpgtables, Q_readpgtables + " ORDER BY tablename");
      failsOK = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failsOK)
      throw logic_error("Bad redefinition of statement went unnoticed");

    cout << "Testing prepared statement with parameter..." << endl;

    C.prepare(QN_seetable, Q_seetable)("varchar", pqxx::prepare::treat_string);

    vector<string> args;
    args.push_back("pg_type");
    compare_results(QN_seetable+"_seq",
	T.prepared(QN_seetable)(args[0]).exec(),
	T.exec(subst(T,Q_seetable,args)));

    cout << "Testing prepared statement with 2 parameters..." << endl;

    C.prepare(QN_seetables, Q_seetables)
      ("varchar",pqxx::prepare::treat_string)
      ("varchar",pqxx::prepare::treat_string);
    args.push_back("pg_index");
    compare_results(QN_seetables+"_seq",
      T.prepared(QN_seetables)(args[0])(args[1]).exec(),
      T.exec(subst(T,Q_seetables,args)));

    cout << "Testing prepared statement with a null parameter..." << endl;
    vector<const char *> ptrs;
    ptrs.push_back(0);
    ptrs.push_back("pg_index");
    compare_results(QN_seetables+"_null1",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.exec(subst(T,Q_seetables,ptrs)));
    compare_results(QN_seetables+"_null2",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)()(ptrs[1]).exec());
    compare_results(QN_seetables+"_null3",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)("somestring",false)(ptrs[1]).exec());
    compare_results(QN_seetables+"_null4",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)(42,false)(ptrs[1]).exec());
    compare_results(QN_seetables+"_null5",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)(0,false)(ptrs[1]).exec());

    cout << "Testing wrong numbers of parameters..." << endl;
    try
    {
      failsOK = true;
      T.prepared(QN_seetables)()()("hi mom!").exec();
      failsOK = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failsOK)
      throw logic_error("No error for too many parameters");
    try
    {
      failsOK = true;
      T.prepared(QN_seetables)("who, me?").exec();
      failsOK = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failsOK)
      throw logic_error("No error for too few parameters");

    cout << "Done." << endl;
  }
  catch (const feature_not_supported &e)
  {
    cout << "Backend version does not support prepared statements.  Skipping."
         << endl;
    return 0;
  }
  catch (const sql_error &e)
  {
    cerr << "SQL error: " << e.what() << endl
         << "Query was: " << e.query() << endl;
    return 1;
  }
  catch (const exception &e)
  {
    // All exceptions thrown by libpqxx are derived from std::exception
    cerr << "Exception: " << e.what() << endl;
    return 2;
  }
  catch (...)
  {
    // This is really unexpected (see above)
    cerr << "Unhandled exception" << endl;
    return 100;
  }

  return 0;
}

<commit_msg>Put compiler-internal include in a better place.<commit_after>#include <cassert>
#include <iostream>
#include <list>

#include <pqxx/compiler-internal.hxx>

#include <pqxx/pqxx>

using namespace PGSTD;
using namespace pqxx;

namespace
{
#ifndef PQXX_HAVE_DISTANCE
template<typename ITERATOR> size_t distance(ITERATOR begin, ITERATOR end)
{
  size_t d = 0;
  while (begin != end)
  {
    ++begin;
    ++d;
  }
  return d;
}
#endif // PQXX_HAVE_DISTANCE

void compare_results(string name, result lhs, result rhs)
{
  if (lhs != rhs)
    throw logic_error("Executing " + name + " as prepared statement "
	  "yields different results from direct execution");

  if (lhs.empty())
    throw logic_error("Results being compared are empty.  Not much point!");
}

string stringize(transaction_base &t, const string &arg)
{
  return "'" + t.esc(arg) + "'";
}
string stringize(transaction_base &t, const char arg[])
{
  return arg ? stringize(t,string(arg)) : "null";
}
string stringize(transaction_base &t, char arg[])
{
  return arg ? stringize(t, string(arg)) : "null";
}
template<typename T> string stringize(transaction_base &t, T i)
{
  return stringize(t, to_string(i));
}

// Substitute variables in raw query.  This is not likely to be very robust,
// but it should do for just this test.  The main shortcomings are escaping,
// and not knowing when to quote the variables.
// Note we do the replacement backwards (meaning forward_only iterators won't
// do!) to avoid substituting e.g. "$12" as "$1" first.
template<typename ITER> string subst(transaction_base &t,
	string q,
	ITER patbegin,
	ITER patend)
{
  int i = distance(patbegin, patend);
  for (ITER arg = patend; i > 0; --i)
  {
   --arg;
    const string marker = "$" + to_string(i),
	  var = stringize(t, *arg);
    const string::size_type msz = marker.size();
    while (q.find(marker) != string::npos) q.replace(q.find(marker),msz,var);
  }
  return q;
}

template<typename CNTNR> string subst(transaction_base &t,
	string q,
	const CNTNR &patterns)
{
  return subst(t, q, patterns.begin(), patterns.end());
}

} // namespace

// Test program for libpqxx.  Define and use prepared statements.
//
// Usage: test085
int main()
{
  try
  {
    /* A bit of nastiness in prepared statements: on 7.3.x backends we can't
     * compare pg_tables.tablename to a string.  We work around this by using
     * the LIKE operator.
     *
     * Later backend versions do not suffer from this problem.
     */
    const string QN_readpgtables = "ReadPGTables",
	  Q_readpgtables = "SELECT * FROM pg_tables",
	  QN_seetable = "SeeTable",
	  Q_seetable = Q_readpgtables + " WHERE tablename LIKE $1",
	  QN_seetables = "SeeTables",
	  Q_seetables = Q_seetable + " OR tablename LIKE $2";

    lazyconnection C;

    cout << "Preparing a simple statement..." << endl;
    C.prepare(QN_readpgtables, Q_readpgtables);
    nontransaction T(C, "test85");

    try
    {
      // See if a basic prepared statement works just like a regular query
      cout << "Basic correctness check on prepared statement..." << endl;
      compare_results(QN_readpgtables,
	T.prepared(QN_readpgtables).exec(),
	T.exec(Q_readpgtables));
    }
    catch (const exception &)
    {
      if (!C.supports(connection_base::cap_prepared_statements))
      {
        cout << "Backend version does not support prepared statements.  "
	        "Skipping."
	     << endl;
	return 0;
      }
      throw;
    }

    // Try prepare_now() on an already prepared statement
    C.prepare_now(QN_readpgtables);

    // Pro forma check: same thing but with name passed as C-style string
    compare_results(QN_readpgtables+"_char",
	T.prepared(QN_readpgtables.c_str()).exec(),
	T.exec(Q_readpgtables));

    cout << "Dropping prepared statement..." << endl;
    C.unprepare(QN_readpgtables);

    bool failed = true;
    try
    {
      disable_noticer d(C);
      C.prepare_now(QN_readpgtables);
      failed = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failed)
      throw runtime_error("prepare_now() succeeded on dropped statement");

    // Just to try and confuse things, "unprepare" twice
    cout << "Testing error detection and handling..." << endl;
    try { C.unprepare(QN_readpgtables); }
    catch (const exception &e) { cout << "(Expected) " << e.what() << endl; }

    // Verify that attempt to execute unprepared statement fails
    bool failsOK = true;
    try { T.prepared(QN_readpgtables).exec(); failsOK = false; }
    catch (const exception &e) { cout << "(Expected) " << e.what() << endl; }
    if (!failsOK) throw logic_error("Execute unprepared statement didn't fail");

    // Re-prepare the same statement and test again
    C.prepare(QN_readpgtables, Q_readpgtables);
    C.prepare_now(QN_readpgtables);
    compare_results(QN_readpgtables+"_2",
	T.prepared(QN_readpgtables).exec(),
	T.exec(Q_readpgtables));

    // Double preparation of identical statement should be ignored...
    C.prepare(QN_readpgtables, Q_readpgtables);
    compare_results(QN_readpgtables+"_double",
	T.prepared(QN_readpgtables).exec(),
	T.exec(Q_readpgtables));

    // ...But a modified definition shouldn't
    try
    {
      failsOK = true;
      C.prepare(QN_readpgtables, Q_readpgtables + " ORDER BY tablename");
      failsOK = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failsOK)
      throw logic_error("Bad redefinition of statement went unnoticed");

    cout << "Testing prepared statement with parameter..." << endl;

    C.prepare(QN_seetable, Q_seetable)("varchar", pqxx::prepare::treat_string);

    vector<string> args;
    args.push_back("pg_type");
    compare_results(QN_seetable+"_seq",
	T.prepared(QN_seetable)(args[0]).exec(),
	T.exec(subst(T,Q_seetable,args)));

    cout << "Testing prepared statement with 2 parameters..." << endl;

    C.prepare(QN_seetables, Q_seetables)
      ("varchar",pqxx::prepare::treat_string)
      ("varchar",pqxx::prepare::treat_string);
    args.push_back("pg_index");
    compare_results(QN_seetables+"_seq",
      T.prepared(QN_seetables)(args[0])(args[1]).exec(),
      T.exec(subst(T,Q_seetables,args)));

    cout << "Testing prepared statement with a null parameter..." << endl;
    vector<const char *> ptrs;
    ptrs.push_back(0);
    ptrs.push_back("pg_index");
    compare_results(QN_seetables+"_null1",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.exec(subst(T,Q_seetables,ptrs)));
    compare_results(QN_seetables+"_null2",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)()(ptrs[1]).exec());
    compare_results(QN_seetables+"_null3",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)("somestring",false)(ptrs[1]).exec());
    compare_results(QN_seetables+"_null4",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)(42,false)(ptrs[1]).exec());
    compare_results(QN_seetables+"_null5",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)(0,false)(ptrs[1]).exec());

    cout << "Testing wrong numbers of parameters..." << endl;
    try
    {
      failsOK = true;
      T.prepared(QN_seetables)()()("hi mom!").exec();
      failsOK = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failsOK)
      throw logic_error("No error for too many parameters");
    try
    {
      failsOK = true;
      T.prepared(QN_seetables)("who, me?").exec();
      failsOK = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failsOK)
      throw logic_error("No error for too few parameters");

    cout << "Done." << endl;
  }
  catch (const feature_not_supported &e)
  {
    cout << "Backend version does not support prepared statements.  Skipping."
         << endl;
    return 0;
  }
  catch (const sql_error &e)
  {
    cerr << "SQL error: " << e.what() << endl
         << "Query was: " << e.query() << endl;
    return 1;
  }
  catch (const exception &e)
  {
    // All exceptions thrown by libpqxx are derived from std::exception
    cerr << "Exception: " << e.what() << endl;
    return 2;
  }
  catch (...)
  {
    // This is really unexpected (see above)
    cerr << "Unhandled exception" << endl;
    return 100;
  }

  return 0;
}

<|endoftext|>